qemu-ppc
[Top][All Lists]
Advanced

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

Re: [Qemu-ppc] [PATCH v6 06/37] ppc/xive: add support for the END Event


From: Cédric Le Goater
Subject: Re: [Qemu-ppc] [PATCH v6 06/37] ppc/xive: add support for the END Event State buffers
Date: Thu, 6 Dec 2018 07:30:34 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.3.0

On 12/6/18 5:09 AM, David Gibson wrote:
> On Thu, Dec 06, 2018 at 12:22:20AM +0100, Cédric Le Goater wrote:
>> The Event Notification Descriptor (END) XIVE structure also contains
>> two Event State Buffers providing further coalescing of interrupts,
>> one for the notification event (ESn) and one for the escalation events
>> (ESe). A MMIO page is assigned for each to control the EOI through
>> loads only. Stores are not allowed.
>>
>> The END ESBs are modeled through an object resembling the 'XiveSource'
>> It is stateless as the END state bits are backed into the XiveEND
>> structure under the XiveRouter and the MMIO accesses follow the same
>> rules as for the standard source ESBs.
>>
>> END ESBs are not supported by the Linux drivers neither on OPAL nor on
>> sPAPR. Nevetherless, it provides a mean to study the question in the
>> future and validates a bit more the XIVE model.
>>
>> Signed-off-by: Cédric Le Goater <address@hidden>
>> ---
>>  include/hw/ppc/xive.h |  22 ++++++
>>  hw/intc/xive.c        | 173 +++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 193 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
>> index d1b4c6c78ec5..d67b0785df7c 100644
>> --- a/include/hw/ppc/xive.h
>> +++ b/include/hw/ppc/xive.h
>> @@ -305,6 +305,8 @@ static inline void xive_source_irq_set(XiveSource *xsrc, 
>> uint32_t srcno,
>>  
>>  typedef struct XiveRouter {
>>      SysBusDevice    parent;
>> +
>> +    uint32_t       chip_id;
> 
> I still don't think you need this..

I know :) 

> 
>>  } XiveRouter;
>>  
>>  #define TYPE_XIVE_ROUTER "xive-router"
>> @@ -336,6 +338,26 @@ int xive_router_get_end(XiveRouter *xrtr, uint8_t 
>> end_blk, uint32_t end_idx,
>>  int xive_router_write_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t 
>> end_idx,
>>                            XiveEND *end, uint8_t word_number);
>>  
>> +/*
>> + * XIVE END ESBs
>> + */
>> +
>> +#define TYPE_XIVE_END_SOURCE "xive-end-source"
>> +#define XIVE_END_SOURCE(obj) \
>> +    OBJECT_CHECK(XiveENDSource, (obj), TYPE_XIVE_END_SOURCE)
>> +
>> +typedef struct XiveENDSource {
>> +    DeviceState parent;
>> +
>> +    uint32_t        nr_ends;
>> +
>> +    /* ESB memory region */
>> +    uint32_t        esb_shift;
>> +    MemoryRegion    esb_mmio;
>> +
>> +    XiveRouter      *xrtr;
> 
> ..or this..
> 
>> +} XiveENDSource;
>> +
>>  /*
>>   * For legacy compatibility, the exceptions define up to 256 different
>>   * priorities. P9 implements only 9 levels : 8 active levels [0 - 7]
>> diff --git a/hw/intc/xive.c b/hw/intc/xive.c
>> index 41d8ba1540d0..83686e260df5 100644
>> --- a/hw/intc/xive.c
>> +++ b/hw/intc/xive.c
>> @@ -612,8 +612,18 @@ static void xive_router_end_notify(XiveRouter *xrtr, 
>> uint8_t end_blk,
>>       * even futher coalescing in the Router
>>       */
>>      if (!xive_end_is_notify(&end)) {
>> -        qemu_log_mask(LOG_UNIMP, "XIVE: !UCOND_NOTIFY not implemented\n");
>> -        return;
>> +        uint8_t pq = GETFIELD_BE32(END_W1_ESn, end.w1);
>> +        bool notify = xive_esb_trigger(&pq);
>> +
>> +        if (pq != GETFIELD_BE32(END_W1_ESn, end.w1)) {
>> +            end.w1 = SETFIELD_BE32(END_W1_ESn, end.w1, pq);
>> +            xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
>> +        }
>> +
>> +        /* ESn[Q]=1 : end of notification */
>> +        if (!notify) {
>> +            return;
>> +        }
>>      }
>>  
>>      /*
>> @@ -658,12 +668,18 @@ static void xive_router_notify(XiveNotifier *xn, 
>> uint32_t lisn)
>>                             GETFIELD_BE64(EAS_END_DATA,  eas.w));
>>  }
>>  
>> +static Property xive_router_properties[] = {
>> +    DEFINE_PROP_UINT32("chip-id", XiveRouter, chip_id, 0),
>> +    DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>>  static void xive_router_class_init(ObjectClass *klass, void *data)
>>  {
>>      DeviceClass *dc = DEVICE_CLASS(klass);
>>      XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
>>  
>>      dc->desc    = "XIVE Router Engine";
>> +    dc->props   = xive_router_properties;
>>      xnc->notify = xive_router_notify;
>>  }
>>  
>> @@ -692,6 +708,158 @@ void xive_eas_pic_print_info(XiveEAS *eas, uint32_t 
>> lisn, Monitor *mon)
>>                     (uint32_t) GETFIELD_BE64(EAS_END_DATA, eas->w));
>>  }
>>  
>> +/*
>> + * END ESB MMIO loads
>> + */
>> +static uint64_t xive_end_source_read(void *opaque, hwaddr addr, unsigned 
>> size)
>> +{
>> +    XiveENDSource *xsrc = XIVE_END_SOURCE(opaque);
>> +    XiveRouter *xrtr = xsrc->xrtr;
>> +    uint32_t offset = addr & 0xFFF;
>> +    uint8_t end_blk;
>> +    uint32_t end_idx;
>> +    XiveEND end;
>> +    uint32_t end_esmask;
>> +    uint8_t pq;
>> +    uint64_t ret = -1;
>> +
>> +    end_blk = xrtr->chip_id;
> 
> .. instead I think it makes more sense to just configure the end_blk
> directly on the end_source, rather than reaching into another object
> to 

Ah. That's what I was asking in an email. I missed the answer maybe.
Let's drop it and sPAPRXive block will be 0. 

> 
>> +    end_idx = addr >> (xsrc->esb_shift + 1);
>> +
>> +    if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) {
>> +        qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No END %x/%x\n", end_blk,
>> +                      end_idx);
>> +        return -1;
>> +    }
>> +
>> +    if (!xive_end_is_valid(&end)) {
>> +        qemu_log_mask(LOG_GUEST_ERROR, "XIVE: END %x/%x is invalid\n",
>> +                      end_blk, end_idx);
>> +        return -1;
>> +    }
>> +
>> +    end_esmask = addr_is_even(addr, xsrc->esb_shift) ? END_W1_ESn : 
>> END_W1_ESe;
>> +    pq = GETFIELD_BE32(end_esmask, end.w1);
>> +
>> +    switch (offset) {
>> +    case XIVE_ESB_LOAD_EOI ... XIVE_ESB_LOAD_EOI + 0x7FF:
>> +        ret = xive_esb_eoi(&pq);
>> +
>> +        /* Forward the source event notification for routing ?? */
>> +        break;
>> +
>> +    case XIVE_ESB_GET ... XIVE_ESB_GET + 0x3FF:
>> +        ret = pq;
>> +        break;
>> +
>> +    case XIVE_ESB_SET_PQ_00 ... XIVE_ESB_SET_PQ_00 + 0x0FF:
>> +    case XIVE_ESB_SET_PQ_01 ... XIVE_ESB_SET_PQ_01 + 0x0FF:
>> +    case XIVE_ESB_SET_PQ_10 ... XIVE_ESB_SET_PQ_10 + 0x0FF:
>> +    case XIVE_ESB_SET_PQ_11 ... XIVE_ESB_SET_PQ_11 + 0x0FF:
>> +        ret = xive_esb_set(&pq, (offset >> 8) & 0x3);
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid END ESB load addr 
>> %d\n",
>> +                      offset);
>> +        return -1;
>> +    }
>> +
>> +    if (pq != GETFIELD_BE32(end_esmask, end.w1)) {
>> +        end.w1 = SETFIELD_BE32(end_esmask, end.w1, pq);
>> +        xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +/*
>> + * END ESB MMIO stores are invalid
>> + */
>> +static void xive_end_source_write(void *opaque, hwaddr addr,
>> +                                  uint64_t value, unsigned size)
>> +{
>> +    qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid ESB write addr 0x%"
>> +                  HWADDR_PRIx"\n", addr);
>> +}
>> +
>> +static const MemoryRegionOps xive_end_source_ops = {
>> +    .read = xive_end_source_read,
>> +    .write = xive_end_source_write,
>> +    .endianness = DEVICE_BIG_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 8,
>> +        .max_access_size = 8,
>> +    },
>> +    .impl = {
>> +        .min_access_size = 8,
>> +        .max_access_size = 8,
>> +    },
>> +};
>> +
>> +static void xive_source_end_reset(void *dev)
>> +{
>> +    /* TODO: Loop on all ENDs and mask off the ESn and ESe */
> 
> IIUC you're talking about actually writing the (potentially in memory)
> END structures.  I don't think that makes sense for the END source
> hardware model.  I'm guessing you want this for PAPR, where the ENDs
> are in virtual hardware 

That's done already.

> rather than guest memory, but in that case I
> think the reset handling should be in the PAPR specific Xive object,
> not the end_source itself.

I will remove the TODO, it's obsolete.

Thanks,

C.
 
> 
>> +}
>> +
>> +static void xive_end_source_realize(DeviceState *dev, Error **errp)
>> +{
>> +    XiveENDSource *xsrc = XIVE_END_SOURCE(dev);
>> +    Object *obj;
>> +    Error *local_err = NULL;
>> +
>> +    obj = object_property_get_link(OBJECT(dev), "xive", &local_err);
>> +    if (!obj) {
>> +        error_propagate(errp, local_err);
>> +        error_prepend(errp, "required link 'xive' not found: ");
>> +        return;
>> +    }
>> +
>> +    xsrc->xrtr = XIVE_ROUTER(obj);
>> +
>> +    if (!xsrc->nr_ends) {
>> +        error_setg(errp, "Number of interrupt needs to be greater than 0");
>> +        return;
>> +    }
>> +
>> +    if (xsrc->esb_shift != XIVE_ESB_4K &&
>> +        xsrc->esb_shift != XIVE_ESB_64K) {
>> +        error_setg(errp, "Invalid ESB shift setting");
>> +        return;
>> +    }
>> +
>> +    /*
>> +     * Each END is assigned an even/odd pair of MMIO pages, the even page
>> +     * manages the ESn field while the odd page manages the ESe field.
>> +     */
>> +    memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc),
>> +                          &xive_end_source_ops, xsrc, "xive.end",
>> +                          (1ull << (xsrc->esb_shift + 1)) * xsrc->nr_ends);
>> +
>> +    qemu_register_reset(xive_source_end_reset, dev);
>> +}
>> +
>> +static Property xive_end_source_properties[] = {
>> +    DEFINE_PROP_UINT32("nr-ends", XiveENDSource, nr_ends, 0),
>> +    DEFINE_PROP_UINT32("shift", XiveENDSource, esb_shift, XIVE_ESB_64K),
>> +    DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void xive_end_source_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->desc    = "XIVE END Source";
>> +    dc->props   = xive_end_source_properties;
>> +    dc->realize = xive_end_source_realize;
>> +}
>> +
>> +static const TypeInfo xive_end_source_info = {
>> +    .name          = TYPE_XIVE_END_SOURCE,
>> +    .parent        = TYPE_DEVICE,
>> +    .instance_size = sizeof(XiveENDSource),
>> +    .class_init    = xive_end_source_class_init,
>> +};
>> +
>>  /*
>>   * XIVE Fabric
>>   */
>> @@ -706,6 +874,7 @@ static void xive_register_types(void)
>>      type_register_static(&xive_source_info);
>>      type_register_static(&xive_fabric_info);
>>      type_register_static(&xive_router_info);
>> +    type_register_static(&xive_end_source_info);
>>  }
>>  
>>  type_init(xive_register_types)
> 




reply via email to

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