Skip to contentSkip to conversation

fix mt76x2e hangs on U7612E mini-pcie

PATCH In review Lorenzo Bianconi 3 participants 6 messages Oct 27, 2019 – Oct 30, 2019

Subsystems (4)
lore
Share & tools
lore

Lorenzo Bianconi

author maintainer
#0 lore raw

v3 cover fix mt76x2e hangs on U7612E mini-pcie

Various mt76x2e issues have been reported on U7612E mini-pcie card [1]. On U7612E-H1 PCIE_ASPM causes continuous mcu hangs and instability and so patch 1/2 disable it by default.
Moreover mt76 does not properly unmap dma buffers for non-linear skbs. This issue may result in hw hangs if the system relies on IOMMU. Patch 2/2 fix the problem properly unmapping data fragments on non-linear skbs.

Changes since v2:
- fix compilation error if PCI support is not compiled

Changes since v1:
- simplify buf0 unmap condition
- use IS_ENABLED(CONFIG_PCIEASPM) instead of ifdef CONFIG_PCIEASPM
- check pci_disable_link_state return value

[1]: https://lore.kernel.org/netdev/[email protected]/

Lorenzo Bianconi (2):
mt76: mt76x2e: disable pcie_aspm by default
mt76: dma: fix buffer unmap with non-linear skbs

 drivers/net/wireless/mediatek/mt76/Makefile   |  2 +
 drivers/net/wireless/mediatek/mt76/dma.c      |  6 ++-
 drivers/net/wireless/mediatek/mt76/mt76.h     |  6 ++-
 .../net/wireless/mediatek/mt76/mt76x2/pci.c   |  2 +
 drivers/net/wireless/mediatek/mt76/pci.c      | 46 +++++++++++++++++++
 5 files changed, 58 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/wireless/mediatek/mt76/pci.c
Signature · 1 line
2.21.0
author maintainer
#1 lore raw

PATCH v3 1/2 mt76: mt76x2e: disable pcie_aspm by default

On same device (e.g. U7612E-H1) PCIE_ASPM causes continuous mcu hangs and instability. Since mt76x2 series does not manage PCIE PS states, first we try to disable ASPM using pci_disable_link_state. If it fails, we will disable PCIE PS configuring PCI registers.
This patch has been successfully tested on U7612E-H1 mini-pice card

---
 drivers/net/wireless/mediatek/mt76/Makefile   |  2 +
 drivers/net/wireless/mediatek/mt76/mt76.h     |  1 +
 .../net/wireless/mediatek/mt76/mt76x2/pci.c   |  2 +
 drivers/net/wireless/mediatek/mt76/pci.c      | 46 +++++++++++++++++++
 4 files changed, 51 insertions(+)
 create mode 100644 drivers/net/wireless/mediatek/mt76/pci.c
drivers/net/wireless/mediatek/mt76/Makefile +2 -0
index 4d03596e891f..d7a1ddc9e407 100644
@@ -8,6 +8,8 @@ mt76-y := \
 	mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
 	tx.o agg-rx.o mcu.o
 
+mt76-$(CONFIG_PCI) += pci.o
+
 mt76-usb-y := usb.o usb_trace.o
 
 CFLAGS_trace.o := -I$(src)
drivers/net/wireless/mediatek/mt76/mt76.h +1 -0
index 570c159515a0..dc468ed9434a 100644
@@ -578,6 +578,7 @@ bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
 #define mt76_poll_msec(dev, ...) __mt76_poll_msec(&((dev)->mt76), __VA_ARGS__)
 
 void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs);
+void mt76_pci_disable_aspm(struct pci_dev *pdev);
 
 static inline u16 mt76_chip(struct mt76_dev *dev)
 {
drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +2 -0
index 73c3104f8858..cf611d1b817c 100644
@@ -81,6 +81,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	/* RG_SSUSB_CDR_BR_PE1D = 0x3 */
 	mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3);
 
+	mt76_pci_disable_aspm(pdev);
+
 	return 0;
 
 error:
drivers/net/wireless/mediatek/mt76/pci.c new file +46 -0

46 lines not on this page · raw message

Signature · 1 line
2.21.0
#2 lore raw

Re: [PATCH v3 wireless-drivers 1/2] mt76: mt76x2e: disable pcie_aspm by default

Hi.

Quoted 7 lines · Lorenzo Bianconi

On same device (e.g. U7612E-H1) PCIE_ASPM causes continuous mcu hangs and instability. Since mt76x2 series does not manage PCIE PS states, first we try to disable ASPM using pci_disable_link_state. If it fails, we will disable PCIE PS configuring PCI registers.
This patch has been successfully tested on U7612E-H1 mini-pice card

