aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-04-15 00:13:52 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-04-15 00:13:52 -0400
commitdc825b17904a06bbd2f79d720b23156e4c01a22f (patch)
tree8f1e13b850a06264530f1f1bb680a541e73cef34 /arch/sh
parentfecf066c2d2fbc7e6a7e7e3a5af772a165bdd7b0 (diff)
sh: intc: IRQ auto-distribution support.
This implements support for hardware-managed IRQ balancing as implemented by SH-X3 cores (presently only hooked up for SH7786, but can probably be carried over to other SH-X3 cores, too). CPUs need to specify their distribution register along with the mask definitions, as these follow the same format. Peripheral IRQs that don't opt out of balancing will be automatically distributed at the whim of the hardware block, while each CPU needs to verify whether it is handling the IRQ or not, especially before clearing the mask. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/include/asm/irq.h16
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7786.c36
-rw-r--r--arch/sh/kernel/irq.c49
3 files changed, 75 insertions, 26 deletions
diff --git a/arch/sh/include/asm/irq.h b/arch/sh/include/asm/irq.h
index df8e1500527c..99c593b3a827 100644
--- a/arch/sh/include/asm/irq.h
+++ b/arch/sh/include/asm/irq.h
@@ -12,6 +12,14 @@
12#define NR_IRQS_LEGACY 8 /* Legacy external IRQ0-7 */ 12#define NR_IRQS_LEGACY 8 /* Legacy external IRQ0-7 */
13 13
14/* 14/*
15 * This is a special IRQ number for indicating that no IRQ has been
16 * triggered and to simply ignore the IRQ dispatch. This is a special
17 * case that can happen with IRQ auto-distribution when multiple CPUs
18 * are woken up and signalled in parallel.
19 */
20#define NO_IRQ_IGNORE ((unsigned int)-1)
21
22/*
15 * Convert back and forth between INTEVT and IRQ values. 23 * Convert back and forth between INTEVT and IRQ values.
16 */ 24 */
17#ifdef CONFIG_CPU_HAS_INTEVT 25#ifdef CONFIG_CPU_HAS_INTEVT
@@ -53,6 +61,14 @@ extern void irq_ctx_exit(int cpu);
53# define irq_ctx_exit(cpu) do { } while (0) 61# define irq_ctx_exit(cpu) do { } while (0)
54#endif 62#endif
55 63
64#ifdef CONFIG_INTC_BALANCING
65extern unsigned int irq_lookup(unsigned int irq);
66extern void irq_finish(unsigned int irq);
67#else
68#define irq_lookup(irq) (irq)
69#define irq_finish(irq) do { } while (0)
70#endif
71
56#include <asm-generic/irq.h> 72#include <asm-generic/irq.h>
57#ifdef CONFIG_CPU_SH5 73#ifdef CONFIG_CPU_SH5
58#include <cpu/irq.h> 74#include <cpu/irq.h>
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index 235edf8065df..d7336036d04d 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -573,7 +573,6 @@ static struct platform_device *sh7786_devices[] __initdata = {
573 &usb_ohci_device, 573 &usb_ohci_device,
574}; 574};
575 575
576
577/* 576/*
578 * Please call this function if your platform board 577 * Please call this function if your platform board
579 * use external clock for USB 578 * use external clock for USB
@@ -581,6 +580,7 @@ static struct platform_device *sh7786_devices[] __initdata = {
581#define USBCTL0 0xffe70858 580#define USBCTL0 0xffe70858
582#define CLOCK_MODE_MASK 0xffffff7f 581#define CLOCK_MODE_MASK 0xffffff7f
583#define EXT_CLOCK_MODE 0x00000080 582#define EXT_CLOCK_MODE 0x00000080
583
584void __init sh7786_usb_use_exclock(void) 584void __init sh7786_usb_use_exclock(void)
585{ 585{
586 u32 val = __raw_readl(USBCTL0) & CLOCK_MODE_MASK; 586 u32 val = __raw_readl(USBCTL0) & CLOCK_MODE_MASK;
@@ -598,6 +598,7 @@ void __init sh7786_usb_use_exclock(void)
598#define PLL_ENB 0x00000002 598#define PLL_ENB 0x00000002
599#define PHY_RST 0x00000004 599#define PHY_RST 0x00000004
600#define ACT_PLL_STATUS 0xc0000000 600#define ACT_PLL_STATUS 0xc0000000
601
601static void __init sh7786_usb_setup(void) 602static void __init sh7786_usb_setup(void)
602{ 603{
603 int i = 1000000; 604 int i = 1000000;
@@ -753,9 +754,19 @@ static struct intc_vect vectors[] __initdata = {
753#define INTMSK2 0xfe410068 754#define INTMSK2 0xfe410068
754#define INTMSKCLR2 0xfe41006c 755#define INTMSKCLR2 0xfe41006c
755 756
757#define INTDISTCR0 0xfe4100b0
758#define INTDISTCR1 0xfe4100b4
759#define INTACK 0xfe4100b8
760#define INTACKCLR 0xfe4100bc
761#define INT2DISTCR0 0xfe410900
762#define INT2DISTCR1 0xfe410904
763#define INT2DISTCR2 0xfe410908
764#define INT2DISTCR3 0xfe41090c
765
756static struct intc_mask_reg mask_registers[] __initdata = { 766static struct intc_mask_reg mask_registers[] __initdata = {
757 { CnINTMSK0, CnINTMSKCLR0, 32, 767 { CnINTMSK0, CnINTMSKCLR0, 32,
758 { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, 768 { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 },
769 INTC_SMP_BALANCING(INTDISTCR0) },
759 { INTMSK2, INTMSKCLR2, 32, 770 { INTMSK2, INTMSKCLR2, 32,
760 { IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH, 771 { IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
761 IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH, 772 IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
@@ -767,7 +778,8 @@ static struct intc_mask_reg mask_registers[] __initdata = {
767 IRL4_HHLL, IRL4_HHLH, IRL4_HHHL, 0, } }, 778 IRL4_HHLL, IRL4_HHLH, IRL4_HHHL, 0, } },
768 { CnINT2MSKR0, CnINT2MSKCR0 , 32, 779 { CnINT2MSKR0, CnINT2MSKCR0 , 32,
769 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 780 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
770 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, WDT } }, 781 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, WDT },
782 INTC_SMP_BALANCING(INT2DISTCR0) },
771 { CnINT2MSKR1, CnINT2MSKCR1, 32, 783 { CnINT2MSKR1, CnINT2MSKCR1, 32,
772 { TMU0_0, TMU0_1, TMU0_2, TMU0_3, TMU1_0, TMU1_1, TMU1_2, 0, 784 { TMU0_0, TMU0_1, TMU0_2, TMU0_3, TMU1_0, TMU1_1, TMU1_2, 0,
773 DMAC0_0, DMAC0_1, DMAC0_2, DMAC0_3, DMAC0_4, DMAC0_5, DMAC0_6, 785 DMAC0_0, DMAC0_1, DMAC0_2, DMAC0_3, DMAC0_4, DMAC0_5, DMAC0_6,
@@ -776,14 +788,14 @@ static struct intc_mask_reg mask_registers[] __initdata = {
776 HPB_0, HPB_1, HPB_2, 788 HPB_0, HPB_1, HPB_2,
777 SCIF0_0, SCIF0_1, SCIF0_2, SCIF0_3, 789 SCIF0_0, SCIF0_1, SCIF0_2, SCIF0_3,
778 SCIF1, 790 SCIF1,
779 TMU2, TMU3, 0, } }, 791 TMU2, TMU3, 0, }, INTC_SMP_BALANCING(INT2DISTCR1) },
780 { CnINT2MSKR2, CnINT2MSKCR2, 32, 792 { CnINT2MSKR2, CnINT2MSKCR2, 32,
781 { 0, 0, SCIF2, SCIF3, SCIF4, SCIF5, 793 { 0, 0, SCIF2, SCIF3, SCIF4, SCIF5,
782 Eth_0, Eth_1, 794 Eth_0, Eth_1,
783 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 795 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
784 PCIeC0_0, PCIeC0_1, PCIeC0_2, 796 PCIeC0_0, PCIeC0_1, PCIeC0_2,
785 PCIeC1_0, PCIeC1_1, PCIeC1_2, 797 PCIeC1_0, PCIeC1_1, PCIeC1_2,
786 USB, 0, 0 } }, 798 USB, 0, 0 }, INTC_SMP_BALANCING(INT2DISTCR2) },
787 { CnINT2MSKR3, CnINT2MSKCR3, 32, 799 { CnINT2MSKR3, CnINT2MSKCR3, 32,
788 { 0, 0, 0, 0, 0, 0, 800 { 0, 0, 0, 0, 0, 0,
789 I2C0, I2C1, 801 I2C0, I2C1,
@@ -792,7 +804,7 @@ static struct intc_mask_reg mask_registers[] __initdata = {
792 HAC0, HAC1, 804 HAC0, HAC1,
793 FLCTL, 0, 805 FLCTL, 0,
794 HSPI, GPIO0, GPIO1, Thermal, 806 HSPI, GPIO0, GPIO1, Thermal,
795 0, 0, 0, 0, 0, 0, 0, 0 } }, 807 0, 0, 0, 0, 0, 0, 0, 0 }, INTC_SMP_BALANCING(INT2DISTCR3) },
796}; 808};
797 809
798static struct intc_prio_reg prio_registers[] __initdata = { 810static struct intc_prio_reg prio_registers[] __initdata = {
@@ -910,6 +922,18 @@ static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
910#define INTC_INTMSKCLR2 INTMSKCLR2 922#define INTC_INTMSKCLR2 INTMSKCLR2
911#define INTC_USERIMASK 0xfe411000 923#define INTC_USERIMASK 0xfe411000
912 924
925#ifdef CONFIG_INTC_BALANCING
926unsigned int irq_lookup(unsigned int irq)
927{
928 return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
929}
930
931void irq_finish(unsigned int irq)
932{
933 __raw_writel(irq2evt(irq), INTACKCLR);
934}
935#endif
936
913void __init plat_irq_setup(void) 937void __init plat_irq_setup(void)
914{ 938{
915 /* disable IRQ3-0 + IRQ7-4 */ 939 /* disable IRQ3-0 + IRQ7-4 */
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index d2d41d046657..f6a9319c28e2 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -113,19 +113,14 @@ union irq_ctx {
113 113
114static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; 114static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
115static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; 115static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
116#endif
117 116
118asmlinkage __irq_entry int do_IRQ(unsigned int irq, struct pt_regs *regs) 117static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
118static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
119
120static inline void handle_one_irq(unsigned int irq)
119{ 121{
120 struct pt_regs *old_regs = set_irq_regs(regs);
121#ifdef CONFIG_IRQSTACKS
122 union irq_ctx *curctx, *irqctx; 122 union irq_ctx *curctx, *irqctx;
123#endif
124
125 irq_enter();
126 irq = irq_demux(irq);
127 123
128#ifdef CONFIG_IRQSTACKS
129 curctx = (union irq_ctx *)current_thread_info(); 124 curctx = (union irq_ctx *)current_thread_info();
130 irqctx = hardirq_ctx[smp_processor_id()]; 125 irqctx = hardirq_ctx[smp_processor_id()];
131 126
@@ -164,20 +159,9 @@ asmlinkage __irq_entry int do_IRQ(unsigned int irq, struct pt_regs *regs)
164 "r5", "r6", "r7", "r8", "t", "pr" 159 "r5", "r6", "r7", "r8", "t", "pr"
165 ); 160 );
166 } else 161 } else
167#endif
168 generic_handle_irq(irq); 162 generic_handle_irq(irq);
169
170 irq_exit();
171
172 set_irq_regs(old_regs);
173 return 1;
174} 163}
175 164
176#ifdef CONFIG_IRQSTACKS
177static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
178
179static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
180
181/* 165/*
182 * allocate per-cpu stacks for hardirq and for softirq processing 166 * allocate per-cpu stacks for hardirq and for softirq processing
183 */ 167 */
@@ -257,8 +241,33 @@ asmlinkage void do_softirq(void)
257 241
258 local_irq_restore(flags); 242 local_irq_restore(flags);
259} 243}
244#else
245static inline void handle_one_irq(unsigned int irq)
246{
247 generic_handle_irq(irq);
248}
260#endif 249#endif
261 250
251asmlinkage __irq_entry int do_IRQ(unsigned int irq, struct pt_regs *regs)
252{
253 struct pt_regs *old_regs = set_irq_regs(regs);
254
255 irq_enter();
256
257 irq = irq_demux(irq_lookup(irq));
258
259 if (irq != NO_IRQ_IGNORE) {
260 handle_one_irq(irq);
261 irq_finish(irq);
262 }
263
264 irq_exit();
265
266 set_irq_regs(old_regs);
267
268 return IRQ_HANDLED;
269}
270
262void __init init_IRQ(void) 271void __init init_IRQ(void)
263{ 272{
264 plat_irq_setup(); 273 plat_irq_setup();