diff options
author | Felix Fietkau <nbd@nbd.name> | 2020-04-09 14:37:50 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2020-05-12 19:52:31 +0200 |
commit | 9b90ab32f871eae0de982a6567fe32039a756af5 (patch) | |
tree | 03e779c920d3481663ce99869b0ec7a6e7ec8780 /drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | |
parent | 89829c9e65ab680f7e5a1658cb74bc6316ab036e (diff) |
mt76: mt7615: rework IRQ handling to prepare for MSI support
With MSI interrupts, IRQs must not be enabled from within the IRQ handler,
because that can lead to lost events.
Defer IRQ processing to a tasklet, which is also responsible for enabling
IRQs (to avoid race conditions against the handler)
Co-developed-by: Soul Huang <Soul.Huang@mediatek.com>
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Soul Huang <soul.huang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7615/mmio.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 3849bb6b49d0..e9f9cda6bb59 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -80,30 +80,42 @@ mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance) { struct mt7615_dev *dev = dev_instance; - u32 intr; - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + mt76_wr(dev, MT_INT_MASK_CSR, 0); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; - trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); + tasklet_schedule(&dev->irq_tasklet); + + return IRQ_HANDLED; +} + +static void mt7615_irq_tasklet(unsigned long data) +{ + struct mt7615_dev *dev = (struct mt7615_dev *)data; + u32 intr, mask = 0; + + mt76_wr(dev, MT_INT_MASK_CSR, 0); + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + + trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); intr &= dev->mt76.mmio.irqmask; if (intr & MT_INT_TX_DONE_ALL) { - mt7615_irq_disable(dev, MT_INT_TX_DONE_ALL); + mask |= MT_INT_TX_DONE_ALL; napi_schedule(&dev->mt76.tx_napi); } if (intr & MT_INT_RX_DONE(0)) { - mt7615_irq_disable(dev, MT_INT_RX_DONE(0)); + mask |= MT_INT_RX_DONE(0); napi_schedule(&dev->mt76.napi[0]); } if (intr & MT_INT_RX_DONE(1)) { - mt7615_irq_disable(dev, MT_INT_RX_DONE(1)); + mask |= MT_INT_RX_DONE(1); napi_schedule(&dev->mt76.napi[1]); } @@ -117,7 +129,7 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance) } } - return IRQ_HANDLED; + mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, @@ -154,6 +166,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, dev = container_of(mdev, struct mt7615_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); + tasklet_init(&dev->irq_tasklet, mt7615_irq_tasklet, (unsigned long)dev); dev->reg_map = map; dev->ops = ops; |