qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v5 11/17] ppc/xics: Add "native" XICS subclass


From: Cédric Le Goater
Subject: Re: [Qemu-devel] [PATCH v5 11/17] ppc/xics: Add "native" XICS subclass
Date: Thu, 27 Oct 2016 19:43:10 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0

On 10/27/2016 05:09 AM, David Gibson wrote:
> On Wed, Oct 26, 2016 at 09:13:18AM +0200, Cédric Le Goater wrote:
>> On 10/25/2016 07:08 AM, David Gibson wrote:
>>> On Sat, Oct 22, 2016 at 11:46:44AM +0200, Cédric Le Goater wrote:
>>>> This provides access to the MMIO based Interrupt Presentation
>>>> Controllers (ICP) as found on a POWER8 system.
>>>>
>>>> A new XICSNative class is introduced to hold the MMIO region of the
>>>> ICPs. Each thread of the system has a subregion, indexed by its PIR
>>>> number, holding a XIVE (External Interrupt Vector Entry). This
>>>> provides a mean to make the link with the ICPState of the CPU.
>>>>
>>>> Signed-off-by: Cédric Le Goater <address@hidden>
>>>> ---
>>>>
>>>>  Changes since v4:
>>>>
>>>>  - replaced the pir_able by memory subregions using an ICP. 
>>>>  - removed the find_icp() and cpu_setup() handlers which became
>>>>    useless with the memory regions.
>>>>  - removed the superfluous inits done in xics_native_initfn. This is
>>>>    covered in the parent class init.
>>>>  - took ownership of the patch.
>>>>
>>>>  default-configs/ppc64-softmmu.mak |   3 +-
>>>>  hw/intc/Makefile.objs             |   1 +
>>>>  hw/intc/xics_native.c             | 304 
>>>> ++++++++++++++++++++++++++++++++++++++
>>>>  include/hw/ppc/pnv.h              |  19 +++
>>>>  include/hw/ppc/xics.h             |  24 +++
>>>>  5 files changed, 350 insertions(+), 1 deletion(-)
>>>>  create mode 100644 hw/intc/xics_native.c
>>>>
>>>> diff --git a/default-configs/ppc64-softmmu.mak 
>>>> b/default-configs/ppc64-softmmu.mak
>>>> index 67a9bcaa67fa..a22c93a48686 100644
>>>> --- a/default-configs/ppc64-softmmu.mak
>>>> +++ b/default-configs/ppc64-softmmu.mak
>>>> @@ -48,8 +48,9 @@ CONFIG_PLATFORM_BUS=y
>>>>  CONFIG_ETSEC=y
>>>>  CONFIG_LIBDECNUMBER=y
>>>>  # For pSeries
>>>> -CONFIG_XICS=$(CONFIG_PSERIES)
>>>> +CONFIG_XICS=$(or $(CONFIG_PSERIES),$(CONFIG_POWERNV))
>>>>  CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
>>>> +CONFIG_XICS_NATIVE=$(CONFIG_POWERNV)
>>>>  CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
>>>>  # For PReP
>>>>  CONFIG_MC146818RTC=y
>>>> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
>>>> index 2f44a2da26e9..e44a29d75b32 100644
>>>> --- a/hw/intc/Makefile.objs
>>>> +++ b/hw/intc/Makefile.objs
>>>> @@ -34,6 +34,7 @@ obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o
>>>>  obj-$(CONFIG_SH4) += sh_intc.o
>>>>  obj-$(CONFIG_XICS) += xics.o
>>>>  obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
>>>> +obj-$(CONFIG_XICS_NATIVE) += xics_native.o
>>>>  obj-$(CONFIG_XICS_KVM) += xics_kvm.o
>>>>  obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
>>>>  obj-$(CONFIG_S390_FLIC) += s390_flic.o
>>>> diff --git a/hw/intc/xics_native.c b/hw/intc/xics_native.c
>>>> new file mode 100644
>>>> index 000000000000..bbdd786aeb50
>>>> --- /dev/null
>>>> +++ b/hw/intc/xics_native.c
>>>> @@ -0,0 +1,304 @@
>>>> +/*
>>>> + * QEMU PowerPC PowerNV machine model
>>>> + *
>>>> + * Native version of ICS/ICP
>>>> + *
>>>> + * Copyright (c) 2016, IBM Corporation.
>>>> + *
>>>> + * This library is free software; you can redistribute it and/or
>>>> + * modify it under the terms of the GNU Lesser General Public
>>>> + * License as published by the Free Software Foundation; either
>>>> + * version 2 of the License, or (at your option) any later version.
>>>> + *
>>>> + * This library is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> + * Lesser General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU Lesser General Public
>>>> + * License along with this library; if not, see 
>>>> <http://www.gnu.org/licenses/>.
>>>> + */
>>>> +
>>>> +#include "qemu/osdep.h"
>>>> +#include "qapi/error.h"
>>>> +#include "qemu-common.h"
>>>> +#include "cpu.h"
>>>> +#include "hw/hw.h"
>>>> +#include "qemu/log.h"
>>>> +#include "qapi/error.h"
>>>> +
>>>> +#include "hw/ppc/fdt.h"
>>>> +#include "hw/ppc/xics.h"
>>>> +#include "hw/ppc/pnv.h"
>>>> +
>>>> +#include <libfdt.h>
>>>> +
>>>> +static void xics_native_reset(void *opaque)
>>>> +{
>>>> +    device_reset(DEVICE(opaque));
>>>> +}
>>>> +
>>>> +static void xics_native_initfn(Object *obj)
>>>> +{
>>>> +    qemu_register_reset(xics_native_reset, obj);
>>>> +}
>>>
>>> I think we need to investigate why the xics native is not showing up
>>> on the SysBus.  As a "raw" MMIO device, it really should. 
>>
>> Well, it has sysbus mmio region, but it is not created with qdev_create(...) 
>> so it is not under sysbus and the reset does not get called. That is my
>> understanding of the problem.
>>
>> May be we shouldn't be using a sysbus mmio region ?  
> 
> Yeah, maybe not.  We don't really fit the sysbus model well.
> 
> I do kind of wonder if the xics object should be an mmio device at
> all, or if just the individual ICPs should be.  But that might make
> for more trouble.

