summaryrefslogtreecommitdiffstats
path: root/src/lib/special_wakeup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/special_wakeup.c')
-rw-r--r--src/lib/special_wakeup.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/lib/special_wakeup.c b/src/lib/special_wakeup.c
new file mode 100644
index 0000000..59e3274
--- /dev/null
+++ b/src/lib/special_wakeup.c
@@ -0,0 +1,149 @@
+// $Id: special_wakeup.c,v 1.4 2014/02/03 01:30:25 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/special_wakeup.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file special_wakeup.c
+/// \brief Container for special wakeup related procedures
+
+#include "special_wakeup.h"
+
+uint32_t G_special_wakeup_count[PGP_NCORES] = {0};
+
+/// Enter or clear special wakeup for a core
+///
+/// \param set 1 = set, 0 = clear, all other values will cause an error.
+///
+/// \param cores = mask of cores to set/clear special wakeup.
+///
+/// \param[out] o_timeouts. Mask of cores that timed out before special wakeup
+/// complete was observed.
+///
+/// \retval 0 Success
+///
+/// \retval -SPWU_INVALID_ARGUMENT One of the arguments was invalid in some way
+///
+/// \retval others This API may also return non-0 codes from
+/// getscom()/putscom()
+///
+/// If getscom/putscom rc = 0, the state of the global special_wakeup counts
+/// may no longer be valid.
+///
+
+int
+occ_special_wakeup(int set,
+ ChipConfigCores cores,
+ int timeout_ms,
+ ChipConfigCores *o_timeouts)
+
+{
+
+ pmc_core_deconfiguration_reg_t pcdr;
+ pcbs_pmgp0_reg_t pmgp0;
+ pcbs_pmspcwkupocc_reg_t ppr;
+ ChipConfigCores core_list;
+ ChipConfigCores awake_list = 0;
+ ChipConfigCores success_list = 0;
+ ChipConfigCores poll_list = 0;
+ ChipConfigCores timeout_list = 0;
+ int rc, poll_count, core;
+ int time = 0;
+ int bad_clear;
+
+ // get pmc deconfig vector
+ pcdr.value = in32(PMC_CORE_DECONFIGURATION_REG);
+
+ core_list = cores;
+ bad_clear = 0;
+ if (! set) {
+ for (core = 0; core < PGP_NCORES; core++, core_list <<=1) {
+ if (core_list & (0x1 << (PGP_NCORES - 1))) {
+ if (G_special_wakeup_count[core] == 0) {
+ bad_clear = 1;
+ }
+ }
+ }
+ }
+
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF( (set < 0) ||
+ (set > 1) ||
+ (bad_clear) ||
+ (pcdr.fields.core_chiplet_deconf_vector & cores),
+ SPWU_INVALID_ARGUMENT);
+ }
+
+ do {
+ ppr.value = 0;
+ if (set) {
+ // If count is currently zero, set the bit and increment count.
+ // Otherwise, just increment count
+ core_list = cores;
+ for (core = 0; core < PGP_NCORES; core++, core_list <<=1) {
+ if (core_list & (0x1 << (PGP_NCORES - 1))) {
+ if (! G_special_wakeup_count[core]) {
+ ppr.fields.occ_special_wakeup = 1;
+ rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PMSPCWKUPOCC_REG, core), ppr.value);
+ poll_list |= (0x1 << (PGP_NCORES - 1 - core));
+ }
+ if (rc) break; // break for loop
+ ++G_special_wakeup_count[core];
+ success_list |= (0x1 << (PGP_NCORES - 1 - core));
+ }
+ }
+ if (rc) break;
+
+ // poll special_wkup_done bit.
+ poll_count = 0;
+ while ((poll_list != awake_list) && (time < timeout_ms)) {
+ if (! poll_count) {
+ ssx_sleep(SSX_MICROSECONDS(2));
+ ++poll_count;
+ } else {
+ ssx_sleep(SSX_MILLISECONDS(5));
+ time += 5;
+ }
+ core_list = poll_list & (~awake_list);
+ for (core = 0; core < PGP_NCORES; core++, core_list <<=1) {
+ if (core_list & (0x1 << (PGP_NCORES - 1))) {
+ rc = getscom(CORE_CHIPLET_ADDRESS(PCBS_PMGP0_REG, core), &pmgp0.value);
+ if (rc) break;
+ if (pmgp0.fields.special_wkup_done) {
+ awake_list |= (0x1 << (PGP_NCORES - 1 - core));
+ } else {
+ if (time >= timeout_ms) {
+ timeout_list |= (0x1<<(PGP_NCORES-1-core));
+ }
+ }
+ }
+ }
+ }
+ } else { // clear special wakeup
+ core_list = cores;
+ for (core = 0; core < PGP_NCORES; core++, core_list <<=1) {
+ if (core_list & (0x1 << (PGP_NCORES - 1))) {
+ if (G_special_wakeup_count[core] == 1) {
+ ppr.fields.occ_special_wakeup = 0;
+ rc = putscom(CORE_CHIPLET_ADDRESS(PCBS_PMSPCWKUPOCC_REG, core), ppr.value);
+ }
+ if (rc) break;
+ --G_special_wakeup_count[core];
+ success_list |= (0x1 << (PGP_NCORES - 1 - core));
+ }
+ }
+ if (rc) break;
+ }
+ } while (0);
+
+ // bad rc recovery (recovery of counts, etc?)
+
+ *o_timeouts = timeout_list;
+ return rc;
+
+}
+
+
OpenPOWER on IntegriCloud