Pull request
Here are NIC fixes from Fam Zheng that prevent rx hangs (caused by NIC models where .can_receive() stops rx but qemu_flush_queued_packets() isn't called). -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJVtjd0AAoJEJykq7OBq3PI3wsIAIRVH3frjHdYSpPTpAV8Kkhd P29q7Zam4iOoTaJMrlSX5iFGAxBGQB7cW10HZlKBBkHI5SOCYzhhS4zJlyfz5jZn +DSMTr0NRLqSAKE6RJjnrkd1QLcfGfi27DKiF0VqwmWcXOvMbIveSPR1C/5XHemT EBZq8HibDzjgP8htKf4+0NbKxrb2b+MbJKnSbe1uKVGdinadKl2dmjby4M9bgUQ9 pwSnV+efbOkAvVFMVSbkanyg3UPftJjZ3yD3vFU17FbMj55nSIhWLBXlE0NKdYqQ Ml7ntQt56Zo9e+L2pw2ZEEhRbW+z1VSLxMPAcI5VphBcZ2cgcGHbARrYzfF898I= =DVR+ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/net-pull-request' into staging Pull request Here are NIC fixes from Fam Zheng that prevent rx hangs (caused by NIC models where .can_receive() stops rx but qemu_flush_queued_packets() isn't called). # gpg: Signature made Mon Jul 27 14:51:48 2015 BST using RSA key ID 81AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" * remotes/stefanha/tags/net-pull-request: axienet: Flush queued packets when rx is done dp8393x: Flush packets when link comes up stellaris_enet: Flush queued packets when read done mipsnet: Flush queued packets when receiving is enabled milkymist-minimac2: Flush queued packets when link comes up mcf_fec: Drop mcf_fec_can_receive etsec: Flush queue when rx buffer is consumed etsec: Move etsec_can_receive into etsec_receive usbnet: Drop usbnet_can_receive eepro100: Drop nic_can_receive pcnet: Drop pcnet_can_receive xgmac: Drop packets with eth_can_rx is false. hw/net: fix mcf_fec driver receiver hw/net: add simple phy support to mcf_fec driver hw/net: add ANLPAR bit definitions to generic mii hw/net: create common collection of MII definitions Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
122e7dab8a
@ -327,9 +327,14 @@ static void dp8393x_do_stop_timer(dp8393xState *s)
|
||||
dp8393x_update_wt_regs(s);
|
||||
}
|
||||
|
||||
static int dp8393x_can_receive(NetClientState *nc);
|
||||
|
||||
static void dp8393x_do_receiver_enable(dp8393xState *s)
|
||||
{
|
||||
s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
|
||||
if (dp8393x_can_receive(s->nic->ncs)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
}
|
||||
|
||||
static void dp8393x_do_receiver_disable(dp8393xState *s)
|
||||
@ -569,6 +574,9 @@ 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;
|
||||
/* Ignore least significant bit */
|
||||
case SONIC_RSA:
|
||||
|
@ -1617,16 +1617,6 @@ static const MemoryRegionOps eepro100_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static int nic_can_receive(NetClientState *nc)
|
||||
{
|
||||
EEPRO100State *s = qemu_get_nic_opaque(nc);
|
||||
TRACE(RXTX, logout("%p\n", s));
|
||||
return get_ru_state(s) == ru_ready;
|
||||
#if 0
|
||||
return !eepro100_buffer_full(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
||||
{
|
||||
/* TODO:
|
||||
@ -1844,7 +1834,6 @@ static void pci_nic_uninit(PCIDevice *pci_dev)
|
||||
static NetClientInfo net_eepro100_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = nic_can_receive,
|
||||
.receive = nic_receive,
|
||||
};
|
||||
|
||||
|
@ -338,25 +338,26 @@ static void etsec_reset(DeviceState *d)
|
||||
MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
|
||||
}
|
||||
|
||||
static int etsec_can_receive(NetClientState *nc)
|
||||
{
|
||||
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||
|
||||
return etsec->rx_buffer_len == 0;
|
||||
}
|
||||
|
||||
static ssize_t etsec_receive(NetClientState *nc,
|
||||
const uint8_t *buf,
|
||||
size_t size)
|
||||
{
|
||||
ssize_t ret;
|
||||
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||
|
||||
#if defined(HEX_DUMP)
|
||||
fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
|
||||
qemu_hexdump(buf, stderr, "", size);
|
||||
#endif
|
||||
etsec_rx_ring_write(etsec, buf, size);
|
||||
return size;
|
||||
/* Flush is unnecessary as are already in receiving path */
|
||||
etsec->need_flush = false;
|
||||
ret = etsec_rx_ring_write(etsec, buf, size);
|
||||
if (ret == 0) {
|
||||
/* The packet will be queued, let's flush it when buffer is avilable
|
||||
* again. */
|
||||
etsec->need_flush = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -370,7 +371,6 @@ static void etsec_set_link_status(NetClientState *nc)
|
||||
static NetClientInfo net_etsec_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = etsec_can_receive,
|
||||
.receive = etsec_receive,
|
||||
.link_status_changed = etsec_set_link_status,
|
||||
};
|
||||
|
@ -144,6 +144,8 @@ typedef struct eTSEC {
|
||||
QEMUBH *bh;
|
||||
struct ptimer_state *ptimer;
|
||||
|
||||
/* Whether we should flush the rx queue when buffer becomes available. */
|
||||
bool need_flush;
|
||||
} eTSEC;
|
||||
|
||||
#define TYPE_ETSEC_COMMON "eTSEC"
|
||||
@ -162,7 +164,7 @@ DeviceState *etsec_create(hwaddr base,
|
||||
|
||||
void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
|
||||
void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
|
||||
void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
|
||||
ssize_t etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
|
||||
|
||||
void etsec_write_miim(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
|
@ -481,40 +481,42 @@ static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
|
||||
etsec->rx_buffer_len, etsec->rx_padding);
|
||||
}
|
||||
|
||||
void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
|
||||
ssize_t etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
|
||||
{
|
||||
int ring_nbr = 0; /* Always use ring0 (no filer) */
|
||||
|
||||
if (etsec->rx_buffer_len != 0) {
|
||||
RING_DEBUG("%s: We can't receive now,"
|
||||
" a buffer is already in the pipe\n", __func__);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) {
|
||||
RING_DEBUG("%s: The ring is halted\n", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (etsec->regs[DMACTRL].value & DMACTRL_GRS) {
|
||||
RING_DEBUG("%s: Graceful receive stop\n", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) {
|
||||
RING_DEBUG("%s: MAC Receive not enabled\n", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) {
|
||||
/* CRC is not in the packet yet, so short frame is below 60 bytes */
|
||||
RING_DEBUG("%s: Drop short frame\n", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rx_init_frame(etsec, buf, size);
|
||||
|
||||
etsec_walk_rx_ring(etsec, ring_nbr);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
|
||||
@ -644,6 +646,9 @@ void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
|
||||
} else {
|
||||
etsec->rx_buffer_len = 0;
|
||||
etsec->rx_buffer = NULL;
|
||||
if (etsec->need_flush) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(etsec->nic));
|
||||
}
|
||||
}
|
||||
|
||||
RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data);
|
||||
|
@ -94,7 +94,6 @@ static const MemoryRegionOps lance_mem_ops = {
|
||||
static NetClientInfo net_lance_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = pcnet_can_receive,
|
||||
.receive = pcnet_receive,
|
||||
.link_status_changed = pcnet_set_link_status,
|
||||
};
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/m68k/mcf.h"
|
||||
#include "hw/net/mii.h"
|
||||
/* For crc32 */
|
||||
#include <zlib.h>
|
||||
#include "exec/address-spaces.h"
|
||||
@ -216,6 +217,51 @@ static void mcf_fec_reset(mcf_fec_state *s)
|
||||
s->rfsr = 0x500;
|
||||
}
|
||||
|
||||
#define MMFR_WRITE_OP (1 << 28)
|
||||
#define MMFR_READ_OP (2 << 28)
|
||||
#define MMFR_PHYADDR(v) (((v) >> 23) & 0x1f)
|
||||
#define MMFR_REGNUM(v) (((v) >> 18) & 0x1f)
|
||||
|
||||
static uint64_t mcf_fec_read_mdio(mcf_fec_state *s)
|
||||
{
|
||||
uint64_t v;
|
||||
|
||||
if (s->mmfr & MMFR_WRITE_OP)
|
||||
return s->mmfr;
|
||||
if (MMFR_PHYADDR(s->mmfr) != 1)
|
||||
return s->mmfr |= 0xffff;
|
||||
|
||||
switch (MMFR_REGNUM(s->mmfr)) {
|
||||
case MII_BMCR:
|
||||
v = MII_BMCR_SPEED | MII_BMCR_AUTOEN | MII_BMCR_FD;
|
||||
break;
|
||||
case MII_BMSR:
|
||||
v = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
|
||||
MII_BMSR_10T_HD | MII_BMSR_MFPS | MII_BMSR_AN_COMP |
|
||||
MII_BMSR_AUTONEG | MII_BMSR_LINK_ST;
|
||||
break;
|
||||
case MII_PHYID1:
|
||||
v = DP83848_PHYID1;
|
||||
break;
|
||||
case MII_PHYID2:
|
||||
v = DP83848_PHYID2;
|
||||
break;
|
||||
case MII_ANAR:
|
||||
v = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD |
|
||||
MII_ANAR_10 | MII_ANAR_CSMACD;
|
||||
break;
|
||||
case MII_ANLPAR:
|
||||
v = MII_ANLPAR_ACK | MII_ANLPAR_TXFD | MII_ANLPAR_TX |
|
||||
MII_ANLPAR_10FD | MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
|
||||
break;
|
||||
default:
|
||||
v = 0xffff;
|
||||
break;
|
||||
}
|
||||
s->mmfr = (s->mmfr & ~0xffff) | v;
|
||||
return s->mmfr;
|
||||
}
|
||||
|
||||
static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
@ -226,7 +272,7 @@ static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
|
||||
case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
|
||||
case 0x014: return 0; /* TDAR */
|
||||
case 0x024: return s->ecr;
|
||||
case 0x040: return s->mmfr;
|
||||
case 0x040: return mcf_fec_read_mdio(s);
|
||||
case 0x044: return s->mscr;
|
||||
case 0x064: return 0; /* MIBC */
|
||||
case 0x084: return s->rcr;
|
||||
@ -287,8 +333,8 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
break;
|
||||
case 0x040:
|
||||
/* TODO: Implement MII. */
|
||||
s->mmfr = value;
|
||||
s->eir |= FEC_INT_MII;
|
||||
break;
|
||||
case 0x044:
|
||||
s->mscr = value & 0xfe;
|
||||
@ -351,12 +397,6 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
|
||||
mcf_fec_update(s);
|
||||
}
|
||||
|
||||
static int mcf_fec_can_receive(NetClientState *nc)
|
||||
{
|
||||
mcf_fec_state *s = qemu_get_nic_opaque(nc);
|
||||
return s->rx_enabled;
|
||||
}
|
||||
|
||||
static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
{
|
||||
mcf_fec_state *s = qemu_get_nic_opaque(nc);
|
||||
@ -367,10 +407,11 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
uint32_t buf_addr;
|
||||
uint8_t *crc_ptr;
|
||||
unsigned int buf_len;
|
||||
size_t retsize;
|
||||
|
||||
DPRINTF("do_rx len %d\n", size);
|
||||
if (!s->rx_enabled) {
|
||||
fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
|
||||
return -1;
|
||||
}
|
||||
/* 4 bytes for the CRC. */
|
||||
size += 4;
|
||||
@ -386,6 +427,7 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
flags |= FEC_BD_LG;
|
||||
}
|
||||
addr = s->rx_descriptor;
|
||||
retsize = size;
|
||||
while (size > 0) {
|
||||
mcf_fec_read_bd(&bd, addr);
|
||||
if ((bd.flags & FEC_BD_E) == 0) {
|
||||
@ -430,7 +472,7 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
s->rx_descriptor = addr;
|
||||
mcf_fec_enable_rx(s);
|
||||
mcf_fec_update(s);
|
||||
return size;
|
||||
return retsize;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mcf_fec_ops = {
|
||||
@ -442,7 +484,6 @@ static const MemoryRegionOps mcf_fec_ops = {
|
||||
static NetClientInfo net_mcf_fec_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = mcf_fec_can_receive,
|
||||
.receive = mcf_fec_receive,
|
||||
};
|
||||
|
||||
|
@ -303,8 +303,7 @@ static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
r_state = R_STATE1;
|
||||
rx_buf = s->rx1_buf;
|
||||
} else {
|
||||
trace_milkymist_minimac2_drop_rx_frame(buf);
|
||||
return size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* assemble frame */
|
||||
@ -354,6 +353,18 @@ minimac2_read(void *opaque, hwaddr addr, unsigned size)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int minimac2_can_rx(MilkymistMinimac2State *s)
|
||||
{
|
||||
if (s->regs[R_STATE0] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
if (s->regs[R_STATE1] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
minimac2_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
@ -387,6 +398,9 @@ minimac2_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
case R_STATE1:
|
||||
s->regs[addr] = value;
|
||||
update_rx_interrupt(s);
|
||||
if (minimac2_can_rx(s)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
break;
|
||||
case R_SETUP:
|
||||
case R_COUNT0:
|
||||
@ -411,20 +425,6 @@ static const MemoryRegionOps minimac2_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int minimac2_can_rx(NetClientState *nc)
|
||||
{
|
||||
MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
if (s->regs[R_STATE0] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
if (s->regs[R_STATE1] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void milkymist_minimac2_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d);
|
||||
@ -445,7 +445,6 @@ static void milkymist_minimac2_reset(DeviceState *d)
|
||||
static NetClientInfo net_milkymist_minimac2_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = minimac2_can_rx,
|
||||
.receive = minimac2_rx,
|
||||
};
|
||||
|
||||
|
@ -80,7 +80,7 @@ static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
|
||||
trace_mipsnet_receive(size);
|
||||
if (!mipsnet_can_receive(nc))
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
s->busy = 1;
|
||||
|
||||
@ -134,6 +134,9 @@ static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr,
|
||||
if (s->rx_count) {
|
||||
s->rx_count--;
|
||||
ret = s->rx_buffer[s->rx_read++];
|
||||
if (mipsnet_can_receive(s->nic->ncs)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* Reads as zero. */
|
||||
@ -170,6 +173,9 @@ static void mipsnet_ioport_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
s->busy = !!s->intctl;
|
||||
mipsnet_update_irq(s);
|
||||
if (mipsnet_can_receive(s->nic->ncs)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
break;
|
||||
case MIPSNET_TX_DATA_BUFFER:
|
||||
s->tx_buffer[s->tx_written++] = val;
|
||||
@ -214,7 +220,6 @@ static const VMStateDescription vmstate_mipsnet = {
|
||||
static NetClientInfo net_mipsnet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = mipsnet_can_receive,
|
||||
.receive = mipsnet_receive,
|
||||
};
|
||||
|
||||
|
@ -273,7 +273,6 @@ static void pci_pcnet_uninit(PCIDevice *dev)
|
||||
static NetClientInfo net_pci_pcnet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = pcnet_can_receive,
|
||||
.receive = pcnet_receive,
|
||||
.link_status_changed = pcnet_set_link_status,
|
||||
};
|
||||
|
@ -995,15 +995,6 @@ static int pcnet_tdte_poll(PCNetState *s)
|
||||
return !!(CSR_CXST(s) & 0x8000);
|
||||
}
|
||||
|
||||
int pcnet_can_receive(NetClientState *nc)
|
||||
{
|
||||
PCNetState *s = qemu_get_nic_opaque(nc);
|
||||
if (CSR_STOP(s) || CSR_SPND(s))
|
||||
return 0;
|
||||
|
||||
return sizeof(s->buffer)-16;
|
||||
}
|
||||
|
||||
#define MIN_BUF_SIZE 60
|
||||
|
||||
ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
|
||||
|
@ -60,7 +60,6 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
|
||||
void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
|
||||
uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
|
||||
int pcnet_can_receive(NetClientState *nc);
|
||||
ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
|
||||
void pcnet_set_link_status(NetClientState *nc);
|
||||
void pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info);
|
||||
|
@ -228,8 +228,7 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si
|
||||
if ((s->rctl & SE_RCTL_RXEN) == 0)
|
||||
return -1;
|
||||
if (s->np >= 31) {
|
||||
DPRINTF("Packet dropped\n");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DPRINTF("Received packet len=%zu\n", size);
|
||||
@ -260,13 +259,8 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si
|
||||
return size;
|
||||
}
|
||||
|
||||
static int stellaris_enet_can_receive(NetClientState *nc)
|
||||
static int stellaris_enet_can_receive(stellaris_enet_state *s)
|
||||
{
|
||||
stellaris_enet_state *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
if ((s->rctl & SE_RCTL_RXEN) == 0)
|
||||
return 1;
|
||||
|
||||
return (s->np < 31);
|
||||
}
|
||||
|
||||
@ -307,6 +301,9 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
|
||||
s->next_packet = 0;
|
||||
s->np--;
|
||||
DPRINTF("RX done np=%d\n", s->np);
|
||||
if (!s->np && stellaris_enet_can_receive(s)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@ -454,7 +451,6 @@ static void stellaris_enet_reset(stellaris_enet_state *s)
|
||||
static NetClientInfo net_stellaris_enet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = stellaris_enet_can_receive,
|
||||
.receive = stellaris_enet_receive,
|
||||
};
|
||||
|
||||
|
@ -312,10 +312,8 @@ static const MemoryRegionOps enet_mem_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static int eth_can_rx(NetClientState *nc)
|
||||
static int eth_can_rx(XgmacState *s)
|
||||
{
|
||||
XgmacState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
/* RX enabled? */
|
||||
return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
|
||||
}
|
||||
@ -329,6 +327,9 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
struct desc bd;
|
||||
ssize_t ret;
|
||||
|
||||
if (!eth_can_rx(s)) {
|
||||
return -1;
|
||||
}
|
||||
unicast = ~buf[0] & 0x1;
|
||||
broadcast = memcmp(buf, sa_bcast, 6) == 0;
|
||||
multicast = !unicast && !broadcast;
|
||||
@ -371,7 +372,6 @@ out:
|
||||
static NetClientInfo net_xgmac_enet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = eth_can_rx,
|
||||
.receive = eth_rx,
|
||||
};
|
||||
|
||||
|
@ -401,6 +401,9 @@ struct XilinxAXIEnet {
|
||||
|
||||
uint8_t rxapp[CONTROL_PAYLOAD_SIZE];
|
||||
uint32_t rxappsize;
|
||||
|
||||
/* Whether axienet_eth_rx_notify should flush incoming queue. */
|
||||
bool need_flush;
|
||||
};
|
||||
|
||||
static void axienet_rx_reset(XilinxAXIEnet *s)
|
||||
@ -658,10 +661,8 @@ static const MemoryRegionOps enet_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static int eth_can_rx(NetClientState *nc)
|
||||
static int eth_can_rx(XilinxAXIEnet *s)
|
||||
{
|
||||
XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
/* RX enabled? */
|
||||
return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
|
||||
}
|
||||
@ -701,6 +702,10 @@ static void axienet_eth_rx_notify(void *opaque)
|
||||
s->rxpos += ret;
|
||||
if (!s->rxsize) {
|
||||
s->regs[R_IS] |= IS_RX_COMPLETE;
|
||||
if (s->need_flush) {
|
||||
s->need_flush = false;
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
}
|
||||
}
|
||||
enet_update_irq(s);
|
||||
@ -721,6 +726,11 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
|
||||
DENET(qemu_log("%s: %zd bytes\n", __func__, size));
|
||||
|
||||
if (!eth_can_rx(s)) {
|
||||
s->need_flush = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unicast = ~buf[0] & 0x1;
|
||||
broadcast = memcmp(buf, sa_bcast, 6) == 0;
|
||||
multicast = !unicast && !broadcast;
|
||||
@ -925,7 +935,6 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
|
||||
static NetClientInfo net_xilinx_enet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = eth_can_rx,
|
||||
.receive = eth_rx,
|
||||
};
|
||||
|
||||
|
@ -1268,6 +1268,10 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
|
||||
uint8_t *in_buf = s->in_buf;
|
||||
size_t total_size = size;
|
||||
|
||||
if (!s->dev.config) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_rndis(s)) {
|
||||
if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
||||
return -1;
|
||||
@ -1309,21 +1313,6 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
|
||||
return size;
|
||||
}
|
||||
|
||||
static int usbnet_can_receive(NetClientState *nc)
|
||||
{
|
||||
USBNetState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
if (!s->dev.config) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_rndis(s) && s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return !s->in_len;
|
||||
}
|
||||
|
||||
static void usbnet_cleanup(NetClientState *nc)
|
||||
{
|
||||
USBNetState *s = qemu_get_nic_opaque(nc);
|
||||
@ -1343,7 +1332,6 @@ static void usb_net_handle_destroy(USBDevice *dev)
|
||||
static NetClientInfo net_usbnet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = usbnet_can_receive,
|
||||
.receive = usbnet_receive,
|
||||
.cleanup = usbnet_cleanup,
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "net/net.h"
|
||||
#include "qemu/fifo8.h"
|
||||
#include "hw/net/mii.h"
|
||||
|
||||
#define TYPE_AW_EMAC "allwinner-emac"
|
||||
#define AW_EMAC(obj) OBJECT_CHECK(AwEmacState, (obj), TYPE_AW_EMAC)
|
||||
@ -118,45 +119,6 @@
|
||||
#define EMAC_RX_IO_DATA_STATUS_OK (1 << 7)
|
||||
#define EMAC_UNDOCUMENTED_MAGIC 0x0143414d /* header for RX frames */
|
||||
|
||||
/* PHY registers */
|
||||
#define MII_BMCR 0
|
||||
#define MII_BMSR 1
|
||||
#define MII_PHYID1 2
|
||||
#define MII_PHYID2 3
|
||||
#define MII_ANAR 4
|
||||
#define MII_ANLPAR 5
|
||||
#define MII_ANER 6
|
||||
#define MII_NSR 16
|
||||
#define MII_LBREMR 17
|
||||
#define MII_REC 18
|
||||
#define MII_SNRDR 19
|
||||
#define MII_TEST 25
|
||||
|
||||
/* PHY registers fields */
|
||||
#define MII_BMCR_RESET (1 << 15)
|
||||
#define MII_BMCR_LOOPBACK (1 << 14)
|
||||
#define MII_BMCR_SPEED (1 << 13)
|
||||
#define MII_BMCR_AUTOEN (1 << 12)
|
||||
#define MII_BMCR_FD (1 << 8)
|
||||
|
||||
#define MII_BMSR_100TX_FD (1 << 14)
|
||||
#define MII_BMSR_100TX_HD (1 << 13)
|
||||
#define MII_BMSR_10T_FD (1 << 12)
|
||||
#define MII_BMSR_10T_HD (1 << 11)
|
||||
#define MII_BMSR_MFPS (1 << 6)
|
||||
#define MII_BMSR_AN_COMP (1 << 5)
|
||||
#define MII_BMSR_AUTONEG (1 << 3)
|
||||
#define MII_BMSR_LINK_ST (1 << 2)
|
||||
|
||||
#define MII_ANAR_TXFD (1 << 8)
|
||||
#define MII_ANAR_TX (1 << 7)
|
||||
#define MII_ANAR_10FD (1 << 6)
|
||||
#define MII_ANAR_10 (1 << 5)
|
||||
#define MII_ANAR_CSMACD (1 << 0)
|
||||
|
||||
#define RTL8201CP_PHYID1 0x0000
|
||||
#define RTL8201CP_PHYID2 0x8201
|
||||
|
||||
/* INT CTL and INT STA registers fields */
|
||||
#define EMAC_INT_TX_CHAN(x) (1 << (x))
|
||||
#define EMAC_INT_RX (1 << 8)
|
||||
|
76
include/hw/net/mii.h
Normal file
76
include/hw/net/mii.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Common network MII address and register definitions.
|
||||
*
|
||||
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
|
||||
*
|
||||
* Allwinner EMAC register definitions from Linux kernel are:
|
||||
* Copyright 2012 Stefan Roese <sr@denx.de>
|
||||
* Copyright 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
* Copyright 1997 Sten Wang
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#ifndef MII_H
|
||||
#define MII_H
|
||||
|
||||
/* PHY registers */
|
||||
#define MII_BMCR 0
|
||||
#define MII_BMSR 1
|
||||
#define MII_PHYID1 2
|
||||
#define MII_PHYID2 3
|
||||
#define MII_ANAR 4
|
||||
#define MII_ANLPAR 5
|
||||
#define MII_ANER 6
|
||||
#define MII_NSR 16
|
||||
#define MII_LBREMR 17
|
||||
#define MII_REC 18
|
||||
#define MII_SNRDR 19
|
||||
#define MII_TEST 25
|
||||
|
||||
/* PHY registers fields */
|
||||
#define MII_BMCR_RESET (1 << 15)
|
||||
#define MII_BMCR_LOOPBACK (1 << 14)
|
||||
#define MII_BMCR_SPEED (1 << 13)
|
||||
#define MII_BMCR_AUTOEN (1 << 12)
|
||||
#define MII_BMCR_FD (1 << 8)
|
||||
|
||||
#define MII_BMSR_100TX_FD (1 << 14)
|
||||
#define MII_BMSR_100TX_HD (1 << 13)
|
||||
#define MII_BMSR_10T_FD (1 << 12)
|
||||
#define MII_BMSR_10T_HD (1 << 11)
|
||||
#define MII_BMSR_MFPS (1 << 6)
|
||||
#define MII_BMSR_AN_COMP (1 << 5)
|
||||
#define MII_BMSR_AUTONEG (1 << 3)
|
||||
#define MII_BMSR_LINK_ST (1 << 2)
|
||||
|
||||
#define MII_ANAR_TXFD (1 << 8)
|
||||
#define MII_ANAR_TX (1 << 7)
|
||||
#define MII_ANAR_10FD (1 << 6)
|
||||
#define MII_ANAR_10 (1 << 5)
|
||||
#define MII_ANAR_CSMACD (1 << 0)
|
||||
|
||||
#define MII_ANLPAR_ACK (1 << 14)
|
||||
#define MII_ANLPAR_TXFD (1 << 8)
|
||||
#define MII_ANLPAR_TX (1 << 7)
|
||||
#define MII_ANLPAR_10FD (1 << 6)
|
||||
#define MII_ANLPAR_10 (1 << 5)
|
||||
#define MII_ANLPAR_CSMACD (1 << 0)
|
||||
|
||||
/* List of vendor identifiers */
|
||||
/* RealTek 8201 */
|
||||
#define RTL8201CP_PHYID1 0x0000
|
||||
#define RTL8201CP_PHYID2 0x8201
|
||||
|
||||
/* National Semiconductor DP83848 */
|
||||
#define DP83848_PHYID1 0x2000
|
||||
#define DP83848_PHYID2 0x5c90
|
||||
|
||||
#endif /* MII_H */
|
@ -828,7 +828,6 @@ milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "p
|
||||
milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x"
|
||||
milkymist_minimac2_tx_frame(uint32_t length) "length %u"
|
||||
milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u"
|
||||
milkymist_minimac2_drop_rx_frame(const void *buf) "buf %p"
|
||||
milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d"
|
||||
milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX"
|
||||
milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX"
|
||||
|
Loading…
Reference in New Issue
Block a user