qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] PATCH [1/2] Patches to support Juniper Olives - eepro100 mu


From: Brandon Bennett
Subject: [Qemu-devel] PATCH [1/2] Patches to support Juniper Olives - eepro100 multicast
Date: Thu, 16 Oct 2008 15:46:06 -0600

These patches are what I found was needed/wanted to support a "Juniper
Olive".   Juniper routers run on off the shelf x86 archecture as a
result you can load JunOS (the software that runs on Juniper routers)
onto any standard PC and run it as an Olive.   Olive is the state of a
router without a PFE (the forwarding plane of a juniper router).  The
olive allows you to do most Juniper routing allowing you to study for
certifications, test out network changes, or test new features.

More information here:  http://juniper.cluepon.net/index.php/Olive

The first patch is to update eepro100.c to the latest version found
from Stefan Weil's ar7-firmware qemu trunk.   This patch is essential
as it fixes multicast with the eepr100 supported nics.   Olive routers
only support this nic so it is essential.

This patch is line for line from Weil's respository with no changes.
I hope this is alright to support others work.

Also I apologize if the formating of the patch or the email is wrong
as this is my first attempt at a submittal.   Please let me know if
there is anything I need to do/redo.

-Brandon Bennett

Index: hw/pci.c
===================================================================
--- hw/pci.c    (revision 5487)
+++ hw/pci.c    (working copy)
@@ -628,12 +628,14 @@
 {
     if (strcmp(nd->model, "ne2k_pci") == 0) {
         pci_ne2000_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82551") == 0) {
-        pci_i82551_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82557b") == 0) {
-        pci_i82557b_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82559er") == 0) {
-        pci_i82559er_init(bus, nd, devfn);
+    } else if ((strcmp(nd->model, "i82551") == 0) ||
+               (strcmp(nd->model, "i82557a") == 0) ||
+               (strcmp(nd->model, "i82557b") == 0) ||
+               (strcmp(nd->model, "i82557c") == 0) ||
+               (strcmp(nd->model, "i82558b") == 0) ||
+               (strcmp(nd->model, "i82559c") == 0) ||
+               (strcmp(nd->model, "i82559er") == 0)) {
+        pci_eepro100_init(bus, nd, devfn);
     } else if (strcmp(nd->model, "rtl8139") == 0) {
         pci_rtl8139_init(bus, nd, devfn);
     } else if (strcmp(nd->model, "e1000") == 0) {
@@ -641,7 +643,8 @@
     } else if (strcmp(nd->model, "pcnet") == 0) {
         pci_pcnet_init(bus, nd, devfn);
     } else if (strcmp(nd->model, "?") == 0) {
-        fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
+        fprintf(stderr, "qemu: Supported PCI NICs: "
+                                               " i82551 i82557a i82557b 
i82557c i82558b i82559c i82559er"
                         " ne2k_pci pcnet rtl8139 e1000\n");
         exit (1);
     } else {
Index: hw/eepro100.c
===================================================================
--- hw/eepro100.c       (revision 5487)
+++ hw/eepro100.c       (working copy)
@@ -1,14 +1,14 @@
 /*
  * QEMU i8255x (PRO100) emulation
  *
- * Copyright (c) 2006-2007 Stefan Weil
+ * Copyright (C) 2006-2007 Stefan Weil
  *
  * Portions of the code are copies from grub / etherboot eepro100.c
  * and linux e100.c.
  *
- * This program is free software; you can redistribute it and/or modify
+ * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -17,27 +17,30 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301  USA
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  * Tested features (i82559):
- *      PXE boot (i386) no valid link
+ *      PXE boot (i386) ok
  *      Linux networking (i386) ok
+ *      Linux networking e100 driver (mips, mipsel) ok
+ *      Linux networking eepro100 driver (mipsel) not ok
+ *      Windows networking (Vista) ???
  *
  * Untested:
  *      non-i386 platforms
- *      Windows networking
  *
  * References:
  *
  * Intel 8255x 10/100 Mbps Ethernet Controller Family
  * Open Source Software Developer Manual
+ *
+ * TODO:
+ * EE100   eepro100_write2         addr=General Status/Control+2 val=0x0080
+ * EE100   eepro100_write2         feature is missing in this
emulation: unknown word write
+ * EE100   eepro100_read2          addr=General Status/Control+2 val=0x0080
+ * EE100   eepro100_read2          feature is missing in this
emulation: unknown word read
  */

-#if defined(TARGET_I386)
-# warning "PXE boot still not working!"
-#endif
-
 #include <assert.h>
 #include <stddef.h>             /* offsetof */
 #include "hw.h"
@@ -64,6 +67,9 @@
 #define PCI_BASE_ADDRESS_4      0x20    /* 32 bits */
 #define PCI_BASE_ADDRESS_5      0x24    /* 32 bits */

+#define PCI_SUBSYSTEM_ID        0x2c    /* 16 bits */
+#define PCI_SUBSYSTEM_VENDOR    0x2e    /* 16 bits */
+
 #define PCI_CONFIG_8(offset, value) \
     (pci_conf[offset] = (value))
 #define PCI_CONFIG_16(offset, value) \
@@ -74,7 +80,9 @@
 #define KiB 1024

 /* debug EEPRO100 card */
-//~ #define DEBUG_EEPRO100
+/*
+#define DEBUG_EEPRO100
+*/

 #ifdef DEBUG_EEPRO100
 #define logout(fmt, args...) fprintf(stderr, "EE100\t%-24s" fmt,
__func__, ##args)
@@ -83,16 +91,23 @@
 #endif

 /* Set flags to 0 to disable debug output. */
-#define MDI     0
+#define INT     1       /* interrupt related actions */
+#define MDI     1       /* mdi related actions */
+#define OTHER   1
+#define RXTX    1

 #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

 /* This driver supports several different devices which are declared here. */
 #define i82551          0x82551
+#define i82557A         0x82557a
 #define i82557B         0x82557b
 #define i82557C         0x82557c
 #define i82558B         0x82558b
@@ -100,6 +115,7 @@
 #define i82559ER        0x82559e
 #define i82562          0x82562

+/* Use 64 word EEPROM. TODO: could be a runtime option. */
 #define EEPROM_SIZE     64

 #define PCI_MEM_SIZE            (4 * KiB)
@@ -132,25 +148,29 @@

 /* Offsets to the various registers.
    All accesses need not be longword aligned. */
-enum speedo_offsets {
+typedef enum {
     SCBStatus = 0,
     SCBAck = 1,
     SCBCmd = 2,                 /* Rx/Command Unit command and status. */
     SCBIntmask = 3,
     SCBPointer = 4,             /* General purpose pointer. */
     SCBPort = 8,                /* Misc. commands and operands.  */
-    SCBflash = 12, SCBeeprom = 14,      /* EEPROM and flash memory control. */
+    SCBflash = 12,              /* Flash memory control. */
+    SCBeeprom = 14,             /* EEPROM control. */
     SCBCtrlMDI = 16,            /* MDI interface control. */
     SCBEarlyRx = 20,            /* Early receive byte count. */
-    SCBFlow = 24,
-};
+    SCBFlow = 24,               /* Flow Control. */
+    SCBpmdr = 27,               /* Power Management Driver. */
+    SCBgctrl = 28,              /* General Control. */
+    SCBgstat = 29,              /* General Status. */
+} speedo_offset_t;

 /* A speedo3 transmit buffer descriptor with two buffers... */
 typedef struct {
     uint16_t status;
     uint16_t command;
     uint32_t link;              /* void * */
-    uint32_t tx_desc_addr;      /* transmit buffer decsriptor array address. */
+    uint32_t tbd_array_addr;    /* transmit buffer descriptor array address. */
     uint16_t tcb_bytes;         /* transmit command block byte count
(in lower 14 bits */
     uint8_t tx_threshold;       /* transmit threshold */
     uint8_t tbd_count;          /* TBD number */
@@ -172,13 +192,27 @@
     char packet[MAX_ETH_FRAME_SIZE + 4];
 } eepro100_rx_t;

+typedef enum {
+    COMMAND_EL = BIT(15),
+    COMMAND_S = BIT(14),
+    COMMAND_I = BIT(13),
+    COMMAND_NC = BIT(4),
+    COMMAND_SF = BIT(3),
+    COMMAND_CMD = BITS(2, 0),
+} cb_command_bit_t;
+
+typedef enum {
+    STATUS_C = BIT(15),
+    STATUS_OK = BIT(13),
+} cb_status_bit_t;
+
 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;
@@ -199,14 +233,8 @@
     ru_ready = 4
 } ru_state_t;

-#if defined(__BIG_ENDIAN_BITFIELD)
-#define X(a,b) b,a
-#else
-#define X(a,b) a,b
-#endif
-
 typedef struct {
-#if 1
+#if 1   // �berfl�ssige Eintr�ge entfernen, save / load pr�fen!!!
     uint8_t cmd;
     uint32_t start;
     uint32_t stop;
@@ -244,11 +272,17 @@
     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 */
-#if 0
-    uint16_t status;
-#endif

+    cu_state_t cu_state;
+    ru_state_t ru_state;
+
+    /* Temporary data. */
+    eepro100_tx_t tx;
+    uint32_t cb_address;
+
+    /* Statistical counters. */
+    eepro100_stats_t statistics;
+
     /* Configuration bytes. */
     uint8_t configuration[22];

@@ -256,6 +290,32 @@
     uint8_t mem[PCI_MEM_SIZE];
 } EEPRO100State;

+/* Word indices in EEPROM. */
+typedef enum {
+    eeprom_cnfg_mdix  = 0x03,
+    eeprom_phy_id     = 0x06,
+    eeprom_id         = 0x05,
+    eeprom_vendor_id  = 0x0c,
+    eeprom_config_asf = 0x0d,
+    eeprom_device_id  = 0x23,
+    eeprom_smbus_addr = 0x90,
+} eeprom_offset_t;
+
+/* Bit values for EEPROM ID word (offset 0x0a). */
+typedef enum {
+    eeprom_id_mdm = BIT(0),     /* Modem */
+    eeprom_id_stb = BIT(1),     /* Standby Enable */
+    eeprom_id_wmr = BIT(2),     /* ??? */
+    eeprom_id_wol = BIT(5),     /* Wake on LAN */
+    eeprom_id_dpd = BIT(6),     /* Deep Power Down */
+    eeprom_id_alt = BIT(7),     /* */
+    /* BITS(10, 8) device revision */
+    eeprom_id_bd = BIT(11),     /* boot disable */
+    eeprom_id_id = BIT(13),     /* id bit */
+    /* BITS(15, 14) signature */
+    eeprom_id_valid = BIT(14),  /* signature for valid eeprom */
+} eeprom_id_t;
+
 /* Default values for MDI (PHY) registers */
 static const uint16_t eepro100_mdi_default[] = {
     /* MDI Registers 0 - 6, 7 */
@@ -275,11 +335,43 @@
     0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 };

+/* XXX: optimize */
+static uint32_t lduw_le_phys(target_phys_addr_t addr)
+{
+    /* Load 16 bit (little endian) word from emulated hardware. */
+    uint16_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, sizeof(val));
+    return le16_to_cpu(val);
+}
+
+/* XXX: optimize */
+static uint32_t ldl_le_phys(target_phys_addr_t addr)
+{
+    /* Load 32 bit (little endian) word from emulated hardware. */
+    uint32_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, sizeof(val));
+    return le32_to_cpu(val);
+}
+
+/* XXX: optimize */
+static void stw_le_phys(target_phys_addr_t addr, uint16_t val)
+{
+    val = cpu_to_le16(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&val, sizeof(val));
+}
+
+/* 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 */
 /* XXX: optimize */
