Skip to content

Commit

Permalink
AVS Bus divider, loadline and misc changes
Browse files Browse the repository at this point in the history
- validate CRC in cmd response
- read current / voltage on alternating ticks (commands on both bus for each tick)
- calculate chip power (with loadline) and power for each tick
- update divider value for bus speed
- add error history counters and add them to logs

Change-Id: I33bce916dc2dffef6a6d616633a5f1266d7baa7e
RTC: 163992
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/34947
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Martha Broyles <mbroyles@us.ibm.com>
Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com>
  • Loading branch information
cjcain committed Jan 18, 2017
1 parent 4141b5f commit 6089fe0
Show file tree
Hide file tree
Showing 15 changed files with 497 additions and 156 deletions.
213 changes: 167 additions & 46 deletions src/occ_405/amec/amec_sensors_power.c
Expand Up @@ -405,113 +405,234 @@ void amec_update_apss_sensors(void)
}


// Read the current from AVS Bus and update sensors
void process_avsbus_current()
{
if (G_avsbus_vdd_monitoring)
{
// Read Vdd current (returns 10mA)
uint32_t current = avsbus_read(AVSBUS_VDD, AVSBUS_CURRENT);
if (current != 0)
{
// Current value stored in the sensor should be in 10mA (scale -2)
sensor_update(AMECSENSOR_PTR(CURVDD), (uint16_t)current);
}
}
if (G_avsbus_vdn_monitoring)
{
// Read Vdn current (returns 10mA)
uint32_t current = avsbus_read(AVSBUS_VDN, AVSBUS_CURRENT);
if (current != 0)
{
// Current value stored in the sensor should be in 10mA (scale -2)
sensor_update(AMECSENSOR_PTR(CURVDN), (uint16_t)current);
}
}
}


// Read the voltage from AVS Bus and update sensors
void process_avsbus_voltage()
{
if (G_avsbus_vdd_monitoring)
{
// Read Vdd voltage (returns mV)
uint32_t voltage = avsbus_read(AVSBUS_VDD, AVSBUS_VOLTAGE);
if (voltage != 0)
{
// Voltage value stored in the sensor should be in 100mV (scale -1)
voltage /= 100;
sensor_update(AMECSENSOR_PTR(VOLTVDD), (uint16_t)voltage);
}
}
if (G_avsbus_vdn_monitoring)
{
// Read Vdn voltage (returns mV)
uint32_t voltage = avsbus_read(AVSBUS_VDN, AVSBUS_VOLTAGE);
if (voltage != 0)
{
// Voltage value stored in the sensor should be in 100mV (scale -1)
voltage /= 100;
sensor_update(AMECSENSOR_PTR(VOLTVDN), (uint16_t)voltage);
}
}
}


