/* * Copyright (C) 2001-2013 Philippe Gerum . * * Xenomai is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * Xenomai is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Xenomai; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rtdm/internal.h" #include "posix/internal.h" #include "procfs.h" /** * @defgroup cobalt Cobalt * * Cobalt supplements the native Linux kernel in dual kernel * configurations. It deals with all time-critical activities, such as * handling interrupts, and scheduling real-time threads. The Cobalt * kernel has higher priority over all the native kernel activities. * * Cobalt provides an implementation of the POSIX and RTDM interfaces * based on a set of generic RTOS building blocks. */ #ifdef CONFIG_SMP static unsigned long supported_cpus_arg = -1; module_param_named(supported_cpus, supported_cpus_arg, ulong, 0444); #endif /* CONFIG_SMP */ static unsigned long sysheap_size_arg; module_param_named(sysheap_size, sysheap_size_arg, ulong, 0444); static char init_state_arg[16] = "enabled"; module_param_string(state, init_state_arg, sizeof(init_state_arg), 0444); static BLOCKING_NOTIFIER_HEAD(state_notifier_list); struct cobalt_pipeline cobalt_pipeline; EXPORT_SYMBOL_GPL(cobalt_pipeline); DEFINE_PER_CPU(struct cobalt_machine_cpudata, cobalt_machine_cpudata); EXPORT_PER_CPU_SYMBOL_GPL(cobalt_machine_cpudata); atomic_t cobalt_runstate = ATOMIC_INIT(COBALT_STATE_WARMUP); EXPORT_SYMBOL_GPL(cobalt_runstate); struct cobalt_ppd cobalt_kernel_ppd = { .exe_path = "vmlinux", }; EXPORT_SYMBOL_GPL(cobalt_kernel_ppd); #ifdef CONFIG_XENO_OPT_DEBUG #define boot_debug_notice "[DEBUG]" #else #define boot_debug_notice "" #endif #ifdef CONFIG_ENABLE_DEFAULT_TRACERS #define boot_evt_trace_notice "[ETRACE]" #else #define boot_evt_trace_notice "" #endif #define boot_state_notice \ ({ \ realtime_core_state() == COBALT_STATE_STOPPED ? \ "[STOPPED]" : ""; \ }) void cobalt_add_state_chain(struct notifier_block *nb) { blocking_notifier_chain_register(&state_notifier_list, nb); } EXPORT_SYMBOL_GPL(cobalt_add_state_chain); void cobalt_remove_state_chain(struct notifier_block *nb) { blocking_notifier_chain_unregister(&state_notifier_list, nb); } EXPORT_SYMBOL_GPL(cobalt_remove_state_chain); void cobalt_call_state_chain(enum cobalt_run_states newstate) { blocking_notifier_call_chain(&state_notifier_list, newstate, NULL); } EXPORT_SYMBOL_GPL(cobalt_call_state_chain); static void sys_shutdown(void) { void *membase; pipeline_uninstall_tick_proxy(); xnsched_destroy_all(); xnregistry_cleanup(); membase = xnheap_get_membase(&cobalt_heap); xnheap_destroy(&cobalt_heap); xnheap_vfree(membase); } static struct { const char *label; enum cobalt_run_states state; } init_states[] __initdata = { { "disabled", COBALT_STATE_DISABLED }, { "stopped", COBALT_STATE_STOPPED }, { "enabled", COBALT_STATE_WARMUP }, }; static void __init setup_init_state(void) { static char warn_bad_state[] __initdata = XENO_WARNING "invalid init state '%s'\n"; int n; for (n = 0; n < ARRAY_SIZE(init_states); n++) if (strcmp(init_states[n].label, init_state_arg) == 0) { set_realtime_core_state(init_states[n].state); return; } printk(warn_bad_state, init_state_arg); } static __init int sys_init(void) { void *heapaddr; int ret; if (sysheap_size_arg == 0) sysheap_size_arg = CONFIG_XENO_OPT_SYS_HEAPSZ; heapaddr = xnheap_vmalloc(sysheap_size_arg * 1024); if (heapaddr == NULL || xnheap_init(&cobalt_heap, heapaddr, sysheap_size_arg * 1024)) { return -ENOMEM; } xnheap_set_name(&cobalt_heap, "system heap"); xnsched_init_all(); xnregistry_init(); /* * If starting in stopped mode, do all initializations, but do * not enable the core timer. */ if (realtime_core_state() == COBALT_STATE_WARMUP) { ret = pipeline_install_tick_proxy(); if (ret) { sys_shutdown(); return ret; } set_realtime_core_state(COBALT_STATE_RUNNING); } return 0; } static int __init xenomai_init(void) { int ret, __maybe_unused cpu; setup_init_state(); if (!realtime_core_enabled()) { printk(XENO_WARNING "disabled on kernel command line\n"); return 0; } #ifdef CONFIG_SMP cpumask_clear(&xnsched_realtime_cpus); for_each_online_cpu(cpu) { if (supported_cpus_arg & (1UL << cpu)) cpumask_set_cpu(cpu, &xnsched_realtime_cpus); } if (cpumask_empty(&xnsched_realtime_cpus)) { printk(XENO_WARNING "disabled via empty real-time CPU mask\n"); set_realtime_core_state(COBALT_STATE_DISABLED); return 0; } if (!cpumask_test_cpu(0, &xnsched_realtime_cpus)) { printk(XENO_ERR "CPU 0 is missing in real-time CPU mask\n"); set_realtime_core_state(COBALT_STATE_DISABLED); return -EINVAL; } cobalt_cpu_affinity = xnsched_realtime_cpus; #endif /* CONFIG_SMP */ xnsched_register_classes(); ret = xnprocfs_init_tree(); if (ret) goto fail; ret = pipeline_init(); if (ret) goto cleanup_proc; xnintr_mount(); ret = xnpipe_mount(); if (ret) goto cleanup_mach; ret = xnselect_mount(); if (ret) goto cleanup_pipe; ret = sys_init(); if (ret) goto cleanup_select; ret = pipeline_late_init(); if (ret) goto cleanup_sys; ret = rtdm_init(); if (ret) goto cleanup_sys; ret = cobalt_init(); if (ret) goto cleanup_rtdm; rtdm_fd_init(); printk(XENO_INFO "Cobalt v%s %s%s%s%s\n", XENO_VERSION_STRING, boot_debug_notice, boot_lat_trace_notice, boot_evt_trace_notice, boot_state_notice); return 0; cleanup_rtdm: rtdm_cleanup(); cleanup_sys: sys_shutdown(); cleanup_select: xnselect_umount(); cleanup_pipe: xnpipe_umount(); cleanup_mach: pipeline_cleanup(); cleanup_proc: xnprocfs_cleanup_tree(); fail: set_realtime_core_state(COBALT_STATE_DISABLED); printk(XENO_ERR "init failed, code %d\n", ret); return ret; } device_initcall(xenomai_init); /** * @ingroup cobalt * @defgroup cobalt_core Cobalt kernel * * The Cobalt core is a co-kernel which supplements the Linux kernel * for delivering real-time services with very low latency. It * implements a set of generic RTOS building blocks, which the * Cobalt/POSIX and Cobalt/RTDM APIs are based on. Cobalt has higher * priority over the Linux kernel activities. * * @{ * * @page cobalt-core-tags Dual kernel service tags * * The Cobalt kernel services may be restricted to particular calling * contexts, or entail specific side-effects. To describe this * information, each service documented by this section bears a set of * tags when applicable. * * The table below matches the tags used throughout the documentation * with the description of their meaning for the caller. * * @par * Context tags * * * * * * * * * * * *
Tag Context on entry
primary-only Must be called from a Cobalt task in primary mode
primary-timed Requires a Cobalt task in primary mode if timed
coreirq-only Must be called from a Cobalt IRQ handler
secondary-only Must be called from a Cobalt task in secondary mode or regular Linux task
rtdm-task Must be called from a RTDM driver task
mode-unrestricted May be called from a Cobalt task in either primary or secondary mode
task-unrestricted May be called from a Cobalt or regular Linux task indifferently
unrestricted May be called from any context previously described
atomic-entry Caller must currently hold the big Cobalt kernel lock (nklock)
* * @par * Possible side-effects * * * *
Tag Description
might-switch The Cobalt kernel may switch context
* * @} */