|
@@ -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,16 +1827,15 @@ 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,
|
|
|
- struct hlist_head *from)
|
|
|
+static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi,
|
|
|
+ struct hlist_head *from)
|
|
|
{
|
|
|
struct i40e_mac_filter *f;
|
|
|
struct hlist_node *h;
|
|
@@ -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,10 +2015,12 @@ 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,
|
|
|
- struct i40e_mac_filter *f)
|
|
|
+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;
|
|
|
struct i40e_hw *hw = &vsi->back->hw;
|
|
@@ -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 @@ err_no_memory:
|
|
|
/* 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
|