diff options
author | Bruce Allan <bruce.w.allan@intel.com> | 2011-12-15 19:45:51 -0500 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2012-01-26 02:12:29 -0500 |
commit | 508da4264add2eb13bd4d32bb896e79e6f8821fc (patch) | |
tree | 04f530b35714efdd0afd5457e11a7dc3efe47d32 | |
parent | 55aa69854a93d7aaf123a882b0b1f93c86cf3c7e (diff) |
e1000e: re-factor ethtool get/set ring parameter
Make it more like how igb does it, with some additional error checking.
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/ethtool.c | 136 |
1 files changed, 77 insertions, 59 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 01c73aee7fdb..ffb6c14cbbb8 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c | |||
@@ -605,94 +605,112 @@ static void e1000_get_ringparam(struct net_device *netdev, | |||
605 | struct ethtool_ringparam *ring) | 605 | struct ethtool_ringparam *ring) |
606 | { | 606 | { |
607 | struct e1000_adapter *adapter = netdev_priv(netdev); | 607 | struct e1000_adapter *adapter = netdev_priv(netdev); |
608 | struct e1000_ring *tx_ring = adapter->tx_ring; | ||
609 | struct e1000_ring *rx_ring = adapter->rx_ring; | ||
610 | 608 | ||
611 | ring->rx_max_pending = E1000_MAX_RXD; | 609 | ring->rx_max_pending = E1000_MAX_RXD; |
612 | ring->tx_max_pending = E1000_MAX_TXD; | 610 | ring->tx_max_pending = E1000_MAX_TXD; |
613 | ring->rx_pending = rx_ring->count; | 611 | ring->rx_pending = adapter->rx_ring_count; |
614 | ring->tx_pending = tx_ring->count; | 612 | ring->tx_pending = adapter->tx_ring_count; |
615 | } | 613 | } |
616 | 614 | ||
617 | static int e1000_set_ringparam(struct net_device *netdev, | 615 | static int e1000_set_ringparam(struct net_device *netdev, |
618 | struct ethtool_ringparam *ring) | 616 | struct ethtool_ringparam *ring) |
619 | { | 617 | { |
620 | struct e1000_adapter *adapter = netdev_priv(netdev); | 618 | struct e1000_adapter *adapter = netdev_priv(netdev); |
621 | struct e1000_ring *tx_ring, *tx_old; | 619 | struct e1000_ring *temp_tx = NULL, *temp_rx = NULL; |
622 | struct e1000_ring *rx_ring, *rx_old; | 620 | int err = 0, size = sizeof(struct e1000_ring); |
623 | int err; | 621 | bool set_tx = false, set_rx = false; |
622 | u16 new_rx_count, new_tx_count; | ||
624 | 623 | ||
625 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | 624 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) |
626 | return -EINVAL; | 625 | return -EINVAL; |
627 | 626 | ||
628 | while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) | 627 | new_rx_count = clamp_t(u32, ring->rx_pending, E1000_MIN_RXD, |
629 | usleep_range(1000, 2000); | 628 | E1000_MAX_RXD); |
629 | new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE); | ||
630 | 630 | ||
631 | if (netif_running(adapter->netdev)) | 631 | new_tx_count = clamp_t(u32, ring->tx_pending, E1000_MIN_TXD, |
632 | e1000e_down(adapter); | 632 | E1000_MAX_TXD); |
633 | new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); | ||
633 | 634 | ||
634 | tx_old = adapter->tx_ring; | 635 | if ((new_tx_count == adapter->tx_ring_count) && |
635 | rx_old = adapter->rx_ring; | 636 | (new_rx_count == adapter->rx_ring_count)) |
637 | /* nothing to do */ | ||
638 | return 0; | ||
636 | 639 | ||
637 | err = -ENOMEM; | 640 | while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) |
638 | tx_ring = kmemdup(tx_old, sizeof(struct e1000_ring), GFP_KERNEL); | 641 | usleep_range(1000, 2000); |
639 | if (!tx_ring) | ||
640 | goto err_alloc_tx; | ||
641 | 642 | ||
642 | rx_ring = kmemdup(rx_old, sizeof(struct e1000_ring), GFP_KERNEL); | 643 | if (!netif_running(adapter->netdev)) { |
643 | if (!rx_ring) | 644 | /* Set counts now and allocate resources during open() */ |
644 | goto err_alloc_rx; | 645 | adapter->tx_ring->count = new_tx_count; |
646 | adapter->rx_ring->count = new_rx_count; | ||
647 | adapter->tx_ring_count = new_tx_count; | ||
648 | adapter->rx_ring_count = new_rx_count; | ||
649 | goto clear_reset; | ||
650 | } | ||
645 | 651 | ||
646 | adapter->tx_ring = tx_ring; | 652 | set_tx = (new_tx_count != adapter->tx_ring_count); |
647 | adapter->rx_ring = rx_ring; | 653 | set_rx = (new_rx_count != adapter->rx_ring_count); |
648 | 654 | ||
649 | rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD); | 655 | /* Allocate temporary storage for ring updates */ |
650 | rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD)); | 656 | if (set_tx) { |
651 | rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); | 657 | temp_tx = vmalloc(size); |
658 | if (!temp_tx) { | ||
659 | err = -ENOMEM; | ||
660 | goto free_temp; | ||
661 | } | ||
662 | } | ||
663 | if (set_rx) { | ||
664 | temp_rx = vmalloc(size); | ||
665 | if (!temp_rx) { | ||
666 | err = -ENOMEM; | ||
667 | goto free_temp; | ||
668 | } | ||
669 | } | ||
652 | 670 | ||
653 | tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD); | 671 | e1000e_down(adapter); |
654 | tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD)); | ||
655 | tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); | ||
656 | 672 | ||
657 | if (netif_running(adapter->netdev)) { | 673 | /* |
658 | /* Try to get new resources before deleting old */ | 674 | * We can't just free everything and then setup again, because the |
659 | err = e1000e_setup_rx_resources(rx_ring); | 675 | * ISRs in MSI-X mode get passed pointers to the Tx and Rx ring |
676 | * structs. First, attempt to allocate new resources... | ||
677 | */ | ||
678 | if (set_tx) { | ||
679 | memcpy(temp_tx, adapter->tx_ring, size); | ||
680 | temp_tx->count = new_tx_count; | ||
681 | err = e1000e_setup_tx_resources(temp_tx); | ||
660 | if (err) | 682 | if (err) |
661 | goto err_setup_rx; | 683 | goto err_setup; |
662 | err = e1000e_setup_tx_resources(tx_ring); | 684 | } |
685 | if (set_rx) { | ||
686 | memcpy(temp_rx, adapter->rx_ring, size); | ||
687 | temp_rx->count = new_rx_count; | ||
688 | err = e1000e_setup_rx_resources(temp_rx); | ||
663 | if (err) | 689 | if (err) |
664 | goto err_setup_tx; | 690 | goto err_setup_rx; |
691 | } | ||
665 | 692 | ||
666 | /* | 693 | /* ...then free the old resources and copy back any new ring data */ |
667 | * restore the old in order to free it, | 694 | if (set_tx) { |
668 | * then add in the new | ||
669 | */ | ||
670 | adapter->rx_ring = rx_old; | ||
671 | adapter->tx_ring = tx_old; | ||
672 | e1000e_free_rx_resources(adapter->rx_ring); | ||
673 | e1000e_free_tx_resources(adapter->tx_ring); | 695 | e1000e_free_tx_resources(adapter->tx_ring); |
674 | kfree(tx_old); | 696 | memcpy(adapter->tx_ring, temp_tx, size); |
675 | kfree(rx_old); | 697 | adapter->tx_ring_count = new_tx_count; |
676 | adapter->rx_ring = rx_ring; | 698 | } |
677 | adapter->tx_ring = tx_ring; | 699 | if (set_rx) { |
678 | err = e1000e_up(adapter); | 700 | e1000e_free_rx_resources(adapter->rx_ring); |
679 | if (err) | 701 | memcpy(adapter->rx_ring, temp_rx, size); |
680 | goto err_setup; | 702 | adapter->rx_ring_count = new_rx_count; |
681 | } | 703 | } |
682 | 704 | ||
683 | clear_bit(__E1000_RESETTING, &adapter->state); | ||
684 | return 0; | ||
685 | err_setup_tx: | ||
686 | e1000e_free_rx_resources(rx_ring); | ||
687 | err_setup_rx: | 705 | err_setup_rx: |
688 | adapter->rx_ring = rx_old; | 706 | if (err && set_tx) |
689 | adapter->tx_ring = tx_old; | 707 | e1000e_free_tx_resources(temp_tx); |
690 | kfree(rx_ring); | ||
691 | err_alloc_rx: | ||
692 | kfree(tx_ring); | ||
693 | err_alloc_tx: | ||
694 | e1000e_up(adapter); | ||
695 | err_setup: | 708 | err_setup: |
709 | e1000e_up(adapter); | ||
710 | free_temp: | ||
711 | vfree(temp_tx); | ||
712 | vfree(temp_rx); | ||
713 | clear_reset: | ||
696 | clear_bit(__E1000_RESETTING, &adapter->state); | 714 | clear_bit(__E1000_RESETTING, &adapter->state); |
697 | return err; | 715 | return err; |
698 | } | 716 | } |