ppc: support for the XIVE interrupt controller (POWER9)
v4 cover ppc: support for the XIVE interrupt controller (POWER9)
Hello,
Here is the version 4 of the QEMU models adding support for XIVE to the sPAPR machine, under TCG and KVM, and to the PowerNV machine. The common framework is stabilizing and the routing is significantly improved. The next interesting step would be to add escalation events and model VP dispatching.
Thanks,
C.
Changes in v4 :
Common XIVE models :
- minor changes in the XiveSource model. Remove unnecessary 'offset', full IRQ number space is populated.
- reduced XiveFabric. The interface was embedding the Router which was wrong.
- renamed XiveNVT to XiveTCTX for the Thread interrupt context.
- removed the CPU EQDs from under the Thread interrupt context model. That was pratical but slightly ugly.
- unified the TIMA load/store accessors for sPAPR and PowerNV. It supports all the TIMA privilege pages now.
- introduced a XiveRouter abstract class combining the IVRE and the IVPE in one model. Storage for the routing tables should be provisioned by the inheriting classes : sPAPRXive, PnvXive
- extended the routing algorithm. Covers all models and defines a clear sequence of each steps.
- introduced a VP matching algorithm using the CAM lines as in real HW.
- introduced a new XiveEQSource model to expose the EQ ESBs. Not used on the field, only to sync the EQ cache in OPAL.
On the sPAPR side :
- moved the EQDT under sPAPRXive, requires EQ indexing.
- new sPAPR IRQ backend for XIVE
- new pseries-2.13-xive machine supporting only XIVE.
- removed the capacity to switch the interrupt mode after CAS. Will come in time when the models have stabilized. This is not a large rework, the main problem being KVM reset.
- improved migration algo. Still misses OPAL calls to sync XIVE.
On the PowerNV side :
- A massive rework of PnvXive to adapt to the changes
- unified VST accessors
- multichip support
= XIVE =================================================================
The POWER9 processor comes with a new interrupt controller, called XIVE as "eXternal Interrupt Virtualization Engine".
* Overall architecture
XIVE Interrupt Controller
+-------------------------------------+ IPIs
| +---------+ +---------+ +---------+ | +--------+
| |VC | |CQ | |PC |----> | CORES |
| | esb | | | | |----> | |
| | ive | | Bridge | | |----> | |
| |SC eqd | | | | vpd | | | |
+------+ | +---------+ +----+----+ +---------+ | +--+-+-+-+
| RAM | +------------------|------------------+ | | |
| | | | | |
| | | | | |
| | +---------------------v--------------------------v-v-v---+ other
| <---+ Power Bus +----> chips
| esb | +-----------+-----------------------+--------------------+
| ive | | |
| eqd | | |
| vpd | +---+----+ +---+----+
+------+ |SC | |SC |
| | | |
| 2-bits | | 2-bits |
| local | | VC |
+--------+ +--------+
PCIe NX,NPU,CAPI SC: Source Controller (aka. IVSE)
VC: Virtualization Controller (aka. IVRE)
CQ: Common Queue (Bridge)
PC: Presentation Controller (aka. IVPE)
2-bits: source state machine
esb: Event State Buffer (Array of PQ bits in an IVSE)
ive: Interrupt Virtualization Entry
eqd: Event Queue Descriptor
vpd: Virtual Processor Descriptor
It is composed of three sub-engines :
- Interrupt Virtualization Source Engine (IVSE), or Source Controller (SC). These are found in PCI PHBs, in the PSI host bridge controller, but also inside the main controller for the core IPIs and other sub-chips (NX, CAP, NPU) of the chip/processor. They are configured to feed the IVRE with events.
- Interrupt Virtualization Routing Engine (IVRE) or Virtualization Controller (VC). Its job is to match an event source with an Event Queue (EQ).
- Interrupt Virtualization Presentation Engine (IVPE) or Presentation Controller (PC). It maintains the interrupt context state of each thread and handles the delivery of the external exception to the thread.
* XIVE internal tables
Each of the sub-engines uses a set of tables to redirect exceptions from event sources to CPU threads.
+-------+
User or OS | EQ |
or +------>|entries|
Hypervisor | | .. |
Memory | +-------+
| ^
| |
+--------------------------------------------------+
| |
Hypervisor +------+ +---+--+ +---+--+ +------+
Memory | ESB | | IVT | | EQDT | | VPDT |
(skiboot) +----+-+ +----+-+ +----+-+ +------+
^ | ^ | ^ | ^
| | | | | | |
+--------------------------------------------------+
| | | | | | |
| | | | | | |
+-----|--|--------|--|--------|--|-+ +-|-----+ +------+
| | | | | | | | | | tctx| |Thread|
IPI or ----+ + v + v + v |---| + .. |-----> |
HW events | | | | | |
| IVRE | | IVPE | +------+
+----------------------------------+ +-------+The IVSE have a 2-bits, P for pending and Q for queued, state machine for each source that allows events to be triggered. They are stored in an array, the Event State Buffer (ESB) and controlled by MMIOs.
If the event is let through, the IVRE looks up in the Interrupt Virtualization Entry (IVE) table for an Event Queue Descriptor (EQD) configured for the source. Each Event Queue Descriptor defines a notification path to a CPU and an in-memory Event Queue, in which will be pushed an EQ data for the OS to pull.
The IVPE determines if a Virtual Processor (VP) can handle the event by scanning the thread contexts of the VPs dispatched on the processor HW threads. It maintains the interrupt context state of each thread in a Virtual Processor Descriptor (VPD) table.
* Overview of the QEMU models for the XIVE sub-engines
The XiveSource models the IVSE in general, internal and external. It handles the source ESBs and the MMIO interface to control them.
The XiveFabric is a small helper interface interconnecting the XiveSource to the XiveRouter.
The XiveRouter is an abstract model acting as a combined IVRE and IVPE. It routes event notifications using the IVE and EQD tables to the IVPE sub-engine which does a CAM scan to find a CPU to deliver the exception. Storage should be provided by the inheriting classes.
XiveEQSource is a special source object. It exposes the EQ ESB MMIOs of the Event Queues which are used for coalescing event notifications and for escalation. Not used on the field, only to sync the EQ cache in OPAL.
Finally, the XiveTCTX contains the interrupt state context of a thread, four sets of registers, one for each exception that can be delivered to a CPU. These contexts are scanned by the IVPE to find a matching VP when a notification is triggered. It also models the Thread Interrupt Management Area (TIMA), which exposes the thread context registers to the CPU for interrupt management.
* XIVE for sPAPR
sPAPRXive models the XIVE interrupt controller of a sPAPR machine. It inherits from the XiveRouter and provisions storage for the IVE and EQD tables. The VPD table does not need a backend in sPAPR. It owns a XiveSource object for the IPIs and the virtual device interrupts, a memory region for the TIMA and a XiveEQSource to manage the EQ ESBs. (not used by Linux).
These choices were made to have a sPAPR interrupt controller consistent with the one found on baremetal and to facilitate KVM support, the main difficulty being the host memory regions exposed to the guest.
The VP and EQ indexing needs some care and a set of helpers are defined to ease the conversion between the CPU id as seen by the guest and the identifiers manipulated by the models.
* Integration in the sPAPR machine
A new sPAPR IRQ backend is defined for XIVE. It introduces a couple of new operations to handle the differences in the creation of the device tree and in the allocation of the CPU interrupt controller. A new XIVE-only machine is defined with the XIVE backend.
Changing interrupt mode as negotiated through CAS, to switch between the XICS legacy model and XIVE, is obviously not supported. The sPAPR IRQ backend framework should make the changes easier in the future.
* KVM support
Support for KVM introduces a set of specific XIVE models, very much like XICS does, which self-connect to their KVM counterparts in the Linux kernel. Two host memory regions are exposed to the guest and need special care at initialization :
- ESB mmios
- Thread Interrupt Management Area (TIMA)
The models uses KVM accessors to synchronize the QEMU state with KVM.
Hybrid guest using KVM and an emulated irqchip (kernel_irqchip=off) is supported.
Migration is also supported but some synchronisation points are possibly needed to turn off/on XIVE and make sure all HW states are captured correctly. Stress tests will say.
* PowerNV models
The PnvXIVE model now uses the XiveRouter abstract model just like sPAPRXive does. It provides accessors to the IVE, EQD and VPD tables which are stored in the QEMU powernv machine and not in QEMU anymore. It owns a set of memory regions for the IC registers, the ESBs, the EQ ESBs, the TIMA, the notification MMIO.
Multichip is supported and the available IVSEs are the internal one for the IPIS and the PSI host bridge controller.
* GitHub trees
QEMU:
https://github.com/legoater/qemu/commits/xive-3.0
Linux/KVM (to be sent later on):
https://github.com/legoater/linux/commits/xive-4.17
Cédric Le Goater (28):
sparp_pci: simplify how the PCI LSIs are allocated
spapr: introduce a generic IRQ frontend to the machine
spapr: introduce a new IRQ backend using fixed IRQ number ranges ppc/xive: introduce a XIVE interrupt source model ppc/xive: add support for the LSI interrupt sources ppc/xive: introduce the XiveFabric interface
ppc/xive: introduce the XiveRouter model
ppc/xive: introduce the XIVE Event Queues
ppc/xive: add support for the EQ Event State buffers ppc/xive: introduce the XIVE interrupt thread context ppc/xive: introduce a simplified XIVE presenter
ppc/xive: notify the CPU when the interrupt priority is more
privileged
spapr/xive: introduce a XIVE interrupt controller spapr/xive: use the VCPU id as a VP identifier in the OS CAM.
spapr: initialize VSMT before initializing the IRQ backend
spapr: introdude a new machine IRQ backend for XIVE
spapr: add hcalls support for the XIVE exploitation interrupt mode
spapr: add device tree support for the XIVE exploitation mode
spapr: allocate the interrupt thread context under the CPU core
spapr: introduce a 'pseries-3.0-xive' QEMU machine
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: fix XICS migration
pnv: add a physical mapping array describing MMIO ranges in each chip
ppc: externalize ppc_get_vcpu_by_pir()
ppc/pnv: add XIVE support
default-configs/ppc64-softmmu.mak | 3 + hw/intc/pnv_xive_regs.h | 314 +++++++ include/hw/ppc/pnv.h | 71 +- include/hw/ppc/pnv_xive.h | 92 ++ include/hw/ppc/pnv_xscom.h | 3 + include/hw/ppc/ppc.h | 1 + include/hw/ppc/spapr.h | 31 +- include/hw/ppc/spapr_irq.h | 69 ++ include/hw/ppc/spapr_xive.h | 102 +++ include/hw/ppc/xive.h | 323 +++++++ include/hw/ppc/xive_regs.h | 182 ++++ include/migration/vmstate.h | 1 + linux-headers/asm-powerpc/kvm.h | 23 + linux-headers/linux/kvm.h | 3 + target/ppc/kvm_ppc.h | 6 + hw/intc/pnv_xive.c | 1485 ++++++++++++++++++++++++++++++ hw/intc/spapr_xive.c | 432 +++++++++ hw/intc/spapr_xive_hcall.c | 949 +++++++++++++++++++ hw/intc/spapr_xive_kvm.c | 809 +++++++++++++++++ hw/intc/xive.c | 1801 +++++++++++++++++++++++++++++++++++++ hw/ppc/pnv.c | 111 ++- hw/ppc/pnv_core.c | 28 +- hw/ppc/pnv_psi.c | 15 +- hw/ppc/pnv_xscom.c | 8 +- hw/ppc/ppc.c | 16 + hw/ppc/spapr.c | 276 ++---- hw/ppc/spapr_cpu_core.c | 4 +- hw/ppc/spapr_events.c | 8 +- hw/ppc/spapr_irq.c | 834 +++++++++++++++++ hw/ppc/spapr_pci.c | 40 +- hw/ppc/spapr_vio.c | 17 +- target/ppc/kvm.c | 7 + hw/intc/Makefile.objs | 5 +- hw/ppc/Makefile.objs | 2 +- 34 files changed, 7768 insertions(+), 303 deletions(-) create mode 100644 hw/intc/pnv_xive_regs.h create mode 100644 include/hw/ppc/pnv_xive.h create mode 100644 include/hw/ppc/spapr_irq.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 create mode 100644 hw/intc/pnv_xive.c 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 hw/ppc/spapr_irq.c
Signature · 1 line
2.13.6
PATCH v4 1/28 sparp_pci: simplify how the PCI LSIs are allocated
PCI LSIs are today allocated one by one using the IRQ alloc_block routine. Change the code sequence to first allocate a PCI_NUM_PINS block. It will help us providing a generic IRQ framework to the machine.
--- hw/ppc/spapr_pci.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
hw/ppc/spapr_pci.c +10 -11
@@ -1546,6 +1546,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)sPAPRTCETable *tcet;const unsigned windows_supported = sphb->ddw_enabled ?SPAPR_PCI_DMA_MAX_WINDOWS :1 ; +uint32_t irq; +Error *local_err =NULL ;if (!spapr) {error_setg (errp,TYPE_SPAPR_PCI_HOST_BRIDGE " needs a pseries machine" );
@@ -1694,18 +1696,15 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)QLIST_INSERT_HEAD (&spapr->phbs, sphb, list);/* Initialize the LSI table */ -for (i =0 ; i <PCI_NUM_PINS ; i++) { -uint32_t irq; -Error *local_err =NULL ; - - irq =spapr_irq_alloc_block (spapr,1 , true, false, &local_err); -if (local_err) { -error_propagate (errp, local_err); -error_prepend (errp,"can't allocate LSIs: " ); -return ; - } + irq =spapr_irq_alloc_block (spapr,PCI_NUM_PINS , true, false, &local_err); +if (local_err) { +error_propagate (errp, local_err); +error_prepend (errp,"can't allocate LSIs: " ); +return ; + } - sphb->lsi_table[i].irq = irq; +for (i =0 ; i <PCI_NUM_PINS ; i++) { + sphb->lsi_table[i].irq = irq + i; }/* allocate connectors for child PCI devices */
Signature · 1 line
2.13.6
PATCH v4 2/28 spapr: introduce a generic IRQ frontend to the machine
In reply to Cédric Le GoaterThis proposal moves all the related IRQ routines of the sPAPR machine behind a sPAPR IRQ backend interface 'spapr_irq' to prepare for future changes in the sPAPR IRQ controller modeling. First of which is a reorganization of the sPAPR IRQ number space layout and a second, coming later, will be to integrate the support for the new POWER9 XIVE IRQ controller.
The new interface defines a set of fixed IRQ number ranges, for each IRQ type, in which devices allocate the IRQ numbers they need depending on a unique device index. The layout is :
SPAPR_IRQ_IPI 0x0 /* 1 IRQ per CPU */
SPAPR_IRQ_EPOW 0x1000 /* 1 IRQ per device */
SPAPR_IRQ_HOTPLUG 0x1001 /* 1 IRQ per device */
SPAPR_IRQ_VIO 0x1100 /* 1 IRQ per device */
SPAPR_IRQ_PCI_LSI 0x1200 /* 4 IRQs per device */
SPAPR_IRQ_PCI_MSI 0x1400 /* 1K IRQs per device */The IPI range is reserved for future use when XIVE support comes in.
The 'spapr_irq' handlers encompass the previous needs and the new ones and seem complex but the provided sPAPR IRQ backend for XICS should implement what we have today without any functional changes.
Each device model is modified to take the new interface into account using the IRQ range/type definitions and a device index. A part from the VIO devices, lacking an id, the changes are relatively simple.
--- include/hw/ppc/spapr.h | 11 +- include/hw/ppc/spapr_irq.h | 50 ++++++++ hw/ppc/spapr.c | 196 +----------------------------- hw/ppc/spapr_events.c | 8 +- hw/ppc/spapr_irq.c | 291 +++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_pci.c | 21 +++- hw/ppc/spapr_vio.c | 17 ++- hw/ppc/Makefile.objs | 2 +- 8 files changed, 384 insertions(+), 212 deletions(-) create mode 100644 include/hw/ppc/spapr_irq.h create mode 100644 hw/ppc/spapr_irq.c
include/hw/ppc/spapr.h +2 -9
@@ -3,10 +3,10 @@#include "sysemu/dma.h" #include "hw/boards.h" -#include "hw/ppc/xics.h" #include "hw/ppc/spapr_drc.h" #include "hw/mem/pc-dimm.h" #include "hw/ppc/spapr_ovec.h" +#include "hw/ppc/spapr_irq.h" struct VIOsPAPRBus ;struct sPAPRPHBState ;
@@ -104,6 +104,7 @@ struct sPAPRMachineClass { unsigned n_dma, uint32_t *liobns, Error **errp);sPAPRResizeHPT resize_hpt_default;sPAPRCapabilities default_caps; +sPAPRIrq *irq; };/**
@@ -772,14 +773,6 @@ int spapr_get_vcpu_id(PowerPCCPU *cpu);void spapr_set_vcpu_id (PowerPCCPU *cpu,int cpu_index,Error **errp);PowerPCCPU *spapr_find_cpu (int vcpu_id); -int spapr_irq_alloc (sPAPRMachineState *spapr,int irq_hint,bool lsi, -Error **errp); -int spapr_irq_alloc_block (sPAPRMachineState *spapr,int num,bool lsi, -bool align,Error **errp); -void spapr_irq_free (sPAPRMachineState *spapr,int irq,int num); -qemu_irq spapr_qirq (sPAPRMachineState *spapr,int irq); - -int spapr_caps_pre_load (void *opaque);int spapr_caps_pre_save (void *opaque);
include/hw/ppc/spapr_irq.h new file +50 -0
50 lines not on this page · raw message
hw/ppc/spapr.c +4 -192
231 lines not on this page · raw message
hw/ppc/spapr_events.c +4 -4
@@ -712,8 +712,8 @@ void spapr_events_init(sPAPRMachineState *spapr) spapr->event_sources =spapr_event_sources_new ();spapr_event_sources_register (spapr->event_sources,EVENT_CLASS_EPOW , -spapr_irq_alloc (spapr,0 , false, - &error_fatal)); +spapr_irq_alloc (spapr,SPAPR_IRQ_EPOW , +0 , &error_fatal));/* NOTE: if machine supports modern/dedicated hotplug event source, * we add it to the device-tree unconditionally. This means we may
@@ -725,8 +725,8 @@ void spapr_events_init(sPAPRMachineState *spapr)*/ if (spapr->use_hotplug_event_source) {spapr_event_sources_register (spapr->event_sources,EVENT_CLASS_HOT_PLUG , -spapr_irq_alloc (spapr,0 , false, - &error_fatal)); +spapr_irq_alloc (spapr,SPAPR_IRQ_HOTPLUG , +0 , &error_fatal)); } spapr->epow_notifier.notify = spapr_powerdown_req;
hw/ppc/spapr_irq.c new file +291 -0
291 lines not on this page · raw message
hw/ppc/spapr_pci.c +16 -5
@@ -333,7 +333,12 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,return ; } -spapr_irq_free (spapr, msi->first_irq, msi->num); +spapr_irq_free (spapr, msi->first_irq, msi->num, &err); +if (err) { +error_reportf_err (err,"Can't remove MSIs for device %x: " , + config_addr); +rtas_st (rets,0 ,RTAS_OUT_HW_ERROR ); + }if (msi_present (pdev)) {spapr_msi_setmsg (pdev,0 , false,0 ,0 ); }
@@ -371,8 +376,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, }/* Allocate MSIs */ - irq =spapr_irq_alloc_block (spapr, req_num, false, - ret_intr_type ==RTAS_TYPE_MSI , &err); + irq =spapr_irq_alloc_block (spapr,SPAPR_IRQ_PCI_MSI , phb->index, req_num, + ret_intr_type ==RTAS_TYPE_MSI , &err);if (err) {error_reportf_err (err,"Can't allocate MSIs for device %x: " , config_addr);
@@ -382,7 +387,11 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,/* Release previous MSIs */ if (msi) { -spapr_irq_free (spapr, msi->first_irq, msi->num); +spapr_irq_free (spapr, msi->first_irq, msi->num, &err); +if (err) { +error_reportf_err (err,"Can't remove MSIs for device %x: " , + config_addr); + }g_hash_table_remove (phb->msi, &config_addr); }
@@ -1696,7 +1705,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)QLIST_INSERT_HEAD (&spapr->phbs, sphb, list);/* Initialize the LSI table */ - irq =spapr_irq_alloc_block (spapr,PCI_NUM_PINS , true, false, &local_err); + irq =spapr_irq_alloc_block (spapr,SPAPR_IRQ_PCI_LSI , sphb->index, +PCI_NUM_PINS , false, &local_err);if (local_err) {error_propagate (errp, local_err);error_prepend (errp,"can't allocate LSIs: " );
@@ -2112,6 +2122,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,_FDT (fdt_setprop (fdt, bus_off,"ranges" , &ranges, sizeof_ranges));_FDT (fdt_setprop (fdt, bus_off,"reg" , &bus_reg,sizeof (bus_reg)));_FDT (fdt_setprop_cell (fdt, bus_off,"ibm,pci-config-space-type" ,0x1 )); +/* TODO: fix the total count of allocatable MSIs per PHB */ _FDT (fdt_setprop_cell (fdt, bus_off,"ibm,pe-total-#msi" ,XICS_IRQS_SPAPR ));/* Dynamic DMA window */
hw/ppc/spapr_vio.c +16 -1
@@ -433,6 +433,9 @@ static void spapr_vio_busdev_reset(DeviceState *qdev) } } +/* TODO : poor VIO device indexing ... */ +static uint32_t vio_index; +static void spapr_vio_busdev_realize (DeviceState *qdev,Error **errp) {sPAPRMachineState *spapr =SPAPR_MACHINE (qdev_get_machine ());
@@ -472,7 +475,19 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq =spapr_irq_alloc (spapr, dev->irq, false, &local_err); +/* +* The "irq" property has been deprecated. IRQ assignment is soon +* to be removed +*/ +if (dev->irq) { +spapr_irq_assign (spapr,SPAPR_IRQ_VIO , dev->irq, &local_err); +if (local_err) { +error_propagate (errp, local_err); +return ; + } + } + + dev->irq =spapr_irq_alloc (spapr,SPAPR_IRQ_VIO , vio_index++, &local_err);if (local_err) {error_propagate (errp, local_err);return ;
hw/ppc/Makefile.objs +1 -1
@@ -4,7 +4,7 @@ obj-y += ppc.o ppc_booke.o fdt.o obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o -obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o +obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o spapr_irq.o # IBM PowerNV obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
Signature · 1 line
2.13.6
PATCH v4 3/28 spapr: introduce a new IRQ backend using fixed IRQ number ranges
In reply to Cédric Le GoaterThe proposed layout of the IRQ number space is organized as follow :
RANGES DEVICES
0x0000 - 0x0FFF Reserved for future use (IPI = 2)
0x1000 - 0x1000 1 EPOW 0x1001 - 0x1001 1 HOTPLUG 0x1002 - 0x10FF unused 0x1100 - 0x11FF 256 VIO devices (1 IRQ each) 0x1200 - 0x1283 32 PCI LSI devices (4 IRQs each) 0x1284 - 0x13FF unused 0x1400 - 0x17FF PCI MSI device 1 (1024 IRQs each) 0x1800 - 0x1BFF PCI MSI device 2 0x1c00 - 0x1FFF PCI MSI device 3
The MSI range is a bit more complex to handle as the IRQs are dynamically allocated by the guest OS. We use a bitmap allocator under the sPAPR IRQ backend for these.
The XICS IRQ number space is increased to 4K, which gives three MSI ranges of 1K per PHB device. If more PHB devices are needed, the total number of IRQs in the backend should be increased.
--- include/hw/ppc/spapr.h | 2 + include/hw/ppc/spapr_irq.h | 12 +++ hw/ppc/spapr.c | 22 ++++ hw/ppc/spapr_irq.c | 253 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 288 insertions(+), 1 deletion(-)
include/hw/ppc/spapr.h +2 -0
@@ -164,6 +164,8 @@ struct sPAPRMachineState {/*< public >*/ char *kvm_type; +int32_t nr_irqs; +unsigned long *irq_map;const char *icp_type;bool cmd_line_caps[SPAPR_CAP_NUM ];
include/hw/ppc/spapr_irq.h +12 -0
@@ -21,8 +21,16 @@#define SPAPR_IRQ_PCI_LSI 0x1200/* 4 IRQs per device */ #define SPAPR_IRQ_PCI_MSI 0x1400/* 1K IRQs per device covered by * a bitmap allocator */ +typedef struct sPAPRPIrqRange { +const char *name; +uint32_t offset; +uint32_t width; +uint32_t max_index; +}sPAPRPIrqRange ; + typedef struct sPAPRIrq { uint32_t nr_irqs; + const sPAPRPIrqRange *ranges; void (*init)(sPAPRMachineState *spapr, Error **errp); int (*assign)(sPAPRMachineState *spapr, uint32_t range, uint32_t irq,
@@ -36,8 +44,12 @@ typedef struct sPAPRIrq {void (*print_info)(sPAPRMachineState *spapr,Monitor *mon); } sPAPRIrq; +extern sPAPRIrq spapr_irq_legacy;extern sPAPRIrq spapr_irq_xics; +const sPAPRPIrqRange *spapr_irq_get_range (sPAPRMachineState *spapr, +uint32_t offset); +int spapr_irq_assign (sPAPRMachineState *spapr,uint32_t range,uint32_t irq,Error **errp); int spapr_irq_alloc(sPAPRMachineState *spapr, uint32_t range, uint32_t index,
hw/ppc/spapr.c +22 -0
@@ -1850,6 +1850,24 @@ static const VMStateDescription vmstate_spapr_patb_entry = { }, }; +static bool spapr_irq_map_needed (void *opaque) +{ +sPAPRMachineState *spapr = opaque; + +return spapr->irq_map && !bitmap_empty (spapr->irq_map, spapr->nr_irqs); +} + +static const VMStateDescription vmstate_spapr_irq_map = { + .name ="spapr_irq_map" , + .version_id =1 , + .minimum_version_id =1 , + .needed = spapr_irq_map_needed, + .fields = (VMStateField []) { +VMSTATE_BITMAP (irq_map, sPAPRMachineState,0 , nr_irqs), +VMSTATE_END_OF_LIST () + }, +}; +static const VMStateDescription vmstate_spapr = { .name ="spapr" , .version_id =3 ,
@@ -1877,6 +1895,7 @@ static const VMStateDescription vmstate_spapr = { &vmstate_spapr_cap_cfpc, &vmstate_spapr_cap_sbbc, &vmstate_spapr_cap_ibs, + &vmstate_spapr_irq_map, NULL } };
@@ -3913,7 +3932,10 @@ static void spapr_machine_2_12_instance_options(MachineState *machine)static void spapr_machine_2_12_class_options (MachineClass *mc) { +sPAPRMachineClass *smc =SPAPR_MACHINE_CLASS (mc); +spapr_machine_3_0_class_options (mc); + smc->irq = &spapr_irq_legacy;SET_MACHINE_COMPAT (mc,SPAPR_COMPAT_2_12 ); }
hw/ppc/spapr_irq.c +252 -1
265 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 4/28 ppc/xive: introduce a XIVE interrupt source model
In reply to Cédric Le GoaterThe first sub-engine of the overall XIVE architecture is the Interrupt Virtualization Source Engine (IVSE). An IVSE can be integrated into another logic, like in a PCI PHB or in the main interrupt controller to manage IPIs.
Each IVSE instance is associated with an Event State Buffer (ESB) that contains a two bit state entry for each possible event source. When an event is signaled to the IVSE, by MMIO or some other means, the associated interrupt state bits are fetched from the ESB and modified. Depending on the resulting ESB state, the event is forwarded to the IVRE sub-engine of the controller doing the routing.
Each supported ESB entry is associated with either a single or a even/odd pair of pages which provides commands to manage the source:
to EOI, to turn off the source for instance.
On a sPAPR machine, the OS will obtain the page address 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.
--- default-configs/ppc64-softmmu.mak | 1 + include/hw/ppc/xive.h | 130 +++++++++++++ hw/intc/xive.c | 379 ++++++++++++++++++++++++++++++++++++++ hw/intc/Makefile.objs | 1 + 4 files changed, 511 insertions(+) create mode 100644 include/hw/ppc/xive.h create mode 100644 hw/intc/xive.c
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
include/hw/ppc/xive.h new file +130 -0
130 lines not on this page · raw message
hw/intc/xive.c new file +379 -0
379 lines not on this page · raw message
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
Signature · 1 line
2.13.6
PATCH v4 5/28 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.
--- include/hw/ppc/xive.h | 20 ++++++++++++++- hw/intc/xive.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 7 deletions(-)
include/hw/ppc/xive.h +19 -1
@@ -32,8 +32,10 @@ typedef struct XiveSource {/* IRQs */ uint32_t nr_irqs;qemu_irq *qirqs; +unsigned long *lsi_map; +int32_t lsi_map_size;/* for VMSTATE_BITMAP */ -/* PQ bits */ +/* PQ bits and LSI assertion bit */ uint8_t *status;/* ESB memory region */
@@ -89,6 +91,7 @@ static inline hwaddr xive_source_esb_mgmt(XiveSource *xsrc, int srcno)* When doing an EOI, the Q bit will indicate if the interrupt * needs to be re-triggered. */ +#define XIVE_STATUS_ASSERTED 0x4/* Extra bit for LSI */ #define XIVE_ESB_VAL_P 0x2#define XIVE_ESB_VAL_Q 0x1
@@ -127,4 +130,19 @@ static inline qemu_irq xive_source_qirq(XiveSource *xsrc, uint32_t srcno) return xsrc->qirqs[srcno]; } +static inline bool xive_source_irq_is_lsi (XiveSource *xsrc,uint32_t srcno) +{ +assert (srcno < xsrc->nr_irqs); +return test_bit (srcno, xsrc->lsi_map); +} + +static inline void xive_source_irq_set (XiveSource *xsrc,uint32_t srcno, +bool lsi) +{ +assert (srcno < xsrc->nr_irqs); +if (lsi) { +bitmap_set (xsrc->lsi_map, srcno,1 ); + } +} +#endif /* PPC_XIVE_H */
hw/intc/xive.c +62 -6
117 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 6/28 ppc/xive: introduce the XiveFabric interface
In reply to Cédric Le GoaterThe XiveFabric offers a simple interface, between the XiveSource object and the main interrupt controller of the machine. It will forward event notifications to the XIVE Interrupt Virtualization Routing Engine (IVRE).
--- include/hw/ppc/xive.h | 23 +++++++++++++++++++++++ hw/intc/xive.c | 25 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+)
include/hw/ppc/xive.h +23 -0
@@ -13,6 +13,27 @@#include "hw/sysbus.h" /* +* XIVE Fabric (Interface between Source and Router) +*/ + +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 ; + +/* * XIVE Interrupt Source */
@@ -42,6 +63,8 @@ typedef struct XiveSource {uint64_t esb_flags;uint32_t esb_shift;MemoryRegion esb_mmio; + +XiveFabric *xive; } XiveSource;/*
hw/intc/xive.c +25 -0
@@ -152,7 +152,11 @@ static bool xive_source_esb_eoi(XiveSource *xsrc, uint32_t srcno)*/ 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); + } }/* In a two pages ESB MMIO setting, even page is the trigger page, odd
@@ -358,6 +362,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" );
@@ -427,9 +442,19 @@ static const TypeInfo xive_source_info = { .class_init = xive_source_class_init, }; +/* +* XIVE Fabric +*/ +static const TypeInfo xive_fabric_info = { + .name =TYPE_XIVE_FABRIC , + .parent =TYPE_INTERFACE , + .class_size =sizeof (XiveFabricClass), +}; +static void xive_register_types (void ) {type_register_static (&xive_source_info); +type_register_static (&xive_fabric_info); }type_init (xive_register_types)
Signature · 1 line
2.13.6
PATCH v4 7/28 ppc/xive: introduce the XiveRouter model
In reply to Cédric Le GoaterThe XiveRouter models the second sub-engine of the overall XIVE architecture : the Interrupt Virtualization Routing Engine (IVRE).
The IVRE handles event notifications of the IVSE through MMIO stores and performs the interrupt routing process. For this purpose, it uses a set of table stored in system memory, the first of which being the Interrupt Virtualization entries (IVE) table.
The IVT associates an interrupt source number with an Event Queue Descriptor which will be used in a second phase of the routing process to identify a notification target.
The XiveRouter is an abstract class which needs to be inherited from to define a storage for the IVT, and other upcoming tables.
--- include/hw/ppc/xive.h | 32 ++++++++++++++++++ include/hw/ppc/xive_regs.h | 30 +++++++++++++++++ hw/intc/xive.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 include/hw/ppc/xive_regs.h
include/hw/ppc/xive.h +32 -0
@@ -11,6 +11,7 @@#define PPC_XIVE_H #include "hw/sysbus.h" +#include "hw/ppc/xive_regs.h" /* * XIVE Fabric (Interface between Source and Router)
@@ -168,4 +169,35 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, } } +/* +* XIVE Router +*/ + +typedef struct XiveRouter { +SysBusDevice parent; + +uint32_t chip_id; +}XiveRouter ; + +#define TYPE_XIVE_ROUTER "xive-router" +#define XIVE_ROUTER (obj) \ + OBJECT_CHECK(XiveRouter, (obj), TYPE_XIVE_ROUTER) +#define XIVE_ROUTER_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveRouterClass, (klass), TYPE_XIVE_ROUTER) +#define XIVE_ROUTER_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveRouterClass, (obj), TYPE_XIVE_ROUTER) + +typedef struct XiveRouterClass { +SysBusDeviceClass parent; + +/* XIVE table accessors */ +int (*get_ive)(XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive); +int (*set_ive)(XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive); +}XiveRouterClass ; + +void xive_router_print_ive (XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive, +Monitor *mon); +int xive_router_get_ive (XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive); +int xive_router_set_ive (XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive); +#endif /* PPC_XIVE_H */
include/hw/ppc/xive_regs.h new file +30 -0
@@ -0,0 +1,30 @@ +/* +* 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 (Interrupt Virtualization Entry) +* +* One per interrupt source. Targets that interrupt to a given EQ +* and provides the corresponding logical interrupt number (EQ data) +*/ +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 /* _PPC_XIVE_REGS_H */
hw/intc/xive.c +84 -0
96 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 8/28 ppc/xive: introduce the XIVE Event Queues
In reply to Cédric Le GoaterThe Event Queue Descriptor (EQD) table is an internal table of the XIVE routing sub-engine, the IVRE. It specifies on which Event Queue the Event Queue data should be posted when an exception occurs (and later on pulled by the OS) and which Virtual Processor to notify.
The routing algorithm of the XiveRouter is extended to push in the system memory event queue the Event Queue data defined in the associated IVE. The event queue is a circular buffer in RAM provided by the OS, one per server and priority couple, containing Event Queue entries. These are 4 bytes long, the first bit being a 'generation' bit and the 31 following bits the EQ Data field.
The EQ Data field is a way to set an invariant logical event source number for an IRQ. It is set with the H_INT_SET_SOURCE_CONFIG hcall when the EISN flag is used.
--- include/hw/ppc/xive.h | 17 +++++ include/hw/ppc/xive_regs.h | 48 +++++++++++++ hw/intc/xive.c | 163 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 227 insertions(+), 1 deletion(-)
include/hw/ppc/xive.h +17 -0
@@ -193,11 +193,28 @@ typedef struct XiveRouterClass {/* XIVE table accessors */ int (*get_ive)(XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive);int (*set_ive)(XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive); +int (*get_eq)(XiveRouter *xrtr,uint8_t eq_blk,uint32_t eq_idx, +XiveEQ *eq); +int (*set_eq)(XiveRouter *xrtr,uint8_t eq_blk,uint32_t eq_idx, + XiveEQ *eq); } XiveRouterClass;void xive_router_print_ive (XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive,Monitor *mon);int xive_router_get_ive (XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive);int xive_router_set_ive (XiveRouter *xrtr,uint32_t lisn,XiveIVE *ive); +int xive_router_get_eq (XiveRouter *xrtr,uint8_t eq_blk,uint32_t eq_idx, +XiveEQ *eq); +int xive_router_set_eq (XiveRouter *xrtr,uint8_t eq_blk,uint32_t eq_idx, +XiveEQ *eq); + +/* +* For legacy compatibility, the exceptions define up to 256 different +* priorities. P9 implements only 9 levels : 8 active levels [0 - 7] +* and the least favored level 0xFF. +*/ +#define XIVE_PRIORITY_MAX 7 + +void xive_eq_reset (XiveEQ *eq);#endif /* PPC_XIVE_H */
include/hw/ppc/xive_regs.h +48 -0
52 lines not on this page · raw message
hw/intc/xive.c +162 -1
191 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 9/28 ppc/xive: add support for the EQ Event State buffers
In reply to Cédric Le GoaterThe Event Queue Descriptor also contains two Event State Buffers providing further coalescing of interrupts, one for the notification event (ESn) and one for the escalation events (ESe). A MMIO page is assigned for each to control the EOI through loads only. Stores are not allowed.
The EQ ESB are modeled through an object resembling the 'XiveSource' It is stateless as the EQ state bits are backed into the XiveEQ structure under the XiveRouter and the MMIO accesses follow the same rules as the standard source ESBs.
EQ ESBs are not supported by the Linux drivers neither on OPAL nor on sPAPR. Nnevetherless, it provides a mean to study the question in the future and validates a bit more the XIVE model.
--- include/hw/ppc/xive.h | 20 +++++++ hw/intc/xive.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 177 insertions(+), 2 deletions(-)
include/hw/ppc/xive.h +20 -0
@@ -209,6 +209,26 @@ int xive_router_set_eq(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, XiveEQ *eq);/* +* XIVE EQ ESBs +*/ + +#define TYPE_XIVE_EQ_SOURCE "xive-eq-source" +#define XIVE_EQ_SOURCE (obj) \ + OBJECT_CHECK(XiveEQSource, (obj), TYPE_XIVE_EQ_SOURCE) + +typedef struct XiveEQSource { +SysBusDevice parent; + +uint32_t nr_eqs; + +/* ESB memory region */ +uint32_t esb_shift; +MemoryRegion esb_mmio; + +XiveRouter *xrtr; +}XiveEQSource ; + +/* * For legacy compatibility, the exceptions define up to 256 different * priorities. P9 implements only 9 levels : 8 active levels [0 - 7] * and the least favored level 0xFF.
hw/intc/xive.c +157 -2
177 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 10/28 ppc/xive: introduce the XIVE interrupt thread context
In reply to Cédric Le GoaterThere is a XIVE presenter in each POWER9 processor that can generate four different exceptions to its threads:
- hypervisor exception,
- O/S exception
- Event-Based Branch (EBB)
- msgsnd (doorbell).
Each exception has a state independent from the others called a Thread Interrupt Management context. This context is a set of registers which let the thread 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)
These registers are accessible through a specific MMIO region, called the Thread Interrupt Management Area (TIMA), 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 thread interrupt context is modeled with a XiveTCTX object containing the values of the different exception registers. The TIMA region is mapped at the same address for each CPU.
--- include/hw/ppc/xive.h | 37 ++++ include/hw/ppc/xive_regs.h | 82 +++++++++ hw/intc/xive.c | 443 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 562 insertions(+)
include/hw/ppc/xive.h +37 -0
@@ -237,4 +237,41 @@ typedef struct XiveEQSource {void xive_eq_reset (XiveEQ *eq); + +/* +* XIVE Thread interrupt Management (TM) context +*/ + +#define TYPE_XIVE_TCTX "xive-tctx" +#define XIVE_TCTX (obj) OBJECT_CHECK(XiveTCTX, (obj), TYPE_XIVE_TCTX) + +/* +* XIVE Thread interrupt Management register rings : +* +* QW-0 User event-based exception state +* QW-1 O/S OS context for priority management, interrupt acks +* QW-2 Pool hypervisor context for virtual processor being dispatched +* QW-3 Physical for the security monitor to manage the entire context +*/ +#define TM_RING_COUNT 4 +#define TM_RING_SIZE 0x10 + +typedef struct XiveTCTX { +DeviceState parent_obj; + +CPUState *cs; +qemu_irq output; + +uint8_t regs[TM_RING_COUNT *TM_RING_SIZE ]; + +XiveRouter *xrtr; +}XiveTCTX ; + +/* +* XIVE Thread Interrupt Management Aera (TIMA) +*/ +extern const MemoryRegionOps xive_tm_ops; + +void xive_tctx_pic_print_info (XiveTCTX *tctx,Monitor *mon); +#endif /* PPC_XIVE_H */
include/hw/ppc/xive_regs.h +82 -0
88 lines not on this page · raw message
hw/intc/xive.c +443 -0
455 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 11/28 ppc/xive: introduce a simplified XIVE presenter
In reply to Cédric Le GoaterThe last sub-engine of the XIVE architecture is the Interrupt Virtualization Presentation Engine (IVPE). On HW, they share elements, the Power Bus interface (CQ), the routing table descriptors, and they can be combined in the same HW logic. We do the same in QEMU and combine both engines in the XiveRouter for simplicity.
When the IVRE has completed its job of matching an event source with a Virtual Processor (VP) target to notify, it forwards the event notification to the IVPE handling the Virtual Processor threads. The IVPE scans the thread interrupt context of the VPs dispatched on the HW processor threads and if a match is found, it signals the thread. If not, the IVRE escalates the notification to some other targets and records the notification in a backlog queue.
The IVPE maintains the thread interrupt context state for each of its VPs not dispatched on HW processor threads in the Virtual Processor Descriptor (VPD) table.
The model currently only supports single VP notifications.
--- include/hw/ppc/xive.h | 8 ++ include/hw/ppc/xive_regs.h | 22 +++++ hw/intc/xive.c | 227 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+)
include/hw/ppc/xive.h +8 -0
@@ -197,6 +197,10 @@ typedef struct XiveRouterClass { XiveEQ *eq);int (*set_eq)(XiveRouter *xrtr,uint8_t eq_blk,uint32_t eq_idx,XiveEQ *eq); +int (*get_vp)(XiveRouter *xrtr,uint8_t vp_blk,uint32_t vp_idx, +XiveVP *vp); +int (*set_vp)(XiveRouter *xrtr,uint8_t vp_blk,uint32_t vp_idx, +XiveVP *vp); } XiveRouterClass; void xive_router_print_ive(XiveRouter *xrtr, uint32_t lisn, XiveIVE *ive,
@@ -207,6 +211,10 @@ int xive_router_get_eq(XiveRouter *xrtr, uint8_t eq_blk, uint32_t eq_idx, XiveEQ *eq);int xive_router_set_eq (XiveRouter *xrtr,uint8_t eq_blk,uint32_t eq_idx,XiveEQ *eq); +int xive_router_get_vp (XiveRouter *xrtr,uint8_t vp_blk,uint32_t vp_idx, +XiveVP *vp); +int xive_router_set_vp (XiveRouter *xrtr,uint8_t vp_blk,uint32_t vp_idx, +XiveVP *vp);/* * XIVE EQ ESBs
include/hw/ppc/xive_regs.h +22 -0
@@ -157,4 +157,26 @@ typedef struct XiveEQ {#define EQ_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1, 31) } XiveEQ; +/* VP */ +typedef struct XiveVP { +uint32_t w0; +#define VP_W0_VALID PPC_BIT32(0) +uint32_t w1; +uint32_t w2; +uint32_t w3; +uint32_t w4; +uint32_t w5; +uint32_t w6; +uint32_t w7; +uint32_t w8; +#define VP_W8_GRP_VALID PPC_BIT32(0) +uint32_t w9; +uint32_t wa; +uint32_t wb; +uint32_t wc; +uint32_t wd; +uint32_t we; +uint32_t wf; +}XiveVP ; +#endif /* _PPC_XIVE_REGS_H */
hw/intc/xive.c +227 -0
245 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 12/28 ppc/xive: notify the CPU when the interrupt priority is more privileged
In reply to Cédric Le GoaterAfter the event was pushed in the Xive EQ, the IVPE raises the bit corresponding to the priority of the pending interrupt in the register IBP (Interrupt Pending Buffer) to indicate there is an event pending in one of the 8 priority queues. The Pending Interrupt Priority Register (PIPR) is also updated using the IPB. This register represent the priority of the most favored pending notification.
The PIPR is then compared to the the Current Processor Priority Register (CPPR). If it is more favored (numerically less than), the CPU interrupt line is raised and the EO bit of the Notification Source Register (NSR) is updated to notify the presence of an exception for the O/S. The check needs to be done whenever the PIPR or the CPPR are changed.
The O/S acknowledges the interrupt with a special load in the Thread Interrupt Management Area. If the EO bit of the NSR is set, the CPPR takes the value of PIPR. The bit number in the IBP corresponding to the priority of the pending interrupt is reseted and so is the EO bit of the NSR.
--- hw/intc/xive.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-)
hw/intc/xive.c +93 -1
@@ -21,9 +21,73 @@* XIVE Thread Interrupt Management context */ +/* Convert a priority number to an Interrupt Pending Buffer (IPB) +* register, which indicates a pending interrupt at the priority +* corresponding to the bit number +*/ +static uint8_t priority_to_ipb (uint8_t priority) +{ +return priority >XIVE_PRIORITY_MAX ? +0 :1 << (XIVE_PRIORITY_MAX - priority); +} + +/* Convert an Interrupt Pending Buffer (IPB) register to a Pending +* Interrupt Priority Register (PIPR), which contains the priority of +* the most favored pending notification. +*/ +static uint8_t ipb_to_pipr (uint8_t ibp) +{ +return ibp ?clz32 ((uint32_t )ibp <<24 ) :0xff ; +} + +static void ipb_update (uint8_t *regs,uint8_t priority) +{ + regs[TM_IPB ] |=priority_to_ipb (priority); + regs[TM_PIPR ] =ipb_to_pipr (regs[TM_IPB ]); +} + +static uint8_t exception_mask (uint8_t ring) +{ +switch (ring) { +case TM_QW1_OS : +return TM_QW1_NSR_EO ; +default : +g_assert_not_reached (); + } +} +static uint64_t xive_tctx_accept (XiveTCTX *tctx,uint8_t ring) { -return 0 ; +uint8_t *regs = &tctx->regs[ring]; +uint8_t nsr = regs[TM_NSR ]; +uint8_t mask =exception_mask (ring); + +qemu_irq_lower (tctx->output); + +if (regs[TM_NSR ] & mask) { +uint8_t cppr = regs[TM_PIPR ]; + + regs[TM_CPPR ] = cppr; + +/* Reset the pending buffer bit */ + regs[TM_IPB ] &= ~priority_to_ipb (cppr); + regs[TM_PIPR ] =ipb_to_pipr (regs[TM_IPB ]); + +/* Drop Exception bit */ + regs[TM_NSR ] &= ~mask; + } + +return (nsr <<8 ) | regs[TM_CPPR ]; +} + +static void xive_tctx_notify (XiveTCTX *tctx,uint8_t ring) +{ +uint8_t *regs = &tctx->regs[ring]; + +if (regs[TM_PIPR ] < regs[TM_CPPR ]) { + regs[TM_NSR ] |=exception_mask (ring); +qemu_irq_raise (tctx->output); + } }static void xive_tctx_set_cppr (XiveTCTX *tctx,uint8_t ring,uint8_t cppr)
@@ -33,6 +97,9 @@ static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr) } tctx->regs[ring +TM_CPPR ] = cppr; + +/* CPPR has changed, check if we need to raise a pending exception */ +xive_tctx_notify (tctx, ring); }/*
@@ -199,6 +266,17 @@ static void xive_tm_set_os_cppr(XiveTCTX *tctx, hwaddr offset, }/* +* Adjust the IPB to allow a CPU to process event queues of other +* priorities during one physical interrupt cycle. +*/ +static void xive_tm_set_os_pending (XiveTCTX *tctx,hwaddr offset, +uint64_t value,unsigned size) +{ +ipb_update (&tctx->regs[TM_QW1_OS ], value &0xff ); +xive_tctx_notify (tctx,TM_QW1_OS ); +} + +/* * Define a mapping of "special" operations depending on the TIMA page * offset and the size of the operation. */
@@ -220,6 +298,7 @@ static const XiveTmOp xive_tm_operations[] = {/* MMIOs above 2K : special operations with side effects */ { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg }, + { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL }, };static const XiveTmOp *xive_tm_find_op (hwaddr offset,unsigned size,bool write)
@@ -414,6 +493,13 @@ static void xive_tctx_reset(void *dev) tctx->regs[TM_QW1_OS +TM_LSMFB ] =0xFF ; tctx->regs[TM_QW1_OS +TM_ACK_CNT ] =0xFF ; tctx->regs[TM_QW1_OS +TM_AGE ] =0xFF ; + +/* +* Initialize PIPR to 0xFF to avoid phantom interrupts when the +* CPPR is first set. +*/ + tctx->regs[TM_QW1_OS +TM_PIPR ] = +ipb_to_pipr (tctx->regs[TM_QW1_OS +TM_IPB ]); }static void xive_tctx_realize (DeviceState *dev,Error **errp)
@@ -1185,9 +1271,15 @@ static void xive_presenter_notify(XiveRouter *xrtr, uint8_t format, found =xive_presenter_match (xrtr, format, vp_blk, vp_idx, cam_ignore, priority, logic_serv, &match);if (found) { +ipb_update (&match.tctx->regs[match.ring], priority); +xive_tctx_notify (match.tctx, match.ring);return ; } +/* Record the IPB in the associated VP */ +ipb_update ((uint8_t *) &vp.w4, priority); +xive_router_set_vp (xrtr, vp_blk, vp_idx, &vp); +/* If no VP dispatched on a HW thread : * - update the VP if backlog is activated * - escalate (ESe PQ bits and IVE in w4-5) if escalation is
Signature · 1 line
2.13.6
PATCH v4 13/28 spapr/xive: introduce a XIVE interrupt controller
In reply to Cédric Le GoatersPAPRXive models the XIVE interrupt controller of the sPAPR machine. It inherits from the XiveRouter and provisions storage for the routing tables :
- Interrupt Virtualization Entries (IVE)
- Event Queue Descriptor (EQD)
sPAPRXive incorporates an internal XiveSource for the IPIs and the virtual device interrupts of the guest. This model is consistent with XIVE architecture which also incorporates an internal IVSE for IPIs and accelerator interrupts in the IVRE sub-engine.
sPAPRXive exports two memory regions, one for the ESB trigger and management pages used to control the sources and one for the TIMA pages. They are mapped by default at the addresses found on chip 0 of a real system. This is consistent with the XIVE architecture which defines a Virtualization Controller BAR for the internal IVSE ESB pages and a Thread Managment BAR for the TIMA.
--- default-configs/ppc64-softmmu.mak | 1 + include/hw/ppc/spapr_xive.h | 46 ++++++ hw/intc/spapr_xive.c | 308 ++++++++++++++++++++++++++++++++++++++ hw/intc/Makefile.objs | 1 + 4 files changed, 356 insertions(+) create mode 100644 include/hw/ppc/spapr_xive.h create mode 100644 hw/intc/spapr_xive.c
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
include/hw/ppc/spapr_xive.h new file +46 -0
46 lines not on this page · raw message
hw/intc/spapr_xive.c new file +308 -0
308 lines not on this page · raw message
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
Signature · 1 line
2.13.6
PATCH v4 14/28 spapr/xive: use the VCPU id as a VP identifier in the OS CAM.
In reply to Cédric Le GoaterFor the IVPE to find a matching VP among the VPs dispatched on the physical processor threads, the model needs to update the OS CAM line of the XIVE thread interrupt context with the VP identifier.
The model uses the VCPU id as the VP identifier for the sPAPR and provide a set of helpers to do the conversion between identifiers. EQ ids are also derived from the VCPU id.
sPAPRXive does not provision storage for a VPD table but the XiveRouter handlers provide some extra checks to the routing algorithm.
--- include/hw/ppc/spapr_xive.h | 15 +++++++++ hw/intc/spapr_xive.c | 80 +++++++++++++++++++++++++++++++++++++++++++++ hw/intc/xive.c | 12 +++++++ 3 files changed, 107 insertions(+)
include/hw/ppc/spapr_xive.h +15 -0
@@ -43,4 +43,19 @@ bool spapr_xive_irq_disable(sPAPRXive *xive, uint32_t lisn);void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon);qemu_irq spapr_xive_qirq (sPAPRXive *xive,uint32_t lisn); +/* +* sPAPR VP and EQ indexing helpers +*/ +static inline uint32_t spapr_xive_vp_to_target (sPAPRXive *xive,uint8_t vp_blk, +uint32_t vp_idx) +{ +return vp_idx; +} +int spapr_xive_target_to_vp (XiveRouter *xrtr,uint32_t target, +uint8_t *out_vp_blk,uint32_t *out_vp_idx); +int spapr_xive_target_to_eq (XiveRouter *xrtr,uint32_t target,uint8_t prio, +uint8_t *out_eq_blk,uint32_t *out_eq_idx); +int spapr_xive_cpu_to_eq (XiveRouter *xrtr,PowerPCCPU *cpu,uint8_t prio, +uint8_t *out_eq_blk,uint32_t *out_eq_idx); +#endif /* PPC_SPAPR_XIVE_H */
hw/intc/spapr_xive.c +80 -0
92 lines not on this page · raw message
hw/intc/xive.c +12 -0
@@ -486,6 +486,8 @@ static uint32_t xive_tctx_hw_cam(XiveTCTX *tctx, bool block_group)static void xive_tctx_reset (void *dev) {XiveTCTX *tctx =XIVE_TCTX (dev); +PowerPCCPU *cpu =POWERPC_CPU (tctx->cs); +CPUPPCState *env = &cpu->env;memset (tctx->regs,0 ,sizeof (tctx->regs));
@@ -500,6 +502,16 @@ static void xive_tctx_reset(void *dev)*/ tctx->regs[TM_QW1_OS +TM_PIPR ] =ipb_to_pipr (tctx->regs[TM_QW1_OS +TM_IPB ]); + +/* The OS CAM is pushed by the hypervisor when the VP is scheduled +* to run on a HW thread. On QEMU, when running a pseries machine, +* hardwire the VCPU id as this is our VP identifier. +*/ +if (!msr_hv) { +uint32_t os_cam =cpu_to_be32 ( +TM_QW1W2_VO |tctx_cam_line (tctx->xrtr->chip_id, cpu->vcpu_id)); +memcpy (&tctx->regs[TM_QW1_OS +TM_WORD2 ], &os_cam,4 ); + } }static void xive_tctx_realize (DeviceState *dev,Error **errp)
Signature · 1 line
2.13.6
PATCH v4 15/28 spapr: initialize VSMT before initializing the IRQ backend
In reply to Cédric Le GoaterWe will need to use xics_max_server_number() to create the sPAPRXive object modeling the interrupt controller of the machine which is created before the CPUs.
--- hw/ppc/spapr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
hw/ppc/spapr.c +5 -5
@@ -2423,11 +2423,6 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) boot_cores_nr = possible_cpus->len; } -/* VSMT must be set in order to be able to compute VCPU ids, ie to -* call xics_max_server_number() or spapr_vcpu_id(). -*/ -spapr_set_vsmt_mode (spapr, &error_fatal); -if (smc->pre_2_10_has_unused_icps) {int i;
@@ -2547,6 +2542,11 @@ static void spapr_machine_init(MachineState *machine)/* Setup a load limit for the ramdisk leaving room for SLOF and FDT */ load_limit =MIN (spapr->rma_size,RTAS_MAX_ADDR ) -FW_OVERHEAD ; +/* VSMT must be set in order to be able to compute VCPU ids, ie to +* call xics_max_server_number() or spapr_vcpu_id(). +*/ +spapr_set_vsmt_mode (spapr, &error_fatal); +/* Set up Interrupt Controller before we create the VCPUs */ smc->irq->init (spapr, &error_fatal);
Signature · 1 line
2.13.6
PATCH v4 16/28 spapr: introdude a new machine IRQ backend for XIVE
In reply to Cédric Le GoaterThe XIVE IRQ backend uses the same layout as the new XICS backend but covers the full range of the IRQ number space. The IRQ numbers for the CPU IPIs are allocated at the bottom of this space, below 4K, to preserve compatibility with XICS which does not use that range.
This should be enough given that the maximum number of CPUs is 1024 for the sPAPR machine under QEMU. For the record, the biggest POWER8 or POWER9 system has a maximum of 1536 HW threads (16 sockets, 192 cores, SMT8).
--- include/hw/ppc/spapr.h | 2 + include/hw/ppc/spapr_irq.h | 3 +- hw/ppc/spapr.c | 3 +- hw/ppc/spapr_irq.c | 212 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 215 insertions(+), 5 deletions(-)
include/hw/ppc/spapr.h +2 -0
@@ -14,6 +14,7 @@ struct sPAPRNVRAM;typedef struct sPAPREventLogEntry sPAPREventLogEntry ;typedef struct sPAPREventSource sPAPREventSource ;typedef struct sPAPRPendingHPT sPAPRPendingHPT ; +typedef struct sPAPRXive sPAPRXive ;#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL#define SPAPR_ENTRY_POINT 0x100
@@ -167,6 +168,7 @@ struct sPAPRMachineState {int32_t nr_irqs;unsigned long *irq_map;const char *icp_type; +sPAPRXive *xive;bool cmd_line_caps[SPAPR_CAP_NUM ];sPAPRCapabilities def, eff, mig;
include/hw/ppc/spapr_irq.h +2 -1
@@ -32,7 +32,7 @@ typedef struct sPAPRIrq {uint32_t nr_irqs;const sPAPRPIrqRange *ranges; -void (*init)(sPAPRMachineState *spapr,Error **errp); +void (*init)(sPAPRMachineState *spapr,uint32_t nr_servers,Error **errp);int (*assign)(sPAPRMachineState *spapr,uint32_t range,uint32_t irq,Error **errp); int (*alloc)(sPAPRMachineState *spapr, uint32_t range, uint32_t index,
@@ -46,6 +46,7 @@ typedef struct sPAPRIrq {extern sPAPRIrq spapr_irq_legacy;extern sPAPRIrq spapr_irq_xics; +extern sPAPRIrq spapr_irq_xive;const sPAPRPIrqRange *spapr_irq_get_range (sPAPRMachineState *spapr,uint32_t offset);
hw/ppc/spapr.c +2 -1
@@ -55,6 +55,7 @@#include "hw/ppc/spapr_vio.h" #include "hw/pci-host/spapr.h" #include "hw/ppc/xics.h" +#include "hw/ppc/spapr_xive.h" #include "hw/pci/msi.h" #include "hw/pci/pci.h"
@@ -2548,7 +2549,7 @@ static void spapr_machine_init(MachineState *machine)spapr_set_vsmt_mode (spapr, &error_fatal);/* Set up Interrupt Controller before we create the VCPUs */ - smc->irq->init (spapr, &error_fatal); + smc->irq->init (spapr,xics_max_server_number (spapr), &error_fatal);/* Set up containers for ibm,client-architecture-support negotiated options */
hw/ppc/spapr_irq.c +209 -3
243 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 17/28 spapr: add hcalls support for the XIVE exploitation interrupt mode
In reply to Cédric Le GoaterThe different XIVE virtualization engines (sources and event queues) are configured with a set of Hypervisor calls :
- H_INT_GET_SOURCE_INFO
used to obtain the address of the MMIO page of the Event State Buffer (PQ bits) entry associated with the source.
- H_INT_SET_SOURCE_CONFIG
assigns a source to a "target".
- H_INT_GET_SOURCE_CONFIG
determines which "target" and "priority" is assigned to a source
- H_INT_GET_QUEUE_INFO
returns the address of the notification management page associated with the specified "target" and "priority".
- H_INT_SET_QUEUE_CONFIG
sets or resets the event queue for a given "target" and "priority". It is also used to set the notification configuration associated with the queue, only unconditional notification is supported for the moment. Reset is performed with a queue size of 0 and queueing is disabled in that case.
- H_INT_GET_QUEUE_CONFIG
returns the queue settings for a given "target" and "priority".
- H_INT_RESET
resets all of the guest's internal interrupt structures to their initial state, losing all configuration set via the hcalls H_INT_SET_SOURCE_CONFIG and H_INT_SET_QUEUE_CONFIG.
- H_INT_SYNC
issue a synchronisation on a source to make sure all notifications have reached their queue.
Calls that still need to be addressed :
H_INT_SET_OS_REPORTING_LINE
H_INT_GET_OS_REPORTING_LINE
See the code for more documentation on each hcall.
--- include/hw/ppc/spapr.h | 15 +- include/hw/ppc/spapr_xive.h | 5 + hw/intc/spapr_xive_hcall.c | 887 ++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_irq.c | 2 + hw/intc/Makefile.objs | 2 +- 5 files changed, 909 insertions(+), 2 deletions(-) create mode 100644 hw/intc/spapr_xive_hcall.c
include/hw/ppc/spapr.h +14 -1
@@ -444,7 +444,20 @@ struct sPAPRMachineState {#define H_INVALIDATE_PID 0x378#define H_REGISTER_PROC_TBL 0x37C#define H_SIGNAL_SYS_RESET 0x380 -#define MAX_HCALL_OPCODE H_SIGNAL_SYS_RESET + +#define H_INT_GET_SOURCE_INFO 0x3A8 +#define H_INT_SET_SOURCE_CONFIG 0x3AC +#define H_INT_GET_SOURCE_CONFIG 0x3B0 +#define H_INT_GET_QUEUE_INFO 0x3B4 +#define H_INT_SET_QUEUE_CONFIG 0x3B8 +#define H_INT_GET_QUEUE_CONFIG 0x3BC +#define H_INT_SET_OS_REPORTING_LINE 0x3C0 +#define H_INT_GET_OS_REPORTING_LINE 0x3C4 +#define H_INT_ESB 0x3C8 +#define H_INT_SYNC 0x3CC +#define H_INT_RESET 0x3D0 + +#define MAX_HCALL_OPCODE H_INT_RESET/* The hcalls above are standardized in PAPR and implemented by pHyp * as well.
include/hw/ppc/spapr_xive.h +5 -0
@@ -57,5 +57,10 @@ int spapr_xive_target_to_eq(XiveRouter *xrtr, uint32_t target, uint8_t prio, uint8_t *out_eq_blk, uint32_t *out_eq_idx);int spapr_xive_cpu_to_eq (XiveRouter *xrtr,PowerPCCPU *cpu,uint8_t prio,uint8_t *out_eq_blk,uint32_t *out_eq_idx); +bool spapr_xive_eq_is_valid (uint8_t priority); + +typedef struct sPAPRMachineState sPAPRMachineState ; + +void spapr_xive_hcall_init (sPAPRMachineState *spapr);#endif /* PPC_SPAPR_XIVE_H */
hw/intc/spapr_xive_hcall.c new file +887 -0
887 lines not on this page · raw message
hw/ppc/spapr_irq.c +2 -0
@@ -564,6 +564,8 @@ static void spapr_irq_init_xive(sPAPRMachineState *spapr, uint32_t nr_servers,for (i =0 ; i < nr_servers; ++i) {spapr_irq_alloc (spapr,SPAPR_IRQ_IPI , i, errp); } + +spapr_xive_hcall_init (spapr); }/*
hw/intc/Makefile.objs +1 -1
@@ -38,7 +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_XIVE_SPAPR) += spapr_xive.o spapr_xive_hcall.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o
Signature · 1 line
2.13.6
PATCH v4 18/28 spapr: add device tree support for the XIVE exploitation mode
In reply to Cédric Le GoaterThe XIVE interface for the guest is described in the device tree under the "interrupt-controller" node. A couple of new properties are specific to XIVE :
- "reg"
contains the base address and size of the thread interrupt managnement areas (TIMA), also called rings, for the User level and for the Guest OS level. Only the Guest OS level is taken into account today.
- "ibm,xive-eq-sizes"
the size of the event queues. One cell per size supported, contains log2 of size, in ascending order.
- "ibm,xive-lisn-ranges"
the IRQ interrupt number ranges assigned to the guest for the IPIs.
and also under the root node :
- "ibm,plat-res-int-priorities"
contains a list of priorities that the hypervisor has reserved for its own use. OPAL uses the priority 7 queue to automatically escalate interrupts for all other queues (DD2.X POWER9). So only priorities [0..6] are allowed for the guest.
Extend the sPAPR IRQ backend with a new handler to populate the DT with the appropriate "interrupt-controller" node.
--- include/hw/ppc/spapr_irq.h | 2 ++ include/hw/ppc/spapr_xive.h | 2 ++ hw/intc/spapr_xive_hcall.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr.c | 3 ++- hw/ppc/spapr_irq.c | 25 ++++++++++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-)
include/hw/ppc/spapr_irq.h +2 -0
@@ -42,6 +42,8 @@ typedef struct sPAPRIrq {void (*free)(sPAPRMachineState *spapr,int irq,int num,Error **errp);qemu_irq (*qirq)(sPAPRMachineState *spapr,int irq);void (*print_info)(sPAPRMachineState *spapr,Monitor *mon); +void (*dt_populate)(sPAPRMachineState *spapr,uint32_t nr_servers, +void *fdt,uint32_t phandle); } sPAPRIrq;extern sPAPRIrq spapr_irq_legacy;
include/hw/ppc/spapr_xive.h +2 -0
@@ -62,5 +62,7 @@ bool spapr_xive_eq_is_valid(uint8_t priority);typedef struct sPAPRMachineState sPAPRMachineState ;void spapr_xive_hcall_init (sPAPRMachineState *spapr); +void spapr_dt_xive (sPAPRXive *xive,int nr_servers,void *fdt, +uint32_t phandle);#endif /* PPC_SPAPR_XIVE_H */
hw/intc/spapr_xive_hcall.c +62 -0
65 lines not on this page · raw message
hw/ppc/spapr.c +2 -1
@@ -1233,7 +1233,8 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,_FDT (fdt_setprop_cell (fdt,0 ,"#size-cells" ,2 ));/* /interrupt controller */ -spapr_dt_xics (xics_max_server_number (spapr), fdt,PHANDLE_XICP ); + smc->irq->dt_populate (spapr,xics_max_server_number (spapr), fdt, +PHANDLE_XICP ); ret =spapr_populate_memory (spapr, fdt);if (ret <0 ) {
hw/ppc/spapr_irq.c +25 -0
@@ -240,6 +240,14 @@ static void spapr_irq_print_info_legacy(sPAPRMachineState *spapr,ics_pic_print_info (spapr->ics, mon); } + +static void spapr_irq_dt_populate_legacy (sPAPRMachineState *spapr, +uint32_t nr_servers,void *fdt, +uint32_t phandle) +{ +spapr_dt_xics (nr_servers, fdt, phandle); +} +sPAPRIrq spapr_irq_legacy = { .nr_irqs =XICS_IRQS_SPAPR , .init = spapr_irq_init_legacy,
@@ -249,6 +257,7 @@ sPAPRIrq spapr_irq_legacy = { .free = spapr_irq_free_legacy, .qirq = spapr_qirq_legacy, .print_info = spapr_irq_print_info_legacy, + .dt_populate = spapr_irq_dt_populate_legacy, };/*
@@ -457,6 +466,13 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr,spapr_irq_print_info_legacy (spapr, mon); } +static void spapr_irq_dt_populate_xics (sPAPRMachineState *spapr, +uint32_t nr_servers,void *fdt, +uint32_t phandle) +{ +spapr_irq_dt_populate_legacy (spapr, nr_servers, fdt, phandle); +} +/* * XICS IRQ number space *
@@ -501,6 +517,7 @@ sPAPRIrq spapr_irq_xics = { .free = spapr_irq_free_xics, .qirq = spapr_qirq_xics, .print_info = spapr_irq_print_info_xics, + .dt_populate = spapr_irq_dt_populate_xics, };/*
@@ -659,6 +676,13 @@ static void spapr_irq_print_info_xive(sPAPRMachineState *spapr,spapr_xive_pic_print_info (spapr->xive, mon); } +static void spapr_irq_dt_populate_xive (sPAPRMachineState *spapr, +uint32_t nr_servers,void *fdt, +uint32_t phandle) +{ +spapr_dt_xive (spapr->xive, nr_servers, fdt, phandle); +} +/* * XIVE IRQ number space *
@@ -705,6 +729,7 @@ sPAPRIrq spapr_irq_xive = { .free = spapr_irq_free_xive, .qirq = spapr_qirq_xive, .print_info = spapr_irq_print_info_xive, + .dt_populate = spapr_irq_dt_populate_xive, };/*
Signature · 1 line
2.13.6
PATCH v4 19/28 spapr: allocate the interrupt thread context under the CPU core
In reply to Cédric Le GoaterEach interrupt mode has its own specific interrupt presenter object, that we store under the CPU object, one for XICS and one for XIVE.
Extend the sPAPR IRQ backend with a new handler to support them both.
--- include/hw/ppc/spapr.h | 1 + include/hw/ppc/spapr_irq.h | 2 ++ include/hw/ppc/xive.h | 2 ++ hw/intc/xive.c | 21 +++++++++++++++++++++ hw/ppc/spapr_cpu_core.c | 4 ++-- hw/ppc/spapr_irq.c | 23 +++++++++++++++++++++++ 6 files changed, 51 insertions(+), 2 deletions(-)
include/hw/ppc/spapr.h +1 -0
@@ -169,6 +169,7 @@ struct sPAPRMachineState {unsigned long *irq_map;const char *icp_type;sPAPRXive *xive; +const char *xive_tctx_type;bool cmd_line_caps[SPAPR_CAP_NUM ];sPAPRCapabilities def, eff, mig;
include/hw/ppc/spapr_irq.h +2 -0
@@ -44,6 +44,8 @@ typedef struct sPAPRIrq {void (*print_info)(sPAPRMachineState *spapr,Monitor *mon);void (*dt_populate)(sPAPRMachineState *spapr,uint32_t nr_servers,void *fdt,uint32_t phandle); + Object *(*cpu_intc_create)(sPAPRMachineState *spapr, Object *cpu, + Error **errp); } sPAPRIrq;extern sPAPRIrq spapr_irq_legacy;
include/hw/ppc/xive.h +2 -0
@@ -281,5 +281,7 @@ typedef struct XiveTCTX {extern const MemoryRegionOps xive_tm_ops;void xive_tctx_pic_print_info (XiveTCTX *tctx,Monitor *mon); +Object *xive_tctx_create (Object *cpu,const char *type,XiveRouter *xrtr, +Error **errp);#endif /* PPC_XIVE_H */
hw/intc/xive.c +21 -0
@@ -587,6 +587,27 @@ static const TypeInfo xive_tctx_info = { .class_init = xive_tctx_class_init, }; +Object *xive_tctx_create (Object *cpu,const char *type,XiveRouter *xrtr, +Error **errp) +{ +Error *local_err =NULL ; +Object *obj; + + obj =object_new (type); +object_property_add_child (cpu, type, obj, &error_abort); +object_unref (obj); +object_property_add_const_link (obj,"cpu" , cpu, &error_abort); +object_property_add_const_link (obj,"xive" ,OBJECT (xrtr), &error_abort); +object_property_set_bool (obj, true,"realized" , &local_err); +if (local_err) { +object_unparent (obj); +error_propagate (errp, local_err); +return NULL ; + } + +return obj; +} +/* * XIVE ESB helpers */
hw/ppc/spapr_cpu_core.c +2 -2
@@ -148,6 +148,7 @@ static void spapr_cpu_core_realize_child(Object *child,Error *local_err =NULL ;CPUState *cs =CPU (child);PowerPCCPU *cpu =POWERPC_CPU (cs); +sPAPRMachineClass *smc =SPAPR_MACHINE_GET_CLASS (spapr);object_property_set_bool (child, true,"realized" , &local_err);if (local_err) {
@@ -159,8 +160,7 @@ static void spapr_cpu_core_realize_child(Object *child, goto error; } - cpu->intc =icp_create (child, spapr->icp_type,XICS_FABRIC (spapr), - &local_err); + cpu->intc = smc->irq->cpu_intc_create (spapr, child, &local_err);if (local_err) { goto error; }
hw/ppc/spapr_irq.c +23 -0
@@ -248,6 +248,12 @@ static void spapr_irq_dt_populate_legacy(sPAPRMachineState *spapr,spapr_dt_xics (nr_servers, fdt, phandle); } +static Object *spapr_irq_cpu_intc_create_legacy (sPAPRMachineState *spapr, +Object *cpu,Error **errp) +{ +return icp_create (cpu, spapr->icp_type,XICS_FABRIC (spapr), errp); +} +sPAPRIrq spapr_irq_legacy = { .nr_irqs =XICS_IRQS_SPAPR , .init = spapr_irq_init_legacy,
@@ -258,6 +264,7 @@ sPAPRIrq spapr_irq_legacy = { .qirq = spapr_qirq_legacy, .print_info = spapr_irq_print_info_legacy, .dt_populate = spapr_irq_dt_populate_legacy, + .cpu_intc_create = spapr_irq_cpu_intc_create_legacy, };/*
@@ -473,6 +480,12 @@ static void spapr_irq_dt_populate_xics(sPAPRMachineState *spapr,spapr_irq_dt_populate_legacy (spapr, nr_servers, fdt, phandle); } +static Object *spapr_irq_cpu_intc_create_xics (sPAPRMachineState *spapr, +Object *cpu,Error **errp) +{ +return spapr_irq_cpu_intc_create_legacy (spapr, cpu, errp); +} +/* * XICS IRQ number space *
@@ -518,6 +531,7 @@ sPAPRIrq spapr_irq_xics = { .qirq = spapr_qirq_xics, .print_info = spapr_irq_print_info_xics, .dt_populate = spapr_irq_dt_populate_xics, + .cpu_intc_create = spapr_irq_cpu_intc_create_xics, };/*
@@ -582,6 +596,7 @@ static void spapr_irq_init_xive(sPAPRMachineState *spapr, uint32_t nr_servers,spapr_irq_alloc (spapr,SPAPR_IRQ_IPI , i, errp); } + spapr->xive_tctx_type =TYPE_XIVE_TCTX ;spapr_xive_hcall_init (spapr); }
@@ -683,6 +698,13 @@ static void spapr_irq_dt_populate_xive(sPAPRMachineState *spapr,spapr_dt_xive (spapr->xive, nr_servers, fdt, phandle); } +static Object *spapr_irq_cpu_intc_create_xive (sPAPRMachineState *spapr, +Object *cpu,Error **errp) +{ +return xive_tctx_create (cpu, spapr->xive_tctx_type, +XIVE_ROUTER (spapr->xive), errp); +} +/* * XIVE IRQ number space *
@@ -730,6 +752,7 @@ sPAPRIrq spapr_irq_xive = { .qirq = spapr_qirq_xive, .print_info = spapr_irq_print_info_xive, .dt_populate = spapr_irq_dt_populate_xive, + .cpu_intc_create = spapr_irq_cpu_intc_create_xive, };/*
Signature · 1 line
2.13.6
PATCH v4 20/28 spapr: introduce a 'pseries-3.0-xive' QEMU machine
In reply to Cédric Le GoaterThe interrupt mode is statically defined to XIVE only for this machine. The guest OS is required to have support for the XIVE exploitation mode of the POWER9 interrupt controller.
--- include/hw/ppc/spapr_irq.h | 1 + hw/ppc/spapr.c | 35 ++++++++++++++++++++++++++++++----- hw/ppc/spapr_irq.c | 3 +++ 3 files changed, 34 insertions(+), 5 deletions(-)
include/hw/ppc/spapr_irq.h +1 -0
@@ -31,6 +31,7 @@ typedef struct sPAPRPIrqRange { typedef struct sPAPRIrq { uint32_t nr_irqs; const sPAPRPIrqRange *ranges; + uint8_t ov5; void (*init)(sPAPRMachineState *spapr, uint32_t nr_servers, Error **errp); int (*assign)(sPAPRMachineState *spapr, uint32_t range, uint32_t irq,
hw/ppc/spapr.c +30 -5
@@ -1060,12 +1060,14 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)spapr_dt_rtas_tokens (fdt, rtas); } -/* Prepare ibm,arch-vec-5-platform-support, which indicates the MMU features -* that the guest may request and thus the valid values for bytes 24..26 of -* option vector 5: */ -static void spapr_dt_ov5_platform_support (void *fdt,int chosen) +/* Prepare ibm,arch-vec-5-platform-support, which indicates the MMU +* and the XIVE features that the guest may request and thus the valid +* values for bytes 23..26 of option vector 5: */ +static void spapr_dt_ov5_platform_support (sPAPRMachineState *spapr,void *fdt, +int chosen) {PowerPCCPU *first_ppc_cpu =POWERPC_CPU (first_cpu); +sPAPRMachineClass *smc =SPAPR_MACHINE_GET_CLASS (spapr);char val[2 *4 ] = {23 ,0x00 ,/* Xive mode, filled in below. */
@@ -1086,7 +1088,10 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen) }else { val[3 ] =0x00 ;/* Hash */ } + val[1 ] = smc->irq->ov5; }else { + val[1 ] = smc->irq->ov5; +/* V3 MMU supports both hash and radix in tcg (with dynamic switching) */ val[3 ] =0xC0 ; }
@@ -1154,7 +1159,7 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)_FDT (fdt_setprop_string (fdt, chosen,"stdout-path" , stdout_path)); } -spapr_dt_ov5_platform_support (fdt, chosen); +spapr_dt_ov5_platform_support (spapr, fdt, chosen);g_free (stdout_path);g_free (bootlist);
@@ -2577,6 +2582,11 @@ static void spapr_machine_init(MachineState *machine)/* advertise support for ibm,dyamic-memory-v2 */ spapr_ovec_set (spapr->ov5,OV5_DRMEM_V2 ); +/* advertise XIVE */ +if (smc->irq->ov5) { +spapr_ovec_set (spapr->ov5,OV5_XIVE_EXPLOIT ); + } +/* init CPUs */ spapr_init_cpus (spapr);
@@ -3916,6 +3926,21 @@ static void spapr_machine_3_0_class_options(MachineClass *mc) DEFINE_SPAPR_MACHINE(3_0, "3.0", true); +static void spapr_machine_3_0_xive_instance_options (MachineState *machine) +{ +spapr_machine_3_0_instance_options (machine); +} + +static void spapr_machine_3_0_xive_class_options (MachineClass *mc) +{ +sPAPRMachineClass *smc =SPAPR_MACHINE_CLASS (mc); + +spapr_machine_3_0_class_options (mc); + smc->irq = &spapr_irq_xive; +} + +DEFINE_SPAPR_MACHINE(3_0_xive, "3.0-xive", false); +/* * pseries-2.12 */
hw/ppc/spapr_irq.c +3 -0
@@ -256,6 +256,7 @@ static Object *spapr_irq_cpu_intc_create_legacy(sPAPRMachineState *spapr,sPAPRIrq spapr_irq_legacy = { .nr_irqs =XICS_IRQS_SPAPR , + .ov5 =0x0 ,/* XICS only */ .init = spapr_irq_init_legacy, .assign = spapr_irq_assign_legacy, .alloc = spapr_irq_alloc_legacy,
@@ -522,6 +523,7 @@ static const sPAPRPIrqRange spapr_irq_ranges_xics[] = {sPAPRIrq spapr_irq_xics = { .nr_irqs =0x1000 , + .ov5 =0x0 ,/* XICS only */ .init = spapr_irq_init_xics, .ranges = spapr_irq_ranges_xics, .assign = spapr_irq_assign_xics,
@@ -743,6 +745,7 @@ static const sPAPRPIrqRange spapr_irq_ranges_xive[] = {sPAPRIrq spapr_irq_xive = { .nr_irqs =0x2000 , + .ov5 =0x40 ,/* XIVE exploitation mode only */ .init = spapr_irq_init_xive, .ranges = spapr_irq_ranges_xive, .assign = spapr_irq_assign_xive,
Signature · 1 line
2.13.6
PATCH v4 21/28 spapr: add classes for the XIVE models
In reply to Cédric Le GoaterThe XIVE models for TCG and KVM will have a lot in common. Introduce some classes to handle the differences, mostly to synchronize the state with KVM for the monitor and migration. This is very much like the XICS models.
--- include/hw/ppc/spapr_xive.h | 13 ++++++++ include/hw/ppc/xive.h | 29 +++++++++++++++++ hw/intc/spapr_xive.c | 32 ++++++++++++++++++ hw/intc/xive.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+)
include/hw/ppc/spapr_xive.h +13 -0
@@ -38,6 +38,19 @@ typedef struct sPAPRXive {MemoryRegion tm_mmio; } sPAPRXive; +#define SPAPR_XIVE_CLASS (klass) \ + OBJECT_CLASS_CHECK(sPAPRXiveClass, (klass), TYPE_SPAPR_XIVE) +#define SPAPR_XIVE_GET_CLASS (obj) \ + OBJECT_GET_CLASS(sPAPRXiveClass, (obj), TYPE_SPAPR_XIVE) + +typedef struct sPAPRXiveClass { +XiveRouterClass parent_class; + +void (*synchronize_state)(sPAPRXive *xive); +void (*pre_save)(sPAPRXive *xsrc); +int (*post_load)(sPAPRXive *xsrc,int version_id); +}sPAPRXiveClass ; +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);
include/hw/ppc/xive.h +29 -0
@@ -68,6 +68,20 @@ typedef struct XiveSource {XiveFabric *xive; } XiveSource; +#define XIVE_SOURCE_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveSourceClass, (klass), TYPE_XIVE_SOURCE) +#define XIVE_SOURCE_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveSourceClass, (obj), TYPE_XIVE_SOURCE) + +typedef struct XiveSourceClass { +SysBusDeviceClass parent_class; + +void (*synchronize_state)(XiveSource *xsrc); +void (*reset)(XiveSource *xsrc); +void (*pre_save)(XiveSource *xsrc); +int (*post_load)(XiveSource *xsrc,int version_id); +}XiveSourceClass ; +/* * ESB MMIO setting. Can be one page, for both source triggering and * source management, or two different pages. See below for magic
@@ -275,6 +289,21 @@ typedef struct XiveTCTX {XiveRouter *xrtr; } XiveTCTX; +#define XIVE_TCTX_CLASS (klass) \ + OBJECT_CLASS_CHECK(XiveTCTXClass, (klass), TYPE_XIVE_TCTX) +#define XIVE_TCTX_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XiveTCTXClass, (obj), TYPE_XIVE_TCTX) + +typedef struct XiveTCTXClass { +DeviceClass parent_class; + +void (*realize)(XiveTCTX *tctx,Error **errp); +void (*synchronize_state)(XiveTCTX *tctx); +void (*reset)(XiveTCTX *tctx); +void (*pre_save)(XiveTCTX *tctx); +int (*post_load)(XiveTCTX *tctx,int version_id); +}XiveTCTXClass ; +/* * XIVE Thread Interrupt Management Aera (TIMA) */
hw/intc/spapr_xive.c +32 -0
@@ -27,8 +27,13 @@void spapr_xive_pic_print_info (sPAPRXive *xive,Monitor *mon) { +sPAPRXiveClass *sxc =SPAPR_XIVE_GET_CLASS (xive);int i; +if (sxc->synchronize_state) { + sxc->synchronize_state (xive); + } +xive_source_pic_print_info (&xive->source,0 , mon);monitor_printf (mon,"IVE Table\n" );
@@ -279,6 +284,30 @@ static const VMStateDescription vmstate_spapr_xive_eq = { }, }; +static int vmstate_spapr_xive_pre_save (void *opaque) +{ +sPAPRXive *xive = opaque; +sPAPRXiveClass *sxc =SPAPR_XIVE_GET_CLASS (xive); + +if (sxc->pre_save) { + sxc->pre_save (xive); + } + +return 0 ; +} + +static int vmstate_spapr_xive_post_load (void *opaque,int version_id) +{ +sPAPRXive *xive = opaque; +sPAPRXiveClass *sxc =SPAPR_XIVE_GET_CLASS (xive); + +if (sxc->post_load) { + sxc->post_load (xive, version_id); + } + +return 0 ; +} +static const VMStateDescription vmstate_spapr_xive_ive = { .name =TYPE_SPAPR_XIVE "/ive" , .version_id =1 ,
@@ -293,6 +322,8 @@ static const VMStateDescription vmstate_spapr_xive = { .name = TYPE_SPAPR_XIVE, .version_id = 1, .minimum_version_id = 1, + .pre_save = vmstate_spapr_xive_pre_save, + .post_load = vmstate_spapr_xive_post_load, .fields = (VMStateField []) {VMSTATE_UINT32_EQUAL (nr_irqs, sPAPRXive,NULL ), VMSTATE_STRUCT_VARRAY_POINTER_UINT32(ivt, sPAPRXive, nr_irqs,
@@ -336,6 +367,7 @@ static const TypeInfo spapr_xive_info = { .instance_init = spapr_xive_instance_init, .instance_size = sizeof(sPAPRXive), .class_init = spapr_xive_class_init, + .class_size = sizeof(sPAPRXiveClass), };static void spapr_xive_register_types (void )
hw/intc/xive.c +79 -0
162 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v4 22/28 target/ppc/kvm: add Linux KVM definitions for XIVE
In reply to Cédric Le GoaterThese definitions add a new capability and a new KVM device for the XIVE native exploitation interrupt mode. New ioctls are also introduced to initialize the KVM device and to capture/restore the VM state for migration.
--- linux-headers/asm-powerpc/kvm.h | 23 +++++++++++++++++++++++ linux-headers/linux/kvm.h | 3 +++ target/ppc/kvm_ppc.h | 6 ++++++ target/ppc/kvm.c | 7 +++++++ 4 files changed, 39 insertions(+)
linux-headers/asm-powerpc/kvm.h +23 -0
@@ -480,6 +480,16 @@ struct kvm_ppc_cpu_char {#define KVM_REG_PPC_ICP_PPRI_SHIFT 16/* pending irq priority */ #define KVM_REG_PPC_ICP_PPRI_MASK 0xff +#define KVM_REG_PPC_VP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x8d) +#define KVM_REG_PPC_VP_EQ0 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x8e) +#define KVM_REG_PPC_VP_EQ1 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x8f) +#define KVM_REG_PPC_VP_EQ2 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x90) +#define KVM_REG_PPC_VP_EQ3 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x91) +#define KVM_REG_PPC_VP_EQ4 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x92) +#define KVM_REG_PPC_VP_EQ5 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x93) +#define KVM_REG_PPC_VP_EQ6 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x94) +#define KVM_REG_PPC_VP_EQ7 (KVM_REG_PPC | KVM_REG_SIZE_U256 | 0x95) +/* Device control API: PPC-specific devices */ #define KVM_DEV_MPIC_GRP_MISC 1#define KVM_DEV_MPIC_BASE_ADDR 0/* 64-bit */
@@ -673,4 +683,17 @@ struct kvm_ppc_cpu_char {#define KVM_XICS_PRESENTED (1ULL << 43)#define KVM_XICS_QUEUED (1ULL << 44) +/* POWER9 XIVE Interrupt Controller */ +#define KVM_DEV_XIVE_GRP_SOURCES 1/* 64-bit source attributes */ +#define KVM_DEV_XIVE_GRP_CTRL 2 +#define KVM_DEV_XIVE_GET_ESB_FD 1 +#define KVM_DEV_XIVE_GET_TIMA_FD 2 +#define KVM_DEV_XIVE_VC_BASE 3 +#define KVM_DEV_XIVE_GRP_IVE 3/* 64-bit source attributes */ +#define KVM_DEV_XIVE_GRP_SYNC 4/* 64-bit source attributes */ + +/* Layout of 64-bit XIVE source attribute values */ +#define KVM_XIVE_LEVEL_SENSITIVE (1ULL << 0) +#define KVM_XIVE_LEVEL_ASSERTED (1ULL << 1) +#endif /* __LINUX_KVM_POWERPC_H */
linux-headers/linux/kvm.h +3 -0
@@ -948,6 +948,7 @@ struct kvm_ppc_resize_hpt {#define KVM_CAP_S390_BPB 152#define KVM_CAP_GET_MSR_FEATURES 153#define KVM_CAP_HYPERV_EVENTFD 154 +#define KVM_CAP_PPC_IRQ_XIVE 155#ifdef KVM_CAP_IRQ_ROUTING
@@ -1171,6 +1172,8 @@ enum kvm_device_type {#define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_ITS,#define KVM_DEV_TYPE_ARM_VGIC_ITS KVM_DEV_TYPE_ARM_VGIC_ITS + KVM_DEV_TYPE_XIVE, +#define KVM_DEV_TYPE_XIVE KVM_DEV_TYPE_XIVE KVM_DEV_TYPE_MAX, };
target/ppc/kvm_ppc.h +6 -0
@@ -59,6 +59,7 @@ bool kvmppc_has_cap_fixup_hcalls(void);bool kvmppc_has_cap_htm (void );bool kvmppc_has_cap_mmu_radix (void );bool kvmppc_has_cap_mmu_hash_v3 (void ); +bool kvmppc_has_cap_xive (void );int kvmppc_get_cap_safe_cache (void );int kvmppc_get_cap_safe_bounds_check (void );int kvmppc_get_cap_safe_indirect_branch (void );
@@ -293,6 +294,11 @@ static inline bool kvmppc_has_cap_mmu_hash_v3(void)return false; } +static inline bool kvmppc_has_cap_xive (void ) +{ +return false; +} +static inline int kvmppc_get_cap_safe_cache (void ) {return 0 ;
target/ppc/kvm.c +7 -0
@@ -86,6 +86,7 @@ static int cap_fixup_hcalls;static int cap_htm;/* Hardware transactional memory support */ static int cap_mmu_radix;static int cap_mmu_hash_v3; +static int cap_xive;static int cap_resize_hpt;static int cap_ppc_pvr_compat;static int cap_ppc_safe_cache;
@@ -148,6 +149,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_htm =kvm_vm_check_extension (s,KVM_CAP_PPC_HTM ); cap_mmu_radix =kvm_vm_check_extension (s,KVM_CAP_PPC_MMU_RADIX ); cap_mmu_hash_v3 =kvm_vm_check_extension (s,KVM_CAP_PPC_MMU_HASH_V3 ); + cap_xive =kvm_vm_check_extension (s,KVM_CAP_PPC_IRQ_XIVE ); cap_resize_hpt =kvm_vm_check_extension (s,KVM_CAP_SPAPR_RESIZE_HPT );kvmppc_get_cpu_characteristics (s);/*
@@ -2447,6 +2449,11 @@ static int parse_cap_ppc_safe_indirect_branch(struct kvm_ppc_cpu_char c)return 0 ; } +bool kvmppc_has_cap_xive (void ) +{ +return cap_xive; +} +static void kvmppc_get_cpu_characteristics (KVMState *s) {struct kvm_ppc_cpu_char c;
Signature · 1 line
2.13.6
PATCH v4 23/28 spapr/xive: add common realize routine for KVM
In reply to Cédric Le GoaterThe XiveSource and sPAPRXive device models will be shared between the TCG and the KVM mode. The difference will reside in the way the memory regions are initialized and in the qemu_irq handler.
Introduce common realize routines to share some code.
--- include/hw/ppc/spapr_xive.h | 1 + include/hw/ppc/xive.h | 3 +++ hw/intc/spapr_xive.c | 15 +++++++++++++-- hw/intc/xive.c | 22 +++++++++++++++++----- 4 files changed, 34 insertions(+), 7 deletions(-)
include/hw/ppc/spapr_xive.h +1 -0
@@ -55,6 +55,7 @@ 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);qemu_irq spapr_xive_qirq (sPAPRXive *xive,uint32_t lisn); +void spapr_xive_common_realize (sPAPRXive *xive,Error **errp);/* * sPAPR VP and EQ indexing helpers
include/hw/ppc/xive.h +3 -0
@@ -183,6 +183,9 @@ static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno, } } +void xive_source_common_realize (XiveSource *xsrc,qemu_irq_handler handler, +Error **errp); +/* * XIVE Router */
hw/intc/spapr_xive.c +13 -2
@@ -84,9 +84,8 @@ static void spapr_xive_instance_init(Object *obj)object_property_add_child (obj,"eq_source" ,OBJECT (&xive->eq_source),NULL ); } -static void spapr_xive_realize (DeviceState *dev,Error **errp) +void spapr_xive_common_realize (sPAPRXive *xive,Error **errp) { -sPAPRXive *xive =SPAPR_XIVE (dev);XiveSource *xsrc = &xive->source;XiveEQSource *eq_xsrc = &xive->eq_source;Error *local_err =NULL ;
@@ -132,6 +131,18 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp)/* Allocate the routing tables */ xive->ivt =g_new0 (XiveIVE, xive->nr_irqs); xive->eqdt =g_new0 (XiveEQ, xive->nr_eqs); +} + +static void spapr_xive_realize (DeviceState *dev,Error **errp) +{ +sPAPRXive *xive =SPAPR_XIVE (dev); +Error *local_err =NULL ; + +spapr_xive_common_realize (xive, &local_err); +if (local_err) { +error_propagate (errp, local_err); +return ; + }/* TIMA */ memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, xive,
hw/intc/xive.c +17 -5
@@ -1003,13 +1003,13 @@ static void xive_source_reset(DeviceState *dev) } } -static void xive_source_realize (DeviceState *dev,Error **errp) +void xive_source_common_realize (XiveSource *xsrc,qemu_irq_handler handler, +Error **errp) { -XiveSource *xsrc =XIVE_SOURCE (dev);Object *obj;Error *local_err =NULL ; - obj =object_property_get_link (OBJECT (dev),"xive" , &local_err); + obj =object_property_get_link (OBJECT (xsrc),"xive" , &local_err);if (!obj) {error_propagate (errp, local_err);error_prepend (errp,"required link 'xive' not found: " );
@@ -1031,14 +1031,26 @@ static void xive_source_realize(DeviceState *dev, Error **errp)return ; } - xsrc->qirqs =qemu_allocate_irqs (xive_source_set_irq, xsrc, - xsrc->nr_irqs); + xsrc->qirqs =qemu_allocate_irqs (handler, xsrc, xsrc->nr_irqs); xsrc->status =g_malloc0 (xsrc->nr_irqs); xsrc->lsi_map =bitmap_new (xsrc->nr_irqs); xsrc->lsi_map_size = xsrc->nr_irqs; +} + +static void xive_source_realize (DeviceState *dev,Error **errp) +{ +XiveSource *xsrc =XIVE_SOURCE (dev); +Error *local_err =NULL ; + +xive_source_common_realize (xsrc, xive_source_set_irq, &local_err); +if (local_err) { +error_propagate (errp, local_err); +return ; + } +memory_region_init_io (&xsrc->esb_mmio,OBJECT (xsrc), &xive_source_esb_ops, xsrc,"xive.esb" , (1ull << xsrc->esb_shift) * xsrc->nr_irqs);
Signature · 1 line
2.13.6
PATCH v4 24/28 spapr/xive: add KVM support
In reply to Cédric Le GoaterThis introduces a set of XIVE models specific to KVM. They handle the initialization and the state synchronization with KVM, for the monitor usage and for the migration.
The TIMA and the source ESB memory regions are initialized differently under KVM. 'ram device' memory mappings, similarly to VFIO, are exposed to the guest and the associated VMAs on the host are populated dynamically with the appropriate pages using a fault handler.
Migration needs to follow a specific sequence to make sure the different internal states are captured correctly. This is why we raise the sPAPRXive KVM model migration priority to make sure its pre_save handler runs before the other XIVE models' pre_save.
sPAPRXive pre_save starts by masking all the sources to quiesce the interrupt flow and perform a XIVE xync to stabilize the EQs. The EQs are then masked to stop notifications to a VP and their state is captured. What is important is the EQ index and the toggle bit. Follows the capture of the state of the thread context. When done, a rollback is performed to restore the sources and the EQs to their initial state. Post_load is simpler and only needs to restore the different state in the correct order.
The get/set operations rely on their KVM counterpart in the host kernel which acts as a proxy for OPAL, the host firmware. Extra quiescence points are possibly needed so the XIVE migration is currently work in progress.
--- default-configs/ppc64-softmmu.mak | 1 + include/hw/ppc/spapr_xive.h | 20 + include/hw/ppc/xive.h | 3 + include/migration/vmstate.h | 1 + hw/intc/spapr_xive.c | 1 + hw/intc/spapr_xive_kvm.c | 809 ++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_irq.c | 29 +- hw/intc/Makefile.objs | 1 + 8 files changed, 855 insertions(+), 10 deletions(-) create mode 100644 hw/intc/spapr_xive_kvm.c
default-configs/ppc64-softmmu.mak +1 -0
@@ -18,4 +18,5 @@ CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_XIVE=$(CONFIG_PSERIES) CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES) +CONFIG_XIVE_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_MEM_HOTPLUG=y
include/hw/ppc/spapr_xive.h +20 -0
@@ -36,6 +36,10 @@ typedef struct sPAPRXive {/* TIMA mapping address */ hwaddr tm_base;MemoryRegion tm_mmio; + +/* KVM support */ +int fd; +void *tm_mmap; } sPAPRXive;#define SPAPR_XIVE_CLASS (klass) \
@@ -79,4 +83,20 @@ void spapr_xive_hcall_init(sPAPRMachineState *spapr);void spapr_dt_xive (sPAPRXive *xive,int nr_servers,void *fdt,uint32_t phandle); +/* +* XIVE KVM models +*/ + +#define TYPE_SPAPR_XIVE_KVM "spapr-xive-kvm" +#define SPAPR_XIVE_KVM (obj) \ + OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE_KVM) + +#define TYPE_XIVE_SOURCE_KVM "xive-source-kvm" +#define XIVE_SOURCE_KVM (obj) \ + OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE_KVM) + +#define TYPE_XIVE_TCTX_KVM "xive-tctx-kvm" +#define XIVE_TCTX_KVM (obj) \ + OBJECT_CHECK(XiveTCTX, (obj), TYPE_XIVE_TCTX_KVM) +#endif /* PPC_SPAPR_XIVE_H */
include/hw/ppc/xive.h +3 -0
@@ -65,6 +65,9 @@ typedef struct XiveSource {uint32_t esb_shift;MemoryRegion esb_mmio; +/* KVM support */ +void *esb_mmap; +XiveFabric *xive; } XiveSource;
include/migration/vmstate.h +1 -0
@@ -156,6 +156,7 @@ typedef enum {MIG_PRI_PCI_BUS ,/* Must happen before IOMMU */ MIG_PRI_GICV3_ITS ,/* Must happen before PCI devices */ MIG_PRI_GICV3 ,/* Must happen before the ITS */ +MIG_PRI_XIVE_IC ,/* Must happen before XIVE thread context */ MIG_PRI_MAX , } MigrationPriority;
hw/intc/spapr_xive.c +1 -0
@@ -335,6 +335,7 @@ static const VMStateDescription vmstate_spapr_xive = { .minimum_version_id = 1, .pre_save = vmstate_spapr_xive_pre_save, .post_load = vmstate_spapr_xive_post_load, + .priority = MIG_PRI_XIVE_IC, .fields = (VMStateField []) {VMSTATE_UINT32_EQUAL (nr_irqs, sPAPRXive,NULL ), VMSTATE_STRUCT_VARRAY_POINTER_UINT32(ivt, sPAPRXive, nr_irqs,
hw/intc/spapr_xive_kvm.c new file +809 -0
809 lines not on this page · raw message
hw/ppc/spapr_irq.c +19 -10
@@ -575,16 +575,28 @@ static void spapr_irq_init_xive(sPAPRMachineState *spapr, uint32_t nr_servers,sPAPRMachineClass *smc =SPAPR_MACHINE_GET_CLASS (machine);int i; -/* We don't have KVM support yet, so check for irqchip=on */ -if (kvm_enabled () &&machine_kernel_irqchip_required (machine)) { -error_report ("kernel_irqchip requested. no XIVE support" ); -exit (1 ); +if (kvm_enabled ()) { +if (machine_kernel_irqchip_allowed (machine)) { + spapr->xive_tctx_type =TYPE_XIVE_TCTX_KVM ; + spapr->xive =spapr_xive_create (spapr,TYPE_SPAPR_XIVE_KVM , + smc->irq->nr_irqs, nr_servers, + errp); + } + +if (machine_kernel_irqchip_required (machine) && !spapr->xive) { +error_prepend (errp,"kernel_irqchip requested but unavailable: " ); +return ; + } } - spapr->xive =spapr_xive_create (spapr,TYPE_SPAPR_XIVE , smc->irq->nr_irqs, - nr_servers, errp);if (!spapr->xive) { -return ; + spapr->xive =spapr_xive_create (spapr,TYPE_SPAPR_XIVE , + smc->irq->nr_irqs, nr_servers, errp); +if (!spapr->xive) { +return ; + } + spapr->xive_tctx_type =TYPE_XIVE_TCTX ; +spapr_xive_hcall_init (spapr); }/*
@@ -597,9 +609,6 @@ static void spapr_irq_init_xive(sPAPRMachineState *spapr, uint32_t nr_servers,for (i =0 ; i < nr_servers; ++i) {spapr_irq_alloc (spapr,SPAPR_IRQ_IPI , i, errp); } - - spapr->xive_tctx_type =TYPE_XIVE_TCTX ; -spapr_xive_hcall_init (spapr); }/*
hw/intc/Makefile.objs +1 -0
@@ -39,6 +39,7 @@ 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 spapr_xive_hcall.o +obj-$(CONFIG_XIVE_KVM) += spapr_xive_kvm.o obj-$(CONFIG_POWERNV) += xics_pnv.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o
Signature · 1 line
2.13.6
PATCH v4 25/28 spapr: fix XICS migration
In reply to Cédric Le GoaterExtend the sPAPR IRQ backend with a new handler to handle XICS post_load() specificities.
--- include/hw/ppc/spapr_irq.h | 1 + hw/ppc/spapr.c | 9 ++------- hw/ppc/spapr_irq.c | 24 ++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-)
include/hw/ppc/spapr_irq.h +1 -0
@@ -47,6 +47,7 @@ typedef struct sPAPRIrq { void *fdt, uint32_t phandle); Object *(*cpu_intc_create)(sPAPRMachineState *spapr, Object *cpu, Error **errp); +void (*post_load)(sPAPRMachineState *spapr); } sPAPRIrq;extern sPAPRIrq spapr_irq_legacy;
hw/ppc/spapr.c +2 -7
@@ -1689,6 +1689,7 @@ static int spapr_pre_load(void *opaque)static int spapr_post_load (void *opaque,int version_id) {sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; +sPAPRMachineClass *smc =SPAPR_MACHINE_GET_CLASS (spapr);int err =0 ; err =spapr_caps_post_migration (spapr);
@@ -1696,13 +1697,7 @@ static int spapr_post_load(void *opaque, int version_id)return err; } -if (!object_dynamic_cast (OBJECT (spapr->ics),TYPE_ICS_KVM )) { -CPUState *cs; -CPU_FOREACH (cs) { -PowerPCCPU *cpu =POWERPC_CPU (cs); -icp_resend (ICP (cpu->intc)); - } - } + smc->irq->post_load (spapr);/* In earlier versions, there was no separate qdev for the PAPR * RTC, so the RTC offset was stored directly in sPAPREnvironment.
hw/ppc/spapr_irq.c +24 -0
@@ -254,6 +254,17 @@ static Object *spapr_irq_cpu_intc_create_legacy(sPAPRMachineState *spapr,return icp_create (cpu, spapr->icp_type,XICS_FABRIC (spapr), errp); } +static void spapr_irq_post_load_legacy (sPAPRMachineState *spapr) +{ +if (!object_dynamic_cast (OBJECT (spapr->ics),TYPE_ICS_KVM )) { +CPUState *cs; +CPU_FOREACH (cs) { +PowerPCCPU *cpu =POWERPC_CPU (cs); +icp_resend (ICP (cpu->intc)); + } + } +} +sPAPRIrq spapr_irq_legacy = { .nr_irqs =XICS_IRQS_SPAPR , .ov5 =0x0 ,/* XICS only */
@@ -266,6 +277,7 @@ sPAPRIrq spapr_irq_legacy = { .print_info = spapr_irq_print_info_legacy, .dt_populate = spapr_irq_dt_populate_legacy, .cpu_intc_create = spapr_irq_cpu_intc_create_legacy, + .post_load = spapr_irq_post_load_legacy, };/*
@@ -487,6 +499,11 @@ static Object *spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr,return spapr_irq_cpu_intc_create_legacy (spapr, cpu, errp); } +static void spapr_irq_post_load_xics (sPAPRMachineState *spapr) +{ +spapr_irq_post_load_legacy (spapr); +} +/* * XICS IRQ number space *
@@ -534,6 +551,7 @@ sPAPRIrq spapr_irq_xics = { .print_info = spapr_irq_print_info_xics, .dt_populate = spapr_irq_dt_populate_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, + .post_load = spapr_irq_post_load_xics, };/*
@@ -716,6 +734,11 @@ static Object *spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr, XIVE_ROUTER(spapr->xive), errp); } +static void spapr_irq_post_load_xive (sPAPRMachineState *spapr) +{ + ; +} +/* * XIVE IRQ number space *
@@ -765,6 +788,7 @@ sPAPRIrq spapr_irq_xive = { .print_info = spapr_irq_print_info_xive, .dt_populate = spapr_irq_dt_populate_xive, .cpu_intc_create = spapr_irq_cpu_intc_create_xive, + .post_load = spapr_irq_post_load_xive, };/*
Signature · 1 line
2.13.6
PATCH v4 26/28 pnv: add a physical mapping array describing MMIO ranges in each chip
In reply to Cédric Le GoaterBased on previous work done in skiboot, the physical mapping array helps in calculating the MMIO ranges of each controller depending on the chip id and the chip type. This is will be particularly useful for the P9 models which use less the XSCOM bus and rely more on MMIOs.
A link on the chip is now necessary to calculate MMIO BARs and sizes. This is why such a link is introduced in the PSIHB model.
--- include/hw/ppc/pnv.h | 51 ++++++++++++++++++++++++++++++++++---------------- hw/ppc/pnv.c | 53 ++++++++++++++++++++++++++++++++++++++++++++-------- hw/ppc/pnv_psi.c | 15 ++++++++++++--- hw/ppc/pnv_xscom.c | 8 ++++---- 4 files changed, 96 insertions(+), 31 deletions(-)
include/hw/ppc/pnv.h +35 -16
@@ -53,7 +53,6 @@ typedef struct PnvChip {uint64_t cores_mask;void *cores; -hwaddr xscom_base;MemoryRegion xscom_mmio;MemoryRegion xscom;AddressSpace xscom_as;
@@ -64,6 +63,18 @@ typedef struct PnvChip {PnvOCC occ; } PnvChip; +typedef enum PnvPhysMapType { +PNV_MAP_XSCOM , +PNV_MAP_ICP , +PNV_MAP_PSIHB , +PNV_MAP_PSIHB_FSP , +}PnvPhysMapType ; + +typedef struct PnvPhysMapEntry { +uint64_t base; +uint64_t size; +}PnvPhysMapEntry ; + typedef struct PnvChipClass { /*< private >*/ SysBusDeviceClass parent_class;
@@ -73,9 +84,10 @@ typedef struct PnvChipClass {uint64_t chip_cfam_id;uint64_t cores_mask; -hwaddr xscom_base; +const PnvPhysMapEntry *phys_map;uint32_t (*core_pir)(PnvChip *chip,uint32_t core_id); +uint64_t (*map_base)(const PnvChip *chip,PnvPhysMapType type); } PnvChipClass;#define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP
@@ -159,9 +171,21 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);/* * POWER8 MMIO base addresses */ -#define PNV_XSCOM_SIZE 0x800000000ull -#define PNV_XSCOM_BASE (chip) \ - (chip->xscom_base + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE) +static inline uint64_t pnv_map_size (const PnvChip *chip,PnvPhysMapType type) +{ +PnvChipClass *pcc =PNV_CHIP_GET_CLASS (chip); +const PnvPhysMapEntry *map = &pcc->phys_map[type]; + +return map->size; +} + +static inline uint64_t pnv_map_base (const PnvChip *chip,PnvPhysMapType type) +{ +return PNV_CHIP_GET_CLASS (chip)->map_base (chip, type); +} + +#define PNV_XSCOM_SIZE (chip) pnv_map_size(chip, PNV_MAP_XSCOM) +#define PNV_XSCOM_BASE (chip) pnv_map_base(chip, PNV_MAP_XSCOM)/* * XSCOM 0x20109CA defines the ICP BAR:
@@ -177,18 +201,13 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);* 0xffffe02200000000 -> 0x0003ffff80800000 * 0xffffe02600000000 -> 0x0003ffff80900000 */ -#define PNV_ICP_SIZE 0x0000000000100000ull -#define PNV_ICP_BASE (chip) \ - (0x0003ffff80000000ull + (uint64_t) PNV_CHIP_INDEX(chip) * PNV_ICP_SIZE) - +#define PNV_ICP_SIZE (chip) pnv_map_size(chip, PNV_MAP_ICP) +#define PNV_ICP_BASE (chip) pnv_map_base(chip, PNV_MAP_ICP) -#define PNV_PSIHB_SIZE 0x0000000000100000ull -#define PNV_PSIHB_BASE (chip) \ - (0x0003fffe80000000ull + (uint64_t)PNV_CHIP_INDEX(chip) * PNV_PSIHB_SIZE) +#define PNV_PSIHB_SIZE (chip) pnv_map_size(chip, PNV_MAP_PSIHB) +#define PNV_PSIHB_BASE (chip) pnv_map_base(chip, PNV_MAP_PSIHB) -#define PNV_PSIHB_FSP_SIZE 0x0000000100000000ull -#define PNV_PSIHB_FSP_BASE (chip) \ - (0x0003ffe000000000ull + (uint64_t)PNV_CHIP_INDEX(chip) * \ - PNV_PSIHB_FSP_SIZE) +#define PNV_PSIHB_FSP_SIZE (chip) pnv_map_size(chip, PNV_MAP_PSIHB_FSP) +#define PNV_PSIHB_FSP_BASE (chip) pnv_map_base(chip, PNV_MAP_PSIHB_FSP)#endif /* _PPC_PNV_H */
hw/ppc/pnv.c +45 -8
104 lines not on this page · raw message
hw/ppc/pnv_psi.c +12 -3
@@ -465,11 +465,20 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)Object *obj;Error *err =NULL ;unsigned int i; +PnvChip *chip; + + obj =object_property_get_link (OBJECT (dev),"chip" , &err); +if (!obj) { +error_propagate (errp, err); +error_prepend (errp,"required link 'chip' not found: " ); +return ; + } + chip =PNV_CHIP (obj); obj =object_property_get_link (OBJECT (dev),"xics" , &err);if (!obj) { -error_setg (errp,"%s: required link 'xics' not found: %s" , - __func__,error_get_pretty (err)); +error_propagate (errp, err); +error_prepend (errp,"required link 'xics' not found: " );return ; }
@@ -497,7 +506,7 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)/* Initialize MMIO region */ memory_region_init_io (&psi->regs_mr,OBJECT (dev), &psi_mmio_ops, psi, -"psihb" ,PNV_PSIHB_SIZE ); +"psihb" ,PNV_PSIHB_SIZE (chip));/* Default BAR for MMIO region */ pnv_psi_set_bar (psi, psi->bar |PSIHB_BAR_EN );
hw/ppc/pnv_xscom.c +4 -4
@@ -50,7 +50,7 @@ static void xscom_complete(CPUState *cs, uint64_t hmer_bits)static uint32_t pnv_xscom_pcba (PnvChip *chip,uint64_t addr) { - addr &= (PNV_XSCOM_SIZE -1 ); + addr &= (PNV_XSCOM_SIZE (chip) -1 );if (pnv_chip_is_power9 (chip)) {return addr >>3 ;
@@ -179,10 +179,10 @@ void pnv_xscom_realize(PnvChip *chip, Error **errp) name =g_strdup_printf ("xscom-%x" , chip->chip_id);memory_region_init_io (&chip->xscom_mmio,OBJECT (chip), &pnv_xscom_ops, - chip, name,PNV_XSCOM_SIZE ); + chip, name,PNV_XSCOM_SIZE (chip));sysbus_init_mmio (sbd, &chip->xscom_mmio); -memory_region_init (&chip->xscom,OBJECT (chip), name,PNV_XSCOM_SIZE ); +memory_region_init (&chip->xscom,OBJECT (chip), name,PNV_XSCOM_SIZE (chip));address_space_init (&chip->xscom_as, &chip->xscom, name);g_free (name); }
@@ -225,7 +225,7 @@ static const char compat_p9[] = "ibm,power9-xscom\0ibm,xscom";int pnv_dt_xscom (PnvChip *chip,void *fdt,int root_offset) {uint64_t reg[] = {cpu_to_be64 (PNV_XSCOM_BASE (chip)), -cpu_to_be64 (PNV_XSCOM_SIZE ) }; +cpu_to_be64 (PNV_XSCOM_SIZE (chip)) };int xscom_offset;ForeachPopulateArgs args;char *name;
Signature · 1 line
2.13.6
PATCH v4 27/28 ppc: externalize ppc_get_vcpu_by_pir()
In reply to Cédric Le GoaterWe will use it to get the CPU interrupt presenter in XIVE.
--- include/hw/ppc/ppc.h | 1 + hw/ppc/pnv.c | 16 ---------------- hw/ppc/ppc.c | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 16 deletions(-)
include/hw/ppc/ppc.h +1 -0
@@ -4,6 +4,7 @@#include "target/ppc/cpu-qom.h" void ppc_set_irq (PowerPCCPU *cpu,int n_IRQ,int level); +PowerPCCPU *ppc_get_vcpu_by_pir (int pir);/* PowerPC hardware exceptions management helpers */ typedef void (*clk_setup_cb )(void *opaque,uint32_t freq);
hw/ppc/pnv.c +0 -16
@@ -1030,22 +1030,6 @@ static void pnv_ics_resend(XICSFabric *xi) } } -static PowerPCCPU *ppc_get_vcpu_by_pir (int pir) -{ -CPUState *cs; - -CPU_FOREACH (cs) { -PowerPCCPU *cpu =POWERPC_CPU (cs); -CPUPPCState *env = &cpu->env; - -if (env->spr_cb[SPR_PIR ].default_value == pir) { -return cpu; - } - } - -return NULL ; -} -static ICPState *pnv_icp_get (XICSFabric *xi,int pir) {PowerPCCPU *cpu =ppc_get_vcpu_by_pir (pir);
hw/ppc/ppc.c +16 -0
@@ -1358,3 +1358,19 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)break ; } } + +PowerPCCPU *ppc_get_vcpu_by_pir (int pir) +{ +CPUState *cs; + +CPU_FOREACH (cs) { +PowerPCCPU *cpu =POWERPC_CPU (cs); +CPUPPCState *env = &cpu->env; + +if (env->spr_cb[SPR_PIR ].default_value == pir) { +return cpu; + } + } + +return NULL ; +}
Signature · 1 line
2.13.6
PATCH v4 28/28 ppc/pnv: add XIVE support
In reply to Cédric Le GoaterThis is simple model of the POWER9 XIVE interrupt controller for the PowerNV machine. XIVE for baremetal is a complex controller and the model only addresses the needs of the skiboot firmware.
* Overall architecture
XIVE Interrupt Controller
+-------------------------------------+ IPIs
| +---------+ +---------+ +---------+ | +--------+
| |VC | |CQ | |PC |----> | CORES |
| | esb | | | | |----> | |
| | ive | | Bridge | | |----> | |
| |SC eqd | | | | vpd | | | |
+------+ | +---------+ +----+----+ +---------+ | +--+-+-+-+
| RAM | +------------------|------------------+ | | |
| | | | | |
| | | | | |
| | +---------------------v--------------------------v-v-v---+ other
| <---+ Power Bus +----> chips
| esb | +-----------+-----------------------+--------------------+
| ive | | |
| eqd | | |
| vpd | +---+----+ +---+----+
+------+ |SC | |SC |
| | | |
| 2-bits | | 2-bits |
| local | | VC |
+--------+ +--------+
PCIe NX,NPU,CAPI SC: Source Controller (aka. IVSE)
VC: Virtualization Controller (aka. IVRE)
CQ: Common Queue (Bridge)
PC: Presentation Controller (aka. IVPE)
2-bits: source state machine
esb: Event State Buffer (Array of PQ bits in an IVSE)
ive: Interrupt Virtualization Entry
eqd: Event Queue Descriptor
vpd: Virtual Processor Descriptor
It is composed of three sub-engines :
- Interrupt Virtualization Source Engine (IVSE), or Source Controller (SC). These are found in PCI PHBs, in the PSI host bridge controller, but also inside the main controller for the core IPIs and other sub-chips (NX, CAP, NPU) of the chip/processor. They are configured to feed the IVRE with events.
- Interrupt Virtualization Routing Engine (IVRE) or Virtualization Controller (VC). Its job is to match an event source with an Event Queue (EQ).
- Interrupt Virtualization Presentation Engine (IVPE) or Presentation Controller (PC). It maintains the interrupt context state of each thread and handles the delivery of the external exception to the thread.
* XIVE internal tables
Each of the sub-engines uses a set of tables to redirect exceptions from event sources to CPU threads.
+-------+
User or OS | EQ |
or +------>|entries|
Hypervisor | | .. |
Memory | +-------+
| ^
| |
+--------------------------------------------------+
| |
Hypervisor +------+ +---+--+ +---+--+ +------+
Memory | ESB | | IVT | | EQDT | | VPDT |
(skiboot) +----+-+ +----+-+ +----+-+ +------+
^ | ^ | ^ | ^
| | | | | | |
+--------------------------------------------------+
| | | | | | |
| | | | | | |
+-----|--|--------|--|--------|--|-+ +-|-----+ +------+
| | | | | | | | | | tctx| |Thread|
IPI or ----+ + v + v + v |---| + .. |-----> |
HW events | | | | | |
| IVRE | | IVPE | +------+
+----------------------------------+ +-------+The IVSE have a 2-bits, P for pending and Q for queued, state machine for each source that allows events to be triggered. They are stored in an array, the Event State Buffer (ESB) and controlled by MMIOs.
If the event is let through, the IVRE looks up in the Interrupt Virtualization Entry (IVE) table for an Event Queue Descriptor (EQD) configured for the source. Each Event Queue Descriptor defines a notification path to a CPU and an in-memory Event Queue, in which will be pushed an EQ data for the OS to pull.
The IVPE determines if a Virtual Processor (VP) can handle the event by scanning the thread contexts of the VPs dispatched on the processor HW threads. It maintains the interrupt context state of each thread in a Virtual Processor Descriptor (VPD) table.
* QEMU model for PowerNV
The PowerNV model reuses the common XIVE framework developed for sPAPR and the fundamentals aspects are quite the same. The difference are outlined below.
The controller initial BAR configuration is performed using the XSCOM bus from there, MMIO are used for further configuration.
The MMIO regions exposed are :
- Interrupt controller registers
- ESB pages for IPIs and EQs
- Presenter MMIO (Not used)
- Thread Interrupt Management Area MMIO, direct and indirect
Virtualization Controller MMIO region containing the IPI ESB pages and EQ ESB pages is sub-divided into "sets" which map portions of the VC region to the different ESB pages. It is configured at runtime through the EDT set translation table to let the firmware decide how to split the address space between IPI ESB pages and EQ ESB pages.
The XIVE tables are now in the machine RAM and not in the hypervisor anymore. The firmware (skiboot) configures these tables using Virtual Structure Descriptor defining the characteristics of each table : SBE, IVE, EQD and VPD. These are later used to access the virtual interrupt entries. The internal cache of these tables in the interrupt controller is updated and invalidated using a set of registers.
--- hw/intc/pnv_xive_regs.h | 314 ++++++++++ include/hw/ppc/pnv.h | 22 + include/hw/ppc/pnv_xive.h | 92 +++ include/hw/ppc/pnv_xscom.h | 3 + include/hw/ppc/xive.h | 1 + hw/intc/pnv_xive.c | 1485 ++++++++++++++++++++++++++++++++++++++++++++ hw/intc/xive.c | 63 +- hw/ppc/pnv.c | 42 +- hw/ppc/pnv_core.c | 28 +- hw/intc/Makefile.objs | 2 +- 10 files changed, 2034 insertions(+), 18 deletions(-) create mode 100644 hw/intc/pnv_xive_regs.h create mode 100644 include/hw/ppc/pnv_xive.h create mode 100644 hw/intc/pnv_xive.c
hw/intc/pnv_xive_regs.h new file +314 -0
@@ -0,0 +1,314 @@ +/* +* 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_PNV_XIVE_REGS_H +#define PPC_PNV_XIVE_REGS_H + +/* IC register offsets 0x0 - 0x400 */ +#define CQ_SWI_CMD_HIST 0x020 +#define CQ_SWI_CMD_POLL 0x028 +#define CQ_SWI_CMD_BCAST 0x030 +#define CQ_SWI_CMD_ASSIGN 0x038 +#define CQ_SWI_CMD_BLK_UPD 0x040 +#define CQ_SWI_RSP 0x048 +#define X_CQ_CFG_PB_GEN 0x0a +#define CQ_CFG_PB_GEN 0x050 +#define CQ_INT_ADDR_OPT PPC_BITMASK(14, 15) +#define X_CQ_IC_BAR 0x10 +#define X_CQ_MSGSND 0x0b +#define CQ_MSGSND 0x058 +#define CQ_CNPM_SEL 0x078 +#define CQ_IC_BAR 0x080 +#define CQ_IC_BAR_VALID PPC_BIT(0) +#define CQ_IC_BAR_64K PPC_BIT(1) +#define X_CQ_TM1_BAR 0x12 +#define CQ_TM1_BAR 0x90 +#define X_CQ_TM2_BAR 0x014 +#define CQ_TM2_BAR 0x0a0 +#define CQ_TM_BAR_VALID PPC_BIT(0) +#define CQ_TM_BAR_64K PPC_BIT(1) +#define X_CQ_PC_BAR 0x16 +#define CQ_PC_BAR 0x0b0 +#define CQ_PC_BAR_VALID PPC_BIT(0) +#define X_CQ_PC_BARM 0x17 +#define CQ_PC_BARM 0x0b8 +#define CQ_PC_BARM_MASK PPC_BITMASK(26, 38) +#define X_CQ_VC_BAR 0x18 +#define CQ_VC_BAR 0x0c0 +#define CQ_VC_BAR_VALID PPC_BIT(0) +#define X_CQ_VC_BARM 0x19 +#define CQ_VC_BARM 0x0c8 +#define CQ_VC_BARM_MASK PPC_BITMASK(21, 37) +#define X_CQ_TAR 0x1e +#define CQ_TAR 0x0f0 +#define CQ_TAR_TBL_AUTOINC PPC_BIT(0) +#define CQ_TAR_TSEL PPC_BITMASK(12, 15) +#define CQ_TAR_TSEL_BLK PPC_BIT(12) +#define CQ_TAR_TSEL_MIG PPC_BIT(13) +#define CQ_TAR_TSEL_VDT PPC_BIT(14) +#define CQ_TAR_TSEL_EDT PPC_BIT(15) +#define CQ_TAR_TSEL_INDEX PPC_BITMASK(26, 31) +#define X_CQ_TDR 0x1f +#define CQ_TDR 0x0f8 +#define CQ_TDR_VDT_VALID PPC_BIT(0) +#define CQ_TDR_VDT_BLK PPC_BITMASK(11, 15) +#define CQ_TDR_VDT_INDEX PPC_BITMASK(28, 31) +#define CQ_TDR_EDT_TYPE PPC_BITMASK(0, 1) +#define CQ_TDR_EDT_INVALID 0 +#define CQ_TDR_EDT_IPI 1 +#define CQ_TDR_EDT_EQ 2 +#define CQ_TDR_EDT_BLK PPC_BITMASK(12, 15) +#define CQ_TDR_EDT_INDEX PPC_BITMASK(26, 31) +#define X_CQ_PBI_CTL 0x20 +#define CQ_PBI_CTL 0x100 +#define CQ_PBI_PC_64K PPC_BIT(5) +#define CQ_PBI_VC_64K PPC_BIT(6) +#define CQ_PBI_LNX_TRIG PPC_BIT(7) +#define CQ_PBI_FORCE_TM_LOCAL PPC_BIT(22) +#define CQ_PBO_CTL 0x108 +#define CQ_AIB_CTL 0x110 +#define X_CQ_RST_CTL 0x23 +#define CQ_RST_CTL 0x118 +#define X_CQ_FIRMASK 0x33 +#define CQ_FIRMASK 0x198 +#define X_CQ_FIRMASK_AND 0x34 +#define CQ_FIRMASK_AND 0x1a0 +#define X_CQ_FIRMASK_OR 0x35 +#define CQ_FIRMASK_OR 0x1a8 + +/* PC LBS1 register offsets 0x400 - 0x800 */ +#define X_PC_TCTXT_CFG 0x100 +#define PC_TCTXT_CFG 0x400 +#define PC_TCTXT_CFG_BLKGRP_EN PPC_BIT(0) +#define PC_TCTXT_CFG_TARGET_EN PPC_BIT(1) +#define PC_TCTXT_CFG_LGS_EN PPC_BIT(2) +#define PC_TCTXT_CFG_STORE_ACK PPC_BIT(3) +#define PC_TCTXT_CFG_HARD_CHIPID_BLK PPC_BIT(8) +#define PC_TCTXT_CHIPID_OVERRIDE PPC_BIT(9) +#define PC_TCTXT_CHIPID PPC_BITMASK(12, 15) +#define PC_TCTXT_INIT_AGE PPC_BITMASK(30, 31) +#define X_PC_TCTXT_TRACK 0x101 +#define PC_TCTXT_TRACK 0x408 +#define PC_TCTXT_TRACK_EN PPC_BIT(0) +#define X_PC_TCTXT_INDIR0 0x104 +#define PC_TCTXT_INDIR0 0x420 +#define PC_TCTXT_INDIR_VALID PPC_BIT(0) +#define PC_TCTXT_INDIR_THRDID PPC_BITMASK(9, 15) +#define X_PC_TCTXT_INDIR1 0x105 +#define PC_TCTXT_INDIR1 0x428 +#define X_PC_TCTXT_INDIR2 0x106 +#define PC_TCTXT_INDIR2 0x430 +#define X_PC_TCTXT_INDIR3 0x107 +#define PC_TCTXT_INDIR3 0x438 +#define X_PC_THREAD_EN_REG0 0x108 +#define PC_THREAD_EN_REG0 0x440 +#define X_PC_THREAD_EN_REG0_SET 0x109 +#define PC_THREAD_EN_REG0_SET 0x448 +#define X_PC_THREAD_EN_REG0_CLR 0x10a +#define PC_THREAD_EN_REG0_CLR 0x450 +#define X_PC_THREAD_EN_REG1 0x10c +#define PC_THREAD_EN_REG1 0x460 +#define X_PC_THREAD_EN_REG1_SET 0x10d +#define PC_THREAD_EN_REG1_SET 0x468 +#define X_PC_THREAD_EN_REG1_CLR 0x10e +#define PC_THREAD_EN_REG1_CLR 0x470 +#define X_PC_GLOBAL_CONFIG 0x110 +#define PC_GLOBAL_CONFIG 0x480 +#define PC_GCONF_INDIRECT PPC_BIT(32) +#define PC_GCONF_CHIPID_OVR PPC_BIT(40) +#define PC_GCONF_CHIPID PPC_BITMASK(44, 47) +#define X_PC_VSD_TABLE_ADDR 0x111 +#define PC_VSD_TABLE_ADDR 0x488 +#define X_PC_VSD_TABLE_DATA 0x112 +#define PC_VSD_TABLE_DATA 0x490 +#define X_PC_AT_KILL 0x116 +#define PC_AT_KILL 0x4b0 +#define PC_AT_KILL_VALID PPC_BIT(0) +#define PC_AT_KILL_BLOCK_ID PPC_BITMASK(27, 31) +#define PC_AT_KILL_OFFSET PPC_BITMASK(48, 60) +#define X_PC_AT_KILL_MASK 0x117 +#define PC_AT_KILL_MASK 0x4b8 + +/* PC LBS2 register offsets */ +#define X_PC_VPC_CACHE_ENABLE 0x161 +#define PC_VPC_CACHE_ENABLE 0x708 +#define PC_VPC_CACHE_EN_MASK PPC_BITMASK(0, 31) +#define X_PC_VPC_SCRUB_TRIG 0x162 +#define PC_VPC_SCRUB_TRIG 0x710 +#define X_PC_VPC_SCRUB_MASK 0x163 +#define PC_VPC_SCRUB_MASK 0x718 +#define PC_SCRUB_VALID PPC_BIT(0) +#define PC_SCRUB_WANT_DISABLE PPC_BIT(1) +#define PC_SCRUB_WANT_INVAL PPC_BIT(2) +#define PC_SCRUB_BLOCK_ID PPC_BITMASK(27, 31) +#define PC_SCRUB_OFFSET PPC_BITMASK(45, 63) +#define X_PC_VPC_CWATCH_SPEC 0x167 +#define PC_VPC_CWATCH_SPEC 0x738 +#define PC_VPC_CWATCH_CONFLICT PPC_BIT(0) +#define PC_VPC_CWATCH_FULL PPC_BIT(8) +#define PC_VPC_CWATCH_BLOCKID PPC_BITMASK(27, 31) +#define PC_VPC_CWATCH_OFFSET PPC_BITMASK(45, 63) +#define X_PC_VPC_CWATCH_DAT0 0x168 +#define PC_VPC_CWATCH_DAT0 0x740 +#define X_PC_VPC_CWATCH_DAT1 0x169 +#define PC_VPC_CWATCH_DAT1 0x748 +#define X_PC_VPC_CWATCH_DAT2 0x16a +#define PC_VPC_CWATCH_DAT2 0x750 +#define X_PC_VPC_CWATCH_DAT3 0x16b +#define PC_VPC_CWATCH_DAT3 0x758 +#define X_PC_VPC_CWATCH_DAT4 0x16c +#define PC_VPC_CWATCH_DAT4 0x760 +#define X_PC_VPC_CWATCH_DAT5 0x16d +#define PC_VPC_CWATCH_DAT5 0x768 +#define X_PC_VPC_CWATCH_DAT6 0x16e +#define PC_VPC_CWATCH_DAT6 0x770 +#define X_PC_VPC_CWATCH_DAT7 0x16f +#define PC_VPC_CWATCH_DAT7 0x778 + +/* VC0 register offsets 0x800 - 0xFFF */ +#define X_VC_GLOBAL_CONFIG 0x200 +#define VC_GLOBAL_CONFIG 0x800 +#define VC_GCONF_INDIRECT PPC_BIT(32) +#define X_VC_VSD_TABLE_ADDR 0x201 +#define VC_VSD_TABLE_ADDR 0x808 +#define X_VC_VSD_TABLE_DATA 0x202 +#define VC_VSD_TABLE_DATA 0x810 +#define VC_IVE_ISB_BLOCK_MODE 0x818 +#define VC_EQD_BLOCK_MODE 0x820 +#define VC_VPS_BLOCK_MODE 0x828 +#define X_VC_IRQ_CONFIG_IPI 0x208 +#define VC_IRQ_CONFIG_IPI 0x840 +#define VC_IRQ_CONFIG_MEMB_EN PPC_BIT(45) +#define VC_IRQ_CONFIG_MEMB_SZ PPC_BITMASK(46, 51) +#define VC_IRQ_CONFIG_HW 0x848 +#define VC_IRQ_CONFIG_CASCADE1 0x850 +#define VC_IRQ_CONFIG_CASCADE2 0x858 +#define VC_IRQ_CONFIG_REDIST 0x860 +#define VC_IRQ_CONFIG_IPI_CASC 0x868 +#define X_VC_AIB_TX_ORDER_TAG2 0x22d +#define VC_AIB_TX_ORDER_TAG2_REL_TF PPC_BIT(20) +#define VC_AIB_TX_ORDER_TAG2 0x890 +#define X_VC_AT_MACRO_KILL 0x23e +#define VC_AT_MACRO_KILL 0x8b0 +#define X_VC_AT_MACRO_KILL_MASK 0x23f +#define VC_AT_MACRO_KILL_MASK 0x8b8 +#define VC_KILL_VALID PPC_BIT(0) +#define VC_KILL_TYPE PPC_BITMASK(14, 15) +#define VC_KILL_IRQ 0 +#define VC_KILL_IVC 1 +#define VC_KILL_SBC 2 +#define VC_KILL_EQD 3 +#define VC_KILL_BLOCK_ID PPC_BITMASK(27, 31) +#define VC_KILL_OFFSET PPC_BITMASK(48, 60) +#define X_VC_EQC_CACHE_ENABLE 0x211 +#define VC_EQC_CACHE_ENABLE 0x908 +#define VC_EQC_CACHE_EN_MASK PPC_BITMASK(0, 15) +#define X_VC_EQC_SCRUB_TRIG 0x212 +#define VC_EQC_SCRUB_TRIG 0x910 +#define X_VC_EQC_SCRUB_MASK 0x213 +#define VC_EQC_SCRUB_MASK 0x918 +#define X_VC_EQC_CWATCH_SPEC 0x215 +#define VC_EQC_CONFIG 0x920 +#define X_VC_EQC_CONFIG 0x214 +#define VC_EQC_CONF_SYNC_IPI PPC_BIT(32) +#define VC_EQC_CONF_SYNC_HW PPC_BIT(33) +#define VC_EQC_CONF_SYNC_ESC1 PPC_BIT(34) +#define VC_EQC_CONF_SYNC_ESC2 PPC_BIT(35) +#define VC_EQC_CONF_SYNC_REDI PPC_BIT(36) +#define VC_EQC_CONF_EQP_INTERLEAVE PPC_BIT(38) +#define VC_EQC_CONF_ENABLE_END_s_BIT PPC_BIT(39) +#define VC_EQC_CONF_ENABLE_END_u_BIT PPC_BIT(40) +#define VC_EQC_CONF_ENABLE_END_c_BIT PPC_BIT(41) +#define VC_EQC_CONF_ENABLE_MORE_QSZ PPC_BIT(42) +#define VC_EQC_CONF_SKIP_ESCALATE PPC_BIT(43) +#define VC_EQC_CWATCH_SPEC 0x928 +#define VC_EQC_CWATCH_CONFLICT PPC_BIT(0) +#define VC_EQC_CWATCH_FULL PPC_BIT(8) +#define VC_EQC_CWATCH_BLOCKID PPC_BITMASK(28, 31) +#define VC_EQC_CWATCH_OFFSET PPC_BITMASK(40, 63) +#define X_VC_EQC_CWATCH_DAT0 0x216 +#define VC_EQC_CWATCH_DAT0 0x930 +#define X_VC_EQC_CWATCH_DAT1 0x217 +#define VC_EQC_CWATCH_DAT1 0x938 +#define X_VC_EQC_CWATCH_DAT2 0x218 +#define VC_EQC_CWATCH_DAT2 0x940 +#define X_VC_EQC_CWATCH_DAT3 0x219 +#define VC_EQC_CWATCH_DAT3 0x948 +#define X_VC_IVC_SCRUB_TRIG 0x222 +#define VC_IVC_SCRUB_TRIG 0x990 +#define X_VC_IVC_SCRUB_MASK 0x223 +#define VC_IVC_SCRUB_MASK 0x998 +#define X_VC_SBC_SCRUB_TRIG 0x232 +#define VC_SBC_SCRUB_TRIG 0xa10 +#define X_VC_SBC_SCRUB_MASK 0x233 +#define VC_SBC_SCRUB_MASK 0xa18 +#define VC_SCRUB_VALID PPC_BIT(0) +#define VC_SCRUB_WANT_DISABLE PPC_BIT(1) +#define VC_SCRUB_WANT_INVAL PPC_BIT(2)/* EQC and SBC only */ +#define VC_SCRUB_BLOCK_ID PPC_BITMASK(28, 31) +#define VC_SCRUB_OFFSET PPC_BITMASK(40, 63) +#define X_VC_IVC_CACHE_ENABLE 0x221 +#define VC_IVC_CACHE_ENABLE 0x988 +#define VC_IVC_CACHE_EN_MASK PPC_BITMASK(0, 15) +#define X_VC_SBC_CACHE_ENABLE 0x231 +#define VC_SBC_CACHE_ENABLE 0xa08 +#define VC_SBC_CACHE_EN_MASK PPC_BITMASK(0, 15) +#define VC_IVC_CACHE_SCRUB_TRIG 0x990 +#define VC_IVC_CACHE_SCRUB_MASK 0x998 +#define VC_SBC_CACHE_ENABLE 0xa08 +#define VC_SBC_CACHE_SCRUB_TRIG 0xa10 +#define VC_SBC_CACHE_SCRUB_MASK 0xa18 +#define VC_SBC_CONFIG 0xa20 +#define X_VC_SBC_CONFIG 0x234 +#define VC_SBC_CONF_CPLX_CIST PPC_BIT(44) +#define VC_SBC_CONF_CIST_BOTH PPC_BIT(45) +#define VC_SBC_CONF_NO_UPD_PRF PPC_BIT(59) + +/* VC1 register offsets */ + +/* VSD Table address register definitions (shared) */ +#define VST_ADDR_AUTOINC PPC_BIT(0) +#define VST_TABLE_SELECT PPC_BITMASK(13, 15) +#define VST_TSEL_IVT 0 +#define VST_TSEL_SBE 1 +#define VST_TSEL_EQDT 2 +#define VST_TSEL_VPDT 3 +#define VST_TSEL_IRQ 4/* VC only */ +#define VST_TABLE_BLOCK PPC_BITMASK(27, 31) + +/* Number of queue overflow pages */ +#define VC_QUEUE_OVF_COUNT 6 + +/* Bits in a VSD entry. +* +* Note: the address is naturally aligned, we don't use a PPC_BITMASK, +* but just a mask to apply to the address before OR'ing it in. +* +* Note: VSD_FIRMWARE is a SW bit ! It hijacks an unused bit in the +* VSD and is only meant to be used in indirect mode ! +*/ +#define VSD_MODE PPC_BITMASK(0, 1) +#define VSD_MODE_SHARED 1 +#define VSD_MODE_EXCLUSIVE 2 +#define VSD_MODE_FORWARD 3 +#define VSD_ADDRESS_MASK 0x0ffffffffffff000ull +#define VSD_MIGRATION_REG PPC_BITMASK(52, 55) +#define VSD_INDIRECT PPC_BIT(56) +#define VSD_TSIZE PPC_BITMASK(59, 63) +#define VSD_FIRMWARE PPC_BIT(2)/* Read warning above */ + +#define VC_EQC_SYNC_MASK \ + (VC_EQC_CONF_SYNC_IPI | \ + VC_EQC_CONF_SYNC_HW | \ + VC_EQC_CONF_SYNC_ESC1 | \ + VC_EQC_CONF_SYNC_ESC2 | \ + VC_EQC_CONF_SYNC_REDI) + + +#endif /* PPC_PNV_XIVE_REGS_H */
include/hw/ppc/pnv.h +22 -0
@@ -25,6 +25,7 @@#include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_psi.h" #include "hw/ppc/pnv_occ.h" +#include "hw/ppc/pnv_xive.h" #define TYPE_PNV_CHIP "pnv-chip"#define PNV_CHIP (obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
@@ -61,6 +62,8 @@ typedef struct PnvChip {PnvLpcController lpc;PnvPsi psi;PnvOCC occ; + +PnvXive *xive; } PnvChip; typedef enum PnvPhysMapType {
@@ -68,6 +71,10 @@ typedef enum PnvPhysMapType {PNV_MAP_ICP ,PNV_MAP_PSIHB ,PNV_MAP_PSIHB_FSP , +PNV_MAP_XIVE_VC , +PNV_MAP_XIVE_PC , +PNV_MAP_XIVE_IC , +PNV_MAP_XIVE_TM , } PnvPhysMapType; typedef struct PnvPhysMapEntry {
@@ -210,4 +217,19 @@ static inline uint64_t pnv_map_base(const PnvChip *chip, PnvPhysMapType type)#define PNV_PSIHB_FSP_SIZE (chip) pnv_map_size(chip, PNV_MAP_PSIHB_FSP)#define PNV_PSIHB_FSP_BASE (chip) pnv_map_base(chip, PNV_MAP_PSIHB_FSP) +/* +* POWER9 MMIO base addresses +*/ +#define PNV_XIVE_VC_SIZE (chip) pnv_map_size(chip, PNV_MAP_XIVE_VC) +#define PNV_XIVE_VC_BASE (chip) pnv_map_base(chip, PNV_MAP_XIVE_VC) + +#define PNV_XIVE_PC_SIZE (chip) pnv_map_size(chip, PNV_MAP_XIVE_PC) +#define PNV_XIVE_PC_BASE (chip) pnv_map_base(chip, PNV_MAP_XIVE_PC) + +#define PNV_XIVE_IC_SIZE (chip) pnv_map_size(chip, PNV_MAP_XIVE_IC) +#define PNV_XIVE_IC_BASE (chip) pnv_map_base(chip, PNV_MAP_XIVE_IC) + +#define PNV_XIVE_TM_SIZE (chip) pnv_map_size(chip, PNV_MAP_XIVE_TM) +#define PNV_XIVE_TM_BASE (chip) pnv_map_base(chip, PNV_MAP_XIVE_TM) +#endif /* _PPC_PNV_H */
include/hw/ppc/pnv_xive.h new file +92 -0
92 lines not on this page · raw message
include/hw/ppc/pnv_xscom.h +3 -0
@@ -73,6 +73,9 @@ typedef struct PnvXScomInterfaceClass {#define PNV_XSCOM_OCC_BASE 0x0066000#define PNV_XSCOM_OCC_SIZE 0x6000 +#define PNV_XSCOM_XIVE_BASE 0x5013000 +#define PNV_XSCOM_XIVE_SIZE 0x300 +extern void pnv_xscom_realize (PnvChip *chip,Error **errp);extern int pnv_dt_xscom (PnvChip *chip,void *fdt,int offset);
include/hw/ppc/xive.h +1 -0
@@ -235,6 +235,7 @@ int xive_router_get_vp(XiveRouter *xrtr, uint8_t vp_blk, uint32_t vp_idx, XiveVP *vp);int xive_router_set_vp (XiveRouter *xrtr,uint8_t vp_blk,uint32_t vp_idx,XiveVP *vp); +void xive_router_notify (XiveFabric *xf,uint32_t lisn);/* * XIVE EQ ESBs
hw/intc/pnv_xive.c new file +1485 -0
1,485 lines not on this page · raw message
hw/intc/xive.c +59 -4
115 lines not on this page · raw message
hw/ppc/pnv.c +35 -7
81 lines not on this page · raw message
hw/ppc/pnv_core.c +22 -6
@@ -121,11 +121,13 @@ static const MemoryRegionOps pnv_core_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static void pnv_core_realize_child (Object *child,XICSFabric *xi,Error **errp) +static void pnv_core_realize_child (Object *child,XICSFabric *xi,PnvChip *chip, +Error **errp) {Error *local_err =NULL ;CPUState *cs =CPU (child);PowerPCCPU *cpu =POWERPC_CPU (cs); +PnvMachineState *pnv =PNV_MACHINE (xi);object_property_set_bool (child, true,"realized" , &local_err);if (local_err) {
@@ -133,13 +135,18 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp)return ; } - cpu->intc =icp_create (child,TYPE_PNV_ICP , xi, &local_err); +pnv_cpu_init (cpu, &local_err);if (local_err) {error_propagate (errp, local_err);return ; } -pnv_cpu_init (cpu, &local_err); +if (!pnv_is_power9 (pnv)) { + cpu->intc =icp_create (child,TYPE_PNV_ICP , xi, &local_err); + }else { + cpu->intc =xive_tctx_create (child,TYPE_XIVE_TCTX , +XIVE_ROUTER (chip->xive), &local_err); + }if (local_err) {error_propagate (errp, local_err);return ;
@@ -157,11 +164,19 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)int i, j;char name[32 ];Object *xi; +Object *chip; xi =object_property_get_link (OBJECT (dev),"xics" , &local_err);if (!xi) { -error_setg (errp,"%s: required link 'xics' not found: %s" , - __func__,error_get_pretty (local_err)); +error_propagate (errp, local_err); +error_prepend (errp,"required link 'xics' not found: " ); +return ; + } + + chip =object_property_get_link (OBJECT (dev),"chip" , &local_err); +if (!chip) { +error_propagate (errp, local_err); +error_prepend (errp,"required link 'chip' not found: " );return ; }
@@ -184,7 +199,8 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)for (j =0 ; j < cc->nr_threads; j++) { obj = pc->threads + j * size; -pnv_core_realize_child (obj,XICS_FABRIC (xi), &local_err); +pnv_core_realize_child (obj,XICS_FABRIC (xi),PNV_CHIP (chip), + &local_err);if (local_err) { goto err; }
hw/intc/Makefile.objs +1 -1
@@ -40,7 +40,7 @@ obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_XIVE) += xive.o obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o spapr_xive_hcall.o obj-$(CONFIG_XIVE_KVM) += spapr_xive_kvm.o -obj-$(CONFIG_POWERNV) += xics_pnv.o +obj-$(CONFIG_POWERNV) += xics_pnv.o pnv_xive.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
Signature · 1 line
2.13.6