Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next

Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates

This series contains updates to i40e and i40evf.

Jacob provides a i40e patch to remove ptp_tx_work() because it conflicts
with the interrupt-based handler and will cause spurious warning messages
to be displayed in the kernel log.  Since the hardware can properly trigger
an interrupt, we do not need to poll for an available timestamp in a work
queue any more.

Greg provides two patches for i40e, first to retain the MAC filter list
when changing a port VLAN.  Second fixes an issue where the function to
set the VF MAC address was not taking the port VLAN filter into account
when setting/clearing/resetting the VF's host administered MAC address.

Mitch provides three patches for i40evf, first adds support for getting
and setting RSS hashing options, RSS LUT entries, and getting the number
of device channels from ethtool.  Fixes a panic that woudl occur in the VF
if the PF driver failed or was removed from the host kernel.

Shannon adds driver version string to the driver version command so that
can be passed down through the firmware to low-level NC-SI functions.

Neerav provides several patches, first redistributes queue vectors after
DCB reconfiguration because the total number of queues that are configured
for a VSI may change based on a change in the total number of TCs enabled
as a result of a change in the DCB configuration based on DCBX.  Second,
allows the driver probe to continue when querying DCB config fails.
Lastly, provides changes to retrieve and store missing link config
information that was not being cached in the struct i40e_link_status.

Kevin provides a couple of patches, first to change a int variable type
to u16 to avoid a typecheck failure.  Second to update a function
parameters to remove an argument which is no longer used.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2014-04-28 14:53:00 -04:00
commit ed036f809a
12 changed files with 373 additions and 68 deletions

View File

