From 3e230569bf16aa36562967cd76b742c6824481b1 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Fri, 26 Jun 2015 15:27:13 +1000 Subject: hw/net: create common collection of MII definitions Create a common set of definitions of address and register values for ethernet MII phys. A few of the current ethernet drivers have at least a partial set of these definitions. Others just use hard coded raw constant numbers. This initial set is copied directly from the allwinner_emac code. Signed-off-by: Greg Ungerer Reviewed-by: Stefan Hajnoczi Message-id: 1435296436-12152-2-git-send-email-gerg@uclinux.org Signed-off-by: Stefan Hajnoczi --- include/hw/net/allwinner_emac.h | 40 +------------------------- include/hw/net/mii.h | 64 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 include/hw/net/mii.h diff --git a/include/hw/net/allwinner_emac.h b/include/hw/net/allwinner_emac.h index 5ae7717..9f21aa7 100644 --- a/include/hw/net/allwinner_emac.h +++ b/include/hw/net/allwinner_emac.h @@ -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) diff --git a/include/hw/net/mii.h b/include/hw/net/mii.h new file mode 100644 index 0000000..4d93114 --- /dev/null +++ b/include/hw/net/mii.h @@ -0,0 +1,64 @@ +/* + * Common network MII address and register definitions. + * + * Copyright (C) 2014 Beniamino Galvani + * + * Allwinner EMAC register definitions from Linux kernel are: + * Copyright 2012 Stefan Roese + * Copyright 2013 Maxime Ripard + * 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) + +/* List of vendor identifiers */ +#define RTL8201CP_PHYID1 0x0000 +#define RTL8201CP_PHYID2 0x8201 + +#endif /* MII_H */ -- cgit v1.1 From 3634869b27b6b2ff538bcc5bf8dfd1235ede7034 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Fri, 26 Jun 2015 15:27:14 +1000 Subject: hw/net: add ANLPAR bit definitions to generic mii Add a base set of bit definitions for the standard MII phy "Auto-Negotiation Link Partner Ability Register" (ANLPAR). The original definitions moved into mii.h from the allwinner_emac driver did not define these. Signed-off-by: Greg Ungerer Reviewed-by: Stefan Hajnoczi Message-id: 1435296436-12152-3-git-send-email-gerg@uclinux.org Signed-off-by: Stefan Hajnoczi --- include/hw/net/mii.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/hw/net/mii.h b/include/hw/net/mii.h index 4d93114..cd2a4e2 100644 --- a/include/hw/net/mii.h +++ b/include/hw/net/mii.h @@ -57,6 +57,13 @@ #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 */ #define RTL8201CP_PHYID1 0x0000 #define RTL8201CP_PHYID2 0x8201 -- cgit v1.1 From 299f7bec5a109db7563e1286cedf1f4d84e69e6d Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Fri, 26 Jun 2015 15:27:15 +1000 Subject: hw/net: add simple phy support to mcf_fec driver The Linux fec driver needs at least basic phy support to probe and work. The current qemu mcf_fec emulation has no support for the reading or writing of the MDIO lines to access an attached phy. This code adds a very simple set of register results for a fixed phy setup - very similar to that used on an m5208evb board. This is enough to probe and identify an emulated attached phy. Signed-off-by: Greg Ungerer Reviewed-by: Stefan Hajnoczi Message-id: 1435296436-12152-4-git-send-email-gerg@uclinux.org Signed-off-by: Stefan Hajnoczi --- hw/net/mcf_fec.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- include/hw/net/mii.h | 5 +++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 0255612..ea59017 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 #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; diff --git a/include/hw/net/mii.h b/include/hw/net/mii.h index cd2a4e2..9fdd7bb 100644 --- a/include/hw/net/mii.h +++ b/include/hw/net/mii.h @@ -65,7 +65,12 @@ #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 */ -- cgit v1.1 From 491a1f494ed4c0d1a8593dd04b645f8e63c4cfae Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Fri, 26 Jun 2015 15:27:16 +1000 Subject: hw/net: fix mcf_fec driver receiver The network mcf_fec driver emulated receive side method is returning a result of 0 causing the network layer to disable receive for this emulated device. This results in the guest only ever receiving one packet. Fix the recieve side processing to return the number of bytes that we passed back through to the guest. Signed-off-by: Greg Ungerer Reviewed-by: Stefan Hajnoczi Message-id: 1435296436-12152-5-git-send-email-gerg@uclinux.org Signed-off-by: Stefan Hajnoczi --- hw/net/mcf_fec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index ea59017..e63af1b 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -413,6 +413,7 @@ 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) { @@ -432,6 +433,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) { @@ -476,7 +478,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 = { -- cgit v1.1 From 8c8c460c5f38f878675631a66286a6e87bb4d111 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:02 +0800 Subject: xgmac: Drop packets with eth_can_rx is false. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-2-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/xgmac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index b068f3a..15fb681 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -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, }; -- cgit v1.1 From b0ba0b9b6b402d738f11f27eea6c94d97bf84cbf Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:03 +0800 Subject: pcnet: Drop pcnet_can_receive pcnet_receive already checks the conditions and drop packets if false. Due to the new semantics since 6e99c63 ("net/socket: Drop net_socket_can_send"), having .can_receive returning 0 requires us to explicitly flush the queued packets when the conditions are becoming true, but queuing the packets when guest driver is not ready doesn't make much sense. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-3-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/lance.c | 1 - hw/net/pcnet-pci.c | 1 - hw/net/pcnet.c | 9 --------- hw/net/pcnet.h | 1 - 4 files changed, 12 deletions(-) diff --git a/hw/net/lance.c b/hw/net/lance.c index 4baa016..780b39d 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -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, }; diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 8305d1b..b4d60b8 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -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, }; diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index 68b9981..3437376 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -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_) diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h index 79c4c84..dec8de8 100644 --- a/hw/net/pcnet.h +++ b/hw/net/pcnet.h @@ -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); -- cgit v1.1 From 363db4b249244f31d3c47fbd5a8b128c95ba8fe7 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:04 +0800 Subject: eepro100: Drop nic_can_receive nic_receive already checks the conditions and drop packets if false. Due to the new semantics since 6e99c63 ("net/socket: Drop net_socket_can_send"), having .can_receive returning 0 requires us to explicitly flush the queued packets when the conditions are becoming true, but queuing the packets when guest driver is not ready doesn't make much sense. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-4-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/eepro100.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index c374c1a..60333b7 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -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, }; -- cgit v1.1 From 913440249ea2e697177e9d43167ac325a8dfe907 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:05 +0800 Subject: usbnet: Drop usbnet_can_receive usbnet_receive already drops packet if rndis_state is not RNDIS_DATA_INITIALIZED, and queues packet if in buffer is not available. The only difference is s->dev.config but that is similar to rndis_state. Drop usbnet_can_receive and move these checks to usbnet_receive, so that we don't need to explicitly flush the queue when s->dev.config changes value. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-5-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/usb/dev-network.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 5eeb4c6..7800cee 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -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, }; -- cgit v1.1 From b6cb6610c27c5b0773a340499f19c3477bf45aeb Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:06 +0800 Subject: etsec: Move etsec_can_receive into etsec_receive When etsec_reset returns 0, peer would queue the packet as if .can_receive returns false. Drop etsec_can_receive and let etsec_receive carry the semantics. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-6-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/fsl_etsec/etsec.c | 11 +---------- hw/net/fsl_etsec/etsec.h | 2 +- hw/net/fsl_etsec/rings.c | 14 ++++++++------ 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index c57365f..f5170ae 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -338,13 +338,6 @@ 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) @@ -355,8 +348,7 @@ static ssize_t etsec_receive(NetClientState *nc, 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; + return etsec_rx_ring_write(etsec, buf, size); } @@ -370,7 +362,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, }; diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h index 78d2c57..fc41773 100644 --- a/hw/net/fsl_etsec/etsec.h +++ b/hw/net/fsl_etsec/etsec.h @@ -162,7 +162,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, diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index d4a494f..a11280b 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -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) -- cgit v1.1 From 575bafd1f387c5f06b59cf2515f6bb1eff9d119d Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:07 +0800 Subject: etsec: Flush queue when rx buffer is consumed The BH will be scheduled when etsec->rx_buffer_len is becoming 0, which is the condition of queuing. Signed-off-by: Fam Zheng Reviewed-by: Jason Wang Reviewed-by: Stefan Hajnoczi Message-id: 1436955553-22791-7-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/fsl_etsec/etsec.c | 11 ++++++++++- hw/net/fsl_etsec/etsec.h | 2 ++ hw/net/fsl_etsec/rings.c | 3 +++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index f5170ae..0f5cf44 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -342,13 +342,22 @@ 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 - return etsec_rx_ring_write(etsec, buf, 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; } diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h index fc41773..e7dc0a4 100644 --- a/hw/net/fsl_etsec/etsec.h +++ b/hw/net/fsl_etsec/etsec.h @@ -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" diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index a11280b..68e7b6d 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -646,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); -- cgit v1.1 From e813f0d8813944061fa9bde861cf6899379843e6 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:08 +0800 Subject: mcf_fec: Drop mcf_fec_can_receive The semantics of .can_receive requires us to flush the queue explicitly when s->rx_enabled becomes true after it returns 0, but the packet being queued is not meaningful since the guest hasn't activated the card. Let's just drop the packet in this case. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-8-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/mcf_fec.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index e63af1b..4e6939f 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -397,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); @@ -417,7 +411,7 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si 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; @@ -490,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, }; -- cgit v1.1 From 3b7031e9609baf710823aa7880fd9802b39c4563 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:09 +0800 Subject: milkymist-minimac2: Flush queued packets when link comes up Drop .can_receive and move the semantics into minimac2_rx, by returning 0. That is once minimac2_rx returns 0, incoming packets will be queued until the queue is explicitly flushed. We do this when s->regs[R_STATE0] or s->regs[R_STATE1] is changed in minimac2_write. Also drop the unused trace point. Signed-off-by: Fam Zheng Reviewed-by: Jason Wang Reviewed-by: Stefan Hajnoczi Message-id: 1436955553-22791-9-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/milkymist-minimac2.c | 33 ++++++++++++++++----------------- trace-events | 1 - 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c index f06afaa..5d1cf08 100644 --- a/hw/net/milkymist-minimac2.c +++ b/hw/net/milkymist-minimac2.c @@ -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, }; diff --git a/trace-events b/trace-events index 2d395c5..94bf3bb 100644 --- a/trace-events +++ b/trace-events @@ -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" -- cgit v1.1 From 1dd58ae0583c3d3fb15fa1d563d6b497558d3ad0 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:10 +0800 Subject: mipsnet: Flush queued packets when receiving is enabled Drop .can_receive and move the semantics to mipsnet_receive, by returning 0. After 0 is returned, we must flush the queue explicitly to restart it: Call qemu_flush_queued_packets when s->busy or s->rx_count is being updated. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-10-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/mipsnet.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index c813e0c..f261011 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -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, }; -- cgit v1.1 From 1ef4a6069f8b4c09c3383cd4b8e27b6ff25b2d41 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:11 +0800 Subject: stellaris_enet: Flush queued packets when read done If s->np reaches 31, the queue will be disabled by peer when it sees stellaris_enet_can_receive() returns false, until we explicitly flushes it which notifies the peer. Do this when guest is done reading all existing data. Move the semantics to stellaris_enet_receive, by returning 0 when the buffer is full, so that new packets will be queued. In stellaris_enet_read, flush and restart the queue when guest has done reading. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-11-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/stellaris_enet.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index 278a654..21a4773 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -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, }; -- cgit v1.1 From 4594f93a732f1f5936c3a5225481586e24bffa9e Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:12 +0800 Subject: dp8393x: Flush packets when link comes up .can_receive callback changes semantics that once return 0, backend will try sending again until explicitly flushed, change the device to meet that. dp8393x_can_receive checks SONIC_CR_RXEN bit in SONIC_CR register and SONIC_ISR_RBE bit in SONIC_ISR register, try flushing the queue when either bit is being updated. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Jason Wang Message-id: 1436955553-22791-12-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/dp8393x.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index cd889bc..451ff72 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -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: -- cgit v1.1 From f9f7492ea4a9dda538fedeec31399fb940533a16 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 15 Jul 2015 18:19:13 +0800 Subject: axienet: Flush queued packets when rx is done eth_can_rx checks s->rxsize and returns false if it is non-zero. Because of the .can_receive semantics change, this will make the incoming queue disabled by peer, until it is explicitly flushed. So we should flush it when s->rxsize is becoming zero. Squash eth_can_rx semantics into etx_rx and drop .can_receive() callback, also add flush when rx buffer becomes available again after a packet gets queued. The other conditions, "!axienet_rx_resetting(s) && axienet_rx_enabled(s)" are OK because enet_write already calls qemu_flush_queued_packets when the register bits are changed. Signed-off-by: Fam Zheng Reviewed-by: Jason Wang Reviewed-by: Stefan Hajnoczi Message-id: 1436955553-22791-13-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/net/xilinx_axienet.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 9205770..d63c423 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -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, }; -- cgit v1.1