diff mbox series

[v2,4/5] skiboot: Enable opal calls to init/start/stop IMC Trace mode

Message ID 20181212061545.9756-5-anju@linux.vnet.ibm.com
State Changes Requested
Headers show
Series skiboot: OPAL support for IMC trace-mode | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success master/apply_patch Successfully applied
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master

Commit Message

Anju T Sudhakar Dec. 12, 2018, 6:15 a.m. UTC
Patch to enhance the imc opal call to support and handle trace_imc mode.

To initialize the trace-mode, TRACE_IMC_SCOM value is written to
TRACE_IMC_ADDR of the respective core.

TRACE_IMC_SCOM is a 64bit value, and each bit represent the following:
0:1       : SAMPSEL
2:33      : CPMC_LOAD
34:40     : CPMC1SEL
41:47     : CPMC2SEL
48:50     : BUFFERSIZE
51:63      : RESERVED
For the nonce the value for TRACE_IMC_SCOM is hard coded.
During initialization htm_mode is disabled, and enabled only at start.

The opal calls to start/stop the counters, will write CORE_IMC_HTM_MODE_ENABLE/
CORE_IMC_HTM_MODE_DISABLE respectively to the htm_scom_index of the desired
cores.

Additional switch cases are added to the current opal calls to start/stop
the counters for trace-mode.

Signed-off-by: Anju T Sudhakar <anju@linux.vnet.ibm.com>
Reviewed-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
Cc: Akshay Adiga <akshay.adiga@linux.vnet.ibm.com>
---
 hw/imc.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

Comments

Stewart Smith Feb. 25, 2019, 5:37 a.m. UTC | #1
Anju T Sudhakar <anju@linux.vnet.ibm.com> writes:
> Patch to enhance the imc opal call to support and handle trace_imc mode.
>
> To initialize the trace-mode, TRACE_IMC_SCOM value is written to
> TRACE_IMC_ADDR of the respective core.
>
> TRACE_IMC_SCOM is a 64bit value, and each bit represent the following:
> 0:1       : SAMPSEL
> 2:33      : CPMC_LOAD
> 34:40     : CPMC1SEL
> 41:47     : CPMC2SEL
> 48:50     : BUFFERSIZE
> 51:63      : RESERVED
> For the nonce the value for TRACE_IMC_SCOM is hard coded.

nonce?

Do you mean we initialize the trace to a default value?

> During initialization htm_mode is disabled, and enabled only at start.
>
> The opal calls to start/stop the counters, will write CORE_IMC_HTM_MODE_ENABLE/
> CORE_IMC_HTM_MODE_DISABLE respectively to the htm_scom_index of the desired
> cores.
>
> Additional switch cases are added to the current opal calls to start/stop
> the counters for trace-mode.
>
> Signed-off-by: Anju T Sudhakar <anju@linux.vnet.ibm.com>
> Reviewed-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
> Cc: Akshay Adiga <akshay.adiga@linux.vnet.ibm.com>
> ---
>  hw/imc.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 103 insertions(+)
>
> diff --git a/hw/imc.c b/hw/imc.c
> index 3392eaf1..40c64d58 100644
> --- a/hw/imc.c
> +++ b/hw/imc.c
> @@ -22,6 +22,15 @@
>  #include <device.h>
>  #include <p9_stop_api.H>
>
> +/*
> + * IMC trace scom values
> + */

for these defines, please have them CAPITALIZED so we know they're
#define and not variables, and also please prefix with something IMC related.

> +#define samplesel	1	/* select cpmc2 */
> +#define cpmcload	0xfa	/* Value to be loaded into cpmc2 at sampling start */
> +#define cpmc1sel	2	/* Event: CPM_CCYC */
> +#define cpmc2sel	2	/* Event: CPM_32MHZ_CYC */

What do these two things mean? Are there any other options?

> +#define buffersize	0	/* b’000’- 4K entries * 64 per entry =
> 256K buffersize */

I feel this should be documented somewhere in the device tree details
for the trace nodes.

