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