summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorRussell Currey <ruscur@russell.cc>2017-11-20 17:32:13 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-11-21 21:05:06 -0600
commit1172a6c57ff3c66f6361e572a1790cbcc0e5ff37 (patch)
treecf7cc0b3a75d219636d6d550027ccad52a397e78 /core
parent93cde639b56e927d96e102186f1ec862a4a1b671 (diff)
downloadblackbird-skiboot-1172a6c57ff3c66f6361e572a1790cbcc0e5ff37.tar.gz
blackbird-skiboot-1172a6c57ff3c66f6361e572a1790cbcc0e5ff37.zip
pci: Shared slot state synchronisation for hot reset
When a device is shared between two PHBs, it doesn't get reset properly unless both PHBs issue a hot reset at "the same time". Practically this means a hot reset needs to be issued on both sides, and neither should bring the link up until the reset on both has completed. Signed-off-by: Russell Currey <ruscur@russell.cc> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'core')
-rw-r--r--core/pci-slot.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/core/pci-slot.c b/core/pci-slot.c
index 8bddc147..f8922df5 100644
--- a/core/pci-slot.c
+++ b/core/pci-slot.c
@@ -78,6 +78,7 @@ static void pci_slot_prepare_link_change(struct pci_slot *slot, bool up)
static int64_t pci_slot_run_sm(struct pci_slot *slot)
{
+ struct pci_slot *peer = slot->peer_slot;
uint64_t now = mftb();
int64_t ret;
@@ -89,10 +90,23 @@ static int64_t pci_slot_run_sm(struct pci_slot *slot)
slot->delay_tgt_tb = 0;
switch (slot->state & PCI_SLOT_STATE_MASK) {
case PCI_SLOT_STATE_LINK:
+ // If the peer slot hasn't finished its hreset, need to wait
+ if (peer && peer->state & PCI_SLOT_STATE_HRESET &&
+ !pci_slot_has_flags(peer, PCI_SLOT_FLAG_BOOTUP))
+ return slot->ops.hreset(peer);
+
ret = slot->ops.poll_link(slot);
+ if (peer && peer->state & PCI_SLOT_STATE_LINK &&
+ !pci_slot_has_flags(peer, PCI_SLOT_FLAG_BOOTUP))
+ ret = MAX(ret, slot->ops.poll_link(peer));
break;
case PCI_SLOT_STATE_HRESET:
ret = slot->ops.hreset(slot);
+
+ // If the slot has a peer, it needs to hreset as well.
+ if (peer && peer->state == PCI_SLOT_STATE_NORMAL &&
+ !pci_slot_has_flags(peer, PCI_SLOT_FLAG_BOOTUP))
+ slot->ops.hreset(peer);
break;
case PCI_SLOT_STATE_FRESET:
ret = slot->ops.freset(slot);
OpenPOWER on IntegriCloud