@@ -126,41 +126,6 @@ enum speedo_offsets {
SCBFlow = 24,
};
-/* 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. */
- 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 */
- //~ /* This constitutes two "TBD" entries: hdr and data */
- //~ uint32_t tx_buf_addr0; /* void *, header of frame to be transmitted. */
- //~ int32_t tx_buf_size0; /* Length of Tx hdr. */
- //~ uint32_t tx_buf_addr1; /* void *, data to be transmitted. */
- //~ int32_t tx_buf_size1; /* Length of Tx data. */
-} eepro100_tx_t;
-
-/* Receive frame descriptor. */
-typedef struct {
- int16_t status;
- uint16_t command;
- uint32_t link; /* struct RxFD * */
- uint32_t rx_buf_addr; /* void * */
- uint16_t count;
- uint16_t size;
- char packet[MAX_ETH_FRAME_SIZE + 4];
-} eepro100_rx_t;
-
-/* Receive buffer descriptor. */
-typedef struct {
- uint32_t count;
- uint32_t link;
- uint32_t buffer;
- uint32_t size;
-} eepro100_rbd_t;
-
typedef struct {
uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
@@ -229,6 +194,7 @@ typedef struct {
uint32_t rbd_addr;
uint32_t statsaddr; /* pointer to eepro100_stats_t */
eepro100_stats_t statistics; /* statistical counters */
+ int stats_size;
#if 0
uint16_t status;
#endif
@@ -621,26 +587,29 @@ static void set_ru_state(EEPRO100State * s, ru_state_t state)
s->mem[SCBStatus] = (s->mem[SCBStatus] & 0xc3) + (state << 2);
}
-static void dump_statistics(EEPRO100State * s)
+static void dump_statistics(EEPRO100State * s, int reset)
{
/* Dump statistical data. Most data is never changed by the emulation
* and always 0, so we first just copy the whole block and then those
* values which really matter.
* Number of data should check configuration!!!
*/
- cpu_physical_memory_write(s->statsaddr, (uint8_t *) & s->statistics, 64);
+ uint8_t zeros[80];
+ assert(s->stats_size <= sizeof(zeros));
+ memset(zeros, 0, sizeof(zeros));
+ cpu_physical_memory_write(s->statsaddr, zeros, 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);
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);
- //~ missing("CU dump statistical counters");
+ stl_phys(s->statsaddr + s->stats_size, reset ? 0xA007 : 0xA005);
+ memset(&s->statistics, 0, sizeof(s->statistics));
}
static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
{
- eepro100_tx_t tx;
uint32_t cb_address;
switch (val) {
case CU_NOP:
@@ -658,19 +627,21 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
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);
+ uint16_t status = lduw_phys(cb_address);
+ uint16_t command = lduw_phys(cb_address + 2);
+ s->cu_offset = ldl_phys (cb_address + 4);
+ uint32_t tbd_array = ldl_phys (cb_address + 8);
+ uint16_t tcb_bytes = lduw_phys(cb_address + 12) & 0x3fff;
+ uint8_t tx_tbd_count = ldub_phys(cb_address + 15);
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->cu_offset);
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) {
case CmdNOp:
/* Do nothing. */
@@ -689,11 +660,9 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
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);
+ tbd_array, tcb_bytes, tx_tbd_count);
assert(!bit_nc);
//~ assert(!bit_sf);
assert(tcb_bytes <= 2600);
@@ -744,7 +713,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
}
}
tbd_address = tbd_array;
- for (; tbd_count < tx.tbd_count; tbd_count++) {
+ 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);
@@ -821,7 +790,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
break;
case CU_SHOWSTATS:
/* Dump statistical counters. */
- dump_statistics(s);
+ dump_statistics(s, 0);
break;
case CU_CMD_BASE:
/* Load CU base. */
@@ -830,8 +799,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
break;
case CU_DUMPSTATS:
/* Dump and reset statistical counters. */
- dump_statistics(s);
- memset(&s->statistics, 0, sizeof(s->statistics));
+ dump_statistics(s, 1);
break;
case CU_SRESUME:
/* CU static resume. */
@@ -1082,11 +1050,6 @@ static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
#define PORT_DUMP 3
#define PORT_SELECTION_MASK 3
-typedef struct {
- uint32_t st_sign; /* Self Test Signature */
- uint32_t st_result; /* Self Test Results */
-} eepro100_selftest_t;
-
static uint32_t eepro100_read_port(EEPRO100State * s)
{
return 0;
@@ -1103,11 +1066,10 @@ static void eepro100_write_port(EEPRO100State * s, uint32_t val)
break;
case PORT_SELFTEST:
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;
- cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data));
+ // self-test signature, driver initializes to 0
+ stl_phys(address, 0xffffffff);
+ // self-test result (failure bitmask), driver initializes to 0xffffffff
+ stl_phys(address + 4, 0);
break;
case PORT_SELECTIVE_RESET:
logout("selective reset, selftest address=0x%08x\n", address);
@@ -1530,29 +1492,30 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size
}
//~ !!!
//~ $3 = {status = 0x0, command = 0xc000, link = 0x2d220, rx_buf_addr = 0x207dc, count = 0x0, size = 0x5f8, packet = {0x0 <repeats 1518 times>}}
- 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);
- uint32_t rfd_size = le16_to_cpu(rx.size);
- uint32_t dst_addr = s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, packet);
+ uint32_t rx = s->ru_base + s->ru_offset;
+ // Read and update the receive frame descriptor (RFD)
+ stw_phys (rx, rfd_status);
+ uint16_t rfd_command = lduw_phys(rx + 2);
+ s->ru_offset = ldl_phys (rx + 4);
+ uint32_t rfd_rbd = ldl_phys (rx + 8);
+ stw_phys (rx + 12, size);
+ uint32_t rfd_size = lduw_phys(rx + 14);
+ uint32_t dst_addr = rx + 16;
if (rfd_command & 8) {
// argh! Flexible mode. Intel docs say it is not supported but the Mac OS driver uses it anyway.
- eepro100_rbd_t rbd;
- if (!s->rbd_addr)
- s->rbd_addr = le32_to_cpu(rx.rx_buf_addr);
- cpu_physical_memory_read(s->rbd_addr, (uint8_t *) & rbd, sizeof(rbd));
- rfd_size = le32_to_cpu(rbd.size);
- dst_addr = le32_to_cpu(rbd.buffer);
- stl_phys(s->rbd_addr + offsetof(eepro100_rbd_t, count), size | 0x8000);
- s->rbd_addr = le32_to_cpu(rbd.link);
+ // Read and update the receive buffer descriptor (RBD)
+ if (s->rbd_addr)
+ // Only the RBD address in the first RFD is valid, if we have a
+ // link value from a previous RBD follow that instead.
+ rfd_rbd = s->rbd_addr;
+ stl_phys(rfd_rbd, size | 0x8000);
+ s->rbd_addr = ldl_phys(rfd_rbd + 4);
+ dst_addr = ldl_phys(rfd_rbd + 8);
+ rfd_size = ldl_phys(rfd_rbd + 12);
}
assert(size <= rfd_size);
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);
+ rfd_link, rfd_rbd, rfd_size);
/* Early receive interrupt not supported. */
//~ eepro100_er_interrupt(s);
/* Receive CRC Transfer not supported. */
@@ -1562,7 +1525,6 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size
cpu_physical_memory_write(dst_addr, buf, size);
s->statistics.rx_good_frames++;
eepro100_fr_interrupt(s);
- s->ru_offset = le32_to_cpu(rx.link);
if (rfd_command & 0x8000) {
/* EL bit is set, so this was the last frame. */
set_ru_state(s, ru_no_resources);
@@ -1772,6 +1734,23 @@ static void nic_init(PCIDevice *pci_dev, uint32_t device)
s = &d->eepro100;
s->device = device;
s->pci_dev = &d->dev;
+ s->stats_size = 64;
+ switch (device) {
+ case i82551:
+ break;
+ case i82557B:
+ case i82557C:
+ break;
+ case i82558B:
+ s->stats_size = 76;
+ break;
+ case i82559C:
+ case i82559ER:
+ s->stats_size = 80;
+ break;
+ default:
+ assert(!"Unknown device set");
+ }
pci_reset(s);