161ae650dSJack F Vogel /****************************************************************************** 261ae650dSJack F Vogel 3b6c8f260SJack F Vogel Copyright (c) 2013-2015, Intel Corporation 461ae650dSJack F Vogel All rights reserved. 561ae650dSJack F Vogel 661ae650dSJack F Vogel Redistribution and use in source and binary forms, with or without 761ae650dSJack F Vogel modification, are permitted provided that the following conditions are met: 861ae650dSJack F Vogel 961ae650dSJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 1061ae650dSJack F Vogel this list of conditions and the following disclaimer. 1161ae650dSJack F Vogel 1261ae650dSJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 1361ae650dSJack F Vogel notice, this list of conditions and the following disclaimer in the 1461ae650dSJack F Vogel documentation and/or other materials provided with the distribution. 1561ae650dSJack F Vogel 1661ae650dSJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 1761ae650dSJack F Vogel contributors may be used to endorse or promote products derived from 1861ae650dSJack F Vogel this software without specific prior written permission. 1961ae650dSJack F Vogel 2061ae650dSJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2161ae650dSJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2261ae650dSJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2361ae650dSJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2461ae650dSJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2561ae650dSJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2661ae650dSJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2761ae650dSJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2861ae650dSJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2961ae650dSJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3061ae650dSJack F Vogel POSSIBILITY OF SUCH DAMAGE. 3161ae650dSJack F Vogel 3261ae650dSJack F Vogel ******************************************************************************/ 3361ae650dSJack F Vogel /*$FreeBSD$*/ 3461ae650dSJack F Vogel 3561ae650dSJack F Vogel /* 3661ae650dSJack F Vogel ** IXL driver TX/RX Routines: 3761ae650dSJack F Vogel ** This was seperated to allow usage by 384294f337SSean Bruno ** both the PF and VF drivers. 3961ae650dSJack F Vogel */ 4061ae650dSJack F Vogel 41b6c8f260SJack F Vogel #ifndef IXL_STANDALONE_BUILD 4261ae650dSJack F Vogel #include "opt_inet.h" 4361ae650dSJack F Vogel #include "opt_inet6.h" 44df1d7a71SJack F Vogel #include "opt_rss.h" 45b6c8f260SJack F Vogel #endif 46b6c8f260SJack F Vogel 4761ae650dSJack F Vogel #include "ixl.h" 4861ae650dSJack F Vogel 49dcd7b3b2SJack F Vogel #ifdef RSS 50dcd7b3b2SJack F Vogel #include <net/rss_config.h> 51dcd7b3b2SJack F Vogel #endif 52dcd7b3b2SJack F Vogel 5361ae650dSJack F Vogel /* Local Prototypes */ 5461ae650dSJack F Vogel static void ixl_rx_checksum(struct mbuf *, u32, u32, u8); 5561ae650dSJack F Vogel static void ixl_refresh_mbufs(struct ixl_queue *, int); 5661ae650dSJack F Vogel static int ixl_xmit(struct ixl_queue *, struct mbuf **); 5761ae650dSJack F Vogel static int ixl_tx_setup_offload(struct ixl_queue *, 5861ae650dSJack F Vogel struct mbuf *, u32 *, u32 *); 5961ae650dSJack F Vogel static bool ixl_tso_setup(struct ixl_queue *, struct mbuf *); 6061ae650dSJack F Vogel 614294f337SSean Bruno static inline void ixl_rx_discard(struct rx_ring *, int); 624294f337SSean Bruno static inline void ixl_rx_input(struct rx_ring *, struct ifnet *, 6361ae650dSJack F Vogel struct mbuf *, u8); 6461ae650dSJack F Vogel 654294f337SSean Bruno static inline bool ixl_tso_detect_sparse(struct mbuf *mp); 664294f337SSean Bruno static int ixl_tx_setup_offload(struct ixl_queue *que, 674294f337SSean Bruno struct mbuf *mp, u32 *cmd, u32 *off); 684294f337SSean Bruno static inline u32 ixl_get_tx_head(struct ixl_queue *que); 694294f337SSean Bruno 7031830672SJack F Vogel #ifdef DEV_NETMAP 7131830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h> 72ff9b61caSEric Joyner int ixl_rx_miss, ixl_rx_miss_bufs, ixl_crcstrip = 1; 7331830672SJack F Vogel #endif /* DEV_NETMAP */ 74bc8b78d3SLuigi Rizzo 7561ae650dSJack F Vogel /* 764294f337SSean Bruno * @key key is saved into this parameter 774294f337SSean Bruno */ 784294f337SSean Bruno void 794294f337SSean Bruno ixl_get_default_rss_key(u32 *key) 804294f337SSean Bruno { 814294f337SSean Bruno MPASS(key != NULL); 824294f337SSean Bruno 834294f337SSean Bruno u32 rss_seed[IXL_RSS_KEY_SIZE_REG] = {0x41b01687, 844294f337SSean Bruno 0x183cfd8c, 0xce880440, 0x580cbc3c, 854294f337SSean Bruno 0x35897377, 0x328b25e1, 0x4fa98922, 864294f337SSean Bruno 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1, 874294f337SSean Bruno 0x0, 0x0, 0x0}; 884294f337SSean Bruno 894294f337SSean Bruno bcopy(rss_seed, key, IXL_RSS_KEY_SIZE); 904294f337SSean Bruno } 914294f337SSean Bruno 924294f337SSean Bruno /* 9361ae650dSJack F Vogel ** Multiqueue Transmit driver 9461ae650dSJack F Vogel */ 9561ae650dSJack F Vogel int 9661ae650dSJack F Vogel ixl_mq_start(struct ifnet *ifp, struct mbuf *m) 9761ae650dSJack F Vogel { 9861ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 9961ae650dSJack F Vogel struct ixl_queue *que; 10061ae650dSJack F Vogel struct tx_ring *txr; 10161ae650dSJack F Vogel int err, i; 102845a028fSJack F Vogel #ifdef RSS 103845a028fSJack F Vogel u32 bucket_id; 104845a028fSJack F Vogel #endif 10561ae650dSJack F Vogel 106845a028fSJack F Vogel /* 107845a028fSJack F Vogel ** Which queue to use: 108845a028fSJack F Vogel ** 109845a028fSJack F Vogel ** When doing RSS, map it to the same outbound 110845a028fSJack F Vogel ** queue as the incoming flow would be mapped to. 111845a028fSJack F Vogel ** If everything is setup correctly, it should be 112845a028fSJack F Vogel ** the same bucket that the current CPU we're on is. 113845a028fSJack F Vogel */ 114845a028fSJack F Vogel if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 115845a028fSJack F Vogel #ifdef RSS 116845a028fSJack F Vogel if (rss_hash2bucket(m->m_pkthdr.flowid, 117845a028fSJack F Vogel M_HASHTYPE_GET(m), &bucket_id) == 0) { 118845a028fSJack F Vogel i = bucket_id % vsi->num_queues; 119845a028fSJack F Vogel } else 120845a028fSJack F Vogel #endif 12161ae650dSJack F Vogel i = m->m_pkthdr.flowid % vsi->num_queues; 122845a028fSJack F Vogel } else 12361ae650dSJack F Vogel i = curcpu % vsi->num_queues; 12461ae650dSJack F Vogel 12561ae650dSJack F Vogel que = &vsi->queues[i]; 12661ae650dSJack F Vogel txr = &que->txr; 12761ae650dSJack F Vogel 12861ae650dSJack F Vogel err = drbr_enqueue(ifp, txr->br, m); 12961ae650dSJack F Vogel if (err) 13061ae650dSJack F Vogel return (err); 13161ae650dSJack F Vogel if (IXL_TX_TRYLOCK(txr)) { 13261ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 13361ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 13461ae650dSJack F Vogel } else 13561ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->tx_task); 13661ae650dSJack F Vogel 13761ae650dSJack F Vogel return (0); 13861ae650dSJack F Vogel } 13961ae650dSJack F Vogel 14061ae650dSJack F Vogel int 14161ae650dSJack F Vogel ixl_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr) 14261ae650dSJack F Vogel { 14361ae650dSJack F Vogel struct ixl_queue *que = txr->que; 14461ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 14561ae650dSJack F Vogel struct mbuf *next; 14661ae650dSJack F Vogel int err = 0; 14761ae650dSJack F Vogel 14861ae650dSJack F Vogel 14961ae650dSJack F Vogel if (((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) || 15061ae650dSJack F Vogel vsi->link_active == 0) 15161ae650dSJack F Vogel return (ENETDOWN); 15261ae650dSJack F Vogel 15361ae650dSJack F Vogel /* Process the transmit queue */ 15461ae650dSJack F Vogel while ((next = drbr_peek(ifp, txr->br)) != NULL) { 15561ae650dSJack F Vogel if ((err = ixl_xmit(que, &next)) != 0) { 15661ae650dSJack F Vogel if (next == NULL) 15761ae650dSJack F Vogel drbr_advance(ifp, txr->br); 15861ae650dSJack F Vogel else 15961ae650dSJack F Vogel drbr_putback(ifp, txr->br, next); 16061ae650dSJack F Vogel break; 16161ae650dSJack F Vogel } 16261ae650dSJack F Vogel drbr_advance(ifp, txr->br); 16361ae650dSJack F Vogel /* Send a copy of the frame to the BPF listener */ 16461ae650dSJack F Vogel ETHER_BPF_MTAP(ifp, next); 16561ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 16661ae650dSJack F Vogel break; 16761ae650dSJack F Vogel } 16861ae650dSJack F Vogel 16961ae650dSJack F Vogel if (txr->avail < IXL_TX_CLEANUP_THRESHOLD) 17061ae650dSJack F Vogel ixl_txeof(que); 17161ae650dSJack F Vogel 17261ae650dSJack F Vogel return (err); 17361ae650dSJack F Vogel } 17461ae650dSJack F Vogel 17561ae650dSJack F Vogel /* 17661ae650dSJack F Vogel * Called from a taskqueue to drain queued transmit packets. 17761ae650dSJack F Vogel */ 17861ae650dSJack F Vogel void 17961ae650dSJack F Vogel ixl_deferred_mq_start(void *arg, int pending) 18061ae650dSJack F Vogel { 18161ae650dSJack F Vogel struct ixl_queue *que = arg; 18261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 18361ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 18461ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 18561ae650dSJack F Vogel 18661ae650dSJack F Vogel IXL_TX_LOCK(txr); 18761ae650dSJack F Vogel if (!drbr_empty(ifp, txr->br)) 18861ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 18961ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 19061ae650dSJack F Vogel } 19161ae650dSJack F Vogel 19261ae650dSJack F Vogel /* 19361ae650dSJack F Vogel ** Flush all queue ring buffers 19461ae650dSJack F Vogel */ 19561ae650dSJack F Vogel void 19661ae650dSJack F Vogel ixl_qflush(struct ifnet *ifp) 19761ae650dSJack F Vogel { 19861ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 19961ae650dSJack F Vogel 20061ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 20161ae650dSJack F Vogel struct ixl_queue *que = &vsi->queues[i]; 20261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 20361ae650dSJack F Vogel struct mbuf *m; 20461ae650dSJack F Vogel IXL_TX_LOCK(txr); 20561ae650dSJack F Vogel while ((m = buf_ring_dequeue_sc(txr->br)) != NULL) 20661ae650dSJack F Vogel m_freem(m); 20761ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 20861ae650dSJack F Vogel } 20961ae650dSJack F Vogel if_qflush(ifp); 21061ae650dSJack F Vogel } 21161ae650dSJack F Vogel 21261ae650dSJack F Vogel /* 21361ae650dSJack F Vogel ** Find mbuf chains passed to the driver 21461ae650dSJack F Vogel ** that are 'sparse', using more than 8 21561ae650dSJack F Vogel ** mbufs to deliver an mss-size chunk of data 21661ae650dSJack F Vogel */ 21761ae650dSJack F Vogel static inline bool 21861ae650dSJack F Vogel ixl_tso_detect_sparse(struct mbuf *mp) 21961ae650dSJack F Vogel { 22061ae650dSJack F Vogel struct mbuf *m; 221*cb6b8299SEric Joyner int num, mss; 22261ae650dSJack F Vogel 223*cb6b8299SEric Joyner num = 0; 22461ae650dSJack F Vogel mss = mp->m_pkthdr.tso_segsz; 22561ae650dSJack F Vogel 226*cb6b8299SEric Joyner /* Exclude first mbuf; assume it contains all headers */ 227*cb6b8299SEric Joyner for (m = mp->m_next; m != NULL; m = m->m_next) { 228*cb6b8299SEric Joyner if (m == NULL) 229*cb6b8299SEric Joyner break; 230*cb6b8299SEric Joyner num++; 231*cb6b8299SEric Joyner mss -= m->m_len % mp->m_pkthdr.tso_segsz; 232*cb6b8299SEric Joyner 233*cb6b8299SEric Joyner if (mss < 1) { 234*cb6b8299SEric Joyner if (num > IXL_SPARSE_CHAIN) 235*cb6b8299SEric Joyner return (true); 236*cb6b8299SEric Joyner num = (mss == 0) ? 0 : 1; 237*cb6b8299SEric Joyner mss += mp->m_pkthdr.tso_segsz; 238*cb6b8299SEric Joyner } 239*cb6b8299SEric Joyner } 240*cb6b8299SEric Joyner 241*cb6b8299SEric Joyner return (false); 24261ae650dSJack F Vogel } 24361ae650dSJack F Vogel 24461ae650dSJack F Vogel 24561ae650dSJack F Vogel /********************************************************************* 24661ae650dSJack F Vogel * 24761ae650dSJack F Vogel * This routine maps the mbufs to tx descriptors, allowing the 24861ae650dSJack F Vogel * TX engine to transmit the packets. 24961ae650dSJack F Vogel * - return 0 on success, positive on failure 25061ae650dSJack F Vogel * 25161ae650dSJack F Vogel **********************************************************************/ 25261ae650dSJack F Vogel #define IXL_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) 25361ae650dSJack F Vogel 25461ae650dSJack F Vogel static int 25561ae650dSJack F Vogel ixl_xmit(struct ixl_queue *que, struct mbuf **m_headp) 25661ae650dSJack F Vogel { 25761ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 25861ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 25961ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 26061ae650dSJack F Vogel struct ixl_tx_buf *buf; 26161ae650dSJack F Vogel struct i40e_tx_desc *txd = NULL; 26261ae650dSJack F Vogel struct mbuf *m_head, *m; 2634294f337SSean Bruno int i, j, error, nsegs; 26461ae650dSJack F Vogel int first, last = 0; 26561ae650dSJack F Vogel u16 vtag = 0; 26661ae650dSJack F Vogel u32 cmd, off; 26761ae650dSJack F Vogel bus_dmamap_t map; 26861ae650dSJack F Vogel bus_dma_tag_t tag; 26961ae650dSJack F Vogel bus_dma_segment_t segs[IXL_MAX_TSO_SEGS]; 27061ae650dSJack F Vogel 27161ae650dSJack F Vogel cmd = off = 0; 27261ae650dSJack F Vogel m_head = *m_headp; 27361ae650dSJack F Vogel 27461ae650dSJack F Vogel /* 27561ae650dSJack F Vogel * Important to capture the first descriptor 27661ae650dSJack F Vogel * used because it will contain the index of 27761ae650dSJack F Vogel * the one we tell the hardware to report back 27861ae650dSJack F Vogel */ 27961ae650dSJack F Vogel first = txr->next_avail; 28061ae650dSJack F Vogel buf = &txr->buffers[first]; 28161ae650dSJack F Vogel map = buf->map; 28261ae650dSJack F Vogel tag = txr->tx_tag; 28361ae650dSJack F Vogel 28461ae650dSJack F Vogel if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 28561ae650dSJack F Vogel /* Use larger mapping for TSO */ 28661ae650dSJack F Vogel tag = txr->tso_tag; 28761ae650dSJack F Vogel if (ixl_tso_detect_sparse(m_head)) { 28861ae650dSJack F Vogel m = m_defrag(m_head, M_NOWAIT); 289e5100ee2SJack F Vogel if (m == NULL) { 290e5100ee2SJack F Vogel m_freem(*m_headp); 291e5100ee2SJack F Vogel *m_headp = NULL; 292e5100ee2SJack F Vogel return (ENOBUFS); 293e5100ee2SJack F Vogel } 29461ae650dSJack F Vogel *m_headp = m; 29561ae650dSJack F Vogel } 29661ae650dSJack F Vogel } 29761ae650dSJack F Vogel 29861ae650dSJack F Vogel /* 29961ae650dSJack F Vogel * Map the packet for DMA. 30061ae650dSJack F Vogel */ 30161ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(tag, map, 30261ae650dSJack F Vogel *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); 30361ae650dSJack F Vogel 30461ae650dSJack F Vogel if (error == EFBIG) { 30561ae650dSJack F Vogel struct mbuf *m; 30661ae650dSJack F Vogel 3076d011ad5SEric Joyner m = m_defrag(*m_headp, M_NOWAIT); 30861ae650dSJack F Vogel if (m == NULL) { 30961ae650dSJack F Vogel que->mbuf_defrag_failed++; 31061ae650dSJack F Vogel m_freem(*m_headp); 31161ae650dSJack F Vogel *m_headp = NULL; 31261ae650dSJack F Vogel return (ENOBUFS); 31361ae650dSJack F Vogel } 31461ae650dSJack F Vogel *m_headp = m; 31561ae650dSJack F Vogel 31661ae650dSJack F Vogel /* Try it again */ 31761ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(tag, map, 31861ae650dSJack F Vogel *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); 31961ae650dSJack F Vogel 320*cb6b8299SEric Joyner if (error != 0) { 3214294f337SSean Bruno que->tx_dmamap_failed++; 32261ae650dSJack F Vogel m_freem(*m_headp); 32361ae650dSJack F Vogel *m_headp = NULL; 32461ae650dSJack F Vogel return (error); 32561ae650dSJack F Vogel } 32661ae650dSJack F Vogel } else if (error != 0) { 3274294f337SSean Bruno que->tx_dmamap_failed++; 32861ae650dSJack F Vogel m_freem(*m_headp); 32961ae650dSJack F Vogel *m_headp = NULL; 33061ae650dSJack F Vogel return (error); 33161ae650dSJack F Vogel } 33261ae650dSJack F Vogel 33361ae650dSJack F Vogel /* Make certain there are enough descriptors */ 33461ae650dSJack F Vogel if (nsegs > txr->avail - 2) { 33561ae650dSJack F Vogel txr->no_desc++; 33661ae650dSJack F Vogel error = ENOBUFS; 33761ae650dSJack F Vogel goto xmit_fail; 33861ae650dSJack F Vogel } 33961ae650dSJack F Vogel m_head = *m_headp; 34061ae650dSJack F Vogel 34161ae650dSJack F Vogel /* Set up the TSO/CSUM offload */ 34261ae650dSJack F Vogel if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) { 34361ae650dSJack F Vogel error = ixl_tx_setup_offload(que, m_head, &cmd, &off); 34461ae650dSJack F Vogel if (error) 34561ae650dSJack F Vogel goto xmit_fail; 34661ae650dSJack F Vogel } 34761ae650dSJack F Vogel 34861ae650dSJack F Vogel cmd |= I40E_TX_DESC_CMD_ICRC; 34961ae650dSJack F Vogel /* Grab the VLAN tag */ 35061ae650dSJack F Vogel if (m_head->m_flags & M_VLANTAG) { 35161ae650dSJack F Vogel cmd |= I40E_TX_DESC_CMD_IL2TAG1; 35261ae650dSJack F Vogel vtag = htole16(m_head->m_pkthdr.ether_vtag); 35361ae650dSJack F Vogel } 35461ae650dSJack F Vogel 35561ae650dSJack F Vogel i = txr->next_avail; 35661ae650dSJack F Vogel for (j = 0; j < nsegs; j++) { 35761ae650dSJack F Vogel bus_size_t seglen; 35861ae650dSJack F Vogel 35961ae650dSJack F Vogel buf = &txr->buffers[i]; 36061ae650dSJack F Vogel buf->tag = tag; /* Keep track of the type tag */ 36161ae650dSJack F Vogel txd = &txr->base[i]; 36261ae650dSJack F Vogel seglen = segs[j].ds_len; 36361ae650dSJack F Vogel 36461ae650dSJack F Vogel txd->buffer_addr = htole64(segs[j].ds_addr); 36561ae650dSJack F Vogel txd->cmd_type_offset_bsz = 36661ae650dSJack F Vogel htole64(I40E_TX_DESC_DTYPE_DATA 36761ae650dSJack F Vogel | ((u64)cmd << I40E_TXD_QW1_CMD_SHIFT) 36861ae650dSJack F Vogel | ((u64)off << I40E_TXD_QW1_OFFSET_SHIFT) 36961ae650dSJack F Vogel | ((u64)seglen << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) 37061ae650dSJack F Vogel | ((u64)vtag << I40E_TXD_QW1_L2TAG1_SHIFT)); 37161ae650dSJack F Vogel 37261ae650dSJack F Vogel last = i; /* descriptor that will get completion IRQ */ 37361ae650dSJack F Vogel 37461ae650dSJack F Vogel if (++i == que->num_desc) 37561ae650dSJack F Vogel i = 0; 37661ae650dSJack F Vogel 37761ae650dSJack F Vogel buf->m_head = NULL; 37861ae650dSJack F Vogel buf->eop_index = -1; 37961ae650dSJack F Vogel } 38061ae650dSJack F Vogel /* Set the last descriptor for report */ 38161ae650dSJack F Vogel txd->cmd_type_offset_bsz |= 38261ae650dSJack F Vogel htole64(((u64)IXL_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT)); 38361ae650dSJack F Vogel txr->avail -= nsegs; 38461ae650dSJack F Vogel txr->next_avail = i; 38561ae650dSJack F Vogel 38661ae650dSJack F Vogel buf->m_head = m_head; 38761ae650dSJack F Vogel /* Swap the dma map between the first and last descriptor */ 38861ae650dSJack F Vogel txr->buffers[first].map = buf->map; 38961ae650dSJack F Vogel buf->map = map; 39061ae650dSJack F Vogel bus_dmamap_sync(tag, map, BUS_DMASYNC_PREWRITE); 39161ae650dSJack F Vogel 39261ae650dSJack F Vogel /* Set the index of the descriptor that will be marked done */ 39361ae650dSJack F Vogel buf = &txr->buffers[first]; 39461ae650dSJack F Vogel buf->eop_index = last; 39561ae650dSJack F Vogel 39661ae650dSJack F Vogel bus_dmamap_sync(txr->dma.tag, txr->dma.map, 39761ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 39861ae650dSJack F Vogel /* 39961ae650dSJack F Vogel * Advance the Transmit Descriptor Tail (Tdt), this tells the 40061ae650dSJack F Vogel * hardware that this frame is available to transmit. 40161ae650dSJack F Vogel */ 40261ae650dSJack F Vogel ++txr->total_packets; 40361ae650dSJack F Vogel wr32(hw, txr->tail, i); 40461ae650dSJack F Vogel 40561ae650dSJack F Vogel /* Mark outstanding work */ 406*cb6b8299SEric Joyner atomic_store_rel_32(&txr->watchdog_timer, IXL_WATCHDOG); 40761ae650dSJack F Vogel return (0); 40861ae650dSJack F Vogel 40961ae650dSJack F Vogel xmit_fail: 41061ae650dSJack F Vogel bus_dmamap_unload(tag, buf->map); 41161ae650dSJack F Vogel return (error); 41261ae650dSJack F Vogel } 41361ae650dSJack F Vogel 41461ae650dSJack F Vogel 41561ae650dSJack F Vogel /********************************************************************* 41661ae650dSJack F Vogel * 41761ae650dSJack F Vogel * Allocate memory for tx_buffer structures. The tx_buffer stores all 41861ae650dSJack F Vogel * the information needed to transmit a packet on the wire. This is 41961ae650dSJack F Vogel * called only once at attach, setup is done every reset. 42061ae650dSJack F Vogel * 42161ae650dSJack F Vogel **********************************************************************/ 42261ae650dSJack F Vogel int 42361ae650dSJack F Vogel ixl_allocate_tx_data(struct ixl_queue *que) 42461ae650dSJack F Vogel { 42561ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 42661ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 42761ae650dSJack F Vogel device_t dev = vsi->dev; 42861ae650dSJack F Vogel struct ixl_tx_buf *buf; 42961ae650dSJack F Vogel int error = 0; 43061ae650dSJack F Vogel 43161ae650dSJack F Vogel /* 43261ae650dSJack F Vogel * Setup DMA descriptor areas. 43361ae650dSJack F Vogel */ 43461ae650dSJack F Vogel if ((error = bus_dma_tag_create(NULL, /* parent */ 43561ae650dSJack F Vogel 1, 0, /* alignment, bounds */ 43661ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* lowaddr */ 43761ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* highaddr */ 43861ae650dSJack F Vogel NULL, NULL, /* filter, filterarg */ 43961ae650dSJack F Vogel IXL_TSO_SIZE, /* maxsize */ 44061ae650dSJack F Vogel IXL_MAX_TX_SEGS, /* nsegments */ 44161ae650dSJack F Vogel PAGE_SIZE, /* maxsegsize */ 44261ae650dSJack F Vogel 0, /* flags */ 44361ae650dSJack F Vogel NULL, /* lockfunc */ 44461ae650dSJack F Vogel NULL, /* lockfuncarg */ 44561ae650dSJack F Vogel &txr->tx_tag))) { 44661ae650dSJack F Vogel device_printf(dev,"Unable to allocate TX DMA tag\n"); 44761ae650dSJack F Vogel goto fail; 44861ae650dSJack F Vogel } 44961ae650dSJack F Vogel 45061ae650dSJack F Vogel /* Make a special tag for TSO */ 45161ae650dSJack F Vogel if ((error = bus_dma_tag_create(NULL, /* parent */ 45261ae650dSJack F Vogel 1, 0, /* alignment, bounds */ 45361ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* lowaddr */ 45461ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* highaddr */ 45561ae650dSJack F Vogel NULL, NULL, /* filter, filterarg */ 45661ae650dSJack F Vogel IXL_TSO_SIZE, /* maxsize */ 45761ae650dSJack F Vogel IXL_MAX_TSO_SEGS, /* nsegments */ 45861ae650dSJack F Vogel PAGE_SIZE, /* maxsegsize */ 45961ae650dSJack F Vogel 0, /* flags */ 46061ae650dSJack F Vogel NULL, /* lockfunc */ 46161ae650dSJack F Vogel NULL, /* lockfuncarg */ 46261ae650dSJack F Vogel &txr->tso_tag))) { 46361ae650dSJack F Vogel device_printf(dev,"Unable to allocate TX TSO DMA tag\n"); 46461ae650dSJack F Vogel goto fail; 46561ae650dSJack F Vogel } 46661ae650dSJack F Vogel 46761ae650dSJack F Vogel if (!(txr->buffers = 46861ae650dSJack F Vogel (struct ixl_tx_buf *) malloc(sizeof(struct ixl_tx_buf) * 46961ae650dSJack F Vogel que->num_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) { 47061ae650dSJack F Vogel device_printf(dev, "Unable to allocate tx_buffer memory\n"); 47161ae650dSJack F Vogel error = ENOMEM; 47261ae650dSJack F Vogel goto fail; 47361ae650dSJack F Vogel } 47461ae650dSJack F Vogel 47561ae650dSJack F Vogel /* Create the descriptor buffer default dma maps */ 47661ae650dSJack F Vogel buf = txr->buffers; 47761ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++, buf++) { 47861ae650dSJack F Vogel buf->tag = txr->tx_tag; 47961ae650dSJack F Vogel error = bus_dmamap_create(buf->tag, 0, &buf->map); 48061ae650dSJack F Vogel if (error != 0) { 48161ae650dSJack F Vogel device_printf(dev, "Unable to create TX DMA map\n"); 48261ae650dSJack F Vogel goto fail; 48361ae650dSJack F Vogel } 48461ae650dSJack F Vogel } 48561ae650dSJack F Vogel fail: 48661ae650dSJack F Vogel return (error); 48761ae650dSJack F Vogel } 48861ae650dSJack F Vogel 48961ae650dSJack F Vogel 49061ae650dSJack F Vogel /********************************************************************* 49161ae650dSJack F Vogel * 49261ae650dSJack F Vogel * (Re)Initialize a queue transmit ring. 49361ae650dSJack F Vogel * - called by init, it clears the descriptor ring, 49461ae650dSJack F Vogel * and frees any stale mbufs 49561ae650dSJack F Vogel * 49661ae650dSJack F Vogel **********************************************************************/ 49761ae650dSJack F Vogel void 49861ae650dSJack F Vogel ixl_init_tx_ring(struct ixl_queue *que) 49961ae650dSJack F Vogel { 50031830672SJack F Vogel #ifdef DEV_NETMAP 50131830672SJack F Vogel struct netmap_adapter *na = NA(que->vsi->ifp); 50231830672SJack F Vogel struct netmap_slot *slot; 50331830672SJack F Vogel #endif /* DEV_NETMAP */ 50461ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 50561ae650dSJack F Vogel struct ixl_tx_buf *buf; 50661ae650dSJack F Vogel 50761ae650dSJack F Vogel /* Clear the old ring contents */ 50861ae650dSJack F Vogel IXL_TX_LOCK(txr); 50956c2c47bSJack F Vogel 51031830672SJack F Vogel #ifdef DEV_NETMAP 51131830672SJack F Vogel /* 51231830672SJack F Vogel * (under lock): if in netmap mode, do some consistency 51331830672SJack F Vogel * checks and set slot to entry 0 of the netmap ring. 51431830672SJack F Vogel */ 51531830672SJack F Vogel slot = netmap_reset(na, NR_TX, que->me, 0); 51631830672SJack F Vogel #endif /* DEV_NETMAP */ 517bc8b78d3SLuigi Rizzo 51861ae650dSJack F Vogel bzero((void *)txr->base, 51961ae650dSJack F Vogel (sizeof(struct i40e_tx_desc)) * que->num_desc); 52061ae650dSJack F Vogel 52161ae650dSJack F Vogel /* Reset indices */ 52261ae650dSJack F Vogel txr->next_avail = 0; 52361ae650dSJack F Vogel txr->next_to_clean = 0; 52461ae650dSJack F Vogel 525*cb6b8299SEric Joyner /* Reset watchdog status */ 526*cb6b8299SEric Joyner txr->watchdog_timer = 0; 527*cb6b8299SEric Joyner 52861ae650dSJack F Vogel #ifdef IXL_FDIR 52961ae650dSJack F Vogel /* Initialize flow director */ 53061ae650dSJack F Vogel txr->atr_rate = ixl_atr_rate; 53161ae650dSJack F Vogel txr->atr_count = 0; 53261ae650dSJack F Vogel #endif 53361ae650dSJack F Vogel /* Free any existing tx mbufs. */ 53461ae650dSJack F Vogel buf = txr->buffers; 53561ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++, buf++) { 53661ae650dSJack F Vogel if (buf->m_head != NULL) { 53761ae650dSJack F Vogel bus_dmamap_sync(buf->tag, buf->map, 53861ae650dSJack F Vogel BUS_DMASYNC_POSTWRITE); 53961ae650dSJack F Vogel bus_dmamap_unload(buf->tag, buf->map); 54061ae650dSJack F Vogel m_freem(buf->m_head); 54161ae650dSJack F Vogel buf->m_head = NULL; 54261ae650dSJack F Vogel } 54331830672SJack F Vogel #ifdef DEV_NETMAP 54431830672SJack F Vogel /* 54531830672SJack F Vogel * In netmap mode, set the map for the packet buffer. 54631830672SJack F Vogel * NOTE: Some drivers (not this one) also need to set 54731830672SJack F Vogel * the physical buffer address in the NIC ring. 54831830672SJack F Vogel * netmap_idx_n2k() maps a nic index, i, into the corresponding 54931830672SJack F Vogel * netmap slot index, si 55031830672SJack F Vogel */ 55131830672SJack F Vogel if (slot) { 55231830672SJack F Vogel int si = netmap_idx_n2k(&na->tx_rings[que->me], i); 55331830672SJack F Vogel netmap_load_map(na, buf->tag, buf->map, NMB(na, slot + si)); 55431830672SJack F Vogel } 55531830672SJack F Vogel #endif /* DEV_NETMAP */ 55661ae650dSJack F Vogel /* Clear the EOP index */ 55761ae650dSJack F Vogel buf->eop_index = -1; 55861ae650dSJack F Vogel } 55961ae650dSJack F Vogel 56061ae650dSJack F Vogel /* Set number of descriptors available */ 56161ae650dSJack F Vogel txr->avail = que->num_desc; 56261ae650dSJack F Vogel 56361ae650dSJack F Vogel bus_dmamap_sync(txr->dma.tag, txr->dma.map, 56461ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 56561ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 56661ae650dSJack F Vogel } 56761ae650dSJack F Vogel 56861ae650dSJack F Vogel 56961ae650dSJack F Vogel /********************************************************************* 57061ae650dSJack F Vogel * 57161ae650dSJack F Vogel * Free transmit ring related data structures. 57261ae650dSJack F Vogel * 57361ae650dSJack F Vogel **********************************************************************/ 57461ae650dSJack F Vogel void 57561ae650dSJack F Vogel ixl_free_que_tx(struct ixl_queue *que) 57661ae650dSJack F Vogel { 57761ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 57861ae650dSJack F Vogel struct ixl_tx_buf *buf; 57961ae650dSJack F Vogel 58061ae650dSJack F Vogel INIT_DBG_IF(que->vsi->ifp, "queue %d: begin", que->me); 58161ae650dSJack F Vogel 58261ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++) { 58361ae650dSJack F Vogel buf = &txr->buffers[i]; 58461ae650dSJack F Vogel if (buf->m_head != NULL) { 58561ae650dSJack F Vogel bus_dmamap_sync(buf->tag, buf->map, 58661ae650dSJack F Vogel BUS_DMASYNC_POSTWRITE); 58761ae650dSJack F Vogel bus_dmamap_unload(buf->tag, 58861ae650dSJack F Vogel buf->map); 58961ae650dSJack F Vogel m_freem(buf->m_head); 59061ae650dSJack F Vogel buf->m_head = NULL; 59161ae650dSJack F Vogel if (buf->map != NULL) { 59261ae650dSJack F Vogel bus_dmamap_destroy(buf->tag, 59361ae650dSJack F Vogel buf->map); 59461ae650dSJack F Vogel buf->map = NULL; 59561ae650dSJack F Vogel } 59661ae650dSJack F Vogel } else if (buf->map != NULL) { 59761ae650dSJack F Vogel bus_dmamap_unload(buf->tag, 59861ae650dSJack F Vogel buf->map); 59961ae650dSJack F Vogel bus_dmamap_destroy(buf->tag, 60061ae650dSJack F Vogel buf->map); 60161ae650dSJack F Vogel buf->map = NULL; 60261ae650dSJack F Vogel } 60361ae650dSJack F Vogel } 60461ae650dSJack F Vogel if (txr->br != NULL) 60561ae650dSJack F Vogel buf_ring_free(txr->br, M_DEVBUF); 60661ae650dSJack F Vogel if (txr->buffers != NULL) { 60761ae650dSJack F Vogel free(txr->buffers, M_DEVBUF); 60861ae650dSJack F Vogel txr->buffers = NULL; 60961ae650dSJack F Vogel } 61061ae650dSJack F Vogel if (txr->tx_tag != NULL) { 61161ae650dSJack F Vogel bus_dma_tag_destroy(txr->tx_tag); 61261ae650dSJack F Vogel txr->tx_tag = NULL; 61361ae650dSJack F Vogel } 61461ae650dSJack F Vogel if (txr->tso_tag != NULL) { 61561ae650dSJack F Vogel bus_dma_tag_destroy(txr->tso_tag); 61661ae650dSJack F Vogel txr->tso_tag = NULL; 61761ae650dSJack F Vogel } 61861ae650dSJack F Vogel 61961ae650dSJack F Vogel INIT_DBG_IF(que->vsi->ifp, "queue %d: end", que->me); 62061ae650dSJack F Vogel return; 62161ae650dSJack F Vogel } 62261ae650dSJack F Vogel 62361ae650dSJack F Vogel /********************************************************************* 62461ae650dSJack F Vogel * 62561ae650dSJack F Vogel * Setup descriptor for hw offloads 62661ae650dSJack F Vogel * 62761ae650dSJack F Vogel **********************************************************************/ 62861ae650dSJack F Vogel 62961ae650dSJack F Vogel static int 63061ae650dSJack F Vogel ixl_tx_setup_offload(struct ixl_queue *que, 63161ae650dSJack F Vogel struct mbuf *mp, u32 *cmd, u32 *off) 63261ae650dSJack F Vogel { 63361ae650dSJack F Vogel struct ether_vlan_header *eh; 6341f873f18SJack F Vogel #ifdef INET 63561ae650dSJack F Vogel struct ip *ip = NULL; 6361f873f18SJack F Vogel #endif 63761ae650dSJack F Vogel struct tcphdr *th = NULL; 6381f873f18SJack F Vogel #ifdef INET6 63961ae650dSJack F Vogel struct ip6_hdr *ip6; 6401f873f18SJack F Vogel #endif 64161ae650dSJack F Vogel int elen, ip_hlen = 0, tcp_hlen; 64261ae650dSJack F Vogel u16 etype; 64361ae650dSJack F Vogel u8 ipproto = 0; 64461ae650dSJack F Vogel bool tso = FALSE; 64561ae650dSJack F Vogel 64661ae650dSJack F Vogel /* Set up the TSO context descriptor if required */ 64761ae650dSJack F Vogel if (mp->m_pkthdr.csum_flags & CSUM_TSO) { 64861ae650dSJack F Vogel tso = ixl_tso_setup(que, mp); 64961ae650dSJack F Vogel if (tso) 65061ae650dSJack F Vogel ++que->tso; 65161ae650dSJack F Vogel else 65261ae650dSJack F Vogel return (ENXIO); 65361ae650dSJack F Vogel } 65461ae650dSJack F Vogel 65561ae650dSJack F Vogel /* 65661ae650dSJack F Vogel * Determine where frame payload starts. 65761ae650dSJack F Vogel * Jump over vlan headers if already present, 65861ae650dSJack F Vogel * helpful for QinQ too. 65961ae650dSJack F Vogel */ 66061ae650dSJack F Vogel eh = mtod(mp, struct ether_vlan_header *); 66161ae650dSJack F Vogel if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 66261ae650dSJack F Vogel etype = ntohs(eh->evl_proto); 66361ae650dSJack F Vogel elen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 66461ae650dSJack F Vogel } else { 66561ae650dSJack F Vogel etype = ntohs(eh->evl_encap_proto); 66661ae650dSJack F Vogel elen = ETHER_HDR_LEN; 66761ae650dSJack F Vogel } 66861ae650dSJack F Vogel 66961ae650dSJack F Vogel switch (etype) { 6702f4959abSJack F Vogel #ifdef INET 671b555c614SBjoern A. Zeeb case ETHERTYPE_IP: 67261ae650dSJack F Vogel ip = (struct ip *)(mp->m_data + elen); 67361ae650dSJack F Vogel ip_hlen = ip->ip_hl << 2; 67461ae650dSJack F Vogel ipproto = ip->ip_p; 67561ae650dSJack F Vogel th = (struct tcphdr *)((caddr_t)ip + ip_hlen); 67661ae650dSJack F Vogel /* The IP checksum must be recalculated with TSO */ 67761ae650dSJack F Vogel if (tso) 67861ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM; 67961ae650dSJack F Vogel else 68061ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_IIPT_IPV4; 68161ae650dSJack F Vogel break; 682b555c614SBjoern A. Zeeb #endif 6832f4959abSJack F Vogel #ifdef INET6 684b555c614SBjoern A. Zeeb case ETHERTYPE_IPV6: 68561ae650dSJack F Vogel ip6 = (struct ip6_hdr *)(mp->m_data + elen); 68661ae650dSJack F Vogel ip_hlen = sizeof(struct ip6_hdr); 68761ae650dSJack F Vogel ipproto = ip6->ip6_nxt; 68861ae650dSJack F Vogel th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); 68961ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_IIPT_IPV6; 690b555c614SBjoern A. Zeeb break; 6912f4959abSJack F Vogel #endif 69261ae650dSJack F Vogel default: 69361ae650dSJack F Vogel break; 69461ae650dSJack F Vogel } 69561ae650dSJack F Vogel 69661ae650dSJack F Vogel *off |= (elen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; 69761ae650dSJack F Vogel *off |= (ip_hlen >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT; 69861ae650dSJack F Vogel 69961ae650dSJack F Vogel switch (ipproto) { 70061ae650dSJack F Vogel case IPPROTO_TCP: 70161ae650dSJack F Vogel tcp_hlen = th->th_off << 2; 70261ae650dSJack F Vogel if (mp->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_TCP_IPV6)) { 70361ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP; 70461ae650dSJack F Vogel *off |= (tcp_hlen >> 2) << 70561ae650dSJack F Vogel I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 70661ae650dSJack F Vogel } 70761ae650dSJack F Vogel #ifdef IXL_FDIR 70861ae650dSJack F Vogel ixl_atr(que, th, etype); 70961ae650dSJack F Vogel #endif 71061ae650dSJack F Vogel break; 71161ae650dSJack F Vogel case IPPROTO_UDP: 71261ae650dSJack F Vogel if (mp->m_pkthdr.csum_flags & (CSUM_UDP|CSUM_UDP_IPV6)) { 71361ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP; 71461ae650dSJack F Vogel *off |= (sizeof(struct udphdr) >> 2) << 71561ae650dSJack F Vogel I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 71661ae650dSJack F Vogel } 71761ae650dSJack F Vogel break; 71861ae650dSJack F Vogel 71961ae650dSJack F Vogel case IPPROTO_SCTP: 72061ae650dSJack F Vogel if (mp->m_pkthdr.csum_flags & (CSUM_SCTP|CSUM_SCTP_IPV6)) { 72161ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP; 72261ae650dSJack F Vogel *off |= (sizeof(struct sctphdr) >> 2) << 72361ae650dSJack F Vogel I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 72461ae650dSJack F Vogel } 72561ae650dSJack F Vogel /* Fall Thru */ 72661ae650dSJack F Vogel default: 72761ae650dSJack F Vogel break; 72861ae650dSJack F Vogel } 72961ae650dSJack F Vogel 73061ae650dSJack F Vogel return (0); 73161ae650dSJack F Vogel } 73261ae650dSJack F Vogel 73361ae650dSJack F Vogel 73461ae650dSJack F Vogel /********************************************************************** 73561ae650dSJack F Vogel * 73661ae650dSJack F Vogel * Setup context for hardware segmentation offload (TSO) 73761ae650dSJack F Vogel * 73861ae650dSJack F Vogel **********************************************************************/ 73961ae650dSJack F Vogel static bool 74061ae650dSJack F Vogel ixl_tso_setup(struct ixl_queue *que, struct mbuf *mp) 74161ae650dSJack F Vogel { 74261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 74361ae650dSJack F Vogel struct i40e_tx_context_desc *TXD; 74461ae650dSJack F Vogel struct ixl_tx_buf *buf; 74561ae650dSJack F Vogel u32 cmd, mss, type, tsolen; 74661ae650dSJack F Vogel u16 etype; 74761ae650dSJack F Vogel int idx, elen, ip_hlen, tcp_hlen; 74861ae650dSJack F Vogel struct ether_vlan_header *eh; 7491f873f18SJack F Vogel #ifdef INET 75061ae650dSJack F Vogel struct ip *ip; 7511f873f18SJack F Vogel #endif 7521f873f18SJack F Vogel #ifdef INET6 75361ae650dSJack F Vogel struct ip6_hdr *ip6; 7541f873f18SJack F Vogel #endif 755b555c614SBjoern A. Zeeb #if defined(INET6) || defined(INET) 75661ae650dSJack F Vogel struct tcphdr *th; 757b555c614SBjoern A. Zeeb #endif 75861ae650dSJack F Vogel u64 type_cmd_tso_mss; 75961ae650dSJack F Vogel 76061ae650dSJack F Vogel /* 76161ae650dSJack F Vogel * Determine where frame payload starts. 76261ae650dSJack F Vogel * Jump over vlan headers if already present 76361ae650dSJack F Vogel */ 76461ae650dSJack F Vogel eh = mtod(mp, struct ether_vlan_header *); 76561ae650dSJack F Vogel if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 76661ae650dSJack F Vogel elen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 76761ae650dSJack F Vogel etype = eh->evl_proto; 76861ae650dSJack F Vogel } else { 76961ae650dSJack F Vogel elen = ETHER_HDR_LEN; 77061ae650dSJack F Vogel etype = eh->evl_encap_proto; 77161ae650dSJack F Vogel } 77261ae650dSJack F Vogel 77361ae650dSJack F Vogel switch (ntohs(etype)) { 77461ae650dSJack F Vogel #ifdef INET6 77561ae650dSJack F Vogel case ETHERTYPE_IPV6: 77661ae650dSJack F Vogel ip6 = (struct ip6_hdr *)(mp->m_data + elen); 77761ae650dSJack F Vogel if (ip6->ip6_nxt != IPPROTO_TCP) 77861ae650dSJack F Vogel return (ENXIO); 77961ae650dSJack F Vogel ip_hlen = sizeof(struct ip6_hdr); 78061ae650dSJack F Vogel th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); 78161ae650dSJack F Vogel th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 78261ae650dSJack F Vogel tcp_hlen = th->th_off << 2; 7836d011ad5SEric Joyner /* 7846d011ad5SEric Joyner * The corresponding flag is set by the stack in the IPv4 7856d011ad5SEric Joyner * TSO case, but not in IPv6 (at least in FreeBSD 10.2). 7866d011ad5SEric Joyner * So, set it here because the rest of the flow requires it. 7876d011ad5SEric Joyner */ 7886d011ad5SEric Joyner mp->m_pkthdr.csum_flags |= CSUM_TCP_IPV6; 78961ae650dSJack F Vogel break; 79061ae650dSJack F Vogel #endif 79161ae650dSJack F Vogel #ifdef INET 79261ae650dSJack F Vogel case ETHERTYPE_IP: 79361ae650dSJack F Vogel ip = (struct ip *)(mp->m_data + elen); 79461ae650dSJack F Vogel if (ip->ip_p != IPPROTO_TCP) 79561ae650dSJack F Vogel return (ENXIO); 79661ae650dSJack F Vogel ip->ip_sum = 0; 79761ae650dSJack F Vogel ip_hlen = ip->ip_hl << 2; 79861ae650dSJack F Vogel th = (struct tcphdr *)((caddr_t)ip + ip_hlen); 79961ae650dSJack F Vogel th->th_sum = in_pseudo(ip->ip_src.s_addr, 80061ae650dSJack F Vogel ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 80161ae650dSJack F Vogel tcp_hlen = th->th_off << 2; 80261ae650dSJack F Vogel break; 80361ae650dSJack F Vogel #endif 80461ae650dSJack F Vogel default: 805b555c614SBjoern A. Zeeb printf("%s: CSUM_TSO but no supported IP version (0x%04x)", 80661ae650dSJack F Vogel __func__, ntohs(etype)); 807b555c614SBjoern A. Zeeb return FALSE; 80861ae650dSJack F Vogel } 80961ae650dSJack F Vogel 81061ae650dSJack F Vogel /* Ensure we have at least the IP+TCP header in the first mbuf. */ 81161ae650dSJack F Vogel if (mp->m_len < elen + ip_hlen + sizeof(struct tcphdr)) 81261ae650dSJack F Vogel return FALSE; 81361ae650dSJack F Vogel 81461ae650dSJack F Vogel idx = txr->next_avail; 81561ae650dSJack F Vogel buf = &txr->buffers[idx]; 81661ae650dSJack F Vogel TXD = (struct i40e_tx_context_desc *) &txr->base[idx]; 81761ae650dSJack F Vogel tsolen = mp->m_pkthdr.len - (elen + ip_hlen + tcp_hlen); 81861ae650dSJack F Vogel 81961ae650dSJack F Vogel type = I40E_TX_DESC_DTYPE_CONTEXT; 82061ae650dSJack F Vogel cmd = I40E_TX_CTX_DESC_TSO; 821*cb6b8299SEric Joyner /* TSO MSS must not be less than 64 */ 822*cb6b8299SEric Joyner if (mp->m_pkthdr.tso_segsz < IXL_MIN_TSO_MSS) { 823*cb6b8299SEric Joyner que->mss_too_small++; 824*cb6b8299SEric Joyner mp->m_pkthdr.tso_segsz = IXL_MIN_TSO_MSS; 825*cb6b8299SEric Joyner } 82661ae650dSJack F Vogel mss = mp->m_pkthdr.tso_segsz; 82761ae650dSJack F Vogel 82861ae650dSJack F Vogel type_cmd_tso_mss = ((u64)type << I40E_TXD_CTX_QW1_DTYPE_SHIFT) | 82961ae650dSJack F Vogel ((u64)cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) | 83061ae650dSJack F Vogel ((u64)tsolen << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) | 83161ae650dSJack F Vogel ((u64)mss << I40E_TXD_CTX_QW1_MSS_SHIFT); 83261ae650dSJack F Vogel TXD->type_cmd_tso_mss = htole64(type_cmd_tso_mss); 83361ae650dSJack F Vogel 83461ae650dSJack F Vogel TXD->tunneling_params = htole32(0); 83561ae650dSJack F Vogel buf->m_head = NULL; 83661ae650dSJack F Vogel buf->eop_index = -1; 83761ae650dSJack F Vogel 83861ae650dSJack F Vogel if (++idx == que->num_desc) 83961ae650dSJack F Vogel idx = 0; 84061ae650dSJack F Vogel 84161ae650dSJack F Vogel txr->avail--; 84261ae650dSJack F Vogel txr->next_avail = idx; 84361ae650dSJack F Vogel 84461ae650dSJack F Vogel return TRUE; 84561ae650dSJack F Vogel } 84661ae650dSJack F Vogel 84761ae650dSJack F Vogel /* 84861ae650dSJack F Vogel ** ixl_get_tx_head - Retrieve the value from the 84961ae650dSJack F Vogel ** location the HW records its HEAD index 85061ae650dSJack F Vogel */ 85161ae650dSJack F Vogel static inline u32 85261ae650dSJack F Vogel ixl_get_tx_head(struct ixl_queue *que) 85361ae650dSJack F Vogel { 85461ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 85561ae650dSJack F Vogel void *head = &txr->base[que->num_desc]; 85661ae650dSJack F Vogel return LE32_TO_CPU(*(volatile __le32 *)head); 85761ae650dSJack F Vogel } 85861ae650dSJack F Vogel 85961ae650dSJack F Vogel /********************************************************************** 86061ae650dSJack F Vogel * 86161ae650dSJack F Vogel * Examine each tx_buffer in the used queue. If the hardware is done 86261ae650dSJack F Vogel * processing the packet then free associated resources. The 86361ae650dSJack F Vogel * tx_buffer is put back on the free queue. 86461ae650dSJack F Vogel * 86561ae650dSJack F Vogel **********************************************************************/ 86661ae650dSJack F Vogel bool 86761ae650dSJack F Vogel ixl_txeof(struct ixl_queue *que) 86861ae650dSJack F Vogel { 86961ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 87061ae650dSJack F Vogel u32 first, last, head, done, processed; 87161ae650dSJack F Vogel struct ixl_tx_buf *buf; 87261ae650dSJack F Vogel struct i40e_tx_desc *tx_desc, *eop_desc; 87361ae650dSJack F Vogel 87461ae650dSJack F Vogel 87561ae650dSJack F Vogel mtx_assert(&txr->mtx, MA_OWNED); 87661ae650dSJack F Vogel 87731830672SJack F Vogel #ifdef DEV_NETMAP 87831830672SJack F Vogel // XXX todo: implement moderation 87931830672SJack F Vogel if (netmap_tx_irq(que->vsi->ifp, que->me)) 88031830672SJack F Vogel return FALSE; 88131830672SJack F Vogel #endif /* DEF_NETMAP */ 882e5100ee2SJack F Vogel 88361ae650dSJack F Vogel /* These are not the descriptors you seek, move along :) */ 88461ae650dSJack F Vogel if (txr->avail == que->num_desc) { 885*cb6b8299SEric Joyner atomic_store_rel_32(&txr->watchdog_timer, 0); 88661ae650dSJack F Vogel return FALSE; 88761ae650dSJack F Vogel } 88861ae650dSJack F Vogel 88961ae650dSJack F Vogel processed = 0; 89061ae650dSJack F Vogel first = txr->next_to_clean; 89161ae650dSJack F Vogel buf = &txr->buffers[first]; 89261ae650dSJack F Vogel tx_desc = (struct i40e_tx_desc *)&txr->base[first]; 89361ae650dSJack F Vogel last = buf->eop_index; 89461ae650dSJack F Vogel if (last == -1) 89561ae650dSJack F Vogel return FALSE; 89661ae650dSJack F Vogel eop_desc = (struct i40e_tx_desc *)&txr->base[last]; 89761ae650dSJack F Vogel 89861ae650dSJack F Vogel /* Get the Head WB value */ 89961ae650dSJack F Vogel head = ixl_get_tx_head(que); 90061ae650dSJack F Vogel 90161ae650dSJack F Vogel /* 90261ae650dSJack F Vogel ** Get the index of the first descriptor 90361ae650dSJack F Vogel ** BEYOND the EOP and call that 'done'. 90461ae650dSJack F Vogel ** I do this so the comparison in the 90561ae650dSJack F Vogel ** inner while loop below can be simple 90661ae650dSJack F Vogel */ 90761ae650dSJack F Vogel if (++last == que->num_desc) last = 0; 90861ae650dSJack F Vogel done = last; 90961ae650dSJack F Vogel 91061ae650dSJack F Vogel bus_dmamap_sync(txr->dma.tag, txr->dma.map, 91161ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 91261ae650dSJack F Vogel /* 91361ae650dSJack F Vogel ** The HEAD index of the ring is written in a 91461ae650dSJack F Vogel ** defined location, this rather than a done bit 91561ae650dSJack F Vogel ** is what is used to keep track of what must be 91661ae650dSJack F Vogel ** 'cleaned'. 91761ae650dSJack F Vogel */ 91861ae650dSJack F Vogel while (first != head) { 91961ae650dSJack F Vogel /* We clean the range of the packet */ 92061ae650dSJack F Vogel while (first != done) { 92161ae650dSJack F Vogel ++txr->avail; 92261ae650dSJack F Vogel ++processed; 92361ae650dSJack F Vogel 92461ae650dSJack F Vogel if (buf->m_head) { 92561ae650dSJack F Vogel txr->bytes += /* for ITR adjustment */ 92661ae650dSJack F Vogel buf->m_head->m_pkthdr.len; 92761ae650dSJack F Vogel txr->tx_bytes += /* for TX stats */ 92861ae650dSJack F Vogel buf->m_head->m_pkthdr.len; 92961ae650dSJack F Vogel bus_dmamap_sync(buf->tag, 93061ae650dSJack F Vogel buf->map, 93161ae650dSJack F Vogel BUS_DMASYNC_POSTWRITE); 93261ae650dSJack F Vogel bus_dmamap_unload(buf->tag, 93361ae650dSJack F Vogel buf->map); 93461ae650dSJack F Vogel m_freem(buf->m_head); 93561ae650dSJack F Vogel buf->m_head = NULL; 93661ae650dSJack F Vogel buf->map = NULL; 93761ae650dSJack F Vogel } 93861ae650dSJack F Vogel buf->eop_index = -1; 93961ae650dSJack F Vogel 94061ae650dSJack F Vogel if (++first == que->num_desc) 94161ae650dSJack F Vogel first = 0; 94261ae650dSJack F Vogel 94361ae650dSJack F Vogel buf = &txr->buffers[first]; 94461ae650dSJack F Vogel tx_desc = &txr->base[first]; 94561ae650dSJack F Vogel } 94661ae650dSJack F Vogel ++txr->packets; 94761ae650dSJack F Vogel /* See if there is more work now */ 94861ae650dSJack F Vogel last = buf->eop_index; 94961ae650dSJack F Vogel if (last != -1) { 95061ae650dSJack F Vogel eop_desc = &txr->base[last]; 95161ae650dSJack F Vogel /* Get next done point */ 95261ae650dSJack F Vogel if (++last == que->num_desc) last = 0; 95361ae650dSJack F Vogel done = last; 95461ae650dSJack F Vogel } else 95561ae650dSJack F Vogel break; 95661ae650dSJack F Vogel } 95761ae650dSJack F Vogel bus_dmamap_sync(txr->dma.tag, txr->dma.map, 95861ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 95961ae650dSJack F Vogel 96061ae650dSJack F Vogel txr->next_to_clean = first; 96161ae650dSJack F Vogel 96261ae650dSJack F Vogel 96361ae650dSJack F Vogel /* 96461ae650dSJack F Vogel * If there are no pending descriptors, clear the timeout. 96561ae650dSJack F Vogel */ 96661ae650dSJack F Vogel if (txr->avail == que->num_desc) { 967*cb6b8299SEric Joyner atomic_store_rel_32(&txr->watchdog_timer, 0); 96861ae650dSJack F Vogel return FALSE; 96961ae650dSJack F Vogel } 97061ae650dSJack F Vogel 97161ae650dSJack F Vogel return TRUE; 97261ae650dSJack F Vogel } 97361ae650dSJack F Vogel 97461ae650dSJack F Vogel /********************************************************************* 97561ae650dSJack F Vogel * 97661ae650dSJack F Vogel * Refresh mbuf buffers for RX descriptor rings 97761ae650dSJack F Vogel * - now keeps its own state so discards due to resource 97861ae650dSJack F Vogel * exhaustion are unnecessary, if an mbuf cannot be obtained 97961ae650dSJack F Vogel * it just returns, keeping its placeholder, thus it can simply 98061ae650dSJack F Vogel * be recalled to try again. 98161ae650dSJack F Vogel * 98261ae650dSJack F Vogel **********************************************************************/ 98361ae650dSJack F Vogel static void 98461ae650dSJack F Vogel ixl_refresh_mbufs(struct ixl_queue *que, int limit) 98561ae650dSJack F Vogel { 98661ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 98761ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 98861ae650dSJack F Vogel bus_dma_segment_t hseg[1]; 98961ae650dSJack F Vogel bus_dma_segment_t pseg[1]; 99061ae650dSJack F Vogel struct ixl_rx_buf *buf; 99161ae650dSJack F Vogel struct mbuf *mh, *mp; 99261ae650dSJack F Vogel int i, j, nsegs, error; 99361ae650dSJack F Vogel bool refreshed = FALSE; 99461ae650dSJack F Vogel 99561ae650dSJack F Vogel i = j = rxr->next_refresh; 99661ae650dSJack F Vogel /* Control the loop with one beyond */ 99761ae650dSJack F Vogel if (++j == que->num_desc) 99861ae650dSJack F Vogel j = 0; 99961ae650dSJack F Vogel 100061ae650dSJack F Vogel while (j != limit) { 100161ae650dSJack F Vogel buf = &rxr->buffers[i]; 100261ae650dSJack F Vogel if (rxr->hdr_split == FALSE) 100361ae650dSJack F Vogel goto no_split; 100461ae650dSJack F Vogel 100561ae650dSJack F Vogel if (buf->m_head == NULL) { 100661ae650dSJack F Vogel mh = m_gethdr(M_NOWAIT, MT_DATA); 100761ae650dSJack F Vogel if (mh == NULL) 100861ae650dSJack F Vogel goto update; 100961ae650dSJack F Vogel } else 101061ae650dSJack F Vogel mh = buf->m_head; 101161ae650dSJack F Vogel 101261ae650dSJack F Vogel mh->m_pkthdr.len = mh->m_len = MHLEN; 101361ae650dSJack F Vogel mh->m_len = MHLEN; 101461ae650dSJack F Vogel mh->m_flags |= M_PKTHDR; 101561ae650dSJack F Vogel /* Get the memory mapping */ 101661ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(rxr->htag, 101761ae650dSJack F Vogel buf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT); 101861ae650dSJack F Vogel if (error != 0) { 101961ae650dSJack F Vogel printf("Refresh mbufs: hdr dmamap load" 102061ae650dSJack F Vogel " failure - %d\n", error); 102161ae650dSJack F Vogel m_free(mh); 102261ae650dSJack F Vogel buf->m_head = NULL; 102361ae650dSJack F Vogel goto update; 102461ae650dSJack F Vogel } 102561ae650dSJack F Vogel buf->m_head = mh; 102661ae650dSJack F Vogel bus_dmamap_sync(rxr->htag, buf->hmap, 102761ae650dSJack F Vogel BUS_DMASYNC_PREREAD); 102861ae650dSJack F Vogel rxr->base[i].read.hdr_addr = 102961ae650dSJack F Vogel htole64(hseg[0].ds_addr); 103061ae650dSJack F Vogel 103161ae650dSJack F Vogel no_split: 103261ae650dSJack F Vogel if (buf->m_pack == NULL) { 103361ae650dSJack F Vogel mp = m_getjcl(M_NOWAIT, MT_DATA, 103461ae650dSJack F Vogel M_PKTHDR, rxr->mbuf_sz); 103561ae650dSJack F Vogel if (mp == NULL) 103661ae650dSJack F Vogel goto update; 103761ae650dSJack F Vogel } else 103861ae650dSJack F Vogel mp = buf->m_pack; 103961ae650dSJack F Vogel 104061ae650dSJack F Vogel mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz; 104161ae650dSJack F Vogel /* Get the memory mapping */ 104261ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(rxr->ptag, 104361ae650dSJack F Vogel buf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT); 104461ae650dSJack F Vogel if (error != 0) { 104561ae650dSJack F Vogel printf("Refresh mbufs: payload dmamap load" 104661ae650dSJack F Vogel " failure - %d\n", error); 104761ae650dSJack F Vogel m_free(mp); 104861ae650dSJack F Vogel buf->m_pack = NULL; 104961ae650dSJack F Vogel goto update; 105061ae650dSJack F Vogel } 105161ae650dSJack F Vogel buf->m_pack = mp; 105261ae650dSJack F Vogel bus_dmamap_sync(rxr->ptag, buf->pmap, 105361ae650dSJack F Vogel BUS_DMASYNC_PREREAD); 105461ae650dSJack F Vogel rxr->base[i].read.pkt_addr = 105561ae650dSJack F Vogel htole64(pseg[0].ds_addr); 105661ae650dSJack F Vogel /* Used only when doing header split */ 105761ae650dSJack F Vogel rxr->base[i].read.hdr_addr = 0; 105861ae650dSJack F Vogel 105961ae650dSJack F Vogel refreshed = TRUE; 106061ae650dSJack F Vogel /* Next is precalculated */ 106161ae650dSJack F Vogel i = j; 106261ae650dSJack F Vogel rxr->next_refresh = i; 106361ae650dSJack F Vogel if (++j == que->num_desc) 106461ae650dSJack F Vogel j = 0; 106561ae650dSJack F Vogel } 106661ae650dSJack F Vogel update: 106761ae650dSJack F Vogel if (refreshed) /* Update hardware tail index */ 106861ae650dSJack F Vogel wr32(vsi->hw, rxr->tail, rxr->next_refresh); 106961ae650dSJack F Vogel return; 107061ae650dSJack F Vogel } 107161ae650dSJack F Vogel 107261ae650dSJack F Vogel 107361ae650dSJack F Vogel /********************************************************************* 107461ae650dSJack F Vogel * 107561ae650dSJack F Vogel * Allocate memory for rx_buffer structures. Since we use one 107661ae650dSJack F Vogel * rx_buffer per descriptor, the maximum number of rx_buffer's 107761ae650dSJack F Vogel * that we'll need is equal to the number of receive descriptors 107861ae650dSJack F Vogel * that we've defined. 107961ae650dSJack F Vogel * 108061ae650dSJack F Vogel **********************************************************************/ 108161ae650dSJack F Vogel int 108261ae650dSJack F Vogel ixl_allocate_rx_data(struct ixl_queue *que) 108361ae650dSJack F Vogel { 108461ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 108561ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 108661ae650dSJack F Vogel device_t dev = vsi->dev; 108761ae650dSJack F Vogel struct ixl_rx_buf *buf; 108861ae650dSJack F Vogel int i, bsize, error; 108961ae650dSJack F Vogel 109061ae650dSJack F Vogel bsize = sizeof(struct ixl_rx_buf) * que->num_desc; 109161ae650dSJack F Vogel if (!(rxr->buffers = 109261ae650dSJack F Vogel (struct ixl_rx_buf *) malloc(bsize, 109361ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO))) { 109461ae650dSJack F Vogel device_printf(dev, "Unable to allocate rx_buffer memory\n"); 109561ae650dSJack F Vogel error = ENOMEM; 109661ae650dSJack F Vogel return (error); 109761ae650dSJack F Vogel } 109861ae650dSJack F Vogel 109961ae650dSJack F Vogel if ((error = bus_dma_tag_create(NULL, /* parent */ 110061ae650dSJack F Vogel 1, 0, /* alignment, bounds */ 110161ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* lowaddr */ 110261ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* highaddr */ 110361ae650dSJack F Vogel NULL, NULL, /* filter, filterarg */ 110461ae650dSJack F Vogel MSIZE, /* maxsize */ 110561ae650dSJack F Vogel 1, /* nsegments */ 110661ae650dSJack F Vogel MSIZE, /* maxsegsize */ 110761ae650dSJack F Vogel 0, /* flags */ 110861ae650dSJack F Vogel NULL, /* lockfunc */ 110961ae650dSJack F Vogel NULL, /* lockfuncarg */ 111061ae650dSJack F Vogel &rxr->htag))) { 111161ae650dSJack F Vogel device_printf(dev, "Unable to create RX DMA htag\n"); 111261ae650dSJack F Vogel return (error); 111361ae650dSJack F Vogel } 111461ae650dSJack F Vogel 111561ae650dSJack F Vogel if ((error = bus_dma_tag_create(NULL, /* parent */ 111661ae650dSJack F Vogel 1, 0, /* alignment, bounds */ 111761ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* lowaddr */ 111861ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* highaddr */ 111961ae650dSJack F Vogel NULL, NULL, /* filter, filterarg */ 112061ae650dSJack F Vogel MJUM16BYTES, /* maxsize */ 112161ae650dSJack F Vogel 1, /* nsegments */ 112261ae650dSJack F Vogel MJUM16BYTES, /* maxsegsize */ 112361ae650dSJack F Vogel 0, /* flags */ 112461ae650dSJack F Vogel NULL, /* lockfunc */ 112561ae650dSJack F Vogel NULL, /* lockfuncarg */ 112661ae650dSJack F Vogel &rxr->ptag))) { 112761ae650dSJack F Vogel device_printf(dev, "Unable to create RX DMA ptag\n"); 112861ae650dSJack F Vogel return (error); 112961ae650dSJack F Vogel } 113061ae650dSJack F Vogel 113161ae650dSJack F Vogel for (i = 0; i < que->num_desc; i++) { 113261ae650dSJack F Vogel buf = &rxr->buffers[i]; 113361ae650dSJack F Vogel error = bus_dmamap_create(rxr->htag, 113461ae650dSJack F Vogel BUS_DMA_NOWAIT, &buf->hmap); 113561ae650dSJack F Vogel if (error) { 113661ae650dSJack F Vogel device_printf(dev, "Unable to create RX head map\n"); 113761ae650dSJack F Vogel break; 113861ae650dSJack F Vogel } 113961ae650dSJack F Vogel error = bus_dmamap_create(rxr->ptag, 114061ae650dSJack F Vogel BUS_DMA_NOWAIT, &buf->pmap); 114161ae650dSJack F Vogel if (error) { 114261ae650dSJack F Vogel device_printf(dev, "Unable to create RX pkt map\n"); 114361ae650dSJack F Vogel break; 114461ae650dSJack F Vogel } 114561ae650dSJack F Vogel } 114661ae650dSJack F Vogel 114761ae650dSJack F Vogel return (error); 114861ae650dSJack F Vogel } 114961ae650dSJack F Vogel 115061ae650dSJack F Vogel 115161ae650dSJack F Vogel /********************************************************************* 115261ae650dSJack F Vogel * 115361ae650dSJack F Vogel * (Re)Initialize the queue receive ring and its buffers. 115461ae650dSJack F Vogel * 115561ae650dSJack F Vogel **********************************************************************/ 115661ae650dSJack F Vogel int 115761ae650dSJack F Vogel ixl_init_rx_ring(struct ixl_queue *que) 115861ae650dSJack F Vogel { 1159b3f7259bSBjoern A. Zeeb struct rx_ring *rxr = &que->rxr; 1160393c4bb1SJack F Vogel struct ixl_vsi *vsi = que->vsi; 1161a2cf30b9SBjoern A. Zeeb #if defined(INET6) || defined(INET) 116261ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 116361ae650dSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 1164b3f7259bSBjoern A. Zeeb #endif 116561ae650dSJack F Vogel struct ixl_rx_buf *buf; 116661ae650dSJack F Vogel bus_dma_segment_t pseg[1], hseg[1]; 116761ae650dSJack F Vogel int rsize, nsegs, error = 0; 116831830672SJack F Vogel #ifdef DEV_NETMAP 116931830672SJack F Vogel struct netmap_adapter *na = NA(que->vsi->ifp); 117031830672SJack F Vogel struct netmap_slot *slot; 117131830672SJack F Vogel #endif /* DEV_NETMAP */ 117261ae650dSJack F Vogel 117361ae650dSJack F Vogel IXL_RX_LOCK(rxr); 117431830672SJack F Vogel #ifdef DEV_NETMAP 117531830672SJack F Vogel /* same as in ixl_init_tx_ring() */ 117631830672SJack F Vogel slot = netmap_reset(na, NR_RX, que->me, 0); 117731830672SJack F Vogel #endif /* DEV_NETMAP */ 117861ae650dSJack F Vogel /* Clear the ring contents */ 117961ae650dSJack F Vogel rsize = roundup2(que->num_desc * 118061ae650dSJack F Vogel sizeof(union i40e_rx_desc), DBA_ALIGN); 118161ae650dSJack F Vogel bzero((void *)rxr->base, rsize); 118261ae650dSJack F Vogel /* Cleanup any existing buffers */ 118361ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++) { 118461ae650dSJack F Vogel buf = &rxr->buffers[i]; 118561ae650dSJack F Vogel if (buf->m_head != NULL) { 118661ae650dSJack F Vogel bus_dmamap_sync(rxr->htag, buf->hmap, 118761ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 118861ae650dSJack F Vogel bus_dmamap_unload(rxr->htag, buf->hmap); 118961ae650dSJack F Vogel buf->m_head->m_flags |= M_PKTHDR; 119061ae650dSJack F Vogel m_freem(buf->m_head); 119161ae650dSJack F Vogel } 119261ae650dSJack F Vogel if (buf->m_pack != NULL) { 119361ae650dSJack F Vogel bus_dmamap_sync(rxr->ptag, buf->pmap, 119461ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 119561ae650dSJack F Vogel bus_dmamap_unload(rxr->ptag, buf->pmap); 119661ae650dSJack F Vogel buf->m_pack->m_flags |= M_PKTHDR; 119761ae650dSJack F Vogel m_freem(buf->m_pack); 119861ae650dSJack F Vogel } 119961ae650dSJack F Vogel buf->m_head = NULL; 120061ae650dSJack F Vogel buf->m_pack = NULL; 120161ae650dSJack F Vogel } 120261ae650dSJack F Vogel 120361ae650dSJack F Vogel /* header split is off */ 120461ae650dSJack F Vogel rxr->hdr_split = FALSE; 120561ae650dSJack F Vogel 120661ae650dSJack F Vogel /* Now replenish the mbufs */ 120761ae650dSJack F Vogel for (int j = 0; j != que->num_desc; ++j) { 120861ae650dSJack F Vogel struct mbuf *mh, *mp; 120961ae650dSJack F Vogel 121061ae650dSJack F Vogel buf = &rxr->buffers[j]; 121131830672SJack F Vogel #ifdef DEV_NETMAP 121231830672SJack F Vogel /* 121331830672SJack F Vogel * In netmap mode, fill the map and set the buffer 121431830672SJack F Vogel * address in the NIC ring, considering the offset 121531830672SJack F Vogel * between the netmap and NIC rings (see comment in 121631830672SJack F Vogel * ixgbe_setup_transmit_ring() ). No need to allocate 121731830672SJack F Vogel * an mbuf, so end the block with a continue; 121831830672SJack F Vogel */ 121931830672SJack F Vogel if (slot) { 122031830672SJack F Vogel int sj = netmap_idx_n2k(&na->rx_rings[que->me], j); 122131830672SJack F Vogel uint64_t paddr; 122231830672SJack F Vogel void *addr; 1223bc8b78d3SLuigi Rizzo 122431830672SJack F Vogel addr = PNMB(na, slot + sj, &paddr); 122531830672SJack F Vogel netmap_load_map(na, rxr->dma.tag, buf->pmap, addr); 122631830672SJack F Vogel /* Update descriptor and the cached value */ 122731830672SJack F Vogel rxr->base[j].read.pkt_addr = htole64(paddr); 122831830672SJack F Vogel rxr->base[j].read.hdr_addr = 0; 122931830672SJack F Vogel continue; 123031830672SJack F Vogel } 123131830672SJack F Vogel #endif /* DEV_NETMAP */ 123261ae650dSJack F Vogel /* 123361ae650dSJack F Vogel ** Don't allocate mbufs if not 123461ae650dSJack F Vogel ** doing header split, its wasteful 123561ae650dSJack F Vogel */ 123661ae650dSJack F Vogel if (rxr->hdr_split == FALSE) 123761ae650dSJack F Vogel goto skip_head; 123861ae650dSJack F Vogel 123961ae650dSJack F Vogel /* First the header */ 124061ae650dSJack F Vogel buf->m_head = m_gethdr(M_NOWAIT, MT_DATA); 124161ae650dSJack F Vogel if (buf->m_head == NULL) { 124261ae650dSJack F Vogel error = ENOBUFS; 124361ae650dSJack F Vogel goto fail; 124461ae650dSJack F Vogel } 124561ae650dSJack F Vogel m_adj(buf->m_head, ETHER_ALIGN); 124661ae650dSJack F Vogel mh = buf->m_head; 124761ae650dSJack F Vogel mh->m_len = mh->m_pkthdr.len = MHLEN; 124861ae650dSJack F Vogel mh->m_flags |= M_PKTHDR; 124961ae650dSJack F Vogel /* Get the memory mapping */ 125061ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(rxr->htag, 125161ae650dSJack F Vogel buf->hmap, buf->m_head, hseg, 125261ae650dSJack F Vogel &nsegs, BUS_DMA_NOWAIT); 125361ae650dSJack F Vogel if (error != 0) /* Nothing elegant to do here */ 125461ae650dSJack F Vogel goto fail; 125561ae650dSJack F Vogel bus_dmamap_sync(rxr->htag, 125661ae650dSJack F Vogel buf->hmap, BUS_DMASYNC_PREREAD); 125761ae650dSJack F Vogel /* Update descriptor */ 125861ae650dSJack F Vogel rxr->base[j].read.hdr_addr = htole64(hseg[0].ds_addr); 125961ae650dSJack F Vogel 126061ae650dSJack F Vogel skip_head: 126161ae650dSJack F Vogel /* Now the payload cluster */ 126261ae650dSJack F Vogel buf->m_pack = m_getjcl(M_NOWAIT, MT_DATA, 126361ae650dSJack F Vogel M_PKTHDR, rxr->mbuf_sz); 126461ae650dSJack F Vogel if (buf->m_pack == NULL) { 126561ae650dSJack F Vogel error = ENOBUFS; 126661ae650dSJack F Vogel goto fail; 126761ae650dSJack F Vogel } 126861ae650dSJack F Vogel mp = buf->m_pack; 126961ae650dSJack F Vogel mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz; 127061ae650dSJack F Vogel /* Get the memory mapping */ 127161ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(rxr->ptag, 127261ae650dSJack F Vogel buf->pmap, mp, pseg, 127361ae650dSJack F Vogel &nsegs, BUS_DMA_NOWAIT); 127461ae650dSJack F Vogel if (error != 0) 127561ae650dSJack F Vogel goto fail; 127661ae650dSJack F Vogel bus_dmamap_sync(rxr->ptag, 127761ae650dSJack F Vogel buf->pmap, BUS_DMASYNC_PREREAD); 127861ae650dSJack F Vogel /* Update descriptor */ 127961ae650dSJack F Vogel rxr->base[j].read.pkt_addr = htole64(pseg[0].ds_addr); 128061ae650dSJack F Vogel rxr->base[j].read.hdr_addr = 0; 128161ae650dSJack F Vogel } 128261ae650dSJack F Vogel 128361ae650dSJack F Vogel 128461ae650dSJack F Vogel /* Setup our descriptor indices */ 128561ae650dSJack F Vogel rxr->next_check = 0; 128661ae650dSJack F Vogel rxr->next_refresh = 0; 128761ae650dSJack F Vogel rxr->lro_enabled = FALSE; 128861ae650dSJack F Vogel rxr->split = 0; 128961ae650dSJack F Vogel rxr->bytes = 0; 129061ae650dSJack F Vogel rxr->discard = FALSE; 129161ae650dSJack F Vogel 1292e5100ee2SJack F Vogel wr32(vsi->hw, rxr->tail, que->num_desc - 1); 1293e5100ee2SJack F Vogel ixl_flush(vsi->hw); 1294e5100ee2SJack F Vogel 1295b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET) 129661ae650dSJack F Vogel /* 129761ae650dSJack F Vogel ** Now set up the LRO interface: 129861ae650dSJack F Vogel */ 129961ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_LRO) { 130061ae650dSJack F Vogel int err = tcp_lro_init(lro); 130161ae650dSJack F Vogel if (err) { 130261ae650dSJack F Vogel if_printf(ifp, "queue %d: LRO Initialization failed!\n", que->me); 130361ae650dSJack F Vogel goto fail; 130461ae650dSJack F Vogel } 130561ae650dSJack F Vogel INIT_DBG_IF(ifp, "queue %d: RX Soft LRO Initialized", que->me); 130661ae650dSJack F Vogel rxr->lro_enabled = TRUE; 130761ae650dSJack F Vogel lro->ifp = vsi->ifp; 130861ae650dSJack F Vogel } 1309b3f7259bSBjoern A. Zeeb #endif 131061ae650dSJack F Vogel 131161ae650dSJack F Vogel bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, 131261ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 131361ae650dSJack F Vogel 131461ae650dSJack F Vogel fail: 131561ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 131661ae650dSJack F Vogel return (error); 131761ae650dSJack F Vogel } 131861ae650dSJack F Vogel 131961ae650dSJack F Vogel 132061ae650dSJack F Vogel /********************************************************************* 132161ae650dSJack F Vogel * 132261ae650dSJack F Vogel * Free station receive ring data structures 132361ae650dSJack F Vogel * 132461ae650dSJack F Vogel **********************************************************************/ 132561ae650dSJack F Vogel void 132661ae650dSJack F Vogel ixl_free_que_rx(struct ixl_queue *que) 132761ae650dSJack F Vogel { 132861ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 132961ae650dSJack F Vogel struct ixl_rx_buf *buf; 133061ae650dSJack F Vogel 133161ae650dSJack F Vogel INIT_DBG_IF(que->vsi->ifp, "queue %d: begin", que->me); 133261ae650dSJack F Vogel 133361ae650dSJack F Vogel /* Cleanup any existing buffers */ 133461ae650dSJack F Vogel if (rxr->buffers != NULL) { 133561ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++) { 133661ae650dSJack F Vogel buf = &rxr->buffers[i]; 133761ae650dSJack F Vogel if (buf->m_head != NULL) { 133861ae650dSJack F Vogel bus_dmamap_sync(rxr->htag, buf->hmap, 133961ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 134061ae650dSJack F Vogel bus_dmamap_unload(rxr->htag, buf->hmap); 134161ae650dSJack F Vogel buf->m_head->m_flags |= M_PKTHDR; 134261ae650dSJack F Vogel m_freem(buf->m_head); 134361ae650dSJack F Vogel } 134461ae650dSJack F Vogel if (buf->m_pack != NULL) { 134561ae650dSJack F Vogel bus_dmamap_sync(rxr->ptag, buf->pmap, 134661ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 134761ae650dSJack F Vogel bus_dmamap_unload(rxr->ptag, buf->pmap); 134861ae650dSJack F Vogel buf->m_pack->m_flags |= M_PKTHDR; 134961ae650dSJack F Vogel m_freem(buf->m_pack); 135061ae650dSJack F Vogel } 135161ae650dSJack F Vogel buf->m_head = NULL; 135261ae650dSJack F Vogel buf->m_pack = NULL; 135361ae650dSJack F Vogel if (buf->hmap != NULL) { 135461ae650dSJack F Vogel bus_dmamap_destroy(rxr->htag, buf->hmap); 135561ae650dSJack F Vogel buf->hmap = NULL; 135661ae650dSJack F Vogel } 135761ae650dSJack F Vogel if (buf->pmap != NULL) { 135861ae650dSJack F Vogel bus_dmamap_destroy(rxr->ptag, buf->pmap); 135961ae650dSJack F Vogel buf->pmap = NULL; 136061ae650dSJack F Vogel } 136161ae650dSJack F Vogel } 136261ae650dSJack F Vogel if (rxr->buffers != NULL) { 136361ae650dSJack F Vogel free(rxr->buffers, M_DEVBUF); 136461ae650dSJack F Vogel rxr->buffers = NULL; 136561ae650dSJack F Vogel } 136661ae650dSJack F Vogel } 136761ae650dSJack F Vogel 136861ae650dSJack F Vogel if (rxr->htag != NULL) { 136961ae650dSJack F Vogel bus_dma_tag_destroy(rxr->htag); 137061ae650dSJack F Vogel rxr->htag = NULL; 137161ae650dSJack F Vogel } 137261ae650dSJack F Vogel if (rxr->ptag != NULL) { 137361ae650dSJack F Vogel bus_dma_tag_destroy(rxr->ptag); 137461ae650dSJack F Vogel rxr->ptag = NULL; 137561ae650dSJack F Vogel } 137661ae650dSJack F Vogel 137761ae650dSJack F Vogel INIT_DBG_IF(que->vsi->ifp, "queue %d: end", que->me); 137861ae650dSJack F Vogel return; 137961ae650dSJack F Vogel } 138061ae650dSJack F Vogel 13814294f337SSean Bruno static inline void 138261ae650dSJack F Vogel ixl_rx_input(struct rx_ring *rxr, struct ifnet *ifp, struct mbuf *m, u8 ptype) 138361ae650dSJack F Vogel { 1384b3f7259bSBjoern A. Zeeb 1385b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET) 138661ae650dSJack F Vogel /* 138761ae650dSJack F Vogel * ATM LRO is only for IPv4/TCP packets and TCP checksum of the packet 138861ae650dSJack F Vogel * should be computed by hardware. Also it should not have VLAN tag in 138961ae650dSJack F Vogel * ethernet header. 139061ae650dSJack F Vogel */ 139161ae650dSJack F Vogel if (rxr->lro_enabled && 139261ae650dSJack F Vogel (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && 139361ae650dSJack F Vogel (m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == 139461ae650dSJack F Vogel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) { 139561ae650dSJack F Vogel /* 139661ae650dSJack F Vogel * Send to the stack if: 139761ae650dSJack F Vogel ** - LRO not enabled, or 139861ae650dSJack F Vogel ** - no LRO resources, or 139961ae650dSJack F Vogel ** - lro enqueue fails 140061ae650dSJack F Vogel */ 140161ae650dSJack F Vogel if (rxr->lro.lro_cnt != 0) 140261ae650dSJack F Vogel if (tcp_lro_rx(&rxr->lro, m, 0) == 0) 140361ae650dSJack F Vogel return; 140461ae650dSJack F Vogel } 1405b3f7259bSBjoern A. Zeeb #endif 140661ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 140761ae650dSJack F Vogel (*ifp->if_input)(ifp, m); 140861ae650dSJack F Vogel IXL_RX_LOCK(rxr); 140961ae650dSJack F Vogel } 141061ae650dSJack F Vogel 141161ae650dSJack F Vogel 14124294f337SSean Bruno static inline void 141361ae650dSJack F Vogel ixl_rx_discard(struct rx_ring *rxr, int i) 141461ae650dSJack F Vogel { 141561ae650dSJack F Vogel struct ixl_rx_buf *rbuf; 141661ae650dSJack F Vogel 141761ae650dSJack F Vogel rbuf = &rxr->buffers[i]; 141861ae650dSJack F Vogel 141961ae650dSJack F Vogel if (rbuf->fmp != NULL) {/* Partial chain ? */ 142061ae650dSJack F Vogel rbuf->fmp->m_flags |= M_PKTHDR; 142161ae650dSJack F Vogel m_freem(rbuf->fmp); 142261ae650dSJack F Vogel rbuf->fmp = NULL; 142361ae650dSJack F Vogel } 142461ae650dSJack F Vogel 142561ae650dSJack F Vogel /* 142661ae650dSJack F Vogel ** With advanced descriptors the writeback 142761ae650dSJack F Vogel ** clobbers the buffer addrs, so its easier 142861ae650dSJack F Vogel ** to just free the existing mbufs and take 142961ae650dSJack F Vogel ** the normal refresh path to get new buffers 143061ae650dSJack F Vogel ** and mapping. 143161ae650dSJack F Vogel */ 143261ae650dSJack F Vogel if (rbuf->m_head) { 143361ae650dSJack F Vogel m_free(rbuf->m_head); 143461ae650dSJack F Vogel rbuf->m_head = NULL; 143561ae650dSJack F Vogel } 143661ae650dSJack F Vogel 143761ae650dSJack F Vogel if (rbuf->m_pack) { 143861ae650dSJack F Vogel m_free(rbuf->m_pack); 143961ae650dSJack F Vogel rbuf->m_pack = NULL; 144061ae650dSJack F Vogel } 144161ae650dSJack F Vogel 144261ae650dSJack F Vogel return; 144361ae650dSJack F Vogel } 144461ae650dSJack F Vogel 14456b30e6aeSJack F Vogel #ifdef RSS 14466b30e6aeSJack F Vogel /* 1447b6c8f260SJack F Vogel ** i40e_ptype_to_hash: parse the packet type 14486b30e6aeSJack F Vogel ** to determine the appropriate hash. 14496b30e6aeSJack F Vogel */ 14506b30e6aeSJack F Vogel static inline int 14516b30e6aeSJack F Vogel ixl_ptype_to_hash(u8 ptype) 14526b30e6aeSJack F Vogel { 14536b30e6aeSJack F Vogel struct i40e_rx_ptype_decoded decoded; 1454b2bdc62aSAdrian Chadd u8 ex = 0; 14556b30e6aeSJack F Vogel 1456dcd7b3b2SJack F Vogel decoded = decode_rx_desc_ptype(ptype); 14576b30e6aeSJack F Vogel ex = decoded.outer_frag; 14586b30e6aeSJack F Vogel 14596b30e6aeSJack F Vogel if (!decoded.known) 146036ad8372SSepherosa Ziehau return M_HASHTYPE_OPAQUE_HASH; 14616b30e6aeSJack F Vogel 14626b30e6aeSJack F Vogel if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_L2) 146336ad8372SSepherosa Ziehau return M_HASHTYPE_OPAQUE_HASH; 14646b30e6aeSJack F Vogel 14656b30e6aeSJack F Vogel /* Note: anything that gets to this point is IP */ 14666b30e6aeSJack F Vogel if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) { 14676b30e6aeSJack F Vogel switch (decoded.inner_prot) { 14686b30e6aeSJack F Vogel case I40E_RX_PTYPE_INNER_PROT_TCP: 14696b30e6aeSJack F Vogel if (ex) 14706b30e6aeSJack F Vogel return M_HASHTYPE_RSS_TCP_IPV6_EX; 14716b30e6aeSJack F Vogel else 14726b30e6aeSJack F Vogel return M_HASHTYPE_RSS_TCP_IPV6; 14736b30e6aeSJack F Vogel case I40E_RX_PTYPE_INNER_PROT_UDP: 14746b30e6aeSJack F Vogel if (ex) 14756b30e6aeSJack F Vogel return M_HASHTYPE_RSS_UDP_IPV6_EX; 14766b30e6aeSJack F Vogel else 14776b30e6aeSJack F Vogel return M_HASHTYPE_RSS_UDP_IPV6; 14786b30e6aeSJack F Vogel default: 14796b30e6aeSJack F Vogel if (ex) 14806b30e6aeSJack F Vogel return M_HASHTYPE_RSS_IPV6_EX; 14816b30e6aeSJack F Vogel else 14826b30e6aeSJack F Vogel return M_HASHTYPE_RSS_IPV6; 14836b30e6aeSJack F Vogel } 14846b30e6aeSJack F Vogel } 14856b30e6aeSJack F Vogel if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4) { 14866b30e6aeSJack F Vogel switch (decoded.inner_prot) { 14876b30e6aeSJack F Vogel case I40E_RX_PTYPE_INNER_PROT_TCP: 14886b30e6aeSJack F Vogel return M_HASHTYPE_RSS_TCP_IPV4; 14896b30e6aeSJack F Vogel case I40E_RX_PTYPE_INNER_PROT_UDP: 14906b30e6aeSJack F Vogel if (ex) 14916b30e6aeSJack F Vogel return M_HASHTYPE_RSS_UDP_IPV4_EX; 14926b30e6aeSJack F Vogel else 14936b30e6aeSJack F Vogel return M_HASHTYPE_RSS_UDP_IPV4; 14946b30e6aeSJack F Vogel default: 14956b30e6aeSJack F Vogel return M_HASHTYPE_RSS_IPV4; 14966b30e6aeSJack F Vogel } 14976b30e6aeSJack F Vogel } 14986b30e6aeSJack F Vogel /* We should never get here!! */ 149936ad8372SSepherosa Ziehau return M_HASHTYPE_OPAQUE_HASH; 15006b30e6aeSJack F Vogel } 15016b30e6aeSJack F Vogel #endif /* RSS */ 150261ae650dSJack F Vogel 150361ae650dSJack F Vogel /********************************************************************* 150461ae650dSJack F Vogel * 150561ae650dSJack F Vogel * This routine executes in interrupt context. It replenishes 150661ae650dSJack F Vogel * the mbufs in the descriptor and sends data which has been 150761ae650dSJack F Vogel * dma'ed into host memory to upper layer. 150861ae650dSJack F Vogel * 150961ae650dSJack F Vogel * We loop at most count times if count is > 0, or until done if 151061ae650dSJack F Vogel * count < 0. 151161ae650dSJack F Vogel * 151261ae650dSJack F Vogel * Return TRUE for more work, FALSE for all clean. 151361ae650dSJack F Vogel *********************************************************************/ 151461ae650dSJack F Vogel bool 151561ae650dSJack F Vogel ixl_rxeof(struct ixl_queue *que, int count) 151661ae650dSJack F Vogel { 151761ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 151861ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 151961ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 1520b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET) 152161ae650dSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 1522b3f7259bSBjoern A. Zeeb #endif 152361ae650dSJack F Vogel int i, nextp, processed = 0; 152461ae650dSJack F Vogel union i40e_rx_desc *cur; 152561ae650dSJack F Vogel struct ixl_rx_buf *rbuf, *nbuf; 152661ae650dSJack F Vogel 152761ae650dSJack F Vogel 152861ae650dSJack F Vogel IXL_RX_LOCK(rxr); 152961ae650dSJack F Vogel 153031830672SJack F Vogel #ifdef DEV_NETMAP 153131830672SJack F Vogel if (netmap_rx_irq(ifp, que->me, &count)) { 153231830672SJack F Vogel IXL_RX_UNLOCK(rxr); 153331830672SJack F Vogel return (FALSE); 153431830672SJack F Vogel } 153531830672SJack F Vogel #endif /* DEV_NETMAP */ 1536e5100ee2SJack F Vogel 153761ae650dSJack F Vogel for (i = rxr->next_check; count != 0;) { 153861ae650dSJack F Vogel struct mbuf *sendmp, *mh, *mp; 15394294f337SSean Bruno u32 status, error; 154061ae650dSJack F Vogel u16 hlen, plen, vtag; 154161ae650dSJack F Vogel u64 qword; 154261ae650dSJack F Vogel u8 ptype; 154361ae650dSJack F Vogel bool eop; 154461ae650dSJack F Vogel 154561ae650dSJack F Vogel /* Sync the ring. */ 154661ae650dSJack F Vogel bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, 154761ae650dSJack F Vogel BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 154861ae650dSJack F Vogel 154961ae650dSJack F Vogel cur = &rxr->base[i]; 155061ae650dSJack F Vogel qword = le64toh(cur->wb.qword1.status_error_len); 155161ae650dSJack F Vogel status = (qword & I40E_RXD_QW1_STATUS_MASK) 155261ae650dSJack F Vogel >> I40E_RXD_QW1_STATUS_SHIFT; 155361ae650dSJack F Vogel error = (qword & I40E_RXD_QW1_ERROR_MASK) 155461ae650dSJack F Vogel >> I40E_RXD_QW1_ERROR_SHIFT; 155561ae650dSJack F Vogel plen = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) 155661ae650dSJack F Vogel >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT; 155761ae650dSJack F Vogel hlen = (qword & I40E_RXD_QW1_LENGTH_HBUF_MASK) 155861ae650dSJack F Vogel >> I40E_RXD_QW1_LENGTH_HBUF_SHIFT; 155961ae650dSJack F Vogel ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) 156061ae650dSJack F Vogel >> I40E_RXD_QW1_PTYPE_SHIFT; 156161ae650dSJack F Vogel 156261ae650dSJack F Vogel if ((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) == 0) { 156361ae650dSJack F Vogel ++rxr->not_done; 156461ae650dSJack F Vogel break; 156561ae650dSJack F Vogel } 156661ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 156761ae650dSJack F Vogel break; 156861ae650dSJack F Vogel 156961ae650dSJack F Vogel count--; 157061ae650dSJack F Vogel sendmp = NULL; 157161ae650dSJack F Vogel nbuf = NULL; 157261ae650dSJack F Vogel cur->wb.qword1.status_error_len = 0; 157361ae650dSJack F Vogel rbuf = &rxr->buffers[i]; 157461ae650dSJack F Vogel mh = rbuf->m_head; 157561ae650dSJack F Vogel mp = rbuf->m_pack; 157661ae650dSJack F Vogel eop = (status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)); 157761ae650dSJack F Vogel if (status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) 157861ae650dSJack F Vogel vtag = le16toh(cur->wb.qword0.lo_dword.l2tag1); 157961ae650dSJack F Vogel else 158061ae650dSJack F Vogel vtag = 0; 158161ae650dSJack F Vogel 158261ae650dSJack F Vogel /* 158361ae650dSJack F Vogel ** Make sure bad packets are discarded, 158461ae650dSJack F Vogel ** note that only EOP descriptor has valid 158561ae650dSJack F Vogel ** error results. 158661ae650dSJack F Vogel */ 158761ae650dSJack F Vogel if (eop && (error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { 15886d011ad5SEric Joyner rxr->desc_errs++; 158961ae650dSJack F Vogel ixl_rx_discard(rxr, i); 159061ae650dSJack F Vogel goto next_desc; 159161ae650dSJack F Vogel } 159261ae650dSJack F Vogel 159361ae650dSJack F Vogel /* Prefetch the next buffer */ 159461ae650dSJack F Vogel if (!eop) { 159561ae650dSJack F Vogel nextp = i + 1; 159661ae650dSJack F Vogel if (nextp == que->num_desc) 159761ae650dSJack F Vogel nextp = 0; 159861ae650dSJack F Vogel nbuf = &rxr->buffers[nextp]; 159961ae650dSJack F Vogel prefetch(nbuf); 160061ae650dSJack F Vogel } 160161ae650dSJack F Vogel 160261ae650dSJack F Vogel /* 160361ae650dSJack F Vogel ** The header mbuf is ONLY used when header 160461ae650dSJack F Vogel ** split is enabled, otherwise we get normal 160561ae650dSJack F Vogel ** behavior, ie, both header and payload 160661ae650dSJack F Vogel ** are DMA'd into the payload buffer. 160761ae650dSJack F Vogel ** 160861ae650dSJack F Vogel ** Rather than using the fmp/lmp global pointers 160961ae650dSJack F Vogel ** we now keep the head of a packet chain in the 161061ae650dSJack F Vogel ** buffer struct and pass this along from one 161161ae650dSJack F Vogel ** descriptor to the next, until we get EOP. 161261ae650dSJack F Vogel */ 161361ae650dSJack F Vogel if (rxr->hdr_split && (rbuf->fmp == NULL)) { 161461ae650dSJack F Vogel if (hlen > IXL_RX_HDR) 161561ae650dSJack F Vogel hlen = IXL_RX_HDR; 161661ae650dSJack F Vogel mh->m_len = hlen; 161761ae650dSJack F Vogel mh->m_flags |= M_PKTHDR; 161861ae650dSJack F Vogel mh->m_next = NULL; 161961ae650dSJack F Vogel mh->m_pkthdr.len = mh->m_len; 162061ae650dSJack F Vogel /* Null buf pointer so it is refreshed */ 162161ae650dSJack F Vogel rbuf->m_head = NULL; 162261ae650dSJack F Vogel /* 162361ae650dSJack F Vogel ** Check the payload length, this 162461ae650dSJack F Vogel ** could be zero if its a small 162561ae650dSJack F Vogel ** packet. 162661ae650dSJack F Vogel */ 162761ae650dSJack F Vogel if (plen > 0) { 162861ae650dSJack F Vogel mp->m_len = plen; 162961ae650dSJack F Vogel mp->m_next = NULL; 163061ae650dSJack F Vogel mp->m_flags &= ~M_PKTHDR; 163161ae650dSJack F Vogel mh->m_next = mp; 163261ae650dSJack F Vogel mh->m_pkthdr.len += mp->m_len; 163361ae650dSJack F Vogel /* Null buf pointer so it is refreshed */ 163461ae650dSJack F Vogel rbuf->m_pack = NULL; 163561ae650dSJack F Vogel rxr->split++; 163661ae650dSJack F Vogel } 163761ae650dSJack F Vogel /* 163861ae650dSJack F Vogel ** Now create the forward 163961ae650dSJack F Vogel ** chain so when complete 164061ae650dSJack F Vogel ** we wont have to. 164161ae650dSJack F Vogel */ 164261ae650dSJack F Vogel if (eop == 0) { 164361ae650dSJack F Vogel /* stash the chain head */ 164461ae650dSJack F Vogel nbuf->fmp = mh; 164561ae650dSJack F Vogel /* Make forward chain */ 164661ae650dSJack F Vogel if (plen) 164761ae650dSJack F Vogel mp->m_next = nbuf->m_pack; 164861ae650dSJack F Vogel else 164961ae650dSJack F Vogel mh->m_next = nbuf->m_pack; 165061ae650dSJack F Vogel } else { 165161ae650dSJack F Vogel /* Singlet, prepare to send */ 165261ae650dSJack F Vogel sendmp = mh; 165361ae650dSJack F Vogel if (vtag) { 165461ae650dSJack F Vogel sendmp->m_pkthdr.ether_vtag = vtag; 165561ae650dSJack F Vogel sendmp->m_flags |= M_VLANTAG; 165661ae650dSJack F Vogel } 165761ae650dSJack F Vogel } 165861ae650dSJack F Vogel } else { 165961ae650dSJack F Vogel /* 166061ae650dSJack F Vogel ** Either no header split, or a 166161ae650dSJack F Vogel ** secondary piece of a fragmented 166261ae650dSJack F Vogel ** split packet. 166361ae650dSJack F Vogel */ 166461ae650dSJack F Vogel mp->m_len = plen; 166561ae650dSJack F Vogel /* 166661ae650dSJack F Vogel ** See if there is a stored head 166761ae650dSJack F Vogel ** that determines what we are 166861ae650dSJack F Vogel */ 166961ae650dSJack F Vogel sendmp = rbuf->fmp; 167061ae650dSJack F Vogel rbuf->m_pack = rbuf->fmp = NULL; 167161ae650dSJack F Vogel 167261ae650dSJack F Vogel if (sendmp != NULL) /* secondary frag */ 167361ae650dSJack F Vogel sendmp->m_pkthdr.len += mp->m_len; 167461ae650dSJack F Vogel else { 167561ae650dSJack F Vogel /* first desc of a non-ps chain */ 167661ae650dSJack F Vogel sendmp = mp; 167761ae650dSJack F Vogel sendmp->m_flags |= M_PKTHDR; 167861ae650dSJack F Vogel sendmp->m_pkthdr.len = mp->m_len; 167961ae650dSJack F Vogel } 168061ae650dSJack F Vogel /* Pass the head pointer on */ 168161ae650dSJack F Vogel if (eop == 0) { 168261ae650dSJack F Vogel nbuf->fmp = sendmp; 168361ae650dSJack F Vogel sendmp = NULL; 168461ae650dSJack F Vogel mp->m_next = nbuf->m_pack; 168561ae650dSJack F Vogel } 168661ae650dSJack F Vogel } 168761ae650dSJack F Vogel ++processed; 168861ae650dSJack F Vogel /* Sending this frame? */ 168961ae650dSJack F Vogel if (eop) { 169061ae650dSJack F Vogel sendmp->m_pkthdr.rcvif = ifp; 169161ae650dSJack F Vogel /* gather stats */ 169261ae650dSJack F Vogel rxr->rx_packets++; 169361ae650dSJack F Vogel rxr->rx_bytes += sendmp->m_pkthdr.len; 169461ae650dSJack F Vogel /* capture data for dynamic ITR adjustment */ 169561ae650dSJack F Vogel rxr->packets++; 169661ae650dSJack F Vogel rxr->bytes += sendmp->m_pkthdr.len; 16974294f337SSean Bruno /* Set VLAN tag (field only valid in eop desc) */ 16984294f337SSean Bruno if (vtag) { 16994294f337SSean Bruno sendmp->m_pkthdr.ether_vtag = vtag; 17004294f337SSean Bruno sendmp->m_flags |= M_VLANTAG; 17014294f337SSean Bruno } 170261ae650dSJack F Vogel if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 170361ae650dSJack F Vogel ixl_rx_checksum(sendmp, status, error, ptype); 1704845a028fSJack F Vogel #ifdef RSS 17056b30e6aeSJack F Vogel sendmp->m_pkthdr.flowid = 17066b30e6aeSJack F Vogel le32toh(cur->wb.qword0.hi_dword.rss); 17076b30e6aeSJack F Vogel M_HASHTYPE_SET(sendmp, ixl_ptype_to_hash(ptype)); 17086b30e6aeSJack F Vogel #else 170961ae650dSJack F Vogel sendmp->m_pkthdr.flowid = que->msix; 1710845a028fSJack F Vogel M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE); 17116b30e6aeSJack F Vogel #endif 171261ae650dSJack F Vogel } 171361ae650dSJack F Vogel next_desc: 171461ae650dSJack F Vogel bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, 171561ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 171661ae650dSJack F Vogel 171761ae650dSJack F Vogel /* Advance our pointers to the next descriptor. */ 171861ae650dSJack F Vogel if (++i == que->num_desc) 171961ae650dSJack F Vogel i = 0; 172061ae650dSJack F Vogel 172161ae650dSJack F Vogel /* Now send to the stack or do LRO */ 172261ae650dSJack F Vogel if (sendmp != NULL) { 172361ae650dSJack F Vogel rxr->next_check = i; 172461ae650dSJack F Vogel ixl_rx_input(rxr, ifp, sendmp, ptype); 172561ae650dSJack F Vogel i = rxr->next_check; 172661ae650dSJack F Vogel } 172761ae650dSJack F Vogel 172861ae650dSJack F Vogel /* Every 8 descriptors we go to refresh mbufs */ 172961ae650dSJack F Vogel if (processed == 8) { 173061ae650dSJack F Vogel ixl_refresh_mbufs(que, i); 173161ae650dSJack F Vogel processed = 0; 173261ae650dSJack F Vogel } 173361ae650dSJack F Vogel } 173461ae650dSJack F Vogel 173561ae650dSJack F Vogel /* Refresh any remaining buf structs */ 173661ae650dSJack F Vogel if (ixl_rx_unrefreshed(que)) 173761ae650dSJack F Vogel ixl_refresh_mbufs(que, i); 173861ae650dSJack F Vogel 173961ae650dSJack F Vogel rxr->next_check = i; 174061ae650dSJack F Vogel 1741b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET) 174261ae650dSJack F Vogel /* 174361ae650dSJack F Vogel * Flush any outstanding LRO work 174461ae650dSJack F Vogel */ 1745*cb6b8299SEric Joyner #if __FreeBSD_version >= 1100105 17466dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro); 1747*cb6b8299SEric Joyner #else 1748*cb6b8299SEric Joyner struct lro_entry *queued; 1749*cb6b8299SEric Joyner while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { 1750*cb6b8299SEric Joyner SLIST_REMOVE_HEAD(&lro->lro_active, next); 1751*cb6b8299SEric Joyner tcp_lro_flush(lro, queued); 1752*cb6b8299SEric Joyner } 1753b3f7259bSBjoern A. Zeeb #endif 1754*cb6b8299SEric Joyner #endif /* defined(INET6) || defined(INET) */ 175561ae650dSJack F Vogel 175661ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 175761ae650dSJack F Vogel return (FALSE); 175861ae650dSJack F Vogel } 175961ae650dSJack F Vogel 176061ae650dSJack F Vogel 176161ae650dSJack F Vogel /********************************************************************* 176261ae650dSJack F Vogel * 176361ae650dSJack F Vogel * Verify that the hardware indicated that the checksum is valid. 176461ae650dSJack F Vogel * Inform the stack about the status of checksum so that stack 176561ae650dSJack F Vogel * doesn't spend time verifying the checksum. 176661ae650dSJack F Vogel * 176761ae650dSJack F Vogel *********************************************************************/ 176861ae650dSJack F Vogel static void 176961ae650dSJack F Vogel ixl_rx_checksum(struct mbuf * mp, u32 status, u32 error, u8 ptype) 177061ae650dSJack F Vogel { 177161ae650dSJack F Vogel struct i40e_rx_ptype_decoded decoded; 177261ae650dSJack F Vogel 177361ae650dSJack F Vogel decoded = decode_rx_desc_ptype(ptype); 177461ae650dSJack F Vogel 177561ae650dSJack F Vogel /* Errors? */ 177661ae650dSJack F Vogel if (error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | 177761ae650dSJack F Vogel (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))) { 177861ae650dSJack F Vogel mp->m_pkthdr.csum_flags = 0; 177961ae650dSJack F Vogel return; 178061ae650dSJack F Vogel } 178161ae650dSJack F Vogel 178261ae650dSJack F Vogel /* IPv6 with extension headers likely have bad csum */ 178361ae650dSJack F Vogel if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && 178461ae650dSJack F Vogel decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) 178561ae650dSJack F Vogel if (status & 178661ae650dSJack F Vogel (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) { 178761ae650dSJack F Vogel mp->m_pkthdr.csum_flags = 0; 178861ae650dSJack F Vogel return; 178961ae650dSJack F Vogel } 179061ae650dSJack F Vogel 179161ae650dSJack F Vogel 179261ae650dSJack F Vogel /* IP Checksum Good */ 179361ae650dSJack F Vogel mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; 179461ae650dSJack F Vogel mp->m_pkthdr.csum_flags |= CSUM_IP_VALID; 179561ae650dSJack F Vogel 179661ae650dSJack F Vogel if (status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)) { 179761ae650dSJack F Vogel mp->m_pkthdr.csum_flags |= 179861ae650dSJack F Vogel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 179961ae650dSJack F Vogel mp->m_pkthdr.csum_data |= htons(0xffff); 180061ae650dSJack F Vogel } 180161ae650dSJack F Vogel return; 180261ae650dSJack F Vogel } 18034b443922SGleb Smirnoff 18044b443922SGleb Smirnoff #if __FreeBSD_version >= 1100000 18054b443922SGleb Smirnoff uint64_t 18064b443922SGleb Smirnoff ixl_get_counter(if_t ifp, ift_counter cnt) 18074b443922SGleb Smirnoff { 18084b443922SGleb Smirnoff struct ixl_vsi *vsi; 18094b443922SGleb Smirnoff 18104b443922SGleb Smirnoff vsi = if_getsoftc(ifp); 18114b443922SGleb Smirnoff 18124b443922SGleb Smirnoff switch (cnt) { 18134b443922SGleb Smirnoff case IFCOUNTER_IPACKETS: 18144b443922SGleb Smirnoff return (vsi->ipackets); 18154b443922SGleb Smirnoff case IFCOUNTER_IERRORS: 18164b443922SGleb Smirnoff return (vsi->ierrors); 18174b443922SGleb Smirnoff case IFCOUNTER_OPACKETS: 18184b443922SGleb Smirnoff return (vsi->opackets); 18194b443922SGleb Smirnoff case IFCOUNTER_OERRORS: 18204b443922SGleb Smirnoff return (vsi->oerrors); 18214b443922SGleb Smirnoff case IFCOUNTER_COLLISIONS: 18224b443922SGleb Smirnoff /* Collisions are by standard impossible in 40G/10G Ethernet */ 18234b443922SGleb Smirnoff return (0); 18244b443922SGleb Smirnoff case IFCOUNTER_IBYTES: 18254b443922SGleb Smirnoff return (vsi->ibytes); 18264b443922SGleb Smirnoff case IFCOUNTER_OBYTES: 18274b443922SGleb Smirnoff return (vsi->obytes); 18284b443922SGleb Smirnoff case IFCOUNTER_IMCASTS: 18294b443922SGleb Smirnoff return (vsi->imcasts); 18304b443922SGleb Smirnoff case IFCOUNTER_OMCASTS: 18314b443922SGleb Smirnoff return (vsi->omcasts); 18324b443922SGleb Smirnoff case IFCOUNTER_IQDROPS: 18334b443922SGleb Smirnoff return (vsi->iqdrops); 18344b443922SGleb Smirnoff case IFCOUNTER_OQDROPS: 18354b443922SGleb Smirnoff return (vsi->oqdrops); 18364b443922SGleb Smirnoff case IFCOUNTER_NOPROTO: 18374b443922SGleb Smirnoff return (vsi->noproto); 18384b443922SGleb Smirnoff default: 18394b443922SGleb Smirnoff return (if_get_counter_default(ifp, cnt)); 18404b443922SGleb Smirnoff } 18414b443922SGleb Smirnoff } 18424b443922SGleb Smirnoff #endif 1843e5100ee2SJack F Vogel 1844