Expose reset clock, soft reset and processor power registers through the shared CSR window. Keep mutable register state and reset handling in the reset controller.
Signed-off-by: Kirill A. Korinsky <[email protected]> --- hw/mips/octeon.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 0caf088adf..007fc4b537 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -24,6 +24,8 @@ #include "system/cpus.h" #include "system/memory.h" #include "system/reset.h" +#include "system/runstate.h" +#include "system/system.h" #include "exec/cpu-interrupt.h" #include "qemu/error-report.h" #include "qemu/atomic.h" @@ -124,6 +126,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_CSR_BANK) #define OCTEON_CIU3_UART0_INTSN 0x8000 #define OCTEON_CSR_BASE 0x1180000000000ULL #define OCTEON_CSR_SIZE 0x100000000ULL +#define OCTEON_RST_BOOT 0x6001600 +#define OCTEON_RST_SOFT_RST 0x6001680 +/* U-Boot uses the reset controller to park and release secondary cores. */ +#define OCTEON_RST_PP_POWER 0x6001700 +#define OCTEON_RST_BOOT_C_MUL_SHIFT 30 +#define OCTEON_RST_BOOT_PNR_MUL_SHIFT 24 /* * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; * the guest sees the virtual CVMSEG window, not this physical address. @@ -168,6 +176,7 @@ struct OcteonPeripheralClass { struct OcteonRstState { OcteonPeripheralState parent_obj; + GHashTable *regs; uint64_t rst_pp_power; }; @@ -294,11 +303,18 @@ void octeon_reg_store(GHashTable *regs, uint64_t reg, uint64_t value) bool octeon_csr_lookup(OcteonState *s, uint64_t reg, uint64_t *value) { + if (reg == OCTEON_RST_SOFT_RST) { + return octeon_reg_lookup(s->rst->regs, reg, value); + } return octeon_reg_lookup(s->csr_bank->values, reg, value); } static void octeon_csr_store(OcteonState *s, uint64_t reg, uint64_t value) { + if (reg == OCTEON_RST_SOFT_RST) { + octeon_reg_store(s->rst->regs, reg, value); + return; + } octeon_reg_store(s->csr_bank->values, reg, value); } @@ -869,6 +885,33 @@ static void octeon_ciu3_nmi(OcteonState *s, uint64_t mask) } } +static void octeon_rst_pp_power_write(OcteonState *s, hwaddr addr, + uint64_t value, unsigned size) +{ + uint64_t old = s->rst->rst_pp_power; + uint64_t changed; + unsigned int cpu; + + value = octeon_write64(old, addr, value, size) & + octeon_present_cpu_mask(s); + s->rst->rst_pp_power = value; + changed = old ^ value; + + for (cpu = 1; cpu < s->cpu_count; cpu++) { + uint64_t mask = 1ULL << cpu; + + if (!(changed & mask)) { + continue; + } + if (value & mask) { + async_run_on_cpu(CPU(s->cpu[cpu].cpu), octeon_cpu_park_work, + RUN_ON_CPU_NULL); + } else { + octeon_start_cpu(s, cpu); + } + } +} + static const MemoryRegionOps octeon_ciu_ops = { .read = octeon_ciu_read, .write = octeon_ciu_write, @@ -1082,6 +1125,19 @@ static uint64_t octeon_csr_read(void *opaque, hwaddr addr, unsigned size) hwaddr reg = addr & ~7ULL; uint64_t value; + switch (reg) { + case OCTEON_RST_BOOT: + value = ((uint64_t)(s->cpu_hz / s->ref_hz) << + OCTEON_RST_BOOT_C_MUL_SHIFT) | + ((uint64_t)(s->io_hz / s->ref_hz) << + OCTEON_RST_BOOT_PNR_MUL_SHIFT); + return octeon_read64(value, addr, size); + case OCTEON_RST_PP_POWER: + return octeon_read64(s->rst->rst_pp_power, addr, size); + default: + break; + } + if (!octeon_csr_lookup(s, reg, &value)) { value = 0; } @@ -1095,6 +1151,16 @@ static void octeon_csr_write(void *opaque, hwaddr addr, hwaddr reg = addr & ~7ULL; uint64_t old; + if (reg == OCTEON_RST_SOFT_RST && value) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; + } + + if (reg == OCTEON_RST_PP_POWER) { + octeon_rst_pp_power_write(s, addr, value, size); + return; + } + if (!octeon_csr_lookup(s, reg, &old)) { old = 0; } @@ -1354,6 +1420,7 @@ static void octeon_rst_reset_hold(Object *obj, ResetType type) opc->parent_phases.hold(obj, type); } + g_hash_table_remove_all(rst->regs); rst->rst_pp_power = octeon_secondary_cpu_mask(rst->parent_obj.board); } @@ -1411,6 +1478,16 @@ static GHashTable *octeon_reg_table_new(void) g_free, g_free); } +static void octeon_rst_init(Object *obj) +{ + OCTEON_RST(obj)->regs = octeon_reg_table_new(); +} + +static void octeon_rst_finalize(Object *obj) +{ + g_hash_table_destroy(OCTEON_RST(obj)->regs); +} + static void octeon_csr_bank_init(Object *obj) { OCTEON_CSR_BANK(obj)->values = octeon_reg_table_new(); @@ -1594,6 +1671,8 @@ static const TypeInfo octeon_machine_types[] = { .name = TYPE_OCTEON_RST, .parent = TYPE_OCTEON_PERIPHERAL, .instance_size = sizeof(OcteonRstState), + .instance_init = octeon_rst_init, + .instance_finalize = octeon_rst_finalize, .class_init = octeon_rst_class_init, }, { -- 2.56.0
