Blob Blame History Raw
From b496490886f919a08e946ca4cf8bdd375f54e77f Mon Sep 17 00:00:00 2001
From: Sean Wang <sean.wang@mediatek.com>
Date: Tue, 18 Aug 2020 12:12:28 +0800
Subject: [PATCH] mt76: mt7663s: fix unable to handle kernel paging request
Git-commit: b496490886f919a08e946ca4cf8bdd375f54e77f
Patch-mainline: v5.10-rc1
References: git-fixes

[ backport note: contexts slightly adapted to the 5.9.y code base -- tiwai ]

Use buffer allocated with kmalloc instead of with stack to fix kernel
crash due to Unable to handle kernel paging request at virtual address
ffffffc0095cbce8.

[  156.977349] Unable to handle kernel paging request at virtual address ffffffc0095cbce8
[  156.985270] Mem abort info:
[  156.988059]   ESR = 0x96000045
[  156.991104]   Exception class = DABT (current EL), IL = 32 bits
[  156.997013]   SET = 0, FnV = 0
[  157.000057]   EA = 0, S1PTW = 0
[  157.003190] Data abort info:
[  157.006061]   ISV = 0, ISS = 0x00000045
[  157.009887]   CM = 0, WnR = 1
[  157.012850] swapper pgtable: 4k pages, 39-bit VAs, pgdp = 0000000042adcba2
[  157.019715] [ffffffc0095cbce8] pgd=0000000000000000, pud=0000000000000000
[  157.026499] Internal error: Oops: 96000045 [#1] PREEMPT SMP
[  157.032065] Modules linked in: mt7663s mt7663_usb_sdio_common mt7615_common

...

[  157.073007] Process CompositorTileW (pid: 1625, stack limit = 0x000000003f2389fc)
[  157.080484] CPU: 0 PID: 1625 Comm: CompositorTileW Not tainted 4.19.137 #36
[  157.092219] pstate: 80000085 (Nzcv daIf -PAN -UAO)
[  157.097012] pc : __memcpy+0xc0/0x180
[  157.100585] lr : swiotlb_tbl_unmap_single+0x84/0x14c
[  157.105540] sp : ffffff8008003cb0
[  157.108845] x29: ffffff8008003cb0 x28: ffffff9c1a211f60
[  157.114149] x27: ffffff9c19ecc018 x26: 0000000000001000
[  157.119452] x25: ffffff9c1a378000 x24: 0000000000000001
[  157.124755] x23: ffffff9c1a378000 x22: 00000000000001ff
[  157.130058] x21: 0000000000000000 x20: 00000000fbefe800
[  157.135360] x19: 0000000000000070 x18: 0000000000000000
[  157.140663] x17: 0000000000000000 x16: 0000000000000000
[  157.145965] x15: 0000000000000000 x14: 0000000000000000
[  157.151267] x13: 0000000000000000 x12: 000000000000000d
[  157.156569] x11: 000000000000000c x10: 0000000a7befe800
[  157.161873] x9 : fffffff680000000 x8 : 0000000000000000
[  157.167175] x7 : 0000000100000003 x6 : ffffffc0095cbce8
[  157.172479] x5 : 0000000000000000 x4 : 0000000000000000
[  157.177781] x3 : 0000000000000002 x2 : fffffffffffffff0
[  157.183085] x1 : ffffffca7befe810 x0 : ffffffc0095cbce8
[  157.188389] Call trace:
[  157.190832]  __memcpy+0xc0/0x180
[  157.194053]  swiotlb_unmap_sg_attrs+0xa8/0xb0
[  157.198406]  __swiotlb_unmap_sg_attrs+0x8c/0xa4
[  157.202931]  msdc_unprepare_data+0x6c/0x84
[  157.207019]  msdc_request_done+0x58/0x98
[  157.210934]  msdc_data_xfer_done+0x1a8/0x1d0
[  157.215195]  msdc_irq+0x12c/0x17c
[  157.218505]  __handle_irq_event_percpu+0xd8/0x298
[  157.223202]  handle_irq_event+0x60/0xdc
[  157.227031]  handle_fasteoi_irq+0xa4/0x1d4
[  157.231120]  __handle_domain_irq+0x84/0xc4
[  157.235210]  gic_handle_irq+0x124/0x1a4
[  157.239038]  el0_irq_naked+0x4c/0x54
[  157.242608] Code: 14000028 f1020042 5400024a a8c12027 (a88120c7)
[  157.248693] ---[ end trace 28b8090135b0a2e1 ]---
[  157.265589] Kernel panic - not syncing: Fatal exception in interrupt
[  157.271944] SMP: stopping secondary CPUs
[  157.275865] Kernel Offset: 0x1c10e00000 from 0xffffff8008000000
[  157.281779] CPU features: 0x0,2188200c
[  157.285519] Memory Limit: none

Fixes: a66cbdd6573d ("mt76: mt7615: introduce mt7663s support")
Co-developed-by: YN Chen <YN.Chen@mediatek.com>
Signed-off-by: YN Chen <YN.Chen@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 drivers/net/wireless/mediatek/mt76/mt76.h             |    1 
 drivers/net/wireless/mediatek/mt76/mt7615/sdio.c      |    8 +++++++
 drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c |   20 +++++++++---------
 3 files changed, 19 insertions(+), 10 deletions(-)

--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -453,6 +453,7 @@ struct mt76_sdio {
 	unsigned long state;
 
 	struct sdio_func *func;
+	void *intr_data;
 
 	struct {
 		struct mutex lock;
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
@@ -381,6 +381,14 @@ static int mt7663s_probe(struct sdio_fun
 		    (mt76_rr(dev, MT_HW_REV) & 0xff);
 	dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
 
+	mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
+					    sizeof(struct mt76s_intr),
+					    GFP_KERNEL);
+	if (!mdev->sdio.intr_data) {
+		ret = -ENOMEM;
+		goto err_deinit;
+	}
+
 	ret = mt76s_alloc_queues(&dev->mt76);
 	if (ret)
 		goto err_deinit;
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
@@ -234,34 +234,34 @@ void mt7663s_sdio_irq(struct sdio_func *
 {
 	struct mt7615_dev *dev = sdio_get_drvdata(func);
 	struct mt76_sdio *sdio = &dev->mt76.sdio;
-	struct mt76s_intr intr;
+	struct mt76s_intr *intr = sdio->intr_data;
 
 	/* disable interrupt */
 	sdio_writel(func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
 
 	do {
-		sdio_readsb(func, &intr, MCR_WHISR, sizeof(struct mt76s_intr));
-		trace_dev_irq(&dev->mt76, intr.isr, 0);
+		sdio_readsb(func, intr, MCR_WHISR, sizeof(struct mt76s_intr));
+		trace_dev_irq(&dev->mt76, intr->isr, 0);
 
 		if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
 			goto out;
 
-		if (intr.isr & WHIER_RX0_DONE_INT_EN) {
-			mt7663s_rx_run_queue(dev, 0, &intr);
+		if (intr->isr & WHIER_RX0_DONE_INT_EN) {
+			mt7663s_rx_run_queue(dev, 0, intr);
 			wake_up_process(sdio->kthread);
 		}
 
-		if (intr.isr & WHIER_RX1_DONE_INT_EN) {
-			mt7663s_rx_run_queue(dev, 1, &intr);
+		if (intr->isr & WHIER_RX1_DONE_INT_EN) {
+			mt7663s_rx_run_queue(dev, 1, intr);
 			wake_up_process(sdio->kthread);
 		}
 
-		if (intr.isr & WHIER_TX_DONE_INT_EN) {
-			mt7663s_refill_sched_quota(dev, intr.tx.wtqcr);
+		if (intr->isr & WHIER_TX_DONE_INT_EN) {
+			mt7663s_refill_sched_quota(dev, intr->tx.wtqcr);
 			mt7663s_tx_run_queues(dev);
 			wake_up_process(sdio->kthread);
 		}
-	} while (intr.isr);
+	} while (intr->isr);
 out:
 	/* enable interrupt */
 	sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);