diff options
Diffstat (limited to 'hw/eepro100.c')
-rw-r--r-- | hw/eepro100.c | 193 |
1 files changed, 99 insertions, 94 deletions
diff --git a/hw/eepro100.c b/hw/eepro100.c index d0c45bfbbb..3467f77898 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -212,6 +212,11 @@ typedef struct { uint32_t ru_offset; /* RU address offset */ uint32_t statsaddr; /* pointer to eepro100_stats_t */ + /* Temporary status information (no need to save these values), + * used while processing CU commands. */ + eepro100_tx_t tx; /* transmit buffer descriptor */ + uint32_t cb_address; /* = cu_base + cu_offset */ + /* Statistical counters. Also used for wake-up packet (i82559). */ eepro100_stats_t statistics; @@ -760,17 +765,100 @@ static void dump_statistics(EEPRO100State * s) //~ missing("CU dump statistical counters"); } +static void tx_command(EEPRO100State *s) +{ + uint32_t tbd_array = le32_to_cpu(s->tx.tx_desc_addr); + uint16_t tcb_bytes = (le16_to_cpu(s->tx.tcb_bytes) & 0x3fff); + /* 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 = 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)); + + if (tcb_bytes > 2600) { + logout("TCB byte count too large, using 2600\n"); + tcb_bytes = 2600; + } + if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) { + logout + ("illegal values of TBD array address and TCB byte count!\n"); + } + 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 (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); + 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 < 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->nic->nc, 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 (;;) { - uint32_t cb_address = s->cu_base + s->cu_offset; - eepro100_tx_t tx; - 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); + s->cb_address = s->cu_base + s->cu_offset; + cpu_physical_memory_read(s->cb_address, (uint8_t *)&s->tx, sizeof(s->tx)); + uint16_t status = le16_to_cpu(s->tx.status); + uint16_t 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); + val, status, command, s->tx.link); bool bit_el = ((command & 0x8000) != 0); bool bit_s = ((command & 0x4000) != 0); bool bit_i = ((command & 0x2000) != 0); @@ -778,17 +866,17 @@ static void action_command(EEPRO100State *s) bool success = true; //~ bool bit_sf = ((command & 0x0008) != 0); uint16_t cmd = command & 0x0007; - s->cu_offset = le32_to_cpu(tx.link); + 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->conf.macaddr.a[0], 6); + cpu_physical_memory_read(s->cb_address + 8, &s->conf.macaddr.a[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; @@ -796,95 +884,12 @@ static void action_command(EEPRO100State *s) //~ 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)); - if (bit_nc) { missing("CmdTx: NC = 0"); success = false; break; } - //~ assert(!bit_sf); - if (tcb_bytes > 2600) { - logout("TCB byte count too large, using 2600\n"); - 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 (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); - 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->nic->nc, 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")); @@ -897,7 +902,7 @@ static void action_command(EEPRO100State *s) break; } /* Write new status. */ - stw_phys(cb_address, status | 0x8000 | (success ? 0x2000 : 0)); + stw_phys(s->cb_address, status | 0x8000 | (success ? 0x2000 : 0)); if (bit_i) { /* CU completed action. */ eepro100_cx_interrupt(s); |