/* In case lazy-allocation is allowed, postpone allocation until the *endoftheNAPIrun.We'dstillneedtomakesuretheRxringhas *sufficientbufferstoguaranteeanadditionalRxinterrupt.
*/ if (allow_lazy && likely(rxq->filled_buffers > 12)) {
rxq->filled_buffers--; return0;
}
data = alloc_pages(GFP_ATOMIC, 0); if (unlikely(!data)) return -ENOMEM;
/* Map the entire page as it would be used *formultipleRXbuffersegmentsizemapping.
*/
mapping = dma_map_page(rxq->dev, data, 0,
PAGE_SIZE, rxq->data_direction); if (unlikely(dma_mapping_error(rxq->dev, mapping))) {
__free_page(data); return -ENOMEM;
}
/* Unmap the data of the skb frags */ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, bds_consumed++) {
tx_data_bd = (struct eth_tx_bd *)
qed_chain_consume(&txq->tx_pbl);
dma_unmap_page(&edev->pdev->dev, BD_UNMAP_ADDR(tx_data_bd),
BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
}
while (bds_consumed++ < nbds)
qed_chain_consume(&txq->tx_pbl);
/* Unmap the data of the skb frags */ for (i = 0; i < nbd; i++) {
tx_data_bd = (struct eth_tx_bd *)
qed_chain_produce(&txq->tx_pbl); if (tx_data_bd->nbytes)
dma_unmap_page(txq->dev,
BD_UNMAP_ADDR(tx_data_bd),
BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
}
/* Return again prod to its position before this skb was handled */
qed_chain_set_prod(&txq->tx_pbl,
le16_to_cpu(txq->tx_db.data.bd_prod), first_bd);
staticinlinevoid qede_update_tx_producer(struct qede_tx_queue *txq)
{ /* wmb makes sure that the BDs data is updated before updating the *producer,otherwiseFWmayreadolddatafromtheBDs.
*/
wmb();
barrier();
writel(txq->tx_db.raw, txq->doorbell_addr);
/* Fence required to flush the write combined buffer, since another *CPUmaywritetothesamedoorbelladdressanddatamaybelost *duetorelaxedordernatureofwritecombinedbar.
*/
wmb();
}
/* Need to make the tx_bd_cons update visible to start_xmit() *beforecheckingfornetif_tx_queue_stopped().Withoutthe *memorybarrier,thereisasmallpossibilitythat *start_xmit()willmissitandcausethequeuetobestopped *forever. *Ontheotherhandweneedanrmb()heretoensuretheproper *orderingofbittestinginthefollowing *netif_tx_queue_stopped(txq)call.
*/
smp_mb();
if (unlikely(netif_tx_queue_stopped(netdev_txq))) { /* Taking tx_lock is needed to prevent reenabling the queue *whileit'sempty.Thiscouldhavehappenifrx_action()gets *suspendedinqede_tx_int()aftertheconditionbefore *netif_tx_wake_queue(),whiletx_action(qede_start_xmit()): * *stopsthequeue->seesfreshtx_bd_cons->releasesthequeue-> *sendssomepacketsconsumingthewholequeueagain-> *stopsthequeue
*/
staticinlineint qede_realloc_rx_buffer(struct qede_rx_queue *rxq, struct sw_rx_data *curr_cons)
{ /* Move to the next segment in the page */
curr_cons->page_offset += rxq->rx_buf_seg_size;
if (curr_cons->page_offset == PAGE_SIZE) { if (unlikely(qede_alloc_rx_buffer(rxq, true))) { /* Since we failed to allocate new buffer *currentbuffercanbeusedagain.
*/
curr_cons->page_offset -= rxq->rx_buf_seg_size;
return -ENOMEM;
}
dma_unmap_page(rxq->dev, curr_cons->mapping,
PAGE_SIZE, rxq->data_direction);
} else { /* Increment refcount of the page as we don't want *networkstacktotaketheownershipofthepage *whichcanberecycledmultipletimesbythedriver.
*/
page_ref_inc(curr_cons->data);
qede_reuse_page(rxq, curr_cons);
}
if (unlikely(tpa_info->state != QEDE_AGG_STATE_START)) goto out;
/* Add one frag and update the appropriate fields in the skb */
skb_fill_page_desc(skb, tpa_info->frag_id++,
current_bd->data,
current_bd->page_offset + rxq->rx_headroom,
len_on_bd);
if (unlikely(qede_realloc_rx_buffer(rxq, current_bd))) { /* Incr page ref count to reuse on allocation failure *sothatitdoesn'tgetfreedwhilefreeingSKB.
*/
page_ref_inc(current_bd->data); goto out;
}
/* For smaller frames still need to allocate skb, memcpy *dataandbenefitinreusingthepagesegmentinsteadof *un-mappingit.
*/ if ((len + pad <= edev->rx_copybreak)) { unsignedint offset = bd->page_offset + pad;
skb = netdev_alloc_skb(edev->ndev, QEDE_RX_HDR_SIZE); if (unlikely(!skb)) return NULL;
if (unlikely(qede_realloc_rx_buffer(rxq, bd))) { /* Incr page ref count to reuse on allocation failure so *thatitdoesn'tgetfreedwhilefreeingSKB[asits *alreadymappedthere].
*/
page_ref_inc(bd->data);
dev_kfree_skb_any(skb); return NULL;
}
out: /* We've consumed the first BD and prepared an SKB */
qede_rx_bd_ring_consume(rxq);
if (unlikely(!tpa_info->skb)) {
DP_NOTICE(edev, "Failed to allocate SKB for gro\n");
/* Consume from ring but do not produce since *thismightbeusedbyFWstill,itwillbere-used *atTPAend.
*/
tpa_info->tpa_start_fail = true;
qede_rx_bd_ring_consume(rxq);
tpa_info->state = QEDE_AGG_STATE_ERROR; goto cons_buf;
}
/* This is needed in order to enable forwarding support */
qede_set_gro_params(edev, tpa_info->skb, cqe);
cons_buf: /* We still need to handle bd_len_list to consume buffers */ if (likely(cqe->bw_ext_bd_len_list[0]))
qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
le16_to_cpu(cqe->bw_ext_bd_len_list[0]));
if (unlikely(cqe->bw_ext_bd_len_list[1])) {
DP_ERR(edev, "Unlikely - got a TPA aggregation with more than one bw_ext_bd_len_list entry in the TPA start\n");
tpa_info->state = QEDE_AGG_STATE_ERROR;
}
}
if (tpa_info->buffer.page_offset == PAGE_SIZE)
dma_unmap_page(rxq->dev, tpa_info->buffer.mapping,
PAGE_SIZE, rxq->data_direction);
for (i = 0; cqe->len_list[i]; i++)
qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
le16_to_cpu(cqe->len_list[i])); if (unlikely(i > 1))
DP_ERR(edev, "Strange - TPA emd with more than a single len_list entry\n");
if (unlikely(tpa_info->state != QEDE_AGG_STATE_START)) goto err;
/* Sanity */ if (unlikely(cqe->num_of_bds != tpa_info->frag_id + 1))
DP_ERR(edev, "Strange - TPA had %02x BDs, but SKB has only %d frags\n",
cqe->num_of_bds, tpa_info->frag_id); if (unlikely(skb->len != le16_to_cpu(cqe->total_packet_len)))
DP_ERR(edev, "Strange - total packet len [cqe] is %4x but SKB has len %04x\n",
le16_to_cpu(cqe->total_packet_len), skb->len);
/* Recalculate, as XDP might have changed the headers */
*data_offset = xdp.data - xdp.data_hard_start;
*len = xdp.data_end - xdp.data;
if (act == XDP_PASS) returntrue;
/* Count number of packets not to be passed to stack */
rxq->xdp_no_pass++;
switch (act) { case XDP_TX: /* We need the replacement buffer before transmit. */ if (unlikely(qede_alloc_rx_buffer(rxq, true))) {
qede_recycle_rx_bd_ring(rxq, 1);
/* Now if there's a transmission problem, we'd still have to *throwcurrentbuffer,asreplacementwasalreadyallocated.
*/ if (unlikely(qede_xdp_xmit(fp->xdp_tx, bd->mapping,
*data_offset, *len, bd->data,
NULL))) {
dma_unmap_page(rxq->dev, bd->mapping, PAGE_SIZE,
rxq->data_direction);
__free_page(bd->data);
/* Regardless, we've consumed an Rx BD */
qede_rx_bd_ring_consume(rxq); break; case XDP_REDIRECT: /* We need the replacement buffer before transmit. */ if (unlikely(qede_alloc_rx_buffer(rxq, true))) {
qede_recycle_rx_bd_ring(rxq, 1);
/* We've already used one BD for the SKB. Now take care of the rest */ for (num_frags = cqe->bd_num - 1; num_frags > 0; num_frags--) {
u16 cur_size = pkt_len > rxq->rx_buf_size ? rxq->rx_buf_size :
pkt_len;
if (unlikely(!cur_size)) {
DP_ERR(edev, "Still got %d BDs for mapping jumbo, but length became 0\n",
num_frags); goto out;
}
/* We need a replacement buffer for each BD */ if (unlikely(qede_alloc_rx_buffer(rxq, true))) goto out;
/* Now that we've allocated the replacement buffer, *wecansafelyconsumethenextBDandmapittotheSKB.
*/
bd_cons_idx = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
bd = &rxq->sw_rx_ring[bd_cons_idx];
qede_rx_bd_ring_consume(rxq);
/* Get the data from the SW ring; Consume it only after it's evident *wewouldn'trecycleit.
*/
bd_cons_idx = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
bd = &rxq->sw_rx_ring[bd_cons_idx];
fp_cqe = &cqe->fast_path_regular;
len = le16_to_cpu(fp_cqe->len_on_first_bd);
pad = fp_cqe->placement_offset + rxq->rx_headroom;
/* Run eBPF program if one is attached */ if (xdp_prog) if (!qede_rx_xdp(edev, fp, rxq, xdp_prog, bd, fp_cqe,
&pad, &len)) return0;
/* If this is an error packet then drop it */
flags = cqe->fast_path_regular.pars_flags.flags;
parse_flag = le16_to_cpu(flags);
csum_flag = qede_check_csum(parse_flag); if (unlikely(csum_flag == QEDE_CSUM_ERROR)) { if (qede_pkt_is_ip_fragmented(fp_cqe, parse_flag))
rxq->rx_ip_frags++; else
rxq->rx_hw_errors++;
}
/* Basic validation passed; Need to prepare an SKB. This would also *guaranteetofinallyconsumethefirstBDuponsuccess.
*/
skb = qede_rx_build_skb(edev, rxq, bd, len, pad); if (!skb) {
rxq->rx_alloc_errors++;
qede_recycle_rx_bd_ring(rxq, fp_cqe->bd_num); return0;
}
/* In case of Jumbo packet, several PAGE_SIZEd buffers will be pointed *byasinglecqe.
*/ if (fp_cqe->bd_num > 1) {
u16 unmapped_frags = qede_rx_build_jumbo(edev, rxq, skb,
fp_cqe, len);
/* Memory barrier to prevent the CPU from doing speculative reads of CQE */BDinthewhile-loopbeforereadinghw_comp_cons.IftheCQEis *readbeforeitiswrittenbyFW,thenFWwritesCQEandSB,andthen *theCPUreadsthehw_comp_cons,itwilluseanoldCQE.
*/
rmb();
/* Loop to complete all indicated BDs */ while ((sw_comp_cons != hw_comp_cons) && (work_done < budget)) {
rcv_pkts += qede_rx_process_cqe(edev, fp, rxq);
qed_chain_recycle_consumed(&rxq->rx_comp_ring);
sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring);
work_done++;
}
rxq->rcv_pkts += rcv_pkts;
/* Allocate replacement buffers */ while (rxq->num_rx_buffers - rxq->filled_buffers) if (qede_alloc_rx_buffer(rxq, false)) break;
/* *_has_*_work() reads the status block, thus we need to ensure that *statusblockindiceshavebeenactuallyread(qed_sb_update_sb_idx) *priortothischeck(*_has_*_work)sothatwewon'twritethe *"newer"valueofthestatusblocktoHW(iftherewasaDMAright *afterqede_has_rx_workandifthereisnormb,thememoryreading *(qed_sb_update_sb_idx)maybepostponedtorightbefore*_ack_sb). *Inthiscasetherewillneverbeanotherinterruptuntilthereis *anotherupdateofthestatusblock,whilethereisstillunhandled *work.
*/
rmb();
if (likely(fp->type & QEDE_FASTPATH_RX)) if (qede_has_rx_work(fp->rxq)) returntrue;
if (fp->type & QEDE_FASTPATH_XDP) if (qede_txq_has_work(fp->xdp_tx)) returntrue;
if (likely(fp->type & QEDE_FASTPATH_TX)) { int cos;
for_each_cos_in_txq(fp->edev, cos) { if (qede_txq_has_work(&fp->txq[cos])) returntrue;
}
}
returnfalse;
}
/********************* *NDO&APIrelated*
*********************/ int qede_poll(struct napi_struct *napi, int budget)
{ struct qede_fastpath *fp = container_of(napi, struct qede_fastpath,
napi); struct qede_dev *edev = fp->edev; int rx_work_done = 0;
u16 xdp_prod;
fp->xdp_xmit = 0;
if (likely(fp->type & QEDE_FASTPATH_TX)) { int cos;
for_each_cos_in_txq(fp->edev, cos) { if (qede_txq_has_work(&fp->txq[cos]))
qede_tx_int(edev, &fp->txq[cos]);
}
}
if ((fp->type & QEDE_FASTPATH_XDP) && qede_txq_has_work(fp->xdp_tx))
qede_xdp_tx_int(edev, fp->xdp_tx);
if (fp->xdp_xmit & QEDE_XDP_REDIRECT)
xdp_do_flush();
/* Handle case where we are called by netpoll with a budget of 0 */ if (rx_work_done < budget || !budget) { if (!qede_poll_is_more_work(fp)) {
napi_complete_done(napi, rx_work_done);
/* Fill the entry in the SW ring and the BDs in the FW ring */
idx = txq->sw_tx_prod;
txq->sw_tx_ring.skbs[idx].skb = skb;
first_bd = (struct eth_tx_1st_bd *)
qed_chain_produce(&txq->tx_pbl);
memset(first_bd, 0, sizeof(*first_bd));
first_bd->data.bd_flags.bitfields = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT;
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
qede_ptp_tx_ts(edev, skb);
/* Map skb linear data for DMA and set in the first BD */
mapping = dma_map_single(txq->dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE); if (unlikely(dma_mapping_error(txq->dev, mapping))) {
DP_NOTICE(edev, "SKB mapping failed\n");
qede_free_failed_tx_pkt(txq, first_bd, 0, false);
qede_update_tx_producer(txq); return NETDEV_TX_OK;
}
nbd++;
BD_SET_UNMAP_ADDR_LEN(first_bd, mapping, skb_headlen(skb));
/* In case there is IPv6 with extension headers or LSO we need 2nd and *3rdBDs.
*/ if (unlikely((xmit_type & XMIT_LSO) | ipv6_ext)) {
second_bd = (struct eth_tx_2nd_bd *)
qed_chain_produce(&txq->tx_pbl);
memset(second_bd, 0, sizeof(*second_bd));
/* Fill the parsing flags & params according to the requested offload */ if (xmit_type & XMIT_L4_CSUM) { /* We don't re-calculate IP checksum as it is already done by *theupperstack
*/
first_bd->data.bd_flags.bitfields |= 1 << ETH_TX_1ST_BD_FLAGS_L4_CSUM_SHIFT;
if (xmit_type & XMIT_ENC) {
first_bd->data.bd_flags.bitfields |= 1 << ETH_TX_1ST_BD_FLAGS_IP_CSUM_SHIFT;
val |= (1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT);
}
/* Legacy FW had flipped behavior in regard to this bit - *I.e.,neededtosettopreventFWfromtouchingencapsulated *packetswhenitdidn'tneedto.
*/ if (unlikely(txq->is_legacy))
val ^= (1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT);
/* If the packet is IPv6 with extension header, indicate that *toFWandpassfewparams,sincethedevicecrackerdoesn't *supportparsingIPv6withextensionheader/s.
*/ if (unlikely(ipv6_ext))
qede_set_params_for_ipv6_ext(skb, second_bd, third_bd);
}
/* @@@TBD - if will not be removed need to check */
third_bd->data.bitfields |=
cpu_to_le16(1 << ETH_TX_DATA_3RD_BD_HDR_NBD_SHIFT);
/* Make life easier for FW guys who can't deal with header and *dataonsameBD.Ifweneedtosplit,usethesecondbd...
*/ if (unlikely(skb_headlen(skb) > hlen)) {
DP_VERBOSE(edev, NETIF_MSG_TX_QUEUED, "TSO split header size is %d (%x:%x)\n",
first_bd->nbytes, first_bd->addr.hi,
first_bd->addr.lo);
/* update the first BD with the actual num BDs */
first_bd->data.nbds = nbd;
netdev_tx_sent_queue(netdev_txq, skb->len);
skb_tx_timestamp(skb);
/* Advance packet producer only before sending the packet since mapping *ofpagesmayfail.
*/
txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers;
/* 'next page' entries are counted in the producer value */
txq->tx_db.data.bd_prod =
cpu_to_le16(qed_chain_get_prod_idx(&txq->tx_pbl));
if (!netdev_xmit_more() || netif_xmit_stopped(netdev_txq))
qede_update_tx_producer(txq);
if (unlikely(qed_chain_get_elem_left(&txq->tx_pbl)
< (MAX_SKB_FRAGS + 1))) { if (netdev_xmit_more())
qede_update_tx_producer(txq);
netif_tx_stop_queue(netdev_txq);
txq->stopped_cnt++;
DP_VERBOSE(edev, NETIF_MSG_TX_QUEUED, "Stop queue was called\n"); /* paired memory barrier is in qede_tx_int(), we have to keep *orderingofset_bit()innetif_tx_stop_queue()andreadof *fp->bd_tx_cons
*/
smp_mb();
if ((qed_chain_get_elem_left(&txq->tx_pbl) >=
(MAX_SKB_FRAGS + 1)) &&
(edev->state == QEDE_STATE_OPEN)) {
netif_tx_wake_queue(netdev_txq);
DP_VERBOSE(edev, NETIF_MSG_TX_QUEUED, "Wake queue was called\n");
}
}
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.