aboutsummaryrefslogtreecommitdiff
path: root/hw/pci
diff options
context:
space:
mode:
Diffstat (limited to 'hw/pci')
-rw-r--r--hw/pci/msix.c6
-rw-r--r--hw/pci/pci.c18
-rw-r--r--hw/pci/pci_bridge.c7
-rw-r--r--hw/pci/pcie.c19
4 files changed, 38 insertions, 12 deletions
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 2c7ead7..67e34f3 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -200,6 +200,9 @@ static const MemoryRegionOps msix_table_mmio_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
.max_access_size = 4,
},
};
@@ -228,6 +231,9 @@ static const MemoryRegionOps msix_pba_mmio_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
.max_access_size = 4,
},
};
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 70c6696..a60cf3a 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1381,6 +1381,8 @@ uint32_t pci_default_read_config(PCIDevice *d,
{
uint32_t val = 0;
+ assert(address + len <= pci_config_size(d));
+
if (pci_is_express_downstream_port(d) &&
ranges_overlap(address, len, d->exp.exp_cap + PCI_EXP_LNKSTA, 2)) {
pcie_sync_bridge_lnk(d);
@@ -1394,6 +1396,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int
int i, was_irq_disabled = pci_irq_disabled(d);
uint32_t val = val_in;
+ assert(addr + l <= pci_config_size(d));
+
for (i = 0; i < l; val >>= 8, ++i) {
uint8_t wmask = d->wmask[addr + i];
uint8_t w1cmask = d->w1cmask[addr + i];
@@ -1772,6 +1776,7 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
info->regions = qmp_query_pci_regions(dev);
info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
+ info->irq_pin = dev->config[PCI_INTERRUPT_PIN];
if (dev->config[PCI_INTERRUPT_PIN] != 0) {
info->has_irq = true;
info->irq = dev->config[PCI_INTERRUPT_LINE];
@@ -1887,7 +1892,18 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) &&
dc->user_creatable) {
const char *name = object_class_get_name(list->data);
- g_ptr_array_add(pci_nic_models, (gpointer)name);
+ /*
+ * A network device might also be something else than a NIC, see
+ * e.g. the "rocker" device. Thus we have to look for the "netdev"
+ * property, too. Unfortunately, some devices like virtio-net only
+ * create this property during instance_init, so we have to create
+ * a temporary instance here to be able to check it.
+ */
+ Object *obj = object_new_with_class(OBJECT_CLASS(dc));
+ if (object_property_find(obj, "netdev", NULL)) {
+ g_ptr_array_add(pci_nic_models, (gpointer)name);
+ }
+ object_unref(obj);
}
next = list->next;
g_slist_free_1(list);
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index 97967d1..3789c17 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -30,6 +30,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_bus.h"
#include "qemu/module.h"
@@ -381,7 +382,7 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename)
memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX);
sec_bus->address_space_io = &br->address_space_io;
memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io",
- UINT32_MAX);
+ 4 * GiB);
br->windows = pci_bridge_region_init(br);
QLIST_INIT(&sec_bus->child);
QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
@@ -422,14 +423,14 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
}
if (res_reserve.mem_non_pref != (uint64_t)-1 &&
- res_reserve.mem_non_pref >= (1ULL << 32)) {
+ res_reserve.mem_non_pref >= 4 * GiB) {
error_setg(errp,
"PCI resource reserve cap: mem-reserve must be less than 4G");
return -EINVAL;
}
if (res_reserve.mem_pref_32 != (uint64_t)-1 &&
- res_reserve.mem_pref_32 >= (1ULL << 32)) {
+ res_reserve.mem_pref_32 >= 4 * GiB) {
error_setg(errp,
"PCI resource reserve cap: pref32-reserve must be less than 4G");
return -EINVAL;
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index f50e10b..5b9c022 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -407,6 +407,17 @@ static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev,
void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
+ PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
+ uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
+ uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP);
+
+ /* Check if hot-plug is disabled on the slot */
+ if (dev->hotplugged && (sltcap & PCI_EXP_SLTCAP_HPC) == 0) {
+ error_setg(errp, "Hot-plug failed: unsupported by the port device '%s'",
+ DEVICE(hotplug_pdev)->id);
+ return;
+ }
+
pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp);
}
@@ -415,7 +426,6 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
{
PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
- uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP);
PCIDevice *pci_dev = PCI_DEVICE(dev);
/* Don't send event when device is enabled during qemu machine creation:
@@ -431,13 +441,6 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
- /* Check if hot-plug is disabled on the slot */
- if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) {
- error_setg(errp, "Hot-plug failed: unsupported by the port device '%s'",
- DEVICE(hotplug_pdev)->id);
- return;
- }
-
/* To enable multifunction hot-plug, we just ensure the function
* 0 added last. When function 0 is added, we set the sltsta and
* inform OS via event notification.