diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-07-27 14:53:42 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-07-27 14:53:42 +0100 |
commit | 122e7dab8ac549c8c5a9e1e13aa2464190e888de (patch) | |
tree | 110679c12752916fc4ae9b011b9d7fa98a2127ae /hw/net/mcf_fec.c | |
parent | e40db4c6d391419c0039fe274c74df32a6ca1a28 (diff) | |
parent | f9f7492ea4a9dda538fedeec31399fb940533a16 (diff) | |
download | hqemu-122e7dab8ac549c8c5a9e1e13aa2464190e888de.zip hqemu-122e7dab8ac549c8c5a9e1e13aa2464190e888de.tar.gz |
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>
Diffstat (limited to 'hw/net/mcf_fec.c')
-rw-r--r-- | hw/net/mcf_fec.c | 63 |
1 files changed, 52 insertions, 11 deletions
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 0255612..4e6939f 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -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, }; |