[Skiboot] [RFC V2] sensors: dts: Assert special wakeup on idle cores while reading temperature
Shilpasri G Bhat
shilpa.bhat at linux.vnet.ibm.com
Mon Aug 14 17:28:01 AEST 2017
In P9, when a core enters a stop state, its clocks will be stopped
to save power and hence we will not be able to perform a scom
operation to read the DTS temperature sensor. Hence, assert
a special wakeup on cores that have entered a stop state in order to
successfully complete the scom operation.
Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
Changes from V1:
- Make dts_sensor_read() async call for P9
- Remove reading from Stop-Interface-Status-Register as it can be racy
to decide if a core is in stop and then read DTS scom.
- Issue unconditional special wakeup while reading temperature.
core/hostservices.c | 79 +++++++++++++++++++++++++++++-------------------
core/sensor.c | 2 +-
hw/dts.c | 81 ++++++++++++++++++++++++++++++++++++++++++--------
include/dts.h | 2 +-
include/hostservices.h | 4 +++
include/xscom.h | 6 ++++
6 files changed, 130 insertions(+), 44 deletions(-)
diff --git a/core/hostservices.c b/core/hostservices.c
index d1f6fda..345c8c0 100644
--- a/core/hostservices.c
+++ b/core/hostservices.c
@@ -545,9 +545,10 @@ static void hservice_nanosleep(uint64_t i_seconds, uint64_t i_nano_seconds)
nanosleep_nopoll(&ts, NULL);
}
-static int hservice_set_special_wakeup(struct cpu_thread *cpu)
+int hservice_set_special_wakeup(struct cpu_thread *cpu)
{
uint64_t val, core_id, poll_target, stamp;
+ u64 wkup_addr, wkup_mask, pm_reg, idle_hist_reg;
int rc;
/*
@@ -558,20 +559,36 @@ static int hservice_set_special_wakeup(struct cpu_thread *cpu)
/* Grab core ID once */
core_id = pir_to_core_id(cpu->pir);
+ switch (proc_gen) {
+ case proc_gen_p8:
+ wkup_addr = XSCOM_ADDR_P8_EX_SLAVE(core_id,
+ EX_PM_SPECIAL_WAKEUP_PHYP);
+ wkup_mask = EX_PM_GP0_SPECIAL_WAKEUP_DONE;
+ pm_reg = XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_GP0);
+ idle_hist_reg = XSCOM_ADDR_P8_EX_SLAVE(core_id,
+ EX_PM_IDLE_STATE_HISTORY_PHYP);
+ break;
+ case proc_gen_p9:
+ wkup_addr = XSCOM_ADDR_P9_EC_SLAVE(core_id,
+ EC_PPM_SPECIAL_WKUP_HYP);
+ wkup_mask = EC_PPM_GPPMR_SPECIAL_WAKEUP_DONE;
+ pm_reg = XSCOM_ADDR_P9_EC_SLAVE(core_id, EC_PPM_GPPMR_SCOM);
+ idle_hist_reg = XSCOM_ADDR_P9_EC_SLAVE(core_id,
+ EC_PM_IDLE_STATE_HISTORY_PHYP);
+ break;
+ default:
+ return OPAL_UNSUPPORTED;
+ }
+
/*
* The original HWp reads the XSCOM first but ignores the result
* and error, let's do the same until I know for sure that is
* not necessary
*/
- xscom_read(cpu->chip_id,
- XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_SPECIAL_WAKEUP_PHYP),
- &val);
+ xscom_read(cpu->chip_id, wkup_addr, &val);
/* Then we write special wakeup */
- rc = xscom_write(cpu->chip_id,
- XSCOM_ADDR_P8_EX_SLAVE(core_id,
- EX_PM_SPECIAL_WAKEUP_PHYP),
- PPC_BIT(0));
+ rc = xscom_write(cpu->chip_id, wkup_addr, PPC_BIT(0));
if (rc) {
prerror("HBRT: XSCOM error %d asserting special"
" wakeup on 0x%x\n", rc, cpu->pir);
@@ -602,14 +619,13 @@ static int hservice_set_special_wakeup(struct cpu_thread *cpu)
stamp = mftb();
poll_target = stamp + msecs_to_tb(200);
val = 0;
- while (!(val & EX_PM_GP0_SPECIAL_WAKEUP_DONE)) {
+
+ while (!(val & wkup_mask)) {
/* Wait 1 us */
hservice_nanosleep(0, 1000);
/* Read PM state */
- rc = xscom_read(cpu->chip_id,
- XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_GP0),
- &val);
+ rc = xscom_read(cpu->chip_id, pm_reg, &val);
if (rc) {
prerror("HBRT: XSCOM error %d reading PM state on"
" 0x%x\n", rc, cpu->pir);
@@ -621,7 +637,7 @@ static int hservice_set_special_wakeup(struct cpu_thread *cpu)
}
/* Success ? */
- if (val & EX_PM_GP0_SPECIAL_WAKEUP_DONE) {
+ if (val & wkup_mask) {
uint64_t now = mftb();
prlog(PR_TRACE, "HBRT: Special wakeup complete after %ld us\n",
tb_to_usecs(now - stamp));
@@ -639,23 +655,19 @@ static int hservice_set_special_wakeup(struct cpu_thread *cpu)
prerror("HBRT: Timeout on special wakeup of 0x%0x\n", cpu->pir);
prerror("HBRT: PM0 = 0x%016llx\n", val);
val = -1;
- xscom_read(cpu->chip_id,
- XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_SPECIAL_WAKEUP_PHYP),
- &val);
+ xscom_read(cpu->chip_id, wkup_addr, &val);
prerror("HBRT: SPC_WKUP = 0x%016llx\n", val);
val = -1;
- xscom_read(cpu->chip_id,
- XSCOM_ADDR_P8_EX_SLAVE(core_id,
- EX_PM_IDLE_STATE_HISTORY_PHYP),
- &val);
+ xscom_read(cpu->chip_id, idle_hist_reg, &val);
prerror("HBRT: HISTORY = 0x%016llx\n", val);
return OPAL_HARDWARE;
}
-static int hservice_clr_special_wakeup(struct cpu_thread *cpu)
+int hservice_clr_special_wakeup(struct cpu_thread *cpu)
{
uint64_t val, core_id;
+ u64 addr;
int rc;
/*
@@ -671,14 +683,23 @@ static int hservice_clr_special_wakeup(struct cpu_thread *cpu)
* and error, let's do the same until I know for sure that is
* not necessary
*/
- xscom_read(cpu->chip_id,
- XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_SPECIAL_WAKEUP_PHYP),
- &val);
+ switch (proc_gen) {
+ case proc_gen_p8:
+ addr = XSCOM_ADDR_P8_EX_SLAVE(core_id,
+ EX_PM_SPECIAL_WAKEUP_PHYP);
+ break;
+ case proc_gen_p9:
+ addr = XSCOM_ADDR_P9_EC_SLAVE(core_id,
+ EC_PPM_SPECIAL_WKUP_HYP);
+ break;
+ default:
+ return OPAL_UNSUPPORTED;
+ }
+
+ xscom_read(cpu->chip_id, addr, &val);
/* Then we write special wakeup */
- rc = xscom_write(cpu->chip_id,
- XSCOM_ADDR_P8_EX_SLAVE(core_id,
- EX_PM_SPECIAL_WAKEUP_PHYP), 0);
+ rc = xscom_write(cpu->chip_id, addr, 0);
if (rc) {
prerror("HBRT: XSCOM error %d deasserting"
" special wakeup on 0x%x\n", rc, cpu->pir);
@@ -690,9 +711,7 @@ static int hservice_clr_special_wakeup(struct cpu_thread *cpu)
* "This puts an inherent delay in the propagation of the reset
* transition"
*/
- xscom_read(cpu->chip_id,
- XSCOM_ADDR_P8_EX_SLAVE(core_id, EX_PM_SPECIAL_WAKEUP_PHYP),
- &val);
+ xscom_read(cpu->chip_id, addr, &val);
return 0;
}
diff --git a/core/sensor.c b/core/sensor.c
index 57b21bc..0e2a5ca 100644
--- a/core/sensor.c
+++ b/core/sensor.c
@@ -28,7 +28,7 @@ static int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
{
switch (sensor_get_family(sensor_hndl)) {
case SENSOR_DTS:
- return dts_sensor_read(sensor_hndl, sensor_data);
+ return dts_sensor_read(sensor_hndl, token, sensor_data);
case SENSOR_OCC:
return occ_sensor_read(sensor_hndl, sensor_data);
default:
diff --git a/hw/dts.c b/hw/dts.c
index a10df58..3524102 100644
--- a/hw/dts.c
+++ b/hw/dts.c
@@ -20,6 +20,10 @@
#include <dts.h>
#include <skiboot.h>
#include <opal-api.h>
+#include <hostservices.h>
+#include <opal-msg.h>
+#include <timer.h>
+#include <timebase.h>
struct dts {
uint8_t valid;
@@ -27,6 +31,14 @@ struct dts {
int16_t temp;
};
+/*
+ * Attributes for the core temperature sensor
+ */
+enum {
+ SENSOR_DTS_ATTR_TEMP_MAX,
+ SENSOR_DTS_ATTR_TEMP_TRIP
+};
+
/* Different sensor locations */
#define P7_CT_ZONE_LSU 0
#define P7_CT_ZONE_ISU 1
@@ -196,7 +208,7 @@ static int dts_read_core_temp_p8(uint32_t pir, struct dts *dts)
* Returns the temperature as the max of all zones and a global trip
* attribute.
*/
-static int dts_read_core_temp_p9(uint32_t pir, struct dts *dts)
+static int _dts_read_core_temp_p9(u32 pir, struct dts *dts)
{
int32_t chip_id = pir_to_chip_id(pir);
int32_t core = pir_to_core_id(pir);
@@ -222,7 +234,55 @@ static int dts_read_core_temp_p9(uint32_t pir, struct dts *dts)
* them for the moment until we understand why.
*/
dts->trip = 0;
- return 0;
+ return rc;
+}
+
+static struct timer dts_timer;
+static struct dts_async_data {
+ u32 *sensor_data;
+ u32 pir;
+ int token;
+ u8 attr;
+} dts_async_data;
+
+static void dts_spl_wkup(struct timer *t __unused, void *data,
+ u64 now __unused)
+{
+ struct dts_async_data *async_data = data;
+ struct dts dts;
+ u32 pir;
+ int rc;
+
+ pir = async_data->pir;
+ rc = hservice_set_special_wakeup(find_cpu_by_pir(pir));
+ if (rc) {
+ prerror("Failed to set special wakeup on %d (%d)\n",
+ pir_to_core_id(pir), rc);
+ goto out;
+ }
+
+ if (!_dts_read_core_temp_p9(pir, &dts)) {
+ if (async_data->attr == SENSOR_DTS_ATTR_TEMP_MAX)
+ *async_data->sensor_data = dts.temp;
+ else if (async_data->attr == SENSOR_DTS_ATTR_TEMP_TRIP)
+ *async_data->sensor_data = dts.trip;
+ }
+
+ rc = hservice_clr_special_wakeup(find_cpu_by_pir(pir));
+ if (rc)
+ prerror("Failed to clear special wakeup on %d (%d)\n",
+ pir_to_core_id(pir), rc);
+out:
+ rc = opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL, async_data->token,
+ rc);
+ if (rc)
+ prerror("Failed to queue async message\n");
+}
+
+static int dts_read_core_temp_p9(void)
+{
+ schedule_timer(&dts_timer, usecs_to_tb(1));
+ return OPAL_ASYNC_COMPLETION;
}
static int dts_read_core_temp(uint32_t pir, struct dts *dts)
@@ -237,7 +297,7 @@ static int dts_read_core_temp(uint32_t pir, struct dts *dts)
rc = dts_read_core_temp_p8(pir, dts);
break;
case proc_gen_p9:
- rc = dts_read_core_temp_p9(pir, dts);
+ rc = dts_read_core_temp_p9();
break;
default:
rc = OPAL_UNSUPPORTED;
@@ -303,20 +363,12 @@ enum sensor_dts_class {
};
/*
- * Attributes for the core temperature sensor
- */
-enum {
- SENSOR_DTS_ATTR_TEMP_MAX,
- SENSOR_DTS_ATTR_TEMP_TRIP
-};
-
-/*
* Extract the centaur chip id which was truncated to fit in the
* resource identifier field of the sensor handler
*/
#define centaur_get_id(rid) (0x80000000 | ((rid) & 0x3ff))
-int64_t dts_sensor_read(uint32_t sensor_hndl, uint32_t *sensor_data)
+int64_t dts_sensor_read(u32 sensor_hndl, int token, u32 *sensor_data)
{
uint8_t attr = sensor_get_attr(sensor_hndl);
uint32_t rid = sensor_get_rid(sensor_hndl);
@@ -330,6 +382,10 @@ int64_t dts_sensor_read(uint32_t sensor_hndl, uint32_t *sensor_data)
switch (sensor_get_frc(sensor_hndl)) {
case SENSOR_DTS_CORE_TEMP:
+ dts_async_data.attr = attr;
+ dts_async_data.pir = rid;
+ dts_async_data.sensor_data = sensor_data;
+ dts_async_data.token = token;
rc = dts_read_core_temp(rid, &dts);
break;
case SENSOR_DTS_MEM_TEMP:
@@ -431,5 +487,6 @@ bool dts_sensor_create_nodes(struct dt_node *sensors)
dt_add_property_string(node, "label", "Centaur");
}
+ init_timer(&dts_timer, dts_spl_wkup, &dts_async_data);
return true;
}
diff --git a/include/dts.h b/include/dts.h
index b37919f..17e2e15 100644
--- a/include/dts.h
+++ b/include/dts.h
@@ -19,7 +19,7 @@
#include <stdint.h>
-extern int64_t dts_sensor_read(uint32_t sensor_hndl, uint32_t *sensor_data);
+extern int64_t dts_sensor_read(u32 sensor_hndl, int token, u32 *sensor_data);
extern bool dts_sensor_create_nodes(struct dt_node *sensors);
#endif /* __DTS_H */
diff --git a/include/hostservices.h b/include/hostservices.h
index d6bb3e3..82303b8 100644
--- a/include/hostservices.h
+++ b/include/hostservices.h
@@ -17,6 +17,8 @@
#ifndef __HOSTSERVICES_H
#define __HOSTSERVICES_H
+#include <cpu.h>
+
bool hservices_init(void);
void hservices_lid_preload(void);
bool hservices_lid_preload_complete(void);
@@ -39,4 +41,6 @@ void host_services_occ_base_setup(void);
int find_master_and_slave_occ(uint64_t **master, uint64_t **slave,
int *nr_masters, int *nr_slaves);
+int hservice_clr_special_wakeup(struct cpu_thread *cpu);
+int hservice_set_special_wakeup(struct cpu_thread *cpu);
#endif /* __HOSTSERVICES_H */
diff --git a/include/xscom.h b/include/xscom.h
index 5a5d0b9..a3ce99e 100644
--- a/include/xscom.h
+++ b/include/xscom.h
@@ -148,6 +148,12 @@
#define EC_PPM_SPECIAL_WKUP_FSP 0x010B
#define EC_PPM_SPECIAL_WKUP_OCC 0x010C
#define EC_PPM_SPECIAL_WKUP_HYP 0x010D
+#define EC_PM_IDLE_STATE_HISTORY_PHYP 0x0114
+#define EC_PPM_GPPMR_SCOM 0x0100
+#define EC_PPM_GPPMR_SCOM1 0x0101
+#define EC_PPM_GPPMR_SCOM2 0x0102
+
+#define EC_PPM_GPPMR_SPECIAL_WAKEUP_DONE PPC_BIT(0)
/************* XXXX Move these P8 only registers elswhere !!! ****************/
--
1.8.3.1
More information about the Skiboot
mailing list