hw/riscv: clint: Avoid using hard-coded timebase frequency

At present the CLINT timestamp is using a hard-coded timebase
frequency value SIFIVE_CLINT_TIMEBASE_FREQ. This might not be
true for all boards.

Add a new 'timebase-freq' property to the CLINT device, and
update various functions to accept this as a parameter.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-Id: <1598924352-89526-16-git-send-email-bmeng.cn@gmail.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Bin Meng 2020-09-01 09:39:10 +08:00 committed by Alistair Francis
parent ce908a2f6f
commit a47ef6e93a
10 changed files with 40 additions and 22 deletions

View file

@ -60,6 +60,9 @@
#define BIOS_FILENAME "hss.bin" #define BIOS_FILENAME "hss.bin"
#define RESET_VECTOR 0x20220000 #define RESET_VECTOR 0x20220000
/* CLINT timebase frequency */
#define CLINT_TIMEBASE_FREQ 1000000
/* GEM version */ /* GEM version */
#define GEM_REVISION 0x0107010c #define GEM_REVISION 0x0107010c
@ -187,7 +190,8 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
/* CLINT */ /* CLINT */
sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base, sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus, memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
CLINT_TIMEBASE_FREQ, false);
/* L2 cache controller */ /* L2 cache controller */
create_unimplemented_device("microchip.pfsoc.l2cc", create_unimplemented_device("microchip.pfsoc.l2cc",

View file

@ -29,22 +29,23 @@
#include "hw/riscv/sifive_clint.h" #include "hw/riscv/sifive_clint.h"
#include "qemu/timer.h" #include "qemu/timer.h"
static uint64_t cpu_riscv_read_rtc(void) static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
{ {
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
SIFIVE_CLINT_TIMEBASE_FREQ, NANOSECONDS_PER_SECOND); timebase_freq, NANOSECONDS_PER_SECOND);
} }
/* /*
* Called when timecmp is written to update the QEMU timer or immediately * Called when timecmp is written to update the QEMU timer or immediately
* trigger timer interrupt if mtimecmp <= current timer value. * trigger timer interrupt if mtimecmp <= current timer value.
*/ */
static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value) static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
uint32_t timebase_freq)
{ {
uint64_t next; uint64_t next;
uint64_t diff; uint64_t diff;
uint64_t rtc_r = cpu_riscv_read_rtc(); uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
cpu->env.timecmp = value; cpu->env.timecmp = value;
if (cpu->env.timecmp <= rtc_r) { if (cpu->env.timecmp <= rtc_r) {
@ -59,7 +60,7 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
diff = cpu->env.timecmp - rtc_r; diff = cpu->env.timecmp - rtc_r;
/* back to ns (note args switched in muldiv64) */ /* back to ns (note args switched in muldiv64) */
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
muldiv64(diff, NANOSECONDS_PER_SECOND, SIFIVE_CLINT_TIMEBASE_FREQ); muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
timer_mod(cpu->env.timer, next); timer_mod(cpu->env.timer, next);
} }
@ -112,10 +113,10 @@ static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
} }
} else if (addr == clint->time_base) { } else if (addr == clint->time_base) {
/* time_lo */ /* time_lo */
return cpu_riscv_read_rtc() & 0xFFFFFFFF; return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
} else if (addr == clint->time_base + 4) { } else if (addr == clint->time_base + 4) {
/* time_hi */ /* time_hi */
return (cpu_riscv_read_rtc() >> 32) & 0xFFFFFFFF; return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
} }
error_report("clint: invalid read: %08x", (uint32_t)addr); error_report("clint: invalid read: %08x", (uint32_t)addr);
@ -153,13 +154,13 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
/* timecmp_lo */ /* timecmp_lo */
uint64_t timecmp_hi = env->timecmp >> 32; uint64_t timecmp_hi = env->timecmp >> 32;
sifive_clint_write_timecmp(RISCV_CPU(cpu), sifive_clint_write_timecmp(RISCV_CPU(cpu),
timecmp_hi << 32 | (value & 0xFFFFFFFF)); timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
return; return;
} else if ((addr & 0x7) == 4) { } else if ((addr & 0x7) == 4) {
/* timecmp_hi */ /* timecmp_hi */
uint64_t timecmp_lo = env->timecmp; uint64_t timecmp_lo = env->timecmp;
sifive_clint_write_timecmp(RISCV_CPU(cpu), sifive_clint_write_timecmp(RISCV_CPU(cpu),
value << 32 | (timecmp_lo & 0xFFFFFFFF)); value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
} else { } else {
error_report("clint: invalid timecmp write: %08x", (uint32_t)addr); error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
} }
@ -194,6 +195,7 @@ static Property sifive_clint_properties[] = {
DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0), DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0), DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0), DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -232,7 +234,8 @@ type_init(sifive_clint_register_types)
*/ */
DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base, uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
uint32_t timecmp_base, uint32_t time_base, bool provide_rdtime) uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
bool provide_rdtime)
{ {
int i; int i;
for (i = 0; i < num_harts; i++) { for (i = 0; i < num_harts; i++) {
@ -242,7 +245,7 @@ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
continue; continue;
} }
if (provide_rdtime) { if (provide_rdtime) {
riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc); riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
} }
env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
&sifive_clint_timer_cb, cpu); &sifive_clint_timer_cb, cpu);
@ -256,6 +259,7 @@ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base); qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
qdev_prop_set_uint32(dev, "time-base", time_base); qdev_prop_set_uint32(dev, "time-base", time_base);
qdev_prop_set_uint32(dev, "aperture-size", size); qdev_prop_set_uint32(dev, "aperture-size", size);
qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
return dev; return dev;

