Node counter is a timer presents on Loongson-3 chips, which runs as fast as CPU clock. It's being mapped into a MMIO location.
Emulate this for loongson3_virt machine, in hope that kernel can use it as a better clock source. Hardware's behavior on 32-bit read/write is also emulated in case legacy kernel is trying to use it with hi/lo splitted read. Signed-off-by: Jiaxun Yang <jiaxun.y...@flygoat.com> --- hw/mips/loongson3_bootp.h | 1 + hw/mips/loongson3_virt.c | 38 ++++++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/hw/mips/loongson3_bootp.h b/hw/mips/loongson3_bootp.h index 1b0dd3b59171..c6a435397d2c 100644 --- a/hw/mips/loongson3_bootp.h +++ b/hw/mips/loongson3_bootp.h @@ -210,6 +210,7 @@ enum { VIRT_PCIE_ECAM, VIRT_BIOS_ROM, VIRT_UART, + VIRT_NODECNT, VIRT_LIOINTC, VIRT_PCIE_MMIO, VIRT_HIGHMEM diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index b10a611a98f4..b78ac8032096 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -74,6 +74,7 @@ const MemMapEntry virt_memmap[] = { [VIRT_PCIE_ECAM] = { 0x1a000000, 0x2000000 }, [VIRT_BIOS_ROM] = { 0x1fc00000, 0x200000 }, [VIRT_UART] = { 0x1fe001e0, 0x8 }, + [VIRT_NODECNT] = { 0x3ff00408, 0x8 }, [VIRT_LIOINTC] = { 0x3ff01400, 0x64 }, [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, [VIRT_HIGHMEM] = { 0x80000000, 0x0 }, /* Variable */ @@ -92,6 +93,7 @@ static const MemMapEntry loader_rommap[] = { struct LoongsonMachineState { MachineState parent_obj; + Clock *cpuclk; MemoryRegion *pio_alias; MemoryRegion *mmio_alias; MemoryRegion *ecam_alias; @@ -145,6 +147,29 @@ static const MemoryRegionOps loongson3_pm_ops = { } }; +static uint64_t loongson3_nodecnt_read(void *opaque, + hwaddr addr, unsigned size) +{ + LoongsonMachineState *s = opaque; + int64_t now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint64_t ticks = clock_ns_to_ticks(s->cpuclk, now_ns); + + if (addr == 0x4) { + return ticks >> 32; + } + + return ticks; +} + +static const MemoryRegionOps loongson3_nodecnt_ops = { + .read = loongson3_nodecnt_read, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 8, + .impl.min_access_size = 4, + .impl.max_access_size = 8, +}; + #define DEF_LOONGSON3_FREQ (800 * 1000 * 1000) static uint64_t get_cpu_freq_hz(void) @@ -463,7 +488,6 @@ static void mips_loongson3_virt_init(MachineState *machine) int i; long bios_size; MIPSCPU *cpu; - Clock *cpuclk; CPUMIPSState *env; DeviceState *liointc; char *filename; @@ -471,10 +495,12 @@ static void mips_loongson3_virt_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; ram_addr_t ram_size = machine->ram_size; + LoongsonMachineState *ms = LOONGSON_MACHINE(machine); MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios = g_new(MemoryRegion, 1); MemoryRegion *iomem = g_new(MemoryRegion, 1); + MemoryRegion *nodecnt = g_new(MemoryRegion, 1); /* TODO: TCG will support all CPU types */ if (!kvm_enabled()) { @@ -520,14 +546,14 @@ static void mips_loongson3_virt_init(MachineState *machine) sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base, qdev_get_gpio_in(liointc, RTC_IRQ)); - cpuclk = clock_new(OBJECT(machine), "cpu-refclk"); - clock_set_hz(cpuclk, DEF_LOONGSON3_FREQ); + ms->cpuclk = clock_new(OBJECT(machine), "cpu-refclk"); + clock_set_hz(ms->cpuclk, DEF_LOONGSON3_FREQ); for (i = 0; i < machine->smp.cpus; i++) { int ip; /* init CPUs */ - cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk); + cpu = mips_cpu_create_with_clock(machine->cpu_type, ms->cpuclk); /* Init internal devices */ cpu_mips_irq_init_cpu(cpu); @@ -553,6 +579,8 @@ static void mips_loongson3_virt_init(MachineState *machine) machine->ram, 0, virt_memmap[VIRT_LOWMEM].size); memory_region_init_io(iomem, NULL, &loongson3_pm_ops, NULL, "loongson3_pm", virt_memmap[VIRT_PM].size); + memory_region_init_io(nodecnt, NULL, &loongson3_nodecnt_ops, ms, + "loongson3_nodecnt", virt_memmap[VIRT_NODECNT].size); memory_region_add_subregion(address_space_mem, virt_memmap[VIRT_LOWMEM].base, ram); @@ -562,6 +590,8 @@ static void mips_loongson3_virt_init(MachineState *machine) virt_memmap[VIRT_HIGHMEM].base, machine->ram); memory_region_add_subregion(address_space_mem, virt_memmap[VIRT_PM].base, iomem); + memory_region_add_subregion(address_space_mem, + virt_memmap[VIRT_NODECNT].base, nodecnt); /* * We do not support flash operation, just loading bios.bin as raw BIOS. --- base-commit: 248f6f62df073a3b4158fd0093863ab885feabb5 change-id: 20240511-loongson3_hpt-cb02790b24db Best regards, -- Jiaxun Yang <jiaxun.y...@flygoat.com>