/* find if our max speed is Gen3 and parent supports Gen3 speeds */
dd->link_gen3_capable = 1;
ret = pcie_capability_read_dword(dd->pcidev, PCI_EXP_LNKCAP, &linkcap); if (ret) {
dd_dev_err(dd, "Unable to read from PCI config\n"); return pcibios_err_to_errno(ret);
}
if ((linkcap & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_8_0GB) {
dd_dev_info(dd, "This HFI is not Gen3 capable, max speed 0x%x, need 0x3\n",
linkcap & PCI_EXP_LNKCAP_SLS);
dd->link_gen3_capable = 0;
}
/* *bus->max_bus_speedissetfromthebridge'slinkcapMaxLinkSpeed
*/ if (parent &&
(dd->pcidev->bus->max_bus_speed == PCIE_SPEED_2_5GT ||
dd->pcidev->bus->max_bus_speed == PCIE_SPEED_5_0GT)) {
dd_dev_info(dd, "Parent PCIe bridge does not support Gen3\n");
dd->link_gen3_capable = 0;
}
/* obtain the link width and current speed */
update_lbus_info(dd);
dd_dev_info(dd, "%s\n", dd->lbus_info);
return0;
}
/* *RestorecommandandBARsafteraresethaswipedthemout * *Returns0onsuccess,otherwiseanegativeerrorvalue
*/ int restore_pci_variables(struct hfi1_devdata *dd)
{ int ret;
ret = pci_write_config_word(dd->pcidev, PCI_COMMAND, dd->pci_command); if (ret) goto error;
ret = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
dd->pcibar0); if (ret) goto error;
ret = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
dd->pcibar1); if (ret) goto error;
ret = pci_write_config_dword(dd->pcidev, PCI_ROM_ADDRESS, dd->pci_rom); if (ret) goto error;
ret = pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL,
dd->pcie_devctl); if (ret) goto error;
ret = pcie_capability_write_word(dd->pcidev, PCI_EXP_LNKCTL,
dd->pcie_lnkctl); if (ret) goto error;
ret = pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL2,
dd->pcie_devctl2); if (ret) goto error;
ret = pci_write_config_dword(dd->pcidev, PCI_CFG_MSIX0, dd->pci_msix0); if (ret) goto error;
if (pci_find_ext_capability(dd->pcidev, PCI_EXT_CAP_ID_TPH)) {
ret = pci_write_config_dword(dd->pcidev, PCIE_CFG_TPH2,
dd->pci_tph2); if (ret) goto error;
} return0;
error:
dd_dev_err(dd, "Unable to write to PCI config\n"); return pcibios_err_to_errno(ret);
}
/* *SaveBARsandcommandtorewriteafterdevicereset * *Returns0onsuccess,otherwiseanegativeerrorvalue
*/ int save_pci_variables(struct hfi1_devdata *dd)
{ int ret;
ret = pci_read_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
&dd->pcibar0); if (ret) goto error;
ret = pci_read_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
&dd->pcibar1); if (ret) goto error;
ret = pci_read_config_dword(dd->pcidev, PCI_ROM_ADDRESS, &dd->pci_rom); if (ret) goto error;
ret = pci_read_config_word(dd->pcidev, PCI_COMMAND, &dd->pci_command); if (ret) goto error;
ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL,
&dd->pcie_devctl); if (ret) goto error;
ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKCTL,
&dd->pcie_lnkctl); if (ret) goto error;
ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL2,
&dd->pcie_devctl2); if (ret) goto error;
ret = pci_read_config_dword(dd->pcidev, PCI_CFG_MSIX0, &dd->pci_msix0); if (ret) goto error;
if (pci_find_ext_capability(dd->pcidev, PCI_EXT_CAP_ID_TPH)) {
ret = pci_read_config_dword(dd->pcidev, PCIE_CFG_TPH2,
&dd->pci_tph2); if (ret) goto error;
} return0;
error:
dd_dev_err(dd, "Unable to read from PCI config\n"); return pcibios_err_to_errno(ret);
}
switch (state) { case pci_channel_io_normal:
dd_dev_info(dd, "State Normal, ignoring\n"); break;
case pci_channel_io_frozen:
dd_dev_info(dd, "State Frozen, requesting reset\n");
pci_disable_device(pdev);
ret = PCI_ERS_RESULT_NEED_RESET; break;
case pci_channel_io_perm_failure: if (dd) {
dd_dev_info(dd, "State Permanent Failure, disabling\n"); /* no more register accesses! */
dd->flags &= ~HFI1_PRESENT;
hfi1_disable_after_error(dd);
} /* else early, or other problem */
ret = PCI_ERS_RESULT_DISCONNECT; break;
dd_dev_info(dd, "HFI1 resume function called\n"); /* *Runningjobswillfail,sinceit'sasynchronous *unlikesysfs-requestedreset.Betterthan *doingnothing.
*/
hfi1_init(dd, 1); /* same as re-init after reset */
}
static uint pcie_force;
module_param(pcie_force, uint, S_IRUGO);
MODULE_PARM_DESC(pcie_force, "Force driver to do a PCIe firmware download even if already at target speed");
static uint pcie_retry = 5;
module_param(pcie_retry, uint, S_IRUGO);
MODULE_PARM_DESC(pcie_retry, "Driver will try this many times to reach requested speed");
#define UNSET_PSET 255 #define DEFAULT_DISCRETE_PSET 2/* discrete HFI */ #define DEFAULT_MCP_PSET 6/* MCP HFI */ static uint pcie_pset = UNSET_PSET;
module_param(pcie_pset, uint, S_IRUGO);
MODULE_PARM_DESC(pcie_pset, "PCIe Eq Pset value to use, range is 0-10");
static uint pcie_ctle = 3; /* discrete on, integrated on */
module_param(pcie_ctle, uint, S_IRUGO);
MODULE_PARM_DESC(pcie_ctle, "PCIe static CTLE mode, bit 0 - discrete on/off, bit 1 - integrated on/off");
/* need a parent */ if (!dev->bus->self) {
dd_dev_err(dd, "%s: no parent device\n", __func__); return -ENOTTY;
}
/* should not be anyone else on the bus */
list_for_each_entry(pdev, &dev->bus->devices, bus_list) if (pdev != dev) {
dd_dev_err(dd, "%s: another device is on the same bus\n",
__func__); return -ENOTTY;
}
/* step 2: if either side is not capable of Gen3, done */ if (pcie_target == 3 && !dd->link_gen3_capable) {
dd_dev_err(dd, "The PCIe link is not Gen3 capable\n");
ret = -ENOSYS; goto done_no_mutex;
}
/* hold the SBus resource across the firmware download and SBR */
ret = acquire_chip_resource(dd, CR_SBUS, SBUS_TIMEOUT); if (ret) {
dd_dev_err(dd, "%s: unable to acquire SBus resource\n",
__func__); return ret;
}
/* make sure thermal polling is not causing interrupts */
therm = read_csr(dd, ASIC_CFG_THERM_POLL_EN); if (therm) {
write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0x0);
msleep(100);
dd_dev_info(dd, "%s: Disabled therm polling\n",
__func__);
}
retry: /* the SBus download will reset the spico for thermal */
/* step 3: download SBus Master firmware */ /* step 4: download PCIe Gen3 SerDes firmware */
dd_dev_info(dd, "%s: downloading firmware\n", __func__);
ret = load_pcie_firmware(dd); if (ret) { /* do not proceed if the firmware cannot be downloaded */
return_error = 1; goto done;
}
/* step 5: set up device parameter settings */
dd_dev_info(dd, "%s: setting PCIe registers\n", __func__);
/* step 5g: Set target link speed */ /* *Settargetlinkspeedtobetargetonbothdeviceandparent. *Onsettingtheparent:SomesystemBIOSs"helpfully"setthe *parenttargetspeedtoGen2tomatchtheASIC'sinitialspeed. *WecansetthetargetGen3becausewehavealreadychecked *thatitisGen3capableearlier.
*/
dd_dev_info(dd, "%s: setting parent target link speed\n", __func__);
ret = pcie_capability_read_word(parent, PCI_EXP_LNKCTL2, &lnkctl2); if (ret) {
dd_dev_err(dd, "Unable to read from PCI config\n");
return_error = 1; goto done;
}
dd_dev_info(dd, "%s: ..old link control2: 0x%x\n", __func__,
(u32)lnkctl2); /* only write to parent if target is not as high as ours */ if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) < target_vector) {
ret = pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL2,
PCI_EXP_LNKCTL2_TLS,
target_vector); if (ret) {
dd_dev_err(dd, "Unable to change parent PCI target speed\n");
return_error = 1; goto done;
}
} else {
dd_dev_info(dd, "%s: ..target speed is OK\n", __func__);
}
dd_dev_info(dd, "%s: setting target link speed\n", __func__);
ret = pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL2,
PCI_EXP_LNKCTL2_TLS,
target_vector); if (ret) {
dd_dev_err(dd, "Unable to change device PCI target speed\n");
return_error = 1; goto done;
}
/* step 5h: arm gasket logic */ /* hold DC in reset across the SBR */
write_csr(dd, CCE_DC_CTRL, CCE_DC_CTRL_DC_RESET_SMASK);
(void)read_csr(dd, CCE_DC_CTRL); /* DC reset hold */ /* save firmware control across the SBR */
fw_ctrl = read_csr(dd, MISC_CFG_FW_CTRL);
/* *step7:initiatethesecondarybusreset(SBR) *step8:hardwarebringsthelinksbackup *step9:waitforlinkspeedtransitiontobecomplete
*/
dd_dev_info(dd, "%s: calling trigger_sbr\n", __func__);
ret = trigger_sbr(dd); if (ret) goto done;
/* step 10: decide what to do next */
/* check if we can read PCI space */
ret = pci_read_config_word(dd->pcidev, PCI_VENDOR_ID, &vendor); if (ret) {
dd_dev_info(dd, "%s: read of VendorID failed after SBR, err %d\n",
__func__, ret);
return_error = 1; goto done;
} if (vendor == 0xffff) {
dd_dev_info(dd, "%s: VendorID is all 1s after SBR\n", __func__);
return_error = 1;
ret = -EIO; goto done;
}
/* restore PCI space registers we know were reset */
dd_dev_info(dd, "%s: calling restore_pci_variables\n", __func__);
ret = restore_pci_variables(dd); if (ret) {
dd_dev_err(dd, "%s: Could not restore PCI variables\n",
__func__);
return_error = 1; goto done;
}
/* restore firmware control */
write_csr(dd, MISC_CFG_FW_CTRL, fw_ctrl);
/* clear the DC reset */
write_csr(dd, CCE_DC_CTRL, 0);
/* Set the LED off */
setextled(dd, 0);
/* check for any per-lane errors */
ret = pci_read_config_dword(dd->pcidev, PCIE_CFG_SPCIE2, ®32); if (ret) {
dd_dev_err(dd, "Unable to read from PCI config\n");
return_error = 1; goto done;
}
/* update our link information cache */
update_lbus_info(dd);
dd_dev_info(dd, "%s: new speed and width: %s\n", __func__,
dd->lbus_info);
if (dd->lbus_speed != target_speed ||
dd->lbus_width < target_width) { /* not target */ /* maybe retry */
do_retry = retry_count < pcie_retry;
dd_dev_err(dd, "PCIe link speed or width did not match target%s\n",
do_retry ? ", retrying" : "");
retry_count++; if (do_retry) {
msleep(100); /* allow time to settle */ goto retry;
}
ret = -EIO;
}
done: if (therm) {
write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0x1);
msleep(100);
dd_dev_info(dd, "%s: Re-enable therm polling\n",
__func__);
}
release_chip_resource(dd, CR_SBUS);
done_no_mutex: /* return no error if it is OK to be at current speed */ if (ret && !return_error) {
dd_dev_err(dd, "Proceeding at current speed PCIe speed\n");
ret = 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.