]> git.karo-electronics.de Git - linux-beck.git/commitdiff
qlcnic: Enable Tx queue changes using ethtool for 82xx Series adapter.
authorHimanshu Madhani <himanshu.madhani@qlogic.com>
Wed, 21 Aug 2013 15:24:11 +0000 (11:24 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 21 Aug 2013 19:17:18 +0000 (12:17 -0700)
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>
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c

index 2f9985f2fbcb5d821d39ad3b32a7547210427b63..101b538df8ab953d5419165980abed548366db2f 100644 (file)
@@ -1531,8 +1531,9 @@ int qlcnic_reset_context(struct qlcnic_adapter *);
 void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t);
+int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, int);
 int qlcnic_validate_max_rss(struct qlcnic_adapter *, __u32);
+int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *, int);
 void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
 void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);
 int qlcnic_enable_msix(struct qlcnic_adapter *, u32);
@@ -1679,7 +1680,7 @@ struct qlcnic_hardware_ops {
        int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
        void (*get_ocm_win) (struct qlcnic_hardware_context *);
        int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
-       int (*setup_intr) (struct qlcnic_adapter *, u8);
+       int (*setup_intr) (struct qlcnic_adapter *, u8, int);
        int (*alloc_mbx_args)(struct qlcnic_cmd_args *,
                              struct qlcnic_adapter *, u32);
        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,
        return adapter->ahw->hw_ops->get_mac_address(adapter, mac);
 }
 
-static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter,
+                                   u8 num_intr, int txq)
 {
-       return adapter->ahw->hw_ops->setup_intr(adapter, num_intr);
+       return adapter->ahw->hw_ops->setup_intr(adapter, num_intr, txq);
 }
 
 static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
index f0dc5d438ed6446d3ca3dd6f447e08a303ab50fe..ea44828a546d08ce9a7f872ed0ee8e2289d5534b 100644 (file)
@@ -261,7 +261,7 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
        }
 }
 
-int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq)
 {
        int err, i, num_msix;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
index d4c58c6a97d84ba0d341d0e5758f4bdcfd116fdc..bfd2741d6c77943e6b4f0024dfa72395f572ee25 100644 (file)
@@ -523,7 +523,7 @@ enum qlc_83xx_ext_regs {
 /* 83xx funcitons */
 int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);
 int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
-int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8, int);
 void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);
 int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);
 void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *);
index f23e66780e7ab5f44d23ba67b8a59a644d7c4436..fb0ef36b529ba60c5747b53cbbebcb98e228dc4b 100644 (file)
@@ -2201,7 +2201,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        if (err)
                goto detach_mbx;
 
-       err = qlcnic_setup_intr(adapter, 0);
+       err = qlcnic_setup_intr(adapter, 0, 0);
        if (err) {
                dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");
                goto disable_intr;
index 79a5855f926cab78a0b2c99b0ec5c8052106809c..583dc2b29a84282c0686a7b8533675bdb66f9f62 100644 (file)
@@ -125,6 +125,14 @@ static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
 };
 
 #define QLCNIC_STATS_LEN       ARRAY_SIZE(qlcnic_gstrings_stats)
+
+static const char qlcnic_tx_ring_stats_strings[][ETH_GSTRING_LEN] = {
+       "xmit_on",
+       "xmit_off",
+       "xmit_called",
+       "xmit_finished",
+};
+
 static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
        "ctx_rx_bytes",
        "ctx_rx_pkts",
@@ -630,15 +638,15 @@ qlcnic_set_ringparam(struct net_device *dev,
 static void qlcnic_get_channels(struct net_device *dev,
                struct ethtool_channels *channel)
 {
-       int min;
        struct qlcnic_adapter *adapter = netdev_priv(dev);
+       int min;
 
        min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus());
        channel->max_rx = rounddown_pow_of_two(min);
-       channel->max_tx = adapter->ahw->max_tx_ques;
+       channel->max_tx = min_t(int, QLCNIC_MAX_TX_RINGS, num_online_cpus());
 
        channel->rx_count = adapter->max_sds_rings;
-       channel->tx_count = adapter->ahw->max_tx_ques;
+       channel->tx_count = adapter->max_drv_tx_rings;
 }
 
 static int qlcnic_set_channels(struct net_device *dev,
@@ -646,18 +654,27 @@ static int qlcnic_set_channels(struct net_device *dev,
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        int err;
+       int txq = 0;
 
-       if (channel->other_count || channel->combined_count ||
-           channel->tx_count != channel->max_tx)
+       if (channel->other_count || channel->combined_count)
                return -EINVAL;
 
-       err = qlcnic_validate_max_rss(adapter, channel->rx_count);
-       if (err)
-               return err;
+       if (channel->rx_count) {
+               err = qlcnic_validate_max_rss(adapter, channel->rx_count);
+               if (err)
+                       return err;
+       }
+
+       if (channel->tx_count) {
+               err = qlcnic_validate_max_tx_rings(adapter, channel->tx_count);
+               if (err)
+                       return err;
+               txq = channel->tx_count;
+       }
 
-       err = qlcnic_set_max_rss(adapter, channel->rx_count, 0);
-       netdev_info(dev, "allocated 0x%x sds rings\n",
-                                adapter->max_sds_rings);
+       err = qlcnic_set_max_rss(adapter, channel->rx_count, txq);
+       netdev_info(dev, "allocated 0x%x sds rings and  0x%x tx rings\n",
+                   adapter->max_sds_rings, adapter->max_drv_tx_rings);
        return err;
 }
 
@@ -893,6 +910,7 @@ free_diag_res:
 clear_diag_irq:
        adapter->max_sds_rings = max_sds_rings;
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
        return ret;
 }
 
