aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSucheta Chakraborty <sucheta.chakraborty@qlogic.com>2011-04-28 07:48:18 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-29 15:59:59 -0400
commitf94bc1e70281c5a587049015af8f3e024d45ad66 (patch)
treef221f5ea160c98f30c4ef2ff23e776f0c408600f
parentad246c992bea6d33c6421ba1f03e2b405792adf9 (diff)
qlcnic: support rcv ring configuration through ethtool
o Support ethtool command ETHTOOL_GCHANNELS and ETHTOOL_SCHANNELS. o Number of rcv rings configuration depend upon number of msix vector. Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/qlcnic/qlcnic.h8
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c35
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c146
3 files changed, 156 insertions, 33 deletions
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index f7acb807a03d..1934ed9a1aad 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -118,7 +118,6 @@
118#define PHAN_PEG_RCV_INITIALIZED 0xff01 118#define PHAN_PEG_RCV_INITIALIZED 0xff01
119 119
120#define NUM_RCV_DESC_RINGS 3 120#define NUM_RCV_DESC_RINGS 3
121#define NUM_STS_DESC_RINGS 4
122 121
123#define RCV_RING_NORMAL 0 122#define RCV_RING_NORMAL 0
124#define RCV_RING_JUMBO 1 123#define RCV_RING_JUMBO 1
@@ -871,7 +870,8 @@ struct qlcnic_ipaddr {
871#define QLCNIC_IS_MSI_FAMILY(adapter) \ 870#define QLCNIC_IS_MSI_FAMILY(adapter) \
872 ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) 871 ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
873 872
874#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS 873#define QLCNIC_DEF_NUM_STS_DESC_RINGS 4
874#define QLCNIC_MIN_NUM_RSS_RINGS 2
875#define QLCNIC_MSIX_TBL_SPACE 8192 875#define QLCNIC_MSIX_TBL_SPACE 8192
876#define QLCNIC_PCI_REG_MSIX_TBL 0x44 876#define QLCNIC_PCI_REG_MSIX_TBL 0x44
877#define QLCNIC_MSIX_TBL_PGSIZE 4096 877#define QLCNIC_MSIX_TBL_PGSIZE 4096
@@ -987,7 +987,7 @@ struct qlcnic_adapter {
987 void __iomem *crb_int_state_reg; 987 void __iomem *crb_int_state_reg;
988 void __iomem *isr_int_vec; 988 void __iomem *isr_int_vec;
989 989
990 struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; 990 struct msix_entry *msix_entries;
991 991
992 struct delayed_work fw_work; 992 struct delayed_work fw_work;
993 993
@@ -1262,6 +1262,8 @@ u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
1262void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); 1262void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
1263int qlcnic_diag_alloc_res(struct net_device *netdev, int test); 1263int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
1264netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); 1264netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
1265int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val);
1266int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
1265 1267
1266/* Management functions */ 1268/* Management functions */
1267int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*); 1269int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index de65847f3559..8db1d1983cfe 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -474,6 +474,39 @@ qlcnic_set_ringparam(struct net_device *dev,
474 return qlcnic_reset_context(adapter); 474 return qlcnic_reset_context(adapter);
475} 475}
476 476
477static void qlcnic_get_channels(struct net_device *dev,
478 struct ethtool_channels *channel)
479{
480 struct qlcnic_adapter *adapter = netdev_priv(dev);
481
482 channel->max_rx = rounddown_pow_of_two(min_t(int,
483 adapter->max_rx_ques, num_online_cpus()));
484 channel->max_tx = adapter->max_tx_ques;
485
486 channel->rx_count = adapter->max_sds_rings;
487 channel->tx_count = adapter->max_tx_ques;
488}
489
490static int qlcnic_set_channels(struct net_device *dev,
491 struct ethtool_channels *channel)
492{
493 struct qlcnic_adapter *adapter = netdev_priv(dev);
494 int err;
495
496 if (channel->other_count || channel->combined_count ||
497 channel->tx_count != channel->max_tx)
498 return -EINVAL;
499
500 err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
501 if (err)
502 return err;
503
504 err = qlcnic_set_max_rss(adapter, channel->rx_count);
505 netdev_info(dev, "allocated 0x%x sds rings\n",
506 adapter->max_sds_rings);
507 return err;
508}
509
477static void 510static void
478qlcnic_get_pauseparam(struct net_device *netdev, 511qlcnic_get_pauseparam(struct net_device *netdev,
479 struct ethtool_pauseparam *pause) 512 struct ethtool_pauseparam *pause)
@@ -949,6 +982,8 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
949 .get_eeprom = qlcnic_get_eeprom, 982 .get_eeprom = qlcnic_get_eeprom,
950 .get_ringparam = qlcnic_get_ringparam, 983 .get_ringparam = qlcnic_get_ringparam,
951 .set_ringparam = qlcnic_set_ringparam, 984 .set_ringparam = qlcnic_set_ringparam,
985 .get_channels = qlcnic_get_channels,
986 .set_channels = qlcnic_set_channels,
952 .get_pauseparam = qlcnic_get_pauseparam, 987 .get_pauseparam = qlcnic_get_pauseparam,
953 .set_pauseparam = qlcnic_set_pauseparam, 988 .set_pauseparam = qlcnic_set_pauseparam,
954 .get_wol = qlcnic_get_wol, 989 .get_wol = qlcnic_get_wol,
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 6e619514feee..d6cc4d479591 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -18,6 +18,7 @@
18#include <linux/inetdevice.h> 18#include <linux/inetdevice.h>
19#include <linux/sysfs.h> 19#include <linux/sysfs.h>
20#include <linux/aer.h> 20#include <linux/aer.h>
21#include <linux/log2.h>
21 22
22MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); 23MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
23MODULE_LICENSE("GPL"); 24MODULE_LICENSE("GPL");
@@ -350,39 +351,17 @@ static struct qlcnic_nic_template qlcnic_vf_ops = {
350 .start_firmware = qlcnicvf_start_firmware 351 .start_firmware = qlcnicvf_start_firmware
351}; 352};
352 353
353static void 354static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
354qlcnic_setup_intr(struct qlcnic_adapter *adapter)
355{ 355{
356 const struct qlcnic_legacy_intr_set *legacy_intrp;
357 struct pci_dev *pdev = adapter->pdev; 356 struct pci_dev *pdev = adapter->pdev;
358 int err, num_msix; 357 int err = -1;
359
360 if (adapter->msix_supported) {
361 num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
362 MSIX_ENTRIES_PER_ADAPTER : 2;
363 } else
364 num_msix = 1;
365 358
366 adapter->max_sds_rings = 1; 359 adapter->max_sds_rings = 1;
367
368 adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); 360 adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
369
370 legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
371
372 adapter->int_vec_bit = legacy_intrp->int_vec_bit;
373 adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
374 legacy_intrp->tgt_status_reg);
375 adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
376 legacy_intrp->tgt_mask_reg);
377 adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
378
379 adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
380 ISR_INT_STATE_REG);
381
382 qlcnic_set_msix_bit(pdev, 0); 361 qlcnic_set_msix_bit(pdev, 0);
383 362
384 if (adapter->msix_supported) { 363 if (adapter->msix_supported) {
385 364 enable_msix:
386 qlcnic_init_msix_entries(adapter, num_msix); 365 qlcnic_init_msix_entries(adapter, num_msix);
387 err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); 366 err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
388 if (err == 0) { 367 if (err == 0) {
@@ -392,14 +371,22 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter)
392 adapter->max_sds_rings = num_msix; 371 adapter->max_sds_rings = num_msix;
393 372
394 dev_info(&pdev->dev, "using msi-x interrupts\n"); 373 dev_info(&pdev->dev, "using msi-x interrupts\n");
395 return; 374 return err;
396 } 375 }
376 if (err > 0) {
377 num_msix = rounddown_pow_of_two(err);
378 if (num_msix)
379 goto enable_msix;
380 }
381 }
382 return err;
383}
397 384
398 if (err > 0)
399 pci_disable_msix(pdev);
400 385
401 /* fall through for msi */ 386static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
402 } 387{
388 const struct qlcnic_legacy_intr_set *legacy_intrp;
389 struct pci_dev *pdev = adapter->pdev;
403 390
404 if (use_msi && !pci_enable_msi(pdev)) { 391 if (use_msi && !pci_enable_msi(pdev)) {
405 adapter->flags |= QLCNIC_MSI_ENABLED; 392 adapter->flags |= QLCNIC_MSI_ENABLED;
@@ -410,11 +397,41 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter)
410 return; 397 return;
411 } 398 }
412 399
400 legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
401
402 adapter->int_vec_bit = legacy_intrp->int_vec_bit;
403 adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
404 legacy_intrp->tgt_status_reg);
405 adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
406 legacy_intrp->tgt_mask_reg);
407 adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
408
409 adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
410 ISR_INT_STATE_REG);
413 dev_info(&pdev->dev, "using legacy interrupts\n"); 411 dev_info(&pdev->dev, "using legacy interrupts\n");
414 adapter->msix_entries[0].vector = pdev->irq; 412 adapter->msix_entries[0].vector = pdev->irq;
415} 413}
416 414
417static void 415static void
416qlcnic_setup_intr(struct qlcnic_adapter *adapter)
417{
418 int num_msix;
419
420 if (adapter->msix_supported) {
421 num_msix = (num_online_cpus() >=
422 QLCNIC_DEF_NUM_STS_DESC_RINGS) ?
423 QLCNIC_DEF_NUM_STS_DESC_RINGS :
424 QLCNIC_MIN_NUM_RSS_RINGS;
425 } else
426 num_msix = 1;
427
428 if (!qlcnic_enable_msix(adapter, num_msix))
429 return;
430
431 qlcnic_enable_msi_legacy(adapter);
432}
433
434static void
418qlcnic_teardown_intr(struct qlcnic_adapter *adapter) 435qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
419{ 436{
420 if (adapter->flags & QLCNIC_MSIX_ENABLED) 437 if (adapter->flags & QLCNIC_MSIX_ENABLED)
@@ -1493,6 +1510,19 @@ static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
1493 return 0; 1510 return 0;
1494} 1511}
1495 1512
1513static int
1514qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count)
1515{
1516 adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry),
1517 GFP_KERNEL);
1518
1519 if (adapter->msix_entries)
1520 return 0;
1521
1522 dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n");
1523 return -ENOMEM;
1524}
1525
1496static int __devinit 1526static int __devinit
1497qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 1527qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1498{ 1528{
@@ -1587,6 +1617,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1587 1617
1588 qlcnic_clear_stats(adapter); 1618 qlcnic_clear_stats(adapter);
1589 1619
1620 err = qlcnic_alloc_msix_entries(adapter, adapter->max_rx_ques);
1621 if (err)
1622 goto err_out_decr_ref;
1623
1590 qlcnic_setup_intr(adapter); 1624 qlcnic_setup_intr(adapter);
1591 1625
1592 err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac); 1626 err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
@@ -1615,6 +1649,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1615 1649
1616err_out_disable_msi: 1650err_out_disable_msi:
1617 qlcnic_teardown_intr(adapter); 1651 qlcnic_teardown_intr(adapter);
1652 kfree(adapter->msix_entries);
1618 1653
1619err_out_decr_ref: 1654err_out_decr_ref:
1620 qlcnic_clr_all_drv_state(adapter, 0); 1655 qlcnic_clr_all_drv_state(adapter, 0);
@@ -1666,6 +1701,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
1666 qlcnic_free_lb_filters_mem(adapter); 1701 qlcnic_free_lb_filters_mem(adapter);
1667 1702
1668 qlcnic_teardown_intr(adapter); 1703 qlcnic_teardown_intr(adapter);
1704 kfree(adapter->msix_entries);
1669 1705
1670 qlcnic_remove_diag_entries(adapter); 1706 qlcnic_remove_diag_entries(adapter);
1671 1707
@@ -3299,6 +3335,56 @@ static struct device_attribute dev_attr_diag_mode = {
3299 .store = qlcnic_store_diag_mode, 3335 .store = qlcnic_store_diag_mode,
3300}; 3336};
3301 3337
3338int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
3339{
3340 if (!use_msi_x && !use_msi) {
3341 netdev_info(netdev, "no msix or msi support, hence no rss\n");
3342 return -EINVAL;
3343 }
3344
3345 if ((val > max_hw) || (val < 2) || !is_power_of_2(val)) {
3346 netdev_info(netdev, "rss_ring valid range [2 - %x] in "
3347 " powers of 2\n", max_hw);
3348 return -EINVAL;
3349 }
3350 return 0;
3351
3352}
3353
3354int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
3355{
3356 struct net_device *netdev = adapter->netdev;
3357 int err = 0;
3358
3359 if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
3360 return -EBUSY;
3361
3362 netif_device_detach(netdev);
3363 if (netif_running(netdev))
3364 __qlcnic_down(adapter, netdev);
3365 qlcnic_detach(adapter);
3366 qlcnic_teardown_intr(adapter);
3367
3368 if (qlcnic_enable_msix(adapter, data)) {
3369 netdev_info(netdev, "failed setting max_rss; rss disabled\n");
3370 qlcnic_enable_msi_legacy(adapter);
3371 }
3372
3373 if (netif_running(netdev)) {
3374 err = qlcnic_attach(adapter);
3375 if (err)
3376 goto done;
3377 err = __qlcnic_up(adapter, netdev);
3378 if (err)
3379 goto done;
3380 qlcnic_restore_indev_addr(netdev, NETDEV_UP);
3381 }
3382 done:
3383 netif_device_attach(netdev);
3384 clear_bit(__QLCNIC_RESETTING, &adapter->state);
3385 return err;
3386}
3387
3302static int 3388static int
3303qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter, 3389qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
3304 loff_t offset, size_t size) 3390 loff_t offset, size_t size)