genirq: handling GIC per-cpu interrupts
Subsystems (6)
v4 cover genirq: handling GIC per-cpu interrupts
The current GIC per-cpu interrupts (aka PPIs) suffer from a number of problems:
- They use a completely separate scheme to handle the interrupts, mostly because the PPI concept doesn't really match the kernel view of an interrupt.
- PPIs can only be used by the timer code, unless we add more low-level assembly code.
- The local timer code can only be used by devices generating PPIs, and not SPIs.
- At least one platform (msm) has started implementing its own alternative scheme.
- Some low-level code gets duplicated, as usual...
The proposed solution is to handle the PPIs using the same path as SPIs. A new core API is added to deal with per-cpu interrupts in a less awkward way. The local timer code is updated to reflect these changes.
The core API changes are based on an initial idea by Thomas Gleixner.
Tested on ARM Versatile Express (Cortex A15), ARM RealView PB11MP, OMAP4 (Panda) and Tegra (Harmony). Patch series against next-20110930.
The two first patches can also be found in Thomas' tree:
git://tesla.tglx.de/git/linux-2.6-tip irq/core
Changelog:
PATCH v4 1/4 genirq: Add support for per-cpu dev_id interrupts
The ARM GIC interrupt controller offers per CPU interrupts (PPIs), which are usually used to connect local timers to each core. Each CPU has its own private interface to the GIC, and only sees the PPIs that are directly connect to it.
While these timers are separate devices and have a separate interrupt line to a core, they all use the same IRQ number.
For these devices, request_irq() is not the right API as it assumes that an IRQ number is visible by a number of CPUs (through the affinity setting), but makes it very awkward to express that an IRQ number can be handled by all CPUs, and yet be a different interrupt line on each CPU, requiring a different dev_id cookie to be passed back to the handler.
The *_percpu_irq() functions is designed to overcome these limitations, by providing a per-cpu dev_id vector:
int request_percpu_irq(unsigned int irq, irq_handler_t handler,
const char *devname, void __percpu *percpu_dev_id);
void free_percpu_irq(unsigned int, void __percpu *); int setup_percpu_irq(unsigned int irq, struct irqaction *new); void remove_percpu_irq(unsigned int irq, struct irqaction *act); void enable_percpu_irq(unsigned int irq);
void disable_percpu_irq(unsigned int irq);
The API has a number of limitations:
- no interrupt sharing
- no threading
- common handler across all the CPUs
Once the interrupt is requested using setup_percpu_irq() or request_percpu_irq(), it must be enabled by each core that wishes its local interrupt to be delivered.
Based on an initial patch by Thomas Gleixner.
--- include/linux/interrupt.h | 38 ++++++--- include/linux/irq.h | 16 ++++- include/linux/irqdesc.h | 1 + kernel/irq/chip.c | 64 +++++++++++++-- kernel/irq/internals.h | 19 +++- kernel/irq/irqdesc.c | 32 +++++++- kernel/irq/manage.c | 202 +++++++++++++++++++++++++++++++++++++++++++-- kernel/irq/settings.h | 7 ++ 8 files changed, 345 insertions(+), 34 deletions(-)
include/linux/interrupt.h +27 -11
@@ -95,6 +95,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);* @flags: flags (see IRQF_* above) * @name: name of the device * @dev_id: cookie to identify the device +* @percpu_dev_id: cookie to identify the device * @next: pointer to the next irqaction for shared interrupts * @irq: interrupt number * @dir: pointer to the proc/irq/NN/name entry
@@ -104,17 +105,18 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);* @thread_mask: bitmask for keeping track of @thread activity */ struct irqaction { -irq_handler_t handler; -unsigned long flags; -void *dev_id; -struct irqaction *next; -int irq; -irq_handler_t thread_fn; -struct task_struct *thread; -unsigned long thread_flags; -unsigned long thread_mask; -const char *name; -struct proc_dir_entry *dir; +irq_handler_t handler; +unsigned long flags; +void *dev_id; +void __percpu *percpu_dev_id; +struct irqaction *next; +int irq; +irq_handler_t thread_fn; +struct task_struct *thread; +unsigned long thread_flags; +unsigned long thread_mask; +const char *name; +struct proc_dir_entry *dir; }____cacheline_internodealigned_in_smp ;extern irqreturn_t no_action (int cpl,void *dev_id);
@@ -136,6 +138,10 @@ extern int __must_check request_any_context_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev_id); +extern int __must_check +request_percpu_irq (unsigned int irq,irq_handler_t handler, +const char *devname,void __percpu *percpu_dev_id); +extern void exit_irq_thread (void );#else
@@ -164,10 +170,18 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler, return request_irq(irq, handler, flags, name, dev_id); } +static inline int __must_check +request_percpu_irq (unsigned int irq,irq_handler_t handler, +const char *devname,void __percpu *percpu_dev_id) +{ +return request_irq (irq, handler,0 , devname, percpu_dev_id); +} +static inline void exit_irq_thread (void ) { }#endif extern void free_irq (unsigned int ,void *); +extern void free_percpu_irq (unsigned int ,void __percpu *);struct device ;
@@ -207,7 +221,9 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);extern void disable_irq_nosync (unsigned int irq);extern void disable_irq (unsigned int irq); +extern void disable_percpu_irq (unsigned int irq);extern void enable_irq (unsigned int irq); +extern void enable_percpu_irq (unsigned int irq);/* The following three functions are for the core kernel use only. */ #ifdef CONFIG_GENERIC_HARDIRQS
include/linux/irq.h +15 -1
@@ -66,6 +66,7 @@ typedef void (*irq_preflow_handler_t)(struct irq_data *data);* IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set) * IRQ_MOVE_PCNTXT - Interrupt can be migrated from process context * IRQ_NESTED_TRHEAD - Interrupt nests into another thread +* IRQ_PER_CPU_DEVID - Dev_id is a per-cpu variable */ enum {IRQ_TYPE_NONE =0x00000000 ,
@@ -88,12 +89,13 @@ enum {IRQ_MOVE_PCNTXT = (1 <<14 ),IRQ_NESTED_THREAD = (1 <<15 ),IRQ_NOTHREAD = (1 <<16 ), + IRQ_PER_CPU_DEVID = (1 << 17), };#define IRQF_MODIFY_MASK \ (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \ IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \ - IRQ_PER_CPU | IRQ_NESTED_THREAD) + IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID)#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
@@ -367,6 +369,8 @@ enum {struct irqaction ;extern int setup_irq (unsigned int irq,struct irqaction *new);extern void remove_irq (unsigned int irq,struct irqaction *act); +extern int setup_percpu_irq (unsigned int irq,struct irqaction *new); +extern void remove_percpu_irq (unsigned int irq,struct irqaction *act);extern void irq_cpu_online (void );extern void irq_cpu_offline (void );
@@ -394,6 +398,7 @@ extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc);extern void handle_edge_eoi_irq (unsigned int irq,struct irq_desc *desc);extern void handle_simple_irq (unsigned int irq,struct irq_desc *desc);extern void handle_percpu_irq (unsigned int irq,struct irq_desc *desc); +extern void handle_percpu_devid_irq (unsigned int irq,struct irq_desc *desc);extern void handle_bad_irq (unsigned int irq,struct irq_desc *desc);extern void handle_nested_irq (unsigned int irq);
@@ -422,6 +427,8 @@ static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *cirq_set_chip_and_handler_name (irq, chip, handle,NULL ); } +extern int irq_set_percpu_devid (unsigned int irq); +extern void __irq_set_handler (unsigned int irq,irq_flow_handler_t handle,int is_chained,const char *name);
@@ -483,6 +490,13 @@ static inline void irq_set_nested_thread(unsigned int irq, bool nest)irq_clear_status_flags (irq,IRQ_NESTED_THREAD ); } +static inline void irq_set_percpu_devid_flags (unsigned int irq) +{ +irq_set_status_flags (irq, +IRQ_NOAUTOEN |IRQ_PER_CPU |IRQ_NOTHREAD | +IRQ_NOPROBE |IRQ_PER_CPU_DEVID ); +} +/* Handle dynamic irq creation and destruction */ extern unsigned int create_irq_nr (unsigned int irq_want,int node);extern int create_irq (void );
include/linux/irqdesc.h +1 -0
@@ -54,6 +54,7 @@ struct irq_desc {unsigned long last_unhandled;/* Aging timer for unhandled count */ unsigned int irqs_unhandled;raw_spinlock_t lock; +struct cpumask *percpu_enabled;#ifdef CONFIG_SMP const struct cpumask *affinity_hint;struct irq_affinity_notify *affinity_notify;
kernel/irq/chip.c +57 -7
117 lines not on this page · raw message
kernel/irq/internals.h +14 -5
@@ -71,6 +71,8 @@ extern int irq_startup(struct irq_desc *desc);extern void irq_shutdown (struct irq_desc *desc);extern void irq_enable (struct irq_desc *desc);extern void irq_disable (struct irq_desc *desc); +extern void irq_percpu_enable (struct irq_desc *desc,unsigned int cpu); +extern void irq_percpu_disable (struct irq_desc *desc,unsigned int cpu);extern void mask_irq (struct irq_desc *desc);extern void unmask_irq (struct irq_desc *desc);
@@ -114,14 +116,21 @@ static inline void chip_bus_sync_unlock(struct irq_desc *desc) desc->irq_data.chip->irq_bus_sync_unlock (&desc->irq_data); } +#define _IRQ_DESC_CHECK (1 << 0) +#define _IRQ_DESC_PERCPU (1 << 1) + +#define IRQ_GET_DESC_CHECK_GLOBAL (_IRQ_DESC_CHECK) +#define IRQ_GET_DESC_CHECK_PERCPU (_IRQ_DESC_CHECK | _IRQ_DESC_PERCPU) +struct irq_desc * -__irq_get_desc_lock (unsigned int irq,unsigned long *flags,bool bus); +__irq_get_desc_lock (unsigned int irq,unsigned long *flags,bool bus, +unsigned int check);void __irq_put_desc_unlock (struct irq_desc *desc,unsigned long flags,bool bus);static inline struct irq_desc * -irq_get_desc_buslock (unsigned int irq,unsigned long *flags) +irq_get_desc_buslock (unsigned int irq,unsigned long *flags,unsigned int check) { -return __irq_get_desc_lock (irq, flags, true); +return __irq_get_desc_lock (irq, flags, true, check); } static inline void
@@ -131,9 +140,9 @@ irq_put_desc_busunlock(struct irq_desc *desc, unsigned long flags) }static inline struct irq_desc * -irq_get_desc_lock (unsigned int irq,unsigned long *flags) +irq_get_desc_lock (unsigned int irq,unsigned long *flags,unsigned int check) { -return __irq_get_desc_lock (irq, flags, false); +return __irq_get_desc_lock (irq, flags, false, check); } static inline void
kernel/irq/irqdesc.c +31 -1
@@ -424,11 +424,22 @@ unsigned int irq_get_next_irq(unsigned int offset) }struct irq_desc * -__irq_get_desc_lock (unsigned int irq,unsigned long *flags,bool bus) +__irq_get_desc_lock (unsigned int irq,unsigned long *flags,bool bus, +unsigned int check) {struct irq_desc *desc =irq_to_desc (irq);if (desc) { +if (check & _IRQ_DESC_CHECK) { +if ((check & _IRQ_DESC_PERCPU) && + !irq_settings_is_per_cpu_devid (desc)) +return NULL ; + +if (!(check & _IRQ_DESC_PERCPU) && +irq_settings_is_per_cpu_devid (desc)) +return NULL ; + } +if (bus)chip_bus_lock (desc);raw_spin_lock_irqsave (&desc->lock, *flags);
@@ -443,6 +454,25 @@ void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)chip_bus_sync_unlock (desc); } +int irq_set_percpu_devid (unsigned int irq) +{ +struct irq_desc *desc =irq_to_desc (irq); + +if (!desc) +return -EINVAL ; + +if (desc->percpu_enabled) +return -EINVAL ; + + desc->percpu_enabled =kzalloc (sizeof (*desc->percpu_enabled),GFP_KERNEL ); + +if (!desc->percpu_enabled) +return -ENOMEM ; + +irq_set_percpu_devid_flags (irq); +return 0 ; +} +/** * dynamic_irq_cleanup - cleanup a dynamically allocated irq * @irq: irq number to initialize
kernel/irq/manage.c +193 -9
265 lines not on this page · raw message
kernel/irq/settings.h +7 -0
@@ -13,6 +13,7 @@ enum { _IRQ_MOVE_PCNTXT =IRQ_MOVE_PCNTXT , _IRQ_NO_BALANCING =IRQ_NO_BALANCING , _IRQ_NESTED_THREAD =IRQ_NESTED_THREAD , + _IRQ_PER_CPU_DEVID =IRQ_PER_CPU_DEVID , _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, };
@@ -24,6 +25,7 @@ enum {#define IRQ_NOTHREAD GOT_YOU_MORON#define IRQ_NOAUTOEN GOT_YOU_MORON#define IRQ_NESTED_THREAD GOT_YOU_MORON +#define IRQ_PER_CPU_DEVID GOT_YOU_MORON#undef IRQF_MODIFY_MASK#define IRQF_MODIFY_MASK GOT_YOU_MORON
@@ -39,6 +41,11 @@ static inline bool irq_settings_is_per_cpu(struct irq_desc *desc)return desc->status_use_accessors & _IRQ_PER_CPU; } +static inline bool irq_settings_is_per_cpu_devid (struct irq_desc *desc) +{ +return desc->status_use_accessors & _IRQ_PER_CPU_DEVID; +} +static inline void irq_settings_set_per_cpu (struct irq_desc *desc) { desc->status_use_accessors |= _IRQ_PER_CPU;
Signature · 1 line
1.7.0.4
PATCH v4 2/4 genirq: percpu: allow interrupt type to be set at enable time
In reply to Marc ZyngierAs request_percpu_irq() doesn't allow for a percpu interrupt to have its type configured (it is generally impossible to configure it on all CPUs at once), add a 'type' argument to enable_percpu_irq().
This allows some low-level, board specific init code to be switched to a generic API.
[ tglx: Added WARN_ON argument ]
--- include/linux/interrupt.h | 2 +- kernel/irq/manage.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-)
include/linux/interrupt.h +1 -1
@@ -223,7 +223,7 @@ extern void disable_irq_nosync(unsigned int irq);extern void disable_irq (unsigned int irq);extern void disable_percpu_irq (unsigned int irq);extern void enable_irq (unsigned int irq); -extern void enable_percpu_irq (unsigned int irq); +extern void enable_percpu_irq (unsigned int irq,unsigned int type);/* The following three functions are for the core kernel use only. */ #ifdef CONFIG_GENERIC_HARDIRQS
kernel/irq/manage.c +14 -1
@@ -1419,7 +1419,7 @@ int request_any_context_irq(unsigned int irq, irq_handler_t handler, }EXPORT_SYMBOL_GPL (request_any_context_irq); -void enable_percpu_irq (unsigned int irq) +void enable_percpu_irq (unsigned int irq,unsigned int type) {unsigned int cpu =smp_processor_id ();unsigned long flags;
@@ -1428,7 +1428,20 @@ void enable_percpu_irq(unsigned int irq)if (!desc)return ; + type &=IRQ_TYPE_SENSE_MASK ; +if (type !=IRQ_TYPE_NONE ) { +int ret; + + ret =__irq_set_trigger (desc, irq, type); + +if (ret) { +WARN (1 ,"failed to set type for IRQ%d\n, irq" ); + goto out; + } + } +irq_percpu_enable (desc, cpu); +out:irq_put_desc_unlock (desc, flags); }
Signature · 1 line
1.7.0.4
PATCH v4 3/4 ARM: gic: consolidate PPI handling
In reply to Marc ZyngierPPI handling is a bit of an odd beast. It uses its own low level handling code and is hardwired to the local timers (hence lacking a registration interface).
Instead, switch the low handling to the normal SPI handling code. PPIs are handled by the handle_percpu_devid_irq flow.
This also allows the removal of some duplicated code.
--- arch/arm/common/Kconfig | 1 + arch/arm/common/gic.c | 70 +++++++++++++++++++- arch/arm/include/asm/entry-macro-multi.S | 7 -- arch/arm/include/asm/hardirq.h | 3 - arch/arm/include/asm/hardware/entry-macro-gic.S | 19 +----- arch/arm/include/asm/localtimer.h | 6 +- arch/arm/include/asm/smp.h | 5 -- arch/arm/kernel/irq.c | 3 - arch/arm/kernel/smp.c | 27 ++------ arch/arm/mach-exynos4/include/mach/entry-macro.S | 6 +-- arch/arm/mach-msm/board-msm8x60.c | 11 --- arch/arm/mach-msm/include/mach/entry-macro-qgic.S | 73 +-------------------- arch/arm/mach-omap2/include/mach/entry-macro.S | 14 +---- arch/arm/mach-shmobile/entry-intc.S | 3 - arch/arm/mach-shmobile/include/mach/entry-macro.S | 3 - 15 files changed, 84 insertions(+), 167 deletions(-)
arch/arm/common/Kconfig +1 -0
@@ -1,4 +1,5 @@ config ARM_GIC + select IRQ_PERCPU_DEVID bool config ARM_VIC
arch/arm/common/gic.c +69 -1
104 lines not on this page · raw message
arch/arm/include/asm/entry-macro-multi.S +0 -7
@@ -25,13 +25,6 @@ movne r1, sp adrne lr, BSYM(1b) bne do_IPI - -#ifdef CONFIG_LOCAL_TIMERS - test_for_ltirq r0, r2, r6, lr - movne r0, sp - adrne lr, BSYM(1b) - bne do_local_timer -#endif #endif 9997: .endm
arch/arm/include/asm/hardirq.h +0 -3
@@ -9,9 +9,6 @@ typedef struct { unsigned int __softirq_pending; -#ifdef CONFIG_LOCAL_TIMERS - unsigned int local_timer_irqs; -#endif #ifdef CONFIG_SMP unsigned int ipi_irqs[NR_IPI]; #endif
arch/arm/include/asm/hardware/entry-macro-gic.S +2 -17
@@ -22,15 +22,11 @@ * interrupt controller spec. To wit: * * Interrupts 0-15 are IPI - * 16-28 are reserved - * 29-31 are local. We allow 30 to be used for the watchdog. + * 16-31 are local. We allow 30 to be used for the watchdog. * 32-1020 are global * 1021-1022 are reserved * 1023 is "spurious" (no interrupt) * - * For now, we ignore all local interrupts so only return an interrupt if it's - * between 30 and 1020. The test_for_ipi routine below will pick up on IPIs. - * * A simple read from the controller will tell us the number of the highest * priority enabled interrupt. We then just need to check whether it is in the * valid range for an IRQ (30-1020 inclusive).
@@ -43,7 +39,7 @@ ldr \tmp, =1021 bic \irqnr, \irqstat, #0x1c00 - cmp \irqnr, #29 + cmp \irqnr, #15 cmpcc \irqnr, \irqnr cmpne \irqnr, \tmp cmpcs \irqnr, \irqnr
@@ -62,14 +58,3 @@ strcc \irqstat, [\base, #GIC_CPU_EOI] cmpcs \irqnr, \irqnr .endm - -/* As above, this assumes that irqstat and base are preserved.. */ - - .macro test_for_ltirq, irqnr, irqstat, base, tmp - bic \irqnr, \irqstat, #0x1c00 - mov \tmp, #0 - cmp \irqnr, #29 - moveq \tmp, #1 - streq \irqstat, [\base, #GIC_CPU_EOI] - cmp \tmp, #0 - .endm
arch/arm/include/asm/localtimer.h +4 -2
@@ -10,6 +10,8 @@#ifndef __ASM_ARM_LOCALTIMER_H#define __ASM_ARM_LOCALTIMER_H +#include <linux/interrupt.h> +struct clock_event_device ;/*
@@ -18,9 +20,9 @@ struct clock_event_device;void percpu_timer_setup (void );/* -* Called from assembly, this is the local timer IRQ handler +* Per-cpu timer IRQ handler */ -asmlinkage void do_local_timer(struct pt_regs *); +irqreturn_t percpu_timer_handler (int irq,void *dev_id);#ifdef CONFIG_LOCAL_TIMERS
arch/arm/include/asm/smp.h +0 -5
@@ -79,9 +79,4 @@ extern void cpu_die(void);extern void arch_send_call_function_single_ipi (int cpu);extern void arch_send_call_function_ipi_mask (const struct cpumask *mask); -/* -* show local interrupt info -*/ -extern void show_local_irqs (struct seq_file *,int ); -#endif /* ifndef __ASM_ARM_SMP_H */
arch/arm/kernel/irq.c +0 -3
@@ -58,9 +58,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)#ifdef CONFIG_SMP show_ipi_list (p, prec);#endif -#ifdef CONFIG_LOCAL_TIMERS -show_local_irqs (p, prec); -#endif seq_printf (p,"%*s: %10lu\n" , prec,"Err" , irq_err_count);return 0 ; }
arch/arm/kernel/smp.c +5 -22
@@ -504,10 +504,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu)for (i =0 ; i <NR_IPI ; i++) sum +=__get_irq_stat (cpu, ipi_irqs[i]); -#ifdef CONFIG_LOCAL_TIMERS - sum +=__get_irq_stat (cpu, local_timer_irqs); -#endif -return sum; }
@@ -525,29 +521,16 @@ static void ipi_timer(void) }#ifdef CONFIG_LOCAL_TIMERS -asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs) +irqreturn_t percpu_timer_handler (int irq,void *dev_id) { -struct pt_regs *old_regs =set_irq_regs (regs); -int cpu =smp_processor_id (); +struct clock_event_device *evt = &__get_cpu_var (percpu_clockevent);if (local_timer_ack ()) { -__inc_irq_stat (cpu, local_timer_irqs); -ipi_timer (); + evt->event_handler (evt); +return IRQ_HANDLED ; } -set_irq_regs (old_regs); -} - -void show_local_irqs (struct seq_file *p,int prec) -{ -unsigned int cpu; - -seq_printf (p,"%*s: " , prec,"LOC" ); - -for_each_present_cpu (cpu) -seq_printf (p,"%10u " ,__get_irq_stat (cpu, local_timer_irqs)); - -seq_printf (p," Local timer interrupts\n" ); +return IRQ_NONE ; }#endif
arch/arm/mach-exynos4/include/mach/entry-macro.S +1 -5
@@ -55,7 +55,7 @@ bic \irqnr, \irqstat, #0x1c00 - cmp \irqnr, #29 + cmp \irqnr, #15 cmpcc \irqnr, \irqnr cmpne \irqnr, \tmp cmpcs \irqnr, \irqnr
@@ -77,7 +77,3 @@ cmpcs \irqnr, \irqnr .endm - /* As above, this assumes that irqstat and base are preserved.. */ - - .macro test_for_ltirq, irqnr, irqstat, base, tmp - .endm
arch/arm/mach-msm/board-msm8x60.c +0 -11
@@ -53,8 +53,6 @@ static void __init msm8x60_map_io(void)static void __init msm8x60_init_irq (void ) { -unsigned int i; -gic_init (0 ,GIC_PPI_START ,MSM_QGIC_DIST_BASE , (void *)MSM_QGIC_CPU_BASE );
@@ -66,15 +64,6 @@ static void __init msm8x60_init_irq(void)*/ if (!machine_is_msm8x60_sim ())writel (0x0000FFFF ,MSM_QGIC_DIST_BASE +GIC_DIST_ENABLE_SET ); - -/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet -* as they are configured as level, which does not play nice with -* handle_percpu_irq. -*/ -for (i =GIC_PPI_START ; i <GIC_SPI_START ; i++) { -if (i !=AVS_SVICINT && i !=AVS_SVICINTSWDONE ) -irq_set_handler (i, handle_percpu_irq); - } }static void __init msm8x60_init (void )
arch/arm/mach-msm/include/mach/entry-macro-qgic.S +1 -72
82 lines not on this page · raw message
arch/arm/mach-omap2/include/mach/entry-macro.S +1 -13
@@ -78,7 +78,7 @@ 4401: ldr \irqstat, [\base, #GIC_CPU_INTACK] ldr \tmp, =1021 bic \irqnr, \irqstat, #0x1c00 - cmp \irqnr, #29 + cmp \irqnr, #15 cmpcc \irqnr, \irqnr cmpne \irqnr, \tmp cmpcs \irqnr, \irqnr
@@ -101,18 +101,6 @@ it cs cmpcs \irqnr, \irqnr .endm - - /* As above, this assumes that irqstat and base are preserved */ - - .macro test_for_ltirq, irqnr, irqstat, base, tmp - bic \irqnr, \irqstat, #0x1c00 - mov \tmp, #0 - cmp \irqnr, #29 - itt eq - moveq \tmp, #1 - streq \irqstat, [\base, #GIC_CPU_EOI] - cmp \tmp, #0 - .endm #endif /* CONFIG_SMP */ #else /* MULTI_OMAP2 */
arch/arm/mach-shmobile/entry-intc.S +0 -3
@@ -51,7 +51,4 @@ .macro test_for_ipi, irqnr, irqstat, base, tmp .endm - .macro test_for_ltirq, irqnr, irqstat, base, tmp - .endm - arch_irq_handler shmobile_handle_irq_intc
arch/arm/mach-shmobile/include/mach/entry-macro.S +0 -3
@@ -27,8 +27,5 @@ .macro test_for_ipi, irqnr, irqstat, base, tmp .endm - .macro test_for_ltirq, irqnr, irqstat, base, tmp - .endm - .macro arch_ret_to_user, tmp1, tmp2 .endm
Signature · 1 line
1.7.0.4
PATCH v4 4/4 ARM: gic, local timers: use the request_percpu_irq() interface
In reply to Marc ZyngierThis patch remove the hardcoded link between local timers and PPIs, and convert the PPI users (TWD and MSM timers) to the new *_percpu_irq interface. Also some collateral cleanup (local_timer_ack() is gone, and the interrupt handler is strictly private to each driver).
PPIs are now useable for more than just the local timers.
Additional testing by David Brown (msm8250 and msm8660) and Shawn Guo (imx6q).
--- arch/arm/common/gic.c | 52 -------------------------- arch/arm/include/asm/hardware/gic.h | 1 - arch/arm/include/asm/localtimer.h | 17 ++++----- arch/arm/include/asm/smp_twd.h | 2 +- arch/arm/kernel/smp.c | 16 +-------- arch/arm/kernel/smp_twd.c | 47 +++++++++++++++++++++++- arch/arm/mach-exynos4/mct.c | 5 --- arch/arm/mach-msm/timer.c | 69 ++++++++++++++++++++--------------- 8 files changed, 94 insertions(+), 115 deletions(-)
arch/arm/common/gic.c +0 -52
@@ -35,7 +35,6 @@#include <asm/irq.h> #include <asm/mach/irq.h> #include <asm/hardware/gic.h> -#include <asm/localtimer.h> static DEFINE_RAW_SPINLOCK (irq_controller_lock);
@@ -259,32 +258,6 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)irq_set_chained_handler (irq, gic_handle_cascade_irq); } -#ifdef CONFIG_LOCAL_TIMERS -#define gic_ppi_handler percpu_timer_handler -#else -static irqreturn_t gic_ppi_handler (int irq,void *dev_id) -{ -return IRQ_NONE ; -} -#endif - -#define PPI_IRQACT (nr) \ - { \ - .handler = gic_ppi_handler, \ - .flags = IRQF_PERCPU | IRQF_TIMER, \ - .irq = nr, \ - .name = "PPI-" # nr, \ - } - -static struct irqaction ppi_irqaction_template[16 ]__initdata = { -PPI_IRQACT (0 ),PPI_IRQACT (1 ),PPI_IRQACT (2 ),PPI_IRQACT (3 ), -PPI_IRQACT (4 ),PPI_IRQACT (5 ),PPI_IRQACT (6 ),PPI_IRQACT (7 ), -PPI_IRQACT (8 ),PPI_IRQACT (9 ),PPI_IRQACT (10 ),PPI_IRQACT (11 ), -PPI_IRQACT (12 ),PPI_IRQACT (13 ),PPI_IRQACT (14 ),PPI_IRQACT (15 ), -}; - -static struct irqaction *ppi_irqaction; -static void __init gic_dist_init (struct gic_chip_data *gic,unsigned int irq_start) {
@@ -320,16 +293,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic,if (gic == &gic_data[0 ]) { nrppis =16 - (irq_start &15 ); ppi_base = gic->irq_offset +32 - nrppis; - - ppi_irqaction =kmemdup (&ppi_irqaction_template[16 - nrppis], -sizeof (*ppi_irqaction) * nrppis, -GFP_KERNEL ); - -if (nrppis && !ppi_irqaction) { -pr_err ("GIC: Can't allocate PPI memory" ); - nrppis =0 ; - ppi_base =0 ; - } } pr_info("Configuring GIC with %d sources (%d PPIs)\n",
@@ -372,17 +335,12 @@ static void __init gic_dist_init(struct gic_chip_data *gic,*/ for (i =0 ; i < nrppis; i++) {int ppi = i + ppi_base; -int err;irq_set_percpu_devid (ppi);irq_set_chip_and_handler (ppi, &gic_chip, handle_percpu_devid_irq);irq_set_chip_data (ppi, gic);set_irq_flags (ppi,IRQF_VALID |IRQF_NOAUTOEN ); - - err =setup_percpu_irq (ppi, &ppi_irqaction[i]); -if (err) -pr_err ("GIC: can't setup PPI%d (%d)\n" , ppi, err); }for (i = irq_start + nrppis; i < irq_limit; i++) {
@@ -443,16 +401,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr)gic_cpu_init (&gic_data[gic_nr]); } -void __cpuinit gic_enable_ppi (unsigned int irq) -{ -unsigned long flags; - -local_irq_save (flags); -irq_set_status_flags (irq,IRQ_NOPROBE ); -gic_unmask_irq (irq_get_irq_data (irq)); -local_irq_restore (flags); -} -#ifdef CONFIG_SMP void gic_raise_softirq (const struct cpumask *mask,unsigned int irq) {
arch/arm/include/asm/hardware/gic.h +0 -1
@@ -40,7 +40,6 @@ void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);void gic_secondary_init (unsigned int );void gic_cascade_irq (unsigned int gic_nr,unsigned int irq);void gic_raise_softirq (const struct cpumask *mask,unsigned int irq); -void gic_enable_ppi (unsigned int );struct gic_chip_data {unsigned int irq_offset;
arch/arm/include/asm/localtimer.h +7 -10
@@ -19,27 +19,20 @@ struct clock_event_device;*/ void percpu_timer_setup (void ); -/* -* Per-cpu timer IRQ handler -*/ -irqreturn_t percpu_timer_handler (int irq,void *dev_id); - -#ifdef CONFIG_LOCAL_TIMERS #ifdef CONFIG_HAVE_ARM_TWD #include "smp_twd.h" -#define local_timer_ack () twd_timer_ack() +#define local_timer_stop (c) twd_timer_stop((c))#else /* -* Platform provides this to acknowledge a local timer IRQ. -* Returns true if the local timer IRQ is to be processed. +* Stop the local timer */ -int local_timer_ack (void ); +void local_timer_stop (struct clock_event_device *);#endif
@@ -54,6 +47,10 @@ static inline int local_timer_setup(struct clock_event_device *evt) {return -ENXIO ; } + +static inline void local_timer_stop (struct clock_event_device *evt) +{ +}#endif #endif
arch/arm/include/asm/smp_twd.h +1 -1
@@ -22,7 +22,7 @@ struct clock_event_device;extern void __iomem *twd_base; -int twd_timer_ack (void );void twd_timer_setup (struct clock_event_device *); +void twd_timer_stop (struct clock_event_device *);#endif
arch/arm/kernel/smp.c +1 -15
@@ -520,20 +520,6 @@ static void ipi_timer(void)irq_exit (); } -#ifdef CONFIG_LOCAL_TIMERS -irqreturn_t percpu_timer_handler (int irq,void *dev_id) -{ -struct clock_event_device *evt = &__get_cpu_var (percpu_clockevent); - -if (local_timer_ack ()) { - evt->event_handler (evt); -return IRQ_HANDLED ; - } - -return IRQ_NONE ; -} -#endif -#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST static void smp_timer_broadcast (const struct cpumask *mask) {
@@ -584,7 +570,7 @@ static void percpu_timer_stop(void)unsigned int cpu =smp_processor_id ();struct clock_event_device *evt = &per_cpu (percpu_clockevent, cpu); - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + local_timer_stop(evt); }#endif
arch/arm/kernel/smp_twd.c +45 -2
82 lines not on this page · raw message
arch/arm/mach-exynos4/mct.c +0 -5
@@ -402,11 +402,6 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) return 0; } -int local_timer_ack (void ) -{ -return 0 ; -} -#endif /* CONFIG_LOCAL_TIMERS */ static void __init exynos4_timer_resources (void )
arch/arm/mach-msm/timer.c +40 -29
136 lines not on this page · raw message
Signature · 1 line
1.7.0.4
v4 cover genirq: handling GIC per-cpu interrupts
In reply to Marc ZyngierQuoted 19 lines · Marc Zyngier
The current GIC per-cpu interrupts (aka PPIs) suffer from a number of problems:
- They use a completely separate scheme to handle the interrupts, mostly because the PPI concept doesn't really match the kernel view of an interrupt.
- PPIs can only be used by the timer code, unless we add more low-level assembly code.
- The local timer code can only be used by devices generating PPIs, and not SPIs.
- At least one platform (msm) has started implementing its own alternative scheme.
- Some low-level code gets duplicated, as usual...The proposed solution is to handle the PPIs using the same path as SPIs. A new core API is added to deal with per-cpu interrupts in a less awkward way. The local timer code is updated to reflect these changes.
Quoted 8 lines
The core API changes are based on an initial idea by Thomas Gleixner.
Tested on ARM Versatile Express (Cortex A15), ARM RealView PB11MP, OMAP4 (Panda) and Tegra (Harmony). Patch series against next-20110930.
The two first patches can also be found in Thomas' tree:
git://tesla.tglx.de/git/linux-2.6-tip irq/core
So, how do we deal with merging this without ending up with some problematical inter-tree dependencies?
It looks like I'll see conflicts with:arch/arm/common/gic.carch/arm/kernel/smp.carch/arm/include/asm/localtimer.h
and possibly:arch/arm/include/asm/smp.harch/arm/kernel/irq.c
as well. I've not checked with patch 4, so there may be some more too.
Some of this is probably because of 7123/1 and 7124/1.
v4 cover genirq: handling GIC per-cpu interrupts
Quoted 25 lines · Russell King - ARM Linux
Quoted 24 lines · Marc Zyngier
The current GIC per-cpu interrupts (aka PPIs) suffer from a number of problems:
- They use a completely separate scheme to handle the interrupts, mostly because the PPI concept doesn't really match the kernel view of an interrupt.
- PPIs can only be used by the timer code, unless we add more low-level assembly code.
- The local timer code can only be used by devices generating PPIs, and not SPIs.
- At least one platform (msm) has started implementing its own alternative scheme.
- Some low-level code gets duplicated, as usual...The proposed solution is to handle the PPIs using the same path as SPIs. A new core API is added to deal with per-cpu interrupts in a less awkward way. The local timer code is updated to reflect these changes.
The core API changes are based on an initial idea by Thomas Gleixner.
Tested on ARM Versatile Express (Cortex A15), ARM RealView PB11MP, OMAP4 (Panda) and Tegra (Harmony). Patch series against next-20110930.
Quoted 6 lines
Quoted 3 lines
The two first patches can also be found in Thomas' tree:
git://tesla.tglx.de/git/linux-2.6-tip irq/coreSo, how do we deal with merging this without ending up with some problematical inter-tree dependencies?
My view on this is that the whole series should ideally be merged via one tree only. I suspect that yours would be the best candidate, as there is probably little chance of conflicts on the core code.
Otherwise, we'd have to do a two step merge, adding the ARM bits once the core code has been merged.
Quoted 5 lines
It looks like I'll see conflicts with:
arch/arm/common/gic.carch/arm/kernel/smp.carch/arm/include/asm/localtimer.h
Quoted 7 lines
and possibly:
arch/arm/include/asm/smp.harch/arm/kernel/irq.cas well. I've not checked with patch 4, so there may be some more too.
Some of this is probably because of 7123/1 and 7124/1.
Do you have a branch you consider stable enough for me to rebase this series on? I've already solved these conflicts against -next, so rebasing it should be faily trivial.
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
v4 cover genirq: handling GIC per-cpu interrupts
In reply to Russell King - ARM LinuxQuoted 37 lines · Russell King - ARM Linux
Quoted 19 lines · Marc Zyngier
The current GIC per-cpu interrupts (aka PPIs) suffer from a number of problems:
- They use a completely separate scheme to handle the interrupts, mostly because the PPI concept doesn't really match the kernel view of an interrupt.
- PPIs can only be used by the timer code, unless we add more low-level assembly code.
- The local timer code can only be used by devices generating PPIs, and not SPIs.
- At least one platform (msm) has started implementing its own alternative scheme.
- Some low-level code gets duplicated, as usual...The proposed solution is to handle the PPIs using the same path as SPIs. A new core API is added to deal with per-cpu interrupts in a less awkward way. The local timer code is updated to reflect these changes.
Quoted 8 lines
The core API changes are based on an initial idea by Thomas Gleixner.
Tested on ARM Versatile Express (Cortex A15), ARM RealView PB11MP, OMAP4 (Panda) and Tegra (Harmony). Patch series against next-20110930.
The two first patches can also be found in Thomas' tree:
git://tesla.tglx.de/git/linux-2.6-tip irq/coreSo, how do we deal with merging this without ending up with some problematical inter-tree dependencies?
It looks like I'll see conflicts with:
arch/arm/common/gic.carch/arm/kernel/smp.carch/arm/include/asm/localtimer.h
Quoted 7 lines
and possibly:
arch/arm/include/asm/smp.harch/arm/kernel/irq.cas well. I've not checked with patch 4, so there may be some more too.
Some of this is probably because of 7123/1 and 7124/1.
I've set up a branch based on your "smp" branch, resolving the above conflicts:
git://github.com/mzyngier/arm-platforms.git ppi-for-rmk
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
v4 cover genirq: handling GIC per-cpu interrupts
Quoted 42 lines · Marc Zyngier
Quoted 41 lines · Russell King - ARM Linux
Quoted 19 lines · Marc Zyngier
The current GIC per-cpu interrupts (aka PPIs) suffer from a number of problems:
- They use a completely separate scheme to handle the interrupts, mostly because the PPI concept doesn't really match the kernel view of an interrupt.
- PPIs can only be used by the timer code, unless we add more low-level assembly code.
- The local timer code can only be used by devices generating PPIs, and not SPIs.
- At least one platform (msm) has started implementing its own alternative scheme.
- Some low-level code gets duplicated, as usual...The proposed solution is to handle the PPIs using the same path as SPIs. A new core API is added to deal with per-cpu interrupts in a less awkward way. The local timer code is updated to reflect these changes.
Quoted 8 lines
The core API changes are based on an initial idea by Thomas Gleixner.
Tested on ARM Versatile Express (Cortex A15), ARM RealView PB11MP, OMAP4 (Panda) and Tegra (Harmony). Patch series against next-20110930.
The two first patches can also be found in Thomas' tree:
git://tesla.tglx.de/git/linux-2.6-tip irq/coreSo, how do we deal with merging this without ending up with some problematical inter-tree dependencies?
It looks like I'll see conflicts with:
arch/arm/common/gic.carch/arm/kernel/smp.carch/arm/include/asm/localtimer.hand possibly:
arch/arm/include/asm/smp.harch/arm/kernel/irq.c
Quoted 9 lines
Quoted 3 lines
as well. I've not checked with patch 4, so there may be some more too.
Some of this is probably because of 7123/1 and 7124/1.
I've set up a branch based on your "smp" branch, resolving the above conflicts:
git://github.com/mzyngier/arm-platforms.gitppi-for-rmk
Hi Russell,
It seems that you are going to queue this series for v3.2-rc1. I'm moving my imx6q series onto it. Otherwise, please let me know.
Signature · 2 lines
Regards, Shawn
v4 cover genirq: handling GIC per-cpu interrupts
In reply to Marc ZyngierQuoted 42 lines · Marc Zyngier
Quoted 41 lines · Russell King - ARM Linux
Quoted 19 lines · Marc Zyngier
The current GIC per-cpu interrupts (aka PPIs) suffer from a number of problems:
- They use a completely separate scheme to handle the interrupts, mostly because the PPI concept doesn't really match the kernel view of an interrupt.
- PPIs can only be used by the timer code, unless we add more low-level assembly code.
- The local timer code can only be used by devices generating PPIs, and not SPIs.
- At least one platform (msm) has started implementing its own alternative scheme.
- Some low-level code gets duplicated, as usual...The proposed solution is to handle the PPIs using the same path as SPIs. A new core API is added to deal with per-cpu interrupts in a less awkward way. The local timer code is updated to reflect these changes.
Quoted 8 lines
The core API changes are based on an initial idea by Thomas Gleixner.
Tested on ARM Versatile Express (Cortex A15), ARM RealView PB11MP, OMAP4 (Panda) and Tegra (Harmony). Patch series against next-20110930.
The two first patches can also be found in Thomas' tree:
git://tesla.tglx.de/git/linux-2.6-tip irq/coreSo, how do we deal with merging this without ending up with some problematical inter-tree dependencies?
It looks like I'll see conflicts with:
arch/arm/common/gic.carch/arm/kernel/smp.carch/arm/include/asm/localtimer.hand possibly:
arch/arm/include/asm/smp.harch/arm/kernel/irq.c
Quoted 8 lines
Quoted 3 lines
as well. I've not checked with patch 4, so there may be some more too.
Some of this is probably because of 7123/1 and 7124/1.
I've set up a branch based on your "smp" branch, resolving the above conflicts:
git://github.com/mzyngier/arm-platforms.gitppi-for-rmk
Please send me a proper pull request - and this almost got lost because it doesn't have a PULL tag in the subject line (and would've if Shawn Guo hadn't replied to this).