[Skiboot] [PATCH] pci: Check power state before powering off slot

Gavin Shan gwshan at linux.vnet.ibm.com
Fri Oct 21 16:47:53 AEDT 2016


I made the inappropriate assumption: PCI slot's power state is
always on from the beginning. We don't check the slot's power
state before turning it off in PCI enumeration path when there
are no PCI adapters behind the slot. The PCI slot's power might
have been turned off and we needn't power it off again. Otherwise,
the below (not harmful) message is raised:

[   47.243635711,5] SkiBoot skiboot-5.4.0-rc1 starting...
       :
[   13.239871630,5] PHB#0001:02:01.0 Error -1 powering off slot

This checks power state and avoid turning it off again if it's
already in off state. Flag PCI_SLOT_FLAG_BOOTUP is also removed
after the requested operation is completed as the flag should
be used at skiboot booting stage.

Cc: stable # 5.3.0+
Reported-by: Pridhiviraj Paidipeddi <ppaidipe at linux.vnet.ibm.com>
Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>
Tested-by: Pridhiviraj Paidipeddi <ppaidipe at linux.vnet.ibm.com>
---
 core/pci.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/core/pci.c b/core/pci.c
index ba7cd9d..4160299 100644
--- a/core/pci.c
+++ b/core/pci.c
@@ -501,6 +501,7 @@ void pci_remove_bus(struct phb *phb, struct list_head *list)
 static void pci_slot_power_off(struct phb *phb, struct pci_device *pd)
 {
 	struct pci_slot *slot;
+	uint8_t pstate;
 	int32_t wait = 100;
 	int64_t rc;
 
@@ -508,7 +509,9 @@ static void pci_slot_power_off(struct phb *phb, struct pci_device *pd)
 		return;
 
 	slot = pd->slot;
-	if (!slot->pluggable || !slot->ops.set_power_state)
+	if (!slot->pluggable ||
+	    !slot->ops.get_power_state ||
+	    !slot->ops.set_power_state)
 		return;
 
 	/* Bail if there're something connected */
@@ -516,11 +519,23 @@ static void pci_slot_power_off(struct phb *phb, struct pci_device *pd)
 		return;
 
 	pci_slot_add_flags(slot, PCI_SLOT_FLAG_BOOTUP);
+	rc = slot->ops.get_power_state(slot, &pstate);
+	if (rc != OPAL_SUCCESS) {
+		pci_slot_remove_flags(slot, PCI_SLOT_FLAG_BOOTUP);
+		PCINOTICE(phb, pd->bdfn, "Error %lld getting slot power state\n", rc);
+		return;
+	} else if (pstate == PCI_SLOT_POWER_OFF) {
+		pci_slot_remove_flags(slot, PCI_SLOT_FLAG_BOOTUP);
+		return;
+	}
+
 	rc = slot->ops.set_power_state(slot, PCI_SLOT_POWER_OFF);
 	if (rc == OPAL_SUCCESS) {
+		pci_slot_remove_flags(slot, PCI_SLOT_FLAG_BOOTUP);
 		PCIDBG(phb, pd->bdfn, "Power off hotpluggable slot\n");
 		return;
 	} else if (rc != OPAL_ASYNC_COMPLETION) {
+		pci_slot_remove_flags(slot, PCI_SLOT_FLAG_BOOTUP);
 		pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
 		PCINOTICE(phb, pd->bdfn, "Error %lld powering off slot\n", rc);
 		return;
@@ -534,6 +549,7 @@ static void pci_slot_power_off(struct phb *phb, struct pci_device *pd)
 		time_wait_ms(10);
 	} while (--wait >= 0);
 
+	pci_slot_remove_flags(slot, PCI_SLOT_FLAG_BOOTUP);
 	pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
 	if (wait >= 0)
 		PCIDBG(phb, pd->bdfn, "Power off hotpluggable slot\n");
-- 
2.1.0



More information about the Skiboot mailing list