summaryrefslogtreecommitdiffstats
path: root/src/occ_gpe1/gpe_centaur_scom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/occ_gpe1/gpe_centaur_scom.c')
-rw-r--r--src/occ_gpe1/gpe_centaur_scom.c571
1 files changed, 571 insertions, 0 deletions
diff --git a/src/occ_gpe1/gpe_centaur_scom.c b/src/occ_gpe1/gpe_centaur_scom.c
new file mode 100644
index 0000000..cef0977
--- /dev/null
+++ b/src/occ_gpe1/gpe_centaur_scom.c
@@ -0,0 +1,571 @@
+/* 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"
+
+/**
+ * @file centaur_scom
+ * @brief scom access from gpe to a centaur
+ */
+
+/**
+ * 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
+ */
+uint32_t centaur_scom_setup(CentaurConfiguration_t* i_config,
+ uint32_t i_centaur_instance,
+ uint32_t i_scom_address)
+{
+ uint32_t oci_addr = 0;
+ #if defined(__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(__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);
+#endif
+ // HW bug work-around
+ {
+ // workaround - don't use extr addr - use pbabar.
+ uint64_t barMsk = 0;
+ // put the PBA in the BAR
+ putscom_abs(PBA_BARN(PBA_BAR_CENTAUR), pb_addr);
+ putscom_abs(PBA_BARMSKN(PBA_BAR_CENTAUR), barMsk);
+ }
+ // make oci address
+ oci_addr = (uint32_t)(pb_addr & 0x07ffffffull);
+
+ // upper nibble is PBA region and BAR_SELECT
+ oci_addr |= ((PBA_BAR_CENTAUR | 0x8) << 28);
+ PK_TRACE_DBG("Centaur OCI scom addr: %08x",oci_addr);
+ return oci_addr;
+}
+
+uint32_t centaur_sensorcache_setup(CentaurConfiguration_t* i_config,
+ uint32_t i_centaur_instance)
+{
+ uint32_t oci_addr = 0;
+#if defined(__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(__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);
+#endif
+ {
+ // HW bug workaround - don't use extr addr - use pbabar.
+ uint64_t barMsk = 0;
+ // put the PBA in the BAR
+ putscom_abs(PBA_BARN(PBA_BAR_CENTAUR), pb_addr);
+ putscom_abs(PBA_BARMSKN(PBA_BAR_CENTAUR), barMsk);
+ }
+ // make oci address
+ oci_addr = (uint32_t)(pb_addr & 0x07ffffffull);
+
+ // PBA space bits[0:1] = '10' bar select bits[3:4]
+ oci_addr |= ((PBA_BAR_CENTAUR | 0x8) << 28);
+
+ return oci_addr;
+}
+
+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 the most severe rc from the sibrca field in the msr
+int rc_from_sibrc()
+{
+ int rc = 0;
+ uint32_t sibrca = (mfmsr() & 0x0000007f);
+ if(sibrca)
+ {
+ uint32_t mask = 1;
+ rc = 7;
+ for(; mask != 0x00000080; mask <<=1)
+ {
+ if( mask & sibrca )
+ {
+ break;
+ }
+ --rc;
+ }
+ }
+ return rc;
+}
+
+// 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 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 =
+ centaur_scom_setup(i_config, instance, i_scom_address);
+
+ // read centaur scom
+ PPE_LVD(oci_addr, *o_data);
+ }
+ 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_from_sibrc();
+}
+
+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));
+
+ oci_addr =
+ centaur_scom_setup(i_config, i_centaur_instance, i_scom_address);
+
+ if( CHIP_CONFIG_CENTAUR(i_centaur_instance) & (i_config->config))
+ {
+ // read centaur scom
+ rc = getscom_abs(oci_addr, o_data);
+ }
+ 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 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 =
+ centaur_scom_setup(i_config, instance, i_scom_address);
+
+ // centaur scom
+ PPE_STVD(oci_addr, i_data);
+ }
+ }
+
+ // gpe_pba_cntl function?
+ pbaslvctl_reset(&(i_config->scomParms));
+ PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save);
+
+ return rc_from_sibrc();
+}
+
+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));
+
+ oci_addr =
+ centaur_scom_setup(i_config, i_centaur_instance, i_scom_address);
+
+ if( CHIP_CONFIG_CENTAUR(i_centaur_instance) & (i_config->config))
+ {
+ // write centaur scom
+ rc = putscom_abs(oci_addr, i_data);
+ }
+ else
+ {
+ rc = CENTAUR_INVALID_SCOM;
+ }
+
+ // gpe_pba_cntl function?
+ 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));
+
+ oci_addr =
+ centaur_scom_setup(i_config, i_centaur_instance, i_scom_address);
+
+ rc = getscom_abs(oci_addr, &data64);
+ if(!rc)
+ {
+ data64 &= (i_mask ^ 0xffffffffffffffffull);
+ data64 |= *i_data;
+
+ rc = putscom_abs(oci_addr, data64);
+ if(i_scom_address == 0x3010416)
+ {
+ PK_TRACE("N/M RMW PUTSCOM: %08x%08x",(uint32_t)(data64>>32),(uint32_t)data64);
+ }
+ }
+
+ 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 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))
+ {
+ uint64_t data64;
+ uint32_t oci_addr =
+ centaur_scom_setup(i_config, instance, i_scom_address);
+
+ PPE_LVD(oci_addr, data64);
+ data64 &= (i_mask ^ 0xffffffffffffffffull);
+ data64 |= i_data;
+ PPE_STVD(oci_addr, data64);
+
+ pbaslvctl_reset(&(i_config->scomParms));
+ }
+ }
+
+ PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save);
+
+ return rc_from_sibrc();
+}
+
+
+int centaur_scom_sync(CentaurConfiguration_t* i_config,
+ uint64_t i_data)
+{
+ int rc = 0;
+ uint32_t addr = (PBA_BAR_CENTAUR << 28);
+ uint64_t pba_slvctln_save;
+
+ pbaslvctl_reset(&(i_config->scomParms));
+ pba_slvctln_save = pbaslvctl_setup(&(i_config->scomParms));
+
+ // sync setup
+ pba_slvctln_t slvctl;
+ PPE_LVD((i_config->scomParms).slvctl_address, slvctl.value);
+ slvctl.fields.extaddr = (i_config->syncSlaveControl).fields.extaddr;
+ PPE_STVD((i_config->scomParms).slvctl_address, slvctl.value);
+
+ PPE_STVD(addr, i_data);
+
+ pbaslvctl_reset(&(i_config->scomParms));
+ PPE_STVD((i_config->scomParms).slvctl_address, pba_slvctln_save);
+
+ return rc;
+}
+
+
+int centaur_scom_sync_all(CentaurConfiguration_t* i_config,
+ uint64_t i_data)
+{
+ return centaur_scom_sync(i_config,
+ (uint64_t)(i_config->config << 24) | i_data);
+}
+
+// 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;
+ uint64_t barMskOrg = 0;
+
+ i_parms->error.rc = CENTAUR_GET_MEM_DATA_DIED;
+
+ // HW bug work-around
+ rc = getscom_abs(PBA_BARMSKN(PBA_BAR_CENTAUR), &barMskOrg);
+ if(rc)
+ {
+ PK_TRACE("Workaround failed to read bar mask. rc = %x",rc);
+ }
+
+ pbaslvctl_reset(&(i_config->dataParms));
+ pba_slvctln_save = pbaslvctl_setup(&(i_config->dataParms));
+
+ 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
+ {
+ oci_addr = centaur_sensorcache_setup(i_config, i_parms->collect);
+
+ // Poke the Centaur sensor cache by writing to base address.
+ data64 = 0;
+ PPE_STVD(oci_addr, data64);
+
+ // 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);
+ }
+ }
+ }
+ // TODO Decide to keep this or not.
+#if defined(__JUNK__)
+ if(!rc && i_parms->update != -1)
+ {
+ if((i_parms->update >= OCCHW_NCENTAUR) ||
+ (0 == (CHIP_CONFIG_CENTAUR(i_parms->update) & (i_config->config))))
+ {
+ rc = CENTAUR_GET_MEM_DATA_UPDATE_INVALID;
+ }
+ else
+ {
+ oci_addr = centaur_sensorcache_setup(i_config, i_parms->update);
+
+ //PK_TRACE("CACHE POKE: %08x",oci_addr);
+ // Writing a zero to this address "pokes" the centaur.
+ data64 = 0;
+ PPE_STVD(oci_addr, data64);
+ }
+ }
+#endif
+
+ pbaslvctl_reset(&(i_config->dataParms));
+ PPE_STVD((i_config->dataParms).slvctl_address, pba_slvctln_save);
+
+ // TODO if RC then check for centaur channel checkstop
+ // The MCFIR reg no longer contains a bit for CHANNEL_FAIL_SIGNAL_ACTIVE.
+ // No equivalent has been identified yet for P9.
+ // Return rc = CENTAUR_CHANNEL_CHECKSTOP
+
+ // HW bug work-around
+ rc = putscom_abs(PBA_BARMSKN(PBA_BAR_CENTAUR), barMskOrg);
+ if(rc)
+ {
+ PK_TRACE("Work around Failed to set bar mask. rc = %x",rc);
+ }
+
+ i_parms->error.rc = rc;
+ 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;
+ mtmsr((mfmsr() & ~(MSR_SIBRC | MSR_SIBRCA)) | MSR_SEM);
+
+ // Do reset and pba_setup here?
+ for(i = 0; i < i_parms->entries; ++i)
+ {
+ switch(i_parms->scomList[i].commandType)
+ {
+ case CENTAUR_SCOM_NOP:
+ break;
+
+ case CENTAUR_SCOM_READ:
+ 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:
+ 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:
+ 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:
+ centaur_get_scom_vector(i_config,
+ i_parms->scomList[i].scom,
+ i_parms->scomList[i].pData
+ );
+ break;
+
+ case CENTAUR_SCOM_WRITE_ALL:
+ centaur_put_scom_all(i_config,
+ i_parms->scomList[i].scom,
+ i_parms->scomList[i].data);
+ break;
+
+ case CENTAUR_SCOM_RMW_ALL:
+ 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:
+ centaur_scom_sync(i_config,
+ i_parms->scomList[i].data);
+ break;
+
+ case CENTAUR_SCOM_CENTAUR_SYNC_ALL:
+ centaur_scom_sync(i_config,
+ i_parms->scomList[i].data);
+ break;
+
+ default:
+ break;
+ };
+ }
+}
OpenPOWER on IntegriCloud