162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <asm/page.h> 3562306a36Sopenharmony_ci#include <linux/mlx4/cq.h> 3662306a36Sopenharmony_ci#include <linux/slab.h> 3762306a36Sopenharmony_ci#include <linux/mlx4/qp.h> 3862306a36Sopenharmony_ci#include <linux/skbuff.h> 3962306a36Sopenharmony_ci#include <linux/if_vlan.h> 4062306a36Sopenharmony_ci#include <linux/prefetch.h> 4162306a36Sopenharmony_ci#include <linux/vmalloc.h> 4262306a36Sopenharmony_ci#include <linux/tcp.h> 4362306a36Sopenharmony_ci#include <linux/ip.h> 4462306a36Sopenharmony_ci#include <linux/ipv6.h> 4562306a36Sopenharmony_ci#include <linux/indirect_call_wrapper.h> 4662306a36Sopenharmony_ci#include <net/ipv6.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include "mlx4_en.h" 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciint mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, 5162306a36Sopenharmony_ci struct mlx4_en_tx_ring **pring, u32 size, 5262306a36Sopenharmony_ci u16 stride, int node, int queue_index) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 5562306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring; 5662306a36Sopenharmony_ci int tmp; 5762306a36Sopenharmony_ci int err; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci ring = kzalloc_node(sizeof(*ring), GFP_KERNEL, node); 6062306a36Sopenharmony_ci if (!ring) { 6162306a36Sopenharmony_ci en_err(priv, "Failed allocating TX ring\n"); 6262306a36Sopenharmony_ci return -ENOMEM; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci ring->size = size; 6662306a36Sopenharmony_ci ring->size_mask = size - 1; 6762306a36Sopenharmony_ci ring->sp_stride = stride; 6862306a36Sopenharmony_ci ring->full_size = ring->size - HEADROOM - MLX4_MAX_DESC_TXBBS; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci tmp = size * sizeof(struct mlx4_en_tx_info); 7162306a36Sopenharmony_ci ring->tx_info = kvmalloc_node(tmp, GFP_KERNEL, node); 7262306a36Sopenharmony_ci if (!ring->tx_info) { 7362306a36Sopenharmony_ci err = -ENOMEM; 7462306a36Sopenharmony_ci goto err_ring; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", 7862306a36Sopenharmony_ci ring->tx_info, tmp); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci ring->bounce_buf = kmalloc_node(MLX4_TX_BOUNCE_BUFFER_SIZE, 8162306a36Sopenharmony_ci GFP_KERNEL, node); 8262306a36Sopenharmony_ci if (!ring->bounce_buf) { 8362306a36Sopenharmony_ci ring->bounce_buf = kmalloc(MLX4_TX_BOUNCE_BUFFER_SIZE, 8462306a36Sopenharmony_ci GFP_KERNEL); 8562306a36Sopenharmony_ci if (!ring->bounce_buf) { 8662306a36Sopenharmony_ci err = -ENOMEM; 8762306a36Sopenharmony_ci goto err_info; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci ring->buf_size = ALIGN(size * ring->sp_stride, MLX4_EN_PAGE_SIZE); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Allocate HW buffers on provided NUMA node */ 9362306a36Sopenharmony_ci set_dev_node(&mdev->dev->persist->pdev->dev, node); 9462306a36Sopenharmony_ci err = mlx4_alloc_hwq_res(mdev->dev, &ring->sp_wqres, ring->buf_size); 9562306a36Sopenharmony_ci set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node); 9662306a36Sopenharmony_ci if (err) { 9762306a36Sopenharmony_ci en_err(priv, "Failed allocating hwq resources\n"); 9862306a36Sopenharmony_ci goto err_bounce; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ring->buf = ring->sp_wqres.buf.direct.buf; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci en_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d buf_size:%d dma:%llx\n", 10462306a36Sopenharmony_ci ring, ring->buf, ring->size, ring->buf_size, 10562306a36Sopenharmony_ci (unsigned long long) ring->sp_wqres.buf.direct.map); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn, 10862306a36Sopenharmony_ci MLX4_RESERVE_ETH_BF_QP, 10962306a36Sopenharmony_ci MLX4_RES_USAGE_DRIVER); 11062306a36Sopenharmony_ci if (err) { 11162306a36Sopenharmony_ci en_err(priv, "failed reserving qp for TX ring\n"); 11262306a36Sopenharmony_ci goto err_hwq_res; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->sp_qp); 11662306a36Sopenharmony_ci if (err) { 11762306a36Sopenharmony_ci en_err(priv, "Failed allocating qp %d\n", ring->qpn); 11862306a36Sopenharmony_ci goto err_reserve; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci ring->sp_qp.event = mlx4_en_sqp_event; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci err = mlx4_bf_alloc(mdev->dev, &ring->bf, node); 12362306a36Sopenharmony_ci if (err) { 12462306a36Sopenharmony_ci en_dbg(DRV, priv, "working without blueflame (%d)\n", err); 12562306a36Sopenharmony_ci ring->bf.uar = &mdev->priv_uar; 12662306a36Sopenharmony_ci ring->bf.uar->map = mdev->uar_map; 12762306a36Sopenharmony_ci ring->bf_enabled = false; 12862306a36Sopenharmony_ci ring->bf_alloced = false; 12962306a36Sopenharmony_ci priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME; 13062306a36Sopenharmony_ci } else { 13162306a36Sopenharmony_ci ring->bf_alloced = true; 13262306a36Sopenharmony_ci ring->bf_enabled = !!(priv->pflags & 13362306a36Sopenharmony_ci MLX4_EN_PRIV_FLAGS_BLUEFLAME); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci ring->doorbell_address = ring->bf.uar->map + MLX4_SEND_DOORBELL; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type; 13862306a36Sopenharmony_ci ring->queue_index = queue_index; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (queue_index < priv->num_tx_rings_p_up) 14162306a36Sopenharmony_ci cpumask_set_cpu(cpumask_local_spread(queue_index, 14262306a36Sopenharmony_ci priv->mdev->dev->numa_node), 14362306a36Sopenharmony_ci &ring->sp_affinity_mask); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci *pring = ring; 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cierr_reserve: 14962306a36Sopenharmony_ci mlx4_qp_release_range(mdev->dev, ring->qpn, 1); 15062306a36Sopenharmony_cierr_hwq_res: 15162306a36Sopenharmony_ci mlx4_free_hwq_res(mdev->dev, &ring->sp_wqres, ring->buf_size); 15262306a36Sopenharmony_cierr_bounce: 15362306a36Sopenharmony_ci kfree(ring->bounce_buf); 15462306a36Sopenharmony_ci ring->bounce_buf = NULL; 15562306a36Sopenharmony_cierr_info: 15662306a36Sopenharmony_ci kvfree(ring->tx_info); 15762306a36Sopenharmony_ci ring->tx_info = NULL; 15862306a36Sopenharmony_cierr_ring: 15962306a36Sopenharmony_ci kfree(ring); 16062306a36Sopenharmony_ci *pring = NULL; 16162306a36Sopenharmony_ci return err; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_civoid mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, 16562306a36Sopenharmony_ci struct mlx4_en_tx_ring **pring) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 16862306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring = *pring; 16962306a36Sopenharmony_ci en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (ring->bf_alloced) 17262306a36Sopenharmony_ci mlx4_bf_free(mdev->dev, &ring->bf); 17362306a36Sopenharmony_ci mlx4_qp_remove(mdev->dev, &ring->sp_qp); 17462306a36Sopenharmony_ci mlx4_qp_free(mdev->dev, &ring->sp_qp); 17562306a36Sopenharmony_ci mlx4_qp_release_range(priv->mdev->dev, ring->qpn, 1); 17662306a36Sopenharmony_ci mlx4_free_hwq_res(mdev->dev, &ring->sp_wqres, ring->buf_size); 17762306a36Sopenharmony_ci kfree(ring->bounce_buf); 17862306a36Sopenharmony_ci ring->bounce_buf = NULL; 17962306a36Sopenharmony_ci kvfree(ring->tx_info); 18062306a36Sopenharmony_ci ring->tx_info = NULL; 18162306a36Sopenharmony_ci kfree(ring); 18262306a36Sopenharmony_ci *pring = NULL; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciint mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, 18662306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring, 18762306a36Sopenharmony_ci int cq, int user_prio) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 19062306a36Sopenharmony_ci int err; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci ring->sp_cqn = cq; 19362306a36Sopenharmony_ci ring->prod = 0; 19462306a36Sopenharmony_ci ring->cons = 0xffffffff; 19562306a36Sopenharmony_ci ring->last_nr_txbb = 1; 19662306a36Sopenharmony_ci memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info)); 19762306a36Sopenharmony_ci memset(ring->buf, 0, ring->buf_size); 19862306a36Sopenharmony_ci ring->free_tx_desc = mlx4_en_free_tx_desc; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ring->sp_qp_state = MLX4_QP_STATE_RST; 20162306a36Sopenharmony_ci ring->doorbell_qpn = cpu_to_be32(ring->sp_qp.qpn << 8); 20262306a36Sopenharmony_ci ring->mr_key = cpu_to_be32(mdev->mr.key); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci mlx4_en_fill_qp_context(priv, ring->size, ring->sp_stride, 1, 0, ring->qpn, 20562306a36Sopenharmony_ci ring->sp_cqn, user_prio, &ring->sp_context); 20662306a36Sopenharmony_ci if (ring->bf_alloced) 20762306a36Sopenharmony_ci ring->sp_context.usr_page = 20862306a36Sopenharmony_ci cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev, 20962306a36Sopenharmony_ci ring->bf.uar->index)); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci err = mlx4_qp_to_ready(mdev->dev, &ring->sp_wqres.mtt, &ring->sp_context, 21262306a36Sopenharmony_ci &ring->sp_qp, &ring->sp_qp_state); 21362306a36Sopenharmony_ci if (!cpumask_empty(&ring->sp_affinity_mask)) 21462306a36Sopenharmony_ci netif_set_xps_queue(priv->dev, &ring->sp_affinity_mask, 21562306a36Sopenharmony_ci ring->queue_index); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return err; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_civoid mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, 22162306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci mlx4_qp_modify(mdev->dev, NULL, ring->sp_qp_state, 22662306a36Sopenharmony_ci MLX4_QP_STATE_RST, NULL, 0, 0, &ring->sp_qp); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic inline bool mlx4_en_is_tx_ring_full(struct mlx4_en_tx_ring *ring) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci u32 used = READ_ONCE(ring->prod) - READ_ONCE(ring->cons); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return used > ring->full_size; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv, 23762306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring, int index, 23862306a36Sopenharmony_ci u8 owner) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT)); 24162306a36Sopenharmony_ci struct mlx4_en_tx_desc *tx_desc = ring->buf + (index << LOG_TXBB_SIZE); 24262306a36Sopenharmony_ci struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; 24362306a36Sopenharmony_ci void *end = ring->buf + ring->buf_size; 24462306a36Sopenharmony_ci __be32 *ptr = (__be32 *)tx_desc; 24562306a36Sopenharmony_ci int i; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Optimize the common case when there are no wraparounds */ 24862306a36Sopenharmony_ci if (likely((void *)tx_desc + 24962306a36Sopenharmony_ci (tx_info->nr_txbb << LOG_TXBB_SIZE) <= end)) { 25062306a36Sopenharmony_ci /* Stamp the freed descriptor */ 25162306a36Sopenharmony_ci for (i = 0; i < tx_info->nr_txbb << LOG_TXBB_SIZE; 25262306a36Sopenharmony_ci i += STAMP_STRIDE) { 25362306a36Sopenharmony_ci *ptr = stamp; 25462306a36Sopenharmony_ci ptr += STAMP_DWORDS; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci } else { 25762306a36Sopenharmony_ci /* Stamp the freed descriptor */ 25862306a36Sopenharmony_ci for (i = 0; i < tx_info->nr_txbb << LOG_TXBB_SIZE; 25962306a36Sopenharmony_ci i += STAMP_STRIDE) { 26062306a36Sopenharmony_ci *ptr = stamp; 26162306a36Sopenharmony_ci ptr += STAMP_DWORDS; 26262306a36Sopenharmony_ci if ((void *)ptr >= end) { 26362306a36Sopenharmony_ci ptr = ring->buf; 26462306a36Sopenharmony_ci stamp ^= cpu_to_be32(0x80000000); 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, 27162306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring, 27262306a36Sopenharmony_ci int index, u64 timestamp, 27362306a36Sopenharmony_ci int napi_mode)); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ciu32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, 27662306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring, 27762306a36Sopenharmony_ci int index, u64 timestamp, 27862306a36Sopenharmony_ci int napi_mode) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; 28162306a36Sopenharmony_ci struct mlx4_en_tx_desc *tx_desc = ring->buf + (index << LOG_TXBB_SIZE); 28262306a36Sopenharmony_ci struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset; 28362306a36Sopenharmony_ci void *end = ring->buf + ring->buf_size; 28462306a36Sopenharmony_ci struct sk_buff *skb = tx_info->skb; 28562306a36Sopenharmony_ci int nr_maps = tx_info->nr_maps; 28662306a36Sopenharmony_ci int i; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* We do not touch skb here, so prefetch skb->users location 28962306a36Sopenharmony_ci * to speedup consume_skb() 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci prefetchw(&skb->users); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (unlikely(timestamp)) { 29462306a36Sopenharmony_ci struct skb_shared_hwtstamps hwts; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci mlx4_en_fill_hwtstamps(priv->mdev, &hwts, timestamp); 29762306a36Sopenharmony_ci skb_tstamp_tx(skb, &hwts); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!tx_info->inl) { 30162306a36Sopenharmony_ci if (tx_info->linear) 30262306a36Sopenharmony_ci dma_unmap_single(priv->ddev, 30362306a36Sopenharmony_ci tx_info->map0_dma, 30462306a36Sopenharmony_ci tx_info->map0_byte_count, 30562306a36Sopenharmony_ci DMA_TO_DEVICE); 30662306a36Sopenharmony_ci else 30762306a36Sopenharmony_ci dma_unmap_page(priv->ddev, 30862306a36Sopenharmony_ci tx_info->map0_dma, 30962306a36Sopenharmony_ci tx_info->map0_byte_count, 31062306a36Sopenharmony_ci DMA_TO_DEVICE); 31162306a36Sopenharmony_ci /* Optimize the common case when there are no wraparounds */ 31262306a36Sopenharmony_ci if (likely((void *)tx_desc + 31362306a36Sopenharmony_ci (tx_info->nr_txbb << LOG_TXBB_SIZE) <= end)) { 31462306a36Sopenharmony_ci for (i = 1; i < nr_maps; i++) { 31562306a36Sopenharmony_ci data++; 31662306a36Sopenharmony_ci dma_unmap_page(priv->ddev, 31762306a36Sopenharmony_ci (dma_addr_t)be64_to_cpu(data->addr), 31862306a36Sopenharmony_ci be32_to_cpu(data->byte_count), 31962306a36Sopenharmony_ci DMA_TO_DEVICE); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } else { 32262306a36Sopenharmony_ci if ((void *)data >= end) 32362306a36Sopenharmony_ci data = ring->buf + ((void *)data - end); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci for (i = 1; i < nr_maps; i++) { 32662306a36Sopenharmony_ci data++; 32762306a36Sopenharmony_ci /* Check for wraparound before unmapping */ 32862306a36Sopenharmony_ci if ((void *) data >= end) 32962306a36Sopenharmony_ci data = ring->buf; 33062306a36Sopenharmony_ci dma_unmap_page(priv->ddev, 33162306a36Sopenharmony_ci (dma_addr_t)be64_to_cpu(data->addr), 33262306a36Sopenharmony_ci be32_to_cpu(data->byte_count), 33362306a36Sopenharmony_ci DMA_TO_DEVICE); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci napi_consume_skb(skb, napi_mode); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return tx_info->nr_txbb; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(u32 mlx4_en_recycle_tx_desc(struct mlx4_en_priv *priv, 34362306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring, 34462306a36Sopenharmony_ci int index, u64 timestamp, 34562306a36Sopenharmony_ci int napi_mode)); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ciu32 mlx4_en_recycle_tx_desc(struct mlx4_en_priv *priv, 34862306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring, 34962306a36Sopenharmony_ci int index, u64 timestamp, 35062306a36Sopenharmony_ci int napi_mode) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; 35362306a36Sopenharmony_ci struct mlx4_en_rx_alloc frame = { 35462306a36Sopenharmony_ci .page = tx_info->page, 35562306a36Sopenharmony_ci .dma = tx_info->map0_dma, 35662306a36Sopenharmony_ci }; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (!napi_mode || !mlx4_en_rx_recycle(ring->recycle_ring, &frame)) { 35962306a36Sopenharmony_ci dma_unmap_page(priv->ddev, tx_info->map0_dma, 36062306a36Sopenharmony_ci PAGE_SIZE, priv->dma_dir); 36162306a36Sopenharmony_ci put_page(tx_info->page); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return tx_info->nr_txbb; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ciint mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 37062306a36Sopenharmony_ci int cnt = 0; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Skip last polled descriptor */ 37362306a36Sopenharmony_ci ring->cons += ring->last_nr_txbb; 37462306a36Sopenharmony_ci en_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", 37562306a36Sopenharmony_ci ring->cons, ring->prod); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if ((u32) (ring->prod - ring->cons) > ring->size) { 37862306a36Sopenharmony_ci if (netif_msg_tx_err(priv)) 37962306a36Sopenharmony_ci en_warn(priv, "Tx consumer passed producer!\n"); 38062306a36Sopenharmony_ci return 0; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci while (ring->cons != ring->prod) { 38462306a36Sopenharmony_ci ring->last_nr_txbb = ring->free_tx_desc(priv, ring, 38562306a36Sopenharmony_ci ring->cons & ring->size_mask, 38662306a36Sopenharmony_ci 0, 0 /* Non-NAPI caller */); 38762306a36Sopenharmony_ci ring->cons += ring->last_nr_txbb; 38862306a36Sopenharmony_ci cnt++; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (ring->tx_queue) 39262306a36Sopenharmony_ci netdev_tx_reset_queue(ring->tx_queue); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (cnt) 39562306a36Sopenharmony_ci en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return cnt; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void mlx4_en_handle_err_cqe(struct mlx4_en_priv *priv, struct mlx4_err_cqe *err_cqe, 40162306a36Sopenharmony_ci u16 cqe_index, struct mlx4_en_tx_ring *ring) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 40462306a36Sopenharmony_ci struct mlx4_en_tx_info *tx_info; 40562306a36Sopenharmony_ci struct mlx4_en_tx_desc *tx_desc; 40662306a36Sopenharmony_ci u16 wqe_index; 40762306a36Sopenharmony_ci int desc_size; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci en_err(priv, "CQE error - cqn 0x%x, ci 0x%x, vendor syndrome: 0x%x syndrome: 0x%x\n", 41062306a36Sopenharmony_ci ring->sp_cqn, cqe_index, err_cqe->vendor_err_syndrome, err_cqe->syndrome); 41162306a36Sopenharmony_ci print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, err_cqe, sizeof(*err_cqe), 41262306a36Sopenharmony_ci false); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci wqe_index = be16_to_cpu(err_cqe->wqe_index) & ring->size_mask; 41562306a36Sopenharmony_ci tx_info = &ring->tx_info[wqe_index]; 41662306a36Sopenharmony_ci desc_size = tx_info->nr_txbb << LOG_TXBB_SIZE; 41762306a36Sopenharmony_ci en_err(priv, "Related WQE - qpn 0x%x, wqe index 0x%x, wqe size 0x%x\n", ring->qpn, 41862306a36Sopenharmony_ci wqe_index, desc_size); 41962306a36Sopenharmony_ci tx_desc = ring->buf + (wqe_index << LOG_TXBB_SIZE); 42062306a36Sopenharmony_ci print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, tx_desc, desc_size, false); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state)) 42362306a36Sopenharmony_ci return; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci en_err(priv, "Scheduling port restart\n"); 42662306a36Sopenharmony_ci queue_work(mdev->workqueue, &priv->restart_task); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciint mlx4_en_process_tx_cq(struct net_device *dev, 43062306a36Sopenharmony_ci struct mlx4_en_cq *cq, int napi_budget) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 43362306a36Sopenharmony_ci struct mlx4_cq *mcq = &cq->mcq; 43462306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->type][cq->ring]; 43562306a36Sopenharmony_ci struct mlx4_cqe *cqe; 43662306a36Sopenharmony_ci u16 index, ring_index, stamp_index; 43762306a36Sopenharmony_ci u32 txbbs_skipped = 0; 43862306a36Sopenharmony_ci u32 txbbs_stamp = 0; 43962306a36Sopenharmony_ci u32 cons_index = mcq->cons_index; 44062306a36Sopenharmony_ci int size = cq->size; 44162306a36Sopenharmony_ci u32 size_mask = ring->size_mask; 44262306a36Sopenharmony_ci struct mlx4_cqe *buf = cq->buf; 44362306a36Sopenharmony_ci u32 packets = 0; 44462306a36Sopenharmony_ci u32 bytes = 0; 44562306a36Sopenharmony_ci int factor = priv->cqe_factor; 44662306a36Sopenharmony_ci int done = 0; 44762306a36Sopenharmony_ci int budget = priv->tx_work_limit; 44862306a36Sopenharmony_ci u32 last_nr_txbb; 44962306a36Sopenharmony_ci u32 ring_cons; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (unlikely(!priv->port_up)) 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci netdev_txq_bql_complete_prefetchw(ring->tx_queue); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci index = cons_index & size_mask; 45762306a36Sopenharmony_ci cqe = mlx4_en_get_cqe(buf, index, priv->cqe_size) + factor; 45862306a36Sopenharmony_ci last_nr_txbb = READ_ONCE(ring->last_nr_txbb); 45962306a36Sopenharmony_ci ring_cons = READ_ONCE(ring->cons); 46062306a36Sopenharmony_ci ring_index = ring_cons & size_mask; 46162306a36Sopenharmony_ci stamp_index = ring_index; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Process all completed CQEs */ 46462306a36Sopenharmony_ci while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, 46562306a36Sopenharmony_ci cons_index & size) && (done < budget)) { 46662306a36Sopenharmony_ci u16 new_index; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * make sure we read the CQE after we read the 47062306a36Sopenharmony_ci * ownership bit 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci dma_rmb(); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == 47562306a36Sopenharmony_ci MLX4_CQE_OPCODE_ERROR)) 47662306a36Sopenharmony_ci if (!test_and_set_bit(MLX4_EN_TX_RING_STATE_RECOVERING, &ring->state)) 47762306a36Sopenharmony_ci mlx4_en_handle_err_cqe(priv, (struct mlx4_err_cqe *)cqe, index, 47862306a36Sopenharmony_ci ring); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Skip over last polled CQE */ 48162306a36Sopenharmony_ci new_index = be16_to_cpu(cqe->wqe_index) & size_mask; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci do { 48462306a36Sopenharmony_ci u64 timestamp = 0; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci txbbs_skipped += last_nr_txbb; 48762306a36Sopenharmony_ci ring_index = (ring_index + last_nr_txbb) & size_mask; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (unlikely(ring->tx_info[ring_index].ts_requested)) 49062306a36Sopenharmony_ci timestamp = mlx4_en_get_cqe_ts(cqe); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* free next descriptor */ 49362306a36Sopenharmony_ci last_nr_txbb = INDIRECT_CALL_2(ring->free_tx_desc, 49462306a36Sopenharmony_ci mlx4_en_free_tx_desc, 49562306a36Sopenharmony_ci mlx4_en_recycle_tx_desc, 49662306a36Sopenharmony_ci priv, ring, ring_index, 49762306a36Sopenharmony_ci timestamp, napi_budget); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci mlx4_en_stamp_wqe(priv, ring, stamp_index, 50062306a36Sopenharmony_ci !!((ring_cons + txbbs_stamp) & 50162306a36Sopenharmony_ci ring->size)); 50262306a36Sopenharmony_ci stamp_index = ring_index; 50362306a36Sopenharmony_ci txbbs_stamp = txbbs_skipped; 50462306a36Sopenharmony_ci packets++; 50562306a36Sopenharmony_ci bytes += ring->tx_info[ring_index].nr_bytes; 50662306a36Sopenharmony_ci } while ((++done < budget) && (ring_index != new_index)); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ++cons_index; 50962306a36Sopenharmony_ci index = cons_index & size_mask; 51062306a36Sopenharmony_ci cqe = mlx4_en_get_cqe(buf, index, priv->cqe_size) + factor; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* 51462306a36Sopenharmony_ci * To prevent CQ overflow we first update CQ consumer and only then 51562306a36Sopenharmony_ci * the ring consumer. 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci mcq->cons_index = cons_index; 51862306a36Sopenharmony_ci mlx4_cq_set_ci(mcq); 51962306a36Sopenharmony_ci wmb(); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* we want to dirty this cache line once */ 52262306a36Sopenharmony_ci WRITE_ONCE(ring->last_nr_txbb, last_nr_txbb); 52362306a36Sopenharmony_ci WRITE_ONCE(ring->cons, ring_cons + txbbs_skipped); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (cq->type == TX_XDP) 52662306a36Sopenharmony_ci return done; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci netdev_tx_completed_queue(ring->tx_queue, packets, bytes); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Wakeup Tx queue if this stopped, and ring is not full. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci if (netif_tx_queue_stopped(ring->tx_queue) && 53362306a36Sopenharmony_ci !mlx4_en_is_tx_ring_full(ring)) { 53462306a36Sopenharmony_ci netif_tx_wake_queue(ring->tx_queue); 53562306a36Sopenharmony_ci ring->wake_queue++; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return done; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_civoid mlx4_en_tx_irq(struct mlx4_cq *mcq) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq); 54462306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(cq->dev); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (likely(priv->port_up)) 54762306a36Sopenharmony_ci napi_schedule_irqoff(&cq->napi); 54862306a36Sopenharmony_ci else 54962306a36Sopenharmony_ci mlx4_en_arm_cq(priv, cq); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci/* TX CQ polling - called by NAPI */ 55362306a36Sopenharmony_ciint mlx4_en_poll_tx_cq(struct napi_struct *napi, int budget) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi); 55662306a36Sopenharmony_ci struct net_device *dev = cq->dev; 55762306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 55862306a36Sopenharmony_ci int work_done; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci work_done = mlx4_en_process_tx_cq(dev, cq, budget); 56162306a36Sopenharmony_ci if (work_done >= budget) 56262306a36Sopenharmony_ci return budget; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (napi_complete_done(napi, work_done)) 56562306a36Sopenharmony_ci mlx4_en_arm_cq(priv, cq); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, 57162306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring, 57262306a36Sopenharmony_ci u32 index, 57362306a36Sopenharmony_ci unsigned int desc_size) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci u32 copy = (ring->size - index) << LOG_TXBB_SIZE; 57662306a36Sopenharmony_ci int i; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci for (i = desc_size - copy - 4; i >= 0; i -= 4) { 57962306a36Sopenharmony_ci if ((i & (TXBB_SIZE - 1)) == 0) 58062306a36Sopenharmony_ci wmb(); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci *((u32 *) (ring->buf + i)) = 58362306a36Sopenharmony_ci *((u32 *) (ring->bounce_buf + copy + i)); 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci for (i = copy - 4; i >= 4 ; i -= 4) { 58762306a36Sopenharmony_ci if ((i & (TXBB_SIZE - 1)) == 0) 58862306a36Sopenharmony_ci wmb(); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci *((u32 *)(ring->buf + (index << LOG_TXBB_SIZE) + i)) = 59162306a36Sopenharmony_ci *((u32 *) (ring->bounce_buf + i)); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* Return real descriptor location */ 59562306a36Sopenharmony_ci return ring->buf + (index << LOG_TXBB_SIZE); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* Decide if skb can be inlined in tx descriptor to avoid dma mapping 59962306a36Sopenharmony_ci * 60062306a36Sopenharmony_ci * It seems strange we do not simply use skb_copy_bits(). 60162306a36Sopenharmony_ci * This would allow to inline all skbs iff skb->len <= inline_thold 60262306a36Sopenharmony_ci * 60362306a36Sopenharmony_ci * Note that caller already checked skb was not a gso packet 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_cistatic bool is_inline(int inline_thold, const struct sk_buff *skb, 60662306a36Sopenharmony_ci const struct skb_shared_info *shinfo, 60762306a36Sopenharmony_ci void **pfrag) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci void *ptr; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (skb->len > inline_thold || !inline_thold) 61262306a36Sopenharmony_ci return false; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (shinfo->nr_frags == 1) { 61562306a36Sopenharmony_ci ptr = skb_frag_address_safe(&shinfo->frags[0]); 61662306a36Sopenharmony_ci if (unlikely(!ptr)) 61762306a36Sopenharmony_ci return false; 61862306a36Sopenharmony_ci *pfrag = ptr; 61962306a36Sopenharmony_ci return true; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci if (shinfo->nr_frags) 62262306a36Sopenharmony_ci return false; 62362306a36Sopenharmony_ci return true; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int inline_size(const struct sk_buff *skb) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci if (skb->len + CTRL_SIZE + sizeof(struct mlx4_wqe_inline_seg) 62962306a36Sopenharmony_ci <= MLX4_INLINE_ALIGN) 63062306a36Sopenharmony_ci return ALIGN(skb->len + CTRL_SIZE + 63162306a36Sopenharmony_ci sizeof(struct mlx4_wqe_inline_seg), 16); 63262306a36Sopenharmony_ci else 63362306a36Sopenharmony_ci return ALIGN(skb->len + CTRL_SIZE + 2 * 63462306a36Sopenharmony_ci sizeof(struct mlx4_wqe_inline_seg), 16); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic int get_real_size(const struct sk_buff *skb, 63862306a36Sopenharmony_ci const struct skb_shared_info *shinfo, 63962306a36Sopenharmony_ci struct net_device *dev, 64062306a36Sopenharmony_ci int *lso_header_size, 64162306a36Sopenharmony_ci bool *inline_ok, 64262306a36Sopenharmony_ci void **pfrag, 64362306a36Sopenharmony_ci int *hopbyhop) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 64662306a36Sopenharmony_ci int real_size; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (shinfo->gso_size) { 64962306a36Sopenharmony_ci *inline_ok = false; 65062306a36Sopenharmony_ci *hopbyhop = 0; 65162306a36Sopenharmony_ci if (skb->encapsulation) { 65262306a36Sopenharmony_ci *lso_header_size = skb_inner_tcp_all_headers(skb); 65362306a36Sopenharmony_ci } else { 65462306a36Sopenharmony_ci /* Detects large IPV6 TCP packets and prepares for removal of 65562306a36Sopenharmony_ci * HBH header that has been pushed by ip6_xmit(), 65662306a36Sopenharmony_ci * mainly so that tcpdump can dissect them. 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_ci if (ipv6_has_hopopt_jumbo(skb)) 65962306a36Sopenharmony_ci *hopbyhop = sizeof(struct hop_jumbo_hdr); 66062306a36Sopenharmony_ci *lso_header_size = skb_tcp_all_headers(skb); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci real_size = CTRL_SIZE + shinfo->nr_frags * DS_SIZE + 66362306a36Sopenharmony_ci ALIGN(*lso_header_size - *hopbyhop + 4, DS_SIZE); 66462306a36Sopenharmony_ci if (unlikely(*lso_header_size != skb_headlen(skb))) { 66562306a36Sopenharmony_ci /* We add a segment for the skb linear buffer only if 66662306a36Sopenharmony_ci * it contains data */ 66762306a36Sopenharmony_ci if (*lso_header_size < skb_headlen(skb)) 66862306a36Sopenharmony_ci real_size += DS_SIZE; 66962306a36Sopenharmony_ci else { 67062306a36Sopenharmony_ci if (netif_msg_tx_err(priv)) 67162306a36Sopenharmony_ci en_warn(priv, "Non-linear headers\n"); 67262306a36Sopenharmony_ci return 0; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci } else { 67662306a36Sopenharmony_ci *lso_header_size = 0; 67762306a36Sopenharmony_ci *inline_ok = is_inline(priv->prof->inline_thold, skb, 67862306a36Sopenharmony_ci shinfo, pfrag); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (*inline_ok) 68162306a36Sopenharmony_ci real_size = inline_size(skb); 68262306a36Sopenharmony_ci else 68362306a36Sopenharmony_ci real_size = CTRL_SIZE + 68462306a36Sopenharmony_ci (shinfo->nr_frags + 1) * DS_SIZE; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return real_size; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, 69162306a36Sopenharmony_ci const struct sk_buff *skb, 69262306a36Sopenharmony_ci const struct skb_shared_info *shinfo, 69362306a36Sopenharmony_ci void *fragptr) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct mlx4_wqe_inline_seg *inl = &tx_desc->inl; 69662306a36Sopenharmony_ci int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - sizeof(*inl); 69762306a36Sopenharmony_ci unsigned int hlen = skb_headlen(skb); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (skb->len <= spc) { 70062306a36Sopenharmony_ci if (likely(skb->len >= MIN_PKT_LEN)) { 70162306a36Sopenharmony_ci inl->byte_count = cpu_to_be32(1 << 31 | skb->len); 70262306a36Sopenharmony_ci } else { 70362306a36Sopenharmony_ci inl->byte_count = cpu_to_be32(1 << 31 | MIN_PKT_LEN); 70462306a36Sopenharmony_ci memset(inl->data + skb->len, 0, 70562306a36Sopenharmony_ci MIN_PKT_LEN - skb->len); 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci skb_copy_from_linear_data(skb, inl->data, hlen); 70862306a36Sopenharmony_ci if (shinfo->nr_frags) 70962306a36Sopenharmony_ci memcpy(inl->data + hlen, fragptr, 71062306a36Sopenharmony_ci skb_frag_size(&shinfo->frags[0])); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci } else { 71362306a36Sopenharmony_ci inl->byte_count = cpu_to_be32(1 << 31 | spc); 71462306a36Sopenharmony_ci if (hlen <= spc) { 71562306a36Sopenharmony_ci skb_copy_from_linear_data(skb, inl->data, hlen); 71662306a36Sopenharmony_ci if (hlen < spc) { 71762306a36Sopenharmony_ci memcpy(inl->data + hlen, 71862306a36Sopenharmony_ci fragptr, spc - hlen); 71962306a36Sopenharmony_ci fragptr += spc - hlen; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci inl = (void *)inl->data + spc; 72262306a36Sopenharmony_ci memcpy(inl->data, fragptr, skb->len - spc); 72362306a36Sopenharmony_ci } else { 72462306a36Sopenharmony_ci skb_copy_from_linear_data(skb, inl->data, spc); 72562306a36Sopenharmony_ci inl = (void *)inl->data + spc; 72662306a36Sopenharmony_ci skb_copy_from_linear_data_offset(skb, spc, inl->data, 72762306a36Sopenharmony_ci hlen - spc); 72862306a36Sopenharmony_ci if (shinfo->nr_frags) 72962306a36Sopenharmony_ci memcpy(inl->data + hlen - spc, 73062306a36Sopenharmony_ci fragptr, 73162306a36Sopenharmony_ci skb_frag_size(&shinfo->frags[0])); 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci dma_wmb(); 73562306a36Sopenharmony_ci inl->byte_count = cpu_to_be32(1 << 31 | (skb->len - spc)); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ciu16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb, 74062306a36Sopenharmony_ci struct net_device *sb_dev) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 74362306a36Sopenharmony_ci u16 rings_p_up = priv->num_tx_rings_p_up; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (netdev_get_num_tc(dev)) 74662306a36Sopenharmony_ci return netdev_pick_tx(dev, skb, NULL); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci return netdev_pick_tx(dev, skb, NULL) % rings_p_up; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic void mlx4_bf_copy(void __iomem *dst, const void *src, 75262306a36Sopenharmony_ci unsigned int bytecnt) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci __iowrite64_copy(dst, src, bytecnt / 8); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_civoid mlx4_en_xmit_doorbell(struct mlx4_en_tx_ring *ring) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci wmb(); 76062306a36Sopenharmony_ci /* Since there is no iowrite*_native() that writes the 76162306a36Sopenharmony_ci * value as is, without byteswapping - using the one 76262306a36Sopenharmony_ci * the doesn't do byteswapping in the relevant arch 76362306a36Sopenharmony_ci * endianness. 76462306a36Sopenharmony_ci */ 76562306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN) 76662306a36Sopenharmony_ci iowrite32( 76762306a36Sopenharmony_ci#else 76862306a36Sopenharmony_ci iowrite32be( 76962306a36Sopenharmony_ci#endif 77062306a36Sopenharmony_ci (__force u32)ring->doorbell_qpn, ring->doorbell_address); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void mlx4_en_tx_write_desc(struct mlx4_en_tx_ring *ring, 77462306a36Sopenharmony_ci struct mlx4_en_tx_desc *tx_desc, 77562306a36Sopenharmony_ci union mlx4_wqe_qpn_vlan qpn_vlan, 77662306a36Sopenharmony_ci int desc_size, int bf_index, 77762306a36Sopenharmony_ci __be32 op_own, bool bf_ok, 77862306a36Sopenharmony_ci bool send_doorbell) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci tx_desc->ctrl.qpn_vlan = qpn_vlan; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (bf_ok) { 78362306a36Sopenharmony_ci op_own |= htonl((bf_index & 0xffff) << 8); 78462306a36Sopenharmony_ci /* Ensure new descriptor hits memory 78562306a36Sopenharmony_ci * before setting ownership of this descriptor to HW 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ci dma_wmb(); 78862306a36Sopenharmony_ci tx_desc->ctrl.owner_opcode = op_own; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci wmb(); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci mlx4_bf_copy(ring->bf.reg + ring->bf.offset, &tx_desc->ctrl, 79362306a36Sopenharmony_ci desc_size); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci wmb(); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci ring->bf.offset ^= ring->bf.buf_size; 79862306a36Sopenharmony_ci } else { 79962306a36Sopenharmony_ci /* Ensure new descriptor hits memory 80062306a36Sopenharmony_ci * before setting ownership of this descriptor to HW 80162306a36Sopenharmony_ci */ 80262306a36Sopenharmony_ci dma_wmb(); 80362306a36Sopenharmony_ci tx_desc->ctrl.owner_opcode = op_own; 80462306a36Sopenharmony_ci if (send_doorbell) 80562306a36Sopenharmony_ci mlx4_en_xmit_doorbell(ring); 80662306a36Sopenharmony_ci else 80762306a36Sopenharmony_ci ring->xmit_more++; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic bool mlx4_en_build_dma_wqe(struct mlx4_en_priv *priv, 81262306a36Sopenharmony_ci struct skb_shared_info *shinfo, 81362306a36Sopenharmony_ci struct mlx4_wqe_data_seg *data, 81462306a36Sopenharmony_ci struct sk_buff *skb, 81562306a36Sopenharmony_ci int lso_header_size, 81662306a36Sopenharmony_ci __be32 mr_key, 81762306a36Sopenharmony_ci struct mlx4_en_tx_info *tx_info) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct device *ddev = priv->ddev; 82062306a36Sopenharmony_ci dma_addr_t dma = 0; 82162306a36Sopenharmony_ci u32 byte_count = 0; 82262306a36Sopenharmony_ci int i_frag; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* Map fragments if any */ 82562306a36Sopenharmony_ci for (i_frag = shinfo->nr_frags - 1; i_frag >= 0; i_frag--) { 82662306a36Sopenharmony_ci const skb_frag_t *frag = &shinfo->frags[i_frag]; 82762306a36Sopenharmony_ci byte_count = skb_frag_size(frag); 82862306a36Sopenharmony_ci dma = skb_frag_dma_map(ddev, frag, 82962306a36Sopenharmony_ci 0, byte_count, 83062306a36Sopenharmony_ci DMA_TO_DEVICE); 83162306a36Sopenharmony_ci if (dma_mapping_error(ddev, dma)) 83262306a36Sopenharmony_ci goto tx_drop_unmap; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci data->addr = cpu_to_be64(dma); 83562306a36Sopenharmony_ci data->lkey = mr_key; 83662306a36Sopenharmony_ci dma_wmb(); 83762306a36Sopenharmony_ci data->byte_count = cpu_to_be32(byte_count); 83862306a36Sopenharmony_ci --data; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* Map linear part if needed */ 84262306a36Sopenharmony_ci if (tx_info->linear) { 84362306a36Sopenharmony_ci byte_count = skb_headlen(skb) - lso_header_size; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci dma = dma_map_single(ddev, skb->data + 84662306a36Sopenharmony_ci lso_header_size, byte_count, 84762306a36Sopenharmony_ci DMA_TO_DEVICE); 84862306a36Sopenharmony_ci if (dma_mapping_error(ddev, dma)) 84962306a36Sopenharmony_ci goto tx_drop_unmap; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci data->addr = cpu_to_be64(dma); 85262306a36Sopenharmony_ci data->lkey = mr_key; 85362306a36Sopenharmony_ci dma_wmb(); 85462306a36Sopenharmony_ci data->byte_count = cpu_to_be32(byte_count); 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci /* tx completion can avoid cache line miss for common cases */ 85762306a36Sopenharmony_ci tx_info->map0_dma = dma; 85862306a36Sopenharmony_ci tx_info->map0_byte_count = byte_count; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci return true; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_citx_drop_unmap: 86362306a36Sopenharmony_ci en_err(priv, "DMA mapping error\n"); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci while (++i_frag < shinfo->nr_frags) { 86662306a36Sopenharmony_ci ++data; 86762306a36Sopenharmony_ci dma_unmap_page(ddev, (dma_addr_t)be64_to_cpu(data->addr), 86862306a36Sopenharmony_ci be32_to_cpu(data->byte_count), 86962306a36Sopenharmony_ci DMA_TO_DEVICE); 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return false; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cinetdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci struct skb_shared_info *shinfo = skb_shinfo(skb); 87862306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 87962306a36Sopenharmony_ci union mlx4_wqe_qpn_vlan qpn_vlan = {}; 88062306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring; 88162306a36Sopenharmony_ci struct mlx4_en_tx_desc *tx_desc; 88262306a36Sopenharmony_ci struct mlx4_wqe_data_seg *data; 88362306a36Sopenharmony_ci struct mlx4_en_tx_info *tx_info; 88462306a36Sopenharmony_ci u32 __maybe_unused ring_cons; 88562306a36Sopenharmony_ci int tx_ind; 88662306a36Sopenharmony_ci int nr_txbb; 88762306a36Sopenharmony_ci int desc_size; 88862306a36Sopenharmony_ci int real_size; 88962306a36Sopenharmony_ci u32 index, bf_index; 89062306a36Sopenharmony_ci struct ipv6hdr *h6; 89162306a36Sopenharmony_ci __be32 op_own; 89262306a36Sopenharmony_ci int lso_header_size; 89362306a36Sopenharmony_ci void *fragptr = NULL; 89462306a36Sopenharmony_ci bool bounce = false; 89562306a36Sopenharmony_ci bool send_doorbell; 89662306a36Sopenharmony_ci bool stop_queue; 89762306a36Sopenharmony_ci bool inline_ok; 89862306a36Sopenharmony_ci u8 data_offset; 89962306a36Sopenharmony_ci int hopbyhop; 90062306a36Sopenharmony_ci bool bf_ok; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci tx_ind = skb_get_queue_mapping(skb); 90362306a36Sopenharmony_ci ring = priv->tx_ring[TX][tx_ind]; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (unlikely(!priv->port_up)) 90662306a36Sopenharmony_ci goto tx_drop; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci real_size = get_real_size(skb, shinfo, dev, &lso_header_size, 90962306a36Sopenharmony_ci &inline_ok, &fragptr, &hopbyhop); 91062306a36Sopenharmony_ci if (unlikely(!real_size)) 91162306a36Sopenharmony_ci goto tx_drop_count; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* Align descriptor to TXBB size */ 91462306a36Sopenharmony_ci desc_size = ALIGN(real_size, TXBB_SIZE); 91562306a36Sopenharmony_ci nr_txbb = desc_size >> LOG_TXBB_SIZE; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci bf_ok = ring->bf_enabled; 91862306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 91962306a36Sopenharmony_ci u16 vlan_proto; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci qpn_vlan.vlan_tag = cpu_to_be16(skb_vlan_tag_get(skb)); 92262306a36Sopenharmony_ci vlan_proto = be16_to_cpu(skb->vlan_proto); 92362306a36Sopenharmony_ci if (vlan_proto == ETH_P_8021AD) 92462306a36Sopenharmony_ci qpn_vlan.ins_vlan = MLX4_WQE_CTRL_INS_SVLAN; 92562306a36Sopenharmony_ci else if (vlan_proto == ETH_P_8021Q) 92662306a36Sopenharmony_ci qpn_vlan.ins_vlan = MLX4_WQE_CTRL_INS_CVLAN; 92762306a36Sopenharmony_ci else 92862306a36Sopenharmony_ci qpn_vlan.ins_vlan = 0; 92962306a36Sopenharmony_ci bf_ok = false; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci netdev_txq_bql_enqueue_prefetchw(ring->tx_queue); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci /* Packet is good - grab an index and transmit it */ 93562306a36Sopenharmony_ci index = ring->prod & ring->size_mask; 93662306a36Sopenharmony_ci bf_index = ring->prod; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* See if we have enough space for whole descriptor TXBB for setting 93962306a36Sopenharmony_ci * SW ownership on next descriptor; if not, use a bounce buffer. */ 94062306a36Sopenharmony_ci if (likely(index + nr_txbb <= ring->size)) 94162306a36Sopenharmony_ci tx_desc = ring->buf + (index << LOG_TXBB_SIZE); 94262306a36Sopenharmony_ci else { 94362306a36Sopenharmony_ci if (unlikely(nr_txbb > MLX4_MAX_DESC_TXBBS)) { 94462306a36Sopenharmony_ci if (netif_msg_tx_err(priv)) 94562306a36Sopenharmony_ci en_warn(priv, "Oversized header or SG list\n"); 94662306a36Sopenharmony_ci goto tx_drop_count; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf; 94962306a36Sopenharmony_ci bounce = true; 95062306a36Sopenharmony_ci bf_ok = false; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci /* Save skb in tx_info ring */ 95462306a36Sopenharmony_ci tx_info = &ring->tx_info[index]; 95562306a36Sopenharmony_ci tx_info->skb = skb; 95662306a36Sopenharmony_ci tx_info->nr_txbb = nr_txbb; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (!lso_header_size) { 95962306a36Sopenharmony_ci data = &tx_desc->data; 96062306a36Sopenharmony_ci data_offset = offsetof(struct mlx4_en_tx_desc, data); 96162306a36Sopenharmony_ci } else { 96262306a36Sopenharmony_ci int lso_align = ALIGN(lso_header_size - hopbyhop + 4, DS_SIZE); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci data = (void *)&tx_desc->lso + lso_align; 96562306a36Sopenharmony_ci data_offset = offsetof(struct mlx4_en_tx_desc, lso) + lso_align; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* valid only for none inline segments */ 96962306a36Sopenharmony_ci tx_info->data_offset = data_offset; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci tx_info->inl = inline_ok; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci tx_info->linear = lso_header_size < skb_headlen(skb) && !inline_ok; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci tx_info->nr_maps = shinfo->nr_frags + tx_info->linear; 97662306a36Sopenharmony_ci data += tx_info->nr_maps - 1; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (!tx_info->inl) 97962306a36Sopenharmony_ci if (!mlx4_en_build_dma_wqe(priv, shinfo, data, skb, 98062306a36Sopenharmony_ci lso_header_size, ring->mr_key, 98162306a36Sopenharmony_ci tx_info)) 98262306a36Sopenharmony_ci goto tx_drop_count; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci /* 98562306a36Sopenharmony_ci * For timestamping add flag to skb_shinfo and 98662306a36Sopenharmony_ci * set flag for further reference 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_ci tx_info->ts_requested = 0; 98962306a36Sopenharmony_ci if (unlikely(ring->hwtstamp_tx_type == HWTSTAMP_TX_ON && 99062306a36Sopenharmony_ci shinfo->tx_flags & SKBTX_HW_TSTAMP)) { 99162306a36Sopenharmony_ci shinfo->tx_flags |= SKBTX_IN_PROGRESS; 99262306a36Sopenharmony_ci tx_info->ts_requested = 1; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* Prepare ctrl segement apart opcode+ownership, which depends on 99662306a36Sopenharmony_ci * whether LSO is used */ 99762306a36Sopenharmony_ci tx_desc->ctrl.srcrb_flags = priv->ctrl_flags; 99862306a36Sopenharmony_ci if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { 99962306a36Sopenharmony_ci if (!skb->encapsulation) 100062306a36Sopenharmony_ci tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM | 100162306a36Sopenharmony_ci MLX4_WQE_CTRL_TCP_UDP_CSUM); 100262306a36Sopenharmony_ci else 100362306a36Sopenharmony_ci tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM); 100462306a36Sopenharmony_ci ring->tx_csum++; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_ENABLE_HW_LOOPBACK) { 100862306a36Sopenharmony_ci struct ethhdr *ethh; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci /* Copy dst mac address to wqe. This allows loopback in eSwitch, 101162306a36Sopenharmony_ci * so that VFs and PF can communicate with each other 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_ci ethh = (struct ethhdr *)skb->data; 101462306a36Sopenharmony_ci tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((__be16 *)ethh->h_dest); 101562306a36Sopenharmony_ci tx_desc->ctrl.imm = get_unaligned((__be32 *)(ethh->h_dest + 2)); 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* Handle LSO (TSO) packets */ 101962306a36Sopenharmony_ci if (lso_header_size) { 102062306a36Sopenharmony_ci int i; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* Mark opcode as LSO */ 102362306a36Sopenharmony_ci op_own = cpu_to_be32(MLX4_OPCODE_LSO | (1 << 6)) | 102462306a36Sopenharmony_ci ((ring->prod & ring->size) ? 102562306a36Sopenharmony_ci cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci lso_header_size -= hopbyhop; 102862306a36Sopenharmony_ci /* Fill in the LSO prefix */ 102962306a36Sopenharmony_ci tx_desc->lso.mss_hdr_size = cpu_to_be32( 103062306a36Sopenharmony_ci shinfo->gso_size << 16 | lso_header_size); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (unlikely(hopbyhop)) { 103462306a36Sopenharmony_ci /* remove the HBH header. 103562306a36Sopenharmony_ci * Layout: [Ethernet header][IPv6 header][HBH][TCP header] 103662306a36Sopenharmony_ci */ 103762306a36Sopenharmony_ci memcpy(tx_desc->lso.header, skb->data, ETH_HLEN + sizeof(*h6)); 103862306a36Sopenharmony_ci h6 = (struct ipv6hdr *)((char *)tx_desc->lso.header + ETH_HLEN); 103962306a36Sopenharmony_ci h6->nexthdr = IPPROTO_TCP; 104062306a36Sopenharmony_ci /* Copy the TCP header after the IPv6 one */ 104162306a36Sopenharmony_ci memcpy(h6 + 1, 104262306a36Sopenharmony_ci skb->data + ETH_HLEN + sizeof(*h6) + 104362306a36Sopenharmony_ci sizeof(struct hop_jumbo_hdr), 104462306a36Sopenharmony_ci tcp_hdrlen(skb)); 104562306a36Sopenharmony_ci /* Leave ipv6 payload_len set to 0, as LSO v2 specs request. */ 104662306a36Sopenharmony_ci } else { 104762306a36Sopenharmony_ci /* Copy headers; 104862306a36Sopenharmony_ci * note that we already verified that it is linear 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ci memcpy(tx_desc->lso.header, skb->data, lso_header_size); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci ring->tso_packets++; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci i = shinfo->gso_segs; 105562306a36Sopenharmony_ci tx_info->nr_bytes = skb->len + (i - 1) * lso_header_size; 105662306a36Sopenharmony_ci ring->packets += i; 105762306a36Sopenharmony_ci } else { 105862306a36Sopenharmony_ci /* Normal (Non LSO) packet */ 105962306a36Sopenharmony_ci op_own = cpu_to_be32(MLX4_OPCODE_SEND) | 106062306a36Sopenharmony_ci ((ring->prod & ring->size) ? 106162306a36Sopenharmony_ci cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0); 106262306a36Sopenharmony_ci tx_info->nr_bytes = max_t(unsigned int, skb->len, ETH_ZLEN); 106362306a36Sopenharmony_ci ring->packets++; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci ring->bytes += tx_info->nr_bytes; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (tx_info->inl) 106862306a36Sopenharmony_ci build_inline_wqe(tx_desc, skb, shinfo, fragptr); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (skb->encapsulation) { 107162306a36Sopenharmony_ci union { 107262306a36Sopenharmony_ci struct iphdr *v4; 107362306a36Sopenharmony_ci struct ipv6hdr *v6; 107462306a36Sopenharmony_ci unsigned char *hdr; 107562306a36Sopenharmony_ci } ip; 107662306a36Sopenharmony_ci u8 proto; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci ip.hdr = skb_inner_network_header(skb); 107962306a36Sopenharmony_ci proto = (ip.v4->version == 4) ? ip.v4->protocol : 108062306a36Sopenharmony_ci ip.v6->nexthdr; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (proto == IPPROTO_TCP || proto == IPPROTO_UDP) 108362306a36Sopenharmony_ci op_own |= cpu_to_be32(MLX4_WQE_CTRL_IIP | MLX4_WQE_CTRL_ILP); 108462306a36Sopenharmony_ci else 108562306a36Sopenharmony_ci op_own |= cpu_to_be32(MLX4_WQE_CTRL_IIP); 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci WRITE_ONCE(ring->prod, ring->prod + nr_txbb); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci /* If we used a bounce buffer then copy descriptor back into place */ 109162306a36Sopenharmony_ci if (unlikely(bounce)) 109262306a36Sopenharmony_ci tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci skb_tx_timestamp(skb); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* Check available TXBBs And 2K spare for prefetch */ 109762306a36Sopenharmony_ci stop_queue = mlx4_en_is_tx_ring_full(ring); 109862306a36Sopenharmony_ci if (unlikely(stop_queue)) { 109962306a36Sopenharmony_ci netif_tx_stop_queue(ring->tx_queue); 110062306a36Sopenharmony_ci ring->queue_stopped++; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci send_doorbell = __netdev_tx_sent_queue(ring->tx_queue, 110462306a36Sopenharmony_ci tx_info->nr_bytes, 110562306a36Sopenharmony_ci netdev_xmit_more()); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci real_size = (real_size / 16) & 0x3f; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci bf_ok &= desc_size <= MAX_BF && send_doorbell; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (bf_ok) 111262306a36Sopenharmony_ci qpn_vlan.bf_qpn = ring->doorbell_qpn | cpu_to_be32(real_size); 111362306a36Sopenharmony_ci else 111462306a36Sopenharmony_ci qpn_vlan.fence_size = real_size; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci mlx4_en_tx_write_desc(ring, tx_desc, qpn_vlan, desc_size, bf_index, 111762306a36Sopenharmony_ci op_own, bf_ok, send_doorbell); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (unlikely(stop_queue)) { 112062306a36Sopenharmony_ci /* If queue was emptied after the if (stop_queue) , and before 112162306a36Sopenharmony_ci * the netif_tx_stop_queue() - need to wake the queue, 112262306a36Sopenharmony_ci * or else it will remain stopped forever. 112362306a36Sopenharmony_ci * Need a memory barrier to make sure ring->cons was not 112462306a36Sopenharmony_ci * updated before queue was stopped. 112562306a36Sopenharmony_ci */ 112662306a36Sopenharmony_ci smp_rmb(); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (unlikely(!mlx4_en_is_tx_ring_full(ring))) { 112962306a36Sopenharmony_ci netif_tx_wake_queue(ring->tx_queue); 113062306a36Sopenharmony_ci ring->wake_queue++; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci return NETDEV_TX_OK; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_citx_drop_count: 113662306a36Sopenharmony_ci ring->tx_dropped++; 113762306a36Sopenharmony_citx_drop: 113862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 113962306a36Sopenharmony_ci return NETDEV_TX_OK; 114062306a36Sopenharmony_ci} 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci#define MLX4_EN_XDP_TX_NRTXBB 1 114362306a36Sopenharmony_ci#define MLX4_EN_XDP_TX_REAL_SZ (((CTRL_SIZE + MLX4_EN_XDP_TX_NRTXBB * DS_SIZE) \ 114462306a36Sopenharmony_ci / 16) & 0x3f) 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_civoid mlx4_en_init_tx_xdp_ring_descs(struct mlx4_en_priv *priv, 114762306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci int i; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci for (i = 0; i < ring->size; i++) { 115262306a36Sopenharmony_ci struct mlx4_en_tx_info *tx_info = &ring->tx_info[i]; 115362306a36Sopenharmony_ci struct mlx4_en_tx_desc *tx_desc = ring->buf + 115462306a36Sopenharmony_ci (i << LOG_TXBB_SIZE); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci tx_info->map0_byte_count = PAGE_SIZE; 115762306a36Sopenharmony_ci tx_info->nr_txbb = MLX4_EN_XDP_TX_NRTXBB; 115862306a36Sopenharmony_ci tx_info->data_offset = offsetof(struct mlx4_en_tx_desc, data); 115962306a36Sopenharmony_ci tx_info->ts_requested = 0; 116062306a36Sopenharmony_ci tx_info->nr_maps = 1; 116162306a36Sopenharmony_ci tx_info->linear = 1; 116262306a36Sopenharmony_ci tx_info->inl = 0; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci tx_desc->data.lkey = ring->mr_key; 116562306a36Sopenharmony_ci tx_desc->ctrl.qpn_vlan.fence_size = MLX4_EN_XDP_TX_REAL_SZ; 116662306a36Sopenharmony_ci tx_desc->ctrl.srcrb_flags = priv->ctrl_flags; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cinetdev_tx_t mlx4_en_xmit_frame(struct mlx4_en_rx_ring *rx_ring, 117162306a36Sopenharmony_ci struct mlx4_en_rx_alloc *frame, 117262306a36Sopenharmony_ci struct mlx4_en_priv *priv, unsigned int length, 117362306a36Sopenharmony_ci int tx_ind, bool *doorbell_pending) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci struct mlx4_en_tx_desc *tx_desc; 117662306a36Sopenharmony_ci struct mlx4_en_tx_info *tx_info; 117762306a36Sopenharmony_ci struct mlx4_wqe_data_seg *data; 117862306a36Sopenharmony_ci struct mlx4_en_tx_ring *ring; 117962306a36Sopenharmony_ci dma_addr_t dma; 118062306a36Sopenharmony_ci __be32 op_own; 118162306a36Sopenharmony_ci int index; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (unlikely(!priv->port_up)) 118462306a36Sopenharmony_ci goto tx_drop; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci ring = priv->tx_ring[TX_XDP][tx_ind]; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (unlikely(mlx4_en_is_tx_ring_full(ring))) 118962306a36Sopenharmony_ci goto tx_drop_count; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci index = ring->prod & ring->size_mask; 119262306a36Sopenharmony_ci tx_info = &ring->tx_info[index]; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci tx_desc = ring->buf + (index << LOG_TXBB_SIZE); 119562306a36Sopenharmony_ci data = &tx_desc->data; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci dma = frame->dma; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci tx_info->page = frame->page; 120062306a36Sopenharmony_ci frame->page = NULL; 120162306a36Sopenharmony_ci tx_info->map0_dma = dma; 120262306a36Sopenharmony_ci tx_info->nr_bytes = max_t(unsigned int, length, ETH_ZLEN); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci dma_sync_single_range_for_device(priv->ddev, dma, frame->page_offset, 120562306a36Sopenharmony_ci length, DMA_TO_DEVICE); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci data->addr = cpu_to_be64(dma + frame->page_offset); 120862306a36Sopenharmony_ci dma_wmb(); 120962306a36Sopenharmony_ci data->byte_count = cpu_to_be32(length); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci /* tx completion can avoid cache line miss for common cases */ 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci op_own = cpu_to_be32(MLX4_OPCODE_SEND) | 121462306a36Sopenharmony_ci ((ring->prod & ring->size) ? 121562306a36Sopenharmony_ci cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci rx_ring->xdp_tx++; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci WRITE_ONCE(ring->prod, ring->prod + MLX4_EN_XDP_TX_NRTXBB); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci /* Ensure new descriptor hits memory 122262306a36Sopenharmony_ci * before setting ownership of this descriptor to HW 122362306a36Sopenharmony_ci */ 122462306a36Sopenharmony_ci dma_wmb(); 122562306a36Sopenharmony_ci tx_desc->ctrl.owner_opcode = op_own; 122662306a36Sopenharmony_ci ring->xmit_more++; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci *doorbell_pending = true; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci return NETDEV_TX_OK; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_citx_drop_count: 123362306a36Sopenharmony_ci rx_ring->xdp_tx_full++; 123462306a36Sopenharmony_ci *doorbell_pending = true; 123562306a36Sopenharmony_citx_drop: 123662306a36Sopenharmony_ci return NETDEV_TX_BUSY; 123762306a36Sopenharmony_ci} 1238