[Skiboot] [PATCH 3/3] pci: Wait for CRS and switch link when restoring bus numbers
Hari Bathini
hbathini at linux.vnet.ibm.com
Thu Aug 17 19:16:16 AEST 2017
On Thursday 17 August 2017 11:34 AM, Russell Currey wrote:
> When a complete reset occurs, after the PHB recovers it propagates a
> reset down the wire to every device. At the same time, skiboot talks to
> every device in order to restore the state of devices to what they were
> before the reset.
>
> In some situations, such as devices that recovered slowly and/or were
> behind a switch, skiboot attempted to access config space of the device
> before the link was up and the device could respond.
>
> Fix this by retrying CRS until the device responds correctly, and for
> devices behind a switch, making sure the switch has its link up first.
>
> Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
> Signed-off-by: Russell Currey <ruscur at russell.cc>
With this patch, PCI devices are initialized properly in kdump environment..
Tested-by: Hari Bathini <hbathini at linux.vnet.ibm.com>
> ---
> core/pci.c | 51 ++++++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 38 insertions(+), 13 deletions(-)
>
> diff --git a/core/pci.c b/core/pci.c
> index a709e27f..917a9e6e 100644
> --- a/core/pci.c
> +++ b/core/pci.c
> @@ -218,21 +218,18 @@ void pci_init_capabilities(struct phb *phb, struct pci_device *pd)
> pci_init_pm_cap(phb, pd);
> }
>
> -static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *parent,
> - uint16_t bdfn)
> +static bool pci_wait_crs(struct phb *phb, uint16_t bdfn, uint32_t *out_vdid)
> {
> - struct pci_device *pd = NULL;
> uint32_t retries, vdid;
> int64_t rc;
> - uint8_t htype;
> bool had_crs = false;
>
> for (retries = 0; retries < 40; retries++) {
> rc = pci_cfg_read32(phb, bdfn, PCI_CFG_VENDOR_ID, &vdid);
> if (rc)
> - return NULL;
> + return false;
> if (vdid == 0xffffffff || vdid == 0x00000000)
> - return NULL;
> + return false;
> if (vdid != 0xffff0001)
> break;
> had_crs = true;
> @@ -240,11 +237,27 @@ static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *paren
> }
> if (vdid == 0xffff0001) {
> PCIERR(phb, bdfn, "CRS timeout !\n");
> - return NULL;
> + return false;
> }
> if (had_crs)
> PCIDBG(phb, bdfn, "Probe success after %d CRS\n", retries);
>
> + if (out_vdid)
> + *out_vdid = vdid;
> + return true;
> +}
> +
> +static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *parent,
> + uint16_t bdfn)
> +{
> + struct pci_device *pd = NULL;
> + uint32_t vdid;
> + int64_t rc;
> + uint8_t htype;
> +
> + if (!pci_wait_crs(phb, bdfn, &vdid))
> + return NULL;
> +
> /* Perform a dummy write to the device in order for it to
> * capture it's own bus number, so any subsequent error
> * messages will be properly tagged
> @@ -1835,14 +1848,26 @@ static int __pci_restore_bridge_buses(struct phb *phb,
> struct pci_device *pd,
> void *data __unused)
> {
> - if (!pd->is_bridge) {
> - uint32_t vdid;
> + uint32_t vdid;
> +
> + /* If the device is behind a switch, wait for the switch */
> + if (!pd->is_vf && !(pd->bdfn & 7) && pd->parent != NULL &&
> + pd->parent->dev_type == PCIE_TYPE_SWITCH_DNPORT) {
> + if (!pci_bridge_wait_link(phb, pd->parent, true)) {
> + PCIERR(phb, pd->bdfn, "Timeout waiting for switch\n");
> + return -1;
> + }
> + }
> +
> + /* Wait for config space to stop returning CRS */
> + if (!pci_wait_crs(phb, pd->bdfn, &vdid))
> + return -1;
>
> - /* Make all devices below a bridge "re-capture" the bdfn */
> - if (pci_cfg_read32(phb, pd->bdfn, PCI_CFG_VENDOR_ID, &vdid) == 0)
> - pci_cfg_write32(phb, pd->bdfn, PCI_CFG_VENDOR_ID, vdid);
> + /* Make all devices below a bridge "re-capture" the bdfn */
> + pci_cfg_write32(phb, pd->bdfn, PCI_CFG_VENDOR_ID, vdid);
> +
> + if (!pd->is_bridge)
> return 0;
> - }
>
> pci_cfg_write8(phb, pd->bdfn, PCI_CFG_PRIMARY_BUS,
> pd->primary_bus);
More information about the Skiboot
mailing list