diff options
Diffstat (limited to 'drivers/pci/pcie/aspm.c')
| -rw-r--r-- | drivers/pci/pcie/aspm.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 61fedb2448b6..f82495583e63 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
| @@ -506,6 +506,23 @@ static void free_link_state(struct pci_dev *pdev) | |||
| 506 | pdev->link_state = NULL; | 506 | pdev->link_state = NULL; |
| 507 | } | 507 | } |
| 508 | 508 | ||
| 509 | static int pcie_aspm_sanity_check(struct pci_dev *pdev) | ||
| 510 | { | ||
| 511 | struct pci_dev *child_dev; | ||
| 512 | int child_pos; | ||
| 513 | |||
| 514 | /* | ||
| 515 | * Some functions in a slot might not all be PCIE functions, very | ||
| 516 | * strange. Disable ASPM for the whole slot | ||
| 517 | */ | ||
| 518 | list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { | ||
| 519 | child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); | ||
| 520 | if (!child_pos) | ||
| 521 | return -EINVAL; | ||
| 522 | } | ||
| 523 | return 0; | ||
| 524 | } | ||
| 525 | |||
| 509 | /* | 526 | /* |
| 510 | * pcie_aspm_init_link_state: Initiate PCI express link state. | 527 | * pcie_aspm_init_link_state: Initiate PCI express link state. |
| 511 | * It is called after the pcie and its children devices are scaned. | 528 | * It is called after the pcie and its children devices are scaned. |
| @@ -526,6 +543,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
| 526 | if (list_empty(&pdev->subordinate->devices)) | 543 | if (list_empty(&pdev->subordinate->devices)) |
| 527 | goto out; | 544 | goto out; |
| 528 | 545 | ||
| 546 | if (pcie_aspm_sanity_check(pdev)) | ||
| 547 | goto out; | ||
| 548 | |||
| 529 | mutex_lock(&aspm_lock); | 549 | mutex_lock(&aspm_lock); |
| 530 | 550 | ||
| 531 | link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); | 551 | link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); |