-static int compute_mcast_idx(const uint8_t * ep)
+static unsigned compute_mcast_idx(const uint8_t * ep)
 {
     uint32_t crc;
     int carry, i, j;
@@ -296,7 +388,7 @@
                 crc = ((crc ^ POLYNOMIAL) | carry);
         }
     }
-    return (crc >> 26);
+    return (crc & BITS(7, 2)) >> 2;
 }

 #if defined(DEBUG_EEPRO100)
@@ -313,6 +405,7 @@
 }
 #endif                          /* DEBUG_EEPRO100 */

+#if 0
 enum scb_stat_ack {
     stat_ack_not_ours = 0x00,
     stat_ack_sw_gen = 0x04,
@@ -324,11 +417,12 @@
     stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
     stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
 };
+#endif

 static void disable_interrupt(EEPRO100State * s)
 {
     if (s->int_stat) {
-        logout("interrupt disabled\n");
+        TRACE(INT, logout("interrupt disabled\n"));
         qemu_irq_lower(s->pci_dev->irq[0]);
         s->int_stat = 0;
     }
@@ -337,7 +431,7 @@
 static void enable_interrupt(EEPRO100State * s)
 {
     if (!s->int_stat) {
-        logout("interrupt enabled\n");
+        TRACE(INT, logout("interrupt enabled\n"));
         qemu_irq_raise(s->pci_dev->irq[0]);
         s->int_stat = 1;
     }
@@ -352,14 +446,14 @@
     }
 }

