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

Commit 417d18d3 authored by David S. Miller's avatar David S. Miller
Browse files


Jeff Kirsher says:

====================
40GbE Intel Wired LAN Driver Updates 2017-02-11

This series contains updates to i40e and i40evf only.

Jake makes a minor change to prevent a minor bit of work, if it is not
necessary.  In the case where we do not have a client, there is no need
to check the client params, so move the check till after we have ensured
we have a client.  Correct a code comment which incorrectly implied
that raw_packet buffers were freed in i40e_clean_tx_ring(), so fixed
the code comment to better explain where memory is freed.  Reduce the
severity and frequency of the message notifying we cleared the receive
timestamp register, since the logic has a much better detection scheme
that could detect a stalled receive timestamp register.  The improved
logic was actually causing the notification message to occur more
frequently and was giving the user a false perception that a timestamp
event was missed for a valid packet, so reduce the severity from
dev_warn to dev_dbg and only fire off the message when 3 or 4 of the
RXTIME registers are stalled and get cleared within the same
watchdog event.  Fixed a bug, where we were modifying the mac_filter
outside a lock when handling the addition of broadcast filters.  Fix
this by updating i40e_update_filter_state logic so that it knows to
avoid broadcast filters, which ensures that we do not have to remove
the filter separately and can put it back using the normal flow.
Refactored how we add new filters to firmware to avoid a race condition
that can occur due to removing filters from the hash temporarily.

Mitch adds a sleep (without timeout) so that we wait for a reply from
the PF before we continue, since the iWarp client cannot continue until
the operation is completed.  Fixed up a function which could never
return an error, to be void and cleaned up the checking of the now
null and void return value.

Scott limits the DMA sync to CPU to the actual length of the incoming
packet, versus the syncing of the entire buffer.  Also reduces the
receive buffer struct (by a single pointer) and align the driver to be
more consistent with other Intel drivers with respect to packets that
span buffers.

Sudheer adds a field to track the bus number info and modified log
statements to print bus, device and function information.

Henry adds the ability to store the FEC status bits from the link up
event.  Also adds the ethtool support for FEC capabilities and 25G
link types.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8f9000a5 b7eaf8f1
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -467,6 +467,22 @@ struct i40e_mac_filter {
	enum i40e_filter_state state;
};

/* Wrapper structure to keep track of filters while we are preparing to send
 * firmware commands. We cannot send firmware commands while holding a
 * spinlock, since it might sleep. To avoid this, we wrap the added filters in
 * a separate structure, which will track the state change and update the real
 * filter while under lock. We can't simply hold the filters in a separate
 * list, as this opens a window for a race condition when adding new MAC
 * addresses to all VLANs, or when adding new VLANs to all MAC addresses.
 */
struct i40e_new_mac_filter {
	struct hlist_node hlist;
	struct i40e_mac_filter *f;

	/* Track future changes to state separately */
	enum i40e_filter_state state;
};