Indeed, I see that documentation missing from doc/device-tree/imc.rst -
can you please add it?

> +
>  /*
>   * Nest IMC PMU names along with their bit values as represented in the
>   * imc_chip_avl_vector(in struct imc_chip_cb, look at include/imc.h).
> @@ -264,6 +273,8 @@ static int get_imc_device_type(struct dt_node *node)
>  		return IMC_COUNTER_CORE;
>  	case IMC_COUNTER_THREAD:
>  		return IMC_COUNTER_THREAD;
> +	case IMC_COUNTER_TRACE:
> +		return IMC_COUNTER_TRACE;
>  	default:
>  		break;
>  	}
> @@ -283,11 +294,23 @@ static bool is_nest_node(struct dt_node *node)
>  static bool is_imc_device_type_supported(struct dt_node *node)
>  {
>  	u32 val = get_imc_device_type(node);
> +	struct proc_chip *chip = get_chip(this_cpu()->chip_id);
> +	uint64_t pvr;
>
>  	if ((val == IMC_COUNTER_CHIP) || (val == IMC_COUNTER_CORE) ||
>  						(val == IMC_COUNTER_THREAD))
>  		return true;
>
> +	if (val == IMC_COUNTER_TRACE) {
> +		pvr = mfspr(SPR_PVR);
> +		/*
> +		 * Trace mode is supported in Nimbus DD2.2
> +		 * and later versions.
> +		 */
> +		if ((chip->type == PROC_CHIP_P9_NIMBUS) &&
> +			(PVR_VERS_MAJ(pvr) == 2) && (PVR_VERS_MIN(pvr) >= 2))
> +			return true;
> +	}
>  	return false;

What about Cumulus? Or do we just not know currently?

>  }
>
> @@ -644,6 +667,8 @@ static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr, uint64_t cpu
>  	int port_id, phys_core_id;
>  	int ret;
>  	uint32_t scoms;
> +	uint64_t trace_scom_val = TRACE_IMC_SCOM(samplesel, cpmcload,
> +					    cpmc1sel, cpmc2sel, buffersize);
>
>  	switch (type) {
>  	case OPAL_IMC_COUNTERS_NEST:
> @@ -738,6 +763,53 @@ static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr, uint64_t cpu
>  			return OPAL_HARDWARE;
>  		}
>  		return OPAL_SUCCESS;
> +	case OPAL_IMC_COUNTERS_TRACE:
> +		if (!c)
> +			return OPAL_PARAMETER;
> +
> +		phys_core_id = cpu_get_core_index(c);
> +		port_id = phys_core_id % 4;
> +
> +		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
> +			return OPAL_SUCCESS;
> +
> +		if (has_deep_states) {
> +			if (wakeup_engine_state == WAKEUP_ENGINE_PRESENT) {
> +				struct proc_chip *chip = get_chip(c->chip_id);
> +
> +				prlog(PR_INFO, "Configuring stopapi for
>  	IMC trace-mode\n");

should probably be PR_DEBUG.

> +				scoms = XSCOM_ADDR_P9_EC(phys_core_id, TRACE_IMC_ADDR);
> +				ret = p9_stop_save_scom((void *)chip->homer_base, scoms,
> +					trace_scom_val,
> +					P9_STOP_SCOM_REPLACE,
> +					P9_STOP_SECTION_CORE_SCOM);
> +				if (ret) {
> +					prerror("IMC trace_mode stopapi ret = %d, scoms = %x (core id = %x)\n", ret, scoms, phys_core_id);
> +					if (ret != STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED)
> +						wakeup_engine_state = WAKEUP_ENGINE_FAILED;
> +					else
> +						prerror("SCOM entries are full\n");
> +					return OPAL_HARDWARE;
> +				}

getting longer than 80 columns here, maybe split up the trace init into its own function?

> +			} else {
> +				prerror("IMC: TRACE:  Wakeup engine in error state!");
> +				return OPAL_HARDWARE;

This error isn't strictly true, we have WAKEUP_ENGINE_(NOT_PRESENT|PRESENT|FAILED).

> +			}
> +		}
> +		if (xscom_write(c->chip_id,
> +			XSCOM_ADDR_P9_EP(phys_core_id, htm_scom_index[port_id]),
> +					(u64)CORE_IMC_HTM_MODE_DISABLE)) {
> +				prerror("IMC: error in xscom_write for htm mode\n");
> +				return OPAL_HARDWARE;
> +		}
> +		if (xscom_write(c->chip_id,
> +			XSCOM_ADDR_P9_EC(phys_core_id,
> +					TRACE_IMC_ADDR), trace_scom_val)) {
> +			prerror("IMC: error in xscom_write for trace mode\n");
> +			return OPAL_HARDWARE;
> +		}
> +		return OPAL_SUCCESS;
> +
>  	}
>
>  	return OPAL_SUCCESS;
> @@ -797,6 +869,21 @@ static int64_t opal_imc_counters_start(uint32_t type, uint64_t cpu_pir)
>  			return OPAL_HARDWARE;
>  		}
>
> +		return OPAL_SUCCESS;
> +	case OPAL_IMC_COUNTERS_TRACE:
> +		phys_core_id = cpu_get_core_index(c);
> +		port_id = phys_core_id % 4;
> +
> +		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
> +			return OPAL_SUCCESS;
> +
> +		if (xscom_write(c->chip_id,
> +				XSCOM_ADDR_P9_EP(phys_core_id,
> +						 htm_scom_index[port_id]),
> +				(u64)CORE_IMC_HTM_MODE_ENABLE)) {
> +			prerror("IMC OPAL_start: error in xscom_write for htm_mode\n");
> +			return OPAL_HARDWARE;
> +		}