@@ -1077,11 +1095,21 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
                       QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
                break;
        case ETH_SS_STATS:
+               num_stats = ARRAY_SIZE(qlcnic_tx_ring_stats_strings);
+               for (i = 0; i < adapter->max_drv_tx_rings; i++) {
+                       for (index = 0; index < num_stats; index++) {
+                               sprintf(data, "tx_ring_%d %s", i,
+                                       qlcnic_tx_ring_stats_strings[index]);
+                               data += ETH_GSTRING_LEN;
+                       }
+               }
+
                for (index = 0; index < QLCNIC_STATS_LEN; index++) {
                        memcpy(data + index * ETH_GSTRING_LEN,
                               qlcnic_gstrings_stats[index].stat_string,
                               ETH_GSTRING_LEN);
                }
+
                if (qlcnic_83xx_check(adapter)) {
                        num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
                        for (i = 0; i < num_stats; i++, index++)
@@ -1173,11 +1201,22 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev,
                                     struct ethtool_stats *stats, u64 *data)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
+       struct qlcnic_host_tx_ring *tx_ring;
        struct qlcnic_esw_statistics port_stats;
        struct qlcnic_mac_statistics mac_stats;
-       int index, ret, length, size;
+       int index, ret, length, size, ring;
        char *p;
 
+       memset(data, 0, adapter->max_drv_tx_rings * 4 * sizeof(u64));
+       for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       *data++ = tx_ring->xmit_on;
+                       *data++ = tx_ring->xmit_off;
+                       *data++ = tx_ring->xmit_called;
+                       *data++ = tx_ring->xmit_finished;
+               }
+       }
        memset(data, 0, stats->n_stats * sizeof(u64));
        length = QLCNIC_STATS_LEN;
        for (index = 0; index < length; index++) {
index e9a2225746a75baf00d519f6df5cbda4f68342a4..cf35220cbfadba877786ca3ead8e68d38f64aff0 100644 (file)
@@ -150,7 +150,6 @@ struct ethtool_stats;
 struct pci_device_id;
 struct qlcnic_host_sds_ring;
 struct qlcnic_host_tx_ring;
-struct qlcnic_host_tx_ring;
 struct qlcnic_hardware_context;
 struct qlcnic_adapter;
 
@@ -174,7 +173,7 @@ int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *, u8);
 void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
 void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
 void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32);
-int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8);
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8, int);
 irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *);
 int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
                          struct qlcnic_cmd_args *);
index af2b2e2bfceba883f01ee957823c0bdb1ea6a033..94b3e820f89efcc62a0bc36bcebed46ea7177f43 100644 (file)
@@ -656,7 +656,7 @@ static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
        return err;
 }
 
-int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq)
 {
        struct qlcnic_hardware_context *ahw = adapter->ahw;
        int num_msix, err = 0;
@@ -667,8 +667,11 @@ int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
        if (ahw->msix_supported) {
                num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
                                                num_intr));
-               if (qlcnic_check_multi_tx(adapter))
+               if (qlcnic_check_multi_tx(adapter)) {
+                       if (txq)
+                               adapter->max_drv_tx_rings = txq;
                        num_msix += adapter->max_drv_tx_rings;
+               }
        } else {
                num_msix = 1;
        }
@@ -1990,11 +1993,9 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
        netdev->priv_flags |= IFF_UNICAST_FLT;
        netdev->irq = adapter->msix_entries[0].vector;
 