struct i40e_veb {
	struct i40e_pf *pf;
	u16 idx;
+14 −19
Original line number Diff line number Diff line
@@ -174,8 +174,6 @@ void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi)

	if (!vsi)
		return;
	memset(&params, 0, sizeof(params));
	i40e_client_get_params(vsi, &params);
	mutex_lock(&i40e_client_instance_mutex);
	list_for_each_entry(cdev, &i40e_client_instances, list) {
		if (cdev->lan_info.pf == vsi->back) {
@@ -186,6 +184,8 @@ void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi)
					"Cannot locate client instance l2_param_change routine\n");
				continue;
			}
	memset(&params, 0, sizeof(params));
	i40e_client_get_params(vsi, &params);
			if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
				      &cdev->state)) {
				dev_dbg(&vsi->back->pdev->dev, "Client is not open, abort l2 param change\n");
@@ -510,9 +510,10 @@ void i40e_client_subtask(struct i40e_pf *pf)
			continue;

		if (!existing) {
			dev_info(&pf->pdev->dev, "Added instance of Client %s to PF%d bus=0x%02x func=0x%02x\n",
			dev_info(&pf->pdev->dev, "Added instance of Client %s to PF%d bus=0x%02x dev=0x%02x func=0x%02x\n",
				 client->name, pf->hw.pf_id,
				 pf->hw.bus.device, pf->hw.bus.func);
				 pf->hw.bus.bus_id, pf->hw.bus.device,
				 pf->hw.bus.func);
		}

		mutex_lock(&i40e_client_instance_mutex);
@@ -561,8 +562,9 @@ int i40e_lan_add_device(struct i40e_pf *pf)
	ldev->pf = pf;
	INIT_LIST_HEAD(&ldev->list);
	list_add(&ldev->list, &i40e_devices);
	dev_info(&pf->pdev->dev, "Added LAN device PF%d bus=0x%02x func=0x%02x\n",
		 pf->hw.pf_id, pf->hw.bus.device, pf->hw.bus.func);
	dev_info(&pf->pdev->dev, "Added LAN device PF%d bus=0x%02x dev=0x%02x func=0x%02x\n",
		 pf->hw.pf_id, pf->hw.bus.bus_id,
		 pf->hw.bus.device, pf->hw.bus.func);

	/* Since in some cases register may have happened before a device gets
	 * added, we can schedule a subtask to go initiate the clients if
@@ -590,9 +592,9 @@ int i40e_lan_del_device(struct i40e_pf *pf)
	mutex_lock(&i40e_device_mutex);
	list_for_each_entry_safe(ldev, tmp, &i40e_devices, list) {
		if (ldev->pf == pf) {
			dev_info(&pf->pdev->dev, "Deleted LAN device PF%d bus=0x%02x func=0x%02x\n",
				 pf->hw.pf_id, pf->hw.bus.device,
				 pf->hw.bus.func);
			dev_info(&pf->pdev->dev, "Deleted LAN device PF%d bus=0x%02x dev=0x%02x func=0x%02x\n",
				 pf->hw.pf_id, pf->hw.bus.bus_id,
				 pf->hw.bus.device, pf->hw.bus.func);
			list_del(&ldev->list);
			kfree(ldev);
			ret = 0;
@@ -653,13 +655,11 @@ static int i40e_client_release(struct i40e_client *client)
 * i40e_client_prepare - prepare client specific resources
 * @client: pointer to the registered client
 *
 * Return 0 on success or < 0 on error
 **/
static int i40e_client_prepare(struct i40e_client *client)
static void i40e_client_prepare(struct i40e_client *client)
{
	struct i40e_device *ldev;
	struct i40e_pf *pf;
	int ret = 0;

	mutex_lock(&i40e_device_mutex);
	list_for_each_entry(ldev, &i40e_devices, list) {
@@ -669,7 +669,6 @@ static int i40e_client_prepare(struct i40e_client *client)
		i40e_service_event_schedule(pf);
	}
	mutex_unlock(&i40e_device_mutex);
	return ret;
}

/**
@@ -926,13 +925,9 @@ int i40e_register_client(struct i40e_client *client)
	set_bit(__I40E_CLIENT_REGISTERED, &client->state);
	mutex_unlock(&i40e_client_mutex);

	if (i40e_client_prepare(client)) {
		ret = -EIO;
		goto out;
	}
	i40e_client_prepare(client);

	pr_info("i40e: Registered client %s with return code %d\n",
		client->name, ret);
	pr_info("i40e: Registered client %s\n", client->name);
out:
	return ret;
}
+2 −0
Original line number Diff line number Diff line
@@ -1838,6 +1838,8 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
	hw_link_info->link_speed = (enum i40e_aq_link_speed)resp->link_speed;
	hw_link_info->link_info = resp->link_info;
	hw_link_info->an_info = resp->an_info;
	hw_link_info->fec_info = resp->config & (I40E_AQ_CONFIG_FEC_KR_ENA |
						 I40E_AQ_CONFIG_FEC_RS_ENA);
	hw_link_info->ext_info = resp->ext_info;
	hw_link_info->loopback = resp->loopback;
	hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size);
+3 −0
Original line number Diff line number Diff line
@@ -803,9 +803,12 @@ static int i40e_set_settings(struct net_device *netdev,
	if (change || (abilities.link_speed != config.link_speed)) {
		/* copy over the rest of the abilities */
		config.phy_type = abilities.phy_type;
		config.phy_type_ext = abilities.phy_type_ext;
		config.eee_capability = abilities.eee_capability;
		config.eeer = abilities.eeer_val;
		config.low_power_ctrl = abilities.d3_lpan;
		config.fec_config = abilities.fec_cfg_curr_mod_ext_info &
				    I40E_AQ_PHY_FEC_CONFIG_MASK;

		/* save the requested speeds */
		hw->phy.link_info.requested_speeds = config.link_speed;
+138 −54
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ static const char i40e_driver_string[] =

#define DRV_VERSION_MAJOR 1
#define DRV_VERSION_MINOR 6
#define DRV_VERSION_BUILD 25
#define DRV_VERSION_BUILD 27
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
	     __stringify(DRV_VERSION_MINOR) "." \
	     __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -1255,6 +1255,7 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi,
					 int vlan_filters)
{
	struct i40e_mac_filter *f, *add_head;
	struct i40e_new_mac_filter *new;
	struct hlist_node *h;
	int bkt, new_vlan;

@@ -1273,13 +1274,13 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi,
	 */

	/* Update the filters about to be added in place */
	hlist_for_each_entry(f, tmp_add_list, hlist) {
		if (vsi->info.pvid && f->vlan != vsi->info.pvid)
			f->vlan = vsi->info.pvid;
		else if (vlan_filters && f->vlan == I40E_VLAN_ANY)
			f->vlan = 0;
		else if (!vlan_filters && f->vlan == 0)
			f->vlan = I40E_VLAN_ANY;
	hlist_for_each_entry(new, tmp_add_list, hlist) {
		if (vsi->info.pvid && new->f->vlan != vsi->info.pvid)
			new->f->vlan = vsi->info.pvid;
		else if (vlan_filters && new->f->vlan == I40E_VLAN_ANY)
			new->f->vlan = 0;
		else if (!vlan_filters && new->f->vlan == 0)
			new->f->vlan = I40E_VLAN_ANY;
	}

	/* Update the remaining active filters */
@@ -1305,9 +1306,16 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi,
			if (!add_head)
				return -ENOMEM;

			/* Put the replacement filter into the add list */
			hash_del(&add_head->hlist);
			hlist_add_head(&add_head->hlist, tmp_add_list);
			/* Create a temporary i40e_new_mac_filter */
			new = kzalloc(sizeof(*new), GFP_ATOMIC);
			if (!new)
				return -ENOMEM;

			new->f = add_head;
			new->state = add_head->state;

			/* Add the new filter to the tmp list */
			hlist_add_head(&new->hlist, tmp_add_list);

			/* Put the original filter into the delete list */
			f->state = I40E_FILTER_REMOVE;
@@ -1819,15 +1827,14 @@ static void i40e_set_rx_mode(struct net_device *netdev)
}

/**
 * i40e_undo_filter_entries - Undo the changes made to MAC filter entries
 * i40e_undo_del_filter_entries - Undo the changes made to MAC filter entries
 * @vsi: Pointer to VSI struct
 * @from: Pointer to list which contains MAC filter entries - changes to
 *        those entries needs to be undone.
 *
 * MAC filter entries from list were slated to be sent to firmware, either for
 * addition or deletion.
 * MAC filter entries from this list were slated for deletion.
 **/
static void i40e_undo_filter_entries(struct i40e_vsi *vsi,
static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi,
					 struct hlist_head *from)
{
	struct i40e_mac_filter *f;
@@ -1842,6 +1849,53 @@ static void i40e_undo_filter_entries(struct i40e_vsi *vsi,
	}
}

/**
 * i40e_undo_add_filter_entries - Undo the changes made to MAC filter entries
 * @vsi: Pointer to vsi struct
 * @from: Pointer to list which contains MAC filter entries - changes to
 *        those entries needs to be undone.
 *
 * MAC filter entries from this list were slated for addition.
 **/
static void i40e_undo_add_filter_entries(struct i40e_vsi *vsi,
					 struct hlist_head *from)
{
	struct i40e_new_mac_filter *new;
	struct hlist_node *h;

	hlist_for_each_entry_safe(new, h, from, hlist) {
		/* We can simply free the wrapper structure */
		hlist_del(&new->hlist);
		kfree(new);
	}
}

/**
 * i40e_next_entry - Get the next non-broadcast filter from a list
 * @next: pointer to filter in list
 *
 * Returns the next non-broadcast filter in the list. Required so that we
 * ignore broadcast filters within the list, since these are not handled via
 * the normal firmware update path.
 */
static
struct i40e_new_mac_filter *i40e_next_filter(struct i40e_new_mac_filter *next)
{
	while (next) {
		next = hlist_entry(next->hlist.next,
				   typeof(struct i40e_new_mac_filter),
				   hlist);

		/* keep going if we found a broadcast filter */
		if (next && is_broadcast_ether_addr(next->f->macaddr))
			continue;

		break;
	}

	return next;
}

/**
 * i40e_update_filter_state - Update filter state based on return data
 * from firmware
@@ -1855,7 +1909,7 @@ static void i40e_undo_filter_entries(struct i40e_vsi *vsi,
static int
i40e_update_filter_state(int count,
			 struct i40e_aqc_add_macvlan_element_data *add_list,
			 struct i40e_mac_filter *add_head)
			 struct i40e_new_mac_filter *add_head)
{
	int retval = 0;
	int i;
@@ -1874,9 +1928,9 @@ i40e_update_filter_state(int count,
			retval++;
		}

		add_head = hlist_entry(add_head->hlist.next,
				       typeof(struct i40e_mac_filter),
				       hlist);
		add_head = i40e_next_filter(add_head);
		if (!add_head)
			break;
	}

	return retval;
@@ -1933,7 +1987,7 @@ void i40e_aqc_del_filters(struct i40e_vsi *vsi, const char *vsi_name,
static
void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
			  struct i40e_aqc_add_macvlan_element_data *list,
			  struct i40e_mac_filter *add_head,
			  struct i40e_new_mac_filter *add_head,
			  int num_add, bool *promisc_changed)
{
	struct i40e_hw *hw = &vsi->back->hw;
@@ -1961,9 +2015,11 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
 * This function sets or clears the promiscuous broadcast flags for VLAN
 * filters in order to properly receive broadcast frames. Assumes that only
 * broadcast filters are passed.
 *
 * Returns status indicating success or failure;
 **/
static
void i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
static i40e_status
i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
			  struct i40e_mac_filter *f)
{
	bool enable = f->state == I40E_FILTER_NEW;
@@ -1983,15 +2039,13 @@ void i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
							    NULL);
	}

	if (aq_ret) {
	if (aq_ret)
		dev_warn(&vsi->back->pdev->dev,
			 "Error %s setting broadcast promiscuous mode on %s\n",
			 i40e_aq_str(hw, hw->aq.asq_last_status),
			 vsi_name);
		f->state = I40E_FILTER_FAILED;
	} else if (enable) {
		f->state = I40E_FILTER_ACTIVE;
	}

	return aq_ret;
}

