diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 0b8bc62b99..5464977424 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1912,16 +1912,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, build_piix4_pci_hotplug(dsdt); build_piix4_pci0_int(dsdt); } else { - sb_scope = aml_scope("_SB"); - aml_append(sb_scope, - aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(0xae00), 0x0c)); - aml_append(sb_scope, - aml_operation_region("PCSB", AML_SYSTEM_IO, aml_int(0xae0c), 0x01)); - field = aml_field("PCSB", AML_ANY_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); - aml_append(field, aml_named_field("PCIB", 8)); - aml_append(sb_scope, field); - aml_append(dsdt, sb_scope); - sb_scope = aml_scope("_SB"); dev = aml_device("PCI0"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 7b6d4ea3f3..d93ffc2a15 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1158,13 +1158,23 @@ static void amdvi_realize(DeviceState *dev, Error **err) x86_iommu->type = TYPE_AMD; qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus); object_property_set_bool(OBJECT(&s->pci), true, "realized", err); - s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, - AMDVI_CAPAB_SIZE); - assert(s->capab_offset > 0); - ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE); - assert(ret > 0); - ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE); - assert(ret > 0); + ret = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, + AMDVI_CAPAB_SIZE, err); + if (ret < 0) { + return; + } + s->capab_offset = ret; + + ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, + AMDVI_CAPAB_REG_SIZE, err); + if (ret < 0) { + return; + } + ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, + AMDVI_CAPAB_REG_SIZE, err); + if (ret < 0) { + return; + } /* set up MMIO */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio", diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index a9b59bdce5..88dc042b5c 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1450,10 +1450,7 @@ static uint64_t vtd_iotlb_flush(IntelIOMMUState *s, uint64_t val) return iaig; } -static inline bool vtd_queued_inv_enable_check(IntelIOMMUState *s) -{ - return s->iq_tail == 0; -} +static void vtd_fetch_inv_desc(IntelIOMMUState *s); static inline bool vtd_queued_inv_disable_check(IntelIOMMUState *s) { @@ -1468,16 +1465,24 @@ static void vtd_handle_gcmd_qie(IntelIOMMUState *s, bool en) trace_vtd_inv_qi_enable(en); if (en) { - if (vtd_queued_inv_enable_check(s)) { - s->iq = iqa_val & VTD_IQA_IQA_MASK; - /* 2^(x+8) entries */ - s->iq_size = 1UL << ((iqa_val & VTD_IQA_QS) + 8); - s->qi_enabled = true; - trace_vtd_inv_qi_setup(s->iq, s->iq_size); - /* Ok - report back to driver */ - vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_QIES); - } else { - trace_vtd_err_qi_enable(s->iq_tail); + s->iq = iqa_val & VTD_IQA_IQA_MASK; + /* 2^(x+8) entries */ + s->iq_size = 1UL << ((iqa_val & VTD_IQA_QS) + 8); + s->qi_enabled = true; + trace_vtd_inv_qi_setup(s->iq, s->iq_size); + /* Ok - report back to driver */ + vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_QIES); + + if (s->iq_tail != 0) { + /* + * This is a spec violation but Windows guests are known to set up + * Queued Invalidation this way so we allow the write and process + * Invalidation Descriptors right away. + */ + trace_vtd_warn_invalid_qi_tail(s->iq_tail); + if (!(vtd_get_long_raw(s, DMAR_FSTS_REG) & VTD_FSTS_IQE)) { + vtd_fetch_inv_desc(s); + } } } else { if (vtd_queued_inv_disable_check(s)) { @@ -2332,11 +2337,26 @@ static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu, } } +static int vtd_post_load(void *opaque, int version_id) +{ + IntelIOMMUState *iommu = opaque; + + /* + * Memory regions are dynamically turned on/off depending on + * context entry configurations from the guest. After migration, + * we need to make sure the memory regions are still correct. + */ + vtd_switch_address_space_all(iommu); + + return 0; +} + static const VMStateDescription vtd_vmstate = { .name = "iommu-intel", .version_id = 1, .minimum_version_id = 1, .priority = MIG_PRI_IOMMU, + .post_load = vtd_post_load, .fields = (VMStateField[]) { VMSTATE_UINT64(root, IntelIOMMUState), VMSTATE_UINT64(intr_root, IntelIOMMUState), diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index 87dcbdd51a..9f2615cbe0 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -824,12 +824,13 @@ static void assign_device(AssignedDevice *dev, Error **errp) } } -static void verify_irqchip_in_kernel(Error **errp) +static int verify_irqchip_in_kernel(Error **errp) { if (kvm_irqchip_in_kernel()) { - return; + return -1; } error_setg(errp, "pci-assign requires KVM with in-kernel irqchip enabled"); + return 0; } static int assign_intx(AssignedDevice *dev, Error **errp) @@ -838,7 +839,6 @@ static int assign_intx(AssignedDevice *dev, Error **errp) PCIINTxRoute intx_route; bool intx_host_msi; int r; - Error *local_err = NULL; /* Interrupt PIN 0 means don't use INTx */ if (assigned_dev_pci_read_byte(&dev->dev, PCI_INTERRUPT_PIN) == 0) { @@ -846,9 +846,7 @@ static int assign_intx(AssignedDevice *dev, Error **errp) return 0; } - verify_irqchip_in_kernel(&local_err); - if (local_err) { - error_propagate(errp, local_err); + if (verify_irqchip_in_kernel(errp) < 0) { return -ENOTSUP; } @@ -1234,7 +1232,6 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) AssignedDevice *dev = PCI_ASSIGN(pci_dev); PCIRegion *pci_region = dev->real_device.regions; int ret, pos; - Error *local_err = NULL; /* Clear initial capabilities pointer and status copied from hw */ pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0); @@ -1246,18 +1243,15 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) * MSI capability is the 1st capability in capability config */ pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0); if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) { - verify_irqchip_in_kernel(&local_err); - if (local_err) { - error_propagate(errp, local_err); + if (verify_irqchip_in_kernel(errp) < 0) { return -ENOTSUP; } dev->dev.cap_present |= QEMU_PCI_CAP_MSI; dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI; /* Only 32-bit/no-mask currently supported */ - ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSI, pos, 10, - &local_err); + ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSI, pos, 10, + errp); if (ret < 0) { - error_propagate(errp, local_err); return ret; } pci_dev->msi_cap = pos; @@ -1281,17 +1275,14 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) uint32_t msix_table_entry; uint16_t msix_max; - verify_irqchip_in_kernel(&local_err); - if (local_err) { - error_propagate(errp, local_err); + if (verify_irqchip_in_kernel(errp) < 0) { return -ENOTSUP; } dev->dev.cap_present |= QEMU_PCI_CAP_MSIX; dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX; - ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSIX, pos, 12, - &local_err); + ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSIX, pos, 12, + errp); if (ret < 0) { - error_propagate(errp, local_err); return ret; } pci_dev->msix_cap = pos; @@ -1318,10 +1309,9 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) if (pos) { uint16_t pmc; - ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF, - &local_err); + ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF, + errp); if (ret < 0) { - error_propagate(errp, local_err); return ret; } @@ -1386,10 +1376,9 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) return -EINVAL; } - ret = pci_add_capability2(pci_dev, PCI_CAP_ID_EXP, pos, size, - &local_err); + ret = pci_add_capability(pci_dev, PCI_CAP_ID_EXP, pos, size, + errp); if (ret < 0) { - error_propagate(errp, local_err); return ret; } @@ -1462,10 +1451,9 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) uint32_t status; /* Only expose the minimum, 8 byte capability */ - ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PCIX, pos, 8, - &local_err); + ret = pci_add_capability(pci_dev, PCI_CAP_ID_PCIX, pos, 8, + errp); if (ret < 0) { - error_propagate(errp, local_err); return ret; } @@ -1490,10 +1478,9 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0); if (pos) { /* Direct R/W passthrough */ - ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VPD, pos, 8, - &local_err); + ret = pci_add_capability(pci_dev, PCI_CAP_ID_VPD, pos, 8, + errp); if (ret < 0) { - error_propagate(errp, local_err); return ret; } @@ -1508,10 +1495,9 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) pos += PCI_CAP_LIST_NEXT) { uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS); /* Direct R/W passthrough */ - ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VNDR, pos, len, - &local_err); + ret = pci_add_capability(pci_dev, PCI_CAP_ID_VNDR, pos, len, + errp); if (ret < 0) { - error_propagate(errp, local_err); return ret; } diff --git a/hw/i386/trace-events b/hw/i386/trace-events index 5f111d6dde..42d8a7e27a 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -74,7 +74,7 @@ vtd_err_dmar_slpte_read_error(uint64_t iova, int level) "iova 0x%"PRIx64" level vtd_err_dmar_slpte_perm_error(uint64_t iova, int level, uint64_t slpte, bool is_write) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64" write %d" vtd_err_dmar_slpte_resv_error(uint64_t iova, int level, uint64_t slpte) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64 vtd_err_dmar_translate(uint8_t bus, uint8_t slot, uint8_t func, uint64_t iova) "dev %02x:%02x.%02x iova 0x%"PRIx64 -vtd_err_qi_enable(uint16_t tail) "tail 0x%"PRIx16 +vtd_warn_invalid_qi_tail(uint16_t tail) "tail 0x%"PRIx16 vtd_err_qi_disable(uint16_t head, uint16_t tail, int type) "head 0x%"PRIx16" tail 0x%"PRIx16" last_desc_type %d" vtd_err_qi_tail(uint16_t tail, uint16_t size) "tail 0x%"PRIx16" size 0x%"PRIx16 vtd_err_irte(int index, uint64_t lo, uint64_t hi) "index %d low 0x%"PRIx64" high 0x%"PRIx64 diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 459916977e..989fca5e9f 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -130,7 +130,7 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp) pci_register_bar(dev, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->ahci.mem); - sata_cap_offset = pci_add_capability2(dev, PCI_CAP_ID_SATA, + sata_cap_offset = pci_add_capability(dev, PCI_CAP_ID_SATA, ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE, errp); if (sata_cap_offset < 0) { diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 0e0a1dc888..6c42b4478c 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -47,6 +47,7 @@ #include "e1000e_core.h" #include "trace.h" +#include "qapi/error.h" #define TYPE_E1000E "e1000e" #define E1000E(obj) OBJECT_CHECK(E1000EState, (obj), TYPE_E1000E) @@ -372,22 +373,27 @@ e1000e_gen_dsn(uint8_t *mac) static int e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc) { - int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset, PCI_PM_SIZEOF); + Error *local_err = NULL; + int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset, + PCI_PM_SIZEOF, &local_err); - if (ret >= 0) { - pci_set_word(pdev->config + offset + PCI_PM_PMC, - PCI_PM_CAP_VER_1_1 | - pmc); - - pci_set_word(pdev->wmask + offset + PCI_PM_CTRL, - PCI_PM_CTRL_STATE_MASK | - PCI_PM_CTRL_PME_ENABLE | - PCI_PM_CTRL_DATA_SEL_MASK); - - pci_set_word(pdev->w1cmask + offset + PCI_PM_CTRL, - PCI_PM_CTRL_PME_STATUS); + if (local_err) { + error_report_err(local_err); + return ret; } + pci_set_word(pdev->config + offset + PCI_PM_PMC, + PCI_PM_CAP_VER_1_1 | + pmc); + + pci_set_word(pdev->wmask + offset + PCI_PM_CTRL, + PCI_PM_CTRL_STATE_MASK | + PCI_PM_CTRL_PME_ENABLE | + PCI_PM_CTRL_DATA_SEL_MASK); + + pci_set_word(pdev->w1cmask + offset + PCI_PM_CTRL, + PCI_PM_CTRL_PME_STATUS); + return ret; } diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index 4bf71f2d85..5a4774aab4 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -48,6 +48,7 @@ #include "sysemu/sysemu.h" #include "sysemu/dma.h" #include "qemu/bitops.h" +#include "qapi/error.h" /* QEMU sends frames smaller than 60 bytes to ethernet nics. * Such frames are rejected by real nics and their emulations. @@ -494,7 +495,7 @@ static void eepro100_fcp_interrupt(EEPRO100State * s) } #endif -static void e100_pci_reset(EEPRO100State * s) +static void e100_pci_reset(EEPRO100State *s, Error **errp) { E100PCIDeviceInfo *info = eepro100_get_class(s); uint32_t device = s->device; @@ -570,8 +571,12 @@ static void e100_pci_reset(EEPRO100State * s) /* Power Management Capabilities */ int cfg_offset = 0xdc; int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM, - cfg_offset, PCI_PM_SIZEOF); - assert(r >= 0); + cfg_offset, PCI_PM_SIZEOF, + errp); + if (r < 0) { + return; + } + pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21); #if 0 /* TODO: replace dummy code for power management emulation. */ /* TODO: Power Management Control / Status. */ @@ -1858,12 +1863,17 @@ static void e100_nic_realize(PCIDevice *pci_dev, Error **errp) { EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev); E100PCIDeviceInfo *info = eepro100_get_class(s); + Error *local_err = NULL; TRACE(OTHER, logout("\n")); s->device = info->device; - e100_pci_reset(s); + e100_pci_reset(s, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM, * i82559 and later support 64 or 256 word EEPROM. */ diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 91eddaf93b..5630a9ec44 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -34,8 +34,11 @@ /* previously fixed value */ #define VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE 256 +#define VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE 256 + /* for now, only allow larger queues; with virtio-1, guest can downsize */ #define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE +#define VIRTIO_NET_TX_QUEUE_MIN_SIZE VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE /* * Calculate the number of bytes up to and including the given 'field' of @@ -495,6 +498,24 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, } } +static int virtio_net_max_tx_queue_size(VirtIONet *n) +{ + NetClientState *peer = n->nic_conf.peers.ncs[0]; + + /* + * Backends other than vhost-user don't support max queue size. + */ + if (!peer) { + return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; + } + + if (peer->info->type != NET_CLIENT_DRIVER_VHOST_USER) { + return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; + } + + return VIRTQUEUE_MAX_SIZE; +} + static int peer_attach(VirtIONet *n, int index) { NetClientState *nc = qemu_get_subqueue(n->nic, index); @@ -1508,15 +1529,18 @@ static void virtio_net_add_queue(VirtIONet *n, int index) n->vqs[index].rx_vq = virtio_add_queue(vdev, n->net_conf.rx_queue_size, virtio_net_handle_rx); + if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) { n->vqs[index].tx_vq = - virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer); + virtio_add_queue(vdev, n->net_conf.tx_queue_size, + virtio_net_handle_tx_timer); n->vqs[index].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, virtio_net_tx_timer, &n->vqs[index]); } else { n->vqs[index].tx_vq = - virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh); + virtio_add_queue(vdev, n->net_conf.tx_queue_size, + virtio_net_handle_tx_bh); n->vqs[index].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[index]); } @@ -1927,6 +1951,17 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) return; } + if (n->net_conf.tx_queue_size < VIRTIO_NET_TX_QUEUE_MIN_SIZE || + n->net_conf.tx_queue_size > VIRTQUEUE_MAX_SIZE || + !is_power_of_2(n->net_conf.tx_queue_size)) { + error_setg(errp, "Invalid tx_queue_size (= %" PRIu16 "), " + "must be a power of 2 between %d and %d", + n->net_conf.tx_queue_size, VIRTIO_NET_TX_QUEUE_MIN_SIZE, + VIRTQUEUE_MAX_SIZE); + virtio_cleanup(vdev); + return; + } + n->max_queues = MAX(n->nic_conf.peers.queues, 1); if (n->max_queues * 2 + 1 > VIRTIO_QUEUE_MAX) { error_setg(errp, "Invalid number of queues (= %" PRIu32 "), " @@ -1947,6 +1982,9 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) error_report("Defaulting to \"bh\""); } + n->net_conf.tx_queue_size = MIN(virtio_net_max_tx_queue_size(n), + n->net_conf.tx_queue_size); + for (i = 0; i < n->max_queues; i++) { virtio_net_add_queue(n, i); } @@ -2106,6 +2144,8 @@ static Property virtio_net_properties[] = { DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx), DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE), + DEFINE_PROP_UINT16("tx_queue_size", VirtIONet, net_conf.tx_queue_size, + VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE), DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0), DEFINE_PROP_BOOL("x-mtu-bypass-backend", VirtIONet, mtu_bypass_backend, true), diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 316fca9bc1..99bdbc2233 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -96,7 +96,6 @@ struct FWCfgIoState { /*< public >*/ MemoryRegion comb_iomem; - uint32_t iobase, dma_iobase; }; struct FWCfgMemState { @@ -914,6 +913,7 @@ static void fw_cfg_init1(DeviceState *dev) { FWCfgState *s = FW_CFG(dev); MachineState *machine = MACHINE(qdev_get_machine()); + uint32_t version = FW_CFG_VERSION; assert(!object_resolve_path(FW_CFG_PATH, NULL)); @@ -928,6 +928,12 @@ static void fw_cfg_init1(DeviceState *dev) fw_cfg_bootsplash(s); fw_cfg_reboot(s); + if (s->dma_enabled) { + version |= FW_CFG_VERSION_DMA; + } + + fw_cfg_add_i32(s, FW_CFG_ID, version); + s->machine_ready.notify = fw_cfg_machine_ready; qemu_add_machine_init_done_notifier(&s->machine_ready); } @@ -936,30 +942,31 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, AddressSpace *dma_as) { DeviceState *dev; + SysBusDevice *sbd; + FWCfgIoState *ios; FWCfgState *s; - uint32_t version = FW_CFG_VERSION; bool dma_requested = dma_iobase && dma_as; dev = qdev_create(NULL, TYPE_FW_CFG_IO); - qdev_prop_set_uint32(dev, "iobase", iobase); - qdev_prop_set_uint32(dev, "dma_iobase", dma_iobase); if (!dma_requested) { qdev_prop_set_bit(dev, "dma_enabled", false); } fw_cfg_init1(dev); + + sbd = SYS_BUS_DEVICE(dev); + ios = FW_CFG_IO(dev); + sysbus_add_io(sbd, iobase, &ios->comb_iomem); + s = FW_CFG(dev); if (s->dma_enabled) { /* 64 bits for the address field */ s->dma_as = dma_as; s->dma_addr = 0; - - version |= FW_CFG_VERSION_DMA; + sysbus_add_io(sbd, dma_iobase, &s->dma_iomem); } - fw_cfg_add_i32(s, FW_CFG_ID, version); - return s; } @@ -975,7 +982,6 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, DeviceState *dev; SysBusDevice *sbd; FWCfgState *s; - uint32_t version = FW_CFG_VERSION; bool dma_requested = dma_addr && dma_as; dev = qdev_create(NULL, TYPE_FW_CFG_MEM); @@ -996,11 +1002,8 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr, s->dma_as = dma_as; s->dma_addr = 0; sysbus_mmio_map(sbd, 2, dma_addr); - version |= FW_CFG_VERSION_DMA; } - fw_cfg_add_i32(s, FW_CFG_ID, version); - return s; } @@ -1059,8 +1062,6 @@ static void fw_cfg_file_slots_allocate(FWCfgState *s, Error **errp) } static Property fw_cfg_io_properties[] = { - DEFINE_PROP_UINT32("iobase", FWCfgIoState, iobase, -1), - DEFINE_PROP_UINT32("dma_iobase", FWCfgIoState, dma_iobase, -1), DEFINE_PROP_BOOL("dma_enabled", FWCfgIoState, parent_obj.dma_enabled, true), DEFINE_PROP_UINT16("x-file-slots", FWCfgIoState, parent_obj.file_slots, @@ -1071,7 +1072,6 @@ static Property fw_cfg_io_properties[] = { static void fw_cfg_io_realize(DeviceState *dev, Error **errp) { FWCfgIoState *s = FW_CFG_IO(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); Error *local_err = NULL; fw_cfg_file_slots_allocate(FW_CFG(s), &local_err); @@ -1085,13 +1085,11 @@ static void fw_cfg_io_realize(DeviceState *dev, Error **errp) * of the i/o region used is FW_CFG_CTL_SIZE */ memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops, FW_CFG(s), "fwcfg", FW_CFG_CTL_SIZE); - sysbus_add_io(sbd, s->iobase, &s->comb_iomem); if (FW_CFG(s)->dma_enabled) { memory_region_init_io(&FW_CFG(s)->dma_iomem, OBJECT(s), &fw_cfg_dma_mem_ops, FW_CFG(s), "fwcfg.dma", sizeof(dma_addr_t)); - sysbus_add_io(sbd, s->dma_iobase, &FW_CFG(s)->dma_iomem); } } diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c index cca93620ac..eb275e1a25 100644 --- a/hw/pci-bridge/dec.c +++ b/hw/pci-bridge/dec.c @@ -62,6 +62,7 @@ static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); k->realize = dec_pci_bridge_realize; k->exit = pci_bridge_exitfn; k->vendor_id = PCI_VENDOR_ID_DEC; @@ -118,6 +119,7 @@ static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); k->realize = dec_21154_pci_host_realize; k->vendor_id = PCI_VENDOR_ID_DEC; k->device_id = PCI_DEVICE_ID_DEC_21154; diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index 2404e7ebae..2c1b747b4b 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -44,6 +44,7 @@ #include "qemu/osdep.h" #include "hw/pci/pci.h" #include "hw/i386/ich9.h" +#include "qapi/error.h" /*****************************************************************************/ @@ -58,24 +59,23 @@ typedef struct I82801b11Bridge { /*< public >*/ } I82801b11Bridge; -static int i82801b11_bridge_initfn(PCIDevice *d) +static void i82801b11_bridge_realize(PCIDevice *d, Error **errp) { int rc; pci_bridge_initfn(d, TYPE_PCI_BUS); rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET, - I82801ba_SSVID_SVID, I82801ba_SSVID_SSID); + I82801ba_SSVID_SVID, I82801ba_SSVID_SSID, + errp); if (rc < 0) { goto err_bridge; } pci_config_set_prog_interface(d->config, PCI_CLASS_BRIDGE_PCI_INF_SUB); - return 0; + return; err_bridge: pci_bridge_exitfn(d); - - return rc; } static const VMStateDescription i82801b11_bridge_dev_vmstate = { @@ -95,7 +95,7 @@ static void i82801b11_bridge_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11; k->revision = ICH9_D2P_A2_REVISION; - k->init = i82801b11_bridge_initfn; + k->realize = i82801b11_bridge_realize; k->config_write = pci_bridge_write_config; dc->vmsd = &i82801b11_bridge_dev_vmstate; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 5dbd933cc1..4373f1d3e2 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -49,7 +49,7 @@ struct PCIBridgeDev { }; typedef struct PCIBridgeDev PCIBridgeDev; -static int pci_bridge_dev_initfn(PCIDevice *dev) +static void pci_bridge_dev_realize(PCIDevice *dev, Error **errp) { PCIBridge *br = PCI_BRIDGE(dev); PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev); @@ -62,7 +62,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) dev->config[PCI_INTERRUPT_PIN] = 0x1; memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar", shpc_bar_size(dev)); - err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0); + err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0, errp); if (err) { goto shpc_error; } @@ -71,7 +71,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) bridge_dev->msi = ON_OFF_AUTO_OFF; } - err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0); + err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0, errp); if (err) { goto slotid_error; } @@ -87,7 +87,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) /* Can't satisfy user's explicit msi=on request, fail */ error_append_hint(&local_err, "You have to use msi=auto (default) " "or msi=off with this machine type.\n"); - error_report_err(local_err); + error_propagate(errp, local_err); goto msi_error; } assert(!local_err || bridge_dev->msi == ON_OFF_AUTO_AUTO); @@ -101,7 +101,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar); } - return 0; + return; msi_error: slotid_cap_cleanup(dev); @@ -111,8 +111,6 @@ slotid_error: } shpc_error: pci_bridge_exitfn(dev); - - return err; } static void pci_bridge_dev_exitfn(PCIDevice *dev) @@ -216,7 +214,7 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - k->init = pci_bridge_dev_initfn; + k->realize = pci_bridge_dev_realize; k->exit = pci_bridge_dev_exitfn; k->config_write = pci_bridge_dev_write_config; k->vendor_id = PCI_VENDOR_ID_REDHAT; diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c index cf3631806f..4d588cb22e 100644 --- a/hw/pci-bridge/pcie_root_port.c +++ b/hw/pci-bridge/pcie_root_port.c @@ -59,29 +59,30 @@ static void rp_realize(PCIDevice *d, Error **errp) PCIDeviceClass *dc = PCI_DEVICE_GET_CLASS(d); PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d); int rc; - Error *local_err = NULL; pci_config_set_interrupt_pin(d->config, 1); pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); - rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id, rpc->ssid); + rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id, + rpc->ssid, errp); if (rc < 0) { - error_setg(errp, "Can't init SSV ID, error %d", rc); + error_append_hint(errp, "Can't init SSV ID, error %d\n", rc); goto err_bridge; } if (rpc->interrupts_init) { - rc = rpc->interrupts_init(d, &local_err); + rc = rpc->interrupts_init(d, errp); if (rc < 0) { - error_propagate(errp, local_err); goto err_bridge; } } - rc = pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT, p->port); + rc = pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT, + p->port, errp); if (rc < 0) { - error_setg(errp, "Can't add Root Port capability, error %d", rc); + error_append_hint(errp, "Can't add Root Port capability, " + "error %d\n", rc); goto err_int; } @@ -98,9 +99,8 @@ static void rp_realize(PCIDevice *d, Error **errp) } rc = pcie_aer_init(d, PCI_ERR_VER, rpc->aer_offset, - PCI_ERR_SIZEOF, &local_err); + PCI_ERR_SIZEOF, errp); if (rc < 0) { - error_propagate(errp, local_err); goto err; } pcie_aer_root_init(d); diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index cfe8a3657f..e706f36cb7 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -56,33 +56,33 @@ static void xio3130_downstream_reset(DeviceState *qdev) pci_bridge_reset(qdev); } -static int xio3130_downstream_initfn(PCIDevice *d) +static void xio3130_downstream_realize(PCIDevice *d, Error **errp) { PCIEPort *p = PCIE_PORT(d); PCIESlot *s = PCIE_SLOT(d); int rc; - Error *err = NULL; pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR, XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, - XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err); + XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, + errp); if (rc < 0) { assert(rc == -ENOTSUP); - error_report_err(err); goto err_bridge; } rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET, - XIO3130_SSVID_SVID, XIO3130_SSVID_SSID); + XIO3130_SSVID_SVID, XIO3130_SSVID_SSID, + errp); if (rc < 0) { goto err_bridge; } rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM, - p->port); + p->port, errp); if (rc < 0) { goto err_msi; } @@ -98,13 +98,12 @@ static int xio3130_downstream_initfn(PCIDevice *d) } rc = pcie_aer_init(d, PCI_ERR_VER, XIO3130_AER_OFFSET, - PCI_ERR_SIZEOF, &err); + PCI_ERR_SIZEOF, errp); if (rc < 0) { - error_report_err(err); goto err; } - return 0; + return; err: pcie_chassis_del_slot(s); @@ -114,7 +113,6 @@ err_msi: msi_uninit(d); err_bridge: pci_bridge_exitfn(d); - return rc; } static void xio3130_downstream_exitfn(PCIDevice *d) @@ -181,7 +179,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data) k->is_express = 1; k->is_bridge = 1; k->config_write = xio3130_downstream_write_config; - k->init = xio3130_downstream_initfn; + k->realize = xio3130_downstream_realize; k->exit = xio3130_downstream_exitfn; k->vendor_id = PCI_VENDOR_ID_TI; k->device_id = PCI_DEVICE_ID_TI_XIO3130D; diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 401c78452b..a052224bbf 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -53,32 +53,32 @@ static void xio3130_upstream_reset(DeviceState *qdev) pcie_cap_deverr_reset(d); } -static int xio3130_upstream_initfn(PCIDevice *d) +static void xio3130_upstream_realize(PCIDevice *d, Error **errp) { PCIEPort *p = PCIE_PORT(d); int rc; - Error *err = NULL; pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR, XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, - XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err); + XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, + errp); if (rc < 0) { assert(rc == -ENOTSUP); - error_report_err(err); goto err_bridge; } rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET, - XIO3130_SSVID_SVID, XIO3130_SSVID_SSID); + XIO3130_SSVID_SVID, XIO3130_SSVID_SSID, + errp); if (rc < 0) { goto err_bridge; } rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM, - p->port); + p->port, errp); if (rc < 0) { goto err_msi; } @@ -86,13 +86,12 @@ static int xio3130_upstream_initfn(PCIDevice *d) pcie_cap_deverr_init(d); rc = pcie_aer_init(d, PCI_ERR_VER, XIO3130_AER_OFFSET, - PCI_ERR_SIZEOF, &err); + PCI_ERR_SIZEOF, errp); if (rc < 0) { - error_report_err(err); goto err; } - return 0; + return; err: pcie_cap_exit(d); @@ -100,7 +99,6 @@ err_msi: msi_uninit(d); err_bridge: pci_bridge_exitfn(d); - return rc; } static void xio3130_upstream_exitfn(PCIDevice *d) @@ -153,7 +151,7 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data) k->is_express = 1; k->is_bridge = 1; k->config_write = xio3130_upstream_write_config; - k->init = xio3130_upstream_initfn; + k->realize = xio3130_upstream_realize; k->exit = xio3130_upstream_exitfn; k->vendor_id = PCI_VENDOR_ID_TI; k->device_id = PCI_DEVICE_ID_TI_XIO3130U; diff --git a/hw/pci/msi.c b/hw/pci/msi.c index a87b2278a3..5e05ce5ec2 100644 --- a/hw/pci/msi.c +++ b/hw/pci/msi.c @@ -216,7 +216,7 @@ int msi_init(struct PCIDevice *dev, uint8_t offset, } cap_size = msi_cap_sizeof(flags); - config_offset = pci_add_capability2(dev, PCI_CAP_ID_MSI, offset, + config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size, errp); if (config_offset < 0) { return config_offset; diff --git a/hw/pci/msix.c b/hw/pci/msix.c index fc5fe511b3..5078d3dd19 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -301,7 +301,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, return -EINVAL; } - cap = pci_add_capability2(dev, PCI_CAP_ID_MSIX, + cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH, errp); if (cap < 0) { return cap; diff --git a/hw/pci/pci.c b/hw/pci/pci.c index b7fee4bdf2..0c6f74a347 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2259,28 +2259,12 @@ static void pci_del_option_rom(PCIDevice *pdev) } /* - * if offset = 0, - * Find and reserve space and add capability to the linked list - * in pci config space + * On success, pci_add_capability() returns a positive value + * that the offset of the pci capability. + * On failure, it sets an error and returns a negative error + * code. */ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, - uint8_t offset, uint8_t size) -{ - int ret; - Error *local_err = NULL; - - ret = pci_add_capability2(pdev, cap_id, offset, size, &local_err); - if (local_err) { - assert(ret < 0); - error_report_err(local_err); - } else { - /* success implies a positive offset in config space */ - assert(ret > 0); - } - return ret; -} - -int pci_add_capability2(PCIDevice *pdev, uint8_t cap_id, uint8_t offset, uint8_t size, Error **errp) { diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 5118ef404f..720119b21a 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -33,6 +33,7 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" #include "qemu/range.h" +#include "qapi/error.h" /* PCI bridge subsystem vendor ID helper functions */ #define PCI_SSVID_SIZEOF 8 @@ -40,10 +41,13 @@ #define PCI_SSVID_SSID 6 int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, - uint16_t svid, uint16_t ssid) + uint16_t svid, uint16_t ssid, + Error **errp) { int pos; - pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF); + + pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, + PCI_SSVID_SIZEOF, errp); if (pos < 0) { return pos; } diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 18e634f577..32191f2a55 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -86,7 +86,9 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) pci_set_word(cmask + PCI_EXP_LNKSTA, 0); } -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) +int pcie_cap_init(PCIDevice *dev, uint8_t offset, + uint8_t type, uint8_t port, + Error **errp) { /* PCIe cap v2 init */ int pos; @@ -94,7 +96,8 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) assert(pci_is_express(dev)); - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, PCI_EXP_VER2_SIZEOF); + pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, + PCI_EXP_VER2_SIZEOF, errp); if (pos < 0) { return pos; } @@ -123,11 +126,14 @@ int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type, { /* PCIe cap v1 init */ int pos; + Error *local_err = NULL; assert(pci_is_express(dev)); - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, PCI_EXP_VER1_SIZEOF); + pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, + PCI_EXP_VER1_SIZEOF, &local_err); if (pos < 0) { + error_report_err(local_err); return pos; } dev->exp.exp_cap = pos; @@ -141,6 +147,8 @@ static int pcie_endpoint_cap_common_init(PCIDevice *dev, uint8_t offset, uint8_t cap_size) { uint8_t type = PCI_EXP_TYPE_ENDPOINT; + Error *local_err = NULL; + int ret; /* * Windows guests will report Code 10, device cannot start, if @@ -151,9 +159,17 @@ pcie_endpoint_cap_common_init(PCIDevice *dev, uint8_t offset, uint8_t cap_size) type = PCI_EXP_TYPE_RC_END; } - return (cap_size == PCI_EXP_VER1_SIZEOF) - ? pcie_cap_v1_init(dev, offset, type, 0) - : pcie_cap_init(dev, offset, type, 0); + if (cap_size == PCI_EXP_VER1_SIZEOF) { + return pcie_cap_v1_init(dev, offset, type, 0); + } else { + ret = pcie_cap_init(dev, offset, type, 0, &local_err); + + if (ret < 0) { + error_report_err(local_err); + } + + return ret; + } } int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset) diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index 42fafac91b..69fc14b218 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -446,12 +446,13 @@ static void shpc_cap_update_dword(PCIDevice *d) } /* Add SHPC capability to the config space for the device. */ -static int shpc_cap_add_config(PCIDevice *d) +static int shpc_cap_add_config(PCIDevice *d, Error **errp) { uint8_t *config; int config_offset; config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC, - 0, SHPC_CAP_LENGTH); + 0, SHPC_CAP_LENGTH, + errp); if (config_offset < 0) { return config_offset; } @@ -581,13 +582,14 @@ void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev, } /* Initialize the SHPC structure in bridge's BAR. */ -int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset) +int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, + unsigned offset, Error **errp) { int i, ret; int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */ SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc)); shpc->sec_bus = sec_bus; - ret = shpc_cap_add_config(d); + ret = shpc_cap_add_config(d, errp); if (ret) { g_free(d->shpc); return ret; diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c index aec1e9166d..36d021b4a6 100644 --- a/hw/pci/slotid_cap.c +++ b/hw/pci/slotid_cap.c @@ -2,18 +2,21 @@ #include "hw/pci/slotid_cap.h" #include "hw/pci/pci.h" #include "qemu/error-report.h" +#include "qapi/error.h" #define SLOTID_CAP_LENGTH 4 #define SLOTID_NSLOTS_SHIFT ctz32(PCI_SID_ESR_NSLOTS) int slotid_cap_init(PCIDevice *d, int nslots, uint8_t chassis, - unsigned offset) + unsigned offset, + Error **errp) { int cap; + if (!chassis) { - error_report("Bridge chassis not specified. Each bridge is required " - "to be assigned a unique chassis id > 0."); + error_setg(errp, "Bridge chassis not specified. Each bridge is required" + " to be assigned a unique chassis id > 0."); return -EINVAL; } if (nslots < 0 || nslots > (PCI_SID_ESR_NSLOTS >> SLOTID_NSLOTS_SHIFT)) { @@ -21,7 +24,8 @@ int slotid_cap_init(PCIDevice *d, int nslots, return -EINVAL; } - cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH); + cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, + SLOTID_CAP_LENGTH, errp); if (cap < 0) { return cap; } diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 760135c0d2..204ea69d3f 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3419,7 +3419,7 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp) if (pci_bus_is_express(dev->bus) || xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) { ret = pcie_endpoint_cap_init(dev, 0xa0); - assert(ret >= 0); + assert(ret > 0); } if (xhci->msix != ON_OFF_AUTO_OFF) { diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 32aca77701..8de8272e96 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1743,11 +1743,14 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size, PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS); } - pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size); - if (pos >= 0) { - vdev->pdev.exp.exp_cap = pos; + pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size, + errp); + if (pos < 0) { + return pos; } + vdev->pdev.exp.exp_cap = pos; + return pos; } @@ -1834,14 +1837,14 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp) case PCI_CAP_ID_PM: vfio_check_pm_reset(vdev, pos); vdev->pm_cap = pos; - ret = pci_add_capability2(pdev, cap_id, pos, size, errp); + ret = pci_add_capability(pdev, cap_id, pos, size, errp); break; case PCI_CAP_ID_AF: vfio_check_af_flr(vdev, pos); - ret = pci_add_capability2(pdev, cap_id, pos, size, errp); + ret = pci_add_capability(pdev, cap_id, pos, size, errp); break; default: - ret = pci_add_capability2(pdev, cap_id, pos, size, errp); + ret = pci_add_capability(pdev, cap_id, pos, size, errp); break; } out: diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 4e31de1686..cb055e8f21 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -309,7 +309,10 @@ int vhost_backend_update_device_iotlb(struct vhost_dev *dev, return -EINVAL; } - return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg); + if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg) + return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg); + + return -ENODEV; } int vhost_backend_invalidate_device_iotlb(struct vhost_dev *dev, @@ -321,7 +324,10 @@ int vhost_backend_invalidate_device_iotlb(struct vhost_dev *dev, imsg.size = len; imsg.type = VHOST_IOTLB_INVALIDATE; - return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg); + if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg) + return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg); + + return -ENODEV; } int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 958ee09bcb..2203011125 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -779,6 +779,7 @@ static int vhost_user_cleanup(struct vhost_dev *dev) u = dev->opaque; if (u->slave_fd >= 0) { + qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL); close(u->slave_fd); u->slave_fd = -1; } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 301920ec1b..93480a7af1 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1162,8 +1162,8 @@ static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, PCIDevice *dev = &proxy->pci_dev; int offset; - offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len); - assert(offset > 0); + offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, + cap->cap_len, &error_abort); assert(cap->cap_len >= sizeof *cap); memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len, @@ -1810,8 +1810,12 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) pos = pcie_endpoint_cap_init(pci_dev, 0); assert(pos > 0); - pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF); - assert(pos > 0); + pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0, + PCI_PM_SIZEOF, errp); + if (pos < 0) { + return; + } + pci_dev->exp.pm_cap = pos; /* diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index a37a2d5cb6..e598b095eb 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -356,8 +356,6 @@ void pci_unregister_vga(PCIDevice *pci_dev); pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, - uint8_t offset, uint8_t size); -int pci_add_capability2(PCIDevice *pdev, uint8_t cap_id, uint8_t offset, uint8_t size, Error **errp); diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index d5891cd30e..ff7cbaa227 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -33,7 +33,8 @@ #define PCI_BRIDGE_DEV_PROP_SHPC "shpc" int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, - uint16_t svid, uint16_t ssid); + uint16_t svid, uint16_t ssid, + Error **errp); PCIDevice *pci_bridge_get_device(PCIBus *bus); PCIBus *pci_bridge_get_sec_bus(PCIBridge *br); diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index 3d8f24b007..b71e369703 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -84,7 +84,8 @@ struct PCIExpressDevice { #define COMPAT_PROP_PCP "power_controller_present" /* PCI express capability helper functions */ -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, + uint8_t port, Error **errp); int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset); diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h index 71e836b1c0..ee19fecf61 100644 --- a/include/hw/pci/shpc.h +++ b/include/hw/pci/shpc.h @@ -38,7 +38,8 @@ struct SHPCDevice { void shpc_reset(PCIDevice *d); int shpc_bar_size(PCIDevice *dev); -int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off); +int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, + unsigned off, Error **errp); void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar); void shpc_free(PCIDevice *dev); void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len); diff --git a/include/hw/pci/slotid_cap.h b/include/hw/pci/slotid_cap.h index 70db0470b0..a777ea0e49 100644 --- a/include/hw/pci/slotid_cap.h +++ b/include/hw/pci/slotid_cap.h @@ -5,7 +5,8 @@ int slotid_cap_init(PCIDevice *dev, int nslots, uint8_t chassis, - unsigned offset); + unsigned offset, + Error **errp); void slotid_cap_cleanup(PCIDevice *dev); #endif diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 602b4868d4..b81b6a4624 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -36,6 +36,7 @@ typedef struct virtio_net_conf int32_t txburst; char *tx; uint16_t rx_queue_size; + uint16_t tx_queue_size; uint16_t mtu; } virtio_net_conf; diff --git a/tests/Makefile.include b/tests/Makefile.include index ae889cae02..18cd06a6b3 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -250,6 +250,7 @@ check-qtest-i386-y += tests/usb-hcd-xhci-test$(EXESUF) gcov-files-i386-y += hw/usb/hcd-xhci.c check-qtest-i386-y += tests/pc-cpu-test$(EXESUF) check-qtest-i386-y += tests/q35-test$(EXESUF) +check-qtest-i386-y += tests/vmgenid-test$(EXESUF) gcov-files-i386-y += hw/pci-host/q35.c check-qtest-i386-$(CONFIG_VHOST_NET_TEST_i386) += tests/vhost-user-test$(EXESUF) ifeq ($(CONFIG_VHOST_NET_TEST_i386),) @@ -760,6 +761,7 @@ tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y) tests/numa-test$(EXESUF): tests/numa-test.o +tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/acpi-utils.o tests/migration/stress$(EXESUF): tests/migration/stress.o $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@") diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT index 0dccad439b..a6138c8291 100644 Binary files a/tests/acpi-test-data/q35/DSDT and b/tests/acpi-test-data/q35/DSDT differ diff --git a/tests/acpi-test-data/q35/DSDT.bridge b/tests/acpi-test-data/q35/DSDT.bridge index 8cd66c3b31..6b90f606f8 100644 Binary files a/tests/acpi-test-data/q35/DSDT.bridge and b/tests/acpi-test-data/q35/DSDT.bridge differ diff --git a/tests/acpi-test-data/q35/DSDT.cphp b/tests/acpi-test-data/q35/DSDT.cphp index 3c28a17a69..976755ef2d 100644 Binary files a/tests/acpi-test-data/q35/DSDT.cphp and b/tests/acpi-test-data/q35/DSDT.cphp differ diff --git a/tests/acpi-test-data/q35/DSDT.ipmibt b/tests/acpi-test-data/q35/DSDT.ipmibt index 3ceb876127..b3fa4359ff 100644 Binary files a/tests/acpi-test-data/q35/DSDT.ipmibt and b/tests/acpi-test-data/q35/DSDT.ipmibt differ diff --git a/tests/acpi-test-data/q35/DSDT.memhp b/tests/acpi-test-data/q35/DSDT.memhp index bdbefd47a5..7341c405bf 100644 Binary files a/tests/acpi-test-data/q35/DSDT.memhp and b/tests/acpi-test-data/q35/DSDT.memhp differ diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c new file mode 100644 index 0000000000..e7ba38c9d1 --- /dev/null +++ b/tests/vmgenid-test.c @@ -0,0 +1,203 @@ +/* + * QTest testcase for VM Generation ID + * + * Copyright (c) 2016 Red Hat, Inc. + * Copyright (c) 2017 Skyport Systems + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include "qemu/osdep.h" +#include "qemu/bitmap.h" +#include "qemu/uuid.h" +#include "hw/acpi/acpi-defs.h" +#include "acpi-utils.h" +#include "libqtest.h" + +#define VGID_GUID "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87" +#define VMGENID_GUID_OFFSET 40 /* allow space for + * OVMF SDT Header Probe Supressor + */ +#define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */ +#define RSDP_SLEEP_US 100000 /* Sleep for 100ms between tries */ +#define RSDP_TRIES_MAX 100 /* Max total time is 10 seconds */ + +typedef struct { + AcpiTableHeader header; + gchar name_op; + gchar vgia[4]; + gchar val_op; + uint32_t vgia_val; +} QEMU_PACKED VgidTable; + +static uint32_t acpi_find_vgia(void) +{ + uint32_t rsdp_offset; + uint32_t guid_offset = 0; + AcpiRsdpDescriptor rsdp_table; + uint32_t rsdt; + AcpiRsdtDescriptorRev1 rsdt_table; + int tables_nr; + uint32_t *tables; + AcpiTableHeader ssdt_table; + VgidTable vgid_table; + int i; + + /* Tables may take a short time to be set up by the guest */ + for (i = 0; i < RSDP_TRIES_MAX; i++) { + rsdp_offset = acpi_find_rsdp_address(); + if (rsdp_offset < RSDP_ADDR_INVALID) { + break; + } + g_usleep(RSDP_SLEEP_US); + } + g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID); + + acpi_parse_rsdp_table(rsdp_offset, &rsdp_table); + + rsdt = rsdp_table.rsdt_physical_address; + /* read the header */ + ACPI_READ_TABLE_HEADER(&rsdt_table, rsdt); + ACPI_ASSERT_CMP(rsdt_table.signature, "RSDT"); + + /* compute the table entries in rsdt */ + tables_nr = (rsdt_table.length - sizeof(AcpiRsdtDescriptorRev1)) / + sizeof(uint32_t); + g_assert_cmpint(tables_nr, >, 0); + + /* get the addresses of the tables pointed by rsdt */ + tables = g_new0(uint32_t, tables_nr); + ACPI_READ_ARRAY_PTR(tables, tables_nr, rsdt); + + for (i = 0; i < tables_nr; i++) { + ACPI_READ_TABLE_HEADER(&ssdt_table, tables[i]); + if (!strncmp((char *)ssdt_table.oem_table_id, "VMGENID", 7)) { + /* the first entry in the table should be VGIA + * That's all we need + */ + ACPI_READ_FIELD(vgid_table.name_op, tables[i]); + g_assert(vgid_table.name_op == 0x08); /* name */ + ACPI_READ_ARRAY(vgid_table.vgia, tables[i]); + g_assert(memcmp(vgid_table.vgia, "VGIA", 4) == 0); + ACPI_READ_FIELD(vgid_table.val_op, tables[i]); + g_assert(vgid_table.val_op == 0x0C); /* dword */ + ACPI_READ_FIELD(vgid_table.vgia_val, tables[i]); + /* The GUID is written at a fixed offset into the fw_cfg file + * in order to implement the "OVMF SDT Header probe suppressor" + * see docs/specs/vmgenid.txt for more details + */ + guid_offset = vgid_table.vgia_val + VMGENID_GUID_OFFSET; + break; + } + } + g_free(tables); + return guid_offset; +} + +static void read_guid_from_memory(QemuUUID *guid) +{ + uint32_t vmgenid_addr; + int i; + + vmgenid_addr = acpi_find_vgia(); + g_assert(vmgenid_addr); + + /* Read the GUID directly from guest memory */ + for (i = 0; i < 16; i++) { + guid->data[i] = readb(vmgenid_addr + i); + } + /* The GUID is in little-endian format in the guest, while QEMU + * uses big-endian. Swap after reading. + */ + qemu_uuid_bswap(guid); +} + +static void read_guid_from_monitor(QemuUUID *guid) +{ + QDict *rsp, *rsp_ret; + const char *guid_str; + + rsp = qmp("{ 'execute': 'query-vm-generation-id' }"); + if (qdict_haskey(rsp, "return")) { + rsp_ret = qdict_get_qdict(rsp, "return"); + g_assert(qdict_haskey(rsp_ret, "guid")); + guid_str = qdict_get_str(rsp_ret, "guid"); + g_assert(qemu_uuid_parse(guid_str, guid) == 0); + } + QDECREF(rsp); +} + +static void vmgenid_set_guid_test(void) +{ + QemuUUID expected, measured; + gchar *cmd; + + g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0); + + cmd = g_strdup_printf("-machine accel=tcg -device vmgenid,id=testvgid," + "guid=%s", VGID_GUID); + qtest_start(cmd); + + /* Read the GUID from accessing guest memory */ + read_guid_from_memory(&measured); + g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0); + + qtest_quit(global_qtest); + g_free(cmd); +} + +static void vmgenid_set_guid_auto_test(void) +{ + const char *cmd; + QemuUUID measured; + + cmd = "-machine accel=tcg -device vmgenid,id=testvgid," "guid=auto"; + qtest_start(cmd); + + read_guid_from_memory(&measured); + + /* Just check that the GUID is non-null */ + g_assert(!qemu_uuid_is_null(&measured)); + + qtest_quit(global_qtest); +} + +static void vmgenid_query_monitor_test(void) +{ + QemuUUID expected, measured; + gchar *cmd; + + g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0); + + cmd = g_strdup_printf("-machine accel=tcg -device vmgenid,id=testvgid," + "guid=%s", VGID_GUID); + qtest_start(cmd); + + /* Read the GUID via the monitor */ + read_guid_from_monitor(&measured); + g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0); + + qtest_quit(global_qtest); + g_free(cmd); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/vmgenid/vmgenid/set-guid", + vmgenid_set_guid_test); + qtest_add_func("/vmgenid/vmgenid/set-guid-auto", + vmgenid_set_guid_auto_test); + qtest_add_func("/vmgenid/vmgenid/query-monitor", + vmgenid_query_monitor_test); + ret = g_test_run(); + + return ret; +}