diff options
author | Vasant Hegde <hegdevasant@linux.vnet.ibm.com> | 2018-04-23 12:15:31 +0530 |
---|---|---|
committer | Stewart Smith <stewart@linux.ibm.com> | 2018-04-30 19:04:42 -0500 |
commit | 6421fc56dc289c8d14a1ce9eddbb88d3687fbb77 (patch) | |
tree | 1e62f2f3795e0476f092107d76a68b1a432e7394 /hw | |
parent | 6739c890a2f298ed382b9557840a493fb97df44b (diff) | |
download | skiboot-6421fc56dc289c8d14a1ce9eddbb88d3687fbb77.zip skiboot-6421fc56dc289c8d14a1ce9eddbb88d3687fbb77.tar.gz skiboot-6421fc56dc289c8d14a1ce9eddbb88d3687fbb77.tar.bz2 |
Move P8 timer code to separate file
Lets move P8 timer support code from slw.c to sbe-p8.c (as suggested
by BenH). There is a difference between timer support in P8 and P9.
Hence I think it makes sense to name it as sbe-p8.c.
Note that this is pure code movement and renaming functions/variables.
No functionality changes.
Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/Makefile.inc | 2 | ||||
-rw-r--r-- | hw/sbe-p8.c | 203 | ||||
-rw-r--r-- | hw/slw.c | 185 |
3 files changed, 206 insertions, 184 deletions
diff --git a/hw/Makefile.inc b/hw/Makefile.inc index 15bf5cf..4dec986 100644 --- a/hw/Makefile.inc +++ b/hw/Makefile.inc @@ -9,7 +9,7 @@ HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o HW_OBJS += npu2-common.o phys-map.o sbe-p9.o capp.o occ-sensor.o vas.o HW_OBJS += npu2-common.o npu2-opencapi.o phys-map.o sbe-p9.o capp.o occ-sensor.o -HW_OBJS += vas.o +HW_OBJS += vas.o sbe-p8.o HW=hw/built-in.a # FIXME hack this for now diff --git a/hw/sbe-p8.c b/hw/sbe-p8.c new file mode 100644 index 0000000..58049c7 --- /dev/null +++ b/hw/sbe-p8.c @@ -0,0 +1,203 @@ +/* Copyright 2013-2018 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 <device.h> +#include <sbe-p8.h> +#include <skiboot.h> +#include <timebase.h> +#include <xscom.h> + +/* SLW timer related stuff */ +static bool sbe_has_timer; +static uint64_t sbe_timer_inc; +static uint64_t sbe_timer_target; +static uint32_t sbe_timer_chip; +static uint64_t sbe_last_gen; +static uint64_t sbe_last_gen_stamp; + +static void p8_sbe_dump_timer_ffdc(void) +{ + uint64_t i, val; + int64_t rc; + + static const uint32_t dump_regs[] = { + 0xe0000, 0xe0001, 0xe0002, 0xe0003, + 0xe0004, 0xe0005, 0xe0006, 0xe0007, + 0xe0008, 0xe0009, 0xe000a, 0xe000b, + 0xe000c, 0xe000d, 0xe000e, 0xe000f, + 0xe0010, 0xe0011, 0xe0012, 0xe0013, + 0xe0014, 0xe0015, 0xe0016, 0xe0017, + 0xe0018, 0xe0019, + 0x5001c, + 0x50038, 0x50039, 0x5003a, 0x5003b + }; + + /** + * @fwts-label SLWRegisterDump + * @fwts-advice An error condition occurred in sleep/winkle + * engines timer state machine. Dumping debug information to + * root-cause. OPAL/skiboot may be stuck on some operation that + * requires SLW timer state machine (e.g. core powersaving) + */ + prlog(PR_DEBUG, "SLW: Register state:\n"); + + for (i = 0; i < ARRAY_SIZE(dump_regs); i++) { + uint32_t reg = dump_regs[i]; + rc = xscom_read(sbe_timer_chip, reg, &val); + if (rc) { + prlog(PR_DEBUG, "SLW: XSCOM error %lld reading" + " reg 0x%x\n", rc, reg); + break; + } + prlog(PR_DEBUG, "SLW: %5x = %016llx\n", reg, val); + } +} + +/* This is called with the timer lock held, so there is no + * issue with re-entrancy or concurrence + */ +void p8_sbe_update_timer_expiry(uint64_t new_target) +{ + uint64_t count, gen, gen2, req, now = mftb(); + int64_t rc; + + if (!sbe_has_timer || new_target == sbe_timer_target) + return; + + sbe_timer_target = new_target; + + /* Calculate how many increments from now, rounded up */ + if (now < new_target) + count = (new_target - now + sbe_timer_inc - 1) / sbe_timer_inc; + else + count = 1; + + /* Max counter is 24-bit */ + if (count > 0xffffff) + count = 0xffffff; + /* Fabricate update request */ + req = (1ull << 63) | (count << 32); + + prlog(PR_TRACE, "SLW: TMR expiry: 0x%llx, req: %016llx\n", count, req); + + do { + /* Grab generation and spin if odd */ + _xscom_lock(); + for (;;) { + rc = _xscom_read(sbe_timer_chip, 0xE0006, &gen, false); + if (rc) { + prerror("SLW: Error %lld reading tmr gen " + " count\n", rc); + _xscom_unlock(); + return; + } + if (!(gen & 1)) + break; + if (tb_compare(now + msecs_to_tb(1), mftb()) == TB_ABEFOREB) { + /** + * @fwts-label SLWTimerStuck + * @fwts-advice The SLeep/Winkle Engine (SLW) + * failed to increment the generation number + * within our timeout period (it *should* have + * done so within ~10us, not >1ms. OPAL uses + * the SLW timer to schedule some operations, + * but can fall back to the (much less frequent + * OPAL poller, which although does not affect + * functionality, runs *much* less frequently. + * This could have the effect of slow I2C + * operations (for example). It may also mean + * that you *had* an increase in jitter, due + * to slow interactions with SLW. + * This error may also occur if the machine + * is connected to via soft FSI. + */ + prerror("SLW: timer stuck, falling back to OPAL pollers. You will likely have slower I2C and may have experienced increased jitter.\n"); + prlog(PR_DEBUG, "SLW: Stuck with odd generation !\n"); + _xscom_unlock(); + sbe_has_timer = false; + p8_sbe_dump_timer_ffdc(); + return; + } + } + + rc = _xscom_write(sbe_timer_chip, 0x5003A, req, false); + if (rc) { + prerror("SLW: Error %lld writing tmr request\n", rc); + _xscom_unlock(); + return; + } + + /* Re-check gen count */ + rc = _xscom_read(sbe_timer_chip, 0xE0006, &gen2, false); + if (rc) { + prerror("SLW: Error %lld re-reading tmr gen " + " count\n", rc); + _xscom_unlock(); + return; + } + _xscom_unlock(); + } while(gen != gen2); + + /* Check if the timer is working. If at least 1ms has elapsed + * since the last call to this function, check that the gen + * count has changed + */ + if (tb_compare(sbe_last_gen_stamp + msecs_to_tb(1), now) + == TB_ABEFOREB) { + if (sbe_last_gen == gen) { + prlog(PR_ERR, + "SLW: Timer appears to not be running !\n"); + sbe_has_timer = false; + p8_sbe_dump_timer_ffdc(); + } + sbe_last_gen = gen; + sbe_last_gen_stamp = mftb(); + } + + prlog(PR_TRACE, "SLW: gen: %llx\n", gen); +} + +bool p8_sbe_timer_ok(void) +{ + return sbe_has_timer; +} + +void p8_sbe_init_timer(void) +{ + struct dt_node *np; + int64_t rc; + uint32_t tick_us; + + np = dt_find_compatible_node(dt_root, NULL, "ibm,power8-sbe-timer"); + if (!np) + return; + + sbe_timer_chip = dt_get_chip_id(np); + tick_us = dt_prop_get_u32(np, "tick-time-us"); + sbe_timer_inc = usecs_to_tb(tick_us); + sbe_timer_target = ~0ull; + + rc = xscom_read(sbe_timer_chip, 0xE0006, &sbe_last_gen); + if (rc) { + prerror("SLW: Error %lld reading tmr gen count\n", rc); + return; + } + sbe_last_gen_stamp = mftb(); + + prlog(PR_INFO, "SLW: Timer facility on chip %d, resolution %dus\n", + sbe_timer_chip, tick_us); + sbe_has_timer = true; +} @@ -30,6 +30,7 @@ #include <libfdt/libfdt.h> #include <opal-api.h> #include <nvram.h> +#include <sbe-p8.h> #include <p9_stop_api.H> #include <p8_pore_table_gen_api.H> @@ -44,14 +45,6 @@ static bool slw_current_le = false; enum wakeup_engine_states wakeup_engine_state = WAKEUP_ENGINE_NOT_PRESENT; bool has_deep_states = false; -/* SLW timer related stuff */ -static bool slw_has_timer; -static uint64_t slw_timer_inc; -static uint64_t slw_timer_target; -static uint32_t slw_timer_chip; -static uint64_t slw_last_gen; -static uint64_t slw_last_gen_stamp; - DEFINE_LOG_ENTRY(OPAL_RC_SLW_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_SLW, OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL, OPAL_NA); @@ -1582,180 +1575,6 @@ int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val) opal_call(OPAL_SLW_SET_REG, opal_slw_set_reg, 3); -static void slw_dump_timer_ffdc(void) -{ - uint64_t i, val; - int64_t rc; - - static const uint32_t dump_regs[] = { - 0xe0000, 0xe0001, 0xe0002, 0xe0003, - 0xe0004, 0xe0005, 0xe0006, 0xe0007, - 0xe0008, 0xe0009, 0xe000a, 0xe000b, - 0xe000c, 0xe000d, 0xe000e, 0xe000f, - 0xe0010, 0xe0011, 0xe0012, 0xe0013, - 0xe0014, 0xe0015, 0xe0016, 0xe0017, - 0xe0018, 0xe0019, - 0x5001c, - 0x50038, 0x50039, 0x5003a, 0x5003b - }; - - /** - * @fwts-label SLWRegisterDump - * @fwts-advice An error condition occurred in sleep/winkle - * engines timer state machine. Dumping debug information to - * root-cause. OPAL/skiboot may be stuck on some operation that - * requires SLW timer state machine (e.g. core powersaving) - */ - prlog(PR_DEBUG, "SLW: Register state:\n"); - - for (i = 0; i < ARRAY_SIZE(dump_regs); i++) { - uint32_t reg = dump_regs[i]; - rc = xscom_read(slw_timer_chip, reg, &val); - if (rc) { - prlog(PR_DEBUG, "SLW: XSCOM error %lld reading" - " reg 0x%x\n", rc, reg); - break; - } - prlog(PR_DEBUG, "SLW: %5x = %016llx\n", reg, val); - } -} - -/* This is called with the timer lock held, so there is no - * issue with re-entrancy or concurrence - */ -void slw_update_timer_expiry(uint64_t new_target) -{ - uint64_t count, gen, gen2, req, now = mftb(); - int64_t rc; - - if (!slw_has_timer || new_target == slw_timer_target) - return; - - slw_timer_target = new_target; - - /* Calculate how many increments from now, rounded up */ - if (now < new_target) - count = (new_target - now + slw_timer_inc - 1) / slw_timer_inc; - else - count = 1; - - /* Max counter is 24-bit */ - if (count > 0xffffff) - count = 0xffffff; - /* Fabricate update request */ - req = (1ull << 63) | (count << 32); - - prlog(PR_TRACE, "SLW: TMR expiry: 0x%llx, req: %016llx\n", count, req); - - do { - /* Grab generation and spin if odd */ - _xscom_lock(); - for (;;) { - rc = _xscom_read(slw_timer_chip, 0xE0006, &gen, false); - if (rc) { - prerror("SLW: Error %lld reading tmr gen " - " count\n", rc); - _xscom_unlock(); - return; - } - if (!(gen & 1)) - break; - if (tb_compare(now + msecs_to_tb(1), mftb()) == TB_ABEFOREB) { - /** - * @fwts-label SLWTimerStuck - * @fwts-advice The SLeep/Winkle Engine (SLW) - * failed to increment the generation number - * within our timeout period (it *should* have - * done so within ~10us, not >1ms. OPAL uses - * the SLW timer to schedule some operations, - * but can fall back to the (much less frequent - * OPAL poller, which although does not affect - * functionality, runs *much* less frequently. - * This could have the effect of slow I2C - * operations (for example). It may also mean - * that you *had* an increase in jitter, due - * to slow interactions with SLW. - * This error may also occur if the machine - * is connected to via soft FSI. - */ - prerror("SLW: timer stuck, falling back to OPAL pollers. You will likely have slower I2C and may have experienced increased jitter.\n"); - prlog(PR_DEBUG, "SLW: Stuck with odd generation !\n"); - _xscom_unlock(); - slw_has_timer = false; - slw_dump_timer_ffdc(); - return; - } - } - - rc = _xscom_write(slw_timer_chip, 0x5003A, req, false); - if (rc) { - prerror("SLW: Error %lld writing tmr request\n", rc); - _xscom_unlock(); - return; - } - - /* Re-check gen count */ - rc = _xscom_read(slw_timer_chip, 0xE0006, &gen2, false); - if (rc) { - prerror("SLW: Error %lld re-reading tmr gen " - " count\n", rc); - _xscom_unlock(); - return; - } - _xscom_unlock(); - } while(gen != gen2); - - /* Check if the timer is working. If at least 1ms has elapsed - * since the last call to this function, check that the gen - * count has changed - */ - if (tb_compare(slw_last_gen_stamp + msecs_to_tb(1), now) - == TB_ABEFOREB) { - if (slw_last_gen == gen) { - prlog(PR_ERR, - "SLW: Timer appears to not be running !\n"); - slw_has_timer = false; - slw_dump_timer_ffdc(); - } - slw_last_gen = gen; - slw_last_gen_stamp = mftb(); - } - - prlog(PR_TRACE, "SLW: gen: %llx\n", gen); -} - -bool slw_timer_ok(void) -{ - return slw_has_timer; -} - -static void slw_init_timer(void) -{ - struct dt_node *np; - int64_t rc; - uint32_t tick_us; - - np = dt_find_compatible_node(dt_root, NULL, "ibm,power8-sbe-timer"); - if (!np) - return; - - slw_timer_chip = dt_get_chip_id(np); - tick_us = dt_prop_get_u32(np, "tick-time-us"); - slw_timer_inc = usecs_to_tb(tick_us); - slw_timer_target = ~0ull; - - rc = xscom_read(slw_timer_chip, 0xE0006, &slw_last_gen); - if (rc) { - prerror("SLW: Error %lld reading tmr gen count\n", rc); - return; - } - slw_last_gen_stamp = mftb(); - - prlog(PR_INFO, "SLW: Timer facility on chip %d, resolution %dus\n", - slw_timer_chip, tick_us); - slw_has_timer = true; -} - void slw_init(void) { struct proc_chip *chip; @@ -1772,7 +1591,7 @@ void slw_init(void) if (wakeup_engine_state == WAKEUP_ENGINE_PRESENT) slw_late_init_p8(chip); } - slw_init_timer(); + p8_sbe_init_timer(); } else if (proc_gen == proc_gen_p9) { for_each_chip(chip) { slw_init_chip_p9(chip); |