diff options
author | Dimitris Michailidis <dm@chelsio.com> | 2010-07-11 08:01:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-11 20:07:46 -0400 |
commit | 671b0060d82984a566f2e75ffd166a9b61c6da7d (patch) | |
tree | 13fe5d130f8d837f095563fca1d1e7546c9c3464 /drivers/net/cxgb4 | |
parent | 065463915c3a2a2ce142f64ed3ed591d72ad88b1 (diff) |
cxgb4: add user manipulation of the RSS table
Implement the get_rxnfc, get_rxfh_indir, and set_rxfh_indir ethtool
methods for user manipulation of the RSS table. Besides the methods
themselves the rest of the changes here store, initialize, and write
the table contents.
Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/cxgb4')
-rw-r--r-- | drivers/net/cxgb4/cxgb4.h | 1 | ||||
-rw-r--r-- | drivers/net/cxgb4/cxgb4_main.c | 113 |
2 files changed, 98 insertions, 16 deletions
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h index 62804bb4022d..a614eb5d85d5 100644 --- a/drivers/net/cxgb4/cxgb4.h +++ b/drivers/net/cxgb4/cxgb4.h | |||
@@ -295,6 +295,7 @@ struct port_info { | |||
295 | u8 nqsets; /* # of qsets */ | 295 | u8 nqsets; /* # of qsets */ |
296 | u8 first_qset; /* index of first qset */ | 296 | u8 first_qset; /* index of first qset */ |
297 | struct link_config link_cfg; | 297 | struct link_config link_cfg; |
298 | u16 *rss; | ||
298 | }; | 299 | }; |
299 | 300 | ||
300 | /* port_info.rx_offload flags */ | 301 | /* port_info.rx_offload flags */ |
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index 653bb546edd3..61d43130eff2 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c | |||
@@ -597,30 +597,47 @@ static void free_msix_queue_irqs(struct adapter *adap) | |||
597 | } | 597 | } |
598 | 598 | ||
599 | /** | 599 | /** |
600 | * write_rss - write the RSS table for a given port | ||
601 | * @pi: the port | ||
602 | * @queues: array of queue indices for RSS | ||
603 | * | ||
604 | * Sets up the portion of the HW RSS table for the port's VI to distribute | ||
605 | * packets to the Rx queues in @queues. | ||
606 | */ | ||
607 | static int write_rss(const struct port_info *pi, const u16 *queues) | ||
608 | { | ||
609 | u16 *rss; | ||
610 | int i, err; | ||
611 | const struct sge_eth_rxq *q = &pi->adapter->sge.ethrxq[pi->first_qset]; | ||
612 | |||
613 | rss = kmalloc(pi->rss_size * sizeof(u16), GFP_KERNEL); | ||
614 | if (!rss) | ||
615 | return -ENOMEM; | ||
616 | |||
617 | /* map the queue indices to queue ids */ | ||
618 | for (i = 0; i < pi->rss_size; i++, queues++) | ||
619 | rss[i] = q[*queues].rspq.abs_id; | ||
620 | |||
621 | err = t4_config_rss_range(pi->adapter, 0, pi->viid, 0, pi->rss_size, | ||
622 | rss, pi->rss_size); | ||
623 | kfree(rss); | ||
624 | return err; | ||
625 | } | ||
626 | |||
627 | /** | ||
600 | * setup_rss - configure RSS | 628 | * setup_rss - configure RSS |
601 | * @adap: the adapter | 629 | * @adap: the adapter |
602 | * | 630 | * |
603 | * Sets up RSS to distribute packets to multiple receive queues. We | 631 | * Sets up RSS for each port. |
604 | * configure the RSS CPU lookup table to distribute to the number of HW | ||
605 | * receive queues, and the response queue lookup table to narrow that | ||
606 | * down to the response queues actually configured for each port. | ||
607 | * We always configure the RSS mapping for all ports since the mapping | ||
608 | * table has plenty of entries. | ||
609 | */ | 632 | */ |
610 | static int setup_rss(struct adapter *adap) | 633 | static int setup_rss(struct adapter *adap) |
611 | { | 634 | { |
612 | int i, j, err; | 635 | int i, err; |
613 | u16 rss[MAX_ETH_QSETS]; | ||
614 | 636 | ||
615 | for_each_port(adap, i) { | 637 | for_each_port(adap, i) { |
616 | const struct port_info *pi = adap2pinfo(adap, i); | 638 | const struct port_info *pi = adap2pinfo(adap, i); |
617 | const struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; | ||
618 | |||
619 | for (j = 0; j < pi->nqsets; j++) | ||
620 | rss[j] = q[j].rspq.abs_id; | ||
621 | 639 | ||
622 | err = t4_config_rss_range(adap, 0, pi->viid, 0, pi->rss_size, | 640 | err = write_rss(pi, pi->rss); |
623 | rss, pi->nqsets); | ||
624 | if (err) | 641 | if (err) |
625 | return err; | 642 | return err; |
626 | } | 643 | } |
@@ -1802,6 +1819,46 @@ static int set_flags(struct net_device *dev, u32 flags) | |||
1802 | return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH); | 1819 | return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH); |
1803 | } | 1820 | } |
1804 | 1821 | ||
1822 | static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p) | ||
1823 | { | ||
1824 | const struct port_info *pi = netdev_priv(dev); | ||
1825 | unsigned int n = min_t(unsigned int, p->size, pi->rss_size); | ||
1826 | |||
1827 | p->size = pi->rss_size; | ||
1828 | while (n--) | ||
1829 | p->ring_index[n] = pi->rss[n]; | ||
1830 | return 0; | ||
1831 | } | ||
1832 | |||
1833 | static int set_rss_table(struct net_device *dev, | ||
1834 | const struct ethtool_rxfh_indir *p) | ||
1835 | { | ||
1836 | unsigned int i; | ||
1837 | struct port_info *pi = netdev_priv(dev); | ||
1838 | |||
1839 | if (p->size != pi->rss_size) | ||
1840 | return -EINVAL; | ||
1841 | for (i = 0; i < p->size; i++) | ||
1842 | if (p->ring_index[i] >= pi->nqsets) | ||
1843 | return -EINVAL; | ||
1844 | for (i = 0; i < p->size; i++) | ||
1845 | pi->rss[i] = p->ring_index[i]; | ||
1846 | if (pi->adapter->flags & FULL_INIT_DONE) | ||
1847 | return write_rss(pi, pi->rss); | ||
1848 | return 0; | ||
1849 | } | ||
1850 | |||
1851 | static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, | ||
1852 | void *rules) | ||
1853 | { | ||
1854 | switch (info->cmd) { | ||
1855 | case ETHTOOL_GRXRINGS: | ||
1856 | info->data = netdev2pinfo(dev)->nqsets; | ||
1857 | return 0; | ||
1858 | } | ||
1859 | return -EOPNOTSUPP; | ||
1860 | } | ||
1861 | |||
1805 | static struct ethtool_ops cxgb_ethtool_ops = { | 1862 | static struct ethtool_ops cxgb_ethtool_ops = { |
1806 | .get_settings = get_settings, | 1863 | .get_settings = get_settings, |
1807 | .set_settings = set_settings, | 1864 | .set_settings = set_settings, |
@@ -1833,6 +1890,9 @@ static struct ethtool_ops cxgb_ethtool_ops = { | |||
1833 | .set_wol = set_wol, | 1890 | .set_wol = set_wol, |
1834 | .set_tso = set_tso, | 1891 | .set_tso = set_tso, |
1835 | .set_flags = set_flags, | 1892 | .set_flags = set_flags, |
1893 | .get_rxnfc = get_rxnfc, | ||
1894 | .get_rxfh_indir = get_rss_table, | ||
1895 | .set_rxfh_indir = set_rss_table, | ||
1836 | .flash_device = set_flash, | 1896 | .flash_device = set_flash, |
1837 | }; | 1897 | }; |
1838 | 1898 | ||
@@ -3318,6 +3378,22 @@ static int __devinit enable_msix(struct adapter *adap) | |||
3318 | 3378 | ||
3319 | #undef EXTRA_VECS | 3379 | #undef EXTRA_VECS |
3320 | 3380 | ||
3381 | static int __devinit init_rss(struct adapter *adap) | ||
3382 | { | ||
3383 | unsigned int i, j; | ||
3384 | |||
3385 | for_each_port(adap, i) { | ||
3386 | struct port_info *pi = adap2pinfo(adap, i); | ||
3387 | |||
3388 | pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL); | ||
3389 | if (!pi->rss) | ||
3390 | return -ENOMEM; | ||
3391 | for (j = 0; j < pi->rss_size; j++) | ||
3392 | pi->rss[j] = j % pi->nqsets; | ||
3393 | } | ||
3394 | return 0; | ||
3395 | } | ||
3396 | |||
3321 | static void __devinit print_port_info(struct adapter *adap) | 3397 | static void __devinit print_port_info(struct adapter *adap) |
3322 | { | 3398 | { |
3323 | static const char *base[] = { | 3399 | static const char *base[] = { |
@@ -3380,9 +3456,10 @@ static void free_some_resources(struct adapter *adapter) | |||
3380 | disable_msi(adapter); | 3456 | disable_msi(adapter); |
3381 | 3457 | ||
3382 | for_each_port(adapter, i) | 3458 | for_each_port(adapter, i) |
3383 | if (adapter->port[i]) | 3459 | if (adapter->port[i]) { |
3460 | kfree(adap2pinfo(adapter, i)->rss); | ||
3384 | free_netdev(adapter->port[i]); | 3461 | free_netdev(adapter->port[i]); |
3385 | 3462 | } | |
3386 | if (adapter->flags & FW_OK) | 3463 | if (adapter->flags & FW_OK) |
3387 | t4_fw_bye(adapter, 0); | 3464 | t4_fw_bye(adapter, 0); |
3388 | } | 3465 | } |
@@ -3536,6 +3613,10 @@ static int __devinit init_one(struct pci_dev *pdev, | |||
3536 | else if (msi > 0 && pci_enable_msi(pdev) == 0) | 3613 | else if (msi > 0 && pci_enable_msi(pdev) == 0) |
3537 | adapter->flags |= USING_MSI; | 3614 | adapter->flags |= USING_MSI; |
3538 | 3615 | ||
3616 | err = init_rss(adapter); | ||
3617 | if (err) | ||
3618 | goto out_free_dev; | ||
3619 | |||
3539 | /* | 3620 | /* |
3540 | * The card is now ready to go. If any errors occur during device | 3621 | * The card is now ready to go. If any errors occur during device |
3541 | * registration we do not fail the whole card but rather proceed only | 3622 | * registration we do not fail the whole card but rather proceed only |