Commit 5198cfd9277af376c0d1c667f5a1943f100fee45
1 parent
68998c5d
smc91c111 fixes (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1713 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
27 additions
and
5 deletions
hw/smc91c111.c
| ... | ... | @@ -35,8 +35,10 @@ typedef struct { |
| 35 | 35 | int tx_fifo[NUM_PACKETS]; |
| 36 | 36 | int rx_fifo_len; |
| 37 | 37 | int rx_fifo[NUM_PACKETS]; |
| 38 | + int tx_fifo_done_len; | |
| 39 | + int tx_fifo_done[NUM_PACKETS]; | |
| 38 | 40 | /* Packet buffer memory. */ |
| 39 | - uint8_t data[2048][NUM_PACKETS]; | |
| 41 | + uint8_t data[NUM_PACKETS][2048]; | |
| 40 | 42 | uint8_t int_level; |
| 41 | 43 | uint8_t int_mask; |
| 42 | 44 | uint8_t macaddr[6]; |
| ... | ... | @@ -81,6 +83,8 @@ static void smc91c111_update(smc91c111_state *s) |
| 81 | 83 | |
| 82 | 84 | if (s->tx_fifo_len == 0) |
| 83 | 85 | s->int_level |= INT_TX_EMPTY; |
| 86 | + if (s->tx_fifo_done_len != 0) | |
| 87 | + s->int_level |= INT_TX; | |
| 84 | 88 | level = (s->int_level & s->int_mask) != 0; |
| 85 | 89 | pic_set_irq_new(s->pic, s->irq, level); |
| 86 | 90 | } |
| ... | ... | @@ -128,6 +132,18 @@ static void smc91c111_pop_rx_fifo(smc91c111_state *s) |
| 128 | 132 | smc91c111_update(s); |
| 129 | 133 | } |
| 130 | 134 | |
| 135 | +/* Remove an item from the TX completion FIFO. */ | |
| 136 | +static void smc91c111_pop_tx_fifo_done(smc91c111_state *s) | |
| 137 | +{ | |
| 138 | + int i; | |
| 139 | + | |
| 140 | + if (s->tx_fifo_done_len == 0) | |
| 141 | + return; | |
| 142 | + s->tx_fifo_done_len--; | |
| 143 | + for (i = 0; i < s->tx_fifo_done_len; i++) | |
| 144 | + s->tx_fifo_done[i] = s->tx_fifo_done[i + 1]; | |
| 145 | +} | |
| 146 | + | |
| 131 | 147 | /* Release the memory allocated to a packet. */ |
| 132 | 148 | static void smc91c111_release_packet(smc91c111_state *s, int packet) |
| 133 | 149 | { |
| ... | ... | @@ -184,12 +200,13 @@ static void smc91c111_do_tx(smc91c111_state *s) |
| 184 | 200 | add_crc = 0; |
| 185 | 201 | #endif |
| 186 | 202 | if (s->ctr & CTR_AUTO_RELEASE) |
| 203 | + /* Race? */ | |
| 187 | 204 | smc91c111_release_packet(s, packetnum); |
| 205 | + else if (s->tx_fifo_done_len < NUM_PACKETS) | |
| 206 | + s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum; | |
| 188 | 207 | qemu_send_packet(s->vc, p, len); |
| 189 | 208 | } |
| 190 | 209 | s->tx_fifo_len = 0; |
| 191 | - if ((s->ctr & CTR_AUTO_RELEASE) == 0) | |
| 192 | - s->int_level |= INT_TX; | |
| 193 | 210 | smc91c111_update(s); |
| 194 | 211 | } |
| 195 | 212 | |
| ... | ... | @@ -206,6 +223,7 @@ static void smc91c111_reset(smc91c111_state *s) |
| 206 | 223 | { |
| 207 | 224 | s->bank = 0; |
| 208 | 225 | s->tx_fifo_len = 0; |
| 226 | + s->tx_fifo_done_len = 0; | |
| 209 | 227 | s->rx_fifo_len = 0; |
| 210 | 228 | s->allocated = 0; |
| 211 | 229 | s->packet_num = 0; |
| ... | ... | @@ -306,6 +324,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, |
| 306 | 324 | case 2: /* Reset MMU. */ |
| 307 | 325 | s->allocated = 0; |
| 308 | 326 | s->tx_fifo_len = 0; |
| 327 | + s->tx_fifo_done_len = 0; | |
| 309 | 328 | s->rx_fifo_len = 0; |
| 310 | 329 | s->tx_alloc = 0; |
| 311 | 330 | break; |
| ... | ... | @@ -326,6 +345,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, |
| 326 | 345 | break; |
| 327 | 346 | case 7: /* Reset TX FIFO. */ |
| 328 | 347 | s->tx_fifo_len = 0; |
| 348 | + s->tx_fifo_done_len = 0; | |
| 329 | 349 | break; |
| 330 | 350 | } |
| 331 | 351 | return; |
| ... | ... | @@ -364,6 +384,8 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, |
| 364 | 384 | return; |
| 365 | 385 | case 12: /* Interrupt ACK. */ |
| 366 | 386 | s->int_level &= ~(value & 0xd6); |
| 387 | + if (value & INT_TX) | |
| 388 | + smc91c111_pop_tx_fifo_done(s); | |
| 367 | 389 | smc91c111_update(s); |
| 368 | 390 | return; |
| 369 | 391 | case 13: /* Interrupt mask. */ |
| ... | ... | @@ -473,10 +495,10 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) |
| 473 | 495 | case 3: /* Allocation Result. */ |
| 474 | 496 | return s->tx_alloc; |
| 475 | 497 | case 4: /* TX FIFO */ |
| 476 | - if (s->tx_fifo_len == 0) | |
| 498 | + if (s->tx_fifo_done_len == 0) | |
| 477 | 499 | return 0x80; |
| 478 | 500 | else |
| 479 | - return s->tx_fifo[0]; | |
| 501 | + return s->tx_fifo_done[0]; | |
| 480 | 502 | case 5: /* RX FIFO */ |
| 481 | 503 | if (s->rx_fifo_len == 0) |
| 482 | 504 | return 0x80; | ... | ... |