}
};
+static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
static void pci_update_mappings(PCIDevice *d);
static void pci_set_irq(void *opaque, int irq_num, int level);
static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom);
VMSTATE_END_OF_LIST()
}
};
-
static int pci_bar(PCIDevice *d, int reg)
{
uint8_t type;
* Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
* [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
*/
-int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
unsigned int *slotp, unsigned int *funcp)
{
const char *p;
if (*e)
return -1;
- /* Note: QEMU doesn't implement domains other than 0 */
- if (!pci_find_bus(pci_find_root_bus(dom), bus))
- return -1;
-
*domp = dom;
*busp = bus;
*slotp = slot;
if (!devaddr) {
*devfnp = -1;
- return pci_find_bus(pci_find_root_bus(0), 0);
+ return pci_find_bus_nr(pci_find_root_bus(0), 0);
}
if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
}
*devfnp = PCI_DEVFN(slot, 0);
- return pci_find_bus(pci_find_root_bus(dom), bus);
+ return pci_find_bus_nr(pci_find_root_bus(dom), bus);
}
static void pci_init_cmask(PCIDevice *dev)
PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
}
-static void pci_init_wmask_bridge(PCIDevice *d)
+static void pci_init_mask_bridge(PCIDevice *d)
{
/* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and
PCI_SEC_LETENCY_TIMER */
/* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */
memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);
+ /* Supported memory and i/o types */
+ d->config[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_16;
+ d->config[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_16;
+ pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_BASE,
+ PCI_PREF_RANGE_TYPE_64);
+ pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
+ PCI_PREF_RANGE_TYPE_64);
+
/* TODO: add this define to pci_regs.h in linux and then in qemu. */
#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */
#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */
* completeness. */
pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_DISCARD_STATUS);
+ d->cmask[PCI_IO_BASE] |= PCI_IO_RANGE_TYPE_MASK;
+ d->cmask[PCI_IO_LIMIT] |= PCI_IO_RANGE_TYPE_MASK;
+ pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_BASE,
+ PCI_PREF_RANGE_TYPE_MASK);
+ pci_word_test_and_set_mask(d->cmask + PCI_PREF_MEMORY_LIMIT,
+ PCI_PREF_RANGE_TYPE_MASK);
}
static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
/* -1 for devfn means auto assign */
static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
- const char *name, int devfn,
- const PCIDeviceInfo *info)
+ const char *name, int devfn)
{
- PCIConfigReadFunc *config_read = info->config_read;
- PCIConfigWriteFunc *config_write = info->config_write;
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
+ PCIConfigReadFunc *config_read = pc->config_read;
+ PCIConfigWriteFunc *config_write = pc->config_write;
if (devfn < 0) {
for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
pci_dev->irq_state = 0;
pci_config_alloc(pci_dev);
- pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
- pci_config_set_device_id(pci_dev->config, info->device_id);
- pci_config_set_revision(pci_dev->config, info->revision);
- pci_config_set_class(pci_dev->config, info->class_id);
+ pci_config_set_vendor_id(pci_dev->config, pc->vendor_id);
+ pci_config_set_device_id(pci_dev->config, pc->device_id);
+ pci_config_set_revision(pci_dev->config, pc->revision);
+ pci_config_set_class(pci_dev->config, pc->class_id);
- if (!info->is_bridge) {
- if (info->subsystem_vendor_id || info->subsystem_id) {
+ if (!pc->is_bridge) {
+ if (pc->subsystem_vendor_id || pc->subsystem_id) {
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
- info->subsystem_vendor_id);
+ pc->subsystem_vendor_id);
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
- info->subsystem_id);
+ pc->subsystem_id);
} else {
pci_set_default_subsystem_id(pci_dev);
}
} else {
/* subsystem_vendor_id/subsystem_id are only for header type 0 */
- assert(!info->subsystem_vendor_id);
- assert(!info->subsystem_id);
+ assert(!pc->subsystem_vendor_id);
+ assert(!pc->subsystem_id);
}
pci_init_cmask(pci_dev);
pci_init_wmask(pci_dev);
pci_init_w1cmask(pci_dev);
- if (info->is_bridge) {
- pci_init_wmask_bridge(pci_dev);
+ if (pc->is_bridge) {
+ pci_init_mask_bridge(pci_dev);
}
if (pci_init_multifunction(bus, pci_dev)) {
pci_config_free(pci_dev);
pci_config_free(pci_dev);
}
-/* TODO: obsolete. eliminate this once all pci devices are qdevifed. */
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
- int instance_size, int devfn,
- PCIConfigReadFunc *config_read,
- PCIConfigWriteFunc *config_write)
-{
- PCIDevice *pci_dev;
- PCIDeviceInfo info = {
- .config_read = config_read,
- .config_write = config_write,
- };
-
- pci_dev = g_malloc0(instance_size);
- pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);
- if (pci_dev == NULL) {
- hw_error("PCI: can't register device\n");
- }
- return pci_dev;
-}
-
static void pci_unregister_io_regions(PCIDevice *pci_dev)
{
PCIIORegion *r;
static int pci_unregister_device(DeviceState *dev)
{
- PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
- PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->info);
+ PCIDevice *pci_dev = PCI_DEVICE(dev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
int ret = 0;
- if (info->exit)
- ret = info->exit(pci_dev);
+ if (pc->exit)
+ ret = pc->exit(pci_dev);
if (ret)
return ret;
pci_unregister_io_regions(pci_dev);
pci_del_option_rom(pci_dev);
- g_free(pci_dev->romfile);
do_pci_unregister_device(pci_dev);
return 0;
}
void pci_for_each_device(PCIBus *bus, int bus_num,
void (*fn)(PCIBus *b, PCIDevice *d))
{
- bus = pci_find_bus(bus, bus_num);
+ bus = pci_find_bus_nr(bus, bus_num);
if (bus) {
pci_for_each_device_under_bus(bus, fn);
info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
if (dev->config[PCI_SECONDARY_BUS] != 0) {
- PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
+ PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]);
if (child_bus) {
info->has_devices = true;
info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
{
PciInfo *info = NULL;
- bus = pci_find_bus(bus, bus_num);
+ bus = pci_find_bus_nr(bus, bus_num);
if (bus) {
info = g_malloc0(sizeof(*info));
info->bus = bus_num;
bus_num <= dev->config[PCI_SUBORDINATE_BUS];
}
-PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
+static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
{
PCIBus *sec;
PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
{
- bus = pci_find_bus(bus, bus_num);
+ bus = pci_find_bus_nr(bus, bus_num);
if (!bus)
return NULL;
return bus->devices[devfn];
}
-static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int pci_qdev_init(DeviceState *qdev)
{
PCIDevice *pci_dev = (PCIDevice *)qdev;
- PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
PCIBus *bus;
int rc;
bool is_default_rom;
/* initialize cap_present for pci_is_express() and pci_config_size() */
- if (info->is_express) {
+ if (pc->is_express) {
pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
- pci_dev = do_pci_register_device(pci_dev, bus, base->name,
- pci_dev->devfn, info);
+ pci_dev = do_pci_register_device(pci_dev, bus,
+ object_get_typename(OBJECT(qdev)),
+ pci_dev->devfn);
if (pci_dev == NULL)
return -1;
- if (qdev->hotplugged && info->no_hotplug) {
- qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+ if (qdev->hotplugged && pc->no_hotplug) {
+ qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev)));
do_pci_unregister_device(pci_dev);
return -1;
}
- if (info->init) {
- rc = info->init(pci_dev);
+ if (pc->init) {
+ rc = pc->init(pci_dev);
if (rc != 0) {
do_pci_unregister_device(pci_dev);
return rc;
/* rom loading */
is_default_rom = false;
- if (pci_dev->romfile == NULL && info->romfile != NULL) {
- pci_dev->romfile = g_strdup(info->romfile);
+ if (pci_dev->romfile == NULL && pc->romfile != NULL) {
+ pci_dev->romfile = g_strdup(pc->romfile);
is_default_rom = true;
}
pci_add_option_rom(pci_dev, is_default_rom);
static int pci_unplug_device(DeviceState *qdev)
{
- PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
- PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+ PCIDevice *dev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- if (info->no_hotplug) {
- qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+ if (pc->no_hotplug) {
+ qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
return -1;
}
+ object_unparent(OBJECT(dev));
return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
PCI_HOTPLUG_DISABLED);
}
-void pci_qdev_register(PCIDeviceInfo *info)
-{
- info->qdev.init = pci_qdev_init;
- info->qdev.unplug = pci_unplug_device;
- info->qdev.exit = pci_unregister_device;
- info->qdev.bus_info = &pci_bus_info;
- qdev_register(&info->qdev);
-}
-
-void pci_qdev_register_many(PCIDeviceInfo *info)
-{
- while (info->qdev.name) {
- pci_qdev_register(info);
- info++;
- }
-}
-
PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
const char *name)
{
dev = qdev_create(&bus->qbus, name);
qdev_prop_set_uint32(dev, "addr", devfn);
qdev_prop_set_bit(dev, "multifunction", multifunction);
- return DO_UPCAST(PCIDevice, qdev, dev);
+ return PCI_DEVICE(dev);
}
PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
char *path;
void *ptr;
char name[32];
+ const VMStateDescription *vmsd;
if (!pdev->romfile)
return 0;
size = 1 << qemu_fls(size);
}
- if (pdev->qdev.info->vmsd)
- snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
- else
- snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
+ vmsd = qdev_get_vmsd(DEVICE(pdev));
+
+ if (vmsd) {
+ snprintf(name, sizeof(name), "%s.rom", vmsd->name);
+ } else {
+ snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev)));
+ }
pdev->has_rom = true;
memory_region_init_ram(&pdev->rom, name, size);
vmstate_register_ram(&pdev->rom, &pdev->qdev);
}
/* roughly check if given qdev is pci device */
- if (qdev->info->init == &pci_qdev_init &&
- qdev->parent_bus->info == &pci_bus_info) {
- *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+ if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) {
+ *pdev = PCI_DEVICE(qdev);
return 0;
}
return -EINVAL;
{
return dev->bus->address_space_io;
}
+
+static void pci_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = pci_qdev_init;
+ k->unplug = pci_unplug_device;
+ k->exit = pci_unregister_device;
+ k->bus_info = &pci_bus_info;
+}
+
+static TypeInfo pci_device_type_info = {
+ .name = TYPE_PCI_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .abstract = true,
+ .class_size = sizeof(PCIDeviceClass),
+ .class_init = pci_device_class_init,
+};
+
+static void pci_register_types(void)
+{
+ type_register_static(&pci_device_type_info);
+}
+
+type_init(pci_register_types)