diff options
author | Gavin Shan <gwshan@linux.vnet.ibm.com> | 2016-10-21 16:47:53 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-10-24 12:18:43 +1100 |
commit | 1408f6f9baa684f280dfb2c4a66daa4d5db996b2 (patch) | |
tree | 8ac3a09cac475bf84a7e20d7cf3ae5fafa626dc1 | |
parent | 0074e3d9446e7174a2bff8562241f5cb9eee547e (diff) | |
download | skiboot-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>
-rw-r--r-- | core/pci.c | 18 |
1 files changed, 17 insertions, 1 deletions
@@ -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"); |