aboutsummaryrefslogtreecommitdiff
path: root/core/pci.c
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-10-21 16:47:53 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-10-24 12:18:43 +1100
commit1408f6f9baa684f280dfb2c4a66daa4d5db996b2 (patch)
tree8ac3a09cac475bf84a7e20d7cf3ae5fafa626dc1 /core/pci.c
parent0074e3d9446e7174a2bff8562241f5cb9eee547e (diff)
downloadskiboot-1408f6f9baa684f280dfb2c4a66daa4d5db996b2.zip
skiboot-1408f6f9baa684f280dfb2c4a66daa4d5db996b2.tar.gz
skiboot-1408f6f9baa684f280dfb2c4a66daa4d5db996b2.tar.bz2
pci: Check power state before powering off slot
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@linux.vnet.ibm.com> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Tested-by: Pridhiviraj Paidipeddi <ppaidipe@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'core/pci.c')
-rw-r--r--core/pci.c18
1 files changed, 17 insertions, 1 deletions
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");