mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.1-20190529' into staging
ppc patch queue 2019-05-29
Next pull request against qemu-4.1. Highlights:
* KVM accelerated support for the XIVE interrupt controller in PAPR
guests
* A number of TCG vector fixes
* Fixes for the PReP / 40p machine
* Improvements to make check-tcg test coverage
Other than that it's just a bunch of assorted fixes, cleanups and
minor improvements.
This supersedes both the pull request dated 2019-05-21 and the one
dated 2019-05-22. I've dropped one hunk which I think may have caused
the check-tcg failure that Peter saw (by enabling the ppc64abi32
build, which I think has been broken for ages). I'm not entirely
certain, since I haven't reproduced exactly the same failure.
# gpg: Signature made Wed 29 May 2019 07:49:04 BST
# gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full]
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full]
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full]
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown]
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-4.1-20190529: (44 commits)
ppc/pnv: add dummy XSCOM registers for PRD initialization
ppc/pnv: introduce new skiboot platform properties
spapr: Don't migrate the hpt_maxpagesize cap to older machine types
spapr: change default interrupt mode to 'dual'
spapr/xive: fix multiple resets when using the 'dual' interrupt mode
docs: provide documentation on the POWER9 XIVE interrupt controller
spapr/irq: add KVM support to the 'dual' machine
ppc/xics: fix irq priority in ics_set_irq_type()
spapr/irq: initialize the IRQ device only once
spapr/irq: introduce a spapr_irq_init_device() helper
spapr: check for the activation of the KVM IRQ device
spapr: introduce routines to delete the KVM IRQ device
sysbus: add a sysbus_mmio_unmap() helper
spapr/xive: activate KVM support
spapr/xive: add migration support for KVM
spapr/xive: introduce a VM state change handler
spapr/xive: add state synchronization with KVM
spapr/xive: add hcall support when under KVM
spapr/xive: add KVM support
spapr: Print out extra hints when CAS negotiation of interrupt mode fails
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -1720,6 +1720,7 @@ L: qemu-ppc@nongnu.org
|
||||
S: Supported
|
||||
F: hw/*/*xive*
|
||||
F: include/hw/*/*xive*
|
||||
F: docs/*/*xive*
|
||||
|
||||
Subsystems
|
||||
----------
|
||||
|
||||
@@ -198,7 +198,7 @@ supported_kvm_target() {
|
||||
i386:i386 | i386:x86_64 | i386:x32 | \
|
||||
x86_64:i386 | x86_64:x86_64 | x86_64:x32 | \
|
||||
mips:mips | mipsel:mips | \
|
||||
ppc:ppc | ppc64:ppc | ppc:ppc64 | ppc64:ppc64 | \
|
||||
ppc:ppc | ppc64:ppc | ppc:ppc64 | ppc64:ppc64 | ppc64:ppc64le | \
|
||||
s390x:s390x)
|
||||
return 0
|
||||
;;
|
||||
@@ -502,8 +502,11 @@ cross_cc_arm="arm-linux-gnueabihf-gcc"
|
||||
cross_cc_cflags_armeb="-mbig-endian"
|
||||
cross_cc_i386="i386-pc-linux-gnu-gcc"
|
||||
cross_cc_cflags_i386=""
|
||||
cross_cc_powerpc="powerpc-linux-gnu-gcc"
|
||||
cross_cc_powerpc="powerpc-linux-gnu-gcc"
|
||||
cross_cc_ppc="powerpc-linux-gnu-gcc"
|
||||
cross_cc_cflags_ppc="-m32"
|
||||
cross_cc_ppc64="powerpc-linux-gnu-gcc"
|
||||
cross_cc_cflags_ppc64="-m64"
|
||||
cross_cc_ppc64le="powerpc64le-linux-gnu-gcc"
|
||||
|
||||
enabled_cross_compilers=""
|
||||
|
||||
@@ -700,7 +703,11 @@ elif check_define __sparc__ ; then
|
||||
fi
|
||||
elif check_define _ARCH_PPC ; then
|
||||
if check_define _ARCH_PPC64 ; then
|
||||
cpu="ppc64"
|
||||
if check_define _LITTLE_ENDIAN ; then
|
||||
cpu="ppc64le"
|
||||
else
|
||||
cpu="ppc64"
|
||||
fi
|
||||
else
|
||||
cpu="ppc"
|
||||
fi
|
||||
@@ -731,10 +738,14 @@ ARCH=
|
||||
# Note that this case should only have supported host CPUs, not guests.
|
||||
case "$cpu" in
|
||||
ppc|ppc64|s390|s390x|sparc64|x32|riscv32|riscv64)
|
||||
cpu="$cpu"
|
||||
supported_cpu="yes"
|
||||
eval "cross_cc_${cpu}=\$host_cc"
|
||||
;;
|
||||
ppc64le)
|
||||
ARCH="ppc64"
|
||||
supported_cpu="yes"
|
||||
cross_cc_ppc64le=$host_cc
|
||||
;;
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
cpu="i386"
|
||||
supported_cpu="yes"
|
||||
@@ -1538,44 +1549,44 @@ case "$cpu" in
|
||||
ppc)
|
||||
CPU_CFLAGS="-m32"
|
||||
LDFLAGS="-m32 $LDFLAGS"
|
||||
cross_cc_powerpc=$cc
|
||||
cross_cc_cflags_powerpc=$CPU_CFLAGS
|
||||
cross_cc_ppc=$cc
|
||||
cross_cc_cflags_ppc="$CPU_CFLAGS"
|
||||
;;
|
||||
ppc64)
|
||||
CPU_CFLAGS="-m64"
|
||||
LDFLAGS="-m64 $LDFLAGS"
|
||||
cross_cc_ppc64=$cc
|
||||
cross_cc_cflags_ppc64=$CPU_CFLAGS
|
||||
cross_cc_cflags_ppc64="$CPU_CFLAGS"
|
||||
;;
|
||||
sparc)
|
||||
CPU_CFLAGS="-m32 -mv8plus -mcpu=ultrasparc"
|
||||
LDFLAGS="-m32 -mv8plus $LDFLAGS"
|
||||
cross_cc_sparc=$cc
|
||||
cross_cc_cflags_sparc=$CPU_CFLAGS
|
||||
cross_cc_cflags_sparc="$CPU_CFLAGS"
|
||||
;;
|
||||
sparc64)
|
||||
CPU_CFLAGS="-m64 -mcpu=ultrasparc"
|
||||
LDFLAGS="-m64 $LDFLAGS"
|
||||
cross_cc_sparc64=$cc
|
||||
cross_cc_cflags_sparc64=$CPU_CFLAGS
|
||||
cross_cc_cflags_sparc64="$CPU_CFLAGS"
|
||||
;;
|
||||
s390)
|
||||
CPU_CFLAGS="-m31"
|
||||
LDFLAGS="-m31 $LDFLAGS"
|
||||
cross_cc_s390=$cc
|
||||
cross_cc_cflags_s390=$CPU_CFLAGS
|
||||
cross_cc_cflags_s390="$CPU_CFLAGS"
|
||||
;;
|
||||
s390x)
|
||||
CPU_CFLAGS="-m64"
|
||||
LDFLAGS="-m64 $LDFLAGS"
|
||||
cross_cc_s390x=$cc
|
||||
cross_cc_cflags_s390x=$CPU_CFLAGS
|
||||
cross_cc_cflags_s390x="$CPU_CFLAGS"
|
||||
;;
|
||||
i386)
|
||||
CPU_CFLAGS="-m32"
|
||||
LDFLAGS="-m32 $LDFLAGS"
|
||||
cross_cc_i386=$cc
|
||||
cross_cc_cflags_i386=$CPU_CFLAGS
|
||||
cross_cc_cflags_i386="$CPU_CFLAGS"
|
||||
;;
|
||||
x86_64)
|
||||
# ??? Only extremely old AMD cpus do not have cmpxchg16b.
|
||||
@@ -1584,13 +1595,13 @@ case "$cpu" in
|
||||
CPU_CFLAGS="-m64 -mcx16"
|
||||
LDFLAGS="-m64 $LDFLAGS"
|
||||
cross_cc_x86_64=$cc
|
||||
cross_cc_cflags_x86_64=$CPU_CFLAGS
|
||||
cross_cc_cflags_x86_64="$CPU_CFLAGS"
|
||||
;;
|
||||
x32)
|
||||
CPU_CFLAGS="-mx32"
|
||||
LDFLAGS="-mx32 $LDFLAGS"
|
||||
cross_cc_i386=$cc
|
||||
cross_cc_cflags_i386=$CPU_CFLAGS
|
||||
cross_cc_cflags_i386="$CPU_CFLAGS"
|
||||
;;
|
||||
# No special flags required for other host CPUs
|
||||
esac
|
||||
@@ -6198,7 +6209,7 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test "$cpu" = "ppc64" && test "$targetos" != "Darwin" ; then
|
||||
if test "$ARCH" = "ppc64" && test "$targetos" != "Darwin" ; then
|
||||
roms="$roms spapr-rtas"
|
||||
fi
|
||||
|
||||
@@ -7392,7 +7403,7 @@ if test "$linux" = "yes" ; then
|
||||
i386|x86_64|x32)
|
||||
linux_arch=x86
|
||||
;;
|
||||
ppc|ppc64)
|
||||
ppc|ppc64|ppc64le)
|
||||
linux_arch=powerpc
|
||||
;;
|
||||
s390x)
|
||||
@@ -7553,7 +7564,8 @@ case "$target_name" in
|
||||
;;
|
||||
ppc)
|
||||
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
|
||||
target_compiler=$cross_cc_powerpc
|
||||
target_compiler=$cross_cc_ppc
|
||||
target_compiler_cflags="$cross_cc_cflags_ppc"
|
||||
;;
|
||||
ppc64)
|
||||
TARGET_BASE_ARCH=ppc
|
||||
@@ -7561,6 +7573,7 @@ case "$target_name" in
|
||||
mttcg=yes
|
||||
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml"
|
||||
target_compiler=$cross_cc_ppc64
|
||||
target_compiler_cflags="$cross_cc_cflags_ppc64"
|
||||
;;
|
||||
ppc64le)
|
||||
TARGET_ARCH=ppc64
|
||||
|
||||
@@ -12,4 +12,5 @@ Welcome to QEMU's documentation!
|
||||
|
||||
interop/index
|
||||
devel/index
|
||||
specs/index
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
. This is the top level page for the 'specs' manual
|
||||
|
||||
|
||||
QEMU full-system emulation guest hardware specifications
|
||||
========================================================
|
||||
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
xive
|
||||
@@ -0,0 +1,174 @@
|
||||
XIVE for sPAPR (pseries machines)
|
||||
=================================
|
||||
|
||||
The POWER9 processor comes with a new interrupt controller
|
||||
architecture, called XIVE as "eXternal Interrupt Virtualization
|
||||
Engine". It supports a larger number of interrupt sources and offers
|
||||
virtualization features which enables the HW to deliver interrupts
|
||||
directly to virtual processors without hypervisor assistance.
|
||||
|
||||
A QEMU ``pseries`` machine (which is PAPR compliant) using POWER9
|
||||
processors can run under two interrupt modes:
|
||||
|
||||
- *Legacy Compatibility Mode*
|
||||
|
||||
the hypervisor provides identical interfaces and similar
|
||||
functionality to PAPR+ Version 2.7. This is the default mode
|
||||
|
||||
It is also referred as *XICS* in QEMU.
|
||||
|
||||
- *XIVE native exploitation mode*
|
||||
|
||||
the hypervisor provides new interfaces to manage the XIVE control
|
||||
structures, and provides direct control for interrupt management
|
||||
through MMIO pages.
|
||||
|
||||
Which interrupt modes can be used by the machine is negotiated with
|
||||
the guest O/S during the Client Architecture Support negotiation
|
||||
sequence. The two modes are mutually exclusive.
|
||||
|
||||
Both interrupt mode share the same IRQ number space. See below for the
|
||||
layout.
|
||||
|
||||
CAS Negotiation
|
||||
---------------
|
||||
|
||||
QEMU advertises the supported interrupt modes in the device tree
|
||||
property "ibm,arch-vec-5-platform-support" in byte 23 and the OS
|
||||
Selection for XIVE is indicated in the "ibm,architecture-vec-5"
|
||||
property byte 23.
|
||||
|
||||
The interrupt modes supported by the machine depend on the CPU type
|
||||
(POWER9 is required for XIVE) but also on the machine property
|
||||
``ic-mode`` which can be set on the command line. It can take the
|
||||
following values: ``xics``, ``xive``, ``dual`` and currently ``xics``
|
||||
is the default but it may change in the future.
|
||||
|
||||
The choosen interrupt mode is activated after a reconfiguration done
|
||||
in a machine reset.
|
||||
|
||||
XIVE Device tree properties
|
||||
---------------------------
|
||||
|
||||
The properties for the PAPR interrupt controller node when the *XIVE
|
||||
native exploitation mode* is selected shoud contain:
|
||||
|
||||
- ``device_type``
|
||||
|
||||
value should be "power-ivpe".
|
||||
|
||||
- ``compatible``
|
||||
|
||||
value should be "ibm,power-ivpe".
|
||||
|
||||
- ``reg``
|
||||
|
||||
contains the base address and size of the thread interrupt
|
||||
managnement areas (TIMA), 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.
|
||||
|
||||
The root node also exports :
|
||||
|
||||
- ``ibm,plat-res-int-priorities``
|
||||
|
||||
contains a list of priorities that the hypervisor has reserved for
|
||||
its own use.
|
||||
|
||||
IRQ number space
|
||||
----------------
|
||||
|
||||
IRQ Number space of the ``pseries`` machine is 8K wide and is the same
|
||||
for both interrupt mode. The different ranges are defined as follow :
|
||||
|
||||
- ``0x0000 .. 0x0FFF`` 4K CPU IPIs (only used under XIVE)
|
||||
- ``0x1000 .. 0x1000`` 1 EPOW
|
||||
- ``0x1001 .. 0x1001`` 1 HOTPLUG
|
||||
- ``0x1100 .. 0x11FF`` 256 VIO devices
|
||||
- ``0x1200 .. 0x127F`` 32 PHBs devices
|
||||
- ``0x1280 .. 0x12FF`` unused
|
||||
- ``0x1300 .. 0x1FFF`` PHB MSIs
|
||||
|
||||
Monitoring XIVE
|
||||
---------------
|
||||
|
||||
The state of the XIVE interrupt controller can be queried through the
|
||||
monitor commands ``info pic``. The output comes in two parts.
|
||||
|
||||
First, the state of the thread interrupt context registers is dumped
|
||||
for each CPU :
|
||||
|
||||
::
|
||||
|
||||
(qemu) info pic
|
||||
CPU[0000]: QW NSR CPPR IPB LSMFB ACK# INC AGE PIPR W2
|
||||
CPU[0000]: USER 00 00 00 00 00 00 00 00 00000000
|
||||
CPU[0000]: OS 00 ff 00 00 ff 00 ff ff 80000400
|
||||
CPU[0000]: POOL 00 00 00 00 00 00 00 00 00000000
|
||||
CPU[0000]: PHYS 00 00 00 00 00 00 00 ff 00000000
|
||||
...
|
||||
|
||||
In the case of a ``pseries`` machine, QEMU acts as the hypervisor and only
|
||||
the O/S and USER register rings make sense. ``W2`` contains the vCPU CAM
|
||||
line which is set to the VP identifier.
|
||||
|
||||
Then comes the routing information which aggregates the EAS and the
|
||||
END configuration:
|
||||
|
||||
::
|
||||
|
||||
...
|
||||
LISN PQ EISN CPU/PRIO EQ
|
||||
00000000 MSI -- 00000010 0/6 380/16384 @1fe3e0000 ^1 [ 80000010 ... ]
|
||||
00000001 MSI -- 00000010 1/6 305/16384 @1fc230000 ^1 [ 80000010 ... ]
|
||||
00000002 MSI -- 00000010 2/6 220/16384 @1fc2f0000 ^1 [ 80000010 ... ]
|
||||
00000003 MSI -- 00000010 3/6 201/16384 @1fc390000 ^1 [ 80000010 ... ]
|
||||
00000004 MSI -Q M 00000000
|
||||
00000005 MSI -Q M 00000000
|
||||
00000006 MSI -Q M 00000000
|
||||
00000007 MSI -Q M 00000000
|
||||
00001000 MSI -- 00000012 0/6 380/16384 @1fe3e0000 ^1 [ 80000010 ... ]
|
||||
00001001 MSI -- 00000013 0/6 380/16384 @1fe3e0000 ^1 [ 80000010 ... ]
|
||||
00001100 MSI -- 00000100 1/6 305/16384 @1fc230000 ^1 [ 80000010 ... ]
|
||||
00001101 MSI -Q M 00000000
|
||||
00001200 LSI -Q M 00000000
|
||||
00001201 LSI -Q M 00000000
|
||||
00001202 LSI -Q M 00000000
|
||||
00001203 LSI -Q M 00000000
|
||||
00001300 MSI -- 00000102 1/6 305/16384 @1fc230000 ^1 [ 80000010 ... ]
|
||||
00001301 MSI -- 00000103 2/6 220/16384 @1fc2f0000 ^1 [ 80000010 ... ]
|
||||
00001302 MSI -- 00000104 3/6 201/16384 @1fc390000 ^1 [ 80000010 ... ]
|
||||
|
||||
The source information and configuration:
|
||||
|
||||
- The ``LISN`` column outputs the interrupt number of the source in
|
||||
range ``[ 0x0 ... 0x1FFF ]`` and its type : ``MSI`` or ``LSI``
|
||||
- The ``PQ`` column reflects the state of the PQ bits of the source :
|
||||
|
||||
- ``--`` source is ready to take events
|
||||
- ``P-`` an event was sent and an EOI is PENDING
|
||||
- ``PQ`` an event was QUEUED
|
||||
- ``-Q`` source is OFF
|
||||
|
||||
a ``M`` indicates that source is *MASKED* at the EAS level,
|
||||
|
||||
The targeting configuration :
|
||||
|
||||
- The ``EISN`` column is the event data that will be queued in the event
|
||||
queue of the O/S.
|
||||
- The ``CPU/PRIO`` column is the tuple defining the CPU number and
|
||||
priority queue serving the source.
|
||||
- The ``EQ`` column outputs :
|
||||
|
||||
- the current index of the event queue/ the max number of entries
|
||||
- the O/S event queue address
|
||||
- the toggle bit
|
||||
- the last entries that were pushed in the event queue.
|
||||
@@ -0,0 +1,199 @@
|
||||
================================
|
||||
POWER9 XIVE interrupt controller
|
||||
================================
|
||||
|
||||
The POWER9 processor comes with a new interrupt controller
|
||||
architecture, called XIVE as "eXternal Interrupt Virtualization
|
||||
Engine".
|
||||
|
||||
Compared to the previous architecture, the main characteristics of
|
||||
XIVE are to support a larger number of interrupt sources and to
|
||||
deliver interrupts directly to virtual processors without hypervisor
|
||||
assistance. This removes the context switches required for the
|
||||
delivery process.
|
||||
|
||||
|
||||
XIVE architecture
|
||||
=================
|
||||
|
||||
The XIVE IC is composed of three sub-engines, each taking care of a
|
||||
processing layer of external interrupts:
|
||||
|
||||
- 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). It handles event coalescing and perform interrupt
|
||||
routing by matching an event source number with an Event
|
||||
Notification Descriptor (END).
|
||||
- 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 interrupt to the
|
||||
thread.
|
||||
|
||||
::
|
||||
|
||||
XIVE Interrupt Controller
|
||||
+------------------------------------+ IPIs
|
||||
| +---------+ +---------+ +--------+ | +-------+
|
||||
| |IVRE | |Common Q | |IVPE |----> | CORES |
|
||||
| | esb | | | | |----> | |
|
||||
| | eas | | Bridge | | tctx |----> | |
|
||||
| |SC end | | | | nvt | | | |
|
||||
+------+ | +---------+ +----+----+ +--------+ | +-+-+-+-+
|
||||
| RAM | +------------------|-----------------+ | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | +--------------------v------------------------v-v-v--+ other
|
||||
| <--+ Power Bus +--> chips
|
||||
| esb | +---------+-----------------------+------------------+
|
||||
| eas | | |
|
||||
| end | +--|------+ |
|
||||
| nvt | +----+----+ | +----+----+
|
||||
+------+ |IVSE | | |IVSE |
|
||||
| | | | |
|
||||
| PQ-bits | | | PQ-bits |
|
||||
| local |-+ | in VC |
|
||||
+---------+ +---------+
|
||||
PCIe NX,NPU,CAPI
|
||||
|
||||
|
||||
PQ-bits: 2 bits source state machine (P:pending Q:queued)
|
||||
esb: Event State Buffer (Array of PQ bits in an IVSE)
|
||||
eas: Event Assignment Structure
|
||||
end: Event Notification Descriptor
|
||||
nvt: Notification Virtual Target
|
||||
tctx: Thread interrupt Context registers
|
||||
|
||||
|
||||
|
||||
XIVE internal tables
|
||||
--------------------
|
||||
|
||||
Each of the sub-engines uses a set of tables to redirect interrupts
|
||||
from event sources to CPU threads.
|
||||
|
||||
::
|
||||
|
||||
+-------+
|
||||
User or O/S | EQ |
|
||||
or +------>|entries|
|
||||
Hypervisor | | .. |
|
||||
Memory | +-------+
|
||||
| ^
|
||||
| |
|
||||
+-------------------------------------------------+
|
||||
| |
|
||||
Hypervisor +------+ +---+--+ +---+--+ +------+
|
||||
Memory | ESB | | EAT | | ENDT | | NVTT |
|
||||
(skiboot) +----+-+ +----+-+ +----+-+ +------+
|
||||
^ | ^ | ^ | ^
|
||||
| | | | | | |
|
||||
+-------------------------------------------------+
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
+----|--|--------|--|--------|--|-+ +-|-----+ +------+
|
||||
| | | | | | | | | | tctx| |Thread|
|
||||
IPI or ---+ + v + v + v |---| + .. |-----> |
|
||||
HW events | | | | | |
|
||||
| IVRE | | IVPE | +------+
|
||||
+---------------------------------+ +-------+
|
||||
|
||||
|
||||
The IVSE have a 2-bits state machine, P for pending and Q for queued,
|
||||
for each source that allows events to be triggered. They are stored in
|
||||
an Event State Buffer (ESB) array and can be controlled by MMIOs.
|
||||
|
||||
If the event is let through, the IVRE looks up in the Event Assignment
|
||||
Structure (EAS) table for an Event Notification Descriptor (END)
|
||||
configured for the source. Each Event Notification Descriptor defines
|
||||
a notification path to a CPU and an in-memory Event Queue, in which
|
||||
will be enqueued an EQ data for the O/S to pull.
|
||||
|
||||
The IVPE determines if a Notification Virtual Target (NVT) can handle
|
||||
the event by scanning the thread contexts of the VCPUs dispatched on
|
||||
the processor HW threads. It maintains the interrupt context state of
|
||||
each thread in a NVT table.
|
||||
|
||||
XIVE thread interrupt context
|
||||
-----------------------------
|
||||
|
||||
The XIVE presenter can generate four different exceptions to its
|
||||
HW threads:
|
||||
|
||||
- hypervisor exception
|
||||
- O/S exception
|
||||
- Event-Based Branch (user level)
|
||||
- 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
|
||||
lets 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)
|
||||
|
||||
TIMA
|
||||
~~~~
|
||||
|
||||
The Thread Interrupt Management 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 view for the
|
||||
physical thread context. The second (page address ending in ``0b01``)
|
||||
is for the hypervisor, ring 1 view. The third (page address ending in
|
||||
``0b10``) is for the operating system, ring 2 view. The fourth (page
|
||||
address ending in ``0b11``) is for user level, ring 3 view.
|
||||
|
||||
Interrupt flow from an O/S perspective
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After an event data has been enqueued in the O/S Event Queue, the IVPE
|
||||
raises the bit corresponding to the priority of the pending interrupt
|
||||
in the register IBP (Interrupt Pending Buffer) to indicate that an
|
||||
event is 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 O/S acknowledges the interrupt with a special load in the
|
||||
Thread Interrupt Management Area.
|
||||
|
||||
The O/S handles the interrupt and when done, performs an EOI using a
|
||||
MMIO operation on the ESB management page of the associate source.
|
||||
|
||||
Overview of the QEMU models for XIVE
|
||||
====================================
|
||||
|
||||
The XiveSource models the IVSE in general, internal and external. It
|
||||
handles the source ESBs and the MMIO interface to control them.
|
||||
|
||||
The XiveNotifier 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 EAS and END 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.
|
||||
|
||||
XiveEnDSource is a special source object. It exposes the END 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.
|
||||
@@ -153,6 +153,16 @@ static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
|
||||
}
|
||||
}
|
||||
|
||||
void sysbus_mmio_unmap(SysBusDevice *dev, int n)
|
||||
{
|
||||
assert(n >= 0 && n < dev->num_mmio);
|
||||
|
||||
if (dev->mmio[n].addr != (hwaddr)-1) {
|
||||
memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
|
||||
dev->mmio[n].addr = (hwaddr)-1;
|
||||
}
|
||||
}
|
||||
|
||||
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
|
||||
{
|
||||
sysbus_mmio_map_common(dev, n, addr, false, 0);
|
||||
|
||||
@@ -39,6 +39,7 @@ obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
|
||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||
obj-$(CONFIG_XIVE) += xive.o
|
||||
obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o
|
||||
obj-$(CONFIG_XIVE_KVM) += spapr_xive_kvm.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
|
||||
|
||||
+164
-29
@@ -40,13 +40,6 @@
|
||||
|
||||
#define SPAPR_XIVE_NVT_BASE 0x400
|
||||
|
||||
/*
|
||||
* The sPAPR machine has a unique XIVE IC device. Assign a fixed value
|
||||
* to the controller block id value. It can nevertheless be changed
|
||||
* for testing purpose.
|
||||
*/
|
||||
#define SPAPR_XIVE_BLOCK_ID 0x0
|
||||
|
||||
/*
|
||||
* sPAPR NVT and END indexing helpers
|
||||
*/
|
||||
@@ -86,6 +79,22 @@ static int spapr_xive_target_to_nvt(uint32_t target,
|
||||
* sPAPR END indexing uses a simple mapping of the CPU vcpu_id, 8
|
||||
* priorities per CPU
|
||||
*/
|
||||
int spapr_xive_end_to_target(uint8_t end_blk, uint32_t end_idx,
|
||||
uint32_t *out_server, uint8_t *out_prio)
|
||||
{
|
||||
|
||||
assert(end_blk == SPAPR_XIVE_BLOCK_ID);
|
||||
|
||||
if (out_server) {
|
||||
*out_server = end_idx >> 3;
|
||||
}
|
||||
|
||||
if (out_prio) {
|
||||
*out_prio = end_idx & 0x7;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spapr_xive_cpu_to_end(PowerPCCPU *cpu, uint8_t prio,
|
||||
uint8_t *out_end_blk, uint32_t *out_end_idx)
|
||||
{
|
||||
@@ -120,6 +129,7 @@ static int spapr_xive_target_to_end(uint32_t target, uint8_t prio,
|
||||
static void spapr_xive_end_pic_print_info(SpaprXive *xive, XiveEND *end,
|
||||
Monitor *mon)
|
||||
{
|
||||
uint64_t qaddr_base = xive_end_qaddr(end);
|
||||
uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
|
||||
uint32_t qgen = xive_get_field32(END_W1_GENERATION, end->w1);
|
||||
uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
|
||||
@@ -127,9 +137,9 @@ static void spapr_xive_end_pic_print_info(SpaprXive *xive, XiveEND *end,
|
||||
uint32_t nvt = xive_get_field32(END_W6_NVT_INDEX, end->w6);
|
||||
uint8_t priority = xive_get_field32(END_W7_F0_PRIORITY, end->w7);
|
||||
|
||||
monitor_printf(mon, "%3d/%d % 6d/%5d ^%d",
|
||||
monitor_printf(mon, "%3d/%d % 6d/%5d @%"PRIx64" ^%d",
|
||||
spapr_xive_nvt_to_target(0, nvt),
|
||||
priority, qindex, qentries, qgen);
|
||||
priority, qindex, qentries, qaddr_base, qgen);
|
||||
|
||||
xive_end_queue_pic_print_info(end, 6, mon);
|
||||
monitor_printf(mon, "]");
|
||||
@@ -140,7 +150,17 @@ void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon)
|
||||
XiveSource *xsrc = &xive->source;
|
||||
int i;
|
||||
|
||||
monitor_printf(mon, " LSIN PQ EISN CPU/PRIO EQ\n");
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
kvmppc_xive_synchronize_state(xive, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
monitor_printf(mon, " LISN PQ EISN CPU/PRIO EQ\n");
|
||||
|
||||
for (i = 0; i < xive->nr_irqs; i++) {
|
||||
uint8_t pq = xive_source_esb_get(xsrc, i);
|
||||
@@ -173,7 +193,7 @@ void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon)
|
||||
}
|
||||
}
|
||||
|
||||
static void spapr_xive_map_mmio(SpaprXive *xive)
|
||||
void spapr_xive_map_mmio(SpaprXive *xive)
|
||||
{
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(xive), 0, xive->vc_base);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(xive), 1, xive->end_base);
|
||||
@@ -250,6 +270,9 @@ static void spapr_xive_instance_init(Object *obj)
|
||||
object_initialize_child(obj, "end_source", &xive->end_source,
|
||||
sizeof(xive->end_source), TYPE_XIVE_END_SOURCE,
|
||||
&error_abort, NULL);
|
||||
|
||||
/* Not connected to the KVM XIVE device */
|
||||
xive->fd = -1;
|
||||
}
|
||||
|
||||
static void spapr_xive_realize(DeviceState *dev, Error **errp)
|
||||
@@ -304,22 +327,36 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp)
|
||||
xive->eat = g_new0(XiveEAS, xive->nr_irqs);
|
||||
xive->endt = g_new0(XiveEND, xive->nr_ends);
|
||||
|
||||
/* TIMA initialization */
|
||||
memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, xive,
|
||||
"xive.tima", 4ull << TM_SHIFT);
|
||||
xive->nodename = g_strdup_printf("interrupt-controller@%" PRIx64,
|
||||
xive->tm_base + XIVE_TM_USER_PAGE * (1 << TM_SHIFT));
|
||||
|
||||
qemu_register_reset(spapr_xive_reset, dev);
|
||||
|
||||
/* Define all XIVE MMIO regions on SysBus */
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio);
|
||||
}
|
||||
|
||||
void spapr_xive_init(SpaprXive *xive, Error **errp)
|
||||
{
|
||||
XiveSource *xsrc = &xive->source;
|
||||
|
||||
/*
|
||||
* The emulated XIVE device can only be initialized once. If the
|
||||
* ESB memory region has been already mapped, it means we have been
|
||||
* through there.
|
||||
*/
|
||||
if (memory_region_is_mapped(&xsrc->esb_mmio)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* TIMA initialization */
|
||||
memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, xive,
|
||||
"xive.tima", 4ull << TM_SHIFT);
|
||||
|
||||
/* Map all regions */
|
||||
spapr_xive_map_mmio(xive);
|
||||
|
||||
xive->nodename = g_strdup_printf("interrupt-controller@%" PRIx64,
|
||||
xive->tm_base + XIVE_TM_USER_PAGE * (1 << TM_SHIFT));
|
||||
|
||||
qemu_register_reset(spapr_xive_reset, dev);
|
||||
}
|
||||
|
||||
static int spapr_xive_get_eas(XiveRouter *xrtr, uint8_t eas_blk,
|
||||
@@ -427,10 +464,34 @@ static const VMStateDescription vmstate_spapr_xive_eas = {
|
||||
},
|
||||
};
|
||||
|
||||
static int vmstate_spapr_xive_pre_save(void *opaque)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return kvmppc_xive_pre_save(SPAPR_XIVE(opaque));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by the sPAPR IRQ backend 'post_load' method at the machine
|
||||
* level.
|
||||
*/
|
||||
int spapr_xive_post_load(SpaprXive *xive, int version_id)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return kvmppc_xive_post_load(xive, version_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = NULL, /* handled at the machine level */
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_EQUAL(nr_irqs, SpaprXive, NULL),
|
||||
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(eat, SpaprXive, nr_irqs,
|
||||
@@ -494,6 +555,17 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi)
|
||||
if (lsi) {
|
||||
xive_source_irq_set_lsi(xsrc, lisn);
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
kvmppc_xive_source_reset_one(xsrc, lisn, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -755,6 +827,16 @@ static target_ulong h_int_set_source_config(PowerPCCPU *cpu,
|
||||
new_eas.w = xive_set_field64(EAS_END_DATA, new_eas.w, eisn);
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
kvmppc_xive_set_source_config(xive, lisn, &new_eas, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return H_HARDWARE;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
xive->eat[lisn] = new_eas;
|
||||
return H_SUCCESS;
|
||||
@@ -993,6 +1075,12 @@ static target_ulong h_int_set_queue_config(PowerPCCPU *cpu,
|
||||
case 16:
|
||||
case 21:
|
||||
case 24:
|
||||
if (!QEMU_IS_ALIGNED(qpage, 1ul << qsize)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: EQ @0x%" HWADDR_PRIx
|
||||
" is not naturally aligned with %" HWADDR_PRIx "\n",
|
||||
qpage, (hwaddr)1 << qsize);
|
||||
return H_P4;
|
||||
}
|
||||
end.w2 = cpu_to_be32((qpage >> 32) & 0x0fffffff);
|
||||
end.w3 = cpu_to_be32(qpage & 0xffffffff);
|
||||
end.w0 |= cpu_to_be32(END_W0_ENQUEUE);
|
||||
@@ -1060,6 +1148,16 @@ static target_ulong h_int_set_queue_config(PowerPCCPU *cpu,
|
||||
*/
|
||||
|
||||
out:
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
kvmppc_xive_set_queue_config(xive, end_blk, end_idx, &end, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return H_HARDWARE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update END */
|
||||
memcpy(&xive->endt[end_idx], &end, sizeof(XiveEND));
|
||||
return H_SUCCESS;
|
||||
@@ -1144,14 +1242,23 @@ static target_ulong h_int_get_queue_config(PowerPCCPU *cpu,
|
||||
}
|
||||
|
||||
if (xive_end_is_enqueue(end)) {
|
||||
args[1] = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
|
||||
| be32_to_cpu(end->w3);
|
||||
args[1] = xive_end_qaddr(end);
|
||||
args[2] = xive_get_field32(END_W0_QSIZE, end->w0) + 12;
|
||||
} else {
|
||||
args[1] = 0;
|
||||
args[2] = 0;
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
kvmppc_xive_get_queue_config(xive, end_blk, end_idx, end, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return H_HARDWARE;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: do we need any locking on the END ? */
|
||||
if (flags & SPAPR_XIVE_END_DEBUG) {
|
||||
/* Load the event queue generation number into the return flags */
|
||||
@@ -1304,15 +1411,20 @@ static target_ulong h_int_esb(PowerPCCPU *cpu,
|
||||
return H_P3;
|
||||
}
|
||||
|
||||
mmio_addr = xive->vc_base + xive_source_esb_mgmt(xsrc, lisn) + offset;
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
args[0] = kvmppc_xive_esb_rw(xsrc, lisn, offset, data,
|
||||
flags & SPAPR_XIVE_ESB_STORE);
|
||||
} else {
|
||||
mmio_addr = xive->vc_base + xive_source_esb_mgmt(xsrc, lisn) + offset;
|
||||
|
||||
if (dma_memory_rw(&address_space_memory, mmio_addr, &data, 8,
|
||||
(flags & SPAPR_XIVE_ESB_STORE))) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to access ESB @0x%"
|
||||
HWADDR_PRIx "\n", mmio_addr);
|
||||
return H_HARDWARE;
|
||||
if (dma_memory_rw(&address_space_memory, mmio_addr, &data, 8,
|
||||
(flags & SPAPR_XIVE_ESB_STORE))) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to access ESB @0x%"
|
||||
HWADDR_PRIx "\n", mmio_addr);
|
||||
return H_HARDWARE;
|
||||
}
|
||||
args[0] = (flags & SPAPR_XIVE_ESB_STORE) ? -1 : data;
|
||||
}
|
||||
args[0] = (flags & SPAPR_XIVE_ESB_STORE) ? -1 : data;
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1369,7 +1481,20 @@ static target_ulong h_int_sync(PowerPCCPU *cpu,
|
||||
* This is not needed when running the emulation under QEMU
|
||||
*/
|
||||
|
||||
/* This is not real hardware. Nothing to be done */
|
||||
/*
|
||||
* This is not real hardware. Nothing to be done unless when
|
||||
* under KVM
|
||||
*/
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
kvmppc_xive_sync_source(xive, lisn, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return H_HARDWARE;
|
||||
}
|
||||
}
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1404,6 +1529,16 @@ static target_ulong h_int_reset(PowerPCCPU *cpu,
|
||||
}
|
||||
|
||||
device_reset(DEVICE(xive));
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
kvmppc_xive_reset(xive, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return H_HARDWARE;
|
||||
}
|
||||
}
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+8
-2
@@ -610,6 +610,12 @@ static const TypeInfo ics_simple_info = {
|
||||
.class_size = sizeof(ICSStateClass),
|
||||
};
|
||||
|
||||
static void ics_reset_irq(ICSIRQState *irq)
|
||||
{
|
||||
irq->priority = 0xff;
|
||||
irq->saved_priority = 0xff;
|
||||
}
|
||||
|
||||
static void ics_base_reset(DeviceState *dev)
|
||||
{
|
||||
ICSState *ics = ICS_BASE(dev);
|
||||
@@ -623,8 +629,7 @@ static void ics_base_reset(DeviceState *dev)
|
||||
memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
ics->irqs[i].priority = 0xff;
|
||||
ics->irqs[i].saved_priority = 0xff;
|
||||
ics_reset_irq(ics->irqs + i);
|
||||
ics->irqs[i].flags = flags[i];
|
||||
}
|
||||
}
|
||||
@@ -760,6 +765,7 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
|
||||
lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
ics_reset_irq(ics->irqs + srcno);
|
||||
ics_set_kvm_state_one(ics, srcno);
|
||||
}
|
||||
}
|
||||
|
||||
+112
-1
@@ -33,6 +33,7 @@
|
||||
#include "trace.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/spapr_cpu_core.h"
|
||||
#include "hw/ppc/xics.h"
|
||||
#include "hw/ppc/xics_spapr.h"
|
||||
#include "kvm_ppc.h"
|
||||
@@ -51,6 +52,16 @@ typedef struct KVMEnabledICP {
|
||||
static QLIST_HEAD(, KVMEnabledICP)
|
||||
kvm_enabled_icps = QLIST_HEAD_INITIALIZER(&kvm_enabled_icps);
|
||||
|
||||
static void kvm_disable_icps(void)
|
||||
{
|
||||
KVMEnabledICP *enabled_icp, *next;
|
||||
|
||||
QLIST_FOREACH_SAFE(enabled_icp, &kvm_enabled_icps, node, next) {
|
||||
QLIST_REMOVE(enabled_icp, node);
|
||||
g_free(enabled_icp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ICP-KVM
|
||||
*/
|
||||
@@ -59,6 +70,11 @@ void icp_get_kvm_state(ICPState *icp)
|
||||
uint64_t state;
|
||||
int ret;
|
||||
|
||||
/* The KVM XICS device is not in use */
|
||||
if (kernel_xics_fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* ICP for this CPU thread is not in use, exiting */
|
||||
if (!icp->cs) {
|
||||
return;
|
||||
@@ -95,6 +111,11 @@ int icp_set_kvm_state(ICPState *icp)
|
||||
uint64_t state;
|
||||
int ret;
|
||||
|
||||
/* The KVM XICS device is not in use */
|
||||
if (kernel_xics_fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ICP for this CPU thread is not in use, exiting */
|
||||
if (!icp->cs) {
|
||||
return 0;
|
||||
@@ -123,8 +144,9 @@ void icp_kvm_realize(DeviceState *dev, Error **errp)
|
||||
unsigned long vcpu_id;
|
||||
int ret;
|
||||
|
||||
/* The KVM XICS device is not in use */
|
||||
if (kernel_xics_fd == -1) {
|
||||
abort();
|
||||
return;
|
||||
}
|
||||
|
||||
cs = icp->cs;
|
||||
@@ -160,6 +182,11 @@ void ics_get_kvm_state(ICSState *ics)
|
||||
uint64_t state;
|
||||
int i;
|
||||
|
||||
/* The KVM XICS device is not in use */
|
||||
if (kernel_xics_fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
ICSIRQState *irq = &ics->irqs[i];
|
||||
|
||||
@@ -220,6 +247,11 @@ int ics_set_kvm_state_one(ICSState *ics, int srcno)
|
||||
ICSIRQState *irq = &ics->irqs[srcno];
|
||||
int ret;
|
||||
|
||||
/* The KVM XICS device is not in use */
|
||||
if (kernel_xics_fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
state = irq->server;
|
||||
state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK)
|
||||
<< KVM_XICS_PRIORITY_SHIFT;
|
||||
@@ -259,6 +291,11 @@ int ics_set_kvm_state(ICSState *ics)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* The KVM XICS device is not in use */
|
||||
if (kernel_xics_fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ics->nr_irqs; i++) {
|
||||
int ret;
|
||||
|
||||
@@ -276,6 +313,9 @@ void ics_kvm_set_irq(ICSState *ics, int srcno, int val)
|
||||
struct kvm_irq_level args;
|
||||
int rc;
|
||||
|
||||
/* The KVM XICS device should be in use */
|
||||
assert(kernel_xics_fd != -1);
|
||||
|
||||
args.irq = srcno + ics->offset;
|
||||
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) {
|
||||
if (!val) {
|
||||
@@ -303,6 +343,16 @@ static void rtas_dummy(PowerPCCPU *cpu, SpaprMachineState *spapr,
|
||||
int xics_kvm_init(SpaprMachineState *spapr, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
CPUState *cs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* The KVM XICS device already in use. This is the case when
|
||||
* rebooting under the XICS-only interrupt mode.
|
||||
*/
|
||||
if (kernel_xics_fd != -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) {
|
||||
error_setg(errp,
|
||||
@@ -351,6 +401,26 @@ int xics_kvm_init(SpaprMachineState *spapr, Error **errp)
|
||||
kvm_msi_via_irqfd_allowed = true;
|
||||
kvm_gsi_direct_mapping = true;
|
||||
|
||||
/* Create the presenters */
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
icp_kvm_realize(DEVICE(spapr_cpu_state(cpu)->icp), &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the KVM sources */
|
||||
ics_set_kvm_state(spapr->ics);
|
||||
|
||||
/* Connect the presenters to the initial VCPUs of the machine */
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
icp_set_kvm_state(spapr_cpu_state(cpu)->icp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@@ -360,3 +430,44 @@ fail:
|
||||
kvmppc_define_rtas_kernel_token(0, "ibm,int-off");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp)
|
||||
{
|
||||
/* The KVM XICS device is not in use */
|
||||
if (kernel_xics_fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) {
|
||||
error_setg(errp,
|
||||
"KVM and IRQ_XICS capability must be present for KVM XICS device");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only on P9 using the XICS-on XIVE KVM device:
|
||||
*
|
||||
* When the KVM device fd is closed, the device is destroyed and
|
||||
* removed from the list of devices of the VM. The VCPU presenters
|
||||
* are also detached from the device.
|
||||
*/
|
||||
close(kernel_xics_fd);
|
||||
kernel_xics_fd = -1;
|
||||
|
||||
spapr_rtas_unregister(RTAS_IBM_SET_XIVE);
|
||||
spapr_rtas_unregister(RTAS_IBM_GET_XIVE);
|
||||
spapr_rtas_unregister(RTAS_IBM_INT_OFF);
|
||||
spapr_rtas_unregister(RTAS_IBM_INT_ON);
|
||||
|
||||
kvmppc_define_rtas_kernel_token(0, "ibm,set-xive");
|
||||
kvmppc_define_rtas_kernel_token(0, "ibm,get-xive");
|
||||
kvmppc_define_rtas_kernel_token(0, "ibm,int-on");
|
||||
kvmppc_define_rtas_kernel_token(0, "ibm,int-off");
|
||||
|
||||
kvm_kernel_irqchip = false;
|
||||
kvm_msi_via_irqfd_allowed = false;
|
||||
kvm_gsi_direct_mapping = false;
|
||||
|
||||
/* Clear the presenter from the VCPUs */
|
||||
kvm_disable_icps();
|
||||
}
|
||||
|
||||
@@ -239,6 +239,13 @@ static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr,
|
||||
|
||||
void xics_spapr_init(SpaprMachineState *spapr)
|
||||
{
|
||||
/* Emulated mode can only be initialized once. */
|
||||
if (spapr->ics->init) {
|
||||
return;
|
||||
}
|
||||
|
||||
spapr->ics->init = true;
|
||||
|
||||
/* Registration of global state belongs into realize */
|
||||
spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
|
||||
spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
|
||||
|
||||
+44
-9
@@ -493,6 +493,16 @@ void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon)
|
||||
int cpu_index = tctx->cs ? tctx->cs->cpu_index : -1;
|
||||
int i;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
kvmppc_xive_cpu_synchronize_state(tctx, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
monitor_printf(mon, "CPU[%04x]: QW NSR CPPR IPB LSMFB ACK# INC AGE PIPR"
|
||||
" W2\n", cpu_index);
|
||||
|
||||
@@ -555,6 +565,15 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Connect the presenter to the VCPU (required for CPU hotplug) */
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvmppc_xive_cpu_connect(tctx, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_register_reset(xive_tctx_reset, dev);
|
||||
}
|
||||
|
||||
@@ -563,10 +582,27 @@ static void xive_tctx_unrealize(DeviceState *dev, Error **errp)
|
||||
qemu_unregister_reset(xive_tctx_reset, dev);
|
||||
}
|
||||
|
||||
static int vmstate_xive_tctx_pre_save(void *opaque)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvmppc_xive_cpu_get_state(XIVE_TCTX(opaque), &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_xive_tctx = {
|
||||
.name = TYPE_XIVE_TCTX,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = vmstate_xive_tctx_pre_save,
|
||||
.post_load = NULL, /* handled by the sPAPRxive model */
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BUFFER(regs, XiveTCTX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
@@ -990,9 +1026,11 @@ static void xive_source_realize(DeviceState *dev, Error **errp)
|
||||
xsrc->status = g_malloc0(xsrc->nr_irqs);
|
||||
xsrc->lsi_map = bitmap_new(xsrc->nr_irqs);
|
||||
|
||||
memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc),
|
||||
&xive_source_esb_ops, xsrc, "xive.esb",
|
||||
(1ull << xsrc->esb_shift) * xsrc->nr_irqs);
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc),
|
||||
&xive_source_esb_ops, xsrc, "xive.esb",
|
||||
(1ull << xsrc->esb_shift) * xsrc->nr_irqs);
|
||||
}
|
||||
|
||||
qemu_register_reset(xive_source_reset, dev);
|
||||
}
|
||||
@@ -1042,8 +1080,7 @@ static const TypeInfo xive_source_info = {
|
||||
|
||||
void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon)
|
||||
{
|
||||
uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
|
||||
| be32_to_cpu(end->w3);
|
||||
uint64_t qaddr_base = xive_end_qaddr(end);
|
||||
uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
|
||||
uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
|
||||
uint32_t qentries = 1 << (qsize + 10);
|
||||
@@ -1072,8 +1109,7 @@ void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon)
|
||||
|
||||
void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon)
|
||||
{
|
||||
uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
|
||||
| be32_to_cpu(end->w3);
|
||||
uint64_t qaddr_base = xive_end_qaddr(end);
|
||||
uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
|
||||
uint32_t qgen = xive_get_field32(END_W1_GENERATION, end->w1);
|
||||
uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
|
||||
@@ -1101,8 +1137,7 @@ void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon)
|
||||
|
||||
static void xive_end_enqueue(XiveEND *end, uint32_t data)
|
||||
{
|
||||
uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
|
||||
| be32_to_cpu(end->w3);
|
||||
uint64_t qaddr_base = xive_end_qaddr(end);
|
||||
uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
|
||||
uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
|
||||
uint32_t qgen = xive_get_field32(END_W1_GENERATION, end->w1);
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "hw/timer/mc146818rtc.h"
|
||||
#include "hw/audio/pcspk.h"
|
||||
|
||||
#define TYPE_I82378 "i82378"
|
||||
@@ -105,9 +104,6 @@ static void i82378_realize(PCIDevice *pci, Error **errp)
|
||||
|
||||
/* 2 82C37 (dma) */
|
||||
isa = isa_create_simple(isabus, "i82374");
|
||||
|
||||
/* timer */
|
||||
isa_create_simple(isabus, TYPE_MC146818_RTC);
|
||||
}
|
||||
|
||||
static void i82378_init(Object *obj)
|
||||
|
||||
@@ -122,3 +122,8 @@ config XIVE_SPAPR
|
||||
default y
|
||||
depends on PSERIES
|
||||
select XIVE
|
||||
|
||||
config XIVE_KVM
|
||||
bool
|
||||
default y
|
||||
depends on XIVE_SPAPR && KVM
|
||||
|
||||
+10
-3
@@ -450,7 +450,8 @@ static void pnv_dt_power_mgt(void *fdt)
|
||||
|
||||
static void *pnv_dt_create(MachineState *machine)
|
||||
{
|
||||
const char plat_compat[] = "qemu,powernv\0ibm,powernv";
|
||||
const char plat_compat8[] = "qemu,powernv8\0qemu,powernv\0ibm,powernv";
|
||||
const char plat_compat9[] = "qemu,powernv9\0ibm,powernv";
|
||||
PnvMachineState *pnv = PNV_MACHINE(machine);
|
||||
void *fdt;
|
||||
char *buf;
|
||||
@@ -465,8 +466,14 @@ static void *pnv_dt_create(MachineState *machine)
|
||||
_FDT((fdt_setprop_cell(fdt, 0, "#size-cells", 0x2)));
|
||||
_FDT((fdt_setprop_string(fdt, 0, "model",
|
||||
"IBM PowerNV (emulated by qemu)")));
|
||||
_FDT((fdt_setprop(fdt, 0, "compatible", plat_compat,
|
||||
sizeof(plat_compat))));
|
||||
if (pnv_is_power9(pnv)) {
|
||||
_FDT((fdt_setprop(fdt, 0, "compatible", plat_compat9,
|
||||
sizeof(plat_compat9))));
|
||||
} else {
|
||||
_FDT((fdt_setprop(fdt, 0, "compatible", plat_compat8,
|
||||
sizeof(plat_compat8))));
|
||||
}
|
||||
|
||||
|
||||
buf = qemu_uuid_unparse_strdup(&qemu_uuid);
|
||||
_FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
/* PRD registers */
|
||||
#define PRD_P8_IPOLL_REG_MASK 0x01020013
|
||||
#define PRD_P8_IPOLL_REG_STATUS 0x01020014
|
||||
#define PRD_P9_IPOLL_REG_MASK 0x000F0033
|
||||
#define PRD_P9_IPOLL_REG_STATUS 0x000F0034
|
||||
|
||||
static void xscom_complete(CPUState *cs, uint64_t hmer_bits)
|
||||
{
|
||||
/*
|
||||
@@ -70,6 +76,12 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
|
||||
case 0x1010c00: /* PIBAM FIR */
|
||||
case 0x1010c03: /* PIBAM FIR MASK */
|
||||
|
||||
/* PRD registers */
|
||||
case PRD_P8_IPOLL_REG_MASK:
|
||||
case PRD_P8_IPOLL_REG_STATUS:
|
||||
case PRD_P9_IPOLL_REG_MASK:
|
||||
case PRD_P9_IPOLL_REG_STATUS:
|
||||
|
||||
/* P9 xscom reset */
|
||||
case 0x0090018: /* Receive status reg */
|
||||
case 0x0090012: /* log register */
|
||||
@@ -124,6 +136,12 @@ static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val)
|
||||
case 0x201302a: /* CAPP stuff */
|
||||
case 0x2013801: /* CAPP stuff */
|
||||
case 0x2013802: /* CAPP stuff */
|
||||
|
||||
/* P8 PRD registers */
|
||||
case PRD_P8_IPOLL_REG_MASK:
|
||||
case PRD_P8_IPOLL_REG_STATUS:
|
||||
case PRD_P9_IPOLL_REG_MASK:
|
||||
case PRD_P9_IPOLL_REG_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
+6
-1
@@ -601,7 +601,7 @@ static int prep_set_cmos_checksum(DeviceState *dev, void *opaque)
|
||||
uint16_t checksum = *(uint16_t *)opaque;
|
||||
ISADevice *rtc;
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), "mc146818rtc")) {
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) {
|
||||
rtc = ISA_DEVICE(dev);
|
||||
rtc_set_memory(rtc, 0x2e, checksum & 0xff);
|
||||
rtc_set_memory(rtc, 0x3e, checksum & 0xff);
|
||||
@@ -675,6 +675,11 @@ static void ibm_40p_init(MachineState *machine)
|
||||
qdev_prop_set_uint32(dev, "ram-size", machine->ram_size);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* RTC */
|
||||
dev = DEVICE(isa_create(isa_bus, TYPE_MC146818_RTC));
|
||||
qdev_prop_set_int32(dev, "base_year", 1900);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* initialize CMOS checksums */
|
||||
cmos_checksum = 0x6aa9;
|
||||
qbus_walk_children(BUS(isa_bus), prep_set_cmos_checksum, NULL, NULL, NULL,
|
||||
|
||||
+23
-15
@@ -500,7 +500,10 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
||||
_FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
|
||||
|
||||
if (env->spr_cb[SPR_PURR].oea_read) {
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
|
||||
}
|
||||
if (env->spr_cb[SPR_SPURR].oea_read) {
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
|
||||
}
|
||||
|
||||
if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
|
||||
@@ -2122,6 +2125,7 @@ static const VMStateDescription vmstate_spapr = {
|
||||
&vmstate_spapr_cap_cfpc,
|
||||
&vmstate_spapr_cap_sbbc,
|
||||
&vmstate_spapr_cap_ibs,
|
||||
&vmstate_spapr_cap_hpt_maxpagesize,
|
||||
&vmstate_spapr_irq_map,
|
||||
&vmstate_spapr_cap_nested_kvm_hv,
|
||||
&vmstate_spapr_dtb,
|
||||
@@ -4348,7 +4352,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
|
||||
smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
|
||||
spapr_caps_add_properties(smc, &error_abort);
|
||||
smc->irq = &spapr_irq_xics;
|
||||
smc->irq = &spapr_irq_dual;
|
||||
smc->dr_phb_enabled = true;
|
||||
}
|
||||
|
||||
@@ -4407,18 +4411,7 @@ DEFINE_SPAPR_MACHINE(4_1, "4.1", true);
|
||||
/*
|
||||
* pseries-4.0
|
||||
*/
|
||||
static void spapr_machine_4_0_class_options(MachineClass *mc)
|
||||
{
|
||||
spapr_machine_4_1_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
|
||||
|
||||
/*
|
||||
* pseries-3.1
|
||||
*/
|
||||
static void phb_placement_3_1(SpaprMachineState *spapr, uint32_t index,
|
||||
static void phb_placement_4_0(SpaprMachineState *spapr, uint32_t index,
|
||||
uint64_t *buid, hwaddr *pio,
|
||||
hwaddr *mmio32, hwaddr *mmio64,
|
||||
unsigned n_dma, uint32_t *liobns,
|
||||
@@ -4430,6 +4423,22 @@ static void phb_placement_3_1(SpaprMachineState *spapr, uint32_t index,
|
||||
*nv2atsd = 0;
|
||||
}
|
||||
|
||||
static void spapr_machine_4_0_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
|
||||
spapr_machine_4_1_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_4_0, hw_compat_4_0_len);
|
||||
smc->phb_placement = phb_placement_4_0;
|
||||
smc->irq = &spapr_irq_xics;
|
||||
smc->pre_4_1_migration = true;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(4_0, "4.0", false);
|
||||
|
||||
/*
|
||||
* pseries-3.1
|
||||
*/
|
||||
static void spapr_machine_3_1_class_options(MachineClass *mc)
|
||||
{
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
|
||||
@@ -4445,7 +4454,6 @@ static void spapr_machine_3_1_class_options(MachineClass *mc)
|
||||
smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
|
||||
smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
|
||||
smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
|
||||
smc->phb_placement = phb_placement_3_1;
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user