[PATCH 07/10] powerpc/powernv: Block PCI-CFG access if necessary
From: Gavin Shan <hidden>
Date: 2013-06-25 05:55:32
Subsystem:
linux for powerpc (32-bit and 64-bit), pci enhanced error handling (eeh) for powerpc, the rest · Maintainers:
Madhavan Srinivasan, Michael Ellerman, Mahesh J Salgaonkar, Linus Torvalds
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 <redacted> --- 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