diff options
author | Wael El-Essawy <welessa@us.ibm.com> | 2017-03-22 10:30:48 -0500 |
---|---|---|
committer | Wael El-Essawy <welessa@us.ibm.com> | 2017-05-10 13:53:16 -0400 |
commit | cf2258322bb72a2cd868f8eaef25e9a665077f4f (patch) | |
tree | f7a9b13ef36943246377ff623ed917fa4fd08ada /src/occ_gpe1 | |
parent | ff3b5a1c08389bf766de21adcd033e3c7b86af87 (diff) | |
download | talos-occ-cf2258322bb72a2cd868f8eaef25e9a665077f4f.tar.gz talos-occ-cf2258322bb72a2cd868f8eaef25e9a665077f4f.zip |
Memory Power Control when entering and exiting IPS (Idle Power Save)
memory power control settings for IPS/default modes - as defined by
memory config data packet version 0x21 - are applied to memory
power control registers of all configured ports whenever the OCC
enters/exits IPS, respectively.
Change-Id: I56514bb8cbab80c6d4877edc74db96f3b011e523
RTC: 165546
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/38294
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com>
Reviewed-by: Wael El-Essawy <welessa@us.ibm.com>
Diffstat (limited to 'src/occ_gpe1')
-rw-r--r-- | src/occ_gpe1/gpe1_dimm_control.c | 6 | ||||
-rw-r--r-- | src/occ_gpe1/gpe1_memory_power_control.c | 218 | ||||
-rw-r--r-- | src/occ_gpe1/gpe1_memory_power_control.h | 47 | ||||
-rw-r--r-- | src/occ_gpe1/ipc_func_tables.c | 25 | ||||
-rw-r--r-- | src/occ_gpe1/topfiles.mk | 2 |
5 files changed, 281 insertions, 17 deletions
diff --git a/src/occ_gpe1/gpe1_dimm_control.c b/src/occ_gpe1/gpe1_dimm_control.c index a87a464..5319913 100644 --- a/src/occ_gpe1/gpe1_dimm_control.c +++ b/src/occ_gpe1/gpe1_dimm_control.c @@ -30,6 +30,7 @@ #include "gpe_err.h" #include "gpe_util.h" #include "dimm_structs.h" +#include "mca_addresses.h" #include "gpe1.h" /* @@ -47,9 +48,6 @@ * End Function Specification */ -#define NUM_NIMBUS_MC_PAIRS 2 -#define MAX_NUM_MCU_PORTS 4 - void gpe_dimm_control(ipc_msg_t* cmd, void* arg) { // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it. @@ -96,7 +94,7 @@ void gpe_dimm_control(ipc_msg_t* cmd, void* arg) N_M_DIMM_TCR(mc,port), regValue, rc); gpe_set_ffdc(&(args->error), N_M_DIMM_TCR(mc,port), - GPE_RC_SCOM_GET_FAILED, rc); + GPE_RC_SCOM_PUT_FAILED, rc); break; } else diff --git a/src/occ_gpe1/gpe1_memory_power_control.c b/src/occ_gpe1/gpe1_memory_power_control.c new file mode 100644 index 0000000..a63ac75 --- /dev/null +++ b/src/occ_gpe1/gpe1_memory_power_control.c @@ -0,0 +1,218 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_gpe1/gpe1_memory_power_control.c $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* [+] 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.h" +#include "ppe42_scom.h" +#include "ipc_api.h" +#include "ipc_async_cmd.h" +#include "gpe_err.h" +#include "gpe_util.h" +#include "mem_structs.h" +#include "gpe1.h" +#include "mca_addresses.h" +#include "gpe1_memory_power_control.h" + +/* + * Function Specifications: + * + * Name: gpe_mem_power_control + * + * Description: memory power control code on the GPE + * + * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct + * + * Outputs: error: sets rc, address, and ffdc in the cmd_data's + * GpeErrorStruct + * + * End Function Specification + */ + +void gpe_mem_power_control(ipc_msg_t* cmd, void* arg) +{ + // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it. + // the ipc arguments passed through the ipc_msg_t structure, has a pointer + // to the mem_power_control_args_t struct. + + int rc; + uint64_t pcrRegValue; // holds Power Control Register0 + uint64_t strRegValue; // holds STR0 SCOM register value + ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd; + mem_power_control_args_t *args = (mem_power_control_args_t*)async_cmd->cmd_data; + + uint8_t mc = args->mc, port = args->port; // memory controller pair and port + + args->error.error = 0; + args->error.ffdc = 0; + + do + { // For now, just loop through all ports amd MCs. May be time consuming, and + // if this is the case will change code to set only one port/mc register pair + + // Read Power Control Register 0 SCOM + rc = getscom_abs(POWER_CTRL_REG0(mc,port), &pcrRegValue); + + if(rc) + { + PK_TRACE("gpe_mem_power_control: Power Control Register 0 read fails" + "MC#|Port:0x%08x, Address:0x%08x, rc:0x%08x", + (uint32_t)((mc << 16) | port), + POWER_CTRL_REG0(mc,port), rc); + + gpe_set_ffdc(&(args->error), POWER_CTRL_REG0(mc,port), + GPE_RC_SCOM_GET_FAILED, rc); + break; + } + + // Read STR0 SCOM Register + rc = getscom_abs(STR_REG0(mc,port), &strRegValue); + + if(rc) + { + PK_TRACE("gpe_mem_power_control: STR Register 0 read fails" + "MC#|Port:0x%08x, Address:0x%08x, rc:0x%08x", + (uint32_t)((mc << 16) | port), + STR_REG0(mc,port), rc); + + gpe_set_ffdc(&(args->error), STR_REG0(mc,port), + GPE_RC_SCOM_GET_FAILED, rc); + break; + } + + switch(args->mem_pwr_ctl) + { + // MEM_PWR_CTL_OFF: clears the following memory control bits: + // - master_enable (PCR0(2)), + // - power_down_enable (PCR0(22)), + // - STR_enable (STR(0)), + // - disable_memory_clocks (STR(1)). + case MEM_PWR_CTL_OFF: + pcrRegValue = CLR_2BITS(pcrRegValue, PCR0_MASTER_ENABLE_BIT, PCR0_POWERDOWN_ENABLE_BIT); + strRegValue = CLR_2BITS(strRegValue, STR0_STR_ENABLE_BIT, STR0_DISABLE_MEMORY_CLOCKS_BIT); + break; + + // MEM_PWR_CTL_POWER_DOWN: + // sets: + // - master_enable (PCR0(2)), + // - power_down_enable (PCR0(22)), + // and clears: + // - STR_enable (STR(0)), + // - disable_memory_clocks (STR(1)). + case MEM_PWR_CTL_POWER_DOWN: + pcrRegValue = SET_2BITS(pcrRegValue, PCR0_MASTER_ENABLE_BIT, PCR0_POWERDOWN_ENABLE_BIT); + + strRegValue = CLR_2BITS(strRegValue, STR0_STR_ENABLE_BIT, STR0_DISABLE_MEMORY_CLOCKS_BIT); + break; + + // MEM_PWR_CTL_PD_AND_STR: + // sets: + // - master_enable (PCR0(2)), + // - power_down_enable (PCR0(22)), + // - STR_enable (STR(0)), + // and clears: + // - disable_memory_clocks (STR(1)). + case MEM_PWR_CTL_PD_AND_STR: + pcrRegValue = SET_2BITS(pcrRegValue, PCR0_MASTER_ENABLE_BIT, PCR0_POWERDOWN_ENABLE_BIT); + strRegValue = SET_BIT(strRegValue, STR0_STR_ENABLE_BIT); + + strRegValue = CLR_BIT(strRegValue, STR0_DISABLE_MEMORY_CLOCKS_BIT); + break; + + // MEM_PWR_CTL_PD_AND_STR_CLK_STOP: set the following memory power control bits + // - master_enable (PCR0(2)), + // - power_down_enable (PCR0(22)), + // - STR_enable (STR(0)), + // - disable_memory_clocks (STR(1)). + case MEM_PWR_CTL_PD_AND_STR_CLK_STOP: + pcrRegValue = SET_2BITS(pcrRegValue, PCR0_MASTER_ENABLE_BIT, PCR0_POWERDOWN_ENABLE_BIT); + strRegValue = SET_2BITS(strRegValue, STR0_STR_ENABLE_BIT, STR0_DISABLE_MEMORY_CLOCKS_BIT); + break; + + default: + PK_TRACE("gpe_mem_power_control: Invalid memory power control command:0x%d", + args->mem_pwr_ctl); + rc = GPE_RC_INVALID_MEM_PWR_CTL; + + gpe_set_ffdc(&(args->error), 0, rc, args->mem_pwr_ctl); + break; + } + if(rc) + { + break; + } + + // Write Modified Power Control Register 0 SCOM + rc = putscom_abs(POWER_CTRL_REG0(mc,port), pcrRegValue); + + if(rc) + { + PK_TRACE("gpe_mem_power_control: Power Control Register 0 write fails" + "MC#|Port:0x%08x, Address:0x%08x, rc:0x%08x", + (uint32_t)((mc << 16) | port), + POWER_CTRL_REG0(mc,port), rc); + + gpe_set_ffdc(&(args->error), POWER_CTRL_REG0(mc,port), + GPE_RC_SCOM_PUT_FAILED, rc); + break; + } + + // Write Modified STR0 SCOM Register + rc = putscom_abs(STR_REG0(mc,port), strRegValue); + + if(rc) + { + PK_TRACE("gpe_mem_power_control: STR Register 0 write fails" + "MC#|Port:0x%08x, Address:0x%08x, rc:0x%08x", + (uint32_t)((mc << 16) | port), + STR_REG0(mc,port), rc); + + gpe_set_ffdc(&(args->error), STR_REG0(mc,port), + GPE_RC_SCOM_PUT_FAILED, rc); + } + } while(0); + + + if(rc) + { + GPE1_DIMM_DBG("gpe_mem_power_control: Failed to apply memory power control"); + } + else + { + GPE1_DIMM_DBG("gpe_mem_power_control: Memory Power Control Register successfully written" + "mc|port#:0x%04x, PCR0:0x%08x, STR0:0x%08x", + (uint16_t)((mc << 8) | port), + pcrRegValue, strRegValue); + } + + + // send back a response, IPC success even if ffdc/rc are non zeros + rc = ipc_send_rsp(cmd, IPC_RC_SUCCESS); + if(rc) + { + PK_TRACE("gpe_mem_power_control: Failed to send response back. Halting GPE1", rc); + gpe_set_ffdc(&(args->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc); + pk_halt(); + } + +} diff --git a/src/occ_gpe1/gpe1_memory_power_control.h b/src/occ_gpe1/gpe1_memory_power_control.h new file mode 100644 index 0000000..e5f704f --- /dev/null +++ b/src/occ_gpe1/gpe1_memory_power_control.h @@ -0,0 +1,47 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/occ_gpe1/gpe1_memory_power_control.h $ */ +/* */ +/* OpenPOWER OnChipController Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,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 */ + +#ifndef _GPE1_MEMORY_POWER_CONTROL_H +#define _GPE1_MEMORY_POWER_CONTROL_H + +#define PCR0_MASTER_ENABLE_BIT 2 +#define PCR0_POWERDOWN_ENABLE_BIT 22 + +#define STR0_STR_ENABLE_BIT 0 +#define STR0_DISABLE_MEMORY_CLOCKS_BIT 1 + +// Big Endian set/clear bit MACROS +#define SET_BIT(var, bit) (var | (0x8000000000000000 >> bit) ) + +#define CLR_BIT(var, bit) (var & ~(0x8000000000000000 >> bit) ) + + +// Big Endian set/clear 2 different bits MACROS +#define SET_2BITS(var, bit1, bit2) SET_BIT(SET_BIT(var, bit1), bit2) + +#define CLR_2BITS(var, bit1, bit2) CLR_BIT(CLR_BIT(var, bit1), bit2) + + +#endif // _GPE1_MEMORY_POWER_CONTROL_H diff --git a/src/occ_gpe1/ipc_func_tables.c b/src/occ_gpe1/ipc_func_tables.c index c2740e9..0e43fad 100644 --- a/src/occ_gpe1/ipc_func_tables.c +++ b/src/occ_gpe1/ipc_func_tables.c @@ -29,6 +29,7 @@ void gpe_dimm_control(ipc_msg_t* cmd, void* arg); void gpe1_nop(ipc_msg_t* cmd, void* arg); void gpe_reset_mem_deadman(ipc_msg_t* cmd, void* arg); void gpe_24x7(ipc_msg_t* cmd, void* arg); +void gpe_mem_power_control(ipc_msg_t* cmd, void* arg); // Function table for multi target (common) functions @@ -49,16 +50,16 @@ IPC_HANDLER(gpe_dimm_sm, 0) // 0 - IPC_ST_DIMM_SM_FUNCID IPC_HANDLER(gpe_dimm_control, 0) // 1 - IPC_ST_DIMM_CONTROL_FUNCID IPC_HANDLER(gpe1_nop, 0) // 2 - IPC_ST_GPE1_NOP IPC_HANDLER(gpe_reset_mem_deadman, 0) // 3 - IPC_ST_RESET_MEM_DEADMAN -IPC_HANDLER(gpe_24x7, 0) // 4 - IPC_ST_24_X_7_FUNCID -IPC_HANDLER_DEFAULT // 5 -IPC_HANDLER_DEFAULT // 6 -IPC_HANDLER_DEFAULT // 7 -IPC_HANDLER_DEFAULT // 8 -IPC_HANDLER_DEFAULT // 9 -IPC_HANDLER_DEFAULT // 10 -IPC_HANDLER_DEFAULT // 11 -IPC_HANDLER_DEFAULT // 12 -IPC_HANDLER_DEFAULT // 13 -IPC_HANDLER_DEFAULT // 14 -IPC_HANDLER_DEFAULT // 15 +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_DEFAULT // 6 +IPC_HANDLER_DEFAULT // 7 +IPC_HANDLER_DEFAULT // 8 +IPC_HANDLER_DEFAULT // 9 +IPC_HANDLER_DEFAULT // 10 +IPC_HANDLER_DEFAULT // 11 +IPC_HANDLER_DEFAULT // 12 +IPC_HANDLER_DEFAULT // 13 +IPC_HANDLER_DEFAULT // 14 +IPC_HANDLER_DEFAULT // 15 IPC_ST_FUNC_TABLE_END diff --git a/src/occ_gpe1/topfiles.mk b/src/occ_gpe1/topfiles.mk index 9983f69..6dbae16 100644 --- a/src/occ_gpe1/topfiles.mk +++ b/src/occ_gpe1/topfiles.mk @@ -25,7 +25,7 @@ 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_24x7.c gpe1_memory_power_control.c TOP-S-SOURCES = |