@@ -1685,6 +1685,9 @@ static void pnv_chip_power10_quad_realize(Pnv10Chip *chip10, Error **errp)
pnv_xscom_add_subregion(chip, PNV10_XSCOM_EQ_BASE(eq->quad_id),
&eq->xscom_regs);
+
+ pnv_xscom_add_subregion(chip, PNV10_XSCOM_QME_BASE(eq->quad_id),
+ &eq->xscom_qme_regs);
}
}
@@ -496,7 +496,67 @@ static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_quad_realize(DeviceState *dev, Error **errp)
+#define P10_QME_SPWU_HYP 0x83c
+#define P10_QME_SSH_HYP 0x82c
+
+static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
+ unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+ uint64_t val = -1;
+
+ /*
+ * Forth nibble selects the core within a quad, mask it to process read
+ * for any core.
+ */
+ switch (offset & ~0xf000) {
+ case P10_QME_SPWU_HYP:
+ case P10_QME_SSH_HYP:
+ return 0;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
+ offset);
+ }
+
+ return val;
+}
+
+static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned int width)
+{
+ uint32_t offset = addr >> 3;
+
+ switch (offset) {
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
+ offset);
+ }
+}
+
+static const MemoryRegionOps pnv_qme_power10_xscom_ops = {
+ .read = pnv_qme_power10_xscom_read,
+ .write = pnv_qme_power10_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void pnv_quad_power9_realize(DeviceState *dev, Error **errp)
+{
+ PnvQuad *eq = PNV_QUAD(dev);
+ PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
+ char name[32];
+
+ snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
+ pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
+ pqc->xscom_ops,
+ eq, name,
+ pqc->xscom_size);
+}
+
+static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
{
PnvQuad *eq = PNV_QUAD(dev);
PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
@@ -507,6 +567,12 @@ static void pnv_quad_realize(DeviceState *dev, Error **errp)
pqc->xscom_ops,
eq, name,
pqc->xscom_size);
+
+ snprintf(name, sizeof(name), "xscom-qme.%d", eq->quad_id);
+ pnv_xscom_region_init(&eq->xscom_qme_regs, OBJECT(dev),
+ pqc->xscom_qme_ops,
+ eq, name,
+ pqc->xscom_qme_size);
}
static Property pnv_quad_properties[] = {
@@ -517,6 +583,9 @@ static Property pnv_quad_properties[] = {
static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
{
PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = pnv_quad_power9_realize;
pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
@@ -525,16 +594,21 @@ static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
{
PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = pnv_quad_power10_realize;
pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
+
+ pqc->xscom_qme_ops = &pnv_qme_power10_xscom_ops;
+ pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
}
static void pnv_quad_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->realize = pnv_quad_realize;
device_class_set_props(dc, pnv_quad_properties);
dc->user_creatable = false;
}
@@ -66,6 +66,9 @@ struct PnvQuadClass {
const MemoryRegionOps *xscom_ops;
uint64_t xscom_size;
+
+ const MemoryRegionOps *xscom_qme_ops;
+ uint64_t xscom_qme_size;
};
#define TYPE_PNV_QUAD "powernv-cpu-quad"
@@ -80,5 +83,6 @@ struct PnvQuad {
uint32_t quad_id;
MemoryRegion xscom_regs;
+ MemoryRegion xscom_qme_regs;
};
#endif /* PPC_PNV_CORE_H */
@@ -127,6 +127,17 @@ struct PnvXScomInterfaceClass {
#define PNV10_XSCOM_EC(proc) \
((0x2 << 16) | ((1 << (3 - (proc))) << 12))
+#define PNV10_XSCOM_QME(chiplet) \
+ (PNV10_XSCOM_EQ(chiplet) | (0xE << 16))
+
+/*
+ * Make the region larger by 0x1000 (instead of starting at an offset) so the
+ * modelled addresses start from 0
+ */
+#define PNV10_XSCOM_QME_BASE(core) \
+ ((uint64_t) PNV10_XSCOM_QME(PNV10_XSCOM_EQ_CHIPLET(core)))
+#define PNV10_XSCOM_QME_SIZE (0x8000 + 0x1000)
+
#define PNV10_XSCOM_EQ_BASE(core) \
((uint64_t) PNV10_XSCOM_EQ(PNV10_XSCOM_EQ_CHIPLET(core)))
#define PNV10_XSCOM_EQ_SIZE 0x20000