From e74818f3cd439e29aa18935631663e9abb84a302 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 6 Apr 2010 13:44:01 +0200 Subject: [PATCH 01/13] eepro100: Don't allow writing SCBStatus SCBStatus is readonly, but most drivers which were derived from the old Linux eepro100.c do a word write to this address when they want to acknowledge interrupts. So we have to mask these writes here. The patch also removes old unused code for status read / write. Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/eepro100.c | 49 +++++-------------------------------------------- 1 file changed, 5 insertions(+), 44 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 7db6fb5a70..041513288a 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -237,10 +237,6 @@ typedef struct { /* Statistical counters. Also used for wake-up packet (i82559). */ eepro100_stats_t statistics; -#if 0 - uint16_t status; -#endif - /* Configuration bytes. */ uint8_t configuration[22]; @@ -693,21 +689,6 @@ static char *regname(uint32_t addr) } #endif /* DEBUG_EEPRO100 */ -#if 0 -static uint16_t eepro100_read_status(EEPRO100State * s) -{ - uint16_t val = s->status; - TRACE(OTHER, logout("val=0x%04x\n", val)); - return val; -} - -static void eepro100_write_status(EEPRO100State * s, uint16_t val) -{ - TRACE(OTHER, logout("val=0x%04x\n", val)); - s->status = val; -} -#endif - /***************************************************************************** * * Command emulation. @@ -1364,15 +1345,7 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr) switch (addr) { case SCBStatus: -#if 0 - val = eepro100_read_status(s); -#endif - TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val)); - break; case SCBAck: -#if 0 - val = eepro100_read_status(s); -#endif TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val)); break; case SCBCmd: @@ -1415,9 +1388,6 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr) switch (addr) { case SCBStatus: -#if 0 - val = eepro100_read_status(s); -#endif case SCBCmd: TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val)); break; @@ -1441,9 +1411,6 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr) switch (addr) { case SCBStatus: -#if 0 - val = eepro100_read_status(s); -#endif TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val)); break; case SCBPointer: @@ -1468,7 +1435,8 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr) static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val) { - if (addr <= sizeof(s->mem) - sizeof(val)) { + /* SCBStatus is readonly. */ + if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) { memcpy(&s->mem[addr], &val, sizeof(val)); } @@ -1476,9 +1444,6 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val) switch (addr) { case SCBStatus: -#if 0 - eepro100_write_status(s, val); -#endif break; case SCBAck: eepro100_acknowledge(s); @@ -1510,7 +1475,8 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val) static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val) { - if (addr <= sizeof(s->mem) - sizeof(val)) { + /* SCBStatus is readonly. */ + if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) { memcpy(&s->mem[addr], &val, sizeof(val)); } @@ -1518,9 +1484,7 @@ static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val) switch (addr) { case SCBStatus: -#if 0 - eepro100_write_status(s, val); -#endif + s->mem[SCBAck] = (val >> 8); eepro100_acknowledge(s); break; case SCBCmd: @@ -1908,9 +1872,6 @@ static const VMStateDescription vmstate_eepro100 = { VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State), VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State), VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State), -#if 0 - VMSTATE_UINT16(status, EEPRO100State), -#endif /* Configuration bytes. */ VMSTATE_BUFFER(configuration, EEPRO100State), VMSTATE_END_OF_LIST() From 75f5a6cccdc76a025cb460d53bb7509a2b5d7548 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 6 Apr 2010 13:44:02 +0200 Subject: [PATCH 02/13] eepro100: Simplify status handling Includes a minor STATUS_NOT_OK -> 0 tweak. Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/eepro100.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 041513288a..90e7d8a10a 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -882,7 +882,7 @@ static void action_command(EEPRO100State *s) bool bit_s; bool bit_i; bool bit_nc; - bool success = true; + uint16_t ok_status = STATUS_OK; s->cb_address = s->cu_base + s->cu_offset; read_cb(s); bit_el = ((s->tx.command & COMMAND_EL) != 0); @@ -915,7 +915,7 @@ static void action_command(EEPRO100State *s) case CmdTx: if (bit_nc) { missing("CmdTx: NC = 0"); - success = false; + ok_status = 0; break; } tx_command(s); @@ -932,11 +932,11 @@ static void action_command(EEPRO100State *s) break; default: missing("undefined command"); - success = false; + ok_status = 0; break; } /* Write new status. */ - stw_phys(s->cb_address, s->tx.status | STATUS_C | (success ? STATUS_OK : 0)); + stw_phys(s->cb_address, s->tx.status | ok_status | STATUS_C); if (bit_i) { /* CU completed action. */ eepro100_cx_interrupt(s); From 558c86345a8bacd8c763a9184baa169362fe3a43 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 6 Apr 2010 13:44:03 +0200 Subject: [PATCH 03/13] 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 Signed-off-by: Michael S. Tsirkin --- hw/eepro100.c | 447 +++++++++++++++++++------------------------------- 1 file changed, 167 insertions(+), 280 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 90e7d8a10a..9f63893887 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -117,6 +117,16 @@ #define INT_MASK 0x0100 #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. All accesses need not be longword aligned. */ enum speedo_offsets { @@ -443,136 +453,70 @@ static void eepro100_fcp_interrupt(EEPRO100State * s) } #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; uint8_t *pci_conf = s->dev.config; - bool power_management = 1; TRACE(OTHER, logout("%p\n", s)); /* PCI Vendor ID */ 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_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_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 Latency Timer */ pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */ /* Capability Pointer */ - /* TODO: revisions with power_management 1 use this but - * do not set new capability list bit in status register. */ - pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0xdc); + if (e100_device->power_management) { + pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0xdc); + } else { + pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00); + } /* Minimum Grant */ pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08); /* 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; + switch (device) { 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: - 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: - 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: - 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: - 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: - 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: - 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: - 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: - 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, 0x07); - s->stats_size = 80; - s->has_extended_tcb_support = 1; + case i82559ER: + case i82562: break; 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 - 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); #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; default: logout("Device %X is undefined!\n", device); } + /* Standard statistical counters. */ s->configuration[6] |= BIT(5); 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)); - if (power_management) { + if (e100_device->power_management) { /* Power Management Capabilities */ - pci_set_byte(pci_conf + 0xdc, 0x01); + pci_set_byte(pci_conf + 0xdc, PCI_CAP_ID_PM); /* Next Item Pointer */ /* Capability ID */ pci_set_word(pci_conf + 0xde, 0x7e21); @@ -1904,15 +1848,17 @@ static NetClientInfo net_eepro100_info = { .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); + E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev, + pci_dev->qdev.info); 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, * 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; } -static int pci_i82550_init(PCIDevice *pci_dev) -{ - 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[] = { +static E100PCIDeviceInfo e100_devices[] = { { - .qdev.name = "i82550", - .qdev.desc = "Intel i82550 Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82550_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861209.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82550", + .pci.qdev.desc = "Intel i82550 Ethernet", + .device = i82550, + /* TODO: check device id. */ + .device_id = PCI_DEVICE_ID_INTEL_82551IT, + /* Revision ID: 0x0c, 0x0d, 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, },{ - .qdev.name = "i82551", - .qdev.desc = "Intel i82551 Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82551_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861209.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82551", + .pci.qdev.desc = "Intel i82551 Ethernet", + .device = i82551, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, + /* Revision ID: 0x0f, 0x10. */ + .revision = 0x0f, + /* TODO: check size of statistical counters. */ + .stats_size = 80, + .has_extended_tcb_support = true, + .power_management = true, },{ - .qdev.name = "i82557a", - .qdev.desc = "Intel i82557A Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82557a_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861229.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82557a", + .pci.qdev.desc = "Intel i82557A Ethernet", + .device = i82557A, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x01, + .power_management = false, },{ - .qdev.name = "i82557b", - .qdev.desc = "Intel i82557B Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82557b_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861229.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82557b", + .pci.qdev.desc = "Intel i82557B Ethernet", + .device = i82557B, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x02, + .power_management = false, },{ - .qdev.name = "i82557c", - .qdev.desc = "Intel i82557C Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82557c_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861229.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82557c", + .pci.qdev.desc = "Intel i82557C Ethernet", + .device = i82557C, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x03, + .power_management = false, },{ - .qdev.name = "i82558a", - .qdev.desc = "Intel i82558A Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82558a_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861229.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82558a", + .pci.qdev.desc = "Intel i82558A Ethernet", + .device = i82558A, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x04, + .stats_size = 76, + .has_extended_tcb_support = true, + .power_management = true, },{ - .qdev.name = "i82558b", - .qdev.desc = "Intel i82558B Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82558b_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861229.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82558b", + .pci.qdev.desc = "Intel i82558B Ethernet", + .device = i82558B, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x05, + .stats_size = 76, + .has_extended_tcb_support = true, + .power_management = true, },{ - .qdev.name = "i82559a", - .qdev.desc = "Intel i82559A Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82559a_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861229.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82559a", + .pci.qdev.desc = "Intel i82559A Ethernet", + .device = i82559A, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x06, + .stats_size = 80, + .has_extended_tcb_support = true, + .power_management = true, },{ - .qdev.name = "i82559b", - .qdev.desc = "Intel i82559B Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82559b_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861229.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82559b", + .pci.qdev.desc = "Intel i82559B Ethernet", + .device = i82559B, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x07, + .stats_size = 80, + .has_extended_tcb_support = true, + .power_management = true, },{ - .qdev.name = "i82559c", - .qdev.desc = "Intel i82559C Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82559c_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861229.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82559c", + .pci.qdev.desc = "Intel i82559C Ethernet", + .device = i82559C, + .device_id = PCI_DEVICE_ID_INTEL_82557, +#if 0 + .revision = 0x08, +#endif + /* TODO: Windows wants revision id 0x0c. */ + .revision = 0x0c, + .stats_size = 80, + .has_extended_tcb_support = true, + .power_management = true, },{ - .qdev.name = "i82559er", - .qdev.desc = "Intel i82559ER Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82559er_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861209.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, + .pci.qdev.name = "i82559er", + .pci.qdev.desc = "Intel i82559ER Ethernet", + .device = i82559ER, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, + .revision = 0x09, + .stats_size = 80, + .has_extended_tcb_support = true, + .power_management = true, },{ - .qdev.name = "i82562", - .qdev.desc = "Intel i82562 Ethernet", - .qdev.size = sizeof(EEPRO100State), - .init = pci_i82562_init, - .exit = pci_nic_uninit, - .romfile = "gpxe-eepro100-80861209.rom", - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(EEPRO100State, conf), - DEFINE_PROP_END_OF_LIST(), - }, - },{ - /* end of list */ + .pci.qdev.name = "i82562", + .pci.qdev.desc = "Intel i82562 Ethernet", + .device = i82562, + /* TODO: check device id. */ + .device_id = PCI_DEVICE_ID_INTEL_82551IT, + /* TODO: wrong revision id. */ + .revision = 0x0e, + .stats_size = 80, + .has_extended_tcb_support = true, + .power_management = true, } }; +static Property e100_properties[] = { + DEFINE_NIC_PROPERTIES(EEPRO100State, conf), + DEFINE_PROP_END_OF_LIST(), +}; + 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) From db667a1205587d7b5123330f1f0dc506a9b06459 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 6 Apr 2010 13:44:04 +0200 Subject: [PATCH 04/13] eepro100: Add new device variant i82801 This ethernet device is used in Toshiba Tecra 8200 notebooks. Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/eepro100.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/eepro100.c b/hw/eepro100.c index 9f63893887..e74d3bb108 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -87,6 +87,7 @@ #define i82559C 0x82559c #define i82559ER 0x82559e #define i82562 0x82562 +#define i82801 0x82801 /* Use 64 word EEPROM. TODO: could be a runtime option. */ #define EEPROM_SIZE 64 @@ -505,6 +506,7 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) case i82559B: case i82559ER: case i82562: + case i82801: break; case i82559C: #if EEPROM_SIZE > 0 @@ -2013,6 +2015,16 @@ static E100PCIDeviceInfo e100_devices[] = { .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, + },{ + /* Toshiba Tecra 8200. */ + .pci.qdev.name = "i82801", + .pci.qdev.desc = "Intel i82801 Ethernet", + .device = i82801, + .device_id = 0x2449, + .revision = 0x03, + .stats_size = 80, + .has_extended_tcb_support = true, + .power_management = true, } }; @@ -2033,6 +2045,9 @@ static void eepro100_register_devices(void) case PCI_DEVICE_ID_INTEL_82557: pci_dev->romfile = "gpxe-eepro100-80861229.rom"; break; + case 0x2449: + pci_dev->romfile = "gpxe-eepro100-80862449.rom"; + break; } pci_dev->init = e100_nic_init; pci_dev->exit = pci_nic_uninit; From 3dec59a1fb5e1144b655e00cca693240cab0bc70 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 6 Apr 2010 13:44:05 +0200 Subject: [PATCH 05/13] eepro100: Set configuration bit for standard TCB For some devices, this bit is always set. For the others, it is set by default. Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/eepro100.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/eepro100.c b/hw/eepro100.c index e74d3bb108..32e670ec93 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -518,6 +518,9 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) logout("Device %X is undefined!\n", device); } + /* Standard TxCB. */ + s->configuration[6] |= BIT(4); + /* Standard statistical counters. */ s->configuration[6] |= BIT(5); From ae543b498ca75aee6cadd67cb308501f5f267418 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 6 Apr 2010 13:44:07 +0200 Subject: [PATCH 06/13] eepro100: Set power management capability using pci_reserve_capability pci_add_capability automatically updates PCI status and PCI capability pointer, so use it. Use pci_reserve_capability to make the new capability appear at the correct offset. Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/eepro100.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 32e670ec93..c7059296bb 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -456,7 +456,6 @@ static void eepro100_fcp_interrupt(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; uint8_t *pci_conf = s->dev.config; @@ -467,25 +466,14 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) /* PCI Device ID */ pci_config_set_device_id(pci_conf, e100_device->device_id); /* PCI Status */ - 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_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM | + PCI_STATUS_FAST_BACK); /* PCI Revision ID */ pci_config_set_revision(pci_conf, e100_device->revision); pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); /* PCI Latency Timer */ pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */ - /* Capability Pointer */ - if (e100_device->power_management) { - pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0xdc); - } else { - pci_set_byte(pci_conf + PCI_CAPABILITY_LIST, 0x00); - } + /* Capability Pointer is set by PCI framework. */ /* Minimum Grant */ pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08); /* Maximum Latency */ @@ -548,12 +536,21 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) if (e100_device->power_management) { /* Power Management Capabilities */ - pci_set_byte(pci_conf + 0xdc, PCI_CAP_ID_PM); - /* Next Item Pointer */ - /* Capability ID */ - pci_set_word(pci_conf + 0xde, 0x7e21); - /* TODO: Power Management Control / Status. */ - /* TODO: Ethernet Power Consumption Registers (i82559 and later). */ + int cfg_offset; + pci_reserve_capability(&s->dev, PCI_CONFIG_HEADER_SIZE, + 0xdc - PCI_CONFIG_HEADER_SIZE); + cfg_offset = pci_add_capability(&s->dev, PCI_CAP_ID_PM, PCI_PM_SIZEOF); + assert(cfg_offset == 0xdc); + if (cfg_offset > 0) { + /* Power Management Capabilities */ + pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21); +#if 0 /* TODO: replace dummy code for power management emulation. */ + /* TODO: Power Management Control / Status. */ + pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000); + /* TODO: Ethernet Power Consumption Registers (i82559 and later). */ + pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000); +#endif + } } #if EEPROM_SIZE > 0 From 269eba077104df9b4d6faedb4da1c2aa978e2b1d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 6 Apr 2010 13:44:08 +0200 Subject: [PATCH 07/13] eepro100: fix mapping of flash memory Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/eepro100.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index c7059296bb..949ca4ed2a 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1621,11 +1621,11 @@ static void pci_mmio_map(PCIDevice * pci_dev, int region_num, "size=0x%08"FMT_PCIBUS", type=%d\n", region_num, addr, size, type)); - if (region_num == 0) { - /* Map control / status registers. */ - cpu_register_physical_memory(addr, size, s->mmio_index); - s->region[region_num] = addr; - } + assert(region_num == 0 || region_num == 2); + + /* Map control / status registers and flash. */ + cpu_register_physical_memory(addr, size, s->mmio_index); + s->region[region_num] = addr; } static int nic_can_receive(VLANClientState *nc) From f62719ca6fcdab99d6fbd7a1d6798e0fad4e0b70 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 6 Apr 2010 13:44:09 +0200 Subject: [PATCH 08/13] eepro100: fix PCI interrupt pin configuration regression Commit 15e89f5916c9e82347cbd1fd416db3e348bab426 removed this setting, but it is still needed. Without this patch, e100 device drivers using interrupts don't work with qemu. See other nic emulations which also set the PCI interrupt pin. Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/eepro100.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/eepro100.c b/hw/eepro100.c index 949ca4ed2a..785a7daac8 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -474,6 +474,9 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) /* PCI Latency Timer */ pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */ /* Capability Pointer is set by PCI framework. */ + /* Interrupt Line */ + /* Interrupt Pin */ + pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1); /* interrupt pin A */ /* Minimum Grant */ pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08); /* Maximum Latency */ From 1db5a3aad3c689be1255ed850ef8e3515ab461e8 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 6 Apr 2010 16:05:46 +0300 Subject: [PATCH 09/13] pci: add API to add capability at a known offset Unlike virtio, device emulations need to add pci capabilities at known offsets to match real hardware. Make this possible by adding an appropriate API. Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 17 +++++++++++++---- hw/pci.h | 2 ++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 0dbca173e3..b6abd67e52 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1789,12 +1789,10 @@ static int pci_add_option_rom(PCIDevice *pdev) } /* Reserve space and add capability to the linked list in pci config space */ -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) +int pci_add_capability_at_offset(PCIDevice *pdev, uint8_t cap_id, + uint8_t offset, uint8_t size) { - uint8_t offset = pci_find_space(pdev, size); uint8_t *config = pdev->config + offset; - if (!offset) - return -ENOSPC; config[PCI_CAP_LIST_ID] = cap_id; config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; pdev->config[PCI_CAPABILITY_LIST] = offset; @@ -1807,6 +1805,17 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) return offset; } +/* Find and reserve space and add capability to the linked list + * in pci config space */ +int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) +{ + uint8_t offset = pci_find_space(pdev, size); + if (!offset) { + return -ENOSPC; + } + return pci_add_capability_at_offset(pdev, cap_id, offset, size); +} + /* Unlink capability from the pci config space. */ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) { diff --git a/hw/pci.h b/hw/pci.h index 20c670edbb..625188c0e6 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -190,6 +190,8 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, PCIMapIORegionFunc *map_func); int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); +int pci_add_capability_at_offset(PCIDevice *pci_dev, uint8_t cap_id, + uint8_t cap_offset, uint8_t cap_size); void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); From 8bbd1ce236130dc92d5d592e76701dd1c740df36 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 7 Apr 2010 10:55:47 +0300 Subject: [PATCH 10/13] eepro100: convert to new capability API Using new pci_add_capability_at_offset makes eepro100 code cleaner. Signed-off-by: Michael S. Tsirkin Acked-by: Stefan Weil --- hw/eepro100.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 785a7daac8..a74d834811 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -539,21 +539,17 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) if (e100_device->power_management) { /* Power Management Capabilities */ - int cfg_offset; - pci_reserve_capability(&s->dev, PCI_CONFIG_HEADER_SIZE, - 0xdc - PCI_CONFIG_HEADER_SIZE); - cfg_offset = pci_add_capability(&s->dev, PCI_CAP_ID_PM, PCI_PM_SIZEOF); - assert(cfg_offset == 0xdc); - if (cfg_offset > 0) { - /* Power Management Capabilities */ - pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21); + int cfg_offset = 0xdc; + int r = pci_add_capability_at_offset(&s->dev, PCI_CAP_ID_PM, + cfg_offset, PCI_PM_SIZEOF); + assert(r >= 0); + pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21); #if 0 /* TODO: replace dummy code for power management emulation. */ - /* TODO: Power Management Control / Status. */ - pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000); - /* TODO: Ethernet Power Consumption Registers (i82559 and later). */ - pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000); + /* TODO: Power Management Control / Status. */ + pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000); + /* TODO: Ethernet Power Consumption Registers (i82559 and later). */ + pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000); #endif - } } #if EEPROM_SIZE > 0 From af4c828e7043b2c594f904bca419fd3ab2b80a38 Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Wed, 31 Mar 2010 21:20:31 +0300 Subject: [PATCH 11/13] vhost: fix features ack vhost driver in qemu didn't ack features, and this happens to work because we don't really require any features. However, it's better not to rely on this. This patch passes features to vhost as guest acks them. Signed-off-by: David L Stevens Signed-off-by: Michael S. Tsirkin --- hw/virtio-net.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 970ba06275..acb3cec7cb 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -219,6 +219,14 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) (features >> VIRTIO_NET_F_GUEST_ECN) & 1, (features >> VIRTIO_NET_F_GUEST_UFO) & 1); } + if (!n->nic->nc.peer || + n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) { + return; + } + if (!tap_get_vhost_net(n->nic->nc.peer)) { + return; + } + return vhost_net_ack_features(tap_get_vhost_net(n->nic->nc.peer), features); } static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, From c6b35ac4c47290561b072a34f7bf1fdbc540a4a3 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 4 Apr 2010 17:36:55 +0300 Subject: [PATCH 12/13] vhost-net: disable mergeable buffers vhost in current kernels doesn't support mergeable buffers. Disable this feature if vhost is enabled, until such support is implemented. Signed-off-by: Michael S. Tsirkin --- hw/vhost_net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/vhost_net.c b/hw/vhost_net.c index 39643f1e99..2e292eea26 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -51,6 +51,7 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features) if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) { features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC); } + features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); return features; } From 15a2cb7b70b8d55f650bd51d25b4aebc39186934 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Thu, 8 Apr 2010 17:49:50 -0300 Subject: [PATCH 13/13] vhost.c: include last So the userspace headers define KERNEL_STRICT_NAMES and there's no conflict on type definition for older kernels. Signed-off-by: Marcelo Tosatti Signed-off-by: Michael S. Tsirkin --- hw/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vhost.c b/hw/vhost.c index ad2f98a8a3..d37a66e0ea 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -10,13 +10,13 @@ * the COPYING file in the top-level directory. */ -#include #include #include #include "vhost.h" #include "hw/hw.h" /* For range_get_last */ #include "pci.h" +#include static void vhost_dev_sync_region(struct vhost_dev *dev, uint64_t mfirst, uint64_t mlast,