diff options
author | Himanshu Madhani <himanshu.madhani@qlogic.com> | 2013-08-21 11:24:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-21 15:17:18 -0400 |
commit | aa4a1f7df7cbb98797c9f4edfde3c726e2b3841f (patch) | |
tree | 0281089c4d1e9650bc5f558e8fd1dfb496ce6e2e /drivers/net/ethernet | |
parent | 012ec81223aa45d2b80aeafb77392fd1a19c7b10 (diff) |
qlcnic: Enable Tx queue changes using ethtool for 82xx Series adapter.
o using ethtool {set|get}_channel option, user can change number
of Tx queues for 82xx Series adapter.
o updated ethtool -S <ethX> option to display stats from each Tx queue.
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
8 files changed, 145 insertions, 35 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 2f9985f2fbcb..101b538df8ab 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | |||
@@ -1531,8 +1531,9 @@ int qlcnic_reset_context(struct qlcnic_adapter *); | |||
1531 | void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); | 1531 | void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); |
1532 | int qlcnic_diag_alloc_res(struct net_device *netdev, int test); | 1532 | int qlcnic_diag_alloc_res(struct net_device *netdev, int test); |
1533 | netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); | 1533 | netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); |
1534 | int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t); | 1534 | int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, int); |
1535 | int qlcnic_validate_max_rss(struct qlcnic_adapter *, __u32); | 1535 | int qlcnic_validate_max_rss(struct qlcnic_adapter *, __u32); |
1536 | int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *, int); | ||
1536 | void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter); | 1537 | void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter); |
1537 | void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *); | 1538 | void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *); |
1538 | int qlcnic_enable_msix(struct qlcnic_adapter *, u32); | 1539 | int qlcnic_enable_msix(struct qlcnic_adapter *, u32); |
@@ -1679,7 +1680,7 @@ struct qlcnic_hardware_ops { | |||
1679 | int (*write_reg) (struct qlcnic_adapter *, ulong, u32); | 1680 | int (*write_reg) (struct qlcnic_adapter *, ulong, u32); |
1680 | void (*get_ocm_win) (struct qlcnic_hardware_context *); | 1681 | void (*get_ocm_win) (struct qlcnic_hardware_context *); |
1681 | int (*get_mac_address) (struct qlcnic_adapter *, u8 *); | 1682 | int (*get_mac_address) (struct qlcnic_adapter *, u8 *); |
1682 | int (*setup_intr) (struct qlcnic_adapter *, u8); | 1683 | int (*setup_intr) (struct qlcnic_adapter *, u8, int); |
1683 | int (*alloc_mbx_args)(struct qlcnic_cmd_args *, | 1684 | int (*alloc_mbx_args)(struct qlcnic_cmd_args *, |
1684 | struct qlcnic_adapter *, u32); | 1685 | struct qlcnic_adapter *, u32); |
1685 | int (*mbx_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *); | 1686 | int (*mbx_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *); |
@@ -1745,9 +1746,10 @@ static inline int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, | |||
1745 | return adapter->ahw->hw_ops->get_mac_address(adapter, mac); | 1746 | return adapter->ahw->hw_ops->get_mac_address(adapter, mac); |
1746 | } | 1747 | } |
1747 | 1748 | ||
1748 | static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr) | 1749 | static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter, |
1750 | u8 num_intr, int txq) | ||
1749 | { | 1751 | { |
1750 | return adapter->ahw->hw_ops->setup_intr(adapter, num_intr); | 1752 | return adapter->ahw->hw_ops->setup_intr(adapter, num_intr, txq); |
1751 | } | 1753 | } |
1752 | 1754 | ||
1753 | static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx, | 1755 | static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx, |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index f0dc5d438ed6..ea44828a546d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
@@ -261,7 +261,7 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr, | |||
261 | } | 261 | } |
262 | } | 262 | } |
263 | 263 | ||
264 | int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr) | 264 | int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq) |
265 | { | 265 | { |
266 | int err, i, num_msix; | 266 | int err, i, num_msix; |
267 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 267 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index d4c58c6a97d8..bfd2741d6c77 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | |||
@@ -523,7 +523,7 @@ enum qlc_83xx_ext_regs { | |||
523 | /* 83xx funcitons */ | 523 | /* 83xx funcitons */ |
524 | int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *); | 524 | int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *); |
525 | int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *); | 525 | int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *); |
526 | int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8); | 526 | int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8, int); |
527 | void qlcnic_83xx_get_func_no(struct qlcnic_adapter *); | 527 | void qlcnic_83xx_get_func_no(struct qlcnic_adapter *); |
528 | int qlcnic_83xx_cam_lock(struct qlcnic_adapter *); | 528 | int qlcnic_83xx_cam_lock(struct qlcnic_adapter *); |
529 | void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *); | 529 | void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index f23e66780e7a..fb0ef36b529b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | |||
@@ -2201,7 +2201,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) | |||
2201 | if (err) | 2201 | if (err) |
2202 | goto detach_mbx; | 2202 | goto detach_mbx; |
2203 | 2203 | ||
2204 | err = qlcnic_setup_intr(adapter, 0); | 2204 | err = qlcnic_setup_intr(adapter, 0, 0); |
2205 | if (err) { | 2205 | if (err) { |
2206 | dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n"); | 2206 | dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n"); |
2207 | goto disable_intr; | 2207 | goto disable_intr; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 79a5855f926c..583dc2b29a84 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | |||
@@ -125,6 +125,14 @@ static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = { | |||
125 | }; | 125 | }; |
126 | 126 | ||
127 | #define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) | 127 | #define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) |
128 | |||
129 | static const char qlcnic_tx_ring_stats_strings[][ETH_GSTRING_LEN] = { | ||
130 | "xmit_on", | ||
131 | "xmit_off", | ||
132 | "xmit_called", | ||
133 | "xmit_finished", | ||
134 | }; | ||
135 | |||
128 | static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = { | 136 | static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = { |
129 | "ctx_rx_bytes", | 137 | "ctx_rx_bytes", |
130 | "ctx_rx_pkts", | 138 | "ctx_rx_pkts", |
@@ -630,15 +638,15 @@ qlcnic_set_ringparam(struct net_device *dev, | |||
630 | static void qlcnic_get_channels(struct net_device *dev, | 638 | static void qlcnic_get_channels(struct net_device *dev, |
631 | struct ethtool_channels *channel) | 639 | struct ethtool_channels *channel) |
632 | { | 640 | { |
633 | int min; | ||
634 | struct qlcnic_adapter *adapter = netdev_priv(dev); | 641 | struct qlcnic_adapter *adapter = netdev_priv(dev); |
642 | int min; | ||
635 | 643 | ||
636 | min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus()); | 644 | min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus()); |
637 | channel->max_rx = rounddown_pow_of_two(min); | 645 | channel->max_rx = rounddown_pow_of_two(min); |
638 | channel->max_tx = adapter->ahw->max_tx_ques; | 646 | channel->max_tx = min_t(int, QLCNIC_MAX_TX_RINGS, num_online_cpus()); |
639 | 647 | ||
640 | channel->rx_count = adapter->max_sds_rings; | 648 | channel->rx_count = adapter->max_sds_rings; |
641 | channel->tx_count = adapter->ahw->max_tx_ques; | 649 | channel->tx_count = adapter->max_drv_tx_rings; |
642 | } | 650 | } |
643 | 651 | ||
644 | static int qlcnic_set_channels(struct net_device *dev, | 652 | static int qlcnic_set_channels(struct net_device *dev, |
@@ -646,18 +654,27 @@ static int qlcnic_set_channels(struct net_device *dev, | |||
646 | { | 654 | { |
647 | struct qlcnic_adapter *adapter = netdev_priv(dev); | 655 | struct qlcnic_adapter *adapter = netdev_priv(dev); |
648 | int err; | 656 | int err; |
657 | int txq = 0; | ||
649 | 658 | ||
650 | if (channel->other_count || channel->combined_count || | 659 | if (channel->other_count || channel->combined_count) |
651 | channel->tx_count != channel->max_tx) | ||
652 | return -EINVAL; | 660 | return -EINVAL; |
653 | 661 | ||
654 | err = qlcnic_validate_max_rss(adapter, channel->rx_count); | 662 | if (channel->rx_count) { |
655 | if (err) | 663 | err = qlcnic_validate_max_rss(adapter, channel->rx_count); |
656 | return err; | 664 | if (err) |
665 | return err; | ||
666 | } | ||
667 | |||
668 | if (channel->tx_count) { | ||
669 | err = qlcnic_validate_max_tx_rings(adapter, channel->tx_count); | ||
670 | if (err) | ||
671 | return err; | ||
672 | txq = channel->tx_count; | ||
673 | } | ||
657 | 674 | ||
658 | err = qlcnic_set_max_rss(adapter, channel->rx_count, 0); | 675 | err = qlcnic_set_max_rss(adapter, channel->rx_count, txq); |
659 | netdev_info(dev, "allocated 0x%x sds rings\n", | 676 | netdev_info(dev, "allocated 0x%x sds rings and 0x%x tx rings\n", |
660 | adapter->max_sds_rings); | 677 | adapter->max_sds_rings, adapter->max_drv_tx_rings); |
661 | return err; | 678 | return err; |
662 | } | 679 | } |
663 | 680 | ||
@@ -893,6 +910,7 @@ free_diag_res: | |||
893 | clear_diag_irq: | 910 | clear_diag_irq: |
894 | adapter->max_sds_rings = max_sds_rings; | 911 | adapter->max_sds_rings = max_sds_rings; |
895 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | 912 | clear_bit(__QLCNIC_RESETTING, &adapter->state); |
913 | |||
896 | return ret; | 914 | return ret; |
897 | } | 915 | } |
898 | 916 | ||
@@ -1077,11 +1095,21 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data) | |||
1077 | QLCNIC_TEST_LEN * ETH_GSTRING_LEN); | 1095 | QLCNIC_TEST_LEN * ETH_GSTRING_LEN); |
1078 | break; | 1096 | break; |
1079 | case ETH_SS_STATS: | 1097 | case ETH_SS_STATS: |
1098 | num_stats = ARRAY_SIZE(qlcnic_tx_ring_stats_strings); | ||
1099 | for (i = 0; i < adapter->max_drv_tx_rings; i++) { | ||
1100 | for (index = 0; index < num_stats; index++) { | ||
1101 | sprintf(data, "tx_ring_%d %s", i, | ||
1102 | qlcnic_tx_ring_stats_strings[index]); | ||
1103 | data += ETH_GSTRING_LEN; | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1080 | for (index = 0; index < QLCNIC_STATS_LEN; index++) { | 1107 | for (index = 0; index < QLCNIC_STATS_LEN; index++) { |
1081 | memcpy(data + index * ETH_GSTRING_LEN, | 1108 | memcpy(data + index * ETH_GSTRING_LEN, |
1082 | qlcnic_gstrings_stats[index].stat_string, | 1109 | qlcnic_gstrings_stats[index].stat_string, |
1083 | ETH_GSTRING_LEN); | 1110 | ETH_GSTRING_LEN); |
1084 | } | 1111 | } |
1112 | |||
1085 | if (qlcnic_83xx_check(adapter)) { | 1113 | if (qlcnic_83xx_check(adapter)) { |
1086 | num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings); | 1114 | num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings); |
1087 | for (i = 0; i < num_stats; i++, index++) | 1115 | for (i = 0; i < num_stats; i++, index++) |
@@ -1173,11 +1201,22 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev, | |||
1173 | struct ethtool_stats *stats, u64 *data) | 1201 | struct ethtool_stats *stats, u64 *data) |
1174 | { | 1202 | { |
1175 | struct qlcnic_adapter *adapter = netdev_priv(dev); | 1203 | struct qlcnic_adapter *adapter = netdev_priv(dev); |
1204 | struct qlcnic_host_tx_ring *tx_ring; | ||
1176 | struct qlcnic_esw_statistics port_stats; | 1205 | struct qlcnic_esw_statistics port_stats; |
1177 | struct qlcnic_mac_statistics mac_stats; | 1206 | struct qlcnic_mac_statistics mac_stats; |
1178 | int index, ret, length, size; | 1207 | int index, ret, length, size, ring; |
1179 | char *p; | 1208 | char *p; |
1180 | 1209 | ||
1210 | memset(data, 0, adapter->max_drv_tx_rings * 4 * sizeof(u64)); | ||
1211 | for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) { | ||
1212 | if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { | ||
1213 | tx_ring = &adapter->tx_ring[ring]; | ||
1214 | *data++ = tx_ring->xmit_on; | ||
1215 | *data++ = tx_ring->xmit_off; | ||
1216 | *data++ = tx_ring->xmit_called; | ||
1217 | *data++ = tx_ring->xmit_finished; | ||
1218 | } | ||
1219 | } | ||
1181 | memset(data, 0, stats->n_stats * sizeof(u64)); | 1220 | memset(data, 0, stats->n_stats * sizeof(u64)); |
1182 | length = QLCNIC_STATS_LEN; | 1221 | length = QLCNIC_STATS_LEN; |
1183 | for (index = 0; index < length; index++) { | 1222 | for (index = 0; index < length; index++) { |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index e9a2225746a7..cf35220cbfad 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | |||
@@ -150,7 +150,6 @@ struct ethtool_stats; | |||
150 | struct pci_device_id; | 150 | struct pci_device_id; |
151 | struct qlcnic_host_sds_ring; | 151 | struct qlcnic_host_sds_ring; |
152 | struct qlcnic_host_tx_ring; | 152 | struct qlcnic_host_tx_ring; |
153 | struct qlcnic_host_tx_ring; | ||
154 | struct qlcnic_hardware_context; | 153 | struct qlcnic_hardware_context; |
155 | struct qlcnic_adapter; | 154 | struct qlcnic_adapter; |
156 | 155 | ||
@@ -174,7 +173,7 @@ int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *, u8); | |||
174 | void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t); | 173 | void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t); |
175 | void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t); | 174 | void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t); |
176 | void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32); | 175 | void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32); |
177 | int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8); | 176 | int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8, int); |
178 | irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *); | 177 | irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *); |
179 | int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, | 178 | int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, |
180 | struct qlcnic_cmd_args *); | 179 | struct qlcnic_cmd_args *); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index af2b2e2bfceb..94b3e820f89e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | |||
@@ -656,7 +656,7 @@ static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter) | |||
656 | return err; | 656 | return err; |
657 | } | 657 | } |
658 | 658 | ||
659 | int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr) | 659 | int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq) |
660 | { | 660 | { |
661 | struct qlcnic_hardware_context *ahw = adapter->ahw; | 661 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
662 | int num_msix, err = 0; | 662 | int num_msix, err = 0; |
@@ -667,8 +667,11 @@ int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr) | |||
667 | if (ahw->msix_supported) { | 667 | if (ahw->msix_supported) { |
668 | num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(), | 668 | num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(), |
669 | num_intr)); | 669 | num_intr)); |
670 | if (qlcnic_check_multi_tx(adapter)) | 670 | if (qlcnic_check_multi_tx(adapter)) { |
671 | if (txq) | ||
672 | adapter->max_drv_tx_rings = txq; | ||
671 | num_msix += adapter->max_drv_tx_rings; | 673 | num_msix += adapter->max_drv_tx_rings; |
674 | } | ||
672 | } else { | 675 | } else { |
673 | num_msix = 1; | 676 | num_msix = 1; |
674 | } | 677 | } |
@@ -1990,11 +1993,9 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev, | |||
1990 | netdev->priv_flags |= IFF_UNICAST_FLT; | 1993 | netdev->priv_flags |= IFF_UNICAST_FLT; |
1991 | netdev->irq = adapter->msix_entries[0].vector; | 1994 | netdev->irq = adapter->msix_entries[0].vector; |
1992 | 1995 | ||
1993 | if (qlcnic_82xx_check(adapter) && qlcnic_check_multi_tx(adapter)) { | 1996 | err = qlcnic_set_real_num_queues(adapter, netdev); |
1994 | err = qlcnic_set_real_num_queues(adapter, netdev); | 1997 | if (err) |
1995 | if (err) | 1998 | return err; |
1996 | return err; | ||
1997 | } | ||
1998 | 1999 | ||
1999 | err = register_netdev(netdev); | 2000 | err = register_netdev(netdev); |
2000 | if (err) { | 2001 | if (err) { |
@@ -2253,7 +2254,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2253 | "Device does not support MSI interrupts\n"); | 2254 | "Device does not support MSI interrupts\n"); |
2254 | 2255 | ||
2255 | if (qlcnic_82xx_check(adapter)) { | 2256 | if (qlcnic_82xx_check(adapter)) { |
2256 | err = qlcnic_setup_intr(adapter, 0); | 2257 | err = qlcnic_setup_intr(adapter, 0, 0); |
2257 | if (err) { | 2258 | if (err) { |
2258 | dev_err(&pdev->dev, "Failed to setup interrupt\n"); | 2259 | dev_err(&pdev->dev, "Failed to setup interrupt\n"); |
2259 | goto err_out_disable_msi; | 2260 | goto err_out_disable_msi; |
@@ -3371,7 +3372,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev) | |||
3371 | qlcnic_clr_drv_state(adapter); | 3372 | qlcnic_clr_drv_state(adapter); |
3372 | kfree(adapter->msix_entries); | 3373 | kfree(adapter->msix_entries); |
3373 | adapter->msix_entries = NULL; | 3374 | adapter->msix_entries = NULL; |
3374 | err = qlcnic_setup_intr(adapter, 0); | 3375 | err = qlcnic_setup_intr(adapter, 0, 0); |
3375 | 3376 | ||
3376 | if (err) { | 3377 | if (err) { |
3377 | kfree(adapter->msix_entries); | 3378 | kfree(adapter->msix_entries); |
@@ -3496,6 +3497,49 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter) | |||
3496 | return err; | 3497 | return err; |
3497 | } | 3498 | } |
3498 | 3499 | ||
3500 | int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *adapter, int txq) | ||
3501 | { | ||
3502 | struct net_device *netdev = adapter->netdev; | ||
3503 | u8 max_hw = QLCNIC_MAX_TX_RINGS; | ||
3504 | u32 max_allowed; | ||
3505 | |||
3506 | if (!qlcnic_82xx_check(adapter)) { | ||
3507 | netdev_err(netdev, "No Multi TX-Q support\n"); | ||
3508 | return -EINVAL; | ||
3509 | } | ||
3510 | |||
3511 | if (!qlcnic_use_msi_x && !qlcnic_use_msi) { | ||
3512 | netdev_err(netdev, "No Multi TX-Q support in INT-x mode\n"); | ||
3513 | return -EINVAL; | ||
3514 | } | ||
3515 | |||
3516 | if (!qlcnic_check_multi_tx(adapter)) { | ||
3517 | netdev_err(netdev, "No Multi TX-Q support\n"); | ||
3518 | return -EINVAL; | ||
3519 | } | ||
3520 | |||
3521 | if (txq > QLCNIC_MAX_TX_RINGS) { | ||
3522 | netdev_err(netdev, "Invalid ring count\n"); | ||
3523 | return -EINVAL; | ||
3524 | } | ||
3525 | |||
3526 | max_allowed = rounddown_pow_of_two(min_t(int, max_hw, | ||
3527 | num_online_cpus())); | ||
3528 | if ((txq > max_allowed) || !is_power_of_2(txq)) { | ||
3529 | if (!is_power_of_2(txq)) | ||
3530 | netdev_err(netdev, | ||
3531 | "TX queue should be a power of 2\n"); | ||
3532 | if (txq > num_online_cpus()) | ||
3533 | netdev_err(netdev, | ||
3534 | "Tx queue should not be higher than [%u], number of online CPUs in the system\n", | ||
3535 | num_online_cpus()); | ||
3536 | netdev_err(netdev, "Unable to configure %u Tx rings\n", txq); | ||
3537 | return -EINVAL; | ||
3538 | } | ||
3539 | |||
3540 | return 0; | ||
3541 | } | ||
3542 | |||
3499 | int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter, | 3543 | int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter, |
3500 | __u32 val) | 3544 | __u32 val) |
3501 | { | 3545 | { |
@@ -3503,6 +3547,12 @@ int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter, | |||
3503 | u8 max_hw = adapter->ahw->max_rx_ques; | 3547 | u8 max_hw = adapter->ahw->max_rx_ques; |
3504 | u32 max_allowed; | 3548 | u32 max_allowed; |
3505 | 3549 | ||
3550 | if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x && | ||
3551 | !qlcnic_use_msi) { | ||
3552 | netdev_err(netdev, "No RSS support in INT-x mode\n"); | ||
3553 | return -EINVAL; | ||
3554 | } | ||
3555 | |||
3506 | if (val > QLCNIC_MAX_SDS_RINGS) { | 3556 | if (val > QLCNIC_MAX_SDS_RINGS) { |
3507 | netdev_err(netdev, "RSS value should not be higher than %u\n", | 3557 | netdev_err(netdev, "RSS value should not be higher than %u\n", |
3508 | QLCNIC_MAX_SDS_RINGS); | 3558 | QLCNIC_MAX_SDS_RINGS); |
@@ -3535,27 +3585,48 @@ int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter, | |||
3535 | return 0; | 3585 | return 0; |
3536 | } | 3586 | } |
3537 | 3587 | ||
3538 | int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len) | 3588 | int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, int txq) |
3539 | { | 3589 | { |
3540 | int err; | 3590 | int err; |
3541 | struct net_device *netdev = adapter->netdev; | 3591 | struct net_device *netdev = adapter->netdev; |
3592 | int num_msix; | ||
3542 | 3593 | ||
3543 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) | 3594 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) |
3544 | return -EBUSY; | 3595 | return -EBUSY; |
3545 | 3596 | ||
3597 | if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x && | ||
3598 | !qlcnic_use_msi) { | ||
3599 | netdev_err(netdev, "No RSS support in INT-x mode\n"); | ||
3600 | return -EINVAL; | ||
3601 | } | ||
3602 | |||
3546 | netif_device_detach(netdev); | 3603 | netif_device_detach(netdev); |
3547 | if (netif_running(netdev)) | 3604 | if (netif_running(netdev)) |
3548 | __qlcnic_down(adapter, netdev); | 3605 | __qlcnic_down(adapter, netdev); |
3549 | 3606 | ||
3550 | qlcnic_detach(adapter); | 3607 | qlcnic_detach(adapter); |
3551 | 3608 | ||
3609 | if (qlcnic_82xx_check(adapter)) { | ||
3610 | if (txq != 0) | ||
3611 | adapter->max_drv_tx_rings = txq; | ||
3612 | |||
3613 | if (qlcnic_check_multi_tx(adapter) && | ||
3614 | (txq > adapter->max_drv_tx_rings)) | ||
3615 | num_msix = adapter->max_drv_tx_rings; | ||
3616 | else | ||
3617 | num_msix = data; | ||
3618 | } | ||
3619 | |||
3552 | if (qlcnic_83xx_check(adapter)) { | 3620 | if (qlcnic_83xx_check(adapter)) { |
3553 | qlcnic_83xx_free_mbx_intr(adapter); | 3621 | qlcnic_83xx_free_mbx_intr(adapter); |
3554 | qlcnic_83xx_enable_mbx_poll(adapter); | 3622 | qlcnic_83xx_enable_mbx_poll(adapter); |
3555 | } | 3623 | } |
3556 | 3624 | ||
3625 | netif_set_real_num_tx_queues(netdev, adapter->max_drv_tx_rings); | ||
3626 | |||
3557 | qlcnic_teardown_intr(adapter); | 3627 | qlcnic_teardown_intr(adapter); |
3558 | err = qlcnic_setup_intr(adapter, data); | 3628 | |
3629 | err = qlcnic_setup_intr(adapter, data, txq); | ||
3559 | if (err) { | 3630 | if (err) { |
3560 | kfree(adapter->msix_entries); | 3631 | kfree(adapter->msix_entries); |
3561 | netdev_err(netdev, "failed to setup interrupt\n"); | 3632 | netdev_err(netdev, "failed to setup interrupt\n"); |
@@ -3583,8 +3654,7 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len) | |||
3583 | goto done; | 3654 | goto done; |
3584 | qlcnic_restore_indev_addr(netdev, NETDEV_UP); | 3655 | qlcnic_restore_indev_addr(netdev, NETDEV_UP); |
3585 | } | 3656 | } |
3586 | err = len; | 3657 | done: |
3587 | done: | ||
3588 | netif_device_attach(netdev); | 3658 | netif_device_attach(netdev); |
3589 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | 3659 | clear_bit(__QLCNIC_RESETTING, &adapter->state); |
3590 | return err; | 3660 | return err; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index b2fbefc0b73e..2f79ec5246dc 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | |||
@@ -512,7 +512,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, | |||
512 | dev_warn(&adapter->pdev->dev, | 512 | dev_warn(&adapter->pdev->dev, |
513 | "Device does not support MSI interrupts\n"); | 513 | "Device does not support MSI interrupts\n"); |
514 | 514 | ||
515 | err = qlcnic_setup_intr(adapter, 1); | 515 | err = qlcnic_setup_intr(adapter, 1, 0); |
516 | if (err) { | 516 | if (err) { |
517 | dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n"); | 517 | dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n"); |
518 | goto err_out_disable_msi; | 518 | goto err_out_disable_msi; |