Skip to contentSkip to conversation

ppc: support for the XIVE interrupt controller (POWER9)

PATCH Superseded Cédric Le Goater 1 participant 29 messages Jun 7, 2018

v4 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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
index 39a14980d397..4fd97ffe4c6e 100644
@@ -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
#2 lore raw

PATCH v4 2/28 spapr: introduce a generic IRQ frontend to the machine

In reply to Cédric Le Goater

This 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
index 3388750fc795..aba1892f2bd0 100644
@@ -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
index 86836f0626dc..f131b8c6fd1b 100644
@@ -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
index 4fd97ffe4c6e..cca4169fa10b 100644
@@ -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
index 28bb3b849b9b..d19b28142a13 100644
@@ -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
index 86d82a6ec3ac..4fe3b7804d43 100644
@@ -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
#3 lore raw

PATCH v4 3/28 spapr: introduce a new IRQ backend using fixed IRQ number ranges

In reply to Cédric Le Goater

The 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
index aba1892f2bd0..bd256fbc9158 100644
@@ -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
index 67ec7ff162a6..dd9c4038d5b6 100644
@@ -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
index fd37ca4803eb..c097a7093e62 100644
@@ -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
#4 lore raw

PATCH v4 4/28 ppc/xive: introduce a XIVE interrupt source model

In reply to Cédric Le Goater

The 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
index b94af6c7c62a..c6d13e757977 100644
@@ -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
index 0e9963f5eecc..72a46ed91c31 100644
@@ -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
#5 lore raw

PATCH v4 5/28 ppc/xive: add support for the LSI interrupt sources

In reply to Cédric Le Goater

The 'sent' status of the LSI interrupt source is modeled with the 'P' bit of the ESB and the assertion status of the source is maintained in an array under the main sPAPRXive object. The type of the source is stored in the same array for practical reasons.

---
 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
index 5fec4b08705d..e118acd59f1e 100644
@@ -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
#6 lore raw

PATCH v4 6/28 ppc/xive: introduce the XiveFabric interface

In reply to Cédric Le Goater

The 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
index e118acd59f1e..be93fae6317b 100644
@@ -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
index 3ad8c151b9dc..3f6fcb358f83 100644
@@ -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
#7 lore raw

PATCH v4 7/28 ppc/xive: introduce the XiveRouter model

In reply to Cédric Le Goater

The 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
index be93fae6317b..13c414bf7d55 100644
@@ -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
new file mode 100644
index 000000000000..74420030111a
@@ -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
#8 lore raw

PATCH v4 8/28 ppc/xive: introduce the XIVE Event Queues

In reply to Cédric Le Goater

The 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
index 13c414bf7d55..fc2ed7319f0f 100644
@@ -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
#9 lore raw

PATCH v4 9/28 ppc/xive: add support for the EQ Event State buffers

In reply to Cédric Le Goater

The 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
index fc2ed7319f0f..e5f6800b50d3 100644
@@ -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
#10 lore raw

PATCH v4 10/28 ppc/xive: introduce the XIVE interrupt thread context

In reply to Cédric Le Goater

There 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
index e5f6800b50d3..280bd5a1e6ee 100644
@@ -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
#11 lore raw

PATCH v4 11/28 ppc/xive: introduce a simplified XIVE presenter

In reply to Cédric Le Goater

The 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
index 280bd5a1e6ee..e29b52eeb91f 100644
@@ -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
index a5473bb2d01b..b438184a88b8 100644
@@ -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
#12 lore raw

PATCH v4 12/28 ppc/xive: notify the CPU when the interrupt priority is more privileged

In reply to Cédric Le Goater

After 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
index 6ea9441852e3..f249ffc8943e 100644
@@ -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
#13 lore raw

PATCH v4 13/28 spapr/xive: introduce a XIVE interrupt controller

In reply to Cédric Le Goater

sPAPRXive 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
index c6d13e757977..f8d34722931d 100644
@@ -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
index 72a46ed91c31..301a8e972d91 100644
@@ -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
#14 lore raw

PATCH v4 14/28 spapr/xive: use the VCPU id as a VP identifier in the OS CAM.

In reply to Cédric Le Goater

For 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
index 32733270f734..be1163a8f272 100644
@@ -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
index f249ffc8943e..671ea1c6c36b 100644
@@ -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
#15 lore raw

PATCH v4 15/28 spapr: initialize VSMT before initializing the IRQ backend

In reply to Cédric Le Goater

We 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
index c097a7093e62..ae915a3b4803 100644
@@ -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
#16 lore raw

PATCH v4 16/28 spapr: introdude a new machine IRQ backend for XIVE

In reply to Cédric Le Goater

The 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
index bd256fbc9158..fd0e32c4b32c 100644
@@ -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
index dd9c4038d5b6..aa41c487b705 100644
@@ -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
index ae915a3b4803..156feff6e3fa 100644
@@ -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
#17 lore raw

PATCH v4 17/28 spapr: add hcalls support for the XIVE exploitation interrupt mode

In reply to Cédric Le Goater

