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; | ... | ... |