PCI: disable ASPM on pre-1.1 PCIe devices

Disable ASPM on pre-1.1 PCIe devices, as many of them don't implement it
correctly.

Tested-by: Jack Howarth <howarth@bromo.msbb.uc.edu>
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

authored by Shaohua Li and committed by Jesse Barnes 149e1637 5fde244d

+16 -1
+13
drivers/pci/pcie/aspm.c
··· 510 510 { 511 511 struct pci_dev *child_dev; 512 512 int child_pos; 513 + u32 reg32; 513 514 514 515 /* 515 516 * Some functions in a slot might not all be PCIE functions, very ··· 520 519 child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); 521 520 if (!child_pos) 522 521 return -EINVAL; 522 + 523 + /* 524 + * Disable ASPM for pre-1.1 PCIe device, we follow MS to use 525 + * RBER bit to determine if a function is 1.1 version device 526 + */ 527 + pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP, 528 + &reg32); 529 + if (!(reg32 & PCI_EXP_DEVCAP_RBER)) { 530 + printk("Pre-1.1 PCIe device detected, " 531 + "disable ASPM for %s\n", pci_name(pdev)); 532 + return -EINVAL; 533 + } 523 534 } 524 535 return 0; 525 536 }
+2 -1
drivers/pci/probe.c
··· 1057 1057 } 1058 1058 } 1059 1059 1060 - if (bus->self) 1060 + /* only one slot has pcie device */ 1061 + if (bus->self && nr) 1061 1062 pcie_aspm_init_link_state(bus->self); 1062 1063 1063 1064 return nr;
+1
include/linux/pci_regs.h
··· 374 374 #define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ 375 375 #define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ 376 376 #define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ 377 + #define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ 377 378 #define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ 378 379 #define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ 379 380 #define PCI_EXP_DEVCTL 8 /* Device Control */