18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet 38c2ecf20Sopenharmony_ci * driver for Linux. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 88c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 98c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 108c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 118c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 148c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 158c2ecf20Sopenharmony_ci * conditions are met: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 188c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 198c2ecf20Sopenharmony_ci * disclaimer. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 228c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 238c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 248c2ecf20Sopenharmony_ci * provided with the distribution. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 278c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 288c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 298c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 308c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 318c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 328c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 338c2ecf20Sopenharmony_ci * SOFTWARE. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 378c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 388c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 398c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 408c2ecf20Sopenharmony_ci#include <linux/ip.h> 418c2ecf20Sopenharmony_ci#include <net/ipv6.h> 428c2ecf20Sopenharmony_ci#include <net/tcp.h> 438c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 448c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include "t4vf_common.h" 478c2ecf20Sopenharmony_ci#include "t4vf_defs.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include "../cxgb4/t4_regs.h" 508c2ecf20Sopenharmony_ci#include "../cxgb4/t4_values.h" 518c2ecf20Sopenharmony_ci#include "../cxgb4/t4fw_api.h" 528c2ecf20Sopenharmony_ci#include "../cxgb4/t4_msg.h" 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Constants ... 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cienum { 588c2ecf20Sopenharmony_ci /* 598c2ecf20Sopenharmony_ci * Egress Queue sizes, producer and consumer indices are all in units 608c2ecf20Sopenharmony_ci * of Egress Context Units bytes. Note that as far as the hardware is 618c2ecf20Sopenharmony_ci * concerned, the free list is an Egress Queue (the host produces free 628c2ecf20Sopenharmony_ci * buffers which the hardware consumes) and free list entries are 638c2ecf20Sopenharmony_ci * 64-bit PCI DMA addresses. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci EQ_UNIT = SGE_EQ_IDXSIZE, 668c2ecf20Sopenharmony_ci FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), 678c2ecf20Sopenharmony_ci TXD_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * Max number of TX descriptors we clean up at a time. Should be 718c2ecf20Sopenharmony_ci * modest as freeing skbs isn't cheap and it happens while holding 728c2ecf20Sopenharmony_ci * locks. We just need to free packets faster than they arrive, we 738c2ecf20Sopenharmony_ci * eventually catch up and keep the amortized cost reasonable. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci MAX_TX_RECLAIM = 16, 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * Max number of Rx buffers we replenish at a time. Again keep this 798c2ecf20Sopenharmony_ci * modest, allocating buffers isn't cheap either. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci MAX_RX_REFILL = 16, 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * Period of the Rx queue check timer. This timer is infrequent as it 858c2ecf20Sopenharmony_ci * has something to do only when the system experiences severe memory 868c2ecf20Sopenharmony_ci * shortage. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci RX_QCHECK_PERIOD = (HZ / 2), 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * Period of the TX queue check timer and the maximum number of TX 928c2ecf20Sopenharmony_ci * descriptors to be reclaimed by the TX timer. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci TX_QCHECK_PERIOD = (HZ / 2), 958c2ecf20Sopenharmony_ci MAX_TIMER_TX_RECLAIM = 100, 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * Suspend an Ethernet TX queue with fewer available descriptors than 998c2ecf20Sopenharmony_ci * this. We always want to have room for a maximum sized packet: 1008c2ecf20Sopenharmony_ci * inline immediate data + MAX_SKB_FRAGS. This is the same as 1018c2ecf20Sopenharmony_ci * calc_tx_flits() for a TSO packet with nr_frags == MAX_SKB_FRAGS 1028c2ecf20Sopenharmony_ci * (see that function and its helpers for a description of the 1038c2ecf20Sopenharmony_ci * calculation). 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci ETHTXQ_MAX_FRAGS = MAX_SKB_FRAGS + 1, 1068c2ecf20Sopenharmony_ci ETHTXQ_MAX_SGL_LEN = ((3 * (ETHTXQ_MAX_FRAGS-1))/2 + 1078c2ecf20Sopenharmony_ci ((ETHTXQ_MAX_FRAGS-1) & 1) + 1088c2ecf20Sopenharmony_ci 2), 1098c2ecf20Sopenharmony_ci ETHTXQ_MAX_HDR = (sizeof(struct fw_eth_tx_pkt_vm_wr) + 1108c2ecf20Sopenharmony_ci sizeof(struct cpl_tx_pkt_lso_core) + 1118c2ecf20Sopenharmony_ci sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64), 1128c2ecf20Sopenharmony_ci ETHTXQ_MAX_FLITS = ETHTXQ_MAX_SGL_LEN + ETHTXQ_MAX_HDR, 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ETHTXQ_STOP_THRES = 1 + DIV_ROUND_UP(ETHTXQ_MAX_FLITS, TXD_PER_EQ_UNIT), 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * Max TX descriptor space we allow for an Ethernet packet to be 1188c2ecf20Sopenharmony_ci * inlined into a WR. This is limited by the maximum value which 1198c2ecf20Sopenharmony_ci * we can specify for immediate data in the firmware Ethernet TX 1208c2ecf20Sopenharmony_ci * Work Request. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_M, 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * Max size of a WR sent through a control TX queue. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci MAX_CTRL_WR_LEN = 256, 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * Maximum amount of data which we'll ever need to inline into a 1318c2ecf20Sopenharmony_ci * TX ring: max(MAX_IMM_TX_PKT_LEN, MAX_CTRL_WR_LEN). 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci MAX_IMM_TX_LEN = (MAX_IMM_TX_PKT_LEN > MAX_CTRL_WR_LEN 1348c2ecf20Sopenharmony_ci ? MAX_IMM_TX_PKT_LEN 1358c2ecf20Sopenharmony_ci : MAX_CTRL_WR_LEN), 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * For incoming packets less than RX_COPY_THRES, we copy the data into 1398c2ecf20Sopenharmony_ci * an skb rather than referencing the data. We allocate enough 1408c2ecf20Sopenharmony_ci * in-line room in skb's to accommodate pulling in RX_PULL_LEN bytes 1418c2ecf20Sopenharmony_ci * of the data (header). 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci RX_COPY_THRES = 256, 1448c2ecf20Sopenharmony_ci RX_PULL_LEN = 128, 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* 1478c2ecf20Sopenharmony_ci * Main body length for sk_buffs used for RX Ethernet packets with 1488c2ecf20Sopenharmony_ci * fragments. Should be >= RX_PULL_LEN but possibly bigger to give 1498c2ecf20Sopenharmony_ci * pskb_may_pull() some room. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci RX_SKB_LEN = 512, 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci * Software state per TX descriptor. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistruct tx_sw_desc { 1588c2ecf20Sopenharmony_ci struct sk_buff *skb; /* socket buffer of TX data source */ 1598c2ecf20Sopenharmony_ci struct ulptx_sgl *sgl; /* scatter/gather list in TX Queue */ 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * Software state per RX Free List descriptor. We keep track of the allocated 1648c2ecf20Sopenharmony_ci * FL page, its size, and its PCI DMA address (if the page is mapped). The FL 1658c2ecf20Sopenharmony_ci * page size and its PCI DMA mapped state are stored in the low bits of the 1668c2ecf20Sopenharmony_ci * PCI DMA address as per below. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cistruct rx_sw_desc { 1698c2ecf20Sopenharmony_ci struct page *page; /* Free List page buffer */ 1708c2ecf20Sopenharmony_ci dma_addr_t dma_addr; /* PCI DMA address (if mapped) */ 1718c2ecf20Sopenharmony_ci /* and flags (see below) */ 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* 1758c2ecf20Sopenharmony_ci * The low bits of rx_sw_desc.dma_addr have special meaning. Note that the 1768c2ecf20Sopenharmony_ci * SGE also uses the low 4 bits to determine the size of the buffer. It uses 1778c2ecf20Sopenharmony_ci * those bits to index into the SGE_FL_BUFFER_SIZE[index] register array. 1788c2ecf20Sopenharmony_ci * Since we only use SGE_FL_BUFFER_SIZE0 and SGE_FL_BUFFER_SIZE1, these low 4 1798c2ecf20Sopenharmony_ci * bits can only contain a 0 or a 1 to indicate which size buffer we're giving 1808c2ecf20Sopenharmony_ci * to the SGE. Thus, our software state of "is the buffer mapped for DMA" is 1818c2ecf20Sopenharmony_ci * maintained in an inverse sense so the hardware never sees that bit high. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_cienum { 1848c2ecf20Sopenharmony_ci RX_LARGE_BUF = 1 << 0, /* buffer is SGE_FL_BUFFER_SIZE[1] */ 1858c2ecf20Sopenharmony_ci RX_UNMAPPED_BUF = 1 << 1, /* buffer is not mapped */ 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/** 1898c2ecf20Sopenharmony_ci * get_buf_addr - return DMA buffer address of software descriptor 1908c2ecf20Sopenharmony_ci * @sdesc: pointer to the software buffer descriptor 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Return the DMA buffer address of a software descriptor (stripping out 1938c2ecf20Sopenharmony_ci * our low-order flag bits). 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_cistatic inline dma_addr_t get_buf_addr(const struct rx_sw_desc *sdesc) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci return sdesc->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci/** 2018c2ecf20Sopenharmony_ci * is_buf_mapped - is buffer mapped for DMA? 2028c2ecf20Sopenharmony_ci * @sdesc: pointer to the software buffer descriptor 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * Determine whether the buffer associated with a software descriptor in 2058c2ecf20Sopenharmony_ci * mapped for DMA or not. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_cistatic inline bool is_buf_mapped(const struct rx_sw_desc *sdesc) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci return !(sdesc->dma_addr & RX_UNMAPPED_BUF); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/** 2138c2ecf20Sopenharmony_ci * need_skb_unmap - does the platform need unmapping of sk_buffs? 2148c2ecf20Sopenharmony_ci * 2158c2ecf20Sopenharmony_ci * Returns true if the platform needs sk_buff unmapping. The compiler 2168c2ecf20Sopenharmony_ci * optimizes away unnecessary code if this returns true. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_cistatic inline int need_skb_unmap(void) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci#ifdef CONFIG_NEED_DMA_MAP_STATE 2218c2ecf20Sopenharmony_ci return 1; 2228c2ecf20Sopenharmony_ci#else 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci#endif 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * txq_avail - return the number of available slots in a TX queue 2298c2ecf20Sopenharmony_ci * @tq: the TX queue 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Returns the number of available descriptors in a TX queue. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_cistatic inline unsigned int txq_avail(const struct sge_txq *tq) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci return tq->size - 1 - tq->in_use; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/** 2398c2ecf20Sopenharmony_ci * fl_cap - return the capacity of a Free List 2408c2ecf20Sopenharmony_ci * @fl: the Free List 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Returns the capacity of a Free List. The capacity is less than the 2438c2ecf20Sopenharmony_ci * size because an Egress Queue Index Unit worth of descriptors needs to 2448c2ecf20Sopenharmony_ci * be left unpopulated, otherwise the Producer and Consumer indices PIDX 2458c2ecf20Sopenharmony_ci * and CIDX will match and the hardware will think the FL is empty. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_cistatic inline unsigned int fl_cap(const struct sge_fl *fl) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci return fl->size - FL_PER_EQ_UNIT; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/** 2538c2ecf20Sopenharmony_ci * fl_starving - return whether a Free List is starving. 2548c2ecf20Sopenharmony_ci * @adapter: pointer to the adapter 2558c2ecf20Sopenharmony_ci * @fl: the Free List 2568c2ecf20Sopenharmony_ci * 2578c2ecf20Sopenharmony_ci * Tests specified Free List to see whether the number of buffers 2588c2ecf20Sopenharmony_ci * available to the hardware has falled below our "starvation" 2598c2ecf20Sopenharmony_ci * threshold. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_cistatic inline bool fl_starving(const struct adapter *adapter, 2628c2ecf20Sopenharmony_ci const struct sge_fl *fl) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci const struct sge *s = &adapter->sge; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return fl->avail - fl->pend_cred <= s->fl_starve_thres; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/** 2708c2ecf20Sopenharmony_ci * map_skb - map an skb for DMA to the device 2718c2ecf20Sopenharmony_ci * @dev: the egress net device 2728c2ecf20Sopenharmony_ci * @skb: the packet to map 2738c2ecf20Sopenharmony_ci * @addr: a pointer to the base of the DMA mapping array 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * Map an skb for DMA to the device and return an array of DMA addresses. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_cistatic int map_skb(struct device *dev, const struct sk_buff *skb, 2788c2ecf20Sopenharmony_ci dma_addr_t *addr) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci const skb_frag_t *fp, *end; 2818c2ecf20Sopenharmony_ci const struct skb_shared_info *si; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci *addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); 2848c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, *addr)) 2858c2ecf20Sopenharmony_ci goto out_err; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci si = skb_shinfo(skb); 2888c2ecf20Sopenharmony_ci end = &si->frags[si->nr_frags]; 2898c2ecf20Sopenharmony_ci for (fp = si->frags; fp < end; fp++) { 2908c2ecf20Sopenharmony_ci *++addr = skb_frag_dma_map(dev, fp, 0, skb_frag_size(fp), 2918c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 2928c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, *addr)) 2938c2ecf20Sopenharmony_ci goto unwind; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ciunwind: 2988c2ecf20Sopenharmony_ci while (fp-- > si->frags) 2998c2ecf20Sopenharmony_ci dma_unmap_page(dev, *--addr, skb_frag_size(fp), DMA_TO_DEVICE); 3008c2ecf20Sopenharmony_ci dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ciout_err: 3038c2ecf20Sopenharmony_ci return -ENOMEM; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void unmap_sgl(struct device *dev, const struct sk_buff *skb, 3078c2ecf20Sopenharmony_ci const struct ulptx_sgl *sgl, const struct sge_txq *tq) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci const struct ulptx_sge_pair *p; 3108c2ecf20Sopenharmony_ci unsigned int nfrags = skb_shinfo(skb)->nr_frags; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (likely(skb_headlen(skb))) 3138c2ecf20Sopenharmony_ci dma_unmap_single(dev, be64_to_cpu(sgl->addr0), 3148c2ecf20Sopenharmony_ci be32_to_cpu(sgl->len0), DMA_TO_DEVICE); 3158c2ecf20Sopenharmony_ci else { 3168c2ecf20Sopenharmony_ci dma_unmap_page(dev, be64_to_cpu(sgl->addr0), 3178c2ecf20Sopenharmony_ci be32_to_cpu(sgl->len0), DMA_TO_DEVICE); 3188c2ecf20Sopenharmony_ci nfrags--; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* 3228c2ecf20Sopenharmony_ci * the complexity below is because of the possibility of a wrap-around 3238c2ecf20Sopenharmony_ci * in the middle of an SGL 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci for (p = sgl->sge; nfrags >= 2; nfrags -= 2) { 3268c2ecf20Sopenharmony_ci if (likely((u8 *)(p + 1) <= (u8 *)tq->stat)) { 3278c2ecf20Sopenharmony_ciunmap: 3288c2ecf20Sopenharmony_ci dma_unmap_page(dev, be64_to_cpu(p->addr[0]), 3298c2ecf20Sopenharmony_ci be32_to_cpu(p->len[0]), DMA_TO_DEVICE); 3308c2ecf20Sopenharmony_ci dma_unmap_page(dev, be64_to_cpu(p->addr[1]), 3318c2ecf20Sopenharmony_ci be32_to_cpu(p->len[1]), DMA_TO_DEVICE); 3328c2ecf20Sopenharmony_ci p++; 3338c2ecf20Sopenharmony_ci } else if ((u8 *)p == (u8 *)tq->stat) { 3348c2ecf20Sopenharmony_ci p = (const struct ulptx_sge_pair *)tq->desc; 3358c2ecf20Sopenharmony_ci goto unmap; 3368c2ecf20Sopenharmony_ci } else if ((u8 *)p + 8 == (u8 *)tq->stat) { 3378c2ecf20Sopenharmony_ci const __be64 *addr = (const __be64 *)tq->desc; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci dma_unmap_page(dev, be64_to_cpu(addr[0]), 3408c2ecf20Sopenharmony_ci be32_to_cpu(p->len[0]), DMA_TO_DEVICE); 3418c2ecf20Sopenharmony_ci dma_unmap_page(dev, be64_to_cpu(addr[1]), 3428c2ecf20Sopenharmony_ci be32_to_cpu(p->len[1]), DMA_TO_DEVICE); 3438c2ecf20Sopenharmony_ci p = (const struct ulptx_sge_pair *)&addr[2]; 3448c2ecf20Sopenharmony_ci } else { 3458c2ecf20Sopenharmony_ci const __be64 *addr = (const __be64 *)tq->desc; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci dma_unmap_page(dev, be64_to_cpu(p->addr[0]), 3488c2ecf20Sopenharmony_ci be32_to_cpu(p->len[0]), DMA_TO_DEVICE); 3498c2ecf20Sopenharmony_ci dma_unmap_page(dev, be64_to_cpu(addr[0]), 3508c2ecf20Sopenharmony_ci be32_to_cpu(p->len[1]), DMA_TO_DEVICE); 3518c2ecf20Sopenharmony_ci p = (const struct ulptx_sge_pair *)&addr[1]; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci if (nfrags) { 3558c2ecf20Sopenharmony_ci __be64 addr; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if ((u8 *)p == (u8 *)tq->stat) 3588c2ecf20Sopenharmony_ci p = (const struct ulptx_sge_pair *)tq->desc; 3598c2ecf20Sopenharmony_ci addr = ((u8 *)p + 16 <= (u8 *)tq->stat 3608c2ecf20Sopenharmony_ci ? p->addr[0] 3618c2ecf20Sopenharmony_ci : *(const __be64 *)tq->desc); 3628c2ecf20Sopenharmony_ci dma_unmap_page(dev, be64_to_cpu(addr), be32_to_cpu(p->len[0]), 3638c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci/** 3688c2ecf20Sopenharmony_ci * free_tx_desc - reclaims TX descriptors and their buffers 3698c2ecf20Sopenharmony_ci * @adapter: the adapter 3708c2ecf20Sopenharmony_ci * @tq: the TX queue to reclaim descriptors from 3718c2ecf20Sopenharmony_ci * @n: the number of descriptors to reclaim 3728c2ecf20Sopenharmony_ci * @unmap: whether the buffers should be unmapped for DMA 3738c2ecf20Sopenharmony_ci * 3748c2ecf20Sopenharmony_ci * Reclaims TX descriptors from an SGE TX queue and frees the associated 3758c2ecf20Sopenharmony_ci * TX buffers. Called with the TX queue lock held. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_cistatic void free_tx_desc(struct adapter *adapter, struct sge_txq *tq, 3788c2ecf20Sopenharmony_ci unsigned int n, bool unmap) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct tx_sw_desc *sdesc; 3818c2ecf20Sopenharmony_ci unsigned int cidx = tq->cidx; 3828c2ecf20Sopenharmony_ci struct device *dev = adapter->pdev_dev; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci const int need_unmap = need_skb_unmap() && unmap; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci sdesc = &tq->sdesc[cidx]; 3878c2ecf20Sopenharmony_ci while (n--) { 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * If we kept a reference to the original TX skb, we need to 3908c2ecf20Sopenharmony_ci * unmap it from PCI DMA space (if required) and free it. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci if (sdesc->skb) { 3938c2ecf20Sopenharmony_ci if (need_unmap) 3948c2ecf20Sopenharmony_ci unmap_sgl(dev, sdesc->skb, sdesc->sgl, tq); 3958c2ecf20Sopenharmony_ci dev_consume_skb_any(sdesc->skb); 3968c2ecf20Sopenharmony_ci sdesc->skb = NULL; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci sdesc++; 4008c2ecf20Sopenharmony_ci if (++cidx == tq->size) { 4018c2ecf20Sopenharmony_ci cidx = 0; 4028c2ecf20Sopenharmony_ci sdesc = tq->sdesc; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci tq->cidx = cidx; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/* 4098c2ecf20Sopenharmony_ci * Return the number of reclaimable descriptors in a TX queue. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_cistatic inline int reclaimable(const struct sge_txq *tq) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci int hw_cidx = be16_to_cpu(tq->stat->cidx); 4148c2ecf20Sopenharmony_ci int reclaimable = hw_cidx - tq->cidx; 4158c2ecf20Sopenharmony_ci if (reclaimable < 0) 4168c2ecf20Sopenharmony_ci reclaimable += tq->size; 4178c2ecf20Sopenharmony_ci return reclaimable; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci/** 4218c2ecf20Sopenharmony_ci * reclaim_completed_tx - reclaims completed TX descriptors 4228c2ecf20Sopenharmony_ci * @adapter: the adapter 4238c2ecf20Sopenharmony_ci * @tq: the TX queue to reclaim completed descriptors from 4248c2ecf20Sopenharmony_ci * @unmap: whether the buffers should be unmapped for DMA 4258c2ecf20Sopenharmony_ci * 4268c2ecf20Sopenharmony_ci * Reclaims TX descriptors that the SGE has indicated it has processed, 4278c2ecf20Sopenharmony_ci * and frees the associated buffers if possible. Called with the TX 4288c2ecf20Sopenharmony_ci * queue locked. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_cistatic inline void reclaim_completed_tx(struct adapter *adapter, 4318c2ecf20Sopenharmony_ci struct sge_txq *tq, 4328c2ecf20Sopenharmony_ci bool unmap) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci int avail = reclaimable(tq); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (avail) { 4378c2ecf20Sopenharmony_ci /* 4388c2ecf20Sopenharmony_ci * Limit the amount of clean up work we do at a time to keep 4398c2ecf20Sopenharmony_ci * the TX lock hold time O(1). 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci if (avail > MAX_TX_RECLAIM) 4428c2ecf20Sopenharmony_ci avail = MAX_TX_RECLAIM; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci free_tx_desc(adapter, tq, avail, unmap); 4458c2ecf20Sopenharmony_ci tq->in_use -= avail; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci/** 4508c2ecf20Sopenharmony_ci * get_buf_size - return the size of an RX Free List buffer. 4518c2ecf20Sopenharmony_ci * @adapter: pointer to the associated adapter 4528c2ecf20Sopenharmony_ci * @sdesc: pointer to the software buffer descriptor 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_cistatic inline int get_buf_size(const struct adapter *adapter, 4558c2ecf20Sopenharmony_ci const struct rx_sw_desc *sdesc) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci const struct sge *s = &adapter->sge; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return (s->fl_pg_order > 0 && (sdesc->dma_addr & RX_LARGE_BUF) 4608c2ecf20Sopenharmony_ci ? (PAGE_SIZE << s->fl_pg_order) : PAGE_SIZE); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci/** 4648c2ecf20Sopenharmony_ci * free_rx_bufs - free RX buffers on an SGE Free List 4658c2ecf20Sopenharmony_ci * @adapter: the adapter 4668c2ecf20Sopenharmony_ci * @fl: the SGE Free List to free buffers from 4678c2ecf20Sopenharmony_ci * @n: how many buffers to free 4688c2ecf20Sopenharmony_ci * 4698c2ecf20Sopenharmony_ci * Release the next @n buffers on an SGE Free List RX queue. The 4708c2ecf20Sopenharmony_ci * buffers must be made inaccessible to hardware before calling this 4718c2ecf20Sopenharmony_ci * function. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_cistatic void free_rx_bufs(struct adapter *adapter, struct sge_fl *fl, int n) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci while (n--) { 4768c2ecf20Sopenharmony_ci struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx]; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (is_buf_mapped(sdesc)) 4798c2ecf20Sopenharmony_ci dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc), 4808c2ecf20Sopenharmony_ci get_buf_size(adapter, sdesc), 4818c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 4828c2ecf20Sopenharmony_ci put_page(sdesc->page); 4838c2ecf20Sopenharmony_ci sdesc->page = NULL; 4848c2ecf20Sopenharmony_ci if (++fl->cidx == fl->size) 4858c2ecf20Sopenharmony_ci fl->cidx = 0; 4868c2ecf20Sopenharmony_ci fl->avail--; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/** 4918c2ecf20Sopenharmony_ci * unmap_rx_buf - unmap the current RX buffer on an SGE Free List 4928c2ecf20Sopenharmony_ci * @adapter: the adapter 4938c2ecf20Sopenharmony_ci * @fl: the SGE Free List 4948c2ecf20Sopenharmony_ci * 4958c2ecf20Sopenharmony_ci * Unmap the current buffer on an SGE Free List RX queue. The 4968c2ecf20Sopenharmony_ci * buffer must be made inaccessible to HW before calling this function. 4978c2ecf20Sopenharmony_ci * 4988c2ecf20Sopenharmony_ci * This is similar to @free_rx_bufs above but does not free the buffer. 4998c2ecf20Sopenharmony_ci * Do note that the FL still loses any further access to the buffer. 5008c2ecf20Sopenharmony_ci * This is used predominantly to "transfer ownership" of an FL buffer 5018c2ecf20Sopenharmony_ci * to another entity (typically an skb's fragment list). 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_cistatic void unmap_rx_buf(struct adapter *adapter, struct sge_fl *fl) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx]; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (is_buf_mapped(sdesc)) 5088c2ecf20Sopenharmony_ci dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc), 5098c2ecf20Sopenharmony_ci get_buf_size(adapter, sdesc), 5108c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 5118c2ecf20Sopenharmony_ci sdesc->page = NULL; 5128c2ecf20Sopenharmony_ci if (++fl->cidx == fl->size) 5138c2ecf20Sopenharmony_ci fl->cidx = 0; 5148c2ecf20Sopenharmony_ci fl->avail--; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/** 5188c2ecf20Sopenharmony_ci * ring_fl_db - righ doorbell on free list 5198c2ecf20Sopenharmony_ci * @adapter: the adapter 5208c2ecf20Sopenharmony_ci * @fl: the Free List whose doorbell should be rung ... 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * Tell the Scatter Gather Engine that there are new free list entries 5238c2ecf20Sopenharmony_ci * available. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_cistatic inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci u32 val = adapter->params.arch.sge_fl_db; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* The SGE keeps track of its Producer and Consumer Indices in terms 5308c2ecf20Sopenharmony_ci * of Egress Queue Units so we can only tell it about integral numbers 5318c2ecf20Sopenharmony_ci * of multiples of Free List Entries per Egress Queue Units ... 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_ci if (fl->pend_cred >= FL_PER_EQ_UNIT) { 5348c2ecf20Sopenharmony_ci if (is_t4(adapter->params.chip)) 5358c2ecf20Sopenharmony_ci val |= PIDX_V(fl->pend_cred / FL_PER_EQ_UNIT); 5368c2ecf20Sopenharmony_ci else 5378c2ecf20Sopenharmony_ci val |= PIDX_T5_V(fl->pend_cred / FL_PER_EQ_UNIT); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* Make sure all memory writes to the Free List queue are 5408c2ecf20Sopenharmony_ci * committed before we tell the hardware about them. 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci wmb(); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* If we don't have access to the new User Doorbell (T5+), use 5458c2ecf20Sopenharmony_ci * the old doorbell mechanism; otherwise use the new BAR2 5468c2ecf20Sopenharmony_ci * mechanism. 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_ci if (unlikely(fl->bar2_addr == NULL)) { 5498c2ecf20Sopenharmony_ci t4_write_reg(adapter, 5508c2ecf20Sopenharmony_ci T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, 5518c2ecf20Sopenharmony_ci QID_V(fl->cntxt_id) | val); 5528c2ecf20Sopenharmony_ci } else { 5538c2ecf20Sopenharmony_ci writel(val | QID_V(fl->bar2_qid), 5548c2ecf20Sopenharmony_ci fl->bar2_addr + SGE_UDB_KDOORBELL); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* This Write memory Barrier will force the write to 5578c2ecf20Sopenharmony_ci * the User Doorbell area to be flushed. 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci wmb(); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci fl->pend_cred %= FL_PER_EQ_UNIT; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci/** 5668c2ecf20Sopenharmony_ci * set_rx_sw_desc - initialize software RX buffer descriptor 5678c2ecf20Sopenharmony_ci * @sdesc: pointer to the softwore RX buffer descriptor 5688c2ecf20Sopenharmony_ci * @page: pointer to the page data structure backing the RX buffer 5698c2ecf20Sopenharmony_ci * @dma_addr: PCI DMA address (possibly with low-bit flags) 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_cistatic inline void set_rx_sw_desc(struct rx_sw_desc *sdesc, struct page *page, 5728c2ecf20Sopenharmony_ci dma_addr_t dma_addr) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci sdesc->page = page; 5758c2ecf20Sopenharmony_ci sdesc->dma_addr = dma_addr; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci/* 5798c2ecf20Sopenharmony_ci * Support for poisoning RX buffers ... 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ci#define POISON_BUF_VAL -1 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic inline void poison_buf(struct page *page, size_t sz) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci#if POISON_BUF_VAL >= 0 5868c2ecf20Sopenharmony_ci memset(page_address(page), POISON_BUF_VAL, sz); 5878c2ecf20Sopenharmony_ci#endif 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci/** 5918c2ecf20Sopenharmony_ci * refill_fl - refill an SGE RX buffer ring 5928c2ecf20Sopenharmony_ci * @adapter: the adapter 5938c2ecf20Sopenharmony_ci * @fl: the Free List ring to refill 5948c2ecf20Sopenharmony_ci * @n: the number of new buffers to allocate 5958c2ecf20Sopenharmony_ci * @gfp: the gfp flags for the allocations 5968c2ecf20Sopenharmony_ci * 5978c2ecf20Sopenharmony_ci * (Re)populate an SGE free-buffer queue with up to @n new packet buffers, 5988c2ecf20Sopenharmony_ci * allocated with the supplied gfp flags. The caller must assure that 5998c2ecf20Sopenharmony_ci * @n does not exceed the queue's capacity -- i.e. (cidx == pidx) _IN 6008c2ecf20Sopenharmony_ci * EGRESS QUEUE UNITS_ indicates an empty Free List! Returns the number 6018c2ecf20Sopenharmony_ci * of buffers allocated. If afterwards the queue is found critically low, 6028c2ecf20Sopenharmony_ci * mark it as starving in the bitmap of starving FLs. 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_cistatic unsigned int refill_fl(struct adapter *adapter, struct sge_fl *fl, 6058c2ecf20Sopenharmony_ci int n, gfp_t gfp) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 6088c2ecf20Sopenharmony_ci struct page *page; 6098c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 6108c2ecf20Sopenharmony_ci unsigned int cred = fl->avail; 6118c2ecf20Sopenharmony_ci __be64 *d = &fl->desc[fl->pidx]; 6128c2ecf20Sopenharmony_ci struct rx_sw_desc *sdesc = &fl->sdesc[fl->pidx]; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * Sanity: ensure that the result of adding n Free List buffers 6168c2ecf20Sopenharmony_ci * won't result in wrapping the SGE's Producer Index around to 6178c2ecf20Sopenharmony_ci * it's Consumer Index thereby indicating an empty Free List ... 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci BUG_ON(fl->avail + n > fl->size - FL_PER_EQ_UNIT); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci gfp |= __GFP_NOWARN; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * If we support large pages, prefer large buffers and fail over to 6258c2ecf20Sopenharmony_ci * small pages if we can't allocate large pages to satisfy the refill. 6268c2ecf20Sopenharmony_ci * If we don't support large pages, drop directly into the small page 6278c2ecf20Sopenharmony_ci * allocation code. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci if (s->fl_pg_order == 0) 6308c2ecf20Sopenharmony_ci goto alloc_small_pages; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci while (n) { 6338c2ecf20Sopenharmony_ci page = __dev_alloc_pages(gfp, s->fl_pg_order); 6348c2ecf20Sopenharmony_ci if (unlikely(!page)) { 6358c2ecf20Sopenharmony_ci /* 6368c2ecf20Sopenharmony_ci * We've failed inour attempt to allocate a "large 6378c2ecf20Sopenharmony_ci * page". Fail over to the "small page" allocation 6388c2ecf20Sopenharmony_ci * below. 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_ci fl->large_alloc_failed++; 6418c2ecf20Sopenharmony_ci break; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci poison_buf(page, PAGE_SIZE << s->fl_pg_order); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci dma_addr = dma_map_page(adapter->pdev_dev, page, 0, 6468c2ecf20Sopenharmony_ci PAGE_SIZE << s->fl_pg_order, 6478c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 6488c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) { 6498c2ecf20Sopenharmony_ci /* 6508c2ecf20Sopenharmony_ci * We've run out of DMA mapping space. Free up the 6518c2ecf20Sopenharmony_ci * buffer and return with what we've managed to put 6528c2ecf20Sopenharmony_ci * into the free list. We don't want to fail over to 6538c2ecf20Sopenharmony_ci * the small page allocation below in this case 6548c2ecf20Sopenharmony_ci * because DMA mapping resources are typically 6558c2ecf20Sopenharmony_ci * critical resources once they become scarse. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_ci __free_pages(page, s->fl_pg_order); 6588c2ecf20Sopenharmony_ci goto out; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci dma_addr |= RX_LARGE_BUF; 6618c2ecf20Sopenharmony_ci *d++ = cpu_to_be64(dma_addr); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci set_rx_sw_desc(sdesc, page, dma_addr); 6648c2ecf20Sopenharmony_ci sdesc++; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci fl->avail++; 6678c2ecf20Sopenharmony_ci if (++fl->pidx == fl->size) { 6688c2ecf20Sopenharmony_ci fl->pidx = 0; 6698c2ecf20Sopenharmony_ci sdesc = fl->sdesc; 6708c2ecf20Sopenharmony_ci d = fl->desc; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci n--; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cialloc_small_pages: 6768c2ecf20Sopenharmony_ci while (n--) { 6778c2ecf20Sopenharmony_ci page = __dev_alloc_page(gfp); 6788c2ecf20Sopenharmony_ci if (unlikely(!page)) { 6798c2ecf20Sopenharmony_ci fl->alloc_failed++; 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci poison_buf(page, PAGE_SIZE); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci dma_addr = dma_map_page(adapter->pdev_dev, page, 0, PAGE_SIZE, 6858c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 6868c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) { 6878c2ecf20Sopenharmony_ci put_page(page); 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci *d++ = cpu_to_be64(dma_addr); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci set_rx_sw_desc(sdesc, page, dma_addr); 6938c2ecf20Sopenharmony_ci sdesc++; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci fl->avail++; 6968c2ecf20Sopenharmony_ci if (++fl->pidx == fl->size) { 6978c2ecf20Sopenharmony_ci fl->pidx = 0; 6988c2ecf20Sopenharmony_ci sdesc = fl->sdesc; 6998c2ecf20Sopenharmony_ci d = fl->desc; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ciout: 7048c2ecf20Sopenharmony_ci /* 7058c2ecf20Sopenharmony_ci * Update our accounting state to incorporate the new Free List 7068c2ecf20Sopenharmony_ci * buffers, tell the hardware about them and return the number of 7078c2ecf20Sopenharmony_ci * buffers which we were able to allocate. 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_ci cred = fl->avail - cred; 7108c2ecf20Sopenharmony_ci fl->pend_cred += cred; 7118c2ecf20Sopenharmony_ci ring_fl_db(adapter, fl); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (unlikely(fl_starving(adapter, fl))) { 7148c2ecf20Sopenharmony_ci smp_wmb(); 7158c2ecf20Sopenharmony_ci set_bit(fl->cntxt_id, adapter->sge.starving_fl); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci return cred; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci/* 7228c2ecf20Sopenharmony_ci * Refill a Free List to its capacity or the Maximum Refill Increment, 7238c2ecf20Sopenharmony_ci * whichever is smaller ... 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_cistatic inline void __refill_fl(struct adapter *adapter, struct sge_fl *fl) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci refill_fl(adapter, fl, 7288c2ecf20Sopenharmony_ci min((unsigned int)MAX_RX_REFILL, fl_cap(fl) - fl->avail), 7298c2ecf20Sopenharmony_ci GFP_ATOMIC); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/** 7338c2ecf20Sopenharmony_ci * alloc_ring - allocate resources for an SGE descriptor ring 7348c2ecf20Sopenharmony_ci * @dev: the PCI device's core device 7358c2ecf20Sopenharmony_ci * @nelem: the number of descriptors 7368c2ecf20Sopenharmony_ci * @hwsize: the size of each hardware descriptor 7378c2ecf20Sopenharmony_ci * @swsize: the size of each software descriptor 7388c2ecf20Sopenharmony_ci * @busaddrp: the physical PCI bus address of the allocated ring 7398c2ecf20Sopenharmony_ci * @swringp: return address pointer for software ring 7408c2ecf20Sopenharmony_ci * @stat_size: extra space in hardware ring for status information 7418c2ecf20Sopenharmony_ci * 7428c2ecf20Sopenharmony_ci * Allocates resources for an SGE descriptor ring, such as TX queues, 7438c2ecf20Sopenharmony_ci * free buffer lists, response queues, etc. Each SGE ring requires 7448c2ecf20Sopenharmony_ci * space for its hardware descriptors plus, optionally, space for software 7458c2ecf20Sopenharmony_ci * state associated with each hardware entry (the metadata). The function 7468c2ecf20Sopenharmony_ci * returns three values: the virtual address for the hardware ring (the 7478c2ecf20Sopenharmony_ci * return value of the function), the PCI bus address of the hardware 7488c2ecf20Sopenharmony_ci * ring (in *busaddrp), and the address of the software ring (in swringp). 7498c2ecf20Sopenharmony_ci * Both the hardware and software rings are returned zeroed out. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_cistatic void *alloc_ring(struct device *dev, size_t nelem, size_t hwsize, 7528c2ecf20Sopenharmony_ci size_t swsize, dma_addr_t *busaddrp, void *swringp, 7538c2ecf20Sopenharmony_ci size_t stat_size) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci /* 7568c2ecf20Sopenharmony_ci * Allocate the hardware ring and PCI DMA bus address space for said. 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci size_t hwlen = nelem * hwsize + stat_size; 7598c2ecf20Sopenharmony_ci void *hwring = dma_alloc_coherent(dev, hwlen, busaddrp, GFP_KERNEL); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!hwring) 7628c2ecf20Sopenharmony_ci return NULL; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* 7658c2ecf20Sopenharmony_ci * If the caller wants a software ring, allocate it and return a 7668c2ecf20Sopenharmony_ci * pointer to it in *swringp. 7678c2ecf20Sopenharmony_ci */ 7688c2ecf20Sopenharmony_ci BUG_ON((swsize != 0) != (swringp != NULL)); 7698c2ecf20Sopenharmony_ci if (swsize) { 7708c2ecf20Sopenharmony_ci void *swring = kcalloc(nelem, swsize, GFP_KERNEL); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (!swring) { 7738c2ecf20Sopenharmony_ci dma_free_coherent(dev, hwlen, hwring, *busaddrp); 7748c2ecf20Sopenharmony_ci return NULL; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci *(void **)swringp = swring; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return hwring; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci/** 7838c2ecf20Sopenharmony_ci * sgl_len - calculates the size of an SGL of the given capacity 7848c2ecf20Sopenharmony_ci * @n: the number of SGL entries 7858c2ecf20Sopenharmony_ci * 7868c2ecf20Sopenharmony_ci * Calculates the number of flits (8-byte units) needed for a Direct 7878c2ecf20Sopenharmony_ci * Scatter/Gather List that can hold the given number of entries. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_cistatic inline unsigned int sgl_len(unsigned int n) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci /* 7928c2ecf20Sopenharmony_ci * A Direct Scatter Gather List uses 32-bit lengths and 64-bit PCI DMA 7938c2ecf20Sopenharmony_ci * addresses. The DSGL Work Request starts off with a 32-bit DSGL 7948c2ecf20Sopenharmony_ci * ULPTX header, then Length0, then Address0, then, for 1 <= i <= N, 7958c2ecf20Sopenharmony_ci * repeated sequences of { Length[i], Length[i+1], Address[i], 7968c2ecf20Sopenharmony_ci * Address[i+1] } (this ensures that all addresses are on 64-bit 7978c2ecf20Sopenharmony_ci * boundaries). If N is even, then Length[N+1] should be set to 0 and 7988c2ecf20Sopenharmony_ci * Address[N+1] is omitted. 7998c2ecf20Sopenharmony_ci * 8008c2ecf20Sopenharmony_ci * The following calculation incorporates all of the above. It's 8018c2ecf20Sopenharmony_ci * somewhat hard to follow but, briefly: the "+2" accounts for the 8028c2ecf20Sopenharmony_ci * first two flits which include the DSGL header, Length0 and 8038c2ecf20Sopenharmony_ci * Address0; the "(3*(n-1))/2" covers the main body of list entries (3 8048c2ecf20Sopenharmony_ci * flits for every pair of the remaining N) +1 if (n-1) is odd; and 8058c2ecf20Sopenharmony_ci * finally the "+((n-1)&1)" adds the one remaining flit needed if 8068c2ecf20Sopenharmony_ci * (n-1) is odd ... 8078c2ecf20Sopenharmony_ci */ 8088c2ecf20Sopenharmony_ci n--; 8098c2ecf20Sopenharmony_ci return (3 * n) / 2 + (n & 1) + 2; 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci/** 8138c2ecf20Sopenharmony_ci * flits_to_desc - returns the num of TX descriptors for the given flits 8148c2ecf20Sopenharmony_ci * @flits: the number of flits 8158c2ecf20Sopenharmony_ci * 8168c2ecf20Sopenharmony_ci * Returns the number of TX descriptors needed for the supplied number 8178c2ecf20Sopenharmony_ci * of flits. 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_cistatic inline unsigned int flits_to_desc(unsigned int flits) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci BUG_ON(flits > SGE_MAX_WR_LEN / sizeof(__be64)); 8228c2ecf20Sopenharmony_ci return DIV_ROUND_UP(flits, TXD_PER_EQ_UNIT); 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci/** 8268c2ecf20Sopenharmony_ci * is_eth_imm - can an Ethernet packet be sent as immediate data? 8278c2ecf20Sopenharmony_ci * @skb: the packet 8288c2ecf20Sopenharmony_ci * 8298c2ecf20Sopenharmony_ci * Returns whether an Ethernet packet is small enough to fit completely as 8308c2ecf20Sopenharmony_ci * immediate data. 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_cistatic inline int is_eth_imm(const struct sk_buff *skb) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci /* 8358c2ecf20Sopenharmony_ci * The VF Driver uses the FW_ETH_TX_PKT_VM_WR firmware Work Request 8368c2ecf20Sopenharmony_ci * which does not accommodate immediate data. We could dike out all 8378c2ecf20Sopenharmony_ci * of the support code for immediate data but that would tie our hands 8388c2ecf20Sopenharmony_ci * too much if we ever want to enhace the firmware. It would also 8398c2ecf20Sopenharmony_ci * create more differences between the PF and VF Drivers. 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_ci return false; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci/** 8458c2ecf20Sopenharmony_ci * calc_tx_flits - calculate the number of flits for a packet TX WR 8468c2ecf20Sopenharmony_ci * @skb: the packet 8478c2ecf20Sopenharmony_ci * 8488c2ecf20Sopenharmony_ci * Returns the number of flits needed for a TX Work Request for the 8498c2ecf20Sopenharmony_ci * given Ethernet packet, including the needed WR and CPL headers. 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_cistatic inline unsigned int calc_tx_flits(const struct sk_buff *skb) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci unsigned int flits; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * If the skb is small enough, we can pump it out as a work request 8578c2ecf20Sopenharmony_ci * with only immediate data. In that case we just have to have the 8588c2ecf20Sopenharmony_ci * TX Packet header plus the skb data in the Work Request. 8598c2ecf20Sopenharmony_ci */ 8608c2ecf20Sopenharmony_ci if (is_eth_imm(skb)) 8618c2ecf20Sopenharmony_ci return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 8628c2ecf20Sopenharmony_ci sizeof(__be64)); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* 8658c2ecf20Sopenharmony_ci * Otherwise, we're going to have to construct a Scatter gather list 8668c2ecf20Sopenharmony_ci * of the skb body and fragments. We also include the flits necessary 8678c2ecf20Sopenharmony_ci * for the TX Packet Work Request and CPL. We always have a firmware 8688c2ecf20Sopenharmony_ci * Write Header (incorporated as part of the cpl_tx_pkt_lso and 8698c2ecf20Sopenharmony_ci * cpl_tx_pkt structures), followed by either a TX Packet Write CPL 8708c2ecf20Sopenharmony_ci * message or, if we're doing a Large Send Offload, an LSO CPL message 8718c2ecf20Sopenharmony_ci * with an embedded TX Packet Write CPL message. 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_ci flits = sgl_len(skb_shinfo(skb)->nr_frags + 1); 8748c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_size) 8758c2ecf20Sopenharmony_ci flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) + 8768c2ecf20Sopenharmony_ci sizeof(struct cpl_tx_pkt_lso_core) + 8778c2ecf20Sopenharmony_ci sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); 8788c2ecf20Sopenharmony_ci else 8798c2ecf20Sopenharmony_ci flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) + 8808c2ecf20Sopenharmony_ci sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); 8818c2ecf20Sopenharmony_ci return flits; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci/** 8858c2ecf20Sopenharmony_ci * write_sgl - populate a Scatter/Gather List for a packet 8868c2ecf20Sopenharmony_ci * @skb: the packet 8878c2ecf20Sopenharmony_ci * @tq: the TX queue we are writing into 8888c2ecf20Sopenharmony_ci * @sgl: starting location for writing the SGL 8898c2ecf20Sopenharmony_ci * @end: points right after the end of the SGL 8908c2ecf20Sopenharmony_ci * @start: start offset into skb main-body data to include in the SGL 8918c2ecf20Sopenharmony_ci * @addr: the list of DMA bus addresses for the SGL elements 8928c2ecf20Sopenharmony_ci * 8938c2ecf20Sopenharmony_ci * Generates a Scatter/Gather List for the buffers that make up a packet. 8948c2ecf20Sopenharmony_ci * The caller must provide adequate space for the SGL that will be written. 8958c2ecf20Sopenharmony_ci * The SGL includes all of the packet's page fragments and the data in its 8968c2ecf20Sopenharmony_ci * main body except for the first @start bytes. @pos must be 16-byte 8978c2ecf20Sopenharmony_ci * aligned and within a TX descriptor with available space. @end points 8988c2ecf20Sopenharmony_ci * write after the end of the SGL but does not account for any potential 8998c2ecf20Sopenharmony_ci * wrap around, i.e., @end > @tq->stat. 9008c2ecf20Sopenharmony_ci */ 9018c2ecf20Sopenharmony_cistatic void write_sgl(const struct sk_buff *skb, struct sge_txq *tq, 9028c2ecf20Sopenharmony_ci struct ulptx_sgl *sgl, u64 *end, unsigned int start, 9038c2ecf20Sopenharmony_ci const dma_addr_t *addr) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci unsigned int i, len; 9068c2ecf20Sopenharmony_ci struct ulptx_sge_pair *to; 9078c2ecf20Sopenharmony_ci const struct skb_shared_info *si = skb_shinfo(skb); 9088c2ecf20Sopenharmony_ci unsigned int nfrags = si->nr_frags; 9098c2ecf20Sopenharmony_ci struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1]; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci len = skb_headlen(skb) - start; 9128c2ecf20Sopenharmony_ci if (likely(len)) { 9138c2ecf20Sopenharmony_ci sgl->len0 = htonl(len); 9148c2ecf20Sopenharmony_ci sgl->addr0 = cpu_to_be64(addr[0] + start); 9158c2ecf20Sopenharmony_ci nfrags++; 9168c2ecf20Sopenharmony_ci } else { 9178c2ecf20Sopenharmony_ci sgl->len0 = htonl(skb_frag_size(&si->frags[0])); 9188c2ecf20Sopenharmony_ci sgl->addr0 = cpu_to_be64(addr[1]); 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | 9228c2ecf20Sopenharmony_ci ULPTX_NSGE_V(nfrags)); 9238c2ecf20Sopenharmony_ci if (likely(--nfrags == 0)) 9248c2ecf20Sopenharmony_ci return; 9258c2ecf20Sopenharmony_ci /* 9268c2ecf20Sopenharmony_ci * Most of the complexity below deals with the possibility we hit the 9278c2ecf20Sopenharmony_ci * end of the queue in the middle of writing the SGL. For this case 9288c2ecf20Sopenharmony_ci * only we create the SGL in a temporary buffer and then copy it. 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_ci to = (u8 *)end > (u8 *)tq->stat ? buf : sgl->sge; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) { 9338c2ecf20Sopenharmony_ci to->len[0] = cpu_to_be32(skb_frag_size(&si->frags[i])); 9348c2ecf20Sopenharmony_ci to->len[1] = cpu_to_be32(skb_frag_size(&si->frags[++i])); 9358c2ecf20Sopenharmony_ci to->addr[0] = cpu_to_be64(addr[i]); 9368c2ecf20Sopenharmony_ci to->addr[1] = cpu_to_be64(addr[++i]); 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci if (nfrags) { 9398c2ecf20Sopenharmony_ci to->len[0] = cpu_to_be32(skb_frag_size(&si->frags[i])); 9408c2ecf20Sopenharmony_ci to->len[1] = cpu_to_be32(0); 9418c2ecf20Sopenharmony_ci to->addr[0] = cpu_to_be64(addr[i + 1]); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci if (unlikely((u8 *)end > (u8 *)tq->stat)) { 9448c2ecf20Sopenharmony_ci unsigned int part0 = (u8 *)tq->stat - (u8 *)sgl->sge, part1; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (likely(part0)) 9478c2ecf20Sopenharmony_ci memcpy(sgl->sge, buf, part0); 9488c2ecf20Sopenharmony_ci part1 = (u8 *)end - (u8 *)tq->stat; 9498c2ecf20Sopenharmony_ci memcpy(tq->desc, (u8 *)buf + part0, part1); 9508c2ecf20Sopenharmony_ci end = (void *)tq->desc + part1; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */ 9538c2ecf20Sopenharmony_ci *end = 0; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci/** 9578c2ecf20Sopenharmony_ci * check_ring_tx_db - check and potentially ring a TX queue's doorbell 9588c2ecf20Sopenharmony_ci * @adapter: the adapter 9598c2ecf20Sopenharmony_ci * @tq: the TX queue 9608c2ecf20Sopenharmony_ci * @n: number of new descriptors to give to HW 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * Ring the doorbel for a TX queue. 9638c2ecf20Sopenharmony_ci */ 9648c2ecf20Sopenharmony_cistatic inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, 9658c2ecf20Sopenharmony_ci int n) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci /* Make sure that all writes to the TX Descriptors are committed 9688c2ecf20Sopenharmony_ci * before we tell the hardware about them. 9698c2ecf20Sopenharmony_ci */ 9708c2ecf20Sopenharmony_ci wmb(); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* If we don't have access to the new User Doorbell (T5+), use the old 9738c2ecf20Sopenharmony_ci * doorbell mechanism; otherwise use the new BAR2 mechanism. 9748c2ecf20Sopenharmony_ci */ 9758c2ecf20Sopenharmony_ci if (unlikely(tq->bar2_addr == NULL)) { 9768c2ecf20Sopenharmony_ci u32 val = PIDX_V(n); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, 9798c2ecf20Sopenharmony_ci QID_V(tq->cntxt_id) | val); 9808c2ecf20Sopenharmony_ci } else { 9818c2ecf20Sopenharmony_ci u32 val = PIDX_T5_V(n); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* T4 and later chips share the same PIDX field offset within 9848c2ecf20Sopenharmony_ci * the doorbell, but T5 and later shrank the field in order to 9858c2ecf20Sopenharmony_ci * gain a bit for Doorbell Priority. The field was absurdly 9868c2ecf20Sopenharmony_ci * large in the first place (14 bits) so we just use the T5 9878c2ecf20Sopenharmony_ci * and later limits and warn if a Queue ID is too large. 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_ci WARN_ON(val & DBPRIO_F); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* If we're only writing a single Egress Unit and the BAR2 9928c2ecf20Sopenharmony_ci * Queue ID is 0, we can use the Write Combining Doorbell 9938c2ecf20Sopenharmony_ci * Gather Buffer; otherwise we use the simple doorbell. 9948c2ecf20Sopenharmony_ci */ 9958c2ecf20Sopenharmony_ci if (n == 1 && tq->bar2_qid == 0) { 9968c2ecf20Sopenharmony_ci unsigned int index = (tq->pidx 9978c2ecf20Sopenharmony_ci ? (tq->pidx - 1) 9988c2ecf20Sopenharmony_ci : (tq->size - 1)); 9998c2ecf20Sopenharmony_ci __be64 *src = (__be64 *)&tq->desc[index]; 10008c2ecf20Sopenharmony_ci __be64 __iomem *dst = (__be64 __iomem *)(tq->bar2_addr + 10018c2ecf20Sopenharmony_ci SGE_UDB_WCDOORBELL); 10028c2ecf20Sopenharmony_ci unsigned int count = EQ_UNIT / sizeof(__be64); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* Copy the TX Descriptor in a tight loop in order to 10058c2ecf20Sopenharmony_ci * try to get it to the adapter in a single Write 10068c2ecf20Sopenharmony_ci * Combined transfer on the PCI-E Bus. If the Write 10078c2ecf20Sopenharmony_ci * Combine fails (say because of an interrupt, etc.) 10088c2ecf20Sopenharmony_ci * the hardware will simply take the last write as a 10098c2ecf20Sopenharmony_ci * simple doorbell write with a PIDX Increment of 1 10108c2ecf20Sopenharmony_ci * and will fetch the TX Descriptor from memory via 10118c2ecf20Sopenharmony_ci * DMA. 10128c2ecf20Sopenharmony_ci */ 10138c2ecf20Sopenharmony_ci while (count) { 10148c2ecf20Sopenharmony_ci /* the (__force u64) is because the compiler 10158c2ecf20Sopenharmony_ci * doesn't understand the endian swizzling 10168c2ecf20Sopenharmony_ci * going on 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_ci writeq((__force u64)*src, dst); 10198c2ecf20Sopenharmony_ci src++; 10208c2ecf20Sopenharmony_ci dst++; 10218c2ecf20Sopenharmony_ci count--; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci } else 10248c2ecf20Sopenharmony_ci writel(val | QID_V(tq->bar2_qid), 10258c2ecf20Sopenharmony_ci tq->bar2_addr + SGE_UDB_KDOORBELL); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* This Write Memory Barrier will force the write to the User 10288c2ecf20Sopenharmony_ci * Doorbell area to be flushed. This is needed to prevent 10298c2ecf20Sopenharmony_ci * writes on different CPUs for the same queue from hitting 10308c2ecf20Sopenharmony_ci * the adapter out of order. This is required when some Work 10318c2ecf20Sopenharmony_ci * Requests take the Write Combine Gather Buffer path (user 10328c2ecf20Sopenharmony_ci * doorbell area offset [SGE_UDB_WCDOORBELL..+63]) and some 10338c2ecf20Sopenharmony_ci * take the traditional path where we simply increment the 10348c2ecf20Sopenharmony_ci * PIDX (User Doorbell area SGE_UDB_KDOORBELL) and have the 10358c2ecf20Sopenharmony_ci * hardware DMA read the actual Work Request. 10368c2ecf20Sopenharmony_ci */ 10378c2ecf20Sopenharmony_ci wmb(); 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci/** 10428c2ecf20Sopenharmony_ci * inline_tx_skb - inline a packet's data into TX descriptors 10438c2ecf20Sopenharmony_ci * @skb: the packet 10448c2ecf20Sopenharmony_ci * @tq: the TX queue where the packet will be inlined 10458c2ecf20Sopenharmony_ci * @pos: starting position in the TX queue to inline the packet 10468c2ecf20Sopenharmony_ci * 10478c2ecf20Sopenharmony_ci * Inline a packet's contents directly into TX descriptors, starting at 10488c2ecf20Sopenharmony_ci * the given position within the TX DMA ring. 10498c2ecf20Sopenharmony_ci * Most of the complexity of this operation is dealing with wrap arounds 10508c2ecf20Sopenharmony_ci * in the middle of the packet we want to inline. 10518c2ecf20Sopenharmony_ci */ 10528c2ecf20Sopenharmony_cistatic void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *tq, 10538c2ecf20Sopenharmony_ci void *pos) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci u64 *p; 10568c2ecf20Sopenharmony_ci int left = (void *)tq->stat - pos; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (likely(skb->len <= left)) { 10598c2ecf20Sopenharmony_ci if (likely(!skb->data_len)) 10608c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, pos, skb->len); 10618c2ecf20Sopenharmony_ci else 10628c2ecf20Sopenharmony_ci skb_copy_bits(skb, 0, pos, skb->len); 10638c2ecf20Sopenharmony_ci pos += skb->len; 10648c2ecf20Sopenharmony_ci } else { 10658c2ecf20Sopenharmony_ci skb_copy_bits(skb, 0, pos, left); 10668c2ecf20Sopenharmony_ci skb_copy_bits(skb, left, tq->desc, skb->len - left); 10678c2ecf20Sopenharmony_ci pos = (void *)tq->desc + (skb->len - left); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci /* 0-pad to multiple of 16 */ 10718c2ecf20Sopenharmony_ci p = PTR_ALIGN(pos, 8); 10728c2ecf20Sopenharmony_ci if ((uintptr_t)p & 8) 10738c2ecf20Sopenharmony_ci *p = 0; 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci/* 10778c2ecf20Sopenharmony_ci * Figure out what HW csum a packet wants and return the appropriate control 10788c2ecf20Sopenharmony_ci * bits. 10798c2ecf20Sopenharmony_ci */ 10808c2ecf20Sopenharmony_cistatic u64 hwcsum(enum chip_type chip, const struct sk_buff *skb) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci int csum_type; 10838c2ecf20Sopenharmony_ci const struct iphdr *iph = ip_hdr(skb); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (iph->version == 4) { 10868c2ecf20Sopenharmony_ci if (iph->protocol == IPPROTO_TCP) 10878c2ecf20Sopenharmony_ci csum_type = TX_CSUM_TCPIP; 10888c2ecf20Sopenharmony_ci else if (iph->protocol == IPPROTO_UDP) 10898c2ecf20Sopenharmony_ci csum_type = TX_CSUM_UDPIP; 10908c2ecf20Sopenharmony_ci else { 10918c2ecf20Sopenharmony_cinocsum: 10928c2ecf20Sopenharmony_ci /* 10938c2ecf20Sopenharmony_ci * unknown protocol, disable HW csum 10948c2ecf20Sopenharmony_ci * and hope a bad packet is detected 10958c2ecf20Sopenharmony_ci */ 10968c2ecf20Sopenharmony_ci return TXPKT_L4CSUM_DIS_F; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci } else { 10998c2ecf20Sopenharmony_ci /* 11008c2ecf20Sopenharmony_ci * this doesn't work with extension headers 11018c2ecf20Sopenharmony_ci */ 11028c2ecf20Sopenharmony_ci const struct ipv6hdr *ip6h = (const struct ipv6hdr *)iph; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (ip6h->nexthdr == IPPROTO_TCP) 11058c2ecf20Sopenharmony_ci csum_type = TX_CSUM_TCPIP6; 11068c2ecf20Sopenharmony_ci else if (ip6h->nexthdr == IPPROTO_UDP) 11078c2ecf20Sopenharmony_ci csum_type = TX_CSUM_UDPIP6; 11088c2ecf20Sopenharmony_ci else 11098c2ecf20Sopenharmony_ci goto nocsum; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (likely(csum_type >= TX_CSUM_TCPIP)) { 11138c2ecf20Sopenharmony_ci u64 hdr_len = TXPKT_IPHDR_LEN_V(skb_network_header_len(skb)); 11148c2ecf20Sopenharmony_ci int eth_hdr_len = skb_network_offset(skb) - ETH_HLEN; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (chip <= CHELSIO_T5) 11178c2ecf20Sopenharmony_ci hdr_len |= TXPKT_ETHHDR_LEN_V(eth_hdr_len); 11188c2ecf20Sopenharmony_ci else 11198c2ecf20Sopenharmony_ci hdr_len |= T6_TXPKT_ETHHDR_LEN_V(eth_hdr_len); 11208c2ecf20Sopenharmony_ci return TXPKT_CSUM_TYPE_V(csum_type) | hdr_len; 11218c2ecf20Sopenharmony_ci } else { 11228c2ecf20Sopenharmony_ci int start = skb_transport_offset(skb); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci return TXPKT_CSUM_TYPE_V(csum_type) | 11258c2ecf20Sopenharmony_ci TXPKT_CSUM_START_V(start) | 11268c2ecf20Sopenharmony_ci TXPKT_CSUM_LOC_V(start + skb->csum_offset); 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci/* 11318c2ecf20Sopenharmony_ci * Stop an Ethernet TX queue and record that state change. 11328c2ecf20Sopenharmony_ci */ 11338c2ecf20Sopenharmony_cistatic void txq_stop(struct sge_eth_txq *txq) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci netif_tx_stop_queue(txq->txq); 11368c2ecf20Sopenharmony_ci txq->q.stops++; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci/* 11408c2ecf20Sopenharmony_ci * Advance our software state for a TX queue by adding n in use descriptors. 11418c2ecf20Sopenharmony_ci */ 11428c2ecf20Sopenharmony_cistatic inline void txq_advance(struct sge_txq *tq, unsigned int n) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci tq->in_use += n; 11458c2ecf20Sopenharmony_ci tq->pidx += n; 11468c2ecf20Sopenharmony_ci if (tq->pidx >= tq->size) 11478c2ecf20Sopenharmony_ci tq->pidx -= tq->size; 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci/** 11518c2ecf20Sopenharmony_ci * t4vf_eth_xmit - add a packet to an Ethernet TX queue 11528c2ecf20Sopenharmony_ci * @skb: the packet 11538c2ecf20Sopenharmony_ci * @dev: the egress net device 11548c2ecf20Sopenharmony_ci * 11558c2ecf20Sopenharmony_ci * Add a packet to an SGE Ethernet TX queue. Runs with softirqs disabled. 11568c2ecf20Sopenharmony_ci */ 11578c2ecf20Sopenharmony_cinetdev_tx_t t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci u32 wr_mid; 11608c2ecf20Sopenharmony_ci u64 cntrl, *end; 11618c2ecf20Sopenharmony_ci int qidx, credits, max_pkt_len; 11628c2ecf20Sopenharmony_ci unsigned int flits, ndesc; 11638c2ecf20Sopenharmony_ci struct adapter *adapter; 11648c2ecf20Sopenharmony_ci struct sge_eth_txq *txq; 11658c2ecf20Sopenharmony_ci const struct port_info *pi; 11668c2ecf20Sopenharmony_ci struct fw_eth_tx_pkt_vm_wr *wr; 11678c2ecf20Sopenharmony_ci struct cpl_tx_pkt_core *cpl; 11688c2ecf20Sopenharmony_ci const struct skb_shared_info *ssi; 11698c2ecf20Sopenharmony_ci dma_addr_t addr[MAX_SKB_FRAGS + 1]; 11708c2ecf20Sopenharmony_ci const size_t fw_hdr_copy_len = (sizeof(wr->ethmacdst) + 11718c2ecf20Sopenharmony_ci sizeof(wr->ethmacsrc) + 11728c2ecf20Sopenharmony_ci sizeof(wr->ethtype) + 11738c2ecf20Sopenharmony_ci sizeof(wr->vlantci)); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* 11768c2ecf20Sopenharmony_ci * The chip minimum packet length is 10 octets but the firmware 11778c2ecf20Sopenharmony_ci * command that we are using requires that we copy the Ethernet header 11788c2ecf20Sopenharmony_ci * (including the VLAN tag) into the header so we reject anything 11798c2ecf20Sopenharmony_ci * smaller than that ... 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_ci if (unlikely(skb->len < fw_hdr_copy_len)) 11828c2ecf20Sopenharmony_ci goto out_free; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* Discard the packet if the length is greater than mtu */ 11858c2ecf20Sopenharmony_ci max_pkt_len = ETH_HLEN + dev->mtu; 11868c2ecf20Sopenharmony_ci if (skb_vlan_tagged(skb)) 11878c2ecf20Sopenharmony_ci max_pkt_len += VLAN_HLEN; 11888c2ecf20Sopenharmony_ci if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len))) 11898c2ecf20Sopenharmony_ci goto out_free; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* 11928c2ecf20Sopenharmony_ci * Figure out which TX Queue we're going to use. 11938c2ecf20Sopenharmony_ci */ 11948c2ecf20Sopenharmony_ci pi = netdev_priv(dev); 11958c2ecf20Sopenharmony_ci adapter = pi->adapter; 11968c2ecf20Sopenharmony_ci qidx = skb_get_queue_mapping(skb); 11978c2ecf20Sopenharmony_ci BUG_ON(qidx >= pi->nqsets); 11988c2ecf20Sopenharmony_ci txq = &adapter->sge.ethtxq[pi->first_qset + qidx]; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (pi->vlan_id && !skb_vlan_tag_present(skb)) 12018c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, cpu_to_be16(ETH_P_8021Q), 12028c2ecf20Sopenharmony_ci pi->vlan_id); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* 12058c2ecf20Sopenharmony_ci * Take this opportunity to reclaim any TX Descriptors whose DMA 12068c2ecf20Sopenharmony_ci * transfers have completed. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci reclaim_completed_tx(adapter, &txq->q, true); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci /* 12118c2ecf20Sopenharmony_ci * Calculate the number of flits and TX Descriptors we're going to 12128c2ecf20Sopenharmony_ci * need along with how many TX Descriptors will be left over after 12138c2ecf20Sopenharmony_ci * we inject our Work Request. 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_ci flits = calc_tx_flits(skb); 12168c2ecf20Sopenharmony_ci ndesc = flits_to_desc(flits); 12178c2ecf20Sopenharmony_ci credits = txq_avail(&txq->q) - ndesc; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci if (unlikely(credits < 0)) { 12208c2ecf20Sopenharmony_ci /* 12218c2ecf20Sopenharmony_ci * Not enough room for this packet's Work Request. Stop the 12228c2ecf20Sopenharmony_ci * TX Queue and return a "busy" condition. The queue will get 12238c2ecf20Sopenharmony_ci * started later on when the firmware informs us that space 12248c2ecf20Sopenharmony_ci * has opened up. 12258c2ecf20Sopenharmony_ci */ 12268c2ecf20Sopenharmony_ci txq_stop(txq); 12278c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 12288c2ecf20Sopenharmony_ci "%s: TX ring %u full while queue awake!\n", 12298c2ecf20Sopenharmony_ci dev->name, qidx); 12308c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (!is_eth_imm(skb) && 12348c2ecf20Sopenharmony_ci unlikely(map_skb(adapter->pdev_dev, skb, addr) < 0)) { 12358c2ecf20Sopenharmony_ci /* 12368c2ecf20Sopenharmony_ci * We need to map the skb into PCI DMA space (because it can't 12378c2ecf20Sopenharmony_ci * be in-lined directly into the Work Request) and the mapping 12388c2ecf20Sopenharmony_ci * operation failed. Record the error and drop the packet. 12398c2ecf20Sopenharmony_ci */ 12408c2ecf20Sopenharmony_ci txq->mapping_err++; 12418c2ecf20Sopenharmony_ci goto out_free; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci wr_mid = FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2)); 12458c2ecf20Sopenharmony_ci if (unlikely(credits < ETHTXQ_STOP_THRES)) { 12468c2ecf20Sopenharmony_ci /* 12478c2ecf20Sopenharmony_ci * After we're done injecting the Work Request for this 12488c2ecf20Sopenharmony_ci * packet, we'll be below our "stop threshold" so stop the TX 12498c2ecf20Sopenharmony_ci * Queue now and schedule a request for an SGE Egress Queue 12508c2ecf20Sopenharmony_ci * Update message. The queue will get started later on when 12518c2ecf20Sopenharmony_ci * the firmware processes this Work Request and sends us an 12528c2ecf20Sopenharmony_ci * Egress Queue Status Update message indicating that space 12538c2ecf20Sopenharmony_ci * has opened up. 12548c2ecf20Sopenharmony_ci */ 12558c2ecf20Sopenharmony_ci txq_stop(txq); 12568c2ecf20Sopenharmony_ci wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* 12608c2ecf20Sopenharmony_ci * Start filling in our Work Request. Note that we do _not_ handle 12618c2ecf20Sopenharmony_ci * the WR Header wrapping around the TX Descriptor Ring. If our 12628c2ecf20Sopenharmony_ci * maximum header size ever exceeds one TX Descriptor, we'll need to 12638c2ecf20Sopenharmony_ci * do something else here. 12648c2ecf20Sopenharmony_ci */ 12658c2ecf20Sopenharmony_ci BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1); 12668c2ecf20Sopenharmony_ci wr = (void *)&txq->q.desc[txq->q.pidx]; 12678c2ecf20Sopenharmony_ci wr->equiq_to_len16 = cpu_to_be32(wr_mid); 12688c2ecf20Sopenharmony_ci wr->r3[0] = cpu_to_be32(0); 12698c2ecf20Sopenharmony_ci wr->r3[1] = cpu_to_be32(0); 12708c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len); 12718c2ecf20Sopenharmony_ci end = (u64 *)wr + flits; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* 12748c2ecf20Sopenharmony_ci * If this is a Large Send Offload packet we'll put in an LSO CPL 12758c2ecf20Sopenharmony_ci * message with an encapsulated TX Packet CPL message. Otherwise we 12768c2ecf20Sopenharmony_ci * just use a TX Packet CPL message. 12778c2ecf20Sopenharmony_ci */ 12788c2ecf20Sopenharmony_ci ssi = skb_shinfo(skb); 12798c2ecf20Sopenharmony_ci if (ssi->gso_size) { 12808c2ecf20Sopenharmony_ci struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); 12818c2ecf20Sopenharmony_ci bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0; 12828c2ecf20Sopenharmony_ci int l3hdr_len = skb_network_header_len(skb); 12838c2ecf20Sopenharmony_ci int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci wr->op_immdlen = 12868c2ecf20Sopenharmony_ci cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_PKT_VM_WR) | 12878c2ecf20Sopenharmony_ci FW_WR_IMMDLEN_V(sizeof(*lso) + 12888c2ecf20Sopenharmony_ci sizeof(*cpl))); 12898c2ecf20Sopenharmony_ci /* 12908c2ecf20Sopenharmony_ci * Fill in the LSO CPL message. 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_ci lso->lso_ctrl = 12938c2ecf20Sopenharmony_ci cpu_to_be32(LSO_OPCODE_V(CPL_TX_PKT_LSO) | 12948c2ecf20Sopenharmony_ci LSO_FIRST_SLICE_F | 12958c2ecf20Sopenharmony_ci LSO_LAST_SLICE_F | 12968c2ecf20Sopenharmony_ci LSO_IPV6_V(v6) | 12978c2ecf20Sopenharmony_ci LSO_ETHHDR_LEN_V(eth_xtra_len / 4) | 12988c2ecf20Sopenharmony_ci LSO_IPHDR_LEN_V(l3hdr_len / 4) | 12998c2ecf20Sopenharmony_ci LSO_TCPHDR_LEN_V(tcp_hdr(skb)->doff)); 13008c2ecf20Sopenharmony_ci lso->ipid_ofst = cpu_to_be16(0); 13018c2ecf20Sopenharmony_ci lso->mss = cpu_to_be16(ssi->gso_size); 13028c2ecf20Sopenharmony_ci lso->seqno_offset = cpu_to_be32(0); 13038c2ecf20Sopenharmony_ci if (is_t4(adapter->params.chip)) 13048c2ecf20Sopenharmony_ci lso->len = cpu_to_be32(skb->len); 13058c2ecf20Sopenharmony_ci else 13068c2ecf20Sopenharmony_ci lso->len = cpu_to_be32(LSO_T5_XFER_SIZE_V(skb->len)); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* 13098c2ecf20Sopenharmony_ci * Set up TX Packet CPL pointer, control word and perform 13108c2ecf20Sopenharmony_ci * accounting. 13118c2ecf20Sopenharmony_ci */ 13128c2ecf20Sopenharmony_ci cpl = (void *)(lso + 1); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) 13158c2ecf20Sopenharmony_ci cntrl = TXPKT_ETHHDR_LEN_V(eth_xtra_len); 13168c2ecf20Sopenharmony_ci else 13178c2ecf20Sopenharmony_ci cntrl = T6_TXPKT_ETHHDR_LEN_V(eth_xtra_len); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci cntrl |= TXPKT_CSUM_TYPE_V(v6 ? 13208c2ecf20Sopenharmony_ci TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | 13218c2ecf20Sopenharmony_ci TXPKT_IPHDR_LEN_V(l3hdr_len); 13228c2ecf20Sopenharmony_ci txq->tso++; 13238c2ecf20Sopenharmony_ci txq->tx_cso += ssi->gso_segs; 13248c2ecf20Sopenharmony_ci } else { 13258c2ecf20Sopenharmony_ci int len; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl); 13288c2ecf20Sopenharmony_ci wr->op_immdlen = 13298c2ecf20Sopenharmony_ci cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_PKT_VM_WR) | 13308c2ecf20Sopenharmony_ci FW_WR_IMMDLEN_V(len)); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* 13338c2ecf20Sopenharmony_ci * Set up TX Packet CPL pointer, control word and perform 13348c2ecf20Sopenharmony_ci * accounting. 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ci cpl = (void *)(wr + 1); 13378c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 13388c2ecf20Sopenharmony_ci cntrl = hwcsum(adapter->params.chip, skb) | 13398c2ecf20Sopenharmony_ci TXPKT_IPCSUM_DIS_F; 13408c2ecf20Sopenharmony_ci txq->tx_cso++; 13418c2ecf20Sopenharmony_ci } else 13428c2ecf20Sopenharmony_ci cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* 13468c2ecf20Sopenharmony_ci * If there's a VLAN tag present, add that to the list of things to 13478c2ecf20Sopenharmony_ci * do in this Work Request. 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 13508c2ecf20Sopenharmony_ci txq->vlan_ins++; 13518c2ecf20Sopenharmony_ci cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb)); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci /* 13558c2ecf20Sopenharmony_ci * Fill in the TX Packet CPL message header. 13568c2ecf20Sopenharmony_ci */ 13578c2ecf20Sopenharmony_ci cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE_V(CPL_TX_PKT_XT) | 13588c2ecf20Sopenharmony_ci TXPKT_INTF_V(pi->port_id) | 13598c2ecf20Sopenharmony_ci TXPKT_PF_V(0)); 13608c2ecf20Sopenharmony_ci cpl->pack = cpu_to_be16(0); 13618c2ecf20Sopenharmony_ci cpl->len = cpu_to_be16(skb->len); 13628c2ecf20Sopenharmony_ci cpl->ctrl1 = cpu_to_be64(cntrl); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci#ifdef T4_TRACE 13658c2ecf20Sopenharmony_ci T4_TRACE5(adapter->tb[txq->q.cntxt_id & 7], 13668c2ecf20Sopenharmony_ci "eth_xmit: ndesc %u, credits %u, pidx %u, len %u, frags %u", 13678c2ecf20Sopenharmony_ci ndesc, credits, txq->q.pidx, skb->len, ssi->nr_frags); 13688c2ecf20Sopenharmony_ci#endif 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci /* 13718c2ecf20Sopenharmony_ci * Fill in the body of the TX Packet CPL message with either in-lined 13728c2ecf20Sopenharmony_ci * data or a Scatter/Gather List. 13738c2ecf20Sopenharmony_ci */ 13748c2ecf20Sopenharmony_ci if (is_eth_imm(skb)) { 13758c2ecf20Sopenharmony_ci /* 13768c2ecf20Sopenharmony_ci * In-line the packet's data and free the skb since we don't 13778c2ecf20Sopenharmony_ci * need it any longer. 13788c2ecf20Sopenharmony_ci */ 13798c2ecf20Sopenharmony_ci inline_tx_skb(skb, &txq->q, cpl + 1); 13808c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 13818c2ecf20Sopenharmony_ci } else { 13828c2ecf20Sopenharmony_ci /* 13838c2ecf20Sopenharmony_ci * Write the skb's Scatter/Gather list into the TX Packet CPL 13848c2ecf20Sopenharmony_ci * message and retain a pointer to the skb so we can free it 13858c2ecf20Sopenharmony_ci * later when its DMA completes. (We store the skb pointer 13868c2ecf20Sopenharmony_ci * in the Software Descriptor corresponding to the last TX 13878c2ecf20Sopenharmony_ci * Descriptor used by the Work Request.) 13888c2ecf20Sopenharmony_ci * 13898c2ecf20Sopenharmony_ci * The retained skb will be freed when the corresponding TX 13908c2ecf20Sopenharmony_ci * Descriptors are reclaimed after their DMAs complete. 13918c2ecf20Sopenharmony_ci * However, this could take quite a while since, in general, 13928c2ecf20Sopenharmony_ci * the hardware is set up to be lazy about sending DMA 13938c2ecf20Sopenharmony_ci * completion notifications to us and we mostly perform TX 13948c2ecf20Sopenharmony_ci * reclaims in the transmit routine. 13958c2ecf20Sopenharmony_ci * 13968c2ecf20Sopenharmony_ci * This is good for performamce but means that we rely on new 13978c2ecf20Sopenharmony_ci * TX packets arriving to run the destructors of completed 13988c2ecf20Sopenharmony_ci * packets, which open up space in their sockets' send queues. 13998c2ecf20Sopenharmony_ci * Sometimes we do not get such new packets causing TX to 14008c2ecf20Sopenharmony_ci * stall. A single UDP transmitter is a good example of this 14018c2ecf20Sopenharmony_ci * situation. We have a clean up timer that periodically 14028c2ecf20Sopenharmony_ci * reclaims completed packets but it doesn't run often enough 14038c2ecf20Sopenharmony_ci * (nor do we want it to) to prevent lengthy stalls. A 14048c2ecf20Sopenharmony_ci * solution to this problem is to run the destructor early, 14058c2ecf20Sopenharmony_ci * after the packet is queued but before it's DMAd. A con is 14068c2ecf20Sopenharmony_ci * that we lie to socket memory accounting, but the amount of 14078c2ecf20Sopenharmony_ci * extra memory is reasonable (limited by the number of TX 14088c2ecf20Sopenharmony_ci * descriptors), the packets do actually get freed quickly by 14098c2ecf20Sopenharmony_ci * new packets almost always, and for protocols like TCP that 14108c2ecf20Sopenharmony_ci * wait for acks to really free up the data the extra memory 14118c2ecf20Sopenharmony_ci * is even less. On the positive side we run the destructors 14128c2ecf20Sopenharmony_ci * on the sending CPU rather than on a potentially different 14138c2ecf20Sopenharmony_ci * completing CPU, usually a good thing. 14148c2ecf20Sopenharmony_ci * 14158c2ecf20Sopenharmony_ci * Run the destructor before telling the DMA engine about the 14168c2ecf20Sopenharmony_ci * packet to make sure it doesn't complete and get freed 14178c2ecf20Sopenharmony_ci * prematurely. 14188c2ecf20Sopenharmony_ci */ 14198c2ecf20Sopenharmony_ci struct ulptx_sgl *sgl = (struct ulptx_sgl *)(cpl + 1); 14208c2ecf20Sopenharmony_ci struct sge_txq *tq = &txq->q; 14218c2ecf20Sopenharmony_ci int last_desc; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* 14248c2ecf20Sopenharmony_ci * If the Work Request header was an exact multiple of our TX 14258c2ecf20Sopenharmony_ci * Descriptor length, then it's possible that the starting SGL 14268c2ecf20Sopenharmony_ci * pointer lines up exactly with the end of our TX Descriptor 14278c2ecf20Sopenharmony_ci * ring. If that's the case, wrap around to the beginning 14288c2ecf20Sopenharmony_ci * here ... 14298c2ecf20Sopenharmony_ci */ 14308c2ecf20Sopenharmony_ci if (unlikely((void *)sgl == (void *)tq->stat)) { 14318c2ecf20Sopenharmony_ci sgl = (void *)tq->desc; 14328c2ecf20Sopenharmony_ci end = ((void *)tq->desc + ((void *)end - (void *)tq->stat)); 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci write_sgl(skb, tq, sgl, end, 0, addr); 14368c2ecf20Sopenharmony_ci skb_orphan(skb); 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci last_desc = tq->pidx + ndesc - 1; 14398c2ecf20Sopenharmony_ci if (last_desc >= tq->size) 14408c2ecf20Sopenharmony_ci last_desc -= tq->size; 14418c2ecf20Sopenharmony_ci tq->sdesc[last_desc].skb = skb; 14428c2ecf20Sopenharmony_ci tq->sdesc[last_desc].sgl = sgl; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci /* 14468c2ecf20Sopenharmony_ci * Advance our internal TX Queue state, tell the hardware about 14478c2ecf20Sopenharmony_ci * the new TX descriptors and return success. 14488c2ecf20Sopenharmony_ci */ 14498c2ecf20Sopenharmony_ci txq_advance(&txq->q, ndesc); 14508c2ecf20Sopenharmony_ci netif_trans_update(dev); 14518c2ecf20Sopenharmony_ci ring_tx_db(adapter, &txq->q, ndesc); 14528c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ciout_free: 14558c2ecf20Sopenharmony_ci /* 14568c2ecf20Sopenharmony_ci * An error of some sort happened. Free the TX skb and tell the 14578c2ecf20Sopenharmony_ci * OS that we've "dealt" with the packet ... 14588c2ecf20Sopenharmony_ci */ 14598c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 14608c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci/** 14648c2ecf20Sopenharmony_ci * copy_frags - copy fragments from gather list into skb_shared_info 14658c2ecf20Sopenharmony_ci * @skb: destination skb 14668c2ecf20Sopenharmony_ci * @gl: source internal packet gather list 14678c2ecf20Sopenharmony_ci * @offset: packet start offset in first page 14688c2ecf20Sopenharmony_ci * 14698c2ecf20Sopenharmony_ci * Copy an internal packet gather list into a Linux skb_shared_info 14708c2ecf20Sopenharmony_ci * structure. 14718c2ecf20Sopenharmony_ci */ 14728c2ecf20Sopenharmony_cistatic inline void copy_frags(struct sk_buff *skb, 14738c2ecf20Sopenharmony_ci const struct pkt_gl *gl, 14748c2ecf20Sopenharmony_ci unsigned int offset) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci int i; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* usually there's just one frag */ 14798c2ecf20Sopenharmony_ci __skb_fill_page_desc(skb, 0, gl->frags[0].page, 14808c2ecf20Sopenharmony_ci gl->frags[0].offset + offset, 14818c2ecf20Sopenharmony_ci gl->frags[0].size - offset); 14828c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags = gl->nfrags; 14838c2ecf20Sopenharmony_ci for (i = 1; i < gl->nfrags; i++) 14848c2ecf20Sopenharmony_ci __skb_fill_page_desc(skb, i, gl->frags[i].page, 14858c2ecf20Sopenharmony_ci gl->frags[i].offset, 14868c2ecf20Sopenharmony_ci gl->frags[i].size); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* get a reference to the last page, we don't own it */ 14898c2ecf20Sopenharmony_ci get_page(gl->frags[gl->nfrags - 1].page); 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci/** 14938c2ecf20Sopenharmony_ci * t4vf_pktgl_to_skb - build an sk_buff from a packet gather list 14948c2ecf20Sopenharmony_ci * @gl: the gather list 14958c2ecf20Sopenharmony_ci * @skb_len: size of sk_buff main body if it carries fragments 14968c2ecf20Sopenharmony_ci * @pull_len: amount of data to move to the sk_buff's main body 14978c2ecf20Sopenharmony_ci * 14988c2ecf20Sopenharmony_ci * Builds an sk_buff from the given packet gather list. Returns the 14998c2ecf20Sopenharmony_ci * sk_buff or %NULL if sk_buff allocation failed. 15008c2ecf20Sopenharmony_ci */ 15018c2ecf20Sopenharmony_cistatic struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl, 15028c2ecf20Sopenharmony_ci unsigned int skb_len, 15038c2ecf20Sopenharmony_ci unsigned int pull_len) 15048c2ecf20Sopenharmony_ci{ 15058c2ecf20Sopenharmony_ci struct sk_buff *skb; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* 15088c2ecf20Sopenharmony_ci * If the ingress packet is small enough, allocate an skb large enough 15098c2ecf20Sopenharmony_ci * for all of the data and copy it inline. Otherwise, allocate an skb 15108c2ecf20Sopenharmony_ci * with enough room to pull in the header and reference the rest of 15118c2ecf20Sopenharmony_ci * the data via the skb fragment list. 15128c2ecf20Sopenharmony_ci * 15138c2ecf20Sopenharmony_ci * Below we rely on RX_COPY_THRES being less than the smallest Rx 15148c2ecf20Sopenharmony_ci * buff! size, which is expected since buffers are at least 15158c2ecf20Sopenharmony_ci * PAGE_SIZEd. In this case packets up to RX_COPY_THRES have only one 15168c2ecf20Sopenharmony_ci * fragment. 15178c2ecf20Sopenharmony_ci */ 15188c2ecf20Sopenharmony_ci if (gl->tot_len <= RX_COPY_THRES) { 15198c2ecf20Sopenharmony_ci /* small packets have only one fragment */ 15208c2ecf20Sopenharmony_ci skb = alloc_skb(gl->tot_len, GFP_ATOMIC); 15218c2ecf20Sopenharmony_ci if (unlikely(!skb)) 15228c2ecf20Sopenharmony_ci goto out; 15238c2ecf20Sopenharmony_ci __skb_put(skb, gl->tot_len); 15248c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, gl->va, gl->tot_len); 15258c2ecf20Sopenharmony_ci } else { 15268c2ecf20Sopenharmony_ci skb = alloc_skb(skb_len, GFP_ATOMIC); 15278c2ecf20Sopenharmony_ci if (unlikely(!skb)) 15288c2ecf20Sopenharmony_ci goto out; 15298c2ecf20Sopenharmony_ci __skb_put(skb, pull_len); 15308c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, gl->va, pull_len); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci copy_frags(skb, gl, pull_len); 15338c2ecf20Sopenharmony_ci skb->len = gl->tot_len; 15348c2ecf20Sopenharmony_ci skb->data_len = skb->len - pull_len; 15358c2ecf20Sopenharmony_ci skb->truesize += skb->data_len; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ciout: 15398c2ecf20Sopenharmony_ci return skb; 15408c2ecf20Sopenharmony_ci} 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci/** 15438c2ecf20Sopenharmony_ci * t4vf_pktgl_free - free a packet gather list 15448c2ecf20Sopenharmony_ci * @gl: the gather list 15458c2ecf20Sopenharmony_ci * 15468c2ecf20Sopenharmony_ci * Releases the pages of a packet gather list. We do not own the last 15478c2ecf20Sopenharmony_ci * page on the list and do not free it. 15488c2ecf20Sopenharmony_ci */ 15498c2ecf20Sopenharmony_cistatic void t4vf_pktgl_free(const struct pkt_gl *gl) 15508c2ecf20Sopenharmony_ci{ 15518c2ecf20Sopenharmony_ci int frag; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci frag = gl->nfrags - 1; 15548c2ecf20Sopenharmony_ci while (frag--) 15558c2ecf20Sopenharmony_ci put_page(gl->frags[frag].page); 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci/** 15598c2ecf20Sopenharmony_ci * do_gro - perform Generic Receive Offload ingress packet processing 15608c2ecf20Sopenharmony_ci * @rxq: ingress RX Ethernet Queue 15618c2ecf20Sopenharmony_ci * @gl: gather list for ingress packet 15628c2ecf20Sopenharmony_ci * @pkt: CPL header for last packet fragment 15638c2ecf20Sopenharmony_ci * 15648c2ecf20Sopenharmony_ci * Perform Generic Receive Offload (GRO) ingress packet processing. 15658c2ecf20Sopenharmony_ci * We use the standard Linux GRO interfaces for this. 15668c2ecf20Sopenharmony_ci */ 15678c2ecf20Sopenharmony_cistatic void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, 15688c2ecf20Sopenharmony_ci const struct cpl_rx_pkt *pkt) 15698c2ecf20Sopenharmony_ci{ 15708c2ecf20Sopenharmony_ci struct adapter *adapter = rxq->rspq.adapter; 15718c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 15728c2ecf20Sopenharmony_ci struct port_info *pi; 15738c2ecf20Sopenharmony_ci int ret; 15748c2ecf20Sopenharmony_ci struct sk_buff *skb; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci skb = napi_get_frags(&rxq->rspq.napi); 15778c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 15788c2ecf20Sopenharmony_ci t4vf_pktgl_free(gl); 15798c2ecf20Sopenharmony_ci rxq->stats.rx_drops++; 15808c2ecf20Sopenharmony_ci return; 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci copy_frags(skb, gl, s->pktshift); 15848c2ecf20Sopenharmony_ci skb->len = gl->tot_len - s->pktshift; 15858c2ecf20Sopenharmony_ci skb->data_len = skb->len; 15868c2ecf20Sopenharmony_ci skb->truesize += skb->data_len; 15878c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 15888c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, rxq->rspq.idx); 15898c2ecf20Sopenharmony_ci pi = netdev_priv(skb->dev); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci if (pkt->vlan_ex && !pi->vlan_id) { 15928c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, cpu_to_be16(ETH_P_8021Q), 15938c2ecf20Sopenharmony_ci be16_to_cpu(pkt->vlan)); 15948c2ecf20Sopenharmony_ci rxq->stats.vlan_ex++; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci ret = napi_gro_frags(&rxq->rspq.napi); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (ret == GRO_HELD) 15998c2ecf20Sopenharmony_ci rxq->stats.lro_pkts++; 16008c2ecf20Sopenharmony_ci else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE) 16018c2ecf20Sopenharmony_ci rxq->stats.lro_merged++; 16028c2ecf20Sopenharmony_ci rxq->stats.pkts++; 16038c2ecf20Sopenharmony_ci rxq->stats.rx_cso++; 16048c2ecf20Sopenharmony_ci} 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci/** 16078c2ecf20Sopenharmony_ci * t4vf_ethrx_handler - process an ingress ethernet packet 16088c2ecf20Sopenharmony_ci * @rspq: the response queue that received the packet 16098c2ecf20Sopenharmony_ci * @rsp: the response queue descriptor holding the RX_PKT message 16108c2ecf20Sopenharmony_ci * @gl: the gather list of packet fragments 16118c2ecf20Sopenharmony_ci * 16128c2ecf20Sopenharmony_ci * Process an ingress ethernet packet and deliver it to the stack. 16138c2ecf20Sopenharmony_ci */ 16148c2ecf20Sopenharmony_ciint t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, 16158c2ecf20Sopenharmony_ci const struct pkt_gl *gl) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci struct sk_buff *skb; 16188c2ecf20Sopenharmony_ci const struct cpl_rx_pkt *pkt = (void *)rsp; 16198c2ecf20Sopenharmony_ci bool csum_ok = pkt->csum_calc && !pkt->err_vec && 16208c2ecf20Sopenharmony_ci (rspq->netdev->features & NETIF_F_RXCSUM); 16218c2ecf20Sopenharmony_ci struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq); 16228c2ecf20Sopenharmony_ci struct adapter *adapter = rspq->adapter; 16238c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 16248c2ecf20Sopenharmony_ci struct port_info *pi; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci /* 16278c2ecf20Sopenharmony_ci * If this is a good TCP packet and we have Generic Receive Offload 16288c2ecf20Sopenharmony_ci * enabled, handle the packet in the GRO path. 16298c2ecf20Sopenharmony_ci */ 16308c2ecf20Sopenharmony_ci if ((pkt->l2info & cpu_to_be32(RXF_TCP_F)) && 16318c2ecf20Sopenharmony_ci (rspq->netdev->features & NETIF_F_GRO) && csum_ok && 16328c2ecf20Sopenharmony_ci !pkt->ip_frag) { 16338c2ecf20Sopenharmony_ci do_gro(rxq, gl, pkt); 16348c2ecf20Sopenharmony_ci return 0; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci /* 16388c2ecf20Sopenharmony_ci * Convert the Packet Gather List into an skb. 16398c2ecf20Sopenharmony_ci */ 16408c2ecf20Sopenharmony_ci skb = t4vf_pktgl_to_skb(gl, RX_SKB_LEN, RX_PULL_LEN); 16418c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 16428c2ecf20Sopenharmony_ci t4vf_pktgl_free(gl); 16438c2ecf20Sopenharmony_ci rxq->stats.rx_drops++; 16448c2ecf20Sopenharmony_ci return 0; 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci __skb_pull(skb, s->pktshift); 16478c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, rspq->netdev); 16488c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, rspq->idx); 16498c2ecf20Sopenharmony_ci pi = netdev_priv(skb->dev); 16508c2ecf20Sopenharmony_ci rxq->stats.pkts++; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci if (csum_ok && !pkt->err_vec && 16538c2ecf20Sopenharmony_ci (be32_to_cpu(pkt->l2info) & (RXF_UDP_F | RXF_TCP_F))) { 16548c2ecf20Sopenharmony_ci if (!pkt->ip_frag) { 16558c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 16568c2ecf20Sopenharmony_ci rxq->stats.rx_cso++; 16578c2ecf20Sopenharmony_ci } else if (pkt->l2info & htonl(RXF_IP_F)) { 16588c2ecf20Sopenharmony_ci __sum16 c = (__force __sum16)pkt->csum; 16598c2ecf20Sopenharmony_ci skb->csum = csum_unfold(c); 16608c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 16618c2ecf20Sopenharmony_ci rxq->stats.rx_cso++; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci } else 16648c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci if (pkt->vlan_ex && !pi->vlan_id) { 16678c2ecf20Sopenharmony_ci rxq->stats.vlan_ex++; 16688c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 16698c2ecf20Sopenharmony_ci be16_to_cpu(pkt->vlan)); 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci netif_receive_skb(skb); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci return 0; 16758c2ecf20Sopenharmony_ci} 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci/** 16788c2ecf20Sopenharmony_ci * is_new_response - check if a response is newly written 16798c2ecf20Sopenharmony_ci * @rc: the response control descriptor 16808c2ecf20Sopenharmony_ci * @rspq: the response queue 16818c2ecf20Sopenharmony_ci * 16828c2ecf20Sopenharmony_ci * Returns true if a response descriptor contains a yet unprocessed 16838c2ecf20Sopenharmony_ci * response. 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_cistatic inline bool is_new_response(const struct rsp_ctrl *rc, 16868c2ecf20Sopenharmony_ci const struct sge_rspq *rspq) 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci return ((rc->type_gen >> RSPD_GEN_S) & 0x1) == rspq->gen; 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci/** 16928c2ecf20Sopenharmony_ci * restore_rx_bufs - put back a packet's RX buffers 16938c2ecf20Sopenharmony_ci * @gl: the packet gather list 16948c2ecf20Sopenharmony_ci * @fl: the SGE Free List 16958c2ecf20Sopenharmony_ci * @frags: how many fragments in @si 16968c2ecf20Sopenharmony_ci * 16978c2ecf20Sopenharmony_ci * Called when we find out that the current packet, @si, can't be 16988c2ecf20Sopenharmony_ci * processed right away for some reason. This is a very rare event and 16998c2ecf20Sopenharmony_ci * there's no effort to make this suspension/resumption process 17008c2ecf20Sopenharmony_ci * particularly efficient. 17018c2ecf20Sopenharmony_ci * 17028c2ecf20Sopenharmony_ci * We implement the suspension by putting all of the RX buffers associated 17038c2ecf20Sopenharmony_ci * with the current packet back on the original Free List. The buffers 17048c2ecf20Sopenharmony_ci * have already been unmapped and are left unmapped, we mark them as 17058c2ecf20Sopenharmony_ci * unmapped in order to prevent further unmapping attempts. (Effectively 17068c2ecf20Sopenharmony_ci * this function undoes the series of @unmap_rx_buf calls which were done 17078c2ecf20Sopenharmony_ci * to create the current packet's gather list.) This leaves us ready to 17088c2ecf20Sopenharmony_ci * restart processing of the packet the next time we start processing the 17098c2ecf20Sopenharmony_ci * RX Queue ... 17108c2ecf20Sopenharmony_ci */ 17118c2ecf20Sopenharmony_cistatic void restore_rx_bufs(const struct pkt_gl *gl, struct sge_fl *fl, 17128c2ecf20Sopenharmony_ci int frags) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci struct rx_sw_desc *sdesc; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci while (frags--) { 17178c2ecf20Sopenharmony_ci if (fl->cidx == 0) 17188c2ecf20Sopenharmony_ci fl->cidx = fl->size - 1; 17198c2ecf20Sopenharmony_ci else 17208c2ecf20Sopenharmony_ci fl->cidx--; 17218c2ecf20Sopenharmony_ci sdesc = &fl->sdesc[fl->cidx]; 17228c2ecf20Sopenharmony_ci sdesc->page = gl->frags[frags].page; 17238c2ecf20Sopenharmony_ci sdesc->dma_addr |= RX_UNMAPPED_BUF; 17248c2ecf20Sopenharmony_ci fl->avail++; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci/** 17298c2ecf20Sopenharmony_ci * rspq_next - advance to the next entry in a response queue 17308c2ecf20Sopenharmony_ci * @rspq: the queue 17318c2ecf20Sopenharmony_ci * 17328c2ecf20Sopenharmony_ci * Updates the state of a response queue to advance it to the next entry. 17338c2ecf20Sopenharmony_ci */ 17348c2ecf20Sopenharmony_cistatic inline void rspq_next(struct sge_rspq *rspq) 17358c2ecf20Sopenharmony_ci{ 17368c2ecf20Sopenharmony_ci rspq->cur_desc = (void *)rspq->cur_desc + rspq->iqe_len; 17378c2ecf20Sopenharmony_ci if (unlikely(++rspq->cidx == rspq->size)) { 17388c2ecf20Sopenharmony_ci rspq->cidx = 0; 17398c2ecf20Sopenharmony_ci rspq->gen ^= 1; 17408c2ecf20Sopenharmony_ci rspq->cur_desc = rspq->desc; 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci} 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci/** 17458c2ecf20Sopenharmony_ci * process_responses - process responses from an SGE response queue 17468c2ecf20Sopenharmony_ci * @rspq: the ingress response queue to process 17478c2ecf20Sopenharmony_ci * @budget: how many responses can be processed in this round 17488c2ecf20Sopenharmony_ci * 17498c2ecf20Sopenharmony_ci * Process responses from a Scatter Gather Engine response queue up to 17508c2ecf20Sopenharmony_ci * the supplied budget. Responses include received packets as well as 17518c2ecf20Sopenharmony_ci * control messages from firmware or hardware. 17528c2ecf20Sopenharmony_ci * 17538c2ecf20Sopenharmony_ci * Additionally choose the interrupt holdoff time for the next interrupt 17548c2ecf20Sopenharmony_ci * on this queue. If the system is under memory shortage use a fairly 17558c2ecf20Sopenharmony_ci * long delay to help recovery. 17568c2ecf20Sopenharmony_ci */ 17578c2ecf20Sopenharmony_cistatic int process_responses(struct sge_rspq *rspq, int budget) 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq); 17608c2ecf20Sopenharmony_ci struct adapter *adapter = rspq->adapter; 17618c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 17628c2ecf20Sopenharmony_ci int budget_left = budget; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci while (likely(budget_left)) { 17658c2ecf20Sopenharmony_ci int ret, rsp_type; 17668c2ecf20Sopenharmony_ci const struct rsp_ctrl *rc; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci rc = (void *)rspq->cur_desc + (rspq->iqe_len - sizeof(*rc)); 17698c2ecf20Sopenharmony_ci if (!is_new_response(rc, rspq)) 17708c2ecf20Sopenharmony_ci break; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci /* 17738c2ecf20Sopenharmony_ci * Figure out what kind of response we've received from the 17748c2ecf20Sopenharmony_ci * SGE. 17758c2ecf20Sopenharmony_ci */ 17768c2ecf20Sopenharmony_ci dma_rmb(); 17778c2ecf20Sopenharmony_ci rsp_type = RSPD_TYPE_G(rc->type_gen); 17788c2ecf20Sopenharmony_ci if (likely(rsp_type == RSPD_TYPE_FLBUF_X)) { 17798c2ecf20Sopenharmony_ci struct page_frag *fp; 17808c2ecf20Sopenharmony_ci struct pkt_gl gl; 17818c2ecf20Sopenharmony_ci const struct rx_sw_desc *sdesc; 17828c2ecf20Sopenharmony_ci u32 bufsz, frag; 17838c2ecf20Sopenharmony_ci u32 len = be32_to_cpu(rc->pldbuflen_qid); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci /* 17868c2ecf20Sopenharmony_ci * If we get a "new buffer" message from the SGE we 17878c2ecf20Sopenharmony_ci * need to move on to the next Free List buffer. 17888c2ecf20Sopenharmony_ci */ 17898c2ecf20Sopenharmony_ci if (len & RSPD_NEWBUF_F) { 17908c2ecf20Sopenharmony_ci /* 17918c2ecf20Sopenharmony_ci * We get one "new buffer" message when we 17928c2ecf20Sopenharmony_ci * first start up a queue so we need to ignore 17938c2ecf20Sopenharmony_ci * it when our offset into the buffer is 0. 17948c2ecf20Sopenharmony_ci */ 17958c2ecf20Sopenharmony_ci if (likely(rspq->offset > 0)) { 17968c2ecf20Sopenharmony_ci free_rx_bufs(rspq->adapter, &rxq->fl, 17978c2ecf20Sopenharmony_ci 1); 17988c2ecf20Sopenharmony_ci rspq->offset = 0; 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci len = RSPD_LEN_G(len); 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci gl.tot_len = len; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci /* 18058c2ecf20Sopenharmony_ci * Gather packet fragments. 18068c2ecf20Sopenharmony_ci */ 18078c2ecf20Sopenharmony_ci for (frag = 0, fp = gl.frags; /**/; frag++, fp++) { 18088c2ecf20Sopenharmony_ci BUG_ON(frag >= MAX_SKB_FRAGS); 18098c2ecf20Sopenharmony_ci BUG_ON(rxq->fl.avail == 0); 18108c2ecf20Sopenharmony_ci sdesc = &rxq->fl.sdesc[rxq->fl.cidx]; 18118c2ecf20Sopenharmony_ci bufsz = get_buf_size(adapter, sdesc); 18128c2ecf20Sopenharmony_ci fp->page = sdesc->page; 18138c2ecf20Sopenharmony_ci fp->offset = rspq->offset; 18148c2ecf20Sopenharmony_ci fp->size = min(bufsz, len); 18158c2ecf20Sopenharmony_ci len -= fp->size; 18168c2ecf20Sopenharmony_ci if (!len) 18178c2ecf20Sopenharmony_ci break; 18188c2ecf20Sopenharmony_ci unmap_rx_buf(rspq->adapter, &rxq->fl); 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci gl.nfrags = frag+1; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci /* 18238c2ecf20Sopenharmony_ci * Last buffer remains mapped so explicitly make it 18248c2ecf20Sopenharmony_ci * coherent for CPU access and start preloading first 18258c2ecf20Sopenharmony_ci * cache line ... 18268c2ecf20Sopenharmony_ci */ 18278c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(rspq->adapter->pdev_dev, 18288c2ecf20Sopenharmony_ci get_buf_addr(sdesc), 18298c2ecf20Sopenharmony_ci fp->size, DMA_FROM_DEVICE); 18308c2ecf20Sopenharmony_ci gl.va = (page_address(gl.frags[0].page) + 18318c2ecf20Sopenharmony_ci gl.frags[0].offset); 18328c2ecf20Sopenharmony_ci prefetch(gl.va); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci /* 18358c2ecf20Sopenharmony_ci * Hand the new ingress packet to the handler for 18368c2ecf20Sopenharmony_ci * this Response Queue. 18378c2ecf20Sopenharmony_ci */ 18388c2ecf20Sopenharmony_ci ret = rspq->handler(rspq, rspq->cur_desc, &gl); 18398c2ecf20Sopenharmony_ci if (likely(ret == 0)) 18408c2ecf20Sopenharmony_ci rspq->offset += ALIGN(fp->size, s->fl_align); 18418c2ecf20Sopenharmony_ci else 18428c2ecf20Sopenharmony_ci restore_rx_bufs(&gl, &rxq->fl, frag); 18438c2ecf20Sopenharmony_ci } else if (likely(rsp_type == RSPD_TYPE_CPL_X)) { 18448c2ecf20Sopenharmony_ci ret = rspq->handler(rspq, rspq->cur_desc, NULL); 18458c2ecf20Sopenharmony_ci } else { 18468c2ecf20Sopenharmony_ci WARN_ON(rsp_type > RSPD_TYPE_CPL_X); 18478c2ecf20Sopenharmony_ci ret = 0; 18488c2ecf20Sopenharmony_ci } 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (unlikely(ret)) { 18518c2ecf20Sopenharmony_ci /* 18528c2ecf20Sopenharmony_ci * Couldn't process descriptor, back off for recovery. 18538c2ecf20Sopenharmony_ci * We use the SGE's last timer which has the longest 18548c2ecf20Sopenharmony_ci * interrupt coalescing value ... 18558c2ecf20Sopenharmony_ci */ 18568c2ecf20Sopenharmony_ci const int NOMEM_TIMER_IDX = SGE_NTIMERS-1; 18578c2ecf20Sopenharmony_ci rspq->next_intr_params = 18588c2ecf20Sopenharmony_ci QINTR_TIMER_IDX_V(NOMEM_TIMER_IDX); 18598c2ecf20Sopenharmony_ci break; 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci rspq_next(rspq); 18638c2ecf20Sopenharmony_ci budget_left--; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci /* 18678c2ecf20Sopenharmony_ci * If this is a Response Queue with an associated Free List and 18688c2ecf20Sopenharmony_ci * at least two Egress Queue units available in the Free List 18698c2ecf20Sopenharmony_ci * for new buffer pointers, refill the Free List. 18708c2ecf20Sopenharmony_ci */ 18718c2ecf20Sopenharmony_ci if (rspq->offset >= 0 && 18728c2ecf20Sopenharmony_ci fl_cap(&rxq->fl) - rxq->fl.avail >= 2*FL_PER_EQ_UNIT) 18738c2ecf20Sopenharmony_ci __refill_fl(rspq->adapter, &rxq->fl); 18748c2ecf20Sopenharmony_ci return budget - budget_left; 18758c2ecf20Sopenharmony_ci} 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci/** 18788c2ecf20Sopenharmony_ci * napi_rx_handler - the NAPI handler for RX processing 18798c2ecf20Sopenharmony_ci * @napi: the napi instance 18808c2ecf20Sopenharmony_ci * @budget: how many packets we can process in this round 18818c2ecf20Sopenharmony_ci * 18828c2ecf20Sopenharmony_ci * Handler for new data events when using NAPI. This does not need any 18838c2ecf20Sopenharmony_ci * locking or protection from interrupts as data interrupts are off at 18848c2ecf20Sopenharmony_ci * this point and other adapter interrupts do not interfere (the latter 18858c2ecf20Sopenharmony_ci * in not a concern at all with MSI-X as non-data interrupts then have 18868c2ecf20Sopenharmony_ci * a separate handler). 18878c2ecf20Sopenharmony_ci */ 18888c2ecf20Sopenharmony_cistatic int napi_rx_handler(struct napi_struct *napi, int budget) 18898c2ecf20Sopenharmony_ci{ 18908c2ecf20Sopenharmony_ci unsigned int intr_params; 18918c2ecf20Sopenharmony_ci struct sge_rspq *rspq = container_of(napi, struct sge_rspq, napi); 18928c2ecf20Sopenharmony_ci int work_done = process_responses(rspq, budget); 18938c2ecf20Sopenharmony_ci u32 val; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci if (likely(work_done < budget)) { 18968c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 18978c2ecf20Sopenharmony_ci intr_params = rspq->next_intr_params; 18988c2ecf20Sopenharmony_ci rspq->next_intr_params = rspq->intr_params; 18998c2ecf20Sopenharmony_ci } else 19008c2ecf20Sopenharmony_ci intr_params = QINTR_TIMER_IDX_V(SGE_TIMER_UPD_CIDX); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (unlikely(work_done == 0)) 19038c2ecf20Sopenharmony_ci rspq->unhandled_irqs++; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci val = CIDXINC_V(work_done) | SEINTARM_V(intr_params); 19068c2ecf20Sopenharmony_ci /* If we don't have access to the new User GTS (T5+), use the old 19078c2ecf20Sopenharmony_ci * doorbell mechanism; otherwise use the new BAR2 mechanism. 19088c2ecf20Sopenharmony_ci */ 19098c2ecf20Sopenharmony_ci if (unlikely(!rspq->bar2_addr)) { 19108c2ecf20Sopenharmony_ci t4_write_reg(rspq->adapter, 19118c2ecf20Sopenharmony_ci T4VF_SGE_BASE_ADDR + SGE_VF_GTS, 19128c2ecf20Sopenharmony_ci val | INGRESSQID_V((u32)rspq->cntxt_id)); 19138c2ecf20Sopenharmony_ci } else { 19148c2ecf20Sopenharmony_ci writel(val | INGRESSQID_V(rspq->bar2_qid), 19158c2ecf20Sopenharmony_ci rspq->bar2_addr + SGE_UDB_GTS); 19168c2ecf20Sopenharmony_ci wmb(); 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci return work_done; 19198c2ecf20Sopenharmony_ci} 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci/* 19228c2ecf20Sopenharmony_ci * The MSI-X interrupt handler for an SGE response queue for the NAPI case 19238c2ecf20Sopenharmony_ci * (i.e., response queue serviced by NAPI polling). 19248c2ecf20Sopenharmony_ci */ 19258c2ecf20Sopenharmony_ciirqreturn_t t4vf_sge_intr_msix(int irq, void *cookie) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci struct sge_rspq *rspq = cookie; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci napi_schedule(&rspq->napi); 19308c2ecf20Sopenharmony_ci return IRQ_HANDLED; 19318c2ecf20Sopenharmony_ci} 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci/* 19348c2ecf20Sopenharmony_ci * Process the indirect interrupt entries in the interrupt queue and kick off 19358c2ecf20Sopenharmony_ci * NAPI for each queue that has generated an entry. 19368c2ecf20Sopenharmony_ci */ 19378c2ecf20Sopenharmony_cistatic unsigned int process_intrq(struct adapter *adapter) 19388c2ecf20Sopenharmony_ci{ 19398c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 19408c2ecf20Sopenharmony_ci struct sge_rspq *intrq = &s->intrq; 19418c2ecf20Sopenharmony_ci unsigned int work_done; 19428c2ecf20Sopenharmony_ci u32 val; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci spin_lock(&adapter->sge.intrq_lock); 19458c2ecf20Sopenharmony_ci for (work_done = 0; ; work_done++) { 19468c2ecf20Sopenharmony_ci const struct rsp_ctrl *rc; 19478c2ecf20Sopenharmony_ci unsigned int qid, iq_idx; 19488c2ecf20Sopenharmony_ci struct sge_rspq *rspq; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci /* 19518c2ecf20Sopenharmony_ci * Grab the next response from the interrupt queue and bail 19528c2ecf20Sopenharmony_ci * out if it's not a new response. 19538c2ecf20Sopenharmony_ci */ 19548c2ecf20Sopenharmony_ci rc = (void *)intrq->cur_desc + (intrq->iqe_len - sizeof(*rc)); 19558c2ecf20Sopenharmony_ci if (!is_new_response(rc, intrq)) 19568c2ecf20Sopenharmony_ci break; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci /* 19598c2ecf20Sopenharmony_ci * If the response isn't a forwarded interrupt message issue a 19608c2ecf20Sopenharmony_ci * error and go on to the next response message. This should 19618c2ecf20Sopenharmony_ci * never happen ... 19628c2ecf20Sopenharmony_ci */ 19638c2ecf20Sopenharmony_ci dma_rmb(); 19648c2ecf20Sopenharmony_ci if (unlikely(RSPD_TYPE_G(rc->type_gen) != RSPD_TYPE_INTR_X)) { 19658c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 19668c2ecf20Sopenharmony_ci "Unexpected INTRQ response type %d\n", 19678c2ecf20Sopenharmony_ci RSPD_TYPE_G(rc->type_gen)); 19688c2ecf20Sopenharmony_ci continue; 19698c2ecf20Sopenharmony_ci } 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci /* 19728c2ecf20Sopenharmony_ci * Extract the Queue ID from the interrupt message and perform 19738c2ecf20Sopenharmony_ci * sanity checking to make sure it really refers to one of our 19748c2ecf20Sopenharmony_ci * Ingress Queues which is active and matches the queue's ID. 19758c2ecf20Sopenharmony_ci * None of these error conditions should ever happen so we may 19768c2ecf20Sopenharmony_ci * want to either make them fatal and/or conditionalized under 19778c2ecf20Sopenharmony_ci * DEBUG. 19788c2ecf20Sopenharmony_ci */ 19798c2ecf20Sopenharmony_ci qid = RSPD_QID_G(be32_to_cpu(rc->pldbuflen_qid)); 19808c2ecf20Sopenharmony_ci iq_idx = IQ_IDX(s, qid); 19818c2ecf20Sopenharmony_ci if (unlikely(iq_idx >= MAX_INGQ)) { 19828c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 19838c2ecf20Sopenharmony_ci "Ingress QID %d out of range\n", qid); 19848c2ecf20Sopenharmony_ci continue; 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci rspq = s->ingr_map[iq_idx]; 19878c2ecf20Sopenharmony_ci if (unlikely(rspq == NULL)) { 19888c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 19898c2ecf20Sopenharmony_ci "Ingress QID %d RSPQ=NULL\n", qid); 19908c2ecf20Sopenharmony_ci continue; 19918c2ecf20Sopenharmony_ci } 19928c2ecf20Sopenharmony_ci if (unlikely(rspq->abs_id != qid)) { 19938c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 19948c2ecf20Sopenharmony_ci "Ingress QID %d refers to RSPQ %d\n", 19958c2ecf20Sopenharmony_ci qid, rspq->abs_id); 19968c2ecf20Sopenharmony_ci continue; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci /* 20008c2ecf20Sopenharmony_ci * Schedule NAPI processing on the indicated Response Queue 20018c2ecf20Sopenharmony_ci * and move on to the next entry in the Forwarded Interrupt 20028c2ecf20Sopenharmony_ci * Queue. 20038c2ecf20Sopenharmony_ci */ 20048c2ecf20Sopenharmony_ci napi_schedule(&rspq->napi); 20058c2ecf20Sopenharmony_ci rspq_next(intrq); 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci val = CIDXINC_V(work_done) | SEINTARM_V(intrq->intr_params); 20098c2ecf20Sopenharmony_ci /* If we don't have access to the new User GTS (T5+), use the old 20108c2ecf20Sopenharmony_ci * doorbell mechanism; otherwise use the new BAR2 mechanism. 20118c2ecf20Sopenharmony_ci */ 20128c2ecf20Sopenharmony_ci if (unlikely(!intrq->bar2_addr)) { 20138c2ecf20Sopenharmony_ci t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, 20148c2ecf20Sopenharmony_ci val | INGRESSQID_V(intrq->cntxt_id)); 20158c2ecf20Sopenharmony_ci } else { 20168c2ecf20Sopenharmony_ci writel(val | INGRESSQID_V(intrq->bar2_qid), 20178c2ecf20Sopenharmony_ci intrq->bar2_addr + SGE_UDB_GTS); 20188c2ecf20Sopenharmony_ci wmb(); 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci spin_unlock(&adapter->sge.intrq_lock); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci return work_done; 20248c2ecf20Sopenharmony_ci} 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci/* 20278c2ecf20Sopenharmony_ci * The MSI interrupt handler handles data events from SGE response queues as 20288c2ecf20Sopenharmony_ci * well as error and other async events as they all use the same MSI vector. 20298c2ecf20Sopenharmony_ci */ 20308c2ecf20Sopenharmony_cistatic irqreturn_t t4vf_intr_msi(int irq, void *cookie) 20318c2ecf20Sopenharmony_ci{ 20328c2ecf20Sopenharmony_ci struct adapter *adapter = cookie; 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci process_intrq(adapter); 20358c2ecf20Sopenharmony_ci return IRQ_HANDLED; 20368c2ecf20Sopenharmony_ci} 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci/** 20398c2ecf20Sopenharmony_ci * t4vf_intr_handler - select the top-level interrupt handler 20408c2ecf20Sopenharmony_ci * @adapter: the adapter 20418c2ecf20Sopenharmony_ci * 20428c2ecf20Sopenharmony_ci * Selects the top-level interrupt handler based on the type of interrupts 20438c2ecf20Sopenharmony_ci * (MSI-X or MSI). 20448c2ecf20Sopenharmony_ci */ 20458c2ecf20Sopenharmony_ciirq_handler_t t4vf_intr_handler(struct adapter *adapter) 20468c2ecf20Sopenharmony_ci{ 20478c2ecf20Sopenharmony_ci BUG_ON((adapter->flags & 20488c2ecf20Sopenharmony_ci (CXGB4VF_USING_MSIX | CXGB4VF_USING_MSI)) == 0); 20498c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4VF_USING_MSIX) 20508c2ecf20Sopenharmony_ci return t4vf_sge_intr_msix; 20518c2ecf20Sopenharmony_ci else 20528c2ecf20Sopenharmony_ci return t4vf_intr_msi; 20538c2ecf20Sopenharmony_ci} 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci/** 20568c2ecf20Sopenharmony_ci * sge_rx_timer_cb - perform periodic maintenance of SGE RX queues 20578c2ecf20Sopenharmony_ci * @t: Rx timer 20588c2ecf20Sopenharmony_ci * 20598c2ecf20Sopenharmony_ci * Runs periodically from a timer to perform maintenance of SGE RX queues. 20608c2ecf20Sopenharmony_ci * 20618c2ecf20Sopenharmony_ci * a) Replenishes RX queues that have run out due to memory shortage. 20628c2ecf20Sopenharmony_ci * Normally new RX buffers are added when existing ones are consumed but 20638c2ecf20Sopenharmony_ci * when out of memory a queue can become empty. We schedule NAPI to do 20648c2ecf20Sopenharmony_ci * the actual refill. 20658c2ecf20Sopenharmony_ci */ 20668c2ecf20Sopenharmony_cistatic void sge_rx_timer_cb(struct timer_list *t) 20678c2ecf20Sopenharmony_ci{ 20688c2ecf20Sopenharmony_ci struct adapter *adapter = from_timer(adapter, t, sge.rx_timer); 20698c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 20708c2ecf20Sopenharmony_ci unsigned int i; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci /* 20738c2ecf20Sopenharmony_ci * Scan the "Starving Free Lists" flag array looking for any Free 20748c2ecf20Sopenharmony_ci * Lists in need of more free buffers. If we find one and it's not 20758c2ecf20Sopenharmony_ci * being actively polled, then bump its "starving" counter and attempt 20768c2ecf20Sopenharmony_ci * to refill it. If we're successful in adding enough buffers to push 20778c2ecf20Sopenharmony_ci * the Free List over the starving threshold, then we can clear its 20788c2ecf20Sopenharmony_ci * "starving" status. 20798c2ecf20Sopenharmony_ci */ 20808c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) { 20818c2ecf20Sopenharmony_ci unsigned long m; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci for (m = s->starving_fl[i]; m; m &= m - 1) { 20848c2ecf20Sopenharmony_ci unsigned int id = __ffs(m) + i * BITS_PER_LONG; 20858c2ecf20Sopenharmony_ci struct sge_fl *fl = s->egr_map[id]; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci clear_bit(id, s->starving_fl); 20888c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci /* 20918c2ecf20Sopenharmony_ci * Since we are accessing fl without a lock there's a 20928c2ecf20Sopenharmony_ci * small probability of a false positive where we 20938c2ecf20Sopenharmony_ci * schedule napi but the FL is no longer starving. 20948c2ecf20Sopenharmony_ci * No biggie. 20958c2ecf20Sopenharmony_ci */ 20968c2ecf20Sopenharmony_ci if (fl_starving(adapter, fl)) { 20978c2ecf20Sopenharmony_ci struct sge_eth_rxq *rxq; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci rxq = container_of(fl, struct sge_eth_rxq, fl); 21008c2ecf20Sopenharmony_ci if (napi_reschedule(&rxq->rspq.napi)) 21018c2ecf20Sopenharmony_ci fl->starving++; 21028c2ecf20Sopenharmony_ci else 21038c2ecf20Sopenharmony_ci set_bit(id, s->starving_fl); 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci } 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci /* 21098c2ecf20Sopenharmony_ci * Reschedule the next scan for starving Free Lists ... 21108c2ecf20Sopenharmony_ci */ 21118c2ecf20Sopenharmony_ci mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD); 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci/** 21158c2ecf20Sopenharmony_ci * sge_tx_timer_cb - perform periodic maintenance of SGE Tx queues 21168c2ecf20Sopenharmony_ci * @t: Tx timer 21178c2ecf20Sopenharmony_ci * 21188c2ecf20Sopenharmony_ci * Runs periodically from a timer to perform maintenance of SGE TX queues. 21198c2ecf20Sopenharmony_ci * 21208c2ecf20Sopenharmony_ci * b) Reclaims completed Tx packets for the Ethernet queues. Normally 21218c2ecf20Sopenharmony_ci * packets are cleaned up by new Tx packets, this timer cleans up packets 21228c2ecf20Sopenharmony_ci * when no new packets are being submitted. This is essential for pktgen, 21238c2ecf20Sopenharmony_ci * at least. 21248c2ecf20Sopenharmony_ci */ 21258c2ecf20Sopenharmony_cistatic void sge_tx_timer_cb(struct timer_list *t) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci struct adapter *adapter = from_timer(adapter, t, sge.tx_timer); 21288c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 21298c2ecf20Sopenharmony_ci unsigned int i, budget; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci budget = MAX_TIMER_TX_RECLAIM; 21328c2ecf20Sopenharmony_ci i = s->ethtxq_rover; 21338c2ecf20Sopenharmony_ci do { 21348c2ecf20Sopenharmony_ci struct sge_eth_txq *txq = &s->ethtxq[i]; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci if (reclaimable(&txq->q) && __netif_tx_trylock(txq->txq)) { 21378c2ecf20Sopenharmony_ci int avail = reclaimable(&txq->q); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci if (avail > budget) 21408c2ecf20Sopenharmony_ci avail = budget; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci free_tx_desc(adapter, &txq->q, avail, true); 21438c2ecf20Sopenharmony_ci txq->q.in_use -= avail; 21448c2ecf20Sopenharmony_ci __netif_tx_unlock(txq->txq); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci budget -= avail; 21478c2ecf20Sopenharmony_ci if (!budget) 21488c2ecf20Sopenharmony_ci break; 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci i++; 21528c2ecf20Sopenharmony_ci if (i >= s->ethqsets) 21538c2ecf20Sopenharmony_ci i = 0; 21548c2ecf20Sopenharmony_ci } while (i != s->ethtxq_rover); 21558c2ecf20Sopenharmony_ci s->ethtxq_rover = i; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci /* 21588c2ecf20Sopenharmony_ci * If we found too many reclaimable packets schedule a timer in the 21598c2ecf20Sopenharmony_ci * near future to continue where we left off. Otherwise the next timer 21608c2ecf20Sopenharmony_ci * will be at its normal interval. 21618c2ecf20Sopenharmony_ci */ 21628c2ecf20Sopenharmony_ci mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2)); 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci/** 21668c2ecf20Sopenharmony_ci * bar2_address - return the BAR2 address for an SGE Queue's Registers 21678c2ecf20Sopenharmony_ci * @adapter: the adapter 21688c2ecf20Sopenharmony_ci * @qid: the SGE Queue ID 21698c2ecf20Sopenharmony_ci * @qtype: the SGE Queue Type (Egress or Ingress) 21708c2ecf20Sopenharmony_ci * @pbar2_qid: BAR2 Queue ID or 0 for Queue ID inferred SGE Queues 21718c2ecf20Sopenharmony_ci * 21728c2ecf20Sopenharmony_ci * Returns the BAR2 address for the SGE Queue Registers associated with 21738c2ecf20Sopenharmony_ci * @qid. If BAR2 SGE Registers aren't available, returns NULL. Also 21748c2ecf20Sopenharmony_ci * returns the BAR2 Queue ID to be used with writes to the BAR2 SGE 21758c2ecf20Sopenharmony_ci * Queue Registers. If the BAR2 Queue ID is 0, then "Inferred Queue ID" 21768c2ecf20Sopenharmony_ci * Registers are supported (e.g. the Write Combining Doorbell Buffer). 21778c2ecf20Sopenharmony_ci */ 21788c2ecf20Sopenharmony_cistatic void __iomem *bar2_address(struct adapter *adapter, 21798c2ecf20Sopenharmony_ci unsigned int qid, 21808c2ecf20Sopenharmony_ci enum t4_bar2_qtype qtype, 21818c2ecf20Sopenharmony_ci unsigned int *pbar2_qid) 21828c2ecf20Sopenharmony_ci{ 21838c2ecf20Sopenharmony_ci u64 bar2_qoffset; 21848c2ecf20Sopenharmony_ci int ret; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci ret = t4vf_bar2_sge_qregs(adapter, qid, qtype, 21878c2ecf20Sopenharmony_ci &bar2_qoffset, pbar2_qid); 21888c2ecf20Sopenharmony_ci if (ret) 21898c2ecf20Sopenharmony_ci return NULL; 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci return adapter->bar2 + bar2_qoffset; 21928c2ecf20Sopenharmony_ci} 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci/** 21958c2ecf20Sopenharmony_ci * t4vf_sge_alloc_rxq - allocate an SGE RX Queue 21968c2ecf20Sopenharmony_ci * @adapter: the adapter 21978c2ecf20Sopenharmony_ci * @rspq: pointer to to the new rxq's Response Queue to be filled in 21988c2ecf20Sopenharmony_ci * @iqasynch: if 0, a normal rspq; if 1, an asynchronous event queue 21998c2ecf20Sopenharmony_ci * @dev: the network device associated with the new rspq 22008c2ecf20Sopenharmony_ci * @intr_dest: MSI-X vector index (overriden in MSI mode) 22018c2ecf20Sopenharmony_ci * @fl: pointer to the new rxq's Free List to be filled in 22028c2ecf20Sopenharmony_ci * @hnd: the interrupt handler to invoke for the rspq 22038c2ecf20Sopenharmony_ci */ 22048c2ecf20Sopenharmony_ciint t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq, 22058c2ecf20Sopenharmony_ci bool iqasynch, struct net_device *dev, 22068c2ecf20Sopenharmony_ci int intr_dest, 22078c2ecf20Sopenharmony_ci struct sge_fl *fl, rspq_handler_t hnd) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 22108c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 22118c2ecf20Sopenharmony_ci struct fw_iq_cmd cmd, rpl; 22128c2ecf20Sopenharmony_ci int ret, iqandst, flsz = 0; 22138c2ecf20Sopenharmony_ci int relaxed = !(adapter->flags & CXGB4VF_ROOT_NO_RELAXED_ORDERING); 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci /* 22168c2ecf20Sopenharmony_ci * If we're using MSI interrupts and we're not initializing the 22178c2ecf20Sopenharmony_ci * Forwarded Interrupt Queue itself, then set up this queue for 22188c2ecf20Sopenharmony_ci * indirect interrupts to the Forwarded Interrupt Queue. Obviously 22198c2ecf20Sopenharmony_ci * the Forwarded Interrupt Queue must be set up before any other 22208c2ecf20Sopenharmony_ci * ingress queue ... 22218c2ecf20Sopenharmony_ci */ 22228c2ecf20Sopenharmony_ci if ((adapter->flags & CXGB4VF_USING_MSI) && 22238c2ecf20Sopenharmony_ci rspq != &adapter->sge.intrq) { 22248c2ecf20Sopenharmony_ci iqandst = SGE_INTRDST_IQ; 22258c2ecf20Sopenharmony_ci intr_dest = adapter->sge.intrq.abs_id; 22268c2ecf20Sopenharmony_ci } else 22278c2ecf20Sopenharmony_ci iqandst = SGE_INTRDST_PCI; 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci /* 22308c2ecf20Sopenharmony_ci * Allocate the hardware ring for the Response Queue. The size needs 22318c2ecf20Sopenharmony_ci * to be a multiple of 16 which includes the mandatory status entry 22328c2ecf20Sopenharmony_ci * (regardless of whether the Status Page capabilities are enabled or 22338c2ecf20Sopenharmony_ci * not). 22348c2ecf20Sopenharmony_ci */ 22358c2ecf20Sopenharmony_ci rspq->size = roundup(rspq->size, 16); 22368c2ecf20Sopenharmony_ci rspq->desc = alloc_ring(adapter->pdev_dev, rspq->size, rspq->iqe_len, 22378c2ecf20Sopenharmony_ci 0, &rspq->phys_addr, NULL, 0); 22388c2ecf20Sopenharmony_ci if (!rspq->desc) 22398c2ecf20Sopenharmony_ci return -ENOMEM; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci /* 22428c2ecf20Sopenharmony_ci * Fill in the Ingress Queue Command. Note: Ideally this code would 22438c2ecf20Sopenharmony_ci * be in t4vf_hw.c but there are so many parameters and dependencies 22448c2ecf20Sopenharmony_ci * on our Linux SGE state that we would end up having to pass tons of 22458c2ecf20Sopenharmony_ci * parameters. We'll have to think about how this might be migrated 22468c2ecf20Sopenharmony_ci * into OS-independent common code ... 22478c2ecf20Sopenharmony_ci */ 22488c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 22498c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) | 22508c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 22518c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 22528c2ecf20Sopenharmony_ci FW_CMD_EXEC_F); 22538c2ecf20Sopenharmony_ci cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_ALLOC_F | 22548c2ecf20Sopenharmony_ci FW_IQ_CMD_IQSTART_F | 22558c2ecf20Sopenharmony_ci FW_LEN16(cmd)); 22568c2ecf20Sopenharmony_ci cmd.type_to_iqandstindex = 22578c2ecf20Sopenharmony_ci cpu_to_be32(FW_IQ_CMD_TYPE_V(FW_IQ_TYPE_FL_INT_CAP) | 22588c2ecf20Sopenharmony_ci FW_IQ_CMD_IQASYNCH_V(iqasynch) | 22598c2ecf20Sopenharmony_ci FW_IQ_CMD_VIID_V(pi->viid) | 22608c2ecf20Sopenharmony_ci FW_IQ_CMD_IQANDST_V(iqandst) | 22618c2ecf20Sopenharmony_ci FW_IQ_CMD_IQANUS_V(1) | 22628c2ecf20Sopenharmony_ci FW_IQ_CMD_IQANUD_V(SGE_UPDATEDEL_INTR) | 22638c2ecf20Sopenharmony_ci FW_IQ_CMD_IQANDSTINDEX_V(intr_dest)); 22648c2ecf20Sopenharmony_ci cmd.iqdroprss_to_iqesize = 22658c2ecf20Sopenharmony_ci cpu_to_be16(FW_IQ_CMD_IQPCIECH_V(pi->port_id) | 22668c2ecf20Sopenharmony_ci FW_IQ_CMD_IQGTSMODE_F | 22678c2ecf20Sopenharmony_ci FW_IQ_CMD_IQINTCNTTHRESH_V(rspq->pktcnt_idx) | 22688c2ecf20Sopenharmony_ci FW_IQ_CMD_IQESIZE_V(ilog2(rspq->iqe_len) - 4)); 22698c2ecf20Sopenharmony_ci cmd.iqsize = cpu_to_be16(rspq->size); 22708c2ecf20Sopenharmony_ci cmd.iqaddr = cpu_to_be64(rspq->phys_addr); 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci if (fl) { 22738c2ecf20Sopenharmony_ci unsigned int chip_ver = 22748c2ecf20Sopenharmony_ci CHELSIO_CHIP_VERSION(adapter->params.chip); 22758c2ecf20Sopenharmony_ci /* 22768c2ecf20Sopenharmony_ci * Allocate the ring for the hardware free list (with space 22778c2ecf20Sopenharmony_ci * for its status page) along with the associated software 22788c2ecf20Sopenharmony_ci * descriptor ring. The free list size needs to be a multiple 22798c2ecf20Sopenharmony_ci * of the Egress Queue Unit and at least 2 Egress Units larger 22808c2ecf20Sopenharmony_ci * than the SGE's Egress Congrestion Threshold 22818c2ecf20Sopenharmony_ci * (fl_starve_thres - 1). 22828c2ecf20Sopenharmony_ci */ 22838c2ecf20Sopenharmony_ci if (fl->size < s->fl_starve_thres - 1 + 2 * FL_PER_EQ_UNIT) 22848c2ecf20Sopenharmony_ci fl->size = s->fl_starve_thres - 1 + 2 * FL_PER_EQ_UNIT; 22858c2ecf20Sopenharmony_ci fl->size = roundup(fl->size, FL_PER_EQ_UNIT); 22868c2ecf20Sopenharmony_ci fl->desc = alloc_ring(adapter->pdev_dev, fl->size, 22878c2ecf20Sopenharmony_ci sizeof(__be64), sizeof(struct rx_sw_desc), 22888c2ecf20Sopenharmony_ci &fl->addr, &fl->sdesc, s->stat_len); 22898c2ecf20Sopenharmony_ci if (!fl->desc) { 22908c2ecf20Sopenharmony_ci ret = -ENOMEM; 22918c2ecf20Sopenharmony_ci goto err; 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci /* 22958c2ecf20Sopenharmony_ci * Calculate the size of the hardware free list ring plus 22968c2ecf20Sopenharmony_ci * Status Page (which the SGE will place after the end of the 22978c2ecf20Sopenharmony_ci * free list ring) in Egress Queue Units. 22988c2ecf20Sopenharmony_ci */ 22998c2ecf20Sopenharmony_ci flsz = (fl->size / FL_PER_EQ_UNIT + 23008c2ecf20Sopenharmony_ci s->stat_len / EQ_UNIT); 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci /* 23038c2ecf20Sopenharmony_ci * Fill in all the relevant firmware Ingress Queue Command 23048c2ecf20Sopenharmony_ci * fields for the free list. 23058c2ecf20Sopenharmony_ci */ 23068c2ecf20Sopenharmony_ci cmd.iqns_to_fl0congen = 23078c2ecf20Sopenharmony_ci cpu_to_be32( 23088c2ecf20Sopenharmony_ci FW_IQ_CMD_FL0HOSTFCMODE_V(SGE_HOSTFCMODE_NONE) | 23098c2ecf20Sopenharmony_ci FW_IQ_CMD_FL0PACKEN_F | 23108c2ecf20Sopenharmony_ci FW_IQ_CMD_FL0FETCHRO_V(relaxed) | 23118c2ecf20Sopenharmony_ci FW_IQ_CMD_FL0DATARO_V(relaxed) | 23128c2ecf20Sopenharmony_ci FW_IQ_CMD_FL0PADEN_F); 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci /* In T6, for egress queue type FL there is internal overhead 23158c2ecf20Sopenharmony_ci * of 16B for header going into FLM module. Hence the maximum 23168c2ecf20Sopenharmony_ci * allowed burst size is 448 bytes. For T4/T5, the hardware 23178c2ecf20Sopenharmony_ci * doesn't coalesce fetch requests if more than 64 bytes of 23188c2ecf20Sopenharmony_ci * Free List pointers are provided, so we use a 128-byte Fetch 23198c2ecf20Sopenharmony_ci * Burst Minimum there (T6 implements coalescing so we can use 23208c2ecf20Sopenharmony_ci * the smaller 64-byte value there). 23218c2ecf20Sopenharmony_ci */ 23228c2ecf20Sopenharmony_ci cmd.fl0dcaen_to_fl0cidxfthresh = 23238c2ecf20Sopenharmony_ci cpu_to_be16( 23248c2ecf20Sopenharmony_ci FW_IQ_CMD_FL0FBMIN_V(chip_ver <= CHELSIO_T5 23258c2ecf20Sopenharmony_ci ? FETCHBURSTMIN_128B_X 23268c2ecf20Sopenharmony_ci : FETCHBURSTMIN_64B_T6_X) | 23278c2ecf20Sopenharmony_ci FW_IQ_CMD_FL0FBMAX_V((chip_ver <= CHELSIO_T5) ? 23288c2ecf20Sopenharmony_ci FETCHBURSTMAX_512B_X : 23298c2ecf20Sopenharmony_ci FETCHBURSTMAX_256B_X)); 23308c2ecf20Sopenharmony_ci cmd.fl0size = cpu_to_be16(flsz); 23318c2ecf20Sopenharmony_ci cmd.fl0addr = cpu_to_be64(fl->addr); 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci /* 23358c2ecf20Sopenharmony_ci * Issue the firmware Ingress Queue Command and extract the results if 23368c2ecf20Sopenharmony_ci * it completes successfully. 23378c2ecf20Sopenharmony_ci */ 23388c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 23398c2ecf20Sopenharmony_ci if (ret) 23408c2ecf20Sopenharmony_ci goto err; 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci netif_napi_add(dev, &rspq->napi, napi_rx_handler, 64); 23438c2ecf20Sopenharmony_ci rspq->cur_desc = rspq->desc; 23448c2ecf20Sopenharmony_ci rspq->cidx = 0; 23458c2ecf20Sopenharmony_ci rspq->gen = 1; 23468c2ecf20Sopenharmony_ci rspq->next_intr_params = rspq->intr_params; 23478c2ecf20Sopenharmony_ci rspq->cntxt_id = be16_to_cpu(rpl.iqid); 23488c2ecf20Sopenharmony_ci rspq->bar2_addr = bar2_address(adapter, 23498c2ecf20Sopenharmony_ci rspq->cntxt_id, 23508c2ecf20Sopenharmony_ci T4_BAR2_QTYPE_INGRESS, 23518c2ecf20Sopenharmony_ci &rspq->bar2_qid); 23528c2ecf20Sopenharmony_ci rspq->abs_id = be16_to_cpu(rpl.physiqid); 23538c2ecf20Sopenharmony_ci rspq->size--; /* subtract status entry */ 23548c2ecf20Sopenharmony_ci rspq->adapter = adapter; 23558c2ecf20Sopenharmony_ci rspq->netdev = dev; 23568c2ecf20Sopenharmony_ci rspq->handler = hnd; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci /* set offset to -1 to distinguish ingress queues without FL */ 23598c2ecf20Sopenharmony_ci rspq->offset = fl ? 0 : -1; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci if (fl) { 23628c2ecf20Sopenharmony_ci fl->cntxt_id = be16_to_cpu(rpl.fl0id); 23638c2ecf20Sopenharmony_ci fl->avail = 0; 23648c2ecf20Sopenharmony_ci fl->pend_cred = 0; 23658c2ecf20Sopenharmony_ci fl->pidx = 0; 23668c2ecf20Sopenharmony_ci fl->cidx = 0; 23678c2ecf20Sopenharmony_ci fl->alloc_failed = 0; 23688c2ecf20Sopenharmony_ci fl->large_alloc_failed = 0; 23698c2ecf20Sopenharmony_ci fl->starving = 0; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci /* Note, we must initialize the BAR2 Free List User Doorbell 23728c2ecf20Sopenharmony_ci * information before refilling the Free List! 23738c2ecf20Sopenharmony_ci */ 23748c2ecf20Sopenharmony_ci fl->bar2_addr = bar2_address(adapter, 23758c2ecf20Sopenharmony_ci fl->cntxt_id, 23768c2ecf20Sopenharmony_ci T4_BAR2_QTYPE_EGRESS, 23778c2ecf20Sopenharmony_ci &fl->bar2_qid); 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci refill_fl(adapter, fl, fl_cap(fl), GFP_KERNEL); 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci return 0; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_cierr: 23858c2ecf20Sopenharmony_ci /* 23868c2ecf20Sopenharmony_ci * An error occurred. Clean up our partial allocation state and 23878c2ecf20Sopenharmony_ci * return the error. 23888c2ecf20Sopenharmony_ci */ 23898c2ecf20Sopenharmony_ci if (rspq->desc) { 23908c2ecf20Sopenharmony_ci dma_free_coherent(adapter->pdev_dev, rspq->size * rspq->iqe_len, 23918c2ecf20Sopenharmony_ci rspq->desc, rspq->phys_addr); 23928c2ecf20Sopenharmony_ci rspq->desc = NULL; 23938c2ecf20Sopenharmony_ci } 23948c2ecf20Sopenharmony_ci if (fl && fl->desc) { 23958c2ecf20Sopenharmony_ci kfree(fl->sdesc); 23968c2ecf20Sopenharmony_ci fl->sdesc = NULL; 23978c2ecf20Sopenharmony_ci dma_free_coherent(adapter->pdev_dev, flsz * EQ_UNIT, 23988c2ecf20Sopenharmony_ci fl->desc, fl->addr); 23998c2ecf20Sopenharmony_ci fl->desc = NULL; 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci return ret; 24028c2ecf20Sopenharmony_ci} 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci/** 24058c2ecf20Sopenharmony_ci * t4vf_sge_alloc_eth_txq - allocate an SGE Ethernet TX Queue 24068c2ecf20Sopenharmony_ci * @adapter: the adapter 24078c2ecf20Sopenharmony_ci * @txq: pointer to the new txq to be filled in 24088c2ecf20Sopenharmony_ci * @dev: the network device 24098c2ecf20Sopenharmony_ci * @devq: the network TX queue associated with the new txq 24108c2ecf20Sopenharmony_ci * @iqid: the relative ingress queue ID to which events relating to 24118c2ecf20Sopenharmony_ci * the new txq should be directed 24128c2ecf20Sopenharmony_ci */ 24138c2ecf20Sopenharmony_ciint t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq, 24148c2ecf20Sopenharmony_ci struct net_device *dev, struct netdev_queue *devq, 24158c2ecf20Sopenharmony_ci unsigned int iqid) 24168c2ecf20Sopenharmony_ci{ 24178c2ecf20Sopenharmony_ci unsigned int chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip); 24188c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 24198c2ecf20Sopenharmony_ci struct fw_eq_eth_cmd cmd, rpl; 24208c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 24218c2ecf20Sopenharmony_ci int ret, nentries; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci /* 24248c2ecf20Sopenharmony_ci * Calculate the size of the hardware TX Queue (including the Status 24258c2ecf20Sopenharmony_ci * Page on the end of the TX Queue) in units of TX Descriptors. 24268c2ecf20Sopenharmony_ci */ 24278c2ecf20Sopenharmony_ci nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc); 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci /* 24308c2ecf20Sopenharmony_ci * Allocate the hardware ring for the TX ring (with space for its 24318c2ecf20Sopenharmony_ci * status page) along with the associated software descriptor ring. 24328c2ecf20Sopenharmony_ci */ 24338c2ecf20Sopenharmony_ci txq->q.desc = alloc_ring(adapter->pdev_dev, txq->q.size, 24348c2ecf20Sopenharmony_ci sizeof(struct tx_desc), 24358c2ecf20Sopenharmony_ci sizeof(struct tx_sw_desc), 24368c2ecf20Sopenharmony_ci &txq->q.phys_addr, &txq->q.sdesc, s->stat_len); 24378c2ecf20Sopenharmony_ci if (!txq->q.desc) 24388c2ecf20Sopenharmony_ci return -ENOMEM; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci /* 24418c2ecf20Sopenharmony_ci * Fill in the Egress Queue Command. Note: As with the direct use of 24428c2ecf20Sopenharmony_ci * the firmware Ingress Queue COmmand above in our RXQ allocation 24438c2ecf20Sopenharmony_ci * routine, ideally, this code would be in t4vf_hw.c. Again, we'll 24448c2ecf20Sopenharmony_ci * have to see if there's some reasonable way to parameterize it 24458c2ecf20Sopenharmony_ci * into the common code ... 24468c2ecf20Sopenharmony_ci */ 24478c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 24488c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) | 24498c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 24508c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 24518c2ecf20Sopenharmony_ci FW_CMD_EXEC_F); 24528c2ecf20Sopenharmony_ci cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC_F | 24538c2ecf20Sopenharmony_ci FW_EQ_ETH_CMD_EQSTART_F | 24548c2ecf20Sopenharmony_ci FW_LEN16(cmd)); 24558c2ecf20Sopenharmony_ci cmd.autoequiqe_to_viid = cpu_to_be32(FW_EQ_ETH_CMD_AUTOEQUEQE_F | 24568c2ecf20Sopenharmony_ci FW_EQ_ETH_CMD_VIID_V(pi->viid)); 24578c2ecf20Sopenharmony_ci cmd.fetchszm_to_iqid = 24588c2ecf20Sopenharmony_ci cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE_V(SGE_HOSTFCMODE_STPG) | 24598c2ecf20Sopenharmony_ci FW_EQ_ETH_CMD_PCIECHN_V(pi->port_id) | 24608c2ecf20Sopenharmony_ci FW_EQ_ETH_CMD_IQID_V(iqid)); 24618c2ecf20Sopenharmony_ci cmd.dcaen_to_eqsize = 24628c2ecf20Sopenharmony_ci cpu_to_be32(FW_EQ_ETH_CMD_FBMIN_V(chip_ver <= CHELSIO_T5 24638c2ecf20Sopenharmony_ci ? FETCHBURSTMIN_64B_X 24648c2ecf20Sopenharmony_ci : FETCHBURSTMIN_64B_T6_X) | 24658c2ecf20Sopenharmony_ci FW_EQ_ETH_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) | 24668c2ecf20Sopenharmony_ci FW_EQ_ETH_CMD_CIDXFTHRESH_V( 24678c2ecf20Sopenharmony_ci CIDXFLUSHTHRESH_32_X) | 24688c2ecf20Sopenharmony_ci FW_EQ_ETH_CMD_EQSIZE_V(nentries)); 24698c2ecf20Sopenharmony_ci cmd.eqaddr = cpu_to_be64(txq->q.phys_addr); 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci /* 24728c2ecf20Sopenharmony_ci * Issue the firmware Egress Queue Command and extract the results if 24738c2ecf20Sopenharmony_ci * it completes successfully. 24748c2ecf20Sopenharmony_ci */ 24758c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 24768c2ecf20Sopenharmony_ci if (ret) { 24778c2ecf20Sopenharmony_ci /* 24788c2ecf20Sopenharmony_ci * The girmware Ingress Queue Command failed for some reason. 24798c2ecf20Sopenharmony_ci * Free up our partial allocation state and return the error. 24808c2ecf20Sopenharmony_ci */ 24818c2ecf20Sopenharmony_ci kfree(txq->q.sdesc); 24828c2ecf20Sopenharmony_ci txq->q.sdesc = NULL; 24838c2ecf20Sopenharmony_ci dma_free_coherent(adapter->pdev_dev, 24848c2ecf20Sopenharmony_ci nentries * sizeof(struct tx_desc), 24858c2ecf20Sopenharmony_ci txq->q.desc, txq->q.phys_addr); 24868c2ecf20Sopenharmony_ci txq->q.desc = NULL; 24878c2ecf20Sopenharmony_ci return ret; 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci txq->q.in_use = 0; 24918c2ecf20Sopenharmony_ci txq->q.cidx = 0; 24928c2ecf20Sopenharmony_ci txq->q.pidx = 0; 24938c2ecf20Sopenharmony_ci txq->q.stat = (void *)&txq->q.desc[txq->q.size]; 24948c2ecf20Sopenharmony_ci txq->q.cntxt_id = FW_EQ_ETH_CMD_EQID_G(be32_to_cpu(rpl.eqid_pkd)); 24958c2ecf20Sopenharmony_ci txq->q.bar2_addr = bar2_address(adapter, 24968c2ecf20Sopenharmony_ci txq->q.cntxt_id, 24978c2ecf20Sopenharmony_ci T4_BAR2_QTYPE_EGRESS, 24988c2ecf20Sopenharmony_ci &txq->q.bar2_qid); 24998c2ecf20Sopenharmony_ci txq->q.abs_id = 25008c2ecf20Sopenharmony_ci FW_EQ_ETH_CMD_PHYSEQID_G(be32_to_cpu(rpl.physeqid_pkd)); 25018c2ecf20Sopenharmony_ci txq->txq = devq; 25028c2ecf20Sopenharmony_ci txq->tso = 0; 25038c2ecf20Sopenharmony_ci txq->tx_cso = 0; 25048c2ecf20Sopenharmony_ci txq->vlan_ins = 0; 25058c2ecf20Sopenharmony_ci txq->q.stops = 0; 25068c2ecf20Sopenharmony_ci txq->q.restarts = 0; 25078c2ecf20Sopenharmony_ci txq->mapping_err = 0; 25088c2ecf20Sopenharmony_ci return 0; 25098c2ecf20Sopenharmony_ci} 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci/* 25128c2ecf20Sopenharmony_ci * Free the DMA map resources associated with a TX queue. 25138c2ecf20Sopenharmony_ci */ 25148c2ecf20Sopenharmony_cistatic void free_txq(struct adapter *adapter, struct sge_txq *tq) 25158c2ecf20Sopenharmony_ci{ 25168c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci dma_free_coherent(adapter->pdev_dev, 25198c2ecf20Sopenharmony_ci tq->size * sizeof(*tq->desc) + s->stat_len, 25208c2ecf20Sopenharmony_ci tq->desc, tq->phys_addr); 25218c2ecf20Sopenharmony_ci tq->cntxt_id = 0; 25228c2ecf20Sopenharmony_ci tq->sdesc = NULL; 25238c2ecf20Sopenharmony_ci tq->desc = NULL; 25248c2ecf20Sopenharmony_ci} 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci/* 25278c2ecf20Sopenharmony_ci * Free the resources associated with a response queue (possibly including a 25288c2ecf20Sopenharmony_ci * free list). 25298c2ecf20Sopenharmony_ci */ 25308c2ecf20Sopenharmony_cistatic void free_rspq_fl(struct adapter *adapter, struct sge_rspq *rspq, 25318c2ecf20Sopenharmony_ci struct sge_fl *fl) 25328c2ecf20Sopenharmony_ci{ 25338c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 25348c2ecf20Sopenharmony_ci unsigned int flid = fl ? fl->cntxt_id : 0xffff; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci t4vf_iq_free(adapter, FW_IQ_TYPE_FL_INT_CAP, 25378c2ecf20Sopenharmony_ci rspq->cntxt_id, flid, 0xffff); 25388c2ecf20Sopenharmony_ci dma_free_coherent(adapter->pdev_dev, (rspq->size + 1) * rspq->iqe_len, 25398c2ecf20Sopenharmony_ci rspq->desc, rspq->phys_addr); 25408c2ecf20Sopenharmony_ci netif_napi_del(&rspq->napi); 25418c2ecf20Sopenharmony_ci rspq->netdev = NULL; 25428c2ecf20Sopenharmony_ci rspq->cntxt_id = 0; 25438c2ecf20Sopenharmony_ci rspq->abs_id = 0; 25448c2ecf20Sopenharmony_ci rspq->desc = NULL; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci if (fl) { 25478c2ecf20Sopenharmony_ci free_rx_bufs(adapter, fl, fl->avail); 25488c2ecf20Sopenharmony_ci dma_free_coherent(adapter->pdev_dev, 25498c2ecf20Sopenharmony_ci fl->size * sizeof(*fl->desc) + s->stat_len, 25508c2ecf20Sopenharmony_ci fl->desc, fl->addr); 25518c2ecf20Sopenharmony_ci kfree(fl->sdesc); 25528c2ecf20Sopenharmony_ci fl->sdesc = NULL; 25538c2ecf20Sopenharmony_ci fl->cntxt_id = 0; 25548c2ecf20Sopenharmony_ci fl->desc = NULL; 25558c2ecf20Sopenharmony_ci } 25568c2ecf20Sopenharmony_ci} 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci/** 25598c2ecf20Sopenharmony_ci * t4vf_free_sge_resources - free SGE resources 25608c2ecf20Sopenharmony_ci * @adapter: the adapter 25618c2ecf20Sopenharmony_ci * 25628c2ecf20Sopenharmony_ci * Frees resources used by the SGE queue sets. 25638c2ecf20Sopenharmony_ci */ 25648c2ecf20Sopenharmony_civoid t4vf_free_sge_resources(struct adapter *adapter) 25658c2ecf20Sopenharmony_ci{ 25668c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 25678c2ecf20Sopenharmony_ci struct sge_eth_rxq *rxq = s->ethrxq; 25688c2ecf20Sopenharmony_ci struct sge_eth_txq *txq = s->ethtxq; 25698c2ecf20Sopenharmony_ci struct sge_rspq *evtq = &s->fw_evtq; 25708c2ecf20Sopenharmony_ci struct sge_rspq *intrq = &s->intrq; 25718c2ecf20Sopenharmony_ci int qs; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci for (qs = 0; qs < adapter->sge.ethqsets; qs++, rxq++, txq++) { 25748c2ecf20Sopenharmony_ci if (rxq->rspq.desc) 25758c2ecf20Sopenharmony_ci free_rspq_fl(adapter, &rxq->rspq, &rxq->fl); 25768c2ecf20Sopenharmony_ci if (txq->q.desc) { 25778c2ecf20Sopenharmony_ci t4vf_eth_eq_free(adapter, txq->q.cntxt_id); 25788c2ecf20Sopenharmony_ci free_tx_desc(adapter, &txq->q, txq->q.in_use, true); 25798c2ecf20Sopenharmony_ci kfree(txq->q.sdesc); 25808c2ecf20Sopenharmony_ci free_txq(adapter, &txq->q); 25818c2ecf20Sopenharmony_ci } 25828c2ecf20Sopenharmony_ci } 25838c2ecf20Sopenharmony_ci if (evtq->desc) 25848c2ecf20Sopenharmony_ci free_rspq_fl(adapter, evtq, NULL); 25858c2ecf20Sopenharmony_ci if (intrq->desc) 25868c2ecf20Sopenharmony_ci free_rspq_fl(adapter, intrq, NULL); 25878c2ecf20Sopenharmony_ci} 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci/** 25908c2ecf20Sopenharmony_ci * t4vf_sge_start - enable SGE operation 25918c2ecf20Sopenharmony_ci * @adapter: the adapter 25928c2ecf20Sopenharmony_ci * 25938c2ecf20Sopenharmony_ci * Start tasklets and timers associated with the DMA engine. 25948c2ecf20Sopenharmony_ci */ 25958c2ecf20Sopenharmony_civoid t4vf_sge_start(struct adapter *adapter) 25968c2ecf20Sopenharmony_ci{ 25978c2ecf20Sopenharmony_ci adapter->sge.ethtxq_rover = 0; 25988c2ecf20Sopenharmony_ci mod_timer(&adapter->sge.rx_timer, jiffies + RX_QCHECK_PERIOD); 25998c2ecf20Sopenharmony_ci mod_timer(&adapter->sge.tx_timer, jiffies + TX_QCHECK_PERIOD); 26008c2ecf20Sopenharmony_ci} 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci/** 26038c2ecf20Sopenharmony_ci * t4vf_sge_stop - disable SGE operation 26048c2ecf20Sopenharmony_ci * @adapter: the adapter 26058c2ecf20Sopenharmony_ci * 26068c2ecf20Sopenharmony_ci * Stop tasklets and timers associated with the DMA engine. Note that 26078c2ecf20Sopenharmony_ci * this is effective only if measures have been taken to disable any HW 26088c2ecf20Sopenharmony_ci * events that may restart them. 26098c2ecf20Sopenharmony_ci */ 26108c2ecf20Sopenharmony_civoid t4vf_sge_stop(struct adapter *adapter) 26118c2ecf20Sopenharmony_ci{ 26128c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci if (s->rx_timer.function) 26158c2ecf20Sopenharmony_ci del_timer_sync(&s->rx_timer); 26168c2ecf20Sopenharmony_ci if (s->tx_timer.function) 26178c2ecf20Sopenharmony_ci del_timer_sync(&s->tx_timer); 26188c2ecf20Sopenharmony_ci} 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci/** 26218c2ecf20Sopenharmony_ci * t4vf_sge_init - initialize SGE 26228c2ecf20Sopenharmony_ci * @adapter: the adapter 26238c2ecf20Sopenharmony_ci * 26248c2ecf20Sopenharmony_ci * Performs SGE initialization needed every time after a chip reset. 26258c2ecf20Sopenharmony_ci * We do not initialize any of the queue sets here, instead the driver 26268c2ecf20Sopenharmony_ci * top-level must request those individually. We also do not enable DMA 26278c2ecf20Sopenharmony_ci * here, that should be done after the queues have been set up. 26288c2ecf20Sopenharmony_ci */ 26298c2ecf20Sopenharmony_ciint t4vf_sge_init(struct adapter *adapter) 26308c2ecf20Sopenharmony_ci{ 26318c2ecf20Sopenharmony_ci struct sge_params *sge_params = &adapter->params.sge; 26328c2ecf20Sopenharmony_ci u32 fl_small_pg = sge_params->sge_fl_buffer_size[0]; 26338c2ecf20Sopenharmony_ci u32 fl_large_pg = sge_params->sge_fl_buffer_size[1]; 26348c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci /* 26378c2ecf20Sopenharmony_ci * Start by vetting the basic SGE parameters which have been set up by 26388c2ecf20Sopenharmony_ci * the Physical Function Driver. Ideally we should be able to deal 26398c2ecf20Sopenharmony_ci * with _any_ configuration. Practice is different ... 26408c2ecf20Sopenharmony_ci */ 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci /* We only bother using the Large Page logic if the Large Page Buffer 26438c2ecf20Sopenharmony_ci * is larger than our Page Size Buffer. 26448c2ecf20Sopenharmony_ci */ 26458c2ecf20Sopenharmony_ci if (fl_large_pg <= fl_small_pg) 26468c2ecf20Sopenharmony_ci fl_large_pg = 0; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci /* The Page Size Buffer must be exactly equal to our Page Size and the 26498c2ecf20Sopenharmony_ci * Large Page Size Buffer should be 0 (per above) or a power of 2. 26508c2ecf20Sopenharmony_ci */ 26518c2ecf20Sopenharmony_ci if (fl_small_pg != PAGE_SIZE || 26528c2ecf20Sopenharmony_ci (fl_large_pg & (fl_large_pg - 1)) != 0) { 26538c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n", 26548c2ecf20Sopenharmony_ci fl_small_pg, fl_large_pg); 26558c2ecf20Sopenharmony_ci return -EINVAL; 26568c2ecf20Sopenharmony_ci } 26578c2ecf20Sopenharmony_ci if ((sge_params->sge_control & RXPKTCPLMODE_F) != 26588c2ecf20Sopenharmony_ci RXPKTCPLMODE_V(RXPKTCPLMODE_SPLIT_X)) { 26598c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n"); 26608c2ecf20Sopenharmony_ci return -EINVAL; 26618c2ecf20Sopenharmony_ci } 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci /* 26648c2ecf20Sopenharmony_ci * Now translate the adapter parameters into our internal forms. 26658c2ecf20Sopenharmony_ci */ 26668c2ecf20Sopenharmony_ci if (fl_large_pg) 26678c2ecf20Sopenharmony_ci s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT; 26688c2ecf20Sopenharmony_ci s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F) 26698c2ecf20Sopenharmony_ci ? 128 : 64); 26708c2ecf20Sopenharmony_ci s->pktshift = PKTSHIFT_G(sge_params->sge_control); 26718c2ecf20Sopenharmony_ci s->fl_align = t4vf_fl_pkt_align(adapter); 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci /* A FL with <= fl_starve_thres buffers is starving and a periodic 26748c2ecf20Sopenharmony_ci * timer will attempt to refill it. This needs to be larger than the 26758c2ecf20Sopenharmony_ci * SGE's Egress Congestion Threshold. If it isn't, then we can get 26768c2ecf20Sopenharmony_ci * stuck waiting for new packets while the SGE is waiting for us to 26778c2ecf20Sopenharmony_ci * give it more Free List entries. (Note that the SGE's Egress 26788c2ecf20Sopenharmony_ci * Congestion Threshold is in units of 2 Free List pointers.) 26798c2ecf20Sopenharmony_ci */ 26808c2ecf20Sopenharmony_ci switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) { 26818c2ecf20Sopenharmony_ci case CHELSIO_T4: 26828c2ecf20Sopenharmony_ci s->fl_starve_thres = 26838c2ecf20Sopenharmony_ci EGRTHRESHOLD_G(sge_params->sge_congestion_control); 26848c2ecf20Sopenharmony_ci break; 26858c2ecf20Sopenharmony_ci case CHELSIO_T5: 26868c2ecf20Sopenharmony_ci s->fl_starve_thres = 26878c2ecf20Sopenharmony_ci EGRTHRESHOLDPACKING_G(sge_params->sge_congestion_control); 26888c2ecf20Sopenharmony_ci break; 26898c2ecf20Sopenharmony_ci case CHELSIO_T6: 26908c2ecf20Sopenharmony_ci default: 26918c2ecf20Sopenharmony_ci s->fl_starve_thres = 26928c2ecf20Sopenharmony_ci T6_EGRTHRESHOLDPACKING_G(sge_params->sge_congestion_control); 26938c2ecf20Sopenharmony_ci break; 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci s->fl_starve_thres = s->fl_starve_thres * 2 + 1; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci /* 26988c2ecf20Sopenharmony_ci * Set up tasklet timers. 26998c2ecf20Sopenharmony_ci */ 27008c2ecf20Sopenharmony_ci timer_setup(&s->rx_timer, sge_rx_timer_cb, 0); 27018c2ecf20Sopenharmony_ci timer_setup(&s->tx_timer, sge_tx_timer_cb, 0); 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci /* 27048c2ecf20Sopenharmony_ci * Initialize Forwarded Interrupt Queue lock. 27058c2ecf20Sopenharmony_ci */ 27068c2ecf20Sopenharmony_ci spin_lock_init(&s->intrq_lock); 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci return 0; 27098c2ecf20Sopenharmony_ci} 2710