Commit 5dad902c authored by Cédric Le Goater's avatar Cédric Le Goater Committed by David Gibson
Browse files

ppc/pnv: POWER9 XSCOM quad support



The POWER9 processor does not support per-core frequency control. The
cores are arranged in groups of four, along with their respective L2
and L3 caches, into a structure known as a Quad. The frequency must be
managed at the Quad level.

Provide a basic Quad model to fake the settings done by the firmware
on the Non-Cacheable Unit (NCU). Each core pair (EX) needs a special
BAR setting for the TIMA area of XIVE because it resides on the same
address on all chips.

Signed-off-by: default avatarCédric Le Goater <clg@kaod.org>
Message-Id: <20190307223548.20516-12-clg@kaod.org>
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent 90ef386c
Loading
Loading
Loading
Loading
+37 −1
Original line number Diff line number Diff line
@@ -963,6 +963,36 @@ static void pnv_chip_power9_instance_init(Object *obj)
                                   OBJECT(&chip9->psi), &error_abort);
}

static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
{
    PnvChip *chip = PNV_CHIP(chip9);
    const char *typename = pnv_chip_core_typename(chip);
    size_t typesize = object_type_get_instance_size(typename);
    int i;

    chip9->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4);
    chip9->quads = g_new0(PnvQuad, chip9->nr_quads);

    for (i = 0; i < chip9->nr_quads; i++) {
        char eq_name[32];
        PnvQuad *eq = &chip9->quads[i];
        PnvCore *pnv_core = PNV_CORE(chip->cores + (i * 4) * typesize);
        int core_id = CPU_CORE(pnv_core)->core_id;

        object_initialize(eq, sizeof(*eq), TYPE_PNV_QUAD);
        snprintf(eq_name, sizeof(eq_name), "eq[%d]", core_id);

        object_property_add_child(OBJECT(chip), eq_name, OBJECT(eq),
                                  &error_fatal);
        object_property_set_int(OBJECT(eq), core_id, "id", &error_fatal);
        object_property_set_bool(OBJECT(eq), true, "realized", &error_fatal);
        object_unref(OBJECT(eq));

        pnv_xscom_add_subregion(chip, PNV9_XSCOM_EQ_BASE(eq->id),
                                &eq->xscom_regs);
    }
}

static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
{
    PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
@@ -977,6 +1007,12 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
        return;
    }

    pnv_chip_quad_realize(chip9, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }

    /* XIVE interrupt controller (POWER9) */
    object_property_set_int(OBJECT(&chip9->xive), PNV9_XIVE_IC_BASE(chip),
                            "ic-bar", &error_fatal);
@@ -1135,7 +1171,7 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
        if (!pnv_chip_is_power9(chip)) {
            xscom_core_base = PNV_XSCOM_EX_BASE(core_hwid);
        } else {
            xscom_core_base = PNV_XSCOM_P9_EC_BASE(core_hwid);
            xscom_core_base = PNV9_XSCOM_EC_BASE(core_hwid);
        }

        pnv_xscom_add_subregion(chip, xscom_core_base,
+87 −0
Original line number Diff line number Diff line
@@ -327,3 +327,90 @@ static const TypeInfo pnv_core_infos[] = {
};

DEFINE_TYPES(pnv_core_infos)

/*
 * POWER9 Quads
 */

#define P9X_EX_NCU_SPEC_BAR                     0x11010

static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr,
                                    unsigned int width)
{
    uint32_t offset = addr >> 3;
    uint64_t val = -1;

    switch (offset) {
    case P9X_EX_NCU_SPEC_BAR:
    case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
        val = 0;
        break;
    default:
        qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
                      offset);
    }

    return val;
}

static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val,
                                 unsigned int width)
{
    uint32_t offset = addr >> 3;

    switch (offset) {
    case P9X_EX_NCU_SPEC_BAR:
    case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
        break;
    default:
        qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
                  offset);
    }
}

static const MemoryRegionOps pnv_quad_xscom_ops = {
    .read = pnv_quad_xscom_read,
    .write = pnv_quad_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_realize(DeviceState *dev, Error **errp)
{
    PnvQuad *eq = PNV_QUAD(dev);
    char name[32];

    snprintf(name, sizeof(name), "xscom-quad.%d", eq->id);
    pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), &pnv_quad_xscom_ops,
                          eq, name, PNV9_XSCOM_EQ_SIZE);
}

static Property pnv_quad_properties[] = {
    DEFINE_PROP_UINT32("id", PnvQuad, id, 0),
    DEFINE_PROP_END_OF_LIST(),
};

static void pnv_quad_class_init(ObjectClass *oc, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(oc);

    dc->realize = pnv_quad_realize;
    dc->props = pnv_quad_properties;
}

static const TypeInfo pnv_quad_info = {
    .name          = TYPE_PNV_QUAD,
    .parent        = TYPE_DEVICE,
    .instance_size = sizeof(PnvQuad),
    .class_init    = pnv_quad_class_init,
};

static void pnv_core_register_types(void)
{
    type_register_static(&pnv_quad_info);
}

type_init(pnv_core_register_types)
+4 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "hw/ppc/pnv_psi.h"
#include "hw/ppc/pnv_occ.h"
#include "hw/ppc/pnv_xive.h"
#include "hw/ppc/pnv_core.h"

#define TYPE_PNV_CHIP "pnv-chip"
#define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
@@ -89,6 +90,9 @@ typedef struct Pnv9Chip {
    Pnv9Psi      psi;
    PnvLpcController lpc;
    PnvOCC       occ;

    uint32_t     nr_quads;
    PnvQuad      *quads;
} Pnv9Chip;

typedef struct PnvChipClass {
+10 −0
Original line number Diff line number Diff line
@@ -58,4 +58,14 @@ static inline PnvCPUState *pnv_cpu_state(PowerPCCPU *cpu)
    return (PnvCPUState *)cpu->machine_data;
}

#define TYPE_PNV_QUAD "powernv-cpu-quad"
#define PNV_QUAD(obj) \
    OBJECT_CHECK(PnvQuad, (obj), TYPE_PNV_QUAD)

typedef struct PnvQuad {
    DeviceState parent_obj;

    uint32_t id;
    MemoryRegion xscom_regs;
} PnvQuad;
#endif /* _PPC_PNV_CORE_H */
+8 −4
Original line number Diff line number Diff line
@@ -60,10 +60,6 @@ typedef struct PnvXScomInterfaceClass {
    (PNV_XSCOM_EX_CORE_BASE | ((uint64_t)(core) << 24))
#define PNV_XSCOM_EX_SIZE         0x100000

#define PNV_XSCOM_P9_EC_BASE(core) \
    ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
#define PNV_XSCOM_P9_EC_SIZE      0x100000

#define PNV_XSCOM_LPC_BASE        0xb0020
#define PNV_XSCOM_LPC_SIZE        0x4

@@ -73,6 +69,14 @@ typedef struct PnvXScomInterfaceClass {
#define PNV_XSCOM_OCC_BASE        0x0066000
#define PNV_XSCOM_OCC_SIZE        0x6000

#define PNV9_XSCOM_EC_BASE(core) \
    ((uint64_t)(((core) & 0x1F) + 0x20) << 24)
#define PNV9_XSCOM_EC_SIZE        0x100000

#define PNV9_XSCOM_EQ_BASE(core) \
    ((uint64_t)(((core) & 0x1C) + 0x40) << 22)
#define PNV9_XSCOM_EQ_SIZE        0x100000

#define PNV9_XSCOM_OCC_BASE       PNV_XSCOM_OCC_BASE
#define PNV9_XSCOM_OCC_SIZE       0x8000