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

virtio, pci, pc: fixes, features

Bugfixes all over the place.
HMAT support.
New flags for vhost-user-blk utility.
Auto-tuning of seg max for virtio storage.

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

# gpg: Signature made Mon 06 Jan 2020 17:05:05 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: (32 commits)
  intel_iommu: add present bit check for pasid table entries
  intel_iommu: a fix to vtd_find_as_from_bus_num()
  virtio-net: delete also control queue when TX/RX deleted
  virtio: reset region cache when on queue deletion
  virtio-mmio: update queue size on guest write
  tests: add virtio-scsi and virtio-blk seg_max_adjust test
  virtio: make seg_max virtqueue size dependent
  hw: fix using 4.2 compat in 5.0 machine types for i440fx/q35
  vhost-user-scsi: reset the device if supported
  vhost-user: add VHOST_USER_RESET_DEVICE to reset devices
  hw/pci/pci_host: Let pci_data_[read/write] use unsigned 'size' argument
  hw/pci/pci_host: Remove redundant PCI_DPRINTF()
  virtio-mmio: Clear v2 transport state on soft reset
  ACPI: add expected files for HMAT tests (acpihmat)
  tests/bios-tables-test: add test cases for ACPI HMAT
  tests/numa: Add case for QMP build HMAT
  hmat acpi: Build Memory Side Cache Information Structure(s)
  hmat acpi: Build System Locality Latency and Bandwidth Information Structure(s)
  hmat acpi: Build Memory Proximity Domain Attributes Structure(s)
  numa: Extend CLI to provide memory side cache information
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2020-01-07 16:25:00 +00:00
45 changed files with 1796 additions and 133 deletions
+64 -44
View File
@@ -576,70 +576,90 @@ vub_new(char *blk_file)
return vdev_blk;
}
static int opt_fdnum = -1;
static char *opt_socket_path;
static char *opt_blk_file;
static gboolean opt_print_caps;
static gboolean opt_read_only;
static GOptionEntry entries[] = {
{ "print-capabilities", 'c', 0, G_OPTION_ARG_NONE, &opt_print_caps,
"Print capabilities", NULL },
{ "fd", 'f', 0, G_OPTION_ARG_INT, &opt_fdnum,
"Use inherited fd socket", "FDNUM" },
{ "socket-path", 's', 0, G_OPTION_ARG_FILENAME, &opt_socket_path,
"Use UNIX socket path", "PATH" },
{"blk-file", 'b', 0, G_OPTION_ARG_FILENAME, &opt_blk_file,
"block device or file path", "PATH"},
{ "read-only", 'r', 0, G_OPTION_ARG_NONE, &opt_read_only,
"Enable read-only", NULL }
};
int main(int argc, char **argv)
{
int opt;
char *unix_socket = NULL;
char *blk_file = NULL;
bool enable_ro = false;
int lsock = -1, csock = -1;
VubDev *vdev_blk = NULL;
GError *error = NULL;
GOptionContext *context;
while ((opt = getopt(argc, argv, "b:rs:h")) != -1) {
switch (opt) {
case 'b':
blk_file = g_strdup(optarg);
break;
case 's':
unix_socket = g_strdup(optarg);
break;
case 'r':
enable_ro = true;
break;
case 'h':
default:
printf("Usage: %s [ -b block device or file, -s UNIX domain socket"
" | -r Enable read-only ] | [ -h ]\n", argv[0]);
return 0;
context = g_option_context_new(NULL);
g_option_context_add_main_entries(context, entries, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_printerr("Option parsing failed: %s\n", error->message);
exit(EXIT_FAILURE);
}
if (opt_print_caps) {
g_print("{\n");
g_print(" \"type\": \"block\",\n");
g_print(" \"features\": [\n");
g_print(" \"read-only\",\n");
g_print(" \"blk-file\"\n");
g_print(" ]\n");
g_print("}\n");
exit(EXIT_SUCCESS);
}
if (!opt_blk_file) {
g_print("%s\n", g_option_context_get_help(context, true, NULL));
exit(EXIT_FAILURE);
}
if (opt_socket_path) {
lsock = unix_sock_new(opt_socket_path);
if (lsock < 0) {
exit(EXIT_FAILURE);
}
} else if (opt_fdnum < 0) {
g_print("%s\n", g_option_context_get_help(context, true, NULL));
exit(EXIT_FAILURE);
} else {
lsock = opt_fdnum;
}
if (!unix_socket || !blk_file) {
printf("Usage: %s [ -b block device or file, -s UNIX domain socket"
" | -r Enable read-only ] | [ -h ]\n", argv[0]);
return -1;
}
lsock = unix_sock_new(unix_socket);
if (lsock < 0) {
goto err;
}
csock = accept(lsock, (void *)0, (void *)0);
csock = accept(lsock, NULL, NULL);
if (csock < 0) {
fprintf(stderr, "Accept error %s\n", strerror(errno));
goto err;
g_printerr("Accept error %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
vdev_blk = vub_new(blk_file);
vdev_blk = vub_new(opt_blk_file);
if (!vdev_blk) {
goto err;
exit(EXIT_FAILURE);
}
if (enable_ro) {
if (opt_read_only) {
vdev_blk->enable_ro = true;
}
if (!vug_init(&vdev_blk->parent, VHOST_USER_BLK_MAX_QUEUES, csock,
vub_panic_cb, &vub_iface)) {
fprintf(stderr, "Failed to initialized libvhost-user-glib\n");
goto err;
g_printerr("Failed to initialize libvhost-user-glib\n");
exit(EXIT_FAILURE);
}
g_main_loop_run(vdev_blk->loop);
g_main_loop_unref(vdev_blk->loop);
g_option_context_free(context);
vug_deinit(&vdev_blk->parent);
err:
vub_free(vdev_blk);
if (csock >= 0) {
close(csock);
@@ -647,8 +667,8 @@ err:
if (lsock >= 0) {
close(lsock);
}
g_free(unix_socket);
g_free(blk_file);
g_free(opt_socket_path);
g_free(opt_blk_file);
return 0;
}
+31
View File
@@ -54,6 +54,37 @@
]
}
##
# @VHostUserBackendBlockFeature:
#
# List of vhost user "block" features.
#
# @read-only: The --read-only command line option is supported.
# @blk-file: The --blk-file command line option is supported.
#
# Since: 5.0
##
{
'enum': 'VHostUserBackendBlockFeature',
'data': [ 'read-only', 'blk-file' ]
}
##
# @VHostUserBackendCapabilitiesBlock:
#
# Capabilities reported by vhost user "block" backends
#
# @features: list of supported features.
#
# Since: 5.0
##
{
'struct': 'VHostUserBackendCapabilitiesBlock',
'data': {
'features': [ 'VHostUserBackendBlockFeature' ]
}
}
##
# @VHostUserBackendInputFeature:
#
+32
View File
@@ -785,6 +785,7 @@ Protocol features
#define VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD 10
#define VHOST_USER_PROTOCOL_F_HOST_NOTIFIER 11
#define VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD 12
#define VHOST_USER_PROTOCOL_F_RESET_DEVICE 13
Master message types
--------------------
@@ -1190,6 +1191,20 @@ Master message types
ancillary data. The GPU protocol is used to inform the master of
rendering state and updates. See vhost-user-gpu.rst for details.
``VHOST_USER_RESET_DEVICE``
:id: 34
:equivalent ioctl: N/A
:master payload: N/A
:slave payload: N/A
Ask the vhost user backend to disable all rings and reset all
internal device state to the initial state, ready to be
reinitialized. The backend retains ownership of the device
throughout the reset operation.
Only valid if the ``VHOST_USER_PROTOCOL_F_RESET_DEVICE`` protocol
feature is set by the backend.
Slave message types
-------------------
@@ -1376,3 +1391,20 @@ Command line options:
Enable virgl rendering support.
(optional)
vhost-user-blk
--------------
Command line options:
--blk-file=PATH
Specify block device or file path.
(optional)
--read-only
Enable read-only.
(optional)
+5 -2
View File
@@ -7,6 +7,7 @@ config ACPI_X86
select ACPI_NVDIMM
select ACPI_CPU_HOTPLUG
select ACPI_MEMORY_HOTPLUG
select ACPI_HMAT
config ACPI_X86_ICH
bool
@@ -23,6 +24,10 @@ config ACPI_NVDIMM
bool
depends on ACPI
config ACPI_HMAT
bool
depends on ACPI
config ACPI_PCI
bool
depends on ACPI && PCI
@@ -33,5 +38,3 @@ config ACPI_VMGENID
depends on PC
config ACPI_HW_REDUCED
bool
depends on ACPI
+1
View File
@@ -7,6 +7,7 @@ common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
common-obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device.o
common-obj-$(CONFIG_ACPI_HMAT) += hmat.o
common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
common-obj-$(call lnot,$(CONFIG_PC)) += acpi-x86-stub.o
+268
View File
@@ -0,0 +1,268 @@
/*
* HMAT ACPI Implementation
*
* Copyright(C) 2019 Intel Corporation.
*
* Author:
* Liu jingqi <jingqi.liu@linux.intel.com>
* Tao Xu <tao3.xu@intel.com>
*
* HMAT is defined in ACPI 6.3: 5.2.27 Heterogeneous Memory Attribute Table
* (HMAT)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "sysemu/numa.h"
#include "hw/acpi/hmat.h"
/*
* ACPI 6.3:
* 5.2.27.3 Memory Proximity Domain Attributes Structure: Table 5-145
*/
static void build_hmat_mpda(GArray *table_data, uint16_t flags,
uint32_t initiator, uint32_t mem_node)
{
/* Memory Proximity Domain Attributes Structure */
/* Type */
build_append_int_noprefix(table_data, 0, 2);
/* Reserved */
build_append_int_noprefix(table_data, 0, 2);
/* Length */
build_append_int_noprefix(table_data, 40, 4);
/* Flags */
build_append_int_noprefix(table_data, flags, 2);
/* Reserved */
build_append_int_noprefix(table_data, 0, 2);
/* Proximity Domain for the Attached Initiator */
build_append_int_noprefix(table_data, initiator, 4);
/* Proximity Domain for the Memory */
build_append_int_noprefix(table_data, mem_node, 4);
/* Reserved */
build_append_int_noprefix(table_data, 0, 4);
/*
* Reserved:
* Previously defined as the Start Address of the System Physical
* Address Range. Deprecated since ACPI Spec 6.3.
*/
build_append_int_noprefix(table_data, 0, 8);
/*
* Reserved:
* Previously defined as the Range Length of the region in bytes.
* Deprecated since ACPI Spec 6.3.
*/
build_append_int_noprefix(table_data, 0, 8);
}
/*
* ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information
* Structure: Table 5-146
*/
static void build_hmat_lb(GArray *table_data, HMAT_LB_Info *hmat_lb,
uint32_t num_initiator, uint32_t num_target,
uint32_t *initiator_list)
{
int i, index;
HMAT_LB_Data *lb_data;
uint16_t *entry_list;
uint32_t base;
/* Length in bytes for entire structure */
uint32_t lb_length
= 32 /* Table length upto and including Entry Base Unit */
+ 4 * num_initiator /* Initiator Proximity Domain List */
+ 4 * num_target /* Target Proximity Domain List */
+ 2 * num_initiator * num_target; /* Latency or Bandwidth Entries */
/* Type */
build_append_int_noprefix(table_data, 1, 2);
/* Reserved */
build_append_int_noprefix(table_data, 0, 2);
/* Length */
build_append_int_noprefix(table_data, lb_length, 4);
/* Flags: Bits [3:0] Memory Hierarchy, Bits[7:4] Reserved */
assert(!(hmat_lb->hierarchy >> 4));
build_append_int_noprefix(table_data, hmat_lb->hierarchy, 1);
/* Data Type */
build_append_int_noprefix(table_data, hmat_lb->data_type, 1);
/* Reserved */
build_append_int_noprefix(table_data, 0, 2);
/* Number of Initiator Proximity Domains (s) */
build_append_int_noprefix(table_data, num_initiator, 4);
/* Number of Target Proximity Domains (t) */
build_append_int_noprefix(table_data, num_target, 4);
/* Reserved */
build_append_int_noprefix(table_data, 0, 4);
/* Entry Base Unit */
if (hmat_lb->data_type <= HMAT_LB_DATA_WRITE_LATENCY) {
/* Convert latency base from nanoseconds to picosecond */
base = hmat_lb->base * 1000;
} else {
/* Convert bandwidth base from Byte to Megabyte */
base = hmat_lb->base / MiB;
}
build_append_int_noprefix(table_data, base, 8);
/* Initiator Proximity Domain List */
for (i = 0; i < num_initiator; i++) {
build_append_int_noprefix(table_data, initiator_list[i], 4);
}
/* Target Proximity Domain List */
for (i = 0; i < num_target; i++) {
build_append_int_noprefix(table_data, i, 4);
}
/* Latency or Bandwidth Entries */
entry_list = g_malloc0(num_initiator * num_target * sizeof(uint16_t));
for (i = 0; i < hmat_lb->list->len; i++) {
lb_data = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
index = lb_data->initiator * num_target + lb_data->target;
entry_list[index] = (uint16_t)(lb_data->data / hmat_lb->base);
}
for (i = 0; i < num_initiator * num_target; i++) {
build_append_int_noprefix(table_data, entry_list[i], 2);
}
g_free(entry_list);
}
/* ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure: Table 5-147 */
static void build_hmat_cache(GArray *table_data, uint8_t total_levels,
NumaHmatCacheOptions *hmat_cache)
{
/*
* Cache Attributes: Bits [3:0] Total Cache Levels
* for this Memory Proximity Domain
*/
uint32_t cache_attr = total_levels;
/* Bits [7:4] : Cache Level described in this structure */
cache_attr |= (uint32_t) hmat_cache->level << 4;
/* Bits [11:8] - Cache Associativity */
cache_attr |= (uint32_t) hmat_cache->associativity << 8;
/* Bits [15:12] - Write Policy */
cache_attr |= (uint32_t) hmat_cache->policy << 12;
/* Bits [31:16] - Cache Line size in bytes */
cache_attr |= (uint32_t) hmat_cache->line << 16;
/* Type */
build_append_int_noprefix(table_data, 2, 2);
/* Reserved */
build_append_int_noprefix(table_data, 0, 2);
/* Length */
build_append_int_noprefix(table_data, 32, 4);
/* Proximity Domain for the Memory */
build_append_int_noprefix(table_data, hmat_cache->node_id, 4);
/* Reserved */
build_append_int_noprefix(table_data, 0, 4);
/* Memory Side Cache Size */
build_append_int_noprefix(table_data, hmat_cache->size, 8);
/* Cache Attributes */
build_append_int_noprefix(table_data, cache_attr, 4);
/* Reserved */
build_append_int_noprefix(table_data, 0, 2);
/*
* Number of SMBIOS handles (n)
* Linux kernel uses Memory Side Cache Information Structure
* without SMBIOS entries for now, so set Number of SMBIOS handles
* as 0.
*/
build_append_int_noprefix(table_data, 0, 2);
}
/* Build HMAT sub table structures */
static void hmat_build_table_structs(GArray *table_data, NumaState *numa_state)
{
uint16_t flags;
uint32_t num_initiator = 0;
uint32_t initiator_list[MAX_NODES];
int i, hierarchy, type, cache_level, total_levels;
HMAT_LB_Info *hmat_lb;
NumaHmatCacheOptions *hmat_cache;
for (i = 0; i < numa_state->num_nodes; i++) {
flags = 0;
if (numa_state->nodes[i].initiator < MAX_NODES) {
flags |= HMAT_PROXIMITY_INITIATOR_VALID;
}
build_hmat_mpda(table_data, flags, numa_state->nodes[i].initiator, i);
}
for (i = 0; i < numa_state->num_nodes; i++) {
if (numa_state->nodes[i].has_cpu) {
initiator_list[num_initiator++] = i;
}
}
/*
* ACPI 6.3: 5.2.27.4 System Locality Latency and Bandwidth Information
* Structure: Table 5-146
*/
for (hierarchy = HMAT_LB_MEM_MEMORY;
hierarchy <= HMAT_LB_MEM_CACHE_3RD_LEVEL; hierarchy++) {
for (type = HMAT_LB_DATA_ACCESS_LATENCY;
type <= HMAT_LB_DATA_WRITE_BANDWIDTH; type++) {
hmat_lb = numa_state->hmat_lb[hierarchy][type];
if (hmat_lb && hmat_lb->list->len) {
build_hmat_lb(table_data, hmat_lb, num_initiator,
numa_state->num_nodes, initiator_list);
}
}
}
/*
* ACPI 6.3: 5.2.27.5 Memory Side Cache Information Structure:
* Table 5-147
*/
for (i = 0; i < numa_state->num_nodes; i++) {
total_levels = 0;
for (cache_level = 1; cache_level < HMAT_LB_LEVELS; cache_level++) {
if (numa_state->hmat_cache[i][cache_level]) {
total_levels++;
}
}
for (cache_level = 0; cache_level <= total_levels; cache_level++) {
hmat_cache = numa_state->hmat_cache[i][cache_level];
if (hmat_cache) {
build_hmat_cache(table_data, total_levels, hmat_cache);
}
}
}
}
void build_hmat(GArray *table_data, BIOSLinker *linker, NumaState *numa_state)
{
int hmat_start = table_data->len;
/* reserve space for HMAT header */
acpi_data_push(table_data, 40);
hmat_build_table_structs(table_data, numa_state);
build_header(linker, table_data,
(void *)(table_data->data + hmat_start),
"HMAT", table_data->len - hmat_start, 2, NULL, NULL);
}
+42
View File
@@ -0,0 +1,42 @@
/*
* HMAT ACPI Implementation Header
*
* Copyright(C) 2019 Intel Corporation.
*
* Author:
* Liu jingqi <jingqi.liu@linux.intel.com>
* Tao Xu <tao3.xu@intel.com>
*
* HMAT is defined in ACPI 6.3: 5.2.27 Heterogeneous Memory Attribute Table
* (HMAT)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#ifndef HMAT_H
#define HMAT_H
#include "hw/acpi/aml-build.h"
/*
* ACPI 6.3: 5.2.27.3 Memory Proximity Domain Attributes Structure,
* Table 5-145, Field "flag", Bit [0]: set to 1 to indicate that data in
* the Proximity Domain for the Attached Initiator field is valid.
* Other bits reserved.
*/
#define HMAT_PROXIMITY_INITIATOR_VALID 0x1
void build_hmat(GArray *table_data, BIOSLinker *linker, NumaState *numa_state);
#endif
+15 -3
View File
@@ -764,13 +764,16 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
{
VirtIOBlockReq *req;
MultiReqBuffer mrb = {};
bool suppress_notifications = virtio_queue_get_notification(vq);
bool progress = false;
aio_context_acquire(blk_get_aio_context(s->blk));
blk_io_plug(s->blk);
do {
virtio_queue_set_notification(vq, 0);
if (suppress_notifications) {
virtio_queue_set_notification(vq, 0);
}
while ((req = virtio_blk_get_request(s, vq))) {
progress = true;
@@ -781,7 +784,9 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
}
}
virtio_queue_set_notification(vq, 1);
if (suppress_notifications) {
virtio_queue_set_notification(vq, 1);
}
} while (!virtio_queue_empty(vq));
if (mrb.num_reqs) {
@@ -908,7 +913,8 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
blk_get_geometry(s->blk, &capacity);
memset(&blkcfg, 0, sizeof(blkcfg));
virtio_stq_p(vdev, &blkcfg.capacity, capacity);
virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2);
virtio_stl_p(vdev, &blkcfg.seg_max,
s->conf.seg_max_adjust ? s->conf.queue_size - 2 : 128 - 2);
virtio_stw_p(vdev, &blkcfg.geometry.cylinders, conf->cyls);
virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size);
@@ -1133,6 +1139,11 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
error_setg(errp, "num-queues property must be larger than 0");
return;
}
if (conf->queue_size <= 2) {
error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
"must be > 2", conf->queue_size);
return;
}
if (!is_power_of_2(conf->queue_size) ||
conf->queue_size > VIRTQUEUE_MAX_SIZE) {
error_setg(errp, "invalid queue-size property (%" PRIu16 "), "
@@ -1262,6 +1273,7 @@ static Property virtio_blk_properties[] = {
true),
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
DEFINE_PROP_BOOL("seg-max-adjust", VirtIOBlock, conf.seg_max_adjust, true),
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
IOThread *),
DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
+8
View File
@@ -1126,9 +1126,17 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOSerial *vser = VIRTIO_SERIAL(dev);
int i;
QLIST_REMOVE(vser, next);
virtio_delete_queue(vser->c_ivq);
virtio_delete_queue(vser->c_ovq);
for (i = 0; i < vser->bus.max_nr_ports; i++) {
virtio_delete_queue(vser->ivqs[i]);
virtio_delete_queue(vser->ovqs[i]);
}
g_free(vser->ivqs);
g_free(vser->ovqs);
g_free(vser->ports_map);
+68
View File
@@ -29,11 +29,15 @@
GlobalProperty hw_compat_4_2[] = {
{ "virtio-blk-device", "x-enable-wce-if-config-wce", "off" },
{ "virtio-blk-device", "seg-max-adjust", "off"},
{ "virtio-scsi-device", "seg_max_adjust", "off"},
{ "vhost-blk-device", "seg_max_adjust", "off"},
};
const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2);
GlobalProperty hw_compat_4_1[] = {
{ "virtio-pci", "x-pcie-flr-init", "off" },
{ "virtio-device", "use-disabled-flag", "false" },
};
const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1);
@@ -429,6 +433,20 @@ static void machine_set_nvdimm(Object *obj, bool value, Error **errp)
ms->nvdimms_state->is_enabled = value;
}
static bool machine_get_hmat(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
return ms->numa_state->hmat_enabled;
}
static void machine_set_hmat(Object *obj, bool value, Error **errp)
{
MachineState *ms = MACHINE(obj);
ms->numa_state->hmat_enabled = value;
}
static char *machine_get_nvdimm_persistence(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -556,6 +574,7 @@ void machine_set_cpu_numa_node(MachineState *machine,
const CpuInstanceProperties *props, Error **errp)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
NodeInfo *numa_info = machine->numa_state->nodes;
bool match = false;
int i;
@@ -625,6 +644,17 @@ void machine_set_cpu_numa_node(MachineState *machine,
match = true;
slot->props.node_id = props->node_id;
slot->props.has_node_id = props->has_node_id;
if (machine->numa_state->hmat_enabled) {
if ((numa_info[props->node_id].initiator < MAX_NODES) &&
(props->node_id != numa_info[props->node_id].initiator)) {
error_setg(errp, "The initiator of CPU NUMA node %" PRId64
" should be itself", props->node_id);
return;
}
numa_info[props->node_id].has_cpu = true;
numa_info[props->node_id].initiator = props->node_id;
}
}
if (!match) {
@@ -845,6 +875,13 @@ static void machine_initfn(Object *obj)
if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) {
ms->numa_state = g_new0(NumaState, 1);
object_property_add_bool(obj, "hmat",
machine_get_hmat, machine_set_hmat,
&error_abort);
object_property_set_description(obj, "hmat",
"Set on/off to enable/disable "
"ACPI Heterogeneous Memory Attribute "
"Table (HMAT)", NULL);
}
/* Register notifier when init is done for sysbus sanity checks */
@@ -912,6 +949,32 @@ static char *cpu_slot_to_string(const CPUArchId *cpu)
return g_string_free(s, false);
}
static void numa_validate_initiator(NumaState *numa_state)
{
int i;
NodeInfo *numa_info = numa_state->nodes;
for (i = 0; i < numa_state->num_nodes; i++) {
if (numa_info[i].initiator == MAX_NODES) {
error_report("The initiator of NUMA node %d is missing, use "
"'-numa node,initiator' option to declare it", i);
exit(1);
}
if (!numa_info[numa_info[i].initiator].present) {
error_report("NUMA node %" PRIu16 " is missing, use "
"'-numa node' option to declare it first",
numa_info[i].initiator);
exit(1);
}
if (!numa_info[numa_info[i].initiator].has_cpu) {
error_report("The initiator of NUMA node %d is invalid", i);
exit(1);
}
}
}
static void machine_numa_finish_cpu_init(MachineState *machine)
{
int i;
@@ -952,6 +1015,11 @@ static void machine_numa_finish_cpu_init(MachineState *machine)
machine_set_cpu_numa_node(machine, &props, &error_fatal);
}
}
if (machine->numa_state->hmat_enabled) {
numa_validate_initiator(machine->numa_state);
}
if (s->len && !qtest_enabled()) {
warn_report("CPU(s) not present in any NUMA nodes: %s",
s->str);
+297
View File
@@ -23,6 +23,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "sysemu/hostmem.h"
#include "sysemu/numa.h"
#include "sysemu/sysemu.h"
@@ -129,6 +130,29 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node,
numa_info[nodenr].node_mem = object_property_get_uint(o, "size", NULL);
numa_info[nodenr].node_memdev = MEMORY_BACKEND(o);
}
/*
* If not set the initiator, set it to MAX_NODES. And if
* HMAT is enabled and this node has no cpus, QEMU will raise error.
*/
numa_info[nodenr].initiator = MAX_NODES;
if (node->has_initiator) {
if (!ms->numa_state->hmat_enabled) {
error_setg(errp, "ACPI Heterogeneous Memory Attribute Table "
"(HMAT) is disabled, enable it with -machine hmat=on "
"before using any of hmat specific options");
return;
}
if (node->initiator >= MAX_NODES) {
error_report("The initiator id %" PRIu16 " expects an integer "
"between 0 and %d", node->initiator,
MAX_NODES - 1);
return;
}
numa_info[nodenr].initiator = node->initiator;
}
numa_info[nodenr].present = true;
max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1);
ms->numa_state->num_nodes++;
@@ -171,6 +195,253 @@ void parse_numa_distance(MachineState *ms, NumaDistOptions *dist, Error **errp)
ms->numa_state->have_numa_distance = true;
}
void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
Error **errp)
{
int i, first_bit, last_bit;
uint64_t max_entry, temp_base, bitmap_copy;
NodeInfo *numa_info = numa_state->nodes;
HMAT_LB_Info *hmat_lb =
numa_state->hmat_lb[node->hierarchy][node->data_type];
HMAT_LB_Data lb_data = {};
HMAT_LB_Data *lb_temp;
/* Error checking */
if (node->initiator > numa_state->num_nodes) {
error_setg(errp, "Invalid initiator=%d, it should be less than %d",
node->initiator, numa_state->num_nodes);
return;
}
if (node->target > numa_state->num_nodes) {
error_setg(errp, "Invalid target=%d, it should be less than %d",
node->target, numa_state->num_nodes);
return;
}
if (!numa_info[node->initiator].has_cpu) {
error_setg(errp, "Invalid initiator=%d, it isn't an "
"initiator proximity domain", node->initiator);
return;
}
if (!numa_info[node->target].present) {
error_setg(errp, "The target=%d should point to an existing node",
node->target);
return;
}
if (!hmat_lb) {
hmat_lb = g_malloc0(sizeof(*hmat_lb));
numa_state->hmat_lb[node->hierarchy][node->data_type] = hmat_lb;
hmat_lb->list = g_array_new(false, true, sizeof(HMAT_LB_Data));
}
hmat_lb->hierarchy = node->hierarchy;
hmat_lb->data_type = node->data_type;
lb_data.initiator = node->initiator;
lb_data.target = node->target;
if (node->data_type <= HMATLB_DATA_TYPE_WRITE_LATENCY) {
/* Input latency data */
if (!node->has_latency) {
error_setg(errp, "Missing 'latency' option");
return;
}
if (node->has_bandwidth) {
error_setg(errp, "Invalid option 'bandwidth' since "
"the data type is latency");
return;
}
/* Detect duplicate configuration */
for (i = 0; i < hmat_lb->list->len; i++) {
lb_temp = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
if (node->initiator == lb_temp->initiator &&
node->target == lb_temp->target) {
error_setg(errp, "Duplicate configuration of the latency for "
"initiator=%d and target=%d", node->initiator,
node->target);
return;
}
}
hmat_lb->base = hmat_lb->base ? hmat_lb->base : UINT64_MAX;
if (node->latency) {
/* Calculate the temporary base and compressed latency */
max_entry = node->latency;
temp_base = 1;
while (QEMU_IS_ALIGNED(max_entry, 10)) {
max_entry /= 10;
temp_base *= 10;
}
/* Calculate the max compressed latency */
temp_base = MIN(hmat_lb->base, temp_base);
max_entry = node->latency / hmat_lb->base;
max_entry = MAX(hmat_lb->range_bitmap, max_entry);
/*
* For latency hmat_lb->range_bitmap record the max compressed
* latency which should be less than 0xFFFF (UINT16_MAX)
*/
if (max_entry >= UINT16_MAX) {
error_setg(errp, "Latency %" PRIu64 " between initiator=%d and "
"target=%d should not differ from previously entered "
"min or max values on more than %d", node->latency,
node->initiator, node->target, UINT16_MAX - 1);
return;
} else {
hmat_lb->base = temp_base;
hmat_lb->range_bitmap = max_entry;
}
/*
* Set lb_info_provided bit 0 as 1,
* latency information is provided
*/
numa_info[node->target].lb_info_provided |= BIT(0);
}
lb_data.data = node->latency;
} else if (node->data_type >= HMATLB_DATA_TYPE_ACCESS_BANDWIDTH) {
/* Input bandwidth data */
if (!node->has_bandwidth) {
error_setg(errp, "Missing 'bandwidth' option");
return;
}
if (node->has_latency) {
error_setg(errp, "Invalid option 'latency' since "
"the data type is bandwidth");
return;
}
if (!QEMU_IS_ALIGNED(node->bandwidth, MiB)) {
error_setg(errp, "Bandwidth %" PRIu64 " between initiator=%d and "
"target=%d should be 1MB aligned", node->bandwidth,
node->initiator, node->target);
return;
}
/* Detect duplicate configuration */
for (i = 0; i < hmat_lb->list->len; i++) {
lb_temp = &g_array_index(hmat_lb->list, HMAT_LB_Data, i);
if (node->initiator == lb_temp->initiator &&
node->target == lb_temp->target) {
error_setg(errp, "Duplicate configuration of the bandwidth for "
"initiator=%d and target=%d", node->initiator,
node->target);
return;
}
}
hmat_lb->base = hmat_lb->base ? hmat_lb->base : 1;
if (node->bandwidth) {
/* Keep bitmap unchanged when bandwidth out of range */
bitmap_copy = hmat_lb->range_bitmap;
bitmap_copy |= node->bandwidth;
first_bit = ctz64(bitmap_copy);
temp_base = UINT64_C(1) << first_bit;
max_entry = node->bandwidth / temp_base;
last_bit = 64 - clz64(bitmap_copy);
/*
* For bandwidth, first_bit record the base unit of bandwidth bits,
* last_bit record the last bit of the max bandwidth. The max
* compressed bandwidth should be less than 0xFFFF (UINT16_MAX)
*/
if ((last_bit - first_bit) > UINT16_BITS ||
max_entry >= UINT16_MAX) {
error_setg(errp, "Bandwidth %" PRIu64 " between initiator=%d "
"and target=%d should not differ from previously "
"entered values on more than %d", node->bandwidth,
node->initiator, node->target, UINT16_MAX - 1);
return;
} else {
hmat_lb->base = temp_base;
hmat_lb->range_bitmap = bitmap_copy;
}
/*
* Set lb_info_provided bit 1 as 1,
* bandwidth information is provided
*/
numa_info[node->target].lb_info_provided |= BIT(1);
}
lb_data.data = node->bandwidth;
} else {
assert(0);
}
g_array_append_val(hmat_lb->list, lb_data);
}
void parse_numa_hmat_cache(MachineState *ms, NumaHmatCacheOptions *node,
Error **errp)
{
int nb_numa_nodes = ms->numa_state->num_nodes;
NodeInfo *numa_info = ms->numa_state->nodes;
NumaHmatCacheOptions *hmat_cache = NULL;
if (node->node_id >= nb_numa_nodes) {
error_setg(errp, "Invalid node-id=%" PRIu32 ", it should be less "
"than %d", node->node_id, nb_numa_nodes);
return;
}
if (numa_info[node->node_id].lb_info_provided != (BIT(0) | BIT(1))) {
error_setg(errp, "The latency and bandwidth information of "
"node-id=%" PRIu32 " should be provided before memory side "
"cache attributes", node->node_id);
return;
}
if (node->level < 1 || node->level >= HMAT_LB_LEVELS) {
error_setg(errp, "Invalid level=%" PRIu8 ", it should be larger than 0 "
"and less than or equal to %d", node->level,
HMAT_LB_LEVELS - 1);
return;
}
assert(node->associativity < HMAT_CACHE_ASSOCIATIVITY__MAX);
assert(node->policy < HMAT_CACHE_WRITE_POLICY__MAX);
if (ms->numa_state->hmat_cache[node->node_id][node->level]) {
error_setg(errp, "Duplicate configuration of the side cache for "
"node-id=%" PRIu32 " and level=%" PRIu8,
node->node_id, node->level);
return;
}
if ((node->level > 1) &&
ms->numa_state->hmat_cache[node->node_id][node->level - 1] &&
(node->size >=
ms->numa_state->hmat_cache[node->node_id][node->level - 1]->size)) {
error_setg(errp, "Invalid size=%" PRIu64 ", the size of level=%" PRIu8
" should be less than the size(%" PRIu64 ") of "
"level=%u", node->size, node->level,
ms->numa_state->hmat_cache[node->node_id]
[node->level - 1]->size,
node->level - 1);
return;
}
if ((node->level < HMAT_LB_LEVELS - 1) &&
ms->numa_state->hmat_cache[node->node_id][node->level + 1] &&
(node->size <=
ms->numa_state->hmat_cache[node->node_id][node->level + 1]->size)) {
error_setg(errp, "Invalid size=%" PRIu64 ", the size of level=%" PRIu8
" should be larger than the size(%" PRIu64 ") of "
"level=%u", node->size, node->level,
ms->numa_state->hmat_cache[node->node_id]
[node->level + 1]->size,
node->level + 1);
return;
}
hmat_cache = g_malloc0(sizeof(*hmat_cache));
memcpy(hmat_cache, node, sizeof(*hmat_cache));
ms->numa_state->hmat_cache[node->node_id][node->level] = hmat_cache;
}
void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
{
Error *err = NULL;
@@ -208,6 +479,32 @@ void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
machine_set_cpu_numa_node(ms, qapi_NumaCpuOptions_base(&object->u.cpu),
&err);
break;
case NUMA_OPTIONS_TYPE_HMAT_LB:
if (!ms->numa_state->hmat_enabled) {
error_setg(errp, "ACPI Heterogeneous Memory Attribute Table "
"(HMAT) is disabled, enable it with -machine hmat=on "
"before using any of hmat specific options");
return;
}
parse_numa_hmat_lb(ms->numa_state, &object->u.hmat_lb, &err);
if (err) {
goto end;
}
break;
case NUMA_OPTIONS_TYPE_HMAT_CACHE:
if (!ms->numa_state->hmat_enabled) {
error_setg(errp, "ACPI Heterogeneous Memory Attribute Table "
"(HMAT) is disabled, enable it with -machine hmat=on "
"before using any of hmat specific options");
return;
}
parse_numa_hmat_cache(ms, &object->u.hmat_cache, &err);
if (err) {
goto end;
}
break;
default:
abort();
}
+5
View File
@@ -68,6 +68,7 @@
#include "hw/i386/intel_iommu.h"
#include "hw/acpi/ipmi.h"
#include "hw/acpi/hmat.h"
/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
* -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
@@ -2835,6 +2836,10 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_slit(tables_blob, tables->linker, machine);
}
if (machine->numa_state->hmat_enabled) {
acpi_add_table(table_offsets, tables_blob);
build_hmat(tables_blob, tables->linker, machine->numa_state);
}
}
if (acpi_get_mcfg(&mcfg)) {
acpi_add_table(table_offsets, tables_blob);
+77 -23
View File
@@ -686,9 +686,18 @@ static inline bool vtd_pe_type_check(X86IOMMUState *x86_iommu,
return true;
}
static int vtd_get_pasid_dire(dma_addr_t pasid_dir_base,
uint32_t pasid,
VTDPASIDDirEntry *pdire)
static inline bool vtd_pdire_present(VTDPASIDDirEntry *pdire)
{
return pdire->val & 1;
}
/**
* Caller of this function should check present bit if wants
* to use pdir entry for futher usage except for fpd bit check.
*/
static int vtd_get_pdire_from_pdir_table(dma_addr_t pasid_dir_base,
uint32_t pasid,
VTDPASIDDirEntry *pdire)
{
uint32_t index;
dma_addr_t addr, entry_size;
@@ -703,18 +712,22 @@ static int vtd_get_pasid_dire(dma_addr_t pasid_dir_base,
return 0;
}
static int vtd_get_pasid_entry(IntelIOMMUState *s,
uint32_t pasid,
VTDPASIDDirEntry *pdire,
VTDPASIDEntry *pe)
static inline bool vtd_pe_present(VTDPASIDEntry *pe)
{
return pe->val[0] & VTD_PASID_ENTRY_P;
}
static int vtd_get_pe_in_pasid_leaf_table(IntelIOMMUState *s,
uint32_t pasid,
dma_addr_t addr,
VTDPASIDEntry *pe)
{
uint32_t index;
dma_addr_t addr, entry_size;
dma_addr_t entry_size;
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
index = VTD_PASID_TABLE_INDEX(pasid);
entry_size = VTD_PASID_ENTRY_SIZE;
addr = pdire->val & VTD_PASID_TABLE_BASE_ADDR_MASK;
addr = addr + index * entry_size;
if (dma_memory_read(&address_space_memory, addr, pe, entry_size)) {
return -VTD_FR_PASID_TABLE_INV;
@@ -732,25 +745,54 @@ static int vtd_get_pasid_entry(IntelIOMMUState *s,
return 0;
}
static int vtd_get_pasid_entry_from_pasid(IntelIOMMUState *s,
dma_addr_t pasid_dir_base,
uint32_t pasid,
VTDPASIDEntry *pe)
/**
* Caller of this function should check present bit if wants
* to use pasid entry for futher usage except for fpd bit check.
*/
static int vtd_get_pe_from_pdire(IntelIOMMUState *s,
uint32_t pasid,
VTDPASIDDirEntry *pdire,
VTDPASIDEntry *pe)
{
dma_addr_t addr = pdire->val & VTD_PASID_TABLE_BASE_ADDR_MASK;
return vtd_get_pe_in_pasid_leaf_table(s, pasid, addr, pe);
}
/**
* This function gets a pasid entry from a specified pasid
* table (includes dir and leaf table) with a specified pasid.
* Sanity check should be done to ensure return a present
* pasid entry to caller.
*/
static int vtd_get_pe_from_pasid_table(IntelIOMMUState *s,
dma_addr_t pasid_dir_base,
uint32_t pasid,
VTDPASIDEntry *pe)
{
int ret;
VTDPASIDDirEntry pdire;
ret = vtd_get_pasid_dire(pasid_dir_base, pasid, &pdire);
ret = vtd_get_pdire_from_pdir_table(pasid_dir_base,
pasid, &pdire);
if (ret) {
return ret;
}
ret = vtd_get_pasid_entry(s, pasid, &pdire, pe);
if (!vtd_pdire_present(&pdire)) {
return -VTD_FR_PASID_TABLE_INV;
}
ret = vtd_get_pe_from_pdire(s, pasid, &pdire, pe);
if (ret) {
return ret;
}
return ret;
if (!vtd_pe_present(pe)) {
return -VTD_FR_PASID_TABLE_INV;
}
return 0;
}
static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s,
@@ -763,7 +805,7 @@ static int vtd_ce_get_rid2pasid_entry(IntelIOMMUState *s,
pasid = VTD_CE_GET_RID2PASID(ce);
pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
ret = vtd_get_pasid_entry_from_pasid(s, pasid_dir_base, pasid, pe);
ret = vtd_get_pe_from_pasid_table(s, pasid_dir_base, pasid, pe);
return ret;
}
@@ -781,7 +823,11 @@ static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s,
pasid = VTD_CE_GET_RID2PASID(ce);
pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
ret = vtd_get_pasid_dire(pasid_dir_base, pasid, &pdire);
/*
* No present bit check since fpd is meaningful even
* if the present bit is clear.
*/
ret = vtd_get_pdire_from_pdir_table(pasid_dir_base, pasid, &pdire);
if (ret) {
return ret;
}
@@ -791,7 +837,15 @@ static int vtd_ce_get_pasid_fpd(IntelIOMMUState *s,
return 0;
}
ret = vtd_get_pasid_entry(s, pasid, &pdire, &pe);
if (!vtd_pdire_present(&pdire)) {
return -VTD_FR_PASID_TABLE_INV;
}
/*
* No present bit check since fpd is meaningful even
* if the present bit is clear.
*/
ret = vtd_get_pe_from_pdire(s, pasid, &pdire, &pe);
if (ret) {
return ret;
}
@@ -948,6 +1002,7 @@ static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num)
return vtd_bus;
}
}
vtd_bus = NULL;
}
return vtd_bus;
}
@@ -2610,16 +2665,15 @@ static uint64_t vtd_mem_read(void *opaque, hwaddr addr, unsigned size)
switch (addr) {
/* Root Table Address Register, 64-bit */
case DMAR_RTADDR_REG:
val = vtd_get_quad_raw(s, DMAR_RTADDR_REG);
if (size == 4) {
val = s->root & ((1ULL << 32) - 1);
} else {
val = s->root;
val = val & ((1ULL << 32) - 1);
}
break;
case DMAR_RTADDR_REG_HI:
assert(size == 4);
val = s->root >> 32;
val = vtd_get_quad_raw(s, DMAR_RTADDR_REG) >> 32;
break;
/* Invalidation Queue Address Register, 64-bit */
+1
View File
@@ -479,6 +479,7 @@ typedef struct VTDRootEntry VTDRootEntry;
#define VTD_PASID_ENTRY_FPD (1ULL << 1) /* Fault Processing Disable */
/* PASID Granular Translation Type Mask */
#define VTD_PASID_ENTRY_P 1ULL
#define VTD_SM_PASID_ENTRY_PGTT (7ULL << 6)
#define VTD_SM_PASID_ENTRY_FLT (1ULL << 6)
#define VTD_SM_PASID_ENTRY_SLT (2ULL << 6)
-1
View File
@@ -425,7 +425,6 @@ static void pc_i440fx_5_0_machine_options(MachineClass *m)
m->alias = "pc";
m->is_default = 1;
pcmc->default_cpu_version = 1;
compat_props_add(m->compat_props, hw_compat_4_2, hw_compat_4_2_len);
}
DEFINE_I440FX_MACHINE(v5_0, "pc-i440fx-5.0", NULL,
-1
View File
@@ -354,7 +354,6 @@ static void pc_q35_5_0_machine_options(MachineClass *m)
pc_q35_machine_options(m);
m->alias = "q35";
pcmc->default_cpu_version = 1;
compat_props_add(m->compat_props, hw_compat_4_2, hw_compat_4_2_len);
}
DEFINE_Q35_MACHINE(v5_0, "pc-q35-5.0", NULL,
+3 -2
View File
@@ -280,6 +280,7 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOInput *vinput = VIRTIO_INPUT(dev);
Error *local_err = NULL;
if (vic->unrealize) {
@@ -289,8 +290,8 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
return;
}
}
virtio_del_queue(vdev, 0);
virtio_del_queue(vdev, 1);
virtio_delete_queue(vinput->evt);
virtio_delete_queue(vinput->sts);
virtio_cleanup(vdev);
}
+2 -1
View File
@@ -3102,7 +3102,8 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
for (i = 0; i < max_queues; i++) {
virtio_net_del_queue(n, i);
}
/* delete also control vq */
virtio_del_queue(vdev, max_queues * 2);
qemu_announce_timer_del(&n->announce_timer, false);
g_free(n->vqs);
qemu_del_nic(n->nic);
+7 -18
View File
@@ -106,7 +106,7 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
return ret;
}
void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, unsigned len)
{
PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
@@ -115,28 +115,21 @@ void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
return;
}
PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
__func__, pci_dev->name, config_addr, val, len);
pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
val, len);
}
uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
uint32_t pci_data_read(PCIBus *s, uint32_t addr, unsigned len)
{
PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
uint32_t val;
if (!pci_dev) {
return ~0x0;
}
val = pci_host_config_read_common(pci_dev, config_addr,
PCI_CONFIG_SPACE_SIZE, len);
PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
__func__, pci_dev->name, config_addr, val, len);
return val;
return pci_host_config_read_common(pci_dev, config_addr,
PCI_CONFIG_SPACE_SIZE, len);
}
static void pci_host_config_write(void *opaque, hwaddr addr,
@@ -167,8 +160,7 @@ static void pci_host_data_write(void *opaque, hwaddr addr,
uint64_t val, unsigned len)
{
PCIHostState *s = opaque;
PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n",
addr, len, (unsigned)val);
if (s->config_reg & (1u << 31))
pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
}
@@ -177,14 +169,11 @@ static uint64_t pci_host_data_read(void *opaque,
hwaddr addr, unsigned len)
{
PCIHostState *s = opaque;
uint32_t val;
if (!(s->config_reg & (1U << 31))) {
return 0xffffffff;
}
val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
PCI_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
addr, len, val);
return val;
return pci_data_read(s->bus, s->config_reg | (addr & 3), len);
}
const MemoryRegionOps pci_host_conf_le_ops = {
+2
View File
@@ -275,6 +275,8 @@ static Property vhost_scsi_properties[] = {
DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
128),
DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSICommon, conf.seg_max_adjust,
true),
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
0xFFFF),
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),

Some files were not shown because too many files have changed in this diff Show More