// Calculate chip voltage and power and update sensors
void update_avsbus_power_sensors(const avsbus_type_e i_type)
{
static bool L_throttle_vdd = FALSE;
static bool L_throttle_vdn = FALSE;
bool * L_throttle = &L_throttle_vdd;
uint16_t l_loadline = G_sysConfigData.avsbus_vdd.loadline;
uint32_t l_voltageSensor = VOLTVDD;
// TODO: RTC 130216 : read loadline and distloss from Pstate Super Structure
uint16_t l_loadline = 0x61AB; // OCCPstateParmBlock.vdd_sysparm.loadline_uohm
uint16_t l_distloss = 0x0000; // OCCPstateParmBlock.vdd_sysparm.distloss_uohm
uint32_t l_currentSensor = CURVDD;
uint32_t l_voltageSensor = VOLTVDD;
uint32_t l_voltageChip = VOLTVDDSENSE;
uint32_t l_powerSensor = PWRVDD;
if (AVSBUS_VDN == i_type)
{
L_throttle = &L_throttle_vdn;
l_loadline = G_sysConfigData.avsbus_vdn.loadline;
l_voltageSensor = VOLTVDN;
l_loadline = 0x6BA8; // OCCPstateParmBlock.vdn_sysparm.loadline_uohm
l_distloss = 0x0000; // OCCPstateParmBlock.vdn_sysparm.distloss_uohm
l_currentSensor = CURVDN;
l_voltageSensor = VOLTVDN;
l_voltageChip = VOLTVDNSENSE;
l_powerSensor = PWRVDN;
}

// Read AVS Bus current
uint32_t l_current_10ma = avsbus_read(i_type, AVSBUS_CURRENT);
if (l_current_10ma != 0)
// Read latest voltage/current sensors
const sensor_t *volt = getSensorByGsid(l_voltageSensor);
const uint32_t l_voltage_100mv = volt->sample;
const sensor_t *curr = getSensorByGsid(l_currentSensor);
const uint32_t l_current_10ma = curr->sample;

#ifdef AVSDEBUG
// TODO: RTC 130216 : REMOVE AFTER VERIFYING loadline/distlost from Pstate Super Structure
static uint8_t L_traceCount = 0;
if (L_traceCount < 4)
{
// Current value stored in the sensor should be in 10mA (scale -2)
sensor_update(AMECSENSOR_PTR(l_currentSensor), (uint16_t)l_current_10ma);
TRAC_INFO("update_avsbus_power_sensors: #%d Vd%c=%dx100mV, I=%dx10mA", L_traceCount, (i_type==AVSBUS_VDD)?'d':'n',
l_voltage_100mv, l_current_10ma);
TRAC_INFO("update_avsbus_power_sensors: #%d Vd%c Rloadline=%d, Rdistloss=%d", L_traceCount, (i_type==AVSBUS_VDD)?'d':'n',
l_loadline, l_distloss);
}
#endif

// Read AVS Bus voltage
uint32_t l_voltage_mv = avsbus_read(i_type, AVSBUS_VOLTAGE);
if (l_voltage_mv != 0)
if ((l_voltage_100mv != 0) && (l_current_10ma != 0))
{
// Calculate voltage on just processor package (need to take load-line into account)
// Voltage value stored in the sensor should be in 100mV (scale -1)
// (current is in 10mA units, and load-line is in tenth of microOhms)
// v(V) = i(10mA)*(1 A/1000 mA) * r(1/10u Ohm)*(1 Ohm/1,000,000 uOhm)
// = i * (1 A/100) * r * (1 Ohm/10,000,000)
// = i * r / 1,000,000,000
// v(V) = i(10mA)*(1 A/1000 mA) * r(1 uOhm)*(1 Ohm/1,000,000 uOhm)
// = i * (1 A/100) * r * (1 Ohm/1,000,000)
// = i * r / 100,000,000
// v(mV) = v(V) * 1,000
// v(100mV) = v(mV) / 100
// = (v(V) * 1,000) / 100 = v(V) * 10
// = (i * r / 1,000,000,000) * 10 = i * r / 100,000,000
const uint64_t l_volt_drop_100mv = (l_current_10ma * l_loadline) / 100000000;
// TODO: RTC163992 - Confirm loadline calculation (chip package load line vs regulator load line)
// Convert voltage to 100mv units and subtract the drop:
int32_t l_voltage_100mv = (l_voltage_mv / 100) - l_volt_drop_100mv;
if ((l_voltage_100mv <= 0) || (l_voltage_100mv > 0xFFFF))
// = (i * r / 100,000,000) * 10 = i * r / 10,000,000
// NOTE: distloss is the same as Rpath in the WOF algorithm
const uint64_t l_volt_drop_100mv = (l_current_10ma * (l_loadline+l_distloss)) / 10000000;
// Calculate chip voltage
int32_t l_chip_voltage_100mv = l_voltage_100mv - l_volt_drop_100mv;
if ((l_chip_voltage_100mv <= 0) || (l_chip_voltage_100mv > 0xFFFF))
{
// Voltage out of range, write 0
// Voltage out of range, do not write sensors
if (!*L_throttle)
{
TRAC_ERR("update_avsbus_power_sensors: Voltage out of range! %dmV - %d(100mV) = %d(100mV)",
l_voltage_mv, WORD_LOW(l_volt_drop_100mv), l_voltage_100mv);
TRAC_ERR("update_avsbus_power_sensors: chip voltage out of range! %dmV - %d(100mV) = %d(100mV)",
l_voltage_100mv, WORD_LOW(l_volt_drop_100mv), l_chip_voltage_100mv);
*L_throttle = TRUE;
}
l_voltage_100mv = 0;
}
else
{
*L_throttle = FALSE;
}
sensor_update(AMECSENSOR_PTR(l_voltageSensor), (uint16_t)l_voltage_100mv);

if (l_current_10ma != 0)
{
// Update chip voltage (remote sense adjusted for loadline) (100mV units)
sensor_update(AMECSENSOR_PTR(l_voltageChip), (uint16_t)l_chip_voltage_100mv);

// Power value stored in the sensor should be in W (scale 0)
// p(W) = v(V) * i(A) = v(100mV)*100/1000 * i(10mA)*10/1000
// = v(100mV)/10 * i(10mA)/100
// = v(100mv) * i(10mA) / 1000
const uint32_t l_power = l_voltage_100mv * l_current_10ma / 1000;
const uint32_t l_power = l_chip_voltage_100mv * l_current_10ma / 1000;
sensor_update(AMECSENSOR_PTR(l_powerSensor), (uint16_t)l_power);
}

#ifdef AVSDEBUG
// TODO: RTC 130216 : REMOVE AFTER VERIFYING loadline/distlost from Pstate Super Structure
if (L_traceCount < 4)
{
const sensor_t *power = getSensorByGsid(l_powerSensor);
TRAC_INFO("update_avsbus_power_sensors: #%d Vd%cs=%dx100mV, P=%dW", L_traceCount, (i_type==AVSBUS_VDD)?'d':'n',
l_chip_voltage_100mv, power->sample);
}
#endif
}

#ifdef AVSDEBUG
// TODO: RTC 130216 : REMOVE AFTER VERIFYING loadline/distlost from Pstate Super Structure
++L_traceCount;
#endif

} // end update_avsbus_power_sensors()


