[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