staging/rdma/hfi1: Avoid using upstream component if it is not accessible

When the hfi1 device is assigned to a VM (eg KVM), the hfi1 driver has
no access to the upstream component and therefore cannot use it to perform
some operations, such as secondary bus reset. As a result, the hfi1 driver
cannot perform the pcie Gen3 transition. Instead, those operation should
be done in the host environment, preferrably done during the Option ROM
initialization. Similarly, the hfi1 driver cannot support ASPM and tune
the pcie capability under this circumstance.

Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Kaike Wan <kaike.wan@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
Kaike Wan 2016-02-26 13:33:18 -08:00 committed by Doug Ledford
parent aa0ad411e5
commit bf400235f3
2 changed files with 36 additions and 5 deletions

View File

@ -72,6 +72,13 @@ static inline bool aspm_hw_l1_supported(struct hfi1_devdata *dd)
struct pci_dev *parent = dd->pcidev->bus->self; struct pci_dev *parent = dd->pcidev->bus->self;
u32 up, dn; u32 up, dn;
/*
* If the driver does not have access to the upstream component,
* it cannot support ASPM L1 at all.
*/
if (!parent)
return false;
pcie_capability_read_dword(dd->pcidev, PCI_EXP_LNKCAP, &dn); pcie_capability_read_dword(dd->pcidev, PCI_EXP_LNKCAP, &dn);
dn = ASPM_L1_SUPPORTED(dn); dn = ASPM_L1_SUPPORTED(dn);
@ -98,6 +105,13 @@ static inline void aspm_hw_enable_l1(struct hfi1_devdata *dd)
{ {
struct pci_dev *parent = dd->pcidev->bus->self; struct pci_dev *parent = dd->pcidev->bus->self;
/*
* If the driver does not have access to the upstream component,
* it cannot support ASPM L1 at all.
*/
if (!parent)
return;
/* Enable ASPM L1 first in upstream component and then downstream */ /* Enable ASPM L1 first in upstream component and then downstream */
pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL, pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, PCI_EXP_LNKCTL_ASPMC,
@ -114,8 +128,9 @@ static inline void aspm_hw_disable_l1(struct hfi1_devdata *dd)
/* Disable ASPM L1 first in downstream component and then upstream */ /* Disable ASPM L1 first in downstream component and then upstream */
pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL, pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, 0x0); PCI_EXP_LNKCTL_ASPMC, 0x0);
pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL, if (parent)
PCI_EXP_LNKCTL_ASPMC, 0x0); pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, 0x0);
} }
static inline void aspm_enable(struct hfi1_devdata *dd) static inline void aspm_enable(struct hfi1_devdata *dd)

View File

@ -362,6 +362,7 @@ static void update_lbus_info(struct hfi1_devdata *dd)
int pcie_speeds(struct hfi1_devdata *dd) int pcie_speeds(struct hfi1_devdata *dd)
{ {
u32 linkcap; u32 linkcap;
struct pci_dev *parent = dd->pcidev->bus->self;
if (!pci_is_pcie(dd->pcidev)) { if (!pci_is_pcie(dd->pcidev)) {
dd_dev_err(dd, "Can't find PCI Express capability!\n"); dd_dev_err(dd, "Can't find PCI Express capability!\n");
@ -382,7 +383,7 @@ int pcie_speeds(struct hfi1_devdata *dd)
/* /*
* bus->max_bus_speed is set from the bridge's linkcap Max Link Speed * bus->max_bus_speed is set from the bridge's linkcap Max Link Speed
*/ */
if (dd->pcidev->bus->max_bus_speed != PCIE_SPEED_8_0GT) { if (parent && dd->pcidev->bus->max_bus_speed != PCIE_SPEED_8_0GT) {
dd_dev_info(dd, "Parent PCIe bridge does not support Gen3\n"); dd_dev_info(dd, "Parent PCIe bridge does not support Gen3\n");
dd->link_gen3_capable = 0; dd->link_gen3_capable = 0;
} }
@ -471,6 +472,12 @@ static void tune_pcie_caps(struct hfi1_devdata *dd)
} }
/* Find out supported and configured values for parent (root) */ /* Find out supported and configured values for parent (root) */
parent = dd->pcidev->bus->self; parent = dd->pcidev->bus->self;
/*
* The driver cannot perform the tuning if it does not have
* access to the upstream component.
*/
if (!parent)
return;
if (!pci_is_root_bus(parent->bus)) { if (!pci_is_root_bus(parent->bus)) {
dd_dev_info(dd, "Parent not root\n"); dd_dev_info(dd, "Parent not root\n");
return; return;
@ -939,7 +946,7 @@ static void write_xmt_margin(struct hfi1_devdata *dd, const char *fname)
*/ */
int do_pcie_gen3_transition(struct hfi1_devdata *dd) int do_pcie_gen3_transition(struct hfi1_devdata *dd)
{ {
struct pci_dev *parent; struct pci_dev *parent = dd->pcidev->bus->self;
u64 fw_ctrl; u64 fw_ctrl;
u64 reg, therm; u64 reg, therm;
u32 reg32, fs, lf; u32 reg32, fs, lf;
@ -981,6 +988,16 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
return 0; return 0;
} }
/*
* The driver cannot do the transition if it has no access to the
* upstream component
*/
if (!parent) {
dd_dev_info(dd, "%s: No upstream, Can't do gen3 transition\n",
__func__);
return 0;
}
/* /*
* Do the Gen3 transition. Steps are those of the PCIe Gen3 * Do the Gen3 transition. Steps are those of the PCIe Gen3
* recipe. * recipe.
@ -1157,7 +1174,6 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
* that it is Gen3 capable earlier. * that it is Gen3 capable earlier.
*/ */
dd_dev_info(dd, "%s: setting parent target link speed\n", __func__); dd_dev_info(dd, "%s: setting parent target link speed\n", __func__);
parent = dd->pcidev->bus->self;
pcie_capability_read_word(parent, PCI_EXP_LNKCTL2, &lnkctl2); pcie_capability_read_word(parent, PCI_EXP_LNKCTL2, &lnkctl2);
dd_dev_info(dd, "%s: ..old link control2: 0x%x\n", __func__, dd_dev_info(dd, "%s: ..old link control2: 0x%x\n", __func__,
(u32)lnkctl2); (u32)lnkctl2);