diff options
author | Reza Arbab <arbab@linux.ibm.com> | 2019-07-17 15:44:22 -0500 |
---|---|---|
committer | Oliver O'Halloran <oohall@gmail.com> | 2019-07-26 15:30:21 +1000 |
commit | 8279e529d524bce56fca20f6ece0e6f92b0f7aba (patch) | |
tree | 34eca8ed940bc7d791f57b72178a86fa43463d45 /hw/cache-p9.c | |
parent | 6db75f1d8e91548a52143949f2b5c49f1e87d608 (diff) | |
download | skiboot-8279e529d524bce56fca20f6ece0e6f92b0f7aba.zip skiboot-8279e529d524bce56fca20f6ece0e6f92b0f7aba.tar.gz skiboot-8279e529d524bce56fca20f6ece0e6f92b0f7aba.tar.bz2 |
npu2: Prepare purge_l2_l3_caches() for reuse
Move this to a separate compilation unit with its own header, for reuse.
The code formerly in npu2.c is copied verbatim. The #defines formerly in
npu2-regs.h have been reformatted and changed to use PPC_BITMASK()
instead of multiple consecutive PPC_BIT()s.
Signed-off-by: Reza Arbab <arbab@linux.ibm.com>
Reviewed-by: Andrew Donnellan <ajd@linux.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: Stewart Smith <stewart@linux.ibm.com>
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Diffstat (limited to 'hw/cache-p9.c')
-rw-r--r-- | hw/cache-p9.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/hw/cache-p9.c b/hw/cache-p9.c new file mode 100644 index 0000000..ea6f00b --- /dev/null +++ b/hw/cache-p9.c @@ -0,0 +1,173 @@ +/* Copyright 2019 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <skiboot.h> +#include <chip.h> +#include <xscom.h> +#include <timebase.h> +#include <xscom-p9-regs.h> +#include <cache-p9.h> + +/* Registers and bits used to clear the L2 and L3 cache */ +#define L2_PRD_PURGE_CMD_REG 0x1080e +#define L2_PRD_PURGE_CMD_TRIGGER PPC_BIT(0) +#define L2_PRD_PURGE_CMD_TYPE_MASK PPC_BITMASK(1, 4) +#define L2CAC_FLUSH 0x0 +#define L2_PRD_PURGE_CMD_REG_BUSY PPC_BIT(9) +#define L3_PRD_PURGE_REG 0x1180e +#define L3_PRD_PURGE_REQ PPC_BIT(0) +#define L3_PRD_PURGE_TTYPE_MASK PPC_BITMASK(1, 4) +#define L3_FULL_PURGE 0x0 + +#define L2_L3_PRD_PURGE_TIMEOUT_MS 20 + +static int start_l2_purge(uint32_t chip_id, uint32_t core_id) +{ + uint64_t addr = XSCOM_ADDR_P9_EX(core_id, L2_PRD_PURGE_CMD_REG); + int rc; + + rc = xscom_write_mask(chip_id, addr, L2CAC_FLUSH, + L2_PRD_PURGE_CMD_TYPE_MASK); + if (!rc) + rc = xscom_write_mask(chip_id, addr, L2_PRD_PURGE_CMD_TRIGGER, + L2_PRD_PURGE_CMD_TRIGGER); + if (rc) + prlog(PR_ERR, "PURGE L2 on core 0x%x: XSCOM write_mask " + "failed %i\n", core_id, rc); + return rc; +} + +static int wait_l2_purge(uint32_t chip_id, uint32_t core_id) +{ + uint64_t val; + uint64_t addr = XSCOM_ADDR_P9_EX(core_id, L2_PRD_PURGE_CMD_REG); + unsigned long now = mftb(); + unsigned long end = now + msecs_to_tb(L2_L3_PRD_PURGE_TIMEOUT_MS); + int rc; + + while (1) { + rc = xscom_read(chip_id, addr, &val); + if (rc) { + prlog(PR_ERR, "PURGE L2 on core 0x%x: XSCOM read " + "failed %i\n", core_id, rc); + break; + } + if (!(val & L2_PRD_PURGE_CMD_REG_BUSY)) + break; + now = mftb(); + if (tb_compare(now, end) == TB_AAFTERB) { + prlog(PR_ERR, "PURGE L2 on core 0x%x timed out %i\n", + core_id, rc); + return OPAL_BUSY; + } + } + + /* We have to clear the trigger bit ourselves */ + val &= ~L2_PRD_PURGE_CMD_TRIGGER; + rc = xscom_write(chip_id, addr, val); + if (rc) + prlog(PR_ERR, "PURGE L2 on core 0x%x: XSCOM write failed %i\n", + core_id, rc); + return rc; +} + +static int start_l3_purge(uint32_t chip_id, uint32_t core_id) +{ + uint64_t addr = XSCOM_ADDR_P9_EX(core_id, L3_PRD_PURGE_REG); + int rc; + + rc = xscom_write_mask(chip_id, addr, L3_FULL_PURGE, + L3_PRD_PURGE_TTYPE_MASK); + if (!rc) + rc = xscom_write_mask(chip_id, addr, L3_PRD_PURGE_REQ, + L3_PRD_PURGE_REQ); + if (rc) + prlog(PR_ERR, "PURGE L3 on core 0x%x: XSCOM write_mask " + "failed %i\n", core_id, rc); + return rc; +} + +static int wait_l3_purge(uint32_t chip_id, uint32_t core_id) +{ + uint64_t val; + uint64_t addr = XSCOM_ADDR_P9_EX(core_id, L3_PRD_PURGE_REG); + unsigned long now = mftb(); + unsigned long end = now + msecs_to_tb(L2_L3_PRD_PURGE_TIMEOUT_MS); + int rc; + + /* Trigger bit is automatically set to zero when flushing is done */ + while (1) { + rc = xscom_read(chip_id, addr, &val); + if (rc) { + prlog(PR_ERR, "PURGE L3 on core 0x%x: XSCOM read " + "failed %i\n", core_id, rc); + break; + } + if (!(val & L3_PRD_PURGE_REQ)) + break; + now = mftb(); + if (tb_compare(now, end) == TB_AAFTERB) { + prlog(PR_ERR, "PURGE L3 on core 0x%x timed out %i\n", + core_id, rc); + return OPAL_BUSY; + } + } + return rc; +} + +int64_t purge_l2_l3_caches(void) +{ + struct cpu_thread *t; + uint64_t core_id, prev_core_id = (uint64_t)-1; + int rc; + unsigned long now = mftb(); + + for_each_ungarded_cpu(t) { + /* Only need to do it once per core chiplet */ + core_id = pir_to_core_id(t->pir); + if (prev_core_id == core_id) + continue; + prev_core_id = core_id; + rc = start_l2_purge(t->chip_id, core_id); + if (rc) + goto trace_exit; + rc = start_l3_purge(t->chip_id, core_id); + if (rc) + goto trace_exit; + } + + prev_core_id = (uint64_t)-1; + for_each_ungarded_cpu(t) { + /* Only need to do it once per core chiplet */ + core_id = pir_to_core_id(t->pir); + if (prev_core_id == core_id) + continue; + prev_core_id = core_id; + + rc = wait_l2_purge(t->chip_id, core_id); + if (rc) + goto trace_exit; + rc = wait_l3_purge(t->chip_id, core_id); + if (rc) + goto trace_exit; + } + +trace_exit: + prlog(PR_TRACE, "L2/L3 purging took %ldus\n", + tb_to_usecs(mftb() - now)); + + return rc; +} |