X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/2bb39a657abeac3f33ab3298177fb27c35f5b50a..a2a9d4adabe340617a24eb73a8b2a116d28a6b38:/hw/pci/pci.c diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 67a3f72bd6..8076a80ab3 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qemu-common.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" @@ -120,23 +121,39 @@ static void pci_bus_realize(BusState *qbus, Error **errp) vmstate_register(NULL, -1, &vmstate_pcibus, bus); } -static void pci_bus_unrealize(BusState *qbus, Error **errp) +static void pcie_bus_realize(BusState *qbus, Error **errp) { PCIBus *bus = PCI_BUS(qbus); - qemu_remove_machine_init_done_notifier(&bus->machine_done); + pci_bus_realize(qbus, errp); - vmstate_unregister(NULL, &vmstate_pcibus, bus); + /* + * A PCI-E bus can support extended config space if it's the root + * bus, or if the bus/bridge above it does as well + */ + if (pci_bus_is_root(bus)) { + bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; + } else { + PCIBus *parent_bus = pci_get_bus(bus->parent_dev); + + if (pci_bus_allows_extended_config_space(parent_bus)) { + bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; + } + } } -static bool pcibus_is_root(PCIBus *bus) +static void pci_bus_unrealize(BusState *qbus, Error **errp) { - return !bus->parent_dev; + PCIBus *bus = PCI_BUS(qbus); + + qemu_remove_machine_init_done_notifier(&bus->machine_done); + + vmstate_unregister(NULL, &vmstate_pcibus, bus); } static int pcibus_num(PCIBus *bus) { - if (pcibus_is_root(bus)) { + if (pci_bus_is_root(bus)) { return 0; /* pci host bridge */ } return bus->parent_dev->config[PCI_SECONDARY_BUS]; @@ -159,7 +176,6 @@ static void pci_bus_class_init(ObjectClass *klass, void *data) k->unrealize = pci_bus_unrealize; k->reset = pcibus_reset; - pbc->is_root = pcibus_is_root; pbc->bus_num = pcibus_num; pbc->numa_node = pcibus_numa_node; } @@ -182,9 +198,17 @@ static const TypeInfo conventional_pci_interface_info = { .parent = TYPE_INTERFACE, }; +static void pcie_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->realize = pcie_bus_realize; +} + static const TypeInfo pcie_bus_info = { .name = TYPE_PCIE_BUS, .parent = TYPE_PCI_BUS, + .class_init = pcie_bus_class_init, }; static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); @@ -211,13 +235,13 @@ int pci_bar(PCIDevice *d, int reg) static inline int pci_irq_state(PCIDevice *d, int irq_num) { - return (d->irq_state >> irq_num) & 0x1; + return (d->irq_state >> irq_num) & 0x1; } static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level) { - d->irq_state &= ~(0x1 << irq_num); - d->irq_state |= level << irq_num; + d->irq_state &= ~(0x1 << irq_num); + d->irq_state |= level << irq_num; } static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) @@ -333,6 +357,13 @@ static void pci_host_bus_register(DeviceState *host) QLIST_INSERT_HEAD(&pci_host_bridges, host_bridge, next); } +static void pci_host_bus_unregister(DeviceState *host) +{ + PCIHostState *host_bridge = PCI_HOST_BRIDGE(host); + + QLIST_REMOVE(host_bridge, next); +} + PCIBus *pci_device_root_bus(const PCIDevice *d) { PCIBus *bus = pci_get_bus(d); @@ -372,6 +403,7 @@ static void pci_root_bus_init(PCIBus *bus, DeviceState *parent, bus->slot_reserved_mask = 0x0; bus->address_space_mem = address_space_mem; bus->address_space_io = address_space_io; + bus->flags |= PCI_BUS_IS_ROOT; /* host bridge */ QLIST_INIT(&bus->child); @@ -379,14 +411,14 @@ static void pci_root_bus_init(PCIBus *bus, DeviceState *parent, pci_host_bus_register(parent); } -bool pci_bus_is_express(PCIBus *bus) +static void pci_bus_uninit(PCIBus *bus) { - return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); + pci_host_bus_unregister(BUS(bus)->parent); } -bool pci_bus_is_root(PCIBus *bus) +bool pci_bus_is_express(PCIBus *bus) { - return PCI_BUS_GET_CLASS(bus)->is_root(bus); + return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); } void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, @@ -413,6 +445,13 @@ PCIBus *pci_root_bus_new(DeviceState *parent, const char *name, return bus; } +void pci_root_bus_cleanup(PCIBus *bus) +{ + pci_bus_uninit(bus); + /* the caller of the unplug hotplug handler will delete this device */ + object_property_set_bool(OBJECT(bus), false, "realized", NULL); +} + void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int nirq) { @@ -423,6 +462,15 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); } +void pci_bus_irqs_cleanup(PCIBus *bus) +{ + bus->set_irq = NULL; + bus->map_irq = NULL; + bus->irq_opaque = NULL; + bus->nirq = 0; + g_free(bus->irq_count); +} + PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, @@ -439,6 +487,12 @@ PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, return bus; } +void pci_unregister_root_bus(PCIBus *bus) +{ + pci_bus_irqs_cleanup(bus); + pci_root_bus_cleanup(bus); +} + int pci_bus_num(PCIBus *s) { return PCI_BUS_GET_CLASS(s)->bus_num(s); @@ -450,7 +504,7 @@ int pci_bus_numa_node(PCIBus *bus) } static int get_pci_config_device(QEMUFile *f, void *pv, size_t size, - VMStateField *field) + const VMStateField *field) { PCIDevice *s = container_of(pv, PCIDevice, config); PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(s); @@ -490,7 +544,7 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size, /* just put buffer */ static int put_pci_config_device(QEMUFile *f, void *pv, size_t size, - VMStateField *field, QJSON *vmdesc) + const VMStateField *field, QJSON *vmdesc) { const uint8_t **v = pv; assert(size == pci_config_size(container_of(pv, PCIDevice, config))); @@ -506,7 +560,7 @@ static VMStateInfo vmstate_info_pci_config = { }; static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size, - VMStateField *field) + const VMStateField *field) { PCIDevice *s = container_of(pv, PCIDevice, irq_state); uint32_t irq_state[PCI_NUM_PINS]; @@ -528,7 +582,7 @@ static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size, } static int put_pci_irq_state(QEMUFile *f, void *pv, size_t size, - VMStateField *field, QJSON *vmdesc) + const VMStateField *field, QJSON *vmdesc) { int i; PCIDevice *s = container_of(pv, PCIDevice, irq_state); @@ -571,8 +625,8 @@ const VMStateDescription vmstate_pci_device = { 0, vmstate_info_pci_config, PCIE_CONFIG_SPACE_SIZE), VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2, - vmstate_info_pci_irq_state, - PCI_NUM_PINS * sizeof(int32_t)), + vmstate_info_pci_irq_state, + PCI_NUM_PINS * sizeof(int32_t)), VMSTATE_END_OF_LIST() } }; @@ -624,21 +678,21 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, p = addr; val = strtoul(p, &e, 16); if (e == p) - return -1; + return -1; if (*e == ':') { - bus = val; - p = e + 1; - val = strtoul(p, &e, 16); - if (e == p) - return -1; - if (*e == ':') { - dom = bus; - bus = val; - p = e + 1; - val = strtoul(p, &e, 16); - if (e == p) - return -1; - } + bus = val; + p = e + 1; + val = strtoul(p, &e, 16); + if (e == p) + return -1; + if (*e == ':') { + dom = bus; + bus = val; + p = e + 1; + val = strtoul(p, &e, 16); + if (e == p) + return -1; + } } slot = val; @@ -657,10 +711,10 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, /* if funcp == NULL func is 0 */ if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) - return -1; + return -1; if (*e) - return -1; + return -1; *domp = dom; *busp = bus; @@ -670,37 +724,6 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, return 0; } -static PCIBus *pci_get_bus_devfn(int *devfnp, PCIBus *root, - const char *devaddr) -{ - int dom, bus; - unsigned slot; - - if (!root) { - fprintf(stderr, "No primary PCI bus\n"); - return NULL; - } - - assert(!root->parent_dev); - - if (!devaddr) { - *devfnp = -1; - return pci_find_bus_nr(root, 0); - } - - if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) { - return NULL; - } - - if (dom != 0) { - fprintf(stderr, "No support for non-zero PCI domains\n"); - return NULL; - } - - *devfnp = PCI_DEVFN(slot, 0); - return pci_find_bus_nr(root, bus); -} - static void pci_init_cmask(PCIDevice *dev) { pci_set_word(dev->cmask + PCI_VENDOR_ID, 0xffff); @@ -893,7 +916,7 @@ static uint16_t pci_req_id_cache_extract(PCIReqIDCache *cache) result = PCI_BUILD_BDF(bus_n, 0); break; default: - error_printf("Invalid PCI requester ID cache type: %d\n", + error_report("Invalid PCI requester ID cache type: %d", cache->type); exit(1); break; @@ -1217,7 +1240,7 @@ pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) } static pcibus_t pci_bar_address(PCIDevice *d, - int reg, uint8_t type, pcibus_t size) + int reg, uint8_t type, pcibus_t size) { pcibus_t new_addr, last_addr; int bar = pci_bar(d, reg); @@ -1353,6 +1376,10 @@ uint32_t pci_default_read_config(PCIDevice *d, { uint32_t val = 0; + if (pci_is_express_downstream_port(d) && + ranges_overlap(address, len, d->exp.exp_cap + PCI_EXP_LNKSTA, 2)) { + pcie_sync_bridge_lnk(d); + } memcpy(&val, d->config + address, len); return le32_to_cpu(val); } @@ -1494,7 +1521,7 @@ void pci_device_set_intx_routing_notifier(PCIDevice *dev, */ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) { - return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; + return pci_swizzle(PCI_SLOT(pci_dev->devfn), pin); } /***********************************************************/ @@ -1749,6 +1776,16 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, if (type == PCI_HEADER_TYPE_BRIDGE) { info->has_pci_bridge = true; info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); + } else if (type == PCI_HEADER_TYPE_NORMAL) { + info->id->has_subsystem = info->id->has_subsystem_vendor = true; + info->id->subsystem = pci_get_word(dev->config + PCI_SUBSYSTEM_ID); + info->id->subsystem_vendor = + pci_get_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID); + } else if (type == PCI_HEADER_TYPE_CARDBUS) { + info->id->has_subsystem = info->id->has_subsystem_vendor = true; + info->id->subsystem = pci_get_word(dev->config + PCI_CB_SUBSYSTEM_ID); + info->id->subsystem_vendor = + pci_get_word(dev->config + PCI_CB_SUBSYSTEM_VENDOR_ID); } return info; @@ -1828,6 +1865,8 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, DeviceState *dev; int devfn; int i; + int dom, busnr; + unsigned slot; if (nd->model && !strcmp(nd->model, "virtio")) { g_free(nd->model); @@ -1861,7 +1900,32 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, exit(1); } - bus = pci_get_bus_devfn(&devfn, rootbus, devaddr); + if (!rootbus) { + error_report("No primary PCI bus"); + exit(1); + } + + assert(!rootbus->parent_dev); + + if (!devaddr) { + devfn = -1; + busnr = 0; + } else { + if (pci_parse_devaddr(devaddr, &dom, &busnr, &slot, NULL) < 0) { + error_report("Invalid PCI device address %s for device %s", + devaddr, nd->model); + exit(1); + } + + if (dom != 0) { + error_report("No support for non-zero PCI domains"); + exit(1); + } + + devfn = PCI_DEVFN(slot, 0); + } + + bus = pci_find_bus_nr(rootbus, busnr); if (!bus) { error_report("Invalid PCI device address %s for device %s", devaddr, nd->model); @@ -2048,18 +2112,6 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) } } -static void pci_default_realize(PCIDevice *dev, Error **errp) -{ - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); - - if (pc->init) { - if (pc->init(dev) < 0) { - error_setg(errp, "Device initialization failed"); - return; - } - } -} - PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name) { @@ -2263,7 +2315,11 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, pdev->has_rom = true; memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, size, &error_fatal); ptr = memory_region_get_ram_ptr(&pdev->rom); - load_image(path, ptr); + if (load_image_size(path, ptr, size) < 0) { + error_setg(errp, "failed to load romfile \"%s\"", pdev->romfile); + g_free(path); + return; + } g_free(path); if (is_default_rom) { @@ -2532,13 +2588,11 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev) static void pci_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); - PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); k->realize = pci_qdev_realize; k->unrealize = pci_qdev_unrealize; k->bus_type = TYPE_PCI_BUS; k->props = pci_props; - pc->realize = pci_default_realize; } static void pci_device_class_base_init(ObjectClass *klass, void *data)