aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorValentine Barshak <vbarshak@ru.mvista.com>2007-11-14 09:00:52 -0500
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2007-12-23 14:23:47 -0500
commitc80905637efb4af6e58da91fae89ffcb2cf8f1aa (patch)
treedb6bfac2a50fd7c4a7823b5caf5c010527cc7f0f /arch/powerpc/sysdev
parent309ae1a363181a6b290b5bdfaee81123431f8644 (diff)
[POWERPC] 4xx: make UIC use generic level irq handler
This patch makes PowerPC 4xx UIC use generic level irq handler instead of a custom handle_uic_irq() function. We ack only edge irqs in mask_ack callback, since acking a level irq on UIC has no effect if the interrupt is still asserted by the device, even if the interrupt is already masked. So, to really de-assert the interrupt we need to de-assert the external source first *and* ack it on UIC then. The handle_level_irq() function masks and ack's the interrupt with mask_ack callback prior to calling the actual ISR and unmasks it at the end. So, to use it with UIC interrupts we need to ack level irqs in the unmask callback instead, after the ISR has de-asserted the external interrupt source. Even if we ack the interrupt that we didn't handle (unmask/ack it at the end of the handler, while next irq is already pending) it will not de-assert the irq, untill we de-assert its exteral source. Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/uic.c81
1 files changed, 19 insertions, 62 deletions
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 847a5496b869..ba024985e66a 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -60,14 +60,19 @@ struct uic {
60 60
61static void uic_unmask_irq(unsigned int virq) 61static void uic_unmask_irq(unsigned int virq)
62{ 62{
63 struct irq_desc *desc = get_irq_desc(virq);
63 struct uic *uic = get_irq_chip_data(virq); 64 struct uic *uic = get_irq_chip_data(virq);
64 unsigned int src = uic_irq_to_hw(virq); 65 unsigned int src = uic_irq_to_hw(virq);
65 unsigned long flags; 66 unsigned long flags;
66 u32 er; 67 u32 er, sr;
67 68
69 sr = 1 << (31-src);
68 spin_lock_irqsave(&uic->lock, flags); 70 spin_lock_irqsave(&uic->lock, flags);
71 /* ack level-triggered interrupts here */
72 if (desc->status & IRQ_LEVEL)
73 mtdcr(uic->dcrbase + UIC_SR, sr);
69 er = mfdcr(uic->dcrbase + UIC_ER); 74 er = mfdcr(uic->dcrbase + UIC_ER);
70 er |= 1 << (31 - src); 75 er |= sr;
71 mtdcr(uic->dcrbase + UIC_ER, er); 76 mtdcr(uic->dcrbase + UIC_ER, er);
72 spin_unlock_irqrestore(&uic->lock, flags); 77 spin_unlock_irqrestore(&uic->lock, flags);
73} 78}
@@ -99,6 +104,7 @@ static void uic_ack_irq(unsigned int virq)
99 104
100static void uic_mask_ack_irq(unsigned int virq) 105static void uic_mask_ack_irq(unsigned int virq)
101{ 106{
107 struct irq_desc *desc = get_irq_desc(virq);
102 struct uic *uic = get_irq_chip_data(virq); 108 struct uic *uic = get_irq_chip_data(virq);
103 unsigned int src = uic_irq_to_hw(virq); 109 unsigned int src = uic_irq_to_hw(virq);
104 unsigned long flags; 110 unsigned long flags;
@@ -109,7 +115,16 @@ static void uic_mask_ack_irq(unsigned int virq)
109 er = mfdcr(uic->dcrbase + UIC_ER); 115 er = mfdcr(uic->dcrbase + UIC_ER);
110 er &= ~sr; 116 er &= ~sr;
111 mtdcr(uic->dcrbase + UIC_ER, er); 117 mtdcr(uic->dcrbase + UIC_ER, er);
112 mtdcr(uic->dcrbase + UIC_SR, sr); 118 /* On the UIC, acking (i.e. clearing the SR bit)
119 * a level irq will have no effect if the interrupt
120 * is still asserted by the device, even if
121 * the interrupt is already masked. Therefore
122 * we only ack the egde interrupts here, while
123 * level interrupts are ack'ed after the actual
124 * isr call in the uic_unmask_irq()
125 */
126 if (!(desc->status & IRQ_LEVEL))
127 mtdcr(uic->dcrbase + UIC_SR, sr);
113 spin_unlock_irqrestore(&uic->lock, flags); 128 spin_unlock_irqrestore(&uic->lock, flags);
114} 129}
115 130
@@ -173,64 +188,6 @@ static struct irq_chip uic_irq_chip = {
173 .set_type = uic_set_irq_type, 188 .set_type = uic_set_irq_type,
174}; 189};
175 190
176/**
177 * handle_uic_irq - irq flow handler for UIC
178 * @irq: the interrupt number
179 * @desc: the interrupt description structure for this irq
180 *
181 * This is modified version of the generic handle_level_irq() suitable
182 * for the UIC. On the UIC, acking (i.e. clearing the SR bit) a level
183 * irq will have no effect if the interrupt is still asserted by the
184 * device, even if the interrupt is already masked. Therefore, unlike
185 * the standard handle_level_irq(), we must ack the interrupt *after*
186 * invoking the ISR (which should have de-asserted the interrupt in
187 * the external source). For edge interrupts we ack at the beginning
188 * instead of the end, to keep the window in which we can miss an
189 * interrupt as small as possible.
190 */
191void fastcall handle_uic_irq(unsigned int irq, struct irq_desc *desc)
192{
193 unsigned int cpu = smp_processor_id();
194 struct irqaction *action;
195 irqreturn_t action_ret;
196
197 spin_lock(&desc->lock);
198 if (desc->status & IRQ_LEVEL)
199 desc->chip->mask(irq);
200 else
201 desc->chip->mask_ack(irq);
202
203 if (unlikely(desc->status & IRQ_INPROGRESS))
204 goto out_unlock;
205 desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
206 kstat_cpu(cpu).irqs[irq]++;
207
208 /*
209 * If its disabled or no action available
210 * keep it masked and get out of here
211 */
212 action = desc->action;
213 if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
214 desc->status |= IRQ_PENDING;
215 goto out_unlock;
216 }
217
218 desc->status |= IRQ_INPROGRESS;
219 desc->status &= ~IRQ_PENDING;
220 spin_unlock(&desc->lock);
221
222 action_ret = handle_IRQ_event(irq, action);
223
224 spin_lock(&desc->lock);
225 desc->status &= ~IRQ_INPROGRESS;
226 if (desc->status & IRQ_LEVEL)
227 desc->chip->ack(irq);
228 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
229 desc->chip->unmask(irq);
230out_unlock:
231 spin_unlock(&desc->lock);
232}
233
234static int uic_host_map(struct irq_host *h, unsigned int virq, 191static int uic_host_map(struct irq_host *h, unsigned int virq,
235 irq_hw_number_t hw) 192 irq_hw_number_t hw)
236{ 193{
@@ -239,7 +196,7 @@ static int uic_host_map(struct irq_host *h, unsigned int virq,
239 set_irq_chip_data(virq, uic); 196 set_irq_chip_data(virq, uic);
240 /* Despite the name, handle_level_irq() works for both level 197 /* Despite the name, handle_level_irq() works for both level
241 * and edge irqs on UIC. FIXME: check this is correct */ 198 * and edge irqs on UIC. FIXME: check this is correct */
242 set_irq_chip_and_handler(virq, &uic_irq_chip, handle_uic_irq); 199 set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);
243 200
244 /* Set default irq type */ 201 /* Set default irq type */
245 set_irq_type(virq, IRQ_TYPE_NONE); 202 set_irq_type(virq, IRQ_TYPE_NONE);