diff options
author | Lorenzo Bianconi <lorenzo@kernel.org> | 2019-10-27 15:53:08 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2019-10-30 10:59:46 -0400 |
commit | f37f05503575c59020dacd36e999f4e8b3dbc115 (patch) | |
tree | 2984b7e1df447180642c0d7254a976a3ebb37203 | |
parent | b43f4a169f220e459edf3ea8f8cd3ec4ae7fa82d (diff) |
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
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt76.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/pci.c | 46 |
4 files changed, 51 insertions, 0 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 4d03596e891f..d7a1ddc9e407 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile | |||
@@ -8,6 +8,8 @@ mt76-y := \ | |||
8 | mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ | 8 | mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ |
9 | tx.o agg-rx.o mcu.o | 9 | tx.o agg-rx.o mcu.o |
10 | 10 | ||
11 | mt76-$(CONFIG_PCI) += pci.o | ||
12 | |||
11 | mt76-usb-y := usb.o usb_trace.o | 13 | mt76-usb-y := usb.o usb_trace.o |
12 | 14 | ||
13 | CFLAGS_trace.o := -I$(src) | 15 | CFLAGS_trace.o := -I$(src) |
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 570c159515a0..dc468ed9434a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h | |||
@@ -578,6 +578,7 @@ bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, | |||
578 | #define mt76_poll_msec(dev, ...) __mt76_poll_msec(&((dev)->mt76), __VA_ARGS__) | 578 | #define mt76_poll_msec(dev, ...) __mt76_poll_msec(&((dev)->mt76), __VA_ARGS__) |
579 | 579 | ||
580 | void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); | 580 | void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); |
581 | void mt76_pci_disable_aspm(struct pci_dev *pdev); | ||
581 | 582 | ||
582 | static inline u16 mt76_chip(struct mt76_dev *dev) | 583 | static inline u16 mt76_chip(struct mt76_dev *dev) |
583 | { | 584 | { |
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 73c3104f8858..cf611d1b817c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | |||
@@ -81,6 +81,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
81 | /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ | 81 | /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ |
82 | mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); | 82 | mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); |
83 | 83 | ||
84 | mt76_pci_disable_aspm(pdev); | ||
85 | |||
84 | return 0; | 86 | return 0; |
85 | 87 | ||
86 | error: | 88 | error: |
diff --git a/drivers/net/wireless/mediatek/mt76/pci.c b/drivers/net/wireless/mediatek/mt76/pci.c new file mode 100644 index 000000000000..04c5a692bc85 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/pci.c | |||
@@ -0,0 +1,46 @@ | |||
1 | // SPDX-License-Identifier: ISC | ||
2 | /* | ||
3 | * Copyright (C) 2019 Lorenzo Bianconi <lorenzo@kernel.org> | ||
4 | */ | ||
5 | |||
6 | #include <linux/pci.h> | ||
7 | |||
8 | void mt76_pci_disable_aspm(struct pci_dev *pdev) | ||
9 | { | ||
10 | struct pci_dev *parent = pdev->bus->self; | ||
11 | u16 aspm_conf, parent_aspm_conf = 0; | ||
12 | |||
13 | pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf); | ||
14 | aspm_conf &= PCI_EXP_LNKCTL_ASPMC; | ||
15 | if (parent) { | ||
16 | pcie_capability_read_word(parent, PCI_EXP_LNKCTL, | ||
17 | &parent_aspm_conf); | ||
18 | parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC; | ||
19 | } | ||
20 | |||
21 | if (!aspm_conf && (!parent || !parent_aspm_conf)) { | ||
22 | /* aspm already disabled */ | ||
23 | return; | ||
24 | } | ||
25 | |||
26 | dev_info(&pdev->dev, "disabling ASPM %s %s\n", | ||
27 | (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "", | ||
28 | (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : ""); | ||
29 | |||
30 | if (IS_ENABLED(CONFIG_PCIEASPM)) { | ||
31 | int err; | ||
32 | |||
33 | err = pci_disable_link_state(pdev, aspm_conf); | ||
34 | if (!err) | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | /* both device and parent should have the same ASPM setting. | ||
39 | * disable ASPM in downstream component first and then upstream. | ||
40 | */ | ||
41 | pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf); | ||
42 | if (parent) | ||
43 | pcie_capability_clear_word(parent, PCI_EXP_LNKCTL, | ||
44 | aspm_conf); | ||
45 | } | ||
46 | EXPORT_SYMBOL_GPL(mt76_pci_disable_aspm); | ||