[PATCH 07/10] powerpc/powernv: Block PCI-CFG access if necessary
Gavin Shan
shangw at linux.vnet.ibm.com
Tue Jun 25 15:55:14 EST 2013
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 <shangw at 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
More information about the Linuxppc-dev
mailing list