]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/ethernet/cadence/macb_main.c
net: macb: Limit maximum GEM TX length in TSO
[linux.git] / drivers / net / ethernet / cadence / macb_main.c
index f7d87c71aaa9c399ccb462ae377a2e5c8b42db10..4508f0d150da95d8e838d0ead806e8ef74794cc5 100644 (file)
@@ -73,7 +73,11 @@ struct sifive_fu540_macb_mgmt {
 /* Max length of transmit frame must be a multiple of 8 bytes */
 #define MACB_TX_LEN_ALIGN      8
 #define MACB_MAX_TX_LEN                ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1)))
-#define GEM_MAX_TX_LEN         ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1)))
+/* Limit maximum TX length as per Cadence TSO errata. This is to avoid a
+ * false amba_error in TX path from the DMA assuming there is not enough
+ * space in the SRAM (16KB) even when there is.
+ */
+#define GEM_MAX_TX_LEN         (unsigned int)(0x3FC0)
 
 #define GEM_MTU_MIN_SIZE       ETH_MIN_MTU
 #define MACB_NETIF_LSO         NETIF_F_TSO
@@ -337,11 +341,30 @@ static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        if (status < 0)
                goto mdio_read_exit;
 
-       macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-                             | MACB_BF(RW, MACB_MAN_READ)
-                             | MACB_BF(PHYA, mii_id)
-                             | MACB_BF(REGA, regnum)
-                             | MACB_BF(CODE, MACB_MAN_CODE)));
+       if (regnum & MII_ADDR_C45) {
+               macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
+                           | MACB_BF(RW, MACB_MAN_C45_ADDR)
+                           | MACB_BF(PHYA, mii_id)
+                           | MACB_BF(REGA, (regnum >> 16) & 0x1F)
+                           | MACB_BF(DATA, regnum & 0xFFFF)
+                           | MACB_BF(CODE, MACB_MAN_C45_CODE)));
+
+               status = macb_mdio_wait_for_idle(bp);
+               if (status < 0)
+                       goto mdio_read_exit;
+
+               macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
+                           | MACB_BF(RW, MACB_MAN_C45_READ)
+                           | MACB_BF(PHYA, mii_id)
+                           | MACB_BF(REGA, (regnum >> 16) & 0x1F)
+                           | MACB_BF(CODE, MACB_MAN_C45_CODE)));
+       } else {
+               macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF)
+                               | MACB_BF(RW, MACB_MAN_C22_READ)
+                               | MACB_BF(PHYA, mii_id)
+                               | MACB_BF(REGA, regnum)
+                               | MACB_BF(CODE, MACB_MAN_C22_CODE)));
+       }
 
        status = macb_mdio_wait_for_idle(bp);
        if (status < 0)
@@ -370,12 +393,32 @@ static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        if (status < 0)
                goto mdio_write_exit;
 
-       macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
-                             | MACB_BF(RW, MACB_MAN_WRITE)
-                             | MACB_BF(PHYA, mii_id)
-                             | MACB_BF(REGA, regnum)
-                             | MACB_BF(CODE, MACB_MAN_CODE)
-                             | MACB_BF(DATA, value)));
+       if (regnum & MII_ADDR_C45) {
+               macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
+                           | MACB_BF(RW, MACB_MAN_C45_ADDR)
+                           | MACB_BF(PHYA, mii_id)
+                           | MACB_BF(REGA, (regnum >> 16) & 0x1F)
+                           | MACB_BF(DATA, regnum & 0xFFFF)
+                           | MACB_BF(CODE, MACB_MAN_C45_CODE)));
+
+               status = macb_mdio_wait_for_idle(bp);
+               if (status < 0)
+                       goto mdio_write_exit;
+
+               macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
+                           | MACB_BF(RW, MACB_MAN_C45_WRITE)
+                           | MACB_BF(PHYA, mii_id)
+                           | MACB_BF(REGA, (regnum >> 16) & 0x1F)
+                           | MACB_BF(CODE, MACB_MAN_C45_CODE)
+                           | MACB_BF(DATA, value)));
+       } else {
+               macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF)
+                               | MACB_BF(RW, MACB_MAN_C22_WRITE)
+                               | MACB_BF(PHYA, mii_id)
+                               | MACB_BF(REGA, regnum)
+                               | MACB_BF(CODE, MACB_MAN_C22_CODE)
+                               | MACB_BF(DATA, value)));
+       }
 
        status = macb_mdio_wait_for_idle(bp);
        if (status < 0)
@@ -1752,16 +1795,14 @@ static netdev_features_t macb_features_check(struct sk_buff *skb,
 
        /* Validate LSO compatibility */
 
-       /* there is only one buffer */
-       if (!skb_is_nonlinear(skb))
+       /* there is only one buffer or protocol is not UDP */
+       if (!skb_is_nonlinear(skb) || (ip_hdr(skb)->protocol != IPPROTO_UDP))
                return features;
 
        /* length of header */
        hdrlen = skb_transport_offset(skb);
-       if (ip_hdr(skb)->protocol == IPPROTO_TCP)
-               hdrlen += tcp_hdrlen(skb);
 
-       /* For LSO:
+       /* For UFO only:
         * When software supplies two or more payload buffers all payload buffers
         * apart from the last must be a multiple of 8 bytes in size.
         */