Commit d52bfbda authored by David S. Miller's avatar David S. Miller

Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue

Jeff Kirsher says:

====================
40GbE Intel Wired LAN Driver Updates 2016-08-18

This series contains updates to i40e and i40evf only.

Wei Yongjun updates i40e to use list_move() instead of list_del() &
list_add() operations.

Anjali fixes an issue where the client->open call was not protected with
the client instance mutex, which allowed client->close to be called before
the open all completed.

Catherine makes sure that the VLAN count (and stats) gets reset to 0
after reset.

Jake provides two patches, first adds the needed rtnl lock around
i40evf_set_interrupt_capability() since i40evf_init_task() does not
hold the rtnl_lock.  Second fixes an issue where users could reduce
the number of channels (queues) below the current flow director
filter rules targets.

Dave fixes a problem where a static analysis tool generates a warning
so eliminating the irrelevant check and redundant assignment for the
value of enabled_tc.

Avinash fixes an sync issue where the iWARP device open is called
before the PCI register writes are completed, so ensure the register
writes complete before exiting the setup function.

Alan fixes a bug which causes RSS to continue to work after being
disabled.

Carolyn implements a feature change which allows using ethtool to set
RDD hash options using less than four parameters if desired.

Dan Carpenter cleans up a stray unlock.

