[Skiboot] [PATCH 13/16] core/pci: Claim surprise hotplug capability

Gavin Shan gwshan at linux.vnet.ibm.com
Fri Sep 16 15:05:20 AEST 2016


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 at linux.vnet.ibm.com>
---
 core/pci-slot.c                 |  2 ++
 core/pcie-slot.c                | 40 ++++++++++++++++++++++++++++++++--------
 include/pci-slot.h              |  1 +
 platforms/ibm-fsp/firenze-pci.c | 10 ++++++++++
 4 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/core/pci-slot.c b/core/pci-slot.c
index 8735598..721b2d9 100644
--- a/core/pci-slot.c
+++ b/core/pci-slot.c
@@ -116,6 +116,8 @@ void pci_slot_add_dt_properties(struct pci_slot *slot,
 
 	dt_add_property_cells(np, "ibm,reset-by-firmware", 1);
 	dt_add_property_cells(np, "ibm,slot-pluggable", slot->pluggable);
+	dt_add_property_cells(np, "ibm,slot-surprise-pluggable",
+			      slot->surprise_pluggable);
 	dt_add_property_cells(np, "ibm,slot-power-ctl", slot->power_ctl);
 	dt_add_property_cells(np, "ibm,slot-power-led-ctlled",
 			      slot->power_led_ctl);
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;
diff --git a/include/pci-slot.h b/include/pci-slot.h
index cf22432..694a448 100644
--- a/include/pci-slot.h
+++ b/include/pci-slot.h
@@ -161,6 +161,7 @@ struct pci_slot {
 
 	/* Slot information */
 	uint8_t			pluggable;
+	uint8_t			surprise_pluggable;
 	uint8_t			power_ctl;
 	uint8_t			power_led_ctl;
 	uint8_t			attn_led_ctl;
diff --git a/platforms/ibm-fsp/firenze-pci.c b/platforms/ibm-fsp/firenze-pci.c
index 4cc0284..322c0f2 100644
--- a/platforms/ibm-fsp/firenze-pci.c
+++ b/platforms/ibm-fsp/firenze-pci.c
@@ -688,6 +688,16 @@ static int64_t firenze_pci_slot_set_power_state(struct pci_slot *slot,
 	if (slot->power_state == val)
 		return OPAL_SUCCESS;
 
+	/* Update with the requested power state and bail immediately when
+	 * surprise hotplug is supported on the slot. It keeps the power
+	 * supply to the slot on and it guarentees the link state change
+	 * events will be raised properly during surprise hot add/remove.
+	 */
+	if (slot->surprise_pluggable) {
+		slot->power_state = val;
+		return OPAL_SUCCESS;
+	}
+
 	slot->power_state = val;
 	pci_slot_set_state(slot, FIRENZE_PCI_SLOT_SPOWER_START);
 
-- 
2.1.0



More information about the Skiboot mailing list