-static void eepro100_interrupt(EEPRO100State * s, uint8_t stat)
+static void eepro100_interrupt(EEPRO100State * s, uint8_t status)
 {
     uint8_t mask = ~s->mem[SCBIntmask];
-    s->mem[SCBAck] |= stat;
-    stat = s->scb_stat = s->mem[SCBAck];
-    stat &= (mask | 0x0f);
-    //~ stat &= (~s->mem[SCBIntmask] | 0x0xf);
-    if (stat && (mask & 0x01)) {
+    s->mem[SCBAck] |= status;
+    status = s->scb_stat = s->mem[SCBAck];
+    status &= (mask | 0x0f);
+    //~ status &= (~s->mem[SCBIntmask] | 0x0xf);
+    if (status && (mask & 0x01)) {
         /* SCB mask and SCB Bit M do not disable interrupt. */
         enable_interrupt(s);
     } else if (s->int_stat) {
@@ -419,18 +513,17 @@
     uint32_t device = s->device;
     uint8_t *pci_conf = s->pci_dev->config;

-    logout("%p\n", s);
+    TRACE(OTHER, logout("%p\n", s));

     /* PCI Vendor ID */
     PCI_CONFIG_16(PCI_VENDOR_ID, 0x8086);
     /* PCI Device ID */
     PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
     /* PCI Command */
-    PCI_CONFIG_16(PCI_COMMAND, 0x0000);
+    PCI_CONFIG_16(PCI_COMMAND, 0x0000);         // TODO: maybe 0x17
     /* 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_8(PCI_SUBCLASS_CODE, 0x00);      // ethernet network controller
@@ -440,7 +533,7 @@
     //~ PCI_CONFIG_8(0x0c, 0x00);
     /* 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
@@ -476,31 +569,43 @@
         //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
         PCI_CONFIG_8(PCI_REVISION_ID, 0x0f);
         break;
+    case i82557A:
+        PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+        PCI_CONFIG_8(PCI_REVISION_ID, 0x01);
+        PCI_CONFIG_8(0x34, 0x00);
+        break;
     case i82557B:
         PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
         PCI_CONFIG_8(PCI_REVISION_ID, 0x02);
+        PCI_CONFIG_8(0x34, 0x00);
         break;
     case i82557C:
         PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
         PCI_CONFIG_8(PCI_REVISION_ID, 0x03);
+        PCI_CONFIG_8(0x34, 0x00);
         break;
     case i82558B:
         PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
-        PCI_CONFIG_16(PCI_STATUS, 0x2810);
+        PCI_CONFIG_16(PCI_STATUS, 0x0290);
         PCI_CONFIG_8(PCI_REVISION_ID, 0x05);
         break;
     case i82559C:
         PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
-        PCI_CONFIG_16(PCI_STATUS, 0x2810);
+        PCI_CONFIG_16(PCI_STATUS, 0x0290);
         //~ PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
+        PCI_CONFIG_8(PCI_REVISION_ID, 0x0c);
+#if EEPROM_SIZE > 0
+        PCI_CONFIG_16(PCI_SUBSYSTEM_ID, 0x8086);
+        PCI_CONFIG_16(PCI_SUBSYSTEM_VENDOR, 0x0040);
+#endif
         break;
     case i82559ER:
         //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
-        PCI_CONFIG_16(PCI_STATUS, 0x2810);
+        PCI_CONFIG_16(PCI_STATUS, 0x0290);
         PCI_CONFIG_8(PCI_REVISION_ID, 0x09);
         break;
     //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1029);
-    //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1030);       /* 82559
InBusiness 10/100 */
+    //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1030);       /* 82559
InBusiness 10/100 !!! */
     default:
         logout("Device %X is undefined!\n", device);
     }
@@ -512,19 +617,40 @@

 static void nic_selective_reset(EEPRO100State * s)
 {
+#if EEPROM_SIZE > 0
+static const uint8_t eeprom_i82559[] = {
+    /* 0x0000 */ 0x00, 0x02, 0xb3, 0x46, 0x92, 0xd7, 0x0b, 0x02,
0xff, 0xff, 0x01, 0x02, 0x01, 0x47, 0xff, 0xff,
+    /* 0x0010 */ 0x17, 0x75, 0x04, 0x67, 0xa2, 0x50, 0x40, 0x00,
0x86, 0x80, 0x64, 0x00, 0xff, 0xff, 0xff, 0xff,
+    /* 0x0020 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    /* 0x0030 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    /* 0x0040 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x29, 0x12,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    /* 0x0050 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    /* 0x0060 */ 0x2c, 0x00, 0x00, 0x40, 0x03, 0x30, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    /* 0x0070 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x58, 0x1f,
+};
     size_t i;
+    uint8_t *pci_conf = s->pci_dev->config;
     uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
     //~ eeprom93xx_reset(s->eeprom);
+    memcpy(eeprom_contents, eeprom_i82559, EEPROM_SIZE * 2);
     memcpy(eeprom_contents, s->macaddr, 6);
-    eeprom_contents[0xa] = 0x4000;
+    memcpy(eeprom_contents + eeprom_vendor_id, pci_conf + PCI_VENDOR_ID, 2);
+    memcpy(eeprom_contents + eeprom_device_id, pci_conf + PCI_DEVICE_ID, 2);
+    for (i = 0; i < 3; i++) {
+      eeprom_contents[i] = le16_to_cpu(eeprom_contents[i]);
+    }
+    *(char *)(eeprom_contents + eeprom_phy_id) = 1;
+    /* TODO: eeprom_id_alt for i82559 */
+    eeprom_contents[eeprom_id] |= eeprom_id_valid;
     uint16_t sum = 0;
     for (i = 0; i < EEPROM_SIZE - 1; i++) {
         sum += eeprom_contents[i];
     }
-    eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
+    eeprom_contents[EEPROM_SIZE - 1] = (0xbaba - sum);
+#endif

     memset(s->mem, 0, sizeof(s->mem));
-    uint32_t val = BIT(21);
+    uint32_t val = cpu_to_le32(BIT(21));
     memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val));

     assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
@@ -533,9 +659,9 @@

 static void nic_reset(void *opaque)
 {
+    static int first;
     EEPRO100State *s = (EEPRO100State *) opaque;
-    logout("%p\n", s);
-    static int first;
+    TRACE(OTHER, logout("%p\n", s));
     if (!first) {
         first = 1;
     }
@@ -543,14 +669,14 @@
 }

 #if defined(DEBUG_EEPRO100)
-static const char *reg[PCI_IO_SIZE / 4] = {
+static const char *e100_reg[PCI_IO_SIZE / 4] = {
     "Command/Status",
     "General Pointer",
     "Port",
     "EEPROM/Flash Control",
     "MDI Control",
     "Receive DMA Byte Count",
-    "Flow control register",
+    "Flow Control",
     "General Status/Control"
 };

@@ -558,7 +684,7 @@
 {
     static char buf[16];
     if (addr < PCI_IO_SIZE) {
-        const char *r = reg[addr / 4];
+        const char *r = e100_reg[addr / 4];
         if (r != 0) {
             sprintf(buf, "%s+%u", r, addr % 4);
         } else {
@@ -575,13 +701,13 @@
 static uint16_t eepro100_read_status(EEPRO100State * s)
 {
     uint16_t val = s->status;
-    logout("val=0x%04x\n", val);
+    TRACE(OTHER, logout("val=0x%04x\n", val));
     return val;
 }

 static void eepro100_write_status(EEPRO100State * s, uint16_t val)
 {
-    logout("val=0x%04x\n", val);
+    TRACE(OTHER, logout("val=0x%04x\n", val));
     s->status = val;
 }
 #endif
@@ -596,7 +722,7 @@
 static uint16_t eepro100_read_command(EEPRO100State * s)
 {
     uint16_t val = 0xffff;
-    //~ logout("val=0x%04x\n", val);
+    //~ TRACE(OTHER, logout("val=0x%04x\n", val));
     return val;
 }
 #endif
@@ -613,28 +739,30 @@
     CmdDiagnose = 7,

     /* And some extra flags: */
-    CmdSuspend = 0x4000,        /* Suspend after completion. */
-    CmdIntr = 0x2000,           /* Interrupt after completion. */
     CmdTxFlex = 0x0008,         /* Use "Flexible mode" for CmdTx command. */
 };

 static cu_state_t get_cu_state(EEPRO100State * s)
 {
-    return ((s->mem[SCBStatus] >> 6) & 0x03);
+    return s->cu_state;
+    //~ return ((s->mem[SCBStatus] >> 6) & 0x03);
 }

 static void set_cu_state(EEPRO100State * s, cu_state_t state)
 {
+    s->cu_state = state;
     s->mem[SCBStatus] = (s->mem[SCBStatus] & 0x3f) + (state << 6);
 }

 static ru_state_t get_ru_state(EEPRO100State * s)
 {
-    return ((s->mem[SCBStatus] >> 2) & 0x0f);
+    return s->ru_state;
+    //~ return ((s->mem[SCBStatus] >> 2) & 0x0f);
 }

 static void set_ru_state(EEPRO100State * s, ru_state_t state)
 {
+    s->ru_state = state;
     s->mem[SCBStatus] = (s->mem[SCBStatus] & 0xc3) + (state << 2);
 }

@@ -646,145 +774,167 @@
      * 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);
+    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");
 }

-static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
+static void read_cb(EEPRO100State *s)
 {
-    eepro100_tx_t tx;
-    uint32_t cb_address;
-    switch (val) {
-    case CU_NOP:
-        /* No operation. */
-        break;
-    case CU_START:
-        if (get_cu_state(s) != cu_idle) {
-            /* Intel documentation says that CU must be idle for the CU
-             * start command. Intel driver for Linux also starts the CU
-             * from suspended state. */
-            logout("CU state is %u, should be %u\n", get_cu_state(s), cu_idle);
-            //~ assert(!"wrong CU state");
+    cpu_physical_memory_read(s->cb_address, (uint8_t *) &s->tx, sizeof(s->tx));
+    s->tx.status = le16_to_cpu(s->tx.status);
+    s->tx.command = le16_to_cpu(s->tx.command);
+    s->tx.link = le32_to_cpu(s->tx.link);
+    s->tx.tbd_array_addr = le32_to_cpu(s->tx.tbd_array_addr);
+    s->tx.tcb_bytes = le16_to_cpu(s->tx.tcb_bytes);
+}
+
+static void tx_command(EEPRO100State *s)
+{
+    uint32_t tbd_array = s->tx.tbd_array_addr;
+    uint16_t tcb_bytes = (s->tx.tcb_bytes & 0x3fff);
+    uint8_t buf[2600];
+    uint16_t size = 0;
+    uint32_t tbd_address = s->cb_address + 0x10;
+    TRACE(RXTX, logout
+        ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x,
TBD count %u\n",
+         tbd_array, tcb_bytes, s->tx.tbd_count));
+    assert(!(s->tx.command & COMMAND_NC));
+    assert(tcb_bytes <= sizeof(buf));
+    if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
+        logout
+            ("illegal values of TBD array address and TCB byte count!\n");
+    }
+    for (size = 0; size < tcb_bytes; ) {
+        uint32_t tx_buffer_address = ldl_le_phys(tbd_address);
+        uint16_t tx_buffer_size = lduw_le_phys(tbd_address + 4);
+        //~ uint16_t tx_buffer_el = lduw_le_phys(tbd_address + 6);
+        tbd_address += 8;
+        TRACE(RXTX, logout
+            ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
+             tx_buffer_address, tx_buffer_size));
+        assert(size + tx_buffer_size <= sizeof(buf));
+        cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                 tx_buffer_size);
+        size += tx_buffer_size;
+    }
+    if (!(s->tx.command & COMMAND_SF)) {
+        /* Simplified mode. Was already handled by code above. */
+        if (tbd_array != 0xffffffff) {
+            UNEXPECTED();
         }
-        set_cu_state(s, cu_active);
-        s->cu_offset = s->pointer;
-      next_command:
-        cb_address = s->cu_base + s->cu_offset;
-        cpu_physical_memory_read(cb_address, (uint8_t *) & tx, sizeof(tx));
-        uint16_t status = le16_to_cpu(tx.status);
-        uint16_t command = le16_to_cpu(tx.command);
-        logout
-            ("val=0x%02x (cu start), status=0x%04x, command=0x%04x,
link=0x%08x\n",
-             val, status, command, tx.link);
-        bool bit_el = ((command & 0x8000) != 0);
-        bool bit_s = ((command & 0x4000) != 0);
-        bool bit_i = ((command & 0x2000) != 0);
-        bool bit_nc = ((command & 0x0010) != 0);
-        //~ bool bit_sf = ((command & 0x0008) != 0);
-        uint16_t cmd = command & 0x0007;
-        s->cu_offset = le32_to_cpu(tx.link);
-        switch (cmd) {
+    } else if (s->device >= i82557A && s->device <= i82557C) {
+        /* 82557 does not support extend TCB. */
+        UNEXPECTED();
+    } else {
+        /* Flexible mode. */
+        uint8_t tbd_count = 0;
+        if (!(s->configuration[6] & BIT(4)) && s->device != i82557C) {
+            /* Extended TCB (not for 82557). */
+            assert(tcb_bytes == 0);
+            for (; tbd_count < 2 && tbd_count < s->tx.tbd_count; tbd_count++) {
+                uint32_t tx_buffer_address = ldl_le_phys(tbd_address);
+                uint16_t tx_buffer_size = lduw_le_phys(tbd_address + 4);
+                uint16_t tx_buffer_el = lduw_le_phys(tbd_address + 6);
+                tbd_address += 8;
+                TRACE(RXTX, logout
+                    ("TBD (extended mode): buffer address 0x%08x,
size 0x%04x\n",
+                     tx_buffer_address, tx_buffer_size));
+                if (size + tx_buffer_size > sizeof(buf)) {
+                    logout("bad extended TCB with size 0x%04x\n",
tx_buffer_size);
+                } else if (tx_buffer_size > 0) {
+                    assert(tx_buffer_address != 0);
+                    cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                             tx_buffer_size);
+                    size += tx_buffer_size;
+                }
+                if (tx_buffer_el & 1) {
+                    break;
+                }
+            }
+        }
+        tbd_address = tbd_array;
+        for (; tbd_count < s->tx.tbd_count; tbd_count++) {
+            uint32_t tx_buffer_address = ldl_le_phys(tbd_address);
+            uint16_t tx_buffer_size = lduw_le_phys(tbd_address + 4);
+            uint16_t tx_buffer_el = lduw_le_phys(tbd_address + 6);
+            tbd_address += 8;
+            TRACE(RXTX, logout
+                ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
+                 tx_buffer_address, tx_buffer_size));
+            if (size + tx_buffer_size > sizeof(buf)) {
+                logout("bad flexible TCB with size 0x%04x\n", tx_buffer_size);
+            } else {
+                cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                         tx_buffer_size);
+                size += tx_buffer_size;
+            }
+            if (tx_buffer_el & 1) {
+                break;
+            }
+        }
+    }
+    TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size,
nic_dump(buf, size)));
+    assert(size <= sizeof(buf));
+    qemu_send_packet(s->vc, buf, size);
+    s->statistics.tx_good_frames++;
+    /* Transmit with bad status would raise an CX/TNO interrupt.
+     * (82557 only). Emulation never has bad status. */
+    //~ eepro100_cx_interrupt(s);
+}
+
+static void set_multicast_list(EEPRO100State *s, uint16_t multicast_count)
+{
+      uint16_t i;
+      memset(&s->mult[0], 0, sizeof(s->mult));
+      TRACE(OTHER, logout("multicast list, multicast count = %u\n",
multicast_count));
+      for (i = 0; i < multicast_count; i += 6) {
+          uint8_t multicast_addr[6];
+          cpu_physical_memory_read(s->cb_address + 10 + i, multicast_addr, 6);
+          TRACE(OTHER, logout("multicast entry %s\n",
nic_dump(multicast_addr, 6)));
+          unsigned mcast_idx = compute_mcast_idx(multicast_addr);
+          assert(mcast_idx < 64);
+          s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
+      }
+}
+
+static void action_command(EEPRO100State *s)
+{
+    for (;;) {
+        s->cb_address = s->cu_base + s->cu_offset;
+        read_cb(s);
+        bool bit_el = ((s->tx.command & COMMAND_EL) != 0);
+        bool bit_s = ((s->tx.command & COMMAND_S) != 0);
+        s->cu_offset = s->tx.link;
+        TRACE(OTHER, logout
+            ("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
+             s->tx.status, s->tx.command, s->cu_offset));
+        switch (s->tx.command & COMMAND_CMD) {
         case CmdNOp:
             /* Do nothing. */
             break;
         case CmdIASetup:
-            cpu_physical_memory_read(cb_address + 8, &s->macaddr[0], 6);
-            logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6));
+            cpu_physical_memory_read(s->cb_address + 8, &s->macaddr[0], 6);
+            TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6)));
+        // !!! missing
             break;
         case CmdConfigure:
