qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] eepro100: Improve handling of different devices


From: Stefan Weil
Subject: [Qemu-devel] [PATCH] eepro100: Improve handling of different devices
Date: Sun, 20 Sep 2009 19:48:56 +0200

* 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 <address@hidden>
---
 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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]