For this revision, not yet ;) (see below).

Quoted 61 lines
---
 drivers/net/wireless/mediatek/mt76/Makefile   |  2 +
 drivers/net/wireless/mediatek/mt76/mt76.h     |  1 +
 .../net/wireless/mediatek/mt76/mt76x2/pci.c   |  2 +
 drivers/net/wireless/mediatek/mt76/pci.c      | 46 +++++++++++++++++++
 4 files changed, 51 insertions(+)
 create mode 100644 drivers/net/wireless/mediatek/mt76/pci.c
drivers/net/wireless/mediatek/mt76/Makefile +2 -0
index 4d03596e891f..d7a1ddc9e407 100644
@@ -8,6 +8,8 @@ mt76-y := \
 	mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
 	tx.o agg-rx.o mcu.o
 
+mt76-$(CONFIG_PCI) += pci.o
+
 mt76-usb-y := usb.o usb_trace.o
 
 CFLAGS_trace.o := -I$(src)
drivers/net/wireless/mediatek/mt76/mt76.h +1 -0
index 570c159515a0..dc468ed9434a 100644
@@ -578,6 +578,7 @@ bool __mt76_poll_msec(struct mt76_dev *dev, u32
 offset, u32 mask, u32 val,
 #define mt76_poll_msec(dev, ...) __mt76_poll_msec(&((dev)->mt76), 
 __VA_ARGS__)
 
 void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs);
+void mt76_pci_disable_aspm(struct pci_dev *pdev);
 

static inline u16 mt76_chip(struct mt76_dev *dev) {

drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +2 -0
index 73c3104f8858..cf611d1b817c 100644
@@ -81,6 +81,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct
 pci_device_id *id)
 	/* RG_SSUSB_CDR_BR_PE1D = 0x3 */
 	mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3);
 
+	mt76_pci_disable_aspm(pdev);
+
 	return 0;
 

error:

drivers/net/wireless/mediatek/mt76/pci.c new file +0 -0
new file mode 100644
index 000000000000..04c5a692bc85

drivers/net/wireless/mediatek/mt76/pci.c line 6

Quoted 6 lines
drivers/net/wireless/mediatek/mt76/pci.c new file +6 -0
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (C) 2019 Lorenzo Bianconi <[email protected]>
+ */
+
+#include <linux/pci.h>

FYI, I had to #include <linux/pci-aspm.h> on 5.3 kernel because this is where pci_disable_link_state() is defined. It is not needed on 5.4+ since the declaration got moved to pci.h; this is just a note for those who are going to test these changes on 5.3.

I'm still building the kernel, though. Will get back with the results later.

Quoted 40 lines
drivers/net/wireless/mediatek/mt76/pci.c new file +40 -0
+
+void mt76_pci_disable_aspm(struct pci_dev *pdev)
+{
+	struct pci_dev *parent = pdev->bus->self;
+	u16 aspm_conf, parent_aspm_conf = 0;
+
+	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf);
+	aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
+	if (parent) {
+		pcie_capability_read_word(parent, PCI_EXP_LNKCTL,
+					  &parent_aspm_conf);
+		parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
+	}
+
+	if (!aspm_conf && (!parent || !parent_aspm_conf)) {
+		/* aspm already disabled */
+		return;
+	}
+
+	dev_info(&pdev->dev, "disabling ASPM %s %s\n",
+		 (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "",
+		 (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : "");
+
+	if (IS_ENABLED(CONFIG_PCIEASPM)) {
+		int err;
+
+		err = pci_disable_link_state(pdev, aspm_conf);
+		if (!err)
+			return;
+	}
+
+	/* both device and parent should have the same ASPM setting.
+	 * disable ASPM in downstream component first and then upstream.
+	 */
+	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf);
+	if (parent)
+		pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
+					   aspm_conf);
+}
+EXPORT_SYMBOL_GPL(mt76_pci_disable_aspm);
Signature · 1 line
  Oleksandr Natalenko (post-factum)
#3 lore raw

Re: [PATCH v3 wireless-drivers 1/2] mt76: mt76x2e: disable pcie_aspm by default

In reply to Lorenzo Bianconi
Quoted 9 lines · Lorenzo Bianconi

On same device (e.g. U7612E-H1) PCIE_ASPM causes continuous mcu hangs and instability. Since mt76x2 series does not manage PCIE PS states, first we try to disable ASPM using pci_disable_link_state. If it fails, we will disable PCIE PS configuring PCI registers.
This patch has been successfully tested on U7612E-H1 mini-pice card