Should we also return OPAL_PARAMETER if start is called on a CPU
revision that doesn't support it?

>  		return OPAL_SUCCESS;
>  	}
>
> @@ -857,6 +944,22 @@ static int64_t opal_imc_counters_stop(uint32_t type, uint64_t cpu_pir)
>  		}
>
>  		return OPAL_SUCCESS;
> +	case OPAL_IMC_COUNTERS_TRACE:
> +		phys_core_id = cpu_get_core_index(c);
> +		port_id = phys_core_id % 4;
> +
> +		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
> +			return OPAL_SUCCESS;
> +
> +		if (xscom_write(c->chip_id,
> +				XSCOM_ADDR_P9_EP(phys_core_id,
> +						htm_scom_index[port_id]),
> +				(u64)CORE_IMC_HTM_MODE_DISABLE)) {
> +			prerror("IMC: error in xscom_write for htm_mode\n");
> +			return OPAL_HARDWARE;
> +		}
> +		return OPAL_SUCCESS;
> +
>  	}
>
>  	return OPAL_SUCCESS;
> -- 
> 2.17.1
>
Anju T Sudhakar March 11, 2019, 5:36 a.m. UTC | #2
Hi,

Thank you for reviewing the patch.

On 2/25/19 11:07 AM, Stewart Smith wrote:
> Anju T Sudhakar<anju@linux.vnet.ibm.com>  writes:
>> Patch to enhance the imc opal call to support and handle trace_imc mode.
>>
>> To initialize the trace-mode, TRACE_IMC_SCOM value is written to
>> TRACE_IMC_ADDR of the respective core.
>>
>> TRACE_IMC_SCOM is a 64bit value, and each bit represent the following:
>> 0:1       : SAMPSEL
>> 2:33      : CPMC_LOAD
>> 34:40     : CPMC1SEL
>> 41:47     : CPMC2SEL
>> 48:50     : BUFFERSIZE
>> 51:63      : RESERVED
>> For the nonce the value for TRACE_IMC_SCOM is hard coded.
> nonce?
>
> Do you mean we initialize the trace to a default value?


yes. Right now we initialize this to a default value.


