Skip to content

Commit

Permalink
core/direct-controls: fix p9_cont_thread for stopped/inactive threads
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
npiggin authored and stewartsmith committed May 6, 2018
1 parent 7dcd666 commit 5a1463d
Showing 1 changed file with 70 additions and 17 deletions.
87 changes: 70 additions & 17 deletions core/direct-controls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 5a1463d

Please sign in to comment.