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 | |
| 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>
| -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 | 
