Handling both IRQs, FIFOP and SFD, in one isr and having only one variable to protect it brings up a race conditions we can hit with ienable_irq():
[ 2081.881115] WARNING: at kernel/irq/manage.c:274 enable_irq+0x4c/0x74() [ 2081.887621] Unbalanced enable for IRQ 112 Split the isr handler into two separate ones and provide two different irq_enabled varibales. Signed-off-by: Stefan Schmidt <[email protected]> --- drivers/ieee802154/cc2420.c | 43 ++++++++++++++++++++++++++++--------------- 1 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/ieee802154/cc2420.c b/drivers/ieee802154/cc2420.c index b2fdd57..c7a4468 100644 --- a/drivers/ieee802154/cc2420.c +++ b/drivers/ieee802154/cc2420.c @@ -85,7 +85,8 @@ struct cc2420_local { struct work_struct fifop_irqwork; struct work_struct sfd_irqwork; spinlock_t lock; - unsigned irq_disabled:1;/* P:lock */ + unsigned fifop_irq_disabled:1;/* P:lock */ + unsigned sfd_irq_disabled:1;/* P:lock */ unsigned is_tx:1; /* P:lock */ struct completion tx_complete; @@ -569,22 +570,18 @@ static void cc2420_unregister(struct cc2420_local *lp) ieee802154_free_device(lp->dev); } -static irqreturn_t cc2420_isr(int irq, void *data) +static irqreturn_t cc2420_fifop_isr(int irq, void *data) { struct cc2420_local *lp = data; spin_lock(&lp->lock); - if (!lp->irq_disabled) { + if (!lp->fifop_irq_disabled) { disable_irq_nosync(irq); - lp->irq_disabled = 1; + lp->fifop_irq_disabled = 1; } spin_unlock(&lp->lock); - if (irq == lp->sfd_irq) - schedule_work(&lp->sfd_irqwork); - - if (irq == lp->fifop_irq) - schedule_work(&lp->fifop_irqwork); + schedule_work(&lp->fifop_irqwork); return IRQ_HANDLED; } @@ -606,13 +603,29 @@ static void cc2420_fifop_irqwork(struct work_struct *work) cc2420_cmd_strobe(lp, CC2420_SFLUSHRX); spin_lock_irqsave(&lp->lock, flags); - if (lp->irq_disabled) { - lp->irq_disabled = 0; + if (lp->fifop_irq_disabled) { + lp->fifop_irq_disabled = 0; enable_irq(lp->fifop_irq); } spin_unlock_irqrestore(&lp->lock, flags); } +static irqreturn_t cc2420_sfd_isr(int irq, void *data) +{ + struct cc2420_local *lp = data; + + spin_lock(&lp->lock); + if (!lp->sfd_irq_disabled) { + disable_irq_nosync(irq); + lp->sfd_irq_disabled = 1; + } + spin_unlock(&lp->lock); + + schedule_work(&lp->sfd_irqwork); + + return IRQ_HANDLED; +} + static void cc2420_sfd_irqwork(struct work_struct *work) { struct cc2420_local *lp @@ -631,8 +644,8 @@ static void cc2420_sfd_irqwork(struct work_struct *work) } spin_lock_irqsave(&lp->lock, flags); - if (lp->irq_disabled) { - lp->irq_disabled = 0; + if (lp->sfd_irq_disabled) { + lp->sfd_irq_disabled = 0; enable_irq(lp->sfd_irq); } spin_unlock_irqrestore(&lp->lock, flags); @@ -782,7 +795,7 @@ static int __devinit cc2420_probe(struct spi_device *spi) lp->sfd_irq = gpio_to_irq(lp->pdata->sfd); ret = request_irq(lp->fifop_irq, - cc2420_isr, + cc2420_fifop_isr, IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&spi->dev), lp); @@ -792,7 +805,7 @@ static int __devinit cc2420_probe(struct spi_device *spi) } ret = request_irq(lp->sfd_irq, - cc2420_isr, + cc2420_sfd_isr, IRQF_TRIGGER_FALLING, dev_name(&spi->dev), lp); -- 1.7.5.4 ------------------------------------------------------------------------------ EditLive Enterprise is the world's most technically advanced content authoring tool. Experience the power of Track Changes, Inline Image Editing and ensure content is compliant with Accessibility Checking. http://p.sf.net/sfu/ephox-dev2dev _______________________________________________ Linux-zigbee-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel
