aboutsummaryrefslogtreecommitdiffstats
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
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>
-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
-rw-r--r--drivers/sh/Kconfig11
-rw-r--r--drivers/sh/intc.c200
-rw-r--r--include/linux/sh_intc.h11
6 files changed, 244 insertions, 79 deletions
diff --git a/arch/sh/include/asm/irq.h b/arch/sh/include/asm/irq.h
index df8e1500527..99c593b3a82 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 235edf8065d..d7336036d04 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 d2d41d04665..f6a9319c28e 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();
diff --git a/drivers/sh/Kconfig b/drivers/sh/Kconfig
index 22c3cdaf22f..a54de0b9b3d 100644
--- a/drivers/sh/Kconfig
+++ b/drivers/sh/Kconfig
@@ -11,3 +11,14 @@ config INTC_USERIMASK
11 drivers that are using special priority levels. 11 drivers that are using special priority levels.
12 12
13 If in doubt, say N. 13 If in doubt, say N.
14
15config INTC_BALANCING
16 bool "Hardware IRQ balancing support"
17 depends on SMP && SUPERH && CPU_SUBTYPE_SH7786
18 help
19 This enables support for IRQ auto-distribution mode on SH-X3
20 SMP parts. All of the balancing and CPU wakeup decisions are
21 taken care of automatically by hardware for distributed
22 vectors.
23
24 If in doubt, say N.
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 77d10acf188..dcb4c833820 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -98,6 +98,9 @@ static DEFINE_SPINLOCK(vector_lock);
98static unsigned int intc_prio_level[NR_IRQS]; /* for now */ 98static unsigned int intc_prio_level[NR_IRQS]; /* for now */
99static unsigned int default_prio_level = 2; /* 2 - 16 */ 99static unsigned int default_prio_level = 2; /* 2 - 16 */
100static unsigned long ack_handle[NR_IRQS]; 100static unsigned long ack_handle[NR_IRQS];
101#ifdef CONFIG_INTC_BALANCING
102static unsigned long dist_handle[NR_IRQS];
103#endif
101 104
102static inline struct intc_desc_int *get_intc_desc(unsigned int irq) 105static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
103{ 106{
@@ -105,6 +108,47 @@ static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
105 return container_of(chip, struct intc_desc_int, chip); 108 return container_of(chip, struct intc_desc_int, chip);
106} 109}
107 110
111static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
112 unsigned long address)
113{
114 struct intc_window *window;
115 int k;
116
117 /* scan through physical windows and convert address */
118 for (k = 0; k < d->nr_windows; k++) {
119 window = d->window + k;
120
121 if (address < window->phys)
122 continue;
123
124 if (address >= (window->phys + window->size))
125 continue;
126
127 address -= window->phys;
128 address += (unsigned long)window->virt;
129
130 return address;
131 }
132
133 /* no windows defined, register must be 1:1 mapped virt:phys */
134 return address;
135}
136
137static unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
138{
139 unsigned int k;
140
141 address = intc_phys_to_virt(d, address);
142
143 for (k = 0; k < d->nr_reg; k++) {
144 if (d->reg[k] == address)
145 return k;
146 }
147
148 BUG();
149 return 0;
150}
151
108static inline unsigned int set_field(unsigned int value, 152static inline unsigned int set_field(unsigned int value,
109 unsigned int field_value, 153 unsigned int field_value,
110 unsigned int handle) 154 unsigned int handle)
@@ -238,6 +282,85 @@ static void (*intc_disable_fns[])(unsigned long addr,
238 [MODE_PCLR_REG] = intc_mode_field, 282 [MODE_PCLR_REG] = intc_mode_field,
239}; 283};
240 284
285#ifdef CONFIG_INTC_BALANCING
286static inline void intc_balancing_enable(unsigned int irq)
287{
288 struct intc_desc_int *d = get_intc_desc(irq);
289 unsigned long handle = dist_handle[irq];
290 unsigned long addr;
291
292 if (irq_balancing_disabled(irq) || !handle)
293 return;
294
295 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
296 intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
297}
298
299static inline void intc_balancing_disable(unsigned int irq)
300{
301 struct intc_desc_int *d = get_intc_desc(irq);
302 unsigned long handle = dist_handle[irq];
303 unsigned long addr;
304
305 if (irq_balancing_disabled(irq) || !handle)
306 return;
307
308 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
309 intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
310}
311
312static unsigned int intc_dist_data(struct intc_desc *desc,
313 struct intc_desc_int *d,
314 intc_enum enum_id)
315{
316 struct intc_mask_reg *mr = desc->hw.mask_regs;
317 unsigned int i, j, fn, mode;
318 unsigned long reg_e, reg_d;
319
320 for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
321 mr = desc->hw.mask_regs + i;
322
323 /*
324 * Skip this entry if there's no auto-distribution
325 * register associated with it.
326 */
327 if (!mr->dist_reg)
328 continue;
329
330 for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
331 if (mr->enum_ids[j] != enum_id)
332 continue;
333
334 fn = REG_FN_MODIFY_BASE;
335 mode = MODE_ENABLE_REG;
336 reg_e = mr->dist_reg;
337 reg_d = mr->dist_reg;
338
339 fn += (mr->reg_width >> 3) - 1;
340 return _INTC_MK(fn, mode,
341 intc_get_reg(d, reg_e),
342 intc_get_reg(d, reg_d),
343 1,
344 (mr->reg_width - 1) - j);
345 }
346 }
347
348 /*
349 * It's possible we've gotten here with no distribution options
350 * available for the IRQ in question, so we just skip over those.
351 */
352 return 0;
353}
354#else
355static inline void intc_balancing_enable(unsigned int irq)
356{
357}
358
359static inline void intc_balancing_disable(unsigned int irq)
360{
361}
362#endif
363
241static inline void _intc_enable(unsigned int irq, unsigned long handle) 364static inline void _intc_enable(unsigned int irq, unsigned long handle)
242{ 365{
243 struct intc_desc_int *d = get_intc_desc(irq); 366 struct intc_desc_int *d = get_intc_desc(irq);
@@ -253,6 +376,8 @@ static inline void _intc_enable(unsigned int irq, unsigned long handle)
253 intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ 376 intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
254 [_INTC_FN(handle)], irq); 377 [_INTC_FN(handle)], irq);
255 } 378 }
379
380 intc_balancing_enable(irq);
256} 381}
257 382
258static void intc_enable(unsigned int irq) 383static void intc_enable(unsigned int irq)
@@ -263,10 +388,12 @@ static void intc_enable(unsigned int irq)
263static void intc_disable(unsigned int irq) 388static void intc_disable(unsigned int irq)
264{ 389{
265 struct intc_desc_int *d = get_intc_desc(irq); 390 struct intc_desc_int *d = get_intc_desc(irq);
266 unsigned long handle = (unsigned long) get_irq_chip_data(irq); 391 unsigned long handle = (unsigned long)get_irq_chip_data(irq);
267 unsigned long addr; 392 unsigned long addr;
268 unsigned int cpu; 393 unsigned int cpu;
269 394
395 intc_balancing_disable(irq);
396
270 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { 397 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
271#ifdef CONFIG_SMP 398#ifdef CONFIG_SMP
272 if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) 399 if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
@@ -345,8 +472,7 @@ static void intc_mask_ack(unsigned int irq)
345 472
346 intc_disable(irq); 473 intc_disable(irq);
347 474
348 /* read register and write zero only to the assocaited bit */ 475 /* read register and write zero only to the associated bit */
349
350 if (handle) { 476 if (handle) {
351 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); 477 addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
352 switch (_INTC_FN(handle)) { 478 switch (_INTC_FN(handle)) {
@@ -375,7 +501,8 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
375{ 501{
376 int i; 502 int i;
377 503
378 /* this doesn't scale well, but... 504 /*
505 * this doesn't scale well, but...
379 * 506 *
380 * this function should only be used for cerain uncommon 507 * this function should only be used for cerain uncommon
381 * operations such as intc_set_priority() and intc_set_sense() 508 * operations such as intc_set_priority() and intc_set_sense()
@@ -386,7 +513,6 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
386 * memory footprint down is to make sure the array is sorted 513 * memory footprint down is to make sure the array is sorted
387 * and then perform a bisect to lookup the irq. 514 * and then perform a bisect to lookup the irq.
388 */ 515 */
389
390 for (i = 0; i < nr_hp; i++) { 516 for (i = 0; i < nr_hp; i++) {
391 if ((hp + i)->irq != irq) 517 if ((hp + i)->irq != irq)
392 continue; 518 continue;
@@ -417,7 +543,6 @@ int intc_set_priority(unsigned int irq, unsigned int prio)
417 * primary masking method is using intc_prio_level[irq] 543 * primary masking method is using intc_prio_level[irq]
418 * priority level will be set during next enable() 544 * priority level will be set during next enable()
419 */ 545 */
420
421 if (_INTC_FN(ihp->handle) != REG_FN_ERR) 546 if (_INTC_FN(ihp->handle) != REG_FN_ERR)
422 _intc_enable(irq, ihp->handle); 547 _intc_enable(irq, ihp->handle);
423 } 548 }
@@ -456,48 +581,6 @@ static int intc_set_sense(unsigned int irq, unsigned int type)
456 return 0; 581 return 0;
457} 582}
458 583
459static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
460 unsigned long address)
461{
462 struct intc_window *window;
463 int k;
464
465 /* scan through physical windows and convert address */
466 for (k = 0; k < d->nr_windows; k++) {
467 window = d->window + k;
468
469 if (address < window->phys)
470 continue;
471
472 if (address >= (window->phys + window->size))
473 continue;
474
475 address -= window->phys;
476 address += (unsigned long)window->virt;
477
478 return address;
479 }
480
481 /* no windows defined, register must be 1:1 mapped virt:phys */
482 return address;
483}
484
485static unsigned int __init intc_get_reg(struct intc_desc_int *d,
486 unsigned long address)
487{
488 unsigned int k;
489
490 address = intc_phys_to_virt(d, address);
491
492 for (k = 0; k < d->nr_reg; k++) {
493 if (d->reg[k] == address)
494 return k;
495 }
496
497 BUG();
498 return 0;
499}
500
501static intc_enum __init intc_grp_id(struct intc_desc *desc, 584static intc_enum __init intc_grp_id(struct intc_desc *desc,
502 intc_enum enum_id) 585 intc_enum enum_id)
503{ 586{
@@ -755,13 +838,14 @@ static void __init intc_register_irq(struct intc_desc *desc,
755 */ 838 */
756 set_bit(irq, intc_irq_map); 839 set_bit(irq, intc_irq_map);
757 840
758 /* Prefer single interrupt source bitmap over other combinations: 841 /*
842 * Prefer single interrupt source bitmap over other combinations:
843 *
759 * 1. bitmap, single interrupt source 844 * 1. bitmap, single interrupt source
760 * 2. priority, single interrupt source 845 * 2. priority, single interrupt source
761 * 3. bitmap, multiple interrupt sources (groups) 846 * 3. bitmap, multiple interrupt sources (groups)
762 * 4. priority, multiple interrupt sources (groups) 847 * 4. priority, multiple interrupt sources (groups)
763 */ 848 */
764
765 data[0] = intc_mask_data(desc, d, enum_id, 0); 849 data[0] = intc_mask_data(desc, d, enum_id, 0);
766 data[1] = intc_prio_data(desc, d, enum_id, 0); 850 data[1] = intc_prio_data(desc, d, enum_id, 0);
767 851
@@ -786,7 +870,8 @@ static void __init intc_register_irq(struct intc_desc *desc,
786 handle_level_irq, "level"); 870 handle_level_irq, "level");
787 set_irq_chip_data(irq, (void *)data[primary]); 871 set_irq_chip_data(irq, (void *)data[primary]);
788 872
789 /* set priority level 873 /*
874 * set priority level
790 * - this needs to be at least 2 for 5-bit priorities on 7780 875 * - this needs to be at least 2 for 5-bit priorities on 7780
791 */ 876 */
792 intc_prio_level[irq] = default_prio_level; 877 intc_prio_level[irq] = default_prio_level;
@@ -806,7 +891,6 @@ static void __init intc_register_irq(struct intc_desc *desc,
806 * only secondary priority should access registers, so 891 * only secondary priority should access registers, so
807 * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() 892 * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
808 */ 893 */
809
810 hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); 894 hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
811 hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); 895 hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
812 } 896 }
@@ -827,6 +911,11 @@ static void __init intc_register_irq(struct intc_desc *desc,
827 if (desc->hw.ack_regs) 911 if (desc->hw.ack_regs)
828 ack_handle[irq] = intc_ack_data(desc, d, enum_id); 912 ack_handle[irq] = intc_ack_data(desc, d, enum_id);
829 913
914#ifdef CONFIG_INTC_BALANCING
915 if (desc->hw.mask_regs)
916 dist_handle[irq] = intc_dist_data(desc, d, enum_id);
917#endif
918
830#ifdef CONFIG_ARM 919#ifdef CONFIG_ARM
831 set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */ 920 set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
832#endif 921#endif
@@ -892,6 +981,10 @@ int __init register_intc_controller(struct intc_desc *desc)
892 } 981 }
893 982
894 d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; 983 d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
984#ifdef CONFIG_INTC_BALANCING
985 if (d->nr_reg)
986 d->nr_reg += hw->nr_mask_regs;
987#endif
895 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; 988 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
896 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; 989 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
897 d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; 990 d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
@@ -912,6 +1005,9 @@ int __init register_intc_controller(struct intc_desc *desc)
912 smp = IS_SMP(hw->mask_regs[i]); 1005 smp = IS_SMP(hw->mask_regs[i]);
913 k += save_reg(d, k, hw->mask_regs[i].set_reg, smp); 1006 k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
914 k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp); 1007 k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
1008#ifdef CONFIG_INTC_BALANCING
1009 k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
1010#endif
915 } 1011 }
916 } 1012 }
917 1013
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index f0e8cca199c..0d6cd38e673 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -23,6 +23,9 @@ struct intc_group {
23struct intc_mask_reg { 23struct intc_mask_reg {
24 unsigned long set_reg, clr_reg, reg_width; 24 unsigned long set_reg, clr_reg, reg_width;
25 intc_enum enum_ids[32]; 25 intc_enum enum_ids[32];
26#ifdef CONFIG_INTC_BALANCING
27 unsigned long dist_reg;
28#endif
26#ifdef CONFIG_SMP 29#ifdef CONFIG_SMP
27 unsigned long smp; 30 unsigned long smp;
28#endif 31#endif
@@ -41,8 +44,14 @@ struct intc_sense_reg {
41 intc_enum enum_ids[16]; 44 intc_enum enum_ids[16];
42}; 45};
43 46
47#ifdef CONFIG_INTC_BALANCING
48#define INTC_SMP_BALANCING(reg) .dist_reg = (reg)
49#else
50#define INTC_SMP_BALANCING(reg)
51#endif
52
44#ifdef CONFIG_SMP 53#ifdef CONFIG_SMP
45#define INTC_SMP(stride, nr) .smp = (stride) | ((nr) << 8) 54#define INTC_SMP(stride, nr) .smp = (stride) | ((nr) << 8)
46#else 55#else
47#define INTC_SMP(stride, nr) 56#define INTC_SMP(stride, nr)
48#endif 57#endif