diff options
author | Anju T Sudhakar <anju@linux.vnet.ibm.com> | 2017-06-22 17:45:22 +0530 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2017-06-27 18:45:30 +1000 |
commit | 7801be0fcf2a2dc306f611934e5559a5218f6a87 (patch) | |
tree | b6c924dade5b4c89b4098ef8209d1cc2d9887502 /hw | |
parent | f98d59958db19f85154dfa36db8f5c7322148294 (diff) | |
download | skiboot-7801be0fcf2a2dc306f611934e5559a5218f6a87.zip skiboot-7801be0fcf2a2dc306f611934e5559a5218f6a87.tar.gz skiboot-7801be0fcf2a2dc306f611934e5559a5218f6a87.tar.bz2 |
skiboot: Add opal calls to init/start/stop IMC devices
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.
Acked-by: Michael Neuling <mikey@neuling.org>
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>
[stewart@linux.vnet.ibm.com: use pr_fmt rather than hardcode IMC prefix]
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/imc.c | 193 |
1 files changed, 193 insertions, 0 deletions
@@ -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); @@ -434,3 +454,176 @@ 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); + 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; + + /* + * 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(c->chip_id, + XSCOM_ADDR_P9_EP(phys_core_id, + pdbar_scom_index[port_id]), + (u64)(CORE_IMC_PDBAR_MASK & addr))) { + prerror("error in xscom_write for pdbar\n"); + return OPAL_HARDWARE; + } + + if (xscom_write(c->chip_id, + XSCOM_ADDR_P9_EC(phys_core_id, + CORE_IMC_EVENT_MASK_ADDR), + (u64)CORE_IMC_EVENT_MASK)) { + prerror("error in xscom_write for event mask\n"); + 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("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; + int port_id, phys_core_id; + + if (!c) + return OPAL_PARAMETER; + + switch (type) { + case OPAL_IMC_COUNTERS_NEST: + /* Fetch the IMC control block structure */ + cb = get_imc_cb(c->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(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; + } + + 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); + int port_id, phys_core_id; + + if (!c) + return OPAL_PARAMETER; + + switch (type) { + case OPAL_IMC_COUNTERS_NEST: + /* Fetch the IMC control block structure */ + cb = get_imc_cb(c->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(c->chip_id, + XSCOM_ADDR_P9_EP(phys_core_id, + htm_scom_index[port_id]), + (u64) CORE_IMC_HTM_MODE_DISABLE)) { + prerror("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); |