diff options
Diffstat (limited to 'linux/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sg.c')
-rw-r--r-- | linux/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sg.c | 710 |
1 files changed, 0 insertions, 710 deletions
diff --git a/linux/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sg.c b/linux/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sg.c deleted file mode 100644 index 2d0903e3..00000000 --- a/linux/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sg.c +++ /dev/null @@ -1,710 +0,0 @@ -#include <machine/rtems-bsd-kernel-space.h> - -#include <rtems/bsd/local/opt_dpaa.h> - -/* Copyright 2012 - 2015 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/init.h> -#include <linux/skbuff.h> -#include <linux/highmem.h> -#include <soc/fsl/bman.h> - -#include "dpaa_eth.h" -#include "dpaa_eth_common.h" - -/* Convenience macros for storing/retrieving the skb back-pointers. - * - * NB: @off is an offset from a (struct sk_buff **) pointer! - */ -#define DPA_WRITE_SKB_PTR(skb, skbh, addr, off) \ - { \ - skbh = (struct sk_buff **)addr; \ - *(skbh + (off)) = skb; \ - } -#define DPA_READ_SKB_PTR(skb, skbh, addr, off) \ - { \ - skbh = (struct sk_buff **)addr; \ - skb = *(skbh + (off)); \ - } - -/* DMA map and add a page frag back into the bpool. - * @vaddr fragment must have been allocated with netdev_alloc_frag(), - * specifically for fitting into @dpa_bp. - */ -static void dpa_bp_recycle_frag(struct dpa_bp *dpa_bp, unsigned long vaddr, - int *count_ptr) -{ - struct bm_buffer bmb; - dma_addr_t addr; - - addr = dma_map_single(dpa_bp->dev, (void *)vaddr, dpa_bp->size, - DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { - dev_err(dpa_bp->dev, "DMA mapping failed"); - return; - } - - bm_buffer_set64(&bmb, addr); - - while (bman_release(dpa_bp->pool, &bmb, 1, 0)) - cpu_relax(); - - (*count_ptr)++; -} - -static int _dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp) -{ - struct bm_buffer bmb[8]; - void *new_buf; - dma_addr_t addr; - u8 i; - struct device *dev = dpa_bp->dev; - struct sk_buff *skb, **skbh; - - memset(bmb, 0, sizeof(bmb)); - - for (i = 0; i < 8; i++) { - /* We'll prepend the skb back-pointer; can't use the DPA - * priv space, because FMan will overwrite it (from offset 0) - * if it ends up being the second, third, etc. fragment - * in a S/G frame. - * - * We only need enough space to store a pointer, but allocate - * an entire cacheline for performance reasons. - */ - new_buf = netdev_alloc_frag(SMP_CACHE_BYTES + DPA_BP_RAW_SIZE); - if (unlikely(!new_buf)) - goto netdev_alloc_failed; - new_buf = PTR_ALIGN(new_buf + SMP_CACHE_BYTES, SMP_CACHE_BYTES); - - skb = build_skb(new_buf, DPA_SKB_SIZE(dpa_bp->size) + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); - if (unlikely(!skb)) { - put_page(virt_to_head_page(new_buf)); - goto build_skb_failed; - } - DPA_WRITE_SKB_PTR(skb, skbh, new_buf, -1); - - addr = dma_map_single(dev, new_buf, - dpa_bp->size, DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(dev, addr))) - goto dma_map_failed; - - bm_buffer_set64(&bmb[i], addr); - } - -release_bufs: - /* Release the buffers. In case bman is busy, keep trying - * until successful. bman_release() is guaranteed to succeed - * in a reasonable amount of time - */ - while (unlikely(bman_release(dpa_bp->pool, bmb, i, 0))) - cpu_relax(); - return i; - -dma_map_failed: - kfree_skb(skb); - -build_skb_failed: -netdev_alloc_failed: - net_err_ratelimited("dpa_bp_add_8_bufs() failed\n"); - WARN_ONCE(1, "Memory allocation failure on Rx\n"); - - bm_buffer_set64(&bmb[i], 0); - /* Avoid releasing a completely null buffer; bman_release() requires - * at least one buffer. - */ - if (likely(i)) - goto release_bufs; - - return 0; -} - -/* Cold path wrapper over _dpa_bp_add_8_bufs(). */ -static void dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp, int cpu) -{ - int *count_ptr = per_cpu_ptr(dpa_bp->percpu_count, cpu); - *count_ptr += _dpa_bp_add_8_bufs(dpa_bp); -} - -int dpa_bp_priv_seed(struct dpa_bp *dpa_bp) -{ - int i; - - /* Give each CPU an allotment of "config_count" buffers */ - for_each_possible_cpu(i) { - int j; - - /* Although we access another CPU's counters here - * we do it at boot time so it is safe - */ - for (j = 0; j < dpa_bp->config_count; j += 8) - dpa_bp_add_8_bufs(dpa_bp, i); - } - return 0; -} - -/* Add buffers/(pages) for Rx processing whenever bpool count falls below - * REFILL_THRESHOLD. - */ -int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp, int *countptr) -{ - int count = *countptr; - int new_bufs; - - if (unlikely(count < FSL_DPAA_ETH_REFILL_THRESHOLD)) { - do { - new_bufs = _dpa_bp_add_8_bufs(dpa_bp); - if (unlikely(!new_bufs)) { - /* Avoid looping forever if we've temporarily - * run out of memory. We'll try again at the - * next NAPI cycle. - */ - break; - } - count += new_bufs; - } while (count < FSL_DPAA_ETH_MAX_BUF_COUNT); - - *countptr = count; - if (unlikely(count < FSL_DPAA_ETH_MAX_BUF_COUNT)) - return -ENOMEM; - } - - return 0; -} - -/* Cleanup function for outgoing frame descriptors that were built on Tx path, - * either contiguous frames or scatter/gather ones. - * Skb freeing is not handled here. - * - * This function may be called on error paths in the Tx function, so guard - * against cases when not all fd relevant fields were filled in. - * - * Return the skb backpointer, since for S/G frames the buffer containing it - * gets freed here. - */ -struct sk_buff *_dpa_cleanup_tx_fd(const struct dpa_priv_s *priv, - const struct qm_fd *fd) -{ - const struct qm_sg_entry *sgt; - int i; - struct dpa_bp *dpa_bp = priv->dpa_bp; - dma_addr_t addr = qm_fd_addr(fd); - struct sk_buff **skbh; - struct sk_buff *skb = NULL; - const enum dma_data_direction dma_dir = DMA_TO_DEVICE; - int nr_frags; - - - /* retrieve skb back pointer */ - DPA_READ_SKB_PTR(skb, skbh, phys_to_virt(addr), 0); - - if (unlikely(fd->format == qm_fd_sg)) { - nr_frags = skb_shinfo(skb)->nr_frags; - dma_unmap_single(dpa_bp->dev, addr, dpa_fd_offset(fd) + - sizeof(struct qm_sg_entry) * (1 + nr_frags), - dma_dir); - - /* The sgt buffer has been allocated with netdev_alloc_frag(), - * it's from lowmem. - */ - sgt = phys_to_virt(addr + dpa_fd_offset(fd)); - - /* sgt[0] is from lowmem, was dma_map_single()-ed */ - dma_unmap_single(dpa_bp->dev, (dma_addr_t)sgt[0].addr, - sgt[0].length, dma_dir); - - /* remaining pages were mapped with dma_map_page() */ - for (i = 1; i < nr_frags; i++) { - DPA_ERR_ON(sgt[i].extension); - - dma_unmap_page(dpa_bp->dev, (dma_addr_t)sgt[i].addr, - sgt[i].length, dma_dir); - } - - /* Free the page frag that we allocated on Tx */ - put_page(virt_to_head_page(sgt)); - } else { - dma_unmap_single(dpa_bp->dev, addr, - skb_tail_pointer(skb) - (u8 *)skbh, dma_dir); - } - - return skb; -} - -/* Build a linear skb around the received buffer. - * We are guaranteed there is enough room at the end of the data buffer to - * accommodate the shared info area of the skb. - */ -static struct sk_buff *contig_fd_to_skb(const struct dpa_priv_s *priv, - const struct qm_fd *fd) -{ - struct sk_buff *skb = NULL, **skbh; - ssize_t fd_off = dpa_fd_offset(fd); - dma_addr_t addr = qm_fd_addr(fd); - void *vaddr; - - vaddr = phys_to_virt(addr); - DPA_ERR_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES)); - - /* Retrieve the skb and adjust data and tail pointers, to make sure - * forwarded skbs will have enough space on Tx if extra headers - * are added. - */ - DPA_READ_SKB_PTR(skb, skbh, vaddr, -1); - - DPA_ERR_ON(fd_off != priv->rx_headroom); - skb_reserve(skb, fd_off); - skb_put(skb, dpa_fd_length(fd)); - - skb->ip_summed = CHECKSUM_NONE; - - return skb; -} - -/* Build an skb with the data of the first S/G entry in the linear portion and - * the rest of the frame as skb fragments. - * - * The page fragment holding the S/G Table is recycled here. - */ -static struct sk_buff *sg_fd_to_skb(const struct dpa_priv_s *priv, - const struct qm_fd *fd, - int *count_ptr) -{ - const struct qm_sg_entry *sgt; - dma_addr_t addr = qm_fd_addr(fd); - ssize_t fd_off = dpa_fd_offset(fd); - dma_addr_t sg_addr; - void *vaddr, *sg_vaddr; - struct dpa_bp *dpa_bp; - struct page *page, *head_page; - int frag_offset, frag_len; - int page_offset; - int i; - struct sk_buff *skb = NULL, *skb_tmp, **skbh; - - vaddr = phys_to_virt(addr); - DPA_ERR_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES)); - - dpa_bp = priv->dpa_bp; - /* Iterate through the SGT entries and add data buffers to the skb */ - sgt = vaddr + fd_off; - for (i = 0; i < DPA_SGT_MAX_ENTRIES; i++) { - /* Extension bit is not supported */ - DPA_ERR_ON(sgt[i].extension); - - /* We use a single global Rx pool */ - DPA_ERR_ON(dpa_bp != dpa_bpid2pool(sgt[i].bpid)); - - sg_addr = qm_sg_addr(&sgt[i]); - sg_vaddr = phys_to_virt(sg_addr); - DPA_ERR_ON(!IS_ALIGNED((unsigned long)sg_vaddr, - SMP_CACHE_BYTES)); - - dma_unmap_single(dpa_bp->dev, sg_addr, dpa_bp->size, - DMA_BIDIRECTIONAL); - if (i == 0) { - DPA_READ_SKB_PTR(skb, skbh, sg_vaddr, -1); - DPA_ERR_ON(skb->head != sg_vaddr); - - skb->ip_summed = CHECKSUM_NONE; - - /* Make sure forwarded skbs will have enough space - * on Tx, if extra headers are added. - */ - DPA_ERR_ON(fd_off != priv->rx_headroom); - skb_reserve(skb, fd_off); - skb_put(skb, sgt[i].length); - } else { - /* Not the first S/G entry; all data from buffer will - * be added in an skb fragment; fragment index is offset - * by one since first S/G entry was incorporated in the - * linear part of the skb. - * - * Caution: 'page' may be a tail page. - */ - DPA_READ_SKB_PTR(skb_tmp, skbh, sg_vaddr, -1); - page = virt_to_page(sg_vaddr); - head_page = virt_to_head_page(sg_vaddr); - - /* Free (only) the skbuff shell because its data buffer - * is already a frag in the main skb. - */ - get_page(head_page); - dev_kfree_skb(skb_tmp); - - /* Compute offset in (possibly tail) page */ - page_offset = ((unsigned long)sg_vaddr & - (PAGE_SIZE - 1)) + - (page_address(page) - page_address(head_page)); - /* page_offset only refers to the beginning of sgt[i]; - * but the buffer itself may have an internal offset. - */ - frag_offset = sgt[i].offset + page_offset; - frag_len = sgt[i].length; - /* skb_add_rx_frag() does no checking on the page; if - * we pass it a tail page, we'll end up with - * bad page accounting and eventually with segafults. - */ - skb_add_rx_frag(skb, i - 1, head_page, frag_offset, - frag_len, dpa_bp->size); - } - /* Update the pool count for the current {cpu x bpool} */ - (*count_ptr)--; - - if (sgt[i].final) - break; - } - WARN_ONCE(i == DPA_SGT_MAX_ENTRIES, "No final bit on SGT\n"); - - /* recycle the SGT fragment */ - DPA_ERR_ON(dpa_bp != dpa_bpid2pool(fd->bpid)); - dpa_bp_recycle_frag(dpa_bp, (unsigned long)vaddr, count_ptr); - return skb; -} - -void _dpa_rx(struct net_device *net_dev, - struct qman_portal *portal, - const struct dpa_priv_s *priv, - struct dpa_percpu_priv_s *percpu_priv, - const struct qm_fd *fd, - u32 fqid, - int *count_ptr) -{ - struct dpa_bp *dpa_bp; - struct sk_buff *skb; - dma_addr_t addr = qm_fd_addr(fd); - u32 fd_status = fd->status; - unsigned int skb_len; - struct rtnl_link_stats64 *percpu_stats = &percpu_priv->stats; - - if (unlikely(fd_status & FM_FD_STAT_RX_ERRORS) != 0) { - if (net_ratelimit()) - netif_warn(priv, hw, net_dev, "FD status = 0x%08x\n", - fd_status & FM_FD_STAT_RX_ERRORS); - - percpu_stats->rx_errors++; - goto _release_frame; - } - - dpa_bp = priv->dpa_bp; - DPA_ERR_ON(dpa_bp != dpa_bpid2pool(fd->bpid)); - - /* prefetch the first 64 bytes of the frame or the SGT start */ - dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL); - prefetch(phys_to_virt(addr) + dpa_fd_offset(fd)); - - /* The only FD types that we may receive are contig and S/G */ - DPA_ERR_ON((fd->format != qm_fd_contig) && (fd->format != qm_fd_sg)); - - if (likely(fd->format == qm_fd_contig)) - skb = contig_fd_to_skb(priv, fd); - else - skb = sg_fd_to_skb(priv, fd, count_ptr); - - /* Account for either the contig buffer or the SGT buffer (depending on - * which case we were in) having been removed from the pool. - */ - (*count_ptr)--; - skb->protocol = eth_type_trans(skb, net_dev); - - /* IP Reassembled frames are allowed to be larger than MTU */ - if (unlikely(dpa_check_rx_mtu(skb, net_dev->mtu) && - !(fd_status & FM_FD_IPR))) { - percpu_stats->rx_dropped++; - goto drop_bad_frame; - } - - skb_len = skb->len; - - if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) - goto packet_dropped; - - percpu_stats->rx_packets++; - percpu_stats->rx_bytes += skb_len; - -packet_dropped: - return; - -drop_bad_frame: - dev_kfree_skb(skb); - return; - -_release_frame: - dpa_fd_release(net_dev, fd); -} - -static int skb_to_contig_fd(struct dpa_priv_s *priv, - struct sk_buff *skb, struct qm_fd *fd, - int *count_ptr, int *offset) -{ - struct sk_buff **skbh; - dma_addr_t addr; - struct dpa_bp *dpa_bp = priv->dpa_bp; - struct net_device *net_dev = priv->net_dev; - int err; - enum dma_data_direction dma_dir; - unsigned char *buffer_start; - - { - /* We are guaranteed to have at least tx_headroom bytes - * available, so just use that for offset. - */ - fd->bpid = 0xff; - buffer_start = skb->data - priv->tx_headroom; - fd->offset = priv->tx_headroom; - dma_dir = DMA_TO_DEVICE; - - DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, 0); - } - - /* Enable L3/L4 hardware checksum computation. - * - * We must do this before dma_map_single(DMA_TO_DEVICE), because we may - * need to write into the skb. - */ - err = dpa_enable_tx_csum(priv, skb, fd, - ((char *)skbh) + DPA_TX_PRIV_DATA_SIZE); - if (unlikely(err < 0)) { - if (net_ratelimit()) - netif_err(priv, tx_err, net_dev, "HW csum error: %d\n", - err); - return err; - } - - /* Fill in the rest of the FD fields */ - fd->format = qm_fd_contig; - fd->length20 = skb->len; - fd->cmd |= FM_FD_CMD_FCO; - - /* Map the entire buffer size that may be seen by FMan, but no more */ - addr = dma_map_single(dpa_bp->dev, skbh, - skb_tail_pointer(skb) - buffer_start, dma_dir); - if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { - if (net_ratelimit()) - netif_err(priv, tx_err, net_dev, "dma_map_single() failed\n"); - return -EINVAL; - } - fd->addr_hi = (u8)upper_32_bits(addr); - fd->addr_lo = lower_32_bits(addr); - - return 0; -} - -static int skb_to_sg_fd(struct dpa_priv_s *priv, - struct sk_buff *skb, struct qm_fd *fd) -{ - struct dpa_bp *dpa_bp = priv->dpa_bp; - dma_addr_t addr; - struct sk_buff **skbh; - struct net_device *net_dev = priv->net_dev; - int err; - - struct qm_sg_entry *sgt; - void *sgt_buf; - void *buffer_start; - skb_frag_t *frag; - int i, j; - const enum dma_data_direction dma_dir = DMA_TO_DEVICE; - const int nr_frags = skb_shinfo(skb)->nr_frags; - - fd->format = qm_fd_sg; - - /* get a page frag to store the SGTable */ - sgt_buf = netdev_alloc_frag(priv->tx_headroom + - sizeof(struct qm_sg_entry) * (1 + nr_frags)); - if (unlikely(!sgt_buf)) { - netdev_err(net_dev, "netdev_alloc_frag() failed\n"); - return -ENOMEM; - } - - /* Enable L3/L4 hardware checksum computation. - * - * We must do this before dma_map_single(DMA_TO_DEVICE), because we may - * need to write into the skb. - */ - err = dpa_enable_tx_csum(priv, skb, fd, - sgt_buf + DPA_TX_PRIV_DATA_SIZE); - if (unlikely(err < 0)) { - if (net_ratelimit()) - netif_err(priv, tx_err, net_dev, "HW csum error: %d\n", - err); - goto csum_failed; - } - - sgt = (struct qm_sg_entry *)(sgt_buf + priv->tx_headroom); - sgt[0].bpid = 0xff; - sgt[0].offset = 0; - sgt[0].length = cpu_to_be32(skb_headlen(skb)); - sgt[0].extension = 0; - sgt[0].final = 0; - addr = dma_map_single(dpa_bp->dev, skb->data, sgt[0].length, dma_dir); - if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { - dev_err(dpa_bp->dev, "DMA mapping failed"); - err = -EINVAL; - goto sg0_map_failed; - } - sgt[0].addr_hi = (u8)upper_32_bits(addr); - sgt[0].addr_lo = cpu_to_be32(lower_32_bits(addr)); - - /* populate the rest of SGT entries */ - for (i = 1; i <= nr_frags; i++) { - frag = &skb_shinfo(skb)->frags[i - 1]; - sgt[i].bpid = 0xff; - sgt[i].offset = 0; - sgt[i].length = cpu_to_be32(frag->size); - sgt[i].extension = 0; - sgt[i].final = 0; - - DPA_ERR_ON(!skb_frag_page(frag)); - addr = skb_frag_dma_map(dpa_bp->dev, frag, 0, sgt[i].length, - dma_dir); - if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { - dev_err(dpa_bp->dev, "DMA mapping failed"); - err = -EINVAL; - goto sg_map_failed; - } - - /* keep the offset in the address */ - sgt[i].addr_hi = (u8)upper_32_bits(addr); - sgt[i].addr_lo = cpu_to_be32(lower_32_bits(addr)); - } - sgt[i - 1].final = 1; - - fd->length20 = skb->len; - fd->offset = priv->tx_headroom; - - /* DMA map the SGT page */ - buffer_start = (void *)sgt - priv->tx_headroom; - DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, 0); - - addr = dma_map_single(dpa_bp->dev, buffer_start, priv->tx_headroom + - sizeof(struct qm_sg_entry) * (1 + nr_frags), - dma_dir); - if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { - dev_err(dpa_bp->dev, "DMA mapping failed"); - err = -EINVAL; - goto sgt_map_failed; - } - - fd->bpid = 0xff; - fd->cmd |= FM_FD_CMD_FCO; - fd->addr_hi = (u8)upper_32_bits(addr); - fd->addr_lo = lower_32_bits(addr); - - return 0; - -sgt_map_failed: -sg_map_failed: - for (j = 0; j < i; j++) - dma_unmap_page(dpa_bp->dev, qm_sg_addr(&sgt[j]), - cpu_to_be32(sgt[j].length), dma_dir); -sg0_map_failed: -csum_failed: - put_page(virt_to_head_page(sgt_buf)); - - return err; -} - -int dpa_tx(struct sk_buff *skb, struct net_device *net_dev) -{ - struct dpa_priv_s *priv; - struct qm_fd fd; - struct dpa_percpu_priv_s *percpu_priv; - struct rtnl_link_stats64 *percpu_stats; - int err = 0; - const int queue_mapping = dpa_get_queue_mapping(skb); - bool nonlinear = skb_is_nonlinear(skb); - int *countptr, offset = 0; - - priv = netdev_priv(net_dev); - /* Non-migratable context, safe to use raw_cpu_ptr */ - percpu_priv = raw_cpu_ptr(priv->percpu_priv); - percpu_stats = &percpu_priv->stats; - countptr = raw_cpu_ptr(priv->dpa_bp->percpu_count); - - clear_fd(&fd); - - if (!nonlinear) { - /* We're going to store the skb backpointer at the beginning - * of the data buffer, so we need a privately owned skb - * - * We've made sure skb is not shared in dev->priv_flags, - * we need to verify the skb head is not cloned - */ - if (skb_cow_head(skb, priv->tx_headroom)) - goto enomem; - - BUG_ON(skb_is_nonlinear(skb)); - } - - /* MAX_SKB_FRAGS is equal or larger than our DPA_SGT_MAX_ENTRIES; - * make sure we don't feed FMan with more fragments than it supports. - * Btw, we're using the first sgt entry to store the linear part of - * the skb, so we're one extra frag short. - */ - if (nonlinear && - likely(skb_shinfo(skb)->nr_frags < DPA_SGT_MAX_ENTRIES)) { - /* Just create a S/G fd based on the skb */ - err = skb_to_sg_fd(priv, skb, &fd); - percpu_priv->tx_frag_skbuffs++; - } else { - /* If the egress skb contains more fragments than we support - * we have no choice but to linearize it ourselves. - */ - if (unlikely(nonlinear) && __skb_linearize(skb)) - goto enomem; - - /* Finally, create a contig FD from this skb */ - err = skb_to_contig_fd(priv, skb, &fd, countptr, &offset); - } - if (unlikely(err < 0)) - goto skb_to_fd_failed; - - if (likely(dpa_xmit(priv, percpu_stats, queue_mapping, &fd) == 0)) - return NETDEV_TX_OK; - - /* dpa_xmit failed */ - if (fd.bpid != 0xff) { - (*countptr)--; - dpa_fd_release(net_dev, &fd); - percpu_stats->tx_errors++; - return NETDEV_TX_OK; - } - _dpa_cleanup_tx_fd(priv, &fd); -skb_to_fd_failed: -enomem: - percpu_stats->tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} |