@@ -158,6 +158,7 @@ typedef struct dp8393xState {
/* Hardware */
uint8_t it_shift;
bool big_endian;
+ bool last_rba_is_full;
qemu_irq irq;
#ifdef DEBUG_SONIC
int irq_level;
@@ -347,12 +348,15 @@ static void dp8393x_do_read_rra(dp8393xState *s)
s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
}
- /* Check resource exhaustion */
+ /* Warn the host if CRBA now has the last available resource */
if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
{
s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
dp8393x_update_irq(s);
}
+
+ /* Allow packet reception */
+ s->last_rba_is_full = false;
}
static void dp8393x_do_software_reset(dp8393xState *s)
@@ -659,9 +663,6 @@ static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data,
dp8393x_do_read_rra(s);
}
dp8393x_update_irq(s);
- if (dp8393x_can_receive(s->nic->ncs)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
break;
/* The guest is required to store aligned pointers here */
case SONIC_RSA:
@@ -721,8 +722,6 @@ static int dp8393x_can_receive(NetClientState *nc)
if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
return 0;
- if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
- return 0;
return 1;
}
@@ -773,6 +772,10 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
+ if (s->last_rba_is_full) {
+ return pkt_size;
+ }
+
rx_len = pkt_size + sizeof(checksum);
if (s->regs[SONIC_DCR] & SONIC_DCR_DW) {
width = 2;
@@ -786,8 +789,8 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
DPRINTF("oversize packet, pkt_size is %d\n", pkt_size);
s->regs[SONIC_ISR] |= SONIC_ISR_RBAE;
dp8393x_update_irq(s);
- dp8393x_do_read_rra(s);
- return pkt_size;
+ s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
+ goto done;
}
packet_type = dp8393x_receive_filter(s, buf, pkt_size);
@@ -899,17 +902,23 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
}
+ dp8393x_update_irq(s);
+
s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) |
((s->regs[SONIC_RSC] + 1) & 0x00ff);
+done:
+
if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
- /* Read next RRA */
- dp8393x_do_read_rra(s);
+ if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP]) {
+ /* Stop packet reception */
+ s->last_rba_is_full = true;
+ } else {
+ /* Read next resource */
+ dp8393x_do_read_rra(s);
+ }
}
- /* Done */
- dp8393x_update_irq(s);
-
return pkt_size;
}