X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fethernet%2Fintel%2Fi40e%2Fi40e_main.c;h=36cca7b93f36514bf71440404858657347487ab1;hb=216590355cb0e79fa36c7220176ce850f0e3d276;hp=12b90fa45d879606648ab8b6eca28c2b92fb7c4f;hpb=6995b36c0fc3dd97c1d641f9630d19db2cadf44f;p=deliverable%2Flinux.git diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 12b90fa45d87..36cca7b93f36 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 21 +#define DRV_VERSION_BUILD 34 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN @@ -1355,6 +1355,9 @@ static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr) * @is_netdev: make sure its a netdev filter, else doesn't matter * * Returns ptr to the filter object or NULL when no memory available. + * + * NOTE: This function is expected to be called with mac_filter_list_lock + * being held. **/ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan, @@ -1413,6 +1416,9 @@ add_filter_out: * @vlan: the vlan * @is_vf: make sure it's a VF filter, else doesn't matter * @is_netdev: make sure it's a netdev filter, else doesn't matter + * + * NOTE: This function is expected to be called with mac_filter_list_lock + * being held. **/ void i40e_del_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan, @@ -1519,8 +1525,10 @@ static int i40e_set_mac(struct net_device *netdev, void *p) element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); } else { + spin_lock_bh(&vsi->mac_filter_list_lock); i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY, false, false); + spin_unlock_bh(&vsi->mac_filter_list_lock); } if (ether_addr_equal(addr->sa_data, hw->mac.addr)) { @@ -1531,10 +1539,12 @@ static int i40e_set_mac(struct net_device *netdev, void *p) element.flags = cpu_to_le16(I40E_AQC_MACVLAN_ADD_PERFECT_MATCH); i40e_aq_add_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); } else { + spin_lock_bh(&vsi->mac_filter_list_lock); f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY, false, false); if (f) f->is_laa = true; + spin_unlock_bh(&vsi->mac_filter_list_lock); } i40e_sync_vsi_filters(vsi, false); @@ -1707,6 +1717,8 @@ static void i40e_set_rx_mode(struct net_device *netdev) struct netdev_hw_addr *mca; struct netdev_hw_addr *ha; + spin_lock_bh(&vsi->mac_filter_list_lock); + /* add addr if not already in the filter list */ netdev_for_each_uc_addr(uca, netdev) { if (!i40e_find_mac(vsi, uca->addr, false, true)) { @@ -1754,6 +1766,7 @@ static void i40e_set_rx_mode(struct net_device *netdev) bottom_of_search_loop: continue; } + spin_unlock_bh(&vsi->mac_filter_list_lock); /* check for other flag changes */ if (vsi->current_netdev_flags != vsi->netdev->flags) { @@ -1762,6 +1775,79 @@ bottom_of_search_loop: } } +/** + * i40e_mac_filter_entry_clone - Clones a MAC filter entry + * @src: source MAC filter entry to be clones + * + * Returns the pointer to newly cloned MAC filter entry or NULL + * in case of error + **/ +static struct i40e_mac_filter *i40e_mac_filter_entry_clone( + struct i40e_mac_filter *src) +{ + struct i40e_mac_filter *f; + + f = kzalloc(sizeof(*f), GFP_ATOMIC); + if (!f) + return NULL; + *f = *src; + + INIT_LIST_HEAD(&f->list); + + return f; +} + +/** + * 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 removed from device. + **/ +static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi, + struct list_head *from) +{ + struct i40e_mac_filter *f, *ftmp; + + list_for_each_entry_safe(f, ftmp, from, list) { + f->changed = true; + /* Move the element back into MAC filter list*/ + list_move_tail(&f->list, &vsi->mac_filter_list); + } +} + +/** + * i40e_undo_add_filter_entries - Undo the changes made to MAC filter entries + * @vsi: pointer to vsi struct + * + * MAC filter entries from list were slated to be added from device. + **/ +static void i40e_undo_add_filter_entries(struct i40e_vsi *vsi) +{ + struct i40e_mac_filter *f, *ftmp; + + list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { + if (!f->changed && f->counter) + f->changed = true; + } +} + +/** + * i40e_cleanup_add_list - Deletes the element from add list and release + * memory + * @add_list: Pointer to list which contains MAC filter entries + **/ +static void i40e_cleanup_add_list(struct list_head *add_list) +{ + struct i40e_mac_filter *f, *ftmp; + + list_for_each_entry_safe(f, ftmp, add_list, list) { + list_del(&f->list); + kfree(f); + } +} + /** * i40e_sync_vsi_filters - Update the VSI filter list to the HW * @vsi: ptr to the VSI @@ -1773,11 +1859,13 @@ bottom_of_search_loop: **/ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl) { - struct i40e_mac_filter *f, *ftmp; + struct list_head tmp_del_list, tmp_add_list; + struct i40e_mac_filter *f, *ftmp, *fclone; bool promisc_forced_on = false; bool add_happened = false; int filter_list_len = 0; u32 changed_flags = 0; + bool err_cond = false; i40e_status ret = 0; struct i40e_pf *pf; int num_add = 0; @@ -1798,17 +1886,13 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl) vsi->current_netdev_flags = vsi->netdev->flags; } + INIT_LIST_HEAD(&tmp_del_list); + INIT_LIST_HEAD(&tmp_add_list); + if (vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) { vsi->flags &= ~I40E_VSI_FLAG_FILTER_CHANGED; - filter_list_len = pf->hw.aq.asq_buf_size / - sizeof(struct i40e_aqc_remove_macvlan_element_data); - del_list = kcalloc(filter_list_len, - sizeof(struct i40e_aqc_remove_macvlan_element_data), - GFP_KERNEL); - if (!del_list) - return -ENOMEM; - + spin_lock_bh(&vsi->mac_filter_list_lock); list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { if (!f->changed) continue; @@ -1816,6 +1900,58 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl) if (f->counter != 0) continue; f->changed = false; + + /* Move the element into temporary del_list */ + list_move_tail(&f->list, &tmp_del_list); + } + + list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { + if (!f->changed) + continue; + + if (f->counter == 0) + continue; + f->changed = false; + + /* Clone MAC filter entry and add into temporary list */ + fclone = i40e_mac_filter_entry_clone(f); + if (!fclone) { + err_cond = true; + break; + } + list_add_tail(&fclone->list, &tmp_add_list); + } + + /* if failed to clone MAC filter entry - undo */ + if (err_cond) { + i40e_undo_del_filter_entries(vsi, &tmp_del_list); + i40e_undo_add_filter_entries(vsi); + } + spin_unlock_bh(&vsi->mac_filter_list_lock); + + if (err_cond) + i40e_cleanup_add_list(&tmp_add_list); + } + + /* Now process 'del_list' outside the lock */ + if (!list_empty(&tmp_del_list)) { + filter_list_len = pf->hw.aq.asq_buf_size / + sizeof(struct i40e_aqc_remove_macvlan_element_data); + del_list = kcalloc(filter_list_len, + sizeof(struct i40e_aqc_remove_macvlan_element_data), + GFP_KERNEL); + if (!del_list) { + i40e_cleanup_add_list(&tmp_add_list); + + /* Undo VSI's MAC filter entry element updates */ + spin_lock_bh(&vsi->mac_filter_list_lock); + i40e_undo_del_filter_entries(vsi, &tmp_del_list); + i40e_undo_add_filter_entries(vsi); + spin_unlock_bh(&vsi->mac_filter_list_lock); + return -ENOMEM; + } + + list_for_each_entry_safe(f, ftmp, &tmp_del_list, list) { cmd_flags = 0; /* add to delete list */ @@ -1828,10 +1964,6 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl) del_list[num_del].flags = cmd_flags; num_del++; - /* unlink from filter list */ - list_del(&f->list); - kfree(f); - /* flush a full buffer */ if (num_del == filter_list_len) { ret = i40e_aq_remove_macvlan(&pf->hw, @@ -1842,12 +1974,18 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl) memset(del_list, 0, sizeof(*del_list)); if (ret && aq_err != I40E_AQ_RC_ENOENT) - dev_info(&pf->pdev->dev, - "ignoring delete macvlan error, err %s, aq_err %s while flushing a full buffer\n", - i40e_stat_str(&pf->hw, ret), - i40e_aq_str(&pf->hw, aq_err)); + dev_err(&pf->pdev->dev, + "ignoring delete macvlan error, err %s, aq_err %s while flushing a full buffer\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, aq_err)); } + /* Release memory for MAC filter entries which were + * synced up with HW. + */ + list_del(&f->list); + kfree(f); } + if (num_del) { ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, del_list, num_del, NULL); @@ -1863,6 +2001,9 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl) kfree(del_list); del_list = NULL; + } + + if (!list_empty(&tmp_add_list)) { /* do all the adds now */ filter_list_len = pf->hw.aq.asq_buf_size / @@ -1870,16 +2011,19 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl) add_list = kcalloc(filter_list_len, sizeof(struct i40e_aqc_add_macvlan_element_data), GFP_KERNEL); - if (!add_list) + if (!add_list) { + /* Purge element from temporary lists */ + i40e_cleanup_add_list(&tmp_add_list); + + /* Undo add filter entries from VSI MAC filter list */ + spin_lock_bh(&vsi->mac_filter_list_lock); + i40e_undo_add_filter_entries(vsi); + spin_unlock_bh(&vsi->mac_filter_list_lock); return -ENOMEM; + } - list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { - if (!f->changed) - continue; + list_for_each_entry_safe(f, ftmp, &tmp_add_list, list) { - if (f->counter == 0) - continue; - f->changed = false; add_happened = true; cmd_flags = 0; @@ -1906,7 +2050,13 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl) break; memset(add_list, 0, sizeof(*add_list)); } + /* Entries from tmp_add_list were cloned from MAC + * filter list, hence clean those cloned entries + */ + list_del(&f->list); + kfree(f); } + if (num_add) { ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, add_list, num_add, NULL); @@ -2158,6 +2308,9 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) is_vf = (vsi->type == I40E_VSI_SRIOV); is_netdev = !!(vsi->netdev); + /* Locked once because all functions invoked below iterates list*/ + spin_lock_bh(&vsi->mac_filter_list_lock); + if (is_netdev) { add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, vid, is_vf, is_netdev); @@ -2165,6 +2318,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) dev_info(&vsi->back->pdev->dev, "Could not add vlan filter %d for %pM\n", vid, vsi->netdev->dev_addr); + spin_unlock_bh(&vsi->mac_filter_list_lock); return -ENOMEM; } } @@ -2175,6 +2329,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) dev_info(&vsi->back->pdev->dev, "Could not add vlan filter %d for %pM\n", vid, f->macaddr); + spin_unlock_bh(&vsi->mac_filter_list_lock); return -ENOMEM; } } @@ -2196,6 +2351,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) dev_info(&vsi->back->pdev->dev, "Could not add filter 0 for %pM\n", vsi->netdev->dev_addr); + spin_unlock_bh(&vsi->mac_filter_list_lock); return -ENOMEM; } } @@ -2204,22 +2360,28 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) /* Do not assume that I40E_VLAN_ANY should be reset to VLAN 0 */ if (vid > 0 && !vsi->info.pvid) { list_for_each_entry(f, &vsi->mac_filter_list, list) { - if (i40e_find_filter(vsi, f->macaddr, I40E_VLAN_ANY, - is_vf, is_netdev)) { - i40e_del_filter(vsi, f->macaddr, I40E_VLAN_ANY, - is_vf, is_netdev); - add_f = i40e_add_filter(vsi, f->macaddr, - 0, is_vf, is_netdev); - if (!add_f) { - dev_info(&vsi->back->pdev->dev, - "Could not add filter 0 for %pM\n", - f->macaddr); - return -ENOMEM; - } + if (!i40e_find_filter(vsi, f->macaddr, I40E_VLAN_ANY, + is_vf, is_netdev)) + continue; + i40e_del_filter(vsi, f->macaddr, I40E_VLAN_ANY, + is_vf, is_netdev); + add_f = i40e_add_filter(vsi, f->macaddr, + 0, is_vf, is_netdev); + if (!add_f) { + dev_info(&vsi->back->pdev->dev, + "Could not add filter 0 for %pM\n", + f->macaddr); + spin_unlock_bh(&vsi->mac_filter_list_lock); + return -ENOMEM; } } } + /* Make sure to release before sync_vsi_filter because that + * function will lock/unlock as necessary + */ + spin_unlock_bh(&vsi->mac_filter_list_lock); + if (test_bit(__I40E_DOWN, &vsi->back->state) || test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state)) return 0; @@ -2244,6 +2406,9 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) is_vf = (vsi->type == I40E_VSI_SRIOV); is_netdev = !!(netdev); + /* Locked once because all functions invoked below iterates list */ + spin_lock_bh(&vsi->mac_filter_list_lock); + if (is_netdev) i40e_del_filter(vsi, netdev->dev_addr, vid, is_vf, is_netdev); @@ -2274,6 +2439,7 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) dev_info(&vsi->back->pdev->dev, "Could not add filter %d for %pM\n", I40E_VLAN_ANY, netdev->dev_addr); + spin_unlock_bh(&vsi->mac_filter_list_lock); return -ENOMEM; } } @@ -2282,16 +2448,22 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) list_for_each_entry(f, &vsi->mac_filter_list, list) { i40e_del_filter(vsi, f->macaddr, 0, is_vf, is_netdev); add_f = i40e_add_filter(vsi, f->macaddr, I40E_VLAN_ANY, - is_vf, is_netdev); + is_vf, is_netdev); if (!add_f) { dev_info(&vsi->back->pdev->dev, "Could not add filter %d for %pM\n", I40E_VLAN_ANY, f->macaddr); + spin_unlock_bh(&vsi->mac_filter_list_lock); return -ENOMEM; } } } + /* Make sure to release before sync_vsi_filter because that + * function with lock/unlock as necessary + */ + spin_unlock_bh(&vsi->mac_filter_list_lock); + if (test_bit(__I40E_DOWN, &vsi->back->state) || test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state)) return 0; @@ -2901,11 +3073,9 @@ static int i40e_vsi_configure(struct i40e_vsi *vsi) static void i40e_vsi_configure_msix(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; - struct i40e_q_vector *q_vector; struct i40e_hw *hw = &pf->hw; u16 vector; int i, q; - u32 val; u32 qp; /* The interrupt indexing is offset by 1 in the PFINT_ITRn @@ -2915,7 +3085,8 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi) qp = vsi->base_queue; vector = vsi->base_vector; for (i = 0; i < vsi->num_q_vectors; i++, vector++) { - q_vector = vsi->q_vectors[i]; + struct i40e_q_vector *q_vector = vsi->q_vectors[i]; + q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting); q_vector->rx.latency_range = I40E_LOW_LATENCY; wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1), @@ -2924,10 +3095,14 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi) q_vector->tx.latency_range = I40E_LOW_LATENCY; wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1), q_vector->tx.itr); + wr32(hw, I40E_PFINT_RATEN(vector - 1), + INTRL_USEC_TO_REG(vsi->int_rate_limit)); /* Linked list for the queuepairs assigned to this vector */ wr32(hw, I40E_PFINT_LNKLSTN(vector - 1), qp); for (q = 0; q < q_vector->num_ringpairs; q++) { + u32 val; + val = I40E_QINT_RQCTL_CAUSE_ENA_MASK | (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | @@ -3574,14 +3749,12 @@ static void i40e_netpoll(struct net_device *netdev) if (test_bit(__I40E_DOWN, &vsi->state)) return; - pf->flags |= I40E_FLAG_IN_NETPOLL; if (pf->flags & I40E_FLAG_MSIX_ENABLED) { for (i = 0; i < vsi->num_q_vectors; i++) i40e_msix_clean_rings(0, vsi->q_vectors[i]); } else { i40e_intr(pf->pdev->irq, netdev); } - pf->flags &= ~I40E_FLAG_IN_NETPOLL; } #endif @@ -4844,8 +5017,8 @@ out: */ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup) { - char speed[SPEED_SIZE] = "Unknown"; - char fc[FC_SIZE] = "RX/TX"; + char *speed = "Unknown"; + char *fc = "Unknown"; if (vsi->current_isup == isup) return; @@ -4866,19 +5039,19 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup) switch (vsi->back->hw.phy.link_info.link_speed) { case I40E_LINK_SPEED_40GB: - strlcpy(speed, "40 Gbps", SPEED_SIZE); + speed = "40 G"; break; case I40E_LINK_SPEED_20GB: - strncpy(speed, "20 Gbps", SPEED_SIZE); + speed = "20 G"; break; case I40E_LINK_SPEED_10GB: - strlcpy(speed, "10 Gbps", SPEED_SIZE); + speed = "10 G"; break; case I40E_LINK_SPEED_1GB: - strlcpy(speed, "1000 Mbps", SPEED_SIZE); + speed = "1000 M"; break; case I40E_LINK_SPEED_100MB: - strncpy(speed, "100 Mbps", SPEED_SIZE); + speed = "100 M"; break; default: break; @@ -4886,20 +5059,20 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup) switch (vsi->back->hw.fc.current_mode) { case I40E_FC_FULL: - strlcpy(fc, "RX/TX", FC_SIZE); + fc = "RX/TX"; break; case I40E_FC_TX_PAUSE: - strlcpy(fc, "TX", FC_SIZE); + fc = "TX"; break; case I40E_FC_RX_PAUSE: - strlcpy(fc, "RX", FC_SIZE); + fc = "RX"; break; default: - strlcpy(fc, "None", FC_SIZE); + fc = "None"; break; } - netdev_info(vsi->netdev, "NIC Link is Up %s Full Duplex, Flow Control: %s\n", + netdev_info(vsi->netdev, "NIC Link is Up %sbps Full Duplex, Flow Control: %s\n", speed, fc); } @@ -5679,49 +5852,51 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf) if (!(pf->flags & (I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED))) return; - if (time_after(jiffies, pf->fd_flush_timestamp + - (I40E_MIN_FD_FLUSH_INTERVAL * HZ))) { - /* If the flush is happening too quick and we have mostly - * SB rules we should not re-enable ATR for some time. - */ - min_flush_time = pf->fd_flush_timestamp - + (I40E_MIN_FD_FLUSH_SB_ATR_UNSTABLE * HZ); - fd_room = pf->fdir_pf_filter_count - pf->fdir_pf_active_filters; + if (!time_after(jiffies, pf->fd_flush_timestamp + + (I40E_MIN_FD_FLUSH_INTERVAL * HZ))) + return; - if (!(time_after(jiffies, min_flush_time)) && - (fd_room < I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR)) { - if (I40E_DEBUG_FD & pf->hw.debug_mask) - dev_info(&pf->pdev->dev, "ATR disabled, not enough FD filter space.\n"); - disable_atr = true; - } + /* If the flush is happening too quick and we have mostly SB rules we + * should not re-enable ATR for some time. + */ + min_flush_time = pf->fd_flush_timestamp + + (I40E_MIN_FD_FLUSH_SB_ATR_UNSTABLE * HZ); + fd_room = pf->fdir_pf_filter_count - pf->fdir_pf_active_filters; - pf->fd_flush_timestamp = jiffies; - pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; - /* flush all filters */ - wr32(&pf->hw, I40E_PFQF_CTL_1, - I40E_PFQF_CTL_1_CLEARFDTABLE_MASK); - i40e_flush(&pf->hw); - pf->fd_flush_cnt++; - pf->fd_add_err = 0; - do { - /* Check FD flush status every 5-6msec */ - usleep_range(5000, 6000); - reg = rd32(&pf->hw, I40E_PFQF_CTL_1); - if (!(reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK)) - break; - } while (flush_wait_retry--); - if (reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK) { - dev_warn(&pf->pdev->dev, "FD table did not flush, needs more time\n"); - } else { - /* replay sideband filters */ - i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]); - if (!disable_atr) - pf->flags |= I40E_FLAG_FD_ATR_ENABLED; - clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state); - if (I40E_DEBUG_FD & pf->hw.debug_mask) - dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n"); - } + if (!(time_after(jiffies, min_flush_time)) && + (fd_room < I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR)) { + if (I40E_DEBUG_FD & pf->hw.debug_mask) + dev_info(&pf->pdev->dev, "ATR disabled, not enough FD filter space.\n"); + disable_atr = true; } + + pf->fd_flush_timestamp = jiffies; + pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; + /* flush all filters */ + wr32(&pf->hw, I40E_PFQF_CTL_1, + I40E_PFQF_CTL_1_CLEARFDTABLE_MASK); + i40e_flush(&pf->hw); + pf->fd_flush_cnt++; + pf->fd_add_err = 0; + do { + /* Check FD flush status every 5-6msec */ + usleep_range(5000, 6000); + reg = rd32(&pf->hw, I40E_PFQF_CTL_1); + if (!(reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK)) + break; + } while (flush_wait_retry--); + if (reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK) { + dev_warn(&pf->pdev->dev, "FD table did not flush, needs more time\n"); + } else { + /* replay sideband filters */ + i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]); + if (!disable_atr) + pf->flags |= I40E_FLAG_FD_ATR_ENABLED; + clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state); + if (I40E_DEBUG_FD & pf->hw.debug_mask) + dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n"); + } + } /** @@ -6218,8 +6393,9 @@ static void i40e_config_bridge_mode(struct i40e_veb *veb) { struct i40e_pf *pf = veb->pf; - dev_info(&pf->pdev->dev, "enabling bridge mode: %s\n", - veb->bridge_mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB"); + if (pf->hw.debug_mask & I40E_DEBUG_LAN) + dev_info(&pf->pdev->dev, "enabling bridge mode: %s\n", + veb->bridge_mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB"); if (veb->bridge_mode & BRIDGE_MODE_VEPA) i40e_disable_pf_switch_lb(pf); else @@ -6351,12 +6527,6 @@ static int i40e_get_capabilities(struct i40e_pf *pf) } } while (err); - if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) || - (pf->hw.aq.fw_maj_ver < 2)) { - pf->hw.func_caps.num_msix_vectors++; - pf->hw.func_caps.num_msix_vectors_vf++; - } - if (pf->hw.debug_mask & I40E_DEBUG_USER) dev_info(&pf->pdev->dev, "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n", @@ -6591,9 +6761,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) /* make sure our flow control settings are restored */ ret = i40e_set_fc(&pf->hw, &set_fc_aq_fail, true); if (ret) - dev_info(&pf->pdev->dev, "set fc fail, err %s aq_err %s\n", - i40e_stat_str(&pf->hw, ret), - i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); + dev_dbg(&pf->pdev->dev, "setting flow control: ret = %s last_status = %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* Rebuild the VSIs and VEBs that existed before reset. * They are still in our local switch element arrays, so only @@ -7045,6 +7215,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) vsi->idx = vsi_idx; vsi->rx_itr_setting = pf->rx_itr_default; vsi->tx_itr_setting = pf->tx_itr_default; + vsi->int_rate_limit = 0; vsi->rss_table_size = (vsi->type == I40E_VSI_MAIN) ? pf->rss_table_size : 64; vsi->netdev_registered = false; @@ -7063,6 +7234,8 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) /* Setup default MSIX irq handler for VSI */ i40e_vsi_setup_irqhandler(vsi, i40e_msix_clean_rings); + /* Initialize VSI lock */ + spin_lock_init(&vsi->mac_filter_list_lock); pf->vsi[vsi_idx] = vsi; ret = vsi_idx; goto unlock_pf; @@ -7953,12 +8126,12 @@ static int i40e_sw_init(struct i40e_pf *pf) (pf->hw.func_caps.fd_filters_best_effort > 0)) { pf->flags |= I40E_FLAG_FD_ATR_ENABLED; pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE; - if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) { - pf->flags |= I40E_FLAG_FD_SB_ENABLED; - } else { + if (pf->flags & I40E_FLAG_MFP_ENABLED && + pf->hw.num_partitions > 1) dev_info(&pf->pdev->dev, "Flow Director Sideband mode Disabled in MFP mode\n"); - } + else + pf->flags |= I40E_FLAG_FD_SB_ENABLED; pf->fdir_pf_filter_count = pf->hw.func_caps.fd_filters_guaranteed; pf->hw.fdir_shared_filter_count = @@ -8328,13 +8501,15 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, * @seq: RTNL message seq # * @dev: the netdev being configured * @filter_mask: unused + * @nlflags: netlink flags passed in * * Return the mode in which the hardware bridge is operating in * i.e VEB or VEPA. **/ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, - u32 filter_mask, int nlflags) + u32 __always_unused filter_mask, + int nlflags) { struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_vsi *vsi = np->vsi; @@ -8476,17 +8651,26 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) * default a MAC-VLAN filter that accepts any tagged packet * which must be replaced by a normal filter. */ - if (!i40e_rm_default_mac_filter(vsi, mac_addr)) + if (!i40e_rm_default_mac_filter(vsi, mac_addr)) { + spin_lock_bh(&vsi->mac_filter_list_lock); i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, true); + spin_unlock_bh(&vsi->mac_filter_list_lock); + } } else { /* relate the VSI_VMDQ name to the VSI_MAIN name */ snprintf(netdev->name, IFNAMSIZ, "%sv%%d", pf->vsi[pf->lan_vsi]->netdev->name); random_ether_addr(mac_addr); + + spin_lock_bh(&vsi->mac_filter_list_lock); i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, false); + spin_unlock_bh(&vsi->mac_filter_list_lock); } + + spin_lock_bh(&vsi->mac_filter_list_lock); i40e_add_filter(vsi, brdcast, I40E_VLAN_ANY, false, false); + spin_unlock_bh(&vsi->mac_filter_list_lock); ether_addr_copy(netdev->dev_addr, mac_addr); ether_addr_copy(netdev->perm_addr, mac_addr); @@ -8560,10 +8744,13 @@ int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi) static int i40e_add_vsi(struct i40e_vsi *vsi) { int ret = -ENODEV; - struct i40e_mac_filter *f, *ftmp; + u8 laa_macaddr[ETH_ALEN]; + bool found_laa_mac_filter = false; struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; struct i40e_vsi_context ctxt; + struct i40e_mac_filter *f, *ftmp; + u8 enabled_tc = 0x1; /* TC0 enabled */ int f_count = 0; @@ -8735,32 +8922,41 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) vsi->id = ctxt.vsi_number; } + spin_lock_bh(&vsi->mac_filter_list_lock); /* If macvlan filters already exist, force them to get loaded */ list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { f->changed = true; f_count++; + /* Expected to have only one MAC filter entry for LAA in list */ if (f->is_laa && vsi->type == I40E_VSI_MAIN) { - struct i40e_aqc_remove_macvlan_element_data element; + ether_addr_copy(laa_macaddr, f->macaddr); + found_laa_mac_filter = true; + } + } + spin_unlock_bh(&vsi->mac_filter_list_lock); - memset(&element, 0, sizeof(element)); - ether_addr_copy(element.mac_addr, f->macaddr); - element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; - ret = i40e_aq_remove_macvlan(hw, vsi->seid, - &element, 1, NULL); - if (ret) { - /* some older FW has a different default */ - element.flags |= - I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; - i40e_aq_remove_macvlan(hw, vsi->seid, - &element, 1, NULL); - } + if (found_laa_mac_filter) { + struct i40e_aqc_remove_macvlan_element_data element; - i40e_aq_mac_address_write(hw, - I40E_AQC_WRITE_TYPE_LAA_WOL, - f->macaddr, NULL); + memset(&element, 0, sizeof(element)); + ether_addr_copy(element.mac_addr, laa_macaddr); + element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; + ret = i40e_aq_remove_macvlan(hw, vsi->seid, + &element, 1, NULL); + if (ret) { + /* some older FW has a different default */ + element.flags |= + I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; + i40e_aq_remove_macvlan(hw, vsi->seid, + &element, 1, NULL); } + + i40e_aq_mac_address_write(hw, + I40E_AQC_WRITE_TYPE_LAA_WOL, + laa_macaddr, NULL); } + if (f_count) { vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; pf->flags |= I40E_FLAG_FILTER_SYNC; @@ -8823,9 +9019,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi) i40e_vsi_disable_irq(vsi); } + spin_lock_bh(&vsi->mac_filter_list_lock); list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) i40e_del_filter(vsi, f->macaddr, f->vlan, f->is_vf, f->is_netdev); + spin_unlock_bh(&vsi->mac_filter_list_lock); + i40e_sync_vsi_filters(vsi, false); i40e_vsi_delete(vsi); @@ -9725,7 +9924,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) i40e_config_rss(pf); /* fill in link information and enable LSE reporting */ - i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); + i40e_update_link_info(&pf->hw); i40e_link_event(pf); /* Initialize user-specific link properties */ @@ -9843,8 +10042,14 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) } pf->queues_left = queues_left; + dev_dbg(&pf->pdev->dev, + "qs_avail=%d FD SB=%d lan_qs=%d lan_tc0=%d vf=%d*%d vmdq=%d*%d, remaining=%d\n", + pf->hw.func_caps.num_tx_qp, + !!(pf->flags & I40E_FLAG_FD_SB_ENABLED), + pf->num_lan_qps, pf->rss_size, pf->num_req_vfs, pf->num_vf_qps, + pf->num_vmdq_vsis, pf->num_vmdq_qps, queues_left); #ifdef I40E_FCOE - dev_info(&pf->pdev->dev, "fcoe queues = %d\n", pf->num_fcoe_qps); + dev_dbg(&pf->pdev->dev, "fcoe queues = %d\n", pf->num_fcoe_qps); #endif } @@ -9912,12 +10117,19 @@ static void i40e_print_features(struct i40e_pf *pf) } if (pf->flags & I40E_FLAG_DCB_CAPABLE) buf += sprintf(buf, "DCB "); +#if IS_ENABLED(CONFIG_VXLAN) + buf += sprintf(buf, "VxLAN "); +#endif if (pf->flags & I40E_FLAG_PTP) buf += sprintf(buf, "PTP "); #ifdef I40E_FCOE if (pf->flags & I40E_FLAG_FCOE_ENABLED) buf += sprintf(buf, "FCOE "); #endif + if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED) + buf += sprintf(buf, "VEB "); + else + buf += sprintf(buf, "VEPA "); BUG_ON(buf > (string + INFO_STRING_LEN)); dev_info(&pf->pdev->dev, "%s\n", string); @@ -10057,7 +10269,13 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pf->hw.fc.requested_mode = I40E_FC_NONE; err = i40e_init_adminq(hw); - dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw)); + + /* provide nvm, fw, api versions */ + dev_info(&pdev->dev, "fw %d.%d.%05d api %d.%d nvm %s\n", + hw->aq.fw_maj_ver, hw->aq.fw_min_ver, hw->aq.fw_build, + hw->aq.api_maj_ver, hw->aq.api_min_ver, + i40e_nvm_version_str(hw)); + if (err) { dev_info(&pdev->dev, "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n"); @@ -10294,37 +10512,73 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) i40e_fcoe_vsi_setup(pf); #endif - /* Get the negotiated link width and speed from PCI config space */ - pcie_capability_read_word(pf->pdev, PCI_EXP_LNKSTA, &link_status); +#define PCI_SPEED_SIZE 8 +#define PCI_WIDTH_SIZE 8 + /* Devices on the IOSF bus do not have this information + * and will report PCI Gen 1 x 1 by default so don't bother + * checking them. + */ + if (!(pf->flags & I40E_FLAG_NO_PCI_LINK_CHECK)) { + char speed[PCI_SPEED_SIZE] = "Unknown"; + char width[PCI_WIDTH_SIZE] = "Unknown"; - i40e_set_pci_config_data(hw, link_status); + /* Get the negotiated link width and speed from PCI config + * space + */ + pcie_capability_read_word(pf->pdev, PCI_EXP_LNKSTA, + &link_status); + + i40e_set_pci_config_data(hw, link_status); + + switch (hw->bus.speed) { + case i40e_bus_speed_8000: + strncpy(speed, "8.0", PCI_SPEED_SIZE); break; + case i40e_bus_speed_5000: + strncpy(speed, "5.0", PCI_SPEED_SIZE); break; + case i40e_bus_speed_2500: + strncpy(speed, "2.5", PCI_SPEED_SIZE); break; + default: + break; + } + switch (hw->bus.width) { + case i40e_bus_width_pcie_x8: + strncpy(width, "8", PCI_WIDTH_SIZE); break; + case i40e_bus_width_pcie_x4: + strncpy(width, "4", PCI_WIDTH_SIZE); break; + case i40e_bus_width_pcie_x2: + strncpy(width, "2", PCI_WIDTH_SIZE); break; + case i40e_bus_width_pcie_x1: + strncpy(width, "1", PCI_WIDTH_SIZE); break; + default: + break; + } - dev_info(&pdev->dev, "PCI-Express: %s %s\n", - (hw->bus.speed == i40e_bus_speed_8000 ? "Speed 8.0GT/s" : - hw->bus.speed == i40e_bus_speed_5000 ? "Speed 5.0GT/s" : - hw->bus.speed == i40e_bus_speed_2500 ? "Speed 2.5GT/s" : - "Unknown"), - (hw->bus.width == i40e_bus_width_pcie_x8 ? "Width x8" : - hw->bus.width == i40e_bus_width_pcie_x4 ? "Width x4" : - hw->bus.width == i40e_bus_width_pcie_x2 ? "Width x2" : - hw->bus.width == i40e_bus_width_pcie_x1 ? "Width x1" : - "Unknown")); + dev_info(&pdev->dev, "PCI-Express: Speed %sGT/s Width x%s\n", + speed, width); - if (hw->bus.width < i40e_bus_width_pcie_x8 || - hw->bus.speed < i40e_bus_speed_8000) { - dev_warn(&pdev->dev, "PCI-Express bandwidth available for this device may be insufficient for optimal performance.\n"); - dev_warn(&pdev->dev, "Please move the device to a different PCI-e link with more lanes and/or higher transfer rate.\n"); + if (hw->bus.width < i40e_bus_width_pcie_x8 || + hw->bus.speed < i40e_bus_speed_8000) { + dev_warn(&pdev->dev, "PCI-Express bandwidth available for this device may be insufficient for optimal performance.\n"); + dev_warn(&pdev->dev, "Please move the device to a different PCI-e link with more lanes and/or higher transfer rate.\n"); + } } /* get the requested speeds from the fw */ err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, NULL); if (err) - dev_info(&pf->pdev->dev, - "get phy capabilities failed, err %s aq_err %s, advertised speed settings may not be correct\n", - i40e_stat_str(&pf->hw, err), - i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); + dev_dbg(&pf->pdev->dev, "get requested speeds ret = %s last_status = %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); pf->hw.phy.link_info.requested_speeds = abilities.link_speed; + /* get the supported phy types from the fw */ + err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities, NULL); + if (err) + dev_dbg(&pf->pdev->dev, "get supported phy types ret = %s last_status = %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); + pf->hw.phy.phy_types = le32_to_cpu(abilities.phy_type); + /* print a string summarizing features */ i40e_print_features(pf);