diff mbox series

[4/6] rainier: Define PCI slot table

Message ID 20211018123751.72794-5-fbarrat@linux.ibm.com
State Superseded
Headers show
Series PCI hotplug on Rainier (and ZZ) | expand

Commit Message

Frederic Barrat Oct. 18, 2021, 12:37 p.m. UTC
Define the table of PCI slots for Rainier, reusing the existing slot
table infrastructure. For each slot, add the information useful to
control power through the hotplug controller.

This patch also redefines the slot power management callbacks to route
them to the previously introduced hotplug controller interfaces.

Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com>
---
 platforms/astbmc/rainier.c | 159 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 157 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/platforms/astbmc/rainier.c b/platforms/astbmc/rainier.c
index 467e6d5a..baa93254 100644
--- a/platforms/astbmc/rainier.c
+++ b/platforms/astbmc/rainier.c
@@ -10,6 +10,7 @@ 
 #include <i2c.h>
 #include <timebase.h>
 #include <timer.h>
+#include <pci.h>
 #include <pci-slot.h>
 
 #include "astbmc.h"
@@ -46,6 +47,61 @@  struct slot_hp_data {
 	uint8_t slot_index;
 };
 
+#define RAINIER_HP_DATA(st_name, controller, n)				\
+	static const struct slot_hp_data st_name = {			\
+		.hp_controller = &(controller),				\
+		.slot_index = n,					\
+	}
+
+#define RAINIER_SLOT_DEF(st_name, slot_name, hp_data)			\
+	static const struct slot_table_entry st_name[] = {		\
+		{							\
+			.etype = st_pluggable_slot,			\
+			.name = slot_name,				\
+			.platform_data = &(hp_data),			\
+		},							\
+		{ .etype = st_end },					\
+	}
+
+RAINIER_HP_DATA(c7_data, hp_controller_dcm0, 0);
+RAINIER_HP_DATA(c8_data, hp_controller_dcm0, 1);
+RAINIER_HP_DATA(c9_data, hp_controller_dcm0, 2);
+RAINIER_HP_DATA(c10_data, hp_controller_dcm0, 3);
+RAINIER_HP_DATA(c11_data, hp_controller_dcm0, 4);
+RAINIER_SLOT_DEF(p1phb3_slot, "C7", c7_data);
+RAINIER_SLOT_DEF(p1phb1_slot, "C8", c8_data);
+RAINIER_SLOT_DEF(p1phb0_slot, "C9", c9_data);
+RAINIER_SLOT_DEF(p0phb3_slot, "C10", c10_data);
+RAINIER_SLOT_DEF(p0phb0_slot, "C11", c11_data);
+
+RAINIER_HP_DATA(c0_data, hp_controller_dcm1, 0);
+RAINIER_HP_DATA(c1_data, hp_controller_dcm1, 1);
+RAINIER_HP_DATA(c2_data, hp_controller_dcm1, 2);
+RAINIER_HP_DATA(c3_data, hp_controller_dcm1, 3);
+RAINIER_HP_DATA(c4_data, hp_controller_dcm1, 4);
+RAINIER_SLOT_DEF(p3phb3_slot, "C0", c0_data);
+RAINIER_SLOT_DEF(p3phb1_slot, "C1", c1_data);
+RAINIER_SLOT_DEF(p3phb0_slot, "C2", c2_data);
+RAINIER_SLOT_DEF(p2phb3_slot, "C3", c3_data);
+RAINIER_SLOT_DEF(p2phb0_slot, "C4", c4_data);
+
+static const struct slot_table_entry rainier_phb_table[] = {
+	ST_PHB_ENTRY(0, 0, p0phb0_slot),
+	ST_PHB_ENTRY(0, 3, p0phb3_slot),
+
+	ST_PHB_ENTRY(2, 0, p1phb0_slot),
+	ST_PHB_ENTRY(2, 1, p1phb1_slot),
+	ST_PHB_ENTRY(2, 3, p1phb3_slot),
+
+	ST_PHB_ENTRY(4, 0, p2phb0_slot),
+	ST_PHB_ENTRY(4, 3, p2phb3_slot),
+
+	ST_PHB_ENTRY(6, 0, p3phb0_slot),
+	ST_PHB_ENTRY(6, 1, p3phb1_slot),
+	ST_PHB_ENTRY(6, 3, p3phb3_slot),
+	{ .etype = st_end },
+};
+
 static int64_t hp_controller_i2c_read(struct hp_controller *hpc,
 				      uint32_t *data)
 {
@@ -127,7 +183,7 @@  unlock:
 	return rc;
 }
 
-static void __unused timer_check_enable(struct timer *t __unused, void *data,
+static void timer_check_enable(struct timer *t __unused, void *data,
 			       uint64_t now __unused)
 {
 	struct pci_slot *slot = data;
@@ -176,7 +232,7 @@  unlock:
 	return rc;
 }
 
-static int64_t __unused hp_controller_disable(struct hp_controller *hpc, int slot_index)
+static int64_t hp_controller_disable(struct hp_controller *hpc, int slot_index)
 {
 	uint32_t state, en_mask, ctl_mask, pg_mask;
 	uint64_t rc = OPAL_SUCCESS;
@@ -227,11 +283,108 @@  static void hp_controller_init(struct hp_controller *hpc, uint32_t chip_id)
 	}
 }
 
