The rte_pktmbuf_read method does not guarantee that data will be copied
from an mbuf. If the requested data is all contiguous, the method will
instead return a pointer to the memory location within the buffer that
should be read from, leaving the destination buffer empty.
This is problematic for TSO/multi-segment TX packets which only make use
of two mbufs. If all data in the second mbuf is contiguous, the data
will not be read to QPL memory.
Update the QPL copy logic to copy if the rte_pktmbuf_read does not.
Fixes: a46583cf43c8 ("net/gve: support Rx/Tx")
Cc: [email protected]
Signed-off-by: Joshua Washington <[email protected]>
Reviewed-by: Jasper Tran O'Leary <[email protected]>
---
drivers/net/gve/gve_tx.c | 34 ++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/drivers/net/gve/gve_tx.c b/drivers/net/gve/gve_tx.c
index 59c82b04ed..2f5a7b0a2e 100644
--- a/drivers/net/gve/gve_tx.c
+++ b/drivers/net/gve/gve_tx.c
@@ -273,6 +273,9 @@ gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts)
gve_tx_clean_swr_qpl(txq);
for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
+ const void *mbuf_header_addr;
+ void *qpl_write_addr;
+
tx_pkt = *tx_pkts++;
ol_flags = tx_pkt->ol_flags;
@@ -317,26 +320,33 @@ gve_tx_burst_qpl(void *tx_queue, struct rte_mbuf
**tx_pkts, uint16_t nb_pkts)
goto end_of_tx;
}
}
- if (tx_pkt->nb_segs == 1 || ol_flags & RTE_MBUF_F_TX_TCP_SEG)
- rte_memcpy((void *)(size_t)(fifo_addr + txq->fifo_base),
- (void *)(size_t)addr, hlen);
- else
- rte_pktmbuf_read(tx_pkt, 0, hlen,
- (void *)(size_t)(fifo_addr +
txq->fifo_base));
+
+ qpl_write_addr = (void *)(size_t)(fifo_addr + txq->fifo_base);
+ mbuf_header_addr = rte_pktmbuf_read(tx_pkt, 0, hlen,
qpl_write_addr);
+
+ /* Header data is linear in the mbuf head. Copy directly. */
+ if (mbuf_header_addr != qpl_write_addr)
+ rte_memcpy(qpl_write_addr, mbuf_header_addr, hlen);
+
gve_tx_fill_pkt_desc(txd, tx_pkt, nb_used, hlen, fifo_addr);
if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ const void *mbuf_payload_addr;
+
tx_id = (tx_id + 1) & mask;
txd = &txr[tx_id];
addr = (uint64_t)(tx_pkt->buf_addr) + tx_pkt->data_off
+ hlen;
fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id,
tx_pkt->pkt_len - hlen);
- if (tx_pkt->nb_segs == 1)
- rte_memcpy((void *)(size_t)(fifo_addr +
txq->fifo_base),
- (void *)(size_t)addr,
+ qpl_write_addr = (void *)(txq->fifo_base + fifo_addr);
+ mbuf_payload_addr = rte_pktmbuf_read(tx_pkt, hlen,
tx_pkt->pkt_len - hlen,
+ qpl_write_addr);
+
+ /* Payload data is contiguous. Take the offset from the
+ * read request and copy from there.
+ */
+ if (mbuf_payload_addr != qpl_write_addr)
+ rte_memcpy(qpl_write_addr, mbuf_payload_addr,
tx_pkt->pkt_len - hlen);
- else
- rte_pktmbuf_read(tx_pkt, hlen, tx_pkt->pkt_len
- hlen,
- (void *)(size_t)(fifo_addr +
txq->fifo_base));
gve_tx_fill_seg_desc(txd, ol_flags, tx_offload,
tx_pkt->pkt_len - hlen, fifo_addr);
--
2.55.0.rc0.799.gd6f94ed593-goog