aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/core/pcie-slot.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/core/pcie-slot.c')
-rw-r--r--roms/skiboot/core/pcie-slot.c566
1 files changed, 566 insertions, 0 deletions
diff --git a/roms/skiboot/core/pcie-slot.c b/roms/skiboot/core/pcie-slot.c
new file mode 100644
index 000000000..03326e58f
--- /dev/null
+++ b/roms/skiboot/core/pcie-slot.c
@@ -0,0 +1,566 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * PCIe Slots
+ *
+ * Copyright 2013-2019 IBM Corp.
+ */
+
+#include <skiboot.h>
+#include <opal-msg.h>
+#include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
+
+/* Debugging options */
+#define PCIE_SLOT_PREFIX "PCIE-SLOT-%016llx "
+#define PCIE_SLOT_DBG(s, fmt, a...) \
+ prlog(PR_DEBUG, PCIE_SLOT_PREFIX fmt, (s)->id, ##a)
+
+static int64_t pcie_slot_get_presence_state(struct pci_slot *slot, uint8_t *val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* The presence is always on if it's a switch upstream port */
+ if (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT) {
+ *val = OPAL_PCI_SLOT_PRESENT;
+ return OPAL_SUCCESS;
+ }
+
+ /*
+ * The presence is always on if a switch downstream port
+ * doesn't support slot capability according to PCIE spec.
+ */
+ if (pd->dev_type == PCIE_TYPE_SWITCH_DNPORT &&
+ !(slot->pcie_cap & PCICAP_EXP_CAP_SLOT)) {
+ *val = OPAL_PCI_SLOT_PRESENT;
+ return OPAL_SUCCESS;
+ }
+
+ /* Retrieve presence status */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTSTAT, &state);
+ if (state & PCICAP_EXP_SLOTSTAT_PDETECTST)
+ *val = OPAL_PCI_SLOT_PRESENT;
+ else
+ *val = OPAL_PCI_SLOT_EMPTY;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_get_link_state(struct pci_slot *slot,
+ uint8_t *val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ int16_t state;
+
+ /*
+ * The link behind switch upstream port is always on
+ * since it doesn't have a valid link indicator.
+ */
+ if (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT) {
+ *val = 1;
+ return OPAL_SUCCESS;
+ }
+
+ /* Retrieve link width */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LSTAT, &state);
+ if (state & PCICAP_EXP_LSTAT_DLLL_ACT)
+ *val = ((state & PCICAP_EXP_LSTAT_WIDTH) >> 4);
+ else
+ *val = 0;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_get_power_state(struct pci_slot *slot __unused,
+ uint8_t *val)
+{
+ /* We should return the cached power state that is same to
+ * the PCI slot hotplug state (added/removed). Otherwise,
+ * the OS will see mismatched states, causing the adapter
+ * behind the slot can't be probed successfully on request
+ * of hot add. So we could run into the situation where the
+ * OS sees power-off but it's on in hardware.
+ */
+ *val = slot->power_state;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_get_attention_state(struct pci_slot *slot,
+ uint8_t *val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* Attention is off if the capability is missing */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI)) {
+ *val = 0;
+ return OPAL_SUCCESS;
+ }
+
+ /* Retrieve attention state */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);
+ state = (state & PCICAP_EXP_SLOTCTL_ATTNI) >> 6;
+ switch (state) {
+ case PCIE_INDIC_ON:
+ *val = PCI_SLOT_ATTN_LED_ON;
+ break;
+ case PCIE_INDIC_BLINK:
+ *val = PCI_SLOT_ATTN_LED_BLINK;
+ break;
+ case PCIE_INDIC_OFF:
+ default:
+ *val = PCI_SLOT_ATTN_LED_OFF;
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_get_latch_state(struct pci_slot *slot,
+ uint8_t *val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* Latch is off if MRL sensor doesn't exist */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_MRLSENS)) {
+ *val = 0;
+ return OPAL_SUCCESS;
+ }
+
+ /* Retrieve MRL sensor state */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTSTAT, &state);
+ if (state & PCICAP_EXP_SLOTSTAT_MRLSENSST)
+ *val = 1;
+ else
+ *val = 0;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_set_attention_state(struct pci_slot *slot,
+ uint8_t val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* Drop the request if functionality doesn't exist */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI))
+ return OPAL_SUCCESS;
+
+ /* Update with the requested state */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);
+ state &= ~PCICAP_EXP_SLOTCTL_ATTNI;
+ switch (val) {
+ case PCI_SLOT_ATTN_LED_ON:
+ state |= (PCIE_INDIC_ON << 6);
+ break;
+ case PCI_SLOT_ATTN_LED_BLINK:
+ state |= (PCIE_INDIC_BLINK << 6);
+ break;
+ case PCI_SLOT_ATTN_LED_OFF:
+ state |= (PCIE_INDIC_OFF << 6);
+ break;
+ default:
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "Invalid attention state (0x%x)\n", slot->id, val);
+ return OPAL_PARAMETER;
+ }
+
+ pci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, state);
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_set_power_state_ext(struct pci_slot *slot, uint8_t val,
+ bool surprise_check)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ if (slot->power_state == val)
+ return OPAL_SUCCESS;
+
+ /* Update the power state and return immediately if the power
+ * control functionality isn't supported on the PCI slot.
+ */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL)) {
+ slot->power_state = val;
+ return OPAL_SUCCESS;
+ }
+
+ /*
+ * Suprise hotpluggable slots need to be handled with care since
+ * many systems do not implement the presence detect side-band
+ * signal. Instead, they rely on in-band presence to report the
+ * existence of a hotplugged card.
+ *
+ * This is problematic because:
+ * a) When PERST is asserted in-band presence doesn't work, and
+ * b) Switches assert PERST as a part of the "slot power down" sequence
+ *
+ * To work around the problem we leave the slot physically powered on
+ * and exit early here. This way when a new card is inserted, the switch
+ * will raise an interrupt due to the PresDet status changing.
+ */
+ if (surprise_check && slot->surprise_pluggable) {
+ slot->power_state = val;
+ if (val == PCI_SLOT_POWER_OFF)
+ return OPAL_SUCCESS;
+
+ /*
+ * Some systems have the slot power disabled by default
+ * so we always perform the power-on step. This is not
+ * *strictly* required, but it's probably a good idea.
+ */
+ }
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_SPOWER_START);
+ slot->power_state = val;
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);
+ state &= ~(PCICAP_EXP_SLOTCTL_PWRCTLR | PCICAP_EXP_SLOTCTL_PWRI);
+ switch (val) {
+ case PCI_SLOT_POWER_OFF:
+ state |= (PCICAP_EXP_SLOTCTL_PWRCTLR | (PCIE_INDIC_OFF << 8));
+ break;
+ case PCI_SLOT_POWER_ON:
+ state |= (PCIE_INDIC_ON << 8);
+ break;
+ default:
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "Invalid power state (0x%x)\n", slot->id, val);
+ return OPAL_PARAMETER;
+ }
+
+ pci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, state);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_SPOWER_DONE);
+
+ return OPAL_ASYNC_COMPLETION;
+}
+
+static int64_t pcie_slot_set_power_state(struct pci_slot *slot, uint8_t val)
+{
+ return pcie_slot_set_power_state_ext(slot, val, true);
+}
+
+static int64_t pcie_slot_sm_poll_link(struct pci_slot *slot)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ uint16_t val;
+ uint8_t presence = 0;
+
+ switch (slot->state) {
+ case PCI_SLOT_STATE_LINK_START_POLL:
+ PCIE_SLOT_DBG(slot, "LINK: Start polling\n");
+
+ /* Link is down for ever without devices attached */
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ PCIE_SLOT_DBG(slot, "LINK: No adapter, end polling\n");
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_SUCCESS;
+ }
+
+ /* Enable the link without check */
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LCTL, &val);
+ val &= ~PCICAP_EXP_LCTL_LINK_DIS;
+ pci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_LCTL, val);
+
+ /*
+ * If the link change report isn't supported, we expect
+ * the link is up and stabilized after one second.
+ */
+ if (!(slot->link_cap & PCICAP_EXP_LCAP_DL_ACT_REP)) {
+ pci_slot_set_state(slot,
+ PCI_SLOT_STATE_LINK_DELAY_FINALIZED);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ }
+
+ /*
+ * Poll the link state if link state change report is
+ * supported on the link.
+ */
+ pci_slot_set_state(slot, PCI_SLOT_STATE_LINK_POLLING);
+ slot->retries = 250;
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(20));
+ case PCI_SLOT_STATE_LINK_DELAY_FINALIZED:
+ PCIE_SLOT_DBG(slot, "LINK: No link report, end polling\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, true);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_SUCCESS;
+ case PCI_SLOT_STATE_LINK_POLLING:
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LSTAT, &val);
+ if (val & PCICAP_EXP_LSTAT_DLLL_ACT) {
+ PCIE_SLOT_DBG(slot, "LINK: Link is up, end polling\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, true);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_SUCCESS;
+ }
+
+ /* Check link state again until timeout */
+ if (slot->retries-- == 0) {
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "LINK: Timeout waiting for up (%04x)\n",
+ slot->id, val);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_SUCCESS;
+ }
+
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(20));
+ default:
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "Link: Unexpected slot state %08x\n",
+ slot->id, slot->state);
+ }
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static void pcie_slot_reset(struct pci_slot *slot, bool assert)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint16_t ctl;
+
+ pci_cfg_read16(phb, pd->bdfn, PCI_CFG_BRCTL, &ctl);
+ if (assert)
+ ctl |= PCI_CFG_BRCTL_SECONDARY_RESET;
+ else
+ ctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;
+ pci_cfg_write16(phb, pd->bdfn, PCI_CFG_BRCTL, ctl);
+}
+
+static int64_t pcie_slot_sm_hreset(struct pci_slot *slot)
+{
+ switch (slot->state) {
+ case PCI_SLOT_STATE_NORMAL:
+ PCIE_SLOT_DBG(slot, "HRESET: Starts\n");
+ if (slot->ops.prepare_link_change) {
+ PCIE_SLOT_DBG(slot, "HRESET: Prepare for link down\n");
+ slot->ops.prepare_link_change(slot, false);
+ }
+ /* fall through */
+ case PCI_SLOT_STATE_HRESET_START:
+ PCIE_SLOT_DBG(slot, "HRESET: Assert\n");
+ pcie_slot_reset(slot, true);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_HRESET_HOLD);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(250));
+ case PCI_SLOT_STATE_HRESET_HOLD:
+ PCIE_SLOT_DBG(slot, "HRESET: Deassert\n");
+ pcie_slot_reset(slot, false);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_LINK_START_POLL);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(1800));
+ default:
+ PCIE_SLOT_DBG(slot, "HRESET: Unexpected slot state %08x\n",
+ slot->state);
+ }
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+/*
+ * Usually, individual platforms need to override the power
+ * management methods for fundamental reset, but the hot
+ * reset method is commonly shared.
+ */
+static int64_t pcie_slot_sm_freset(struct pci_slot *slot)
+{
+ uint8_t power_state = PCI_SLOT_POWER_ON;
+
+ switch (slot->state) {
+ case PCI_SLOT_STATE_NORMAL:
+ PCIE_SLOT_DBG(slot, "FRESET: Starts\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, false);
+
+ /* Retrieve power state */
+ if (slot->ops.get_power_state) {
+ PCIE_SLOT_DBG(slot, "FRESET: Retrieve power state\n");
+ slot->ops.get_power_state(slot, &power_state);
+ }
+
+ /* In power on state, power it off */
+ if (power_state == PCI_SLOT_POWER_ON) {
+ PCIE_SLOT_DBG(slot, "FRESET: Power is on, turn off\n");
+ pcie_slot_set_power_state_ext(slot,
+ PCI_SLOT_POWER_OFF, false);
+ pci_slot_set_state(slot,
+ PCI_SLOT_STATE_FRESET_POWER_OFF);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(50));
+ }
+ /* No power state change, */
+ /* fallthrough */
+ case PCI_SLOT_STATE_FRESET_POWER_OFF:
+ PCIE_SLOT_DBG(slot, "FRESET: Power is off, turn on\n");
+ pcie_slot_set_power_state_ext(slot, PCI_SLOT_POWER_ON, false);
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_LINK_START_POLL);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(50));
+ default:
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "FRESET: Unexpected slot state %08x\n",
+ slot->id, slot->state);
+ }
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+struct pci_slot *pcie_slot_create(struct phb *phb, struct pci_device *pd)
+{
+ struct pci_slot *slot;
+ uint32_t ecap;
+ uint16_t slot_ctl;
+
+ /* Allocate PCI slot */
+ slot = pci_slot_alloc(phb, pd);
+ if (!slot)
+ return NULL;
+
+ /* Cache the link and slot capabilities */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_CAPABILITY_REG,
+ &slot->pcie_cap);
+ pci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_LCAP,
+ &slot->link_cap);
+
+ /* Leave PCI slot capability blank if PCI slot isn't supported */
+ if (slot->pcie_cap & PCICAP_EXP_CAP_SLOT)
+ pci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCAP,
+ &slot->slot_cap);
+ else
+ slot->slot_cap = 0;
+
+ if (slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_CAP)
+ slot->pluggable = 1;
+
+ /* Assume the slot is powered on by default */
+ slot->power_state = PCI_SLOT_POWER_ON;
+ if (slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL) {
+ slot->power_ctl = 1;
+
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL,
+ &slot_ctl);
+ if (slot_ctl & PCICAP_EXP_SLOTCTL_PWRCTLR)
+ slot->power_state = PCI_SLOT_POWER_OFF;
+ }
+
+ if (slot->slot_cap & PCICAP_EXP_SLOTCAP_PWRI)
+ slot->power_led_ctl = PCI_SLOT_PWR_LED_CTL_KERNEL;
+ if (slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI)
+ slot->attn_led_ctl = PCI_SLOT_ATTN_LED_CTL_KERNEL;
+ slot->wired_lanes = ((slot->link_cap & PCICAP_EXP_LCAP_MAXWDTH) >> 4);
+
+ /* The surprise hotplug capability is claimed when it's supported
+ * in the slot's capability bits or link state change reporting is
+ * supported in PCIe link capability. It means the surprise hotplug
+ * relies on presence or link state change events. In order for the
+ * link state change event to be properly raised during surprise hot
+ * add/remove, the power supply to the slot should be always on.
+ *
+ * For PCI slots that don't claim surprise hotplug capability explicitly.
+ * Its PDC (Presence Detection Change) isn't reliable. To mark that as
+ * broken on them.
+ */
+ if (slot->pcie_cap & PCICAP_EXP_CAP_SLOT) {
+ if (slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_SURP) {
+ slot->surprise_pluggable = 1;
+ } else if (slot->link_cap & PCICAP_EXP_LCAP_DL_ACT_REP) {
+ slot->surprise_pluggable = 1;
+
+ pci_slot_add_flags(slot, PCI_SLOT_FLAG_BROKEN_PDC);
+ }
+ }
+
+ /* Standard slot operations */
+ slot->ops.get_presence_state = pcie_slot_get_presence_state;
+ slot->ops.get_link_state = pcie_slot_get_link_state;
+ slot->ops.get_power_state = pcie_slot_get_power_state;
+ slot->ops.get_attention_state = pcie_slot_get_attention_state;
+ slot->ops.get_latch_state = pcie_slot_get_latch_state;
+ slot->ops.set_power_state = pcie_slot_set_power_state;
+ slot->ops.set_attention_state = pcie_slot_set_attention_state;
+
+ /*
+ * State machine (SM) based reset stuff. The poll function is always
+ * unified for all cases.
+ */
+ slot->ops.poll_link = pcie_slot_sm_poll_link;
+ slot->ops.hreset = pcie_slot_sm_hreset;
+ slot->ops.freset = pcie_slot_sm_freset;
+
+ slot->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
+ slot->connector_type = PCI_SLOT_CONNECTOR_PCIE_NS;
+ slot->card_desc = PCI_SLOT_DESC_NON_STANDARD;
+ slot->card_mech = PCI_SLOT_MECH_NONE;
+ slot->power_led_ctl = PCI_SLOT_PWR_LED_CTL_NONE;
+ slot->attn_led_ctl = PCI_SLOT_ATTN_LED_CTL_NONE;
+
+ return slot;
+}
+
+/* FIXME: this is kind of insane */
+struct pci_slot *pcie_slot_create_dynamic(struct phb *phb,
+ struct pci_device *pd)
+{
+ uint32_t ecap, val;
+ struct pci_slot *slot;
+
+ if (!phb || !pd || pd->slot)
+ return NULL;
+
+ /* Try to create slot whose details aren't provided by platform. */
+ if (pd->dev_type != PCIE_TYPE_SWITCH_DNPORT)
+ return NULL;
+
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCAP, &val);
+ if (!(val & PCICAP_EXP_SLOTCAP_HPLUG_CAP))
+ return NULL;
+
+ slot = pcie_slot_create(phb, pd);
+
+ /* On superMicro's "p8dnu" platform, we create dynamic PCI slots
+ * for all downstream ports of PEX9733 that is connected to PHB
+ * direct slot. The power supply to the PCI slot is lost after
+ * PCI adapter is removed from it. The power supply can't be
+ * turned on when the slot is in empty state. The power supply
+ * isn't turned on automatically when inserting PCI adapter to
+ * the slot at later point. We set a flag to the slot here, to
+ * turn on the power supply in (suprise or managed) hot-add path.
+ *
+ * We have same issue with PEX8718 as above on "p8dnu" platform.
+ */
+ if (dt_node_is_compatible(dt_root, "supermicro,p8dnu") && slot &&
+ slot->pd && (slot->pd->vdid == 0x973310b5 ||
+ slot->pd->vdid == 0x871810b5))
+ pci_slot_add_flags(slot, PCI_SLOT_FLAG_FORCE_POWERON);
+
+ return slot;
+}