eepro100: Simplified device instantiation

By using a private device info structure
(as suggested by Gerd Hoffmann), handling of the
different device variants becomes much easier.

Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Stefan Weil 2010-04-06 13:44:03 +02:00 committed by Michael S. Tsirkin
parent 75f5a6cccd
commit 558c86345a
1 changed files with 167 additions and 280 deletions

View File

@ -117,6 +117,16 @@
#define INT_MASK 0x0100 #define INT_MASK 0x0100
#define DRVR_INT 0x0200 /* Driver generated interrupt. */ #define DRVR_INT 0x0200 /* Driver generated interrupt. */
typedef struct {
PCIDeviceInfo pci;
uint32_t device;
uint16_t device_id;
uint8_t revision;
uint8_t stats_size;
bool has_extended_tcb_support;
bool power_management;
} E100PCIDeviceInfo;
/* Offsets to the various registers. /* Offsets to the various registers.
All accesses need not be longword aligned. */ All accesses need not be longword aligned. */
enum speedo_offsets { enum speedo_offsets {
@ -443,136 +453,70 @@ static void eepro100_fcp_interrupt(EEPRO100State * s)
} }
#endif #endif
static void pci_reset(EEPRO100State * s) static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
{ {
/* TODO: Use pci_add_capability(&s->dev, PCI_CAP_ID_PM, ...) for PM. */
uint32_t device = s->device; uint32_t device = s->device;
uint8_t *pci_conf = s->dev.config; uint8_t *pci_conf = s->dev.config;
bool power_management = 1;
TRACE(OTHER, logout("%p\n", s)); TRACE(OTHER, logout("%p\n", s));
/* PCI Vendor ID */ /* PCI Vendor ID */
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
/* PCI Device ID depends on device and is set below. */ /* PCI Device ID */
pci_config_set_device_id(pci_conf, e100_device->device_id);
/* PCI Status */ /* PCI Status */
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM | PCI_STATUS_FAST_BACK); if (e100_device->power_management) {
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
PCI_STATUS_FAST_BACK |
PCI_STATUS_CAP_LIST);
} else {
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
PCI_STATUS_FAST_BACK);
}
/* PCI Revision ID */ /* PCI Revision ID */
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x08); pci_config_set_revision(pci_conf, e100_device->revision);
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
/* PCI Latency Timer */ /* PCI Latency Timer */
pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */ pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */
/* Capability Pointer */ /* Capability Pointer */
/* TODO: revisions with power_management 1 use this but if (e100_device->power_management) {
* do not set new capability list bit in status register. */ pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0xdc);
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0xdc); } else {
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
}
/* Minimum Grant */ /* Minimum Grant */
pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08); pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
/* Maximum Latency */ /* Maximum Latency */
pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18); 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;
switch (device) { switch (device) {
case i82550: case i82550:
/* TODO: check device id. */
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
/* Revision ID: 0x0c, 0x0d, 0x0e. */
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0e);
/* TODO: check size of statistical counters. */
s->stats_size = 80;
/* TODO: check extended tcb support. */
s->has_extended_tcb_support = 1;
break;
case i82551: case i82551:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
/* Revision ID: 0x0f, 0x10. */
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0f);
/* TODO: check size of statistical counters. */
s->stats_size = 80;
s->has_extended_tcb_support = 1;
break;
case i82557A: case i82557A:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x01);
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
power_management = 0;
break;
case i82557B: case i82557B:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x02);
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
power_management = 0;
break;
case i82557C: case i82557C:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x03);
pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00);
power_management = 0;
break;
case i82558A: case i82558A:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x04);
s->stats_size = 76;
s->has_extended_tcb_support = 1;
break;
case i82558B: case i82558B:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x05);
s->stats_size = 76;
s->has_extended_tcb_support = 1;
break;
case i82559A: case i82559A:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x06);
s->stats_size = 80;
s->has_extended_tcb_support = 1;
break;
case i82559B: case i82559B:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557); case i82559ER:
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM | case i82562:
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x07);
s->stats_size = 80;
s->has_extended_tcb_support = 1;
break; break;
case i82559C: case i82559C:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557);
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x08);
/* TODO: Windows wants revision id 0x0c. */
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0c);
#if EEPROM_SIZE > 0 #if EEPROM_SIZE > 0
pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x8086); pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_INTEL);
pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0040); pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0040);
#endif #endif
s->stats_size = 80;
s->has_extended_tcb_support = 1;
break;
case i82559ER:
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
PCI_STATUS_FAST_BACK | PCI_STATUS_CAP_LIST);
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x09);
s->stats_size = 80;
s->has_extended_tcb_support = 1;
break;
case i82562:
/* TODO: check device id. */
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82551IT);
/* TODO: wrong revision id. */
pci_set_byte(pci_conf + PCI_REVISION_ID, 0x0e);
s->stats_size = 80;
s->has_extended_tcb_support = 1;
break; break;
default: default:
logout("Device %X is undefined!\n", device); logout("Device %X is undefined!\n", device);
} }
/* Standard statistical counters. */
s->configuration[6] |= BIT(5); s->configuration[6] |= BIT(5);
if (s->stats_size == 80) { if (s->stats_size == 80) {
@ -597,9 +541,9 @@ static void pci_reset(EEPRO100State * s)
} }
assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics)); assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
if (power_management) { if (e100_device->power_management) {
/* Power Management Capabilities */ /* Power Management Capabilities */
pci_set_byte(pci_conf + 0xdc, 0x01); pci_set_byte(pci_conf + 0xdc, PCI_CAP_ID_PM);
/* Next Item Pointer */ /* Next Item Pointer */
/* Capability ID */ /* Capability ID */
pci_set_word(pci_conf + 0xde, 0x7e21); pci_set_word(pci_conf + 0xde, 0x7e21);
@ -1904,15 +1848,17 @@ static NetClientInfo net_eepro100_info = {
.cleanup = nic_cleanup, .cleanup = nic_cleanup,
}; };
static int nic_init(PCIDevice *pci_dev, uint32_t device) static int e100_nic_init(PCIDevice *pci_dev)
{ {
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev); EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
pci_dev->qdev.info);
TRACE(OTHER, logout("\n")); TRACE(OTHER, logout("\n"));
s->device = device; s->device = e100_device->device;
pci_reset(s); e100_pci_reset(s, e100_device);
/* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM, /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
* i82559 and later support 64 or 256 word EEPROM. */ * i82559 and later support 64 or 256 word EEPROM. */
@ -1952,207 +1898,148 @@ static int nic_init(PCIDevice *pci_dev, uint32_t device)
return 0; return 0;
} }
static int pci_i82550_init(PCIDevice *pci_dev) static E100PCIDeviceInfo e100_devices[] = {
{
return nic_init(pci_dev, i82550);
}
static int pci_i82551_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82551);
}
static int pci_i82557a_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82557A);
}
static int pci_i82557b_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82557B);
}
static int pci_i82557c_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82557C);
}
static int pci_i82558a_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82558A);
}
static int pci_i82558b_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82558B);
}
static int pci_i82559a_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82559A);
}
static int pci_i82559b_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82559B);
}
static int pci_i82559c_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82559C);
}
static int pci_i82559er_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82559ER);
}
static int pci_i82562_init(PCIDevice *pci_dev)
{
return nic_init(pci_dev, i82562);
}
static PCIDeviceInfo eepro100_info[] = {
{ {
.qdev.name = "i82550", .pci.qdev.name = "i82550",
.qdev.desc = "Intel i82550 Ethernet", .pci.qdev.desc = "Intel i82550 Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82550,
.init = pci_i82550_init, /* TODO: check device id. */
.exit = pci_nic_uninit, .device_id = PCI_DEVICE_ID_INTEL_82551IT,
.romfile = "gpxe-eepro100-80861209.rom", /* Revision ID: 0x0c, 0x0d, 0x0e. */
.qdev.props = (Property[]) { .revision = 0x0e,
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), /* TODO: check size of statistical counters. */
DEFINE_PROP_END_OF_LIST(), .stats_size = 80,
}, /* TODO: check extended tcb support. */
.has_extended_tcb_support = true,
.power_management = true,
},{ },{
.qdev.name = "i82551", .pci.qdev.name = "i82551",
.qdev.desc = "Intel i82551 Ethernet", .pci.qdev.desc = "Intel i82551 Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82551,
.init = pci_i82551_init, .device_id = PCI_DEVICE_ID_INTEL_82551IT,
.exit = pci_nic_uninit, /* Revision ID: 0x0f, 0x10. */
.romfile = "gpxe-eepro100-80861209.rom", .revision = 0x0f,
.qdev.props = (Property[]) { /* TODO: check size of statistical counters. */
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), .stats_size = 80,
DEFINE_PROP_END_OF_LIST(), .has_extended_tcb_support = true,
}, .power_management = true,
},{ },{
.qdev.name = "i82557a", .pci.qdev.name = "i82557a",
.qdev.desc = "Intel i82557A Ethernet", .pci.qdev.desc = "Intel i82557A Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82557A,
.init = pci_i82557a_init, .device_id = PCI_DEVICE_ID_INTEL_82557,
.exit = pci_nic_uninit, .revision = 0x01,
.romfile = "gpxe-eepro100-80861229.rom", .power_management = false,
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
DEFINE_PROP_END_OF_LIST(),
},
},{ },{
.qdev.name = "i82557b", .pci.qdev.name = "i82557b",
.qdev.desc = "Intel i82557B Ethernet", .pci.qdev.desc = "Intel i82557B Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82557B,
.init = pci_i82557b_init, .device_id = PCI_DEVICE_ID_INTEL_82557,
.exit = pci_nic_uninit, .revision = 0x02,
.romfile = "gpxe-eepro100-80861229.rom", .power_management = false,
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
DEFINE_PROP_END_OF_LIST(),
},
},{ },{
.qdev.name = "i82557c", .pci.qdev.name = "i82557c",
.qdev.desc = "Intel i82557C Ethernet", .pci.qdev.desc = "Intel i82557C Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82557C,
.init = pci_i82557c_init, .device_id = PCI_DEVICE_ID_INTEL_82557,
.exit = pci_nic_uninit, .revision = 0x03,
.romfile = "gpxe-eepro100-80861229.rom", .power_management = false,
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
DEFINE_PROP_END_OF_LIST(),
},
},{ },{
.qdev.name = "i82558a", .pci.qdev.name = "i82558a",
.qdev.desc = "Intel i82558A Ethernet", .pci.qdev.desc = "Intel i82558A Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82558A,
.init = pci_i82558a_init, .device_id = PCI_DEVICE_ID_INTEL_82557,
.exit = pci_nic_uninit, .revision = 0x04,
.romfile = "gpxe-eepro100-80861229.rom", .stats_size = 76,
.qdev.props = (Property[]) { .has_extended_tcb_support = true,
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), .power_management = true,
DEFINE_PROP_END_OF_LIST(),
},
},{ },{
.qdev.name = "i82558b", .pci.qdev.name = "i82558b",
.qdev.desc = "Intel i82558B Ethernet", .pci.qdev.desc = "Intel i82558B Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82558B,
.init = pci_i82558b_init, .device_id = PCI_DEVICE_ID_INTEL_82557,
.exit = pci_nic_uninit, .revision = 0x05,
.romfile = "gpxe-eepro100-80861229.rom", .stats_size = 76,
.qdev.props = (Property[]) { .has_extended_tcb_support = true,
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), .power_management = true,
DEFINE_PROP_END_OF_LIST(),
},
},{ },{
.qdev.name = "i82559a", .pci.qdev.name = "i82559a",
.qdev.desc = "Intel i82559A Ethernet", .pci.qdev.desc = "Intel i82559A Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82559A,
.init = pci_i82559a_init, .device_id = PCI_DEVICE_ID_INTEL_82557,
.exit = pci_nic_uninit, .revision = 0x06,
.romfile = "gpxe-eepro100-80861229.rom", .stats_size = 80,
.qdev.props = (Property[]) { .has_extended_tcb_support = true,
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), .power_management = true,
DEFINE_PROP_END_OF_LIST(),
},
},{ },{
.qdev.name = "i82559b", .pci.qdev.name = "i82559b",
.qdev.desc = "Intel i82559B Ethernet", .pci.qdev.desc = "Intel i82559B Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82559B,
.init = pci_i82559b_init, .device_id = PCI_DEVICE_ID_INTEL_82557,
.exit = pci_nic_uninit, .revision = 0x07,
.romfile = "gpxe-eepro100-80861229.rom", .stats_size = 80,
.qdev.props = (Property[]) { .has_extended_tcb_support = true,
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), .power_management = true,
DEFINE_PROP_END_OF_LIST(),
},
},{ },{
.qdev.name = "i82559c", .pci.qdev.name = "i82559c",
.qdev.desc = "Intel i82559C Ethernet", .pci.qdev.desc = "Intel i82559C Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82559C,
.init = pci_i82559c_init, .device_id = PCI_DEVICE_ID_INTEL_82557,
.exit = pci_nic_uninit, #if 0
.romfile = "gpxe-eepro100-80861229.rom", .revision = 0x08,
.qdev.props = (Property[]) { #endif
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), /* TODO: Windows wants revision id 0x0c. */
DEFINE_PROP_END_OF_LIST(), .revision = 0x0c,
}, .stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{ },{
.qdev.name = "i82559er", .pci.qdev.name = "i82559er",
.qdev.desc = "Intel i82559ER Ethernet", .pci.qdev.desc = "Intel i82559ER Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82559ER,
.init = pci_i82559er_init, .device_id = PCI_DEVICE_ID_INTEL_82551IT,
.exit = pci_nic_uninit, .revision = 0x09,
.romfile = "gpxe-eepro100-80861209.rom", .stats_size = 80,
.qdev.props = (Property[]) { .has_extended_tcb_support = true,
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), .power_management = true,
DEFINE_PROP_END_OF_LIST(),
},
},{ },{
.qdev.name = "i82562", .pci.qdev.name = "i82562",
.qdev.desc = "Intel i82562 Ethernet", .pci.qdev.desc = "Intel i82562 Ethernet",
.qdev.size = sizeof(EEPRO100State), .device = i82562,
.init = pci_i82562_init, /* TODO: check device id. */
.exit = pci_nic_uninit, .device_id = PCI_DEVICE_ID_INTEL_82551IT,
.romfile = "gpxe-eepro100-80861209.rom", /* TODO: wrong revision id. */
.qdev.props = (Property[]) { .revision = 0x0e,
DEFINE_NIC_PROPERTIES(EEPRO100State, conf), .stats_size = 80,
DEFINE_PROP_END_OF_LIST(), .has_extended_tcb_support = true,
}, .power_management = true,
},{
/* end of list */
} }
}; };
static Property e100_properties[] = {
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
DEFINE_PROP_END_OF_LIST(),
};
static void eepro100_register_devices(void) static void eepro100_register_devices(void)
{ {
pci_qdev_register_many(eepro100_info); size_t i;
for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
switch (e100_devices[i].device_id) {
case PCI_DEVICE_ID_INTEL_82551IT:
pci_dev->romfile = "gpxe-eepro100-80861209.rom";
break;
case PCI_DEVICE_ID_INTEL_82557:
pci_dev->romfile = "gpxe-eepro100-80861229.rom";
break;
}
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);
}
} }
device_init(eepro100_register_devices) device_init(eepro100_register_devices)