Skip to content

Commit

Permalink
PCI: Disable ASPM if BIOS asks us to
Browse files Browse the repository at this point in the history
We currently refuse to touch the ASPM registers if the BIOS tells us that
ASPM isn't supported. This can cause problems if the BIOS has (for any
reason) enabled ASPM on some devices anyway. Change the code such that we
explicitly clear ASPM if the FADT indicates that ASPM isn't supported,
and make sure we tidy up appropriately on device removal in order to deal
with the hotplug case. If ASPM is disabled because the BIOS doesn't hand
over control then we won't touch the registers.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
  • Loading branch information
Matthew Garrett authored and Jesse Barnes committed Dec 23, 2010
1 parent 8d80528 commit 2f671e2
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 5 deletions.
1 change: 1 addition & 0 deletions drivers/pci/pci-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ static int __init acpi_pci_init(void)

if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
pcie_clear_aspm();
pcie_no_aspm();
}

Expand Down
21 changes: 17 additions & 4 deletions drivers/pci/pcie/aspm.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ struct pcie_link_state {
struct aspm_latency acceptable[8];
};

static int aspm_disabled, aspm_force;
static int aspm_disabled, aspm_force, aspm_clear_state;
static DEFINE_MUTEX(aspm_lock);
static LIST_HEAD(link_list);

Expand Down Expand Up @@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
{
/* Don't enable Clock PM if the link is not Clock PM capable */
if (!link->clkpm_capable && enable)
return;
enable = 0;
/* Need nothing if the specified equals to current state */
if (link->clkpm_enabled == enable)
return;
Expand Down Expand Up @@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
struct pci_dev *child;
int pos;
u32 reg32;

if (aspm_clear_state)
return -EINVAL;

/*
* Some functions in a slot might not all be PCIe functions,
* very strange. Disable ASPM for the whole slot
Expand Down Expand Up @@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
struct pcie_link_state *link;
int blacklist = !!pcie_aspm_sanity_check(pdev);

if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
if (!pci_is_pcie(pdev) || pdev->link_state)
return;
if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
return;

if (aspm_disabled && !aspm_clear_state)
return;

/* VIA has a strange chipset, root port is under a bridge */
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
pdev->bus->self)
Expand Down Expand Up @@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link, *root, *parent_link;

if (aspm_disabled || !pci_is_pcie(pdev) ||
if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
!parent || !parent->link_state)
return;
if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
Expand Down Expand Up @@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str)

__setup("pcie_aspm=", pcie_aspm_disable);

void pcie_clear_aspm(void)
{
if (!aspm_force)
aspm_clear_state = 1;
}

void pcie_no_aspm(void)
{
if (!aspm_force)
Expand Down
5 changes: 4 additions & 1 deletion include/linux/pci-aspm.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
extern void pci_disable_link_state(struct pci_dev *pdev, int state);
extern void pcie_clear_aspm(void);
extern void pcie_no_aspm(void);
#else
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
Expand All @@ -41,7 +42,9 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
{
}

static inline void pcie_clear_aspm(void)
{
}
static inline void pcie_no_aspm(void)
{
}
Expand Down

0 comments on commit 2f671e2

Please sign in to comment.