// Function Specification
//
// Name: amec_update_avsbus_sensors
//
// Description: Read AVS Bus data and update sensors
// Description: Read AVS Bus data and update sensors (called every tick)
// The very first tick kicks off a read of the currents for both buses (Vdd/Vdn).
// The next tick will process the currents and then start a read of the voltages.
// The next tick will process the voltages and then start a read of the currents.
// (readings for each bus will essentially be updated every 2 ticks)
//
// Thread: RealTime Loop
//
// End Function Specification
void amec_update_avsbus_sensors(void)
{
static bool L_vdd_state = TRUE;

if (L_vdd_state)
static enum {
AVSBUS_STATE_DISABLED = 0,
AVSBUS_STATE_INITIATE_READ = 1,
AVSBUS_STATE_PROCESS_CURRENT = 2,
AVSBUS_STATE_PROCESS_VOLTAGE = 3
} L_avsbus_state = AVSBUS_STATE_INITIATE_READ;

if (isSafeStateRequested())
{
// If AVS Bus Vdd config data was received, update sensors
if (G_avsbus_vdd_monitoring)
{
update_avsbus_power_sensors(AVSBUS_VDD);
}
L_avsbus_state = AVSBUS_STATE_DISABLED;
G_avsbus_vdd_monitoring = FALSE;
G_avsbus_vdn_monitoring = FALSE;
}
else

switch (L_avsbus_state)
{
// If AVS Bus Vdn config data was received, update sensors
if (G_avsbus_vdn_monitoring)
{
update_avsbus_power_sensors(AVSBUS_VDN);
}
case AVSBUS_STATE_INITIATE_READ:
// Start first AVS Bus read of current
initiate_avsbus_reads(AVSBUS_CURRENT);
L_avsbus_state = AVSBUS_STATE_PROCESS_CURRENT;
break;

case AVSBUS_STATE_PROCESS_CURRENT:
// Process the current readings
process_avsbus_current();
// Initiate read of voltages
initiate_avsbus_reads(AVSBUS_VOLTAGE);
L_avsbus_state = AVSBUS_STATE_PROCESS_VOLTAGE;
break;

case AVSBUS_STATE_PROCESS_VOLTAGE:
// Process the voltage readings
process_avsbus_voltage();
// Initiate read of currents
initiate_avsbus_reads(AVSBUS_CURRENT);
L_avsbus_state = AVSBUS_STATE_PROCESS_CURRENT;
break;

case AVSBUS_STATE_DISABLED:
break;

default:
TRAC_ERR("amec_update_avsbus_sensors: INVALID AVSBUS STATE 0x%02X", L_avsbus_state);
L_avsbus_state = AVSBUS_STATE_INITIATE_READ;
break;
}

// Alternate between Vdd/Vdn readings
L_vdd_state = !L_vdd_state;
// Update the chip voltage and power sensors after every reading
if (G_avsbus_vdd_monitoring)
{
update_avsbus_power_sensors(AVSBUS_VDD);
}
if (G_avsbus_vdn_monitoring)
{
update_avsbus_power_sensors(AVSBUS_VDN);
}

} // end amec_update_avsbus_sensors()

Expand Down
2 changes: 2 additions & 0 deletions src/occ_405/amec/amec_sys.h
Expand Up @@ -79,6 +79,8 @@ typedef struct
sensor_t gpetickdur[NUM_GPE_ENGINES];
sensor_t prcdupdatedur;
sensor_t probe250us[NUM_AMEC_FW_PROBES];
sensor_t voltvddsense;
sensor_t voltvdnsense;

