Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 671b0060 authored by Dimitris Michailidis's avatar Dimitris Michailidis Committed by David S. Miller
Browse files

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: default avatarDimitris Michailidis <dm@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 06546391
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -295,6 +295,7 @@ struct port_info {
	u8     nqsets;                /* # of qsets */
	u8     first_qset;            /* index of first qset */
	struct link_config link_cfg;
	u16   *rss;
};

/* port_info.rx_offload flags */
+97 −16
Original line number Diff line number Diff line
@@ -596,31 +596,48 @@ static void free_msix_queue_irqs(struct adapter *adap)
		free_irq(adap->msix_info[msi++].vec, &s->rdmarxq[i].rspq);
}

/**
 *	write_rss - write the RSS table for a given port
 *	@pi: the port
 *	@queues: array of queue indices for RSS
 *
 *	Sets up the portion of the HW RSS table for the port's VI to distribute
 *	packets to the Rx queues in @queues.
 */
static int write_rss(const struct port_info *pi, const u16 *queues)
{
	u16 *rss;
	int i, err;
	const struct sge_eth_rxq *q = &pi->adapter->sge.ethrxq[pi->first_qset];

	rss = kmalloc(pi->rss_size * sizeof(u16), GFP_KERNEL);
	if (!rss)
		return -ENOMEM;

	/* map the queue indices to queue ids */
	for (i = 0; i < pi->rss_size; i++, queues++)
		rss[i] = q[*queues].rspq.abs_id;

	err = t4_config_rss_range(pi->adapter, 0, pi->viid, 0, pi->rss_size,
				  rss, pi->rss_size);
	kfree(rss);
	return err;
}

/**
 *	setup_rss - configure RSS
 *	@adap: the adapter
 *
 *	Sets up RSS to distribute packets to multiple receive queues.  We
 *	configure the RSS CPU lookup table to distribute to the number of HW
 *	receive queues, and the response queue lookup table to narrow that
 *	down to the response queues actually configured for each port.
 *	We always configure the RSS mapping for all ports since the mapping
 *	table has plenty of entries.
 *	Sets up RSS for each port.
 */
static int setup_rss(struct adapter *adap)
{
	int i, j, err;
	u16 rss[MAX_ETH_QSETS];
	int i, err;

	for_each_port(adap, i) {
		const struct port_info *pi = adap2pinfo(adap, i);
		const struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset];

		for (j = 0; j < pi->nqsets; j++)
			rss[j] = q[j].rspq.abs_id;

		err = t4_config_rss_range(adap, 0, pi->viid, 0, pi->rss_size,
					  rss, pi->nqsets);
		err = write_rss(pi, pi->rss);
		if (err)
			return err;
	}
@@ -1802,6 +1819,46 @@ static int set_flags(struct net_device *dev, u32 flags)
	return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH);
}

static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p)
{
	const struct port_info *pi = netdev_priv(dev);
	unsigned int n = min_t(unsigned int, p->size, pi->rss_size);

	p->size = pi->rss_size;
	while (n--)
		p->ring_index[n] = pi->rss[n];
	return 0;
}

static int set_rss_table(struct net_device *dev,
			 const struct ethtool_rxfh_indir *p)
{
	unsigned int i;
	struct port_info *pi = netdev_priv(dev);

	if (p->size != pi->rss_size)
		return -EINVAL;
	for (i = 0; i < p->size; i++)
		if (p->ring_index[i] >= pi->nqsets)
			return -EINVAL;
	for (i = 0; i < p->size; i++)
		pi->rss[i] = p->ring_index[i];
	if (pi->adapter->flags & FULL_INIT_DONE)
		return write_rss(pi, pi->rss);
	return 0;
}

static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
		     void *rules)
{
	switch (info->cmd) {
	case ETHTOOL_GRXRINGS:
		info->data = netdev2pinfo(dev)->nqsets;
		return 0;
	}
	return -EOPNOTSUPP;
}

static struct ethtool_ops cxgb_ethtool_ops = {
	.get_settings      = get_settings,
	.set_settings      = set_settings,
@@ -1833,6 +1890,9 @@ static struct ethtool_ops cxgb_ethtool_ops = {
	.set_wol           = set_wol,
	.set_tso           = set_tso,
	.set_flags         = set_flags,
	.get_rxnfc         = get_rxnfc,
	.get_rxfh_indir    = get_rss_table,
	.set_rxfh_indir    = set_rss_table,
	.flash_device      = set_flash,
};

@@ -3318,6 +3378,22 @@ static int __devinit enable_msix(struct adapter *adap)

#undef EXTRA_VECS

static int __devinit init_rss(struct adapter *adap)
{
	unsigned int i, j;

	for_each_port(adap, i) {
		struct port_info *pi = adap2pinfo(adap, i);

		pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL);
		if (!pi->rss)
			return -ENOMEM;
		for (j = 0; j < pi->rss_size; j++)
			pi->rss[j] = j % pi->nqsets;
	}
	return 0;
}

static void __devinit print_port_info(struct adapter *adap)
{
	static const char *base[] = {
@@ -3380,9 +3456,10 @@ static void free_some_resources(struct adapter *adapter)
	disable_msi(adapter);

	for_each_port(adapter, i)
		if (adapter->port[i])
		if (adapter->port[i]) {
			kfree(adap2pinfo(adapter, i)->rss);
			free_netdev(adapter->port[i]);

		}
	if (adapter->flags & FW_OK)
		t4_fw_bye(adapter, 0);
}
@@ -3536,6 +3613,10 @@ static int __devinit init_one(struct pci_dev *pdev,
	else if (msi > 0 && pci_enable_msi(pdev) == 0)
		adapter->flags |= USING_MSI;

	err = init_rss(adapter);
	if (err)
		goto out_free_dev;

	/*
	 * The card is now ready to go.  If any errors occur during device
	 * registration we do not fail the whole card but rather proceed only