1d37cece2SSean Bruno /*- 2034f38cdSKevin Bowling * SPDX-License-Identifier: BSD-2-Clause 3034f38cdSKevin Bowling * 47021bf05SStephen Hurd * Copyright (c) 2016 Nicole Graziano <nicole@nextbsd.org> 57021bf05SStephen Hurd * Copyright (c) 2017 Matthew Macy <mmacy@mattmacy.io> 6d37cece2SSean Bruno * All rights reserved. 7d37cece2SSean Bruno * 8d37cece2SSean Bruno * Redistribution and use in source and binary forms, with or without 9d37cece2SSean Bruno * modification, are permitted provided that the following conditions 10d37cece2SSean Bruno * are met: 11d37cece2SSean Bruno * 1. Redistributions of source code must retain the above copyright 12d37cece2SSean Bruno * notice, this list of conditions and the following disclaimer. 13d37cece2SSean Bruno * 2. Redistributions in binary form must reproduce the above copyright 14d37cece2SSean Bruno * notice, this list of conditions and the following disclaimer in the 15d37cece2SSean Bruno * documentation and/or other materials provided with the distribution. 16d37cece2SSean Bruno * 17d37cece2SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18d37cece2SSean Bruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19d37cece2SSean Bruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20d37cece2SSean Bruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21d37cece2SSean Bruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22d37cece2SSean Bruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23d37cece2SSean Bruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24d37cece2SSean Bruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25d37cece2SSean Bruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26d37cece2SSean Bruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27d37cece2SSean Bruno * SUCH DAMAGE. 28d37cece2SSean Bruno */ 29d37cece2SSean Bruno 30f2d6ace4SSean Bruno #include "if_em.h" 31f2d6ace4SSean Bruno 32f2d6ace4SSean Bruno #ifdef RSS 33f2d6ace4SSean Bruno #include <net/rss_config.h> 34f2d6ace4SSean Bruno #include <netinet/in_rss.h> 35f2d6ace4SSean Bruno #endif 36f2d6ace4SSean Bruno 37f2d6ace4SSean Bruno #ifdef VERBOSE_DEBUG 38f2d6ace4SSean Bruno #define DPRINTF device_printf 39f2d6ace4SSean Bruno #else 40f2d6ace4SSean Bruno #define DPRINTF(...) 41f2d6ace4SSean Bruno #endif 42f2d6ace4SSean Bruno 43f2d6ace4SSean Bruno /********************************************************************* 44f2d6ace4SSean Bruno * Local Function prototypes 45f2d6ace4SSean Bruno *********************************************************************/ 469dc452b9SKevin Bowling static int em_tso_setup(struct e1000_softc *, if_pkt_info_t, uint32_t *, 479dc452b9SKevin Bowling uint32_t *); 489dc452b9SKevin Bowling static int em_transmit_checksum_setup(struct e1000_softc *, if_pkt_info_t, 499dc452b9SKevin Bowling uint32_t *, uint32_t *); 509dc452b9SKevin Bowling static int em_isc_txd_encap(void *, if_pkt_info_t); 519dc452b9SKevin Bowling static void em_isc_txd_flush(void *, uint16_t, qidx_t); 529dc452b9SKevin Bowling static int em_isc_txd_credits_update(void *, uint16_t, bool); 539dc452b9SKevin Bowling static void em_isc_rxd_refill(void *, if_rxd_update_t); 549dc452b9SKevin Bowling static void em_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t); 559dc452b9SKevin Bowling static int em_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t); 569dc452b9SKevin Bowling static int em_isc_rxd_pkt_get(void *, if_rxd_info_t); 57f2d6ace4SSean Bruno 589dc452b9SKevin Bowling static void lem_isc_rxd_refill(void *, if_rxd_update_t); 59f2d6ace4SSean Bruno 609dc452b9SKevin Bowling static int lem_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t); 619dc452b9SKevin Bowling static int lem_isc_rxd_pkt_get(void *, if_rxd_info_t); 62f2d6ace4SSean Bruno 63015075f3SKevin Bowling static void em_receive_checksum(uint16_t, uint8_t, if_rxd_info_t); 649dc452b9SKevin Bowling static int em_determine_rsstype(uint32_t); 659dc452b9SKevin Bowling extern int em_intr(void *); 66f2d6ace4SSean Bruno 67f2d6ace4SSean Bruno struct if_txrx em_txrx = { 68fbf8b74cSMark Johnston .ift_txd_encap = em_isc_txd_encap, 69fbf8b74cSMark Johnston .ift_txd_flush = em_isc_txd_flush, 70fbf8b74cSMark Johnston .ift_txd_credits_update = em_isc_txd_credits_update, 71fbf8b74cSMark Johnston .ift_rxd_available = em_isc_rxd_available, 72fbf8b74cSMark Johnston .ift_rxd_pkt_get = em_isc_rxd_pkt_get, 73fbf8b74cSMark Johnston .ift_rxd_refill = em_isc_rxd_refill, 74fbf8b74cSMark Johnston .ift_rxd_flush = em_isc_rxd_flush, 75fbf8b74cSMark Johnston .ift_legacy_intr = em_intr 76f2d6ace4SSean Bruno }; 77f2d6ace4SSean Bruno 78f2d6ace4SSean Bruno struct if_txrx lem_txrx = { 79fbf8b74cSMark Johnston .ift_txd_encap = em_isc_txd_encap, 80fbf8b74cSMark Johnston .ift_txd_flush = em_isc_txd_flush, 81fbf8b74cSMark Johnston .ift_txd_credits_update = em_isc_txd_credits_update, 82fbf8b74cSMark Johnston .ift_rxd_available = lem_isc_rxd_available, 83fbf8b74cSMark Johnston .ift_rxd_pkt_get = lem_isc_rxd_pkt_get, 84fbf8b74cSMark Johnston .ift_rxd_refill = lem_isc_rxd_refill, 85fbf8b74cSMark Johnston .ift_rxd_flush = em_isc_rxd_flush, 86fbf8b74cSMark Johnston .ift_legacy_intr = em_intr 87f2d6ace4SSean Bruno }; 88f2d6ace4SSean Bruno 89f2d6ace4SSean Bruno extern if_shared_ctx_t em_sctx; 90f2d6ace4SSean Bruno 9195246abbSSean Bruno void 92dc926051SKevin Bowling em_dump_rs(struct e1000_softc *sc) 9395246abbSSean Bruno { 94dc926051SKevin Bowling if_softc_ctx_t scctx = sc->shared; 9595246abbSSean Bruno struct em_tx_queue *que; 9695246abbSSean Bruno struct tx_ring *txr; 9795246abbSSean Bruno qidx_t i, ntxd, qid, cur; 9895246abbSSean Bruno int16_t rs_cidx; 9995246abbSSean Bruno uint8_t status; 10095246abbSSean Bruno 10195246abbSSean Bruno printf("\n"); 10295246abbSSean Bruno ntxd = scctx->isc_ntxd[0]; 103dc926051SKevin Bowling for (qid = 0; qid < sc->tx_num_queues; qid++) { 104dc926051SKevin Bowling que = &sc->tx_queues[qid]; 10595246abbSSean Bruno txr = &que->txr; 10695246abbSSean Bruno rs_cidx = txr->tx_rs_cidx; 10795246abbSSean Bruno if (rs_cidx != txr->tx_rs_pidx) { 10895246abbSSean Bruno cur = txr->tx_rsq[rs_cidx]; 10995246abbSSean Bruno status = txr->tx_base[cur].upper.fields.status; 11095246abbSSean Bruno if (!(status & E1000_TXD_STAT_DD)) 111*7390daf8SKevin Bowling printf("qid[%d]->tx_rsq[%d]: %d clear ", 112*7390daf8SKevin Bowling qid, rs_cidx, cur); 11395246abbSSean Bruno } else { 11495246abbSSean Bruno rs_cidx = (rs_cidx-1)&(ntxd-1); 11595246abbSSean Bruno cur = txr->tx_rsq[rs_cidx]; 116*7390daf8SKevin Bowling printf("qid[%d]->tx_rsq[rs_cidx-1=%d]: %d ", 117*7390daf8SKevin Bowling qid, rs_cidx, cur); 11895246abbSSean Bruno } 1195253d74eSKevin Bowling printf("cidx_prev=%d rs_pidx=%d ",txr->tx_cidx_processed, 1205253d74eSKevin Bowling txr->tx_rs_pidx); 12195246abbSSean Bruno for (i = 0; i < ntxd; i++) { 122*7390daf8SKevin Bowling if (txr->tx_base[i].upper.fields.status & 123*7390daf8SKevin Bowling E1000_TXD_STAT_DD) 12495246abbSSean Bruno printf("%d set ", i); 12595246abbSSean Bruno } 12695246abbSSean Bruno printf("\n"); 12795246abbSSean Bruno } 12895246abbSSean Bruno } 12995246abbSSean Bruno 130f2d6ace4SSean Bruno /********************************************************************** 131f2d6ace4SSean Bruno * 132f2d6ace4SSean Bruno * Setup work for hardware segmentation offload (TSO) on 133f2d6ace4SSean Bruno * adapters using advanced tx descriptors 134f2d6ace4SSean Bruno * 135f2d6ace4SSean Bruno **********************************************************************/ 136f2d6ace4SSean Bruno static int 1375253d74eSKevin Bowling em_tso_setup(struct e1000_softc *sc, if_pkt_info_t pi, uint32_t *txd_upper, 1385253d74eSKevin Bowling uint32_t *txd_lower) 139f2d6ace4SSean Bruno { 140dc926051SKevin Bowling if_softc_ctx_t scctx = sc->shared; 141dc926051SKevin Bowling struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx]; 142f2d6ace4SSean Bruno struct tx_ring *txr = &que->txr; 143f2d6ace4SSean Bruno struct e1000_context_desc *TXD; 144f2d6ace4SSean Bruno int cur, hdr_len; 145201c4b7cSKevin Bowling uint32_t cmd_type_len; 146f2d6ace4SSean Bruno 147f2d6ace4SSean Bruno hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen; 148f2d6ace4SSean Bruno *txd_lower = (E1000_TXD_CMD_DEXT | /* Extended descr type */ 149f2d6ace4SSean Bruno E1000_TXD_DTYP_D | /* Data descr type */ 150f2d6ace4SSean Bruno E1000_TXD_CMD_TSE); /* Do TSE on this packet */ 151f2d6ace4SSean Bruno 152f2d6ace4SSean Bruno cur = pi->ipi_pidx; 153f2d6ace4SSean Bruno TXD = (struct e1000_context_desc *)&txr->tx_base[cur]; 154f2d6ace4SSean Bruno 155f2d6ace4SSean Bruno /* 156e1353dcbSKevin Bowling * ipcss - Start offset for header checksum calculation. 157e1353dcbSKevin Bowling * ipcse - End offset for header checksum calculation. 158e1353dcbSKevin Bowling * ipcso - Offset of place to put the checksum. 159f2d6ace4SSean Bruno */ 160e1353dcbSKevin Bowling switch(pi->ipi_etype) { 161e1353dcbSKevin Bowling case ETHERTYPE_IP: 162e1353dcbSKevin Bowling /* IP and/or TCP header checksum calculation and insertion. */ 163*7390daf8SKevin Bowling *txd_upper = 164*7390daf8SKevin Bowling (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; 165e1353dcbSKevin Bowling 166f2d6ace4SSean Bruno TXD->lower_setup.ip_fields.ipcse = 167f2d6ace4SSean Bruno htole16(pi->ipi_ehdrlen + pi->ipi_ip_hlen - 1); 168e1353dcbSKevin Bowling break; 169e1353dcbSKevin Bowling case ETHERTYPE_IPV6: 170e1353dcbSKevin Bowling /* TCP header checksum calculation and insertion. */ 171e1353dcbSKevin Bowling *txd_upper = E1000_TXD_POPTS_TXSM << 8; 172e1353dcbSKevin Bowling 173e1353dcbSKevin Bowling TXD->lower_setup.ip_fields.ipcse = htole16(0); 174e1353dcbSKevin Bowling break; 175e1353dcbSKevin Bowling default: 176e1353dcbSKevin Bowling break; 177e1353dcbSKevin Bowling } 178e1353dcbSKevin Bowling TXD->lower_setup.ip_fields.ipcss = pi->ipi_ehdrlen; 1795253d74eSKevin Bowling TXD->lower_setup.ip_fields.ipcso = 1805253d74eSKevin Bowling pi->ipi_ehdrlen + offsetof(struct ip, ip_sum); 181f2d6ace4SSean Bruno 182f2d6ace4SSean Bruno /* 183e1353dcbSKevin Bowling * tucss - Start offset for payload checksum calculation. 184e1353dcbSKevin Bowling * tucse - End offset for payload checksum calculation. 185e1353dcbSKevin Bowling * tucso - Offset of place to put the checksum. 186f2d6ace4SSean Bruno */ 187f2d6ace4SSean Bruno TXD->upper_setup.tcp_fields.tucss = pi->ipi_ehdrlen + pi->ipi_ip_hlen; 188f2d6ace4SSean Bruno TXD->upper_setup.tcp_fields.tucse = 0; 189f2d6ace4SSean Bruno TXD->upper_setup.tcp_fields.tucso = 190*7390daf8SKevin Bowling pi->ipi_ehdrlen + pi->ipi_ip_hlen + 191*7390daf8SKevin Bowling offsetof(struct tcphdr, th_sum); 192f2d6ace4SSean Bruno 193f2d6ace4SSean Bruno /* 194f2d6ace4SSean Bruno * Payload size per packet w/o any headers. 195f2d6ace4SSean Bruno * Length of all headers up to payload. 196f2d6ace4SSean Bruno */ 197f2d6ace4SSean Bruno TXD->tcp_seg_setup.fields.mss = htole16(pi->ipi_tso_segsz); 198f2d6ace4SSean Bruno TXD->tcp_seg_setup.fields.hdr_len = hdr_len; 199f2d6ace4SSean Bruno 200201c4b7cSKevin Bowling /* 201cbcab907SKevin Bowling * "PCI/PCI-X SDM 4.0" page 45, and "PCIe GbE SDM 2.5" page 63 202201c4b7cSKevin Bowling * - Set up basic TUCMDs 203201c4b7cSKevin Bowling * - For others IP bit on indicates IPv4, while off indicates IPv6 204201c4b7cSKevin Bowling */ 205201c4b7cSKevin Bowling cmd_type_len = sc->txd_cmd | 206f2d6ace4SSean Bruno E1000_TXD_CMD_DEXT | /* Extended descr */ 207f2d6ace4SSean Bruno E1000_TXD_CMD_TSE | /* TSE context */ 208201c4b7cSKevin Bowling E1000_TXD_CMD_TCP; /* Do TCP checksum */ 209e1353dcbSKevin Bowling if (pi->ipi_etype == ETHERTYPE_IP) 210201c4b7cSKevin Bowling cmd_type_len |= E1000_TXD_CMD_IP; 211201c4b7cSKevin Bowling TXD->cmd_and_length = htole32(cmd_type_len | 212f2d6ace4SSean Bruno (pi->ipi_len - hdr_len)); /* Total len */ 213201c4b7cSKevin Bowling 2141bbdc25fSKevin Bowling txr->tx_tso = true; 215f2d6ace4SSean Bruno 216f2d6ace4SSean Bruno if (++cur == scctx->isc_ntxd[0]) { 217f2d6ace4SSean Bruno cur = 0; 218f2d6ace4SSean Bruno } 219*7390daf8SKevin Bowling DPRINTF(iflib_get_dev(sc->ctx), "%s: pidx: %d cur: %d\n", 220*7390daf8SKevin Bowling __FUNCTION__, pi->ipi_pidx, cur); 221f2d6ace4SSean Bruno return (cur); 222f2d6ace4SSean Bruno } 223f2d6ace4SSean Bruno 224f2d6ace4SSean Bruno /********************************************************************* 225f2d6ace4SSean Bruno * The offload context is protocol specific (TCP/UDP) and thus 226f2d6ace4SSean Bruno * only needs to be set when the protocol changes. The occasion 227f2d6ace4SSean Bruno * of a context change can be a performance detriment, and 228f2d6ace4SSean Bruno * might be better just disabled. The reason arises in the way 229f2d6ace4SSean Bruno * in which the controller supports pipelined requests from the 230f2d6ace4SSean Bruno * Tx data DMA. Up to four requests can be pipelined, and they may 231f2d6ace4SSean Bruno * belong to the same packet or to multiple packets. However all 232f2d6ace4SSean Bruno * requests for one packet are issued before a request is issued 233f2d6ace4SSean Bruno * for a subsequent packet and if a request for the next packet 234f2d6ace4SSean Bruno * requires a context change, that request will be stalled 235f2d6ace4SSean Bruno * until the previous request completes. This means setting up 236f2d6ace4SSean Bruno * a new context effectively disables pipelined Tx data DMA which 237f2d6ace4SSean Bruno * in turn greatly slow down performance to send small sized 238f2d6ace4SSean Bruno * frames. 239f2d6ace4SSean Bruno **********************************************************************/ 240cbcab907SKevin Bowling #define DONT_FORCE_CTX 1 241f2d6ace4SSean Bruno 242f2d6ace4SSean Bruno static int 2435253d74eSKevin Bowling em_transmit_checksum_setup(struct e1000_softc *sc, if_pkt_info_t pi, 2445253d74eSKevin Bowling uint32_t *txd_upper, uint32_t *txd_lower) 245f2d6ace4SSean Bruno { 246f2d6ace4SSean Bruno struct e1000_context_desc *TXD = NULL; 247dc926051SKevin Bowling if_softc_ctx_t scctx = sc->shared; 248dc926051SKevin Bowling struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx]; 249f2d6ace4SSean Bruno struct tx_ring *txr = &que->txr; 250f2d6ace4SSean Bruno int csum_flags = pi->ipi_csum_flags; 251f2d6ace4SSean Bruno int cur, hdr_len; 2525253d74eSKevin Bowling uint32_t cmd; 253f2d6ace4SSean Bruno 254f2d6ace4SSean Bruno cur = pi->ipi_pidx; 255f2d6ace4SSean Bruno hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen; 256dc926051SKevin Bowling cmd = sc->txd_cmd; 257f2d6ace4SSean Bruno 258f2d6ace4SSean Bruno /* 259f2d6ace4SSean Bruno * The 82574L can only remember the *last* context used 260f2d6ace4SSean Bruno * regardless of queue that it was use for. We cannot reuse 261f2d6ace4SSean Bruno * contexts on this hardware platform and must generate a new 262f2d6ace4SSean Bruno * context every time. 82574L hardware spec, section 7.2.6, 263f2d6ace4SSean Bruno * second note. 264f2d6ace4SSean Bruno */ 265f2d6ace4SSean Bruno if (DONT_FORCE_CTX && 266dc926051SKevin Bowling sc->tx_num_queues == 1 && 267f2d6ace4SSean Bruno txr->csum_lhlen == pi->ipi_ehdrlen && 268f2d6ace4SSean Bruno txr->csum_iphlen == pi->ipi_ip_hlen && 269f2d6ace4SSean Bruno txr->csum_flags == csum_flags) { 270f2d6ace4SSean Bruno /* 271f2d6ace4SSean Bruno * Same csum offload context as the previous packets; 272f2d6ace4SSean Bruno * just return. 273f2d6ace4SSean Bruno */ 274f2d6ace4SSean Bruno *txd_upper = txr->csum_txd_upper; 275f2d6ace4SSean Bruno *txd_lower = txr->csum_txd_lower; 276f2d6ace4SSean Bruno return (cur); 277f2d6ace4SSean Bruno } 278f2d6ace4SSean Bruno 279f2d6ace4SSean Bruno TXD = (struct e1000_context_desc *)&txr->tx_base[cur]; 280f2d6ace4SSean Bruno /* 281cbcab907SKevin Bowling * ipcss - Start offset for header checksum calculation. 282cbcab907SKevin Bowling * ipcse - End offset for header checksum calculation. 283cbcab907SKevin Bowling * ipcso - Offset of place to put the checksum. 284cbcab907SKevin Bowling * 285*7390daf8SKevin Bowling * We set ipcsX values regardless of IP version to work around HW 286*7390daf8SKevin Bowling * issues and ipcse must be 0 for IPv6 per "PCIe GbE SDM 2.5" page 61. 287cbcab907SKevin Bowling * IXSM controls whether it's inserted. 288f2d6ace4SSean Bruno */ 289f2d6ace4SSean Bruno TXD->lower_setup.ip_fields.ipcss = pi->ipi_ehdrlen; 2905253d74eSKevin Bowling TXD->lower_setup.ip_fields.ipcso = pi->ipi_ehdrlen + 2915253d74eSKevin Bowling offsetof(struct ip, ip_sum); 292cbcab907SKevin Bowling if (csum_flags & CSUM_IP) { 293cbcab907SKevin Bowling *txd_upper |= E1000_TXD_POPTS_IXSM << 8; 294eac761e9SKevin Bowling TXD->lower_setup.ip_fields.ipcse = htole16(hdr_len - 1); 295f2d6ace4SSean Bruno cmd |= E1000_TXD_CMD_IP; 296cbcab907SKevin Bowling } else if (csum_flags & (CSUM_IP6_TCP | CSUM_IP6_UDP)) 297cbcab907SKevin Bowling TXD->lower_setup.ip_fields.ipcse = htole16(0); 298f2d6ace4SSean Bruno 299cbcab907SKevin Bowling /* 300cbcab907SKevin Bowling * tucss - Start offset for payload checksum calculation. 301cbcab907SKevin Bowling * tucse - End offset for payload checksum calculation. 302cbcab907SKevin Bowling * tucso - Offset of place to put the checksum. 303cbcab907SKevin Bowling */ 304*7390daf8SKevin Bowling if (csum_flags & (CSUM_TCP | CSUM_UDP | CSUM_IP6_TCP | 305*7390daf8SKevin Bowling CSUM_IP6_UDP)) { 306f2d6ace4SSean Bruno uint8_t tucso; 307f2d6ace4SSean Bruno 308f2d6ace4SSean Bruno *txd_upper |= E1000_TXD_POPTS_TXSM << 8; 309f2d6ace4SSean Bruno *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; 310f2d6ace4SSean Bruno 31192fd2f39SKevin Bowling if (csum_flags & (CSUM_TCP | CSUM_IP6_TCP)) { 312f2d6ace4SSean Bruno tucso = hdr_len + offsetof(struct tcphdr, th_sum); 313f2d6ace4SSean Bruno cmd |= E1000_TXD_CMD_TCP; 314f2d6ace4SSean Bruno } else 315f2d6ace4SSean Bruno tucso = hdr_len + offsetof(struct udphdr, uh_sum); 316f2d6ace4SSean Bruno TXD->upper_setup.tcp_fields.tucss = hdr_len; 317f2d6ace4SSean Bruno TXD->upper_setup.tcp_fields.tucse = htole16(0); 318f2d6ace4SSean Bruno TXD->upper_setup.tcp_fields.tucso = tucso; 319f2d6ace4SSean Bruno } 320f2d6ace4SSean Bruno 321f2d6ace4SSean Bruno txr->csum_lhlen = pi->ipi_ehdrlen; 322f2d6ace4SSean Bruno txr->csum_iphlen = pi->ipi_ip_hlen; 323f2d6ace4SSean Bruno txr->csum_flags = csum_flags; 324f2d6ace4SSean Bruno txr->csum_txd_upper = *txd_upper; 325f2d6ace4SSean Bruno txr->csum_txd_lower = *txd_lower; 326f2d6ace4SSean Bruno 327f2d6ace4SSean Bruno TXD->tcp_seg_setup.data = htole32(0); 328f2d6ace4SSean Bruno TXD->cmd_and_length = 329f2d6ace4SSean Bruno htole32(E1000_TXD_CMD_IFCS | E1000_TXD_CMD_DEXT | cmd); 330f2d6ace4SSean Bruno 331f2d6ace4SSean Bruno if (++cur == scctx->isc_ntxd[0]) { 332f2d6ace4SSean Bruno cur = 0; 333f2d6ace4SSean Bruno } 3345253d74eSKevin Bowling DPRINTF(iflib_get_dev(sc->ctx), 335*7390daf8SKevin Bowling "checksum_setup csum_flags=%x txd_upper=%x txd_lower=%x" 336*7390daf8SKevin Bowling " hdr_len=%d cmd=%x\n", 337f2d6ace4SSean Bruno csum_flags, *txd_upper, *txd_lower, hdr_len, cmd); 338f2d6ace4SSean Bruno return (cur); 339f2d6ace4SSean Bruno } 340f2d6ace4SSean Bruno 341cbcab907SKevin Bowling #define TSO_WORKAROUND 4 /* TSO sentinel descriptor */ 342cbcab907SKevin Bowling 343f2d6ace4SSean Bruno static int 344f2d6ace4SSean Bruno em_isc_txd_encap(void *arg, if_pkt_info_t pi) 345f2d6ace4SSean Bruno { 346dc926051SKevin Bowling struct e1000_softc *sc = arg; 347f2d6ace4SSean Bruno if_softc_ctx_t scctx = sc->shared; 348f2d6ace4SSean Bruno struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx]; 349f2d6ace4SSean Bruno struct tx_ring *txr = &que->txr; 350f2d6ace4SSean Bruno bus_dma_segment_t *segs = pi->ipi_segs; 351f2d6ace4SSean Bruno int nsegs = pi->ipi_nsegs; 352f2d6ace4SSean Bruno int csum_flags = pi->ipi_csum_flags; 353f2d6ace4SSean Bruno int i, j, first, pidx_last; 3545253d74eSKevin Bowling uint32_t txd_flags, txd_upper = 0, txd_lower = 0; 355f2d6ace4SSean Bruno 356f2d6ace4SSean Bruno struct e1000_tx_desc *ctxd = NULL; 357f2d6ace4SSean Bruno bool do_tso, tso_desc; 35895246abbSSean Bruno qidx_t ntxd; 359f2d6ace4SSean Bruno 36095246abbSSean Bruno txd_flags = pi->ipi_flags & IPI_TX_INTR ? E1000_TXD_CMD_RS : 0; 361f2d6ace4SSean Bruno i = first = pi->ipi_pidx; 362f2d6ace4SSean Bruno do_tso = (csum_flags & CSUM_TSO); 3631bbdc25fSKevin Bowling tso_desc = false; 36495246abbSSean Bruno ntxd = scctx->isc_ntxd[0]; 365f2d6ace4SSean Bruno /* 366f2d6ace4SSean Bruno * TSO Hardware workaround, if this packet is not 367f2d6ace4SSean Bruno * TSO, and is only a single descriptor long, and 368f2d6ace4SSean Bruno * it follows a TSO burst, then we need to add a 369f2d6ace4SSean Bruno * sentinel descriptor to prevent premature writeback. 370f2d6ace4SSean Bruno */ 3711bbdc25fSKevin Bowling if ((!do_tso) && (txr->tx_tso == true)) { 372f2d6ace4SSean Bruno if (nsegs == 1) 3731bbdc25fSKevin Bowling tso_desc = true; 3741bbdc25fSKevin Bowling txr->tx_tso = false; 375f2d6ace4SSean Bruno } 376f2d6ace4SSean Bruno 377f2d6ace4SSean Bruno /* Do hardware assists */ 378f2d6ace4SSean Bruno if (do_tso) { 379f2d6ace4SSean Bruno i = em_tso_setup(sc, pi, &txd_upper, &txd_lower); 3801bbdc25fSKevin Bowling tso_desc = true; 38182379056SSean Bruno } else if (csum_flags & EM_CSUM_OFFLOAD) { 382*7390daf8SKevin Bowling i = em_transmit_checksum_setup(sc, pi, &txd_upper, 383*7390daf8SKevin Bowling &txd_lower); 384f2d6ace4SSean Bruno } 385f2d6ace4SSean Bruno 386f2d6ace4SSean Bruno if (pi->ipi_mflags & M_VLANTAG) { 387f2d6ace4SSean Bruno /* Set the vlan id. */ 388f2d6ace4SSean Bruno txd_upper |= htole16(pi->ipi_vtag) << 16; 389f2d6ace4SSean Bruno /* Tell hardware to add tag */ 390f2d6ace4SSean Bruno txd_lower |= htole32(E1000_TXD_CMD_VLE); 391f2d6ace4SSean Bruno } 392f2d6ace4SSean Bruno 3935253d74eSKevin Bowling DPRINTF(iflib_get_dev(sc->ctx), 3945253d74eSKevin Bowling "encap: set up tx: nsegs=%d first=%d i=%d\n", nsegs, first, i); 395dc926051SKevin Bowling /* XXX sc->pcix_82544 -- lem_fill_descriptors */ 396f2d6ace4SSean Bruno 397f2d6ace4SSean Bruno /* Set up our transmit descriptors */ 398f2d6ace4SSean Bruno for (j = 0; j < nsegs; j++) { 399f2d6ace4SSean Bruno bus_size_t seg_len; 400f2d6ace4SSean Bruno bus_addr_t seg_addr; 401f2d6ace4SSean Bruno uint32_t cmd; 402f2d6ace4SSean Bruno 403f2d6ace4SSean Bruno ctxd = &txr->tx_base[i]; 404f2d6ace4SSean Bruno seg_addr = segs[j].ds_addr; 405f2d6ace4SSean Bruno seg_len = segs[j].ds_len; 406f2d6ace4SSean Bruno cmd = E1000_TXD_CMD_IFCS | sc->txd_cmd; 407f2d6ace4SSean Bruno 408f2d6ace4SSean Bruno /* 40995246abbSSean Bruno * TSO Workaround: 41095246abbSSean Bruno * If this is the last descriptor, we want to 41195246abbSSean Bruno * split it so we have a small final sentinel 412f2d6ace4SSean Bruno */ 413f2d6ace4SSean Bruno if (tso_desc && (j == (nsegs - 1)) && (seg_len > 8)) { 414f2d6ace4SSean Bruno seg_len -= TSO_WORKAROUND; 415f2d6ace4SSean Bruno ctxd->buffer_addr = htole64(seg_addr); 416f2d6ace4SSean Bruno ctxd->lower.data = htole32(cmd | txd_lower | seg_len); 417f2d6ace4SSean Bruno ctxd->upper.data = htole32(txd_upper); 418f2d6ace4SSean Bruno 419f2d6ace4SSean Bruno if (++i == scctx->isc_ntxd[0]) 420f2d6ace4SSean Bruno i = 0; 421f2d6ace4SSean Bruno 422f2d6ace4SSean Bruno /* Now make the sentinel */ 423f2d6ace4SSean Bruno ctxd = &txr->tx_base[i]; 424f2d6ace4SSean Bruno ctxd->buffer_addr = htole64(seg_addr + seg_len); 425*7390daf8SKevin Bowling ctxd->lower.data = 426*7390daf8SKevin Bowling htole32(cmd | txd_lower | TSO_WORKAROUND); 427f2d6ace4SSean Bruno ctxd->upper.data = htole32(txd_upper); 428f2d6ace4SSean Bruno pidx_last = i; 429f2d6ace4SSean Bruno if (++i == scctx->isc_ntxd[0]) 430f2d6ace4SSean Bruno i = 0; 4315253d74eSKevin Bowling DPRINTF(iflib_get_dev(sc->ctx), 4325253d74eSKevin Bowling "TSO path pidx_last=%d i=%d ntxd[0]=%d\n", 4335253d74eSKevin Bowling pidx_last, i, scctx->isc_ntxd[0]); 434f2d6ace4SSean Bruno } else { 435f2d6ace4SSean Bruno ctxd->buffer_addr = htole64(seg_addr); 436f2d6ace4SSean Bruno ctxd->lower.data = htole32(cmd | txd_lower | seg_len); 437f2d6ace4SSean Bruno ctxd->upper.data = htole32(txd_upper); 438f2d6ace4SSean Bruno pidx_last = i; 439f2d6ace4SSean Bruno if (++i == scctx->isc_ntxd[0]) 440f2d6ace4SSean Bruno i = 0; 441*7390daf8SKevin Bowling DPRINTF(iflib_get_dev(sc->ctx), 442*7390daf8SKevin Bowling "pidx_last=%d i=%d ntxd[0]=%d\n", 4435253d74eSKevin Bowling pidx_last, i, scctx->isc_ntxd[0]); 444f2d6ace4SSean Bruno } 445f2d6ace4SSean Bruno } 446f2d6ace4SSean Bruno 447f2d6ace4SSean Bruno /* 448f2d6ace4SSean Bruno * Last Descriptor of Packet 449f2d6ace4SSean Bruno * needs End Of Packet (EOP) 450f2d6ace4SSean Bruno * and Report Status (RS) 451f2d6ace4SSean Bruno */ 4528fd222ebSMatt Macy if (txd_flags && nsegs) { 45395246abbSSean Bruno txr->tx_rsq[txr->tx_rs_pidx] = pidx_last; 4545253d74eSKevin Bowling DPRINTF(iflib_get_dev(sc->ctx), 4555253d74eSKevin Bowling "setting to RS on %d rs_pidx %d first: %d\n", 4565253d74eSKevin Bowling pidx_last, txr->tx_rs_pidx, first); 45795246abbSSean Bruno txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & (ntxd-1); 45895246abbSSean Bruno MPASS(txr->tx_rs_pidx != txr->tx_rs_cidx); 45995246abbSSean Bruno } 46095246abbSSean Bruno ctxd->lower.data |= htole32(E1000_TXD_CMD_EOP | txd_flags); 4615253d74eSKevin Bowling DPRINTF(iflib_get_dev(sc->ctx), 462*7390daf8SKevin Bowling "tx_buffers[%d]->eop = %d ipi_new_pidx=%d\n", 463*7390daf8SKevin Bowling first, pidx_last, i); 464f2d6ace4SSean Bruno pi->ipi_new_pidx = i; 465f2d6ace4SSean Bruno 4663e501ef8SKevin Bowling /* Sent data accounting for AIM */ 4673e501ef8SKevin Bowling txr->tx_bytes += pi->ipi_len; 4683e501ef8SKevin Bowling ++txr->tx_packets; 4693e501ef8SKevin Bowling 470f2d6ace4SSean Bruno return (0); 471f2d6ace4SSean Bruno } 472f2d6ace4SSean Bruno 473f2d6ace4SSean Bruno static void 47495246abbSSean Bruno em_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx) 475f2d6ace4SSean Bruno { 476dc926051SKevin Bowling struct e1000_softc *sc = arg; 477dc926051SKevin Bowling struct em_tx_queue *que = &sc->tx_queues[txqid]; 478f2d6ace4SSean Bruno struct tx_ring *txr = &que->txr; 479f2d6ace4SSean Bruno 480dc926051SKevin Bowling E1000_WRITE_REG(&sc->hw, E1000_TDT(txr->me), pidx); 481f2d6ace4SSean Bruno } 482f2d6ace4SSean Bruno 483f2d6ace4SSean Bruno static int 48495246abbSSean Bruno em_isc_txd_credits_update(void *arg, uint16_t txqid, bool clear) 485f2d6ace4SSean Bruno { 486dc926051SKevin Bowling struct e1000_softc *sc = arg; 487dc926051SKevin Bowling if_softc_ctx_t scctx = sc->shared; 488dc926051SKevin Bowling struct em_tx_queue *que = &sc->tx_queues[txqid]; 489f2d6ace4SSean Bruno struct tx_ring *txr = &que->txr; 490f2d6ace4SSean Bruno 49195246abbSSean Bruno qidx_t processed = 0; 49295246abbSSean Bruno int updated; 49395246abbSSean Bruno qidx_t cur, prev, ntxd, rs_cidx; 49495246abbSSean Bruno int32_t delta; 49595246abbSSean Bruno uint8_t status; 496f2d6ace4SSean Bruno 49795246abbSSean Bruno rs_cidx = txr->tx_rs_cidx; 49895246abbSSean Bruno if (rs_cidx == txr->tx_rs_pidx) 49995246abbSSean Bruno return (0); 50095246abbSSean Bruno cur = txr->tx_rsq[rs_cidx]; 50195246abbSSean Bruno MPASS(cur != QIDX_INVALID); 50295246abbSSean Bruno status = txr->tx_base[cur].upper.fields.status; 50395246abbSSean Bruno updated = !!(status & E1000_TXD_STAT_DD); 504f2d6ace4SSean Bruno 505adf93b56SEric Joyner if (!updated) 506adf93b56SEric Joyner return (0); 507adf93b56SEric Joyner 508adf93b56SEric Joyner /* If clear is false just let caller know that there 509adf93b56SEric Joyner * are descriptors to reclaim */ 510adf93b56SEric Joyner if (!clear) 511adf93b56SEric Joyner return (1); 51295246abbSSean Bruno 51395246abbSSean Bruno prev = txr->tx_cidx_processed; 51495246abbSSean Bruno ntxd = scctx->isc_ntxd[0]; 51595246abbSSean Bruno do { 516088a0b27SEric Joyner MPASS(prev != cur); 51795246abbSSean Bruno delta = (int32_t)cur - (int32_t)prev; 51895246abbSSean Bruno if (delta < 0) 51995246abbSSean Bruno delta += ntxd; 520088a0b27SEric Joyner MPASS(delta > 0); 521dc926051SKevin Bowling DPRINTF(iflib_get_dev(sc->ctx), 52295246abbSSean Bruno "%s: cidx_processed=%u cur=%u clear=%d delta=%d\n", 52395246abbSSean Bruno __FUNCTION__, prev, cur, clear, delta); 524f2d6ace4SSean Bruno 52595246abbSSean Bruno processed += delta; 52695246abbSSean Bruno prev = cur; 52795246abbSSean Bruno rs_cidx = (rs_cidx + 1) & (ntxd-1); 52895246abbSSean Bruno if (rs_cidx == txr->tx_rs_pidx) 529f2d6ace4SSean Bruno break; 53095246abbSSean Bruno cur = txr->tx_rsq[rs_cidx]; 53195246abbSSean Bruno MPASS(cur != QIDX_INVALID); 53295246abbSSean Bruno status = txr->tx_base[cur].upper.fields.status; 53395246abbSSean Bruno } while ((status & E1000_TXD_STAT_DD)); 534f2d6ace4SSean Bruno 53595246abbSSean Bruno txr->tx_rs_cidx = rs_cidx; 53695246abbSSean Bruno txr->tx_cidx_processed = prev; 537f2d6ace4SSean Bruno return(processed); 538f2d6ace4SSean Bruno } 539f2d6ace4SSean Bruno 540f2d6ace4SSean Bruno static void 54195246abbSSean Bruno lem_isc_rxd_refill(void *arg, if_rxd_update_t iru) 542f2d6ace4SSean Bruno { 543dc926051SKevin Bowling struct e1000_softc *sc = arg; 544f2d6ace4SSean Bruno if_softc_ctx_t scctx = sc->shared; 54595246abbSSean Bruno struct em_rx_queue *que = &sc->rx_queues[iru->iru_qsidx]; 546f2d6ace4SSean Bruno struct rx_ring *rxr = &que->rxr; 547f2d6ace4SSean Bruno struct e1000_rx_desc *rxd; 54895246abbSSean Bruno uint64_t *paddrs; 54995246abbSSean Bruno uint32_t next_pidx, pidx; 55095246abbSSean Bruno uint16_t count; 551f2d6ace4SSean Bruno int i; 55295246abbSSean Bruno 55395246abbSSean Bruno paddrs = iru->iru_paddrs; 55495246abbSSean Bruno pidx = iru->iru_pidx; 55595246abbSSean Bruno count = iru->iru_count; 556f2d6ace4SSean Bruno 557f2d6ace4SSean Bruno for (i = 0, next_pidx = pidx; i < count; i++) { 558f2d6ace4SSean Bruno rxd = (struct e1000_rx_desc *)&rxr->rx_base[next_pidx]; 559f2d6ace4SSean Bruno rxd->buffer_addr = htole64(paddrs[i]); 560f2d6ace4SSean Bruno /* status bits must be cleared */ 561f2d6ace4SSean Bruno rxd->status = 0; 562f2d6ace4SSean Bruno 563f2d6ace4SSean Bruno if (++next_pidx == scctx->isc_nrxd[0]) 564f2d6ace4SSean Bruno next_pidx = 0; 565f2d6ace4SSean Bruno } 566f2d6ace4SSean Bruno } 567f2d6ace4SSean Bruno 568f2d6ace4SSean Bruno static void 56995246abbSSean Bruno em_isc_rxd_refill(void *arg, if_rxd_update_t iru) 570f2d6ace4SSean Bruno { 571dc926051SKevin Bowling struct e1000_softc *sc = arg; 572f2d6ace4SSean Bruno if_softc_ctx_t scctx = sc->shared; 57395246abbSSean Bruno uint16_t rxqid = iru->iru_qsidx; 574f2d6ace4SSean Bruno struct em_rx_queue *que = &sc->rx_queues[rxqid]; 575f2d6ace4SSean Bruno struct rx_ring *rxr = &que->rxr; 576f2d6ace4SSean Bruno union e1000_rx_desc_extended *rxd; 57795246abbSSean Bruno uint64_t *paddrs; 57895246abbSSean Bruno uint32_t next_pidx, pidx; 57995246abbSSean Bruno uint16_t count; 580f2d6ace4SSean Bruno int i; 58195246abbSSean Bruno 58295246abbSSean Bruno paddrs = iru->iru_paddrs; 58395246abbSSean Bruno pidx = iru->iru_pidx; 58495246abbSSean Bruno count = iru->iru_count; 585f2d6ace4SSean Bruno 586f2d6ace4SSean Bruno for (i = 0, next_pidx = pidx; i < count; i++) { 587f2d6ace4SSean Bruno rxd = &rxr->rx_base[next_pidx]; 588f2d6ace4SSean Bruno rxd->read.buffer_addr = htole64(paddrs[i]); 589ab2e3f79SStephen Hurd /* DD bits must be cleared */ 590ab2e3f79SStephen Hurd rxd->wb.upper.status_error = 0; 591f2d6ace4SSean Bruno 592f2d6ace4SSean Bruno if (++next_pidx == scctx->isc_nrxd[0]) 593f2d6ace4SSean Bruno next_pidx = 0; 594f2d6ace4SSean Bruno } 595f2d6ace4SSean Bruno } 596f2d6ace4SSean Bruno 597f2d6ace4SSean Bruno static void 5985253d74eSKevin Bowling em_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused, 5995253d74eSKevin Bowling qidx_t pidx) 600f2d6ace4SSean Bruno { 601dc926051SKevin Bowling struct e1000_softc *sc = arg; 602f2d6ace4SSean Bruno struct em_rx_queue *que = &sc->rx_queues[rxqid]; 603f2d6ace4SSean Bruno struct rx_ring *rxr = &que->rxr; 604f2d6ace4SSean Bruno 605f2d6ace4SSean Bruno E1000_WRITE_REG(&sc->hw, E1000_RDT(rxr->me), pidx); 606f2d6ace4SSean Bruno } 607f2d6ace4SSean Bruno 608f2d6ace4SSean Bruno static int 60995246abbSSean Bruno lem_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget) 610f2d6ace4SSean Bruno { 611dc926051SKevin Bowling struct e1000_softc *sc = arg; 612f2d6ace4SSean Bruno if_softc_ctx_t scctx = sc->shared; 613f2d6ace4SSean Bruno struct em_rx_queue *que = &sc->rx_queues[rxqid]; 614f2d6ace4SSean Bruno struct rx_ring *rxr = &que->rxr; 615f2d6ace4SSean Bruno struct e1000_rx_desc *rxd; 6165253d74eSKevin Bowling uint32_t staterr = 0; 617f2d6ace4SSean Bruno int cnt, i; 618f2d6ace4SSean Bruno 619ab2e3f79SStephen Hurd for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) { 620f2d6ace4SSean Bruno rxd = (struct e1000_rx_desc *)&rxr->rx_base[i]; 621f2d6ace4SSean Bruno staterr = rxd->status; 622f2d6ace4SSean Bruno 623f2d6ace4SSean Bruno if ((staterr & E1000_RXD_STAT_DD) == 0) 624f2d6ace4SSean Bruno break; 625f2d6ace4SSean Bruno if (++i == scctx->isc_nrxd[0]) 626f2d6ace4SSean Bruno i = 0; 627f2d6ace4SSean Bruno if (staterr & E1000_RXD_STAT_EOP) 628f2d6ace4SSean Bruno cnt++; 629f2d6ace4SSean Bruno } 630f2d6ace4SSean Bruno return (cnt); 631f2d6ace4SSean Bruno } 632f2d6ace4SSean Bruno 633f2d6ace4SSean Bruno static int 63495246abbSSean Bruno em_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget) 635f2d6ace4SSean Bruno { 636dc926051SKevin Bowling struct e1000_softc *sc = arg; 637f2d6ace4SSean Bruno if_softc_ctx_t scctx = sc->shared; 638f2d6ace4SSean Bruno struct em_rx_queue *que = &sc->rx_queues[rxqid]; 639f2d6ace4SSean Bruno struct rx_ring *rxr = &que->rxr; 640f2d6ace4SSean Bruno union e1000_rx_desc_extended *rxd; 6415253d74eSKevin Bowling uint32_t staterr = 0; 642f2d6ace4SSean Bruno int cnt, i; 643f2d6ace4SSean Bruno 644ab2e3f79SStephen Hurd for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) { 645f2d6ace4SSean Bruno rxd = &rxr->rx_base[i]; 646f2d6ace4SSean Bruno staterr = le32toh(rxd->wb.upper.status_error); 647f2d6ace4SSean Bruno 648f2d6ace4SSean Bruno if ((staterr & E1000_RXD_STAT_DD) == 0) 649f2d6ace4SSean Bruno break; 650adf93b56SEric Joyner if (++i == scctx->isc_nrxd[0]) 651f2d6ace4SSean Bruno i = 0; 652f2d6ace4SSean Bruno if (staterr & E1000_RXD_STAT_EOP) 653f2d6ace4SSean Bruno cnt++; 654f2d6ace4SSean Bruno } 655f2d6ace4SSean Bruno return (cnt); 656f2d6ace4SSean Bruno } 657f2d6ace4SSean Bruno 658f2d6ace4SSean Bruno static int 659f2d6ace4SSean Bruno lem_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri) 660f2d6ace4SSean Bruno { 661dc926051SKevin Bowling struct e1000_softc *sc = arg; 662dc926051SKevin Bowling if_softc_ctx_t scctx = sc->shared; 663dc926051SKevin Bowling struct em_rx_queue *que = &sc->rx_queues[ri->iri_qsidx]; 664f2d6ace4SSean Bruno struct rx_ring *rxr = &que->rxr; 665f2d6ace4SSean Bruno struct e1000_rx_desc *rxd; 6665253d74eSKevin Bowling uint16_t len; 6675253d74eSKevin Bowling uint32_t status, errors; 668f2d6ace4SSean Bruno bool eop; 669f2d6ace4SSean Bruno int i, cidx; 670f2d6ace4SSean Bruno 671f2d6ace4SSean Bruno status = errors = i = 0; 672f2d6ace4SSean Bruno cidx = ri->iri_cidx; 673f2d6ace4SSean Bruno 674f2d6ace4SSean Bruno do { 675f2d6ace4SSean Bruno rxd = (struct e1000_rx_desc *)&rxr->rx_base[cidx]; 676f2d6ace4SSean Bruno status = rxd->status; 677f2d6ace4SSean Bruno errors = rxd->errors; 678f2d6ace4SSean Bruno 679f2d6ace4SSean Bruno /* Error Checking then decrement count */ 680f2d6ace4SSean Bruno MPASS ((status & E1000_RXD_STAT_DD) != 0); 681f2d6ace4SSean Bruno 682f2d6ace4SSean Bruno len = le16toh(rxd->length); 683f2d6ace4SSean Bruno ri->iri_len += len; 6843e501ef8SKevin Bowling rxr->rx_bytes += ri->iri_len; 685f2d6ace4SSean Bruno 686f2d6ace4SSean Bruno eop = (status & E1000_RXD_STAT_EOP) != 0; 687f2d6ace4SSean Bruno 688f2d6ace4SSean Bruno /* Make sure bad packets are discarded */ 689f2d6ace4SSean Bruno if (errors & E1000_RXD_ERR_FRAME_ERR_MASK) { 690dc926051SKevin Bowling sc->dropped_pkts++; 691f2d6ace4SSean Bruno /* XXX fixup if common */ 692f2d6ace4SSean Bruno return (EBADMSG); 693f2d6ace4SSean Bruno } 694f2d6ace4SSean Bruno 695f2d6ace4SSean Bruno ri->iri_frags[i].irf_flid = 0; 696f2d6ace4SSean Bruno ri->iri_frags[i].irf_idx = cidx; 697f2d6ace4SSean Bruno ri->iri_frags[i].irf_len = len; 698f2d6ace4SSean Bruno /* Zero out the receive descriptors status. */ 699f2d6ace4SSean Bruno rxd->status = 0; 700f2d6ace4SSean Bruno 701f2d6ace4SSean Bruno if (++cidx == scctx->isc_nrxd[0]) 702f2d6ace4SSean Bruno cidx = 0; 703f2d6ace4SSean Bruno i++; 704f2d6ace4SSean Bruno } while (!eop); 705f2d6ace4SSean Bruno 7063e501ef8SKevin Bowling rxr->rx_packets++; 7073e501ef8SKevin Bowling 708918c2567SKevin Bowling if (scctx->isc_capenable & IFCAP_RXCSUM) 709015075f3SKevin Bowling em_receive_checksum(status, errors, ri); 710f2d6ace4SSean Bruno 711918c2567SKevin Bowling if (scctx->isc_capenable & IFCAP_VLAN_HWTAGGING && 712918c2567SKevin Bowling status & E1000_RXD_STAT_VP) { 713*7390daf8SKevin Bowling ri->iri_vtag = 714*7390daf8SKevin Bowling le16toh(rxd->special & E1000_RXD_SPC_VLAN_MASK); 715f2d6ace4SSean Bruno ri->iri_flags |= M_VLANTAG; 716f2d6ace4SSean Bruno } 717f2d6ace4SSean Bruno 718f2d6ace4SSean Bruno ri->iri_nfrags = i; 719f2d6ace4SSean Bruno 720f2d6ace4SSean Bruno return (0); 721f2d6ace4SSean Bruno } 722f2d6ace4SSean Bruno 723f2d6ace4SSean Bruno static int 724f2d6ace4SSean Bruno em_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri) 725f2d6ace4SSean Bruno { 726dc926051SKevin Bowling struct e1000_softc *sc = arg; 727dc926051SKevin Bowling if_softc_ctx_t scctx = sc->shared; 728dc926051SKevin Bowling struct em_rx_queue *que = &sc->rx_queues[ri->iri_qsidx]; 729f2d6ace4SSean Bruno struct rx_ring *rxr = &que->rxr; 730f2d6ace4SSean Bruno union e1000_rx_desc_extended *rxd; 731f2d6ace4SSean Bruno 7325253d74eSKevin Bowling uint16_t len; 7335253d74eSKevin Bowling uint32_t pkt_info; 734918c2567SKevin Bowling uint32_t staterr; 735f2d6ace4SSean Bruno bool eop; 736f7926a6dSVincenzo Maffione int i, cidx; 737f2d6ace4SSean Bruno 738918c2567SKevin Bowling staterr = i = 0; 739f2d6ace4SSean Bruno cidx = ri->iri_cidx; 740f2d6ace4SSean Bruno 741f2d6ace4SSean Bruno do { 742f2d6ace4SSean Bruno rxd = &rxr->rx_base[cidx]; 743f2d6ace4SSean Bruno staterr = le32toh(rxd->wb.upper.status_error); 744cbf1505dSSean Bruno pkt_info = le32toh(rxd->wb.lower.mrq); 745f2d6ace4SSean Bruno 746f2d6ace4SSean Bruno /* Error Checking then decrement count */ 747ab2e3f79SStephen Hurd MPASS ((staterr & E1000_RXD_STAT_DD) != 0); 748f2d6ace4SSean Bruno 749f2d6ace4SSean Bruno len = le16toh(rxd->wb.upper.length); 750f2d6ace4SSean Bruno ri->iri_len += len; 7513e501ef8SKevin Bowling rxr->rx_bytes += ri->iri_len; 752f2d6ace4SSean Bruno 753f2d6ace4SSean Bruno eop = (staterr & E1000_RXD_STAT_EOP) != 0; 754f2d6ace4SSean Bruno 755f2d6ace4SSean Bruno /* Make sure bad packets are discarded */ 756f2d6ace4SSean Bruno if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) { 757dc926051SKevin Bowling sc->dropped_pkts++; 758f2d6ace4SSean Bruno return EBADMSG; 759f2d6ace4SSean Bruno } 760f2d6ace4SSean Bruno 761f2d6ace4SSean Bruno ri->iri_frags[i].irf_flid = 0; 762f2d6ace4SSean Bruno ri->iri_frags[i].irf_idx = cidx; 763f2d6ace4SSean Bruno ri->iri_frags[i].irf_len = len; 764f2d6ace4SSean Bruno /* Zero out the receive descriptors status. */ 765f2d6ace4SSean Bruno rxd->wb.upper.status_error &= htole32(~0xFF); 766f2d6ace4SSean Bruno 767f2d6ace4SSean Bruno if (++cidx == scctx->isc_nrxd[0]) 768f2d6ace4SSean Bruno cidx = 0; 769f2d6ace4SSean Bruno i++; 770f2d6ace4SSean Bruno } while (!eop); 771f2d6ace4SSean Bruno 7723e501ef8SKevin Bowling rxr->rx_packets++; 7733e501ef8SKevin Bowling 77452f45d8aSVincenzo Maffione if (scctx->isc_capenable & IFCAP_RXCSUM) 775015075f3SKevin Bowling em_receive_checksum(staterr, staterr >> 24, ri); 776f2d6ace4SSean Bruno 777918c2567SKevin Bowling if (scctx->isc_capenable & IFCAP_VLAN_HWTAGGING && 778918c2567SKevin Bowling staterr & E1000_RXD_STAT_VP) { 779f7926a6dSVincenzo Maffione ri->iri_vtag = le16toh(rxd->wb.upper.vlan); 780f2d6ace4SSean Bruno ri->iri_flags |= M_VLANTAG; 781f7926a6dSVincenzo Maffione } 782f2d6ace4SSean Bruno 78395246abbSSean Bruno ri->iri_flowid = le32toh(rxd->wb.lower.hi_dword.rss); 784cbf1505dSSean Bruno ri->iri_rsstype = em_determine_rsstype(pkt_info); 785cbf1505dSSean Bruno 786cbf1505dSSean Bruno ri->iri_nfrags = i; 787f2d6ace4SSean Bruno return (0); 788f2d6ace4SSean Bruno } 789f2d6ace4SSean Bruno 790f2d6ace4SSean Bruno /********************************************************************* 791f2d6ace4SSean Bruno * 792f2d6ace4SSean Bruno * Verify that the hardware indicated that the checksum is valid. 793f2d6ace4SSean Bruno * Inform the stack about the status of checksum so that stack 794f2d6ace4SSean Bruno * doesn't spend time verifying the checksum. 795f2d6ace4SSean Bruno * 796f2d6ace4SSean Bruno *********************************************************************/ 797f2d6ace4SSean Bruno static void 798015075f3SKevin Bowling em_receive_checksum(uint16_t status, uint8_t errors, if_rxd_info_t ri) 799f2d6ace4SSean Bruno { 800015075f3SKevin Bowling if (__predict_false(status & E1000_RXD_STAT_IXSM)) 801015075f3SKevin Bowling return; 802015075f3SKevin Bowling 803015075f3SKevin Bowling /* If there is a layer 3 or 4 error we are done */ 804*7390daf8SKevin Bowling if (__predict_false(errors & (E1000_RXD_ERR_IPE | 805*7390daf8SKevin Bowling E1000_RXD_ERR_TCPE))) 806015075f3SKevin Bowling return; 807015075f3SKevin Bowling 808015075f3SKevin Bowling /* IP Checksum Good */ 809015075f3SKevin Bowling if (status & E1000_RXD_STAT_IPCS) 810f2d6ace4SSean Bruno ri->iri_csum_flags = (CSUM_IP_CHECKED | CSUM_IP_VALID); 811f2d6ace4SSean Bruno 812015075f3SKevin Bowling /* Valid L4E checksum */ 813015075f3SKevin Bowling if (__predict_true(status & 814015075f3SKevin Bowling (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) { 815015075f3SKevin Bowling ri->iri_csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 816f2d6ace4SSean Bruno ri->iri_csum_data = htons(0xffff); 817f2d6ace4SSean Bruno } 818f2d6ace4SSean Bruno } 819f2d6ace4SSean Bruno 820cbf1505dSSean Bruno /******************************************************************** 821cbf1505dSSean Bruno * 822cbf1505dSSean Bruno * Parse the packet type to determine the appropriate hash 823cbf1505dSSean Bruno * 824cbf1505dSSean Bruno ******************************************************************/ 825cbf1505dSSean Bruno static int 8265253d74eSKevin Bowling em_determine_rsstype(uint32_t pkt_info) 827cbf1505dSSean Bruno { 828cbf1505dSSean Bruno switch (pkt_info & E1000_RXDADV_RSSTYPE_MASK) { 829cbf1505dSSean Bruno case E1000_RXDADV_RSSTYPE_IPV4_TCP: 830cbf1505dSSean Bruno return M_HASHTYPE_RSS_TCP_IPV4; 831cbf1505dSSean Bruno case E1000_RXDADV_RSSTYPE_IPV4: 832cbf1505dSSean Bruno return M_HASHTYPE_RSS_IPV4; 833cbf1505dSSean Bruno case E1000_RXDADV_RSSTYPE_IPV6_TCP: 834cbf1505dSSean Bruno return M_HASHTYPE_RSS_TCP_IPV6; 835cbf1505dSSean Bruno case E1000_RXDADV_RSSTYPE_IPV6_EX: 836cbf1505dSSean Bruno return M_HASHTYPE_RSS_IPV6_EX; 837cbf1505dSSean Bruno case E1000_RXDADV_RSSTYPE_IPV6: 838cbf1505dSSean Bruno return M_HASHTYPE_RSS_IPV6; 839cbf1505dSSean Bruno case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX: 840cbf1505dSSean Bruno return M_HASHTYPE_RSS_TCP_IPV6_EX; 841cbf1505dSSean Bruno default: 842cbf1505dSSean Bruno return M_HASHTYPE_OPAQUE; 843cbf1505dSSean Bruno } 844cbf1505dSSean Bruno } 845