@ -329,9 +329,7 @@ struct i40e_pf {
struct ptp_clock *ptp_clock; struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps; struct ptp_clock_info ptp_caps;
struct sk_buff *ptp_tx_skb; struct sk_buff *ptp_tx_skb;
struct work_struct ptp_tx_work;
struct hwtstamp_config tstamp_config; struct hwtstamp_config tstamp_config;
unsigned long ptp_tx_start;
unsigned long last_rx_ptp_check; unsigned long last_rx_ptp_check;
spinlock_t tmreg_lock; /* Used to protect the device time registers. */ spinlock_t tmreg_lock; /* Used to protect the device time registers. */
u64 ptp_base_adj; u64 ptp_base_adj;

View File

@ -975,6 +975,13 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
hw_link_info->an_info = resp->an_info; hw_link_info->an_info = resp->an_info;
hw_link_info->ext_info = resp->ext_info; hw_link_info->ext_info = resp->ext_info;
hw_link_info->loopback = resp->loopback; hw_link_info->loopback = resp->loopback;
hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size);
hw_link_info->pacing = resp->config & I40E_AQ_CONFIG_PACING_MASK;
if (resp->config & I40E_AQ_CONFIG_CRC_ENA)
hw_link_info->crc_enable = true;
else
hw_link_info->crc_enable = false;
if (resp->command_flags & cpu_to_le16(I40E_AQ_LSE_ENABLE)) if (resp->command_flags & cpu_to_le16(I40E_AQ_LSE_ENABLE))
hw_link_info->lse_enable = true; hw_link_info->lse_enable = true;
@ -1300,6 +1307,7 @@ i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw,
struct i40e_aqc_driver_version *cmd = struct i40e_aqc_driver_version *cmd =
(struct i40e_aqc_driver_version *)&desc.params.raw; (struct i40e_aqc_driver_version *)&desc.params.raw;
i40e_status status; i40e_status status;
u16 len;
if (dv == NULL) if (dv == NULL)
return I40E_ERR_PARAM; return I40E_ERR_PARAM;
@ -1311,7 +1319,14 @@ i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw,
cmd->driver_minor_ver = dv->minor_version; cmd->driver_minor_ver = dv->minor_version;
cmd->driver_build_ver = dv->build_version; cmd->driver_build_ver = dv->build_version;
cmd->driver_subbuild_ver = dv->subbuild_version; cmd->driver_subbuild_ver = dv->subbuild_version;
status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
len = 0;
while (len < sizeof(dv->driver_string) &&
(dv->driver_string[len] < 0x80) &&
dv->driver_string[len])
len++;
status = i40e_asq_send_command(hw, &desc, dv->driver_string,
len, cmd_details);
return status; return status;
} }
@ -2094,8 +2109,8 @@ i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
* @cmd_details: pointer to command details structure or NULL * @cmd_details: pointer to command details structure or NULL
**/ **/
i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw, i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
u16 udp_port, u8 header_len, u16 udp_port, u8 protocol_index,
u8 protocol_index, u8 *filter_index, u8 *filter_index,
struct i40e_asq_cmd_details *cmd_details) struct i40e_asq_cmd_details *cmd_details)
{ {
struct i40e_aq_desc desc; struct i40e_aq_desc desc;

View File

@ -1744,10 +1744,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, false); i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, false);
} else if (strncmp(cmd_buf, "fd-atr on", 9) == 0) { } else if (strncmp(cmd_buf, "fd-atr on", 9) == 0) {
i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, true); i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, true);
} else if (strncmp(cmd_buf, "fd-sb off", 9) == 0) {
i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_SB_ENABLED, false);
} else if (strncmp(cmd_buf, "fd-sb on", 8) == 0) {
i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_SB_ENABLED, true);
} else if (strncmp(cmd_buf, "lldp", 4) == 0) { } else if (strncmp(cmd_buf, "lldp", 4) == 0) {
if (strncmp(&cmd_buf[5], "stop", 4) == 0) { if (strncmp(&cmd_buf[5], "stop", 4) == 0) {
int ret; int ret;
@ -1967,8 +1963,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
dev_info(&pf->pdev->dev, " rem fd_filter <dest q_index> <flex_off> <pctype> <dest_vsi> <dest_ctl> <fd_status> <cnt_index> <fd_id> <packet_len> <packet>\n"); dev_info(&pf->pdev->dev, " rem fd_filter <dest q_index> <flex_off> <pctype> <dest_vsi> <dest_ctl> <fd_status> <cnt_index> <fd_id> <packet_len> <packet>\n");
dev_info(&pf->pdev->dev, " fd-atr off\n"); dev_info(&pf->pdev->dev, " fd-atr off\n");
dev_info(&pf->pdev->dev, " fd-atr on\n"); dev_info(&pf->pdev->dev, " fd-atr on\n");
dev_info(&pf->pdev->dev, " fd-sb off\n");
dev_info(&pf->pdev->dev, " fd-sb on\n");
dev_info(&pf->pdev->dev, " lldp start\n"); dev_info(&pf->pdev->dev, " lldp start\n");
dev_info(&pf->pdev->dev, " lldp stop\n"); dev_info(&pf->pdev->dev, " lldp stop\n");
dev_info(&pf->pdev->dev, " lldp get local\n"); dev_info(&pf->pdev->dev, " lldp get local\n");

View File

@ -39,7 +39,7 @@ static const char i40e_driver_string[] =
#define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MAJOR 0
#define DRV_VERSION_MINOR 3 #define DRV_VERSION_MINOR 3
#define DRV_VERSION_BUILD 43 #define DRV_VERSION_BUILD 46
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN __stringify(DRV_VERSION_BUILD) DRV_KERN
@ -4027,6 +4027,8 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf)
pf->vsi[v]->seid); pf->vsi[v]->seid);
/* Will try to configure as many components */ /* Will try to configure as many components */
} else { } else {
/* Re-configure VSI vectors based on updated TC map */
i40e_vsi_map_rings_to_vectors(pf->vsi[v]);
if (pf->vsi[v]->netdev) if (pf->vsi[v]->netdev)
i40e_dcbnl_set_all(pf->vsi[v]); i40e_dcbnl_set_all(pf->vsi[v]);
} }
@ -4066,6 +4068,9 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
DCB_CAP_DCBX_VER_IEEE; DCB_CAP_DCBX_VER_IEEE;
pf->flags |= I40E_FLAG_DCB_ENABLED; pf->flags |= I40E_FLAG_DCB_ENABLED;
} }
} else {
dev_info(&pf->pdev->dev, "AQ Querying DCB configuration failed: %d\n",
pf->hw.aq.asq_last_status);
} }
out: out:
@ -5603,7 +5608,6 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
**/ **/
static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf)
{ {
const int vxlan_hdr_qwords = 4;
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
i40e_status ret; i40e_status ret;
u8 filter_index; u8 filter_index;
@ -5621,7 +5625,6 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf)
port = pf->vxlan_ports[i]; port = pf->vxlan_ports[i];
ret = port ? ret = port ?
i40e_aq_add_udp_tunnel(hw, ntohs(port), i40e_aq_add_udp_tunnel(hw, ntohs(port),
vxlan_hdr_qwords,
I40E_AQC_TUNNEL_TYPE_VXLAN, I40E_AQC_TUNNEL_TYPE_VXLAN,
&filter_index, NULL) &filter_index, NULL)
: i40e_aq_del_udp_tunnel(hw, i, NULL); : i40e_aq_del_udp_tunnel(hw, i, NULL);
@ -6778,10 +6781,12 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
NETIF_F_TSO_ECN | NETIF_F_TSO_ECN |
NETIF_F_TSO6 | NETIF_F_TSO6 |
NETIF_F_RXCSUM | NETIF_F_RXCSUM |
NETIF_F_NTUPLE |
NETIF_F_RXHASH | NETIF_F_RXHASH |
0; 0;
if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
netdev->features |= NETIF_F_NTUPLE;
/* copy netdev features into list of user selectable features */ /* copy netdev features into list of user selectable features */
netdev->hw_features |= netdev->features; netdev->hw_features |= netdev->features;
@ -8298,7 +8303,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err) { if (err) {
dev_info(&pdev->dev, "init_pf_dcb failed: %d\n", err); dev_info(&pdev->dev, "init_pf_dcb failed: %d\n", err);
pf->flags &= ~I40E_FLAG_DCB_ENABLED; pf->flags &= ~I40E_FLAG_DCB_ENABLED;
goto err_init_dcb; /* Continue without DCB enabled */
} }
#endif /* CONFIG_I40E_DCB */ #endif /* CONFIG_I40E_DCB */
@ -8394,6 +8399,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dv.minor_version = DRV_VERSION_MINOR; dv.minor_version = DRV_VERSION_MINOR;
dv.build_version = DRV_VERSION_BUILD; dv.build_version = DRV_VERSION_BUILD;
dv.subbuild_version = 0; dv.subbuild_version = 0;
strncpy(dv.driver_string, DRV_VERSION, sizeof(dv.driver_string));
i40e_aq_send_driver_version(&pf->hw, &dv, NULL); i40e_aq_send_driver_version(&pf->hw, &dv, NULL);
/* since everything's happy, start the service_task timer */ /* since everything's happy, start the service_task timer */
@ -8435,9 +8441,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_switch_setup: err_switch_setup:
i40e_reset_interrupt_capability(pf); i40e_reset_interrupt_capability(pf);
del_timer_sync(&pf->service_timer); del_timer_sync(&pf->service_timer);
#ifdef CONFIG_I40E_DCB
err_init_dcb:
#endif /* CONFIG_I40E_DCB */
err_mac_addr: err_mac_addr:
err_configure_lan_hmc: err_configure_lan_hmc:
(void)i40e_shutdown_lan_hmc(hw); (void)i40e_shutdown_lan_hmc(hw);

