mirror of https://gitee.com/openkylin/qemu.git
virtio, pc, memory: fixes+features for 2.5
New features: This enables hotplug for multifunction devices. Patches are very small, so I think it's OK to merge at this stage. There's also some new infrastructure for vhost-user testing not enabled yet so it's harmless to merge. I've reverted the "gap between DIMMs" workaround, as it seems too risky, and applied my own patch in virtio, but not in dataplane code. This means that dataplane is broken for some complex DIMM configurations for now. Waiting for Stefan to review the dataplane fix. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWMeiQAAoJECgfDbjSjVRpPp0IAIBR6oclUoH6SlD/4uzIJxDy ErrLCYCjC01L/hJLfbTfmu3kGyGlDURYZ4/mRz9NjW+gH6n6irRTw8i3+hh7UzJU WhL6+u6UDqW5YoeJGJSmdOAmukuqdToQ8He9MSvwOT81i+XlR+0QP4A4jneyQu9Q LZxVELn+6mAEU4ySK+gtREI/fethsVRQ27Klxn+6k2kBvCqXCyNYh3XQN25sjG1V PrRZcfKgb08vDaMJB0WNnS9+FC9ywkHlYxIWTIJe1AsfLhPH/vF9/XF31O0sINxl F4AS6IMV7KXH3fzO/qVmMkPtqtdq32t9/k8SnHT2d6LOXSWfl9l+EDX9FFHj64U= =ANvi -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging virtio, pc, memory: fixes+features for 2.5 New features: This enables hotplug for multifunction devices. Patches are very small, so I think it's OK to merge at this stage. There's also some new infrastructure for vhost-user testing not enabled yet so it's harmless to merge. I've reverted the "gap between DIMMs" workaround, as it seems too risky, and applied my own patch in virtio, but not in dataplane code. This means that dataplane is broken for some complex DIMM configurations for now. Waiting for Stefan to review the dataplane fix. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Thu 29 Oct 2015 09:36:16 GMT using RSA key ID D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" * remotes/mst/tags/for_upstream: enable multi-function hot-add remove function during multi-function hot-add tests/vhost-user-bridge: add vhost-user bridge application Revert "memhp: extend address auto assignment to support gaps" Revert "pc: memhp: force gaps between DIMM's GPA" virtio: drop virtqueue_map_sg virtio-scsi: convert to virtqueue_map virtio-serial: convert to virtio_map virtio-blk: convert to virtqueue_map virtio: switch to virtio_map virtio: introduce virtio_map mmap-alloc: fix error handling pc: memhp: do not emit inserting event for coldplugged DIMMs vhost-user-test: fix up rhel6 build vhost-user: cleanup msg size math vhost-user: cleanup struct size math Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7bc8e0c967
|
@ -238,10 +238,12 @@ void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
|
|||
|
||||
mdev->dimm = dev;
|
||||
mdev->is_enabled = true;
|
||||
mdev->is_inserting = true;
|
||||
if (dev->hotplugged) {
|
||||
mdev->is_inserting = true;
|
||||
|
||||
/* do ACPI magic */
|
||||
acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS);
|
||||
/* do ACPI magic */
|
||||
acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -839,10 +839,7 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
|
|||
req->next = s->rq;
|
||||
s->rq = req;
|
||||
|
||||
virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
|
||||
req->elem.in_num, 1);
|
||||
virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
|
||||
req->elem.out_num, 0);
|
||||
virtqueue_map(&req->elem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -705,10 +705,7 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id,
|
|||
|
||||
qemu_get_buffer(f, (unsigned char *)&port->elem,
|
||||
sizeof(port->elem));
|
||||
virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
|
||||
port->elem.in_num, 1);
|
||||
virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
|
||||
port->elem.out_num, 1);
|
||||
virtqueue_map(&port->elem);
|
||||
|
||||
/*
|
||||
* Port was throttled on source machine. Let's
|
||||
|
|
|
@ -1616,7 +1616,6 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
|||
HotplugHandlerClass *hhc;
|
||||
Error *local_err = NULL;
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
||||
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
||||
MemoryRegion *mr = ddc->get_memory_region(dimm);
|
||||
|
@ -1632,8 +1631,7 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
pc_dimm_memory_plug(dev, &pcms->hotplug_memory, mr, align,
|
||||
pcmc->inter_dimm_gap, &local_err);
|
||||
pc_dimm_memory_plug(dev, &pcms->hotplug_memory, mr, align, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -1953,7 +1951,6 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
|
|||
PCMachineClass *pcmc = PC_MACHINE_CLASS(oc);
|
||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
||||
|
||||
pcmc->inter_dimm_gap = true;
|
||||
pcmc->get_hotplug_handler = mc->get_hotplug_handler;
|
||||
mc->get_hotplug_handler = pc_get_hotpug_handler;
|
||||
mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
|
||||
|
|
|
@ -487,7 +487,6 @@ static void pc_i440fx_2_4_machine_options(MachineClass *m)
|
|||
m->alias = NULL;
|
||||
m->is_default = 0;
|
||||
pcmc->broken_reserved_end = true;
|
||||
pcmc->inter_dimm_gap = false;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
|
||||
}
|
||||
|
||||
|
|
|
@ -385,7 +385,6 @@ static void pc_q35_2_4_machine_options(MachineClass *m)
|
|||
pc_q35_2_5_machine_options(m);
|
||||
m->alias = NULL;
|
||||
pcmc->broken_reserved_end = true;
|
||||
pcmc->inter_dimm_gap = false;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,8 +33,7 @@ typedef struct pc_dimms_capacity {
|
|||
} pc_dimms_capacity;
|
||||
|
||||
void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
|
||||
MemoryRegion *mr, uint64_t align, bool gap,
|
||||
Error **errp)
|
||||
MemoryRegion *mr, uint64_t align, Error **errp)
|
||||
{
|
||||
int slot;
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
@ -50,7 +49,7 @@ void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
|
|||
|
||||
addr = pc_dimm_get_free_addr(hpms->base,
|
||||
memory_region_size(&hpms->mr),
|
||||
!addr ? NULL : &addr, align, gap,
|
||||
!addr ? NULL : &addr, align,
|
||||
memory_region_size(mr), &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
|
@ -295,8 +294,8 @@ static int pc_dimm_built_list(Object *obj, void *opaque)
|
|||
|
||||
uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
|
||||
uint64_t address_space_size,
|
||||
uint64_t *hint, uint64_t align, bool gap,
|
||||
uint64_t size, Error **errp)
|
||||
uint64_t *hint, uint64_t align, uint64_t size,
|
||||
Error **errp)
|
||||
{
|
||||
GSList *list = NULL, *item;
|
||||
uint64_t new_addr, ret = 0;
|
||||
|
@ -341,15 +340,13 @@ uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (ranges_overlap(dimm->addr, dimm_size, new_addr,
|
||||
size + (gap ? 1 : 0))) {
|
||||
if (ranges_overlap(dimm->addr, dimm_size, new_addr, size)) {
|
||||
if (hint) {
|
||||
DeviceState *d = DEVICE(dimm);
|
||||
error_setg(errp, "address range conflicts with '%s'", d->id);
|
||||
goto out;
|
||||
}
|
||||
new_addr = QEMU_ALIGN_UP(dimm->addr + dimm_size + (gap ? 1 : 0),
|
||||
align);
|
||||
new_addr = QEMU_ALIGN_UP(dimm->addr + dimm_size, align);
|
||||
}
|
||||
}
|
||||
ret = new_addr;
|
||||
|
|
40
hw/pci/pci.c
40
hw/pci/pci.c
|
@ -847,6 +847,9 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
|
|||
PCIConfigWriteFunc *config_write = pc->config_write;
|
||||
Error *local_err = NULL;
|
||||
AddressSpace *dma_as;
|
||||
DeviceState *dev = DEVICE(pci_dev);
|
||||
|
||||
pci_dev->bus = bus;
|
||||
|
||||
if (devfn < 0) {
|
||||
for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
|
||||
|
@ -864,9 +867,17 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
|
|||
PCI_SLOT(devfn), PCI_FUNC(devfn), name,
|
||||
bus->devices[devfn]->name);
|
||||
return NULL;
|
||||
} else if (dev->hotplugged &&
|
||||
pci_get_function_0(pci_dev)) {
|
||||
error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s,"
|
||||
" new func %s cannot be exposed to guest.",
|
||||
PCI_SLOT(devfn),
|
||||
bus->devices[PCI_DEVFN(PCI_SLOT(devfn), 0)]->name,
|
||||
name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pci_dev->bus = bus;
|
||||
pci_dev->devfn = devfn;
|
||||
dma_as = pci_device_iommu_address_space(pci_dev);
|
||||
|
||||
|
@ -2454,6 +2465,33 @@ void pci_bus_get_w64_range(PCIBus *bus, Range *range)
|
|||
pci_for_each_device_under_bus(bus, pci_dev_get_w64, range);
|
||||
}
|
||||
|
||||
static bool pcie_has_upstream_port(PCIDevice *dev)
|
||||
{
|
||||
PCIDevice *parent_dev = pci_bridge_get_device(dev->bus);
|
||||
|
||||
/* Device associated with an upstream port.
|
||||
* As there are several types of these, it's easier to check the
|
||||
* parent device: upstream ports are always connected to
|
||||
* root or downstream ports.
|
||||
*/
|
||||
return parent_dev &&
|
||||
pci_is_express(parent_dev) &&
|
||||
parent_dev->exp.exp_cap &&
|
||||
(pcie_cap_get_type(parent_dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pcie_cap_get_type(parent_dev) == PCI_EXP_TYPE_DOWNSTREAM);
|
||||
}
|
||||
|
||||
PCIDevice *pci_get_function_0(PCIDevice *pci_dev)
|
||||
{
|
||||
if(pcie_has_upstream_port(pci_dev)) {
|
||||
/* With an upstream PCIe port, we only support 1 device at slot 0 */
|
||||
return pci_dev->bus->devices[0];
|
||||
} else {
|
||||
/* Other bus types might support multiple devices at slots 0-31 */
|
||||
return pci_dev->bus->devices[PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 0)];
|
||||
}
|
||||
}
|
||||
|
||||
static const TypeInfo pci_device_type_info = {
|
||||
.name = TYPE_PCI_DEVICE,
|
||||
.parent = TYPE_DEVICE,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* debug PCI */
|
||||
|
@ -52,6 +53,13 @@ void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
|
|||
uint32_t limit, uint32_t val, uint32_t len)
|
||||
{
|
||||
assert(len <= 4);
|
||||
/* non-zero functions are only exposed when function 0 is present,
|
||||
* allowing direct removal of unexposed functions.
|
||||
*/
|
||||
if (pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
trace_pci_cfg_write(pci_dev->name, PCI_SLOT(pci_dev->devfn),
|
||||
PCI_FUNC(pci_dev->devfn), addr, val);
|
||||
pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
|
||||
|
@ -63,6 +71,13 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
|
|||
uint32_t ret;
|
||||
|
||||
assert(len <= 4);
|
||||
/* non-zero functions are only exposed when function 0 is present,
|
||||
* allowing direct removal of unexposed functions.
|
||||
*/
|
||||
if (pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) {
|
||||
return ~0x0;
|
||||
}
|
||||
|
||||
ret = pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
|
||||
trace_pci_cfg_read(pci_dev->name, PCI_SLOT(pci_dev->devfn),
|
||||
PCI_FUNC(pci_dev->devfn), addr, ret);
|
||||
|
|
|
@ -249,25 +249,43 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|||
return;
|
||||
}
|
||||
|
||||
/* TODO: multifunction hot-plug.
|
||||
* Right now, only a device of function = 0 is allowed to be
|
||||
* hot plugged/unplugged.
|
||||
/* To enable multifunction hot-plug, we just ensure the function
|
||||
* 0 added last. When function 0 is added, we set the sltsta and
|
||||
* inform OS via event notification.
|
||||
*/
|
||||
assert(PCI_FUNC(pci_dev->devfn) == 0);
|
||||
if (pci_get_function_0(pci_dev)) {
|
||||
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
||||
PCI_EXP_SLTSTA_PDS);
|
||||
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
|
||||
PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
|
||||
}
|
||||
}
|
||||
|
||||
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
||||
PCI_EXP_SLTSTA_PDS);
|
||||
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
|
||||
PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
|
||||
static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
|
||||
{
|
||||
object_unparent(OBJECT(dev));
|
||||
}
|
||||
|
||||
void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
uint8_t *exp_cap;
|
||||
PCIDevice *pci_dev = PCI_DEVICE(dev);
|
||||
PCIBus *bus = pci_dev->bus;
|
||||
|
||||
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
|
||||
|
||||
/* In case user cancel the operation of multi-function hot-add,
|
||||
* remove the function that is unexposed to guest individually,
|
||||
* without interaction with guest.
|
||||
*/
|
||||
if (pci_dev->devfn &&
|
||||
!bus->devices[0]) {
|
||||
pcie_unplug_device(bus, pci_dev, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev));
|
||||
}
|
||||
|
||||
|
@ -378,11 +396,6 @@ void pcie_cap_slot_reset(PCIDevice *dev)
|
|||
hotplug_event_update_event_status(dev);
|
||||
}
|
||||
|
||||
static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
|
||||
{
|
||||
object_unparent(OBJECT(dev));
|
||||
}
|
||||
|
||||
void pcie_cap_slot_write_config(PCIDevice *dev,
|
||||
uint32_t addr, uint32_t val, int len)
|
||||
{
|
||||
|
|
|
@ -2157,7 +2157,7 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, false, &local_err);
|
||||
pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -205,20 +205,8 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
|
|||
assert(n < vs->conf.num_queues);
|
||||
req = virtio_scsi_init_req(s, vs->cmd_vqs[n]);
|
||||
qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
|
||||
/* TODO: add a way for SCSIBusInfo's load_request to fail,
|
||||
* and fail migration instead of asserting here.
|
||||
* When we do, we might be able to re-enable NDEBUG below.
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#error building with NDEBUG is not supported
|
||||
#endif
|
||||
assert(req->elem.in_num <= ARRAY_SIZE(req->elem.in_sg));
|
||||
assert(req->elem.out_num <= ARRAY_SIZE(req->elem.out_sg));
|
||||
|
||||
virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
|
||||
req->elem.in_num, 1);
|
||||
virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
|
||||
req->elem.out_num, 0);
|
||||
virtqueue_map(&req->elem);
|
||||
|
||||
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
|
||||
sizeof(VirtIOSCSICmdResp) + vs->sense_size) < 0) {
|
||||
|
|
|
@ -201,7 +201,7 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
|
|||
.request = VHOST_USER_SET_LOG_BASE,
|
||||
.flags = VHOST_USER_VERSION,
|
||||
.payload.u64 = base,
|
||||
.size = sizeof(m.payload.u64),
|
||||
.size = sizeof(msg.payload.u64),
|
||||
};
|
||||
|
||||
if (shmfd && log->fd != -1) {
|
||||
|
@ -265,8 +265,8 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
|
|||
return -1;
|
||||
}
|
||||
|
||||
msg.size = sizeof(m.payload.memory.nregions);
|
||||
msg.size += sizeof(m.payload.memory.padding);
|
||||
msg.size = sizeof(msg.payload.memory.nregions);
|
||||
msg.size += sizeof(msg.payload.memory.padding);
|
||||
msg.size += fd_num * sizeof(VhostUserMemoryRegion);
|
||||
|
||||
vhost_user_write(dev, &msg, fds, fd_num);
|
||||
|
@ -281,7 +281,7 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev,
|
|||
.request = VHOST_USER_SET_VRING_ADDR,
|
||||
.flags = VHOST_USER_VERSION,
|
||||
.payload.addr = *addr,
|
||||
.size = sizeof(*addr),
|
||||
.size = sizeof(msg.payload.addr),
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
|
@ -304,7 +304,7 @@ static int vhost_set_vring(struct vhost_dev *dev,
|
|||
.request = request,
|
||||
.flags = VHOST_USER_VERSION,
|
||||
.payload.state = *ring,
|
||||
.size = sizeof(*ring),
|
||||
.size = sizeof(msg.payload.state),
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
|
@ -346,7 +346,7 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
|
|||
.request = VHOST_USER_GET_VRING_BASE,
|
||||
.flags = VHOST_USER_VERSION,
|
||||
.payload.state = *ring,
|
||||
.size = sizeof(*ring),
|
||||
.size = sizeof(msg.payload.state),
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
|
@ -361,7 +361,7 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (msg.size != sizeof(m.payload.state)) {
|
||||
if (msg.size != sizeof(msg.payload.state)) {
|
||||
error_report("Received bad msg size.");
|
||||
return -1;
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ static int vhost_set_vring_file(struct vhost_dev *dev,
|
|||
.request = request,
|
||||
.flags = VHOST_USER_VERSION,
|
||||
.payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK,
|
||||
.size = sizeof(m.payload.u64),
|
||||
.size = sizeof(msg.payload.u64),
|
||||
};
|
||||
|
||||
if (ioeventfd_enabled() && file->fd > 0) {
|
||||
|
@ -413,7 +413,7 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64)
|
|||
.request = request,
|
||||
.flags = VHOST_USER_VERSION,
|
||||
.payload.u64 = u64,
|
||||
.size = sizeof(m.payload.u64),
|
||||
.size = sizeof(msg.payload.u64),
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
|
@ -456,7 +456,7 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (msg.size != sizeof(m.payload.u64)) {
|
||||
if (msg.size != sizeof(msg.payload.u64)) {
|
||||
error_report("Received bad msg size.");
|
||||
return -1;
|
||||
}
|
||||
|
@ -592,7 +592,7 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
|
|||
msg.request = VHOST_USER_SEND_RARP;
|
||||
msg.flags = VHOST_USER_VERSION;
|
||||
memcpy((char *)&msg.payload.u64, mac_addr, 6);
|
||||
msg.size = sizeof(m.payload.u64);
|
||||
msg.size = sizeof(msg.payload.u64);
|
||||
|
||||
err = vhost_user_write(dev, &msg, NULL, 0);
|
||||
return err;
|
||||
|
|
|
@ -448,28 +448,59 @@ int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
|
|||
return in_bytes <= in_total && out_bytes <= out_total;
|
||||
}
|
||||
|
||||
void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
|
||||
size_t num_sg, int is_write)
|
||||
static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
|
||||
unsigned int *num_sg, unsigned int max_size,
|
||||
int is_write)
|
||||
{
|
||||
unsigned int i;
|
||||
hwaddr len;
|
||||
|
||||
if (num_sg > VIRTQUEUE_MAX_SIZE) {
|
||||
error_report("virtio: map attempt out of bounds: %zd > %d",
|
||||
num_sg, VIRTQUEUE_MAX_SIZE);
|
||||
exit(1);
|
||||
}
|
||||
/* Note: this function MUST validate input, some callers
|
||||
* are passing in num_sg values received over the network.
|
||||
*/
|
||||
/* TODO: teach all callers that this can fail, and return failure instead
|
||||
* of asserting here.
|
||||
* When we do, we might be able to re-enable NDEBUG below.
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#error building with NDEBUG is not supported
|
||||
#endif
|
||||
assert(*num_sg <= max_size);
|
||||
|
||||
for (i = 0; i < num_sg; i++) {
|
||||
for (i = 0; i < *num_sg; i++) {
|
||||
len = sg[i].iov_len;
|
||||
sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
|
||||
if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
|
||||
if (!sg[i].iov_base) {
|
||||
error_report("virtio: error trying to map MMIO memory");
|
||||
exit(1);
|
||||
}
|
||||
if (len == sg[i].iov_len) {
|
||||
continue;
|
||||
}
|
||||
if (*num_sg >= max_size) {
|
||||
error_report("virtio: memory split makes iovec too large");
|
||||
exit(1);
|
||||
}
|
||||
memmove(sg + i + 1, sg + i, sizeof(*sg) * (*num_sg - i));
|
||||
memmove(addr + i + 1, addr + i, sizeof(*addr) * (*num_sg - i));
|
||||
assert(len < sg[i + 1].iov_len);
|
||||
sg[i].iov_len = len;
|
||||
addr[i + 1] += len;
|
||||
sg[i + 1].iov_len -= len;
|
||||
++*num_sg;
|
||||
}
|
||||
}
|
||||
|
||||
void virtqueue_map(VirtQueueElement *elem)
|
||||
{
|
||||
virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num,
|
||||
MIN(ARRAY_SIZE(elem->in_sg), ARRAY_SIZE(elem->in_addr)),
|
||||
1);
|
||||
virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num,
|
||||
MIN(ARRAY_SIZE(elem->out_sg), ARRAY_SIZE(elem->out_addr)),
|
||||
0);
|
||||
}
|
||||
|
||||
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
||||
{
|
||||
unsigned int i, head, max;
|
||||
|
@ -531,8 +562,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
|||
} while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max);
|
||||
|
||||
/* Now map what we have collected */
|
||||
virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
|
||||
virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);
|
||||
virtqueue_map(elem);
|
||||
|
||||
elem->index = head;
|
||||
|
||||
|
|
|
@ -60,7 +60,6 @@ struct PCMachineClass {
|
|||
|
||||
/*< public >*/
|
||||
bool broken_reserved_end;
|
||||
bool inter_dimm_gap;
|
||||
HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
|
||||
DeviceState *dev);
|
||||
};
|
||||
|
|
|
@ -83,16 +83,15 @@ typedef struct MemoryHotplugState {
|
|||
|
||||
uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
|
||||
uint64_t address_space_size,
|
||||
uint64_t *hint, uint64_t align, bool gap,
|
||||
uint64_t size, Error **errp);
|
||||
uint64_t *hint, uint64_t align, uint64_t size,
|
||||
Error **errp);
|
||||
|
||||
int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp);
|
||||
|
||||
int qmp_pc_dimm_device_list(Object *obj, void *opaque);
|
||||
uint64_t pc_existing_dimms_capacity(Error **errp);
|
||||
void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
|
||||
MemoryRegion *mr, uint64_t align, bool gap,
|
||||
Error **errp);
|
||||
MemoryRegion *mr, uint64_t align, Error **errp);
|
||||
void pc_dimm_memory_unplug(DeviceState *dev, MemoryHotplugState *hpms,
|
||||
MemoryRegion *mr);
|
||||
#endif
|
||||
|
|
|
@ -397,6 +397,7 @@ void pci_for_each_bus_depth_first(PCIBus *bus,
|
|||
void *(*begin)(PCIBus *bus, void *parent_state),
|
||||
void (*end)(PCIBus *bus, void *state),
|
||||
void *parent_state);
|
||||
PCIDevice *pci_get_function_0(PCIDevice *pci_dev);
|
||||
|
||||
/* Use this wrapper when specific scan order is not required. */
|
||||
static inline
|
||||
|
|
|
@ -151,8 +151,7 @@ void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
|
|||
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len, unsigned int idx);
|
||||
|
||||
void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
|
||||
size_t num_sg, int is_write);
|
||||
void virtqueue_map(VirtQueueElement *elem);
|
||||
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
|
||||
int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
|
||||
unsigned int out_bytes);
|
||||
|
|
|
@ -525,6 +525,7 @@ tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
|
|||
tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y)
|
||||
tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y)
|
||||
tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y)
|
||||
tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o
|
||||
|
||||
ifeq ($(CONFIG_POSIX),y)
|
||||
LIBS += -lutil
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -98,7 +98,7 @@ typedef struct VhostUserMsg {
|
|||
struct vhost_vring_state state;
|
||||
struct vhost_vring_addr addr;
|
||||
VhostUserMemory memory;
|
||||
};
|
||||
} payload;
|
||||
} QEMU_PACKED VhostUserMsg;
|
||||
|
||||
static VhostUserMsg m __attribute__ ((unused));
|
||||
|
@ -242,23 +242,23 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
|
|||
case VHOST_USER_GET_FEATURES:
|
||||
/* send back features to qemu */
|
||||
msg.flags |= VHOST_USER_REPLY_MASK;
|
||||
msg.size = sizeof(m.u64);
|
||||
msg.u64 = 0x1ULL << VHOST_F_LOG_ALL |
|
||||
msg.size = sizeof(m.payload.u64);
|
||||
msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
|
||||
0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
|
||||
p = (uint8_t *) &msg;
|
||||
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
|
||||
break;
|
||||
|
||||
case VHOST_USER_SET_FEATURES:
|
||||
g_assert_cmpint(msg.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
|
||||
g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
|
||||
!=, 0ULL);
|
||||
break;
|
||||
|
||||
case VHOST_USER_GET_PROTOCOL_FEATURES:
|
||||
/* send back features to qemu */
|
||||
msg.flags |= VHOST_USER_REPLY_MASK;
|
||||
msg.size = sizeof(m.u64);
|
||||
msg.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
|
||||
msg.size = sizeof(m.payload.u64);
|
||||
msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
|
||||
p = (uint8_t *) &msg;
|
||||
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
|
||||
break;
|
||||
|
@ -266,15 +266,15 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
|
|||
case VHOST_USER_GET_VRING_BASE:
|
||||
/* send back vring base to qemu */
|
||||
msg.flags |= VHOST_USER_REPLY_MASK;
|
||||
msg.size = sizeof(m.state);
|
||||
msg.state.num = 0;
|
||||
msg.size = sizeof(m.payload.state);
|
||||
msg.payload.state.num = 0;
|
||||
p = (uint8_t *) &msg;
|
||||
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
|
||||
break;
|
||||
|
||||
case VHOST_USER_SET_MEM_TABLE:
|
||||
/* received the mem table */
|
||||
memcpy(&s->memory, &msg.memory, sizeof(msg.memory));
|
||||
memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
|
||||
s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds, G_N_ELEMENTS(s->fds));
|
||||
|
||||
/* signal the test that it can continue */
|
||||
|
|
|
@ -26,7 +26,7 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared)
|
|||
void *ptr1;
|
||||
|
||||
if (ptr == MAP_FAILED) {
|
||||
return NULL;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
/* Make sure align is a power of 2 */
|
||||
|
@ -41,7 +41,7 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared)
|
|||
fd, 0);
|
||||
if (ptr1 == MAP_FAILED) {
|
||||
munmap(ptr, total);
|
||||
return NULL;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
ptr += offset;
|
||||
|
|
Loading…
Reference in New Issue