]> Git Repo - qemu.git/commitdiff
imx_fec: Emulate SHIFT16 in ENETx_RACC
authorAndrey Smirnov <[email protected]>
Thu, 11 Jan 2018 13:25:37 +0000 (13:25 +0000)
committerPeter Maydell <[email protected]>
Thu, 11 Jan 2018 13:25:37 +0000 (13:25 +0000)
Needed to support latest Linux kernel driver which relies on that
functionality.

Cc: Peter Maydell <[email protected]>
Cc: Jason Wang <[email protected]>
Cc: Philippe Mathieu-Daudé <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Reviewed-by: Peter Maydell <[email protected]>
Signed-off-by: Andrey Smirnov <[email protected]>
Signed-off-by: Peter Maydell <[email protected]>
hw/net/imx_fec.c
include/hw/net/imx_fec.h

index 6feda18742d7a92fa9b6a3358067c8f3892a65c3..825c879a28de002427a3b3b54a2c8b63091a8335 100644 (file)
@@ -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) {
index a390d704a61265cb7b7afb7371c2c90562abfaae..af0840a0fa5f3a1a49f37b5082332567555bbccb 100644 (file)
 #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;
This page took 0.030402 seconds and 4 git commands to generate.