2 patches applied to wireless-drivers.git, thanks.

f37f05503575 mt76: mt76x2e: disable pcie_aspm by default 7bd0650be63c mt76: dma: fix buffer unmap with non-linear skbs

Signature · 3 lines
https://patchwork.kernel.org/patch/11214309/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
author maintainer
#4 lore raw

PATCH v3 2/2 mt76: dma: fix buffer unmap with non-linear skbs

In reply to Lorenzo Bianconi

mt76 dma layer is supposed to unmap skb data buffers while keep txwi mapped on hw dma ring. At the moment mt76 wrongly unmap txwi or does not unmap data fragments in even positions for non-linear skbs. This issue may result in hw hangs with A-MSDU if the system relies on IOMMU or SWIOTLB. Fix this behaviour properly unmapping data fragments on non-linear skbs.

Fixes 17f1de56df05 ("mt76: add common code shared between multiple chipsets")
---
 drivers/net/wireless/mediatek/mt76/dma.c  | 6 ++++--
 drivers/net/wireless/mediatek/mt76/mt76.h | 5 +++--
 2 files changed, 7 insertions(+), 4 deletions(-)
drivers/net/wireless/mediatek/mt76/dma.c +4 -2
index c747eb24581c..8f69d00bd940 100644
@@ -53,8 +53,10 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
 	u32 ctrl;
 	int i, idx = -1;
 
-	if (txwi)
+	if (txwi) {
 		q->entry[q->head].txwi = DMA_DUMMY_DATA;
+		q->entry[q->head].skip_buf0 = true;
+	}
 
 	for (i = 0; i < nbufs; i += 2, buf += 2) {
 		u32 buf0 = buf[0].addr, buf1 = 0;
@@ -97,7 +99,7 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,
 	__le32 __ctrl = READ_ONCE(q->desc[idx].ctrl);
 	u32 ctrl = le32_to_cpu(__ctrl);
 
-	if (!e->txwi || !e->skb) {
+	if (!e->skip_buf0) {
 		__le32 addr = READ_ONCE(q->desc[idx].buf0);
 		u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl);
 
drivers/net/wireless/mediatek/mt76/mt76.h +3 -2
index dc468ed9434a..8aec7ccf2d79 100644
@@ -93,8 +93,9 @@ struct mt76_queue_entry {
 		struct urb *urb;
 	};
 	enum mt76_txq_id qid;
-	bool schedule;
-	bool done;
+	bool skip_buf0:1;
+	bool schedule:1;
+	bool done:1;
 };
 
 struct mt76_queue_regs {
Signature · 1 line
2.21.0
Tested-by on the v3 series
#5 lore raw
In reply to Lorenzo Bianconi
Quoted 24 lines · Lorenzo Bianconi

Various mt76x2e issues have been reported on U7612E mini-pcie card [1]. On U7612E-H1 PCIE_ASPM causes continuous mcu hangs and instability and so patch 1/2 disable it by default.
Moreover mt76 does not properly unmap dma buffers for non-linear skbs. This issue may result in hw hangs if the system relies on IOMMU. Patch 2/2 fix the problem properly unmapping data fragments on non-linear skbs.

Changes since v2:
- fix compilation error if PCI support is not compiled

Changes since v1:
- simplify buf0 unmap condition
- use IS_ENABLED(CONFIG_PCIEASPM) instead of ifdef CONFIG_PCIEASPM
- check pci_disable_link_state return value

[1]:
https://lore.kernel.org/netdev/[email protected]/

Lorenzo Bianconi (2):
mt76: mt76x2e: disable pcie_aspm by default
mt76: dma: fix buffer unmap with non-linear skbs

Quoted 7 lines
 drivers/net/wireless/mediatek/mt76/Makefile   |  2 +
 drivers/net/wireless/mediatek/mt76/dma.c      |  6 ++-
 drivers/net/wireless/mediatek/mt76/mt76.h     |  6 ++-
 .../net/wireless/mediatek/mt76/mt76x2/pci.c   |  2 +
 drivers/net/wireless/mediatek/mt76/pci.c      | 46 +++++++++++++++++++
 5 files changed, 58 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/wireless/mediatek/mt76/pci.c

So, works fine for me. Checked with 5.3 and additional include fix I've mentioned previously.

With that, for the whole series feel free to add:

Thank you.

Signature · 1 line
  Oleksandr Natalenko (post-factum)