Skip to content

Commit 057dad6

Browse files
hoermandavem330
authored andcommitted
at86rf230: change irq handling to prevent lockups with edge type irq
Implemented separate irq handling for edge and level type interrupt configuration. For edge type interrupts calls to disable_irq_nosync() and enable_irq() are removed. The at86rf230 resets the irq line only after the irq status register is read. Disabling the irq can lock the driver in situations where a irq is set by the radio while the driver is still reading the frame buffer. With irq_type configuration set to 0 the original behavior is preserverd. Additional the irq filter register is set to filter out all unused interrupts and the irq status register is read in the probe function to clear the irq line. Signed-off-by: Sascha Herrmann <[email protected]> Conflicts: drivers/net/ieee802154/at86rf230.c Signed-off-by: David S. Miller <[email protected]>
1 parent 43b5abe commit 057dad6

File tree

1 file changed

+38
-15
lines changed

1 file changed

+38
-15
lines changed

drivers/net/ieee802154/at86rf230.c

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct at86rf230_local {
5151
struct ieee802154_dev *dev;
5252

5353
spinlock_t lock;
54-
bool irq_disabled;
54+
bool irq_busy;
5555
bool is_tx;
5656
};
5757

@@ -547,7 +547,7 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
547547
unsigned long flags;
548548

549549
spin_lock(&lp->lock);
550-
if (lp->irq_disabled) {
550+
if (lp->irq_busy) {
551551
spin_unlock(&lp->lock);
552552
return -EBUSY;
553553
}
@@ -708,8 +708,16 @@ static void at86rf230_irqwork(struct work_struct *work)
708708
}
709709

710710
spin_lock_irqsave(&lp->lock, flags);
711-
lp->irq_disabled = 0;
711+
lp->irq_busy = 0;
712712
spin_unlock_irqrestore(&lp->lock, flags);
713+
}
714+
715+
static void at86rf230_irqwork_level(struct work_struct *work)
716+
{
717+
struct at86rf230_local *lp =
718+
container_of(work, struct at86rf230_local, irqwork);
719+
720+
at86rf230_irqwork(work);
713721

714722
enable_irq(lp->spi->irq);
715723
}
@@ -718,17 +726,22 @@ static irqreturn_t at86rf230_isr(int irq, void *data)
718726
{
719727
struct at86rf230_local *lp = data;
720728

721-
disable_irq_nosync(irq);
722-
723729
spin_lock(&lp->lock);
724-
lp->irq_disabled = 1;
730+
lp->irq_busy = 1;
725731
spin_unlock(&lp->lock);
726732

727733
schedule_work(&lp->irqwork);
728734

729735
return IRQ_HANDLED;
730736
}
731737

738+
static irqreturn_t at86rf230_isr_level(int irq, void *data)
739+
{
740+
disable_irq_nosync(irq);
741+
742+
return at86rf230_isr(irq, data);
743+
}
744+
732745
static int at86rf230_irq_polarity(struct at86rf230_local *lp, int pol)
733746
{
734747
return at86rf230_write_subreg(lp, SR_IRQ_POLARITY, pol);
@@ -766,12 +779,7 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
766779
if (rc)
767780
return rc;
768781

769-
rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, 0xff); /* IRQ_TRX_UR |
770-
* IRQ_CCA_ED |
771-
* IRQ_TRX_END |
772-
* IRQ_PLL_UNL |
773-
* IRQ_PLL_LOCK
774-
*/
782+
rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, IRQ_TRX_END);
775783
if (rc)
776784
return rc;
777785

@@ -831,7 +839,9 @@ static int at86rf230_probe(struct spi_device *spi)
831839
struct at86rf230_platform_data *pdata;
832840
struct ieee802154_dev *dev;
833841
struct at86rf230_local *lp;
834-
u8 man_id_0, man_id_1;
842+
u8 man_id_0, man_id_1, status;
843+
irq_handler_t irq_handler;
844+
work_func_t irq_worker;
835845
int rc, supported = 0;
836846
const char *chip;
837847

@@ -861,8 +871,16 @@ static int at86rf230_probe(struct spi_device *spi)
861871
dev->phy->channels_supported[0] = 0x7FFF800;
862872
dev->flags = IEEE802154_HW_OMIT_CKSUM;
863873

874+
if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
875+
irq_worker = at86rf230_irqwork;
876+
irq_handler = at86rf230_isr;
877+
} else {
878+
irq_worker = at86rf230_irqwork_level;
879+
irq_handler = at86rf230_isr_level;
880+
}
881+
864882
mutex_init(&lp->bmux);
865-
INIT_WORK(&lp->irqwork, at86rf230_irqwork);
883+
INIT_WORK(&lp->irqwork, irq_worker);
866884
spin_lock_init(&lp->lock);
867885
init_completion(&lp->tx_complete);
868886

@@ -943,12 +961,17 @@ static int at86rf230_probe(struct spi_device *spi)
943961
if (rc)
944962
goto err_gpio_dir;
945963

946-
rc = request_irq(spi->irq, at86rf230_isr,
964+
rc = request_irq(spi->irq, irq_handler,
947965
IRQF_SHARED | pdata->irq_type,
948966
dev_name(&spi->dev), lp);
949967
if (rc)
950968
goto err_gpio_dir;
951969

970+
/* Read irq status register to reset irq line */
971+
rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
972+
if (rc)
973+
goto err_irq;
974+
952975
rc = ieee802154_register_device(lp->dev);
953976
if (rc)
954977
goto err_irq;

0 commit comments

Comments
 (0)