1517904deSPeter Grehan /*-
2517904deSPeter Grehan * SPDX-License-Identifier: BSD-2-Clause
3517904deSPeter Grehan *
4517904deSPeter Grehan * Copyright (c) 2016 Matthew Macy <mmacy@mattmacy.io>
5517904deSPeter Grehan * All rights reserved.
6517904deSPeter Grehan * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
7517904deSPeter Grehan *
8517904deSPeter Grehan * Redistribution and use in source and binary forms, with or without
9517904deSPeter Grehan * modification, are permitted provided that the following conditions
10517904deSPeter Grehan * are met:
11517904deSPeter Grehan * 1. Redistributions of source code must retain the above copyright
12517904deSPeter Grehan * notice, this list of conditions and the following disclaimer.
13517904deSPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright
14517904deSPeter Grehan * notice, this list of conditions and the following disclaimer in the
15517904deSPeter Grehan * documentation and/or other materials provided with the distribution.
16517904deSPeter Grehan *
17517904deSPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18517904deSPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19517904deSPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20517904deSPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21517904deSPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22517904deSPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23517904deSPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24517904deSPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25517904deSPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26517904deSPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27517904deSPeter Grehan * SUCH DAMAGE.
28517904deSPeter Grehan */
29517904deSPeter Grehan
30517904deSPeter Grehan #include <sys/cdefs.h>
31517904deSPeter Grehan #include "if_igc.h"
32517904deSPeter Grehan
33517904deSPeter Grehan #ifdef RSS
34517904deSPeter Grehan #include <net/rss_config.h>
35517904deSPeter Grehan #include <netinet/in_rss.h>
36517904deSPeter Grehan #endif
37517904deSPeter Grehan
38517904deSPeter Grehan #ifdef VERBOSE_DEBUG
39517904deSPeter Grehan #define DPRINTF device_printf
40517904deSPeter Grehan #else
41517904deSPeter Grehan #define DPRINTF(...)
42517904deSPeter Grehan #endif
43517904deSPeter Grehan
44517904deSPeter Grehan /*********************************************************************
45517904deSPeter Grehan * Local Function prototypes
46517904deSPeter Grehan *********************************************************************/
477763b194SKevin Bowling static int igc_isc_txd_encap(void *, if_pkt_info_t);
487763b194SKevin Bowling static void igc_isc_txd_flush(void *, uint16_t, qidx_t);
497763b194SKevin Bowling static int igc_isc_txd_credits_update(void *, uint16_t, bool);
50517904deSPeter Grehan
517763b194SKevin Bowling static void igc_isc_rxd_refill(void *, if_rxd_update_t);
52517904deSPeter Grehan
537763b194SKevin Bowling static void igc_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t);
547763b194SKevin Bowling static int igc_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t);
55517904deSPeter Grehan
567763b194SKevin Bowling static int igc_isc_rxd_pkt_get(void *, if_rxd_info_t);
57517904deSPeter Grehan
587763b194SKevin Bowling static int igc_tx_ctx_setup(struct tx_ring *, if_pkt_info_t, uint32_t *,
597763b194SKevin Bowling uint32_t *);
607763b194SKevin Bowling static int igc_tso_setup(struct tx_ring *, if_pkt_info_t, uint32_t *,
617763b194SKevin Bowling uint32_t *);
62517904deSPeter Grehan
637763b194SKevin Bowling static void igc_rx_checksum(uint32_t, if_rxd_info_t, uint32_t);
647763b194SKevin Bowling static int igc_determine_rsstype(uint16_t);
65517904deSPeter Grehan
667763b194SKevin Bowling extern void igc_if_enable_intr(if_ctx_t);
677763b194SKevin Bowling extern int igc_intr(void *);
68517904deSPeter Grehan
69517904deSPeter Grehan struct if_txrx igc_txrx = {
70517904deSPeter Grehan .ift_txd_encap = igc_isc_txd_encap,
71517904deSPeter Grehan .ift_txd_flush = igc_isc_txd_flush,
72517904deSPeter Grehan .ift_txd_credits_update = igc_isc_txd_credits_update,
73517904deSPeter Grehan .ift_rxd_available = igc_isc_rxd_available,
74517904deSPeter Grehan .ift_rxd_pkt_get = igc_isc_rxd_pkt_get,
75517904deSPeter Grehan .ift_rxd_refill = igc_isc_rxd_refill,
76517904deSPeter Grehan .ift_rxd_flush = igc_isc_rxd_flush,
77517904deSPeter Grehan .ift_legacy_intr = igc_intr
78517904deSPeter Grehan };
79517904deSPeter Grehan
80517904deSPeter Grehan void
igc_dump_rs(struct igc_softc * sc)81542f5d56SKevin Bowling igc_dump_rs(struct igc_softc *sc)
82517904deSPeter Grehan {
83542f5d56SKevin Bowling if_softc_ctx_t scctx = sc->shared;
84517904deSPeter Grehan struct igc_tx_queue *que;
85517904deSPeter Grehan struct tx_ring *txr;
86517904deSPeter Grehan qidx_t i, ntxd, qid, cur;
87517904deSPeter Grehan int16_t rs_cidx;
88517904deSPeter Grehan uint8_t status;
89517904deSPeter Grehan
90517904deSPeter Grehan printf("\n");
91517904deSPeter Grehan ntxd = scctx->isc_ntxd[0];
92542f5d56SKevin Bowling for (qid = 0; qid < sc->tx_num_queues; qid++) {
93542f5d56SKevin Bowling que = &sc->tx_queues[qid];
94517904deSPeter Grehan txr = &que->txr;
95517904deSPeter Grehan rs_cidx = txr->tx_rs_cidx;
96517904deSPeter Grehan if (rs_cidx != txr->tx_rs_pidx) {
97517904deSPeter Grehan cur = txr->tx_rsq[rs_cidx];
98517904deSPeter Grehan status = txr->tx_base[cur].upper.fields.status;
99517904deSPeter Grehan if (!(status & IGC_TXD_STAT_DD))
100*c7fb7b5dSKevin Bowling printf("qid[%d]->tx_rsq[%d]: %d clear ",
101*c7fb7b5dSKevin Bowling qid, rs_cidx, cur);
102517904deSPeter Grehan } else {
103517904deSPeter Grehan rs_cidx = (rs_cidx-1)&(ntxd-1);
104517904deSPeter Grehan cur = txr->tx_rsq[rs_cidx];
105*c7fb7b5dSKevin Bowling printf("qid[%d]->tx_rsq[rs_cidx-1=%d]: %d ",
106*c7fb7b5dSKevin Bowling qid, rs_cidx, cur);
107517904deSPeter Grehan }
108*c7fb7b5dSKevin Bowling printf("cidx_prev=%d rs_pidx=%d ",txr->tx_cidx_processed,
109*c7fb7b5dSKevin Bowling txr->tx_rs_pidx);
110517904deSPeter Grehan for (i = 0; i < ntxd; i++) {
111*c7fb7b5dSKevin Bowling if (txr->tx_base[i].upper.fields.status &
112*c7fb7b5dSKevin Bowling IGC_TXD_STAT_DD)
113517904deSPeter Grehan printf("%d set ", i);
114517904deSPeter Grehan }
115517904deSPeter Grehan printf("\n");
116517904deSPeter Grehan }
117517904deSPeter Grehan }
118517904deSPeter Grehan
119517904deSPeter Grehan /**********************************************************************
120517904deSPeter Grehan *
121517904deSPeter Grehan * Setup work for hardware segmentation offload (TSO) on
122517904deSPeter Grehan * adapters using advanced tx descriptors
123517904deSPeter Grehan *
124517904deSPeter Grehan **********************************************************************/
125517904deSPeter Grehan static int
igc_tso_setup(struct tx_ring * txr,if_pkt_info_t pi,uint32_t * cmd_type_len,uint32_t * olinfo_status)126d02e4363SKevin Bowling igc_tso_setup(struct tx_ring *txr, if_pkt_info_t pi, uint32_t *cmd_type_len,
127d02e4363SKevin Bowling uint32_t *olinfo_status)
128517904deSPeter Grehan {
129517904deSPeter Grehan struct igc_adv_tx_context_desc *TXD;
130d02e4363SKevin Bowling uint32_t type_tucmd_mlhl = 0, vlan_macip_lens = 0;
131d02e4363SKevin Bowling uint32_t mss_l4len_idx = 0;
132d02e4363SKevin Bowling uint32_t paylen;
133517904deSPeter Grehan
134517904deSPeter Grehan switch(pi->ipi_etype) {
135517904deSPeter Grehan case ETHERTYPE_IPV6:
136517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV6;
137517904deSPeter Grehan break;
138517904deSPeter Grehan case ETHERTYPE_IP:
139517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV4;
140517904deSPeter Grehan /* Tell transmit desc to also do IPv4 checksum. */
141517904deSPeter Grehan *olinfo_status |= IGC_TXD_POPTS_IXSM << 8;
142517904deSPeter Grehan break;
143517904deSPeter Grehan default:
144517904deSPeter Grehan panic("%s: CSUM_TSO but no supported IP version (0x%04x)",
145517904deSPeter Grehan __func__, ntohs(pi->ipi_etype));
146517904deSPeter Grehan break;
147517904deSPeter Grehan }
148517904deSPeter Grehan
149517904deSPeter Grehan TXD = (struct igc_adv_tx_context_desc *) &txr->tx_base[pi->ipi_pidx];
150517904deSPeter Grehan
151517904deSPeter Grehan /* This is used in the transmit desc in encap */
152*c7fb7b5dSKevin Bowling paylen = pi->ipi_len - pi->ipi_ehdrlen - pi->ipi_ip_hlen -
153*c7fb7b5dSKevin Bowling pi->ipi_tcp_hlen;
154517904deSPeter Grehan
155517904deSPeter Grehan /* VLAN MACLEN IPLEN */
156517904deSPeter Grehan if (pi->ipi_mflags & M_VLANTAG) {
157517904deSPeter Grehan vlan_macip_lens |= (pi->ipi_vtag << IGC_ADVTXD_VLAN_SHIFT);
158517904deSPeter Grehan }
159517904deSPeter Grehan
160517904deSPeter Grehan vlan_macip_lens |= pi->ipi_ehdrlen << IGC_ADVTXD_MACLEN_SHIFT;
161517904deSPeter Grehan vlan_macip_lens |= pi->ipi_ip_hlen;
162517904deSPeter Grehan TXD->vlan_macip_lens = htole32(vlan_macip_lens);
163517904deSPeter Grehan
164517904deSPeter Grehan /* ADV DTYPE TUCMD */
165517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_DCMD_DEXT | IGC_ADVTXD_DTYP_CTXT;
166517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_TCP;
167517904deSPeter Grehan TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
168517904deSPeter Grehan
169517904deSPeter Grehan /* MSS L4LEN IDX */
170517904deSPeter Grehan mss_l4len_idx |= (pi->ipi_tso_segsz << IGC_ADVTXD_MSS_SHIFT);
171517904deSPeter Grehan mss_l4len_idx |= (pi->ipi_tcp_hlen << IGC_ADVTXD_L4LEN_SHIFT);
172517904deSPeter Grehan TXD->mss_l4len_idx = htole32(mss_l4len_idx);
173517904deSPeter Grehan
174517904deSPeter Grehan TXD->seqnum_seed = htole32(0);
175517904deSPeter Grehan *cmd_type_len |= IGC_ADVTXD_DCMD_TSE;
176517904deSPeter Grehan *olinfo_status |= IGC_TXD_POPTS_TXSM << 8;
177517904deSPeter Grehan *olinfo_status |= paylen << IGC_ADVTXD_PAYLEN_SHIFT;
178517904deSPeter Grehan
179517904deSPeter Grehan return (1);
180517904deSPeter Grehan }
181517904deSPeter Grehan
182517904deSPeter Grehan /*********************************************************************
183517904deSPeter Grehan *
184517904deSPeter Grehan * Advanced Context Descriptor setup for VLAN, CSUM or TSO
185517904deSPeter Grehan *
186517904deSPeter Grehan **********************************************************************/
187517904deSPeter Grehan static int
igc_tx_ctx_setup(struct tx_ring * txr,if_pkt_info_t pi,uint32_t * cmd_type_len,uint32_t * olinfo_status)188*c7fb7b5dSKevin Bowling igc_tx_ctx_setup(struct tx_ring *txr, if_pkt_info_t pi,
189*c7fb7b5dSKevin Bowling uint32_t *cmd_type_len, uint32_t *olinfo_status)
190517904deSPeter Grehan {
191517904deSPeter Grehan struct igc_adv_tx_context_desc *TXD;
192d02e4363SKevin Bowling uint32_t vlan_macip_lens, type_tucmd_mlhl;
193d02e4363SKevin Bowling uint32_t mss_l4len_idx;
194517904deSPeter Grehan mss_l4len_idx = vlan_macip_lens = type_tucmd_mlhl = 0;
195517904deSPeter Grehan
196517904deSPeter Grehan /* First check if TSO is to be used */
197517904deSPeter Grehan if (pi->ipi_csum_flags & CSUM_TSO)
198517904deSPeter Grehan return (igc_tso_setup(txr, pi, cmd_type_len, olinfo_status));
199517904deSPeter Grehan
200517904deSPeter Grehan /* Indicate the whole packet as payload when not doing TSO */
201517904deSPeter Grehan *olinfo_status |= pi->ipi_len << IGC_ADVTXD_PAYLEN_SHIFT;
202517904deSPeter Grehan
203517904deSPeter Grehan /* Now ready a context descriptor */
204517904deSPeter Grehan TXD = (struct igc_adv_tx_context_desc *) &txr->tx_base[pi->ipi_pidx];
205517904deSPeter Grehan
206517904deSPeter Grehan /*
207517904deSPeter Grehan ** In advanced descriptors the vlan tag must
208517904deSPeter Grehan ** be placed into the context descriptor. Hence
209517904deSPeter Grehan ** we need to make one even if not doing offloads.
210517904deSPeter Grehan */
211517904deSPeter Grehan if (pi->ipi_mflags & M_VLANTAG) {
212517904deSPeter Grehan vlan_macip_lens |= (pi->ipi_vtag << IGC_ADVTXD_VLAN_SHIFT);
213517904deSPeter Grehan } else if ((pi->ipi_csum_flags & IGC_CSUM_OFFLOAD) == 0) {
214517904deSPeter Grehan return (0);
215517904deSPeter Grehan }
216517904deSPeter Grehan
217517904deSPeter Grehan /* Set the ether header length */
218517904deSPeter Grehan vlan_macip_lens |= pi->ipi_ehdrlen << IGC_ADVTXD_MACLEN_SHIFT;
219517904deSPeter Grehan
220517904deSPeter Grehan switch(pi->ipi_etype) {
221517904deSPeter Grehan case ETHERTYPE_IP:
222517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV4;
223517904deSPeter Grehan break;
224517904deSPeter Grehan case ETHERTYPE_IPV6:
225517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV6;
226517904deSPeter Grehan break;
227517904deSPeter Grehan default:
228517904deSPeter Grehan break;
229517904deSPeter Grehan }
230517904deSPeter Grehan
231517904deSPeter Grehan vlan_macip_lens |= pi->ipi_ip_hlen;
232517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_DCMD_DEXT | IGC_ADVTXD_DTYP_CTXT;
233517904deSPeter Grehan
234517904deSPeter Grehan switch (pi->ipi_ipproto) {
235517904deSPeter Grehan case IPPROTO_TCP:
236517904deSPeter Grehan if (pi->ipi_csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) {
237517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_TCP;
238517904deSPeter Grehan *olinfo_status |= IGC_TXD_POPTS_TXSM << 8;
239517904deSPeter Grehan }
240517904deSPeter Grehan break;
241517904deSPeter Grehan case IPPROTO_UDP:
242517904deSPeter Grehan if (pi->ipi_csum_flags & (CSUM_IP_UDP | CSUM_IP6_UDP)) {
243517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_UDP;
244517904deSPeter Grehan *olinfo_status |= IGC_TXD_POPTS_TXSM << 8;
245517904deSPeter Grehan }
246517904deSPeter Grehan break;
247517904deSPeter Grehan case IPPROTO_SCTP:
248517904deSPeter Grehan if (pi->ipi_csum_flags & (CSUM_IP_SCTP | CSUM_IP6_SCTP)) {
249517904deSPeter Grehan type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_L4T_SCTP;
250517904deSPeter Grehan *olinfo_status |= IGC_TXD_POPTS_TXSM << 8;
251517904deSPeter Grehan }
252517904deSPeter Grehan break;
253517904deSPeter Grehan default:
254517904deSPeter Grehan break;
255517904deSPeter Grehan }
256517904deSPeter Grehan
257517904deSPeter Grehan /* Now copy bits into descriptor */
258517904deSPeter Grehan TXD->vlan_macip_lens = htole32(vlan_macip_lens);
259517904deSPeter Grehan TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl);
260517904deSPeter Grehan TXD->seqnum_seed = htole32(0);
261517904deSPeter Grehan TXD->mss_l4len_idx = htole32(mss_l4len_idx);
262517904deSPeter Grehan
263517904deSPeter Grehan return (1);
264517904deSPeter Grehan }
265517904deSPeter Grehan
266517904deSPeter Grehan static int
igc_isc_txd_encap(void * arg,if_pkt_info_t pi)267517904deSPeter Grehan igc_isc_txd_encap(void *arg, if_pkt_info_t pi)
268517904deSPeter Grehan {
269542f5d56SKevin Bowling struct igc_softc *sc = arg;
270517904deSPeter Grehan if_softc_ctx_t scctx = sc->shared;
271517904deSPeter Grehan struct igc_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx];
272517904deSPeter Grehan struct tx_ring *txr = &que->txr;
273517904deSPeter Grehan int nsegs = pi->ipi_nsegs;
274517904deSPeter Grehan bus_dma_segment_t *segs = pi->ipi_segs;
275517904deSPeter Grehan union igc_adv_tx_desc *txd = NULL;
276517904deSPeter Grehan int i, j, pidx_last;
277d02e4363SKevin Bowling uint32_t olinfo_status, cmd_type_len, txd_flags;
278517904deSPeter Grehan qidx_t ntxd;
279517904deSPeter Grehan
280517904deSPeter Grehan pidx_last = olinfo_status = 0;
281517904deSPeter Grehan /* Basic descriptor defines */
282517904deSPeter Grehan cmd_type_len = (IGC_ADVTXD_DTYP_DATA |
283517904deSPeter Grehan IGC_ADVTXD_DCMD_IFCS | IGC_ADVTXD_DCMD_DEXT);
284517904deSPeter Grehan
285517904deSPeter Grehan if (pi->ipi_mflags & M_VLANTAG)
286517904deSPeter Grehan cmd_type_len |= IGC_ADVTXD_DCMD_VLE;
287517904deSPeter Grehan
288517904deSPeter Grehan i = pi->ipi_pidx;
289517904deSPeter Grehan ntxd = scctx->isc_ntxd[0];
290517904deSPeter Grehan txd_flags = pi->ipi_flags & IPI_TX_INTR ? IGC_ADVTXD_DCMD_RS : 0;
291517904deSPeter Grehan /* Consume the first descriptor */
292517904deSPeter Grehan i += igc_tx_ctx_setup(txr, pi, &cmd_type_len, &olinfo_status);
293517904deSPeter Grehan if (i == scctx->isc_ntxd[0])
294517904deSPeter Grehan i = 0;
295517904deSPeter Grehan
296517904deSPeter Grehan for (j = 0; j < nsegs; j++) {
297517904deSPeter Grehan bus_size_t seglen;
298517904deSPeter Grehan bus_addr_t segaddr;
299517904deSPeter Grehan
300517904deSPeter Grehan txd = (union igc_adv_tx_desc *)&txr->tx_base[i];
301517904deSPeter Grehan seglen = segs[j].ds_len;
302517904deSPeter Grehan segaddr = htole64(segs[j].ds_addr);
303517904deSPeter Grehan
304517904deSPeter Grehan txd->read.buffer_addr = segaddr;
305517904deSPeter Grehan txd->read.cmd_type_len = htole32(IGC_ADVTXD_DCMD_IFCS |
306517904deSPeter Grehan cmd_type_len | seglen);
307517904deSPeter Grehan txd->read.olinfo_status = htole32(olinfo_status);
308517904deSPeter Grehan pidx_last = i;
309517904deSPeter Grehan if (++i == scctx->isc_ntxd[0]) {
310517904deSPeter Grehan i = 0;
311517904deSPeter Grehan }
312517904deSPeter Grehan }
313517904deSPeter Grehan if (txd_flags) {
314517904deSPeter Grehan txr->tx_rsq[txr->tx_rs_pidx] = pidx_last;
315517904deSPeter Grehan txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & (ntxd-1);
316517904deSPeter Grehan MPASS(txr->tx_rs_pidx != txr->tx_rs_cidx);
317517904deSPeter Grehan }
318517904deSPeter Grehan
319517904deSPeter Grehan txd->read.cmd_type_len |= htole32(IGC_ADVTXD_DCMD_EOP | txd_flags);
320517904deSPeter Grehan pi->ipi_new_pidx = i;
321517904deSPeter Grehan
322bc9402abSKevin Bowling /* Sent data accounting for AIM */
323bc9402abSKevin Bowling txr->tx_bytes += pi->ipi_len;
324bc9402abSKevin Bowling ++txr->tx_packets;
325bc9402abSKevin Bowling
326517904deSPeter Grehan return (0);
327517904deSPeter Grehan }
328517904deSPeter Grehan
329517904deSPeter Grehan static void
igc_isc_txd_flush(void * arg,uint16_t txqid,qidx_t pidx)330517904deSPeter Grehan igc_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
331517904deSPeter Grehan {
332542f5d56SKevin Bowling struct igc_softc *sc = arg;
333542f5d56SKevin Bowling struct igc_tx_queue *que = &sc->tx_queues[txqid];
334517904deSPeter Grehan struct tx_ring *txr = &que->txr;
335517904deSPeter Grehan
336542f5d56SKevin Bowling IGC_WRITE_REG(&sc->hw, IGC_TDT(txr->me), pidx);
337517904deSPeter Grehan }
338517904deSPeter Grehan
339517904deSPeter Grehan static int
igc_isc_txd_credits_update(void * arg,uint16_t txqid,bool clear)340517904deSPeter Grehan igc_isc_txd_credits_update(void *arg, uint16_t txqid, bool clear)
341517904deSPeter Grehan {
342542f5d56SKevin Bowling struct igc_softc *sc = arg;
343542f5d56SKevin Bowling if_softc_ctx_t scctx = sc->shared;
344542f5d56SKevin Bowling struct igc_tx_queue *que = &sc->tx_queues[txqid];
345517904deSPeter Grehan struct tx_ring *txr = &que->txr;
346517904deSPeter Grehan
347517904deSPeter Grehan qidx_t processed = 0;
348517904deSPeter Grehan int updated;
349517904deSPeter Grehan qidx_t cur, prev, ntxd, rs_cidx;
350517904deSPeter Grehan int32_t delta;
351517904deSPeter Grehan uint8_t status;
352517904deSPeter Grehan
353517904deSPeter Grehan rs_cidx = txr->tx_rs_cidx;
354517904deSPeter Grehan if (rs_cidx == txr->tx_rs_pidx)
355517904deSPeter Grehan return (0);
356517904deSPeter Grehan cur = txr->tx_rsq[rs_cidx];
357517904deSPeter Grehan status = ((union igc_adv_tx_desc *)&txr->tx_base[cur])->wb.status;
358517904deSPeter Grehan updated = !!(status & IGC_TXD_STAT_DD);
359517904deSPeter Grehan
360517904deSPeter Grehan if (!updated)
361517904deSPeter Grehan return (0);
362517904deSPeter Grehan
363517904deSPeter Grehan /* If clear is false just let caller know that there
364517904deSPeter Grehan * are descriptors to reclaim */
365517904deSPeter Grehan if (!clear)
366517904deSPeter Grehan return (1);
367517904deSPeter Grehan
368517904deSPeter Grehan prev = txr->tx_cidx_processed;
369517904deSPeter Grehan ntxd = scctx->isc_ntxd[0];
370517904deSPeter Grehan do {
371517904deSPeter Grehan MPASS(prev != cur);
372517904deSPeter Grehan delta = (int32_t)cur - (int32_t)prev;
373517904deSPeter Grehan if (delta < 0)
374517904deSPeter Grehan delta += ntxd;
375517904deSPeter Grehan MPASS(delta > 0);
376517904deSPeter Grehan
377517904deSPeter Grehan processed += delta;
378517904deSPeter Grehan prev = cur;
379517904deSPeter Grehan rs_cidx = (rs_cidx + 1) & (ntxd-1);
380517904deSPeter Grehan if (rs_cidx == txr->tx_rs_pidx)
381517904deSPeter Grehan break;
382517904deSPeter Grehan cur = txr->tx_rsq[rs_cidx];
383*c7fb7b5dSKevin Bowling status =
384*c7fb7b5dSKevin Bowling ((union igc_adv_tx_desc *)&txr->tx_base[cur])->wb.status;
385517904deSPeter Grehan } while ((status & IGC_TXD_STAT_DD));
386517904deSPeter Grehan
387517904deSPeter Grehan txr->tx_rs_cidx = rs_cidx;
388517904deSPeter Grehan txr->tx_cidx_processed = prev;
389517904deSPeter Grehan return (processed);
390517904deSPeter Grehan }
391517904deSPeter Grehan
392517904deSPeter Grehan static void
igc_isc_rxd_refill(void * arg,if_rxd_update_t iru)393517904deSPeter Grehan igc_isc_rxd_refill(void *arg, if_rxd_update_t iru)
394517904deSPeter Grehan {
395542f5d56SKevin Bowling struct igc_softc *sc = arg;
396517904deSPeter Grehan if_softc_ctx_t scctx = sc->shared;
397517904deSPeter Grehan uint16_t rxqid = iru->iru_qsidx;
398517904deSPeter Grehan struct igc_rx_queue *que = &sc->rx_queues[rxqid];
399517904deSPeter Grehan union igc_adv_rx_desc *rxd;
400517904deSPeter Grehan struct rx_ring *rxr = &que->rxr;
401517904deSPeter Grehan uint64_t *paddrs;
402517904deSPeter Grehan uint32_t next_pidx, pidx;
403517904deSPeter Grehan uint16_t count;
404517904deSPeter Grehan int i;
405517904deSPeter Grehan
406517904deSPeter Grehan paddrs = iru->iru_paddrs;
407517904deSPeter Grehan pidx = iru->iru_pidx;
408517904deSPeter Grehan count = iru->iru_count;
409517904deSPeter Grehan
410517904deSPeter Grehan for (i = 0, next_pidx = pidx; i < count; i++) {
411517904deSPeter Grehan rxd = (union igc_adv_rx_desc *)&rxr->rx_base[next_pidx];
412517904deSPeter Grehan
413517904deSPeter Grehan rxd->read.pkt_addr = htole64(paddrs[i]);
414517904deSPeter Grehan if (++next_pidx == scctx->isc_nrxd[0])
415517904deSPeter Grehan next_pidx = 0;
416517904deSPeter Grehan }
417517904deSPeter Grehan }
418517904deSPeter Grehan
419517904deSPeter Grehan static void
igc_isc_rxd_flush(void * arg,uint16_t rxqid,uint8_t flid __unused,qidx_t pidx)420*c7fb7b5dSKevin Bowling igc_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused,
421*c7fb7b5dSKevin Bowling qidx_t pidx)
422517904deSPeter Grehan {
423542f5d56SKevin Bowling struct igc_softc *sc = arg;
424517904deSPeter Grehan struct igc_rx_queue *que = &sc->rx_queues[rxqid];
425517904deSPeter Grehan struct rx_ring *rxr = &que->rxr;
426517904deSPeter Grehan
427517904deSPeter Grehan IGC_WRITE_REG(&sc->hw, IGC_RDT(rxr->me), pidx);
428517904deSPeter Grehan }
429517904deSPeter Grehan
430517904deSPeter Grehan static int
igc_isc_rxd_available(void * arg,uint16_t rxqid,qidx_t idx,qidx_t budget)431517904deSPeter Grehan igc_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget)
432517904deSPeter Grehan {
433542f5d56SKevin Bowling struct igc_softc *sc = arg;
434517904deSPeter Grehan if_softc_ctx_t scctx = sc->shared;
435517904deSPeter Grehan struct igc_rx_queue *que = &sc->rx_queues[rxqid];
436517904deSPeter Grehan struct rx_ring *rxr = &que->rxr;
437517904deSPeter Grehan union igc_adv_rx_desc *rxd;
438d02e4363SKevin Bowling uint32_t staterr = 0;
439517904deSPeter Grehan int cnt, i;
440517904deSPeter Grehan
441517904deSPeter Grehan for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) {
442517904deSPeter Grehan rxd = (union igc_adv_rx_desc *)&rxr->rx_base[i];
443517904deSPeter Grehan staterr = le32toh(rxd->wb.upper.status_error);
444517904deSPeter Grehan
445517904deSPeter Grehan if ((staterr & IGC_RXD_STAT_DD) == 0)
446517904deSPeter Grehan break;
447517904deSPeter Grehan if (++i == scctx->isc_nrxd[0])
448517904deSPeter Grehan i = 0;
449517904deSPeter Grehan if (staterr & IGC_RXD_STAT_EOP)
450517904deSPeter Grehan cnt++;
451517904deSPeter Grehan }
452517904deSPeter Grehan return (cnt);
453517904deSPeter Grehan }
454517904deSPeter Grehan
455517904deSPeter Grehan /****************************************************************
456517904deSPeter Grehan * Routine sends data which has been dma'ed into host memory
457517904deSPeter Grehan * to upper layer. Initialize ri structure.
458517904deSPeter Grehan *
459517904deSPeter Grehan * Returns 0 upon success, errno on failure
460517904deSPeter Grehan ***************************************************************/
461517904deSPeter Grehan
462517904deSPeter Grehan static int
igc_isc_rxd_pkt_get(void * arg,if_rxd_info_t ri)463517904deSPeter Grehan igc_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
464517904deSPeter Grehan {
465542f5d56SKevin Bowling struct igc_softc *sc = arg;
466542f5d56SKevin Bowling if_softc_ctx_t scctx = sc->shared;
467542f5d56SKevin Bowling struct igc_rx_queue *que = &sc->rx_queues[ri->iri_qsidx];
468517904deSPeter Grehan struct rx_ring *rxr = &que->rxr;
469517904deSPeter Grehan union igc_adv_rx_desc *rxd;
470517904deSPeter Grehan
471f7926a6dSVincenzo Maffione uint16_t pkt_info, len;
472d02e4363SKevin Bowling uint32_t ptype, staterr;
473d02e4363SKevin Bowling int i, cidx;
474517904deSPeter Grehan bool eop;
475d02e4363SKevin Bowling
476f7926a6dSVincenzo Maffione staterr = i = 0;
477d02e4363SKevin Bowling cidx = ri->iri_cidx;
478517904deSPeter Grehan
479517904deSPeter Grehan do {
480517904deSPeter Grehan rxd = (union igc_adv_rx_desc *)&rxr->rx_base[cidx];
481517904deSPeter Grehan staterr = le32toh(rxd->wb.upper.status_error);
482517904deSPeter Grehan pkt_info = le16toh(rxd->wb.lower.lo_dword.hs_rss.pkt_info);
483517904deSPeter Grehan
484517904deSPeter Grehan MPASS ((staterr & IGC_RXD_STAT_DD) != 0);
485517904deSPeter Grehan
486517904deSPeter Grehan len = le16toh(rxd->wb.upper.length);
487*c7fb7b5dSKevin Bowling ptype =
488*c7fb7b5dSKevin Bowling le32toh(rxd->wb.lower.lo_dword.data) & IGC_PKTTYPE_MASK;
489517904deSPeter Grehan
490517904deSPeter Grehan ri->iri_len += len;
491517904deSPeter Grehan rxr->rx_bytes += ri->iri_len;
492517904deSPeter Grehan
493517904deSPeter Grehan rxd->wb.upper.status_error = 0;
494517904deSPeter Grehan eop = ((staterr & IGC_RXD_STAT_EOP) == IGC_RXD_STAT_EOP);
495517904deSPeter Grehan
496517904deSPeter Grehan /* Make sure bad packets are discarded */
497517904deSPeter Grehan if (eop && ((staterr & IGC_RXDEXT_STATERR_RXE) != 0)) {
498542f5d56SKevin Bowling sc->dropped_pkts++;
499517904deSPeter Grehan ++rxr->rx_discarded;
500517904deSPeter Grehan return (EBADMSG);
501517904deSPeter Grehan }
502517904deSPeter Grehan ri->iri_frags[i].irf_flid = 0;
503517904deSPeter Grehan ri->iri_frags[i].irf_idx = cidx;
504517904deSPeter Grehan ri->iri_frags[i].irf_len = len;
505517904deSPeter Grehan
506517904deSPeter Grehan if (++cidx == scctx->isc_nrxd[0])
507517904deSPeter Grehan cidx = 0;
508517904deSPeter Grehan #ifdef notyet
509517904deSPeter Grehan if (rxr->hdr_split == true) {
510517904deSPeter Grehan ri->iri_frags[i].irf_flid = 1;
511517904deSPeter Grehan ri->iri_frags[i].irf_idx = cidx;
512517904deSPeter Grehan if (++cidx == scctx->isc_nrxd[0])
513517904deSPeter Grehan cidx = 0;
514517904deSPeter Grehan }
515517904deSPeter Grehan #endif
516517904deSPeter Grehan i++;
517517904deSPeter Grehan } while (!eop);
518517904deSPeter Grehan
519517904deSPeter Grehan rxr->rx_packets++;
520517904deSPeter Grehan
521d02e4363SKevin Bowling if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0)
522517904deSPeter Grehan igc_rx_checksum(staterr, ri, ptype);
523517904deSPeter Grehan
524b4a58b3dSKevin Bowling if (staterr & IGC_RXD_STAT_VP) {
525f7926a6dSVincenzo Maffione ri->iri_vtag = le16toh(rxd->wb.upper.vlan);
526517904deSPeter Grehan ri->iri_flags |= M_VLANTAG;
527517904deSPeter Grehan }
528d02e4363SKevin Bowling
529517904deSPeter Grehan ri->iri_flowid =
530517904deSPeter Grehan le32toh(rxd->wb.lower.hi_dword.rss);
531517904deSPeter Grehan ri->iri_rsstype = igc_determine_rsstype(pkt_info);
532517904deSPeter Grehan ri->iri_nfrags = i;
533517904deSPeter Grehan
534517904deSPeter Grehan return (0);
535517904deSPeter Grehan }
536517904deSPeter Grehan
537517904deSPeter Grehan /*********************************************************************
538517904deSPeter Grehan *
539517904deSPeter Grehan * Verify that the hardware indicated that the checksum is valid.
540517904deSPeter Grehan * Inform the stack about the status of checksum so that stack
541517904deSPeter Grehan * doesn't spend time verifying the checksum.
542517904deSPeter Grehan *
543517904deSPeter Grehan *********************************************************************/
544517904deSPeter Grehan static void
igc_rx_checksum(uint32_t staterr,if_rxd_info_t ri,uint32_t ptype)545d02e4363SKevin Bowling igc_rx_checksum(uint32_t staterr, if_rxd_info_t ri, uint32_t ptype)
546517904deSPeter Grehan {
547d02e4363SKevin Bowling uint16_t status = (uint16_t)staterr;
548d02e4363SKevin Bowling uint8_t errors = (uint8_t)(staterr >> 24);
549517904deSPeter Grehan
550d02e4363SKevin Bowling if (__predict_false(status & IGC_RXD_STAT_IXSM))
551517904deSPeter Grehan return;
552517904deSPeter Grehan
553d02e4363SKevin Bowling /* If there is a layer 3 or 4 error we are done */
554d02e4363SKevin Bowling if (__predict_false(errors & (IGC_RXD_ERR_IPE | IGC_RXD_ERR_TCPE)))
555d02e4363SKevin Bowling return;
556d02e4363SKevin Bowling
557d02e4363SKevin Bowling /* IP Checksum Good */
558d02e4363SKevin Bowling if (status & IGC_RXD_STAT_IPCS)
559d02e4363SKevin Bowling ri->iri_csum_flags = (CSUM_IP_CHECKED | CSUM_IP_VALID);
560d02e4363SKevin Bowling
561d02e4363SKevin Bowling /* Valid L4E checksum */
562d02e4363SKevin Bowling if (__predict_true(status &
563d02e4363SKevin Bowling (IGC_RXD_STAT_TCPCS | IGC_RXD_STAT_UDPCS))) {
564d02e4363SKevin Bowling /* SCTP header present */
565d02e4363SKevin Bowling if (__predict_false((ptype & IGC_RXDADV_PKTTYPE_ETQF) == 0 &&
566d02e4363SKevin Bowling (ptype & IGC_RXDADV_PKTTYPE_SCTP) != 0)) {
567d02e4363SKevin Bowling ri->iri_csum_flags |= CSUM_SCTP_VALID;
568d02e4363SKevin Bowling } else {
569*c7fb7b5dSKevin Bowling ri->iri_csum_flags |=
570*c7fb7b5dSKevin Bowling CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
571517904deSPeter Grehan ri->iri_csum_data = htons(0xffff);
572517904deSPeter Grehan }
573517904deSPeter Grehan }
574517904deSPeter Grehan }
575517904deSPeter Grehan
576517904deSPeter Grehan /********************************************************************
577517904deSPeter Grehan *
578517904deSPeter Grehan * Parse the packet type to determine the appropriate hash
579517904deSPeter Grehan *
580517904deSPeter Grehan ******************************************************************/
581517904deSPeter Grehan static int
igc_determine_rsstype(uint16_t pkt_info)582d02e4363SKevin Bowling igc_determine_rsstype(uint16_t pkt_info)
583517904deSPeter Grehan {
584517904deSPeter Grehan switch (pkt_info & IGC_RXDADV_RSSTYPE_MASK) {
585517904deSPeter Grehan case IGC_RXDADV_RSSTYPE_IPV4_TCP:
586517904deSPeter Grehan return M_HASHTYPE_RSS_TCP_IPV4;
587517904deSPeter Grehan case IGC_RXDADV_RSSTYPE_IPV4:
588517904deSPeter Grehan return M_HASHTYPE_RSS_IPV4;
589517904deSPeter Grehan case IGC_RXDADV_RSSTYPE_IPV6_TCP:
590517904deSPeter Grehan return M_HASHTYPE_RSS_TCP_IPV6;
591517904deSPeter Grehan case IGC_RXDADV_RSSTYPE_IPV6_EX:
592517904deSPeter Grehan return M_HASHTYPE_RSS_IPV6_EX;
593517904deSPeter Grehan case IGC_RXDADV_RSSTYPE_IPV6:
594517904deSPeter Grehan return M_HASHTYPE_RSS_IPV6;
595517904deSPeter Grehan case IGC_RXDADV_RSSTYPE_IPV6_TCP_EX:
596517904deSPeter Grehan return M_HASHTYPE_RSS_TCP_IPV6_EX;
597517904deSPeter Grehan default:
598517904deSPeter Grehan return M_HASHTYPE_OPAQUE;
599517904deSPeter Grehan }
600517904deSPeter Grehan }
601