These patches update 4xx uic code. The first one
fixes a minor issue with edge-triggered interrupts,
while the second one makes it use generic level and edge irq
handlers. I've added irq ack'ing to the unmask callback for
level-triggered interrupts, because to de-assert them we have
to do 2 things is the exact order as below:
1. de-assert the external source in the ISR.
2. ack the IRQ on the UIC.
So, ack'ing level interrupts before unmasking them makes possible
to use generic level irq handler and it doesn't hurt, cause
we can never miss a level-triggered interrupt. It always stays
asserted untill the external source is removed and ack'ed on UIC.
These have been tested on Sequoia PowerPC 440EPx board.
Thanks,
Valentine.
This adds uic_mask_ack_irq() callback to PowerPC 4xx uic code
to avoid kernel crash. It is used for edge-triggered interrupts
by handle_uic_irq().
Signed-off-by: Valentine Barshak <redacted>
---
arch/powerpc/sysdev/uic.c | 18 +++++++++++++++++-
1 files changed, 17 insertions(+), 1 deletion(-)
From: David Gibson <hidden> Date: 2007-11-14 00:59:35
On Tue, Nov 13, 2007 at 11:25:21PM +0300, Valentine Barshak wrote:
This adds uic_mask_ack_irq() callback to PowerPC 4xx uic code
to avoid kernel crash. It is used for edge-triggered interrupts
by handle_uic_irq().
Oops. Obviously never caught this obvious bug, because I've never
used an edge-triggered interrupt on the Ebony yet.
Signed-off-by: Valentine Barshak <redacted>
Acked-by: David Gibson <redacted>
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
On Tue, 13 Nov 2007 23:15:59 +0300
Valentine Barshak [off-list ref] wrote:
These patches update 4xx uic code. The first one
fixes a minor issue with edge-triggered interrupts,
while the second one makes it use generic level and edge irq
handlers. I've added irq ack'ing to the unmask callback for
level-triggered interrupts, because to de-assert them we have
to do 2 things is the exact order as below:
1. de-assert the external source in the ISR.
2. ack the IRQ on the UIC.
So, ack'ing level interrupts before unmasking them makes possible
to use generic level irq handler and it doesn't hurt, cause
we can never miss a level-triggered interrupt. It always stays
asserted untill the external source is removed and ack'ed on UIC.
These have been tested on Sequoia PowerPC 440EPx board.
Is my mail server slow, or did patch 2 of 2 never make it out?
josh
From: David Gibson <hidden> Date: 2007-11-14 02:14:41
On Tue, Nov 13, 2007 at 11:27:31PM +0300, Valentine Barshak wrote:
This patch makes PowerPC 4xx UIC use generic edge and level irq handlers
instead of a custom handle_uic_irq() function. 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 level interrupts we need to ack 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.
Hrm. I *think* I'm convinced this is safe, although acking in a
callback which doesn't say it acks is rather yucky. Essentially this
code is trading flow readability (because just reading
handle_level_irq will tell you something other than what it does in
our case) for smaller code size. I'm not sure if this is a good trade
or not.
There's also one definite problem: according to the discussions I had
with Thomas Gleixner when I wrote uic.c, handle_edge_irq is not what
we want for edge interrupts.
Apparently handle_edge_irq is only for edge interrupts on "broken"
PICs which won't latch new interrupts while the irq is masked. UIC is
not in this category, so handle_level_irq is actually what we want,
even for an edge irq.
Yes, I thought the naming was more than a little confusing, too.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
From: David Gibson <hidden> Date: 2007-11-14 02:19:04
On Tue, Nov 13, 2007 at 08:05:14PM -0600, Josh Boyer wrote:
On Tue, 13 Nov 2007 23:15:59 +0300
Valentine Barshak [off-list ref] wrote:
quoted
These patches update 4xx uic code. The first one
fixes a minor issue with edge-triggered interrupts,
while the second one makes it use generic level and edge irq
handlers. I've added irq ack'ing to the unmask callback for
level-triggered interrupts, because to de-assert them we have
to do 2 things is the exact order as below:
1. de-assert the external source in the ISR.
2. ack the IRQ on the UIC.
So, ack'ing level interrupts before unmasking them makes possible
to use generic level irq handler and it doesn't hurt, cause
we can never miss a level-triggered interrupt. It always stays
asserted untill the external source is removed and ack'ed on UIC.
These have been tested on Sequoia PowerPC 440EPx board.
Is my mail server slow, or did patch 2 of 2 never make it out?
It reached me eventually, but only to my ibm address, not via the
list (whereas I got both copies of 0 and 1).
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-11-14 03:43:30
On Wed, 2007-11-14 at 13:13 +1100, David Gibson wrote:
Hrm. I *think* I'm convinced this is safe, although acking in a
callback which doesn't say it acks is rather yucky. Essentially this
code is trading flow readability (because just reading
handle_level_irq will tell you something other than what it does in
our case) for smaller code size. I'm not sure if this is a good trade
or not.
There's also one definite problem: according to the discussions I had
with Thomas Gleixner when I wrote uic.c, handle_edge_irq is not what
we want for edge interrupts.
Apparently handle_edge_irq is only for edge interrupts on "broken"
PICs which won't latch new interrupts while the irq is masked. UIC is
not in this category, so handle_level_irq is actually what we want,
even for an edge irq.
Yes, I thought the naming was more than a little confusing, too.
Hrm... handle_edge_irq works for both and you have a small performance
benefit in not masking, and thus using handle_edge_irq, so I don't
totally agree here. Basically, what handle_edge_irq() does is lazy
masking. Now there -is- an issue here is that if you do lazy masking,
you need to be able to re-emit in some convenient way.
Ben.
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2007-11-14 03:46:54
On Tue, 2007-11-13 at 20:05 -0600, Josh Boyer wrote:
On Tue, 13 Nov 2007 23:15:59 +0300
Valentine Barshak [off-list ref] wrote:
quoted
These patches update 4xx uic code. The first one
fixes a minor issue with edge-triggered interrupts,
while the second one makes it use generic level and edge irq
handlers. I've added irq ack'ing to the unmask callback for
level-triggered interrupts, because to de-assert them we have
to do 2 things is the exact order as below:
1. de-assert the external source in the ISR.
2. ack the IRQ on the UIC.
So, ack'ing level interrupts before unmasking them makes possible
to use generic level irq handler and it doesn't hurt, cause
we can never miss a level-triggered interrupt. It always stays
asserted untill the external source is removed and ack'ed on UIC.
These have been tested on Sequoia PowerPC 440EPx board.
Is my mail server slow, or did patch 2 of 2 never make it out?
This patch makes PowerPC 4xx UIC use generic edge and level irq handlers
instead of a custom handle_uic_irq() function. 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 level interrupts we need to ack 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 <redacted>
---
arch/powerpc/sysdev/uic.c | 89 ++++++++++++----------------------------------
1 files changed, 24 insertions(+), 65 deletions(-)
@@ -99,6 +104,7 @@ static void uic_ack_irq(unsigned int virstaticvoiduic_mask_ack_irq(unsignedintvirq){+structirq_desc*desc=get_irq_desc(virq);structuic*uic=get_irq_chip_data(virq);unsignedintsrc=uic_irq_to_hw(virq);unsignedlongflags;
@@ -109,7 +115,16 @@ static void uic_mask_ack_irq(unsigned iner=mfdcr(uic->dcrbase+UIC_ER);er&=~sr;mtdcr(uic->dcrbase+UIC_ER,er);-mtdcr(uic->dcrbase+UIC_SR,sr);+/* on the uic, acking (i.e. clearing the sr bit)+*alevelirqwillhavenoeffectiftheinterrupt+*isstillassertedbythedevice,evenif+*theinterruptisalreadymasked.therefore+*weonlyacktheegdeinterruptshere,while+*levelinterruptsareack'edaftertheactual+*isrcallintheuic_unmask_irq()+*/+if(!(desc->status&IRQ_LEVEL))+mtdcr(uic->dcrbase+UIC_SR,sr);spin_unlock_irqrestore(&uic->lock,flags);}
@@ -156,8 +171,11 @@ static int uic_set_irq_type(unsigned intdesc->status&=~(IRQ_TYPE_SENSE_MASK|IRQ_LEVEL);desc->status|=flow_type&IRQ_TYPE_SENSE_MASK;-if(!trigger)+if(!trigger){desc->status|=IRQ_LEVEL;+set_irq_handler(virq,handle_level_irq);+}else+set_irq_handler(virq,handle_edge_irq);spin_unlock_irqrestore(&uic->lock,flags);
@@ -173,73 +191,14 @@ static struct irq_chip uic_irq_chip = {.set_type=uic_set_irq_type,};-/**-*handle_uic_irq-irqflowhandlerforUIC-*@irq:theinterruptnumber-*@desc:theinterruptdescriptionstructureforthisirq-*-*Thisismodifiedversionofthegenerichandle_level_irq()suitable-*fortheUIC.OntheUIC,acking(i.e.clearingtheSRbit)alevel-*irqwillhavenoeffectiftheinterruptisstillassertedbythe-*device,eveniftheinterruptisalreadymasked.Therefore,unlike-*thestandardhandle_level_irq(),wemustacktheinterrupt*after*-*invokingtheISR(whichshouldhavede-assertedtheinterruptin-*theexternalsource).Foredgeinterruptsweackatthebeginning-*insteadoftheend,tokeepthewindowinwhichwecanmissan-*interruptassmallaspossible.-*/-voidfastcallhandle_uic_irq(unsignedintirq,structirq_desc*desc)-{-unsignedintcpu=smp_processor_id();-structirqaction*action;-irqreturn_taction_ret;--spin_lock(&desc->lock);-if(desc->status&IRQ_LEVEL)-desc->chip->mask(irq);-else-desc->chip->mask_ack(irq);--if(unlikely(desc->status&IRQ_INPROGRESS))-gotoout_unlock;-desc->status&=~(IRQ_REPLAY|IRQ_WAITING);-kstat_cpu(cpu).irqs[irq]++;--/*-*Ifitsdisabledornoactionavailable-*keepitmaskedandgetoutofhere-*/-action=desc->action;-if(unlikely(!action||(desc->status&IRQ_DISABLED))){-desc->status|=IRQ_PENDING;-gotoout_unlock;-}--desc->status|=IRQ_INPROGRESS;-desc->status&=~IRQ_PENDING;-spin_unlock(&desc->lock);--action_ret=handle_IRQ_event(irq,action);--spin_lock(&desc->lock);-desc->status&=~IRQ_INPROGRESS;-if(desc->status&IRQ_LEVEL)-desc->chip->ack(irq);-if(!(desc->status&IRQ_DISABLED)&&desc->chip->unmask)-desc->chip->unmask(irq);-out_unlock:-spin_unlock(&desc->lock);-}-staticintuic_host_map(structirq_host*h,unsignedintvirq,irq_hw_number_thw){structuic*uic=h->host_data;set_irq_chip_data(virq,uic);-/* Despite the name, handle_level_irq() works for both level-*andedgeirqsonUIC.FIXME:checkthisiscorrect*/-set_irq_chip_and_handler(virq,&uic_irq_chip,handle_uic_irq);+/* appropriate irq handler is set by set_irq_type() */+set_irq_chip(virq,&uic_irq_chip);/* Set default irq type */set_irq_type(virq,IRQ_TYPE_NONE);
On Wed, 2007-11-14 at 13:13 +1100, David Gibson wrote:
quoted
Hrm. I *think* I'm convinced this is safe, although acking in a
callback which doesn't say it acks is rather yucky. Essentially this
code is trading flow readability (because just reading
handle_level_irq will tell you something other than what it does in
our case) for smaller code size. I'm not sure if this is a good trade
or not.
It's not just code size. Actually, I was having problems with Ingo's
real-time patch, that works on all platforms that use generic hard irq
handlers and doesn't work just on 4xx since we use a custom one here.
And I thought that using generic handlers would be easier to maintain.
I agree that ack'ing in a callback which doesn't say it ack's looks odd,
but ack'ing level-triggered interrupts is quirky on UIC itself. So, I
just thought that adding a couple of quirks to mask_ack and unmask
callbacks was not that bad.
quoted
There's also one definite problem: according to the discussions I had
with Thomas Gleixner when I wrote uic.c, handle_edge_irq is not what
we want for edge interrupts.
Apparently handle_edge_irq is only for edge interrupts on "broken"
PICs which won't latch new interrupts while the irq is masked. UIC is
not in this category, so handle_level_irq is actually what we want,
even for an edge irq.
Yes, I thought the naming was more than a little confusing, too.
Hrm... handle_edge_irq works for both and you have a small performance
benefit in not masking, and thus using handle_edge_irq, so I don't
totally agree here. Basically, what handle_edge_irq() does is lazy
masking. Now there -is- an issue here is that if you do lazy masking,
you need to be able to re-emit in some convenient way.
With the ack quirks added we can use handle_level_irq for edge-triggered
interrupts. I'll test and resubmit the patch.
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 <redacted>
---
arch/powerpc/sysdev/uic.c | 81 ++++++++++------------------------------------
1 files changed, 19 insertions(+), 62 deletions(-)
@@ -99,6 +104,7 @@ static void uic_ack_irq(unsigned int virstaticvoiduic_mask_ack_irq(unsignedintvirq){+structirq_desc*desc=get_irq_desc(virq);structuic*uic=get_irq_chip_data(virq);unsignedintsrc=uic_irq_to_hw(virq);unsignedlongflags;
@@ -109,7 +115,16 @@ static void uic_mask_ack_irq(unsigned iner=mfdcr(uic->dcrbase+UIC_ER);er&=~sr;mtdcr(uic->dcrbase+UIC_ER,er);-mtdcr(uic->dcrbase+UIC_SR,sr);+/* On the UIC, acking (i.e. clearing the SR bit)+*alevelirqwillhavenoeffectiftheinterrupt+*isstillassertedbythedevice,evenif+*theinterruptisalreadymasked.Therefore+*weonlyacktheegdeinterruptshere,while+*levelinterruptsareack'edaftertheactual+*isrcallintheuic_unmask_irq()+*/+if(!(desc->status&IRQ_LEVEL))+mtdcr(uic->dcrbase+UIC_SR,sr);spin_unlock_irqrestore(&uic->lock,flags);}
@@ -239,7 +196,7 @@ static int uic_host_map(struct irq_host set_irq_chip_data(virq,uic);/* Despite the name, handle_level_irq() works for both level*andedgeirqsonUIC.FIXME:checkthisiscorrect*/-set_irq_chip_and_handler(virq,&uic_irq_chip,handle_uic_irq);+set_irq_chip_and_handler(virq,&uic_irq_chip,handle_level_irq);/* Set default irq type */set_irq_type(virq,IRQ_TYPE_NONE);