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

virtio, pc, pci: features, fixes, cleanups

virtio-pmem support.
libvhost user mq support.
A bunch of fixes all over the place.

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

# gpg: Signature made Thu 04 Jul 2019 22:00:49 BST
# gpg:                using RSA key 281F0DB8D28D5469
# 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: (22 commits)
  docs: avoid vhost-user-net specifics in multiqueue section
  libvhost-user: implement VHOST_USER_PROTOCOL_F_MQ
  libvhost-user: support many virtqueues
  libvhost-user: add vmsg_set_reply_u64() helper
  pc: Move compat_apic_id_mode variable to PCMachineClass
  virtio: Don't change "started" flag on virtio_vmstate_change()
  virtio: Make sure we get correct state of device on handle_aio_output()
  virtio: Set "start_on_kick" on virtio_set_features()
  virtio: Set "start_on_kick" for legacy devices
  virtio: add "use-started" property
  virtio-pci: fix missing device properties
  pc: Support for virtio-pmem-pci
  numa: Handle virtio-pmem in NUMA stats
  hmp: Handle virtio-pmem when printing memory device infos
  virtio-pci: Proxy for virtio-pmem
  virtio-pmem: sync linux headers
  virtio-pci: Allow to specify additional interfaces for the base type
  virtio-pmem: add virtio device
  pcie: minor cleanups for slot control/status
  pcie: work around for racy guest init
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2019-07-05 09:51:50 +01:00
36 changed files with 843 additions and 161 deletions
+9 -3
View File
@@ -131,18 +131,24 @@ static void vug_watch(VuDev *dev, int condition, void *data)
}
}
void
vug_init(VugDev *dev, int socket,
bool
vug_init(VugDev *dev, uint16_t max_queues, int socket,
vu_panic_cb panic, const VuDevIface *iface)
{
g_assert(dev);
g_assert(iface);
vu_init(&dev->parent, socket, panic, set_watch, remove_watch, iface);
if (!vu_init(&dev->parent, max_queues, socket, panic, set_watch,
remove_watch, iface)) {
return false;
}
dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL,
(GDestroyNotify) g_source_destroy);
dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL);
return true;
}
void
+1 -1
View File
@@ -25,7 +25,7 @@ typedef struct VugDev {
GSource *src;
} VugDev;
void vug_init(VugDev *dev, int socket,
bool vug_init(VugDev *dev, uint16_t max_queues, int socket,
vu_panic_cb panic, const VuDevIface *iface);
void vug_deinit(VugDev *dev);
+41 -25
View File
@@ -216,6 +216,15 @@ vmsg_close_fds(VhostUserMsg *vmsg)
}
}
/* Set reply payload.u64 and clear request flags and fd_num */
static void vmsg_set_reply_u64(VhostUserMsg *vmsg, uint64_t val)
{
vmsg->flags = 0; /* defaults will be set by vu_send_reply() */
vmsg->size = sizeof(vmsg->payload.u64);
vmsg->payload.u64 = val;
vmsg->fd_num = 0;
}
/* A test to see if we have userfault available */
static bool
have_userfault(void)
@@ -484,9 +493,9 @@ vu_get_features_exec(VuDev *dev, VhostUserMsg *vmsg)
static void
vu_set_enable_all_rings(VuDev *dev, bool enabled)
{
int i;
uint16_t i;
for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
for (i = 0; i < dev->max_queues; i++) {
dev->vq[i].enable = enabled;
}
}
@@ -907,7 +916,7 @@ vu_check_queue_msg_file(VuDev *dev, VhostUserMsg *vmsg)
{
int index = vmsg->payload.u64 & VHOST_USER_VRING_IDX_MASK;
if (index >= VHOST_MAX_NR_VIRTQUEUE) {
if (index >= dev->max_queues) {
vmsg_close_fds(vmsg);
vu_panic(dev, "Invalid queue index: %u", index);
return false;
@@ -1151,7 +1160,8 @@ vu_set_vring_err_exec(VuDev *dev, VhostUserMsg *vmsg)
static bool
vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg)
{
uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD |
uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_MQ |
1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD |
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ |
1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER |
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD;
@@ -1168,10 +1178,7 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg)
features |= dev->iface->get_protocol_features(dev);
}
vmsg->payload.u64 = features;
vmsg->size = sizeof(vmsg->payload.u64);
vmsg->fd_num = 0;
vmsg_set_reply_u64(vmsg, features);
return true;
}
@@ -1194,8 +1201,8 @@ vu_set_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg)
static bool
vu_get_queue_num_exec(VuDev *dev, VhostUserMsg *vmsg)
{
DPRINT("Function %s() not implemented yet.\n", __func__);
return false;
vmsg_set_reply_u64(vmsg, dev->max_queues);
return true;
}
static bool
@@ -1207,7 +1214,7 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg)
DPRINT("State.index: %d\n", index);
DPRINT("State.enable: %d\n", enable);
if (index >= VHOST_MAX_NR_VIRTQUEUE) {
if (index >= dev->max_queues) {
vu_panic(dev, "Invalid vring_enable index: %u", index);
return false;
}
@@ -1307,17 +1314,14 @@ out:
static bool
vu_set_postcopy_listen(VuDev *dev, VhostUserMsg *vmsg)
{
vmsg->payload.u64 = -1;
vmsg->size = sizeof(vmsg->payload.u64);
if (dev->nregions) {
vu_panic(dev, "Regions already registered at postcopy-listen");
vmsg_set_reply_u64(vmsg, -1);
return true;
}
dev->postcopy_listening = true;
vmsg->flags = VHOST_USER_VERSION | VHOST_USER_REPLY_MASK;
vmsg->payload.u64 = 0; /* Success */
vmsg_set_reply_u64(vmsg, 0);
return true;
}
@@ -1332,10 +1336,7 @@ vu_set_postcopy_end(VuDev *dev, VhostUserMsg *vmsg)
DPRINT("%s: Done close\n", __func__);
}
vmsg->fd_num = 0;
vmsg->payload.u64 = 0;
vmsg->size = sizeof(vmsg->payload.u64);
vmsg->flags = VHOST_USER_VERSION | VHOST_USER_REPLY_MASK;
vmsg_set_reply_u64(vmsg, 0);
DPRINT("%s: exit\n", __func__);
return true;
}
@@ -1582,7 +1583,7 @@ vu_deinit(VuDev *dev)
}
dev->nregions = 0;
for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
for (i = 0; i < dev->max_queues; i++) {
VuVirtq *vq = &dev->vq[i];
if (vq->call_fd != -1) {
@@ -1627,18 +1628,23 @@ vu_deinit(VuDev *dev)
if (dev->sock != -1) {
close(dev->sock);
}
free(dev->vq);
dev->vq = NULL;
}
void
bool
vu_init(VuDev *dev,
uint16_t max_queues,
int socket,
vu_panic_cb panic,
vu_set_watch_cb set_watch,
vu_remove_watch_cb remove_watch,
const VuDevIface *iface)
{
int i;
uint16_t i;
assert(max_queues > 0);
assert(socket >= 0);
assert(set_watch);
assert(remove_watch);
@@ -1654,18 +1660,28 @@ vu_init(VuDev *dev,
dev->iface = iface;
dev->log_call_fd = -1;
dev->slave_fd = -1;
for (i = 0; i < VHOST_MAX_NR_VIRTQUEUE; i++) {
dev->max_queues = max_queues;
dev->vq = malloc(max_queues * sizeof(dev->vq[0]));
if (!dev->vq) {
DPRINT("%s: failed to malloc virtqueues\n", __func__);
return false;
}
for (i = 0; i < max_queues; i++) {
dev->vq[i] = (VuVirtq) {
.call_fd = -1, .kick_fd = -1, .err_fd = -1,
.notification = true,
};
}
return true;
}
VuVirtq *
vu_get_queue(VuDev *dev, int qidx)
{
assert(qidx < VHOST_MAX_NR_VIRTQUEUE);
assert(qidx < dev->max_queues);
return &dev->vq[qidx];
}
+7 -3
View File
@@ -25,7 +25,6 @@
#define VHOST_USER_F_PROTOCOL_FEATURES 30
#define VHOST_LOG_PAGE 4096
#define VHOST_MAX_NR_VIRTQUEUE 8
#define VIRTQUEUE_MAX_SIZE 1024
#define VHOST_MEMORY_MAX_NREGIONS 8
@@ -353,7 +352,7 @@ struct VuDev {
int sock;
uint32_t nregions;
VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS];
VuVirtq vq[VHOST_MAX_NR_VIRTQUEUE];
VuVirtq *vq;
VuDevInflightInfo inflight_info;
int log_call_fd;
int slave_fd;
@@ -362,6 +361,7 @@ struct VuDev {
uint64_t features;
uint64_t protocol_features;
bool broken;
uint16_t max_queues;
/* @set_watch: add or update the given fd to the watch set,
* call cb when condition is met */
@@ -391,6 +391,7 @@ typedef struct VuVirtqElement {
/**
* vu_init:
* @dev: a VuDev context
* @max_queues: maximum number of virtqueues
* @socket: the socket connected to vhost-user master
* @panic: a panic callback
* @set_watch: a set_watch callback
@@ -398,8 +399,11 @@ typedef struct VuVirtqElement {
* @iface: a VuDevIface structure with vhost-user device callbacks
*
* Intializes a VuDev vhost-user context.
*
* Returns: true on success, false on failure.
**/
void vu_init(VuDev *dev,
bool vu_init(VuDev *dev,
uint16_t max_queues,
int socket,
vu_panic_cb panic,
vu_set_watch_cb set_watch,
+9 -7
View File
@@ -25,6 +25,10 @@
#include <sys/ioctl.h>
#endif
enum {
VHOST_USER_BLK_MAX_QUEUES = 8,
};
struct virtio_blk_inhdr {
unsigned char status;
};
@@ -334,12 +338,6 @@ static void vub_process_vq(VuDev *vu_dev, int idx)
VuVirtq *vq;
int ret;
if ((idx < 0) || (idx >= VHOST_MAX_NR_VIRTQUEUE)) {
fprintf(stderr, "VQ Index out of range: %d\n", idx);
vub_panic_cb(vu_dev, NULL);
return;
}
gdev = container_of(vu_dev, VugDev, parent);
vdev_blk = container_of(gdev, VubDev, parent);
assert(vdev_blk);
@@ -631,7 +629,11 @@ int main(int argc, char **argv)
vdev_blk->enable_ro = true;
}
vug_init(&vdev_blk->parent, csock, vub_panic_cb, &vub_iface);
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_main_loop_run(vdev_blk->loop);
+8 -1
View File
@@ -25,6 +25,10 @@
#include "virgl.h"
#include "vugbm.h"
enum {
VHOST_USER_GPU_MAX_QUEUES = 2,
};
struct virtio_gpu_simple_resource {
uint32_t resource_id;
uint32_t width;
@@ -1169,7 +1173,10 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
vug_init(&g.dev, fd, vg_panic, &vuiface);
if (!vug_init(&g.dev, VHOST_USER_GPU_MAX_QUEUES, fd, vg_panic, &vuiface)) {
g_printerr("Failed to initialize libvhost-user-glib.\n");
exit(EXIT_FAILURE);
}
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
+10 -1
View File
@@ -17,6 +17,10 @@
#include "standard-headers/linux/virtio_input.h"
#include "qapi/error.h"
enum {
VHOST_USER_INPUT_MAX_QUEUES = 2,
};
typedef struct virtio_input_event virtio_input_event;
typedef struct virtio_input_config virtio_input_config;
@@ -384,7 +388,12 @@ main(int argc, char *argv[])
g_printerr("Invalid vhost-user socket.\n");
exit(EXIT_FAILURE);
}
vug_init(&vi.dev, fd, vi_panic, &vuiface);
if (!vug_init(&vi.dev, VHOST_USER_INPUT_MAX_QUEUES, fd, vi_panic,
&vuiface)) {
g_printerr("Failed to initialize libvhost-user-glib.\n");
exit(EXIT_FAILURE);
}
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
+9 -12
View File
@@ -19,6 +19,10 @@
#define VUS_ISCSI_INITIATOR "iqn.2016-11.com.nutanix:vhost-user-scsi"
enum {
VHOST_USER_SCSI_MAX_QUEUES = 8,
};
typedef struct VusIscsiLun {
struct iscsi_context *iscsi_ctx;
int iscsi_lun;
@@ -231,11 +235,6 @@ static void vus_proc_req(VuDev *vu_dev, int idx)
gdev = container_of(vu_dev, VugDev, parent);
vdev_scsi = container_of(gdev, VusDev, parent);
if (idx < 0 || idx >= VHOST_MAX_NR_VIRTQUEUE) {
g_warning("VQ Index out of range: %d", idx);
vus_panic_cb(vu_dev, NULL);
return;
}
vq = vu_get_queue(vu_dev, idx);
if (!vq) {
@@ -295,12 +294,6 @@ static void vus_queue_set_started(VuDev *vu_dev, int idx, bool started)
assert(vu_dev);
if (idx < 0 || idx >= VHOST_MAX_NR_VIRTQUEUE) {
g_warning("VQ Index out of range: %d", idx);
vus_panic_cb(vu_dev, NULL);
return;
}
vq = vu_get_queue(vu_dev, idx);
if (idx == 0 || idx == 1) {
@@ -398,7 +391,11 @@ int main(int argc, char **argv)
goto err;
}
vug_init(&vdev_scsi->parent, csock, vus_panic_cb, &vus_iface);
if (!vug_init(&vdev_scsi->parent, VHOST_USER_SCSI_MAX_QUEUES, csock,
vus_panic_cb, &vus_iface)) {
g_printerr("Failed to initialize libvhost-user-glib\n");
goto err;
}
g_main_loop_run(vdev_scsi->loop);
+11 -10
View File
@@ -324,19 +324,20 @@ must support changing some configuration aspects on the fly.
Multiple queue support
----------------------
Multiple queue is treated as a protocol extension, hence the slave has
to implement protocol features first. The multiple queues feature is
supported only when the protocol feature ``VHOST_USER_PROTOCOL_F_MQ``
(bit 0) is set.
Multiple queue support allows the slave to advertise the maximum number of
queues. This is treated as a protocol extension, hence the slave has to
implement protocol features first. The multiple queues feature is supported
only when the protocol feature ``VHOST_USER_PROTOCOL_F_MQ`` (bit 0) is set.
The max number of queue pairs the slave supports can be queried with
message ``VHOST_USER_GET_QUEUE_NUM``. Master should stop when the
number of requested queues is bigger than that.
The max number of queues the slave supports can be queried with message
``VHOST_USER_GET_QUEUE_NUM``. Master should stop when the number of requested
queues is bigger than that.
As all queues share one connection, the master uses a unique index for each
queue in the sent message to identify a specified queue. One queue pair
is enabled initially. More queues are enabled dynamically, by sending
message ``VHOST_USER_SET_VRING_ENABLE``.
queue in the sent message to identify a specified queue.
The master enables queues by sending message ``VHOST_USER_SET_VRING_ENABLE``.
vhost-user-net has historically automatically enabled the first queue pair.
Migration
---------
+2 -2
View File
@@ -191,7 +191,7 @@ static void vhost_user_blk_stop(VirtIODevice *vdev)
static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserBlk *s = VHOST_USER_BLK(vdev);
bool should_start = vdev->started;
bool should_start = virtio_device_started(vdev, status);
int ret;
if (!vdev->vm_running) {
@@ -317,7 +317,7 @@ static int vhost_user_blk_connect(DeviceState *dev)
}
/* restore vhost state */
if (vdev->started) {
if (virtio_device_started(vdev, vdev->status)) {
ret = vhost_user_blk_start(vdev);
if (ret < 0) {
error_report("vhost-user-blk: vhost start failed: %s",
+1
View File
@@ -30,6 +30,7 @@ GlobalProperty hw_compat_4_0[] = {
{ "bochs-display", "edid", "false" },
{ "virtio-vga", "edid", "false" },
{ "virtio-gpu-pci", "edid", "false" },
{ "virtio-device", "use-started", "false" },
};
const size_t hw_compat_4_0_len = G_N_ELEMENTS(hw_compat_4_0);
+12 -12
View File
@@ -533,6 +533,7 @@ static void numa_stat_memory_devices(NumaNodeMem node_mem[])
MemoryDeviceInfoList *info_list = qmp_memory_device_list();
MemoryDeviceInfoList *info;
PCDIMMDeviceInfo *pcdimm_info;
VirtioPMEMDeviceInfo *vpi;
for (info = info_list; info; info = info->next) {
MemoryDeviceInfo *value = info->value;
@@ -540,22 +541,21 @@ static void numa_stat_memory_devices(NumaNodeMem node_mem[])
if (value) {
switch (value->type) {
case MEMORY_DEVICE_INFO_KIND_DIMM:
pcdimm_info = value->u.dimm.data;
break;
case MEMORY_DEVICE_INFO_KIND_NVDIMM:
pcdimm_info = value->u.nvdimm.data;
break;
default:
pcdimm_info = NULL;
break;
}
if (pcdimm_info) {
pcdimm_info = value->type == MEMORY_DEVICE_INFO_KIND_DIMM ?
value->u.dimm.data : value->u.nvdimm.data;
node_mem[pcdimm_info->node].node_mem += pcdimm_info->size;
node_mem[pcdimm_info->node].node_plugged_mem +=
pcdimm_info->size;
break;
case MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM:
vpi = value->u.virtio_pmem.data;
/* TODO: once we support numa, assign to right node */
node_mem[0].node_mem += vpi->size;
node_mem[0].node_plugged_mem += vpi->size;
break;
default:
g_assert_not_reached();
}
}
}
+1
View File
@@ -30,6 +30,7 @@ config PC
# For ACPI builder:
select SERIAL_ISA
select ACPI_VMGENID
select VIRTIO_PMEM_SUPPORTED
config PC_PCI
bool
+80 -14
View File
@@ -79,6 +79,8 @@
#include "hw/i386/intel_iommu.h"
#include "hw/net/ne2000-isa.h"
#include "standard-headers/asm-x86/bootparam.h"
#include "hw/virtio/virtio-pmem-pci.h"
#include "hw/mem/memory-device.h"
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
@@ -913,14 +915,6 @@ bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length)
return false;
}
/* Enables contiguous-apic-ID mode, for compatibility */
static bool compat_apic_id_mode;
void enable_compat_apic_id_mode(void)
{
compat_apic_id_mode = true;
}
/* Calculates initial APIC ID for a specific CPU index
*
* Currently we need to be able to calculate the APIC ID from the CPU index
@@ -928,13 +922,15 @@ void enable_compat_apic_id_mode(void)
* no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
* all CPUs up to max_cpus.
*/
static uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index)
static uint32_t x86_cpu_apic_id_from_index(PCMachineState *pcms,
unsigned int cpu_index)
{
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
uint32_t correct_id;
static bool warned;
correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index);
if (compat_apic_id_mode) {
if (pcmc->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");
@@ -1533,7 +1529,8 @@ static void pc_new_cpu(const char *typename, int64_t apic_id, Error **errp)
void pc_hot_add_cpu(const int64_t id, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
int64_t apic_id = x86_cpu_apic_id_from_index(id);
PCMachineState *pcms = PC_MACHINE(ms);
int64_t apic_id = x86_cpu_apic_id_from_index(pcms, id);
Error *local_err = NULL;
if (id < 0) {
@@ -1569,7 +1566,7 @@ void pc_cpus_init(PCMachineState *pcms)
*
* This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init().
*/
pcms->apic_id_limit = x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
pcms->apic_id_limit = x86_cpu_apic_id_from_index(pcms, max_cpus - 1) + 1;
possible_cpus = mc->possible_cpu_arch_ids(ms);
for (i = 0; i < smp_cpus; i++) {
pc_new_cpu(possible_cpus->cpus[i].type, possible_cpus->cpus[i].arch_id,
@@ -2395,6 +2392,65 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
numa_cpu_pre_plug(cpu_slot, dev, errp);
}
static void pc_virtio_pmem_pci_pre_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
HotplugHandler *hotplug_dev2 = qdev_get_bus_hotplug_handler(dev);
Error *local_err = NULL;
if (!hotplug_dev2) {
/*
* Without a bus hotplug handler, we cannot control the plug/unplug
* order. This should never be the case on x86, however better add
* a safety net.
*/
error_setg(errp, "virtio-pmem-pci not supported on this bus.");
return;
}
/*
* First, see if we can plug this memory device at all. If that
* succeeds, branch of to the actual hotplug handler.
*/
memory_device_pre_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev), NULL,
&local_err);
if (!local_err) {
hotplug_handler_pre_plug(hotplug_dev2, dev, &local_err);
}
error_propagate(errp, local_err);
}
static void pc_virtio_pmem_pci_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
HotplugHandler *hotplug_dev2 = qdev_get_bus_hotplug_handler(dev);
Error *local_err = NULL;
/*
* Plug the memory device first and then branch off to the actual
* hotplug handler. If that one fails, we can easily undo the memory
* device bits.
*/
memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
hotplug_handler_plug(hotplug_dev2, dev, &local_err);
if (local_err) {
memory_device_unplug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
}
error_propagate(errp, local_err);
}
static void pc_virtio_pmem_pci_unplug_request(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
/* We don't support virtio pmem hot unplug */
error_setg(errp, "virtio pmem device unplug not supported.");
}
static void pc_virtio_pmem_pci_unplug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
/* We don't support virtio pmem hot unplug */
}
static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -2402,6 +2458,8 @@ static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
pc_memory_pre_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
pc_cpu_pre_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
pc_virtio_pmem_pci_pre_plug(hotplug_dev, dev, errp);
}
}
@@ -2412,6 +2470,8 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
pc_memory_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
pc_cpu_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
pc_virtio_pmem_pci_plug(hotplug_dev, dev, errp);
}
}
@@ -2422,6 +2482,8 @@ static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
pc_memory_unplug_request(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
pc_cpu_unplug_request_cb(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
pc_virtio_pmem_pci_unplug_request(hotplug_dev, dev, errp);
} else {
error_setg(errp, "acpi: device unplug request for not supported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -2435,6 +2497,8 @@ static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
pc_memory_unplug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
pc_cpu_unplug_cb(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
pc_virtio_pmem_pci_unplug(hotplug_dev, dev, errp);
} else {
error_setg(errp, "acpi: device unplug for not supported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -2445,7 +2509,8 @@ static HotplugHandler *pc_get_hotplug_handler(MachineState *machine,
DeviceState *dev)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI)) {
return HOTPLUG_HANDLER(machine);
}
@@ -2660,6 +2725,7 @@ static int64_t pc_get_default_cpu_node_id(const MachineState *ms, int idx)
static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms)
{
PCMachineState *pcms = PC_MACHINE(ms);
int i;
if (ms->possible_cpus) {
@@ -2679,7 +2745,7 @@ static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms)
ms->possible_cpus->cpus[i].type = ms->cpu_type;
ms->possible_cpus->cpus[i].vcpus_count = 1;
ms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(i);
ms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(pcms, i);
x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id,
smp_cores, smp_threads, &topo);
ms->possible_cpus->cpus[i].props.has_socket_id = true;
+2 -1
View File
@@ -358,7 +358,6 @@ static void pc_compat_1_4_fn(MachineState *machine)
static void pc_compat_1_3(MachineState *machine)
{
pc_compat_1_4_fn(machine);
enable_compat_apic_id_mode();
}
/* PC compat function for pc-0.14 to pc-1.2 */
@@ -708,6 +707,7 @@ DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4_fn,
static void pc_i440fx_1_3_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
static GlobalProperty compat[] = {
PC_CPU_MODEL_IDS("1.3.0")
{ "usb-tablet", "usb_version", "1" },
@@ -718,6 +718,7 @@ static void pc_i440fx_1_3_machine_options(MachineClass *m)
pc_i440fx_1_4_machine_options(m);
m->hw_version = "1.3.0";
pcmc->compat_apic_id_mode = true;
compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
+4 -1
View File
@@ -31,10 +31,13 @@ static void rp_write_config(PCIDevice *d, uint32_t address,
{
uint32_t root_cmd =
pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
uint16_t slt_ctl, slt_sta;
pcie_cap_slot_get(d, &slt_ctl, &slt_sta);
pci_bridge_write_config(d, address, val, len);
rp_aer_vector_update(d);
pcie_cap_slot_write_config(d, address, val, len);
pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);
pcie_aer_write_config(d, address, val, len);
pcie_aer_root_write_config(d, address, val, len, root_cmd);
}
+4 -1
View File
@@ -41,9 +41,12 @@
static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
uint32_t val, int len)
{
uint16_t slt_ctl, slt_sta;
pcie_cap_slot_get(d, &slt_sta, &slt_ctl);
pci_bridge_write_config(d, address, val, len);
pcie_cap_flr_write_config(d, address, val, len);
pcie_cap_slot_write_config(d, address, val, len);
pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);
pcie_aer_write_config(d, address, val, len);
}
+37 -3
View File
@@ -383,7 +383,7 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
{
/* Minor optimization: if nothing changed - no event is needed. */
if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
PCI_EXP_SLTSTA, event)) {
PCI_EXP_SLTSTA, event) == event) {
return;
}
hotplug_event_notify(dev);
@@ -594,7 +594,16 @@ void pcie_cap_slot_reset(PCIDevice *dev)
hotplug_event_update_event_status(dev);
}
void pcie_cap_slot_get(PCIDevice *dev, uint16_t *slt_ctl, uint16_t *slt_sta)
{
uint32_t pos = dev->exp.exp_cap;
uint8_t *exp_cap = dev->config + pos;
*slt_ctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
*slt_sta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
}
void pcie_cap_slot_write_config(PCIDevice *dev,
uint16_t old_slt_ctl, uint16_t old_slt_sta,
uint32_t addr, uint32_t val, int len)
{
uint32_t pos = dev->exp.exp_cap;
@@ -602,6 +611,25 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
/*
* Guests tend to clears all bits during init.
* If they clear bits that weren't set this is racy and will lose events:
* not a big problem for manual button presses, but a problem for us.
* As a work-around, detect this and revert status to what it was
* before the write.
*
* Note: in theory this can be detected as a duplicate button press
* which cancels the previous press. Does not seem to happen in
* practice as guests seem to only have this bug during init.
*/
#define PCIE_SLOT_EVENTS (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | \
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | \
PCI_EXP_SLTSTA_CC)
if (val & ~old_slt_sta & PCIE_SLOT_EVENTS) {
sltsta = (sltsta & ~PCIE_SLOT_EVENTS) | (old_slt_sta & PCIE_SLOT_EVENTS);
pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
}
hotplug_event_clear(dev);
}
@@ -619,11 +647,17 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
}
/*
* If the slot is polulated, power indicator is off and power
* If the slot is populated, power indicator is off and power
* controller is off, it is safe to detach the devices.
*
* Note: don't detach if condition was already true:
* this is a work around for guests that overwrite
* control of powered off slots before powering them on.
*/
if ((sltsta & PCI_EXP_SLTSTA_PDS) && (val & PCI_EXP_SLTCTL_PCC) &&
((val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF)) {
(val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF &&
(!(old_slt_ctl & PCI_EXP_SLTCTL_PCC) ||
(old_slt_ctl & PCI_EXP_SLTCTL_PIC_OFF) != PCI_EXP_SLTCTL_PIC_OFF)) {
PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
pcie_unplug_device, NULL);
+10
View File
@@ -29,3 +29,13 @@ config VIRTIO_CRYPTO
bool
default y
depends on VIRTIO
config VIRTIO_PMEM_SUPPORTED
bool
config VIRTIO_PMEM
bool
default y
depends on VIRTIO
depends on VIRTIO_PMEM_SUPPORTED
select MEM_DEVICE
+2
View File
@@ -12,6 +12,8 @@ common-obj-$(CONFIG_VIRTIO_MMIO) += virtio-mmio.o
obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon.o
obj-$(CONFIG_VIRTIO_CRYPTO) += virtio-crypto.o
obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-pci.o
obj-$(CONFIG_VIRTIO_PMEM) += virtio-pmem.o
common-obj-$(call land,$(CONFIG_VIRTIO_PMEM),$(CONFIG_VIRTIO_PCI)) += virtio-pmem-pci.o
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
ifeq ($(CONFIG_VIRTIO_PCI),y)

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