162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2019 Netronome Systems, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/seq_file.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "../nfp_net.h" 762306a36Sopenharmony_ci#include "../nfp_net_dp.h" 862306a36Sopenharmony_ci#include "nfdk.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic void 1162306a36Sopenharmony_cinfp_nfdk_tx_ring_reset(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci struct device *dev = dp->dev; 1462306a36Sopenharmony_ci struct netdev_queue *nd_q; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci while (!tx_ring->is_xdp && tx_ring->rd_p != tx_ring->wr_p) { 1762306a36Sopenharmony_ci const skb_frag_t *frag, *fend; 1862306a36Sopenharmony_ci unsigned int size, n_descs = 1; 1962306a36Sopenharmony_ci struct nfp_nfdk_tx_buf *txbuf; 2062306a36Sopenharmony_ci int nr_frags, rd_idx; 2162306a36Sopenharmony_ci struct sk_buff *skb; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci rd_idx = D_IDX(tx_ring, tx_ring->rd_p); 2462306a36Sopenharmony_ci txbuf = &tx_ring->ktxbufs[rd_idx]; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci skb = txbuf->skb; 2762306a36Sopenharmony_ci if (!skb) { 2862306a36Sopenharmony_ci n_descs = D_BLOCK_CPL(tx_ring->rd_p); 2962306a36Sopenharmony_ci goto next; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 3362306a36Sopenharmony_ci txbuf++; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* Unmap head */ 3662306a36Sopenharmony_ci size = skb_headlen(skb); 3762306a36Sopenharmony_ci dma_unmap_single(dev, txbuf->dma_addr, size, DMA_TO_DEVICE); 3862306a36Sopenharmony_ci n_descs += nfp_nfdk_headlen_to_segs(size); 3962306a36Sopenharmony_ci txbuf++; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci frag = skb_shinfo(skb)->frags; 4262306a36Sopenharmony_ci fend = frag + nr_frags; 4362306a36Sopenharmony_ci for (; frag < fend; frag++) { 4462306a36Sopenharmony_ci size = skb_frag_size(frag); 4562306a36Sopenharmony_ci dma_unmap_page(dev, txbuf->dma_addr, 4662306a36Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 4762306a36Sopenharmony_ci n_descs += DIV_ROUND_UP(size, 4862306a36Sopenharmony_ci NFDK_TX_MAX_DATA_PER_DESC); 4962306a36Sopenharmony_ci txbuf++; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (skb_is_gso(skb)) 5362306a36Sopenharmony_ci n_descs++; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 5662306a36Sopenharmony_cinext: 5762306a36Sopenharmony_ci tx_ring->rd_p += n_descs; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci memset(tx_ring->txds, 0, tx_ring->size); 6162306a36Sopenharmony_ci tx_ring->data_pending = 0; 6262306a36Sopenharmony_ci tx_ring->wr_p = 0; 6362306a36Sopenharmony_ci tx_ring->rd_p = 0; 6462306a36Sopenharmony_ci tx_ring->qcp_rd_p = 0; 6562306a36Sopenharmony_ci tx_ring->wr_ptr_add = 0; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (tx_ring->is_xdp || !dp->netdev) 6862306a36Sopenharmony_ci return; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci nd_q = netdev_get_tx_queue(dp->netdev, tx_ring->idx); 7162306a36Sopenharmony_ci netdev_tx_reset_queue(nd_q); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic void nfp_nfdk_tx_ring_free(struct nfp_net_tx_ring *tx_ring) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct nfp_net_r_vector *r_vec = tx_ring->r_vec; 7762306a36Sopenharmony_ci struct nfp_net_dp *dp = &r_vec->nfp_net->dp; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci kvfree(tx_ring->ktxbufs); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (tx_ring->ktxds) 8262306a36Sopenharmony_ci dma_free_coherent(dp->dev, tx_ring->size, 8362306a36Sopenharmony_ci tx_ring->ktxds, tx_ring->dma); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci tx_ring->cnt = 0; 8662306a36Sopenharmony_ci tx_ring->txbufs = NULL; 8762306a36Sopenharmony_ci tx_ring->txds = NULL; 8862306a36Sopenharmony_ci tx_ring->dma = 0; 8962306a36Sopenharmony_ci tx_ring->size = 0; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int 9362306a36Sopenharmony_cinfp_nfdk_tx_ring_alloc(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct nfp_net_r_vector *r_vec = tx_ring->r_vec; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci tx_ring->cnt = dp->txd_cnt * NFDK_TX_DESC_PER_SIMPLE_PKT; 9862306a36Sopenharmony_ci tx_ring->size = array_size(tx_ring->cnt, sizeof(*tx_ring->ktxds)); 9962306a36Sopenharmony_ci tx_ring->ktxds = dma_alloc_coherent(dp->dev, tx_ring->size, 10062306a36Sopenharmony_ci &tx_ring->dma, 10162306a36Sopenharmony_ci GFP_KERNEL | __GFP_NOWARN); 10262306a36Sopenharmony_ci if (!tx_ring->ktxds) { 10362306a36Sopenharmony_ci netdev_warn(dp->netdev, "failed to allocate TX descriptor ring memory, requested descriptor count: %d, consider lowering descriptor count\n", 10462306a36Sopenharmony_ci tx_ring->cnt); 10562306a36Sopenharmony_ci goto err_alloc; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci tx_ring->ktxbufs = kvcalloc(tx_ring->cnt, sizeof(*tx_ring->ktxbufs), 10962306a36Sopenharmony_ci GFP_KERNEL); 11062306a36Sopenharmony_ci if (!tx_ring->ktxbufs) 11162306a36Sopenharmony_ci goto err_alloc; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!tx_ring->is_xdp && dp->netdev) 11462306a36Sopenharmony_ci netif_set_xps_queue(dp->netdev, &r_vec->affinity_mask, 11562306a36Sopenharmony_ci tx_ring->idx); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cierr_alloc: 12062306a36Sopenharmony_ci nfp_nfdk_tx_ring_free(tx_ring); 12162306a36Sopenharmony_ci return -ENOMEM; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void 12562306a36Sopenharmony_cinfp_nfdk_tx_ring_bufs_free(struct nfp_net_dp *dp, 12662306a36Sopenharmony_ci struct nfp_net_tx_ring *tx_ring) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int 13162306a36Sopenharmony_cinfp_nfdk_tx_ring_bufs_alloc(struct nfp_net_dp *dp, 13262306a36Sopenharmony_ci struct nfp_net_tx_ring *tx_ring) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void 13862306a36Sopenharmony_cinfp_nfdk_print_tx_descs(struct seq_file *file, 13962306a36Sopenharmony_ci struct nfp_net_r_vector *r_vec, 14062306a36Sopenharmony_ci struct nfp_net_tx_ring *tx_ring, 14162306a36Sopenharmony_ci u32 d_rd_p, u32 d_wr_p) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct nfp_nfdk_tx_desc *txd; 14462306a36Sopenharmony_ci u32 txd_cnt = tx_ring->cnt; 14562306a36Sopenharmony_ci int i; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci for (i = 0; i < txd_cnt; i++) { 14862306a36Sopenharmony_ci txd = &tx_ring->ktxds[i]; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci seq_printf(file, "%04d: 0x%08x 0x%08x 0x%016llx", i, 15162306a36Sopenharmony_ci txd->vals[0], txd->vals[1], tx_ring->ktxbufs[i].raw); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (i == tx_ring->rd_p % txd_cnt) 15462306a36Sopenharmony_ci seq_puts(file, " H_RD"); 15562306a36Sopenharmony_ci if (i == tx_ring->wr_p % txd_cnt) 15662306a36Sopenharmony_ci seq_puts(file, " H_WR"); 15762306a36Sopenharmony_ci if (i == d_rd_p % txd_cnt) 15862306a36Sopenharmony_ci seq_puts(file, " D_RD"); 15962306a36Sopenharmony_ci if (i == d_wr_p % txd_cnt) 16062306a36Sopenharmony_ci seq_puts(file, " D_WR"); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci seq_putc(file, '\n'); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define NFP_NFDK_CFG_CTRL_SUPPORTED \ 16762306a36Sopenharmony_ci (NFP_NET_CFG_CTRL_ENABLE | NFP_NET_CFG_CTRL_PROMISC | \ 16862306a36Sopenharmony_ci NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC | \ 16962306a36Sopenharmony_ci NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM | \ 17062306a36Sopenharmony_ci NFP_NET_CFG_CTRL_RXVLAN | \ 17162306a36Sopenharmony_ci NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ | \ 17262306a36Sopenharmony_ci NFP_NET_CFG_CTRL_TXVLAN_V2 | \ 17362306a36Sopenharmony_ci NFP_NET_CFG_CTRL_GATHER | NFP_NET_CFG_CTRL_LSO | \ 17462306a36Sopenharmony_ci NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA | \ 17562306a36Sopenharmony_ci NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_IRQMOD | \ 17662306a36Sopenharmony_ci NFP_NET_CFG_CTRL_TXRWB | NFP_NET_CFG_CTRL_VEPA | \ 17762306a36Sopenharmony_ci NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE | \ 17862306a36Sopenharmony_ci NFP_NET_CFG_CTRL_BPF | NFP_NET_CFG_CTRL_LSO2 | \ 17962306a36Sopenharmony_ci NFP_NET_CFG_CTRL_RSS2 | NFP_NET_CFG_CTRL_CSUM_COMPLETE | \ 18062306a36Sopenharmony_ci NFP_NET_CFG_CTRL_LIVE_ADDR) 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ciconst struct nfp_dp_ops nfp_nfdk_ops = { 18362306a36Sopenharmony_ci .version = NFP_NFD_VER_NFDK, 18462306a36Sopenharmony_ci .tx_min_desc_per_pkt = NFDK_TX_DESC_PER_SIMPLE_PKT, 18562306a36Sopenharmony_ci .cap_mask = NFP_NFDK_CFG_CTRL_SUPPORTED, 18662306a36Sopenharmony_ci .dma_mask = DMA_BIT_MASK(48), 18762306a36Sopenharmony_ci .poll = nfp_nfdk_poll, 18862306a36Sopenharmony_ci .ctrl_poll = nfp_nfdk_ctrl_poll, 18962306a36Sopenharmony_ci .xmit = nfp_nfdk_tx, 19062306a36Sopenharmony_ci .ctrl_tx_one = nfp_nfdk_ctrl_tx_one, 19162306a36Sopenharmony_ci .rx_ring_fill_freelist = nfp_nfdk_rx_ring_fill_freelist, 19262306a36Sopenharmony_ci .tx_ring_alloc = nfp_nfdk_tx_ring_alloc, 19362306a36Sopenharmony_ci .tx_ring_reset = nfp_nfdk_tx_ring_reset, 19462306a36Sopenharmony_ci .tx_ring_free = nfp_nfdk_tx_ring_free, 19562306a36Sopenharmony_ci .tx_ring_bufs_alloc = nfp_nfdk_tx_ring_bufs_alloc, 19662306a36Sopenharmony_ci .tx_ring_bufs_free = nfp_nfdk_tx_ring_bufs_free, 19762306a36Sopenharmony_ci .print_tx_descs = nfp_nfdk_print_tx_descs 19862306a36Sopenharmony_ci}; 199