We implemented following functions to allow software
to probe and control VPs on secondary core
- Reading out pcore count and coherence state
- Two scratch GCRs for firmware
- Semaphore GCR for register locking
- Redirect block to other cores
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
hw/misc/mips_cmgcr.c | 168 +++++++++++++++++++++++++++++++++++--------
include/hw/misc/mips_cmgcr.h | 87 +++++++++++++++++++---
2 files changed, 215 insertions(+), 40 deletions(-)
diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c
index 2703040f45..8c2d184f2c 100644
--- a/hw/misc/mips_cmgcr.c
+++ b/hw/misc/mips_cmgcr.c
@@ -73,14 +73,19 @@ static inline void update_gic_base(MIPSGCRState *gcr, uint64_t val)
static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
{
MIPSGCRState *gcr = (MIPSGCRState *) opaque;
- MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index];
- MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other];
+ int redirect_corenum = mips_gcr_get_redirect_corenum(gcr);
+ int redirect_vpid = mips_gcr_get_redirect_vpid(gcr);
+ int current_corenum = mips_gcr_get_current_corenum(gcr);
+ int current_vpid = mips_gcr_get_current_vpid(gcr);
+ MIPSGCRPCoreState *current_pcore = &gcr->pcs[current_corenum];
+ MIPSGCRVPState *current_vps = ¤t_pcore->vps[current_vpid];
+ MIPSGCRPCoreState *other_pcore = &gcr->pcs[redirect_corenum];
+ MIPSGCRVPState *other_vps = &other_pcore->vps[redirect_vpid];
switch (addr) {
/* Global Control Block Register */
case GCR_CONFIG_OFS:
- /* Set PCORES to 0 */
- return 0;
+ return gcr->num_pcores - 1;
case GCR_BASE_OFS:
return gcr->gcr_base;
case GCR_REV_OFS:
@@ -96,7 +101,19 @@ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
case GCR_L2_CONFIG_OFS:
/* L2 BYPASS */
return GCR_L2_CONFIG_BYPASS_MSK;
+ case GCR_SYS_CONFIG2_OFS:
+ return gcr->num_vps << GCR_SYS_CONFIG2_MAXVP_SHF;
+ case GCR_SCRATCH0_OFS:
+ return gcr->scratch[0];
+ case GCR_SCRATCH1_OFS:
+ return gcr->scratch[1];
+ case GCR_SEM_OFS:
+ return gcr->sem;
/* Core-Local and Core-Other Control Blocks */
+ case MIPS_CLCB_OFS + GCR_CL_COH_EN_OFS:
+ return current_pcore->coh_en;
+ case MIPS_COCB_OFS + GCR_CL_COH_EN_OFS:
+ return other_pcore->coh_en;
case MIPS_CLCB_OFS + GCR_CL_CONFIG_OFS:
case MIPS_COCB_OFS + GCR_CL_CONFIG_OFS:
/* Set PVP to # of VPs - 1 */
@@ -105,10 +122,18 @@ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
return current_vps->reset_base;
case MIPS_COCB_OFS + GCR_CL_RESETBASE_OFS:
return other_vps->reset_base;
- case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS:
- return current_vps->other;
- case MIPS_COCB_OFS + GCR_CL_OTHER_OFS:
- return other_vps->other;
+ case MIPS_CLCB_OFS + GCR_CL_REDIRECT_OFS:
+ return current_vps->redirect;
+ case MIPS_COCB_OFS + GCR_CL_REDIRECT_OFS:
+ return other_vps->redirect;
+ case MIPS_CLCB_OFS + GCR_CL_ID_OFS:
+ return current_corenum;
+ case MIPS_COCB_OFS + GCR_CL_ID_OFS:
+ return redirect_corenum;
+ case MIPS_CLCB_OFS + GCR_CL_SCRATCH_OFS:
+ return current_vps->scratch;
+ case MIPS_COCB_OFS + GCR_CL_SCRATCH_OFS:
+ return other_vps->scratch;
default:
qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
"\n", size, addr);
@@ -123,12 +148,36 @@ static inline target_ulong get_exception_base(MIPSGCRVPState *vps)
return (int32_t)(vps->reset_base & GCR_CL_RESET_BASE_RESETBASE_MSK);
}
+static inline void set_redirect(MIPSGCRState *gcr,
+ MIPSGCRVPState *vps, target_ulong data)
+{
+ int new_vpid = data & GCR_CL_REDIRECT_VP_MSK;
+ int new_coreid = (data & GCR_CL_REDIRECT_CORE_MSK) >> GCR_CL_REDIRECT_CORE_SHF;
+
+ if (new_vpid >= gcr->num_vps) {
+ return;
+ }
+
+ if (new_coreid >= gcr->num_pcores) {
+ return;
+ }
+
+ vps->redirect = data & (GCR_CL_REDIRECT_VP_MSK | GCR_CL_REDIRECT_CORE_MSK);
+}
+
/* Write GCR registers */
static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
{
- MIPSGCRState *gcr = (MIPSGCRState *)opaque;
- MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index];
- MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other];
+ MIPSGCRState *gcr = (MIPSGCRState *) opaque;
+ int redirect_corenum = mips_gcr_get_redirect_corenum(gcr);
+ int redirect_vpid = mips_gcr_get_redirect_vpid(gcr);
+ int redirect_vpnum = mips_gcr_get_redirect_vpnum(gcr);
+ int current_corenum = mips_gcr_get_current_corenum(gcr);
+ int current_vpid = mips_gcr_get_current_vpid(gcr);
+ MIPSGCRPCoreState *current_pcore = &gcr->pcs[current_corenum];
+ MIPSGCRVPState *current_vps = ¤t_pcore->vps[current_vpid];
+ MIPSGCRPCoreState *other_pcore = &gcr->pcs[redirect_corenum];
+ MIPSGCRVPState *other_vps = &other_pcore->vps[redirect_vpid];
switch (addr) {
case GCR_BASE_OFS:
@@ -140,6 +189,25 @@ static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
case GCR_CPC_BASE_OFS:
update_cpc_base(gcr, data);
break;
+ case GCR_SCRATCH0_OFS:
+ gcr->scratch[0] = data;
+ break;
+ case GCR_SCRATCH1_OFS:
+ gcr->scratch[1] = data;
+ break;
+ case GCR_SEM_OFS:
+ /* Write is inhibited if the SEM_LOCK bit is already 1 */
+ if ((data & GCR_SEM_LOCK_MASK) && (gcr->sem & GCR_SEM_LOCK_MASK)) {
+ break;
+ }
+ gcr->sem = data;
+ break;
+ case MIPS_CLCB_OFS + GCR_CL_COH_EN_OFS:
+ current_pcore->coh_en = data & 1;
+ break;
+ case MIPS_COCB_OFS + GCR_CL_COH_EN_OFS:
+ other_pcore->coh_en = data & 1;
+ break;
case MIPS_CLCB_OFS + GCR_CL_RESETBASE_OFS:
current_vps->reset_base = data & GCR_CL_RESET_BASE_MSK;
cpu_set_exception_base(current_cpu->cpu_index,
@@ -147,18 +215,17 @@ static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
break;
case MIPS_COCB_OFS + GCR_CL_RESETBASE_OFS:
other_vps->reset_base = data & GCR_CL_RESET_BASE_MSK;
- cpu_set_exception_base(current_vps->other,
+ cpu_set_exception_base(redirect_vpnum,
get_exception_base(other_vps));
break;
- case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS:
- if ((data & GCR_CL_OTHER_MSK) < gcr->num_vps) {
- current_vps->other = data & GCR_CL_OTHER_MSK;
- }
+ case MIPS_CLCB_OFS + GCR_CL_REDIRECT_OFS:
+ set_redirect(gcr, current_vps, data);
break;
- case MIPS_COCB_OFS + GCR_CL_OTHER_OFS:
- if ((data & GCR_CL_OTHER_MSK) < gcr->num_vps) {
- other_vps->other = data & GCR_CL_OTHER_MSK;
- }
+ case MIPS_COCB_OFS + GCR_CL_SCRATCH_OFS:
+ other_vps->scratch = data;
+ break;
+ case MIPS_COCB_OFS + GCR_CL_REDIRECT_OFS:
+ set_redirect(gcr, other_vps, data);
break;
default:
qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
@@ -189,30 +256,67 @@ static void mips_gcr_init(Object *obj)
static void mips_gcr_reset(DeviceState *dev)
{
MIPSGCRState *s = MIPS_GCR(dev);
- int i;
+ int pc, vp;
+ update_gcr_base(s, s->gcr_base);
update_gic_base(s, 0);
update_cpc_base(s, 0);
- for (i = 0; i < s->num_vps; i++) {
- s->vps[i].other = 0;
- s->vps[i].reset_base = 0xBFC00000 & GCR_CL_RESET_BASE_MSK;
- cpu_set_exception_base(i, get_exception_base(&s->vps[i]));
+ for (pc = 0; pc < s->num_pcores; pc++) {
+ s->pcs[pc].coh_en = 1;
+ for (vp = 0; vp < s->num_vps; vp++) {
+ int vpnum = pc * s->num_vps + vp;
+
+ s->pcs[pc].vps[vp].redirect = 0;
+ s->pcs[pc].vps[vp].reset_base = 0xBFC00000 & GCR_CL_RESET_BASE_MSK;
+ cpu_set_exception_base(vpnum, get_exception_base(&s->pcs[pc].vps[vp]));
+ }
}
}
-static const VMStateDescription vmstate_mips_gcr = {
- .name = "mips-gcr",
+static const VMStateDescription vmstate_mips_gcr_vps = {
+ .name = "mips-gcr/vps",
.version_id = 0,
.minimum_version_id = 0,
.fields = (const VMStateField[]) {
+ VMSTATE_UINT32(redirect, MIPSGCRVPState),
+ VMSTATE_UINT64(reset_base, MIPSGCRVPState),
+ VMSTATE_UINT64(scratch, MIPSGCRVPState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_mips_gcr_pcs = {
+ .name = "mips-gcr/pcs",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (const VMStateField[]) {
+ VMSTATE_INT32(num_vps, MIPSGCRPCoreState),
+ VMSTATE_UINT32(coh_en, MIPSGCRPCoreState),
+ VMSTATE_STRUCT_VARRAY_ALLOC(vps, MIPSGCRPCoreState, num_vps, 0,
+ vmstate_mips_gcr_vps, MIPSGCRVPState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_mips_gcr = {
+ .name = "mips-gcr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64_ARRAY(scratch, MIPSGCRState, 2),
+ VMSTATE_UINT32(sem, MIPSGCRState),
VMSTATE_UINT64(cpc_base, MIPSGCRState),
+ VMSTATE_UINT64(gic_base, MIPSGCRState),
+ VMSTATE_STRUCT_VARRAY_ALLOC(pcs, MIPSGCRState, num_pcores, 0,
+ vmstate_mips_gcr_pcs, MIPSGCRPCoreState),
VMSTATE_END_OF_LIST()
},
};
static Property mips_gcr_properties[] = {
- DEFINE_PROP_UINT32("num-vp", MIPSGCRState, num_vps, 1),
+ DEFINE_PROP_INT32("num-pcores", MIPSGCRState, num_pcores, 1),
+ DEFINE_PROP_INT32("num-vp", MIPSGCRState, num_vps, 1),
DEFINE_PROP_INT32("gcr-rev", MIPSGCRState, gcr_rev, 0x800),
DEFINE_PROP_UINT64("gcr-base", MIPSGCRState, gcr_base, GCR_BASE_ADDR),
DEFINE_PROP_LINK("gic", MIPSGCRState, gic_mr, TYPE_MEMORY_REGION,
@@ -226,8 +330,12 @@ static void mips_gcr_realize(DeviceState *dev, Error **errp)
{
MIPSGCRState *s = MIPS_GCR(dev);
- /* Create local set of registers for each VP */
- s->vps = g_new(MIPSGCRVPState, s->num_vps);
+ /* Create local set of registers for each VP and each pcore */
+ s->pcs = g_new(MIPSGCRPCoreState, s->num_pcores);
+ for (int i = 0; i < s->num_pcores; i++) {
+ s->pcs[i].num_vps = s->num_vps;
+ s->pcs[i].vps = g_new(MIPSGCRVPState, s->num_vps);
+ }
}
static void mips_gcr_class_init(ObjectClass *klass, void *data)
diff --git a/include/hw/misc/mips_cmgcr.h b/include/hw/misc/mips_cmgcr.h
index db4bf5f449..f75ff660c2 100644
--- a/include/hw/misc/mips_cmgcr.h
+++ b/include/hw/misc/mips_cmgcr.h
@@ -34,16 +34,27 @@ OBJECT_DECLARE_SIMPLE_TYPE(MIPSGCRState, MIPS_GCR)
#define GCR_GIC_STATUS_OFS 0x00D0
#define GCR_CPC_STATUS_OFS 0x00F0
#define GCR_L2_CONFIG_OFS 0x0130
+#define GCR_SYS_CONFIG2_OFS 0x0150
+#define GCR_SCRATCH0_OFS 0x0280
+#define GCR_SCRATCH1_OFS 0x0288
+#define GCR_SEM_OFS 0x0640
/* Core Local and Core Other Block Register Map */
-#define GCR_CL_CONFIG_OFS 0x0010
-#define GCR_CL_OTHER_OFS 0x0018
-#define GCR_CL_RESETBASE_OFS 0x0020
+#define GCR_CL_COH_EN_OFS 0x0008 /* Core-Local */
+#define GCR_CL_CONFIG_OFS 0x0010 /* Core-Local */
+#define GCR_CL_REDIRECT_OFS 0x0018 /* VP-Local */
+#define GCR_CL_RESETBASE_OFS 0x0020 /* VP-Local */
+#define GCR_CL_ID_OFS 0x0028 /* Core-Local */
+#define GCR_CL_SCRATCH_OFS 0x0060 /* VP-Local */
/* GCR_L2_CONFIG register fields */
#define GCR_L2_CONFIG_BYPASS_SHF 20
#define GCR_L2_CONFIG_BYPASS_MSK ((0x1ULL) << GCR_L2_CONFIG_BYPASS_SHF)
+/* GCR_SYS_CONFIG2 register fields */
+#define GCR_SYS_CONFIG2_MAXVP_SHF 0
+#define GCR_SYS_CONFIG2_MAXVP_MSK ((0xFULL) << GCR_SYS_CONFIG2_MAXVP_SHF)
+
/* GCR_BASE register fields */
#define GCR_BASE_GCRBASE_MSK 0xffffffff8000ULL
@@ -52,14 +63,20 @@ OBJECT_DECLARE_SIMPLE_TYPE(MIPSGCRState, MIPS_GCR)
#define GCR_GIC_BASE_GICBASE_MSK 0xFFFFFFFE0000ULL
#define GCR_GIC_BASE_MSK (GCR_GIC_BASE_GICEN_MSK | GCR_GIC_BASE_GICBASE_MSK)
+/* GCR_SEM register fields */
+#define GCR_SEM_DATA_MSK 0x00000000EFFFFFFFULL
+#define GCR_SEM_LOCK_MASK 0x0000000080000000ULL
+
/* GCR_CPC_BASE register fields */
#define GCR_CPC_BASE_CPCEN_MSK 1
#define GCR_CPC_BASE_CPCBASE_MSK 0xFFFFFFFF8000ULL
#define GCR_CPC_BASE_MSK (GCR_CPC_BASE_CPCEN_MSK | GCR_CPC_BASE_CPCBASE_MSK)
-/* GCR_CL_OTHER_OFS register fields */
-#define GCR_CL_OTHER_VPOTHER_MSK 0x7
-#define GCR_CL_OTHER_MSK GCR_CL_OTHER_VPOTHER_MSK
+/* GCR_CL_REDIRECT_OFS register fields */
+#define GCR_CL_REDIRECT_VP_MSK 0x7U
+#define GCR_CL_REDIRECT_VP_SHF 0
+#define GCR_CL_REDIRECT_CORE_MSK 0xF00U
+#define GCR_CL_REDIRECT_CORE_SHF 8
/* GCR_CL_RESETBASE_OFS register fields */
#define GCR_CL_RESET_BASE_RESETBASE_MSK 0xFFFFF000U
@@ -67,15 +84,28 @@ OBJECT_DECLARE_SIMPLE_TYPE(MIPSGCRState, MIPS_GCR)
typedef struct MIPSGCRVPState MIPSGCRVPState;
struct MIPSGCRVPState {
- uint32_t other;
+ uint32_t redirect;
uint64_t reset_base;
+ uint64_t scratch;
+};
+
+typedef struct MIPSGCRPCoreState MIPSGCRPCoreState;
+struct MIPSGCRPCoreState {
+ int32_t num_vps; /* Number of VPs in that core */
+ uint32_t coh_en;
+ /* VP Local/Other Registers */
+ MIPSGCRVPState *vps;
};
struct MIPSGCRState {
SysBusDevice parent_obj;
int32_t gcr_rev;
- uint32_t num_vps;
+ int32_t num_pcores; /* Number of physical cores */
+ int32_t num_vps; /* Number of VPs per physical core */
+
+ uint64_t scratch[2]; /* GCR Scratch */
+ uint32_t sem; /* GCR Semaphore */
hwaddr gcr_base;
MemoryRegion iomem;
MemoryRegion *cpc_mr;
@@ -84,8 +114,45 @@ struct MIPSGCRState {
uint64_t cpc_base;
uint64_t gic_base;
- /* VP Local/Other Registers */
- MIPSGCRVPState *vps;
+ /* Core Local/Other Registers */
+ MIPSGCRPCoreState *pcs;
};
+static inline int mips_gcr_get_current_corenum(MIPSGCRState *s)
+{
+ return current_cpu->cpu_index / s->num_vps;
+}
+
+static inline int mips_gcr_get_current_vpid(MIPSGCRState *s)
+{
+ return current_cpu->cpu_index % s->num_vps;
+}
+
+static inline int mips_gcr_get_redirect_corenum(MIPSGCRState *s)
+{
+ int current_corenum = mips_gcr_get_current_corenum(s);
+ int current_vpid = mips_gcr_get_current_vpid(s);
+ MIPSGCRVPState *current_vps = &s->pcs[current_corenum].vps[current_vpid];
+
+ return (current_vps->redirect & GCR_CL_REDIRECT_CORE_MSK) >>
+ GCR_CL_REDIRECT_CORE_SHF;
+}
+
+static inline int mips_gcr_get_redirect_vpid(MIPSGCRState *s)
+{
+ int current_corenum = mips_gcr_get_current_corenum(s);
+ int current_vpid = mips_gcr_get_current_vpid(s);
+ MIPSGCRVPState *current_vps = &s->pcs[current_corenum].vps[current_vpid];
+
+ return (current_vps->redirect & GCR_CL_REDIRECT_VP_MSK) >>
+ GCR_CL_REDIRECT_VP_SHF;
+}
+
+static inline int mips_gcr_get_redirect_vpnum(MIPSGCRState *s)
+{
+ int core = mips_gcr_get_redirect_corenum(s);
+ int vpid = mips_gcr_get_redirect_vpid(s);
+ return core * s->num_vps + vpid;
+}
+
#endif /* MIPS_CMGCR_H */
--
2.34.1
© 2016 - 2024 Red Hat, Inc.