aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-01-23 14:19:32 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-01-23 14:19:32 -0500
commitd227e87e6c939c6071def92bc7691ad774c733ff (patch)
tree31fbc74974da765322b26de321e0b33f2f7e1478
parentf66d45e99eb7ca91822c3e3f6d7a98843c9626cb (diff)
parent364ca8a897eadb2f0e76b7f0ffe94168f6d83d66 (diff)
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: [MIPS] Vr41xx: Fix after GENERIC_HARDIRQS_NO__DO_IRQ change [MIPS] SMTC: Instant IPI replay.
-rw-r--r--arch/mips/Kconfig14
-rw-r--r--arch/mips/kernel/smtc.c54
-rw-r--r--arch/mips/vr41xx/common/irq.c12
-rw-r--r--drivers/char/vr41xx_giu.c114
-rw-r--r--include/asm-mips/irqflags.h22
5 files changed, 130 insertions, 86 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index fd2ff0698a85..bbd386f572d9 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1568,6 +1568,20 @@ config MIPS_MT_FPAFF
1568 depends on MIPS_MT 1568 depends on MIPS_MT
1569 default y 1569 default y
1570 1570
1571config MIPS_MT_SMTC_INSTANT_REPLAY
1572 bool "Low-latency Dispatch of Deferred SMTC IPIs"
1573 depends on MIPS_MT_SMTC
1574 default y
1575 help
1576 SMTC pseudo-interrupts between TCs are deferred and queued
1577 if the target TC is interrupt-inhibited (IXMT). In the first
1578 SMTC prototypes, these queued IPIs were serviced on return
1579 to user mode, or on entry into the kernel idle loop. The
1580 INSTANT_REPLAY option dispatches them as part of local_irq_restore()
1581 processing, which adds runtime overhead (hence the option to turn
1582 it off), but ensures that IPIs are handled promptly even under
1583 heavy I/O interrupt load.
1584
1571config MIPS_VPE_LOADER_TOM 1585config MIPS_VPE_LOADER_TOM
1572 bool "Load VPE program into memory hidden from linux" 1586 bool "Load VPE program into memory hidden from linux"
1573 depends on MIPS_VPE_LOADER 1587 depends on MIPS_VPE_LOADER
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index a8b387197d5b..44238ab2fc99 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -1017,6 +1017,33 @@ void setup_cross_vpe_interrupts(void)
1017 * SMTC-specific hacks invoked from elsewhere in the kernel. 1017 * SMTC-specific hacks invoked from elsewhere in the kernel.
1018 */ 1018 */
1019 1019
1020void smtc_ipi_replay(void)
1021{
1022 /*
1023 * To the extent that we've ever turned interrupts off,
1024 * we may have accumulated deferred IPIs. This is subtle.
1025 * If we use the smtc_ipi_qdepth() macro, we'll get an
1026 * exact number - but we'll also disable interrupts
1027 * and create a window of failure where a new IPI gets
1028 * queued after we test the depth but before we re-enable
1029 * interrupts. So long as IXMT never gets set, however,
1030 * we should be OK: If we pick up something and dispatch
1031 * it here, that's great. If we see nothing, but concurrent
1032 * with this operation, another TC sends us an IPI, IXMT
1033 * is clear, and we'll handle it as a real pseudo-interrupt
1034 * and not a pseudo-pseudo interrupt.
1035 */
1036 if (IPIQ[smp_processor_id()].depth > 0) {
1037 struct smtc_ipi *pipi;
1038 extern void self_ipi(struct smtc_ipi *);
1039
1040 while ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()]))) {
1041 self_ipi(pipi);
1042 smtc_cpu_stats[smp_processor_id()].selfipis++;
1043 }
1044 }
1045}
1046
1020void smtc_idle_loop_hook(void) 1047void smtc_idle_loop_hook(void)
1021{ 1048{
1022#ifdef SMTC_IDLE_HOOK_DEBUG 1049#ifdef SMTC_IDLE_HOOK_DEBUG
@@ -1113,29 +1140,14 @@ void smtc_idle_loop_hook(void)
1113 if (pdb_msg != &id_ho_db_msg[0]) 1140 if (pdb_msg != &id_ho_db_msg[0])
1114 printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg); 1141 printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg);
1115#endif /* SMTC_IDLE_HOOK_DEBUG */ 1142#endif /* SMTC_IDLE_HOOK_DEBUG */
1143
1116 /* 1144 /*
1117 * To the extent that we've ever turned interrupts off, 1145 * Replay any accumulated deferred IPIs. If "Instant Replay"
1118 * we may have accumulated deferred IPIs. This is subtle. 1146 * is in use, there should never be any.
1119 * If we use the smtc_ipi_qdepth() macro, we'll get an
1120 * exact number - but we'll also disable interrupts
1121 * and create a window of failure where a new IPI gets
1122 * queued after we test the depth but before we re-enable
1123 * interrupts. So long as IXMT never gets set, however,
1124 * we should be OK: If we pick up something and dispatch
1125 * it here, that's great. If we see nothing, but concurrent
1126 * with this operation, another TC sends us an IPI, IXMT
1127 * is clear, and we'll handle it as a real pseudo-interrupt
1128 * and not a pseudo-pseudo interrupt.
1129 */ 1147 */
1130 if (IPIQ[smp_processor_id()].depth > 0) { 1148#ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
1131 struct smtc_ipi *pipi; 1149 smtc_ipi_replay();
1132 extern void self_ipi(struct smtc_ipi *); 1150#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
1133
1134 if ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()])) != NULL) {
1135 self_ipi(pipi);
1136 smtc_cpu_stats[smp_processor_id()].selfipis++;
1137 }
1138 }
1139} 1151}
1140 1152
1141void smtc_soft_dump(void) 1153void smtc_soft_dump(void)
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index 397ba94cd7ec..16decf4ac2f4 100644
--- a/arch/mips/vr41xx/common/irq.c
+++ b/arch/mips/vr41xx/common/irq.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Interrupt handing routines for NEC VR4100 series. 2 * Interrupt handing routines for NEC VR4100 series.
3 * 3 *
4 * Copyright (C) 2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> 4 * Copyright (C) 2005-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -73,13 +73,19 @@ static void irq_dispatch(unsigned int irq)
73 if (cascade->get_irq != NULL) { 73 if (cascade->get_irq != NULL) {
74 unsigned int source_irq = irq; 74 unsigned int source_irq = irq;
75 desc = irq_desc + source_irq; 75 desc = irq_desc + source_irq;
76 desc->chip->ack(source_irq); 76 if (desc->chip->mask_ack)
77 desc->chip->mask_ack(source_irq);
78 else {
79 desc->chip->mask(source_irq);
80 desc->chip->ack(source_irq);
81 }
77 irq = cascade->get_irq(irq); 82 irq = cascade->get_irq(irq);
78 if (irq < 0) 83 if (irq < 0)
79 atomic_inc(&irq_err_count); 84 atomic_inc(&irq_err_count);
80 else 85 else
81 irq_dispatch(irq); 86 irq_dispatch(irq);
82 desc->chip->end(source_irq); 87 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
88 desc->chip->unmask(source_irq);
83 } else 89 } else
84 do_IRQ(irq); 90 do_IRQ(irq);
85} 91}
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index a744dad9cf45..0cea8d4907df 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 2002 MontaVista Software Inc. 4 * Copyright (C) 2002 MontaVista Software Inc.
5 * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> 5 * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
6 * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> 6 * Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -125,30 +125,17 @@ static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
125 return data; 125 return data;
126} 126}
127 127
128static unsigned int startup_giuint_low_irq(unsigned int irq) 128static void ack_giuint_low(unsigned int irq)
129{ 129{
130 unsigned int pin; 130 giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
131
132 pin = GPIO_PIN_OF_IRQ(irq);
133 giu_write(GIUINTSTATL, 1 << pin);
134 giu_set(GIUINTENL, 1 << pin);
135
136 return 0;
137} 131}
138 132
139static void shutdown_giuint_low_irq(unsigned int irq) 133static void mask_giuint_low(unsigned int irq)
140{ 134{
141 giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); 135 giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
142} 136}
143 137
144static void enable_giuint_low_irq(unsigned int irq) 138static void mask_ack_giuint_low(unsigned int irq)
145{
146 giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
147}
148
149#define disable_giuint_low_irq shutdown_giuint_low_irq
150
151static void ack_giuint_low_irq(unsigned int irq)
152{ 139{
153 unsigned int pin; 140 unsigned int pin;
154 141
@@ -157,46 +144,30 @@ static void ack_giuint_low_irq(unsigned int irq)
157 giu_write(GIUINTSTATL, 1 << pin); 144 giu_write(GIUINTSTATL, 1 << pin);
158} 145}
159 146
160static void end_giuint_low_irq(unsigned int irq) 147static void unmask_giuint_low(unsigned int irq)
161{ 148{
162 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 149 giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
163 giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
164} 150}
165 151
166static struct hw_interrupt_type giuint_low_irq_type = { 152static struct irq_chip giuint_low_irq_chip = {
167 .typename = "GIUINTL", 153 .name = "GIUINTL",
168 .startup = startup_giuint_low_irq, 154 .ack = ack_giuint_low,
169 .shutdown = shutdown_giuint_low_irq, 155 .mask = mask_giuint_low,
170 .enable = enable_giuint_low_irq, 156 .mask_ack = mask_ack_giuint_low,
171 .disable = disable_giuint_low_irq, 157 .unmask = unmask_giuint_low,
172 .ack = ack_giuint_low_irq,
173 .end = end_giuint_low_irq,
174}; 158};
175 159
176static unsigned int startup_giuint_high_irq(unsigned int irq) 160static void ack_giuint_high(unsigned int irq)
177{ 161{
178 unsigned int pin; 162 giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
179
180 pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
181 giu_write(GIUINTSTATH, 1 << pin);
182 giu_set(GIUINTENH, 1 << pin);
183
184 return 0;
185} 163}
186 164
187static void shutdown_giuint_high_irq(unsigned int irq) 165static void mask_giuint_high(unsigned int irq)
188{ 166{
189 giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); 167 giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
190} 168}
191 169
192static void enable_giuint_high_irq(unsigned int irq) 170static void mask_ack_giuint_high(unsigned int irq)
193{
194 giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
195}
196
197#define disable_giuint_high_irq shutdown_giuint_high_irq
198
199static void ack_giuint_high_irq(unsigned int irq)
200{ 171{
201 unsigned int pin; 172 unsigned int pin;
202 173
@@ -205,20 +176,17 @@ static void ack_giuint_high_irq(unsigned int irq)
205 giu_write(GIUINTSTATH, 1 << pin); 176 giu_write(GIUINTSTATH, 1 << pin);
206} 177}
207 178
208static void end_giuint_high_irq(unsigned int irq) 179static void unmask_giuint_high(unsigned int irq)
209{ 180{
210 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 181 giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
211 giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
212} 182}
213 183
214static struct hw_interrupt_type giuint_high_irq_type = { 184static struct irq_chip giuint_high_irq_chip = {
215 .typename = "GIUINTH", 185 .name = "GIUINTH",
216 .startup = startup_giuint_high_irq, 186 .ack = ack_giuint_high,
217 .shutdown = shutdown_giuint_high_irq, 187 .mask = mask_giuint_high,
218 .enable = enable_giuint_high_irq, 188 .mask_ack = mask_ack_giuint_high,
219 .disable = disable_giuint_high_irq, 189 .unmask = unmask_giuint_high,
220 .ack = ack_giuint_high_irq,
221 .end = end_giuint_high_irq,
222}; 190};
223 191
224static int giu_get_irq(unsigned int irq) 192static int giu_get_irq(unsigned int irq)
@@ -282,9 +250,15 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
282 break; 250 break;
283 } 251 }
284 } 252 }
253 set_irq_chip_and_handler(GIU_IRQ(pin),
254 &giuint_low_irq_chip,
255 handle_edge_irq);
285 } else { 256 } else {
286 giu_clear(GIUINTTYPL, mask); 257 giu_clear(GIUINTTYPL, mask);
287 giu_clear(GIUINTHTSELL, mask); 258 giu_clear(GIUINTHTSELL, mask);
259 set_irq_chip_and_handler(GIU_IRQ(pin),
260 &giuint_low_irq_chip,
261 handle_level_irq);
288 } 262 }
289 giu_write(GIUINTSTATL, mask); 263 giu_write(GIUINTSTATL, mask);
290 } else if (pin < GIUINT_HIGH_MAX) { 264 } else if (pin < GIUINT_HIGH_MAX) {
@@ -311,9 +285,15 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
311 break; 285 break;
312 } 286 }
313 } 287 }
288 set_irq_chip_and_handler(GIU_IRQ(pin),
289 &giuint_high_irq_chip,
290 handle_edge_irq);
314 } else { 291 } else {
315 giu_clear(GIUINTTYPH, mask); 292 giu_clear(GIUINTTYPH, mask);
316 giu_clear(GIUINTHTSELH, mask); 293 giu_clear(GIUINTHTSELH, mask);
294 set_irq_chip_and_handler(GIU_IRQ(pin),
295 &giuint_high_irq_chip,
296 handle_level_irq);
317 } 297 }
318 giu_write(GIUINTSTATH, mask); 298 giu_write(GIUINTSTATH, mask);
319 } 299 }
@@ -617,10 +597,11 @@ static const struct file_operations gpio_fops = {
617static int __devinit giu_probe(struct platform_device *dev) 597static int __devinit giu_probe(struct platform_device *dev)
618{ 598{
619 unsigned long start, size, flags = 0; 599 unsigned long start, size, flags = 0;
620 unsigned int nr_pins = 0; 600 unsigned int nr_pins = 0, trigger, i, pin;
621 struct resource *res1, *res2 = NULL; 601 struct resource *res1, *res2 = NULL;
622 void *base; 602 void *base;
623 int retval, i; 603 struct irq_chip *chip;
604 int retval;
624 605
625 switch (current_cpu_data.cputype) { 606 switch (current_cpu_data.cputype) {
626 case CPU_VR4111: 607 case CPU_VR4111:
@@ -688,11 +669,20 @@ static int __devinit giu_probe(struct platform_device *dev)
688 giu_write(GIUINTENL, 0); 669 giu_write(GIUINTENL, 0);
689 giu_write(GIUINTENH, 0); 670 giu_write(GIUINTENH, 0);
690 671
672 trigger = giu_read(GIUINTTYPH) << 16;
673 trigger |= giu_read(GIUINTTYPL);
691 for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { 674 for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
692 if (i < GIU_IRQ(GIUINT_HIGH_OFFSET)) 675 pin = GPIO_PIN_OF_IRQ(i);
693 irq_desc[i].chip = &giuint_low_irq_type; 676 if (pin < GIUINT_HIGH_OFFSET)
677 chip = &giuint_low_irq_chip;
694 else 678 else
695 irq_desc[i].chip = &giuint_high_irq_type; 679 chip = &giuint_high_irq_chip;
680
681 if (trigger & (1 << pin))
682 set_irq_chip_and_handler(i, chip, handle_edge_irq);
683 else
684 set_irq_chip_and_handler(i, chip, handle_level_irq);
685
696 } 686 }
697 687
698 return cascade_irq(GIUINT_IRQ, giu_get_irq); 688 return cascade_irq(GIUINT_IRQ, giu_get_irq);
diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h
index 46bf5de5ac72..af3b07dfad4b 100644
--- a/include/asm-mips/irqflags.h
+++ b/include/asm-mips/irqflags.h
@@ -15,6 +15,27 @@
15 15
16#include <asm/hazards.h> 16#include <asm/hazards.h>
17 17
18/*
19 * CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY does prompt replay of deferred IPIs,
20 * at the cost of branch and call overhead on each local_irq_restore()
21 */
22
23#ifdef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
24
25extern void smtc_ipi_replay(void);
26
27#define irq_restore_epilog(flags) \
28do { \
29 if (!(flags & 0x0400)) \
30 smtc_ipi_replay(); \
31} while (0)
32
33#else
34
35#define irq_restore_epilog(ignore) do { } while (0)
36
37#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
38
18__asm__ ( 39__asm__ (
19 " .macro raw_local_irq_enable \n" 40 " .macro raw_local_irq_enable \n"
20 " .set push \n" 41 " .set push \n"
@@ -193,6 +214,7 @@ do { \
193 : "=r" (__tmp1) \ 214 : "=r" (__tmp1) \
194 : "0" (flags) \ 215 : "0" (flags) \
195 : "memory"); \ 216 : "memory"); \
217 irq_restore_epilog(flags); \
196} while(0) 218} while(0)
197 219
198static inline int raw_irqs_disabled_flags(unsigned long flags) 220static inline int raw_irqs_disabled_flags(unsigned long flags)