View file

@ -213,7 +213,8 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
memmap[SIFIVE_E_PLIC].size); memmap[SIFIVE_E_PLIC].size);
sifive_clint_create(memmap[SIFIVE_E_CLINT].base, sifive_clint_create(memmap[SIFIVE_E_CLINT].base,
memmap[SIFIVE_E_CLINT].size, 0, ms->smp.cpus, memmap[SIFIVE_E_CLINT].size, 0, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
SIFIVE_CLINT_TIMEBASE_FREQ, false);
create_unimplemented_device("riscv.sifive.e.aon", create_unimplemented_device("riscv.sifive.e.aon",
memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size); memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size);
sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base); sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base);

View file

@ -706,7 +706,8 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ)); serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
sifive_clint_create(memmap[SIFIVE_U_CLINT].base, sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
memmap[SIFIVE_U_CLINT].size, 0, ms->smp.cpus, memmap[SIFIVE_U_CLINT].size, 0, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
SIFIVE_CLINT_TIMEBASE_FREQ, false);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
return; return;

View file

@ -242,7 +242,8 @@ static void spike_board_init(MachineState *machine)
sifive_clint_create( sifive_clint_create(
memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size, memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
memmap[SPIKE_CLINT].size, base_hartid, hart_count, memmap[SPIKE_CLINT].size, base_hartid, hart_count,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
SIFIVE_CLINT_TIMEBASE_FREQ, false);
} }
/* register system main memory (actual RAM) */ /* register system main memory (actual RAM) */

View file

@ -541,7 +541,8 @@ static void virt_machine_init(MachineState *machine)
sifive_clint_create( sifive_clint_create(
memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size, memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
memmap[VIRT_CLINT].size, base_hartid, hart_count, memmap[VIRT_CLINT].size, base_hartid, hart_count,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, true); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
SIFIVE_CLINT_TIMEBASE_FREQ, true);
/* Per-socket PLIC hart topology configuration string */ /* Per-socket PLIC hart topology configuration string */
plic_hart_config_len = plic_hart_config_len =

View file

@ -39,11 +39,13 @@ typedef struct SiFiveCLINTState {
uint32_t timecmp_base; uint32_t timecmp_base;
uint32_t time_base; uint32_t time_base;
uint32_t aperture_size; uint32_t aperture_size;
uint32_t timebase_freq;
} SiFiveCLINTState; } SiFiveCLINTState;
DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base, uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
uint32_t timecmp_base, uint32_t time_base, bool provide_rdtime); uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
bool provide_rdtime);
enum { enum {
SIFIVE_SIP_BASE = 0x0, SIFIVE_SIP_BASE = 0x0,

View file

@ -219,7 +219,8 @@ struct CPURISCVState {
pmp_table_t pmp_state; pmp_table_t pmp_state;
/* machine specific rdtime callback */ /* machine specific rdtime callback */
uint64_t (*rdtime_fn)(void); uint64_t (*rdtime_fn)(uint32_t);
uint32_t rdtime_fn_arg;
/* True if in debugger mode. */ /* True if in debugger mode. */
bool debugger; bool debugger;
@ -350,7 +351,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
#define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void)); void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
uint32_t arg);
#endif #endif
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv); void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);

View file

@ -276,9 +276,11 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
return old; return old;
} }
void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void)) void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
uint32_t arg)
{ {
env->rdtime_fn = fn; env->rdtime_fn = fn;
env->rdtime_fn_arg = arg;
} }
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)

View file

@ -351,7 +351,7 @@ static int read_time(CPURISCVState *env, int csrno, target_ulong *val)
return -RISCV_EXCP_ILLEGAL_INST; return -RISCV_EXCP_ILLEGAL_INST;
} }
*val = env->rdtime_fn() + delta; *val = env->rdtime_fn(env->rdtime_fn_arg) + delta;
return 0; return 0;
} }
@ -364,7 +364,7 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
return -RISCV_EXCP_ILLEGAL_INST; return -RISCV_EXCP_ILLEGAL_INST;
} }
*val = (env->rdtime_fn() + delta) >> 32; *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32;
return 0; return 0;
} }
#endif #endif