Sridhar exposes the "trust" flag to userspace via ndo_get_vf_config().
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 60747ef4 d40062f3
......@@ -586,9 +586,6 @@ struct i40e_vsi {
/* VSI specific handlers */
irqreturn_t (*irq_handler)(int irq, void *data);
/* current rxnfc data */
struct ethtool_rxnfc rxnfc; /* current rss hash opts */
} ____cacheline_internodealigned_in_smp;
struct i40e_netdev_priv {
......
......@@ -541,6 +541,7 @@ void i40e_client_subtask(struct i40e_pf *pf)
client->name, pf->hw.pf_id,
pf->hw.bus.device, pf->hw.bus.func);
mutex_lock(&i40e_client_instance_mutex);
/* Send an Open request to the client */
atomic_inc(&cdev->ref_cnt);
if (client->ops && client->ops->open)
......@@ -554,6 +555,7 @@ void i40e_client_subtask(struct i40e_pf *pf)
atomic_dec(&client->ref_cnt);
continue;
}
mutex_unlock(&i40e_client_instance_mutex);
}
mutex_unlock(&i40e_client_mutex);
}
......@@ -662,8 +664,7 @@ static int i40e_client_release(struct i40e_client *client)
client->name, pf->hw.pf_id);
}
/* delete the client instance from the list */
list_del(&cdev->list);
list_add(&cdev->list, &cdevs_tmp);
list_move(&cdev->list, &cdevs_tmp);
atomic_dec(&client->ref_cnt);
dev_info(&pf->pdev->dev, "Deleted client instance of Client %s\n",
client->name);
......@@ -792,7 +793,8 @@ static int i40e_client_setup_qvlist(struct i40e_info *ldev,
wr32(hw, I40E_PFINT_AEQCTL, reg);
}
}
/* Mitigate sync problems with iwarp VF driver */
i40e_flush(hw);
return 0;
err:
kfree(ldev->qvlist_info);
......@@ -990,7 +992,6 @@ int i40e_unregister_client(struct i40e_client *client)
if (!i40e_client_is_registered(client)) {
pr_info("i40e: Client %s has not been registered\n",
client->name);
mutex_unlock(&i40e_client_mutex);
ret = -ENODEV;
goto out;
}
......
......@@ -2141,41 +2141,72 @@ static int i40e_set_per_queue_coalesce(struct net_device *netdev, u32 queue,
**/
static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
{
struct i40e_hw *hw = &pf->hw;
u8 flow_pctype = 0;
u64 i_set = 0;
cmd->data = 0;
if (pf->vsi[pf->lan_vsi]->rxnfc.data != 0) {
cmd->data = pf->vsi[pf->lan_vsi]->rxnfc.data;
cmd->flow_type = pf->vsi[pf->lan_vsi]->rxnfc.flow_type;
return 0;
}
/* Report default options for RSS on i40e */
switch (cmd->flow_type) {
case TCP_V4_FLOW:
flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
break;
case UDP_V4_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through to add IP fields */
flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
break;
case TCP_V6_FLOW:
flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
break;
case UDP_V6_FLOW:
flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
break;
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case IPV4_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through to add IP fields */
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV6_FLOW:
/* Default is src/dest for IP, no matter the L4 hashing */
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
default:
return -EINVAL;
}
/* Read flow based hash input set register */
if (flow_pctype) {
i_set = (u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0,
flow_pctype)) |
((u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1,
flow_pctype)) << 32);
}
/* Process bits of hash input set */
if (i_set) {
if (i_set & I40E_L4_SRC_MASK)
cmd->data |= RXH_L4_B_0_1;
if (i_set & I40E_L4_DST_MASK)
cmd->data |= RXH_L4_B_2_3;
if (cmd->flow_type == TCP_V4_FLOW ||
cmd->flow_type == UDP_V4_FLOW) {
if (i_set & I40E_L3_SRC_MASK)
cmd->data |= RXH_IP_SRC;
if (i_set & I40E_L3_DST_MASK)
cmd->data |= RXH_IP_DST;
} else if (cmd->flow_type == TCP_V6_FLOW ||
cmd->flow_type == UDP_V6_FLOW) {
if (i_set & I40E_L3_V6_SRC_MASK)
cmd->data |= RXH_IP_SRC;
if (i_set & I40E_L3_V6_DST_MASK)
cmd->data |= RXH_IP_DST;
}
}
return 0;
}
......@@ -2317,6 +2348,51 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
return ret;
}
/**
* i40e_get_rss_hash_bits - Read RSS Hash bits from register
* @nfc: pointer to user request
* @i_setc bits currently set
*
* Returns value of bits to be set per user request
**/
static u64 i40e_get_rss_hash_bits(struct ethtool_rxnfc *nfc, u64 i_setc)
{
u64 i_set = i_setc;
u64 src_l3 = 0, dst_l3 = 0;
if (nfc->data & RXH_L4_B_0_1)
i_set |= I40E_L4_SRC_MASK;
else
i_set &= ~I40E_L4_SRC_MASK;
if (nfc->data & RXH_L4_B_2_3)
i_set |= I40E_L4_DST_MASK;
else
i_set &= ~I40E_L4_DST_MASK;
if (nfc->flow_type == TCP_V6_FLOW || nfc->flow_type == UDP_V6_FLOW) {
src_l3 = I40E_L3_V6_SRC_MASK;
dst_l3 = I40E_L3_V6_DST_MASK;
} else if (nfc->flow_type == TCP_V4_FLOW ||
nfc->flow_type == UDP_V4_FLOW) {
src_l3 = I40E_L3_SRC_MASK;
dst_l3 = I40E_L3_DST_MASK;
} else {
/* Any other flow type are not supported here */
return i_set;
}
if (nfc->data & RXH_IP_SRC)
i_set |= src_l3;
else
i_set &= ~src_l3;
if (nfc->data & RXH_IP_DST)
i_set |= dst_l3;
else
i_set &= ~dst_l3;
return i_set;
}
/**
* i40e_set_rss_hash_opt - Enable/Disable flow types for RSS hash
* @pf: pointer to the physical function struct
......@@ -2329,6 +2405,8 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
struct i40e_hw *hw = &pf->hw;
u64 hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
u8 flow_pctype = 0;
u64 i_set, i_setc;
/* RSS does not support anything other than hashing
* to queues on src and dst IPs and ports
......@@ -2337,75 +2415,39 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
RXH_L4_B_0_1 | RXH_L4_B_2_3))
return -EINVAL;
/* We need at least the IP SRC and DEST fields for hashing */
if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST))
return -EINVAL;
switch (nfc->flow_type) {
case TCP_V4_FLOW:
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
return -EINVAL;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
break;
default:
return -EINVAL;
}
flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
break;
case TCP_V6_FLOW:
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
return -EINVAL;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK);
hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
break;
default:
return -EINVAL;
}
flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK);
break;
case UDP_V4_FLOW:
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
return -EINVAL;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP);
hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
break;
default:
return -EINVAL;
}
flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP);
hena |= BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4);
break;
case UDP_V6_FLOW:
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
return -EINVAL;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP);
hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
break;
default:
return -EINVAL;
}
flow_pctype = I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE)
hena |=
BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP);
hena |= BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6);
break;
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
......@@ -2437,13 +2479,23 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
return -EINVAL;
}
if (flow_pctype) {
i_setc = (u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0,
flow_pctype)) |
((u64)i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1,
flow_pctype)) << 32);
i_set = i40e_get_rss_hash_bits(nfc, i_setc);
i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, flow_pctype),
(u32)i_set);
i40e_write_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, flow_pctype),
(u32)(i_set >> 32));
hena |= BIT_ULL(flow_pctype);
}
i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
i40e_flush(hw);
/* Save setting for future output/update */
pf->vsi[pf->lan_vsi]->rxnfc = *nfc;
return 0;
}
......@@ -2744,11 +2796,15 @@ static void i40e_get_channels(struct net_device *dev,
static int i40e_set_channels(struct net_device *dev,
struct ethtool_channels *ch)
{
const u8 drop = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET;
struct i40e_netdev_priv *np = netdev_priv(dev);
unsigned int count = ch->combined_count;
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
struct i40e_fdir_filter *rule;
struct hlist_node *node2;
int new_count;
int err = 0;
/* We do not support setting channels for any other VSI at present */
if (vsi->type != I40E_VSI_MAIN)
......@@ -2766,6 +2822,26 @@ static int i40e_set_channels(struct net_device *dev,
if (count > i40e_max_channels(vsi))
return -EINVAL;
/* verify that the number of channels does not invalidate any current
* flow director rules
*/
hlist_for_each_entry_safe(rule, node2,
&pf->fdir_filter_list, fdir_node) {
if (rule->dest_ctl != drop && count <= rule->q_index) {
dev_warn(&pf->pdev->dev,
"Existing user defined filter %d assigns flow to queue %d\n",
rule->fd_id, rule->q_index);
err = -EINVAL;
}
}
if (err) {
dev_err(&pf->pdev->dev,
"Existing filter rules must be deleted to reduce combined channel count to %d\n",
count);
return err;
}
/* update feature limits from largest to smallest supported values */
/* TODO: Flow director limit, DCB etc */
......
......@@ -41,7 +41,7 @@ static const char i40e_driver_string[] =
#define DRV_VERSION_MAJOR 1
#define DRV_VERSION_MINOR 6
#define DRV_VERSION_BUILD 11
#define DRV_VERSION_BUILD 12
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN
......@@ -527,6 +527,7 @@ void i40e_pf_reset_stats(struct i40e_pf *pf)
pf->veb[i]->stat_offsets_loaded = false;
}
}
pf->hw_csum_rx_error = 0;
}
/**
......@@ -4616,7 +4617,7 @@ static u8 i40e_dcb_get_enabled_tc(struct i40e_dcbx_config *dcbcfg)
static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
{
struct i40e_hw *hw = &pf->hw;
u8 i, enabled_tc;
u8 i, enabled_tc = 1;
u8 num_tc = 0;
struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config;
......@@ -4634,8 +4635,6 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
else
return 1; /* Only TC0 */
/* At least have TC0 */
enabled_tc = (enabled_tc ? enabled_tc : 0x1);
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
if (enabled_tc & BIT(i))
num_tc++;
......@@ -8691,6 +8690,28 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
return need_reset;
}
/**
* i40e_clear_rss_lut - clear the rx hash lookup table
* @vsi: the VSI being configured
**/
static void i40e_clear_rss_lut(struct i40e_vsi *vsi)
{
struct i40e_pf *pf = vsi->back;
struct i40e_hw *hw = &pf->hw;
u16 vf_id = vsi->vf_id;
u8 i;
if (vsi->type == I40E_VSI_MAIN) {
for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++)
wr32(hw, I40E_PFQF_HLUT(i), 0);
} else if (vsi->type == I40E_VSI_SRIOV) {
for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++)
i40e_write_rx_ctl(hw, I40E_VFQF_HLUT1(i, vf_id), 0);
} else {
dev_err(&pf->pdev->dev, "Cannot set RSS LUT - invalid VSI type\n");
}
}
/**
* i40e_set_features - set the netdev feature flags
* @netdev: ptr to the netdev being adjusted
......@@ -8704,6 +8725,12 @@ static int i40e_set_features(struct net_device *netdev,
struct i40e_pf *pf = vsi->back;
bool need_reset;
if (features & NETIF_F_RXHASH && !(netdev->features & NETIF_F_RXHASH))
i40e_pf_config_rss(pf);
else if (!(features & NETIF_F_RXHASH) &&
netdev->features & NETIF_F_RXHASH)
i40e_clear_rss_lut(vsi);
if (features & NETIF_F_HW_VLAN_CTAG_RX)
i40e_vlan_stripping_enable(vsi);
else
......
......@@ -991,7 +991,10 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
i40e_enable_vf_mappings(vf);
set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
clear_bit(I40E_VF_STAT_DISABLED, &vf->vf_states);
i40e_notify_client_of_vf_reset(pf, abs_vf_id);
/* Do not notify the client during VF init */
if (vf->pf->num_alloc_vfs)
i40e_notify_client_of_vf_reset(pf, abs_vf_id);
vf->num_vlan = 0;
}
/* tell the VF the reset is done */
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
......@@ -1089,7 +1092,6 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
goto err_iov;
}
}
i40e_notify_client_of_vf_enable(pf, num_alloc_vfs);
/* allocate memory */
vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL);
if (!vfs) {
......@@ -1113,6 +1115,8 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
}
pf->num_alloc_vfs = num_alloc_vfs;
i40e_notify_client_of_vf_enable(pf, num_alloc_vfs);
err_alloc:
if (ret)
i40e_free_vfs(pf);
......@@ -2314,6 +2318,7 @@ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen)
/* send the response back to the VF */
aq_ret = i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS,
aq_ret, (u8 *)vrh, len);
kfree(vrh);
return aq_ret;
}
......@@ -2995,6 +3000,7 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
else
ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
ivi->spoofchk = vf->spoofchk;
ivi->trusted = vf->trusted;
ret = 0;
error_param:
......
......@@ -38,7 +38,7 @@ static const char i40evf_driver_string[] =
#define DRV_VERSION_MAJOR 1
#define DRV_VERSION_MINOR 6
#define DRV_VERSION_BUILD 11
#define DRV_VERSION_BUILD 12
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) \
......@@ -1420,7 +1420,9 @@ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter)
{
int err;
rtnl_lock();
err = i40evf_set_interrupt_capability(adapter);
rtnl_unlock();
if (err) {
dev_err(&adapter->pdev->dev,
"Unable to setup interrupt capabilities\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment