Each DSP ordinarily has fewer HVX contexts than hw threads. The thread's SSR:XA selects the one it's bound to.
Add a hexagon-hvx-context device holding the register file. The machine creates as many as the config table specifies, linked to every vCPU. The CPU picks among the links at run time. The linux-user side keeps one context per CPU, w/o need for a device. SSR:XA is not consulted yet, the CPU always uses context 0. Signed-off-by: Brian Cain <[email protected]> --- include/hw/hexagon/hexagon.h | 1 + include/hw/hexagon/hexagon_hvx_context.h | 27 ++++++++ target/hexagon/cpu.h | 9 ++- hw/hexagon/hex-subsys.c | 36 ++++++++++ hw/hexagon/hexagon_hvx_context.c | 83 ++++++++++++++++++++++++ linux-user/hexagon/cpu_loop.c | 2 +- linux-user/main.c | 3 + target/hexagon/cpu.c | 19 +++++- hw/hexagon/meson.build | 1 + 9 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 include/hw/hexagon/hexagon_hvx_context.h create mode 100644 hw/hexagon/hexagon_hvx_context.c diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index 3d7b3cb12dc..0ee6fd8d033 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -162,6 +162,7 @@ struct HexagonCommonMachineState { DeviceState *qtimer; DeviceState *glob_regs; DeviceState *tlb; + unsigned num_hvx_ctx; }; #endif diff --git a/include/hw/hexagon/hexagon_hvx_context.h b/include/hw/hexagon/hexagon_hvx_context.h new file mode 100644 index 00000000000..ab85816a7ff --- /dev/null +++ b/include/hw/hexagon/hexagon_hvx_context.h @@ -0,0 +1,27 @@ +/* + * Hexagon HVX Extension Context QOM Object + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HEXAGON_HVX_CONTEXT_H +#define HEXAGON_HVX_CONTEXT_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" +#include "target/hexagon/cpu.h" + +#define TYPE_HEXAGON_HVX_CONTEXT "hexagon-hvx-context" +OBJECT_DECLARE_SIMPLE_TYPE(HexagonHVXContextState, HEXAGON_HVX_CONTEXT) + +struct HexagonHVXContextState { + SysBusDevice parent_obj; + + /* Physical context number, as SSR:XA maps to it. */ + uint32_t index; + + HexagonHVXContext regs; +}; + +#endif /* HEXAGON_HVX_CONTEXT_H */ diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index c983a9791e1..867390e84d2 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -29,6 +29,7 @@ typedef struct HexagonTLBState HexagonTLBState; typedef struct HexagonGlobalRegState HexagonGlobalRegState; +typedef struct HexagonHVXContextState HexagonHVXContextState; #include "cpu-qom.h" #include "exec/cpu-common.h" @@ -49,6 +50,7 @@ typedef struct HexagonGlobalRegState HexagonGlobalRegState; #define REG_WRITES_MAX 32 #define PRED_WRITES_MAX 5 /* 4 insns + endloop */ #define VSTORES_MAX 2 +#define HVX_CONTEXTS_MAX 8 #define MAX_TLB_ENTRIES 1024 #define THREADS_MAX 8 @@ -165,7 +167,6 @@ typedef struct CPUArchState { uint64_t llsc_val_i64; HexagonHVXContext *hvx; - HexagonHVXContext hvx_ctx QEMU_ALIGNED(16); MMVector future_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16); MMVector tmp_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16); @@ -201,7 +202,11 @@ struct ArchCPU { CPUHexagonState env; HexagonCPUConfig cfg; -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY + HexagonHVXContext hvx_ctx QEMU_ALIGNED(16); +#else + HexagonHVXContextState *hvx_ctx[HVX_CONTEXTS_MAX]; + HexagonHVXContext hvx_fallback QEMU_ALIGNED(16); HexagonTLBState *tlb; uint32_t boot_addr; HexagonGlobalRegState *globalregs; diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c index 4e3a418340e..0efcb40d8a3 100644 --- a/hw/hexagon/hex-subsys.c +++ b/hw/hexagon/hex-subsys.c @@ -7,8 +7,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "hw/hexagon/hex-subsys.h" #include "hw/hexagon/hexagon_globalreg.h" +#include "hw/hexagon/hexagon_hvx_context.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/intc/hex-l2vic.h" #include "hw/timer/qct-qtimer.h" @@ -98,6 +100,33 @@ static DeviceState *tlb_create(HexagonCommonMachineState *hms, return tlb; } +/* + * Create the core's HVX extension contexts. There are fewer of them than + * there are hardware threads, and SSR:XA picks which one a thread uses, so + * they belong to the subsystem rather than to any one CPU. + */ +static void hvx_contexts_create(HexagonCommonMachineState *hms, + const struct hexagon_machine_config *m_cfg) +{ + unsigned n = m_cfg->cfgtable.ext_contexts; + unsigned i; + + if (n > HVX_CONTEXTS_MAX) { + error_report("machine declares %u HVX contexts, only %u are usable", + n, HVX_CONTEXTS_MAX); + exit(1); + } + for (i = 0; i < n; i++) { + DeviceState *ctx = qdev_new(TYPE_HEXAGON_HVX_CONTEXT); + g_autofree char *name = g_strdup_printf("hvx-context[%u]", i); + + object_property_add_child(OBJECT(hms), name, OBJECT(ctx)); + qdev_prop_set_uint32(ctx, "index", i); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ctx), &error_fatal); + } + hms->num_hvx_ctx = n; +} + static DeviceState *cluster_create(HexagonCommonMachineState *hms) { DeviceState *cluster = qdev_new(TYPE_CPU_CLUSTER); @@ -140,6 +169,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms, hms->qtimer = qtimer_create(hms, m_cfg); hms->glob_regs = globalreg_create(hms, m_cfg, rev); hms->tlb = tlb_create(hms, m_cfg); + hvx_contexts_create(hms, m_cfg); } void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) @@ -151,6 +181,12 @@ void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) &error_fatal); object_property_set_link(OBJECT(cpu), "l2vic", OBJECT(hms->l2vic), &error_fatal); + for (unsigned i = 0; i < hms->num_hvx_ctx; i++) { + g_autofree char *name = g_strdup_printf("hvx-context[%u]", i); + Object *ctx = object_resolve_path_component(OBJECT(hms), name); + + object_property_set_link(OBJECT(cpu), name, ctx, &error_fatal); + } } void hex_subsys_realize_cluster(HexagonCommonMachineState *hms) diff --git a/hw/hexagon/hexagon_hvx_context.c b/hw/hexagon/hexagon_hvx_context.c new file mode 100644 index 00000000000..d17aee0f1d0 --- /dev/null +++ b/hw/hexagon/hexagon_hvx_context.c @@ -0,0 +1,83 @@ +/* + * Hexagon HVX Extension Context QOM Object + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/hexagon/hexagon_hvx_context.h" +#include "hw/core/qdev-properties.h" +#include "migration/vmstate.h" + +static void hexagon_hvx_context_reset_hold(Object *obj, ResetType type) +{ + HexagonHVXContextState *s = HEXAGON_HVX_CONTEXT(obj); + + memset(&s->regs, 0, sizeof(s->regs)); +} + +/* gvec needs VRegs/QRegs 16-aligned within the struct. */ +QEMU_BUILD_BUG_ON(offsetof(HexagonHVXContextState, regs) % 16 != 0); + +static const VMStateDescription vmstate_mmvector = { + .name = "hexagon_mmvector", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]){ + VMSTATE_UINT64_ARRAY(ud, MMVector, MAX_VEC_SIZE_BYTES / 8), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_mmqreg = { + .name = "hexagon_mmqreg", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]){ + VMSTATE_UINT64_ARRAY(ud, MMQReg, MAX_VEC_SIZE_BYTES / 8 / 8), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_hexagon_hvx_context = { + .name = "hexagon_hvx_context", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]){ + VMSTATE_STRUCT_ARRAY(regs.VRegs, HexagonHVXContextState, NUM_VREGS, + 1, vmstate_mmvector, MMVector), + VMSTATE_STRUCT_ARRAY(regs.QRegs, HexagonHVXContextState, NUM_QREGS, + 1, vmstate_mmqreg, MMQReg), + VMSTATE_END_OF_LIST() + } +}; + +static const Property hexagon_hvx_context_properties[] = { + DEFINE_PROP_UINT32("index", HexagonHVXContextState, index, 0), +}; + +static void hexagon_hvx_context_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.hold = hexagon_hvx_context_reset_hold; + dc->vmsd = &vmstate_hexagon_hvx_context; + dc->user_creatable = false; + device_class_set_props(dc, hexagon_hvx_context_properties); +} + +static const TypeInfo hexagon_hvx_context_info = { + .name = TYPE_HEXAGON_HVX_CONTEXT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(HexagonHVXContextState), + .class_init = hexagon_hvx_context_class_init, +}; + +static void hexagon_hvx_context_register_types(void) +{ + type_register_static(&hexagon_hvx_context_info); +} + +type_init(hexagon_hvx_context_register_types) diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c index ccfb1da86f5..c8fa6080a4e 100644 --- a/linux-user/hexagon/cpu_loop.c +++ b/linux-user/hexagon/cpu_loop.c @@ -33,7 +33,7 @@ void cpu_loop(CPUHexagonState *env) target_ulong syscallnum; target_ulong ret; - env->hvx = &env->hvx_ctx; + env->hvx = &HEXAGON_CPU(cs)->hvx_ctx; for (;;) { cpu_exec_start(cs); diff --git a/linux-user/main.c b/linux-user/main.c index 60a695b7ca3..918b4930b07 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -244,6 +244,9 @@ CPUArchState *cpu_copy(CPUArchState *env) new_cpu->tcg_cflags = cpu->tcg_cflags; memcpy(new_env, env, sizeof(CPUArchState)); +#if defined(TARGET_HEXAGON) + HEXAGON_CPU(new_cpu)->hvx_ctx = HEXAGON_CPU(cpu)->hvx_ctx; +#endif #if defined(TARGET_I386) || defined(TARGET_X86_64) new_env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, PROT_READ | PROT_WRITE, diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 68c50cbcb45..a62191cf3fb 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -43,6 +43,7 @@ #include "exec/page-protection.h" #include "exec/target_page.h" #include "hw/hexagon/hexagon_globalreg.h" +#include "hw/hexagon/hexagon_hvx_context.h" #endif static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model) @@ -412,15 +413,17 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) CPUState *cs = CPU(obj); HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(obj); CPUHexagonState *env = cpu_env(cs); -#ifndef CONFIG_USER_ONLY HexagonCPU *cpu = HEXAGON_CPU(cs); -#endif if (mcc->parent_phases.hold) { mcc->parent_phases.hold(obj, type); } - env->hvx = &env->hvx_ctx; +#ifdef CONFIG_USER_ONLY + env->hvx = &cpu->hvx_ctx; +#else + env->hvx = cpu->hvx_ctx[0] ? &cpu->hvx_ctx[0]->regs : &cpu->hvx_fallback; +#endif set_default_nan_mode(1, &env->fp_status); set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); @@ -547,7 +550,17 @@ static void hexagon_cpu_init(Object *obj) { #ifndef CONFIG_USER_ONLY HexagonCPU *cpu = HEXAGON_CPU(obj); + int i; + qdev_init_gpio_in(DEVICE(cpu), hexagon_cpu_set_irq, 8); + + for (i = 0; i < HVX_CONTEXTS_MAX; i++) { + object_property_add_link(obj, "hvx-context[*]", + TYPE_HEXAGON_HVX_CONTEXT, + (Object **)&cpu->hvx_ctx[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } #endif } diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build index 720a5d54dcc..c4b257dfa28 100644 --- a/hw/hexagon/meson.build +++ b/hw/hexagon/meson.build @@ -1,6 +1,7 @@ hexagon_ss = ss.source_set() hexagon_ss.add(files('hexagon_tlb.c')) hexagon_ss.add(files('hexagon_globalreg.c')) +hexagon_ss.add(files('hexagon_hvx_context.c')) hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hex-subsys.c')) hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c')) hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c')) -- 2.34.1
