From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MpQXF-0004qU-0G for qemu-devel@nongnu.org; Sun, 20 Sep 2009 13:49:17 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MpQX9-0004pl-6z for qemu-devel@nongnu.org; Sun, 20 Sep 2009 13:49:15 -0400 Received: from [199.232.76.173] (port=58586 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MpQX9-0004pe-4Z for qemu-devel@nongnu.org; Sun, 20 Sep 2009 13:49:11 -0400 Received: from moutng.kundenserver.de ([212.227.17.9]:50359) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MpQX8-00011U-96 for qemu-devel@nongnu.org; Sun, 20 Sep 2009 13:49:10 -0400 From: Stefan Weil Date: Sun, 20 Sep 2009 19:48:56 +0200 Message-Id: <1253468936-21377-1-git-send-email-weil@mail.berlios.de> Subject: [Qemu-devel] [PATCH] eepro100: Improve handling of different devices List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: QEMU Developers * Fix size of statistical counters and add this size to device state. * Fix handling of statistical counters. * Add flag for extended tcb support to device state. * Fix a number of PCI configuration values. * Add setup code for new devices. This patch is a step to synchronize my maintainer version of eepro100.c (git://repo.or.cz/qemu/ar7.git) with the version integrated in QEMU. Signed-off-by: Stefan Weil --- hw/eepro100.c | 206 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 157 insertions(+), 49 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 6aafbef..ba17e8e 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -73,7 +73,10 @@ #define TRACE(flag, command) ((flag) ? (command) : (void)0) -#define missing(text) assert(!"feature is missing in this emulation: " text) +#define UNEXPECTED() logout("%s:%u unexpected\n", __FILE__, __LINE__) + +//~ #define missing(text) assert(!"feature is missing in this emulation: " text) +#define missing(text) logout("feature is missing in this emulation: " text "\n") #define MAX_ETH_FRAME_SIZE 1514 @@ -164,14 +167,15 @@ typedef struct { typedef struct { uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions, - tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, - tx_multiple_collisions, tx_total_collisions; + tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, + tx_multiple_collisions, tx_total_collisions; uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors, - rx_resource_errors, rx_overrun_errors, rx_cdt_errors, - rx_short_frame_errors; + rx_resource_errors, rx_overrun_errors, rx_cdt_errors, + rx_short_frame_errors; uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; uint16_t xmt_tco_frames, rcv_tco_frames; - uint32_t complete; + /* TODO: i82559 has six reserved statistics but a total of 24 dwords. */ + uint32_t reserved[4]; } eepro100_stats_t; typedef enum { @@ -191,14 +195,12 @@ typedef enum { typedef struct { PCIDevice dev; -#if 1 uint8_t cmd; uint32_t start; uint32_t stop; uint8_t mult[8]; /* multicast mask array */ int mmio_index; VLANClientState *vc; -#endif uint8_t scb_stat; /* SCB stat/ack byte */ uint8_t int_stat; /* PCI interrupt status */ uint32_t region[3]; /* PCI region addresses */ @@ -221,20 +223,22 @@ 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]; /* Data in mem is always in the byte order of the controller (le). */ uint8_t mem[PCI_MEM_SIZE]; + + /* Quasi static device properties (no need to save them). */ + uint16_t stats_size; + bool has_extended_tcb_support; } EEPRO100State; /* Parameters for nic_save, nic_load. */ static const int eepro100_instance = -1; -static const int eepro100_version = 20090807; +/* TODO: Set eepro100_version to 4 as soon as EEPRO100State is finished. */ +static const int eepro100_version = 20090920; /* Default values for MDI (PHY) registers */ static const uint16_t eepro100_mdi_default[] = { @@ -255,6 +259,13 @@ static const uint16_t eepro100_mdi_mask[] = { 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; +/* XXX: optimize */ +static void stl_le_phys(target_phys_addr_t addr, uint32_t val) +{ + val = cpu_to_le32(val); + cpu_physical_memory_write(addr, (const uint8_t *)&val, sizeof(val)); +} + #define POLYNOMIAL 0x04c11db6 /* From FreeBSD */ @@ -398,6 +409,7 @@ static void pci_reset(EEPRO100State * s) { uint32_t device = s->device; uint8_t *pci_conf = s->dev.config; + bool power_management = 1; TRACE(OTHER, logout("%p\n", s)); @@ -407,35 +419,18 @@ static void pci_reset(EEPRO100State * s) /* PCI Command */ PCI_CONFIG_16(PCI_COMMAND, 0x0000); /* PCI Status */ - PCI_CONFIG_16(PCI_STATUS, 0x2800); - /* PCI Revision ID */ - PCI_CONFIG_8(PCI_REVISION_ID, 0x08); + PCI_CONFIG_16(PCI_STATUS, 0x0280); + /* PCI Revision ID depends on device. */ /* PCI Class Code */ PCI_CONFIG_8(0x09, 0x00); pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); /* PCI Cache Line Size */ - /* check cache line size!!! */ - //~ PCI_CONFIG_8(0x0c, 0x00); + /* Only bit 3 and bit 4 are writable (not emulated). */ /* PCI Latency Timer */ PCI_CONFIG_8(0x0d, 0x20); // latency timer = 32 clocks /* PCI Header Type */ + PCI_CONFIG_8(PCI_HEADER_TYPE, 0x00); /* BIST (built-in self test) */ -#if defined(TARGET_I386) -// !!! workaround for buggy bios -//~ #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0 -#endif -#if 0 - /* PCI Base Address Registers */ - /* CSR Memory Mapped Base Address */ - PCI_CONFIG_32(PCI_BASE_ADDRESS_0, - PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH); - /* CSR I/O Mapped Base Address */ - PCI_CONFIG_32(PCI_BASE_ADDRESS_1, PCI_ADDRESS_SPACE_IO); -#if 0 - /* Flash Memory Mapped Base Address */ - PCI_CONFIG_32(PCI_BASE_ADDRESS_2, 0xfffe0000 | PCI_ADDRESS_SPACE_MEM); -#endif -#endif /* Expansion ROM Base Address (depends on boot disable!!!) */ PCI_CONFIG_32(0x30, 0x00000000); /* Capability Pointer */ @@ -447,50 +442,158 @@ static void pci_reset(EEPRO100State * s) PCI_CONFIG_8(0x3e, 0x08); /* Maximum Latency */ PCI_CONFIG_8(0x3f, 0x18); - /* Power Management Capabilities / Next Item Pointer / Capability ID */ - PCI_CONFIG_32(0xdc, 0x7e210001); 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_CONFIG_8(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_CONFIG_8(PCI_REVISION_ID, 0x0f); + // TODO: check size of statistical counters. + s->stats_size = 80; + // TODO: check extended tcb support. + s->has_extended_tcb_support = 1; + break; + case i82557A: + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557); + PCI_CONFIG_8(PCI_REVISION_ID, 0x01); + PCI_CONFIG_8(0x34, 0x00); + power_management = 0; break; case i82557B: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557); PCI_CONFIG_8(PCI_REVISION_ID, 0x02); + PCI_CONFIG_8(0x34, 0x00); + power_management = 0; break; case i82557C: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557); PCI_CONFIG_8(PCI_REVISION_ID, 0x03); + PCI_CONFIG_8(0x34, 0x00); + power_management = 0; + break; + case i82558A: + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557); + PCI_CONFIG_16(PCI_STATUS, 0x0290); + PCI_CONFIG_8(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_CONFIG_16(PCI_STATUS, 0x2810); + PCI_CONFIG_16(PCI_STATUS, 0x0290); PCI_CONFIG_8(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_CONFIG_16(PCI_STATUS, 0x0290); + PCI_CONFIG_8(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_CONFIG_16(PCI_STATUS, 0x0290); + PCI_CONFIG_8(PCI_REVISION_ID, 0x07); + s->stats_size = 80; + s->has_extended_tcb_support = 1; break; case i82559C: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82557); - PCI_CONFIG_16(PCI_STATUS, 0x2810); + PCI_CONFIG_16(PCI_STATUS, 0x0290); + // TODO: Windows wants revision id 0x0c. //~ PCI_CONFIG_8(PCI_REVISION_ID, 0x08); + PCI_CONFIG_8(PCI_REVISION_ID, 0x0c); +#if EEPROM_SIZE > 0 + PCI_CONFIG_16(PCI_SUBSYSTEM_VENDOR_ID, 0x8086); + PCI_CONFIG_16(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_CONFIG_16(PCI_STATUS, 0x2810); + //~ pci_config_set_device_id(pci_conf, 0x1030); /* 82559 InBusiness 10/100 !!! */ + PCI_CONFIG_16(PCI_STATUS, 0x0290); PCI_CONFIG_8(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_CONFIG_8(PCI_REVISION_ID, 0x0e); + s->stats_size = 80; + s->has_extended_tcb_support = 1; break; - //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1029); - //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1030); /* 82559 InBusiness 10/100 */ default: logout("Device %X is undefined!\n", device); } + s->configuration[6] |= BIT(5); + + if (s->stats_size == 80) { + /* TODO: check TCO Statistical Counters bit. Documentation not clear. */ + if (s->configuration[6] & BIT(2)) { + /* TCO statistical counters. */ + assert(s->configuration[6] & BIT(5)); + } else { + if (s->configuration[6] & BIT(5)) { + /* No extended statistical counters, i82557 compatible. */ + s->stats_size = 64; + } else { + /* i82558 compatible. */ + s->stats_size = 76; + } + } + } else { + if (s->configuration[6] & BIT(5)) { + /* No extended statistical counters. */ + s->stats_size = 64; + } + } + assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics)); + + if (power_management) { + /* Power Management Capabilities */ + PCI_CONFIG_8(0xdc, 0x01); + /* Next Item Pointer */ + /* Capability ID */ + PCI_CONFIG_16(0xde, 0x7e21); + /* TODO: Power Management Control / Status. */ + /* TODO: Ethernet Power Consumption Registers (i82559 and later). */ + } + +#if EEPROM_SIZE > 0 if (device == i82557C || device == i82558B || device == i82559C) { + // TODO: get vendor id from EEPROM for i82557C or later. + // TODO: get device id from EEPROM for i82557C or later. + // TODO: status bit 4 can be disabled by EEPROM for i82558, i82559. + // TODO: header type is determined by EEPROM for i82559. + // TODO: get subsystem id from EEPROM for i82557C or later. + // TODO: get subsystem vendor id from EEPROM for i82557C or later. + // TODO: exp. rom baddr depends on a bit in EEPROM for i82558 or later. + // TODO: capability pointer depends on EEPROM for i82558. logout("Get device id and revision from EEPROM!!!\n"); } +#endif /* EEPROM_SIZE > 0 */ } static void nic_selective_reset(EEPRO100State * s) { +#if EEPROM_SIZE > 0 size_t i; uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom); //~ eeprom93xx_reset(s->eeprom); @@ -502,6 +605,7 @@ static void nic_selective_reset(EEPRO100State * s) } eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum; TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1])); +#endif /* EEPROM_SIZE > 0 */ memset(s->mem, 0, sizeof(s->mem)); uint32_t val = BIT(21); @@ -579,11 +683,6 @@ static uint16_t eepro100_read_command(EEPRO100State * s) } #endif -static bool device_supports_eTxCB(EEPRO100State * s) -{ - return (s->device != i82557B && s->device != i82557C); -} - /* Commands that can be put in a command list entry. */ enum commands { CmdNOp = 0, @@ -628,7 +727,8 @@ static void dump_statistics(EEPRO100State * s) * values which really matter. * Number of data should check configuration!!! */ - cpu_physical_memory_write(s->statsaddr, (uint8_t *) & s->statistics, 64); + cpu_physical_memory_write(s->statsaddr, + (uint8_t *) & s->statistics, s->stats_size); stl_phys(s->statsaddr + 0, s->statistics.tx_good_frames); stl_phys(s->statsaddr + 36, s->statistics.rx_good_frames); stl_phys(s->statsaddr + 48, s->statistics.rx_resource_errors); @@ -673,10 +773,13 @@ static void tx_command(EEPRO100State *s) } if (tbd_array == 0xffffffff) { /* Simplified mode. Was already handled by code above. */ + } else if (!s->has_extended_tcb_support) { + /* Device does not support extend TCB. */ + UNEXPECTED(); } else { /* Flexible mode. */ uint8_t tbd_count = 0; - if (device_supports_eTxCB(s) && !(s->configuration[6] & BIT(4))) { + if (!(s->configuration[6] & BIT(4))) { /* Extended Flexible TCB. */ assert(tcb_bytes == 0); for (; tbd_count < 2; tbd_count++) { @@ -848,6 +951,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val) /* Dump statistical counters. */ TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val)); dump_statistics(s); + stl_le_phys(s->statsaddr + s->stats_size, 0xa005); break; case CU_CMD_BASE: /* Load CU base. */ @@ -858,6 +962,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val) /* Dump and reset statistical counters. */ TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val)); dump_statistics(s); + stl_le_phys(s->statsaddr + s->stats_size, 0xa007); memset(&s->statistics, 0, sizeof(s->statistics)); break; case CU_SRESUME: @@ -1682,7 +1787,6 @@ static int nic_load(QEMUFile * f, void *opaque, int version_id) qemu_get_be32s(f, &s->statistics.fc_rcv_unsupported); qemu_get_be16s(f, &s->statistics.xmt_tco_frames); qemu_get_be16s(f, &s->statistics.rcv_tco_frames); - qemu_get_be32s(f, &s->statistics.complete); #if 0 qemu_get_be16s(f, &s->status); #endif @@ -1746,7 +1850,6 @@ static void nic_save(QEMUFile * f, void *opaque) qemu_put_be32s(f, &s->statistics.fc_rcv_unsupported); qemu_put_be16s(f, &s->statistics.xmt_tco_frames); qemu_put_be16s(f, &s->statistics.rcv_tco_frames); - qemu_put_be32s(f, &s->statistics.complete); #if 0 qemu_put_be16s(f, &s->status); #endif @@ -1785,9 +1888,11 @@ static int nic_init(PCIDevice *pci_dev, uint32_t device) pci_reset(s); +#if EEPROM_SIZE > 0 /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM, * i82559 and later support 64 or 256 word EEPROM. */ s->eeprom = eeprom93xx_new(EEPROM_SIZE); +#endif /* Handler for memory-mapped I/O */ s->mmio_index = @@ -1818,6 +1923,7 @@ static int nic_init(PCIDevice *pci_dev, uint32_t device) register_savevm(s->vc->model, eepro100_instance, eepro100_version, nic_save, nic_load, s); + return 0; } @@ -1941,3 +2047,5 @@ static void eepro100_register_devices(void) } device_init(eepro100_register_devices) + +/* eof */ -- 1.5.6.5