18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2019 Lorenzo Bianconi <lorenzo@kernel.org>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "mt76.h"
78c2ecf20Sopenharmony_ci#include <linux/pci.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_civoid mt76_pci_disable_aspm(struct pci_dev *pdev)
108c2ecf20Sopenharmony_ci{
118c2ecf20Sopenharmony_ci	struct pci_dev *parent = pdev->bus->self;
128c2ecf20Sopenharmony_ci	u16 aspm_conf, parent_aspm_conf = 0;
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf);
158c2ecf20Sopenharmony_ci	aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
168c2ecf20Sopenharmony_ci	if (parent) {
178c2ecf20Sopenharmony_ci		pcie_capability_read_word(parent, PCI_EXP_LNKCTL,
188c2ecf20Sopenharmony_ci					  &parent_aspm_conf);
198c2ecf20Sopenharmony_ci		parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
208c2ecf20Sopenharmony_ci	}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	if (!aspm_conf && (!parent || !parent_aspm_conf)) {
238c2ecf20Sopenharmony_ci		/* aspm already disabled */
248c2ecf20Sopenharmony_ci		return;
258c2ecf20Sopenharmony_ci	}
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "disabling ASPM %s %s\n",
288c2ecf20Sopenharmony_ci		 (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "",
298c2ecf20Sopenharmony_ci		 (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : "");
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCIEASPM)) {
328c2ecf20Sopenharmony_ci		int err;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci		err = pci_disable_link_state(pdev, aspm_conf);
358c2ecf20Sopenharmony_ci		if (!err)
368c2ecf20Sopenharmony_ci			return;
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	/* both device and parent should have the same ASPM setting.
408c2ecf20Sopenharmony_ci	 * disable ASPM in downstream component first and then upstream.
418c2ecf20Sopenharmony_ci	 */
428c2ecf20Sopenharmony_ci	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf);
438c2ecf20Sopenharmony_ci	if (parent)
448c2ecf20Sopenharmony_ci		pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
458c2ecf20Sopenharmony_ci					   aspm_conf);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_pci_disable_aspm);
48