-            cpu_physical_memory_read(cb_address + 8, &s->configuration[0],
+            cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
                                      sizeof(s->configuration));
-            logout("configuration: %s\n", nic_dump(&s->configuration[0], 16));
+            TRACE(OTHER, logout("configuration: %s\n",
nic_dump(&s->configuration[0], 16)));
             break;
         case CmdMulticastList:
-            //~ missing("multicast list");
+            set_multicast_list(s, s->tx.tbd_array_addr & BITS(13, 0));
             break;
         case CmdTx:
-            (void)0;
-            uint32_t tbd_array = le32_to_cpu(tx.tx_desc_addr);
-            uint16_t tcb_bytes = (le16_to_cpu(tx.tcb_bytes) & 0x3fff);
-            logout
-                ("transmit, TBD array address 0x%08x, TCB byte count
0x%04x, TBD count %u\n",
-                 tbd_array, tcb_bytes, tx.tbd_count);
-            assert(!bit_nc);
-            //~ assert(!bit_sf);
-            assert(tcb_bytes <= 2600);
-            /* Next assertion fails for local configuration. */
-            //~ assert((tcb_bytes > 0) || (tbd_array != 0xffffffff));
-            if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
-                logout
-                    ("illegal values of TBD array address and TCB
byte count!\n");
-            }
-            uint8_t buf[MAX_ETH_FRAME_SIZE + 4];
-            uint16_t size = 0;
-            uint32_t tbd_address = cb_address + 0x10;
-            assert(tcb_bytes <= sizeof(buf));
-            while (size < tcb_bytes) {
-                uint32_t tx_buffer_address = ldl_phys(tbd_address);
-                uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
-                //~ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
-                tbd_address += 8;
-                logout
-                    ("TBD (simplified mode): buffer address 0x%08x,
size 0x%04x\n",
-                     tx_buffer_address, tx_buffer_size);
-                cpu_physical_memory_read(tx_buffer_address, &buf[size],
-                                         tx_buffer_size);
-                size += tx_buffer_size;
-            }
-            if (tbd_array == 0xffffffff) {
-                /* Simplified mode. Was already handled by code above. */
-            } else {
-                /* Flexible mode. */
-                uint8_t tbd_count = 0;
-                if (!(s->configuration[6] & BIT(4))) {
-                    /* Extended TCB. */
-                    assert(tcb_bytes == 0);
-                    for (; tbd_count < 2; tbd_count++) {
-                        uint32_t tx_buffer_address = ldl_phys(tbd_address);
-                        uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
-                        uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
-                        tbd_address += 8;
-                        logout
-                            ("TBD (extended mode): buffer address
0x%08x, size 0x%04x\n",
-                             tx_buffer_address, tx_buffer_size);
-                        cpu_physical_memory_read(tx_buffer_address, &buf[size],
-                                                 tx_buffer_size);
-                        size += tx_buffer_size;
-                        if (tx_buffer_el & 1) {
-                            break;
-                        }
-                    }
-                }
-                tbd_address = tbd_array;
-                for (; tbd_count < tx.tbd_count; tbd_count++) {
-                    uint32_t tx_buffer_address = ldl_phys(tbd_address);
-                    uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
-                    uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
-                    tbd_address += 8;
-                    logout
-                        ("TBD (flexible mode): buffer address 0x%08x,
size 0x%04x\n",
-                         tx_buffer_address, tx_buffer_size);
-                    cpu_physical_memory_read(tx_buffer_address, &buf[size],
-                                             tx_buffer_size);
-                    size += tx_buffer_size;
-                    if (tx_buffer_el & 1) {
-                        break;
-                    }
-                }
-            }
-            qemu_send_packet(s->vc, buf, size);
-            s->statistics.tx_good_frames++;
-            /* Transmit with bad status would raise an CX/TNO interrupt.
-             * (82557 only). Emulation never has bad status. */
-            //~ eepro100_cx_interrupt(s);
+            tx_command(s);
             break;
         case CmdTDR:
