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 3861ae650dSJack F Vogel ** both the BASE and the 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 6161ae650dSJack F Vogel static __inline void ixl_rx_discard(struct rx_ring *, int); 6261ae650dSJack F Vogel static __inline void ixl_rx_input(struct rx_ring *, struct ifnet *, 6361ae650dSJack F Vogel struct mbuf *, u8); 6461ae650dSJack F Vogel 65bc8b78d3SLuigi Rizzo 6661ae650dSJack F Vogel /* 6761ae650dSJack F Vogel ** Multiqueue Transmit driver 6861ae650dSJack F Vogel */ 6961ae650dSJack F Vogel int 7061ae650dSJack F Vogel ixl_mq_start(struct ifnet *ifp, struct mbuf *m) 7161ae650dSJack F Vogel { 7261ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 7361ae650dSJack F Vogel struct ixl_queue *que; 7461ae650dSJack F Vogel struct tx_ring *txr; 7561ae650dSJack F Vogel int err, i; 76845a028fSJack F Vogel #ifdef RSS 77845a028fSJack F Vogel u32 bucket_id; 78845a028fSJack F Vogel #endif 7961ae650dSJack F Vogel 80845a028fSJack F Vogel /* 81845a028fSJack F Vogel ** Which queue to use: 82845a028fSJack F Vogel ** 83845a028fSJack F Vogel ** When doing RSS, map it to the same outbound 84845a028fSJack F Vogel ** queue as the incoming flow would be mapped to. 85845a028fSJack F Vogel ** If everything is setup correctly, it should be 86845a028fSJack F Vogel ** the same bucket that the current CPU we're on is. 87845a028fSJack F Vogel */ 88845a028fSJack F Vogel if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 89845a028fSJack F Vogel #ifdef RSS 90845a028fSJack F Vogel if (rss_hash2bucket(m->m_pkthdr.flowid, 91845a028fSJack F Vogel M_HASHTYPE_GET(m), &bucket_id) == 0) { 92845a028fSJack F Vogel i = bucket_id % vsi->num_queues; 93845a028fSJack F Vogel } else 94845a028fSJack F Vogel #endif 9561ae650dSJack F Vogel i = m->m_pkthdr.flowid % vsi->num_queues; 96845a028fSJack F Vogel } else 9761ae650dSJack F Vogel i = curcpu % vsi->num_queues; 98845a028fSJack F Vogel /* 99845a028fSJack F Vogel ** This may not be perfect, but until something 100845a028fSJack F Vogel ** better comes along it will keep from scheduling 101845a028fSJack F Vogel ** on stalled queues. 102845a028fSJack F Vogel */ 10361ae650dSJack F Vogel if (((1 << i) & vsi->active_queues) == 0) 10461ae650dSJack F Vogel i = ffsl(vsi->active_queues); 10561ae650dSJack F Vogel 10661ae650dSJack F Vogel que = &vsi->queues[i]; 10761ae650dSJack F Vogel txr = &que->txr; 10861ae650dSJack F Vogel 10961ae650dSJack F Vogel err = drbr_enqueue(ifp, txr->br, m); 11061ae650dSJack F Vogel if (err) 11161ae650dSJack F Vogel return (err); 11261ae650dSJack F Vogel if (IXL_TX_TRYLOCK(txr)) { 11361ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 11461ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 11561ae650dSJack F Vogel } else 11661ae650dSJack F Vogel taskqueue_enqueue(que->tq, &que->tx_task); 11761ae650dSJack F Vogel 11861ae650dSJack F Vogel return (0); 11961ae650dSJack F Vogel } 12061ae650dSJack F Vogel 12161ae650dSJack F Vogel int 12261ae650dSJack F Vogel ixl_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr) 12361ae650dSJack F Vogel { 12461ae650dSJack F Vogel struct ixl_queue *que = txr->que; 12561ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 12661ae650dSJack F Vogel struct mbuf *next; 12761ae650dSJack F Vogel int err = 0; 12861ae650dSJack F Vogel 12961ae650dSJack F Vogel 13061ae650dSJack F Vogel if (((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) || 13161ae650dSJack F Vogel vsi->link_active == 0) 13261ae650dSJack F Vogel return (ENETDOWN); 13361ae650dSJack F Vogel 13461ae650dSJack F Vogel /* Process the transmit queue */ 13561ae650dSJack F Vogel while ((next = drbr_peek(ifp, txr->br)) != NULL) { 13661ae650dSJack F Vogel if ((err = ixl_xmit(que, &next)) != 0) { 13761ae650dSJack F Vogel if (next == NULL) 13861ae650dSJack F Vogel drbr_advance(ifp, txr->br); 13961ae650dSJack F Vogel else 14061ae650dSJack F Vogel drbr_putback(ifp, txr->br, next); 14161ae650dSJack F Vogel break; 14261ae650dSJack F Vogel } 14361ae650dSJack F Vogel drbr_advance(ifp, txr->br); 14461ae650dSJack F Vogel /* Send a copy of the frame to the BPF listener */ 14561ae650dSJack F Vogel ETHER_BPF_MTAP(ifp, next); 14661ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 14761ae650dSJack F Vogel break; 14861ae650dSJack F Vogel } 14961ae650dSJack F Vogel 15061ae650dSJack F Vogel if (txr->avail < IXL_TX_CLEANUP_THRESHOLD) 15161ae650dSJack F Vogel ixl_txeof(que); 15261ae650dSJack F Vogel 15361ae650dSJack F Vogel return (err); 15461ae650dSJack F Vogel } 15561ae650dSJack F Vogel 15661ae650dSJack F Vogel /* 15761ae650dSJack F Vogel * Called from a taskqueue to drain queued transmit packets. 15861ae650dSJack F Vogel */ 15961ae650dSJack F Vogel void 16061ae650dSJack F Vogel ixl_deferred_mq_start(void *arg, int pending) 16161ae650dSJack F Vogel { 16261ae650dSJack F Vogel struct ixl_queue *que = arg; 16361ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 16461ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 16561ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 16661ae650dSJack F Vogel 16761ae650dSJack F Vogel IXL_TX_LOCK(txr); 16861ae650dSJack F Vogel if (!drbr_empty(ifp, txr->br)) 16961ae650dSJack F Vogel ixl_mq_start_locked(ifp, txr); 17061ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 17161ae650dSJack F Vogel } 17261ae650dSJack F Vogel 17361ae650dSJack F Vogel /* 17461ae650dSJack F Vogel ** Flush all queue ring buffers 17561ae650dSJack F Vogel */ 17661ae650dSJack F Vogel void 17761ae650dSJack F Vogel ixl_qflush(struct ifnet *ifp) 17861ae650dSJack F Vogel { 17961ae650dSJack F Vogel struct ixl_vsi *vsi = ifp->if_softc; 18061ae650dSJack F Vogel 18161ae650dSJack F Vogel for (int i = 0; i < vsi->num_queues; i++) { 18261ae650dSJack F Vogel struct ixl_queue *que = &vsi->queues[i]; 18361ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 18461ae650dSJack F Vogel struct mbuf *m; 18561ae650dSJack F Vogel IXL_TX_LOCK(txr); 18661ae650dSJack F Vogel while ((m = buf_ring_dequeue_sc(txr->br)) != NULL) 18761ae650dSJack F Vogel m_freem(m); 18861ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 18961ae650dSJack F Vogel } 19061ae650dSJack F Vogel if_qflush(ifp); 19161ae650dSJack F Vogel } 19261ae650dSJack F Vogel 19361ae650dSJack F Vogel /* 19461ae650dSJack F Vogel ** Find mbuf chains passed to the driver 19561ae650dSJack F Vogel ** that are 'sparse', using more than 8 19661ae650dSJack F Vogel ** mbufs to deliver an mss-size chunk of data 19761ae650dSJack F Vogel */ 19861ae650dSJack F Vogel static inline bool 19961ae650dSJack F Vogel ixl_tso_detect_sparse(struct mbuf *mp) 20061ae650dSJack F Vogel { 20161ae650dSJack F Vogel struct mbuf *m; 20261ae650dSJack F Vogel int num = 0, mss; 20361ae650dSJack F Vogel bool ret = FALSE; 20461ae650dSJack F Vogel 20561ae650dSJack F Vogel mss = mp->m_pkthdr.tso_segsz; 20661ae650dSJack F Vogel for (m = mp->m_next; m != NULL; m = m->m_next) { 20761ae650dSJack F Vogel num++; 20861ae650dSJack F Vogel mss -= m->m_len; 20961ae650dSJack F Vogel if (mss < 1) 21061ae650dSJack F Vogel break; 21161ae650dSJack F Vogel if (m->m_next == NULL) 21261ae650dSJack F Vogel break; 21361ae650dSJack F Vogel } 21461ae650dSJack F Vogel if (num > IXL_SPARSE_CHAIN) 21561ae650dSJack F Vogel ret = TRUE; 21661ae650dSJack F Vogel 21761ae650dSJack F Vogel return (ret); 21861ae650dSJack F Vogel } 21961ae650dSJack F Vogel 22061ae650dSJack F Vogel 22161ae650dSJack F Vogel /********************************************************************* 22261ae650dSJack F Vogel * 22361ae650dSJack F Vogel * This routine maps the mbufs to tx descriptors, allowing the 22461ae650dSJack F Vogel * TX engine to transmit the packets. 22561ae650dSJack F Vogel * - return 0 on success, positive on failure 22661ae650dSJack F Vogel * 22761ae650dSJack F Vogel **********************************************************************/ 22861ae650dSJack F Vogel #define IXL_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) 22961ae650dSJack F Vogel 23061ae650dSJack F Vogel static int 23161ae650dSJack F Vogel ixl_xmit(struct ixl_queue *que, struct mbuf **m_headp) 23261ae650dSJack F Vogel { 23361ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 23461ae650dSJack F Vogel struct i40e_hw *hw = vsi->hw; 23561ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 23661ae650dSJack F Vogel struct ixl_tx_buf *buf; 23761ae650dSJack F Vogel struct i40e_tx_desc *txd = NULL; 23861ae650dSJack F Vogel struct mbuf *m_head, *m; 23961ae650dSJack F Vogel int i, j, error, nsegs, maxsegs; 24061ae650dSJack F Vogel int first, last = 0; 24161ae650dSJack F Vogel u16 vtag = 0; 24261ae650dSJack F Vogel u32 cmd, off; 24361ae650dSJack F Vogel bus_dmamap_t map; 24461ae650dSJack F Vogel bus_dma_tag_t tag; 24561ae650dSJack F Vogel bus_dma_segment_t segs[IXL_MAX_TSO_SEGS]; 24661ae650dSJack F Vogel 24761ae650dSJack F Vogel 24861ae650dSJack F Vogel cmd = off = 0; 24961ae650dSJack F Vogel m_head = *m_headp; 25061ae650dSJack F Vogel 25161ae650dSJack F Vogel /* 25261ae650dSJack F Vogel * Important to capture the first descriptor 25361ae650dSJack F Vogel * used because it will contain the index of 25461ae650dSJack F Vogel * the one we tell the hardware to report back 25561ae650dSJack F Vogel */ 25661ae650dSJack F Vogel first = txr->next_avail; 25761ae650dSJack F Vogel buf = &txr->buffers[first]; 25861ae650dSJack F Vogel map = buf->map; 25961ae650dSJack F Vogel tag = txr->tx_tag; 26061ae650dSJack F Vogel maxsegs = IXL_MAX_TX_SEGS; 26161ae650dSJack F Vogel 26261ae650dSJack F Vogel if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 26361ae650dSJack F Vogel /* Use larger mapping for TSO */ 26461ae650dSJack F Vogel tag = txr->tso_tag; 26561ae650dSJack F Vogel maxsegs = IXL_MAX_TSO_SEGS; 26661ae650dSJack F Vogel if (ixl_tso_detect_sparse(m_head)) { 26761ae650dSJack F Vogel m = m_defrag(m_head, M_NOWAIT); 268e5100ee2SJack F Vogel if (m == NULL) { 269e5100ee2SJack F Vogel m_freem(*m_headp); 270e5100ee2SJack F Vogel *m_headp = NULL; 271e5100ee2SJack F Vogel return (ENOBUFS); 272e5100ee2SJack F Vogel } 27361ae650dSJack F Vogel *m_headp = m; 27461ae650dSJack F Vogel } 27561ae650dSJack F Vogel } 27661ae650dSJack F Vogel 27761ae650dSJack F Vogel /* 27861ae650dSJack F Vogel * Map the packet for DMA. 27961ae650dSJack F Vogel */ 28061ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(tag, map, 28161ae650dSJack F Vogel *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); 28261ae650dSJack F Vogel 28361ae650dSJack F Vogel if (error == EFBIG) { 28461ae650dSJack F Vogel struct mbuf *m; 28561ae650dSJack F Vogel 28661ae650dSJack F Vogel m = m_collapse(*m_headp, M_NOWAIT, maxsegs); 28761ae650dSJack F Vogel if (m == NULL) { 28861ae650dSJack F Vogel que->mbuf_defrag_failed++; 28961ae650dSJack F Vogel m_freem(*m_headp); 29061ae650dSJack F Vogel *m_headp = NULL; 29161ae650dSJack F Vogel return (ENOBUFS); 29261ae650dSJack F Vogel } 29361ae650dSJack F Vogel *m_headp = m; 29461ae650dSJack F Vogel 29561ae650dSJack F Vogel /* Try it again */ 29661ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(tag, map, 29761ae650dSJack F Vogel *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); 29861ae650dSJack F Vogel 29961ae650dSJack F Vogel if (error == ENOMEM) { 30061ae650dSJack F Vogel que->tx_dma_setup++; 30161ae650dSJack F Vogel return (error); 30261ae650dSJack F Vogel } else if (error != 0) { 30361ae650dSJack F Vogel que->tx_dma_setup++; 30461ae650dSJack F Vogel m_freem(*m_headp); 30561ae650dSJack F Vogel *m_headp = NULL; 30661ae650dSJack F Vogel return (error); 30761ae650dSJack F Vogel } 30861ae650dSJack F Vogel } else if (error == ENOMEM) { 30961ae650dSJack F Vogel que->tx_dma_setup++; 31061ae650dSJack F Vogel return (error); 31161ae650dSJack F Vogel } else if (error != 0) { 31261ae650dSJack F Vogel que->tx_dma_setup++; 31361ae650dSJack F Vogel m_freem(*m_headp); 31461ae650dSJack F Vogel *m_headp = NULL; 31561ae650dSJack F Vogel return (error); 31661ae650dSJack F Vogel } 31761ae650dSJack F Vogel 31861ae650dSJack F Vogel /* Make certain there are enough descriptors */ 31961ae650dSJack F Vogel if (nsegs > txr->avail - 2) { 32061ae650dSJack F Vogel txr->no_desc++; 32161ae650dSJack F Vogel error = ENOBUFS; 32261ae650dSJack F Vogel goto xmit_fail; 32361ae650dSJack F Vogel } 32461ae650dSJack F Vogel m_head = *m_headp; 32561ae650dSJack F Vogel 32661ae650dSJack F Vogel /* Set up the TSO/CSUM offload */ 32761ae650dSJack F Vogel if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) { 32861ae650dSJack F Vogel error = ixl_tx_setup_offload(que, m_head, &cmd, &off); 32961ae650dSJack F Vogel if (error) 33061ae650dSJack F Vogel goto xmit_fail; 33161ae650dSJack F Vogel } 33261ae650dSJack F Vogel 33361ae650dSJack F Vogel cmd |= I40E_TX_DESC_CMD_ICRC; 33461ae650dSJack F Vogel /* Grab the VLAN tag */ 33561ae650dSJack F Vogel if (m_head->m_flags & M_VLANTAG) { 33661ae650dSJack F Vogel cmd |= I40E_TX_DESC_CMD_IL2TAG1; 33761ae650dSJack F Vogel vtag = htole16(m_head->m_pkthdr.ether_vtag); 33861ae650dSJack F Vogel } 33961ae650dSJack F Vogel 34061ae650dSJack F Vogel i = txr->next_avail; 34161ae650dSJack F Vogel for (j = 0; j < nsegs; j++) { 34261ae650dSJack F Vogel bus_size_t seglen; 34361ae650dSJack F Vogel 34461ae650dSJack F Vogel buf = &txr->buffers[i]; 34561ae650dSJack F Vogel buf->tag = tag; /* Keep track of the type tag */ 34661ae650dSJack F Vogel txd = &txr->base[i]; 34761ae650dSJack F Vogel seglen = segs[j].ds_len; 34861ae650dSJack F Vogel 34961ae650dSJack F Vogel txd->buffer_addr = htole64(segs[j].ds_addr); 35061ae650dSJack F Vogel txd->cmd_type_offset_bsz = 35161ae650dSJack F Vogel htole64(I40E_TX_DESC_DTYPE_DATA 35261ae650dSJack F Vogel | ((u64)cmd << I40E_TXD_QW1_CMD_SHIFT) 35361ae650dSJack F Vogel | ((u64)off << I40E_TXD_QW1_OFFSET_SHIFT) 35461ae650dSJack F Vogel | ((u64)seglen << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) 35561ae650dSJack F Vogel | ((u64)vtag << I40E_TXD_QW1_L2TAG1_SHIFT)); 35661ae650dSJack F Vogel 35761ae650dSJack F Vogel last = i; /* descriptor that will get completion IRQ */ 35861ae650dSJack F Vogel 35961ae650dSJack F Vogel if (++i == que->num_desc) 36061ae650dSJack F Vogel i = 0; 36161ae650dSJack F Vogel 36261ae650dSJack F Vogel buf->m_head = NULL; 36361ae650dSJack F Vogel buf->eop_index = -1; 36461ae650dSJack F Vogel } 36561ae650dSJack F Vogel /* Set the last descriptor for report */ 36661ae650dSJack F Vogel txd->cmd_type_offset_bsz |= 36761ae650dSJack F Vogel htole64(((u64)IXL_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT)); 36861ae650dSJack F Vogel txr->avail -= nsegs; 36961ae650dSJack F Vogel txr->next_avail = i; 37061ae650dSJack F Vogel 37161ae650dSJack F Vogel buf->m_head = m_head; 37261ae650dSJack F Vogel /* Swap the dma map between the first and last descriptor */ 37361ae650dSJack F Vogel txr->buffers[first].map = buf->map; 37461ae650dSJack F Vogel buf->map = map; 37561ae650dSJack F Vogel bus_dmamap_sync(tag, map, BUS_DMASYNC_PREWRITE); 37661ae650dSJack F Vogel 37761ae650dSJack F Vogel /* Set the index of the descriptor that will be marked done */ 37861ae650dSJack F Vogel buf = &txr->buffers[first]; 37961ae650dSJack F Vogel buf->eop_index = last; 38061ae650dSJack F Vogel 38161ae650dSJack F Vogel bus_dmamap_sync(txr->dma.tag, txr->dma.map, 38261ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 38361ae650dSJack F Vogel /* 38461ae650dSJack F Vogel * Advance the Transmit Descriptor Tail (Tdt), this tells the 38561ae650dSJack F Vogel * hardware that this frame is available to transmit. 38661ae650dSJack F Vogel */ 38761ae650dSJack F Vogel ++txr->total_packets; 38861ae650dSJack F Vogel wr32(hw, txr->tail, i); 38961ae650dSJack F Vogel 39061ae650dSJack F Vogel ixl_flush(hw); 39161ae650dSJack F Vogel /* Mark outstanding work */ 39261ae650dSJack F Vogel if (que->busy == 0) 39361ae650dSJack F Vogel que->busy = 1; 39461ae650dSJack F Vogel return (0); 39561ae650dSJack F Vogel 39661ae650dSJack F Vogel xmit_fail: 39761ae650dSJack F Vogel bus_dmamap_unload(tag, buf->map); 39861ae650dSJack F Vogel return (error); 39961ae650dSJack F Vogel } 40061ae650dSJack F Vogel 40161ae650dSJack F Vogel 40261ae650dSJack F Vogel /********************************************************************* 40361ae650dSJack F Vogel * 40461ae650dSJack F Vogel * Allocate memory for tx_buffer structures. The tx_buffer stores all 40561ae650dSJack F Vogel * the information needed to transmit a packet on the wire. This is 40661ae650dSJack F Vogel * called only once at attach, setup is done every reset. 40761ae650dSJack F Vogel * 40861ae650dSJack F Vogel **********************************************************************/ 40961ae650dSJack F Vogel int 41061ae650dSJack F Vogel ixl_allocate_tx_data(struct ixl_queue *que) 41161ae650dSJack F Vogel { 41261ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 41361ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 41461ae650dSJack F Vogel device_t dev = vsi->dev; 41561ae650dSJack F Vogel struct ixl_tx_buf *buf; 41661ae650dSJack F Vogel int error = 0; 41761ae650dSJack F Vogel 41861ae650dSJack F Vogel /* 41961ae650dSJack F Vogel * Setup DMA descriptor areas. 42061ae650dSJack F Vogel */ 42161ae650dSJack F Vogel if ((error = bus_dma_tag_create(NULL, /* parent */ 42261ae650dSJack F Vogel 1, 0, /* alignment, bounds */ 42361ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* lowaddr */ 42461ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* highaddr */ 42561ae650dSJack F Vogel NULL, NULL, /* filter, filterarg */ 42661ae650dSJack F Vogel IXL_TSO_SIZE, /* maxsize */ 42761ae650dSJack F Vogel IXL_MAX_TX_SEGS, /* nsegments */ 42861ae650dSJack F Vogel PAGE_SIZE, /* maxsegsize */ 42961ae650dSJack F Vogel 0, /* flags */ 43061ae650dSJack F Vogel NULL, /* lockfunc */ 43161ae650dSJack F Vogel NULL, /* lockfuncarg */ 43261ae650dSJack F Vogel &txr->tx_tag))) { 43361ae650dSJack F Vogel device_printf(dev,"Unable to allocate TX DMA tag\n"); 43461ae650dSJack F Vogel goto fail; 43561ae650dSJack F Vogel } 43661ae650dSJack F Vogel 43761ae650dSJack F Vogel /* Make a special tag for TSO */ 43861ae650dSJack F Vogel if ((error = bus_dma_tag_create(NULL, /* parent */ 43961ae650dSJack F Vogel 1, 0, /* alignment, bounds */ 44061ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* lowaddr */ 44161ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* highaddr */ 44261ae650dSJack F Vogel NULL, NULL, /* filter, filterarg */ 44361ae650dSJack F Vogel IXL_TSO_SIZE, /* maxsize */ 44461ae650dSJack F Vogel IXL_MAX_TSO_SEGS, /* nsegments */ 44561ae650dSJack F Vogel PAGE_SIZE, /* maxsegsize */ 44661ae650dSJack F Vogel 0, /* flags */ 44761ae650dSJack F Vogel NULL, /* lockfunc */ 44861ae650dSJack F Vogel NULL, /* lockfuncarg */ 44961ae650dSJack F Vogel &txr->tso_tag))) { 45061ae650dSJack F Vogel device_printf(dev,"Unable to allocate TX TSO DMA tag\n"); 45161ae650dSJack F Vogel goto fail; 45261ae650dSJack F Vogel } 45361ae650dSJack F Vogel 45461ae650dSJack F Vogel if (!(txr->buffers = 45561ae650dSJack F Vogel (struct ixl_tx_buf *) malloc(sizeof(struct ixl_tx_buf) * 45661ae650dSJack F Vogel que->num_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) { 45761ae650dSJack F Vogel device_printf(dev, "Unable to allocate tx_buffer memory\n"); 45861ae650dSJack F Vogel error = ENOMEM; 45961ae650dSJack F Vogel goto fail; 46061ae650dSJack F Vogel } 46161ae650dSJack F Vogel 46261ae650dSJack F Vogel /* Create the descriptor buffer default dma maps */ 46361ae650dSJack F Vogel buf = txr->buffers; 46461ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++, buf++) { 46561ae650dSJack F Vogel buf->tag = txr->tx_tag; 46661ae650dSJack F Vogel error = bus_dmamap_create(buf->tag, 0, &buf->map); 46761ae650dSJack F Vogel if (error != 0) { 46861ae650dSJack F Vogel device_printf(dev, "Unable to create TX DMA map\n"); 46961ae650dSJack F Vogel goto fail; 47061ae650dSJack F Vogel } 47161ae650dSJack F Vogel } 47261ae650dSJack F Vogel fail: 47361ae650dSJack F Vogel return (error); 47461ae650dSJack F Vogel } 47561ae650dSJack F Vogel 47661ae650dSJack F Vogel 47761ae650dSJack F Vogel /********************************************************************* 47861ae650dSJack F Vogel * 47961ae650dSJack F Vogel * (Re)Initialize a queue transmit ring. 48061ae650dSJack F Vogel * - called by init, it clears the descriptor ring, 48161ae650dSJack F Vogel * and frees any stale mbufs 48261ae650dSJack F Vogel * 48361ae650dSJack F Vogel **********************************************************************/ 48461ae650dSJack F Vogel void 48561ae650dSJack F Vogel ixl_init_tx_ring(struct ixl_queue *que) 48661ae650dSJack F Vogel { 48761ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 48861ae650dSJack F Vogel struct ixl_tx_buf *buf; 48961ae650dSJack F Vogel 49061ae650dSJack F Vogel /* Clear the old ring contents */ 49161ae650dSJack F Vogel IXL_TX_LOCK(txr); 492*56c2c47bSJack F Vogel 493bc8b78d3SLuigi Rizzo 49461ae650dSJack F Vogel bzero((void *)txr->base, 49561ae650dSJack F Vogel (sizeof(struct i40e_tx_desc)) * que->num_desc); 49661ae650dSJack F Vogel 49761ae650dSJack F Vogel /* Reset indices */ 49861ae650dSJack F Vogel txr->next_avail = 0; 49961ae650dSJack F Vogel txr->next_to_clean = 0; 50061ae650dSJack F Vogel 50161ae650dSJack F Vogel #ifdef IXL_FDIR 50261ae650dSJack F Vogel /* Initialize flow director */ 50361ae650dSJack F Vogel txr->atr_rate = ixl_atr_rate; 50461ae650dSJack F Vogel txr->atr_count = 0; 50561ae650dSJack F Vogel #endif 50661ae650dSJack F Vogel 50761ae650dSJack F Vogel /* Free any existing tx mbufs. */ 50861ae650dSJack F Vogel buf = txr->buffers; 50961ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++, buf++) { 51061ae650dSJack F Vogel if (buf->m_head != NULL) { 51161ae650dSJack F Vogel bus_dmamap_sync(buf->tag, buf->map, 51261ae650dSJack F Vogel BUS_DMASYNC_POSTWRITE); 51361ae650dSJack F Vogel bus_dmamap_unload(buf->tag, buf->map); 51461ae650dSJack F Vogel m_freem(buf->m_head); 51561ae650dSJack F Vogel buf->m_head = NULL; 51661ae650dSJack F Vogel } 51761ae650dSJack F Vogel /* Clear the EOP index */ 51861ae650dSJack F Vogel buf->eop_index = -1; 51961ae650dSJack F Vogel } 52061ae650dSJack F Vogel 52161ae650dSJack F Vogel /* Set number of descriptors available */ 52261ae650dSJack F Vogel txr->avail = que->num_desc; 52361ae650dSJack F Vogel 52461ae650dSJack F Vogel bus_dmamap_sync(txr->dma.tag, txr->dma.map, 52561ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 52661ae650dSJack F Vogel IXL_TX_UNLOCK(txr); 52761ae650dSJack F Vogel } 52861ae650dSJack F Vogel 52961ae650dSJack F Vogel 53061ae650dSJack F Vogel /********************************************************************* 53161ae650dSJack F Vogel * 53261ae650dSJack F Vogel * Free transmit ring related data structures. 53361ae650dSJack F Vogel * 53461ae650dSJack F Vogel **********************************************************************/ 53561ae650dSJack F Vogel void 53661ae650dSJack F Vogel ixl_free_que_tx(struct ixl_queue *que) 53761ae650dSJack F Vogel { 53861ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 53961ae650dSJack F Vogel struct ixl_tx_buf *buf; 54061ae650dSJack F Vogel 54161ae650dSJack F Vogel INIT_DBG_IF(que->vsi->ifp, "queue %d: begin", que->me); 54261ae650dSJack F Vogel 54361ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++) { 54461ae650dSJack F Vogel buf = &txr->buffers[i]; 54561ae650dSJack F Vogel if (buf->m_head != NULL) { 54661ae650dSJack F Vogel bus_dmamap_sync(buf->tag, buf->map, 54761ae650dSJack F Vogel BUS_DMASYNC_POSTWRITE); 54861ae650dSJack F Vogel bus_dmamap_unload(buf->tag, 54961ae650dSJack F Vogel buf->map); 55061ae650dSJack F Vogel m_freem(buf->m_head); 55161ae650dSJack F Vogel buf->m_head = NULL; 55261ae650dSJack F Vogel if (buf->map != NULL) { 55361ae650dSJack F Vogel bus_dmamap_destroy(buf->tag, 55461ae650dSJack F Vogel buf->map); 55561ae650dSJack F Vogel buf->map = NULL; 55661ae650dSJack F Vogel } 55761ae650dSJack F Vogel } else if (buf->map != NULL) { 55861ae650dSJack F Vogel bus_dmamap_unload(buf->tag, 55961ae650dSJack F Vogel buf->map); 56061ae650dSJack F Vogel bus_dmamap_destroy(buf->tag, 56161ae650dSJack F Vogel buf->map); 56261ae650dSJack F Vogel buf->map = NULL; 56361ae650dSJack F Vogel } 56461ae650dSJack F Vogel } 56561ae650dSJack F Vogel if (txr->br != NULL) 56661ae650dSJack F Vogel buf_ring_free(txr->br, M_DEVBUF); 56761ae650dSJack F Vogel if (txr->buffers != NULL) { 56861ae650dSJack F Vogel free(txr->buffers, M_DEVBUF); 56961ae650dSJack F Vogel txr->buffers = NULL; 57061ae650dSJack F Vogel } 57161ae650dSJack F Vogel if (txr->tx_tag != NULL) { 57261ae650dSJack F Vogel bus_dma_tag_destroy(txr->tx_tag); 57361ae650dSJack F Vogel txr->tx_tag = NULL; 57461ae650dSJack F Vogel } 57561ae650dSJack F Vogel if (txr->tso_tag != NULL) { 57661ae650dSJack F Vogel bus_dma_tag_destroy(txr->tso_tag); 57761ae650dSJack F Vogel txr->tso_tag = NULL; 57861ae650dSJack F Vogel } 57961ae650dSJack F Vogel 58061ae650dSJack F Vogel INIT_DBG_IF(que->vsi->ifp, "queue %d: end", que->me); 58161ae650dSJack F Vogel return; 58261ae650dSJack F Vogel } 58361ae650dSJack F Vogel 58461ae650dSJack F Vogel /********************************************************************* 58561ae650dSJack F Vogel * 58661ae650dSJack F Vogel * Setup descriptor for hw offloads 58761ae650dSJack F Vogel * 58861ae650dSJack F Vogel **********************************************************************/ 58961ae650dSJack F Vogel 59061ae650dSJack F Vogel static int 59161ae650dSJack F Vogel ixl_tx_setup_offload(struct ixl_queue *que, 59261ae650dSJack F Vogel struct mbuf *mp, u32 *cmd, u32 *off) 59361ae650dSJack F Vogel { 59461ae650dSJack F Vogel struct ether_vlan_header *eh; 5951f873f18SJack F Vogel #ifdef INET 59661ae650dSJack F Vogel struct ip *ip = NULL; 5971f873f18SJack F Vogel #endif 59861ae650dSJack F Vogel struct tcphdr *th = NULL; 5991f873f18SJack F Vogel #ifdef INET6 60061ae650dSJack F Vogel struct ip6_hdr *ip6; 6011f873f18SJack F Vogel #endif 60261ae650dSJack F Vogel int elen, ip_hlen = 0, tcp_hlen; 60361ae650dSJack F Vogel u16 etype; 60461ae650dSJack F Vogel u8 ipproto = 0; 60561ae650dSJack F Vogel bool tso = FALSE; 60661ae650dSJack F Vogel 60761ae650dSJack F Vogel 60861ae650dSJack F Vogel /* Set up the TSO context descriptor if required */ 60961ae650dSJack F Vogel if (mp->m_pkthdr.csum_flags & CSUM_TSO) { 61061ae650dSJack F Vogel tso = ixl_tso_setup(que, mp); 61161ae650dSJack F Vogel if (tso) 61261ae650dSJack F Vogel ++que->tso; 61361ae650dSJack F Vogel else 61461ae650dSJack F Vogel return (ENXIO); 61561ae650dSJack F Vogel } 61661ae650dSJack F Vogel 61761ae650dSJack F Vogel /* 61861ae650dSJack F Vogel * Determine where frame payload starts. 61961ae650dSJack F Vogel * Jump over vlan headers if already present, 62061ae650dSJack F Vogel * helpful for QinQ too. 62161ae650dSJack F Vogel */ 62261ae650dSJack F Vogel eh = mtod(mp, struct ether_vlan_header *); 62361ae650dSJack F Vogel if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 62461ae650dSJack F Vogel etype = ntohs(eh->evl_proto); 62561ae650dSJack F Vogel elen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 62661ae650dSJack F Vogel } else { 62761ae650dSJack F Vogel etype = ntohs(eh->evl_encap_proto); 62861ae650dSJack F Vogel elen = ETHER_HDR_LEN; 62961ae650dSJack F Vogel } 63061ae650dSJack F Vogel 63161ae650dSJack F Vogel switch (etype) { 6322f4959abSJack F Vogel #ifdef INET 633b555c614SBjoern A. Zeeb case ETHERTYPE_IP: 63461ae650dSJack F Vogel ip = (struct ip *)(mp->m_data + elen); 63561ae650dSJack F Vogel ip_hlen = ip->ip_hl << 2; 63661ae650dSJack F Vogel ipproto = ip->ip_p; 63761ae650dSJack F Vogel th = (struct tcphdr *)((caddr_t)ip + ip_hlen); 63861ae650dSJack F Vogel /* The IP checksum must be recalculated with TSO */ 63961ae650dSJack F Vogel if (tso) 64061ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM; 64161ae650dSJack F Vogel else 64261ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_IIPT_IPV4; 64361ae650dSJack F Vogel break; 644b555c614SBjoern A. Zeeb #endif 6452f4959abSJack F Vogel #ifdef INET6 646b555c614SBjoern A. Zeeb case ETHERTYPE_IPV6: 64761ae650dSJack F Vogel ip6 = (struct ip6_hdr *)(mp->m_data + elen); 64861ae650dSJack F Vogel ip_hlen = sizeof(struct ip6_hdr); 64961ae650dSJack F Vogel ipproto = ip6->ip6_nxt; 65061ae650dSJack F Vogel th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); 65161ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_IIPT_IPV6; 652b555c614SBjoern A. Zeeb break; 6532f4959abSJack F Vogel #endif 65461ae650dSJack F Vogel default: 65561ae650dSJack F Vogel break; 65661ae650dSJack F Vogel } 65761ae650dSJack F Vogel 65861ae650dSJack F Vogel *off |= (elen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; 65961ae650dSJack F Vogel *off |= (ip_hlen >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT; 66061ae650dSJack F Vogel 66161ae650dSJack F Vogel switch (ipproto) { 66261ae650dSJack F Vogel case IPPROTO_TCP: 66361ae650dSJack F Vogel tcp_hlen = th->th_off << 2; 66461ae650dSJack F Vogel if (mp->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_TCP_IPV6)) { 66561ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP; 66661ae650dSJack F Vogel *off |= (tcp_hlen >> 2) << 66761ae650dSJack F Vogel I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 66861ae650dSJack F Vogel } 66961ae650dSJack F Vogel #ifdef IXL_FDIR 67061ae650dSJack F Vogel ixl_atr(que, th, etype); 67161ae650dSJack F Vogel #endif 67261ae650dSJack F Vogel break; 67361ae650dSJack F Vogel case IPPROTO_UDP: 67461ae650dSJack F Vogel if (mp->m_pkthdr.csum_flags & (CSUM_UDP|CSUM_UDP_IPV6)) { 67561ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP; 67661ae650dSJack F Vogel *off |= (sizeof(struct udphdr) >> 2) << 67761ae650dSJack F Vogel I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 67861ae650dSJack F Vogel } 67961ae650dSJack F Vogel break; 68061ae650dSJack F Vogel 68161ae650dSJack F Vogel case IPPROTO_SCTP: 68261ae650dSJack F Vogel if (mp->m_pkthdr.csum_flags & (CSUM_SCTP|CSUM_SCTP_IPV6)) { 68361ae650dSJack F Vogel *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP; 68461ae650dSJack F Vogel *off |= (sizeof(struct sctphdr) >> 2) << 68561ae650dSJack F Vogel I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 68661ae650dSJack F Vogel } 68761ae650dSJack F Vogel /* Fall Thru */ 68861ae650dSJack F Vogel default: 68961ae650dSJack F Vogel break; 69061ae650dSJack F Vogel } 69161ae650dSJack F Vogel 69261ae650dSJack F Vogel return (0); 69361ae650dSJack F Vogel } 69461ae650dSJack F Vogel 69561ae650dSJack F Vogel 69661ae650dSJack F Vogel /********************************************************************** 69761ae650dSJack F Vogel * 69861ae650dSJack F Vogel * Setup context for hardware segmentation offload (TSO) 69961ae650dSJack F Vogel * 70061ae650dSJack F Vogel **********************************************************************/ 70161ae650dSJack F Vogel static bool 70261ae650dSJack F Vogel ixl_tso_setup(struct ixl_queue *que, struct mbuf *mp) 70361ae650dSJack F Vogel { 70461ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 70561ae650dSJack F Vogel struct i40e_tx_context_desc *TXD; 70661ae650dSJack F Vogel struct ixl_tx_buf *buf; 70761ae650dSJack F Vogel u32 cmd, mss, type, tsolen; 70861ae650dSJack F Vogel u16 etype; 70961ae650dSJack F Vogel int idx, elen, ip_hlen, tcp_hlen; 71061ae650dSJack F Vogel struct ether_vlan_header *eh; 7111f873f18SJack F Vogel #ifdef INET 71261ae650dSJack F Vogel struct ip *ip; 7131f873f18SJack F Vogel #endif 7141f873f18SJack F Vogel #ifdef INET6 71561ae650dSJack F Vogel struct ip6_hdr *ip6; 7161f873f18SJack F Vogel #endif 717b555c614SBjoern A. Zeeb #if defined(INET6) || defined(INET) 71861ae650dSJack F Vogel struct tcphdr *th; 719b555c614SBjoern A. Zeeb #endif 72061ae650dSJack F Vogel u64 type_cmd_tso_mss; 72161ae650dSJack F Vogel 72261ae650dSJack F Vogel /* 72361ae650dSJack F Vogel * Determine where frame payload starts. 72461ae650dSJack F Vogel * Jump over vlan headers if already present 72561ae650dSJack F Vogel */ 72661ae650dSJack F Vogel eh = mtod(mp, struct ether_vlan_header *); 72761ae650dSJack F Vogel if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 72861ae650dSJack F Vogel elen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 72961ae650dSJack F Vogel etype = eh->evl_proto; 73061ae650dSJack F Vogel } else { 73161ae650dSJack F Vogel elen = ETHER_HDR_LEN; 73261ae650dSJack F Vogel etype = eh->evl_encap_proto; 73361ae650dSJack F Vogel } 73461ae650dSJack F Vogel 73561ae650dSJack F Vogel switch (ntohs(etype)) { 73661ae650dSJack F Vogel #ifdef INET6 73761ae650dSJack F Vogel case ETHERTYPE_IPV6: 73861ae650dSJack F Vogel ip6 = (struct ip6_hdr *)(mp->m_data + elen); 73961ae650dSJack F Vogel if (ip6->ip6_nxt != IPPROTO_TCP) 74061ae650dSJack F Vogel return (ENXIO); 74161ae650dSJack F Vogel ip_hlen = sizeof(struct ip6_hdr); 74261ae650dSJack F Vogel th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); 74361ae650dSJack F Vogel th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 74461ae650dSJack F Vogel tcp_hlen = th->th_off << 2; 74561ae650dSJack F Vogel break; 74661ae650dSJack F Vogel #endif 74761ae650dSJack F Vogel #ifdef INET 74861ae650dSJack F Vogel case ETHERTYPE_IP: 74961ae650dSJack F Vogel ip = (struct ip *)(mp->m_data + elen); 75061ae650dSJack F Vogel if (ip->ip_p != IPPROTO_TCP) 75161ae650dSJack F Vogel return (ENXIO); 75261ae650dSJack F Vogel ip->ip_sum = 0; 75361ae650dSJack F Vogel ip_hlen = ip->ip_hl << 2; 75461ae650dSJack F Vogel th = (struct tcphdr *)((caddr_t)ip + ip_hlen); 75561ae650dSJack F Vogel th->th_sum = in_pseudo(ip->ip_src.s_addr, 75661ae650dSJack F Vogel ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 75761ae650dSJack F Vogel tcp_hlen = th->th_off << 2; 75861ae650dSJack F Vogel break; 75961ae650dSJack F Vogel #endif 76061ae650dSJack F Vogel default: 761b555c614SBjoern A. Zeeb printf("%s: CSUM_TSO but no supported IP version (0x%04x)", 76261ae650dSJack F Vogel __func__, ntohs(etype)); 763b555c614SBjoern A. Zeeb return FALSE; 76461ae650dSJack F Vogel } 76561ae650dSJack F Vogel 76661ae650dSJack F Vogel /* Ensure we have at least the IP+TCP header in the first mbuf. */ 76761ae650dSJack F Vogel if (mp->m_len < elen + ip_hlen + sizeof(struct tcphdr)) 76861ae650dSJack F Vogel return FALSE; 76961ae650dSJack F Vogel 77061ae650dSJack F Vogel idx = txr->next_avail; 77161ae650dSJack F Vogel buf = &txr->buffers[idx]; 77261ae650dSJack F Vogel TXD = (struct i40e_tx_context_desc *) &txr->base[idx]; 77361ae650dSJack F Vogel tsolen = mp->m_pkthdr.len - (elen + ip_hlen + tcp_hlen); 77461ae650dSJack F Vogel 77561ae650dSJack F Vogel type = I40E_TX_DESC_DTYPE_CONTEXT; 77661ae650dSJack F Vogel cmd = I40E_TX_CTX_DESC_TSO; 77761ae650dSJack F Vogel mss = mp->m_pkthdr.tso_segsz; 77861ae650dSJack F Vogel 77961ae650dSJack F Vogel type_cmd_tso_mss = ((u64)type << I40E_TXD_CTX_QW1_DTYPE_SHIFT) | 78061ae650dSJack F Vogel ((u64)cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) | 78161ae650dSJack F Vogel ((u64)tsolen << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) | 78261ae650dSJack F Vogel ((u64)mss << I40E_TXD_CTX_QW1_MSS_SHIFT); 78361ae650dSJack F Vogel TXD->type_cmd_tso_mss = htole64(type_cmd_tso_mss); 78461ae650dSJack F Vogel 78561ae650dSJack F Vogel TXD->tunneling_params = htole32(0); 78661ae650dSJack F Vogel buf->m_head = NULL; 78761ae650dSJack F Vogel buf->eop_index = -1; 78861ae650dSJack F Vogel 78961ae650dSJack F Vogel if (++idx == que->num_desc) 79061ae650dSJack F Vogel idx = 0; 79161ae650dSJack F Vogel 79261ae650dSJack F Vogel txr->avail--; 79361ae650dSJack F Vogel txr->next_avail = idx; 79461ae650dSJack F Vogel 79561ae650dSJack F Vogel return TRUE; 79661ae650dSJack F Vogel } 79761ae650dSJack F Vogel 79861ae650dSJack F Vogel /* 79961ae650dSJack F Vogel ** ixl_get_tx_head - Retrieve the value from the 80061ae650dSJack F Vogel ** location the HW records its HEAD index 80161ae650dSJack F Vogel */ 80261ae650dSJack F Vogel static inline u32 80361ae650dSJack F Vogel ixl_get_tx_head(struct ixl_queue *que) 80461ae650dSJack F Vogel { 80561ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 80661ae650dSJack F Vogel void *head = &txr->base[que->num_desc]; 80761ae650dSJack F Vogel return LE32_TO_CPU(*(volatile __le32 *)head); 80861ae650dSJack F Vogel } 80961ae650dSJack F Vogel 81061ae650dSJack F Vogel /********************************************************************** 81161ae650dSJack F Vogel * 81261ae650dSJack F Vogel * Examine each tx_buffer in the used queue. If the hardware is done 81361ae650dSJack F Vogel * processing the packet then free associated resources. The 81461ae650dSJack F Vogel * tx_buffer is put back on the free queue. 81561ae650dSJack F Vogel * 81661ae650dSJack F Vogel **********************************************************************/ 81761ae650dSJack F Vogel bool 81861ae650dSJack F Vogel ixl_txeof(struct ixl_queue *que) 81961ae650dSJack F Vogel { 82061ae650dSJack F Vogel struct tx_ring *txr = &que->txr; 82161ae650dSJack F Vogel u32 first, last, head, done, processed; 82261ae650dSJack F Vogel struct ixl_tx_buf *buf; 82361ae650dSJack F Vogel struct i40e_tx_desc *tx_desc, *eop_desc; 82461ae650dSJack F Vogel 82561ae650dSJack F Vogel 82661ae650dSJack F Vogel mtx_assert(&txr->mtx, MA_OWNED); 82761ae650dSJack F Vogel 828e5100ee2SJack F Vogel 82961ae650dSJack F Vogel /* These are not the descriptors you seek, move along :) */ 83061ae650dSJack F Vogel if (txr->avail == que->num_desc) { 83161ae650dSJack F Vogel que->busy = 0; 83261ae650dSJack F Vogel return FALSE; 83361ae650dSJack F Vogel } 83461ae650dSJack F Vogel 83561ae650dSJack F Vogel processed = 0; 83661ae650dSJack F Vogel first = txr->next_to_clean; 83761ae650dSJack F Vogel buf = &txr->buffers[first]; 83861ae650dSJack F Vogel tx_desc = (struct i40e_tx_desc *)&txr->base[first]; 83961ae650dSJack F Vogel last = buf->eop_index; 84061ae650dSJack F Vogel if (last == -1) 84161ae650dSJack F Vogel return FALSE; 84261ae650dSJack F Vogel eop_desc = (struct i40e_tx_desc *)&txr->base[last]; 84361ae650dSJack F Vogel 84461ae650dSJack F Vogel /* Get the Head WB value */ 84561ae650dSJack F Vogel head = ixl_get_tx_head(que); 84661ae650dSJack F Vogel 84761ae650dSJack F Vogel /* 84861ae650dSJack F Vogel ** Get the index of the first descriptor 84961ae650dSJack F Vogel ** BEYOND the EOP and call that 'done'. 85061ae650dSJack F Vogel ** I do this so the comparison in the 85161ae650dSJack F Vogel ** inner while loop below can be simple 85261ae650dSJack F Vogel */ 85361ae650dSJack F Vogel if (++last == que->num_desc) last = 0; 85461ae650dSJack F Vogel done = last; 85561ae650dSJack F Vogel 85661ae650dSJack F Vogel bus_dmamap_sync(txr->dma.tag, txr->dma.map, 85761ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 85861ae650dSJack F Vogel /* 85961ae650dSJack F Vogel ** The HEAD index of the ring is written in a 86061ae650dSJack F Vogel ** defined location, this rather than a done bit 86161ae650dSJack F Vogel ** is what is used to keep track of what must be 86261ae650dSJack F Vogel ** 'cleaned'. 86361ae650dSJack F Vogel */ 86461ae650dSJack F Vogel while (first != head) { 86561ae650dSJack F Vogel /* We clean the range of the packet */ 86661ae650dSJack F Vogel while (first != done) { 86761ae650dSJack F Vogel ++txr->avail; 86861ae650dSJack F Vogel ++processed; 86961ae650dSJack F Vogel 87061ae650dSJack F Vogel if (buf->m_head) { 87161ae650dSJack F Vogel txr->bytes += /* for ITR adjustment */ 87261ae650dSJack F Vogel buf->m_head->m_pkthdr.len; 87361ae650dSJack F Vogel txr->tx_bytes += /* for TX stats */ 87461ae650dSJack F Vogel buf->m_head->m_pkthdr.len; 87561ae650dSJack F Vogel bus_dmamap_sync(buf->tag, 87661ae650dSJack F Vogel buf->map, 87761ae650dSJack F Vogel BUS_DMASYNC_POSTWRITE); 87861ae650dSJack F Vogel bus_dmamap_unload(buf->tag, 87961ae650dSJack F Vogel buf->map); 88061ae650dSJack F Vogel m_freem(buf->m_head); 88161ae650dSJack F Vogel buf->m_head = NULL; 88261ae650dSJack F Vogel buf->map = NULL; 88361ae650dSJack F Vogel } 88461ae650dSJack F Vogel buf->eop_index = -1; 88561ae650dSJack F Vogel 88661ae650dSJack F Vogel if (++first == que->num_desc) 88761ae650dSJack F Vogel first = 0; 88861ae650dSJack F Vogel 88961ae650dSJack F Vogel buf = &txr->buffers[first]; 89061ae650dSJack F Vogel tx_desc = &txr->base[first]; 89161ae650dSJack F Vogel } 89261ae650dSJack F Vogel ++txr->packets; 89361ae650dSJack F Vogel /* See if there is more work now */ 89461ae650dSJack F Vogel last = buf->eop_index; 89561ae650dSJack F Vogel if (last != -1) { 89661ae650dSJack F Vogel eop_desc = &txr->base[last]; 89761ae650dSJack F Vogel /* Get next done point */ 89861ae650dSJack F Vogel if (++last == que->num_desc) last = 0; 89961ae650dSJack F Vogel done = last; 90061ae650dSJack F Vogel } else 90161ae650dSJack F Vogel break; 90261ae650dSJack F Vogel } 90361ae650dSJack F Vogel bus_dmamap_sync(txr->dma.tag, txr->dma.map, 90461ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 90561ae650dSJack F Vogel 90661ae650dSJack F Vogel txr->next_to_clean = first; 90761ae650dSJack F Vogel 90861ae650dSJack F Vogel 90961ae650dSJack F Vogel /* 91061ae650dSJack F Vogel ** Hang detection, we know there's 91161ae650dSJack F Vogel ** work outstanding or the first return 91261ae650dSJack F Vogel ** would have been taken, so indicate an 91361ae650dSJack F Vogel ** unsuccessful pass, in local_timer if 91461ae650dSJack F Vogel ** the value is too great the queue will 91561ae650dSJack F Vogel ** be considered hung. If anything has been 91661ae650dSJack F Vogel ** cleaned then reset the state. 91761ae650dSJack F Vogel */ 91861ae650dSJack F Vogel if ((processed == 0) && (que->busy != IXL_QUEUE_HUNG)) 91961ae650dSJack F Vogel ++que->busy; 92061ae650dSJack F Vogel 92161ae650dSJack F Vogel if (processed) 92261ae650dSJack F Vogel que->busy = 1; /* Note this turns off HUNG */ 92361ae650dSJack F Vogel 92461ae650dSJack F Vogel /* 92561ae650dSJack F Vogel * If there are no pending descriptors, clear the timeout. 92661ae650dSJack F Vogel */ 92761ae650dSJack F Vogel if (txr->avail == que->num_desc) { 92861ae650dSJack F Vogel que->busy = 0; 92961ae650dSJack F Vogel return FALSE; 93061ae650dSJack F Vogel } 93161ae650dSJack F Vogel 93261ae650dSJack F Vogel return TRUE; 93361ae650dSJack F Vogel } 93461ae650dSJack F Vogel 93561ae650dSJack F Vogel /********************************************************************* 93661ae650dSJack F Vogel * 93761ae650dSJack F Vogel * Refresh mbuf buffers for RX descriptor rings 93861ae650dSJack F Vogel * - now keeps its own state so discards due to resource 93961ae650dSJack F Vogel * exhaustion are unnecessary, if an mbuf cannot be obtained 94061ae650dSJack F Vogel * it just returns, keeping its placeholder, thus it can simply 94161ae650dSJack F Vogel * be recalled to try again. 94261ae650dSJack F Vogel * 94361ae650dSJack F Vogel **********************************************************************/ 94461ae650dSJack F Vogel static void 94561ae650dSJack F Vogel ixl_refresh_mbufs(struct ixl_queue *que, int limit) 94661ae650dSJack F Vogel { 94761ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 94861ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 94961ae650dSJack F Vogel bus_dma_segment_t hseg[1]; 95061ae650dSJack F Vogel bus_dma_segment_t pseg[1]; 95161ae650dSJack F Vogel struct ixl_rx_buf *buf; 95261ae650dSJack F Vogel struct mbuf *mh, *mp; 95361ae650dSJack F Vogel int i, j, nsegs, error; 95461ae650dSJack F Vogel bool refreshed = FALSE; 95561ae650dSJack F Vogel 95661ae650dSJack F Vogel i = j = rxr->next_refresh; 95761ae650dSJack F Vogel /* Control the loop with one beyond */ 95861ae650dSJack F Vogel if (++j == que->num_desc) 95961ae650dSJack F Vogel j = 0; 96061ae650dSJack F Vogel 96161ae650dSJack F Vogel while (j != limit) { 96261ae650dSJack F Vogel buf = &rxr->buffers[i]; 96361ae650dSJack F Vogel if (rxr->hdr_split == FALSE) 96461ae650dSJack F Vogel goto no_split; 96561ae650dSJack F Vogel 96661ae650dSJack F Vogel if (buf->m_head == NULL) { 96761ae650dSJack F Vogel mh = m_gethdr(M_NOWAIT, MT_DATA); 96861ae650dSJack F Vogel if (mh == NULL) 96961ae650dSJack F Vogel goto update; 97061ae650dSJack F Vogel } else 97161ae650dSJack F Vogel mh = buf->m_head; 97261ae650dSJack F Vogel 97361ae650dSJack F Vogel mh->m_pkthdr.len = mh->m_len = MHLEN; 97461ae650dSJack F Vogel mh->m_len = MHLEN; 97561ae650dSJack F Vogel mh->m_flags |= M_PKTHDR; 97661ae650dSJack F Vogel /* Get the memory mapping */ 97761ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(rxr->htag, 97861ae650dSJack F Vogel buf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT); 97961ae650dSJack F Vogel if (error != 0) { 98061ae650dSJack F Vogel printf("Refresh mbufs: hdr dmamap load" 98161ae650dSJack F Vogel " failure - %d\n", error); 98261ae650dSJack F Vogel m_free(mh); 98361ae650dSJack F Vogel buf->m_head = NULL; 98461ae650dSJack F Vogel goto update; 98561ae650dSJack F Vogel } 98661ae650dSJack F Vogel buf->m_head = mh; 98761ae650dSJack F Vogel bus_dmamap_sync(rxr->htag, buf->hmap, 98861ae650dSJack F Vogel BUS_DMASYNC_PREREAD); 98961ae650dSJack F Vogel rxr->base[i].read.hdr_addr = 99061ae650dSJack F Vogel htole64(hseg[0].ds_addr); 99161ae650dSJack F Vogel 99261ae650dSJack F Vogel no_split: 99361ae650dSJack F Vogel if (buf->m_pack == NULL) { 99461ae650dSJack F Vogel mp = m_getjcl(M_NOWAIT, MT_DATA, 99561ae650dSJack F Vogel M_PKTHDR, rxr->mbuf_sz); 99661ae650dSJack F Vogel if (mp == NULL) 99761ae650dSJack F Vogel goto update; 99861ae650dSJack F Vogel } else 99961ae650dSJack F Vogel mp = buf->m_pack; 100061ae650dSJack F Vogel 100161ae650dSJack F Vogel mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz; 100261ae650dSJack F Vogel /* Get the memory mapping */ 100361ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(rxr->ptag, 100461ae650dSJack F Vogel buf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT); 100561ae650dSJack F Vogel if (error != 0) { 100661ae650dSJack F Vogel printf("Refresh mbufs: payload dmamap load" 100761ae650dSJack F Vogel " failure - %d\n", error); 100861ae650dSJack F Vogel m_free(mp); 100961ae650dSJack F Vogel buf->m_pack = NULL; 101061ae650dSJack F Vogel goto update; 101161ae650dSJack F Vogel } 101261ae650dSJack F Vogel buf->m_pack = mp; 101361ae650dSJack F Vogel bus_dmamap_sync(rxr->ptag, buf->pmap, 101461ae650dSJack F Vogel BUS_DMASYNC_PREREAD); 101561ae650dSJack F Vogel rxr->base[i].read.pkt_addr = 101661ae650dSJack F Vogel htole64(pseg[0].ds_addr); 101761ae650dSJack F Vogel /* Used only when doing header split */ 101861ae650dSJack F Vogel rxr->base[i].read.hdr_addr = 0; 101961ae650dSJack F Vogel 102061ae650dSJack F Vogel refreshed = TRUE; 102161ae650dSJack F Vogel /* Next is precalculated */ 102261ae650dSJack F Vogel i = j; 102361ae650dSJack F Vogel rxr->next_refresh = i; 102461ae650dSJack F Vogel if (++j == que->num_desc) 102561ae650dSJack F Vogel j = 0; 102661ae650dSJack F Vogel } 102761ae650dSJack F Vogel update: 102861ae650dSJack F Vogel if (refreshed) /* Update hardware tail index */ 102961ae650dSJack F Vogel wr32(vsi->hw, rxr->tail, rxr->next_refresh); 103061ae650dSJack F Vogel return; 103161ae650dSJack F Vogel } 103261ae650dSJack F Vogel 103361ae650dSJack F Vogel 103461ae650dSJack F Vogel /********************************************************************* 103561ae650dSJack F Vogel * 103661ae650dSJack F Vogel * Allocate memory for rx_buffer structures. Since we use one 103761ae650dSJack F Vogel * rx_buffer per descriptor, the maximum number of rx_buffer's 103861ae650dSJack F Vogel * that we'll need is equal to the number of receive descriptors 103961ae650dSJack F Vogel * that we've defined. 104061ae650dSJack F Vogel * 104161ae650dSJack F Vogel **********************************************************************/ 104261ae650dSJack F Vogel int 104361ae650dSJack F Vogel ixl_allocate_rx_data(struct ixl_queue *que) 104461ae650dSJack F Vogel { 104561ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 104661ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 104761ae650dSJack F Vogel device_t dev = vsi->dev; 104861ae650dSJack F Vogel struct ixl_rx_buf *buf; 104961ae650dSJack F Vogel int i, bsize, error; 105061ae650dSJack F Vogel 105161ae650dSJack F Vogel bsize = sizeof(struct ixl_rx_buf) * que->num_desc; 105261ae650dSJack F Vogel if (!(rxr->buffers = 105361ae650dSJack F Vogel (struct ixl_rx_buf *) malloc(bsize, 105461ae650dSJack F Vogel M_DEVBUF, M_NOWAIT | M_ZERO))) { 105561ae650dSJack F Vogel device_printf(dev, "Unable to allocate rx_buffer memory\n"); 105661ae650dSJack F Vogel error = ENOMEM; 105761ae650dSJack F Vogel return (error); 105861ae650dSJack F Vogel } 105961ae650dSJack F Vogel 106061ae650dSJack F Vogel if ((error = bus_dma_tag_create(NULL, /* parent */ 106161ae650dSJack F Vogel 1, 0, /* alignment, bounds */ 106261ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* lowaddr */ 106361ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* highaddr */ 106461ae650dSJack F Vogel NULL, NULL, /* filter, filterarg */ 106561ae650dSJack F Vogel MSIZE, /* maxsize */ 106661ae650dSJack F Vogel 1, /* nsegments */ 106761ae650dSJack F Vogel MSIZE, /* maxsegsize */ 106861ae650dSJack F Vogel 0, /* flags */ 106961ae650dSJack F Vogel NULL, /* lockfunc */ 107061ae650dSJack F Vogel NULL, /* lockfuncarg */ 107161ae650dSJack F Vogel &rxr->htag))) { 107261ae650dSJack F Vogel device_printf(dev, "Unable to create RX DMA htag\n"); 107361ae650dSJack F Vogel return (error); 107461ae650dSJack F Vogel } 107561ae650dSJack F Vogel 107661ae650dSJack F Vogel if ((error = bus_dma_tag_create(NULL, /* parent */ 107761ae650dSJack F Vogel 1, 0, /* alignment, bounds */ 107861ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* lowaddr */ 107961ae650dSJack F Vogel BUS_SPACE_MAXADDR, /* highaddr */ 108061ae650dSJack F Vogel NULL, NULL, /* filter, filterarg */ 108161ae650dSJack F Vogel MJUM16BYTES, /* maxsize */ 108261ae650dSJack F Vogel 1, /* nsegments */ 108361ae650dSJack F Vogel MJUM16BYTES, /* maxsegsize */ 108461ae650dSJack F Vogel 0, /* flags */ 108561ae650dSJack F Vogel NULL, /* lockfunc */ 108661ae650dSJack F Vogel NULL, /* lockfuncarg */ 108761ae650dSJack F Vogel &rxr->ptag))) { 108861ae650dSJack F Vogel device_printf(dev, "Unable to create RX DMA ptag\n"); 108961ae650dSJack F Vogel return (error); 109061ae650dSJack F Vogel } 109161ae650dSJack F Vogel 109261ae650dSJack F Vogel for (i = 0; i < que->num_desc; i++) { 109361ae650dSJack F Vogel buf = &rxr->buffers[i]; 109461ae650dSJack F Vogel error = bus_dmamap_create(rxr->htag, 109561ae650dSJack F Vogel BUS_DMA_NOWAIT, &buf->hmap); 109661ae650dSJack F Vogel if (error) { 109761ae650dSJack F Vogel device_printf(dev, "Unable to create RX head map\n"); 109861ae650dSJack F Vogel break; 109961ae650dSJack F Vogel } 110061ae650dSJack F Vogel error = bus_dmamap_create(rxr->ptag, 110161ae650dSJack F Vogel BUS_DMA_NOWAIT, &buf->pmap); 110261ae650dSJack F Vogel if (error) { 110361ae650dSJack F Vogel device_printf(dev, "Unable to create RX pkt map\n"); 110461ae650dSJack F Vogel break; 110561ae650dSJack F Vogel } 110661ae650dSJack F Vogel } 110761ae650dSJack F Vogel 110861ae650dSJack F Vogel return (error); 110961ae650dSJack F Vogel } 111061ae650dSJack F Vogel 111161ae650dSJack F Vogel 111261ae650dSJack F Vogel /********************************************************************* 111361ae650dSJack F Vogel * 111461ae650dSJack F Vogel * (Re)Initialize the queue receive ring and its buffers. 111561ae650dSJack F Vogel * 111661ae650dSJack F Vogel **********************************************************************/ 111761ae650dSJack F Vogel int 111861ae650dSJack F Vogel ixl_init_rx_ring(struct ixl_queue *que) 111961ae650dSJack F Vogel { 1120b3f7259bSBjoern A. Zeeb struct rx_ring *rxr = &que->rxr; 1121393c4bb1SJack F Vogel struct ixl_vsi *vsi = que->vsi; 1122a2cf30b9SBjoern A. Zeeb #if defined(INET6) || defined(INET) 112361ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 112461ae650dSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 1125b3f7259bSBjoern A. Zeeb #endif 112661ae650dSJack F Vogel struct ixl_rx_buf *buf; 112761ae650dSJack F Vogel bus_dma_segment_t pseg[1], hseg[1]; 112861ae650dSJack F Vogel int rsize, nsegs, error = 0; 112961ae650dSJack F Vogel 113061ae650dSJack F Vogel IXL_RX_LOCK(rxr); 113161ae650dSJack F Vogel /* Clear the ring contents */ 113261ae650dSJack F Vogel rsize = roundup2(que->num_desc * 113361ae650dSJack F Vogel sizeof(union i40e_rx_desc), DBA_ALIGN); 113461ae650dSJack F Vogel bzero((void *)rxr->base, rsize); 113561ae650dSJack F Vogel /* Cleanup any existing buffers */ 113661ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++) { 113761ae650dSJack F Vogel buf = &rxr->buffers[i]; 113861ae650dSJack F Vogel if (buf->m_head != NULL) { 113961ae650dSJack F Vogel bus_dmamap_sync(rxr->htag, buf->hmap, 114061ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 114161ae650dSJack F Vogel bus_dmamap_unload(rxr->htag, buf->hmap); 114261ae650dSJack F Vogel buf->m_head->m_flags |= M_PKTHDR; 114361ae650dSJack F Vogel m_freem(buf->m_head); 114461ae650dSJack F Vogel } 114561ae650dSJack F Vogel if (buf->m_pack != NULL) { 114661ae650dSJack F Vogel bus_dmamap_sync(rxr->ptag, buf->pmap, 114761ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 114861ae650dSJack F Vogel bus_dmamap_unload(rxr->ptag, buf->pmap); 114961ae650dSJack F Vogel buf->m_pack->m_flags |= M_PKTHDR; 115061ae650dSJack F Vogel m_freem(buf->m_pack); 115161ae650dSJack F Vogel } 115261ae650dSJack F Vogel buf->m_head = NULL; 115361ae650dSJack F Vogel buf->m_pack = NULL; 115461ae650dSJack F Vogel } 115561ae650dSJack F Vogel 115661ae650dSJack F Vogel /* header split is off */ 115761ae650dSJack F Vogel rxr->hdr_split = FALSE; 115861ae650dSJack F Vogel 115961ae650dSJack F Vogel /* Now replenish the mbufs */ 116061ae650dSJack F Vogel for (int j = 0; j != que->num_desc; ++j) { 116161ae650dSJack F Vogel struct mbuf *mh, *mp; 116261ae650dSJack F Vogel 116361ae650dSJack F Vogel buf = &rxr->buffers[j]; 1164bc8b78d3SLuigi Rizzo 116561ae650dSJack F Vogel /* 116661ae650dSJack F Vogel ** Don't allocate mbufs if not 116761ae650dSJack F Vogel ** doing header split, its wasteful 116861ae650dSJack F Vogel */ 116961ae650dSJack F Vogel if (rxr->hdr_split == FALSE) 117061ae650dSJack F Vogel goto skip_head; 117161ae650dSJack F Vogel 117261ae650dSJack F Vogel /* First the header */ 117361ae650dSJack F Vogel buf->m_head = m_gethdr(M_NOWAIT, MT_DATA); 117461ae650dSJack F Vogel if (buf->m_head == NULL) { 117561ae650dSJack F Vogel error = ENOBUFS; 117661ae650dSJack F Vogel goto fail; 117761ae650dSJack F Vogel } 117861ae650dSJack F Vogel m_adj(buf->m_head, ETHER_ALIGN); 117961ae650dSJack F Vogel mh = buf->m_head; 118061ae650dSJack F Vogel mh->m_len = mh->m_pkthdr.len = MHLEN; 118161ae650dSJack F Vogel mh->m_flags |= M_PKTHDR; 118261ae650dSJack F Vogel /* Get the memory mapping */ 118361ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(rxr->htag, 118461ae650dSJack F Vogel buf->hmap, buf->m_head, hseg, 118561ae650dSJack F Vogel &nsegs, BUS_DMA_NOWAIT); 118661ae650dSJack F Vogel if (error != 0) /* Nothing elegant to do here */ 118761ae650dSJack F Vogel goto fail; 118861ae650dSJack F Vogel bus_dmamap_sync(rxr->htag, 118961ae650dSJack F Vogel buf->hmap, BUS_DMASYNC_PREREAD); 119061ae650dSJack F Vogel /* Update descriptor */ 119161ae650dSJack F Vogel rxr->base[j].read.hdr_addr = htole64(hseg[0].ds_addr); 119261ae650dSJack F Vogel 119361ae650dSJack F Vogel skip_head: 119461ae650dSJack F Vogel /* Now the payload cluster */ 119561ae650dSJack F Vogel buf->m_pack = m_getjcl(M_NOWAIT, MT_DATA, 119661ae650dSJack F Vogel M_PKTHDR, rxr->mbuf_sz); 119761ae650dSJack F Vogel if (buf->m_pack == NULL) { 119861ae650dSJack F Vogel error = ENOBUFS; 119961ae650dSJack F Vogel goto fail; 120061ae650dSJack F Vogel } 120161ae650dSJack F Vogel mp = buf->m_pack; 120261ae650dSJack F Vogel mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz; 120361ae650dSJack F Vogel /* Get the memory mapping */ 120461ae650dSJack F Vogel error = bus_dmamap_load_mbuf_sg(rxr->ptag, 120561ae650dSJack F Vogel buf->pmap, mp, pseg, 120661ae650dSJack F Vogel &nsegs, BUS_DMA_NOWAIT); 120761ae650dSJack F Vogel if (error != 0) 120861ae650dSJack F Vogel goto fail; 120961ae650dSJack F Vogel bus_dmamap_sync(rxr->ptag, 121061ae650dSJack F Vogel buf->pmap, BUS_DMASYNC_PREREAD); 121161ae650dSJack F Vogel /* Update descriptor */ 121261ae650dSJack F Vogel rxr->base[j].read.pkt_addr = htole64(pseg[0].ds_addr); 121361ae650dSJack F Vogel rxr->base[j].read.hdr_addr = 0; 121461ae650dSJack F Vogel } 121561ae650dSJack F Vogel 121661ae650dSJack F Vogel 121761ae650dSJack F Vogel /* Setup our descriptor indices */ 121861ae650dSJack F Vogel rxr->next_check = 0; 121961ae650dSJack F Vogel rxr->next_refresh = 0; 122061ae650dSJack F Vogel rxr->lro_enabled = FALSE; 122161ae650dSJack F Vogel rxr->split = 0; 122261ae650dSJack F Vogel rxr->bytes = 0; 122361ae650dSJack F Vogel rxr->discard = FALSE; 122461ae650dSJack F Vogel 1225e5100ee2SJack F Vogel wr32(vsi->hw, rxr->tail, que->num_desc - 1); 1226e5100ee2SJack F Vogel ixl_flush(vsi->hw); 1227e5100ee2SJack F Vogel 1228b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET) 122961ae650dSJack F Vogel /* 123061ae650dSJack F Vogel ** Now set up the LRO interface: 123161ae650dSJack F Vogel */ 123261ae650dSJack F Vogel if (ifp->if_capenable & IFCAP_LRO) { 123361ae650dSJack F Vogel int err = tcp_lro_init(lro); 123461ae650dSJack F Vogel if (err) { 123561ae650dSJack F Vogel if_printf(ifp, "queue %d: LRO Initialization failed!\n", que->me); 123661ae650dSJack F Vogel goto fail; 123761ae650dSJack F Vogel } 123861ae650dSJack F Vogel INIT_DBG_IF(ifp, "queue %d: RX Soft LRO Initialized", que->me); 123961ae650dSJack F Vogel rxr->lro_enabled = TRUE; 124061ae650dSJack F Vogel lro->ifp = vsi->ifp; 124161ae650dSJack F Vogel } 1242b3f7259bSBjoern A. Zeeb #endif 124361ae650dSJack F Vogel 124461ae650dSJack F Vogel bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, 124561ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 124661ae650dSJack F Vogel 124761ae650dSJack F Vogel fail: 124861ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 124961ae650dSJack F Vogel return (error); 125061ae650dSJack F Vogel } 125161ae650dSJack F Vogel 125261ae650dSJack F Vogel 125361ae650dSJack F Vogel /********************************************************************* 125461ae650dSJack F Vogel * 125561ae650dSJack F Vogel * Free station receive ring data structures 125661ae650dSJack F Vogel * 125761ae650dSJack F Vogel **********************************************************************/ 125861ae650dSJack F Vogel void 125961ae650dSJack F Vogel ixl_free_que_rx(struct ixl_queue *que) 126061ae650dSJack F Vogel { 126161ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 126261ae650dSJack F Vogel struct ixl_rx_buf *buf; 126361ae650dSJack F Vogel 126461ae650dSJack F Vogel INIT_DBG_IF(que->vsi->ifp, "queue %d: begin", que->me); 126561ae650dSJack F Vogel 126661ae650dSJack F Vogel /* Cleanup any existing buffers */ 126761ae650dSJack F Vogel if (rxr->buffers != NULL) { 126861ae650dSJack F Vogel for (int i = 0; i < que->num_desc; i++) { 126961ae650dSJack F Vogel buf = &rxr->buffers[i]; 127061ae650dSJack F Vogel if (buf->m_head != NULL) { 127161ae650dSJack F Vogel bus_dmamap_sync(rxr->htag, buf->hmap, 127261ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 127361ae650dSJack F Vogel bus_dmamap_unload(rxr->htag, buf->hmap); 127461ae650dSJack F Vogel buf->m_head->m_flags |= M_PKTHDR; 127561ae650dSJack F Vogel m_freem(buf->m_head); 127661ae650dSJack F Vogel } 127761ae650dSJack F Vogel if (buf->m_pack != NULL) { 127861ae650dSJack F Vogel bus_dmamap_sync(rxr->ptag, buf->pmap, 127961ae650dSJack F Vogel BUS_DMASYNC_POSTREAD); 128061ae650dSJack F Vogel bus_dmamap_unload(rxr->ptag, buf->pmap); 128161ae650dSJack F Vogel buf->m_pack->m_flags |= M_PKTHDR; 128261ae650dSJack F Vogel m_freem(buf->m_pack); 128361ae650dSJack F Vogel } 128461ae650dSJack F Vogel buf->m_head = NULL; 128561ae650dSJack F Vogel buf->m_pack = NULL; 128661ae650dSJack F Vogel if (buf->hmap != NULL) { 128761ae650dSJack F Vogel bus_dmamap_destroy(rxr->htag, buf->hmap); 128861ae650dSJack F Vogel buf->hmap = NULL; 128961ae650dSJack F Vogel } 129061ae650dSJack F Vogel if (buf->pmap != NULL) { 129161ae650dSJack F Vogel bus_dmamap_destroy(rxr->ptag, buf->pmap); 129261ae650dSJack F Vogel buf->pmap = NULL; 129361ae650dSJack F Vogel } 129461ae650dSJack F Vogel } 129561ae650dSJack F Vogel if (rxr->buffers != NULL) { 129661ae650dSJack F Vogel free(rxr->buffers, M_DEVBUF); 129761ae650dSJack F Vogel rxr->buffers = NULL; 129861ae650dSJack F Vogel } 129961ae650dSJack F Vogel } 130061ae650dSJack F Vogel 130161ae650dSJack F Vogel if (rxr->htag != NULL) { 130261ae650dSJack F Vogel bus_dma_tag_destroy(rxr->htag); 130361ae650dSJack F Vogel rxr->htag = NULL; 130461ae650dSJack F Vogel } 130561ae650dSJack F Vogel if (rxr->ptag != NULL) { 130661ae650dSJack F Vogel bus_dma_tag_destroy(rxr->ptag); 130761ae650dSJack F Vogel rxr->ptag = NULL; 130861ae650dSJack F Vogel } 130961ae650dSJack F Vogel 131061ae650dSJack F Vogel INIT_DBG_IF(que->vsi->ifp, "queue %d: end", que->me); 131161ae650dSJack F Vogel return; 131261ae650dSJack F Vogel } 131361ae650dSJack F Vogel 131461ae650dSJack F Vogel static __inline void 131561ae650dSJack F Vogel ixl_rx_input(struct rx_ring *rxr, struct ifnet *ifp, struct mbuf *m, u8 ptype) 131661ae650dSJack F Vogel { 1317b3f7259bSBjoern A. Zeeb 1318b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET) 131961ae650dSJack F Vogel /* 132061ae650dSJack F Vogel * ATM LRO is only for IPv4/TCP packets and TCP checksum of the packet 132161ae650dSJack F Vogel * should be computed by hardware. Also it should not have VLAN tag in 132261ae650dSJack F Vogel * ethernet header. 132361ae650dSJack F Vogel */ 132461ae650dSJack F Vogel if (rxr->lro_enabled && 132561ae650dSJack F Vogel (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && 132661ae650dSJack F Vogel (m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == 132761ae650dSJack F Vogel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) { 132861ae650dSJack F Vogel /* 132961ae650dSJack F Vogel * Send to the stack if: 133061ae650dSJack F Vogel ** - LRO not enabled, or 133161ae650dSJack F Vogel ** - no LRO resources, or 133261ae650dSJack F Vogel ** - lro enqueue fails 133361ae650dSJack F Vogel */ 133461ae650dSJack F Vogel if (rxr->lro.lro_cnt != 0) 133561ae650dSJack F Vogel if (tcp_lro_rx(&rxr->lro, m, 0) == 0) 133661ae650dSJack F Vogel return; 133761ae650dSJack F Vogel } 1338b3f7259bSBjoern A. Zeeb #endif 133961ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 134061ae650dSJack F Vogel (*ifp->if_input)(ifp, m); 134161ae650dSJack F Vogel IXL_RX_LOCK(rxr); 134261ae650dSJack F Vogel } 134361ae650dSJack F Vogel 134461ae650dSJack F Vogel 134561ae650dSJack F Vogel static __inline void 134661ae650dSJack F Vogel ixl_rx_discard(struct rx_ring *rxr, int i) 134761ae650dSJack F Vogel { 134861ae650dSJack F Vogel struct ixl_rx_buf *rbuf; 134961ae650dSJack F Vogel 135061ae650dSJack F Vogel rbuf = &rxr->buffers[i]; 135161ae650dSJack F Vogel 135261ae650dSJack F Vogel if (rbuf->fmp != NULL) {/* Partial chain ? */ 135361ae650dSJack F Vogel rbuf->fmp->m_flags |= M_PKTHDR; 135461ae650dSJack F Vogel m_freem(rbuf->fmp); 135561ae650dSJack F Vogel rbuf->fmp = NULL; 135661ae650dSJack F Vogel } 135761ae650dSJack F Vogel 135861ae650dSJack F Vogel /* 135961ae650dSJack F Vogel ** With advanced descriptors the writeback 136061ae650dSJack F Vogel ** clobbers the buffer addrs, so its easier 136161ae650dSJack F Vogel ** to just free the existing mbufs and take 136261ae650dSJack F Vogel ** the normal refresh path to get new buffers 136361ae650dSJack F Vogel ** and mapping. 136461ae650dSJack F Vogel */ 136561ae650dSJack F Vogel if (rbuf->m_head) { 136661ae650dSJack F Vogel m_free(rbuf->m_head); 136761ae650dSJack F Vogel rbuf->m_head = NULL; 136861ae650dSJack F Vogel } 136961ae650dSJack F Vogel 137061ae650dSJack F Vogel if (rbuf->m_pack) { 137161ae650dSJack F Vogel m_free(rbuf->m_pack); 137261ae650dSJack F Vogel rbuf->m_pack = NULL; 137361ae650dSJack F Vogel } 137461ae650dSJack F Vogel 137561ae650dSJack F Vogel return; 137661ae650dSJack F Vogel } 137761ae650dSJack F Vogel 13786b30e6aeSJack F Vogel #ifdef RSS 13796b30e6aeSJack F Vogel /* 1380b6c8f260SJack F Vogel ** i40e_ptype_to_hash: parse the packet type 13816b30e6aeSJack F Vogel ** to determine the appropriate hash. 13826b30e6aeSJack F Vogel */ 13836b30e6aeSJack F Vogel static inline int 13846b30e6aeSJack F Vogel ixl_ptype_to_hash(u8 ptype) 13856b30e6aeSJack F Vogel { 13866b30e6aeSJack F Vogel struct i40e_rx_ptype_decoded decoded; 1387b2bdc62aSAdrian Chadd u8 ex = 0; 13886b30e6aeSJack F Vogel 1389dcd7b3b2SJack F Vogel decoded = decode_rx_desc_ptype(ptype); 13906b30e6aeSJack F Vogel ex = decoded.outer_frag; 13916b30e6aeSJack F Vogel 13926b30e6aeSJack F Vogel if (!decoded.known) 13936b30e6aeSJack F Vogel return M_HASHTYPE_OPAQUE; 13946b30e6aeSJack F Vogel 13956b30e6aeSJack F Vogel if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_L2) 13966b30e6aeSJack F Vogel return M_HASHTYPE_OPAQUE; 13976b30e6aeSJack F Vogel 13986b30e6aeSJack F Vogel /* Note: anything that gets to this point is IP */ 13996b30e6aeSJack F Vogel if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) { 14006b30e6aeSJack F Vogel switch (decoded.inner_prot) { 14016b30e6aeSJack F Vogel case I40E_RX_PTYPE_INNER_PROT_TCP: 14026b30e6aeSJack F Vogel if (ex) 14036b30e6aeSJack F Vogel return M_HASHTYPE_RSS_TCP_IPV6_EX; 14046b30e6aeSJack F Vogel else 14056b30e6aeSJack F Vogel return M_HASHTYPE_RSS_TCP_IPV6; 14066b30e6aeSJack F Vogel case I40E_RX_PTYPE_INNER_PROT_UDP: 14076b30e6aeSJack F Vogel if (ex) 14086b30e6aeSJack F Vogel return M_HASHTYPE_RSS_UDP_IPV6_EX; 14096b30e6aeSJack F Vogel else 14106b30e6aeSJack F Vogel return M_HASHTYPE_RSS_UDP_IPV6; 14116b30e6aeSJack F Vogel default: 14126b30e6aeSJack F Vogel if (ex) 14136b30e6aeSJack F Vogel return M_HASHTYPE_RSS_IPV6_EX; 14146b30e6aeSJack F Vogel else 14156b30e6aeSJack F Vogel return M_HASHTYPE_RSS_IPV6; 14166b30e6aeSJack F Vogel } 14176b30e6aeSJack F Vogel } 14186b30e6aeSJack F Vogel if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4) { 14196b30e6aeSJack F Vogel switch (decoded.inner_prot) { 14206b30e6aeSJack F Vogel case I40E_RX_PTYPE_INNER_PROT_TCP: 14216b30e6aeSJack F Vogel return M_HASHTYPE_RSS_TCP_IPV4; 14226b30e6aeSJack F Vogel case I40E_RX_PTYPE_INNER_PROT_UDP: 14236b30e6aeSJack F Vogel if (ex) 14246b30e6aeSJack F Vogel return M_HASHTYPE_RSS_UDP_IPV4_EX; 14256b30e6aeSJack F Vogel else 14266b30e6aeSJack F Vogel return M_HASHTYPE_RSS_UDP_IPV4; 14276b30e6aeSJack F Vogel default: 14286b30e6aeSJack F Vogel return M_HASHTYPE_RSS_IPV4; 14296b30e6aeSJack F Vogel } 14306b30e6aeSJack F Vogel } 14316b30e6aeSJack F Vogel /* We should never get here!! */ 14326b30e6aeSJack F Vogel return M_HASHTYPE_OPAQUE; 14336b30e6aeSJack F Vogel } 14346b30e6aeSJack F Vogel #endif /* RSS */ 143561ae650dSJack F Vogel 143661ae650dSJack F Vogel /********************************************************************* 143761ae650dSJack F Vogel * 143861ae650dSJack F Vogel * This routine executes in interrupt context. It replenishes 143961ae650dSJack F Vogel * the mbufs in the descriptor and sends data which has been 144061ae650dSJack F Vogel * dma'ed into host memory to upper layer. 144161ae650dSJack F Vogel * 144261ae650dSJack F Vogel * We loop at most count times if count is > 0, or until done if 144361ae650dSJack F Vogel * count < 0. 144461ae650dSJack F Vogel * 144561ae650dSJack F Vogel * Return TRUE for more work, FALSE for all clean. 144661ae650dSJack F Vogel *********************************************************************/ 144761ae650dSJack F Vogel bool 144861ae650dSJack F Vogel ixl_rxeof(struct ixl_queue *que, int count) 144961ae650dSJack F Vogel { 145061ae650dSJack F Vogel struct ixl_vsi *vsi = que->vsi; 145161ae650dSJack F Vogel struct rx_ring *rxr = &que->rxr; 145261ae650dSJack F Vogel struct ifnet *ifp = vsi->ifp; 1453b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET) 145461ae650dSJack F Vogel struct lro_ctrl *lro = &rxr->lro; 145561ae650dSJack F Vogel struct lro_entry *queued; 1456b3f7259bSBjoern A. Zeeb #endif 145761ae650dSJack F Vogel int i, nextp, processed = 0; 145861ae650dSJack F Vogel union i40e_rx_desc *cur; 145961ae650dSJack F Vogel struct ixl_rx_buf *rbuf, *nbuf; 146061ae650dSJack F Vogel 146161ae650dSJack F Vogel 146261ae650dSJack F Vogel IXL_RX_LOCK(rxr); 146361ae650dSJack F Vogel 1464e5100ee2SJack F Vogel 146561ae650dSJack F Vogel for (i = rxr->next_check; count != 0;) { 146661ae650dSJack F Vogel struct mbuf *sendmp, *mh, *mp; 146761ae650dSJack F Vogel u32 rsc, status, error; 146861ae650dSJack F Vogel u16 hlen, plen, vtag; 146961ae650dSJack F Vogel u64 qword; 147061ae650dSJack F Vogel u8 ptype; 147161ae650dSJack F Vogel bool eop; 147261ae650dSJack F Vogel 147361ae650dSJack F Vogel /* Sync the ring. */ 147461ae650dSJack F Vogel bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, 147561ae650dSJack F Vogel BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 147661ae650dSJack F Vogel 147761ae650dSJack F Vogel cur = &rxr->base[i]; 147861ae650dSJack F Vogel qword = le64toh(cur->wb.qword1.status_error_len); 147961ae650dSJack F Vogel status = (qword & I40E_RXD_QW1_STATUS_MASK) 148061ae650dSJack F Vogel >> I40E_RXD_QW1_STATUS_SHIFT; 148161ae650dSJack F Vogel error = (qword & I40E_RXD_QW1_ERROR_MASK) 148261ae650dSJack F Vogel >> I40E_RXD_QW1_ERROR_SHIFT; 148361ae650dSJack F Vogel plen = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) 148461ae650dSJack F Vogel >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT; 148561ae650dSJack F Vogel hlen = (qword & I40E_RXD_QW1_LENGTH_HBUF_MASK) 148661ae650dSJack F Vogel >> I40E_RXD_QW1_LENGTH_HBUF_SHIFT; 148761ae650dSJack F Vogel ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) 148861ae650dSJack F Vogel >> I40E_RXD_QW1_PTYPE_SHIFT; 148961ae650dSJack F Vogel 149061ae650dSJack F Vogel if ((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) == 0) { 149161ae650dSJack F Vogel ++rxr->not_done; 149261ae650dSJack F Vogel break; 149361ae650dSJack F Vogel } 149461ae650dSJack F Vogel if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 149561ae650dSJack F Vogel break; 149661ae650dSJack F Vogel 149761ae650dSJack F Vogel count--; 149861ae650dSJack F Vogel sendmp = NULL; 149961ae650dSJack F Vogel nbuf = NULL; 150061ae650dSJack F Vogel rsc = 0; 150161ae650dSJack F Vogel cur->wb.qword1.status_error_len = 0; 150261ae650dSJack F Vogel rbuf = &rxr->buffers[i]; 150361ae650dSJack F Vogel mh = rbuf->m_head; 150461ae650dSJack F Vogel mp = rbuf->m_pack; 150561ae650dSJack F Vogel eop = (status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)); 150661ae650dSJack F Vogel if (status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) 150761ae650dSJack F Vogel vtag = le16toh(cur->wb.qword0.lo_dword.l2tag1); 150861ae650dSJack F Vogel else 150961ae650dSJack F Vogel vtag = 0; 151061ae650dSJack F Vogel 151161ae650dSJack F Vogel /* 151261ae650dSJack F Vogel ** Make sure bad packets are discarded, 151361ae650dSJack F Vogel ** note that only EOP descriptor has valid 151461ae650dSJack F Vogel ** error results. 151561ae650dSJack F Vogel */ 151661ae650dSJack F Vogel if (eop && (error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { 151761ae650dSJack F Vogel rxr->discarded++; 151861ae650dSJack F Vogel ixl_rx_discard(rxr, i); 151961ae650dSJack F Vogel goto next_desc; 152061ae650dSJack F Vogel } 152161ae650dSJack F Vogel 152261ae650dSJack F Vogel /* Prefetch the next buffer */ 152361ae650dSJack F Vogel if (!eop) { 152461ae650dSJack F Vogel nextp = i + 1; 152561ae650dSJack F Vogel if (nextp == que->num_desc) 152661ae650dSJack F Vogel nextp = 0; 152761ae650dSJack F Vogel nbuf = &rxr->buffers[nextp]; 152861ae650dSJack F Vogel prefetch(nbuf); 152961ae650dSJack F Vogel } 153061ae650dSJack F Vogel 153161ae650dSJack F Vogel /* 153261ae650dSJack F Vogel ** The header mbuf is ONLY used when header 153361ae650dSJack F Vogel ** split is enabled, otherwise we get normal 153461ae650dSJack F Vogel ** behavior, ie, both header and payload 153561ae650dSJack F Vogel ** are DMA'd into the payload buffer. 153661ae650dSJack F Vogel ** 153761ae650dSJack F Vogel ** Rather than using the fmp/lmp global pointers 153861ae650dSJack F Vogel ** we now keep the head of a packet chain in the 153961ae650dSJack F Vogel ** buffer struct and pass this along from one 154061ae650dSJack F Vogel ** descriptor to the next, until we get EOP. 154161ae650dSJack F Vogel */ 154261ae650dSJack F Vogel if (rxr->hdr_split && (rbuf->fmp == NULL)) { 154361ae650dSJack F Vogel if (hlen > IXL_RX_HDR) 154461ae650dSJack F Vogel hlen = IXL_RX_HDR; 154561ae650dSJack F Vogel mh->m_len = hlen; 154661ae650dSJack F Vogel mh->m_flags |= M_PKTHDR; 154761ae650dSJack F Vogel mh->m_next = NULL; 154861ae650dSJack F Vogel mh->m_pkthdr.len = mh->m_len; 154961ae650dSJack F Vogel /* Null buf pointer so it is refreshed */ 155061ae650dSJack F Vogel rbuf->m_head = NULL; 155161ae650dSJack F Vogel /* 155261ae650dSJack F Vogel ** Check the payload length, this 155361ae650dSJack F Vogel ** could be zero if its a small 155461ae650dSJack F Vogel ** packet. 155561ae650dSJack F Vogel */ 155661ae650dSJack F Vogel if (plen > 0) { 155761ae650dSJack F Vogel mp->m_len = plen; 155861ae650dSJack F Vogel mp->m_next = NULL; 155961ae650dSJack F Vogel mp->m_flags &= ~M_PKTHDR; 156061ae650dSJack F Vogel mh->m_next = mp; 156161ae650dSJack F Vogel mh->m_pkthdr.len += mp->m_len; 156261ae650dSJack F Vogel /* Null buf pointer so it is refreshed */ 156361ae650dSJack F Vogel rbuf->m_pack = NULL; 156461ae650dSJack F Vogel rxr->split++; 156561ae650dSJack F Vogel } 156661ae650dSJack F Vogel /* 156761ae650dSJack F Vogel ** Now create the forward 156861ae650dSJack F Vogel ** chain so when complete 156961ae650dSJack F Vogel ** we wont have to. 157061ae650dSJack F Vogel */ 157161ae650dSJack F Vogel if (eop == 0) { 157261ae650dSJack F Vogel /* stash the chain head */ 157361ae650dSJack F Vogel nbuf->fmp = mh; 157461ae650dSJack F Vogel /* Make forward chain */ 157561ae650dSJack F Vogel if (plen) 157661ae650dSJack F Vogel mp->m_next = nbuf->m_pack; 157761ae650dSJack F Vogel else 157861ae650dSJack F Vogel mh->m_next = nbuf->m_pack; 157961ae650dSJack F Vogel } else { 158061ae650dSJack F Vogel /* Singlet, prepare to send */ 158161ae650dSJack F Vogel sendmp = mh; 158261ae650dSJack F Vogel if (vtag) { 158361ae650dSJack F Vogel sendmp->m_pkthdr.ether_vtag = vtag; 158461ae650dSJack F Vogel sendmp->m_flags |= M_VLANTAG; 158561ae650dSJack F Vogel } 158661ae650dSJack F Vogel } 158761ae650dSJack F Vogel } else { 158861ae650dSJack F Vogel /* 158961ae650dSJack F Vogel ** Either no header split, or a 159061ae650dSJack F Vogel ** secondary piece of a fragmented 159161ae650dSJack F Vogel ** split packet. 159261ae650dSJack F Vogel */ 159361ae650dSJack F Vogel mp->m_len = plen; 159461ae650dSJack F Vogel /* 159561ae650dSJack F Vogel ** See if there is a stored head 159661ae650dSJack F Vogel ** that determines what we are 159761ae650dSJack F Vogel */ 159861ae650dSJack F Vogel sendmp = rbuf->fmp; 159961ae650dSJack F Vogel rbuf->m_pack = rbuf->fmp = NULL; 160061ae650dSJack F Vogel 160161ae650dSJack F Vogel if (sendmp != NULL) /* secondary frag */ 160261ae650dSJack F Vogel sendmp->m_pkthdr.len += mp->m_len; 160361ae650dSJack F Vogel else { 160461ae650dSJack F Vogel /* first desc of a non-ps chain */ 160561ae650dSJack F Vogel sendmp = mp; 160661ae650dSJack F Vogel sendmp->m_flags |= M_PKTHDR; 160761ae650dSJack F Vogel sendmp->m_pkthdr.len = mp->m_len; 160861ae650dSJack F Vogel if (vtag) { 160961ae650dSJack F Vogel sendmp->m_pkthdr.ether_vtag = vtag; 161061ae650dSJack F Vogel sendmp->m_flags |= M_VLANTAG; 161161ae650dSJack F Vogel } 161261ae650dSJack F Vogel } 161361ae650dSJack F Vogel /* Pass the head pointer on */ 161461ae650dSJack F Vogel if (eop == 0) { 161561ae650dSJack F Vogel nbuf->fmp = sendmp; 161661ae650dSJack F Vogel sendmp = NULL; 161761ae650dSJack F Vogel mp->m_next = nbuf->m_pack; 161861ae650dSJack F Vogel } 161961ae650dSJack F Vogel } 162061ae650dSJack F Vogel ++processed; 162161ae650dSJack F Vogel /* Sending this frame? */ 162261ae650dSJack F Vogel if (eop) { 162361ae650dSJack F Vogel sendmp->m_pkthdr.rcvif = ifp; 162461ae650dSJack F Vogel /* gather stats */ 162561ae650dSJack F Vogel rxr->rx_packets++; 162661ae650dSJack F Vogel rxr->rx_bytes += sendmp->m_pkthdr.len; 162761ae650dSJack F Vogel /* capture data for dynamic ITR adjustment */ 162861ae650dSJack F Vogel rxr->packets++; 162961ae650dSJack F Vogel rxr->bytes += sendmp->m_pkthdr.len; 163061ae650dSJack F Vogel if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 163161ae650dSJack F Vogel ixl_rx_checksum(sendmp, status, error, ptype); 1632845a028fSJack F Vogel #ifdef RSS 16336b30e6aeSJack F Vogel sendmp->m_pkthdr.flowid = 16346b30e6aeSJack F Vogel le32toh(cur->wb.qword0.hi_dword.rss); 16356b30e6aeSJack F Vogel M_HASHTYPE_SET(sendmp, ixl_ptype_to_hash(ptype)); 16366b30e6aeSJack F Vogel #else 163761ae650dSJack F Vogel sendmp->m_pkthdr.flowid = que->msix; 1638845a028fSJack F Vogel M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE); 16396b30e6aeSJack F Vogel #endif 164061ae650dSJack F Vogel } 164161ae650dSJack F Vogel next_desc: 164261ae650dSJack F Vogel bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, 164361ae650dSJack F Vogel BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 164461ae650dSJack F Vogel 164561ae650dSJack F Vogel /* Advance our pointers to the next descriptor. */ 164661ae650dSJack F Vogel if (++i == que->num_desc) 164761ae650dSJack F Vogel i = 0; 164861ae650dSJack F Vogel 164961ae650dSJack F Vogel /* Now send to the stack or do LRO */ 165061ae650dSJack F Vogel if (sendmp != NULL) { 165161ae650dSJack F Vogel rxr->next_check = i; 165261ae650dSJack F Vogel ixl_rx_input(rxr, ifp, sendmp, ptype); 165361ae650dSJack F Vogel i = rxr->next_check; 165461ae650dSJack F Vogel } 165561ae650dSJack F Vogel 165661ae650dSJack F Vogel /* Every 8 descriptors we go to refresh mbufs */ 165761ae650dSJack F Vogel if (processed == 8) { 165861ae650dSJack F Vogel ixl_refresh_mbufs(que, i); 165961ae650dSJack F Vogel processed = 0; 166061ae650dSJack F Vogel } 166161ae650dSJack F Vogel } 166261ae650dSJack F Vogel 166361ae650dSJack F Vogel /* Refresh any remaining buf structs */ 166461ae650dSJack F Vogel if (ixl_rx_unrefreshed(que)) 166561ae650dSJack F Vogel ixl_refresh_mbufs(que, i); 166661ae650dSJack F Vogel 166761ae650dSJack F Vogel rxr->next_check = i; 166861ae650dSJack F Vogel 1669b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET) 167061ae650dSJack F Vogel /* 167161ae650dSJack F Vogel * Flush any outstanding LRO work 167261ae650dSJack F Vogel */ 167361ae650dSJack F Vogel while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { 167461ae650dSJack F Vogel SLIST_REMOVE_HEAD(&lro->lro_active, next); 167561ae650dSJack F Vogel tcp_lro_flush(lro, queued); 167661ae650dSJack F Vogel } 1677b3f7259bSBjoern A. Zeeb #endif 167861ae650dSJack F Vogel 167961ae650dSJack F Vogel IXL_RX_UNLOCK(rxr); 168061ae650dSJack F Vogel return (FALSE); 168161ae650dSJack F Vogel } 168261ae650dSJack F Vogel 168361ae650dSJack F Vogel 168461ae650dSJack F Vogel /********************************************************************* 168561ae650dSJack F Vogel * 168661ae650dSJack F Vogel * Verify that the hardware indicated that the checksum is valid. 168761ae650dSJack F Vogel * Inform the stack about the status of checksum so that stack 168861ae650dSJack F Vogel * doesn't spend time verifying the checksum. 168961ae650dSJack F Vogel * 169061ae650dSJack F Vogel *********************************************************************/ 169161ae650dSJack F Vogel static void 169261ae650dSJack F Vogel ixl_rx_checksum(struct mbuf * mp, u32 status, u32 error, u8 ptype) 169361ae650dSJack F Vogel { 169461ae650dSJack F Vogel struct i40e_rx_ptype_decoded decoded; 169561ae650dSJack F Vogel 169661ae650dSJack F Vogel decoded = decode_rx_desc_ptype(ptype); 169761ae650dSJack F Vogel 169861ae650dSJack F Vogel /* Errors? */ 169961ae650dSJack F Vogel if (error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | 170061ae650dSJack F Vogel (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))) { 170161ae650dSJack F Vogel mp->m_pkthdr.csum_flags = 0; 170261ae650dSJack F Vogel return; 170361ae650dSJack F Vogel } 170461ae650dSJack F Vogel 170561ae650dSJack F Vogel /* IPv6 with extension headers likely have bad csum */ 170661ae650dSJack F Vogel if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && 170761ae650dSJack F Vogel decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) 170861ae650dSJack F Vogel if (status & 170961ae650dSJack F Vogel (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) { 171061ae650dSJack F Vogel mp->m_pkthdr.csum_flags = 0; 171161ae650dSJack F Vogel return; 171261ae650dSJack F Vogel } 171361ae650dSJack F Vogel 171461ae650dSJack F Vogel 171561ae650dSJack F Vogel /* IP Checksum Good */ 171661ae650dSJack F Vogel mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; 171761ae650dSJack F Vogel mp->m_pkthdr.csum_flags |= CSUM_IP_VALID; 171861ae650dSJack F Vogel 171961ae650dSJack F Vogel if (status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)) { 172061ae650dSJack F Vogel mp->m_pkthdr.csum_flags |= 172161ae650dSJack F Vogel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 172261ae650dSJack F Vogel mp->m_pkthdr.csum_data |= htons(0xffff); 172361ae650dSJack F Vogel } 172461ae650dSJack F Vogel return; 172561ae650dSJack F Vogel } 17264b443922SGleb Smirnoff 17274b443922SGleb Smirnoff #if __FreeBSD_version >= 1100000 17284b443922SGleb Smirnoff uint64_t 17294b443922SGleb Smirnoff ixl_get_counter(if_t ifp, ift_counter cnt) 17304b443922SGleb Smirnoff { 17314b443922SGleb Smirnoff struct ixl_vsi *vsi; 17324b443922SGleb Smirnoff 17334b443922SGleb Smirnoff vsi = if_getsoftc(ifp); 17344b443922SGleb Smirnoff 17354b443922SGleb Smirnoff switch (cnt) { 17364b443922SGleb Smirnoff case IFCOUNTER_IPACKETS: 17374b443922SGleb Smirnoff return (vsi->ipackets); 17384b443922SGleb Smirnoff case IFCOUNTER_IERRORS: 17394b443922SGleb Smirnoff return (vsi->ierrors); 17404b443922SGleb Smirnoff case IFCOUNTER_OPACKETS: 17414b443922SGleb Smirnoff return (vsi->opackets); 17424b443922SGleb Smirnoff case IFCOUNTER_OERRORS: 17434b443922SGleb Smirnoff return (vsi->oerrors); 17444b443922SGleb Smirnoff case IFCOUNTER_COLLISIONS: 17454b443922SGleb Smirnoff /* Collisions are by standard impossible in 40G/10G Ethernet */ 17464b443922SGleb Smirnoff return (0); 17474b443922SGleb Smirnoff case IFCOUNTER_IBYTES: 17484b443922SGleb Smirnoff return (vsi->ibytes); 17494b443922SGleb Smirnoff case IFCOUNTER_OBYTES: 17504b443922SGleb Smirnoff return (vsi->obytes); 17514b443922SGleb Smirnoff case IFCOUNTER_IMCASTS: 17524b443922SGleb Smirnoff return (vsi->imcasts); 17534b443922SGleb Smirnoff case IFCOUNTER_OMCASTS: 17544b443922SGleb Smirnoff return (vsi->omcasts); 17554b443922SGleb Smirnoff case IFCOUNTER_IQDROPS: 17564b443922SGleb Smirnoff return (vsi->iqdrops); 17574b443922SGleb Smirnoff case IFCOUNTER_OQDROPS: 17584b443922SGleb Smirnoff return (vsi->oqdrops); 17594b443922SGleb Smirnoff case IFCOUNTER_NOPROTO: 17604b443922SGleb Smirnoff return (vsi->noproto); 17614b443922SGleb Smirnoff default: 17624b443922SGleb Smirnoff return (if_get_counter_default(ifp, cnt)); 17634b443922SGleb Smirnoff } 17644b443922SGleb Smirnoff } 17654b443922SGleb Smirnoff #endif 1766e5100ee2SJack F Vogel 1767