>> During initialization htm_mode is disabled, and enabled only at start.
>>
>> The opal calls to start/stop the counters, will write CORE_IMC_HTM_MODE_ENABLE/
>> CORE_IMC_HTM_MODE_DISABLE respectively to the htm_scom_index of the desired
>> cores.
>>
>> Additional switch cases are added to the current opal calls to start/stop
>> the counters for trace-mode.
>>
>> Signed-off-by: Anju T Sudhakar<anju@linux.vnet.ibm.com>
>> Reviewed-by: Madhavan Srinivasan<maddy@linux.vnet.ibm.com>
>> Cc: Akshay Adiga<akshay.adiga@linux.vnet.ibm.com>
>> ---
>>   hw/imc.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 103 insertions(+)
>>
>> diff --git a/hw/imc.c b/hw/imc.c
>> index 3392eaf1..40c64d58 100644
>> --- a/hw/imc.c
>> +++ b/hw/imc.c
>> @@ -22,6 +22,15 @@
>>   #include <device.h>
>>   #include <p9_stop_api.H>
>>
>> +/*
>> + * IMC trace scom values
>> + */
> for these defines, please have them CAPITALIZED so we know they're
> #define and not variables, and also please prefix with something IMC related.


Sure, will do.

>> +#define samplesel	1	/* select cpmc2 */
>> +#define cpmcload	0xfa	/* Value to be loaded into cpmc2 at sampling start */
>> +#define cpmc1sel	2	/* Event: CPM_CCYC */
>> +#define cpmc2sel	2	/* Event: CPM_32MHZ_CYC */
> What do these two things mean? Are there any other options?
>> +#define buffersize	0	/* b’000’- 4K entries * 64 per entry =
>> 256K buffersize */
> I feel this should be documented somewhere in the device tree details
> for the trace nodes.
>
> Indeed, I see that documentation missing from doc/device-tree/imc.rst -
> can you please add it?


Sure, I will document this.

>> +
>>   /*
>>    * Nest IMC PMU names along with their bit values as represented in the
>>    * imc_chip_avl_vector(in struct imc_chip_cb, look at include/imc.h).
>> @@ -264,6 +273,8 @@ static int get_imc_device_type(struct dt_node *node)
>>   		return IMC_COUNTER_CORE;
>>   	case IMC_COUNTER_THREAD:
>>   		return IMC_COUNTER_THREAD;
>> +	case IMC_COUNTER_TRACE:
>> +		return IMC_COUNTER_TRACE;
>>   	default:
>>   		break;
>>   	}
>> @@ -283,11 +294,23 @@ static bool is_nest_node(struct dt_node *node)
>>   static bool is_imc_device_type_supported(struct dt_node *node)
>>   {
>>   	u32 val = get_imc_device_type(node);
>> +	struct proc_chip *chip = get_chip(this_cpu()->chip_id);
>> +	uint64_t pvr;
>>
>>   	if ((val == IMC_COUNTER_CHIP) || (val == IMC_COUNTER_CORE) ||
>>   						(val == IMC_COUNTER_THREAD))
>>   		return true;
>>
>> +	if (val == IMC_COUNTER_TRACE) {
>> +		pvr = mfspr(SPR_PVR);
>> +		/*
>> +		 * Trace mode is supported in Nimbus DD2.2
>> +		 * and later versions.
>> +		 */
>> +		if ((chip->type == PROC_CHIP_P9_NIMBUS) &&
>> +			(PVR_VERS_MAJ(pvr) == 2) && (PVR_VERS_MIN(pvr) >= 2))
>> +			return true;
>> +	}
>>   	return false;
> What about Cumulus? Or do we just not know currently?
>
IIUC Cumulus is powervm, so we don't support this.


