[Skiboot] [PATCH 7/8] phb4: Block D-state power management on direct slots

Benjamin Herrenschmidt benh at kernel.crashing.org
Tue Jun 6 08:59:23 AEST 2017


As current revisions of PHB4 don't properly handle the resulting
L1 link transition.

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
 core/pci.c        | 10 ++++++++++
 hw/phb4.c         | 34 ++++++++++++++++++++++++++++++----
 include/pci-cfg.h |  3 +++
 3 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/core/pci.c b/core/pci.c
index c791ebd..1477358 100644
--- a/core/pci.c
+++ b/core/pci.c
@@ -202,11 +202,21 @@ static void pci_init_aer_cap(struct phb *phb, struct pci_device *pd)
 		pci_set_cap(pd, PCIECAP_ID_AER, pos, NULL, true);
 }
 
+static void pci_init_pm_cap(struct phb *phb, struct pci_device *pd)
+{
+	int64_t pos;
+
+	pos = pci_find_cap(phb, pd->bdfn, PCI_CFG_CAP_ID_PM);
+	if (pos > 0)
+		pci_set_cap(pd, PCI_CFG_CAP_ID_PM, pos, NULL, false);
+}
+
 void pci_init_capabilities(struct phb *phb, struct pci_device *pd)
 {
 	pci_init_pcie_cap(phb, pd);
 	pci_init_aer_cap(phb, pd);
 	pci_init_iov_cap(phb, pd);
+	pci_init_pm_cap(phb, pd);
 }
 
 static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *parent,
diff --git a/hw/phb4.c b/hw/phb4.c
index bf664af..b53dadf 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -644,9 +644,36 @@ static void phb4_endpoint_init(struct phb *phb,
 	pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32);
 }
 
+static int64_t phb4_pcicfg_no_dstate(void *dev,
+				     struct pci_cfg_reg_filter *pcrf,
+				     uint32_t offset, uint32_t len,
+				     uint32_t *data,  bool write)
+{
+	uint32_t loff = offset - pcrf->start;
+
+	/* Disable D-state change on children of the PHB. For now we
+	 * simply block all writes to the PM control/status
+	 */
+	if (write && loff >= 4 && loff < 6)
+		return OPAL_SUCCESS;
+
+	return OPAL_PARTIAL;
+}
+
 static void phb4_check_device_quirks(struct phb *phb, struct pci_device *dev)
 {
-	// FIXME: add quirks later if necessary
+	/* Some special adapter tweaks for devices directly under the PHB */
+	if (dev->primary_bus != 1)
+		return;
+
+	/* PM quirk */
+	if (!pci_has_cap(dev, PCI_CFG_CAP_ID_PM, false))
+		return;
+
+	pci_add_cfg_reg_filter(dev,
+			       pci_cap(dev, PCI_CFG_CAP_ID_PM, false), 8,
+			       PCI_REG_FLAG_WRITE,
+			       phb4_pcicfg_no_dstate);
 }
 
 static int phb4_device_init(struct phb *phb, struct pci_device *dev,
@@ -654,9 +681,8 @@ static int phb4_device_init(struct phb *phb, struct pci_device *dev,
 {
 	int ecap, aercap;
 
-	/* Some special adapter tweaks for devices directly under the PHB */
-	if (dev->primary_bus == 1)
-		phb4_check_device_quirks(phb, dev);
+	/* Setup special device quirks */
+	phb4_check_device_quirks(phb, dev);
 
 	/* Common initialization for the device */
 	pci_device_init(phb, dev);
diff --git a/include/pci-cfg.h b/include/pci-cfg.h
index 530f0a8..6061584 100644
--- a/include/pci-cfg.h
+++ b/include/pci-cfg.h
@@ -108,6 +108,9 @@
 #define PCI_CFG_CAP_ID			0
 #define PCI_CFG_CAP_NEXT		1
 
+/* PCI Power Management capability */
+#define PCI_CFG_CAP_ID_PM		1
+
 /* PCI bridge subsystem ID capability */
 #define PCI_CFG_CAP_ID_SUBSYS_VID	0x0d
 #define   PCICAP_SUBSYS_VID_VENDOR	4
-- 
2.9.4



More information about the Skiboot mailing list