pci.c 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. // SPDX-License-Identifier: ISC
  2. /*
  3. * Copyright (C) 2019 Lorenzo Bianconi <lorenzo@kernel.org>
  4. */
  5. #include "mt76.h"
  6. #include <linux/pci.h>
  7. void mt76_pci_disable_aspm(struct pci_dev *pdev)
  8. {
  9. struct pci_dev *parent = pdev->bus->self;
  10. u16 aspm_conf, parent_aspm_conf = 0;
  11. pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf);
  12. aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
  13. if (parent) {
  14. pcie_capability_read_word(parent, PCI_EXP_LNKCTL,
  15. &parent_aspm_conf);
  16. parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
  17. }
  18. if (!aspm_conf && (!parent || !parent_aspm_conf)) {
  19. /* aspm already disabled */
  20. return;
  21. }
  22. dev_info(&pdev->dev, "disabling ASPM %s %s\n",
  23. (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "",
  24. (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : "");
  25. if (IS_ENABLED(CONFIG_PCIEASPM)) {
  26. int err;
  27. err = pci_disable_link_state(pdev, aspm_conf);
  28. if (!err)
  29. return;
  30. }
  31. /* both device and parent should have the same ASPM setting.
  32. * disable ASPM in downstream component first and then upstream.
  33. */
  34. pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf);
  35. if (parent)
  36. pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
  37. aspm_conf);
  38. }
  39. EXPORT_SYMBOL_GPL(mt76_pci_disable_aspm);