📄 hal.c
字号:
return apc;}/** * @fn int rthal_apc_free (int apc) * * @brief Releases an APC slot. * * This service deallocates an APC slot obtained by rthal_apc_alloc(). * * @param apc The APC id. to release, as returned by a successful call * to the rthal_apc_alloc() service. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a apc is invalid. * * Environments: * * This service can be called from: * * - Any domain context. */int rthal_apc_free (int apc){ if (apc < 0 || apc >= RTHAL_NR_APCS || !test_and_clear_bit(apc,&rthal_apc_map)) return -EINVAL; return 0;}/** * @fn int rthal_apc_schedule (int apc) * * @brief Schedule an APC invocation. * * This service marks the APC as pending for the Linux domain, so that * its handler will be called as soon as possible, when the Linux * domain gets back in control. * * When posted from the Linux domain, the APC handler is fired as soon * as the interrupt mask is explicitely cleared by some kernel * code. When posted from the Xenomai domain, the APC handler is * fired as soon as the Linux domain is resumed, i.e. after Xenomai has * completed all its pending duties. * * @param apc The APC id. to schedule. * * @return 0 or 1 are returned upon success, the former meaning that * the APC was already pending. Otherwise: * * - -EINVAL is returned if @a apc is invalid. * * Environments: * * This service can be called from: * * - Any domain context, albeit the usual calling place is from the * Xenomai domain. */int rthal_apc_schedule (int apc){ rthal_declare_cpuid; if (apc < 0 || apc >= RTHAL_NR_APCS) return -EINVAL; rthal_load_cpuid(); /* Migration would be harmless here. */ if (!test_and_set_bit(apc,&rthal_apc_pending[cpuid])) { rthal_schedule_irq(rthal_apc_virq); return 1; } return 0; /* Already pending. */}#ifdef CONFIG_PROC_FSstruct proc_dir_entry *rthal_proc_root;static int hal_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ int len, major, minor, patchlevel;#ifdef CONFIG_IPIPE major = IPIPE_MAJOR_NUMBER; minor = IPIPE_MINOR_NUMBER; patchlevel = IPIPE_PATCH_NUMBER;#else /* !CONFIG_IPIPE */ /* Canonicalize the Adeos relno-candidate information to some major.minor.patchlevel format to be parser-friendly. */ major = ADEOS_MAJOR_NUMBER; if (ADEOS_MINOR_NUMBER < 255) { --major; minor = 99; patchlevel = ADEOS_MINOR_NUMBER; } else { minor = 0; patchlevel = 0; }#endif /* CONFIG_IPIPE */ len = sprintf(page,"%d.%d-%.2d\n",major,minor,patchlevel); len -= off; if (len <= off + count) *eof = 1; *start = page + off; if(len > count) len = count; if(len < 0) len = 0; return len;}static int faults_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0, cpu, trap; char *p = page; p += sprintf(p,"TRAP "); for_each_online_cpu(cpu) { p += sprintf(p," CPU%d",cpu); } for (trap = 0; rthal_fault_labels[trap] != NULL; trap++) { if (!*rthal_fault_labels[trap]) continue; p += sprintf(p,"\n%3d: ",trap); for_each_online_cpu(cpu) { p += sprintf(p,"%12d", rthal_realtime_faults[cpu][trap]); } p += sprintf(p," (%s)",rthal_fault_labels[trap]); } p += sprintf(p,"\n"); len = p - page - off; if (len <= off + count) *eof = 1; *start = page + off; if (len > count) len = count; if (len < 0) len = 0; return len;}static int apc_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0, cpu, apc; char *p = page; p += sprintf(p,"APC "); for_each_online_cpu(cpu) { p += sprintf(p," CPU%d",cpu); } for (apc = 0; apc < BITS_PER_LONG; apc++) { if (!test_bit(apc,&rthal_apc_map)) continue; /* Not hooked. */ p += sprintf(p,"\n%3d: ",apc); for_each_online_cpu(cpu) { p += sprintf(p,"%12lu", rthal_apc_table[apc].hits[cpu]); } p += sprintf(p," (%s)",rthal_apc_table[apc].name); } p += sprintf(p,"\n"); len = p - page - off; if (len <= off + count) *eof = 1; *start = page + off; if (len > count) len = count; if (len < 0) len = 0; return len;}struct proc_dir_entry *__rthal_add_proc_leaf (const char *name, read_proc_t rdproc, write_proc_t wrproc, void *data, struct proc_dir_entry *parent){ int mode = wrproc ? 0644 : 0444; struct proc_dir_entry *entry; entry = create_proc_entry(name,mode,parent); if (entry) { entry->nlink = 1; entry->data = data; entry->read_proc = rdproc; entry->write_proc = wrproc; entry->owner = THIS_MODULE; } return entry;}static int rthal_proc_register (void){ rthal_proc_root = create_proc_entry("xenomai",S_IFDIR, 0); if (!rthal_proc_root) { printk(KERN_ERR "Xenomai: Unable to initialize /proc/xenomai.\n"); return -1; } rthal_proc_root->owner = THIS_MODULE; __rthal_add_proc_leaf("hal", &hal_read_proc, NULL, NULL, rthal_proc_root); __rthal_add_proc_leaf("faults", &faults_read_proc, NULL, NULL, rthal_proc_root); __rthal_add_proc_leaf("apc", &apc_read_proc, NULL, NULL, rthal_proc_root); rthal_nmi_proc_register(); return 0;}static void rthal_proc_unregister (void){ rthal_nmi_proc_unregister(); remove_proc_entry("hal",rthal_proc_root); remove_proc_entry("faults",rthal_proc_root); remove_proc_entry("apc",rthal_proc_root); remove_proc_entry("xenomai",NULL);}#endif /* CONFIG_PROC_FS */int rthal_init (void){ int err;#ifdef CONFIG_SMP /* The nucleus also sets the same CPU affinity so that both modules keep their execution sequence on SMP boxen. */ set_cpus_allowed(current,cpumask_of_cpu(0));#endif /* CONFIG_SMP */ err = rthal_arch_init(); if (err) goto out; /* The arch-dependent support must have updated the frequency args as required. */ rthal_tunables.cpu_freq = rthal_cpufreq_arg; rthal_tunables.timer_freq = rthal_timerfreq_arg; /* Allocate a virtual interrupt to handle apcs within the Linux domain. */ rthal_apc_virq = rthal_alloc_virq(); if (!rthal_apc_virq) { printk(KERN_ERR "Xenomai: No virtual interrupt available.\n"); err = -EBUSY; goto out_arch_cleanup; } err = rthal_virtualize_irq(rthal_current_domain, rthal_apc_virq, &rthal_apc_trampoline, NULL, NULL, IPIPE_HANDLE_MASK); if (err) { printk(KERN_ERR "Xenomai: Failed to virtualize IRQ.\n"); goto out_free_irq; }#ifdef CONFIG_PREEMPT_RT { int cpu; for_each_online_cpu(cpu) { rthal_apc_servers[cpu] = kthread_create(&rthal_apc_thread,(void *)(unsigned long)cpu,"apc/%d",cpu); if (!rthal_apc_servers[cpu]) goto out_kthread_stop; wake_up_process(rthal_apc_servers[cpu]); } }#endif /* CONFIG_PREEMPT_RT */#ifdef CONFIG_PROC_FS rthal_proc_register();#endif /* CONFIG_PROC_FS */ err = rthal_register_domain(&rthal_domain, "Xenomai", RTHAL_DOMAIN_ID, RTHAL_ROOT_PRIO + 100, &rthal_domain_entry); if (!err) rthal_init_done = 1; else { printk(KERN_ERR "Xenomai: Domain registration failed.\n"); goto out_proc_unregister; } return 0;out_proc_unregister:#ifdef CONFIG_PROC_FS rthal_proc_unregister();#endif#ifdef CONFIG_PREEMPT_RTout_kthread_stop: { int cpu; for_each_online_cpu(cpu) { if (rthal_apc_servers[cpu]) kthread_stop(rthal_apc_servers[cpu]); } }#endif /* CONFIG_PREEMPT_RT */ rthal_virtualize_irq(rthal_current_domain,rthal_apc_virq,NULL,NULL,NULL,0); out_free_irq: rthal_free_virq(rthal_apc_virq); out_arch_cleanup: rthal_arch_cleanup(); out: return err;}void rthal_exit (void){#ifdef CONFIG_SMP /* The nucleus also sets the same CPU affinity so that both modules keep their execution sequence on SMP boxen. */ set_cpus_allowed(current,cpumask_of_cpu(0));#endif /* CONFIG_SMP */#ifdef CONFIG_PROC_FS rthal_proc_unregister();#endif /* CONFIG_PROC_FS */ if (rthal_apc_virq) { rthal_virtualize_irq(rthal_current_domain,rthal_apc_virq,NULL,NULL,NULL,0); rthal_free_virq(rthal_apc_virq);#ifdef CONFIG_PREEMPT_RT { int cpu; for_each_online_cpu(cpu) { kthread_stop(rthal_apc_servers[cpu]); } }#endif /* CONFIG_PREEMPT_RT */ } if (rthal_init_done) rthal_unregister_domain(&rthal_domain); rthal_arch_cleanup();}/** * @fn int rthal_irq_enable(unsigned irq) * * @brief Enable an interrupt source. * * Enables an interrupt source at PIC level. Since Adeos masks and * acknowledges the associated interrupt source upon IRQ receipt, this * action is usually needed whenever the HAL handler does not * propagate the IRQ event to the Linux domain, thus preventing the * regular Linux interrupt handling code from re-enabling said * source. After this call has returned, IRQs from the given source * will be enabled again. * * @param irq The interrupt source to enable. This value is * architecture-dependent. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a irq is invalid. * * - Other error codes might be returned in case some internal error * happens at the Adeos level. Such error might caused by conflicting * Adeos requests made by third-party code. * * Environments: * * This service can be called from: * * - Any domain context. *//** * @fn int rthal_irq_disable(unsigned irq) * * @brief Disable an interrupt source. * * Disables an interrupt source at PIC level. After this call has * returned, no more IRQs from the given source will be allowed, until * the latter is enabled again using rthal_irq_enable(). * * @param irq The interrupt source to disable. This value is * architecture-dependent. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a irq is invalid. * * - Other error codes might be returned in case some internal error * happens at the Adeos level. Such error might caused by conflicting * Adeos requests made by third-party code. * * Environments: * * This service can be called from: * * - Any domain context. *//*! * \fn int rthal_timer_request(void (*handler)(void),unsigned long nstick) * \brief Grab the hardware timer. * * rthal_timer_request() grabs and tunes the hardware timer so that a * user-defined routine is called according to a given frequency. On * architectures that provide a oneshot-programmable time source, the * hardware timer can operate either in aperiodic or periodic * mode. Using the aperiodic mode still allows to run periodic timings * over it: the underlying hardware simply needs to be reprogrammed * after each tick using the appropriate interval value * * The time interval that elapses between two consecutive invocations * of the handler is called a tick. The user-supplied handler will * always be invoked on behalf of the Xenomai domain for each incoming * tick. * * @param handler The address of the tick handler which will process * each incoming tick. * * @param nstick The timer period in nanoseconds. If this parameter is * zero, the underlying hardware timer is set to operate in * oneshot-programming mode. In this mode, timing accuracy is higher - * since it is not rounded to a constant time slice - at the expense * of a lesser efficicency due to the timer chip programming * duties. On the other hand, the shorter the period, the higher the * overhead induced by the periodic mode, since the handler will end * up consuming a lot of CPU power to process useless ticks. * * @return 0 is returned on success. Otherwise: * * - -EBUSY is returned if the hardware timer has already been * grabbed. rthal_timer_request() must be issued before * rthal_timer_request() is called again. * * Environments: * * This service can be called from: * * - Linux domain context. *//*! * \fn void rthal_timer_release(void) * \brief Release the hardware timer. * * Releases the hardware timer, thus reverting the effect of a * previous call to rthal_timer_request(). In case the timer hardware * is shared with Linux, a periodic setup suitable for the Linux * kernel will be reset. * * Environments: * * This service can be called from: * * - Linux domain context. *//*@}*/EXPORT_SYMBOL(rthal_irq_request);EXPORT_SYMBOL(rthal_irq_release);EXPORT_SYMBOL(rthal_irq_enable);EXPORT_SYMBOL(rthal_irq_disable);EXPORT_SYMBOL(rthal_irq_end);EXPORT_SYMBOL(rthal_irq_host_request);EXPORT_SYMBOL(rthal_irq_host_release);EXPORT_SYMBOL(rthal_irq_host_pend);EXPORT_SYMBOL(rthal_irq_affinity);EXPORT_SYMBOL(rthal_trap_catch);EXPORT_SYMBOL(rthal_timer_request);EXPORT_SYMBOL(rthal_timer_release);EXPORT_SYMBOL(rthal_timer_calibrate);EXPORT_SYMBOL(rthal_apc_alloc);EXPORT_SYMBOL(rthal_apc_free);EXPORT_SYMBOL(rthal_apc_schedule);EXPORT_SYMBOL(rthal_critical_enter);EXPORT_SYMBOL(rthal_critical_exit);EXPORT_SYMBOL(rthal_domain);EXPORT_SYMBOL(rthal_tunables);EXPORT_SYMBOL(rthal_cpu_realtime);#ifdef CONFIG_PROC_FSEXPORT_SYMBOL(rthal_proc_root);#endif /* CONFIG_PROC_FS */EXPORT_SYMBOL(rthal_init);EXPORT_SYMBOL(rthal_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -