From 2b75c0f93e395aa6130c20a08016b143e6ec8c53 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 7 May 2014 15:25:10 +0530 Subject: ARC: [SMP] unify cpu private IRQ requests (TIMER/IPI) The current cpu-private IRQ registration is ugly as it requires need to expose arch_unmask_irq() outside of intc code. So switch to percpu IRQ APIs: -request_percpu_irq [boot core] -enable_percpu_irq [all cores] Encapsulated in helper arc_request_percpu_irq() Signed-off-by: Vineet Gupta --- arch/arc/kernel/irq.c | 26 ++++++++++++++++++++++++++ arch/arc/kernel/smp.c | 15 ++++----------- arch/arc/kernel/time.c | 18 +++--------------- 3 files changed, 33 insertions(+), 26 deletions(-) (limited to 'arch/arc/kernel') diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index 7d653c0d0773..835fa5e71b62 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -150,6 +150,32 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs) set_irq_regs(old_regs); } +void arc_request_percpu_irq(int irq, int cpu, + irqreturn_t (*isr)(int irq, void *dev), + const char *irq_nm, + void *percpu_dev) +{ + /* Boot cpu calls request, all call enable */ + if (!cpu) { + int rc; + + /* + * These 2 calls are essential to making percpu IRQ APIs work + * Ideally these details could be hidden in irq chip map function + * but the issue is IPIs IRQs being static (non-DT) and platform + * specific, so we can't identify them there. + */ + irq_set_percpu_devid(irq); + irq_modify_status(irq, IRQ_NOAUTOEN, 0); /* @irq, @clr, @set */ + + rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev); + if (rc) + panic("Percpu IRQ request failed for %d\n", irq); + } + + enable_percpu_irq(irq, 0); +} + /* * arch_local_irq_enable - Enable interrupts. * diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index c802bb500602..1790c21760a1 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -136,7 +136,7 @@ void start_kernel_secondary(void) pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); if (machine_desc->init_smp) - machine_desc->init_smp(smp_processor_id()); + machine_desc->init_smp(cpu); arc_local_timer_setup(); @@ -338,18 +338,11 @@ irqreturn_t do_IPI(int irq, void *dev_id) */ static DEFINE_PER_CPU(int, ipi_dev); -static struct irqaction arc_ipi_irq = { - .name = "IPI Interrupt", - .flags = IRQF_PERCPU, - .handler = do_IPI, -}; - int smp_ipi_irq_setup(int cpu, int irq) { - if (!cpu) - return setup_irq(irq, &arc_ipi_irq); - else - arch_unmask_irq(irq); + int *dev = per_cpu_ptr(&ipi_dev, cpu); + + arc_request_percpu_irq(irq, cpu, do_IPI, "IPI Interrupt", dev); return 0; } diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 36c2aa99436f..f92cfb14ecd3 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -210,12 +210,6 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irqaction arc_timer_irq = { - .name = "Timer0 (clock-evt-dev)", - .flags = IRQF_TIMER | IRQF_PERCPU, - .handler = timer_irq_handler, -}; - /* * Setup the local event timer for @cpu */ @@ -228,15 +222,9 @@ void arc_local_timer_setup() clockevents_config_and_register(evt, arc_get_core_freq(), 0, ARC_TIMER_MAX); - /* - * setup the per-cpu timer IRQ handler - for all cpus - * For non boot CPU explicitly unmask at intc - * setup_irq() -> .. -> irq_startup() already does this on boot-cpu - */ - if (!cpu) - setup_irq(TIMER0_IRQ, &arc_timer_irq); - else - arch_unmask_irq(TIMER0_IRQ); + /* setup the per-cpu timer IRQ handler - for all cpus */ + arc_request_percpu_irq(TIMER0_IRQ, cpu, timer_irq_handler, + "Timer0 (per-cpu-tick)", evt); } /* -- cgit v1.3.1 From c9a98e1849a201ce88b42fc177b449df576a92b4 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 25 Jun 2014 17:14:03 +0530 Subject: ARC: update some comments Signed-off-by: Vineet Gupta --- arch/arc/kernel/time.c | 10 +++++++--- arch/arc/mm/tlbex.S | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'arch/arc/kernel') diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index f92cfb14ecd3..dbe74f418019 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -144,12 +144,12 @@ static struct clocksource arc_counter = { /********** Clock Event Device *********/ /* - * Arm the timer to interrupt after @limit cycles + * Arm the timer to interrupt after @cycles * The distinction for oneshot/periodic is done in arc_event_timer_ack() below */ -static void arc_timer_event_setup(unsigned int limit) +static void arc_timer_event_setup(unsigned int cycles) { - write_aux_reg(ARC_REG_TIMER0_LIMIT, limit); + write_aux_reg(ARC_REG_TIMER0_LIMIT, cycles); write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */ write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH); @@ -168,6 +168,10 @@ static void arc_clkevent_set_mode(enum clock_event_mode mode, { switch (mode) { case CLOCK_EVT_MODE_PERIODIC: + /* + * At X Hz, 1 sec = 1000ms -> X cycles; + * 10ms -> X / 100 cycles + */ arc_timer_event_setup(arc_get_core_freq() / HZ); break; case CLOCK_EVT_MODE_ONESHOT: diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S index 79bfc81358c9..d572f1c2c724 100644 --- a/arch/arc/mm/tlbex.S +++ b/arch/arc/mm/tlbex.S @@ -220,9 +220,9 @@ ex_saved_reg1: .macro CONV_PTE_TO_TLB and r3, r0, PTE_BITS_RWX ; r w x - lsl r2, r3, 3 ; r w x 0 0 0 + lsl r2, r3, 3 ; r w x 0 0 0 (GLOBAL, kernel only) and.f 0, r0, _PAGE_GLOBAL - or.z r2, r2, r3 ; r w x r w x + or.z r2, r2, r3 ; r w x r w x (!GLOBAL, user page) and r3, r0, PTE_BITS_NON_RWX_IN_PD1 ; Extract PFN+cache bits from PTE or r3, r3, r2 -- cgit v1.3.1 From c16e3e22839a33e1485b950ff7e86e58a862adea Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 12 Jun 2014 22:48:59 +0530 Subject: ARC: prune extra header includes from smp.c Signed-off-by: Vineet Gupta --- arch/arc/kernel/smp.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'arch/arc/kernel') diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 1790c21760a1..dcd317c47d09 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -12,23 +12,15 @@ * -- Initial Write (Borrowed heavily from ARM) */ -#include -#include #include #include #include #include -#include -#include #include #include -#include #include -#include #include -#include #include -#include #include #include #include -- cgit v1.3.1 From 878f46c71e99cfb6d8e4e15a561db63a3c9601e5 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 25 Jun 2014 17:16:04 +0530 Subject: ARC: [intc] don't mask all IRQ by default Hardware keeps them enabled on reset, and Linux needs to keep status quo. Any spurious interrupts will be reported/blocked by genirq. This helps remove a SMP IRQ quirk (next commit), where a peripheral IRQ is hard wired to core0, and request_irq()->unmask() happens on core1, keeping the IRQ masked on core0, needing an explicit unmask. Signed-off-by: Vineet Gupta --- arch/arc/kernel/irq.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'arch/arc/kernel') diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index 835fa5e71b62..02ffc764c97a 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -19,21 +19,16 @@ /* * Early Hardware specific Interrupt setup + * -Platform independent, needed for each CPU (not foldable into init_IRQ) * -Called very early (start_kernel -> setup_arch -> setup_processor) - * -Platform Independent (must for any ARC700) - * -Needed for each CPU (hence not foldable into init_IRQ) * * what it does ? - * -Disable all IRQs (on CPU side) * -Optionally, setup the High priority Interrupts as Level 2 IRQs */ void arc_init_IRQ(void) { int level_mask = 0; - /* Disable all IRQs: enable them as devices request */ - write_aux_reg(AUX_IENABLE, 0); - /* setup any high priority Interrupts (Level2 in ARCompact jargon) */ level_mask |= IS_ENABLED(CONFIG_ARC_IRQ3_LV2) << 3; level_mask |= IS_ENABLED(CONFIG_ARC_IRQ5_LV2) << 5; -- cgit v1.3.1 From 590892deb650fa152698f0a2f4eba44789e51c38 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 25 Jun 2014 17:25:46 +0530 Subject: ARC: [intc] mask/unmask can be hidden again Signed-off-by: Vineet Gupta --- arch/arc/include/asm/irqflags.h | 18 ------------------ arch/arc/kernel/irq.c | 20 ++++++++++++++------ 2 files changed, 14 insertions(+), 24 deletions(-) (limited to 'arch/arc/kernel') diff --git a/arch/arc/include/asm/irqflags.h b/arch/arc/include/asm/irqflags.h index cb7efc29f16f..587df8236e8b 100644 --- a/arch/arc/include/asm/irqflags.h +++ b/arch/arc/include/asm/irqflags.h @@ -131,24 +131,6 @@ static inline int arch_irqs_disabled(void) return arch_irqs_disabled_flags(arch_local_save_flags()); } -static inline void arch_mask_irq(unsigned int irq) -{ - unsigned int ienb; - - ienb = read_aux_reg(AUX_IENABLE); - ienb &= ~(1 << irq); - write_aux_reg(AUX_IENABLE, ienb); -} - -static inline void arch_unmask_irq(unsigned int irq) -{ - unsigned int ienb; - - ienb = read_aux_reg(AUX_IENABLE); - ienb |= (1 << irq); - write_aux_reg(AUX_IENABLE, ienb); -} - #else #ifdef CONFIG_TRACE_IRQFLAGS diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index 02ffc764c97a..620ec2fe32a9 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -55,20 +55,28 @@ void arc_init_IRQ(void) * below, per IRQ. */ -static void arc_mask_irq(struct irq_data *data) +static void arc_irq_mask(struct irq_data *data) { - arch_mask_irq(data->irq); + unsigned int ienb; + + ienb = read_aux_reg(AUX_IENABLE); + ienb &= ~(1 << data->irq); + write_aux_reg(AUX_IENABLE, ienb); } -static void arc_unmask_irq(struct irq_data *data) +static void arc_irq_unmask(struct irq_data *data) { - arch_unmask_irq(data->irq); + unsigned int ienb; + + ienb = read_aux_reg(AUX_IENABLE); + ienb |= (1 << data->irq); + write_aux_reg(AUX_IENABLE, ienb); } static struct irq_chip onchip_intc = { .name = "ARC In-core Intc", - .irq_mask = arc_mask_irq, - .irq_unmask = arc_unmask_irq, + .irq_mask = arc_irq_mask, + .irq_unmask = arc_irq_unmask, }; static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq, -- cgit v1.3.1