]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Add skge fix from shemminger
authorChris Wright <chrisw@sous-sol.org>
Thu, 5 Jan 2006 02:45:16 +0000 (18:45 -0800)
committerChris Wright <chrisw@sous-sol.org>
Thu, 5 Jan 2006 02:45:16 +0000 (18:45 -0800)
queue/series
queue/skge-handle-out-of-memory-on-ring-changes.patch [new file with mode: 0644]

index c549f09336947de4c76aa9909ac3e81347e32779..29f1414a949836c3830020f55b5af535578bc2f2 100644 (file)
@@ -1,3 +1,4 @@
 bridge-fix-faulty-check-in-br_stp_recalculate_bridge_id.patch
 ufs-inode-i_sem-is-not-released-in-error-path.patch
 acpi-fix-asus_acpi-on-samsung-p30-p35.patch
+skge-handle-out-of-memory-on-ring-changes.patch
diff --git a/queue/skge-handle-out-of-memory-on-ring-changes.patch b/queue/skge-handle-out-of-memory-on-ring-changes.patch
new file mode 100644 (file)
index 0000000..da80d24
--- /dev/null
@@ -0,0 +1,224 @@
+From stable-bounces@linux.kernel.org  Wed Jan  4 15:55:59 2006
+Date: Wed, 4 Jan 2006 15:52:28 -0800
+From: Stephen Hemminger <shemminger@osdl.org>
+To: stable@kernel.org
+Message-ID: <20060104155228.014d6326@dxpl.pdx.osdl.net>
+Subject: [PATCH] skge: handle out of memory on ring changes
+
+Please consider this for 2.6.15.1; it fixes several cases where
+the skge driver can get in a bad state and later crash; if an
+admin operation that causes a restart fails from out of memory.
+Such as changing the MTU or increasing the ring size.
+
+The fixes involve checking the return value and doing necessary
+unwinds. Or in some cases avoiding doing a full restart.
+
+The same code is the netdev-2.6 tree for 2.6.16 but as separate pieces
+
+Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+
+
+ drivers/net/skge.c |   80 +++++++++++++++++++++++++++++++----------------------
+ 1 files changed, 48 insertions(+), 32 deletions(-)
+
+Index: linux-2.6.15.y/drivers/net/skge.c
+===================================================================
+--- linux-2.6.15.y.orig/drivers/net/skge.c
++++ linux-2.6.15.y/drivers/net/skge.c
+@@ -43,7 +43,7 @@
+ #include "skge.h"
+ #define DRV_NAME              "skge"
+-#define DRV_VERSION           "1.2"
++#define DRV_VERSION           "1.3"
+ #define PFX                   DRV_NAME " "
+ #define DEFAULT_TX_RING_SIZE  128
+@@ -88,15 +88,14 @@ MODULE_DEVICE_TABLE(pci, skge_id_table);
+ static int skge_up(struct net_device *dev);
+ static int skge_down(struct net_device *dev);
++static void skge_phy_reset(struct skge_port *skge);
+ static void skge_tx_clean(struct skge_port *skge);
+ static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+ static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+ static void genesis_get_stats(struct skge_port *skge, u64 *data);
+ static void yukon_get_stats(struct skge_port *skge, u64 *data);
+ static void yukon_init(struct skge_hw *hw, int port);
+-static void yukon_reset(struct skge_hw *hw, int port);
+ static void genesis_mac_init(struct skge_hw *hw, int port);
+-static void genesis_reset(struct skge_hw *hw, int port);
+ static void genesis_link_up(struct skge_port *skge);
+ /* Avoid conditionals by using array */
+@@ -276,10 +275,9 @@ static int skge_set_settings(struct net_
+       skge->autoneg = ecmd->autoneg;
+       skge->advertising = ecmd->advertising;
+-      if (netif_running(dev)) {
+-              skge_down(dev);
+-              skge_up(dev);
+-      }
++      if (netif_running(dev))
++              skge_phy_reset(skge);
++
+       return (0);
+ }
+@@ -399,6 +397,7 @@ static int skge_set_ring_param(struct ne
+                              struct ethtool_ringparam *p)
+ {
+       struct skge_port *skge = netdev_priv(dev);
++      int err;
+       if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE ||
+           p->tx_pending == 0 || p->tx_pending > MAX_TX_RING_SIZE)
+@@ -409,7 +408,11 @@ static int skge_set_ring_param(struct ne
+       if (netif_running(dev)) {
+               skge_down(dev);
+-              skge_up(dev);
++              err = skge_up(dev);
++              if (err)
++                      dev_close(dev);
++              else
++                      dev->set_multicast_list(dev);
+       }
+       return 0;
+@@ -430,21 +433,11 @@ static void skge_set_msglevel(struct net
+ static int skge_nway_reset(struct net_device *dev)
+ {
+       struct skge_port *skge = netdev_priv(dev);
+-      struct skge_hw *hw = skge->hw;
+-      int port = skge->port;
+       if (skge->autoneg != AUTONEG_ENABLE || !netif_running(dev))
+               return -EINVAL;
+-      spin_lock_bh(&hw->phy_lock);
+-      if (hw->chip_id == CHIP_ID_GENESIS) {
+-              genesis_reset(hw, port);
+-              genesis_mac_init(hw, port);
+-      } else {
+-              yukon_reset(hw, port);
+-              yukon_init(hw, port);
+-      }
+-      spin_unlock_bh(&hw->phy_lock);
++      skge_phy_reset(skge);
+       return 0;
+ }
+@@ -516,10 +509,8 @@ static int skge_set_pauseparam(struct ne
+       else
+               skge->flow_control = FLOW_MODE_NONE;
+-      if (netif_running(dev)) {
+-              skge_down(dev);
+-              skge_up(dev);
+-      }
++      if (netif_running(dev))
++              skge_phy_reset(skge);
+       return 0;
+ }
+@@ -1935,7 +1926,6 @@ static void yukon_link_down(struct skge_
+       }
+-      yukon_reset(hw, port);
+       skge_link_down(skge);
+       yukon_init(hw, port);
+@@ -2019,6 +2009,22 @@ static void yukon_phy_intr(struct skge_p
+       /* XXX restart autonegotiation? */
+ }
++static void skge_phy_reset(struct skge_port *skge)
++{
++      struct skge_hw *hw = skge->hw;
++      int port = skge->port;
++
++      netif_stop_queue(skge->netdev);
++      netif_carrier_off(skge->netdev);
++
++      spin_lock_bh(&hw->phy_lock);
++      if (hw->chip_id == CHIP_ID_GENESIS)
++              genesis_mac_init(hw, port);
++      else
++              yukon_init(hw, port);
++      spin_unlock_bh(&hw->phy_lock);
++}
++
+ /* Basic MII support */
+ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+@@ -2187,6 +2193,7 @@ static int skge_up(struct net_device *de
+       kfree(skge->rx_ring.start);
+  free_pci_mem:
+       pci_free_consistent(hw->pdev, skge->mem_size, skge->mem, skge->dma);
++      skge->mem = NULL;
+       return err;
+ }
+@@ -2197,6 +2204,9 @@ static int skge_down(struct net_device *
+       struct skge_hw *hw = skge->hw;
+       int port = skge->port;
++      if (skge->mem == NULL)
++              return 0;
++
+       if (netif_msg_ifdown(skge))
+               printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
+@@ -2253,6 +2263,7 @@ static int skge_down(struct net_device *
+       kfree(skge->rx_ring.start);
+       kfree(skge->tx_ring.start);
+       pci_free_consistent(hw->pdev, skge->mem_size, skge->mem, skge->dma);
++      skge->mem = NULL;
+       return 0;
+ }
+@@ -2413,18 +2424,23 @@ static void skge_tx_timeout(struct net_d
+ static int skge_change_mtu(struct net_device *dev, int new_mtu)
+ {
+-      int err = 0;
+-      int running = netif_running(dev);
++      int err;
+       if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
+               return -EINVAL;
++      if (!netif_running(dev)) {
++              dev->mtu = new_mtu;
++              return 0;
++      }
++
++      skge_down(dev);
+-      if (running)
+-              skge_down(dev);
+       dev->mtu = new_mtu;
+-      if (running)
+-              skge_up(dev);
++
++      err = skge_up(dev);
++      if (err)
++              dev_close(dev);
+       return err;
+ }
+@@ -3398,8 +3414,8 @@ static int skge_resume(struct pci_dev *p
+               struct net_device *dev = hw->dev[i];
+               if (dev) {
+                       netif_device_attach(dev);
+-                      if (netif_running(dev))
+-                              skge_up(dev);
++                      if (netif_running(dev) && skge_up(dev))
++                              dev_close(dev);
+               }
+       }
+       return 0;