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,8 +35,10 @@ typedef struct { | ||
| 35 | int tx_fifo[NUM_PACKETS]; | 35 | int tx_fifo[NUM_PACKETS]; |
| 36 | int rx_fifo_len; | 36 | int rx_fifo_len; |
| 37 | int rx_fifo[NUM_PACKETS]; | 37 | int rx_fifo[NUM_PACKETS]; |
| 38 | + int tx_fifo_done_len; | ||
| 39 | + int tx_fifo_done[NUM_PACKETS]; | ||
| 38 | /* Packet buffer memory. */ | 40 | /* Packet buffer memory. */ |
| 39 | - uint8_t data[2048][NUM_PACKETS]; | 41 | + uint8_t data[NUM_PACKETS][2048]; |
| 40 | uint8_t int_level; | 42 | uint8_t int_level; |
| 41 | uint8_t int_mask; | 43 | uint8_t int_mask; |
| 42 | uint8_t macaddr[6]; | 44 | uint8_t macaddr[6]; |
| @@ -81,6 +83,8 @@ static void smc91c111_update(smc91c111_state *s) | @@ -81,6 +83,8 @@ static void smc91c111_update(smc91c111_state *s) | ||
| 81 | 83 | ||
| 82 | if (s->tx_fifo_len == 0) | 84 | if (s->tx_fifo_len == 0) |
| 83 | s->int_level |= INT_TX_EMPTY; | 85 | s->int_level |= INT_TX_EMPTY; |
| 86 | + if (s->tx_fifo_done_len != 0) | ||
| 87 | + s->int_level |= INT_TX; | ||
| 84 | level = (s->int_level & s->int_mask) != 0; | 88 | level = (s->int_level & s->int_mask) != 0; |
| 85 | pic_set_irq_new(s->pic, s->irq, level); | 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,6 +132,18 @@ static void smc91c111_pop_rx_fifo(smc91c111_state *s) | ||
| 128 | smc91c111_update(s); | 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 | /* Release the memory allocated to a packet. */ | 147 | /* Release the memory allocated to a packet. */ |
| 132 | static void smc91c111_release_packet(smc91c111_state *s, int packet) | 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,12 +200,13 @@ static void smc91c111_do_tx(smc91c111_state *s) | ||
| 184 | add_crc = 0; | 200 | add_crc = 0; |
| 185 | #endif | 201 | #endif |
| 186 | if (s->ctr & CTR_AUTO_RELEASE) | 202 | if (s->ctr & CTR_AUTO_RELEASE) |
| 203 | + /* Race? */ | ||
| 187 | smc91c111_release_packet(s, packetnum); | 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 | qemu_send_packet(s->vc, p, len); | 207 | qemu_send_packet(s->vc, p, len); |
| 189 | } | 208 | } |
| 190 | s->tx_fifo_len = 0; | 209 | s->tx_fifo_len = 0; |
| 191 | - if ((s->ctr & CTR_AUTO_RELEASE) == 0) | ||
| 192 | - s->int_level |= INT_TX; | ||
| 193 | smc91c111_update(s); | 210 | smc91c111_update(s); |
| 194 | } | 211 | } |
| 195 | 212 | ||
| @@ -206,6 +223,7 @@ static void smc91c111_reset(smc91c111_state *s) | @@ -206,6 +223,7 @@ static void smc91c111_reset(smc91c111_state *s) | ||
| 206 | { | 223 | { |
| 207 | s->bank = 0; | 224 | s->bank = 0; |
| 208 | s->tx_fifo_len = 0; | 225 | s->tx_fifo_len = 0; |
| 226 | + s->tx_fifo_done_len = 0; | ||
| 209 | s->rx_fifo_len = 0; | 227 | s->rx_fifo_len = 0; |
| 210 | s->allocated = 0; | 228 | s->allocated = 0; |
| 211 | s->packet_num = 0; | 229 | s->packet_num = 0; |
| @@ -306,6 +324,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, | @@ -306,6 +324,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, | ||
| 306 | case 2: /* Reset MMU. */ | 324 | case 2: /* Reset MMU. */ |
| 307 | s->allocated = 0; | 325 | s->allocated = 0; |
| 308 | s->tx_fifo_len = 0; | 326 | s->tx_fifo_len = 0; |
| 327 | + s->tx_fifo_done_len = 0; | ||
| 309 | s->rx_fifo_len = 0; | 328 | s->rx_fifo_len = 0; |
| 310 | s->tx_alloc = 0; | 329 | s->tx_alloc = 0; |
| 311 | break; | 330 | break; |
| @@ -326,6 +345,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, | @@ -326,6 +345,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, | ||
| 326 | break; | 345 | break; |
| 327 | case 7: /* Reset TX FIFO. */ | 346 | case 7: /* Reset TX FIFO. */ |
| 328 | s->tx_fifo_len = 0; | 347 | s->tx_fifo_len = 0; |
| 348 | + s->tx_fifo_done_len = 0; | ||
| 329 | break; | 349 | break; |
| 330 | } | 350 | } |
| 331 | return; | 351 | return; |
| @@ -364,6 +384,8 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, | @@ -364,6 +384,8 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, | ||
| 364 | return; | 384 | return; |
| 365 | case 12: /* Interrupt ACK. */ | 385 | case 12: /* Interrupt ACK. */ |
| 366 | s->int_level &= ~(value & 0xd6); | 386 | s->int_level &= ~(value & 0xd6); |
| 387 | + if (value & INT_TX) | ||
| 388 | + smc91c111_pop_tx_fifo_done(s); | ||
| 367 | smc91c111_update(s); | 389 | smc91c111_update(s); |
| 368 | return; | 390 | return; |
| 369 | case 13: /* Interrupt mask. */ | 391 | case 13: /* Interrupt mask. */ |
| @@ -473,10 +495,10 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) | @@ -473,10 +495,10 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) | ||
| 473 | case 3: /* Allocation Result. */ | 495 | case 3: /* Allocation Result. */ |
| 474 | return s->tx_alloc; | 496 | return s->tx_alloc; |
| 475 | case 4: /* TX FIFO */ | 497 | case 4: /* TX FIFO */ |
| 476 | - if (s->tx_fifo_len == 0) | 498 | + if (s->tx_fifo_done_len == 0) |
| 477 | return 0x80; | 499 | return 0x80; |
| 478 | else | 500 | else |
| 479 | - return s->tx_fifo[0]; | 501 | + return s->tx_fifo_done[0]; |
| 480 | case 5: /* RX FIFO */ | 502 | case 5: /* RX FIFO */ |
| 481 | if (s->rx_fifo_len == 0) | 503 | if (s->rx_fifo_len == 0) |
| 482 | return 0x80; | 504 | return 0x80; |