-       if (qlcnic_82xx_check(adapter) && qlcnic_check_multi_tx(adapter)) {
-               err = qlcnic_set_real_num_queues(adapter, netdev);
-               if (err)
-                       return err;
-       }
+       err = qlcnic_set_real_num_queues(adapter, netdev);
+       if (err)
+               return err;
 
        err = register_netdev(netdev);
        if (err) {
@@ -2253,7 +2254,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                         "Device does not support MSI interrupts\n");
 
        if (qlcnic_82xx_check(adapter)) {
-               err = qlcnic_setup_intr(adapter, 0);
+               err = qlcnic_setup_intr(adapter, 0, 0);
                if (err) {
                        dev_err(&pdev->dev, "Failed to setup interrupt\n");
                        goto err_out_disable_msi;
@@ -3371,7 +3372,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
        qlcnic_clr_drv_state(adapter);
        kfree(adapter->msix_entries);
        adapter->msix_entries = NULL;
-       err = qlcnic_setup_intr(adapter, 0);
+       err = qlcnic_setup_intr(adapter, 0, 0);
 
        if (err) {
                kfree(adapter->msix_entries);
@@ -3496,6 +3497,49 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
        return err;
 }
 
+int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *adapter, int txq)
+{
+       struct net_device *netdev = adapter->netdev;
+       u8 max_hw = QLCNIC_MAX_TX_RINGS;
+       u32 max_allowed;
+
+       if (!qlcnic_82xx_check(adapter)) {
+               netdev_err(netdev, "No Multi TX-Q support\n");
+               return -EINVAL;
+       }
+
+       if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
+               netdev_err(netdev, "No Multi TX-Q support in INT-x mode\n");
+               return -EINVAL;
+       }
+
+       if (!qlcnic_check_multi_tx(adapter)) {
+               netdev_err(netdev, "No Multi TX-Q support\n");
+               return -EINVAL;
+       }
+
+       if (txq > QLCNIC_MAX_TX_RINGS) {
+               netdev_err(netdev, "Invalid ring count\n");
+               return -EINVAL;
+       }
+
+       max_allowed = rounddown_pow_of_two(min_t(int, max_hw,
+                                                num_online_cpus()));
+       if ((txq > max_allowed) || !is_power_of_2(txq)) {
+               if (!is_power_of_2(txq))
+                       netdev_err(netdev,
+                                  "TX queue should be a power of 2\n");
+               if (txq > num_online_cpus())
+                       netdev_err(netdev,
+                                  "Tx queue should not be higher than [%u], number of online CPUs in the system\n",
+                                  num_online_cpus());
+               netdev_err(netdev, "Unable to configure %u Tx rings\n", txq);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
                                __u32 val)
 {
@@ -3503,6 +3547,12 @@ int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
        u8 max_hw = adapter->ahw->max_rx_ques;
        u32 max_allowed;
 
+       if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x &&
+           !qlcnic_use_msi) {
+               netdev_err(netdev, "No RSS support in INT-x mode\n");
+               return -EINVAL;
+       }
+
        if (val > QLCNIC_MAX_SDS_RINGS) {
                netdev_err(netdev, "RSS value should not be higher than %u\n",
                           QLCNIC_MAX_SDS_RINGS);
@@ -3535,27 +3585,48 @@ int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
        return 0;
 }
 
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
+int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, int txq)
 {
        int err;
        struct net_device *netdev = adapter->netdev;
+       int num_msix;
 
        if (test_bit(__QLCNIC_RESETTING, &adapter->state))
                return -EBUSY;
 
+       if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x &&
+           !qlcnic_use_msi) {
+               netdev_err(netdev, "No RSS support in INT-x mode\n");
+               return -EINVAL;
+       }
+
        netif_device_detach(netdev);
        if (netif_running(netdev))
                __qlcnic_down(adapter, netdev);
 
        qlcnic_detach(adapter);
 
+       if (qlcnic_82xx_check(adapter)) {
+               if (txq != 0)
+                       adapter->max_drv_tx_rings = txq;
+
+               if (qlcnic_check_multi_tx(adapter) &&
+                   (txq > adapter->max_drv_tx_rings))
+                       num_msix = adapter->max_drv_tx_rings;
+               else
+                       num_msix = data;
+       }
+
        if (qlcnic_83xx_check(adapter)) {
                qlcnic_83xx_free_mbx_intr(adapter);
                qlcnic_83xx_enable_mbx_poll(adapter);
        }
 
+       netif_set_real_num_tx_queues(netdev, adapter->max_drv_tx_rings);
+
        qlcnic_teardown_intr(adapter);
-       err = qlcnic_setup_intr(adapter, data);
+
+       err = qlcnic_setup_intr(adapter, data, txq);
        if (err) {
                kfree(adapter->msix_entries);
                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)
                        goto done;
                qlcnic_restore_indev_addr(netdev, NETDEV_UP);
        }
-       err = len;
- done:
+done:
        netif_device_attach(netdev);
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
        return err;
index b2fbefc0b73ef88ab35a0ecef49ca779143ea480..2f79ec5246dcf250e969c5e3810d7210079eafa1 100644 (file)
@@ -512,7 +512,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
                dev_warn(&adapter->pdev->dev,
                         "Device does not support MSI interrupts\n");
 
-       err = qlcnic_setup_intr(adapter, 1);
+       err = qlcnic_setup_intr(adapter, 1, 0);
        if (err) {
                dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");
                goto err_out_disable_msi;