[Skiboot] [PATCH] sensors: dts: Assert special wakeup on idle cores while reading temperature
Shilpasri G Bhat
shilpa.bhat at linux.vnet.ibm.com
Wed Aug 9 04:32:36 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>
---
TODO:
- Make the dts_read_core_temp_p9() call async
core/hostservices.c | 79 +++++++++++++++++++++++++++++++-------------------
hw/dts.c | 32 ++++++++++++++++++--
hw/slw.c | 20 +++++++++++++
include/hostservices.h | 4 +++
include/skiboot.h | 3 ++
include/xscom.h | 12 ++++++++
6 files changed, 118 insertions(+), 32 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/hw/dts.c b/hw/dts.c
index a10df58..a19f7d3 100644
--- a/hw/dts.c
+++ b/hw/dts.c
@@ -20,6 +20,7 @@
#include <dts.h>
#include <skiboot.h>
#include <opal-api.h>
+#include <hostservices.h>
struct dts {
uint8_t valid;
@@ -198,16 +199,32 @@ static int dts_read_core_temp_p8(uint32_t pir, struct dts *dts)
*/
static int dts_read_core_temp_p9(uint32_t pir, struct dts *dts)
{
+ struct cpu_thread *cpu = find_cpu_by_pir(pir);
int32_t chip_id = pir_to_chip_id(pir);
int32_t core = pir_to_core_id(pir);
uint64_t dts0;
struct dts temps[P9_CORE_ZONES];
int rc;
+ bool stopped;
+
+ /* Check if CPU is idle */
+ stopped = check_core_stopped(pir);
+
+ /* Assert special wakeup */
+ if (stopped) {
+ rc = hservice_set_special_wakeup(cpu);
+ if (rc) {
+ prerror("Failed to set special wakeup on %d (%d)\n",
+ core, rc);
+ return rc;
+ }
+ }
+ /* Read temperature */
rc = xscom_read(chip_id, XSCOM_ADDR_P9_EC(core, EC_THERM_P9_DTS_RESULT0),
&dts0);
if (rc)
- return rc;
+ goto clr;
dts_decode_one_dts(dts0 >> 48, &temps[P9_CORE_DTS0]);
dts_decode_one_dts(dts0 >> 32, &temps[P9_CORE_DTS1]);
@@ -222,7 +239,18 @@ 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;
+clr:
+ /* Release special wakeup */
+ if (stopped) {
+ rc = hservice_clr_special_wakeup(cpu);
+ if (rc) {
+ prerror("Failed to clear special wakeup on %d (%d)\n",
+ core, rc);
+ return rc;
+ }
+ }
+
+ return rc;
}
static int dts_read_core_temp(uint32_t pir, struct dts *dts)
diff --git a/hw/slw.c b/hw/slw.c
index c0ab9de..32fc6d4 100644
--- a/hw/slw.c
+++ b/hw/slw.c
@@ -1521,3 +1521,23 @@ void slw_init(void)
slw_init_chip_p9(chip);
}
}
+
+bool check_core_stopped(u32 pir)
+{
+ u64 val;
+ u32 chip_id = pir_to_chip_id(pir);
+ u32 core = pir_to_core_id(pir);
+ int rc;
+
+ rc = xscom_read(chip_id, XSCOM_ADDR_P9_EX(core, EX_PM_SISR), &val);
+ if (rc) {
+ prerror("Failed to read Stop Interface Status Register %d\n",
+ rc);
+ return true;
+ }
+
+ if (pir & 0x4)
+ return (!(val & EX_PM_SISR_INST_C1));
+ else
+ return (!(val & EX_PM_SISR_INST_C0));
+}
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/skiboot.h b/include/skiboot.h
index 4b7d519..c1e2aa3 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -317,4 +317,7 @@ extern int occ_sensor_group_clear(u32 group_hndl, int token);
extern void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles,
int nr_phandles, int chipid);
+/* Check if a core has entered a stop state */
+bool check_core_stopped(u32 pir);
+
#endif /* __SKIBOOT_H */
diff --git a/include/xscom.h b/include/xscom.h
index 5a5d0b9..da72dd5 100644
--- a/include/xscom.h
+++ b/include/xscom.h
@@ -148,6 +148,18 @@
#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)
+
+/* P9 CME Local Stop Interface Status Register */
+#define EX_PM_SISR 0x1204C
+#define EX_PM_SISR_INST_C0 PPC_BIT(46)
+#define EX_PM_SISR_INST_C1 PPC_BIT(47)
+
/************* XXXX Move these P8 only registers elswhere !!! ****************/
--
1.8.3.1
More information about the Skiboot
mailing list