A cleanup brings another :) It is true that xics native does not
have any controls. It is just a container to hold the array of ICPs 
and so each of these could well be a child object of PnvCore. Well,
of a PnvThread but we don't have that today. 

I am going to move the container region to PnvChip to start with and 
if I can the ICP regions to PnvCore. When we realize the PnvCore, we 
have the xics, but I need to find a way to grab the ICPState from it. 
I might need to use the cpu_index for that or could I change 
xics_cpu_setup() to return an 'ICPState *' ? 

I would prefer the ICP to be a PnvCore/Thread child object but that
is too early I think.

So if that comes well together, we will get rid of XICSNative and we 
will use a XICSState for its ICP array. 

>>> If it was, device_reset should be called without these shenannigans.
>>
>> yes.
>>
>>
>>>> +
>>>> +static uint64_t xics_native_read(void *opaque, hwaddr addr, unsigned 
>>>> width)
>>>> +{
>>>> +    ICPState *icp = opaque;
>>>> +    bool byte0 = (width == 1 && (addr & 0x3) == 0);
>>>> +    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 xics_native_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 xics_native_ops = {
>>>> +    .read = xics_native_read,
>>>> +    .write = xics_native_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 uint64_t xics_native_default_read(void *opaque, hwaddr addr,
>>>> +                                         unsigned width)
>>>> +{
>>>> +    qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
>>>> +                  HWADDR_PRIx"/%d\n", addr, width);
>>>> +    return 0xffffffffffffffffull;
>>>> +}
>>>> +
>>>> +static void xics_native_default_write(void *opaque, hwaddr addr, uint64_t 
>>>> val,
>>>> +                                      unsigned width)
>>>> +{
>>>> +    qemu_log_mask(LOG_GUEST_ERROR, "XICS: Bad ICP access 0x%"
>>>> +                  HWADDR_PRIx"/%d\n", addr, width);
>>>> +}
>>>> +
>>>> +static const MemoryRegionOps xics_native_default_ops = {
>>>> +    .read = xics_native_default_read,
>>>> +    .write = xics_native_default_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 xics_native_set_nr_servers(XICSState *xics, uint32_t 
>>>> nr_servers,
>>>> +                                       Error **errp)
>>>> +{
>>>> +    xics_set_nr_servers(xics, nr_servers, TYPE_ICP, errp);
>>>> +}
>>>> +
>>>> +static void xics_native_realize(DeviceState *dev, Error **errp)
>>>> +{
>>>> +    XICSState *xics = XICS_COMMON(dev);
>>>> +    XICSNative *xicsn = XICS_NATIVE(dev);
>>>> +    Error *error = NULL;
>>>> +    int i;
>>>> +
>>>> +    if (!xics->nr_servers) {
>>>> +        error_setg(errp, "Number of servers needs to be greater than 0");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    for (i = 0; i < xics->nr_servers; i++) {
>>>> +        object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized",
>>>> +                                 &error);
>>>> +        if (error) {
>>>> +            error_propagate(errp, error);
>>>> +            return;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /*
>>>> +     * Initialize the container region for the ICPs and the subregion
>>>> +     * for each cpu. The mmapping will be done at the board level
>>>> +     * depending on the pir of the core.
>>>> +     *
>>>> +     * TODO: build a name with the chip id
>>>> +     */
>>>> +    memory_region_init_io(&xicsn->icp_mmio, OBJECT(dev),
>>>> +                          &xics_native_default_ops, xicsn, "icp-0",
>>>> +                          PNV_XICS_SIZE);
>>>
>>> I don't think you should need these native ops.  I believe you can
>>> construct a memory region as a "pure" container, then just put the
>>> populated regions inside it.
>>
>> It is a way to track bogus read/writes the guest shouldn't be doing
>> but it is not that important. I can remove it.
> 
> Right.  I don't recall exactly what will happen if you don't populate
> this at all, but I think you should eventually arrive at the global
> fallback handler which should give you a similar effect.
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]