Commit 68fd9910 authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller

igb: Fix tx/rx_ring_count parameters for igb on suspend/resume/ring resize

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: default avatarAlexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b2d56536
...@@ -294,6 +294,8 @@ struct igb_adapter { ...@@ -294,6 +294,8 @@ struct igb_adapter {
unsigned int lro_flushed; unsigned int lro_flushed;
unsigned int lro_no_desc; unsigned int lro_no_desc;
#endif #endif
unsigned int tx_ring_count;
unsigned int rx_ring_count;
}; };
#define IGB_FLAG_HAS_MSI (1 << 0) #define IGB_FLAG_HAS_MSI (1 << 0)
...@@ -325,6 +327,8 @@ extern void igb_reset(struct igb_adapter *); ...@@ -325,6 +327,8 @@ extern void igb_reset(struct igb_adapter *);
extern int igb_set_spd_dplx(struct igb_adapter *, u16); 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_tx_resources(struct igb_adapter *, struct igb_ring *);
extern int igb_setup_rx_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_update_stats(struct igb_adapter *);
extern void igb_set_ethtool_ops(struct net_device *); extern void igb_set_ethtool_ops(struct net_device *);
......
...@@ -714,15 +714,13 @@ static void igb_get_ringparam(struct net_device *netdev, ...@@ -714,15 +714,13 @@ static void igb_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring) struct ethtool_ringparam *ring)
{ {
struct igb_adapter *adapter = netdev_priv(netdev); 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->rx_max_pending = IGB_MAX_RXD;
ring->tx_max_pending = IGB_MAX_TXD; ring->tx_max_pending = IGB_MAX_TXD;
ring->rx_mini_max_pending = 0; ring->rx_mini_max_pending = 0;
ring->rx_jumbo_max_pending = 0; ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rx_ring->count; ring->rx_pending = adapter->rx_ring_count;
ring->tx_pending = tx_ring->count; ring->tx_pending = adapter->tx_ring_count;
ring->rx_mini_pending = 0; ring->rx_mini_pending = 0;
ring->rx_jumbo_pending = 0; ring->rx_jumbo_pending = 0;
} }
...@@ -731,12 +729,9 @@ static int igb_set_ringparam(struct net_device *netdev, ...@@ -731,12 +729,9 @@ static int igb_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring) struct ethtool_ringparam *ring)
{ {
struct igb_adapter *adapter = netdev_priv(netdev); struct igb_adapter *adapter = netdev_priv(netdev);
struct igb_buffer *old_buf; struct igb_ring *temp_ring;
struct igb_buffer *old_rx_buf;
void *old_desc;
int i, err; int i, err;
u32 new_rx_count, new_tx_count, old_size; u32 new_rx_count, new_tx_count;
dma_addr_t old_dma;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL; return -EINVAL;
...@@ -749,12 +744,19 @@ static int igb_set_ringparam(struct net_device *netdev, ...@@ -749,12 +744,19 @@ static int igb_set_ringparam(struct net_device *netdev,
new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD); new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD);
new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
if ((new_tx_count == adapter->tx_ring->count) && if ((new_tx_count == adapter->tx_ring_count) &&
(new_rx_count == adapter->rx_ring->count)) { (new_rx_count == adapter->rx_ring_count)) {
/* nothing to do */ /* nothing to do */
return 0; 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)) while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
msleep(1); msleep(1);
...@@ -766,62 +768,55 @@ static int igb_set_ringparam(struct net_device *netdev, ...@@ -766,62 +768,55 @@ static int igb_set_ringparam(struct net_device *netdev,
* because the ISRs in MSI-X mode get passed pointers * because the ISRs in MSI-X mode get passed pointers
* to the tx and rx ring structs. * 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++) { for (i = 0; i < adapter->num_tx_queues; i++) {
/* Save existing descriptor ring */ temp_ring[i].count = new_tx_count;
old_buf = adapter->tx_ring[i].buffer_info; err = igb_setup_tx_resources(adapter, &temp_ring[i]);
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]);
if (err) { if (err) {
/* Restore the old one so at least while (i) {
the adapter still works, even if i--;
we failed the request */ igb_free_tx_resources(&temp_ring[i]);
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;
goto err_setup; 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) { 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; for (i = 0; i < adapter->num_rx_queues; i++) {
old_desc = adapter->rx_ring[i].desc; temp_ring[i].count = new_rx_count;
old_size = adapter->rx_ring[i].size; err = igb_setup_rx_resources(adapter, &temp_ring[i]);
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]);
if (err) { if (err) {
adapter->rx_ring[i].buffer_info = old_rx_buf; while (i) {
adapter->rx_ring[i].desc = old_desc; i--;
adapter->rx_ring[i].size = old_size; igb_free_rx_resources(&temp_ring[i]);
adapter->rx_ring[i].dma = old_dma; }
goto err_setup; 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; err = 0;
...@@ -830,6 +825,7 @@ static int igb_set_ringparam(struct net_device *netdev, ...@@ -830,6 +825,7 @@ static int igb_set_ringparam(struct net_device *netdev,
igb_up(adapter); igb_up(adapter);
clear_bit(__IGB_RESETTING, &adapter->state); clear_bit(__IGB_RESETTING, &adapter->state);
vfree(temp_ring);
return err; return err;
} }
......
...@@ -76,8 +76,6 @@ static int igb_setup_all_tx_resources(struct igb_adapter *); ...@@ -76,8 +76,6 @@ static int igb_setup_all_tx_resources(struct igb_adapter *);
static int igb_setup_all_rx_resources(struct igb_adapter *); 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_tx_resources(struct igb_adapter *);
static void igb_free_all_rx_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 *); void igb_update_stats(struct igb_adapter *);
static int igb_probe(struct pci_dev *, const struct pci_device_id *); static int igb_probe(struct pci_dev *, const struct pci_device_id *);
static void __devexit igb_remove(struct pci_dev *pdev); static void __devexit igb_remove(struct pci_dev *pdev);
...@@ -259,11 +257,13 @@ static int igb_alloc_queues(struct igb_adapter *adapter) ...@@ -259,11 +257,13 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
for (i = 0; i < adapter->num_tx_queues; i++) { for (i = 0; i < adapter->num_tx_queues; i++) {
struct igb_ring *ring = &(adapter->tx_ring[i]); struct igb_ring *ring = &(adapter->tx_ring[i]);
ring->count = adapter->tx_ring_count;
ring->adapter = adapter; ring->adapter = adapter;
ring->queue_index = i; ring->queue_index = i;
} }
for (i = 0; i < adapter->num_rx_queues; i++) { for (i = 0; i < adapter->num_rx_queues; i++) {
struct igb_ring *ring = &(adapter->rx_ring[i]); struct igb_ring *ring = &(adapter->rx_ring[i]);
ring->count = adapter->rx_ring_count;
ring->adapter = adapter; ring->adapter = adapter;
ring->queue_index = i; ring->queue_index = i;
ring->itr_register = E1000_ITR; ring->itr_register = E1000_ITR;
...@@ -1400,6 +1400,8 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) ...@@ -1400,6 +1400,8 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); 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_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
adapter->rx_ps_hdr_size = 0; /* disable packet split */ adapter->rx_ps_hdr_size = 0; /* disable packet split */
adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
...@@ -1988,7 +1990,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) ...@@ -1988,7 +1990,7 @@ static void igb_configure_rx(struct igb_adapter *adapter)
* *
* Free all transmit software resources * 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; struct pci_dev *pdev = tx_ring->adapter->pdev;
...@@ -2088,7 +2090,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter) ...@@ -2088,7 +2090,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter)
* *
* Free all receive software resources * 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; struct pci_dev *pdev = rx_ring->adapter->pdev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment