]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.drivers/igp-fix-ring-on-suspend.patch
Move xen patchset to new version's subdir.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / igp-fix-ring-on-suspend.patch
diff --git a/src/patches/suse-2.6.27.31/patches.drivers/igp-fix-ring-on-suspend.patch b/src/patches/suse-2.6.27.31/patches.drivers/igp-fix-ring-on-suspend.patch
new file mode 100644 (file)
index 0000000..97163ce
--- /dev/null
@@ -0,0 +1,261 @@
+Subject: Fix tx/rx_ring_count parameters for igb on suspend/resume/ring resize
+Patch-mainline: 2.6.29-rc3
+References: bnc#465049
+From: Alexander Duyck <alexander.h.duyck@intel.com>
+
+When suspending the device the ring structure is freed which causes it to
+loose track of the count.  To resolve this we need to move the ring count
+outside of the ring structure and store it in the adapter struct.
+
+In addition to resolving the suspend/resume issue this patch also addresses
+issues seen in the event of memory allocation errors causing uneven ring
+sizes on multiple queues.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
+Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Pavel Machek <pavel@suse.cz>
+
+
+
+---
+ drivers/net/igb/igb.h         |    4 +
+ drivers/net/igb/igb_ethtool.c |  102 ++++++++++++++++++++----------------------
+ drivers/net/igb/igb_main.c    |   10 ++--
+ 3 files changed, 59 insertions(+), 57 deletions(-)
+
+--- a/drivers/net/igb/igb_ethtool.c
++++ b/drivers/net/igb/igb_ethtool.c
+@@ -714,15 +714,13 @@ static void igb_get_ringparam(struct net
+                             struct ethtool_ringparam *ring)
+ {
+       struct igb_adapter *adapter = netdev_priv(netdev);
+-      struct igb_ring *tx_ring = adapter->tx_ring;
+-      struct igb_ring *rx_ring = adapter->rx_ring;
+       ring->rx_max_pending = IGB_MAX_RXD;
+       ring->tx_max_pending = IGB_MAX_TXD;
+       ring->rx_mini_max_pending = 0;
+       ring->rx_jumbo_max_pending = 0;
+-      ring->rx_pending = rx_ring->count;
+-      ring->tx_pending = tx_ring->count;
++      ring->rx_pending = adapter->rx_ring_count;
++      ring->tx_pending = adapter->tx_ring_count;
+       ring->rx_mini_pending = 0;
+       ring->rx_jumbo_pending = 0;
+ }
+@@ -731,12 +729,9 @@ static int igb_set_ringparam(struct net_
+                            struct ethtool_ringparam *ring)
+ {
+       struct igb_adapter *adapter = netdev_priv(netdev);
+-      struct igb_buffer *old_buf;
+-      struct igb_buffer *old_rx_buf;
+-      void *old_desc;
++      struct igb_ring *temp_ring;
+       int i, err;
+-      u32 new_rx_count, new_tx_count, old_size;
+-      dma_addr_t old_dma;
++      u32 new_rx_count, new_tx_count;
+       if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+               return -EINVAL;
+@@ -749,12 +744,19 @@ static int igb_set_ringparam(struct net_
+       new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD);
+       new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
+-      if ((new_tx_count == adapter->tx_ring->count) &&
+-          (new_rx_count == adapter->rx_ring->count)) {
++      if ((new_tx_count == adapter->tx_ring_count) &&
++          (new_rx_count == adapter->rx_ring_count)) {
+               /* nothing to do */
+               return 0;
+       }
++      if (adapter->num_tx_queues > adapter->num_rx_queues)
++              temp_ring = vmalloc(adapter->num_tx_queues * sizeof(struct igb_ring));
++      else
++              temp_ring = vmalloc(adapter->num_rx_queues * sizeof(struct igb_ring));
++      if (!temp_ring)
++              return -ENOMEM;
++
+       while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+               msleep(1);
+@@ -766,62 +768,55 @@ static int igb_set_ringparam(struct net_
+        * because the ISRs in MSI-X mode get passed pointers
+        * to the tx and rx ring structs.
+        */
+-      if (new_tx_count != adapter->tx_ring->count) {
++      if (new_tx_count != adapter->tx_ring_count) {
++              memcpy(temp_ring, adapter->tx_ring,
++                     adapter->num_tx_queues * sizeof(struct igb_ring));
++
+               for (i = 0; i < adapter->num_tx_queues; i++) {
+-                      /* Save existing descriptor ring */
+-                      old_buf = adapter->tx_ring[i].buffer_info;
+-                      old_desc = adapter->tx_ring[i].desc;
+-                      old_size = adapter->tx_ring[i].size;
+-                      old_dma = adapter->tx_ring[i].dma;
+-                      /* Try to allocate a new one */
+-                      adapter->tx_ring[i].buffer_info = NULL;
+-                      adapter->tx_ring[i].desc = NULL;
+-                      adapter->tx_ring[i].count = new_tx_count;
+-                      err = igb_setup_tx_resources(adapter,
+-                                              &adapter->tx_ring[i]);
++                      temp_ring[i].count = new_tx_count;
++                      err = igb_setup_tx_resources(adapter, &temp_ring[i]);
+                       if (err) {
+-                              /* Restore the old one so at least
+-                                 the adapter still works, even if
+-                                 we failed the request */
+-                              adapter->tx_ring[i].buffer_info = old_buf;
+-                              adapter->tx_ring[i].desc = old_desc;
+-                              adapter->tx_ring[i].size = old_size;
+-                              adapter->tx_ring[i].dma = old_dma;
++                              while (i) {
++                                      i--;
++                                      igb_free_tx_resources(&temp_ring[i]);
++                              }
+                               goto err_setup;
+                       }
+-                      /* Free the old buffer manually */
+-                      vfree(old_buf);
+-                      pci_free_consistent(adapter->pdev, old_size,
+-                                          old_desc, old_dma);
+               }
++
++              for (i = 0; i < adapter->num_tx_queues; i++)
++                      igb_free_tx_resources(&adapter->tx_ring[i]);
++
++              memcpy(adapter->tx_ring, temp_ring,
++                     adapter->num_tx_queues * sizeof(struct igb_ring));
++
++              adapter->tx_ring_count = new_tx_count;
+       }
+       if (new_rx_count != adapter->rx_ring->count) {
+-              for (i = 0; i < adapter->num_rx_queues; i++) {
++              memcpy(temp_ring, adapter->rx_ring,
++                     adapter->num_rx_queues * sizeof(struct igb_ring));
+-                      old_rx_buf = adapter->rx_ring[i].buffer_info;
+-                      old_desc = adapter->rx_ring[i].desc;
+-                      old_size = adapter->rx_ring[i].size;
+-                      old_dma = adapter->rx_ring[i].dma;
+-
+-                      adapter->rx_ring[i].buffer_info = NULL;
+-                      adapter->rx_ring[i].desc = NULL;
+-                      adapter->rx_ring[i].dma = 0;
+-                      adapter->rx_ring[i].count = new_rx_count;
+-                      err = igb_setup_rx_resources(adapter,
+-                                                   &adapter->rx_ring[i]);
++              for (i = 0; i < adapter->num_rx_queues; i++) {
++                      temp_ring[i].count = new_rx_count;
++                      err = igb_setup_rx_resources(adapter, &temp_ring[i]);
+                       if (err) {
+-                              adapter->rx_ring[i].buffer_info = old_rx_buf;
+-                              adapter->rx_ring[i].desc = old_desc;
+-                              adapter->rx_ring[i].size = old_size;
+-                              adapter->rx_ring[i].dma = old_dma;
++                              while (i) {
++                                      i--;
++                                      igb_free_rx_resources(&temp_ring[i]);
++                              }
+                               goto err_setup;
+                       }
+-                      vfree(old_rx_buf);
+-                      pci_free_consistent(adapter->pdev, old_size, old_desc,
+-                                          old_dma);
+               }
++
++              for (i = 0; i < adapter->num_rx_queues; i++)
++                      igb_free_rx_resources(&adapter->rx_ring[i]);
++
++              memcpy(adapter->rx_ring, temp_ring,
++                     adapter->num_rx_queues * sizeof(struct igb_ring));
++
++              adapter->rx_ring_count = new_rx_count;
+       }
+       err = 0;
+@@ -830,6 +825,7 @@ err_setup:
+               igb_up(adapter);
+       clear_bit(__IGB_RESETTING, &adapter->state);
++      vfree(temp_ring);
+       return err;
+ }
+--- a/drivers/net/igb/igb.h
++++ b/drivers/net/igb/igb.h
+@@ -294,6 +294,8 @@ struct igb_adapter {
+       unsigned int lro_flushed;
+       unsigned int lro_no_desc;
+ #endif
++      unsigned int tx_ring_count;
++      unsigned int rx_ring_count;
+ };
+ #define IGB_FLAG_HAS_MSI           (1 << 0)
+@@ -325,6 +327,8 @@ extern void igb_reset(struct igb_adapter
+ extern int igb_set_spd_dplx(struct igb_adapter *, u16);
+ extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *);
+ extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *);
++extern void igb_free_tx_resources(struct igb_ring *);
++extern void igb_free_rx_resources(struct igb_ring *);
+ extern void igb_update_stats(struct igb_adapter *);
+ extern void igb_set_ethtool_ops(struct net_device *);
+--- a/drivers/net/igb/igb_main.c
++++ b/drivers/net/igb/igb_main.c
+@@ -75,8 +75,6 @@ static int igb_setup_all_tx_resources(st
+ static int igb_setup_all_rx_resources(struct igb_adapter *);
+ static void igb_free_all_tx_resources(struct igb_adapter *);
+ static void igb_free_all_rx_resources(struct igb_adapter *);
+-static void igb_free_tx_resources(struct igb_ring *);
+-static void igb_free_rx_resources(struct igb_ring *);
+ void igb_update_stats(struct igb_adapter *);
+ static int igb_probe(struct pci_dev *, const struct pci_device_id *);
+ static void __devexit igb_remove(struct pci_dev *pdev);
+@@ -258,11 +256,13 @@ static int igb_alloc_queues(struct igb_a
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               struct igb_ring *ring = &(adapter->tx_ring[i]);
++              ring->count = adapter->tx_ring_count;
+               ring->adapter = adapter;
+               ring->queue_index = i;
+       }
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               struct igb_ring *ring = &(adapter->rx_ring[i]);
++              ring->count = adapter->rx_ring_count;
+               ring->adapter = adapter;
+               ring->queue_index = i;
+               ring->itr_register = E1000_ITR;
+@@ -1374,6 +1374,8 @@ static int __devinit igb_sw_init(struct 
+       pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
++      adapter->tx_ring_count = IGB_DEFAULT_TXD;
++      adapter->rx_ring_count = IGB_DEFAULT_RXD;
+       adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+       adapter->rx_ps_hdr_size = 0; /* disable packet split */
+       adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+@@ -1962,7 +1964,7 @@ static void igb_configure_rx(struct igb_
+  *
+  * Free all transmit software resources
+  **/
+-static void igb_free_tx_resources(struct igb_ring *tx_ring)
++void igb_free_tx_resources(struct igb_ring *tx_ring)
+ {
+       struct pci_dev *pdev = tx_ring->adapter->pdev;
+@@ -2062,7 +2064,7 @@ static void igb_clean_all_tx_rings(struc
+  *
+  * Free all receive software resources
+  **/
+-static void igb_free_rx_resources(struct igb_ring *rx_ring)
++void igb_free_rx_resources(struct igb_ring *rx_ring)
+ {
+       struct pci_dev *pdev = rx_ring->adapter->pdev;