diff options
Diffstat (limited to 'src/occ_gpe1')
-rw-r--r-- | src/occ_gpe1/gpe1_main.c | 29 | ||||
-rw-r--r-- | src/occ_gpe1/gpe_centaur.c | 726 | ||||
-rw-r--r-- | src/occ_gpe1/gpe_centaur.h | 61 | ||||
-rw-r--r-- | src/occ_gpe1/gpe_centaur_configuration.c | 497 | ||||
-rw-r--r-- | src/occ_gpe1/gpe_centaur_scom.c | 762 | ||||
-rw-r--r-- | src/occ_gpe1/gpe_membuf.c | 147 | ||||
-rw-r--r-- | src/occ_gpe1/gpe_membuf.h | 177 | ||||
-rw-r--r-- | src/occ_gpe1/gpe_membuf_scom.c | 605 | ||||
-rw-r--r-- | src/occ_gpe1/gpe_ocmb.c | 630 | ||||
-rw-r--r-- | src/occ_gpe1/ipc_func_tables.c | 8 | ||||
-rw-r--r-- | src/occ_gpe1/link.cmd | 2 | ||||
-rw-r--r-- | src/occ_gpe1/occ_gpe1_machine_check_handler.c | 38 | ||||
-rw-r--r-- | src/occ_gpe1/topfiles.mk | 5 |
13 files changed, 2291 insertions, 1396 deletions
diff --git a/src/occ_gpe1/gpe1_main.c b/src/occ_gpe1/gpe1_main.c index 2385ac9..2115f39 100644 --- a/src/occ_gpe1/gpe1_main.c +++ b/src/occ_gpe1/gpe1_main.c @@ -33,7 +33,12 @@ #include "pk_trace.h" #include "ipc_api.h" #include "gpe_export.h" -#include "gpe_centaur.h" +#include "gpe_membuf.h" + +#if defined(__OCMB_UNIT_TEST__) +#include "membuf_structs.h" +#include "ocmb_mem_data.h" +#endif #define KERNEL_STACK_SIZE 1024 @@ -47,6 +52,18 @@ gpe_shared_data_t * G_gpe_shared_data = (gpe_shared_data_t*) GPE_SHARED_DATA_ADD extern PkTraceBuffer* g_pk_trace_buf_ptr; +#if defined(__OCMB_UNIT_TEST__) +MemBufGetMemDataParms_t G_dataParms; +MemBufConfiguration_t G_membufConfiguration; +OcmbMemData G_escache; + +extern MemBufConfiguration_t * G_membuf_config; + +int gpe_ocmb_configuration_create(MemBufConfiguration_t* o_config); +int get_ocmb_sensorcache(MemBufConfiguration_t* i_config, + MemBufGetMemDataParms_t* i_parms); +#endif + // The main function is called by the boot code (after initializing some // registers) int main(int argc, char **argv) @@ -87,7 +104,17 @@ int main(int argc, char **argv) PK_TRACE("ipc_enable failed with rc = 0x%08x", rc); pk_halt(); } +#if defined(__OCMB_UNIT_TEST__) + G_dataParms.error.rc = 0; + G_dataParms.collect = 0; + G_dataParms.update = -1; + G_dataParms.data = (uint64_t*)(&G_escache); + G_membuf_config = &G_membufConfiguration; + + rc = get_ocmb_sensorcache(&G_membufConfiguration, &G_dataParms); + PK_TRACE("get_ocmb_sensorcache rc = %x",rc); +#endif return 0; } diff --git a/src/occ_gpe1/gpe_centaur.c b/src/occ_gpe1/gpe_centaur.c index d492133..6c17878 100644 --- a/src/occ_gpe1/gpe_centaur.c +++ b/src/occ_gpe1/gpe_centaur.c @@ -1,102 +1,706 @@ -#include "gpe_centaur.h" -#include "ipc_async_cmd.h" -#include "gpe_util.h" +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/lib/pm/centaur_thermal_access.c $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @briefcentaur_thermal_access + */ -CentaurConfiguration_t * G_centaur_config = NULL; +#include "gpe_membuf.h" +#include "ppe42_scom.h" +#include "pk.h" +#include "p9_misc_scom_addresses.h" +#include "mcs_firmware_registers.h" +#include "pba_firmware_constants.h" +#include "pba_register_addresses.h" +#include "centaur_register_addresses.h" +#include "ppe42_msr.h" +#include "occhw_pba_common.h" -void gpe_centaur_init(ipc_msg_t* i_cmd, void* i_arg) +// Power Bus Address bit that configures centaur for HOST/OCC P9=bit(38) +#define PBA_HOST_OCC_CFG 0x0000000002000000ull; + + +const uint32_t MCFGPR[OCCHW_N_MEMBUF] = +{ + MCS_0_MCRSVDE, + MCS_0_MCRSVDF, + MCS_1_MCRSVDE, + MCS_1_MCRSVDF, + MCS_2_MCRSVDE, + MCS_2_MCRSVDF, + MCS_3_MCRSVDE, + MCS_3_MCRSVDF +}; + +const uint32_t MCSYNC[OCCHW_N_MEMBUF/2] = +{ + MCS_0_MCSYNC, + MCS_1_MCSYNC, + MCS_2_MCSYNC, + MCS_3_MCSYNC +}; + +const uint32_t MCCHIFIR[OCCHW_N_MEMBUF] = +{ + MCP_CHAN0_CHI_FIR, + MCP_CHAN1_CHI_FIR, + MCP_CHAN2_CHI_FIR, + MCP_CHAN3_CHI_FIR, + MCP_CHAN4_CHI_FIR, + MCP_CHAN5_CHI_FIR, + MCP_CHAN6_CHI_FIR, + MCP_CHAN7_CHI_FIR +}; + +const uint32_t MCMCICFG1Q[OCCHW_N_MEMBUF] = { - int rc; - ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)i_cmd; - CentaurConfigParms_t* payload = (CentaurConfigParms_t*)async_cmd->cmd_data; + MCP_CHAN0_CHI_MCICFG1Q, + MCP_CHAN1_CHI_MCICFG1Q, + MCP_CHAN2_CHI_MCICFG1Q, + MCP_CHAN3_CHI_MCICFG1Q, + MCP_CHAN4_CHI_MCICFG1Q, + MCP_CHAN5_CHI_MCICFG1Q, + MCP_CHAN6_CHI_MCICFG1Q, + MCP_CHAN7_CHI_MCICFG1Q +}; + +/////////////////////////////////////////////////////////////// +// These are PPE specific PBA routines. +////////////////////////////////////////////////////////////// +int +gpe_pba_parms_create(GpePbaParms* parms, + int slave, + int write_ttype, + int write_tsize, + int read_ttype) +{ + pba_slvctln_t* slvctl, *mask; + pba_slvrst_t* slvrst; + pba_slvrst_t* slvrst_in_progress; + uint64_t all1 = 0xffffffffffffffffull; + + parms->slave_id = slave; + + slvctl = &(parms->slvctl); + mask = &(parms->mask); + slvrst = &(parms->slvrst); + slvrst_in_progress = &(parms->slvrst_in_progress); + + parms->slvctl_address = PBA_SLVCTLN(slave); + + slvrst->value = 0; + slvrst->fields.set = PBA_SLVRST_SET(slave); + + slvrst_in_progress->value = 0; + slvrst_in_progress->fields.in_prog = PBA_SLVRST_IN_PROG(slave); + + slvctl->value = 0; + mask->value = 0; - CentaurConfiguration_t * config = payload->centaurConfiguration; - G_centaur_config = config; + slvctl->fields.enable = 1; + mask->fields.enable = all1; - payload->error.error = 0; - payload->error.ffdc = 0; + slvctl->fields.mid_match_value = OCI_MASTER_ID_GPE1; + mask->fields.mid_match_value = all1; - if(G_centaur_config == NULL) + slvctl->fields.mid_care_mask = all1; + mask->fields.mid_care_mask = all1; + + slvctl->fields.write_ttype = write_ttype; + mask->fields.write_ttype = all1; + + slvctl->fields.write_tsize = write_tsize; + mask->fields.write_tsize = all1; + + slvctl->fields.read_ttype = read_ttype; + mask->fields.read_ttype = all1; + + slvctl->fields.buf_alloc_a = 1; + slvctl->fields.buf_alloc_b = 1; + slvctl->fields.buf_alloc_c = 1; + slvctl->fields.buf_alloc_w = 1; + mask->fields.buf_alloc_a = 1; + mask->fields.buf_alloc_b = 1; + mask->fields.buf_alloc_c = 1; + mask->fields.buf_alloc_w = 1; + + if (read_ttype == PBA_READ_TTYPE_CI_PR_RD) { - PK_TRACE("gpe_centaur_init: centaurConfiguration data ptr is NULL!"); - rc = GPE_RC_CONFIG_DATA_NULL_PTR; + + slvctl->fields.buf_invalidate_ctl = 1; + mask->fields.buf_invalidate_ctl = all1; + + slvctl->fields.read_prefetch_ctl = PBA_READ_PREFETCH_NONE; + mask->fields.read_prefetch_ctl = all1; + } else { - PK_TRACE("Centaur_configuration. MSR:%08x",mfmsr()); - rc = gpe_centaur_configuration_create(G_centaur_config); + + slvctl->fields.buf_invalidate_ctl = 0; + mask->fields.buf_invalidate_ctl = all1; } - payload->error.rc = rc; + mask->value = ~(mask->value); + + return 0; +} + + +//////////////////////////////////////////////// +// Centaur specific routines +//////////////////////////////////////////////// +int gpe_centaur_configuration_create(MemBufConfiguration_t* o_config) +{ + int rc = 0; + unsigned int i = 0; + mcfgpr_t mcfgpr; + uint64_t* ptr = (uint64_t*)o_config; + int designated_sync = -1; + + // Prevent unwanted interrupts from scom errors + const uint32_t orig_msr = mfmsr(); + mtmsr((orig_msr & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM); - // Send response - rc = ipc_send_rsp(i_cmd, IPC_RC_SUCCESS); - if(rc) + for(i = 0; i < sizeof(MemBufConfiguration_t) / 8; ++i) { - PK_TRACE("gpe_centaur_init: Failed to send response. rc = %x. Halting GPE1.", - rc); + *ptr++ = 0ull; + } + + o_config->configRc = MEMBUF_NOT_CONFIGURED; + + do + { + // Create the PBASLV configurations for the GPE procedures. + // The 'dataParms' define the PBASLV setup needed to access the + // Centaur sensor cache. The 'scomParms' define the PBASLV setup + // needed to access the Centaur SCOMs. + + rc = gpe_pba_parms_create(&(o_config->dataParms), + PBA_SLAVE_MEMBUF, + PBA_WRITE_TTYPE_CI_PR_W, + PBA_WRITE_TTYPE_DC, + PBA_READ_TTYPE_CL_RD_NC); + + if (rc) + { + rc = MEMBUF_DATA_SETUP_ERROR; + break; + } + + rc = gpe_pba_parms_create(&(o_config->scomParms), + PBA_SLAVE_MEMBUF, + PBA_WRITE_TTYPE_CI_PR_W, + PBA_WRITE_TTYPE_DC, + PBA_READ_TTYPE_CI_PR_RD); + + if (rc) + { + rc = MEMBUF_SCOM_SETUP_ERROR; + break; + } + + // Iterate through each MCS on the chip and check configuration. + + // Note that the code uniformly treats SCOM failures of the MCFGPR + // registers as an unconfigured Centaur. This works both for real + // hardware, as well as for our VBU models where some of the "valid" + // MCS are not in the simulation models. + + for (i = 0; i < OCCHW_N_MEMBUF; ++i) + { + // check for channel checkstop + rc = check_centaur_channel_chkstp(i); + if (rc) + { + // If scom failed OR there is a channel checkstop then + // Centaur is not usable. + rc = 0; + continue; + } + + // Verify that inband scom has been setup. If not then + // assume the centaur is either non-existant or not configured. + // Setup is provided by HWP p9c_set_inband_addr.C + rc = getscom_abs(MCFGPR[i], &(mcfgpr.value)); + + if (rc) + { + // ignore if can't be scomed. + rc = 0; + continue; + } + + // If inband scom is not configured then assume the centaur does not exist + if (!mcfgpr.fields.mcfgprq_valid) + { + continue; + } + + + // The 31-bit base-address (inband scom BAR) corresponds to bits [8:38] in the + // 64-bit PowerBus address. + // Set the HOST/OCC bit in the address. + o_config->baseAddress[i] = + ((uint64_t)(mcfgpr.fields.mcfgprq_base_address) << 25) | PBA_HOST_OCC_CFG; + + PK_TRACE_DBG("Centar[%d] Base Address: %016llx",i,o_config->baseAddress[i]); + + // Add the Centaur to the configuration + o_config->config |= (CHIP_CONFIG_MCS(i) | CHIP_CONFIG_MEMBUF(i)); + } + + if (rc) + { + break; + } + + // Find the designated sync + for (i = 0; i < (OCCHW_N_MEMBUF/2); ++i) + { + uint64_t mcsync; + rc = getscom_abs(MCSYNC[i], &mcsync); + if (rc) + { + PK_TRACE("getscom failed on MCSYNC, rc = %d. The first configured MC will be" + " the designated sync",rc); + rc = 0; + } + if (mcsync != 0) + { + designated_sync = i; + // There can only be one sync, so stop searching. + break; + } + } + + if (designated_sync < 0) + { + designated_sync = cntlz32(o_config->config << CHIP_CONFIG_MCS_BASE); + PK_TRACE("No designated sync found, using MCS(%d)",designated_sync); + } + + o_config->mcSyncAddr = MCSYNC[designated_sync]; + + + rc = configure_pba_bar_for_inband_access(o_config); + if( rc ) + { + break; + } + // At this point the structure is initialized well-enough that it can + // be used by gpe_inband_scom(). + + + o_config->configRc = 0; + + if (o_config->config == 0) + { + break; + } + + + // Get Device ID from each centaur + membuf_get_scom_vector(o_config, + CENTAUR_DEVICE_ID, + (uint64_t*)(&(o_config->deviceId[0]))); - gpe_set_ffdc(&(payload->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); - pk_halt(); } + while(0); + + o_config->configRc = rc; + + mtmsr(orig_msr); + + return rc; } -void gpe_centaur_scom(ipc_msg_t* i_cmd, void* i_arg) +int configure_pba_bar_for_inband_access(MemBufConfiguration_t * i_config) { - static int g_log_once = 0; - int rc; - ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)i_cmd; - CentaurScomParms_t * scomParms = (CentaurScomParms_t*)async_cmd->cmd_data; + uint64_t bar = 0; + uint64_t barMsk = PBA_BARMSKN_MASK_MASK; + uint64_t mask = 0; + int i = 0; + int rc = 0; - if(g_log_once == 0) + do { - g_log_once = 1; - PK_TRACE("Centaur Scom. MSR:%08x",mfmsr()); - } - gpe_scom_centaur(G_centaur_config, scomParms); + // Configure the PBA BAR and PBA BARMSK. + // Set the BARMSK bits such that: + // -PBA[8:22] are provided by the PBABAR. + // -PBA[23:36] are provided by the PBASLVCTL ExtrAddr field + // -PBA[37:43] are provided by the OCI addr[5:11] + // PBA[44:63] will always come from the OCI addr[12:31] + // Note: This code should no longer be needed when the BAR/BARMSK is set + // by PHYP. + if (i_config->config != 0) + { + + for (i = 0; i < OCCHW_N_MEMBUF; ++i) + { + bar |= i_config->baseAddress[i]; + } + + bar &= ~barMsk; + + PK_TRACE_DBG("PBABAR(%d): %016llx", PBA_BAR_MEMBUF, bar); + PK_TRACE_DBG("PBABARMSK: %016llx", barMsk); + + rc = putscom_abs(PBA_BARMSKN(PBA_BAR_MEMBUF), barMsk); + + if (rc) + { + PK_TRACE_DBG("Unexpected rc = 0x%08x SCOMing PBA_BARMSKN(%d)\n", + (uint32_t)rc, PBA_BAR_MEMBUF); + rc = MEMBUF_BARMSKN_PUTSCOM_FAILURE; + break; + } + + rc = putscom_abs(PBA_BARN(PBA_BAR_MEMBUF), bar); + if (rc) + { + PK_TRACE_DBG("Unexpected rc = 0x%08x SCOMing PBA_BARN(%d)\n", + (uint32_t)rc, PBA_BAR_MEMBUF); + rc = MEMBUF_BARN_PUTSCOM_FAILURE; + break; + } + } + + // Do an independent check that every Centaur base address + // can be generated by the combination of the current BAR and + // BAR Mask, along with the initial requirement that the mask must + // include at least bits 38:43. + + if (i_config->config != 0) + { + rc = getscom_abs(PBA_BARN(PBA_BAR_MEMBUF), &bar); + + if (rc) + { + PK_TRACE_DBG("Unexpected rc = 0x%08x SCOMing PBA_BARN(%d)\n", + (uint32_t)rc, PBA_BAR_MEMBUF); + rc = MEMBUF_BARN_GETSCOM_FAILURE; + break; + } + + rc = getscom_abs(PBA_BARMSKN(PBA_BAR_MEMBUF), &mask); + + if (rc) + { + PK_TRACE_DBG("Unexpected rc = 0x%08x SCOMing PBA_BARMSKN(%d)\n", + (uint32_t)rc, PBA_BAR_MEMBUF); + rc = MEMBUF_BARMSKN_GETSCOM_FAILURE; + break; + } + + bar = bar & PBA_BARN_ADDR_MASK; + mask = mask & PBA_BARMSKN_MASK_MASK; + + if ((mask & 0x0000000003f00000ull) != 0x0000000003f00000ull) + { - // Send response - rc = ipc_send_rsp(i_cmd, IPC_RC_SUCCESS); - if(rc) + PK_TRACE("PBA BAR mask (%d) does not cover bits 38:43\n", PBA_BAR_MEMBUF); + rc = MEMBUF_MASK_ERROR; + break; + } + + for (i = 0; i < OCCHW_N_MEMBUF; ++i) + { + if (i_config->baseAddress[i] != 0) + { + if ((i_config->baseAddress[i] & ~mask) != + (bar & ~mask)) + { + + PK_TRACE("BAR/Mask (%d) error for MCS/Centaur %d", + PBA_BAR_MEMBUF, i); + + PK_TRACE(" base = 0x%08x%08x", + (uint32_t)(i_config->baseAddress[i]>>32), + (uint32_t)(i_config->baseAddress[i])); + + PK_TRACE(" bar = 0x%08x%08x" + " mask = 0x%08x%08x", + (uint32_t)(bar >> 32), + (uint32_t)(bar), + (uint32_t)(mask >> 32), + (uint32_t)(mask)); + + rc = MEMBUF_BAR_MASK_ERROR; + break; + } + } + } + } + } while(0); + return rc; +} + + + +int check_centaur_channel_chkstp(unsigned int i_centaur) +{ + int rc = 0; + mcchifir_t chifir; + mcmcicfg_t chicfg; + + do { - PK_TRACE("gpe_centaur_scom: Failed to send response. rc = %x. Halting GPE1.", - rc); + rc = getscom_abs(MCCHIFIR[i_centaur], &(chifir.value)); + if (rc) + { + PK_TRACE("MCCHIFIR scom failed. rc = %d",rc); + break; + } - gpe_set_ffdc(&(scomParms->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); - pk_halt(); - } + if(chifir.fields.fir_dsrc_no_forward_progress || + chifir.fields.fir_dmi_channel_fail || + chifir.fields.fir_channel_init_timeout || + chifir.fields.fir_channel_interlock_err || + chifir.fields.fir_replay_buffer_ue || + chifir.fields.fir_replay_buffer_overrun || + chifir.fields.fir_df_sm_perr || + chifir.fields.fir_cen_checkstop || + chifir.fields.fir_dsff_tag_overrun || + chifir.fields.fir_dsff_mca_async_cmd_error || + chifir.fields.fir_dsff_seq_error || + chifir.fields.fir_dsff_timeout) + { + PK_TRACE("MCCHIFIR: %08x%08x for channel %d", + chifir.words.high_order, + chifir.words.low_order, + i_centaur); + rc = getscom_abs(MCMCICFG1Q[i_centaur], &(chicfg.value)); + if (rc) + { + PK_TRACE("MCMCICFG scom failed. rc = %d",rc); + break; + } + PK_TRACE("MCMCICFG1Q %08x%08x", + chicfg.words.high_order, + chicfg.words.low_order); + + rc = MEMBUF_CHANNEL_CHECKSTOP; + } + } while(0); + + return rc; } -void gpe_centaur_data(ipc_msg_t* i_cmd, void* i_arg) +int centaur_throttle_sync(MemBufConfiguration_t* i_config) { - static int g_log_once = 0; - int rc; - ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)i_cmd; + uint64_t data; + int rc = 0; + do + { + rc = getscom_abs(i_config->mcSyncAddr,&data); + if (rc) + { + PK_TRACE("centaur_throttle_sync: getscom failed. rc = %d",rc); + break; + } - CentaurGetMemDataParms_t * dataParms = - (CentaurGetMemDataParms_t *)async_cmd->cmd_data; + data &= ~MCS_MCSYNC_SYNC_GO; - if(g_log_once == 0) + rc = putscom_abs(i_config->mcSyncAddr, data); + if (rc) + { + PK_TRACE("centaur_throttle_sync: reset sync putscom failed. rc = %d",rc); + break; + } + + data |= MCS_MCSYNC_SYNC_GO; + + rc = putscom_abs(i_config->mcSyncAddr, data); + if (rc) + { + PK_TRACE("centaur_throttle_sync: set sync putscom failed. rc = %d",rc); + break; + } + } while (0); + + return rc; +} + +int centaur_sensorcache_setup(MemBufConfiguration_t* i_config, + uint32_t i_centaur_instance, + uint32_t * o_oci_addr) +{ + int rc = 0; +#if defined(__USE_PBASLV__) + pba_slvctln_t slvctln; +#endif + uint64_t pb_addr = i_config->baseAddress[i_centaur_instance]; + + // bit 38 set OCI master, bits 39,40 Centaur thermal sensors '10'b + pb_addr |= 0x0000000003000000ull; + +#if defined(__USE_PBASLV__) + PPE_LVD((i_config->dataParms).slvctl_address, slvctln.value); + slvctln.fields.extaddr = pb_addr >> 27; + PPE_STVD((i_config->dataParms).slvctl_address, slvctln.value); +#else { - g_log_once = 1; - PK_TRACE("Centaur Data. MSR:%08x",mfmsr()); + // HW bug workaround - don't use extaddr - use pbabar. + uint64_t barMsk = 0; + + // Mask SIB from generating mck + mtmsr(mfmsr() | MSR_SEM); + + // put the PBA in the BAR + rc = putscom_abs(PBA_BARN(PBA_BAR_MEMBUF), pb_addr); + if (rc) + { + PK_TRACE("centaur_sensorcache_setup: putscom fail on PBABAR," + " rc = %d",rc); + } + else + { + rc = putscom_abs(PBA_BARMSKN(PBA_BAR_MEMBUF), barMsk); + if (rc) + { + PK_TRACE("centaur_sensrocache_setup: putscom fail on" + " PBABARMSK, rc = %d",rc); + } + } } - rc = centaur_get_mem_data(G_centaur_config, dataParms); +#endif + // make oci address + *o_oci_addr = (uint32_t)(pb_addr & 0x07ffffffull); + + // PBA space bits[0:1] = '10' bar select bits[3:4] + *o_oci_addr |= ((PBA_BAR_MEMBUF | 0x8) << 28); + + return rc; +} + + +// read centaur data sensor cache +int get_centaur_sensorcache(MemBufConfiguration_t* i_config, + MemBufGetMemDataParms_t* i_parms) +{ + int rc = 0; + uint32_t oci_addr = 0; + uint64_t pba_slvctln_save; + uint64_t data64 = 0; + + i_parms->error.rc = MEMBUF_GET_MEM_DATA_DIED; - dataParms->error.rc = rc; + pbaslvctl_reset(&(i_config->dataParms)); + pba_slvctln_save = pbaslvctl_setup(&(i_config->dataParms)); - // Send response - rc = ipc_send_rsp(i_cmd, IPC_RC_SUCCESS); - if(rc) + // Clear SIB error accumulator bits & mask SIB errors from + // generating machine checks + mtmsr((mfmsr() & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM); + + if(i_parms->collect != -1) { - PK_TRACE("gpe_centaur_init: Failed to send response. rc = %x. Halting GPE1.", - rc); + if((i_parms->collect >= OCCHW_N_MEMBUF) || + (0 == (CHIP_CONFIG_MEMBUF(i_parms->collect) & (i_config->config)))) + { + rc = MEMBUF_GET_MEM_DATA_COLLECT_INVALID; + } + else + { + rc = centaur_sensorcache_setup(i_config, i_parms->collect,&oci_addr); + + if(!rc) + { + uint32_t org_msr = mfmsr(); + mtmsr(org_msr | MSR_SEM); // Mask off SIB errors from gen mck + g_inband_access_state = INBAND_ACCESS_IN_PROGRESS; + // Read 128 bytes from centaur cache + int i; + for(i = 0; i < 128; i += 8) + { + PPE_LVDX(oci_addr, i, data64); + PPE_STVDX((i_parms->data), i, data64); + } - gpe_set_ffdc(&(dataParms->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); - pk_halt(); + // Poll for SIB errors or machine check + if((mfmsr() & MSR_SIBRC) || + g_inband_access_state != INBAND_ACCESS_IN_PROGRESS) + { + // Take centaur out of config list + PK_TRACE("Removing Membuf %d from list of configured Membufs", + i_parms->collect); + i_config->config &= ~(CHIP_CONFIG_MEMBUF(i_parms->collect)); + + // This rc will cause the 405 to remove this centaur sensor + rc = MEMBUF_CHANNEL_CHECKSTOP; + } + mtmsr(org_msr); + g_inband_access_state = INBAND_ACCESS_INACTIVE; + } + } } + + if(i_parms->update != -1) + { + int update_rc = 0; + if((i_parms->update >= OCCHW_N_MEMBUF) || + (0 == (CHIP_CONFIG_MEMBUF(i_parms->update) & (i_config->config)))) + { + update_rc = MEMBUF_GET_MEM_DATA_UPDATE_INVALID; + } + else + { + update_rc = centaur_sensorcache_setup(i_config, i_parms->update,&oci_addr); + + if(!update_rc) + { + // Writing a zero to this address tells the centaur to update + // the sensor cache for the next centaur. + data64 = 0; + update_rc = inband_access(i_config, + i_parms->update, + oci_addr, + &data64, + INBAND_ACCESS_WRITE); + } + } + if(!rc && update_rc) + { + rc = update_rc; + } + } + + pbaslvctl_reset(&(i_config->dataParms)); + PPE_STVD((i_config->dataParms).slvctl_address, pba_slvctln_save); + + if(!rc) + { + int instance = i_parms->collect; + if(instance == -1) + { + instance = i_parms->update; + } + if (instance != -1) + { + rc = check_centaur_channel_chkstp(instance); + } + } + + i_parms->error.rc = rc; + return rc; } + diff --git a/src/occ_gpe1/gpe_centaur.h b/src/occ_gpe1/gpe_centaur.h deleted file mode 100644 index 482af22..0000000 --- a/src/occ_gpe1/gpe_centaur.h +++ /dev/null @@ -1,61 +0,0 @@ -#if !defined(_GPE_CENTAUR_H) -#define _GPE_CENTAUR_H - -#include "ipc_structs.h" -#include "centaur_structs.h" - -// IPC interface -void gpe_centaur_scom(ipc_msg_t* i_cmd, void* i_arg); -void gpe_centaur_data(ipc_msg_t* i_cmd, void* i_arg); -void gpe_centaur_init(ipc_msg_t* i_cmd, void* i_arg); - -// HCODE interface -/** - * Populate a CentaurConfiguration object - * @param[out] 8 byte aligned pointer to the CentaurConfiguration object. - * @return [0 | return code] - * @note The CentaurConfiguration object is shared with the 405 so - * it needs to be in non-cacheable sram. - */ -int gpe_centaur_configuration_create(CentaurConfiguration_t * o_config); - -/** - * Scom all of the centaurs with the same SCOM address. - * @param[in] The CentaurConfig object - * @param[in] The SCOM address - * @param[out] The array of data collected. Must be large enough to hold - * uint64_t data from each centaur. - * @return [0 | return code] - */ -int centaur_get_scom_vector(CentaurConfiguration_t* i_config, - uint32_t i_scom_address, - uint64_t* o_data); - -/** - * Scom one or more centaurs - * @param[in] The CentaurConfig object - * @param[in/out] The Centaur Scom Parms object - * @return The return code is part of the Centaur Scom Parms object - */ -void gpe_scom_centaur(CentaurConfiguration_t* i_config, - CentaurScomParms_t* i_parms); - - -/** - * Collect the centaur thermal data - * @param[in] The CentaurConfig object - * @param[in/out] The Centaur data parm object - * @return [0 | return code] - */ -int centaur_get_mem_data(CentaurConfiguration_t* i_config, - CentaurGetMemDataParms_t* i_parms); - -/** - * Check for channel checkstop - * @param[in] The ordinal centaur number - * @return [0 | return code] - */ -int check_channel_chkstp(unsigned int i_centaur); - -extern uint32_t g_centaur_access_state; -#endif diff --git a/src/occ_gpe1/gpe_centaur_configuration.c b/src/occ_gpe1/gpe_centaur_configuration.c deleted file mode 100644 index b9866bb..0000000 --- a/src/occ_gpe1/gpe_centaur_configuration.c +++ /dev/null @@ -1,497 +0,0 @@ -/* IBM_PROLOG_BEGIN_TAG */ -/* This is an automatically generated prolog. */ -/* */ -/* $Source: chips/p9/procedures/lib/pm/centaur_thermal_access.c $ */ -/* */ -/* IBM CONFIDENTIAL */ -/* */ -/* EKB Project */ -/* */ -/* COPYRIGHT 2017 */ -/* [+] International Business Machines Corp. */ -/* */ -/* */ -/* The source code for this program is not published or otherwise */ -/* divested of its trade secrets, irrespective of what has been */ -/* deposited with the U.S. Copyright Office. */ -/* */ -/* IBM_PROLOG_END_TAG */ -/** - * @briefcentaur_thermal_access - */ - -#include "gpe_centaur.h" -#include "ppe42_scom.h" -#include "pk.h" -#include "p9_misc_scom_addresses.h" -#include "mcs_firmware_registers.h" -#include "pba_firmware_constants.h" -#include "pba_register_addresses.h" -#include "centaur_register_addresses.h" -#include "ppe42_msr.h" -#include "occhw_pba_common.h" - -// Which GPE controls the PBASLAVE -#define OCI_MASTER_ID_GPE1 1 - -// Power Bus Address bit that configures centaur for HOST/OCC P9=bit(38) -#define PBA_HOST_OCC_CFG 0x0000000002000000ull; - - -const uint32_t MCFGPR[OCCHW_NCENTAUR] = -{ - MCS_0_MCRSVDE, - MCS_0_MCRSVDF, - MCS_1_MCRSVDE, - MCS_1_MCRSVDF, - MCS_2_MCRSVDE, - MCS_2_MCRSVDF, - MCS_3_MCRSVDE, - MCS_3_MCRSVDF -}; - -const uint32_t MCSYNC[OCCHW_NCENTAUR/2] = -{ - MCS_0_MCSYNC, - MCS_1_MCSYNC, - MCS_2_MCSYNC, - MCS_3_MCSYNC -}; - -const uint32_t MCCHIFIR[OCCHW_NCENTAUR] = -{ - MCP_CHAN0_CHI_FIR, - MCP_CHAN1_CHI_FIR, - MCP_CHAN2_CHI_FIR, - MCP_CHAN3_CHI_FIR, - MCP_CHAN4_CHI_FIR, - MCP_CHAN5_CHI_FIR, - MCP_CHAN6_CHI_FIR, - MCP_CHAN7_CHI_FIR -}; - -const uint32_t MCMCICFG1Q[OCCHW_NCENTAUR] = -{ - MCP_CHAN0_CHI_MCICFG1Q, - MCP_CHAN1_CHI_MCICFG1Q, - MCP_CHAN2_CHI_MCICFG1Q, - MCP_CHAN3_CHI_MCICFG1Q, - MCP_CHAN4_CHI_MCICFG1Q, - MCP_CHAN5_CHI_MCICFG1Q, - MCP_CHAN6_CHI_MCICFG1Q, - MCP_CHAN7_CHI_MCICFG1Q -}; - -/////////////////////////////////////////////////////////////// -// These are PPE specific PBA routines. -////////////////////////////////////////////////////////////// -int -gpe_pba_parms_create(GpePbaParms* parms, - int slave, - int write_ttype, - int write_tsize, - int read_ttype) -{ - pba_slvctln_t* slvctl, *mask; - pba_slvrst_t* slvrst; - pba_slvrst_t* slvrst_in_progress; - uint64_t all1 = 0xffffffffffffffffull; - - parms->slave_id = slave; - - slvctl = &(parms->slvctl); - mask = &(parms->mask); - slvrst = &(parms->slvrst); - slvrst_in_progress = &(parms->slvrst_in_progress); - - parms->slvctl_address = PBA_SLVCTLN(slave); - - slvrst->value = 0; - slvrst->fields.set = PBA_SLVRST_SET(slave); - - slvrst_in_progress->value = 0; - slvrst_in_progress->fields.in_prog = PBA_SLVRST_IN_PROG(slave); - - slvctl->value = 0; - mask->value = 0; - - slvctl->fields.enable = 1; - mask->fields.enable = all1; - - slvctl->fields.mid_match_value = OCI_MASTER_ID_GPE1; - mask->fields.mid_match_value = all1; - - slvctl->fields.mid_care_mask = all1; - mask->fields.mid_care_mask = all1; - - slvctl->fields.write_ttype = write_ttype; - mask->fields.write_ttype = all1; - - slvctl->fields.write_tsize = write_tsize; - mask->fields.write_tsize = all1; - - slvctl->fields.read_ttype = read_ttype; - mask->fields.read_ttype = all1; - - slvctl->fields.buf_alloc_a = 1; - slvctl->fields.buf_alloc_b = 1; - slvctl->fields.buf_alloc_c = 1; - slvctl->fields.buf_alloc_w = 1; - mask->fields.buf_alloc_a = 1; - mask->fields.buf_alloc_b = 1; - mask->fields.buf_alloc_c = 1; - mask->fields.buf_alloc_w = 1; - - if (read_ttype == PBA_READ_TTYPE_CI_PR_RD) - { - - slvctl->fields.buf_invalidate_ctl = 1; - mask->fields.buf_invalidate_ctl = all1; - - slvctl->fields.read_prefetch_ctl = PBA_READ_PREFETCH_NONE; - mask->fields.read_prefetch_ctl = all1; - - } - else - { - - slvctl->fields.buf_invalidate_ctl = 0; - mask->fields.buf_invalidate_ctl = all1; - } - - mask->value = ~(mask->value); - - return 0; -} - - -//////////////////////////////////////////////// -// Centaur specific routines -//////////////////////////////////////////////// -int gpe_centaur_configuration_create(CentaurConfiguration_t* o_config) -{ - int rc = 0; - unsigned int i = 0; - mcfgpr_t mcfgpr; - uint64_t bar = 0; - uint64_t mask = 0; - uint64_t* ptr = (uint64_t*)o_config; - int designated_sync = -1; - - // Prevent unwanted interrupts from scom errors - const uint32_t orig_msr = mfmsr() & MSR_SEM; - mtmsr((orig_msr & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM); - - for(i = 0; i < sizeof(CentaurConfiguration_t) / 8; ++i) - { - *ptr++ = 0ull; - } - - o_config->configRc = CENTAUR_NOT_CONFIGURED; - - do - { - // Create the PBASLV configurations for the GPE procedures. - // The 'dataParms' define the PBASLV setup needed to access the - // Centaur sensor cache. The 'scomParms' define the PBASLV setup - // needed to access the Centaur SCOMs. - - rc = gpe_pba_parms_create(&(o_config->dataParms), - PBA_SLAVE_CENTAUR, - PBA_WRITE_TTYPE_CI_PR_W, - PBA_WRITE_TTYPE_DC, - PBA_READ_TTYPE_CL_RD_NC); - - if (rc) - { - rc = CENTAUR_DATA_SETUP_ERROR; - break; - } - - rc = gpe_pba_parms_create(&(o_config->scomParms), - PBA_SLAVE_CENTAUR, - PBA_WRITE_TTYPE_CI_PR_W, - PBA_WRITE_TTYPE_DC, - PBA_READ_TTYPE_CI_PR_RD); - - if (rc) - { - rc = CENTAUR_SCOM_SETUP_ERROR; - break; - } - - // Iterate through each MCS on the chip and check configuration. - - // Note that the code uniformly treats SCOM failures of the MCFGPR - // registers as an unconfigured Centaur. This works both for real - // hardware, as well as for our VBU models where some of the "valid" - // MCS are not in the simulation models. - - for (i = 0; i < OCCHW_NCENTAUR; ++i) - { - // check for channel checkstop - rc = check_channel_chkstp(i); - if (rc) - { - // If scom failed OR there is a channel checkstop then - // Centaur is not usable. - rc = 0; - continue; - } - - // Verify that inband scom has been setup. If not then - // assume the centaur is either non-existant or not configured. - // Setup is provided by HWP p9c_set_inband_addr.C - rc = getscom_abs(MCFGPR[i], &(mcfgpr.value)); - - if (rc) - { - // ignore if can't be scomed. - rc = 0; - continue; - } - - // If inband scom is not configured then assume the centaur does not exist - if (!mcfgpr.fields.mcfgprq_valid) - { - continue; - } - - - // The 31-bit base-address (inband scom BAR) corresponds to bits [8:38] in the - // 64-bit PowerBus address. - // Set the HOST/OCC bit in the address. - o_config->baseAddress[i] = - ((uint64_t)(mcfgpr.fields.mcfgprq_base_address) << 25) | PBA_HOST_OCC_CFG; - - PK_TRACE_DBG("Centar[%d] Base Address: %016llx",i,o_config->baseAddress[i]); - - // Add the Centaur to the configuration - o_config->config |= (CHIP_CONFIG_MCS(i) | CHIP_CONFIG_CENTAUR(i)); - } - - if (rc) - { - break; - } - - // Find the designated sync - for (i = 0; i < (OCCHW_NCENTAUR/2); ++i) - { - uint64_t mcsync; - rc = getscom_abs(MCSYNC[i], &mcsync); - if (rc) - { - PK_TRACE("getscom failed on MCSYNC, rc = %d. The first configured MC will be the designated sync",rc); - rc = 0; - } - if (mcsync != 0) - { - designated_sync = i; - // There can only be one sync, so stop searching. - break; - } - } - - if (designated_sync < 0) - { - designated_sync = cntlz32(o_config->config << CHIP_CONFIG_MCS_BASE); - PK_TRACE("No designated sync found, using MCS(%d)",designated_sync); - } - - o_config->mcSyncAddr = MCSYNC[designated_sync]; - - - // Configure the PBA BAR and PBA BARMSK. - // Set the BARMSK bits such that: - // -PBA[8:22] are provided by the PBABAR. - // -PBA[23:36] are provided by the PBASLVCTL ExtrAddr field - // -PBA[37:43] are provided by the OCI addr[5:11] - // PBA[44:63] will always come from the OCI addr[12:31] - // Note: This code should no longer be needed when the BAR/BARMSK is set - // by PHYP. - if (o_config->config != 0) - { - uint64_t bar = 0; - uint64_t barMsk = PBA_BARMSKN_MASK_MASK; - - for (i = 0; i < OCCHW_NCENTAUR; ++i) - { - bar |= o_config->baseAddress[i]; - } - - bar &= ~barMsk; - - PK_TRACE_DBG("PBABAR(%d): %016llx", PBA_BAR_CENTAUR, bar); - PK_TRACE_DBG("PBABARMSK: %016llx", barMsk); - - rc = putscom_abs(PBA_BARMSKN(PBA_BAR_CENTAUR), barMsk); - - if (rc) - { - PK_TRACE_DBG("Unexpected rc = 0x%08x SCOMing PBA_BARMSKN(%d)\n", - (uint32_t)rc, PBA_BAR_CENTAUR); - rc = CENTAUR_BARMSKN_PUTSCOM_FAILURE; - break; - } - - rc = putscom_abs(PBA_BARN(PBA_BAR_CENTAUR), bar); - if (rc) - { - PK_TRACE_DBG("Unexpected rc = 0x%08x SCOMing PBA_BARN(%d)\n", - (uint32_t)rc, PBA_BAR_CENTAUR); - rc = CENTAUR_BARN_PUTSCOM_FAILURE; - break; - } - } - - // Do an independent check that every Centaur base address - // can be generated by the combination of the current BAR and - // BAR Mask, along with the initial requirement that the mask must - // include at least bits 38:43. - - if (o_config->config != 0) - { - rc = getscom_abs(PBA_BARN(PBA_BAR_CENTAUR), &bar); - - if (rc) - { - PK_TRACE_DBG("Unexpected rc = 0x%08x SCOMing PBA_BARN(%d)\n", - (uint32_t)rc, PBA_BAR_CENTAUR); - rc = CENTAUR_BARN_GETSCOM_FAILURE; - break; - } - - rc = getscom_abs(PBA_BARMSKN(PBA_BAR_CENTAUR), &mask); - - if (rc) - { - PK_TRACE_DBG("Unexpected rc = 0x%08x SCOMing PBA_BARMSKN(%d)\n", - (uint32_t)rc, PBA_BAR_CENTAUR); - rc = CENTAUR_BARMSKN_GETSCOM_FAILURE; - break; - } - - bar = bar & PBA_BARN_ADDR_MASK; - mask = mask & PBA_BARMSKN_MASK_MASK; - - if ((mask & 0x0000000003f00000ull) != 0x0000000003f00000ull) - { - - PK_TRACE("PBA BAR mask (%d) does not cover bits 38:43\n", PBA_BAR_CENTAUR); - rc = CENTAUR_MASK_ERROR; - break; - } - - for (i = 0; i < OCCHW_NCENTAUR; ++i) - { - if (o_config->baseAddress[i] != 0) - { - if ((o_config->baseAddress[i] & ~mask) != - (bar & ~mask)) - { - - PK_TRACE("BAR/Mask (%d) error for MCS/Centaur %d", - PBA_BAR_CENTAUR, i); - - PK_TRACE(" base = 0x%08x%08x", - (uint32_t)(o_config->baseAddress[i]>>32), - (uint32_t)(o_config->baseAddress[i])); - - PK_TRACE(" bar = 0x%08x%08x" - " mask = 0x%08x%08x", - (uint32_t)(bar >> 32), - (uint32_t)(bar), - (uint32_t)(mask >> 32), - (uint32_t)(mask)); - - rc = CENTAUR_BAR_MASK_ERROR; - break; - } - } - } - - if (rc) - { - break; - } - } - - - // At this point the structure is initialized well-enough that it can - // be used by gpe_scom_centaur(). - - - o_config->configRc = 0; - - if (o_config->config == 0) - { - break; - } - - - // Get Device ID from each centaur - centaur_get_scom_vector(o_config, - CENTAUR_DEVICE_ID, - (uint64_t*)(&(o_config->deviceId[0]))); - - } - while(0); - - o_config->configRc = rc; - - mtmsr(orig_msr); - - return rc; -} - -int check_channel_chkstp(unsigned int i_centaur) -{ - int rc = 0; - mcchifir_t chifir; - mcmcicfg_t chicfg; - - do - { - rc = getscom_abs(MCCHIFIR[i_centaur], &(chifir.value)); - if (rc) - { - PK_TRACE("MCCHIFIR scom failed. rc = %d",rc); - break; - } - - if(chifir.fields.fir_dsrc_no_forward_progress || - chifir.fields.fir_dmi_channel_fail || - chifir.fields.fir_channel_init_timeout || - chifir.fields.fir_channel_interlock_err || - chifir.fields.fir_replay_buffer_ue || - chifir.fields.fir_replay_buffer_overrun || - chifir.fields.fir_df_sm_perr || - chifir.fields.fir_cen_checkstop || - chifir.fields.fir_dsff_tag_overrun || - chifir.fields.fir_dsff_mca_async_cmd_error || - chifir.fields.fir_dsff_seq_error || - chifir.fields.fir_dsff_timeout) - { - PK_TRACE("MCCHIFIR: %08x%08x for channel %d", - chifir.words.high_order, - chifir.words.low_order, - i_centaur); - - rc = getscom_abs(MCMCICFG1Q[i_centaur], &(chicfg.value)); - if (rc) - { - PK_TRACE("MCMCICFG scom failed. rc = %d",rc); - break; - } - - PK_TRACE("MCMCICFG1Q %08x%08x", - chicfg.words.high_order, - chicfg.words.low_order); - - rc = CENTAUR_CHANNEL_CHECKSTOP; - } - } while(0); - - return rc; -} diff --git a/src/occ_gpe1/gpe_centaur_scom.c b/src/occ_gpe1/gpe_centaur_scom.c deleted file mode 100644 index edee857..0000000 --- a/src/occ_gpe1/gpe_centaur_scom.c +++ /dev/null @@ -1,762 +0,0 @@ -/* IBM_PROLOG_BEGIN_TAG */ -/* This is an automatically generated prolog. */ -/* */ -/* $Source: chips/p9/procedures/lib/pm/centaur_scom.c $ */ -/* */ -/* IBM CONFIDENTIAL */ -/* */ -/* EKB Project */ -/* */ -/* COPYRIGHT 2017 */ -/* [+] International Business Machines Corp. */ -/* */ -/* */ -/* The source code for this program is not published or otherwise */ -/* divested of its trade secrets, irrespective of what has been */ -/* deposited with the U.S. Copyright Office. */ -/* */ -/* IBM_PROLOG_END_TAG */ -#include <stdint.h> -#include "gpe_centaur.h" -#include "gpe_pba_cntl.h" -#include "ppe42_scom.h" -#include "ppe42.h" -#include "pba_register_addresses.h" -#include "ppe42_msr.h" - -#define CENTAUR_ACCESS_READ 1 -#define CENTAUR_ACCESS_WRITE 2 - -/** - * @file centaur_scom - * @brief scom access from gpe to a centaur - */ - -uint32_t g_centaur_access_state = CENTAUR_ACCESS_INACTIVE; - -int centaur_access(CentaurConfiguration_t* i_config, - uint32_t i_instance, - uint32_t i_oci_addr, - uint64_t * io_data, - int i_read_write) -{ - int rc = 0; - uint32_t org_msr = mfmsr(); - uint32_t msr = org_msr | MSR_SEM; // Mask off SIB from generating mck. - - g_centaur_access_state = CENTAUR_ACCESS_IN_PROGRESS; - - if(i_read_write == CENTAUR_ACCESS_READ) - { - mtmsr(msr); - sync(); - PPE_LVD(i_oci_addr, *io_data); - } - else - { - // Set PPE to precise mode for stores so that in the case of a machine - // check, there is a predictable instruction address to resume on. - msr &= ~MSR_IPE; - mtmsr(msr); - sync(); - - PPE_STVD(i_oci_addr, *io_data); - } - - // Poll SIB error or machine check - if((mfmsr() & MSR_SIBRC) || - g_centaur_access_state != CENTAUR_ACCESS_IN_PROGRESS) - { - // Take centaur out of config - PK_TRACE("Removing Centaur %d from list of configured Centaurs", - i_instance); - - i_config->config &= ~(CHIP_CONFIG_CENTAUR(i_instance)); - - // This will cause the 405 to remove the centaur sensor. - rc = CENTAUR_CHANNEL_CHECKSTOP; - } - g_centaur_access_state = CENTAUR_ACCESS_INACTIVE; - mtmsr(org_msr); - return rc; -} - -/** - * Setup the PBASLVCTLN extended address and calculate the OCI scom address - * @param[in] PBA base address - * @param[in] The Centaur scom address - * @returns the OCI address to scom the centaur - * @Post The extended address field in the PBASLVCNT is set - */ -int centaur_scom_setup(CentaurConfiguration_t* i_config, - uint32_t i_centaur_instance, - uint32_t i_scom_address, - uint32_t *o_oci_addr) -{ - int rc = 0; -#if defined(__USE_PBASLV__) - pba_slvctln_t slvctln; -#endif - uint64_t pb_addr = i_config->baseAddress[i_centaur_instance]; - - // Break address into componets - uint32_t local = i_scom_address & 0x00001fff; - uint32_t port = i_scom_address & 0x000f0000; - uint32_t slave = i_scom_address & 0x03000000; - uint32_t multi = i_scom_address & 0xc0000000; - - // compress to 21 bits for P9 - uint32_t scom_address = - local + - (port >> 3) + - (slave >> 7) + - (multi >> 11); - - // P9: Turn on bit 38 to indicate OCC - pb_addr |= 0x0000000002000000ull; - pb_addr |= ((uint64_t)scom_address << 3); - -#if defined(__USE_PBASLV__) - // put bits 23:36 of address into slvctln extended addr - PPE_LVD((i_config->scomParms).slvctl_address, slvctln.value); - slvctln.fields.extaddr = pb_addr >> 27; - PPE_STVD((i_config->scomParms).slvctl_address, slvctln.value); -#else - // HW bug work-around - { - // workaround - don't use extraddr - use pbabar. - uint64_t barMsk = 0; - - // Mask SIB from generating mck - mtmsr(mfmsr() | MSR_SEM); - - // put the PBA in the BAR - rc = putscom_abs(PBA_BARN(PBA_BAR_CENTAUR), pb_addr); - if(rc) - { - PK_TRACE("centaur_scom_setup. putscom fail on PBABAR." - " rc = %d",rc); - } - else - { - rc = putscom_abs(PBA_BARMSKN(PBA_BAR_CENTAUR), barMsk); - if(rc) - { - PK_TRACE("centaur_scom_setup. putscom fail on PBABARMSK" - " rc = %d",rc); - } - } - } -#endif - // make oci address - *o_oci_addr = (uint32_t)(pb_addr & 0x07ffffffull); - - // upper nibble is PBA region and BAR_SELECT - *o_oci_addr |= ((PBA_BAR_CENTAUR | 0x8) << 28); - PK_TRACE_DBG("Centaur OCI scom addr: %08x",*o_oci_addr); - return rc; -} - -int centaur_sensorcache_setup(CentaurConfiguration_t* i_config, - uint32_t i_centaur_instance, - uint32_t * o_oci_addr) -{ - int rc = 0; -#if defined(__USE_PBASLV__) - pba_slvctln_t slvctln; -#endif - uint64_t pb_addr = i_config->baseAddress[i_centaur_instance]; - - // bit 38 set OCI master, bits 39,40 Centaur thermal sensors '10'b - pb_addr |= 0x0000000003000000ull; - -#if defined(__USE_PBASLV__) - PPE_LVD((i_config->dataParms).slvctl_address, slvctln.value); - slvctln.fields.extaddr = pb_addr >> 27; - PPE_STVD((i_config->dataParms).slvctl_address, slvctln.value); -#else - { - // HW bug workaround - don't use extaddr - use pbabar. - uint64_t barMsk = 0; - - // Mask SIB from generating mck - mtmsr(mfmsr() | MSR_SEM); - - // put the PBA in the BAR - rc = putscom_abs(PBA_BARN(PBA_BAR_CENTAUR), pb_addr); - if (rc) - { - PK_TRACE("centaur_sensorcache_setup: putscom fail on PBABAR," - " rc = %d",rc); - } - else - { - rc = putscom_abs(PBA_BARMSKN(PBA_BAR_CENTAUR), barMsk); - if (rc) - { - PK_TRACE("centaur_sensrocache_setup: putscom fail on" - " PBABARMSK, rc = %d",rc); - } - } - } -#endif - // make oci address - *o_oci_addr = (uint32_t)(pb_addr & 0x07ffffffull); - - // PBA space bits[0:1] = '10' bar select bits[3:4] - *o_oci_addr |= ((PBA_BAR_CENTAUR | 0x8) << 28); - - return rc; -} - -void pbaslvctl_reset(GpePbaParms* i_pba_parms) -{ - uint64_t val = 0; - - do - { - PPE_STVD(PBA_SLVRST, i_pba_parms->slvrst.value); - PPE_LVD(PBA_SLVRST, val); - val &= i_pba_parms->slvrst_in_progress.value; - } - while(val != 0); -} - -uint64_t pbaslvctl_setup(GpePbaParms* i_pba_parms) -{ - uint64_t slvctl_val; - uint64_t slvctl_val_org; - PPE_LVD(i_pba_parms->slvctl_address, slvctl_val_org); - slvctl_val = slvctl_val_org; - slvctl_val &= i_pba_parms->mask.value; - slvctl_val |= i_pba_parms->slvctl.value; - PPE_STVD(i_pba_parms->slvctl_address, slvctl_val); - return slvctl_val_org; -} - -// Get data from each existing centaur. -int centaur_get_scom_vector(CentaurConfiguration_t* i_config, - uint32_t i_scom_address, - uint64_t* o_data) -{ - int rc = 0; - int access_rc = 0; - int pba_rc = 0; - int instance = 0; - uint64_t pba_slvctln_save; - - pbaslvctl_reset(&(i_config->scomParms)); - pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); - - // clear SIB errors in MSR - mtmsr((mfmsr() & ~(MSR_SIBRC | MSR_SIBRCA))); - - for(instance = 0; instance < OCCHW_NCENTAUR; ++instance) - { - if( CHIP_CONFIG_CENTAUR(instance) & (i_config->config)) - { - uint32_t oci_addr; - pba_rc = centaur_scom_setup(i_config, - instance, - i_scom_address, - &oci_addr); - - if(pba_rc) - { - rc = pba_rc; - // Already traced. - // Trumps any access error - *o_data = 0; - } - - // read centaur scom - access_rc = centaur_access(i_config, - instance, - oci_addr, - o_data, - CENTAUR_ACCESS_READ); - if(!rc && access_rc) - { - // not critical, but don't touch this centaur again. - rc = access_rc; - *o_data = 0; - // continue - } - } - else - { - *o_data = 0; - } - - ++o_data; - } - - // gpe_pba_cntl function? - pbaslvctl_reset(&(i_config->scomParms)); - PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); - - return rc; -} - -int centaur_get_scom(CentaurConfiguration_t* i_config, - int i_centaur_instance, - uint32_t i_scom_address, - uint64_t* o_data) -{ - int rc = 0; - uint32_t oci_addr; - uint64_t pba_slvctln_save; - - pbaslvctl_reset(&(i_config->scomParms)); - pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); - - rc = centaur_scom_setup(i_config, - i_centaur_instance, - i_scom_address, - &oci_addr); - - if( !rc && (CHIP_CONFIG_CENTAUR(i_centaur_instance) & (i_config->config))) - { - // read centaur scom - rc = centaur_access(i_config, - i_centaur_instance, - oci_addr, - o_data, - CENTAUR_ACCESS_READ); - } - else - { - *o_data = 0; - } - - // gpe_pba_cntl function? - pbaslvctl_reset(&(i_config->scomParms)); - PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); - - return rc; -} - - -// Write all configured centaur with the same data -int centaur_put_scom_all(CentaurConfiguration_t* i_config, - uint32_t i_scom_address, - uint64_t i_data) -{ - int rc = 0; - int pba_rc = 0; - int access_rc = 0; - int instance = 0; - uint64_t pba_slvctln_save; - - pbaslvctl_reset(&(i_config->scomParms)); - pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); - - for(instance = 0; instance < OCCHW_NCENTAUR; ++instance) - { - if( CHIP_CONFIG_CENTAUR(instance) & (i_config->config)) - { - uint32_t oci_addr; - pba_rc = centaur_scom_setup(i_config, - instance, - i_scom_address, - &oci_addr); - - if(pba_rc) - { - // Already traced in centaur_scom_setup - // Trumps access_rc - rc = pba_rc; - } - - // centaur scom - access_rc = centaur_access(i_config, - instance, - oci_addr, - &i_data, - CENTAUR_ACCESS_WRITE); - if(!rc && access_rc) - { - // Centaur won't be touched again. - rc = access_rc; - // continue - } - } - } - - // reset pba slave - pbaslvctl_reset(&(i_config->scomParms)); - PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); - - return rc; -} - -int centaur_put_scom(CentaurConfiguration_t* i_config, - int i_centaur_instance, - uint32_t i_scom_address, - uint64_t i_data) -{ - int rc = 0; - uint32_t oci_addr; - uint64_t pba_slvctln_save; - - pbaslvctl_reset(&(i_config->scomParms)); - pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); - - rc = centaur_scom_setup(i_config, - i_centaur_instance, - i_scom_address, - &oci_addr); - - if(!rc) - { - if(CHIP_CONFIG_CENTAUR(i_centaur_instance) & (i_config->config)) - { - // write centaur scom - rc = centaur_access(i_config, - i_centaur_instance, - oci_addr, - &i_data, - CENTAUR_ACCESS_WRITE); - } - } - - // reset pba slave - pbaslvctl_reset(&(i_config->scomParms)); - PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); - - return rc; -} - -// write x -int centaur_scom_rmw(CentaurConfiguration_t* i_config, - int i_centaur_instance, - uint32_t i_scom_address, - uint64_t i_mask, - uint64_t* i_data) -{ - int rc = 0; - uint32_t oci_addr; - uint64_t pba_slvctln_save; - uint64_t data64; - - pbaslvctl_reset(&(i_config->scomParms)); - pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); - - rc = centaur_scom_setup(i_config, - i_centaur_instance, - i_scom_address, - &oci_addr); - if(!rc) - { - - rc = centaur_access(i_config, - i_centaur_instance, - oci_addr, - &data64, - CENTAUR_ACCESS_READ); - - if(!rc) - { - data64 &= (i_mask ^ 0xffffffffffffffffull); - data64 |= *i_data; - - rc = centaur_access(i_config, - i_centaur_instance, - oci_addr, - &data64, - CENTAUR_ACCESS_WRITE); - } - } - - pbaslvctl_reset(&(i_config->scomParms)); - PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); - - return rc; -} - - -int centaur_scom_rmw_all(CentaurConfiguration_t* i_config, - uint32_t i_scom_address, - uint64_t i_mask, - uint64_t i_data) -{ - int rc = 0; - int pba_rc = 0; - int access_rc = 0; - int instance = 0; - uint64_t pba_slvctln_save; - - pbaslvctl_reset(&(i_config->scomParms)); - pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); - - for(instance = 0; (instance < OCCHW_NCENTAUR); ++instance) - { - if( CHIP_CONFIG_CENTAUR(instance) & (i_config->config)) - { - uint64_t data64; - uint32_t oci_addr; - pba_rc = centaur_scom_setup(i_config, - instance, - i_scom_address, - &oci_addr); - if(pba_rc) - { - rc = pba_rc; - // Already traced in centaur_scom_setup - // Trumps any access_rc - } - if(!pba_rc) - { - - access_rc = centaur_access(i_config, - instance, - oci_addr, - &data64, - CENTAUR_ACCESS_READ); - - if(!access_rc) - { - data64 &= (i_mask ^ 0xffffffffffffffffull); - data64 |= i_data; - - access_rc = centaur_access(i_config, - instance, - oci_addr, - &data64, - CENTAUR_ACCESS_WRITE); - } - } - if(!rc && access_rc) - { - rc = access_rc; - } - - pbaslvctl_reset(&(i_config->scomParms)); - } - } - - PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); - - return rc; -} - - -// read centaur data sensor cache -int centaur_get_mem_data(CentaurConfiguration_t* i_config, - CentaurGetMemDataParms_t* i_parms) -{ - int rc = 0; - uint32_t oci_addr = 0; - uint64_t pba_slvctln_save; - uint64_t data64 = 0; - - i_parms->error.rc = CENTAUR_GET_MEM_DATA_DIED; - - pbaslvctl_reset(&(i_config->dataParms)); - pba_slvctln_save = pbaslvctl_setup(&(i_config->dataParms)); - - // Clear SIB error accumulator bits & mask SIB errors from - // generating machine checks - mtmsr((mfmsr() & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM); - - if(i_parms->collect != -1) - { - if((i_parms->collect >= OCCHW_NCENTAUR) || - (0 == (CHIP_CONFIG_CENTAUR(i_parms->collect) & (i_config->config)))) - { - rc = CENTAUR_GET_MEM_DATA_COLLECT_INVALID; - } - else - { - rc = centaur_sensorcache_setup(i_config, i_parms->collect,&oci_addr); - - if(!rc) - { - uint32_t org_msr = mfmsr(); - mtmsr(org_msr | MSR_SEM); // Mask off SIB errors from gen mck - g_centaur_access_state = CENTAUR_ACCESS_IN_PROGRESS; - // Read 128 bytes from centaur cache - int i; - for(i = 0; i < 128; i += 8) - { - PPE_LVDX(oci_addr, i, data64); - PPE_STVDX((i_parms->data), i, data64); - } - - // Poll for SIB errors or machine check - if((mfmsr() & MSR_SIBRC) || - g_centaur_access_state != CENTAUR_ACCESS_IN_PROGRESS) - { - // Take centaur out of config list - PK_TRACE("Removing Centaur %d from list of configured Centaurs", - i_parms->collect); - i_config->config &= ~(CHIP_CONFIG_CENTAUR(i_parms->collect)); - - // This rc will cause the 405 to remove this centaur sensor - rc = CENTAUR_CHANNEL_CHECKSTOP; - } - mtmsr(org_msr); - g_centaur_access_state = CENTAUR_ACCESS_INACTIVE; - } - } - } - - if(i_parms->update != -1) - { - int update_rc = 0; - if((i_parms->update >= OCCHW_NCENTAUR) || - (0 == (CHIP_CONFIG_CENTAUR(i_parms->update) & (i_config->config)))) - { - update_rc = CENTAUR_GET_MEM_DATA_UPDATE_INVALID; - } - else - { - update_rc = centaur_sensorcache_setup(i_config, i_parms->update,&oci_addr); - - if(!update_rc) - { - // Writing a zero to this address tells the centaur to update - // the sensor cache for the next centaur. - data64 = 0; - update_rc = centaur_access(i_config, - i_parms->update, - oci_addr, - &data64, - CENTAUR_ACCESS_WRITE); - } - } - if(!rc && update_rc) - { - rc = update_rc; - } - } - - pbaslvctl_reset(&(i_config->dataParms)); - PPE_STVD((i_config->dataParms).slvctl_address, pba_slvctln_save); - - if(!rc) - { - int instance = i_parms->collect; - if(instance == -1) - { - instance = i_parms->update; - } - if (instance != -1) - { - rc = check_channel_chkstp(instance); - } - } - - - i_parms->error.rc = rc; - return rc; -} - - -int centaur_scom_sync(CentaurConfiguration_t* i_config) -{ - uint64_t data; - int rc = 0; - do - { - rc = getscom_abs(i_config->mcSyncAddr,&data); - if (rc) - { - PK_TRACE("centaur_scom_sync: getscom failed. rc = %d",rc); - break; - } - - data &= ~MCS_MCSYNC_SYNC_GO; - - rc = putscom_abs(i_config->mcSyncAddr, data); - if (rc) - { - PK_TRACE("centaur_scom_sync: reset sync putscom failed. rc = %d",rc); - break; - } - - data |= MCS_MCSYNC_SYNC_GO; - - rc = putscom_abs(i_config->mcSyncAddr, data); - if (rc) - { - PK_TRACE("centaur_scom_sync: set sync putscom failed. rc = %d",rc); - break; - } - } while (0); - - return rc; -} - - -// CentaurConfiguration needs to be setup before this is called -void gpe_scom_centaur(CentaurConfiguration_t* i_config, - CentaurScomParms_t* i_parms) -{ - int i; - int rc = 0; - mtmsr((mfmsr() & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM); - - for(i = 0; i < i_parms->entries; ++i) - { - switch(i_parms->scomList[i].commandType) - { - case CENTAUR_SCOM_NOP: - break; - - case CENTAUR_SCOM_READ: - rc =centaur_get_scom(i_config, - i_parms->scomList[i].instanceNumber, - i_parms->scomList[i].scom, - &(i_parms->scomList[i].data)); - break; - - case CENTAUR_SCOM_WRITE: - rc = centaur_put_scom(i_config, - i_parms->scomList[i].instanceNumber, - i_parms->scomList[i].scom, - i_parms->scomList[i].data); - break; - - case CENTAUR_SCOM_RMW: - rc = centaur_scom_rmw(i_config, - i_parms->scomList[i].instanceNumber, - i_parms->scomList[i].scom, - i_parms->scomList[i].mask, - &(i_parms->scomList[i].data)); - break; - - case CENTAUR_SCOM_READ_VECTOR: - rc = centaur_get_scom_vector(i_config, - i_parms->scomList[i].scom, - i_parms->scomList[i].pData - ); - break; - - case CENTAUR_SCOM_WRITE_ALL: - rc = centaur_put_scom_all(i_config, - i_parms->scomList[i].scom, - i_parms->scomList[i].data); - break; - - case CENTAUR_SCOM_RMW_ALL: - rc = centaur_scom_rmw_all(i_config, - i_parms->scomList[i].scom, - i_parms->scomList[i].mask, - i_parms->scomList[i].data); - break; - - case CENTAUR_SCOM_CENTAUR_SYNC: - rc = centaur_scom_sync(i_config); - break; - - default: - break; - }; - i_parms->error.rc = rc; - if (rc) - { - break; - } - } -} diff --git a/src/occ_gpe1/gpe_membuf.c b/src/occ_gpe1/gpe_membuf.c new file mode 100644 index 0000000..c5f9dd4 --- /dev/null +++ b/src/occ_gpe1/gpe_membuf.c @@ -0,0 +1,147 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_gpe1/gpe_membuf.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include "gpe_membuf.h" +#include "ipc_async_cmd.h" +#include "gpe_util.h" + +MemBufConfiguration_t * G_membuf_config = NULL; + +void gpe_membuf_init(ipc_msg_t* i_cmd, void* i_arg) +{ + int rc; + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)i_cmd; + MemBufConfigParms_t* payload = (MemBufConfigParms_t*)async_cmd->cmd_data; + + MemBufConfiguration_t * config = payload->membufConfiguration; + G_membuf_config = config; + + payload->error.error = 0; + payload->error.ffdc = 0; + + if(G_membuf_config == NULL) + { + PK_TRACE("gpe_membuf_init: membufConfiguration data ptr is NULL!"); + rc = GPE_RC_CONFIG_DATA_NULL_PTR; + } + else + { + if(payload->mem_type == MEMTYPE_CENTAUR) + { + PK_TRACE("Centaur_configuration. MSR:%08x",mfmsr()); + rc = gpe_centaur_configuration_create(G_membuf_config); + } + else if(payload->mem_type == MEMTYPE_OCMB) + { + PK_TRACE("Ocmb_configuration. MSR:%08x",mfmsr()); + rc = gpe_ocmb_configuration_create(G_membuf_config); + } + else + { + rc = GPE_RC_INVALID_MEMBUF_TYPE; + } + // Must set membuf_type AFTER config created! + G_membuf_config->membuf_type = payload->mem_type; + } + + payload->error.rc = rc; + + // Send response + rc = ipc_send_rsp(i_cmd, IPC_RC_SUCCESS); + if(rc) + { + PK_TRACE("gpe_membuf_init: Failed to send response. rc = %x. Halting GPE1.", + rc); + + gpe_set_ffdc(&(payload->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); + pk_halt(); + } +} + +void gpe_membuf_scom(ipc_msg_t* i_cmd, void* i_arg) +{ + static int g_log_once = 0; + int rc; + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)i_cmd; + MemBufScomParms_t * scomParms = (MemBufScomParms_t*)async_cmd->cmd_data; + + if(g_log_once == 0) + { + g_log_once = 1; + PK_TRACE("gpe_membuf_scom. MSR:%08x",mfmsr()); + } + gpe_inband_scom(G_membuf_config, scomParms); + + // Send response + rc = ipc_send_rsp(i_cmd, IPC_RC_SUCCESS); + if(rc) + { + PK_TRACE("gpe_membuf_scom: Failed to send response. rc = %x. Halting GPE1.", + rc); + + gpe_set_ffdc(&(scomParms->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); + pk_halt(); + } + + +} + +void gpe_membuf_data(ipc_msg_t* i_cmd, void* i_arg) +{ + static int g_log_once = 0; + int rc; + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)i_cmd; + + MemBufGetMemDataParms_t * dataParms = + (MemBufGetMemDataParms_t *)async_cmd->cmd_data; + + if(g_log_once == 0) + { + g_log_once = 1; + PK_TRACE("Centaur Data. MSR:%08x",mfmsr()); + } + if(G_membuf_config->membuf_type == MEMTYPE_CENTAUR) + { + rc = get_centaur_sensorcache(G_membuf_config, dataParms); + } + else + { + rc = get_ocmb_sensorcache(G_membuf_config, dataParms); + } + + dataParms->error.rc = rc; + + // Send response + rc = ipc_send_rsp(i_cmd, IPC_RC_SUCCESS); + if(rc) + { + PK_TRACE("gpe_membuf_data: Failed to send response. rc = %x. Halting GPE1.", + rc); + + gpe_set_ffdc(&(dataParms->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); + pk_halt(); + } +} + + diff --git a/src/occ_gpe1/gpe_membuf.h b/src/occ_gpe1/gpe_membuf.h new file mode 100644 index 0000000..39a4f53 --- /dev/null +++ b/src/occ_gpe1/gpe_membuf.h @@ -0,0 +1,177 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_gpe1/gpe_membuf.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#if !defined(_GPE_MEMBUF_H) +#define _GPE_MEMBUF_H + +#include "ipc_structs.h" +#include "membuf_structs.h" + + +// Which GPE controls the PBASLAVE +#define OCI_MASTER_ID_GPE1 1 + + +#define INBAND_ACCESS_READ 1 +#define INBAND_ACCESS_WRITE 2 + + +// IPC interface +void gpe_membuf_scom(ipc_msg_t* i_cmd, void* i_arg); +void gpe_membuf_data(ipc_msg_t* i_cmd, void* i_arg); +void gpe_membuf_init(ipc_msg_t* i_cmd, void* i_arg); + +// HCODE interfaces +/** + * Reset the PBA slave controller + * @param[in] pba_parms + */ +void pbaslvctl_reset(GpePbaParms* i_pba_parms); + +/** + * Configure the PBA Slave + * @param[in] pba_parms + */ +uint64_t pbaslvctl_setup(GpePbaParms* i_pba_parms); + + +/** + * Access the MEMBUF mmio over the PBA slave. + * @param[in] Memory buffer configuration + * @param[in] The membuf ordinal number + * @param[in] The OCI mapped address + * @param[io] The data to move + * @param[in] The operation to perform + */ +int inband_access(MemBufConfiguration_t* i_config, + uint32_t i_instance, + uint32_t i_oci_addr, + uint64_t * io_data, + int i_read_write); + +/** + * Populate the MemBufConfiguration object for Centaur + * @param[out] 8 byte aligned pointer to the CentaurConfiguration object. + * @return [0 | return code] + * @note The CentaurConfiguration object is shared with the 405 so + * it needs to be in non-cacheable sram. + */ +int gpe_centaur_configuration_create(MemBufConfiguration_t * o_config); + +/** + * Scom all of the membufs with the same SCOM address. + * @param[in] The CentaurConfig object + * @param[in] The SCOM address + * @param[out] The array of data collected. Must be large enough to hold + * uint64_t data from each membuf. + * @return [0 | return code] + */ +int membuf_get_scom_vector(MemBufConfiguration_t* i_config, + uint32_t i_scom_address, + uint64_t* o_data); + +/** + * Scom one or more membuf modules + * @param[in] The MemBufConfiguration object + * @param[in/out] The Scom Parms object + * @return The return code is part of the MemBufScomParms object + */ +void gpe_inband_scom(MemBufConfiguration_t* i_config, + MemBufScomParms_t* i_parms); + + +/** + * Collect the centaur thermal data + * @param[in] The CentaurConfig object + * @param[in/out] The Centaur data parm object + * @return [0 | return code] + */ +int get_centaur_sensorcache(MemBufConfiguration_t* i_config, + MemBufGetMemDataParms_t* i_parms); + +/** + * Check for channel checkstop + * @param[in] The ordinal centaur number + * @return [0 | return code] + */ +int check_centaur_channel_chkstp(unsigned int i_centaur); + +/** + * Send SYNC to centaur to effectuate the thottle values + * @param[in] the membuf configuration + */ +int centaur_throttle_sync(MemBufConfiguration_t* i_config); + +/** + * Create PBA slave configuration parameters. + * @param[in] ptr tor param data area to be filled out. + * @param[in] PBA slave to use. + * @param[in] write ttype (@see occhw_pba_common.h) + * @param[in] write tsize (@see occhw_pba_common.h) + * @param[in] read_ttype (@see occhw_pba_common.h) + * @return [SUCCESS | return code] + */ +int gpe_pba_parms_create(GpePbaParms* parms, + int slave, + int write_ttype, + int write_tsize, + int read_ttype); + +/** + * Configure the PBABAR for inband access + * @param[in] Configuration information + */ +int configure_pba_bar_for_inband_access(MemBufConfiguration_t * i_config); + + +extern uint32_t g_inband_access_state; + +/** + * Populate a CentaurConfiguration object for ocmb + * @param[out] 8 byte aligned pointer to the CentaurConfiguration object. + * @return [0 | return code] + * @note The CentaurConfiguration object is shared with the 405 so + * it needs to be in non-cacheable sram. + */ +int gpe_ocmb_configuration_create(MemBufConfiguration_t * o_config); + +/** + * Check for OCMBr sensor errors + * @param[in] Configuration information + * @param[in] The ordinal membuf number + * @return [0 | return code] + */ +int check_and_reset_mmio_fir(MemBufConfiguration_t * i_config,unsigned int i_membuf); + +/** + * Send SYNC to ocmb to effectuate the thottle values + * @param[in] the membuf configuration + */ +int ocmb_throttle_sync(MemBufConfiguration_t* i_config); + +int get_ocmb_sensorcache(MemBufConfiguration_t* i_config, + MemBufGetMemDataParms_t* i_parms); + + +#endif diff --git a/src/occ_gpe1/gpe_membuf_scom.c b/src/occ_gpe1/gpe_membuf_scom.c new file mode 100644 index 0000000..b27ab3f --- /dev/null +++ b/src/occ_gpe1/gpe_membuf_scom.c @@ -0,0 +1,605 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: chips/p9/procedures/lib/pm/membuf_scom.c $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* EKB Project */ +/* */ +/* COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include <stdint.h> +#include "gpe_membuf.h" +#include "gpe_pba_cntl.h" +#include "ppe42_scom.h" +#include "ppe42.h" +#include "pba_register_addresses.h" +#include "ppe42_msr.h" + +/** + * @file gpe_membuf_scom + * @brief scom access from gpe to a membuf + */ + +uint32_t g_inband_access_state = INBAND_ACCESS_INACTIVE; + +void swap_u64(uint64_t * data64) +{ + uint64_t val = *data64; + val = ((val << 8) & 0xff00ff00ff00ff00ULL) | ((val >> 8) & 0x00ff00ff00ff00ffULL); + val = ((val <<16) & 0xffff0000ffff0000ULL) | ((val >>16) & 0x0000ffff0000ffffULL); + *data64 = (val << 32) | (val >> 32); +} + +int inband_access(MemBufConfiguration_t* i_config, + uint32_t i_instance, + uint32_t i_oci_addr, + uint64_t * io_data, + int i_read_write) +{ + int rc = 0; + uint32_t org_msr = mfmsr(); + uint32_t msr = org_msr | MSR_SEM; // Mask off SIB from generating mck. + + g_inband_access_state = INBAND_ACCESS_IN_PROGRESS; + + if(i_read_write == INBAND_ACCESS_READ) + { + mtmsr(msr); + sync(); + PPE_LVD(i_oci_addr, *io_data); + + PK_TRACE("inband read %08x%08x from %08x", + (uint32_t)((*io_data)>>32), + (uint32_t)((*io_data)), + i_oci_addr); + if(i_config->membuf_type != MEMTYPE_CENTAUR) + { + swap_u64(io_data); + } + } + else + { + if(i_config->membuf_type != MEMTYPE_CENTAUR) + { + swap_u64(io_data); + } + // Set PPE to precise mode for stores so that in the case of a machine + // check, there is a predictable instruction address to resume on. + + msr &= ~MSR_IPE; + mtmsr(msr); + sync(); + + uint64_t data64 = *io_data; //This makes PPE_STVD generate better code + PPE_STVD(i_oci_addr, data64); + + PK_TRACE("inband write %08x%08x to %08x", + (uint32_t)((*io_data)>>32), + (uint32_t)((*io_data)), + i_oci_addr); + } + + // Poll SIB error or machine check + if((mfmsr() & MSR_SIBRC) || + g_inband_access_state != INBAND_ACCESS_IN_PROGRESS) + { + // Take membuf out of config + PK_TRACE("Removing MemBuf %d from list of configured MemBufs", + i_instance); + + i_config->config &= ~(CHIP_CONFIG_MEMBUF(i_instance)); + + // This will cause the 405 to remove the membuf sensor(s). + rc = MEMBUF_CHANNEL_CHECKSTOP; + } + g_inband_access_state = INBAND_ACCESS_INACTIVE; + mtmsr(org_msr); + return rc; +} + +/** + * Setup the PBASLVCTLN extended address and calculate the OCI scom address + * @param[in] PBA base address + * @param[in] The inband scom address + * @returns the mapped OCI address to scom the membuf + * @Post The extended address field in the PBASLVCNT is set + */ +int inband_scom_setup(MemBufConfiguration_t* i_config, + uint32_t i_membuf_instance, + uint32_t i_scom_address, + uint32_t *o_oci_addr) +{ + int rc = 0; + uint32_t scom_address = i_scom_address; + // TODO use PBASLV in P10 +#if defined(__USE_PBASLV__) + pba_slvctln_t slvctln; +#endif + uint64_t pb_addr = i_config->baseAddress[i_membuf_instance]; + + if(i_config->membuf_type == MEMTYPE_CENTAUR) + { + // Break address into componets + uint32_t local = i_scom_address & 0x00001fff; + uint32_t port = i_scom_address & 0x000f0000; + uint32_t slave = i_scom_address & 0x03000000; + uint32_t multi = i_scom_address & 0xc0000000; + + // compress to 21 bits for P9 + scom_address = + local + + (port >> 3) + + (slave >> 7) + + (multi >> 11); + // P9: Turn on bit 38 to indicate OCC + pb_addr |= 0x0000000002000000ull; + } + pb_addr |= ((uint64_t)scom_address << 3); + +#if defined(__USE_PBASLV__) + // put bits 23:36 of address into slvctln extended addr + PPE_LVD((i_config->scomParms).slvctl_address, slvctln.value); + slvctln.fields.extaddr = pb_addr >> 27; + PPE_STVD((i_config->scomParms).slvctl_address, slvctln.value); +#else + // TODO P9 HW bug work-around - Use PBASLV in P10 + { + // workaround - don't use extraddr - use pbabar. + uint64_t barMsk = 0; + + // Mask SIB from generating mck + mtmsr(mfmsr() | MSR_SEM); + + // put the PBA in the BAR + rc = putscom_abs(PBA_BARN(PBA_BAR_MEMBUF), pb_addr & 0x00fffffffff00000ull); + if(rc) + { + PK_TRACE("inband_scom_setup. putscom fail on PBABAR." + " rc = %d",rc); + } + else + { + rc = putscom_abs(PBA_BARMSKN(PBA_BAR_MEMBUF), barMsk); + if(rc) + { + PK_TRACE("inband_scom_setup. putscom fail on PBABARMSK" + " rc = %d",rc); + } + } + } +#endif + // make oci address + *o_oci_addr = (uint32_t)(pb_addr & 0x07ffffffull); + + // upper nibble is PBA region and BAR_SELECT + *o_oci_addr |= ((PBA_BAR_MEMBUF | 0x8) << 28); + PK_TRACE_DBG("OCI mapped scom addr: %08x",*o_oci_addr); + return rc; +} + +void pbaslvctl_reset(GpePbaParms* i_pba_parms) +{ + uint64_t val = 0; + + do + { + PPE_STVD(PBA_SLVRST, i_pba_parms->slvrst.value); + PPE_LVD(PBA_SLVRST, val); + val &= i_pba_parms->slvrst_in_progress.value; + } + while(val != 0); +} + +uint64_t pbaslvctl_setup(GpePbaParms* i_pba_parms) +{ + uint64_t slvctl_val; + uint64_t slvctl_val_org; + PPE_LVD(i_pba_parms->slvctl_address, slvctl_val_org); + slvctl_val = slvctl_val_org; + slvctl_val &= i_pba_parms->mask.value; + slvctl_val |= i_pba_parms->slvctl.value; + PPE_STVD(i_pba_parms->slvctl_address, slvctl_val); + return slvctl_val_org; +} + +// Get data from each existing membuf. +int membuf_get_scom_vector(MemBufConfiguration_t* i_config, + uint32_t i_scom_address, + uint64_t* o_data) +{ + int rc = 0; + int access_rc = 0; + int pba_rc = 0; + int instance = 0; + uint64_t pba_slvctln_save; + + pbaslvctl_reset(&(i_config->scomParms)); + pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); + + // clear SIB errors in MSR + mtmsr((mfmsr() & ~(MSR_SIBRC | MSR_SIBRCA))); + + for(instance = 0; instance < OCCHW_N_MEMBUF; ++instance) + { + if( CHIP_CONFIG_MEMBUF(instance) & (i_config->config)) + { + uint32_t oci_addr; + pba_rc = inband_scom_setup(i_config, + instance, + i_scom_address, + &oci_addr); + + if(pba_rc) + { + rc = pba_rc; + // Already traced. + // Trumps any access error + *o_data = 0; + } + else + { + // inband scom read + access_rc = inband_access(i_config, + instance, + oci_addr, + o_data, + INBAND_ACCESS_READ); + // only set access_rc if rc not already set. + if(!rc && access_rc) + { + // not critical, but don't access this membuf again. + rc = access_rc; + *o_data = 0; + // continue with next instance + } + } + } + else + { + *o_data = 0; + } + + ++o_data; + } + + // gpe_pba_cntl function? + pbaslvctl_reset(&(i_config->scomParms)); + PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); + + return rc; +} + +int membuf_get_scom(MemBufConfiguration_t* i_config, + int i_membuf_instance, + uint32_t i_scom_address, + uint64_t* o_data) +{ + int rc = 0; + uint32_t oci_addr; + uint64_t pba_slvctln_save; + + pbaslvctl_reset(&(i_config->scomParms)); + pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); + + rc = inband_scom_setup(i_config, + i_membuf_instance, + i_scom_address, + &oci_addr); + + if( !rc && (CHIP_CONFIG_MEMBUF(i_membuf_instance) & (i_config->config))) + { + // read membuf scom + rc = inband_access(i_config, + i_membuf_instance, + oci_addr, + o_data, + INBAND_ACCESS_READ); + } + else + { + *o_data = 0; + } + + // gpe_pba_cntl function? + pbaslvctl_reset(&(i_config->scomParms)); + PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); + + return rc; +} + + +// Write all configured membuf with the same data +int membuf_put_scom_all(MemBufConfiguration_t* i_config, + uint32_t i_scom_address, + uint64_t i_data) +{ + int rc = 0; + int pba_rc = 0; + int access_rc = 0; + int instance = 0; + uint64_t pba_slvctln_save; + + pbaslvctl_reset(&(i_config->scomParms)); + pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); + + for(instance = 0; instance < OCCHW_N_MEMBUF; ++instance) + { + if( CHIP_CONFIG_MEMBUF(instance) & (i_config->config)) + { + uint32_t oci_addr; + pba_rc = inband_scom_setup(i_config, + instance, + i_scom_address, + &oci_addr); + + if(pba_rc) + { + // Already traced in inband_scom_setup + // Trumps access_rc + rc = pba_rc; + } + else + { + // membuf scom + access_rc = inband_access(i_config, + instance, + oci_addr, + &i_data, + INBAND_ACCESS_WRITE); + // Only set access_rc if rc not already set + if(!rc && access_rc) + { + // This MemBuf won't be touched again. + rc = access_rc; + // continue with next instance + } + } + } + } + + // reset pba slave + pbaslvctl_reset(&(i_config->scomParms)); + PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); + + return rc; +} + +int membuf_put_scom(MemBufConfiguration_t* i_config, + int i_membuf_instance, + uint32_t i_scom_address, + uint64_t i_data) +{ + int rc = 0; + uint32_t oci_addr; + uint64_t pba_slvctln_save; + + pbaslvctl_reset(&(i_config->scomParms)); + pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); + + rc = inband_scom_setup(i_config, + i_membuf_instance, + i_scom_address, + &oci_addr); + + if(!rc) + { + if(CHIP_CONFIG_MEMBUF(i_membuf_instance) & (i_config->config)) + { + // write membuf scom + rc = inband_access(i_config, + i_membuf_instance, + oci_addr, + &i_data, + INBAND_ACCESS_WRITE); + } + } + + // reset pba slave + pbaslvctl_reset(&(i_config->scomParms)); + PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); + + return rc; +} + +// write x +int membuf_scom_rmw(MemBufConfiguration_t* i_config, + int i_membuf_instance, + uint32_t i_scom_address, + uint64_t i_mask, + uint64_t* i_data) +{ + int rc = 0; + uint32_t oci_addr; + uint64_t pba_slvctln_save; + uint64_t data64; + + pbaslvctl_reset(&(i_config->scomParms)); + pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); + + rc = inband_scom_setup(i_config, + i_membuf_instance, + i_scom_address, + &oci_addr); + if(!rc) + { + + rc = inband_access(i_config, + i_membuf_instance, + oci_addr, + &data64, + INBAND_ACCESS_READ); + + if(!rc) + { + data64 &= (i_mask ^ 0xffffffffffffffffull); + data64 |= *i_data; + + rc = inband_access(i_config, + i_membuf_instance, + oci_addr, + &data64, + INBAND_ACCESS_WRITE); + } + } + + pbaslvctl_reset(&(i_config->scomParms)); + PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); + + return rc; +} + + +int membuf_scom_rmw_all(MemBufConfiguration_t* i_config, + uint32_t i_scom_address, + uint64_t i_mask, + uint64_t i_data) +{ + int rc = 0; + int pba_rc = 0; + int access_rc = 0; + int instance = 0; + uint64_t pba_slvctln_save; + + pbaslvctl_reset(&(i_config->scomParms)); + pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms)); + + for(instance = 0; (instance < OCCHW_N_MEMBUF); ++instance) + { + if( CHIP_CONFIG_MEMBUF(instance) & (i_config->config)) + { + uint64_t data64; + uint32_t oci_addr; + pba_rc = inband_scom_setup(i_config, + instance, + i_scom_address, + &oci_addr); + if(pba_rc) + { + rc = pba_rc; + // Already traced in inband_scom_setup + // Trumps any access_rc + } + if(!pba_rc) + { + + access_rc = inband_access(i_config, + instance, + oci_addr, + &data64, + INBAND_ACCESS_READ); + + if(!access_rc) + { + data64 &= (i_mask ^ 0xffffffffffffffffull); + data64 |= i_data; + + access_rc = inband_access(i_config, + instance, + oci_addr, + &data64, + INBAND_ACCESS_WRITE); + } + } + if(!rc && access_rc) + { + rc = access_rc; + } + + pbaslvctl_reset(&(i_config->scomParms)); + } + } + + PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save); + + return rc; +} + + + +// MemBufConfiguration needs to be setup before this is called +void gpe_inband_scom(MemBufConfiguration_t* i_config, + MemBufScomParms_t* i_parms) +{ + int i; + int rc = 0; + mtmsr((mfmsr() & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM); + + for(i = 0; i < i_parms->entries; ++i) + { + switch(i_parms->scomList[i].commandType) + { + case MEMBUF_SCOM_NOP: + break; + + case MEMBUF_SCOM_READ: + rc =membuf_get_scom(i_config, + i_parms->scomList[i].instanceNumber, + i_parms->scomList[i].scom, + &(i_parms->scomList[i].data)); + break; + + case MEMBUF_SCOM_WRITE: + rc = membuf_put_scom(i_config, + i_parms->scomList[i].instanceNumber, + i_parms->scomList[i].scom, + i_parms->scomList[i].data); + break; + + case MEMBUF_SCOM_RMW: + rc = membuf_scom_rmw(i_config, + i_parms->scomList[i].instanceNumber, + i_parms->scomList[i].scom, + i_parms->scomList[i].mask, + &(i_parms->scomList[i].data)); + break; + + case MEMBUF_SCOM_READ_VECTOR: + rc = membuf_get_scom_vector(i_config, + i_parms->scomList[i].scom, + i_parms->scomList[i].pData + ); + break; + + case MEMBUF_SCOM_WRITE_ALL: + rc = membuf_put_scom_all(i_config, + i_parms->scomList[i].scom, + i_parms->scomList[i].data); + break; + + case MEMBUF_SCOM_RMW_ALL: + rc = membuf_scom_rmw_all(i_config, + i_parms->scomList[i].scom, + i_parms->scomList[i].mask, + i_parms->scomList[i].data); + break; + + case MEMBUF_SCOM_MEMBUF_SYNC: + if( i_config->membuf_type == MEMTYPE_CENTAUR) + { + rc = centaur_throttle_sync(i_config); + } + else + { + rc = ocmb_throttle_sync(i_config); + } + break; + + default: + break; + }; + if (rc) + { + break; + } + } + i_parms->error.rc = rc; +} diff --git a/src/occ_gpe1/gpe_ocmb.c b/src/occ_gpe1/gpe_ocmb.c new file mode 100644 index 0000000..dfe7d89 --- /dev/null +++ b/src/occ_gpe1/gpe_ocmb.c @@ -0,0 +1,630 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_gpe1/gpe_ocmb.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include "gpe_membuf.h" +#include "ppe42_scom.h" +#include "pk.h" +#include "ppe42_msr.h" +#include "occhw_pba_common.h" +#include "p9a_misc_scom_addresses.h" +#include "p9a_firmware_registers.h" +#include "ocmb_register_addresses.h" +#include "ocmb_firmware_registers.h" +#include "ocmb_mem_data.h" + +const uint32_t AXONE_MCFGPR[OCCHW_N_MEMBUF] = +{ + P9A_MI_0_MCFGPR0, + P9A_MI_0_MCFGPR1, + P9A_MI_1_MCFGPR0, + P9A_MI_1_MCFGPR1, + P9A_MI_2_MCFGPR0, + P9A_MI_2_MCFGPR1, + P9A_MI_3_MCFGPR0, + P9A_MI_3_MCFGPR1 +}; + +const uint32_t AXONE_MCSYNC[OCCHW_N_MEMBUF/2] = +{ + P9A_MI_0_MCSYNC, + P9A_MI_1_MCSYNC, + P9A_MI_2_MCSYNC, + P9A_MI_3_MCSYNC +}; + +// This table was taken from ekb p9a_omi_setup_bars.C +const int NUM_EXT_MASKS = 20; +const uint8_t EXT_MASK_REORDER[][9] = // Workbook table 7 +{ + // B 6 7 8 9 10 11 12 13 + { 0x00, 15, 18, 16, 17, 21, 20, 19, 14 }, + { 0x04, 15, 18, 16, 17, 21, 20, 14, 19 }, + { 0x06, 15, 18, 16, 17, 21, 14, 20, 19 }, + { 0x07, 15, 18, 16, 17, 14, 21, 20, 19 }, + { 0x80, 15, 18, 16, 17, 21, 20, 19, 14 }, + { 0x84, 15, 18, 16, 17, 21, 20, 14, 19 }, + { 0x86, 15, 18, 16, 17, 21, 14, 20, 19 }, + { 0x87, 15, 18, 16, 17, 14, 21, 20, 19 }, + { 0xC0, 15, 21, 17, 18, 20, 19, 14, 16 }, + { 0xC4, 15, 21, 17, 18, 20, 14, 19, 16 }, + { 0xC6, 15, 21, 17, 18, 14, 20, 19, 16 }, + { 0xC7, 15, 14, 17, 18, 21, 20, 19, 16 }, + { 0xE0, 15, 20, 18, 21, 19, 14, 17, 16 }, + { 0xE4, 15, 20, 18, 21, 14, 19, 17, 16 }, + { 0xE6, 15, 14, 18, 21, 20, 19, 17, 16 }, + { 0xE7, 15, 21, 18, 14, 20, 19, 17, 16 }, + { 0xF0, 15, 19, 21, 20, 14, 18, 17, 16 }, + { 0xF4, 15, 14, 21, 20, 19, 18, 17, 16 }, + { 0xF6, 15, 20, 21, 14, 19, 18, 17, 16 }, + { 0xF7, 15, 20, 14, 21, 19, 18, 17, 16 } +}; + +int inband_scom_setup(MemBufConfiguration_t* i_config, + uint32_t i_membuf_instance, + uint32_t i_scom_address, + uint32_t *o_oci_addr); + +int membuf_get_scom(MemBufConfiguration_t* i_config, + int i_membuf_instance, + uint32_t i_scom_address, + uint64_t* o_data); + +int membuf_put_scom(MemBufConfiguration_t* i_config, + int i_membuf_instance, + uint32_t i_scom_address, + uint64_t i_data); + +void swap_u32(uint32_t * data32) +{ + uint32_t val = *data32; + val = ((val << 8) & 0xff00ff00) | ((val >> 8) & 0x00ff00ff); + *data32 = (val << 16) | (val >> 16); +} + + +int ocmb_check_sensor_cache_enabled(MemBufConfiguration_t * i_config, + int i_instance) +{ + int rc = 0; + mmio_merrctl_t merrctl; + + rc = membuf_get_scom(i_config, + i_instance, + MMIO_MERRCTL, + &(merrctl.value)); + if(rc) + { + PK_TRACE("OCMB MERRCTL getscom failed. rc = %d", + (uint16_t)rc); + } + else + { + //PK_TRACE("1MERRCTL: %08x%08x", + // merrctl.words.high_order, + // merrctl.words.low_order); + if(merrctl.fields.snsc_master_enable == SNSC_MASTER_DISABLED) + { + // attempted to enable it + merrctl.fields.snsc_master_enable = SNSC_MASTER_ENABLED; + rc = membuf_put_scom(i_config, + i_instance, + MMIO_MERRCTL, + merrctl.value); + if(rc) + { + PK_TRACE("OCMB MERRCTL putscom failed. rc = %d", + (uint16_t)rc); + } + //PK_TRACE("2MERRCTL: %08x%08x", + // merrctl.words.high_order, + // merrctl.words.low_order); + } + + } + return rc; +} + +int gpe_ocmb_configuration_create(MemBufConfiguration_t* o_config) +{ + int rc = 0; + int i = 0; + int l_rule = 0; + int l_ext_addr_mask = 0; + int designated_sync = -1; + mcfgpr_t mcfgpr; + pb_mode_t pb_mode; + uint64_t* ptr = (uint64_t*)o_config; + + // Prevent unwanted interrupts from scom errors + // Enable store Gathering, and Icache prefetch for performance. + const uint32_t orig_msr = mfmsr(); + mtmsr((orig_msr & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM | MSR_IS1 | MSR_IS2 ); + sync(); + + for(i = 0; i < sizeof(MemBufConfiguration_t) / 8; ++i) + { + *ptr++ = 0ull; + } + + o_config->configRc = MEMBUF_NOT_CONFIGURED; + o_config->membuf_type = MEMTYPE_OCMB; + + do + { + // Create the PBASLV configuration for collecting sensor data. + rc = gpe_pba_parms_create(&(o_config->dataParms), + PBA_SLAVE_MEMBUF, + PBA_WRITE_TTYPE_CI_PR_W, + PBA_WRITE_TTYPE_DC, + PBA_READ_TTYPE_CI_PR_RD); + + if (rc) + { + rc = MEMBUF_DATA_SETUP_ERROR; + break; + } + + // create the PBASLV configuration for doing inband scoms. + rc = gpe_pba_parms_create(&(o_config->scomParms), + PBA_SLAVE_MEMBUF, + PBA_WRITE_TTYPE_CI_PR_W, + PBA_WRITE_TTYPE_DC, + PBA_READ_TTYPE_CI_PR_RD); + if (rc) + { + rc = MEMBUF_SCOM_SETUP_ERROR; + break; + } + + // On Ocmb the mmio bar value has been swizzled + // Need to un-swizzle + rc = getscom_abs(P9A_PU_NMMU_MMCQ_PB_MODE_REG, &(pb_mode.value)); + if( rc ) + { + PK_TRACE("Scom failed on PB_MODE_REG. rc = %d", + rc); + rc = MEMBUF_PBMODE_GETSCOM_FAILURE; + break; + } + + l_ext_addr_mask = pb_mode.fields.addr_extension_group_id << 4; + l_ext_addr_mask |= pb_mode.fields.addr_extension_chip_id; + + // bits [6:13] in mmio bar have been rearranged - look up translation + // rule. + for(l_rule = 0; l_rule < NUM_EXT_MASKS; ++l_rule) + { + if(EXT_MASK_REORDER[l_rule][0] == l_ext_addr_mask) // found + { + break; + } + } + + if(l_rule == NUM_EXT_MASKS) // rule not found. + { + PK_TRACE("Failed to find match for %x in EXT_MASK_REORDER", + l_ext_addr_mask); + rc = MEMBUF_PMODE_DATA_MISMATCH; + break; + } + + // Find all configured MEMBUFs + for (i = 0; i < OCCHW_N_MEMBUF; ++i) + { + uint64_t l_pba_addr = 0; + uint32_t l_mmio_bar = 0; + + rc = getscom_abs(AXONE_MCFGPR[i], &(mcfgpr.value)); + + if( rc ) + { + rc = 0; // Can't be scommed then ignore this MEMBUF + continue; + } + + if(!mcfgpr.fields.mmio_valid) + { + continue; // MEMBUF MMIOBAR not configured, ignore MEMBUF + } + + l_mmio_bar = + (uint32_t)(mcfgpr.fields.mmio_group_base_addr) << 1; + PK_TRACE("Ocmb[%d] MMIO Bar: %08x", i, l_mmio_bar); + + // The mmio bar has been swizzled, It needs to be unswizzled. + // Make this easy for PPE 32 bit arch. + + uint32_t l_mask = 0x02000000; //Start bit 6 + uint32_t l_reordered = 0; + int l_col; + + for(l_col = 1; l_col < 9; ++l_col) + { + if((l_mask & l_mmio_bar) != 0) + { + uint32_t l_setbit = 0x80000000 >> + EXT_MASK_REORDER[l_rule][l_col]; + l_reordered |= l_setbit; + } + + l_mask >>= 1; + } + l_mmio_bar &= 0xfc03ffff; //mask off bits 6-13 + l_mmio_bar |= (l_reordered << 8); + + l_pba_addr = (uint64_t)(l_mmio_bar) << 32; + + // The 31-bit base-address (inband scom BAR) corresponds + // to bits [8:38] of the Power Bus addresss + l_pba_addr >>= 8; + + if((i % 2) != 0) + { + l_pba_addr |= OCMB_IB_BAR_B_BIT; + } + + PK_TRACE("MMIO Base Address: 0x%08x%08x on ocmb %d", + (uint32_t)(l_pba_addr >> 32), + (uint32_t)(l_pba_addr), + i); + + o_config->baseAddress[i] = l_pba_addr; + // Add this membuf to the configuration + o_config->config |= (CHIP_CONFIG_MCS(i) | CHIP_CONFIG_MEMBUF(i)); + } + + if( rc ) + { + break; + } + + // Find the designated sync. + // Find the register that HWPs used to sync the throttle n/m values + // accross all membufs. Only one register should be setup. + for (i = 0; i < (OCCHW_N_MEMBUF/2); ++i) + { + uint64_t mcsync; + rc = getscom_abs(AXONE_MCSYNC[i], &mcsync); + if (rc) + { + PK_TRACE("getscom failed on MCSYNC, rc = %d. The first configured " + "MC will be the designated sync",rc); + rc = 0; + } + if (mcsync != 0) + { + designated_sync = i; + // There can only be one sync, so stop searching. + break; + } + } + + if (designated_sync < 0) + { + // Leave mcSyncAddr zero. + PK_TRACE("No designated sync found. Ocmb sync disabled."); + } + else + { + o_config->mcSyncAddr = AXONE_MCSYNC[designated_sync]; + } + + if(o_config->config != 0) + { + rc = configure_pba_bar_for_inband_access(o_config); + + if( rc ) + { + break; + } + } + + if(!rc) + { + for(i = 0; i < OCCHW_N_MEMBUF; ++i) + { + if( CHIP_CONFIG_MEMBUF(i) & (o_config->config)) + { + // Attempt to reset any SCACHE FIR errors + // and insure the SCACHE is enabled + check_and_reset_mmio_fir(o_config, i); + ocmb_check_sensor_cache_enabled(o_config,i); + } + } + + // Find out which DTS are present + OcmbMemData escache; + MemBufGetMemDataParms_t l_parms; + + l_parms.update = -1; + l_parms.data = (uint64_t *)(&escache); + + for(i = 0; i < OCCHW_N_MEMBUF; ++i) + { + if( CHIP_CONFIG_MEMBUF(i) & (o_config->config)) + { + l_parms.collect = i; + rc = get_ocmb_sensorcache(o_config, &l_parms); + if( rc ) + { + PK_TRACE("gpe_ocmb_configuration_create failed to" + " get sensorcache for MEMBUF %d, rc = %d.", + i, rc); + continue; // Thermal sensors not available. + } + + if(escache.status.fields.ubdts0_present) + { + o_config->dts_config |= CONFIG_UBDTS0(i); + } + if(escache.status.fields.memdts0_present) + { + o_config->dts_config |= CONFIG_MEMDTS0(i); + } + if(escache.status.fields.memdts1_present) + { + o_config->dts_config |= CONFIG_MEMDTS1(i); + } + PK_TRACE("Ocmb dts_config: %08x",o_config->dts_config); + } + } + } + + } + while( 0 ); + + o_config->configRc = rc; + + mtmsr(orig_msr); + + return rc; +} + +int check_and_reset_mmio_fir(MemBufConfiguration_t* i_config, unsigned int i_membuf) +{ + int rc = 0; + mmio_mfir_t mfir; + + rc = membuf_get_scom(i_config, i_membuf, MMIO_MFIR, &(mfir.value)); + if(rc) + { + PK_TRACE("check_and_reset_mmio_fir mmio scom fail. rc = %d",rc); + } + else + { + + // Check for bits 7,8,9,10 + if(mfir.fields.snsc_both_starts_err || + mfir.fields.snsc_mult_seq_perr || + mfir.fields.snsc_fsm_perr || + mfir.fields.snsc_reg_perr) + { + PK_TRACE("ocmb mmio fir: 0x%08x%08x", + mfir.words.high_order, + mfir.words.low_order); + + rc = MEMBUF_SCACHE_ERROR; + + mfir.value = 0xffffffffffffffffull; + mfir.fields.snsc_both_starts_err = 0; + mfir.fields.snsc_mult_seq_perr = 0; + mfir.fields.snsc_fsm_perr = 0; + mfir.fields.snsc_reg_perr = 0; + membuf_put_scom(i_config, i_membuf, MMIO_MFIR_AND, mfir.value); + } + } + + return rc; +} + +int ocmb_throttle_sync(MemBufConfiguration_t* i_config) +{ + // see + // https://farm3802.rtp.stglabs.ibm.com/regdb/entire_table.php?db=FIGDB_cb1_25_36_DB&name=MB_SIM.SRQ.MBA_FARB3Q + // SYNC only needed if OCMB_MBA_FARB3Q bit cfg_nm_change_after_sync is set. + // HWP programs this. + // Ocmb may not need to sync as it only has one FARB3Q reg to write. + uint64_t data; + int rc = 0; + do + { + // No designated sync addr, therefore Sync not needed. + if(i_config->mcSyncAddr == 0) + { + break; + } + + rc = getscom_abs(i_config->mcSyncAddr,&data); + if (rc) + { + PK_TRACE("ocmb_throttle_sync: getscom failed. rc = %d",rc); + break; + } + + data &= ~MCS_MCSYNC_SYNC_GO; + + rc = putscom_abs(i_config->mcSyncAddr, data); + if (rc) + { + PK_TRACE("ocmb_throttle_sync: reset sync putscom failed. rc = %d",rc); + break; + } + + data |= MCS_MCSYNC_SYNC_GO; + + rc = putscom_abs(i_config->mcSyncAddr, data); + if (rc) + { + PK_TRACE("ocmb_throttle_sync: set sync putscom failed. rc = %d",rc); + break; + } + } while (0); + + return rc; +} + +void extract_32b(uint32_t oci_addr, uint64_t * i_dest_addr) +{ + typedef union + { + uint64_t v; + struct + { + uint32_t h; + uint32_t l; + } w; + } data64_t; + + data64_t data64; + uint32_t * dest_addr = (uint32_t *)i_dest_addr; + PkMachineContext ctx; + + pk_critical_section_enter(&ctx); + // Invalidate the cache block at oci_addr + asm volatile ("dcbi 0, %0" : : "r" (oci_addr) : "memory"); + + // The first load causes the PBA bridge to fetch the 32 byte sensor cache + // and place it in the PPE42 data cache. The PPE42 cache must not be + // invalidated by any other load(s) until all 32 bytes have been read. + // Note: A store does a store-through and won't invalidate the data cache. + + asm volatile ("lvd %[d], 0(%[a])\n" : [d]"=r"(data64.v) : [a]"b"(oci_addr)); + dest_addr[7] = data64.w.h; + dest_addr[6] = data64.w.l; + + asm volatile ("lvd %[d], 8(%[a])\n" : [d]"=r"(data64.v) : [a]"b"(oci_addr)); + dest_addr[5] = data64.w.h; + dest_addr[4] = data64.w.l; + + asm volatile ("lvd %[d], 16(%[a])\n" : [d]"=r"(data64.v) : [a]"b"(oci_addr)); + dest_addr[3] = data64.w.h; + dest_addr[2] = data64.w.l; + + asm volatile ("lvd %[d], 24(%[a])\n" : [d]"=r"(data64.v) : [a]"b"(oci_addr)); + dest_addr[1] = data64.w.h; + dest_addr[0] = data64.w.l; + sync(); + pk_critical_section_exit(&ctx); +} + +int get_ocmb_sensorcache(MemBufConfiguration_t* i_config, + MemBufGetMemDataParms_t* i_parms) +{ + int rc = 0; + uint64_t pba_slvctln_save; + + i_parms->error.rc = MEMBUF_GET_MEM_DATA_DIED; + + pbaslvctl_reset(&(i_config->dataParms)); + pba_slvctln_save = pbaslvctl_setup(&(i_config->dataParms)); + + // Clear SIB error accumulator bits & mask SIB errors from + // generating machine checks + mtmsr((mfmsr() & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM); + + //collect has the ordinal # of the membuf from which to collect the + //sensor cache. + if(i_parms->collect != -1) + { + if((i_parms->collect >= OCCHW_N_MEMBUF) || + (0 == (CHIP_CONFIG_MEMBUF(i_parms->collect) & (i_config->config)))) + { + rc = MEMBUF_GET_MEM_DATA_COLLECT_INVALID; + } + else + { + uint32_t oci_addr = 0; + + int rc1 = check_and_reset_mmio_fir(i_config, i_parms->collect); + int rc2 = ocmb_check_sensor_cache_enabled(i_config, + i_parms->collect); + + if(rc2) + { + rc = rc2; // mmio scom fail + } + else if (rc1) + { + rc = rc1; //mmio scom fail or MEMBUF_SCACHE_ERROR; + } + else + { + + // NOTE: inband_scom_setup can be used to map the oci_addr so + // long as i_config->dataParms and i_config->scomParms are the, + // same, which for ocmb is currently true. + rc = inband_scom_setup(i_config, + i_parms->collect, + OCMB_IB_SENSOR_CACHE_ADDR, + &oci_addr); + + if(!rc) + { + uint32_t org_msr = mfmsr(); + // Mask off SIB errors from gen mck and set data cache enable, + // Enable Store Gathering, and Icache prefetch + mtmsr(org_msr | MSR_SEM | MSR_IS0 | MSR_IS1 | MSR_IS2); + sync(); + g_inband_access_state = INBAND_ACCESS_IN_PROGRESS; + + extract_32b(oci_addr,(i_parms->data)); //packet0 + extract_32b(oci_addr + 32, (i_parms->data) + 4); //packet1 + + // Poll for SIB errors or machine check + if((mfmsr() & MSR_SIBRC) || + g_inband_access_state != INBAND_ACCESS_IN_PROGRESS) + { + // Take membuf out of config list + PK_TRACE("Removing Membuf %d from list of configured Membufs", + i_parms->collect); + i_config->config &= ~(CHIP_CONFIG_MEMBUF(i_parms->collect)); + + // This rc will cause the 405 to remove this centaur sensor + rc = MEMBUF_CHANNEL_CHECKSTOP; + } + mtmsr(org_msr); + g_inband_access_state = INBAND_ACCESS_INACTIVE; + + // Finish making data big-endian + uint32_t * p = (uint32_t *)(i_parms->data); + int i; + for(i=0; i < 16; ++i) + { + swap_u32(p); + ++p; + } + } + } + } + } + // if(i_parms->update != -1) {} -- not used for Ocmb + + pbaslvctl_reset(&(i_config->dataParms)); + PPE_STVD((i_config->dataParms).slvctl_address, pba_slvctln_save); + + i_parms->error.rc = rc; + return rc; +} + + diff --git a/src/occ_gpe1/ipc_func_tables.c b/src/occ_gpe1/ipc_func_tables.c index abc1575..8ee7cd0 100644 --- a/src/occ_gpe1/ipc_func_tables.c +++ b/src/occ_gpe1/ipc_func_tables.c @@ -26,7 +26,7 @@ #include "ipc_async_cmd.h" #include "gpe1_dimm.h" #include "gpu_structs.h" -#include "gpe_centaur.h" +#include "gpe_membuf.h" void gpe_dimm_control(ipc_msg_t* cmd, void* arg); void gpe1_nop(ipc_msg_t* cmd, void* arg); @@ -86,9 +86,9 @@ IPC_HANDLER(gpe_24x7, 0) // 4 - IPC_ST_24_X_7_FUNCID IPC_HANDLER(gpe_mem_power_control, 0) // 5 - IPC_ST_MEM_POWER_CONTROL_FUNCID IPC_HANDLER(gpe_gpu_sm, 0) // 6 - IPC_ST_GPU_SM_FUNCID IPC_HANDLER(gpe_gpu_init, 0) // 7 - IPC_ST_GPE_GPU_INIT_FUNCID -IPC_HANDLER(gpe_centaur_scom, 0) // 8 - IPC_ST_CENTAUR_SCOM_FUNCID -IPC_HANDLER(gpe_centaur_data, 0) // 9 - IPC_ST_CENTAUR_DATA_FUNCID -IPC_HANDLER(gpe_centaur_init, 0) // 10 -IPC_ST_CENTAUR_INIT_FUNCID +IPC_HANDLER(gpe_membuf_scom, 0) // 8 - IPC_ST_MEMBUF_SCOM_FUNCID +IPC_HANDLER(gpe_membuf_data, 0) // 9 - IPC_ST_MEMBUF_DATA_FUNCID +IPC_HANDLER(gpe_membuf_init, 0) // 10 -IPC_ST_MEMBUF_INIT_FUNCID IPC_HANDLER(gpe_scom_nvdimms_nimbus, 0) // 11 -IPC_ST_EPOW_GPIO_ASSERT_FUNCID IPC_HANDLER_DEFAULT // 12 IPC_HANDLER_DEFAULT // 13 diff --git a/src/occ_gpe1/link.cmd b/src/occ_gpe1/link.cmd index ae41e28..67de73f 100644 --- a/src/occ_gpe1/link.cmd +++ b/src/occ_gpe1/link.cmd @@ -27,7 +27,7 @@ #undef powerpc #ifndef INITIAL_STACK_SIZE -#define INITIAL_STACK_SIZE 256 +#define INITIAL_STACK_SIZE 512 #endif OUTPUT_FORMAT(elf32-powerpc); diff --git a/src/occ_gpe1/occ_gpe1_machine_check_handler.c b/src/occ_gpe1/occ_gpe1_machine_check_handler.c index 33424c6..53780f7 100644 --- a/src/occ_gpe1/occ_gpe1_machine_check_handler.c +++ b/src/occ_gpe1/occ_gpe1_machine_check_handler.c @@ -1,5 +1,29 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_gpe1/occ_gpe1_machine_check_handler.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ #include "pk_panic_codes.h" -#include "gpe_centaur.h" +#include "gpe_membuf.h" #include "pk.h" #define OCI_ADDR_BAR_MASK 0xf0000000 @@ -8,7 +32,7 @@ extern uint32_t gpe1_machine_check_handler(uint32_t srr0, uint32_t srr1, uint32_t edr); -extern uint32_t g_centaur_access_state; +extern uint32_t g_inband_access_state; uint32_t gpe1_machine_check_handler(uint32_t srr0, uint32_t srr1, @@ -20,15 +44,15 @@ uint32_t gpe1_machine_check_handler(uint32_t srr0, edr); // It's possible to get back-to-back machine checks for the same condition - // so CENTAUR_CHANNEL_CHECKSTOP may already be set. Also check that the - // machine check was due to a Centaur Access (PBABAR1) - if((g_centaur_access_state == CENTAUR_ACCESS_IN_PROGRESS || - g_centaur_access_state == CENTAUR_CHANNEL_CHECKSTOP) && + // so MEMBUF_CHANNEL_CHECKSTOP may already be set. Also check that the + // machine check was due to a MEMBUF PBA Access (PBABAR1) + if((g_inband_access_state == INBAND_ACCESS_IN_PROGRESS || + g_inband_access_state == MEMBUF_CHANNEL_CHECKSTOP) && ((edr & OCI_ADDR_BAR_MASK) == OCI_ADDR_BAR1)) { // Returning this to OCC405 will cause sensor to be removed from // active list - g_centaur_access_state = CENTAUR_CHANNEL_CHECKSTOP; + g_inband_access_state = MEMBUF_CHANNEL_CHECKSTOP; // The instruction that caused the machine check should // be a double word load or store. diff --git a/src/occ_gpe1/topfiles.mk b/src/occ_gpe1/topfiles.mk index 53d35b5..5a0095f 100644 --- a/src/occ_gpe1/topfiles.mk +++ b/src/occ_gpe1/topfiles.mk @@ -26,8 +26,9 @@ TOP-C-SOURCES = gpe1_main.c gpe1_dimm_read.c gpe1_dimm_reset.c nop.c \ pk_app_irq_table.c ipc_func_tables.c gpe1_dimm_control.c \ gpe1_24x7.c gpe1_memory_power_control.c gpe_gpu_init.c \ - gpe_centaur_scom.c gpe_centaur_configuration.c \ - gpe_centaur.c occ_gpe1_machine_check_handler.c + gpe_membuf_scom.c gpe_centaur.c \ + gpe_membuf.c occ_gpe1_machine_check_handler.c \ + gpe_ocmb.c TOP-S-SOURCES = occ_gpe1_mck_handler.S |