Message ID | 1497789339-28819-9-git-send-email-maddy@linux.vnet.ibm.com |
---|---|
State | Superseded |
Headers | show |
On Sunday 18 June 2017 06:05 PM, Madhavan Srinivasan wrote: > From: Anju T Sudhakar <anju@linux.vnet.ibm.com> > > Add new opal calls to init, start and stop the IMC nest/core units. > To initialize the core IMC counters, it takes a physical address per > core as an input and writes that address to PDBAR[14:50] bits. > It initializes the htm_mode and event_mask, 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/enable the nest IMC counters (stop or resume counting), > writes into "command" field of the nest control block in the reserve > memory location. To disable/enable the core IMC counters (stop or > resume counting), writes into appropriate bits of htm_mode to > disable the counters. > > Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com> > Signed-off-by: Anju T Sudhakar <anju@linux.vnet.ibm.com> > Signed-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com> > --- > hw/imc.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > include/imc.h | 9 +++ > include/opal-api.h | 12 +++- > 3 files changed, 228 insertions(+), 1 deletion(-) > > diff --git a/hw/imc.c b/hw/imc.c > index 696805ae23d2..48c940f7ee99 100644 > --- a/hw/imc.c > +++ b/hw/imc.c > @@ -94,6 +94,26 @@ static bool is_nest_mem_initialized(struct imc_chip_cb *ptr) > return true; > } > > +/* > + * A Quad contains 4 cores in Power 9, and there are 4 addresses for > + * the Core Hardware Trace Macro (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 Hardware Trace Macro (HTM) > + * mode and PDBAR. > + */ > +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(uint32_t chip_id) > { > struct proc_chip *chip = get_chip(chip_id); > @@ -427,3 +447,191 @@ err: > free(decompress_buf); > free(compress_buf); > } > + > +/* > + * opal_imc_counters_init : This call initialize the IMC engine. > + * > + * For Nest IMC, this is no-op and returns OPAL_SUCCESS at this point. > + * For Core IMC, this initializes core IMC Engine, by initializing > + * these scoms "PDBAR", "HTM_MODE" and the "EVENT_MASK" in a given cpu. > + */ > +static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr, uint64_t cpu_pir) > +{ > + struct cpu_thread *c = find_cpu_by_pir(cpu_pir); > + struct proc_chip *chip; > + int port_id, phys_core_id; > + > + switch (type) { > + case OPAL_IMC_COUNTERS_NEST: > + return OPAL_SUCCESS; > + case OPAL_IMC_COUNTERS_CORE: > + if (!c) > + return OPAL_PARAMETER; > + > + chip = get_chip(c->chip_id); Sorry posted wrong version of this patch. This should have been if (!chip). > + if (chip) > + return OPAL_PARAMETER; > + > + /* > + * Core IMC hardware mandates setting of htm_mode and > + * pdbar in specific scom ports. port_id are in > + * pdbar_scom_index[] and htm_scom_index[]. > + */ > + phys_core_id = cpu_get_core_index(c); > + port_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. > + */ > + if (xscom_write(chip->id, > + XSCOM_ADDR_P9_EP(phys_core_id, > + pdbar_scom_index[port_id]), > + (u64)(CORE_IMC_PDBAR_MASK & addr))) { > + prerror("IMC: error in xscom_write for pdbar\n"); > + return OPAL_HARDWARE; > + } > + > + if (xscom_write(chip->id, > + XSCOM_ADDR_P9_EC(phys_core_id, > + CORE_IMC_EVENT_MASK_ADDR), > + (u64)CORE_IMC_EVENT_MASK)) { > + prerror("IMC: error in xscom_write for event mask\n"); > + return OPAL_HARDWARE; > + } > + > + if (xscom_write(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; > +} > +opal_call(OPAL_IMC_COUNTERS_INIT, opal_imc_counters_init, 3); > + > +/* opal_imc_counters_control_start: This call starts the nest/core imc engine. */ > +static int64_t opal_imc_counters_start(uint32_t type, uint64_t cpu_pir) > +{ > + u64 op; > + struct cpu_thread *c = find_cpu_by_pir(cpu_pir); > + struct imc_chip_cb *cb; > + struct proc_chip *chip; > + int port_id, phys_core_id; > + > + if (!c) > + return OPAL_PARAMETER; > + > + chip = get_chip(c->chip_id); Once again, Sorry posted wrong version of this patch. This should have been if (!chip). > + if (chip) > + return OPAL_PARAMETER; > + > + switch (type) { > + case OPAL_IMC_COUNTERS_NEST: > + /* Fetch the IMC control block structure */ > + cb = get_imc_cb(chip->id); > + > + /* Set the run command */ > + op = NEST_IMC_ENABLE; > + > + /* Write the command to the control block now */ > + cb->imc_chip_command = cpu_to_be64(op); > + > + return OPAL_SUCCESS; > + case OPAL_IMC_COUNTERS_CORE: > + /* > + * Core IMC hardware mandates setting of htm_mode in specific > + * scom ports (port_id are in htm_scom_index[]) > + */ > + phys_core_id = cpu_get_core_index(c); > + port_id = phys_core_id % 4; > + > + /* > + * 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. > + */ > + if (xscom_write(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; > + } > + > + return OPAL_SUCCESS; > +} > +opal_call(OPAL_IMC_COUNTERS_START, opal_imc_counters_start, 2); > + > +/* opal_imc_counters_control_stop: This call stops the nest imc engine. */ > +static int64_t opal_imc_counters_stop(uint32_t type, uint64_t cpu_pir) > +{ > + u64 op; > + struct imc_chip_cb *cb; > + struct cpu_thread *c = find_cpu_by_pir(cpu_pir); > + struct proc_chip *chip; > + int port_id, phys_core_id; > + > + if (!c) > + return OPAL_PARAMETER; > + > + chip = get_chip(c->chip_id); Once again, Sorry posted wrong version of this patch. This should have been if (!chip). > + if (chip) > + return OPAL_PARAMETER; > + > + switch (type) { > + case OPAL_IMC_COUNTERS_NEST: > + /* Fetch the IMC control block structure */ > + cb = get_imc_cb(chip->id); > + > + /* Set the run command */ > + op = NEST_IMC_DISABLE; > + > + /* Write the command to the control block */ > + cb->imc_chip_command = cpu_to_be64(op); > + > + return OPAL_SUCCESS; > + > + case OPAL_IMC_COUNTERS_CORE: > + /* > + * Core IMC hardware mandates setting of htm_mode in specific > + * scom ports (port_id are in htm_scom_index[]) > + */ > + phys_core_id = cpu_get_core_index(c); > + port_id = phys_core_id % 4; > + > + /* > + * Disables the core imc engine by clearing > + * bits 4-9 of the HTM_MODE scom port. > + */ > + if (xscom_write(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; > +} > +opal_call(OPAL_IMC_COUNTERS_STOP, opal_imc_counters_stop, 2); > diff --git a/include/imc.h b/include/imc.h > index fcd220d1b316..d4381bb2adae 100644 > --- a/include/imc.h > +++ b/include/imc.h > @@ -121,6 +121,15 @@ struct imc_chip_cb > > #define MAX_NEST_UNITS 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_HTM_MODE_ENABLE 0xE800000000000000ull > +#define CORE_IMC_HTM_MODE_DISABLE 0xE000000000000000ull > + > void imc_init(void); > void imc_catalog_preload(void); > #endif /* __IMC_H */ > diff --git a/include/opal-api.h b/include/opal-api.h > index 80033c6fa77f..6497c94cd46a 100644 > --- a/include/opal-api.h > +++ b/include/opal-api.h > @@ -204,7 +204,10 @@ > #define OPAL_NPU_INIT_CONTEXT 146 > #define OPAL_NPU_DESTROY_CONTEXT 147 > #define OPAL_NPU_MAP_LPAR 148 > -#define OPAL_LAST 148 > +#define OPAL_IMC_COUNTERS_INIT 149 > +#define OPAL_IMC_COUNTERS_START 150 > +#define OPAL_IMC_COUNTERS_STOP 151 > +#define OPAL_LAST 151 > > /* Device tree flags */ > > @@ -1215,6 +1218,13 @@ enum { > XIVE_DUMP_EMU_STATE = 5, > }; > > +/* Operation argument to IMC Microcode */ > +enum { > + OPAL_IMC_COUNTERS_NEST = 1, > + OPAL_IMC_COUNTERS_CORE = 2, > +}; > + > + > #endif /* __ASSEMBLY__ */ > > #endif /* __OPAL_API_H */
diff --git a/hw/imc.c b/hw/imc.c index 696805ae23d2..48c940f7ee99 100644 --- a/hw/imc.c +++ b/hw/imc.c @@ -94,6 +94,26 @@ static bool is_nest_mem_initialized(struct imc_chip_cb *ptr) return true; } +/* + * A Quad contains 4 cores in Power 9, and there are 4 addresses for + * the Core Hardware Trace Macro (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 Hardware Trace Macro (HTM) + * mode and PDBAR. + */ +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(uint32_t chip_id) { struct proc_chip *chip = get_chip(chip_id); @@ -427,3 +447,191 @@ err: free(decompress_buf); free(compress_buf); } + +/* + * opal_imc_counters_init : This call initialize the IMC engine. + * + * For Nest IMC, this is no-op and returns OPAL_SUCCESS at this point. + * For Core IMC, this initializes core IMC Engine, by initializing + * these scoms "PDBAR", "HTM_MODE" and the "EVENT_MASK" in a given cpu. + */ +static int64_t opal_imc_counters_init(uint32_t type, uint64_t addr, uint64_t cpu_pir) +{ + struct cpu_thread *c = find_cpu_by_pir(cpu_pir); + struct proc_chip *chip; + int port_id, phys_core_id; + + switch (type) { + case OPAL_IMC_COUNTERS_NEST: + return OPAL_SUCCESS; + case OPAL_IMC_COUNTERS_CORE: + if (!c) + return OPAL_PARAMETER; + + chip = get_chip(c->chip_id); + if (chip) + return OPAL_PARAMETER; + + /* + * Core IMC hardware mandates setting of htm_mode and + * pdbar in specific scom ports. port_id are in + * pdbar_scom_index[] and htm_scom_index[]. + */ + phys_core_id = cpu_get_core_index(c); + port_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. + */ + if (xscom_write(chip->id, + XSCOM_ADDR_P9_EP(phys_core_id, + pdbar_scom_index[port_id]), + (u64)(CORE_IMC_PDBAR_MASK & addr))) { + prerror("IMC: error in xscom_write for pdbar\n"); + return OPAL_HARDWARE; + } + + if (xscom_write(chip->id, + XSCOM_ADDR_P9_EC(phys_core_id, + CORE_IMC_EVENT_MASK_ADDR), + (u64)CORE_IMC_EVENT_MASK)) { + prerror("IMC: error in xscom_write for event mask\n"); + return OPAL_HARDWARE; + } + + if (xscom_write(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; +} +opal_call(OPAL_IMC_COUNTERS_INIT, opal_imc_counters_init, 3); + +/* opal_imc_counters_control_start: This call starts the nest/core imc engine. */ +static int64_t opal_imc_counters_start(uint32_t type, uint64_t cpu_pir) +{ + u64 op; + struct cpu_thread *c = find_cpu_by_pir(cpu_pir); + struct imc_chip_cb *cb; + struct proc_chip *chip; + int port_id, phys_core_id; + + if (!c) + return OPAL_PARAMETER; + + chip = get_chip(c->chip_id); + if (chip) + return OPAL_PARAMETER; + + switch (type) { + case OPAL_IMC_COUNTERS_NEST: + /* Fetch the IMC control block structure */ + cb = get_imc_cb(chip->id); + + /* Set the run command */ + op = NEST_IMC_ENABLE; + + /* Write the command to the control block now */ + cb->imc_chip_command = cpu_to_be64(op); + + return OPAL_SUCCESS; + case OPAL_IMC_COUNTERS_CORE: + /* + * Core IMC hardware mandates setting of htm_mode in specific + * scom ports (port_id are in htm_scom_index[]) + */ + phys_core_id = cpu_get_core_index(c); + port_id = phys_core_id % 4; + + /* + * 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. + */ + if (xscom_write(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; + } + + return OPAL_SUCCESS; +} +opal_call(OPAL_IMC_COUNTERS_START, opal_imc_counters_start, 2); + +/* opal_imc_counters_control_stop: This call stops the nest imc engine. */ +static int64_t opal_imc_counters_stop(uint32_t type, uint64_t cpu_pir) +{ + u64 op; + struct imc_chip_cb *cb; + struct cpu_thread *c = find_cpu_by_pir(cpu_pir); + struct proc_chip *chip; + int port_id, phys_core_id; + + if (!c) + return OPAL_PARAMETER; + + chip = get_chip(c->chip_id); + if (chip) + return OPAL_PARAMETER; + + switch (type) { + case OPAL_IMC_COUNTERS_NEST: + /* Fetch the IMC control block structure */ + cb = get_imc_cb(chip->id); + + /* Set the run command */ + op = NEST_IMC_DISABLE; + + /* Write the command to the control block */ + cb->imc_chip_command = cpu_to_be64(op); + + return OPAL_SUCCESS; + + case OPAL_IMC_COUNTERS_CORE: + /* + * Core IMC hardware mandates setting of htm_mode in specific + * scom ports (port_id are in htm_scom_index[]) + */ + phys_core_id = cpu_get_core_index(c); + port_id = phys_core_id % 4; + + /* + * Disables the core imc engine by clearing + * bits 4-9 of the HTM_MODE scom port. + */ + if (xscom_write(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; +} +opal_call(OPAL_IMC_COUNTERS_STOP, opal_imc_counters_stop, 2); diff --git a/include/imc.h b/include/imc.h index fcd220d1b316..d4381bb2adae 100644 --- a/include/imc.h +++ b/include/imc.h @@ -121,6 +121,15 @@ struct imc_chip_cb #define MAX_NEST_UNITS 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_HTM_MODE_ENABLE 0xE800000000000000ull +#define CORE_IMC_HTM_MODE_DISABLE 0xE000000000000000ull + void imc_init(void); void imc_catalog_preload(void); #endif /* __IMC_H */ diff --git a/include/opal-api.h b/include/opal-api.h index 80033c6fa77f..6497c94cd46a 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -204,7 +204,10 @@ #define OPAL_NPU_INIT_CONTEXT 146 #define OPAL_NPU_DESTROY_CONTEXT 147 #define OPAL_NPU_MAP_LPAR 148 -#define OPAL_LAST 148 +#define OPAL_IMC_COUNTERS_INIT 149 +#define OPAL_IMC_COUNTERS_START 150 +#define OPAL_IMC_COUNTERS_STOP 151 +#define OPAL_LAST 151 /* Device tree flags */ @@ -1215,6 +1218,13 @@ enum { XIVE_DUMP_EMU_STATE = 5, }; +/* Operation argument to IMC Microcode */ +enum { + OPAL_IMC_COUNTERS_NEST = 1, + OPAL_IMC_COUNTERS_CORE = 2, +}; + + #endif /* __ASSEMBLY__ */ #endif /* __OPAL_API_H */