xref: /freebsd/sys/dev/e1000/em_txrx.c (revision 71625ec9)
1d37cece2SSean Bruno /*-
2034f38cdSKevin Bowling  * SPDX-License-Identifier: BSD-2-Clause
3034f38cdSKevin Bowling  *
47021bf05SStephen Hurd  * Copyright (c) 2016 Nicole Graziano <nicole@nextbsd.org>
57021bf05SStephen Hurd  * Copyright (c) 2017 Matthew Macy <mmacy@mattmacy.io>
6d37cece2SSean Bruno  * All rights reserved.
7d37cece2SSean Bruno  *
8d37cece2SSean Bruno  * Redistribution and use in source and binary forms, with or without
9d37cece2SSean Bruno  * modification, are permitted provided that the following conditions
10d37cece2SSean Bruno  * are met:
11d37cece2SSean Bruno  * 1. Redistributions of source code must retain the above copyright
12d37cece2SSean Bruno  *    notice, this list of conditions and the following disclaimer.
13d37cece2SSean Bruno  * 2. Redistributions in binary form must reproduce the above copyright
14d37cece2SSean Bruno  *    notice, this list of conditions and the following disclaimer in the
15d37cece2SSean Bruno  *    documentation and/or other materials provided with the distribution.
16d37cece2SSean Bruno  *
17d37cece2SSean Bruno  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d37cece2SSean Bruno  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d37cece2SSean Bruno  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d37cece2SSean Bruno  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d37cece2SSean Bruno  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d37cece2SSean Bruno  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d37cece2SSean Bruno  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d37cece2SSean Bruno  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d37cece2SSean Bruno  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d37cece2SSean Bruno  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d37cece2SSean Bruno  * SUCH DAMAGE.
28d37cece2SSean Bruno  */
29d37cece2SSean Bruno 
30f2d6ace4SSean Bruno #include "if_em.h"
31f2d6ace4SSean Bruno 
32f2d6ace4SSean Bruno #ifdef RSS
33f2d6ace4SSean Bruno #include <net/rss_config.h>
34f2d6ace4SSean Bruno #include <netinet/in_rss.h>
35f2d6ace4SSean Bruno #endif
36f2d6ace4SSean Bruno 
37f2d6ace4SSean Bruno #ifdef VERBOSE_DEBUG
38f2d6ace4SSean Bruno #define DPRINTF device_printf
39f2d6ace4SSean Bruno #else
40f2d6ace4SSean Bruno #define DPRINTF(...)
41f2d6ace4SSean Bruno #endif
42f2d6ace4SSean Bruno 
43f2d6ace4SSean Bruno /*********************************************************************
44f2d6ace4SSean Bruno  *  Local Function prototypes
45f2d6ace4SSean Bruno  *********************************************************************/
465253d74eSKevin Bowling static int em_tso_setup(struct e1000_softc *sc, if_pkt_info_t pi,
475253d74eSKevin Bowling     uint32_t *txd_upper, uint32_t *txd_lower);
485253d74eSKevin Bowling static int em_transmit_checksum_setup(struct e1000_softc *sc,
495253d74eSKevin Bowling     if_pkt_info_t pi, uint32_t *txd_upper, uint32_t *txd_lower);
50f2d6ace4SSean Bruno static int em_isc_txd_encap(void *arg, if_pkt_info_t pi);
5195246abbSSean Bruno static void em_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx);
5295246abbSSean Bruno static int em_isc_txd_credits_update(void *arg, uint16_t txqid, bool clear);
5395246abbSSean Bruno static void em_isc_rxd_refill(void *arg, if_rxd_update_t iru);
5495246abbSSean Bruno static void em_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused,
5595246abbSSean Bruno     qidx_t pidx);
5695246abbSSean Bruno static int em_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx,
5795246abbSSean Bruno     qidx_t budget);
58f2d6ace4SSean Bruno static int em_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri);
59f2d6ace4SSean Bruno 
6095246abbSSean Bruno static void lem_isc_rxd_refill(void *arg, if_rxd_update_t iru);
61f2d6ace4SSean Bruno 
6295246abbSSean Bruno static int lem_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx,
6395246abbSSean Bruno    qidx_t budget);
64f2d6ace4SSean Bruno static int lem_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri);
65f2d6ace4SSean Bruno 
66015075f3SKevin Bowling static void em_receive_checksum(uint16_t, uint8_t, if_rxd_info_t);
675253d74eSKevin Bowling static int em_determine_rsstype(uint32_t pkt_info);
68f2d6ace4SSean Bruno extern int em_intr(void *arg);
69f2d6ace4SSean Bruno 
70f2d6ace4SSean Bruno struct if_txrx em_txrx = {
71fbf8b74cSMark Johnston 	.ift_txd_encap = em_isc_txd_encap,
72fbf8b74cSMark Johnston 	.ift_txd_flush = em_isc_txd_flush,
73fbf8b74cSMark Johnston 	.ift_txd_credits_update = em_isc_txd_credits_update,
74fbf8b74cSMark Johnston 	.ift_rxd_available = em_isc_rxd_available,
75fbf8b74cSMark Johnston 	.ift_rxd_pkt_get = em_isc_rxd_pkt_get,
76fbf8b74cSMark Johnston 	.ift_rxd_refill = em_isc_rxd_refill,
77fbf8b74cSMark Johnston 	.ift_rxd_flush = em_isc_rxd_flush,
78fbf8b74cSMark Johnston 	.ift_legacy_intr = em_intr
79f2d6ace4SSean Bruno };
80f2d6ace4SSean Bruno 
81f2d6ace4SSean Bruno struct if_txrx lem_txrx = {
82fbf8b74cSMark Johnston 	.ift_txd_encap = em_isc_txd_encap,
83fbf8b74cSMark Johnston 	.ift_txd_flush = em_isc_txd_flush,
84fbf8b74cSMark Johnston 	.ift_txd_credits_update = em_isc_txd_credits_update,
85fbf8b74cSMark Johnston 	.ift_rxd_available = lem_isc_rxd_available,
86fbf8b74cSMark Johnston 	.ift_rxd_pkt_get = lem_isc_rxd_pkt_get,
87fbf8b74cSMark Johnston 	.ift_rxd_refill = lem_isc_rxd_refill,
88fbf8b74cSMark Johnston 	.ift_rxd_flush = em_isc_rxd_flush,
89fbf8b74cSMark Johnston 	.ift_legacy_intr = em_intr
90f2d6ace4SSean Bruno };
91f2d6ace4SSean Bruno 
92f2d6ace4SSean Bruno extern if_shared_ctx_t em_sctx;
93f2d6ace4SSean Bruno 
9495246abbSSean Bruno void
em_dump_rs(struct e1000_softc * sc)95dc926051SKevin Bowling em_dump_rs(struct e1000_softc *sc)
9695246abbSSean Bruno {
97dc926051SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
9895246abbSSean Bruno 	struct em_tx_queue *que;
9995246abbSSean Bruno 	struct tx_ring *txr;
10095246abbSSean Bruno 	qidx_t i, ntxd, qid, cur;
10195246abbSSean Bruno 	int16_t rs_cidx;
10295246abbSSean Bruno 	uint8_t status;
10395246abbSSean Bruno 
10495246abbSSean Bruno 	printf("\n");
10595246abbSSean Bruno 	ntxd = scctx->isc_ntxd[0];
106dc926051SKevin Bowling 	for (qid = 0; qid < sc->tx_num_queues; qid++) {
107dc926051SKevin Bowling 		que = &sc->tx_queues[qid];
10895246abbSSean Bruno 		txr =  &que->txr;
10995246abbSSean Bruno 		rs_cidx = txr->tx_rs_cidx;
11095246abbSSean Bruno 		if (rs_cidx != txr->tx_rs_pidx) {
11195246abbSSean Bruno 			cur = txr->tx_rsq[rs_cidx];
11295246abbSSean Bruno 			status = txr->tx_base[cur].upper.fields.status;
11395246abbSSean Bruno 			if (!(status & E1000_TXD_STAT_DD))
11495246abbSSean Bruno 				printf("qid[%d]->tx_rsq[%d]: %d clear ", qid, rs_cidx, cur);
11595246abbSSean Bruno 		} else {
11695246abbSSean Bruno 			rs_cidx = (rs_cidx-1)&(ntxd-1);
11795246abbSSean Bruno 			cur = txr->tx_rsq[rs_cidx];
11895246abbSSean Bruno 			printf("qid[%d]->tx_rsq[rs_cidx-1=%d]: %d  ", qid, rs_cidx, cur);
11995246abbSSean Bruno 		}
1205253d74eSKevin Bowling 		printf("cidx_prev=%d rs_pidx=%d ",txr->tx_cidx_processed,
1215253d74eSKevin Bowling 		    txr->tx_rs_pidx);
12295246abbSSean Bruno 		for (i = 0; i < ntxd; i++) {
12395246abbSSean Bruno 			if (txr->tx_base[i].upper.fields.status & E1000_TXD_STAT_DD)
12495246abbSSean Bruno 				printf("%d set ", i);
12595246abbSSean Bruno 		}
12695246abbSSean Bruno 		printf("\n");
12795246abbSSean Bruno 	}
12895246abbSSean Bruno }
12995246abbSSean Bruno 
130f2d6ace4SSean Bruno /**********************************************************************
131f2d6ace4SSean Bruno  *
132f2d6ace4SSean Bruno  *  Setup work for hardware segmentation offload (TSO) on
133f2d6ace4SSean Bruno  *  adapters using advanced tx descriptors
134f2d6ace4SSean Bruno  *
135f2d6ace4SSean Bruno  **********************************************************************/
136f2d6ace4SSean Bruno static int
em_tso_setup(struct e1000_softc * sc,if_pkt_info_t pi,uint32_t * txd_upper,uint32_t * txd_lower)1375253d74eSKevin Bowling em_tso_setup(struct e1000_softc *sc, if_pkt_info_t pi, uint32_t *txd_upper,
1385253d74eSKevin Bowling     uint32_t *txd_lower)
139f2d6ace4SSean Bruno {
140dc926051SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
141dc926051SKevin Bowling 	struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx];
142f2d6ace4SSean Bruno 	struct tx_ring *txr = &que->txr;
143f2d6ace4SSean Bruno 	struct e1000_context_desc *TXD;
144f2d6ace4SSean Bruno 	int cur, hdr_len;
145201c4b7cSKevin Bowling 	uint32_t cmd_type_len;
146f2d6ace4SSean Bruno 
147f2d6ace4SSean Bruno 	hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
148f2d6ace4SSean Bruno 	*txd_lower = (E1000_TXD_CMD_DEXT |	/* Extended descr type */
149f2d6ace4SSean Bruno 		      E1000_TXD_DTYP_D |	/* Data descr type */
150f2d6ace4SSean Bruno 		      E1000_TXD_CMD_TSE);	/* Do TSE on this packet */
151f2d6ace4SSean Bruno 
152f2d6ace4SSean Bruno 	cur = pi->ipi_pidx;
153f2d6ace4SSean Bruno 	TXD = (struct e1000_context_desc *)&txr->tx_base[cur];
154f2d6ace4SSean Bruno 
155f2d6ace4SSean Bruno 	/*
156e1353dcbSKevin Bowling 	 * ipcss - Start offset for header checksum calculation.
157e1353dcbSKevin Bowling 	 * ipcse - End offset for header checksum calculation.
158e1353dcbSKevin Bowling 	 * ipcso - Offset of place to put the checksum.
159f2d6ace4SSean Bruno 	 */
160e1353dcbSKevin Bowling 	switch(pi->ipi_etype) {
161e1353dcbSKevin Bowling 	case ETHERTYPE_IP:
162e1353dcbSKevin Bowling 		/* IP and/or TCP header checksum calculation and insertion. */
163e1353dcbSKevin Bowling 		*txd_upper = (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8;
164e1353dcbSKevin Bowling 
165f2d6ace4SSean Bruno 		TXD->lower_setup.ip_fields.ipcse =
166f2d6ace4SSean Bruno 		    htole16(pi->ipi_ehdrlen + pi->ipi_ip_hlen - 1);
167e1353dcbSKevin Bowling 		break;
168e1353dcbSKevin Bowling 	case ETHERTYPE_IPV6:
169e1353dcbSKevin Bowling 		/* TCP header checksum calculation and insertion. */
170e1353dcbSKevin Bowling 		*txd_upper = E1000_TXD_POPTS_TXSM << 8;
171e1353dcbSKevin Bowling 
172e1353dcbSKevin Bowling 		TXD->lower_setup.ip_fields.ipcse = htole16(0);
173e1353dcbSKevin Bowling 		break;
174e1353dcbSKevin Bowling 	default:
175e1353dcbSKevin Bowling 		break;
176e1353dcbSKevin Bowling 	}
177e1353dcbSKevin Bowling 	TXD->lower_setup.ip_fields.ipcss = pi->ipi_ehdrlen;
1785253d74eSKevin Bowling 	TXD->lower_setup.ip_fields.ipcso =
1795253d74eSKevin Bowling 	    pi->ipi_ehdrlen + offsetof(struct ip, ip_sum);
180f2d6ace4SSean Bruno 
181f2d6ace4SSean Bruno 	/*
182e1353dcbSKevin Bowling 	 * tucss - Start offset for payload checksum calculation.
183e1353dcbSKevin Bowling 	 * tucse - End offset for payload checksum calculation.
184e1353dcbSKevin Bowling 	 * tucso - Offset of place to put the checksum.
185f2d6ace4SSean Bruno 	 */
186f2d6ace4SSean Bruno 	TXD->upper_setup.tcp_fields.tucss = pi->ipi_ehdrlen + pi->ipi_ip_hlen;
187f2d6ace4SSean Bruno 	TXD->upper_setup.tcp_fields.tucse = 0;
188f2d6ace4SSean Bruno 	TXD->upper_setup.tcp_fields.tucso =
189f2d6ace4SSean Bruno 	    pi->ipi_ehdrlen + pi->ipi_ip_hlen + offsetof(struct tcphdr, th_sum);
190f2d6ace4SSean Bruno 
191f2d6ace4SSean Bruno 	/*
192f2d6ace4SSean Bruno 	 * Payload size per packet w/o any headers.
193f2d6ace4SSean Bruno 	 * Length of all headers up to payload.
194f2d6ace4SSean Bruno 	 */
195f2d6ace4SSean Bruno 	TXD->tcp_seg_setup.fields.mss = htole16(pi->ipi_tso_segsz);
196f2d6ace4SSean Bruno 	TXD->tcp_seg_setup.fields.hdr_len = hdr_len;
197f2d6ace4SSean Bruno 
198201c4b7cSKevin Bowling 	/*
199cbcab907SKevin Bowling 	 * "PCI/PCI-X SDM 4.0" page 45, and "PCIe GbE SDM 2.5" page 63
200201c4b7cSKevin Bowling 	 * - Set up basic TUCMDs
201201c4b7cSKevin Bowling 	 * - For others IP bit on indicates IPv4, while off indicates IPv6
202201c4b7cSKevin Bowling 	*/
203201c4b7cSKevin Bowling 	cmd_type_len = sc->txd_cmd |
204f2d6ace4SSean Bruno 	    E1000_TXD_CMD_DEXT | /* Extended descr */
205f2d6ace4SSean Bruno 	    E1000_TXD_CMD_TSE |  /* TSE context */
206201c4b7cSKevin Bowling 	    E1000_TXD_CMD_TCP;   /* Do TCP checksum */
207e1353dcbSKevin Bowling 	if (pi->ipi_etype == ETHERTYPE_IP)
208201c4b7cSKevin Bowling 		cmd_type_len |= E1000_TXD_CMD_IP;
209201c4b7cSKevin Bowling 	TXD->cmd_and_length = htole32(cmd_type_len |
210f2d6ace4SSean Bruno 	    (pi->ipi_len - hdr_len)); /* Total len */
211201c4b7cSKevin Bowling 
2121bbdc25fSKevin Bowling 	txr->tx_tso = true;
213f2d6ace4SSean Bruno 
214f2d6ace4SSean Bruno 	if (++cur == scctx->isc_ntxd[0]) {
215f2d6ace4SSean Bruno 		cur = 0;
216f2d6ace4SSean Bruno 	}
2175253d74eSKevin Bowling 	DPRINTF(iflib_get_dev(sc->ctx), "%s: pidx: %d cur: %d\n", __FUNCTION__,
2185253d74eSKevin Bowling 	    pi->ipi_pidx, cur);
219f2d6ace4SSean Bruno 	return (cur);
220f2d6ace4SSean Bruno }
221f2d6ace4SSean Bruno 
222f2d6ace4SSean Bruno /*********************************************************************
223f2d6ace4SSean Bruno  *  The offload context is protocol specific (TCP/UDP) and thus
224f2d6ace4SSean Bruno  *  only needs to be set when the protocol changes. The occasion
225f2d6ace4SSean Bruno  *  of a context change can be a performance detriment, and
226f2d6ace4SSean Bruno  *  might be better just disabled. The reason arises in the way
227f2d6ace4SSean Bruno  *  in which the controller supports pipelined requests from the
228f2d6ace4SSean Bruno  *  Tx data DMA. Up to four requests can be pipelined, and they may
229f2d6ace4SSean Bruno  *  belong to the same packet or to multiple packets. However all
230f2d6ace4SSean Bruno  *  requests for one packet are issued before a request is issued
231f2d6ace4SSean Bruno  *  for a subsequent packet and if a request for the next packet
232f2d6ace4SSean Bruno  *  requires a context change, that request will be stalled
233f2d6ace4SSean Bruno  *  until the previous request completes. This means setting up
234f2d6ace4SSean Bruno  *  a new context effectively disables pipelined Tx data DMA which
235f2d6ace4SSean Bruno  *  in turn greatly slow down performance to send small sized
236f2d6ace4SSean Bruno  *  frames.
237f2d6ace4SSean Bruno  **********************************************************************/
238cbcab907SKevin Bowling #define DONT_FORCE_CTX 1
239f2d6ace4SSean Bruno 
240f2d6ace4SSean Bruno static int
em_transmit_checksum_setup(struct e1000_softc * sc,if_pkt_info_t pi,uint32_t * txd_upper,uint32_t * txd_lower)2415253d74eSKevin Bowling em_transmit_checksum_setup(struct e1000_softc *sc, if_pkt_info_t pi,
2425253d74eSKevin Bowling     uint32_t *txd_upper, uint32_t *txd_lower)
243f2d6ace4SSean Bruno {
244f2d6ace4SSean Bruno 	struct e1000_context_desc *TXD = NULL;
245dc926051SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
246dc926051SKevin Bowling 	struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx];
247f2d6ace4SSean Bruno 	struct tx_ring *txr = &que->txr;
248f2d6ace4SSean Bruno 	int csum_flags = pi->ipi_csum_flags;
249f2d6ace4SSean Bruno 	int cur, hdr_len;
2505253d74eSKevin Bowling 	uint32_t cmd;
251f2d6ace4SSean Bruno 
252f2d6ace4SSean Bruno 	cur = pi->ipi_pidx;
253f2d6ace4SSean Bruno 	hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen;
254dc926051SKevin Bowling 	cmd = sc->txd_cmd;
255f2d6ace4SSean Bruno 
256f2d6ace4SSean Bruno 	/*
257f2d6ace4SSean Bruno 	 * The 82574L can only remember the *last* context used
258f2d6ace4SSean Bruno 	 * regardless of queue that it was use for.  We cannot reuse
259f2d6ace4SSean Bruno 	 * contexts on this hardware platform and must generate a new
260f2d6ace4SSean Bruno 	 * context every time.  82574L hardware spec, section 7.2.6,
261f2d6ace4SSean Bruno 	 * second note.
262f2d6ace4SSean Bruno 	 */
263f2d6ace4SSean Bruno 	if (DONT_FORCE_CTX &&
264dc926051SKevin Bowling 	    sc->tx_num_queues == 1 &&
265f2d6ace4SSean Bruno 	    txr->csum_lhlen == pi->ipi_ehdrlen &&
266f2d6ace4SSean Bruno 	    txr->csum_iphlen == pi->ipi_ip_hlen &&
267f2d6ace4SSean Bruno 	    txr->csum_flags == csum_flags) {
268f2d6ace4SSean Bruno 		/*
269f2d6ace4SSean Bruno 		 * Same csum offload context as the previous packets;
270f2d6ace4SSean Bruno 		 * just return.
271f2d6ace4SSean Bruno 		 */
272f2d6ace4SSean Bruno 		*txd_upper = txr->csum_txd_upper;
273f2d6ace4SSean Bruno 		*txd_lower = txr->csum_txd_lower;
274f2d6ace4SSean Bruno 		return (cur);
275f2d6ace4SSean Bruno 	}
276f2d6ace4SSean Bruno 
277f2d6ace4SSean Bruno 	TXD = (struct e1000_context_desc *)&txr->tx_base[cur];
278f2d6ace4SSean Bruno 	/*
279cbcab907SKevin Bowling 	 * ipcss - Start offset for header checksum calculation.
280cbcab907SKevin Bowling 	 * ipcse - End offset for header checksum calculation.
281cbcab907SKevin Bowling 	 * ipcso - Offset of place to put the checksum.
282cbcab907SKevin Bowling 	 *
283cbcab907SKevin Bowling 	 * We set ipcsX values regardless of IP version to work around HW issues
284cbcab907SKevin Bowling 	 * and ipcse must be 0 for IPv6 per "PCIe GbE SDM 2.5" page 61.
285cbcab907SKevin Bowling 	 * IXSM controls whether it's inserted.
286f2d6ace4SSean Bruno 	 */
287f2d6ace4SSean Bruno 	TXD->lower_setup.ip_fields.ipcss = pi->ipi_ehdrlen;
2885253d74eSKevin Bowling 	TXD->lower_setup.ip_fields.ipcso = pi->ipi_ehdrlen +
2895253d74eSKevin Bowling 	    offsetof(struct ip, ip_sum);
290cbcab907SKevin Bowling 	if (csum_flags & CSUM_IP) {
291cbcab907SKevin Bowling 		*txd_upper |= E1000_TXD_POPTS_IXSM << 8;
292eac761e9SKevin Bowling 		TXD->lower_setup.ip_fields.ipcse = htole16(hdr_len - 1);
293f2d6ace4SSean Bruno 		cmd |= E1000_TXD_CMD_IP;
294cbcab907SKevin Bowling 	} else if (csum_flags & (CSUM_IP6_TCP | CSUM_IP6_UDP))
295cbcab907SKevin Bowling 		TXD->lower_setup.ip_fields.ipcse = htole16(0);
296f2d6ace4SSean Bruno 
297cbcab907SKevin Bowling 	/*
298cbcab907SKevin Bowling 	 * tucss - Start offset for payload checksum calculation.
299cbcab907SKevin Bowling 	 * tucse - End offset for payload checksum calculation.
300cbcab907SKevin Bowling 	 * tucso - Offset of place to put the checksum.
301cbcab907SKevin Bowling 	 */
3024f9a44a2SKevin Bowling 	if (csum_flags & (CSUM_TCP | CSUM_UDP | CSUM_IP6_TCP | CSUM_IP6_UDP)) {
303f2d6ace4SSean Bruno 		uint8_t tucso;
304f2d6ace4SSean Bruno 
305f2d6ace4SSean Bruno 		*txd_upper |= E1000_TXD_POPTS_TXSM << 8;
306f2d6ace4SSean Bruno 		*txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
307f2d6ace4SSean Bruno 
30892fd2f39SKevin Bowling 		if (csum_flags & (CSUM_TCP | CSUM_IP6_TCP)) {
309f2d6ace4SSean Bruno 			tucso = hdr_len + offsetof(struct tcphdr, th_sum);
310f2d6ace4SSean Bruno 			cmd |= E1000_TXD_CMD_TCP;
311f2d6ace4SSean Bruno 		} else
312f2d6ace4SSean Bruno 			tucso = hdr_len + offsetof(struct udphdr, uh_sum);
313f2d6ace4SSean Bruno 		TXD->upper_setup.tcp_fields.tucss = hdr_len;
314f2d6ace4SSean Bruno 		TXD->upper_setup.tcp_fields.tucse = htole16(0);
315f2d6ace4SSean Bruno 		TXD->upper_setup.tcp_fields.tucso = tucso;
316f2d6ace4SSean Bruno 	}
317f2d6ace4SSean Bruno 
318f2d6ace4SSean Bruno 	txr->csum_lhlen = pi->ipi_ehdrlen;
319f2d6ace4SSean Bruno 	txr->csum_iphlen = pi->ipi_ip_hlen;
320f2d6ace4SSean Bruno 	txr->csum_flags = csum_flags;
321f2d6ace4SSean Bruno 	txr->csum_txd_upper = *txd_upper;
322f2d6ace4SSean Bruno 	txr->csum_txd_lower = *txd_lower;
323f2d6ace4SSean Bruno 
324f2d6ace4SSean Bruno 	TXD->tcp_seg_setup.data = htole32(0);
325f2d6ace4SSean Bruno 	TXD->cmd_and_length =
326f2d6ace4SSean Bruno 		htole32(E1000_TXD_CMD_IFCS | E1000_TXD_CMD_DEXT | cmd);
327f2d6ace4SSean Bruno 
328f2d6ace4SSean Bruno 	if (++cur == scctx->isc_ntxd[0]) {
329f2d6ace4SSean Bruno 		cur = 0;
330f2d6ace4SSean Bruno 	}
3315253d74eSKevin Bowling 	DPRINTF(iflib_get_dev(sc->ctx),
3325253d74eSKevin Bowling 	    "checksum_setup csum_flags=%x txd_upper=%x txd_lower=%x hdr_len=%d cmd=%x\n",
333f2d6ace4SSean Bruno 	    csum_flags, *txd_upper, *txd_lower, hdr_len, cmd);
334f2d6ace4SSean Bruno 	return (cur);
335f2d6ace4SSean Bruno }
336f2d6ace4SSean Bruno 
337cbcab907SKevin Bowling #define TSO_WORKAROUND 4 /* TSO sentinel descriptor */
338cbcab907SKevin Bowling 
339f2d6ace4SSean Bruno static int
em_isc_txd_encap(void * arg,if_pkt_info_t pi)340f2d6ace4SSean Bruno em_isc_txd_encap(void *arg, if_pkt_info_t pi)
341f2d6ace4SSean Bruno {
342dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
343f2d6ace4SSean Bruno 	if_softc_ctx_t scctx = sc->shared;
344f2d6ace4SSean Bruno 	struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx];
345f2d6ace4SSean Bruno 	struct tx_ring *txr = &que->txr;
346f2d6ace4SSean Bruno 	bus_dma_segment_t *segs = pi->ipi_segs;
347f2d6ace4SSean Bruno 	int nsegs = pi->ipi_nsegs;
348f2d6ace4SSean Bruno 	int csum_flags = pi->ipi_csum_flags;
349f2d6ace4SSean Bruno 	int i, j, first, pidx_last;
3505253d74eSKevin Bowling 	uint32_t txd_flags, txd_upper = 0, txd_lower = 0;
351f2d6ace4SSean Bruno 
352f2d6ace4SSean Bruno 	struct e1000_tx_desc *ctxd = NULL;
353f2d6ace4SSean Bruno 	bool do_tso, tso_desc;
35495246abbSSean Bruno 	qidx_t ntxd;
355f2d6ace4SSean Bruno 
35695246abbSSean Bruno 	txd_flags = pi->ipi_flags & IPI_TX_INTR ? E1000_TXD_CMD_RS : 0;
357f2d6ace4SSean Bruno 	i = first = pi->ipi_pidx;
358f2d6ace4SSean Bruno 	do_tso = (csum_flags & CSUM_TSO);
3591bbdc25fSKevin Bowling 	tso_desc = false;
36095246abbSSean Bruno 	ntxd = scctx->isc_ntxd[0];
361f2d6ace4SSean Bruno 	/*
362f2d6ace4SSean Bruno 	 * TSO Hardware workaround, if this packet is not
363f2d6ace4SSean Bruno 	 * TSO, and is only a single descriptor long, and
364f2d6ace4SSean Bruno 	 * it follows a TSO burst, then we need to add a
365f2d6ace4SSean Bruno 	 * sentinel descriptor to prevent premature writeback.
366f2d6ace4SSean Bruno 	 */
3671bbdc25fSKevin Bowling 	if ((!do_tso) && (txr->tx_tso == true)) {
368f2d6ace4SSean Bruno 		if (nsegs == 1)
3691bbdc25fSKevin Bowling 			tso_desc = true;
3701bbdc25fSKevin Bowling 		txr->tx_tso = false;
371f2d6ace4SSean Bruno 	}
372f2d6ace4SSean Bruno 
373f2d6ace4SSean Bruno 	/* Do hardware assists */
374f2d6ace4SSean Bruno 	if (do_tso) {
375f2d6ace4SSean Bruno 		i = em_tso_setup(sc, pi, &txd_upper, &txd_lower);
3761bbdc25fSKevin Bowling 		tso_desc = true;
37782379056SSean Bruno 	} else if (csum_flags & EM_CSUM_OFFLOAD) {
378f2d6ace4SSean Bruno 		i = em_transmit_checksum_setup(sc, pi, &txd_upper, &txd_lower);
379f2d6ace4SSean Bruno 	}
380f2d6ace4SSean Bruno 
381f2d6ace4SSean Bruno 	if (pi->ipi_mflags & M_VLANTAG) {
382f2d6ace4SSean Bruno 		/* Set the vlan id. */
383f2d6ace4SSean Bruno 		txd_upper |= htole16(pi->ipi_vtag) << 16;
384f2d6ace4SSean Bruno 		/* Tell hardware to add tag */
385f2d6ace4SSean Bruno 		txd_lower |= htole32(E1000_TXD_CMD_VLE);
386f2d6ace4SSean Bruno 	}
387f2d6ace4SSean Bruno 
3885253d74eSKevin Bowling 	DPRINTF(iflib_get_dev(sc->ctx),
3895253d74eSKevin Bowling 	    "encap: set up tx: nsegs=%d first=%d i=%d\n", nsegs, first, i);
390dc926051SKevin Bowling 	/* XXX sc->pcix_82544 -- lem_fill_descriptors */
391f2d6ace4SSean Bruno 
392f2d6ace4SSean Bruno 	/* Set up our transmit descriptors */
393f2d6ace4SSean Bruno 	for (j = 0; j < nsegs; j++) {
394f2d6ace4SSean Bruno 		bus_size_t seg_len;
395f2d6ace4SSean Bruno 		bus_addr_t seg_addr;
396f2d6ace4SSean Bruno 		uint32_t cmd;
397f2d6ace4SSean Bruno 
398f2d6ace4SSean Bruno 		ctxd = &txr->tx_base[i];
399f2d6ace4SSean Bruno 		seg_addr = segs[j].ds_addr;
400f2d6ace4SSean Bruno 		seg_len = segs[j].ds_len;
401f2d6ace4SSean Bruno 		cmd = E1000_TXD_CMD_IFCS | sc->txd_cmd;
402f2d6ace4SSean Bruno 
403f2d6ace4SSean Bruno 		/*
40495246abbSSean Bruno 		 * TSO Workaround:
40595246abbSSean Bruno 		 * If this is the last descriptor, we want to
40695246abbSSean Bruno 		 * split it so we have a small final sentinel
407f2d6ace4SSean Bruno 		 */
408f2d6ace4SSean Bruno 		if (tso_desc && (j == (nsegs - 1)) && (seg_len > 8)) {
409f2d6ace4SSean Bruno 			seg_len -= TSO_WORKAROUND;
410f2d6ace4SSean Bruno 			ctxd->buffer_addr = htole64(seg_addr);
411f2d6ace4SSean Bruno 			ctxd->lower.data = htole32(cmd | txd_lower | seg_len);
412f2d6ace4SSean Bruno 			ctxd->upper.data = htole32(txd_upper);
413f2d6ace4SSean Bruno 
414f2d6ace4SSean Bruno 			if (++i == scctx->isc_ntxd[0])
415f2d6ace4SSean Bruno 				i = 0;
416f2d6ace4SSean Bruno 
417f2d6ace4SSean Bruno 			/* Now make the sentinel */
418f2d6ace4SSean Bruno 			ctxd = &txr->tx_base[i];
419f2d6ace4SSean Bruno 			ctxd->buffer_addr = htole64(seg_addr + seg_len);
420f2d6ace4SSean Bruno 			ctxd->lower.data = htole32(cmd | txd_lower | TSO_WORKAROUND);
421f2d6ace4SSean Bruno 			ctxd->upper.data = htole32(txd_upper);
422f2d6ace4SSean Bruno 			pidx_last = i;
423f2d6ace4SSean Bruno 			if (++i == scctx->isc_ntxd[0])
424f2d6ace4SSean Bruno 				i = 0;
4255253d74eSKevin Bowling 			DPRINTF(iflib_get_dev(sc->ctx),
4265253d74eSKevin Bowling 			    "TSO path pidx_last=%d i=%d ntxd[0]=%d\n",
4275253d74eSKevin Bowling 			    pidx_last, i, scctx->isc_ntxd[0]);
428f2d6ace4SSean Bruno 		} else {
429f2d6ace4SSean Bruno 			ctxd->buffer_addr = htole64(seg_addr);
430f2d6ace4SSean Bruno 			ctxd->lower.data = htole32(cmd | txd_lower | seg_len);
431f2d6ace4SSean Bruno 			ctxd->upper.data = htole32(txd_upper);
432f2d6ace4SSean Bruno 			pidx_last = i;
433f2d6ace4SSean Bruno 			if (++i == scctx->isc_ntxd[0])
434f2d6ace4SSean Bruno 				i = 0;
4355253d74eSKevin Bowling 			DPRINTF(iflib_get_dev(sc->ctx), "pidx_last=%d i=%d ntxd[0]=%d\n",
4365253d74eSKevin Bowling 			    pidx_last, i, scctx->isc_ntxd[0]);
437f2d6ace4SSean Bruno 		}
438f2d6ace4SSean Bruno 	}
439f2d6ace4SSean Bruno 
440f2d6ace4SSean Bruno 	/*
441f2d6ace4SSean Bruno 	 * Last Descriptor of Packet
442f2d6ace4SSean Bruno 	 * needs End Of Packet (EOP)
443f2d6ace4SSean Bruno 	 * and Report Status (RS)
444f2d6ace4SSean Bruno 	 */
4458fd222ebSMatt Macy 	if (txd_flags && nsegs) {
44695246abbSSean Bruno 		txr->tx_rsq[txr->tx_rs_pidx] = pidx_last;
4475253d74eSKevin Bowling 		DPRINTF(iflib_get_dev(sc->ctx),
4485253d74eSKevin Bowling 		    "setting to RS on %d rs_pidx %d first: %d\n",
4495253d74eSKevin Bowling 		    pidx_last, txr->tx_rs_pidx, first);
45095246abbSSean Bruno 		txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & (ntxd-1);
45195246abbSSean Bruno 		MPASS(txr->tx_rs_pidx != txr->tx_rs_cidx);
45295246abbSSean Bruno 	}
45395246abbSSean Bruno 	ctxd->lower.data |= htole32(E1000_TXD_CMD_EOP | txd_flags);
4545253d74eSKevin Bowling 	DPRINTF(iflib_get_dev(sc->ctx),
4555253d74eSKevin Bowling 	    "tx_buffers[%d]->eop = %d ipi_new_pidx=%d\n", first, pidx_last, i);
456f2d6ace4SSean Bruno 	pi->ipi_new_pidx = i;
457f2d6ace4SSean Bruno 
458f2d6ace4SSean Bruno 	return (0);
459f2d6ace4SSean Bruno }
460f2d6ace4SSean Bruno 
461f2d6ace4SSean Bruno static void
em_isc_txd_flush(void * arg,uint16_t txqid,qidx_t pidx)46295246abbSSean Bruno em_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
463f2d6ace4SSean Bruno {
464dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
465dc926051SKevin Bowling 	struct em_tx_queue *que = &sc->tx_queues[txqid];
466f2d6ace4SSean Bruno 	struct tx_ring *txr = &que->txr;
467f2d6ace4SSean Bruno 
468dc926051SKevin Bowling 	E1000_WRITE_REG(&sc->hw, E1000_TDT(txr->me), pidx);
469f2d6ace4SSean Bruno }
470f2d6ace4SSean Bruno 
471f2d6ace4SSean Bruno static int
em_isc_txd_credits_update(void * arg,uint16_t txqid,bool clear)47295246abbSSean Bruno em_isc_txd_credits_update(void *arg, uint16_t txqid, bool clear)
473f2d6ace4SSean Bruno {
474dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
475dc926051SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
476dc926051SKevin Bowling 	struct em_tx_queue *que = &sc->tx_queues[txqid];
477f2d6ace4SSean Bruno 	struct tx_ring *txr = &que->txr;
478f2d6ace4SSean Bruno 
47995246abbSSean Bruno 	qidx_t processed = 0;
48095246abbSSean Bruno 	int updated;
48195246abbSSean Bruno 	qidx_t cur, prev, ntxd, rs_cidx;
48295246abbSSean Bruno 	int32_t delta;
48395246abbSSean Bruno 	uint8_t status;
484f2d6ace4SSean Bruno 
48595246abbSSean Bruno 	rs_cidx = txr->tx_rs_cidx;
48695246abbSSean Bruno 	if (rs_cidx == txr->tx_rs_pidx)
48795246abbSSean Bruno 		return (0);
48895246abbSSean Bruno 	cur = txr->tx_rsq[rs_cidx];
48995246abbSSean Bruno 	MPASS(cur != QIDX_INVALID);
49095246abbSSean Bruno 	status = txr->tx_base[cur].upper.fields.status;
49195246abbSSean Bruno 	updated = !!(status & E1000_TXD_STAT_DD);
492f2d6ace4SSean Bruno 
493adf93b56SEric Joyner 	if (!updated)
494adf93b56SEric Joyner 		return (0);
495adf93b56SEric Joyner 
496adf93b56SEric Joyner 	/* If clear is false just let caller know that there
497adf93b56SEric Joyner 	 * are descriptors to reclaim */
498adf93b56SEric Joyner 	if (!clear)
499adf93b56SEric Joyner 		return (1);
50095246abbSSean Bruno 
50195246abbSSean Bruno 	prev = txr->tx_cidx_processed;
50295246abbSSean Bruno 	ntxd = scctx->isc_ntxd[0];
50395246abbSSean Bruno 	do {
504088a0b27SEric Joyner 		MPASS(prev != cur);
50595246abbSSean Bruno 		delta = (int32_t)cur - (int32_t)prev;
50695246abbSSean Bruno 		if (delta < 0)
50795246abbSSean Bruno 			delta += ntxd;
508088a0b27SEric Joyner 		MPASS(delta > 0);
509dc926051SKevin Bowling 		DPRINTF(iflib_get_dev(sc->ctx),
51095246abbSSean Bruno 			      "%s: cidx_processed=%u cur=%u clear=%d delta=%d\n",
51195246abbSSean Bruno 			      __FUNCTION__, prev, cur, clear, delta);
512f2d6ace4SSean Bruno 
51395246abbSSean Bruno 		processed += delta;
51495246abbSSean Bruno 		prev  = cur;
51595246abbSSean Bruno 		rs_cidx = (rs_cidx + 1) & (ntxd-1);
51695246abbSSean Bruno 		if (rs_cidx  == txr->tx_rs_pidx)
517f2d6ace4SSean Bruno 			break;
51895246abbSSean Bruno 		cur = txr->tx_rsq[rs_cidx];
51995246abbSSean Bruno 		MPASS(cur != QIDX_INVALID);
52095246abbSSean Bruno 		status = txr->tx_base[cur].upper.fields.status;
52195246abbSSean Bruno 	} while ((status & E1000_TXD_STAT_DD));
522f2d6ace4SSean Bruno 
52395246abbSSean Bruno 	txr->tx_rs_cidx = rs_cidx;
52495246abbSSean Bruno 	txr->tx_cidx_processed = prev;
525f2d6ace4SSean Bruno 	return(processed);
526f2d6ace4SSean Bruno }
527f2d6ace4SSean Bruno 
528f2d6ace4SSean Bruno static void
lem_isc_rxd_refill(void * arg,if_rxd_update_t iru)52995246abbSSean Bruno lem_isc_rxd_refill(void *arg, if_rxd_update_t iru)
530f2d6ace4SSean Bruno {
531dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
532f2d6ace4SSean Bruno 	if_softc_ctx_t scctx = sc->shared;
53395246abbSSean Bruno 	struct em_rx_queue *que = &sc->rx_queues[iru->iru_qsidx];
534f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
535f2d6ace4SSean Bruno 	struct e1000_rx_desc *rxd;
53695246abbSSean Bruno 	uint64_t *paddrs;
53795246abbSSean Bruno 	uint32_t next_pidx, pidx;
53895246abbSSean Bruno 	uint16_t count;
539f2d6ace4SSean Bruno 	int i;
54095246abbSSean Bruno 
54195246abbSSean Bruno 	paddrs = iru->iru_paddrs;
54295246abbSSean Bruno 	pidx = iru->iru_pidx;
54395246abbSSean Bruno 	count = iru->iru_count;
544f2d6ace4SSean Bruno 
545f2d6ace4SSean Bruno 	for (i = 0, next_pidx = pidx; i < count; i++) {
546f2d6ace4SSean Bruno 		rxd = (struct e1000_rx_desc *)&rxr->rx_base[next_pidx];
547f2d6ace4SSean Bruno 		rxd->buffer_addr = htole64(paddrs[i]);
548f2d6ace4SSean Bruno 		/* status bits must be cleared */
549f2d6ace4SSean Bruno 		rxd->status = 0;
550f2d6ace4SSean Bruno 
551f2d6ace4SSean Bruno 		if (++next_pidx == scctx->isc_nrxd[0])
552f2d6ace4SSean Bruno 			next_pidx = 0;
553f2d6ace4SSean Bruno 	}
554f2d6ace4SSean Bruno }
555f2d6ace4SSean Bruno 
556f2d6ace4SSean Bruno static void
em_isc_rxd_refill(void * arg,if_rxd_update_t iru)55795246abbSSean Bruno em_isc_rxd_refill(void *arg, if_rxd_update_t iru)
558f2d6ace4SSean Bruno {
559dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
560f2d6ace4SSean Bruno 	if_softc_ctx_t scctx = sc->shared;
56195246abbSSean Bruno 	uint16_t rxqid = iru->iru_qsidx;
562f2d6ace4SSean Bruno 	struct em_rx_queue *que = &sc->rx_queues[rxqid];
563f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
564f2d6ace4SSean Bruno 	union e1000_rx_desc_extended *rxd;
56595246abbSSean Bruno 	uint64_t *paddrs;
56695246abbSSean Bruno 	uint32_t next_pidx, pidx;
56795246abbSSean Bruno 	uint16_t count;
568f2d6ace4SSean Bruno 	int i;
56995246abbSSean Bruno 
57095246abbSSean Bruno 	paddrs = iru->iru_paddrs;
57195246abbSSean Bruno 	pidx = iru->iru_pidx;
57295246abbSSean Bruno 	count = iru->iru_count;
573f2d6ace4SSean Bruno 
574f2d6ace4SSean Bruno 	for (i = 0, next_pidx = pidx; i < count; i++) {
575f2d6ace4SSean Bruno 		rxd = &rxr->rx_base[next_pidx];
576f2d6ace4SSean Bruno 		rxd->read.buffer_addr = htole64(paddrs[i]);
577ab2e3f79SStephen Hurd 		/* DD bits must be cleared */
578ab2e3f79SStephen Hurd 		rxd->wb.upper.status_error = 0;
579f2d6ace4SSean Bruno 
580f2d6ace4SSean Bruno 		if (++next_pidx == scctx->isc_nrxd[0])
581f2d6ace4SSean Bruno 			next_pidx = 0;
582f2d6ace4SSean Bruno 	}
583f2d6ace4SSean Bruno }
584f2d6ace4SSean Bruno 
585f2d6ace4SSean Bruno static void
em_isc_rxd_flush(void * arg,uint16_t rxqid,uint8_t flid __unused,qidx_t pidx)5865253d74eSKevin Bowling em_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused,
5875253d74eSKevin Bowling     qidx_t pidx)
588f2d6ace4SSean Bruno {
589dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
590f2d6ace4SSean Bruno 	struct em_rx_queue *que = &sc->rx_queues[rxqid];
591f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
592f2d6ace4SSean Bruno 
593f2d6ace4SSean Bruno 	E1000_WRITE_REG(&sc->hw, E1000_RDT(rxr->me), pidx);
594f2d6ace4SSean Bruno }
595f2d6ace4SSean Bruno 
596f2d6ace4SSean Bruno static int
lem_isc_rxd_available(void * arg,uint16_t rxqid,qidx_t idx,qidx_t budget)59795246abbSSean Bruno lem_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget)
598f2d6ace4SSean Bruno {
599dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
600f2d6ace4SSean Bruno 	if_softc_ctx_t scctx = sc->shared;
601f2d6ace4SSean Bruno 	struct em_rx_queue *que = &sc->rx_queues[rxqid];
602f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
603f2d6ace4SSean Bruno 	struct e1000_rx_desc *rxd;
6045253d74eSKevin Bowling 	uint32_t staterr = 0;
605f2d6ace4SSean Bruno 	int cnt, i;
606f2d6ace4SSean Bruno 
607ab2e3f79SStephen Hurd 	for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) {
608f2d6ace4SSean Bruno 		rxd = (struct e1000_rx_desc *)&rxr->rx_base[i];
609f2d6ace4SSean Bruno 		staterr = rxd->status;
610f2d6ace4SSean Bruno 
611f2d6ace4SSean Bruno 		if ((staterr & E1000_RXD_STAT_DD) == 0)
612f2d6ace4SSean Bruno 			break;
613f2d6ace4SSean Bruno 		if (++i == scctx->isc_nrxd[0])
614f2d6ace4SSean Bruno 			i = 0;
615f2d6ace4SSean Bruno 		if (staterr & E1000_RXD_STAT_EOP)
616f2d6ace4SSean Bruno 			cnt++;
617f2d6ace4SSean Bruno 	}
618f2d6ace4SSean Bruno 	return (cnt);
619f2d6ace4SSean Bruno }
620f2d6ace4SSean Bruno 
621f2d6ace4SSean Bruno static int
em_isc_rxd_available(void * arg,uint16_t rxqid,qidx_t idx,qidx_t budget)62295246abbSSean Bruno em_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget)
623f2d6ace4SSean Bruno {
624dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
625f2d6ace4SSean Bruno 	if_softc_ctx_t scctx = sc->shared;
626f2d6ace4SSean Bruno 	struct em_rx_queue *que = &sc->rx_queues[rxqid];
627f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
628f2d6ace4SSean Bruno 	union e1000_rx_desc_extended *rxd;
6295253d74eSKevin Bowling 	uint32_t staterr = 0;
630f2d6ace4SSean Bruno 	int cnt, i;
631f2d6ace4SSean Bruno 
632ab2e3f79SStephen Hurd 	for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) {
633f2d6ace4SSean Bruno 		rxd = &rxr->rx_base[i];
634f2d6ace4SSean Bruno 		staterr = le32toh(rxd->wb.upper.status_error);
635f2d6ace4SSean Bruno 
636f2d6ace4SSean Bruno 		if ((staterr & E1000_RXD_STAT_DD) == 0)
637f2d6ace4SSean Bruno 			break;
638adf93b56SEric Joyner 		if (++i == scctx->isc_nrxd[0])
639f2d6ace4SSean Bruno 			i = 0;
640f2d6ace4SSean Bruno 		if (staterr & E1000_RXD_STAT_EOP)
641f2d6ace4SSean Bruno 			cnt++;
642f2d6ace4SSean Bruno 	}
643f2d6ace4SSean Bruno 	return (cnt);
644f2d6ace4SSean Bruno }
645f2d6ace4SSean Bruno 
646f2d6ace4SSean Bruno static int
lem_isc_rxd_pkt_get(void * arg,if_rxd_info_t ri)647f2d6ace4SSean Bruno lem_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
648f2d6ace4SSean Bruno {
649dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
650dc926051SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
651dc926051SKevin Bowling 	struct em_rx_queue *que = &sc->rx_queues[ri->iri_qsidx];
652f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
653f2d6ace4SSean Bruno 	struct e1000_rx_desc *rxd;
6545253d74eSKevin Bowling 	uint16_t len;
6555253d74eSKevin Bowling 	uint32_t status, errors;
656f2d6ace4SSean Bruno 	bool eop;
657f2d6ace4SSean Bruno 	int i, cidx;
658f2d6ace4SSean Bruno 
659f2d6ace4SSean Bruno 	status = errors = i = 0;
660f2d6ace4SSean Bruno 	cidx = ri->iri_cidx;
661f2d6ace4SSean Bruno 
662f2d6ace4SSean Bruno 	do {
663f2d6ace4SSean Bruno 		rxd = (struct e1000_rx_desc *)&rxr->rx_base[cidx];
664f2d6ace4SSean Bruno 		status = rxd->status;
665f2d6ace4SSean Bruno 		errors = rxd->errors;
666f2d6ace4SSean Bruno 
667f2d6ace4SSean Bruno 		/* Error Checking then decrement count */
668f2d6ace4SSean Bruno 		MPASS ((status & E1000_RXD_STAT_DD) != 0);
669f2d6ace4SSean Bruno 
670f2d6ace4SSean Bruno 		len = le16toh(rxd->length);
671f2d6ace4SSean Bruno 		ri->iri_len += len;
672f2d6ace4SSean Bruno 
673f2d6ace4SSean Bruno 		eop = (status & E1000_RXD_STAT_EOP) != 0;
674f2d6ace4SSean Bruno 
675f2d6ace4SSean Bruno 		/* Make sure bad packets are discarded */
676f2d6ace4SSean Bruno 		if (errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
677dc926051SKevin Bowling 			sc->dropped_pkts++;
678f2d6ace4SSean Bruno 			/* XXX fixup if common */
679f2d6ace4SSean Bruno 			return (EBADMSG);
680f2d6ace4SSean Bruno 		}
681f2d6ace4SSean Bruno 
682f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_flid = 0;
683f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_idx = cidx;
684f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_len = len;
685f2d6ace4SSean Bruno 		/* Zero out the receive descriptors status. */
686f2d6ace4SSean Bruno 		rxd->status = 0;
687f2d6ace4SSean Bruno 
688f2d6ace4SSean Bruno 		if (++cidx == scctx->isc_nrxd[0])
689f2d6ace4SSean Bruno 			cidx = 0;
690f2d6ace4SSean Bruno 		i++;
691f2d6ace4SSean Bruno 	} while (!eop);
692f2d6ace4SSean Bruno 
693918c2567SKevin Bowling 	if (scctx->isc_capenable & IFCAP_RXCSUM)
694015075f3SKevin Bowling 		em_receive_checksum(status, errors, ri);
695f2d6ace4SSean Bruno 
696918c2567SKevin Bowling 	if (scctx->isc_capenable & IFCAP_VLAN_HWTAGGING &&
697918c2567SKevin Bowling 	    status & E1000_RXD_STAT_VP) {
698918c2567SKevin Bowling 		ri->iri_vtag = le16toh(rxd->special & E1000_RXD_SPC_VLAN_MASK);
699f2d6ace4SSean Bruno 		ri->iri_flags |= M_VLANTAG;
700f2d6ace4SSean Bruno 	}
701f2d6ace4SSean Bruno 
702f2d6ace4SSean Bruno 	ri->iri_nfrags = i;
703f2d6ace4SSean Bruno 
704f2d6ace4SSean Bruno 	return (0);
705f2d6ace4SSean Bruno }
706f2d6ace4SSean Bruno 
707f2d6ace4SSean Bruno static int
em_isc_rxd_pkt_get(void * arg,if_rxd_info_t ri)708f2d6ace4SSean Bruno em_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
709f2d6ace4SSean Bruno {
710dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
711dc926051SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
712dc926051SKevin Bowling 	struct em_rx_queue *que = &sc->rx_queues[ri->iri_qsidx];
713f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
714f2d6ace4SSean Bruno 	union e1000_rx_desc_extended *rxd;
715f2d6ace4SSean Bruno 
7165253d74eSKevin Bowling 	uint16_t len;
7175253d74eSKevin Bowling 	uint32_t pkt_info;
718918c2567SKevin Bowling 	uint32_t staterr;
719f2d6ace4SSean Bruno 	bool eop;
720f7926a6dSVincenzo Maffione 	int i, cidx;
721f2d6ace4SSean Bruno 
722918c2567SKevin Bowling 	staterr = i = 0;
723f2d6ace4SSean Bruno 	cidx = ri->iri_cidx;
724f2d6ace4SSean Bruno 
725f2d6ace4SSean Bruno 	do {
726f2d6ace4SSean Bruno 		rxd = &rxr->rx_base[cidx];
727f2d6ace4SSean Bruno 		staterr = le32toh(rxd->wb.upper.status_error);
728cbf1505dSSean Bruno 		pkt_info = le32toh(rxd->wb.lower.mrq);
729f2d6ace4SSean Bruno 
730f2d6ace4SSean Bruno 		/* Error Checking then decrement count */
731ab2e3f79SStephen Hurd 		MPASS ((staterr & E1000_RXD_STAT_DD) != 0);
732f2d6ace4SSean Bruno 
733f2d6ace4SSean Bruno 		len = le16toh(rxd->wb.upper.length);
734f2d6ace4SSean Bruno 		ri->iri_len += len;
735f2d6ace4SSean Bruno 
736f2d6ace4SSean Bruno 		eop = (staterr & E1000_RXD_STAT_EOP) != 0;
737f2d6ace4SSean Bruno 
738f2d6ace4SSean Bruno 		/* Make sure bad packets are discarded */
739f2d6ace4SSean Bruno 		if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
740dc926051SKevin Bowling 			sc->dropped_pkts++;
741f2d6ace4SSean Bruno 			return EBADMSG;
742f2d6ace4SSean Bruno 		}
743f2d6ace4SSean Bruno 
744f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_flid = 0;
745f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_idx = cidx;
746f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_len = len;
747f2d6ace4SSean Bruno 		/* Zero out the receive descriptors status. */
748f2d6ace4SSean Bruno 		rxd->wb.upper.status_error &= htole32(~0xFF);
749f2d6ace4SSean Bruno 
750f2d6ace4SSean Bruno 		if (++cidx == scctx->isc_nrxd[0])
751f2d6ace4SSean Bruno 			cidx = 0;
752f2d6ace4SSean Bruno 		i++;
753f2d6ace4SSean Bruno 	} while (!eop);
754f2d6ace4SSean Bruno 
75552f45d8aSVincenzo Maffione 	if (scctx->isc_capenable & IFCAP_RXCSUM)
756015075f3SKevin Bowling 		em_receive_checksum(staterr, staterr >> 24, ri);
757f2d6ace4SSean Bruno 
758918c2567SKevin Bowling 	if (scctx->isc_capenable & IFCAP_VLAN_HWTAGGING &&
759918c2567SKevin Bowling 	    staterr & E1000_RXD_STAT_VP) {
760f7926a6dSVincenzo Maffione 		ri->iri_vtag = le16toh(rxd->wb.upper.vlan);
761f2d6ace4SSean Bruno 		ri->iri_flags |= M_VLANTAG;
762f7926a6dSVincenzo Maffione 	}
763f2d6ace4SSean Bruno 
76495246abbSSean Bruno 	ri->iri_flowid = le32toh(rxd->wb.lower.hi_dword.rss);
765cbf1505dSSean Bruno 	ri->iri_rsstype = em_determine_rsstype(pkt_info);
766cbf1505dSSean Bruno 
767cbf1505dSSean Bruno 	ri->iri_nfrags = i;
768f2d6ace4SSean Bruno 	return (0);
769f2d6ace4SSean Bruno }
770f2d6ace4SSean Bruno 
771f2d6ace4SSean Bruno /*********************************************************************
772f2d6ace4SSean Bruno  *
773f2d6ace4SSean Bruno  *  Verify that the hardware indicated that the checksum is valid.
774f2d6ace4SSean Bruno  *  Inform the stack about the status of checksum so that stack
775f2d6ace4SSean Bruno  *  doesn't spend time verifying the checksum.
776f2d6ace4SSean Bruno  *
777f2d6ace4SSean Bruno  *********************************************************************/
778f2d6ace4SSean Bruno static void
em_receive_checksum(uint16_t status,uint8_t errors,if_rxd_info_t ri)779015075f3SKevin Bowling em_receive_checksum(uint16_t status, uint8_t errors, if_rxd_info_t ri)
780f2d6ace4SSean Bruno {
781015075f3SKevin Bowling 	if (__predict_false(status & E1000_RXD_STAT_IXSM))
782015075f3SKevin Bowling 		return;
783015075f3SKevin Bowling 
784015075f3SKevin Bowling 	/* If there is a layer 3 or 4 error we are done */
785015075f3SKevin Bowling 	if (__predict_false(errors & (E1000_RXD_ERR_IPE | E1000_RXD_ERR_TCPE)))
786015075f3SKevin Bowling 		return;
787015075f3SKevin Bowling 
788015075f3SKevin Bowling 	/* IP Checksum Good */
789015075f3SKevin Bowling 	if (status & E1000_RXD_STAT_IPCS)
790f2d6ace4SSean Bruno 		ri->iri_csum_flags = (CSUM_IP_CHECKED | CSUM_IP_VALID);
791f2d6ace4SSean Bruno 
792015075f3SKevin Bowling 	/* Valid L4E checksum */
793015075f3SKevin Bowling 	if (__predict_true(status &
794015075f3SKevin Bowling 	    (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) {
795015075f3SKevin Bowling 		ri->iri_csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
796f2d6ace4SSean Bruno 		ri->iri_csum_data = htons(0xffff);
797f2d6ace4SSean Bruno 	}
798f2d6ace4SSean Bruno }
799f2d6ace4SSean Bruno 
800cbf1505dSSean Bruno /********************************************************************
801cbf1505dSSean Bruno  *
802cbf1505dSSean Bruno  *  Parse the packet type to determine the appropriate hash
803cbf1505dSSean Bruno  *
804cbf1505dSSean Bruno  ******************************************************************/
805cbf1505dSSean Bruno static int
em_determine_rsstype(uint32_t pkt_info)8065253d74eSKevin Bowling em_determine_rsstype(uint32_t pkt_info)
807cbf1505dSSean Bruno {
808cbf1505dSSean Bruno 	switch (pkt_info & E1000_RXDADV_RSSTYPE_MASK) {
809cbf1505dSSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV4_TCP:
810cbf1505dSSean Bruno 		return M_HASHTYPE_RSS_TCP_IPV4;
811cbf1505dSSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV4:
812cbf1505dSSean Bruno 		return M_HASHTYPE_RSS_IPV4;
813cbf1505dSSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV6_TCP:
814cbf1505dSSean Bruno 		return M_HASHTYPE_RSS_TCP_IPV6;
815cbf1505dSSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV6_EX:
816cbf1505dSSean Bruno 		return M_HASHTYPE_RSS_IPV6_EX;
817cbf1505dSSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV6:
818cbf1505dSSean Bruno 		return M_HASHTYPE_RSS_IPV6;
819cbf1505dSSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX:
820cbf1505dSSean Bruno 		return M_HASHTYPE_RSS_TCP_IPV6_EX;
821cbf1505dSSean Bruno 	default:
822cbf1505dSSean Bruno 		return M_HASHTYPE_OPAQUE;
823cbf1505dSSean Bruno 	}
824cbf1505dSSean Bruno }
825