diff options
author | Jesse Brandeburg <jesse.brandeburg@intel.com> | 2008-09-11 22:59:16 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-09-24 18:54:57 -0400 |
commit | c431f97ef96026e6da7032a871a0789cf5a2eaea (patch) | |
tree | 40e3fcc159d95916bb8a4071fe10f46b01f54d46 /drivers/net/ixgbe | |
parent | b95f5fcb8ba6073a652927d232a7a7cb552afe62 (diff) |
ixgbe: fix ring reallocation in ethtool
changing ring sizes in ethtool needs to be robust. If an allocation fails the
driver must continue operation, with the previous settings.
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/ixgbe')
-rw-r--r-- | drivers/net/ixgbe/ixgbe.h | 4 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_ethtool.c | 95 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 10 |
3 files changed, 56 insertions, 53 deletions
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 71ddac6ac4f4..27db64f5c860 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h | |||
@@ -336,5 +336,9 @@ extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, | |||
336 | struct ixgbe_ring *rxdr); | 336 | struct ixgbe_ring *rxdr); |
337 | extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, | 337 | extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, |
338 | struct ixgbe_ring *txdr); | 338 | struct ixgbe_ring *txdr); |
339 | extern void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, | ||
340 | struct ixgbe_ring *rxdr); | ||
341 | extern void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, | ||
342 | struct ixgbe_ring *txdr); | ||
339 | 343 | ||
340 | #endif /* _IXGBE_H_ */ | 344 | #endif /* _IXGBE_H_ */ |
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index f18e3daaf4f5..928b97cc1700 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c | |||
@@ -654,12 +654,9 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
654 | struct ethtool_ringparam *ring) | 654 | struct ethtool_ringparam *ring) |
655 | { | 655 | { |
656 | struct ixgbe_adapter *adapter = netdev_priv(netdev); | 656 | struct ixgbe_adapter *adapter = netdev_priv(netdev); |
657 | struct ixgbe_tx_buffer *old_buf; | 657 | struct ixgbe_ring *temp_ring; |
658 | struct ixgbe_rx_buffer *old_rx_buf; | ||
659 | void *old_desc; | ||
660 | int i, err; | 658 | int i, err; |
661 | u32 new_rx_count, new_tx_count, old_size; | 659 | u32 new_rx_count, new_tx_count; |
662 | dma_addr_t old_dma; | ||
663 | 660 | ||
664 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | 661 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) |
665 | return -EINVAL; | 662 | return -EINVAL; |
@@ -678,6 +675,15 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
678 | return 0; | 675 | return 0; |
679 | } | 676 | } |
680 | 677 | ||
678 | if (adapter->num_tx_queues > adapter->num_rx_queues) | ||
679 | temp_ring = vmalloc(adapter->num_tx_queues * | ||
680 | sizeof(struct ixgbe_ring)); | ||
681 | else | ||
682 | temp_ring = vmalloc(adapter->num_rx_queues * | ||
683 | sizeof(struct ixgbe_ring)); | ||
684 | if (!temp_ring) | ||
685 | return -ENOMEM; | ||
686 | |||
681 | while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) | 687 | while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) |
682 | msleep(1); | 688 | msleep(1); |
683 | 689 | ||
@@ -690,66 +696,59 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
690 | * to the tx and rx ring structs. | 696 | * to the tx and rx ring structs. |
691 | */ | 697 | */ |
692 | if (new_tx_count != adapter->tx_ring->count) { | 698 | if (new_tx_count != adapter->tx_ring->count) { |
699 | memcpy(temp_ring, adapter->tx_ring, | ||
700 | adapter->num_tx_queues * sizeof(struct ixgbe_ring)); | ||
701 | |||
693 | for (i = 0; i < adapter->num_tx_queues; i++) { | 702 | for (i = 0; i < adapter->num_tx_queues; i++) { |
694 | /* Save existing descriptor ring */ | 703 | temp_ring[i].count = new_tx_count; |
695 | old_buf = adapter->tx_ring[i].tx_buffer_info; | 704 | err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); |
696 | old_desc = adapter->tx_ring[i].desc; | ||
697 | old_size = adapter->tx_ring[i].size; | ||
698 | old_dma = adapter->tx_ring[i].dma; | ||
699 | /* Try to allocate a new one */ | ||
700 | adapter->tx_ring[i].tx_buffer_info = NULL; | ||
701 | adapter->tx_ring[i].desc = NULL; | ||
702 | adapter->tx_ring[i].count = new_tx_count; | ||
703 | err = ixgbe_setup_tx_resources(adapter, | ||
704 | &adapter->tx_ring[i]); | ||
705 | if (err) { | 705 | if (err) { |
706 | /* Restore the old one so at least | 706 | while (i) { |
707 | the adapter still works, even if | 707 | i--; |
708 | we failed the request */ | 708 | ixgbe_free_tx_resources(adapter, &temp_ring[i]); |
709 | adapter->tx_ring[i].tx_buffer_info = old_buf; | 709 | } |
710 | adapter->tx_ring[i].desc = old_desc; | ||
711 | adapter->tx_ring[i].size = old_size; | ||
712 | adapter->tx_ring[i].dma = old_dma; | ||
713 | goto err_setup; | 710 | goto err_setup; |
714 | } | 711 | } |
715 | /* Free the old buffer manually */ | ||
716 | vfree(old_buf); | ||
717 | pci_free_consistent(adapter->pdev, old_size, | ||
718 | old_desc, old_dma); | ||
719 | } | 712 | } |
713 | |||
714 | for (i = 0; i < adapter->num_tx_queues; i++) | ||
715 | ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); | ||
716 | |||
717 | memcpy(adapter->tx_ring, temp_ring, | ||
718 | adapter->num_tx_queues * sizeof(struct ixgbe_ring)); | ||
719 | |||
720 | adapter->tx_ring_count = new_tx_count; | ||
720 | } | 721 | } |
721 | 722 | ||
722 | if (new_rx_count != adapter->rx_ring->count) { | 723 | if (new_rx_count != adapter->rx_ring->count) { |
723 | for (i = 0; i < adapter->num_rx_queues; i++) { | 724 | memcpy(temp_ring, adapter->rx_ring, |
725 | adapter->num_rx_queues * sizeof(struct ixgbe_ring)); | ||
724 | 726 | ||
725 | old_rx_buf = adapter->rx_ring[i].rx_buffer_info; | 727 | for (i = 0; i < adapter->num_rx_queues; i++) { |
726 | old_desc = adapter->rx_ring[i].desc; | 728 | temp_ring[i].count = new_rx_count; |
727 | old_size = adapter->rx_ring[i].size; | 729 | err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); |
728 | old_dma = adapter->rx_ring[i].dma; | ||
729 | |||
730 | adapter->rx_ring[i].rx_buffer_info = NULL; | ||
731 | adapter->rx_ring[i].desc = NULL; | ||
732 | adapter->rx_ring[i].dma = 0; | ||
733 | adapter->rx_ring[i].count = new_rx_count; | ||
734 | err = ixgbe_setup_rx_resources(adapter, | ||
735 | &adapter->rx_ring[i]); | ||
736 | if (err) { | 730 | if (err) { |
737 | adapter->rx_ring[i].rx_buffer_info = old_rx_buf; | 731 | while (i) { |
738 | adapter->rx_ring[i].desc = old_desc; | 732 | i--; |
739 | adapter->rx_ring[i].size = old_size; | 733 | ixgbe_free_rx_resources(adapter, &temp_ring[i]); |
740 | adapter->rx_ring[i].dma = old_dma; | 734 | } |
741 | goto err_setup; | 735 | goto err_setup; |
742 | } | 736 | } |
743 | |||
744 | vfree(old_rx_buf); | ||
745 | pci_free_consistent(adapter->pdev, old_size, old_desc, | ||
746 | old_dma); | ||
747 | } | 737 | } |
738 | |||
739 | for (i = 0; i < adapter->num_rx_queues; i++) | ||
740 | ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); | ||
741 | |||
742 | memcpy(adapter->rx_ring, temp_ring, | ||
743 | adapter->num_rx_queues * sizeof(struct ixgbe_ring)); | ||
744 | |||
745 | adapter->rx_ring_count = new_rx_count; | ||
748 | } | 746 | } |
749 | 747 | ||
748 | /* success! */ | ||
750 | err = 0; | 749 | err = 0; |
751 | err_setup: | 750 | err_setup: |
752 | if (netif_running(adapter->netdev)) | 751 | if (netif_running(netdev)) |
753 | ixgbe_up(adapter); | 752 | ixgbe_up(adapter); |
754 | 753 | ||
755 | clear_bit(__IXGBE_RESETTING, &adapter->state); | 754 | clear_bit(__IXGBE_RESETTING, &adapter->state); |
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 3b0481a9979e..cde5d5a5a9ab 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -2731,8 +2731,8 @@ alloc_failed: | |||
2731 | * | 2731 | * |
2732 | * Free all transmit software resources | 2732 | * Free all transmit software resources |
2733 | **/ | 2733 | **/ |
2734 | static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, | 2734 | void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, |
2735 | struct ixgbe_ring *tx_ring) | 2735 | struct ixgbe_ring *tx_ring) |
2736 | { | 2736 | { |
2737 | struct pci_dev *pdev = adapter->pdev; | 2737 | struct pci_dev *pdev = adapter->pdev; |
2738 | 2738 | ||
@@ -2761,14 +2761,14 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter) | |||
2761 | } | 2761 | } |
2762 | 2762 | ||
2763 | /** | 2763 | /** |
2764 | * ixgbe_free_rx_resources - Free Rx Resources | 2764 | * ixgbe_ree_rx_resources - Free Rx Resources |
2765 | * @adapter: board private structure | 2765 | * @adapter: board private structure |
2766 | * @rx_ring: ring to clean the resources from | 2766 | * @rx_ring: ring to clean the resources from |
2767 | * | 2767 | * |
2768 | * Free all receive software resources | 2768 | * Free all receive software resources |
2769 | **/ | 2769 | **/ |
2770 | static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, | 2770 | void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, |
2771 | struct ixgbe_ring *rx_ring) | 2771 | struct ixgbe_ring *rx_ring) |
2772 | { | 2772 | { |
2773 | struct pci_dev *pdev = adapter->pdev; | 2773 | struct pci_dev *pdev = adapter->pdev; |
2774 | 2774 | ||