Skip to content

Commit

Permalink
PCI: let pci_disable_link_state propagate errors
Browse files Browse the repository at this point in the history
Drivers may rely on pci_disable_link_state() having disabled certain
ASPM link states. If OS can't control ASPM then pci_disable_link_state()
turns into a no-op w/o informing the caller. The driver therefore may
falsely assume the respective ASPM link states are disabled.
Let pci_disable_link_state() propagate errors to the caller, enabling
the caller to react accordingly.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Heiner Kallweit authored and David S. Miller committed Jun 22, 2019
1 parent dca73a6 commit 4cfd218
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 12 deletions.
20 changes: 11 additions & 9 deletions drivers/pci/pcie/aspm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1062,18 +1062,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
up_read(&pci_bus_sem);
}

static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
{
struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link;

if (!pci_is_pcie(pdev))
return;
return 0;

if (pdev->has_secondary_link)
parent = pdev;
if (!parent || !parent->link_state)
return;
return -EINVAL;

/*
* A driver requested that ASPM be disabled on this device, but
Expand All @@ -1085,7 +1085,7 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
*/
if (aspm_disabled) {
pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n");
return;
return -EPERM;
}

if (sem)
Expand All @@ -1105,26 +1105,28 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
mutex_unlock(&aspm_lock);
if (sem)
up_read(&pci_bus_sem);

return 0;
}

void pci_disable_link_state_locked(struct pci_dev *pdev, int state)
int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
{
__pci_disable_link_state(pdev, state, false);
return __pci_disable_link_state(pdev, state, false);
}
EXPORT_SYMBOL(pci_disable_link_state_locked);

/**
* pci_disable_link_state - Disable device's link state, so the link will
* never enter specific states. Note that if the BIOS didn't grant ASPM
* control to the OS, this does nothing because we can't touch the LNKCTL
* register.
* register. Returns 0 or a negative errno.
*
* @pdev: PCI device
* @state: ASPM link state to disable
*/
void pci_disable_link_state(struct pci_dev *pdev, int state)
int pci_disable_link_state(struct pci_dev *pdev, int state)
{
__pci_disable_link_state(pdev, state, true);
return __pci_disable_link_state(pdev, state, true);
}
EXPORT_SYMBOL(pci_disable_link_state);

Expand Down
7 changes: 4 additions & 3 deletions include/linux/pci-aspm.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
#define PCIE_LINK_STATE_CLKPM 4

#ifdef CONFIG_PCIEASPM
void pci_disable_link_state(struct pci_dev *pdev, int state);
void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
int pci_disable_link_state(struct pci_dev *pdev, int state);
int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
void pcie_no_aspm(void);
#else
static inline void pci_disable_link_state(struct pci_dev *pdev, int state) { }
static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
{ return 0; }
static inline void pcie_no_aspm(void) { }
#endif

Expand Down

0 comments on commit 4cfd218

Please sign in to comment.