[Skiboot] [PATCH v9 10/11] skiboot: Add core IMC related counter configuration OPAL call

Anju T Sudhakar anju at linux.vnet.ibm.com
Thu Apr 27 06:37:00 AEST 2017


This patch add support to start, stop and initialize 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 at linux.vnet.ibm.com>
[maddy: Fixed core imc scom macro and added comments]
Signed-off-by: Madhavan Srinivasan <maddy at linux.vnet.ibm.com>
Signed-off-by: Anju T Sudhakar <anju at linux.vnet.ibm.com>
---
 hw/imc.c           | 143 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 include/imc.h      |  10 ++++
 include/opal-api.h |   1 +
 3 files changed, 143 insertions(+), 11 deletions(-)

diff --git a/hw/imc.c b/hw/imc.c
index 6a1982e..f21945d 100644
--- a/hw/imc.c
+++ b/hw/imc.c
@@ -79,6 +79,26 @@ char const *nest_pmus[] = {
 
 void fixup_handler(hash_entry_p entry, const struct dt_property *prop);
 
+
+/*
+ * 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;
@@ -295,25 +315,84 @@ err:
 }
 
 /*
- * opal_imc_counters_init : This call initialize the IMC engine.
- *
+ * opal_imc_counters_init : This call 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.
  * This call is not being used in case of NEST IMC.
- * Additional arguments will be added to this call in the following patch.
  */
-static int64_t opal_imc_counters_init(uint32_t type)
+static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr)
 {
-	if (type == OPAL_IMC_COUNTERS_NEST)
+	struct proc_chip *chip;
+	int core_id, phys_core_id, ret = OPAL_PARAMETER;
+
+	switch (type) {
+	case OPAL_IMC_COUNTERS_NEST:
 		prerror("IMC: unknown operation for nest imc\n");
-	return OPAL_PARAMETER;
+		return ret;
+		break;
+	case OPAL_IMC_COUNTERS_CORE:
+		chip = get_chip(this_cpu()->chip_id);
+		phys_core_id = cpu_get_core_index(this_cpu());
+		core_id = phys_core_id % 4;
+
+		/*
+		* Core IMC hardware mandate initing of three scoms
+		* to enbale or disable of the Core IMC engine.
+		*
+		* PDBAR: Scom contains the real address to store per-core
+		*        counter data in memory along with other bits.
+		*
+		* EventMask: Scom contain bits to denote event to multiplex
+		*            at different MSR[HV PR] values, along with bits for
+		*            sampling duration.
+		*
+		* HTM Scom: scom to enable counter data movement to memory.
+		*/
+		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_DISABLE);
+		if (ret < 0) {
+			prerror("IMC: error in xscom_write for htm mode\n");
+			goto hw_err;
+		}
+
+		return OPAL_SUCCESS;
+		break;
+	default:
+		return ret;
+	}
+hw_err:
+	return OPAL_HARDWARE;
 }
-opal_call(OPAL_IMC_COUNTERS_INIT, opal_imc_counters_init, 1);
+opal_call(OPAL_IMC_COUNTERS_INIT, opal_imc_counters_init, 2);
 
-/* opal_imc_counters_control_start: This call starts the nest imc engine. */
+/* opal_imc_counters_control_start: This call starts the nest/core imc engine. */
 static int64_t opal_imc_counters_start(uint32_t type)
 {
 	u64 op, status;
 	struct imc_chip_cb *cb;
-	int ret = OPAL_PARAMETER;
+	struct proc_chip *chip;
+	int core_id, phys_core_id, ret = OPAL_PARAMETER;
 
 	switch (type) {
 	case OPAL_IMC_COUNTERS_NEST: 
@@ -331,6 +410,28 @@ static int64_t opal_imc_counters_start(uint32_t type)
 
 		return OPAL_SUCCESS;
 		break;
+	case OPAL_IMC_COUNTERS_CORE:
+		/*
+		* 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.
+		*/
+		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,
+						htm_scom_index[core_id]),
+		       		(u64) CORE_IMC_HTM_MODE_ENABLE);
+
+		if (ret < 0) {
+			prerror("IMC: error in xscom_write for htm_mode\n");
+			return OPAL_HARDWARE;
+		}
+		return OPAL_SUCCESS;
+		break;
 	default:
 		prerror("IMC: unknown domain \n");
 		return ret;
@@ -339,12 +440,13 @@ static int64_t opal_imc_counters_start(uint32_t type)
 }
 opal_call(OPAL_IMC_COUNTERS_START, opal_imc_counters_start, 1);
 
-/* opal_imc_counters_control_stop: This call stops the nest imc engine. */
+/* opal_imc_counters_control_stop: This call stops the nest/core imc engine. */
 static int64_t opal_imc_counters_stop(uint32_t type)
 {
 	u64 op, status;
 	struct imc_chip_cb *cb;
-	int ret = OPAL_PARAMETER;
+	struct proc_chip *chip;
+	int core_id, phys_core_id, ret = OPAL_PARAMETER;
 
 	switch (type) {
 	case OPAL_IMC_COUNTERS_NEST: 
@@ -363,6 +465,25 @@ static int64_t opal_imc_counters_stop(uint32_t type)
 
 		return OPAL_SUCCESS;
 		break;
+	case OPAL_IMC_COUNTERS_CORE:
+		/*
+		* Disables the core imc engine by clearing
+		* bits 4-9 of the HTM_MODE scom port.
+		*/
+		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,
+						htm_scom_index[core_id]),
+				(u64) CORE_IMC_HTM_MODE_DISABLE);
+		if (ret < 0) {
+			prerror("IMC: error in xscom_write for htm_mode\n");
+			return OPAL_HARDWARE;
+		}
+		return OPAL_SUCCESS;
+		break;
 	default:
 		prerror("IMC: unknown domain \n");
 		return ret;	
diff --git a/include/imc.h b/include/imc.h
index 9dc2557..468f494 100644
--- a/include/imc.h
+++ b/include/imc.h
@@ -115,5 +115,15 @@ struct imc_chip_cb
 
 #define MAX_AVL		48
 
+/*
+ * 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 14477c3..04a6e4a 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -1154,6 +1154,7 @@ enum {
 /* Operation argument to IMC Microcode */
 enum {
 	OPAL_IMC_COUNTERS_NEST = 1,
+	OPAL_IMC_COUNTERS_CORE = 2,
 };
 
 
-- 
2.7.4



More information about the Skiboot mailing list