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.
---
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.54.0