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); 47