aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-10-14 15:26:02 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-10-17 10:33:55 +1100
commit27ed9b4ceae9f852ab7a80065590007564863e4e (patch)
tree402a814d9d9bdd423990c6ada8bb886a656fe8ec
parentb0e5149417b310df7dd62c5daaec678a18845791 (diff)
downloadskiboot-27ed9b4ceae9f852ab7a80065590007564863e4e.zip
skiboot-27ed9b4ceae9f852ab7a80065590007564863e4e.tar.gz
skiboot-27ed9b4ceae9f852ab7a80065590007564863e4e.tar.bz2
core/pci: Update PCI topology after power change
When OPAL_SUCCESS is returned from slot->ops.set_power_state(), we need update the PCI toplogy accordingly. This scenario can happen when builtin power control functionality is ignored to accomodate PCI surprise hotplug or not supported at all by the hardware. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--core/pci-opal.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/core/pci-opal.c b/core/pci-opal.c
index ba7a261..27872aa 100644
--- a/core/pci-opal.c
+++ b/core/pci-opal.c
@@ -805,8 +805,8 @@ static int64_t opal_pci_set_power_state(uint64_t async_token,
return OPAL_PARAMETER;
pci_remove_bus(phb, &pd->children);
- rc = OPAL_SUCCESS;
- break;
+ phb_unlock(phb);
+ return OPAL_SUCCESS;
case OPAL_PCI_SLOT_ONLINE:
if (!pd)
return OPAL_PARAMETER;
@@ -814,19 +814,35 @@ static int64_t opal_pci_set_power_state(uint64_t async_token,
&pd->children, pd, true);
pci_add_device_nodes(phb, &pd->children, pd->dn,
&phb->lstate, 0);
- rc = OPAL_SUCCESS;
- break;
+ phb_unlock(phb);
+ return OPAL_SUCCESS;
default:
rc = OPAL_PARAMETER;
}
- phb_unlock(phb);
+ /*
+ * OPAL_ASYNC_COMPLETION is returned when delay is needed to change
+ * the power state in the backend. When it can be finished without
+ * delay, OPAL_SUCCESS is returned. The PCI topology needs to be
+ * updated in both cases.
+ */
if (rc == OPAL_ASYNC_COMPLETION) {
slot->retries = 500;
init_timer(&slot->timer, set_power_timer, slot);
schedule_timer(&slot->timer, msecs_to_tb(10));
+ } else if (rc == OPAL_SUCCESS) {
+ if (*state == OPAL_PCI_SLOT_POWER_OFF) {
+ pci_remove_bus(phb, &pd->children);
+ } else {
+ slot->ops.prepare_link_change(slot, true);
+ pci_scan_bus(phb, pd->secondary_bus,
+ pd->subordinate_bus, &pd->children, pd, true);
+ pci_add_device_nodes(phb, &pd->children, pd->dn,
+ &phb->lstate, 0);
+ }
}
+ phb_unlock(phb);
return rc;
}
opal_call(OPAL_PCI_SET_POWER_STATE, opal_pci_set_power_state, 3);