If the PCI-CFG access on the specific PHB, to return 0xFF's for reading and drop writing. The patch implements that for PowerNV platform. The patch also removes the check on "hose == NULL" for PCI-CFG accessors since the kernel should stop while fetching platform-dependent PHB (struct pnv_phb).
Signed-off-by: Gavin Shan <sha...@linux.vnet.ibm.com> --- arch/powerpc/platforms/powernv/eeh-powernv.c | 10 ++--- arch/powerpc/platforms/powernv/pci.c | 59 ++++++++++++++++++++------ arch/powerpc/platforms/powernv/pci.h | 4 ++ 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 20a7865..249798e 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -328,9 +328,9 @@ static int powernv_eeh_read_config(struct device_node *dn, int where, { struct eeh_dev *edev = of_node_to_eeh_dev(dn); struct pci_dev *dev = eeh_dev_to_pci_dev(edev); - struct pci_controller *hose = edev->phb; - return hose->ops->read(dev->bus, dev->devfn, where, size, val); + return pnv_pci_cfg_read(dev->bus, dev->devfn, + where, size, val, false); } /** @@ -347,11 +347,9 @@ static int powernv_eeh_write_config(struct device_node *dn, int where, { struct eeh_dev *edev = of_node_to_eeh_dev(dn); struct pci_dev *dev = eeh_dev_to_pci_dev(edev); - struct pci_controller *hose = edev->phb; - hose = pci_bus_to_host(dev->bus); - - return hose->ops->write(dev->bus, dev->devfn, where, size, val); + return pnv_pci_cfg_write(dev->bus, dev->devfn, + where, size, val, false); } /** diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 1f31826..47fa921 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -255,21 +255,30 @@ static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus, pnv_pci_handle_eeh_config(phb, pe_no); } -static int pnv_pci_read_config(struct pci_bus *bus, - unsigned int devfn, - int where, int size, u32 *val) +int pnv_pci_cfg_read(struct pci_bus *bus, + unsigned int devfn, + int where, int size, + u32 *val, bool check) { struct pci_controller *hose = pci_bus_to_host(bus); struct pnv_phb *phb = hose->private_data; + u32 bdfn = (((uint64_t)bus->number) << 8) | devfn; + s64 rc; #ifdef CONFIG_EEH struct device_node *busdn, *dn; struct eeh_pe *phb_pe = NULL; -#endif - u32 bdfn = (((uint64_t)bus->number) << 8) | devfn; - s64 rc; - if (hose == NULL) + /* + * If PCI-CFG access has been blocked, we simply + * return 0xFF's here. + */ + if (check && + (phb->eeh_state & PNV_EEH_STATE_ENABLED) && + (phb->eeh_state & PNV_EEH_STATE_CFG_BLOCKED)) { + *val = 0xFFFFFFFF; return PCIBIOS_DEVICE_NOT_FOUND; + } +#endif switch (size) { case 1: { @@ -329,19 +338,26 @@ static int pnv_pci_read_config(struct pci_bus *bus, return PCIBIOS_SUCCESSFUL; } -static int pnv_pci_write_config(struct pci_bus *bus, - unsigned int devfn, - int where, int size, u32 val) +int pnv_pci_cfg_write(struct pci_bus *bus, + unsigned int devfn, + int where, int size, + u32 val, bool check) { struct pci_controller *hose = pci_bus_to_host(bus); struct pnv_phb *phb = hose->private_data; u32 bdfn = (((uint64_t)bus->number) << 8) | devfn; - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - cfg_dbg("pnv_pci_write_config bus: %x devfn: %x +%x/%x -> %08x\n", bus->number, devfn, where, size, val); + +#ifdef CONFIG_EEH + /* If PCI-CFG access has been blocked, drop it */ + if (check && + (phb->eeh_state & PNV_EEH_STATE_ENABLED) && + (phb->eeh_state & PNV_EEH_STATE_CFG_BLOCKED)) + return PCIBIOS_DEVICE_NOT_FOUND; +#endif + switch (size) { case 1: opal_pci_config_write_byte(phb->opal_id, bdfn, where, val); @@ -367,6 +383,23 @@ static int pnv_pci_write_config(struct pci_bus *bus, return PCIBIOS_SUCCESSFUL; } +static int pnv_pci_read_config(struct pci_bus *bus, + unsigned int devfn, + int where, int size, u32 *val) +{ + return pnv_pci_cfg_read(bus, devfn, where, + size, val, true); +} + +static int pnv_pci_write_config(struct pci_bus *bus, + unsigned int devfn, + int where, int size, + u32 val) +{ + return pnv_pci_cfg_write(bus, devfn, where, + size, val, true); +} + struct pci_ops pnv_pci_ops = { .read = pnv_pci_read_config, .write = pnv_pci_write_config, diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index a281a1c..8624f8f 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -187,6 +187,10 @@ extern struct pci_ops pnv_pci_ops; extern struct pnv_eeh_ops ioda_eeh_ops; #endif +extern int pnv_pci_cfg_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val, bool check); +extern int pnv_pci_cfg_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val, bool check); extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl, void *tce_mem, u64 tce_size, u64 dma_offset); -- 1.7.5.4 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev