[v7,08/10] skiboot: Add core IMC related counter configuration OPAL call

Message ID 1489036089-6529-9-git-send-email-maddy@linux.vnet.ibm.com
State Superseded
Headers show

Commit Message

Madhavan Srinivasan March 9, 2017, 5:08 a.m.
From: Hemant Kumar <hemant@linux.vnet.ibm.com>

This patch adds macro definitions related to Core IMC related macro
definitions for the configuration of the required SCOM ports. A new OPAL
call opal_core_imc_counters_countrol() is added to initialize, enable or
disable the core IMC counters.

To initialize the core IMC counters, it takes a physical address per
core as an input and writes that address to 14-50 bits of the
PDBAR. It initializes the htm_mode, where it selects the time
interval at which the counter values must be posted to the given memory
location and enables the counters to start running by setting the
appropriate bits.

To disable the core IMC counters (only stop counting), writes into
appropriate bits of htm_mode to disable the counters.
To enable the core IMC counters (only resume counting), writes into
appropriate bits of the htm_mode to enable the counters.

Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com>
[maddy: Fixed core imc scom macro]
Signed-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
---
 hw/imc.c           | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/imc.h      |  10 ++++
 include/opal-api.h |  10 +++-
 3 files changed, 169 insertions(+), 1 deletion(-)

Patch

diff --git a/hw/imc.c b/hw/imc.c
index ba768a58a7ac..5e825708ccc1 100644
--- a/hw/imc.c
+++ b/hw/imc.c
@@ -78,6 +78,28 @@  char const *nest_pmus[] = {
 };
 
 