-            logout("load microcode\n");
+            TRACE(OTHER, logout("load microcode\n"));
             /* Starting with offset 8, the command contains
              * 64 dwords microcode which we just ignore here. */
             break;
@@ -792,27 +942,48 @@
             missing("undefined command");
         }
         /* Write new status (success). */
-        stw_phys(cb_address, status | 0x8000 | 0x2000);
-        if (bit_i) {
+        stw_le_phys(s->cb_address, s->tx.status | STATUS_C | STATUS_OK);
+        if (s->tx.command & COMMAND_I) {
             /* CU completed action. */
             eepro100_cx_interrupt(s);
         }
         if (bit_el) {
-            /* CU becomes idle. */
+            /* CU becomes idle. Terminate command loop. */
             set_cu_state(s, cu_idle);
             eepro100_cna_interrupt(s);
+            break;
         } else if (bit_s) {
-            /* CU becomes suspended. */
+            /* CU becomes suspended. Terminate command loop. */
             set_cu_state(s, cu_suspended);
             eepro100_cna_interrupt(s);
+            break;
         } else {
             /* More entries in list. */
-            logout("CU list with at least one more entry\n");
-            goto next_command;
+            TRACE(OTHER, logout("CU list with at least one more entry\n"));
         }
-        logout("CU list empty\n");
-        /* List is empty. Now CU is idle or suspended. */
+    }
+    TRACE(OTHER, logout("CU list empty\n"));
+    /* List is empty. Now CU is idle or suspended. */
+}
+
+static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
+{
+    cu_state_t cu_state;
+    switch (val) {
+    case CU_NOP:
+        /* No operation. */
         break;
+    case CU_START:
+        cu_state = get_cu_state(s);
+        if (cu_state != cu_idle && cu_state != cu_suspended) {
+            /* Intel documentation says that CU must be idle or suspended
+             * for the CU start command. */
+            logout("unexpected CU state is %u\n", cu_state);
+        }
+        set_cu_state(s, cu_active);
+        s->cu_offset = s->pointer;
+        action_command(s);
+        break;
     case CU_RESUME:
         if (get_cu_state(s) != cu_suspended) {
             logout("bad CU resume from CU state %u\n", get_cu_state(s));
@@ -822,15 +993,15 @@
             set_cu_state(s, cu_suspended);
         }
         if (get_cu_state(s) == cu_suspended) {
-            logout("CU resuming\n");
+            TRACE(OTHER, logout("CU resuming\n"));
             set_cu_state(s, cu_active);
-            goto next_command;
+            action_command(s);
         }
         break;
     case CU_STATSADDR:
         /* Load dump counters address. */
         s->statsaddr = s->pointer;
-        logout("val=0x%02x (status address)\n", val);
+        TRACE(OTHER, logout("val=0x%02x (status address)\n", val));
         break;
     case CU_SHOWSTATS:
         /* Dump statistical counters. */
@@ -838,7 +1009,7 @@
         break;
     case CU_CMD_BASE:
         /* Load CU base. */
-        logout("val=0x%02x (CU base address)\n", val);
+        TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
         s->cu_base = s->pointer;
         break;
     case CU_DUMPSTATS:
@@ -869,7 +1040,7 @@
         }
         set_ru_state(s, ru_ready);
         s->ru_offset = s->pointer;
-        logout("val=0x%02x (rx start)\n", val);
+        TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
         break;
     case RX_RESUME:
         /* Restart RU. */
@@ -882,7 +1053,7 @@
         break;
     case RX_ADDR_LOAD:
         /* Load RU base. */
-        logout("val=0x%02x (RU base address)\n", val);
+        TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
         s->ru_base = s->pointer;
         break;
     default:
@@ -896,7 +1067,7 @@
     eepro100_ru_command(s, val & 0x0f);
     eepro100_cu_command(s, val & 0xf0);
     if ((val) == 0) {
-        logout("val=0x%02x\n", val);
+        TRACE(OTHER, logout("val=0x%02x\n", val));
     }
     /* Clear command byte after command was accepted. */
     s->mem[SCBCmd] = 0;
@@ -917,17 +1088,21 @@
 {
     uint16_t val;
     memcpy(&val, &s->mem[SCBeeprom], sizeof(val));
+    val = le16_to_cpu(val);
     if (eeprom93xx_read(s->eeprom)) {
         val |= EEPROM_DO;
     } else {
         val &= ~EEPROM_DO;
+
     }
+    val = cpu_to_le16(val);
+    TRACE(OTHER, logout("val=0x%04x\n", val));
     return val;
 }

 static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
 {
-    logout("write val=0x%02x\n", val);
+    TRACE(OTHER, logout("val=0x%02x\n", val));

     /* mask unwriteable bits */
     //~ val = SET_MASKED(val, 0x31, eeprom->value);
@@ -940,8 +1115,8 @@

 static void eepro100_write_pointer(EEPRO100State * s, uint32_t val)
 {
-    s->pointer = le32_to_cpu(val);
-    logout("val=0x%08x\n", val);
+    s->pointer = val;
+    TRACE(OTHER, logout("val=0x%08x\n", val));
 }

 /*****************************************************************************
@@ -967,12 +1142,26 @@
     "Auto-Negotiation Link Partner Ability",
     "Auto-Negotiation Expansion"
 };
+
+static const char *reg2name(uint8_t reg)
+{
+    static char buffer[10];
+    const char *p = buffer;
+    if (reg < sizeof(mdi_reg_name) / sizeof(*mdi_reg_name)) {
+        p = mdi_reg_name[reg];
+    } else {
+        sprintf(buffer, "reg=0x%02x", reg);
+    }
+    return p;
+}
+
 #endif                          /* DEBUG_EEPRO100 */

 static uint32_t eepro100_read_mdi(EEPRO100State * s)
 {
     uint32_t val;
     memcpy(&val, &s->mem[0x10], sizeof(val));
+    val = le32_to_cpu(val);

 #ifdef DEBUG_EEPRO100
     uint8_t raiseint = (val & BIT(29)) >> 29;
@@ -985,11 +1174,10 @@
     val |= BIT(28);
     TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
                       val, raiseint, mdi_op_name[opcode], phy,
-                      mdi_reg_name[reg], data));
+                      reg2name(reg), data));
     return val;
 }

