xref: /freebsd-src/sys/dev/e1000/igb_txrx.c (revision 7390daf87c53073da5e74b2d73ac7320c1a44475)
1d37cece2SSean Bruno /*-
241f02257SKevin Bowling  * SPDX-License-Identifier: BSD-2-Clause
341f02257SKevin Bowling  *
496fc97c8SStephen Hurd  * Copyright (c) 2016 Matthew Macy <mmacy@mattmacy.io>
5d37cece2SSean Bruno  * All rights reserved.
6d37cece2SSean Bruno  *
7d37cece2SSean Bruno  * Redistribution and use in source and binary forms, with or without
8d37cece2SSean Bruno  * modification, are permitted provided that the following conditions
9d37cece2SSean Bruno  * are met:
10d37cece2SSean Bruno  * 1. Redistributions of source code must retain the above copyright
11d37cece2SSean Bruno  *    notice, this list of conditions and the following disclaimer.
12d37cece2SSean Bruno  * 2. Redistributions in binary form must reproduce the above copyright
13d37cece2SSean Bruno  *    notice, this list of conditions and the following disclaimer in the
14d37cece2SSean Bruno  *    documentation and/or other materials provided with the distribution.
15d37cece2SSean Bruno  *
16d37cece2SSean Bruno  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17d37cece2SSean Bruno  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d37cece2SSean Bruno  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19d37cece2SSean Bruno  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20d37cece2SSean Bruno  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d37cece2SSean Bruno  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d37cece2SSean Bruno  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d37cece2SSean Bruno  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d37cece2SSean Bruno  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d37cece2SSean Bruno  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d37cece2SSean Bruno  * SUCH DAMAGE.
27d37cece2SSean Bruno  */
28d37cece2SSean Bruno 
29f2d6ace4SSean Bruno #include "if_em.h"
30f2d6ace4SSean Bruno 
31f2d6ace4SSean Bruno #ifdef RSS
32f2d6ace4SSean Bruno #include <net/rss_config.h>
33f2d6ace4SSean Bruno #include <netinet/in_rss.h>
34f2d6ace4SSean Bruno #endif
35f2d6ace4SSean Bruno 
36f2d6ace4SSean Bruno #ifdef VERBOSE_DEBUG
37f2d6ace4SSean Bruno #define DPRINTF device_printf
38f2d6ace4SSean Bruno #else
39f2d6ace4SSean Bruno #define DPRINTF(...)
40f2d6ace4SSean Bruno #endif
41f2d6ace4SSean Bruno 
42f2d6ace4SSean Bruno /*********************************************************************
43f2d6ace4SSean Bruno  *  Local Function prototypes
44f2d6ace4SSean Bruno  *********************************************************************/
459dc452b9SKevin Bowling static int igb_isc_txd_encap(void *, if_pkt_info_t);
469dc452b9SKevin Bowling static void igb_isc_txd_flush(void *, uint16_t, qidx_t);
479dc452b9SKevin Bowling static int igb_isc_txd_credits_update(void *, uint16_t, bool);
48f2d6ace4SSean Bruno 
499dc452b9SKevin Bowling static void igb_isc_rxd_refill(void *, if_rxd_update_t);
5095246abbSSean Bruno 
519dc452b9SKevin Bowling static void igb_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t);
529dc452b9SKevin Bowling static int igb_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t);
5395246abbSSean Bruno 
54f2d6ace4SSean Bruno static int igb_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri);
55f2d6ace4SSean Bruno 
569dc452b9SKevin Bowling static int igb_tx_ctx_setup(struct tx_ring *, if_pkt_info_t, uint32_t *,
579dc452b9SKevin Bowling     uint32_t *);
589dc452b9SKevin Bowling static int igb_tso_setup(struct tx_ring *, if_pkt_info_t, uint32_t *,
599dc452b9SKevin Bowling     uint32_t *);
60f2d6ace4SSean Bruno 
619dc452b9SKevin Bowling static void igb_rx_checksum(uint32_t, if_rxd_info_t, uint32_t);
629dc452b9SKevin Bowling static int igb_determine_rsstype(uint16_t);
63f2d6ace4SSean Bruno 
649dc452b9SKevin Bowling extern void igb_if_enable_intr(if_ctx_t);
659dc452b9SKevin Bowling extern int em_intr(void *);
66f2d6ace4SSean Bruno 
67f2d6ace4SSean Bruno struct if_txrx igb_txrx = {
68fbf8b74cSMark Johnston 	.ift_txd_encap = igb_isc_txd_encap,
69fbf8b74cSMark Johnston 	.ift_txd_flush = igb_isc_txd_flush,
70fbf8b74cSMark Johnston 	.ift_txd_credits_update = igb_isc_txd_credits_update,
71fbf8b74cSMark Johnston 	.ift_rxd_available = igb_isc_rxd_available,
72fbf8b74cSMark Johnston 	.ift_rxd_pkt_get = igb_isc_rxd_pkt_get,
73fbf8b74cSMark Johnston 	.ift_rxd_refill = igb_isc_rxd_refill,
74fbf8b74cSMark Johnston 	.ift_rxd_flush = igb_isc_rxd_flush,
75fbf8b74cSMark Johnston 	.ift_legacy_intr = em_intr
76f2d6ace4SSean Bruno };
77f2d6ace4SSean Bruno 
78f2d6ace4SSean Bruno /**********************************************************************
79f2d6ace4SSean Bruno  *
80f2d6ace4SSean Bruno  *  Setup work for hardware segmentation offload (TSO) on
81f2d6ace4SSean Bruno  *  adapters using advanced tx descriptors
82f2d6ace4SSean Bruno  *
83f2d6ace4SSean Bruno  **********************************************************************/
84f2d6ace4SSean Bruno static int
8541f02257SKevin Bowling igb_tso_setup(struct tx_ring *txr, if_pkt_info_t pi, uint32_t *cmd_type_len,
8641f02257SKevin Bowling     uint32_t *olinfo_status)
87f2d6ace4SSean Bruno {
88f2d6ace4SSean Bruno 	struct e1000_adv_tx_context_desc *TXD;
89dc926051SKevin Bowling 	struct e1000_softc *sc = txr->sc;
9041f02257SKevin Bowling 	uint32_t type_tucmd_mlhl = 0, vlan_macip_lens = 0;
9141f02257SKevin Bowling 	uint32_t mss_l4len_idx = 0;
9241f02257SKevin Bowling 	uint32_t paylen;
93f2d6ace4SSean Bruno 
94f2d6ace4SSean Bruno 	switch(pi->ipi_etype) {
95f2d6ace4SSean Bruno 	case ETHERTYPE_IPV6:
96f2d6ace4SSean Bruno 		type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV6;
97f2d6ace4SSean Bruno 		break;
98f2d6ace4SSean Bruno 	case ETHERTYPE_IP:
99f2d6ace4SSean Bruno 		type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4;
100f2d6ace4SSean Bruno 		/* Tell transmit desc to also do IPv4 checksum. */
101f2d6ace4SSean Bruno 		*olinfo_status |= E1000_TXD_POPTS_IXSM << 8;
102f2d6ace4SSean Bruno 		break;
103f2d6ace4SSean Bruno 	default:
104f2d6ace4SSean Bruno 		panic("%s: CSUM_TSO but no supported IP version (0x%04x)",
105f2d6ace4SSean Bruno 		    __func__, ntohs(pi->ipi_etype));
106f2d6ace4SSean Bruno 		break;
107f2d6ace4SSean Bruno 	}
108f2d6ace4SSean Bruno 
109f2d6ace4SSean Bruno 	TXD = (struct e1000_adv_tx_context_desc *)&txr->tx_base[pi->ipi_pidx];
110f2d6ace4SSean Bruno 
111f2d6ace4SSean Bruno 	/* This is used in the transmit desc in encap */
112*7390daf8SKevin Bowling 	paylen = pi->ipi_len - pi->ipi_ehdrlen - pi->ipi_ip_hlen -
113*7390daf8SKevin Bowling 	    pi->ipi_tcp_hlen;
114f2d6ace4SSean Bruno 
115f2d6ace4SSean Bruno 	/* VLAN MACLEN IPLEN */
116f2d6ace4SSean Bruno 	if (pi->ipi_mflags & M_VLANTAG) {
117f2d6ace4SSean Bruno 		vlan_macip_lens |= (pi->ipi_vtag << E1000_ADVTXD_VLAN_SHIFT);
118f2d6ace4SSean Bruno 	}
119f2d6ace4SSean Bruno 
120f2d6ace4SSean Bruno 	vlan_macip_lens |= pi->ipi_ehdrlen << E1000_ADVTXD_MACLEN_SHIFT;
121f2d6ace4SSean Bruno 	vlan_macip_lens |= pi->ipi_ip_hlen;
122f2d6ace4SSean Bruno 	TXD->vlan_macip_lens = htole32(vlan_macip_lens);
123f2d6ace4SSean Bruno 
124f2d6ace4SSean Bruno 	/* ADV DTYPE TUCMD */
125f2d6ace4SSean Bruno 	type_tucmd_mlhl |= E1000_ADVTXD_DCMD_DEXT | E1000_ADVTXD_DTYP_CTXT;
126f2d6ace4SSean Bruno 	type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP;
127f2d6ace4SSean Bruno 	TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
128f2d6ace4SSean Bruno 
129f2d6ace4SSean Bruno 	/* MSS L4LEN IDX */
130f2d6ace4SSean Bruno 	mss_l4len_idx |= (pi->ipi_tso_segsz << E1000_ADVTXD_MSS_SHIFT);
131f2d6ace4SSean Bruno 	mss_l4len_idx |= (pi->ipi_tcp_hlen << E1000_ADVTXD_L4LEN_SHIFT);
132f2d6ace4SSean Bruno 	/* 82575 needs the queue index added */
133dc926051SKevin Bowling 	if (sc->hw.mac.type == e1000_82575)
134f2d6ace4SSean Bruno 		mss_l4len_idx |= txr->me << 4;
135f2d6ace4SSean Bruno 	TXD->mss_l4len_idx = htole32(mss_l4len_idx);
136f2d6ace4SSean Bruno 
1376b9d35faSGuinan Sun 	TXD->u.seqnum_seed = htole32(0);
138f2d6ace4SSean Bruno 	*cmd_type_len |= E1000_ADVTXD_DCMD_TSE;
139f2d6ace4SSean Bruno 	*olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
140f2d6ace4SSean Bruno 	*olinfo_status |= paylen << E1000_ADVTXD_PAYLEN_SHIFT;
141f2d6ace4SSean Bruno 
142f2d6ace4SSean Bruno 	return (1);
143f2d6ace4SSean Bruno }
144f2d6ace4SSean Bruno 
145f2d6ace4SSean Bruno /*********************************************************************
146f2d6ace4SSean Bruno  *
147f2d6ace4SSean Bruno  *  Advanced Context Descriptor setup for VLAN, CSUM or TSO
148f2d6ace4SSean Bruno  *
149f2d6ace4SSean Bruno  **********************************************************************/
150f2d6ace4SSean Bruno static int
151*7390daf8SKevin Bowling igb_tx_ctx_setup(struct tx_ring *txr, if_pkt_info_t pi,
152*7390daf8SKevin Bowling     uint32_t *cmd_type_len, uint32_t *olinfo_status)
153f2d6ace4SSean Bruno {
154f2d6ace4SSean Bruno 	struct e1000_adv_tx_context_desc *TXD;
155dc926051SKevin Bowling 	struct e1000_softc *sc = txr->sc;
15641f02257SKevin Bowling 	uint32_t vlan_macip_lens, type_tucmd_mlhl;
15741f02257SKevin Bowling 	uint32_t mss_l4len_idx;
158f2d6ace4SSean Bruno 	mss_l4len_idx = vlan_macip_lens = type_tucmd_mlhl = 0;
159f2d6ace4SSean Bruno 
160f2d6ace4SSean Bruno 	/* First check if TSO is to be used */
161f2d6ace4SSean Bruno 	if (pi->ipi_csum_flags & CSUM_TSO)
162f2d6ace4SSean Bruno 		return (igb_tso_setup(txr, pi, cmd_type_len, olinfo_status));
163f2d6ace4SSean Bruno 
164f2d6ace4SSean Bruno 	/* Indicate the whole packet as payload when not doing TSO */
165f2d6ace4SSean Bruno 	*olinfo_status |= pi->ipi_len << E1000_ADVTXD_PAYLEN_SHIFT;
166f2d6ace4SSean Bruno 
167f2d6ace4SSean Bruno 	/* Now ready a context descriptor */
168f2d6ace4SSean Bruno 	TXD = (struct e1000_adv_tx_context_desc *)&txr->tx_base[pi->ipi_pidx];
169f2d6ace4SSean Bruno 
170f2d6ace4SSean Bruno 	/*
171f2d6ace4SSean Bruno 	** In advanced descriptors the vlan tag must
172f2d6ace4SSean Bruno 	** be placed into the context descriptor. Hence
173f2d6ace4SSean Bruno 	** we need to make one even if not doing offloads.
174f2d6ace4SSean Bruno 	*/
175f2d6ace4SSean Bruno 	if (pi->ipi_mflags & M_VLANTAG) {
176f2d6ace4SSean Bruno 		vlan_macip_lens |= (pi->ipi_vtag << E1000_ADVTXD_VLAN_SHIFT);
17782379056SSean Bruno 	} else if ((pi->ipi_csum_flags & IGB_CSUM_OFFLOAD) == 0) {
178f2d6ace4SSean Bruno 		return (0);
179f2d6ace4SSean Bruno 	}
180f2d6ace4SSean Bruno 
181f2d6ace4SSean Bruno 	/* Set the ether header length */
182f2d6ace4SSean Bruno 	vlan_macip_lens |= pi->ipi_ehdrlen << E1000_ADVTXD_MACLEN_SHIFT;
183f2d6ace4SSean Bruno 
184f2d6ace4SSean Bruno 	switch(pi->ipi_etype) {
185f2d6ace4SSean Bruno 	case ETHERTYPE_IP:
186f2d6ace4SSean Bruno 		type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4;
187f2d6ace4SSean Bruno 		break;
188f2d6ace4SSean Bruno 	case ETHERTYPE_IPV6:
189f2d6ace4SSean Bruno 		type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV6;
190f2d6ace4SSean Bruno 		break;
191f2d6ace4SSean Bruno 	default:
192f2d6ace4SSean Bruno 		break;
193f2d6ace4SSean Bruno 	}
194f2d6ace4SSean Bruno 
195f2d6ace4SSean Bruno 	vlan_macip_lens |= pi->ipi_ip_hlen;
196f2d6ace4SSean Bruno 	type_tucmd_mlhl |= E1000_ADVTXD_DCMD_DEXT | E1000_ADVTXD_DTYP_CTXT;
197f2d6ace4SSean Bruno 
198f2d6ace4SSean Bruno 	switch (pi->ipi_ipproto) {
199f2d6ace4SSean Bruno 	case IPPROTO_TCP:
200e873ccd0SStephen Hurd 		if (pi->ipi_csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) {
201f2d6ace4SSean Bruno 			type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP;
202e873ccd0SStephen Hurd 			*olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
203e873ccd0SStephen Hurd 		}
204f2d6ace4SSean Bruno 		break;
205f2d6ace4SSean Bruno 	case IPPROTO_UDP:
206e873ccd0SStephen Hurd 		if (pi->ipi_csum_flags & (CSUM_IP_UDP | CSUM_IP6_UDP)) {
207f2d6ace4SSean Bruno 			type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_UDP;
208e873ccd0SStephen Hurd 			*olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
209e873ccd0SStephen Hurd 		}
210f2d6ace4SSean Bruno 		break;
211f2d6ace4SSean Bruno 	case IPPROTO_SCTP:
212e873ccd0SStephen Hurd 		if (pi->ipi_csum_flags & (CSUM_IP_SCTP | CSUM_IP6_SCTP)) {
213f2d6ace4SSean Bruno 			type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_SCTP;
214e873ccd0SStephen Hurd 			*olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
215e873ccd0SStephen Hurd 		}
216f2d6ace4SSean Bruno 		break;
217f2d6ace4SSean Bruno 	default:
218f2d6ace4SSean Bruno 		break;
219f2d6ace4SSean Bruno 	}
220f2d6ace4SSean Bruno 
221f2d6ace4SSean Bruno 	/* 82575 needs the queue index added */
222dc926051SKevin Bowling 	if (sc->hw.mac.type == e1000_82575)
223f2d6ace4SSean Bruno 		mss_l4len_idx = txr->me << 4;
224f2d6ace4SSean Bruno 
225f2d6ace4SSean Bruno 	/* Now copy bits into descriptor */
226f2d6ace4SSean Bruno 	TXD->vlan_macip_lens = htole32(vlan_macip_lens);
227f2d6ace4SSean Bruno 	TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
2286b9d35faSGuinan Sun 	TXD->u.seqnum_seed = htole32(0);
229f2d6ace4SSean Bruno 	TXD->mss_l4len_idx = htole32(mss_l4len_idx);
230f2d6ace4SSean Bruno 
231f2d6ace4SSean Bruno 	return (1);
232f2d6ace4SSean Bruno }
233f2d6ace4SSean Bruno 
234f2d6ace4SSean Bruno static int
235f2d6ace4SSean Bruno igb_isc_txd_encap(void *arg, if_pkt_info_t pi)
236f2d6ace4SSean Bruno {
237dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
238f2d6ace4SSean Bruno 	if_softc_ctx_t scctx = sc->shared;
239f2d6ace4SSean Bruno 	struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx];
240f2d6ace4SSean Bruno 	struct tx_ring *txr = &que->txr;
241f2d6ace4SSean Bruno 	int nsegs = pi->ipi_nsegs;
242f2d6ace4SSean Bruno 	bus_dma_segment_t *segs = pi->ipi_segs;
243f2d6ace4SSean Bruno 	union e1000_adv_tx_desc *txd = NULL;
244151ba793SAlexander Kabaev 	int i, j, pidx_last;
24541f02257SKevin Bowling 	uint32_t olinfo_status, cmd_type_len, txd_flags;
24695246abbSSean Bruno 	qidx_t ntxd;
247f2d6ace4SSean Bruno 
248f2d6ace4SSean Bruno 	pidx_last = olinfo_status = 0;
249f2d6ace4SSean Bruno 	/* Basic descriptor defines */
250*7390daf8SKevin Bowling 	cmd_type_len = (E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_IFCS |
251*7390daf8SKevin Bowling 	    E1000_ADVTXD_DCMD_DEXT);
252f2d6ace4SSean Bruno 
253f2d6ace4SSean Bruno 	if (pi->ipi_mflags & M_VLANTAG)
254f2d6ace4SSean Bruno 		cmd_type_len |= E1000_ADVTXD_DCMD_VLE;
255f2d6ace4SSean Bruno 
256151ba793SAlexander Kabaev 	i = pi->ipi_pidx;
25795246abbSSean Bruno 	ntxd = scctx->isc_ntxd[0];
25895246abbSSean Bruno 	txd_flags = pi->ipi_flags & IPI_TX_INTR ? E1000_ADVTXD_DCMD_RS : 0;
259f2d6ace4SSean Bruno 	/* Consume the first descriptor */
260f2d6ace4SSean Bruno 	i += igb_tx_ctx_setup(txr, pi, &cmd_type_len, &olinfo_status);
261f2d6ace4SSean Bruno 	if (i == scctx->isc_ntxd[0])
262f2d6ace4SSean Bruno 		i = 0;
263f2d6ace4SSean Bruno 
264f2d6ace4SSean Bruno 	/* 82575 needs the queue index added */
265f2d6ace4SSean Bruno 	if (sc->hw.mac.type == e1000_82575)
266f2d6ace4SSean Bruno 		olinfo_status |= txr->me << 4;
267f2d6ace4SSean Bruno 
268f2d6ace4SSean Bruno 	for (j = 0; j < nsegs; j++) {
269f2d6ace4SSean Bruno 		bus_size_t seglen;
270f2d6ace4SSean Bruno 		bus_addr_t segaddr;
271f2d6ace4SSean Bruno 
272f2d6ace4SSean Bruno 		txd = (union e1000_adv_tx_desc *)&txr->tx_base[i];
273f2d6ace4SSean Bruno 		seglen = segs[j].ds_len;
274f2d6ace4SSean Bruno 		segaddr = htole64(segs[j].ds_addr);
275f2d6ace4SSean Bruno 
276f2d6ace4SSean Bruno 		txd->read.buffer_addr = segaddr;
277f2d6ace4SSean Bruno 		txd->read.cmd_type_len = htole32(E1000_TXD_CMD_IFCS |
278f2d6ace4SSean Bruno 		    cmd_type_len | seglen);
279f2d6ace4SSean Bruno 		txd->read.olinfo_status = htole32(olinfo_status);
280f2d6ace4SSean Bruno 		pidx_last = i;
281f2d6ace4SSean Bruno 		if (++i == scctx->isc_ntxd[0]) {
282f2d6ace4SSean Bruno 			i = 0;
283f2d6ace4SSean Bruno 		}
284f2d6ace4SSean Bruno 	}
28595246abbSSean Bruno 	if (txd_flags) {
28695246abbSSean Bruno 		txr->tx_rsq[txr->tx_rs_pidx] = pidx_last;
28795246abbSSean Bruno 		txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & (ntxd-1);
28895246abbSSean Bruno 		MPASS(txr->tx_rs_pidx != txr->tx_rs_cidx);
28995246abbSSean Bruno 	}
290f2d6ace4SSean Bruno 
29195246abbSSean Bruno 	txd->read.cmd_type_len |= htole32(E1000_TXD_CMD_EOP | txd_flags);
292f2d6ace4SSean Bruno 	pi->ipi_new_pidx = i;
293f2d6ace4SSean Bruno 
2943e501ef8SKevin Bowling 	/* Sent data accounting for AIM */
2953e501ef8SKevin Bowling 	txr->tx_bytes += pi->ipi_len;
2963e501ef8SKevin Bowling 	++txr->tx_packets;
2973e501ef8SKevin Bowling 
298f2d6ace4SSean Bruno 	return (0);
299f2d6ace4SSean Bruno }
300f2d6ace4SSean Bruno 
301f2d6ace4SSean Bruno static void
30295246abbSSean Bruno igb_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
303f2d6ace4SSean Bruno {
304dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
305dc926051SKevin Bowling 	struct em_tx_queue *que = &sc->tx_queues[txqid];
306f2d6ace4SSean Bruno 	struct tx_ring *txr = &que->txr;
307f2d6ace4SSean Bruno 
308dc926051SKevin Bowling 	E1000_WRITE_REG(&sc->hw, E1000_TDT(txr->me), pidx);
309f2d6ace4SSean Bruno }
310f2d6ace4SSean Bruno 
311f2d6ace4SSean Bruno static int
31295246abbSSean Bruno igb_isc_txd_credits_update(void *arg, uint16_t txqid, bool clear)
313f2d6ace4SSean Bruno {
314dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
315dc926051SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
316dc926051SKevin Bowling 	struct em_tx_queue *que = &sc->tx_queues[txqid];
317f2d6ace4SSean Bruno 	struct tx_ring *txr = &que->txr;
318f2d6ace4SSean Bruno 
31995246abbSSean Bruno 	qidx_t processed = 0;
32095246abbSSean Bruno 	int updated;
32195246abbSSean Bruno 	qidx_t cur, prev, ntxd, rs_cidx;
32295246abbSSean Bruno 	int32_t delta;
32395246abbSSean Bruno 	uint8_t status;
324f2d6ace4SSean Bruno 
32595246abbSSean Bruno 	rs_cidx = txr->tx_rs_cidx;
32695246abbSSean Bruno 	if (rs_cidx == txr->tx_rs_pidx)
32795246abbSSean Bruno 		return (0);
32895246abbSSean Bruno 	cur = txr->tx_rsq[rs_cidx];
32995246abbSSean Bruno 	status = ((union e1000_adv_tx_desc *)&txr->tx_base[cur])->wb.status;
33095246abbSSean Bruno 	updated = !!(status & E1000_TXD_STAT_DD);
331f2d6ace4SSean Bruno 
332adf93b56SEric Joyner 	if (!updated)
333adf93b56SEric Joyner 		return (0);
334adf93b56SEric Joyner 
335adf93b56SEric Joyner 	/* If clear is false just let caller know that there
336adf93b56SEric Joyner 	 * are descriptors to reclaim */
337adf93b56SEric Joyner 	if (!clear)
338adf93b56SEric Joyner 		return (1);
339f2d6ace4SSean Bruno 
34095246abbSSean Bruno 	prev = txr->tx_cidx_processed;
341f2d6ace4SSean Bruno 	ntxd = scctx->isc_ntxd[0];
342f2d6ace4SSean Bruno 	do {
343088a0b27SEric Joyner 		MPASS(prev != cur);
34495246abbSSean Bruno 		delta = (int32_t)cur - (int32_t)prev;
34595246abbSSean Bruno 		if (delta < 0)
34695246abbSSean Bruno 			delta += ntxd;
347088a0b27SEric Joyner 		MPASS(delta > 0);
34895246abbSSean Bruno 
34995246abbSSean Bruno 		processed += delta;
35095246abbSSean Bruno 		prev  = cur;
35195246abbSSean Bruno 		rs_cidx = (rs_cidx + 1) & (ntxd-1);
35295246abbSSean Bruno 		if (rs_cidx  == txr->tx_rs_pidx)
353f2d6ace4SSean Bruno 			break;
35495246abbSSean Bruno 		cur = txr->tx_rsq[rs_cidx];
355*7390daf8SKevin Bowling 		status = ((union e1000_adv_tx_desc *)
356*7390daf8SKevin Bowling 		    &txr->tx_base[cur])->wb.status;
35795246abbSSean Bruno 	} while ((status & E1000_TXD_STAT_DD));
358f2d6ace4SSean Bruno 
35995246abbSSean Bruno 	txr->tx_rs_cidx = rs_cidx;
36095246abbSSean Bruno 	txr->tx_cidx_processed = prev;
361f2d6ace4SSean Bruno 	return (processed);
362f2d6ace4SSean Bruno }
363f2d6ace4SSean Bruno 
364f2d6ace4SSean Bruno static void
36595246abbSSean Bruno igb_isc_rxd_refill(void *arg, if_rxd_update_t iru)
366f2d6ace4SSean Bruno {
367dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
368f2d6ace4SSean Bruno 	if_softc_ctx_t scctx = sc->shared;
36995246abbSSean Bruno 	uint16_t rxqid = iru->iru_qsidx;
370f2d6ace4SSean Bruno 	struct em_rx_queue *que = &sc->rx_queues[rxqid];
371f2d6ace4SSean Bruno 	union e1000_adv_rx_desc *rxd;
372f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
37395246abbSSean Bruno 	uint64_t *paddrs;
37495246abbSSean Bruno 	uint32_t next_pidx, pidx;
37595246abbSSean Bruno 	uint16_t count;
376f2d6ace4SSean Bruno 	int i;
37795246abbSSean Bruno 
37895246abbSSean Bruno 	paddrs = iru->iru_paddrs;
37995246abbSSean Bruno 	pidx = iru->iru_pidx;
38095246abbSSean Bruno 	count = iru->iru_count;
381f2d6ace4SSean Bruno 
382f2d6ace4SSean Bruno 	for (i = 0, next_pidx = pidx; i < count; i++) {
383f2d6ace4SSean Bruno 		rxd = (union e1000_adv_rx_desc *)&rxr->rx_base[next_pidx];
384f2d6ace4SSean Bruno 
385f2d6ace4SSean Bruno 		rxd->read.pkt_addr = htole64(paddrs[i]);
386f2d6ace4SSean Bruno 		if (++next_pidx == scctx->isc_nrxd[0])
387f2d6ace4SSean Bruno 			next_pidx = 0;
388f2d6ace4SSean Bruno 	}
389f2d6ace4SSean Bruno }
390f2d6ace4SSean Bruno 
391f2d6ace4SSean Bruno static void
392*7390daf8SKevin Bowling igb_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused,
393*7390daf8SKevin Bowling     qidx_t pidx)
394f2d6ace4SSean Bruno {
395dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
396f2d6ace4SSean Bruno 	struct em_rx_queue *que = &sc->rx_queues[rxqid];
397f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
398f2d6ace4SSean Bruno 
399f2d6ace4SSean Bruno 	E1000_WRITE_REG(&sc->hw, E1000_RDT(rxr->me), pidx);
400f2d6ace4SSean Bruno }
401f2d6ace4SSean Bruno 
402f2d6ace4SSean Bruno static int
40395246abbSSean Bruno igb_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget)
404f2d6ace4SSean Bruno {
405dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
406f2d6ace4SSean Bruno 	if_softc_ctx_t scctx = sc->shared;
407f2d6ace4SSean Bruno 	struct em_rx_queue *que = &sc->rx_queues[rxqid];
408f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
409f2d6ace4SSean Bruno 	union e1000_adv_rx_desc *rxd;
41041f02257SKevin Bowling 	uint32_t staterr = 0;
411adf93b56SEric Joyner 	int cnt, i;
412f2d6ace4SSean Bruno 
413adf93b56SEric Joyner 	for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) {
414f2d6ace4SSean Bruno 		rxd = (union e1000_adv_rx_desc *)&rxr->rx_base[i];
415f2d6ace4SSean Bruno 		staterr = le32toh(rxd->wb.upper.status_error);
416f2d6ace4SSean Bruno 
417f2d6ace4SSean Bruno 		if ((staterr & E1000_RXD_STAT_DD) == 0)
418f2d6ace4SSean Bruno 			break;
419adf93b56SEric Joyner 		if (++i == scctx->isc_nrxd[0])
420f2d6ace4SSean Bruno 			i = 0;
421f2d6ace4SSean Bruno 		if (staterr & E1000_RXD_STAT_EOP)
422f2d6ace4SSean Bruno 			cnt++;
423f2d6ace4SSean Bruno 	}
424f2d6ace4SSean Bruno 	return (cnt);
425f2d6ace4SSean Bruno }
426f2d6ace4SSean Bruno 
427f2d6ace4SSean Bruno /****************************************************************
428f2d6ace4SSean Bruno  * Routine sends data which has been dma'ed into host memory
429f2d6ace4SSean Bruno  * to upper layer. Initialize ri structure.
430f2d6ace4SSean Bruno  *
431f2d6ace4SSean Bruno  * Returns 0 upon success, errno on failure
432f2d6ace4SSean Bruno  ***************************************************************/
433f2d6ace4SSean Bruno 
434f2d6ace4SSean Bruno static int
435f2d6ace4SSean Bruno igb_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
436f2d6ace4SSean Bruno {
437dc926051SKevin Bowling 	struct e1000_softc *sc = arg;
438dc926051SKevin Bowling 	if_softc_ctx_t scctx = sc->shared;
439dc926051SKevin Bowling 	struct em_rx_queue *que = &sc->rx_queues[ri->iri_qsidx];
440f2d6ace4SSean Bruno 	struct rx_ring *rxr = &que->rxr;
441f2d6ace4SSean Bruno 	union e1000_adv_rx_desc *rxd;
442f2d6ace4SSean Bruno 
443f7926a6dSVincenzo Maffione 	uint16_t pkt_info, len;
44441f02257SKevin Bowling 	uint32_t ptype, staterr;
44541f02257SKevin Bowling 	int i, cidx;
446f2d6ace4SSean Bruno 	bool eop;
44741f02257SKevin Bowling 
448f7926a6dSVincenzo Maffione 	staterr = i = 0;
44941f02257SKevin Bowling 	cidx = ri->iri_cidx;
450f2d6ace4SSean Bruno 
451f2d6ace4SSean Bruno 	do {
452f2d6ace4SSean Bruno 		rxd = (union e1000_adv_rx_desc *)&rxr->rx_base[cidx];
453f2d6ace4SSean Bruno 		staterr = le32toh(rxd->wb.upper.status_error);
454f2d6ace4SSean Bruno 		pkt_info = le16toh(rxd->wb.lower.lo_dword.hs_rss.pkt_info);
455f2d6ace4SSean Bruno 
456f2d6ace4SSean Bruno 		MPASS ((staterr & E1000_RXD_STAT_DD) != 0);
457f2d6ace4SSean Bruno 
458f2d6ace4SSean Bruno 		len = le16toh(rxd->wb.upper.length);
459*7390daf8SKevin Bowling 		ptype =
460*7390daf8SKevin Bowling 		    le32toh(rxd->wb.lower.lo_dword.data) &  IGB_PKTTYPE_MASK;
461f2d6ace4SSean Bruno 
462f2d6ace4SSean Bruno 		ri->iri_len += len;
463f2d6ace4SSean Bruno 		rxr->rx_bytes += ri->iri_len;
464f2d6ace4SSean Bruno 
465f2d6ace4SSean Bruno 		rxd->wb.upper.status_error = 0;
466f2d6ace4SSean Bruno 		eop = ((staterr & E1000_RXD_STAT_EOP) == E1000_RXD_STAT_EOP);
467f2d6ace4SSean Bruno 
468f2d6ace4SSean Bruno 		/* Make sure bad packets are discarded */
469*7390daf8SKevin Bowling 		if (eop &&
470*7390daf8SKevin Bowling 		    ((staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) != 0)) {
471dc926051SKevin Bowling 			sc->dropped_pkts++;
472f2d6ace4SSean Bruno 			++rxr->rx_discarded;
473f2d6ace4SSean Bruno 			return (EBADMSG);
474f2d6ace4SSean Bruno 		}
475f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_flid = 0;
476f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_idx = cidx;
477f2d6ace4SSean Bruno 		ri->iri_frags[i].irf_len = len;
478f2d6ace4SSean Bruno 
479f2d6ace4SSean Bruno 		if (++cidx == scctx->isc_nrxd[0])
480f2d6ace4SSean Bruno 			cidx = 0;
481f2d6ace4SSean Bruno #ifdef notyet
4821bbdc25fSKevin Bowling 		if (rxr->hdr_split == true) {
483f2d6ace4SSean Bruno 			ri->iri_frags[i].irf_flid = 1;
484f2d6ace4SSean Bruno 			ri->iri_frags[i].irf_idx = cidx;
485f2d6ace4SSean Bruno 			if (++cidx == scctx->isc_nrxd[0])
486f2d6ace4SSean Bruno 				cidx = 0;
487f2d6ace4SSean Bruno 		}
488f2d6ace4SSean Bruno #endif
489f2d6ace4SSean Bruno 		i++;
490f2d6ace4SSean Bruno 	} while (!eop);
491f2d6ace4SSean Bruno 
492f2d6ace4SSean Bruno 	rxr->rx_packets++;
493f2d6ace4SSean Bruno 
49441f02257SKevin Bowling 	if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0)
495f2d6ace4SSean Bruno 		igb_rx_checksum(staterr, ri, ptype);
496f2d6ace4SSean Bruno 
497f7926a6dSVincenzo Maffione 	if (staterr & E1000_RXD_STAT_VP) {
498f7926a6dSVincenzo Maffione 		if (((sc->hw.mac.type == e1000_i350) ||
499f7926a6dSVincenzo Maffione 		    (sc->hw.mac.type == e1000_i354)) &&
500f7926a6dSVincenzo Maffione 		    (staterr & E1000_RXDEXT_STATERR_LB))
501f7926a6dSVincenzo Maffione 			ri->iri_vtag = be16toh(rxd->wb.upper.vlan);
502f7926a6dSVincenzo Maffione 		else
503f7926a6dSVincenzo Maffione 			ri->iri_vtag = le16toh(rxd->wb.upper.vlan);
504f2d6ace4SSean Bruno 		ri->iri_flags |= M_VLANTAG;
505f2d6ace4SSean Bruno 	}
50641f02257SKevin Bowling 
507f2d6ace4SSean Bruno 	ri->iri_flowid =
508f2d6ace4SSean Bruno 		le32toh(rxd->wb.lower.hi_dword.rss);
509f2d6ace4SSean Bruno 	ri->iri_rsstype = igb_determine_rsstype(pkt_info);
510f2d6ace4SSean Bruno 	ri->iri_nfrags = i;
511f2d6ace4SSean Bruno 
512f2d6ace4SSean Bruno 	return (0);
513f2d6ace4SSean Bruno }
514f2d6ace4SSean Bruno 
515f2d6ace4SSean Bruno /*********************************************************************
516f2d6ace4SSean Bruno  *
517f2d6ace4SSean Bruno  *  Verify that the hardware indicated that the checksum is valid.
518f2d6ace4SSean Bruno  *  Inform the stack about the status of checksum so that stack
519f2d6ace4SSean Bruno  *  doesn't spend time verifying the checksum.
520f2d6ace4SSean Bruno  *
521f2d6ace4SSean Bruno  *********************************************************************/
522f2d6ace4SSean Bruno static void
52341f02257SKevin Bowling igb_rx_checksum(uint32_t staterr, if_rxd_info_t ri, uint32_t ptype)
524f2d6ace4SSean Bruno {
52541f02257SKevin Bowling 	uint16_t status = (uint16_t)staterr;
52641f02257SKevin Bowling 	uint8_t errors = (uint8_t)(staterr >> 24);
527f2d6ace4SSean Bruno 
52841f02257SKevin Bowling 	if (__predict_false(status & E1000_RXD_STAT_IXSM))
529f2d6ace4SSean Bruno 		return;
530f2d6ace4SSean Bruno 
53141f02257SKevin Bowling 	/* If there is a layer 3 or 4 error we are done */
532*7390daf8SKevin Bowling 	if (__predict_false(errors &
533*7390daf8SKevin Bowling 	    (E1000_RXD_ERR_IPE | E1000_RXD_ERR_TCPE)))
53441f02257SKevin Bowling 		return;
535f2d6ace4SSean Bruno 
536f2d6ace4SSean Bruno 	/* IP Checksum Good */
53741f02257SKevin Bowling 	if (status & E1000_RXD_STAT_IPCS)
53841f02257SKevin Bowling 		ri->iri_csum_flags = (CSUM_IP_CHECKED | CSUM_IP_VALID);
539f2d6ace4SSean Bruno 
54041f02257SKevin Bowling 	/* Valid L4E checksum */
54141f02257SKevin Bowling 	if (__predict_true(status &
54241f02257SKevin Bowling 	    (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) {
543ff01d634SKevin Bowling 		/* SCTP header present */
544*7390daf8SKevin Bowling 		if (__predict_false(
545*7390daf8SKevin Bowling 		    (ptype & E1000_RXDADV_PKTTYPE_ETQF) == 0 &&
54641f02257SKevin Bowling 		    (ptype & E1000_RXDADV_PKTTYPE_SCTP) != 0)) {
54741f02257SKevin Bowling 			ri->iri_csum_flags |= CSUM_SCTP_VALID;
54841f02257SKevin Bowling 		} else {
549*7390daf8SKevin Bowling 			ri->iri_csum_flags |=
550*7390daf8SKevin Bowling 			    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
551f2d6ace4SSean Bruno 			ri->iri_csum_data = htons(0xffff);
552f2d6ace4SSean Bruno 		}
553f2d6ace4SSean Bruno 	}
554f2d6ace4SSean Bruno }
555f2d6ace4SSean Bruno 
556f2d6ace4SSean Bruno /********************************************************************
557f2d6ace4SSean Bruno  *
558f2d6ace4SSean Bruno  *  Parse the packet type to determine the appropriate hash
559f2d6ace4SSean Bruno  *
560f2d6ace4SSean Bruno  ******************************************************************/
561f2d6ace4SSean Bruno static int
56241f02257SKevin Bowling igb_determine_rsstype(uint16_t pkt_info)
563f2d6ace4SSean Bruno {
564f2d6ace4SSean Bruno 	switch (pkt_info & E1000_RXDADV_RSSTYPE_MASK) {
565f2d6ace4SSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV4_TCP:
566f2d6ace4SSean Bruno 		return M_HASHTYPE_RSS_TCP_IPV4;
567f2d6ace4SSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV4:
568f2d6ace4SSean Bruno 		return M_HASHTYPE_RSS_IPV4;
569f2d6ace4SSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV6_TCP:
570f2d6ace4SSean Bruno 		return M_HASHTYPE_RSS_TCP_IPV6;
571f2d6ace4SSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV6_EX:
572f2d6ace4SSean Bruno 		return M_HASHTYPE_RSS_IPV6_EX;
573f2d6ace4SSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV6:
574f2d6ace4SSean Bruno 		return M_HASHTYPE_RSS_IPV6;
575f2d6ace4SSean Bruno 	case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX:
576f2d6ace4SSean Bruno 		return M_HASHTYPE_RSS_TCP_IPV6_EX;
577f2d6ace4SSean Bruno 	default:
578f2d6ace4SSean Bruno 		return M_HASHTYPE_OPAQUE;
579f2d6ace4SSean Bruno 	}
580f2d6ace4SSean Bruno }
581