+static int64_t rainier_pci_slot_get_power_state(struct pci_slot *slot,
+						uint8_t *val)
+{
+	uint32_t state, en_mask, ctl_mask, pg_mask;
+	struct slot_table_entry *ent = slot->data;
+	const struct slot_hp_data *hp_data;
+	struct hp_controller *hpc;
+	uint32_t slot_index;
+
+	if (!ent || !ent->platform_data)
+		return OPAL_PARAMETER;
+
+	hp_data = ent->platform_data;
+	slot_index = hp_data->slot_index;
+	hpc = hp_data->hp_controller;
+
+	hp_get_masks(slot_index, &en_mask, &pg_mask, &ctl_mask);
+
+	lock(&hpc->lock);
+	hp_controller_i2c_read(hpc, &state);
+	unlock(&hpc->lock);
+
+	*val = (state & en_mask) && (state & pg_mask);
+	return 0;
+}
+
+static int64_t rainier_pci_slot_set_power_state(struct pci_slot *slot,
+						uint8_t val)
+{
+	struct slot_table_entry *ent = slot->data;
+	const struct slot_hp_data *hp_data;
+	struct hp_controller *hpc;
+	uint32_t slot_index;
+	int64_t rc;
+
+	if (!ent || !ent->platform_data)
+		return OPAL_PARAMETER;
+	if (val != PCI_SLOT_POWER_OFF && val != PCI_SLOT_POWER_ON)
+		return OPAL_PARAMETER;
+
+	hp_data = ent->platform_data;
+	slot_index = hp_data->slot_index;
+	hpc = hp_data->hp_controller;
+
+	slot->power_state = val;
+	if (val == PCI_SLOT_POWER_ON) {
+		rc = hp_controller_enable(hpc, slot_index);
+		if (!rc) {
+			/* schedule to check state of PGOOD after 2s */
+			init_timer(&hpc->slot_timer[slot_index],
+				   timer_check_enable, slot);
+			schedule_timer(&hpc->slot_timer[slot_index],
+				       msecs_to_tb(PGOOD_QUERY_WINDOW));
+			pci_slot_set_state(slot, PCI_SLOT_STATE_SPOWER_START);
+			rc = OPAL_ASYNC_COMPLETION;
+		}
+	} else {
+		rc = hp_controller_disable(hpc, slot_index);
+	}
+	return rc;
+}
+
+static void rainier_get_slot_info(struct phb *phb, struct pci_device *pd)
+{
+	struct pci_slot *slot;
+
+	if (!pd || pd->slot)
+		return;
+
+	slot_table_get_slot_info(phb, pd);
+	if (!pd->slot)
+		return;
+
+	slot = pd->slot;
+	if (!pd->parent && phb->slot) {
+		void (*tmp)(struct pci_slot *slot, struct dt_node *np);
+		/*
+		 * For PHB slots, keep the ops of the PHB, except for
+		 * add_properties, which was defined by the slot table
+		 * framework and takes care of things like slot label,
+		 * location, ...
+		 */
+		tmp = slot->ops.add_properties;
+		memcpy(&slot->ops, &phb->slot->ops,
+		       sizeof(struct pci_slot_ops));
+		slot->ops.add_properties = tmp;
+	}
+
+	if (slot->data) {
+		/* slots defined in our slot table support power management */
+		slot->ops.get_power_state = rainier_pci_slot_get_power_state;
+		slot->ops.set_power_state = rainier_pci_slot_set_power_state;
+	}
+}
+
 static void rainier_pci_probe_complete(void)
 {
 	prlog(PR_DEBUG, "PLAT: checking power of PCI slots\n");
 	hp_controller_check_enable(&hp_controller_dcm0, -1);
 	hp_controller_check_enable(&hp_controller_dcm1, -1);
+
+	check_all_slot_table();
 }
 
 static void rainier_init_slot_power(void)
@@ -246,6 +399,7 @@  static void rainier_init_slot_power(void)
 static void rainier_init(void)
 {
 	astbmc_init();
+	slot_table_init(rainier_phb_table);
 	rainier_init_slot_power();
 }
 
@@ -274,6 +428,7 @@  DECLARE_PLATFORM(rainier) = {
 	.bmc			= &bmc_plat_ast2600_openbmc,
 	.cec_power_down         = astbmc_ipmi_power_down,
 	.cec_reboot             = astbmc_ipmi_reboot,
+	.pci_get_slot_info	= rainier_get_slot_info,
 	.pci_probe_complete	= rainier_pci_probe_complete,
 	.elog_commit		= ipmi_elog_commit,
 	.exit			= astbmc_exit,