diff options
Diffstat (limited to 'core/pcie-slot.c')
-rw-r--r-- | core/pcie-slot.c | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/core/pcie-slot.c b/core/pcie-slot.c index fed3462..2484570 100644 --- a/core/pcie-slot.c +++ b/core/pcie-slot.c @@ -196,7 +196,8 @@ static int64_t pcie_slot_set_attention_state(struct pci_slot *slot, return OPAL_SUCCESS; } -static int64_t pcie_slot_set_power_state(struct pci_slot *slot, uint8_t val) +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; @@ -214,6 +215,15 @@ static int64_t pcie_slot_set_power_state(struct pci_slot *slot, uint8_t val) return OPAL_SUCCESS; } + /* The power supply to the slot should be always on when surprise + * hotplug is claimed. For this case, update with the requested + * power state and bail immediately. + */ + if (surprise_check && slot->surprise_pluggable) { + slot->power_state = val; + return OPAL_SUCCESS; + } + pci_slot_set_state(slot, PCI_SLOT_STATE_SPOWER_START); slot->power_state = val; ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false); @@ -239,6 +249,11 @@ static int64_t pcie_slot_set_power_state(struct pci_slot *slot, uint8_t val) 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; @@ -383,10 +398,10 @@ static int64_t pcie_slot_sm_freset(struct pci_slot *slot) } /* In power on state, power it off */ - if (power_state == PCI_SLOT_POWER_ON && - slot->ops.set_power_state) { + if (power_state == PCI_SLOT_POWER_ON) { PCIE_SLOT_DBG(slot, "FRESET: Power is on, turn off\n"); - slot->ops.set_power_state(slot, PCI_SLOT_POWER_OFF); + 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)); @@ -394,8 +409,7 @@ static int64_t pcie_slot_sm_freset(struct pci_slot *slot) /* No power state change, fall through */ case PCI_SLOT_STATE_FRESET_POWER_OFF: PCIE_SLOT_DBG(slot, "FRESET: Power is off, turn on\n"); - if (slot->ops.set_power_state) - slot->ops.set_power_state(slot, PCI_SLOT_POWER_ON); + pcie_slot_set_power_state_ext(slot, PCI_SLOT_POWER_ON, false); pci_slot_set_state(slot, PCI_SLOT_STATE_HRESET_START); return pci_slot_set_sm_timeout(slot, msecs_to_tb(50)); default: @@ -428,8 +442,7 @@ struct pci_slot *pcie_slot_create(struct phb *phb, struct pci_device *pd) &slot->slot_cap); } - if ((slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_SURP) && - (slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_CAP)) + if (slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_CAP) slot->pluggable = 1; if (slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL) { @@ -451,6 +464,17 @@ struct pci_slot *pcie_slot_create(struct phb *phb, struct pci_device *pd) 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. + */ + if ((slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_SURP) || + (slot->link_cap & PCICAP_EXP_LCAP_DL_ACT_REP)) + slot->surprise_pluggable = 1; + /* Standard slot operations */ slot->ops.get_presence_state = pcie_slot_get_presence_state; slot->ops.get_link_state = pcie_slot_get_link_state; |