+#define CORE_IMC_OP_DISABLE 0
+#define CORE_IMC_OP_ENABLE 1
+
+/*
+ * A Quad contains 4 cores in Power 9, and there are 4 addresses for
+ * the CHTM attached to each core.
+ * So, for core index 0 to core index 3, we have a sequential range of
+ * SCOM port addresses in the arrays below, each for PDBAR and HTM mode.
+ */
+unsigned int pdbar_scom_index[] = {
+	0x1001220B,
+	0x1001230B,
+	0x1001260B,
+	0x1001270B
+};
+unsigned int htm_scom_index[] = {
+	0x10012200,
+	0x10012300,
+	0x10012600,
+	0x10012700
+};
+
 static struct imc_chip_cb *get_imc_cb(void)
 {
 	uint64_t cb_loc;
@@ -310,3 +332,131 @@  static int64_t opal_nest_imc_counters_control(uint64_t mode,
 }
 
 opal_call(OPAL_NEST_IMC_COUNTERS_CONTROL, opal_nest_imc_counters_control, 4);
+
+static int opal_core_imc_counters_switch(uint64_t op)
+{
+	struct proc_chip *chip;
+	int ret = -1, core_id, phys_core_id;
+
+	chip = get_chip(this_cpu()->chip_id);
+	phys_core_id = cpu_get_core_index(this_cpu());
+	core_id = phys_core_id % 4;
+
+	if (op == CORE_IMC_OP_DISABLE)
+		ret = xscom_write(chip->id,
+				  XSCOM_ADDR_P9_EP(phys_core_id,
+						   htm_scom_index[core_id]),
+				  (u64) CORE_IMC_HTM_MODE_DISABLE);
+	else if (op == CORE_IMC_OP_ENABLE)
+		ret = xscom_write(chip->id,
+				  XSCOM_ADDR_P9_EP(phys_core_id,
+						   htm_scom_index[core_id]),
+				  htm_scom_index[core_id]);
+
+	if (ret < 0) {
+		prerror("IMC: error in xscom_write for htm_mode\n");
+		return OPAL_HARDWARE;
+	}
+
+	return OPAL_SUCCESS;
+}
+
+static int opal_core_imc_counters_init(uint64_t addr)
+{
+	struct proc_chip *chip;
+	int ret, core_id, phys_core_id;
+
+	chip = get_chip(this_cpu()->chip_id);
+	phys_core_id = cpu_get_core_index(this_cpu());
+	core_id = phys_core_id % 4;
+
+	ret = xscom_write(chip->id,
+			  XSCOM_ADDR_P9_EP(phys_core_id,
+					   pdbar_scom_index[core_id]),
+			  (u64)(CORE_IMC_PDBAR_MASK & addr));
+	if (ret < 0) {
+		prerror("IMC: error in xscom_write for pdbar\n");
+		goto hw_err;
+	}
+
+	ret = xscom_write(chip->id,
+			  XSCOM_ADDR_P9_EC(phys_core_id,
+					   CORE_IMC_EVENT_MASK_ADDR),
+			  (u64)CORE_IMC_EVENT_MASK);
+	if (ret < 0) {
+		prerror("IMC: error in xscom_write for event mask\n");
+		goto hw_err;
+	}
+
+	ret = xscom_write(chip->id,
+			  XSCOM_ADDR_P9_EP(phys_core_id,
+					   htm_scom_index[core_id]),
+			  (u64)CORE_IMC_HTM_MODE_ENABLE);
+	if (ret < 0) {
+		prerror("IMC: error in xscom_write for htm mode\n");
+		goto hw_err;
+	}
+
+	return OPAL_SUCCESS;
+hw_err:
+	ret = OPAL_HARDWARE;
+	return ret;
+}
+
+/*
+ * opal_core_imc_counters_control : Controls the Core IMC counters.
+ *
+ * operation : For now, this call supports only OPAL_CORE_IMC_INIT,
+ *             OPAL_CORE_IMC_DISABLE and OPAL_CORE_IMC_ENABLE operations.
+ *
+ *             OPAL_CORE_IMC_INIT initializes core IMC Engine for the
+ *             current core, by initializing the pdbars, htm_mode,
+ *             and the event_mask. "addr" must be non-zero for this operation.
+ *
+ *             OPAL_CORE_IMC_ENABLE enables the core imc engine by
+ *             appropriately setting bits 4-9 of the HTM_MODE scom port. No
+ *             initialization is done in this call. This just enables the
+ *             the counters to count with the previous initialization.
+ *
+ *             OPAL_CORE_IMC_DISABLE disables the core imc engine by clearing
+ *             bits 4-9 of the HTM_MODE scom port.
+ *
+ * addr      : Contains per-core physical address. This is the memory
+ *	       address where the core IMC engine writes the counter values.
+ *             Must be non-zero for CORE_IMC_INIT and zero for
+ *             CORE_IMC_DISABLE and CORE_IMC_ENABLE operations.
+ *
+ * This call can be extended to include other operations in "operation" and
+ * the  other two parameters value_1 and value_2 are provided in case, they
+ * are needed in future. For now, they are unused and must be zero.
+ */
+static int64_t opal_core_imc_counters_control(uint64_t operation,
+					      uint64_t addr,
+					      uint64_t value_1,
+					      uint64_t value_2)
+{
+	int ret = OPAL_PARAMETER;
+
+	if (value_1 || value_2)
+		return ret;
+
+	switch (operation) {
+	case OPAL_CORE_IMC_DISABLE:
+		if (!addr)
+			ret = opal_core_imc_counters_switch(CORE_IMC_OP_DISABLE);
+		break;
+	case OPAL_CORE_IMC_ENABLE:
+		if (!addr)
+			ret = opal_core_imc_counters_switch(CORE_IMC_OP_ENABLE);
+		break;
+	case OPAL_CORE_IMC_INIT:
+		if (addr)
+			ret = opal_core_imc_counters_init(addr);
+		break;
+	default:
+		ret = OPAL_PARAMETER;
+	}
+
+	return ret;
+}
+opal_call(OPAL_CORE_IMC_COUNTERS_CONTROL, opal_core_imc_counters_control, 4);
diff --git a/include/imc.h b/include/imc.h
index d2f5d4edda1d..1d553467e28a 100644
--- a/include/imc.h
+++ b/include/imc.h
@@ -122,5 +122,15 @@  struct imc_chip_cb
 #define MAX_AVL		48
 /* Reserved bits : 48-64 */
 
+/*
+ * Core IMC SCOMs
+ */
+#define CORE_IMC_EVENT_MASK_ADDR        0x20010AA8ull
+#define CORE_IMC_EVENT_MASK		0x0001020000000000ull
+#define CORE_IMC_PDBAR_MASK		0x0003ffffffffe000ull
+#define CORE_IMC_NCU_MODE		0x0800000000000000ull
+#define CORE_IMC_HTM_MODE_ENABLE	0xE800000000000000ull
+#define CORE_IMC_HTM_MODE_DISABLE	0xE000000000000000ull
+
 void imc_init(void);
 #endif /* __IMC_H */
diff --git a/include/opal-api.h b/include/opal-api.h
index 3e66db3d53f5..ba9418e70aeb 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -201,7 +201,8 @@ 
 #define OPAL_XIVE_RESERVED3			143
 #define OPAL_XIVE_RESERVED4			144
 #define OPAL_NEST_IMC_COUNTERS_CONTROL		145
-#define OPAL_LAST				145
+#define OPAL_CORE_IMC_COUNTERS_CONTROL		146
+#define OPAL_LAST				146
 
 /* Device tree flags */
 
@@ -1144,6 +1145,13 @@  enum {
 	OPAL_NEST_IMC_START,
 };
 
+/* Operation argument to Core IMC */
+enum {
+	OPAL_CORE_IMC_DISABLE,
+	OPAL_CORE_IMC_ENABLE,
+	OPAL_CORE_IMC_INIT,
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __OPAL_API_H */