From patchwork Fri Oct 30 12:36:21 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Weil X-Patchwork-Id: 37299 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 79DE7B7B88 for ; Sat, 31 Oct 2009 01:07:33 +1100 (EST) Received: from localhost ([127.0.0.1]:51303 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N3s8W-0002DT-SP for incoming@patchwork.ozlabs.org; Fri, 30 Oct 2009 10:07:29 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1N3qiW-0008JG-Lj for qemu-devel@nongnu.org; Fri, 30 Oct 2009 08:36:33 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1N3qiR-0008GZ-T7 for qemu-devel@nongnu.org; Fri, 30 Oct 2009 08:36:31 -0400 Received: from [199.232.76.173] (port=57369 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N3qiR-0008GD-1B for qemu-devel@nongnu.org; Fri, 30 Oct 2009 08:36:27 -0400 Received: from moutng.kundenserver.de ([212.227.17.8]:55918) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1N3qiQ-0004ar-7H for qemu-devel@nongnu.org; Fri, 30 Oct 2009 08:36:26 -0400 Received: from flocke.weilnetz.de (p54ADEBA3.dip.t-dialin.net [84.173.235.163]) by mrelayeu.kundenserver.de (node=mrbap0) with ESMTP (Nemesis) id 0MYtKV-1MhWcP3i3X-00V8Yb; Fri, 30 Oct 2009 13:36:23 +0100 Received: from stefan by flocke.weilnetz.de with local (Exim 4.69) (envelope-from ) id 1N3qiL-0002BG-T8; Fri, 30 Oct 2009 13:36:21 +0100 From: Stefan Weil To: QEMU Developers Date: Fri, 30 Oct 2009 13:36:21 +0100 Message-Id: <1256906181-8353-1-git-send-email-weil@mail.berlios.de> X-Mailer: git-send-email 1.5.6.5 X-Provags-ID: V01U2FsdGVkX18+N6j5waK3KIwNxsFUvblya0IZ7j+wBHmr639 aEe9BNvlW92GXrPiLfoi7hfT4gpEG8B96qGY5kH2gNd9iG4xAF MGP5P58ohd6B0OKBsEV563m5voWgxBx92y5zWmZzGrNwtRYzrJ G/Q== X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: Subject: [Qemu-devel] [PATCH] eepro100: Improve support for different devices X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org * Add device properties (size of statistical data, extended tcb support) to EEPRO100State and set these values for the different devices. * Fix PCI configuration for existing devices. * Add initialisation code for missing devices. * Remove function device_supports_eTxCB. It is no longer needed. * Fix dump of statistical data. It now respects the real size of the statistical data. An endianess issue was fixed here, too. * CU_SHOWSTATS, CU_DUMPSTATS now write a completion value after the statistical data. There is no need to keep this value in eepro100_stats_t, so member "complete" could be removed. Signed-off-by: Stefan Weil --- hw/eepro100.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 143 insertions(+), 25 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 46bb9b5..5507295 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -171,7 +171,8 @@ typedef struct { 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 { @@ -210,7 +211,10 @@ typedef struct { uint32_t ru_base; /* RU base address */ uint32_t ru_offset; /* RU address offset */ uint32_t statsaddr; /* pointer to eepro100_stats_t */ - eepro100_stats_t statistics; /* statistical counters */ + + /* Statistical counters. Also used for wake-up packet (i82559). */ + eepro100_stats_t statistics; + #if 0 uint16_t status; #endif @@ -222,6 +226,10 @@ typedef struct { uint8_t mem[PCI_MEM_SIZE]; /* vmstate for each particular nic */ VMStateDescription *vmstate; + + /* Quasi static device properties (no need to save them). */ + uint16_t stats_size; + bool has_extended_tcb_support; } EEPRO100State; /* Default values for MDI (PHY) registers */ @@ -243,6 +251,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 */ @@ -388,6 +403,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)); @@ -437,46 +453,151 @@ 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; + 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_8(PCI_REVISION_ID, 0x08); + PCI_CONFIG_16(PCI_STATUS, 0x0290); + PCI_CONFIG_8(PCI_REVISION_ID, 0x08); + // TODO: Windows wants revision id 0x0c. + 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_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) @@ -569,11 +690,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, @@ -618,13 +734,14 @@ 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); - 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); - stl_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors); - //~ stw_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames); - //~ stw_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames); + cpu_physical_memory_write(s->statsaddr, + (uint8_t *) & s->statistics, s->stats_size); + stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames); + stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames); + stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors); + stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors); + //~ stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames); + //~ stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames); //~ missing("CU dump statistical counters"); } @@ -710,7 +827,7 @@ static void action_command(EEPRO100State *s) } else { /* Flexible mode. */ uint8_t tbd_count = 0; - if (device_supports_eTxCB(s) && !(s->configuration[6] & BIT(4))) { + if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) { /* Extended Flexible TCB. */ for (; tbd_count < 2; tbd_count++) { uint32_t tx_buffer_address = ldl_phys(tbd_address); @@ -830,6 +947,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. */ @@ -840,6 +958,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: @@ -1624,7 +1743,7 @@ static const VMStateDescription vmstate_eepro100 = { VMSTATE_UINT32(ru_base, EEPRO100State), VMSTATE_UINT32(ru_offset, EEPRO100State), VMSTATE_UINT32(statsaddr, EEPRO100State), - /* Save epro100_stats_t statistics. */ + /* Save eepro100_stats_t statistics. */ VMSTATE_UINT32(statistics.tx_good_frames, EEPRO100State), VMSTATE_UINT32(statistics.tx_max_collisions, EEPRO100State), VMSTATE_UINT32(statistics.tx_late_collisions, EEPRO100State), @@ -1646,7 +1765,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), - VMSTATE_UINT32(statistics.complete, EEPRO100State), #if 0 VMSTATE_UINT16(status, EEPRO100State), #endif