The 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
index fd0e32c4b32c..3c7bae874f91 100644
@@ -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
index be1163a8f272..5dedb9e5c7c0 100644
@@ -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
index b5c3e7b197b6..c9a3c9694a91 100644
@@ -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
index 301a8e972d91..eacd26836ebf 100644
@@ -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
#18 lore raw

PATCH v4 18/28 spapr: add device tree support for the XIVE exploitation mode

In reply to Cédric Le Goater

The 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
index aa41c487b705..b070276c9abb 100644
@@ -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
index 5dedb9e5c7c0..3cbf8dbefb87 100644
@@ -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
index 156feff6e3fa..3340264e4cfb 100644
@@ -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
index c9a3c9694a91..be71998777c2 100644
@@ -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
#19 lore raw

PATCH v4 19/28 spapr: allocate the interrupt thread context under the CPU core

In reply to Cédric Le Goater

Each 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
index 3c7bae874f91..223837882496 100644
@@ -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
index b070276c9abb..8046cbd83d61 100644
@@ -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
index e29b52eeb91f..378bd61c6d18 100644
@@ -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
index 671ea1c6c36b..8d86f739522d 100644
@@ -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
index f3e9b879b251..fe9bcfdf01c8 100644
@@ -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
index be71998777c2..266f7db3be7b 100644
@@ -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
#20 lore raw

PATCH v4 20/28 spapr: introduce a 'pseries-3.0-xive' QEMU machine

In reply to Cédric Le Goater

The 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
index 8046cbd83d61..85829928a9c4 100644
@@ -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
index 3340264e4cfb..2774b53f169e 100644
@@ -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
index 266f7db3be7b..745c78024d6f 100644
@@ -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
#21 lore raw

PATCH v4 21/28 spapr: add classes for the XIVE models

In reply to Cédric Le Goater

The 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
index 3cbf8dbefb87..1284784f1152 100644
@@ -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
index 378bd61c6d18..d943770efd9d 100644
@@ -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
index 222c1266a547..91f9b28ebcc4 100644
@@ -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
#22 lore raw

PATCH v4 22/28 target/ppc/kvm: add Linux KVM definitions for XIVE

In reply to Cédric Le Goater

These 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
index 833ed9a16adf..27f3dae65761 100644
@@ -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
index cdb148e959eb..634a24e92b03 100644
@@ -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
index e2840e1d33e8..52f25bfb03b9 100644
@@ -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
index 2c0c34e125e4..09e4c1efdf79 100644
@@ -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
#23 lore raw

PATCH v4 23/28 spapr/xive: add common realize routine for KVM

In reply to Cédric Le Goater

The 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
index 1284784f1152..4aa04bc48ccb 100644
@@ -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
index d943770efd9d..7a54b3ce594f 100644
@@ -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
index 91f9b28ebcc4..2812b1a1a030 100644
@@ -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
index 5cf9fc4e1cb3..4d073c37bbda 100644
@@ -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
#24 lore raw

PATCH v4 24/28 spapr/xive: add KVM support

In reply to Cédric Le Goater

This 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
index f8d34722931d..ac7e3af2473c 100644
@@ -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
index 4aa04bc48ccb..f3e9208ad1f3 100644
@@ -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
index 7a54b3ce594f..a2c1cc6b5126 100644
@@ -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
index 3747110f951a..b707c31b1b0c 100644
@@ -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
index 2812b1a1a030..4eebba5ab8e7 100644
@@ -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
index 745c78024d6f..a5d89c6ac55f 100644
@@ -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
index eacd26836ebf..dd4d69db2bdd 100644
@@ -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
#25 lore raw

PATCH v4 25/28 spapr: fix XICS migration

In reply to Cédric Le Goater

Extend 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
index 85829928a9c4..1ca35ffc13cd 100644
@@ -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
index 2774b53f169e..025d5af84def 100644
@@ -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
index a5d89c6ac55f..5f445e17d125 100644
@@ -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
#26 lore raw

PATCH v4 26/28 pnv: add a physical mapping array describing MMIO ranges in each chip

In reply to Cédric Le Goater

Based 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
index 90759240a7b1..ffa4a0899705 100644
@@ -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
index 5b969127c303..882b5d4b9f99 100644
@@ -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
index 46fae41f32b0..20ffc233174c 100644
@@ -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
#27 lore raw

PATCH v4 27/28 ppc: externalize ppc_get_vcpu_by_pir()

In reply to Cédric Le Goater

We 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
index ff0ac306be72..c8e54544e563 100644
@@ -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
index 77caaea64b2f..e7bc4534e63d 100644
@@ -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
index ec4be25f4994..9292f986eba7 100644
@@ -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
#28 lore raw

PATCH v4 28/28 ppc/pnv: add XIVE support

In reply to Cédric Le Goater

This 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
new file mode 100644
index 000000000000..509d5a18cdde
@@ -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
index ffa4a0899705..cf86ab816f22 100644
@@ -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
index 255b26a5aaf6..f4b1649ffffa 100644
@@ -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
index a2c1cc6b5126..29c780605c33 100644
@@ -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
index cbb64ad9e7e0..3a8d55342308 100644
@@ -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
index dd4d69db2bdd..145bfaf44014 100644
@@ -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