diff options
-rw-r--r-- | hw/net/imx_fec.c | 23 | ||||
-rw-r--r-- | include/hw/net/imx_fec.h | 2 |
2 files changed, 25 insertions, 0 deletions
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6feda18742..825c879a28 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) { diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index a390d704a6..af0840a0fa 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -170,6 +170,8 @@ #define ENET_TWFR_TFWR_LENGTH (6) #define ENET_TWFR_STRFWD (1 << 8) +#define ENET_RACC_SHIFT16 BIT(7) + /* Buffer Descriptor. */ typedef struct { uint16_t length; |