xref: /freebsd/sys/dev/gve/gve_tx_dqo.c (revision 46fce000843215ff3d574d1c24fc24771975973e)
1d438b4efSShailend Chand /*-
2d438b4efSShailend Chand  * SPDX-License-Identifier: BSD-3-Clause
3d438b4efSShailend Chand  *
4d438b4efSShailend Chand  * Copyright (c) 2024 Google LLC
5d438b4efSShailend Chand  *
6d438b4efSShailend Chand  * Redistribution and use in source and binary forms, with or without modification,
7d438b4efSShailend Chand  * are permitted provided that the following conditions are met:
8d438b4efSShailend Chand  *
9d438b4efSShailend Chand  * 1. Redistributions of source code must retain the above copyright notice, this
10d438b4efSShailend Chand  *    list of conditions and the following disclaimer.
11d438b4efSShailend Chand  *
12d438b4efSShailend Chand  * 2. Redistributions in binary form must reproduce the above copyright notice,
13d438b4efSShailend Chand  *    this list of conditions and the following disclaimer in the documentation
14d438b4efSShailend Chand  *    and/or other materials provided with the distribution.
15d438b4efSShailend Chand  *
16d438b4efSShailend Chand  * 3. Neither the name of the copyright holder nor the names of its contributors
17d438b4efSShailend Chand  *    may be used to endorse or promote products derived from this software without
18d438b4efSShailend Chand  *    specific prior written permission.
19d438b4efSShailend Chand  *
20d438b4efSShailend Chand  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21d438b4efSShailend Chand  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22d438b4efSShailend Chand  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23d438b4efSShailend Chand  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24d438b4efSShailend Chand  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25d438b4efSShailend Chand  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26d438b4efSShailend Chand  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27d438b4efSShailend Chand  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28d438b4efSShailend Chand  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29d438b4efSShailend Chand  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30d438b4efSShailend Chand  */
31d438b4efSShailend Chand 
32d438b4efSShailend Chand #include "opt_inet6.h"
33d438b4efSShailend Chand 
34d438b4efSShailend Chand #include "gve.h"
35d438b4efSShailend Chand #include "gve_dqo.h"
36d438b4efSShailend Chand 
37d438b4efSShailend Chand static void
gve_unmap_packet(struct gve_tx_ring * tx,struct gve_tx_pending_pkt_dqo * pending_pkt)38d438b4efSShailend Chand gve_unmap_packet(struct gve_tx_ring *tx,
39d438b4efSShailend Chand     struct gve_tx_pending_pkt_dqo *pending_pkt)
40d438b4efSShailend Chand {
41d438b4efSShailend Chand 	bus_dmamap_sync(tx->dqo.buf_dmatag, pending_pkt->dmamap,
42d438b4efSShailend Chand 	    BUS_DMASYNC_POSTWRITE);
43d438b4efSShailend Chand 	bus_dmamap_unload(tx->dqo.buf_dmatag, pending_pkt->dmamap);
44d438b4efSShailend Chand }
45d438b4efSShailend Chand 
46d438b4efSShailend Chand static void
gve_clear_qpl_pending_pkt(struct gve_tx_pending_pkt_dqo * pending_pkt)4773c3fe4dSJasper Tran O'Leary gve_clear_qpl_pending_pkt(struct gve_tx_pending_pkt_dqo *pending_pkt)
4873c3fe4dSJasper Tran O'Leary {
4973c3fe4dSJasper Tran O'Leary 	pending_pkt->qpl_buf_head = -1;
5073c3fe4dSJasper Tran O'Leary 	pending_pkt->num_qpl_bufs = 0;
5173c3fe4dSJasper Tran O'Leary }
5273c3fe4dSJasper Tran O'Leary 
5373c3fe4dSJasper Tran O'Leary static void
gve_free_tx_mbufs_dqo(struct gve_tx_ring * tx)54d438b4efSShailend Chand gve_free_tx_mbufs_dqo(struct gve_tx_ring *tx)
55d438b4efSShailend Chand {
56d438b4efSShailend Chand 	struct gve_tx_pending_pkt_dqo *pending_pkt;
57d438b4efSShailend Chand 	int i;
58d438b4efSShailend Chand 
59d438b4efSShailend Chand 	for (i = 0; i < tx->dqo.num_pending_pkts; i++) {
60d438b4efSShailend Chand 		pending_pkt = &tx->dqo.pending_pkts[i];
61d438b4efSShailend Chand 		if (!pending_pkt->mbuf)
62d438b4efSShailend Chand 			continue;
63d438b4efSShailend Chand 
6473c3fe4dSJasper Tran O'Leary 		if (gve_is_qpl(tx->com.priv))
6573c3fe4dSJasper Tran O'Leary 			gve_clear_qpl_pending_pkt(pending_pkt);
6673c3fe4dSJasper Tran O'Leary 		else
67d438b4efSShailend Chand 			gve_unmap_packet(tx, pending_pkt);
682348ac89SShailend Chand 
69d438b4efSShailend Chand 		m_freem(pending_pkt->mbuf);
70d438b4efSShailend Chand 		pending_pkt->mbuf = NULL;
71d438b4efSShailend Chand 	}
72d438b4efSShailend Chand }
73d438b4efSShailend Chand 
74d438b4efSShailend Chand void
gve_tx_free_ring_dqo(struct gve_priv * priv,int i)75d438b4efSShailend Chand gve_tx_free_ring_dqo(struct gve_priv *priv, int i)
76d438b4efSShailend Chand {
77d438b4efSShailend Chand 	struct gve_tx_ring *tx = &priv->tx[i];
78f8ed8382SVee Agarwal 	struct gve_ring_com *com = &tx->com;
79d438b4efSShailend Chand 	int j;
80d438b4efSShailend Chand 
81d438b4efSShailend Chand 	if (tx->dqo.desc_ring != NULL) {
82d438b4efSShailend Chand 		gve_dma_free_coherent(&tx->desc_ring_mem);
83d438b4efSShailend Chand 		tx->dqo.desc_ring = NULL;
84d438b4efSShailend Chand 	}
85d438b4efSShailend Chand 
86d438b4efSShailend Chand 	if (tx->dqo.compl_ring != NULL) {
87d438b4efSShailend Chand 		gve_dma_free_coherent(&tx->dqo.compl_ring_mem);
88d438b4efSShailend Chand 		tx->dqo.compl_ring = NULL;
89d438b4efSShailend Chand 	}
90d438b4efSShailend Chand 
91d438b4efSShailend Chand 	if (tx->dqo.pending_pkts != NULL) {
92d438b4efSShailend Chand 		gve_free_tx_mbufs_dqo(tx);
93d438b4efSShailend Chand 
942348ac89SShailend Chand 		if (!gve_is_qpl(priv) && tx->dqo.buf_dmatag) {
95d438b4efSShailend Chand 			for (j = 0; j < tx->dqo.num_pending_pkts; j++)
96d438b4efSShailend Chand 				if (tx->dqo.pending_pkts[j].state !=
97d438b4efSShailend Chand 				    GVE_PACKET_STATE_UNALLOCATED)
98d438b4efSShailend Chand 					bus_dmamap_destroy(tx->dqo.buf_dmatag,
99d438b4efSShailend Chand 					    tx->dqo.pending_pkts[j].dmamap);
100d438b4efSShailend Chand 		}
101d438b4efSShailend Chand 
102d438b4efSShailend Chand 		free(tx->dqo.pending_pkts, M_GVE);
103d438b4efSShailend Chand 		tx->dqo.pending_pkts = NULL;
104d438b4efSShailend Chand 	}
105d438b4efSShailend Chand 
1062348ac89SShailend Chand 	if (!gve_is_qpl(priv) && tx->dqo.buf_dmatag)
107d438b4efSShailend Chand 		bus_dma_tag_destroy(tx->dqo.buf_dmatag);
1082348ac89SShailend Chand 
1092348ac89SShailend Chand 	if (gve_is_qpl(priv) && tx->dqo.qpl_bufs != NULL) {
1102348ac89SShailend Chand 		free(tx->dqo.qpl_bufs, M_GVE);
1112348ac89SShailend Chand 		tx->dqo.qpl_bufs = NULL;
1122348ac89SShailend Chand 	}
113f8ed8382SVee Agarwal 
114f8ed8382SVee Agarwal 	if (com->qpl != NULL) {
115f8ed8382SVee Agarwal 		gve_free_qpl(priv, com->qpl);
116f8ed8382SVee Agarwal 		com->qpl = NULL;
117f8ed8382SVee Agarwal 	}
1182348ac89SShailend Chand }
1192348ac89SShailend Chand 
1202348ac89SShailend Chand static int
gve_tx_alloc_rda_fields_dqo(struct gve_tx_ring * tx)1212348ac89SShailend Chand gve_tx_alloc_rda_fields_dqo(struct gve_tx_ring *tx)
1222348ac89SShailend Chand {
1232348ac89SShailend Chand 	struct gve_priv *priv = tx->com.priv;
1242348ac89SShailend Chand 	int err;
1252348ac89SShailend Chand 	int j;
1262348ac89SShailend Chand 
1272348ac89SShailend Chand 	/*
1282348ac89SShailend Chand 	 * DMA tag for mapping Tx mbufs
1292348ac89SShailend Chand 	 * The maxsize, nsegments, and maxsegsize params should match
1302348ac89SShailend Chand 	 * the if_sethwtso* arguments in gve_setup_ifnet in gve_main.c.
1312348ac89SShailend Chand 	 */
1322348ac89SShailend Chand 	err = bus_dma_tag_create(
1332348ac89SShailend Chand 	    bus_get_dma_tag(priv->dev),	/* parent */
1342348ac89SShailend Chand 	    1, 0,			/* alignment, bounds */
1352348ac89SShailend Chand 	    BUS_SPACE_MAXADDR,		/* lowaddr */
1362348ac89SShailend Chand 	    BUS_SPACE_MAXADDR,		/* highaddr */
1372348ac89SShailend Chand 	    NULL, NULL,			/* filter, filterarg */
1382348ac89SShailend Chand 	    GVE_TSO_MAXSIZE_DQO,	/* maxsize */
1392348ac89SShailend Chand 	    GVE_TX_MAX_DATA_DESCS_DQO,	/* nsegments */
1402348ac89SShailend Chand 	    GVE_TX_MAX_BUF_SIZE_DQO,	/* maxsegsize */
1412348ac89SShailend Chand 	    BUS_DMA_ALLOCNOW,		/* flags */
1422348ac89SShailend Chand 	    NULL,			/* lockfunc */
1432348ac89SShailend Chand 	    NULL,			/* lockarg */
1442348ac89SShailend Chand 	    &tx->dqo.buf_dmatag);
1452348ac89SShailend Chand 	if (err != 0) {
1462348ac89SShailend Chand 		device_printf(priv->dev, "%s: bus_dma_tag_create failed: %d\n",
1472348ac89SShailend Chand 		    __func__, err);
1482348ac89SShailend Chand 		return (err);
1492348ac89SShailend Chand 	}
1502348ac89SShailend Chand 
1512348ac89SShailend Chand 	for (j = 0; j < tx->dqo.num_pending_pkts; j++) {
1522348ac89SShailend Chand 		err = bus_dmamap_create(tx->dqo.buf_dmatag, 0,
1532348ac89SShailend Chand 		    &tx->dqo.pending_pkts[j].dmamap);
1542348ac89SShailend Chand 		if (err != 0) {
1552348ac89SShailend Chand 			device_printf(priv->dev,
1562348ac89SShailend Chand 			    "err in creating pending pkt dmamap %d: %d",
1572348ac89SShailend Chand 			    j, err);
1582348ac89SShailend Chand 			return (err);
1592348ac89SShailend Chand 		}
1602348ac89SShailend Chand 		tx->dqo.pending_pkts[j].state = GVE_PACKET_STATE_FREE;
1612348ac89SShailend Chand 	}
1622348ac89SShailend Chand 
1632348ac89SShailend Chand 	return (0);
164d438b4efSShailend Chand }
165d438b4efSShailend Chand 
166d438b4efSShailend Chand int
gve_tx_alloc_ring_dqo(struct gve_priv * priv,int i)167d438b4efSShailend Chand gve_tx_alloc_ring_dqo(struct gve_priv *priv, int i)
168d438b4efSShailend Chand {
169d438b4efSShailend Chand 	struct gve_tx_ring *tx = &priv->tx[i];
170d438b4efSShailend Chand 	uint16_t num_pending_pkts;
171d438b4efSShailend Chand 	int err;
172d438b4efSShailend Chand 
173d438b4efSShailend Chand 	/* Descriptor ring */
174d438b4efSShailend Chand 	err = gve_dma_alloc_coherent(priv,
175d438b4efSShailend Chand 	    sizeof(union gve_tx_desc_dqo) * priv->tx_desc_cnt,
176d438b4efSShailend Chand 	    CACHE_LINE_SIZE, &tx->desc_ring_mem);
177d438b4efSShailend Chand 	if (err != 0) {
178d438b4efSShailend Chand 		device_printf(priv->dev,
179d438b4efSShailend Chand 		    "Failed to alloc desc ring for tx ring %d", i);
180d438b4efSShailend Chand 		goto abort;
181d438b4efSShailend Chand 	}
182d438b4efSShailend Chand 	tx->dqo.desc_ring = tx->desc_ring_mem.cpu_addr;
183d438b4efSShailend Chand 
184d438b4efSShailend Chand 	/* Completion ring */
185d438b4efSShailend Chand 	err = gve_dma_alloc_coherent(priv,
186d438b4efSShailend Chand 	    sizeof(struct gve_tx_compl_desc_dqo) * priv->tx_desc_cnt,
187d438b4efSShailend Chand 	    CACHE_LINE_SIZE, &tx->dqo.compl_ring_mem);
188d438b4efSShailend Chand 	if (err != 0) {
189d438b4efSShailend Chand 		device_printf(priv->dev,
190d438b4efSShailend Chand 		    "Failed to alloc compl ring for tx ring %d", i);
191d438b4efSShailend Chand 		goto abort;
192d438b4efSShailend Chand 	}
193d438b4efSShailend Chand 	tx->dqo.compl_ring = tx->dqo.compl_ring_mem.cpu_addr;
194d438b4efSShailend Chand 
195d438b4efSShailend Chand 	/*
196d438b4efSShailend Chand 	 * pending_pkts array
197d438b4efSShailend Chand 	 *
198d438b4efSShailend Chand 	 * The max number of pending packets determines the maximum number of
199d438b4efSShailend Chand 	 * descriptors which maybe written to the completion queue.
200d438b4efSShailend Chand 	 *
201d438b4efSShailend Chand 	 * We must set the number small enough to make sure we never overrun the
202d438b4efSShailend Chand 	 * completion queue.
203d438b4efSShailend Chand 	 */
204d438b4efSShailend Chand 	num_pending_pkts = priv->tx_desc_cnt;
205d438b4efSShailend Chand 	/*
206d438b4efSShailend Chand 	 * Reserve space for descriptor completions, which will be reported at
207d438b4efSShailend Chand 	 * most every GVE_TX_MIN_RE_INTERVAL packets.
208d438b4efSShailend Chand 	 */
209d438b4efSShailend Chand 	num_pending_pkts -= num_pending_pkts / GVE_TX_MIN_RE_INTERVAL;
210d438b4efSShailend Chand 
211d438b4efSShailend Chand 	tx->dqo.num_pending_pkts = num_pending_pkts;
212d438b4efSShailend Chand 	tx->dqo.pending_pkts = malloc(
213d438b4efSShailend Chand 	    sizeof(struct gve_tx_pending_pkt_dqo) * num_pending_pkts,
214d438b4efSShailend Chand 	    M_GVE, M_WAITOK | M_ZERO);
215d438b4efSShailend Chand 
2162348ac89SShailend Chand 	if (gve_is_qpl(priv)) {
2172348ac89SShailend Chand 		int qpl_buf_cnt;
218d438b4efSShailend Chand 
219f8ed8382SVee Agarwal 		tx->com.qpl = gve_alloc_qpl(priv, i, GVE_TX_NUM_QPL_PAGES_DQO,
220f8ed8382SVee Agarwal 		    /*single_kva*/false);
221f8ed8382SVee Agarwal 		if (tx->com.qpl == NULL) {
222f8ed8382SVee Agarwal 			device_printf(priv->dev,
223f8ed8382SVee Agarwal 			    "Failed to alloc QPL for tx ring %d", i);
224f8ed8382SVee Agarwal 			err = ENOMEM;
225f8ed8382SVee Agarwal 			goto abort;
226f8ed8382SVee Agarwal 		}
227f8ed8382SVee Agarwal 
2282348ac89SShailend Chand 		qpl_buf_cnt = GVE_TX_BUFS_PER_PAGE_DQO *
2292348ac89SShailend Chand 		    tx->com.qpl->num_pages;
2302348ac89SShailend Chand 
2312348ac89SShailend Chand 		tx->dqo.qpl_bufs = malloc(
2322348ac89SShailend Chand 		    sizeof(*tx->dqo.qpl_bufs) * qpl_buf_cnt,
2332348ac89SShailend Chand 		    M_GVE, M_WAITOK | M_ZERO);
2342348ac89SShailend Chand 	} else
2352348ac89SShailend Chand 		gve_tx_alloc_rda_fields_dqo(tx);
236d438b4efSShailend Chand 	return (0);
237d438b4efSShailend Chand 
238d438b4efSShailend Chand abort:
239d438b4efSShailend Chand 	gve_tx_free_ring_dqo(priv, i);
240d438b4efSShailend Chand 	return (err);
241d438b4efSShailend Chand }
242d438b4efSShailend Chand 
243d438b4efSShailend Chand static void
gve_extract_tx_metadata_dqo(const struct mbuf * mbuf,struct gve_tx_metadata_dqo * metadata)244d438b4efSShailend Chand gve_extract_tx_metadata_dqo(const struct mbuf *mbuf,
245d438b4efSShailend Chand     struct gve_tx_metadata_dqo *metadata)
246d438b4efSShailend Chand {
247d438b4efSShailend Chand 	uint32_t hash = mbuf->m_pkthdr.flowid;
248d438b4efSShailend Chand 	uint16_t path_hash;
249d438b4efSShailend Chand 
250d438b4efSShailend Chand 	metadata->version = GVE_TX_METADATA_VERSION_DQO;
251d438b4efSShailend Chand 	if (hash) {
252d438b4efSShailend Chand 		path_hash = hash ^ (hash >> 16);
253d438b4efSShailend Chand 
254d438b4efSShailend Chand 		path_hash &= (1 << 15) - 1;
255d438b4efSShailend Chand 		if (__predict_false(path_hash == 0))
256d438b4efSShailend Chand 			path_hash = ~path_hash;
257d438b4efSShailend Chand 
258d438b4efSShailend Chand 		metadata->path_hash = path_hash;
259d438b4efSShailend Chand 	}
260d438b4efSShailend Chand }
261d438b4efSShailend Chand 
262d438b4efSShailend Chand static void
gve_tx_fill_pkt_desc_dqo(struct gve_tx_ring * tx,uint32_t * desc_idx,uint32_t len,uint64_t addr,int16_t compl_tag,bool eop,bool csum_enabled)263d438b4efSShailend Chand gve_tx_fill_pkt_desc_dqo(struct gve_tx_ring *tx,
264d438b4efSShailend Chand     uint32_t *desc_idx, uint32_t len, uint64_t addr,
265d438b4efSShailend Chand     int16_t compl_tag, bool eop, bool csum_enabled)
266d438b4efSShailend Chand {
267d438b4efSShailend Chand 	while (len > 0) {
268d438b4efSShailend Chand 		struct gve_tx_pkt_desc_dqo *desc =
269d438b4efSShailend Chand 		    &tx->dqo.desc_ring[*desc_idx].pkt;
270d438b4efSShailend Chand 		uint32_t cur_len = MIN(len, GVE_TX_MAX_BUF_SIZE_DQO);
271d438b4efSShailend Chand 		bool cur_eop = eop && cur_len == len;
272d438b4efSShailend Chand 
273d438b4efSShailend Chand 		*desc = (struct gve_tx_pkt_desc_dqo){
274d438b4efSShailend Chand 			.buf_addr = htole64(addr),
275d438b4efSShailend Chand 			.dtype = GVE_TX_PKT_DESC_DTYPE_DQO,
276d438b4efSShailend Chand 			.end_of_packet = cur_eop,
277d438b4efSShailend Chand 			.checksum_offload_enable = csum_enabled,
278d438b4efSShailend Chand 			.compl_tag = htole16(compl_tag),
279d438b4efSShailend Chand 			.buf_size = cur_len,
280d438b4efSShailend Chand 		};
281d438b4efSShailend Chand 
282d438b4efSShailend Chand 		addr += cur_len;
283d438b4efSShailend Chand 		len -= cur_len;
284d438b4efSShailend Chand 		*desc_idx = (*desc_idx + 1) & tx->dqo.desc_mask;
285d438b4efSShailend Chand 	}
286d438b4efSShailend Chand }
287d438b4efSShailend Chand 
288d438b4efSShailend Chand static void
gve_tx_fill_tso_ctx_desc(struct gve_tx_tso_context_desc_dqo * desc,const struct mbuf * mbuf,const struct gve_tx_metadata_dqo * metadata,int header_len)289d438b4efSShailend Chand gve_tx_fill_tso_ctx_desc(struct gve_tx_tso_context_desc_dqo *desc,
290d438b4efSShailend Chand     const struct mbuf *mbuf, const struct gve_tx_metadata_dqo *metadata,
291d438b4efSShailend Chand     int header_len)
292d438b4efSShailend Chand {
293d438b4efSShailend Chand 	*desc = (struct gve_tx_tso_context_desc_dqo){
294d438b4efSShailend Chand 		.header_len = header_len,
295d438b4efSShailend Chand 		.cmd_dtype = {
296d438b4efSShailend Chand 			.dtype = GVE_TX_TSO_CTX_DESC_DTYPE_DQO,
297d438b4efSShailend Chand 			.tso = 1,
298d438b4efSShailend Chand 		},
299d438b4efSShailend Chand 		.flex0 = metadata->bytes[0],
300d438b4efSShailend Chand 		.flex5 = metadata->bytes[5],
301d438b4efSShailend Chand 		.flex6 = metadata->bytes[6],
302d438b4efSShailend Chand 		.flex7 = metadata->bytes[7],
303d438b4efSShailend Chand 		.flex8 = metadata->bytes[8],
304d438b4efSShailend Chand 		.flex9 = metadata->bytes[9],
305d438b4efSShailend Chand 		.flex10 = metadata->bytes[10],
306d438b4efSShailend Chand 		.flex11 = metadata->bytes[11],
307d438b4efSShailend Chand 	};
308d438b4efSShailend Chand 	desc->tso_total_len = mbuf->m_pkthdr.len - header_len;
309d438b4efSShailend Chand 	desc->mss = mbuf->m_pkthdr.tso_segsz;
310d438b4efSShailend Chand }
311d438b4efSShailend Chand 
312d438b4efSShailend Chand static void
gve_tx_fill_general_ctx_desc(struct gve_tx_general_context_desc_dqo * desc,const struct gve_tx_metadata_dqo * metadata)313d438b4efSShailend Chand gve_tx_fill_general_ctx_desc(struct gve_tx_general_context_desc_dqo *desc,
314d438b4efSShailend Chand     const struct gve_tx_metadata_dqo *metadata)
315d438b4efSShailend Chand {
316d438b4efSShailend Chand 	*desc = (struct gve_tx_general_context_desc_dqo){
317d438b4efSShailend Chand 		.flex0 = metadata->bytes[0],
318d438b4efSShailend Chand 		.flex1 = metadata->bytes[1],
319d438b4efSShailend Chand 		.flex2 = metadata->bytes[2],
320d438b4efSShailend Chand 		.flex3 = metadata->bytes[3],
321d438b4efSShailend Chand 		.flex4 = metadata->bytes[4],
322d438b4efSShailend Chand 		.flex5 = metadata->bytes[5],
323d438b4efSShailend Chand 		.flex6 = metadata->bytes[6],
324d438b4efSShailend Chand 		.flex7 = metadata->bytes[7],
325d438b4efSShailend Chand 		.flex8 = metadata->bytes[8],
326d438b4efSShailend Chand 		.flex9 = metadata->bytes[9],
327d438b4efSShailend Chand 		.flex10 = metadata->bytes[10],
328d438b4efSShailend Chand 		.flex11 = metadata->bytes[11],
329d438b4efSShailend Chand 		.cmd_dtype = {.dtype = GVE_TX_GENERAL_CTX_DESC_DTYPE_DQO},
330d438b4efSShailend Chand 	};
331d438b4efSShailend Chand }
332d438b4efSShailend Chand 
333d438b4efSShailend Chand #define PULLUP_HDR(m, len)				\
334d438b4efSShailend Chand do {							\
335d438b4efSShailend Chand 	if (__predict_false((m)->m_len < (len))) {	\
336d438b4efSShailend Chand 		(m) = m_pullup((m), (len));		\
337d438b4efSShailend Chand 		if ((m) == NULL)			\
338d438b4efSShailend Chand 			return (EINVAL);		\
339d438b4efSShailend Chand 	}						\
340d438b4efSShailend Chand } while (0)
341d438b4efSShailend Chand 
342d438b4efSShailend Chand static int
gve_prep_tso(struct mbuf * mbuf,int * header_len)343d438b4efSShailend Chand gve_prep_tso(struct mbuf *mbuf, int *header_len)
344d438b4efSShailend Chand {
345d438b4efSShailend Chand 	uint8_t l3_off, l4_off = 0;
346d438b4efSShailend Chand 	struct ether_header *eh;
347d438b4efSShailend Chand 	struct tcphdr *th;
348d438b4efSShailend Chand 	u_short csum;
349d438b4efSShailend Chand 
350d438b4efSShailend Chand 	PULLUP_HDR(mbuf, sizeof(*eh));
351d438b4efSShailend Chand 	eh = mtod(mbuf, struct ether_header *);
352d438b4efSShailend Chand 	KASSERT(eh->ether_type != ETHERTYPE_VLAN,
353d438b4efSShailend Chand 	    ("VLAN-tagged packets not supported"));
354d438b4efSShailend Chand 	l3_off = ETHER_HDR_LEN;
355d438b4efSShailend Chand 
356d438b4efSShailend Chand #ifdef INET6
357d438b4efSShailend Chand 	if (ntohs(eh->ether_type) == ETHERTYPE_IPV6) {
358d438b4efSShailend Chand 		struct ip6_hdr *ip6;
359d438b4efSShailend Chand 
360d438b4efSShailend Chand 		PULLUP_HDR(mbuf, l3_off + sizeof(*ip6));
361d438b4efSShailend Chand 		ip6 = (struct ip6_hdr *)(mtodo(mbuf, l3_off));
362d438b4efSShailend Chand 		l4_off = l3_off + sizeof(struct ip6_hdr);
363d438b4efSShailend Chand 		csum = in6_cksum_pseudo(ip6, /*len=*/0, IPPROTO_TCP,
364d438b4efSShailend Chand 		    /*csum=*/0);
365d438b4efSShailend Chand 	} else
366d438b4efSShailend Chand #endif
367d438b4efSShailend Chand 	if (ntohs(eh->ether_type) == ETHERTYPE_IP) {
368d438b4efSShailend Chand 		struct ip *ip;
369d438b4efSShailend Chand 
370d438b4efSShailend Chand 		PULLUP_HDR(mbuf, l3_off + sizeof(*ip));
371d438b4efSShailend Chand 		ip = (struct ip *)(mtodo(mbuf, l3_off));
372d438b4efSShailend Chand 		l4_off = l3_off + (ip->ip_hl << 2);
373d438b4efSShailend Chand 		csum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
374d438b4efSShailend Chand 		    htons(IPPROTO_TCP));
375d438b4efSShailend Chand 	}
376d438b4efSShailend Chand 
377d438b4efSShailend Chand 	PULLUP_HDR(mbuf, l4_off + sizeof(struct tcphdr *));
378d438b4efSShailend Chand 	th = (struct tcphdr *)(mtodo(mbuf, l4_off));
379d438b4efSShailend Chand 	*header_len = l4_off + (th->th_off << 2);
380d438b4efSShailend Chand 
381d438b4efSShailend Chand 	/*
382d438b4efSShailend Chand 	 * Hardware requires the th->th_sum to not include the TCP payload,
383d438b4efSShailend Chand 	 * hence we recompute the csum with it excluded.
384d438b4efSShailend Chand 	 */
385d438b4efSShailend Chand 	th->th_sum = csum;
386d438b4efSShailend Chand 
387d438b4efSShailend Chand 	return (0);
388d438b4efSShailend Chand }
389d438b4efSShailend Chand 
390d438b4efSShailend Chand static int
gve_tx_fill_ctx_descs(struct gve_tx_ring * tx,struct mbuf * mbuf,bool is_tso,uint32_t * desc_idx)3912348ac89SShailend Chand gve_tx_fill_ctx_descs(struct gve_tx_ring *tx, struct mbuf *mbuf,
3922348ac89SShailend Chand     bool is_tso, uint32_t *desc_idx)
3932348ac89SShailend Chand {
3942348ac89SShailend Chand 	struct gve_tx_general_context_desc_dqo *gen_desc;
3952348ac89SShailend Chand 	struct gve_tx_tso_context_desc_dqo *tso_desc;
3962348ac89SShailend Chand 	struct gve_tx_metadata_dqo metadata;
3972348ac89SShailend Chand 	int header_len;
3982348ac89SShailend Chand 	int err;
3992348ac89SShailend Chand 
4002348ac89SShailend Chand 	metadata = (struct gve_tx_metadata_dqo){0};
4012348ac89SShailend Chand 	gve_extract_tx_metadata_dqo(mbuf, &metadata);
4022348ac89SShailend Chand 
4032348ac89SShailend Chand 	if (is_tso) {
4042348ac89SShailend Chand 		err = gve_prep_tso(mbuf, &header_len);
4052348ac89SShailend Chand 		if (__predict_false(err)) {
4062348ac89SShailend Chand 			counter_enter();
4072348ac89SShailend Chand 			counter_u64_add_protected(
4082348ac89SShailend Chand 			    tx->stats.tx_delayed_pkt_tsoerr, 1);
4092348ac89SShailend Chand 			counter_exit();
4102348ac89SShailend Chand 			return (err);
4112348ac89SShailend Chand 		}
4122348ac89SShailend Chand 
4132348ac89SShailend Chand 		tso_desc = &tx->dqo.desc_ring[*desc_idx].tso_ctx;
4142348ac89SShailend Chand 		gve_tx_fill_tso_ctx_desc(tso_desc, mbuf, &metadata, header_len);
4152348ac89SShailend Chand 
4162348ac89SShailend Chand 		*desc_idx = (*desc_idx + 1) & tx->dqo.desc_mask;
4172348ac89SShailend Chand 		counter_enter();
4182348ac89SShailend Chand 		counter_u64_add_protected(tx->stats.tso_packet_cnt, 1);
4192348ac89SShailend Chand 		counter_exit();
4202348ac89SShailend Chand 	}
4212348ac89SShailend Chand 
4222348ac89SShailend Chand 	gen_desc = &tx->dqo.desc_ring[*desc_idx].general_ctx;
4232348ac89SShailend Chand 	gve_tx_fill_general_ctx_desc(gen_desc, &metadata);
4242348ac89SShailend Chand 	*desc_idx = (*desc_idx + 1) & tx->dqo.desc_mask;
4252348ac89SShailend Chand 	return (0);
4262348ac89SShailend Chand }
4272348ac89SShailend Chand 
4282348ac89SShailend Chand static int
gve_map_mbuf_dqo(struct gve_tx_ring * tx,struct mbuf ** mbuf,bus_dmamap_t dmamap,bus_dma_segment_t * segs,int * nsegs,int attempt)429d438b4efSShailend Chand gve_map_mbuf_dqo(struct gve_tx_ring *tx,
430d438b4efSShailend Chand     struct mbuf **mbuf, bus_dmamap_t dmamap,
431d438b4efSShailend Chand     bus_dma_segment_t *segs, int *nsegs, int attempt)
432d438b4efSShailend Chand {
433d438b4efSShailend Chand 	struct mbuf *m_new = NULL;
434d438b4efSShailend Chand 	int err;
435d438b4efSShailend Chand 
436d438b4efSShailend Chand 	err = bus_dmamap_load_mbuf_sg(tx->dqo.buf_dmatag, dmamap,
437d438b4efSShailend Chand 	    *mbuf, segs, nsegs, BUS_DMA_NOWAIT);
438d438b4efSShailend Chand 
439d438b4efSShailend Chand 	switch (err) {
440d438b4efSShailend Chand 	case __predict_true(0):
441d438b4efSShailend Chand 		break;
442d438b4efSShailend Chand 	case EFBIG:
443d438b4efSShailend Chand 		if (__predict_false(attempt > 0))
444d438b4efSShailend Chand 			goto abort;
445d438b4efSShailend Chand 
446d438b4efSShailend Chand 		counter_enter();
447d438b4efSShailend Chand 		counter_u64_add_protected(
448d438b4efSShailend Chand 		    tx->stats.tx_mbuf_collapse, 1);
449d438b4efSShailend Chand 		counter_exit();
450d438b4efSShailend Chand 
451d438b4efSShailend Chand 		/* Try m_collapse before m_defrag */
452d438b4efSShailend Chand 		m_new = m_collapse(*mbuf, M_NOWAIT,
453d438b4efSShailend Chand 		    GVE_TX_MAX_DATA_DESCS_DQO);
454d438b4efSShailend Chand 		if (m_new == NULL) {
455d438b4efSShailend Chand 			counter_enter();
456d438b4efSShailend Chand 			counter_u64_add_protected(
457d438b4efSShailend Chand 			    tx->stats.tx_mbuf_defrag, 1);
458d438b4efSShailend Chand 			counter_exit();
459d438b4efSShailend Chand 			m_new = m_defrag(*mbuf, M_NOWAIT);
460d438b4efSShailend Chand 		}
461d438b4efSShailend Chand 
462d438b4efSShailend Chand 		if (__predict_false(m_new == NULL)) {
463d438b4efSShailend Chand 			counter_enter();
464d438b4efSShailend Chand 			counter_u64_add_protected(
465d438b4efSShailend Chand 			    tx->stats.tx_mbuf_defrag_err, 1);
466d438b4efSShailend Chand 			counter_exit();
467d438b4efSShailend Chand 
468d438b4efSShailend Chand 			m_freem(*mbuf);
469d438b4efSShailend Chand 			*mbuf = NULL;
470d438b4efSShailend Chand 			err = ENOMEM;
471d438b4efSShailend Chand 			goto abort;
472d438b4efSShailend Chand 		} else {
473d438b4efSShailend Chand 			*mbuf = m_new;
474d438b4efSShailend Chand 			return (gve_map_mbuf_dqo(tx, mbuf, dmamap,
475d438b4efSShailend Chand 			    segs, nsegs, ++attempt));
476d438b4efSShailend Chand 		}
477d438b4efSShailend Chand 	case ENOMEM:
478d438b4efSShailend Chand 		counter_enter();
479d438b4efSShailend Chand 		counter_u64_add_protected(
480d438b4efSShailend Chand 		    tx->stats.tx_mbuf_dmamap_enomem_err, 1);
481d438b4efSShailend Chand 		counter_exit();
482d438b4efSShailend Chand 		goto abort;
483d438b4efSShailend Chand 	default:
484d438b4efSShailend Chand 		goto abort;
485d438b4efSShailend Chand 	}
486d438b4efSShailend Chand 
487d438b4efSShailend Chand 	return (0);
488d438b4efSShailend Chand 
489d438b4efSShailend Chand abort:
490d438b4efSShailend Chand 	counter_enter();
491d438b4efSShailend Chand 	counter_u64_add_protected(tx->stats.tx_mbuf_dmamap_err, 1);
492d438b4efSShailend Chand 	counter_exit();
493d438b4efSShailend Chand 	return (err);
494d438b4efSShailend Chand }
495d438b4efSShailend Chand 
496d438b4efSShailend Chand static uint32_t
num_avail_desc_ring_slots(const struct gve_tx_ring * tx)497d438b4efSShailend Chand num_avail_desc_ring_slots(const struct gve_tx_ring *tx)
498d438b4efSShailend Chand {
499d438b4efSShailend Chand 	uint32_t num_used = (tx->dqo.desc_tail - tx->dqo.desc_head) &
500d438b4efSShailend Chand 	    tx->dqo.desc_mask;
501d438b4efSShailend Chand 
502d438b4efSShailend Chand 	return (tx->dqo.desc_mask - num_used);
503d438b4efSShailend Chand }
504d438b4efSShailend Chand 
505d438b4efSShailend Chand static struct gve_tx_pending_pkt_dqo *
gve_alloc_pending_packet(struct gve_tx_ring * tx)506d438b4efSShailend Chand gve_alloc_pending_packet(struct gve_tx_ring *tx)
507d438b4efSShailend Chand {
508d438b4efSShailend Chand 	int32_t index = tx->dqo.free_pending_pkts_csm;
509d438b4efSShailend Chand 	struct gve_tx_pending_pkt_dqo *pending_pkt;
510d438b4efSShailend Chand 
511d438b4efSShailend Chand 	/*
512d438b4efSShailend Chand 	 * No pending packets available in the consumer list,
513d438b4efSShailend Chand 	 * try to steal the producer list.
514d438b4efSShailend Chand 	 */
515d438b4efSShailend Chand 	if (__predict_false(index == -1)) {
516d438b4efSShailend Chand 		tx->dqo.free_pending_pkts_csm = atomic_swap_32(
517d438b4efSShailend Chand 		    &tx->dqo.free_pending_pkts_prd, -1);
518d438b4efSShailend Chand 
519d438b4efSShailend Chand 		index = tx->dqo.free_pending_pkts_csm;
520d438b4efSShailend Chand 		if (__predict_false(index == -1))
521d438b4efSShailend Chand 			return (NULL);
522d438b4efSShailend Chand 	}
523d438b4efSShailend Chand 
524d438b4efSShailend Chand 	pending_pkt = &tx->dqo.pending_pkts[index];
525d438b4efSShailend Chand 
526d438b4efSShailend Chand 	/* Remove pending_pkt from the consumer list */
527d438b4efSShailend Chand 	tx->dqo.free_pending_pkts_csm = pending_pkt->next;
528d438b4efSShailend Chand 	pending_pkt->state = GVE_PACKET_STATE_PENDING_DATA_COMPL;
529d438b4efSShailend Chand 
5303d295733SJasper Tran O'Leary 	gve_set_timestamp(&pending_pkt->enqueue_time_sec);
5313d295733SJasper Tran O'Leary 
532d438b4efSShailend Chand 	return (pending_pkt);
533d438b4efSShailend Chand }
534d438b4efSShailend Chand 
535d438b4efSShailend Chand static void
gve_free_pending_packet(struct gve_tx_ring * tx,struct gve_tx_pending_pkt_dqo * pending_pkt)536d438b4efSShailend Chand gve_free_pending_packet(struct gve_tx_ring *tx,
537d438b4efSShailend Chand     struct gve_tx_pending_pkt_dqo *pending_pkt)
538d438b4efSShailend Chand {
539d438b4efSShailend Chand 	int index = pending_pkt - tx->dqo.pending_pkts;
540d438b4efSShailend Chand 	int32_t old_head;
541d438b4efSShailend Chand 
542d438b4efSShailend Chand 	pending_pkt->state = GVE_PACKET_STATE_FREE;
543d438b4efSShailend Chand 
5443d295733SJasper Tran O'Leary 	gve_invalidate_timestamp(&pending_pkt->enqueue_time_sec);
5453d295733SJasper Tran O'Leary 
546d438b4efSShailend Chand 	/* Add pending_pkt to the producer list */
547d438b4efSShailend Chand 	while (true) {
548d438b4efSShailend Chand 		old_head = atomic_load_acq_32(&tx->dqo.free_pending_pkts_prd);
549d438b4efSShailend Chand 
550d438b4efSShailend Chand 		pending_pkt->next = old_head;
551d438b4efSShailend Chand 		if (atomic_cmpset_32(&tx->dqo.free_pending_pkts_prd,
552d438b4efSShailend Chand 		    old_head, index))
553d438b4efSShailend Chand 			break;
554d438b4efSShailend Chand 	}
555d438b4efSShailend Chand }
556d438b4efSShailend Chand 
557d438b4efSShailend Chand /*
558d438b4efSShailend Chand  * Has the side-effect of retrieving the value of the last desc index
559d438b4efSShailend Chand  * processed by the NIC. hw_tx_head is written to by the completions-processing
560d438b4efSShailend Chand  * taskqueue upon receiving descriptor-completions.
561d438b4efSShailend Chand  */
562d438b4efSShailend Chand static bool
gve_tx_has_desc_room_dqo(struct gve_tx_ring * tx,int needed_descs)563d438b4efSShailend Chand gve_tx_has_desc_room_dqo(struct gve_tx_ring *tx, int needed_descs)
564d438b4efSShailend Chand {
565d438b4efSShailend Chand 	if (needed_descs <= num_avail_desc_ring_slots(tx))
566d438b4efSShailend Chand 		return (true);
567d438b4efSShailend Chand 
568d438b4efSShailend Chand 	tx->dqo.desc_head = atomic_load_acq_32(&tx->dqo.hw_tx_head);
569d438b4efSShailend Chand 	if (needed_descs > num_avail_desc_ring_slots(tx)) {
570d438b4efSShailend Chand 		counter_enter();
571d438b4efSShailend Chand 		counter_u64_add_protected(
572d438b4efSShailend Chand 		    tx->stats.tx_delayed_pkt_nospace_descring, 1);
573d438b4efSShailend Chand 		counter_exit();
574d438b4efSShailend Chand 		return (false);
575d438b4efSShailend Chand 	}
576d438b4efSShailend Chand 
577d438b4efSShailend Chand 	return (0);
578d438b4efSShailend Chand }
579d438b4efSShailend Chand 
580d438b4efSShailend Chand static void
gve_tx_request_desc_compl(struct gve_tx_ring * tx,uint32_t desc_idx)581d438b4efSShailend Chand gve_tx_request_desc_compl(struct gve_tx_ring *tx, uint32_t desc_idx)
582d438b4efSShailend Chand {
583d438b4efSShailend Chand 	uint32_t last_report_event_interval;
584d438b4efSShailend Chand 	uint32_t last_desc_idx;
585d438b4efSShailend Chand 
586d438b4efSShailend Chand 	last_desc_idx = (desc_idx - 1) & tx->dqo.desc_mask;
587d438b4efSShailend Chand 	last_report_event_interval =
588d438b4efSShailend Chand 	    (last_desc_idx - tx->dqo.last_re_idx) & tx->dqo.desc_mask;
589d438b4efSShailend Chand 
590d438b4efSShailend Chand 	if (__predict_false(last_report_event_interval >=
591d438b4efSShailend Chand 	    GVE_TX_MIN_RE_INTERVAL)) {
592d438b4efSShailend Chand 		tx->dqo.desc_ring[last_desc_idx].pkt.report_event = true;
593d438b4efSShailend Chand 		tx->dqo.last_re_idx = last_desc_idx;
594d438b4efSShailend Chand 	}
595d438b4efSShailend Chand }
596d438b4efSShailend Chand 
5972348ac89SShailend Chand static bool
gve_tx_have_enough_qpl_bufs(struct gve_tx_ring * tx,int num_bufs)5982348ac89SShailend Chand gve_tx_have_enough_qpl_bufs(struct gve_tx_ring *tx, int num_bufs)
5992348ac89SShailend Chand {
6002348ac89SShailend Chand 	uint32_t available = tx->dqo.qpl_bufs_produced_cached -
6012348ac89SShailend Chand 	    tx->dqo.qpl_bufs_consumed;
6022348ac89SShailend Chand 
6032348ac89SShailend Chand 	if (__predict_true(available >= num_bufs))
6042348ac89SShailend Chand 		return (true);
6052348ac89SShailend Chand 
6062348ac89SShailend Chand 	tx->dqo.qpl_bufs_produced_cached = atomic_load_acq_32(
6072348ac89SShailend Chand 	    &tx->dqo.qpl_bufs_produced);
6082348ac89SShailend Chand 	available = tx->dqo.qpl_bufs_produced_cached -
6092348ac89SShailend Chand 	    tx->dqo.qpl_bufs_consumed;
6102348ac89SShailend Chand 
6112348ac89SShailend Chand 	if (__predict_true(available >= num_bufs))
6122348ac89SShailend Chand 		return (true);
6132348ac89SShailend Chand 	return (false);
6142348ac89SShailend Chand }
6152348ac89SShailend Chand 
6162348ac89SShailend Chand static int32_t
gve_tx_alloc_qpl_buf(struct gve_tx_ring * tx)6172348ac89SShailend Chand gve_tx_alloc_qpl_buf(struct gve_tx_ring *tx)
6182348ac89SShailend Chand {
6192348ac89SShailend Chand 	int32_t buf = tx->dqo.free_qpl_bufs_csm;
6202348ac89SShailend Chand 
6212348ac89SShailend Chand 	if (__predict_false(buf == -1)) {
6222348ac89SShailend Chand 		tx->dqo.free_qpl_bufs_csm = atomic_swap_32(
6232348ac89SShailend Chand 		    &tx->dqo.free_qpl_bufs_prd, -1);
6242348ac89SShailend Chand 		buf = tx->dqo.free_qpl_bufs_csm;
6252348ac89SShailend Chand 		if (__predict_false(buf == -1))
6262348ac89SShailend Chand 			return (-1);
6272348ac89SShailend Chand 	}
6282348ac89SShailend Chand 
6292348ac89SShailend Chand 	tx->dqo.free_qpl_bufs_csm = tx->dqo.qpl_bufs[buf];
6302348ac89SShailend Chand 	tx->dqo.qpl_bufs_consumed++;
6312348ac89SShailend Chand 	return (buf);
6322348ac89SShailend Chand }
6332348ac89SShailend Chand 
6342348ac89SShailend Chand /*
6352348ac89SShailend Chand  * Tx buffer i corresponds to
6362348ac89SShailend Chand  * qpl_page_id = i / GVE_TX_BUFS_PER_PAGE_DQO
6372348ac89SShailend Chand  * qpl_page_offset = (i % GVE_TX_BUFS_PER_PAGE_DQO) * GVE_TX_BUF_SIZE_DQO
6382348ac89SShailend Chand  */
6392348ac89SShailend Chand static void
gve_tx_buf_get_addr_dqo(struct gve_tx_ring * tx,int32_t index,void ** va,bus_addr_t * dma_addr)6402348ac89SShailend Chand gve_tx_buf_get_addr_dqo(struct gve_tx_ring *tx,
6412348ac89SShailend Chand     int32_t index, void **va, bus_addr_t *dma_addr)
6422348ac89SShailend Chand {
6432348ac89SShailend Chand 	int page_id = index >> (PAGE_SHIFT - GVE_TX_BUF_SHIFT_DQO);
6442348ac89SShailend Chand 	int offset = (index & (GVE_TX_BUFS_PER_PAGE_DQO - 1)) <<
6452348ac89SShailend Chand 	    GVE_TX_BUF_SHIFT_DQO;
6462348ac89SShailend Chand 
6472348ac89SShailend Chand 	*va = (char *)tx->com.qpl->dmas[page_id].cpu_addr + offset;
6482348ac89SShailend Chand 	*dma_addr = tx->com.qpl->dmas[page_id].bus_addr + offset;
6492348ac89SShailend Chand }
6502348ac89SShailend Chand 
6512348ac89SShailend Chand static struct gve_dma_handle *
gve_get_page_dma_handle(struct gve_tx_ring * tx,int32_t index)6522348ac89SShailend Chand gve_get_page_dma_handle(struct gve_tx_ring *tx, int32_t index)
6532348ac89SShailend Chand {
6542348ac89SShailend Chand 	int page_id = index >> (PAGE_SHIFT - GVE_TX_BUF_SHIFT_DQO);
6552348ac89SShailend Chand 
6562348ac89SShailend Chand 	return (&tx->com.qpl->dmas[page_id]);
6572348ac89SShailend Chand }
6582348ac89SShailend Chand 
6592348ac89SShailend Chand static void
gve_tx_copy_mbuf_and_write_pkt_descs(struct gve_tx_ring * tx,struct mbuf * mbuf,struct gve_tx_pending_pkt_dqo * pkt,bool csum_enabled,int16_t completion_tag,uint32_t * desc_idx)6602348ac89SShailend Chand gve_tx_copy_mbuf_and_write_pkt_descs(struct gve_tx_ring *tx,
6612348ac89SShailend Chand     struct mbuf *mbuf, struct gve_tx_pending_pkt_dqo *pkt,
6622348ac89SShailend Chand     bool csum_enabled, int16_t completion_tag,
6632348ac89SShailend Chand     uint32_t *desc_idx)
6642348ac89SShailend Chand {
6652348ac89SShailend Chand 	int32_t pkt_len = mbuf->m_pkthdr.len;
6662348ac89SShailend Chand 	struct gve_dma_handle *dma;
6672348ac89SShailend Chand 	uint32_t copy_offset = 0;
6682348ac89SShailend Chand 	int32_t prev_buf = -1;
6692348ac89SShailend Chand 	uint32_t copy_len;
6702348ac89SShailend Chand 	bus_addr_t addr;
6712348ac89SShailend Chand 	int32_t buf;
6722348ac89SShailend Chand 	void *va;
6732348ac89SShailend Chand 
6742348ac89SShailend Chand 	MPASS(pkt->num_qpl_bufs == 0);
6752348ac89SShailend Chand 	MPASS(pkt->qpl_buf_head == -1);
6762348ac89SShailend Chand 
6772348ac89SShailend Chand 	while (copy_offset < pkt_len) {
6782348ac89SShailend Chand 		buf = gve_tx_alloc_qpl_buf(tx);
6792348ac89SShailend Chand 		/* We already checked for availability */
6802348ac89SShailend Chand 		MPASS(buf != -1);
6812348ac89SShailend Chand 
6822348ac89SShailend Chand 		gve_tx_buf_get_addr_dqo(tx, buf, &va, &addr);
6832348ac89SShailend Chand 		copy_len = MIN(GVE_TX_BUF_SIZE_DQO, pkt_len - copy_offset);
6842348ac89SShailend Chand 		m_copydata(mbuf, copy_offset, copy_len, va);
6852348ac89SShailend Chand 		copy_offset += copy_len;
6862348ac89SShailend Chand 
6872348ac89SShailend Chand 		dma = gve_get_page_dma_handle(tx, buf);
6882348ac89SShailend Chand 		bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE);
6892348ac89SShailend Chand 
6902348ac89SShailend Chand 		gve_tx_fill_pkt_desc_dqo(tx, desc_idx,
6912348ac89SShailend Chand 		    copy_len, addr, completion_tag,
6922348ac89SShailend Chand 		    /*eop=*/copy_offset == pkt_len,
6932348ac89SShailend Chand 		    csum_enabled);
6942348ac89SShailend Chand 
6952348ac89SShailend Chand 		/* Link all the qpl bufs for a packet */
6962348ac89SShailend Chand 		if (prev_buf == -1)
6972348ac89SShailend Chand 			pkt->qpl_buf_head = buf;
6982348ac89SShailend Chand 		else
6992348ac89SShailend Chand 			tx->dqo.qpl_bufs[prev_buf] = buf;
7002348ac89SShailend Chand 
7012348ac89SShailend Chand 		prev_buf = buf;
7022348ac89SShailend Chand 		pkt->num_qpl_bufs++;
7032348ac89SShailend Chand 	}
7042348ac89SShailend Chand 
7052348ac89SShailend Chand 	tx->dqo.qpl_bufs[buf] = -1;
7062348ac89SShailend Chand }
7072348ac89SShailend Chand 
7082348ac89SShailend Chand int
gve_xmit_dqo_qpl(struct gve_tx_ring * tx,struct mbuf * mbuf)7092348ac89SShailend Chand gve_xmit_dqo_qpl(struct gve_tx_ring *tx, struct mbuf *mbuf)
7102348ac89SShailend Chand {
7112348ac89SShailend Chand 	uint32_t desc_idx = tx->dqo.desc_tail;
7122348ac89SShailend Chand 	struct gve_tx_pending_pkt_dqo *pkt;
7132348ac89SShailend Chand 	int total_descs_needed;
7142348ac89SShailend Chand 	int16_t completion_tag;
7152348ac89SShailend Chand 	bool has_csum_flag;
7162348ac89SShailend Chand 	int csum_flags;
7172348ac89SShailend Chand 	bool is_tso;
7182348ac89SShailend Chand 	int nsegs;
7192348ac89SShailend Chand 	int err;
7202348ac89SShailend Chand 
7212348ac89SShailend Chand 	csum_flags = mbuf->m_pkthdr.csum_flags;
7222348ac89SShailend Chand 	has_csum_flag = csum_flags & (CSUM_TCP | CSUM_UDP |
7232348ac89SShailend Chand 	    CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_TSO);
7242348ac89SShailend Chand 	is_tso = csum_flags & CSUM_TSO;
7252348ac89SShailend Chand 
7262348ac89SShailend Chand 	nsegs = howmany(mbuf->m_pkthdr.len, GVE_TX_BUF_SIZE_DQO);
7272348ac89SShailend Chand 	/* Check if we have enough room in the desc ring */
7282348ac89SShailend Chand 	total_descs_needed = 1 +     /* general_ctx_desc */
7292348ac89SShailend Chand 	    nsegs +		     /* pkt_desc */
7302348ac89SShailend Chand 	    (is_tso ? 1 : 0);        /* tso_ctx_desc */
7312348ac89SShailend Chand 	if (__predict_false(!gve_tx_has_desc_room_dqo(tx, total_descs_needed)))
7322348ac89SShailend Chand 		return (ENOBUFS);
7332348ac89SShailend Chand 
7342348ac89SShailend Chand 	if (!gve_tx_have_enough_qpl_bufs(tx, nsegs)) {
7352348ac89SShailend Chand 		counter_enter();
7362348ac89SShailend Chand 		counter_u64_add_protected(
7372348ac89SShailend Chand 		    tx->stats.tx_delayed_pkt_nospace_qpl_bufs, 1);
7382348ac89SShailend Chand 		counter_exit();
7392348ac89SShailend Chand 		return (ENOBUFS);
7402348ac89SShailend Chand 	}
7412348ac89SShailend Chand 
7422348ac89SShailend Chand 	pkt = gve_alloc_pending_packet(tx);
7432348ac89SShailend Chand 	if (pkt == NULL) {
7442348ac89SShailend Chand 		counter_enter();
7452348ac89SShailend Chand 		counter_u64_add_protected(
7462348ac89SShailend Chand 		    tx->stats.tx_delayed_pkt_nospace_compring, 1);
7472348ac89SShailend Chand 		counter_exit();
7482348ac89SShailend Chand 		return (ENOBUFS);
7492348ac89SShailend Chand 	}
7502348ac89SShailend Chand 	completion_tag = pkt - tx->dqo.pending_pkts;
7512348ac89SShailend Chand 	pkt->mbuf = mbuf;
7522348ac89SShailend Chand 
7532348ac89SShailend Chand 	err = gve_tx_fill_ctx_descs(tx, mbuf, is_tso, &desc_idx);
7542348ac89SShailend Chand 	if (err)
7552348ac89SShailend Chand 		goto abort;
7562348ac89SShailend Chand 
7572348ac89SShailend Chand 	gve_tx_copy_mbuf_and_write_pkt_descs(tx, mbuf, pkt,
7582348ac89SShailend Chand 	    has_csum_flag, completion_tag, &desc_idx);
7592348ac89SShailend Chand 
7602348ac89SShailend Chand 	/* Remember the index of the last desc written */
7612348ac89SShailend Chand 	tx->dqo.desc_tail = desc_idx;
7622348ac89SShailend Chand 
7632348ac89SShailend Chand 	/*
7642348ac89SShailend Chand 	 * Request a descriptor completion on the last descriptor of the
7652348ac89SShailend Chand 	 * packet if we are allowed to by the HW enforced interval.
7662348ac89SShailend Chand 	 */
7672348ac89SShailend Chand 	gve_tx_request_desc_compl(tx, desc_idx);
7682348ac89SShailend Chand 
7692348ac89SShailend Chand 	tx->req += total_descs_needed; /* tx->req is just a sysctl counter */
7702348ac89SShailend Chand 	return (0);
7712348ac89SShailend Chand 
7722348ac89SShailend Chand abort:
7732348ac89SShailend Chand 	pkt->mbuf = NULL;
7742348ac89SShailend Chand 	gve_free_pending_packet(tx, pkt);
7752348ac89SShailend Chand 	return (err);
7762348ac89SShailend Chand }
7772348ac89SShailend Chand 
778d438b4efSShailend Chand int
gve_xmit_dqo(struct gve_tx_ring * tx,struct mbuf ** mbuf_ptr)779d438b4efSShailend Chand gve_xmit_dqo(struct gve_tx_ring *tx, struct mbuf **mbuf_ptr)
780d438b4efSShailend Chand {
781d438b4efSShailend Chand 	bus_dma_segment_t segs[GVE_TX_MAX_DATA_DESCS_DQO];
782d438b4efSShailend Chand 	uint32_t desc_idx = tx->dqo.desc_tail;
783d438b4efSShailend Chand 	struct gve_tx_pending_pkt_dqo *pkt;
784d438b4efSShailend Chand 	struct mbuf *mbuf = *mbuf_ptr;
785d438b4efSShailend Chand 	int total_descs_needed;
786d438b4efSShailend Chand 	int16_t completion_tag;
787d438b4efSShailend Chand 	bool has_csum_flag;
788d438b4efSShailend Chand 	int csum_flags;
789d438b4efSShailend Chand 	bool is_tso;
790d438b4efSShailend Chand 	int nsegs;
791d438b4efSShailend Chand 	int err;
792d438b4efSShailend Chand 	int i;
793d438b4efSShailend Chand 
794d438b4efSShailend Chand 	csum_flags = mbuf->m_pkthdr.csum_flags;
795d438b4efSShailend Chand 	has_csum_flag = csum_flags & (CSUM_TCP | CSUM_UDP |
796d438b4efSShailend Chand 	    CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_TSO);
797d438b4efSShailend Chand 	is_tso = csum_flags & CSUM_TSO;
798d438b4efSShailend Chand 
799d438b4efSShailend Chand 	/*
800d438b4efSShailend Chand 	 * This mbuf might end up needing more than 1 pkt desc.
801d438b4efSShailend Chand 	 * The actual number, `nsegs` is known only after the
802d438b4efSShailend Chand 	 * expensive gve_map_mbuf_dqo call. This check beneath
803d438b4efSShailend Chand 	 * exists to fail early when the desc ring is really full.
804d438b4efSShailend Chand 	 */
805d438b4efSShailend Chand 	total_descs_needed = 1 +     /* general_ctx_desc */
806d438b4efSShailend Chand 	    1 +			     /* pkt_desc */
807d438b4efSShailend Chand 	    (is_tso ? 1 : 0);        /* tso_ctx_desc */
808d438b4efSShailend Chand 	if (__predict_false(!gve_tx_has_desc_room_dqo(tx, total_descs_needed)))
809d438b4efSShailend Chand 		return (ENOBUFS);
810d438b4efSShailend Chand 
811d438b4efSShailend Chand 	pkt = gve_alloc_pending_packet(tx);
812d438b4efSShailend Chand 	if (pkt == NULL) {
813d438b4efSShailend Chand 		counter_enter();
814d438b4efSShailend Chand 		counter_u64_add_protected(
815d438b4efSShailend Chand 		    tx->stats.tx_delayed_pkt_nospace_compring, 1);
816d438b4efSShailend Chand 		counter_exit();
817d438b4efSShailend Chand 		return (ENOBUFS);
818d438b4efSShailend Chand 	}
819d438b4efSShailend Chand 	completion_tag = pkt - tx->dqo.pending_pkts;
820d438b4efSShailend Chand 
821d438b4efSShailend Chand 	err = gve_map_mbuf_dqo(tx, mbuf_ptr, pkt->dmamap,
822d438b4efSShailend Chand 	    segs, &nsegs, /*attempt=*/0);
823d438b4efSShailend Chand 	if (err)
824d438b4efSShailend Chand 		goto abort;
825d438b4efSShailend Chand 	mbuf = *mbuf_ptr;  /* gve_map_mbuf_dqo might replace the mbuf chain */
826d438b4efSShailend Chand 	pkt->mbuf = mbuf;
827d438b4efSShailend Chand 
828d438b4efSShailend Chand 	total_descs_needed = 1 + /* general_ctx_desc */
829d438b4efSShailend Chand 	    nsegs +              /* pkt_desc */
830d438b4efSShailend Chand 	    (is_tso ? 1 : 0);    /* tso_ctx_desc */
831d438b4efSShailend Chand 	if (__predict_false(
832d438b4efSShailend Chand 	    !gve_tx_has_desc_room_dqo(tx, total_descs_needed))) {
833d438b4efSShailend Chand 		err = ENOBUFS;
834d438b4efSShailend Chand 		goto abort_with_dma;
835d438b4efSShailend Chand 	}
836d438b4efSShailend Chand 
8372348ac89SShailend Chand 	err = gve_tx_fill_ctx_descs(tx, mbuf, is_tso, &desc_idx);
8382348ac89SShailend Chand 	if (err)
839d438b4efSShailend Chand 		goto abort_with_dma;
840d438b4efSShailend Chand 
8412348ac89SShailend Chand 	bus_dmamap_sync(tx->dqo.buf_dmatag, pkt->dmamap, BUS_DMASYNC_PREWRITE);
842d438b4efSShailend Chand 	for (i = 0; i < nsegs; i++) {
843d438b4efSShailend Chand 		gve_tx_fill_pkt_desc_dqo(tx, &desc_idx,
844d438b4efSShailend Chand 		    segs[i].ds_len, segs[i].ds_addr,
845d438b4efSShailend Chand 		    completion_tag, /*eop=*/i == (nsegs - 1),
846d438b4efSShailend Chand 		    has_csum_flag);
847d438b4efSShailend Chand 	}
848d438b4efSShailend Chand 
849d438b4efSShailend Chand 	/* Remember the index of the last desc written */
850d438b4efSShailend Chand 	tx->dqo.desc_tail = desc_idx;
851d438b4efSShailend Chand 
852d438b4efSShailend Chand 	/*
853d438b4efSShailend Chand 	 * Request a descriptor completion on the last descriptor of the
854d438b4efSShailend Chand 	 * packet if we are allowed to by the HW enforced interval.
855d438b4efSShailend Chand 	 */
856d438b4efSShailend Chand 	gve_tx_request_desc_compl(tx, desc_idx);
857d438b4efSShailend Chand 
858d438b4efSShailend Chand 	tx->req += total_descs_needed; /* tx->req is just a sysctl counter */
859d438b4efSShailend Chand 	return (0);
860d438b4efSShailend Chand 
861d438b4efSShailend Chand abort_with_dma:
862d438b4efSShailend Chand 	gve_unmap_packet(tx, pkt);
863d438b4efSShailend Chand abort:
864d438b4efSShailend Chand 	pkt->mbuf = NULL;
865d438b4efSShailend Chand 	gve_free_pending_packet(tx, pkt);
866d438b4efSShailend Chand 	return (err);
867d438b4efSShailend Chand }
868d438b4efSShailend Chand 
8692348ac89SShailend Chand static void
gve_reap_qpl_bufs_dqo(struct gve_tx_ring * tx,struct gve_tx_pending_pkt_dqo * pkt)8702348ac89SShailend Chand gve_reap_qpl_bufs_dqo(struct gve_tx_ring *tx,
8712348ac89SShailend Chand     struct gve_tx_pending_pkt_dqo *pkt)
8722348ac89SShailend Chand {
8732348ac89SShailend Chand 	int32_t buf = pkt->qpl_buf_head;
8742348ac89SShailend Chand 	struct gve_dma_handle *dma;
8752348ac89SShailend Chand 	int32_t qpl_buf_tail;
8762348ac89SShailend Chand 	int32_t old_head;
8772348ac89SShailend Chand 	int i;
8782348ac89SShailend Chand 
8792348ac89SShailend Chand 	for (i = 0; i < pkt->num_qpl_bufs; i++) {
8802348ac89SShailend Chand 		dma = gve_get_page_dma_handle(tx, buf);
8812348ac89SShailend Chand 		bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTWRITE);
8822348ac89SShailend Chand 		qpl_buf_tail = buf;
8832348ac89SShailend Chand 		buf = tx->dqo.qpl_bufs[buf];
8842348ac89SShailend Chand 	}
8852348ac89SShailend Chand 	MPASS(buf == -1);
8862348ac89SShailend Chand 	buf = qpl_buf_tail;
8872348ac89SShailend Chand 
8882348ac89SShailend Chand 	while (true) {
8892348ac89SShailend Chand 		old_head = atomic_load_32(&tx->dqo.free_qpl_bufs_prd);
8902348ac89SShailend Chand 		tx->dqo.qpl_bufs[buf] = old_head;
8912348ac89SShailend Chand 
8922348ac89SShailend Chand 		/*
8932348ac89SShailend Chand 		 * The "rel" ensures that the update to dqo.free_qpl_bufs_prd
8942348ac89SShailend Chand 		 * is visible only after the linked list from this pkt is
8952348ac89SShailend Chand 		 * attached above to old_head.
8962348ac89SShailend Chand 		 */
8972348ac89SShailend Chand 		if (atomic_cmpset_rel_32(&tx->dqo.free_qpl_bufs_prd,
8982348ac89SShailend Chand 		    old_head, pkt->qpl_buf_head))
8992348ac89SShailend Chand 			break;
9002348ac89SShailend Chand 	}
9012348ac89SShailend Chand 	/*
9022348ac89SShailend Chand 	 * The "rel" ensures that the update to dqo.qpl_bufs_produced is
9032348ac89SShailend Chand 	 * visible only adter the update to dqo.free_qpl_bufs_prd above.
9042348ac89SShailend Chand 	 */
9052348ac89SShailend Chand 	atomic_add_rel_32(&tx->dqo.qpl_bufs_produced, pkt->num_qpl_bufs);
9062348ac89SShailend Chand 
90773c3fe4dSJasper Tran O'Leary 	gve_clear_qpl_pending_pkt(pkt);
9082348ac89SShailend Chand }
9092348ac89SShailend Chand 
910d438b4efSShailend Chand static uint64_t
gve_handle_packet_completion(struct gve_priv * priv,struct gve_tx_ring * tx,uint16_t compl_tag)911d438b4efSShailend Chand gve_handle_packet_completion(struct gve_priv *priv,
912d438b4efSShailend Chand     struct gve_tx_ring *tx, uint16_t compl_tag)
913d438b4efSShailend Chand {
914d438b4efSShailend Chand 	struct gve_tx_pending_pkt_dqo *pending_pkt;
915d438b4efSShailend Chand 	int32_t pkt_len;
916d438b4efSShailend Chand 
917d438b4efSShailend Chand 	if (__predict_false(compl_tag >= tx->dqo.num_pending_pkts)) {
918d438b4efSShailend Chand 		device_printf(priv->dev, "Invalid TX completion tag: %d\n",
919d438b4efSShailend Chand 		    compl_tag);
920d438b4efSShailend Chand 		return (0);
921d438b4efSShailend Chand 	}
922d438b4efSShailend Chand 
923d438b4efSShailend Chand 	pending_pkt = &tx->dqo.pending_pkts[compl_tag];
924d438b4efSShailend Chand 
925d438b4efSShailend Chand 	/* Packet is allocated but not pending data completion. */
926d438b4efSShailend Chand 	if (__predict_false(pending_pkt->state !=
927d438b4efSShailend Chand 	    GVE_PACKET_STATE_PENDING_DATA_COMPL)) {
928d438b4efSShailend Chand 		device_printf(priv->dev,
929d438b4efSShailend Chand 		    "No pending data completion: %d\n", compl_tag);
930d438b4efSShailend Chand 		return (0);
931d438b4efSShailend Chand 	}
932d438b4efSShailend Chand 
933d438b4efSShailend Chand 	pkt_len = pending_pkt->mbuf->m_pkthdr.len;
9342348ac89SShailend Chand 
9352348ac89SShailend Chand 	if (gve_is_qpl(priv))
9362348ac89SShailend Chand 		gve_reap_qpl_bufs_dqo(tx, pending_pkt);
9372348ac89SShailend Chand 	else
938d438b4efSShailend Chand 		gve_unmap_packet(tx, pending_pkt);
9392348ac89SShailend Chand 
940d438b4efSShailend Chand 	m_freem(pending_pkt->mbuf);
941d438b4efSShailend Chand 	pending_pkt->mbuf = NULL;
942d438b4efSShailend Chand 	gve_free_pending_packet(tx, pending_pkt);
943d438b4efSShailend Chand 	return (pkt_len);
944d438b4efSShailend Chand }
945d438b4efSShailend Chand 
946d438b4efSShailend Chand int
gve_check_tx_timeout_dqo(struct gve_priv * priv,struct gve_tx_ring * tx)9473d295733SJasper Tran O'Leary gve_check_tx_timeout_dqo(struct gve_priv *priv, struct gve_tx_ring *tx)
9483d295733SJasper Tran O'Leary {
9493d295733SJasper Tran O'Leary 	struct gve_tx_pending_pkt_dqo *pending_pkt;
9503d295733SJasper Tran O'Leary 	int num_timeouts;
9513d295733SJasper Tran O'Leary 	uint16_t pkt_idx;
9523d295733SJasper Tran O'Leary 
9533d295733SJasper Tran O'Leary 	num_timeouts = 0;
9543d295733SJasper Tran O'Leary 	for (pkt_idx = 0; pkt_idx < tx->dqo.num_pending_pkts; pkt_idx++) {
9553d295733SJasper Tran O'Leary 		pending_pkt = &tx->dqo.pending_pkts[pkt_idx];
9563d295733SJasper Tran O'Leary 
9573d295733SJasper Tran O'Leary 		if (!gve_timestamp_valid(&pending_pkt->enqueue_time_sec))
9583d295733SJasper Tran O'Leary 			continue;
9593d295733SJasper Tran O'Leary 
9603d295733SJasper Tran O'Leary 		if (__predict_false(
9613d295733SJasper Tran O'Leary 		    gve_seconds_since(&pending_pkt->enqueue_time_sec) >
9623d295733SJasper Tran O'Leary 		    GVE_TX_TIMEOUT_PKT_SEC))
9633d295733SJasper Tran O'Leary 			num_timeouts += 1;
9643d295733SJasper Tran O'Leary 	}
9653d295733SJasper Tran O'Leary 
9663d295733SJasper Tran O'Leary 	return (num_timeouts);
9673d295733SJasper Tran O'Leary }
9683d295733SJasper Tran O'Leary 
9693d295733SJasper Tran O'Leary int
gve_tx_intr_dqo(void * arg)970d438b4efSShailend Chand gve_tx_intr_dqo(void *arg)
971d438b4efSShailend Chand {
972d438b4efSShailend Chand 	struct gve_tx_ring *tx = arg;
973d438b4efSShailend Chand 	struct gve_priv *priv = tx->com.priv;
974d438b4efSShailend Chand 	struct gve_ring_com *com = &tx->com;
975d438b4efSShailend Chand 
976d438b4efSShailend Chand 	if (__predict_false((if_getdrvflags(priv->ifp) & IFF_DRV_RUNNING) == 0))
977d438b4efSShailend Chand 		return (FILTER_STRAY);
978d438b4efSShailend Chand 
979d438b4efSShailend Chand 	/* Interrupts are automatically masked */
980d438b4efSShailend Chand 	taskqueue_enqueue(com->cleanup_tq, &com->cleanup_task);
981d438b4efSShailend Chand 	return (FILTER_HANDLED);
982d438b4efSShailend Chand }
983d438b4efSShailend Chand 
984d438b4efSShailend Chand static void
gve_tx_clear_desc_ring_dqo(struct gve_tx_ring * tx)985d438b4efSShailend Chand gve_tx_clear_desc_ring_dqo(struct gve_tx_ring *tx)
986d438b4efSShailend Chand {
987d438b4efSShailend Chand 	struct gve_ring_com *com = &tx->com;
988d438b4efSShailend Chand 	int i;
989d438b4efSShailend Chand 
990*46fce000SJasper Tran O'Leary 	for (i = 0; i < com->priv->tx_desc_cnt; i++)
991d438b4efSShailend Chand 		tx->dqo.desc_ring[i] = (union gve_tx_desc_dqo){};
992d438b4efSShailend Chand 
993d438b4efSShailend Chand 	bus_dmamap_sync(tx->desc_ring_mem.tag, tx->desc_ring_mem.map,
994d438b4efSShailend Chand 	    BUS_DMASYNC_PREWRITE);
995d438b4efSShailend Chand }
996d438b4efSShailend Chand 
997d438b4efSShailend Chand static void
gve_tx_clear_compl_ring_dqo(struct gve_tx_ring * tx)998d438b4efSShailend Chand gve_tx_clear_compl_ring_dqo(struct gve_tx_ring *tx)
999d438b4efSShailend Chand {
1000d438b4efSShailend Chand 	struct gve_ring_com *com = &tx->com;
1001d438b4efSShailend Chand 	int entries;
1002d438b4efSShailend Chand 	int i;
1003d438b4efSShailend Chand 
1004d438b4efSShailend Chand 	entries = com->priv->tx_desc_cnt;
1005d438b4efSShailend Chand 	for (i = 0; i < entries; i++)
1006d438b4efSShailend Chand 		tx->dqo.compl_ring[i] = (struct gve_tx_compl_desc_dqo){};
1007d438b4efSShailend Chand 
1008d438b4efSShailend Chand 	bus_dmamap_sync(tx->dqo.compl_ring_mem.tag, tx->dqo.compl_ring_mem.map,
1009d438b4efSShailend Chand 	    BUS_DMASYNC_PREWRITE);
1010d438b4efSShailend Chand }
1011d438b4efSShailend Chand 
1012d438b4efSShailend Chand void
gve_clear_tx_ring_dqo(struct gve_priv * priv,int i)1013d438b4efSShailend Chand gve_clear_tx_ring_dqo(struct gve_priv *priv, int i)
1014d438b4efSShailend Chand {
1015d438b4efSShailend Chand 	struct gve_tx_ring *tx = &priv->tx[i];
1016d438b4efSShailend Chand 	int j;
1017d438b4efSShailend Chand 
1018d438b4efSShailend Chand 	tx->dqo.desc_head = 0;
1019d438b4efSShailend Chand 	tx->dqo.desc_tail = 0;
1020d438b4efSShailend Chand 	tx->dqo.desc_mask = priv->tx_desc_cnt - 1;
1021d438b4efSShailend Chand 	tx->dqo.last_re_idx = 0;
1022d438b4efSShailend Chand 
1023d438b4efSShailend Chand 	tx->dqo.compl_head = 0;
1024d438b4efSShailend Chand 	tx->dqo.compl_mask = priv->tx_desc_cnt - 1;
1025d438b4efSShailend Chand 	atomic_store_32(&tx->dqo.hw_tx_head, 0);
1026d438b4efSShailend Chand 	tx->dqo.cur_gen_bit = 0;
1027d438b4efSShailend Chand 
1028d438b4efSShailend Chand 	gve_free_tx_mbufs_dqo(tx);
1029d438b4efSShailend Chand 
103073c3fe4dSJasper Tran O'Leary 	for (j = 0; j < tx->dqo.num_pending_pkts; j++) {
103173c3fe4dSJasper Tran O'Leary 		if (gve_is_qpl(tx->com.priv))
103273c3fe4dSJasper Tran O'Leary 			gve_clear_qpl_pending_pkt(&tx->dqo.pending_pkts[j]);
1033*46fce000SJasper Tran O'Leary 		gve_invalidate_timestamp(
1034*46fce000SJasper Tran O'Leary 		    &tx->dqo.pending_pkts[j].enqueue_time_sec);
103573c3fe4dSJasper Tran O'Leary 		tx->dqo.pending_pkts[j].next =
103673c3fe4dSJasper Tran O'Leary 		    (j == tx->dqo.num_pending_pkts - 1) ? -1 : j + 1;
1037d438b4efSShailend Chand 		tx->dqo.pending_pkts[j].state = GVE_PACKET_STATE_FREE;
1038d438b4efSShailend Chand 	}
1039d438b4efSShailend Chand 	tx->dqo.free_pending_pkts_csm = 0;
1040d438b4efSShailend Chand 	atomic_store_rel_32(&tx->dqo.free_pending_pkts_prd, -1);
1041d438b4efSShailend Chand 
10422348ac89SShailend Chand 	if (gve_is_qpl(priv)) {
10432348ac89SShailend Chand 		int qpl_buf_cnt = GVE_TX_BUFS_PER_PAGE_DQO *
10442348ac89SShailend Chand 		    tx->com.qpl->num_pages;
10452348ac89SShailend Chand 
10462348ac89SShailend Chand 		for (j = 0; j < qpl_buf_cnt - 1; j++)
10472348ac89SShailend Chand 			tx->dqo.qpl_bufs[j] = j + 1;
10482348ac89SShailend Chand 		tx->dqo.qpl_bufs[j] = -1;
10492348ac89SShailend Chand 
10502348ac89SShailend Chand 		tx->dqo.free_qpl_bufs_csm = 0;
10512348ac89SShailend Chand 		atomic_store_32(&tx->dqo.free_qpl_bufs_prd, -1);
10522348ac89SShailend Chand 		atomic_store_32(&tx->dqo.qpl_bufs_produced, qpl_buf_cnt);
10532348ac89SShailend Chand 		tx->dqo.qpl_bufs_produced_cached = qpl_buf_cnt;
10542348ac89SShailend Chand 		tx->dqo.qpl_bufs_consumed = 0;
10552348ac89SShailend Chand 	}
10562348ac89SShailend Chand 
1057d438b4efSShailend Chand 	gve_tx_clear_desc_ring_dqo(tx);
1058d438b4efSShailend Chand 	gve_tx_clear_compl_ring_dqo(tx);
1059d438b4efSShailend Chand }
1060d438b4efSShailend Chand 
1061b044f125SJasper Tran O'Leary static uint8_t
gve_tx_get_gen_bit(uint8_t * desc)1062b044f125SJasper Tran O'Leary gve_tx_get_gen_bit(uint8_t *desc)
1063b044f125SJasper Tran O'Leary {
1064b044f125SJasper Tran O'Leary 	uint8_t byte;
1065b044f125SJasper Tran O'Leary 
1066b044f125SJasper Tran O'Leary 	/*
1067b044f125SJasper Tran O'Leary 	 * Prevent generation bit from being read after the rest of the
1068b044f125SJasper Tran O'Leary 	 * descriptor.
1069b044f125SJasper Tran O'Leary 	 */
1070b044f125SJasper Tran O'Leary 	byte = atomic_load_acq_8(desc + GVE_TX_DESC_DQO_GEN_BYTE_OFFSET);
1071b044f125SJasper Tran O'Leary 	return ((byte & GVE_TX_DESC_DQO_GEN_BIT_MASK) != 0);
1072b044f125SJasper Tran O'Leary }
1073b044f125SJasper Tran O'Leary 
1074d438b4efSShailend Chand static bool
gve_tx_cleanup_dqo(struct gve_priv * priv,struct gve_tx_ring * tx,int budget)1075d438b4efSShailend Chand gve_tx_cleanup_dqo(struct gve_priv *priv, struct gve_tx_ring *tx, int budget)
1076d438b4efSShailend Chand {
1077d438b4efSShailend Chand 	struct gve_tx_compl_desc_dqo *compl_desc;
1078d438b4efSShailend Chand 	uint64_t bytes_done = 0;
1079d438b4efSShailend Chand 	uint64_t pkts_done = 0;
1080d438b4efSShailend Chand 	uint16_t compl_tag;
1081d438b4efSShailend Chand 	int work_done = 0;
1082d438b4efSShailend Chand 	uint16_t tx_head;
1083d438b4efSShailend Chand 	uint16_t type;
1084d438b4efSShailend Chand 
1085d438b4efSShailend Chand 	while (work_done < budget) {
1086b044f125SJasper Tran O'Leary 		bus_dmamap_sync(tx->dqo.compl_ring_mem.tag,
1087b044f125SJasper Tran O'Leary 		    tx->dqo.compl_ring_mem.map,
1088d438b4efSShailend Chand 		    BUS_DMASYNC_POSTREAD);
1089d438b4efSShailend Chand 
1090d438b4efSShailend Chand 		compl_desc = &tx->dqo.compl_ring[tx->dqo.compl_head];
1091b044f125SJasper Tran O'Leary 		if (gve_tx_get_gen_bit((uint8_t *)compl_desc) ==
1092b044f125SJasper Tran O'Leary 		    tx->dqo.cur_gen_bit)
1093d438b4efSShailend Chand 			break;
1094d438b4efSShailend Chand 
1095d438b4efSShailend Chand 		type = compl_desc->type;
1096d438b4efSShailend Chand 		if (type == GVE_COMPL_TYPE_DQO_DESC) {
1097d438b4efSShailend Chand 			/* This is the last descriptor fetched by HW plus one */
1098d438b4efSShailend Chand 			tx_head = le16toh(compl_desc->tx_head);
1099d438b4efSShailend Chand 			atomic_store_rel_32(&tx->dqo.hw_tx_head, tx_head);
1100d438b4efSShailend Chand 		} else if (type == GVE_COMPL_TYPE_DQO_PKT) {
1101d438b4efSShailend Chand 			compl_tag = le16toh(compl_desc->completion_tag);
1102d438b4efSShailend Chand 			bytes_done += gve_handle_packet_completion(priv,
1103d438b4efSShailend Chand 			    tx, compl_tag);
1104d438b4efSShailend Chand 			pkts_done++;
1105d438b4efSShailend Chand 		}
1106d438b4efSShailend Chand 
1107d438b4efSShailend Chand 		tx->dqo.compl_head = (tx->dqo.compl_head + 1) &
1108d438b4efSShailend Chand 		    tx->dqo.compl_mask;
1109d438b4efSShailend Chand 		/* Flip the generation bit when we wrap around */
1110d438b4efSShailend Chand 		tx->dqo.cur_gen_bit ^= tx->dqo.compl_head == 0;
1111d438b4efSShailend Chand 		work_done++;
1112d438b4efSShailend Chand 	}
1113d438b4efSShailend Chand 
111440097cd6SShailend Chand 	/*
111540097cd6SShailend Chand 	 * Waking the xmit taskqueue has to occur after room has been made in
111640097cd6SShailend Chand 	 * the queue.
111740097cd6SShailend Chand 	 */
111840097cd6SShailend Chand 	atomic_thread_fence_seq_cst();
111940097cd6SShailend Chand 	if (atomic_load_bool(&tx->stopped) && work_done) {
112040097cd6SShailend Chand 		atomic_store_bool(&tx->stopped, false);
112140097cd6SShailend Chand 		taskqueue_enqueue(tx->xmit_tq, &tx->xmit_task);
112240097cd6SShailend Chand 	}
112340097cd6SShailend Chand 
1124d438b4efSShailend Chand 	tx->done += work_done; /* tx->done is just a sysctl counter */
1125d438b4efSShailend Chand 	counter_enter();
1126d438b4efSShailend Chand 	counter_u64_add_protected(tx->stats.tbytes, bytes_done);
1127d438b4efSShailend Chand 	counter_u64_add_protected(tx->stats.tpackets, pkts_done);
1128d438b4efSShailend Chand 	counter_exit();
1129d438b4efSShailend Chand 
1130d438b4efSShailend Chand 	return (work_done == budget);
1131d438b4efSShailend Chand }
1132d438b4efSShailend Chand 
1133d438b4efSShailend Chand void
gve_tx_cleanup_tq_dqo(void * arg,int pending)1134d438b4efSShailend Chand gve_tx_cleanup_tq_dqo(void *arg, int pending)
1135d438b4efSShailend Chand {
1136d438b4efSShailend Chand 	struct gve_tx_ring *tx = arg;
1137d438b4efSShailend Chand 	struct gve_priv *priv = tx->com.priv;
1138d438b4efSShailend Chand 
1139d438b4efSShailend Chand 	if (__predict_false((if_getdrvflags(priv->ifp) & IFF_DRV_RUNNING) == 0))
1140d438b4efSShailend Chand 		return;
1141d438b4efSShailend Chand 
1142d438b4efSShailend Chand 	if (gve_tx_cleanup_dqo(priv, tx, /*budget=*/1024)) {
1143d438b4efSShailend Chand 		taskqueue_enqueue(tx->com.cleanup_tq, &tx->com.cleanup_task);
1144d438b4efSShailend Chand 		return;
1145d438b4efSShailend Chand 	}
1146d438b4efSShailend Chand 
1147d438b4efSShailend Chand 	gve_db_bar_dqo_write_4(priv, tx->com.irq_db_offset,
1148d438b4efSShailend Chand 	    GVE_ITR_NO_UPDATE_DQO | GVE_ITR_ENABLE_BIT_DQO);
1149d438b4efSShailend Chand }
1150