[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-ppc] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt p
From: |
Cédric Le Goater |
Subject: |
Re: [Qemu-ppc] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model |
Date: |
Thu, 26 Apr 2018 11:27:21 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.2 |
On 04/26/2018 09:11 AM, David Gibson wrote:
> On Thu, Apr 19, 2018 at 02:43:02PM +0200, Cédric Le Goater wrote:
>> The XIVE presenter engine uses a set of registers to handle priority
>> management and interrupt acknowledgment among other things. The most
>> important ones being :
>>
>> - Interrupt Priority Register (PIPR)
>> - Interrupt Pending Buffer (IPB)
>> - Current Processor Priority (CPPR)
>> - Notification Source Register (NSR)
>>
>> There is one set of registers per level of privilege, four in all :
>> HW, HV pool, OS and User. These are called rings. All registers are
>> accessible through a specific MMIO region called the Thread Interrupt
>> Management Areas (TIMA) but, depending on the privilege level of the
>> CPU, the view of the TIMA is filtered. The sPAPR machine runs at the
>> OS privilege and therefore can only accesses the OS and the User
>> rings. The others are for hypervisor levels.
>>
>> The CPU interrupt state is modeled with a XiveNVT object which stores
>> the values of the different registers. The different TIMA views are
>> mapped at the same address for each CPU and 'current_cpu' is used to
>> retrieve the XiveNVT holding the ring registers.
>>
>> Signed-off-by: Cédric Le Goater <address@hidden>
>> ---
>>
>> Changes since v2 :
>>
>> - introduced the XiveFabric interface
>>
>> hw/intc/spapr_xive.c | 25 ++++
>> hw/intc/xive.c | 279
>> ++++++++++++++++++++++++++++++++++++++++++++
>> include/hw/ppc/spapr_xive.h | 5 +
>> include/hw/ppc/xive.h | 31 +++++
>> include/hw/ppc/xive_regs.h | 84 +++++++++++++
>> 5 files changed, 424 insertions(+)
>>
>> diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
>> index 90cde8a4082d..f07832bf0a00 100644
>> --- a/hw/intc/spapr_xive.c
>> +++ b/hw/intc/spapr_xive.c
>> @@ -13,6 +13,7 @@
>> #include "target/ppc/cpu.h"
>> #include "sysemu/cpus.h"
>> #include "monitor/monitor.h"
>> +#include "hw/ppc/spapr.h"
>> #include "hw/ppc/spapr_xive.h"
>> #include "hw/ppc/xive.h"
>> #include "hw/ppc/xive_regs.h"
>> @@ -95,6 +96,22 @@ static void spapr_xive_realize(DeviceState *dev, Error
>> **errp)
>>
>> /* Allocate the Interrupt Virtualization Table */
>> xive->ivt = g_new0(XiveIVE, xive->nr_irqs);
>> +
>> + /* The Thread Interrupt Management Area has the same address for
>> + * each chip. On sPAPR, we only need to expose the User and OS
>> + * level views of the TIMA.
>> + */
>> + xive->tm_base = XIVE_TM_BASE;
>
> The constant should probably have PAPR in the name somewhere, since
> it's just for PAPR machines (same for the ESB mappings, actually).
ok.
I have also made 'tm_base' a property, like 'vc_base' for ESBs, in
case we want to change the value when the guest is instantiated.
I doubt it but this is an address in the global address space, so
letting the machine have control is better I think.
>
>> +
>> + memory_region_init_io(&xive->tm_mmio_user, OBJECT(xive),
>> + &xive_tm_user_ops, xive, "xive.tima.user",
>> + 1ull << TM_SHIFT);
>> + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xive->tm_mmio_user);
>> +
>> + memory_region_init_io(&xive->tm_mmio_os, OBJECT(xive),
>> + &xive_tm_os_ops, xive, "xive.tima.os",
>> + 1ull << TM_SHIFT);
>> + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &xive->tm_mmio_os);
>> }
>>
>> static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn)
>> @@ -104,6 +121,13 @@ static XiveIVE *spapr_xive_get_ive(XiveFabric *xf,
>> uint32_t lisn)
>> return lisn < xive->nr_irqs ? &xive->ivt[lisn] : NULL;
>> }
>>
>> +static XiveNVT *spapr_xive_get_nvt(XiveFabric *xf, uint32_t server)
>> +{
>> + PowerPCCPU *cpu = spapr_find_cpu(server);
>> +
>> + return cpu ? XIVE_NVT(cpu->intc) : NULL;
>> +}
>
> So this is a bit of a tangent, but I've been thinking of implementing
> a scheme where there's an opaque pointer in the cpu structure for the
> use of the machine. I'm planning for that to replace the intc pointer
> (which isn't really used directly by the cpu). That would allow us to
> have spapr put a structure there and have both xics and xive pointers
> which could be useful later on.
ok. That should simplify the patchset at the end, in which we need to
switch the 'intc' pointer.
> I think we'd need something similar to correctly handle migration of
> the VPA state, which is currently horribly broken.
>
>> +
>> static const VMStateDescription vmstate_spapr_xive_ive = {
>> .name = TYPE_SPAPR_XIVE "/ive",
>> .version_id = 1,
>> @@ -143,6 +167,7 @@ static void spapr_xive_class_init(ObjectClass *klass,
>> void *data)
>> dc->vmsd = &vmstate_spapr_xive;
>>
>> xfc->get_ive = spapr_xive_get_ive;
>> + xfc->get_nvt = spapr_xive_get_nvt;
>> }
>>
>> static const TypeInfo spapr_xive_info = {
>> diff --git a/hw/intc/xive.c b/hw/intc/xive.c
>> index dccad0318834..5691bb9474e4 100644
>> --- a/hw/intc/xive.c
>> +++ b/hw/intc/xive.c
>> @@ -14,7 +14,278 @@
>> #include "sysemu/cpus.h"
>> #include "sysemu/dma.h"
>> #include "monitor/monitor.h"
>> +#include "hw/ppc/xics.h" /* for ICP_PROP_CPU */
>> #include "hw/ppc/xive.h"
>> +#include "hw/ppc/xive_regs.h"
>> +
>> +/*
>> + * XIVE Interrupt Presenter
>> + */
>> +
>> +static uint64_t xive_nvt_accept(XiveNVT *nvt)
>> +{
>> + return 0;
>> +}
>> +
>> +static void xive_nvt_set_cppr(XiveNVT *nvt, uint8_t cppr)
>> +{
>> + if (cppr > XIVE_PRIORITY_MAX) {
>> + cppr = 0xff;
>> + }
>> +
>> + nvt->ring_os[TM_CPPR] = cppr;
>
> Surely this needs to recheck if we should be interrupting the cpu?
yes. In patch 9, when we introduce the nvt notify routine.
>> +}
>> +
>> +/*
>> + * OS Thread Interrupt Management Area MMIO
>> + */
>> +static uint64_t xive_tm_read_special(XiveNVT *nvt, hwaddr offset,
>> + unsigned size)
>> +{
>> + uint64_t ret = -1;
>> +
>> + if (offset == TM_SPC_ACK_OS_REG && size == 2) {
>> + ret = xive_nvt_accept(nvt);
>> + } else {
>> + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid TIMA read @%"
>> + HWADDR_PRIx" size %d\n", offset, size);
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +#define TM_RING(offset) ((offset) & 0xf0)
>> +
>> +static uint64_t xive_tm_os_read(void *opaque, hwaddr offset,
>> + unsigned size)
>> +{
>> + PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
>
> So, as I said on a previous version of this, we can actually correctly
> represent different mappings in different cpu spaces, by exploiting
> cpu->as and not just having them all point to &address_space_memory.
Yes, you did and I haven't studied the question yet. For the next version.
>> + XiveNVT *nvt = XIVE_NVT(cpu->intc);
>> + uint64_t ret = -1;
>> + int i;
>> +
>> + if (offset >= TM_SPC_ACK_EBB) {
>> + return xive_tm_read_special(nvt, offset, size);
>> + }
>> +
>> + if (TM_RING(offset) != TM_QW1_OS) {
>> + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid access to non-OS ring
>> @%"
>> + HWADDR_PRIx"\n", offset);
>> + return ret;
>
> Just return -1 would be clearer here;
ok.
>
>> + }
>> +
>> + ret = 0;
>> + for (i = 0; i < size; i++) {
>> + ret |= (uint64_t) nvt->regs[offset + i] << (8 * (size - i - 1));
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static bool xive_tm_is_readonly(uint8_t offset)
>> +{
>> + return offset != TM_QW1_OS + TM_CPPR;
>> +}
>> +
>> +static void xive_tm_write_special(XiveNVT *nvt, hwaddr offset,
>> + uint64_t value, unsigned size)
>> +{
>> + /* TODO: support TM_SPC_SET_OS_PENDING */
>> +
>> + /* TODO: support TM_SPC_ACK_OS_EL */
>> +}
>> +
>> +static void xive_tm_os_write(void *opaque, hwaddr offset,
>> + uint64_t value, unsigned size)
>> +{
>> + PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
>> + XiveNVT *nvt = XIVE_NVT(cpu->intc);
>> + int i;
>> +
>> + if (offset >= TM_SPC_ACK_EBB) {
>> + xive_tm_write_special(nvt, offset, value, size);
>> + return;
>> + }
>> +
>> + if (TM_RING(offset) != TM_QW1_OS) {
>
> Why have this if you have separate OS and user regions as you appear
> to do below?
This is another problem we are trying to solve.
The registers a CPU can access depends on the TIMA view it is using.
The OS TIMA view only sees the OS ring registers. The HV view sees all.
> Or to look at it another way, shouldn't it be possible to make the
> read/write accessors the same for the OS and user rings?
For some parts yes, but the special load/store addresses are different
for each view, the read-only register also. It seemed easier to duplicate.
I think the problem will become clearer (or worse) with pnv which uses
the HV mode.
>> + qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid access to non-OS ring
>> @%"
>> + HWADDR_PRIx"\n", offset);
>> + return;
>> + }
>> +
>> + switch (size) {
>> + case 1:
>> + if (offset == TM_QW1_OS + TM_CPPR) {
>> + xive_nvt_set_cppr(nvt, value & 0xff);
>> + }
>> + break;
>> + case 4:
>> + case 8:
>> + for (i = 0; i < size; i++) {
>> + if (!xive_tm_is_readonly(offset + i)) {
>> + nvt->regs[offset + i] = (value >> (8 * (size - i - 1))) &
>> 0xff;
>> + }
>> + }
>> + break;
>> + default:
>> + g_assert_not_reached();
>> + }
>> +}
>> +
>> +const MemoryRegionOps xive_tm_os_ops = {
>> + .read = xive_tm_os_read,
>> + .write = xive_tm_os_write,
>> + .endianness = DEVICE_BIG_ENDIAN,
>> + .valid = {
>> + .min_access_size = 1,
>> + .max_access_size = 8,
>> + },
>> + .impl = {
>> + .min_access_size = 1,
>> + .max_access_size = 8,
>> + },
>> +};
>> +
>> +/*
>> + * User Thread Interrupt Management Area MMIO
>> + */
>> +
>> +static uint64_t xive_tm_user_read(void *opaque, hwaddr offset,
>> + unsigned size)
>> +{
>> + qemu_log_mask(LOG_UNIMP, "XIVE: invalid access to User TIMA @%"
>> + HWADDR_PRIx"\n", offset);
>> + return -1;
>> +}
>> +
>> +static void xive_tm_user_write(void *opaque, hwaddr offset,
>> + uint64_t value, unsigned size)
>> +{
>> + qemu_log_mask(LOG_UNIMP, "XIVE: invalid access to User TIMA @%"
>> + HWADDR_PRIx"\n", offset);
>> +}
>> +
>> +
>> +const MemoryRegionOps xive_tm_user_ops = {
>> + .read = xive_tm_user_read,
>> + .write = xive_tm_user_write,
>> + .endianness = DEVICE_BIG_ENDIAN,
>> + .valid = {
>> + .min_access_size = 1,
>> + .max_access_size = 8,
>> + },
>> + .impl = {
>> + .min_access_size = 1,
>> + .max_access_size = 8,
>> + },
>> +};
>> +
>> +static char *xive_nvt_ring_print(uint8_t *ring)
>> +{
>> + uint32_t w2 = be32_to_cpu(*((uint32_t *) &ring[TM_WORD2]));
>> +
>> + return g_strdup_printf("%02x %02x %02x %02x %02x "
>> + "%02x %02x %02x %08x",
>> + ring[TM_NSR], ring[TM_CPPR], ring[TM_IPB],
>> ring[TM_LSMFB],
>> + ring[TM_ACK_CNT], ring[TM_INC], ring[TM_AGE],
>> ring[TM_PIPR],
>> + w2);
>> +}
>> +
>> +void xive_nvt_pic_print_info(XiveNVT *nvt, Monitor *mon)
>> +{
>> + int cpu_index = nvt->cs ? nvt->cs->cpu_index : -1;
>> + char *s;
>> +
>> + monitor_printf(mon, "CPU[%04x]: QW NSR CPPR IPB LSMFB ACK# INC AGE
>> PIPR"
>> + " W2\n", cpu_index);
>> +
>> + s = xive_nvt_ring_print(&nvt->regs[TM_QW1_OS]);
>> + monitor_printf(mon, "CPU[%04x]: OS %s\n", cpu_index, s);
>> + g_free(s);
>> + s = xive_nvt_ring_print(&nvt->regs[TM_QW0_USER]);
>> + monitor_printf(mon, "CPU[%04x]: USER %s\n", cpu_index, s);
>> + g_free(s);
>> +}
>> +
>> +static void xive_nvt_reset(void *dev)
>> +{
>> + XiveNVT *nvt = XIVE_NVT(dev);
>> +
>> + memset(nvt->regs, 0, sizeof(nvt->regs));
>> +}
>> +
>> +static void xive_nvt_realize(DeviceState *dev, Error **errp)
>> +{
>> + XiveNVT *nvt = XIVE_NVT(dev);
>> + PowerPCCPU *cpu;
>> + CPUPPCState *env;
>> + Object *obj;
>> + Error *err = NULL;
>> +
>> + obj = object_property_get_link(OBJECT(dev), ICP_PROP_CPU, &err);
>
> Please get rid of the remaining "ICP" naming in the xive code.
ok. I will kill the define.
>> + if (!obj) {
>> + error_propagate(errp, err);
>> + error_prepend(errp, "required link '" ICP_PROP_CPU "' not found: ");
>> + return;
>> + }
>> +
>> + cpu = POWERPC_CPU(obj);
>> + nvt->cs = CPU(obj);
>> +
>> + env = &cpu->env;
>> + switch (PPC_INPUT(env)) {
>> + case PPC_FLAGS_INPUT_POWER7:
>> + nvt->output = env->irq_inputs[POWER7_INPUT_INT];
>> + break;
>> +
>> + default:
>> + error_setg(errp, "XIVE interrupt controller does not support "
>> + "this CPU bus model");
>> + return;
>> + }
>> +
>> + qemu_register_reset(xive_nvt_reset, dev);
>
> If this is a sysbus device, which I think it is,
It is not. The TIMA MMIO region is in the sPAPRXive model but that might
change if we use cpu->as. I agree it would look better to have a memory
region per cpu.
> you shouldn't need to
> explicitly register a reset handler. Instead you can set a device
> reset handler which will be called with the reset.
>
>> +}
>> +
>> +static void xive_nvt_unrealize(DeviceState *dev, Error **errp)
>> +{
>> + qemu_unregister_reset(xive_nvt_reset, dev);
>> +}
>> +
>> +static void xive_nvt_init(Object *obj)
>> +{
>> + XiveNVT *nvt = XIVE_NVT(obj);
>> +
>> + nvt->ring_os = &nvt->regs[TM_QW1_OS];
>
> The ring_os field is basically pointless, being just an offset into a
> structure you already have. A macro or inline would be a better idea.
ok. I liked the idea but I agree it's overkill to have an init routine
just for this. I will find something.
>> +}
>> +
>> +static const VMStateDescription vmstate_xive_nvt = {
>> + .name = TYPE_XIVE_NVT,
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_BUFFER(regs, XiveNVT),
>> + VMSTATE_END_OF_LIST()
>> + },
>> +};
>> +
>> +static void xive_nvt_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + dc->realize = xive_nvt_realize;
>> + dc->unrealize = xive_nvt_unrealize;
>> + dc->desc = "XIVE Interrupt Presenter";
>> + dc->vmsd = &vmstate_xive_nvt;
>> +}
>> +
>> +static const TypeInfo xive_nvt_info = {
>> + .name = TYPE_XIVE_NVT,
>> + .parent = TYPE_DEVICE,
>> + .instance_size = sizeof(XiveNVT),
>> + .instance_init = xive_nvt_init,
>> + .class_init = xive_nvt_class_init,
>> +};
>>
>> /*
>> * XIVE Fabric
>> @@ -27,6 +298,13 @@ XiveIVE *xive_fabric_get_ive(XiveFabric *xf, uint32_t
>> lisn)
>> return xfc->get_ive(xf, lisn);
>> }
>>
>> +XiveNVT *xive_fabric_get_nvt(XiveFabric *xf, uint32_t server)
>> +{
>> + XiveFabricClass *xfc = XIVE_FABRIC_GET_CLASS(xf);
>> +
>> + return xfc->get_nvt(xf, server);
>> +}
>> +
>> static void xive_fabric_route(XiveFabric *xf, int lisn)
>> {
>>
>> @@ -418,6 +696,7 @@ static void xive_register_types(void)
>> {
>> type_register_static(&xive_source_info);
>> type_register_static(&xive_fabric_info);
>> + type_register_static(&xive_nvt_info);
>> }
>>
>> type_init(xive_register_types)
>> diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h
>> index 4538c622b60a..25d78eec884d 100644
>> --- a/include/hw/ppc/spapr_xive.h
>> +++ b/include/hw/ppc/spapr_xive.h
>> @@ -25,6 +25,11 @@ typedef struct sPAPRXive {
>> /* Routing table */
>> XiveIVE *ivt;
>> uint32_t nr_irqs;
>> +
>> + /* TIMA memory regions */
>> + hwaddr tm_base;
>> + MemoryRegion tm_mmio_user;
>> + MemoryRegion tm_mmio_os;
>> } sPAPRXive;
>>
>> bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi);
>> diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
>> index 57295715a4a5..1a2da610d91c 100644
>> --- a/include/hw/ppc/xive.h
>> +++ b/include/hw/ppc/xive.h
>> @@ -20,6 +20,7 @@ typedef struct XiveFabric XiveFabric;
>> */
>>
>> #define XIVE_VC_BASE 0x0006010000000000ull
>> +#define XIVE_TM_BASE 0x0006030203180000ull
>>
>> /*
>> * XIVE Interrupt Source
>> @@ -155,6 +156,34 @@ static inline void xive_source_irq_set(XiveSource
>> *xsrc, uint32_t srcno,
>> }
>>
>> /*
>> + * XIVE Interrupt Presenter
>> + */
>> +
>> +#define TYPE_XIVE_NVT "xive-nvt"
>> +#define XIVE_NVT(obj) OBJECT_CHECK(XiveNVT, (obj), TYPE_XIVE_NVT)
>> +
>> +#define TM_RING_COUNT 4
>> +#define TM_RING_SIZE 0x10
>> +
>> +typedef struct XiveNVT {
>> + DeviceState parent_obj;
>> +
>> + CPUState *cs;
>> + qemu_irq output;
>> +
>> + /* Thread interrupt Management (TM) registers */
>> + uint8_t regs[TM_RING_COUNT * TM_RING_SIZE];
>> +
>> + /* Shortcuts to rings */
>> + uint8_t *ring_os;
>> +} XiveNVT;
>> +
>> +extern const MemoryRegionOps xive_tm_user_ops;
>> +extern const MemoryRegionOps xive_tm_os_ops;
>> +
>> +void xive_nvt_pic_print_info(XiveNVT *nvt, Monitor *mon);
>> +
>> +/*
>> * XIVE Fabric
>> */
>>
>> @@ -175,8 +204,10 @@ typedef struct XiveFabricClass {
>> void (*notify)(XiveFabric *xf, uint32_t lisn);
>>
>> XiveIVE *(*get_ive)(XiveFabric *xf, uint32_t lisn);
>> + XiveNVT *(*get_nvt)(XiveFabric *xf, uint32_t server);
>> } XiveFabricClass;
>>
>> XiveIVE *xive_fabric_get_ive(XiveFabric *xf, uint32_t lisn);
>> +XiveNVT *xive_fabric_get_nvt(XiveFabric *xf, uint32_t server);
>>
>> #endif /* PPC_XIVE_H */
>> diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h
>> index 5903f29eb789..f2e2a1ac8f6e 100644
>> --- a/include/hw/ppc/xive_regs.h
>> +++ b/include/hw/ppc/xive_regs.h
>> @@ -10,6 +10,88 @@
>> #ifndef _PPC_XIVE_REGS_H
>> #define _PPC_XIVE_REGS_H
>>
>> +#define TM_SHIFT 16
>> +
>> +/* TM register offsets */
>> +#define TM_QW0_USER 0x000 /* All rings */
>> +#define TM_QW1_OS 0x010 /* Ring 0..2 */
>> +#define TM_QW2_HV_POOL 0x020 /* Ring 0..1 */
>> +#define TM_QW3_HV_PHYS 0x030 /* Ring 0..1 */
>> +
>> +/* Byte offsets inside a QW QW0 QW1 QW2 QW3 */
>> +#define TM_NSR 0x0 /* + + - + */
>> +#define TM_CPPR 0x1 /* - + - + */
>> +#define TM_IPB 0x2 /* - + + + */
>> +#define TM_LSMFB 0x3 /* - + + + */
>> +#define TM_ACK_CNT 0x4 /* - + - - */
>> +#define TM_INC 0x5 /* - + - + */
>> +#define TM_AGE 0x6 /* - + - + */
>> +#define TM_PIPR 0x7 /* - + - + */
>> +
>> +#define TM_WORD0 0x0
>> +#define TM_WORD1 0x4
>> +
>> +/*
>> + * QW word 2 contains the valid bit at the top and other fields
>> + * depending on the QW.
>> + */
>> +#define TM_WORD2 0x8
>> +#define TM_QW0W2_VU PPC_BIT32(0)
>> +#define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1, 31) /* XX 2,31 ? */
>> +#define TM_QW1W2_VO PPC_BIT32(0)
>> +#define TM_QW1W2_OS_CAM PPC_BITMASK32(8, 31)
>> +#define TM_QW2W2_VP PPC_BIT32(0)
>> +#define TM_QW2W2_POOL_CAM PPC_BITMASK32(8, 31)
>> +#define TM_QW3W2_VT PPC_BIT32(0)
>> +#define TM_QW3W2_LP PPC_BIT32(6)
>> +#define TM_QW3W2_LE PPC_BIT32(7)
>> +#define TM_QW3W2_T PPC_BIT32(31)
>> +
>> +/*
>> + * In addition to normal loads to "peek" and writes (only when invalid)
>> + * using 4 and 8 bytes accesses, the above registers support these
>> + * "special" byte operations:
>> + *
>> + * - Byte load from QW0[NSR] - User level NSR (EBB)
>> + * - Byte store to QW0[NSR] - User level NSR (EBB)
>> + * - Byte load/store to QW1[CPPR] and QW3[CPPR] - CPPR access
>> + * - Byte load from QW3[TM_WORD2] - Read VT||00000||LP||LE on thrd 0
>> + * otherwise VT||0000000
>> + * - Byte store to QW3[TM_WORD2] - Set VT bit (and LP/LE if present)
>> + *
>> + * Then we have all these "special" CI ops at these offset that trigger
>> + * all sorts of side effects:
>> + */
>> +#define TM_SPC_ACK_EBB 0x800 /* Load8 ack EBB to reg*/
>> +#define TM_SPC_ACK_OS_REG 0x810 /* Load16 ack OS irq to reg */
>> +#define TM_SPC_PUSH_USR_CTX 0x808 /* Store32 Push/Validate user
>> context */
>> +#define TM_SPC_PULL_USR_CTX 0x808 /* Load32 Pull/Invalidate user
>> + * context */
>> +#define TM_SPC_SET_OS_PENDING 0x812 /* Store8 Set OS irq pending bit */
>> +#define TM_SPC_PULL_OS_CTX 0x818 /* Load32/Load64 Pull/Invalidate OS
>> + * context to reg */
>> +#define TM_SPC_PULL_POOL_CTX 0x828 /* Load32/Load64 Pull/Invalidate
>> Pool
>> + * context to reg*/
>> +#define TM_SPC_ACK_HV_REG 0x830 /* Load16 ack HV irq to reg */
>> +#define TM_SPC_PULL_USR_CTX_OL 0xc08 /* Store8 Pull/Inval usr ctx to odd
>> + * line */
>> +#define TM_SPC_ACK_OS_EL 0xc10 /* Store8 ack OS irq to even line */
>> +#define TM_SPC_ACK_HV_POOL_EL 0xc20 /* Store8 ack HV evt pool to even
>> + * line */
>> +#define TM_SPC_ACK_HV_EL 0xc30 /* Store8 ack HV irq to even line */
>> +/* XXX more... */
>> +
>> +/* NSR fields for the various QW ack types */
>> +#define TM_QW0_NSR_EB PPC_BIT8(0)
>> +#define TM_QW1_NSR_EO PPC_BIT8(0)
>> +#define TM_QW3_NSR_HE PPC_BITMASK8(0, 1)
>> +#define TM_QW3_NSR_HE_NONE 0
>> +#define TM_QW3_NSR_HE_POOL 1
>> +#define TM_QW3_NSR_HE_PHYS 2
>> +#define TM_QW3_NSR_HE_LSI 3
>> +#define TM_QW3_NSR_I PPC_BIT8(2)
>> +#define TM_QW3_NSR_GRP_LVL PPC_BIT8(3, 7)
>> +
>> /* IVE/EAS
>> *
>> * One per interrupt source. Targets that interrupt to a given EQ
>> @@ -30,4 +112,6 @@ typedef struct XiveIVE {
>> #define IVE_EQ_DATA PPC_BITMASK(33, 63) /* Data written to the EQ
>> */
>> } XiveIVE;
>>
>> +#define XIVE_PRIORITY_MAX 7
>> +
>> #endif /* _INTC_XIVE_INTERNAL_H */
>
- Re: [Qemu-ppc] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR, (continued)
[Qemu-ppc] [PATCH v3 05/35] spapr/xive: add a single source block to the sPAPR XIVE model, Cédric Le Goater, 2018/04/19
[Qemu-ppc] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model, Cédric Le Goater, 2018/04/19
[Qemu-ppc] [PATCH v3 07/35] spapr/xive: introduce the XIVE Event Queues, Cédric Le Goater, 2018/04/19
[Qemu-ppc] [PATCH v3 08/35] spapr: push the XIVE EQ data in OS event queue, Cédric Le Goater, 2018/04/19
[Qemu-ppc] [PATCH v3 09/35] spapr: notify the CPU when the XIVE interrupt priority is more privileged, Cédric Le Goater, 2018/04/19
[Qemu-ppc] [PATCH v3 10/35] spapr: add support for the SET_OS_PENDING command (XIVE), Cédric Le Goater, 2018/04/19
[Qemu-ppc] [PATCH v3 11/35] spapr: introduce a 'xive_exploitation' option to enable XIVE, Cédric Le Goater, 2018/04/19
[Qemu-ppc] [PATCH v3 12/35] spapr: add a sPAPRXive object to the machine, Cédric Le Goater, 2018/04/19
[Qemu-ppc] [PATCH v3 14/35] spapr: add device tree support for the XIVE exploitation mode, Cédric Le Goater, 2018/04/19