View File

@ -157,8 +157,8 @@ i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent,
i40e_status i40e_aq_start_lldp(struct i40e_hw *hw, i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details); struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw, i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
u16 udp_port, u8 header_len, u16 udp_port, u8 protocol_index,
u8 protocol_index, u8 *filter_index, u8 *filter_index,
struct i40e_asq_cmd_details *cmd_details); struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_del_udp_tunnel(struct i40e_hw *hw, u8 index, i40e_status i40e_aq_del_udp_tunnel(struct i40e_hw *hw, u8 index,
struct i40e_asq_cmd_details *cmd_details); struct i40e_asq_cmd_details *cmd_details);

View File

@ -216,40 +216,6 @@ static int i40e_ptp_settime(struct ptp_clock_info *ptp,
return 0; return 0;
} }
/**
* i40e_ptp_tx_work
* @work: pointer to work struct
*
* This work function polls the PRTTSYN_STAT_0.TXTIME bit to determine when a
* Tx timestamp event has occurred, in order to pass the Tx timestamp value up
* the stack in the skb.
*/
static void i40e_ptp_tx_work(struct work_struct *work)
{
struct i40e_pf *pf = container_of(work, struct i40e_pf,
ptp_tx_work);
struct i40e_hw *hw = &pf->hw;
u32 prttsyn_stat_0;
if (!pf->ptp_tx_skb)
return;
if (time_is_before_jiffies(pf->ptp_tx_start +
I40E_PTP_TX_TIMEOUT)) {
dev_kfree_skb_any(pf->ptp_tx_skb);
pf->ptp_tx_skb = NULL;
pf->tx_hwtstamp_timeouts++;
dev_warn(&pf->pdev->dev, "clearing Tx timestamp hang\n");
return;
}
prttsyn_stat_0 = rd32(hw, I40E_PRTTSYN_STAT_0);
if (prttsyn_stat_0 & I40E_PRTTSYN_STAT_0_TXTIME_MASK)
i40e_ptp_tx_hwtstamp(pf);
else
schedule_work(&pf->ptp_tx_work);
}
/** /**
* i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem * i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem
* @ptp: The PTP clock structure * @ptp: The PTP clock structure
@ -608,7 +574,6 @@ void i40e_ptp_init(struct i40e_pf *pf)
u32 regval; u32 regval;
spin_lock_init(&pf->tmreg_lock); spin_lock_init(&pf->tmreg_lock);
INIT_WORK(&pf->ptp_tx_work, i40e_ptp_tx_work);
dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__, dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__,
netdev->name); netdev->name);
@ -647,7 +612,6 @@ void i40e_ptp_stop(struct i40e_pf *pf)
pf->ptp_tx = false; pf->ptp_tx = false;
pf->ptp_rx = false; pf->ptp_rx = false;
cancel_work_sync(&pf->ptp_tx_work);
if (pf->ptp_tx_skb) { if (pf->ptp_tx_skb) {
dev_kfree_skb_any(pf->ptp_tx_skb); dev_kfree_skb_any(pf->ptp_tx_skb);
pf->ptp_tx_skb = NULL; pf->ptp_tx_skb = NULL;

View File

@ -1825,9 +1825,6 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
*cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN << *cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN <<
I40E_TXD_CTX_QW1_CMD_SHIFT; I40E_TXD_CTX_QW1_CMD_SHIFT;
pf->ptp_tx_start = jiffies;
schedule_work(&pf->ptp_tx_work);
return 1; return 1;
} }

View File

@ -167,6 +167,9 @@ struct i40e_link_status {
u8 loopback; u8 loopback;
/* is Link Status Event notification to SW enabled */ /* is Link Status Event notification to SW enabled */
bool lse_enable; bool lse_enable;
u16 max_frame_size;
bool crc_enable;
u8 pacing;
}; };
struct i40e_phy_info { struct i40e_phy_info {
@ -409,6 +412,7 @@ struct i40e_driver_version {
u8 minor_version; u8 minor_version;
u8 build_version; u8 build_version;
u8 subbuild_version; u8 subbuild_version;
u8 driver_string[32];
}; };
/* RX Descriptors */ /* RX Descriptors */

View File

@ -2049,10 +2049,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
} }
/* delete the temporary mac address */ /* delete the temporary mac address */
i40e_del_filter(vsi, vf->default_lan_addr.addr, 0, true, false); i40e_del_filter(vsi, vf->default_lan_addr.addr, vf->port_vlan_id,
true, false);
/* add the new mac address */ /* add the new mac address */
f = i40e_add_filter(vsi, mac, 0, true, false); f = i40e_add_filter(vsi, mac, vf->port_vlan_id, true, false);
if (!f) { if (!f) {
dev_err(&pf->pdev->dev, dev_err(&pf->pdev->dev,
"Unable to add VF ucast filter\n"); "Unable to add VF ucast filter\n");
@ -2128,11 +2129,15 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
/* Check for condition where there was already a port VLAN ID /* Check for condition where there was already a port VLAN ID
* filter set and now it is being deleted by setting it to zero. * filter set and now it is being deleted by setting it to zero.
* Additionally check for the condition where there was a port
* VLAN but now there is a new and different port VLAN being set.
* Before deleting all the old VLAN filters we must add new ones * Before deleting all the old VLAN filters we must add new ones
* with -1 (I40E_VLAN_ANY) or otherwise we're left with all our * with -1 (I40E_VLAN_ANY) or otherwise we're left with all our
* MAC addresses deleted. * MAC addresses deleted.
*/ */
if (!(vlan_id || qos) && vsi->info.pvid) if ((!(vlan_id || qos) ||
(vlan_id | qos) != le16_to_cpu(vsi->info.pvid)) &&
vsi->info.pvid)
ret = i40e_vsi_add_vlan(vsi, I40E_VLAN_ANY); ret = i40e_vsi_add_vlan(vsi, I40E_VLAN_ANY);
if (vsi->info.pvid) { if (vsi->info.pvid) {

View File

@ -173,6 +173,9 @@ struct i40e_link_status {
u8 loopback; u8 loopback;
/* is Link Status Event notification to SW enabled */ /* is Link Status Event notification to SW enabled */
bool lse_enable; bool lse_enable;
u16 max_frame_size;
bool crc_enable;
u8 pacing;
}; };
struct i40e_phy_info { struct i40e_phy_info {
@ -415,6 +418,7 @@ struct i40e_driver_version {
u8 minor_version; u8 minor_version;
u8 build_version; u8 build_version;
u8 subbuild_version; u8 subbuild_version;
u8 driver_string[32];
}; };
/* RX Descriptors */ /* RX Descriptors */

View File

@ -365,6 +365,316 @@ static int i40evf_set_coalesce(struct net_device *netdev,
return 0; return 0;
} }
/**
* i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type
* @adapter: board private structure
* @cmd: ethtool rxnfc command
*
* Returns Success if the flow is supported, else Invalid Input.
**/
static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter,
struct ethtool_rxnfc *cmd)
{
struct i40e_hw *hw = &adapter->hw;
u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) |
((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32);
/* We always hash on IP src and dest addresses */
cmd->data = RXH_IP_SRC | RXH_IP_DST;
switch (cmd->flow_type) {
case TCP_V4_FLOW:
if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP))
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
break;
case UDP_V4_FLOW:
if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP))
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
break;
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case IPV4_FLOW:
break;
case TCP_V6_FLOW:
if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP))
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
break;
case UDP_V6_FLOW:
if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP))
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
break;
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV6_FLOW:
break;
default:
cmd->data = 0;
return -EINVAL;
}
return 0;
}
/**
* i40evf_get_rxnfc - command to get RX flow classification rules
* @netdev: network interface device structure
* @cmd: ethtool rxnfc command
*
* Returns Success if the command is supported.
**/
static int i40evf_get_rxnfc(struct net_device *netdev,
struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
int ret = -EOPNOTSUPP;
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
cmd->data = adapter->vsi_res->num_queue_pairs;
ret = 0;
break;
case ETHTOOL_GRXFH:
ret = i40evf_get_rss_hash_opts(adapter, cmd);
break;
default:
break;
}
return ret;
}
/**
* i40evf_set_rss_hash_opt - Enable/Disable flow types for RSS hash
* @adapter: board private structure
* @cmd: ethtool rxnfc command
*
* Returns Success if the flow input set is supported.
**/
static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter,
struct ethtool_rxnfc *nfc)
{
struct i40e_hw *hw = &adapter->hw;
u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) |
((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32);
/* RSS does not support anything other than hashing
* to queues on src and dst IPs and ports
*/
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
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:
hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
break;
default:
return -EINVAL;
}
break;
case TCP_V6_FLOW:
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
break;
default:
return -EINVAL;
}
break;
case UDP_V4_FLOW:
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4));
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4));
break;
default:
return -EINVAL;
}
break;
case UDP_V6_FLOW:
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
case 0:
hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6));
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6));
break;
default:
return -EINVAL;
}
break;
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case SCTP_V4_FLOW:
if ((nfc->data & RXH_L4_B_0_1) ||
(nfc->data & RXH_L4_B_2_3))
return -EINVAL;
hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
break;
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case SCTP_V6_FLOW:
if ((nfc->data & RXH_L4_B_0_1) ||
(nfc->data & RXH_L4_B_2_3))
return -EINVAL;
hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
break;
case IPV4_FLOW:
hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4);
break;
case IPV6_FLOW:
hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
break;
default:
return -EINVAL;
}
wr32(hw, I40E_VFQF_HENA(0), (u32)hena);
wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
i40e_flush(hw);
return 0;
}
/**
* i40evf_set_rxnfc - command to set RX flow classification rules
* @netdev: network interface device structure
* @cmd: ethtool rxnfc command
*
* Returns Success if the command is supported.
**/
static int i40evf_set_rxnfc(struct net_device *netdev,
struct ethtool_rxnfc *cmd)
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
int ret = -EOPNOTSUPP;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
ret = i40evf_set_rss_hash_opt(adapter, cmd);
break;
default:
break;
}
return ret;
}
/**
* i40evf_get_channels: get the number of channels supported by the device
* @netdev: network interface device structure
* @ch: channel information structure
*
* For the purposes of our device, we only use combined channels, i.e. a tx/rx
* queue pair. Report one extra channel to match our "other" MSI-X vector.
**/
static void i40evf_get_channels(struct net_device *netdev,
struct ethtool_channels *ch)
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
/* Report maximum channels */
ch->max_combined = adapter->vsi_res->num_queue_pairs;
ch->max_other = NONQ_VECS;
ch->other_count = NONQ_VECS;
ch->combined_count = adapter->vsi_res->num_queue_pairs;
}
/**
* i40evf_get_rxfh_indir_size - get the rx flow hash indirection table size
* @netdev: network interface device structure
*
* Returns the table size.
**/
static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev)
{
return (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4;
}
/**
* i40evf_get_rxfh_indir - get the rx flow hash indirection table
* @netdev: network interface device structure
* @indir: indirection table
*
* Reads the indirection table directly from the hardware. Always returns 0.
**/
static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir)
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
struct i40e_hw *hw = &adapter->hw;
u32 hlut_val;
int i, j;
for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX; i++) {
hlut_val = rd32(hw, I40E_VFQF_HLUT(i));
indir[j++] = hlut_val & 0xff;
indir[j++] = (hlut_val >> 8) & 0xff;
indir[j++] = (hlut_val >> 16) & 0xff;
indir[j++] = (hlut_val >> 24) & 0xff;
}
return 0;
}
/**
* i40evf_set_rxfh_indir - set the rx flow hash indirection table
* @netdev: network interface device structure
* @indir: indirection table
*
* Returns -EINVAL if the table specifies an inavlid queue id, otherwise
* returns 0 after programming the table.
**/
static int i40evf_set_rxfh_indir(struct net_device *netdev, const u32 *indir)
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
struct i40e_hw *hw = &adapter->hw;
u32 hlut_val;
int i, j;
for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX + 1; i++) {
hlut_val = indir[j++];
hlut_val |= indir[j++] << 8;
hlut_val |= indir[j++] << 16;
hlut_val |= indir[j++] << 24;
wr32(hw, I40E_VFQF_HLUT(i), hlut_val);
}
return 0;
}
static struct ethtool_ops i40evf_ethtool_ops = { static struct ethtool_ops i40evf_ethtool_ops = {
.get_settings = i40evf_get_settings, .get_settings = i40evf_get_settings,
.get_drvinfo = i40evf_get_drvinfo, .get_drvinfo = i40evf_get_drvinfo,
@ -378,6 +688,12 @@ static struct ethtool_ops i40evf_ethtool_ops = {
.set_msglevel = i40evf_set_msglevel, .set_msglevel = i40evf_set_msglevel,
.get_coalesce = i40evf_get_coalesce, .get_coalesce = i40evf_get_coalesce,
.set_coalesce = i40evf_set_coalesce, .set_coalesce = i40evf_set_coalesce,
.get_rxnfc = i40evf_get_rxnfc,
.set_rxnfc = i40evf_set_rxnfc,
.get_rxfh_indir_size = i40evf_get_rxfh_indir_size,
.get_rxfh_indir = i40evf_get_rxfh_indir,
.set_rxfh_indir = i40evf_set_rxfh_indir,
.get_channels = i40evf_get_channels,
}; };
/** /**

View File

@ -25,13 +25,15 @@
#include "i40e_prototype.h" #include "i40e_prototype.h"
static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter); static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter);
static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter); static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter);
static void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter);
static void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter);
static int i40evf_close(struct net_device *netdev); static int i40evf_close(struct net_device *netdev);
char i40evf_driver_name[] = "i40evf"; char i40evf_driver_name[] = "i40evf";
static const char i40evf_driver_string[] = static const char i40evf_driver_string[] =
"Intel(R) XL710 X710 Virtual Function Network Driver"; "Intel(R) XL710 X710 Virtual Function Network Driver";
#define DRV_VERSION "0.9.21" #define DRV_VERSION "0.9.23"
const char i40evf_driver_version[] = DRV_VERSION; const char i40evf_driver_version[] = DRV_VERSION;
static const char i40evf_copyright[] = static const char i40evf_copyright[] =
"Copyright (c) 2013 - 2014 Intel Corporation."; "Copyright (c) 2013 - 2014 Intel Corporation.";
@ -1309,7 +1311,6 @@ static void i40evf_watchdog_task(struct work_struct *work)
goto restart_watchdog; goto restart_watchdog;
if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
dev_info(&adapter->pdev->dev, "Checking for redemption\n");
if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) { if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) {
/* A chance for redemption! */ /* A chance for redemption! */
dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n");
@ -1534,9 +1535,13 @@ static void i40evf_reset_task(struct work_struct *work)
rstat_val); rstat_val);
adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
if (netif_running(adapter->netdev)) if (netif_running(adapter->netdev)) {
i40evf_close(adapter->netdev); set_bit(__I40E_DOWN, &adapter->vsi.state);
i40evf_down(adapter);
i40evf_free_traffic_irqs(adapter);
i40evf_free_all_tx_resources(adapter);
i40evf_free_all_rx_resources(adapter);
}
i40evf_free_misc_irq(adapter); i40evf_free_misc_irq(adapter);
i40evf_reset_interrupt_capability(adapter); i40evf_reset_interrupt_capability(adapter);
i40evf_free_queues(adapter); i40evf_free_queues(adapter);