-//~ #define BITS(val, upper, lower) (val & ???)
 static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
 {
     uint8_t raiseint = (val & BIT(29)) >> 29;
@@ -997,6 +1185,8 @@
     uint8_t phy = (val & BITS(25, 21)) >> 21;
     uint8_t reg = (val & BITS(20, 16)) >> 16;
     uint16_t data = (val & BITS(15, 0));
+    TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+          val, raiseint, mdi_op_name[opcode], phy, reg2name(reg), data));
     if (phy != 1) {
         /* Unsupported PHY address. */
         //~ logout("phy must be 1 but is %u\n", phy);
@@ -1012,7 +1202,7 @@
     } else {
         TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
                           val, raiseint, mdi_op_name[opcode], phy,
-                          mdi_reg_name[reg], data));
+                          reg2name(reg), data));
         if (opcode == 1) {
             /* MDI write */
             switch (reg) {
@@ -1078,6 +1268,7 @@
         }
     }
     val = (val & 0xffff0000) + data;
+    val = cpu_to_le32(val);
     memcpy(&s->mem[0x10], &val, sizeof(val));
 }

@@ -1105,7 +1296,6 @@

 static void eepro100_write_port(EEPRO100State * s, uint32_t val)
 {
-    val = le32_to_cpu(val);
     uint32_t address = (val & ~PORT_SELECTION_MASK);
     uint8_t selection = (val & PORT_SELECTION_MASK);
     switch (selection) {
@@ -1113,15 +1303,15 @@
         nic_reset(s);
         break;
     case PORT_SELFTEST:
-        logout("selftest address=0x%08x\n", address);
+        TRACE(OTHER, logout("selftest address=0x%08x\n", address));
         eepro100_selftest_t data;
         cpu_physical_memory_read(address, (uint8_t *) & data, sizeof(data));
-        data.st_sign = 0xffffffff;
-        data.st_result = 0;
+        data.st_sign = cpu_to_le32(0xffffffff);
+        data.st_result = cpu_to_le32(0);
         cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data));
         break;
     case PORT_SELECTIVE_RESET:
