[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-ppc] [Qemu-devel] [PATCH for-2.10 4/8] ppc/pnv: add memory reg
From: |
Cédric Le Goater |
Subject: |
Re: [Qemu-ppc] [Qemu-devel] [PATCH for-2.10 4/8] ppc/pnv: add memory regions for the ICP registers |
Date: |
Wed, 8 Mar 2017 14:33:36 +0100 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.7.0 |
On 03/08/2017 12:24 PM, Philippe Mathieu-Daudé wrote:
> Hi Cédric,
>
> On 03/08/2017 07:52 AM, Cédric Le Goater wrote:
>> This provides to a PowerNV chip (POWER8) access to the Interrupt
>> Management area, which contains the registers of the Interrupt Control
>> Presenters of each thread. These are used to accept, return, forward
>> interrupts in the system.
>>
>> This area is modeled with a per-chip container memory region holding
>> all the ICP registers. Each thread of a chip is then associated with
>> its ICP registers using a memory subregion indexed by its PIR number
>> in the overall region.
>>
>> Signed-off-by: Cédric Le Goater <address@hidden>
>> ---
>> hw/ppc/pnv.c | 20 +++++++
>> hw/ppc/pnv_core.c | 146
>> ++++++++++++++++++++++++++++++++++++++++++++++
>> include/hw/ppc/pnv.h | 20 +++++++
>> include/hw/ppc/pnv_core.h | 1 +
>> include/hw/ppc/xics.h | 3 +
>> 5 files changed, 190 insertions(+)
>>
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 461d3535e99c..7b13b08deadf 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -658,6 +658,16 @@ static void pnv_chip_init(Object *obj)
>> object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL);
>> }
>>
>> +static void pnv_chip_icp_realize(PnvChip *chip, Error **errp)
>> +{
>> + char *name;
>> +
>> + name = g_strdup_printf("icp-%x", chip->chip_id);
>> + memory_region_init(&chip->icp_mmio, OBJECT(chip), name, PNV_ICP_SIZE);
>> + sysbus_init_mmio(SYS_BUS_DEVICE(chip), &chip->icp_mmio);
>> + g_free(name);
>> +}
>> +
>> static void pnv_chip_realize(DeviceState *dev, Error **errp)
>> {
>> PnvChip *chip = PNV_CHIP(dev);
>> @@ -680,6 +690,14 @@ static void pnv_chip_realize(DeviceState *dev, Error
>> **errp)
>> }
>> sysbus_mmio_map(SYS_BUS_DEVICE(chip), 0, PNV_XSCOM_BASE(chip));
>>
>> + /* Interrupt Management Area. This is the memory region holding
>> + * all the Interrupt Control Presenter (ICP) registers */
>> + pnv_chip_icp_realize(chip, &error);
>> + if (error) {
>> + error_propagate(errp, error);
>> + return;
>> + }
>> +
>> /* Cores */
>> pnv_chip_core_sanitize(chip, &error);
>> if (error) {
>> @@ -709,6 +727,8 @@ static void pnv_chip_realize(DeviceState *dev, Error
>> **errp)
>> object_property_set_int(OBJECT(pnv_core),
>> pcc->core_pir(chip, core_hwid),
>> "pir", &error_fatal);
>> + object_property_add_const_link(OBJECT(pnv_core), "xics",
>> + qdev_get_machine(), &error_fatal);
>> object_property_set_bool(OBJECT(pnv_core), true, "realized",
>> &error_fatal);
>> object_unref(OBJECT(pnv_core));
>> diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
>> index d79d530b4881..8633afbff795 100644
>> --- a/hw/ppc/pnv_core.c
>> +++ b/hw/ppc/pnv_core.c
>> @@ -26,6 +26,128 @@
>> #include "hw/ppc/pnv_core.h"
>> #include "hw/ppc/pnv_xscom.h"
>>
>> +static uint64_t pnv_core_icp_read(void *opaque, hwaddr addr, unsigned width)
>> +{
>> + ICPState *icp = opaque;
>> + bool byte0 = (width == 1 && (addr & 0x3) == 0);
>
> hard to read, an inline function should produce the same code at be more
> easily reviewable.
true. I can improve that if a resend is needed.
Thanks,
C.
>> + uint64_t val = 0xffffffff;
>> +
>> + switch (addr & 0xffc) {
>> + case 0: /* poll */
>> + val = icp_ipoll(icp, NULL);
>> + if (byte0) {
>> + val >>= 24;
>> + } else if (width != 4) {
>> + goto bad_access;
>> + }
>> + break;
>> + case 4: /* xirr */
>> + if (byte0) {
>> + val = icp_ipoll(icp, NULL) >> 24;
>> + } else if (width == 4) {
>> + val = icp_accept(icp);
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + case 12:
>> + if (byte0) {
>> + val = icp->mfrr;
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + case 16:
>> + if (width == 4) {
>> + val = icp->links[0];
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + case 20:
>> + if (width == 4) {
>> + val = icp->links[1];
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + case 24:
>> + if (width == 4) {
>> + val = icp->links[2];
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + default:
>> +bad_access:
>> + qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
>> + HWADDR_PRIx"/%d\n", addr, width);
>> + }
>> +
>> + return val;
>> +}
>> +
>> +static void pnv_core_icp_write(void *opaque, hwaddr addr, uint64_t val,
>> + unsigned width)
>> +{
>> + ICPState *icp = opaque;
>> + bool byte0 = (width == 1 && (addr & 0x3) == 0);
>> +
>> + switch (addr & 0xffc) {
>> + case 4: /* xirr */
>> + if (byte0) {
>> + icp_set_cppr(icp, val);
>> + } else if (width == 4) {
>> + icp_eoi(icp, val);
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + case 12:
>> + if (byte0) {
>> + icp_set_mfrr(icp, val);
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + case 16:
>> + if (width == 4) {
>> + icp->links[0] = val;
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + case 20:
>> + if (width == 4) {
>> + icp->links[1] = val;
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + case 24:
>> + if (width == 4) {
>> + icp->links[2] = val;
>> + } else {
>> + goto bad_access;
>> + }
>> + break;
>> + default:
>> +bad_access:
>> + qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
>> + HWADDR_PRIx"/%d\n", addr, width);
>> + }
>> +}
>> +
>> +static const MemoryRegionOps pnv_core_icp_ops = {
>> + .read = pnv_core_icp_read,
>> + .write = pnv_core_icp_write,
>> + .valid.min_access_size = 1,
>> + .valid.max_access_size = 4,
>> + .impl.min_access_size = 1,
>> + .impl.max_access_size = 4,
>> + .endianness = DEVICE_BIG_ENDIAN,
>> +};
>> +
>> static void powernv_cpu_reset(void *opaque)
>> {
>> PowerPCCPU *cpu = opaque;
>> @@ -129,6 +251,14 @@ static void pnv_core_realize_child(Object *child, Error
>> **errp)
>> }
>> }
>>
>> +static ICPState *xics_get_icp_per_pir(XICSFabric *xi, int pir)
>> +{
>> + int index = xics_get_cpu_index_by_pir(pir);
>> + assert(index != -1);
>> +
>> + return xics_icp_get(xi, index);
>> +}
>> +
>> static void pnv_core_realize(DeviceState *dev, Error **errp)
>> {
>> PnvCore *pc = PNV_CORE(OBJECT(dev));
>> @@ -140,6 +270,14 @@ static void pnv_core_realize(DeviceState *dev, Error
>> **errp)
>> void *obj;
>> int i, j;
>> char name[32];
>> + Object *xi;
>> +
>> + xi = object_property_get_link(OBJECT(dev), "xics", &local_err);
>> + if (!xi) {
>> + error_setg(errp, "%s: required link 'xics' not found: %s",
>> + __func__, error_get_pretty(local_err));
>> + return;
>> + }
>>
>> pc->threads = g_malloc0(size * cc->nr_threads);
>> for (i = 0; i < cc->nr_threads; i++) {
>> @@ -169,6 +307,14 @@ static void pnv_core_realize(DeviceState *dev, Error
>> **errp)
>> snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
>> pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), &pnv_core_xscom_ops,
>> pc, name, PNV_XSCOM_EX_CORE_SIZE);
>> +
>> + pc->icp_mmios = g_new0(MemoryRegion, cc->nr_threads);
>> + for (i = 0; i < cc->nr_threads; i++) {
>> + ICPState *icp = xics_get_icp_per_pir(XICS_FABRIC(xi), pc->pir + i);
>> + snprintf(name, sizeof(name), "icp-core.%d", cc->core_id);
>> + memory_region_init_io(&pc->icp_mmios[i], OBJECT(dev),
>> + &pnv_core_icp_ops, icp, name, 0x1000);
>> + }
>> return;
>>
>> err:
>> diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
>> index 6a0b004cea93..f11215ea31f2 100644
>> --- a/include/hw/ppc/pnv.h
>> +++ b/include/hw/ppc/pnv.h
>> @@ -55,6 +55,7 @@ typedef struct PnvChip {
>> MemoryRegion xscom_mmio;
>> MemoryRegion xscom;
>> AddressSpace xscom_as;
>> + MemoryRegion icp_mmio;
>>
>> PnvLpcController lpc;
>> } PnvChip;
>> @@ -130,4 +131,23 @@ typedef struct PnvMachineState {
>> #define PNV_XSCOM_BASE(chip) \
>> (chip->xscom_base + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE)
>>
>> +/*
>> + * XSCOM 0x20109CA defines the ICP BAR:
>> + *
>> + * 0:29 : bits 14 to 43 of address to define 1 MB region.
>> + * 30 : 1 to enable ICP to receive loads/stores against its BAR region
>> + * 31:63 : Constant 0
>> + *
>> + * Usually defined as :
>> + *
>> + * 0xffffe00200000000 -> 0x0003ffff80000000
>> + * 0xffffe00600000000 -> 0x0003ffff80100000
>> + * 0xffffe02200000000 -> 0x0003ffff80800000
>> + * 0xffffe02600000000 -> 0x0003ffff80900000
>> + *
>> + * TODO: make a macro using the chip hw id
>> + */
>> +#define PNV_ICP_BASE(chip) 0x0003ffff80000000ull
>> +#define PNV_ICP_SIZE 0x0000000000100000ull
>> +
>> #endif /* _PPC_PNV_H */
>> diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
>> index 2955a41c901f..f2fad8f6361b 100644
>> --- a/include/hw/ppc/pnv_core.h
>> +++ b/include/hw/ppc/pnv_core.h
>> @@ -38,6 +38,7 @@ typedef struct PnvCore {
>> uint32_t pir;
>>
>> MemoryRegion xscom_regs;
>> + MemoryRegion *icp_mmios;
>> } PnvCore;
>>
>> typedef struct PnvCoreClass {
>> diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h
>> index c2032cac55f6..a3dcdf93bbe3 100644
>> --- a/include/hw/ppc/xics.h
>> +++ b/include/hw/ppc/xics.h
>> @@ -78,6 +78,9 @@ struct ICPState {
>> bool cap_irq_xics_enabled;
>>
>> XICSFabric *xics;
>> +
>> + /* for the PowerNV ICP registers (not used by Linux). */
>> + uint32_t links[3];
>> };
>>
>> #define TYPE_ICS_BASE "ics-base"
>>
[Qemu-ppc] [PATCH for-2.10 4/8] ppc/pnv: add memory regions for the ICP registers, Cédric Le Goater, 2017/03/08
[Qemu-ppc] [PATCH for-2.10 2/8] ppc/xics: add an ics_eoi() handler to XICSFabric, Cédric Le Goater, 2017/03/08
[Qemu-ppc] [PATCH for-2.10 3/8] ppc/pnv: create the ICP and ICS objects under the machine, Cédric Le Goater, 2017/03/08
[Qemu-ppc] [PATCH for-2.10 5/8] ppc/pnv: map the ICP memory regions, Cédric Le Goater, 2017/03/08