]> git.itanic.dy.fi Git - linux-stable/commitdiff
net: ixp4xx_eth: Support changing the MTU
authorLinus Walleij <linus.walleij@linaro.org>
Wed, 4 Oct 2023 22:43:53 +0000 (00:43 +0200)
committerJakub Kicinski <kuba@kernel.org>
Fri, 6 Oct 2023 22:52:08 +0000 (15:52 -0700)
As we don't specify the MTU in the driver, the framework
will fall back to 1500 bytes and this doesn't work very
well when we try to attach a DSA switch:

  eth1: mtu greater than device maximum
  ixp4xx_eth c800a000.ethernet eth1: error -22 setting
  MTU to 1504 to include DSA overhead

After locating an out-of-tree patch in OpenWrt I found
suitable code to set the MTU on the interface and ported
it and updated it. Now the MTU gets set properly.

Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20231005-ixp4xx-eth-mtu-v4-1-08c66ed0bc69@linaro.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/xscale/ixp4xx_eth.c

index 5c2fd2852e32b60de7aa78064d80f3c88fe2a8e3..c47108f2a0a01f903913f8e9f12a1e3e5ead657b 100644 (file)
 
 #define POOL_ALLOC_SIZE                (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
 #define REGS_SIZE              0x1000
-#define MAX_MRU                        1536 /* 0x600 */
+
+/* MRU is said to be 14320 in a code dump, the SW manual says that
+ * MRU/MTU is 16320 and includes VLAN and ethernet headers.
+ * See "IXP400 Software Programmer's Guide" section 10.3.2, page 161.
+ *
+ * FIXME: we have chosen the safe default (14320) but if you can test
+ * jumboframes, experiment with 16320 and see what happens!
+ */
+#define MAX_MRU                        (14320 - VLAN_ETH_HLEN)
 #define RX_BUFF_SIZE           ALIGN((NET_IP_ALIGN) + MAX_MRU, 4)
 
 #define NAPI_WEIGHT            16
@@ -1183,6 +1191,54 @@ static void destroy_queues(struct port *port)
        }
 }
 
+static int ixp4xx_do_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct port *port = netdev_priv(dev);
+       struct npe *npe = port->npe;
+       int framesize, chunks;
+       struct msg msg = {};
+
+       /* adjust for ethernet headers */
+       framesize = new_mtu + VLAN_ETH_HLEN;
+       /* max rx/tx 64 byte chunks */
+       chunks = DIV_ROUND_UP(framesize, 64);
+
+       msg.cmd = NPE_SETMAXFRAMELENGTHS;
+       msg.eth_id = port->id;
+
+       /* Firmware wants to know buffer size in 64 byte chunks */
+       msg.byte2 = chunks << 8;
+       msg.byte3 = chunks << 8;
+
+       msg.byte4 = msg.byte6 = framesize >> 8;
+       msg.byte5 = msg.byte7 = framesize & 0xff;
+
+       if (npe_send_recv_message(npe, &msg, "ETH_SET_MAX_FRAME_LENGTH"))
+               return -EIO;
+       netdev_dbg(dev, "set MTU on NPE %s to %d bytes\n",
+                  npe_name(npe), new_mtu);
+
+       return 0;
+}
+
+static int ixp4xx_eth_change_mtu(struct net_device *dev, int new_mtu)
+{
+       int ret;
+
+       /* MTU can only be changed when the interface is up. We also
+        * set the MTU from dev->mtu when opening the device.
+        */
+       if (dev->flags & IFF_UP) {
+               ret = ixp4xx_do_change_mtu(dev, new_mtu);
+               if (ret < 0)
+                       return ret;
+       }
+
+       dev->mtu = new_mtu;
+
+       return 0;
+}
+
 static int eth_open(struct net_device *dev)
 {
        struct port *port = netdev_priv(dev);
@@ -1233,6 +1289,8 @@ static int eth_open(struct net_device *dev)
        if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE"))
                return -EIO;
 
+       ixp4xx_do_change_mtu(dev, dev->mtu);
+
        if ((err = request_queues(port)) != 0)
                return err;
 
@@ -1375,6 +1433,7 @@ static int eth_close(struct net_device *dev)
 static const struct net_device_ops ixp4xx_netdev_ops = {
        .ndo_open = eth_open,
        .ndo_stop = eth_close,
+       .ndo_change_mtu = ixp4xx_eth_change_mtu,
        .ndo_start_xmit = eth_xmit,
        .ndo_set_rx_mode = eth_set_mcast_list,
        .ndo_eth_ioctl = eth_ioctl,
@@ -1489,12 +1548,8 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
        ndev->dev.dma_mask = dev->dma_mask;
        ndev->dev.coherent_dma_mask = dev->coherent_dma_mask;
 
-       /* Maximum frame size is 16320 bytes and includes VLAN and
-        * ethernet headers. See "IXP400 Software Programmer's Guide"
-        * section 10.3.2, page 161.
-        */
        ndev->min_mtu = ETH_MIN_MTU;
-       ndev->max_mtu = 16320 - VLAN_ETH_HLEN;
+       ndev->max_mtu = MAX_MRU;
 
        netif_napi_add_weight(ndev, &port->napi, eth_poll, NAPI_WEIGHT);