-        logout("selective reset, selftest address=0x%08x\n", address);
+        TRACE(OTHER, logout("selective reset, selftest
address=0x%08x\n", address));
         nic_selective_reset(s);
         break;
     default:
@@ -1146,33 +1336,36 @@
     switch (addr) {
     case SCBStatus:
         //~ val = eepro100_read_status(s);
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
     case SCBAck:
         //~ val = eepro100_read_status(s);
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
     case SCBCmd:
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         //~ val = eepro100_read_command(s);
         break;
     case SCBIntmask:
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
     case SCBPort + 3:
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
     case SCBeeprom:
-        val = eepro100_read_eeprom(s);
+        val = le16_to_cpu(eepro100_read_eeprom(s));
         break;
-    case 0x1b:                 /* PMDR (power management driver register) */
+    case SCBpmdr:       /* Power Management Driver Register */
         val = 0;
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
-    case 0x1d:                 /* general status register */
+    case SCBgctrl:      /* General Control Register */
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBgstat:      /* General Status Register */
         /* 100 Mbps full duplex, valid link */
         val = 0x07;
-        logout("addr=General Status val=%02x\n", val);
+        TRACE(OTHER, logout("addr=General Status val=%02x\n", val));
         break;
     default:
         logout("addr=%s val=0x%02x\n", regname(addr), val);
@@ -1187,50 +1380,59 @@
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&val, &s->mem[addr], sizeof(val));
     }
+    val = le16_to_cpu(val);

-    logout("addr=%s val=0x%04x\n", regname(addr), val);
-
     switch (addr) {
     case SCBStatus:
         //~ val = eepro100_read_status(s);
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
         break;
     case SCBeeprom:
         val = eepro100_read_eeprom(s);
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
         break;
     default:
         logout("addr=%s val=0x%04x\n", regname(addr), val);
         missing("unknown word read");
     }
+    val = cpu_to_le16(val);
+#if defined(TARGET_WORDS_BIGENDIAN)
+    val = bswap16(val);
+#endif
     return val;
 }

 static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
 {
-    uint32_t val;
+    uint32_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&val, &s->mem[addr], sizeof(val));
     }
-
+    val = le32_to_cpu(val);
     switch (addr) {
     case SCBStatus:
         //~ val = eepro100_read_status(s);
-        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
         break;
     case SCBPointer:
         //~ val = eepro100_read_pointer(s);
-        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
         break;
     case SCBPort:
         val = eepro100_read_port(s);
-        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
         break;
     case SCBCtrlMDI:
-        val = eepro100_read_mdi(s);
+        val = le32_to_cpu(eepro100_read_mdi(s));
         break;
     default:
         logout("addr=%s val=0x%08x\n", regname(addr), val);
         missing("unknown longword read");
     }
+    val = cpu_to_le32(val);
+#if defined(TARGET_WORDS_BIGENDIAN)
+    val = bswap32(val);
+#endif
     return val;
 }

@@ -1240,7 +1442,7 @@
         memcpy(&s->mem[addr], &val, sizeof(val));
     }

-    logout("addr=%s val=0x%02x\n", regname(addr), val);
+    TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));

     switch (addr) {
     case SCBStatus:
@@ -1259,11 +1461,11 @@
         eepro100_interrupt(s, 0);
         break;
     case SCBPort + 3:
-    case SCBFlow:
+    case SCBFlow:       /* does not exist on 82557 */
     case SCBFlow + 1:
     case SCBFlow + 2:
-    case SCBFlow + 3:
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
+    case SCBpmdr:       /* does not exist on 82557 */
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
         break;
     case SCBeeprom:
         eepro100_write_eeprom(s->eeprom, val);
@@ -1276,12 +1478,17 @@

 static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
 {
+#if defined(TARGET_WORDS_BIGENDIAN)
+    val = bswap16(val);
+#endif
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&s->mem[addr], &val, sizeof(val));
     }

-    logout("addr=%s val=0x%04x\n", regname(addr), val);
+    val = le16_to_cpu(val);

+    TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+
     switch (addr) {
     case SCBStatus:
         //~ eepro100_write_status(s, val);
@@ -1302,16 +1509,21 @@

 static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
 {
+#if defined(TARGET_WORDS_BIGENDIAN)
+    val = bswap32(val);
+#endif
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&s->mem[addr], &val, sizeof(val));
     }

+    //~ val = le32_to_cpu(val);
+
     switch (addr) {
     case SCBPointer:
         eepro100_write_pointer(s, val);
         break;
     case SCBPort:
-        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
         eepro100_write_port(s, val);
         break;
     case SCBCtrlMDI:
@@ -1323,6 +1535,12 @@
     }
 }

+/*****************************************************************************
+ *
+ * Port mapped I/O.
+ *
+ ****************************************************************************/
+
 static uint32_t ioport_read1(void *opaque, uint32_t addr)
 {
     EEPRO100State *s = opaque;
@@ -1364,7 +1582,7 @@
 /***********************************************************/
 /* PCI EEPRO100 definitions */

-typedef struct PCIEEPRO100State {
+typedef struct {
     PCIDevice dev;
     EEPRO100State eepro100;
 } PCIEEPRO100State;
@@ -1375,8 +1593,8 @@
     PCIEEPRO100State *d = (PCIEEPRO100State *) pci_dev;
     EEPRO100State *s = &d->eepro100;

-    logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
-           region_num, addr, size, type);
+    TRACE(OTHER, logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
+          region_num, addr, size, type));

     assert(region_num == 1);
     register_ioport_write(addr, size, 1, ioport_write1, s);
@@ -1389,6 +1607,12 @@
     s->region[region_num] = addr;
 }

