aboutsummaryrefslogtreecommitdiff
path: root/core/pcie-slot.c
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-10-14 15:26:05 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-10-17 10:33:56 +1100
commit51931bad325e3feba934eaf95b422deeb24cf4e5 (patch)
tree984642f7ee72a5146c187fbbd24f7432e0a05299 /core/pcie-slot.c
parent481ad7330e332770b1dcd2c9f56d0a2caac67755 (diff)
downloadskiboot-51931bad325e3feba934eaf95b422deeb24cf4e5.zip
skiboot-51931bad325e3feba934eaf95b422deeb24cf4e5.tar.gz
skiboot-51931bad325e3feba934eaf95b422deeb24cf4e5.tar.bz2
core/pci: Claim surprise hotplug capability
This claims PCIe surprise hotplug capability through device node's property "ibm,slot-surprise-pluggable". The slot has the capability when surprise hotplug is supported in its slot's capability bits or link state change reporting is supported in PCIe link capability bits. In order for link state events to be properly raised during surprise hotplug, the power supply to the slot should be always on. The slot's power state should be switched accordingly during fundamental reset. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'core/pcie-slot.c')
-rw-r--r--core/pcie-slot.c40
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;