// DPS update flag
// 8 bit flag: =1, no updating allowed; =0, updating is allowed
Expand Down
8 changes: 8 additions & 0 deletions src/occ_405/cmdh/cmdh_fsp_cmds.c
Expand Up @@ -1160,6 +1160,14 @@ errlHndl_t cmdh_tmgt_setmodestate(const cmdh_fsp_cmd_t * i_cmd_ptr,
break;
}

// Verify not in safe state
if ((TRUE == isSafeStateRequested()) || (CURRENT_STATE() == OCC_STATE_SAFE))
{
CMDH_TRAC_ERR("OCC in safe state, rejecting mode change request");
l_rc = ERRL_RC_INVALID_STATE;
break;
}

// -------------------------------------------------
// Act on State & Mode Changes
// -------------------------------------------------
Expand Down
10 changes: 4 additions & 6 deletions src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
Expand Up @@ -1001,9 +1001,8 @@ errlHndl_t data_store_avsbus_config(const cmdh_fsp_cmd_t * i_cmd_ptr,
G_avsbus_vdd_monitoring = TRUE;
G_sysConfigData.avsbus_vdd.bus = l_cmd_ptr->vdd_bus;
G_sysConfigData.avsbus_vdd.rail = l_cmd_ptr->vdd_rail;
G_sysConfigData.avsbus_vdd.loadline = l_cmd_ptr->vdd_loadline;
CNFG_DBG("data_store_avsbus_config: Vdd bus[%d] rail[%d] loadline[0x%02X]",
G_sysConfigData.avsbus_vdd.bus, G_sysConfigData.avsbus_vdd.rail, G_sysConfigData.avsbus_vdd.loadline);
CNFG_DBG("data_store_avsbus_config: Vdd bus[%d] rail[%d]",
G_sysConfigData.avsbus_vdd.bus, G_sysConfigData.avsbus_vdd.rail);
}
else
{
Expand Down Expand Up @@ -1035,9 +1034,8 @@ errlHndl_t data_store_avsbus_config(const cmdh_fsp_cmd_t * i_cmd_ptr,
G_avsbus_vdn_monitoring = TRUE;
G_sysConfigData.avsbus_vdn.bus = l_cmd_ptr->vdn_bus;
G_sysConfigData.avsbus_vdn.rail = l_cmd_ptr->vdn_rail;
G_sysConfigData.avsbus_vdn.loadline = l_cmd_ptr->vdn_loadline;
CNFG_DBG("data_store_avsbus_config: Vdn bus[%d] rail[%d] loadline[0x%02X]",
G_sysConfigData.avsbus_vdn.bus, G_sysConfigData.avsbus_vdn.rail, G_sysConfigData.avsbus_vdn.loadline);
CNFG_DBG("data_store_avsbus_config: Vdn bus[%d] rail[%d]",
G_sysConfigData.avsbus_vdn.bus, G_sysConfigData.avsbus_vdn.rail);

if (G_avsbus_vdd_monitoring &&
(G_sysConfigData.avsbus_vdd.bus == G_sysConfigData.avsbus_vdn.bus))
Expand Down
4 changes: 2 additions & 2 deletions src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.h
Expand Up @@ -140,10 +140,10 @@ typedef struct __attribute__ ((packed))
uint8_t version;
uint8_t vdd_bus;
uint8_t vdd_rail;
uint16_t vdd_loadline;
uint16_t reserved1;
uint8_t vdn_bus;
uint8_t vdn_rail;
uint16_t vdn_loadline;
uint16_t reserved2;
}cmdh_avsbus_config_t;

// Used by TMGT to send OCC the PCAP config data.
Expand Down
9 changes: 9 additions & 0 deletions src/occ_405/dimm/dimm.c
Expand Up @@ -281,6 +281,15 @@ void mark_dimm_failed()

g_amec->proc[0].memctl[port].centaur.dimm_temps[dimm].flags |= FRU_SENSOR_STATUS_ERROR;

if (port == 0)
{
INCREMENT_ERR_HISTORY(ERR_DIMM_I2C_PORT0);
}
else
{
INCREMENT_ERR_HISTORY(ERR_DIMM_I2C_PORT1);
}

if (++G_dimm[port][dimm].errorCount > MAX_CONSECUTIVE_DIMM_RESETS)
{
// Disable collection on this DIMM, collect FFDC and log error
Expand Down

0 comments on commit 6089fe0

Please sign in to comment.