Skip to content

Commit

Permalink
ppc/pnv: Add QME region for P10
Browse files Browse the repository at this point in the history
The Quad Management Engine (QME) manages power related settings for its
quad. The xscom region is separate from the quad xscoms, therefore a new
region is added. The xscoms in a QME select a given core by selecting
the forth nibble.

Implement dummy reads for the stop state history (SSH) and special
wakeup (SPWU) registers. This quietens some sxcom errors when skiboot
boots on p10.

Power9 does not have a QME.

Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20230707071213.9924-1-joel@jms.id.au>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
  • Loading branch information
shenki authored and danielhb committed Jul 7, 2023
1 parent 9c1ce77 commit bdb9759
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 2 deletions.
3 changes: 3 additions & 0 deletions hw/ppc/pnv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
78 changes: 76 additions & 2 deletions hw/ppc/pnv_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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[] = {
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down
4 changes: 4 additions & 0 deletions include/hw/ppc/pnv_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -80,5 +83,6 @@ struct PnvQuad {

uint32_t quad_id;
MemoryRegion xscom_regs;
MemoryRegion xscom_qme_regs;
};
#endif /* PPC_PNV_CORE_H */
11 changes: 11 additions & 0 deletions include/hw/ppc/pnv_xscom.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit bdb9759

Please sign in to comment.