aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ieee802154
diff options
context:
space:
mode:
authorSascha Herrmann <sascha@ps.nvbi.de>2013-04-14 18:33:29 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-16 16:34:08 -0400
commit057dad6fcb89aa829bdf1f66b282a75defbf6761 (patch)
tree0db034d9f4706f706e1820997c2951d577502340 /drivers/net/ieee802154
parent43b5abe0640100a9e9424c91298c7993d443ffb7 (diff)
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 <sascha@ps.nvbi.de> Conflicts: drivers/net/ieee802154/at86rf230.c Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ieee802154')
-rw-r--r--drivers/net/ieee802154/at86rf230.c53
1 files changed, 38 insertions, 15 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index cf098889ba64..6f10b4964726 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -51,7 +51,7 @@ struct at86rf230_local {
51 struct ieee802154_dev *dev; 51 struct ieee802154_dev *dev;
52 52
53 spinlock_t lock; 53 spinlock_t lock;
54 bool irq_disabled; 54 bool irq_busy;
55 bool is_tx; 55 bool is_tx;
56}; 56};
57 57
@@ -547,7 +547,7 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
547 unsigned long flags; 547 unsigned long flags;
548 548
549 spin_lock(&lp->lock); 549 spin_lock(&lp->lock);
550 if (lp->irq_disabled) { 550 if (lp->irq_busy) {
551 spin_unlock(&lp->lock); 551 spin_unlock(&lp->lock);
552 return -EBUSY; 552 return -EBUSY;
553 } 553 }
@@ -708,8 +708,16 @@ static void at86rf230_irqwork(struct work_struct *work)
708 } 708 }
709 709
710 spin_lock_irqsave(&lp->lock, flags); 710 spin_lock_irqsave(&lp->lock, flags);
711 lp->irq_disabled = 0; 711 lp->irq_busy = 0;
712 spin_unlock_irqrestore(&lp->lock, flags); 712 spin_unlock_irqrestore(&lp->lock, flags);
713}
714
715static 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);
713 721
714 enable_irq(lp->spi->irq); 722 enable_irq(lp->spi->irq);
715} 723}
@@ -718,10 +726,8 @@ static irqreturn_t at86rf230_isr(int irq, void *data)
718{ 726{
719 struct at86rf230_local *lp = data; 727 struct at86rf230_local *lp = data;
720 728
721 disable_irq_nosync(irq);
722
723 spin_lock(&lp->lock); 729 spin_lock(&lp->lock);
724 lp->irq_disabled = 1; 730 lp->irq_busy = 1;
725 spin_unlock(&lp->lock); 731 spin_unlock(&lp->lock);
726 732
727 schedule_work(&lp->irqwork); 733 schedule_work(&lp->irqwork);
@@ -729,6 +735,13 @@ static irqreturn_t at86rf230_isr(int irq, void *data)
729 return IRQ_HANDLED; 735 return IRQ_HANDLED;
730} 736}
731 737
738static irqreturn_t at86rf230_isr_level(int irq, void *data)
739{
740 disable_irq_nosync(irq);
741
742 return at86rf230_isr(irq, data);
743}
744
732static int at86rf230_irq_polarity(struct at86rf230_local *lp, int pol) 745static int at86rf230_irq_polarity(struct at86rf230_local *lp, int pol)
733{ 746{
734 return at86rf230_write_subreg(lp, SR_IRQ_POLARITY, pol); 747 return at86rf230_write_subreg(lp, SR_IRQ_POLARITY, pol);
@@ -766,12 +779,7 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
766 if (rc) 779 if (rc)
767 return rc; 780 return rc;
768 781
769 rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, 0xff); /* IRQ_TRX_UR | 782 rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, IRQ_TRX_END);
770 * IRQ_CCA_ED |
771 * IRQ_TRX_END |
772 * IRQ_PLL_UNL |
773 * IRQ_PLL_LOCK
774 */
775 if (rc) 783 if (rc)
776 return rc; 784 return rc;
777 785
@@ -831,7 +839,9 @@ static int at86rf230_probe(struct spi_device *spi)
831 struct at86rf230_platform_data *pdata; 839 struct at86rf230_platform_data *pdata;
832 struct ieee802154_dev *dev; 840 struct ieee802154_dev *dev;
833 struct at86rf230_local *lp; 841 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;
835 int rc, supported = 0; 845 int rc, supported = 0;
836 const char *chip; 846 const char *chip;
837 847
@@ -861,8 +871,16 @@ static int at86rf230_probe(struct spi_device *spi)
861 dev->phy->channels_supported[0] = 0x7FFF800; 871 dev->phy->channels_supported[0] = 0x7FFF800;
862 dev->flags = IEEE802154_HW_OMIT_CKSUM; 872 dev->flags = IEEE802154_HW_OMIT_CKSUM;
863 873
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
864 mutex_init(&lp->bmux); 882 mutex_init(&lp->bmux);
865 INIT_WORK(&lp->irqwork, at86rf230_irqwork); 883 INIT_WORK(&lp->irqwork, irq_worker);
866 spin_lock_init(&lp->lock); 884 spin_lock_init(&lp->lock);
867 init_completion(&lp->tx_complete); 885 init_completion(&lp->tx_complete);
868 886
@@ -943,12 +961,17 @@ static int at86rf230_probe(struct spi_device *spi)
943 if (rc) 961 if (rc)
944 goto err_gpio_dir; 962 goto err_gpio_dir;
945 963
946 rc = request_irq(spi->irq, at86rf230_isr, 964 rc = request_irq(spi->irq, irq_handler,
947 IRQF_SHARED | pdata->irq_type, 965 IRQF_SHARED | pdata->irq_type,
948 dev_name(&spi->dev), lp); 966 dev_name(&spi->dev), lp);
949 if (rc) 967 if (rc)
950 goto err_gpio_dir; 968 goto err_gpio_dir;
951 969
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
952 rc = ieee802154_register_device(lp->dev); 975 rc = ieee802154_register_device(lp->dev);
953 if (rc) 976 if (rc)
954 goto err_irq; 977 goto err_irq;