netdev
[Top] [All Lists]

mv643xx(16/20): Limit MTU to 1500 bytes unless connected at GigE speed

To: Netdev <netdev@xxxxxxxxxxx>, Jeff Garzik <jgarzik@xxxxxxxxx>
Subject: mv643xx(16/20): Limit MTU to 1500 bytes unless connected at GigE speed
From: "Dale Farnsworth" <dale@xxxxxxxxxxxxxx>
Date: Mon, 28 Mar 2005 16:57:58 -0700
Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx>, Manish Lachwani <mlachwani@xxxxxxxxxx>, Brian Waite <brian@xxxxxxxxxxxxxx>, "Steven J. Hill" <sjhill@xxxxxxxxxxxxxxxxxx>, Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx>, James Chapman <jchapman@xxxxxxxxxxx>
In-reply-to: <20050328233807.GA28423@xyzzy>
References: <20050328233807.GA28423@xyzzy>
Sender: netdev-bounce@xxxxxxxxxxx
User-agent: Mutt/1.5.6+20040907i
Signed-off-by: Dale Farnsworth <dale@xxxxxxxxxxxxxx>

Index: linux-2.5-enet/drivers/net/mv643xx_eth.c
===================================================================
--- linux-2.5-enet.orig/drivers/net/mv643xx_eth.c
+++ linux-2.5-enet/drivers/net/mv643xx_eth.c
@@ -371,6 +371,7 @@
        struct mv643xx_private *mp = netdev_priv(dev);
        unsigned int port_num = mp->port_num;
        int tx_curr_desc, rx_curr_desc;
+       int rx_buffer_size_index;
 
        /* Assignment of Tx CTRP of given queue */
        tx_curr_desc = mp->tx_curr_desc_q;
@@ -398,14 +399,16 @@
        mv643xx_eth_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
        mv643xx_eth_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), 0);
 
-       /* Increase the Rx side buffer size if supporting GigE */
-       if (mp->port_serial_control & MV643XX_ETH_SET_GMII_SPEED_TO_1000)
-               mv643xx_eth_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
-                                 (mp->port_serial_control & 0xfff1ffff) |
-                                 (0x5 << 17));
+       /* Adjust Rx side buffer size based on mtu */
+       if (dev->mtu <= 1500)
+               rx_buffer_size_index = 1;
        else
-               mv643xx_eth_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
-                                 mp->port_serial_control);
+               rx_buffer_size_index = 5;
+       mp->port_serial_control &= 0xfff1ffff;
+       mp->port_serial_control |= rx_buffer_size_index << 17;
+
+       mv643xx_eth_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
+                         mp->port_serial_control);
 
        mv643xx_eth_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
                          mp->port_serial_control |
@@ -1289,13 +1292,13 @@
                printk(KERN_INFO "%s: TX timeout  ", dev->name);
 
        /* Do the reset outside of interrupt context */
-       schedule_work(&mp->tx_timeout_task);
+       schedule_work(&mp->reset_task);
 }
 
 /*
  * Actual routine to reset the adapter when a timeout on Tx has occurred
  */
-static void mv643xx_eth_tx_timeout_task(struct net_device *dev)
+static void mv643xx_eth_reset_task(struct net_device *dev)
 {
        netif_device_detach(dev);
        mv643xx_eth_port_reset(dev);
@@ -1536,6 +1539,15 @@
                        netif_wake_queue(dev);
                        /* Start TX queue */
                        
mv643xx_eth_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 1);
+                       /* Chip only supports jumbo frames at 1Gb/S */
+                       if (cmd.speed != SPEED_1000 && dev->mtu > 1500) {
+                               dev->mtu = 1500;
+                               mp->port_serial_control &= 0xfff1ffff;
+                               mp->port_serial_control |= 1 << 17;
+
+                               /* Do the reset outside of interrupt context */
+                               schedule_work(&mp->reset_task);
+                       }
 
                } else if (!mii_link_ok(&mp->mii) && netif_carrier_ok(dev)) {
                        netif_stop_queue(dev);
@@ -2220,10 +2232,22 @@
 {
        struct mv643xx_private *mp = netdev_priv(dev);
        unsigned long flags;
+       int max_mtu;
+       u32 port_status;
 
        spin_lock_irqsave(&mp->lock, flags);
 
-       if ((new_mtu > 9500) || (new_mtu < 64)) {
+       /* Jumbo frames are not supported when connected at less than 1Gb/S */
+       port_status =
+               mv643xx_eth_read(MV643XX_ETH_PORT_STATUS_REG(mp->port_num));
+       if ((port_status & (MV643XX_ETH_PORT_STATUS_LINK_UP |
+                           MV643XX_ETH_PORT_STATUS_GMII_1000)) ==
+                          (MV643XX_ETH_PORT_STATUS_LINK_UP))
+               max_mtu = 1500;
+       else
+               max_mtu = 9500;
+
+       if ((new_mtu > max_mtu) || (new_mtu < 64)) {
                spin_unlock_irqrestore(&mp->lock, flags);
                return -EINVAL;
        }
@@ -2517,9 +2541,9 @@
 #endif
 #endif
 
-       /* Configure the timeout task */
-       INIT_WORK(&mp->tx_timeout_task,
-                 (void (*)(void *))mv643xx_eth_tx_timeout_task, dev);
+       /* Configure the reset task */
+       INIT_WORK(&mp->reset_task,
+                 (void (*)(void *))mv643xx_eth_reset_task, dev);
 
        spin_lock_init(&mp->lock);
 
Index: linux-2.5-enet/drivers/net/mv643xx_eth.h
===================================================================
--- linux-2.5-enet.orig/drivers/net/mv643xx_eth.h
+++ linux-2.5-enet/drivers/net/mv643xx_eth.h
@@ -512,7 +512,7 @@
        unsigned int tx_desc_area_size;
        struct sk_buff **tx_skb;
 
-       struct work_struct tx_timeout_task;
+       struct work_struct reset_task;
 
        /*
         * Former struct mv643xx_eth_priv members start here

<Prev in Thread] Current Thread [Next in Thread>