>>   }
>>
>> @@ -644,6 +667,8 @@ static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr, uint64_t cpu
>>   	int port_id, phys_core_id;
>>   	int ret;
>>   	uint32_t scoms;
>> +	uint64_t trace_scom_val = TRACE_IMC_SCOM(samplesel, cpmcload,
>> +					    cpmc1sel, cpmc2sel, buffersize);
>>
>>   	switch (type) {
>>   	case OPAL_IMC_COUNTERS_NEST:
>> @@ -738,6 +763,53 @@ static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr, uint64_t cpu
>>   			return OPAL_HARDWARE;
>>   		}
>>   		return OPAL_SUCCESS;
>> +	case OPAL_IMC_COUNTERS_TRACE:
>> +		if (!c)
>> +			return OPAL_PARAMETER;
>> +
>> +		phys_core_id = cpu_get_core_index(c);
>> +		port_id = phys_core_id % 4;
>> +
>> +		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
>> +			return OPAL_SUCCESS;
>> +
>> +		if (has_deep_states) {
>> +			if (wakeup_engine_state == WAKEUP_ENGINE_PRESENT) {
>> +				struct proc_chip *chip = get_chip(c->chip_id);
>> +
>> +				prlog(PR_INFO, "Configuring stopapi for
>>   	IMC trace-mode\n");
> should probably be PR_DEBUG.


OK.

>> +				scoms = XSCOM_ADDR_P9_EC(phys_core_id, TRACE_IMC_ADDR);
>> +				ret = p9_stop_save_scom((void *)chip->homer_base, scoms,
>> +					trace_scom_val,
>> +					P9_STOP_SCOM_REPLACE,
>> +					P9_STOP_SECTION_CORE_SCOM);
>> +				if (ret) {
>> +					prerror("IMC trace_mode stopapi ret = %d, scoms = %x (core id = %x)\n", ret, scoms, phys_core_id);
>> +					if (ret != STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED)
>> +						wakeup_engine_state = WAKEUP_ENGINE_FAILED;
>> +					else
>> +						prerror("SCOM entries are full\n");
>> +					return OPAL_HARDWARE;
>> +				}
> getting longer than 80 columns here, maybe split up the trace init into its own function?
>
>> +			} else {
>> +				prerror("IMC: TRACE:  Wakeup engine in error state!");
>> +				return OPAL_HARDWARE;
> This error isn't strictly true, we have WAKEUP_ENGINE_(NOT_PRESENT|PRESENT|FAILED).


ok. I will change the error message here to something say 'Wakeup engine 
not present', is that sounds good?

>> +			}
>> +		}
>> +		if (xscom_write(c->chip_id,
>> +			XSCOM_ADDR_P9_EP(phys_core_id, htm_scom_index[port_id]),
>> +					(u64)CORE_IMC_HTM_MODE_DISABLE)) {
>> +				prerror("IMC: error in xscom_write for htm mode\n");
>> +				return OPAL_HARDWARE;
>> +		}
>> +		if (xscom_write(c->chip_id,
>> +			XSCOM_ADDR_P9_EC(phys_core_id,
>> +					TRACE_IMC_ADDR), trace_scom_val)) {
>> +			prerror("IMC: error in xscom_write for trace mode\n");
>> +			return OPAL_HARDWARE;
>> +		}
>> +		return OPAL_SUCCESS;
>> +
>>   	}
>>
>>   	return OPAL_SUCCESS;
>> @@ -797,6 +869,21 @@ static int64_t opal_imc_counters_start(uint32_t type, uint64_t cpu_pir)
>>   			return OPAL_HARDWARE;
>>   		}
>>
>> +		return OPAL_SUCCESS;
>> +	case OPAL_IMC_COUNTERS_TRACE:
>> +		phys_core_id = cpu_get_core_index(c);
>> +		port_id = phys_core_id % 4;
>> +
>> +		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
>> +			return OPAL_SUCCESS;
>> +
>> +		if (xscom_write(c->chip_id,
>> +				XSCOM_ADDR_P9_EP(phys_core_id,
>> +						 htm_scom_index[port_id]),
>> +				(u64)CORE_IMC_HTM_MODE_ENABLE)) {
>> +			prerror("IMC OPAL_start: error in xscom_write for htm_mode\n");
>> +			return OPAL_HARDWARE;
>> +		}
> Should we also return OPAL_PARAMETER if start is called on a CPU
> revision that doesn't support it?


