mutex_lock(&adapter->vector_lock);
min_vec = adapter->num_msix_entries - adapter->num_avail_msix;
stack = &adapter->vector_stack;
stack->size = adapter->num_msix_entries; /* set the base and top to point at start of the 'free pool' to *distributetheunusedvectorson-demandbasis
*/
stack->base = min_vec;
stack->top = min_vec;
stack->vec_idx = kcalloc(stack->size, sizeof(u16), GFP_KERNEL); if (!stack->vec_idx) {
mutex_unlock(&adapter->vector_lock);
return -ENOMEM;
}
for (i = 0; i < stack->size; i++)
stack->vec_idx[i] = i;
if (stack->top == stack->size) {
dev_err(&adapter->pdev->dev, "No interrupt vectors are available to distribute!\n");
return -EINVAL;
}
return stack->vec_idx[stack->top++];
}
/** *idpf_vector_stash-Storethevectorindexesontothestack *@adapter:privatedatastruct *@q_vector_idxs:vectorindexarray *@vec_info:inforelatedtothenumberofvectors * *Thisfunctionisano-opiftherearenovectorsindexestobestashed
*/ staticvoid idpf_vector_stash(struct idpf_adapter *adapter, u16 *q_vector_idxs, struct idpf_vector_info *vec_info)
{ int i, base = 0;
u16 vec_idx;
lockdep_assert_held(&adapter->vector_lock);
if (!vec_info->num_curr_vecs) return;
/* For default vports, no need to stash vector allocated from the *defaultpoolontothestack
*/ if (vec_info->default_vport)
base = IDPF_MIN_Q_VEC;
for (i = vec_info->num_curr_vecs - 1; i >= base ; i--) {
vec_idx = q_vector_idxs[i];
idpf_vector_lifo_push(adapter, vec_idx);
adapter->num_avail_msix++;
}
}
/* Stash interrupt vector indexes onto the stack if required */
idpf_vector_stash(adapter, q_vector_idxs, vec_info);
if (!num_req_vecs) goto rel_lock;
if (vec_info->default_vport) { /* As IDPF_MIN_Q_VEC per default vport is put aside in the *defaultpoolofthestack,usethemfordefaultvports
*/
j = vec_info->index * IDPF_MIN_Q_VEC + IDPF_MBX_Q_VEC; for (i = 0; i < IDPF_MIN_Q_VEC; i++) {
q_vector_idxs[num_alloc_vecs++] = stack->vec_idx[j++];
num_req_vecs--;
}
}
/* Find if stack has enough vector to allocate */
max_vecs = min(adapter->num_avail_msix, num_req_vecs);
if (idpf_is_rdma_cap_ena(adapter)) { if (actual_vecs < total_vecs) {
dev_warn(&adapter->pdev->dev, "Warning: %d vectors requested, only %d available. Defaulting to minimum (%d) for RDMA and remaining for LAN.\n",
total_vecs, actual_vecs, IDPF_MIN_RDMA_VEC);
num_rdma_vecs = IDPF_MIN_RDMA_VEC;
}
for (vector = 0; vector < num_lan_vecs; vector++) {
adapter->msix_entries[vector].entry = vecids[vector];
adapter->msix_entries[vector].vector =
pci_irq_vector(adapter->pdev, vector);
} for (i = 0; i < num_rdma_vecs; vector++, i++) {
adapter->rdma_msix_entries[i].entry = vecids[vector];
adapter->rdma_msix_entries[i].vector =
pci_irq_vector(adapter->pdev, vector);
}
/* 'num_avail_msix' is used to distribute excess vectors to the vports *afterconsideringtheminimumvectorsrequiredpereachdefault *vport
*/
adapter->num_avail_msix = num_lan_vecs - min_lan_vecs;
adapter->num_msix_entries = num_lan_vecs; if (idpf_is_rdma_cap_ena(adapter))
adapter->num_rdma_msix_entries = num_rdma_vecs;
/* Fill MSIX vector lifo stack with vector indexes */
err = idpf_init_vector_stack(adapter); if (err) goto free_vecids;
err = idpf_mb_intr_init(adapter); if (err) goto deinit_vec_stack;
idpf_mb_irq_enable(adapter);
kfree(vecids);
if (!idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS,
VIRTCHNL2_CAP_MACFILTER)) {
dev_err(&adapter->pdev->dev, "MAC address is not provided and capability is not set\n");
dev_info(&adapter->pdev->dev, "Invalid MAC address %pM, using random %pM\n",
vport->default_mac_addr, netdev->dev_addr);
ether_addr_copy(vport->default_mac_addr, netdev->dev_addr);
idpf_send_disable_vport_msg(vport);
idpf_send_disable_queues_msg(vport);
idpf_send_map_unmap_queue_vector_msg(vport, false); /* Normally we ask for queues in create_vport, but if the number of *initiallyrequestedqueueshavechanged,forexampleviaethtool *setchannels,wedodeletequeuesandthenaddthequeuesback *insteadofdeletingandreallocatingthevport.
*/ if (test_and_clear_bit(IDPF_VPORT_DEL_QUEUES, vport->flags))
idpf_send_delete_queues_msg(vport);
/* Release all max queues allocated to the adapter's pool */
max_q.max_rxq = vport_config->max_q.max_rxq;
max_q.max_txq = vport_config->max_q.max_txq;
max_q.max_bufq = vport_config->max_q.max_bufq;
max_q.max_complq = vport_config->max_q.max_complq;
idpf_vport_dealloc_max_qs(adapter, &max_q);
/* Release all the allocated vectors on the stack */
vec_info.num_req_vecs = 0;
vec_info.num_curr_vecs = vport->num_q_vectors;
vec_info.default_vport = vport->default_vport;
if (!test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags))
idpf_decfg_netdev(vport); if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags))
idpf_del_all_mac_filters(vport);
if (adapter->netdevs[i]) { struct idpf_netdev_priv *np = netdev_priv(adapter->netdevs[i]);
switch (val) { case ETHTOOL_TCP_DATA_SPLIT_UNKNOWN: /* Default is to enable */ case ETHTOOL_TCP_DATA_SPLIT_ENABLED:
__set_bit(__IDPF_USER_FLAG_HSPLIT, config->user_flags); returntrue; case ETHTOOL_TCP_DATA_SPLIT_DISABLED:
__clear_bit(__IDPF_USER_FLAG_HSPLIT, config->user_flags); returntrue; default: returnfalse;
}
}
vport->q_vector_idxs = kcalloc(num_max_q, sizeof(u16), GFP_KERNEL); if (!vport->q_vector_idxs) goto free_vport;
idpf_vport_init(vport, max_q);
/* This alloc is done separate from the LUT because it's not strictly *dependentonhowmanyqueueswehave.Ifwechangenumberofqueues *andsoftresetwe'llneedanewLUTbutthekeycanremainthesame *foraslongasthevportexists.
*/
rss_data = &adapter->vport_config[idx]->user_config.rss_data;
rss_data->rss_key = kzalloc(rss_data->rss_key_size, GFP_KERNEL); if (!rss_data->rss_key) goto free_vector_idxs;
err = idpf_check_supported_desc_ids(vport); if (err) {
dev_err(&pdev->dev, "failed to get required descriptor ids\n"); goto cfg_netdev_err;
}
if (idpf_cfg_netdev(vport)) goto cfg_netdev_err;
err = idpf_send_get_rx_ptype_msg(vport); if (err) goto handle_err;
/* Once state is put into DOWN, driver is ready for dev_open */
np = netdev_priv(vport->netdev);
np->state = __IDPF_VPORT_DOWN; if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, vport_config->flags))
idpf_vport_open(vport, true);
/* Spawn and return 'idpf_init_task' work queue until all the *defaultvportsarecreated
*/ if (adapter->num_alloc_vports < num_default_vports) {
queue_delayed_work(adapter->init_wq, &adapter->init_task,
msecs_to_jiffies(5 * (adapter->pdev->devfn & 0x07)));
return;
}
for (index = 0; index < adapter->max_vports; index++) { struct net_device *netdev = adapter->netdevs[index]; struct idpf_vport_config *vport_config;
vport_config = adapter->vport_config[index];
if (!netdev ||
test_bit(IDPF_VPORT_REG_NETDEV, vport_config->flags)) continue;
err = register_netdev(netdev); if (err) {
dev_err(&pdev->dev, "failed to register netdev for vport %d: %pe\n",
index, ERR_PTR(err)); continue;
}
set_bit(IDPF_VPORT_REG_NETDEV, vport_config->flags);
}
/* As all the required vports are created, clear the reset flag *unconditionallyhereincasewewereinresetandthelinkwasdown.
*/
clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags); /* Start the statistics task now */
queue_delayed_work(adapter->stats_wq, &adapter->stats_task,
msecs_to_jiffies(10 * (pdev->devfn & 0x07)));
return;
handle_err:
idpf_decfg_netdev(vport);
cfg_netdev_err:
idpf_vport_rel(vport);
adapter->vports[index] = NULL;
unwind_vports: if (default_vport) { for (index = 0; index < adapter->max_vports; index++) { if (adapter->vports[index])
idpf_vport_dealloc(adapter->vports[index]);
}
}
clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
}
/** *idpf_sriov_ena-EnableorchangenumberofVFs *@adapter:privatedatastruct *@num_vfs:numberofVFstoallocate
*/ staticint idpf_sriov_ena(struct idpf_adapter *adapter, int num_vfs)
{ struct device *dev = &adapter->pdev->dev; int err;
err = idpf_send_set_sriov_vfs_msg(adapter, num_vfs); if (err) {
dev_err(dev, "Failed to allocate VFs: %d\n", err);
return err;
}
err = pci_enable_sriov(adapter->pdev, num_vfs); if (err) {
idpf_send_set_sriov_vfs_msg(adapter, 0);
dev_err(dev, "Failed to enable SR-IOV: %d\n", err);
return err;
}
adapter->num_vfs = num_vfs;
return num_vfs;
}
/** *idpf_sriov_configure-ConfiguretherequestedVFs *@pdev:pointertoapci_devstructure *@num_vfs:numberofvfstoallocate * *EnableorchangethenumberofVFs.Calledwhentheuserupdatesthenumber *ofVFsinsysfs.
**/ int idpf_sriov_configure(struct pci_dev *pdev, int num_vfs)
{ struct idpf_adapter *adapter = pci_get_drvdata(pdev);
if (!idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_SRIOV)) {
dev_info(&pdev->dev, "SR-IOV is not supported on this device\n");
return -EOPNOTSUPP;
}
if (num_vfs) return idpf_sriov_ena(adapter, num_vfs);
if (pci_vfs_assigned(pdev)) {
dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs\n");
/* Wait until the init_task is done else this thread might release *theresourcesfirstandtheotherthreadmightendupinabadstate
*/
cancel_delayed_work_sync(&adapter->init_task);
if (!adapter->vports) return;
cancel_delayed_work_sync(&adapter->stats_task);
for (i = 0; i < adapter->max_vports; i++) { if (adapter->vports[i])
idpf_vport_dealloc(adapter->vports[i]);
}
}
for (i = 0; i < 2000; i++) {
u32 reg_val = readl(reset_reg->rstat);
/* 0xFFFFFFFF might be read if other side hasn't cleared the *registerforusyetand0xFFFFFFFFisnotavalidvaluefor *theregister,sotreatthatasinvalid.
*/ if (reg_val != 0xFFFFFFFF && (reg_val & reset_reg->rstat_m)) return0;
usleep_range(5000, 10000);
}
dev_warn(&adapter->pdev->dev, "Device reset timeout!\n"); /* Clear the reset flag unconditionally here since the reset *technicallyisn'tinprogressanymorefromthedriver'sperspective
*/
clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
/* Wait for reset to complete */
err = idpf_check_reset_complete(&adapter->hw, &adapter->reset_reg); if (err) {
dev_err(dev, "The driver was unable to contact the device's firmware. Check that the FW is running. Driver state= 0x%x\n",
adapter->state); goto unlock_mutex;
}
/* Reset is complete and so start building the driver resources again */
err = idpf_init_dflt_mbx(adapter); if (err) {
dev_err(dev, "Failed to initialize default mailbox: %d\n", err); goto unlock_mutex;
}
/* Initialize the state machine, also allocate memory and request *resources
*/
err = idpf_vc_core_init(adapter); if (err) {
cancel_delayed_work_sync(&adapter->mbx_task);
idpf_deinit_dflt_mbx(adapter); goto unlock_mutex;
}
/* Wait till all the vports are initialized to release the reset lock, *elseuserspacecallbacksmayaccessuninitializedvports
*/ while (test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags))
msleep(100);
/* If the system is low on memory, we can end up in bad state if we *freeallthememoryforqueueresourcesandtrytoallocatethem *again.Instead,wecanpre-allocatethenewresourcesbeforedoing *anythingandbailingiftheallocfails. * *Makeacloneoftheexistingvporttomimicitscurrent *configuration,thenmodifythenewstructurewithanyrequested *changes.Oncetheallocationofthenewresourcesisdone,stopthe *existingvportandcopytheconfigurationtothemainvport.Ifan *erroroccurred,theexistingvportwillbeuntouched. *
*/
new_vport = kzalloc(sizeof(*vport), GFP_KERNEL); if (!new_vport) return -ENOMEM;
/* This purposely avoids copying the end of the struct because it *containswait_queuesandmutexesandotherstuffwedon'twantto *messwith.Nothingbelowshouldusethosevariablesfromnew_vport *andshouldinsteadalwaysrefertotheminvportiftheyneedto.
*/
memcpy(new_vport, vport, offsetof(struct idpf_vport, link_up));
/* Adjust resource parameters prior to reallocating resources */ switch (reset_cause) { case IDPF_SR_Q_CHANGE:
err = idpf_vport_adjust_qs(new_vport); if (err) goto free_vport; break; case IDPF_SR_Q_DESC_CHANGE: /* Update queue parameters before allocating resources */
idpf_vport_calc_num_q_desc(new_vport); break; case IDPF_SR_MTU_CHANGE:
idpf_idc_vdev_mtu_event(vport->vdev_info,
IIDC_RDMA_EVENT_BEFORE_MTU_CHANGE); break; case IDPF_SR_RSC_CHANGE: break; default:
dev_err(&adapter->pdev->dev, "Unhandled soft reset cause\n");
err = -EINVAL; goto free_vport;
}
idpf_deinit_rss(vport); /* We're passing in vport here because we need its wait_queue *tosendamessageanditshouldbegettingallthevport *configdataoutoftheadapterbutweneedtobecarefulnot *toaddcodetoadd_queuestochangethevportconfigwithin *vportitselfasitwillbewipedwithamemcpylater.
*/
err = idpf_send_add_queues_msg(vport, new_vport->num_txq,
new_vport->num_complq,
new_vport->num_rxq,
new_vport->num_bufq); if (err) goto err_reset;
/* Same comment as above regarding avoiding copying the wait_queues and *mutexesapplieshere.Wedonotwanttomesswiththoseifpossible.
*/
memcpy(vport, new_vport, offsetof(struct idpf_vport, link_up));
if (reset_cause == IDPF_SR_Q_CHANGE)
idpf_vport_alloc_vec_indexes(vport);
err = idpf_set_real_num_queues(vport); if (err) goto err_open;
if (current_state == __IDPF_VPORT_UP)
err = idpf_vport_open(vport, false);
/* Under some circumstances, we might receive a request to delete *ourowndeviceaddressfromouruclist.Becausewestorethe *deviceaddressintheVSI'sMACfilterlist,weneedtoignore *suchrequestsandnotdeleteourdeviceaddressfromthislist.
*/ if (ether_addr_equal(addr, netdev->dev_addr)) return0;
if (ena) { /* This will contain the default or user configured LUT */
memcpy(rss_data->rss_lut, rss_data->cached_lut, lut_size);
} else { /* Save a copy of the current LUT to be restored later if *requested.
*/
memcpy(rss_data->cached_lut, rss_data->rss_lut, lut_size);
/* Zero out the current LUT to disable */
memset(rss_data->rss_lut, 0, lut_size);
}
/* no need to check if number of frags is less than max_bufs - 1 */
nr_frags = shinfo->nr_frags; if (nr_frags < (max_bufs - 1)) returnfalse;
/* We need to walk through the list and validate that each group *ofmax_bufs-2fragmentstotalsatleastgso_size.
*/
nr_frags -= max_bufs - 2;
frag = &shinfo->frags[0];
/* Initialize size to the negative value of gso_size minus 1. We use *thisastheworstcasescenarioinwhichthefragaheadofusonly *providesonebytewhichiswhywearelimitedtomax_bufs-2 *descriptorsforasingletransmitastheheaderandprevious *fragmentarealreadyconsuming2descriptors.
*/
sum = 1 - shinfo->gso_size;
/* Add size of frags 0 through 4 to create our initial sum */
sum += skb_frag_size(frag++);
sum += skb_frag_size(frag++);
sum += skb_frag_size(frag++);
sum += skb_frag_size(frag++);
sum += skb_frag_size(frag++);
/* Walk through fragments adding latest fragment, testing it, and *thenremovingstalefragmentsfromthesum.
*/ for (stale = &shinfo->frags[0];; stale++) { int stale_size = skb_frag_size(stale);
sum += skb_frag_size(frag++);
/* The stale fragment may present us with a smaller *descriptorthantheactualfragmentsize.Toaccount *forthatweneedtoremoveallthedataonthefrontand *figureoutwhattheremainderwouldbeinthelast *descriptorassociatedwiththefragment.
*/ if (stale_size > IDPF_TX_MAX_DESC_DATA) { int align_pad = -(skb_frag_off(stale)) &
(IDPF_TX_MAX_READ_REQ_SIZE - 1);
sum -= align_pad;
stale_size -= align_pad;
do {
sum -= IDPF_TX_MAX_DESC_DATA_ALIGNED;
stale_size -= IDPF_TX_MAX_DESC_DATA_ALIGNED;
} while (stale_size > IDPF_TX_MAX_DESC_DATA);
}
/* if sum is negative we failed to make sufficient progress */ if (sum < 0) returntrue;
/* 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;
if (skb_is_gso(skb)) { /* We cannot support GSO if the MSS is going to be less than *88bytes.IfitisthenweneedtodropsupportforGSO.
*/ if (skb_shinfo(skb)->gso_size < IDPF_TX_TSO_MIN_MSS)
features &= ~NETIF_F_GSO_MASK; elseif (idpf_chk_tso_segment(skb, np->tx_max_bufs))
features &= ~NETIF_F_GSO_MASK;
}
/* Ensure MACLEN is <= 126 bytes (63 words) and not an odd size */
len = skb_network_offset(skb); if (unlikely(len & ~(126))) goto unsupported;
len = skb_network_header_len(skb); if (unlikely(len > max_tx_hdr_size)) goto unsupported;
if (!skb->encapsulation) return features;
/* L4TUNLEN can support 127 words */
len = skb_inner_network_header(skb) - skb_transport_header(skb); if (unlikely(len & ~(127 * 2))) goto unsupported;
/* IPLEN can support at most 127 dwords */
len = skb_inner_network_header_len(skb); if (unlikely(len > max_tx_hdr_size)) goto unsupported;
/* No need to validate L4LEN as TCP is the only protocol with a *aflexiblevalueandwesupportallpossiblevaluessupported *byTCP,whichisatmost15dwords
*/
return features;
unsupported: return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
}
if (!idpf_is_cap_ena(vport->adapter, IDPF_OTHER_CAPS,
VIRTCHNL2_CAP_MACFILTER)) {
dev_info(&vport->adapter->pdev->dev, "Setting MAC address is not supported\n");
err = -EOPNOTSUPP; goto unlock_mutex;
}
if (!is_valid_ether_addr(addr->sa_data)) {
dev_info(&vport->adapter->pdev->dev, "Invalid MAC address: %pM\n",
addr->sa_data);
err = -EADDRNOTAVAIL; goto unlock_mutex;
}
if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) goto unlock_mutex;
/* The control queue resources are freed under a spinlock, contiguous *pageswillavoidIOMMUremappingandtheusevmap(andvunmapin *dma_free_*()path.
*/
mem->va = dma_alloc_attrs(&adapter->pdev->dev, sz, &mem->pa,
GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS);
mem->size = sz;
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.