aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJonas Gorski <jogo@openwrt.org>2014-07-12 06:49:35 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-07-30 09:27:47 -0400
commit86ee4333ba991654f21b7a9e7a7bff0b319f0800 (patch)
tree878141286a33f5809675f5274e5fcd479a3e15bd /arch
parenta6dfde817cb45934e87d4493df0df3c12a6604e1 (diff)
MIPS: BCM63xx: Replace irq dispatch code with a generic version
The generic version uses a variable length of u32 registers instead of u32/u64. This allows easier support for "wider" registers without having to rewrite everything. This "generic" version is as fast as the old version in the best case (i == next set bit), and twice as fast in the worst case in 64 bits. Using a macro was chosen over a (forced) inline version because gcc generated more compact code with the macro. The change from (signed) int to unsigned int for i and to_call was intentional as the value can be only between 0 and (width - 1) anyway, and allowed gcc to optimise the code a bit further. Signed-off-by: Jonas Gorski <jogo@openwrt.org> Cc: linux-mips@linux-mips.org Cc: John Crispin <blogic@openwrt.org> Cc: Maxime Bizon <mbizon@freebox.fr> Cc: Florian Fainelli <florian@openwrt.org> Cc: Kevin Cernekee <cernekee@gmail.com> Cc: Gregory Fong <gregory.0xf0@gmail.com> Patchwork: https://patchwork.linux-mips.org/patch/7316/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/bcm63xx/irq.c130
1 files changed, 56 insertions, 74 deletions
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c
index f6c933a68c75..db9f2ef76ebe 100644
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -51,47 +51,65 @@ static inline void handle_internal(int intbit)
51 * will resume the loop where it ended the last time we left this 51 * will resume the loop where it ended the last time we left this
52 * function. 52 * function.
53 */ 53 */
54static void __dispatch_internal_32(void)
55{
56 u32 pending;
57 static int i;
58
59 pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr);
60
61 if (!pending)
62 return ;
63
64 while (1) {
65 int to_call = i;
66 54
67 i = (i + 1) & 0x1f; 55#define BUILD_IPIC_INTERNAL(width) \
68 if (pending & (1 << to_call)) { 56void __dispatch_internal_##width(void) \
69 handle_internal(to_call); 57{ \
70 break; 58 u32 pending[width / 32]; \
71 } 59 unsigned int src, tgt; \
72 } 60 bool irqs_pending = false; \
61 static unsigned int i; \
62 \
63 /* read registers in reverse order */ \
64 for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \
65 u32 val; \
66 \
67 val = bcm_readl(irq_stat_addr + src * sizeof(u32)); \
68 val &= bcm_readl(irq_mask_addr + src * sizeof(u32)); \
69 pending[--tgt] = val; \
70 \
71 if (val) \
72 irqs_pending = true; \
73 } \
74 \
75 if (!irqs_pending) \
76 return; \
77 \
78 while (1) { \
79 unsigned int to_call = i; \
80 \
81 i = (i + 1) & (width - 1); \
82 if (pending[to_call / 32] & (1 << (to_call & 0x1f))) { \
83 handle_internal(to_call); \
84 break; \
85 } \
86 } \
87} \
88 \
89static void __internal_irq_mask_##width(unsigned int irq) \
90{ \
91 u32 val; \
92 unsigned reg = (irq / 32) ^ (width/32 - 1); \
93 unsigned bit = irq & 0x1f; \
94 \
95 val = bcm_readl(irq_mask_addr + reg * sizeof(u32)); \
96 val &= ~(1 << bit); \
97 bcm_writel(val, irq_mask_addr + reg * sizeof(u32)); \
98} \
99 \
100static void __internal_irq_unmask_##width(unsigned int irq) \
101{ \
102 u32 val; \
103 unsigned reg = (irq / 32) ^ (width/32 - 1); \
104 unsigned bit = irq & 0x1f; \
105 \
106 val = bcm_readl(irq_mask_addr + reg * sizeof(u32)); \
107 val |= (1 << bit); \
108 bcm_writel(val, irq_mask_addr + reg * sizeof(u32)); \
73} 109}
74 110
75static void __dispatch_internal_64(void) 111BUILD_IPIC_INTERNAL(32);
76{ 112BUILD_IPIC_INTERNAL(64);
77 u64 pending;
78 static int i;
79
80 pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr);
81
82 if (!pending)
83 return ;
84
85 while (1) {
86 int to_call = i;
87
88 i = (i + 1) & 0x3f;
89 if (pending & (1ull << to_call)) {
90 handle_internal(to_call);
91 break;
92 }
93 }
94}
95 113
96asmlinkage void plat_irq_dispatch(void) 114asmlinkage void plat_irq_dispatch(void)
97{ 115{
@@ -128,42 +146,6 @@ asmlinkage void plat_irq_dispatch(void)
128 * internal IRQs operations: only mask/unmask on PERF irq mask 146 * internal IRQs operations: only mask/unmask on PERF irq mask
129 * register. 147 * register.
130 */ 148 */
131static void __internal_irq_mask_32(unsigned int irq)
132{
133 u32 mask;
134
135 mask = bcm_readl(irq_mask_addr);
136 mask &= ~(1 << irq);
137 bcm_writel(mask, irq_mask_addr);
138}
139
140static void __internal_irq_mask_64(unsigned int irq)
141{
142 u64 mask;
143
144 mask = bcm_readq(irq_mask_addr);
145 mask &= ~(1ull << irq);
146 bcm_writeq(mask, irq_mask_addr);
147}
148
149static void __internal_irq_unmask_32(unsigned int irq)
150{
151 u32 mask;
152
153 mask = bcm_readl(irq_mask_addr);
154 mask |= (1 << irq);
155 bcm_writel(mask, irq_mask_addr);
156}
157
158static void __internal_irq_unmask_64(unsigned int irq)
159{
160 u64 mask;
161
162 mask = bcm_readq(irq_mask_addr);
163 mask |= (1ull << irq);
164 bcm_writeq(mask, irq_mask_addr);
165}
166
167static void bcm63xx_internal_irq_mask(struct irq_data *d) 149static void bcm63xx_internal_irq_mask(struct irq_data *d)
168{ 150{
169 internal_irq_mask(d->irq - IRQ_INTERNAL_BASE); 151 internal_irq_mask(d->irq - IRQ_INTERNAL_BASE);