virtio,pc,pci: features, cleanups, fixes

vhost-user enabled on non-linux systems
 beginning of nvme sriov support
 bigger tx queue for vdpa
 virtio iommu bypass
 FADT flag to detect legacy keyboards
 
 Fixes, cleanups all over the place
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmImipMPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRpD5AH/jz73VVDE3dZTtsdEH/f2tuO8uosur9fIjHJ
 nCMwBoosdDWmrWjrwxynmG6e+qIcOHEGdTInvS1TY2OTU+elNNTiR57pWiljXRsJ
 2kNIXKp4dXaYI/bxmKUzKSoVscyWxL686ND4U8sZhuppSNrWpLmMUNgwqmYjQQLV
 yd2JpIKgZYnzShPnJMDtF3ItcCHetY6jeB28WAclKywIEuCTmjulYCTaH5ujroG9
 rykMaQIjoe/isdmCcBx05UuMxH61vf5L8pR06N6e3GO9T2/Y/hWuteVoEJaCQvNa
 +zIyL2hOjGuMKr+icLo9c42s3yfwWNsRfz87wqdAY47yYSyc1wo=
 =3NVe
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

virtio,pc,pci: features, cleanups, fixes

vhost-user enabled on non-linux systems
beginning of nvme sriov support
bigger tx queue for vdpa
virtio iommu bypass
FADT flag to detect legacy keyboards

Fixes, cleanups all over the place

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Mon 07 Mar 2022 22:43:31 GMT
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream: (47 commits)
  hw/acpi/microvm: turn on 8042 bit in FADT boot architecture flags if present
  tests/acpi: i386: update FACP table differences
  hw/acpi: add indication for i8042 in IA-PC boot flags of the FADT table
  tests/acpi: i386: allow FACP acpi table changes
  docs: vhost-user: add subsection for non-Linux platforms
  configure, meson: allow enabling vhost-user on all POSIX systems
  vhost: use wfd on functions setting vring call fd
  event_notifier: add event_notifier_get_wfd()
  pci: drop COMPAT_PROP_PCP for 2.0 machine types
  hw/smbios: Add table 4 parameter, "processor-id"
  x86: cleanup unused compat_apic_id_mode
  vhost-vsock: detach the virqueue element in case of error
  pc: add option to disable PS/2 mouse/keyboard
  acpi: pcihp: pcie: set power on cap on parent slot
  pci: expose TYPE_XIO3130_DOWNSTREAM name
  pci: show id info when pci BDF conflict
  hw/misc/pvpanic: Use standard headers instead
  headers: Add pvpanic.h
  pci-bridge/xio3130_downstream: Fix error handling
  pci-bridge/xio3130_upstream: Fix error handling
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

# Conflicts:
#	docs/specs/index.rst
This commit is contained in:
Peter Maydell 2022-03-08 22:27:34 +00:00
commit 9f0369efb0
66 changed files with 1229 additions and 174 deletions

View File

@ -1819,7 +1819,6 @@ F: docs/specs/acpi_hw_reduced_hotplug.rst
ACPI/VIOT
M: Jean-Philippe Brucker <jean-philippe@linaro.org>
R: Ani Sinha <ani@anisinha.ca>
S: Supported
F: hw/acpi/viot.c
F: hw/acpi/viot.h

4
configure vendored
View File

@ -1659,8 +1659,8 @@ fi
# vhost interdependencies and host support
# vhost backends
if test "$vhost_user" = "yes" && test "$linux" != "yes"; then
error_exit "vhost-user is only available on Linux"
if test "$vhost_user" = "yes" && test "$mingw32" = "yes"; then
error_exit "vhost-user is not available on Windows"
fi
test "$vhost_vdpa" = "" && vhost_vdpa=$linux
if test "$vhost_vdpa" = "yes" && test "$linux" != "yes"; then

View File

