Skip to content

Commit

Permalink
Move P8 timer code to separate file
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Vasant Hegde authored and stewartsmith committed May 1, 2018
1 parent 6739c89 commit 6421fc5
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 197 deletions.
5 changes: 3 additions & 2 deletions core/interrupts.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <device.h>
#include <ccan/str/str.h>
#include <timer.h>
#include <sbe-p8.h>

/* ICP registers */
#define ICP_XIRR 0x4 /* 32-bit access */
Expand Down Expand Up @@ -487,8 +488,8 @@ static int64_t opal_handle_interrupt(uint32_t isn, __be64 *outstanding_event_mas
/* Run it */
is->ops->interrupt(is, isn);

/* Check timers if SLW timer isn't working */
if (!slw_timer_ok())
/* Check timers if SBE timer isn't working */
if (!p8_sbe_timer_ok())
check_timers(true);

/* Update output events */
Expand Down
2 changes: 1 addition & 1 deletion core/test/run-timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static void expiry(struct timer *t, void *data, uint64_t now)
count--;
}

void slw_update_timer_expiry(uint64_t new_target)
void p8_sbe_update_timer_expiry(uint64_t new_target)
{
(void)new_target;
/* FIXME: do intersting SLW timer sim */
Expand Down
9 changes: 5 additions & 4 deletions core/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <fsp.h>
#include <device.h>
#include <opal.h>
#include <sbe-p8.h>

#ifdef __TEST__
#define this_cpu() ((void *)-1)
Expand Down Expand Up @@ -109,7 +110,7 @@ static void __schedule_timer_at(struct timer *t, uint64_t when)
/* Pick up the next timer and upddate the SBE HW timer */
lt = list_top(&timer_list, struct timer, link);
if (lt)
slw_update_timer_expiry(lt->target);
p8_sbe_update_timer_expiry(lt->target);
}

void schedule_timer_at(struct timer *t, uint64_t when)
Expand Down Expand Up @@ -166,7 +167,7 @@ static void __check_poll_timers(uint64_t now)
* arbitrarily 1us.
*/
if (t->running) {
slw_update_timer_expiry(now + usecs_to_tb(1));
p8_sbe_update_timer_expiry(now + usecs_to_tb(1));
break;
}

Expand Down Expand Up @@ -257,15 +258,15 @@ void late_init_timers(void)
*
* If a platform quirk exists, use that, else use the default.
*
* If we have an SLW timer facility, we run this 10 times slower,
* If we have an SBE timer facility, we run this 10 times slower,
* we could possibly completely get rid of it.
*
* We use a value in milliseconds, we don't want this to ever be
* faster than that.
*/
if (platform.heartbeat_time) {
heartbeat = platform.heartbeat_time();
} else if (slw_timer_ok() || fsp_present()) {
} else if (p8_sbe_timer_ok() || fsp_present()) {
heartbeat = HEARTBEAT_DEFAULT_MS * 10;
}

Expand Down
2 changes: 1 addition & 1 deletion hw/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
203 changes: 203 additions & 0 deletions hw/sbe-p8.c
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 6421fc5

Please sign in to comment.