* [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector @ 2009-03-04 18:54 Dimitri Sivanich 2009-03-04 18:56 ` [PATCH 1/3 v7] SGI RTC: add " Dimitri Sivanich 2009-03-04 19:46 ` [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector Ingo Molnar 0 siblings, 2 replies; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 18:54 UTC (permalink / raw) To: Ingo Molnar Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, john stultz, linux-kernel The following patches provide UV RTC driven clocksource and clockevents for SGI systems, as well as introducing a generic system interrupt vector. With these patches, the UV system-wide synchronized RTC clock and timers are used as clocksource and clockevents running in high resolution mode. Subject: [PATCH 1/3 v7] SGI RTC: add generic system vector Subject: [PATCH 2/3 v7] SGI RTC: loop through installed UV blades Subject: [PATCH 3/3 v7] SGI RTC: add UV RTC clocksource/clockevents ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/3 v7] SGI RTC: add generic system vector 2009-03-04 18:54 [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector Dimitri Sivanich @ 2009-03-04 18:56 ` Dimitri Sivanich 2009-03-04 18:57 ` [PATCH 2/3 v7] SGI RTC: loop through installed UV blades Dimitri Sivanich ` (2 more replies) 2009-03-04 19:46 ` [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector Ingo Molnar 1 sibling, 3 replies; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 18:56 UTC (permalink / raw) To: Ingo Molnar Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, john stultz, linux-kernel This patch allocates a system interrupt vector for various platform specific uses. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> --- Made suggested simplifications and made symmetric across 32/64 bit. arch/x86/include/asm/entry_arch.h | 2 + arch/x86/include/asm/hardirq.h | 1 arch/x86/include/asm/hw_irq.h | 1 arch/x86/include/asm/irq.h | 1 arch/x86/include/asm/irq_vectors.h | 5 ++++ arch/x86/kernel/entry_64.S | 2 + arch/x86/kernel/irq.c | 34 +++++++++++++++++++++++++++++++++ arch/x86/kernel/irqinit_32.c | 3 ++ arch/x86/kernel/irqinit_64.c | 3 ++ 9 files changed, 52 insertions(+) Index: linux/arch/x86/kernel/entry_64.S =================================================================== --- linux.orig/arch/x86/kernel/entry_64.S 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/kernel/entry_64.S 2009-03-04 11:07:51.000000000 -0600 @@ -984,6 +984,8 @@ apicinterrupt UV_BAU_MESSAGE \ #endif apicinterrupt LOCAL_TIMER_VECTOR \ apic_timer_interrupt smp_apic_timer_interrupt +apicinterrupt GENERIC_INTERRUPT_VECTOR \ + generic_interrupt smp_generic_interrupt #ifdef CONFIG_SMP apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \ Index: linux/arch/x86/kernel/irqinit_64.c =================================================================== --- linux.orig/arch/x86/kernel/irqinit_64.c 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/kernel/irqinit_64.c 2009-03-04 11:07:51.000000000 -0600 @@ -147,6 +147,9 @@ static void __init apic_intr_init(void) /* self generated IPI for local APIC timer */ alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); + /* generic IPI for platform specific use */ + alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt); + /* IPI vectors for APIC spurious and error interrupts */ alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); Index: linux/arch/x86/include/asm/irq_vectors.h =================================================================== --- linux.orig/arch/x86/include/asm/irq_vectors.h 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/include/asm/irq_vectors.h 2009-03-04 11:07:51.000000000 -0600 @@ -112,6 +112,11 @@ #define LOCAL_PERF_VECTOR 0xee /* + * Generic system vector for platform specific use + */ +#define GENERIC_INTERRUPT_VECTOR 0xed + +/* * First APIC vector available to drivers: (vectors 0x30-0xee) we * start at 0x31(0x41) to spread out vectors evenly between priority * levels. (0x80 is the syscall vector) Index: linux/arch/x86/include/asm/hw_irq.h =================================================================== --- linux.orig/arch/x86/include/asm/hw_irq.h 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/include/asm/hw_irq.h 2009-03-04 11:07:51.000000000 -0600 @@ -27,6 +27,7 @@ /* Interrupt handlers registered during init_IRQ */ extern void apic_timer_interrupt(void); +extern void generic_interrupt(void); extern void error_interrupt(void); extern void perf_counter_interrupt(void); Index: linux/arch/x86/include/asm/irq.h =================================================================== --- linux.orig/arch/x86/include/asm/irq.h 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/include/asm/irq.h 2009-03-04 11:07:51.000000000 -0600 @@ -36,6 +36,7 @@ static inline int irq_canonicalize(int i extern void fixup_irqs(void); #endif +extern void (*generic_interrupt_extension)(void); extern void init_IRQ(void); extern void native_init_IRQ(void); extern bool handle_irq(unsigned irq, struct pt_regs *regs); Index: linux/arch/x86/kernel/irq.c =================================================================== --- linux.orig/arch/x86/kernel/irq.c 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/kernel/irq.c 2009-03-04 11:07:51.000000000 -0600 @@ -15,6 +15,9 @@ atomic_t irq_err_count; +/* Function pointer for generic interrupt vector handling */ +void (*generic_interrupt_extension)(void) = NULL; + /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves. @@ -60,6 +63,12 @@ static int show_other_interrupts(struct seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs); seq_printf(p, " Performance counter interrupts\n"); #endif + if (generic_interrupt_extension) { + seq_printf(p, "PLT: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", irq_stats(j)->generic_irqs); + seq_printf(p, " Platform interrupts\n"); + } #ifdef CONFIG_SMP seq_printf(p, "RES: "); for_each_online_cpu(j) @@ -168,6 +177,8 @@ u64 arch_irq_stat_cpu(unsigned int cpu) sum += irq_stats(cpu)->apic_timer_irqs; sum += irq_stats(cpu)->apic_perf_irqs; #endif + if (generic_interrupt_extension) + sum += irq_stats(cpu)->generic_irqs; #ifdef CONFIG_SMP sum += irq_stats(cpu)->irq_resched_count; sum += irq_stats(cpu)->irq_call_count; @@ -231,4 +242,27 @@ unsigned int __irq_entry do_IRQ(struct p return 1; } +/* + * Handler for GENERIC_INTERRUPT_VECTOR. + */ +void smp_generic_interrupt(struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + ack_APIC_irq(); + + exit_idle(); + + irq_enter(); + + inc_irq_stat(generic_irqs); + + if (generic_interrupt_extension) + generic_interrupt_extension(); + + irq_exit(); + + set_irq_regs(old_regs); +} + EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); Index: linux/arch/x86/include/asm/hardirq.h =================================================================== --- linux.orig/arch/x86/include/asm/hardirq.h 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/include/asm/hardirq.h 2009-03-04 11:07:51.000000000 -0600 @@ -13,6 +13,7 @@ typedef struct { unsigned int irq_spurious_count; #endif unsigned int apic_perf_irqs; + unsigned int generic_irqs; /* arch dependent */ #ifdef CONFIG_SMP unsigned int irq_resched_count; unsigned int irq_call_count; Index: linux/arch/x86/include/asm/entry_arch.h =================================================================== --- linux.orig/arch/x86/include/asm/entry_arch.h 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/include/asm/entry_arch.h 2009-03-04 11:07:51.000000000 -0600 @@ -33,6 +33,8 @@ BUILD_INTERRUPT3(invalidate_interrupt7,I smp_invalidate_interrupt) #endif +BUILD_INTERRUPT(generic_interrupt, GENERIC_INTERRUPT_VECTOR) + /* * every pentium local APIC has two 'local interrupts', with a * soft-definable vector attached to both interrupts, one of Index: linux/arch/x86/kernel/irqinit_32.c =================================================================== --- linux.orig/arch/x86/kernel/irqinit_32.c 2009-03-04 11:07:48.000000000 -0600 +++ linux/arch/x86/kernel/irqinit_32.c 2009-03-04 11:07:51.000000000 -0600 @@ -160,6 +160,9 @@ static void __init apic_intr_init(void) /* self generated IPI for local APIC timer */ alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); + /* generic IPI for platform specific use */ + alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt); + /* IPI vectors for APIC spurious and error interrupts */ alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/3 v7] SGI RTC: loop through installed UV blades 2009-03-04 18:56 ` [PATCH 1/3 v7] SGI RTC: add " Dimitri Sivanich @ 2009-03-04 18:57 ` Dimitri Sivanich 2009-03-04 18:59 ` [PATCH 3/3 v7] SGI RTC: add UV RTC clocksource/clockevents Dimitri Sivanich 2009-03-04 19:48 ` [tip:x86/uv] x86: UV, SGI RTC: loop through installed UV blades Dimitri Sivanich 2009-03-04 19:48 ` [tip:x86/uv] x86: UV, SGI RTC: add generic system vector Dimitri Sivanich 2009-03-05 14:18 ` [tip:x86/uv] x86: UV, SGI RTC: add generic system vector, build fix on UP Ingo Molnar 2 siblings, 2 replies; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 18:57 UTC (permalink / raw) To: Ingo Molnar Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, john stultz, linux-kernel Add macro to loop through each possible blade. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> --- arch/x86/include/asm/uv/uv_hub.h | 4 ++++ 1 file changed, 4 insertions(+) Index: linux/arch/x86/include/asm/uv/uv_hub.h =================================================================== --- linux.orig/arch/x86/include/asm/uv/uv_hub.h 2009-03-04 09:38:04.000000000 -0600 +++ linux/arch/x86/include/asm/uv/uv_hub.h 2009-03-04 10:51:20.000000000 -0600 @@ -199,6 +199,10 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __ #define SCIR_CPU_ACTIVITY 0x02 /* not idle */ #define SCIR_CPU_HB_INTERVAL (HZ) /* once per second */ +/* Loop through all installed blades */ +#define for_each_possible_blade(bid) \ + for ((bid) = 0; (bid) < uv_num_possible_blades(); (bid)++) + /* * Macros for converting between kernel virtual addresses, socket local physical * addresses, and UV global physical addresses. ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 3/3 v7] SGI RTC: add UV RTC clocksource/clockevents 2009-03-04 18:57 ` [PATCH 2/3 v7] SGI RTC: loop through installed UV blades Dimitri Sivanich @ 2009-03-04 18:59 ` Dimitri Sivanich 2009-03-04 19:48 ` [tip:x86/uv] x86: UV, " Dimitri Sivanich 2009-03-04 19:48 ` [tip:x86/uv] x86: UV, SGI RTC: loop through installed UV blades Dimitri Sivanich 1 sibling, 1 reply; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 18:59 UTC (permalink / raw) To: Ingo Molnar Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, john stultz, linux-kernel This patch provides a high resolution clock/timer source using the SGI UV system-wide synchronized RTC clock/timer hardware. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> --- Made suggested simplifications. arch/x86/kernel/Makefile | 2 arch/x86/kernel/uv_time.c | 386 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 387 insertions(+), 1 deletion(-) Index: linux/arch/x86/kernel/uv_time.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/arch/x86/kernel/uv_time.c 2009-03-04 11:20:38.000000000 -0600 @@ -0,0 +1,386 @@ +/* + * SGI RTC clock/timer routines. + * + * This program 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. + * + * This program 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 + * + * Copyright (c) 2009 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Dimitri Sivanich + */ +#include <linux/clockchips.h> +#include <asm/uv/uv.h> +#include <asm/uv/uv_mmrs.h> +#include <asm/uv/uv_hub.h> +#include <asm/uv/bios.h> + +#define RTC_NAME "sgi_rtc" + +static cycle_t uv_read_rtc(void); +static int uv_rtc_next_event(unsigned long, struct clock_event_device *); +static void uv_rtc_timer_setup(enum clock_event_mode, + struct clock_event_device *); + +static struct clocksource clocksource_uv = { + .name = RTC_NAME, + .rating = 400, + .read = uv_read_rtc, + .mask = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK, + .shift = 10, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static struct clock_event_device clock_event_device_uv = { + .name = RTC_NAME, + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 20, + .rating = 400, + .irq = -1, + .set_next_event = uv_rtc_next_event, + .set_mode = uv_rtc_timer_setup, + .event_handler = NULL, +}; + +static DEFINE_PER_CPU(struct clock_event_device, cpu_ced); + +/* There is one of these allocated per node */ +struct uv_rtc_timer_head { + spinlock_t lock; + int next_cpu; /* next cpu waiting for timer, local node relative */ + int ncpus; /* number of cpus on this node */ + struct { + int lcpu; /* systemwide logical cpu number */ + u64 expires; /* next timer expiration for this cpu */ + } cpu[1]; +}; + +/* + * Access to uv_rtc_timer_head via blade id. + */ +static struct uv_rtc_timer_head **blade_info __read_mostly; + +static int uv_rtc_enable; + +/* + * Hardware interface routines + */ + +/* Send IPIs to another node */ +static void uv_rtc_send_IPI(int cpu) +{ + unsigned long apicid, val; + int pnode; + + apicid = per_cpu(x86_cpu_to_apicid, cpu); + pnode = uv_apicid_to_pnode(apicid); + val = (1UL << UVH_IPI_INT_SEND_SHFT) | + (apicid << UVH_IPI_INT_APIC_ID_SHFT) | + (GENERIC_INTERRUPT_VECTOR << UVH_IPI_INT_VECTOR_SHFT); + + uv_write_global_mmr64(pnode, UVH_IPI_INT, val); +} + +/* Check for an RTC interrupt pending */ +static int uv_intr_pending(int pnode) +{ + return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) & + UVH_EVENT_OCCURRED0_RTC1_MASK; +} + +/* Setup interrupt and return non-zero if early expiration occurred. */ +static int uv_setup_intr(int cpu, u64 expires) +{ + u64 val; + int pnode = uv_cpu_to_pnode(cpu); + + uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, + UVH_RTC1_INT_CONFIG_M_MASK); + uv_write_global_mmr64(pnode, UVH_INT_CMPB, -1L); + + uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS, + UVH_EVENT_OCCURRED0_RTC1_MASK); + + val = (GENERIC_INTERRUPT_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) | + ((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT); + + /* Set configuration */ + uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val); + /* Initialize comparator value */ + uv_write_global_mmr64(pnode, UVH_INT_CMPB, expires); + + return (expires < uv_read_rtc() && !uv_intr_pending(pnode)); +} + +/* + * Per-cpu timer tracking routines + */ + +static __init void uv_rtc_deallocate_timers(void) +{ + int bid; + + for_each_possible_blade(bid) { + kfree(blade_info[bid]); + } + kfree(blade_info); +} + +/* Allocate per-node list of cpu timer expiration times. */ +static __init int uv_rtc_allocate_timers(void) +{ + int cpu; + + blade_info = kmalloc(uv_possible_blades * sizeof(void *), GFP_KERNEL); + if (!blade_info) + return -ENOMEM; + memset(blade_info, 0, uv_possible_blades * sizeof(void *)); + + for_each_present_cpu(cpu) { + int nid = cpu_to_node(cpu); + int bid = uv_cpu_to_blade_id(cpu); + int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id; + struct uv_rtc_timer_head *head = blade_info[bid]; + + if (!head) { + head = kmalloc_node(sizeof(struct uv_rtc_timer_head) + + (uv_blade_nr_possible_cpus(bid) * + 2 * sizeof(u64)), + GFP_KERNEL, nid); + if (!head) { + uv_rtc_deallocate_timers(); + return -ENOMEM; + } + spin_lock_init(&head->lock); + head->ncpus = uv_blade_nr_possible_cpus(bid); + head->next_cpu = -1; + blade_info[bid] = head; + } + + head->cpu[bcpu].lcpu = cpu; + head->cpu[bcpu].expires = ULLONG_MAX; + } + + return 0; +} + +/* Find and set the next expiring timer. */ +static void uv_rtc_find_next_timer(struct uv_rtc_timer_head *head, int pnode) +{ + u64 lowest = ULLONG_MAX; + int c, bcpu = -1; + + head->next_cpu = -1; + for (c = 0; c < head->ncpus; c++) { + u64 exp = head->cpu[c].expires; + if (exp < lowest) { + bcpu = c; + lowest = exp; + } + } + if (bcpu >= 0) { + head->next_cpu = bcpu; + c = head->cpu[bcpu].lcpu; + if (uv_setup_intr(c, lowest)) + /* If we didn't set it up in time, trigger */ + uv_rtc_send_IPI(c); + } else + uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, + UVH_RTC1_INT_CONFIG_M_MASK); +} + +/* + * Set expiration time for current cpu. + * + * Returns 1 if we missed the expiration time. + */ +static int uv_rtc_set_timer(int cpu, u64 expires) +{ + int pnode = uv_cpu_to_pnode(cpu); + int bid = uv_cpu_to_blade_id(cpu); + struct uv_rtc_timer_head *head = blade_info[bid]; + int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id; + u64 *t = &head->cpu[bcpu].expires; + unsigned long flags; + int next_cpu; + + spin_lock_irqsave(&head->lock, flags); + + next_cpu = head->next_cpu; + *t = expires; + /* Will this one be next to go off? */ + if (next_cpu < 0 || bcpu == next_cpu || + expires < head->cpu[next_cpu].expires) { + head->next_cpu = bcpu; + if (uv_setup_intr(cpu, expires)) { + *t = ULLONG_MAX; + uv_rtc_find_next_timer(head, pnode); + spin_unlock_irqrestore(&head->lock, flags); + return 1; + } + } + + spin_unlock_irqrestore(&head->lock, flags); + return 0; +} + +/* + * Unset expiration time for current cpu. + * + * Returns 1 if this timer was pending. + */ +static int uv_rtc_unset_timer(int cpu) +{ + int pnode = uv_cpu_to_pnode(cpu); + int bid = uv_cpu_to_blade_id(cpu); + struct uv_rtc_timer_head *head = blade_info[bid]; + int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id; + u64 *t = &head->cpu[bcpu].expires; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&head->lock, flags); + + if (head->next_cpu == bcpu && uv_read_rtc() >= *t) + rc = 1; + + *t = ULLONG_MAX; + + /* Was the hardware setup for this timer? */ + if (head->next_cpu == bcpu) + uv_rtc_find_next_timer(head, pnode); + + spin_unlock_irqrestore(&head->lock, flags); + return rc; +} + + +/* + * Kernel interface routines. + */ + +/* + * Read the RTC. + */ +static cycle_t uv_read_rtc(void) +{ + return (cycle_t)uv_read_local_mmr(UVH_RTC); +} + +/* + * Program the next event, relative to now + */ +static int uv_rtc_next_event(unsigned long delta, + struct clock_event_device *ced) +{ + int ced_cpu = cpumask_first(ced->cpumask); + + return uv_rtc_set_timer(ced_cpu, delta + uv_read_rtc()); +} + +/* + * Setup the RTC timer in oneshot mode + */ +static void uv_rtc_timer_setup(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + int ced_cpu = cpumask_first(evt->cpumask); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_RESUME: + /* Nothing to do here yet */ + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + uv_rtc_unset_timer(ced_cpu); + break; + } +} + +static void uv_rtc_interrupt(void) +{ + struct clock_event_device *ced = &__get_cpu_var(cpu_ced); + int cpu = smp_processor_id(); + + if (!ced || !ced->event_handler) + return; + + if (uv_rtc_unset_timer(cpu) != 1) + return; + + ced->event_handler(ced); +} + +static int __init uv_enable_rtc(char *str) +{ + uv_rtc_enable = 1; + + return 1; +} +__setup("uvrtc", uv_enable_rtc); + +static __init void uv_rtc_register_clockevents(struct work_struct *dummy) +{ + struct clock_event_device *ced = &__get_cpu_var(cpu_ced); + + *ced = clock_event_device_uv; + ced->cpumask = cpumask_of(smp_processor_id()); + clockevents_register_device(ced); +} + +static __init int uv_rtc_setup_clock(void) +{ + int rc; + + if (!uv_rtc_enable || !is_uv_system() || generic_interrupt_extension) + return -ENODEV; + + generic_interrupt_extension = uv_rtc_interrupt; + + clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second, + clocksource_uv.shift); + + rc = clocksource_register(&clocksource_uv); + if (rc) { + generic_interrupt_extension = NULL; + return rc; + } + + /* Setup and register clockevents */ + rc = uv_rtc_allocate_timers(); + if (rc) { + clocksource_unregister(&clocksource_uv); + generic_interrupt_extension = NULL; + return rc; + } + + clock_event_device_uv.mult = div_sc(sn_rtc_cycles_per_second, + NSEC_PER_SEC, clock_event_device_uv.shift); + + clock_event_device_uv.min_delta_ns = NSEC_PER_SEC / + sn_rtc_cycles_per_second; + + clock_event_device_uv.max_delta_ns = clocksource_uv.mask * + (NSEC_PER_SEC / sn_rtc_cycles_per_second); + + rc = schedule_on_each_cpu(uv_rtc_register_clockevents); + if (rc) { + clocksource_unregister(&clocksource_uv); + generic_interrupt_extension = NULL; + uv_rtc_deallocate_timers(); + } + + return rc; +} +arch_initcall(uv_rtc_setup_clock); Index: linux/arch/x86/kernel/Makefile =================================================================== --- linux.orig/arch/x86/kernel/Makefile 2009-03-04 11:07:46.000000000 -0600 +++ linux/arch/x86/kernel/Makefile 2009-03-04 11:07:56.000000000 -0600 @@ -111,7 +111,7 @@ obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o ### # 64 bit specific files ifeq ($(CONFIG_X86_64),y) - obj-$(CONFIG_X86_UV) += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o + obj-$(CONFIG_X86_UV) += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o obj-$(CONFIG_AUDIT) += audit_64.o ^ permalink raw reply [flat|nested] 14+ messages in thread
* [tip:x86/uv] x86: UV, SGI RTC: add UV RTC clocksource/clockevents 2009-03-04 18:59 ` [PATCH 3/3 v7] SGI RTC: add UV RTC clocksource/clockevents Dimitri Sivanich @ 2009-03-04 19:48 ` Dimitri Sivanich 0 siblings, 0 replies; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 19:48 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, hpa, mingo, johnstul, akpm, tglx, sivanich, mingo Commit-ID: 5ab5ab34498f94d60884c4ccea890601e429042e Gitweb: http://git.kernel.org/tip/5ab5ab34498f94d60884c4ccea890601e429042e Author: "Dimitri Sivanich" <sivanich@sgi.com> AuthorDate: Wed, 4 Mar 2009 12:59:18 -0600 Commit: Ingo Molnar <mingo@elte.hu> CommitDate: Wed, 4 Mar 2009 20:25:38 +0100 x86: UV, SGI RTC: add UV RTC clocksource/clockevents This patch provides a high resolution clock/timer source using the SGI UV system-wide synchronized RTC clock/timer hardware. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: john stultz <johnstul@us.ibm.com> LKML-Reference: <20090304185918.GC24419@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/x86/kernel/Makefile | 2 +- arch/x86/kernel/uv_time.c | 391 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 392 insertions(+), 1 deletions(-) diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 95f216b..339ce35 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -111,7 +111,7 @@ obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o # NB rename without _64 ### # 64 bit specific files ifeq ($(CONFIG_X86_64),y) - obj-$(CONFIG_X86_UV) += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o + obj-$(CONFIG_X86_UV) += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o obj-$(CONFIG_AUDIT) += audit_64.o diff --git a/arch/x86/kernel/uv_time.c b/arch/x86/kernel/uv_time.c new file mode 100644 index 0000000..6f8e325 --- /dev/null +++ b/arch/x86/kernel/uv_time.c @@ -0,0 +1,391 @@ +/* + * SGI RTC clock/timer routines. + * + * This program 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. + * + * This program 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 + * + * Copyright (c) 2009 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Dimitri Sivanich + */ +#include <linux/clockchips.h> + +#include <asm/uv/uv_mmrs.h> +#include <asm/uv/uv_hub.h> +#include <asm/uv/bios.h> +#include <asm/uv/uv.h> + +#define RTC_NAME "sgi_rtc" + +static cycle_t uv_read_rtc(void); +static int uv_rtc_next_event(unsigned long, struct clock_event_device *); +static void uv_rtc_timer_setup(enum clock_event_mode, + struct clock_event_device *); + +static struct clocksource clocksource_uv = { + .name = RTC_NAME, + .rating = 400, + .read = uv_read_rtc, + .mask = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK, + .shift = 10, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static struct clock_event_device clock_event_device_uv = { + .name = RTC_NAME, + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 20, + .rating = 400, + .irq = -1, + .set_next_event = uv_rtc_next_event, + .set_mode = uv_rtc_timer_setup, + .event_handler = NULL, +}; + +static DEFINE_PER_CPU(struct clock_event_device, cpu_ced); + +/* There is one of these allocated per node */ +struct uv_rtc_timer_head { + spinlock_t lock; + /* next cpu waiting for timer, local node relative: */ + int next_cpu; + /* number of cpus on this node: */ + int ncpus; + struct { + int lcpu; /* systemwide logical cpu number */ + u64 expires; /* next timer expiration for this cpu */ + } cpu[1]; +}; + +/* + * Access to uv_rtc_timer_head via blade id. + */ +static struct uv_rtc_timer_head **blade_info __read_mostly; + +static int uv_rtc_enable; + +/* + * Hardware interface routines + */ + +/* Send IPIs to another node */ +static void uv_rtc_send_IPI(int cpu) +{ + unsigned long apicid, val; + int pnode; + + apicid = per_cpu(x86_cpu_to_apicid, cpu); + pnode = uv_apicid_to_pnode(apicid); + val = (1UL << UVH_IPI_INT_SEND_SHFT) | + (apicid << UVH_IPI_INT_APIC_ID_SHFT) | + (GENERIC_INTERRUPT_VECTOR << UVH_IPI_INT_VECTOR_SHFT); + + uv_write_global_mmr64(pnode, UVH_IPI_INT, val); +} + +/* Check for an RTC interrupt pending */ +static int uv_intr_pending(int pnode) +{ + return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) & + UVH_EVENT_OCCURRED0_RTC1_MASK; +} + +/* Setup interrupt and return non-zero if early expiration occurred. */ +static int uv_setup_intr(int cpu, u64 expires) +{ + u64 val; + int pnode = uv_cpu_to_pnode(cpu); + + uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, + UVH_RTC1_INT_CONFIG_M_MASK); + uv_write_global_mmr64(pnode, UVH_INT_CMPB, -1L); + + uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS, + UVH_EVENT_OCCURRED0_RTC1_MASK); + + val = (GENERIC_INTERRUPT_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) | + ((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT); + + /* Set configuration */ + uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val); + /* Initialize comparator value */ + uv_write_global_mmr64(pnode, UVH_INT_CMPB, expires); + + return (expires < uv_read_rtc() && !uv_intr_pending(pnode)); +} + +/* + * Per-cpu timer tracking routines + */ + +static __init void uv_rtc_deallocate_timers(void) +{ + int bid; + + for_each_possible_blade(bid) { + kfree(blade_info[bid]); + } + kfree(blade_info); +} + +/* Allocate per-node list of cpu timer expiration times. */ +static __init int uv_rtc_allocate_timers(void) +{ + int cpu; + + blade_info = kmalloc(uv_possible_blades * sizeof(void *), GFP_KERNEL); + if (!blade_info) + return -ENOMEM; + memset(blade_info, 0, uv_possible_blades * sizeof(void *)); + + for_each_present_cpu(cpu) { + int nid = cpu_to_node(cpu); + int bid = uv_cpu_to_blade_id(cpu); + int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id; + struct uv_rtc_timer_head *head = blade_info[bid]; + + if (!head) { + head = kmalloc_node(sizeof(struct uv_rtc_timer_head) + + (uv_blade_nr_possible_cpus(bid) * + 2 * sizeof(u64)), + GFP_KERNEL, nid); + if (!head) { + uv_rtc_deallocate_timers(); + return -ENOMEM; + } + spin_lock_init(&head->lock); + head->ncpus = uv_blade_nr_possible_cpus(bid); + head->next_cpu = -1; + blade_info[bid] = head; + } + + head->cpu[bcpu].lcpu = cpu; + head->cpu[bcpu].expires = ULLONG_MAX; + } + + return 0; +} + +/* Find and set the next expiring timer. */ +static void uv_rtc_find_next_timer(struct uv_rtc_timer_head *head, int pnode) +{ + u64 lowest = ULLONG_MAX; + int c, bcpu = -1; + + head->next_cpu = -1; + for (c = 0; c < head->ncpus; c++) { + u64 exp = head->cpu[c].expires; + if (exp < lowest) { + bcpu = c; + lowest = exp; + } + } + if (bcpu >= 0) { + head->next_cpu = bcpu; + c = head->cpu[bcpu].lcpu; + if (uv_setup_intr(c, lowest)) + /* If we didn't set it up in time, trigger */ + uv_rtc_send_IPI(c); + } else { + uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, + UVH_RTC1_INT_CONFIG_M_MASK); + } +} + +/* + * Set expiration time for current cpu. + * + * Returns 1 if we missed the expiration time. + */ +static int uv_rtc_set_timer(int cpu, u64 expires) +{ + int pnode = uv_cpu_to_pnode(cpu); + int bid = uv_cpu_to_blade_id(cpu); + struct uv_rtc_timer_head *head = blade_info[bid]; + int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id; + u64 *t = &head->cpu[bcpu].expires; + unsigned long flags; + int next_cpu; + + spin_lock_irqsave(&head->lock, flags); + + next_cpu = head->next_cpu; + *t = expires; + /* Will this one be next to go off? */ + if (next_cpu < 0 || bcpu == next_cpu || + expires < head->cpu[next_cpu].expires) { + head->next_cpu = bcpu; + if (uv_setup_intr(cpu, expires)) { + *t = ULLONG_MAX; + uv_rtc_find_next_timer(head, pnode); + spin_unlock_irqrestore(&head->lock, flags); + return 1; + } + } + + spin_unlock_irqrestore(&head->lock, flags); + return 0; +} + +/* + * Unset expiration time for current cpu. + * + * Returns 1 if this timer was pending. + */ +static int uv_rtc_unset_timer(int cpu) +{ + int pnode = uv_cpu_to_pnode(cpu); + int bid = uv_cpu_to_blade_id(cpu); + struct uv_rtc_timer_head *head = blade_info[bid]; + int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id; + u64 *t = &head->cpu[bcpu].expires; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&head->lock, flags); + + if (head->next_cpu == bcpu && uv_read_rtc() >= *t) + rc = 1; + + *t = ULLONG_MAX; + + /* Was the hardware setup for this timer? */ + if (head->next_cpu == bcpu) + uv_rtc_find_next_timer(head, pnode); + + spin_unlock_irqrestore(&head->lock, flags); + + return rc; +} + + +/* + * Kernel interface routines. + */ + +/* + * Read the RTC. + */ +static cycle_t uv_read_rtc(void) +{ + return (cycle_t)uv_read_local_mmr(UVH_RTC); +} + +/* + * Program the next event, relative to now + */ +static int uv_rtc_next_event(unsigned long delta, + struct clock_event_device *ced) +{ + int ced_cpu = cpumask_first(ced->cpumask); + + return uv_rtc_set_timer(ced_cpu, delta + uv_read_rtc()); +} + +/* + * Setup the RTC timer in oneshot mode + */ +static void uv_rtc_timer_setup(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + int ced_cpu = cpumask_first(evt->cpumask); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_RESUME: + /* Nothing to do here yet */ + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + uv_rtc_unset_timer(ced_cpu); + break; + } +} + +static void uv_rtc_interrupt(void) +{ + struct clock_event_device *ced = &__get_cpu_var(cpu_ced); + int cpu = smp_processor_id(); + + if (!ced || !ced->event_handler) + return; + + if (uv_rtc_unset_timer(cpu) != 1) + return; + + ced->event_handler(ced); +} + +static int __init uv_enable_rtc(char *str) +{ + uv_rtc_enable = 1; + + return 1; +} +__setup("uvrtc", uv_enable_rtc); + +static __init void uv_rtc_register_clockevents(struct work_struct *dummy) +{ + struct clock_event_device *ced = &__get_cpu_var(cpu_ced); + + *ced = clock_event_device_uv; + ced->cpumask = cpumask_of(smp_processor_id()); + clockevents_register_device(ced); +} + +static __init int uv_rtc_setup_clock(void) +{ + int rc; + + if (!uv_rtc_enable || !is_uv_system() || generic_interrupt_extension) + return -ENODEV; + + generic_interrupt_extension = uv_rtc_interrupt; + + clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second, + clocksource_uv.shift); + + rc = clocksource_register(&clocksource_uv); + if (rc) { + generic_interrupt_extension = NULL; + return rc; + } + + /* Setup and register clockevents */ + rc = uv_rtc_allocate_timers(); + if (rc) { + clocksource_unregister(&clocksource_uv); + generic_interrupt_extension = NULL; + return rc; + } + + clock_event_device_uv.mult = div_sc(sn_rtc_cycles_per_second, + NSEC_PER_SEC, clock_event_device_uv.shift); + + clock_event_device_uv.min_delta_ns = NSEC_PER_SEC / + sn_rtc_cycles_per_second; + + clock_event_device_uv.max_delta_ns = clocksource_uv.mask * + (NSEC_PER_SEC / sn_rtc_cycles_per_second); + + rc = schedule_on_each_cpu(uv_rtc_register_clockevents); + if (rc) { + clocksource_unregister(&clocksource_uv); + generic_interrupt_extension = NULL; + uv_rtc_deallocate_timers(); + } + + return rc; +} +arch_initcall(uv_rtc_setup_clock); ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [tip:x86/uv] x86: UV, SGI RTC: loop through installed UV blades 2009-03-04 18:57 ` [PATCH 2/3 v7] SGI RTC: loop through installed UV blades Dimitri Sivanich 2009-03-04 18:59 ` [PATCH 3/3 v7] SGI RTC: add UV RTC clocksource/clockevents Dimitri Sivanich @ 2009-03-04 19:48 ` Dimitri Sivanich 1 sibling, 0 replies; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 19:48 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, hpa, mingo, johnstul, akpm, tglx, sivanich, mingo Commit-ID: 8661984f628c6f7d9cbaac6697f26d6b0be3ad3b Gitweb: http://git.kernel.org/tip/8661984f628c6f7d9cbaac6697f26d6b0be3ad3b Author: "Dimitri Sivanich" <sivanich@sgi.com> AuthorDate: Wed, 4 Mar 2009 12:57:19 -0600 Commit: Ingo Molnar <mingo@elte.hu> CommitDate: Wed, 4 Mar 2009 20:25:37 +0100 x86: UV, SGI RTC: loop through installed UV blades Add macro to loop through each possible blade. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: john stultz <johnstul@us.ibm.com> LKML-Reference: <20090304185719.GB24419@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/x86/include/asm/uv/uv_hub.h | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index 777327e..9f4dfba 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -199,6 +199,10 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); #define SCIR_CPU_ACTIVITY 0x02 /* not idle */ #define SCIR_CPU_HB_INTERVAL (HZ) /* once per second */ +/* Loop through all installed blades */ +#define for_each_possible_blade(bid) \ + for ((bid) = 0; (bid) < uv_num_possible_blades(); (bid)++) + /* * Macros for converting between kernel virtual addresses, socket local physical * addresses, and UV global physical addresses. ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [tip:x86/uv] x86: UV, SGI RTC: add generic system vector 2009-03-04 18:56 ` [PATCH 1/3 v7] SGI RTC: add " Dimitri Sivanich 2009-03-04 18:57 ` [PATCH 2/3 v7] SGI RTC: loop through installed UV blades Dimitri Sivanich @ 2009-03-04 19:48 ` Dimitri Sivanich 2009-03-05 14:18 ` [tip:x86/uv] x86: UV, SGI RTC: add generic system vector, build fix on UP Ingo Molnar 2 siblings, 0 replies; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 19:48 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, hpa, mingo, johnstul, akpm, tglx, sivanich, mingo Commit-ID: acaabe795a62bba089c185917af86b44654313dc Gitweb: http://git.kernel.org/tip/acaabe795a62bba089c185917af86b44654313dc Author: "Dimitri Sivanich" <sivanich@sgi.com> AuthorDate: Wed, 4 Mar 2009 12:56:05 -0600 Commit: Ingo Molnar <mingo@elte.hu> CommitDate: Wed, 4 Mar 2009 20:25:37 +0100 x86: UV, SGI RTC: add generic system vector This patch allocates a system interrupt vector for various platform specific uses. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: john stultz <johnstul@us.ibm.com> LKML-Reference: <20090304185605.GA24419@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/x86/include/asm/entry_arch.h | 2 ++ arch/x86/include/asm/hardirq.h | 1 + arch/x86/include/asm/hw_irq.h | 1 + arch/x86/include/asm/irq.h | 1 + arch/x86/include/asm/irq_vectors.h | 5 +++++ arch/x86/kernel/entry_64.S | 2 ++ arch/x86/kernel/irq.c | 34 ++++++++++++++++++++++++++++++++++ arch/x86/kernel/irqinit_32.c | 3 +++ arch/x86/kernel/irqinit_64.c | 3 +++ 9 files changed, 52 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h index 854d538..c2e6bed 100644 --- a/arch/x86/include/asm/entry_arch.h +++ b/arch/x86/include/asm/entry_arch.h @@ -33,6 +33,8 @@ BUILD_INTERRUPT3(invalidate_interrupt7,INVALIDATE_TLB_VECTOR_START+7, smp_invalidate_interrupt) #endif +BUILD_INTERRUPT(generic_interrupt, GENERIC_INTERRUPT_VECTOR) + /* * every pentium local APIC has two 'local interrupts', with a * soft-definable vector attached to both interrupts, one of diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index 176f058..039db6a 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -12,6 +12,7 @@ typedef struct { unsigned int apic_timer_irqs; /* arch dependent */ unsigned int irq_spurious_count; #endif + unsigned int generic_irqs; /* arch dependent */ #ifdef CONFIG_SMP unsigned int irq_resched_count; unsigned int irq_call_count; diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index 370e1c8..b762ea4 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -27,6 +27,7 @@ /* Interrupt handlers registered during init_IRQ */ extern void apic_timer_interrupt(void); +extern void generic_interrupt(void); extern void error_interrupt(void); extern void spurious_interrupt(void); extern void thermal_interrupt(void); diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 107eb21..f38481b 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -36,6 +36,7 @@ static inline int irq_canonicalize(int irq) extern void fixup_irqs(void); #endif +extern void (*generic_interrupt_extension)(void); extern void init_IRQ(void); extern void native_init_IRQ(void); extern bool handle_irq(unsigned irq, struct pt_regs *regs); diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 8a285f3..3cbd79b 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h @@ -112,6 +112,11 @@ #define LOCAL_PERF_VECTOR 0xee /* + * Generic system vector for platform specific use + */ +#define GENERIC_INTERRUPT_VECTOR 0xed + +/* * First APIC vector available to drivers: (vectors 0x30-0xee) we * start at 0x31(0x41) to spread out vectors evenly between priority * levels. (0x80 is the syscall vector) diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 83d1836..7ba4621 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -984,6 +984,8 @@ apicinterrupt UV_BAU_MESSAGE \ #endif apicinterrupt LOCAL_TIMER_VECTOR \ apic_timer_interrupt smp_apic_timer_interrupt +apicinterrupt GENERIC_INTERRUPT_VECTOR \ + generic_interrupt smp_generic_interrupt #ifdef CONFIG_SMP apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \ diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index f13ca16..b864341 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -15,6 +15,9 @@ atomic_t irq_err_count; +/* Function pointer for generic interrupt vector handling */ +void (*generic_interrupt_extension)(void) = NULL; + /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves. @@ -56,6 +59,12 @@ static int show_other_interrupts(struct seq_file *p) seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs); seq_printf(p, " Local timer interrupts\n"); #endif + if (generic_interrupt_extension) { + seq_printf(p, "PLT: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", irq_stats(j)->generic_irqs); + seq_printf(p, " Platform interrupts\n"); + } #ifdef CONFIG_SMP seq_printf(p, "RES: "); for_each_online_cpu(j) @@ -163,6 +172,8 @@ u64 arch_irq_stat_cpu(unsigned int cpu) #ifdef CONFIG_X86_LOCAL_APIC sum += irq_stats(cpu)->apic_timer_irqs; #endif + if (generic_interrupt_extension) + sum += irq_stats(cpu)->generic_irqs; #ifdef CONFIG_SMP sum += irq_stats(cpu)->irq_resched_count; sum += irq_stats(cpu)->irq_call_count; @@ -226,4 +237,27 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs) return 1; } +/* + * Handler for GENERIC_INTERRUPT_VECTOR. + */ +void smp_generic_interrupt(struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + ack_APIC_irq(); + + exit_idle(); + + irq_enter(); + + inc_irq_stat(generic_irqs); + + if (generic_interrupt_extension) + generic_interrupt_extension(); + + irq_exit(); + + set_irq_regs(old_regs); +} + EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq); diff --git a/arch/x86/kernel/irqinit_32.c b/arch/x86/kernel/irqinit_32.c index 50b8c3a..bc13261 100644 --- a/arch/x86/kernel/irqinit_32.c +++ b/arch/x86/kernel/irqinit_32.c @@ -175,6 +175,9 @@ void __init native_init_IRQ(void) /* self generated IPI for local APIC timer */ alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); + /* generic IPI for platform specific use */ + alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt); + /* IPI vectors for APIC spurious and error interrupts */ alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c index da481a1..c7a49e0 100644 --- a/arch/x86/kernel/irqinit_64.c +++ b/arch/x86/kernel/irqinit_64.c @@ -147,6 +147,9 @@ static void __init apic_intr_init(void) /* self generated IPI for local APIC timer */ alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); + /* generic IPI for platform specific use */ + alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt); + /* IPI vectors for APIC spurious and error interrupts */ alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [tip:x86/uv] x86: UV, SGI RTC: add generic system vector, build fix on UP 2009-03-04 18:56 ` [PATCH 1/3 v7] SGI RTC: add " Dimitri Sivanich 2009-03-04 18:57 ` [PATCH 2/3 v7] SGI RTC: loop through installed UV blades Dimitri Sivanich 2009-03-04 19:48 ` [tip:x86/uv] x86: UV, SGI RTC: add generic system vector Dimitri Sivanich @ 2009-03-05 14:18 ` Ingo Molnar 2 siblings, 0 replies; 14+ messages in thread From: Ingo Molnar @ 2009-03-05 14:18 UTC (permalink / raw) To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, tglx, sivanich, mingo Commit-ID: b2b352590d94651579e6914ecdb08d30b2cb5f19 Gitweb: http://git.kernel.org/tip/b2b352590d94651579e6914ecdb08d30b2cb5f19 Author: "Ingo Molnar" <mingo@elte.hu> AuthorDate: Thu, 5 Mar 2009 15:15:44 +0100 Commit: Ingo Molnar <mingo@elte.hu> CommitDate: Thu, 5 Mar 2009 15:15:56 +0100 x86: UV, SGI RTC: add generic system vector, build fix on UP Make ack_APIC_irq() build on !SMP && !APIC too. Cc: Dimitri Sivanich <sivanich@sgi.com> LKML-Reference: <20090304185605.GA24419@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/x86/include/asm/apic.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 4ef949c..394d177 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -379,6 +379,7 @@ static inline u32 safe_apic_wait_icr_idle(void) static inline void ack_APIC_irq(void) { +#ifdef CONFIG_X86_LOCAL_APIC /* * ack_APIC_irq() actually gets compiled as a single instruction * ... yummie. @@ -386,6 +387,7 @@ static inline void ack_APIC_irq(void) /* Docs say use 0 for future compatibility */ apic_write(APIC_EOI, 0); +#endif } static inline unsigned default_get_apic_id(unsigned long x) ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector 2009-03-04 18:54 [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector Dimitri Sivanich 2009-03-04 18:56 ` [PATCH 1/3 v7] SGI RTC: add " Dimitri Sivanich @ 2009-03-04 19:46 ` Ingo Molnar 2009-03-04 20:45 ` [PATCH 4/3 v7] SGI RTC: fix uv_time for UP Dimitri Sivanich 1 sibling, 1 reply; 14+ messages in thread From: Ingo Molnar @ 2009-03-04 19:46 UTC (permalink / raw) To: Dimitri Sivanich Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, john stultz, linux-kernel * Dimitri Sivanich <sivanich@sgi.com> wrote: > The following patches provide UV RTC driven clocksource and > clockevents for SGI systems, as well as introducing a generic > system interrupt vector. > > With these patches, the UV system-wide synchronized RTC clock > and timers are used as clocksource and clockevents running in > high resolution mode. > > > Subject: [PATCH 1/3 v7] SGI RTC: add generic system vector > Subject: [PATCH 2/3 v7] SGI RTC: loop through installed UV blades > Subject: [PATCH 3/3 v7] SGI RTC: add UV RTC clocksource/clockevents applied to tip:x86/uv, thanks Dimitri! Note, the new code does not build on !SMP: arch/x86/kernel/uv_time.c:87: error: (Each undeclared identifier is reported only once arch/x86/kernel/uv_time.c:87: error: for each function it appears in.) arch/x86/kernel/uv_time.c: In function 'uv_setup_intr': arch/x86/kernel/uv_time.c:117: error: implicit declaration of function 'cpu_physical_id' So it's not merged into tip:master yet and not en route to 2.6.30 yet either. Please send a delta fix against tip:x86/uv. Thanks, Ingo ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 4/3 v7] SGI RTC: fix uv_time for UP 2009-03-04 19:46 ` [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector Ingo Molnar @ 2009-03-04 20:45 ` Dimitri Sivanich 2009-03-04 20:58 ` Ingo Molnar 0 siblings, 1 reply; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 20:45 UTC (permalink / raw) To: Ingo Molnar Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, john stultz, linux-kernel Fix UP build of uv_time.c. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> --- arch/x86/kernel/uv_time.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) Index: linux/arch/x86/kernel/uv_time.c =================================================================== --- linux.orig/arch/x86/kernel/uv_time.c 2009-03-04 12:32:58.000000000 -0600 +++ linux/arch/x86/kernel/uv_time.c 2009-03-04 14:23:32.000000000 -0600 @@ -19,6 +19,8 @@ * Copyright (c) Dimitri Sivanich */ #include <linux/clockchips.h> +#include <asm/apic.h> +#include <asm/cpu.h> #include <asm/uv/uv.h> #include <asm/uv/uv_mmrs.h> #include <asm/uv/uv_hub.h> @@ -81,7 +83,7 @@ static void uv_rtc_send_IPI(int cpu) unsigned long apicid, val; int pnode; - apicid = per_cpu(x86_cpu_to_apicid, cpu); + apicid = cpu_physical_id(cpu); pnode = uv_apicid_to_pnode(apicid); val = (1UL << UVH_IPI_INT_SEND_SHFT) | (apicid << UVH_IPI_INT_APIC_ID_SHFT) | ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/3 v7] SGI RTC: fix uv_time for UP 2009-03-04 20:45 ` [PATCH 4/3 v7] SGI RTC: fix uv_time for UP Dimitri Sivanich @ 2009-03-04 20:58 ` Ingo Molnar 2009-03-04 22:02 ` Dimitri Sivanich 0 siblings, 1 reply; 14+ messages in thread From: Ingo Molnar @ 2009-03-04 20:58 UTC (permalink / raw) To: Dimitri Sivanich Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, john stultz, linux-kernel * Dimitri Sivanich <sivanich@sgi.com> wrote: > Fix UP build of uv_time.c. it's not against tip:x86/uv as i asked ... (i did a few cleanups of the file so your patch does not apply.) If you have -tip as a remote you can check it out via: git checkout tip/x86/uv Ingo ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 4/3 v7] SGI RTC: fix uv_time for UP 2009-03-04 20:58 ` Ingo Molnar @ 2009-03-04 22:02 ` Dimitri Sivanich 2009-03-05 10:26 ` Ingo Molnar 2009-03-05 10:30 ` [tip:x86/uv] x86: UV, SGI RTC: fix uv_time.c " Dimitri Sivanich 0 siblings, 2 replies; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-04 22:02 UTC (permalink / raw) To: Ingo Molnar; +Cc: linux-kernel Fix non-smp build of uv_time.c. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> --- This time against tip/x86/uv arch/x86/kernel/uv_time.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) Index: linux-2.6.tip-uv/arch/x86/kernel/uv_time.c =================================================================== --- linux-2.6.tip-uv.orig/arch/x86/kernel/uv_time.c 2009-03-04 15:52:10.000000000 -0600 +++ linux-2.6.tip-uv/arch/x86/kernel/uv_time.c 2009-03-04 15:58:48.000000000 -0600 @@ -20,6 +20,9 @@ */ #include <linux/clockchips.h> +#include <asm/apic.h> +#include <asm/cpu.h> + #include <asm/uv/uv_mmrs.h> #include <asm/uv/uv_hub.h> #include <asm/uv/bios.h> @@ -84,7 +87,7 @@ static void uv_rtc_send_IPI(int cpu) unsigned long apicid, val; int pnode; - apicid = per_cpu(x86_cpu_to_apicid, cpu); + apicid = cpu_physical_id(cpu); pnode = uv_apicid_to_pnode(apicid); val = (1UL << UVH_IPI_INT_SEND_SHFT) | (apicid << UVH_IPI_INT_APIC_ID_SHFT) | ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/3 v7] SGI RTC: fix uv_time for UP 2009-03-04 22:02 ` Dimitri Sivanich @ 2009-03-05 10:26 ` Ingo Molnar 2009-03-05 10:30 ` [tip:x86/uv] x86: UV, SGI RTC: fix uv_time.c " Dimitri Sivanich 1 sibling, 0 replies; 14+ messages in thread From: Ingo Molnar @ 2009-03-05 10:26 UTC (permalink / raw) To: Dimitri Sivanich; +Cc: linux-kernel, the arch/x86 maintainers * Dimitri Sivanich <sivanich@sgi.com> wrote: > Fix non-smp build of uv_time.c. > > Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> > > --- > > This time against tip/x86/uv > > arch/x86/kernel/uv_time.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > Index: linux-2.6.tip-uv/arch/x86/kernel/uv_time.c > =================================================================== > --- linux-2.6.tip-uv.orig/arch/x86/kernel/uv_time.c 2009-03-04 15:52:10.000000000 -0600 > +++ linux-2.6.tip-uv/arch/x86/kernel/uv_time.c 2009-03-04 15:58:48.000000000 -0600 > @@ -20,6 +20,9 @@ > */ > #include <linux/clockchips.h> > > +#include <asm/apic.h> > +#include <asm/cpu.h> > + > #include <asm/uv/uv_mmrs.h> > #include <asm/uv/uv_hub.h> > #include <asm/uv/bios.h> Btw: trivia: have you ever thought about why the include files sections looks like that and why i modified your original patch? Have a look at arch/x86/mm/fault.c. Anyway, i fixed up your patch. Ingo ^ permalink raw reply [flat|nested] 14+ messages in thread
* [tip:x86/uv] x86: UV, SGI RTC: fix uv_time.c for UP 2009-03-04 22:02 ` Dimitri Sivanich 2009-03-05 10:26 ` Ingo Molnar @ 2009-03-05 10:30 ` Dimitri Sivanich 1 sibling, 0 replies; 14+ messages in thread From: Dimitri Sivanich @ 2009-03-05 10:30 UTC (permalink / raw) To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, tglx, sivanich, mingo Commit-ID: 1400b3faab8fedfffde5a7fe47098e2732d4aa76 Gitweb: http://git.kernel.org/tip/1400b3faab8fedfffde5a7fe47098e2732d4aa76 Author: "Dimitri Sivanich" <sivanich@sgi.com> AuthorDate: Wed, 4 Mar 2009 16:02:46 -0600 Commit: Ingo Molnar <mingo@elte.hu> CommitDate: Thu, 5 Mar 2009 11:27:49 +0100 x86: UV, SGI RTC: fix uv_time.c for UP Fix non-smp build of uv_time.c. Signed-off-by: Dimitri Sivanich <sivanich@sgi.com> LKML-Reference: <20090304220246.GC6288@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/x86/kernel/uv_time.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/arch/x86/kernel/uv_time.c b/arch/x86/kernel/uv_time.c index 6f8e325..2ffb6c5 100644 --- a/arch/x86/kernel/uv_time.c +++ b/arch/x86/kernel/uv_time.c @@ -24,6 +24,8 @@ #include <asm/uv/uv_hub.h> #include <asm/uv/bios.h> #include <asm/uv/uv.h> +#include <asm/apic.h> +#include <asm/cpu.h> #define RTC_NAME "sgi_rtc" @@ -84,7 +86,7 @@ static void uv_rtc_send_IPI(int cpu) unsigned long apicid, val; int pnode; - apicid = per_cpu(x86_cpu_to_apicid, cpu); + apicid = cpu_physical_id(cpu); pnode = uv_apicid_to_pnode(apicid); val = (1UL << UVH_IPI_INT_SEND_SHFT) | (apicid << UVH_IPI_INT_APIC_ID_SHFT) | ^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2009-03-05 14:19 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-03-04 18:54 [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector Dimitri Sivanich 2009-03-04 18:56 ` [PATCH 1/3 v7] SGI RTC: add " Dimitri Sivanich 2009-03-04 18:57 ` [PATCH 2/3 v7] SGI RTC: loop through installed UV blades Dimitri Sivanich 2009-03-04 18:59 ` [PATCH 3/3 v7] SGI RTC: add UV RTC clocksource/clockevents Dimitri Sivanich 2009-03-04 19:48 ` [tip:x86/uv] x86: UV, " Dimitri Sivanich 2009-03-04 19:48 ` [tip:x86/uv] x86: UV, SGI RTC: loop through installed UV blades Dimitri Sivanich 2009-03-04 19:48 ` [tip:x86/uv] x86: UV, SGI RTC: add generic system vector Dimitri Sivanich 2009-03-05 14:18 ` [tip:x86/uv] x86: UV, SGI RTC: add generic system vector, build fix on UP Ingo Molnar 2009-03-04 19:46 ` [PATCH 0/3 v7] SGI RTC: add UV RTC clocksource/clockevents and generic system vector Ingo Molnar 2009-03-04 20:45 ` [PATCH 4/3 v7] SGI RTC: fix uv_time for UP Dimitri Sivanich 2009-03-04 20:58 ` Ingo Molnar 2009-03-04 22:02 ` Dimitri Sivanich 2009-03-05 10:26 ` Ingo Molnar 2009-03-05 10:30 ` [tip:x86/uv] x86: UV, SGI RTC: fix uv_time.c " Dimitri Sivanich
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox