#include "hw/loader.h"
#include "qemu/error-report.h"
#include "qemu/range.h"
-#include "qmp-commands.h"
#include "trace.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/hotplug.h"
#include "hw/boards.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
#include "qemu/cutils.h"
//#define DEBUG_PCI
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);
pci_host_bus_register(parent);
}
+static void pci_bus_uninit(PCIBus *bus)
+{
+ pci_host_bus_unregister(BUS(bus)->parent);
+}
+
bool pci_bus_is_express(PCIBus *bus)
{
return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
return bus;
}
+void pci_root_bus_cleanup(PCIBus *bus)
+{
+ pci_bus_uninit(bus);
+ object_unparent(OBJECT(bus));
+}
+
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;
}
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);
}
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;
return head;
}
-static const char * const pci_nic_models[] = {
- "ne2k_pci",
- "i82551",
- "i82557b",
- "i82559er",
- "rtl8139",
- "e1000",
- "pcnet",
- "virtio",
- "sungem",
- NULL
-};
-
-static const char * const pci_nic_names[] = {
- "ne2k_pci",
- "i82551",
- "i82557b",
- "i82559er",
- "rtl8139",
- "e1000",
- "pcnet",
- "virtio-net-pci",
- "sungem",
- NULL
-};
-
/* Initialize a PCI NIC. */
PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
const char *default_model,
const char *default_devaddr)
{
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
+ GSList *list;
+ GPtrArray *pci_nic_models;
PCIBus *bus;
PCIDevice *pci_dev;
DeviceState *dev;
int devfn;
int i;
- if (qemu_show_nic_models(nd->model, pci_nic_models)) {
+ if (nd->model && !strcmp(nd->model, "virtio")) {
+ g_free(nd->model);
+ nd->model = g_strdup("virtio-net-pci");
+ }
+
+ list = object_class_get_list_sorted(TYPE_PCI_DEVICE, false);
+ pci_nic_models = g_ptr_array_new();
+ while (list) {
+ DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data,
+ TYPE_DEVICE);
+ GSList *next;
+ 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);
+ }
+ next = list->next;
+ g_slist_free_1(list);
+ list = next;
+ }
+ g_ptr_array_add(pci_nic_models, NULL);
+
+ if (qemu_show_nic_models(nd->model, (const char **)pci_nic_models->pdata)) {
exit(0);
}
- i = qemu_find_nic_model(nd, pci_nic_models, default_model);
+ i = qemu_find_nic_model(nd, (const char **)pci_nic_models->pdata,
+ default_model);
if (i < 0) {
exit(1);
}
bus = pci_get_bus_devfn(&devfn, rootbus, devaddr);
if (!bus) {
error_report("Invalid PCI device address %s for device %s",
- devaddr, pci_nic_names[i]);
+ devaddr, nd->model);
exit(1);
}
- pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
+ pci_dev = pci_create(bus, devfn, nd->model);
dev = &pci_dev->qdev;
qdev_set_nic_properties(dev, nd);
qdev_init_nofail(dev);
-
+ g_ptr_array_free(pci_nic_models, true);
return pci_dev;
}
}
}
-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)
{
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) {
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)