*/
#include "qemu/osdep.h"
+#include "qemu-common.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
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];
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;
}
.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);
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)
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);
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);
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,
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)
{
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,
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);
}
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);
/* 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)));
};
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];
}
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);
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()
}
};
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;
/* 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;
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);
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;
}
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);
{
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);
}
*/
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);
}
/***********************************************************/
info->id = g_new0(PciDeviceId, 1);
info->id->vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
info->id->device = pci_get_word(dev->config + PCI_DEVICE_ID);
- info->id->subsystem = pci_get_word(dev->config + PCI_SUBSYSTEM_ID);
- info->id->subsystem_vendor =
- pci_get_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID);
info->regions = qmp_query_pci_regions(dev);
info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
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;
DeviceState *dev;
int devfn;
int i;
+ int dom, busnr;
+ unsigned slot;
if (nd->model && !strcmp(nd->model, "virtio")) {
g_free(nd->model);
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);
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) {