aboutsummaryrefslogtreecommitdiff
path: root/hw/net/ftgmac100.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-06-08 16:26:51 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-06-08 16:26:51 +0100
commit0d2fa03dae4fbe185a082f361342b1e30aed4582 (patch)
tree2ee9e184f32e4884cf78078841e31df7f15ffea5 /hw/net/ftgmac100.c
parented6b018ef7667f73aa25190b04e1fe3a4a87c323 (diff)
parent113f31c06c6bf16451892b2459d83c9b9c5e9844 (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180608' into staging
target-arm queue: * arm_gicv3_kvm: fix migration of registers corresponding to IRQs 992 to 1020 in the KVM GIC * aspeed: remove ignore_memory_transaction_failures on all boards * aspeed: add support for the witherspoon-bmc board * aspeed: add an I2C RTC device and EEPROM I2C devices * aspeed: add the pc9552 chips to the witherspoon machine * ftgmac100: fix various bugs * hw/arm: Remove the deprecated xlnx-ep108 machine * hw/i2c: Add trace events * add missing '\n' on various qemu_log() logging strings * sdcard: clean up spec version support so we report the right spec version to the guest and only implement the commands that are supposed to be present in that version # gpg: Signature made Fri 08 Jun 2018 13:36:37 BST # gpg: using RSA key 3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20180608: (31 commits) sdcard: Disable CMD19/CMD23 for Spec v2 sdcard: Reflect when the Spec v3 is supported in the Config Register (SCR) sdcard: Disable SEND_IF_COND (CMD8) for Spec v1 sdcard: Add a 'spec_version' property, default to Spec v2.00 sdcard: Allow commands valid in SPI mode sdcard: Update the Configuration Register (SCR) to Spec Version 1.10 target/xtensa: Add trailing '\n' to qemu_log() calls RISC-V: Add trailing '\n' to qemu_log() calls target/m68k: Add trailing '\n' to qemu_log() call target/arm: Add trailing '\n' to qemu_log() calls stellaris: Add trailing '\n' to qemu_log() calls hw/mips/boston: Add trailing '\n' to qemu_log() calls hw/core/register: Add trailing '\n' to qemu_log() call ppc/pnv: Add trailing '\n' to qemu_log() calls xilinx-dp: Add trailing '\n' to qemu_log() call hw/digic: Add trailing '\n' to qemu_log() calls hw/sd/milkymist-memcard: Add trailing '\n' to qemu_log() call hw/i2c: Add trace events hw/arm: Remove the deprecated xlnx-ep108 machine ftgmac100: remove check on runt messages ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/net/ftgmac100.c')
-rw-r--r--hw/net/ftgmac100.c64
1 files changed, 44 insertions, 20 deletions
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 3300e8ef4a..909c1182ee 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -207,16 +207,18 @@ typedef struct {
/*
* Max frame size for the receiving buffer
*/
-#define FTGMAC100_MAX_FRAME_SIZE 10240
+#define FTGMAC100_MAX_FRAME_SIZE 9220
/* Limits depending on the type of the frame
*
* 9216 for Jumbo frames (+ 4 for VLAN)
* 1518 for other frames (+ 4 for VLAN)
*/
-static int ftgmac100_max_frame_size(FTGMAC100State *s)
+static int ftgmac100_max_frame_size(FTGMAC100State *s, uint16_t proto)
{
- return (s->maccr & FTGMAC100_MACCR_JUMBO_LF ? 9216 : 1518) + 4;
+ int max = (s->maccr & FTGMAC100_MACCR_JUMBO_LF ? 9216 : 1518);
+
+ return max + (proto == ETH_P_VLAN ? 4 : 0);
}
static void ftgmac100_update_irq(FTGMAC100State *s)
@@ -408,7 +410,6 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
uint8_t *ptr = s->frame;
uint32_t addr = tx_descriptor;
uint32_t flags = 0;
- int max_frame_size = ftgmac100_max_frame_size(s);
while (1) {
FTGMAC100Desc bd;
@@ -427,11 +428,12 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
flags = bd.des1;
}
- len = bd.des0 & 0x3FFF;
- if (frame_size + len > max_frame_size) {
+ len = FTGMAC100_TXDES0_TXBUF_SIZE(bd.des0);
+ if (frame_size + len > sizeof(s->frame)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %d bytes\n",
__func__, len);
- len = max_frame_size - frame_size;
+ s->isr |= FTGMAC100_INT_XPKT_LOST;
+ len = sizeof(s->frame) - frame_size;
}
if (dma_memory_read(&address_space_memory, bd.des3, ptr, len)) {
@@ -441,6 +443,22 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
break;
}
+ /* Check for VLAN */
+ if (bd.des0 & FTGMAC100_TXDES0_FTS &&
+ bd.des1 & FTGMAC100_TXDES1_INS_VLANTAG &&
+ be16_to_cpu(PKT_GET_ETH_HDR(ptr)->h_proto) != ETH_P_VLAN) {
+ if (frame_size + len + 4 > sizeof(s->frame)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %d bytes\n",
+ __func__, len);
+ s->isr |= FTGMAC100_INT_XPKT_LOST;
+ len = sizeof(s->frame) - frame_size - 4;
+ }
+ memmove(ptr + 16, ptr + 12, len - 12);
+ stw_be_p(ptr + 12, ETH_P_VLAN);
+ stw_be_p(ptr + 14, bd.des1);
+ len += 4;
+ }
+
ptr += len;
frame_size += len;
if (bd.des0 & FTGMAC100_TXDES0_LTS) {
@@ -758,8 +776,8 @@ static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len)
return 0;
}
- /* TODO: this does not seem to work for ftgmac100 */
- mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
+ mcast_idx = net_crc32_le(buf, ETH_ALEN);
+ mcast_idx = (~(mcast_idx >> 2)) & 0x3f;
if (!(s->math[mcast_idx / 32] & (1 << (mcast_idx % 32)))) {
return 0;
}
@@ -788,7 +806,8 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
uint32_t buf_len;
size_t size = len;
uint32_t first = FTGMAC100_RXDES0_FRS;
- int max_frame_size = ftgmac100_max_frame_size(s);
+ uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(buf)->h_proto);
+ int max_frame_size = ftgmac100_max_frame_size(s, proto);
if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN))
!= (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) {
@@ -803,12 +822,6 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
return size;
}
- if (size < 64 && !(s->maccr & FTGMAC100_MACCR_RX_RUNT)) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: dropped runt frame of %zd bytes\n",
- __func__, size);
- return size;
- }
-
if (!ftgmac100_filter(s, buf, size)) {
return size;
}
@@ -820,9 +833,9 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
/* Huge frames are truncated. */
if (size > max_frame_size) {
- size = max_frame_size;
qemu_log_mask(LOG_GUEST_ERROR, "%s: frame too big : %zd bytes\n",
__func__, size);
+ size = max_frame_size;
flags |= FTGMAC100_RXDES0_FTL;
}
@@ -861,7 +874,20 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf,
buf_len += size - 4;
}
buf_addr = bd.des3;
- dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ if (first && proto == ETH_P_VLAN && buf_len >= 18) {
+ bd.des1 = lduw_be_p(buf + 14) | FTGMAC100_RXDES1_VLANTAG_AVAIL;
+
+ if (s->maccr & FTGMAC100_MACCR_RM_VLAN) {
+ dma_memory_write(&address_space_memory, buf_addr, buf, 12);
+ dma_memory_write(&address_space_memory, buf_addr + 12, buf + 16,
+ buf_len - 16);
+ } else {
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ }
+ } else {
+ bd.des1 = 0;
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ }
buf += buf_len;
if (size < 4) {
dma_memory_write(&address_space_memory, buf_addr + buf_len,
@@ -940,8 +966,6 @@ static void ftgmac100_realize(DeviceState *dev, Error **errp)
object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- s->frame = g_malloc(FTGMAC100_MAX_FRAME_SIZE);
}
static const VMStateDescription vmstate_ftgmac100 = {