[Skiboot] [PATCH v2 14/16] npu2-opencapi: Activate PCI hotplug on opencapi slot

Frederic Barrat fbarrat at linux.ibm.com
Thu Oct 10 06:38:09 AEDT 2019


Implement the get_power_state() and set_power_state() callbacks for
the opencapi slot and add properties in the device tree to mark the
opencapi slot as hot-pluggable.

We don't really power off/on the opencapi adapter. The slot at play
here is the virtual slot associated to the virtual opencapi PHB. The
real PCIe slot where the card is drawing its power from is
untouched (skiboot is not even aware which PCIe slot the card is
seated on). So the 'fake' power off is fencing the card and set it in
reset so that the FPGA image can be updated. The 'fake' power on is
not doing much, as the unfencing happens on the subsequent link
training.

Opencapi slots are named 'OPENCAPI-xxxx' where xxxx is the opal ID of
the PHB/slot. This is meant to easily identify the slot used by an AFU
device, as the AFU device names are also built around that ID.
For example, the device /dev/ocxl/AFP3.0006:00:00.1.0 uses the slot
OPENCAPI-0006.

Signed-off-by: Frederic Barrat <fbarrat at linux.ibm.com>
---
Changelog:
v2:
 - move call to mark the opencapi slot hot-pluggable (Christophe)


hw/npu2-opencapi.c | 69 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 65 insertions(+), 4 deletions(-)

diff --git a/hw/npu2-opencapi.c b/hw/npu2-opencapi.c
index a8dd0210..f5c821d9 100644
--- a/hw/npu2-opencapi.c
+++ b/hw/npu2-opencapi.c
@@ -1032,9 +1032,10 @@ static int64_t npu2_opencapi_get_presence_state(struct pci_slot __unused *slot,
 	 * As such we will never be asked to get the presence of a slot that's
 	 * empty.
 	 *
-	 * This may change if we ever support hotplug down the track.
+	 * This may change if we ever support surprise hotplug down
+	 * the track.
 	 */
-	*val = true;
+	*val = OPAL_PCI_SLOT_PRESENT;
 	return OPAL_SUCCESS;
 }
 
@@ -1092,6 +1093,38 @@ static int64_t npu2_opencapi_get_link_state(struct pci_slot *slot, uint8_t *val)
 	return OPAL_SUCCESS;
 }
 
+static int64_t npu2_opencapi_get_power_state(struct pci_slot *slot,
+					     uint8_t *val)
+{
+	*val = slot->power_state;
+	return OPAL_SUCCESS;
+}
+
+static int64_t npu2_opencapi_set_power_state(struct pci_slot *slot, uint8_t val)
+{
+	struct npu2_dev *dev = phb_to_npu2_dev_ocapi(slot->phb);
+
+	switch (val) {
+	case PCI_SLOT_POWER_OFF:
+		OCAPIDBG(dev, "Fake power off\n");
+		fence_brick(dev);
+		assert_adapter_reset(dev);
+		slot->power_state = PCI_SLOT_POWER_OFF;
+		return OPAL_SUCCESS;
+
+	case PCI_SLOT_POWER_ON:
+		if (slot->power_state != PCI_SLOT_POWER_OFF)
+			return OPAL_SUCCESS;
+		OCAPIDBG(dev, "Fake power on\n");
+		slot->power_state = PCI_SLOT_POWER_ON;
+		slot->state = OCAPI_SLOT_NORMAL;
+		return OPAL_SUCCESS;
+
+	default:
+		return OPAL_UNSUPPORTED;
+	}
+}
+
 static void check_trained_link(struct npu2_dev *dev, uint64_t odl_status)
 {
 	if (get_link_width(odl_status) != OPAL_SHPC_LINK_UP_x8) {
@@ -1132,6 +1165,14 @@ static int64_t npu2_opencapi_retry_state(struct pci_slot *slot,
 	return pci_slot_set_sm_timeout(slot, msecs_to_tb(1));
 }
 
+static void npu2_opencapi_prepare_link_change(struct pci_slot *slot __unused,
+					      bool up __unused)
+{
+	/*
+	 * PCI hotplug wants it defined, but we don't need to do anything
+	 */
+}
+
 static int64_t npu2_opencapi_poll_link(struct pci_slot *slot)
 {
 	struct npu2_dev *dev = phb_to_npu2_dev_ocapi(slot->phb);
@@ -1261,6 +1302,24 @@ static int64_t npu2_opencapi_hreset(struct pci_slot *slot __unused)
 	return OPAL_UNSUPPORTED;
 }
 
+static void make_slot_hotpluggable(struct pci_slot *slot, struct phb *phb)
+{
+	char label[40];
+
+	/*
+	 * Add a few definitions to the DT so that the linux PCI
+	 * hotplug framework can find the slot and identify it as
+	 * hot-pluggable.
+	 *
+	 * The "ibm,slot-label" property is used by linux as the slot name
+	 */
+	slot->pluggable = 1;
+	pci_slot_add_dt_properties(slot, phb->dt_node);
+	snprintf(label, sizeof(label), "OPENCAPI-%04x",
+		 (int)PCI_SLOT_PHB_INDEX(slot->id));
+	dt_add_property_string(phb->dt_node, "ibm,slot-label", label);
+}
+
 static struct pci_slot *npu2_opencapi_slot_create(struct phb *phb)
 {
 	struct pci_slot *slot;
@@ -1272,12 +1331,13 @@ static struct pci_slot *npu2_opencapi_slot_create(struct phb *phb)
 	/* TODO: Figure out other slot functions */
 	slot->ops.get_presence_state  = npu2_opencapi_get_presence_state;
 	slot->ops.get_link_state      = npu2_opencapi_get_link_state;
-	slot->ops.get_power_state     = NULL;
+	slot->ops.get_power_state     = npu2_opencapi_get_power_state;
 	slot->ops.get_attention_state = NULL;
 	slot->ops.get_latch_state     = NULL;
-	slot->ops.set_power_state     = NULL;
+	slot->ops.set_power_state     = npu2_opencapi_set_power_state;
 	slot->ops.set_attention_state = NULL;
 
+	slot->ops.prepare_link_change = npu2_opencapi_prepare_link_change;
 	slot->ops.poll_link           = npu2_opencapi_poll_link;
 	slot->ops.creset              = npu2_opencapi_creset;
 	slot->ops.freset              = npu2_opencapi_freset;
@@ -1716,6 +1776,7 @@ static void setup_device(struct npu2_dev *dev)
 			 */
 			prlog(PR_ERR, "OCAPI: Cannot create PHB slot\n");
 		}
+		make_slot_hotpluggable(slot, &dev->phb_ocapi);
 	}
 	return;
 }
-- 
2.21.0



More information about the Skiboot mailing list