Do we really need this? Because is_imc_device_type_supported() function 
verifies the cpu version

before adding the trace node to the device tree.


>
>>   		return OPAL_SUCCESS;
>>   	}
>>
>> @@ -857,6 +944,22 @@ static int64_t opal_imc_counters_stop(uint32_t type, uint64_t cpu_pir)
>>   		}
>>
>>   		return OPAL_SUCCESS;
>> +	case OPAL_IMC_COUNTERS_TRACE:
>> +		phys_core_id = cpu_get_core_index(c);
>> +		port_id = phys_core_id % 4;
>> +
>> +		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
>> +			return OPAL_SUCCESS;
>> +
>> +		if (xscom_write(c->chip_id,
>> +				XSCOM_ADDR_P9_EP(phys_core_id,
>> +						htm_scom_index[port_id]),
>> +				(u64)CORE_IMC_HTM_MODE_DISABLE)) {
>> +			prerror("IMC: error in xscom_write for htm_mode\n");
>> +			return OPAL_HARDWARE;
>> +		}
>> +		return OPAL_SUCCESS;
>> +
>>   	}
>>
>>   	return OPAL_SUCCESS;
>> -- 
>> 2.17.1
>>
diff mbox series

Patch

diff --git a/hw/imc.c b/hw/imc.c
index 3392eaf1..40c64d58 100644
--- a/hw/imc.c
+++ b/hw/imc.c
@@ -22,6 +22,15 @@ 
 #include <device.h>
 #include <p9_stop_api.H>
 
+/*
+ * IMC trace scom values
+ */
+#define samplesel	1	/* select cpmc2 */
+#define cpmcload	0xfa	/* Value to be loaded into cpmc2 at sampling start */
+#define cpmc1sel	2	/* Event: CPM_CCYC */
+#define cpmc2sel	2	/* Event: CPM_32MHZ_CYC */
+#define buffersize	0	/* b’000’- 4K entries * 64 per entry = 256K buffersize */
+
 /*
  * Nest IMC PMU names along with their bit values as represented in the
  * imc_chip_avl_vector(in struct imc_chip_cb, look at include/imc.h).
@@ -264,6 +273,8 @@  static int get_imc_device_type(struct dt_node *node)
 		return IMC_COUNTER_CORE;
 	case IMC_COUNTER_THREAD:
 		return IMC_COUNTER_THREAD;
+	case IMC_COUNTER_TRACE:
+		return IMC_COUNTER_TRACE;
 	default:
 		break;
 	}
@@ -283,11 +294,23 @@  static bool is_nest_node(struct dt_node *node)
 static bool is_imc_device_type_supported(struct dt_node *node)
 {
 	u32 val = get_imc_device_type(node);
+	struct proc_chip *chip = get_chip(this_cpu()->chip_id);
+	uint64_t pvr;
 
 	if ((val == IMC_COUNTER_CHIP) || (val == IMC_COUNTER_CORE) ||
 						(val == IMC_COUNTER_THREAD))
 		return true;
 
+	if (val == IMC_COUNTER_TRACE) {
+		pvr = mfspr(SPR_PVR);
+		/*
+		 * Trace mode is supported in Nimbus DD2.2
+		 * and later versions.
+		 */
+		if ((chip->type == PROC_CHIP_P9_NIMBUS) &&
+			(PVR_VERS_MAJ(pvr) == 2) && (PVR_VERS_MIN(pvr) >= 2))
+			return true;
+	}
 	return false;
 }
 
@@ -644,6 +667,8 @@  static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr, uint64_t cpu
 	int port_id, phys_core_id;
 	int ret;
 	uint32_t scoms;
+	uint64_t trace_scom_val = TRACE_IMC_SCOM(samplesel, cpmcload,
+					    cpmc1sel, cpmc2sel, buffersize);
 
 	switch (type) {
 	case OPAL_IMC_COUNTERS_NEST:
@@ -738,6 +763,53 @@  static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr, uint64_t cpu
 			return OPAL_HARDWARE;
 		}
 		return OPAL_SUCCESS;
