Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into sta…
Browse files Browse the repository at this point in the history
…ging

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>
  • Loading branch information
pm215 committed Oct 29, 2015
2 parents 331c5e2 + 3f1e147 commit 7bc8e0c
Show file tree
Hide file tree
Showing 22 changed files with 1,276 additions and 95 deletions.
8 changes: 5 additions & 3 deletions hw/acpi/memory_hotplug.c
Expand Up @@ -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;
}

Expand Down
5 changes: 1 addition & 4 deletions hw/block/virtio-blk.c
Expand Up @@ -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;
Expand Down
5 changes: 1 addition & 4 deletions hw/char/virtio-serial-bus.c
Expand Up @@ -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
Expand Down
5 changes: 1 addition & 4 deletions hw/i386/pc.c
Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion hw/i386/pc_piix.c
Expand Up @@ -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);
}

Expand Down
1 change: 0 additions & 1 deletion hw/i386/pc_q35.c
Expand Up @@ -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);
}

Expand Down
15 changes: 6 additions & 9 deletions hw/mem/pc-dimm.c
Expand Up @@ -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());
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
40 changes: 39 additions & 1 deletion hw/pci/pci.c
Expand Up @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -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,
Expand Down
15 changes: 15 additions & 0 deletions hw/pci/pci_host.c
Expand Up @@ -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 */
Expand Down Expand Up @@ -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));
Expand All @@ -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);
Expand Down
39 changes: 26 additions & 13 deletions hw/pci/pcie.c
Expand Up @@ -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));
}

Expand Down Expand Up @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion hw/ppc/spapr.c
Expand Up @@ -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;
}
Expand Down
16 changes: 2 additions & 14 deletions hw/scsi/virtio-scsi.c
Expand Up @@ -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) {
Expand Down

0 comments on commit 7bc8e0c

Please sign in to comment.