diff options
Diffstat (limited to 'hw/eepro100.c')
-rw-r--r-- | hw/eepro100.c | 200 |
1 files changed, 125 insertions, 75 deletions
diff --git a/hw/eepro100.c b/hw/eepro100.c index f0059c6ce7..9f6d3336f0 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -128,7 +128,13 @@ #define DRVR_INT 0x0200 /* Driver generated interrupt. */ typedef struct { - PCIDeviceInfo pci; + DeviceInfo qdev; + + uint16_t device_id; + uint8_t revision; + uint16_t subsystem_vendor_id; + uint16_t subsystem_id; + uint32_t device; uint8_t stats_size; bool has_extended_tcb_support; @@ -318,6 +324,8 @@ static const uint16_t eepro100_mdi_mask[] = { #define POLYNOMIAL 0x04c11db6 +static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s); + /* From FreeBSD */ /* XXX: optimize */ static unsigned compute_mcast_idx(const uint8_t * ep) @@ -487,8 +495,9 @@ static void eepro100_fcp_interrupt(EEPRO100State * s) } #endif -static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) +static void e100_pci_reset(EEPRO100State * s) { + E100PCIDeviceInfo *info = eepro100_get_class(s); uint32_t device = s->device; uint8_t *pci_conf = s->dev.config; @@ -508,8 +517,8 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) /* Maximum Latency */ pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18); - s->stats_size = e100_device->stats_size; - s->has_extended_tcb_support = e100_device->has_extended_tcb_support; + s->stats_size = info->stats_size; + s->has_extended_tcb_support = info->has_extended_tcb_support; switch (device) { case i82550: @@ -558,7 +567,7 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) } assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics)); - if (e100_device->power_management) { + if (info->power_management) { /* Power Management Capabilities */ int cfg_offset = 0xdc; int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM, @@ -1847,14 +1856,13 @@ static NetClientInfo net_eepro100_info = { static int e100_nic_init(PCIDevice *pci_dev) { EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev); - E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev, - qdev_get_info(&pci_dev->qdev)); + E100PCIDeviceInfo *info = eepro100_get_class(s); TRACE(OTHER, logout("\n")); - s->device = e100_device->device; + s->device = info->device; - e100_pci_reset(s, e100_device); + e100_pci_reset(s); /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM, * i82559 and later support 64 or 256 word EEPROM. */ @@ -1897,136 +1905,182 @@ static int e100_nic_init(PCIDevice *pci_dev) static E100PCIDeviceInfo e100_devices[] = { { - .pci.qdev.name = "i82550", - .pci.qdev.desc = "Intel i82550 Ethernet", + .qdev.name = "i82550", + .qdev.desc = "Intel i82550 Ethernet", .device = i82550, /* TODO: check device id. */ - .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, /* Revision ID: 0x0c, 0x0d, 0x0e. */ - .pci.revision = 0x0e, + .revision = 0x0e, /* TODO: check size of statistical counters. */ .stats_size = 80, /* TODO: check extended tcb support. */ .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82551", - .pci.qdev.desc = "Intel i82551 Ethernet", + .qdev.name = "i82551", + .qdev.desc = "Intel i82551 Ethernet", .device = i82551, - .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, /* Revision ID: 0x0f, 0x10. */ - .pci.revision = 0x0f, + .revision = 0x0f, /* TODO: check size of statistical counters. */ .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82557a", - .pci.qdev.desc = "Intel i82557A Ethernet", + .qdev.name = "i82557a", + .qdev.desc = "Intel i82557A Ethernet", .device = i82557A, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x01, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x01, .power_management = false, },{ - .pci.qdev.name = "i82557b", - .pci.qdev.desc = "Intel i82557B Ethernet", + .qdev.name = "i82557b", + .qdev.desc = "Intel i82557B Ethernet", .device = i82557B, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x02, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x02, .power_management = false, },{ - .pci.qdev.name = "i82557c", - .pci.qdev.desc = "Intel i82557C Ethernet", + .qdev.name = "i82557c", + .qdev.desc = "Intel i82557C Ethernet", .device = i82557C, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x03, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x03, .power_management = false, },{ - .pci.qdev.name = "i82558a", - .pci.qdev.desc = "Intel i82558A Ethernet", + .qdev.name = "i82558a", + .qdev.desc = "Intel i82558A Ethernet", .device = i82558A, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x04, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x04, .stats_size = 76, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82558b", - .pci.qdev.desc = "Intel i82558B Ethernet", + .qdev.name = "i82558b", + .qdev.desc = "Intel i82558B Ethernet", .device = i82558B, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x05, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x05, .stats_size = 76, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82559a", - .pci.qdev.desc = "Intel i82559A Ethernet", + .qdev.name = "i82559a", + .qdev.desc = "Intel i82559A Ethernet", .device = i82559A, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x06, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x06, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82559b", - .pci.qdev.desc = "Intel i82559B Ethernet", + .qdev.name = "i82559b", + .qdev.desc = "Intel i82559B Ethernet", .device = i82559B, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x07, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x07, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82559c", - .pci.qdev.desc = "Intel i82559C Ethernet", + .qdev.name = "i82559c", + .qdev.desc = "Intel i82559C Ethernet", .device = i82559C, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, + .device_id = PCI_DEVICE_ID_INTEL_82557, #if 0 - .pci.revision = 0x08, + .revision = 0x08, #endif /* TODO: Windows wants revision id 0x0c. */ - .pci.revision = 0x0c, + .revision = 0x0c, #if EEPROM_SIZE > 0 - .pci.subsystem_vendor_id = PCI_VENDOR_ID_INTEL, - .pci.subsystem_id = 0x0040, + .subsystem_vendor_id = PCI_VENDOR_ID_INTEL, + .subsystem_id = 0x0040, #endif .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82559er", - .pci.qdev.desc = "Intel i82559ER Ethernet", + .qdev.name = "i82559er", + .qdev.desc = "Intel i82559ER Ethernet", .device = i82559ER, - .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT, - .pci.revision = 0x09, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, + .revision = 0x09, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82562", - .pci.qdev.desc = "Intel i82562 Ethernet", + .qdev.name = "i82562", + .qdev.desc = "Intel i82562 Ethernet", .device = i82562, /* TODO: check device id. */ - .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, /* TODO: wrong revision id. */ - .pci.revision = 0x0e, + .revision = 0x0e, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ /* Toshiba Tecra 8200. */ - .pci.qdev.name = "i82801", - .pci.qdev.desc = "Intel i82801 Ethernet", + .qdev.name = "i82801", + .qdev.desc = "Intel i82801 Ethernet", .device = i82801, - .pci.device_id = 0x2449, - .pci.revision = 0x03, + .device_id = 0x2449, + .revision = 0x03, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, } }; +static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename) +{ + E100PCIDeviceInfo *info = NULL; + int i; + + /* This is admittedly awkward but also temporary. QOM allows for + * parameterized typing and for subclassing both of which would suitable + * handle what's going on here. But class_data is already being used as + * a stop-gap hack to allow incremental qdev conversion so we cannot use it + * right now. Once we merge the final QOM series, we can come back here and + * do this in a much more elegant fashion. + */ + for (i = 0; i < ARRAY_SIZE(e100_devices); i++) { + if (strcmp(e100_devices[i].qdev.name, typename) == 0) { + info = &e100_devices[i]; + break; + } + } + assert(info != NULL); + + return info; +} + +static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s) +{ + return eepro100_get_class_by_name(object_get_typename(OBJECT(s))); +} + +static void eepro100_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + E100PCIDeviceInfo *info; + + info = eepro100_get_class_by_name(object_class_get_name(klass)); + + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + k->romfile = "pxe-eepro100.rom"; + k->init = e100_nic_init; + k->exit = pci_nic_uninit; + k->device_id = info->device_id; + k->revision = info->revision; + k->subsystem_vendor_id = info->subsystem_vendor_id; + k->subsystem_id = info->subsystem_id; +} + static Property e100_properties[] = { DEFINE_NIC_PROPERTIES(EEPRO100State, conf), DEFINE_PROP_END_OF_LIST(), @@ -2036,17 +2090,13 @@ static void eepro100_register_devices(void) { size_t i; for (i = 0; i < ARRAY_SIZE(e100_devices); i++) { - PCIDeviceInfo *pci_dev = &e100_devices[i].pci; - /* We use the same rom file for all device ids. - QEMU fixes the device id during rom load. */ - pci_dev->vendor_id = PCI_VENDOR_ID_INTEL; - pci_dev->class_id = PCI_CLASS_NETWORK_ETHERNET; - pci_dev->romfile = "pxe-eepro100.rom"; - pci_dev->init = e100_nic_init; - pci_dev->exit = pci_nic_uninit; - pci_dev->qdev.props = e100_properties; - pci_dev->qdev.size = sizeof(EEPRO100State); - pci_qdev_register(pci_dev); + DeviceInfo *info = &e100_devices[i].qdev; + + info->class_init = eepro100_class_init; + info->size = sizeof(EEPRO100State); + info->props = e100_properties; + + pci_qdev_register(info); } } |