mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc,pci,virtio: fixes, cleanups Lots of fixes, cleanups. CPU hot-unplug improvements. A new AER property for virtio devices, adding a dummy AER capability. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Wed 09 Dec 2020 18:04:28 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: (65 commits) hw/virtio-pci Added AER capability. hw/virtio-pci Added counter for pcie capabilities offsets. pcie_aer: Fix help message of pcie_aer_inject_error command x86: ich9: let firmware negotiate 'CPU hot-unplug with SMI' feature x86: ich9: factor out "guest_cpu_hotplug_features" tests/acpi: update expected files x86: acpi: let the firmware handle pending "CPU remove" events in SMM tests/acpi: allow expected files change x86: acpi: introduce AcpiPmInfo::smi_on_cpu_unplug acpi: cpuhp: introduce 'firmware performs eject' status/control bits hw/i386/pc: add max combined fw size as machine configuration option block/export: avoid g_return_val_if() input validation contrib/vhost-user-input: avoid g_return_val_if() input validation contrib/vhost-user-gpu: avoid g_return_val_if() input validation contrib/vhost-user-blk: avoid g_return_val_if() input validation .gitlab-ci: add build-libvhost-user libvhost-user: add a simple link test without glib libvhost-user: make it a meson subproject libvhost-user: drop qemu/osdep.h dependency libvhost-user: remove qemu/compiler.h usage ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -535,6 +535,17 @@ check-dco:
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
|
||||
build-libvhost-user:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/fedora:latest
|
||||
before_script:
|
||||
- dnf install -y meson ninja-build
|
||||
script:
|
||||
- mkdir subprojects/libvhost-user/build
|
||||
- cd subprojects/libvhost-user/build
|
||||
- meson
|
||||
- ninja
|
||||
|
||||
pages:
|
||||
image: $CI_REGISTRY_IMAGE/qemu/ubuntu2004:latest
|
||||
stage: test
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/block.h"
|
||||
#include "contrib/libvhost-user/libvhost-user.h"
|
||||
#include "subprojects/libvhost-user/libvhost-user.h" /* only for the type definitions */
|
||||
#include "standard-headers/linux/virtio_blk.h"
|
||||
#include "qemu/vhost-user-server.h"
|
||||
#include "vhost-user-blk-server.h"
|
||||
@@ -267,7 +267,9 @@ vu_blk_get_config(VuDev *vu_dev, uint8_t *config, uint32_t len)
|
||||
VuServer *server = container_of(vu_dev, VuServer, vu_dev);
|
||||
VuBlkExport *vexp = container_of(server, VuBlkExport, vu_server);
|
||||
|
||||
g_return_val_if_fail(len <= sizeof(struct virtio_blk_config), -1);
|
||||
if (len > sizeof(struct virtio_blk_config)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(config, &vexp->blkcfg, len);
|
||||
return 0;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
libvhost_user = static_library('vhost-user',
|
||||
files('libvhost-user.c', 'libvhost-user-glib.c'),
|
||||
build_by_default: false)
|
||||
vhost_user = declare_dependency(link_with: libvhost_user)
|
||||
@@ -1,6 +1,5 @@
|
||||
# FIXME: broken on 32-bit architectures
|
||||
executable('vhost-user-blk', files('vhost-user-blk.c'),
|
||||
link_with: libvhost_user,
|
||||
dependencies: qemuutil,
|
||||
dependencies: [qemuutil, vhost_user],
|
||||
build_by_default: false,
|
||||
install: false)
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "standard-headers/linux/virtio_blk.h"
|
||||
#include "contrib/libvhost-user/libvhost-user-glib.h"
|
||||
#include "contrib/libvhost-user/libvhost-user.h"
|
||||
#include "libvhost-user-glib.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/fs.h>
|
||||
@@ -404,7 +403,9 @@ vub_get_config(VuDev *vu_dev, uint8_t *config, uint32_t len)
|
||||
VugDev *gdev;
|
||||
VubDev *vdev_blk;
|
||||
|
||||
g_return_val_if_fail(len <= sizeof(struct virtio_blk_config), -1);
|
||||
if (len > sizeof(struct virtio_blk_config)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gdev = container_of(vu_dev, VugDev, parent);
|
||||
vdev_blk = container_of(gdev, VubDev, parent);
|
||||
|
||||
@@ -2,8 +2,7 @@ if 'CONFIG_TOOLS' in config_host and 'CONFIG_VIRGL' in config_host \
|
||||
and 'CONFIG_GBM' in config_host and 'CONFIG_LINUX' in config_host \
|
||||
and pixman.found()
|
||||
executable('vhost-user-gpu', files('vhost-user-gpu.c', 'virgl.c', 'vugbm.c'),
|
||||
link_with: libvhost_user,
|
||||
dependencies: [qemuutil, pixman, gbm, virgl],
|
||||
dependencies: [qemuutil, pixman, gbm, virgl, vhost_user],
|
||||
install: true,
|
||||
install_dir: get_option('libexecdir'))
|
||||
|
||||
|
||||
@@ -1044,7 +1044,9 @@ vg_get_config(VuDev *dev, uint8_t *config, uint32_t len)
|
||||
{
|
||||
VuGpu *g = container_of(dev, VuGpu, dev.parent);
|
||||
|
||||
g_return_val_if_fail(len <= sizeof(struct virtio_gpu_config), -1);
|
||||
if (len > sizeof(struct virtio_gpu_config)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opt_virgl) {
|
||||
g->virtio_config.num_capsets = vg_virgl_get_num_capsets();
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "contrib/libvhost-user/libvhost-user-glib.h"
|
||||
#include "libvhost-user-glib.h"
|
||||
#include "standard-headers/linux/virtio_gpu.h"
|
||||
|
||||
#include "qemu/queue.h"
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "contrib/libvhost-user/libvhost-user.h"
|
||||
#include "contrib/libvhost-user/libvhost-user-glib.h"
|
||||
#include "libvhost-user-glib.h"
|
||||
#include "standard-headers/linux/virtio_input.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
@@ -212,7 +211,9 @@ static int vi_get_config(VuDev *dev, uint8_t *config, uint32_t len)
|
||||
{
|
||||
VuInput *vi = container_of(dev, VuInput, dev.parent);
|
||||
|
||||
g_return_val_if_fail(len <= sizeof(*vi->sel_config), -1);
|
||||
if (len > sizeof(*vi->sel_config)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vi->sel_config) {
|
||||
memcpy(config, vi->sel_config, len);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
executable('vhost-user-input', files('main.c'),
|
||||
link_with: libvhost_user,
|
||||
dependencies: qemuutil,
|
||||
dependencies: [qemuutil, vhost_user],
|
||||
build_by_default: targetos == 'linux',
|
||||
install: false)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
if 'CONFIG_LIBISCSI' in config_host
|
||||
executable('vhost-user-scsi', files('vhost-user-scsi.c'),
|
||||
link_with: libvhost_user,
|
||||
dependencies: [qemuutil, libiscsi],
|
||||
dependencies: [qemuutil, libiscsi, vhost_user],
|
||||
build_by_default: targetos == 'linux',
|
||||
install: false)
|
||||
endif
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#define inline __attribute__((gnu_inline)) /* required for libiscsi v1.9.0 */
|
||||
#include <iscsi/scsi-lowlevel.h>
|
||||
#undef inline
|
||||
#include "contrib/libvhost-user/libvhost-user-glib.h"
|
||||
#include "libvhost-user-glib.h"
|
||||
#include "standard-headers/linux/virtio_scsi.h"
|
||||
|
||||
|
||||
@@ -232,6 +232,7 @@ static void vus_proc_req(VuDev *vu_dev, int idx)
|
||||
VugDev *gdev;
|
||||
VusDev *vdev_scsi;
|
||||
VuVirtq *vq;
|
||||
VuVirtqElement *elem = NULL;
|
||||
|
||||
assert(vu_dev);
|
||||
|
||||
@@ -248,7 +249,6 @@ static void vus_proc_req(VuDev *vu_dev, int idx)
|
||||
g_debug("Got kicked on vq[%d]@%p", idx, vq);
|
||||
|
||||
while (1) {
|
||||
VuVirtqElement *elem;
|
||||
VirtIOSCSICmdReq *req;
|
||||
VirtIOSCSICmdResp *rsp;
|
||||
|
||||
@@ -288,6 +288,7 @@ static void vus_proc_req(VuDev *vu_dev, int idx)
|
||||
|
||||
free(elem);
|
||||
}
|
||||
free(elem);
|
||||
}
|
||||
|
||||
static void vus_queue_set_started(VuDev *vu_dev, int idx, bool started)
|
||||
|
||||
@@ -56,8 +56,11 @@ read access:
|
||||
no device check event to OSPM was issued.
|
||||
It's valid only when bit 0 is set.
|
||||
2: Device remove event, used to distinguish device for which
|
||||
no device eject request to OSPM was issued.
|
||||
3-7: reserved and should be ignored by OSPM
|
||||
no device eject request to OSPM was issued. Firmware must
|
||||
ignore this bit.
|
||||
3: reserved and should be ignored by OSPM
|
||||
4: if set to 1, OSPM requests firmware to perform device eject.
|
||||
5-7: reserved and should be ignored by OSPM
|
||||
[0x5-0x7] reserved
|
||||
[0x8] Command data: (DWORD access)
|
||||
contains 0 unless value last stored in 'Command field' is one of:
|
||||
@@ -79,10 +82,16 @@ write access:
|
||||
selected CPU device
|
||||
2: if set to 1 clears device remove event, set by OSPM
|
||||
after it has emitted device eject request for the
|
||||
selected CPU device
|
||||
selected CPU device.
|
||||
3: if set to 1 initiates device eject, set by OSPM when it
|
||||
triggers CPU device removal and calls _EJ0 method
|
||||
4-7: reserved, OSPM must clear them before writing to register
|
||||
triggers CPU device removal and calls _EJ0 method or by firmware
|
||||
when bit #4 is set. In case bit #4 were set, it's cleared as
|
||||
part of device eject.
|
||||
4: if set to 1, OSPM hands over device eject to firmware.
|
||||
Firmware shall issue device eject request as described above
|
||||
(bit #3) and OSPM should not touch device eject bit (#3) in case
|
||||
it's asked firmware to perform CPU device eject.
|
||||
5-7: reserved, OSPM must clear them before writing to register
|
||||
[0x5] Command field: (1 byte access)
|
||||
value:
|
||||
0: selects a CPU device with inserting/removing events and
|
||||
|
||||
+2
-2
@@ -1302,8 +1302,8 @@ ERST
|
||||
" -c for correctable error\n\t\t\t"
|
||||
"<id> = qdev device id\n\t\t\t"
|
||||
"<error_status> = error string or 32bit\n\t\t\t"
|
||||
"<tlb header> = 32bit x 4\n\t\t\t"
|
||||
"<tlb header prefix> = 32bit x 4",
|
||||
"<tlp header> = 32bit x 4\n\t\t\t"
|
||||
"<tlp header prefix> = 32bit x 4",
|
||||
.cmd = hmp_pcie_aer_inject_error,
|
||||
},
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include "sysemu/numa.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/pci/pci_bridge.h"
|
||||
|
||||
static GArray *build_alloc_array(void)
|
||||
{
|
||||
@@ -55,6 +58,128 @@ static void build_append_array(GArray *array, GArray *val)
|
||||
|
||||
#define ACPI_NAMESEG_LEN 4
|
||||
|
||||
void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t limit)
|
||||
{
|
||||
CrsRangeEntry *entry;
|
||||
|
||||
entry = g_malloc(sizeof(*entry));
|
||||
entry->base = base;
|
||||
entry->limit = limit;
|
||||
|
||||
g_ptr_array_add(ranges, entry);
|
||||
}
|
||||
|
||||
static void crs_range_free(gpointer data)
|
||||
{
|
||||
CrsRangeEntry *entry = (CrsRangeEntry *)data;
|
||||
g_free(entry);
|
||||
}
|
||||
|
||||
void crs_range_set_init(CrsRangeSet *range_set)
|
||||
{
|
||||
range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
range_set->mem_64bit_ranges =
|
||||
g_ptr_array_new_with_free_func(crs_range_free);
|
||||
}
|
||||
|
||||
void crs_range_set_free(CrsRangeSet *range_set)
|
||||
{
|
||||
g_ptr_array_free(range_set->io_ranges, true);
|
||||
g_ptr_array_free(range_set->mem_ranges, true);
|
||||
g_ptr_array_free(range_set->mem_64bit_ranges, true);
|
||||
}
|
||||
|
||||
static gint crs_range_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
|
||||
CrsRangeEntry *entry_b = *(CrsRangeEntry **)b;
|
||||
|
||||
if (entry_a->base < entry_b->base) {
|
||||
return -1;
|
||||
} else if (entry_a->base > entry_b->base) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* crs_replace_with_free_ranges - given the 'used' ranges within [start - end]
|
||||
* interval, computes the 'free' ranges from the same interval.
|
||||
* Example: If the input array is { [a1 - a2],[b1 - b2] }, the function
|
||||
* will return { [base - a1], [a2 - b1], [b2 - limit] }.
|
||||
*/
|
||||
void crs_replace_with_free_ranges(GPtrArray *ranges,
|
||||
uint64_t start, uint64_t end)
|
||||
{
|
||||
GPtrArray *free_ranges = g_ptr_array_new();
|
||||
uint64_t free_base = start;
|
||||
int i;
|
||||
|
||||
g_ptr_array_sort(ranges, crs_range_compare);
|
||||
for (i = 0; i < ranges->len; i++) {
|
||||
CrsRangeEntry *used = g_ptr_array_index(ranges, i);
|
||||
|
||||
if (free_base < used->base) {
|
||||
crs_range_insert(free_ranges, free_base, used->base - 1);
|
||||
}
|
||||
|
||||
free_base = used->limit + 1;
|
||||
}
|
||||
|
||||
if (free_base < end) {
|
||||
crs_range_insert(free_ranges, free_base, end);
|
||||
}
|
||||
|
||||
g_ptr_array_set_size(ranges, 0);
|
||||
for (i = 0; i < free_ranges->len; i++) {
|
||||
g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i));
|
||||
}
|
||||
|
||||
g_ptr_array_free(free_ranges, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* crs_range_merge - merges adjacent ranges in the given array.
|
||||
* Array elements are deleted and replaced with the merged ranges.
|
||||
*/
|
||||
static void crs_range_merge(GPtrArray *range)
|
||||
{
|
||||
GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
CrsRangeEntry *entry;
|
||||
uint64_t range_base, range_limit;
|
||||
int i;
|
||||
|
||||
if (!range->len) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_ptr_array_sort(range, crs_range_compare);
|
||||
|
||||
entry = g_ptr_array_index(range, 0);
|
||||
range_base = entry->base;
|
||||
range_limit = entry->limit;
|
||||
for (i = 1; i < range->len; i++) {
|
||||
entry = g_ptr_array_index(range, i);
|
||||
if (entry->base - 1 == range_limit) {
|
||||
range_limit = entry->limit;
|
||||
} else {
|
||||
crs_range_insert(tmp, range_base, range_limit);
|
||||
range_base = entry->base;
|
||||
range_limit = entry->limit;
|
||||
}
|
||||
}
|
||||
crs_range_insert(tmp, range_base, range_limit);
|
||||
|
||||
g_ptr_array_set_size(range, 0);
|
||||
for (i = 0; i < tmp->len; i++) {
|
||||
entry = g_ptr_array_index(tmp, i);
|
||||
crs_range_insert(range, entry->base, entry->limit);
|
||||
}
|
||||
g_ptr_array_free(tmp, true);
|
||||
}
|
||||
|
||||
static void
|
||||
build_append_nameseg(GArray *array, const char *seg)
|
||||
{
|
||||
@@ -1951,6 +2076,166 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
|
||||
tpm2_ptr, "TPM2", table_data->len - tpm2_start, 4, NULL, NULL);
|
||||
}
|
||||
|
||||
Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set)
|
||||
{
|
||||
Aml *crs = aml_resource_template();
|
||||
CrsRangeSet temp_range_set;
|
||||
CrsRangeEntry *entry;
|
||||
uint8_t max_bus = pci_bus_num(host->bus);
|
||||
uint8_t type;
|
||||
int devfn;
|
||||
int i;
|
||||
|
||||
crs_range_set_init(&temp_range_set);
|
||||
for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
|
||||
uint64_t range_base, range_limit;
|
||||
PCIDevice *dev = host->bus->devices[devfn];
|
||||
|
||||
if (!dev) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCI_NUM_REGIONS; i++) {
|
||||
PCIIORegion *r = &dev->io_regions[i];
|
||||
|
||||
range_base = r->addr;
|
||||
range_limit = r->addr + r->size - 1;
|
||||
|
||||
/*
|
||||
* Work-around for old bioses
|
||||
* that do not support multiple root buses
|
||||
*/
|
||||
if (!range_base || range_base > range_limit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
crs_range_insert(temp_range_set.io_ranges,
|
||||
range_base, range_limit);
|
||||
} else { /* "memory" */
|
||||
uint64_t length = range_limit - range_base + 1;
|
||||
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
||||
crs_range_insert(temp_range_set.mem_ranges, range_base,
|
||||
range_limit);
|
||||
} else {
|
||||
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
||||
range_base, range_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
||||
if (type == PCI_HEADER_TYPE_BRIDGE) {
|
||||
uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS];
|
||||
if (subordinate > max_bus) {
|
||||
max_bus = subordinate;
|
||||
}
|
||||
|
||||
range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
||||
range_limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
||||
|
||||
/*
|
||||
* Work-around for old bioses
|
||||
* that do not support multiple root buses
|
||||
*/
|
||||
if (range_base && range_base <= range_limit) {
|
||||
crs_range_insert(temp_range_set.io_ranges,
|
||||
range_base, range_limit);
|
||||
}
|
||||
|
||||
range_base =
|
||||
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
||||
range_limit =
|
||||
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
||||
|
||||
/*
|
||||
* Work-around for old bioses
|
||||
* that do not support multiple root buses
|
||||
*/
|
||||
if (range_base && range_base <= range_limit) {
|
||||
uint64_t length = range_limit - range_base + 1;
|
||||
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
||||
crs_range_insert(temp_range_set.mem_ranges,
|
||||
range_base, range_limit);
|
||||
} else {
|
||||
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
||||
range_base, range_limit);
|
||||
}
|
||||
}
|
||||
|
||||
range_base =
|
||||
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||
range_limit =
|
||||
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||
|
||||
/*
|
||||
* Work-around for old bioses
|
||||
* that do not support multiple root buses
|
||||
*/
|
||||
if (range_base && range_base <= range_limit) {
|
||||
uint64_t length = range_limit - range_base + 1;
|
||||
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
||||
crs_range_insert(temp_range_set.mem_ranges,
|
||||
range_base, range_limit);
|
||||
} else {
|
||||
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
||||
range_base, range_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crs_range_merge(temp_range_set.io_ranges);
|
||||
for (i = 0; i < temp_range_set.io_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(temp_range_set.io_ranges, i);
|
||||
aml_append(crs,
|
||||
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||
0, entry->base, entry->limit, 0,
|
||||
entry->limit - entry->base + 1));
|
||||
crs_range_insert(range_set->io_ranges, entry->base, entry->limit);
|
||||
}
|
||||
|
||||
crs_range_merge(temp_range_set.mem_ranges);
|
||||
for (i = 0; i < temp_range_set.mem_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(temp_range_set.mem_ranges, i);
|
||||
assert(entry->limit <= UINT32_MAX &&
|
||||
(entry->limit - entry->base + 1) <= UINT32_MAX);
|
||||
aml_append(crs,
|
||||
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||
AML_READ_WRITE,
|
||||
0, entry->base, entry->limit, 0,
|
||||
entry->limit - entry->base + 1));
|
||||
crs_range_insert(range_set->mem_ranges, entry->base, entry->limit);
|
||||
}
|
||||
|
||||
crs_range_merge(temp_range_set.mem_64bit_ranges);
|
||||
for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i);
|
||||
aml_append(crs,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||
AML_READ_WRITE,
|
||||
0, entry->base, entry->limit, 0,
|
||||
entry->limit - entry->base + 1));
|
||||
crs_range_insert(range_set->mem_64bit_ranges,
|
||||
entry->base, entry->limit);
|
||||
}
|
||||
|
||||
crs_range_set_free(&temp_range_set);
|
||||
|
||||
aml_append(crs,
|
||||
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
|
||||
0,
|
||||
pci_bus_num(host->bus),
|
||||
max_bus,
|
||||
0,
|
||||
max_bus - pci_bus_num(host->bus) + 1));
|
||||
|
||||
return crs;
|
||||
}
|
||||
|
||||
/* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */
|
||||
static Aml *aml_serial_bus_device(uint8_t serial_bus_type, uint8_t flags,
|
||||
uint16_t type_flags,
|
||||
|
||||
+23
-3
@@ -71,6 +71,7 @@ static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
|
||||
val |= cdev->cpu ? 1 : 0;
|
||||
val |= cdev->is_inserting ? 2 : 0;
|
||||
val |= cdev->is_removing ? 4 : 0;
|
||||
val |= cdev->fw_remove ? 16 : 0;
|
||||
trace_cpuhp_acpi_read_flags(cpu_st->selector, val);
|
||||
break;
|
||||
case ACPI_CPU_CMD_DATA_OFFSET_RW:
|
||||
@@ -148,6 +149,14 @@ static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
|
||||
hotplug_ctrl = qdev_get_hotplug_handler(dev);
|
||||
hotplug_handler_unplug(hotplug_ctrl, dev, NULL);
|
||||
object_unparent(OBJECT(dev));
|
||||
cdev->fw_remove = false;
|
||||
} else if (data & 16) {
|
||||
if (!cdev->cpu || cdev->cpu == first_cpu) {
|
||||
trace_cpuhp_acpi_fw_remove_invalid_cpu(cpu_st->selector);
|
||||
break;
|
||||
}
|
||||
trace_cpuhp_acpi_fw_remove_cpu(cpu_st->selector);
|
||||
cdev->fw_remove = true;
|
||||
}
|
||||
break;
|
||||
case ACPI_CPU_CMD_OFFSET_WR:
|
||||
@@ -159,7 +168,8 @@ static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
|
||||
|
||||
do {
|
||||
cdev = &cpu_st->devs[iter];
|
||||
if (cdev->is_inserting || cdev->is_removing) {
|
||||
if (cdev->is_inserting || cdev->is_removing ||
|
||||
cdev->fw_remove) {
|
||||
cpu_st->selector = iter;
|
||||
trace_cpuhp_acpi_cpu_has_events(cpu_st->selector,
|
||||
cdev->is_inserting, cdev->is_removing);
|
||||
@@ -332,6 +342,7 @@ const VMStateDescription vmstate_cpu_hotplug = {
|
||||
#define CPU_INSERT_EVENT "CINS"
|
||||
#define CPU_REMOVE_EVENT "CRMV"
|
||||
#define CPU_EJECT_EVENT "CEJ0"
|
||||
#define CPU_FW_EJECT_EVENT "CEJF"
|
||||
|
||||
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
hwaddr io_base,
|
||||
@@ -384,7 +395,9 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
aml_append(field, aml_named_field(CPU_REMOVE_EVENT, 1));
|
||||
/* initiates device eject, write only */
|
||||
aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1));
|
||||
aml_append(field, aml_reserved_field(4));
|
||||
/* tell firmware to do device eject, write only */
|
||||
aml_append(field, aml_named_field(CPU_FW_EJECT_EVENT, 1));
|
||||
aml_append(field, aml_reserved_field(3));
|
||||
aml_append(field, aml_named_field(CPU_COMMAND, 8));
|
||||
aml_append(cpu_ctrl_dev, field);
|
||||
|
||||
@@ -419,6 +432,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT);
|
||||
Aml *rm_evt = aml_name("%s.%s", cphp_res_path, CPU_REMOVE_EVENT);
|
||||
Aml *ej_evt = aml_name("%s.%s", cphp_res_path, CPU_EJECT_EVENT);
|
||||
Aml *fw_ej_evt = aml_name("%s.%s", cphp_res_path, CPU_FW_EJECT_EVENT);
|
||||
|
||||
aml_append(cpus_dev, aml_name_decl("_HID", aml_string("ACPI0010")));
|
||||
aml_append(cpus_dev, aml_name_decl("_CID", aml_eisaid("PNP0A05")));
|
||||
@@ -461,7 +475,13 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(idx, cpu_selector));
|
||||
aml_append(method, aml_store(one, ej_evt));
|
||||
if (opts.fw_unplugs_cpu) {
|
||||
aml_append(method, aml_store(one, fw_ej_evt));
|
||||
aml_append(method, aml_store(aml_int(OVMF_CPUHP_SMI_CMD),
|
||||
aml_name("%s", opts.smi_path)));
|
||||
} else {
|
||||
aml_append(method, aml_store(one, ej_evt));
|
||||
}
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(cpus_dev, method);
|
||||
|
||||
@@ -29,6 +29,8 @@ cpuhp_acpi_clear_inserting_evt(uint32_t idx) "idx[0x%"PRIx32"]"
|
||||
cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]"
|
||||
cpuhp_acpi_ejecting_invalid_cpu(uint32_t idx) "0x%"PRIx32
|
||||
cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32
|
||||
cpuhp_acpi_fw_remove_invalid_cpu(uint32_t idx) "0x%"PRIx32
|
||||
cpuhp_acpi_fw_remove_cpu(uint32_t idx) "0x%"PRIx32
|
||||
cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST EVENT: 0x%"PRIx32
|
||||
cpuhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32
|
||||
|
||||
|
||||
@@ -465,14 +465,15 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid)
|
||||
/* Unmap the whole notifier's range */
|
||||
static void smmu_unmap_notifier_range(IOMMUNotifier *n)
|
||||
{
|
||||
IOMMUTLBEntry entry;
|
||||
IOMMUTLBEvent event;
|
||||
|
||||
entry.target_as = &address_space_memory;
|
||||
entry.iova = n->start;
|
||||
entry.perm = IOMMU_NONE;
|
||||
entry.addr_mask = n->end - n->start;
|
||||
event.type = IOMMU_NOTIFIER_UNMAP;
|
||||
event.entry.target_as = &address_space_memory;
|
||||
event.entry.iova = n->start;
|
||||
event.entry.perm = IOMMU_NONE;
|
||||
event.entry.addr_mask = n->end - n->start;
|
||||
|
||||
memory_region_notify_one(n, &entry);
|
||||
memory_region_notify_iommu_one(n, &event);
|
||||
}
|
||||
|
||||
/* Unmap all notifiers attached to @mr */
|
||||
|
||||
+7
-6
@@ -800,7 +800,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
|
||||
uint8_t tg, uint64_t num_pages)
|
||||
{
|
||||
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
|
||||
IOMMUTLBEntry entry;
|
||||
IOMMUTLBEvent event;
|
||||
uint8_t granule = tg;
|
||||
|
||||
if (!tg) {
|
||||
@@ -823,12 +823,13 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
|
||||
granule = tt->granule_sz;
|
||||
}
|
||||
|
||||
entry.target_as = &address_space_memory;
|
||||
entry.iova = iova;
|
||||
entry.addr_mask = num_pages * (1 << granule) - 1;
|
||||
entry.perm = IOMMU_NONE;
|
||||
event.type = IOMMU_NOTIFIER_UNMAP;
|
||||
event.entry.target_as = &address_space_memory;
|
||||
event.entry.iova = iova;
|
||||
event.entry.addr_mask = num_pages * (1 << granule) - 1;
|
||||
event.entry.perm = IOMMU_NONE;
|
||||
|
||||
memory_region_notify_one(n, &entry);
|
||||
memory_region_notify_iommu_one(n, &event);
|
||||
}
|
||||
|
||||
/* invalidate an asid/iova range tuple in all mr's */
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
|
||||
#define ARM_SPI_BASE 32
|
||||
|
||||
#define ACPI_BUILD_TABLE_SIZE 0x20000
|
||||
|
||||
static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus)
|
||||
{
|
||||
uint16_t i;
|
||||
@@ -153,7 +155,8 @@ static void acpi_dsdt_add_virtio(Aml *scope,
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
||||
uint32_t irq, bool use_highmem, bool highmem_ecam)
|
||||
uint32_t irq, bool use_highmem, bool highmem_ecam,
|
||||
VirtMachineState *vms)
|
||||
{
|
||||
int ecam_id = VIRT_ECAM_ID(highmem_ecam);
|
||||
struct GPEXConfig cfg = {
|
||||
@@ -161,6 +164,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
||||
.pio = memmap[VIRT_PCIE_PIO],
|
||||
.ecam = memmap[ecam_id],
|
||||
.irq = irq,
|
||||
.bus = vms->bus,
|
||||
};
|
||||
|
||||
if (use_highmem) {
|
||||
@@ -609,7 +613,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
|
||||
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
|
||||
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
|
||||
vms->highmem, vms->highmem_ecam);
|
||||
vms->highmem, vms->highmem_ecam, vms);
|
||||
if (vms->acpi_dev) {
|
||||
build_ged_aml(scope, "\\_SB."GED_DEVICE,
|
||||
HOTPLUG_HANDLER(vms->acpi_dev),
|
||||
@@ -654,6 +658,15 @@ struct AcpiBuildState {
|
||||
bool patched;
|
||||
} AcpiBuildState;
|
||||
|
||||
static void acpi_align_size(GArray *blob, unsigned align)
|
||||
{
|
||||
/*
|
||||
* Align size to multiple of given size. This reduces the chance
|
||||
* we need to change size in the future (breaking cross version migration).
|
||||
*/
|
||||
g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
|
||||
}
|
||||
|
||||
static
|
||||
void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
||||
{
|
||||
@@ -741,6 +754,20 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
||||
build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* The align size is 128, warn if 64k is not enough therefore
|
||||
* the align size could be resized.
|
||||
*/
|
||||
if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
|
||||
warn_report("ACPI table size %u exceeds %d bytes,"
|
||||
" migration may not work",
|
||||
tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
|
||||
error_printf("Try removing CPUs, NUMA nodes, memory slots"
|
||||
" or PCI bridges.");
|
||||
}
|
||||
acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
|
||||
|
||||
|
||||
/* Cleanup memory that's no longer used. */
|
||||
g_array_free(table_offsets, true);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user