From 489983d6b4cb501a86dfd08648fb370aec0f9b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:22 -0300 Subject: hw/net/ne2000: extract ne2k-isa code from i386/pc to ne2000-isa.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add "hw/net/ne2000-isa.h" - remove the old i386 dependency Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Hervé Poussineau Acked-by: David Gibson [PPC] Signed-off-by: Michael Tokarev --- hw/net/ne2000-isa.c | 6 ++---- hw/net/ne2000.c | 2 -- hw/net/ne2000.h | 3 +++ 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'hw/net') diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index f345533..70e5c1d 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -22,17 +22,15 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" +#include "hw/net/ne2000-isa.h" #include "hw/qdev.h" -#include "net/net.h" #include "ne2000.h" +#include "sysemu/sysemu.h" #include "exec/address-spaces.h" #include "qapi/error.h" #include "qapi/visitor.h" -#define TYPE_ISA_NE2000 "ne2k_isa" #define ISA_NE2000(obj) OBJECT_CHECK(ISANE2000State, (obj), TYPE_ISA_NE2000) typedef struct ISANE2000State { diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 3938e6d..6874c8c 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -22,9 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" #include "hw/pci/pci.h" -#include "net/net.h" #include "ne2000.h" #include "hw/loader.h" #include "sysemu/sysemu.h" diff --git a/hw/net/ne2000.h b/hw/net/ne2000.h index d213dcc..adb8021 100644 --- a/hw/net/ne2000.h +++ b/hw/net/ne2000.h @@ -1,6 +1,9 @@ #ifndef HW_NE2000_H #define HW_NE2000_H +#include "hw/hw.h" +#include "net/net.h" + #define NE2000_PMEM_SIZE (32*1024) #define NE2000_PMEM_START (16*1024) #define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START) -- cgit v1.1 From 7d08c73e7bdc39b10e5f2f5acdce700f17ffe962 Mon Sep 17 00:00:00 2001 From: Ed Swierk via Qemu-devel Date: Tue, 14 Nov 2017 15:23:33 -0800 Subject: e1000, e1000e: Move per-packet TX offload flags out of context state sum_needed and cptse flags are received from the guest within each transmit data descriptor. They are not part of the offload context; instead, they determine how to apply a previously received context to the packet being transmitted: - If cptse is set, perform both segmentation and checksum offload using the parameters in the TSO context; otherwise just do checksum offload. (Currently the e1000 device incorrectly stores only one context, which will be fixed in a subsequent patch.) - Depending on the bits set in sum_needed, possibly perform L4 checksum offload and/or IP checksum offload, using the parameters in the appropriate context. Move these flags out of struct e1000x_txd_props, which is otherwise dedicated to storing values from a context descriptor, and into the per-packet TX struct. Signed-off-by: Ed Swierk Signed-off-by: Jason Wang --- hw/net/e1000.c | 30 ++++++++++++++++-------------- hw/net/e1000e.c | 4 ++-- hw/net/e1000e_core.c | 16 ++++++++-------- hw/net/e1000e_core.h | 2 ++ hw/net/e1000x_common.h | 2 -- 5 files changed, 28 insertions(+), 26 deletions(-) (limited to 'hw/net') diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 05a00cb..30aef93 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -98,6 +98,8 @@ typedef struct E1000State_st { unsigned char data[0x10000]; uint16_t size; unsigned char vlan_needed; + unsigned char sum_needed; + bool cptse; e1000x_txd_props props; uint16_t tso_frames; } tx; @@ -540,7 +542,7 @@ xmit_seg(E1000State *s) unsigned int frames = s->tx.tso_frames, css, sofar; struct e1000_tx *tp = &s->tx; - if (tp->props.tse && tp->props.cptse) { + if (tp->props.tse && tp->cptse) { css = tp->props.ipcss; DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", frames, tp->size, css); @@ -564,7 +566,7 @@ xmit_seg(E1000State *s) } } else /* UDP */ stw_be_p(tp->data+css+4, len); - if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { unsigned int phsum; // add pseudo-header length before checksum calculation void *sp = tp->data + tp->props.tucso; @@ -576,11 +578,11 @@ xmit_seg(E1000State *s) tp->tso_frames++; } - if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { putsum(tp->data, tp->size, tp->props.tucso, tp->props.tucss, tp->props.tucse); } - if (tp->props.sum_needed & E1000_TXD_POPTS_IXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_IXSM) { putsum(tp->data, tp->size, tp->props.ipcso, tp->props.ipcss, tp->props.ipcse); } @@ -624,17 +626,17 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { // data descriptor if (tp->size == 0) { - tp->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8; + tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; } - tp->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; + tp->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; } else { // legacy descriptor - tp->props.cptse = 0; + tp->cptse = 0; } if (e1000x_vlan_enabled(s->mac_reg) && e1000x_is_vlan_txd(txd_lower) && - (tp->props.cptse || txd_lower & E1000_TXD_CMD_EOP)) { + (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) { tp->vlan_needed = 1; stw_be_p(tp->vlan_header, le16_to_cpu(s->mac_reg[VET])); @@ -643,7 +645,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } addr = le64_to_cpu(dp->buffer_addr); - if (tp->props.tse && tp->props.cptse) { + if (tp->props.tse && tp->cptse) { msh = tp->props.hdr_len + tp->props.mss; do { bytes = split_size; @@ -665,7 +667,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } split_size -= bytes; } while (bytes && split_size); - } else if (!tp->props.tse && tp->props.cptse) { + } else if (!tp->props.tse && tp->cptse) { // context descriptor TSE is not set, while data descriptor TSE is set DBGOUT(TXERR, "TCP segmentation error\n"); } else { @@ -676,14 +678,14 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) if (!(txd_lower & E1000_TXD_CMD_EOP)) return; - if (!(tp->props.tse && tp->props.cptse && tp->size < tp->props.hdr_len)) { + if (!(tp->props.tse && tp->cptse && tp->size < tp->props.hdr_len)) { xmit_seg(s); } tp->tso_frames = 0; - tp->props.sum_needed = 0; + tp->sum_needed = 0; tp->vlan_needed = 0; tp->size = 0; - tp->props.cptse = 0; + tp->cptse = 0; } static uint32_t @@ -1461,7 +1463,7 @@ static const VMStateDescription vmstate_e1000 = { VMSTATE_UINT16(tx.props.mss, E1000State), VMSTATE_UINT16(tx.size, E1000State), VMSTATE_UINT16(tx.tso_frames, E1000State), - VMSTATE_UINT8(tx.props.sum_needed, E1000State), + VMSTATE_UINT8(tx.sum_needed, E1000State), VMSTATE_INT8(tx.props.ip, E1000State), VMSTATE_INT8(tx.props.tcp, E1000State), VMSTATE_BUFFER(tx.header, E1000State), diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index f1af279..191398a 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -556,7 +556,7 @@ static const VMStateDescription e1000e_vmstate_tx = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT8(props.sum_needed, struct e1000e_tx), + VMSTATE_UINT8(sum_needed, struct e1000e_tx), VMSTATE_UINT8(props.ipcss, struct e1000e_tx), VMSTATE_UINT8(props.ipcso, struct e1000e_tx), VMSTATE_UINT16(props.ipcse, struct e1000e_tx), @@ -569,7 +569,7 @@ static const VMStateDescription e1000e_vmstate_tx = { VMSTATE_INT8(props.ip, struct e1000e_tx), VMSTATE_INT8(props.tcp, struct e1000e_tx), VMSTATE_BOOL(props.tse, struct e1000e_tx), - VMSTATE_BOOL(props.cptse, struct e1000e_tx), + VMSTATE_BOOL(cptse, struct e1000e_tx), VMSTATE_BOOL(skip_cp, struct e1000e_tx), VMSTATE_END_OF_LIST() } diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 43a8d89..c93c466 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -632,18 +632,18 @@ e1000e_rss_parse_packet(E1000ECore *core, static void e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx) { - if (tx->props.tse && tx->props.cptse) { + if (tx->props.tse && tx->cptse) { net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss); net_tx_pkt_update_ip_checksums(tx->tx_pkt); e1000x_inc_reg_if_not_full(core->mac, TSCTC); return; } - if (tx->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tx->sum_needed & E1000_TXD_POPTS_TXSM) { net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0); } - if (tx->props.sum_needed & E1000_TXD_POPTS_IXSM) { + if (tx->sum_needed & E1000_TXD_POPTS_IXSM) { net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt); } } @@ -715,13 +715,13 @@ e1000e_process_tx_desc(E1000ECore *core, return; } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { /* data descriptor */ - tx->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8; - tx->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; + tx->sum_needed = le32_to_cpu(dp->upper.data) >> 8; + tx->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; e1000e_process_ts_option(core, dp); } else { /* legacy descriptor */ e1000e_process_ts_option(core, dp); - tx->props.cptse = 0; + tx->cptse = 0; } addr = le64_to_cpu(dp->buffer_addr); @@ -747,8 +747,8 @@ e1000e_process_tx_desc(E1000ECore *core, tx->skip_cp = false; net_tx_pkt_reset(tx->tx_pkt); - tx->props.sum_needed = 0; - tx->props.cptse = 0; + tx->sum_needed = 0; + tx->cptse = 0; } } diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h index 1ff6978..7d8ff41 100644 --- a/hw/net/e1000e_core.h +++ b/hw/net/e1000e_core.h @@ -71,6 +71,8 @@ struct E1000Core { e1000x_txd_props props; bool skip_cp; + unsigned char sum_needed; + bool cptse; struct NetTxPkt *tx_pkt; } tx[E1000E_NUM_QUEUES]; diff --git a/hw/net/e1000x_common.h b/hw/net/e1000x_common.h index 3072ce9..0268884 100644 --- a/hw/net/e1000x_common.h +++ b/hw/net/e1000x_common.h @@ -193,7 +193,6 @@ void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy); void e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int size); typedef struct e1000x_txd_props { - unsigned char sum_needed; uint8_t ipcss; uint8_t ipcso; uint16_t ipcse; @@ -206,7 +205,6 @@ typedef struct e1000x_txd_props { int8_t ip; int8_t tcp; bool tse; - bool cptse; } e1000x_txd_props; void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d, -- cgit v1.1 From d62644b46a86bce2c069af7122501e3ffd349d3c Mon Sep 17 00:00:00 2001 From: Ed Swierk via Qemu-devel Date: Tue, 14 Nov 2017 15:23:34 -0800 Subject: e1000: Separate TSO and non-TSO contexts, fixing UDP TX corruption The device is supposed to maintain two distinct contexts for transmit offloads: one has parameters for both segmentation and checksum offload, the other only for checksum offload. The guest driver can send two context descriptors, one for each context (the TSE flag specifies which). Then the guest can refer to one or the other context in subsequent transmit data descriptors, depending on what offloads it wants applied to each packet. Currently the e1000 device stores just one context, and misinterprets the TSE flags in the context and data descriptors. This is often okay: Linux happens to send a fresh context descriptor before every data descriptor, so forgetting the other context doesn't matter. Windows does rely on separate contexts for TSO vs. non-TSO packets, but for mostly-TCP traffic the two contexts have identical TCP-specific offload parameters so confusing them doesn't matter. One case where this confusion matters is when a Windows guest sets up a TSO context for TCP and a non-TSO context for UDP, and then transmits both TCP and UDP traffic in parallel. The e1000 device sometimes ends up using TCP-specific parameters while doing checksum offload on a UDP datagram: it writes the checksum to offset 16 (the correct location for a TCP checksum), stomping on two bytes of UDP data, and leaving the wrong value in the actual UDP checksum field at offset 6. (Even worse, the host network stack may then recompute the UDP checksum, "correcting" it to match the corrupt data before sending it out a physical interface.) Correct this by tracking the TSO context independently of the non-TSO context, and selecting the appropriate context based on the TSE flag in each transmit data descriptor. Signed-off-by: Ed Swierk Signed-off-by: Jason Wang --- hw/net/e1000.c | 70 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 30 deletions(-) (limited to 'hw/net') diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 30aef93..804ec08 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -101,6 +101,7 @@ typedef struct E1000State_st { unsigned char sum_needed; bool cptse; e1000x_txd_props props; + e1000x_txd_props tso_props; uint16_t tso_frames; } tx; @@ -541,35 +542,37 @@ xmit_seg(E1000State *s) uint16_t len; unsigned int frames = s->tx.tso_frames, css, sofar; struct e1000_tx *tp = &s->tx; + struct e1000x_txd_props *props = tp->cptse ? &tp->tso_props : &tp->props; - if (tp->props.tse && tp->cptse) { - css = tp->props.ipcss; + if (tp->cptse) { + css = props->ipcss; DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", frames, tp->size, css); - if (tp->props.ip) { /* IPv4 */ + if (props->ip) { /* IPv4 */ stw_be_p(tp->data+css+2, tp->size - css); stw_be_p(tp->data+css+4, lduw_be_p(tp->data + css + 4) + frames); } else { /* IPv6 */ stw_be_p(tp->data+css+4, tp->size - css); } - css = tp->props.tucss; + css = props->tucss; len = tp->size - css; - DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->props.tcp, css, len); - if (tp->props.tcp) { - sofar = frames * tp->props.mss; + DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", props->tcp, css, len); + if (props->tcp) { + sofar = frames * props->mss; stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */ - if (tp->props.paylen - sofar > tp->props.mss) { + if (props->paylen - sofar > props->mss) { tp->data[css + 13] &= ~9; /* PSH, FIN */ } else if (frames) { e1000x_inc_reg_if_not_full(s->mac_reg, TSCTC); } - } else /* UDP */ + } else { /* UDP */ stw_be_p(tp->data+css+4, len); + } if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { unsigned int phsum; // add pseudo-header length before checksum calculation - void *sp = tp->data + tp->props.tucso; + void *sp = tp->data + props->tucso; phsum = lduw_be_p(sp) + len; phsum = (phsum >> 16) + (phsum & 0xffff); @@ -579,12 +582,10 @@ xmit_seg(E1000State *s) } if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { - putsum(tp->data, tp->size, tp->props.tucso, - tp->props.tucss, tp->props.tucse); + putsum(tp->data, tp->size, props->tucso, props->tucss, props->tucse); } if (tp->sum_needed & E1000_TXD_POPTS_IXSM) { - putsum(tp->data, tp->size, tp->props.ipcso, - tp->props.ipcss, tp->props.ipcse); + putsum(tp->data, tp->size, props->ipcso, props->ipcss, props->ipcse); } if (tp->vlan_needed) { memmove(tp->vlan, tp->data, 4); @@ -616,11 +617,11 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE); if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */ - e1000x_read_tx_ctx_descr(xp, &tp->props); - tp->tso_frames = 0; - if (tp->props.tucso == 0) { /* this is probably wrong */ - DBGOUT(TXSUM, "TCP/UDP: cso 0!\n"); - tp->props.tucso = tp->props.tucss + (tp->props.tcp ? 16 : 6); + if (le32_to_cpu(xp->cmd_and_length) & E1000_TXD_CMD_TSE) { + e1000x_read_tx_ctx_descr(xp, &tp->tso_props); + tp->tso_frames = 0; + } else { + e1000x_read_tx_ctx_descr(xp, &tp->props); } return; } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { @@ -645,8 +646,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } addr = le64_to_cpu(dp->buffer_addr); - if (tp->props.tse && tp->cptse) { - msh = tp->props.hdr_len + tp->props.mss; + if (tp->cptse) { + msh = tp->tso_props.hdr_len + tp->tso_props.mss; do { bytes = split_size; if (tp->size + bytes > msh) @@ -655,21 +656,19 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) bytes = MIN(sizeof(tp->data) - tp->size, bytes); pci_dma_read(d, addr, tp->data + tp->size, bytes); sz = tp->size + bytes; - if (sz >= tp->props.hdr_len && tp->size < tp->props.hdr_len) { - memmove(tp->header, tp->data, tp->props.hdr_len); + if (sz >= tp->tso_props.hdr_len + && tp->size < tp->tso_props.hdr_len) { + memmove(tp->header, tp->data, tp->tso_props.hdr_len); } tp->size = sz; addr += bytes; if (sz == msh) { xmit_seg(s); - memmove(tp->data, tp->header, tp->props.hdr_len); - tp->size = tp->props.hdr_len; + memmove(tp->data, tp->header, tp->tso_props.hdr_len); + tp->size = tp->tso_props.hdr_len; } split_size -= bytes; } while (bytes && split_size); - } else if (!tp->props.tse && tp->cptse) { - // context descriptor TSE is not set, while data descriptor TSE is set - DBGOUT(TXERR, "TCP segmentation error\n"); } else { split_size = MIN(sizeof(tp->data) - tp->size, split_size); pci_dma_read(d, addr, tp->data + tp->size, split_size); @@ -678,7 +677,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) if (!(txd_lower & E1000_TXD_CMD_EOP)) return; - if (!(tp->props.tse && tp->cptse && tp->size < tp->props.hdr_len)) { + if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) { xmit_seg(s); } tp->tso_frames = 0; @@ -1437,7 +1436,7 @@ static const VMStateDescription vmstate_e1000_full_mac_state = { static const VMStateDescription vmstate_e1000 = { .name = "e1000", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .pre_save = e1000_pre_save, .post_load = e1000_post_load, @@ -1510,6 +1509,17 @@ static const VMStateDescription vmstate_e1000 = { VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32), VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128), VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128), + VMSTATE_UINT8_V(tx.tso_props.ipcss, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.ipcso, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.ipcse, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.tucss, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.tucso, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.tucse, E1000State, 3), + VMSTATE_UINT32_V(tx.tso_props.paylen, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.hdr_len, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.mss, E1000State, 3), + VMSTATE_INT8_V(tx.tso_props.ip, E1000State, 3), + VMSTATE_INT8_V(tx.tso_props.tcp, E1000State, 3), VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription*[]) { -- cgit v1.1 From eaba8f34f0dac5e9296df9c2046d9601264c46a4 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:43 +0000 Subject: net: move CRC32 calculation from compute_mcast_idx() into its own net_crc32() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separate out the standard ethernet CRC32 calculation into a new net_crc32() function, renaming the constant POLYNOMIAL to POLYNOMIAL_BE to make it clear that this is a big-endian CRC32 calculation. As part of the constant rename, remove the duplicate definition of POLYNOMIAL from eepro100.c and use the new POLYNOMIAL_BE constant instead. Once this is complete remove the existing CRC32 implementation from compute_mcast_idx() and call the new net_crc32() function in its place. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/eepro100.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'hw/net') diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index 1c0def5..71cddfe 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -323,8 +323,6 @@ static const uint16_t eepro100_mdi_mask[] = { 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; -#define POLYNOMIAL 0x04c11db6 - static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s); /* From FreeBSD (locally modified). */ @@ -342,7 +340,7 @@ static unsigned e100_compute_mcast_idx(const uint8_t *ep) crc <<= 1; b >>= 1; if (carry) { - crc = ((crc ^ POLYNOMIAL) | carry); + crc = ((crc ^ POLYNOMIAL_BE) | carry); } } } -- cgit v1.1 From cbbeca91819c8e08f4b85777f8dd1671314db586 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:45 +0000 Subject: pcnet: switch pcnet over to use net_crc32_le() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of lnc_mchash() using its own implementation, we can simply call net_crc32_le() directly and apply the bit shift inline. Signed-off-by: Mark Cave-Ayland Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/pcnet.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'hw/net') diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index 6544553..39d5d93 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -38,6 +38,7 @@ #include "qemu/osdep.h" #include "hw/qdev.h" #include "net/net.h" +#include "net/eth.h" #include "qemu/timer.h" #include "qemu/sockets.h" #include "sysemu/sysemu.h" @@ -522,25 +523,6 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, be16_to_cpu(hdr->ether_type)); \ } while (0) -#define MULTICAST_FILTER_LEN 8 - -static inline uint32_t lnc_mchash(const uint8_t *ether_addr) -{ -#define LNC_POLYNOMIAL 0xEDB88320UL - uint32_t crc = 0xFFFFFFFF; - int idx, bit; - uint8_t data; - - for (idx = 0; idx < 6; idx++) { - for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) { - crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); - data >>= 1; - } - } - return crc; -#undef LNC_POLYNOMIAL -} - #define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) /* generated using the AUTODIN II polynomial @@ -656,7 +638,7 @@ static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) s->csr[10] & 0xff, s->csr[10] >> 8, s->csr[11] & 0xff, s->csr[11] >> 8 }; - int index = lnc_mchash(hdr->ether_dhost) >> 26; + int index = net_crc32_le(hdr->ether_dhost, ETH_ALEN) >> 26; return !!(ladr[index >> 3] & (1 << (index & 7))); } return 0; -- cgit v1.1 From 7c0348bd633aff5ff27d5c393008495175ca416b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:46 +0000 Subject: eepro100: switch eepro100 e100_compute_mcast_idx() over to use net_crc32() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of e100_compute_mcast_idx() using its own implementation, we can simply call net_crc32() directly and apply the bit shift inline. Signed-off-by: Mark Cave-Ayland Reviewed-by: Stefan Weil Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/eepro100.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) (limited to 'hw/net') diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index 71cddfe..e30fed8 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -44,6 +44,7 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "net/net.h" +#include "net/eth.h" #include "hw/nvram/eeprom93xx.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" @@ -325,28 +326,6 @@ static const uint16_t eepro100_mdi_mask[] = { static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s); -/* From FreeBSD (locally modified). */ -static unsigned e100_compute_mcast_idx(const uint8_t *ep) -{ - uint32_t crc; - int carry, i, j; - uint8_t b; - - crc = 0xffffffff; - for (i = 0; i < 6; i++) { - b = *ep++; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); - crc <<= 1; - b >>= 1; - if (carry) { - crc = ((crc ^ POLYNOMIAL_BE) | carry); - } - } - } - return (crc & BITS(7, 2)) >> 2; -} - /* Read a 16 bit control/status (CSR) register. */ static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr) { @@ -843,7 +822,8 @@ static void set_multicast_list(EEPRO100State *s) uint8_t multicast_addr[6]; pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6); TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6))); - unsigned mcast_idx = e100_compute_mcast_idx(multicast_addr); + unsigned mcast_idx = (net_crc32(multicast_addr, ETH_ALEN) & + BITS(7, 2)) >> 2; assert(mcast_idx < 64); s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7)); } @@ -1679,7 +1659,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) if (s->configuration[21] & BIT(3)) { /* Multicast all bit is set, receive all multicast frames. */ } else { - unsigned mcast_idx = e100_compute_mcast_idx(buf); + unsigned mcast_idx = (net_crc32(buf, ETH_ALEN) & BITS(7, 2)) >> 2; assert(mcast_idx < 64); if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) { /* Multicast frame is allowed in hash table. */ -- cgit v1.1 From a89a6b052abff87871800406bd3c598fcf406426 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:47 +0000 Subject: sunhme: switch sunhme over to use net_crc32_le() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of sunhme_crc32_le() using its own implementation, we can simply call net_crc32_le() directly and apply the bit shift inline. Signed-off-by: Mark Cave-Ayland Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/sunhme.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'hw/net') diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index b1efa1b..7558fca 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -698,29 +698,6 @@ static inline void sunhme_set_rx_ring_nr(SunHMEState *s, int i) s->erxregs[HME_ERXI_RING >> 2] = ring; } -#define POLYNOMIAL_LE 0xedb88320 -static uint32_t sunhme_crc32_le(const uint8_t *p, int len) -{ - uint32_t crc; - int carry, i, j; - uint8_t b; - - crc = 0xffffffff; - for (i = 0; i < len; i++) { - b = *p++; - for (j = 0; j < 8; j++) { - carry = (crc & 0x1) ^ (b & 0x01); - crc >>= 1; - b >>= 1; - if (carry) { - crc = crc ^ POLYNOMIAL_LE; - } - } - } - - return crc; -} - #define MIN_BUF_SIZE 60 static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf, @@ -761,7 +738,7 @@ static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf, trace_sunhme_rx_filter_bcast_match(); } else if (s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_HENABLE) { /* Didn't match local address, check hash filter */ - int mcast_idx = sunhme_crc32_le(buf, 6) >> 26; + int mcast_idx = net_crc32_le(buf, ETH_ALEN) >> 26; if (!(s->macregs[(HME_MACI_HASHTAB0 >> 2) - (mcast_idx >> 4)] & (1 << (mcast_idx & 0xf)))) { /* Didn't match hash filter */ -- cgit v1.1 From 8f90bc2f8fbba3c98116e80afd537fb0ca90be2e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:48 +0000 Subject: sungem: fix multicast filter CRC calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the Linux sungem driver, we know that the multicast filter CRC is implemented using ether_crc_le() which isn't the same as calling zlib's crc32() function (the zlib implementation requires a complemented initial value and also returns the complemented result). Fix the multicast filter by simply using the new net_crc32_le() function. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/sungem.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'hw/net') diff --git a/hw/net/sungem.c b/hw/net/sungem.c index 6aa8d11..60f1e47 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -11,12 +11,11 @@ #include "hw/pci/pci.h" #include "qemu/log.h" #include "net/net.h" +#include "net/eth.h" #include "net/checksum.h" #include "hw/net/mii.h" #include "sysemu/sysemu.h" #include "trace.h" -/* For crc32 */ -#include #define TYPE_SUNGEM "sungem" @@ -595,7 +594,7 @@ static ssize_t sungem_receive(NetClientState *nc, const uint8_t *buf, } /* Get MAC crc */ - mac_crc = crc32(~0, buf, 6); + mac_crc = net_crc32_le(buf, ETH_ALEN); /* Packet isn't for me ? */ rx_cond = sungem_check_rx_mac(s, buf, mac_crc); -- cgit v1.1 From d00d6d005424dd2447f8b0394e945909852a4282 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:49 +0000 Subject: eepro100: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/eepro100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index e30fed8..a07a632 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -1679,7 +1679,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) rfd_status |= 0x0004; } else if (s->configuration[20] & BIT(6)) { /* Multiple IA bit set. */ - unsigned mcast_idx = compute_mcast_idx(buf); + unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; assert(mcast_idx < 64); if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) { TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s)); -- cgit v1.1 From 308913bb431104f34f5c2e35eaaf297ff3e8ec7b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:50 +0000 Subject: opencores_eth: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/opencores_eth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index 268d6a7..d42b79c 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -36,6 +36,7 @@ #include "hw/net/mii.h" #include "hw/sysbus.h" #include "net/net.h" +#include "net/eth.h" #include "sysemu/sysemu.h" #include "trace.h" @@ -373,7 +374,7 @@ static ssize_t open_eth_receive(NetClientState *nc, if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) == 0) { miss = GET_REGBIT(s, MODER, BRO); } else if ((buf[0] & 0x1) || GET_REGBIT(s, MODER, IAM)) { - unsigned mcast_idx = compute_mcast_idx(buf); + unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; miss = !(s->regs[HASH0 + mcast_idx / 32] & (1 << (mcast_idx % 32))); trace_open_eth_receive_mcast( -- cgit v1.1 From eedeaee73ac47341efca4c06e3ccb0029ee9332f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:51 +0000 Subject: lan9118: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/lan9118.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 3db8937..b9032da 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "net/net.h" +#include "net/eth.h" #include "hw/devices.h" #include "sysemu/sysemu.h" #include "hw/ptimer.h" @@ -504,7 +505,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr) } } else { /* Hash matching */ - hash = compute_mcast_idx(addr); + hash = net_crc32(addr, ETH_ALEN) >> 26; if (hash & 0x20) { return (s->mac_hashh >> (hash & 0x1f)) & 1; } else { -- cgit v1.1 From 4227be63f081e939ae7313b1921d8f60a5d8d714 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:52 +0000 Subject: ftgmac100: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/ftgmac100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 3c36ab9..704f452 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -762,7 +762,7 @@ static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len) } /* TODO: this does not seem to work for ftgmac100 */ - mcast_idx = compute_mcast_idx(buf); + mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; if (!(s->math[mcast_idx / 32] & (1 << (mcast_idx % 32)))) { return 0; } -- cgit v1.1 From 084e2b111bb9c809fd53563e3b5ef1ea3bef08ad Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:53 +0000 Subject: ne2000: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/ne2000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 6874c8c..687ef84 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -23,6 +23,8 @@ */ #include "qemu/osdep.h" #include "hw/pci/pci.h" +#include "net/net.h" +#include "net/eth.h" #include "ne2000.h" #include "hw/loader.h" #include "sysemu/sysemu.h" @@ -199,7 +201,7 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_) /* multicast */ if (!(s->rxcr & 0x08)) return size; - mcast_idx = compute_mcast_idx(buf); + mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) return size; } else if (s->mem[0] == buf[0] && -- cgit v1.1 From e7a58fc71ca039ae46590e9395467cea283d259c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:54 +0000 Subject: rtl8139: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/rtl8139.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index a6b2a9f..1cc95b8 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -882,7 +882,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t return size; } - int mcast_idx = compute_mcast_idx(buf); + int mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { -- cgit v1.1 From f5980f757c028ec68ff8442c418db8462415af2a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: sun4m: remove include/hw/sparc/sun4m.h and all references to it With the previous commit there is now nothing left in sun4m.h so it can be removed, along with all remaining references to it. Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/net/lance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/lance.c b/hw/net/lance.c index 23929fd..0028bc5 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -40,7 +40,7 @@ #include "net/net.h" #include "qemu/timer.h" #include "qemu/sockets.h" -#include "hw/sparc/sun4m.h" +#include "hw/sparc/sparc32_dma.h" #include "hw/net/lance.h" #include "trace.h" #include "sysemu/sysemu.h" -- cgit v1.1 From 1fdde6537ecec4a6b416bc232c868b64d645cc62 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:34 +0000 Subject: imx_fec: Do not link to netdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Binding to a particular netdev doesn't seem to belong to this layer and should probably be done as a part of board or SoC specific code. Convert all of the users of this IP block to use qdev_set_nic_properties() instead. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 90e6ee3..88b4b04 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1171,8 +1171,6 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->conf.peers.ncs[0] = nd_table[0].netdev; - s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, object_get_typename(OBJECT(dev)), DEVICE(dev)->id, s); -- cgit v1.1 From a6383e99ffc3b615d8465aebbd5d48f1fa9b2949 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: imx_fec: Refactor imx_eth_enable_rx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor imx_eth_enable_rx() to have more meaningfull variable name than 'tmp' and to reduce number of logical negations done. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 88b4b04..8b2e4b8 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -536,19 +536,19 @@ static void imx_eth_do_tx(IMXFECState *s) static void imx_eth_enable_rx(IMXFECState *s) { IMXFECBufDesc bd; - bool tmp; + bool rx_ring_full; imx_fec_read_bd(&bd, s->rx_descriptor); - tmp = ((bd.flags & ENET_BD_E) != 0); + rx_ring_full = !(bd.flags & ENET_BD_E); - if (!tmp) { + if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); } else if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } - s->regs[ENET_RDAR] = tmp ? ENET_RDAR_RDAR : 0; + s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR; } static void imx_eth_reset(DeviceState *d) -- cgit v1.1 From b2b012afdd9c03ba8a1619f45301d34f358d367b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: imx_fec: Change queue flushing heuristics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In current implementation, packet queue flushing logic seem to suffer from a deadlock like scenario if a packet is received by the interface before before Rx ring is initialized by Guest's driver. Consider the following sequence of events: 1. A QEMU instance is started against a TAP device on Linux host, running Linux guest, e. g., something to the effect of: qemu-system-arm \ -net nic,model=imx.fec,netdev=lan0 \ netdev tap,id=lan0,ifname=tap0,script=no,downscript=no \ ... rest of the arguments ... 2. Once QEMU starts, but before guest reaches the point where FEC deriver is done initializing the HW, Guest, via TAP interface, receives a number of multicast MDNS packets from Host (not necessarily true for every OS, but it happens at least on Fedora 25) 3. Recieving a packet in such a state results in imx_eth_can_receive() returning '0', which in turn causes tap_send() to disable corresponding event (tap.c:203) 4. Once Guest's driver reaches the point where it is ready to recieve packets it prepares Rx ring descriptors and writes ENET_RDAR_RDAR to ENET_RDAR register to indicate to HW that more descriptors are ready. And at this points emulation layer does this: s->regs[index] = ENET_RDAR_RDAR; imx_eth_enable_rx(s); which, combined with: if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } results in Rx queue never being flushed and corresponding I/O event beign disabled. To prevent the problem, change the code to always flush packet queue when ENET_RDAR transitions 0 -> ENET_RDAR_RDAR. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 8b2e4b8..eb034ff 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -533,7 +533,7 @@ static void imx_eth_do_tx(IMXFECState *s) } } -static void imx_eth_enable_rx(IMXFECState *s) +static void imx_eth_enable_rx(IMXFECState *s, bool flush) { IMXFECBufDesc bd; bool rx_ring_full; @@ -544,7 +544,7 @@ static void imx_eth_enable_rx(IMXFECState *s) if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); - } else if (!s->regs[ENET_RDAR]) { + } else if (flush) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } @@ -807,7 +807,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { if (!s->regs[index]) { s->regs[index] = ENET_RDAR_RDAR; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, true); } } else { s->regs[index] = 0; @@ -930,7 +930,7 @@ static int imx_eth_can_receive(NetClientState *nc) FEC_PRINTF("\n"); - return s->regs[ENET_RDAR] ? 1 : 0; + return !!s->regs[ENET_RDAR]; } static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, @@ -1020,7 +1020,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, } } s->rx_descriptor = addr; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, false); imx_eth_update(s); return len; } @@ -1116,7 +1116,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, } } s->rx_descriptor = addr; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, false); imx_eth_update(s); return len; } -- cgit v1.1 From 7bac20dc5111963083686743dee00e0ae4fd976b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: imx_fec: Move Tx frame buffer away from the stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make Tx frame assembly buffer to be a paort of IMXFECState structure to avoid a concern about having large data buffer on the stack. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Signed-off-by: Andrey Smirnov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index eb034ff..56cb722 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -405,8 +405,7 @@ static void imx_eth_update(IMXFECState *s) static void imx_fec_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; - uint8_t frame[ENET_MAX_FRAME_SIZE]; - uint8_t *ptr = frame; + uint8_t *ptr = s->frame; uint32_t addr = s->tx_descriptor; while (descnt++ < IMX_MAX_DESC) { @@ -431,8 +430,8 @@ static void imx_fec_do_tx(IMXFECState *s) frame_size += len; if (bd.flags & ENET_BD_L) { /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size); - ptr = frame; + qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size); + ptr = s->frame; frame_size = 0; s->regs[ENET_EIR] |= ENET_INT_TXF; } @@ -456,8 +455,7 @@ static void imx_fec_do_tx(IMXFECState *s) static void imx_enet_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; - uint8_t frame[ENET_MAX_FRAME_SIZE]; - uint8_t *ptr = frame; + uint8_t *ptr = s->frame; uint32_t addr = s->tx_descriptor; while (descnt++ < IMX_MAX_DESC) { @@ -482,13 +480,13 @@ static void imx_enet_do_tx(IMXFECState *s) frame_size += len; if (bd.flags & ENET_BD_L) { if (bd.option & ENET_BD_PINS) { - struct ip_header *ip_hd = PKT_GET_IP_HDR(frame); + struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame); if (IP_HEADER_VERSION(ip_hd) == 4) { - net_checksum_calculate(frame, frame_size); + net_checksum_calculate(s->frame, frame_size); } } if (bd.option & ENET_BD_IINS) { - struct ip_header *ip_hd = PKT_GET_IP_HDR(frame); + struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame); /* We compute checksum only for IPv4 frames */ if (IP_HEADER_VERSION(ip_hd) == 4) { uint16_t csum; @@ -498,8 +496,10 @@ static void imx_enet_do_tx(IMXFECState *s) } } /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), frame, len); - ptr = frame; + + qemu_send_packet(qemu_get_queue(s->nic), s->frame, len); + ptr = s->frame; + frame_size = 0; if (bd.option & ENET_BD_TX_INT) { s->regs[ENET_EIR] |= ENET_INT_TXF; -- cgit v1.1 From ff9a7feeab59323d70a9377e9196f042b0647d66 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:36 +0000 Subject: imx_fec: Use ENET_FTRL to determine truncation length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frame truncation length, TRUNC_FL, is determined by the contents of ENET_FTRL register, so convert the code to use it instead of a hardcoded constant. To avoid the case where TRUNC_FL is greater that ENET_MAX_FRAME_SIZE, increase the value of the latter to its theoretical maximum of 16K. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Signed-off-by: Andrey Smirnov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 56cb722..50da91b 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1052,8 +1052,8 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, crc_ptr = (uint8_t *) &crc; /* Huge frames are truncted. */ - if (size > ENET_MAX_FRAME_SIZE) { - size = ENET_MAX_FRAME_SIZE; + if (size > s->regs[ENET_FTRL]) { + size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; } -- cgit v1.1 From 4c5e7a6cdae78ed823042375824ced09cccefbdb Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:36 +0000 Subject: imx_fec: Use MIN instead of explicit ternary operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 50da91b..6feda18 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1076,7 +1076,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, TYPE_IMX_FEC, __func__); break; } - buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR]; + buf_len = MIN(size, s->regs[ENET_MRBR]); bd.length = buf_len; size -= buf_len; -- cgit v1.1 From ebdd8cddb9e657ef75024b4cc9057dd4ce397a55 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: imx_fec: Emulate SHIFT16 in ENETx_RACC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed to support latest Linux kernel driver which relies on that functionality. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6feda18..825c879 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1037,6 +1037,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, uint8_t *crc_ptr; unsigned int buf_len; size_t size = len; + bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16; FEC_PRINTF("len %d\n", (int)size); @@ -1051,6 +1052,10 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, crc = cpu_to_be32(crc32(~0, buf, size)); crc_ptr = (uint8_t *) &crc; + if (shift16) { + size += 2; + } + /* Huge frames are truncted. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; @@ -1087,6 +1092,24 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, buf_len += size - 4; } buf_addr = bd.data; + + if (shift16) { + /* + * If SHIFT16 bit of ENETx_RACC register is set we need to + * align the payload to 4-byte boundary. + */ + const uint8_t zeros[2] = { 0 }; + + dma_memory_write(&address_space_memory, buf_addr, + zeros, sizeof(zeros)); + + buf_addr += sizeof(zeros); + buf_len -= sizeof(zeros); + + /* We only do this once per Ethernet frame */ + shift16 = false; + } + dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); buf += buf_len; if (size < 4) { -- cgit v1.1 From f93f961c40a31228e3f66e66d99a68937aa242c5 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: imx_fec: Add support for multiple Tx DMA rings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More recent version of the IP block support more than one Tx DMA ring, so add the code implementing that feature. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 19 deletions(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 825c879..77d27f7 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -196,6 +196,31 @@ static const char *imx_eth_reg_name(IMXFECState *s, uint32_t index) } } +/* + * Versions of this device with more than one TX descriptor save the + * 2nd and 3rd descriptors in a subsection, to maintain migration + * compatibility with previous versions of the device that only + * supported a single descriptor. + */ +static bool imx_eth_is_multi_tx_ring(void *opaque) +{ + IMXFECState *s = IMX_FEC(opaque); + + return s->tx_ring_num > 1; +} + +static const VMStateDescription vmstate_imx_eth_txdescs = { + .name = "imx.fec/txdescs", + .version_id = 1, + .minimum_version_id = 1, + .needed = imx_eth_is_multi_tx_ring, + .fields = (VMStateField[]) { + VMSTATE_UINT32(tx_descriptor[1], IMXFECState), + VMSTATE_UINT32(tx_descriptor[2], IMXFECState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_imx_eth = { .name = TYPE_IMX_FEC, .version_id = 2, @@ -203,15 +228,18 @@ static const VMStateDescription vmstate_imx_eth = { .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), VMSTATE_UINT32(rx_descriptor, IMXFECState), - VMSTATE_UINT32(tx_descriptor, IMXFECState), - + VMSTATE_UINT32(tx_descriptor[0], IMXFECState), VMSTATE_UINT32(phy_status, IMXFECState), VMSTATE_UINT32(phy_control, IMXFECState), VMSTATE_UINT32(phy_advertise, IMXFECState), VMSTATE_UINT32(phy_int, IMXFECState), VMSTATE_UINT32(phy_int_mask, IMXFECState), VMSTATE_END_OF_LIST() - } + }, + .subsections = (const VMStateDescription * []) { + &vmstate_imx_eth_txdescs, + NULL + }, }; #define PHY_INT_ENERGYON (1 << 7) @@ -406,7 +434,7 @@ static void imx_fec_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; uint8_t *ptr = s->frame; - uint32_t addr = s->tx_descriptor; + uint32_t addr = s->tx_descriptor[0]; while (descnt++ < IMX_MAX_DESC) { IMXFECBufDesc bd; @@ -447,16 +475,47 @@ static void imx_fec_do_tx(IMXFECState *s) } } - s->tx_descriptor = addr; + s->tx_descriptor[0] = addr; imx_eth_update(s); } -static void imx_enet_do_tx(IMXFECState *s) +static void imx_enet_do_tx(IMXFECState *s, uint32_t index) { int frame_size = 0, descnt = 0; + uint8_t *ptr = s->frame; - uint32_t addr = s->tx_descriptor; + uint32_t addr, int_txb, int_txf, tdsr; + size_t ring; + + switch (index) { + case ENET_TDAR: + ring = 0; + int_txb = ENET_INT_TXB; + int_txf = ENET_INT_TXF; + tdsr = ENET_TDSR; + break; + case ENET_TDAR1: + ring = 1; + int_txb = ENET_INT_TXB1; + int_txf = ENET_INT_TXF1; + tdsr = ENET_TDSR1; + break; + case ENET_TDAR2: + ring = 2; + int_txb = ENET_INT_TXB2; + int_txf = ENET_INT_TXF2; + tdsr = ENET_TDSR2; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus value for index %x\n", + __func__, index); + abort(); + break; + } + + addr = s->tx_descriptor[ring]; while (descnt++ < IMX_MAX_DESC) { IMXENETBufDesc bd; @@ -502,32 +561,32 @@ static void imx_enet_do_tx(IMXFECState *s) frame_size = 0; if (bd.option & ENET_BD_TX_INT) { - s->regs[ENET_EIR] |= ENET_INT_TXF; + s->regs[ENET_EIR] |= int_txf; } } if (bd.option & ENET_BD_TX_INT) { - s->regs[ENET_EIR] |= ENET_INT_TXB; + s->regs[ENET_EIR] |= int_txb; } bd.flags &= ~ENET_BD_R; /* Write back the modified descriptor. */ imx_enet_write_bd(&bd, addr); /* Advance to the next descriptor. */ if ((bd.flags & ENET_BD_W) != 0) { - addr = s->regs[ENET_TDSR]; + addr = s->regs[tdsr]; } else { addr += sizeof(bd); } } - s->tx_descriptor = addr; + s->tx_descriptor[ring] = addr; imx_eth_update(s); } -static void imx_eth_do_tx(IMXFECState *s) +static void imx_eth_do_tx(IMXFECState *s, uint32_t index) { if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) { - imx_enet_do_tx(s); + imx_enet_do_tx(s, index); } else { imx_fec_do_tx(s); } @@ -585,7 +644,7 @@ static void imx_eth_reset(DeviceState *d) } s->rx_descriptor = 0; - s->tx_descriptor = 0; + memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor)); /* We also reset the PHY */ phy_reset(s); @@ -791,6 +850,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXFECState *s = IMX_FEC(opaque); + const bool single_tx_ring = !imx_eth_is_multi_tx_ring(s); uint32_t index = offset >> 2; FEC_PRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_eth_reg_name(s, index), @@ -813,10 +873,18 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, s->regs[index] = 0; } break; - case ENET_TDAR: + case ENET_TDAR1: /* FALLTHROUGH */ + case ENET_TDAR2: /* FALLTHROUGH */ + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDAR2 or TDAR1\n", + TYPE_IMX_FEC, __func__); + return; + } + case ENET_TDAR: /* FALLTHROUGH */ if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { s->regs[index] = ENET_TDAR_TDAR; - imx_eth_do_tx(s); + imx_eth_do_tx(s, index); } s->regs[index] = 0; break; @@ -828,8 +896,12 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, if ((s->regs[index] & ENET_ECR_ETHEREN) == 0) { s->regs[ENET_RDAR] = 0; s->rx_descriptor = s->regs[ENET_RDSR]; - s->regs[ENET_TDAR] = 0; - s->tx_descriptor = s->regs[ENET_TDSR]; + s->regs[ENET_TDAR] = 0; + s->regs[ENET_TDAR1] = 0; + s->regs[ENET_TDAR2] = 0; + s->tx_descriptor[0] = s->regs[ENET_TDSR]; + s->tx_descriptor[1] = s->regs[ENET_TDSR1]; + s->tx_descriptor[2] = s->regs[ENET_TDSR2]; } break; case ENET_MMFR: @@ -907,7 +979,29 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, } else { s->regs[index] = value & ~7; } - s->tx_descriptor = s->regs[index]; + s->tx_descriptor[0] = s->regs[index]; + break; + case ENET_TDSR1: + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDSR1\n", + TYPE_IMX_FEC, __func__); + return; + } + + s->regs[index] = value & ~7; + s->tx_descriptor[1] = s->regs[index]; + break; + case ENET_TDSR2: + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDSR2\n", + TYPE_IMX_FEC, __func__); + return; + } + + s->regs[index] = value & ~7; + s->tx_descriptor[2] = s->regs[index]; break; case ENET_MRBR: s->regs[index] = value & 0x00003ff0; @@ -1203,6 +1297,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) static Property imx_eth_properties[] = { DEFINE_NIC_PROPERTIES(IMXFECState, conf), + DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1), DEFINE_PROP_END_OF_LIST(), }; -- cgit v1.1 From 52cfd5846b8979805077ce7608aa36c18a2a9f32 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: imx_fec: Use correct length for packet size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use 'frame_size' instead of 'len' when calling qemu_send_packet(), failing to do so results in malformed packets send in case when that packed is fragmented into multiple DMA transactions. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 77d27f7..6cb9e2e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -556,7 +556,7 @@ static void imx_enet_do_tx(IMXFECState *s, uint32_t index) } /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), s->frame, len); + qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size); ptr = s->frame; frame_size = 0; -- cgit v1.1 From 894d74cc4f2fa577765bae711b9dc9ac9309521e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: imx_fec: Fix a typo in imx_enet_receive() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6cb9e2e..c1cf7f9 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1150,7 +1150,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, size += 2; } - /* Huge frames are truncted. */ + /* Huge frames are truncated. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; -- cgit v1.1 From 831858ad9da7eccf4c260c60ed56cff0f1666424 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: imx_fec: Reserve full FSL_IMX25_FEC_SIZE page for the register file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some i.MX SoCs (e.g. i.MX7) have FEC registers going as far as offset 0x614, so to avoid getting aborts when accessing those on QEMU, extend the register file to cover FSL_IMX25_FEC_SIZE(16K) of address space instead of just 1K. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/net') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index c1cf7f9..4fb48f6 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1281,7 +1281,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); memory_region_init_io(&s->iomem, OBJECT(dev), &imx_eth_ops, s, - TYPE_IMX_FEC, 0x400); + TYPE_IMX_FEC, FSL_IMX25_FEC_SIZE); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq[0]); sysbus_init_irq(sbd, &s->irq[1]); -- cgit v1.1