igb: Expose RSS indirection table for ethtool

This patch adds the ethtool callbacks necessary to change the RETA
indirection table from userspace.

In order to achieve this, we add the indirection table field (rss_indir_tbl)
in the board specific data structure (struct igb_adapter) to preserve the
values across hardware resets.

The indirection table must be initialized with default values in the
following cases:
	* at module init time
	* when the number of RX queues changes.
For this reason we add a new field (rss_indir_tbl_init) in igb_adapter
that keeps track of the number of RX queues. Whenever the number of RX
queues changes, the rss_indir_tbl is modified and initialized with default
values. The rss_indir_tbl_init is updated accordingly.

CC: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Laura Mihaela Vasilescu <laura.vasilescu@rosedu.org>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
Laura Mihaela Vasilescu 2013-07-31 20:19:54 +00:00 committed by Jeff Kirsher
parent c342b39ea7
commit ed12cc9a14
3 changed files with 97 additions and 21 deletions

View File

@ -446,6 +446,8 @@ struct igb_adapter {
struct i2c_algo_bit_data i2c_algo;
struct i2c_adapter i2c_adap;
struct i2c_client *i2c_client;
u32 rss_indir_tbl_init;
u8 rss_indir_tbl[IGB_RETA_SIZE];
};
#define IGB_FLAG_HAS_MSI (1 << 0)
@ -482,6 +484,7 @@ extern int igb_up(struct igb_adapter *);
extern void igb_down(struct igb_adapter *);
extern void igb_reinit_locked(struct igb_adapter *);
extern void igb_reset(struct igb_adapter *);
extern void igb_write_rss_indir_tbl(struct igb_adapter *);
extern int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
extern int igb_setup_tx_resources(struct igb_ring *);
extern int igb_setup_rx_resources(struct igb_ring *);

View File

@ -2784,6 +2784,90 @@ static void igb_ethtool_complete(struct net_device *netdev)
pm_runtime_put(&adapter->pdev->dev);
}
static u32 igb_get_rxfh_indir_size(struct net_device *netdev)
{
return IGB_RETA_SIZE;
}
static int igb_get_rxfh_indir(struct net_device *netdev, u32 *indir)
{
struct igb_adapter *adapter = netdev_priv(netdev);
int i;
for (i = 0; i < IGB_RETA_SIZE; i++)
indir[i] = adapter->rss_indir_tbl[i];
return 0;
}
void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 reg = E1000_RETA(0);
u32 shift = 0;
int i = 0;
switch (hw->mac.type) {
case e1000_82575:
shift = 6;
break;
case e1000_82576:
/* 82576 supports 2 RSS queues for SR-IOV */
if (adapter->vfs_allocated_count)
shift = 3;
break;
default:
break;
}
while (i < IGB_RETA_SIZE) {
u32 val = 0;
int j;
for (j = 3; j >= 0; j--) {
val <<= 8;
val |= adapter->rss_indir_tbl[i + j];
}
wr32(reg, val << shift);
reg += 4;
i += 4;
}
}
static int igb_set_rxfh_indir(struct net_device *netdev, const u32 *indir)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
int i;
u32 num_queues;
num_queues = adapter->rss_queues;
switch (hw->mac.type) {
case e1000_82576:
/* 82576 supports 2 RSS queues for SR-IOV */
if (adapter->vfs_allocated_count)
num_queues = 2;
break;
default:
break;
}
/* Verify user input. */
for (i = 0; i < IGB_RETA_SIZE; i++)
if (indir[i] >= num_queues)
return -EINVAL;
for (i = 0; i < IGB_RETA_SIZE; i++)
adapter->rss_indir_tbl[i] = indir[i];
igb_write_rss_indir_tbl(adapter);
return 0;
}
static const struct ethtool_ops igb_ethtool_ops = {
.get_settings = igb_get_settings,
.set_settings = igb_set_settings,
@ -2817,6 +2901,9 @@ static const struct ethtool_ops igb_ethtool_ops = {
.set_eee = igb_set_eee,
.get_module_info = igb_get_module_info,
.get_module_eeprom = igb_get_module_eeprom,
.get_rxfh_indir_size = igb_get_rxfh_indir_size,
.get_rxfh_indir = igb_get_rxfh_indir,
.set_rxfh_indir = igb_set_rxfh_indir,
.begin = igb_ethtool_begin,
.complete = igb_ethtool_complete,
};

View File

@ -3126,7 +3126,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum;
u32 j, num_rx_queues, shift = 0;
u32 j, num_rx_queues;
static const u32 rsskey[10] = { 0xDA565A6D, 0xC20E5B25, 0x3D256741,
0xB08FA343, 0xCB2BCAD0, 0xB4307BAE,
0xA32DCB77, 0x0CF23080, 0x3BB7426A,
@ -3139,35 +3139,21 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
num_rx_queues = adapter->rss_queues;
switch (hw->mac.type) {
case e1000_82575:
shift = 6;
break;
case e1000_82576:
/* 82576 supports 2 RSS queues for SR-IOV */
if (adapter->vfs_allocated_count) {
shift = 3;
if (adapter->vfs_allocated_count)
num_rx_queues = 2;
}
break;
default:
break;
}
/* Populate the indirection table 4 entries at a time. To do this
* we are generating the results for n and n+2 and then interleaving
* those with the results with n+1 and n+3.
*/
for (j = 0; j < IGB_RETA_SIZE / 4; j++) {
/* first pass generates n and n+2 */
u32 base = ((j * 0x00040004) + 0x00020000) * num_rx_queues;
u32 reta = (base & 0x07800780) >> (7 - shift);
/* second pass generates n+1 and n+3 */
base += 0x00010001 * num_rx_queues;
reta |= (base & 0x07800780) << (1 + shift);
wr32(E1000_RETA(j), reta);
if (adapter->rss_indir_tbl_init != num_rx_queues) {
for (j = 0; j < IGB_RETA_SIZE; j++)
adapter->rss_indir_tbl[j] = (j * num_rx_queues) / IGB_RETA_SIZE;
adapter->rss_indir_tbl_init = num_rx_queues;
}
igb_write_rss_indir_tbl(adapter);
/* Disable raw packet checksumming so that RSS hash is placed in
* descriptor on writeback. No need to enable TCP/UDP/IP checksum