162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2019 Lorenzo Bianconi <lorenzo@kernel.org>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "mt76.h"
762306a36Sopenharmony_ci#include <linux/pci.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_civoid mt76_pci_disable_aspm(struct pci_dev *pdev)
1062306a36Sopenharmony_ci{
1162306a36Sopenharmony_ci	struct pci_dev *parent = pdev->bus->self;
1262306a36Sopenharmony_ci	u16 aspm_conf, parent_aspm_conf = 0;
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf);
1562306a36Sopenharmony_ci	aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
1662306a36Sopenharmony_ci	if (parent) {
1762306a36Sopenharmony_ci		pcie_capability_read_word(parent, PCI_EXP_LNKCTL,
1862306a36Sopenharmony_ci					  &parent_aspm_conf);
1962306a36Sopenharmony_ci		parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
2062306a36Sopenharmony_ci	}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	if (!aspm_conf && (!parent || !parent_aspm_conf)) {
2362306a36Sopenharmony_ci		/* aspm already disabled */
2462306a36Sopenharmony_ci		return;
2562306a36Sopenharmony_ci	}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	dev_info(&pdev->dev, "disabling ASPM %s %s\n",
2862306a36Sopenharmony_ci		 (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "",
2962306a36Sopenharmony_ci		 (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : "");
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCIEASPM)) {
3262306a36Sopenharmony_ci		int err;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci		err = pci_disable_link_state(pdev, aspm_conf);
3562306a36Sopenharmony_ci		if (!err)
3662306a36Sopenharmony_ci			return;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/* both device and parent should have the same ASPM setting.
4062306a36Sopenharmony_ci	 * disable ASPM in downstream component first and then upstream.
4162306a36Sopenharmony_ci	 */
4262306a36Sopenharmony_ci	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf);
4362306a36Sopenharmony_ci	if (parent)
4462306a36Sopenharmony_ci		pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
4562306a36Sopenharmony_ci					   aspm_conf);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_pci_disable_aspm);
48