mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-29 22:40:25 +00:00
pc, acpi, pci, virtio: fixes, cleanups, features, tests
Some fixes and cleanups. New tests. Configurable tx queue size for virtio-net. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJZWp5VAAoJECgfDbjSjVRpI6sIAMFpi+UBsE8NR5s6kNZOJIEc rajYhfnuCoGmAXiDalVVgEjyEjlfeDqkdQyWb9r4XNRGfPAv76V4d9l0KNnuGEHF 5GFNduAuECYm8Hl5e6J/gSNCau/hmdBOtFUZvYWs+yhVpRw7+8lJTvhviNzBIGa0 mZBHCaAUzdyW7fvPh0inWxhXscPaUi8pHfohthsuTxRuBjKrQq4L/4zF9u4Mmtu+ zNHpNMQ/mn3uC9IjiD7csfqF9IHxMlUl0IkoKXm1waIpZjr9LQ5hPhbP1KepVP6c fgPuJYHT+HeVfzyBIXbTZGhza2KduDLM7YCGWkprPBmjwM7OLrBl3JuWmw4Kg+4= =g6bo -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging pc, acpi, pci, virtio: fixes, cleanups, features, tests Some fixes and cleanups. New tests. Configurable tx queue size for virtio-net. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Mon 03 Jul 2017 20:43:17 BST # gpg: using RSA key 0x281F0DB8D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # 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: (21 commits) i386/acpi: update expected acpi files virtio-net: fix tx queue size for !vhost-user tests: Add unit tests for the VM Generation ID feature vhost-user: unregister slave req handler at cleanup time vhost: ensure vhost_ops are set before calling iotlb callback intel_iommu: fix migration breakage on mr switch hw/acpi: remove dead acpi code fw_cfg: move setting of FW_CFG_VERSION_DMA bit to fw_cfg_init1() fw_cfg: don't map the fw_cfg IO ports in fw_cfg_io_realize() i386/kvm/pci-assign: Use errp directly rather than local_err i386/kvm/pci-assign: Fix return type of verify_irqchip_kernel() pci: Convert shpc_init() to Error pci: Convert to realize pci: Replace pci_add_capability2() with pci_add_capability() pci: Make errp the last parameter of pci_add_capability() pci: Fix the wrong assertion. pci: Add comment for pci_add_capability2() pci: Clean up error checking in pci_add_capability() intel_iommu: relax iq tail check on VTD_GCMD_QIE enable hw/pci-bridge/dec: Classify the DEC PCI bridge as bridge device ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0c7a8b9baa
@ -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")));
|
||||
|
@ -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",
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
24
hw/pci/pci.c
24
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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)$@")
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
203
tests/vmgenid-test.c
Normal file
203
tests/vmgenid-test.c
Normal file
@ -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 <glib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user