diff -Naur qemu-0.10.6/hw/eepro100.c qemu-0.10.6-e100/hw/eepro100.c --- qemu-0.10.6/hw/eepro100.c 2009-07-16 20:56:22.000000000 -0400 +++ qemu-0.10.6-e100/hw/eepro100.c 2009-11-10 12:30:42.000000000 -0500 @@ -74,10 +74,12 @@ #define KiB 1024 /* debug EEPRO100 card */ -//~ #define DEBUG_EEPRO100 +#define DEBUG_EEPRO100 + +int e100_debug = 0; #ifdef DEBUG_EEPRO100 -#define logout(fmt, args...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ##args) +#define logout(fmt, args...) {if (e100_debug) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ##args);} #else #define logout(fmt, args...) ((void)0) #endif @@ -173,6 +175,15 @@ } eepro100_rx_t; typedef struct { + uint16_t count; + uint16_t pad0; + uint32_t link; + uint32_t buf_addr; + uint16_t size; + uint16_t pad1; +} 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, tx_multiple_collisions, tx_total_collisions; @@ -243,6 +254,7 @@ /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */ uint32_t ru_base; /* RU base address */ uint32_t ru_offset; /* RU address offset */ + uint32_t rbd_offset; /* RBD address offset */ uint32_t statsaddr; /* pointer to eepro100_stats_t */ eepro100_stats_t statistics; /* statistical counters */ #if 0 @@ -723,20 +735,13 @@ 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; + if (tbd_array == 0xffffffff) { + /* Simplified mode. */ 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. */ + tbd_address, tcb_bytes); + cpu_physical_memory_read(tbd_address, buf, tcb_bytes); + size = tcb_bytes; } else { /* Flexible mode. */ uint8_t tbd_count = 0; @@ -745,7 +750,7 @@ 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_size = lduw_phys(tbd_address + 4) & 0x3fff; uint16_t tx_buffer_el = lduw_phys(tbd_address + 6); tbd_address += 8; logout @@ -868,6 +873,16 @@ } set_ru_state(s, ru_ready); s->ru_offset = s->pointer; + + 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); + + /* If the SF bit is set, then use flexible mode. */ + if (rfd_command & 0x0008) + s->rbd_offset = le32_to_cpu(rx.rx_buf_addr); + logout("val=0x%02x (rx start)\n", val); break; case RX_RESUME: @@ -884,6 +899,10 @@ logout("val=0x%02x (RU base address)\n", val); s->ru_base = s->pointer; break; + case RX_ABORT: + /* TODO XXX _AP_ need to generate interrupts and halt all activity. */ + set_ru_state(s, ru_idle); + break; default: logout("val=0x%02x (undefined RU command)\n", val); missing("Undefined SU command"); @@ -1538,7 +1557,7 @@ 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 < 64) { rfd_status |= 0x0080; } @@ -1546,15 +1565,33 @@ 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); /* Early receive interrupt not supported. */ //~ eepro100_er_interrupt(s); /* Receive CRC Transfer not supported. */ assert(!(s->configuration[18] & 4)); /* TODO: check stripping enable bit. */ //~ assert(!(s->configuration[17] & 1)); - cpu_physical_memory_write(s->ru_base + s->ru_offset + - offsetof(eepro100_rx_t, packet), buf, size); + + if (rfd_command & 0x0008) { + /* XXX TODO _AP_ support more links */ + eepro100_rbd_t rbd; + int wrote = 0; + do { + cpu_physical_memory_read(s->ru_base + s->rbd_offset, (uint8_t *) &rbd, sizeof(rbd)); + int w = (size - wrote) > rbd.size ? rbd.size : (size - wrote); + cpu_physical_memory_write(s->ru_base + rbd.buf_addr, buf + wrote, w); + stw_phys(s->ru_base + s->rbd_offset, w | 0x8000 | 0x4000); + wrote += w; + s->rbd_offset = le32_to_cpu(rbd.link); + } while(wrote < size); + } else { + /* Simplified mode. */ + assert(size <= rfd_size); + cpu_physical_memory_write(s->ru_base + s->ru_offset + + offsetof(eepro100_rx_t, packet), buf, size); + } + /* Update the EOF and F bits in addition to setting the size. */ + stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size | 0x8000 | 0x4000); s->statistics.rx_good_frames++; eepro100_fr_interrupt(s); s->ru_offset = le32_to_cpu(rx.link); @@ -1624,6 +1661,7 @@ qemu_get_be32s(f, &s->cu_offset); qemu_get_be32s(f, &s->ru_base); qemu_get_be32s(f, &s->ru_offset); + qemu_get_be32s(f, &s->rbd_offset); qemu_get_be32s(f, &s->statsaddr); /* Restore epro100_stats_t statistics */ qemu_get_be32s(f, &s->statistics.tx_good_frames); @@ -1703,6 +1741,7 @@ qemu_put_be32s(f, &s->cu_offset); qemu_put_be32s(f, &s->ru_base); qemu_put_be32s(f, &s->ru_offset); + qemu_put_be32s(f, &s->rbd_offset); qemu_put_be32s(f, &s->statsaddr); /* Save epro100_stats_t statistics */ qemu_put_be32s(f, &s->statistics.tx_good_frames);