/**
@@ -2005,7 +2059,8 @@ void i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
{
	struct hlist_head tmp_add_list, tmp_del_list;
	struct i40e_mac_filter *f, *add_head = NULL;
	struct i40e_mac_filter *f;
	struct i40e_new_mac_filter *new, *add_head = NULL;
	struct i40e_hw *hw = &vsi->back->hw;
	unsigned int failed_filters = 0;
	unsigned int vlan_filters = 0;
@@ -2059,8 +2114,17 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
				continue;
			}
			if (f->state == I40E_FILTER_NEW) {
				hash_del(&f->hlist);
				hlist_add_head(&f->hlist, &tmp_add_list);
				/* Create a temporary i40e_new_mac_filter */
				new = kzalloc(sizeof(*new), GFP_ATOMIC);
				if (!new)
					goto err_no_memory_locked;

				/* Store pointer to the real filter */
				new->f = f;
				new->state = f->state;

				/* Add it to the hash list */
				hlist_add_head(&new->hlist, &tmp_add_list);
			}

			/* Count the number of active (current and new) VLAN
@@ -2095,7 +2159,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
			cmd_flags = 0;

			/* handle broadcast filters by updating the broadcast
			 * promiscuous flag instead of deleting a MAC filter.
			 * promiscuous flag and release filter list.
			 */
			if (is_broadcast_ether_addr(f->macaddr)) {
				i40e_aqc_broadcast_filter(vsi, vsi_name, f);
@@ -2153,36 +2217,37 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
			goto err_no_memory;

		num_add = 0;
		hlist_for_each_entry_safe(f, h, &tmp_add_list, hlist) {
		hlist_for_each_entry_safe(new, h, &tmp_add_list, hlist) {
			if (test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
				     &vsi->state)) {
				f->state = I40E_FILTER_FAILED;
				new->state = I40E_FILTER_FAILED;
				continue;
			}

			/* handle broadcast filters by updating the broadcast
			 * promiscuous flag instead of adding a MAC filter.
			 */
			if (is_broadcast_ether_addr(f->macaddr)) {
				u64 key = i40e_addr_to_hkey(f->macaddr);
				i40e_aqc_broadcast_filter(vsi, vsi_name, f);

				hlist_del(&f->hlist);
				hash_add(vsi->mac_filter_hash, &f->hlist, key);
			if (is_broadcast_ether_addr(new->f->macaddr)) {
				if (i40e_aqc_broadcast_filter(vsi, vsi_name,
							      new->f))
					new->state = I40E_FILTER_FAILED;
				else
					new->state = I40E_FILTER_ACTIVE;
				continue;
			}

			/* add to add array */
			if (num_add == 0)
				add_head = f;
				add_head = new;
			cmd_flags = 0;
			ether_addr_copy(add_list[num_add].mac_addr, f->macaddr);
			if (f->vlan == I40E_VLAN_ANY) {
			ether_addr_copy(add_list[num_add].mac_addr,
					new->f->macaddr);
			if (new->f->vlan == I40E_VLAN_ANY) {
				add_list[num_add].vlan_tag = 0;
				cmd_flags |= I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
			} else {
				add_list[num_add].vlan_tag =
					cpu_to_le16((u16)(f->vlan));
					cpu_to_le16((u16)(new->f->vlan));
			}
			add_list[num_add].queue_number = 0;
			/* set invalid match method for later detection */
@@ -2208,11 +2273,12 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
		 * the VSI's list.
		 */
		spin_lock_bh(&vsi->mac_filter_hash_lock);
		hlist_for_each_entry_safe(f, h, &tmp_add_list, hlist) {
			u64 key = i40e_addr_to_hkey(f->macaddr);

			hlist_del(&f->hlist);
			hash_add(vsi->mac_filter_hash, &f->hlist, key);
		hlist_for_each_entry_safe(new, h, &tmp_add_list, hlist) {
			/* Only update the state if we're still NEW */
			if (new->f->state == I40E_FILTER_NEW)
				new->f->state = new->state;
			hlist_del(&new->hlist);
			kfree(new);
		}
		spin_unlock_bh(&vsi->mac_filter_hash_lock);
		kfree(add_list);
@@ -2373,8 +2439,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
	/* Restore elements on the temporary add and delete lists */
	spin_lock_bh(&vsi->mac_filter_hash_lock);
err_no_memory_locked:
	i40e_undo_filter_entries(vsi, &tmp_del_list);
	i40e_undo_filter_entries(vsi, &tmp_add_list);
	i40e_undo_del_filter_entries(vsi, &tmp_del_list);
	i40e_undo_add_filter_entries(vsi, &tmp_add_list);
	spin_unlock_bh(&vsi->mac_filter_hash_lock);

	vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
@@ -5272,6 +5338,8 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
	enum i40e_aq_link_speed new_speed;
	char *speed = "Unknown";
	char *fc = "Unknown";
	char *fec = "";
	char *an = "";

	new_speed = vsi->back->hw.phy.link_info.link_speed;

@@ -5331,8 +5399,23 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
		break;
	}

	netdev_info(vsi->netdev, "NIC Link is Up %sbps Full Duplex, Flow Control: %s\n",
		    speed, fc);
	if (vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_25GB) {
		fec = ", FEC: None";
		an = ", Autoneg: False";

		if (vsi->back->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED)
			an = ", Autoneg: True";

		if (vsi->back->hw.phy.link_info.fec_info &
		    I40E_AQ_CONFIG_FEC_KR_ENA)
			fec = ", FEC: CL74 FC-FEC/BASE-R";
		else if (vsi->back->hw.phy.link_info.fec_info &
			 I40E_AQ_CONFIG_FEC_RS_ENA)
			fec = ", FEC: CL108 RS-FEC";
	}

	netdev_info(vsi->netdev, "NIC Link is Up, %sbps Full Duplex%s%s, Flow Control: %s\n",
		    speed, fec, an, fc);
}

/**
@@ -10990,6 +11073,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	hw->subsystem_device_id = pdev->subsystem_device;
	hw->bus.device = PCI_SLOT(pdev->devfn);
	hw->bus.func = PCI_FUNC(pdev->devfn);
	hw->bus.bus_id = pdev->bus->number;
	pf->instance = pfs_found;

	/* set up the locks for the AQ, do this only once in probe
Loading