diff options
author | Robert Lippert <rlippert@google.com> | 2017-11-20 11:40:36 +0530 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2017-11-20 20:36:07 -0600 |
commit | 27c35b967a84788a45260579802b8ffa66ed05e8 (patch) | |
tree | 0d06429859e957ac16333beb16650b2f8fa9ee99 | |
parent | cbbd16bfbeef40b9f98d9d457fa024a23bfcc23e (diff) | |
download | skiboot-27c35b967a84788a45260579802b8ffa66ed05e8.zip skiboot-27c35b967a84788a45260579802b8ffa66ed05e8.tar.gz skiboot-27c35b967a84788a45260579802b8ffa66ed05e8.tar.bz2 |
core/direct-controls: wait for core special wkup bit cleared
When clearing special wakeup bit on a core, wait until the
bit is actually cleared by the hardware in the status register
until returning success.
This may help avoid issues with back-to-back reads where the
special wakeup request is cleared but the firmware is still
processing the request and the next attempt to set the bit
reads an immediate success from the previous operation.
Change-Id: I86ec8cbbbddd1a5724f451244907693bc09e01ea
Signed-off-by: Robert Lippert <rlippert@google.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r-- | core/direct-controls.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/core/direct-controls.c b/core/direct-controls.c index fcb9350..0ed00c1 100644 --- a/core/direct-controls.c +++ b/core/direct-controls.c @@ -95,8 +95,12 @@ static int p9_core_clear_special_wakeup(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 swake_addr; + uint32_t sshhyp_addr; + uint64_t val; + int i; swake_addr = XSCOM_ADDR_P9_EC_SLAVE(core_id, EC_PPM_SPECIAL_WKUP_HYP); + sshhyp_addr = XSCOM_ADDR_P9_EC_SLAVE(core_id, P9_EC_PPM_SSHHYP); /* * De-assert special wakeup after a small delay. @@ -110,8 +114,25 @@ static int p9_core_clear_special_wakeup(struct cpu_thread *cpu) chip_id, core_id); return OPAL_HARDWARE; } + time_wait_us(1); - return OPAL_SUCCESS; + for (i = 0; i < P9_SPWKUP_TIMEOUT/P9_SPWKUP_POLL_INTERVAL; i++) { + if (xscom_read(chip_id, sshhyp_addr, &val)) { + prlog(PR_ERR, "Could not clear special wakeup on %u:%u:" + " Unable to read PPM_SSHHYP.\n", + chip_id, core_id); + return OPAL_HARDWARE; + } + if (!(val & P9_SPECIAL_WKUP_DONE)) + return 0; + + time_wait_us(P9_SPWKUP_POLL_INTERVAL); + } + + prlog(PR_ERR, "Could not clear special wakeup on %u:%u:" + " timeout waiting for clear of SPECIAL_WKUP_DONE.\n", + chip_id, core_id); + return OPAL_HARDWARE; } static int p9_thread_quiesced(struct cpu_thread *cpu) |