/* Local includes */ #include"i40e.h" #include"i40e_devids.h" #include"i40e_diag.h" #include"i40e_lan_hmc.h" #include"i40e_virtchnl_pf.h" #include"i40e_xsk.h"
/* All i40e tracepoints are defined by the include below, which *mustbeincludedexactlyonceacrossthewholekernelwith *CREATE_TRACE_POINTSdefined
*/ #define CREATE_TRACE_POINTS #include"i40e_trace.h"
/* Allocate last queue in the pile for FDIR VSI queue *soitdoesn'tfragmenttheqp_pile
*/ if (pile == pf->qp_pile && pf->vsi[id]->type == I40E_VSI_FDIR) { if (pile->list[pile->num_entries - 1] & I40E_PILE_VALID_BIT) {
dev_err(&pf->pdev->dev, "Cannot allocate queue %d for I40E_VSI_FDIR\n",
pile->num_entries - 1); return -ENOMEM;
}
pile->list[pile->num_entries - 1] = id | I40E_PILE_VALID_BIT; return pile->num_entries - 1;
}
i = 0; while (i < pile->num_entries) { /* skip already allocated entries */ if (pile->list[i] & I40E_PILE_VALID_BIT) {
i++; continue;
}
/* do we have enough in this lump? */ for (j = 0; (j < needed) && ((i+j) < pile->num_entries); j++) { if (pile->list[i+j] & I40E_PILE_VALID_BIT) break;
}
if (j == needed) { /* there was enough, so assign it to the requestor */ for (j = 0; j < needed; j++)
pile->list[i+j] = id | I40E_PILE_VALID_BIT;
ret = i; break;
}
/* not enough, so skip over it and continue looking */
i += j;
}
return ret;
}
/** *i40e_put_lump-returnalumpofgenericresource *@pile:thepileofresourcetosearch *@index:thebaseitemindex *@id:theowneridoftheitemsassigned * *Returnsthecountofitemsinthelump
**/ staticint i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id)
{ int valid_id = (id | I40E_PILE_VALID_BIT); int count = 0;
u16 i;
if (!pile || index >= pile->num_entries) return -EINVAL;
for (i = index;
i < pile->num_entries && pile->list[i] == valid_id;
i++) {
pile->list[i] = 0;
count++;
}
/* with txqueue index, find the tx_ring struct */ for (i = 0; i < vsi->num_queue_pairs; i++) { if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) { if (txqueue ==
vsi->tx_rings[i]->queue_index) {
tx_ring = vsi->tx_rings[i]; break;
}
}
}
if (time_after(jiffies, (pf->tx_timeout_last_recovery + HZ*20)))
pf->tx_timeout_recovery_level = 1; /* reset after some time */ elseif (time_before(jiffies,
(pf->tx_timeout_last_recovery + netdev->watchdog_timeo))) return; /* don't do any new action before the next timeout */
/* don't kick off another recovery if one is already pending */ if (test_and_set_bit(__I40E_TIMEOUT_RECOVERY_PENDING, pf->state)) return;
if (tx_ring) {
head = i40e_get_head(tx_ring); /* Read interrupt register */ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
val = rd32(&pf->hw,
I40E_PFINT_DYN_CTLN(tx_ring->q_vector->v_idx +
tx_ring->vsi->base_vector - 1)); else
val = rd32(&pf->hw, I40E_PFINT_DYN_CTL0);
es = &vsi->eth_stats;
oes = &vsi->eth_stats_offsets;
/* Gather up the stats that the hw collects */
i40e_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
vsi->stat_offsets_loaded,
&oes->tx_errors, &es->tx_errors);
i40e_stat_update32(hw, I40E_GLV_RUPP(stat_idx),
vsi->stat_offsets_loaded,
&oes->rx_unknown_protocol, &es->rx_unknown_protocol);
/* pull in a couple PF stats if this is the main vsi */ if (vsi->type == I40E_VSI_MAIN) {
ns->rx_crc_errors = pf->stats.crc_errors;
ns->rx_errors = pf->stats.crc_errors + pf->stats.illegal_bytes;
ns->rx_length_errors = pf->stats.rx_length_errors;
}
}
/** *i40e_is_vsi_in_vlan-CheckifVSIisinvlanmode *@vsi:theVSItobesearched * *ReturnstrueifVSIisinvlanmodeorfalseotherwise
**/ bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi)
{ /* If we have a PVID, always operate in VLAN mode */ if (vsi->info.pvid) returntrue;
/* We need to operate in VLAN mode whenever we have any filters with *aVLANotherthanI40E_VLAN_ALL.Wecouldcheckthetableeach *time,incurringsearchcostrepeatedly.However,wecannoticetwo *things: * *1)theonlyplacewherewecangainaVLANfilterisin *i40e_add_filter. * *2)theonlyplacewherefiltersareactuallyremovedisin *i40e_sync_filters_subtask. * *Thus,wecansimplyuseabooleanvalue,has_vlan_filterswhichwe *willsettotruewhenweaddaVLANfilterini40e_add_filter.Then *wehavetoperformthefullsearchafterdeletingfiltersin *i40e_sync_filters_subtask,butwealreadyhavetosearch *filtershereandcanperformthecheckatthesametime.This *resultsinavoidingembeddingaloopforVLANmodeinsideanother *loopoverallthefilters,andshouldmaintaincorrectnessasnoted *above.
*/ return vsi->has_vlan_filter;
}
/* To determine if a particular filter needs to be replaced we *havethethreefollowingconditions: * *a)ifwehaveaPVIDassigned,thenallfilterswhichare *notmarkedasVLAN=PVIDmustbereplacedwithfiltersthat *are. *b)otherwise,ifwehaveanyactiveVLANS,allfilters *whicharemarkedasVLAN=-1mustbereplacedwith *filtersmarkedasVLAN=0 *c)finally,ifwedonothaveanyactiveVLANS,allfilters *whicharemarkedasVLAN=0mustbereplacedwithfilters *markedasVLAN=-1
*/
/* Update the filters about to be added in place */
hlist_for_each_entry(new, tmp_add_list, hlist) { if (pvid && new->f->vlan != pvid) new->f->vlan = pvid; elseif (vlan_filters && new->f->vlan == I40E_VLAN_ANY) new->f->vlan = 0; elseif (!vlan_filters && new->f->vlan == 0) new->f->vlan = I40E_VLAN_ANY;
}
/* Update the remaining active filters */
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { /* Combine the checks for whether a filter needs to be changed *andthendeterminethenewVLANinsidetheifblock,in *ordertoavoidduplicatingcodeforaddingthenewfilter *thendeletingtheoldfilter.
*/ if ((pvid && f->vlan != pvid) ||
(vlan_filters && f->vlan == I40E_VLAN_ANY) ||
(!vlan_filters && f->vlan == 0)) { /* Determine the new vlan we will be adding */ if (pvid)
new_vlan = pvid; elseif (vlan_filters)
new_vlan = 0; else
new_vlan = I40E_VLAN_ANY;
/* Create the new filter */
add_head = i40e_add_filter(vsi, f->macaddr, new_vlan); if (!add_head) return -ENOMEM;
/* Create a temporary i40e_new_mac_filter */ new = kzalloc(sizeof(*new), GFP_ATOMIC); if (!new) return -ENOMEM;
/* If we're asked to add a filter that has been marked for removal, it *issafetosimplyrestoreittoactivestate.__i40e_del_filter *willhavesimplydeletedanyfilterswhichwerepreviouslymarked *NEWorFAILED,soifitiscurrentlymarkedREMOVEitmusthave *previouslybeenACTIVE.Sincewehaven'tyetrunthesyncfilters *task,justrestorethisfiltertotheACTIVEstatesothatthe *synctaskleavesitinplace
*/ if (f->state == I40E_FILTER_REMOVE)
f->state = I40E_FILTER_ACTIVE;
/* If the filter was never added to firmware then we can just delete it *directlyandwedon'twanttosetthestatustoremoveorelsean *adminqueuecommandwillunnecessarilyfire.
*/ if ((f->state == I40E_FILTER_FAILED) ||
(f->state == I40E_FILTER_NEW)) {
hash_del(&f->hlist);
kfree(f);
} else {
f->state = I40E_FILTER_REMOVE;
}
if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL;
if (test_bit(__I40E_DOWN, pf->state) ||
test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) return -EADDRNOTAVAIL;
if (ether_addr_equal(hw->mac.addr, addr->sa_data))
netdev_info(netdev, "returning to hw mac address %pM\n",
hw->mac.addr); else
netdev_info(netdev, "set new mac address %pM\n", addr->sa_data);
/* Copy the address first, so that we avoid a possible race with *.set_rx_mode(). *-RemoveoldaddressfromMACfilter *-Copynewaddress *-AddnewaddresstoMACfilter
*/
spin_lock_bh(&vsi->mac_filter_hash_lock);
i40e_del_mac_filter(vsi, netdev->dev_addr);
eth_hw_addr_set(netdev, addr->sa_data);
i40e_add_mac_filter(vsi, netdev->dev_addr);
spin_unlock_bh(&vsi->mac_filter_hash_lock);
if (vsi->type == I40E_VSI_MAIN) { int ret;
ret = i40e_aq_mac_address_write(hw, I40E_AQC_WRITE_TYPE_LAA_WOL,
addr->sa_data, NULL); if (ret)
netdev_info(netdev, "Ignoring error from firmware on LAA update, status %pe, AQ ret %s\n",
ERR_PTR(ret),
libie_aq_str(hw->aq.asq_last_status));
}
/* schedule our worker thread which will take care of *applyingthenewfilterchanges
*/
i40e_service_event_schedule(pf); return0;
}
if (!test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps)) return0; if (!vsi->rss_size)
vsi->rss_size = min_t(int, pf->alloc_rss_size,
vsi->num_queue_pairs); if (!vsi->rss_size) return -EINVAL;
lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); if (!lut) return -ENOMEM;
/* Use the user configured hash keys and lookup table if there is one, *otherwiseusedefault
*/ if (vsi->rss_lut_user)
memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); else
i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size); if (vsi->rss_hkey_user)
memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE); else
netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
ret = i40e_config_rss_aq(vsi, seed, lut, vsi->rss_table_size);
kfree(lut); return ret;
}
/* find the next higher power-of-2 of num queue pairs */
pow = ilog2(num_qps); if (!is_power_of_2(num_qps))
pow++;
qmap = (offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
(pow << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT);
/* Setup queue offset/count for all TCs for given VSI */
max_qcount = vsi->mqprio_qopt.qopt.count[0]; for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { /* See if the given TC is enabled for the given VSI */ if (vsi->tc_config.enabled_tc & BIT(i)) {
offset = vsi->mqprio_qopt.qopt.offset[i];
qcount = vsi->mqprio_qopt.qopt.count[i]; if (qcount > max_qcount)
max_qcount = qcount;
vsi->tc_config.tc_info[i].qoffset = offset;
vsi->tc_config.tc_info[i].qcount = qcount;
vsi->tc_config.tc_info[i].netdev_tc = netdev_tc++;
} else { /* TC is not enabled so set the offset to *defaultqueueandallocateonequeue *forthegivenTC.
*/
vsi->tc_config.tc_info[i].qoffset = 0;
vsi->tc_config.tc_info[i].qcount = 1;
vsi->tc_config.tc_info[i].netdev_tc = 0;
}
}
/* Set actual Tx/Rx queue pairs */
vsi->num_queue_pairs = offset + qcount;
/* Setup queue TC[0].qmap for given VSI context */
ctxt->info.tc_mapping[0] = cpu_to_le16(qmap);
ctxt->info.mapping_flags |= cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);
ctxt->info.queue_mapping[0] = cpu_to_le16(vsi->base_queue);
ctxt->info.valid_sections |= cpu_to_le16(sections);
/* Reconfigure RSS for main VSI with max queue count */
vsi->rss_size = max_qcount;
ret = i40e_vsi_config_rss(vsi); if (ret) {
dev_info(&vsi->back->pdev->dev, "Failed to reconfig rss for num_queues (%u)\n",
max_qcount); return ret;
}
vsi->reconfig_rss = true;
dev_dbg(&vsi->back->pdev->dev, "Reconfigured rss with num_queues (%u)\n", max_qcount);
/* Find queue count available for channel VSIs and starting offset *forchannelVSIs
*/
override_q = vsi->mqprio_qopt.qopt.count[0]; if (override_q && override_q < vsi->num_queue_pairs) {
vsi->cnt_q_avail = vsi->num_queue_pairs - override_q;
vsi->next_base_queue = override_q;
} return0;
}
sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
offset = 0; /* zero out queue mapping, it will get updated on the end of the function */
memset(ctxt->info.queue_mapping, 0, sizeof(ctxt->info.queue_mapping));
if (vsi->type == I40E_VSI_MAIN) { /* This code helps add more queue to the VSI if we have *morecoresthanRSScansupport,thehighercoreswill *beservedbyATRorotherfilters.Furthermore,the *non-zeroreq_queue_pairssaysthatuserrequestedanew *queuecountviaethtool'sset_channels,sousethis *valueforqueuesdistributionacrosstrafficclasses *Weneedatleastonequeuepairfortheinterface *tobeusableasweseeinelsestatement.
*/ if (vsi->req_queue_pairs > 0)
vsi->num_queue_pairs = vsi->req_queue_pairs; elseif (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
vsi->num_queue_pairs = pf->num_lan_msix; else
vsi->num_queue_pairs = 1;
}
/* Number of queues per enabled TC */ if (vsi->type == I40E_VSI_MAIN ||
(vsi->type == I40E_VSI_SRIOV && vsi->num_queue_pairs != 0))
num_tc_qps = vsi->num_queue_pairs; else
num_tc_qps = vsi->alloc_queue_pairs;
if (enabled_tc && test_bit(I40E_FLAG_DCB_ENA, vsi->back->flags)) { /* Find numtc from enabled TC bitmap */ for (i = 0, numtc = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { if (enabled_tc & BIT(i)) /* TC is enabled */
numtc++;
} if (!numtc) {
dev_warn(&pf->pdev->dev, "DCB is enabled but no TC enabled, forcing TC0\n");
numtc = 1;
}
num_tc_qps = num_tc_qps / numtc;
num_tc_qps = min_t(int, num_tc_qps,
i40e_pf_get_max_q_per_tc(pf));
}
/* Do not allow use more TC queue pairs than MSI-X vectors exist */ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
num_tc_qps = min_t(int, num_tc_qps, pf->num_lan_msix);
/* Setup queue offset/count for all TCs for given VSI */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { /* See if the given TC is enabled for the given VSI */ if (vsi->tc_config.enabled_tc & BIT(i)) { /* TC is enabled */ int pow, num_qps;
switch (vsi->type) { case I40E_VSI_MAIN: if ((!test_bit(I40E_FLAG_FD_SB_ENA,
pf->flags) &&
!test_bit(I40E_FLAG_FD_ATR_ENA,
pf->flags)) ||
vsi->tc_config.enabled_tc != 1) {
qcount = min_t(int, pf->alloc_rss_size,
num_tc_qps); break;
}
fallthrough; case I40E_VSI_FDIR: case I40E_VSI_SRIOV: case I40E_VSI_VMDQ2: default:
qcount = num_tc_qps;
WARN_ON(i != 0); break;
}
vsi->tc_config.tc_info[i].qoffset = offset;
vsi->tc_config.tc_info[i].qcount = qcount;
/* find the next higher power-of-2 of num queue pairs */
num_qps = qcount;
pow = 0; while (num_qps && (BIT_ULL(pow) < qcount)) {
pow++;
num_qps >>= 1;
}
offset += qcount;
} else { /* TC is not enabled so set the offset to *defaultqueueandallocateonequeue *forthegivenTC.
*/
vsi->tc_config.tc_info[i].qoffset = 0;
vsi->tc_config.tc_info[i].qcount = 1;
vsi->tc_config.tc_info[i].netdev_tc = 0;
qmap = 0;
}
ctxt->info.tc_mapping[i] = cpu_to_le16(qmap);
} /* Do not change previously set num_queue_pairs for PFs and VFs*/ if ((vsi->type == I40E_VSI_MAIN && numtc != 1) ||
(vsi->type == I40E_VSI_SRIOV && vsi->num_queue_pairs == 0) ||
(vsi->type != I40E_VSI_MAIN && vsi->type != I40E_VSI_SRIOV))
vsi->num_queue_pairs = offset;
/* Scheduler section valid can only be set for ADD VSI */ if (is_add) {
sections |= I40E_AQ_VSI_PROP_SCHED_VALID;
ctxt->info.up_enable_bits = enabled_tc;
} if (vsi->type == I40E_VSI_SRIOV) {
ctxt->info.mapping_flags |=
cpu_to_le16(I40E_AQ_VSI_QUE_MAP_NONCONTIG); for (i = 0; i < vsi->num_queue_pairs; i++)
ctxt->info.queue_mapping[i] =
cpu_to_le16(vsi->base_queue + i);
} else {
ctxt->info.mapping_flags |=
cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);
ctxt->info.queue_mapping[0] = cpu_to_le16(vsi->base_queue);
}
ctxt->info.valid_sections |= cpu_to_le16(sections);
}
/* Under some circumstances, we might receive a request to delete *ourowndeviceaddressfromouruclist.Becausewestorethe *deviceaddressintheVSI'sMAC/VLANfilterlist,weneedtoignore *suchrequestsandnotdeleteourdeviceaddressfromthislist.
*/ if (ether_addr_equal(addr, netdev->dev_addr)) return0;
/* check for other flag changes */ if (vsi->current_netdev_flags != vsi->netdev->flags) {
vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
set_bit(__I40E_MACVLAN_SYNC_PENDING, vsi->back->state);
}
}
for (i = 0; i < count; i++) { /* Always check status of each filter. We don't need to check *thefirmwarereturnstatusbecausewepre-setthefilter *statustoI40E_AQC_MM_ERR_NO_RESwhensendingthefilter *requesttotheadminq.Thus,ifitnolongermatchesthen *weknowthefilterisactive.
*/ if (add_list[i].match_method == I40E_AQC_MM_ERR_NO_RES) {
add_head->state = I40E_FILTER_FAILED;
} else {
add_head->state = I40E_FILTER_ACTIVE;
retval++;
}
add_head = i40e_next_filter(add_head); if (!add_head) break;
}
if (vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) {
vsi->flags &= ~I40E_VSI_FLAG_FILTER_CHANGED;
spin_lock_bh(&vsi->mac_filter_hash_lock); /* Create a list of filters to delete. */
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { if (f->state == I40E_FILTER_REMOVE) { /* Move the element into temporary del_list */
hash_del(&f->hlist);
hlist_add_head(&f->hlist, &tmp_del_list);
/* Avoid counting removed filters */ continue;
} if (f->state == I40E_FILTER_NEW) { /* 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);
f->state = I40E_FILTER_NEW_SYNC;
}
/* Count the number of active (current and new) VLAN *filterswehavenow.Doesnotcountfilterswhich *aremarkedfordeletion.
*/ if (f->vlan > 0)
vlan_filters++;
}
/* flush a full buffer */ if (num_del == filter_list_len) {
i40e_aqc_del_filters(vsi, vsi_name, del_list,
num_del, &retval);
memset(del_list, 0, list_size);
num_del = 0;
} /* Release memory for MAC filter entries which were *syncedupwithHW.
*/
hlist_del(&f->hlist);
kfree(f);
}
if (num_del) {
i40e_aqc_del_filters(vsi, vsi_name, del_list,
num_del, &retval);
}
kfree(del_list);
del_list = NULL;
}
if (!hlist_empty(&tmp_add_list)) { /* Do all the adds now. */
filter_list_len = hw->aq.asq_buf_size / sizeof(struct i40e_aqc_add_macvlan_element_data);
list_size = filter_list_len * sizeof(struct i40e_aqc_add_macvlan_element_data);
add_list = kzalloc(list_size, GFP_ATOMIC); if (!add_list) goto err_no_memory;
num_add = 0;
hlist_for_each_entry_safe(new, h, &tmp_add_list, hlist) { /* handle broadcast filters by updating the broadcast *promiscuousflaginsteadofaddingaMACfilter.
*/ 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 = new;
cmd_flags = 0;
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)(new->f->vlan));
}
add_list[num_add].queue_number = 0; /* set invalid match method for later detection */
add_list[num_add].match_method = I40E_AQC_MM_ERR_NO_RES;
cmd_flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
add_list[num_add].flags = cpu_to_le16(cmd_flags);
num_add++;
/* flush a full buffer */ if (num_add == filter_list_len) {
i40e_aqc_add_filters(vsi, vsi_name, add_list,
add_head, num_add);
memset(add_list, 0, list_size);
num_add = 0;
}
} if (num_add) {
i40e_aqc_add_filters(vsi, vsi_name, add_list, add_head,
num_add);
} /* Now move all of the filters from the temp add list back to *theVSI'slist.
*/
spin_lock_bh(&vsi->mac_filter_hash_lock);
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 == I40E_FILTER_NEW_SYNC) new->f->state = new->state;
hlist_del(&new->hlist);
netdev_hw_addr_refcnt(new->f, vsi->netdev, -1);
kfree(new);
}
spin_unlock_bh(&vsi->mac_filter_hash_lock);
kfree(add_list);
add_list = NULL;
}
/* Determine the number of active and failed filters. */
spin_lock_bh(&vsi->mac_filter_hash_lock);
vsi->active_filters = 0;
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) { if (f->state == I40E_FILTER_ACTIVE)
vsi->active_filters++; elseif (f->state == I40E_FILTER_FAILED)
failed_filters++;
}
spin_unlock_bh(&vsi->mac_filter_hash_lock);
/* Check if we are able to exit overflow promiscuous mode. We can *safelyexitifwedidn'tjustenter,wenolongerhaveanyfailed *filters,andwehavereducedfiltersbelowthethresholdvalue.
*/ if (old_overflow && !failed_filters &&
vsi->active_filters < vsi->promisc_threshold) {
dev_info(&pf->pdev->dev, "filter logjam cleared on %s, leaving overflow promiscuous mode\n",
vsi_name);
clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
vsi->promisc_threshold = 0;
}
/* if the VF is not trusted do not do promisc */ if (vsi->type == I40E_VSI_SRIOV && pf->vf &&
!pf->vf[vsi->vf_id].trusted) {
clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state); goto out;
}
/* If we are entering overflow promiscuous, we need to calculate a new *thresholdforwhenwearesafetoexit
*/ if (!old_overflow && new_overflow)
vsi->promisc_threshold = (vsi->active_filters * 3) / 4;
/* check for changes in promiscuous modes */ if (changed_flags & IFF_ALLMULTI) { bool cur_multipromisc;
cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
new_overflow);
aq_ret = i40e_set_promiscuous(pf, cur_promisc); if (aq_ret) {
retval = i40e_aq_rc_to_posix(aq_ret,
hw->aq.asq_last_status);
dev_info(&pf->pdev->dev, "Setting promiscuous %s failed on %s, err %pe aq_err %s\n",
cur_promisc ? "on" : "off",
vsi_name,
ERR_PTR(aq_ret),
libie_aq_str(hw->aq.asq_last_status));
}
}
out: /* if something went wrong then set the changed flag so we try again */ if (retval)
vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
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_del_filter_entries(vsi, &tmp_del_list);
i40e_undo_add_filter_entries(vsi, &tmp_add_list);
spin_unlock_bh(&vsi->mac_filter_hash_lock);
if (!pf) return; if (!test_and_clear_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state)) return; if (test_bit(__I40E_VF_DISABLE, pf->state)) {
set_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state); return;
}
i40e_pf_for_each_vsi(pf, v, vsi) { if ((vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) &&
!test_bit(__I40E_VSI_RELEASING, vsi->state)) { int ret = i40e_sync_vsi_filters(vsi);
if (ret) { /* come back and try again later */
set_bit(__I40E_MACVLAN_SYNC_PENDING,
pf->state); break;
}
}
}
}
frame_size = i40e_max_vsi_frame_size(vsi, vsi->xdp_prog); if (new_mtu > frame_size - I40E_PACKET_HDR_PAD) {
netdev_err(netdev, "Error changing mtu to %d, Max is %d\n",
new_mtu, frame_size - I40E_PACKET_HDR_PAD); return -EINVAL;
}
netdev_dbg(netdev, "changing MTU from %d to %d\n",
netdev->mtu, new_mtu);
WRITE_ONCE(netdev->mtu, new_mtu); if (netif_running(netdev))
i40e_vsi_reinit_locked(vsi);
set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
set_bit(__I40E_CLIENT_L2_CHANGE, pf->state); return0;
}
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { /* If we're asked to add a filter that has been marked for *removal,itissafetosimplyrestoreittoactivestate. *__i40e_del_filterwillhavesimplydeletedanyfilterswhich *werepreviouslymarkedNEWorFAILED,soifitiscurrently *markedREMOVEitmusthavepreviouslybeenACTIVE.Sincewe *haven'tyetrunthesyncfilterstask,justrestorethis *filtertotheACTIVEstatesothatthesynctaskleavesit *inplace.
*/ if (f->state == I40E_FILTER_REMOVE && f->vlan == vid) {
f->state = I40E_FILTER_ACTIVE; continue;
} elseif (f->state == I40E_FILTER_REMOVE) { continue;
}
add_f = i40e_add_filter(vsi, f->macaddr, vid); if (!add_f) {
dev_info(&vsi->back->pdev->dev, "Could not add vlan filter %d for %pM\n",
vid, f->macaddr); return -ENOMEM;
}
}
return0;
}
/** *i40e_vsi_add_vlan-AddVSImembershipforgivenVLAN *@vsi:theVSIbeingconfigured *@vid:VLANidtobeadded
**/ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, u16 vid)
{ int err;
if (vsi->info.pvid) return -EINVAL;
/* The network stack will attempt to add VID=0, with the intention to *receiveprioritytaggedpacketswithaVLANof0.OurHWreceives *thesepacketsbydefaultwhenconfiguredtoreceiveuntagged *packets,sowedon'tneedtoaddafilterforthiscase. *Additionally,HWinterpretsaddingaVID=0filterasmeaningto *receive*only*taggedtrafficandstopsreceivinguntaggedtraffic. *Thus,wedonotwanttoactuallyaddafilterforVID=0
*/ if (!vid) return0;
/* Locked once because all functions invoked below iterates list*/
spin_lock_bh(&vsi->mac_filter_hash_lock);
err = i40e_add_vlan_all_mac(vsi, vid);
spin_unlock_bh(&vsi->mac_filter_hash_lock); if (err) return err;
/* schedule our worker thread which will take care of *applyingthenewfilterchanges
*/
i40e_service_event_schedule(vsi->back); return0;
}
/* return code is ignored as there is nothing a user *candoaboutfailuretoremoveandalogmessagewas *alreadyprintedfromtheotherfunction
*/
i40e_vsi_kill_vlan(vsi, vid);
if (vsi->tx_rings) { for (i = 0; i < vsi->num_queue_pairs; i++) if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc)
i40e_free_tx_resources(vsi->tx_rings[i]);
}
if (vsi->xdp_rings) { for (i = 0; i < vsi->num_queue_pairs; i++) if (vsi->xdp_rings[i] && vsi->xdp_rings[i]->desc)
i40e_free_tx_resources(vsi->xdp_rings[i]);
}
}
/** *i40e_vsi_setup_rx_resources-AllocateVSIqueuesRxresources *@vsi:ptrtotheVSI * *Ifthisfunctionreturnswithanerror,thenit'spossibleoneor *moreoftheringsispopulated(whiletherestarenot).Itisthe *callersdutytocleanthoseorphanedrings. * *Return0onsuccess,negativeonfailure
**/ staticint i40e_vsi_setup_rx_resources(struct i40e_vsi *vsi)
{ int i, err = 0;
for (i = 0; i < vsi->num_queue_pairs && !err; i++)
err = i40e_setup_rx_descriptors(vsi->rx_rings[i]); return err;
}
/* clear the context structure first */
memset(&tx_ctx, 0, sizeof(tx_ctx));
tx_ctx.new_context = 1;
tx_ctx.base = (ring->dma / 128);
tx_ctx.qlen = ring->count; if (test_bit(I40E_FLAG_FD_SB_ENA, vsi->back->flags) ||
test_bit(I40E_FLAG_FD_ATR_ENA, vsi->back->flags))
tx_ctx.fd_ena = 1; if (test_bit(I40E_FLAG_PTP_ENA, vsi->back->flags))
tx_ctx.timesync_ena = 1; /* FDIR VSI tx ring can still use RS bit and writebacks */ if (vsi->type != I40E_VSI_FDIR)
tx_ctx.head_wb_ena = 1;
tx_ctx.head_wb_addr = ring->dma +
(ring->count * sizeof(struct i40e_tx_desc));
/* As part of VSI creation/update, FW allocates certain *TxarbitrationqueuesetsforeachTCenabledfor *theVSI.TheFWreturnsthehandlestothesequeue *setsaspartoftheresponsebuffertoAddVSI, *UpdateVSI,etc.AQcommands.Itisexpectedthat *thesequeuesethandlesbeassociatedwiththeTx *queuesbythedriveraspartoftheTXqueuecontext *initialization.Thishastobedoneregardlessof *DCBasbydefaulteverythingismappedtoTC0.
*/
if (ring->ch)
tx_ctx.rdylist =
le16_to_cpu(ring->ch->info.qs_handle[ring->dcb_tc]);
/* clear the context in the HMC */
err = i40e_clear_lan_tx_queue_context(hw, pf_q); if (err) {
dev_info(&vsi->back->pdev->dev, "Failed to clear LAN Tx queue context on Tx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err); return -ENOMEM;
}
/* set the context in the HMC */
err = i40e_set_lan_tx_queue_context(hw, pf_q, &tx_ctx); if (err) {
dev_info(&vsi->back->pdev->dev, "Failed to set LAN Tx queue context on Tx ring %d (pf_q %d, error: %d\n",
ring->queue_index, pf_q, err); return -ENOMEM;
}
/* Now associate this queue with this PCI function */ if (ring->ch) { if (ring->ch->type == I40E_VSI_VMDQ2)
qtx_ctl = I40E_QTX_CTL_VM_QUEUE; else return -EINVAL;
/* descriptor type is always zero *rx_ctx.dtype=0;
*/
rx_ctx.hsplit_0 = 0;
rx_ctx.rxmax = min_t(u16, vsi->max_frame, chain_len * ring->rx_buf_len); if (hw->revision_id == 0)
rx_ctx.lrxqthresh = 0; else
rx_ctx.lrxqthresh = 1;
rx_ctx.crcstrip = 1;
rx_ctx.l2tsel = 1; /* this controls whether VLAN is stripped from inner headers */
rx_ctx.showiv = 0; /* set the prefena field to 1 because the manual says to */
rx_ctx.prefena = 1;
/* clear the context in the HMC */
err = i40e_clear_lan_rx_queue_context(hw, pf_q); if (err) {
dev_info(&vsi->back->pdev->dev, "Failed to clear LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err); return -ENOMEM;
}
/* set the context in the HMC */
err = i40e_set_lan_rx_queue_context(hw, pf_q, &rx_ctx); if (err) {
dev_info(&vsi->back->pdev->dev, "Failed to set LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err); return -ENOMEM;
}
/* configure Rx buffer alignment */ if (!vsi->netdev || test_bit(I40E_FLAG_LEGACY_RX_ENA, vsi->back->flags)) { if (I40E_2K_TOO_SMALL_WITH_PADDING) {
dev_info(&vsi->back->pdev->dev, "2k Rx buffer is too small to fit standard MTU and skb_shared_info\n"); return -EOPNOTSUPP;
}
clear_ring_build_skb_enabled(ring);
} else {
set_ring_build_skb_enabled(ring);
}
ring->rx_offset = i40e_rx_offset(ring);
/* cache tail for quicker writes, and clear the reg before use */
ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
writel(0, ring->tail);
if (ring->xsk_pool) {
xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
ok = i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring));
} else {
ok = !i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
} if (!ok) { /* Log this in case the user has forgotten to give the kernel *anybuffers,evenlaterintheapplication.
*/
dev_info(&vsi->back->pdev->dev, "Failed to allocate some buffers on %sRx ring %d (pf_q %d)\n",
ring->xsk_pool ? "AF_XDP ZC enabled " : "",
ring->queue_index, pf_q);
}
/* The interrupt indexing is offset by 1 in the PFINT_ITRn *andPFINT_LNKLSTnregisters,e.g.: *PFINT_ITRn[0..n-1]getsmsix-1..msix-n(qpairinterrupts)
*/
qp = vsi->base_queue;
vector = vsi->base_vector; for (i = 0; i < vsi->num_q_vectors; i++, vector++) { struct i40e_q_vector *q_vector = vsi->q_vectors[i];
/* Associate the queue pair to the vector and enable the queue *interruptRXqueueinlinkedlistwithnextqueuesettoTX
*/
wr32(hw, I40E_QINT_RQCTL(0), I40E_QINT_RQCTL_VAL(nextqp, 0, TX));
if (i40e_enabled_xdp_vsi(vsi)) { /* TX queue in linked list with next queue set to TX */
wr32(hw, I40E_QINT_TQCTL(nextqp),
I40E_QINT_TQCTL_VAL(nextqp, 0, TX));
}
/* last TX queue so the next RX queue doesn't matter */
wr32(hw, I40E_QINT_TQCTL(0),
I40E_QINT_TQCTL_VAL(I40E_QUEUE_END_OF_LIST, 0, RX));
i40e_flush(hw);
}
/** *i40e_vsi_disable_irq-MaskoffqueueinterruptgenerationontheVSI *@vsi:theVSIbeingun-configured
**/ staticvoid i40e_vsi_disable_irq(struct i40e_vsi *vsi)
{ struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; int base = vsi->base_vector; int i;
/* disable interrupt causation from each queue */ for (i = 0; i < vsi->num_queue_pairs; i++) {
u32 val;
val = rd32(hw, I40E_QINT_TQCTL(vsi->tx_rings[i]->reg_idx));
val &= ~I40E_QINT_TQCTL_CAUSE_ENA_MASK;
wr32(hw, I40E_QINT_TQCTL(vsi->tx_rings[i]->reg_idx), val);
val = rd32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i]->reg_idx));
val &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
wr32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i]->reg_idx), val);
if (!i40e_enabled_xdp_vsi(vsi)) continue;
wr32(hw, I40E_QINT_TQCTL(vsi->xdp_rings[i]->reg_idx), 0);
}
/* disable each interrupt */ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { for (i = vsi->base_vector;
i < (vsi->num_q_vectors + vsi->base_vector); i++)
wr32(hw, I40E_PFINT_DYN_CTLN(i - 1), 0);
i40e_flush(hw); for (i = 0; i < vsi->num_q_vectors; i++)
synchronize_irq(pf->msix_entries[i + base].vector);
} else { /* Legacy and MSI mode - this stops all interrupt handling */
wr32(hw, I40E_PFINT_ICR0_ENA, 0);
wr32(hw, I40E_PFINT_DYN_CTL0, 0);
i40e_flush(hw);
synchronize_irq(pf->pdev->irq);
}
}
if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { for (i = 0; i < vsi->num_q_vectors; i++)
i40e_irq_dynamic_enable(vsi, i);
} else {
i40e_irq_dynamic_enable_icr0(pf);
}
/* if sharing a legacy IRQ, we might get called w/o an intr pending */ if ((icr0 & I40E_PFINT_ICR0_INTEVENT_MASK) == 0) goto enable_intr;
/* if interrupt but no bits showing, must be SWINT */ if (((icr0 & ~I40E_PFINT_ICR0_INTEVENT_MASK) == 0) ||
(icr0 & I40E_PFINT_ICR0_SWINT_MASK))
pf->sw_int_count++;
/* only q0 is used in MSI/Legacy mode, and none are used in MSIX */ if (icr0 & I40E_PFINT_ICR0_QUEUE_0_MASK) { struct i40e_vsi *vsi = i40e_pf_get_main_vsi(pf); struct i40e_q_vector *q_vector = vsi->q_vectors[0];
/* We do not have a way to disarm Queue causes while leaving *interruptenabledforallothercauses,ideally *interruptshouldbedisabledwhileweareinNAPIbut *thisisnotaperformancepathandnapi_schedule() *candealwithrescheduling.
*/ if (!test_bit(__I40E_DOWN, pf->state))
napi_schedule_irqoff(&q_vector->napi);
}
if (icr0 & I40E_PFINT_ICR0_GRST_MASK) { if (!test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
set_bit(__I40E_RESET_INTR_RECEIVED, pf->state);
ena_mask &= ~I40E_PFINT_ICR0_ENA_GRST_MASK;
val = rd32(hw, I40E_GLGEN_RSTAT);
val = FIELD_GET(I40E_GLGEN_RSTAT_RESET_TYPE_MASK, val); if (val == I40E_RESET_CORER) {
pf->corer_count++;
} elseif (val == I40E_RESET_GLOBR) {
pf->globr_count++;
} elseif (val == I40E_RESET_EMPR) {
pf->empr_count++;
set_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state);
}
}
if (icr0 & I40E_PFINT_ICR0_HMC_ERR_MASK) {
icr0 &= ~I40E_PFINT_ICR0_HMC_ERR_MASK;
dev_info(&pf->pdev->dev, "HMC error interrupt\n");
dev_info(&pf->pdev->dev, "HMC error info 0x%x, HMC error data 0x%x\n",
rd32(hw, I40E_PFHMC_ERRORINFO),
rd32(hw, I40E_PFHMC_ERRORDATA));
}
if (icr0 & I40E_PFINT_ICR0_TIMESYNC_MASK) {
u32 prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_0);
if (prttsyn_stat & I40E_PRTTSYN_STAT_0_EVENT0_MASK)
schedule_work(&pf->ptp_extts0_work);
if (prttsyn_stat & I40E_PRTTSYN_STAT_0_TXTIME_MASK)
i40e_ptp_tx_hwtstamp(pf);
icr0 &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
}
/* If a critical error is pending we have no choice but to reset the *device. *Reportandmaskoutanyremainingunexpectedinterrupts.
*/
icr0_remaining = icr0 & ena_mask; if (icr0_remaining) {
dev_info(&pf->pdev->dev, "unhandled interrupt icr0=0x%08x\n",
icr0_remaining); if ((icr0_remaining & I40E_PFINT_ICR0_PE_CRITERR_MASK) ||
(icr0_remaining & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) ||
(icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK)) {
dev_info(&pf->pdev->dev, "device will be reset\n");
set_bit(__I40E_PF_RESET_REQUESTED, pf->state);
i40e_service_event_schedule(pf);
}
ena_mask &= ~icr0_remaining;
}
ret = IRQ_HANDLED;
/* move us past the eop_desc for start of next FD desc */
tx_buf++;
tx_desc++;
i++; if (unlikely(!i)) {
i -= tx_ring->count;
tx_buf = tx_ring->tx_bi;
tx_desc = I40E_TX_DESC(tx_ring, 0);
}
/* update budget accounting */
budget--;
} while (likely(budget));
i += tx_ring->count;
tx_ring->next_to_clean = i;
if (test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags))
i40e_irq_dynamic_enable(vsi, tx_ring->q_vector->v_idx);
/* Place XDP Tx ring in the same q_vector ring list as regular Tx */ if (i40e_enabled_xdp_vsi(vsi)) { struct i40e_ring *xdp_ring = vsi->xdp_rings[qp_idx];
/** *i40e_vsi_map_rings_to_vectors-Mapsdescriptorringstovectors *@vsi:theVSIbeingconfigured * *Thisfunctionmapsdescriptorringstothequeue-specificvectors *wewereallottedthroughtheMSI-Xenablingcode.Ideally,we'dhave *onevectorperqueuepair,butonaconstrainedvectorbudget,we *groupthequeuepairsas"efficiently"aspossible.
**/ staticvoid i40e_vsi_map_rings_to_vectors(struct i40e_vsi *vsi)
{ int qp_remaining = vsi->num_queue_pairs; int q_vectors = vsi->num_q_vectors; int num_ringpairs; int v_start = 0; int qp_idx = 0;
/* If we don't have enough vectors for a 1-to-1 mapping, we'll have to *groupthemsotherearemultiplequeuespervector. *Itisalsoimportanttogothroughallthevectorsavailabletobe *surethatifwedon'tuseallthevectors,thattheremainingvectors *arecleared.Thisisespeciallyimportantwhendecreasingthe *numberofqueuesinuse.
*/ for (; v_start < q_vectors; v_start++) { struct i40e_q_vector *q_vector = vsi->q_vectors[v_start];
for (i = 0; i < I40E_QUEUE_WAIT_RETRY_LIMIT; i++) {
tx_reg = rd32(&pf->hw, I40E_QTX_ENA(pf_q)); if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) break;
usleep_range(10, 20);
} if (i >= I40E_QUEUE_WAIT_RETRY_LIMIT) return -ETIMEDOUT;
/** *i40e_control_wait_tx_q-Start/stopTxqueueandwaitforcompletion *@seid:VSISEID *@pf:thePFstructure *@pf_q:thePFqueuetoconfigure *@is_xdp:trueifthequeueisusedforXDP *@enable:startorstopthequeue
**/ int i40e_control_wait_tx_q(int seid, struct i40e_pf *pf, int pf_q, bool is_xdp, bool enable)
{ int ret;
i40e_control_tx_q(pf, pf_q, enable);
/* wait for the change to finish */
ret = i40e_pf_txq_wait(pf, pf_q, enable); if (ret) {
dev_info(&pf->pdev->dev, "VSI seid %d %sTx ring %d %sable timeout\n",
seid, (is_xdp ? "XDP " : ""), pf_q,
(enable ? "en" : "dis"));
}
return ret;
}
/** *i40e_vsi_enable_tx-StartaVSI'srings *@vsi:theVSIbeingconfigured
**/ staticint i40e_vsi_enable_tx(struct i40e_vsi *vsi)
{ struct i40e_pf *pf = vsi->back; int i, pf_q, ret = 0;
pf_q = vsi->base_queue; for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
ret = i40e_control_wait_tx_q(vsi->seid, pf,
pf_q, false/*is xdp*/, true); if (ret) break;
if (!i40e_enabled_xdp_vsi(vsi)) continue;
ret = i40e_control_wait_tx_q(vsi->seid, pf,
pf_q + vsi->alloc_queue_pairs, true/*is xdp*/, true); if (ret) break;
} return ret;
}
for (i = 0; i < I40E_QUEUE_WAIT_RETRY_LIMIT; i++) {
rx_reg = rd32(&pf->hw, I40E_QRX_ENA(pf_q)); if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) break;
usleep_range(10, 20);
} if (i >= I40E_QUEUE_WAIT_RETRY_LIMIT) return -ETIMEDOUT;
if (vsi->netdev && netif_running(vsi->netdev))
vsi->netdev->netdev_ops->ndo_open(vsi->netdev); else
i40e_vsi_open(vsi); /* this clears the DOWN bit */
}
/** *i40e_vsi_wait_queues_disabled-WaitforVSI'squeuestobedisabled *@vsi:theVSIbeingconfigured * *WaituntilallqueuesonagivenVSIhavebeendisabled.
**/ int i40e_vsi_wait_queues_disabled(struct i40e_vsi *vsi)
{ struct i40e_pf *pf = vsi->back; int i, pf_q, ret;
pf_q = vsi->base_queue; for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) { /* Check and wait for the Tx queue */
ret = i40e_pf_txq_wait(pf, pf_q, false); if (ret) {
dev_info(&pf->pdev->dev, "VSI seid %d Tx ring %d disable timeout\n",
vsi->seid, pf_q); return ret;
}
if (!i40e_enabled_xdp_vsi(vsi)) goto wait_rx;
/* Check and wait for the XDP Tx queue */
ret = i40e_pf_txq_wait(pf, pf_q + vsi->alloc_queue_pairs, false); if (ret) {
dev_info(&pf->pdev->dev, "VSI seid %d XDP Tx ring %d disable timeout\n",
vsi->seid, pf_q); return ret;
}
wait_rx: /* Check and wait for the Rx queue */
ret = i40e_pf_rxq_wait(pf, pf_q, false); if (ret) {
dev_info(&pf->pdev->dev, "VSI seid %d Rx ring %d disable timeout\n",
vsi->seid, pf_q); return ret;
}
}
for (i = 0; i < dcbcfg->numapps; i++) {
app = dcbcfg->app[i]; if (app.selector == I40E_APP_SEL_TCPIP &&
app.protocolid == I40E_APP_PROTOID_ISCSI) {
tc = dcbcfg->etscfg.prioritytable[app.priority];
enabled_tc |= BIT(tc); break;
}
}
return enabled_tc;
}
/** *i40e_dcb_get_num_tc-GetthenumberofTCsfromDCBxconfig *@dcbcfg:thecorrespondingDCBxconfigurationstructure * *ReturnthenumberofTCsfromgivenDCBxconfiguration
**/ static u8 i40e_dcb_get_num_tc(struct i40e_dcbx_config *dcbcfg)
{ int i, tc_unused = 0;
u8 num_tc = 0;
u8 ret = 0;
/* Scan the ETS Config Priority Table to find *trafficclassenabledforagivenpriority *andcreateabitmaskofenabledTCs
*/ for (i = 0; i < I40E_MAX_USER_PRIORITY; i++)
num_tc |= BIT(dcbcfg->etscfg.prioritytable[i]);
/* Now scan the bitmask to check for *contiguousTCsstartingwithTC0
*/ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { if (num_tc & BIT(i)) { if (!tc_unused) {
ret++;
} else {
pr_err("Non-contiguous TC - Disabling DCB\n"); return1;
}
} else {
tc_unused = 1;
}
}
/* There is always at least TC0 */ if (!ret)
ret = 1;
if (i40e_is_tc_mqprio_enabled(pf)) { struct i40e_vsi *vsi = i40e_pf_get_main_vsi(pf);
return vsi->mqprio_qopt.qopt.num_tc;
}
/* If neither MQPRIO nor DCB is enabled, then always use single TC */ if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) return1;
/* SFP mode will be enabled for all TCs on port */ if (!test_bit(I40E_FLAG_MFP_ENA, pf->flags)) return i40e_dcb_get_num_tc(&pf->hw.local_dcbx_config);
/* MFP mode return count of enabled TCs for this PF */ if (pf->hw.func_caps.iscsi)
enabled_tc = i40e_get_iscsi_tc_map(pf); else return1; /* Only TC0 */
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { if (enabled_tc & BIT(i))
num_tc++;
} return num_tc;
}
/* If neither MQPRIO nor DCB is enabled for this PF then just return *defaultTC
*/ if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) return I40E_DEFAULT_TRAFFIC_CLASS;
/* SFP mode we want PF to be enabled for all TCs */ if (!test_bit(I40E_FLAG_MFP_ENA, pf->flags)) return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config);
/* MFP enabled and iSCSI PF type */ if (pf->hw.func_caps.iscsi) return i40e_get_iscsi_tc_map(pf); else return I40E_DEFAULT_TRAFFIC_CLASS;
}
/* Get the VSI level BW configuration */
ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL); if (ret) {
dev_info(&pf->pdev->dev, "couldn't get PF vsi bw config, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status)); return -EINVAL;
}
/* Get the VSI level BW configuration per TC */
ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config,
NULL); if (ret) {
dev_info(&pf->pdev->dev, "couldn't get PF vsi ets bw config, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status)); return -EINVAL;
}
if (bw_config.tc_valid_bits != bw_ets_config.tc_valid_bits) {
dev_info(&pf->pdev->dev, "Enabled TCs mismatch from querying VSI BW info 0x%08x 0x%08x\n",
bw_config.tc_valid_bits,
bw_ets_config.tc_valid_bits); /* Still continuing */
}
vsi->bw_limit = le16_to_cpu(bw_config.port_bw_limit);
vsi->bw_max_quanta = bw_config.max_bw;
tc_bw_max = le16_to_cpu(bw_ets_config.tc_bw_max[0]) |
(le16_to_cpu(bw_ets_config.tc_bw_max[1]) << 16); for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
vsi->bw_ets_share_credits[i] = bw_ets_config.share_credits[i];
vsi->bw_ets_limit_credits[i] =
le16_to_cpu(bw_ets_config.credits[i]); /* 3 bits out of 4 for each TC */
vsi->bw_ets_max_quanta[i] = (u8)((tc_bw_max >> (i*4)) & 0x7);
}
/* There is no need to reset BW when mqprio mode is on. */ if (i40e_is_tc_mqprio_enabled(pf)) return0; if (!vsi->mqprio_qopt.qopt.hw && !test_bit(I40E_FLAG_DCB_ENA, pf->flags)) {
ret = i40e_set_bw_limit(vsi, vsi->seid, 0); if (ret)
dev_info(&pf->pdev->dev, "Failed to reset tx rate for vsi->seid %u\n",
vsi->seid); return ret;
}
memset(&bw_data, 0, sizeof(bw_data));
bw_data.tc_valid_bits = enabled_tc; for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
bw_data.tc_bw_credits[i] = bw_share[i];
ret = i40e_aq_config_vsi_tc_bw(&pf->hw, vsi->seid, &bw_data, NULL); if (ret) {
dev_info(&pf->pdev->dev, "AQ command Config VSI BW allocation per TC failed = %d\n",
pf->hw.aq.asq_last_status); return -EINVAL;
}
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
vsi->info.qs_handle[i] = bw_data.qs_handles[i];
if (!enabled_tc) {
netdev_reset_tc(netdev); return;
}
/* Set up actual enabled TCs on the VSI */ if (netdev_set_num_tc(netdev, vsi->tc_config.numtc)) return;
/* set per TC queues for the VSI */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { /* Only set TC queues for enabled tcs * *e.g.ForaVSIthathasTC0andTC3enabledthe *enabled_tcbitmapwouldbe0x00001001;thedriver *willsetthenumtcfornetdevas2thatwillbe *referencedbythenetdevlayerasTC0and1.
*/ if (vsi->tc_config.enabled_tc & BIT(i))
netdev_set_tc_queue(netdev,
vsi->tc_config.tc_info[i].netdev_tc,
vsi->tc_config.tc_info[i].qcount,
vsi->tc_config.tc_info[i].qoffset);
}
if (i40e_is_tc_mqprio_enabled(pf)) return;
/* Assign UP2TC map for the VSI */ for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) { /* Get the actual TC# for the UP */
u8 ets_tc = dcbcfg->etscfg.prioritytable[i]; /* Get the mapped netdev TC# for the UP */
netdev_tc = vsi->tc_config.tc_info[ets_tc].netdev_tc;
netdev_set_prio_tc_map(netdev, i, netdev_tc);
}
}
/** *i40e_vsi_update_queue_map-UpdateourcopyofVSiinfowithnewqueuemap *@vsi:theVSIbeingconfigured *@ctxt:thectxtbufferreturnedfromAQVSIupdateparamcommand
**/ staticvoid i40e_vsi_update_queue_map(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt)
{ /* copy just the sections touched not the entire info *sincenotallsectionsarevalidasreturnedby *updatevsiparams
*/
vsi->info.mapping_flags = ctxt->info.mapping_flags;
memcpy(&vsi->info.queue_mapping,
&ctxt->info.queue_mapping, sizeof(vsi->info.queue_mapping));
memcpy(&vsi->info.tc_mapping, ctxt->info.tc_mapping, sizeof(vsi->info.tc_mapping));
}
/** *i40e_update_adq_vsi_queues-updatequeuemappingforADqVSI *@vsi:theVSIbeingreconfigured *@vsi_offset:offsetfrommainVFVSI
*/ int i40e_update_adq_vsi_queues(struct i40e_vsi *vsi, int vsi_offset)
{ struct i40e_vsi_context ctxt = {}; struct i40e_pf *pf; struct i40e_hw *hw; int ret;
if (!vsi) return -EINVAL;
pf = vsi->back;
hw = &pf->hw;
i40e_vsi_setup_queue_map(vsi, &ctxt, vsi->tc_config.enabled_tc, false); if (vsi->reconfig_rss) {
vsi->rss_size = min_t(int, pf->alloc_rss_size,
vsi->num_queue_pairs);
ret = i40e_vsi_config_rss(vsi); if (ret) {
dev_info(&pf->pdev->dev, "Failed to reconfig rss for num_queues\n"); return ret;
}
vsi->reconfig_rss = false;
}
ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); if (ret) {
dev_info(&pf->pdev->dev, "Update vsi config failed, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(hw->aq.asq_last_status)); return ret;
} /* update the local VSI info with updated queue map */
i40e_vsi_update_queue_map(vsi, &ctxt);
vsi->info.valid_sections = 0;
/* Check if enabled_tc is same as existing or new TCs */ if (vsi->tc_config.enabled_tc == enabled_tc &&
vsi->mqprio_qopt.mode != TC_MQPRIO_MODE_CHANNEL) return ret;
/* Enable ETS TCs with equal BW Share for now across all VSIs */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { if (enabled_tc & BIT(i))
bw_share[i] = 1;
}
ret = i40e_vsi_configure_bw_alloc(vsi, enabled_tc, bw_share); if (ret) { struct i40e_aqc_query_vsi_bw_config_resp bw_config = {0};
dev_info(&pf->pdev->dev, "Failed configuring TC map %d for VSI %d\n",
enabled_tc, vsi->seid);
ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid,
&bw_config, NULL); if (ret) {
dev_info(&pf->pdev->dev, "Failed querying vsi bw info, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(hw->aq.asq_last_status)); goto out;
} if ((bw_config.tc_valid_bits & enabled_tc) != enabled_tc) {
u8 valid_tc = bw_config.tc_valid_bits & enabled_tc;
if (!valid_tc)
valid_tc = bw_config.tc_valid_bits; /* Always enable TC0, no matter what */
valid_tc |= 1;
dev_info(&pf->pdev->dev, "Requested tc 0x%x, but FW reports 0x%x as valid. Attempting to use 0x%x.\n",
enabled_tc, bw_config.tc_valid_bits, valid_tc);
enabled_tc = valid_tc;
}
ret = i40e_vsi_configure_bw_alloc(vsi, enabled_tc, bw_share); if (ret) {
dev_err(&pf->pdev->dev, "Unable to configure TC map %d for VSI %d\n",
enabled_tc, vsi->seid); goto out;
}
}
/* Update Queue Pairs Mapping for currently enabled UPs */
ctxt.seid = vsi->seid;
ctxt.pf_num = vsi->back->hw.pf_id;
ctxt.vf_num = 0;
ctxt.uplink_seid = vsi->uplink_seid;
ctxt.info = vsi->info; if (i40e_is_tc_mqprio_enabled(pf)) {
ret = i40e_vsi_setup_queue_map_mqprio(vsi, &ctxt, enabled_tc); if (ret) goto out;
} else {
i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false);
}
/* On destroying the qdisc, reset vsi->rss_size, as number of enabled *queueschanged.
*/ if (!vsi->mqprio_qopt.qopt.hw && vsi->reconfig_rss) {
vsi->rss_size = min_t(int, vsi->back->alloc_rss_size,
vsi->num_queue_pairs);
ret = i40e_vsi_config_rss(vsi); if (ret) {
dev_info(&vsi->back->pdev->dev, "Failed to reconfig rss for num_queues\n"); return ret;
}
vsi->reconfig_rss = false;
} if (test_bit(I40E_FLAG_IWARP_ENA, vsi->back->flags)) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID);
ctxt.info.queueing_opt_flags |= I40E_AQ_VSI_QUE_OPT_TCP_ENA;
}
/* Update the VSI after updating the VSI queue-mapping *information
*/
ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); if (ret) {
dev_info(&pf->pdev->dev, "Update vsi tc config failed, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(hw->aq.asq_last_status)); goto out;
} /* update the local VSI info with updated queue map */
i40e_vsi_update_queue_map(vsi, &ctxt);
vsi->info.valid_sections = 0;
/* Update current VSI BW information */
ret = i40e_vsi_get_bw_info(vsi); if (ret) {
dev_info(&pf->pdev->dev, "Failed updating vsi bw info, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(hw->aq.asq_last_status)); goto out;
}
switch (pf->hw.phy.link_info.link_speed) { case I40E_LINK_SPEED_40GB: return40000; case I40E_LINK_SPEED_25GB: return25000; case I40E_LINK_SPEED_20GB: return20000; case I40E_LINK_SPEED_10GB: return10000; case I40E_LINK_SPEED_1GB: return1000; default: return -EINVAL;
}
}
/** *i40e_bw_bytes_to_mbits-Convertmax_tx_ratefrombytestombits *@vsi:Pointertovsistructure *@max_tx_rate:maxTXrateinbytestobeconvertedintoMbits * *HelperfunctiontoconvertunitsbeforesendtosetBWlimit
**/ static u64 i40e_bw_bytes_to_mbits(struct i40e_vsi *vsi, u64 max_tx_rate)
{ if (max_tx_rate < I40E_BW_MBPS_DIVISOR) {
dev_warn(&vsi->back->pdev->dev, "Setting max tx rate to minimum usable value of 50Mbps.\n");
max_tx_rate = I40E_BW_CREDIT_DIVISOR;
} else {
do_div(max_tx_rate, I40E_BW_MBPS_DIVISOR);
}
return max_tx_rate;
}
/** *i40e_set_bw_limit-setupBWlimitforTxtrafficbasedonmax_tx_rate *@vsi:VSItobeconfigured *@seid:seidofthechannel/VSI *@max_tx_rate:maxTXratetobeconfiguredasBWlimit * *HelperfunctiontosetBWlimitforagivenVSI
**/ int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate)
{ struct i40e_pf *pf = vsi->back;
u64 credits = 0; int speed = 0; int ret = 0;
speed = i40e_get_link_speed(vsi); if (max_tx_rate > speed) {
dev_err(&pf->pdev->dev, "Invalid max tx rate %llu specified for VSI seid %d.",
max_tx_rate, seid); return -EINVAL;
} if (max_tx_rate && max_tx_rate < I40E_BW_CREDIT_DIVISOR) {
dev_warn(&pf->pdev->dev, "Setting max tx rate to minimum usable value of 50Mbps.\n");
max_tx_rate = I40E_BW_CREDIT_DIVISOR;
}
/* Tx rate credits are in values of 50Mbps, 0 is disabled */
credits = max_tx_rate;
do_div(credits, I40E_BW_CREDIT_DIVISOR);
ret = i40e_aq_config_vsi_bw_limit(&pf->hw, seid, credits,
I40E_MAX_BW_INACTIVE_ACCUM, NULL); if (ret)
dev_err(&pf->pdev->dev, "Failed set tx rate (%llu Mbps) for vsi->seid %u, err %pe aq_err %s\n",
max_tx_rate, seid, ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status)); return ret;
}
/* Reset BW configured for this VSI via mqprio */
ret = i40e_set_bw_limit(vsi, ch->seid, 0); if (ret)
dev_info(&vsi->back->pdev->dev, "Failed to reset tx rate for ch->seid %u\n",
ch->seid);
/* delete cloud filters associated with this channel */
hlist_for_each_entry_safe(cfilter, node,
&pf->cloud_filter_list, cloud_node) { if (cfilter->seid != ch->seid) continue;
hash_del(&cfilter->cloud_node); if (cfilter->dst_port)
ret = i40e_add_del_cloud_filter_big_buf(vsi,
cfilter, false); else
ret = i40e_add_del_cloud_filter(vsi, cfilter, false);
last_aq_status = pf->hw.aq.asq_last_status; if (ret)
dev_info(&pf->pdev->dev, "Failed to delete cloud filter, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(last_aq_status));
kfree(cfilter);
}
/* delete VSI from FW */
ret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,
NULL); if (ret)
dev_err(&vsi->back->pdev->dev, "unable to remove channel (%d) for parent VSI(%d)\n",
ch->seid, p_vsi->seid);
kfree(ch);
}
INIT_LIST_HEAD(&vsi->ch_list);
}
/** *i40e_get_max_queues_for_channel *@vsi:ptrtoVSItowhichchannelsareassociatedwith * *Helperfunctionwhichreturnsmaxvalueamongthequeuecountssetonthe *channels/TCscreated.
**/ staticint i40e_get_max_queues_for_channel(struct i40e_vsi *vsi)
{ struct i40e_channel *ch, *ch_tmp; int max = 0;
list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) { if (!ch->initialized) continue; if (ch->num_queue_pairs > max)
max = ch->num_queue_pairs;
}
/* Ignoring user configured lut if there is one */
i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, local_rss_size);
/* Use user configured hash key if there is one, otherwise *usedefault.
*/ if (vsi->rss_hkey_user)
memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE); else
netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
ret = i40e_config_rss(vsi, seed, lut, vsi->rss_table_size); if (ret) {
dev_info(&pf->pdev->dev, "Cannot set RSS lut, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(hw->aq.asq_last_status));
kfree(lut); return ret;
}
kfree(lut);
/* Do the update w.r.t. storing rss_size */ if (!vsi->orig_rss_size)
vsi->orig_rss_size = vsi->rss_size;
vsi->current_rss_size = local_rss_size;
/* Set queue map for a given VSI context */
i40e_channel_setup_queue_map(pf, &ctxt, ch);
/* Now time to create VSI */
ret = i40e_aq_add_vsi(hw, &ctxt, NULL); if (ret) {
dev_info(&pf->pdev->dev, "add new vsi failed, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status)); return -ENOENT;
}
/* Success, update channel, set enabled_tc only if the channel *isnotamacvlan
*/
ch->enabled_tc = !i40e_is_channel_macvlan(ch) && enabled_tc;
ch->seid = ctxt.seid;
ch->vsi_number = ctxt.vsi_number;
ch->stat_counter_idx = le16_to_cpu(ctxt.info.stat_counter_idx);
/* copy just the sections touched not the entire info *sincenotallsectionsarevalidasreturnedby *updatevsiparams
*/
ch->info.mapping_flags = ctxt.info.mapping_flags;
memcpy(&ch->info.queue_mapping,
&ctxt.info.queue_mapping, sizeof(ctxt.info.queue_mapping));
memcpy(&ch->info.tc_mapping, ctxt.info.tc_mapping, sizeof(ctxt.info.tc_mapping));
return0;
}
staticint i40e_channel_config_bw(struct i40e_vsi *vsi, struct i40e_channel *ch,
u8 *bw_share)
{ struct i40e_aqc_configure_vsi_tc_bw_data bw_data; int ret; int i;
memset(&bw_data, 0, sizeof(bw_data));
bw_data.tc_valid_bits = ch->enabled_tc; for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
bw_data.tc_bw_credits[i] = bw_share[i];
ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, ch->seid,
&bw_data, NULL); if (ret) {
dev_info(&vsi->back->pdev->dev, "Config VSI BW allocation per TC failed, aq_err: %d for new_vsi->seid %u\n",
vsi->back->hw.aq.asq_last_status, ch->seid); return -EINVAL;
}
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
ch->info.qs_handle[i] = bw_data.qs_handles[i];
/* Enable ETS TCs with equal BW Share for now across all VSIs */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { if (ch->enabled_tc & BIT(i))
bw_share[i] = 1;
}
/* configure BW for new VSI */
ret = i40e_channel_config_bw(vsi, ch, bw_share); if (ret) {
dev_info(&vsi->back->pdev->dev, "Failed configuring TC map %d for channel (seid %u)\n",
ch->enabled_tc, ch->seid); return ret;
}
for (i = 0; i < ch->num_queue_pairs; i++) { struct i40e_ring *tx_ring, *rx_ring;
u16 pf_q;
pf_q = ch->base_queue + i;
/* Get to TX ring ptr of main VSI, for re-setup TX queue *context
*/
tx_ring = vsi->tx_rings[pf_q];
tx_ring->ch = ch;
/* Get the RX ring ptr */
rx_ring = vsi->rx_rings[pf_q];
rx_ring->ch = ch;
}
/* Proceed with creation of channel (VMDq2) VSI */
ret = i40e_add_channel(pf, uplink_seid, ch); if (ret) {
dev_info(&pf->pdev->dev, "failed to add_channel using uplink_seid %u\n",
uplink_seid); return ret;
}
/* Mark the successful creation of channel */
ch->initialized = true;
/* Reconfigure TX queues using QTX_CTL register */
ret = i40e_channel_config_tx_ring(pf, vsi, ch); if (ret) {
dev_info(&pf->pdev->dev, "failed to configure TX rings for channel %u\n",
ch->seid); return ret;
}
ret = i40e_get_capabilities(pf, i40e_aqc_opc_list_dev_capabilities); if (ret) return -EINVAL;
if (hw->dev_caps.switch_mode) { /* if switch mode is set, support mode2 (non-tunneled for *cloudfilter)fornow
*/
u32 switch_mode = hw->dev_caps.switch_mode &
I40E_SWITCH_MODE_MASK; if (switch_mode >= I40E_CLOUD_FILTER_MODE1) { if (switch_mode == I40E_CLOUD_FILTER_MODE2) return0;
dev_err(&pf->pdev->dev, "Invalid switch_mode (%d), only non-tunneled mode for cloud filter is supported\n",
hw->dev_caps.switch_mode); return -EINVAL;
}
}
/* Set Bit 7 to be valid */
mode = I40E_AQ_SET_SWITCH_BIT7_VALID;
/* Set L4type for TCP support */
mode |= I40E_AQ_SET_SWITCH_L4_TYPE_TCP;
/* Set cloud filter mode */
mode |= I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL;
/* Prep mode field for set_switch_config */
ret = i40e_aq_set_switch_config(hw, pf->last_sw_conf_flags,
pf->last_sw_conf_valid_flags,
mode, NULL); if (ret && hw->aq.asq_last_status != LIBIE_AQ_RC_ESRCH)
dev_err(&pf->pdev->dev, "couldn't set switch config bits, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(hw->aq.asq_last_status));
/* validate user requested num_queues for channel */
err = i40e_validate_num_queues(pf, ch->num_queue_pairs, vsi,
&reconfig_rss); if (err) {
dev_info(&pf->pdev->dev, "Failed to validate num_queues (%d)\n",
ch->num_queue_pairs); return -EINVAL;
}
/* By default we are in VEPA mode, if this is the first VF/VMDq *VSItobeaddedswitchtoVEBmode.
*/
if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) {
set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
if (vsi->type == I40E_VSI_MAIN) { if (i40e_is_tc_mqprio_enabled(pf))
i40e_do_reset(pf, I40E_PF_RESET_FLAG, true); else
i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
} /* now onwards for main VSI, number of queues will be value *ofTC0'squeuecount
*/
}
/* By this time, vsi->cnt_q_avail shall be set to non-zero and *itshouldbemorethannum_queues
*/ if (!vsi->cnt_q_avail || vsi->cnt_q_avail < ch->num_queue_pairs) {
dev_dbg(&pf->pdev->dev, "Error: cnt_q_avail (%u) less than num_queues %d\n",
vsi->cnt_q_avail, ch->num_queue_pairs); return -EINVAL;
}
/* reconfig_rss only if vsi type is MAIN_VSI */ if (reconfig_rss && (vsi->type == I40E_VSI_MAIN)) {
err = i40e_vsi_reconfig_rss(vsi, ch->num_queue_pairs); if (err) {
dev_info(&pf->pdev->dev, "Error: unable to reconfig rss for num_queues (%u)\n",
ch->num_queue_pairs); return -EINVAL;
}
}
if (!i40e_setup_channel(pf, vsi, ch)) {
dev_info(&pf->pdev->dev, "Failed to setup channel\n"); return -EINVAL;
}
/* Create app vsi with the TCs. Main VSI with TC0 is already set up */
vsi->tc_seid_map[0] = vsi->seid; for (i = 1; i < I40E_MAX_TRAFFIC_CLASS; i++) { if (vsi->tc_config.enabled_tc & BIT(i)) {
ch = kzalloc(sizeof(*ch), GFP_KERNEL); if (!ch) {
ret = -ENOMEM; goto err_free;
}
/** *i40e_veb_config_tc-ConfigureTCsforgivenVEB *@veb:givenVEB *@enabled_tc:TCbitmap * *ConfiguresgivenTCbitmapforVEB(switching)element
**/ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc)
{ struct i40e_aqc_configure_switching_comp_bw_config_data bw_data = {0}; struct i40e_pf *pf = veb->pf; int ret = 0; int i;
/* No TCs or already enabled TCs just return */ if (!enabled_tc || veb->enabled_tc == enabled_tc) return ret;
bw_data.tc_valid_bits = enabled_tc; /* bw_data.absolute_credits is not set (relative) */
/* Enable ETS TCs with equal BW Share for now */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { if (enabled_tc & BIT(i))
bw_data.tc_bw_share_credits[i] = 1;
}
/* Update the BW information */
ret = i40e_veb_get_bw_info(veb); if (ret) {
dev_info(&pf->pdev->dev, "Failed getting veb bw config, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status));
}
/* Enable the TCs available on PF to all VEBs */
tc_map = i40e_pf_get_tc_map(pf); if (tc_map == I40E_DEFAULT_TRAFFIC_CLASS) return;
i40e_pf_for_each_veb(pf, v, veb) {
ret = i40e_veb_config_tc(veb, tc_map); if (ret) {
dev_info(&pf->pdev->dev, "Failed configuring TC for VEB seid=%d\n",
veb->seid); /* Will try to configure as many components */
}
}
/* Update each VSI */
i40e_pf_for_each_vsi(pf, v, vsi) { /* - Enable all TCs for the LAN VSI *-ForallotherskeepthematTC0fornow
*/ if (vsi->type == I40E_VSI_MAIN)
tc_map = i40e_pf_get_tc_map(pf); else
tc_map = I40E_DEFAULT_TRAFFIC_CLASS;
ret = i40e_vsi_config_tc(vsi, tc_map); if (ret) {
dev_info(&pf->pdev->dev, "Failed configuring TC for VSI seid=%d\n",
vsi->seid); /* Will try to configure as many components */
} else { /* Re-configure VSI vectors based on updated TC map */
i40e_vsi_map_rings_to_vectors(vsi); if (vsi->netdev)
i40e_dcbnl_set_all(vsi);
}
}
}
/* Check if need reconfiguration */ if (!memcmp(&new_cfg, &old_cfg, sizeof(new_cfg))) {
dev_dbg(&pf->pdev->dev, "No Change in DCB Config required.\n"); return0;
}
/* Config change disable all VSIs */
i40e_pf_quiesce_all_vsi(pf);
/* Copy the new config to the current config */
*old_cfg = *new_cfg;
old_cfg->etsrec = old_cfg->etscfg;
ret = i40e_set_dcb_config(&pf->hw); if (ret) {
dev_info(&pf->pdev->dev, "Set DCB Config failed, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status)); goto out;
}
/* Changes in configuration update VEB/VSI */
i40e_dcb_reconfigure(pf);
out: /* In case of reset do not try to resume anything */ if (!test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) { /* Re-start the VSIs if disabled */
ret = i40e_resume_port_tx(pf); /* In case of error no point in resuming VSIs */ if (ret) goto err;
i40e_pf_unquiesce_all_vsi(pf);
}
err: return ret;
}
dev_dbg(&pf->pdev->dev, "Configuring DCB registers directly\n"); /* Un-pack information to Program ETS HW via shared API *numtc,tcmap *LLTCmap *ETS/NON-ETSarbitermode *maxexponent(creditrefills) *Totalnumberofports *PFCprioritybit-map *PriorityTable *BW%perTC *ArbitermodebetweenUPssharingsameTC *TSAtable(ETSornon-ETS) *EEEenabledornot *MFSTCtable
*/
new_numtc = i40e_dcb_get_num_tc(new_cfg);
memset(&ets_data, 0, sizeof(ets_data)); for (i = 0; i < new_numtc; i++) {
tc_map |= BIT(i); switch (new_cfg->etscfg.tsatable[i]) { case I40E_IEEE_TSA_ETS:
prio_type[i] = I40E_DCB_PRIO_TYPE_ETS;
ets_data.tc_bw_share_credits[i] =
new_cfg->etscfg.tcbwtable[i]; break; case I40E_IEEE_TSA_STRICT:
prio_type[i] = I40E_DCB_PRIO_TYPE_STRICT;
lltc_map |= BIT(i);
ets_data.tc_bw_share_credits[i] =
I40E_DCB_STRICT_PRIO_CREDITS; break; default: /* Invalid TSA type */
need_reconfig = false; goto out;
}
}
old_cfg = &hw->local_dcbx_config; /* Check if need reconfiguration */
need_reconfig = i40e_dcb_need_reconfig(pf, old_cfg, new_cfg);
/* If needed, enable/disable frame tagging, disable all VSIs *andsuspendporttx
*/ if (need_reconfig) { /* Enable DCB tagging only when more than one TC */ if (new_numtc > 1)
set_bit(I40E_FLAG_DCB_ENA, pf->flags); else
clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
set_bit(__I40E_PORT_SUSPENDED, pf->state); /* Reconfiguration needed quiesce all VSIs */
i40e_pf_quiesce_all_vsi(pf);
ret = i40e_suspend_port_tx(pf); if (ret) goto err;
}
/* Configure Port ETS Tx Scheduler */
ets_data.tc_valid_bits = tc_map;
ets_data.tc_strict_priority_flags = lltc_map;
ret = i40e_aq_config_switch_comp_ets
(hw, pf->mac_seid, &ets_data,
i40e_aqc_opc_modify_switching_comp_ets, NULL); if (ret) {
dev_info(&pf->pdev->dev, "Modify Port ETS failed, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status)); goto out;
}
/* Update the local Rx Packet buffer config */
pf->pb_cfg = pb_cfg;
/* Inform the FW about changes to DCB configuration */
ret = i40e_aq_dcb_updated(&pf->hw, NULL); if (ret) {
dev_info(&pf->pdev->dev, "DCB Updated failed, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status)); goto out;
}
/* Update the port DCBx configuration */
*old_cfg = *new_cfg;
/* Changes in configuration update VEB/VSI */
i40e_dcb_reconfigure(pf);
out: /* Re-start the VSIs if disabled */ if (need_reconfig) {
ret = i40e_resume_port_tx(pf);
clear_bit(__I40E_PORT_SUSPENDED, pf->state); /* In case of error no point in resuming VSIs */ if (ret) goto err;
/* Wait for the PF's queues to be disabled */
ret = i40e_pf_wait_queues_disabled(pf); if (ret) { /* Schedule PF reset to recover */
set_bit(__I40E_PF_RESET_REQUESTED, pf->state);
i40e_service_event_schedule(pf); goto err;
} else {
i40e_pf_unquiesce_all_vsi(pf);
set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
set_bit(__I40E_CLIENT_L2_CHANGE, pf->state);
} /* registers are set, lets apply */ if (test_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps))
ret = i40e_hw_set_dcb_config(pf, new_cfg);
}
/* Do not enable DCB for SW1 and SW2 images even if the FW is capable *AlsodonotenableDCBxifFWLLDPagentisdisabled
*/ if (test_bit(I40E_HW_CAP_NO_DCB_SUPPORT, pf->hw.caps)) {
dev_info(&pf->pdev->dev, "DCB is not supported.\n");
err = -EOPNOTSUPP; goto out;
} if (test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags)) {
dev_info(&pf->pdev->dev, "FW LLDP is disabled, attempting SW DCB\n");
err = i40e_dcb_sw_default_config(pf); if (err) {
dev_info(&pf->pdev->dev, "Could not initialize SW DCB\n"); goto out;
}
dev_info(&pf->pdev->dev, "SW DCB initialization succeeded.\n");
pf->dcbx_cap = DCB_CAP_DCBX_HOST |
DCB_CAP_DCBX_VER_IEEE; /* at init capable but disabled */
set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
clear_bit(I40E_FLAG_DCB_ENA, pf->flags); goto out;
}
err = i40e_init_dcb(hw, true); if (!err) { /* Device/Function is not DCBX capable */ if ((!hw->func_caps.dcb) ||
(hw->dcbx_status == I40E_DCBX_STATUS_DISABLED)) {
dev_info(&pf->pdev->dev, "DCBX offload is not supported or is disabled for this PF.\n");
} else { /* When status is not DISABLED then DCBX in FW */
pf->dcbx_cap = DCB_CAP_DCBX_LLD_MANAGED |
DCB_CAP_DCBX_VER_IEEE;
set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); /* Enable DCB tagging only when more than one TC *orexplicitlydisableifonlyoneTC
*/ if (i40e_dcb_get_num_tc(&hw->local_dcbx_config) > 1)
set_bit(I40E_FLAG_DCB_ENA, pf->flags); else
clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
dev_dbg(&pf->pdev->dev, "DCBX offload is supported for this PF.\n");
}
} elseif (pf->hw.aq.asq_last_status == LIBIE_AQ_RC_EPERM) {
dev_info(&pf->pdev->dev, "FW LLDP disabled for this PF.\n");
set_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags);
} else {
dev_info(&pf->pdev->dev, "Query for DCB configuration failed, err %pe aq_err %s\n",
ERR_PTR(err), libie_aq_str(pf->hw.aq.asq_last_status));
}
if (isup)
new_speed = pf->hw.phy.link_info.link_speed; else
new_speed = I40E_LINK_SPEED_UNKNOWN;
if ((vsi->current_isup == isup) && (vsi->current_speed == new_speed)) return;
vsi->current_isup = isup;
vsi->current_speed = new_speed; if (!isup) {
netdev_info(vsi->netdev, "NIC Link is Down\n"); return;
}
/* Warn user if link speed on NPAR enabled partition is not at *least10GB
*/ if (pf->hw.func_caps.npar_enable &&
(pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_1GB ||
pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_100MB))
netdev_warn(vsi->netdev, "The partition detected link speed that is less than 10Gbps\n");
switch (pf->hw.phy.link_info.link_speed) { case I40E_LINK_SPEED_40GB:
speed = "40 G"; break; case I40E_LINK_SPEED_20GB:
speed = "20 G"; break; case I40E_LINK_SPEED_25GB:
speed = "25 G"; break; case I40E_LINK_SPEED_10GB:
speed = "10 G"; break; case I40E_LINK_SPEED_5GB:
speed = "5 G"; break; case I40E_LINK_SPEED_2_5GB:
speed = "2.5 G"; break; case I40E_LINK_SPEED_1GB:
speed = "1000 M"; break; case I40E_LINK_SPEED_100MB:
speed = "100 M"; break; default: break;
}
switch (pf->hw.fc.current_mode) { case I40E_FC_FULL:
fc = "RX/TX"; break; case I40E_FC_TX_PAUSE:
fc = "TX"; break; case I40E_FC_RX_PAUSE:
fc = "RX"; break; default:
fc = "None"; break;
}
if (pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_25GB) {
req_fec = "None";
fec = "None";
an = "False";
if (pf->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED)
an = "True";
/* On the next run of the service_task, notify any clients of the new *openednetdev
*/
set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
i40e_service_event_schedule(pf);
/* Card might've been put in an unstable state by other drivers *andapplications,whichcausesincorrectspeedvaluesbeing *setonstartup.Inordertoclearspeedregisters,wecall *get_phy_capabilitiestwice,oncetogetinitialstateof *availablespeeds,andoncetogetcurrentPHYconfig.
*/
err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities,
NULL); if (err) {
dev_err(&pf->pdev->dev, "failed to get phy cap., ret = %pe last_status = %s\n",
ERR_PTR(err), libie_aq_str(hw->aq.asq_last_status)); return err;
}
speed = abilities.link_speed;
/* Get the current phy config */
err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
NULL); if (err) {
dev_err(&pf->pdev->dev, "failed to get phy cap., ret = %pe last_status = %s\n",
ERR_PTR(err), libie_aq_str(hw->aq.asq_last_status)); return err;
}
/* If link needs to go up, but was not forced to go down, *anditsspeedvaluesareOK,noneedforaflap *ifnon_zero_phy_typewasset,stillneedtoforceup
*/ if (test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags))
non_zero_phy_type = true; elseif (is_up && abilities.phy_type != 0 && abilities.link_speed != 0) return0;
/* To force link we need to set bits for all supported PHY types, *buttherearenowmorethan32,soweneedtosplitthebitmap *acrosstwofields.
*/
mask = I40E_PHY_TYPES_BITMASK;
config.phy_type =
non_zero_phy_type ? cpu_to_le32((u32)(mask & 0xffffffff)) : 0;
config.phy_type_ext =
non_zero_phy_type ? (u8)((mask >> 32) & 0xff) : 0; /* Copy the old settings, except of phy_type */
config.abilities = abilities.abilities; if (test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) { if (is_up)
config.abilities |= I40E_AQ_PHY_ENABLE_LINK; else
config.abilities &= ~(I40E_AQ_PHY_ENABLE_LINK);
} if (abilities.link_speed != 0)
config.link_speed = abilities.link_speed; else
config.link_speed = speed;
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;
err = i40e_aq_set_phy_config(hw, &config, NULL);
if (err) {
dev_err(&pf->pdev->dev, "set phy config ret = %pe last_status = %s\n",
ERR_PTR(err), libie_aq_str(pf->hw.aq.asq_last_status)); return err;
}
/* Update the link info */
err = i40e_update_link_info(hw); if (err) { /* Wait a little bit (on 40G cards it sometimes takes a really *longtimeforlinktocomebackfromtheatomicreset) *andtryoncemore
*/
msleep(1000);
i40e_update_link_info(hw);
}
i40e_aq_set_link_restart_an(hw, is_up, NULL);
return0;
}
/** *i40e_up-Bringtheconnectionbackupafterbeingdown *@vsi:theVSIbeingconfigured
**/ int i40e_up(struct i40e_vsi *vsi)
{ int err;
/* It is assumed that the caller of this function *setsthevsi->state__I40E_VSI_DOWNbit.
*/ if (vsi->netdev) {
netif_carrier_off(vsi->netdev);
netif_tx_disable(vsi->netdev);
}
i40e_vsi_disable_irq(vsi);
i40e_vsi_stop_rings(vsi); if (vsi->type == I40E_VSI_MAIN &&
(test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags) ||
test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, vsi->back->flags)))
i40e_force_link_state(vsi->back, false);
i40e_napi_disable_all(vsi);
for (i = 0; i < vsi->num_queue_pairs; i++) {
i40e_clean_tx_ring(vsi->tx_rings[i]); if (i40e_enabled_xdp_vsi(vsi)) { /* Make sure that in-progress ndo_xdp_xmit and *ndo_xsk_wakeupcallsarecompleted.
*/
synchronize_rcu();
i40e_clean_tx_ring(vsi->xdp_rings[i]);
}
i40e_clean_rx_ring(vsi->rx_rings[i]);
}
/* Only TC0 is enabled */
vsi->tc_config.numtc = 1;
vsi->tc_config.enabled_tc = 1;
qcount = min_t(int, vsi->alloc_queue_pairs,
i40e_pf_get_max_q_per_tc(vsi->back)); for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { /* For the TC that is not enabled set the offset to default *queueandallocateonequeueforthegivenTC.
*/
vsi->tc_config.tc_info[i].qoffset = 0; if (i == 0)
vsi->tc_config.tc_info[i].qcount = qcount; else
vsi->tc_config.tc_info[i].qcount = 1;
vsi->tc_config.tc_info[i].netdev_tc = 0;
}
}
/* remove the VSI */
ret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,
NULL); if (ret)
dev_err(&vsi->back->pdev->dev, "unable to remove channel (%d) for parent VSI(%d)\n",
ch->seid, parent_vsi->seid);
kfree(ch);
}
vsi->macvlan_cnt = 0;
}
/* Go through the list and find an available channel */
list_for_each_entry_safe(iter, ch_tmp, &vsi->macvlan_list, list) { if (!i40e_is_channel_macvlan(iter)) {
iter->fwd = fwd; /* record configuration for macvlan interface in vdev */ for (i = 0; i < num_tc; i++)
netdev_bind_sb_channel_queue(vsi->netdev, vdev,
i,
iter->num_queue_pairs,
iter->base_queue); for (i = 0; i < iter->num_queue_pairs; i++) { struct i40e_ring *tx_ring, *rx_ring;
u16 pf_q;
pf_q = iter->base_queue + i;
/* Get to TX ring ptr */
tx_ring = vsi->tx_rings[pf_q];
tx_ring->ch = iter;
/* Get the RX ring ptr */
rx_ring = vsi->rx_rings[pf_q];
rx_ring->ch = iter;
}
ch = iter; break;
}
}
if (!ch) return -EINVAL;
/* Guarantee all rings are updated before we update the *MACaddressfilter.
*/
wmb();
/* Add a mac filter */
ret = i40e_add_macvlan_filter(hw, ch->seid, vdev->dev_addr, &aq_err); if (ret) { /* if we cannot add the MAC rule then disable the offload */
macvlan_release_l2fw_offload(vdev); for (i = 0; i < ch->num_queue_pairs; i++) { struct i40e_ring *rx_ring;
u16 pf_q;
/* Reconfigure RSS for main VSI with new max queue count */
vsi->rss_size = max_t(u16, num_qps, qcnt);
ret = i40e_vsi_config_rss(vsi); if (ret) {
dev_info(&pf->pdev->dev, "Failed to reconfig RSS for num_queues (%u)\n",
vsi->rss_size); return ret;
}
vsi->reconfig_rss = true;
dev_dbg(&vsi->back->pdev->dev, "Reconfigured RSS with num_queues (%u)\n", vsi->rss_size);
vsi->next_base_queue = num_qps;
vsi->cnt_q_avail = vsi->num_queue_pairs - num_qps;
/* Update the VSI after updating the VSI queue-mapping *information
*/
ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); if (ret) {
dev_info(&pf->pdev->dev, "Update vsi tc config failed, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(hw->aq.asq_last_status)); return ret;
} /* update the local VSI info with updated queue map */
i40e_vsi_update_queue_map(vsi, &ctxt);
vsi->info.valid_sections = 0;
/* Create channels for macvlans */
INIT_LIST_HEAD(&vsi->macvlan_list); for (i = 0; i < macvlan_cnt; i++) {
ch = kzalloc(sizeof(*ch), GFP_KERNEL); if (!ch) {
ret = -ENOMEM; goto err_free;
}
INIT_LIST_HEAD(&ch->list);
ch->num_queue_pairs = qcnt; if (!i40e_setup_channel(pf, vsi, ch)) {
ret = -EINVAL;
kfree(ch); goto err_free;
}
ch->parent_vsi = vsi;
vsi->cnt_q_avail -= ch->num_queue_pairs;
vsi->macvlan_cnt++;
list_add_tail(&ch->list, &vsi->macvlan_list);
}
return ret;
err_free:
dev_info(&pf->pdev->dev, "Failed to setup macvlans\n");
i40e_free_macvlan_channels(vsi);
if (test_bit(I40E_FLAG_DCB_ENA, pf->flags)) {
netdev_info(netdev, "Macvlans are not supported when DCB is enabled\n"); return ERR_PTR(-EINVAL);
} if (i40e_is_tc_mqprio_enabled(pf)) {
netdev_info(netdev, "Macvlans are not supported when HW TC offload is on\n"); return ERR_PTR(-EINVAL);
} if (pf->num_lan_msix < I40E_MIN_MACVLAN_VECTORS) {
netdev_info(netdev, "Not enough vectors available to support macvlans\n"); return ERR_PTR(-EINVAL);
}
/* The macvlan device has to be a single Q device so that the *tc_to_txqfieldcanbereusedtopickthetxqueue.
*/ if (netif_is_multiqueue(vdev)) return ERR_PTR(-ERANGE);
if (!vsi->macvlan_cnt) { /* reserve bit 0 for the pf device */
set_bit(0, vsi->fwd_bitmask);
/* Try to reserve as many queues as possible for macvlans. First *reserve3/4thofmaxvectors,thenhalf,thenquarterand *calculateQspermacvlanasyougo
*/
vectors = pf->num_lan_msix; if (vectors <= I40E_MAX_MACVLANS && vectors > 64) { /* allocate 4 Qs per macvlan and 32 Qs to the PF*/
q_per_macvlan = 4;
macvlan_cnt = (vectors - 32) / 4;
} elseif (vectors <= 64 && vectors > 32) { /* allocate 2 Qs per macvlan and 16 Qs to the PF*/
q_per_macvlan = 2;
macvlan_cnt = (vectors - 16) / 2;
} elseif (vectors <= 32 && vectors > 16) { /* allocate 1 Q per macvlan and 16 Qs to the PF*/
q_per_macvlan = 1;
macvlan_cnt = vectors - 16;
} elseif (vectors <= 16 && vectors > 8) { /* allocate 1 Q per macvlan and 8 Qs to the PF */
q_per_macvlan = 1;
macvlan_cnt = vectors - 8;
} else { /* allocate 1 Q per macvlan and 1 Q to the PF */
q_per_macvlan = 1;
macvlan_cnt = vectors - 1;
}
if (macvlan_cnt == 0) return ERR_PTR(-EBUSY);
/* Quiesce VSI queues */
i40e_quiesce_vsi(vsi);
/* sets up the macvlans but does not "enable" them */
ret = i40e_setup_macvlans(vsi, macvlan_cnt, q_per_macvlan,
vdev); if (ret) return ERR_PTR(ret);
/* Unquiesce VSI */
i40e_unquiesce_vsi(vsi);
}
avail_macvlan = find_first_zero_bit(vsi->fwd_bitmask,
vsi->macvlan_cnt); if (avail_macvlan >= I40E_MAX_MACVLANS) return ERR_PTR(-EBUSY);
/* create the fwd struct */
fwd = kzalloc(sizeof(*fwd), GFP_KERNEL); if (!fwd) return ERR_PTR(-ENOMEM);
/* Set fwd ring up */
ret = i40e_fwd_ring_up(vsi, vdev, fwd); if (ret) { /* unbind the queues and drop the subordinate channel config */
netdev_unbind_sb_channel(netdev, vdev);
netdev_set_sb_channel(vdev, 0);
/* Check if MFP enabled */ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) {
netdev_info(netdev, "Configuring TC not supported in MFP mode\n"); return ret;
} switch (mode) { case TC_MQPRIO_MODE_DCB:
clear_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags);
/* Check if DCB enabled to continue */ if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) {
netdev_info(netdev, "DCB is not enabled for adapter\n"); return ret;
}
/* Check whether tc count is within enabled limit */ if (num_tc > i40e_pf_get_num_tc(pf)) {
netdev_info(netdev, "TC count greater than enabled on link for adapter\n"); return ret;
} break; case TC_MQPRIO_MODE_CHANNEL: if (test_bit(I40E_FLAG_DCB_ENA, pf->flags)) {
netdev_info(netdev, "Full offload of TC Mqprio options is not supported when DCB is enabled\n"); return ret;
} if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) return ret;
ret = i40e_validate_mqprio_qopt(vsi, mqprio_qopt); if (ret) return ret;
memcpy(&vsi->mqprio_qopt, mqprio_qopt, sizeof(*mqprio_qopt));
set_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags);
clear_bit(I40E_FLAG_DCB_ENA, pf->flags); break; default: return -EINVAL;
}
config_tc: /* Generate TC map for number of tc requested */ for (i = 0; i < num_tc; i++)
enabled_tc |= BIT(i);
/* Requesting same TC configuration as already enabled */ if (enabled_tc == vsi->tc_config.enabled_tc &&
mode != TC_MQPRIO_MODE_CHANNEL) return0;
/* Quiesce VSI queues */
i40e_quiesce_vsi(vsi);
if (!hw && !i40e_is_tc_mqprio_enabled(pf))
i40e_remove_queue_channels(vsi);
/* Configure VSI for enabled TCs */
ret = i40e_vsi_config_tc(vsi, enabled_tc); if (ret) {
netdev_info(netdev, "Failed configuring TC for VSI seid=%d\n",
vsi->seid);
need_reset = true; gotoexit;
} elseif (enabled_tc &&
(!is_power_of_2(vsi->tc_config.tc_info[0].qcount))) {
netdev_info(netdev, "Failed to create channel. Override queues (%u) not power of 2\n",
vsi->tc_config.tc_info[0].qcount);
ret = -EINVAL;
need_reset = true; gotoexit;
}
/* tenant_id is not supported by FW now, once the support is enabled *fillthecld->tenant_idwithcpu_to_le32(filter->tenant_id)
*/ if (filter->tenant_id) return;
}
/* Both (src/dst) valid mac_addr are not supported */ if ((is_valid_ether_addr(filter->dst_mac) &&
is_valid_ether_addr(filter->src_mac)) ||
(is_multicast_ether_addr(filter->dst_mac) &&
is_multicast_ether_addr(filter->src_mac))) return -EOPNOTSUPP;
/* Big buffer cloud filter needs 'L4 port' to be non-zero. Also, UDP *portsarenotsupportedviabigbuffernow.
*/ if (!filter->dst_port || filter->ip_proto == IPPROTO_UDP) return -EOPNOTSUPP;
/* adding filter using src_port/src_ip is not supported at this stage */ if (filter->src_port ||
(filter->src_ipv4 && filter->n_proto != ETH_P_IPV6) ||
!ipv6_addr_any(&filter->ip.v6.src_ip6)) return -EOPNOTSUPP;
memset(&cld_filter, 0, sizeof(cld_filter));
/* copy element needed to add cloud filter from filter */
i40e_set_cld_element(filter, &cld_filter.element);
if (is_valid_ether_addr(filter->dst_mac) ||
is_valid_ether_addr(filter->src_mac) ||
is_multicast_ether_addr(filter->dst_mac) ||
is_multicast_ether_addr(filter->src_mac)) { /* MAC + IP : unsupported mode */ if (filter->dst_ipv4) return -EOPNOTSUPP;
/* since we validated that L4 port must be valid before *wegethere,startwithrespective"flags"value *andupdateifvlanispresentornot
*/
cld_filter.element.flags =
cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT);
if (filter->vlan_id) {
cld_filter.element.flags =
cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);
}
} elseif ((filter->dst_ipv4 && filter->n_proto != ETH_P_IPV6) ||
!ipv6_addr_any(&filter->ip.v6.dst_ip6)) {
cld_filter.element.flags =
cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT); if (filter->n_proto == ETH_P_IPV6)
cld_filter.element.flags |=
cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV6); else
cld_filter.element.flags |=
cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV4);
} else {
dev_err(&pf->pdev->dev, "either mac or ip has to be valid for cloud filter\n"); return -EINVAL;
}
/* Now copy L4 port in Byte 6..7 in general fields */
cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0] =
be16_to_cpu(filter->dst_port);
if (add) { /* Validate current device switch mode, change if necessary */
ret = i40e_validate_and_set_switch_mode(vsi); if (ret) {
dev_err(&pf->pdev->dev, "failed to set switch mode, ret %d\n",
ret); return ret;
}
ret = i40e_aq_add_cloud_filters_bb(&pf->hw, filter->seid,
&cld_filter, 1);
} else {
ret = i40e_aq_rem_cloud_filters_bb(&pf->hw, filter->seid,
&cld_filter, 1);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { struct flow_match_eth_addrs match;
flow_rule_match_eth_addrs(rule, &match);
/* use is_broadcast and is_zero to check for all 0xf or 0 */ if (!is_zero_ether_addr(match.mask->dst)) { if (is_broadcast_ether_addr(match.mask->dst)) {
field_flags |= I40E_CLOUD_FIELD_OMAC;
} else {
dev_err(&pf->pdev->dev, "Bad ether dest mask %pM\n",
match.mask->dst); return -EIO;
}
}
if (flow_rule_has_control_flags(match.mask->flags,
f->common.extack)) return -EOPNOTSUPP;
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { struct flow_match_ipv4_addrs match;
flow_rule_match_ipv4_addrs(rule, &match); if (match.mask->dst) { if (match.mask->dst == cpu_to_be32(0xffffffff)) {
field_flags |= I40E_CLOUD_FIELD_IIP;
} else {
dev_err(&pf->pdev->dev, "Bad ip dst mask %pI4b\n",
&match.mask->dst); return -EIO;
}
}
if (match.mask->src) { if (match.mask->src == cpu_to_be32(0xffffffff)) {
field_flags |= I40E_CLOUD_FIELD_IIP;
} else {
dev_err(&pf->pdev->dev, "Bad ip src mask %pI4b\n",
&match.mask->src); return -EIO;
}
}
if (field_flags & I40E_CLOUD_FIELD_TEN_ID) {
dev_err(&pf->pdev->dev, "Tenant id not allowed for ip filter\n"); return -EIO;
}
filter->dst_ipv4 = match.key->dst;
filter->src_ipv4 = match.key->src;
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { struct flow_match_ipv6_addrs match;
flow_rule_match_ipv6_addrs(rule, &match);
/* src and dest IPV6 address should not be LOOPBACK *(0:0:0:0:0:0:0:1),whichcanberepresentedas::1
*/ if (ipv6_addr_loopback(&match.key->dst) ||
ipv6_addr_loopback(&match.key->src)) {
dev_err(&pf->pdev->dev, "Bad ipv6, addr is LOOPBACK\n"); return -EIO;
} if (!ipv6_addr_any(&match.mask->dst) ||
!ipv6_addr_any(&match.mask->src))
field_flags |= I40E_CLOUD_FIELD_IIP;
/* direct to a traffic class on the same device */ if (tc == 0) {
filter->seid = vsi->seid; return0;
} elseif (vsi->tc_config.enabled_tc & BIT(tc)) { if (!filter->dst_port) {
dev_err(&vsi->back->pdev->dev, "Specify destination port to direct to traffic class that is not default\n"); return -EINVAL;
} if (list_empty(&vsi->ch_list)) return -EINVAL;
list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list,
list) { if (ch->seid == vsi->tc_seid_map[tc])
filter->seid = ch->seid;
} return0;
}
dev_err(&vsi->back->pdev->dev, "TC is not enabled\n"); return -EINVAL;
}
/* disallow open during test or if eeprom is broken */ if (test_bit(__I40E_TESTING, pf->state) ||
test_bit(__I40E_BAD_EEPROM, pf->state)) return -EBUSY;
netif_carrier_off(netdev);
if (i40e_force_link_state(pf, true)) return -EAGAIN;
/* Reprogram the default input set for TCP/IPv4 */
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV4_TCP,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for TCP/IPv6 */
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV6_TCP,
I40E_L3_V6_SRC_MASK | I40E_L3_V6_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for UDP/IPv4 */
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV4_UDP,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for UDP/IPv6 */
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV6_UDP,
I40E_L3_V6_SRC_MASK | I40E_L3_V6_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for SCTP/IPv4 */
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV4_SCTP,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for SCTP/IPv6 */
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV6_SCTP,
I40E_L3_V6_SRC_MASK | I40E_L3_V6_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for Other/IPv4 */
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV4_OTHER,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK);
/* Reprogram the default input set for Other/IPv6 */
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV6_OTHER,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK);
} elseif (reset_flags & BIT_ULL(__I40E_REINIT_REQUESTED)) { /* Find the VSI(s) that requested a re-init */
dev_info(&pf->pdev->dev, "VSI reinit requested\n");
i40e_pf_for_each_vsi(pf, i, vsi) { if (test_and_clear_bit(__I40E_VSI_REINIT_REQUESTED,
vsi->state))
i40e_vsi_reinit_locked(vsi);
}
} elseif (reset_flags & BIT_ULL(__I40E_DOWN_REQUESTED)) { /* Find the VSI(s) that needs to be brought down */
dev_info(&pf->pdev->dev, "VSI down requested\n");
/* X710-T*L 2.5G and 5G speeds don't support DCB */ if (I40E_IS_X710TL_DEVICE(hw->device_id) &&
(hw->phy.link_info.link_speed &
~(I40E_LINK_SPEED_2_5GB | I40E_LINK_SPEED_5GB)) &&
!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) /* let firmware decide if the DCB should be disabled */
set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
/* Not DCB capable or capability disabled */ if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) return ret;
/* Ignore if event is not for Nearest Bridge */
type = ((mib->type >> I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT)
& I40E_AQ_LLDP_BRIDGE_TYPE_MASK);
dev_dbg(&pf->pdev->dev, "LLDP event mib bridge type 0x%x\n", type); if (type != I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE) return ret;
/* Check MIB Type and return if event for Remote MIB update */
type = mib->type & I40E_AQ_LLDP_MIB_TYPE_MASK;
dev_dbg(&pf->pdev->dev, "LLDP event mib type %s\n", type ? "remote" : "local"); if (type == I40E_AQ_LLDP_MIB_REMOTE) { /* Update the remote cached instance and return */
ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
&hw->remote_dcbx_config); gotoexit;
}
/* Store the old configuration */
tmp_dcbx_cfg = hw->local_dcbx_config;
/* Reset the old DCBx configuration data */
memset(&hw->local_dcbx_config, 0, sizeof(hw->local_dcbx_config)); /* Get updated DCBX data from firmware */
ret = i40e_get_dcb_config(&pf->hw); if (ret) { /* X710-T*L 2.5G and 5G speeds don't support DCB */ if (I40E_IS_X710TL_DEVICE(hw->device_id) &&
(hw->phy.link_info.link_speed &
(I40E_LINK_SPEED_2_5GB | I40E_LINK_SPEED_5GB))) {
dev_warn(&pf->pdev->dev, "DCB is not supported for X710-T*L 2.5/5G speeds\n");
clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
} else {
dev_info(&pf->pdev->dev, "Failed querying DCB configuration data from firmware, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status));
} gotoexit;
}
/* No change detected in DCBX configs */ if (!memcmp(&tmp_dcbx_cfg, &hw->local_dcbx_config, sizeof(tmp_dcbx_cfg))) {
dev_dbg(&pf->pdev->dev, "No change detected in DCBX configuration.\n"); gotoexit;
}
/* Enable DCB tagging only when more than one TC */ if (i40e_dcb_get_num_tc(&hw->local_dcbx_config) > 1)
set_bit(I40E_FLAG_DCB_ENA, pf->flags); else
clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
set_bit(__I40E_PORT_SUSPENDED, pf->state); /* Reconfiguration needed quiesce all VSIs */
i40e_pf_quiesce_all_vsi(pf);
/* Changes in configuration update VEB/VSI */
i40e_dcb_reconfigure(pf);
ret = i40e_resume_port_tx(pf);
clear_bit(__I40E_PORT_SUSPENDED, pf->state); /* In case of error no point in resuming VSIs */ if (ret) gotoexit;
/* Wait for the PF's queues to be disabled */
ret = i40e_pf_wait_queues_disabled(pf); if (ret) { /* Schedule PF reset to recover */
set_bit(__I40E_PF_RESET_REQUESTED, pf->state);
i40e_service_event_schedule(pf);
} else {
i40e_pf_unquiesce_all_vsi(pf);
set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
set_bit(__I40E_CLIENT_L2_CHANGE, pf->state);
}
/** *i40e_reenable_fdir_sb-RestoreFDirSBcapability *@pf:boardprivatestructure
**/ staticvoid i40e_reenable_fdir_sb(struct i40e_pf *pf)
{ if (test_and_clear_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state)) if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) &&
(I40E_DEBUG_FD & pf->hw.debug_mask))
dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
}
/** *i40e_reenable_fdir_atr-RestoreFDirATRcapability *@pf:boardprivatestructure
**/ staticvoid i40e_reenable_fdir_atr(struct i40e_pf *pf)
{ if (test_and_clear_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) { /* ATR uses the same filtering logic as SB rules. It only *functionsproperlyiftheinputsetmaskisatthedefault *settings.Itissafetorestorethedefaultinputset *becausetherearenoactiveTCPv4filterrules.
*/
i40e_write_fd_input_set(pf, LIBIE_FILTER_PCTYPE_NONF_IPV4_TCP,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) &&
(I40E_DEBUG_FD & pf->hw.debug_mask))
dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
}
}
switch (filter->flow_type) { case TCP_V4_FLOW:
pf->fd_tcp4_filter_cnt--; break; case UDP_V4_FLOW:
pf->fd_udp4_filter_cnt--; break; case SCTP_V4_FLOW:
pf->fd_sctp4_filter_cnt--; break; case TCP_V6_FLOW:
pf->fd_tcp6_filter_cnt--; break; case UDP_V6_FLOW:
pf->fd_udp6_filter_cnt--; break; case SCTP_V6_FLOW:
pf->fd_udp6_filter_cnt--; break; case IP_USER_FLOW: switch (filter->ipl4_proto) { case IPPROTO_TCP:
pf->fd_tcp4_filter_cnt--; break; case IPPROTO_UDP:
pf->fd_udp4_filter_cnt--; break; case IPPROTO_SCTP:
pf->fd_sctp4_filter_cnt--; break; case IPPROTO_IP:
pf->fd_ip4_filter_cnt--; break;
} break; case IPV6_USER_FLOW: switch (filter->ipl4_proto) { case IPPROTO_TCP:
pf->fd_tcp6_filter_cnt--; break; case IPPROTO_UDP:
pf->fd_udp6_filter_cnt--; break; case IPPROTO_SCTP:
pf->fd_sctp6_filter_cnt--; break; case IPPROTO_IP:
pf->fd_ip6_filter_cnt--; break;
} break;
}
/* Remove the filter from the list and free memory */
hlist_del(&filter->fdir_node);
kfree(filter);
}
if (test_bit(__I40E_FD_FLUSH_REQUESTED, pf->state)) return;
/* Check if we have enough room to re-enable FDir SB capability. */
fcnt_prog = i40e_get_global_fd_count(pf);
fcnt_avail = pf->fdir_pf_filter_count; if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) ||
(pf->fd_add_err == 0) ||
(i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt))
i40e_reenable_fdir_sb(pf);
/* We should wait for even more space before re-enabling ATR. *Additionally,wecannotenableATRaslongaswestillhaveTCPSB *rulesactive.
*/ if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR)) &&
pf->fd_tcp4_filter_cnt == 0 && pf->fd_tcp6_filter_cnt == 0)
i40e_reenable_fdir_atr(pf);
/* if hw had a problem adding a filter, delete it */ if (pf->fd_inv > 0) {
hlist_for_each_entry_safe(filter, node,
&pf->fdir_filter_list, fdir_node) if (filter->fd_id == pf->fd_inv)
i40e_delete_invalid_filter(pf, filter);
}
}
#define I40E_MIN_FD_FLUSH_INTERVAL 10 #define I40E_MIN_FD_FLUSH_SB_ATR_UNSTABLE 30 /** *i40e_fdir_flush_and_replay-FunctiontoflushallFDfiltersandreplaySB *@pf:boardprivatestructure
**/ staticvoid i40e_fdir_flush_and_replay(struct i40e_pf *pf)
{ unsignedlong min_flush_time; int flush_wait_retry = 50; bool disable_atr = false; int fd_room; int reg;
if (!time_after(jiffies, pf->fd_flush_timestamp +
(I40E_MIN_FD_FLUSH_INTERVAL * HZ))) return;
/* If the flush is happening too quick and we have mostly SB rules we *shouldnotre-enableATRforsometime.
*/
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, 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;
set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state); /* 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(i40e_pf_get_main_vsi(pf)); if (!disable_atr && !pf->fd_tcp4_filter_cnt)
clear_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
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");
}
}
case I40E_VSI_SRIOV: case I40E_VSI_VMDQ2: case I40E_VSI_CTRL: case I40E_VSI_IWARP: case I40E_VSI_MIRROR: default: /* there is no notification for other VSIs */ break;
}
}
/* set this to force the get_link_status call to refresh state */
pf->hw.phy.get_link_info = true;
old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP);
status = i40e_get_link_status(&pf->hw, &new_link);
/* On success, disable temp link polling */ if (status == 0) {
clear_bit(__I40E_TEMP_LINK_POLLING, pf->state);
} else { /* Enable link polling temporarily until i40e_get_link_status *returns0
*/
set_bit(__I40E_TEMP_LINK_POLLING, pf->state);
dev_dbg(&pf->pdev->dev, "couldn't get link state, status: %d\n",
status); return;
}
if (!new_link && old_link)
pf->link_down_events++;
i40e_print_link_message(vsi, new_link);
/* Notify the base of the switch tree connected to *thelink.FloatingVEBsarenotnotified.
*/ if (veb)
i40e_veb_link_event(veb, new_link); else
i40e_vsi_link_event(vsi, new_link);
if (pf->vf)
i40e_vc_notify_link_state(pf);
if (test_bit(I40E_FLAG_PTP_ENA, pf->flags))
i40e_ptp_set_increment(pf); #ifdef CONFIG_I40E_DCB if (new_link == old_link) return; /* Not SW DCB so firmware will take care of default settings */ if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) return;
/* We cover here only link down, as after link up in case of SW DCB *SWLLDPagentwilltakecareofsettingitup
*/ if (!new_link) {
dev_dbg(&pf->pdev->dev, "Reconfig DCB to single TC as result of Link Down\n");
memset(&pf->tmp_cfg, 0, sizeof(pf->tmp_cfg));
err = i40e_dcb_sw_default_config(pf); if (err) {
clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
} else {
pf->dcbx_cap = DCB_CAP_DCBX_HOST |
DCB_CAP_DCBX_VER_IEEE;
set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
}
} #endif/* CONFIG_I40E_DCB */
}
/* if interface is down do nothing */ if (test_bit(__I40E_DOWN, pf->state) ||
test_bit(__I40E_CONFIG_BUSY, pf->state)) return;
/* make sure we don't do these things too often */ if (time_before(jiffies, (pf->service_timer_previous +
pf->service_timer_period))) return;
pf->service_timer_previous = jiffies;
if (test_bit(I40E_FLAG_LINK_POLLING_ENA, pf->flags) ||
test_bit(__I40E_TEMP_LINK_POLLING, pf->state))
i40e_link_event(pf);
/* Update the stats for active netdevs so the network stack *canlookatupdatednumberswheneveritcaresto
*/
i40e_pf_for_each_vsi(pf, i, vsi) if (vsi->netdev)
i40e_update_stats(vsi);
if (test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags)) { /* Update the stats for the active switching components */
i40e_pf_for_each_veb(pf, i, veb)
i40e_update_veb_stats(veb);
}
if (test_bit(__I40E_REINIT_REQUESTED, pf->state)) {
reset_flags |= BIT(__I40E_REINIT_REQUESTED);
clear_bit(__I40E_REINIT_REQUESTED, pf->state);
} if (test_bit(__I40E_PF_RESET_REQUESTED, pf->state)) {
reset_flags |= BIT(__I40E_PF_RESET_REQUESTED);
clear_bit(__I40E_PF_RESET_REQUESTED, pf->state);
} if (test_bit(__I40E_CORE_RESET_REQUESTED, pf->state)) {
reset_flags |= BIT(__I40E_CORE_RESET_REQUESTED);
clear_bit(__I40E_CORE_RESET_REQUESTED, pf->state);
} if (test_bit(__I40E_GLOBAL_RESET_REQUESTED, pf->state)) {
reset_flags |= BIT(__I40E_GLOBAL_RESET_REQUESTED);
clear_bit(__I40E_GLOBAL_RESET_REQUESTED, pf->state);
} if (test_bit(__I40E_DOWN_REQUESTED, pf->state)) {
reset_flags |= BIT(__I40E_DOWN_REQUESTED);
clear_bit(__I40E_DOWN_REQUESTED, pf->state);
}
/* If there's a recovery already waiting, it takes *precedencebeforestartinganewresetsequence.
*/ if (test_bit(__I40E_RESET_INTR_RECEIVED, pf->state)) {
i40e_prep_for_reset(pf);
i40e_reset(pf);
i40e_rebuild(pf, false, false);
}
/* If we're already down or resetting, just bail */ if (reset_flags &&
!test_bit(__I40E_DOWN, pf->state) &&
!test_bit(__I40E_CONFIG_BUSY, pf->state)) {
i40e_do_reset(pf, reset_flags, false);
}
}
/* Do a new status request to re-enable LSE reporting *andloadnewstatusinformationintothehwstruct *Thiscompletelyignoresanystateinformation *intheARQeventinfo,insteadchoosingtoalways *issuetheAQupdatelinkstatuscommand.
*/
i40e_link_event(pf);
/* Check if module meets thermal requirements */ if (status->phy_type == I40E_PHY_TYPE_NOT_SUPPORTED_HIGH_TEMP) {
dev_err(&pf->pdev->dev, "Rx/Tx is disabled on this device because the module does not meet thermal requirements.\n");
dev_err(&pf->pdev->dev, "Refer to the Intel(R) Ethernet Adapters and Devices User Guide for a list of supported modules.\n");
} else { /* check for unqualified module, if link is down, suppress *themessageiflinkwasforcedtobedown.
*/ if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
(!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
(!(status->link_info & I40E_AQ_LINK_UP)) &&
(!test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags))) {
dev_err(&pf->pdev->dev, "Rx/Tx is disabled on this device because an unsupported SFP module type was detected.\n");
dev_err(&pf->pdev->dev, "Refer to the Intel(R) Ethernet Adapters and Devices User Guide for a list of supported modules.\n");
}
}
}
/* As we do not maintain PV (port virtualizer) switch element then *therecanbeonlyonenon-floatingVEBthathaveuplinktoMACSEID *anditscontrolVSIisthemainone.
*/ if (WARN_ON(veb->uplink_seid && veb->uplink_seid != pf->mac_seid)) {
dev_err(&pf->pdev->dev, "Invalid uplink SEID for VEB %d\n", veb->idx); return -ENOENT;
}
if (veb->uplink_seid == pf->mac_seid) { /* Check that the LAN VSI has VEB owning flag set */
ctl_vsi = i40e_pf_get_main_vsi(pf);
if (WARN_ON(ctl_vsi->veb_idx != veb->idx ||
!(ctl_vsi->flags & I40E_VSI_FLAG_VEB_OWNER))) {
dev_err(&pf->pdev->dev, "Invalid control VSI for VEB %d\n", veb->idx); return -ENOENT;
}
/* Add the control VSI to switch */
ret = i40e_add_vsi(ctl_vsi); if (ret) {
dev_err(&pf->pdev->dev, "Rebuild of owner VSI for VEB %d failed: %d\n",
veb->idx, ret); return ret;
}
i40e_vsi_reset_stats(ctl_vsi);
}
/* create the VEB in the switch and move the VSI onto the VEB */
ret = i40e_add_veb(veb, ctl_vsi); if (ret) return ret;
if (veb->uplink_seid) { if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags))
veb->bridge_mode = BRIDGE_MODE_VEB; else
veb->bridge_mode = BRIDGE_MODE_VEPA;
i40e_config_bridge_mode(veb);
}
/* create the remaining VSIs attached to this VEB */
i40e_pf_for_each_vsi(pf, v, vsi) { if (vsi == ctl_vsi) continue;
if (vsi->veb_idx == veb->idx) {
vsi->uplink_seid = veb->seid;
ret = i40e_add_vsi(vsi); if (ret) {
dev_info(&pf->pdev->dev, "rebuild of vsi_idx %d failed: %d\n",
v, ret); return ret;
}
i40e_vsi_reset_stats(vsi);
}
}
buf_len = 40 * sizeof(struct libie_aqc_list_caps_elem); do {
cap_buf = kzalloc(buf_len, GFP_KERNEL); if (!cap_buf) return -ENOMEM;
/* this loads the data into the hw struct for us */
err = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,
&data_size, list_type,
NULL); /* data loaded, buffer no longer needed */
kfree(cap_buf);
if (pf->hw.aq.asq_last_status == LIBIE_AQ_RC_ENOMEM) { /* retry with a larger buffer */
buf_len = data_size;
} elseif (pf->hw.aq.asq_last_status != LIBIE_AQ_RC_OK || err) {
dev_info(&pf->pdev->dev, "capability discovery failed, err %pe aq_err %s\n",
ERR_PTR(err),
libie_aq_str(pf->hw.aq.asq_last_status)); return -ENODEV;
}
} while (err);
/* Add cloud filters back if they exist */
hlist_for_each_entry_safe(cfilter, node, &pf->cloud_filter_list,
cloud_node) { if (cfilter->seid != seid) continue;
if (cfilter->dst_port)
ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter, true); else
ret = i40e_add_del_cloud_filter(vsi, cfilter, true);
clear_bit(__I40E_RESET_INTR_RECEIVED, pf->state); if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) return; if (i40e_check_asq_alive(&pf->hw))
i40e_vc_notify_reset(pf);
dev_dbg(&pf->pdev->dev, "Tearing down internal switch for reset\n");
/* quiesce the VSIs and their queues that are not already DOWN */
i40e_pf_quiesce_all_vsi(pf);
/* Check if pointer to OEM version block is valid. */
i40e_read_nvm_word(hw, I40E_SR_NVM_OEM_VERSION_PTR, &block_offset); if (block_offset == 0xffff) return;
/* Check if OEM version block has correct length. */
i40e_read_nvm_word(hw, block_offset + I40E_NVM_OEM_LENGTH_OFFSET,
&block_length); if (block_length < I40E_NVM_OEM_LENGTH) return;
/* Check if OEM version format is as expected. */
i40e_read_nvm_word(hw, block_offset + I40E_NVM_OEM_CAPABILITIES_OFFSET,
&capabilities); if ((capabilities & I40E_NVM_OEM_CAPABILITIES_MASK) != 0) return;
/* rebuild the basics for the AdminQ, HMC, and initial HW switch */
ret = i40e_init_adminq(&pf->hw); if (ret) {
dev_info(&pf->pdev->dev, "Rebuild AdminQ failed, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status)); goto clear_recovery;
}
i40e_get_oem_version(&pf->hw);
if (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state)) { /* The following delay is necessary for firmware update. */
mdelay(1000);
}
/* re-verify the eeprom if we just had an EMP reset */ if (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state))
i40e_verify_eeprom(pf);
/* if we are going out of or into recovery mode we have to act *accordinglywithregardtoresourcesinitialization *anddeinitialization
*/ if (test_bit(__I40E_RECOVERY_MODE, pf->state)) { if (i40e_get_capabilities(pf,
i40e_aqc_opc_list_func_capabilities)) goto end_unlock;
if (is_recovery_mode_reported) { /* we're staying in recovery mode so we'll reinitialize *miscvectorhere
*/ if (i40e_setup_misc_vector_for_recovery_mode(pf)) goto end_unlock;
} else { if (!lock_acquired)
rtnl_lock(); /* we're going out of recovery mode so we'll free *theIRQallocatedspecificallyforrecoverymode *andrestoretheinterruptscheme
*/
free_irq(pf->pdev->irq, pf);
i40e_clear_interrupt_scheme(pf); if (i40e_restore_interrupt_scheme(pf)) goto end_unlock;
}
/* tell the firmware that we're starting */
i40e_send_version(pf);
/* bail out in case recovery mode was detected, as there is *noneedforfurtherconfiguration.
*/ goto end_unlock;
}
i40e_clear_pxe_mode(hw);
ret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities); if (ret) goto end_core_reset;
ret = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
hw->func_caps.num_rx_qp, 0, 0); if (ret) {
dev_info(&pf->pdev->dev, "init_lan_hmc failed: %d\n", ret); goto end_core_reset;
}
ret = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); if (ret) {
dev_info(&pf->pdev->dev, "configure_lan_hmc failed: %d\n", ret); goto end_core_reset;
}
#ifdef CONFIG_I40E_DCB /* Enable FW to write a default DCB config on link-up *unlessI40E_FLAG_TC_MQPRIOwasenabledorDCB *isnotsupportedwithnewlinkspeed
*/ if (i40e_is_tc_mqprio_enabled(pf)) {
i40e_aq_set_dcb_parameters(hw, false, NULL);
} else { if (I40E_IS_X710TL_DEVICE(hw->device_id) &&
(hw->phy.link_info.link_speed &
(I40E_LINK_SPEED_2_5GB | I40E_LINK_SPEED_5GB))) {
i40e_aq_set_dcb_parameters(hw, false, NULL);
dev_warn(&pf->pdev->dev, "DCB is not supported for X710-T*L 2.5/5G speeds\n");
clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
} else {
i40e_aq_set_dcb_parameters(hw, true, NULL);
ret = i40e_init_pf_dcb(pf); if (ret) {
dev_info(&pf->pdev->dev, "DCB init failed %d, disabled\n",
ret);
clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags); /* Continue without DCB enabled */
}
}
}
#endif/* CONFIG_I40E_DCB */ if (!lock_acquired)
rtnl_lock();
ret = i40e_setup_pf_switch(pf, reinit, true); if (ret) goto end_unlock;
/* The driver only wants link up/down and module qualification *reportsfromfirmware.Notethenegativelogic.
*/
ret = i40e_aq_set_phy_int_mask(&pf->hw,
~(I40E_AQ_EVENT_LINK_UPDOWN |
I40E_AQ_EVENT_MEDIA_NA |
I40E_AQ_EVENT_MODULE_QUAL_FAIL), NULL); if (ret)
dev_info(&pf->pdev->dev, "set phy mask fail, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status));
/* Rebuild the VSIs and VEBs that existed before reset. *Theyarestillinourlocalswitchelementarrays,soonly *needtorebuildtheswitchmodelintheHW. * *IftherewereVEBsbutthereconstitutionfailed,we'lltry *torecoverminimalusebygettingthebasicPFVSIworking.
*/ if (vsi->uplink_seid != pf->mac_seid) {
dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n");
/* Rebuild VEBs */
i40e_pf_for_each_veb(pf, v, veb) {
ret = i40e_reconstitute_veb(veb); if (!ret) continue;
/* If Main VEB failed, we're in deep doodoo, *sogiveuprebuildingtheswitchandsetup *forminimalrebuildofPFVSI. *Iforphanfailed,we'llreporttheerror *buttrytokeepgoing.
*/ if (veb->uplink_seid == pf->mac_seid) {
dev_info(&pf->pdev->dev, "rebuild of switch failed: %d, will try to set up simple PF connection\n",
ret);
vsi->uplink_seid = pf->mac_seid; break;
} elseif (veb->uplink_seid == 0) {
dev_info(&pf->pdev->dev, "rebuild of orphan VEB failed: %d\n",
ret);
}
}
}
if (vsi->uplink_seid == pf->mac_seid) {
dev_dbg(&pf->pdev->dev, "attempting to rebuild PF VSI\n"); /* no VEB, so rebuild only the Main VSI */
ret = i40e_add_vsi(vsi); if (ret) {
dev_info(&pf->pdev->dev, "rebuild of Main VSI failed: %d\n", ret); goto end_unlock;
}
}
ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate); if (ret) goto end_unlock;
credits = max_tx_rate;
do_div(credits, I40E_BW_CREDIT_DIVISOR);
dev_dbg(&vsi->back->pdev->dev, "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
max_tx_rate,
credits,
vsi->seid);
}
ret = i40e_rebuild_cloud_filters(vsi, vsi->seid); if (ret) goto end_unlock;
/* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs *forthismainVSIiftheyexist
*/
ret = i40e_rebuild_channels(vsi); if (ret) goto end_unlock;
/* Reconfigure hardware for allowing smaller MSS in the case *ofTSO,sothatweavoidtheMDDbeingfiredandcausing *aresetinthecaseofsmallMSS+TSO.
*/ #define I40E_REG_MSS 0x000E64DC #define I40E_REG_MSS_MIN_MASK 0x3FF0000 #define I40E_64BYTE_MSS 0x400000
val = rd32(hw, I40E_REG_MSS); if ((val & I40E_REG_MSS_MIN_MASK) > I40E_64BYTE_MSS) {
val &= ~I40E_REG_MSS_MIN_MASK;
val |= I40E_64BYTE_MSS;
wr32(hw, I40E_REG_MSS, val);
}
if (test_bit(I40E_HW_CAP_RESTART_AUTONEG, pf->hw.caps)) {
msleep(75);
ret = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (ret)
dev_info(&pf->pdev->dev, "link restart failed, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status));
} /* reinit the misc interrupt */ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
ret = i40e_setup_misc_vector(pf); if (ret) goto end_unlock;
}
/* Add a filter to drop all Flow control frames from any VSI from being *transmitted.BydoingsowestopamaliciousVFfromsendingout *PAUSEorPFCframesandpotentiallycontrollingtrafficforother *PF/VFVSIs. *TheFWcanstillsendFlowcontrolframesifenabled.
*/
i40e_add_filter_to_drop_tx_flow_control_frames(&pf->hw,
pf->main_vsi_seid);
/* restart the VSIs that were rebuilt and running before the reset */
i40e_pf_unquiesce_all_vsi(pf);
/* Release the RTNL lock before we start resetting VFs */ if (!lock_acquired)
rtnl_unlock();
/* Restore promiscuous settings */
ret = i40e_set_promiscuous(pf, pf->cur_promisc); if (ret)
dev_warn(&pf->pdev->dev, "Failed to restore promiscuous setting: %s, err %pe aq_err %s\n",
pf->cur_promisc ? "on" : "off",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status));
i40e_reset_all_vfs(pf, true);
/* tell the firmware that we're starting */
i40e_send_version(pf);
/* We've already released the lock, so don't do it again */ goto end_core_reset;
if (test_bit(__I40E_IN_REMOVE, pf->state)) return; /* Now we wait for GRST to settle out. *Wedon'thavetodeletetheVEBsorVSIsfromthehwswitch *becausetheresetwillmakethemdisappear.
*/
ret = i40e_reset(pf); if (!ret)
i40e_rebuild(pf, reinit, lock_acquired); else
dev_err(&pf->pdev->dev, "%s: i40e_reset() FAILED", __func__);
}
/* check that there are pending MDD events to print */ if (!test_and_clear_bit(__I40E_MDD_VF_PRINT_PENDING, pf->state)) return;
if (!__ratelimit(&pf->mdd_message_rate_limit)) return;
for (i = 0; i < pf->num_alloc_vfs; i++) { struct i40e_vf *vf = &pf->vf[i]; bool is_printed = false;
/* only print Rx MDD event message if there are new events */ if (vf->mdd_rx_events.count != vf->mdd_rx_events.last_printed) {
vf->mdd_rx_events.last_printed = vf->mdd_rx_events.count;
i40e_print_vf_mdd_event(pf, vf, false);
is_printed = true;
}
/* only print Tx MDD event message if there are new events */ if (vf->mdd_tx_events.count != vf->mdd_tx_events.last_printed) {
vf->mdd_tx_events.last_printed = vf->mdd_tx_events.count;
i40e_print_vf_mdd_event(pf, vf, true);
is_printed = true;
}
if (is_printed && !test_bit(I40E_FLAG_MDD_AUTO_RESET_VF, pf->flags))
dev_info(&pf->pdev->dev, "Use PF Control I/F to re-enable the VF #%d\n",
i);
}
}
if (!test_and_clear_bit(__I40E_MDD_EVENT_PENDING, pf->state)) { /* Since the VF MDD event logging is rate limited, check if *therearependingMDDevents.
*/
i40e_print_vfs_mdd_events(pf); return;
}
/* find what triggered the MDD event */
reg = rd32(hw, I40E_GL_MDET_TX); if (reg & I40E_GL_MDET_TX_VALID_MASK) {
u8 pf_num = FIELD_GET(I40E_GL_MDET_TX_PF_NUM_MASK, reg);
u16 vf_num = FIELD_GET(I40E_GL_MDET_TX_VF_NUM_MASK, reg);
u8 event = FIELD_GET(I40E_GL_MDET_TX_EVENT_MASK, reg);
u16 queue = FIELD_GET(I40E_GL_MDET_TX_QUEUE_MASK, reg) -
pf->hw.func_caps.base_queue; if (netif_msg_tx_err(pf))
dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on TX queue %d PF number 0x%02x VF number 0x%02x\n",
event, queue, pf_num, vf_num);
wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
mdd_detected = true;
}
reg = rd32(hw, I40E_GL_MDET_RX); if (reg & I40E_GL_MDET_RX_VALID_MASK) {
u8 func = FIELD_GET(I40E_GL_MDET_RX_FUNCTION_MASK, reg);
u8 event = FIELD_GET(I40E_GL_MDET_RX_EVENT_MASK, reg);
u16 queue = FIELD_GET(I40E_GL_MDET_RX_QUEUE_MASK, reg) -
pf->hw.func_caps.base_queue; if (netif_msg_rx_err(pf))
dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
event, queue, func);
wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
mdd_detected = true;
}
if (mdd_detected) {
reg = rd32(hw, I40E_PF_MDET_TX); if (reg & I40E_PF_MDET_TX_VALID_MASK) {
wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
dev_dbg(&pf->pdev->dev, "TX driver issue detected on PF\n");
}
reg = rd32(hw, I40E_PF_MDET_RX); if (reg & I40E_PF_MDET_RX_VALID_MASK) {
wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
dev_dbg(&pf->pdev->dev, "RX driver issue detected on PF\n");
}
}
/* see if one of the VFs needs its hand slapped */ for (i = 0; i < pf->num_alloc_vfs && mdd_detected; i++) { bool is_mdd_on_tx = false; bool is_mdd_on_rx = false;
if ((is_mdd_on_tx || is_mdd_on_rx) &&
test_bit(I40E_FLAG_MDD_AUTO_RESET_VF, pf->flags)) { /* VF MDD event counters will be cleared by *reset,soprinttheeventpriortoreset.
*/ if (is_mdd_on_rx)
i40e_print_vf_mdd_event(pf, vf, false); if (is_mdd_on_tx)
i40e_print_vf_mdd_event(pf, vf, true);
/* don't bother with service tasks if a reset is in progress */ if (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||
test_bit(__I40E_SUSPENDED, pf->state)) return;
if (test_and_set_bit(__I40E_SERVICE_SCHED, pf->state)) return;
if (!test_bit(__I40E_RECOVERY_MODE, pf->state)) {
i40e_detect_recover_hung(pf);
i40e_sync_filters_subtask(pf);
i40e_reset_subtask(pf);
i40e_handle_mdd_event(pf);
i40e_vc_process_vflr_event(pf);
i40e_watchdog_subtask(pf);
i40e_fdir_reinit_subtask(pf); if (test_and_clear_bit(__I40E_CLIENT_RESET, pf->state)) { /* Client subtask will reopen next time through. */
i40e_notify_client_of_netdev_close(pf, true);
} else {
i40e_client_subtask(pf); if (test_and_clear_bit(__I40E_CLIENT_L2_CHANGE,
pf->state))
i40e_notify_client_of_l2_param_changes(pf);
}
i40e_sync_filters_subtask(pf);
} else {
i40e_reset_subtask(pf);
}
i40e_clean_adminq_subtask(pf);
/* flush memory to make sure state is correct before next watchdog */
smp_mb__before_atomic();
clear_bit(__I40E_SERVICE_SCHED, pf->state);
/* If the tasks have taken longer than one timer cycle or there *ismoreworktobedone,rescheduletheservicetasknow *ratherthanwaitforthetimertotickagain.
*/ if (time_after(jiffies, (start_time + pf->service_timer_period)) ||
test_bit(__I40E_ADMINQ_EVENT_PENDING, pf->state) ||
test_bit(__I40E_MDD_EVENT_PENDING, pf->state) ||
test_bit(__I40E_VFLR_EVENT_PENDING, pf->state))
i40e_service_event_schedule(pf);
}
case I40E_VSI_VMDQ2:
vsi->alloc_queue_pairs = pf->num_vmdq_qps; if (!vsi->num_tx_desc)
vsi->num_tx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
I40E_REQ_DESCRIPTOR_MULTIPLE); if (!vsi->num_rx_desc)
vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
I40E_REQ_DESCRIPTOR_MULTIPLE);
vsi->num_q_vectors = pf->num_vmdq_msix; break;
case I40E_VSI_SRIOV:
vsi->alloc_queue_pairs = pf->num_vf_qps; if (!vsi->num_tx_desc)
vsi->num_tx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
I40E_REQ_DESCRIPTOR_MULTIPLE); if (!vsi->num_rx_desc)
vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
I40E_REQ_DESCRIPTOR_MULTIPLE); break;
default:
WARN_ON(1); return -ENODATA;
}
if (is_kdump_kernel()) {
vsi->num_tx_desc = I40E_MIN_NUM_DESCRIPTORS;
vsi->num_rx_desc = I40E_MIN_NUM_DESCRIPTORS;
}
return0;
}
/** *i40e_vsi_alloc_arrays-Allocatequeueandvectorpointerarraysforthevsi *@vsi:VSIpointer *@alloc_qvectors:abooltospecifyifq_vectorsneedtobeallocated. * *Onerror:returnserrorcode(negative) *Onsuccess:returns0
**/ staticint i40e_vsi_alloc_arrays(struct i40e_vsi *vsi, bool alloc_qvectors)
{ struct i40e_ring **next_rings; int size; int ret = 0;
/* allocate memory for both Tx, XDP Tx and Rx ring pointers */
size = sizeof(struct i40e_ring *) * vsi->alloc_queue_pairs *
(i40e_enabled_xdp_vsi(vsi) ? 3 : 2);
vsi->tx_rings = kzalloc(size, GFP_KERNEL); if (!vsi->tx_rings) return -ENOMEM;
next_rings = vsi->tx_rings + vsi->alloc_queue_pairs; if (i40e_enabled_xdp_vsi(vsi)) {
vsi->xdp_rings = next_rings;
next_rings += vsi->alloc_queue_pairs;
}
vsi->rx_rings = next_rings;
if (alloc_qvectors) { /* allocate memory for q_vector pointers */
size = sizeof(struct i40e_q_vector *) * vsi->num_q_vectors;
vsi->q_vectors = kzalloc(size, GFP_KERNEL); if (!vsi->q_vectors) {
ret = -ENOMEM; goto err_vectors;
}
} return ret;
err_vectors:
kfree(vsi->tx_rings); return ret;
}
/** *i40e_vsi_mem_alloc-AllocatesthenextavailablestructvsiinthePF *@pf:boardprivatestructure *@type:typeofVSI * *Onerror:returnserrorcode(negative) *Onsuccess:returnsvsiindexinPF(positive)
**/ staticint i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)
{ int ret = -ENODEV; struct i40e_vsi *vsi; int vsi_idx; int i;
/* Need to protect the allocation of the VSIs at the PF level */
mutex_lock(&pf->switch_mutex);
/* VSI list may be fragmented if VSI creation/destruction has *beenhappening.Wecanaffordtodoaquickscantolook *foranyfreeVSIsinthelist. * *findnextemptyvsislot,loopingbackaroundifnecessary
*/
i = pf->next_vsi; while (i < pf->num_alloc_vsi && pf->vsi[i])
i++; if (i >= pf->num_alloc_vsi) {
i = 0; while (i < pf->next_vsi && pf->vsi[i])
i++;
}
if (i < pf->num_alloc_vsi && !pf->vsi[i]) {
vsi_idx = i; /* Found one! */
} else {
ret = -ENODEV; goto unlock_pf; /* out of VSI slots! */
}
pf->next_vsi = ++i;
mutex_lock(&pf->switch_mutex); if (!pf->vsi[vsi->idx]) {
dev_err(&pf->pdev->dev, "pf->vsi[%d] is NULL, just free vsi[%d](type %d)\n",
vsi->idx, vsi->idx, vsi->type); goto unlock_vsi;
}
if (pf->vsi[vsi->idx] != vsi) {
dev_err(&pf->pdev->dev, "pf->vsi[%d](type %d) != vsi[%d](type %d): no free!\n",
pf->vsi[vsi->idx]->idx,
pf->vsi[vsi->idx]->type,
vsi->idx, vsi->type); goto unlock_vsi;
}
/* updates the PF for this cleared vsi */
i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx);
i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx);
/* Set basic values in the rings to be used later during open() */ for (i = 0; i < vsi->alloc_queue_pairs; i++) { /* allocate space for both Tx and Rx in one shot */
ring = kcalloc(qpv, sizeof(struct i40e_ring), GFP_KERNEL); if (!ring) goto err_out;
/* any vectors left over go for VMDq support */ if (test_bit(I40E_FLAG_VMDQ_ENA, pf->flags)) { if (!vectors_left) {
pf->num_vmdq_msix = 0;
pf->num_vmdq_qps = 0;
} else { int vmdq_vecs_wanted =
pf->num_vmdq_vsis * pf->num_vmdq_qps; int vmdq_vecs =
min_t(int, vectors_left, vmdq_vecs_wanted);
/* if we're short on vectors for what's desired, we limit *thequeuespervmdq.Ifthisisstillmorethanare *available,theuserwillneedtochangethenumberof *queues/vectorsusedbythePFlaterwiththeethtool *channelscommand
*/ if (vectors_left < vmdq_vecs_wanted) {
pf->num_vmdq_qps = 1;
vmdq_vecs_wanted = pf->num_vmdq_vsis;
vmdq_vecs = min_t(int,
vectors_left,
vmdq_vecs_wanted);
}
pf->num_vmdq_msix = pf->num_vmdq_qps;
/* On systems with a large number of SMP cores, we previously limited *thenumberofvectorsfornum_lan_msixtobeatmost50%ofthe *availablevectors,toallowforotherfeatures.Now,weaddback *theremainingvectors.However,weensurethatthetotal *num_lan_msixwillnotexceednum_online_cpus().Todothis,we *calculatethenumberofvectorswecanaddwithoutgoingoverthe *capofCPUs.ForsystemswithasmallnumberofCPUsthiswillbe *zero.
*/
extra_vectors = min_t(int, cpus - pf->num_lan_msix, vectors_left);
pf->num_lan_msix += extra_vectors;
vectors_left -= extra_vectors;
WARN(vectors_left < 0, "Calculation of remaining vectors underflowed. This is an accounting bug when determining total MSI-X vectors.\n");
} elseif (v_actual != v_budget) { /* If we have limited resources, we will start with no vectors *forthespecialfeaturesandthenallocatevectorstosome *ofthesefeaturesbasedonthepolicyandattheenddisable *thefeaturesthatdidnotgetanyvectors.
*/ int vec;
dev_info(&pf->pdev->dev, "MSI-X vector limit reached with %d, wanted %d, attempting to redistribute vectors\n",
v_actual, v_budget); /* reserve the misc vector */
vec = v_actual - 1;
/* Scale vector usage down */
pf->num_vmdq_msix = 1; /* force VMDqs to only one vector */
pf->num_vmdq_vsis = 1;
pf->num_vmdq_qps = 1;
/* if not MSIX, give the one vector only to the LAN VSI */ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
num_q_vectors = vsi->num_q_vectors; elseif (vsi->type == I40E_VSI_MAIN)
num_q_vectors = 1; else return -EINVAL;
for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
err = i40e_vsi_alloc_q_vector(vsi, v_idx); if (err) goto err_out;
}
return0;
err_out: while (v_idx--)
i40e_free_q_vector(vsi, v_idx);
/* rework the queue expectations without MSIX */
i40e_determine_queue_usage(pf);
}
}
if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags) &&
test_bit(I40E_FLAG_MSI_ENA, pf->flags)) {
dev_info(&pf->pdev->dev, "MSI-X not available, trying MSI\n");
vectors = pci_enable_msi(pf->pdev); if (vectors < 0) {
dev_info(&pf->pdev->dev, "MSI init failed - %d\n",
vectors);
clear_bit(I40E_FLAG_MSI_ENA, pf->flags);
}
vectors = 1; /* one MSI or Legacy vector */
}
if (!test_bit(I40E_FLAG_MSI_ENA, pf->flags) &&
!test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
dev_info(&pf->pdev->dev, "MSI-X and MSI not available, falling back to Legacy IRQ\n");
/* set up vector assignment tracking */
size = sizeof(struct i40e_lump_tracking) + (sizeof(u16) * vectors);
pf->irq_pile = kzalloc(size, GFP_KERNEL); if (!pf->irq_pile) return -ENOMEM;
pf->irq_pile->num_entries = vectors;
/* track first vector for misc interrupts, ignore return */
(void)i40e_get_lump(pf, pf->irq_pile, 1, I40E_PILE_VALID_BIT - 1);
/* We cleared the MSI and MSI-X flags when disabling the old interrupt *scheme.Weneedtore-enabledthemhereinordertoattemptto *re-acquiretheMSIorMSI-Xvectors
*/
set_bit(I40E_FLAG_MSI_ENA, pf->flags);
set_bit(I40E_FLAG_MSIX_ENA, pf->flags);
err = i40e_init_interrupt_scheme(pf); if (err) return err;
/* Now that we've re-acquired IRQs, we need to remap the vectors and *ringstogetheragain.
*/
i40e_pf_for_each_vsi(pf, i, vsi) {
err = i40e_vsi_alloc_q_vectors(vsi); if (err) goto err_unwind;
i40e_vsi_map_rings_to_vectors(vsi);
}
err = i40e_setup_misc_vector(pf); if (err) goto err_unwind;
if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags))
i40e_client_update_msix_info(pf);
return0;
err_unwind: while (i--) { if (pf->vsi[i])
i40e_vsi_free_q_vectors(pf->vsi[i]);
}
/* Only request the IRQ once, the first time through. */ if (!test_and_set_bit(__I40E_MISC_IRQ_REQUESTED, pf->state)) {
err = request_irq(pf->msix_entries[0].vector,
i40e_intr, 0, pf->int_name, pf); if (err) {
clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
dev_info(&pf->pdev->dev, "request_irq for %s failed: %d\n",
pf->int_name, err); return -EFAULT;
}
}
i40e_enable_misc_int_causes(pf);
/* associate no queues to the misc vector */
wr32(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_END_OF_LIST);
wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), I40E_ITR_8K >> 1);
/* Determine the RSS table size based on the hardware capabilities */
reg_val = i40e_read_rx_ctl(hw, I40E_PFQF_CTL_0);
reg_val = (pf->rss_table_size == 512) ?
(reg_val | I40E_PFQF_CTL_0_HASHLUTSIZE_512) :
(reg_val & ~I40E_PFQF_CTL_0_HASHLUTSIZE_512);
i40e_write_rx_ctl(hw, I40E_PFQF_CTL_0, reg_val);
/* Determine the RSS size of the VSI */ if (!vsi->rss_size) {
u16 qcount; /* If the firmware does something weird during VSI init, we *couldendupwithzeroTCs.Checkforthattoavoid *divide-by-zero.Itprobablywon'tpasstraffic,butitalso *won'tpanic.
*/
qcount = vsi->num_queue_pairs /
(vsi->tc_config.numtc ? vsi->tc_config.numtc : 1);
vsi->rss_size = min_t(int, pf->alloc_rss_size, qcount);
} if (!vsi->rss_size) return -EINVAL;
lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); if (!lut) return -ENOMEM;
/* Use user configured lut if there is one, otherwise use default */ if (vsi->rss_lut_user)
memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); else
i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
/* Use user configured hash key if there is one, otherwise *usedefault.
*/ if (vsi->rss_hkey_user)
memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE); else
netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
ret = i40e_config_rss(vsi, seed, lut, vsi->rss_table_size);
kfree(lut);
return ret;
}
/** *i40e_reconfig_rss_queues-changenumberofqueuesforrssandrebuild *@pf:boardprivatestructure *@queue_count:therequestedqueuecountforrss. * *returns0ifrssisnotenabled,ifenabledreturnsthefinalrssqueue *countwhichmaybedifferentfromtherequestedqueuecount. *Note:expectstobecalledwhileunderrtnl_lock()
**/ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)
{ struct i40e_vsi *vsi = i40e_pf_get_main_vsi(pf); int new_rss_size;
if (!test_bit(I40E_FLAG_RSS_ENA, pf->flags)) return0;
if (queue_count != vsi->num_queue_pairs) {
u16 qcount;
vsi->req_queue_pairs = queue_count;
i40e_prep_for_reset(pf); if (test_bit(__I40E_IN_REMOVE, pf->state)) return pf->alloc_rss_size;
pf->alloc_rss_size = new_rss_size;
i40e_reset_and_rebuild(pf, true, true);
/* Discard the user configured hash keys and lut, if less *queuesareenabled.
*/ if (queue_count < vsi->rss_size) {
i40e_clear_rss_config_user(vsi);
dev_dbg(&pf->pdev->dev, "discard user configured hash keys and lut\n");
}
/* Reset vsi->rss_size, as number of enabled queues changed */
qcount = vsi->num_queue_pairs / vsi->tc_config.numtc;
vsi->rss_size = min_t(int, pf->alloc_rss_size, qcount);
/** *i40e_get_partition_bw_setting-RetrieveBWsettingsforthisPFpartition *@pf:boardprivatestructure
**/ int i40e_get_partition_bw_setting(struct i40e_pf *pf)
{ bool min_valid, max_valid;
u32 max_bw, min_bw; int status;
status = i40e_read_bw_from_alt_ram(&pf->hw, &max_bw, &min_bw,
&min_valid, &max_valid);
if (!status) { if (min_valid)
pf->min_bw = min_bw; if (max_valid)
pf->max_bw = max_bw;
}
return status;
}
/** *i40e_set_partition_bw_setting-SetBWsettingsforthisPFpartition *@pf:boardprivatestructure
**/ int i40e_set_partition_bw_setting(struct i40e_pf *pf)
{ struct i40e_aqc_configure_partition_bw_data bw_data; int status;
memset(&bw_data, 0, sizeof(bw_data));
/* Set the valid bit for this PF */
bw_data.pf_valid_bits = cpu_to_le16(BIT(pf->hw.pf_id));
bw_data.max_bw[pf->hw.pf_id] = pf->max_bw & I40E_ALT_BW_VALUE_MASK;
bw_data.min_bw[pf->hw.pf_id] = pf->min_bw & I40E_ALT_BW_VALUE_MASK;
/* Set the new bandwidths */
status = i40e_aq_configure_partition_bw(&pf->hw, &bw_data, NULL);
/* Depending on PF configurations, it is possible that the RSS *maximummightenduplargerthantheavailablequeues
*/
pf->rss_size_max = BIT(pf->hw.func_caps.rss_table_entry_width);
pf->alloc_rss_size = 1;
pf->rss_table_size = pf->hw.func_caps.rss_table_size;
pf->rss_size_max = min_t(int, pf->rss_size_max,
pf->hw.func_caps.num_tx_qp);
/* find the next higher power-of-2 of num cpus */
pow = roundup_pow_of_two(num_online_cpus());
pf->rss_size_max = min_t(int, pf->rss_size_max, pow);
if (pf->hw.func_caps.iwarp && num_online_cpus() != 1) {
set_bit(I40E_FLAG_IWARP_ENA, pf->flags); /* IWARP needs one extra vector for CQP just like MISC.*/
pf->num_iwarp_msix = (int)num_online_cpus() + 1;
} /* Stopping FW LLDP engine is supported on XL710 and X722 *startingfromFWversionsdeterminedini40e_init_adminq. *StoppingtheFWLLDPengineisnotsupportedonXL710 *ifNPARisfunctioningsounsetthishwflaginthiscase.
*/ if (pf->hw.mac.type == I40E_MAC_XL710 &&
pf->hw.func_caps.npar_enable)
clear_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, pf->hw.caps);
if (pf->hw.mac.type != I40E_MAC_X722 &&
i40e_is_total_port_shutdown_enabled(pf)) { /* Link down on close must be on when total port shutdown *isenabledforagivenport
*/
set_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags);
set_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags);
dev_info(&pf->pdev->dev, "total-port-shutdown was enabled, link-down-on-close is forced on\n");
}
mutex_init(&pf->switch_mutex);
/* Check if Flow Director n-tuple support was enabled or disabled. If *thestatechanged,weneedtoreset.
*/ if (features & NETIF_F_NTUPLE) { /* Enable filters and mark for reset */ if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags))
need_reset = true; /* enable FD_SB only if there is MSI-X vector and no cloud *filtersexist
*/ if (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {
set_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
clear_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
}
} else { /* turn off filters, mark for reset and clear SW filter list */ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) {
need_reset = true;
i40e_fdir_filter_exit(pf);
}
clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
clear_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state);
set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
/* reset fd counters */
pf->fd_add_err = 0;
pf->fd_atr_cnt = 0; /* if ATR was auto disabled it can be re-enabled. */ if (test_and_clear_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) &&
(I40E_DEBUG_FD & pf->hw.debug_mask))
dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
} return need_reset;
}
ret = i40e_aq_set_mac_loopback(&vsi->back->hw, ena, NULL); if (ret)
netdev_err(vsi->netdev, "Failed to toggle loopback state\n"); if (if_running)
i40e_up(vsi);
if (!test_bit(I40E_FLAG_SRIOV_ENA, pf->flags)) return -EOPNOTSUPP;
if (vid) {
pr_info("%s: vlans aren't supported yet for dev_uc|mc_add()\n", dev->name); return -EINVAL;
}
/* Hardware does not support aging addresses so if a *ndm_stateisgivenonlyallowpermanentaddresses
*/ if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
netdev_info(dev, "FDB only supports static addresses\n"); return -EINVAL;
}
/* No point in doing any of this if neither checksum nor GSO are *beingrequestedforthisframe.Wecanruleoutbothbyjust *checkingforCHECKSUM_PARTIAL
*/ if (skb->ip_summed != CHECKSUM_PARTIAL) return features;
/* We cannot support GSO if the MSS is going to be less than *64bytes.IfitisthenweneedtodropsupportforGSO.
*/ if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64))
features &= ~NETIF_F_GSO_MASK;
/* MACLEN can support at most 63 words */
len = skb_network_offset(skb); if (len & ~(63 * 2)) goto out_err;
/* IPLEN and EIPLEN can support at most 127 dwords */
len = skb_network_header_len(skb); if (len & ~(127 * 4)) goto out_err;
if (skb->encapsulation) { /* L4TUNLEN can support 127 words */
len = skb_inner_network_header(skb) - skb_transport_header(skb); if (len & ~(127 * 2)) goto out_err;
/* IPLEN can support at most 127 dwords */
len = skb_inner_transport_header(skb) -
skb_inner_network_header(skb); if (len & ~(127 * 4)) goto out_err;
}
/* No need to validate L4LEN as TCP is the only protocol with a *flexiblevalueandwesupportallpossiblevaluessupported *byTCP,whichisatmost15dwords
*/
return features;
out_err: return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
}
/* VSI shall be deleted in a moment, block loading new programs */ if (prog && test_bit(__I40E_IN_REMOVE, pf->state)) return -EINVAL;
/* Don't allow frames that span over multiple buffers */ if (vsi->netdev->mtu > frame_size - I40E_PACKET_HDR_PAD) {
NL_SET_ERR_MSG_MOD(extack, "MTU too large for linear frames and XDP prog does not support frags"); return -EINVAL;
}
/* When turning XDP on->off/off->on we reset and rebuild the rings. */
need_reset = (i40e_enabled_xdp_vsi(vsi) != !!prog); if (need_reset)
i40e_prep_for_reset(pf);
old_prog = xchg(&vsi->xdp_prog, prog);
if (need_reset) { if (!prog) {
xdp_features_clear_redirect_target(vsi->netdev); /* Wait until ndo_xsk_wakeup completes. */
synchronize_rcu();
}
i40e_reset_and_rebuild(pf, true, true);
}
if (!i40e_enabled_xdp_vsi(vsi) && prog) { if (i40e_realloc_rx_bi_zc(vsi, true)) return -ENOMEM;
} elseif (i40e_enabled_xdp_vsi(vsi) && !prog) { if (i40e_realloc_rx_bi_zc(vsi, false)) return -ENOMEM;
}
for (i = 0; i < vsi->num_queue_pairs; i++)
WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog);
if (old_prog)
bpf_prog_put(old_prog);
/* Kick start the NAPI context if there is an AF_XDP socket open *onthatqueueid.Thissothatreceivingwillstart.
*/ if (need_reset && prog) { for (i = 0; i < vsi->num_queue_pairs; i++) if (vsi->xdp_rings[i]->xsk_pool)
(void)i40e_xsk_wakeup(vsi->netdev, i,
XDP_WAKEUP_RX);
xdp_features_set_redirect_target(vsi->netdev, true);
}
/* All rings in a qp belong to the same qvector. */ if (q_vector->rx.ring || q_vector->tx.ring) { if (enable)
napi_enable(&q_vector->napi); else
napi_disable(&q_vector->napi);
}
}
/** *i40e_queue_pair_toggle_rings-Enables/disablesallringsforaqueuepair *@vsi:vsi *@queue_pair:queuepair *@enable:trueforenable,falsefordisable * *Returns0onsuccess,<0onfailure.
**/ staticint i40e_queue_pair_toggle_rings(struct i40e_vsi *vsi, int queue_pair, bool enable)
{ struct i40e_pf *pf = vsi->back; int pf_q, ret = 0;
/* All rings in a qp belong to the same qvector. */ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
i40e_irq_dynamic_enable(vsi, rxr->q_vector->v_idx); else
i40e_irq_dynamic_enable_icr0(pf);
memset(&ctxt, 0, sizeof(ctxt)); switch (vsi->type) { case I40E_VSI_MAIN: /* The PF's main VSI is already setup as part of the *deviceinitialization,sowe'llnotbotherwith *theadd_vsicall,butwewillretrievethecurrent *VSIcontext.
*/
ctxt.seid = pf->main_vsi_seid;
ctxt.pf_num = pf->hw.pf_id;
ctxt.vf_num = 0;
ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL);
ctxt.flags = I40E_AQ_VSI_TYPE_PF; if (ret) {
dev_info(&pf->pdev->dev, "couldn't get PF vsi config, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status)); return -ENOENT;
}
vsi->info = ctxt.info;
vsi->info.valid_sections = 0;
vsi->seid = ctxt.seid;
vsi->id = ctxt.vsi_number;
enabled_tc = i40e_pf_get_tc_map(pf);
/* Source pruning is enabled by default, so the flag is *negativelogic-ifit'sset,weneedtofiddlewith *theVSItodisablesourcepruning.
*/ if (test_bit(I40E_FLAG_SOURCE_PRUNING_DIS, pf->flags)) {
memset(&ctxt, 0, sizeof(ctxt));
ctxt.seid = pf->main_vsi_seid;
ctxt.pf_num = pf->hw.pf_id;
ctxt.vf_num = 0;
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
ctxt.info.switch_id =
cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB);
ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); if (ret) {
dev_info(&pf->pdev->dev, "update vsi failed, err %d aq_err %s\n",
ret,
libie_aq_str(pf->hw.aq.asq_last_status));
ret = -ENOENT; goto err;
}
}
/* MFP mode setup queue map and update VSI */ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) &&
!(pf->hw.func_caps.iscsi)) { /* NIC type PF */
memset(&ctxt, 0, sizeof(ctxt));
ctxt.seid = pf->main_vsi_seid;
ctxt.pf_num = pf->hw.pf_id;
ctxt.vf_num = 0;
i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false);
ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); if (ret) {
dev_info(&pf->pdev->dev, "update vsi failed, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status));
ret = -ENOENT; goto err;
} /* update the local VSI info queue map */
i40e_vsi_update_queue_map(vsi, &ctxt);
vsi->info.valid_sections = 0;
} else { /* Default/Main VSI is only enabled for TC0 *reconfigureittoenableallTCsthatare *availableontheportinSFPmode. *ForMFPcasetheiSCSIPFwouldusethis *flowtoenableLAN+iSCSITC.
*/
ret = i40e_vsi_config_tc(vsi, enabled_tc); if (ret) { /* Single TC condition is not fatal, *messageandcontinue
*/
dev_info(&pf->pdev->dev, "failed to configure TCs for main VSI tc_map 0x%08x, err %pe aq_err %s\n",
enabled_tc,
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status));
}
} break;
/* This VSI is connected to VEB so the switch_id *shouldbesettozerobydefault.
*/ if (i40e_is_vsi_uplink_mode_veb(vsi)) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
ctxt.info.switch_id =
cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
}
/* Setup the VSI tx/rx queue map for TC0 only for now */
i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true); break;
/* This VSI is connected to VEB so the switch_id *shouldbesettozerobydefault.
*/ if (i40e_is_vsi_uplink_mode_veb(vsi)) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
ctxt.info.switch_id =
cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
}
ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_ALL; if (pf->vf[vsi->vf_id].spoofchk) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID);
ctxt.info.sec_flags |=
(I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK |
I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK);
} /* Setup the VSI tx/rx queue map for TC0 only for now */
i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true); break;
case I40E_VSI_IWARP: /* send down message to iWARP */ break;
default: return -ENODEV;
}
if (vsi->type != I40E_VSI_MAIN) {
ret = i40e_aq_add_vsi(hw, &ctxt, NULL); if (ret) {
dev_info(&vsi->back->pdev->dev, "add vsi failed, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status));
ret = -ENOENT; goto err;
}
vsi->info = ctxt.info;
vsi->info.valid_sections = 0;
vsi->seid = ctxt.seid;
vsi->id = ctxt.vsi_number;
}
spin_lock_bh(&vsi->mac_filter_hash_lock);
vsi->active_filters = 0; /* If macvlan filters already exist, force them to get loaded */
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
f->state = I40E_FILTER_NEW;
f_count++;
}
spin_unlock_bh(&vsi->mac_filter_hash_lock);
clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
if (f_count) {
vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
set_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state);
}
/* Update VSI BW information */
ret = i40e_vsi_get_bw_info(vsi); if (ret) {
dev_info(&pf->pdev->dev, "couldn't get vsi bw info, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status)); /* VSI is already added so not tearing that up */
ret = 0;
}
err: return ret;
}
/** *i40e_vsi_release-DeleteaVSIandfreeitsresources *@vsi:theVSIbeingremoved * *Returns0onsuccessor<0onerror
**/ int i40e_vsi_release(struct i40e_vsi *vsi)
{ struct i40e_mac_filter *f; struct hlist_node *h; struct i40e_veb *veb; struct i40e_pf *pf;
u16 uplink_seid; int i, n, bkt;
pf = vsi->back;
/* release of a VEB-owner or last VSI is not allowed */ if (vsi->flags & I40E_VSI_FLAG_VEB_OWNER) {
dev_info(&pf->pdev->dev, "VSI %d has existing VEB %d\n",
vsi->seid, vsi->uplink_seid); return -ENODEV;
} if (vsi->type == I40E_VSI_MAIN && !test_bit(__I40E_DOWN, pf->state)) {
dev_info(&pf->pdev->dev, "Can't remove PF VSI\n"); return -ENODEV;
}
set_bit(__I40E_VSI_RELEASING, vsi->state);
uplink_seid = vsi->uplink_seid;
if (vsi->type != I40E_VSI_SRIOV) { if (vsi->netdev_registered) {
vsi->netdev_registered = false; if (vsi->netdev) { /* results in a call to i40e_close() */
unregister_netdev(vsi->netdev);
}
} else {
i40e_vsi_close(vsi);
}
i40e_vsi_disable_irq(vsi);
}
if (vsi->type == I40E_VSI_MAIN)
i40e_devlink_destroy_port(pf);
spin_lock_bh(&vsi->mac_filter_hash_lock);
/* clear the sync flag on all filters */ if (vsi->netdev) {
__dev_uc_unsync(vsi->netdev, NULL);
__dev_mc_unsync(vsi->netdev, NULL);
}
/* make sure any remaining filters are marked for deletion */
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist)
__i40e_del_filter(vsi, f);
/* If this was the last thing on the VEB, except for the *controllingVSI,removetheVEB,whichputsthecontrolling *VSIontotheuplinkport. * *Well,okay,there'sonemoreexceptionhere:don'tremove *thefloatingVEBsyet.We'llwaitforanexplicitremoverequest *fromupthenetworkstack.
*/
veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); if (veb && veb->uplink_seid) {
n = 0;
/* Count non-controlling VSIs present on the VEB */
i40e_pf_for_each_vsi(pf, i, vsi) if (vsi->uplink_seid == uplink_seid &&
(vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0)
n++;
/* If there is no VSI except the control one then release *theVEBandputthecontrolVSIontoVEBuplink.
*/ if (!n)
i40e_veb_release(veb);
}
if (vsi->q_vectors[0]) {
dev_info(&pf->pdev->dev, "VSI %d has existing q_vectors\n",
vsi->seid); return -EEXIST;
}
if (vsi->base_vector) {
dev_info(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n",
vsi->seid, vsi->base_vector); return -EEXIST;
}
ret = i40e_vsi_alloc_q_vectors(vsi); if (ret) {
dev_info(&pf->pdev->dev, "failed to allocate %d q_vector for VSI %d, ret=%d\n",
vsi->num_q_vectors, vsi->seid, ret);
vsi->num_q_vectors = 0; goto vector_setup_out;
}
/* In Legacy mode, we do not have to get any other vector since we *piggybackonthemisc/ICR0forqueueinterrupts.
*/ if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) return ret; if (vsi->num_q_vectors)
vsi->base_vector = i40e_get_lump(pf, pf->irq_pile,
vsi->num_q_vectors, vsi->idx); if (vsi->base_vector < 0) {
dev_info(&pf->pdev->dev, "failed to get tracking for %d vectors for VSI %d, err=%d\n",
vsi->num_q_vectors, vsi->seid, vsi->base_vector);
i40e_vsi_free_q_vectors(vsi);
ret = -ENOENT; goto vector_setup_out;
}
ret = i40e_get_lump(pf, pf->qp_pile, alloc_queue_pairs, vsi->idx); if (ret < 0) {
dev_info(&pf->pdev->dev, "failed to get tracking for %d queues for VSI %d err %d\n",
alloc_queue_pairs, vsi->seid, ret); goto err_vsi;
}
vsi->base_queue = ret;
/* Update the FW view of the VSI. Force a reset of TC and queue *layoutconfigurations.
*/
main_vsi = i40e_pf_get_main_vsi(pf);
main_vsi->seid = pf->main_vsi_seid;
i40e_vsi_reconfig_tc(main_vsi);
if (vsi->type == I40E_VSI_MAIN)
i40e_rm_default_mac_filter(vsi, pf->hw.mac.perm_addr);
/* assign it some queues */
ret = i40e_alloc_rings(vsi); if (ret) goto err_rings;
/* map all of the rings to the q_vectors */
i40e_vsi_map_rings_to_vectors(vsi); return vsi;
/* The requested uplink_seid must be either *-thePF'sportseid *noVEBisneededbecausethisisthePF *orthisisaFlowDirectorspecialcaseVSI *-seidofanexistingVEB *-seidofaVSIthatownsanexistingVEB *-seidofaVSIthatdoesn'townaVEB *anewVEBiscreatedandtheVSIbecomestheowner *-seidofthePFVSI,whichiswhatcreatesthefirstVEB *thisisaspecialcaseoftheprevious * *Findwhichuplink_seidweweregivenandcreateanewVEBifneeded
*/
veb = i40e_pf_get_veb_by_seid(pf, uplink_seid); if (!veb && uplink_seid != pf->mac_seid) {
vsi = i40e_pf_get_vsi_by_seid(pf, uplink_seid); if (!vsi) {
dev_info(&pf->pdev->dev, "no such uplink_seid %d\n",
uplink_seid); return NULL;
}
if (vsi->uplink_seid == pf->mac_seid)
veb = i40e_veb_setup(pf, pf->mac_seid, vsi->seid,
vsi->tc_config.enabled_tc); elseif ((vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0)
veb = i40e_veb_setup(pf, vsi->uplink_seid, vsi->seid,
vsi->tc_config.enabled_tc); if (veb) { if (vsi->type != I40E_VSI_MAIN) {
dev_info(&vsi->back->pdev->dev, "New VSI creation error, uplink seid of LAN VSI expected.\n"); return NULL;
} /* We come up by default in VEPA mode if SRIOV is not *alreadyenabled,inwhichcasewecan'tforceVEPA *mode.
*/ if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) {
veb->bridge_mode = BRIDGE_MODE_VEPA;
clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
}
i40e_config_bridge_mode(veb);
}
veb = i40e_pf_get_veb_by_seid(pf, vsi->uplink_seid); if (!veb) {
dev_info(&pf->pdev->dev, "couldn't add VEB\n"); return NULL;
}
/* get vsi sw struct */
v_idx = i40e_vsi_mem_alloc(pf, type); if (v_idx < 0) goto err_alloc;
vsi = pf->vsi[v_idx]; if (!vsi) goto err_alloc;
vsi->type = type;
vsi->veb_idx = (veb ? veb->idx : I40E_NO_VEB);
if (type == I40E_VSI_MAIN)
pf->lan_vsi = v_idx; elseif (type == I40E_VSI_SRIOV)
vsi->vf_id = param1; /* assign it some queues */
alloc_queue_pairs = vsi->alloc_queue_pairs *
(i40e_enabled_xdp_vsi(vsi) ? 2 : 1);
ret = i40e_get_lump(pf, pf->qp_pile, alloc_queue_pairs, vsi->idx); if (ret < 0) {
dev_info(&pf->pdev->dev, "failed to get tracking for %d queues for VSI %d err=%d\n",
alloc_queue_pairs, vsi->seid, ret); goto err_vsi;
}
vsi->base_queue = ret;
/* get a VSI from the hardware */
vsi->uplink_seid = uplink_seid;
ret = i40e_add_vsi(vsi); if (ret) goto err_vsi;
switch (vsi->type) { /* setup the netdev if needed */ case I40E_VSI_MAIN: case I40E_VSI_VMDQ2:
ret = i40e_config_netdev(vsi); if (ret) goto err_netdev;
ret = i40e_netif_set_realnum_tx_rx_queues(vsi); if (ret) goto err_netdev; if (vsi->type == I40E_VSI_MAIN) {
ret = i40e_devlink_create_port(pf); if (ret) goto err_netdev;
SET_NETDEV_DEVLINK_PORT(vsi->netdev, &pf->devlink_port);
}
ret = register_netdev(vsi->netdev); if (ret) goto err_dl_port;
vsi->netdev_registered = true;
netif_carrier_off(vsi->netdev); #ifdef CONFIG_I40E_DCB /* Setup DCB netlink interface */
i40e_dcbnl_setup(vsi); #endif/* CONFIG_I40E_DCB */
fallthrough; case I40E_VSI_FDIR: /* set up vectors and rings if needed */
ret = i40e_vsi_setup_vectors(vsi); if (ret) goto err_msix;
ret = i40e_alloc_rings(vsi); if (ret) goto err_rings;
/* map all of the rings to the q_vectors */
i40e_vsi_map_rings_to_vectors(vsi);
i40e_vsi_reset_stats(vsi); break; default: /* no netdev or rings for the other VSI types */ break;
}
if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps) &&
vsi->type == I40E_VSI_VMDQ2) {
ret = i40e_vsi_config_rss(vsi); if (ret) goto err_config;
} return vsi;
/** *i40e_veb_mem_alloc-AllocatesthenextavailablestructvebinthePF *@pf:boardprivatestructure * *Onerror:returnserrorcode(negative) *Onsuccess:returnsvsiindexinPF(positive)
**/ staticint i40e_veb_mem_alloc(struct i40e_pf *pf)
{ int ret = -ENOENT; struct i40e_veb *veb; int i;
/* Need to protect the allocation of switch elements at the PF level */
mutex_lock(&pf->switch_mutex);
/* VEB list may be fragmented if VEB creation/destruction has *beenhappening.Wecanaffordtodoaquickscantolook *foranyfreeslotsinthelist. * *findnextemptyvebslot,loopingbackaroundifnecessary
*/
i = 0; while ((i < I40E_MAX_VEB) && (pf->veb[i] != NULL))
i++; if (i >= I40E_MAX_VEB) {
ret = -ENOMEM; goto err_alloc_veb; /* out of VEB slots! */
}
veb = kzalloc(sizeof(*veb), GFP_KERNEL); if (!veb) {
ret = -ENOMEM; goto err_alloc_veb;
}
veb->pf = pf;
veb->idx = i;
veb->enabled_tc = 1;
/* release any VEBs on this VEB - RECURSION */
i40e_pf_for_each_veb(pf, i, veb) if (veb->uplink_seid == branch->seid)
i40e_switch_branch_release(veb);
/* Release the VSIs on this VEB, but not the owner VSI. * *NOTE:RemovingthelastVSIonaVEBhastheSIDEEFFECTofremoving *theVEBitself,sodon'tuse(*branch)afterthisloop.
*/
i40e_pf_for_each_vsi(pf, i, vsi) if (vsi->uplink_seid == branch_seid &&
(vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0)
i40e_vsi_release(vsi);
/* There's one corner case where the VEB might not have been *removed,sodoublecheckithereandremoveitifneeded. *Thiscasehappensifthevebwascreatedfromthedebugfs *commandsandnoVSIswereaddedtoit.
*/ if (pf->veb[veb_idx])
i40e_veb_release(pf->veb[veb_idx]);
}
mutex_lock(&pf->switch_mutex); if (pf->veb[veb->idx] == veb)
pf->veb[veb->idx] = NULL;
mutex_unlock(&pf->switch_mutex);
}
kfree(veb);
}
/** *i40e_veb_release-DeleteaVEBandfreeitsresources *@veb:theVEBbeingremoved
**/ void i40e_veb_release(struct i40e_veb *veb)
{ struct i40e_vsi *vsi, *vsi_it; struct i40e_pf *pf; int i, n = 0;
pf = veb->pf;
/* find the remaining VSI and check for extras */
i40e_pf_for_each_vsi(pf, i, vsi_it) if (vsi_it->uplink_seid == veb->seid) { if (vsi_it->flags & I40E_VSI_FLAG_VEB_OWNER)
vsi = vsi_it;
n++;
}
/* Floating VEB has to be empty and regular one must have *singleownerVSI.
*/ if ((veb->uplink_seid && n != 1) || (!veb->uplink_seid && n != 0)) {
dev_info(&pf->pdev->dev, "can't remove VEB %d with %d VSIs left\n",
veb->seid, n); return;
}
/* For regular VEB move the owner VSI to uplink port */ if (veb->uplink_seid) {
vsi->flags &= ~I40E_VSI_FLAG_VEB_OWNER;
vsi->uplink_seid = veb->uplink_seid;
vsi->veb_idx = I40E_NO_VEB;
}
ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi ? vsi->seid : 0,
veb->enabled_tc, vsi ? false : true,
&veb->seid, enable_stats, NULL);
/* get a VEB from the hardware */ if (ret) {
dev_info(&pf->pdev->dev, "couldn't add VEB, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status)); return -EPERM;
}
/* get statistics counter */
ret = i40e_aq_get_veb_parameters(&pf->hw, veb->seid, NULL, NULL,
&veb->stats_idx, NULL, NULL, NULL); if (ret) {
dev_info(&pf->pdev->dev, "couldn't get VEB statistics idx, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status)); return -EPERM;
}
ret = i40e_veb_get_bw_info(veb); if (ret) {
dev_info(&pf->pdev->dev, "couldn't get VEB bw info, err %pe aq_err %s\n",
ERR_PTR(ret), libie_aq_str(pf->hw.aq.asq_last_status));
i40e_aq_delete_element(&pf->hw, veb->seid, NULL); return -ENOENT;
}
/* if one seid is 0, the other must be 0 to create a floating relay */ if ((uplink_seid == 0 || vsi_seid == 0) &&
(uplink_seid + vsi_seid != 0)) {
dev_info(&pf->pdev->dev, "one, not both seid's are 0: uplink=%d vsi=%d\n",
uplink_seid, vsi_seid); return NULL;
}
/* make sure there is such a vsi and uplink */ if (vsi_seid) {
vsi = i40e_pf_get_vsi_by_seid(pf, vsi_seid); if (!vsi) {
dev_err(&pf->pdev->dev, "vsi seid %d not found\n",
vsi_seid); return NULL;
}
}
/* get veb sw struct */
veb_idx = i40e_veb_mem_alloc(pf); if (veb_idx < 0) goto err_alloc;
veb = pf->veb[veb_idx];
veb->uplink_seid = uplink_seid;
veb->enabled_tc = (enabled_tc ? enabled_tc : 0x1);
/* create the VEB in the switch */
ret = i40e_add_veb(veb, vsi); if (ret) goto err_veb;
if (vsi && vsi->idx == pf->lan_vsi)
pf->lan_veb = veb->idx;
switch (element_type) { case I40E_SWITCH_ELEMENT_TYPE_MAC:
pf->mac_seid = seid; break; case I40E_SWITCH_ELEMENT_TYPE_VEB: /* Main VEB? */ if (uplink_seid != pf->mac_seid) break;
veb = i40e_pf_get_main_veb(pf); if (!veb) { int v;
/* find existing or else empty VEB */
veb = i40e_pf_get_veb_by_seid(pf, seid); if (veb) {
pf->lan_veb = veb->idx;
} else {
v = i40e_veb_mem_alloc(pf); if (v < 0) break;
pf->lan_veb = v;
}
}
/* Try to get again main VEB as pf->lan_veb may have changed */
veb = i40e_pf_get_main_veb(pf); if (!veb) break;
veb->seid = seid;
veb->uplink_seid = pf->mac_seid;
veb->pf = pf; break; case I40E_SWITCH_ELEMENT_TYPE_VSI: if (num_reported != 1) break; /* This is immediately after a reset so we can assume this is *thePF'sVSI
*/
pf->mac_seid = uplink_seid;
pf->main_vsi_seid = seid; if (printconfig)
dev_info(&pf->pdev->dev, "pf_seid=%d main_vsi_seid=%d\n",
downlink_seid, pf->main_vsi_seid); break; case I40E_SWITCH_ELEMENT_TYPE_PF: case I40E_SWITCH_ELEMENT_TYPE_VF: case I40E_SWITCH_ELEMENT_TYPE_EMP: case I40E_SWITCH_ELEMENT_TYPE_BMC: case I40E_SWITCH_ELEMENT_TYPE_PE: case I40E_SWITCH_ELEMENT_TYPE_PA: /* ignore these for now */ break; default:
dev_info(&pf->pdev->dev, "unknown element type=%d seid=%d\n",
element_type, seid); break;
}
}
/** *i40e_fetch_switch_configuration-Getswitchconfigfromfirmware *@pf:boardprivatestructure *@printconfig:shouldweprintthecontents * *Getthecurrentswitchconfigurationfromthedeviceand *extractafewusefulSEIDvalues.
**/ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig)
{ struct i40e_aqc_get_switch_config_resp *sw_config;
u16 next_seid = 0; int ret = 0;
u8 *aq_buf; int i;
aq_buf = kzalloc(I40E_AQ_LARGE_BUF, GFP_KERNEL); if (!aq_buf) return -ENOMEM;
sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; do {
u16 num_reported, num_total;
valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
ret = i40e_aq_set_switch_config(&pf->hw, flags, valid_flags, 0,
NULL); if (ret && pf->hw.aq.asq_last_status != LIBIE_AQ_RC_ESRCH) {
dev_info(&pf->pdev->dev, "couldn't set switch config bits, err %pe aq_err %s\n",
ERR_PTR(ret),
libie_aq_str(pf->hw.aq.asq_last_status)); /* not a fatal problem, just keep going */
}
pf->last_sw_conf_valid_flags = valid_flags;
}
/* first time setup */
main_vsi = i40e_pf_get_main_vsi(pf); if (!main_vsi || reinit) { struct i40e_veb *veb;
u16 uplink_seid;
/* Set up the PF VSI associated with the PF's main VSI *thatisalreadyintheHWswitch
*/
veb = i40e_pf_get_main_veb(pf); if (veb)
uplink_seid = veb->seid; else
uplink_seid = pf->mac_seid; if (!main_vsi)
main_vsi = i40e_vsi_setup(pf, I40E_VSI_MAIN,
uplink_seid, 0); elseif (reinit)
main_vsi = i40e_vsi_reinit_setup(main_vsi); if (!main_vsi) {
dev_info(&pf->pdev->dev, "setup of MAIN VSI failed\n");
i40e_cloud_filter_exit(pf);
i40e_fdir_teardown(pf); return -EAGAIN;
}
} else { /* force a reset of TC and queue layout configurations */
main_vsi->seid = pf->main_vsi_seid;
i40e_vsi_reconfig_tc(main_vsi);
}
i40e_vlan_stripping_disable(main_vsi);
i40e_fdir_sb_setup(pf);
/* Setup static PF queue filter control settings */
ret = i40e_setup_pf_filter_control(pf); if (ret) {
dev_info(&pf->pdev->dev, "setup_pf_filter_control failed: %d\n",
ret); /* Failure here should not stop continuing other steps */
}
/* enable RSS in the HW, even for only one queue, as the stack can use *thehash
*/ if (test_bit(I40E_FLAG_RSS_ENA, pf->flags))
i40e_pf_config_rss(pf);
/* fill in link information and enable LSE reporting */
i40e_link_event(pf);
i40e_ptp_init(pf);
if (!lock_acquired)
rtnl_lock();
/* repopulate tunnel port filters */
udp_tunnel_nic_reset_ntf(main_vsi->netdev);
if (!lock_acquired)
rtnl_unlock();
return ret;
}
/** *i40e_determine_queue_usage-Workoutqueuedistribution *@pf:boardprivatestructure
**/ staticvoid i40e_determine_queue_usage(struct i40e_pf *pf)
{ int queues_left; int q_max;
pf->num_lan_qps = 0;
/* Find the max queues to be put into basic use. We'll always be *usingTC0,whetherornotDCBisrunning,andTC0willgetthe *bigRSSset.
*/
queues_left = pf->hw.func_caps.num_tx_qp;
if ((queues_left == 1) ||
!test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) { /* one qp for PF, no queues for anything else */
queues_left = 0;
pf->alloc_rss_size = pf->num_lan_qps = 1;
/* make sure all the fancies are disabled */
clear_bit(I40E_FLAG_RSS_ENA, pf->flags);
clear_bit(I40E_FLAG_IWARP_ENA, pf->flags);
clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
clear_bit(I40E_FLAG_FD_ATR_ENA, pf->flags);
clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags);
clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags);
set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
} elseif (!test_bit(I40E_FLAG_RSS_ENA, pf->flags) &&
!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) &&
!test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) &&
!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) { /* one qp for PF */
pf->alloc_rss_size = pf->num_lan_qps = 1;
queues_left -= pf->num_lan_qps;
clear_bit(I40E_FLAG_RSS_ENA, pf->flags);
clear_bit(I40E_FLAG_IWARP_ENA, pf->flags);
clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
clear_bit(I40E_FLAG_FD_ATR_ENA, pf->flags);
clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags);
set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
} else { /* Not enough queues for all TCs */ if (test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags) &&
queues_left < I40E_MAX_TRAFFIC_CLASS) {
clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
dev_info(&pf->pdev->dev, "not enough queues for DCB. DCB is disabled.\n");
}
/* limit lan qps to the smaller of qps, cpus or msix */
q_max = max_t(int, pf->rss_size_max, num_online_cpus());
q_max = min_t(int, q_max, pf->hw.func_caps.num_tx_qp);
q_max = min_t(int, q_max, pf->hw.func_caps.num_msix_vectors);
pf->num_lan_qps = q_max;
queues_left -= pf->num_lan_qps;
}
if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) { if (queues_left > 1) {
queues_left -= 1; /* save 1 queue for FD */
} else {
clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
dev_info(&pf->pdev->dev, "not enough queues for Flow Director. Flow Director feature is disabled\n");
}
}
/* Flow Director is enabled */ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) ||
test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags))
settings->enable_fdir = true;
/* Ethtype and MACVLAN filters enabled for PF */
settings->enable_ethtype = true;
settings->enable_macvlan = true;
if (i40e_set_filter_control(&pf->hw, settings)) return -ENOENT;
if (val & I40E_GL_FWSTS_FWS1B_MASK) {
dev_crit(&pf->pdev->dev, "Firmware recovery mode detected. Limiting functionality.\n");
dev_crit(&pf->pdev->dev, "Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n");
set_bit(__I40E_RECOVERY_MODE, pf->state);
returntrue;
} if (test_bit(__I40E_RECOVERY_MODE, pf->state))
dev_info(&pf->pdev->dev, "Please do Power-On Reset to initialize adapter in normal mode with full functionality.\n");
if (is_empr || pfr != 0)
dev_crit(&pf->pdev->dev, "Entering recovery mode due to repeated FW resets. This may take several minutes. Refer to the Intel(R) Ethernet Adapters and Devices User Guide.\n");
err = i40e_init_interrupt_scheme(pf); if (err) goto err_switch_setup;
/* The number of VSIs reported by the FW is the minimum guaranteed *tous;HWsupportsfarmoreandwesharetheremainingpoolwith *theotherPFs.Weallocatespaceformorethantheguaranteewith *theunderstandingthatwemightnotgetthemalllater.
*/ if (pf->hw.func_caps.num_vsis < I40E_MIN_VSI_ALLOC)
pf->num_alloc_vsi = I40E_MIN_VSI_ALLOC; else
pf->num_alloc_vsi = pf->hw.func_caps.num_vsis;
/* Set up the vsi struct and our local tracking of the MAIN PF vsi. */
pf->vsi = kcalloc(pf->num_alloc_vsi, sizeof(struct i40e_vsi *),
GFP_KERNEL); if (!pf->vsi) {
err = -ENOMEM; goto err_switch_setup;
}
/* We allocate one VSI which is needed as absolute minimum *inordertoregisterthenetdev
*/
v_idx = i40e_vsi_mem_alloc(pf, I40E_VSI_MAIN); if (v_idx < 0) {
err = v_idx; goto err_switch_setup;
}
pf->lan_vsi = v_idx;
vsi = pf->vsi[v_idx]; if (!vsi) {
err = -EFAULT; goto err_switch_setup;
}
vsi->alloc_queue_pairs = 1;
err = i40e_config_netdev(vsi); if (err) goto err_switch_setup;
err = register_netdev(vsi->netdev); if (err) goto err_switch_setup;
vsi->netdev_registered = true;
i40e_dbg_pf_init(pf);
err = i40e_setup_misc_vector_for_recovery_mode(pf); if (err) goto err_switch_setup;
/* tell the firmware that we're starting */
i40e_send_version(pf);
/* since everything's happy, start the service_task timer */
mod_timer(&pf->service_timer,
round_jiffies(jiffies + pf->service_timer_period));
err = pci_enable_device_mem(pdev); if (err) return err;
/* set up for high or low dma */
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (err) {
dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err); goto err_dma;
}
/* set up pci connections */
err = pci_request_mem_regions(pdev, i40e_driver_name); if (err) {
dev_info(&pdev->dev, "pci_request_selected_regions failed %d\n", err); goto err_pci_reg;
}
pci_set_master(pdev);
/* Now that we have a PCI connection, we need to do the *lowleveldevicesetup.Thisisprimarilysettingup *theAdminQueuestructuresandthenqueryingforthe *device'scurrentprofileinformation.
*/
pf = i40e_alloc_pf(&pdev->dev); if (!pf) {
err = -ENOMEM; goto err_pf_alloc;
}
pf->next_vsi = 0;
pf->pdev = pdev;
set_bit(__I40E_DOWN, pf->state);
hw = &pf->hw;
pf->ioremap_len = min_t(int, pci_resource_len(pdev, 0),
I40E_MAX_CSR_SPACE); /* We believe that the highest register to read is *I40E_GLGEN_STAT_CLEAR,sowecheckiftheBARsize *isnotlessthanthatbeforemappingtopreventa *kernelpanic.
*/ if (pf->ioremap_len < I40E_GLGEN_STAT_CLEAR) {
dev_err(&pdev->dev, "Cannot map registers, bar size 0x%X too small, aborting\n",
pf->ioremap_len);
err = -ENOMEM; goto err_ioremap;
}
hw->hw_addr = ioremap(pci_resource_start(pdev, 0), pf->ioremap_len); if (!hw->hw_addr) {
err = -EIO;
dev_info(&pdev->dev, "ioremap(0x%04x, 0x%04x) failed: 0x%x\n",
(unsignedint)pci_resource_start(pdev, 0),
pf->ioremap_len, err); goto err_ioremap;
}
hw->vendor_id = pdev->vendor;
hw->device_id = pdev->device;
pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
hw->subsystem_vendor_id = pdev->subsystem_vendor;
i40e_set_subsystem_device_id(hw);
hw->bus.device = PCI_SLOT(pdev->devfn);
hw->bus.func = PCI_FUNC(pdev->devfn);
hw->bus.bus_id = pdev->bus->number;
/* Select something other than the 802.1ad ethertype for the *switchtouseinternallyanddroponingress.
*/
hw->switch_tag = 0xffff;
hw->first_tag = ETH_P_8021AD;
hw->second_tag = ETH_P_8021Q;
/* set up the locks for the AQ, do this only once in probe *anddestroythemonlyonceinremove
*/
mutex_init(&hw->aq.asq_mutex);
mutex_init(&hw->aq.arq_mutex);
/* do a special CORER for clearing PXE mode once at init */ if (hw->revision_id == 0 &&
(rd32(hw, I40E_GLLAN_RCTL_0) & I40E_GLLAN_RCTL_0_PXE_MODE_MASK)) {
wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_CORER_MASK);
i40e_flush(hw);
msleep(200);
pf->corer_count++;
i40e_clear_pxe_mode(hw);
}
/* Reset here to make sure all is clean and to define PF 'n' */
i40e_clear_hw(hw);
err = i40e_set_mac_type(hw); if (err) {
dev_warn(&pdev->dev, "unidentified MAC or BLANK NVM: %d\n",
err); goto err_pf_reset;
}
err = i40e_handle_resets(pf); if (err) goto err_pf_reset;
err = i40e_init_shared_code(hw); if (err) {
dev_warn(&pdev->dev, "unidentified MAC or BLANK NVM: %d\n",
err); goto err_pf_reset;
}
/* set up a default setting for link flow control */
pf->hw.fc.requested_mode = I40E_FC_NONE;
err = i40e_init_adminq(hw); if (err) { if (err == -EIO)
dev_info(&pdev->dev, "The driver for the device stopped because the NVM image v%u.%u is newer than expected v%u.%u. You must install the most recent version of the network driver.\n",
hw->aq.api_maj_ver,
hw->aq.api_min_ver,
I40E_FW_API_VERSION_MAJOR,
I40E_FW_MINOR_VERSION(hw)); else
dev_info(&pdev->dev, "The driver for the device stopped because the device firmware failed to init. Try updating your NVM image.\n");
/* provide nvm, fw, api versions, vendor:device id, subsys vendor:device id */
i40e_nvm_version_str(hw, nvm_ver, sizeof(nvm_ver));
dev_info(&pdev->dev, "fw %d.%d.%05d api %d.%d nvm %s [%04x:%04x] [%04x:%04x]\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, nvm_ver,
hw->vendor_id, hw->device_id, hw->subsystem_vendor_id,
hw->subsystem_device_id);
if (i40e_is_aq_api_ver_ge(hw, I40E_FW_API_VERSION_MAJOR,
I40E_FW_MINOR_VERSION(hw) + 1))
dev_dbg(&pdev->dev, "The driver for the device detected a newer version of the NVM image v%u.%u than v%u.%u.\n",
hw->aq.api_maj_ver,
hw->aq.api_min_ver,
I40E_FW_API_VERSION_MAJOR,
I40E_FW_MINOR_VERSION(hw)); elseif (i40e_is_aq_api_ver_lt(hw, 1, 4))
dev_info(&pdev->dev, "The driver for the device detected an older version of the NVM image v%u.%u than expected v%u.%u. Please update the NVM image.\n",
hw->aq.api_maj_ver,
hw->aq.api_min_ver,
I40E_FW_API_VERSION_MAJOR,
I40E_FW_MINOR_VERSION(hw));
i40e_verify_eeprom(pf);
/* Rev 0 hardware was never productized */ if (hw->revision_id < 1)
dev_warn(&pdev->dev, "This device is a pre-production adapter/LOM. Please be aware there may be issues with your hardware. If you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\n");
i40e_clear_pxe_mode(hw);
err = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities); if (err) goto err_adminq_setup;
/* NVM bit on means WoL disabled for the port */
i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); if (BIT (hw->port) & wol_nvm_bits || hw->partition_id != 1)
pf->wol_en = false; else
pf->wol_en = true;
device_set_wakeup_enable(&pf->pdev->dev, pf->wol_en);
/* set up the main switch operations */
i40e_determine_queue_usage(pf);
err = i40e_init_interrupt_scheme(pf); if (err) goto err_switch_setup;
/* Reduce Tx and Rx pairs for kdump *WhenMSI-Xisenabled,it'snotallowedtousemoreTCqueue *pairsthanMSI-Xvectors(pf->num_lan_msix)exist.Thus *vsi->num_queue_pairswillbeequaltopf->num_lan_msix,i.e.,1.
*/ if (is_kdump_kernel())
pf->num_lan_msix = 1;
/* The number of VSIs reported by the FW is the minimum guaranteed *tous;HWsupportsfarmoreandwesharetheremainingpoolwith *theotherPFs.Weallocatespaceformorethantheguaranteewith *theunderstandingthatwemightnotgetthemalllater.
*/ if (pf->hw.func_caps.num_vsis < I40E_MIN_VSI_ALLOC)
pf->num_alloc_vsi = I40E_MIN_VSI_ALLOC; else
pf->num_alloc_vsi = pf->hw.func_caps.num_vsis; if (pf->num_alloc_vsi > UDP_TUNNEL_NIC_MAX_SHARING_DEVICES) {
dev_warn(&pf->pdev->dev, "limiting the VSI count due to UDP tunnel limitation %d > %d\n",
pf->num_alloc_vsi, UDP_TUNNEL_NIC_MAX_SHARING_DEVICES);
pf->num_alloc_vsi = UDP_TUNNEL_NIC_MAX_SHARING_DEVICES;
}
/* Set up the *vsi struct and our local tracking of the MAIN PF vsi. */
pf->vsi = kcalloc(pf->num_alloc_vsi, sizeof(struct i40e_vsi *),
GFP_KERNEL); if (!pf->vsi) {
err = -ENOMEM; goto err_switch_setup;
}
#ifdef CONFIG_PCI_IOV /* prep for VF support */ if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags) &&
test_bit(I40E_FLAG_MSIX_ENA, pf->flags) &&
!test_bit(__I40E_BAD_EEPROM, pf->state)) { if (pci_num_vf(pdev))
set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
} #endif
err = i40e_setup_pf_switch(pf, false, false); if (err) {
dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err); goto err_vsis;
}
vsi = i40e_pf_get_main_vsi(pf);
INIT_LIST_HEAD(&vsi->ch_list);
/* if FDIR VSI was set up, start it now */
vsi = i40e_find_vsi_by_type(pf, I40E_VSI_FDIR); if (vsi)
i40e_vsi_open(vsi);
/* The driver only wants link up/down and module qualification *reportsfromfirmware.Notethenegativelogic.
*/
err = i40e_aq_set_phy_int_mask(&pf->hw,
~(I40E_AQ_EVENT_LINK_UPDOWN |
I40E_AQ_EVENT_MEDIA_NA |
I40E_AQ_EVENT_MODULE_QUAL_FAIL), NULL); if (err)
dev_info(&pf->pdev->dev, "set phy mask fail, err %pe aq_err %s\n",
ERR_PTR(err), libie_aq_str(pf->hw.aq.asq_last_status));
/* VF MDD event logs are rate limited to one second intervals */
ratelimit_state_init(&pf->mdd_message_rate_limit, 1 * HZ, 1);
/* Reconfigure hardware for allowing smaller MSS in the case *ofTSO,sothatweavoidtheMDDbeingfiredandcausing *aresetinthecaseofsmallMSS+TSO.
*/
val = rd32(hw, I40E_REG_MSS); if ((val & I40E_REG_MSS_MIN_MASK) > I40E_64BYTE_MSS) {
val &= ~I40E_REG_MSS_MIN_MASK;
val |= I40E_64BYTE_MSS;
wr32(hw, I40E_REG_MSS, val);
}
if (test_bit(I40E_HW_CAP_RESTART_AUTONEG, pf->hw.caps)) {
msleep(75);
err = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (err)
dev_info(&pf->pdev->dev, "link restart failed, err %pe aq_err %s\n",
ERR_PTR(err),
libie_aq_str(pf->hw.aq.asq_last_status));
} /* The main driver is (mostly) up and happy. We need to set this state *beforesettingupthemiscvectororwegetaraceandthevector *endsupdisabledforever.
*/
clear_bit(__I40E_DOWN, pf->state);
/* In case of MSIX we are going to setup the misc vector right here *tohandleadminqueueeventsetc.IncaseoflegacyandMSI *themiscfunctionalityandqueueprocessingiscombinedin *thesamevectorandthatgetssetupatopen.
*/ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
err = i40e_setup_misc_vector(pf); if (err) {
dev_info(&pdev->dev, "setup of misc vector failed: %d\n", err);
i40e_cloud_filter_exit(pf);
i40e_fdir_teardown(pf); goto err_vsis;
}
}
#ifdef CONFIG_PCI_IOV /* prep for VF support */ if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags) &&
test_bit(I40E_FLAG_MSIX_ENA, pf->flags) &&
!test_bit(__I40E_BAD_EEPROM, pf->state)) { /* disable link interrupts for VFs */
val = rd32(hw, I40E_PFGEN_PORTMDIO_NUM);
val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val);
i40e_flush(hw);
if (pci_num_vf(pdev)) {
dev_info(&pdev->dev, "Active VFs found, allocating resources.\n");
err = i40e_alloc_vfs(pf, pci_num_vf(pdev)); if (err)
dev_info(&pdev->dev, "Error %d allocating resources for existing VFs\n",
err);
}
} #endif/* CONFIG_PCI_IOV */
if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
pf->iwarp_base_vector = i40e_get_lump(pf, pf->irq_pile,
pf->num_iwarp_msix,
I40E_IWARP_IRQ_PILE_ID); if (pf->iwarp_base_vector < 0) {
dev_info(&pdev->dev, "failed to get tracking for %d vectors for IWARP err=%d\n",
pf->num_iwarp_msix, pf->iwarp_base_vector);
clear_bit(I40E_FLAG_IWARP_ENA, pf->flags);
}
}
i40e_dbg_pf_init(pf);
/* tell the firmware that we're starting */
i40e_send_version(pf);
/* since everything's happy, start the service_task timer */
mod_timer(&pf->service_timer,
round_jiffies(jiffies + pf->service_timer_period));
/* add this PF to client device list and launch a client service task */ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
err = i40e_lan_add_device(pf); if (err)
dev_info(&pdev->dev, "Failed to add PF to client API service list: %d\n",
err);
}
#define PCI_SPEED_SIZE 8 #define PCI_WIDTH_SIZE 8 /* Devices on the IOSF bus do not have this information *andwillreportPCIGen1x1bydefaultsodon'tbother *checkingthem.
*/ if (!test_bit(I40E_HW_CAP_NO_PCI_LINK_CHECK, pf->hw.caps)) { char speed[PCI_SPEED_SIZE] = "Unknown"; char width[PCI_WIDTH_SIZE] = "Unknown";
/* 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:
strscpy(speed, "8.0", PCI_SPEED_SIZE); break; case i40e_bus_speed_5000:
strscpy(speed, "5.0", PCI_SPEED_SIZE); break; case i40e_bus_speed_2500:
strscpy(speed, "2.5", PCI_SPEED_SIZE); break; default: break;
} switch (hw->bus.width) { case i40e_bus_width_pcie_x8:
strscpy(width, "8", PCI_WIDTH_SIZE); break; case i40e_bus_width_pcie_x4:
strscpy(width, "4", PCI_WIDTH_SIZE); break; case i40e_bus_width_pcie_x2:
strscpy(width, "2", PCI_WIDTH_SIZE); break; case i40e_bus_width_pcie_x1:
strscpy(width, "1", PCI_WIDTH_SIZE); break; default: break;
}
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_dbg(&pf->pdev->dev, "get requested speeds ret = %pe last_status = %s\n",
ERR_PTR(err), libie_aq_str(pf->hw.aq.asq_last_status));
pf->hw.phy.link_info.requested_speeds = abilities.link_speed;
/* set the FEC config due to the board capabilities */
i40e_set_fec_in_flags(abilities.fec_cfg_curr_mod_ext_info, pf->flags);
/* 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 = %pe last_status = %s\n",
ERR_PTR(err), libie_aq_str(pf->hw.aq.asq_last_status));
#define MAX_FRAME_SIZE_DEFAULT 0x2600
err = i40e_aq_set_mac_config(hw, MAX_FRAME_SIZE_DEFAULT, NULL); if (err)
dev_warn(&pdev->dev, "set mac config ret = %pe last_status = %s\n",
ERR_PTR(err), libie_aq_str(pf->hw.aq.asq_last_status));
/* Make sure the MFS is set to the expected value */
val = rd32(hw, I40E_PRTGL_SAH);
FIELD_MODIFY(I40E_PRTGL_SAH_MFS_MASK, &val, MAX_FRAME_SIZE_DEFAULT);
wr32(hw, I40E_PRTGL_SAH, val);
/* Add a filter to drop all Flow control frames from any VSI from being *transmitted.BydoingsowestopamaliciousVFfromsendingout *PAUSEorPFCframesandpotentiallycontrollingtrafficforother *PF/VFVSIs. *TheFWcanstillsendFlowcontrolframesifenabled.
*/
i40e_add_filter_to_drop_tx_flow_control_frames(&pf->hw,
pf->main_vsi_seid);
if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) ||
(pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4))
set_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps); if (pf->hw.device_id == I40E_DEV_ID_SFP_I_X722)
set_bit(I40E_HW_CAP_CRT_RETIMER, pf->hw.caps); /* print a string summarizing features */
i40e_print_features(pf);
i40e_devlink_register(pf);
return0;
/* Unwind what we've done if something failed in the setup */
err_vsis:
set_bit(__I40E_DOWN, pf->state);
i40e_clear_interrupt_scheme(pf);
kfree(pf->vsi);
err_switch_setup:
i40e_reset_interrupt_capability(pf);
timer_shutdown_sync(&pf->service_timer);
err_mac_addr:
err_configure_lan_hmc:
(void)i40e_shutdown_lan_hmc(hw);
err_init_lan_hmc:
kfree(pf->qp_pile);
err_sw_init:
err_adminq_setup:
err_pf_reset:
iounmap(hw->hw_addr);
err_ioremap:
i40e_free_pf(pf);
err_pf_alloc:
pci_release_mem_regions(pdev);
err_pci_reg:
err_dma:
pci_disable_device(pdev); return err;
}
/* Grab __I40E_RESET_RECOVERY_PENDING and set __I40E_IN_REMOVE *flags,oncetheyareset,i40e_rebuildshouldnotbecalledas *i40e_prep_for_resetalwaysreturnsearly.
*/ while (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
usleep_range(1000, 2000);
set_bit(__I40E_IN_REMOVE, pf->state);
if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags)) {
set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
i40e_free_vfs(pf);
clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags);
} /* no more scheduling of any task */
set_bit(__I40E_SUSPENDED, pf->state);
set_bit(__I40E_DOWN, pf->state); if (pf->service_timer.function)
timer_shutdown_sync(&pf->service_timer); if (pf->service_task.func)
cancel_work_sync(&pf->service_task);
if (test_bit(__I40E_RECOVERY_MODE, pf->state)) { struct i40e_vsi *vsi = pf->vsi[0];
/* We know that we have allocated only one vsi for this PF, *itwasjustforregisteringnetdevice,sotheinterface *couldbevisibleinthe'ifconfig'output
*/
unregister_netdev(vsi->netdev);
free_netdev(vsi->netdev);
goto unmap;
}
/* Client close must be called explicitly here because the timer *hasbeenstopped.
*/
i40e_notify_client_of_netdev_close(pf, false);
i40e_fdir_teardown(pf);
/* If there is a switch structure or any orphans, remove them. *ThiswillleaveonlythePF'sVSIremaining.
*/
i40e_pf_for_each_veb(pf, i, veb) if (veb->uplink_seid == pf->mac_seid ||
veb->uplink_seid == 0)
i40e_switch_branch_release(veb);
/* Now we can shutdown the PF's VSIs, just before we kill *adminqandhmc.
*/
i40e_pf_for_each_vsi(pf, i, vsi) {
i40e_vsi_close(vsi);
i40e_vsi_release(vsi);
pf->vsi[i] = NULL;
}
i40e_cloud_filter_exit(pf);
/* remove attached clients */ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
ret_code = i40e_lan_del_device(pf); if (ret_code)
dev_warn(&pdev->dev, "Failed to delete client device: %d\n",
ret_code);
}
/* shutdown and destroy the HMC */ if (hw->hmc.hmc_obj) {
ret_code = i40e_shutdown_lan_hmc(hw); if (ret_code)
dev_warn(&pdev->dev, "Failed to destroy the HMC resources: %d\n",
ret_code);
}
unmap: /* Free MSI/legacy interrupt 0 when in recovery mode. */ if (test_bit(__I40E_RECOVERY_MODE, pf->state) &&
!test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
free_irq(pf->pdev->irq, pf);
/* shutdown the adminq */
i40e_shutdown_adminq(hw);
/* destroy the locks only once, here */
mutex_destroy(&hw->aq.arq_mutex);
mutex_destroy(&hw->aq.asq_mutex);
/* Clear all dynamic memory lists of rings, q_vectors, and VSIs */
rtnl_lock();
i40e_clear_interrupt_scheme(pf);
i40e_pf_for_each_vsi(pf, i, vsi) { if (!test_bit(__I40E_RECOVERY_MODE, pf->state))
i40e_vsi_clear_rings(vsi);
/* Get current MAC address in case it's an LAA */ if (main_vsi && main_vsi->netdev) {
ether_addr_copy(mac_addr, main_vsi->netdev->dev_addr);
} else {
dev_err(&pf->pdev->dev, "Failed to retrieve MAC address; using default\n");
ether_addr_copy(mac_addr, hw->mac.addr);
}
/* The FW expects the mac address write cmd to first be called with *oneoftheseflagsbeforecallingitagainwiththemulticast *enableflags.
*/
flags = I40E_AQC_WRITE_TYPE_LAA_WOL;
if (hw->func_caps.flex10_enable && hw->partition_id != 1)
flags = I40E_AQC_WRITE_TYPE_LAA_ONLY;
ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL); if (ret) {
dev_err(&pf->pdev->dev, "Failed to update MAC address registers; cannot enable Multicast Magic packet wake up"); return;
}
flags = I40E_AQC_MC_MAG_EN
| I40E_AQC_WOL_PRESERVE_ON_PFR
| I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG;
ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL); if (ret)
dev_err(&pf->pdev->dev, "Failed to enable Multicast Magic Packet wake up\n");
}
/* Clear the interrupt scheme and release our IRQs so that the system *cansafelyhibernateevenwhentherearealargenumberofCPUs. *Otherwisehibernationmightfailwhenmappingallthevectorsback *toCPU0.
*/
i40e_clear_interrupt_scheme(pf);
/* We need to hold the RTNL lock prior to restoring interrupt schemes, *sincewe'regoingtoberestoringqueues
*/
rtnl_lock();
/* We cleared the interrupt scheme when we suspended, so we need to *restoreitnowtoresumedevicefunctionality.
*/
err = i40e_restore_interrupt_scheme(pf); if (err) {
dev_err(dev, "Cannot restore interrupt scheme: %d\n",
err);
}
/* Free MSI/legacy interrupt 0 when in recovery mode. */ if (test_bit(__I40E_RECOVERY_MODE, pf->state) &&
!test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
free_irq(pf->pdev->irq, pf);
/* Since we're going to destroy queues during the *i40e_clear_interrupt_scheme()weshouldholdtheRTNLlockforthis *wholesection
*/
rtnl_lock();
i40e_clear_interrupt_scheme(pf);
rtnl_unlock();
/* If we're already suspended, then there is nothing to do */ if (test_and_set_bit(__I40E_SUSPENDED, pf->state)) return0; return i40e_io_suspend(pf);
}
/* There is no need to throttle the number of active tasks because *eachdevicelimitsitsowntaskusingastatebitforscheduling *theservicetask,andthedevicetasksdonotinterferewitheach *other,sowedon'tsetamaxtasklimit.WemustsetWQ_MEM_RECLAIM *sinceweneedtobeabletoguaranteeforwardprogressevenunder *memorypressure.
*/
i40e_wq = alloc_workqueue("%s", 0, 0, i40e_driver_name); if (!i40e_wq) {
pr_err("%s: Failed to create workqueue\n", i40e_driver_name); return -ENOMEM;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.