@@ -56,7 +56,7 @@
#define KiB 1024
/* Debug EEPRO100 card. */
-//~ #define DEBUG_EEPRO100
+/* #define DEBUG_EEPRO100 */
#ifdef DEBUG_EEPRO100
#define logout(fmt, ...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ## __VA_ARGS__)
@@ -214,6 +214,11 @@ typedef struct {
uint32_t ru_base; /* RU base address */
uint32_t ru_offset; /* RU address offset */
uint32_t statsaddr; /* pointer to eepro100_stats_t */
+
+ /* Temporary data. */
+ eepro100_tx_t tx;
+ uint32_t cb_address;
+
/* Statistical counters. Also used for wake-up packet (i82559). */
eepro100_stats_t statistics;
#if 0
@@ -412,13 +417,9 @@ static void pci_reset(EEPRO100State * s)
/* check cache line size!!! */
//~ PCI_CONFIG_8(0x0c, 0x00);
/* PCI Latency Timer */
- PCI_CONFIG_8(0x0d, 0x20); // latency timer = 32 clocks
+ PCI_CONFIG_8(0x0d, 0x20); /* latency timer = 32 clocks */
/* PCI Header Type */
/* 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 */
@@ -437,7 +438,7 @@ static void pci_reset(EEPRO100State * s)
PCI_CONFIG_8(0x34, 0xdc);
/* Interrupt Line */
/* Interrupt Pin */
- PCI_CONFIG_8(0x3d, 1); // interrupt pin 0
+ PCI_CONFIG_8(0x3d, 1); /* interrupt pin 0 */
/* Minimum Grant */
PCI_CONFIG_8(0x3e, 0x08);
/* Maximum Latency */
@@ -631,49 +632,122 @@ static void dump_statistics(EEPRO100State * s)
//~ missing("CU dump statistical counters");
}
-static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
-{
- 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");
+static void tx_command(EEPRO100State *s)
+{
+ /* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */
+ uint8_t buf[2600];
+ uint16_t size = 0;
+ uint32_t tbd_array = le32_to_cpu(s->tx.tx_desc_addr);
+ uint16_t tcb_bytes = (le16_to_cpu(s->tx.tcb_bytes) & 0x3fff);
+ uint32_t tbd_address;
+ 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(!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");
+ }
+ tbd_address = s->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;
+ TRACE(RXTX, logout
+ ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
+ tx_buffer_address, tx_buffer_size));
+ tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - 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 (device_supports_eTxCB(s) && !(s->configuration[6] & BIT(4))) {
+ /* Extended Flexible 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;
+ TRACE(RXTX, logout
+ ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
+ tx_buffer_address, tx_buffer_size));
+ tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
+ cpu_physical_memory_read(tx_buffer_address, &buf[size],
+ tx_buffer_size);
+ size += tx_buffer_size;
+ if (tx_buffer_el & 1) {
+ break;
+ }
+ }
}
- 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);
+ tbd_address = tbd_array;
+ for (; tbd_count < s->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;
+ TRACE(RXTX, logout
+ ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
+ tx_buffer_address, tx_buffer_size));
+ tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
+ 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)));
+ 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 action_command(EEPRO100State *s)
+{
+ for (;;) {
+ uint16_t status;
+ uint16_t command;
+ bool bit_el;
+ bool bit_s;
+ bool bit_i;
+ uint16_t cmd;
+ s->cb_address = s->cu_base + s->cu_offset;
+ cpu_physical_memory_read(s->cb_address, (uint8_t *)&s->tx, sizeof(s->tx));
+ status = le16_to_cpu(s->tx.status);
+ command = le16_to_cpu(s->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);
+ val, status, command, s->tx.link);
+ bit_el = ((command & 0x8000) != 0);
+ bit_s = ((command & 0x4000) != 0);
+ bit_i = ((command & 0x2000) != 0);
+ cmd = command & 0x0007;
+ s->cu_offset = le32_to_cpu(s->tx.link);
switch (cmd) {
case CmdNOp:
/* Do nothing. */
break;
case CmdIASetup:
- cpu_physical_memory_read(cb_address + 8, &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)));
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));
TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16)));
break;
@@ -681,88 +755,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
//~ missing("multicast list");
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);
- TRACE(RXTX, 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");
- }
- // sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes
- uint8_t buf[2600];
- 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;
- TRACE(RXTX, logout
- ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
- tx_buffer_address, tx_buffer_size));
- tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - 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 (device_supports_eTxCB(s) && !(s->configuration[6] & BIT(4))) {
- /* Extended Flexible 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;
- TRACE(RXTX, logout
- ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
- tx_buffer_address, tx_buffer_size));
- tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - 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;
- TRACE(RXTX, logout
- ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
- tx_buffer_address, tx_buffer_size));
- tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
- 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)));
- 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:
TRACE(OTHER, logout("load microcode\n"));
@@ -773,7 +766,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
missing("undefined command");
}
/* Write new status (success). */
- stw_phys(cb_address, status | 0x8000 | 0x2000);
+ stw_phys(s->cb_address, status | 0x8000 | 0x2000);
if (bit_i) {
/* CU completed action. */
eepro100_cx_interrupt(s);
@@ -782,17 +775,38 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
/* 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. */
TRACE(OTHER, logout("CU list with at least one more entry\n"));
- goto next_command;
}
- TRACE(OTHER, 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)
+{
+ 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");
+ }
+ 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) {
@@ -805,7 +819,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
if (get_cu_state(s) == cu_suspended) {
TRACE(OTHER, logout("CU resuming\n"));
set_cu_state(s, cu_active);
- goto next_command;
+ action_command(s);
}
break;
case CU_STATSADDR:
@@ -1505,7 +1519,7 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size
* Long frames are discarded. */
logout("%p received long frame (%zu byte), ignored\n", s, size);
return -1;
- } else if (memcmp(buf, s->macaddr, 6) == 0) { // !!!
+ } else if (memcmp(buf, s->macaddr, 6) == 0) { /* !!! */
/* Frame matches individual address. */
/* TODO: check configuration byte 15/4 (ignore U/L). */
TRACE(RXTX, logout("%p received frame for me, len=%zu\n", s, size));
@@ -1513,7 +1527,7 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size
/* Broadcast frame. */
TRACE(RXTX, logout("%p received broadcast, len=%zu\n", s, size));
rfd_status |= 0x0002;
- } else if (buf[0] & 0x01) { // !!!
+ } else if (buf[0] & 0x01) { /* !!! */
/* Multicast frame. */
TRACE(RXTX, logout("%p received multicast, len=%zu\n", s, size));
/* TODO: check multicast all bit. */
* Move common code for CU_START, CU_RESUME to new function action_command. * Move code for CmdTx to new function tx_command. 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 <weil@mail.berlios.de> --- hw/eepro100.c | 270 ++++++++++++++++++++++++++++++--------------------------- 1 files changed, 142 insertions(+), 128 deletions(-)