* [Xenomai-core] [RFC][PATCH] refactor x86/hal_*.c
@ 2007-11-01 11:31 Jan Kiszka
0 siblings, 0 replies; only message in thread
From: Jan Kiszka @ 2007-11-01 11:31 UTC (permalink / raw)
To: Xenomai-core
[-- Attachment #1.1: Type: text/plain, Size: 450 bytes --]
This is the kind of patch I've warned about regarding this late -rc
state... :->
It refactores most code from arch/x86/hal_*.c into hal-shared.c, overall
killing more than 200 lines of code. It's compile- and run-tested on
both i386 and x86_64 from 2.6.20 up to 2.6.24-rc1 (x86_64 only on 2.6.23
and 2.6.24). Still, the patch may contain copy&paste regressions or some
remaining ugliness, so it is RFC and not a must for the release.
Jan
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: refactor-x86-hal.patch --]
[-- Type: text/x-patch; name="refactor-x86-hal.patch", Size: 36018 bytes --]
---
include/asm-x86/hal.h | 14 +
include/asm-x86/hal_32.h | 39 ++++
include/asm-x86/hal_64.h | 20 ++
include/asm-x86/wrappers_64.h | 3
ksrc/arch/x86/Makefile | 4
ksrc/arch/x86/hal-shared.c | 371 +++++++++++++++++++++++++++++++++++++++++
ksrc/arch/x86/hal_32.c | 375 ------------------------------------------
ksrc/arch/x86/hal_64.c | 313 -----------------------------------
8 files changed, 450 insertions(+), 689 deletions(-)
Index: xenomai/include/asm-x86/hal.h
===================================================================
--- xenomai.orig/include/asm-x86/hal.h
+++ xenomai/include/asm-x86/hal.h
@@ -1,5 +1,19 @@
+#ifndef _XENO_ASM_X86_HAL_H
+#define _XENO_ASM_X86_HAL_H
+
+enum rthal_ktimer_mode { /* <!> Must follow enum clock_event_mode */
+ KTIMER_MODE_UNUSED = 0,
+ KTIMER_MODE_SHUTDOWN,
+ KTIMER_MODE_PERIODIC,
+ KTIMER_MODE_ONESHOT,
+};
+
+extern enum rthal_ktimer_mode rthal_ktimer_saved_mode;
+
#ifdef __i386__
#include "hal_32.h"
#else
#include "hal_64.h"
#endif
+
+#endif /* !_XENO_ASM_X86_HAL_H */
Index: xenomai/include/asm-x86/hal_32.h
===================================================================
--- xenomai.orig/include/asm-x86/hal_32.h
+++ xenomai/include/asm-x86/hal_32.h
@@ -36,7 +36,8 @@
#ifndef _XENO_ASM_X86_HAL_32_H
#define _XENO_ASM_X86_HAL_32_H
-#define _XENO_ASM_X86_HAL_H
+
+#define RTHAL_ARCH_NAME "i386"
#include <asm/xenomai/wrappers.h>
@@ -175,8 +176,42 @@ static const char *const rthal_fault_lab
[20] = NULL,
};
-long rthal_strncpy_from_user(char *dst, const char __user * src, long count);
+#ifdef CONFIG_X86_LOCAL_APIC
+
+#include <asm/fixmap.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif /* CONFIG_X86_IO_APIC */
+#include <asm/apic.h>
+
+static inline int rthal_set_apic_base(int lvtt_value)
+{
+ if (APIC_INTEGRATED(GET_APIC_VERSION(apic_read(APIC_LVR))))
+ lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);
+
+ return lvtt_value;
+}
+
+static inline void rthal_setup_periodic_apic(int count, int vector)
+{
+ apic_read_around(APIC_LVTT);
+ apic_write_around(APIC_LVTT, rthal_set_apic_base(APIC_LVT_TIMER_PERIODIC | vector));
+ apic_read_around(APIC_TMICT);
+ apic_write_around(APIC_TMICT, count);
+}
+
+static inline void rthal_setup_oneshot_apic(int vector)
+{
+ apic_read_around(APIC_LVTT);
+ apic_write_around(APIC_LVTT, rthal_set_apic_base(vector));
+}
+#endif /* !CONFIG_X86_LOCAL_APIC */
#endif /* !__cplusplus */
+long rthal_strncpy_from_user(char *dst, const char __user * src, long count);
+
+void rthal_latency_above_max(struct pt_regs *regs);
+
#endif /* !_XENO_ASM_X86_HAL_32_H */
Index: xenomai/include/asm-x86/hal_64.h
===================================================================
--- xenomai.orig/include/asm-x86/hal_64.h
+++ xenomai/include/asm-x86/hal_64.h
@@ -22,7 +22,8 @@
#ifndef _XENO_ASM_X86_HAL_64_H
#define _XENO_ASM_X86_HAL_64_H
-#define _XENO_ASM_X86_HAL_H
+
+#define RTHAL_ARCH_NAME "x86_64"
#include <asm/xenomai/wrappers.h>
#include <asm-generic/xenomai/hal.h> /* Read the generic bits. */
@@ -116,6 +117,23 @@ static const char *const rthal_fault_lab
[20] = NULL,
};
+#ifdef CONFIG_X86_LOCAL_APIC
+
+#include <asm/mach_apic.h>
+
+static inline void rthal_setup_periodic_apic(int count, int vector)
+{
+ apic_write(APIC_LVTT, APIC_LVT_TIMER_PERIODIC | vector);
+ apic_write(APIC_TMICT, count);
+}
+
+static inline void rthal_setup_oneshot_apic(int vector)
+{
+ apic_write(APIC_LVTT, vector);
+}
+
+#endif /* !CONFIG_X86_LOCAL_APIC */
+
#endif /* !__cplusplus */
long rthal_strncpy_from_user(char *dst,
Index: xenomai/ksrc/arch/x86/Makefile
===================================================================
--- xenomai.orig/ksrc/arch/x86/Makefile
+++ xenomai/ksrc/arch/x86/Makefile
@@ -10,7 +10,7 @@ endif
obj-$(CONFIG_XENOMAI) += xeno_hal.o
-xeno_hal-y := hal_$(X86_MODE).o usercopy_$(X86_MODE).o
+xeno_hal-y := hal_$(X86_MODE).o hal-shared.o usercopy_$(X86_MODE).o
xeno_hal-$(CONFIG_XENO_HW_NMI_DEBUG_LATENCY) += nmi_$(X86_MODE).o
@@ -26,7 +26,7 @@ USE_STANDARD_AS_RULE := true
O_TARGET := built-in.o
-obj-y := hal_32.o
+obj-y := hal_32.o hal-shared.o
obj-$(CONFIG_XENO_HW_NMI_DEBUG_LATENCY) += nmi_32.o
Index: xenomai/ksrc/arch/x86/hal-shared.c
===================================================================
--- /dev/null
+++ xenomai/ksrc/arch/x86/hal-shared.c
@@ -0,0 +1,371 @@
+/**
+ * @ingroup hal
+ * @file
+ *
+ * Adeos-based Real-Time Abstraction Layer for x86.
+ * Common code of i386 and x86_64.
+ *
+ * Copyright (C) 2007 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, Inc., 675 Mass Ave,
+ * Cambridge MA 02139, USA; 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/**
+ * @addtogroup hal
+ *
+ *@{*/
+
+#include <asm/xenomai/hal.h>
+
+enum rthal_ktimer_mode rthal_ktimer_saved_mode;
+
+static struct {
+ unsigned long flags;
+ int count;
+} rthal_linux_irq[IPIPE_NR_XIRQS];
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+#define RTHAL_SET_ONESHOT_XENOMAI 1
+#define RTHAL_SET_ONESHOT_LINUX 2
+#define RTHAL_SET_PERIODIC 3
+
+static void rthal_critical_sync(void)
+{
+ switch (rthal_sync_op) {
+ case RTHAL_SET_ONESHOT_XENOMAI:
+ rthal_setup_oneshot_apic(RTHAL_APIC_TIMER_VECTOR);
+ break;
+
+ case RTHAL_SET_ONESHOT_LINUX:
+ rthal_setup_oneshot_apic(LOCAL_TIMER_VECTOR);
+ /* We need to keep the timing cycle alive for the kernel. */
+ rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
+ break;
+
+ case RTHAL_SET_PERIODIC:
+ rthal_setup_periodic_apic(RTHAL_APIC_ICOUNT, LOCAL_TIMER_VECTOR);
+ break;
+ }
+}
+
+static void rthal_timer_set_oneshot(int rt_mode)
+{
+ unsigned long flags;
+
+ flags = rthal_critical_enter(rthal_critical_sync);
+ if (rt_mode) {
+ rthal_sync_op = RTHAL_SET_ONESHOT_XENOMAI;
+ rthal_setup_oneshot_apic(RTHAL_APIC_TIMER_VECTOR);
+ } else {
+ rthal_sync_op = RTHAL_SET_ONESHOT_LINUX;
+ rthal_setup_oneshot_apic(LOCAL_TIMER_VECTOR);
+ /* We need to keep the timing cycle alive for the kernel. */
+ rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
+ }
+ rthal_critical_exit(flags);
+}
+
+static void rthal_timer_set_periodic(void)
+{
+ unsigned long flags;
+
+ flags = rthal_critical_enter(&rthal_critical_sync);
+ rthal_sync_op = RTHAL_SET_PERIODIC;
+ rthal_setup_periodic_apic(RTHAL_APIC_ICOUNT, LOCAL_TIMER_VECTOR);
+ rthal_critical_exit(flags);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#include <asm/smpboot.h>
+static inline void send_IPI_all(int vector)
+{
+ unsigned long flags;
+
+ rthal_local_irq_save_hw(flags);
+ apic_wait_icr_idle();
+ apic_write_around(APIC_ICR,
+ APIC_DM_FIXED | APIC_DEST_ALLINC | INT_DEST_ADDR_MODE
+ | vector);
+ rthal_local_irq_restore_hw(flags);
+}
+#elif defined(__i386__)
+#include <mach_ipi.h>
+#endif
+
+DECLARE_LINUX_IRQ_HANDLER(rthal_broadcast_to_local_timers, irq, dev_id)
+{
+#ifdef CONFIG_SMP
+ send_IPI_all(LOCAL_TIMER_VECTOR);
+#else
+ rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
+#endif
+ return IRQ_HANDLED;
+}
+
+int rthal_timer_request(
+ void (*tick_handler)(void),
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ void (*mode_emul)(enum clock_event_mode mode,
+ struct ipipe_tick_device *tdev),
+ int (*tick_emul)(unsigned long delay,
+ struct ipipe_tick_device *tdev),
+#endif
+ int cpu)
+{
+ int tickval, err;
+
+ /* This code works both for UP+LAPIC and SMP configurations. */
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ err = ipipe_request_tickdev("lapic", mode_emul, tick_emul, cpu);
+
+ switch (err) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* oneshot tick emulation callback won't be used, ask
+ * the caller to start an internal timer for emulating
+ * a periodic tick. */
+ tickval = 1000000000UL / HZ;
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* oneshot tick emulation */
+ tickval = 1;
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ /* we don't need to emulate the tick at all. */
+ tickval = 0;
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ return -ENODEV;
+
+ default:
+ return err;
+ }
+
+ rthal_ktimer_saved_mode = err;
+#else /* !CONFIG_GENERIC_CLOCKEVENTS */
+ /*
+ * When the local APIC is enabled for kernels lacking generic
+ * support for clock events, we do not need to relay the host tick
+ * since 8254 interrupts are already flowing normally to Linux
+ * (i.e. the nucleus does not intercept them, but uses a dedicated
+ * APIC-based timer interrupt instead, i.e. RTHAL_APIC_TIMER_IPI).
+ */
+ tickval = 0;
+ rthal_ktimer_saved_mode = KTIMER_MODE_PERIODIC;
+#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
+
+ /*
+ * The rest of the initialization should only be performed
+ * once by a single CPU.
+ */
+ if (cpu > 0)
+ goto out;
+
+ rthal_timer_set_oneshot(1);
+
+ err = rthal_irq_request(RTHAL_APIC_TIMER_IPI,
+ (rthal_irq_handler_t) tick_handler, NULL, NULL);
+
+ if (err)
+ return err;
+
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
+ rthal_irq_host_request(RTHAL_BCAST_TICK_IRQ,
+ &rthal_broadcast_to_local_timers,
+ "rthal_broadcast_timer",
+ &rthal_broadcast_to_local_timers);
+#endif
+
+ rthal_nmi_init(&rthal_latency_above_max);
+out:
+ return tickval;
+}
+
+void rthal_timer_release(int cpu)
+{
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ ipipe_release_tickdev(cpu);
+#else
+ rthal_irq_host_release(RTHAL_BCAST_TICK_IRQ,
+ &rthal_broadcast_to_local_timers);
+#endif
+
+ /*
+ * The rest of the cleanup work should only be performed once
+ * by a single CPU.
+ */
+ if (cpu > 0)
+ return;
+
+ rthal_nmi_release();
+
+ rthal_irq_release(RTHAL_APIC_TIMER_IPI);
+
+ if (rthal_ktimer_saved_mode == KTIMER_MODE_PERIODIC)
+ rthal_timer_set_periodic();
+ else if (rthal_ktimer_saved_mode == KTIMER_MODE_ONESHOT)
+ rthal_timer_set_oneshot(0);
+}
+
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
+void rthal_timer_notify_switch(enum clock_event_mode mode,
+ struct ipipe_tick_device *tdev)
+{
+ if (rthal_processor_id() > 0)
+ /*
+ * We assume all CPUs switch the same way, so we only
+ * track mode switches from the boot CPU.
+ */
+ return;
+
+ rthal_ktimer_saved_mode = mode;
+}
+
+EXPORT_SYMBOL(rthal_timer_notify_switch);
+
+#endif /* CONFIG_GENERIC_CLOCKEVENTS */
+
+int rthal_irq_host_request(unsigned irq,
+ rthal_irq_host_handler_t handler,
+ char *name, void *dev_id)
+{
+ unsigned long flags;
+
+ if (irq >= IPIPE_NR_XIRQS || !handler)
+ return -EINVAL;
+
+ spin_lock_irqsave(&rthal_irq_descp(irq)->lock, flags);
+
+ if (rthal_linux_irq[irq].count++ == 0 && rthal_irq_descp(irq)->action) {
+ rthal_linux_irq[irq].flags =
+ rthal_irq_descp(irq)->action->flags;
+ rthal_irq_descp(irq)->action->flags |= IRQF_SHARED;
+ }
+
+ spin_unlock_irqrestore(&rthal_irq_descp(irq)->lock, flags);
+
+ return request_irq(irq, handler, IRQF_SHARED, name, dev_id);
+}
+
+int rthal_irq_host_release(unsigned irq, void *dev_id)
+{
+ unsigned long flags;
+
+ if (irq >= NR_IRQS || rthal_linux_irq[irq].count == 0)
+ return -EINVAL;
+
+ free_irq(irq, dev_id);
+
+ spin_lock_irqsave(&rthal_irq_descp(irq)->lock, flags);
+
+ if (--rthal_linux_irq[irq].count == 0 && rthal_irq_descp(irq)->action)
+ rthal_irq_descp(irq)->action->flags =
+ rthal_linux_irq[irq].flags;
+
+ spin_unlock_irqrestore(&rthal_irq_descp(irq)->lock, flags);
+
+ return 0;
+}
+
+int rthal_irq_enable(unsigned irq)
+{
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+
+ rthal_irq_desc_status(irq) &= ~IRQ_DISABLED;
+
+ return rthal_irq_chip_enable(irq);
+}
+
+int rthal_irq_disable(unsigned irq)
+{
+
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+
+ rthal_irq_desc_status(irq) |= IRQ_DISABLED;
+
+ return rthal_irq_chip_disable(irq);
+}
+
+int rthal_irq_end(unsigned irq)
+{
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+
+ return rthal_irq_chip_end(irq);
+}
+
+static inline int do_exception_event(unsigned event, unsigned domid, void *data)
+{
+ /* Notes:
+
+ 1) GPF needs to be propagated downstream whichever domain caused
+ it. This is required so that we don't spuriously raise a fatal
+ error when some fixup code is available to solve the error
+ condition. For instance, Linux always attempts to reload the %gs
+ segment register when switching a process in (__switch_to()),
+ regardless of its value. It is then up to Linux's GPF handling
+ code to search for a possible fixup whenever some exception
+ occurs. In the particular case of the %gs register, such an
+ exception could be raised for an exiting process if a preemption
+ occurs inside a short time window, after the process's LDT has
+ been dropped, but before the kernel lock is taken. The same goes
+ for Xenomai switching back a Linux thread in non-RT mode which
+ happens to have been preempted inside do_exit() after the MM
+ context has been dropped (thus the LDT too). In such a case, %gs
+ could be reloaded with what used to be the TLS descriptor of the
+ exiting thread, but unfortunately after the LDT itself has been
+ dropped. Since the default LDT is only 5 entries long, any attempt
+ to refer to an LDT-indexed descriptor above this value would cause
+ a GPF. 2) NMI is not pipelined. */
+
+ if (domid == RTHAL_DOMAIN_ID) {
+ rthal_realtime_faults[rthal_processor_id()][event]++;
+
+ if (rthal_trap_handler != NULL &&
+ rthal_trap_handler(event, domid, data) != 0)
+ return RTHAL_EVENT_STOP;
+ }
+
+ return RTHAL_EVENT_PROPAGATE;
+}
+
+RTHAL_DECLARE_EVENT(exception_event);
+
+static inline void do_rthal_domain_entry(void)
+{
+ unsigned trapnr;
+
+ /* Trap all faults. */
+ for (trapnr = 0; trapnr < RTHAL_NR_FAULTS; trapnr++)
+ rthal_catch_exception(trapnr, &exception_event);
+
+ printk(KERN_INFO "Xenomai: hal/%s started.\n", RTHAL_ARCH_NAME);
+}
+
+RTHAL_DECLARE_DOMAIN(rthal_domain_entry);
+
+/*@}*/
Index: xenomai/ksrc/arch/x86/hal_32.c
===================================================================
--- xenomai.orig/ksrc/arch/x86/hal_32.c
+++ xenomai/ksrc/arch/x86/hal_32.c
@@ -34,7 +34,7 @@
/**
* @addtogroup hal
*
- * x86-specific HAL services.
+ * i386-specific HAL services.
*
*@{*/
@@ -51,14 +51,6 @@
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
-#ifdef CONFIG_X86_LOCAL_APIC
-#include <asm/fixmap.h>
-#include <asm/mpspec.h>
-#ifdef CONFIG_X86_IO_APIC
-#include <asm/io_apic.h>
-#endif /* CONFIG_X86_IO_APIC */
-#include <asm/apic.h>
-#endif /* CONFIG_X86_LOCAL_APIC */
#include <asm/xenomai/hal.h>
#include <stdarg.h>
@@ -76,92 +68,8 @@ static void dummy_mksound(unsigned int h
#include <asm/nmi.h>
#endif
-static struct {
- unsigned long flags;
- int count;
-} rthal_linux_irq[IPIPE_NR_XIRQS];
-
-static enum { /* <!> Must follow enum clock_event_mode */
- KTIMER_MODE_UNUSED = 0,
- KTIMER_MODE_SHUTDOWN,
- KTIMER_MODE_PERIODIC,
- KTIMER_MODE_ONESHOT,
-} rthal_ktimer_saved_mode;
-
#ifdef CONFIG_X86_LOCAL_APIC
-static inline int rthal_set_apic_base(int lvtt_value)
-{
- if (APIC_INTEGRATED(GET_APIC_VERSION(apic_read(APIC_LVR))))
- lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);
-
- return lvtt_value;
-}
-
-static inline void rthal_setup_periodic_apic(int count, int vector)
-{
- apic_read_around(APIC_LVTT);
- apic_write_around(APIC_LVTT, rthal_set_apic_base(APIC_LVT_TIMER_PERIODIC | vector));
- apic_read_around(APIC_TMICT);
- apic_write_around(APIC_TMICT, count);
-}
-
-static inline void rthal_setup_oneshot_apic(int vector)
-{
- apic_read_around(APIC_LVTT);
- apic_write_around(APIC_LVTT, rthal_set_apic_base(vector));
-}
-
-#define RTHAL_SET_ONESHOT_XENOMAI 1
-#define RTHAL_SET_ONESHOT_LINUX 2
-#define RTHAL_SET_PERIODIC 3
-
-static void rthal_critical_sync(void)
-{
- switch (rthal_sync_op) {
- case RTHAL_SET_ONESHOT_XENOMAI:
- rthal_setup_oneshot_apic(RTHAL_APIC_TIMER_VECTOR);
- break;
-
- case RTHAL_SET_ONESHOT_LINUX:
- rthal_setup_oneshot_apic(LOCAL_TIMER_VECTOR);
- /* We need to keep the timing cycle alive for the kernel. */
- rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
- break;
-
- case RTHAL_SET_PERIODIC:
- rthal_setup_periodic_apic(RTHAL_APIC_ICOUNT, LOCAL_TIMER_VECTOR);
- break;
- }
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#include <asm/smpboot.h>
-static inline void send_IPI_all(int vector)
-{
- unsigned long flags;
-
- rthal_local_irq_save_hw(flags);
- apic_wait_icr_idle();
- apic_write_around(APIC_ICR,
- APIC_DM_FIXED | APIC_DEST_ALLINC | INT_DEST_ADDR_MODE
- | vector);
- rthal_local_irq_restore_hw(flags);
-}
-#else
-#include <mach_ipi.h>
-#endif
-
-DECLARE_LINUX_IRQ_HANDLER(rthal_broadcast_to_local_timers, irq, dev_id)
-{
-#ifdef CONFIG_SMP
- send_IPI_all(LOCAL_TIMER_VECTOR);
-#else
- rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
-#endif
- return IRQ_HANDLED;
-}
-
unsigned long rthal_timer_calibrate(void)
{
unsigned long flags, v;
@@ -218,7 +126,7 @@ void die_nmi(struct pt_regs *regs, const
#endif /* Linux < 2.6 */
-static void rthal_latency_above_max(struct pt_regs *regs)
+void rthal_latency_above_max(struct pt_regs *regs)
{
/* Try to report via latency tracer first, then fall back to panic. */
if (rthal_trace_user_freeze(rthal_maxlat_us, 1) < 0) {
@@ -234,141 +142,6 @@ static void rthal_latency_above_max(stru
#endif /* CONFIG_XENO_HW_NMI_DEBUG_LATENCY */
-static void rthal_timer_set_oneshot(int rt_mode)
-{
- unsigned long flags;
-
- flags = rthal_critical_enter(rthal_critical_sync);
- if (rt_mode) {
- rthal_sync_op = RTHAL_SET_ONESHOT_XENOMAI;
- rthal_setup_oneshot_apic(RTHAL_APIC_TIMER_VECTOR);
- } else {
- rthal_sync_op = RTHAL_SET_ONESHOT_LINUX;
- rthal_setup_oneshot_apic(LOCAL_TIMER_VECTOR);
- /* We need to keep the timing cycle alive for the kernel. */
- rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
- }
- rthal_critical_exit(flags);
-}
-
-static void rthal_timer_set_periodic(void)
-{
- unsigned long flags;
-
- flags = rthal_critical_enter(&rthal_critical_sync);
- rthal_sync_op = RTHAL_SET_PERIODIC;
- rthal_setup_periodic_apic(RTHAL_APIC_ICOUNT, LOCAL_TIMER_VECTOR);
- rthal_critical_exit(flags);
-}
-
-int rthal_timer_request(
- void (*tick_handler)(void),
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
- void (*mode_emul)(enum clock_event_mode mode,
- struct ipipe_tick_device *tdev),
- int (*tick_emul)(unsigned long delay,
- struct ipipe_tick_device *tdev),
-#endif
- int cpu)
-{
- int tickval, err;
-
- /* This code works both for UP+LAPIC and SMP configurations. */
-
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
- err = ipipe_request_tickdev("lapic", mode_emul, tick_emul, cpu);
-
- switch (err) {
- case CLOCK_EVT_MODE_PERIODIC:
- /* oneshot tick emulation callback won't be used, ask
- * the caller to start an internal timer for emulating
- * a periodic tick. */
- tickval = 1000000000UL / HZ;
- break;
-
- case CLOCK_EVT_MODE_ONESHOT:
- /* oneshot tick emulation */
- tickval = 1;
- break;
-
- case CLOCK_EVT_MODE_UNUSED:
- /* we don't need to emulate the tick at all. */
- tickval = 0;
- break;
-
- case CLOCK_EVT_MODE_SHUTDOWN:
- return -ENODEV;
-
- default:
- return err;
- }
-
- rthal_ktimer_saved_mode = err;
-#else /* !CONFIG_GENERIC_CLOCKEVENTS */
- /*
- * When the local APIC is enabled for kernels lacking generic
- * support for clock events, we do not need to relay the host tick
- * since 8254 interrupts are already flowing normally to Linux
- * (i.e. the nucleus does not intercept them, but uses a dedicated
- * APIC-based timer interrupt instead, i.e. RTHAL_APIC_TIMER_IPI).
- */
- tickval = 0;
- rthal_ktimer_saved_mode = KTIMER_MODE_PERIODIC;
-#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
-
- /*
- * The rest of the initialization should only be performed
- * once by a single CPU.
- */
- if (cpu > 0)
- goto out;
-
- rthal_timer_set_oneshot(1);
-
- err = rthal_irq_request(RTHAL_APIC_TIMER_IPI,
- (rthal_irq_handler_t) tick_handler, NULL, NULL);
-
- if (err)
- return err;
-
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
- rthal_irq_host_request(RTHAL_BCAST_TICK_IRQ,
- &rthal_broadcast_to_local_timers,
- "rthal_broadcast_timer",
- &rthal_broadcast_to_local_timers);
-#endif
-
- rthal_nmi_init(&rthal_latency_above_max);
-out:
- return tickval;
-}
-
-void rthal_timer_release(int cpu)
-{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
- ipipe_release_tickdev(cpu);
-#else
- rthal_irq_host_release(RTHAL_BCAST_TICK_IRQ,
- &rthal_broadcast_to_local_timers);
-#endif
-
- /*
- * The rest of the cleanup work should only be performed once
- * by a single CPU.
- */
- if (cpu > 0)
- return;
-
- rthal_nmi_release();
-
- rthal_irq_release(RTHAL_APIC_TIMER_IPI);
-
- if (rthal_ktimer_saved_mode == KTIMER_MODE_PERIODIC)
- rthal_timer_set_periodic();
- else if (rthal_ktimer_saved_mode == KTIMER_MODE_ONESHOT)
- rthal_timer_set_oneshot(0);
-}
-
#else /* !CONFIG_X86_LOCAL_APIC */
unsigned long rthal_timer_calibrate(void)
@@ -531,7 +304,7 @@ void rthal_timer_release(int cpu)
rthal_trigger_irq(RTHAL_TIMER_IRQ);
}
-#endif /* CONFIG_X86_LOCAL_APIC */
+#endif /* !CONFIG_X86_LOCAL_APIC */
#ifndef CONFIG_X86_TSC
@@ -584,146 +357,6 @@ rthal_time_t rthal_get_8254_tsc(void)
#endif /* !CONFIG_X86_TSC */
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
-void rthal_timer_notify_switch(enum clock_event_mode mode,
- struct ipipe_tick_device *tdev)
-{
- if (rthal_processor_id() > 0)
- /*
- * We assume all CPUs switch the same way, so we only
- * track mode switches from the boot CPU.
- */
- return;
-
- rthal_ktimer_saved_mode = mode;
-}
-
-EXPORT_SYMBOL(rthal_timer_notify_switch);
-
-#endif /* CONFIG_GENERIC_CLOCKEVENTS */
-
-int rthal_irq_host_request(unsigned irq,
- rthal_irq_host_handler_t handler,
- char *name, void *dev_id)
-{
- unsigned long flags;
-
- if (irq >= IPIPE_NR_XIRQS || !handler)
- return -EINVAL;
-
- spin_lock_irqsave(&rthal_irq_descp(irq)->lock, flags);
-
- if (rthal_linux_irq[irq].count++ == 0 && rthal_irq_descp(irq)->action) {
- rthal_linux_irq[irq].flags =
- rthal_irq_descp(irq)->action->flags;
- rthal_irq_descp(irq)->action->flags |= IRQF_SHARED;
- }
-
- spin_unlock_irqrestore(&rthal_irq_descp(irq)->lock, flags);
-
- return request_irq(irq, handler, IRQF_SHARED, name, dev_id);
-}
-
-int rthal_irq_host_release(unsigned irq, void *dev_id)
-{
- unsigned long flags;
-
- if (irq >= NR_IRQS || rthal_linux_irq[irq].count == 0)
- return -EINVAL;
-
- free_irq(irq, dev_id);
-
- spin_lock_irqsave(&rthal_irq_descp(irq)->lock, flags);
-
- if (--rthal_linux_irq[irq].count == 0 && rthal_irq_descp(irq)->action)
- rthal_irq_descp(irq)->action->flags =
- rthal_linux_irq[irq].flags;
-
- spin_unlock_irqrestore(&rthal_irq_descp(irq)->lock, flags);
-
- return 0;
-}
-
-int rthal_irq_enable(unsigned irq)
-{
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- rthal_irq_desc_status(irq) &= ~IRQ_DISABLED;
-
- return rthal_irq_chip_enable(irq);
-}
-
-int rthal_irq_disable(unsigned irq)
-{
-
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- rthal_irq_desc_status(irq) |= IRQ_DISABLED;
-
- return rthal_irq_chip_disable(irq);
-}
-
-int rthal_irq_end(unsigned irq)
-{
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- return rthal_irq_chip_end(irq);
-}
-
-static inline int do_exception_event(unsigned event, unsigned domid, void *data)
-{
- /* Notes:
-
- 1) GPF needs to be propagated downstream whichever domain caused
- it. This is required so that we don't spuriously raise a fatal
- error when some fixup code is available to solve the error
- condition. For instance, Linux always attempts to reload the %gs
- segment register when switching a process in (__switch_to()),
- regardless of its value. It is then up to Linux's GPF handling
- code to search for a possible fixup whenever some exception
- occurs. In the particular case of the %gs register, such an
- exception could be raised for an exiting process if a preemption
- occurs inside a short time window, after the process's LDT has
- been dropped, but before the kernel lock is taken. The same goes
- for Xenomai switching back a Linux thread in non-RT mode which
- happens to have been preempted inside do_exit() after the MM
- context has been dropped (thus the LDT too). In such a case, %gs
- could be reloaded with what used to be the TLS descriptor of the
- exiting thread, but unfortunately after the LDT itself has been
- dropped. Since the default LDT is only 5 entries long, any attempt
- to refer to an LDT-indexed descriptor above this value would cause
- a GPF. 2) NMI is not pipelined. */
-
- if (domid == RTHAL_DOMAIN_ID) {
- rthal_realtime_faults[rthal_processor_id()][event]++;
-
- if (rthal_trap_handler != NULL &&
- rthal_trap_handler(event, domid, data) != 0)
- return RTHAL_EVENT_STOP;
- }
-
- return RTHAL_EVENT_PROPAGATE;
-}
-
-RTHAL_DECLARE_EVENT(exception_event);
-
-static inline void do_rthal_domain_entry(void)
-{
- unsigned trapnr;
-
- /* Trap all faults. */
- for (trapnr = 0; trapnr < RTHAL_NR_FAULTS; trapnr++)
- rthal_catch_exception(trapnr, &exception_event);
-
- printk(KERN_INFO "Xenomai: hal/x86 started.\n");
-}
-
-RTHAL_DECLARE_DOMAIN(rthal_domain_entry);
-
int rthal_arch_init(void)
{
#ifdef CONFIG_X86_LOCAL_APIC
@@ -777,7 +410,7 @@ void rthal_arch_cleanup(void)
/* Restore previous PC speaker code. */
kd_mksound = old_mksound;
#endif /* Linux < 2.6 && !CONFIG_X86_TSC && CONFIG_VT */
- printk(KERN_INFO "Xenomai: hal/x86 stopped.\n");
+ printk(KERN_INFO "Xenomai: hal/i386 stopped.\n");
}
/*@}*/
Index: xenomai/ksrc/arch/x86/hal_64.c
===================================================================
--- xenomai.orig/ksrc/arch/x86/hal_64.c
+++ xenomai/ksrc/arch/x86/hal_64.c
@@ -43,70 +43,9 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
-#include <asm/fixmap.h>
-#include <asm/mpspec.h>
-#include <asm/io_apic.h>
-#include <asm/apic.h>
#include <asm/xenomai/hal.h>
-#include <asm/mach_apic.h>
#include <stdarg.h>
-#define RTHAL_SET_ONESHOT_XENOMAI 1
-#define RTHAL_SET_ONESHOT_LINUX 2
-#define RTHAL_SET_PERIODIC 3
-
-static enum { /* <!> Must follow enum clock_event_mode */
- KTIMER_MODE_UNUSED = 0,
- KTIMER_MODE_SHUTDOWN,
- KTIMER_MODE_PERIODIC,
- KTIMER_MODE_ONESHOT,
-} rthal_ktimer_saved_mode;
-
-static struct {
- unsigned long flags;
- int count;
-} rthal_linux_irq[IPIPE_NR_XIRQS];
-
-static inline void rthal_setup_periodic_apic(int count, int vector)
-{
- apic_write(APIC_LVTT, APIC_LVT_TIMER_PERIODIC | vector);
- apic_write(APIC_TMICT, count);
-}
-
-static inline void rthal_setup_oneshot_apic(int vector)
-{
- apic_write(APIC_LVTT, vector);
-}
-
-static void rthal_critical_sync(void)
-{
- switch (rthal_sync_op) {
- case RTHAL_SET_ONESHOT_XENOMAI:
- rthal_setup_oneshot_apic(RTHAL_APIC_TIMER_VECTOR);
- break;
-
- case RTHAL_SET_ONESHOT_LINUX:
- rthal_setup_oneshot_apic(LOCAL_TIMER_VECTOR);
- /* We need to keep the timing cycle alive for the kernel. */
- rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
- break;
-
- case RTHAL_SET_PERIODIC:
- rthal_setup_periodic_apic(RTHAL_APIC_ICOUNT, LOCAL_TIMER_VECTOR);
- break;
- }
-}
-
-irqreturn_t rthal_broadcast_to_local_timers(int irq, void *dev_id)
-{
-#ifdef CONFIG_SMP
- send_IPI_all(LOCAL_TIMER_VECTOR);
-#else
- rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
-#endif
- return IRQ_HANDLED;
-}
-
unsigned long rthal_timer_calibrate(void)
{
unsigned long v, flags;
@@ -134,258 +73,6 @@ unsigned long rthal_timer_calibrate(void
return rthal_imuldiv(dt, 20, RTHAL_CPU_FREQ);
}
-static void rthal_timer_set_oneshot(int rt_mode)
-{
- unsigned long flags;
-
- flags = rthal_critical_enter(rthal_critical_sync);
- if (rt_mode) {
- rthal_sync_op = RTHAL_SET_ONESHOT_XENOMAI;
- rthal_setup_oneshot_apic(RTHAL_APIC_TIMER_VECTOR);
- } else {
- rthal_sync_op = RTHAL_SET_ONESHOT_LINUX;
- rthal_setup_oneshot_apic(LOCAL_TIMER_VECTOR);
- /* We need to keep the timing cycle alive for the kernel. */
- rthal_trigger_irq(ipipe_apic_vector_irq(LOCAL_TIMER_VECTOR));
- }
- rthal_critical_exit(flags);
-}
-
-static void rthal_timer_set_periodic(void)
-{
- unsigned long flags;
-
- flags = rthal_critical_enter(&rthal_critical_sync);
- rthal_sync_op = RTHAL_SET_PERIODIC;
- rthal_setup_periodic_apic(RTHAL_APIC_ICOUNT, LOCAL_TIMER_VECTOR);
- rthal_critical_exit(flags);
-}
-
-int rthal_timer_request(
- void (*tick_handler)(void),
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
- void (*mode_emul)(enum clock_event_mode mode,
- struct ipipe_tick_device *tdev),
- int (*tick_emul)(unsigned long delay,
- struct ipipe_tick_device *tdev),
-#endif
- int cpu)
-{
- int tickval, err;
-
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
- err = ipipe_request_tickdev("lapic", mode_emul, tick_emul, cpu);
-
- switch (err) {
- case CLOCK_EVT_MODE_PERIODIC:
- /* oneshot tick emulation callback won't be used, ask
- * the caller to start an internal timer for emulating
- * a periodic tick. */
- tickval = 1000000000UL / HZ;
- break;
-
- case CLOCK_EVT_MODE_ONESHOT:
- /* oneshot tick emulation */
- tickval = 1;
- break;
-
- case CLOCK_EVT_MODE_UNUSED:
- /* we don't need to emulate the tick at all. */
- tickval = 0;
- break;
-
- case CLOCK_EVT_MODE_SHUTDOWN:
- return -ENODEV;
-
- default:
- return err;
- }
-
- rthal_ktimer_saved_mode = err;
-#else /* !CONFIG_GENERIC_CLOCKEVENTS */
- /*
- * When the local APIC is enabled for kernels lacking generic
- * support for clock events, we do not need to relay the host tick
- * since 8254 interrupts are already flowing normally to Linux
- * (i.e. the nucleus does not intercept them, but uses a dedicated
- * APIC-based timer interrupt instead, i.e. RTHAL_APIC_TIMER_IPI).
- */
- tickval = 0;
- rthal_ktimer_saved_mode = KTIMER_MODE_PERIODIC;
-#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
-
- /*
- * The rest of the initialization should only be performed
- * once by a single CPU.
- */
- if (cpu > 0)
- goto out;
-
- rthal_timer_set_oneshot(1);
-
- err = rthal_irq_request(RTHAL_APIC_TIMER_IPI,
- (rthal_irq_handler_t) tick_handler, NULL, NULL);
-
- if (err)
- return err;
-
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
- rthal_irq_host_request(RTHAL_BCAST_TICK_IRQ,
- &rthal_broadcast_to_local_timers,
- "rthal_broadcast_timer",
- &rthal_broadcast_to_local_timers);
-#endif
-
- rthal_nmi_init(&rthal_latency_above_max);
-out:
- return tickval;
-}
-
-void rthal_timer_release(int cpu)
-{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
- ipipe_release_tickdev(cpu);
-#else
- rthal_irq_host_release(RTHAL_BCAST_TICK_IRQ,
- &rthal_broadcast_to_local_timers);
-#endif
-
- /*
- * The rest of the cleanup work should only be performed once
- * by a single CPU.
- */
- if (cpu > 0)
- return;
-
- rthal_nmi_release();
-
- rthal_irq_release(RTHAL_APIC_TIMER_IPI);
-
- if (rthal_ktimer_saved_mode == KTIMER_MODE_PERIODIC)
- rthal_timer_set_periodic();
- else if (rthal_ktimer_saved_mode == KTIMER_MODE_ONESHOT)
- rthal_timer_set_oneshot(0);
-}
-
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
-void rthal_timer_notify_switch(enum clock_event_mode mode,
- struct ipipe_tick_device *tdev)
-{
- if (rthal_processor_id() > 0)
- /*
- * We assume all CPUs switch the same way, so we only
- * track mode switches from the boot CPU.
- */
- return;
-
- rthal_ktimer_saved_mode = mode;
-}
-
-EXPORT_SYMBOL(rthal_timer_notify_switch);
-
-#endif /* CONFIG_GENERIC_CLOCKEVENTS */
-
-int rthal_irq_host_request(unsigned irq,
- rthal_irq_host_handler_t handler,
- char *name, void *dev_id)
-{
- unsigned long flags;
-
- if (irq >= IPIPE_NR_XIRQS || !handler)
- return -EINVAL;
-
- spin_lock_irqsave(&rthal_irq_descp(irq)->lock, flags);
-
- if (rthal_linux_irq[irq].count++ == 0 && rthal_irq_descp(irq)->action) {
- rthal_linux_irq[irq].flags =
- rthal_irq_descp(irq)->action->flags;
- rthal_irq_descp(irq)->action->flags |= IRQF_SHARED;
- }
-
- spin_unlock_irqrestore(&rthal_irq_descp(irq)->lock, flags);
-
- return request_irq(irq, handler, IRQF_SHARED, name, dev_id);
-}
-
-int rthal_irq_host_release(unsigned irq, void *dev_id)
-{
- unsigned long flags;
-
- if (irq >= NR_IRQS || rthal_linux_irq[irq].count == 0)
- return -EINVAL;
-
- free_irq(irq, dev_id);
-
- spin_lock_irqsave(&rthal_irq_descp(irq)->lock, flags);
-
- if (--rthal_linux_irq[irq].count == 0 && rthal_irq_descp(irq)->action)
- rthal_irq_descp(irq)->action->flags =
- rthal_linux_irq[irq].flags;
-
- spin_unlock_irqrestore(&rthal_irq_descp(irq)->lock, flags);
-
- return 0;
-}
-
-int rthal_irq_enable(unsigned irq)
-{
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- rthal_irq_desc_status(irq) &= ~IRQ_DISABLED;
-
- return rthal_irq_chip_enable(irq);
-}
-
-int rthal_irq_disable(unsigned irq)
-{
-
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- rthal_irq_desc_status(irq) |= IRQ_DISABLED;
-
- return rthal_irq_chip_disable(irq);
-}
-
-int rthal_irq_end(unsigned irq)
-{
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- return rthal_irq_chip_end(irq);
-}
-
-static inline int do_exception_event(unsigned event, unsigned domid, void *data)
-{
-
- if (domid == RTHAL_DOMAIN_ID) {
- rthal_realtime_faults[rthal_processor_id()][event]++;
-
- if (rthal_trap_handler != NULL &&
- rthal_trap_handler(event, domid, data) != 0)
- return RTHAL_EVENT_STOP;
- }
-
- return RTHAL_EVENT_PROPAGATE;
-}
-
-RTHAL_DECLARE_EVENT(exception_event);
-
-static inline void do_rthal_domain_entry(void)
-{
- unsigned trapnr;
-
- /* Trap all faults. */
- for (trapnr = 0; trapnr < RTHAL_NR_FAULTS; trapnr++)
- rthal_catch_exception(trapnr, &exception_event);
-
- printk(KERN_INFO "Xenomai: hal/x86_64 started.\n");
-}
-
-RTHAL_DECLARE_DOMAIN(rthal_domain_entry);
-
int rthal_arch_init(void)
{
if (rthal_cpufreq_arg == 0)
Index: xenomai/include/asm-x86/wrappers_64.h
===================================================================
--- xenomai.orig/include/asm-x86/wrappers_64.h
+++ xenomai/include/asm-x86/wrappers_64.h
@@ -37,4 +37,7 @@
typedef irq_handler_t rthal_irq_host_handler_t;
+#define DECLARE_LINUX_IRQ_HANDLER(fn, irq, dev_id) \
+ irqreturn_t fn(int irq, void *dev_id)
+
#endif /* _XENO_ASM_X86_WRAPPERS_64_H */
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2007-11-01 11:31 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-01 11:31 [Xenomai-core] [RFC][PATCH] refactor x86/hal_*.c Jan Kiszka
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.