summaryrefslogtreecommitdiffstats
path: root/src/occ_405
diff options
context:
space:
mode:
authorWael El-Essawy <welessa@us.ibm.com>2016-10-27 12:54:20 -0500
committerWael El-Essawy <welessa@us.ibm.com>2016-11-03 15:08:04 -0400
commit45ceb3d13361ac099c7b0b9f2ff51a731e296ed1 (patch)
tree0b9edc946040fe0f3bd2b2f82a09b1f3d94ebc56 /src/occ_405
parentaa7187f24959d2ec1fbee81a5d100a749161096f (diff)
downloadtalos-occ-45ceb3d13361ac099c7b0b9f2ff51a731e296ed1.tar.gz
talos-occ-45ceb3d13361ac099c7b0b9f2ff51a731e296ed1.zip
Implement task_poke_watchdogs
task_poke_watchdogs() should be called every 2ms (ticks 1 and 9) on both master and slaves while in observation and active state and do the following: 1. Every time called: Enable/Reset the OCC heartbeat: done by a write to OCB OCC Heartbeat Register (set count to 8ms) 2. Every time called: Reset memory deadman timer for 1 MCA (skip if not present and just wait until next call to check next MCA to keep same timing of reset per MCA regardless of # present) Resetting the deadman is done by reading one of the memory performance counters, use one at SCOM offset 0x13C. NOTE: Will take 16ms (8 MCAs x 2ms) to reset all memory timers, this is fine since the shortest time the deadman timeout can be configured to is 28ms 3. Every 4ms (on tick 1 only) : Verify PGPE is still functional by reading PGPE Beacon from SRAM if after 8ms (2 consecutive checks) there is no change to the PGPE Beacon count then log an error and request reset. In addition, this commit adds entries for the PGPE image header and shared SRAM in the TLB, and partially reads PGPE image header parameters. Change-Id: I9906102b3349506612d55c57e9f5c28441eaeb39 RTC: 154960 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/31916 Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Wael El-Essawy <welessa@us.ibm.com>
Diffstat (limited to 'src/occ_405')
-rw-r--r--src/occ_405/amec/amec_init.c10
-rwxr-xr-xsrc/occ_405/incl/occ_common.h1
-rwxr-xr-xsrc/occ_405/main.c146
-rw-r--r--src/occ_405/occ_service_codes.h9
-rwxr-xr-xsrc/occ_405/occ_sys_config.h2
-rw-r--r--src/occ_405/pgpe_shared.h42
-rwxr-xr-xsrc/occ_405/rtls/rtls.h1
-rwxr-xr-xsrc/occ_405/rtls/rtls_tables.c16
-rwxr-xr-xsrc/occ_405/timer/timer.c441
-rwxr-xr-xsrc/occ_405/timer/timer.h6
-rwxr-xr-xsrc/occ_405/timer/timer_service_codes.h2
11 files changed, 606 insertions, 70 deletions
diff --git a/src/occ_405/amec/amec_init.c b/src/occ_405/amec/amec_init.c
index 765b005..b338915 100644
--- a/src/occ_405/amec/amec_init.c
+++ b/src/occ_405/amec/amec_init.c
@@ -393,12 +393,12 @@ void amec_slave_init()
(void *) GPE_ENGINE_1, //callback argument
ASYNC_CALLBACK_IMMEDIATE ); //options
- // If we couldn't create the poreFlex objects, there must be a major problem
+ // If we couldn't create the GpeRequest objects, there must be a major problem
// so we will log an error and halt OCC.
if( rc || rc2 )
{
- //If fail to create pore flex object then there is a problem.
- TRAC_ERR("Failed to create GPE duration poreFlex object[0x%x, 0x%x]", rc, rc2 );
+ //If fail to create GpeRequest object then there is a problem.
+ TRAC_ERR("Failed to create GPE duration GpeRequest object[0x%x, 0x%x]", rc, rc2 );
/* @
* @errortype
@@ -407,7 +407,7 @@ void amec_slave_init()
* @userdata1 return code - gpe0
* @userdata2 return code - gpe1
* @userdata4 OCC_NO_EXTENDED_RC
- * @devdesc Failure to create PORE-GPE poreFlex object for FW timing
+ * @devdesc Failure to create GpeRequest object for FW timing
* analysis.
*
*/
@@ -416,7 +416,7 @@ void amec_slave_init()
SSX_GENERIC_FAILURE, //reasoncode
OCC_NO_EXTENDED_RC, //Extended reason code
ERRL_SEV_PREDICTIVE, //Severity
- NULL, //TODO: create trace //Trace Buf
+ NULL, //Trace Buf
DEFAULT_TRACE_SIZE, //Trace Size
rc, //userdata1
rc2 //userdata2
diff --git a/src/occ_405/incl/occ_common.h b/src/occ_405/incl/occ_common.h
index 2d22d61..ae0172a 100755
--- a/src/occ_405/incl/occ_common.h
+++ b/src/occ_405/incl/occ_common.h
@@ -261,6 +261,7 @@ enum
NEST_DTS_INITIALIZED = 0x0700,
CENTAUR_INITIALIZED = 0x07ff,
SLAVE_OCC_INITIALIZED = 0x08ff,
+ PGPE_IMAGE_HEADER_READ = 0x098f,
WATCHDOG_INITIALIZED = 0x09ff,
RTL_TIMER_INITIALIZED = 0x0aff,
SEMS_AND_TIMERS_INITIALIZED = 0x0bff,
diff --git a/src/occ_405/main.c b/src/occ_405/main.c
index dca5f89..18e680f 100755
--- a/src/occ_405/main.c
+++ b/src/occ_405/main.c
@@ -1,4 +1,3 @@
-
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
@@ -58,6 +57,7 @@
#include <pss_service_codes.h>
#include <dimm.h>
#include "occhw_shared_data.h"
+#include <pgpe_shared.h>
extern uint32_t __ssx_boot; // Function address is 32 bits
extern uint32_t G_occ_phantom_critical_count;
@@ -72,10 +72,14 @@ extern apss_start_args_t G_gpe_start_pwr_meas_read_args;
extern apss_continue_args_t G_gpe_continue_pwr_meas_read_args;
extern apss_complete_args_t G_gpe_complete_pwr_meas_read_args;
-
+extern uint32_t G_pgpe_beacon_address;
IMAGE_HEADER (G_mainAppImageHdr,__ssx_boot,MAIN_APP_ID,ID_NUM_INVALID);
+// PGPE Image Header Parameters
+uint32_t G_pgpe_sram_address;
+uint32_t G_pgpe_sram_sz;
+
//Set main thread timer for one second
#define MAIN_THRD_TIMER_SLICE ((SsxInterval) SSX_SECONDS(1))
@@ -110,6 +114,7 @@ extern uint8_t g_trac_imp_buffer[];
extern uint8_t g_trac_err_buffer[];
void pmc_hw_error_isr(void *private, SsxIrqId irq, int priority);
+void create_tlb_entry(uint32_t address, uint32_t size);
//Macro creates a 'bridge' handler that converts the initial fast-mode to full
//mode interrupt handler
@@ -360,6 +365,132 @@ END TEMP */
/*
* Function Specification
*
+ * Name: create_tlb_entry
+ *
+ * Description: Creates a TLB entry in the 405 processor to access PGPE space.
+ * The TLB entry has read only access, and is cache-inhibited.
+ * This call takes care of pages alignment
+ * and adds additional pages in case the requested
+ * space crosses page boundaries.
+ *
+ * will result in panic if the TLB entry allocation
+ * fails.
+ *
+ * End Function Specification
+ */
+
+#define PAGE_SIZE PPC405_PAGE_SIZE_MIN
+#define PAGE_ALIGNED_ADDRESS(addr) (addr & ~((uint32_t)(PAGE_SIZE-1)))
+#define PAGE_ALIGNED_SIZE(sz) ((uint32_t)PAGE_SIZE*(((uint32_t)sz/PAGE_SIZE)+1))
+
+void create_tlb_entry(uint32_t address, uint32_t size)
+{
+ int l_rc = SSX_OK;
+ uint32_t tlb_entry_address, tlb_entry_size; // address and size that guarantee page alignment
+
+ tlb_entry_address = PAGE_ALIGNED_ADDRESS(address);
+
+ if(address + (size%PPC405_PAGE_SIZE_MIN) >=
+ tlb_entry_address + PPC405_PAGE_SIZE_MIN)
+ {
+ tlb_entry_size = PAGE_ALIGNED_SIZE(size+PPC405_PAGE_SIZE_MIN);
+ }
+ else
+ {
+ tlb_entry_size = PAGE_ALIGNED_SIZE(size);
+ }
+
+ // define DTLB for PGPE image header
+ l_rc = ppc405_mmu_map(
+ tlb_entry_address,
+ tlb_entry_address,
+ tlb_entry_size,
+ 0,
+ TLBLO_I, //Read-only, Cache-inhibited
+ NULL
+ );
+
+ if(l_rc != SSX_OK)
+ {
+ MAIN_TRAC_ERR("Failed to create TLB entry,"
+ "TLB Page Address[0x%08x], TLB Entry size[0x%08x], rc[0x%08x]",
+ tlb_entry_address, tlb_entry_size, l_rc);
+
+ /* @
+ * @errortype
+ * @moduleid CREATE_TLB_ENTRY
+ * @reasoncode SSX_GENERIC_FAILURE
+ * @userdata1 ppc405_mmu_map return code
+ * @userdata2 address for which a TLB entry is created
+ * @userdata4 ERC_TLB_ENTRY_CREATION_FAILURE
+ * @devdesc SSX semaphore related failure
+ */
+
+ errlHndl_t l_err = createErrl(CREATE_TLB_ENTRY, //modId
+ SSX_GENERIC_FAILURE, //reasoncode
+ ERC_TLB_ENTRY_CREATION_FAILURE, //Extended reason code
+ ERRL_SEV_UNRECOVERABLE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ l_rc, //userdata1
+ address); //userdata2
+
+ REQUEST_RESET(l_err);
+ }
+
+ MAIN_TRAC_IMP("Created TLB entry for Address[0x%08x]"
+ "TLB Page Address[0x%08x], TLB Entry size[0x%08x]",
+ address, tlb_entry_address, tlb_entry_size);
+}
+
+
+/*
+ * Function Specification
+ *
+ * Name: read_pgpe_header
+ *
+ * Description: Initialize PGPE image header entry in DTLB,
+ * Read PGPE image header, lookup shared SRAM address and size,
+ * Initialize OCC/PGPE shared SRAM entry in the DTLB,
+ * Populate global variables, including G_pgpe_peacon_address.
+ *
+ * End Function Specification
+ */
+
+void read_pgpe_header(void)
+{
+
+ // define DTLB for the PGPE image header
+ create_tlb_entry(PGPE_HEADER_ADDR, PGPE_HEADER_SZ);
+
+ // Read PGPE Beacon address from PGPE image header
+ G_pgpe_beacon_address = in32(PGPE_BEACON_ADDR_PTR);
+
+ MAIN_TRAC_IMP("Read PGPE Beacon Address[0x%08x]",
+ G_pgpe_beacon_address);
+
+ // Read OCC/PGPE Shared SRAM address and size
+ G_pgpe_sram_address = in32(PGPE_SHARED_SRAM_ADDR_PTR);
+ G_pgpe_sram_sz = in32(PGPE_SHARED_SRAM_SZ_PTR);
+
+ MAIN_TRAC_IMP("Read PGPE Shared SRAM Start Address[0x%08x], Size[0x%08x]",
+ G_pgpe_sram_address, G_pgpe_sram_sz);
+
+ // PGPE Beacon is not implemented in simics yet
+ // the G_pgpe_sram_address and G_pgpe_sram_sz pointers don't
+ // have the proper values yet.
+ // @TODO: remove this condition when PGPE code is integrated. RTC: 163934
+ if(!G_simics_environment)
+ {
+ // define DTLB for OCC/PGPE shared SRAM, which enables access
+ // to OCC-PGPE Shared SRAM space, including pgpe_beacon
+ create_tlb_entry(G_pgpe_sram_address, G_pgpe_sram_sz);
+ }
+}
+
+/*
+ * Function Specification
+ *
* Name: gpe_reset
*
* Description: Force a GPE to start executing instructions at the reset vector
@@ -823,12 +954,17 @@ void Main_thread_routine(void *private)
slave_occ_init();
CHECKPOINT(SLAVE_OCC_INITIALIZED);
+ // Read PGPE header file, extract OCC/PGPE Shared SRAM address and size,
+ // Read other global parameters, e.g. G_pgpe_beacon_address, etc.
+ read_pgpe_header();
+ CHECKPOINT(PGPE_IMAGE_HEADER_READ);
+
// Initialize watchdog timers. This needs to be right before
// start rtl to make sure timer doesn't timeout. This timer is being
// reset from the rtl task.
-// TEMP -- watchdog timers not enabled yet
-// MAIN_TRAC_INFO("Initializing watchdog timers.");
-// initWatchdogTimers();
+
+ MAIN_TRAC_INFO("Initializing watchdog timers.");
+ initWatchdogTimers();
CHECKPOINT(WATCHDOG_INITIALIZED);
// Initialize Real time Loop Timer Interrupt
diff --git a/src/occ_405/occ_service_codes.h b/src/occ_405/occ_service_codes.h
index 3556de5..391cec8 100644
--- a/src/occ_405/occ_service_codes.h
+++ b/src/occ_405/occ_service_codes.h
@@ -110,6 +110,12 @@ enum occReasonCode
DIMM_GPE_FAILURE = 0xD0,
MEMORY_INIT_FAILED = 0xD1,
DIMM_INVALID_STATE = 0xD2,
+ PGPE_BEACON_TIMEOUT = 0xD3,
+ /// GPE IPC TASK RCs
+ GPE_REQUEST_CREATE_FAILURE = 0xD4,
+ GPE_REQUEST_SCHEDULE_FAILURE = 0xD5,
+ GPE_REQUEST_TASK_TIMEOUT = 0xD6,
+
/// Success!
OCC_SUCCESS_REASON_CODE = 0xFF,
};
@@ -210,6 +216,8 @@ enum occExtReasonCode
ERC_MEM_CONTROL_COMPLETE_FAILURE = 0x0081,
ERC_FW_ZERO_FREQ_LIMIT = 0x0090,
+
+ ERC_TLB_ENTRY_CREATION_FAILURE = 0x00A0,
};
// Error log Module Ids
@@ -231,6 +239,7 @@ enum occModuleId
FIR_DATA_MID = MAIN_COMP_ID | 0x0e,
CMDH_DBUG_MID = MAIN_COMP_ID | 0x0f,
I2C_LOCK_UPDATE = MAIN_COMP_ID | 0x10,
+ CREATE_TLB_ENTRY = MAIN_COMP_ID | 0x11,
};
enum occUserDataType
diff --git a/src/occ_405/occ_sys_config.h b/src/occ_405/occ_sys_config.h
index b7abf18..6044227 100755
--- a/src/occ_405/occ_sys_config.h
+++ b/src/occ_405/occ_sys_config.h
@@ -53,6 +53,8 @@
#define MC23 1
#define NUM_NIMBUS_MC_PAIRS 2
+#define NUM_NIMBUS_MCAS (MAX_NUM_MCU_PORTS * NUM_NIMBUS_MC_PAIRS)
+
#define NUM_DIMMS_PER_MEM_CONTROLLER 8
#define NUM_I2C_PORTS 2
diff --git a/src/occ_405/pgpe_shared.h b/src/occ_405/pgpe_shared.h
new file mode 100644
index 0000000..0dac88f
--- /dev/null
+++ b/src/occ_405/pgpe_shared.h
@@ -0,0 +1,42 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_405/pgpe_shared.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
+/* [+] 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 */
+
+#define PGPE_HEADER_ADDR 0xFFF20180 // 0xfff20000 + 0x180
+#define PGPE_HEADER_SZ 96 // Size of PGPE Image header
+
+// Offset addresses of PGPE Header parameters (relative to start address)
+#define PGPE_SHARED_SRAM_ADDR_OFFSET 0x0c
+#define PGPE_SHARED_SRAM_SZ_OFFSET 0x14
+#define PGPE_BEACON_ADDR_OFFSET 0x48
+
+// PGPE Image Header Parameter addresses
+
+//Shared OCC-PGPE SRAM parameters
+#define PGPE_SHARED_SRAM_ADDR_PTR (PGPE_HEADER_ADDR + PGPE_SHARED_SRAM_ADDR_OFFSET)
+#define PGPE_SHARED_SRAM_SZ_PTR (PGPE_HEADER_ADDR + PGPE_SHARED_SRAM_SZ_OFFSET)
+
+// A pointer to PGPE Beacon Address
+#define PGPE_BEACON_ADDR_PTR (PGPE_HEADER_ADDR + PGPE_BEACON_ADDR_OFFSET)
+
diff --git a/src/occ_405/rtls/rtls.h b/src/occ_405/rtls/rtls.h
index 0aead87..7a45afe 100755
--- a/src/occ_405/rtls/rtls.h
+++ b/src/occ_405/rtls/rtls.h
@@ -58,7 +58,6 @@ typedef enum {
// TASK_ID_CORE_DATA_CONTROL,
// TASK_ID_GPU_SM, // GPU State Machine
TASK_ID_DIMM_SM, // DIMM State Machine
-// TASK_ID_MEM_DEADMAN, // Memory deadman timer
TASK_ID_MEMORY_CONTROL, // Memory (centaur/dimm) control task
TASK_ID_NEST_DTS,
TASK_END // This must always be the last enum in this list,
diff --git a/src/occ_405/rtls/rtls_tables.c b/src/occ_405/rtls/rtls_tables.c
index ef42d90..a577069 100755
--- a/src/occ_405/rtls/rtls_tables.c
+++ b/src/occ_405/rtls/rtls_tables.c
@@ -118,8 +118,6 @@ task_t G_task_table[TASK_END] = {
// TEMP -- NOT YET IMPLEMENTED
// { FLAGS_GPU_SM, task_gpu_sm, NULL }, // TASK_ID_GPU_SM
{ FLAGS_MEMORY_DATA, task_dimm_sm, NULL }, // TASK_ID_DIMM_SM
-// TEMP -- NOT YET IMPLEMENTED
-// { FLAGS_MEM_DEADMAN, task_mem_deadman, NULL }, // TASK_ID_MEM_DEADMAN
{ FLAGS_MEMORY_CONTROL, task_memory_control, (void *) &G_memory_control_task }, // TASK_ID_MEMORY_CONTROL
{ FLAGS_NEST_DTS, task_nest_dts, NULL },
};
@@ -136,7 +134,6 @@ const uint8_t G_tick0_seq[] = {
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
TASK_ID_DCOM_RX_OUTBX,
- TASK_ID_POKE_WDT,
TASK_ID_DCOM_TX_OUTBX,
TASK_ID_DCOM_TX_INBX,
TASK_ID_AMEC_SLAVE,
@@ -152,11 +149,11 @@ const uint8_t G_tick1_seq[] = {
TASK_ID_APSS_CONT,
TASK_ID_APSS_DONE,
TASK_ID_MEMORY_CONTROL,
- //TASK_ID_MEM_DEADMAN,
//TASK_ID_CORE_DATA_CONTROL,
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
TASK_ID_DCOM_RX_OUTBX,
+ TASK_ID_POKE_WDT,
TASK_ID_DCOM_TX_OUTBX,
TASK_ID_DCOM_TX_INBX,
TASK_ID_AMEC_SLAVE,
@@ -193,7 +190,6 @@ const uint8_t G_tick3_seq[] = {
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
TASK_ID_MEMORY_CONTROL,
- //TASK_ID_MEM_DEADMAN,
//TASK_ID_CORE_DATA_CONTROL,
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
@@ -218,7 +214,6 @@ const uint8_t G_tick4_seq[] = {
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
TASK_ID_DCOM_RX_OUTBX,
- TASK_ID_POKE_WDT,
TASK_ID_DCOM_TX_OUTBX,
TASK_ID_DCOM_TX_INBX,
TASK_ID_AMEC_SLAVE,
@@ -234,7 +229,6 @@ const uint8_t G_tick5_seq[] = {
TASK_ID_APSS_CONT,
TASK_ID_APSS_DONE,
TASK_ID_MEMORY_CONTROL,
- //TASK_ID_MEM_DEADMAN,
//TASK_ID_CORE_DATA_CONTROL,
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
@@ -274,7 +268,6 @@ const uint8_t G_tick7_seq[] = {
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
TASK_ID_MEMORY_CONTROL,
- //TASK_ID_MEM_DEADMAN,
//TASK_ID_CORE_DATA_CONTROL,
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
@@ -299,7 +292,6 @@ const uint8_t G_tick8_seq[] = {
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
TASK_ID_DCOM_RX_OUTBX,
- TASK_ID_POKE_WDT,
TASK_ID_DCOM_TX_OUTBX,
TASK_ID_DCOM_TX_INBX,
TASK_ID_AMEC_SLAVE,
@@ -315,11 +307,11 @@ const uint8_t G_tick9_seq[] = {
TASK_ID_APSS_CONT,
TASK_ID_APSS_DONE,
TASK_ID_MEMORY_CONTROL,
- //TASK_ID_MEM_DEADMAN,
//TASK_ID_CORE_DATA_CONTROL,
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
TASK_ID_DCOM_RX_OUTBX,
+ TASK_ID_POKE_WDT,
TASK_ID_DCOM_TX_OUTBX,
TASK_ID_DCOM_TX_INBX,
TASK_ID_AMEC_SLAVE,
@@ -355,7 +347,6 @@ const uint8_t G_tick11_seq[] = {
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
TASK_ID_MEMORY_CONTROL,
- //TASK_ID_MEM_DEADMAN,
//TASK_ID_CORE_DATA_CONTROL,
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
@@ -380,7 +371,6 @@ const uint8_t G_tick12_seq[] = {
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
TASK_ID_DCOM_RX_OUTBX,
- TASK_ID_POKE_WDT,
TASK_ID_DCOM_TX_OUTBX,
TASK_ID_DCOM_TX_INBX,
TASK_ID_AMEC_SLAVE,
@@ -396,7 +386,6 @@ const uint8_t G_tick13_seq[] = {
TASK_ID_APSS_CONT,
TASK_ID_APSS_DONE,
TASK_ID_MEMORY_CONTROL,
- //TASK_ID_MEM_DEADMAN,
//TASK_ID_CORE_DATA_CONTROL,
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
@@ -436,7 +425,6 @@ const uint8_t G_tick15_seq[] = {
TASK_ID_CORE_DATA_HIGH,
TASK_ID_APSS_DONE,
TASK_ID_MEMORY_CONTROL,
- //TASK_ID_MEM_DEADMAN,
//TASK_ID_CORE_DATA_CONTROL,
TASK_ID_DCOM_WAIT_4_MSTR,
TASK_ID_DCOM_RX_INBX,
diff --git a/src/occ_405/timer/timer.c b/src/occ_405/timer/timer.c
index 4b0e1b1..ef42c5c 100755
--- a/src/occ_405/timer/timer.c
+++ b/src/occ_405/timer/timer.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -29,17 +29,22 @@
#include <timer.h> // timer defines
#include "ssx.h"
#include <trac.h> // Trace macros
-#include <occhw_common.h> // PGP common defines
-#include <occhw_ocb.h> // OCB timer interfaces
+#include <occhw_common.h> // PGP common defines
+#include <occhw_ocb.h> // OCB timer interfaces
#include <occ_service_codes.h> // Reason codes
#include <timer_service_codes.h> // Module Id
#include <cmdh_fsp.h> // for RCs in the checkpoint macros
+#include <dimm_structs.h>
+#include <occ_sys_config.h>
+#include <pgpe_shared.h>
//*************************************************************************/
// Externs
//*************************************************************************/
// Variable holding main thread loop count
extern uint32_t G_mainThreadLoopCounter;
+// Running in simics?
+extern bool G_simics_environment;
//*************************************************************************/
// Macros
@@ -68,7 +73,17 @@ SSX_IRQ_FAST2FULL(ocbTHndler, ocbTHndlerFull);
//*************************************************************************/
// Globals
//*************************************************************************/
-bool G_wdog_enabled = FALSE;
+bool G_wdog_enabled = false;
+
+// memory deadman is a per port timer that the MCU uses to verify that
+// the memory's power and thermal are properly monitored. The memory deadman
+// timers can be programmed 100 ms to 28 s. Reading the deadman timer's SCOM
+// register resets its value. If the OCC fails to reset the deadman SCOM
+// and the timer is expired, emergency throttle mode will be enforced.
+GpeRequest G_reset_mem_deadman_request; // IPC request
+GPE_BUFFER(reset_mem_deadman_args_t G_gpe_reset_mem_deadman_args); // IPC args
+
+uint32_t G_pgpe_beacon_address; // PGPE Beacon Address
//*************************************************************************/
// Function Prototypes
@@ -130,57 +145,399 @@ void initWatchdogTimers()
commitErrl(&l_err);
}
- if (SSX_OK != l_rc)
+ // initialize memory deadman timer's IPC task
+ if(G_sysConfigData.mem_type == MEM_TYPE_NIMBUS)
{
- TRAC_ERR("Error setting up OCB timer: l_rc: %d",l_rc);
- /*
- * @errortype
- * @moduleid INIT_WD_TIMERS
- * @reasoncode INTERNAL_HW_FAILURE
- * @userdata1 Return code of OCB timer setup
- * @userdata4 ERC_OCB_WD_SETUP_FAILURE
- * @devdesc Failure on hardware related function
- */
- l_err = createErrl(INIT_WD_TIMERS, // mod id
- INTERNAL_HW_FAILURE, // reason code
- ERC_OCB_WD_SETUP_FAILURE, // Extended reason code
- ERRL_SEV_UNRECOVERABLE, // severity
- NULL, // trace buffer
- 0, // trace size
- l_rc, // userdata1
- 0); // userdata2
+ // Initialize the GPE1 IPC task that resets the deadman timer.
+ init_mem_deadman_reset_task();
+ }
+}
- // Callout firmware
- addCalloutToErrl(l_err,
- ERRL_CALLOUT_TYPE_COMPONENT_ID,
- ERRL_COMPONENT_ID_FIRMWARE,
- ERRL_CALLOUT_PRIORITY_HIGH);
+// Function Specification
+//
+// Name: init_mem_deadman_reset_task
+//
+// Description:
+//
+// End Function Specification
+void init_mem_deadman_reset_task(void)
+{
+ errlHndl_t l_err = NULL;
+ int rc = 0;
- // Commit error log
- commitErrl(&l_err);
+ // Initialize memory deadman timer reset task arguments
+ G_gpe_reset_mem_deadman_args.error.error = 0;
+ G_gpe_reset_mem_deadman_args.error.ffdc = 0;
+ G_gpe_reset_mem_deadman_args.mca = 0;
+
+ TRAC_INFO("init_mem_deadman_reset_task: Creating request for GPE deadman reset task");
+ rc = gpe_request_create(&G_reset_mem_deadman_request, // request
+ &G_async_gpe_queue1, // GPE1 queue
+ IPC_ST_RESET_MEM_DEADMAN, // Function ID
+ &G_gpe_reset_mem_deadman_args, // GPE argument_ptr
+ SSX_SECONDS(5), // timeout
+ NULL, // callback
+ NULL, // callback arg
+ ASYNC_CALLBACK_IMMEDIATE); // options
+
+ // If we couldn't create the GpeRequest objects, there must be a major problem
+ // so we will log an error and halt OCC.
+ if(rc)
+ {
+ //Failed to create GpeRequest object, log an error.
+ TRAC_ERR("Failed to create memory deadman GpeRequest object[0x%x]", rc);
+
+ /* @
+ * @errortype
+ * @moduleid INIT_WD_TIMERS
+ * @reasoncode GPE_REQUEST_CREATE_FAILURE
+ * @userdata1 gpe_request_create return code
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failure to create GpeRequest object for
+ * memory deadman reset IPC task.
+ *
+ */
+ l_err = createErrl(
+ INIT_WD_TIMERS, //modId
+ GPE_REQUEST_CREATE_FAILURE, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ rc, //userdata1
+ 0 //userdata2
+ );
+
+ CHECKPOINT_FAIL_AND_HALT(l_err);
}
+
}
// Function Specification
//
// Name: task_poke_watchdogs
//
-// Description: Reset PPC405 watchdog timer by clearing TSR[ENW] bit and reset OCB timer
+// Description: Called every 2ms on both master and slaves while in observation
+// and active state. It performs the following:
+// 1. Enable/Reset the OCC heartbeat, setting the count to 8ms.
+// 2. Reset memory deadman timer for 1 MCA (by a GPE1 IPC task).
+// 3. Every 4ms (every other time called):
+// Verify PGPE is still functional by reading PGPE Beacon from
+// SRAM if after 8ms (2 consecutive checks) there is no change
+// to the PGPE Beacon count then log an error and request reset.
//
// End Function Specification
void task_poke_watchdogs(struct task * i_self)
{
-/* TEMP/TODO: Not Ready yet: PMC => PGPE */
-#if 0
- // Read the PMC status register on every RTL, this is how the OCC
- // generates a PMC hearbeat.
- pmc_status_reg_t psr;
- psr.value = in32(PMC_STATUS_REG);
-#endif
+ pmc_occ_heartbeat_reg_t hbr; // OCC heart beat register
+
+ static bool L_check_pgpe_beacon = false; // Check GPE beacon this time?
+
+// 1. Enable OCC heartbeat
+
+ hbr.fields.pmc_occ_heartbeat_time = 8000; // count corresponding to 8 ms
+ hbr.fields.pmc_occ_heartbeat_en = true; // enable heartbeat timer
+
+ out32(OCB_OCCHBR, hbr.value); // Enable heartbeat register, and set it
+
+
+// 2. Reset memory deadman timer
+ if(G_sysConfigData.mem_type == MEM_TYPE_NIMBUS)
+ {
+ manage_mem_deadman_task();
+ }
+
+// 3. Verify PGPE Beacon is not frozen for 8 ms
+ if(true == L_check_pgpe_beacon)
+ {
+ // Examine pgpe Beacon every other call (every 4ms)
+ //@TODO: remove when PGPE code is integrated, RTC: 163934
+ if(!G_simics_environment) // PGPE Beacon is not implemented in simics
+ {
+ check_pgpe_beacon();
+ }
+ }
+
+ // toggle pgpe beacon check flag, check only once every other call (every 4ms)
+ L_check_pgpe_beacon = !L_check_pgpe_beacon;
+
}
// Function Specification
//
+// Name: manage_mem_deadman_task
+//
+// Description: Verify that if a memory deadman_task was scheduled on GPE1 last cycle
+// then it is completed. Then if there is a new task to be scheduled
+// for this cycle, then schedule it on the GPE1 engine.
+// Called every 2ms.
+//
+// End Function Specification
+
+// MAX number of timeout cycles allowed for memory deadman IPC task
+// before logging an error
+#define MEM_DEADMAN_TASK_TIMEOUT 2
+
+void manage_mem_deadman_task(void)
+{
+ //if a task is scheduled, verify that it is completed ...
+ //track # of consecutive failures on a specific RDIMM
+ static uint8_t L_scom_timeout[NUM_NIMBUS_MCAS] = {0};
+
+ errlHndl_t l_err = NULL; // Error handler
+ int rc = 0; // Return code
+ uint8_t mca; // MCA of last memory deadman task (scheduled/not-configured)
+ static bool L_gpe_scheduled = false;
+ static bool L_gpe_idle_traced = false;
+ static bool L_gpe_timeout_logged = false;
+ static bool L_gpe_had_1_tick = false;
+
+ uint32_t gpe_rc = G_gpe_reset_mem_deadman_args.error.rc; // IPC task rc
+
+ do
+ { // mca of last memory deadman task (either not-configured or scheduled).
+ mca = G_gpe_reset_mem_deadman_args.mca;
+
+ //First, check to see if the previous GPE request still running
+ if( !(async_request_is_idle(&G_reset_mem_deadman_request.request)) )
+ {
+ L_scom_timeout[mca]++;
+ //This can happen due to variability in when the task runs
+ if(!L_gpe_idle_traced && L_gpe_had_1_tick)
+ {
+ TRAC_INFO("manage_mem_deadman_task: GPE is still running. mca[%d]", mca);
+ L_gpe_idle_traced = true;
+ }
+ L_gpe_had_1_tick = true;
+ break;
+ }
+ else
+ {
+ //Request is idle
+ L_gpe_had_1_tick = false;
+ if(L_gpe_idle_traced)
+ {
+ TRAC_INFO("manage_mem_deadman_task: GPE completed. mca[%d]", mca);
+ L_gpe_idle_traced = false;
+ }
+ }
+
+ //check scom status
+ if(L_gpe_scheduled)
+ {
+ if(!async_request_completed(&G_reset_mem_deadman_request.request) || gpe_rc)
+ {
+ //Request failed. Keep count of failures and log an error if we reach a
+ //max retry count
+ L_scom_timeout[mca]++;
+ if(L_scom_timeout[mca] >= MEM_DEADMAN_TASK_TIMEOUT)
+ {
+ break;
+ }
+
+ }
+ else // A Task was scheduled last cycle, completed successfully, no errors
+ {
+ //Reset the timeout.
+ L_scom_timeout[mca] = 0;
+ }
+ }
+
+ //The previous GPE job completed. Now get ready for the next job.
+ L_gpe_scheduled = false;
+
+
+ //We didn't fail, update mca (irrespective of whether it will be scheduled)
+ if ( mca >= NUM_NIMBUS_MCAS )
+ {
+ mca = 0;
+ }
+ else
+ {
+ mca++;
+ }
+ G_gpe_reset_mem_deadman_args.mca = mca;
+
+
+ // If the MCA is not configured, break
+ if(!NIMBUS_DIMM_INDEX_THROTTLING_CONFIGURED(mca))
+ {
+ break;
+ }
+
+ // The MCA is configured, and the previous IPC task completed successfully
+ rc = gpe_request_schedule(&G_reset_mem_deadman_request);
+
+ // Always log an error if gpe request schedule fails
+ if( rc )
+ {
+ //Error in schedule gpe memory deadman reset task
+ TRAC_ERR("manage_mem_deadman_task: Failed to schedule memory deadman reset task rc=%x",
+ rc);
+
+ /* @
+ * @errortype
+ * @moduleid POKE_WD_TIMERS
+ * @reasoncode GPE_REQUEST_SCHEDULE_FAILURE
+ * @userdata1 rc - gpe_request_schedule return code
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc OCC Failed to schedule a GPE job for memory deadman reset
+ */
+ l_err = createErrl(
+ POKE_WD_TIMERS, // modId
+ GPE_REQUEST_SCHEDULE_FAILURE, // reasoncode
+ OCC_NO_EXTENDED_RC, // Extended reason code
+ ERRL_SEV_UNRECOVERABLE, // Severity
+ NULL, // Trace Buf
+ DEFAULT_TRACE_SIZE, // Trace Size
+ rc, // userdata1
+ 0 // userdata2
+ );
+
+ addUsrDtlsToErrl(
+ l_err, //io_err
+ (uint8_t *) &(G_reset_mem_deadman_request.ffdc), //i_dataPtr,
+ sizeof(G_reset_mem_deadman_request.ffdc), //i_size
+ ERRL_USR_DTL_STRUCT_VERSION_1, //version
+ ERRL_USR_DTL_BINARY_DATA); //type
+
+ REQUEST_RESET(l_err); //This will add a firmware callout for us
+ break;
+
+ }
+
+ // Successfully scheduled a new memory deadman timer gpe IPC request
+ L_gpe_scheduled = true;
+
+ } while(0);
+
+
+ if(L_scom_timeout[mca] >= MEM_DEADMAN_TASK_TIMEOUT && L_gpe_timeout_logged == false)
+ {
+ TRAC_ERR("manage_mem_deadman_task: Timeout scomming MCA[%d]", mca);
+
+ /* @
+ * @errortype
+ * @moduleid POKE_WD_TIMERS
+ * @reasoncode GPE_REQUEST_TASK_TIMEOUT
+ * @userdata1 mca number
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Timed out trying to reset the memory deadman timer.
+ */
+
+ l_err = createErrl(
+ POKE_WD_TIMERS, // modId
+ GPE_REQUEST_TASK_TIMEOUT, // reasoncode
+ OCC_NO_EXTENDED_RC, // Extended reason code
+ ERRL_SEV_PREDICTIVE, // Severity
+ NULL, // Trace Buf
+ DEFAULT_TRACE_SIZE, // Trace Size
+ mca, // userdata1
+ 0 // userdata2
+ );
+
+ addUsrDtlsToErrl(l_err, //io_err
+ (uint8_t *) &(G_reset_mem_deadman_request.ffdc), //i_dataPtr,
+ sizeof(G_reset_mem_deadman_request.ffdc), //i_size
+ ERRL_USR_DTL_STRUCT_VERSION_1, //version
+ ERRL_USR_DTL_BINARY_DATA); //type
+
+ // Commit Error Log
+ commitErrl(&l_err);
+
+ L_gpe_timeout_logged = true;
+ }
+
+ return;
+}
+
+// Function Specification
+//
+// Name: check_pgpe_beacon
+//
+// Description: Checks the PGPE Beacon every 4ms
+// logs an error and resets if it
+// doesn't change for 8 ms
+//
+// End Function Specification
+
+void check_pgpe_beacon(void)
+{
+ uint32_t pgpe_beacon; // PGPE Beacon value now
+ static uint32_t L_prev_pgpe_beacon = 0; // PGPE Beacon value 4 ms ago
+ static bool L_first_pgpe_beacon_check = true; // First time examining Beacon?
+ static bool L_pgpe_beacon_unchanged_4ms = false; // pgpe beacon unchanged once (4ms)
+ static bool L_error_logged = false; // trace and error log only once
+ errlHndl_t l_err = NULL; // Error handler
+ do
+ {
+ // return PGPE Beacon
+ pgpe_beacon = in32(G_pgpe_beacon_address);
+
+ // in first invocation, just initialize L_prev_pgpe_beacon
+ // don't check if the PGPE Beacon value changed
+ if(L_first_pgpe_beacon_check)
+ {
+ L_prev_pgpe_beacon = pgpe_beacon;
+ L_first_pgpe_beacon_check = false;
+ break;
+ }
+
+ // L_prev_pgpe_beacon has been initialized; Every 4ms verify
+ // that PGPE Beacon has changed relative to previous reading
+ if(pgpe_beacon == L_prev_pgpe_beacon)
+ {
+ if(false == L_pgpe_beacon_unchanged_4ms)
+ {
+ // First time beacon unchaged (4ms), mark flag
+ L_pgpe_beacon_unchanged_4ms = true;
+ break;
+ }
+ else if (false == L_error_logged)
+ {
+ L_error_logged = true;
+
+ // Second time beacon unchanged (8ms), log timeout error
+ TRAC_ERR("Error PGPE Beacon didn't change for 8 ms: %d",
+ pgpe_beacon);
+
+ /*
+ * @errortype
+ * @moduleid POKE_WD_TIMERS
+ * @reasoncode INTERNAL_HW_FAILURE
+ * @userdata1 PGPE Beacon Value
+ * @userdata2 PGPE Beacon Address
+ * @userdata4 PGPE_BEACON_TIMEOUT
+ * @devdesc PGPE Beacon timeout
+ */
+ l_err = createErrl(POKE_WD_TIMERS, // mod id
+ PGPE_BEACON_TIMEOUT, // reason code
+ OCC_NO_EXTENDED_RC, // Extended reason code
+ ERRL_SEV_UNRECOVERABLE, // severity
+ NULL, // trace buffer
+ 0, // trace size
+ pgpe_beacon, // userdata1
+ G_pgpe_beacon_address); // userdata2
+
+ // Commit error log and request reset
+ REQUEST_RESET(l_err);
+ }
+ }
+ else
+ {
+ // pgpe beacon changed over the last 4 ms
+ L_pgpe_beacon_unchanged_4ms = false;
+ }
+ } while(0);
+
+}
+
+
+// Function Specification
+//
// Name: ppc405WDTHndlerFull
//
// Description: PPC405 watchdog interrupt handler
@@ -219,9 +576,8 @@ void ppc405WDTHndlerFull(void * i_arg, SsxIrqId i_irq, int i_priority)
else
{
-// TEMP -- NOT SUPPORTED IN PHASE1
-// OCC_HALT(ERRL_RC_WDOG_TIMER);
-TRAC_ERR("Should have halted here due to WDOG");
+ OCC_HALT(ERRL_RC_WDOG_TIMER);
+ TRAC_ERR("Should have halted here due to WDOG");
}
}
}
@@ -237,7 +593,6 @@ TRAC_ERR("Should have halted here due to WDOG");
void ocbTHndlerFull(void * i_arg, SsxIrqId i_irq, int i_priority)
{
// OCC_HALT with exception code passed in.
-// TEMP -- NOT SUPPORTED IN PHASE1
-// OCC_HALT(ERRL_RC_OCB_TIMER);
-TRAC_ERR("Should have halted here due to THndlerFull");
+ OCC_HALT(ERRL_RC_OCB_TIMER);
+ TRAC_ERR("Should have halted here due to THndlerFull");
}
diff --git a/src/occ_405/timer/timer.h b/src/occ_405/timer/timer.h
index 777a626..d374ce9 100755
--- a/src/occ_405/timer/timer.h
+++ b/src/occ_405/timer/timer.h
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -69,6 +69,10 @@ void initWatchdogTimers() INIT_SECTION;
// Task to reset PPC405 watchdog timer and reset OCB timer
void task_poke_watchdogs(struct task *i_self);
+void manage_mem_deadman_task(void);
+void init_mem_deadman_reset_task(void);
+void check_pgpe_beacon(void);
+
//*************************************************************************
// Functions
//*************************************************************************
diff --git a/src/occ_405/timer/timer_service_codes.h b/src/occ_405/timer/timer_service_codes.h
index 820ba88..ea9ced9 100755
--- a/src/occ_405/timer/timer_service_codes.h
+++ b/src/occ_405/timer/timer_service_codes.h
@@ -45,7 +45,7 @@
enum occTimerModuleId
{
INIT_WD_TIMERS = TMER_COMP_ID | 0x00,
- RESET_OCB_TIMER = TMER_COMP_ID | 0x01,
+ POKE_WD_TIMERS = TMER_COMP_ID | 0x01,
};
//*************************************************************************
OpenPOWER on IntegriCloud