aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Lippert <rlippert@google.com>2017-11-20 11:40:36 +0530
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-11-20 20:36:07 -0600
commit27c35b967a84788a45260579802b8ffa66ed05e8 (patch)
tree0d06429859e957ac16333beb16650b2f8fa9ee99
parentcbbd16bfbeef40b9f98d9d457fa024a23bfcc23e (diff)
downloadskiboot-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.c23
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)