aboutsummaryrefslogtreecommitdiff
path: root/core/direct-controls.c
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2018-05-03 18:38:08 +1000
committerStewart Smith <stewart@linux.ibm.com>2018-05-06 10:27:37 -0500
commit5a1463d17d4b7420eba53be0f8a2fb3235dbaeff (patch)
treed86f0fd22dd1acd79c929cb93441632bbed4394c /core/direct-controls.c
parent7dcd66655835fb9985686dad1393285bb75a0876 (diff)
downloadskiboot-5a1463d17d4b7420eba53be0f8a2fb3235dbaeff.zip
skiboot-5a1463d17d4b7420eba53be0f8a2fb3235dbaeff.tar.gz
skiboot-5a1463d17d4b7420eba53be0f8a2fb3235dbaeff.tar.bz2
core/direct-controls: fix p9_cont_thread for stopped/inactive threads
Firstly, p9_cont_thread should check that the thread actually was quiesced before it tries to resume it. Anything could happen if we try this from an arbitrary thread state. Then when resuming a quiesced thread that is inactive or stopped (in a stop idle state), we must not send a core_start direct control, clear_maint must be used in these cases. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'core/direct-controls.c')
-rw-r--r--core/direct-controls.c87
1 files changed, 70 insertions, 17 deletions
diff --git a/core/direct-controls.c b/core/direct-controls.c
index c7b9c9b..4511a11 100644
--- a/core/direct-controls.c
+++ b/core/direct-controls.c
@@ -273,10 +273,14 @@ static int p8_sreset_thread(struct cpu_thread *cpu)
#define P9_QUIESCE_POLL_INTERVAL 100
#define P9_QUIESCE_TIMEOUT 100000
+#define P9_CORE_THREAD_STATE 0x10ab3
+#define P9_THREAD_INFO 0x10a9b
+
#define P9_EC_DIRECT_CONTROLS 0x10a9c
#define P9_THREAD_STOP(t) PPC_BIT(7 + 8*(t))
#define P9_THREAD_CONT(t) PPC_BIT(6 + 8*(t))
#define P9_THREAD_SRESET(t) PPC_BIT(4 + 8*(t))
+#define P9_THREAD_CLEAR_MAINT(t) PPC_BIT(3 + 8*(t))
#define P9_THREAD_PWR(t) PPC_BIT(32 + 8*(t))
/* EC_PPM_SPECIAL_WKUP_HYP */
@@ -412,6 +416,72 @@ static int p9_thread_quiesced(struct cpu_thread *cpu)
return 0;
}
+static int p9_cont_thread(struct cpu_thread *cpu)
+{
+ uint32_t chip_id = pir_to_chip_id(cpu->pir);
+ uint32_t core_id = pir_to_core_id(cpu->pir);
+ uint32_t thread_id = pir_to_thread_id(cpu->pir);
+ uint32_t cts_addr;
+ uint32_t ti_addr;
+ uint32_t dctl_addr;
+ uint64_t core_thread_state;
+ uint64_t thread_info;
+ bool active, stop;
+ int rc;
+
+ rc = p9_thread_quiesced(cpu);
+ if (rc < 0)
+ return rc;
+ if (!rc) {
+ prlog(PR_ERR, "Could not cont thread %u:%u:%u:"
+ " Thread is not quiesced.\n",
+ chip_id, core_id, thread_id);
+ return OPAL_BUSY;
+ }
+
+ cts_addr = XSCOM_ADDR_P9_EC(core_id, P9_CORE_THREAD_STATE);
+ ti_addr = XSCOM_ADDR_P9_EC(core_id, P9_THREAD_INFO);
+ dctl_addr = XSCOM_ADDR_P9_EC(core_id, P9_EC_DIRECT_CONTROLS);
+
+ if (xscom_read(chip_id, cts_addr, &core_thread_state)) {
+ prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
+ " Unable to read CORE_THREAD_STATE.\n",
+ chip_id, core_id, thread_id);
+ return OPAL_HARDWARE;
+ }
+ if (core_thread_state & PPC_BIT(56 + thread_id))
+ stop = true;
+ else
+ stop = false;
+
+ if (xscom_read(chip_id, ti_addr, &thread_info)) {
+ prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
+ " Unable to read THREAD_INFO.\n",
+ chip_id, core_id, thread_id);
+ return OPAL_HARDWARE;
+ }
+ if (thread_info & PPC_BIT(thread_id))
+ active = true;
+ else
+ active = false;
+
+ if (!active || stop) {
+ if (xscom_write(chip_id, dctl_addr, P9_THREAD_CLEAR_MAINT(thread_id))) {
+ prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
+ " Unable to write EC_DIRECT_CONTROLS.\n",
+ chip_id, core_id, thread_id);
+ }
+ } else {
+ if (xscom_write(chip_id, dctl_addr, P9_THREAD_CONT(thread_id))) {
+ prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
+ " Unable to write EC_DIRECT_CONTROLS.\n",
+ chip_id, core_id, thread_id);
+ }
+ }
+
+ return 0;
+}
+
static int p9_stop_thread(struct cpu_thread *cpu)
{
uint32_t chip_id = pir_to_chip_id(cpu->pir);
@@ -461,23 +531,6 @@ static int p9_stop_thread(struct cpu_thread *cpu)
return OPAL_HARDWARE;
}
-static int p9_cont_thread(struct cpu_thread *cpu)
-{
- uint32_t chip_id = pir_to_chip_id(cpu->pir);
- uint32_t core_id = pir_to_core_id(cpu->pir);
- uint32_t thread_id = pir_to_thread_id(cpu->pir);
- uint32_t dctl_addr;
-
- dctl_addr = XSCOM_ADDR_P9_EC(core_id, P9_EC_DIRECT_CONTROLS);
- if (xscom_write(chip_id, dctl_addr, P9_THREAD_CONT(thread_id))) {
- prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
- " Unable to write EC_DIRECT_CONTROLS.\n",
- chip_id, core_id, thread_id);
- }
-
- return 0;
-}
-
static int p9_sreset_thread(struct cpu_thread *cpu)
{
uint32_t chip_id = pir_to_chip_id(cpu->pir);