@ -324,6 +324,14 @@ machine is hardly emulated at all (e.g. neither the LCD nor the USB part had
been implemented), so there is not much value added by this board. Use the
``ref405ep`` machine instead.
``pc-i440fx-1.4`` up to ``pc-i440fx-1.7`` (since 7.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''
These old machine types are quite neglected nowadays and thus might have
various pitfalls with regards to live migration. Use a newer machine type
instead.
Backend options
---------------

View File

@ -38,6 +38,26 @@ conventions <backend_conventions>`.
*Master* and *slave* can be either a client (i.e. connecting) or
server (listening) in the socket communication.
Support for platforms other than Linux
--------------------------------------
While vhost-user was initially developed targeting Linux, nowadays it
is supported on any platform that provides the following features:
- A way for requesting shared memory represented by a file descriptor
so it can be passed over a UNIX domain socket and then mapped by the
other process.
- AF_UNIX sockets with SCM_RIGHTS, so QEMU and the other process can
exchange messages through it, including ancillary data when needed.
- Either eventfd or pipe/pipe2. On platforms where eventfd is not
available, QEMU will automatically fall back to pipe2 or, as a last
resort, pipe. Each file descriptor will be used for receiving or
sending events by reading or writing (respectively) an 8-byte value
to the corresponding it. The 8-value itself has no meaning and
should not be interpreted.
Message Specification
=====================

115
docs/pcie_sriov.txt Normal file
View File

@ -0,0 +1,115 @@
PCI SR/IOV EMULATION SUPPORT
============================
Description
===========
SR/IOV (Single Root I/O Virtualization) is an optional extended capability
of a PCI Express device. It allows a single physical function (PF) to appear as multiple
virtual functions (VFs) for the main purpose of eliminating software
overhead in I/O from virtual machines.
Qemu now implements the basic common functionality to enable an emulated device
to support SR/IOV. Yet no fully implemented devices exists in Qemu, but a
proof-of-concept hack of the Intel igb can be found here:
git://github.com/knuto/qemu.git sriov_patches_v5
Implementation
==============
Implementing emulation of an SR/IOV capable device typically consists of
implementing support for two types of device classes; the "normal" physical device
(PF) and the virtual device (VF). From Qemu's perspective, the VFs are just
like other devices, except that some of their properties are derived from
the PF.
A virtual function is different from a physical function in that the BAR
space for all VFs are defined by the BAR registers in the PFs SR/IOV
capability. All VFs have the same BARs and BAR sizes.
Accesses to these virtual BARs then is computed as
<VF BAR start> + <VF number> * <BAR sz> + <offset>
From our emulation perspective this means that there is a separate call for
setting up a BAR for a VF.
1) To enable SR/IOV support in the PF, it must be a PCI Express device so
you would need to add a PCI Express capability in the normal PCI
capability list. You might also want to add an ARI (Alternative
Routing-ID Interpretation) capability to indicate that your device
supports functions beyond it's "own" function space (0-7),
which is necessary to support more than 7 functions, or
if functions extends beyond offset 7 because they are placed at an
offset > 1 or have stride > 1.
...
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_sriov.h"
pci_your_pf_dev_realize( ... )
{
...
int ret = pcie_endpoint_cap_init(d, 0x70);
...
pcie_ari_init(d, 0x100, 1);
...
/* Add and initialize the SR/IOV capability */
pcie_sriov_pf_init(d, 0x200, "your_virtual_dev",
vf_devid, initial_vfs, total_vfs,
fun_offset, stride);
/* Set up individual VF BARs (parameters as for normal BARs) */
pcie_sriov_pf_init_vf_bar( ... )
...
}
For cleanup, you simply call:
pcie_sriov_pf_exit(device);
which will delete all the virtual functions and associated resources.
2) Similarly in the implementation of the virtual function, you need to
make it a PCI Express device and add a similar set of capabilities
except for the SR/IOV capability. Then you need to set up the VF BARs as
subregions of the PFs SR/IOV VF BARs by calling
pcie_sriov_vf_register_bar() instead of the normal pci_register_bar() call:
pci_your_vf_dev_realize( ... )
{
...
int ret = pcie_endpoint_cap_init(d, 0x60);
...
pcie_ari_init(d, 0x100, 1);
...
memory_region_init(mr, ... )
pcie_sriov_vf_register_bar(d, bar_nr, mr);
...
}
Testing on Linux guest
======================
The easiest is if your device driver supports sysfs based SR/IOV
enabling. Support for this was added in kernel v.3.8, so not all drivers
support it yet.
To enable 4 VFs for a device at 01:00.0:
modprobe yourdriver
echo 4 > /sys/bus/pci/devices/0000:01:00.0/sriov_numvfs
You should now see 4 VFs with lspci.
To turn SR/IOV off again - the standard requires you to turn it off before you can enable
another VF count, and the emulation enforces this:
echo 0 > /sys/bus/pci/devices/0000:01:00.0/sriov_numvfs
Older drivers typically provide a max_vfs module parameter
to enable it at load time:
modprobe yourdriver max_vfs=4
To disable the VFs again then, you simply have to unload the driver:
rmmod yourdriver

200
docs/specs/acpi_erst.rst Normal file
View File

@ -0,0 +1,200 @@
ACPI ERST DEVICE
================
The ACPI ERST device is utilized to support the ACPI Error Record
Serialization Table, ERST, functionality. This feature is designed for
storing error records in persistent storage for future reference
and/or debugging.
The ACPI specification[1], in Chapter "ACPI Platform Error Interfaces
(APEI)", and specifically subsection "Error Serialization", outlines a
method for storing error records into persistent storage.
The format of error records is described in the UEFI specification[2],
in Appendix N "Common Platform Error Record".
While the ACPI specification allows for an NVRAM "mode" (see
GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES) where non-volatile RAM is
directly exposed for direct access by the OS/guest, this device
implements the non-NVRAM "mode". This non-NVRAM "mode" is what is
implemented by most BIOS (since flash memory requires programming
operations in order to update its contents). Furthermore, as of the
time of this writing, Linux only supports the non-NVRAM "mode".
Background/Motivation
---------------------
Linux uses the persistent storage filesystem, pstore, to record
information (eg. dmesg tail) upon panics and shutdowns. Pstore is
independent of, and runs before, kdump. In certain scenarios (ie.
hosts/guests with root filesystems on NFS/iSCSI where networking
software and/or hardware fails, and thus kdump fails), pstore may
contain information available for post-mortem debugging.
Two common storage backends for the pstore filesystem are ACPI ERST
and UEFI. Most BIOS implement ACPI ERST. UEFI is not utilized in all
guests. With QEMU supporting ACPI ERST, it becomes a viable pstore
storage backend for virtual machines (as it is now for bare metal
machines).
Enabling support for ACPI ERST facilitates a consistent method to
capture kernel panic information in a wide range of guests: from
resource-constrained microvms to very large guests, and in particular,
in direct-boot environments (which would lack UEFI run-time services).
Note that Microsoft Windows also utilizes the ACPI ERST for certain
crash information, if available[3].
Configuration|Usage
-------------------
To use ACPI ERST, a memory-backend-file object and acpi-erst device
can be created, for example:
qemu ...
-object memory-backend-file,id=erstnvram,mem-path=acpi-erst.backing,size=0x10000,share=on \
-device acpi-erst,memdev=erstnvram
For proper operation, the ACPI ERST device needs a memory-backend-file
object with the following parameters:
- id: The id of the memory-backend-file object is used to associate
this memory with the acpi-erst device.
- size: The size of the ACPI ERST backing storage. This parameter is
required.
- mem-path: The location of the ACPI ERST backing storage file. This
parameter is also required.
- share: The share=on parameter is required so that updates to the
ERST backing store are written to the file.
and ERST device:
- memdev: Is the object id of the memory-backend-file.
- record_size: Specifies the size of the records (or slots) in the
backend storage. Must be a power of two value greater than or
equal to 4096 (PAGE_SIZE).
PCI Interface
-------------
The ERST device is a PCI device with two BARs, one for accessing the
programming registers, and the other for accessing the record exchange
buffer.
BAR0 contains the programming interface consisting of ACTION and VALUE
64-bit registers. All ERST actions/operations/side effects happen on
the write to the ACTION, by design. Any data needed by the action must
be placed into VALUE prior to writing ACTION. Reading the VALUE
simply returns the register contents, which can be updated by a
previous ACTION.
BAR1 contains the 8KiB record exchange buffer, which is the
implemented maximum record size.
Backend Storage Format
----------------------
The backend storage is divided into fixed size "slots", 8KiB in
length, with each slot storing a single record. Not all slots need to
be occupied, and they need not be occupied in a contiguous fashion.
The ability to clear/erase specific records allows for the formation
of unoccupied slots.
Slot 0 contains a backend storage header that identifies the contents
as ERST and also facilitates efficient access to the records.
Depending upon the size of the backend storage, additional slots will
be designated to be a part of the slot 0 header. For example, at 8KiB,
the slot 0 header can accomodate 1021 records. Thus a storage size
of 8MiB (8KiB * 1024) requires an additional slot for use by the
header. In this scenario, slot 0 and slot 1 form the backend storage
header, and records can be stored starting at slot 2.
Below is an example layout of the backend storage format (for storage
size less than 8MiB). The size of the storage is a multiple of 8KiB,
and contains N number of slots to store records. The example below
shows two records (in CPER format) in the backend storage, while the
remaining slots are empty/available.
::
Slot Record
<------------------ 8KiB -------------------->
+--------------------------------------------+
0 | storage header |
+--------------------------------------------+
1 | empty/available |
+--------------------------------------------+
2 | CPER |
+--------------------------------------------+
3 | CPER |
+--------------------------------------------+
... | |
+--------------------------------------------+
N | empty/available |
+--------------------------------------------+
The storage header consists of some basic information and an array
of CPER record_id's to efficiently access records in the backend
storage.
All fields in the header are stored in little endian format.
::
+--------------------------------------------+
| magic | 0x0000
+--------------------------------------------+
| record_offset | record_size | 0x0008
+--------------------------------------------+
| record_count | reserved | version | 0x0010
+--------------------------------------------+
| record_id[0] | 0x0018
+--------------------------------------------+
| record_id[1] | 0x0020
+--------------------------------------------+
| record_id[...] |
+--------------------------------------------+
| record_id[N] | 0x1FF8
+--------------------------------------------+
The 'magic' field contains the value 0x524F545354535245.
The 'record_size' field contains the value 0x2000, 8KiB.
The 'record_offset' field points to the first record_id in the array,
0x0018.
The 'version' field contains 0x0100, the first version.
The 'record_count' field contains the number of valid records in the
backend storage.
The 'record_id' array fields are the 64-bit record identifiers of the
CPER record in the corresponding slot. Stated differently, the
location of a CPER record_id in the record_id[] array provides the
slot index for the corresponding record in the backend storage.
Note that, for example, with a backend storage less than 8MiB, slot 0
contains the header, so the record_id[0] will never contain a valid
CPER record_id. Instead slot 1 is the first available slot and thus
record_id_[1] may contain a CPER.
A 'record_id' of all 0s or all 1s indicates an invalid record (ie. the
slot is available).
References
----------
[1] "Advanced Configuration and Power Interface Specification",
version 4.0, June 2009.
[2] "Unified Extensible Firmware Interface Specification",
version 2.1, October 2008.
[3] "Windows Hardware Error Architecture", specfically
"Error Record Persistence Mechanism".

View File

@ -18,4 +18,5 @@ guest hardware that is specific to QEMU.
acpi_mem_hotplug
acpi_pci_hotplug
acpi_nvdimm
acpi_erst
sev-guest-firmware

View File

@ -65,6 +65,7 @@ PCI devices (other than virtio):
1b36:000f mdpy (mdev sample device), linux/samples/vfio-mdev/mdpy.c
1b36:0010 PCIe NVMe device (-device nvme)
1b36:0011 PCI PVPanic device (-device pvpanic-pci)
1b36:0012 PCI ACPI ERST device (-device acpi-erst)
All these devices are documented in docs/specs.

View File

@ -2152,7 +2152,13 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
build_append_int_noprefix(tbl, 0, 1); /* DAY_ALRM */
build_append_int_noprefix(tbl, 0, 1); /* MON_ALRM */
build_append_int_noprefix(tbl, f->rtc_century, 1); /* CENTURY */
build_append_int_noprefix(tbl, 0, 2); /* IAPC_BOOT_ARCH */
/* IAPC_BOOT_ARCH */
if (f->rev == 1) {
build_append_int_noprefix(tbl, 0, 2);
} else {
/* since ACPI v2.0 */
build_append_int_noprefix(tbl, f->iapc_boot_arch, 2);
}
build_append_int_noprefix(tbl, 0, 1); /* Reserved */
build_append_int_noprefix(tbl, f->flags, 4); /* Flags */

View File

@ -80,11 +80,6 @@
#define UEFI_CPER_RECORD_MIN_SIZE 128U
#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U
#define UEFI_CPER_RECORD_ID_OFFSET 96U
#define IS_UEFI_CPER_RECORD(ptr) \
(((ptr)[0] == 'C') && \
((ptr)[1] == 'P') && \
((ptr)[2] == 'E') && \
((ptr)[3] == 'R'))
/*
* NOTE that when accessing CPER fields within a record, memcpy()

View File

@ -32,6 +32,7 @@
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h"
#include "hw/pci/pcie_port.h"
#include "hw/pci-bridge/xio3130_downstream.h"
#include "hw/i386/acpi-build.h"
#include "hw/acpi/acpi.h"
#include "hw/pci/pci_bus.h"
@ -336,6 +337,8 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
{
PCIDevice *pdev = PCI_DEVICE(dev);
int slot = PCI_SLOT(pdev->devfn);
PCIDevice *bridge;
PCIBus *bus;
int bsel;
/* Don't send event when device is enabled during qemu machine creation:
@ -365,7 +368,14 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
return;
}
bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
bus = pci_get_bus(pdev);
bridge = pci_bridge_get_device(bus);
if (object_dynamic_cast(OBJECT(bridge), TYPE_PCIE_ROOT_PORT) ||
object_dynamic_cast(OBJECT(bridge), TYPE_XIO3130_DOWNSTREAM)) {
pcie_cap_slot_enable_power(bridge);
}
bsel = acpi_pcihp_get_bsel(bus);
g_assert(bsel >= 0);
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);

View File

@ -38,6 +38,7 @@
#include "hw/nvram/fw_cfg.h"
#include "hw/acpi/bios-linker-loader.h"
#include "hw/isa/isa.h"
#include "hw/input/i8042.h"
#include "hw/block/fdc.h"
#include "hw/acpi/memory_hotplug.h"
#include "sysemu/tpm.h"
@ -192,6 +193,13 @@ static void init_common_fadt_data(MachineState *ms, Object *o,
.address = object_property_get_uint(o, ACPI_PM_PROP_GPE0_BLK, NULL)
},
};
/*
* ACPI v2, Table 5-10 - Fixed ACPI Description Table Boot Architecture
* Flags, bit offset 1 - 8042.
*/
fadt.iapc_boot_arch = iapc_boot_arch_8042();
*data = fadt;
}

View File

@ -37,6 +37,7 @@
#include "hw/pci/pcie_host.h"
#include "hw/usb/xhci.h"
#include "hw/virtio/virtio-mmio.h"
#include "hw/input/i8042.h"
#include "acpi-common.h"
#include "acpi-microvm.h"
@ -187,6 +188,11 @@ static void acpi_build_microvm(AcpiBuildTables *tables,
.address = GED_MMIO_BASE_REGS + ACPI_GED_REG_RESET,
},
.reset_val = ACPI_GED_RESET_VALUE,
/*
* ACPI v2, Table 5-10 - Fixed ACPI Description Table Boot Architecture
* Flags, bit offset 1 - 8042.
*/
.iapc_boot_arch = iapc_boot_arch_8042(),
};
table_offsets = g_array_new(false, true /* clear */,

View File

@ -3030,6 +3030,13 @@ static int vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
IntelIOMMUState *s = vtd_as->iommu_state;
/* TODO: add support for VFIO and vhost users */
if (s->snoop_control) {
error_setg_errno(errp, -ENOTSUP,
"Snoop Control with vhost or VFIO is not supported");
return -ENOTSUP;
}
/* Update per-address-space notifier flags */
vtd_as->notifier_flags = new;
@ -3113,6 +3120,7 @@ static Property vtd_properties[] = {
VTD_HOST_ADDRESS_WIDTH),
DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE),
DEFINE_PROP_BOOL("x-scalable-mode", IntelIOMMUState, scalable_mode, FALSE),
DEFINE_PROP_BOOL("snoop-control", IntelIOMMUState, snoop_control, false),
DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true),
DEFINE_PROP_END_OF_LIST(),
};
@ -3643,7 +3651,7 @@ static void vtd_init(IntelIOMMUState *s)
vtd_spte_rsvd_large[3] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits,
x86_iommu->dt_supported);
if (s->scalable_mode) {
if (s->scalable_mode || s->snoop_control) {
vtd_spte_rsvd[1] &= ~VTD_SPTE_SNP;
vtd_spte_rsvd_large[2] &= ~VTD_SPTE_SNP;
vtd_spte_rsvd_large[3] &= ~VTD_SPTE_SNP;
@ -3674,6 +3682,10 @@ static void vtd_init(IntelIOMMUState *s)
s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_SLTS;
}
if (s->snoop_control) {
s->ecap |= VTD_ECAP_SC;
}
vtd_reset_caches(s);
/* Define registers with default values and bit semantics */

View File

@ -188,6 +188,7 @@
#define VTD_ECAP_IR (1ULL << 3)
#define VTD_ECAP_EIM (1ULL << 4)
#define VTD_ECAP_PT (1ULL << 6)
#define VTD_ECAP_SC (1ULL << 7)
#define VTD_ECAP_MHMV (15ULL << 20)
#define VTD_ECAP_SRS (1ULL << 31)
#define VTD_ECAP_SMTS (1ULL << 43)

View File

@ -318,8 +318,6 @@ GlobalProperty pc_compat_2_0[] = {
{ "pci-serial-4x", "prog_if", "0" },
{ "virtio-net-pci", "guest_announce", "off" },
{ "ICH9-LPC", "memory-hotplug-support", "off" },
{ "xio3130-downstream", COMPAT_PROP_PCP, "off" },
{ "ioh3420", COMPAT_PROP_PCP, "off" },
};
const size_t pc_compat_2_0_len = G_N_ELEMENTS(pc_compat_2_0);
@ -1014,7 +1012,8 @@ static const MemoryRegionOps ioportF0_io_ops = {
},
};
static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport)
static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl,
bool create_i8042, bool no_vmport)
{
int i;
DriveInfo *fd[MAX_FD];
@ -1036,6 +1035,10 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport)
}
}
if (!create_i8042) {
return;
}
i8042 = isa_create_simple(isa_bus, "i8042");
if (!no_vmport) {
isa_create_simple(isa_bus, TYPE_VMPORT);
@ -1131,7 +1134,8 @@ void pc_basic_device_init(struct PCMachineState *pcms,
i8257_dma_init(isa_bus, 0);
/* Super I/O */
pc_superio_init(isa_bus, create_fdctrl, pcms->vmport != ON_OFF_AUTO_ON);
pc_superio_init(isa_bus, create_fdctrl, pcms->i8042_enabled,
pcms->vmport != ON_OFF_AUTO_ON);
}
void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
@ -1512,6 +1516,20 @@ static void pc_machine_set_hpet(Object *obj, bool value, Error **errp)
pcms->hpet_enabled = value;
}
static bool pc_machine_get_i8042(Object *obj, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
return pcms->i8042_enabled;
}
static void pc_machine_set_i8042(Object *obj, bool value, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
pcms->i8042_enabled = value;
}
static bool pc_machine_get_default_bus_bypass_iommu(Object *obj, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
@ -1641,6 +1659,7 @@ static void pc_machine_initfn(Object *obj)
pcms->smbus_enabled = true;
pcms->sata_enabled = true;
pcms->pit_enabled = true;
pcms->i8042_enabled = true;
pcms->max_fw_size = 8 * MiB;
#ifdef CONFIG_HPET
pcms->hpet_enabled = true;
@ -1777,6 +1796,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "hpet",
"Enable/disable high precision event timer emulation");
object_class_property_add_bool(oc, PC_MACHINE_I8042,
pc_machine_get_i8042, pc_machine_set_i8042);
object_class_property_add_bool(oc, "default-bus-bypass-iommu",
pc_machine_get_default_bus_bypass_iommu,
pc_machine_set_default_bus_bypass_iommu);

View File

@ -757,6 +757,7 @@ static void pc_i440fx_1_7_machine_options(MachineClass *m)
m->hw_version = "1.7.0";
m->default_machine_opts = NULL;
m->option_rom_has_mr = true;
m->deprecation_reason = "old and unattended - use a newer version instead";
compat_props_add(m->compat_props, pc_compat_1_7, pc_compat_1_7_len);
pcmc->smbios_defaults = false;
pcmc->gigabyte_align = false;

View File

@ -83,24 +83,11 @@ inline void init_topo_info(X86CPUTopoInfo *topo_info,
uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms,
unsigned int cpu_index)
{
X86MachineClass *x86mc = X86_MACHINE_GET_CLASS(x86ms);
X86CPUTopoInfo topo_info;
uint32_t correct_id;
static bool warned;
init_topo_info(&topo_info, x86ms);
correct_id = x86_apicid_from_cpu_idx(&topo_info, cpu_index);
if (x86mc->compat_apic_id_mode) {
if (cpu_index != correct_id && !warned && !qtest_enabled()) {
error_report("APIC IDs set in compatibility mode, "
"CPU topology won't match the configuration");
warned = true;
}
return cpu_index;
} else {
return correct_id;
}
return x86_apicid_from_cpu_idx(&topo_info, cpu_index);
}
@ -1330,7 +1317,6 @@ static void x86_machine_class_init(ObjectClass *oc, void *data)
mc->cpu_index_to_instance_props = x86_cpu_index_to_props;
mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
x86mc->compat_apic_id_mode = false;
x86mc->save_tsc_khz = true;
x86mc->fwcfg_dma_enabled = true;
nc->nmi_monitor_handler = x86_nmi;

View File

@ -21,6 +21,7 @@
#include "hw/misc/pvpanic.h"
#include "qom/object.h"
#include "hw/isa/isa.h"
#include "standard-headers/linux/pvpanic.h"
OBJECT_DECLARE_SIMPLE_TYPE(PVPanicISAState, PVPANIC_ISA_DEVICE)
@ -64,7 +65,8 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
static Property pvpanic_isa_properties[] = {
DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicISAState, ioport, 0x505),
DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events, PVPANIC_PANICKED | PVPANIC_CRASHLOADED),
DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events,
PVPANIC_PANICKED | PVPANIC_CRASH_LOADED),
DEFINE_PROP_END_OF_LIST(),
};

View File

@ -21,6 +21,7 @@
#include "hw/misc/pvpanic.h"
#include "qom/object.h"
#include "hw/pci/pci.h"
#include "standard-headers/linux/pvpanic.h"
OBJECT_DECLARE_SIMPLE_TYPE(PVPanicPCIState, PVPANIC_PCI_DEVICE)
@ -53,7 +54,8 @@ static void pvpanic_pci_realizefn(PCIDevice *dev, Error **errp)
}
static Property pvpanic_pci_properties[] = {
DEFINE_PROP_UINT8("events", PVPanicPCIState, pvpanic.events, PVPANIC_PANICKED | PVPANIC_CRASHLOADED),
DEFINE_PROP_UINT8("events", PVPanicPCIState, pvpanic.events,
PVPANIC_PANICKED | PVPANIC_CRASH_LOADED),
DEFINE_PROP_END_OF_LIST(),
};

View File

@ -21,12 +21,13 @@
#include "hw/qdev-properties.h"
#include "hw/misc/pvpanic.h"
#include "qom/object.h"
#include "standard-headers/linux/pvpanic.h"
static void handle_event(int event)
{
static bool logged;
if (event & ~(PVPANIC_PANICKED | PVPANIC_CRASHLOADED) && !logged) {
if (event & ~(PVPANIC_PANICKED | PVPANIC_CRASH_LOADED) && !logged) {
qemu_log_mask(LOG_GUEST_ERROR, "pvpanic: unknown event %#x.\n", event);
logged = true;
}
@ -36,7 +37,7 @@ static void handle_event(int event)
return;
}
if (event & PVPANIC_CRASHLOADED) {
if (event & PVPANIC_CRASH_LOADED) {
qemu_system_guest_crashloaded(NULL);
return;
}

View File

@ -628,17 +628,20 @@ static int virtio_net_max_tx_queue_size(VirtIONet *n)
NetClientState *peer = n->nic_conf.peers.ncs[0];
/*
* Backends other than vhost-user don't support max queue size.
* Backends other than vhost-user or vhost-vdpa don't support max queue
* size.
*/
if (!peer) {
return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE;
}
if (peer->info->type != NET_CLIENT_DRIVER_VHOST_USER) {
switch(peer->info->type) {
case NET_CLIENT_DRIVER_VHOST_USER:
case NET_CLIENT_DRIVER_VHOST_VDPA:
return VIRTQUEUE_MAX_SIZE;
default:
return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE;
}
return VIRTQUEUE_MAX_SIZE;
};
}
static int peer_attach(VirtIONet *n, int index)

View File

@ -192,6 +192,12 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
{
PCIDevice *pxb = pci_get_bus(pci_dev)->parent_dev;
/*
* First carry out normal swizzle to handle
* multple root ports on a pxb instance.
*/
pin = pci_swizzle_map_irq_fn(pci_dev, pin);
/*
* The bios does not index the pxb slot number when
* it computes the IRQ because it resides on bus 0

View File

@ -28,6 +28,7 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "hw/pci-bridge/xio3130_downstream.h"
#define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */
#define XIO3130_REVISION 0x1
@ -84,7 +85,7 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp)
XIO3130_SSVID_SVID, XIO3130_SSVID_SSID,
errp);
if (rc < 0) {
goto err_bridge;
goto err_msi;
}
rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
@ -173,7 +174,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo xio3130_downstream_info = {
.name = "xio3130-downstream",
.name = TYPE_XIO3130_DOWNSTREAM,
.parent = TYPE_PCIE_SLOT,
.class_init = xio3130_downstream_class_init,
.interfaces = (InterfaceInfo[]) {

View File

@ -75,7 +75,7 @@ static void xio3130_upstream_realize(PCIDevice *d, Error **errp)
XIO3130_SSVID_SVID, XIO3130_SSVID_SSID,
errp);
if (rc < 0) {
goto err_bridge;
goto err_msi;
}
rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,

View File

@ -5,6 +5,7 @@ pci_ss.add(files(
'pci.c',
'pci_bridge.c',
'pci_host.c',
'pcie_sriov.c',
'shpc.c',
'slotid_cap.c'
))

View File

@ -239,6 +239,9 @@ int pci_bar(PCIDevice *d, int reg)
{
uint8_t type;
/* PCIe virtual functions do not have their own BARs */
assert(!pci_is_vf(d));
if (reg != PCI_ROM_SLOT)
return PCI_BASE_ADDRESS_0 + reg * 4;
@ -304,10 +307,30 @@ void pci_device_deassert_intx(PCIDevice *dev)
}
}
static void pci_do_device_reset(PCIDevice *dev)
static void pci_reset_regions(PCIDevice *dev)
{
int r;
if (pci_is_vf(dev)) {
return;
}
for (r = 0; r < PCI_NUM_REGIONS; ++r) {
PCIIORegion *region = &dev->io_regions[r];
if (!region->size) {
continue;
}
if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) &&
region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
pci_set_quad(dev->config + pci_bar(dev, r), region->type);
} else {
pci_set_long(dev->config + pci_bar(dev, r), region->type);
}
}
}
static void pci_do_device_reset(PCIDevice *dev)
{
pci_device_deassert_intx(dev);
assert(dev->irq_state == 0);
@ -323,19 +346,7 @@ static void pci_do_device_reset(PCIDevice *dev)
pci_get_word(dev->wmask + PCI_INTERRUPT_LINE) |
pci_get_word(dev->w1cmask + PCI_INTERRUPT_LINE));
dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
for (r = 0; r < PCI_NUM_REGIONS; ++r) {
PCIIORegion *region = &dev->io_regions[r];
if (!region->size) {
continue;
}
if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) &&
region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
pci_set_quad(dev->config + pci_bar(dev, r), region->type);
} else {
pci_set_long(dev->config + pci_bar(dev, r), region->type);
}
}
pci_reset_regions(dev);
pci_update_mappings(dev);
msi_reset(dev);
@ -884,6 +895,16 @@ static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp)
dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
}
/*
* With SR/IOV and ARI, a device at function 0 need not be a multifunction
* device, as it may just be a VF that ended up with function 0 in
* the legacy PCI interpretation. Avoid failing in such cases:
*/
if (pci_is_vf(dev) &&
dev->exp.sriov_vf.pf->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
return;
}
/*
* multifunction bit is interpreted in two ways as follows.
* - all functions must set the bit to 1.
@ -1078,11 +1099,12 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev,
return NULL;
} else if (!pci_bus_devfn_available(bus, devfn)) {
error_setg(errp, "PCI: slot %d function %d not available for %s,"
" in use by %s",
" in use by %s,id=%s",
PCI_SLOT(devfn), PCI_FUNC(devfn), name,
bus->devices[devfn]->name);
bus->devices[devfn]->name, bus->devices[devfn]->qdev.id);
return NULL;
} else if (dev->hotplugged &&
!pci_is_vf(pci_dev) &&
pci_get_function_0(pci_dev)) {
error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" new func %s cannot be exposed to guest.",
@ -1191,6 +1213,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
pcibus_t size = memory_region_size(memory);
uint8_t hdr_type;
assert(!pci_is_vf(pci_dev)); /* VFs must use pcie_sriov_vf_register_bar */
assert(region_num >= 0);
assert(region_num < PCI_NUM_REGIONS);
assert(is_power_of_2(size));
@ -1294,11 +1317,45 @@ pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
return pci_dev->io_regions[region_num].addr;
}
static pcibus_t pci_bar_address(PCIDevice *d,
int reg, uint8_t type, pcibus_t size)
static pcibus_t pci_config_get_bar_addr(PCIDevice *d, int reg,
uint8_t type, pcibus_t size)
{
pcibus_t new_addr;
if (!pci_is_vf(d)) {
int bar = pci_bar(d, reg);
if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
new_addr = pci_get_quad(d->config + bar);
} else {
new_addr = pci_get_long(d->config + bar);
}
} else {
PCIDevice *pf = d->exp.sriov_vf.pf;
uint16_t sriov_cap = pf->exp.sriov_cap;
int bar = sriov_cap + PCI_SRIOV_BAR + reg * 4;
uint16_t vf_offset =
pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_OFFSET);
uint16_t vf_stride =
pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_STRIDE);
uint32_t vf_num = (d->devfn - (pf->devfn + vf_offset)) / vf_stride;
if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
new_addr = pci_get_quad(pf->config + bar);
} else {
new_addr = pci_get_long(pf->config + bar);
}
new_addr += vf_num * size;
}
/* The ROM slot has a specific enable bit, keep it intact */
if (reg != PCI_ROM_SLOT) {
new_addr &= ~(size - 1);
}
return new_addr;
}
pcibus_t pci_bar_address(PCIDevice *d,
int reg, uint8_t type, pcibus_t size)
{
pcibus_t new_addr, last_addr;
int bar = pci_bar(d, reg);
uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);
Object *machine = qdev_get_machine();
ObjectClass *oc = object_get_class(machine);
@ -1309,7 +1366,7 @@ static pcibus_t pci_bar_address(PCIDevice *d,
if (!(cmd & PCI_COMMAND_IO)) {
return PCI_BAR_UNMAPPED;
}
new_addr = pci_get_long(d->config + bar) & ~(size - 1);
new_addr = pci_config_get_bar_addr(d, reg, type, size);
last_addr = new_addr + size - 1;
/* Check if 32 bit BAR wraps around explicitly.
* TODO: make priorities correct and remove this work around.
@ -1324,11 +1381,7 @@ static pcibus_t pci_bar_address(PCIDevice *d,
if (!(cmd & PCI_COMMAND_MEMORY)) {
return PCI_BAR_UNMAPPED;
}
if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
new_addr = pci_get_quad(d->config + bar);
} else {
new_addr = pci_get_long(d->config + bar);
}
new_addr = pci_config_get_bar_addr(d, reg, type, size);
/* the ROM slot has a specific enable bit */
if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) {
return PCI_BAR_UNMAPPED;
@ -1473,6 +1526,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int
msi_write_config(d, addr, val_in, l);
msix_write_config(d, addr, val_in, l);
pcie_sriov_config_write(d, addr, val_in, l);
}
/***********************************************************/

View File

@ -366,6 +366,17 @@ static void hotplug_event_clear(PCIDevice *dev)
}
}
void pcie_cap_slot_enable_power(PCIDevice *dev)
{
uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
uint32_t sltcap = pci_get_long(exp_cap + PCI_EXP_SLTCAP);
if (sltcap & PCI_EXP_SLTCAP_PCP) {
pci_set_word_by_mask(exp_cap + PCI_EXP_SLTCTL,
PCI_EXP_SLTCTL_PCC, PCI_EXP_SLTCTL_PWR_ON);
}
}
static void pcie_set_power_device(PCIBus *bus, PCIDevice *dev, void *opaque)
{
bool *power = opaque;
@ -446,6 +457,11 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
PCIDevice *pci_dev = PCI_DEVICE(dev);
uint32_t lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP);
if (pci_is_vf(pci_dev)) {
/* Virtual function cannot be physically disconnected */
return;
}
/* Don't send event when device is enabled during qemu machine creation:
* it is present on boot, no hotplug event is necessary. We do send an
* event when the device is disabled later. */

302
hw/pci/pcie_sriov.c Normal file
View File

@ -0,0 +1,302 @@
/*
* pcie_sriov.c:
*
* Implementation of SR/IOV emulation support.
*
* Copyright (c) 2015-2017 Knut Omang <knut.omang@oracle.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pci_bus.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
#include "qemu/range.h"
#include "qapi/error.h"
#include "trace.h"
static PCIDevice *register_vf(PCIDevice *pf, int devfn,
const char *name, uint16_t vf_num);
static void unregister_vfs(PCIDevice *dev);
void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
const char *vfname, uint16_t vf_dev_id,
uint16_t init_vfs, uint16_t total_vfs,
uint16_t vf_offset, uint16_t vf_stride)
{
uint8_t *cfg = dev->config + offset;
uint8_t *wmask;
pcie_add_capability(dev, PCI_EXT_CAP_ID_SRIOV, 1,
offset, PCI_EXT_CAP_SRIOV_SIZEOF);
dev->exp.sriov_cap = offset;
dev->exp.sriov_pf.num_vfs = 0;
dev->exp.sriov_pf.vfname = g_strdup(vfname);
dev->exp.sriov_pf.vf = NULL;
pci_set_word(cfg + PCI_SRIOV_VF_OFFSET, vf_offset);
pci_set_word(cfg + PCI_SRIOV_VF_STRIDE, vf_stride);
/*
* Mandatory page sizes to support.
* Device implementations can call pcie_sriov_pf_add_sup_pgsize()
* to set more bits:
*/
pci_set_word(cfg + PCI_SRIOV_SUP_PGSIZE, SRIOV_SUP_PGSIZE_MINREQ);
/*
* Default is to use 4K pages, software can modify it
* to any of the supported bits
*/
pci_set_word(cfg + PCI_SRIOV_SYS_PGSIZE, 0x1);
/* Set up device ID and initial/total number of VFs available */
pci_set_word(cfg + PCI_SRIOV_VF_DID, vf_dev_id);
pci_set_word(cfg + PCI_SRIOV_INITIAL_VF, init_vfs);
pci_set_word(cfg + PCI_SRIOV_TOTAL_VF, total_vfs);
pci_set_word(cfg + PCI_SRIOV_NUM_VF, 0);
/* Write enable control bits */
wmask = dev->wmask + offset;
pci_set_word(wmask + PCI_SRIOV_CTRL,
PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE | PCI_SRIOV_CTRL_ARI);
pci_set_word(wmask + PCI_SRIOV_NUM_VF, 0xffff);
pci_set_word(wmask + PCI_SRIOV_SYS_PGSIZE, 0x553);
qdev_prop_set_bit(&dev->qdev, "multifunction", true);
}
void pcie_sriov_pf_exit(PCIDevice *dev)
{
unregister_vfs(dev);
g_free((char *)dev->exp.sriov_pf.vfname);
dev->exp.sriov_pf.vfname = NULL;
}
void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
uint8_t type, dma_addr_t size)
{
uint32_t addr;
uint64_t wmask;
uint16_t sriov_cap = dev->exp.sriov_cap;
assert(sriov_cap > 0);
assert(region_num >= 0);
assert(region_num < PCI_NUM_REGIONS);
assert(region_num != PCI_ROM_SLOT);
wmask = ~(size - 1);
addr = sriov_cap + PCI_SRIOV_BAR + region_num * 4;
pci_set_long(dev->config + addr, type);
if (!(type & PCI_BASE_ADDRESS_SPACE_IO) &&
type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
pci_set_quad(dev->wmask + addr, wmask);
pci_set_quad(dev->cmask + addr, ~0ULL);
} else {
pci_set_long(dev->wmask + addr, wmask & 0xffffffff);
pci_set_long(dev->cmask + addr, 0xffffffff);
}
dev->exp.sriov_pf.vf_bar_type[region_num] = type;
}
void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num,
MemoryRegion *memory)
{
PCIIORegion *r;
PCIBus *bus = pci_get_bus(dev);
uint8_t type;
pcibus_t size = memory_region_size(memory);
assert(pci_is_vf(dev)); /* PFs must use pci_register_bar */
assert(region_num >= 0);
assert(region_num < PCI_NUM_REGIONS);
type = dev->exp.sriov_vf.pf->exp.sriov_pf.vf_bar_type[region_num];
if (!is_power_of_2(size)) {
error_report("%s: PCI region size must be a power"
" of two - type=0x%x, size=0x%"FMT_PCIBUS,
__func__, type, size);
exit(1);
}
r = &dev->io_regions[region_num];
r->memory = memory;
r->address_space =
type & PCI_BASE_ADDRESS_SPACE_IO
? bus->address_space_io
: bus->address_space_mem;
r->size = size;
r->type = type;
r->addr = pci_bar_address(dev, region_num, r->type, r->size);
if (r->addr != PCI_BAR_UNMAPPED) {
memory_region_add_subregion_overlap(r->address_space,
r->addr, r->memory, 1);
}
}
static PCIDevice *register_vf(PCIDevice *pf, int devfn, const char *name,
uint16_t vf_num)
{
PCIDevice *dev = pci_new(devfn, name);
dev->exp.sriov_vf.pf = pf;
dev->exp.sriov_vf.vf_number = vf_num;
PCIBus *bus = pci_get_bus(pf);
Error *local_err = NULL;
qdev_realize(&dev->qdev, &bus->qbus, &local_err);
if (local_err) {
error_report_err(local_err);
return NULL;
}
/* set vid/did according to sr/iov spec - they are not used */
pci_config_set_vendor_id(dev->config, 0xffff);
pci_config_set_device_id(dev->config, 0xffff);
return dev;
}
static void register_vfs(PCIDevice *dev)
{
uint16_t num_vfs;
uint16_t i;
uint16_t sriov_cap = dev->exp.sriov_cap;
uint16_t vf_offset =
pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_OFFSET);
uint16_t vf_stride =
pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_STRIDE);
int32_t devfn = dev->devfn + vf_offset;
assert(sriov_cap > 0);
num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
dev->exp.sriov_pf.vf = g_malloc(sizeof(PCIDevice *) * num_vfs);
assert(dev->exp.sriov_pf.vf);
trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), num_vfs);
for (i = 0; i < num_vfs; i++) {
dev->exp.sriov_pf.vf[i] = register_vf(dev, devfn,
dev->exp.sriov_pf.vfname, i);
if (!dev->exp.sriov_pf.vf[i]) {
num_vfs = i;
break;
}
devfn += vf_stride;
}
dev->exp.sriov_pf.num_vfs = num_vfs;
}
static void unregister_vfs(PCIDevice *dev)
{
Error *local_err = NULL;
uint16_t num_vfs = dev->exp.sriov_pf.num_vfs;
uint16_t i;
trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), num_vfs);
for (i = 0; i < num_vfs; i++) {
PCIDevice *vf = dev->exp.sriov_pf.vf[i];
object_property_set_bool(OBJECT(vf), "realized", false, &local_err);
if (local_err) {
fprintf(stderr, "Failed to unplug: %s\n",
error_get_pretty(local_err));
error_free(local_err);
}
object_unparent(OBJECT(vf));
}
g_free(dev->exp.sriov_pf.vf);
dev->exp.sriov_pf.vf = NULL;
dev->exp.sriov_pf.num_vfs = 0;
pci_set_word(dev->config + dev->exp.sriov_cap + PCI_SRIOV_NUM_VF, 0);
}
void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
uint32_t val, int len)
{
uint32_t off;
uint16_t sriov_cap = dev->exp.sriov_cap;
if (!sriov_cap || address < sriov_cap) {
return;
}
off = address - sriov_cap;
if (off >= PCI_EXT_CAP_SRIOV_SIZEOF) {
return;
}
trace_sriov_config_write(dev->name, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), off, val, len);
if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) {
if (dev->exp.sriov_pf.num_vfs) {
if (!(val & PCI_SRIOV_CTRL_VFE)) {
unregister_vfs(dev);
}
} else {
if (val & PCI_SRIOV_CTRL_VFE) {
register_vfs(dev);
}
}
}
}
/* Reset SR/IOV VF Enable bit to trigger an unregister of all VFs */
void pcie_sriov_pf_disable_vfs(PCIDevice *dev)
{
uint16_t sriov_cap = dev->exp.sriov_cap;
if (sriov_cap) {
uint32_t val = pci_get_byte(dev->config + sriov_cap + PCI_SRIOV_CTRL);
if (val & PCI_SRIOV_CTRL_VFE) {
val &= ~PCI_SRIOV_CTRL_VFE;
pcie_sriov_config_write(dev, sriov_cap + PCI_SRIOV_CTRL, val, 1);
}
}
}
/* Add optional supported page sizes to the mask of supported page sizes */
void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize)
{
uint8_t *cfg = dev->config + dev->exp.sriov_cap;
uint8_t *wmask = dev->wmask + dev->exp.sriov_cap;
uint16_t sup_pgsize = pci_get_word(cfg + PCI_SRIOV_SUP_PGSIZE);
sup_pgsize |= opt_sup_pgsize;
/*
* Make sure the new bits are set, and that system page size
* also can be set to any of the new values according to spec:
*/
pci_set_word(cfg + PCI_SRIOV_SUP_PGSIZE, sup_pgsize);
pci_set_word(wmask + PCI_SRIOV_SYS_PGSIZE, sup_pgsize);
}
uint16_t pcie_sriov_vf_number(PCIDevice *dev)
{
assert(pci_is_vf(dev));
return dev->exp.sriov_vf.vf_number;
}
PCIDevice *pcie_sriov_get_pf(PCIDevice *dev)
{
return dev->exp.sriov_vf.pf;
}
PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n)
{
assert(!pci_is_vf(dev));
if (n < dev->exp.sriov_pf.num_vfs) {
return dev->exp.sriov_pf.vf[n];
}
return NULL;
}

View File

@ -10,3 +10,8 @@ pci_cfg_write(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, unsig
# msix.c
msix_write_config(char *name, bool enabled, bool masked) "dev %s enabled %d masked %d"
# hw/pci/pcie_sriov.c
sriov_register_vfs(const char *name, int slot, int function, int num_vfs) "%s %02x:%x: creating %d vf devs"
sriov_unregister_vfs(const char *name, int slot, int function, int num_vfs) "%s %02x:%x: Unregistering %d vf devs"
sriov_config_write(const char *name, int slot, int fun, uint32_t offset, uint32_t val, uint32_t len) "%s %02x:%x: sriov offset 0x%x val 0x%x len %d"

View File

@ -104,9 +104,11 @@ static struct {
const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
uint64_t max_speed;
uint64_t current_speed;
uint64_t processor_id;
} type4 = {
.max_speed = DEFAULT_CPU_SPEED,
.current_speed = DEFAULT_CPU_SPEED
.current_speed = DEFAULT_CPU_SPEED,
.processor_id = 0,
};
static struct {
@ -327,6 +329,10 @@ static const QemuOptDesc qemu_smbios_type4_opts[] = {
.name = "part",
.type = QEMU_OPT_STRING,
.help = "part number",
}, {
.name = "processor-id",
.type = QEMU_OPT_NUMBER,
.help = "processor id",
},
{ /* end of list */ }
};
@ -549,9 +555,23 @@ bool smbios_skip_table(uint8_t type, bool required_table)
return true;
}
#define T0_BASE 0x000
#define T1_BASE 0x100
#define T2_BASE 0x200
#define T3_BASE 0x300
#define T4_BASE 0x400
#define T11_BASE 0xe00
#define T16_BASE 0x1000
#define T17_BASE 0x1100
#define T19_BASE 0x1300
#define T32_BASE 0x2000
#define T41_BASE 0x2900
#define T127_BASE 0x7F00
static void smbios_build_type_0_table(void)
{
SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */
SMBIOS_BUILD_TABLE_PRE(0, T0_BASE, false); /* optional, leave up to BIOS */
SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
@ -599,7 +619,7 @@ static void smbios_encode_uuid(struct smbios_uuid *uuid, QemuUUID *in)
static void smbios_build_type_1_table(void)
{
SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
SMBIOS_BUILD_TABLE_PRE(1, T1_BASE, true); /* required */
SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
@ -619,7 +639,7 @@ static void smbios_build_type_1_table(void)
static void smbios_build_type_2_table(void)
{
SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */
SMBIOS_BUILD_TABLE_PRE(2, T2_BASE, false); /* optional */
SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
@ -637,7 +657,7 @@ static void smbios_build_type_2_table(void)
static void smbios_build_type_3_table(void)
{
SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */
SMBIOS_BUILD_TABLE_PRE(3, T3_BASE, true); /* required */
SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
t->type = 0x01; /* Other */
@ -662,15 +682,20 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance)
{
char sock_str[128];
SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */
SMBIOS_BUILD_TABLE_PRE(4, T4_BASE + instance, true); /* required */
snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
t->processor_type = 0x03; /* CPU */
t->processor_family = 0x01; /* Other */
SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
t->processor_id[0] = cpu_to_le32(smbios_cpuid_version);
t->processor_id[1] = cpu_to_le32(smbios_cpuid_features);
if (type4.processor_id == 0) {
t->processor_id[0] = cpu_to_le32(smbios_cpuid_version);
t->processor_id[1] = cpu_to_le32(smbios_cpuid_features);
} else {
t->processor_id[0] = cpu_to_le32((uint32_t)type4.processor_id);
t->processor_id[1] = cpu_to_le32(type4.processor_id >> 32);
}
SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
t->voltage = 0;
t->external_clock = cpu_to_le16(0); /* Unknown */
@ -702,7 +727,7 @@ static void smbios_build_type_11_table(void)
return;
}
SMBIOS_BUILD_TABLE_PRE(11, 0xe00, true); /* required */
SMBIOS_BUILD_TABLE_PRE(11, T11_BASE, true); /* required */
snprintf(count_str, sizeof(count_str), "%zu", type11.nvalues);
t->count = type11.nvalues;
@ -722,7 +747,7 @@ static void smbios_build_type_16_table(unsigned dimm_cnt)
{
uint64_t size_kb;
SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
SMBIOS_BUILD_TABLE_PRE(16, T16_BASE, true); /* required */
t->location = 0x01; /* Other */
t->use = 0x03; /* System memory */
@ -749,7 +774,7 @@ static void smbios_build_type_17_table(unsigned instance, uint64_t size)
char loc_str[128];
uint64_t size_mb;
SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
SMBIOS_BUILD_TABLE_PRE(17, T17_BASE + instance, true); /* required */
t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
@ -785,12 +810,13 @@ static void smbios_build_type_17_table(unsigned instance, uint64_t size)
SMBIOS_BUILD_TABLE_POST;
}
static void smbios_build_type_19_table(unsigned instance,
static void smbios_build_type_19_table(unsigned instance, unsigned offset,
uint64_t start, uint64_t size)
{
uint64_t end, start_kb, end_kb;
SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */
SMBIOS_BUILD_TABLE_PRE(19, T19_BASE + offset + instance,
true); /* required */
end = start + size - 1;
assert(end > start);
@ -814,7 +840,7 @@ static void smbios_build_type_19_table(unsigned instance,
static void smbios_build_type_32_table(void)
{
SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */
SMBIOS_BUILD_TABLE_PRE(32, T32_BASE, true); /* required */
memset(t->reserved, 0, 6);
t->boot_status = 0; /* No errors detected */
@ -828,7 +854,7 @@ static void smbios_build_type_41_table(Error **errp)
struct type41_instance *t41;
QTAILQ_FOREACH(t41, &type41, next) {
SMBIOS_BUILD_TABLE_PRE(41, 0x2900 + instance, true);
SMBIOS_BUILD_TABLE_PRE(41, T41_BASE + instance, true);
SMBIOS_TABLE_SET_STR(41, reference_designation_str, t41->designation);
t->device_type = t41->kind;
@ -871,7 +897,7 @@ static void smbios_build_type_41_table(Error **errp)
static void smbios_build_type_127_table(void)
{
SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
SMBIOS_BUILD_TABLE_PRE(127, T127_BASE, true); /* required */
SMBIOS_BUILD_TABLE_POST;
}
@ -982,7 +1008,7 @@ void smbios_get_tables(MachineState *ms,
uint8_t **anchor, size_t *anchor_len,
Error **errp)
{
unsigned i, dimm_cnt;
unsigned i, dimm_cnt, offset;
if (smbios_legacy) {
*tables = *anchor = NULL;
@ -1012,6 +1038,16 @@ void smbios_get_tables(MachineState *ms,
dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
/*
* The offset determines if we need to keep additional space betweeen
* table 17 and table 19 header handle numbers so that they do
* not overlap. For example, for a VM with larger than 8 TB guest
* memory and DIMM like chunks of 16 GiB, the default space between
* the two tables (T19_BASE - T17_BASE = 512) is not enough.
*/
offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
dimm_cnt - (T19_BASE - T17_BASE) : 0;
smbios_build_type_16_table(dimm_cnt);
for (i = 0; i < dimm_cnt; i++) {
@ -1019,10 +1055,16 @@ void smbios_get_tables(MachineState *ms,
}
for (i = 0; i < mem_array_size; i++) {
smbios_build_type_19_table(i, mem_array[i].address,
smbios_build_type_19_table(i, offset, mem_array[i].address,
mem_array[i].length);
}
/*
* make sure 16 bit handle numbers in the headers of tables 19
* and 32 do not overlap.
*/
assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
smbios_build_type_32_table();
smbios_build_type_38_table();
smbios_build_type_41_table(errp);
@ -1292,6 +1334,8 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
save_opt(&type4.serial, opts, "serial");
save_opt(&type4.asset, opts, "asset");
save_opt(&type4.part, opts, "part");
/* If the value is 0, it will take the value from the CPU model. */
type4.processor_id = qemu_opt_get_number(opts, "processor-id", 0);
type4.max_speed = qemu_opt_get_number(opts, "max-speed",
DEFAULT_CPU_SPEED);
type4.current_speed = qemu_opt_get_number(opts, "current-speed",

View File

@ -89,9 +89,11 @@ virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d"
# virtio-iommu.c
virtio_iommu_device_reset(void) "reset!"
virtio_iommu_system_reset(void) "system reset!"
virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64
virtio_iommu_device_status(uint8_t status) "driver status = %d"
virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_start, uint32_t domain_end, uint32_t probe_size) "page_size_mask=0x%"PRIx64" input range start=0x%"PRIx64" input range end=0x%"PRIx64" domain range start=%d domain range end=%d probe_size=0x%x"
virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_start, uint32_t domain_end, uint32_t probe_size, uint8_t bypass) "page_size_mask=0x%"PRIx64" input range start=0x%"PRIx64" input range end=0x%"PRIx64" domain range start=%d domain range end=%d probe_size=0x%x bypass=0x%x"
virtio_iommu_set_config(uint8_t bypass) "bypass=0x%x"
virtio_iommu_attach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d"
virtio_iommu_detach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d"
virtio_iommu_map(uint32_t domain_id, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start, uint32_t flags) "domain=%d virt_start=0x%"PRIx64" virt_end=0x%"PRIx64 " phys_start=0x%"PRIx64" flags=%d"

View File

@ -19,6 +19,11 @@
#define VIRTIO_ID_I2C_ADAPTER 34
#endif
static const int feature_bits[] = {
VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
VHOST_INVALID_FEATURE_BIT
};
static void vu_i2c_start(VirtIODevice *vdev)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@ -113,8 +118,10 @@ static void vu_i2c_set_status(VirtIODevice *vdev, uint8_t status)
static uint64_t vu_i2c_get_features(VirtIODevice *vdev,
uint64_t requested_features, Error **errp)
{
/* No feature bits used yet */
return requested_features;
VHostUserI2C *i2c = VHOST_USER_I2C(vdev);
virtio_add_feature(&requested_features, VIRTIO_I2C_F_ZERO_LENGTH_REQUEST);
return vhost_get_features(&i2c->vhost_dev, feature_bits, requested_features);
}
static void vu_i2c_handle_output(VirtIODevice *vdev, VirtQueue *vq)

View File

@ -25,6 +25,7 @@
#include "migration/migration.h"
#include "migration/postcopy-ram.h"
#include "trace.h"
#include "exec/ramblock.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
@ -1162,37 +1163,32 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev,
return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring);
}
static void vhost_user_host_notifier_restore(struct vhost_dev *dev,
int queue_idx)
static void vhost_user_host_notifier_free(VhostUserHostNotifier *n)
{
struct vhost_user *u = dev->opaque;
VhostUserHostNotifier *n = &u->user->notifier[queue_idx];
VirtIODevice *vdev = dev->vdev;
if (n->addr && !n->set) {
virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true);
n->set = true;
}
assert(n && n->unmap_addr);
munmap(n->unmap_addr, qemu_real_host_page_size);
n->unmap_addr = NULL;
}
static void vhost_user_host_notifier_remove(struct vhost_dev *dev,
int queue_idx)
static void vhost_user_host_notifier_remove(VhostUserState *user,
VirtIODevice *vdev, int queue_idx)
{
struct vhost_user *u = dev->opaque;
VhostUserHostNotifier *n = &u->user->notifier[queue_idx];
VirtIODevice *vdev = dev->vdev;
VhostUserHostNotifier *n = &user->notifier[queue_idx];
if (n->addr && n->set) {
virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false);
n->set = false;
if (n->addr) {
if (vdev) {
virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false);
}
assert(!n->unmap_addr);
n->unmap_addr = n->addr;
n->addr = NULL;
call_rcu(n, vhost_user_host_notifier_free, rcu);
}
}
static int vhost_user_set_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
vhost_user_host_notifier_restore(dev, ring->index);
return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
}
@ -1235,8 +1231,9 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
.payload.state = *ring,
.hdr.size = sizeof(msg.payload.state),
};
struct vhost_user *u = dev->opaque;
vhost_user_host_notifier_remove(dev, ring->index);
vhost_user_host_notifier_remove(u->user, dev->vdev, ring->index);
ret = vhost_user_write(dev, &msg, NULL, 0);
if (ret < 0) {
@ -1522,12 +1519,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
n = &user->notifier[queue_idx];
if (n->addr) {
virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false);
object_unparent(OBJECT(&n->mr));
munmap(n->addr, page_size);
n->addr = NULL;
}
vhost_user_host_notifier_remove(user, vdev, queue_idx);
if (area->u64 & VHOST_USER_VRING_NOFD_MASK) {
return 0;
@ -1546,9 +1538,12 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]",
user, queue_idx);
if (!n->mr.ram) /* Don't init again after suspend. */
if (!n->mr.ram) { /* Don't init again after suspend. */
memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name,
page_size, addr);
} else {
n->mr.ram_block->host = addr;
}
g_free(name);
if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) {
@ -1558,7 +1553,6 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
}
n->addr = addr;
n->set = true;
return 0;
}
@ -2522,17 +2516,16 @@ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp)
void vhost_user_cleanup(VhostUserState *user)
{
int i;
VhostUserHostNotifier *n;
if (!user->chr) {
return;
}
memory_region_transaction_begin();
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
if (user->notifier[i].addr) {
object_unparent(OBJECT(&user->notifier[i].mr));
munmap(user->notifier[i].addr, qemu_real_host_page_size);
user->notifier[i].addr = NULL;
}
n = &user->notifier[i];
vhost_user_host_notifier_remove(user, NULL, i);
object_unparent(OBJECT(&n->mr));
}
memory_region_transaction_commit();
user->chr = NULL;

View File

@ -395,15 +395,6 @@ static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev,
}
}
static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n)
{
int i;
for (i = 0; i < n; i++) {
vhost_vdpa_host_notifier_uninit(dev, i);
}
}
static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index)
{
size_t page_size = qemu_real_host_page_size;
@ -431,6 +422,7 @@ static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index)
g_free(name);
if (virtio_queue_set_host_notifier_mr(vdev, queue_index, &n->mr, true)) {
object_unparent(OBJECT(&n->mr));
munmap(addr, page_size);
goto err;
}
@ -442,6 +434,15 @@ err:
return -1;
}
static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n)
{
int i;
for (i = dev->vq_index; i < dev->vq_index + n; i++) {
vhost_vdpa_host_notifier_uninit(dev, i);
}
}
static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev)
{
int i;
@ -455,7 +456,7 @@ static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev)
return;
err:
vhost_vdpa_host_notifiers_uninit(dev, i);
vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index);
return;
}

View File

@ -153,19 +153,23 @@ static void vhost_vsock_common_send_transport_reset(VHostVSockCommon *vvc)
if (elem->out_num) {
error_report("invalid vhost-vsock event virtqueue element with "
"out buffers");
goto out;
goto err;
}
if (iov_from_buf(elem->in_sg, elem->in_num, 0,
&event, sizeof(event)) != sizeof(event)) {
error_report("vhost-vsock event virtqueue element is too short");
goto out;
goto err;
}
virtqueue_push(vq, elem, sizeof(event));
virtio_notify(VIRTIO_DEVICE(vvc), vq);
out:
g_free(elem);
return;
err:
virtqueue_detach_element(vq, elem, 0);
g_free(elem);
}

View File

@ -1287,7 +1287,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
return r;
}
file.fd = event_notifier_get_fd(&vq->masked_notifier);
file.fd = event_notifier_get_wfd(&vq->masked_notifier);
r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
if (r) {
VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed");
@ -1542,9 +1542,9 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
if (mask) {
assert(vdev->use_guest_notifier_mask);
file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier);
file.fd = event_notifier_get_wfd(&hdev->vqs[index].masked_notifier);
} else {
file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
file.fd = event_notifier_get_wfd(virtio_queue_get_guest_notifier(vvq));
}
file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n);

View File

@ -48,6 +48,7 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
bool has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
bool vdev_has_iommu;
Error *local_err = NULL;
DPRINTF("%s: plug device.\n", qbus->name);
@ -69,11 +70,6 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
return;
}
if (has_iommu && !virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
error_setg(errp, "iommu_platform=true is not supported by the device");
return;
}
if (klass->device_plugged != NULL) {
klass->device_plugged(qbus->parent, &local_err);
}
@ -82,9 +78,15 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
return;
}
vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
if (klass->get_dma_as != NULL && has_iommu) {
virtio_add_feature(&vdev->host_features, VIRTIO_F_IOMMU_PLATFORM);
vdev->dma_as = klass->get_dma_as(qbus->parent);
if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) {
error_setg(errp,
"iommu_platform=true is not supported by the device");
return;
}
} else {
vdev->dma_as = &address_space_memory;
}

View File

@ -24,6 +24,7 @@
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio.h"
#include "sysemu/kvm.h"
#include "sysemu/reset.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "trace.h"
@ -42,6 +43,7 @@
typedef struct VirtIOIOMMUDomain {
uint32_t id;
bool bypass;
GTree *mappings;
QLIST_HEAD(, VirtIOIOMMUEndpoint) endpoint_list;
} VirtIOIOMMUDomain;
@ -257,12 +259,16 @@ static void virtio_iommu_put_endpoint(gpointer data)
}
static VirtIOIOMMUDomain *virtio_iommu_get_domain(VirtIOIOMMU *s,
uint32_t domain_id)
uint32_t domain_id,
bool bypass)
{
VirtIOIOMMUDomain *domain;
domain = g_tree_lookup(s->domains, GUINT_TO_POINTER(domain_id));
if (domain) {
if (domain->bypass != bypass) {
return NULL;
}
return domain;
}
domain = g_malloc0(sizeof(*domain));
@ -270,6 +276,7 @@ static VirtIOIOMMUDomain *virtio_iommu_get_domain(VirtIOIOMMU *s,
domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp,
NULL, (GDestroyNotify)g_free,
(GDestroyNotify)g_free);
domain->bypass = bypass;
g_tree_insert(s->domains, GUINT_TO_POINTER(domain_id), domain);
QLIST_INIT(&domain->endpoint_list);
trace_virtio_iommu_get_domain(domain_id);
@ -333,11 +340,16 @@ static int virtio_iommu_attach(VirtIOIOMMU *s,
{
uint32_t domain_id = le32_to_cpu(req->domain);
uint32_t ep_id = le32_to_cpu(req->endpoint);
uint32_t flags = le32_to_cpu(req->flags);
VirtIOIOMMUDomain *domain;
VirtIOIOMMUEndpoint *ep;
trace_virtio_iommu_attach(domain_id, ep_id);
if (flags & ~VIRTIO_IOMMU_ATTACH_F_BYPASS) {
return VIRTIO_IOMMU_S_INVAL;
}
ep = virtio_iommu_get_endpoint(s, ep_id);
if (!ep) {
return VIRTIO_IOMMU_S_NOENT;
@ -355,7 +367,12 @@ static int virtio_iommu_attach(VirtIOIOMMU *s,
}
}
domain = virtio_iommu_get_domain(s, domain_id);
domain = virtio_iommu_get_domain(s, domain_id,
flags & VIRTIO_IOMMU_ATTACH_F_BYPASS);
if (!domain) {
/* Incompatible bypass flag */
return VIRTIO_IOMMU_S_INVAL;
}
QLIST_INSERT_HEAD(&domain->endpoint_list, ep, next);
ep->domain = domain;
@ -418,6 +435,10 @@ static int virtio_iommu_map(VirtIOIOMMU *s,
return VIRTIO_IOMMU_S_NOENT;
}
if (domain->bypass) {
return VIRTIO_IOMMU_S_INVAL;
}
interval = g_malloc0(sizeof(*interval));
interval->low = virt_start;
@ -463,6 +484,11 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s,
if (!domain) {
return VIRTIO_IOMMU_S_NOENT;
}
if (domain->bypass) {
return VIRTIO_IOMMU_S_INVAL;
}
interval.low = virt_start;
interval.high = virt_end;
@ -728,8 +754,7 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr,
.perm = IOMMU_NONE,
};
bypass_allowed = virtio_vdev_has_feature(&s->parent_obj,
VIRTIO_IOMMU_F_BYPASS);
bypass_allowed = s->config.bypass;
sid = virtio_iommu_get_bdf(sdev);
@ -780,6 +805,9 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr,
entry.perm = flag;
}
goto unlock;
} else if (ep->domain->bypass) {
entry.perm = flag;
goto unlock;
}
found = g_tree_lookup_extended(ep->domain->mappings, (gpointer)(&interval),
@ -831,13 +859,37 @@ static void virtio_iommu_get_config(VirtIODevice *vdev, uint8_t *config_data)
out_config->domain_range.start = cpu_to_le32(dev_config->domain_range.start);
out_config->domain_range.end = cpu_to_le32(dev_config->domain_range.end);
out_config->probe_size = cpu_to_le32(dev_config->probe_size);
out_config->bypass = dev_config->bypass;
trace_virtio_iommu_get_config(dev_config->page_size_mask,
dev_config->input_range.start,
dev_config->input_range.end,
dev_config->domain_range.start,
dev_config->domain_range.end,
dev_config->probe_size);
dev_config->probe_size,
dev_config->bypass);
}
static void virtio_iommu_set_config(VirtIODevice *vdev,
const uint8_t *config_data)
{
VirtIOIOMMU *dev = VIRTIO_IOMMU(vdev);
struct virtio_iommu_config *dev_config = &dev->config;
const struct virtio_iommu_config *in_config = (void *)config_data;
if (in_config->bypass != dev_config->bypass) {
if (!virtio_vdev_has_feature(vdev, VIRTIO_IOMMU_F_BYPASS_CONFIG)) {
virtio_error(vdev, "cannot set config.bypass");
return;
} else if (in_config->bypass != 0 && in_config->bypass != 1) {
virtio_error(vdev, "invalid config.bypass value '%u'",
in_config->bypass);
return;
}
dev_config->bypass = in_config->bypass;
}
trace_virtio_iommu_set_config(in_config->bypass);
}
static uint64_t virtio_iommu_get_features(VirtIODevice *vdev, uint64_t f,
@ -963,6 +1015,19 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
return 0;
}
static void virtio_iommu_system_reset(void *opaque)
{
VirtIOIOMMU *s = opaque;
trace_virtio_iommu_system_reset();
/*
* config.bypass is sticky across device reset, but should be restored on
* system reset
*/
s->config.bypass = s->boot_bypass;
}
static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@ -988,9 +1053,9 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_INPUT_RANGE);
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_DOMAIN_RANGE);
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MAP_UNMAP);
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_BYPASS);
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MMIO);
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_PROBE);
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_BYPASS_CONFIG);
qemu_mutex_init(&s->mutex);
@ -1001,6 +1066,8 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
} else {
error_setg(errp, "VIRTIO-IOMMU is not attached to any PCI bus!");
}
qemu_register_reset(virtio_iommu_system_reset, s);
}
static void virtio_iommu_device_unrealize(DeviceState *dev)
@ -1008,6 +1075,8 @@ static void virtio_iommu_device_unrealize(DeviceState *dev)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOIOMMU *s = VIRTIO_IOMMU(dev);
qemu_unregister_reset(virtio_iommu_system_reset, s);
g_hash_table_destroy(s->as_by_busptr);
if (s->domains) {
g_tree_destroy(s->domains);
@ -1098,8 +1167,8 @@ static const VMStateDescription vmstate_endpoint = {
static const VMStateDescription vmstate_domain = {
.name = "domain",
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.pre_load = domain_preload,
.fields = (VMStateField[]) {
VMSTATE_UINT32(id, VirtIOIOMMUDomain),
@ -1108,6 +1177,7 @@ static const VMStateDescription vmstate_domain = {
VirtIOIOMMUInterval, VirtIOIOMMUMapping),
VMSTATE_QLIST_V(endpoint_list, VirtIOIOMMUDomain, 1,
vmstate_endpoint, VirtIOIOMMUEndpoint, next),
VMSTATE_BOOL_V(bypass, VirtIOIOMMUDomain, 2),
VMSTATE_END_OF_LIST()
}
};
@ -1141,21 +1211,22 @@ static int iommu_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_virtio_iommu_device = {
.name = "virtio-iommu-device",
.minimum_version_id = 1,
.version_id = 1,
.minimum_version_id = 2,
.version_id = 2,
.post_load = iommu_post_load,
.fields = (VMStateField[]) {
VMSTATE_GTREE_DIRECT_KEY_V(domains, VirtIOIOMMU, 1,
VMSTATE_GTREE_DIRECT_KEY_V(domains, VirtIOIOMMU, 2,
&vmstate_domain, VirtIOIOMMUDomain),
VMSTATE_UINT8_V(config.bypass, VirtIOIOMMU, 2),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_virtio_iommu = {
.name = "virtio-iommu",
.minimum_version_id = 1,
.minimum_version_id = 2,
.priority = MIG_PRI_IOMMU,
.version_id = 1,
.version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_VIRTIO_DEVICE,
VMSTATE_END_OF_LIST()
@ -1164,6 +1235,7 @@ static const VMStateDescription vmstate_virtio_iommu = {
static Property virtio_iommu_properties[] = {
DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *),
DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true),
DEFINE_PROP_END_OF_LIST(),
};
@ -1180,6 +1252,7 @@ static void virtio_iommu_class_init(ObjectClass *klass, void *data)
vdc->unrealize = virtio_iommu_device_unrealize;
vdc->reset = virtio_iommu_device_reset;
vdc->get_config = virtio_iommu_get_config;
vdc->set_config = virtio_iommu_set_config;
vdc->get_features = virtio_iommu_get_features;
vdc->set_status = virtio_iommu_set_status;
vdc->vmsd = &vmstate_virtio_iommu_device;

View File

@ -77,6 +77,7 @@ typedef struct AcpiFadtData {
uint16_t plvl2_lat; /* P_LVL2_LAT */
uint16_t plvl3_lat; /* P_LVL3_LAT */
uint16_t arm_boot_arch; /* ARM_BOOT_ARCH */
uint16_t iapc_boot_arch; /* IAPC_BOOT_ARCH */
uint8_t minor_ver; /* FADT Minor Version */
/*

View File

@ -228,6 +228,7 @@ struct IntelIOMMUState {
bool caching_mode; /* RO - is cap CM enabled? */
bool scalable_mode; /* RO - is Scalable Mode supported? */
bool snoop_control; /* RO - is SNP filed supported? */
dma_addr_t root; /* Current root table pointer */
bool root_scalable; /* Type of root table (scalable or not) */

View File

@ -48,6 +48,7 @@ typedef struct PCMachineState {
bool sata_enabled;
bool pit_enabled;
bool hpet_enabled;
bool i8042_enabled;
bool default_bus_bypass_iommu;
uint64_t max_fw_size;
@ -64,6 +65,7 @@ typedef struct PCMachineState {
#define PC_MACHINE_SMBUS "smbus"
#define PC_MACHINE_SATA "sata"
#define PC_MACHINE_PIT "pit"
#define PC_MACHINE_I8042 "i8042"
#define PC_MACHINE_MAX_FW_SIZE "max-fw-size"
#define PC_MACHINE_SMBIOS_EP "smbios-entry-point-type"

View File

@ -35,8 +35,6 @@ struct X86MachineClass {
/* TSC rate migration: */
bool save_tsc_khz;
/* Enables contiguous-apic-ID mode */
bool compat_apic_id_mode;
/* use DMA capable linuxboot option rom */
bool fwcfg_dma_enabled;
};

View File

@ -23,4 +23,19 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
void i8042_isa_mouse_fake_event(ISAKBDState *isa);
void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out);
static inline bool i8042_present(void)
{
bool amb = false;
return object_resolve_path_type("", TYPE_I8042, &amb) || amb;
}
/*
* ACPI v2, Table 5-10 - Fixed ACPI Description Table Boot Architecture
* Flags, bit offset 1 - 8042.
*/
static inline uint16_t iapc_boot_arch_8042(void)
{
return i8042_present() ? 0x1 << 1 : 0x0 ;
}
#endif /* HW_INPUT_I8042_H */

View File

@ -22,14 +22,6 @@
#define PVPANIC_IOPORT_PROP "ioport"
/* The bit of supported pv event, TODO: include uapi header and remove this */
#define PVPANIC_F_PANICKED 0
#define PVPANIC_F_CRASHLOADED 1
/* The pv event value */
#define PVPANIC_PANICKED (1 << PVPANIC_F_PANICKED)
#define PVPANIC_CRASHLOADED (1 << PVPANIC_F_CRASHLOADED)
/*
* PVPanicState for any device type
*/

View File

@ -0,0 +1,15 @@
/*
* TI X3130 pci express downstream port switch
*
* Copyright (C) 2022 Igor Mammedov <imammedo@redhat.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef HW_PCI_BRIDGE_XIO3130_DOWNSTREAM_H
#define HW_PCI_BRIDGE_XIO3130_DOWNSTREAM_H
#define TYPE_XIO3130_DOWNSTREAM "xio3130-downstream"
#endif

View File

@ -7,9 +7,6 @@
/* PCI includes legacy ISA access. */
#include "hw/isa/isa.h"
#include "hw/pci/pcie.h"
#include "qom/object.h"
extern bool pci_available;
/* PCI bus */
@ -157,6 +154,7 @@ enum {
#define QEMU_PCI_VGA_IO_HI_SIZE 0x20
#include "hw/pci/pci_regs.h"
#include "hw/pci/pcie.h"
/* PCI HEADER_TYPE */
#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
@ -499,6 +497,9 @@ typedef AddressSpace *(*PCIIOMMUFunc)(PCIBus *, void *, int);
AddressSpace *pci_device_iommu_address_space(PCIDevice *dev);
void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque);
pcibus_t pci_bar_address(PCIDevice *d,
int reg, uint8_t type, pcibus_t size);
static inline void
pci_set_byte(uint8_t *config, uint8_t val)
{
@ -779,6 +780,11 @@ static inline int pci_is_express_downstream_port(const PCIDevice *d)
return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT;
}
static inline int pci_is_vf(const PCIDevice *d)
{
return d->exp.sriov_vf.pf != NULL;
}
static inline uint32_t pci_config_size(const PCIDevice *d)
{
return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;

View File

@ -4,5 +4,6 @@
#include "standard-headers/linux/pci_regs.h"
#define PCI_PM_CAP_VER_1_1 0x0002 /* PCI PM spec ver. 1.1 */
#define PCI_PM_CAP_VER_1_2 0x0003 /* PCI PM spec ver. 1.2 */
#endif

View File

@ -24,6 +24,7 @@
#include "hw/pci/pci_regs.h"
#include "hw/pci/pcie_regs.h"
#include "hw/pci/pcie_aer.h"
#include "hw/pci/pcie_sriov.h"
#include "hw/hotplug.h"
typedef enum {
@ -81,6 +82,11 @@ struct PCIExpressDevice {
/* ACS */
uint16_t acs_cap;
/* SR/IOV */
uint16_t sriov_cap;
PCIESriovPF sriov_pf;
PCIESriovVF sriov_vf;
};
#define COMPAT_PROP_PCP "power_controller_present"
@ -112,6 +118,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
uint32_t addr, uint32_t val, int len);
int pcie_cap_slot_post_load(void *opaque, int version_id);
void pcie_cap_slot_push_attention_button(PCIDevice *dev);
void pcie_cap_slot_enable_power(PCIDevice *dev);
void pcie_cap_root_init(PCIDevice *dev);
void pcie_cap_root_reset(PCIDevice *dev);

View File

@ -0,0 +1,77 @@
/*
* pcie_sriov.h:
*
* Implementation of SR/IOV emulation support.
*
* Copyright (c) 2015 Knut Omang <knut.omang@oracle.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef QEMU_PCIE_SRIOV_H
#define QEMU_PCIE_SRIOV_H
struct PCIESriovPF {
uint16_t num_vfs; /* Number of virtual functions created */
uint8_t vf_bar_type[PCI_NUM_REGIONS]; /* Store type for each VF bar */
const char *vfname; /* Reference to the device type used for the VFs */
PCIDevice **vf; /* Pointer to an array of num_vfs VF devices */
};
struct PCIESriovVF {
PCIDevice *pf; /* Pointer back to owner physical function */
uint16_t vf_number; /* Logical VF number of this function */
};
void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
const char *vfname, uint16_t vf_dev_id,
uint16_t init_vfs, uint16_t total_vfs,
uint16_t vf_offset, uint16_t vf_stride);
void pcie_sriov_pf_exit(PCIDevice *dev);
/* Set up a VF bar in the SR/IOV bar area */
void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
uint8_t type, dma_addr_t size);
/* Instantiate a bar for a VF */
void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num,
MemoryRegion *memory);
/*
* Default (minimal) page size support values
* as required by the SR/IOV standard:
* 0x553 << 12 = 0x553000 = 4K + 8K + 64K + 256K + 1M + 4M
*/
#define SRIOV_SUP_PGSIZE_MINREQ 0x553
/*
* Optionally add supported page sizes to the mask of supported page sizes
* Page size values are interpreted as opt_sup_pgsize << 12.
*/
void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize);
/* SR/IOV capability config write handler */
void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
uint32_t val, int len);
/* Reset SR/IOV VF Enable bit to unregister all VFs */
void pcie_sriov_pf_disable_vfs(PCIDevice *dev);
/* Get logical VF number of a VF - only valid for VFs */
uint16_t pcie_sriov_vf_number(PCIDevice *dev);
/*
* Get the physical function that owns this VF.
* Returns NULL if dev is not a virtual function
*/
PCIDevice *pcie_sriov_get_pf(PCIDevice *dev);
/*
* Get the n-th VF of this physical function - only valid for PF.
* Returns NULL if index is invalid
*/
PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n);
#endif /* QEMU_PCIE_SRIOV_H */

View File

@ -25,4 +25,7 @@ struct VHostUserI2C {
bool connected;
};
/* Virtio Feature bits */
#define VIRTIO_I2C_F_ZERO_LENGTH_REQUEST 0
#endif /* _QEMU_VHOST_USER_I2C_H */

View File

@ -12,9 +12,10 @@
#include "hw/virtio/virtio.h"
typedef struct VhostUserHostNotifier {
struct rcu_head rcu;
MemoryRegion mr;
void *addr;
bool set;
void *unmap_addr;
} VhostUserHostNotifier;
typedef struct VhostUserState {

View File

@ -58,6 +58,7 @@ struct VirtIOIOMMU {
GTree *domains;
QemuMutex mutex;
GTree *endpoints;
bool boot_bypass;
};
#endif

View File

@ -38,6 +38,7 @@ int event_notifier_test_and_clear(EventNotifier *);
#ifdef CONFIG_POSIX
void event_notifier_init_fd(EventNotifier *, int fd);
int event_notifier_get_fd(const EventNotifier *);
int event_notifier_get_wfd(const EventNotifier *);
#else
HANDLE event_notifier_get_handle(EventNotifier *);
#endif

View File

@ -88,6 +88,8 @@ typedef struct PCIDevice PCIDevice;
typedef struct PCIEAERErr PCIEAERErr;
typedef struct PCIEAERLog PCIEAERLog;
typedef struct PCIEAERMsg PCIEAERMsg;
typedef struct PCIESriovPF PCIESriovPF;
typedef struct PCIESriovVF PCIESriovVF;
typedef struct PCIEPort PCIEPort;
typedef struct PCIESlot PCIESlot;
typedef struct PCIExpressDevice PCIExpressDevice;

View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __PVPANIC_H__
#define __PVPANIC_H__
#define PVPANIC_PANICKED (1 << 0)
#define PVPANIC_CRASH_LOADED (1 << 1)
#endif /* __PVPANIC_H__ */

View File

@ -2725,7 +2725,7 @@ if have_system or have_user
endif
vhost_user = not_found
if 'CONFIG_VHOST_USER' in config_host
if targetos == 'linux' and 'CONFIG_VHOST_USER' in config_host
libvhost_user = subproject('libvhost-user')
vhost_user = libvhost_user.get_variable('vhost_user_dep')
endif

View File

@ -2537,6 +2537,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
" specify SMBIOS type 3 fields\n"
"-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str]\n"
" [,asset=str][,part=str][,max-speed=%d][,current-speed=%d]\n"
" [,processor-id=%d]\n"
" specify SMBIOS type 4 fields\n"
"-smbios type=11[,value=str][,path=filename]\n"
" specify SMBIOS type 11 fields\n"
@ -2562,7 +2563,7 @@ SRST
``-smbios type=3[,manufacturer=str][,version=str][,serial=str][,asset=str][,sku=str]``
Specify SMBIOS type 3 fields
``-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str][,asset=str][,part=str]``
``-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str][,asset=str][,part=str][,processor-id=%d]``
Specify SMBIOS type 4 fields
``-smbios type=11[,value=str][,path=filename]``

View File

@ -1168,10 +1168,14 @@ GSList *object_class_get_list_sorted(const char *implements_type,
Object *object_ref(void *objptr)
{
Object *obj = OBJECT(objptr);
uint32_t ref;
if (!obj) {
return NULL;
}
qatomic_inc(&obj->ref);
ref = qatomic_fetch_inc(&obj->ref);
/* Assert waaay before the integer overflows */
g_assert(ref < INT_MAX);
return obj;
}

View File

@ -214,7 +214,8 @@ for i in "$tmpdir"/include/linux/*virtio*.h \
"$tmpdir/include/linux/const.h" \
"$tmpdir/include/linux/kernel.h" \
"$tmpdir/include/linux/vhost_types.h" \
"$tmpdir/include/linux/sysinfo.h"; do
"$tmpdir/include/linux/sysinfo.h" \
"$tmpdir/include/misc/pvpanic.h"; do
cp_portable "$i" "$output/include/standard-headers/linux"
done
mkdir -p "$output/include/standard-headers/drm"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -31,11 +31,13 @@ static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
uint64_t input_range_end = qvirtio_config_readq(dev, 16);
uint32_t domain_range_start = qvirtio_config_readl(dev, 24);
uint32_t domain_range_end = qvirtio_config_readl(dev, 28);
uint8_t bypass = qvirtio_config_readb(dev, 36);
g_assert_cmpint(input_range_start, ==, 0);
g_assert_cmphex(input_range_end, ==, UINT64_MAX);
g_assert_cmpint(domain_range_start, ==, 0);
g_assert_cmpint(domain_range_end, ==, UINT32_MAX);
g_assert_cmpint(bypass, ==, 1);
}
static int read_tail_status(struct virtio_iommu_req_tail *buffer)

View File

@ -99,6 +99,11 @@ int event_notifier_get_fd(const EventNotifier *e)
return e->rfd;
}
int event_notifier_get_wfd(const EventNotifier *e)
{
return e->wfd;
}
int event_notifier_set(EventNotifier *e)
{
static const uint64_t value = 1;