+/*****************************************************************************
+ *
+ * Memory mapped I/O.
+ *
+ ****************************************************************************/
+
 static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val)
 {
     EEPRO100State *s = opaque;
@@ -1454,8 +1678,8 @@
 {
     PCIEEPRO100State *d = (PCIEEPRO100State *) pci_dev;

-    logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
-           region_num, addr, size, type);
+    TRACE(OTHER, logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
+          region_num, addr, size, type));

     if (region_num == 0) {
         /* Map control / status registers. */
@@ -1467,7 +1691,7 @@
 static int nic_can_receive(void *opaque)
 {
     EEPRO100State *s = opaque;
-    logout("%p\n", s);
+    TRACE(RXTX, logout("%p\n", s));
     return get_ru_state(s) == ru_ready;
     //~ return !eepro100_buffer_full(s);
 }
@@ -1506,36 +1730,40 @@
     } else if (memcmp(buf, s->macaddr, 6) == 0) {       // !!!
         /* Frame matches individual address. */
         /* TODO: check configuration byte 15/4 (ignore U/L). */
-        logout("%p received frame for me, len=%d\n", s, size);
+        TRACE(RXTX, logout("%p received frame for me, len=%d\n", s, size));
     } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
         /* Broadcast frame. */
-        logout("%p received broadcast, len=%d\n", s, size);
+        TRACE(RXTX, logout("%p received broadcast, len=%d\n", s, size));
         rfd_status |= 0x0002;
     } else if (buf[0] & 0x01) { // !!!
         /* Multicast frame. */
-        logout("%p received multicast, len=%d\n", s, size);
-        /* TODO: check multicast all bit. */
-        assert(!(s->configuration[21] & BIT(3)));
-        int mcast_idx = compute_mcast_idx(buf);
-        if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) {
-            return;
+        TRACE(RXTX, logout("%p received multicast, len=%d,%s\n", s,
size, nic_dump(buf, size)));
+        if (s->configuration[21] & BIT(3)) {
+          /* Multicast all bit is set, receive all frames. */
+        } else {
+          unsigned mcast_idx = compute_mcast_idx(buf);
+          assert(mcast_idx < 64);
+          if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) {
+              TRACE(RXTX, logout("%p multicast ignored\n", s));
+              return;
+          }
         }
         rfd_status |= 0x0002;
     } else if (s->configuration[15] & 1) {
         /* Promiscuous: receive all. */
-        logout("%p received frame in promiscuous mode, len=%d\n", s, size);
+        TRACE(RXTX, logout("%p received frame in promiscuous mode,
len=%d\n", s, size));
         rfd_status |= 0x0004;
     } else {
-        logout("%p received frame, ignored, len=%d,%s\n", s, size,
-               nic_dump(buf, size));
+        TRACE(RXTX, logout("%p received frame, ignored, len=%d,%s\n", s, size,
+               nic_dump(buf, size)));
         return;
     }

     if (get_ru_state(s) != ru_ready) {
-        /* No ressources available. */
-        logout("no ressources, state=%u\n", get_ru_state(s));
+        /* No resources available. */
+        logout("no resources, state=%u\n", get_ru_state(s));
         s->statistics.rx_resource_errors++;
-        //~ assert(!"no ressources");
+        //~ assert(!"no resources");
         return;
     }
     //~ !!!
@@ -1543,17 +1771,21 @@
     eepro100_rx_t rx;
     cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx,
                              offsetof(eepro100_rx_t, packet));
+    // !!!
     uint16_t rfd_command = le16_to_cpu(rx.command);
     uint16_t rfd_size = le16_to_cpu(rx.size);
-    assert(size <= rfd_size);
+    if (size > rfd_size) {
+      logout("received frame with %d > %u\n", size, rfd_size);
+      UNEXPECTED();
+    }
     if (size < 64) {
         rfd_status |= 0x0080;
     }
-    logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n", rfd_command,
-           rx.link, rx.rx_buf_addr, rfd_size);
-    stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status),
-             rfd_status);
-    stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size);
+    TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
+          rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
+    stw_le_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status),
+                rfd_status);
+    stw_le_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t,
count), size);
     /* Early receive interrupt not supported. */
     //~ eepro100_er_interrupt(s);
     /* Receive CRC Transfer not supported. */
@@ -1567,7 +1799,7 @@
     s->ru_offset = le32_to_cpu(rx.link);
     if (rfd_command & 0x8000) {
         /* EL bit is set, so this was the last frame. */
-        assert(0);
+        set_ru_state(s, ru_idle);
     }
     if (rfd_command & 0x4000) {
         /* S bit is set. */
@@ -1742,15 +1974,14 @@
     qemu_put_buffer(f, s->configuration, sizeof(s->configuration));
 }

-static void nic_init(PCIBus * bus, NICInfo * nd,
-                     const char *name, uint32_t device)
+static void nic_init(PCIBus * bus, NICInfo * nd, uint32_t device)
 {
     PCIEEPRO100State *d;
     EEPRO100State *s;

-    logout("\n");
+    TRACE(OTHER, logout("\n"));

-    d = (PCIEEPRO100State *) pci_register_device(bus, name,
+    d = (PCIEEPRO100State *) pci_register_device(bus, nd->model,
                                                  sizeof(PCIEEPRO100State), -1,
                                                  NULL, NULL);

@@ -1760,9 +1991,11 @@

     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 */
     d->eepro100.mmio_index =
@@ -1777,7 +2010,7 @@
                            pci_mmio_map);

     memcpy(s->macaddr, nd->macaddr, 6);
-    logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6));
+    TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6)));
     assert(s->region[1] == 0);

     nic_reset(s);
@@ -1786,29 +2019,38 @@

     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "eepro100 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
-             s->macaddr[0],
-             s->macaddr[1],
-             s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]);
+             s->macaddr[0], s->macaddr[1], s->macaddr[2],
+             s->macaddr[3], s->macaddr[4], s->macaddr[5]);

     qemu_register_reset(nic_reset, s);

-    register_savevm(name, -1, 3, nic_save, nic_load, s);
+    register_savevm(nd->model, -1, 3, nic_save, nic_load, s);
 }

-void pci_i82551_init(PCIBus * bus, NICInfo * nd, int devfn)
-{
-    nic_init(bus, nd, "i82551", i82551);
-    //~ uint8_t *pci_conf = d->dev.config;
-}
+typedef struct {
+  const char *name;
+  unsigned value;
+} key_value_t;

-void pci_i82557b_init(PCIBus * bus, NICInfo * nd, int devfn)
-{
-    nic_init(bus, nd, "i82557b", i82557B);
-}
+static const key_value_t devicetable[] = {
+  {"i82551", i82551},
+  {"i82557a", i82557A},
+  {"i82557b", i82557B},
+  {"i82557c", i82557C},
+  {"i82558b", i82558B},
+  {"i82559c", i82559C},
+  {"i82559er", i82559ER},
+};

-void pci_i82559er_init(PCIBus * bus, NICInfo * nd, int devfn)
+void pci_eepro100_init(PCIBus * bus, NICInfo * nd, int devfn)
 {
-    nic_init(bus, nd, "i82559er", i82559ER);
+  size_t i;
+  for (i = 0; i < sizeof(devicetable) / sizeof(*devicetable); i++) {
+    if (strcmp(devicetable[i].name, nd->model) == 0) {
+      nic_init(bus, nd, devicetable[i].value);
+      break;
+    }
+  }
 }

 /* eof */

reply via email to

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