+	case OPAL_IMC_COUNTERS_TRACE:
+		if (!c)
+			return OPAL_PARAMETER;
+
+		phys_core_id = cpu_get_core_index(c);
+		port_id = phys_core_id % 4;
+
+		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
+			return OPAL_SUCCESS;
+
+		if (has_deep_states) {
+			if (wakeup_engine_state == WAKEUP_ENGINE_PRESENT) {
+				struct proc_chip *chip = get_chip(c->chip_id);
+
+				prlog(PR_INFO, "Configuring stopapi for IMC trace-mode\n");
+				scoms = XSCOM_ADDR_P9_EC(phys_core_id, TRACE_IMC_ADDR);
+				ret = p9_stop_save_scom((void *)chip->homer_base, scoms,
+					trace_scom_val,
+					P9_STOP_SCOM_REPLACE,
+					P9_STOP_SECTION_CORE_SCOM);
+				if (ret) {
+					prerror("IMC trace_mode stopapi ret = %d, scoms = %x (core id = %x)\n", ret, scoms, phys_core_id);
+					if (ret != STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED)
+						wakeup_engine_state = WAKEUP_ENGINE_FAILED;
+					else
+						prerror("SCOM entries are full\n");
+					return OPAL_HARDWARE;
+				}
+			} else {
+				prerror("IMC: TRACE:  Wakeup engine in error state!");
+				return OPAL_HARDWARE;
+			}
+		}
+		if (xscom_write(c->chip_id,
+			XSCOM_ADDR_P9_EP(phys_core_id, htm_scom_index[port_id]),
+					(u64)CORE_IMC_HTM_MODE_DISABLE)) {
+				prerror("IMC: error in xscom_write for htm mode\n");
+				return OPAL_HARDWARE;
+		}
+		if (xscom_write(c->chip_id,
+			XSCOM_ADDR_P9_EC(phys_core_id,
+					TRACE_IMC_ADDR), trace_scom_val)) {
+			prerror("IMC: error in xscom_write for trace mode\n");
+			return OPAL_HARDWARE;
+		}
+		return OPAL_SUCCESS;
+
 	}
 
 	return OPAL_SUCCESS;
@@ -797,6 +869,21 @@  static int64_t opal_imc_counters_start(uint32_t type, uint64_t cpu_pir)
 			return OPAL_HARDWARE;
 		}
 
+		return OPAL_SUCCESS;
+	case OPAL_IMC_COUNTERS_TRACE:
+		phys_core_id = cpu_get_core_index(c);
+		port_id = phys_core_id % 4;
+
+		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
+			return OPAL_SUCCESS;
+
+		if (xscom_write(c->chip_id,
+				XSCOM_ADDR_P9_EP(phys_core_id,
+						 htm_scom_index[port_id]),
+				(u64)CORE_IMC_HTM_MODE_ENABLE)) {
+			prerror("IMC OPAL_start: error in xscom_write for htm_mode\n");
+			return OPAL_HARDWARE;
+		}
 		return OPAL_SUCCESS;
 	}
 
@@ -857,6 +944,22 @@  static int64_t opal_imc_counters_stop(uint32_t type, uint64_t cpu_pir)
 		}
 
 		return OPAL_SUCCESS;
+	case OPAL_IMC_COUNTERS_TRACE:
+		phys_core_id = cpu_get_core_index(c);
+		port_id = phys_core_id % 4;
+
+		if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS)
+			return OPAL_SUCCESS;
+
+		if (xscom_write(c->chip_id,
+				XSCOM_ADDR_P9_EP(phys_core_id,
+						htm_scom_index[port_id]),
+				(u64)CORE_IMC_HTM_MODE_DISABLE)) {
+			prerror("IMC: error in xscom_write for htm_mode\n");
+			return OPAL_HARDWARE;
+		}
+		return OPAL_SUCCESS;
+
 	}
 
 	return OPAL_SUCCESS;