ppc: support for the XIVE interrupt controller (POWER9)
v3 cover ppc: support for the XIVE interrupt controller (POWER9)
Hello,
The POWER9 processor comes with a new interrupt controller, called XIVE, which introduces a large number of new features, for virtualization in particular.
* XIVE interrupt controller
It is composed of three sub-engines :
- Interrupt Virtualization Source Engine (IVSE). These are in PHBs, in the main controller for the IPIS and in the PSI host bridge. They are configured to feed the IVRE with events.
- Interrupt Virtualization Routing Engine (IVRE). Its job is to match an event source with a Notification Virtualization Target (NVT), a priority and an Event Queue (EQ) to determine if a Virtual Processor can handle the event.
- Interrupt Virtualization Presentation Engine (IVPE). It maintains the interrupt state of each hardware thread and present the notification as an external exception.
Each of the engines uses a set of internal tables to redirect exceptions from event sources to CPU threads. Interrupt sources have a 2-bit state machine, the Event State Buffer (ESB), that allows events to be triggered. If the event is let through, the IVRE looks up in the Interrupt Virtualization Entry (IVE) table for the Event Queue Descriptor configured for the source. Each Event Queue Descriptor defines a notification path to a CPU and an in-memory queue in which will be recorded an event identifier for the OS to pull.
On a POWER9 sPAPR machine, the Client Architecture Support (CAS) negotiation process determines whether the guest operates with a interrupt controller using the XICS legacy model, as found on POWER8, or in XIVE exploitation mode. On a POWER9 PowerNV machine, the XIVE interrupt controller is a must have.
* XIVE for sPAPR
Here are the high level ideas of the current design to add support for XIVE :
- introduce a persistent sPAPRXive object under the sPAPR machine for newer machines and let the CAS negotiation process decide whether it should be used or not. Use the 'ov5_cas' attribute for this purpose.
- introduce a persistent XIVE interrupt presenter under the sPAPR core and switch ICP after CAS. Each core has now two ICPs, one active through the 'intc' pointer and another one among its children ready to be used if the guest requires it.
- move the XIVE EQs under the cores to simplify the XIVE model
- allocate the CPU IPIs at the beginning of the IRQ number space to be compatible with XICS (which starts at 4096) and also to simplify the model. This means that the XIVE model covers the whole IRQ number space. There are no offset like in XICS splitting the IRQ number space.
* sPAPR patchset layout
It first defines new models for XIVE, which will be shared between the machines or with KVM for sPAPR :
- XiveSource holding the PQ bits and the ESB MMIO region used to control them.
- XiveNVT holding the CPU interrupt state and the EQ state. it models the XIVE interrupt presenter engine.
- sPAPRXive modeling the XIVE interrupt controller for sPAPR machines, holding the internal routing table, a single XIVE source for the IPIs and other interrupts and the TIMA MMIO regions used by the XiveNVT to do interrupt management.
We do not model the IVRE, but this is not a problem to introduce it if needed. Maybe for migration. To be discussed.
Then, the notification process and the interrupt delivery to the CPU is described. Support for sPAPR is completed with the integration of the sPAPRXive object in the machine, the definition of the new XIVE hcalls, the device tree layout, and the necessary adjustments to support the CAS negotiation.
Follows the support for KVM with a set of specific XIVE models, very much like XICS does. But, the interrupt mode is still chosen at the init of the machine and the reset does change the KVM interrupt device. A couple of patches try to fix this limitation with a proposal to support resets of KVM devices. Some issues in the MMU migration which still need to be addressed.
* PowerNV extension
It seemed interesting to include the models for PowerNV as a way to validate that the concept are valid.
The patchset finishes with RFCs of models for the XIVE interrupt controller and for the PSI bridge device for the POWER9 PowerNV. PSI provides a good example of the usage of the notify() handler of the XiveFabric interface, linking the PSI XiveSource to its owning device.
* Coverage
At this stage, XIVE support in QEMU covers :
- TCG & KVM kernel_irqchip=off/on
- CPU hotplug
- support for older machines
- migration under TCG
- migration under KVM, including kernel_irqchip=off <-> kernel_irqchip=on
* Caveats
Migration still needs some care to make sure all HW states are captured correctly. Extra quiescence points are possibly needed, to turn off/on the XIVE configuration under KVM.
KVM device reset works well enough but has consequences on MMU migration. Probably an ordering problem.
* Github
QEMU:
https://github.com/legoater/qemu/commits/xive
Linux/KVM (to be sent later on):
https://github.com/legoater/linux/commits/xive
Thanks,
C.
Changes since v2 :
- added support for Store EOI
- added support for two page ESB MMIO setting like on KVM
- introduced the XiveFabric interface
- introduced spapr_xive_mmio_unmap()
- KVM support
Cédric Le Goater (35):
ppc/xive: introduce a XIVE interrupt source model ppc/xive: add support for the LSI interrupt sources ppc/xive: introduce the XiveFabric interface spapr/xive: introduce a XIVE interrupt controller for sPAPR spapr/xive: add a single source block to the sPAPR XIVE model spapr/xive: introduce a XIVE interrupt presenter model spapr/xive: introduce the XIVE Event Queues
spapr: push the XIVE EQ data in OS event queue
spapr: notify the CPU when the XIVE interrupt priority is more
privileged
spapr: add support for the SET_OS_PENDING command (XIVE)
spapr: introduce a 'xive_exploitation' option to enable XIVE
spapr: add a sPAPRXive object to the machine
spapr: add hcalls support for the XIVE exploitation interrupt mode
spapr: add device tree support for the XIVE exploitation mode
sysbus: add a sysbus_mmio_unmap() helper
spapr: introduce a helper to map the XIVE memory regions
spapr: add XIVE support to spapr_qirq()
spapr: introduce a spapr_icp_create() helper
spapr: toggle the ICP depending on the selected interrupt mode
spapr: add support to dump XIVE information
spapr: advertise XIVE exploitation mode in CAS
spapr: add classes for the XIVE models
target/ppc/kvm: add Linux KVM definitions for XIVE spapr/xive: add common realize routine for KVM spapr/xive: add KVM support
spapr/xive: add a XIVE KVM device to the machine
migration: discard non-migratable RAMBlocks
intc: introduce a CPUIntc interface
spapr/xive,xics: use the CPU_INTC handlers to reset KVM spapr/xive,xics: reset KVM at machine reset
spapr/xive: raise migration priority of the machine ppc/pnv: introduce a pnv_icp_create() helper
ppc: externalize ppc_get_vcpu_by_pir()
ppc/pnv: add XIVE support
ppc/pnv: add a PSI bridge model for POWER9 processor
default-configs/ppc64-softmmu.mak | 3 + exec.c | 10 + hw/core/sysbus.c | 10 + hw/intc/Makefile.objs | 5 +- hw/intc/intc.c | 26 + hw/intc/pnv_xive.c | 1234 +++++++++++++++++++++++++++++++++++++ hw/intc/pnv_xive_regs.h | 314 ++++++++++ hw/intc/spapr_xive.c | 324 ++++++++++ hw/intc/spapr_xive_hcall.c | 923 +++++++++++++++++++++++++++ hw/intc/spapr_xive_kvm.c | 655 ++++++++++++++++++++ hw/intc/xics.c | 4 + hw/intc/xics_kvm.c | 108 +++- hw/intc/xive.c | 1200 ++++++++++++++++++++++++++++++++++++ hw/ppc/pnv.c | 93 +-- hw/ppc/pnv_core.c | 2 +- hw/ppc/pnv_psi.c | 399 +++++++++++- hw/ppc/ppc.c | 16 + hw/ppc/spapr.c | 264 +++++++- hw/ppc/spapr_cpu_core.c | 55 +- hw/ppc/spapr_hcall.c | 6 + hw/ppc/spapr_rtas.c | 2 - include/exec/cpu-common.h | 1 + include/hw/intc/intc.h | 21 + include/hw/ppc/pnv.h | 37 +- include/hw/ppc/pnv_psi.h | 50 +- include/hw/ppc/pnv_xive.h | 89 +++ include/hw/ppc/pnv_xscom.h | 5 + include/hw/ppc/ppc.h | 1 + include/hw/ppc/spapr.h | 21 +- include/hw/ppc/spapr_cpu_core.h | 2 + include/hw/ppc/spapr_xive.h | 93 +++ include/hw/ppc/xics.h | 1 + include/hw/ppc/xive.h | 269 ++++++++ include/hw/ppc/xive_regs.h | 187 ++++++ include/hw/sysbus.h | 1 + include/migration/vmstate.h | 2 + linux-headers/asm-powerpc/kvm.h | 18 + linux-headers/linux/kvm.h | 5 + migration/ram.c | 42 +- target/ppc/kvm.c | 7 + target/ppc/kvm_ppc.h | 6 + 41 files changed, 6414 insertions(+), 97 deletions(-) create mode 100644 hw/intc/pnv_xive.c create mode 100644 hw/intc/pnv_xive_regs.h create mode 100644 hw/intc/spapr_xive.c create mode 100644 hw/intc/spapr_xive_hcall.c create mode 100644 hw/intc/spapr_xive_kvm.c create mode 100644 hw/intc/xive.c create mode 100644 include/hw/ppc/pnv_xive.h create mode 100644 include/hw/ppc/spapr_xive.h create mode 100644 include/hw/ppc/xive.h create mode 100644 include/hw/ppc/xive_regs.h
Signature · 1 line
2.13.6
PATCH v3 1/35 ppc/xive: introduce a XIVE interrupt source model
Each XIVE interrupt source is associated with a two bit state machine called an Event State Buffer (ESB) : the first bit "P" means that an interrupt is "pending" and waiting for an EOI and the bit "Q" (queued) means a new interrupt was triggered while another was still pending.
When an event is triggered, the associated interrupt state bits are fetched and modified and forwarded to the virtualization engine of the controller doing the routing. These can also be controlled by MMIO, to trigger events or turn off the sources for instance. See code for more details on the states and transitions.
On a sPAPR machine, the OS will obtain the address of the MMIO page of the ESB entry associated with a source and its characteristic using the H_INT_GET_SOURCE_INFO hcall. On PowerNV, a similar OPAL call is used.
The xive_source_notify() routine is in charge forwarding the source event notification to the routing engine. It will be filled later on.
---
Changes since v2:
- added support for Store EOI
- added support for two page MMIO setting like on KVM
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/xive.c | 335 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/xive.h | 130 +++++++++++++++ 4 files changed, 467 insertions(+) create mode 100644 hw/intc/xive.c create mode 100644 include/hw/ppc/xive.h
default-configs/ppc64-softmmu.mak +1 -0
@@ -16,4 +16,5 @@ CONFIG_VIRTIO_VGA=y CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) +CONFIG_XIVE=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=y
hw/intc/Makefile.objs +1 -0
@@ -37,6 +37,7 @@ obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o +obj-$(CONFIG_XIVE) += xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o
hw/intc/xive.c new file +335 -0
335 lines not on this page · raw message
include/hw/ppc/xive.h new file +130 -0
130 lines not on this page · raw message
Signature · 1 line
2.13.6
Re: [Qemu-devel] [PATCH v3 01/35] ppc/xive: introduce a XIVE interrupt source model
Quoted 19 lines · Cédric Le Goater
Each XIVE interrupt source is associated with a two bit state machine called an Event State Buffer (ESB) : the first bit "P" means that an interrupt is "pending" and waiting for an EOI and the bit "Q" (queued) means a new interrupt was triggered while another was still pending.
When an event is triggered, the associated interrupt state bits are fetched and modified and forwarded to the virtualization engine of the controller doing the routing. These can also be controlled by MMIO, to trigger events or turn off the sources for instance. See code for more details on the states and transitions.
On a sPAPR machine, the OS will obtain the address of the MMIO page of the ESB entry associated with a source and its characteristic using the
H_INT_GET_SOURCE_INFOhcall. On PowerNV, a similar OPAL call is used.The
xive_source_notify()routine is in charge forwarding the source event notification to the routing engine. It will be filled later on.
Quoted 6 lines
Signed-off-by Cédric Le Goater <[email protected]>---
Changes since v2:- added support for Store EOI
- added support for two page MMIO setting like on KVM
Looks generally sane to me, though I have a few queries.
Quoted 135 lines
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/xive.c | 335 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/xive.h | 130 +++++++++++++++ 4 files changed, 467 insertions(+) create mode 100644 hw/intc/xive.c create mode 100644 include/hw/ppc/xive.hdefault-configs/ppc64-softmmu.mak +1
-0@@ -16,4 +16,5 @@ CONFIG_VIRTIO_VGA=y CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) +CONFIG_XIVE=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=yhw/intc/Makefile.objs +1
-0@@ -37,6 +37,7 @@ obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o +obj-$(CONFIG_XIVE) += xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/xive.c new file +98
-0@@ -0,0 +1,335 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "sysemu/dma.h" +#include "monitor/monitor.h" +#include "hw/ppc/xive.h" + +/* +* XIVE Interrupt Source +*/ + +uint8_t xive_source_pq_get (XiveSource *xsrc,uint32_t srcno) +{ +uint32_t byte = srcno /4 ; +uint32_t bit = (srcno %4 ) *2 ; + +assert (byte < xsrc->sbe_size); + +return (xsrc->sbe[byte] >> bit) &0x3 ; +} + +uint8_t xive_source_pq_set (XiveSource *xsrc,uint32_t srcno,uint8_t pq) +{ +uint32_t byte = srcno /4 ; +uint32_t bit = (srcno %4 ) *2 ; +uint8_t old, new; + +assert (byte < xsrc->sbe_size); + + old = xsrc->sbe[byte]; + + new = xsrc->sbe[byte] & ~(0x3 << bit); + new |= (pq &0x3 ) << bit; + + xsrc->sbe[byte] = new; + +return (old >> bit) &0x3 ; +} + +static bool xive_source_pq_eoi (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +switch (old_pq) { +case XIVE_ESB_RESET : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_RESET ); +return false; +case XIVE_ESB_PENDING : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_RESET ); +return false; +case XIVE_ESB_QUEUED : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; +case XIVE_ESB_OFF : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_OFF ); +return false; +default : +g_assert_not_reached (); + } +} + +/* +* Returns whether the event notification should be forwarded. +*/ +static bool xive_source_pq_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +switch (old_pq) { +case XIVE_ESB_RESET : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; +case XIVE_ESB_PENDING : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_QUEUED ); +return false; +case XIVE_ESB_QUEUED : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_QUEUED ); +return false; +case XIVE_ESB_OFF : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_OFF ); +return false; +default : +g_assert_not_reached (); + } +} + +/*
hw/intc/xive.c line 108
Quoted 10 lines
hw/intc/xive.c new file +10
-0+* Forward the source event notification to the associated XiveFabric, +* the device owning the sources. +*/ +static void xive_source_notify (XiveSource *xsrc,int srcno) +{ + +} + +/* In a two pages ESB MMIO setting, even page is the trigger page, odd +* page is for management */
Can I understand from this that the result from this function is only meaningful in 2-pages mode?
hw/intc/xive.c line 111
Quoted 3 lines
hw/intc/xive.c new file +3
-0+static inline bool xive_source_is_trigger_page (hwaddr addr) +{ +return !((addr >>16 ) &1 );
Later on you seem to have both 4k and 64k variants list, but here you hardcode 64k. Is that a problem?
hw/intc/xive.c line 117
Quoted 6 lines
hw/intc/xive.c new file +6
-0+} + +static uint64_t xive_source_esb_read (void *opaque,hwaddr addr,unsigned size) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +uint32_t offset = addr &0xF00 ;
You ignore the low bits of the address entirely, so effective you have a 256 byte range that's all aliases of the same register. Is that intentional?
Quoted 7 lines
hw/intc/xive.c new file +7
-0+uint32_t srcno = addr >> xsrc->esb_shift; +uint64_t ret =-1 ; + +if (xive_source_esb_2page (xsrc) &&xive_source_is_trigger_page (addr)) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid load on IRQ %d trigger page at " +"0x%" HWADDR_PRIx"\n" , srcno, addr);
hw/intc/xive.c line 134
Quoted 10 lines
hw/intc/xive.c new file +10
-0+return -1 ; + } + +switch (offset) { +case XIVE_ESB_LOAD_EOI : +/* +* Load EOI is not the default source setting under QEMU, but +* this is what HW uses currently. +*/ + ret =xive_source_pq_eoi (xsrc, srcno);
You're implicitly casting a bool return value into a u64 here, is that intentional?
Quoted 53 lines
hw/intc/xive.c new file +53
-0+ +break ; + +case XIVE_ESB_GET : + ret =xive_source_pq_get (xsrc, srcno); +break ; + +case XIVE_ESB_SET_PQ_00 : +case XIVE_ESB_SET_PQ_01 : +case XIVE_ESB_SET_PQ_10 : +case XIVE_ESB_SET_PQ_11 : + ret =xive_source_pq_set (xsrc, srcno, (offset >>8 ) &0x3 ); +break ; +default : +qemu_log_mask (LOG_GUEST_ERROR ,"XIVE: invalid ESB addr %d\n" , offset); + } + +return ret; +} + +static void xive_source_esb_write (void *opaque,hwaddr addr, +uint64_t value,unsigned size) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +uint32_t offset = addr &0xF00 ; +uint32_t srcno = addr >> xsrc->esb_shift; +bool notify = false; + +switch (offset) { +case 0 : + notify =xive_source_pq_trigger (xsrc, srcno); +break ; + +case XIVE_ESB_STORE_EOI : +if (xive_source_is_trigger_page (addr)) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid store on IRQ %d trigger page at " +"0x%" HWADDR_PRIx"\n" , srcno, addr); +return ; + } + +if (!(xsrc->esb_flags &XIVE_SRC_STORE_EOI )) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid Store EOI for IRQ %d\n" , srcno); +return ; + } + +/* If the Q bit is set, we should forward a new source event +* notification +*/ + notify =xive_source_pq_eoi (xsrc, srcno); +break ; +
hw/intc/xive.c line 197
Quoted 10 lines
hw/intc/xive.c new file +10
-0+default : +qemu_log_mask (LOG_GUEST_ERROR ,"XIVE: invalid ESB write addr %d\n" , + offset); +return ; + } + +/* Forward the source event notification for routing */ +if (notify) { +xive_source_notify (xsrc, srcno); + }
EOI via this path calls notify, but the one via the read path doesn't. Is that correct?
Quoted 100 lines
hw/intc/xive.c new file +100
-0+} + +static const MemoryRegionOps xive_source_esb_ops = { + .read = xive_source_esb_read, + .write = xive_source_esb_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_set_irq (void *opaque,int srcno,int val) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +bool notify = false; + +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } + +/* Forward the source event notification for routing */ +if (notify) { +xive_source_notify (xsrc, srcno); + } +} + +void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon) +{ +int i; + +monitor_printf (mon,"XIVE Source %6x ..%6x\n" , + xsrc->offset, xsrc->offset + xsrc->nr_irqs -1 ); +for (i =0 ; i < xsrc->nr_irqs; i++) { +uint8_t pq =xive_source_pq_get (xsrc, i); +uint32_t lisn = i + xsrc->offset; + +if (pq ==XIVE_ESB_OFF ) { +continue ; + } + +monitor_printf (mon," %4x %c%c\n" , lisn, + pq &XIVE_ESB_VAL_P ?'P' :'-' , + pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); + } +} + +static void xive_source_reset (DeviceState *dev) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); + +/* SBEs are initialized to 0b01 which corresponds to "ints off" */ +memset (xsrc->sbe,0x55 , xsrc->sbe_size); +} + +static void xive_source_realize (DeviceState *dev,Error **errp) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); + +if (!xsrc->nr_irqs) { +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_4K_2PAGE && + xsrc->esb_shift !=XIVE_ESB_64K && + xsrc->esb_shift !=XIVE_ESB_64K_2PAGE ) { +error_setg (errp,"Invalid ESB shift setting" ); +return ; + } + + xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, + xsrc->nr_irqs); + +/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ + xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 ); + xsrc->sbe =g_malloc0 (xsrc->sbe_size); + +/* TODO: H_INT_ESB support, which removing the ESB MMIOs */ + +memory_region_init_io (&xsrc->esb_mmio,OBJECT (xsrc), + &xive_source_esb_ops, xsrc,"xive.esb" , + (1ull << xsrc->esb_shift) * xsrc->nr_irqs); +sysbus_init_mmio (SYS_BUS_DEVICE (dev), &xsrc->esb_mmio); +} + +static const VMStateDescription vmstate_xive_source = { + .name =TYPE_XIVE_SOURCE , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT32_EQUAL (nr_irqs, XiveSource,NULL ), +VMSTATE_VBUFFER_UINT32 (sbe, XiveSource,1 ,NULL , sbe_size), +VMSTATE_END_OF_LIST () + },
hw/intc/xive.c line 307
Quoted 10 lines
hw/intc/xive.c new file +10
-0+}; + +/* +* The default XIVE interrupt source setting for ESB MMIO is two 64k +* pages without Store EOI. This is in sync with KVM. +*/ +static Property xive_source_properties[] = { +DEFINE_PROP_UINT64 ("flags" , XiveSource, esb_flags,0 ), +DEFINE_PROP_UINT32 ("nr-irqs" , XiveSource, nr_irqs,0 ), +DEFINE_PROP_UINT64 ("bar" , XiveSource, esb_base,0 ),
Isn't this redundant with however the base address is handled through the SysBusDevice stuff (I forget the details)?
Quoted 78 lines
hw/intc/xive.c new file +28
-0+DEFINE_PROP_UINT32 ("shift" , XiveSource, esb_shift,XIVE_ESB_64K_2PAGE ), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xive_source_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->realize = xive_source_realize; + dc->reset = xive_source_reset; + dc->props = xive_source_properties; + dc->desc ="XIVE interrupt source" ; + dc->vmsd = &vmstate_xive_source; +} + +static const TypeInfo xive_source_info = { + .name =TYPE_XIVE_SOURCE , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (XiveSource), + .class_init = xive_source_class_init, +}; + +static void xive_register_types (void ) +{ +type_register_static (&xive_source_info); +} + +type_init (xive_register_types)include/hw/ppc/xive.h new file +44
-0@@ -0,0 +1,130 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_XIVE_H +#define PPC_XIVE_H + +#include "hw/sysbus.h" + +/* + * XIVE Interrupt Source + */ + +#define TYPE_XIVE_SOURCE "xive-source" +#define XIVE_SOURCE(obj) OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE) + +/* + * XIVE Source Interrupt source characteristics, which define how the + * ESB are controlled. + */ +#define XIVE_SRC_H_INT_ESB 0x1 /* ESB managed with hcall H_INT_ESB */ +#define XIVE_SRC_STORE_EOI 0x4 /* Store EOI supported */ + +typedef struct XiveSource { + SysBusDevice parent; + + /* IRQs */ + uint32_t nr_irqs; + uint32_t offset; + qemu_irq *qirqs; + + /* PQ bits */ + uint8_t *sbe; + uint32_t sbe_size; + + /* ESB memory region */ + uint64_t esb_flags; + hwaddr esb_base; + uint32_t esb_shift;
include/hw/ppc/xive.h line 54
Quoted 10 lines
include/hw/ppc/xive.h new file +10
-0+MemoryRegion esb_mmio; +} XiveSource; + +/* +* ESB MMIO setting. Can be one page, for both source triggering and +* source management, or two different pages. See below for magic +* values. +*/ +#define XIVE_ESB_4K 12/* PSI HB */ +#define XIVE_ESB_4K_2PAGE 17
Should this be 13 instead of 17?
include/hw/ppc/xive.h line 56
Quoted 2 lines
include/hw/ppc/xive.h new file +2
-0+#define XIVE_ESB_64K 16 +#define XIVE_ESB_64K_2PAGE 17
(Also, who the hell comes up with a brand new PIC and decides to have *4* different interface variants. But that's not your problem, I realise).
Quoted 74 lines
include/hw/ppc/xive.h new file +74
-0+ +static inline bool xive_source_esb_2page (XiveSource *xsrc) +{ +return xsrc->esb_shift ==XIVE_ESB_64K_2PAGE ; +} + +static inline hwaddr xive_source_esb_base (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->esb_base + (1ull << xsrc->esb_shift) * srcno; +} + +/* The trigger page is always the first/even page */ +#define xive_source_esb_trigger xive_source_esb_base + +/* In a two pages ESB MMIO setting, the odd page is for management */ +static inline hwaddr xive_source_esb_mgmt (XiveSource *xsrc,int srcno) +{ +hwaddr addr =xive_source_esb_base (xsrc, srcno); + +if (xive_source_esb_2page (xsrc)) { + addr += (1 << (xsrc->esb_shift -1 )); + } + +return addr; +} + +/* +* Each interrupt source has a 2-bit state machine called ESB which +* can be controlled by MMIO. It's made of 2 bits, P and Q. P +* indicates that an interrupt is pending (has been sent to a queue +* and is waiting for an EOI). Q indicates that the interrupt has been +* triggered while pending. +* +* This acts as a coalescing mechanism in order to guarantee +* that a given interrupt only occurs at most once in a queue. +* +* When doing an EOI, the Q bit will indicate if the interrupt +* needs to be re-triggered. +*/ +#define XIVE_ESB_VAL_P 0x2 +#define XIVE_ESB_VAL_Q 0x1 + +#define XIVE_ESB_RESET 0x0 +#define XIVE_ESB_PENDING XIVE_ESB_VAL_P +#define XIVE_ESB_QUEUED (XIVE_ESB_VAL_P | XIVE_ESB_VAL_Q) +#define XIVE_ESB_OFF XIVE_ESB_VAL_Q + +/* +* "magic" Event State Buffer (ESB) MMIO offsets. +* +* The following offsets into the ESB MMIO allow to read or +* manipulate the PQ bits. They must be used with an 8-bytes +* load instruction. They all return the previous state of the +* interrupt (atomically). +* +* Additionally, some ESB pages support doing an EOI via a +* store at 0 and some ESBs support doing a trigger via a +* separate trigger page. +*/ +#define XIVE_ESB_STORE_EOI 0x400/* Store */ +#define XIVE_ESB_LOAD_EOI 0x000/* Load */ +#define XIVE_ESB_GET 0x800/* Load */ +#define XIVE_ESB_SET_PQ_00 0xc00/* Load */ +#define XIVE_ESB_SET_PQ_01 0xd00/* Load */ +#define XIVE_ESB_SET_PQ_10 0xe00/* Load */ +#define XIVE_ESB_SET_PQ_11 0xf00/* Load */ + +uint8_t xive_source_pq_get (XiveSource *xsrc,uint32_t srcno); +uint8_t xive_source_pq_set (XiveSource *xsrc,uint32_t srcno,uint8_t pq); + +void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); + +#endif /* PPC_XIVE_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 01/35] ppc/xive: introduce a XIVE interrupt source model
Quoted 169 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Each XIVE interrupt source is associated with a two bit state machine called an Event State Buffer (ESB) : the first bit "P" means that an interrupt is "pending" and waiting for an EOI and the bit "Q" (queued) means a new interrupt was triggered while another was still pending.
When an event is triggered, the associated interrupt state bits are fetched and modified and forwarded to the virtualization engine of the controller doing the routing. These can also be controlled by MMIO, to trigger events or turn off the sources for instance. See code for more details on the states and transitions.
On a sPAPR machine, the OS will obtain the address of the MMIO page of the ESB entry associated with a source and its characteristic using the
H_INT_GET_SOURCE_INFOhcall. On PowerNV, a similar OPAL call is used.The
xive_source_notify()routine is in charge forwarding the source event notification to the routing engine. It will be filled later on.Quoted 6 lines
Signed-off-by Cédric Le Goater <[email protected]>---
Changes since v2:- added support for Store EOI
- added support for two page MMIO setting like on KVMLooks generally sane to me, though I have a few queries.
Quoted 140 lines
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/xive.c | 335 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/xive.h | 130 +++++++++++++++ 4 files changed, 467 insertions(+) create mode 100644 hw/intc/xive.c create mode 100644 include/hw/ppc/xive.hdefault-configs/ppc64-softmmu.mak +1
-0@@ -16,4 +16,5 @@ CONFIG_VIRTIO_VGA=y CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) +CONFIG_XIVE=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=yhw/intc/Makefile.objs +1
-0@@ -37,6 +37,7 @@ obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o +obj-$(CONFIG_XIVE) += xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/xive.c new file +103
-0@@ -0,0 +1,335 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "sysemu/dma.h" +#include "monitor/monitor.h" +#include "hw/ppc/xive.h" + +/* +* XIVE Interrupt Source +*/ + +uint8_t xive_source_pq_get (XiveSource *xsrc,uint32_t srcno) +{ +uint32_t byte = srcno /4 ; +uint32_t bit = (srcno %4 ) *2 ; + +assert (byte < xsrc->sbe_size); + +return (xsrc->sbe[byte] >> bit) &0x3 ; +} + +uint8_t xive_source_pq_set (XiveSource *xsrc,uint32_t srcno,uint8_t pq) +{ +uint32_t byte = srcno /4 ; +uint32_t bit = (srcno %4 ) *2 ; +uint8_t old, new; + +assert (byte < xsrc->sbe_size); + + old = xsrc->sbe[byte]; + + new = xsrc->sbe[byte] & ~(0x3 << bit); + new |= (pq &0x3 ) << bit; + + xsrc->sbe[byte] = new; + +return (old >> bit) &0x3 ; +} + +static bool xive_source_pq_eoi (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +switch (old_pq) { +case XIVE_ESB_RESET : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_RESET ); +return false; +case XIVE_ESB_PENDING : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_RESET ); +return false; +case XIVE_ESB_QUEUED : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; +case XIVE_ESB_OFF : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_OFF ); +return false; +default : +g_assert_not_reached (); + } +} + +/* +* Returns whether the event notification should be forwarded. +*/ +static bool xive_source_pq_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +switch (old_pq) { +case XIVE_ESB_RESET : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; +case XIVE_ESB_PENDING : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_QUEUED ); +return false; +case XIVE_ESB_QUEUED : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_QUEUED ); +return false; +case XIVE_ESB_OFF : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_OFF ); +return false; +default : +g_assert_not_reached (); + } +} + +/* +* Forward the source event notification to the associated XiveFabric, +* the device owning the sources. +*/ +static void xive_source_notify (XiveSource *xsrc,int srcno) +{
Quoted 8 lines
hw/intc/xive.c line 108
Quoted 5 lines
hw/intc/xive.c new file +5
-0+ +} + +/* In a two pages ESB MMIO setting, even page is the trigger page, odd +* page is for management */ Can I understand from this that the result from this function is only meaningful in 2-pages mode?
yes. May be I should rename it to xive_source_is_even_page() ?
Quoted 6 lines
hw/intc/xive.c line 111
Quoted 3 lines
hw/intc/xive.c new file +3
-0+static inline bool xive_source_is_trigger_page (hwaddr addr) +{ +return !((addr >>16 ) &1 );Later on you seem to have both 4k and 64k variants list, but here you hardcode 64k. Is that a problem?
oups. This should be :
(addr >> (xsrc->esb_shift - 1))
I did the tests with the spapr guest which uses 64k ESB MMIO pages. The check is only significant in a 2 pages setting.
Quoted 10 lines
hw/intc/xive.c line 117
Quoted 6 lines
hw/intc/xive.c new file +6
-0+} + +static uint64_t xive_source_esb_read (void *opaque,hwaddr addr,unsigned size) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +uint32_t offset = addr &0xF00 ;You ignore the low bits of the address entirely, so effective you have a 256 byte range that's all aliases of the same register. Is that intentional?
yes but it's not entirely correct. The exact ranges are :
Load Store
0x000 .. 0x3FF EOI and return 0|1 Trigger0x400 .. 0x7FF EOI and return 0|1 EOI0x800 .. 0xBFF return PQ undefined0xC00 .. 0xCFF return PQ and PQ=00 PQ=000xD00 .. 0xDFF return PQ and PQ=01 PQ=010xE00 .. 0xDFF return PQ and PQ=10 PQ=100xF00 .. 0xDFF return PQ and PQ=11 PQ=11
There is room for some improvements.
The trigger page in a two pages ESB MMIO settings only triggers on stores.
Quoted 12 lines
Quoted 12 lines
hw/intc/xive.c new file +12
-0+uint32_t srcno = addr >> xsrc->esb_shift; +uint64_t ret =-1 ; + +if (xive_source_esb_2page (xsrc) &&xive_source_is_trigger_page (addr)) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid load on IRQ %d trigger page at " +"0x%" HWADDR_PRIx"\n" , srcno, addr); +return -1 ; + } + +switch (offset) { +case XIVE_ESB_LOAD_EOI :
Quoted 8 lines
hw/intc/xive.c line 134
Quoted 5 lines
hw/intc/xive.c new file +5
-0+/* +* Load EOI is not the default source setting under QEMU, but +* this is what HW uses currently. +*/ + ret =xive_source_pq_eoi (xsrc, srcno);You're implicitly casting a bool return value into a u64 here, is that intentional?
yes. is that bad ? This is what the load is supposed to return in the transition algo.
Quoted 58 lines
Quoted 58 lines
hw/intc/xive.c new file +58
-0+ +break ; + +case XIVE_ESB_GET : + ret =xive_source_pq_get (xsrc, srcno); +break ; + +case XIVE_ESB_SET_PQ_00 : +case XIVE_ESB_SET_PQ_01 : +case XIVE_ESB_SET_PQ_10 : +case XIVE_ESB_SET_PQ_11 : + ret =xive_source_pq_set (xsrc, srcno, (offset >>8 ) &0x3 ); +break ; +default : +qemu_log_mask (LOG_GUEST_ERROR ,"XIVE: invalid ESB addr %d\n" , offset); + } + +return ret; +} + +static void xive_source_esb_write (void *opaque,hwaddr addr, +uint64_t value,unsigned size) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +uint32_t offset = addr &0xF00 ; +uint32_t srcno = addr >> xsrc->esb_shift; +bool notify = false; + +switch (offset) { +case 0 : + notify =xive_source_pq_trigger (xsrc, srcno); +break ; + +case XIVE_ESB_STORE_EOI : +if (xive_source_is_trigger_page (addr)) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid store on IRQ %d trigger page at " +"0x%" HWADDR_PRIx"\n" , srcno, addr); +return ; + } + +if (!(xsrc->esb_flags &XIVE_SRC_STORE_EOI )) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid Store EOI for IRQ %d\n" , srcno); +return ; + } + +/* If the Q bit is set, we should forward a new source event +* notification +*/ + notify =xive_source_pq_eoi (xsrc, srcno); +break ; + +default : +qemu_log_mask (LOG_GUEST_ERROR ,"XIVE: invalid ESB write addr %d\n" , + offset); +return ; + }
Quoted 8 lines
hw/intc/xive.c line 197
Quoted 5 lines
hw/intc/xive.c new file +5
-0+ +/* Forward the source event notification for routing */ +if (notify) { +xive_source_notify (xsrc, srcno); + }EOI via this path calls notify, but the one via the read path doesn't. Is that correct?
No. I have given attention to the one page ESB MMIO setting + Store EOI in the emulated mode and not enough to the two pages ESB MMIO setting. This is a late change to be compatible with KVM. I will fix.
Quoted 106 lines
Quoted 106 lines
hw/intc/xive.c new file +105
-0+} + +static const MemoryRegionOps xive_source_esb_ops = { + .read = xive_source_esb_read, + .write = xive_source_esb_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_set_irq (void *opaque,int srcno,int val) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +bool notify = false; + +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } + +/* Forward the source event notification for routing */ +if (notify) { +xive_source_notify (xsrc, srcno); + } +} + +void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon) +{ +int i; + +monitor_printf (mon,"XIVE Source %6x ..%6x\n" , + xsrc->offset, xsrc->offset + xsrc->nr_irqs -1 ); +for (i =0 ; i < xsrc->nr_irqs; i++) { +uint8_t pq =xive_source_pq_get (xsrc, i); +uint32_t lisn = i + xsrc->offset; + +if (pq ==XIVE_ESB_OFF ) { +continue ; + } + +monitor_printf (mon," %4x %c%c\n" , lisn, + pq &XIVE_ESB_VAL_P ?'P' :'-' , + pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); + } +} + +static void xive_source_reset (DeviceState *dev) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); + +/* SBEs are initialized to 0b01 which corresponds to "ints off" */ +memset (xsrc->sbe,0x55 , xsrc->sbe_size); +} + +static void xive_source_realize (DeviceState *dev,Error **errp) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); + +if (!xsrc->nr_irqs) { +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_4K_2PAGE && + xsrc->esb_shift !=XIVE_ESB_64K && + xsrc->esb_shift !=XIVE_ESB_64K_2PAGE ) { +error_setg (errp,"Invalid ESB shift setting" ); +return ; + } + + xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, + xsrc->nr_irqs); + +/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ + xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 ); + xsrc->sbe =g_malloc0 (xsrc->sbe_size); + +/* TODO: H_INT_ESB support, which removing the ESB MMIOs */ + +memory_region_init_io (&xsrc->esb_mmio,OBJECT (xsrc), + &xive_source_esb_ops, xsrc,"xive.esb" , + (1ull << xsrc->esb_shift) * xsrc->nr_irqs); +sysbus_init_mmio (SYS_BUS_DEVICE (dev), &xsrc->esb_mmio); +} + +static const VMStateDescription vmstate_xive_source = { + .name =TYPE_XIVE_SOURCE , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT32_EQUAL (nr_irqs, XiveSource,NULL ), +VMSTATE_VBUFFER_UINT32 (sbe, XiveSource,1 ,NULL , sbe_size), +VMSTATE_END_OF_LIST () + }, +}; + +/* +* The default XIVE interrupt source setting for ESB MMIO is two 64k +* pages without Store EOI. This is in sync with KVM.
Quoted 8 lines
hw/intc/xive.c line 307
Quoted 5 lines
hw/intc/xive.c new file +5
-0+*/ +static Property xive_source_properties[] = { +DEFINE_PROP_UINT64 ("flags" , XiveSource, esb_flags,0 ), +DEFINE_PROP_UINT32 ("nr-irqs" , XiveSource, nr_irqs,0 ), +DEFINE_PROP_UINT64 ("bar" , XiveSource, esb_base,0 ),Isn't this redundant with however the base address is handled through the SysBusDevice stuff (I forget the details)?
Storing the ESB MMIO base address under the XiveSource object is convenient later on in the h_int_get_source_info hcall which make use of the helpers :
hwaddr xive_source_esb_trigger(XiveSource *xsrc, uint32_t srcno) hwaddr xive_source_esb_mgmt(XiveSource *xsrc, int srcno)
But it is only used in that place. So we could just store the ESB MMIO base address under the sPAPRXive controller. This makes some sense in the design, as we have to inform KVM of this address with a KVM device ioctl.
Quoted 82 lines
Quoted 82 lines
hw/intc/xive.c new file +28
-0+DEFINE_PROP_UINT32 ("shift" , XiveSource, esb_shift,XIVE_ESB_64K_2PAGE ), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xive_source_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->realize = xive_source_realize; + dc->reset = xive_source_reset; + dc->props = xive_source_properties; + dc->desc ="XIVE interrupt source" ; + dc->vmsd = &vmstate_xive_source; +} + +static const TypeInfo xive_source_info = { + .name =TYPE_XIVE_SOURCE , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (XiveSource), + .class_init = xive_source_class_init, +}; + +static void xive_register_types (void ) +{ +type_register_static (&xive_source_info); +} + +type_init (xive_register_types)include/hw/ppc/xive.h new file +48
-0@@ -0,0 +1,130 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_XIVE_H +#define PPC_XIVE_H + +#include "hw/sysbus.h" + +/* +* XIVE Interrupt Source +*/ + +#define TYPE_XIVE_SOURCE "xive-source" +#define XIVE_SOURCE (obj) OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE) + +/* +* XIVE Source Interrupt source characteristics, which define how the +* ESB are controlled. +*/ +#define XIVE_SRC_H_INT_ESB 0x1/* ESB managed with hcall H_INT_ESB */ +#define XIVE_SRC_STORE_EOI 0x4/* Store EOI supported */ + +typedef struct XiveSource { +SysBusDevice parent; + +/* IRQs */ +uint32_t nr_irqs; +uint32_t offset; +qemu_irq *qirqs; + +/* PQ bits */ +uint8_t *sbe; +uint32_t sbe_size; + +/* ESB memory region */ +uint64_t esb_flags; +hwaddr esb_base; +uint32_t esb_shift; +MemoryRegion esb_mmio; +}XiveSource ; + +/*
Quoted 8 lines
include/hw/ppc/xive.h line 54
Quoted 6 lines
include/hw/ppc/xive.h new file +6
-0+* ESB MMIO setting. Can be one page, for both source triggering and +* source management, or two different pages. See below for magic +* values. +*/ +#define XIVE_ESB_4K 12/* PSI HB */ +#define XIVE_ESB_4K_2PAGE 17Should this be 13 instead of 17?
oups. obviously this is not used.
Quoted 6 lines
include/hw/ppc/xive.h line 56
Quoted 2 lines
include/hw/ppc/xive.h new file +2
-0+#define XIVE_ESB_64K 16 +#define XIVE_ESB_64K_2PAGE 17(Also, who the hell comes up with a brand new PIC and decides to have *4* different interface variants. But that's not your problem, I realise).
HW constraints on the different controllers which need to expose sources : PSI, PHB4. The internal sources of the XIVE interrupt controller can be configured to use 4K or 64K but I doubt the 4k will be ever used.
Thanks,
C.
Quoted 75 lines
Quoted 74 lines
include/hw/ppc/xive.h new file +74
-0+ +static inline bool xive_source_esb_2page (XiveSource *xsrc) +{ +return xsrc->esb_shift ==XIVE_ESB_64K_2PAGE ; +} + +static inline hwaddr xive_source_esb_base (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->esb_base + (1ull << xsrc->esb_shift) * srcno; +} + +/* The trigger page is always the first/even page */ +#define xive_source_esb_trigger xive_source_esb_base + +/* In a two pages ESB MMIO setting, the odd page is for management */ +static inline hwaddr xive_source_esb_mgmt (XiveSource *xsrc,int srcno) +{ +hwaddr addr =xive_source_esb_base (xsrc, srcno); + +if (xive_source_esb_2page (xsrc)) { + addr += (1 << (xsrc->esb_shift -1 )); + } + +return addr; +} + +/* +* Each interrupt source has a 2-bit state machine called ESB which +* can be controlled by MMIO. It's made of 2 bits, P and Q. P +* indicates that an interrupt is pending (has been sent to a queue +* and is waiting for an EOI). Q indicates that the interrupt has been +* triggered while pending. +* +* This acts as a coalescing mechanism in order to guarantee +* that a given interrupt only occurs at most once in a queue. +* +* When doing an EOI, the Q bit will indicate if the interrupt +* needs to be re-triggered. +*/ +#define XIVE_ESB_VAL_P 0x2 +#define XIVE_ESB_VAL_Q 0x1 + +#define XIVE_ESB_RESET 0x0 +#define XIVE_ESB_PENDING XIVE_ESB_VAL_P +#define XIVE_ESB_QUEUED (XIVE_ESB_VAL_P | XIVE_ESB_VAL_Q) +#define XIVE_ESB_OFF XIVE_ESB_VAL_Q + +/* +* "magic" Event State Buffer (ESB) MMIO offsets. +* +* The following offsets into the ESB MMIO allow to read or +* manipulate the PQ bits. They must be used with an 8-bytes +* load instruction. They all return the previous state of the +* interrupt (atomically). +* +* Additionally, some ESB pages support doing an EOI via a +* store at 0 and some ESBs support doing a trigger via a +* separate trigger page. +*/ +#define XIVE_ESB_STORE_EOI 0x400/* Store */ +#define XIVE_ESB_LOAD_EOI 0x000/* Load */ +#define XIVE_ESB_GET 0x800/* Load */ +#define XIVE_ESB_SET_PQ_00 0xc00/* Load */ +#define XIVE_ESB_SET_PQ_01 0xd00/* Load */ +#define XIVE_ESB_SET_PQ_10 0xe00/* Load */ +#define XIVE_ESB_SET_PQ_11 0xf00/* Load */ + +uint8_t xive_source_pq_get (XiveSource *xsrc,uint32_t srcno); +uint8_t xive_source_pq_set (XiveSource *xsrc,uint32_t srcno,uint8_t pq); + +void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); + +#endif /* PPC_XIVE_H */
Re: [Qemu-devel] [PATCH v3 01/35] ppc/xive: introduce a XIVE interrupt source model
Quoted 179 lines · Cédric Le Goater
Quoted 169 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Each XIVE interrupt source is associated with a two bit state machine called an Event State Buffer (ESB) : the first bit "P" means that an interrupt is "pending" and waiting for an EOI and the bit "Q" (queued) means a new interrupt was triggered while another was still pending.
When an event is triggered, the associated interrupt state bits are fetched and modified and forwarded to the virtualization engine of the controller doing the routing. These can also be controlled by MMIO, to trigger events or turn off the sources for instance. See code for more details on the states and transitions.
On a sPAPR machine, the OS will obtain the address of the MMIO page of the ESB entry associated with a source and its characteristic using the
H_INT_GET_SOURCE_INFOhcall. On PowerNV, a similar OPAL call is used.The
xive_source_notify()routine is in charge forwarding the source event notification to the routing engine. It will be filled later on.Quoted 6 lines
Signed-off-by Cédric Le Goater <[email protected]>---
Changes since v2:- added support for Store EOI
- added support for two page MMIO setting like on KVMLooks generally sane to me, though I have a few queries.
Quoted 140 lines
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/xive.c | 335 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/xive.h | 130 +++++++++++++++ 4 files changed, 467 insertions(+) create mode 100644 hw/intc/xive.c create mode 100644 include/hw/ppc/xive.hdefault-configs/ppc64-softmmu.mak +1
-0@@ -16,4 +16,5 @@ CONFIG_VIRTIO_VGA=y CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) +CONFIG_XIVE=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=yhw/intc/Makefile.objs +1
-0@@ -37,6 +37,7 @@ obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o +obj-$(CONFIG_XIVE) += xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/xive.c new file +103
-0@@ -0,0 +1,335 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "sysemu/dma.h" +#include "monitor/monitor.h" +#include "hw/ppc/xive.h" + +/* +* XIVE Interrupt Source +*/ + +uint8_t xive_source_pq_get (XiveSource *xsrc,uint32_t srcno) +{ +uint32_t byte = srcno /4 ; +uint32_t bit = (srcno %4 ) *2 ; + +assert (byte < xsrc->sbe_size); + +return (xsrc->sbe[byte] >> bit) &0x3 ; +} + +uint8_t xive_source_pq_set (XiveSource *xsrc,uint32_t srcno,uint8_t pq) +{ +uint32_t byte = srcno /4 ; +uint32_t bit = (srcno %4 ) *2 ; +uint8_t old, new; + +assert (byte < xsrc->sbe_size); + + old = xsrc->sbe[byte]; + + new = xsrc->sbe[byte] & ~(0x3 << bit); + new |= (pq &0x3 ) << bit; + + xsrc->sbe[byte] = new; + +return (old >> bit) &0x3 ; +} + +static bool xive_source_pq_eoi (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +switch (old_pq) { +case XIVE_ESB_RESET : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_RESET ); +return false; +case XIVE_ESB_PENDING : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_RESET ); +return false; +case XIVE_ESB_QUEUED : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; +case XIVE_ESB_OFF : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_OFF ); +return false; +default : +g_assert_not_reached (); + } +} + +/* +* Returns whether the event notification should be forwarded. +*/ +static bool xive_source_pq_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +switch (old_pq) { +case XIVE_ESB_RESET : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; +case XIVE_ESB_PENDING : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_QUEUED ); +return false; +case XIVE_ESB_QUEUED : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_QUEUED ); +return false; +case XIVE_ESB_OFF : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_OFF ); +return false; +default : +g_assert_not_reached (); + } +} + +/* +* Forward the source event notification to the associated XiveFabric, +* the device owning the sources. +*/ +static void xive_source_notify (XiveSource *xsrc,int srcno) +{Quoted 8 lines
hw/intc/xive.c line 108
Quoted 5 lines
hw/intc/xive.c new file +5
-0+ +} + +/* In a two pages ESB MMIO setting, even page is the trigger page, odd +* page is for management */ Can I understand from this that the result from this function is only meaningful in 2-pages mode?
Quoted 1 line
yes. May be I should rename it to
xive_source_is_even_page()?
Seems very long winded. Maybe keep the name but have it check both whether it's an even page and also whether you're in 2pages mode.
Quoted 7 lines
Quoted 6 lines
hw/intc/xive.c line 111
Quoted 3 lines
hw/intc/xive.c new file +3
-0+static inline bool xive_source_is_trigger_page (hwaddr addr) +{ +return !((addr >>16 ) &1 );Later on you seem to have both 4k and 64k variants list, but here you hardcode 64k. Is that a problem?
Quoted 6 lines
oups. This should be :
(addr >> (xsrc->esb_shift - 1))I did the tests with the spapr guest which uses 64k ESB MMIO pages. The check is only significant in a 2 pages setting.
Ok.
Quoted 23 lines
Quoted 10 lines
hw/intc/xive.c line 117
Quoted 6 lines
hw/intc/xive.c new file +6
-0+} + +static uint64_t xive_source_esb_read (void *opaque,hwaddr addr,unsigned size) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +uint32_t offset = addr &0xF00 ;You ignore the low bits of the address entirely, so effective you have a 256 byte range that's all aliases of the same register. Is that intentional?
yes but it's not entirely correct. The exact ranges are :
Load Store
0x000..0x3FFEOI and return 0|1 Trigger0x400..0x7FFEOI and return 0|1 EOI0x800..0xBFFreturn PQ undefined0xC00..0xCFFreturn PQ and PQ=00 PQ=000xD00..0xDFFreturn PQ and PQ=01 PQ=010xE00..0xDFFreturn PQ and PQ=10 PQ=100xF00..0xDFFreturn PQ and PQ=11 PQ=11
Quoted 3 lines
There is room for some improvements.
The trigger page in a two pages ESB MMIO settings only triggers on stores.
Ok.
Quoted 21 lines
Quoted 12 lines
Quoted 12 lines
hw/intc/xive.c new file +12
-0+uint32_t srcno = addr >> xsrc->esb_shift; +uint64_t ret =-1 ; + +if (xive_source_esb_2page (xsrc) &&xive_source_is_trigger_page (addr)) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid load on IRQ %d trigger page at " +"0x%" HWADDR_PRIx"\n" , srcno, addr); +return -1 ; + } + +switch (offset) { +case XIVE_ESB_LOAD_EOI :Quoted 8 lines
hw/intc/xive.c line 134
Quoted 5 lines
hw/intc/xive.c new file +5
-0+/* +* Load EOI is not the default source setting under QEMU, but +* this is what HW uses currently. +*/ + ret =xive_source_pq_eoi (xsrc, srcno);You're implicitly casting a bool return value into a u64 here, is that intentional?
Quoted 2 lines
yes. is that bad ? This is what the load is supposed to return in the transition algo.
No, that's fine, as long as just using the LSB in your return is correct. Just making sure I understood.
Quoted 67 lines
Quoted 58 lines
Quoted 58 lines
hw/intc/xive.c new file +58
-0+ +break ; + +case XIVE_ESB_GET : + ret =xive_source_pq_get (xsrc, srcno); +break ; + +case XIVE_ESB_SET_PQ_00 : +case XIVE_ESB_SET_PQ_01 : +case XIVE_ESB_SET_PQ_10 : +case XIVE_ESB_SET_PQ_11 : + ret =xive_source_pq_set (xsrc, srcno, (offset >>8 ) &0x3 ); +break ; +default : +qemu_log_mask (LOG_GUEST_ERROR ,"XIVE: invalid ESB addr %d\n" , offset); + } + +return ret; +} + +static void xive_source_esb_write (void *opaque,hwaddr addr, +uint64_t value,unsigned size) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +uint32_t offset = addr &0xF00 ; +uint32_t srcno = addr >> xsrc->esb_shift; +bool notify = false; + +switch (offset) { +case 0 : + notify =xive_source_pq_trigger (xsrc, srcno); +break ; + +case XIVE_ESB_STORE_EOI : +if (xive_source_is_trigger_page (addr)) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid store on IRQ %d trigger page at " +"0x%" HWADDR_PRIx"\n" , srcno, addr); +return ; + } + +if (!(xsrc->esb_flags &XIVE_SRC_STORE_EOI )) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid Store EOI for IRQ %d\n" , srcno); +return ; + } + +/* If the Q bit is set, we should forward a new source event +* notification +*/ + notify =xive_source_pq_eoi (xsrc, srcno); +break ; + +default : +qemu_log_mask (LOG_GUEST_ERROR ,"XIVE: invalid ESB write addr %d\n" , + offset); +return ; + }Quoted 8 lines
hw/intc/xive.c line 197
Quoted 5 lines
hw/intc/xive.c new file +5
-0+ +/* Forward the source event notification for routing */ +if (notify) { +xive_source_notify (xsrc, srcno); + }EOI via this path calls notify, but the one via the read path doesn't. Is that correct?
Quoted 3 lines
No. I have given attention to the one page ESB MMIO setting + Store EOI in the emulated mode and not enough to the two pages ESB MMIO setting. This is a late change to be compatible with KVM. I will fix.
Ok.
Quoted 119 lines
Quoted 106 lines
Quoted 106 lines
hw/intc/xive.c new file +105
-0+} + +static const MemoryRegionOps xive_source_esb_ops = { + .read = xive_source_esb_read, + .write = xive_source_esb_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_set_irq (void *opaque,int srcno,int val) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +bool notify = false; + +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } + +/* Forward the source event notification for routing */ +if (notify) { +xive_source_notify (xsrc, srcno); + } +} + +void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon) +{ +int i; + +monitor_printf (mon,"XIVE Source %6x ..%6x\n" , + xsrc->offset, xsrc->offset + xsrc->nr_irqs -1 ); +for (i =0 ; i < xsrc->nr_irqs; i++) { +uint8_t pq =xive_source_pq_get (xsrc, i); +uint32_t lisn = i + xsrc->offset; + +if (pq ==XIVE_ESB_OFF ) { +continue ; + } + +monitor_printf (mon," %4x %c%c\n" , lisn, + pq &XIVE_ESB_VAL_P ?'P' :'-' , + pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); + } +} + +static void xive_source_reset (DeviceState *dev) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); + +/* SBEs are initialized to 0b01 which corresponds to "ints off" */ +memset (xsrc->sbe,0x55 , xsrc->sbe_size); +} + +static void xive_source_realize (DeviceState *dev,Error **errp) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); + +if (!xsrc->nr_irqs) { +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_4K_2PAGE && + xsrc->esb_shift !=XIVE_ESB_64K && + xsrc->esb_shift !=XIVE_ESB_64K_2PAGE ) { +error_setg (errp,"Invalid ESB shift setting" ); +return ; + } + + xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, + xsrc->nr_irqs); + +/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ + xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 ); + xsrc->sbe =g_malloc0 (xsrc->sbe_size); + +/* TODO: H_INT_ESB support, which removing the ESB MMIOs */ + +memory_region_init_io (&xsrc->esb_mmio,OBJECT (xsrc), + &xive_source_esb_ops, xsrc,"xive.esb" , + (1ull << xsrc->esb_shift) * xsrc->nr_irqs); +sysbus_init_mmio (SYS_BUS_DEVICE (dev), &xsrc->esb_mmio); +} + +static const VMStateDescription vmstate_xive_source = { + .name =TYPE_XIVE_SOURCE , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT32_EQUAL (nr_irqs, XiveSource,NULL ), +VMSTATE_VBUFFER_UINT32 (sbe, XiveSource,1 ,NULL , sbe_size), +VMSTATE_END_OF_LIST () + }, +}; + +/* +* The default XIVE interrupt source setting for ESB MMIO is two 64k +* pages without Store EOI. This is in sync with KVM. Quoted 8 lines
hw/intc/xive.c line 307
Quoted 5 lines
hw/intc/xive.c new file +5
-0+*/ +static Property xive_source_properties[] = { +DEFINE_PROP_UINT64 ("flags" , XiveSource, esb_flags,0 ), +DEFINE_PROP_UINT32 ("nr-irqs" , XiveSource, nr_irqs,0 ), +DEFINE_PROP_UINT64 ("bar" , XiveSource, esb_base,0 ),Isn't this redundant with however the base address is handled through the SysBusDevice stuff (I forget the details)?
Storing the ESB MMIO base address under the XiveSource object is convenient later on in the
h_int_get_source_infohcall which make use of the helpers :
Quoted 7 lines
hwaddr
xive_source_esb_trigger(XiveSource *xsrc, uint32_t srcno)hwaddrxive_source_esb_mgmt(XiveSource *xsrc, int srcno)But it is only used in that place. So we could just store the ESB MMIO base address under the sPAPRXive controller. This makes some sense in the design, as we have to inform KVM of this address with a KVM device ioctl.
Well.. I really dislike the idea that you could change the actual MMIO mapping address in one place, but other bits of code would still think it was mapped somewhere else.
Quoted 100 lines
Quoted 82 lines
Quoted 82 lines
hw/intc/xive.c new file +28
-0+DEFINE_PROP_UINT32 ("shift" , XiveSource, esb_shift,XIVE_ESB_64K_2PAGE ), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xive_source_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->realize = xive_source_realize; + dc->reset = xive_source_reset; + dc->props = xive_source_properties; + dc->desc ="XIVE interrupt source" ; + dc->vmsd = &vmstate_xive_source; +} + +static const TypeInfo xive_source_info = { + .name =TYPE_XIVE_SOURCE , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (XiveSource), + .class_init = xive_source_class_init, +}; + +static void xive_register_types (void ) +{ +type_register_static (&xive_source_info); +} + +type_init (xive_register_types)include/hw/ppc/xive.h new file +48
-0@@ -0,0 +1,130 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_XIVE_H +#define PPC_XIVE_H + +#include "hw/sysbus.h" + +/* +* XIVE Interrupt Source +*/ + +#define TYPE_XIVE_SOURCE "xive-source" +#define XIVE_SOURCE (obj) OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE) + +/* +* XIVE Source Interrupt source characteristics, which define how the +* ESB are controlled. +*/ +#define XIVE_SRC_H_INT_ESB 0x1/* ESB managed with hcall H_INT_ESB */ +#define XIVE_SRC_STORE_EOI 0x4/* Store EOI supported */ + +typedef struct XiveSource { +SysBusDevice parent; + +/* IRQs */ +uint32_t nr_irqs; +uint32_t offset; +qemu_irq *qirqs; + +/* PQ bits */ +uint8_t *sbe; +uint32_t sbe_size; + +/* ESB memory region */ +uint64_t esb_flags; +hwaddr esb_base; +uint32_t esb_shift; +MemoryRegion esb_mmio; +}XiveSource ; + +/* Quoted 8 lines
include/hw/ppc/xive.h line 54
Quoted 6 lines
include/hw/ppc/xive.h new file +6
-0+* ESB MMIO setting. Can be one page, for both source triggering and +* source management, or two different pages. See below for magic +* values. +*/ +#define XIVE_ESB_4K 12/* PSI HB */ +#define XIVE_ESB_4K_2PAGE 17Should this be 13 instead of 17?
oups. obviously this is not used.
Quoted 6 lines
include/hw/ppc/xive.h line 56
Quoted 2 lines
include/hw/ppc/xive.h new file +2
-0+#define XIVE_ESB_64K 16 +#define XIVE_ESB_64K_2PAGE 17(Also, who the hell comes up with a brand new PIC and decides to have *4* different interface variants. But that's not your problem, I realise).
Quoted 4 lines
HW constraints on the different controllers which need to expose sources : PSI, PHB4. The internal sources of the XIVE interrupt controller can be configured to use 4K or 64K but I doubt the 4k will be ever used.
Sure, the hardware is different, but *why* is it different. This is a brand new design, you'd think they could come up with one variant that works for all the cases.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 01/35] ppc/xive: introduce a XIVE interrupt source model
Quoted 180 lines · David Gibson
Quoted 179 lines · Cédric Le Goater
Quoted 177 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Each XIVE interrupt source is associated with a two bit state machine called an Event State Buffer (ESB) : the first bit "P" means that an interrupt is "pending" and waiting for an EOI and the bit "Q" (queued) means a new interrupt was triggered while another was still pending.
When an event is triggered, the associated interrupt state bits are fetched and modified and forwarded to the virtualization engine of the controller doing the routing. These can also be controlled by MMIO, to trigger events or turn off the sources for instance. See code for more details on the states and transitions.
On a sPAPR machine, the OS will obtain the address of the MMIO page of the ESB entry associated with a source and its characteristic using the
H_INT_GET_SOURCE_INFOhcall. On PowerNV, a similar OPAL call is used.The
xive_source_notify()routine is in charge forwarding the source event notification to the routing engine. It will be filled later on.Quoted 6 lines
Signed-off-by Cédric Le Goater <[email protected]>---
Changes since v2:- added support for Store EOI
- added support for two page MMIO setting like on KVMLooks generally sane to me, though I have a few queries.
Quoted 135 lines
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/xive.c | 335 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/xive.h | 130 +++++++++++++++ 4 files changed, 467 insertions(+) create mode 100644 hw/intc/xive.c create mode 100644 include/hw/ppc/xive.hdefault-configs/ppc64-softmmu.mak +1
-0@@ -16,4 +16,5 @@ CONFIG_VIRTIO_VGA=y CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) +CONFIG_XIVE=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=yhw/intc/Makefile.objs +1
-0@@ -37,6 +37,7 @@ obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o +obj-$(CONFIG_XIVE) += xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/xive.c new file +98
-0@@ -0,0 +1,335 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "sysemu/dma.h" +#include "monitor/monitor.h" +#include "hw/ppc/xive.h" + +/* +* XIVE Interrupt Source +*/ + +uint8_t xive_source_pq_get (XiveSource *xsrc,uint32_t srcno) +{ +uint32_t byte = srcno /4 ; +uint32_t bit = (srcno %4 ) *2 ; + +assert (byte < xsrc->sbe_size); + +return (xsrc->sbe[byte] >> bit) &0x3 ; +} + +uint8_t xive_source_pq_set (XiveSource *xsrc,uint32_t srcno,uint8_t pq) +{ +uint32_t byte = srcno /4 ; +uint32_t bit = (srcno %4 ) *2 ; +uint8_t old, new; + +assert (byte < xsrc->sbe_size); + + old = xsrc->sbe[byte]; + + new = xsrc->sbe[byte] & ~(0x3 << bit); + new |= (pq &0x3 ) << bit; + + xsrc->sbe[byte] = new; + +return (old >> bit) &0x3 ; +} + +static bool xive_source_pq_eoi (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +switch (old_pq) { +case XIVE_ESB_RESET : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_RESET ); +return false; +case XIVE_ESB_PENDING : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_RESET ); +return false; +case XIVE_ESB_QUEUED : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; +case XIVE_ESB_OFF : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_OFF ); +return false; +default : +g_assert_not_reached (); + } +} + +/* +* Returns whether the event notification should be forwarded. +*/ +static bool xive_source_pq_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +switch (old_pq) { +case XIVE_ESB_RESET : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; +case XIVE_ESB_PENDING : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_QUEUED ); +return false; +case XIVE_ESB_QUEUED : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_QUEUED ); +return false; +case XIVE_ESB_OFF : +xive_source_pq_set (xsrc, srcno,XIVE_ESB_OFF ); +return false; +default : +g_assert_not_reached (); + } +} + +/* hw/intc/xive.c line 108
Quoted 10 lines
hw/intc/xive.c new file +10
-0+* Forward the source event notification to the associated XiveFabric, +* the device owning the sources. +*/ +static void xive_source_notify (XiveSource *xsrc,int srcno) +{ + +} + +/* In a two pages ESB MMIO setting, even page is the trigger page, odd +* page is for management */ Can I understand from this that the result from this function is only meaningful in 2-pages mode?
Quoted 4 lines
Quoted 1 line
yes. May be I should rename it to
xive_source_is_even_page()?Seems very long winded. Maybe keep the name but have it check both whether it's an even page and also whether you're in 2pages mode.
yes. I had that in mind.
Quoted 40 lines
Quoted 8 lines
Quoted 7 lines
hw/intc/xive.c line 111
Quoted 4 lines
hw/intc/xive.c new file +3
-0+static inline bool xive_source_is_trigger_page (hwaddr addr) +{ +return !((addr >>16 ) &1 );Later on you seem to have both 4k and 64k variants list, but here you hardcode 64k. Is that a problem?
Quoted 6 lines
oups. This should be :
(addr >> (xsrc->esb_shift - 1))I did the tests with the spapr guest which uses 64k ESB MMIO pages. The check is only significant in a 2 pages setting.
Ok.
Quoted 23 lines
Quoted 10 lines
hw/intc/xive.c line 117
Quoted 6 lines
hw/intc/xive.c new file +6
-0+} + +static uint64_t xive_source_esb_read (void *opaque,hwaddr addr,unsigned size) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +uint32_t offset = addr &0xF00 ;You ignore the low bits of the address entirely, so effective you have a 256 byte range that's all aliases of the same register. Is that intentional?
yes but it's not entirely correct. The exact ranges are :
Load Store
0x000..0x3FFEOI and return 0|1 Trigger0x400..0x7FFEOI and return 0|1 EOI0x800..0xBFFreturn PQ undefined0xC00..0xCFFreturn PQ and PQ=00 PQ=000xD00..0xDFFreturn PQ and PQ=01 PQ=010xE00..0xDFFreturn PQ and PQ=10 PQ=100xF00..0xDFFreturn PQ and PQ=11 PQ=11
Quoted 5 lines
Quoted 3 lines
There is room for some improvements.
The trigger page in a two pages ESB MMIO settings only triggers on stores.
Ok.
I have fixed the ranges and added the above table as a comment in the code. it helps in understanding what are the MMIOs are.
Quoted 223 lines
Quoted 22 lines
Quoted 13 lines
Quoted 13 lines
hw/intc/xive.c new file +12
-0+uint32_t srcno = addr >> xsrc->esb_shift; +uint64_t ret =-1 ; + +if (xive_source_esb_2page (xsrc) &&xive_source_is_trigger_page (addr)) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid load on IRQ %d trigger page at " +"0x%" HWADDR_PRIx"\n" , srcno, addr); +return -1 ; + } + +switch (offset) { +case XIVE_ESB_LOAD_EOI :Quoted 8 lines
hw/intc/xive.c line 134
Quoted 5 lines
hw/intc/xive.c new file +5
-0+/* +* Load EOI is not the default source setting under QEMU, but +* this is what HW uses currently. +*/ + ret =xive_source_pq_eoi (xsrc, srcno);You're implicitly casting a bool return value into a u64 here, is that intentional?
Quoted 2 lines
yes. is that bad ? This is what the load is supposed to return in the transition algo.
No, that's fine, as long as just using the LSB in your return is correct. Just making sure I understood.
Quoted 67 lines
Quoted 58 lines
Quoted 58 lines
hw/intc/xive.c new file +58
-0+ +break ; + +case XIVE_ESB_GET : + ret =xive_source_pq_get (xsrc, srcno); +break ; + +case XIVE_ESB_SET_PQ_00 : +case XIVE_ESB_SET_PQ_01 : +case XIVE_ESB_SET_PQ_10 : +case XIVE_ESB_SET_PQ_11 : + ret =xive_source_pq_set (xsrc, srcno, (offset >>8 ) &0x3 ); +break ; +default : +qemu_log_mask (LOG_GUEST_ERROR ,"XIVE: invalid ESB addr %d\n" , offset); + } + +return ret; +} + +static void xive_source_esb_write (void *opaque,hwaddr addr, +uint64_t value,unsigned size) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +uint32_t offset = addr &0xF00 ; +uint32_t srcno = addr >> xsrc->esb_shift; +bool notify = false; + +switch (offset) { +case 0 : + notify =xive_source_pq_trigger (xsrc, srcno); +break ; + +case XIVE_ESB_STORE_EOI : +if (xive_source_is_trigger_page (addr)) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid store on IRQ %d trigger page at " +"0x%" HWADDR_PRIx"\n" , srcno, addr); +return ; + } + +if (!(xsrc->esb_flags &XIVE_SRC_STORE_EOI )) { +qemu_log_mask (LOG_GUEST_ERROR , +"XIVE: invalid Store EOI for IRQ %d\n" , srcno); +return ; + } + +/* If the Q bit is set, we should forward a new source event +* notification +*/ + notify =xive_source_pq_eoi (xsrc, srcno); +break ; + +default : +qemu_log_mask (LOG_GUEST_ERROR ,"XIVE: invalid ESB write addr %d\n" , + offset); +return ; + }Quoted 8 lines
hw/intc/xive.c line 197
Quoted 5 lines
hw/intc/xive.c new file +5
-0+ +/* Forward the source event notification for routing */ +if (notify) { +xive_source_notify (xsrc, srcno); + }EOI via this path calls notify, but the one via the read path doesn't. Is that correct?
Quoted 3 lines
No. I have given attention to the one page ESB MMIO setting + Store EOI in the emulated mode and not enough to the two pages ESB MMIO setting. This is a late change to be compatible with KVM. I will fix.
Ok.
Quoted 122 lines
Quoted 106 lines
Quoted 106 lines
hw/intc/xive.c new file +105
-0+} + +static const MemoryRegionOps xive_source_esb_ops = { + .read = xive_source_esb_read, + .write = xive_source_esb_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_set_irq (void *opaque,int srcno,int val) +{ +XiveSource *xsrc =XIVE_SOURCE (opaque); +bool notify = false; + +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } + +/* Forward the source event notification for routing */ +if (notify) { +xive_source_notify (xsrc, srcno); + } +} + +void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon) +{ +int i; + +monitor_printf (mon,"XIVE Source %6x ..%6x\n" , + xsrc->offset, xsrc->offset + xsrc->nr_irqs -1 ); +for (i =0 ; i < xsrc->nr_irqs; i++) { +uint8_t pq =xive_source_pq_get (xsrc, i); +uint32_t lisn = i + xsrc->offset; + +if (pq ==XIVE_ESB_OFF ) { +continue ; + } + +monitor_printf (mon," %4x %c%c\n" , lisn, + pq &XIVE_ESB_VAL_P ?'P' :'-' , + pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); + } +} + +static void xive_source_reset (DeviceState *dev) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); + +/* SBEs are initialized to 0b01 which corresponds to "ints off" */ +memset (xsrc->sbe,0x55 , xsrc->sbe_size); +} + +static void xive_source_realize (DeviceState *dev,Error **errp) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); + +if (!xsrc->nr_irqs) { +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_4K_2PAGE && + xsrc->esb_shift !=XIVE_ESB_64K && + xsrc->esb_shift !=XIVE_ESB_64K_2PAGE ) { +error_setg (errp,"Invalid ESB shift setting" ); +return ; + } + + xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, + xsrc->nr_irqs); + +/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ + xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 ); + xsrc->sbe =g_malloc0 (xsrc->sbe_size); + +/* TODO: H_INT_ESB support, which removing the ESB MMIOs */ + +memory_region_init_io (&xsrc->esb_mmio,OBJECT (xsrc), + &xive_source_esb_ops, xsrc,"xive.esb" , + (1ull << xsrc->esb_shift) * xsrc->nr_irqs); +sysbus_init_mmio (SYS_BUS_DEVICE (dev), &xsrc->esb_mmio); +} + +static const VMStateDescription vmstate_xive_source = { + .name =TYPE_XIVE_SOURCE , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT32_EQUAL (nr_irqs, XiveSource,NULL ), +VMSTATE_VBUFFER_UINT32 (sbe, XiveSource,1 ,NULL , sbe_size), +VMSTATE_END_OF_LIST () + }, +}; + +/* +* The default XIVE interrupt source setting for ESB MMIO is two 64k +* pages without Store EOI. This is in sync with KVM. Quoted 8 lines
hw/intc/xive.c line 307
Quoted 5 lines
hw/intc/xive.c new file +5
-0+*/ +static Property xive_source_properties[] = { +DEFINE_PROP_UINT64 ("flags" , XiveSource, esb_flags,0 ), +DEFINE_PROP_UINT32 ("nr-irqs" , XiveSource, nr_irqs,0 ), +DEFINE_PROP_UINT64 ("bar" , XiveSource, esb_base,0 ),Isn't this redundant with however the base address is handled through the SysBusDevice stuff (I forget the details)?
Storing the ESB MMIO base address under the XiveSource object is convenient later on in the
h_int_get_source_infohcall which make use of the helpers :hwaddr
xive_source_esb_trigger(XiveSource *xsrc, uint32_t srcno)hwaddrxive_source_esb_mgmt(XiveSource *xsrc, int srcno)
Quoted 8 lines
Quoted 4 lines
But it is only used in that place. So we could just store the ESB MMIO base address under the sPAPRXive controller. This makes some sense in the design, as we have to inform KVM of this address with a KVM device ioctl.
Well.. I really dislike the idea that you could change the actual MMIO mapping address in one place, but other bits of code would still think it was mapped somewhere else.
OK. I think that my last proposal of removing the ESB MMIO address from the source and letting the owning device, the sPAPR Xive controller in this case, but this is the same for PoweNV or PSI HB, handle the mapping goes in the direction you want to take ?
It does looks better in the overall XIVE model and the XiveSource object have no need of this address.
Quoted 101 lines
Quoted 101 lines
Quoted 83 lines
Quoted 83 lines
hw/intc/xive.c new file +28
-0+DEFINE_PROP_UINT32 ("shift" , XiveSource, esb_shift,XIVE_ESB_64K_2PAGE ), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xive_source_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->realize = xive_source_realize; + dc->reset = xive_source_reset; + dc->props = xive_source_properties; + dc->desc ="XIVE interrupt source" ; + dc->vmsd = &vmstate_xive_source; +} + +static const TypeInfo xive_source_info = { + .name =TYPE_XIVE_SOURCE , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (XiveSource), + .class_init = xive_source_class_init, +}; + +static void xive_register_types (void ) +{ +type_register_static (&xive_source_info); +} + +type_init (xive_register_types)include/hw/ppc/xive.h new file +48
-0@@ -0,0 +1,130 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_XIVE_H +#define PPC_XIVE_H + +#include "hw/sysbus.h" + +/* +* XIVE Interrupt Source +*/ + +#define TYPE_XIVE_SOURCE "xive-source" +#define XIVE_SOURCE (obj) OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE) + +/* +* XIVE Source Interrupt source characteristics, which define how the +* ESB are controlled. +*/ +#define XIVE_SRC_H_INT_ESB 0x1/* ESB managed with hcall H_INT_ESB */ +#define XIVE_SRC_STORE_EOI 0x4/* Store EOI supported */ + +typedef struct XiveSource { +SysBusDevice parent; + +/* IRQs */ +uint32_t nr_irqs; +uint32_t offset; +qemu_irq *qirqs; + +/* PQ bits */ +uint8_t *sbe; +uint32_t sbe_size; + +/* ESB memory region */ +uint64_t esb_flags; +hwaddr esb_base; +uint32_t esb_shift; +MemoryRegion esb_mmio; +}XiveSource ; + +/* Quoted 8 lines
include/hw/ppc/xive.h line 54
Quoted 6 lines
include/hw/ppc/xive.h new file +6
-0+* ESB MMIO setting. Can be one page, for both source triggering and +* source management, or two different pages. See below for magic +* values. +*/ +#define XIVE_ESB_4K 12/* PSI HB */ +#define XIVE_ESB_4K_2PAGE 17Should this be 13 instead of 17?
oups. obviously this is not used.
Quoted 6 lines
include/hw/ppc/xive.h line 56
Quoted 2 lines
include/hw/ppc/xive.h new file +2
-0+#define XIVE_ESB_64K 16 +#define XIVE_ESB_64K_2PAGE 17(Also, who the hell comes up with a brand new PIC and decides to have *4* different interface variants. But that's not your problem, I realise).
Quoted 9 lines
Quoted 4 lines
HW constraints on the different controllers which need to expose sources : PSI, PHB4. The internal sources of the XIVE interrupt controller can be configured to use 4K or 64K but I doubt the 4k will be ever used.
Sure, the hardware is different, but *why* is it different. This is a brand new design, you'd think they could come up with one variant that works for all the cases.
Yes this is interesting. I will ask the HW team.
Thanks.
C.
Re: [Qemu-devel] [PATCH v3 01/35] ppc/xive: introduce a XIVE interrupt source model
Quoted 31 lines · Cédric Le Goater
Quoted 30 lines · David Gibson
Quoted 29 lines · Cédric Le Goater
Quoted 28 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Each XIVE interrupt source is associated with a two bit state machine called an Event State Buffer (ESB) : the first bit "P" means that an interrupt is "pending" and waiting for an EOI and the bit "Q" (queued) means a new interrupt was triggered while another was still pending.
When an event is triggered, the associated interrupt state bits are fetched and modified and forwarded to the virtualization engine of the controller doing the routing. These can also be controlled by MMIO, to trigger events or turn off the sources for instance. See code for more details on the states and transitions.
On a sPAPR machine, the OS will obtain the address of the MMIO page of the ESB entry associated with a source and its characteristic using the
H_INT_GET_SOURCE_INFOhcall. On PowerNV, a similar OPAL call is used.The
xive_source_notify()routine is in charge forwarding the source event notification to the routing engine. It will be filled later on.Quoted 6 lines
Signed-off-by Cédric Le Goater <[email protected]>---
Changes since v2:- added support for Store EOI
- added support for two page MMIO setting like on KVMLooks generally sane to me, though I have a few queries.
[snip]
Quoted 27 lines
Quoted 18 lines
Quoted 18 lines
Quoted 10 lines
hw/intc/xive.c line 307
Quoted 7 lines
+ * The default XIVE interrupt source setting for ESB MMIO is two 64k
+ * pages without Store EOI. This is in sync with KVM.
+ */hw/intc/xive.c new file +4
-0+static Property xive_source_properties[] = { +DEFINE_PROP_UINT64 ("flags" , XiveSource, esb_flags,0 ), +DEFINE_PROP_UINT32 ("nr-irqs" , XiveSource, nr_irqs,0 ), +DEFINE_PROP_UINT64 ("bar" , XiveSource, esb_base,0 ),Isn't this redundant with however the base address is handled through the SysBusDevice stuff (I forget the details)?
Storing the ESB MMIO base address under the XiveSource object is convenient later on in the
h_int_get_source_infohcall which make use of the helpers :hwaddr
xive_source_esb_trigger(XiveSource *xsrc, uint32_t srcno)hwaddrxive_source_esb_mgmt(XiveSource *xsrc, int srcno)Quoted 8 lines
Quoted 4 lines
But it is only used in that place. So we could just store the ESB MMIO base address under the sPAPRXive controller. This makes some sense in the design, as we have to inform KVM of this address with a KVM device ioctl.
Well.. I really dislike the idea that you could change the actual MMIO mapping address in one place, but other bits of code would still think it was mapped somewhere else.
Quoted 7 lines
OK. I think that my last proposal of removing the ESB MMIO address from the source and letting the owning device, the sPAPR Xive controller in this case, but this is the same for PoweNV or PSI HB, handle the mapping goes in the direction you want to take ?
It does looks better in the overall XIVE model and the XiveSource object have no need of this address.
Yes, I think that's the way to go.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH v3 2/35 ppc/xive: add support for the LSI interrupt sources
In reply to Cédric Le GoaterThe 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.
--- hw/intc/xive.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/ppc/xive.h | 16 +++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-)
hw/intc/xive.c +50 -4
@@ -104,6 +104,21 @@ static void xive_source_notify(XiveSource *xsrc, int srcno) } +/* +* LSI interrupt sources use the P bit and a custom assertion flag +*/ +static bool xive_source_lsi_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +if (old_pq ==XIVE_ESB_RESET && + xsrc->status[srcno] &XIVE_STATUS_ASSERTED ) { +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; + } +return false; +} +/* In a two pages ESB MMIO setting, even page is the trigger page, odd * page is for management */ static inline bool xive_source_is_trigger_page (hwaddr addr)
@@ -133,6 +148,13 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)*/ ret =xive_source_pq_eoi (xsrc, srcno); +/* If the LSI source is still asserted, forward a new source +* event notification */ +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (xive_source_lsi_trigger (xsrc, srcno)) { +xive_source_notify (xsrc, srcno); + } + }break ;case XIVE_ESB_GET :
@@ -183,6 +205,14 @@ static void xive_source_esb_write(void *opaque, hwaddr addr,* notification */ notify =xive_source_pq_eoi (xsrc, srcno); + +/* LSI sources do not set the Q bit but they can still be +* asserted, in which case we should forward a new source +* event notification +*/ +if (xive_source_irq_is_lsi (xsrc, srcno)) { + notify =xive_source_lsi_trigger (xsrc, srcno); + }break ;default :
@@ -216,8 +246,17 @@ static void xive_source_set_irq(void *opaque, int srcno, int val)XiveSource *xsrc =XIVE_SOURCE (opaque);bool notify = false; -if (val) { - notify =xive_source_pq_trigger (xsrc, srcno); +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (val) { + xsrc->status[srcno] |=XIVE_STATUS_ASSERTED ; + }else { + xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED ; + } + notify =xive_source_lsi_trigger (xsrc, srcno); + }else { +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } }/* Forward the source event notification for routing */
@@ -234,13 +273,13 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon) xsrc->offset, xsrc->offset + xsrc->nr_irqs - 1);for (i =0 ; i < xsrc->nr_irqs; i++) {uint8_t pq =xive_source_pq_get (xsrc, i); -uint32_t lisn = i + xsrc->offset;if (pq ==XIVE_ESB_OFF ) {continue ; } -monitor_printf (mon," %4x %c%c\n" , lisn, +monitor_printf (mon," %4x %s %c%c\n" , i + xsrc->offset, +xive_source_irq_is_lsi (xsrc, i) ?"LSI" :"MSI" , pq &XIVE_ESB_VAL_P ?'P' :'-' , pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); }
@@ -249,6 +288,12 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon)static void xive_source_reset (DeviceState *dev) {XiveSource *xsrc =XIVE_SOURCE (dev); +int i; + +/* Keep the IRQ type */ +for (i =0 ; i < xsrc->nr_irqs; i++) { + xsrc->status[i] &= ~XIVE_STATUS_ASSERTED ; + }/* SBEs are initialized to 0b01 which corresponds to "ints off" */ memset (xsrc->sbe,0x55 , xsrc->sbe_size);
@@ -273,6 +318,7 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, xsrc->nr_irqs); + xsrc->status =g_malloc0 (xsrc->nr_irqs);/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 );
include/hw/ppc/xive.h +16 -0
@@ -33,6 +33,9 @@ typedef struct XiveSource {uint32_t nr_irqs;uint32_t offset;qemu_irq *qirqs; +#define XIVE_STATUS_LSI 0x1 +#define XIVE_STATUS_ASSERTED 0x2 +uint8_t *status;/* PQ bits */ uint8_t *sbe;
@@ -127,4 +130,17 @@ uint8_t xive_source_pq_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); +static inline bool xive_source_irq_is_lsi (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->status[srcno] &XIVE_STATUS_LSI ; +} + +static inline void xive_source_irq_set (XiveSource *xsrc,uint32_t srcno, +bool lsi) +{ +assert (srcno < xsrc->nr_irqs); + xsrc->status[srcno] |= lsi ?XIVE_STATUS_LSI :0 ; +} +#endif /* PPC_XIVE_H */
Signature · 1 line
2.13.6
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 128 lines · Cédric Le Goater
The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/ppc/xive.h | 16 +++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-)hw/intc/xive.c +50
-4@@ -104,6 +104,21 @@ static void xive_source_notify(XiveSource *xsrc, int srcno) } +/* +* LSI interrupt sources use the P bit and a custom assertion flag +*/ +static bool xive_source_lsi_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +if (old_pq ==XIVE_ESB_RESET && + xsrc->status[srcno] &XIVE_STATUS_ASSERTED ) { +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; + } +return false; +} +/* In a two pages ESB MMIO setting, even page is the trigger page, odd * page is for management */ static inline bool xive_source_is_trigger_page (hwaddr addr)@@ -133,6 +148,13 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)*/ ret =xive_source_pq_eoi (xsrc, srcno); +/* If the LSI source is still asserted, forward a new source +* event notification */ +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (xive_source_lsi_trigger (xsrc, srcno)) { +xive_source_notify (xsrc, srcno); + } + }break ;case XIVE_ESB_GET :@@ -183,6 +205,14 @@ static void xive_source_esb_write(void *opaque, hwaddr addr,* notification */ notify =xive_source_pq_eoi (xsrc, srcno); + +/* LSI sources do not set the Q bit but they can still be +* asserted, in which case we should forward a new source +* event notification +*/ +if (xive_source_irq_is_lsi (xsrc, srcno)) { + notify =xive_source_lsi_trigger (xsrc, srcno); + }break ;default :@@ -216,8 +246,17 @@ static void xive_source_set_irq(void *opaque, int srcno, int val)XiveSource *xsrc =XIVE_SOURCE (opaque);bool notify = false; -if (val) { - notify =xive_source_pq_trigger (xsrc, srcno); +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (val) { + xsrc->status[srcno] |=XIVE_STATUS_ASSERTED ; + }else { + xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED ; + } + notify =xive_source_lsi_trigger (xsrc, srcno); + }else { +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } }/* Forward the source event notification for routing */ @@ -234,13 +273,13 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon) xsrc->offset, xsrc->offset + xsrc->nr_irqs - 1);for (i =0 ; i < xsrc->nr_irqs; i++) {uint8_t pq =xive_source_pq_get (xsrc, i); -uint32_t lisn = i + xsrc->offset;if (pq ==XIVE_ESB_OFF ) {continue ; } -monitor_printf (mon," %4x %c%c\n" , lisn, +monitor_printf (mon," %4x %s %c%c\n" , i + xsrc->offset, +xive_source_irq_is_lsi (xsrc, i) ?"LSI" :"MSI" , pq &XIVE_ESB_VAL_P ?'P' :'-' , pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); }@@ -249,6 +288,12 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon)static void xive_source_reset (DeviceState *dev) {XiveSource *xsrc =XIVE_SOURCE (dev); +int i; + +/* Keep the IRQ type */ +for (i =0 ; i < xsrc->nr_irqs; i++) { + xsrc->status[i] &= ~XIVE_STATUS_ASSERTED ; + }/* SBEs are initialized to 0b01 which corresponds to "ints off" */ memset (xsrc->sbe,0x55 , xsrc->sbe_size);@@ -273,6 +318,7 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, xsrc->nr_irqs); + xsrc->status =g_malloc0 (xsrc->nr_irqs);/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 );include/hw/ppc/xive.h +0
-0
include/hw/ppc/xive.h typedef struct XiveSource { · line 38
Quoted 6 lines
include/hw/ppc/xive.h +3
-0@@ -33,6 +33,9 @@ typedef struct XiveSource {uint32_t nr_irqs;uint32_t offset;qemu_irq *qirqs; +#define XIVE_STATUS_LSI 0x1 +#define XIVE_STATUS_ASSERTED 0x2 +uint8_t *status;
I don't love the idea of mixing configuration information (STATUS_LSI) with runtime state information (ASSERTED) in the same field. Any reason not to have these as parallel bitmaps.
Come to that.. is there a compelling reason to allow any individual irq to be marked LSI or MSI, rather than using separate XiveSource objects for MSIs and LSIs?
include/hw/ppc/xive.h typedef struct XiveSource { · line 41
Quoted 2 lines
include/hw/ppc/xive.h +0
-0/* PQ bits */ uint8_t *sbe;
.. and come to that is there a reason to keep the ASSERTED bit in a separate array from sbe? AFAICT the actual 2-bit-per-irq layout is never exposed to the guests.
Or, even re-use the Q bit for asserted in LSIs (but report it as always 0 in the register read/write path).
Quoted 18 lines
include/hw/ppc/xive.h +13
-0@@ -127,4 +130,17 @@ uint8_t xive_source_pq_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); +static inline bool xive_source_irq_is_lsi (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->status[srcno] &XIVE_STATUS_LSI ; +} + +static inline void xive_source_irq_set (XiveSource *xsrc,uint32_t srcno, +bool lsi) +{ +assert (srcno < xsrc->nr_irqs); + xsrc->status[srcno] |= lsi ?XIVE_STATUS_LSI :0 ; +} +#endif /* PPC_XIVE_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/ppc/xive.h | 16 +++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-)hw/intc/xive.c +22
-0@@ -104,6 +104,21 @@ static void xive_source_notify(XiveSource *xsrc, int srcno) } +/* +* LSI interrupt sources use the P bit and a custom assertion flag +*/ +static bool xive_source_lsi_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +if (old_pq ==XIVE_ESB_RESET && + xsrc->status[srcno] &XIVE_STATUS_ASSERTED ) { +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; + } +return false; +} +/* In a two pages ESB MMIO setting, even page is the trigger page, odd * page is for management */ static inline bool xive_source_is_trigger_page (hwaddr addr)@@ -133,6 +148,13 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)*/ ret =xive_source_pq_eoi (xsrc, srcno); +/* If the LSI source is still asserted, forward a new source +* event notification */ +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (xive_source_lsi_trigger (xsrc, srcno)) { +xive_source_notify (xsrc, srcno); + } + }break ;
Quoted 13 lines
hw/intc/xive.c static void xive_source_esb_write(void *opaque, hwaddr addr, · line 215
Quoted 13 lines
hw/intc/xive.c +8
-0case XIVE_ESB_GET :@@ -183,6 +205,14 @@ static void xive_source_esb_write(void *opaque, hwaddr addr,* notification */ notify =xive_source_pq_eoi (xsrc, srcno); + +/* LSI sources do not set the Q bit but they can still be +* asserted, in which case we should forward a new source +* event notification +*/ +if (xive_source_irq_is_lsi (xsrc, srcno)) { + notify =xive_source_lsi_trigger (xsrc, srcno); + }
FYI, I have moved that common test under xive_source_pq_eoi()
Quoted 67 lines
Quoted 67 lines
hw/intc/xive.c +20
-4break ;default :@@ -216,8 +246,17 @@ static void xive_source_set_irq(void *opaque, int srcno, int val)XiveSource *xsrc =XIVE_SOURCE (opaque);bool notify = false; -if (val) { - notify =xive_source_pq_trigger (xsrc, srcno); +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (val) { + xsrc->status[srcno] |=XIVE_STATUS_ASSERTED ; + }else { + xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED ; + } + notify =xive_source_lsi_trigger (xsrc, srcno); + }else { +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } }/* Forward the source event notification for routing */ @@ -234,13 +273,13 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon) xsrc->offset, xsrc->offset + xsrc->nr_irqs - 1);for (i =0 ; i < xsrc->nr_irqs; i++) {uint8_t pq =xive_source_pq_get (xsrc, i); -uint32_t lisn = i + xsrc->offset;if (pq ==XIVE_ESB_OFF ) {continue ; } -monitor_printf (mon," %4x %c%c\n" , lisn, +monitor_printf (mon," %4x %s %c%c\n" , i + xsrc->offset, +xive_source_irq_is_lsi (xsrc, i) ?"LSI" :"MSI" , pq &XIVE_ESB_VAL_P ?'P' :'-' , pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); }@@ -249,6 +288,12 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon)static void xive_source_reset (DeviceState *dev) {XiveSource *xsrc =XIVE_SOURCE (dev); +int i; + +/* Keep the IRQ type */ +for (i =0 ; i < xsrc->nr_irqs; i++) { + xsrc->status[i] &= ~XIVE_STATUS_ASSERTED ; + }/* SBEs are initialized to 0b01 which corresponds to "ints off" */ memset (xsrc->sbe,0x55 , xsrc->sbe_size);@@ -273,6 +318,7 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, xsrc->nr_irqs); + xsrc->status =g_malloc0 (xsrc->nr_irqs);/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 );include/hw/ppc/xive.h +0
-0@@ -33,6 +33,9 @@ typedef struct XiveSource {uint32_t nr_irqs;uint32_t offset;
Quoted 8 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 38
Quoted 4 lines
include/hw/ppc/xive.h +3
-0qemu_irq *qirqs; +#define XIVE_STATUS_LSI 0x1 +#define XIVE_STATUS_ASSERTED 0x2 +uint8_t *status;I don't love the idea of mixing configuration information (
STATUS_LSI) with runtime state information (ASSERTED) in the same field. Any reason not to have these as parallel bitmaps.
none. I can change that.
Quoted 3 lines
Come to that.. is there a compelling reason to allow any individual irq to be marked LSI or MSI, rather than using separate XiveSource objects for MSIs and LSIs?
yes. I would have preferred two distinct interrupt source objects but this is to be compatible with XICS, which uses only one. If we want to be able to change interrupt mode, the IRQ number space should be organized in the exact same way. Or we should change XICS also.
Also, the change (a bitmap) is really small.
Quoted 6 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 41
Quoted 2 lines
include/hw/ppc/xive.h +0
-0/* PQ bits */ uint8_t *sbe;.. and come to that is there a reason to keep the ASSERTED bit in a separate array from sbe? AFAICT the actual 2-bit-per-irq layout is never exposed to the guests.
indeed. we always use the xive_source_pq_get/set() helpers to manipulate the PQ bits. So we could add an extra bit for the ASSERT without too much changes. Could also we put the type there or would you still prefer a bitmap ?
Quoted 2 lines
Or, even re-use the Q bit for asserted in LSIs (but report it as always 0 in the register read/write path).
I would prefer to add extra status bits. It is easier to debug.
Thanks,
C.
Quoted 19 lines
Quoted 18 lines
include/hw/ppc/xive.h +13
-0@@ -127,4 +130,17 @@ uint8_t xive_source_pq_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); +static inline bool xive_source_irq_is_lsi (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->status[srcno] &XIVE_STATUS_LSI ; +} + +static inline void xive_source_irq_set (XiveSource *xsrc,uint32_t srcno, +bool lsi) +{ +assert (srcno < xsrc->nr_irqs); + xsrc->status[srcno] |= lsi ?XIVE_STATUS_LSI :0 ; +} +#endif /* PPC_XIVE_H */
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 52 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/ppc/xive.h | 16 +++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-)hw/intc/xive.c +22
-0@@ -104,6 +104,21 @@ static void xive_source_notify(XiveSource *xsrc, int srcno) } +/* +* LSI interrupt sources use the P bit and a custom assertion flag +*/ +static bool xive_source_lsi_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +if (old_pq ==XIVE_ESB_RESET && + xsrc->status[srcno] &XIVE_STATUS_ASSERTED ) { +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; + } +return false; +} +/* In a two pages ESB MMIO setting, even page is the trigger page, odd * page is for management */ static inline bool xive_source_is_trigger_page (hwaddr addr)@@ -133,6 +148,13 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)*/ ret =xive_source_pq_eoi (xsrc, srcno); +/* If the LSI source is still asserted, forward a new source +* event notification */ +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (xive_source_lsi_trigger (xsrc, srcno)) { +xive_source_notify (xsrc, srcno); + } + }break ;
Quoted 15 lines
Quoted 5 lines
Quoted 5 lines
hw/intc/xive.c +0
-0case XIVE_ESB_GET :@@ -183,6 +205,14 @@ static void xive_source_esb_write(void *opaque, hwaddr addr,* notification */ notify =xive_source_pq_eoi (xsrc, srcno);Quoted 8 lines
hw/intc/xive.c static void xive_source_esb_write(void *opaque, hwaddr addr, · line 215
Quoted 8 lines
hw/intc/xive.c +8
-0+ +/* LSI sources do not set the Q bit but they can still be +* asserted, in which case we should forward a new source +* event notification +*/ +if (xive_source_irq_is_lsi (xsrc, srcno)) { + notify =xive_source_lsi_trigger (xsrc, srcno); + }FYI, I have moved that common test under
xive_source_pq_eoi()
Ok.
Quoted 76 lines
Quoted 67 lines
Quoted 67 lines
hw/intc/xive.c +20
-4break ;default :@@ -216,8 +246,17 @@ static void xive_source_set_irq(void *opaque, int srcno, int val)XiveSource *xsrc =XIVE_SOURCE (opaque);bool notify = false; -if (val) { - notify =xive_source_pq_trigger (xsrc, srcno); +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (val) { + xsrc->status[srcno] |=XIVE_STATUS_ASSERTED ; + }else { + xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED ; + } + notify =xive_source_lsi_trigger (xsrc, srcno); + }else { +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } }/* Forward the source event notification for routing */ @@ -234,13 +273,13 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon) xsrc->offset, xsrc->offset + xsrc->nr_irqs - 1);for (i =0 ; i < xsrc->nr_irqs; i++) {uint8_t pq =xive_source_pq_get (xsrc, i); -uint32_t lisn = i + xsrc->offset;if (pq ==XIVE_ESB_OFF ) {continue ; } -monitor_printf (mon," %4x %c%c\n" , lisn, +monitor_printf (mon," %4x %s %c%c\n" , i + xsrc->offset, +xive_source_irq_is_lsi (xsrc, i) ?"LSI" :"MSI" , pq &XIVE_ESB_VAL_P ?'P' :'-' , pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); }@@ -249,6 +288,12 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon)static void xive_source_reset (DeviceState *dev) {XiveSource *xsrc =XIVE_SOURCE (dev); +int i; + +/* Keep the IRQ type */ +for (i =0 ; i < xsrc->nr_irqs; i++) { + xsrc->status[i] &= ~XIVE_STATUS_ASSERTED ; + }/* SBEs are initialized to 0b01 which corresponds to "ints off" */ memset (xsrc->sbe,0x55 , xsrc->sbe_size);@@ -273,6 +318,7 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, xsrc->nr_irqs); + xsrc->status =g_malloc0 (xsrc->nr_irqs);/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 );include/hw/ppc/xive.h +0
-0@@ -33,6 +33,9 @@ typedef struct XiveSource {uint32_t nr_irqs;uint32_t offset;Quoted 8 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 38
Quoted 4 lines
include/hw/ppc/xive.h +3
-0qemu_irq *qirqs; +#define XIVE_STATUS_LSI 0x1 +#define XIVE_STATUS_ASSERTED 0x2 +uint8_t *status;I don't love the idea of mixing configuration information (
STATUS_LSI) with runtime state information (ASSERTED) in the same field. Any reason not to have these as parallel bitmaps.
Quoted 1 line
none. I can change that.
Ok.
Quoted 10 lines
Quoted 3 lines
Come to that.. is there a compelling reason to allow any individual irq to be marked LSI or MSI, rather than using separate XiveSource objects for MSIs and LSIs?
yes. I would have preferred two distinct interrupt source objects but this is to be compatible with XICS, which uses only one. If we want to be able to change interrupt mode, the IRQ number space should be organized in the exact same way. Or we should change XICS also.
Also, the change (a bitmap) is really small.
Hrm, but since XIVE supports thousands of irqs, it could be quite a large bitmap.
It's not impossible - in fact, not really even that hard - to change the existing irq layout on xics. It does need a new machine type variant, of course.
Quoted 11 lines
Quoted 6 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 41
Quoted 2 lines
include/hw/ppc/xive.h +0
-0/* PQ bits */ uint8_t *sbe;.. and come to that is there a reason to keep the ASSERTED bit in a separate array from sbe? AFAICT the actual 2-bit-per-irq layout is never exposed to the guests.
indeed. we always use the xive_source_pq_get/set() helpers to manipulate the PQ bits. So we could add an extra bit for the ASSERT without too much changes. Could also we put the type there or would you still prefer a bitmap ?
I'd prefer the type (config information) be separate from the P, Q, ASSERTED bits (state information).
Quoted 29 lines
Quoted 2 lines
Or, even re-use the Q bit for asserted in LSIs (but report it as always 0 in the register read/write path).
I would prefer to add extra status bits. It is easier to debug.
Thanks,
C.
Quoted 19 lines
Quoted 18 lines
include/hw/ppc/xive.h +13
-0@@ -127,4 +130,17 @@ uint8_t xive_source_pq_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); +static inline bool xive_source_irq_is_lsi (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->status[srcno] &XIVE_STATUS_LSI ; +} + +static inline void xive_source_irq_set (XiveSource *xsrc,uint32_t srcno, +bool lsi) +{ +assert (srcno < xsrc->nr_irqs); + xsrc->status[srcno] |= lsi ?XIVE_STATUS_LSI :0 ; +} +#endif /* PPC_XIVE_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 160 lines · David Gibson
Quoted 52 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/ppc/xive.h | 16 +++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-)hw/intc/xive.c +22
-0@@ -104,6 +104,21 @@ static void xive_source_notify(XiveSource *xsrc, int srcno) } +/* +* LSI interrupt sources use the P bit and a custom assertion flag +*/ +static bool xive_source_lsi_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +if (old_pq ==XIVE_ESB_RESET && + xsrc->status[srcno] &XIVE_STATUS_ASSERTED ) { +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; + } +return false; +} +/* In a two pages ESB MMIO setting, even page is the trigger page, odd * page is for management */ static inline bool xive_source_is_trigger_page (hwaddr addr)@@ -133,6 +148,13 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)*/ ret =xive_source_pq_eoi (xsrc, srcno); +/* If the LSI source is still asserted, forward a new source +* event notification */ +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (xive_source_lsi_trigger (xsrc, srcno)) { +xive_source_notify (xsrc, srcno); + } + }break ;Quoted 15 lines
Quoted 5 lines
Quoted 5 lines
hw/intc/xive.c +0
-0case XIVE_ESB_GET :@@ -183,6 +205,14 @@ static void xive_source_esb_write(void *opaque, hwaddr addr,* notification */ notify =xive_source_pq_eoi (xsrc, srcno);Quoted 8 lines
hw/intc/xive.c static void xive_source_esb_write(void *opaque, hwaddr addr, · line 215
Quoted 8 lines
hw/intc/xive.c +8
-0+ +/* LSI sources do not set the Q bit but they can still be +* asserted, in which case we should forward a new source +* event notification +*/ +if (xive_source_irq_is_lsi (xsrc, srcno)) { + notify =xive_source_lsi_trigger (xsrc, srcno); + }FYI, I have moved that common test under
xive_source_pq_eoi()Ok.
Quoted 76 lines
Quoted 67 lines
Quoted 67 lines
hw/intc/xive.c +20
-4break ;default :@@ -216,8 +246,17 @@ static void xive_source_set_irq(void *opaque, int srcno, int val)XiveSource *xsrc =XIVE_SOURCE (opaque);bool notify = false; -if (val) { - notify =xive_source_pq_trigger (xsrc, srcno); +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (val) { + xsrc->status[srcno] |=XIVE_STATUS_ASSERTED ; + }else { + xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED ; + } + notify =xive_source_lsi_trigger (xsrc, srcno); + }else { +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } }/* Forward the source event notification for routing */ @@ -234,13 +273,13 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon) xsrc->offset, xsrc->offset + xsrc->nr_irqs - 1);for (i =0 ; i < xsrc->nr_irqs; i++) {uint8_t pq =xive_source_pq_get (xsrc, i); -uint32_t lisn = i + xsrc->offset;if (pq ==XIVE_ESB_OFF ) {continue ; } -monitor_printf (mon," %4x %c%c\n" , lisn, +monitor_printf (mon," %4x %s %c%c\n" , i + xsrc->offset, +xive_source_irq_is_lsi (xsrc, i) ?"LSI" :"MSI" , pq &XIVE_ESB_VAL_P ?'P' :'-' , pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); }@@ -249,6 +288,12 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon)static void xive_source_reset (DeviceState *dev) {XiveSource *xsrc =XIVE_SOURCE (dev); +int i; + +/* Keep the IRQ type */ +for (i =0 ; i < xsrc->nr_irqs; i++) { + xsrc->status[i] &= ~XIVE_STATUS_ASSERTED ; + }/* SBEs are initialized to 0b01 which corresponds to "ints off" */ memset (xsrc->sbe,0x55 , xsrc->sbe_size);@@ -273,6 +318,7 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, xsrc->nr_irqs); + xsrc->status =g_malloc0 (xsrc->nr_irqs);/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 );include/hw/ppc/xive.h +0
-0@@ -33,6 +33,9 @@ typedef struct XiveSource {uint32_t nr_irqs;uint32_t offset;Quoted 8 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 38
Quoted 4 lines
include/hw/ppc/xive.h +3
-0qemu_irq *qirqs; +#define XIVE_STATUS_LSI 0x1 +#define XIVE_STATUS_ASSERTED 0x2 +uint8_t *status;I don't love the idea of mixing configuration information (
STATUS_LSI) with runtime state information (ASSERTED) in the same field. Any reason not to have these as parallel bitmaps.Quoted 1 line
none. I can change that.
Ok.
Quoted 9 lines
Quoted 3 lines
Come to that.. is there a compelling reason to allow any individual irq to be marked LSI or MSI, rather than using separate XiveSource objects for MSIs and LSIs?
yes. I would have preferred two distinct interrupt source objects but this is to be compatible with XICS, which uses only one. If we want to be able to change interrupt mode, the IRQ number space should be organized in the exact same way. Or we should change XICS also.
Quoted 4 lines
Quoted 1 line
Also, the change (a bitmap) is really small.
Hrm, but since XIVE supports thousands of irqs, it could be quite a large bitmap.
Yes. The change is small, not the bitmap.
Quoted 3 lines
It's not impossible - in fact, not really even that hard - to change the existing irq layout on xics. It does need a new machine type variant, of course.
I did some work on that topic a while ago :
https://patchwork.ozlabs.org/cover/836782/
But we stopped exploring the idea. May be it was not the good approach. The PHBs LSIs would benefit from such a split though.
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 41
Quoted 2 lines
include/hw/ppc/xive.h +0
-0/* PQ bits */ uint8_t *sbe;.. and come to that is there a reason to keep the ASSERTED bit in a separate array from sbe? AFAICT the actual 2-bit-per-irq layout is never exposed to the guests.
Quoted 7 lines
Quoted 4 lines
indeed. we always use the xive_source_pq_get/set() helpers to manipulate the PQ bits. So we could add an extra bit for the ASSERT without too much changes. Could also we put the type there or would you still prefer a bitmap ?
I'd prefer the type (config information) be separate from the P, Q, ASSERTED bits (state information).
ok. So I will use the 'uint8_t *status' for P, Q, ASSERT, which leaves 5 bits available, but I don't think it is really worth the pain to optimize the size. The sbe array will disappear and we will have a bitmap for the type.
Thanks,
C.
Quoted 30 lines
Quoted 29 lines
Quoted 2 lines
Or, even re-use the Q bit for asserted in LSIs (but report it as always 0 in the register read/write path).
I would prefer to add extra status bits. It is easier to debug.
Thanks,
C.
Quoted 19 lines
Quoted 18 lines
include/hw/ppc/xive.h +13
-0@@ -127,4 +130,17 @@ uint8_t xive_source_pq_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); +static inline bool xive_source_irq_is_lsi (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->status[srcno] &XIVE_STATUS_LSI ; +} + +static inline void xive_source_irq_set (XiveSource *xsrc,uint32_t srcno, +bool lsi) +{ +assert (srcno < xsrc->nr_irqs); + xsrc->status[srcno] |= lsi ?XIVE_STATUS_LSI :0 ; +} +#endif /* PPC_XIVE_H */
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 172 lines · Cédric Le Goater
Quoted 160 lines · David Gibson
Quoted 52 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/ppc/xive.h | 16 +++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-)hw/intc/xive.c +22
-0@@ -104,6 +104,21 @@ static void xive_source_notify(XiveSource *xsrc, int srcno) } +/* +* LSI interrupt sources use the P bit and a custom assertion flag +*/ +static bool xive_source_lsi_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +if (old_pq ==XIVE_ESB_RESET && + xsrc->status[srcno] &XIVE_STATUS_ASSERTED ) { +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; + } +return false; +} +/* In a two pages ESB MMIO setting, even page is the trigger page, odd * page is for management */ static inline bool xive_source_is_trigger_page (hwaddr addr)@@ -133,6 +148,13 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)*/ ret =xive_source_pq_eoi (xsrc, srcno); +/* If the LSI source is still asserted, forward a new source +* event notification */ +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (xive_source_lsi_trigger (xsrc, srcno)) { +xive_source_notify (xsrc, srcno); + } + }break ;Quoted 15 lines
Quoted 5 lines
Quoted 5 lines
hw/intc/xive.c +0
-0case XIVE_ESB_GET :@@ -183,6 +205,14 @@ static void xive_source_esb_write(void *opaque, hwaddr addr,* notification */ notify =xive_source_pq_eoi (xsrc, srcno);Quoted 8 lines
hw/intc/xive.c static void xive_source_esb_write(void *opaque, hwaddr addr, · line 215
Quoted 8 lines
hw/intc/xive.c +8
-0+ +/* LSI sources do not set the Q bit but they can still be +* asserted, in which case we should forward a new source +* event notification +*/ +if (xive_source_irq_is_lsi (xsrc, srcno)) { + notify =xive_source_lsi_trigger (xsrc, srcno); + }FYI, I have moved that common test under
xive_source_pq_eoi()Ok.
Quoted 76 lines
Quoted 67 lines
Quoted 67 lines
hw/intc/xive.c +20
-4break ;default :@@ -216,8 +246,17 @@ static void xive_source_set_irq(void *opaque, int srcno, int val)XiveSource *xsrc =XIVE_SOURCE (opaque);bool notify = false; -if (val) { - notify =xive_source_pq_trigger (xsrc, srcno); +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (val) { + xsrc->status[srcno] |=XIVE_STATUS_ASSERTED ; + }else { + xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED ; + } + notify =xive_source_lsi_trigger (xsrc, srcno); + }else { +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } }/* Forward the source event notification for routing */ @@ -234,13 +273,13 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon) xsrc->offset, xsrc->offset + xsrc->nr_irqs - 1);for (i =0 ; i < xsrc->nr_irqs; i++) {uint8_t pq =xive_source_pq_get (xsrc, i); -uint32_t lisn = i + xsrc->offset;if (pq ==XIVE_ESB_OFF ) {continue ; } -monitor_printf (mon," %4x %c%c\n" , lisn, +monitor_printf (mon," %4x %s %c%c\n" , i + xsrc->offset, +xive_source_irq_is_lsi (xsrc, i) ?"LSI" :"MSI" , pq &XIVE_ESB_VAL_P ?'P' :'-' , pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); }@@ -249,6 +288,12 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon)static void xive_source_reset (DeviceState *dev) {XiveSource *xsrc =XIVE_SOURCE (dev); +int i; + +/* Keep the IRQ type */ +for (i =0 ; i < xsrc->nr_irqs; i++) { + xsrc->status[i] &= ~XIVE_STATUS_ASSERTED ; + }/* SBEs are initialized to 0b01 which corresponds to "ints off" */ memset (xsrc->sbe,0x55 , xsrc->sbe_size);@@ -273,6 +318,7 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, xsrc->nr_irqs); + xsrc->status =g_malloc0 (xsrc->nr_irqs);/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 );include/hw/ppc/xive.h +0
-0@@ -33,6 +33,9 @@ typedef struct XiveSource {uint32_t nr_irqs;uint32_t offset;Quoted 8 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 38
Quoted 4 lines
include/hw/ppc/xive.h +3
-0qemu_irq *qirqs; +#define XIVE_STATUS_LSI 0x1 +#define XIVE_STATUS_ASSERTED 0x2 +uint8_t *status;I don't love the idea of mixing configuration information (
STATUS_LSI) with runtime state information (ASSERTED) in the same field. Any reason not to have these as parallel bitmaps.Quoted 1 line
none. I can change that.
Ok.
Quoted 9 lines
Quoted 3 lines
Come to that.. is there a compelling reason to allow any individual irq to be marked LSI or MSI, rather than using separate XiveSource objects for MSIs and LSIs?
yes. I would have preferred two distinct interrupt source objects but this is to be compatible with XICS, which uses only one. If we want to be able to change interrupt mode, the IRQ number space should be organized in the exact same way. Or we should change XICS also.
Quoted 4 lines
Quoted 1 line
Also, the change (a bitmap) is really small.
Hrm, but since XIVE supports thousands of irqs, it could be quite a large bitmap.
Yes. The change is small, not the bitmap.
Quoted 3 lines
It's not impossible - in fact, not really even that hard - to change the existing irq layout on xics. It does need a new machine type variant, of course.
Quoted 6 lines
I did some work on that topic a while ago :
https://patchwork.ozlabs.org/cover/836782/But we stopped exploring the idea. May be it was not the good approach. The PHBs LSIs would benefit from such a split though.
So, no, I don't think that was a good approach, but that doesn't mean other ways of rearranging the irq numbers aren't ok. The thing here is that we don't want to think of an "irq allocator" - there are some bits like that in there already, but they were always a mistake.
We have lots of irq space (both XICS and XIVE) so instead we should come up with a static mapping of irqs to devices.
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
Quoted 6 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 41
Quoted 2 lines
include/hw/ppc/xive.h +0
-0/* PQ bits */ uint8_t *sbe;.. and come to that is there a reason to keep the ASSERTED bit in a separate array from sbe? AFAICT the actual 2-bit-per-irq layout is never exposed to the guests.
indeed. we always use the xive_source_pq_get/set() helpers to manipulate the PQ bits. So we could add an extra bit for the ASSERT without too much changes. Could also we put the type there or would you still prefer a bitmap ?
Quoted 6 lines
Quoted 2 lines
I'd prefer the type (config information) be separate from the P, Q, ASSERTED bits (state information).
ok. So I will use the '
uint8_t*status' for P, Q, ASSERT, which leaves 5 bits available, but I don't think it is really worth the pain to optimize the size.
Sure. I don't really care if it's packed or not.
Quoted 2 lines
The sbe array will disappear and we will have
a bitmap for the type.
We may or may not keep the type bitmap based on the discussion above, but in any case this is a good step forward.
Quoted 36 lines
Thanks,
C.
Quoted 30 lines
Quoted 29 lines
Quoted 2 lines
Or, even re-use the Q bit for asserted in LSIs (but report it as always 0 in the register read/write path).
I would prefer to add extra status bits. It is easier to debug.
Thanks,
C.
Quoted 19 lines
Quoted 18 lines
include/hw/ppc/xive.h +13
-0@@ -127,4 +130,17 @@ uint8_t xive_source_pq_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); +static inline bool xive_source_irq_is_lsi (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->status[srcno] &XIVE_STATUS_LSI ; +} + +static inline void xive_source_irq_set (XiveSource *xsrc,uint32_t srcno, +bool lsi) +{ +assert (srcno < xsrc->nr_irqs); + xsrc->status[srcno] |= lsi ?XIVE_STATUS_LSI :0 ; +} +#endif /* PPC_XIVE_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 180 lines · David Gibson
Quoted 172 lines · Cédric Le Goater
Quoted 160 lines · David Gibson
Quoted 52 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/ppc/xive.h | 16 +++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-)hw/intc/xive.c +22
-0@@ -104,6 +104,21 @@ static void xive_source_notify(XiveSource *xsrc, int srcno) } +/* +* LSI interrupt sources use the P bit and a custom assertion flag +*/ +static bool xive_source_lsi_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +if (old_pq ==XIVE_ESB_RESET && + xsrc->status[srcno] &XIVE_STATUS_ASSERTED ) { +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; + } +return false; +} +/* In a two pages ESB MMIO setting, even page is the trigger page, odd * page is for management */ static inline bool xive_source_is_trigger_page (hwaddr addr)@@ -133,6 +148,13 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)*/ ret =xive_source_pq_eoi (xsrc, srcno); +/* If the LSI source is still asserted, forward a new source +* event notification */ +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (xive_source_lsi_trigger (xsrc, srcno)) { +xive_source_notify (xsrc, srcno); + } + }break ;Quoted 15 lines
Quoted 5 lines
Quoted 5 lines
hw/intc/xive.c +0
-0case XIVE_ESB_GET :@@ -183,6 +205,14 @@ static void xive_source_esb_write(void *opaque, hwaddr addr,* notification */ notify =xive_source_pq_eoi (xsrc, srcno);Quoted 8 lines
hw/intc/xive.c static void xive_source_esb_write(void *opaque, hwaddr addr, · line 215
Quoted 8 lines
hw/intc/xive.c +8
-0+ +/* LSI sources do not set the Q bit but they can still be +* asserted, in which case we should forward a new source +* event notification +*/ +if (xive_source_irq_is_lsi (xsrc, srcno)) { + notify =xive_source_lsi_trigger (xsrc, srcno); + }FYI, I have moved that common test under
xive_source_pq_eoi()Ok.
Quoted 76 lines
Quoted 67 lines
Quoted 67 lines
hw/intc/xive.c +20
-4break ;default :@@ -216,8 +246,17 @@ static void xive_source_set_irq(void *opaque, int srcno, int val)XiveSource *xsrc =XIVE_SOURCE (opaque);bool notify = false; -if (val) { - notify =xive_source_pq_trigger (xsrc, srcno); +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (val) { + xsrc->status[srcno] |=XIVE_STATUS_ASSERTED ; + }else { + xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED ; + } + notify =xive_source_lsi_trigger (xsrc, srcno); + }else { +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } }/* Forward the source event notification for routing */ @@ -234,13 +273,13 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon) xsrc->offset, xsrc->offset + xsrc->nr_irqs - 1);for (i =0 ; i < xsrc->nr_irqs; i++) {uint8_t pq =xive_source_pq_get (xsrc, i); -uint32_t lisn = i + xsrc->offset;if (pq ==XIVE_ESB_OFF ) {continue ; } -monitor_printf (mon," %4x %c%c\n" , lisn, +monitor_printf (mon," %4x %s %c%c\n" , i + xsrc->offset, +xive_source_irq_is_lsi (xsrc, i) ?"LSI" :"MSI" , pq &XIVE_ESB_VAL_P ?'P' :'-' , pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); }@@ -249,6 +288,12 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon)static void xive_source_reset (DeviceState *dev) {XiveSource *xsrc =XIVE_SOURCE (dev); +int i; + +/* Keep the IRQ type */ +for (i =0 ; i < xsrc->nr_irqs; i++) { + xsrc->status[i] &= ~XIVE_STATUS_ASSERTED ; + }/* SBEs are initialized to 0b01 which corresponds to "ints off" */ memset (xsrc->sbe,0x55 , xsrc->sbe_size);@@ -273,6 +318,7 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, xsrc->nr_irqs); + xsrc->status =g_malloc0 (xsrc->nr_irqs);/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 );include/hw/ppc/xive.h +0
-0@@ -33,6 +33,9 @@ typedef struct XiveSource {uint32_t nr_irqs;uint32_t offset;Quoted 8 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 38
Quoted 4 lines
include/hw/ppc/xive.h +3
-0qemu_irq *qirqs; +#define XIVE_STATUS_LSI 0x1 +#define XIVE_STATUS_ASSERTED 0x2 +uint8_t *status;I don't love the idea of mixing configuration information (
STATUS_LSI) with runtime state information (ASSERTED) in the same field. Any reason not to have these as parallel bitmaps.Quoted 1 line
none. I can change that.
Ok.
Quoted 9 lines
Quoted 3 lines
Come to that.. is there a compelling reason to allow any individual irq to be marked LSI or MSI, rather than using separate XiveSource objects for MSIs and LSIs?
yes. I would have preferred two distinct interrupt source objects but this is to be compatible with XICS, which uses only one. If we want to be able to change interrupt mode, the IRQ number space should be organized in the exact same way. Or we should change XICS also.
Quoted 4 lines
Quoted 1 line
Also, the change (a bitmap) is really small.
Hrm, but since XIVE supports thousands of irqs, it could be quite a large bitmap.
Yes. The change is small, not the bitmap.
Quoted 3 lines
It's not impossible - in fact, not really even that hard - to change the existing irq layout on xics. It does need a new machine type variant, of course.
Quoted 6 lines
I did some work on that topic a while ago :
https://patchwork.ozlabs.org/cover/836782/But we stopped exploring the idea. May be it was not the good approach. The PHBs LSIs would benefit from such a split though.
Quoted 7 lines
So, no, I don't think that was a good approach, but that doesn't mean other ways of rearranging the irq numbers aren't ok. The thing here is that we don't want to think of an "irq allocator" - there are some bits like that in there already, but they were always a mistake.
We have lots of irq space (both XICS and XIVE) so instead we should come up with a static mapping of irqs to devices.
yes. I would prefer that also.
We could change the spapr_irq_alloc() routine to get a block of IRQs in the range defined for a device family, and use a device id to offset in that family range ? Here are some figures :
device family block size max devices
EVENT_CLASS_EPOW 1 1 EVENT_CLASS_HOT_PLUG 1 1 VIO_VSCSI 1 10 VIO_LLAN 1 10 VIO_VTY 1 5
PCI/PHB 1024 5
C.
Quoted 64 lines
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
Quoted 6 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 41
Quoted 2 lines
include/hw/ppc/xive.h +0
-0/* PQ bits */ uint8_t *sbe;.. and come to that is there a reason to keep the ASSERTED bit in a separate array from sbe? AFAICT the actual 2-bit-per-irq layout is never exposed to the guests.
indeed. we always use the xive_source_pq_get/set() helpers to manipulate the PQ bits. So we could add an extra bit for the ASSERT without too much changes. Could also we put the type there or would you still prefer a bitmap ?
Quoted 6 lines
Quoted 2 lines
I'd prefer the type (config information) be separate from the P, Q, ASSERTED bits (state information).
ok. So I will use the '
uint8_t*status' for P, Q, ASSERT, which leaves 5 bits available, but I don't think it is really worth the pain to optimize the size.Sure. I don't really care if it's packed or not.
Quoted 2 lines
The sbe array will disappear and we will have
a bitmap for the type.We may or may not keep the type bitmap based on the discussion above, but in any case this is a good step forward.
Quoted 36 lines
Thanks,
C.
Quoted 30 lines
Quoted 29 lines
Quoted 2 lines
Or, even re-use the Q bit for asserted in LSIs (but report it as always 0 in the register read/write path).
I would prefer to add extra status bits. It is easier to debug.
Thanks,
C.
Quoted 19 lines
Quoted 18 lines
include/hw/ppc/xive.h +13
-0@@ -127,4 +130,17 @@ uint8_t xive_source_pq_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);void xive_source_pic_print_info (XiveSource *xsrc,Monitor *mon); +static inline bool xive_source_irq_is_lsi (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return xsrc->status[srcno] &XIVE_STATUS_LSI ; +} + +static inline void xive_source_irq_set (XiveSource *xsrc,uint32_t srcno, +bool lsi) +{ +assert (srcno < xsrc->nr_irqs); + xsrc->status[srcno] |= lsi ?XIVE_STATUS_LSI :0 ; +} +#endif /* PPC_XIVE_H */
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 197 lines · Cédric Le Goater
Quoted 180 lines · David Gibson
Quoted 172 lines · Cédric Le Goater
Quoted 160 lines · David Gibson
Quoted 52 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/ppc/xive.h | 16 +++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-)hw/intc/xive.c +22
-0@@ -104,6 +104,21 @@ static void xive_source_notify(XiveSource *xsrc, int srcno) } +/* +* LSI interrupt sources use the P bit and a custom assertion flag +*/ +static bool xive_source_lsi_trigger (XiveSource *xsrc,uint32_t srcno) +{ +uint8_t old_pq =xive_source_pq_get (xsrc, srcno); + +if (old_pq ==XIVE_ESB_RESET && + xsrc->status[srcno] &XIVE_STATUS_ASSERTED ) { +xive_source_pq_set (xsrc, srcno,XIVE_ESB_PENDING ); +return true; + } +return false; +} +/* In a two pages ESB MMIO setting, even page is the trigger page, odd * page is for management */ static inline bool xive_source_is_trigger_page (hwaddr addr)@@ -133,6 +148,13 @@ static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)*/ ret =xive_source_pq_eoi (xsrc, srcno); +/* If the LSI source is still asserted, forward a new source +* event notification */ +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (xive_source_lsi_trigger (xsrc, srcno)) { +xive_source_notify (xsrc, srcno); + } + }break ;Quoted 15 lines
Quoted 5 lines
Quoted 5 lines
hw/intc/xive.c +0
-0case XIVE_ESB_GET :@@ -183,6 +205,14 @@ static void xive_source_esb_write(void *opaque, hwaddr addr,* notification */ notify =xive_source_pq_eoi (xsrc, srcno);Quoted 8 lines
hw/intc/xive.c static void xive_source_esb_write(void *opaque, hwaddr addr, · line 215
Quoted 8 lines
hw/intc/xive.c +8
-0+ +/* LSI sources do not set the Q bit but they can still be +* asserted, in which case we should forward a new source +* event notification +*/ +if (xive_source_irq_is_lsi (xsrc, srcno)) { + notify =xive_source_lsi_trigger (xsrc, srcno); + }FYI, I have moved that common test under
xive_source_pq_eoi()Ok.
Quoted 76 lines
Quoted 67 lines
Quoted 67 lines
hw/intc/xive.c +20
-4break ;default :@@ -216,8 +246,17 @@ static void xive_source_set_irq(void *opaque, int srcno, int val)XiveSource *xsrc =XIVE_SOURCE (opaque);bool notify = false; -if (val) { - notify =xive_source_pq_trigger (xsrc, srcno); +if (xive_source_irq_is_lsi (xsrc, srcno)) { +if (val) { + xsrc->status[srcno] |=XIVE_STATUS_ASSERTED ; + }else { + xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED ; + } + notify =xive_source_lsi_trigger (xsrc, srcno); + }else { +if (val) { + notify =xive_source_pq_trigger (xsrc, srcno); + } }/* Forward the source event notification for routing */ @@ -234,13 +273,13 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon) xsrc->offset, xsrc->offset + xsrc->nr_irqs - 1);for (i =0 ; i < xsrc->nr_irqs; i++) {uint8_t pq =xive_source_pq_get (xsrc, i); -uint32_t lisn = i + xsrc->offset;if (pq ==XIVE_ESB_OFF ) {continue ; } -monitor_printf (mon," %4x %c%c\n" , lisn, +monitor_printf (mon," %4x %s %c%c\n" , i + xsrc->offset, +xive_source_irq_is_lsi (xsrc, i) ?"LSI" :"MSI" , pq &XIVE_ESB_VAL_P ?'P' :'-' , pq &XIVE_ESB_VAL_Q ?'Q' :'-' ); }@@ -249,6 +288,12 @@ void xive_source_pic_print_info(XiveSource *xsrc, Monitor *mon)static void xive_source_reset (DeviceState *dev) {XiveSource *xsrc =XIVE_SOURCE (dev); +int i; + +/* Keep the IRQ type */ +for (i =0 ; i < xsrc->nr_irqs; i++) { + xsrc->status[i] &= ~XIVE_STATUS_ASSERTED ; + }/* SBEs are initialized to 0b01 which corresponds to "ints off" */ memset (xsrc->sbe,0x55 , xsrc->sbe_size);@@ -273,6 +318,7 @@ static void xive_source_realize(DeviceState *dev, Error **errp) xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, xsrc->nr_irqs); + xsrc->status =g_malloc0 (xsrc->nr_irqs);/* Allocate the SBEs (State Bit Entry). 2 bits, so 4 entries per byte */ xsrc->sbe_size =DIV_ROUND_UP (xsrc->nr_irqs,4 );include/hw/ppc/xive.h +0
-0@@ -33,6 +33,9 @@ typedef struct XiveSource {uint32_t nr_irqs;uint32_t offset;Quoted 8 lines
include/hw/ppc/xive.h typedef struct XiveSource { · line 38
Quoted 4 lines
include/hw/ppc/xive.h +3
-0qemu_irq *qirqs; +#define XIVE_STATUS_LSI 0x1 +#define XIVE_STATUS_ASSERTED 0x2 +uint8_t *status;I don't love the idea of mixing configuration information (
STATUS_LSI) with runtime state information (ASSERTED) in the same field. Any reason not to have these as parallel bitmaps.Quoted 1 line
none. I can change that.
Ok.
Quoted 9 lines
Quoted 3 lines
Come to that.. is there a compelling reason to allow any individual irq to be marked LSI or MSI, rather than using separate XiveSource objects for MSIs and LSIs?
yes. I would have preferred two distinct interrupt source objects but this is to be compatible with XICS, which uses only one. If we want to be able to change interrupt mode, the IRQ number space should be organized in the exact same way. Or we should change XICS also.
Quoted 4 lines
Quoted 1 line
Also, the change (a bitmap) is really small.
Hrm, but since XIVE supports thousands of irqs, it could be quite a large bitmap.
Yes. The change is small, not the bitmap.
Quoted 3 lines
It's not impossible - in fact, not really even that hard - to change the existing irq layout on xics. It does need a new machine type variant, of course.
Quoted 6 lines
I did some work on that topic a while ago :
https://patchwork.ozlabs.org/cover/836782/But we stopped exploring the idea. May be it was not the good approach. The PHBs LSIs would benefit from such a split though.
Quoted 7 lines
So, no, I don't think that was a good approach, but that doesn't mean other ways of rearranging the irq numbers aren't ok. The thing here is that we don't want to think of an "irq allocator" - there are some bits like that in there already, but they were always a mistake.
We have lots of irq space (both XICS and XIVE) so instead we should come up with a static mapping of irqs to devices.
yes. I would prefer that also.
We could change the
spapr_irq_alloc()routine to get a block of IRQs in the range defined for a device family, and use a device id to offset in that family range ? Here are some figures :device family block size max devices
Quoted 7 lines
EVENT_CLASS_EPOW 1 1 EVENT_CLASS_HOT_PLUG 1 1 VIO_VSCSI 1 10 VIO_LLAN 1 10 VIO_VTY 1 5PCI/PHB 1024 5
No, I'm thinking we should eliminate spapr_irq_alloc() entirely. Well, ok, not entirely, we'll still need it for the old machine types. But remove it's use for the current machine type completely.
Instead we have an explicit map of ranges for various purposes. The one-off things like EPOW and HOTPLUG can have plain constant values. PCI LSIs will be calculated as something like PCI_IRQ_BASE + <phb index>*4 + <irq pin>. The VIO devices we handle as VIO_BASE + <reg value> or something.
MSIs will still need some sort of allocation, but we can do that within a range set aside for them.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 32 lines · David Gibson
Quoted 21 lines
Quoted 6 lines
Quoted 6 lines
I did some work on that topic a while ago :
https://patchwork.ozlabs.org/cover/836782/But we stopped exploring the idea. May be it was not the good approach. The PHBs LSIs would benefit from such a split though.
Quoted 7 lines
So, no, I don't think that was a good approach, but that doesn't mean other ways of rearranging the irq numbers aren't ok. The thing here is that we don't want to think of an "irq allocator" - there are some bits like that in there already, but they were always a mistake.
We have lots of irq space (both XICS and XIVE) so instead we should come up with a static mapping of irqs to devices.
yes. I would prefer that also.
We could change the
spapr_irq_alloc()routine to get a block of IRQs in the range defined for a device family, and use a device id to offset in that family range ? Here are some figures :device family block size max devices
Quoted 7 lines
EVENT_CLASS_EPOW 1 1 EVENT_CLASS_HOT_PLUG 1 1 VIO_VSCSI 1 10 VIO_LLAN 1 10 VIO_VTY 1 5PCI/PHB 1024 5
No, I'm thinking we should eliminate
spapr_irq_alloc()entirely. Well, ok, not entirely, we'll still need it for the old machine types. But remove it's use for the current machine type completely.
Quoted 8 lines
Instead we have an explicit map of ranges for various purposes. The one-off things like EPOW and HOTPLUG can have plain constant values. PCI LSIs will be calculated as something like
PCI_IRQ_BASE+ <phb index>*4 + <irq pin>. The VIO devices we handle asVIO_BASE+ <reg value> or something.MSIs will still need some sort of allocation, but we can do that within a range set aside for them.
Should we address the static mapping of irqs before introducing XIVE ?
I don't think it changes much of the architecture now that the allocator is under the machine. However, I wonder what would be the impact of PHB hotplug.
C.
Re: [Qemu-devel] [PATCH v3 02/35] ppc/xive: add support for the LSI interrupt sources
Quoted 39 lines · Cédric Le Goater
Quoted 38 lines · David Gibson
Quoted 21 lines
Quoted 6 lines
Quoted 6 lines
I did some work on that topic a while ago :
https://patchwork.ozlabs.org/cover/836782/But we stopped exploring the idea. May be it was not the good approach. The PHBs LSIs would benefit from such a split though.
Quoted 7 lines
So, no, I don't think that was a good approach, but that doesn't mean other ways of rearranging the irq numbers aren't ok. The thing here is that we don't want to think of an "irq allocator" - there are some bits like that in there already, but they were always a mistake.
We have lots of irq space (both XICS and XIVE) so instead we should come up with a static mapping of irqs to devices.
yes. I would prefer that also.
We could change the
spapr_irq_alloc()routine to get a block of IRQs in the range defined for a device family, and use a device id to offset in that family range ? Here are some figures :device family block size max devices
Quoted 7 lines
EVENT_CLASS_EPOW 1 1 EVENT_CLASS_HOT_PLUG 1 1 VIO_VSCSI 1 10 VIO_LLAN 1 10 VIO_VTY 1 5PCI/PHB 1024 5
No, I'm thinking we should eliminate
spapr_irq_alloc()entirely. Well, ok, not entirely, we'll still need it for the old machine types. But remove it's use for the current machine type completely.Instead we have an explicit map of ranges for various purposes. The one-off things like EPOW and HOTPLUG can have plain constant values. PCI LSIs will be calculated as something like
PCI_IRQ_BASE+ <phb index>*4 + <irq pin>. The VIO devices we handle asVIO_BASE+ <reg value> or something.
Quoted 4 lines
Quoted 2 lines
MSIs will still need some sort of allocation, but we can do that within a range set aside for them.
Should we address the static mapping of irqs before introducing XIVE ?
Yes, I think so.
Quoted 3 lines
I don't think it changes much of the architecture now that the allocator is under the machine. However, I wonder what would be the impact of PHB hotplug.
I don't think it should be too bad. We now require that PHBs have the 'index' parameter set, and that won't change with hotplug. We can then set aside a region of irq #s for each index of PHB.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH v3 3/35 ppc/xive: introduce the XiveFabric interface
In reply to Cédric Le GoaterThe XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)
hw/intc/xive.c +36 -1
@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */
@@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) { +XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + } }/*
@@ -302,6 +325,17 @@ static void xive_source_reset(DeviceState *dev)static void xive_source_realize (DeviceState *dev,Error **errp) {XiveSource *xsrc =XIVE_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->xive =XIVE_FABRIC (obj);if (!xsrc->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater than 0" );
@@ -376,6 +410,7 @@ static const TypeInfo xive_source_info = {static void xive_register_types (void ) {type_register_static (&xive_source_info); +type_register_static (&xive_fabric_info); }type_init (xive_register_types)
include/hw/ppc/xive.h +25 -0
@@ -12,6 +12,8 @@#include "hw/sysbus.h" +typedef struct XiveFabric XiveFabric ; +/* * XIVE Interrupt Source */
@@ -46,6 +48,8 @@ typedef struct XiveSource {hwaddr esb_base;uint32_t esb_shift;MemoryRegion esb_mmio; + +XiveFabric *xive; } XiveSource;/*
@@ -143,4 +147,25 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, xsrc->status[srcno] |= lsi ? XIVE_STATUS_LSI : 0; } +/* +* XIVE Fabric +*/ + +typedef struct XiveFabric { +Object parent; +}XiveFabric ; + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC (obj) \ + OBJECT_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveFabricClass, (klass), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveFabricClass, (obj), TYPE_XIVE_FABRIC) + +typedef struct XiveFabricClass { +InterfaceClass parent; +void (*notify)(XiveFabric *xf,uint32_t lisn); +}XiveFabricClass ; +#endif /* PPC_XIVE_H */
Signature · 1 line
2.13.6
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 46 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 10 lines
hw/intc/xive.c +7
-0static void xive_source_notify (XiveSource *xsrc,int srcno) { +XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }
Why 2 cases? Can't the XiveFabric object just make its notify equal to xive_fabric_route if that's what it wants?
Quoted 77 lines
hw/intc/xive.c +12
-0}/* @@ -302,6 +325,17 @@ static void xive_source_reset(DeviceState *dev)static void xive_source_realize (DeviceState *dev,Error **errp) {XiveSource *xsrc =XIVE_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->xive =XIVE_FABRIC (obj);if (!xsrc->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater than 0" );@@ -376,6 +410,7 @@ static const TypeInfo xive_source_info = {static void xive_register_types (void ) {type_register_static (&xive_source_info); +type_register_static (&xive_fabric_info); }type_init (xive_register_types)include/hw/ppc/xive.h +25
-0@@ -12,6 +12,8 @@#include "hw/sysbus.h" +typedef struct XiveFabric XiveFabric ; +/* * XIVE Interrupt Source */ @@ -46,6 +48,8 @@ typedef struct XiveSource {hwaddr esb_base;uint32_t esb_shift;MemoryRegion esb_mmio; + +XiveFabric *xive; } XiveSource;/* @@ -143,4 +147,25 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, xsrc->status[srcno] |= lsi ? XIVE_STATUS_LSI : 0; } +/* +* XIVE Fabric +*/ + +typedef struct XiveFabric { +Object parent; +}XiveFabric ; + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC (obj) \ + OBJECT_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveFabricClass, (klass), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveFabricClass, (obj), TYPE_XIVE_FABRIC) + +typedef struct XiveFabricClass { +InterfaceClass parent; +void (*notify)(XiveFabric *xf,uint32_t lisn); +}XiveFabricClass ; +#endif /* PPC_XIVE_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {
Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by xive_fabric_route(). There is no need of an extra hop. Indeed.
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
static void pnv_psi_notify(XiveFabric *xf, uint32_t lisn)
{
PnvPsi *psi = PNV_PSI(xf);
uint64_t notif_port =
psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)];
bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID;
uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID;
uint32_t data = cpu_to_be32(lisn);
if (valid) {
cpu_physical_memory_write(notify_addr, &data, sizeof(data));
}
}The PnvXive model handles the load and forwards to the fabric again.
The IPIs under PowerNV do not need an extra hop so they reach the routing routine directly without the extra notify() hop.
However, PowerNV at the end should be using xive_fabric_route() but there are some differences on how the NVT registers are updated (HV vs. OS mode) and it's not handled yet so it uses a notify() handler. But is should disappear and call directly xive_fabric_route() in a near future.
May be, XiveFabricNotifier would be a better name for this feature ? I am adding a few ops later which are more related to routing.
Thanks,
C.
Quoted 79 lines
Quoted 78 lines
hw/intc/xive.c +12
-0}/* @@ -302,6 +325,17 @@ static void xive_source_reset(DeviceState *dev)static void xive_source_realize (DeviceState *dev,Error **errp) {XiveSource *xsrc =XIVE_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->xive =XIVE_FABRIC (obj);if (!xsrc->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater than 0" );@@ -376,6 +410,7 @@ static const TypeInfo xive_source_info = {static void xive_register_types (void ) {type_register_static (&xive_source_info); +type_register_static (&xive_fabric_info); }type_init (xive_register_types)include/hw/ppc/xive.h +25
-0@@ -12,6 +12,8 @@#include "hw/sysbus.h" +typedef struct XiveFabric XiveFabric ; +/* * XIVE Interrupt Source */ @@ -46,6 +48,8 @@ typedef struct XiveSource {hwaddr esb_base;uint32_t esb_shift;MemoryRegion esb_mmio; + +XiveFabric *xive; } XiveSource;/* @@ -143,4 +147,25 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, xsrc->status[srcno] |= lsi ? XIVE_STATUS_LSI : 0; } +/* +* XIVE Fabric +*/ + +typedef struct XiveFabric { +Object parent; +}XiveFabric ; + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC (obj) \ + OBJECT_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveFabricClass, (klass), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveFabricClass, (obj), TYPE_XIVE_FABRIC) + +typedef struct XiveFabricClass { +InterfaceClass parent; +void (*notify)(XiveFabric *xf,uint32_t lisn); +}XiveFabricClass ; +#endif /* PPC_XIVE_H */
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 61 lines · Cédric Le Goater
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?
Quoted 3 lines
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by
xive_fabric_route(). There is no need of an extra hop. Indeed.
Ok.
Quoted 4 lines
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
Hm. So you're saying that in pnv some sources send their notification to some other unit, that would then (after possible masking) forward on to the overall xive fabric?
That seems like a property of the source object, rather than a property of the fabric. Indeed varying this by source object would require the objects have a different xive pointer, when I thought the idea was that the XiveFabric was global.
Quoted 114 lines
static void pnv_psi_notify(XiveFabric *xf, uint32_t lisn) { PnvPsi *psi = PNV_PSI(xf); uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)]; bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID; uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID; uint32_t data = cpu_to_be32(lisn); if (valid) { cpu_physical_memory_write(notify_addr, &data, sizeof(data)); } }The PnvXive model handles the load and forwards to the fabric again.
The IPIs under PowerNV do not need an extra hop so they reach the routing routine directly without the extra
notify()hop.However, PowerNV at the end should be using
xive_fabric_route()but there are some differences on how the NVT registers are updated (HV vs. OS mode) and it's not handled yet so it uses anotify()handler. But is should disappear and call directlyxive_fabric_route()in a near future.May be, XiveFabricNotifier would be a better name for this feature ? I am adding a few ops later which are more related to routing.
Thanks,
C.
Quoted 79 lines
Quoted 78 lines
hw/intc/xive.c +12
-0}/* @@ -302,6 +325,17 @@ static void xive_source_reset(DeviceState *dev)static void xive_source_realize (DeviceState *dev,Error **errp) {XiveSource *xsrc =XIVE_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->xive =XIVE_FABRIC (obj);if (!xsrc->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater than 0" );@@ -376,6 +410,7 @@ static const TypeInfo xive_source_info = {static void xive_register_types (void ) {type_register_static (&xive_source_info); +type_register_static (&xive_fabric_info); }type_init (xive_register_types)include/hw/ppc/xive.h +25
-0@@ -12,6 +12,8 @@#include "hw/sysbus.h" +typedef struct XiveFabric XiveFabric ; +/* * XIVE Interrupt Source */ @@ -46,6 +48,8 @@ typedef struct XiveSource {hwaddr esb_base;uint32_t esb_shift;MemoryRegion esb_mmio; + +XiveFabric *xive; } XiveSource;/* @@ -143,4 +147,25 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, xsrc->status[srcno] |= lsi ? XIVE_STATUS_LSI : 0; } +/* +* XIVE Fabric +*/ + +typedef struct XiveFabric { +Object parent; +}XiveFabric ; + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC (obj) \ + OBJECT_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveFabricClass, (klass), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveFabricClass, (obj), TYPE_XIVE_FABRIC) + +typedef struct XiveFabricClass { +InterfaceClass parent; +void (*notify)(XiveFabric *xf,uint32_t lisn); +}XiveFabricClass ; +#endif /* PPC_XIVE_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 68 lines · David Gibson
Quoted 61 lines · Cédric Le Goater
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?Quoted 3 lines
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by
xive_fabric_route(). There is no need of an extra hop. Indeed.Ok.
Quoted 7 lines
Quoted 4 lines
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
Hm. So you're saying that in pnv some sources send their notification to some other unit,
Not to any unit/device, to the device owning the sources.
For the XiveSource object under PSI, the XIVEFabric interface is the PSI device object it self, which knows how to forward the notification on the XIVE Power "bus". To be more precise, the PSI HB device has 14 interrupt sources, which notifications are forwarded using a MMIO load to some address. The load address is configured (by skiboot) in one of the PSI device registers, and points to a MMIO region of the main XIVE interrupt controller.
The PHB4 sources should be the same.
For the XiveSource object (all interrupts) under sPAPRXive, the XIVEFabric is the main interrupt controller sPAPRXive.
For the XiveSource object (IPIs) under PnvXive, the XIVEFabric is also the main interrupt controller PnvXive.
Quoted 1 line
that would then (after possible masking) forward on to the overall> xive fabric ?
yes. May be XIVEFabric is a confusing name. What about XIVEForwarder ?
Quoted 1 line
That seems like a property of the source object,
The source object is generic. It's a bunch of PQ bits that can be controlled by MMIOs. Nothing more.
Quoted 4 lines
rather than a
property of the fabric. Indeed varying this by source object would require the objects have a different xive pointer, when I thought the idea was that the XiveFabric was global.
When a notification is forwarded, the sources needs to call an interface which generally is implemented by the source owner, which is not necessarily the main IC.
Quoted 115 lines
Quoted 114 lines
static void pnv_psi_notify(XiveFabric *xf, uint32_t lisn) { PnvPsi *psi = PNV_PSI(xf); uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)]; bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID; uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID; uint32_t data = cpu_to_be32(lisn); if (valid) { cpu_physical_memory_write(notify_addr, &data, sizeof(data)); } }The PnvXive model handles the load and forwards to the fabric again.
The IPIs under PowerNV do not need an extra hop so they reach the routing routine directly without the extra
notify()hop.However, PowerNV at the end should be using
xive_fabric_route()but there are some differences on how the NVT registers are updated (HV vs. OS mode) and it's not handled yet so it uses anotify()handler. But is should disappear and call directlyxive_fabric_route()in a near future.May be, XiveFabricNotifier would be a better name for this feature ? I am adding a few ops later which are more related to routing.
Thanks,
C.
Quoted 79 lines
Quoted 78 lines
hw/intc/xive.c +12
-0}/* @@ -302,6 +325,17 @@ static void xive_source_reset(DeviceState *dev)static void xive_source_realize (DeviceState *dev,Error **errp) {XiveSource *xsrc =XIVE_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->xive =XIVE_FABRIC (obj);if (!xsrc->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater than 0" );@@ -376,6 +410,7 @@ static const TypeInfo xive_source_info = {static void xive_register_types (void ) {type_register_static (&xive_source_info); +type_register_static (&xive_fabric_info); }type_init (xive_register_types)include/hw/ppc/xive.h +25
-0@@ -12,6 +12,8 @@#include "hw/sysbus.h" +typedef struct XiveFabric XiveFabric ; +/* * XIVE Interrupt Source */ @@ -46,6 +48,8 @@ typedef struct XiveSource {hwaddr esb_base;uint32_t esb_shift;MemoryRegion esb_mmio; + +XiveFabric *xive; } XiveSource;/* @@ -143,4 +147,25 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, xsrc->status[srcno] |= lsi ? XIVE_STATUS_LSI : 0; } +/* +* XIVE Fabric +*/ + +typedef struct XiveFabric { +Object parent; +}XiveFabric ; + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC (obj) \ + OBJECT_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveFabricClass, (klass), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveFabricClass, (obj), TYPE_XIVE_FABRIC) + +typedef struct XiveFabricClass { +InterfaceClass parent; +void (*notify)(XiveFabric *xf,uint32_t lisn); +}XiveFabricClass ; +#endif /* PPC_XIVE_H */
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 87 lines · Cédric Le Goater
Quoted 68 lines · David Gibson
Quoted 61 lines · Cédric Le Goater
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?Quoted 3 lines
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by
xive_fabric_route(). There is no need of an extra hop. Indeed.Ok.
Quoted 7 lines
Quoted 4 lines
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
Hm. So you're saying that in pnv some sources send their notification to some other unit,
Not to any unit/device, to the device owning the sources.
For the XiveSource object under PSI, the XIVEFabric interface is the PSI device object it self, which knows how to forward the notification on the XIVE Power "bus". To be more precise, the PSI HB device has 14 interrupt sources, which notifications are forwarded using a MMIO load to some address. The load address is configured (by skiboot) in one of the PSI device registers, and points to a MMIO region of the main XIVE interrupt controller.
Quoted 7 lines
The PHB4 sources should be the same.
For the XiveSource object (all interrupts) under sPAPRXive, the XIVEFabric is the main interrupt controller sPAPRXive.
For the XiveSource object (IPIs) under PnvXive, the XIVEFabric is also the main interrupt controller PnvXive.
Hrm. Apparently I'm missing something, I'm really not getting what you're trying to explain here.
Quoted 3 lines
Quoted 1 line
that would then (after possible masking) forward on to the overall> xive fabric ?
yes. May be XIVEFabric is a confusing name. What about XIVEForwarder ?
Maybe..?
Quoted 4 lines
Quoted 1 line
That seems like a property of the source object,
The source object is generic. It's a bunch of PQ bits that can be controlled by MMIOs. Nothing more.
Hmm. Isn't the source object also responsible for forwarding the interrupt to something up the chain (whatever that is)?
Quoted 8 lines
Quoted 5 lines
rather than a
property of the fabric. Indeed varying this by source object would require the objects have a different xive pointer, when I thought the idea was that the XiveFabric was global.When a notification is forwarded, the sources needs to call an interface which generally is implemented by the source owner,
I'm not quite sure what you mean by "source owner".
Quoted 118 lines
which is not necessarily the main IC.
Quoted 115 lines
Quoted 114 lines
static void pnv_psi_notify(XiveFabric *xf, uint32_t lisn) { PnvPsi *psi = PNV_PSI(xf); uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)]; bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID; uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID; uint32_t data = cpu_to_be32(lisn); if (valid) { cpu_physical_memory_write(notify_addr, &data, sizeof(data)); } }The PnvXive model handles the load and forwards to the fabric again.
The IPIs under PowerNV do not need an extra hop so they reach the routing routine directly without the extra
notify()hop.However, PowerNV at the end should be using
xive_fabric_route()but there are some differences on how the NVT registers are updated (HV vs. OS mode) and it's not handled yet so it uses anotify()handler. But is should disappear and call directlyxive_fabric_route()in a near future.May be, XiveFabricNotifier would be a better name for this feature ? I am adding a few ops later which are more related to routing.
Thanks,
C.
Quoted 79 lines
Quoted 78 lines
hw/intc/xive.c +12
-0}/* @@ -302,6 +325,17 @@ static void xive_source_reset(DeviceState *dev)static void xive_source_realize (DeviceState *dev,Error **errp) {XiveSource *xsrc =XIVE_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->xive =XIVE_FABRIC (obj);if (!xsrc->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater than 0" );@@ -376,6 +410,7 @@ static const TypeInfo xive_source_info = {static void xive_register_types (void ) {type_register_static (&xive_source_info); +type_register_static (&xive_fabric_info); }type_init (xive_register_types)include/hw/ppc/xive.h +25
-0@@ -12,6 +12,8 @@#include "hw/sysbus.h" +typedef struct XiveFabric XiveFabric ; +/* * XIVE Interrupt Source */ @@ -46,6 +48,8 @@ typedef struct XiveSource {hwaddr esb_base;uint32_t esb_shift;MemoryRegion esb_mmio; + +XiveFabric *xive; } XiveSource;/* @@ -143,4 +147,25 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, xsrc->status[srcno] |= lsi ? XIVE_STATUS_LSI : 0; } +/* +* XIVE Fabric +*/ + +typedef struct XiveFabric { +Object parent; +}XiveFabric ; + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC (obj) \ + OBJECT_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveFabricClass, (klass), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveFabricClass, (obj), TYPE_XIVE_FABRIC) + +typedef struct XiveFabricClass { +InterfaceClass parent; +void (*notify)(XiveFabric *xf,uint32_t lisn); +}XiveFabricClass ; +#endif /* PPC_XIVE_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 90 lines · David Gibson
Quoted 89 lines · Cédric Le Goater
Quoted 68 lines · David Gibson
Quoted 61 lines · Cédric Le Goater
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?Quoted 3 lines
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by
xive_fabric_route(). There is no need of an extra hop. Indeed.Ok.
Quoted 7 lines
Quoted 4 lines
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
Hm. So you're saying that in pnv some sources send their notification to some other unit,
Not to any unit/device, to the device owning the sources.
For the XiveSource object under PSI, the XIVEFabric interface is the PSI device object it self, which knows how to forward the notification on the XIVE Power "bus". To be more precise, the PSI HB device has 14 interrupt sources, which notifications are forwarded using a MMIO load to some address. The load address is configured (by skiboot) in one of the PSI device registers, and points to a MMIO region of the main XIVE interrupt controller.
The PHB4 sources should be the same.
Quoted 8 lines
Quoted 5 lines
For the XiveSource object (all interrupts) under sPAPRXive, the XIVEFabric is the main interrupt controller sPAPRXive.
For the XiveSource object (IPIs) under PnvXive, the XIVEFabric is also the main interrupt controller PnvXive.
Hrm. Apparently I'm missing something, I'm really not getting what you're trying to explain here.
I see that. Let's try again.
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
that would then (after possible masking) forward on to the overall> xive fabric ?
yes. May be XIVEFabric is a confusing name. What about XIVEForwarder ?
Maybe..?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
That seems like a property of the source object,
The source object is generic. It's a bunch of PQ bits that can be controlled by MMIOs. Nothing more.
Hmm. Isn't the source object also responsible for forwarding the interrupt to something up the chain (whatever that is)?
Yes but it can not forward directly. The XiveSource is generic and can only call a handler :
xfc->notify(xsrc->xive, srcno + xsrc->offset);
The device model owner, the parent of the XiveSource object, would do the real forward.
It's very similar to what we have today with XICS :
- The sPAPR model has an ICSState
- The PnvPSI model has an ICSState
- The PnvPHB3 model has two ICSStates
and the 'xics' pointer in ICSState points to the 'interrupt unit' of the machine to do resends and to grab ICPs. So it used for routing essentially.
in Xive
- sPAPRXive model has a XiveSource
- PnvXive model has a XiveSource
- PnvPSI model has a XiveSource
- PnvPHB4 model should have also.
and the 'xive' pointer in XiveSource points to the parent object, which will handle the event notification forwarding or routing.
C.
Quoted 9 lines
Quoted 7 lines
Quoted 4 lines
rather than a
property of the fabric. Indeed varying this by source object would require the objects have a different xive pointer, when I thought the idea was that the XiveFabric was global.When a notification is forwarded, the sources needs to call an interface which generally is implemented by the source owner,
I'm not quite sure what you mean by "source owner".
The parent object.
Quoted 119 lines
Quoted 118 lines
which is not necessarily the main IC.
Quoted 115 lines
Quoted 114 lines
static void pnv_psi_notify(XiveFabric *xf, uint32_t lisn) { PnvPsi *psi = PNV_PSI(xf); uint64_t notif_port = psi->regs[PSIHB_REG(PSIHB9_ESB_NOTIF_ADDR)]; bool valid = notif_port & PSIHB9_ESB_NOTIF_VALID; uint64_t notify_addr = notif_port & ~PSIHB9_ESB_NOTIF_VALID; uint32_t data = cpu_to_be32(lisn); if (valid) { cpu_physical_memory_write(notify_addr, &data, sizeof(data)); } }The PnvXive model handles the load and forwards to the fabric again.
The IPIs under PowerNV do not need an extra hop so they reach the routing routine directly without the extra
notify()hop.However, PowerNV at the end should be using
xive_fabric_route()but there are some differences on how the NVT registers are updated (HV vs. OS mode) and it's not handled yet so it uses anotify()handler. But is should disappear and call directlyxive_fabric_route()in a near future.May be, XiveFabricNotifier would be a better name for this feature ? I am adding a few ops later which are more related to routing.
Thanks,
C.
Quoted 79 lines
Quoted 78 lines
hw/intc/xive.c +12
-0}/* @@ -302,6 +325,17 @@ static void xive_source_reset(DeviceState *dev)static void xive_source_realize (DeviceState *dev,Error **errp) {XiveSource *xsrc =XIVE_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->xive =XIVE_FABRIC (obj);if (!xsrc->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater than 0" );@@ -376,6 +410,7 @@ static const TypeInfo xive_source_info = {static void xive_register_types (void ) {type_register_static (&xive_source_info); +type_register_static (&xive_fabric_info); }type_init (xive_register_types)include/hw/ppc/xive.h +25
-0@@ -12,6 +12,8 @@#include "hw/sysbus.h" +typedef struct XiveFabric XiveFabric ; +/* * XIVE Interrupt Source */ @@ -46,6 +48,8 @@ typedef struct XiveSource {hwaddr esb_base;uint32_t esb_shift;MemoryRegion esb_mmio; + +XiveFabric *xive; } XiveSource;/* @@ -143,4 +147,25 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, xsrc->status[srcno] |= lsi ? XIVE_STATUS_LSI : 0; } +/* +* XIVE Fabric +*/ + +typedef struct XiveFabric { +Object parent; +}XiveFabric ; + +#define TYPE_XIVE_FABRIC "xive-fabric" +#define XIVE_FABRIC (obj) \ + OBJECT_CHECK(XiveFabric, (obj), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveFabricClass, (klass), TYPE_XIVE_FABRIC) +#define XIVE_FABRIC_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveFabricClass, (obj), TYPE_XIVE_FABRIC) + +typedef struct XiveFabricClass { +InterfaceClass parent; +void (*notify)(XiveFabric *xf,uint32_t lisn); +}XiveFabricClass ; +#endif /* PPC_XIVE_H */
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 113 lines · Cédric Le Goater
Quoted 90 lines · David Gibson
Quoted 89 lines · Cédric Le Goater
Quoted 68 lines · David Gibson
Quoted 61 lines · Cédric Le Goater
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?Quoted 3 lines
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by
xive_fabric_route(). There is no need of an extra hop. Indeed.Ok.
Quoted 7 lines
Quoted 4 lines
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
Hm. So you're saying that in pnv some sources send their notification to some other unit,
Not to any unit/device, to the device owning the sources.
For the XiveSource object under PSI, the XIVEFabric interface is the PSI device object it self, which knows how to forward the notification on the XIVE Power "bus". To be more precise, the PSI HB device has 14 interrupt sources, which notifications are forwarded using a MMIO load to some address. The load address is configured (by skiboot) in one of the PSI device registers, and points to a MMIO region of the main XIVE interrupt controller.
The PHB4 sources should be the same.
Quoted 8 lines
Quoted 5 lines
For the XiveSource object (all interrupts) under sPAPRXive, the XIVEFabric is the main interrupt controller sPAPRXive.
For the XiveSource object (IPIs) under PnvXive, the XIVEFabric is also the main interrupt controller PnvXive.
Hrm. Apparently I'm missing something, I'm really not getting what you're trying to explain here.
I see that. Let's try again.
Quoted 11 lines
Quoted 3 lines
Quoted 1 line
that would then (after possible masking) forward on to the overall> xive fabric ?
yes. May be XIVEFabric is a confusing name. What about XIVEForwarder ?
Maybe..?
Quoted 4 lines
Quoted 1 line
That seems like a property of the source object,
The source object is generic. It's a bunch of PQ bits that can be controlled by MMIOs. Nothing more.
Quoted 7 lines
Quoted 2 lines
Hmm. Isn't the source object also responsible for forwarding the interrupt to something up the chain (whatever that is)?
Yes but it can not forward directly. The XiveSource is generic and can only call a handler :
xfc->notify(xsrc->xive, srcno + xsrc->offset);
But.. your patch doesn't do that always, it's conditional which I still don't understand.
Quoted 2 lines
The device model owner, the parent of the XiveSource object, would do the real forward.
Why? I mean the XiveSource basically represents the xive irq related logic of the PHB or whatever, why would it not represent *all* of that, rather than just the ESB bits, meaning the owner has to have some more xive logic for the forwarding.
Note that I don't think the fact that some sources notify via mmio and some are internal really matters. It's not like we're modelling the power bus down to the wire-transaction level.
Quoted 9 lines
It's very similar to what we have today with XICS :
- The sPAPR model has an ICSState
- The PnvPSI model has an ICSState
- The PnvPHB3 model has two ICSStatesand the 'xics' pointer in ICSState points to the 'interrupt unit' of the machine to do resends and to grab ICPs. So it used for routing essentially.
Hmm. I think you and I are looking at XICSFabric kind of differently. As I see it, it's not really an active component at all. Rather it's basically a global "map" of the xics components so that they can find each other.
Quoted 8 lines
in Xive
- sPAPRXive model has a XiveSource
- PnvXive model has a XiveSource
- PnvPSI model has a XiveSource
- PnvPHB4 model should have also.and the 'xive' pointer in XiveSource points to the parent object,
Uh.. yeah.. the xics pointer in ICS units doesn't point to the parent object, except maybe by accident. It's absolutely intended to be global, and so points to the machine.
Quoted 1 line
which will handle the event notification forwarding or routing.
Ok, how about this for a partial model. We have:
XiveSource objects:
* Owns an ESB table
* Knows the mapping of its local irq offsets to global irq numbers
* Provides the mmio interface for ESB manipulation
* When neccessary, notifies a new interrupt to a XiveRouter
XiveRouter objects:
* Responsible for a fixed range of global irq numbers
* Owns an IVT (but what that means can vary, see below)
* When notified of an irq, routes it to the appropriate EQ (haven't thought about this part yet)
* Abstract class - needs subclasses to define how to get IVEs
XiveFabric interface:
* Lets XIVE components locate each other
* get_router() method: maps a global irq number to XiveRouter object
* Always global (implemented on the machine)
On pseries we have:
? XiveSource objects. We probably only need one, but 1 for LSI and one for MSI might be convenient. More wouldn't break the model
1 sPAPRXiveRouter. This is a subclass of XiveRouter that holds the IVT internall (and migrates it).
the XiveFabric implementation always returns the single global router for get_router()
On powernv we have:
N XiveSource objects. Some in PHBs, some extra ones on each chip
(#chips) PowerXiveRouter objects. This subclass of XiveRouter stores the register giving the IVT base address and migrates that, but the IVT contents are in RAM
the XiveFabric get_router() implementation returns the right chip's router based on the irq number
Obviously the router->EQ sides still needs a bunch of thought.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 117 lines · David Gibson
Quoted 116 lines · Cédric Le Goater
Quoted 90 lines · David Gibson
Quoted 89 lines · Cédric Le Goater
Quoted 68 lines · David Gibson
Quoted 61 lines · Cédric Le Goater
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?Quoted 3 lines
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by
xive_fabric_route(). There is no need of an extra hop. Indeed.Ok.
Quoted 7 lines
Quoted 4 lines
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
Hm. So you're saying that in pnv some sources send their notification to some other unit,
Not to any unit/device, to the device owning the sources.
For the XiveSource object under PSI, the XIVEFabric interface is the PSI device object it self, which knows how to forward the notification on the XIVE Power "bus". To be more precise, the PSI HB device has 14 interrupt sources, which notifications are forwarded using a MMIO load to some address. The load address is configured (by skiboot) in one of the PSI device registers, and points to a MMIO region of the main XIVE interrupt controller.
The PHB4 sources should be the same.
Quoted 8 lines
Quoted 5 lines
For the XiveSource object (all interrupts) under sPAPRXive, the XIVEFabric is the main interrupt controller sPAPRXive.
For the XiveSource object (IPIs) under PnvXive, the XIVEFabric is also the main interrupt controller PnvXive.
Hrm. Apparently I'm missing something, I'm really not getting what you're trying to explain here.
I see that. Let's try again.
Quoted 13 lines
Quoted 3 lines
Quoted 1 line
that would then (after possible masking) forward on to the overall> xive fabric ?
yes. May be XIVEFabric is a confusing name. What about XIVEForwarder ?
Maybe..?
Quoted 4 lines
Quoted 1 line
That seems like a property of the source object,
The source object is generic. It's a bunch of PQ bits that can be controlled by MMIOs. Nothing more.
Hmm. Isn't the source object also responsible for forwarding the interrupt to something up the chain (whatever that is)?
Quoted 7 lines
Quoted 4 lines
Yes but it can not forward directly. The XiveSource is generic and can only call a handler :
xfc->notify(xsrc->xive, srcno + xsrc->offset);But.. your patch doesn't do that always, it's conditional which I still don't understand.
Because at the end of the notify/forward chain, you route.
Quoted 4 lines
Quoted 2 lines
The device model owner, the parent of the XiveSource object, would do the real forward.
Why?
because, in my idea of the XiveSource concept, it does not have the logic to do so: the register for the MMIO address to use, another one for the IVT offset, etc
Quoted 4 lines
I mean the XiveSource basically represents the xive irq related logic of the PHB or whatever, why would it not represent *all* of that, rather than just the ESB bits, meaning the owner has to have some more xive logic for the forwarding.
ok. This is where we diverge in the concept.
The PQ bits, the ESB MMIO region handlers can be easily shared between the different device models. They are the common part of devices with XIVE interrupt sources.
Quoted 3 lines
Note that I don't think the fact that some sources notify via mmio and some are internal really matters. It's not like we're modelling the power bus down to the wire-transaction level.
yes but the configuration of the devices are different. pnv devices will have registers accessible through MMIO or XSCOM and configured by the firmware. spapr is all set up by QEMU.
Quoted 6 lines
Quoted 6 lines
It's very similar to what we have today with XICS :
- The sPAPR model has an ICSState
- The PnvPSI model has an ICSState
- The PnvPHB3 model has two ICSStates
Quoted 8 lines
Quoted 3 lines
and the 'xics' pointer in ICSState points to the 'interrupt unit' of the machine to do resends and to grab ICPs. So it used for routing essentially.
Hmm. I think you and I are looking at XICSFabric kind of differently. As I see it, it's not really an active component at all. Rather it's basically a global "map" of the xics components so that they can find each other.
ok. I am not that far either.
Quoted 7 lines
Quoted 7 lines
in Xive
- sPAPRXive model has a XiveSource
- PnvXive model has a XiveSource
- PnvPSI model has a XiveSource
- PnvPHB4 model should have also.
Quoted 5 lines
Quoted 1 line
and the 'xive' pointer in XiveSource points to the parent object,
Uh.. yeah.. the xics pointer in ICS units doesn't point to the parent object, except maybe by accident. It's absolutely intended to be global, and so points to the machine.
yes. I agree.
XIVE has more layers and visible components due to the internal tables used for routing.
Quoted 8 lines
Quoted 1 line
which will handle the event notification forwarding or routing.
Ok, how about this for a partial model. We have:
XiveSource objects:
* Owns an ESB table
* Knows the mapping of its local irq offsets to global irq numbers
That is the 'offset' attribute I suppose. This is set at runtime for the powernv devices. For pseries, we should need it for passthrough. I think. I haven't looked at that part yet.
Quoted 2 lines
* Provides the mmio interface for ESB manipulation
* When neccessary, notifies a new interrupt to a XiveRouter
ok. I think that what we have today fits the idea then.
Quoted 3 lines
XiveRouter objects:
* Responsible for a fixed range of global irq numbers
* Owns an IVT (but what that means can vary, see below)
the size of the IVT table is determined at runtime for powernv.
Quoted 2 lines
* When notified of an irq, routes it to the appropriate EQ (haven't thought about this part yet)
we will need a class handler to get EQs
Quoted 1 line
* Abstract class - needs subclasses to define how to get IVEs
OK. We will need a few other ops. The router needs to :
- get IVEs
- get EQ descriptors
- update OS EQs (write event data in OS RAM)
- update EQ descriptors (to set EQ descriptor index & toggle)
- get an NVT/VP (to notify CPUs)
For powernv, we should also consider updating the NVT/VP. It can be done later.
Quoted 2 lines
XiveFabric interface:
* Lets XIVE components locate each other
hmm, it should be a chain :
source -> router -> presenter -> cpu
So the components should not have to locate each other. The presenter does not know about the source for instance. Only the sources need to forward events to the main controller logic doing the routing.
Quoted 2 lines
*
get_router()method: maps a global irq number to XiveRouter object
Ah. you are thinking about the multichip case under powernv. I need to look at that more closely. But XIVE has a concept of block which is used by skiboot to map a chip to a block and the XIVE tables have a block field.
Quoted 1 line
* Always global (implemented on the machine)
OK. this is more or less the object modeling the main interrupt controller ? What I called sPAPRXive in the current patchset.
Quoted 4 lines
On pseries we have:
? XiveSource objects. We probably only need one, but 1 for LSI and one for MSI might be convenient.
It's not too ugly for the moment. If we create a source object for LSIs only that might be more complex for passthrough devices and their associated ESB MMIO region.
side note :
LSIs work under TCG, and used to work under KVM until we removed the StoreEOI support. Since the EOI is now different, we need to find a way to handle EOI for guest virtual LSIs which are not LSIs for the host. We can still change the Linux spapr backend or have QEMU handle the EOI for virtual LSIs. This is on my TODO list.
Quoted 1 line
More wouldn't break the model
It should not. Initially the pachset had two source objects :
one for IPIs and one for the virtual devices interrupts.
Quoted 2 lines
1 sPAPRXiveRouter. This is a subclass of XiveRouter that holds the IVT internall (and migrates it).
OK.
Quoted 2 lines
the XiveFabric implementation always returns the single global router for
get_router()
we can do that.
Do we gather all XIVE components objects under an object 'sPAPRXive' modeling that way the main interrupt controller of the machine ? It should not have any state but it will hold the TIMA region most certainly, and the addresses where to map the ESB and TIMA regions.
KVM support will bring extra needs.
Quoted 3 lines
On powernv we have:
N XiveSource objects. Some in PHBs, some extra ones on each chip
yes and PSI to start with.
Quoted 8 lines
(#chips) PowerXiveRouter objects. This subclass of XiveRouter stores the register giving the IVT base address and migrates that, but the IVT contents are in RAM
the XiveFabric
get_router()implementation returns the right chip's router based on the irq numberObviously the
router->EQsides still needs a bunch of thought.
These are all routing tables :
- IVT
- EQDT
- VPDT
Thanks,
C.
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 121 lines · Cédric Le Goater
Quoted 120 lines · David Gibson
Quoted 119 lines · Cédric Le Goater
Quoted 90 lines · David Gibson
Quoted 89 lines · Cédric Le Goater
Quoted 68 lines · David Gibson
Quoted 61 lines · Cédric Le Goater
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?Quoted 3 lines
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by
xive_fabric_route(). There is no need of an extra hop. Indeed.Ok.
Quoted 7 lines
Quoted 4 lines
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
Hm. So you're saying that in pnv some sources send their notification to some other unit,
Not to any unit/device, to the device owning the sources.
For the XiveSource object under PSI, the XIVEFabric interface is the PSI device object it self, which knows how to forward the notification on the XIVE Power "bus". To be more precise, the PSI HB device has 14 interrupt sources, which notifications are forwarded using a MMIO load to some address. The load address is configured (by skiboot) in one of the PSI device registers, and points to a MMIO region of the main XIVE interrupt controller.
The PHB4 sources should be the same.
Quoted 8 lines
Quoted 5 lines
For the XiveSource object (all interrupts) under sPAPRXive, the XIVEFabric is the main interrupt controller sPAPRXive.
For the XiveSource object (IPIs) under PnvXive, the XIVEFabric is also the main interrupt controller PnvXive.
Hrm. Apparently I'm missing something, I'm really not getting what you're trying to explain here.
I see that. Let's try again.
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
that would then (after possible masking) forward on to the overall> xive fabric ?
yes. May be XIVEFabric is a confusing name. What about XIVEForwarder ?
Maybe..?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
That seems like a property of the source object,
The source object is generic. It's a bunch of PQ bits that can be controlled by MMIOs. Nothing more.
Hmm. Isn't the source object also responsible for forwarding the interrupt to something up the chain (whatever that is)?
Yes but it can not forward directly. The XiveSource is generic and can only call a handler :
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
xfc->notify(xsrc->xive, srcno + xsrc->offset);But.. your patch doesn't do that always, it's conditional which I still don't understand.
Because at the end of the notify/forward chain, you route.
Hrm. I'm really not understanding this notify/forward thing as distinct from routing. I mean, from the description here it sounds kind of like cascaded interrupt controllers, which qemu already has mechanisms to handle, but I didn't think (most) POWER9 devices worked like that.
Quoted 14 lines
Quoted 4 lines
Quoted 2 lines
The device model owner, the parent of the XiveSource object, would do the real forward.
Why?
because, in my idea of the XiveSource concept, it does not have the logic to do so: the register for the MMIO address to use, another one for the IVT offset, etc
Quoted 4 lines
I mean the XiveSource basically represents the xive irq related logic of the PHB or whatever, why would it not represent *all* of that, rather than just the ESB bits, meaning the owner has to have some more xive logic for the forwarding.
Quoted 5 lines
ok. This is where we diverge in the concept.
The PQ bits, the ESB MMIO region handlers can be easily shared between the different device models. They are the common part of devices with XIVE interrupt sources.
Sure, but QOM subclasses are a thing, which sounds like a better way of doing this than having to have extra XIVE logic in all the parent devices.
Quoted 7 lines
Quoted 3 lines
Note that I don't think the fact that some sources notify via mmio and some are internal really matters. It's not like we're modelling the power bus down to the wire-transaction level.
yes but the configuration of the devices are different. pnv devices will have registers accessible through MMIO or XSCOM and configured by the firmware. spapr is all set up by QEMU.
Ah.. ok. Actually modelling the mmio forwards probably makes sense then. I still think it makes more sense in a pnv XiveSource subclass rather than putting it in the containing device.
Quoted 26 lines
Quoted 6 lines
Quoted 6 lines
It's very similar to what we have today with XICS :
- The sPAPR model has an ICSState
- The PnvPSI model has an ICSState
- The PnvPHB3 model has two ICSStatesQuoted 8 lines
Quoted 3 lines
and the 'xics' pointer in ICSState points to the 'interrupt unit' of the machine to do resends and to grab ICPs. So it used for routing essentially.
Hmm. I think you and I are looking at XICSFabric kind of differently. As I see it, it's not really an active component at all. Rather it's basically a global "map" of the xics components so that they can find each other.
ok. I am not that far either.
Quoted 9 lines
Quoted 8 lines
in Xive
- sPAPRXive model has a XiveSource
- PnvXive model has a XiveSource
- PnvPSI model has a XiveSource
- PnvPHB4 model should have also.and the 'xive' pointer in XiveSource points to the parent object,
Quoted 8 lines
Quoted 3 lines
Uh.. yeah.. the xics pointer in ICS units doesn't point to the parent object, except maybe by accident. It's absolutely intended to be global, and so points to the machine.
yes. I agree.
XIVE has more layers and visible components due to the internal tables used for routing.
Right.
Quoted 11 lines
Quoted 8 lines
Quoted 1 line
which will handle the event notification forwarding or routing.
Ok, how about this for a partial model. We have:
XiveSource objects:
* Owns an ESB table
* Knows the mapping of its local irq offsets to global irq numbersThat is the 'offset' attribute I suppose. This is set at runtime for the powernv devices.
Ok, so that offset is effectively a register (which will have to be migrated), rather than a device property.
Quoted 2 lines
For pseries, we should need it for
passthrough. I think. I haven't looked at that part yet.
Uh.. I really hope not. AIUI the offsets are decided by the platform rather than the guest in this case, yes? In which case if we can't count on a fixed offset even in passthrough mode, then migration is basically impossible.
Quoted 4 lines
Quoted 2 lines
* Provides the mmio interface for ESB manipulation
* When neccessary, notifies a new interrupt to a XiveRouterok. I think that what we have today fits the idea then.
Yes, I think so to - just clarifying in the context of the rest of this proposal.
Quoted 5 lines
Quoted 3 lines
XiveRouter objects:
* Responsible for a fixed range of global irq numbers
* Owns an IVT (but what that means can vary, see below)the size of the IVT table is determined at runtime for powernv.
That's fine - both the size and base of the IVT will be registers of the powernv variant of the device.
Quoted 4 lines
Quoted 2 lines
* When notified of an irq, routes it to the appropriate EQ (haven't thought about this part yet)
we will need a class handler to get EQs
Sure.
Quoted 7 lines
Quoted 1 line
* Abstract class - needs subclasses to define how to get IVEs
OK. We will need a few other ops. The router needs to :
- get IVEs
- get EQ descriptors
- update OS EQs (write event data in OS RAM)
IIUC the actual EQ (as opposed to its descriptor) will be in guest RAM for both powernv and spapr, so this can be common (utiliizing a subclass hook to locate the EQ base address).
Quoted 2 lines
- update EQ descriptors (to set EQ descriptor index & toggle)
- get an NVT/VP (to notify CPUs)
Getting NVT/VP sounds more like it would belong in the XiveFabric than the router, but I haven't looked at this in detail yet.
Quoted 6 lines
For powernv, we should also consider updating the NVT/VP. It can be done later.
Quoted 2 lines
XiveFabric interface:
* Lets XIVE components locate each other
Quoted 7 lines
hmm, it should be a chain :
source -> router -> presenter -> cpuSo the components should not have to locate each other. The presenter does not know about the source for instance. Only the sources need to forward events to the main controller logic doing the routing.
source -> router
From the above sounds like we can maybe make this just a router property in the source, rather than a lookup through a fabric.
router -> presenter
Here we might still need a "fabric". By defintion the router can direct to a bunch of different presenters, so it needs some kind of map to find them, no?
presenter -> cpu
This one's trivial; just the cpu->intc pointer or similar.
Quoted 7 lines
Quoted 2 lines
*
get_router()method: maps a global irq number to XiveRouter objectAh. you are thinking about the multichip case under powernv. I need to look at that more closely. But XIVE has a concept of block which is used by skiboot to map a chip to a block and the XIVE tables have a block field.
Hmm.. I think we need to understand this to make a real model. I'd thought the block number would just be the chip number somewhere in the high bits of the global irq, but sounds like there might be yet another indirection here.
Quoted 4 lines
Quoted 1 line
* Always global (implemented on the machine)
OK. this is more or less the object modeling the main interrupt controller ? What I called sPAPRXive in the current patchset.
No. This is *always* global - assuming we need it at all - even on multichip powernv.
Quoted 9 lines
Quoted 4 lines
On pseries we have:
? XiveSource objects. We probably only need one, but 1 for LSI and one for MSI might be convenient.
It's not too ugly for the moment. If we create a source object for LSIs only that might be more complex for passthrough devices and their associated ESB MMIO region.
Quoted 6 lines
side note :
LSIs work under TCG, and used to work under KVM until we removed the StoreEOI support. Since the EOI is now different, we need to find a way to handle EOI for guest virtual LSIs which are not LSIs for the host.
I can't quite picture that case - can you give a concrete example?
Quoted 12 lines
We can still change the Linux spapr
backend or have QEMU handle the EOI for virtual LSIs. This is on my TODO list.Quoted 1 line
More wouldn't break the model
It should not. Initially the pachset had two source objects :
one for IPIs and one for the virtual devices interrupts.Quoted 2 lines
1 sPAPRXiveRouter. This is a subclass of XiveRouter that holds the IVT internall (and migrates it).
Quoted 6 lines
OK.
Quoted 2 lines
the XiveFabric implementation always returns the single global router for
get_router()we can do that.
Again, if it's true that each source object always forwards to just one router, then we don't need a get_router(), we can just use a link property.
Quoted 2 lines
Do we gather all XIVE components objects under an object 'sPAPRXive' modeling that way the main interrupt controller of the machine ?
No, I don't think so.
Quoted 3 lines
It should not have any state but it will hold the TIMA region most certainly, and the addresses where to map the ESB and TIMA regions.
Uh.. I'd expect the TIMAs to be held by the NVT objects, which we haven't covered yet.
Quoted 15 lines
KVM support will bring extra needs.
Quoted 3 lines
On powernv we have:
N XiveSource objects. Some in PHBs, some extra ones on each chipyes and PSI to start with.
Quoted 7 lines
(#chips) PowerXiveRouter objects. This subclass of XiveRouter stores the register giving the IVT base address and migrates that, but the IVT contents are in RAM
the XiveFabric
get_router()implementation returns the right chip's router based on the irq number
Quoted 7 lines
Quoted 1 line
Obviously the
router->EQsides still needs a bunch of thought.These are all routing tables :
- IVT
- EQDT
- VPDT
Thinking about what you've said, I'm thinking maybe what we need on the source side is two versions which don't exactly correspond to spapr vs powernv:
InBandXiveSource: this one's notify behaviour is to issue an mmio read to a configured address. It's expected that mmio address belongs to a XiveRouter, but the source itself doesn't know anything routers.
OutOfBandXiveSource: this one's notify behaviour is to explicitly poke a XiveRouter. A link to the router and offset (which range of router irqs are used by this source) would be object properties.
powernv would use the first for "external" irq sources and the second for internal ones. spapr would use the second for everything.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 03/35] ppc/xive: introduce the XiveFabric interface
Quoted 127 lines · David Gibson
Quoted 126 lines · Cédric Le Goater
Quoted 124 lines · David Gibson
Quoted 113 lines · Cédric Le Goater
Quoted 90 lines · David Gibson
Quoted 89 lines · Cédric Le Goater
Quoted 68 lines · David Gibson
Quoted 61 lines · Cédric Le Goater
Quoted 50 lines · David Gibson
Quoted 49 lines · Cédric Le Goater
The XiveFabric offers a simple interface, between the XiveSourve object and the device model owning the interrupt sources, to forward an event notification to the XIVE interrupt controller of the machine and if the owner is the controller, to call directly the routing sub-engine.
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/xive.c | 37 ++++++++++++++++++++++++++++++++++++- include/hw/ppc/xive.h | 25 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-)hw/intc/xive.c +17
-1@@ -17,6 +17,21 @@#include "hw/ppc/xive.h" /* +* XIVE Fabric +*/ + +static void xive_fabric_route (XiveFabric *xf,int lisn) +{ + +} + +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; + +/* * XIVE Interrupt Source */ @@ -97,11 +112,19 @@ static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno)/* * Forward the source event notification to the associated XiveFabric, -* the device owning the sources. +* the device owning the sources, or perform the routing if the device +* is the interrupt controller. */ static void xive_source_notify (XiveSource *xsrc,int srcno) {Quoted 10 lines
hw/intc/xive.c static bool xive_source_pq_trigger(XiveSource *xsrc, uint32_t srcno) · line 127
Quoted 7 lines
hw/intc/xive.c +7
-0+XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xsrc->xive); + +if (xfc->notify) { + xfc->notify (xsrc->xive, srcno + xsrc->offset); + }else { +xive_fabric_route (xsrc->xive, srcno + xsrc->offset); + }Why 2 cases? Can't the XiveFabric object just make its notify equal to
xive_fabric_routeif that's what it wants?Quoted 3 lines
Under sPAPR, all the sources, IPIs and virtual device interrupts, generate events which are directly routed by
xive_fabric_route(). There is no need of an extra hop. Indeed.Ok.
Quoted 7 lines
Quoted 4 lines
Under PowerNV, some sources forward the notification to the routing engine using a specific MMIO load on a notify address which is stored in one of the controller registers. So we need a hop to reach the device model, owning the sources, and do that load :
Hm. So you're saying that in pnv some sources send their notification to some other unit,
Not to any unit/device, to the device owning the sources.
For the XiveSource object under PSI, the XIVEFabric interface is the PSI device object it self, which knows how to forward the notification on the XIVE Power "bus". To be more precise, the PSI HB device has 14 interrupt sources, which notifications are forwarded using a MMIO load to some address. The load address is configured (by skiboot) in one of the PSI device registers, and points to a MMIO region of the main XIVE interrupt controller.
The PHB4 sources should be the same.
Quoted 8 lines
Quoted 5 lines
For the XiveSource object (all interrupts) under sPAPRXive, the XIVEFabric is the main interrupt controller sPAPRXive.
For the XiveSource object (IPIs) under PnvXive, the XIVEFabric is also the main interrupt controller PnvXive.
Hrm. Apparently I'm missing something, I'm really not getting what you're trying to explain here.
I see that. Let's try again.
Quoted 11 lines
Quoted 3 lines
Quoted 1 line
that would then (after possible masking) forward on to the overall> xive fabric ?
yes. May be XIVEFabric is a confusing name. What about XIVEForwarder ?
Maybe..?
Quoted 4 lines
Quoted 1 line
That seems like a property of the source object,
The source object is generic. It's a bunch of PQ bits that can be controlled by MMIOs. Nothing more.
Quoted 7 lines
Quoted 2 lines
Hmm. Isn't the source object also responsible for forwarding the interrupt to something up the chain (whatever that is)?
Yes but it can not forward directly. The XiveSource is generic and can only call a handler :
xfc->notify(xsrc->xive, srcno + xsrc->offset);But.. your patch doesn't do that always, it's conditional which I still don't understand.
Quoted 7 lines
Quoted 1 line
Because at the end of the notify/forward chain, you route.
Hrm. I'm really not understanding this notify/forward thing as distinct from routing. I mean, from the description here it sounds kind of like cascaded interrupt controllers, which qemu already has mechanisms to handle, but I didn't think (most) POWER9 devices worked like that.
they don't.
The concept I have in mind for the XIVEFabric QOM interface is something close to the XIVE logic unit in HW which links the device interrupt sources and the XIVE interrupt controller of the chip to the PowerBUS. The interrupt controller also has a special CQ (common queue) unit acting as a proxy for the PowerBus for the virtualization/router and the presenter units.
It's a convenient model for QEMU because the XiveSource model only has to call an interface handler when a notification event is let through. It's like doing a MMIO to send on the PowerBUS the ISN of the source that just triggered.
Quoted 16 lines
Quoted 16 lines
Quoted 4 lines
Quoted 2 lines
The device model owner, the parent of the XiveSource object, would do the real forward.
Why?
because, in my idea of the XiveSource concept, it does not have the logic to do so: the register for the MMIO address to use, another one for the IVT offset, etc
Quoted 4 lines
I mean the XiveSource basically represents the xive irq related logic of the PHB or whatever, why would it not represent *all* of that, rather than just the ESB bits, meaning the owner has to have some more xive logic for the forwarding.
ok. This is where we diverge in the concept.
Quoted 7 lines
Quoted 3 lines
The PQ bits, the ESB MMIO region handlers can be easily shared between the different device models. They are the common part of devices with XIVE interrupt sources.
Sure, but QOM subclasses are a thing, which sounds like a better way of doing this than having to have extra XIVE logic in all the parent devices.
I agree It can be done with subclasses also but QOM interfaces are quickly defined and stateless.
On sPAPR, the extra XIVE logic would only be the sPAPRXive model acting as the machine interrupt controller model. It owns all the guest interrupt sources.
In PowerNV, we would have the PnvXive interrupt controller model for the chip, which also owns the IPI sources, and the PSIHB model and the PHB4 model.
This is very much like XICS. Each relevant device has one or more ICSstate objects. ICSstate has a pointer to the XICSfabric.
Quoted 11 lines
Quoted 7 lines
Quoted 3 lines
Note that I don't think the fact that some sources notify via mmio and some are internal really matters. It's not like we're modelling the power bus down to the wire-transaction level.
yes but the configuration of the devices are different. pnv devices will have registers accessible through MMIO or XSCOM and configured by the firmware. spapr is all set up by QEMU.
Ah.. ok. Actually modelling the mmio forwards probably makes sense then. I still think it makes more sense in a pnv XiveSource subclass rather than putting it in the containing device.
Hmm, we will then need to define classes for the sPAPRXiveSource, PnvXiveSource, PSIXiveSource, which works fine for sure. But with a QOM interface, we could use directly the XiveSource class.
I will take a look.
Quoted 46 lines
Quoted 26 lines
Quoted 6 lines
Quoted 6 lines
It's very similar to what we have today with XICS :
- The sPAPR model has an ICSState
- The PnvPSI model has an ICSState
- The PnvPHB3 model has two ICSStatesQuoted 8 lines
Quoted 3 lines
and the 'xics' pointer in ICSState points to the 'interrupt unit' of the machine to do resends and to grab ICPs. So it used for routing essentially.
Hmm. I think you and I are looking at XICSFabric kind of differently. As I see it, it's not really an active component at all. Rather it's basically a global "map" of the xics components so that they can find each other.
ok. I am not that far either.
Quoted 9 lines
Quoted 8 lines
in Xive
- sPAPRXive model has a XiveSource
- PnvXive model has a XiveSource
- PnvPSI model has a XiveSource
- PnvPHB4 model should have also.and the 'xive' pointer in XiveSource points to the parent object,
Quoted 8 lines
Quoted 3 lines
Uh.. yeah.. the xics pointer in ICS units doesn't point to the parent object, except maybe by accident. It's absolutely intended to be global, and so points to the machine.
yes. I agree.
XIVE has more layers and visible components due to the internal tables used for routing.
Right.
Quoted 9 lines
Quoted 8 lines
Quoted 1 line
which will handle the event notification forwarding or routing.
Ok, how about this for a partial model. We have:
XiveSource objects:
* Owns an ESB table
* Knows the mapping of its local irq offsets to global irq numbers
Quoted 5 lines
Quoted 2 lines
That is the 'offset' attribute I suppose. This is set at runtime for the powernv devices.
Ok, so that offset is effectively a register (which will have to be migrated), rather than a device property.
powernv migration is a not on my radar yet :)
Quoted 5 lines
Quoted 2 lines
For pseries, we should need it for
passthrough. I think. I haven't looked at that part yet.Uh.. I really hope not. AIUI the offsets are decided by the platform rather than the guest in this case, yes?
A mapping is done in the guest. I still need to check how the ESB pages are populated in the guest ESB MMIO region. We should be fine I think.
Quoted 10 lines
In which case if we can't
count on a fixed offset even in passthrough mode, then migration is basically impossible.Quoted 4 lines
Quoted 2 lines
Quoted 1 line
* Provides the mmio interface for ESB manipulation
* When neccessary, notifies a new interrupt to a XiveRouter
ok. I think that what we have today fits the idea then.
Yes, I think so to - just clarifying in the context of the rest of this proposal.
yes. I think we should be adding a XiveRouter class like you propose below.
Quoted 18 lines
Quoted 5 lines
Quoted 3 lines
XiveRouter objects:
* Responsible for a fixed range of global irq numbers
* Owns an IVT (but what that means can vary, see below)the size of the IVT table is determined at runtime for powernv.
That's fine - both the size and base of the IVT will be registers of the powernv variant of the device.
Quoted 4 lines
Quoted 2 lines
* When notified of an irq, routes it to the appropriate EQ (haven't thought about this part yet)
we will need a class handler to get EQs
Sure.
Quoted 2 lines
Quoted 1 line
* Abstract class - needs subclasses to define how to get IVEs
Quoted 8 lines
Quoted 5 lines
OK. We will need a few other ops. The router needs to :
- get IVEs
- get EQ descriptors
- update OS EQs (write event data in OS RAM)IIUC the actual EQ (as opposed to its descriptor) will be in guest RAM for both powernv and spapr,
yes.
Quoted 2 lines
so this can be common (utiliizing a
subclass hook to locate the EQ base address).
yes.
Quoted 5 lines
Quoted 2 lines
- update EQ descriptors (to set EQ descriptor index & toggle)
- get an NVT/VP (to notify CPUs)Getting NVT/VP sounds more like it would belong in the XiveFabric than the router, but I haven't looked at this in detail yet.
The VP table is owned by the presenter unit. It is notified by the router unit when an event is let through. The presenter then looks for the VP to notify among the VPs dispatched on the HW threads. If none is found, the event is escalated.
The router units owns the IVE and the EQ tables, but still can do some remote access to the VPDT, to update the backlog and IBP I think. I don't think we need to introduce a presenter model, accessors for the VPs should enough.
Quoted 10 lines
Quoted 10 lines
For powernv, we should also consider updating the NVT/VP. It can be done later.
Quoted 2 lines
XiveFabric interface:
* Lets XIVE components locate each otherhmm, it should be a chain :
source -> router -> presenter -> cpu
Quoted 8 lines
Quoted 3 lines
So the components should not have to locate each other. The presenter does not know about the source for instance. Only the sources need to forward events to the main controller logic doing the routing.
source -> router
From the above sounds like we can maybe make this just a router property in the source, rather than a lookup through a fabric.
If we use a direct link from the source to the router, how do we handle the powernv case which does event notification with a MMIO load ? I think a call through an interface is better (the XiveFabric)
Quoted 5 lines
router -> presenter
Here we might still need a "fabric". By defintion the router can direct to a bunch of different presenters, so it needs some kind of map to find them, no?
yes. The vp_block identifies the chip. There are different possible scenarios for the block configuration on a system but OPAL uses a simple one : one chip <-> one block. We can use that to start with on PowerNV.
And on pseries, just use block 0 for all, we don't really care. The concept of block does not reach the spapr specs.
As for the presenter it self, it loops on the CPUs to check the CAM line register of the thread interrupt management context to see if one matches vp_block+vp_index. This is one routine. I don't think we need a model for that.
Quoted 3 lines
presenter -> cpu
This one's trivial; just the
cpu->intcpointer or similar.
yes. We store under the cpu the thread interrupt management context, which is a set of registers that the OS accesses through the TIMA, one per machine.
Quoted 8 lines
Quoted 7 lines
Quoted 2 lines
*
get_router()method: maps a global irq number to XiveRouter objectAh. you are thinking about the multichip case under powernv. I need to look at that more closely. But XIVE has a concept of block which is used by skiboot to map a chip to a block and the XIVE tables have a block field.
Quoted 4 lines
Hmm.. I think we need to understand this to make a real model. I'd thought the block number would just be the chip number somewhere in the high bits of the global irq, but sounds like there might be yet another indirection here.
We have a one-to-one mapping today. I doubt it will change. We can start with that.
Quoted 17 lines
Quoted 4 lines
Quoted 1 line
* Always global (implemented on the machine)
OK. this is more or less the object modeling the main interrupt controller ? What I called sPAPRXive in the current patchset.
No. This is *always* global - assuming we need it at all - even on multichip powernv.
Quoted 9 lines
Quoted 4 lines
On pseries we have:
? XiveSource objects. We probably only need one, but 1 for LSI and one for MSI might be convenient.
It's not too ugly for the moment. If we create a source object for LSIs only that might be more complex for passthrough devices and their associated ESB MMIO region.
Quoted 8 lines
Quoted 6 lines
side note :
LSIs work under TCG, and used to work under KVM until we removed the StoreEOI support. Since the EOI is now different, we need to find a way to handle EOI for guest virtual LSIs which are not LSIs for the host.
I can't quite picture that case - can you give a concrete example?
A guest won't be able to use a rtl8139 nic under KVM.
As it is the guest that does the EOI, it should use the appropriate sequence depending on the interrupt type, LSI vs. MSI. The store EOI was used for both types until we removed the support bc of ordering issues. So now, the guest uses a specific EOI sequence for LSI but the hypervisor implements virtual LSIs on top of IPIs interrupts which are MSIs ... we are doomed. We need to fix the guest or to find a way to reroute such interrupts to QEMU.
Quoted 15 lines
Quoted 15 lines
We can still change the Linux spapr
backend or have QEMU handle the EOI for virtual LSIs. This is on my TODO list.Quoted 1 line
More wouldn't break the model
It should not. Initially the pachset had two source objects :
one for IPIs and one for the virtual devices interrupts.Quoted 2 lines
1 sPAPRXiveRouter. This is a subclass of XiveRouter that holds the IVT internall (and migrates it).
OK.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
the XiveFabric implementation always returns the single global router for
get_router()we can do that.
Again, if it's true that each source object always forwards to just one router, then we don't need a
get_router(), we can just use a link property.
that is the goal of the architecture, yes. powernv sources use MMIOs to forward events to the router and source event notifications are usually forwarded to the local chip.
There are some case in which the IVE lookups are be remote. We can use the block to scan the system chips for that. we don't have to implement all the protocol.
Quoted 5 lines
Quoted 3 lines
Do we gather all XIVE components objects under an object 'sPAPRXive' modeling that way the main interrupt controller of the machine ?
No, I don't think so.
Hmm,
sPAPRXive would inherit from the XiveRouter and define the IVT and the EQDT. It is also practical to set up the TIMA memory region which is unique per machine. KVM support will need custom version of this model.
Quoted 6 lines
Quoted 3 lines
It should not have any state but it will hold the TIMA region most certainly, and the addresses where to map the ESB and TIMA regions.
Uh.. I'd expect the TIMAs to be held by the NVT objects, which we haven't covered yet.
There is a set of registers per CPU (thread interrupt management context), but there is one TIMA (thread interrupt management areao) memory region for the whole machine.
We should change the NVT name, it is confusing. NVT is an old name for the backing store struct in RAM, which was replaced by VP.
XiveTCTX (Xive Thread Context) is better IMO and its reflects the names of the IC registers.
Quoted 31 lines
Quoted 15 lines
KVM support will bring extra needs.
Quoted 3 lines
On powernv we have:
N XiveSource objects. Some in PHBs, some extra ones on each chipyes and PSI to start with.
Quoted 7 lines
(#chips) PowerXiveRouter objects. This subclass of XiveRouter stores the register giving the IVT base address and migrates that, but the IVT contents are in RAM
the XiveFabric
get_router()implementation returns the right chip's router based on the irq numberQuoted 7 lines
Quoted 1 line
Obviously the
router->EQsides still needs a bunch of thought.These are all routing tables :
- IVT
- EQDT
- VPDTThinking about what you've said, I'm thinking maybe what we need on the source side is two versions which don't exactly correspond to spapr vs powernv:
InBandXiveSource: this one's notify behaviour is to issue an mmio read to a configured address. It's expected that mmio address belongs to a XiveRouter, but the source itself doesn't know anything routers.
Quoted 7 lines
OutOfBandXiveSource: this one's notify behaviour is to explicitly poke a XiveRouter. A link to the router and offset (which range of router irqs are used by this source) would be object properties.
powernv would use the first for "external" irq sources and the second for internal ones. spapr would use the second for everything.
OK.
I think I will stick to my idea for the next version because there are quite a lot of changes in the models already : a new spapr irq backend, a XiveRouter, a EQD table for sPAPR, a complete TIMA support for all privileges, a renamed XiveTCTX, a simple Presenter scanning CAM lines, support for EQ ESBs (that no system uses), a pseries-2.13-xive machine, etc.
I will share the powernv and PSIHB models to validate the common XIVE model. We can change to the above if it is really not satisfying.
Thanks,
C.
PATCH v3 4/35 spapr/xive: introduce a XIVE interrupt controller for sPAPR
In reply to Cédric Le GoatersPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Changes since v2 :
- introduced the XiveFabric interface
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/spapr_xive.c | 159 ++++++++++++++++++++++++++++++++++++++ hw/intc/xive.c | 7 ++ include/hw/ppc/spapr_xive.h | 31 ++++++++ include/hw/ppc/xive.h | 5 ++ include/hw/ppc/xive_regs.h | 33 ++++++++ 7 files changed, 237 insertions(+) create mode 100644 hw/intc/spapr_xive.c create mode 100644 include/hw/ppc/spapr_xive.h create mode 100644 include/hw/ppc/xive_regs.h
default-configs/ppc64-softmmu.mak +1 -0
@@ -17,4 +17,5 @@ CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_XIVE=$(CONFIG_PSERIES) +CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=y
hw/intc/Makefile.objs +1 -0
@@ -38,6 +38,7 @@ obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_XIVE) += xive.o +obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o
hw/intc/spapr_xive.c new file +159 -0
159 lines not on this page · raw message
hw/intc/xive.c +7 -0
@@ -20,6 +20,13 @@* XIVE Fabric */ +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn) +{ +XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xf); + +return xfc->get_ive (xf, lisn); +} +static void xive_fabric_route (XiveFabric *xf,int lisn) {
include/hw/ppc/spapr_xive.h new file +31 -0
@@ -0,0 +1,31 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_SPAPR_XIVE_H +#define PPC_SPAPR_XIVE_H + +#include "hw/sysbus.h" +#include "hw/ppc/xive.h" + +#define TYPE_SPAPR_XIVE "spapr-xive" +#define SPAPR_XIVE (obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE) + +typedef struct sPAPRXive { +SysBusDevice parent; + +/* Routing table */ +XiveIVE *ivt; +uint32_t nr_irqs; +}sPAPRXive ; + +bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi); +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn); +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon); + +#endif /* PPC_SPAPR_XIVE_H */
include/hw/ppc/xive.h +5 -0
@@ -11,6 +11,7 @@#define PPC_XIVE_H #include "hw/sysbus.h" +#include "hw/ppc/xive_regs.h" typedef struct XiveFabric XiveFabric ;
@@ -166,6 +167,10 @@ typedef struct XiveFabric {typedef struct XiveFabricClass {InterfaceClass parent;void (*notify)(XiveFabric *xf,uint32_t lisn); + +XiveIVE *(*get_ive)(XiveFabric *xf,uint32_t lisn); }XiveFabricClass ; +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn); +#endif /* PPC_XIVE_H */
include/hw/ppc/xive_regs.h new file +33 -0
@@ -0,0 +1,33 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2016-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef _PPC_XIVE_REGS_H +#define _PPC_XIVE_REGS_H + +/* IVE/EAS +* +* One per interrupt source. Targets that interrupt to a given EQ +* and provides the corresponding logical interrupt number (EQ data) +* +* We also map this structure to the escalation descriptor inside +* an EQ, though in that case the valid and masked bits are not used. +*/ +typedef struct XiveIVE { +/* Use a single 64-bit definition to make it easier to +* perform atomic updates +*/ +uint64_t w; +#define IVE_VALID PPC_BIT(0) +#define IVE_EQ_BLOCK PPC_BITMASK(4, 7)/* Destination EQ block# */ +#define IVE_EQ_INDEX PPC_BITMASK(8, 31)/* Destination EQ index */ +#define IVE_MASKED PPC_BIT(32)/* Masked */ +#define IVE_EQ_DATA PPC_BITMASK(33, 63)/* Data written to the EQ */ +}XiveIVE ; + +#endif /* _INTC_XIVE_INTERNAL_H */
Signature · 1 line
2.13.6
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 5 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Quoted 8 lines
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Quoted 87 lines
Changes since v2 :
- introduced the XiveFabric interface
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/spapr_xive.c | 159 ++++++++++++++++++++++++++++++++++++++ hw/intc/xive.c | 7 ++ include/hw/ppc/spapr_xive.h | 31 ++++++++ include/hw/ppc/xive.h | 5 ++ include/hw/ppc/xive_regs.h | 33 ++++++++ 7 files changed, 237 insertions(+) create mode 100644 hw/intc/spapr_xive.c create mode 100644 include/hw/ppc/spapr_xive.h create mode 100644 include/hw/ppc/xive_regs.hdefault-configs/ppc64-softmmu.mak +1
-0@@ -17,4 +17,5 @@ CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_XIVE=$(CONFIG_PSERIES) +CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=yhw/intc/Makefile.objs +1
-0@@ -38,6 +38,7 @@ obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_XIVE) += xive.o +obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/spapr_xive.c new file +42
-0@@ -0,0 +1,159 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "monitor/monitor.h" +#include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive_regs.h" + +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) +{ +int i; + +monitor_printf (mon,"IVE Table\n" ); +for (i =0 ; i < xive->nr_irqs; i++) { +XiveIVE *ive = &xive->ivt[i]; + +if (!(ive->w &IVE_VALID )) { +continue ; + } + +monitor_printf (mon," %4x %s %08x %08x\n" , i, + ive->w &IVE_MASKED ?"M" :" " , + (int )GETFIELD (IVE_EQ_INDEX , ive->w), + (int )GETFIELD (IVE_EQ_DATA , ive->w)); + } +} + +static void spapr_xive_reset (DeviceState *dev) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); +int i; +
hw/intc/spapr_xive.c line 52
Quoted 10 lines
hw/intc/spapr_xive.c new file +10
-0+/* Mask all valid IVEs in the IRQ number space. */ +for (i =0 ; i < xive->nr_irqs; i++) { +XiveIVE *ive = &xive->ivt[i]; +if (ive->w &IVE_VALID ) { + ive->w |=IVE_MASKED ; + } + } +} + +static void spapr_xive_init (Object *obj)
I'm trying to standardize on init_instance methods being called *_instance_init(). It helps to make it obvious that this is ineed an instance_init() method, rather than one of the various other init calls that exist in various places.
Quoted 224 lines
hw/intc/spapr_xive.c new file +107
-0+{ + +} + +static void spapr_xive_realize (DeviceState *dev,Error **errp) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); + +if (!xive->nr_irqs) { +error_setg (errp,"Number of interrupt needs to be greater 0" ); +return ; + } + +/* Allocate the Interrupt Virtualization Table */ + xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); +} + +static XiveIVE *spapr_xive_get_ive (XiveFabric *xf,uint32_t lisn) +{ +sPAPRXive *xive =SPAPR_XIVE (xf); + +return lisn < xive->nr_irqs ? &xive->ivt[lisn] :NULL ; +} + +static const VMStateDescription vmstate_spapr_xive_ive = { + .name =TYPE_SPAPR_XIVE "/ive" , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT64 (w, XiveIVE), +VMSTATE_END_OF_LIST () + }, +}; + +static const VMStateDescription vmstate_spapr_xive = { + .name =TYPE_SPAPR_XIVE , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT32_EQUAL (nr_irqs, sPAPRXive,NULL ), +VMSTATE_STRUCT_VARRAY_POINTER_UINT32 (ivt, sPAPRXive, nr_irqs, + vmstate_spapr_xive_ive, XiveIVE), +VMSTATE_END_OF_LIST () + }, +}; + +static Property spapr_xive_properties[] = { +DEFINE_PROP_UINT32 ("nr-irqs" , sPAPRXive, nr_irqs,0 ), +DEFINE_PROP_END_OF_LIST (), +}; + +static void spapr_xive_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); +XiveFabricClass *xfc =XIVE_FABRIC_CLASS (klass); + + dc->realize = spapr_xive_realize; + dc->reset = spapr_xive_reset; + dc->props = spapr_xive_properties; + dc->desc ="sPAPR XIVE interrupt controller" ; + dc->vmsd = &vmstate_spapr_xive; + + xfc->get_ive = spapr_xive_get_ive; +} + +static const TypeInfo spapr_xive_info = { + .name =TYPE_SPAPR_XIVE , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_init = spapr_xive_init, + .instance_size =sizeof (sPAPRXive), + .class_init = spapr_xive_class_init, + .interfaces = (InterfaceInfo []) { + {TYPE_XIVE_FABRIC }, + { }, + }, +}; + +static void spapr_xive_register_types (void ) +{ +type_register_static (&spapr_xive_info); +} + +type_init (spapr_xive_register_types) + +bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi) +{ +XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); + +if (!ive) { +return false; + } + + ive->w |=IVE_VALID ; +return true; +} + +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn) +{ +XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); + +if (!ive) { +return false; + } + + ive->w &= ~IVE_VALID ; +return true; +}hw/intc/xive.c +7
-0@@ -20,6 +20,13 @@* XIVE Fabric */ +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn) +{ +XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xf); + +return xfc->get_ive (xf, lisn); +} +static void xive_fabric_route (XiveFabric *xf,int lisn) {include/hw/ppc/spapr_xive.h new file +31
-0@@ -0,0 +1,31 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_SPAPR_XIVE_H +#define PPC_SPAPR_XIVE_H + +#include "hw/sysbus.h" +#include "hw/ppc/xive.h" + +#define TYPE_SPAPR_XIVE "spapr-xive" +#define SPAPR_XIVE (obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE) + +typedef struct sPAPRXive { +SysBusDevice parent; + +/* Routing table */ +XiveIVE *ivt; +uint32_t nr_irqs; +}sPAPRXive ; + +bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi); +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn); +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon); + +#endif /* PPC_SPAPR_XIVE_H */ include/hw/ppc/xive.h +5
-0@@ -11,6 +11,7 @@#define PPC_XIVE_H #include "hw/sysbus.h" +#include "hw/ppc/xive_regs.h" typedef struct XiveFabric XiveFabric ;@@ -166,6 +167,10 @@ typedef struct XiveFabric {typedef struct XiveFabricClass {InterfaceClass parent;void (*notify)(XiveFabric *xf,uint32_t lisn); + +XiveIVE *(*get_ive)(XiveFabric *xf,uint32_t lisn); }XiveFabricClass ; +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn); +#endif /* PPC_XIVE_H */ include/hw/ppc/xive_regs.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2016-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef _PPC_XIVE_REGS_H +#define _PPC_XIVE_REGS_H + +/* IVE/EAS +* +* One per interrupt source. Targets that interrupt to a given EQ +* and provides the corresponding logical interrupt number (EQ data) +* +* We also map this structure to the escalation descriptor inside +* an EQ, though in that case the valid and masked bits are not used. +*/ +typedef struct XiveIVE { +/* Use a single 64-bit definition to make it easier to +* perform atomic updates +*/ +uint64_t w; +#define IVE_VALID PPC_BIT(0) +#define IVE_EQ_BLOCK PPC_BITMASK(4, 7)/* Destination EQ block# */ +#define IVE_EQ_INDEX PPC_BITMASK(8, 31)/* Destination EQ index */ +#define IVE_MASKED PPC_BIT(32)/* Masked */ +#define IVE_EQ_DATA PPC_BITMASK(33, 63)/* Data written to the EQ */ +}XiveIVE ; + +#endif /* _INTC_XIVE_INTERNAL_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 9 lines · David Gibson
Quoted 8 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Quoted 8 lines
Quoted 5 lines
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
There is only one, the main IC.
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a set_eq() to push the EQ data.
The XiveRouter would also be a XiveFabric (or some other name) to let the internal sources of the interrupt controller forward events.
Quoted 94 lines
Quoted 94 lines
Changes since v2 :
- introduced the XiveFabric interface
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/spapr_xive.c | 159 ++++++++++++++++++++++++++++++++++++++ hw/intc/xive.c | 7 ++ include/hw/ppc/spapr_xive.h | 31 ++++++++ include/hw/ppc/xive.h | 5 ++ include/hw/ppc/xive_regs.h | 33 ++++++++ 7 files changed, 237 insertions(+) create mode 100644 hw/intc/spapr_xive.c create mode 100644 include/hw/ppc/spapr_xive.h create mode 100644 include/hw/ppc/xive_regs.hdefault-configs/ppc64-softmmu.mak +1
-0@@ -17,4 +17,5 @@ CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_XIVE=$(CONFIG_PSERIES) +CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=yhw/intc/Makefile.objs +1
-0@@ -38,6 +38,7 @@ obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_XIVE) += xive.o +obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/spapr_xive.c new file +49
-0@@ -0,0 +1,159 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "monitor/monitor.h" +#include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive_regs.h" + +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) +{ +int i; + +monitor_printf (mon,"IVE Table\n" ); +for (i =0 ; i < xive->nr_irqs; i++) { +XiveIVE *ive = &xive->ivt[i]; + +if (!(ive->w &IVE_VALID )) { +continue ; + } + +monitor_printf (mon," %4x %s %08x %08x\n" , i, + ive->w &IVE_MASKED ?"M" :" " , + (int )GETFIELD (IVE_EQ_INDEX , ive->w), + (int )GETFIELD (IVE_EQ_DATA , ive->w)); + } +} + +static void spapr_xive_reset (DeviceState *dev) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); +int i; + +/* Mask all valid IVEs in the IRQ number space. */ +for (i =0 ; i < xive->nr_irqs; i++) { +XiveIVE *ive = &xive->ivt[i]; +if (ive->w &IVE_VALID ) { + ive->w |=IVE_MASKED ; + } + }
Quoted 8 lines
hw/intc/spapr_xive.c line 52
Quoted 3 lines
hw/intc/spapr_xive.c new file +3
-0+} + +static void spapr_xive_init (Object *obj)I'm trying to standardize on
init_instancemethods being called*_instance_init(). It helps to make it obvious that this is ineed aninstance_init()method, rather than one of the various other init calls that exist in various places.
ok. this is good practice. I will fix.
Thanks,
C.
Quoted 226 lines
Quoted 225 lines
hw/intc/spapr_xive.c new file +107
-0+{ + +} + +static void spapr_xive_realize (DeviceState *dev,Error **errp) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); + +if (!xive->nr_irqs) { +error_setg (errp,"Number of interrupt needs to be greater 0" ); +return ; + } + +/* Allocate the Interrupt Virtualization Table */ + xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); +} + +static XiveIVE *spapr_xive_get_ive (XiveFabric *xf,uint32_t lisn) +{ +sPAPRXive *xive =SPAPR_XIVE (xf); + +return lisn < xive->nr_irqs ? &xive->ivt[lisn] :NULL ; +} + +static const VMStateDescription vmstate_spapr_xive_ive = { + .name =TYPE_SPAPR_XIVE "/ive" , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT64 (w, XiveIVE), +VMSTATE_END_OF_LIST () + }, +}; + +static const VMStateDescription vmstate_spapr_xive = { + .name =TYPE_SPAPR_XIVE , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT32_EQUAL (nr_irqs, sPAPRXive,NULL ), +VMSTATE_STRUCT_VARRAY_POINTER_UINT32 (ivt, sPAPRXive, nr_irqs, + vmstate_spapr_xive_ive, XiveIVE), +VMSTATE_END_OF_LIST () + }, +}; + +static Property spapr_xive_properties[] = { +DEFINE_PROP_UINT32 ("nr-irqs" , sPAPRXive, nr_irqs,0 ), +DEFINE_PROP_END_OF_LIST (), +}; + +static void spapr_xive_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); +XiveFabricClass *xfc =XIVE_FABRIC_CLASS (klass); + + dc->realize = spapr_xive_realize; + dc->reset = spapr_xive_reset; + dc->props = spapr_xive_properties; + dc->desc ="sPAPR XIVE interrupt controller" ; + dc->vmsd = &vmstate_spapr_xive; + + xfc->get_ive = spapr_xive_get_ive; +} + +static const TypeInfo spapr_xive_info = { + .name =TYPE_SPAPR_XIVE , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_init = spapr_xive_init, + .instance_size =sizeof (sPAPRXive), + .class_init = spapr_xive_class_init, + .interfaces = (InterfaceInfo []) { + {TYPE_XIVE_FABRIC }, + { }, + }, +}; + +static void spapr_xive_register_types (void ) +{ +type_register_static (&spapr_xive_info); +} + +type_init (spapr_xive_register_types) + +bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi) +{ +XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); + +if (!ive) { +return false; + } + + ive->w |=IVE_VALID ; +return true; +} + +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn) +{ +XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); + +if (!ive) { +return false; + } + + ive->w &= ~IVE_VALID ; +return true; +}hw/intc/xive.c +7
-0@@ -20,6 +20,13 @@* XIVE Fabric */ +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn) +{ +XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xf); + +return xfc->get_ive (xf, lisn); +} +static void xive_fabric_route (XiveFabric *xf,int lisn) {include/hw/ppc/spapr_xive.h new file +31
-0@@ -0,0 +1,31 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_SPAPR_XIVE_H +#define PPC_SPAPR_XIVE_H + +#include "hw/sysbus.h" +#include "hw/ppc/xive.h" + +#define TYPE_SPAPR_XIVE "spapr-xive" +#define SPAPR_XIVE (obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE) + +typedef struct sPAPRXive { +SysBusDevice parent; + +/* Routing table */ +XiveIVE *ivt; +uint32_t nr_irqs; +}sPAPRXive ; + +bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi); +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn); +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon); + +#endif /* PPC_SPAPR_XIVE_H */ include/hw/ppc/xive.h +5
-0@@ -11,6 +11,7 @@#define PPC_XIVE_H #include "hw/sysbus.h" +#include "hw/ppc/xive_regs.h" typedef struct XiveFabric XiveFabric ;@@ -166,6 +167,10 @@ typedef struct XiveFabric {typedef struct XiveFabricClass {InterfaceClass parent;void (*notify)(XiveFabric *xf,uint32_t lisn); + +XiveIVE *(*get_ive)(XiveFabric *xf,uint32_t lisn); }XiveFabricClass ; +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn); +#endif /* PPC_XIVE_H */ include/hw/ppc/xive_regs.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2016-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef _PPC_XIVE_REGS_H +#define _PPC_XIVE_REGS_H + +/* IVE/EAS +* +* One per interrupt source. Targets that interrupt to a given EQ +* and provides the corresponding logical interrupt number (EQ data) +* +* We also map this structure to the escalation descriptor inside +* an EQ, though in that case the valid and masked bits are not used. +*/ +typedef struct XiveIVE { +/* Use a single 64-bit definition to make it easier to +* perform atomic updates +*/ +uint64_t w; +#define IVE_VALID PPC_BIT(0) +#define IVE_EQ_BLOCK PPC_BITMASK(4, 7)/* Destination EQ block# */ +#define IVE_EQ_INDEX PPC_BITMASK(8, 31)/* Destination EQ index */ +#define IVE_MASKED PPC_BIT(32)/* Masked */ +#define IVE_EQ_DATA PPC_BITMASK(33, 63)/* Data written to the EQ */ +}XiveIVE ; + +#endif /* _INTC_XIVE_INTERNAL_H */
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 13 lines · Cédric Le Goater
Quoted 12 lines · David Gibson
Quoted 11 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
There is only one, the main IC.
Ok, that's what I thought originally. In that case some of the stuff in the patches really doesn't make sense to me.
Quoted 9 lines
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a
set_eq()to push the EQ data.
Hrm. Well, to add some more clarity, let's say the XiveRouter is the object which owns the IVT. It may or may not do other stuff as well.
Now IIUC, on pnv the IVT lives in main system memory. Under PAPR is the IVT in guest memory, or is it outside (updated by hypercalls/rtas)?
Quoted 2 lines
The XiveRouter would also be a XiveFabric (or some other name) to let the internal sources of the interrupt controller forward events.
The further we go here, the less sure I am that XiveFabric even makes sense as a concept.
Quoted 337 lines
Quoted 95 lines
Quoted 95 lines
Changes since v2 :
- introduced the XiveFabric interface
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/spapr_xive.c | 159 ++++++++++++++++++++++++++++++++++++++ hw/intc/xive.c | 7 ++ include/hw/ppc/spapr_xive.h | 31 ++++++++ include/hw/ppc/xive.h | 5 ++ include/hw/ppc/xive_regs.h | 33 ++++++++ 7 files changed, 237 insertions(+) create mode 100644 hw/intc/spapr_xive.c create mode 100644 include/hw/ppc/spapr_xive.h create mode 100644 include/hw/ppc/xive_regs.hdefault-configs/ppc64-softmmu.mak +1
-0@@ -17,4 +17,5 @@ CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_XIVE=$(CONFIG_PSERIES) +CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=yhw/intc/Makefile.objs +1
-0@@ -38,6 +38,7 @@ obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_XIVE) += xive.o +obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/spapr_xive.c new file +49
-0@@ -0,0 +1,159 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "monitor/monitor.h" +#include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive_regs.h" + +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) +{ +int i; + +monitor_printf (mon,"IVE Table\n" ); +for (i =0 ; i < xive->nr_irqs; i++) { +XiveIVE *ive = &xive->ivt[i]; + +if (!(ive->w &IVE_VALID )) { +continue ; + } + +monitor_printf (mon," %4x %s %08x %08x\n" , i, + ive->w &IVE_MASKED ?"M" :" " , + (int )GETFIELD (IVE_EQ_INDEX , ive->w), + (int )GETFIELD (IVE_EQ_DATA , ive->w)); + } +} + +static void spapr_xive_reset (DeviceState *dev) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); +int i; + +/* Mask all valid IVEs in the IRQ number space. */ +for (i =0 ; i < xive->nr_irqs; i++) { +XiveIVE *ive = &xive->ivt[i]; +if (ive->w &IVE_VALID ) { + ive->w |=IVE_MASKED ; + } + }Quoted 8 lines
hw/intc/spapr_xive.c line 52
Quoted 3 lines
hw/intc/spapr_xive.c new file +3
-0+} + +static void spapr_xive_init (Object *obj)I'm trying to standardize on
init_instancemethods being called*_instance_init(). It helps to make it obvious that this is ineed aninstance_init()method, rather than one of the various other init calls that exist in various places.ok. this is good practice. I will fix.
Thanks,
C.
Quoted 226 lines
Quoted 225 lines
hw/intc/spapr_xive.c new file +107
-0+{ + +} + +static void spapr_xive_realize (DeviceState *dev,Error **errp) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); + +if (!xive->nr_irqs) { +error_setg (errp,"Number of interrupt needs to be greater 0" ); +return ; + } + +/* Allocate the Interrupt Virtualization Table */ + xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); +} + +static XiveIVE *spapr_xive_get_ive (XiveFabric *xf,uint32_t lisn) +{ +sPAPRXive *xive =SPAPR_XIVE (xf); + +return lisn < xive->nr_irqs ? &xive->ivt[lisn] :NULL ; +} + +static const VMStateDescription vmstate_spapr_xive_ive = { + .name =TYPE_SPAPR_XIVE "/ive" , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT64 (w, XiveIVE), +VMSTATE_END_OF_LIST () + }, +}; + +static const VMStateDescription vmstate_spapr_xive = { + .name =TYPE_SPAPR_XIVE , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT32_EQUAL (nr_irqs, sPAPRXive,NULL ), +VMSTATE_STRUCT_VARRAY_POINTER_UINT32 (ivt, sPAPRXive, nr_irqs, + vmstate_spapr_xive_ive, XiveIVE), +VMSTATE_END_OF_LIST () + }, +}; + +static Property spapr_xive_properties[] = { +DEFINE_PROP_UINT32 ("nr-irqs" , sPAPRXive, nr_irqs,0 ), +DEFINE_PROP_END_OF_LIST (), +}; + +static void spapr_xive_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); +XiveFabricClass *xfc =XIVE_FABRIC_CLASS (klass); + + dc->realize = spapr_xive_realize; + dc->reset = spapr_xive_reset; + dc->props = spapr_xive_properties; + dc->desc ="sPAPR XIVE interrupt controller" ; + dc->vmsd = &vmstate_spapr_xive; + + xfc->get_ive = spapr_xive_get_ive; +} + +static const TypeInfo spapr_xive_info = { + .name =TYPE_SPAPR_XIVE , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_init = spapr_xive_init, + .instance_size =sizeof (sPAPRXive), + .class_init = spapr_xive_class_init, + .interfaces = (InterfaceInfo []) { + {TYPE_XIVE_FABRIC }, + { }, + }, +}; + +static void spapr_xive_register_types (void ) +{ +type_register_static (&spapr_xive_info); +} + +type_init (spapr_xive_register_types) + +bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi) +{ +XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); + +if (!ive) { +return false; + } + + ive->w |=IVE_VALID ; +return true; +} + +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn) +{ +XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); + +if (!ive) { +return false; + } + + ive->w &= ~IVE_VALID ; +return true; +}hw/intc/xive.c +7
-0@@ -20,6 +20,13 @@* XIVE Fabric */ +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn) +{ +XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xf); + +return xfc->get_ive (xf, lisn); +} +static void xive_fabric_route (XiveFabric *xf,int lisn) {include/hw/ppc/spapr_xive.h new file +31
-0@@ -0,0 +1,31 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_SPAPR_XIVE_H +#define PPC_SPAPR_XIVE_H + +#include "hw/sysbus.h" +#include "hw/ppc/xive.h" + +#define TYPE_SPAPR_XIVE "spapr-xive" +#define SPAPR_XIVE (obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE) + +typedef struct sPAPRXive { +SysBusDevice parent; + +/* Routing table */ +XiveIVE *ivt; +uint32_t nr_irqs; +}sPAPRXive ; + +bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi); +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn); +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon); + +#endif /* PPC_SPAPR_XIVE_H */ include/hw/ppc/xive.h +5
-0@@ -11,6 +11,7 @@#define PPC_XIVE_H #include "hw/sysbus.h" +#include "hw/ppc/xive_regs.h" typedef struct XiveFabric XiveFabric ;@@ -166,6 +167,10 @@ typedef struct XiveFabric {typedef struct XiveFabricClass {InterfaceClass parent;void (*notify)(XiveFabric *xf,uint32_t lisn); + +XiveIVE *(*get_ive)(XiveFabric *xf,uint32_t lisn); }XiveFabricClass ; +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn); +#endif /* PPC_XIVE_H */ include/hw/ppc/xive_regs.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2016-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef _PPC_XIVE_REGS_H +#define _PPC_XIVE_REGS_H + +/* IVE/EAS +* +* One per interrupt source. Targets that interrupt to a given EQ +* and provides the corresponding logical interrupt number (EQ data) +* +* We also map this structure to the escalation descriptor inside +* an EQ, though in that case the valid and masked bits are not used. +*/ +typedef struct XiveIVE { +/* Use a single 64-bit definition to make it easier to +* perform atomic updates +*/ +uint64_t w; +#define IVE_VALID PPC_BIT(0) +#define IVE_EQ_BLOCK PPC_BITMASK(4, 7)/* Destination EQ block# */ +#define IVE_EQ_INDEX PPC_BITMASK(8, 31)/* Destination EQ index */ +#define IVE_MASKED PPC_BIT(32)/* Masked */ +#define IVE_EQ_DATA PPC_BITMASK(33, 63)/* Data written to the EQ */ +}XiveIVE ; + +#endif /* _INTC_XIVE_INTERNAL_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 17 lines · David Gibson
Quoted 16 lines · Cédric Le Goater
Quoted 15 lines · David Gibson
Quoted 13 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
There is only one, the main IC.
Ok, that's what I thought originally. In that case some of the stuff in the patches really doesn't make sense to me.
well, there is one IC per chip on powernv, but we haven't reach that part yet.
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Quoted 8 lines
Quoted 5 lines
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a
set_eq()to push the EQ data.Hrm. Well, to add some more clarity, let's say the XiveRouter is the object which owns the IVT.
OK. that would be a model with some state and not an interface.
Quoted 1 line
It may or may not do other stuff as well.
Its only task would be to do the final event routing: get the IVE, get the EQ, push the EQ DATA in the OS event queue, notify the CPU.
Quoted 1 line
Now IIUC, on pnv the IVT lives in main system memory.
yes. It is allocated by skiboot in RAM and fed to the HW using some IC configuration registers. Then, each entry is configured with OPAL calls and the HW is updated using cache scrub registers.
Quoted 2 lines
Under PAPR is the IVT in guest memory, or is it outside (updated by hypercalls/rtas)?
Under sPAPR, the IVT is updated by the H_INT_SET_SOURCE_CONFIG hcall which configures the targeting of an IRQ. It's not in the guest memory.
Behind the hood, the IVT is still configured by OPAL under KVM and by QEMU when kernel_irqchip=off
Quoted 5 lines
Quoted 2 lines
The XiveRouter would also be a XiveFabric (or some other name) to let the internal sources of the interrupt controller forward events.
The further we go here, the less sure I am that XiveFabric even makes sense as a concept.
See previous email.
C.
Quoted 338 lines
Quoted 337 lines
Quoted 95 lines
Quoted 95 lines
Changes since v2 :
- introduced the XiveFabric interface
default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/spapr_xive.c | 159 ++++++++++++++++++++++++++++++++++++++ hw/intc/xive.c | 7 ++ include/hw/ppc/spapr_xive.h | 31 ++++++++ include/hw/ppc/xive.h | 5 ++ include/hw/ppc/xive_regs.h | 33 ++++++++ 7 files changed, 237 insertions(+) create mode 100644 hw/intc/spapr_xive.c create mode 100644 include/hw/ppc/spapr_xive.h create mode 100644 include/hw/ppc/xive_regs.hdefault-configs/ppc64-softmmu.mak +1
-0@@ -17,4 +17,5 @@ CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_XIVE=$(CONFIG_PSERIES) +CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES) CONFIG_MEM_HOTPLUG=yhw/intc/Makefile.objs +1
-0@@ -38,6 +38,7 @@ obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_XIVE) += xive.o +obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/spapr_xive.c new file +49
-0@@ -0,0 +1,159 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "target/ppc/cpu.h" +#include "sysemu/cpus.h" +#include "monitor/monitor.h" +#include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive_regs.h" + +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) +{ +int i; + +monitor_printf (mon,"IVE Table\n" ); +for (i =0 ; i < xive->nr_irqs; i++) { +XiveIVE *ive = &xive->ivt[i]; + +if (!(ive->w &IVE_VALID )) { +continue ; + } + +monitor_printf (mon," %4x %s %08x %08x\n" , i, + ive->w &IVE_MASKED ?"M" :" " , + (int )GETFIELD (IVE_EQ_INDEX , ive->w), + (int )GETFIELD (IVE_EQ_DATA , ive->w)); + } +} + +static void spapr_xive_reset (DeviceState *dev) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); +int i; + +/* Mask all valid IVEs in the IRQ number space. */ +for (i =0 ; i < xive->nr_irqs; i++) { +XiveIVE *ive = &xive->ivt[i]; +if (ive->w &IVE_VALID ) { + ive->w |=IVE_MASKED ; + } + }Quoted 8 lines
hw/intc/spapr_xive.c line 52
Quoted 3 lines
hw/intc/spapr_xive.c new file +3
-0+} + +static void spapr_xive_init (Object *obj)I'm trying to standardize on
init_instancemethods being called*_instance_init(). It helps to make it obvious that this is ineed aninstance_init()method, rather than one of the various other init calls that exist in various places.ok. this is good practice. I will fix.
Thanks,
C.
Quoted 226 lines
Quoted 225 lines
hw/intc/spapr_xive.c new file +107
-0+{ + +} + +static void spapr_xive_realize (DeviceState *dev,Error **errp) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); + +if (!xive->nr_irqs) { +error_setg (errp,"Number of interrupt needs to be greater 0" ); +return ; + } + +/* Allocate the Interrupt Virtualization Table */ + xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); +} + +static XiveIVE *spapr_xive_get_ive (XiveFabric *xf,uint32_t lisn) +{ +sPAPRXive *xive =SPAPR_XIVE (xf); + +return lisn < xive->nr_irqs ? &xive->ivt[lisn] :NULL ; +} + +static const VMStateDescription vmstate_spapr_xive_ive = { + .name =TYPE_SPAPR_XIVE "/ive" , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT64 (w, XiveIVE), +VMSTATE_END_OF_LIST () + }, +}; + +static const VMStateDescription vmstate_spapr_xive = { + .name =TYPE_SPAPR_XIVE , + .version_id =1 , + .minimum_version_id =1 , + .fields = (VMStateField []) { +VMSTATE_UINT32_EQUAL (nr_irqs, sPAPRXive,NULL ), +VMSTATE_STRUCT_VARRAY_POINTER_UINT32 (ivt, sPAPRXive, nr_irqs, + vmstate_spapr_xive_ive, XiveIVE), +VMSTATE_END_OF_LIST () + }, +}; + +static Property spapr_xive_properties[] = { +DEFINE_PROP_UINT32 ("nr-irqs" , sPAPRXive, nr_irqs,0 ), +DEFINE_PROP_END_OF_LIST (), +}; + +static void spapr_xive_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (klass); +XiveFabricClass *xfc =XIVE_FABRIC_CLASS (klass); + + dc->realize = spapr_xive_realize; + dc->reset = spapr_xive_reset; + dc->props = spapr_xive_properties; + dc->desc ="sPAPR XIVE interrupt controller" ; + dc->vmsd = &vmstate_spapr_xive; + + xfc->get_ive = spapr_xive_get_ive; +} + +static const TypeInfo spapr_xive_info = { + .name =TYPE_SPAPR_XIVE , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_init = spapr_xive_init, + .instance_size =sizeof (sPAPRXive), + .class_init = spapr_xive_class_init, + .interfaces = (InterfaceInfo []) { + {TYPE_XIVE_FABRIC }, + { }, + }, +}; + +static void spapr_xive_register_types (void ) +{ +type_register_static (&spapr_xive_info); +} + +type_init (spapr_xive_register_types) + +bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi) +{ +XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); + +if (!ive) { +return false; + } + + ive->w |=IVE_VALID ; +return true; +} + +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn) +{ +XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); + +if (!ive) { +return false; + } + + ive->w &= ~IVE_VALID ; +return true; +}hw/intc/xive.c +7
-0@@ -20,6 +20,13 @@* XIVE Fabric */ +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn) +{ +XiveFabricClass *xfc =XIVE_FABRIC_GET_CLASS (xf); + +return xfc->get_ive (xf, lisn); +} +static void xive_fabric_route (XiveFabric *xf,int lisn) {include/hw/ppc/spapr_xive.h new file +31
-0@@ -0,0 +1,31 @@ +/* +* QEMU PowerPC sPAPR XIVE interrupt controller model +* +* Copyright (c) 2017-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef PPC_SPAPR_XIVE_H +#define PPC_SPAPR_XIVE_H + +#include "hw/sysbus.h" +#include "hw/ppc/xive.h" + +#define TYPE_SPAPR_XIVE "spapr-xive" +#define SPAPR_XIVE (obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE) + +typedef struct sPAPRXive { +SysBusDevice parent; + +/* Routing table */ +XiveIVE *ivt; +uint32_t nr_irqs; +}sPAPRXive ; + +bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi); +bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn); +void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon); + +#endif /* PPC_SPAPR_XIVE_H */ include/hw/ppc/xive.h +5
-0@@ -11,6 +11,7 @@#define PPC_XIVE_H #include "hw/sysbus.h" +#include "hw/ppc/xive_regs.h" typedef struct XiveFabric XiveFabric ;@@ -166,6 +167,10 @@ typedef struct XiveFabric {typedef struct XiveFabricClass {InterfaceClass parent;void (*notify)(XiveFabric *xf,uint32_t lisn); + +XiveIVE *(*get_ive)(XiveFabric *xf,uint32_t lisn); }XiveFabricClass ; +XiveIVE *xive_fabric_get_ive (XiveFabric *xf,uint32_t lisn); +#endif /* PPC_XIVE_H */ include/hw/ppc/xive_regs.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* QEMU PowerPC XIVE interrupt controller model +* +* Copyright (c) 2016-2018, IBM Corporation. +* +* This code is licensed under the GPL version 2 or later. See the +* COPYING file in the top-level directory. +*/ + +#ifndef _PPC_XIVE_REGS_H +#define _PPC_XIVE_REGS_H + +/* IVE/EAS +* +* One per interrupt source. Targets that interrupt to a given EQ +* and provides the corresponding logical interrupt number (EQ data) +* +* We also map this structure to the escalation descriptor inside +* an EQ, though in that case the valid and masked bits are not used. +*/ +typedef struct XiveIVE { +/* Use a single 64-bit definition to make it easier to +* perform atomic updates +*/ +uint64_t w; +#define IVE_VALID PPC_BIT(0) +#define IVE_EQ_BLOCK PPC_BITMASK(4, 7)/* Destination EQ block# */ +#define IVE_EQ_INDEX PPC_BITMASK(8, 31)/* Destination EQ index */ +#define IVE_MASKED PPC_BIT(32)/* Masked */ +#define IVE_EQ_DATA PPC_BITMASK(33, 63)/* Data written to the EQ */ +}XiveIVE ; + +#endif /* _INTC_XIVE_INTERNAL_H */
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 21 lines · Cédric Le Goater
Quoted 20 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Quoted 17 lines · David Gibson
Quoted 5 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Quoted 8 lines
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
There is only one, the main IC.
Ok, that's what I thought originally. In that case some of the stuff in the patches really doesn't make sense to me.
well, there is one IC per chip on powernv, but we haven't reach that part yet.
Hmm. There's some things we can delay dealing with, but I don't think this is one of them. I think we need to understand how multichip is going to work in order to come up with a sane architecture. Otherwise I fear we'll end up with something that we either need to horribly bastardize for multichip, or have to rework things dramatically leading to migration nightmares.
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a
set_eq()to push the EQ data.
Quoted 4 lines
Quoted 2 lines
Hrm. Well, to add some more clarity, let's say the XiveRouter is the object which owns the IVT.
OK. that would be a model with some state and not an interface.
Yes. For papr variant it would have the whole IVT contents as its state. For the powernv, just the registers telling it where to find the IVT in RAM.
Quoted 4 lines
Quoted 1 line
It may or may not do other stuff as well.
Its only task would be to do the final event routing: get the IVE, get the EQ, push the EQ DATA in the OS event queue, notify the CPU.
That seems like a lot of steps. Up to push the EQ DATA, certainly. And I guess it'll have to ping an NVT somehow, but I'm not sure it should know about CPUs as such.
I'm not sure at this stage what should own the EQD table. In the multichip case is there one EQD table for every IVT? I'm guessing not - I figure the EQD table must be effectively global so that any chip's router can send events to any EQ in the whole system.
Quoted 5 lines
Quoted 1 line
Now IIUC, on pnv the IVT lives in main system memory.
yes. It is allocated by skiboot in RAM and fed to the HW using some IC configuration registers. Then, each entry is configured with OPAL calls and the HW is updated using cache scrub registers.
Right. At least for the first pass we should be able to treat the cache scrub registers as no-ops and just not cache anything in the qemu implementation.
Quoted 6 lines
Quoted 2 lines
Under PAPR is the IVT in guest memory, or is it outside (updated by hypercalls/rtas)?
Under sPAPR, the IVT is updated by the
H_INT_SET_SOURCE_CONFIGhcall which configures the targeting of an IRQ. It's not in the guest memory.
Right.
Quoted 2 lines
Behind the hood, the IVT is still configured by OPAL under KVM and by QEMU when kernel_irqchip=off
Sure. Even with kernel_irqchip=on there's still logically a guest IVT (or "IVT view" I guess), even if it's actual entries are stored distributed across various places in the host's IVTs.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
The XiveRouter would also be a XiveFabric (or some other name) to let the internal sources of the interrupt controller forward events.
The further we go here, the less sure I am that XiveFabric even makes sense as a concept.
See previous email.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 30 lines · David Gibson
Quoted 21 lines · Cédric Le Goater
Quoted 20 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Quoted 17 lines · David Gibson
Quoted 5 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Quoted 8 lines
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
There is only one, the main IC.
Ok, that's what I thought originally. In that case some of the stuff in the patches really doesn't make sense to me.
well, there is one IC per chip on powernv, but we haven't reach that part yet.
Quoted 6 lines
Hmm. There's some things we can delay dealing with, but I don't think this is one of them. I think we need to understand how multichip is going to work in order to come up with a sane architecture. Otherwise I fear we'll end up with something that we either need to horribly bastardize for multichip, or have to rework things dramatically leading to migration nightmares.
So, it is all controlled by MMIO, so we should be fine on that part. As for the internal tables, they are all configured by firmware, using a chip identifier (block). I need to check how the remote XIVE are accessed. I think this is by MMIO.
I haven't looked at multichip XIVE support but I am not too worried as the framework is already in place for the machine.
Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a
set_eq()to push the EQ data.Quoted 4 lines
Quoted 2 lines
Hrm. Well, to add some more clarity, let's say the XiveRouter is the object which owns the IVT.
OK. that would be a model with some state and not an interface.
Yes. For papr variant it would have the whole IVT contents as its state. For the powernv, just the registers telling it where to find the IVT in RAM.
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
It may or may not do other stuff as well.
Its only task would be to do the final event routing: get the IVE, get the EQ, push the EQ DATA in the OS event queue, notify the CPU.
That seems like a lot of steps. Up to push the EQ DATA, certainly. And I guess it'll have to ping an NVT somehow, but I'm not sure it should know about CPUs as such.
For PowerNV, the concept could be generalized, yes. An NVT can contain the interrupt state of a logical server but the common case is baremetal without guests for QEMU and so we have a NVT per cpu.
PowerNV will have some limitation but we can make it better than today for sure. It boots.
We can improve some of the NVT notification process, the way NVT are matched eventually. may be support remote engines if the NVT is not local. I have not looked at the details.
Quoted 1 line
I'm not sure at this stage what should own the EQD table.
The EQDT is in RAM.
Quoted 1 line
In the multichip case is there one EQD table for every IVT?
There is one EQDT per chip, same for the IVT. They are in RAM, identified with a block ID.
Quoted 5 lines
I'm guessing
not - I figure the EQD table must be effectively global so that any chip's router can send events to any EQ in the whole system.Quoted 2 lines
Quoted 1 line
Quoted 1 line
Now IIUC, on pnv the IVT lives in main system memory.
Quoted 7 lines
Quoted 3 lines
yes. It is allocated by skiboot in RAM and fed to the HW using some IC configuration registers. Then, each entry is configured with OPAL calls and the HW is updated using cache scrub registers.
Right. At least for the first pass we should be able to treat the cache scrub registers as no-ops and just not cache anything in the qemu implementation.
The model currently supports the cache scrub registers, we need it to update some values. It's not too complex.
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
Under PAPR is the IVT in guest memory, or is it outside (updated by hypercalls/rtas)?
Under sPAPR, the IVT is updated by the
H_INT_SET_SOURCE_CONFIGhcall which configures the targeting of an IRQ. It's not in the guest memory.
Quoted 8 lines
Right.
Quoted 2 lines
Behind the hood, the IVT is still configured by OPAL under KVM and by QEMU when kernel_irqchip=off
Sure. Even with kernel_irqchip=on there's still logically a guest IVT (or "IVT view" I guess), even if it's actual entries are stored distributed across various places in the host's IVTs.
yes. The XIVE KVM device caches the info. This is used to dump the state without doing OPAL calls.
C.
Quoted 8 lines
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
The XiveRouter would also be a XiveFabric (or some other name) to let the internal sources of the interrupt controller forward events.
The further we go here, the less sure I am that XiveFabric even makes sense as a concept.
See previous email.
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 38 lines · Cédric Le Goater
Quoted 30 lines · David Gibson
Quoted 21 lines · Cédric Le Goater
Quoted 20 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Quoted 17 lines · David Gibson
Quoted 5 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Quoted 8 lines
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
There is only one, the main IC.
Ok, that's what I thought originally. In that case some of the stuff in the patches really doesn't make sense to me.
well, there is one IC per chip on powernv, but we haven't reach that part yet.
Quoted 6 lines
Hmm. There's some things we can delay dealing with, but I don't think this is one of them. I think we need to understand how multichip is going to work in order to come up with a sane architecture. Otherwise I fear we'll end up with something that we either need to horribly bastardize for multichip, or have to rework things dramatically leading to migration nightmares.
Quoted 4 lines
So, it is all controlled by MMIO, so we should be fine on that part. As for the internal tables, they are all configured by firmware, using a chip identifier (block). I need to check how the remote XIVE are accessed. I think this is by MMIO.
Right, but for powernv we execute OPAL inside the VM, rather than emulating its effects. So we still need to model the actual hardware interfaces. OPAL hides the details from the kernel, but not from us on the other side.
Quoted 27 lines
I haven't looked at multichip XIVE support but I am not too worried as the framework is already in place for the machine.
Quoted 24 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a
set_eq()to push the EQ data.Quoted 4 lines
Quoted 2 lines
Hrm. Well, to add some more clarity, let's say the XiveRouter is the object which owns the IVT.
OK. that would be a model with some state and not an interface.
Yes. For papr variant it would have the whole IVT contents as its state. For the powernv, just the registers telling it where to find the IVT in RAM.
Quoted 4 lines
Quoted 1 line
It may or may not do other stuff as well.
Its only task would be to do the final event routing: get the IVE, get the EQ, push the EQ DATA in the OS event queue, notify the CPU.
Quoted 8 lines
Quoted 3 lines
That seems like a lot of steps. Up to push the EQ DATA, certainly. And I guess it'll have to ping an NVT somehow, but I'm not sure it should know about CPUs as such.
For PowerNV, the concept could be generalized, yes. An NVT can contain the interrupt state of a logical server but the common case is baremetal without guests for QEMU and so we have a NVT per cpu.
Hmm. We eventually want to support a kernel running guests under qemu/powernv though, right? So even if we don't allow it right now, we don't want allowing that to require major surgery to our architecture.
Quoted 10 lines
PowerNV will have some limitation but we can make it better than today for sure. It boots.
We can improve some of the NVT notification process, the way NVT are matched eventually. may be support remote engines if the NVT is not local. I have not looked at the details.
Quoted 1 line
I'm not sure at this stage what should own the EQD table.
The EQDT is in RAM.
Not for spapr, it's not. And even when it is in RAM, something needs to own the register that gives its base address.
Quoted 14 lines
Quoted 1 line
In the multichip case is there one EQD table for every IVT?
There is one EQDT per chip, same for the IVT. They are in RAM, identified with a block ID.
Quoted 9 lines
I'm guessing
not - I figure the EQD table must be effectively global so that any chip's router can send events to any EQ in the whole system.Quoted 5 lines
Quoted 1 line
Quoted 1 line
Now IIUC, on pnv the IVT lives in main system memory.
yes. It is allocated by skiboot in RAM and fed to the HW using some IC configuration registers. Then, each entry is configured with OPAL calls and the HW is updated using cache scrub registers.
Quoted 6 lines
Quoted 3 lines
Right. At least for the first pass we should be able to treat the cache scrub registers as no-ops and just not cache anything in the qemu implementation.
The model currently supports the cache scrub registers, we need it to update some values. It's not too complex.
Ok.
Quoted 31 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
Under PAPR is the IVT in guest memory, or is it outside (updated by hypercalls/rtas)?
Under sPAPR, the IVT is updated by the
H_INT_SET_SOURCE_CONFIGhcall which configures the targeting of an IRQ. It's not in the guest memory.Quoted 8 lines
Right.
Quoted 2 lines
Behind the hood, the IVT is still configured by OPAL under KVM and by QEMU when kernel_irqchip=off
Sure. Even with kernel_irqchip=on there's still logically a guest IVT (or "IVT view" I guess), even if it's actual entries are stored distributed across various places in the host's IVTs.
yes. The XIVE KVM device caches the info. This is used to dump the state without doing OPAL calls.
C.
Quoted 8 lines
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
The XiveRouter would also be a XiveFabric (or some other name) to let the internal sources of the interrupt controller forward events.
The further we go here, the less sure I am that XiveFabric even makes sense as a concept.
See previous email.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 44 lines · David Gibson
Quoted 38 lines · Cédric Le Goater
Quoted 30 lines · David Gibson
Quoted 21 lines · Cédric Le Goater
Quoted 20 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Quoted 17 lines · David Gibson
Quoted 5 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Quoted 8 lines
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
There is only one, the main IC.
Ok, that's what I thought originally. In that case some of the stuff in the patches really doesn't make sense to me.
well, there is one IC per chip on powernv, but we haven't reach that part yet.
Quoted 6 lines
Hmm. There's some things we can delay dealing with, but I don't think this is one of them. I think we need to understand how multichip is going to work in order to come up with a sane architecture. Otherwise I fear we'll end up with something that we either need to horribly bastardize for multichip, or have to rework things dramatically leading to migration nightmares.
Quoted 4 lines
So, it is all controlled by MMIO, so we should be fine on that part. As for the internal tables, they are all configured by firmware, using a chip identifier (block). I need to check how the remote XIVE are accessed. I think this is by MMIO.
Quoted 4 lines
Right, but for powernv we execute OPAL inside the VM, rather than emulating its effects. So we still need to model the actual hardware interfaces. OPAL hides the details from the kernel, but not from us on the other side.
Yes. This is the case in the current model. I took a look today and I have a few fixes for the MMIO layout for P9 chips which I will send.
As for XIVE, the model needs to be a little more complex to support VSD_MODE_FORWARD tables which describe how to forward a notification to another XIVE IC on another chip. They contain an address on which to load, This is another hop in the notification chain.
Quoted 31 lines
Quoted 31 lines
I haven't looked at multichip XIVE support but I am not too worried as the framework is already in place for the machine.
Quoted 27 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a
set_eq()to push the EQ data.Quoted 4 lines
Quoted 2 lines
Hrm. Well, to add some more clarity, let's say the XiveRouter is the object which owns the IVT.
OK. that would be a model with some state and not an interface.
Yes. For papr variant it would have the whole IVT contents as its state. For the powernv, just the registers telling it where to find the IVT in RAM.
Quoted 4 lines
Quoted 1 line
It may or may not do other stuff as well.
Its only task would be to do the final event routing: get the IVE, get the EQ, push the EQ DATA in the OS event queue, notify the CPU.
That seems like a lot of steps. Up to push the EQ DATA, certainly. And I guess it'll have to ping an NVT somehow, but I'm not sure it should know about CPUs as such.
Quoted 7 lines
Quoted 4 lines
For PowerNV, the concept could be generalized, yes. An NVT can contain the interrupt state of a logical server but the common case is baremetal without guests for QEMU and so we have a NVT per cpu.
Hmm. We eventually want to support a kernel running guests under qemu/powernv though, right?
arg. an emulated hypervisor ! OK let's say this is a long term goal :)
Quoted 3 lines
So even if we don't allow it right now,
we don't want allowing that to require major surgery to our architecture.
That I agree on.
Quoted 7 lines
Quoted 7 lines
PowerNV will have some limitation but we can make it better than today for sure. It boots.
We can improve some of the NVT notification process, the way NVT are matched eventually. may be support remote engines if the NVT is not local. I have not looked at the details.
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
I'm not sure at this stage what should own the EQD table.
The EQDT is in RAM.
Not for spapr, it's not.
yeah ok. It's in QEMU/KVM.
Quoted 2 lines
And even when it is in RAM, something needs
to own the register that gives its base address.
It's more complex than registers on powernv. There is a procedure to define the XIVE tables using XIVE table descriptors which contain their characteristics, size, indirect vs. indirect, local vs remote. OPAL/skiboot defines all these to configure the HW, and the model necessarily needs to support the same interface. This is the case for a single chip.
C.
Quoted 55 lines
Quoted 14 lines
Quoted 1 line
In the multichip case is there one EQD table for every IVT?
There is one EQDT per chip, same for the IVT. They are in RAM, identified with a block ID.
Quoted 9 lines
I'm guessing
not - I figure the EQD table must be effectively global so that any chip's router can send events to any EQ in the whole system.Quoted 5 lines
Quoted 1 line
Quoted 1 line
Now IIUC, on pnv the IVT lives in main system memory.
yes. It is allocated by skiboot in RAM and fed to the HW using some IC configuration registers. Then, each entry is configured with OPAL calls and the HW is updated using cache scrub registers.
Quoted 6 lines
Quoted 3 lines
Right. At least for the first pass we should be able to treat the cache scrub registers as no-ops and just not cache anything in the qemu implementation.
The model currently supports the cache scrub registers, we need it to update some values. It's not too complex.
Ok.
Quoted 31 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
Under PAPR is the IVT in guest memory, or is it outside (updated by hypercalls/rtas)?
Under sPAPR, the IVT is updated by the
H_INT_SET_SOURCE_CONFIGhcall which configures the targeting of an IRQ. It's not in the guest memory.Quoted 8 lines
Right.
Quoted 2 lines
Behind the hood, the IVT is still configured by OPAL under KVM and by QEMU when kernel_irqchip=off
Sure. Even with kernel_irqchip=on there's still logically a guest IVT (or "IVT view" I guess), even if it's actual entries are stored distributed across various places in the host's IVTs.
yes. The XIVE KVM device caches the info. This is used to dump the state without doing OPAL calls.
C.
Quoted 8 lines
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
The XiveRouter would also be a XiveFabric (or some other name) to let the internal sources of the interrupt controller forward events.
The further we go here, the less sure I am that XiveFabric even makes sense as a concept.
See previous email.
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 50 lines · Cédric Le Goater
Quoted 44 lines · David Gibson
Quoted 38 lines · Cédric Le Goater
Quoted 30 lines · David Gibson
Quoted 21 lines · Cédric Le Goater
Quoted 20 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Quoted 17 lines · David Gibson
Quoted 5 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Quoted 8 lines
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
There is only one, the main IC.
Ok, that's what I thought originally. In that case some of the stuff in the patches really doesn't make sense to me.
well, there is one IC per chip on powernv, but we haven't reach that part yet.
Quoted 6 lines
Hmm. There's some things we can delay dealing with, but I don't think this is one of them. I think we need to understand how multichip is going to work in order to come up with a sane architecture. Otherwise I fear we'll end up with something that we either need to horribly bastardize for multichip, or have to rework things dramatically leading to migration nightmares.
Quoted 4 lines
So, it is all controlled by MMIO, so we should be fine on that part. As for the internal tables, they are all configured by firmware, using a chip identifier (block). I need to check how the remote XIVE are accessed. I think this is by MMIO.
Quoted 4 lines
Right, but for powernv we execute OPAL inside the VM, rather than emulating its effects. So we still need to model the actual hardware interfaces. OPAL hides the details from the kernel, but not from us on the other side.
Quoted 7 lines
Yes. This is the case in the current model. I took a look today and I have a few fixes for the MMIO layout for P9 chips which I will send.
As for XIVE, the model needs to be a little more complex to support
VSD_MODE_FORWARDtables which describe how to forward a notification to another XIVE IC on another chip. They contain an address on which to load, This is another hop in the notification chain.
Ah, ok. So is that mode and address configured in the (bare metal) IVT as well? Or is that a different piece of configuration?
Quoted 65 lines
Quoted 31 lines
Quoted 31 lines
I haven't looked at multichip XIVE support but I am not too worried as the framework is already in place for the machine.
Quoted 27 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a
set_eq()to push the EQ data.Quoted 4 lines
Quoted 2 lines
Hrm. Well, to add some more clarity, let's say the XiveRouter is the object which owns the IVT.
OK. that would be a model with some state and not an interface.
Yes. For papr variant it would have the whole IVT contents as its state. For the powernv, just the registers telling it where to find the IVT in RAM.
Quoted 4 lines
Quoted 1 line
It may or may not do other stuff as well.
Its only task would be to do the final event routing: get the IVE, get the EQ, push the EQ DATA in the OS event queue, notify the CPU.
That seems like a lot of steps. Up to push the EQ DATA, certainly. And I guess it'll have to ping an NVT somehow, but I'm not sure it should know about CPUs as such.
Quoted 7 lines
Quoted 4 lines
For PowerNV, the concept could be generalized, yes. An NVT can contain the interrupt state of a logical server but the common case is baremetal without guests for QEMU and so we have a NVT per cpu.
Hmm. We eventually want to support a kernel running guests under qemu/powernv though, right?
arg. an emulated hypervisor ! OK let's say this is a long term goal :)
Quoted 3 lines
So even if we don't allow it right now,
we don't want allowing that to require major surgery to our architecture.That I agree on.
Quoted 7 lines
Quoted 7 lines
PowerNV will have some limitation but we can make it better than today for sure. It boots.
We can improve some of the NVT notification process, the way NVT are matched eventually. may be support remote engines if the NVT is not local. I have not looked at the details.
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
I'm not sure at this stage what should own the EQD table.
The EQDT is in RAM.
Not for spapr, it's not.
yeah ok. It's in QEMU/KVM.
Quoted 2 lines
And even when it is in RAM, something needs
to own the register that gives its base address.
Quoted 6 lines
It's more complex than registers on powernv. There is a procedure to define the XIVE tables using XIVE table descriptors which contain their characteristics, size, indirect vs. indirect, local vs remote. OPAL/skiboot defines all these to configure the HW, and the model necessarily needs to support the same interface. This is the case for a single chip.
Ah, ok. So there's some sort of IVTD. Also in RAM? Eventually there must be a register giving the base address of the IVTD, yes?
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 04/35] spapr/xive: introduce a XIVE interrupt controller for sPAPR
Quoted 54 lines · David Gibson
Quoted 53 lines · Cédric Le Goater
Quoted 44 lines · David Gibson
Quoted 38 lines · Cédric Le Goater
Quoted 30 lines · David Gibson
Quoted 21 lines · Cédric Le Goater
Quoted 20 lines · David Gibson
Quoted 19 lines · Cédric Le Goater
Quoted 17 lines · David Gibson
Quoted 5 lines · Cédric Le Goater
sPAPRXive is a model for the XIVE interrupt controller device of the sPAPR machine. It holds the routing XIVE table, the Interrupt Virtualization Entry (IVE) table which associates interrupt source numbers with targets.
Quoted 8 lines
Also extend the XiveFabric with an accessor to the IVT. This will be needed by the routing algorithm.
Signed-off-by Cédric Le Goater <[email protected]>---
May be should introduce a XiveRouter model to hold the IVT. To be discussed.
Yeah, maybe. Am I correct in thinking that on pnv there could be more than one XiveRouter?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
There is only one, the main IC.
Ok, that's what I thought originally. In that case some of the stuff in the patches really doesn't make sense to me.
well, there is one IC per chip on powernv, but we haven't reach that part yet.
Quoted 6 lines
Hmm. There's some things we can delay dealing with, but I don't think this is one of them. I think we need to understand how multichip is going to work in order to come up with a sane architecture. Otherwise I fear we'll end up with something that we either need to horribly bastardize for multichip, or have to rework things dramatically leading to migration nightmares.
Quoted 4 lines
So, it is all controlled by MMIO, so we should be fine on that part. As for the internal tables, they are all configured by firmware, using a chip identifier (block). I need to check how the remote XIVE are accessed. I think this is by MMIO.
Quoted 4 lines
Right, but for powernv we execute OPAL inside the VM, rather than emulating its effects. So we still need to model the actual hardware interfaces. OPAL hides the details from the kernel, but not from us on the other side.
Yes. This is the case in the current model. I took a look today and I have a few fixes for the MMIO layout for P9 chips which I will send.
Quoted 7 lines
Quoted 4 lines
As for XIVE, the model needs to be a little more complex to support
VSD_MODE_FORWARDtables which describe how to forward a notification to another XIVE IC on another chip. They contain an address on which to load, This is another hop in the notification chain.Ah, ok. So is that mode and address configured in the (bare metal) IVT as well? Or is that a different piece of configuration?
The mode of a virtual structure table is configured by firmware. There are 4 main table types: IVT, SBE, EQD, VPD (and an extra one for IRQ) for the 16 possible blocks of a machine (I am simplifying a bit there).
Local tables to a block/chip, today, are set to EXCLUSIVE and all remotes tables set to FORWARD.
The address of a table is configured by FW also. In case of a FORWARD table, it is set to the remote IC BAR + one page. This page has two 2K windows : one for for HW interrupt triggers and another one for to forward interrupts and for operation synchronization.
Quoted 65 lines
Quoted 65 lines
Quoted 31 lines
Quoted 31 lines
I haven't looked at multichip XIVE support but I am not too worried as the framework is already in place for the machine.
Quoted 27 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 3 lines
If we did have a XiveRouter, I'm not sure we'd need the XiveFabric interface, possibly its methods could just be class methods of XiveRouter.
Yes. We could introduce a XiveRouter to share the ivt table between the sPAPRXive and the PnvXIVE models, the interrupt controllers of the machines. Methods would provide way to get the ivt/eq/nvt objects required for routing. I need to add a
set_eq()to push the EQ data.Quoted 4 lines
Quoted 2 lines
Hrm. Well, to add some more clarity, let's say the XiveRouter is the object which owns the IVT.
OK. that would be a model with some state and not an interface.
Yes. For papr variant it would have the whole IVT contents as its state. For the powernv, just the registers telling it where to find the IVT in RAM.
Quoted 4 lines
Quoted 1 line
It may or may not do other stuff as well.
Its only task would be to do the final event routing: get the IVE, get the EQ, push the EQ DATA in the OS event queue, notify the CPU.
That seems like a lot of steps. Up to push the EQ DATA, certainly. And I guess it'll have to ping an NVT somehow, but I'm not sure it should know about CPUs as such.
Quoted 7 lines
Quoted 4 lines
For PowerNV, the concept could be generalized, yes. An NVT can contain the interrupt state of a logical server but the common case is baremetal without guests for QEMU and so we have a NVT per cpu.
Hmm. We eventually want to support a kernel running guests under qemu/powernv though, right?
arg. an emulated hypervisor ! OK let's say this is a long term goal :)
Quoted 3 lines
So even if we don't allow it right now,
we don't want allowing that to require major surgery to our architecture.That I agree on.
Quoted 7 lines
Quoted 7 lines
PowerNV will have some limitation but we can make it better than today for sure. It boots.
We can improve some of the NVT notification process, the way NVT are matched eventually. may be support remote engines if the NVT is not local. I have not looked at the details.
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
I'm not sure at this stage what should own the EQD table.
The EQDT is in RAM.
Not for spapr, it's not.
yeah ok. It's in QEMU/KVM.
Quoted 2 lines
And even when it is in RAM, something needs
to own the register that gives its base address.
Quoted 8 lines
Quoted 6 lines
It's more complex than registers on powernv. There is a procedure to define the XIVE tables using XIVE table descriptors which contain their characteristics, size, indirect vs. indirect, local vs remote. OPAL/skiboot defines all these to configure the HW, and the model necessarily needs to support the same interface. This is the case for a single chip.
Ah, ok. So there's some sort of IVTD.
These are called Virtual Structure table Descriptors (VSDs). Each XIVE chip has an array of these.
Quoted 1 line
Also in RAM?
Yes. But the vsd are just temporary structures to configure HW. What is important is the information it is holding : IVT, EQDT, VPDT, etc.
Quoted 2 lines
Eventually there
must be a register giving the base address of the IVTD, yes?
There are two registers to configure the table. One to set the table type and block, and one to set its VSD.
C.
PATCH v3 5/35 spapr/xive: add a single source block to the sPAPR XIVE model
In reply to Cédric Le GoaterBare-metal systems (PowerNV) have multiples interrupt sources. The XIVE interrupt controller has an internal source for IPIs and generic IPIs, the PSIHB has one and also the PHBs. But, for simplicity on the sPAPR machine, we use a unique XiveSource object for all IPIs and virtual device interrupts of the VM.
The ESB MMIO region used to control the sources is mapped at the address of chip 0 of a real system and only the provisioned IRQ numbers are covered.
--- hw/intc/spapr_xive.c | 34 ++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr_xive.h | 3 +++ include/hw/ppc/xive.h | 6 ++++++ 3 files changed, 43 insertions(+)
hw/intc/spapr_xive.c +34 -0
@@ -14,12 +14,15 @@#include "sysemu/cpus.h" #include "monitor/monitor.h" #include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive.h" #include "hw/ppc/xive_regs.h" void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) {int i; +xive_source_pic_print_info (&xive->source, mon); +monitor_printf (mon,"IVE Table\n" );for (i =0 ; i < xive->nr_irqs; i++) {XiveIVE *ive = &xive->ivt[i];
@@ -40,6 +43,9 @@ static void spapr_xive_reset(DeviceState *dev)sPAPRXive *xive =SPAPR_XIVE (dev);int i; +/* Xive Source reset is done through SysBus, it should put all +* IRQs to OFF (!P|Q) */ +/* Mask all valid IVEs in the IRQ number space. */ for (i =0 ; i < xive->nr_irqs; i++) {XiveIVE *ive = &xive->ivt[i];
@@ -51,18 +57,42 @@ static void spapr_xive_reset(DeviceState *dev)static void spapr_xive_init (Object *obj) { +sPAPRXive *xive =SPAPR_XIVE (obj); +object_initialize (&xive->source,sizeof (xive->source),TYPE_XIVE_SOURCE ); +object_property_add_child (obj,"source" ,OBJECT (&xive->source),NULL ); }static void spapr_xive_realize (DeviceState *dev,Error **errp) {sPAPRXive *xive =SPAPR_XIVE (dev); +XiveSource *xsrc = &xive->source; +Error *local_err =NULL ;if (!xive->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater 0" );return ; } +/* The XIVE interrupt controller has an internal source for IPIs +* and generic IPIs, the PSIHB has one and also the PHBs. For +* simplicity, we use a unique XIVE source object for *all* +* interrupts on sPAPR. The ESBs pages are mapped at the address +* of chip 0 of a real system. +*/ +object_property_set_int (OBJECT (xsrc),XIVE_VC_BASE ,"bar" , + &error_fatal); +object_property_set_int (OBJECT (xsrc), xive->nr_irqs,"nr-irqs" , + &error_fatal); +object_property_add_const_link (OBJECT (xsrc),"xive" ,OBJECT (xive), + &error_fatal); +object_property_set_bool (OBJECT (xsrc), true,"realized" , &local_err); +if (local_err) { +error_propagate (errp, local_err); +return ; + } +qdev_set_parent_bus (DEVICE (xsrc),sysbus_get_default ()); +/* Allocate the Interrupt Virtualization Table */ xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); }
@@ -137,23 +167,27 @@ type_init(spapr_xive_register_types)bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi) {XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); +XiveSource *xsrc = &xive->source;if (!ive) {return false; } ive->w |=IVE_VALID ; +xive_source_irq_set (xsrc, lisn - xsrc->offset, lsi);return true; }bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn) {XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); +XiveSource *xsrc = &xive->source;if (!ive) {return false; } ive->w &= ~IVE_VALID ; +xive_source_irq_set (xsrc, lisn - xsrc->offset, false);return true; }
include/hw/ppc/spapr_xive.h +3 -0
@@ -19,6 +19,9 @@ typedef struct sPAPRXive { SysBusDevice parent; + /* Internal interrupt source for IPIs and virtual devices */ + XiveSource source; + /* Routing table */ XiveIVE *ivt; uint32_t nr_irqs;
include/hw/ppc/xive.h +6 -0
@@ -16,6 +16,12 @@typedef struct XiveFabric XiveFabric ;/* +* XIVE MMIO regions +*/ + +#define XIVE_VC_BASE 0x0006010000000000ull + +/* * XIVE Interrupt Source */
Signature · 1 line
2.13.6
Re: [Qemu-devel] [PATCH v3 05/35] spapr/xive: add a single source block to the sPAPR XIVE model
Quoted 9 lines · Cédric Le Goater
Bare-metal systems (PowerNV) have multiples interrupt sources. The XIVE interrupt controller has an internal source for IPIs and generic IPIs, the PSIHB has one and also the PHBs. But, for simplicity on the sPAPR machine, we use a unique XiveSource object for all IPIs and virtual device interrupts of the VM.
The ESB MMIO region used to control the sources is mapped at the address of chip 0 of a real system and only the provisioned IRQ numbers are covered.
Is that MMIO address PAPR specified, or arbitrary?
Quoted 139 lines
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/spapr_xive.c | 34 ++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr_xive.h | 3 +++ include/hw/ppc/xive.h | 6 ++++++ 3 files changed, 43 insertions(+)hw/intc/spapr_xive.c +34
-0@@ -14,12 +14,15 @@#include "sysemu/cpus.h" #include "monitor/monitor.h" #include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive.h" #include "hw/ppc/xive_regs.h" void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) {int i; +xive_source_pic_print_info (&xive->source, mon); +monitor_printf (mon,"IVE Table\n" );for (i =0 ; i < xive->nr_irqs; i++) {XiveIVE *ive = &xive->ivt[i];@@ -40,6 +43,9 @@ static void spapr_xive_reset(DeviceState *dev)sPAPRXive *xive =SPAPR_XIVE (dev);int i; +/* Xive Source reset is done through SysBus, it should put all +* IRQs to OFF (!P|Q) */ +/* Mask all valid IVEs in the IRQ number space. */ for (i =0 ; i < xive->nr_irqs; i++) {XiveIVE *ive = &xive->ivt[i];@@ -51,18 +57,42 @@ static void spapr_xive_reset(DeviceState *dev)static void spapr_xive_init (Object *obj) { +sPAPRXive *xive =SPAPR_XIVE (obj); +object_initialize (&xive->source,sizeof (xive->source),TYPE_XIVE_SOURCE ); +object_property_add_child (obj,"source" ,OBJECT (&xive->source),NULL ); }static void spapr_xive_realize (DeviceState *dev,Error **errp) {sPAPRXive *xive =SPAPR_XIVE (dev); +XiveSource *xsrc = &xive->source; +Error *local_err =NULL ;if (!xive->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater 0" );return ; } +/* The XIVE interrupt controller has an internal source for IPIs +* and generic IPIs, the PSIHB has one and also the PHBs. For +* simplicity, we use a unique XIVE source object for *all* +* interrupts on sPAPR. The ESBs pages are mapped at the address +* of chip 0 of a real system. +*/ +object_property_set_int (OBJECT (xsrc),XIVE_VC_BASE ,"bar" , + &error_fatal); +object_property_set_int (OBJECT (xsrc), xive->nr_irqs,"nr-irqs" , + &error_fatal); +object_property_add_const_link (OBJECT (xsrc),"xive" ,OBJECT (xive), + &error_fatal); +object_property_set_bool (OBJECT (xsrc), true,"realized" , &local_err); +if (local_err) { +error_propagate (errp, local_err); +return ; + } +qdev_set_parent_bus (DEVICE (xsrc),sysbus_get_default ()); +/* Allocate the Interrupt Virtualization Table */ xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); }@@ -137,23 +167,27 @@ type_init(spapr_xive_register_types)bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi) {XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); +XiveSource *xsrc = &xive->source;if (!ive) {return false; } ive->w |=IVE_VALID ; +xive_source_irq_set (xsrc, lisn - xsrc->offset, lsi);return true; }bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn) {XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); +XiveSource *xsrc = &xive->source;if (!ive) {return false; } ive->w &= ~IVE_VALID ; +xive_source_irq_set (xsrc, lisn - xsrc->offset, false);return true; }include/hw/ppc/spapr_xive.h +3
-0@@ -19,6 +19,9 @@ typedef struct sPAPRXive { SysBusDevice parent; + /* Internal interrupt source for IPIs and virtual devices */ + XiveSource source; + /* Routing table */ XiveIVE *ivt; uint32_t nr_irqs;include/hw/ppc/xive.h +6
-0@@ -16,6 +16,12 @@typedef struct XiveFabric XiveFabric ;/* +* XIVE MMIO regions +*/ + +#define XIVE_VC_BASE 0x0006010000000000ull + +/* * XIVE Interrupt Source */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 05/35] spapr/xive: add a single source block to the sPAPR XIVE model
Quoted 7 lines · David Gibson
Quoted 6 lines · Cédric Le Goater
Bare-metal systems (PowerNV) have multiples interrupt sources. The XIVE interrupt controller has an internal source for IPIs and generic IPIs, the PSIHB has one and also the PHBs. But, for simplicity on the sPAPR machine, we use a unique XiveSource object for all IPIs and virtual device interrupts of the VM.
Quoted 5 lines
Quoted 3 lines
The ESB MMIO region used to control the sources is mapped at the address of chip 0 of a real system and only the provisioned IRQ numbers are covered.
Is that MMIO address PAPR specified, or arbitrary?
There are no specified value for the ESB address. It's queried by the guest using the H_INT_GET_SOURCE_INFO hcall. For KVM, I have introduced a ioctl to configure the KVM device.
Same for the TIMA, but in this case, the address is exposed to the guest in the device tree.
Quoted 141 lines
Quoted 140 lines
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/spapr_xive.c | 34 ++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr_xive.h | 3 +++ include/hw/ppc/xive.h | 6 ++++++ 3 files changed, 43 insertions(+)hw/intc/spapr_xive.c +34
-0@@ -14,12 +14,15 @@#include "sysemu/cpus.h" #include "monitor/monitor.h" #include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive.h" #include "hw/ppc/xive_regs.h" void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) {int i; +xive_source_pic_print_info (&xive->source, mon); +monitor_printf (mon,"IVE Table\n" );for (i =0 ; i < xive->nr_irqs; i++) {XiveIVE *ive = &xive->ivt[i];@@ -40,6 +43,9 @@ static void spapr_xive_reset(DeviceState *dev)sPAPRXive *xive =SPAPR_XIVE (dev);int i; +/* Xive Source reset is done through SysBus, it should put all +* IRQs to OFF (!P|Q) */ +/* Mask all valid IVEs in the IRQ number space. */ for (i =0 ; i < xive->nr_irqs; i++) {XiveIVE *ive = &xive->ivt[i];@@ -51,18 +57,42 @@ static void spapr_xive_reset(DeviceState *dev)static void spapr_xive_init (Object *obj) { +sPAPRXive *xive =SPAPR_XIVE (obj); +object_initialize (&xive->source,sizeof (xive->source),TYPE_XIVE_SOURCE ); +object_property_add_child (obj,"source" ,OBJECT (&xive->source),NULL ); }static void spapr_xive_realize (DeviceState *dev,Error **errp) {sPAPRXive *xive =SPAPR_XIVE (dev); +XiveSource *xsrc = &xive->source; +Error *local_err =NULL ;if (!xive->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater 0" );return ; } +/* The XIVE interrupt controller has an internal source for IPIs +* and generic IPIs, the PSIHB has one and also the PHBs. For +* simplicity, we use a unique XIVE source object for *all* +* interrupts on sPAPR. The ESBs pages are mapped at the address +* of chip 0 of a real system. +*/ +object_property_set_int (OBJECT (xsrc),XIVE_VC_BASE ,"bar" , + &error_fatal); +object_property_set_int (OBJECT (xsrc), xive->nr_irqs,"nr-irqs" , + &error_fatal); +object_property_add_const_link (OBJECT (xsrc),"xive" ,OBJECT (xive), + &error_fatal); +object_property_set_bool (OBJECT (xsrc), true,"realized" , &local_err); +if (local_err) { +error_propagate (errp, local_err); +return ; + } +qdev_set_parent_bus (DEVICE (xsrc),sysbus_get_default ()); +/* Allocate the Interrupt Virtualization Table */ xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); }@@ -137,23 +167,27 @@ type_init(spapr_xive_register_types)bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi) {XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); +XiveSource *xsrc = &xive->source;if (!ive) {return false; } ive->w |=IVE_VALID ; +xive_source_irq_set (xsrc, lisn - xsrc->offset, lsi);return true; }bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn) {XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); +XiveSource *xsrc = &xive->source;if (!ive) {return false; } ive->w &= ~IVE_VALID ; +xive_source_irq_set (xsrc, lisn - xsrc->offset, false);return true; }include/hw/ppc/spapr_xive.h +3
-0@@ -19,6 +19,9 @@ typedef struct sPAPRXive { SysBusDevice parent; + /* Internal interrupt source for IPIs and virtual devices */ + XiveSource source; + /* Routing table */ XiveIVE *ivt; uint32_t nr_irqs;include/hw/ppc/xive.h +6
-0@@ -16,6 +16,12 @@typedef struct XiveFabric XiveFabric ;/* +* XIVE MMIO regions +*/ + +#define XIVE_VC_BASE 0x0006010000000000ull + +/* * XIVE Interrupt Source */
Re: [Qemu-devel] [PATCH v3 05/35] spapr/xive: add a single source block to the sPAPR XIVE model
Quoted 12 lines · Cédric Le Goater
Quoted 11 lines · David Gibson
Quoted 9 lines · Cédric Le Goater
Bare-metal systems (PowerNV) have multiples interrupt sources. The XIVE interrupt controller has an internal source for IPIs and generic IPIs, the PSIHB has one and also the PHBs. But, for simplicity on the sPAPR machine, we use a unique XiveSource object for all IPIs and virtual device interrupts of the VM.
The ESB MMIO region used to control the sources is mapped at the address of chip 0 of a real system and only the provisioned IRQ numbers are covered.
Quoted 5 lines
Quoted 1 line
Is that MMIO address PAPR specified, or arbitrary?
There are no specified value for the ESB address. It's queried by the guest using the
H_INT_GET_SOURCE_INFOhcall. For KVM, I have introduced a ioctl to configure the KVM device.
Ok.
Quoted 149 lines
Same for the TIMA, but in this case, the address is exposed to the guest in the device tree.
Quoted 144 lines
Quoted 143 lines
Signed-off-by Cédric Le Goater <[email protected]>--- hw/intc/spapr_xive.c | 34 ++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr_xive.h | 3 +++ include/hw/ppc/xive.h | 6 ++++++ 3 files changed, 43 insertions(+)hw/intc/spapr_xive.c +34
-0@@ -14,12 +14,15 @@#include "sysemu/cpus.h" #include "monitor/monitor.h" #include "hw/ppc/spapr_xive.h" +#include "hw/ppc/xive.h" #include "hw/ppc/xive_regs.h" void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) {int i; +xive_source_pic_print_info (&xive->source, mon); +monitor_printf (mon,"IVE Table\n" );for (i =0 ; i < xive->nr_irqs; i++) {XiveIVE *ive = &xive->ivt[i];@@ -40,6 +43,9 @@ static void spapr_xive_reset(DeviceState *dev)sPAPRXive *xive =SPAPR_XIVE (dev);int i; +/* Xive Source reset is done through SysBus, it should put all +* IRQs to OFF (!P|Q) */ +/* Mask all valid IVEs in the IRQ number space. */ for (i =0 ; i < xive->nr_irqs; i++) {XiveIVE *ive = &xive->ivt[i];@@ -51,18 +57,42 @@ static void spapr_xive_reset(DeviceState *dev)static void spapr_xive_init (Object *obj) { +sPAPRXive *xive =SPAPR_XIVE (obj); +object_initialize (&xive->source,sizeof (xive->source),TYPE_XIVE_SOURCE ); +object_property_add_child (obj,"source" ,OBJECT (&xive->source),NULL ); }static void spapr_xive_realize (DeviceState *dev,Error **errp) {sPAPRXive *xive =SPAPR_XIVE (dev); +XiveSource *xsrc = &xive->source; +Error *local_err =NULL ;if (!xive->nr_irqs) {error_setg (errp,"Number of interrupt needs to be greater 0" );return ; } +/* The XIVE interrupt controller has an internal source for IPIs +* and generic IPIs, the PSIHB has one and also the PHBs. For +* simplicity, we use a unique XIVE source object for *all* +* interrupts on sPAPR. The ESBs pages are mapped at the address +* of chip 0 of a real system. +*/ +object_property_set_int (OBJECT (xsrc),XIVE_VC_BASE ,"bar" , + &error_fatal); +object_property_set_int (OBJECT (xsrc), xive->nr_irqs,"nr-irqs" , + &error_fatal); +object_property_add_const_link (OBJECT (xsrc),"xive" ,OBJECT (xive), + &error_fatal); +object_property_set_bool (OBJECT (xsrc), true,"realized" , &local_err); +if (local_err) { +error_propagate (errp, local_err); +return ; + } +qdev_set_parent_bus (DEVICE (xsrc),sysbus_get_default ()); +/* Allocate the Interrupt Virtualization Table */ xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); }@@ -137,23 +167,27 @@ type_init(spapr_xive_register_types)bool spapr_xive_irq_enable (sPAPRXive *xive,uint32_t lisn,bool lsi) {XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); +XiveSource *xsrc = &xive->source;if (!ive) {return false; } ive->w |=IVE_VALID ; +xive_source_irq_set (xsrc, lisn - xsrc->offset, lsi);return true; }bool spapr_xive_irq_disable (sPAPRXive *xive,uint32_t lisn) {XiveIVE *ive =spapr_xive_get_ive (XIVE_FABRIC (xive), lisn); +XiveSource *xsrc = &xive->source;if (!ive) {return false; } ive->w &= ~IVE_VALID ; +xive_source_irq_set (xsrc, lisn - xsrc->offset, false);return true; }include/hw/ppc/spapr_xive.h +3
-0@@ -19,6 +19,9 @@ typedef struct sPAPRXive { SysBusDevice parent; + /* Internal interrupt source for IPIs and virtual devices */ + XiveSource source; + /* Routing table */ XiveIVE *ivt; uint32_t nr_irqs;include/hw/ppc/xive.h +6
-0@@ -16,6 +16,12 @@typedef struct XiveFabric XiveFabric ;/* +* XIVE MMIO regions +*/ + +#define XIVE_VC_BASE 0x0006010000000000ull + +/* * XIVE Interrupt Source
*/
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH v3 6/35 spapr/xive: introduce a XIVE interrupt presenter model
In reply to Cédric Le GoaterThe 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.
---
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(+)
hw/intc/spapr_xive.c +25 -0
@@ -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 ; + +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 ; +} +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 = {
hw/intc/xive.c +279 -0
298 lines not on this page · raw message
include/hw/ppc/spapr_xive.h +5 -0
@@ -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);
include/hw/ppc/xive.h +31 -0
@@ -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 */
include/hw/ppc/xive_regs.h +84 -0
94 lines not on this page · raw message
Signature · 1 line
2.13.6
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 49 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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"
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 9 lines
hw/intc/spapr_xive.c +6
-0@@ -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).
Quoted 14 lines
hw/intc/spapr_xive.c +10
-0+ +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)
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 9 lines
hw/intc/spapr_xive.c +6
-0@@ -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.
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 30 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +9
-0@@ -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) +{
hw/intc/xive.c line 36
Quoted 10 lines
hw/intc/xive.c +10
-0+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?
Quoted 16 lines
hw/intc/xive.c +16
-0+} + +/* +* 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); + }
hw/intc/xive.c line 62
Quoted 10 lines
hw/intc/xive.c +10
-0+ +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.
hw/intc/xive.c line 74
Quoted 12 lines
hw/intc/xive.c +12
-0+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;
Quoted 26 lines
hw/intc/xive.c +26
-0+ } + + 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) +{
hw/intc/xive.c line 110
Quoted 10 lines
hw/intc/xive.c +10
-0+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?
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?
Quoted 105 lines
hw/intc/xive.c +105
-0+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)); +}
hw/intc/xive.c line 225
Quoted 10 lines
hw/intc/xive.c +10
-0+ +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.
Quoted 12 lines
hw/intc/xive.c +12
-0+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 :
hw/intc/xive.c line 247
Quoted 10 lines
hw/intc/xive.c +10
-0+ 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, 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.
hw/intc/xive.c line 259
Quoted 12 lines
hw/intc/xive.c +12
-0+} + +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.
Quoted 228 lines
hw/intc/xive.c +37
-0+} + +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)include/hw/ppc/spapr_xive.h +5
-0@@ -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);include/hw/ppc/xive.h +31
-0@@ -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 */ include/hw/ppc/xive_regs.h +84
-0@@ -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 */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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)
Quoted 11 lines
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 8 lines
hw/intc/spapr_xive.c +6
-0/* 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.
Quoted 18 lines
Quoted 18 lines
hw/intc/spapr_xive.c +10
-0+ +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 ; }
Quoted 13 lines
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 6 lines
hw/intc/spapr_xive.c +6
-0+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.
Quoted 37 lines
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 34 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +13
-0@@ -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)
Quoted 8 lines
hw/intc/xive.c line 36
Quoted 6 lines
hw/intc/xive.c +6
-0+{ +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.
Quoted 22 lines
Quoted 22 lines
hw/intc/xive.c +22
-0+} + +/* +* 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) +
Quoted 8 lines
hw/intc/xive.c line 62
Quoted 4 lines
hw/intc/xive.c +4
-0+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->asand 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.
Quoted 6 lines
Quoted 6 lines
hw/intc/xive.c +6
-0+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);
Quoted 8 lines
hw/intc/xive.c line 74
Quoted 6 lines
hw/intc/xive.c +6
-0+ } + +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.
Quoted 32 lines
Quoted 32 lines
hw/intc/xive.c +31
-0+ } + + 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 ) {
Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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.
Quoted 2 lines
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.
Quoted 109 lines
Quoted 109 lines
hw/intc/xive.c +109
-0+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);
Quoted 8 lines
hw/intc/xive.c line 225
Quoted 6 lines
hw/intc/xive.c +6
-0+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.
Quoted 16 lines
Quoted 16 lines
hw/intc/xive.c +16
-0+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 :
Quoted 8 lines
hw/intc/xive.c line 247
Quoted 6 lines
hw/intc/xive.c +6
-0+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.
Quoted 4 lines
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.
Quoted 15 lines
hw/intc/xive.c line 259
Quoted 12 lines
hw/intc/xive.c +12
-0+} + +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_osfield 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.
Quoted 229 lines
Quoted 228 lines
hw/intc/xive.c +37
-0+} + +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)include/hw/ppc/spapr_xive.h +5
-0@@ -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);include/hw/ppc/xive.h +31
-0@@ -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 */ include/hw/ppc/xive_regs.h +84
-0@@ -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-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 245 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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)Quoted 11 lines
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 8 lines
hw/intc/spapr_xive.c +6
-0/* 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.Quoted 18 lines
Quoted 18 lines
hw/intc/spapr_xive.c +10
-0+ +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 ; }Quoted 13 lines
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 6 lines
hw/intc/spapr_xive.c +6
-0+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.
Quoted 37 lines
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 34 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +13
-0@@ -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)Quoted 8 lines
hw/intc/xive.c line 36
Quoted 6 lines
hw/intc/xive.c +6
-0+{ +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.
Quoted 22 lines
Quoted 22 lines
hw/intc/xive.c +22
-0+} + +/* +* 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) +Quoted 8 lines
hw/intc/xive.c line 62
Quoted 4 lines
hw/intc/xive.c +4
-0+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->asand 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.
Quoted 6 lines
Quoted 6 lines
hw/intc/xive.c +6
-0+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);Quoted 8 lines
hw/intc/xive.c line 74
Quoted 6 lines
hw/intc/xive.c +6
-0+ } + +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.
Quoted 32 lines
Quoted 32 lines
hw/intc/xive.c +31
-0+ } + + 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 ) {Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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?
Quoted 4 lines
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.
So, I gave a deeper look at the specs and I understood a little more details of the concepts behind. You need to do frequent round-trips to this document ...
These registers are accessible through four aligned pages, each exposing a different view of the registers. First page (page address ending in 0b00) gives access to the entire context and is reserved for the ring 0 security monitor. The second (page address ending in 0b01) is for the hypervisor, ring 1. The third (page address ending in 0b10) is for the operating system, ring 2. The fourth (page address ending in 0b11) is for user level, ring 3.
The sPAPR machine runs at the OS privilege and therefore can only accesses the OS and the User rings, 2 and 3. The others are for hypervisor levels.
I will try to come with a better implementation of the model and make sure the ring numbers are respected. I am not sure we should have only one memory region or four distinct ones with their own ops. There are some differences in the load/store of each view.
C.
Quoted 412 lines
Quoted 2 lines
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.
Quoted 109 lines
Quoted 109 lines
hw/intc/xive.c +109
-0+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);Quoted 8 lines
hw/intc/xive.c line 225
Quoted 6 lines
hw/intc/xive.c +6
-0+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.
Quoted 16 lines
Quoted 16 lines
hw/intc/xive.c +16
-0+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 :Quoted 8 lines
hw/intc/xive.c line 247
Quoted 6 lines
hw/intc/xive.c +6
-0+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.Quoted 4 lines
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.Quoted 15 lines
hw/intc/xive.c line 259
Quoted 12 lines
hw/intc/xive.c +12
-0+} + +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_osfield 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.
Quoted 229 lines
Quoted 228 lines
hw/intc/xive.c +37
-0+} + +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)include/hw/ppc/spapr_xive.h +5
-0@@ -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);include/hw/ppc/xive.h +31
-0@@ -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 */ include/hw/ppc/xive_regs.h +84
-0@@ -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-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 3 lines · Cédric Le Goater
Quoted 2 lines · Cédric Le Goater
Quoted 1 line · David Gibson
On Thu, Apr 19, 2018 at 02:43:02PM +0200, Cédric Le Goater wrote:
[snip]
Quoted 34 lines
Quoted 17 lines
Quoted 8 lines
Quoted 8 lines
hw/intc/xive.c +8
-0+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 ) {Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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?
Quoted 4 lines
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.
So, I gave a deeper look at the specs and I understood a little more details of the concepts behind. You need to do frequent round-trips to this document ...
These registers are accessible through four aligned pages, each exposing a different view of the registers. First page (page address ending in 0b00) gives access to the entire context and is reserved for the ring 0 security monitor. The second (page address ending in 0b01) is for the hypervisor, ring 1. The third (page address ending in 0b10) is for the operating system, ring 2. The fourth (page address ending in 0b11) is for user level, ring 3.
Quoted 3 lines
The sPAPR machine runs at the OS privilege and therefore can only accesses the OS and the User rings, 2 and 3. The others are for hypervisor levels.
Ok, that much is what I thought. What I'm less clear on is what each page looks like compared to the others. Previously I thought each one had the same registers, just manipulating the corresponding ring. Are you saying instead that each ring's page basically has a subset of the registers in the next most privileged page?
Quoted 4 lines
I will try to come with a better implementation of the model and make sure the ring numbers are respected. I am not sure we should have only one memory region or four distinct ones with their own ops. There are some differences in the load/store of each view.
Right. I'm not clear at this point if that's for good reasons, or just because IBM's hardware designers don't seem to have gotten the hang of Don't Repeat Yourself.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 39 lines · David Gibson
Quoted 3 lines · Cédric Le Goater
Quoted 2 lines · Cédric Le Goater
Quoted 1 line · David Gibson
On Thu, Apr 19, 2018 at 02:43:02PM +0200, Cédric Le Goater wrote:
[snip]
Quoted 34 lines
Quoted 17 lines
Quoted 8 lines
Quoted 8 lines
hw/intc/xive.c +8
-0+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 ) {Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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?
Quoted 4 lines
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.
So, I gave a deeper look at the specs and I understood a little more details of the concepts behind. You need to do frequent round-trips to this document ...
These registers are accessible through four aligned pages, each exposing a different view of the registers. First page (page address ending in 0b00) gives access to the entire context and is reserved for the ring 0 security monitor. The second (page address ending in 0b01) is for the hypervisor, ring 1. The third (page address ending in 0b10) is for the operating system, ring 2. The fourth (page address ending in 0b11) is for user level, ring 3.
Quoted 7 lines
Quoted 3 lines
The sPAPR machine runs at the OS privilege and therefore can only accesses the OS and the User rings, 2 and 3. The others are for hypervisor levels.
Ok, that much is what I thought. What I'm less clear on is what each page looks like compared to the others. Previously I thought each one had the same registers,
yes.
Quoted 1 line
just manipulating the corresponding ring.
no.
Quoted 2 lines
Are you saying instead that each ring's page basically has a subset of the registers in the next most privileged page?
That's the idea.
The registers are defined as follow :
QW-0 User QW-1 O/S QW-2 Pool QW-3 Physical
and the pages :
- 0006030203180000 security monitor
can access all registers
- 0006030203190000 hv
can access all registers minus the secure regs
- 00060302031a0000 os
can access some of the OS (QW1) and User (QW0) registers
- 00060302031b0000 user
can access NSR reg of User (QW0) registers
On sPAPR, we can remap the os/user pages to some other base address but we should keep the same page offset.
Quoted 9 lines
Quoted 4 lines
I will try to come with a better implementation of the model and make sure the ring numbers are respected. I am not sure we should have only one memory region or four distinct ones with their own ops. There are some differences in the load/store of each view.
Right. I'm not clear at this point if that's for good reasons, or just because IBM's hardware designers don't seem to have gotten the hang of Don't Repeat Yourself.
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 50 lines · Cédric Le Goater
Quoted 39 lines · David Gibson
Quoted 3 lines · Cédric Le Goater
Quoted 2 lines · Cédric Le Goater
Quoted 1 line · David Gibson
On Thu, Apr 19, 2018 at 02:43:02PM +0200, Cédric Le Goater wrote:
[snip]
Quoted 34 lines
Quoted 17 lines
Quoted 8 lines
Quoted 8 lines
hw/intc/xive.c +8
-0+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 ) {Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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?
Quoted 4 lines
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.
So, I gave a deeper look at the specs and I understood a little more details of the concepts behind. You need to do frequent round-trips to this document ...
These registers are accessible through four aligned pages, each exposing a different view of the registers. First page (page address ending in 0b00) gives access to the entire context and is reserved for the ring 0 security monitor. The second (page address ending in 0b01) is for the hypervisor, ring 1. The third (page address ending in 0b10) is for the operating system, ring 2. The fourth (page address ending in 0b11) is for user level, ring 3.
Quoted 7 lines
Quoted 3 lines
The sPAPR machine runs at the OS privilege and therefore can only accesses the OS and the User rings, 2 and 3. The others are for hypervisor levels.
Ok, that much is what I thought. What I'm less clear on is what each page looks like compared to the others. Previously I thought each one had the same registers,
yes.
Quoted 8 lines
Quoted 1 line
just manipulating the corresponding ring.
no.
Quoted 2 lines
Are you saying instead that each ring's page basically has a subset of the registers in the next most privileged page?
That's the idea.
Ah, ok.
Quoted 12 lines
The registers are defined as follow :
QW-0 User QW-1 O/S QW-2 Pool QW-3 Physicaland the pages :
- 0006030203180000 security monitor
can access all registers
Quoted 8 lines
- 0006030203190000 hv
can access all registers minus the secure regs-
00060302031a0000os
can access some of the OS (QW1) and User (QW0) registers-
00060302031b0000user
can access NSR reg of User (QW0) registers
I can see two reasonable ways of doing this:
A)
Have a single set of read/write functions. These implement all the registers but take a "privilege level" parameter which controls which will actually work. Those could then be wired up in one of two ways:
A1) Single memory region. The accessor derives the priv level from the relevant address bits, before masking it down to a single register page. Then, as above
A2) Multiple memory regions with the same accessor functions but different opaque pointer. The accessor gets the priv level from its opaque pointer, then the address is just within a single ring's page.
B)
Separate memory regions with separate accessors. The ring-0 accessor implements the ring-0 registers, then calls the ring-1 accessor function for everything else. ring-1 calls ring-2 and so forth.
Quoted 2 lines
On sPAPR, we can remap the os/user pages to some other base address but we should keep the same page offset.
Sure.
Quoted 12 lines
Quoted 11 lines
Quoted 6 lines
I will try to come with a better implementation of the model and make sure the ring numbers are respected. I am not sure we should have only one memory region or four distinct ones with their own ops. There are some differences in the load/store of each view.
Right. I'm not clear at this point if that's for good reasons, or just because IBM's hardware designers don't seem to have gotten the hang of Don't Repeat Yourself.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 87 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
Quoted 39 lines · David Gibson
Quoted 3 lines · Cédric Le Goater
Quoted 2 lines · Cédric Le Goater
Quoted 1 line · David Gibson
On Thu, Apr 19, 2018 at 02:43:02PM +0200, Cédric Le Goater wrote:
[snip]
Quoted 34 lines
Quoted 17 lines
Quoted 8 lines
Quoted 8 lines
(quoted diff) +8
-0+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) {Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ 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?
Quoted 4 lines
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.
So, I gave a deeper look at the specs and I understood a little more details of the concepts behind. You need to do frequent round-trips to this document ...
These registers are accessible through four aligned pages, each exposing a different view of the registers. First page (page address ending in 0b00) gives access to the entire context and is reserved for the ring 0 security monitor. The second (page address ending in 0b01) is for the hypervisor, ring 1. The third (page address ending in 0b10) is for the operating system, ring 2. The fourth (page address ending in 0b11) is for user level, ring 3.
Quoted 7 lines
Quoted 3 lines
The sPAPR machine runs at the OS privilege and therefore can only accesses the OS and the User rings, 2 and 3. The others are for hypervisor levels.
Ok, that much is what I thought. What I'm less clear on is what each page looks like compared to the others. Previously I thought each one had the same registers,
yes.
Quoted 8 lines
Quoted 1 line
just manipulating the corresponding ring.
no.
Quoted 2 lines
Are you saying instead that each ring's page basically has a subset of the registers in the next most privileged page?
That's the idea.
Ah, ok.
Quoted 12 lines
The registers are defined as follow :
QW-0 User QW-1 O/S QW-2 Pool QW-3 Physicaland the pages :
- 0006030203180000 security monitor
can access all registersQuoted 8 lines
- 0006030203190000 hv
can access all registers minus the secure regs-
00060302031a0000os
can access some of the OS (QW1) and User (QW0) registers-
00060302031b0000user
can access NSR reg of User (QW0) registersI can see two reasonable ways of doing this:
A)
Quoted 7 lines
Have a single set of read/write functions. These implement all the registers but take a "privilege level" parameter which controls which will actually work. Those could then be wired up in one of two ways:
A1) Single memory region. The accessor derives the priv level from the relevant address bits, before masking it down to a single register page. Then, as above
Yes. That's the goal behind the page ordering :
page address ending in 0b00 : ring 0, security monitor page address ending in 0b01 : ring 1, hypervisor page address ending in 0b10 : ring 2, operating system page address ending in 0b11 : ring 3, user level
I don't why the registers are ordered the other way around though.
That's would be the direction to take for the emulated mode, I think. It covers well the PowerNV (4 pages) and the sPAPR case (2 pages), in each case, the machine IC controller decides how much pages to map. The memory region ops do the rest.
For KVM, we need to populate the VMA with the host TIMA page associated with ring 2 (OS) and then ring 3 (USER).
This option looks better overall. I will see how ugly it gets with the implementation.
C.
Quoted 29 lines
A2) Multiple memory regions with the same accessor functions but different opaque pointer. The accessor gets the priv level from its opaque pointer, then the address is just within a single ring's page.
B)
Separate memory regions with separate accessors. The ring-0 accessor implements the ring-0 registers, then calls the ring-1 accessor function for everything else. ring-1 calls ring-2 and so forth.
Quoted 2 lines
On sPAPR, we can remap the os/user pages to some other base address but we should keep the same page offset.
Sure.
Quoted 12 lines
Quoted 11 lines
Quoted 6 lines
I will try to come with a better implementation of the model and make sure the ring numbers are respected. I am not sure we should have only one memory region or four distinct ones with their own ops. There are some differences in the load/store of each view.
Right. I'm not clear at this point if that's for good reasons, or just because IBM's hardware designers don't seem to have gotten the hang of Don't Repeat Yourself.
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
In reply to Cédric Le GoaterQuoted 64 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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)Quoted 11 lines
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 8 lines
hw/intc/spapr_xive.c +6
-0/* 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).
Quoted 6 lines
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.
I agree.
Quoted 80 lines
Quoted 17 lines
Quoted 17 lines
hw/intc/spapr_xive.c +10
-0+ +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 ; }Quoted 13 lines
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 6 lines
hw/intc/spapr_xive.c +6
-0+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.
Quoted 37 lines
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 34 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +13
-0@@ -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)Quoted 8 lines
hw/intc/xive.c line 36
Quoted 6 lines
hw/intc/xive.c +6
-0+{ +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?
Quoted 1 line
yes. In patch 9, when we introduce the nvt notify routine.
Ok.
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
hw/intc/xive.c +22
-0+} + +/* +* 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) +Quoted 8 lines
hw/intc/xive.c line 62
Quoted 4 lines
hw/intc/xive.c +4
-0+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->asand not just having them all point to&address_space_memory.
Quoted 1 line
Yes, you did and I haven't studied the question yet. For the next version.
So, it's possible that using the cpu->as thing will be more trouble that it's worth. I am a little concerned about using current_cpu though. First, will it work with KVM with kernel_irqchip=off - the cpus are running truly concurrently, but we still need to work out who's poking at the TIMA. Second, are there any cases where we might need to trip this "on behalf of" a specific cpu that's not the current one.
Quoted 63 lines
Quoted 6 lines
Quoted 6 lines
hw/intc/xive.c +6
-0+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);Quoted 8 lines
hw/intc/xive.c line 74
Quoted 6 lines
hw/intc/xive.c +6
-0+ } + +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.
Quoted 32 lines
Quoted 32 lines
hw/intc/xive.c +31
-0+ } + + 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 ) {Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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.
Quoted 8 lines
Quoted 2 lines
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.
Oh. I had the impression that each ring had a basically identical set of registers and you just had access to the region for your ring and the ones below. Are you saying instead it's basically a single block of registers with various different privilege levels for each of them?
[snip]
Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
hw/intc/xive.c +7
-0+} + +static void xive_nvt_unrealize (DeviceState *dev,Error **errp) +{ +qemu_unregister_reset (xive_nvt_reset, dev); +} +Quoted 8 lines
hw/intc/xive.c line 259
Quoted 5 lines
hw/intc/xive.c +5
-0+static void xive_nvt_init (Object *obj) +{ +XiveNVT *nvt =XIVE_NVT (obj); + + nvt->ring_os = &nvt->regs[TM_QW1_OS ];The
ring_osfield is basically pointless, being just an offset into a structure you already have. A macro or inline would be a better idea.
Quoted 2 lines
ok. I liked the idea but I agree it's overkill to have an init routine just for this. I will find something.
That too, but it's also something that looks like an optimization but isn't, which is bad practice. On modern cpus math is cheap (and this is just a trivial offset), memory accesses are expensive. You're essentially caching this offset - raising all the usual invalidation questions for a cache - when caching it is *more* expensive than just computing it every time.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 189 lines · David Gibson
Quoted 64 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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)Quoted 11 lines
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 8 lines
hw/intc/spapr_xive.c +6
-0/* 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).
Quoted 6 lines
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.I agree.
Quoted 80 lines
Quoted 17 lines
Quoted 17 lines
hw/intc/spapr_xive.c +10
-0+ +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 ; }Quoted 13 lines
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 6 lines
hw/intc/spapr_xive.c +6
-0+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.
Quoted 37 lines
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 34 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +13
-0@@ -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)Quoted 8 lines
hw/intc/xive.c line 36
Quoted 6 lines
hw/intc/xive.c +6
-0+{ +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?
Quoted 1 line
yes. In patch 9, when we introduce the nvt notify routine.
Ok.
Quoted 31 lines
Quoted 30 lines
Quoted 16 lines
hw/intc/xive.c +16
-0+} + +/* +* 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); + }hw/intc/xive.c line 62
Quoted 10 lines
hw/intc/xive.c +10
-0+ +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->asand not just having them all point to&address_space_memory.
Quoted 4 lines
Quoted 1 line
Yes, you did and I haven't studied the question yet. For the next version.
So, it's possible that using the
cpu->asthing will be more trouble that it's worth.
One of the trouble is the number of memory regions to use, one per cpu, and the KVM support. Having a single region is much easier.
Quoted 3 lines
I am a little concerned about using
current_cputhough. First, will it work with KVM with kernel_irqchip=off - the cpus are running truly concurrently,
FWIW, I didn't see any issue yet while stressing.
Quoted 1 line
but we still need to work out who's poking at the TIMA.
I understand. The registers are accessed by the current cpu to set the CPPR and to ack an interrupt. But when we route an event, we also access and modify the registers. Do you suggest some locking ? I am not sure how are protected the TIMA region accesses vs. the routing, which is necessarily initiated by an ESB MMIO though.
Quoted 3 lines
Second, are there any cases where we might
need to trip this "on behalf of" a specific cpu that's not the current one.
ah. yes. sort of :) only in powernv, when the xive is reseted (and when dumping the state for debug).
The IC has a way to access indirectly the registers of a HW thread. It, first, sets the PC_TCTXT_INDIR_THRDID register with the PIR of the targeted thread and then loads on the indirect TIMA can be done as if it was the current thread. The indirect TIMA is mapped 4 pages after the IC BAR.
The resulting memory region op is a little ugly and might need some rework :
static uint64_t xive_tm_hv_read(void *opaque, hwaddr offset,
unsigned size)
{
PowerPCCPU **cpuptr = opaque;
PowerPCCPU *cpu = *cpuptr ? *cpuptr : POWERPC_CPU(current_cpu);
...Quoted 69 lines
Quoted 69 lines
Quoted 6 lines
Quoted 6 lines
hw/intc/xive.c +6
-0+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);Quoted 8 lines
hw/intc/xive.c line 74
Quoted 6 lines
hw/intc/xive.c +6
-0+ } + +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.
Quoted 32 lines
Quoted 32 lines
hw/intc/xive.c +31
-0+ } + + 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 ) {Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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.
Quoted 2 lines
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.
Quoted 7 lines
Quoted 2 lines
I think the problem will become clearer (or worse) with pnv which uses the HV mode.
Oh. I had the impression that each ring had a basically identical set of registers and you just had access to the region for your ring and the ones below. Are you saying instead it's basically a single block of registers with various different privilege levels for each of them?
yes. I think I answered this question more clearly in a previous email.
Quoted 20 lines
[snip]
Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
hw/intc/xive.c +7
-0+} + +static void xive_nvt_unrealize (DeviceState *dev,Error **errp) +{ +qemu_unregister_reset (xive_nvt_reset, dev); +} +Quoted 8 lines
hw/intc/xive.c line 259
Quoted 5 lines
hw/intc/xive.c +5
-0+static void xive_nvt_init (Object *obj) +{ +XiveNVT *nvt =XIVE_NVT (obj); + + nvt->ring_os = &nvt->regs[TM_QW1_OS ];The
ring_osfield is basically pointless, being just an offset into a structure you already have. A macro or inline would be a better idea.Quoted 2 lines
ok. I liked the idea but I agree it's overkill to have an init routine just for this. I will find something.
Quoted 6 lines
That too, but it's also something that looks like an optimization but isn't, which is bad practice. On modern cpus math is cheap (and this is just a trivial offset), memory accesses are expensive. You're essentially caching this offset - raising all the usual invalidation questions for a cache - when caching it is *more* expensive than just computing it every time.
ok. removing this offset was a good opportunity to generalize the routing algorithm and use a 'ring' parameter in all routines. Same for the accept path.
C.
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 190 lines · Cédric Le Goater
Quoted 189 lines · David Gibson
Quoted 64 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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)Quoted 11 lines
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 8 lines
hw/intc/spapr_xive.c +6
-0/* 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).
Quoted 6 lines
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.I agree.
Quoted 80 lines
Quoted 17 lines
Quoted 17 lines
hw/intc/spapr_xive.c +10
-0+ +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 ; }Quoted 13 lines
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 6 lines
hw/intc/spapr_xive.c +6
-0+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.
Quoted 37 lines
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 34 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +13
-0@@ -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)Quoted 8 lines
hw/intc/xive.c line 36
Quoted 6 lines
hw/intc/xive.c +6
-0+{ +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?
Quoted 1 line
yes. In patch 9, when we introduce the nvt notify routine.
Ok.
Quoted 31 lines
Quoted 30 lines
Quoted 16 lines
hw/intc/xive.c +16
-0+} + +/* +* 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); + }hw/intc/xive.c line 62
Quoted 10 lines
hw/intc/xive.c +10
-0+ +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->asand not just having them all point to&address_space_memory.
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
Yes, you did and I haven't studied the question yet. For the next version.
So, it's possible that using the
cpu->asthing will be more trouble that it's worth.One of the trouble is the number of memory regions to use, one per cpu,
Well, we're already going to have an NVT object for each cpu, yes? So a memory region per-cpu doesn't seem like a big stretch.
Quoted 1 line
and the KVM support.
And I really don't see how the memory regions impacts KVM.
Quoted 7 lines
Having a single region is much easier.
Quoted 3 lines
I am a little concerned about using
current_cputhough. First, will it work with KVM with kernel_irqchip=off - the cpus are running truly concurrently,FWIW, I didn't see any issue yet while stressing.
Ok.
Quoted 7 lines
Quoted 1 line
but we still need to work out who's poking at the TIMA.
I understand. The registers are accessed by the current cpu to set the CPPR and to ack an interrupt. But when we route an event, we also access and modify the registers. Do you suggest some locking ? I am not sure how are protected the TIMA region accesses vs. the routing, which is necessarily initiated by an ESB MMIO though.
Locking isn't really the issue. I mean, we do need locking, but the BQL should provide that. The issue is what exactly does "current" mean in the context of multiple concurrently running cpus. Does it always mean what we need it to mean in every context we might call this from.
Quoted 137 lines
Quoted 3 lines
Second, are there any cases where we might
need to trip this "on behalf of" a specific cpu that's not the current one.ah. yes. sort of :) only in powernv, when the xive is reseted (and when dumping the state for debug).
The IC has a way to access indirectly the registers of a HW thread. It, first, sets the
PC_TCTXT_INDIR_THRDIDregister with the PIR of the targeted thread and then loads on the indirect TIMA can be done as if it was the current thread. The indirect TIMA is mapped 4 pages after the IC BAR.The resulting memory region op is a little ugly and might need some rework :
static
uint64_txive_tm_hv_read(void *opaque, hwaddr offset,
unsigned size){ PowerPCCPU **cpuptr = opaque; PowerPCCPU *cpu = *cpuptr ? *cpuptr : POWERPC_CPU(current_cpu); ...Quoted 69 lines
Quoted 69 lines
Quoted 6 lines
Quoted 6 lines
hw/intc/xive.c +6
-0+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);Quoted 8 lines
hw/intc/xive.c line 74
Quoted 6 lines
hw/intc/xive.c +6
-0+ } + +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.
Quoted 32 lines
Quoted 32 lines
hw/intc/xive.c +31
-0+ } + + 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 ) {Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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.
Quoted 2 lines
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.
Quoted 7 lines
Quoted 2 lines
I think the problem will become clearer (or worse) with pnv which uses the HV mode.
Oh. I had the impression that each ring had a basically identical set of registers and you just had access to the region for your ring and the ones below. Are you saying instead it's basically a single block of registers with various different privilege levels for each of them?
yes. I think I answered this question more clearly in a previous email.
Quoted 20 lines
[snip]
Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
hw/intc/xive.c +7
-0+} + +static void xive_nvt_unrealize (DeviceState *dev,Error **errp) +{ +qemu_unregister_reset (xive_nvt_reset, dev); +} +Quoted 8 lines
hw/intc/xive.c line 259
Quoted 5 lines
hw/intc/xive.c +5
-0+static void xive_nvt_init (Object *obj) +{ +XiveNVT *nvt =XIVE_NVT (obj); + + nvt->ring_os = &nvt->regs[TM_QW1_OS ];The
ring_osfield is basically pointless, being just an offset into a structure you already have. A macro or inline would be a better idea.Quoted 2 lines
ok. I liked the idea but I agree it's overkill to have an init routine just for this. I will find something.
Quoted 6 lines
That too, but it's also something that looks like an optimization but isn't, which is bad practice. On modern cpus math is cheap (and this is just a trivial offset), memory accesses are expensive. You're essentially caching this offset - raising all the usual invalidation questions for a cache - when caching it is *more* expensive than just computing it every time.
ok. removing this offset was a good opportunity to generalize the routing algorithm and use a 'ring' parameter in all routines. Same for the accept path.
C.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 196 lines · David Gibson
Quoted 195 lines · Cédric Le Goater
Quoted 193 lines · David Gibson
Quoted 64 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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)Quoted 11 lines
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 8 lines
hw/intc/spapr_xive.c +6
-0/* 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).
Quoted 6 lines
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.I agree.
Quoted 80 lines
Quoted 17 lines
Quoted 17 lines
hw/intc/spapr_xive.c +10
-0+ +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 ; }Quoted 13 lines
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 6 lines
hw/intc/spapr_xive.c +6
-0+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.
Quoted 37 lines
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 34 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +13
-0@@ -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)Quoted 8 lines
hw/intc/xive.c line 36
Quoted 6 lines
hw/intc/xive.c +6
-0+{ +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?
Quoted 1 line
yes. In patch 9, when we introduce the nvt notify routine.
Ok.
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
hw/intc/xive.c +22
-0+} + +/* +* 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) +Quoted 8 lines
hw/intc/xive.c line 62
Quoted 4 lines
hw/intc/xive.c +4
-0+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->asand not just having them all point to&address_space_memory.Quoted 1 line
Yes, you did and I haven't studied the question yet. For the next version.
So, it's possible that using the
cpu->asthing will be more trouble that it's worth.
Quoted 8 lines
Quoted 1 line
One of the trouble is the number of memory regions to use, one per cpu,
Well, we're already going to have an NVT object for each cpu, yes? So a memory region per-cpu doesn't seem like a big stretch.
Quoted 1 line
and the KVM support.
And I really don't see how the memory regions impacts KVM.
The TIMA is setup when the KVM device is initialized using some specific ioctl to get an fd on a MMIO region from the host. It is then passed to the guest as a 'ram_device', same for the ESBs.
This is not a common region.
Quoted 18 lines
Quoted 7 lines
Having a single region is much easier.
Quoted 3 lines
I am a little concerned about using
current_cputhough. First, will it work with KVM with kernel_irqchip=off - the cpus are running truly concurrently,FWIW, I didn't see any issue yet while stressing.
Ok.
Quoted 7 lines
Quoted 1 line
but we still need to work out who's poking at the TIMA.
I understand. The registers are accessed by the current cpu to set the CPPR and to ack an interrupt. But when we route an event, we also access and modify the registers. Do you suggest some locking ? I am not sure how are protected the TIMA region accesses vs. the routing, which is necessarily initiated by an ESB MMIO though.
Quoted 5 lines
Locking isn't really the issue. I mean, we do need locking, but the BQL should provide that. The issue is what exactly does "current" mean in the context of multiple concurrently running cpus. Does it always mean what we need it to mean in every context we might call this from.
I would say so.
C.
Quoted 138 lines
Quoted 137 lines
Quoted 3 lines
Second, are there any cases where we might
need to trip this "on behalf of" a specific cpu that's not the current one.ah. yes. sort of :) only in powernv, when the xive is reseted (and when dumping the state for debug).
The IC has a way to access indirectly the registers of a HW thread. It, first, sets the
PC_TCTXT_INDIR_THRDIDregister with the PIR of the targeted thread and then loads on the indirect TIMA can be done as if it was the current thread. The indirect TIMA is mapped 4 pages after the IC BAR.The resulting memory region op is a little ugly and might need some rework :
static
uint64_txive_tm_hv_read(void *opaque, hwaddr offset,
unsigned size){ PowerPCCPU **cpuptr = opaque; PowerPCCPU *cpu = *cpuptr ? *cpuptr : POWERPC_CPU(current_cpu); ...Quoted 69 lines
Quoted 69 lines
Quoted 6 lines
Quoted 6 lines
hw/intc/xive.c +6
-0+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);Quoted 8 lines
hw/intc/xive.c line 74
Quoted 6 lines
hw/intc/xive.c +6
-0+ } + +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.
Quoted 32 lines
Quoted 32 lines
hw/intc/xive.c +31
-0+ } + + 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 ) {Quoted 8 lines
hw/intc/xive.c line 110
Quoted 5 lines
hw/intc/xive.c +5
-0+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.
Quoted 2 lines
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.
Quoted 7 lines
Quoted 2 lines
I think the problem will become clearer (or worse) with pnv which uses the HV mode.
Oh. I had the impression that each ring had a basically identical set of registers and you just had access to the region for your ring and the ones below. Are you saying instead it's basically a single block of registers with various different privilege levels for each of them?
yes. I think I answered this question more clearly in a previous email.
Quoted 20 lines
[snip]
Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
hw/intc/xive.c +7
-0+} + +static void xive_nvt_unrealize (DeviceState *dev,Error **errp) +{ +qemu_unregister_reset (xive_nvt_reset, dev); +} +Quoted 8 lines
hw/intc/xive.c line 259
Quoted 5 lines
hw/intc/xive.c +5
-0+static void xive_nvt_init (Object *obj) +{ +XiveNVT *nvt =XIVE_NVT (obj); + + nvt->ring_os = &nvt->regs[TM_QW1_OS ];The
ring_osfield is basically pointless, being just an offset into a structure you already have. A macro or inline would be a better idea.Quoted 2 lines
ok. I liked the idea but I agree it's overkill to have an init routine just for this. I will find something.
Quoted 6 lines
That too, but it's also something that looks like an optimization but isn't, which is bad practice. On modern cpus math is cheap (and this is just a trivial offset), memory accesses are expensive. You're essentially caching this offset - raising all the usual invalidation questions for a cache - when caching it is *more* expensive than just computing it every time.
ok. removing this offset was a good opportunity to generalize the routing algorithm and use a 'ring' parameter in all routines. Same for the accept path.
C.
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 202 lines · Cédric Le Goater
Quoted 201 lines · David Gibson
Quoted 190 lines · Cédric Le Goater
Quoted 189 lines · David Gibson
Quoted 64 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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)Quoted 11 lines
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 8 lines
hw/intc/spapr_xive.c +6
-0/* 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).
Quoted 6 lines
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.I agree.
Quoted 80 lines
Quoted 17 lines
Quoted 17 lines
hw/intc/spapr_xive.c +10
-0+ +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 ; }Quoted 13 lines
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 6 lines
hw/intc/spapr_xive.c +6
-0+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.
Quoted 37 lines
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 34 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +13
-0@@ -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)Quoted 8 lines
hw/intc/xive.c line 36
Quoted 6 lines
hw/intc/xive.c +6
-0+{ +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?
Quoted 1 line
yes. In patch 9, when we introduce the nvt notify routine.
Ok.
Quoted 31 lines
Quoted 30 lines
Quoted 16 lines
hw/intc/xive.c +16
-0+} + +/* +* 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); + }hw/intc/xive.c line 62
Quoted 10 lines
hw/intc/xive.c +10
-0+ +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->asand not just having them all point to&address_space_memory.Quoted 6 lines
Quoted 4 lines
Quoted 1 line
Yes, you did and I haven't studied the question yet. For the next version.
So, it's possible that using the
cpu->asthing will be more trouble that it's worth.One of the trouble is the number of memory regions to use, one per cpu,
Well, we're already going to have an NVT object for each cpu, yes? So a memory region per-cpu doesn't seem like a big stretch.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
and the KVM support.
And I really don't see how the memory regions impacts KVM.
The TIMA is setup when the KVM device is initialized using some specific ioctl to get an fd on a MMIO region from the host. It is then passed to the guest as a '
ram_device', same for the ESBs.
Ah, good point.
Quoted 1 line
This is not a common region.
I'm not sure what you mean by that.
Quoted 18 lines
Quoted 18 lines
Quoted 7 lines
Having a single region is much easier.
Quoted 3 lines
I am a little concerned about using
current_cputhough. First, will it work with KVM with kernel_irqchip=off - the cpus are running truly concurrently,FWIW, I didn't see any issue yet while stressing.
Ok.
Quoted 7 lines
Quoted 1 line
but we still need to work out who's poking at the TIMA.
I understand. The registers are accessed by the current cpu to set the CPPR and to ack an interrupt. But when we route an event, we also access and modify the registers. Do you suggest some locking ? I am not sure how are protected the TIMA region accesses vs. the routing, which is necessarily initiated by an ESB MMIO though.
Quoted 7 lines
Quoted 5 lines
Locking isn't really the issue. I mean, we do need locking, but the BQL should provide that. The issue is what exactly does "current" mean in the context of multiple concurrently running cpus. Does it always mean what we need it to mean in every context we might call this from.
I would say so.
Ok.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH v3 06/35] spapr/xive: introduce a XIVE interrupt presenter model
Quoted 211 lines · David Gibson
Quoted 202 lines · Cédric Le Goater
Quoted 201 lines · David Gibson
Quoted 190 lines · Cédric Le Goater
Quoted 189 lines · David Gibson
Quoted 64 lines · Cédric Le Goater
Quoted 51 lines · David Gibson
Quoted 50 lines · Cédric Le Goater
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 <[email protected]>---
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(+)hw/intc/spapr_xive.c +1
-0@@ -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)Quoted 11 lines
hw/intc/spapr_xive.c static void spapr_xive_realize(DeviceState *dev, Error **errp) · line 104
Quoted 8 lines
hw/intc/spapr_xive.c +6
-0/* 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).
Quoted 6 lines
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.I agree.
Quoted 80 lines
Quoted 17 lines
Quoted 17 lines
hw/intc/spapr_xive.c +10
-0+ +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 ; }Quoted 13 lines
hw/intc/spapr_xive.c static XiveIVE *spapr_xive_get_ive(XiveFabric *xf, uint32_t lisn) · line 129
Quoted 6 lines
hw/intc/spapr_xive.c +6
-0+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.
Quoted 37 lines
I think we'd need something similar to correctly handle migration of the VPA state, which is currently horribly broken.
Quoted 34 lines
hw/intc/spapr_xive.c +2
-0+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 = {hw/intc/xive.c +13
-0@@ -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)Quoted 8 lines
hw/intc/xive.c line 36
Quoted 6 lines
hw/intc/xive.c +6
-0+{ +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?
Quoted 1 line
yes. In patch 9, when we introduce the nvt notify routine.
Ok.
Quoted 31 lines
Quoted 30 lines
Quoted 16 lines
hw/intc/xive.c +16
-0+} + +/* +* 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); + }hw/intc/xive.c line 62
Quoted 10 lines
hw/intc/xive.c +10
-0+ +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->asand not just having them all point to&address_space_memory.Quoted 6 lines
Quoted 4 lines
Quoted 1 line
Yes, you did and I haven't studied the question yet. For the next version.
So, it's possible that using the
cpu->asthing will be more trouble that it's worth.One of the trouble is the number of memory regions to use, one per cpu,
Well, we're already going to have an NVT object for each cpu, yes? So a memory region per-cpu doesn't seem like a big stretch.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
and the KVM support.
And I really don't see how the memory regions impacts KVM.
The TIMA is setup when the KVM device is initialized using some specific ioctl to get an fd on a MMIO region from the host. It is then passed to the guest as a '
ram_device', same for the ESBs.
Quoted 5 lines
Ah, good point.
Quoted 1 line
This is not a common region.
I'm not sure what you mean by that.
I meant by that 'out of the ordinary', 'unusual'. Specially when under KVM.
C.
Quoted 28 lines
Quoted 18 lines
Quoted 18 lines
Quoted 7 lines
Having a single region is much easier.
Quoted 3 lines
I am a little concerned about using
current_cputhough. First, will it work with KVM with kernel_irqchip=off - the cpus are running truly concurrently,FWIW, I didn't see any issue yet while stressing.
Ok.
Quoted 7 lines
Quoted 1 line
but we still need to work out who's poking at the TIMA.
I understand. The registers are accessed by the current cpu to set the CPPR and to ack an interrupt. But when we route an event, we also access and modify the registers. Do you suggest some locking ? I am not sure how are protected the TIMA region accesses vs. the routing, which is necessarily initiated by an ESB MMIO though.
Quoted 7 lines
Quoted 5 lines
Locking isn't really the issue. I mean, we do need locking, but the BQL should provide that. The issue is what exactly does "current" mean in the context of multiple concurrently running cpus. Does it always mean what we need it to mean in every context we might call this from.
I would say so.
Ok.