/* When a PCI device is isolated from the bus, a subsequent MMIO read is * required for the kernel EEH mechanisms to notice. As the Solarflare driver * was written to minimise MMIO read (for latency) then a periodic call to check * the EEH status of the device is required so that device recovery can happen * in a timely fashion. */ static void siena_monitor(struct efx_nic *efx) { struct pci_dev *pcidev = efx->pci_dev; struct device_node *dn = pci_device_to_OF_node(pcidev); eeh_dn_check_failure(dn, pcidev); }
int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) { int returnval = -1; unsigned long buid, addr; int ret; if (!pdn) return PCIBIOS_DEVICE_NOT_FOUND; if (!config_access_valid(pdn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; addr = rtas_config_addr(pdn->busno, pdn->devfn, where); buid = pdn->phb->buid; if (buid) { ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, BUID_HI(buid), BUID_LO(buid), size); } else { ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); } *val = returnval; if (ret) return PCIBIOS_DEVICE_NOT_FOUND; if (returnval == EEH_IO_ERROR_VALUE(size) && eeh_dn_check_failure (pdn->node, NULL)) return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_SUCCESSFUL; }
/** * eeh_check_failure - check if all 1's data is due to EEH slot freeze * @token i/o token, should be address in the form 0xA.... * @val value, should be all 1's (XXX why do we need this arg??) * * Check for an EEH failure at the given token address. Call this * routine if the result of a read was all 0xff's and you want to * find out if this is due to an EEH slot freeze event. This routine * will query firmware for the EEH status. * * Note this routine is safe to call in an interrupt context. */ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) { unsigned long addr; struct pci_dev *dev; struct device_node *dn; /* Finding the phys addr + pci device; this is pretty quick. */ addr = eeh_token_to_phys((unsigned long __force) token); dev = pci_get_device_by_addr(addr); if (!dev) { no_device++; return val; } dn = pci_device_to_OF_node(dev); eeh_dn_check_failure (dn, dev); pci_dev_put(dev); return val; }