xref: /freebsd-src/sys/dev/ixgbe/ix_txrx.c (revision c58d34dd67a419866ee50f152044e49cecbae261)
1*c58d34ddSKevin Bowling /*****************************************************************************
2758cc3dcSJack F Vogel 
38eb6488eSEric Joyner   Copyright (c) 2001-2017, Intel Corporation
4758cc3dcSJack F Vogel   All rights reserved.
5758cc3dcSJack F Vogel 
6758cc3dcSJack F Vogel   Redistribution and use in source and binary forms, with or without
7758cc3dcSJack F Vogel   modification, are permitted provided that the following conditions are met:
8758cc3dcSJack F Vogel 
9758cc3dcSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
10758cc3dcSJack F Vogel       this list of conditions and the following disclaimer.
11758cc3dcSJack F Vogel 
12758cc3dcSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
13758cc3dcSJack F Vogel       notice, this list of conditions and the following disclaimer in the
14758cc3dcSJack F Vogel       documentation and/or other materials provided with the distribution.
15758cc3dcSJack F Vogel 
16758cc3dcSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
17758cc3dcSJack F Vogel       contributors may be used to endorse or promote products derived from
18758cc3dcSJack F Vogel       this software without specific prior written permission.
19758cc3dcSJack F Vogel 
20758cc3dcSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21758cc3dcSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22758cc3dcSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23758cc3dcSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24758cc3dcSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25758cc3dcSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26758cc3dcSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27758cc3dcSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28758cc3dcSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29758cc3dcSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30758cc3dcSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
31758cc3dcSJack F Vogel 
32*c58d34ddSKevin Bowling *****************************************************************************/
33758cc3dcSJack F Vogel 
34758cc3dcSJack F Vogel #ifndef IXGBE_STANDALONE_BUILD
35758cc3dcSJack F Vogel #include "opt_inet.h"
36758cc3dcSJack F Vogel #include "opt_inet6.h"
37758cc3dcSJack F Vogel #include "opt_rss.h"
38758cc3dcSJack F Vogel #endif
39758cc3dcSJack F Vogel 
40758cc3dcSJack F Vogel #include "ixgbe.h"
41758cc3dcSJack F Vogel 
428eb6488eSEric Joyner /************************************************************************
43758cc3dcSJack F Vogel  * Local Function prototypes
448eb6488eSEric Joyner  ************************************************************************/
45b1d5caf3SKevin Bowling static int ixgbe_isc_txd_encap(void *, if_pkt_info_t);
46b1d5caf3SKevin Bowling static void ixgbe_isc_txd_flush(void *, uint16_t, qidx_t);
47b1d5caf3SKevin Bowling static int ixgbe_isc_txd_credits_update(void *, uint16_t, bool);
48758cc3dcSJack F Vogel 
49b1d5caf3SKevin Bowling static void ixgbe_isc_rxd_refill(void *, if_rxd_update_t);
50b1d5caf3SKevin Bowling static void ixgbe_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t);
51b1d5caf3SKevin Bowling static int ixgbe_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t);
52b1d5caf3SKevin Bowling static int ixgbe_isc_rxd_pkt_get(void *, if_rxd_info_t);
53758cc3dcSJack F Vogel 
54b1d5caf3SKevin Bowling static void ixgbe_rx_checksum(uint32_t, if_rxd_info_t, uint32_t);
5551e46835SKevin Bowling static int ixgbe_tx_ctx_setup(struct ixgbe_adv_tx_context_desc *,
5651e46835SKevin Bowling     if_pkt_info_t);
57758cc3dcSJack F Vogel 
58c19c7afeSEric Joyner extern void ixgbe_if_enable_intr(if_ctx_t ctx);
5951e46835SKevin Bowling static int ixgbe_determine_rsstype(uint16_t pkt_info);
60758cc3dcSJack F Vogel 
61c19c7afeSEric Joyner struct if_txrx ixgbe_txrx  = {
62fbf8b74cSMark Johnston 	.ift_txd_encap = ixgbe_isc_txd_encap,
63fbf8b74cSMark Johnston 	.ift_txd_flush = ixgbe_isc_txd_flush,
64fbf8b74cSMark Johnston 	.ift_txd_credits_update = ixgbe_isc_txd_credits_update,
65fbf8b74cSMark Johnston 	.ift_rxd_available = ixgbe_isc_rxd_available,
66fbf8b74cSMark Johnston 	.ift_rxd_pkt_get = ixgbe_isc_rxd_pkt_get,
67fbf8b74cSMark Johnston 	.ift_rxd_refill = ixgbe_isc_rxd_refill,
68fbf8b74cSMark Johnston 	.ift_rxd_flush = ixgbe_isc_rxd_flush,
69fbf8b74cSMark Johnston 	.ift_legacy_intr = NULL
70c19c7afeSEric Joyner };
71758cc3dcSJack F Vogel 
728eb6488eSEric Joyner /************************************************************************
738eb6488eSEric Joyner  * ixgbe_tx_ctx_setup
74758cc3dcSJack F Vogel  *
75758cc3dcSJack F Vogel  *   Advanced Context Descriptor setup for VLAN, CSUM or TSO
76c19c7afeSEric Joyner  *
778eb6488eSEric Joyner  ************************************************************************/
78758cc3dcSJack F Vogel static int
79c19c7afeSEric Joyner ixgbe_tx_ctx_setup(struct ixgbe_adv_tx_context_desc *TXD, if_pkt_info_t pi)
80758cc3dcSJack F Vogel {
8151e46835SKevin Bowling 	uint32_t vlan_macip_lens, type_tucmd_mlhl;
8251e46835SKevin Bowling 	uint32_t olinfo_status, mss_l4len_idx, pktlen, offload;
83c19c7afeSEric Joyner 	u8 ehdrlen;
84a9ca1c79SSean Bruno 
8579b36ec9SKevin Bowling 	offload = true;
86c19c7afeSEric Joyner 	olinfo_status = mss_l4len_idx = vlan_macip_lens = type_tucmd_mlhl = 0;
87c19c7afeSEric Joyner 	/* VLAN MACLEN IPLEN */
88c19c7afeSEric Joyner 	vlan_macip_lens |= (htole16(pi->ipi_vtag) << IXGBE_ADVTXD_VLAN_SHIFT);
89758cc3dcSJack F Vogel 
90758cc3dcSJack F Vogel 	/*
91c19c7afeSEric Joyner 	 * Some of our VF devices need a context descriptor for every
92c19c7afeSEric Joyner 	 * packet.  That means the ehdrlen needs to be non-zero in order
93c19c7afeSEric Joyner 	 * for the host driver not to flag a malicious event. The stack
94c19c7afeSEric Joyner 	 * will most likely populate this for all other reasons of why
95c19c7afeSEric Joyner 	 * this function was called.
96758cc3dcSJack F Vogel 	 */
97c19c7afeSEric Joyner 	if (pi->ipi_ehdrlen == 0) {
98758cc3dcSJack F Vogel 		ehdrlen = ETHER_HDR_LEN;
99c19c7afeSEric Joyner 		ehdrlen += (pi->ipi_vtag != 0) ? ETHER_VLAN_ENCAP_LEN : 0;
100c19c7afeSEric Joyner 	} else
101c19c7afeSEric Joyner 		ehdrlen = pi->ipi_ehdrlen;
102758cc3dcSJack F Vogel 	vlan_macip_lens |= ehdrlen << IXGBE_ADVTXD_MACLEN_SHIFT;
103758cc3dcSJack F Vogel 
104c19c7afeSEric Joyner 	pktlen = pi->ipi_len;
105c19c7afeSEric Joyner 	/* First check if TSO is to be used */
106c19c7afeSEric Joyner 	if (pi->ipi_csum_flags & CSUM_TSO) {
107c19c7afeSEric Joyner 		/* This is used in the transmit desc in encap */
108*c58d34ddSKevin Bowling 		pktlen = pi->ipi_len - ehdrlen - pi->ipi_ip_hlen -
109*c58d34ddSKevin Bowling 		    pi->ipi_tcp_hlen;
110*c58d34ddSKevin Bowling 		mss_l4len_idx |=
111*c58d34ddSKevin Bowling 		    (pi->ipi_tso_segsz << IXGBE_ADVTXD_MSS_SHIFT);
112*c58d34ddSKevin Bowling 		mss_l4len_idx |=
113*c58d34ddSKevin Bowling 		    (pi->ipi_tcp_hlen << IXGBE_ADVTXD_L4LEN_SHIFT);
114a9ca1c79SSean Bruno 	}
115c19c7afeSEric Joyner 
116c19c7afeSEric Joyner 	olinfo_status |= pktlen << IXGBE_ADVTXD_PAYLEN_SHIFT;
117c19c7afeSEric Joyner 
118c19c7afeSEric Joyner 	if (pi->ipi_flags & IPI_TX_IPV4) {
119c19c7afeSEric Joyner 		type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
120c19c7afeSEric Joyner 		/* Tell transmit desc to also do IPv4 checksum. */
121c19c7afeSEric Joyner 		if (pi->ipi_csum_flags & (CSUM_IP|CSUM_TSO))
122c19c7afeSEric Joyner 			olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8;
123c19c7afeSEric Joyner 	} else if (pi->ipi_flags & IPI_TX_IPV6)
124758cc3dcSJack F Vogel 		type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6;
125c19c7afeSEric Joyner 	else
12679b36ec9SKevin Bowling 		offload = false;
127c19c7afeSEric Joyner 
128c19c7afeSEric Joyner 	vlan_macip_lens |= pi->ipi_ip_hlen;
129c19c7afeSEric Joyner 
130c19c7afeSEric Joyner 	switch (pi->ipi_ipproto) {
131c19c7afeSEric Joyner 	case IPPROTO_TCP:
132*c58d34ddSKevin Bowling 		if (pi->ipi_csum_flags &
133*c58d34ddSKevin Bowling 		    (CSUM_IP_TCP | CSUM_IP6_TCP | CSUM_TSO))
134c19c7afeSEric Joyner 			type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
135c19c7afeSEric Joyner 		else
13679b36ec9SKevin Bowling 			offload = false;
137758cc3dcSJack F Vogel 		break;
138c19c7afeSEric Joyner 	case IPPROTO_UDP:
139c19c7afeSEric Joyner 		if (pi->ipi_csum_flags & (CSUM_IP_UDP | CSUM_IP6_UDP))
140c19c7afeSEric Joyner 			type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP;
141c19c7afeSEric Joyner 		else
14279b36ec9SKevin Bowling 			offload = false;
143c19c7afeSEric Joyner 		break;
144c19c7afeSEric Joyner 	case IPPROTO_SCTP:
145c19c7afeSEric Joyner 		if (pi->ipi_csum_flags & (CSUM_IP_SCTP | CSUM_IP6_SCTP))
146c19c7afeSEric Joyner 			type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
147c19c7afeSEric Joyner 		else
14879b36ec9SKevin Bowling 			offload = false;
149c19c7afeSEric Joyner 		break;
150758cc3dcSJack F Vogel 	default:
15179b36ec9SKevin Bowling 		offload = false;
152758cc3dcSJack F Vogel 		break;
153758cc3dcSJack F Vogel 	}
154c19c7afeSEric Joyner 	/* Insert L4 checksum into data descriptors */
155c19c7afeSEric Joyner 	if (offload)
156c19c7afeSEric Joyner 		olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8;
157758cc3dcSJack F Vogel 
158758cc3dcSJack F Vogel 	type_tucmd_mlhl |= IXGBE_ADVTXD_DCMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT;
159758cc3dcSJack F Vogel 
160758cc3dcSJack F Vogel 	/* Now copy bits into descriptor */
161758cc3dcSJack F Vogel 	TXD->vlan_macip_lens = htole32(vlan_macip_lens);
162758cc3dcSJack F Vogel 	TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
163758cc3dcSJack F Vogel 	TXD->seqnum_seed = htole32(0);
164c19c7afeSEric Joyner 	TXD->mss_l4len_idx = htole32(mss_l4len_idx);
165758cc3dcSJack F Vogel 
166c19c7afeSEric Joyner 	return (olinfo_status);
1678eb6488eSEric Joyner } /* ixgbe_tx_ctx_setup */
168758cc3dcSJack F Vogel 
1698eb6488eSEric Joyner /************************************************************************
170c19c7afeSEric Joyner  * ixgbe_isc_txd_encap
1718eb6488eSEric Joyner  ************************************************************************/
172758cc3dcSJack F Vogel static int
173c19c7afeSEric Joyner ixgbe_isc_txd_encap(void *arg, if_pkt_info_t pi)
174758cc3dcSJack F Vogel {
175b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
176c19c7afeSEric Joyner 	if_softc_ctx_t scctx = sc->shared;
177c19c7afeSEric Joyner 	struct ix_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx];
178c19c7afeSEric Joyner 	struct tx_ring *txr = &que->txr;
179c19c7afeSEric Joyner 	int nsegs = pi->ipi_nsegs;
180c19c7afeSEric Joyner 	bus_dma_segment_t *segs = pi->ipi_segs;
181c19c7afeSEric Joyner 	union ixgbe_adv_tx_desc *txd = NULL;
182758cc3dcSJack F Vogel 	struct ixgbe_adv_tx_context_desc *TXD;
183c19c7afeSEric Joyner 	int i, j, first, pidx_last;
18451e46835SKevin Bowling 	uint32_t olinfo_status, cmd, flags;
185c19c7afeSEric Joyner 	qidx_t ntxd;
186758cc3dcSJack F Vogel 
187c19c7afeSEric Joyner 	cmd =  (IXGBE_ADVTXD_DTYP_DATA |
188c19c7afeSEric Joyner 		IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT);
189758cc3dcSJack F Vogel 
190c19c7afeSEric Joyner 	if (pi->ipi_mflags & M_VLANTAG)
191c19c7afeSEric Joyner 		cmd |= IXGBE_ADVTXD_DCMD_VLE;
192758cc3dcSJack F Vogel 
193c19c7afeSEric Joyner 	i = first = pi->ipi_pidx;
194c19c7afeSEric Joyner 	flags = (pi->ipi_flags & IPI_TX_INTR) ? IXGBE_TXD_CMD_RS : 0;
195c19c7afeSEric Joyner 	ntxd = scctx->isc_ntxd[0];
196758cc3dcSJack F Vogel 
197c19c7afeSEric Joyner 	TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[first];
198c19c7afeSEric Joyner 	if ((pi->ipi_csum_flags & CSUM_OFFLOAD) ||
199c19c7afeSEric Joyner 	    (sc->feat_en & IXGBE_FEATURE_NEEDS_CTXD) ||
200c19c7afeSEric Joyner 	    pi->ipi_vtag) {
201c19c7afeSEric Joyner 		/*********************************************
202c19c7afeSEric Joyner 		 * Set up the appropriate offload context
203c19c7afeSEric Joyner 		 * this will consume the first descriptor
204c19c7afeSEric Joyner 		 *********************************************/
205c19c7afeSEric Joyner 		olinfo_status = ixgbe_tx_ctx_setup(TXD, pi);
206c19c7afeSEric Joyner 		if (pi->ipi_csum_flags & CSUM_TSO) {
207c19c7afeSEric Joyner 			cmd |= IXGBE_ADVTXD_DCMD_TSE;
208758cc3dcSJack F Vogel 			++txr->tso_tx;
209c19c7afeSEric Joyner 		}
210c19c7afeSEric Joyner 
211c19c7afeSEric Joyner 		if (++i == scctx->isc_ntxd[0])
212c19c7afeSEric Joyner 			i = 0;
213c19c7afeSEric Joyner 	} else {
214c19c7afeSEric Joyner 		/* Indicate the whole packet as payload when not doing TSO */
215c19c7afeSEric Joyner 		olinfo_status = pi->ipi_len << IXGBE_ADVTXD_PAYLEN_SHIFT;
216c19c7afeSEric Joyner 	}
217c19c7afeSEric Joyner 
218c19c7afeSEric Joyner 	olinfo_status |= IXGBE_ADVTXD_CC;
21924a7d6d3SMatt Macy 	pidx_last = 0;
220c19c7afeSEric Joyner 	for (j = 0; j < nsegs; j++) {
221c19c7afeSEric Joyner 		bus_size_t seglen;
222c19c7afeSEric Joyner 
223c19c7afeSEric Joyner 		txd = &txr->tx_base[i];
224c19c7afeSEric Joyner 		seglen = segs[j].ds_len;
225c19c7afeSEric Joyner 
226c19c7afeSEric Joyner 		txd->read.buffer_addr = htole64(segs[j].ds_addr);
227c19c7afeSEric Joyner 		txd->read.cmd_type_len = htole32(cmd | seglen);
228c19c7afeSEric Joyner 		txd->read.olinfo_status = htole32(olinfo_status);
229c19c7afeSEric Joyner 
230c19c7afeSEric Joyner 		pidx_last = i;
231c19c7afeSEric Joyner 		if (++i == scctx->isc_ntxd[0]) {
232c19c7afeSEric Joyner 			i = 0;
233c19c7afeSEric Joyner 		}
234c19c7afeSEric Joyner 	}
235c19c7afeSEric Joyner 
236c19c7afeSEric Joyner 	if (flags) {
237c19c7afeSEric Joyner 		txr->tx_rsq[txr->tx_rs_pidx] = pidx_last;
238c19c7afeSEric Joyner 		txr->tx_rs_pidx = (txr->tx_rs_pidx + 1) & (ntxd - 1);
239c19c7afeSEric Joyner 	}
240c19c7afeSEric Joyner 	txd->read.cmd_type_len |= htole32(IXGBE_TXD_CMD_EOP | flags);
241c19c7afeSEric Joyner 
242c19c7afeSEric Joyner 	txr->bytes += pi->ipi_len;
243c19c7afeSEric Joyner 	pi->ipi_new_pidx = i;
244c19c7afeSEric Joyner 
245c19c7afeSEric Joyner 	++txr->total_packets;
2468eb6488eSEric Joyner 
247758cc3dcSJack F Vogel 	return (0);
248c19c7afeSEric Joyner } /* ixgbe_isc_txd_encap */
249758cc3dcSJack F Vogel 
2508eb6488eSEric Joyner /************************************************************************
251c19c7afeSEric Joyner  * ixgbe_isc_txd_flush
2528eb6488eSEric Joyner  ************************************************************************/
253c19c7afeSEric Joyner static void
254c19c7afeSEric Joyner ixgbe_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
255758cc3dcSJack F Vogel {
256b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
257c19c7afeSEric Joyner 	struct ix_tx_queue *que = &sc->tx_queues[txqid];
258c19c7afeSEric Joyner 	struct tx_ring *txr = &que->txr;
259758cc3dcSJack F Vogel 
260c19c7afeSEric Joyner 	IXGBE_WRITE_REG(&sc->hw, txr->tail, pidx);
261c19c7afeSEric Joyner } /* ixgbe_isc_txd_flush */
262758cc3dcSJack F Vogel 
263c19c7afeSEric Joyner /************************************************************************
264c19c7afeSEric Joyner  * ixgbe_isc_txd_credits_update
265c19c7afeSEric Joyner  ************************************************************************/
266c19c7afeSEric Joyner static int
267c19c7afeSEric Joyner ixgbe_isc_txd_credits_update(void *arg, uint16_t txqid, bool clear)
268c19c7afeSEric Joyner {
269b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
270c19c7afeSEric Joyner 	if_softc_ctx_t scctx = sc->shared;
271c19c7afeSEric Joyner 	struct ix_tx_queue *que = &sc->tx_queues[txqid];
272c19c7afeSEric Joyner 	struct tx_ring *txr = &que->txr;
273c19c7afeSEric Joyner 	qidx_t processed = 0;
274c19c7afeSEric Joyner 	int updated;
275c19c7afeSEric Joyner 	qidx_t cur, prev, ntxd, rs_cidx;
276c19c7afeSEric Joyner 	int32_t delta;
277c19c7afeSEric Joyner 	uint8_t status;
278758cc3dcSJack F Vogel 
279c19c7afeSEric Joyner 	rs_cidx = txr->tx_rs_cidx;
280c19c7afeSEric Joyner 	if (rs_cidx == txr->tx_rs_pidx)
281c19c7afeSEric Joyner 		return (0);
282758cc3dcSJack F Vogel 
283c19c7afeSEric Joyner 	cur = txr->tx_rsq[rs_cidx];
284c19c7afeSEric Joyner 	status = txr->tx_base[cur].wb.status;
285c19c7afeSEric Joyner 	updated = !!(status & IXGBE_TXD_STAT_DD);
286758cc3dcSJack F Vogel 
287adf93b56SEric Joyner 	if (!updated)
288adf93b56SEric Joyner 		return (0);
289adf93b56SEric Joyner 
290adf93b56SEric Joyner 	/* If clear is false just let caller know that there
291adf93b56SEric Joyner 	 * are descriptors to reclaim */
292adf93b56SEric Joyner 	if (!clear)
293adf93b56SEric Joyner 		return (1);
294c19c7afeSEric Joyner 
295c19c7afeSEric Joyner 	prev = txr->tx_cidx_processed;
296c19c7afeSEric Joyner 	ntxd = scctx->isc_ntxd[0];
297758cc3dcSJack F Vogel 	do {
298088a0b27SEric Joyner 		MPASS(prev != cur);
299c19c7afeSEric Joyner 		delta = (int32_t)cur - (int32_t)prev;
300c19c7afeSEric Joyner 		if (delta < 0)
301c19c7afeSEric Joyner 			delta += ntxd;
302088a0b27SEric Joyner 		MPASS(delta > 0);
303c19c7afeSEric Joyner 
304c19c7afeSEric Joyner 		processed += delta;
305c19c7afeSEric Joyner 		prev = cur;
306c19c7afeSEric Joyner 		rs_cidx = (rs_cidx + 1) & (ntxd - 1);
307c19c7afeSEric Joyner 		if (rs_cidx == txr->tx_rs_pidx)
308758cc3dcSJack F Vogel 			break;
309758cc3dcSJack F Vogel 
310c19c7afeSEric Joyner 		cur = txr->tx_rsq[rs_cidx];
311c19c7afeSEric Joyner 		status = txr->tx_base[cur].wb.status;
312c19c7afeSEric Joyner 	} while ((status & IXGBE_TXD_STAT_DD));
313758cc3dcSJack F Vogel 
314c19c7afeSEric Joyner 	txr->tx_rs_cidx = rs_cidx;
315c19c7afeSEric Joyner 	txr->tx_cidx_processed = prev;
316758cc3dcSJack F Vogel 
317c19c7afeSEric Joyner 	return (processed);
318c19c7afeSEric Joyner } /* ixgbe_isc_txd_credits_update */
319758cc3dcSJack F Vogel 
3208eb6488eSEric Joyner /************************************************************************
321c19c7afeSEric Joyner  * ixgbe_isc_rxd_refill
3228eb6488eSEric Joyner  ************************************************************************/
323758cc3dcSJack F Vogel static void
324c19c7afeSEric Joyner ixgbe_isc_rxd_refill(void *arg, if_rxd_update_t iru)
325758cc3dcSJack F Vogel {
326b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
327c19c7afeSEric Joyner 	struct ix_rx_queue *que = &sc->rx_queues[iru->iru_qsidx];
328c19c7afeSEric Joyner 	struct rx_ring *rxr = &que->rxr;
329c19c7afeSEric Joyner 	uint64_t *paddrs;
330c19c7afeSEric Joyner 	int i;
331c19c7afeSEric Joyner 	uint32_t next_pidx, pidx;
332c19c7afeSEric Joyner 	uint16_t count;
333758cc3dcSJack F Vogel 
334c19c7afeSEric Joyner 	paddrs = iru->iru_paddrs;
335c19c7afeSEric Joyner 	pidx = iru->iru_pidx;
336c19c7afeSEric Joyner 	count = iru->iru_count;
337c19c7afeSEric Joyner 
338c19c7afeSEric Joyner 	for (i = 0, next_pidx = pidx; i < count; i++) {
339c19c7afeSEric Joyner 		rxr->rx_base[next_pidx].read.pkt_addr = htole64(paddrs[i]);
340c19c7afeSEric Joyner 		if (++next_pidx == sc->shared->isc_nrxd[0])
341c19c7afeSEric Joyner 			next_pidx = 0;
342758cc3dcSJack F Vogel 	}
343c19c7afeSEric Joyner } /* ixgbe_isc_rxd_refill */
344a9ca1c79SSean Bruno 
3458eb6488eSEric Joyner /************************************************************************
346c19c7afeSEric Joyner  * ixgbe_isc_rxd_flush
3478eb6488eSEric Joyner  ************************************************************************/
348758cc3dcSJack F Vogel static void
349*c58d34ddSKevin Bowling ixgbe_isc_rxd_flush(void *arg, uint16_t qsidx, uint8_t flidx __unused,
350*c58d34ddSKevin Bowling     qidx_t pidx)
351758cc3dcSJack F Vogel {
352b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
353c19c7afeSEric Joyner 	struct ix_rx_queue *que = &sc->rx_queues[qsidx];
354c19c7afeSEric Joyner 	struct rx_ring *rxr = &que->rxr;
355758cc3dcSJack F Vogel 
356c19c7afeSEric Joyner 	IXGBE_WRITE_REG(&sc->hw, rxr->tail, pidx);
357c19c7afeSEric Joyner } /* ixgbe_isc_rxd_flush */
3588eb6488eSEric Joyner 
3598eb6488eSEric Joyner /************************************************************************
360c19c7afeSEric Joyner  * ixgbe_isc_rxd_available
3618eb6488eSEric Joyner  ************************************************************************/
3628eb6488eSEric Joyner static int
363c19c7afeSEric Joyner ixgbe_isc_rxd_available(void *arg, uint16_t qsidx, qidx_t pidx, qidx_t budget)
364758cc3dcSJack F Vogel {
365b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
366c19c7afeSEric Joyner 	struct ix_rx_queue *que = &sc->rx_queues[qsidx];
367c19c7afeSEric Joyner 	struct rx_ring *rxr = &que->rxr;
368c19c7afeSEric Joyner 	union ixgbe_adv_rx_desc *rxd;
36951e46835SKevin Bowling 	uint32_t staterr;
370c19c7afeSEric Joyner 	int cnt, i, nrxd;
371758cc3dcSJack F Vogel 
372c19c7afeSEric Joyner 	nrxd = sc->shared->isc_nrxd[0];
373adf93b56SEric Joyner 	for (cnt = 0, i = pidx; cnt < nrxd && cnt <= budget;) {
374c19c7afeSEric Joyner 		rxd = &rxr->rx_base[i];
375c19c7afeSEric Joyner 		staterr = le32toh(rxd->wb.upper.status_error);
376758cc3dcSJack F Vogel 
377758cc3dcSJack F Vogel 		if ((staterr & IXGBE_RXD_STAT_DD) == 0)
378758cc3dcSJack F Vogel 			break;
379c19c7afeSEric Joyner 		if (++i == nrxd)
380c19c7afeSEric Joyner 			i = 0;
381c19c7afeSEric Joyner 		if (staterr & IXGBE_RXD_STAT_EOP)
382c19c7afeSEric Joyner 			cnt++;
383c19c7afeSEric Joyner 	}
384c19c7afeSEric Joyner 	return (cnt);
385c19c7afeSEric Joyner } /* ixgbe_isc_rxd_available */
386758cc3dcSJack F Vogel 
387c19c7afeSEric Joyner /************************************************************************
388c19c7afeSEric Joyner  * ixgbe_isc_rxd_pkt_get
389c19c7afeSEric Joyner  *
390c19c7afeSEric Joyner  *   Routine sends data which has been dma'ed into host memory
391c19c7afeSEric Joyner  *   to upper layer. Initialize ri structure.
392c19c7afeSEric Joyner  *
393c19c7afeSEric Joyner  *   Returns 0 upon success, errno on failure
394c19c7afeSEric Joyner  ************************************************************************/
395c19c7afeSEric Joyner 
396c19c7afeSEric Joyner static int
397c19c7afeSEric Joyner ixgbe_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
398c19c7afeSEric Joyner {
399b1d5caf3SKevin Bowling 	struct ixgbe_softc *sc = arg;
40052f45d8aSVincenzo Maffione 	if_softc_ctx_t scctx = sc->shared;
401b1d5caf3SKevin Bowling 	struct ix_rx_queue *que = &sc->rx_queues[ri->iri_qsidx];
402c19c7afeSEric Joyner 	struct rx_ring *rxr = &que->rxr;
403c19c7afeSEric Joyner 	union ixgbe_adv_rx_desc *rxd;
404c19c7afeSEric Joyner 
40551e46835SKevin Bowling 	uint16_t pkt_info, len, cidx, i;
40651e46835SKevin Bowling 	uint32_t ptype;
40751e46835SKevin Bowling 	uint32_t staterr = 0;
408c19c7afeSEric Joyner 	bool eop;
409c19c7afeSEric Joyner 
410c19c7afeSEric Joyner 	i = 0;
411c19c7afeSEric Joyner 	cidx = ri->iri_cidx;
412c19c7afeSEric Joyner 	do {
413c19c7afeSEric Joyner 		rxd = &rxr->rx_base[cidx];
414c19c7afeSEric Joyner 		staterr = le32toh(rxd->wb.upper.status_error);
415c19c7afeSEric Joyner 		pkt_info = le16toh(rxd->wb.lower.lo_dword.hs_rss.pkt_info);
416c19c7afeSEric Joyner 
417c19c7afeSEric Joyner 		/* Error Checking then decrement count */
418c19c7afeSEric Joyner 		MPASS ((staterr & IXGBE_RXD_STAT_DD) != 0);
419c19c7afeSEric Joyner 
420c19c7afeSEric Joyner 		len = le16toh(rxd->wb.upper.length);
421c19c7afeSEric Joyner 		ptype = le32toh(rxd->wb.lower.lo_dword.data) &
422758cc3dcSJack F Vogel 			IXGBE_RXDADV_PKTTYPE_MASK;
423c19c7afeSEric Joyner 
424c19c7afeSEric Joyner 		ri->iri_len += len;
425c19c7afeSEric Joyner 		rxr->bytes += len;
426c19c7afeSEric Joyner 
427c19c7afeSEric Joyner 		rxd->wb.upper.status_error = 0;
428758cc3dcSJack F Vogel 		eop = ((staterr & IXGBE_RXD_STAT_EOP) != 0);
429de35521aSEric Joyner 
430758cc3dcSJack F Vogel 		/* Make sure bad packets are discarded */
431758cc3dcSJack F Vogel 		if (eop && (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) != 0) {
432b1d5caf3SKevin Bowling 			if (sc->feat_en & IXGBE_FEATURE_VF)
433*c58d34ddSKevin Bowling 				if_inc_counter(ri->iri_ifp, IFCOUNTER_IERRORS,
434*c58d34ddSKevin Bowling 				    1);
435c19c7afeSEric Joyner 
436758cc3dcSJack F Vogel 			rxr->rx_discarded++;
437c19c7afeSEric Joyner 			return (EBADMSG);
438758cc3dcSJack F Vogel 		}
439c19c7afeSEric Joyner 		ri->iri_frags[i].irf_flid = 0;
440c19c7afeSEric Joyner 		ri->iri_frags[i].irf_idx = cidx;
441c19c7afeSEric Joyner 		ri->iri_frags[i].irf_len = len;
442b1d5caf3SKevin Bowling 		if (++cidx == sc->shared->isc_nrxd[0])
443c19c7afeSEric Joyner 			cidx = 0;
444c19c7afeSEric Joyner 		i++;
445c19c7afeSEric Joyner 		/* even a 16K packet shouldn't consume more than 8 clusters */
446c19c7afeSEric Joyner 		MPASS(i < 9);
447c19c7afeSEric Joyner 	} while (!eop);
448758cc3dcSJack F Vogel 
449758cc3dcSJack F Vogel 	rxr->rx_packets++;
450c19c7afeSEric Joyner 	rxr->packets++;
451c19c7afeSEric Joyner 	rxr->rx_bytes += ri->iri_len;
452c19c7afeSEric Joyner 
45352f45d8aSVincenzo Maffione 	if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0)
454c19c7afeSEric Joyner 		ixgbe_rx_checksum(staterr, ri,  ptype);
455df7b11faSHiren Panchasara 
456c19c7afeSEric Joyner 	ri->iri_flowid = le32toh(rxd->wb.lower.hi_dword.rss);
457c19c7afeSEric Joyner 	ri->iri_rsstype = ixgbe_determine_rsstype(pkt_info);
458b1d5caf3SKevin Bowling 	if ((sc->feat_en & IXGBE_FEATURE_RSS) == 0) {
459236204eeSAndriy Gapon 		if (ri->iri_rsstype == M_HASHTYPE_OPAQUE)
460236204eeSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_NONE;
461236204eeSAndriy Gapon 		else
462236204eeSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
463236204eeSAndriy Gapon 	}
464f7926a6dSVincenzo Maffione 	if ((rxr->vtag_strip) && (staterr & IXGBE_RXD_STAT_VP)) {
465f7926a6dSVincenzo Maffione 		ri->iri_vtag = le16toh(rxd->wb.upper.vlan);
466c19c7afeSEric Joyner 		ri->iri_flags |= M_VLANTAG;
467f7926a6dSVincenzo Maffione 	}
468f7926a6dSVincenzo Maffione 
469f7926a6dSVincenzo Maffione 	ri->iri_nfrags = i;
470c19c7afeSEric Joyner 	return (0);
471c19c7afeSEric Joyner } /* ixgbe_isc_rxd_pkt_get */
472758cc3dcSJack F Vogel 
4738eb6488eSEric Joyner /************************************************************************
4748eb6488eSEric Joyner  * ixgbe_rx_checksum
475758cc3dcSJack F Vogel  *
476758cc3dcSJack F Vogel  *   Verify that the hardware indicated that the checksum is valid.
477758cc3dcSJack F Vogel  *   Inform the stack about the status of checksum so that stack
478758cc3dcSJack F Vogel  *   doesn't spend time verifying the checksum.
4798eb6488eSEric Joyner  ************************************************************************/
480758cc3dcSJack F Vogel static void
48151e46835SKevin Bowling ixgbe_rx_checksum(uint32_t staterr, if_rxd_info_t ri, uint32_t ptype)
482758cc3dcSJack F Vogel {
48351e46835SKevin Bowling 	uint16_t status = (uint16_t)staterr;
48451e46835SKevin Bowling 	uint8_t errors = (uint8_t)(staterr >> 24);
485758cc3dcSJack F Vogel 
48651e46835SKevin Bowling 	/* If there is a layer 3 or 4 error we are done */
487*c58d34ddSKevin Bowling 	if (__predict_false(errors &
488*c58d34ddSKevin Bowling 	    (IXGBE_RXD_ERR_IPE | IXGBE_RXD_ERR_TCPE)))
48951e46835SKevin Bowling 		return;
490758cc3dcSJack F Vogel 
491758cc3dcSJack F Vogel 	/* IP Checksum Good */
49251e46835SKevin Bowling 	if (status & IXGBE_RXD_STAT_IPCS)
49351e46835SKevin Bowling 		ri->iri_csum_flags = (CSUM_IP_CHECKED | CSUM_IP_VALID);
49451e46835SKevin Bowling 
49551e46835SKevin Bowling 	/* Valid L4E checksum */
49651e46835SKevin Bowling 	if (__predict_true(status & IXGBE_RXD_STAT_L4CS)) {
49751e46835SKevin Bowling 		/* SCTP header present. */
49851e46835SKevin Bowling 		if (__predict_false((ptype & IXGBE_RXDADV_PKTTYPE_ETQF) == 0 &&
49951e46835SKevin Bowling 		    (ptype & IXGBE_RXDADV_PKTTYPE_SCTP) != 0)) {
50051e46835SKevin Bowling 			ri->iri_csum_flags |= CSUM_SCTP_VALID;
50151e46835SKevin Bowling 		} else {
502*c58d34ddSKevin Bowling 			ri->iri_csum_flags |=
503*c58d34ddSKevin Bowling 			    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
504c19c7afeSEric Joyner 			ri->iri_csum_data = htons(0xffff);
505758cc3dcSJack F Vogel 		}
506758cc3dcSJack F Vogel 	}
5078eb6488eSEric Joyner } /* ixgbe_rx_checksum */
508758cc3dcSJack F Vogel 
5098eb6488eSEric Joyner /************************************************************************
510c19c7afeSEric Joyner  * ixgbe_determine_rsstype
511c19c7afeSEric Joyner  *
512c19c7afeSEric Joyner  *   Parse the packet type to determine the appropriate hash
5138eb6488eSEric Joyner  ************************************************************************/
5148eb6488eSEric Joyner static int
51551e46835SKevin Bowling ixgbe_determine_rsstype(uint16_t pkt_info)
516758cc3dcSJack F Vogel {
517c19c7afeSEric Joyner 	switch (pkt_info & IXGBE_RXDADV_RSSTYPE_MASK) {
518c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV4_TCP:
519c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_TCP_IPV4;
520c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV4:
521c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_IPV4;
522c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV6_TCP:
523c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_TCP_IPV6;
524c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV6_EX:
525c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_IPV6_EX;
526c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV6:
527c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_IPV6;
528c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX:
529c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_TCP_IPV6_EX;
530c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV4_UDP:
531c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_UDP_IPV4;
532c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV6_UDP:
533c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_UDP_IPV6;
534c19c7afeSEric Joyner 	case IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX:
535c19c7afeSEric Joyner 		return M_HASHTYPE_RSS_UDP_IPV6_EX;
536c19c7afeSEric Joyner 	default:
537c19c7afeSEric Joyner 		return M_HASHTYPE_OPAQUE;
538758cc3dcSJack F Vogel 	}
539c19c7afeSEric Joyner } /* ixgbe_determine_rsstype */
540