|
@@ -169,6 +169,7 @@ enum {
|
|
|
};
|
|
|
|
|
|
enum {
|
|
|
+ INT_SOURCE_BUSY = 0x10,
|
|
|
INT_SOURCE_RXB = 0x4,
|
|
|
INT_SOURCE_TXB = 0x1,
|
|
|
};
|
|
@@ -351,8 +352,7 @@ static int open_eth_can_receive(NetClientState *nc)
|
|
|
OpenEthState *s = qemu_get_nic_opaque(nc);
|
|
|
|
|
|
return GET_REGBIT(s, MODER, RXEN) &&
|
|
|
- (s->regs[TX_BD_NUM] < 0x80) &&
|
|
|
- (rx_desc(s)->len_flags & RXD_E);
|
|
|
+ (s->regs[TX_BD_NUM] < 0x80);
|
|
|
}
|
|
|
|
|
|
static ssize_t open_eth_receive(NetClientState *nc,
|
|
@@ -402,6 +402,12 @@ static ssize_t open_eth_receive(NetClientState *nc,
|
|
|
desc *desc = rx_desc(s);
|
|
|
size_t copy_size = GET_REGBIT(s, MODER, HUGEN) ? 65536 : maxfl;
|
|
|
|
|
|
+ if (!(desc->len_flags & RXD_E)) {
|
|
|
+ open_eth_int_source_write(s,
|
|
|
+ s->regs[INT_SOURCE] | INT_SOURCE_BUSY);
|
|
|
+ return size;
|
|
|
+ }
|
|
|
+
|
|
|
desc->len_flags &= ~(RXD_CF | RXD_M | RXD_OR |
|
|
|
RXD_IS | RXD_DN | RXD_TL | RXD_SF | RXD_CRC | RXD_LC);
|
|
|
|
|
@@ -551,6 +557,15 @@ static uint64_t open_eth_reg_read(void *opaque,
|
|
|
return v;
|
|
|
}
|
|
|
|
|
|
+static void open_eth_notify_can_receive(OpenEthState *s)
|
|
|
+{
|
|
|
+ NetClientState *nc = qemu_get_queue(s->nic);
|
|
|
+
|
|
|
+ if (open_eth_can_receive(nc)) {
|
|
|
+ qemu_flush_queued_packets(nc);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void open_eth_ro(OpenEthState *s, uint32_t val)
|
|
|
{
|
|
|
}
|
|
@@ -567,6 +582,7 @@ static void open_eth_moder_host_write(OpenEthState *s, uint32_t val)
|
|
|
|
|
|
if (set & MODER_RXEN) {
|
|
|
s->rx_desc = s->regs[TX_BD_NUM];
|
|
|
+ open_eth_notify_can_receive(s);
|
|
|
}
|
|
|
if (set & MODER_TXEN) {
|
|
|
s->tx_desc = 0;
|
|
@@ -592,6 +608,18 @@ static void open_eth_int_mask_host_write(OpenEthState *s, uint32_t val)
|
|
|
s->regs[INT_SOURCE] & s->regs[INT_MASK]);
|
|
|
}
|
|
|
|
|
|
+static void open_eth_tx_bd_num_host_write(OpenEthState *s, uint32_t val)
|
|
|
+{
|
|
|
+ if (val < 0x80) {
|
|
|
+ bool enable = s->regs[TX_BD_NUM] == 0x80;
|
|
|
+
|
|
|
+ s->regs[TX_BD_NUM] = val;
|
|
|
+ if (enable) {
|
|
|
+ open_eth_notify_can_receive(s);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void open_eth_mii_command_host_write(OpenEthState *s, uint32_t val)
|
|
|
{
|
|
|
unsigned fiad = GET_REGFIELD(s, MIIADDRESS, FIAD);
|
|
@@ -630,6 +658,7 @@ static void open_eth_reg_write(void *opaque,
|
|
|
[MODER] = open_eth_moder_host_write,
|
|
|
[INT_SOURCE] = open_eth_int_source_host_write,
|
|
|
[INT_MASK] = open_eth_int_mask_host_write,
|
|
|
+ [TX_BD_NUM] = open_eth_tx_bd_num_host_write,
|
|
|
[MIICOMMAND] = open_eth_mii_command_host_write,
|
|
|
[MIITX_DATA] = open_eth_mii_tx_host_write,
|
|
|
[MIISTATUS] = open_eth_ro,
|