18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 338c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 348c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 358c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 368c2ecf20Sopenharmony_ci#include <linux/ip.h> 378c2ecf20Sopenharmony_ci#include <linux/tcp.h> 388c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 398c2ecf20Sopenharmony_ci#include <linux/slab.h> 408c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 418c2ecf20Sopenharmony_ci#include <net/arp.h> 428c2ecf20Sopenharmony_ci#include "common.h" 438c2ecf20Sopenharmony_ci#include "regs.h" 448c2ecf20Sopenharmony_ci#include "sge_defs.h" 458c2ecf20Sopenharmony_ci#include "t3_cpl.h" 468c2ecf20Sopenharmony_ci#include "firmware_exports.h" 478c2ecf20Sopenharmony_ci#include "cxgb3_offload.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define USE_GTS 0 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define SGE_RX_SM_BUF_SIZE 1536 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define SGE_RX_COPY_THRES 256 548c2ecf20Sopenharmony_ci#define SGE_RX_PULL_LEN 128 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define SGE_PG_RSVD SMP_CACHE_BYTES 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * Page chunk size for FL0 buffers if FL0 is to be populated with page chunks. 598c2ecf20Sopenharmony_ci * It must be a divisor of PAGE_SIZE. If set to 0 FL0 will use sk_buffs 608c2ecf20Sopenharmony_ci * directly. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci#define FL0_PG_CHUNK_SIZE 2048 638c2ecf20Sopenharmony_ci#define FL0_PG_ORDER 0 648c2ecf20Sopenharmony_ci#define FL0_PG_ALLOC_SIZE (PAGE_SIZE << FL0_PG_ORDER) 658c2ecf20Sopenharmony_ci#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) 668c2ecf20Sopenharmony_ci#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) 678c2ecf20Sopenharmony_ci#define FL1_PG_ALLOC_SIZE (PAGE_SIZE << FL1_PG_ORDER) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define SGE_RX_DROP_THRES 16 708c2ecf20Sopenharmony_ci#define RX_RECLAIM_PERIOD (HZ/4) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * Max number of Rx buffers we replenish at a time. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci#define MAX_RX_REFILL 16U 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * Period of the Tx buffer reclaim timer. This timer does not need to run 788c2ecf20Sopenharmony_ci * frequently as Tx buffers are usually reclaimed by new Tx packets. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci#define TX_RECLAIM_PERIOD (HZ / 4) 818c2ecf20Sopenharmony_ci#define TX_RECLAIM_TIMER_CHUNK 64U 828c2ecf20Sopenharmony_ci#define TX_RECLAIM_CHUNK 16U 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* WR size in bytes */ 858c2ecf20Sopenharmony_ci#define WR_LEN (WR_FLITS * 8) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 888c2ecf20Sopenharmony_ci * Types of Tx queues in each queue set. Order here matters, do not change. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cienum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL }; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Values for sge_txq.flags */ 938c2ecf20Sopenharmony_cienum { 948c2ecf20Sopenharmony_ci TXQ_RUNNING = 1 << 0, /* fetch engine is running */ 958c2ecf20Sopenharmony_ci TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */ 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistruct tx_desc { 998c2ecf20Sopenharmony_ci __be64 flit[TX_DESC_FLITS]; 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistruct rx_desc { 1038c2ecf20Sopenharmony_ci __be32 addr_lo; 1048c2ecf20Sopenharmony_ci __be32 len_gen; 1058c2ecf20Sopenharmony_ci __be32 gen2; 1068c2ecf20Sopenharmony_ci __be32 addr_hi; 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistruct tx_sw_desc { /* SW state per Tx descriptor */ 1108c2ecf20Sopenharmony_ci struct sk_buff *skb; 1118c2ecf20Sopenharmony_ci u8 eop; /* set if last descriptor for packet */ 1128c2ecf20Sopenharmony_ci u8 addr_idx; /* buffer index of first SGL entry in descriptor */ 1138c2ecf20Sopenharmony_ci u8 fragidx; /* first page fragment associated with descriptor */ 1148c2ecf20Sopenharmony_ci s8 sflit; /* start flit of first SGL entry in descriptor */ 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistruct rx_sw_desc { /* SW state per Rx descriptor */ 1188c2ecf20Sopenharmony_ci union { 1198c2ecf20Sopenharmony_ci struct sk_buff *skb; 1208c2ecf20Sopenharmony_ci struct fl_pg_chunk pg_chunk; 1218c2ecf20Sopenharmony_ci }; 1228c2ecf20Sopenharmony_ci DEFINE_DMA_UNMAP_ADDR(dma_addr); 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistruct rsp_desc { /* response queue descriptor */ 1268c2ecf20Sopenharmony_ci struct rss_header rss_hdr; 1278c2ecf20Sopenharmony_ci __be32 flags; 1288c2ecf20Sopenharmony_ci __be32 len_cq; 1298c2ecf20Sopenharmony_ci u8 imm_data[47]; 1308c2ecf20Sopenharmony_ci u8 intr_gen; 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* 1348c2ecf20Sopenharmony_ci * Holds unmapping information for Tx packets that need deferred unmapping. 1358c2ecf20Sopenharmony_ci * This structure lives at skb->head and must be allocated by callers. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_cistruct deferred_unmap_info { 1388c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1398c2ecf20Sopenharmony_ci dma_addr_t addr[MAX_SKB_FRAGS + 1]; 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci * Maps a number of flits to the number of Tx descriptors that can hold them. 1448c2ecf20Sopenharmony_ci * The formula is 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * desc = 1 + (flits - 2) / (WR_FLITS - 1). 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * HW allows up to 4 descriptors to be combined into a WR. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic u8 flit_desc_map[] = { 1518c2ecf20Sopenharmony_ci 0, 1528c2ecf20Sopenharmony_ci#if SGE_NUM_GENBITS == 1 1538c2ecf20Sopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1548c2ecf20Sopenharmony_ci 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1558c2ecf20Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1568c2ecf20Sopenharmony_ci 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 1578c2ecf20Sopenharmony_ci#elif SGE_NUM_GENBITS == 2 1588c2ecf20Sopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1598c2ecf20Sopenharmony_ci 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1608c2ecf20Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1618c2ecf20Sopenharmony_ci 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1628c2ecf20Sopenharmony_ci#else 1638c2ecf20Sopenharmony_ci# error "SGE_NUM_GENBITS must be 1 or 2" 1648c2ecf20Sopenharmony_ci#endif 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci return container_of(q, struct sge_qset, fl[qidx]); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci return container_of(q, struct sge_qset, rspq); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci return container_of(q, struct sge_qset, txq[qidx]); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/** 1838c2ecf20Sopenharmony_ci * refill_rspq - replenish an SGE response queue 1848c2ecf20Sopenharmony_ci * @adapter: the adapter 1858c2ecf20Sopenharmony_ci * @q: the response queue to replenish 1868c2ecf20Sopenharmony_ci * @credits: how many new responses to make available 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * Replenishes a response queue by making the supplied number of responses 1898c2ecf20Sopenharmony_ci * available to HW. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic inline void refill_rspq(struct adapter *adapter, 1928c2ecf20Sopenharmony_ci const struct sge_rspq *q, unsigned int credits) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci rmb(); 1958c2ecf20Sopenharmony_ci t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN, 1968c2ecf20Sopenharmony_ci V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/** 2008c2ecf20Sopenharmony_ci * need_skb_unmap - does the platform need unmapping of sk_buffs? 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * Returns true if the platform needs sk_buff unmapping. The compiler 2038c2ecf20Sopenharmony_ci * optimizes away unnecessary code if this returns true. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic inline int need_skb_unmap(void) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci#ifdef CONFIG_NEED_DMA_MAP_STATE 2088c2ecf20Sopenharmony_ci return 1; 2098c2ecf20Sopenharmony_ci#else 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci#endif 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/** 2158c2ecf20Sopenharmony_ci * unmap_skb - unmap a packet main body and its page fragments 2168c2ecf20Sopenharmony_ci * @skb: the packet 2178c2ecf20Sopenharmony_ci * @q: the Tx queue containing Tx descriptors for the packet 2188c2ecf20Sopenharmony_ci * @cidx: index of Tx descriptor 2198c2ecf20Sopenharmony_ci * @pdev: the PCI device 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * Unmap the main body of an sk_buff and its page fragments, if any. 2228c2ecf20Sopenharmony_ci * Because of the fairly complicated structure of our SGLs and the desire 2238c2ecf20Sopenharmony_ci * to conserve space for metadata, the information necessary to unmap an 2248c2ecf20Sopenharmony_ci * sk_buff is spread across the sk_buff itself (buffer lengths), the HW Tx 2258c2ecf20Sopenharmony_ci * descriptors (the physical addresses of the various data buffers), and 2268c2ecf20Sopenharmony_ci * the SW descriptor state (assorted indices). The send functions 2278c2ecf20Sopenharmony_ci * initialize the indices for the first packet descriptor so we can unmap 2288c2ecf20Sopenharmony_ci * the buffers held in the first Tx descriptor here, and we have enough 2298c2ecf20Sopenharmony_ci * information at this point to set the state for the next Tx descriptor. 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Note that it is possible to clean up the first descriptor of a packet 2328c2ecf20Sopenharmony_ci * before the send routines have written the next descriptors, but this 2338c2ecf20Sopenharmony_ci * race does not cause any problem. We just end up writing the unmapping 2348c2ecf20Sopenharmony_ci * info for the descriptor first. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_cistatic inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, 2378c2ecf20Sopenharmony_ci unsigned int cidx, struct pci_dev *pdev) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci const struct sg_ent *sgp; 2408c2ecf20Sopenharmony_ci struct tx_sw_desc *d = &q->sdesc[cidx]; 2418c2ecf20Sopenharmony_ci int nfrags, frag_idx, curflit, j = d->addr_idx; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci sgp = (struct sg_ent *)&q->desc[cidx].flit[d->sflit]; 2448c2ecf20Sopenharmony_ci frag_idx = d->fragidx; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (frag_idx == 0 && skb_headlen(skb)) { 2478c2ecf20Sopenharmony_ci pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), 2488c2ecf20Sopenharmony_ci skb_headlen(skb), PCI_DMA_TODEVICE); 2498c2ecf20Sopenharmony_ci j = 1; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci curflit = d->sflit + 1 + j; 2538c2ecf20Sopenharmony_ci nfrags = skb_shinfo(skb)->nr_frags; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci while (frag_idx < nfrags && curflit < WR_FLITS) { 2568c2ecf20Sopenharmony_ci pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]), 2578c2ecf20Sopenharmony_ci skb_frag_size(&skb_shinfo(skb)->frags[frag_idx]), 2588c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 2598c2ecf20Sopenharmony_ci j ^= 1; 2608c2ecf20Sopenharmony_ci if (j == 0) { 2618c2ecf20Sopenharmony_ci sgp++; 2628c2ecf20Sopenharmony_ci curflit++; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci curflit++; 2658c2ecf20Sopenharmony_ci frag_idx++; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ 2698c2ecf20Sopenharmony_ci d = cidx + 1 == q->size ? q->sdesc : d + 1; 2708c2ecf20Sopenharmony_ci d->fragidx = frag_idx; 2718c2ecf20Sopenharmony_ci d->addr_idx = j; 2728c2ecf20Sopenharmony_ci d->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/** 2778c2ecf20Sopenharmony_ci * free_tx_desc - reclaims Tx descriptors and their buffers 2788c2ecf20Sopenharmony_ci * @adapter: the adapter 2798c2ecf20Sopenharmony_ci * @q: the Tx queue to reclaim descriptors from 2808c2ecf20Sopenharmony_ci * @n: the number of descriptors to reclaim 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * Reclaims Tx descriptors from an SGE Tx queue and frees the associated 2838c2ecf20Sopenharmony_ci * Tx buffers. Called with the Tx queue lock held. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic void free_tx_desc(struct adapter *adapter, struct sge_txq *q, 2868c2ecf20Sopenharmony_ci unsigned int n) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct tx_sw_desc *d; 2898c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 2908c2ecf20Sopenharmony_ci unsigned int cidx = q->cidx; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci const int need_unmap = need_skb_unmap() && 2938c2ecf20Sopenharmony_ci q->cntxt_id >= FW_TUNNEL_SGEEC_START; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci d = &q->sdesc[cidx]; 2968c2ecf20Sopenharmony_ci while (n--) { 2978c2ecf20Sopenharmony_ci if (d->skb) { /* an SGL is present */ 2988c2ecf20Sopenharmony_ci if (need_unmap) 2998c2ecf20Sopenharmony_ci unmap_skb(d->skb, q, cidx, pdev); 3008c2ecf20Sopenharmony_ci if (d->eop) { 3018c2ecf20Sopenharmony_ci dev_consume_skb_any(d->skb); 3028c2ecf20Sopenharmony_ci d->skb = NULL; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci ++d; 3068c2ecf20Sopenharmony_ci if (++cidx == q->size) { 3078c2ecf20Sopenharmony_ci cidx = 0; 3088c2ecf20Sopenharmony_ci d = q->sdesc; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci q->cidx = cidx; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/** 3158c2ecf20Sopenharmony_ci * reclaim_completed_tx - reclaims completed Tx descriptors 3168c2ecf20Sopenharmony_ci * @adapter: the adapter 3178c2ecf20Sopenharmony_ci * @q: the Tx queue to reclaim completed descriptors from 3188c2ecf20Sopenharmony_ci * @chunk: maximum number of descriptors to reclaim 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * Reclaims Tx descriptors that the SGE has indicated it has processed, 3218c2ecf20Sopenharmony_ci * and frees the associated buffers if possible. Called with the Tx 3228c2ecf20Sopenharmony_ci * queue's lock held. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_cistatic inline unsigned int reclaim_completed_tx(struct adapter *adapter, 3258c2ecf20Sopenharmony_ci struct sge_txq *q, 3268c2ecf20Sopenharmony_ci unsigned int chunk) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci unsigned int reclaim = q->processed - q->cleaned; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci reclaim = min(chunk, reclaim); 3318c2ecf20Sopenharmony_ci if (reclaim) { 3328c2ecf20Sopenharmony_ci free_tx_desc(adapter, q, reclaim); 3338c2ecf20Sopenharmony_ci q->cleaned += reclaim; 3348c2ecf20Sopenharmony_ci q->in_use -= reclaim; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci return q->processed - q->cleaned; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/** 3408c2ecf20Sopenharmony_ci * should_restart_tx - are there enough resources to restart a Tx queue? 3418c2ecf20Sopenharmony_ci * @q: the Tx queue 3428c2ecf20Sopenharmony_ci * 3438c2ecf20Sopenharmony_ci * Checks if there are enough descriptors to restart a suspended Tx queue. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_cistatic inline int should_restart_tx(const struct sge_txq *q) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci unsigned int r = q->processed - q->cleaned; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return q->in_use - r < (q->size >> 1); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void clear_rx_desc(struct pci_dev *pdev, const struct sge_fl *q, 3538c2ecf20Sopenharmony_ci struct rx_sw_desc *d) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci if (q->use_pages && d->pg_chunk.page) { 3568c2ecf20Sopenharmony_ci (*d->pg_chunk.p_cnt)--; 3578c2ecf20Sopenharmony_ci if (!*d->pg_chunk.p_cnt) 3588c2ecf20Sopenharmony_ci pci_unmap_page(pdev, 3598c2ecf20Sopenharmony_ci d->pg_chunk.mapping, 3608c2ecf20Sopenharmony_ci q->alloc_size, PCI_DMA_FROMDEVICE); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci put_page(d->pg_chunk.page); 3638c2ecf20Sopenharmony_ci d->pg_chunk.page = NULL; 3648c2ecf20Sopenharmony_ci } else { 3658c2ecf20Sopenharmony_ci pci_unmap_single(pdev, dma_unmap_addr(d, dma_addr), 3668c2ecf20Sopenharmony_ci q->buf_size, PCI_DMA_FROMDEVICE); 3678c2ecf20Sopenharmony_ci kfree_skb(d->skb); 3688c2ecf20Sopenharmony_ci d->skb = NULL; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/** 3738c2ecf20Sopenharmony_ci * free_rx_bufs - free the Rx buffers on an SGE free list 3748c2ecf20Sopenharmony_ci * @pdev: the PCI device associated with the adapter 3758c2ecf20Sopenharmony_ci * @q: the SGE free list to clean up 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * Release the buffers on an SGE free-buffer Rx queue. HW fetching from 3788c2ecf20Sopenharmony_ci * this queue should be stopped before calling this function. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_cistatic void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci unsigned int cidx = q->cidx; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci while (q->credits--) { 3858c2ecf20Sopenharmony_ci struct rx_sw_desc *d = &q->sdesc[cidx]; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci clear_rx_desc(pdev, q, d); 3898c2ecf20Sopenharmony_ci if (++cidx == q->size) 3908c2ecf20Sopenharmony_ci cidx = 0; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (q->pg_chunk.page) { 3948c2ecf20Sopenharmony_ci __free_pages(q->pg_chunk.page, q->order); 3958c2ecf20Sopenharmony_ci q->pg_chunk.page = NULL; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/** 4008c2ecf20Sopenharmony_ci * add_one_rx_buf - add a packet buffer to a free-buffer list 4018c2ecf20Sopenharmony_ci * @va: buffer start VA 4028c2ecf20Sopenharmony_ci * @len: the buffer length 4038c2ecf20Sopenharmony_ci * @d: the HW Rx descriptor to write 4048c2ecf20Sopenharmony_ci * @sd: the SW Rx descriptor to write 4058c2ecf20Sopenharmony_ci * @gen: the generation bit value 4068c2ecf20Sopenharmony_ci * @pdev: the PCI device associated with the adapter 4078c2ecf20Sopenharmony_ci * 4088c2ecf20Sopenharmony_ci * Add a buffer of the given length to the supplied HW and SW Rx 4098c2ecf20Sopenharmony_ci * descriptors. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_cistatic inline int add_one_rx_buf(void *va, unsigned int len, 4128c2ecf20Sopenharmony_ci struct rx_desc *d, struct rx_sw_desc *sd, 4138c2ecf20Sopenharmony_ci unsigned int gen, struct pci_dev *pdev) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci dma_addr_t mapping; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); 4188c2ecf20Sopenharmony_ci if (unlikely(pci_dma_mapping_error(pdev, mapping))) 4198c2ecf20Sopenharmony_ci return -ENOMEM; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci dma_unmap_addr_set(sd, dma_addr, mapping); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci d->addr_lo = cpu_to_be32(mapping); 4248c2ecf20Sopenharmony_ci d->addr_hi = cpu_to_be32((u64) mapping >> 32); 4258c2ecf20Sopenharmony_ci dma_wmb(); 4268c2ecf20Sopenharmony_ci d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); 4278c2ecf20Sopenharmony_ci d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic inline int add_one_rx_chunk(dma_addr_t mapping, struct rx_desc *d, 4328c2ecf20Sopenharmony_ci unsigned int gen) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci d->addr_lo = cpu_to_be32(mapping); 4358c2ecf20Sopenharmony_ci d->addr_hi = cpu_to_be32((u64) mapping >> 32); 4368c2ecf20Sopenharmony_ci dma_wmb(); 4378c2ecf20Sopenharmony_ci d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); 4388c2ecf20Sopenharmony_ci d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); 4398c2ecf20Sopenharmony_ci return 0; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q, 4438c2ecf20Sopenharmony_ci struct rx_sw_desc *sd, gfp_t gfp, 4448c2ecf20Sopenharmony_ci unsigned int order) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci if (!q->pg_chunk.page) { 4478c2ecf20Sopenharmony_ci dma_addr_t mapping; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci q->pg_chunk.page = alloc_pages(gfp, order); 4508c2ecf20Sopenharmony_ci if (unlikely(!q->pg_chunk.page)) 4518c2ecf20Sopenharmony_ci return -ENOMEM; 4528c2ecf20Sopenharmony_ci q->pg_chunk.va = page_address(q->pg_chunk.page); 4538c2ecf20Sopenharmony_ci q->pg_chunk.p_cnt = q->pg_chunk.va + (PAGE_SIZE << order) - 4548c2ecf20Sopenharmony_ci SGE_PG_RSVD; 4558c2ecf20Sopenharmony_ci q->pg_chunk.offset = 0; 4568c2ecf20Sopenharmony_ci mapping = pci_map_page(adapter->pdev, q->pg_chunk.page, 4578c2ecf20Sopenharmony_ci 0, q->alloc_size, PCI_DMA_FROMDEVICE); 4588c2ecf20Sopenharmony_ci if (unlikely(pci_dma_mapping_error(adapter->pdev, mapping))) { 4598c2ecf20Sopenharmony_ci __free_pages(q->pg_chunk.page, order); 4608c2ecf20Sopenharmony_ci q->pg_chunk.page = NULL; 4618c2ecf20Sopenharmony_ci return -EIO; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci q->pg_chunk.mapping = mapping; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci sd->pg_chunk = q->pg_chunk; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci prefetch(sd->pg_chunk.p_cnt); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci q->pg_chunk.offset += q->buf_size; 4708c2ecf20Sopenharmony_ci if (q->pg_chunk.offset == (PAGE_SIZE << order)) 4718c2ecf20Sopenharmony_ci q->pg_chunk.page = NULL; 4728c2ecf20Sopenharmony_ci else { 4738c2ecf20Sopenharmony_ci q->pg_chunk.va += q->buf_size; 4748c2ecf20Sopenharmony_ci get_page(q->pg_chunk.page); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (sd->pg_chunk.offset == 0) 4788c2ecf20Sopenharmony_ci *sd->pg_chunk.p_cnt = 1; 4798c2ecf20Sopenharmony_ci else 4808c2ecf20Sopenharmony_ci *sd->pg_chunk.p_cnt += 1; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci if (q->pend_cred >= q->credits / 4) { 4888c2ecf20Sopenharmony_ci q->pend_cred = 0; 4898c2ecf20Sopenharmony_ci wmb(); 4908c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/** 4958c2ecf20Sopenharmony_ci * refill_fl - refill an SGE free-buffer list 4968c2ecf20Sopenharmony_ci * @adap: the adapter 4978c2ecf20Sopenharmony_ci * @q: the free-list to refill 4988c2ecf20Sopenharmony_ci * @n: the number of new buffers to allocate 4998c2ecf20Sopenharmony_ci * @gfp: the gfp flags for allocating new buffers 5008c2ecf20Sopenharmony_ci * 5018c2ecf20Sopenharmony_ci * (Re)populate an SGE free-buffer list with up to @n new packet buffers, 5028c2ecf20Sopenharmony_ci * allocated with the supplied gfp flags. The caller must assure that 5038c2ecf20Sopenharmony_ci * @n does not exceed the queue's capacity. 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_cistatic int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct rx_sw_desc *sd = &q->sdesc[q->pidx]; 5088c2ecf20Sopenharmony_ci struct rx_desc *d = &q->desc[q->pidx]; 5098c2ecf20Sopenharmony_ci unsigned int count = 0; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci while (n--) { 5128c2ecf20Sopenharmony_ci dma_addr_t mapping; 5138c2ecf20Sopenharmony_ci int err; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (q->use_pages) { 5168c2ecf20Sopenharmony_ci if (unlikely(alloc_pg_chunk(adap, q, sd, gfp, 5178c2ecf20Sopenharmony_ci q->order))) { 5188c2ecf20Sopenharmony_cinomem: q->alloc_failed++; 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci mapping = sd->pg_chunk.mapping + sd->pg_chunk.offset; 5228c2ecf20Sopenharmony_ci dma_unmap_addr_set(sd, dma_addr, mapping); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci add_one_rx_chunk(mapping, d, q->gen); 5258c2ecf20Sopenharmony_ci pci_dma_sync_single_for_device(adap->pdev, mapping, 5268c2ecf20Sopenharmony_ci q->buf_size - SGE_PG_RSVD, 5278c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 5288c2ecf20Sopenharmony_ci } else { 5298c2ecf20Sopenharmony_ci void *buf_start; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci struct sk_buff *skb = alloc_skb(q->buf_size, gfp); 5328c2ecf20Sopenharmony_ci if (!skb) 5338c2ecf20Sopenharmony_ci goto nomem; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci sd->skb = skb; 5368c2ecf20Sopenharmony_ci buf_start = skb->data; 5378c2ecf20Sopenharmony_ci err = add_one_rx_buf(buf_start, q->buf_size, d, sd, 5388c2ecf20Sopenharmony_ci q->gen, adap->pdev); 5398c2ecf20Sopenharmony_ci if (unlikely(err)) { 5408c2ecf20Sopenharmony_ci clear_rx_desc(adap->pdev, q, sd); 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci d++; 5468c2ecf20Sopenharmony_ci sd++; 5478c2ecf20Sopenharmony_ci if (++q->pidx == q->size) { 5488c2ecf20Sopenharmony_ci q->pidx = 0; 5498c2ecf20Sopenharmony_ci q->gen ^= 1; 5508c2ecf20Sopenharmony_ci sd = q->sdesc; 5518c2ecf20Sopenharmony_ci d = q->desc; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci count++; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci q->credits += count; 5578c2ecf20Sopenharmony_ci q->pend_cred += count; 5588c2ecf20Sopenharmony_ci ring_fl_db(adap, q); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return count; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits), 5668c2ecf20Sopenharmony_ci GFP_ATOMIC | __GFP_COMP); 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci/** 5708c2ecf20Sopenharmony_ci * recycle_rx_buf - recycle a receive buffer 5718c2ecf20Sopenharmony_ci * @adap: the adapter 5728c2ecf20Sopenharmony_ci * @q: the SGE free list 5738c2ecf20Sopenharmony_ci * @idx: index of buffer to recycle 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * Recycles the specified buffer on the given free list by adding it at 5768c2ecf20Sopenharmony_ci * the next available slot on the list. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_cistatic void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, 5798c2ecf20Sopenharmony_ci unsigned int idx) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct rx_desc *from = &q->desc[idx]; 5828c2ecf20Sopenharmony_ci struct rx_desc *to = &q->desc[q->pidx]; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci q->sdesc[q->pidx] = q->sdesc[idx]; 5858c2ecf20Sopenharmony_ci to->addr_lo = from->addr_lo; /* already big endian */ 5868c2ecf20Sopenharmony_ci to->addr_hi = from->addr_hi; /* likewise */ 5878c2ecf20Sopenharmony_ci dma_wmb(); 5888c2ecf20Sopenharmony_ci to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen)); 5898c2ecf20Sopenharmony_ci to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen)); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (++q->pidx == q->size) { 5928c2ecf20Sopenharmony_ci q->pidx = 0; 5938c2ecf20Sopenharmony_ci q->gen ^= 1; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci q->credits++; 5978c2ecf20Sopenharmony_ci q->pend_cred++; 5988c2ecf20Sopenharmony_ci ring_fl_db(adap, q); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/** 6028c2ecf20Sopenharmony_ci * alloc_ring - allocate resources for an SGE descriptor ring 6038c2ecf20Sopenharmony_ci * @pdev: the PCI device 6048c2ecf20Sopenharmony_ci * @nelem: the number of descriptors 6058c2ecf20Sopenharmony_ci * @elem_size: the size of each descriptor 6068c2ecf20Sopenharmony_ci * @sw_size: the size of the SW state associated with each ring element 6078c2ecf20Sopenharmony_ci * @phys: the physical address of the allocated ring 6088c2ecf20Sopenharmony_ci * @metadata: address of the array holding the SW state for the ring 6098c2ecf20Sopenharmony_ci * 6108c2ecf20Sopenharmony_ci * Allocates resources for an SGE descriptor ring, such as Tx queues, 6118c2ecf20Sopenharmony_ci * free buffer lists, or response queues. Each SGE ring requires 6128c2ecf20Sopenharmony_ci * space for its HW descriptors plus, optionally, space for the SW state 6138c2ecf20Sopenharmony_ci * associated with each HW entry (the metadata). The function returns 6148c2ecf20Sopenharmony_ci * three values: the virtual address for the HW ring (the return value 6158c2ecf20Sopenharmony_ci * of the function), the physical address of the HW ring, and the address 6168c2ecf20Sopenharmony_ci * of the SW ring. 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_cistatic void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, 6198c2ecf20Sopenharmony_ci size_t sw_size, dma_addr_t * phys, void *metadata) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci size_t len = nelem * elem_size; 6228c2ecf20Sopenharmony_ci void *s = NULL; 6238c2ecf20Sopenharmony_ci void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!p) 6268c2ecf20Sopenharmony_ci return NULL; 6278c2ecf20Sopenharmony_ci if (sw_size && metadata) { 6288c2ecf20Sopenharmony_ci s = kcalloc(nelem, sw_size, GFP_KERNEL); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (!s) { 6318c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, len, p, *phys); 6328c2ecf20Sopenharmony_ci return NULL; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci *(void **)metadata = s; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci return p; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci/** 6408c2ecf20Sopenharmony_ci * t3_reset_qset - reset a sge qset 6418c2ecf20Sopenharmony_ci * @q: the queue set 6428c2ecf20Sopenharmony_ci * 6438c2ecf20Sopenharmony_ci * Reset the qset structure. 6448c2ecf20Sopenharmony_ci * the NAPI structure is preserved in the event of 6458c2ecf20Sopenharmony_ci * the qset's reincarnation, for example during EEH recovery. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_cistatic void t3_reset_qset(struct sge_qset *q) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci if (q->adap && 6508c2ecf20Sopenharmony_ci !(q->adap->flags & NAPI_INIT)) { 6518c2ecf20Sopenharmony_ci memset(q, 0, sizeof(*q)); 6528c2ecf20Sopenharmony_ci return; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci q->adap = NULL; 6568c2ecf20Sopenharmony_ci memset(&q->rspq, 0, sizeof(q->rspq)); 6578c2ecf20Sopenharmony_ci memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET); 6588c2ecf20Sopenharmony_ci memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); 6598c2ecf20Sopenharmony_ci q->txq_stopped = 0; 6608c2ecf20Sopenharmony_ci q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ 6618c2ecf20Sopenharmony_ci q->rx_reclaim_timer.function = NULL; 6628c2ecf20Sopenharmony_ci q->nomem = 0; 6638c2ecf20Sopenharmony_ci napi_free_frags(&q->napi); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci/** 6688c2ecf20Sopenharmony_ci * free_qset - free the resources of an SGE queue set 6698c2ecf20Sopenharmony_ci * @adapter: the adapter owning the queue set 6708c2ecf20Sopenharmony_ci * @q: the queue set 6718c2ecf20Sopenharmony_ci * 6728c2ecf20Sopenharmony_ci * Release the HW and SW resources associated with an SGE queue set, such 6738c2ecf20Sopenharmony_ci * as HW contexts, packet buffers, and descriptor rings. Traffic to the 6748c2ecf20Sopenharmony_ci * queue set must be quiesced prior to calling this. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_cistatic void t3_free_qset(struct adapter *adapter, struct sge_qset *q) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci int i; 6798c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci for (i = 0; i < SGE_RXQ_PER_SET; ++i) 6828c2ecf20Sopenharmony_ci if (q->fl[i].desc) { 6838c2ecf20Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 6848c2ecf20Sopenharmony_ci t3_sge_disable_fl(adapter, q->fl[i].cntxt_id); 6858c2ecf20Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 6868c2ecf20Sopenharmony_ci free_rx_bufs(pdev, &q->fl[i]); 6878c2ecf20Sopenharmony_ci kfree(q->fl[i].sdesc); 6888c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 6898c2ecf20Sopenharmony_ci q->fl[i].size * 6908c2ecf20Sopenharmony_ci sizeof(struct rx_desc), q->fl[i].desc, 6918c2ecf20Sopenharmony_ci q->fl[i].phys_addr); 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci for (i = 0; i < SGE_TXQ_PER_SET; ++i) 6958c2ecf20Sopenharmony_ci if (q->txq[i].desc) { 6968c2ecf20Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 6978c2ecf20Sopenharmony_ci t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0); 6988c2ecf20Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 6998c2ecf20Sopenharmony_ci if (q->txq[i].sdesc) { 7008c2ecf20Sopenharmony_ci free_tx_desc(adapter, &q->txq[i], 7018c2ecf20Sopenharmony_ci q->txq[i].in_use); 7028c2ecf20Sopenharmony_ci kfree(q->txq[i].sdesc); 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 7058c2ecf20Sopenharmony_ci q->txq[i].size * 7068c2ecf20Sopenharmony_ci sizeof(struct tx_desc), 7078c2ecf20Sopenharmony_ci q->txq[i].desc, q->txq[i].phys_addr); 7088c2ecf20Sopenharmony_ci __skb_queue_purge(&q->txq[i].sendq); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (q->rspq.desc) { 7128c2ecf20Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 7138c2ecf20Sopenharmony_ci t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id); 7148c2ecf20Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 7158c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, 7168c2ecf20Sopenharmony_ci q->rspq.size * sizeof(struct rsp_desc), 7178c2ecf20Sopenharmony_ci q->rspq.desc, q->rspq.phys_addr); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci t3_reset_qset(q); 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci/** 7248c2ecf20Sopenharmony_ci * init_qset_cntxt - initialize an SGE queue set context info 7258c2ecf20Sopenharmony_ci * @qs: the queue set 7268c2ecf20Sopenharmony_ci * @id: the queue set id 7278c2ecf20Sopenharmony_ci * 7288c2ecf20Sopenharmony_ci * Initializes the TIDs and context ids for the queues of a queue set. 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_cistatic void init_qset_cntxt(struct sge_qset *qs, unsigned int id) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci qs->rspq.cntxt_id = id; 7338c2ecf20Sopenharmony_ci qs->fl[0].cntxt_id = 2 * id; 7348c2ecf20Sopenharmony_ci qs->fl[1].cntxt_id = 2 * id + 1; 7358c2ecf20Sopenharmony_ci qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id; 7368c2ecf20Sopenharmony_ci qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id; 7378c2ecf20Sopenharmony_ci qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id; 7388c2ecf20Sopenharmony_ci qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id; 7398c2ecf20Sopenharmony_ci qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci/** 7438c2ecf20Sopenharmony_ci * sgl_len - calculates the size of an SGL of the given capacity 7448c2ecf20Sopenharmony_ci * @n: the number of SGL entries 7458c2ecf20Sopenharmony_ci * 7468c2ecf20Sopenharmony_ci * Calculates the number of flits needed for a scatter/gather list that 7478c2ecf20Sopenharmony_ci * can hold the given number of entries. 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_cistatic inline unsigned int sgl_len(unsigned int n) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci /* alternatively: 3 * (n / 2) + 2 * (n & 1) */ 7528c2ecf20Sopenharmony_ci return (3 * n) / 2 + (n & 1); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci/** 7568c2ecf20Sopenharmony_ci * flits_to_desc - returns the num of Tx descriptors for the given flits 7578c2ecf20Sopenharmony_ci * @n: the number of flits 7588c2ecf20Sopenharmony_ci * 7598c2ecf20Sopenharmony_ci * Calculates the number of Tx descriptors needed for the supplied number 7608c2ecf20Sopenharmony_ci * of flits. 7618c2ecf20Sopenharmony_ci */ 7628c2ecf20Sopenharmony_cistatic inline unsigned int flits_to_desc(unsigned int n) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci BUG_ON(n >= ARRAY_SIZE(flit_desc_map)); 7658c2ecf20Sopenharmony_ci return flit_desc_map[n]; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci/** 7698c2ecf20Sopenharmony_ci * get_packet - return the next ingress packet buffer from a free list 7708c2ecf20Sopenharmony_ci * @adap: the adapter that received the packet 7718c2ecf20Sopenharmony_ci * @fl: the SGE free list holding the packet 7728c2ecf20Sopenharmony_ci * @len: the packet length including any SGE padding 7738c2ecf20Sopenharmony_ci * @drop_thres: # of remaining buffers before we start dropping packets 7748c2ecf20Sopenharmony_ci * 7758c2ecf20Sopenharmony_ci * Get the next packet from a free list and complete setup of the 7768c2ecf20Sopenharmony_ci * sk_buff. If the packet is small we make a copy and recycle the 7778c2ecf20Sopenharmony_ci * original buffer, otherwise we use the original buffer itself. If a 7788c2ecf20Sopenharmony_ci * positive drop threshold is supplied packets are dropped and their 7798c2ecf20Sopenharmony_ci * buffers recycled if (a) the number of remaining buffers is under the 7808c2ecf20Sopenharmony_ci * threshold and the packet is too big to copy, or (b) the packet should 7818c2ecf20Sopenharmony_ci * be copied but there is no memory for the copy. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_cistatic struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, 7848c2ecf20Sopenharmony_ci unsigned int len, unsigned int drop_thres) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 7878c2ecf20Sopenharmony_ci struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci prefetch(sd->skb->data); 7908c2ecf20Sopenharmony_ci fl->credits--; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (len <= SGE_RX_COPY_THRES) { 7938c2ecf20Sopenharmony_ci skb = alloc_skb(len, GFP_ATOMIC); 7948c2ecf20Sopenharmony_ci if (likely(skb != NULL)) { 7958c2ecf20Sopenharmony_ci __skb_put(skb, len); 7968c2ecf20Sopenharmony_ci pci_dma_sync_single_for_cpu(adap->pdev, 7978c2ecf20Sopenharmony_ci dma_unmap_addr(sd, dma_addr), len, 7988c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 7998c2ecf20Sopenharmony_ci memcpy(skb->data, sd->skb->data, len); 8008c2ecf20Sopenharmony_ci pci_dma_sync_single_for_device(adap->pdev, 8018c2ecf20Sopenharmony_ci dma_unmap_addr(sd, dma_addr), len, 8028c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 8038c2ecf20Sopenharmony_ci } else if (!drop_thres) 8048c2ecf20Sopenharmony_ci goto use_orig_buf; 8058c2ecf20Sopenharmony_cirecycle: 8068c2ecf20Sopenharmony_ci recycle_rx_buf(adap, fl, fl->cidx); 8078c2ecf20Sopenharmony_ci return skb; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (unlikely(fl->credits < drop_thres) && 8118c2ecf20Sopenharmony_ci refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits - 1), 8128c2ecf20Sopenharmony_ci GFP_ATOMIC | __GFP_COMP) == 0) 8138c2ecf20Sopenharmony_ci goto recycle; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ciuse_orig_buf: 8168c2ecf20Sopenharmony_ci pci_unmap_single(adap->pdev, dma_unmap_addr(sd, dma_addr), 8178c2ecf20Sopenharmony_ci fl->buf_size, PCI_DMA_FROMDEVICE); 8188c2ecf20Sopenharmony_ci skb = sd->skb; 8198c2ecf20Sopenharmony_ci skb_put(skb, len); 8208c2ecf20Sopenharmony_ci __refill_fl(adap, fl); 8218c2ecf20Sopenharmony_ci return skb; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci/** 8258c2ecf20Sopenharmony_ci * get_packet_pg - return the next ingress packet buffer from a free list 8268c2ecf20Sopenharmony_ci * @adap: the adapter that received the packet 8278c2ecf20Sopenharmony_ci * @fl: the SGE free list holding the packet 8288c2ecf20Sopenharmony_ci * @q: the queue 8298c2ecf20Sopenharmony_ci * @len: the packet length including any SGE padding 8308c2ecf20Sopenharmony_ci * @drop_thres: # of remaining buffers before we start dropping packets 8318c2ecf20Sopenharmony_ci * 8328c2ecf20Sopenharmony_ci * Get the next packet from a free list populated with page chunks. 8338c2ecf20Sopenharmony_ci * If the packet is small we make a copy and recycle the original buffer, 8348c2ecf20Sopenharmony_ci * otherwise we attach the original buffer as a page fragment to a fresh 8358c2ecf20Sopenharmony_ci * sk_buff. If a positive drop threshold is supplied packets are dropped 8368c2ecf20Sopenharmony_ci * and their buffers recycled if (a) the number of remaining buffers is 8378c2ecf20Sopenharmony_ci * under the threshold and the packet is too big to copy, or (b) there's 8388c2ecf20Sopenharmony_ci * no system memory. 8398c2ecf20Sopenharmony_ci * 8408c2ecf20Sopenharmony_ci * Note: this function is similar to @get_packet but deals with Rx buffers 8418c2ecf20Sopenharmony_ci * that are page chunks rather than sk_buffs. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_cistatic struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, 8448c2ecf20Sopenharmony_ci struct sge_rspq *q, unsigned int len, 8458c2ecf20Sopenharmony_ci unsigned int drop_thres) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct sk_buff *newskb, *skb; 8488c2ecf20Sopenharmony_ci struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci dma_addr_t dma_addr = dma_unmap_addr(sd, dma_addr); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci newskb = skb = q->pg_skb; 8538c2ecf20Sopenharmony_ci if (!skb && (len <= SGE_RX_COPY_THRES)) { 8548c2ecf20Sopenharmony_ci newskb = alloc_skb(len, GFP_ATOMIC); 8558c2ecf20Sopenharmony_ci if (likely(newskb != NULL)) { 8568c2ecf20Sopenharmony_ci __skb_put(newskb, len); 8578c2ecf20Sopenharmony_ci pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len, 8588c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 8598c2ecf20Sopenharmony_ci memcpy(newskb->data, sd->pg_chunk.va, len); 8608c2ecf20Sopenharmony_ci pci_dma_sync_single_for_device(adap->pdev, dma_addr, 8618c2ecf20Sopenharmony_ci len, 8628c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 8638c2ecf20Sopenharmony_ci } else if (!drop_thres) 8648c2ecf20Sopenharmony_ci return NULL; 8658c2ecf20Sopenharmony_cirecycle: 8668c2ecf20Sopenharmony_ci fl->credits--; 8678c2ecf20Sopenharmony_ci recycle_rx_buf(adap, fl, fl->cidx); 8688c2ecf20Sopenharmony_ci q->rx_recycle_buf++; 8698c2ecf20Sopenharmony_ci return newskb; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) 8738c2ecf20Sopenharmony_ci goto recycle; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci prefetch(sd->pg_chunk.p_cnt); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (!skb) 8788c2ecf20Sopenharmony_ci newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (unlikely(!newskb)) { 8818c2ecf20Sopenharmony_ci if (!drop_thres) 8828c2ecf20Sopenharmony_ci return NULL; 8838c2ecf20Sopenharmony_ci goto recycle; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len, 8878c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 8888c2ecf20Sopenharmony_ci (*sd->pg_chunk.p_cnt)--; 8898c2ecf20Sopenharmony_ci if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) 8908c2ecf20Sopenharmony_ci pci_unmap_page(adap->pdev, 8918c2ecf20Sopenharmony_ci sd->pg_chunk.mapping, 8928c2ecf20Sopenharmony_ci fl->alloc_size, 8938c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 8948c2ecf20Sopenharmony_ci if (!skb) { 8958c2ecf20Sopenharmony_ci __skb_put(newskb, SGE_RX_PULL_LEN); 8968c2ecf20Sopenharmony_ci memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); 8978c2ecf20Sopenharmony_ci skb_fill_page_desc(newskb, 0, sd->pg_chunk.page, 8988c2ecf20Sopenharmony_ci sd->pg_chunk.offset + SGE_RX_PULL_LEN, 8998c2ecf20Sopenharmony_ci len - SGE_RX_PULL_LEN); 9008c2ecf20Sopenharmony_ci newskb->len = len; 9018c2ecf20Sopenharmony_ci newskb->data_len = len - SGE_RX_PULL_LEN; 9028c2ecf20Sopenharmony_ci newskb->truesize += newskb->data_len; 9038c2ecf20Sopenharmony_ci } else { 9048c2ecf20Sopenharmony_ci skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags, 9058c2ecf20Sopenharmony_ci sd->pg_chunk.page, 9068c2ecf20Sopenharmony_ci sd->pg_chunk.offset, len); 9078c2ecf20Sopenharmony_ci newskb->len += len; 9088c2ecf20Sopenharmony_ci newskb->data_len += len; 9098c2ecf20Sopenharmony_ci newskb->truesize += len; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci fl->credits--; 9138c2ecf20Sopenharmony_ci /* 9148c2ecf20Sopenharmony_ci * We do not refill FLs here, we let the caller do it to overlap a 9158c2ecf20Sopenharmony_ci * prefetch. 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_ci return newskb; 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci/** 9218c2ecf20Sopenharmony_ci * get_imm_packet - return the next ingress packet buffer from a response 9228c2ecf20Sopenharmony_ci * @resp: the response descriptor containing the packet data 9238c2ecf20Sopenharmony_ci * 9248c2ecf20Sopenharmony_ci * Return a packet containing the immediate data of the given response. 9258c2ecf20Sopenharmony_ci */ 9268c2ecf20Sopenharmony_cistatic inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (skb) { 9318c2ecf20Sopenharmony_ci __skb_put(skb, IMMED_PKT_SIZE); 9328c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, resp->imm_data, IMMED_PKT_SIZE); 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci return skb; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci/** 9388c2ecf20Sopenharmony_ci * calc_tx_descs - calculate the number of Tx descriptors for a packet 9398c2ecf20Sopenharmony_ci * @skb: the packet 9408c2ecf20Sopenharmony_ci * 9418c2ecf20Sopenharmony_ci * Returns the number of Tx descriptors needed for the given Ethernet 9428c2ecf20Sopenharmony_ci * packet. Ethernet packets require addition of WR and CPL headers. 9438c2ecf20Sopenharmony_ci */ 9448c2ecf20Sopenharmony_cistatic inline unsigned int calc_tx_descs(const struct sk_buff *skb) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci unsigned int flits; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt)) 9498c2ecf20Sopenharmony_ci return 1; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2; 9528c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_size) 9538c2ecf20Sopenharmony_ci flits++; 9548c2ecf20Sopenharmony_ci return flits_to_desc(flits); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci/* map_skb - map a packet main body and its page fragments 9588c2ecf20Sopenharmony_ci * @pdev: the PCI device 9598c2ecf20Sopenharmony_ci * @skb: the packet 9608c2ecf20Sopenharmony_ci * @addr: placeholder to save the mapped addresses 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * map the main body of an sk_buff and its page fragments, if any. 9638c2ecf20Sopenharmony_ci */ 9648c2ecf20Sopenharmony_cistatic int map_skb(struct pci_dev *pdev, const struct sk_buff *skb, 9658c2ecf20Sopenharmony_ci dma_addr_t *addr) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci const skb_frag_t *fp, *end; 9688c2ecf20Sopenharmony_ci const struct skb_shared_info *si; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (skb_headlen(skb)) { 9718c2ecf20Sopenharmony_ci *addr = pci_map_single(pdev, skb->data, skb_headlen(skb), 9728c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 9738c2ecf20Sopenharmony_ci if (pci_dma_mapping_error(pdev, *addr)) 9748c2ecf20Sopenharmony_ci goto out_err; 9758c2ecf20Sopenharmony_ci addr++; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci si = skb_shinfo(skb); 9798c2ecf20Sopenharmony_ci end = &si->frags[si->nr_frags]; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci for (fp = si->frags; fp < end; fp++) { 9828c2ecf20Sopenharmony_ci *addr = skb_frag_dma_map(&pdev->dev, fp, 0, skb_frag_size(fp), 9838c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9848c2ecf20Sopenharmony_ci if (pci_dma_mapping_error(pdev, *addr)) 9858c2ecf20Sopenharmony_ci goto unwind; 9868c2ecf20Sopenharmony_ci addr++; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ciunwind: 9918c2ecf20Sopenharmony_ci while (fp-- > si->frags) 9928c2ecf20Sopenharmony_ci dma_unmap_page(&pdev->dev, *--addr, skb_frag_size(fp), 9938c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci pci_unmap_single(pdev, addr[-1], skb_headlen(skb), PCI_DMA_TODEVICE); 9968c2ecf20Sopenharmony_ciout_err: 9978c2ecf20Sopenharmony_ci return -ENOMEM; 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci/** 10018c2ecf20Sopenharmony_ci * write_sgl - populate a scatter/gather list for a packet 10028c2ecf20Sopenharmony_ci * @skb: the packet 10038c2ecf20Sopenharmony_ci * @sgp: the SGL to populate 10048c2ecf20Sopenharmony_ci * @start: start address of skb main body data to include in the SGL 10058c2ecf20Sopenharmony_ci * @len: length of skb main body data to include in the SGL 10068c2ecf20Sopenharmony_ci * @addr: the list of the mapped addresses 10078c2ecf20Sopenharmony_ci * 10088c2ecf20Sopenharmony_ci * Copies the scatter/gather list for the buffers that make up a packet 10098c2ecf20Sopenharmony_ci * and returns the SGL size in 8-byte words. The caller must size the SGL 10108c2ecf20Sopenharmony_ci * appropriately. 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_cistatic inline unsigned int write_sgl(const struct sk_buff *skb, 10138c2ecf20Sopenharmony_ci struct sg_ent *sgp, unsigned char *start, 10148c2ecf20Sopenharmony_ci unsigned int len, const dma_addr_t *addr) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci unsigned int i, j = 0, k = 0, nfrags; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (len) { 10198c2ecf20Sopenharmony_ci sgp->len[0] = cpu_to_be32(len); 10208c2ecf20Sopenharmony_ci sgp->addr[j++] = cpu_to_be64(addr[k++]); 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci nfrags = skb_shinfo(skb)->nr_frags; 10248c2ecf20Sopenharmony_ci for (i = 0; i < nfrags; i++) { 10258c2ecf20Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci sgp->len[j] = cpu_to_be32(skb_frag_size(frag)); 10288c2ecf20Sopenharmony_ci sgp->addr[j] = cpu_to_be64(addr[k++]); 10298c2ecf20Sopenharmony_ci j ^= 1; 10308c2ecf20Sopenharmony_ci if (j == 0) 10318c2ecf20Sopenharmony_ci ++sgp; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci if (j) 10348c2ecf20Sopenharmony_ci sgp->len[j] = 0; 10358c2ecf20Sopenharmony_ci return ((nfrags + (len != 0)) * 3) / 2 + j; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/** 10398c2ecf20Sopenharmony_ci * check_ring_tx_db - check and potentially ring a Tx queue's doorbell 10408c2ecf20Sopenharmony_ci * @adap: the adapter 10418c2ecf20Sopenharmony_ci * @q: the Tx queue 10428c2ecf20Sopenharmony_ci * 10438c2ecf20Sopenharmony_ci * Ring the doorbel if a Tx queue is asleep. There is a natural race, 10448c2ecf20Sopenharmony_ci * where the HW is going to sleep just after we checked, however, 10458c2ecf20Sopenharmony_ci * then the interrupt handler will detect the outstanding TX packet 10468c2ecf20Sopenharmony_ci * and ring the doorbell for us. 10478c2ecf20Sopenharmony_ci * 10488c2ecf20Sopenharmony_ci * When GTS is disabled we unconditionally ring the doorbell. 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_cistatic inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci#if USE_GTS 10538c2ecf20Sopenharmony_ci clear_bit(TXQ_LAST_PKT_DB, &q->flags); 10548c2ecf20Sopenharmony_ci if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) { 10558c2ecf20Sopenharmony_ci set_bit(TXQ_LAST_PKT_DB, &q->flags); 10568c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, 10578c2ecf20Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci#else 10608c2ecf20Sopenharmony_ci wmb(); /* write descriptors before telling HW */ 10618c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, 10628c2ecf20Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 10638c2ecf20Sopenharmony_ci#endif 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic inline void wr_gen2(struct tx_desc *d, unsigned int gen) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci#if SGE_NUM_GENBITS == 2 10698c2ecf20Sopenharmony_ci d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen); 10708c2ecf20Sopenharmony_ci#endif 10718c2ecf20Sopenharmony_ci} 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci/** 10748c2ecf20Sopenharmony_ci * write_wr_hdr_sgl - write a WR header and, optionally, SGL 10758c2ecf20Sopenharmony_ci * @ndesc: number of Tx descriptors spanned by the SGL 10768c2ecf20Sopenharmony_ci * @skb: the packet corresponding to the WR 10778c2ecf20Sopenharmony_ci * @d: first Tx descriptor to be written 10788c2ecf20Sopenharmony_ci * @pidx: index of above descriptors 10798c2ecf20Sopenharmony_ci * @q: the SGE Tx queue 10808c2ecf20Sopenharmony_ci * @sgl: the SGL 10818c2ecf20Sopenharmony_ci * @flits: number of flits to the start of the SGL in the first descriptor 10828c2ecf20Sopenharmony_ci * @sgl_flits: the SGL size in flits 10838c2ecf20Sopenharmony_ci * @gen: the Tx descriptor generation 10848c2ecf20Sopenharmony_ci * @wr_hi: top 32 bits of WR header based on WR type (big endian) 10858c2ecf20Sopenharmony_ci * @wr_lo: low 32 bits of WR header based on WR type (big endian) 10868c2ecf20Sopenharmony_ci * 10878c2ecf20Sopenharmony_ci * Write a work request header and an associated SGL. If the SGL is 10888c2ecf20Sopenharmony_ci * small enough to fit into one Tx descriptor it has already been written 10898c2ecf20Sopenharmony_ci * and we just need to write the WR header. Otherwise we distribute the 10908c2ecf20Sopenharmony_ci * SGL across the number of descriptors it spans. 10918c2ecf20Sopenharmony_ci */ 10928c2ecf20Sopenharmony_cistatic void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, 10938c2ecf20Sopenharmony_ci struct tx_desc *d, unsigned int pidx, 10948c2ecf20Sopenharmony_ci const struct sge_txq *q, 10958c2ecf20Sopenharmony_ci const struct sg_ent *sgl, 10968c2ecf20Sopenharmony_ci unsigned int flits, unsigned int sgl_flits, 10978c2ecf20Sopenharmony_ci unsigned int gen, __be32 wr_hi, 10988c2ecf20Sopenharmony_ci __be32 wr_lo) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct work_request_hdr *wrp = (struct work_request_hdr *)d; 11018c2ecf20Sopenharmony_ci struct tx_sw_desc *sd = &q->sdesc[pidx]; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci sd->skb = skb; 11048c2ecf20Sopenharmony_ci if (need_skb_unmap()) { 11058c2ecf20Sopenharmony_ci sd->fragidx = 0; 11068c2ecf20Sopenharmony_ci sd->addr_idx = 0; 11078c2ecf20Sopenharmony_ci sd->sflit = flits; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (likely(ndesc == 1)) { 11118c2ecf20Sopenharmony_ci sd->eop = 1; 11128c2ecf20Sopenharmony_ci wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | 11138c2ecf20Sopenharmony_ci V_WR_SGLSFLT(flits)) | wr_hi; 11148c2ecf20Sopenharmony_ci dma_wmb(); 11158c2ecf20Sopenharmony_ci wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) | 11168c2ecf20Sopenharmony_ci V_WR_GEN(gen)) | wr_lo; 11178c2ecf20Sopenharmony_ci wr_gen2(d, gen); 11188c2ecf20Sopenharmony_ci } else { 11198c2ecf20Sopenharmony_ci unsigned int ogen = gen; 11208c2ecf20Sopenharmony_ci const u64 *fp = (const u64 *)sgl; 11218c2ecf20Sopenharmony_ci struct work_request_hdr *wp = wrp; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) | 11248c2ecf20Sopenharmony_ci V_WR_SGLSFLT(flits)) | wr_hi; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci while (sgl_flits) { 11278c2ecf20Sopenharmony_ci unsigned int avail = WR_FLITS - flits; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (avail > sgl_flits) 11308c2ecf20Sopenharmony_ci avail = sgl_flits; 11318c2ecf20Sopenharmony_ci memcpy(&d->flit[flits], fp, avail * sizeof(*fp)); 11328c2ecf20Sopenharmony_ci sgl_flits -= avail; 11338c2ecf20Sopenharmony_ci ndesc--; 11348c2ecf20Sopenharmony_ci if (!sgl_flits) 11358c2ecf20Sopenharmony_ci break; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci fp += avail; 11388c2ecf20Sopenharmony_ci d++; 11398c2ecf20Sopenharmony_ci sd->eop = 0; 11408c2ecf20Sopenharmony_ci sd++; 11418c2ecf20Sopenharmony_ci if (++pidx == q->size) { 11428c2ecf20Sopenharmony_ci pidx = 0; 11438c2ecf20Sopenharmony_ci gen ^= 1; 11448c2ecf20Sopenharmony_ci d = q->desc; 11458c2ecf20Sopenharmony_ci sd = q->sdesc; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci sd->skb = skb; 11498c2ecf20Sopenharmony_ci wrp = (struct work_request_hdr *)d; 11508c2ecf20Sopenharmony_ci wrp->wr_hi = htonl(V_WR_DATATYPE(1) | 11518c2ecf20Sopenharmony_ci V_WR_SGLSFLT(1)) | wr_hi; 11528c2ecf20Sopenharmony_ci wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS, 11538c2ecf20Sopenharmony_ci sgl_flits + 1)) | 11548c2ecf20Sopenharmony_ci V_WR_GEN(gen)) | wr_lo; 11558c2ecf20Sopenharmony_ci wr_gen2(d, gen); 11568c2ecf20Sopenharmony_ci flits = 1; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci sd->eop = 1; 11598c2ecf20Sopenharmony_ci wrp->wr_hi |= htonl(F_WR_EOP); 11608c2ecf20Sopenharmony_ci dma_wmb(); 11618c2ecf20Sopenharmony_ci wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; 11628c2ecf20Sopenharmony_ci wr_gen2((struct tx_desc *)wp, ogen); 11638c2ecf20Sopenharmony_ci WARN_ON(ndesc != 0); 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci/** 11688c2ecf20Sopenharmony_ci * write_tx_pkt_wr - write a TX_PKT work request 11698c2ecf20Sopenharmony_ci * @adap: the adapter 11708c2ecf20Sopenharmony_ci * @skb: the packet to send 11718c2ecf20Sopenharmony_ci * @pi: the egress interface 11728c2ecf20Sopenharmony_ci * @pidx: index of the first Tx descriptor to write 11738c2ecf20Sopenharmony_ci * @gen: the generation value to use 11748c2ecf20Sopenharmony_ci * @q: the Tx queue 11758c2ecf20Sopenharmony_ci * @ndesc: number of descriptors the packet will occupy 11768c2ecf20Sopenharmony_ci * @compl: the value of the COMPL bit to use 11778c2ecf20Sopenharmony_ci * @addr: address 11788c2ecf20Sopenharmony_ci * 11798c2ecf20Sopenharmony_ci * Generate a TX_PKT work request to send the supplied packet. 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_cistatic void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, 11828c2ecf20Sopenharmony_ci const struct port_info *pi, 11838c2ecf20Sopenharmony_ci unsigned int pidx, unsigned int gen, 11848c2ecf20Sopenharmony_ci struct sge_txq *q, unsigned int ndesc, 11858c2ecf20Sopenharmony_ci unsigned int compl, const dma_addr_t *addr) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci unsigned int flits, sgl_flits, cntrl, tso_info; 11888c2ecf20Sopenharmony_ci struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; 11898c2ecf20Sopenharmony_ci struct tx_desc *d = &q->desc[pidx]; 11908c2ecf20Sopenharmony_ci struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci cpl->len = htonl(skb->len); 11938c2ecf20Sopenharmony_ci cntrl = V_TXPKT_INTF(pi->port_id); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) 11968c2ecf20Sopenharmony_ci cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(skb_vlan_tag_get(skb)); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size); 11998c2ecf20Sopenharmony_ci if (tso_info) { 12008c2ecf20Sopenharmony_ci int eth_type; 12018c2ecf20Sopenharmony_ci struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci d->flit[2] = 0; 12048c2ecf20Sopenharmony_ci cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO); 12058c2ecf20Sopenharmony_ci hdr->cntrl = htonl(cntrl); 12068c2ecf20Sopenharmony_ci eth_type = skb_network_offset(skb) == ETH_HLEN ? 12078c2ecf20Sopenharmony_ci CPL_ETH_II : CPL_ETH_II_VLAN; 12088c2ecf20Sopenharmony_ci tso_info |= V_LSO_ETH_TYPE(eth_type) | 12098c2ecf20Sopenharmony_ci V_LSO_IPHDR_WORDS(ip_hdr(skb)->ihl) | 12108c2ecf20Sopenharmony_ci V_LSO_TCPHDR_WORDS(tcp_hdr(skb)->doff); 12118c2ecf20Sopenharmony_ci hdr->lso_info = htonl(tso_info); 12128c2ecf20Sopenharmony_ci flits = 3; 12138c2ecf20Sopenharmony_ci } else { 12148c2ecf20Sopenharmony_ci cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT); 12158c2ecf20Sopenharmony_ci cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */ 12168c2ecf20Sopenharmony_ci cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL); 12178c2ecf20Sopenharmony_ci cpl->cntrl = htonl(cntrl); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci if (skb->len <= WR_LEN - sizeof(*cpl)) { 12208c2ecf20Sopenharmony_ci q->sdesc[pidx].skb = NULL; 12218c2ecf20Sopenharmony_ci if (!skb->data_len) 12228c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, &d->flit[2], 12238c2ecf20Sopenharmony_ci skb->len); 12248c2ecf20Sopenharmony_ci else 12258c2ecf20Sopenharmony_ci skb_copy_bits(skb, 0, &d->flit[2], skb->len); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci flits = (skb->len + 7) / 8 + 2; 12288c2ecf20Sopenharmony_ci cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) | 12298c2ecf20Sopenharmony_ci V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) 12308c2ecf20Sopenharmony_ci | F_WR_SOP | F_WR_EOP | compl); 12318c2ecf20Sopenharmony_ci dma_wmb(); 12328c2ecf20Sopenharmony_ci cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) | 12338c2ecf20Sopenharmony_ci V_WR_TID(q->token)); 12348c2ecf20Sopenharmony_ci wr_gen2(d, gen); 12358c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 12368c2ecf20Sopenharmony_ci return; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci flits = 2; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; 12438c2ecf20Sopenharmony_ci sgl_flits = write_sgl(skb, sgp, skb->data, skb_headlen(skb), addr); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, 12468c2ecf20Sopenharmony_ci htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), 12478c2ecf20Sopenharmony_ci htonl(V_WR_TID(q->token))); 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic inline void t3_stop_tx_queue(struct netdev_queue *txq, 12518c2ecf20Sopenharmony_ci struct sge_qset *qs, struct sge_txq *q) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci netif_tx_stop_queue(txq); 12548c2ecf20Sopenharmony_ci set_bit(TXQ_ETH, &qs->txq_stopped); 12558c2ecf20Sopenharmony_ci q->stops++; 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci/** 12598c2ecf20Sopenharmony_ci * eth_xmit - add a packet to the Ethernet Tx queue 12608c2ecf20Sopenharmony_ci * @skb: the packet 12618c2ecf20Sopenharmony_ci * @dev: the egress net device 12628c2ecf20Sopenharmony_ci * 12638c2ecf20Sopenharmony_ci * Add a packet to an SGE Tx queue. Runs with softirqs disabled. 12648c2ecf20Sopenharmony_ci */ 12658c2ecf20Sopenharmony_cinetdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci int qidx; 12688c2ecf20Sopenharmony_ci unsigned int ndesc, pidx, credits, gen, compl; 12698c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 12708c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 12718c2ecf20Sopenharmony_ci struct netdev_queue *txq; 12728c2ecf20Sopenharmony_ci struct sge_qset *qs; 12738c2ecf20Sopenharmony_ci struct sge_txq *q; 12748c2ecf20Sopenharmony_ci dma_addr_t addr[MAX_SKB_FRAGS + 1]; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci /* 12778c2ecf20Sopenharmony_ci * The chip min packet length is 9 octets but play safe and reject 12788c2ecf20Sopenharmony_ci * anything shorter than an Ethernet header. 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_ci if (unlikely(skb->len < ETH_HLEN)) { 12818c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 12828c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci qidx = skb_get_queue_mapping(skb); 12868c2ecf20Sopenharmony_ci qs = &pi->qs[qidx]; 12878c2ecf20Sopenharmony_ci q = &qs->txq[TXQ_ETH]; 12888c2ecf20Sopenharmony_ci txq = netdev_get_tx_queue(dev, qidx); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci credits = q->size - q->in_use; 12938c2ecf20Sopenharmony_ci ndesc = calc_tx_descs(skb); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (unlikely(credits < ndesc)) { 12968c2ecf20Sopenharmony_ci t3_stop_tx_queue(txq, qs, q); 12978c2ecf20Sopenharmony_ci dev_err(&adap->pdev->dev, 12988c2ecf20Sopenharmony_ci "%s: Tx ring %u full while queue awake!\n", 12998c2ecf20Sopenharmony_ci dev->name, q->cntxt_id & 7); 13008c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* Check if ethernet packet can't be sent as immediate data */ 13048c2ecf20Sopenharmony_ci if (skb->len > (WR_LEN - sizeof(struct cpl_tx_pkt))) { 13058c2ecf20Sopenharmony_ci if (unlikely(map_skb(adap->pdev, skb, addr) < 0)) { 13068c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 13078c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci q->in_use += ndesc; 13128c2ecf20Sopenharmony_ci if (unlikely(credits - ndesc < q->stop_thres)) { 13138c2ecf20Sopenharmony_ci t3_stop_tx_queue(txq, qs, q); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (should_restart_tx(q) && 13168c2ecf20Sopenharmony_ci test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { 13178c2ecf20Sopenharmony_ci q->restarts++; 13188c2ecf20Sopenharmony_ci netif_tx_start_queue(txq); 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci gen = q->gen; 13238c2ecf20Sopenharmony_ci q->unacked += ndesc; 13248c2ecf20Sopenharmony_ci compl = (q->unacked & 8) << (S_WR_COMPL - 3); 13258c2ecf20Sopenharmony_ci q->unacked &= 7; 13268c2ecf20Sopenharmony_ci pidx = q->pidx; 13278c2ecf20Sopenharmony_ci q->pidx += ndesc; 13288c2ecf20Sopenharmony_ci if (q->pidx >= q->size) { 13298c2ecf20Sopenharmony_ci q->pidx -= q->size; 13308c2ecf20Sopenharmony_ci q->gen ^= 1; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci /* update port statistics */ 13348c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 13358c2ecf20Sopenharmony_ci qs->port_stats[SGE_PSTAT_TX_CSUM]++; 13368c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_size) 13378c2ecf20Sopenharmony_ci qs->port_stats[SGE_PSTAT_TSO]++; 13388c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) 13398c2ecf20Sopenharmony_ci qs->port_stats[SGE_PSTAT_VLANINS]++; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* 13428c2ecf20Sopenharmony_ci * We do not use Tx completion interrupts to free DMAd Tx packets. 13438c2ecf20Sopenharmony_ci * This is good for performance but means that we rely on new Tx 13448c2ecf20Sopenharmony_ci * packets arriving to run the destructors of completed packets, 13458c2ecf20Sopenharmony_ci * which open up space in their sockets' send queues. Sometimes 13468c2ecf20Sopenharmony_ci * we do not get such new packets causing Tx to stall. A single 13478c2ecf20Sopenharmony_ci * UDP transmitter is a good example of this situation. We have 13488c2ecf20Sopenharmony_ci * a clean up timer that periodically reclaims completed packets 13498c2ecf20Sopenharmony_ci * but it doesn't run often enough (nor do we want it to) to prevent 13508c2ecf20Sopenharmony_ci * lengthy stalls. A solution to this problem is to run the 13518c2ecf20Sopenharmony_ci * destructor early, after the packet is queued but before it's DMAd. 13528c2ecf20Sopenharmony_ci * A cons is that we lie to socket memory accounting, but the amount 13538c2ecf20Sopenharmony_ci * of extra memory is reasonable (limited by the number of Tx 13548c2ecf20Sopenharmony_ci * descriptors), the packets do actually get freed quickly by new 13558c2ecf20Sopenharmony_ci * packets almost always, and for protocols like TCP that wait for 13568c2ecf20Sopenharmony_ci * acks to really free up the data the extra memory is even less. 13578c2ecf20Sopenharmony_ci * On the positive side we run the destructors on the sending CPU 13588c2ecf20Sopenharmony_ci * rather than on a potentially different completing CPU, usually a 13598c2ecf20Sopenharmony_ci * good thing. We also run them without holding our Tx queue lock, 13608c2ecf20Sopenharmony_ci * unlike what reclaim_completed_tx() would otherwise do. 13618c2ecf20Sopenharmony_ci * 13628c2ecf20Sopenharmony_ci * Run the destructor before telling the DMA engine about the packet 13638c2ecf20Sopenharmony_ci * to make sure it doesn't complete and get freed prematurely. 13648c2ecf20Sopenharmony_ci */ 13658c2ecf20Sopenharmony_ci if (likely(!skb_shared(skb))) 13668c2ecf20Sopenharmony_ci skb_orphan(skb); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl, addr); 13698c2ecf20Sopenharmony_ci check_ring_tx_db(adap, q); 13708c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci/** 13748c2ecf20Sopenharmony_ci * write_imm - write a packet into a Tx descriptor as immediate data 13758c2ecf20Sopenharmony_ci * @d: the Tx descriptor to write 13768c2ecf20Sopenharmony_ci * @skb: the packet 13778c2ecf20Sopenharmony_ci * @len: the length of packet data to write as immediate data 13788c2ecf20Sopenharmony_ci * @gen: the generation bit value to write 13798c2ecf20Sopenharmony_ci * 13808c2ecf20Sopenharmony_ci * Writes a packet as immediate data into a Tx descriptor. The packet 13818c2ecf20Sopenharmony_ci * contains a work request at its beginning. We must write the packet 13828c2ecf20Sopenharmony_ci * carefully so the SGE doesn't read it accidentally before it's written 13838c2ecf20Sopenharmony_ci * in its entirety. 13848c2ecf20Sopenharmony_ci */ 13858c2ecf20Sopenharmony_cistatic inline void write_imm(struct tx_desc *d, struct sk_buff *skb, 13868c2ecf20Sopenharmony_ci unsigned int len, unsigned int gen) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct work_request_hdr *from = (struct work_request_hdr *)skb->data; 13898c2ecf20Sopenharmony_ci struct work_request_hdr *to = (struct work_request_hdr *)d; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (likely(!skb->data_len)) 13928c2ecf20Sopenharmony_ci memcpy(&to[1], &from[1], len - sizeof(*from)); 13938c2ecf20Sopenharmony_ci else 13948c2ecf20Sopenharmony_ci skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from)); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | 13978c2ecf20Sopenharmony_ci V_WR_BCNTLFLT(len & 7)); 13988c2ecf20Sopenharmony_ci dma_wmb(); 13998c2ecf20Sopenharmony_ci to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) | 14008c2ecf20Sopenharmony_ci V_WR_LEN((len + 7) / 8)); 14018c2ecf20Sopenharmony_ci wr_gen2(d, gen); 14028c2ecf20Sopenharmony_ci kfree_skb(skb); 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci/** 14068c2ecf20Sopenharmony_ci * check_desc_avail - check descriptor availability on a send queue 14078c2ecf20Sopenharmony_ci * @adap: the adapter 14088c2ecf20Sopenharmony_ci * @q: the send queue 14098c2ecf20Sopenharmony_ci * @skb: the packet needing the descriptors 14108c2ecf20Sopenharmony_ci * @ndesc: the number of Tx descriptors needed 14118c2ecf20Sopenharmony_ci * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL) 14128c2ecf20Sopenharmony_ci * 14138c2ecf20Sopenharmony_ci * Checks if the requested number of Tx descriptors is available on an 14148c2ecf20Sopenharmony_ci * SGE send queue. If the queue is already suspended or not enough 14158c2ecf20Sopenharmony_ci * descriptors are available the packet is queued for later transmission. 14168c2ecf20Sopenharmony_ci * Must be called with the Tx queue locked. 14178c2ecf20Sopenharmony_ci * 14188c2ecf20Sopenharmony_ci * Returns 0 if enough descriptors are available, 1 if there aren't 14198c2ecf20Sopenharmony_ci * enough descriptors and the packet has been queued, and 2 if the caller 14208c2ecf20Sopenharmony_ci * needs to retry because there weren't enough descriptors at the 14218c2ecf20Sopenharmony_ci * beginning of the call but some freed up in the mean time. 14228c2ecf20Sopenharmony_ci */ 14238c2ecf20Sopenharmony_cistatic inline int check_desc_avail(struct adapter *adap, struct sge_txq *q, 14248c2ecf20Sopenharmony_ci struct sk_buff *skb, unsigned int ndesc, 14258c2ecf20Sopenharmony_ci unsigned int qid) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci if (unlikely(!skb_queue_empty(&q->sendq))) { 14288c2ecf20Sopenharmony_ci addq_exit:__skb_queue_tail(&q->sendq, skb); 14298c2ecf20Sopenharmony_ci return 1; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci if (unlikely(q->size - q->in_use < ndesc)) { 14328c2ecf20Sopenharmony_ci struct sge_qset *qs = txq_to_qset(q, qid); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci set_bit(qid, &qs->txq_stopped); 14358c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci if (should_restart_tx(q) && 14388c2ecf20Sopenharmony_ci test_and_clear_bit(qid, &qs->txq_stopped)) 14398c2ecf20Sopenharmony_ci return 2; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci q->stops++; 14428c2ecf20Sopenharmony_ci goto addq_exit; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci return 0; 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci/** 14488c2ecf20Sopenharmony_ci * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs 14498c2ecf20Sopenharmony_ci * @q: the SGE control Tx queue 14508c2ecf20Sopenharmony_ci * 14518c2ecf20Sopenharmony_ci * This is a variant of reclaim_completed_tx() that is used for Tx queues 14528c2ecf20Sopenharmony_ci * that send only immediate data (presently just the control queues) and 14538c2ecf20Sopenharmony_ci * thus do not have any sk_buffs to release. 14548c2ecf20Sopenharmony_ci */ 14558c2ecf20Sopenharmony_cistatic inline void reclaim_completed_tx_imm(struct sge_txq *q) 14568c2ecf20Sopenharmony_ci{ 14578c2ecf20Sopenharmony_ci unsigned int reclaim = q->processed - q->cleaned; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci q->in_use -= reclaim; 14608c2ecf20Sopenharmony_ci q->cleaned += reclaim; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic inline int immediate(const struct sk_buff *skb) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci return skb->len <= WR_LEN; 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci/** 14698c2ecf20Sopenharmony_ci * ctrl_xmit - send a packet through an SGE control Tx queue 14708c2ecf20Sopenharmony_ci * @adap: the adapter 14718c2ecf20Sopenharmony_ci * @q: the control queue 14728c2ecf20Sopenharmony_ci * @skb: the packet 14738c2ecf20Sopenharmony_ci * 14748c2ecf20Sopenharmony_ci * Send a packet through an SGE control Tx queue. Packets sent through 14758c2ecf20Sopenharmony_ci * a control queue must fit entirely as immediate data in a single Tx 14768c2ecf20Sopenharmony_ci * descriptor and have no page fragments. 14778c2ecf20Sopenharmony_ci */ 14788c2ecf20Sopenharmony_cistatic int ctrl_xmit(struct adapter *adap, struct sge_txq *q, 14798c2ecf20Sopenharmony_ci struct sk_buff *skb) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci int ret; 14828c2ecf20Sopenharmony_ci struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci if (unlikely(!immediate(skb))) { 14858c2ecf20Sopenharmony_ci WARN_ON(1); 14868c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 14878c2ecf20Sopenharmony_ci return NET_XMIT_SUCCESS; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP); 14918c2ecf20Sopenharmony_ci wrp->wr_lo = htonl(V_WR_TID(q->token)); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci spin_lock(&q->lock); 14948c2ecf20Sopenharmony_ci again:reclaim_completed_tx_imm(q); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL); 14978c2ecf20Sopenharmony_ci if (unlikely(ret)) { 14988c2ecf20Sopenharmony_ci if (ret == 1) { 14998c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 15008c2ecf20Sopenharmony_ci return NET_XMIT_CN; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci goto again; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci q->in_use++; 15088c2ecf20Sopenharmony_ci if (++q->pidx >= q->size) { 15098c2ecf20Sopenharmony_ci q->pidx = 0; 15108c2ecf20Sopenharmony_ci q->gen ^= 1; 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 15138c2ecf20Sopenharmony_ci wmb(); 15148c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, 15158c2ecf20Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 15168c2ecf20Sopenharmony_ci return NET_XMIT_SUCCESS; 15178c2ecf20Sopenharmony_ci} 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci/** 15208c2ecf20Sopenharmony_ci * restart_ctrlq - restart a suspended control queue 15218c2ecf20Sopenharmony_ci * @t: pointer to the tasklet associated with this handler 15228c2ecf20Sopenharmony_ci * 15238c2ecf20Sopenharmony_ci * Resumes transmission on a suspended Tx control queue. 15248c2ecf20Sopenharmony_ci */ 15258c2ecf20Sopenharmony_cistatic void restart_ctrlq(struct tasklet_struct *t) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci struct sk_buff *skb; 15288c2ecf20Sopenharmony_ci struct sge_qset *qs = from_tasklet(qs, t, txq[TXQ_CTRL].qresume_tsk); 15298c2ecf20Sopenharmony_ci struct sge_txq *q = &qs->txq[TXQ_CTRL]; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci spin_lock(&q->lock); 15328c2ecf20Sopenharmony_ci again:reclaim_completed_tx_imm(q); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci while (q->in_use < q->size && 15358c2ecf20Sopenharmony_ci (skb = __skb_dequeue(&q->sendq)) != NULL) { 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (++q->pidx >= q->size) { 15408c2ecf20Sopenharmony_ci q->pidx = 0; 15418c2ecf20Sopenharmony_ci q->gen ^= 1; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci q->in_use++; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci if (!skb_queue_empty(&q->sendq)) { 15478c2ecf20Sopenharmony_ci set_bit(TXQ_CTRL, &qs->txq_stopped); 15488c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if (should_restart_tx(q) && 15518c2ecf20Sopenharmony_ci test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) 15528c2ecf20Sopenharmony_ci goto again; 15538c2ecf20Sopenharmony_ci q->stops++; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 15578c2ecf20Sopenharmony_ci wmb(); 15588c2ecf20Sopenharmony_ci t3_write_reg(qs->adap, A_SG_KDOORBELL, 15598c2ecf20Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci/* 15638c2ecf20Sopenharmony_ci * Send a management message through control queue 0 15648c2ecf20Sopenharmony_ci */ 15658c2ecf20Sopenharmony_ciint t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci int ret; 15688c2ecf20Sopenharmony_ci local_bh_disable(); 15698c2ecf20Sopenharmony_ci ret = ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb); 15708c2ecf20Sopenharmony_ci local_bh_enable(); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci return ret; 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci/** 15768c2ecf20Sopenharmony_ci * deferred_unmap_destructor - unmap a packet when it is freed 15778c2ecf20Sopenharmony_ci * @skb: the packet 15788c2ecf20Sopenharmony_ci * 15798c2ecf20Sopenharmony_ci * This is the packet destructor used for Tx packets that need to remain 15808c2ecf20Sopenharmony_ci * mapped until they are freed rather than until their Tx descriptors are 15818c2ecf20Sopenharmony_ci * freed. 15828c2ecf20Sopenharmony_ci */ 15838c2ecf20Sopenharmony_cistatic void deferred_unmap_destructor(struct sk_buff *skb) 15848c2ecf20Sopenharmony_ci{ 15858c2ecf20Sopenharmony_ci int i; 15868c2ecf20Sopenharmony_ci const dma_addr_t *p; 15878c2ecf20Sopenharmony_ci const struct skb_shared_info *si; 15888c2ecf20Sopenharmony_ci const struct deferred_unmap_info *dui; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci dui = (struct deferred_unmap_info *)skb->head; 15918c2ecf20Sopenharmony_ci p = dui->addr; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (skb_tail_pointer(skb) - skb_transport_header(skb)) 15948c2ecf20Sopenharmony_ci pci_unmap_single(dui->pdev, *p++, skb_tail_pointer(skb) - 15958c2ecf20Sopenharmony_ci skb_transport_header(skb), PCI_DMA_TODEVICE); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci si = skb_shinfo(skb); 15988c2ecf20Sopenharmony_ci for (i = 0; i < si->nr_frags; i++) 15998c2ecf20Sopenharmony_ci pci_unmap_page(dui->pdev, *p++, skb_frag_size(&si->frags[i]), 16008c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 16018c2ecf20Sopenharmony_ci} 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_cistatic void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev, 16048c2ecf20Sopenharmony_ci const struct sg_ent *sgl, int sgl_flits) 16058c2ecf20Sopenharmony_ci{ 16068c2ecf20Sopenharmony_ci dma_addr_t *p; 16078c2ecf20Sopenharmony_ci struct deferred_unmap_info *dui; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci dui = (struct deferred_unmap_info *)skb->head; 16108c2ecf20Sopenharmony_ci dui->pdev = pdev; 16118c2ecf20Sopenharmony_ci for (p = dui->addr; sgl_flits >= 3; sgl++, sgl_flits -= 3) { 16128c2ecf20Sopenharmony_ci *p++ = be64_to_cpu(sgl->addr[0]); 16138c2ecf20Sopenharmony_ci *p++ = be64_to_cpu(sgl->addr[1]); 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci if (sgl_flits) 16168c2ecf20Sopenharmony_ci *p = be64_to_cpu(sgl->addr[0]); 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci/** 16208c2ecf20Sopenharmony_ci * write_ofld_wr - write an offload work request 16218c2ecf20Sopenharmony_ci * @adap: the adapter 16228c2ecf20Sopenharmony_ci * @skb: the packet to send 16238c2ecf20Sopenharmony_ci * @q: the Tx queue 16248c2ecf20Sopenharmony_ci * @pidx: index of the first Tx descriptor to write 16258c2ecf20Sopenharmony_ci * @gen: the generation value to use 16268c2ecf20Sopenharmony_ci * @ndesc: number of descriptors the packet will occupy 16278c2ecf20Sopenharmony_ci * @addr: the address 16288c2ecf20Sopenharmony_ci * 16298c2ecf20Sopenharmony_ci * Write an offload work request to send the supplied packet. The packet 16308c2ecf20Sopenharmony_ci * data already carry the work request with most fields populated. 16318c2ecf20Sopenharmony_ci */ 16328c2ecf20Sopenharmony_cistatic void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, 16338c2ecf20Sopenharmony_ci struct sge_txq *q, unsigned int pidx, 16348c2ecf20Sopenharmony_ci unsigned int gen, unsigned int ndesc, 16358c2ecf20Sopenharmony_ci const dma_addr_t *addr) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci unsigned int sgl_flits, flits; 16388c2ecf20Sopenharmony_ci struct work_request_hdr *from; 16398c2ecf20Sopenharmony_ci struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; 16408c2ecf20Sopenharmony_ci struct tx_desc *d = &q->desc[pidx]; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (immediate(skb)) { 16438c2ecf20Sopenharmony_ci q->sdesc[pidx].skb = NULL; 16448c2ecf20Sopenharmony_ci write_imm(d, skb, skb->len, gen); 16458c2ecf20Sopenharmony_ci return; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci /* Only TX_DATA builds SGLs */ 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci from = (struct work_request_hdr *)skb->data; 16518c2ecf20Sopenharmony_ci memcpy(&d->flit[1], &from[1], 16528c2ecf20Sopenharmony_ci skb_transport_offset(skb) - sizeof(*from)); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci flits = skb_transport_offset(skb) / 8; 16558c2ecf20Sopenharmony_ci sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; 16568c2ecf20Sopenharmony_ci sgl_flits = write_sgl(skb, sgp, skb_transport_header(skb), 16578c2ecf20Sopenharmony_ci skb_tail_pointer(skb) - skb_transport_header(skb), 16588c2ecf20Sopenharmony_ci addr); 16598c2ecf20Sopenharmony_ci if (need_skb_unmap()) { 16608c2ecf20Sopenharmony_ci setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); 16618c2ecf20Sopenharmony_ci skb->destructor = deferred_unmap_destructor; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, 16658c2ecf20Sopenharmony_ci gen, from->wr_hi, from->wr_lo); 16668c2ecf20Sopenharmony_ci} 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci/** 16698c2ecf20Sopenharmony_ci * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet 16708c2ecf20Sopenharmony_ci * @skb: the packet 16718c2ecf20Sopenharmony_ci * 16728c2ecf20Sopenharmony_ci * Returns the number of Tx descriptors needed for the given offload 16738c2ecf20Sopenharmony_ci * packet. These packets are already fully constructed. 16748c2ecf20Sopenharmony_ci */ 16758c2ecf20Sopenharmony_cistatic inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) 16768c2ecf20Sopenharmony_ci{ 16778c2ecf20Sopenharmony_ci unsigned int flits, cnt; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (skb->len <= WR_LEN) 16808c2ecf20Sopenharmony_ci return 1; /* packet fits as immediate data */ 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci flits = skb_transport_offset(skb) / 8; /* headers */ 16838c2ecf20Sopenharmony_ci cnt = skb_shinfo(skb)->nr_frags; 16848c2ecf20Sopenharmony_ci if (skb_tail_pointer(skb) != skb_transport_header(skb)) 16858c2ecf20Sopenharmony_ci cnt++; 16868c2ecf20Sopenharmony_ci return flits_to_desc(flits + sgl_len(cnt)); 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci/** 16908c2ecf20Sopenharmony_ci * ofld_xmit - send a packet through an offload queue 16918c2ecf20Sopenharmony_ci * @adap: the adapter 16928c2ecf20Sopenharmony_ci * @q: the Tx offload queue 16938c2ecf20Sopenharmony_ci * @skb: the packet 16948c2ecf20Sopenharmony_ci * 16958c2ecf20Sopenharmony_ci * Send an offload packet through an SGE offload queue. 16968c2ecf20Sopenharmony_ci */ 16978c2ecf20Sopenharmony_cistatic int ofld_xmit(struct adapter *adap, struct sge_txq *q, 16988c2ecf20Sopenharmony_ci struct sk_buff *skb) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci int ret; 17018c2ecf20Sopenharmony_ci unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci spin_lock(&q->lock); 17048c2ecf20Sopenharmony_ciagain: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD); 17078c2ecf20Sopenharmony_ci if (unlikely(ret)) { 17088c2ecf20Sopenharmony_ci if (ret == 1) { 17098c2ecf20Sopenharmony_ci skb->priority = ndesc; /* save for restart */ 17108c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 17118c2ecf20Sopenharmony_ci return NET_XMIT_CN; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci goto again; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci if (!immediate(skb) && 17178c2ecf20Sopenharmony_ci map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) { 17188c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 17198c2ecf20Sopenharmony_ci return NET_XMIT_SUCCESS; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci gen = q->gen; 17238c2ecf20Sopenharmony_ci q->in_use += ndesc; 17248c2ecf20Sopenharmony_ci pidx = q->pidx; 17258c2ecf20Sopenharmony_ci q->pidx += ndesc; 17268c2ecf20Sopenharmony_ci if (q->pidx >= q->size) { 17278c2ecf20Sopenharmony_ci q->pidx -= q->size; 17288c2ecf20Sopenharmony_ci q->gen ^= 1; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci write_ofld_wr(adap, skb, q, pidx, gen, ndesc, (dma_addr_t *)skb->head); 17338c2ecf20Sopenharmony_ci check_ring_tx_db(adap, q); 17348c2ecf20Sopenharmony_ci return NET_XMIT_SUCCESS; 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci/** 17388c2ecf20Sopenharmony_ci * restart_offloadq - restart a suspended offload queue 17398c2ecf20Sopenharmony_ci * @t: pointer to the tasklet associated with this handler 17408c2ecf20Sopenharmony_ci * 17418c2ecf20Sopenharmony_ci * Resumes transmission on a suspended Tx offload queue. 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_cistatic void restart_offloadq(struct tasklet_struct *t) 17448c2ecf20Sopenharmony_ci{ 17458c2ecf20Sopenharmony_ci struct sk_buff *skb; 17468c2ecf20Sopenharmony_ci struct sge_qset *qs = from_tasklet(qs, t, txq[TXQ_OFLD].qresume_tsk); 17478c2ecf20Sopenharmony_ci struct sge_txq *q = &qs->txq[TXQ_OFLD]; 17488c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(qs->netdev); 17498c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 17508c2ecf20Sopenharmony_ci unsigned int written = 0; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci spin_lock(&q->lock); 17538c2ecf20Sopenharmony_ciagain: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci while ((skb = skb_peek(&q->sendq)) != NULL) { 17568c2ecf20Sopenharmony_ci unsigned int gen, pidx; 17578c2ecf20Sopenharmony_ci unsigned int ndesc = skb->priority; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci if (unlikely(q->size - q->in_use < ndesc)) { 17608c2ecf20Sopenharmony_ci set_bit(TXQ_OFLD, &qs->txq_stopped); 17618c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci if (should_restart_tx(q) && 17648c2ecf20Sopenharmony_ci test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) 17658c2ecf20Sopenharmony_ci goto again; 17668c2ecf20Sopenharmony_ci q->stops++; 17678c2ecf20Sopenharmony_ci break; 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci if (!immediate(skb) && 17718c2ecf20Sopenharmony_ci map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) 17728c2ecf20Sopenharmony_ci break; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci gen = q->gen; 17758c2ecf20Sopenharmony_ci q->in_use += ndesc; 17768c2ecf20Sopenharmony_ci pidx = q->pidx; 17778c2ecf20Sopenharmony_ci q->pidx += ndesc; 17788c2ecf20Sopenharmony_ci written += ndesc; 17798c2ecf20Sopenharmony_ci if (q->pidx >= q->size) { 17808c2ecf20Sopenharmony_ci q->pidx -= q->size; 17818c2ecf20Sopenharmony_ci q->gen ^= 1; 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci __skb_unlink(skb, &q->sendq); 17848c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci write_ofld_wr(adap, skb, q, pidx, gen, ndesc, 17878c2ecf20Sopenharmony_ci (dma_addr_t *)skb->head); 17888c2ecf20Sopenharmony_ci spin_lock(&q->lock); 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci#if USE_GTS 17938c2ecf20Sopenharmony_ci set_bit(TXQ_RUNNING, &q->flags); 17948c2ecf20Sopenharmony_ci set_bit(TXQ_LAST_PKT_DB, &q->flags); 17958c2ecf20Sopenharmony_ci#endif 17968c2ecf20Sopenharmony_ci wmb(); 17978c2ecf20Sopenharmony_ci if (likely(written)) 17988c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, 17998c2ecf20Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 18008c2ecf20Sopenharmony_ci} 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci/** 18038c2ecf20Sopenharmony_ci * queue_set - return the queue set a packet should use 18048c2ecf20Sopenharmony_ci * @skb: the packet 18058c2ecf20Sopenharmony_ci * 18068c2ecf20Sopenharmony_ci * Maps a packet to the SGE queue set it should use. The desired queue 18078c2ecf20Sopenharmony_ci * set is carried in bits 1-3 in the packet's priority. 18088c2ecf20Sopenharmony_ci */ 18098c2ecf20Sopenharmony_cistatic inline int queue_set(const struct sk_buff *skb) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci return skb->priority >> 1; 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci/** 18158c2ecf20Sopenharmony_ci * is_ctrl_pkt - return whether an offload packet is a control packet 18168c2ecf20Sopenharmony_ci * @skb: the packet 18178c2ecf20Sopenharmony_ci * 18188c2ecf20Sopenharmony_ci * Determines whether an offload packet should use an OFLD or a CTRL 18198c2ecf20Sopenharmony_ci * Tx queue. This is indicated by bit 0 in the packet's priority. 18208c2ecf20Sopenharmony_ci */ 18218c2ecf20Sopenharmony_cistatic inline int is_ctrl_pkt(const struct sk_buff *skb) 18228c2ecf20Sopenharmony_ci{ 18238c2ecf20Sopenharmony_ci return skb->priority & 1; 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci/** 18278c2ecf20Sopenharmony_ci * t3_offload_tx - send an offload packet 18288c2ecf20Sopenharmony_ci * @tdev: the offload device to send to 18298c2ecf20Sopenharmony_ci * @skb: the packet 18308c2ecf20Sopenharmony_ci * 18318c2ecf20Sopenharmony_ci * Sends an offload packet. We use the packet priority to select the 18328c2ecf20Sopenharmony_ci * appropriate Tx queue as follows: bit 0 indicates whether the packet 18338c2ecf20Sopenharmony_ci * should be sent as regular or control, bits 1-3 select the queue set. 18348c2ecf20Sopenharmony_ci */ 18358c2ecf20Sopenharmony_ciint t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb) 18368c2ecf20Sopenharmony_ci{ 18378c2ecf20Sopenharmony_ci struct adapter *adap = tdev2adap(tdev); 18388c2ecf20Sopenharmony_ci struct sge_qset *qs = &adap->sge.qs[queue_set(skb)]; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (unlikely(is_ctrl_pkt(skb))) 18418c2ecf20Sopenharmony_ci return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb); 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb); 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci/** 18478c2ecf20Sopenharmony_ci * offload_enqueue - add an offload packet to an SGE offload receive queue 18488c2ecf20Sopenharmony_ci * @q: the SGE response queue 18498c2ecf20Sopenharmony_ci * @skb: the packet 18508c2ecf20Sopenharmony_ci * 18518c2ecf20Sopenharmony_ci * Add a new offload packet to an SGE response queue's offload packet 18528c2ecf20Sopenharmony_ci * queue. If the packet is the first on the queue it schedules the RX 18538c2ecf20Sopenharmony_ci * softirq to process the queue. 18548c2ecf20Sopenharmony_ci */ 18558c2ecf20Sopenharmony_cistatic inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) 18568c2ecf20Sopenharmony_ci{ 18578c2ecf20Sopenharmony_ci int was_empty = skb_queue_empty(&q->rx_queue); 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci __skb_queue_tail(&q->rx_queue, skb); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (was_empty) { 18628c2ecf20Sopenharmony_ci struct sge_qset *qs = rspq_to_qset(q); 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci napi_schedule(&qs->napi); 18658c2ecf20Sopenharmony_ci } 18668c2ecf20Sopenharmony_ci} 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci/** 18698c2ecf20Sopenharmony_ci * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts 18708c2ecf20Sopenharmony_ci * @tdev: the offload device that will be receiving the packets 18718c2ecf20Sopenharmony_ci * @q: the SGE response queue that assembled the bundle 18728c2ecf20Sopenharmony_ci * @skbs: the partial bundle 18738c2ecf20Sopenharmony_ci * @n: the number of packets in the bundle 18748c2ecf20Sopenharmony_ci * 18758c2ecf20Sopenharmony_ci * Delivers a (partial) bundle of Rx offload packets to an offload device. 18768c2ecf20Sopenharmony_ci */ 18778c2ecf20Sopenharmony_cistatic inline void deliver_partial_bundle(struct t3cdev *tdev, 18788c2ecf20Sopenharmony_ci struct sge_rspq *q, 18798c2ecf20Sopenharmony_ci struct sk_buff *skbs[], int n) 18808c2ecf20Sopenharmony_ci{ 18818c2ecf20Sopenharmony_ci if (n) { 18828c2ecf20Sopenharmony_ci q->offload_bundles++; 18838c2ecf20Sopenharmony_ci tdev->recv(tdev, skbs, n); 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci} 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci/** 18888c2ecf20Sopenharmony_ci * ofld_poll - NAPI handler for offload packets in interrupt mode 18898c2ecf20Sopenharmony_ci * @napi: the network device doing the polling 18908c2ecf20Sopenharmony_ci * @budget: polling budget 18918c2ecf20Sopenharmony_ci * 18928c2ecf20Sopenharmony_ci * The NAPI handler for offload packets when a response queue is serviced 18938c2ecf20Sopenharmony_ci * by the hard interrupt handler, i.e., when it's operating in non-polling 18948c2ecf20Sopenharmony_ci * mode. Creates small packet batches and sends them through the offload 18958c2ecf20Sopenharmony_ci * receive handler. Batches need to be of modest size as we do prefetches 18968c2ecf20Sopenharmony_ci * on the packets in each. 18978c2ecf20Sopenharmony_ci */ 18988c2ecf20Sopenharmony_cistatic int ofld_poll(struct napi_struct *napi, int budget) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci struct sge_qset *qs = container_of(napi, struct sge_qset, napi); 19018c2ecf20Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 19028c2ecf20Sopenharmony_ci struct adapter *adapter = qs->adap; 19038c2ecf20Sopenharmony_ci int work_done = 0; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci while (work_done < budget) { 19068c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp, *skbs[RX_BUNDLE_SIZE]; 19078c2ecf20Sopenharmony_ci struct sk_buff_head queue; 19088c2ecf20Sopenharmony_ci int ngathered; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci spin_lock_irq(&q->lock); 19118c2ecf20Sopenharmony_ci __skb_queue_head_init(&queue); 19128c2ecf20Sopenharmony_ci skb_queue_splice_init(&q->rx_queue, &queue); 19138c2ecf20Sopenharmony_ci if (skb_queue_empty(&queue)) { 19148c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 19158c2ecf20Sopenharmony_ci spin_unlock_irq(&q->lock); 19168c2ecf20Sopenharmony_ci return work_done; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci spin_unlock_irq(&q->lock); 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci ngathered = 0; 19218c2ecf20Sopenharmony_ci skb_queue_walk_safe(&queue, skb, tmp) { 19228c2ecf20Sopenharmony_ci if (work_done >= budget) 19238c2ecf20Sopenharmony_ci break; 19248c2ecf20Sopenharmony_ci work_done++; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci __skb_unlink(skb, &queue); 19278c2ecf20Sopenharmony_ci prefetch(skb->data); 19288c2ecf20Sopenharmony_ci skbs[ngathered] = skb; 19298c2ecf20Sopenharmony_ci if (++ngathered == RX_BUNDLE_SIZE) { 19308c2ecf20Sopenharmony_ci q->offload_bundles++; 19318c2ecf20Sopenharmony_ci adapter->tdev.recv(&adapter->tdev, skbs, 19328c2ecf20Sopenharmony_ci ngathered); 19338c2ecf20Sopenharmony_ci ngathered = 0; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci } 19368c2ecf20Sopenharmony_ci if (!skb_queue_empty(&queue)) { 19378c2ecf20Sopenharmony_ci /* splice remaining packets back onto Rx queue */ 19388c2ecf20Sopenharmony_ci spin_lock_irq(&q->lock); 19398c2ecf20Sopenharmony_ci skb_queue_splice(&queue, &q->rx_queue); 19408c2ecf20Sopenharmony_ci spin_unlock_irq(&q->lock); 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci return work_done; 19468c2ecf20Sopenharmony_ci} 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci/** 19498c2ecf20Sopenharmony_ci * rx_offload - process a received offload packet 19508c2ecf20Sopenharmony_ci * @tdev: the offload device receiving the packet 19518c2ecf20Sopenharmony_ci * @rq: the response queue that received the packet 19528c2ecf20Sopenharmony_ci * @skb: the packet 19538c2ecf20Sopenharmony_ci * @rx_gather: a gather list of packets if we are building a bundle 19548c2ecf20Sopenharmony_ci * @gather_idx: index of the next available slot in the bundle 19558c2ecf20Sopenharmony_ci * 19568c2ecf20Sopenharmony_ci * Process an ingress offload pakcet and add it to the offload ingress 19578c2ecf20Sopenharmony_ci * queue. Returns the index of the next available slot in the bundle. 19588c2ecf20Sopenharmony_ci */ 19598c2ecf20Sopenharmony_cistatic inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq, 19608c2ecf20Sopenharmony_ci struct sk_buff *skb, struct sk_buff *rx_gather[], 19618c2ecf20Sopenharmony_ci unsigned int gather_idx) 19628c2ecf20Sopenharmony_ci{ 19638c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 19648c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 19658c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (rq->polling) { 19688c2ecf20Sopenharmony_ci rx_gather[gather_idx++] = skb; 19698c2ecf20Sopenharmony_ci if (gather_idx == RX_BUNDLE_SIZE) { 19708c2ecf20Sopenharmony_ci tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE); 19718c2ecf20Sopenharmony_ci gather_idx = 0; 19728c2ecf20Sopenharmony_ci rq->offload_bundles++; 19738c2ecf20Sopenharmony_ci } 19748c2ecf20Sopenharmony_ci } else 19758c2ecf20Sopenharmony_ci offload_enqueue(rq, skb); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci return gather_idx; 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci/** 19818c2ecf20Sopenharmony_ci * restart_tx - check whether to restart suspended Tx queues 19828c2ecf20Sopenharmony_ci * @qs: the queue set to resume 19838c2ecf20Sopenharmony_ci * 19848c2ecf20Sopenharmony_ci * Restarts suspended Tx queues of an SGE queue set if they have enough 19858c2ecf20Sopenharmony_ci * free resources to resume operation. 19868c2ecf20Sopenharmony_ci */ 19878c2ecf20Sopenharmony_cistatic void restart_tx(struct sge_qset *qs) 19888c2ecf20Sopenharmony_ci{ 19898c2ecf20Sopenharmony_ci if (test_bit(TXQ_ETH, &qs->txq_stopped) && 19908c2ecf20Sopenharmony_ci should_restart_tx(&qs->txq[TXQ_ETH]) && 19918c2ecf20Sopenharmony_ci test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { 19928c2ecf20Sopenharmony_ci qs->txq[TXQ_ETH].restarts++; 19938c2ecf20Sopenharmony_ci if (netif_running(qs->netdev)) 19948c2ecf20Sopenharmony_ci netif_tx_wake_queue(qs->tx_q); 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci if (test_bit(TXQ_OFLD, &qs->txq_stopped) && 19988c2ecf20Sopenharmony_ci should_restart_tx(&qs->txq[TXQ_OFLD]) && 19998c2ecf20Sopenharmony_ci test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) { 20008c2ecf20Sopenharmony_ci qs->txq[TXQ_OFLD].restarts++; 20018c2ecf20Sopenharmony_ci tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk); 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci if (test_bit(TXQ_CTRL, &qs->txq_stopped) && 20048c2ecf20Sopenharmony_ci should_restart_tx(&qs->txq[TXQ_CTRL]) && 20058c2ecf20Sopenharmony_ci test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) { 20068c2ecf20Sopenharmony_ci qs->txq[TXQ_CTRL].restarts++; 20078c2ecf20Sopenharmony_ci tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk); 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci/** 20128c2ecf20Sopenharmony_ci * cxgb3_arp_process - process an ARP request probing a private IP address 20138c2ecf20Sopenharmony_ci * @pi: the port info 20148c2ecf20Sopenharmony_ci * @skb: the skbuff containing the ARP request 20158c2ecf20Sopenharmony_ci * 20168c2ecf20Sopenharmony_ci * Check if the ARP request is probing the private IP address 20178c2ecf20Sopenharmony_ci * dedicated to iSCSI, generate an ARP reply if so. 20188c2ecf20Sopenharmony_ci */ 20198c2ecf20Sopenharmony_cistatic void cxgb3_arp_process(struct port_info *pi, struct sk_buff *skb) 20208c2ecf20Sopenharmony_ci{ 20218c2ecf20Sopenharmony_ci struct net_device *dev = skb->dev; 20228c2ecf20Sopenharmony_ci struct arphdr *arp; 20238c2ecf20Sopenharmony_ci unsigned char *arp_ptr; 20248c2ecf20Sopenharmony_ci unsigned char *sha; 20258c2ecf20Sopenharmony_ci __be32 sip, tip; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (!dev) 20288c2ecf20Sopenharmony_ci return; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 20318c2ecf20Sopenharmony_ci arp = arp_hdr(skb); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci if (arp->ar_op != htons(ARPOP_REQUEST)) 20348c2ecf20Sopenharmony_ci return; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci arp_ptr = (unsigned char *)(arp + 1); 20378c2ecf20Sopenharmony_ci sha = arp_ptr; 20388c2ecf20Sopenharmony_ci arp_ptr += dev->addr_len; 20398c2ecf20Sopenharmony_ci memcpy(&sip, arp_ptr, sizeof(sip)); 20408c2ecf20Sopenharmony_ci arp_ptr += sizeof(sip); 20418c2ecf20Sopenharmony_ci arp_ptr += dev->addr_len; 20428c2ecf20Sopenharmony_ci memcpy(&tip, arp_ptr, sizeof(tip)); 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci if (tip != pi->iscsi_ipv4addr) 20458c2ecf20Sopenharmony_ci return; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, 20488c2ecf20Sopenharmony_ci pi->iscsic.mac_addr, sha); 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci} 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_cistatic inline int is_arp(struct sk_buff *skb) 20538c2ecf20Sopenharmony_ci{ 20548c2ecf20Sopenharmony_ci return skb->protocol == htons(ETH_P_ARP); 20558c2ecf20Sopenharmony_ci} 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_cistatic void cxgb3_process_iscsi_prov_pack(struct port_info *pi, 20588c2ecf20Sopenharmony_ci struct sk_buff *skb) 20598c2ecf20Sopenharmony_ci{ 20608c2ecf20Sopenharmony_ci if (is_arp(skb)) { 20618c2ecf20Sopenharmony_ci cxgb3_arp_process(pi, skb); 20628c2ecf20Sopenharmony_ci return; 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci if (pi->iscsic.recv) 20668c2ecf20Sopenharmony_ci pi->iscsic.recv(pi, skb); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci/** 20718c2ecf20Sopenharmony_ci * rx_eth - process an ingress ethernet packet 20728c2ecf20Sopenharmony_ci * @adap: the adapter 20738c2ecf20Sopenharmony_ci * @rq: the response queue that received the packet 20748c2ecf20Sopenharmony_ci * @skb: the packet 20758c2ecf20Sopenharmony_ci * @pad: padding 20768c2ecf20Sopenharmony_ci * @lro: large receive offload 20778c2ecf20Sopenharmony_ci * 20788c2ecf20Sopenharmony_ci * Process an ingress ethernet pakcet and deliver it to the stack. 20798c2ecf20Sopenharmony_ci * The padding is 2 if the packet was delivered in an Rx buffer and 0 20808c2ecf20Sopenharmony_ci * if it was immediate data in a response. 20818c2ecf20Sopenharmony_ci */ 20828c2ecf20Sopenharmony_cistatic void rx_eth(struct adapter *adap, struct sge_rspq *rq, 20838c2ecf20Sopenharmony_ci struct sk_buff *skb, int pad, int lro) 20848c2ecf20Sopenharmony_ci{ 20858c2ecf20Sopenharmony_ci struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); 20868c2ecf20Sopenharmony_ci struct sge_qset *qs = rspq_to_qset(rq); 20878c2ecf20Sopenharmony_ci struct port_info *pi; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*p) + pad); 20908c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, adap->port[p->iff]); 20918c2ecf20Sopenharmony_ci pi = netdev_priv(skb->dev); 20928c2ecf20Sopenharmony_ci if ((skb->dev->features & NETIF_F_RXCSUM) && p->csum_valid && 20938c2ecf20Sopenharmony_ci p->csum == htons(0xffff) && !p->fragment) { 20948c2ecf20Sopenharmony_ci qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; 20958c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 20968c2ecf20Sopenharmony_ci } else 20978c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 20988c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci if (p->vlan_valid) { 21018c2ecf20Sopenharmony_ci qs->port_stats[SGE_PSTAT_VLANEX]++; 21028c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(p->vlan)); 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci if (rq->polling) { 21058c2ecf20Sopenharmony_ci if (lro) 21068c2ecf20Sopenharmony_ci napi_gro_receive(&qs->napi, skb); 21078c2ecf20Sopenharmony_ci else { 21088c2ecf20Sopenharmony_ci if (unlikely(pi->iscsic.flags)) 21098c2ecf20Sopenharmony_ci cxgb3_process_iscsi_prov_pack(pi, skb); 21108c2ecf20Sopenharmony_ci netif_receive_skb(skb); 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci } else 21138c2ecf20Sopenharmony_ci netif_rx(skb); 21148c2ecf20Sopenharmony_ci} 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_cistatic inline int is_eth_tcp(u32 rss) 21178c2ecf20Sopenharmony_ci{ 21188c2ecf20Sopenharmony_ci return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE; 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci/** 21228c2ecf20Sopenharmony_ci * lro_add_page - add a page chunk to an LRO session 21238c2ecf20Sopenharmony_ci * @adap: the adapter 21248c2ecf20Sopenharmony_ci * @qs: the associated queue set 21258c2ecf20Sopenharmony_ci * @fl: the free list containing the page chunk to add 21268c2ecf20Sopenharmony_ci * @len: packet length 21278c2ecf20Sopenharmony_ci * @complete: Indicates the last fragment of a frame 21288c2ecf20Sopenharmony_ci * 21298c2ecf20Sopenharmony_ci * Add a received packet contained in a page chunk to an existing LRO 21308c2ecf20Sopenharmony_ci * session. 21318c2ecf20Sopenharmony_ci */ 21328c2ecf20Sopenharmony_cistatic void lro_add_page(struct adapter *adap, struct sge_qset *qs, 21338c2ecf20Sopenharmony_ci struct sge_fl *fl, int len, int complete) 21348c2ecf20Sopenharmony_ci{ 21358c2ecf20Sopenharmony_ci struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; 21368c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(qs->netdev); 21378c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 21388c2ecf20Sopenharmony_ci struct cpl_rx_pkt *cpl; 21398c2ecf20Sopenharmony_ci skb_frag_t *rx_frag; 21408c2ecf20Sopenharmony_ci int nr_frags; 21418c2ecf20Sopenharmony_ci int offset = 0; 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci if (!qs->nomem) { 21448c2ecf20Sopenharmony_ci skb = napi_get_frags(&qs->napi); 21458c2ecf20Sopenharmony_ci qs->nomem = !skb; 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci fl->credits--; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci pci_dma_sync_single_for_cpu(adap->pdev, 21518c2ecf20Sopenharmony_ci dma_unmap_addr(sd, dma_addr), 21528c2ecf20Sopenharmony_ci fl->buf_size - SGE_PG_RSVD, 21538c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci (*sd->pg_chunk.p_cnt)--; 21568c2ecf20Sopenharmony_ci if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) 21578c2ecf20Sopenharmony_ci pci_unmap_page(adap->pdev, 21588c2ecf20Sopenharmony_ci sd->pg_chunk.mapping, 21598c2ecf20Sopenharmony_ci fl->alloc_size, 21608c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci if (!skb) { 21638c2ecf20Sopenharmony_ci put_page(sd->pg_chunk.page); 21648c2ecf20Sopenharmony_ci if (complete) 21658c2ecf20Sopenharmony_ci qs->nomem = 0; 21668c2ecf20Sopenharmony_ci return; 21678c2ecf20Sopenharmony_ci } 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci rx_frag = skb_shinfo(skb)->frags; 21708c2ecf20Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci if (!nr_frags) { 21738c2ecf20Sopenharmony_ci offset = 2 + sizeof(struct cpl_rx_pkt); 21748c2ecf20Sopenharmony_ci cpl = qs->lro_va = sd->pg_chunk.va + 2; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci if ((qs->netdev->features & NETIF_F_RXCSUM) && 21778c2ecf20Sopenharmony_ci cpl->csum_valid && cpl->csum == htons(0xffff)) { 21788c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 21798c2ecf20Sopenharmony_ci qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; 21808c2ecf20Sopenharmony_ci } else 21818c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 21828c2ecf20Sopenharmony_ci } else 21838c2ecf20Sopenharmony_ci cpl = qs->lro_va; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci len -= offset; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci rx_frag += nr_frags; 21888c2ecf20Sopenharmony_ci __skb_frag_set_page(rx_frag, sd->pg_chunk.page); 21898c2ecf20Sopenharmony_ci skb_frag_off_set(rx_frag, sd->pg_chunk.offset + offset); 21908c2ecf20Sopenharmony_ci skb_frag_size_set(rx_frag, len); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci skb->len += len; 21938c2ecf20Sopenharmony_ci skb->data_len += len; 21948c2ecf20Sopenharmony_ci skb->truesize += len; 21958c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags++; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci if (!complete) 21988c2ecf20Sopenharmony_ci return; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci if (cpl->vlan_valid) { 22038c2ecf20Sopenharmony_ci qs->port_stats[SGE_PSTAT_VLANEX]++; 22048c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cpl->vlan)); 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci napi_gro_frags(&qs->napi); 22078c2ecf20Sopenharmony_ci} 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci/** 22108c2ecf20Sopenharmony_ci * handle_rsp_cntrl_info - handles control information in a response 22118c2ecf20Sopenharmony_ci * @qs: the queue set corresponding to the response 22128c2ecf20Sopenharmony_ci * @flags: the response control flags 22138c2ecf20Sopenharmony_ci * 22148c2ecf20Sopenharmony_ci * Handles the control information of an SGE response, such as GTS 22158c2ecf20Sopenharmony_ci * indications and completion credits for the queue set's Tx queues. 22168c2ecf20Sopenharmony_ci * HW coalesces credits, we don't do any extra SW coalescing. 22178c2ecf20Sopenharmony_ci */ 22188c2ecf20Sopenharmony_cistatic inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags) 22198c2ecf20Sopenharmony_ci{ 22208c2ecf20Sopenharmony_ci unsigned int credits; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci#if USE_GTS 22238c2ecf20Sopenharmony_ci if (flags & F_RSPD_TXQ0_GTS) 22248c2ecf20Sopenharmony_ci clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags); 22258c2ecf20Sopenharmony_ci#endif 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci credits = G_RSPD_TXQ0_CR(flags); 22288c2ecf20Sopenharmony_ci if (credits) 22298c2ecf20Sopenharmony_ci qs->txq[TXQ_ETH].processed += credits; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci credits = G_RSPD_TXQ2_CR(flags); 22328c2ecf20Sopenharmony_ci if (credits) 22338c2ecf20Sopenharmony_ci qs->txq[TXQ_CTRL].processed += credits; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci# if USE_GTS 22368c2ecf20Sopenharmony_ci if (flags & F_RSPD_TXQ1_GTS) 22378c2ecf20Sopenharmony_ci clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags); 22388c2ecf20Sopenharmony_ci# endif 22398c2ecf20Sopenharmony_ci credits = G_RSPD_TXQ1_CR(flags); 22408c2ecf20Sopenharmony_ci if (credits) 22418c2ecf20Sopenharmony_ci qs->txq[TXQ_OFLD].processed += credits; 22428c2ecf20Sopenharmony_ci} 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci/** 22458c2ecf20Sopenharmony_ci * check_ring_db - check if we need to ring any doorbells 22468c2ecf20Sopenharmony_ci * @adap: the adapter 22478c2ecf20Sopenharmony_ci * @qs: the queue set whose Tx queues are to be examined 22488c2ecf20Sopenharmony_ci * @sleeping: indicates which Tx queue sent GTS 22498c2ecf20Sopenharmony_ci * 22508c2ecf20Sopenharmony_ci * Checks if some of a queue set's Tx queues need to ring their doorbells 22518c2ecf20Sopenharmony_ci * to resume transmission after idling while they still have unprocessed 22528c2ecf20Sopenharmony_ci * descriptors. 22538c2ecf20Sopenharmony_ci */ 22548c2ecf20Sopenharmony_cistatic void check_ring_db(struct adapter *adap, struct sge_qset *qs, 22558c2ecf20Sopenharmony_ci unsigned int sleeping) 22568c2ecf20Sopenharmony_ci{ 22578c2ecf20Sopenharmony_ci if (sleeping & F_RSPD_TXQ0_GTS) { 22588c2ecf20Sopenharmony_ci struct sge_txq *txq = &qs->txq[TXQ_ETH]; 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci if (txq->cleaned + txq->in_use != txq->processed && 22618c2ecf20Sopenharmony_ci !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { 22628c2ecf20Sopenharmony_ci set_bit(TXQ_RUNNING, &txq->flags); 22638c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | 22648c2ecf20Sopenharmony_ci V_EGRCNTX(txq->cntxt_id)); 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci } 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci if (sleeping & F_RSPD_TXQ1_GTS) { 22698c2ecf20Sopenharmony_ci struct sge_txq *txq = &qs->txq[TXQ_OFLD]; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci if (txq->cleaned + txq->in_use != txq->processed && 22728c2ecf20Sopenharmony_ci !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { 22738c2ecf20Sopenharmony_ci set_bit(TXQ_RUNNING, &txq->flags); 22748c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | 22758c2ecf20Sopenharmony_ci V_EGRCNTX(txq->cntxt_id)); 22768c2ecf20Sopenharmony_ci } 22778c2ecf20Sopenharmony_ci } 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci/** 22818c2ecf20Sopenharmony_ci * is_new_response - check if a response is newly written 22828c2ecf20Sopenharmony_ci * @r: the response descriptor 22838c2ecf20Sopenharmony_ci * @q: the response queue 22848c2ecf20Sopenharmony_ci * 22858c2ecf20Sopenharmony_ci * Returns true if a response descriptor contains a yet unprocessed 22868c2ecf20Sopenharmony_ci * response. 22878c2ecf20Sopenharmony_ci */ 22888c2ecf20Sopenharmony_cistatic inline int is_new_response(const struct rsp_desc *r, 22898c2ecf20Sopenharmony_ci const struct sge_rspq *q) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci return (r->intr_gen & F_RSPD_GEN2) == q->gen; 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_cistatic inline void clear_rspq_bufstate(struct sge_rspq * const q) 22958c2ecf20Sopenharmony_ci{ 22968c2ecf20Sopenharmony_ci q->pg_skb = NULL; 22978c2ecf20Sopenharmony_ci q->rx_recycle_buf = 0; 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) 23018c2ecf20Sopenharmony_ci#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ 23028c2ecf20Sopenharmony_ci V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ 23038c2ecf20Sopenharmony_ci V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \ 23048c2ecf20Sopenharmony_ci V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR)) 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */ 23078c2ecf20Sopenharmony_ci#define NOMEM_INTR_DELAY 2500 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci/** 23108c2ecf20Sopenharmony_ci * process_responses - process responses from an SGE response queue 23118c2ecf20Sopenharmony_ci * @adap: the adapter 23128c2ecf20Sopenharmony_ci * @qs: the queue set to which the response queue belongs 23138c2ecf20Sopenharmony_ci * @budget: how many responses can be processed in this round 23148c2ecf20Sopenharmony_ci * 23158c2ecf20Sopenharmony_ci * Process responses from an SGE response queue up to the supplied budget. 23168c2ecf20Sopenharmony_ci * Responses include received packets as well as credits and other events 23178c2ecf20Sopenharmony_ci * for the queues that belong to the response queue's queue set. 23188c2ecf20Sopenharmony_ci * A negative budget is effectively unlimited. 23198c2ecf20Sopenharmony_ci * 23208c2ecf20Sopenharmony_ci * Additionally choose the interrupt holdoff time for the next interrupt 23218c2ecf20Sopenharmony_ci * on this queue. If the system is under memory shortage use a fairly 23228c2ecf20Sopenharmony_ci * long delay to help recovery. 23238c2ecf20Sopenharmony_ci */ 23248c2ecf20Sopenharmony_cistatic int process_responses(struct adapter *adap, struct sge_qset *qs, 23258c2ecf20Sopenharmony_ci int budget) 23268c2ecf20Sopenharmony_ci{ 23278c2ecf20Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 23288c2ecf20Sopenharmony_ci struct rsp_desc *r = &q->desc[q->cidx]; 23298c2ecf20Sopenharmony_ci int budget_left = budget; 23308c2ecf20Sopenharmony_ci unsigned int sleeping = 0; 23318c2ecf20Sopenharmony_ci struct sk_buff *offload_skbs[RX_BUNDLE_SIZE]; 23328c2ecf20Sopenharmony_ci int ngathered = 0; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci q->next_holdoff = q->holdoff_tmr; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci while (likely(budget_left && is_new_response(r, q))) { 23378c2ecf20Sopenharmony_ci int packet_complete, eth, ethpad = 2; 23388c2ecf20Sopenharmony_ci int lro = !!(qs->netdev->features & NETIF_F_GRO); 23398c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 23408c2ecf20Sopenharmony_ci u32 len, flags; 23418c2ecf20Sopenharmony_ci __be32 rss_hi, rss_lo; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci dma_rmb(); 23448c2ecf20Sopenharmony_ci eth = r->rss_hdr.opcode == CPL_RX_PKT; 23458c2ecf20Sopenharmony_ci rss_hi = *(const __be32 *)r; 23468c2ecf20Sopenharmony_ci rss_lo = r->rss_hdr.rss_hash_val; 23478c2ecf20Sopenharmony_ci flags = ntohl(r->flags); 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) { 23508c2ecf20Sopenharmony_ci skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC); 23518c2ecf20Sopenharmony_ci if (!skb) 23528c2ecf20Sopenharmony_ci goto no_mem; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci __skb_put_data(skb, r, AN_PKT_SIZE); 23558c2ecf20Sopenharmony_ci skb->data[0] = CPL_ASYNC_NOTIF; 23568c2ecf20Sopenharmony_ci rss_hi = htonl(CPL_ASYNC_NOTIF << 24); 23578c2ecf20Sopenharmony_ci q->async_notif++; 23588c2ecf20Sopenharmony_ci } else if (flags & F_RSPD_IMM_DATA_VALID) { 23598c2ecf20Sopenharmony_ci skb = get_imm_packet(r); 23608c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 23618c2ecf20Sopenharmony_cino_mem: 23628c2ecf20Sopenharmony_ci q->next_holdoff = NOMEM_INTR_DELAY; 23638c2ecf20Sopenharmony_ci q->nomem++; 23648c2ecf20Sopenharmony_ci /* consume one credit since we tried */ 23658c2ecf20Sopenharmony_ci budget_left--; 23668c2ecf20Sopenharmony_ci break; 23678c2ecf20Sopenharmony_ci } 23688c2ecf20Sopenharmony_ci q->imm_data++; 23698c2ecf20Sopenharmony_ci ethpad = 0; 23708c2ecf20Sopenharmony_ci } else if ((len = ntohl(r->len_cq)) != 0) { 23718c2ecf20Sopenharmony_ci struct sge_fl *fl; 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci lro &= eth && is_eth_tcp(rss_hi); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; 23768c2ecf20Sopenharmony_ci if (fl->use_pages) { 23778c2ecf20Sopenharmony_ci void *addr = fl->sdesc[fl->cidx].pg_chunk.va; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci net_prefetch(addr); 23808c2ecf20Sopenharmony_ci __refill_fl(adap, fl); 23818c2ecf20Sopenharmony_ci if (lro > 0) { 23828c2ecf20Sopenharmony_ci lro_add_page(adap, qs, fl, 23838c2ecf20Sopenharmony_ci G_RSPD_LEN(len), 23848c2ecf20Sopenharmony_ci flags & F_RSPD_EOP); 23858c2ecf20Sopenharmony_ci goto next_fl; 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci skb = get_packet_pg(adap, fl, q, 23898c2ecf20Sopenharmony_ci G_RSPD_LEN(len), 23908c2ecf20Sopenharmony_ci eth ? 23918c2ecf20Sopenharmony_ci SGE_RX_DROP_THRES : 0); 23928c2ecf20Sopenharmony_ci q->pg_skb = skb; 23938c2ecf20Sopenharmony_ci } else 23948c2ecf20Sopenharmony_ci skb = get_packet(adap, fl, G_RSPD_LEN(len), 23958c2ecf20Sopenharmony_ci eth ? SGE_RX_DROP_THRES : 0); 23968c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 23978c2ecf20Sopenharmony_ci if (!eth) 23988c2ecf20Sopenharmony_ci goto no_mem; 23998c2ecf20Sopenharmony_ci q->rx_drops++; 24008c2ecf20Sopenharmony_ci } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT)) 24018c2ecf20Sopenharmony_ci __skb_pull(skb, 2); 24028c2ecf20Sopenharmony_cinext_fl: 24038c2ecf20Sopenharmony_ci if (++fl->cidx == fl->size) 24048c2ecf20Sopenharmony_ci fl->cidx = 0; 24058c2ecf20Sopenharmony_ci } else 24068c2ecf20Sopenharmony_ci q->pure_rsps++; 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci if (flags & RSPD_CTRL_MASK) { 24098c2ecf20Sopenharmony_ci sleeping |= flags & RSPD_GTS_MASK; 24108c2ecf20Sopenharmony_ci handle_rsp_cntrl_info(qs, flags); 24118c2ecf20Sopenharmony_ci } 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci r++; 24148c2ecf20Sopenharmony_ci if (unlikely(++q->cidx == q->size)) { 24158c2ecf20Sopenharmony_ci q->cidx = 0; 24168c2ecf20Sopenharmony_ci q->gen ^= 1; 24178c2ecf20Sopenharmony_ci r = q->desc; 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci prefetch(r); 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci if (++q->credits >= (q->size / 4)) { 24228c2ecf20Sopenharmony_ci refill_rspq(adap, q, q->credits); 24238c2ecf20Sopenharmony_ci q->credits = 0; 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci packet_complete = flags & 24278c2ecf20Sopenharmony_ci (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID | 24288c2ecf20Sopenharmony_ci F_RSPD_ASYNC_NOTIF); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (skb != NULL && packet_complete) { 24318c2ecf20Sopenharmony_ci if (eth) 24328c2ecf20Sopenharmony_ci rx_eth(adap, q, skb, ethpad, lro); 24338c2ecf20Sopenharmony_ci else { 24348c2ecf20Sopenharmony_ci q->offload_pkts++; 24358c2ecf20Sopenharmony_ci /* Preserve the RSS info in csum & priority */ 24368c2ecf20Sopenharmony_ci skb->csum = rss_hi; 24378c2ecf20Sopenharmony_ci skb->priority = rss_lo; 24388c2ecf20Sopenharmony_ci ngathered = rx_offload(&adap->tdev, q, skb, 24398c2ecf20Sopenharmony_ci offload_skbs, 24408c2ecf20Sopenharmony_ci ngathered); 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci if (flags & F_RSPD_EOP) 24448c2ecf20Sopenharmony_ci clear_rspq_bufstate(q); 24458c2ecf20Sopenharmony_ci } 24468c2ecf20Sopenharmony_ci --budget_left; 24478c2ecf20Sopenharmony_ci } 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered); 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci if (sleeping) 24528c2ecf20Sopenharmony_ci check_ring_db(adap, qs, sleeping); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci smp_mb(); /* commit Tx queue .processed updates */ 24558c2ecf20Sopenharmony_ci if (unlikely(qs->txq_stopped != 0)) 24568c2ecf20Sopenharmony_ci restart_tx(qs); 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci budget -= budget_left; 24598c2ecf20Sopenharmony_ci return budget; 24608c2ecf20Sopenharmony_ci} 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_cistatic inline int is_pure_response(const struct rsp_desc *r) 24638c2ecf20Sopenharmony_ci{ 24648c2ecf20Sopenharmony_ci __be32 n = r->flags & htonl(F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci return (n | r->len_cq) == 0; 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci/** 24708c2ecf20Sopenharmony_ci * napi_rx_handler - the NAPI handler for Rx processing 24718c2ecf20Sopenharmony_ci * @napi: the napi instance 24728c2ecf20Sopenharmony_ci * @budget: how many packets we can process in this round 24738c2ecf20Sopenharmony_ci * 24748c2ecf20Sopenharmony_ci * Handler for new data events when using NAPI. 24758c2ecf20Sopenharmony_ci */ 24768c2ecf20Sopenharmony_cistatic int napi_rx_handler(struct napi_struct *napi, int budget) 24778c2ecf20Sopenharmony_ci{ 24788c2ecf20Sopenharmony_ci struct sge_qset *qs = container_of(napi, struct sge_qset, napi); 24798c2ecf20Sopenharmony_ci struct adapter *adap = qs->adap; 24808c2ecf20Sopenharmony_ci int work_done = process_responses(adap, qs, budget); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci if (likely(work_done < budget)) { 24838c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci /* 24868c2ecf20Sopenharmony_ci * Because we don't atomically flush the following 24878c2ecf20Sopenharmony_ci * write it is possible that in very rare cases it can 24888c2ecf20Sopenharmony_ci * reach the device in a way that races with a new 24898c2ecf20Sopenharmony_ci * response being written plus an error interrupt 24908c2ecf20Sopenharmony_ci * causing the NAPI interrupt handler below to return 24918c2ecf20Sopenharmony_ci * unhandled status to the OS. To protect against 24928c2ecf20Sopenharmony_ci * this would require flushing the write and doing 24938c2ecf20Sopenharmony_ci * both the write and the flush with interrupts off. 24948c2ecf20Sopenharmony_ci * Way too expensive and unjustifiable given the 24958c2ecf20Sopenharmony_ci * rarity of the race. 24968c2ecf20Sopenharmony_ci * 24978c2ecf20Sopenharmony_ci * The race cannot happen at all with MSI-X. 24988c2ecf20Sopenharmony_ci */ 24998c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | 25008c2ecf20Sopenharmony_ci V_NEWTIMER(qs->rspq.next_holdoff) | 25018c2ecf20Sopenharmony_ci V_NEWINDEX(qs->rspq.cidx)); 25028c2ecf20Sopenharmony_ci } 25038c2ecf20Sopenharmony_ci return work_done; 25048c2ecf20Sopenharmony_ci} 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci/* 25078c2ecf20Sopenharmony_ci * Returns true if the device is already scheduled for polling. 25088c2ecf20Sopenharmony_ci */ 25098c2ecf20Sopenharmony_cistatic inline int napi_is_scheduled(struct napi_struct *napi) 25108c2ecf20Sopenharmony_ci{ 25118c2ecf20Sopenharmony_ci return test_bit(NAPI_STATE_SCHED, &napi->state); 25128c2ecf20Sopenharmony_ci} 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci/** 25158c2ecf20Sopenharmony_ci * process_pure_responses - process pure responses from a response queue 25168c2ecf20Sopenharmony_ci * @adap: the adapter 25178c2ecf20Sopenharmony_ci * @qs: the queue set owning the response queue 25188c2ecf20Sopenharmony_ci * @r: the first pure response to process 25198c2ecf20Sopenharmony_ci * 25208c2ecf20Sopenharmony_ci * A simpler version of process_responses() that handles only pure (i.e., 25218c2ecf20Sopenharmony_ci * non data-carrying) responses. Such respones are too light-weight to 25228c2ecf20Sopenharmony_ci * justify calling a softirq under NAPI, so we handle them specially in 25238c2ecf20Sopenharmony_ci * the interrupt handler. The function is called with a pointer to a 25248c2ecf20Sopenharmony_ci * response, which the caller must ensure is a valid pure response. 25258c2ecf20Sopenharmony_ci * 25268c2ecf20Sopenharmony_ci * Returns 1 if it encounters a valid data-carrying response, 0 otherwise. 25278c2ecf20Sopenharmony_ci */ 25288c2ecf20Sopenharmony_cistatic int process_pure_responses(struct adapter *adap, struct sge_qset *qs, 25298c2ecf20Sopenharmony_ci struct rsp_desc *r) 25308c2ecf20Sopenharmony_ci{ 25318c2ecf20Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 25328c2ecf20Sopenharmony_ci unsigned int sleeping = 0; 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci do { 25358c2ecf20Sopenharmony_ci u32 flags = ntohl(r->flags); 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci r++; 25388c2ecf20Sopenharmony_ci if (unlikely(++q->cidx == q->size)) { 25398c2ecf20Sopenharmony_ci q->cidx = 0; 25408c2ecf20Sopenharmony_ci q->gen ^= 1; 25418c2ecf20Sopenharmony_ci r = q->desc; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci prefetch(r); 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci if (flags & RSPD_CTRL_MASK) { 25468c2ecf20Sopenharmony_ci sleeping |= flags & RSPD_GTS_MASK; 25478c2ecf20Sopenharmony_ci handle_rsp_cntrl_info(qs, flags); 25488c2ecf20Sopenharmony_ci } 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci q->pure_rsps++; 25518c2ecf20Sopenharmony_ci if (++q->credits >= (q->size / 4)) { 25528c2ecf20Sopenharmony_ci refill_rspq(adap, q, q->credits); 25538c2ecf20Sopenharmony_ci q->credits = 0; 25548c2ecf20Sopenharmony_ci } 25558c2ecf20Sopenharmony_ci if (!is_new_response(r, q)) 25568c2ecf20Sopenharmony_ci break; 25578c2ecf20Sopenharmony_ci dma_rmb(); 25588c2ecf20Sopenharmony_ci } while (is_pure_response(r)); 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci if (sleeping) 25618c2ecf20Sopenharmony_ci check_ring_db(adap, qs, sleeping); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci smp_mb(); /* commit Tx queue .processed updates */ 25648c2ecf20Sopenharmony_ci if (unlikely(qs->txq_stopped != 0)) 25658c2ecf20Sopenharmony_ci restart_tx(qs); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci return is_new_response(r, q); 25688c2ecf20Sopenharmony_ci} 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci/** 25718c2ecf20Sopenharmony_ci * handle_responses - decide what to do with new responses in NAPI mode 25728c2ecf20Sopenharmony_ci * @adap: the adapter 25738c2ecf20Sopenharmony_ci * @q: the response queue 25748c2ecf20Sopenharmony_ci * 25758c2ecf20Sopenharmony_ci * This is used by the NAPI interrupt handlers to decide what to do with 25768c2ecf20Sopenharmony_ci * new SGE responses. If there are no new responses it returns -1. If 25778c2ecf20Sopenharmony_ci * there are new responses and they are pure (i.e., non-data carrying) 25788c2ecf20Sopenharmony_ci * it handles them straight in hard interrupt context as they are very 25798c2ecf20Sopenharmony_ci * cheap and don't deliver any packets. Finally, if there are any data 25808c2ecf20Sopenharmony_ci * signaling responses it schedules the NAPI handler. Returns 1 if it 25818c2ecf20Sopenharmony_ci * schedules NAPI, 0 if all new responses were pure. 25828c2ecf20Sopenharmony_ci * 25838c2ecf20Sopenharmony_ci * The caller must ascertain NAPI is not already running. 25848c2ecf20Sopenharmony_ci */ 25858c2ecf20Sopenharmony_cistatic inline int handle_responses(struct adapter *adap, struct sge_rspq *q) 25868c2ecf20Sopenharmony_ci{ 25878c2ecf20Sopenharmony_ci struct sge_qset *qs = rspq_to_qset(q); 25888c2ecf20Sopenharmony_ci struct rsp_desc *r = &q->desc[q->cidx]; 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci if (!is_new_response(r, q)) 25918c2ecf20Sopenharmony_ci return -1; 25928c2ecf20Sopenharmony_ci dma_rmb(); 25938c2ecf20Sopenharmony_ci if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { 25948c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | 25958c2ecf20Sopenharmony_ci V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); 25968c2ecf20Sopenharmony_ci return 0; 25978c2ecf20Sopenharmony_ci } 25988c2ecf20Sopenharmony_ci napi_schedule(&qs->napi); 25998c2ecf20Sopenharmony_ci return 1; 26008c2ecf20Sopenharmony_ci} 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci/* 26038c2ecf20Sopenharmony_ci * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case 26048c2ecf20Sopenharmony_ci * (i.e., response queue serviced in hard interrupt). 26058c2ecf20Sopenharmony_ci */ 26068c2ecf20Sopenharmony_cistatic irqreturn_t t3_sge_intr_msix(int irq, void *cookie) 26078c2ecf20Sopenharmony_ci{ 26088c2ecf20Sopenharmony_ci struct sge_qset *qs = cookie; 26098c2ecf20Sopenharmony_ci struct adapter *adap = qs->adap; 26108c2ecf20Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci spin_lock(&q->lock); 26138c2ecf20Sopenharmony_ci if (process_responses(adap, qs, -1) == 0) 26148c2ecf20Sopenharmony_ci q->unhandled_irqs++; 26158c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | 26168c2ecf20Sopenharmony_ci V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); 26178c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 26188c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26198c2ecf20Sopenharmony_ci} 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci/* 26228c2ecf20Sopenharmony_ci * The MSI-X interrupt handler for an SGE response queue for the NAPI case 26238c2ecf20Sopenharmony_ci * (i.e., response queue serviced by NAPI polling). 26248c2ecf20Sopenharmony_ci */ 26258c2ecf20Sopenharmony_cistatic irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) 26268c2ecf20Sopenharmony_ci{ 26278c2ecf20Sopenharmony_ci struct sge_qset *qs = cookie; 26288c2ecf20Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci spin_lock(&q->lock); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci if (handle_responses(qs->adap, q) < 0) 26338c2ecf20Sopenharmony_ci q->unhandled_irqs++; 26348c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 26358c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26368c2ecf20Sopenharmony_ci} 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci/* 26398c2ecf20Sopenharmony_ci * The non-NAPI MSI interrupt handler. This needs to handle data events from 26408c2ecf20Sopenharmony_ci * SGE response queues as well as error and other async events as they all use 26418c2ecf20Sopenharmony_ci * the same MSI vector. We use one SGE response queue per port in this mode 26428c2ecf20Sopenharmony_ci * and protect all response queues with queue 0's lock. 26438c2ecf20Sopenharmony_ci */ 26448c2ecf20Sopenharmony_cistatic irqreturn_t t3_intr_msi(int irq, void *cookie) 26458c2ecf20Sopenharmony_ci{ 26468c2ecf20Sopenharmony_ci int new_packets = 0; 26478c2ecf20Sopenharmony_ci struct adapter *adap = cookie; 26488c2ecf20Sopenharmony_ci struct sge_rspq *q = &adap->sge.qs[0].rspq; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci spin_lock(&q->lock); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci if (process_responses(adap, &adap->sge.qs[0], -1)) { 26538c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | 26548c2ecf20Sopenharmony_ci V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); 26558c2ecf20Sopenharmony_ci new_packets = 1; 26568c2ecf20Sopenharmony_ci } 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci if (adap->params.nports == 2 && 26598c2ecf20Sopenharmony_ci process_responses(adap, &adap->sge.qs[1], -1)) { 26608c2ecf20Sopenharmony_ci struct sge_rspq *q1 = &adap->sge.qs[1].rspq; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) | 26638c2ecf20Sopenharmony_ci V_NEWTIMER(q1->next_holdoff) | 26648c2ecf20Sopenharmony_ci V_NEWINDEX(q1->cidx)); 26658c2ecf20Sopenharmony_ci new_packets = 1; 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci if (!new_packets && t3_slow_intr_handler(adap) == 0) 26698c2ecf20Sopenharmony_ci q->unhandled_irqs++; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 26728c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26738c2ecf20Sopenharmony_ci} 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_cistatic int rspq_check_napi(struct sge_qset *qs) 26768c2ecf20Sopenharmony_ci{ 26778c2ecf20Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci if (!napi_is_scheduled(&qs->napi) && 26808c2ecf20Sopenharmony_ci is_new_response(&q->desc[q->cidx], q)) { 26818c2ecf20Sopenharmony_ci napi_schedule(&qs->napi); 26828c2ecf20Sopenharmony_ci return 1; 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci return 0; 26858c2ecf20Sopenharmony_ci} 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci/* 26888c2ecf20Sopenharmony_ci * The MSI interrupt handler for the NAPI case (i.e., response queues serviced 26898c2ecf20Sopenharmony_ci * by NAPI polling). Handles data events from SGE response queues as well as 26908c2ecf20Sopenharmony_ci * error and other async events as they all use the same MSI vector. We use 26918c2ecf20Sopenharmony_ci * one SGE response queue per port in this mode and protect all response 26928c2ecf20Sopenharmony_ci * queues with queue 0's lock. 26938c2ecf20Sopenharmony_ci */ 26948c2ecf20Sopenharmony_cistatic irqreturn_t t3_intr_msi_napi(int irq, void *cookie) 26958c2ecf20Sopenharmony_ci{ 26968c2ecf20Sopenharmony_ci int new_packets; 26978c2ecf20Sopenharmony_ci struct adapter *adap = cookie; 26988c2ecf20Sopenharmony_ci struct sge_rspq *q = &adap->sge.qs[0].rspq; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci spin_lock(&q->lock); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci new_packets = rspq_check_napi(&adap->sge.qs[0]); 27038c2ecf20Sopenharmony_ci if (adap->params.nports == 2) 27048c2ecf20Sopenharmony_ci new_packets += rspq_check_napi(&adap->sge.qs[1]); 27058c2ecf20Sopenharmony_ci if (!new_packets && t3_slow_intr_handler(adap) == 0) 27068c2ecf20Sopenharmony_ci q->unhandled_irqs++; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 27098c2ecf20Sopenharmony_ci return IRQ_HANDLED; 27108c2ecf20Sopenharmony_ci} 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci/* 27138c2ecf20Sopenharmony_ci * A helper function that processes responses and issues GTS. 27148c2ecf20Sopenharmony_ci */ 27158c2ecf20Sopenharmony_cistatic inline int process_responses_gts(struct adapter *adap, 27168c2ecf20Sopenharmony_ci struct sge_rspq *rq) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci int work; 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci work = process_responses(adap, rspq_to_qset(rq), -1); 27218c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) | 27228c2ecf20Sopenharmony_ci V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx)); 27238c2ecf20Sopenharmony_ci return work; 27248c2ecf20Sopenharmony_ci} 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci/* 27278c2ecf20Sopenharmony_ci * The legacy INTx interrupt handler. This needs to handle data events from 27288c2ecf20Sopenharmony_ci * SGE response queues as well as error and other async events as they all use 27298c2ecf20Sopenharmony_ci * the same interrupt pin. We use one SGE response queue per port in this mode 27308c2ecf20Sopenharmony_ci * and protect all response queues with queue 0's lock. 27318c2ecf20Sopenharmony_ci */ 27328c2ecf20Sopenharmony_cistatic irqreturn_t t3_intr(int irq, void *cookie) 27338c2ecf20Sopenharmony_ci{ 27348c2ecf20Sopenharmony_ci int work_done, w0, w1; 27358c2ecf20Sopenharmony_ci struct adapter *adap = cookie; 27368c2ecf20Sopenharmony_ci struct sge_rspq *q0 = &adap->sge.qs[0].rspq; 27378c2ecf20Sopenharmony_ci struct sge_rspq *q1 = &adap->sge.qs[1].rspq; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci spin_lock(&q0->lock); 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci w0 = is_new_response(&q0->desc[q0->cidx], q0); 27428c2ecf20Sopenharmony_ci w1 = adap->params.nports == 2 && 27438c2ecf20Sopenharmony_ci is_new_response(&q1->desc[q1->cidx], q1); 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci if (likely(w0 | w1)) { 27468c2ecf20Sopenharmony_ci t3_write_reg(adap, A_PL_CLI, 0); 27478c2ecf20Sopenharmony_ci t3_read_reg(adap, A_PL_CLI); /* flush */ 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci if (likely(w0)) 27508c2ecf20Sopenharmony_ci process_responses_gts(adap, q0); 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci if (w1) 27538c2ecf20Sopenharmony_ci process_responses_gts(adap, q1); 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci work_done = w0 | w1; 27568c2ecf20Sopenharmony_ci } else 27578c2ecf20Sopenharmony_ci work_done = t3_slow_intr_handler(adap); 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci spin_unlock(&q0->lock); 27608c2ecf20Sopenharmony_ci return IRQ_RETVAL(work_done != 0); 27618c2ecf20Sopenharmony_ci} 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci/* 27648c2ecf20Sopenharmony_ci * Interrupt handler for legacy INTx interrupts for T3B-based cards. 27658c2ecf20Sopenharmony_ci * Handles data events from SGE response queues as well as error and other 27668c2ecf20Sopenharmony_ci * async events as they all use the same interrupt pin. We use one SGE 27678c2ecf20Sopenharmony_ci * response queue per port in this mode and protect all response queues with 27688c2ecf20Sopenharmony_ci * queue 0's lock. 27698c2ecf20Sopenharmony_ci */ 27708c2ecf20Sopenharmony_cistatic irqreturn_t t3b_intr(int irq, void *cookie) 27718c2ecf20Sopenharmony_ci{ 27728c2ecf20Sopenharmony_ci u32 map; 27738c2ecf20Sopenharmony_ci struct adapter *adap = cookie; 27748c2ecf20Sopenharmony_ci struct sge_rspq *q0 = &adap->sge.qs[0].rspq; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci t3_write_reg(adap, A_PL_CLI, 0); 27778c2ecf20Sopenharmony_ci map = t3_read_reg(adap, A_SG_DATA_INTR); 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci if (unlikely(!map)) /* shared interrupt, most likely */ 27808c2ecf20Sopenharmony_ci return IRQ_NONE; 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci spin_lock(&q0->lock); 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (unlikely(map & F_ERRINTR)) 27858c2ecf20Sopenharmony_ci t3_slow_intr_handler(adap); 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci if (likely(map & 1)) 27888c2ecf20Sopenharmony_ci process_responses_gts(adap, q0); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (map & 2) 27918c2ecf20Sopenharmony_ci process_responses_gts(adap, &adap->sge.qs[1].rspq); 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci spin_unlock(&q0->lock); 27948c2ecf20Sopenharmony_ci return IRQ_HANDLED; 27958c2ecf20Sopenharmony_ci} 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci/* 27988c2ecf20Sopenharmony_ci * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards. 27998c2ecf20Sopenharmony_ci * Handles data events from SGE response queues as well as error and other 28008c2ecf20Sopenharmony_ci * async events as they all use the same interrupt pin. We use one SGE 28018c2ecf20Sopenharmony_ci * response queue per port in this mode and protect all response queues with 28028c2ecf20Sopenharmony_ci * queue 0's lock. 28038c2ecf20Sopenharmony_ci */ 28048c2ecf20Sopenharmony_cistatic irqreturn_t t3b_intr_napi(int irq, void *cookie) 28058c2ecf20Sopenharmony_ci{ 28068c2ecf20Sopenharmony_ci u32 map; 28078c2ecf20Sopenharmony_ci struct adapter *adap = cookie; 28088c2ecf20Sopenharmony_ci struct sge_qset *qs0 = &adap->sge.qs[0]; 28098c2ecf20Sopenharmony_ci struct sge_rspq *q0 = &qs0->rspq; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci t3_write_reg(adap, A_PL_CLI, 0); 28128c2ecf20Sopenharmony_ci map = t3_read_reg(adap, A_SG_DATA_INTR); 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci if (unlikely(!map)) /* shared interrupt, most likely */ 28158c2ecf20Sopenharmony_ci return IRQ_NONE; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci spin_lock(&q0->lock); 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci if (unlikely(map & F_ERRINTR)) 28208c2ecf20Sopenharmony_ci t3_slow_intr_handler(adap); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci if (likely(map & 1)) 28238c2ecf20Sopenharmony_ci napi_schedule(&qs0->napi); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci if (map & 2) 28268c2ecf20Sopenharmony_ci napi_schedule(&adap->sge.qs[1].napi); 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci spin_unlock(&q0->lock); 28298c2ecf20Sopenharmony_ci return IRQ_HANDLED; 28308c2ecf20Sopenharmony_ci} 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci/** 28338c2ecf20Sopenharmony_ci * t3_intr_handler - select the top-level interrupt handler 28348c2ecf20Sopenharmony_ci * @adap: the adapter 28358c2ecf20Sopenharmony_ci * @polling: whether using NAPI to service response queues 28368c2ecf20Sopenharmony_ci * 28378c2ecf20Sopenharmony_ci * Selects the top-level interrupt handler based on the type of interrupts 28388c2ecf20Sopenharmony_ci * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the 28398c2ecf20Sopenharmony_ci * response queues. 28408c2ecf20Sopenharmony_ci */ 28418c2ecf20Sopenharmony_ciirq_handler_t t3_intr_handler(struct adapter *adap, int polling) 28428c2ecf20Sopenharmony_ci{ 28438c2ecf20Sopenharmony_ci if (adap->flags & USING_MSIX) 28448c2ecf20Sopenharmony_ci return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix; 28458c2ecf20Sopenharmony_ci if (adap->flags & USING_MSI) 28468c2ecf20Sopenharmony_ci return polling ? t3_intr_msi_napi : t3_intr_msi; 28478c2ecf20Sopenharmony_ci if (adap->params.rev > 0) 28488c2ecf20Sopenharmony_ci return polling ? t3b_intr_napi : t3b_intr; 28498c2ecf20Sopenharmony_ci return t3_intr; 28508c2ecf20Sopenharmony_ci} 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci#define SGE_PARERR (F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ 28538c2ecf20Sopenharmony_ci F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ 28548c2ecf20Sopenharmony_ci V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ 28558c2ecf20Sopenharmony_ci F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ 28568c2ecf20Sopenharmony_ci F_HIRCQPARITYERROR) 28578c2ecf20Sopenharmony_ci#define SGE_FRAMINGERR (F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR) 28588c2ecf20Sopenharmony_ci#define SGE_FATALERR (SGE_PARERR | SGE_FRAMINGERR | F_RSPQCREDITOVERFOW | \ 28598c2ecf20Sopenharmony_ci F_RSPQDISABLED) 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci/** 28628c2ecf20Sopenharmony_ci * t3_sge_err_intr_handler - SGE async event interrupt handler 28638c2ecf20Sopenharmony_ci * @adapter: the adapter 28648c2ecf20Sopenharmony_ci * 28658c2ecf20Sopenharmony_ci * Interrupt handler for SGE asynchronous (non-data) events. 28668c2ecf20Sopenharmony_ci */ 28678c2ecf20Sopenharmony_civoid t3_sge_err_intr_handler(struct adapter *adapter) 28688c2ecf20Sopenharmony_ci{ 28698c2ecf20Sopenharmony_ci unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE) & 28708c2ecf20Sopenharmony_ci ~F_FLEMPTY; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci if (status & SGE_PARERR) 28738c2ecf20Sopenharmony_ci CH_ALERT(adapter, "SGE parity error (0x%x)\n", 28748c2ecf20Sopenharmony_ci status & SGE_PARERR); 28758c2ecf20Sopenharmony_ci if (status & SGE_FRAMINGERR) 28768c2ecf20Sopenharmony_ci CH_ALERT(adapter, "SGE framing error (0x%x)\n", 28778c2ecf20Sopenharmony_ci status & SGE_FRAMINGERR); 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci if (status & F_RSPQCREDITOVERFOW) 28808c2ecf20Sopenharmony_ci CH_ALERT(adapter, "SGE response queue credit overflow\n"); 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci if (status & F_RSPQDISABLED) { 28838c2ecf20Sopenharmony_ci v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS); 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci CH_ALERT(adapter, 28868c2ecf20Sopenharmony_ci "packet delivered to disabled response queue " 28878c2ecf20Sopenharmony_ci "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff); 28888c2ecf20Sopenharmony_ci } 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) 28918c2ecf20Sopenharmony_ci queue_work(cxgb3_wq, &adapter->db_drop_task); 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci if (status & (F_HIPRIORITYDBFULL | F_LOPRIORITYDBFULL)) 28948c2ecf20Sopenharmony_ci queue_work(cxgb3_wq, &adapter->db_full_task); 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci if (status & (F_HIPRIORITYDBEMPTY | F_LOPRIORITYDBEMPTY)) 28978c2ecf20Sopenharmony_ci queue_work(cxgb3_wq, &adapter->db_empty_task); 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci t3_write_reg(adapter, A_SG_INT_CAUSE, status); 29008c2ecf20Sopenharmony_ci if (status & SGE_FATALERR) 29018c2ecf20Sopenharmony_ci t3_fatal_err(adapter); 29028c2ecf20Sopenharmony_ci} 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci/** 29058c2ecf20Sopenharmony_ci * sge_timer_tx - perform periodic maintenance of an SGE qset 29068c2ecf20Sopenharmony_ci * @t: a timer list containing the SGE queue set to maintain 29078c2ecf20Sopenharmony_ci * 29088c2ecf20Sopenharmony_ci * Runs periodically from a timer to perform maintenance of an SGE queue 29098c2ecf20Sopenharmony_ci * set. It performs two tasks: 29108c2ecf20Sopenharmony_ci * 29118c2ecf20Sopenharmony_ci * Cleans up any completed Tx descriptors that may still be pending. 29128c2ecf20Sopenharmony_ci * Normal descriptor cleanup happens when new packets are added to a Tx 29138c2ecf20Sopenharmony_ci * queue so this timer is relatively infrequent and does any cleanup only 29148c2ecf20Sopenharmony_ci * if the Tx queue has not seen any new packets in a while. We make a 29158c2ecf20Sopenharmony_ci * best effort attempt to reclaim descriptors, in that we don't wait 29168c2ecf20Sopenharmony_ci * around if we cannot get a queue's lock (which most likely is because 29178c2ecf20Sopenharmony_ci * someone else is queueing new packets and so will also handle the clean 29188c2ecf20Sopenharmony_ci * up). Since control queues use immediate data exclusively we don't 29198c2ecf20Sopenharmony_ci * bother cleaning them up here. 29208c2ecf20Sopenharmony_ci * 29218c2ecf20Sopenharmony_ci */ 29228c2ecf20Sopenharmony_cistatic void sge_timer_tx(struct timer_list *t) 29238c2ecf20Sopenharmony_ci{ 29248c2ecf20Sopenharmony_ci struct sge_qset *qs = from_timer(qs, t, tx_reclaim_timer); 29258c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(qs->netdev); 29268c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 29278c2ecf20Sopenharmony_ci unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0}; 29288c2ecf20Sopenharmony_ci unsigned long next_period; 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci if (__netif_tx_trylock(qs->tx_q)) { 29318c2ecf20Sopenharmony_ci tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], 29328c2ecf20Sopenharmony_ci TX_RECLAIM_TIMER_CHUNK); 29338c2ecf20Sopenharmony_ci __netif_tx_unlock(qs->tx_q); 29348c2ecf20Sopenharmony_ci } 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { 29378c2ecf20Sopenharmony_ci tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD], 29388c2ecf20Sopenharmony_ci TX_RECLAIM_TIMER_CHUNK); 29398c2ecf20Sopenharmony_ci spin_unlock(&qs->txq[TXQ_OFLD].lock); 29408c2ecf20Sopenharmony_ci } 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci next_period = TX_RECLAIM_PERIOD >> 29438c2ecf20Sopenharmony_ci (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / 29448c2ecf20Sopenharmony_ci TX_RECLAIM_TIMER_CHUNK); 29458c2ecf20Sopenharmony_ci mod_timer(&qs->tx_reclaim_timer, jiffies + next_period); 29468c2ecf20Sopenharmony_ci} 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci/** 29498c2ecf20Sopenharmony_ci * sge_timer_rx - perform periodic maintenance of an SGE qset 29508c2ecf20Sopenharmony_ci * @t: the timer list containing the SGE queue set to maintain 29518c2ecf20Sopenharmony_ci * 29528c2ecf20Sopenharmony_ci * a) Replenishes Rx queues that have run out due to memory shortage. 29538c2ecf20Sopenharmony_ci * Normally new Rx buffers are added when existing ones are consumed but 29548c2ecf20Sopenharmony_ci * when out of memory a queue can become empty. We try to add only a few 29558c2ecf20Sopenharmony_ci * buffers here, the queue will be replenished fully as these new buffers 29568c2ecf20Sopenharmony_ci * are used up if memory shortage has subsided. 29578c2ecf20Sopenharmony_ci * 29588c2ecf20Sopenharmony_ci * b) Return coalesced response queue credits in case a response queue is 29598c2ecf20Sopenharmony_ci * starved. 29608c2ecf20Sopenharmony_ci * 29618c2ecf20Sopenharmony_ci */ 29628c2ecf20Sopenharmony_cistatic void sge_timer_rx(struct timer_list *t) 29638c2ecf20Sopenharmony_ci{ 29648c2ecf20Sopenharmony_ci spinlock_t *lock; 29658c2ecf20Sopenharmony_ci struct sge_qset *qs = from_timer(qs, t, rx_reclaim_timer); 29668c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(qs->netdev); 29678c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 29688c2ecf20Sopenharmony_ci u32 status; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci lock = adap->params.rev > 0 ? 29718c2ecf20Sopenharmony_ci &qs->rspq.lock : &adap->sge.qs[0].rspq.lock; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci if (!spin_trylock_irq(lock)) 29748c2ecf20Sopenharmony_ci goto out; 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci if (napi_is_scheduled(&qs->napi)) 29778c2ecf20Sopenharmony_ci goto unlock; 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci if (adap->params.rev < 4) { 29808c2ecf20Sopenharmony_ci status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS); 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci if (status & (1 << qs->rspq.cntxt_id)) { 29838c2ecf20Sopenharmony_ci qs->rspq.starved++; 29848c2ecf20Sopenharmony_ci if (qs->rspq.credits) { 29858c2ecf20Sopenharmony_ci qs->rspq.credits--; 29868c2ecf20Sopenharmony_ci refill_rspq(adap, &qs->rspq, 1); 29878c2ecf20Sopenharmony_ci qs->rspq.restarted++; 29888c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_RSPQ_FL_STATUS, 29898c2ecf20Sopenharmony_ci 1 << qs->rspq.cntxt_id); 29908c2ecf20Sopenharmony_ci } 29918c2ecf20Sopenharmony_ci } 29928c2ecf20Sopenharmony_ci } 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci if (qs->fl[0].credits < qs->fl[0].size) 29958c2ecf20Sopenharmony_ci __refill_fl(adap, &qs->fl[0]); 29968c2ecf20Sopenharmony_ci if (qs->fl[1].credits < qs->fl[1].size) 29978c2ecf20Sopenharmony_ci __refill_fl(adap, &qs->fl[1]); 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ciunlock: 30008c2ecf20Sopenharmony_ci spin_unlock_irq(lock); 30018c2ecf20Sopenharmony_ciout: 30028c2ecf20Sopenharmony_ci mod_timer(&qs->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); 30038c2ecf20Sopenharmony_ci} 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci/** 30068c2ecf20Sopenharmony_ci * t3_update_qset_coalesce - update coalescing settings for a queue set 30078c2ecf20Sopenharmony_ci * @qs: the SGE queue set 30088c2ecf20Sopenharmony_ci * @p: new queue set parameters 30098c2ecf20Sopenharmony_ci * 30108c2ecf20Sopenharmony_ci * Update the coalescing settings for an SGE queue set. Nothing is done 30118c2ecf20Sopenharmony_ci * if the queue set is not initialized yet. 30128c2ecf20Sopenharmony_ci */ 30138c2ecf20Sopenharmony_civoid t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) 30148c2ecf20Sopenharmony_ci{ 30158c2ecf20Sopenharmony_ci qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */ 30168c2ecf20Sopenharmony_ci qs->rspq.polling = p->polling; 30178c2ecf20Sopenharmony_ci qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll; 30188c2ecf20Sopenharmony_ci} 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci/** 30218c2ecf20Sopenharmony_ci * t3_sge_alloc_qset - initialize an SGE queue set 30228c2ecf20Sopenharmony_ci * @adapter: the adapter 30238c2ecf20Sopenharmony_ci * @id: the queue set id 30248c2ecf20Sopenharmony_ci * @nports: how many Ethernet ports will be using this queue set 30258c2ecf20Sopenharmony_ci * @irq_vec_idx: the IRQ vector index for response queue interrupts 30268c2ecf20Sopenharmony_ci * @p: configuration parameters for this queue set 30278c2ecf20Sopenharmony_ci * @ntxq: number of Tx queues for the queue set 30288c2ecf20Sopenharmony_ci * @dev: net device associated with this queue set 30298c2ecf20Sopenharmony_ci * @netdevq: net device TX queue associated with this queue set 30308c2ecf20Sopenharmony_ci * 30318c2ecf20Sopenharmony_ci * Allocate resources and initialize an SGE queue set. A queue set 30328c2ecf20Sopenharmony_ci * comprises a response queue, two Rx free-buffer queues, and up to 3 30338c2ecf20Sopenharmony_ci * Tx queues. The Tx queues are assigned roles in the order Ethernet 30348c2ecf20Sopenharmony_ci * queue, offload queue, and control queue. 30358c2ecf20Sopenharmony_ci */ 30368c2ecf20Sopenharmony_ciint t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, 30378c2ecf20Sopenharmony_ci int irq_vec_idx, const struct qset_params *p, 30388c2ecf20Sopenharmony_ci int ntxq, struct net_device *dev, 30398c2ecf20Sopenharmony_ci struct netdev_queue *netdevq) 30408c2ecf20Sopenharmony_ci{ 30418c2ecf20Sopenharmony_ci int i, avail, ret = -ENOMEM; 30428c2ecf20Sopenharmony_ci struct sge_qset *q = &adapter->sge.qs[id]; 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci init_qset_cntxt(q, id); 30458c2ecf20Sopenharmony_ci timer_setup(&q->tx_reclaim_timer, sge_timer_tx, 0); 30468c2ecf20Sopenharmony_ci timer_setup(&q->rx_reclaim_timer, sge_timer_rx, 0); 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size, 30498c2ecf20Sopenharmony_ci sizeof(struct rx_desc), 30508c2ecf20Sopenharmony_ci sizeof(struct rx_sw_desc), 30518c2ecf20Sopenharmony_ci &q->fl[0].phys_addr, &q->fl[0].sdesc); 30528c2ecf20Sopenharmony_ci if (!q->fl[0].desc) 30538c2ecf20Sopenharmony_ci goto err; 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_ci q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size, 30568c2ecf20Sopenharmony_ci sizeof(struct rx_desc), 30578c2ecf20Sopenharmony_ci sizeof(struct rx_sw_desc), 30588c2ecf20Sopenharmony_ci &q->fl[1].phys_addr, &q->fl[1].sdesc); 30598c2ecf20Sopenharmony_ci if (!q->fl[1].desc) 30608c2ecf20Sopenharmony_ci goto err; 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size, 30638c2ecf20Sopenharmony_ci sizeof(struct rsp_desc), 0, 30648c2ecf20Sopenharmony_ci &q->rspq.phys_addr, NULL); 30658c2ecf20Sopenharmony_ci if (!q->rspq.desc) 30668c2ecf20Sopenharmony_ci goto err; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci for (i = 0; i < ntxq; ++i) { 30698c2ecf20Sopenharmony_ci /* 30708c2ecf20Sopenharmony_ci * The control queue always uses immediate data so does not 30718c2ecf20Sopenharmony_ci * need to keep track of any sk_buffs. 30728c2ecf20Sopenharmony_ci */ 30738c2ecf20Sopenharmony_ci size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i], 30768c2ecf20Sopenharmony_ci sizeof(struct tx_desc), sz, 30778c2ecf20Sopenharmony_ci &q->txq[i].phys_addr, 30788c2ecf20Sopenharmony_ci &q->txq[i].sdesc); 30798c2ecf20Sopenharmony_ci if (!q->txq[i].desc) 30808c2ecf20Sopenharmony_ci goto err; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci q->txq[i].gen = 1; 30838c2ecf20Sopenharmony_ci q->txq[i].size = p->txq_size[i]; 30848c2ecf20Sopenharmony_ci spin_lock_init(&q->txq[i].lock); 30858c2ecf20Sopenharmony_ci skb_queue_head_init(&q->txq[i].sendq); 30868c2ecf20Sopenharmony_ci } 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci tasklet_setup(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq); 30898c2ecf20Sopenharmony_ci tasklet_setup(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq); 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci q->fl[0].gen = q->fl[1].gen = 1; 30928c2ecf20Sopenharmony_ci q->fl[0].size = p->fl_size; 30938c2ecf20Sopenharmony_ci q->fl[1].size = p->jumbo_size; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci q->rspq.gen = 1; 30968c2ecf20Sopenharmony_ci q->rspq.size = p->rspq_size; 30978c2ecf20Sopenharmony_ci spin_lock_init(&q->rspq.lock); 30988c2ecf20Sopenharmony_ci skb_queue_head_init(&q->rspq.rx_queue); 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci q->txq[TXQ_ETH].stop_thres = nports * 31018c2ecf20Sopenharmony_ci flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3); 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci#if FL0_PG_CHUNK_SIZE > 0 31048c2ecf20Sopenharmony_ci q->fl[0].buf_size = FL0_PG_CHUNK_SIZE; 31058c2ecf20Sopenharmony_ci#else 31068c2ecf20Sopenharmony_ci q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); 31078c2ecf20Sopenharmony_ci#endif 31088c2ecf20Sopenharmony_ci#if FL1_PG_CHUNK_SIZE > 0 31098c2ecf20Sopenharmony_ci q->fl[1].buf_size = FL1_PG_CHUNK_SIZE; 31108c2ecf20Sopenharmony_ci#else 31118c2ecf20Sopenharmony_ci q->fl[1].buf_size = is_offload(adapter) ? 31128c2ecf20Sopenharmony_ci (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : 31138c2ecf20Sopenharmony_ci MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt); 31148c2ecf20Sopenharmony_ci#endif 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; 31178c2ecf20Sopenharmony_ci q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0; 31188c2ecf20Sopenharmony_ci q->fl[0].order = FL0_PG_ORDER; 31198c2ecf20Sopenharmony_ci q->fl[1].order = FL1_PG_ORDER; 31208c2ecf20Sopenharmony_ci q->fl[0].alloc_size = FL0_PG_ALLOC_SIZE; 31218c2ecf20Sopenharmony_ci q->fl[1].alloc_size = FL1_PG_ALLOC_SIZE; 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci /* FL threshold comparison uses < */ 31268c2ecf20Sopenharmony_ci ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx, 31278c2ecf20Sopenharmony_ci q->rspq.phys_addr, q->rspq.size, 31288c2ecf20Sopenharmony_ci q->fl[0].buf_size - SGE_PG_RSVD, 1, 0); 31298c2ecf20Sopenharmony_ci if (ret) 31308c2ecf20Sopenharmony_ci goto err_unlock; 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci for (i = 0; i < SGE_RXQ_PER_SET; ++i) { 31338c2ecf20Sopenharmony_ci ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0, 31348c2ecf20Sopenharmony_ci q->fl[i].phys_addr, q->fl[i].size, 31358c2ecf20Sopenharmony_ci q->fl[i].buf_size - SGE_PG_RSVD, 31368c2ecf20Sopenharmony_ci p->cong_thres, 1, 0); 31378c2ecf20Sopenharmony_ci if (ret) 31388c2ecf20Sopenharmony_ci goto err_unlock; 31398c2ecf20Sopenharmony_ci } 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS, 31428c2ecf20Sopenharmony_ci SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr, 31438c2ecf20Sopenharmony_ci q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token, 31448c2ecf20Sopenharmony_ci 1, 0); 31458c2ecf20Sopenharmony_ci if (ret) 31468c2ecf20Sopenharmony_ci goto err_unlock; 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci if (ntxq > 1) { 31498c2ecf20Sopenharmony_ci ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id, 31508c2ecf20Sopenharmony_ci USE_GTS, SGE_CNTXT_OFLD, id, 31518c2ecf20Sopenharmony_ci q->txq[TXQ_OFLD].phys_addr, 31528c2ecf20Sopenharmony_ci q->txq[TXQ_OFLD].size, 0, 1, 0); 31538c2ecf20Sopenharmony_ci if (ret) 31548c2ecf20Sopenharmony_ci goto err_unlock; 31558c2ecf20Sopenharmony_ci } 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci if (ntxq > 2) { 31588c2ecf20Sopenharmony_ci ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0, 31598c2ecf20Sopenharmony_ci SGE_CNTXT_CTRL, id, 31608c2ecf20Sopenharmony_ci q->txq[TXQ_CTRL].phys_addr, 31618c2ecf20Sopenharmony_ci q->txq[TXQ_CTRL].size, 31628c2ecf20Sopenharmony_ci q->txq[TXQ_CTRL].token, 1, 0); 31638c2ecf20Sopenharmony_ci if (ret) 31648c2ecf20Sopenharmony_ci goto err_unlock; 31658c2ecf20Sopenharmony_ci } 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci q->adap = adapter; 31708c2ecf20Sopenharmony_ci q->netdev = dev; 31718c2ecf20Sopenharmony_ci q->tx_q = netdevq; 31728c2ecf20Sopenharmony_ci t3_update_qset_coalesce(q, p); 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, 31758c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_COMP); 31768c2ecf20Sopenharmony_ci if (!avail) { 31778c2ecf20Sopenharmony_ci CH_ALERT(adapter, "free list queue 0 initialization failed\n"); 31788c2ecf20Sopenharmony_ci ret = -ENOMEM; 31798c2ecf20Sopenharmony_ci goto err; 31808c2ecf20Sopenharmony_ci } 31818c2ecf20Sopenharmony_ci if (avail < q->fl[0].size) 31828c2ecf20Sopenharmony_ci CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", 31838c2ecf20Sopenharmony_ci avail); 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, 31868c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_COMP); 31878c2ecf20Sopenharmony_ci if (avail < q->fl[1].size) 31888c2ecf20Sopenharmony_ci CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", 31898c2ecf20Sopenharmony_ci avail); 31908c2ecf20Sopenharmony_ci refill_rspq(adapter, &q->rspq, q->rspq.size - 1); 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) | 31938c2ecf20Sopenharmony_ci V_NEWTIMER(q->rspq.holdoff_tmr)); 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci return 0; 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_cierr_unlock: 31988c2ecf20Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 31998c2ecf20Sopenharmony_cierr: 32008c2ecf20Sopenharmony_ci t3_free_qset(adapter, q); 32018c2ecf20Sopenharmony_ci return ret; 32028c2ecf20Sopenharmony_ci} 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci/** 32058c2ecf20Sopenharmony_ci * t3_start_sge_timers - start SGE timer call backs 32068c2ecf20Sopenharmony_ci * @adap: the adapter 32078c2ecf20Sopenharmony_ci * 32088c2ecf20Sopenharmony_ci * Starts each SGE queue set's timer call back 32098c2ecf20Sopenharmony_ci */ 32108c2ecf20Sopenharmony_civoid t3_start_sge_timers(struct adapter *adap) 32118c2ecf20Sopenharmony_ci{ 32128c2ecf20Sopenharmony_ci int i; 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) { 32158c2ecf20Sopenharmony_ci struct sge_qset *q = &adap->sge.qs[i]; 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci if (q->tx_reclaim_timer.function) 32188c2ecf20Sopenharmony_ci mod_timer(&q->tx_reclaim_timer, 32198c2ecf20Sopenharmony_ci jiffies + TX_RECLAIM_PERIOD); 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci if (q->rx_reclaim_timer.function) 32228c2ecf20Sopenharmony_ci mod_timer(&q->rx_reclaim_timer, 32238c2ecf20Sopenharmony_ci jiffies + RX_RECLAIM_PERIOD); 32248c2ecf20Sopenharmony_ci } 32258c2ecf20Sopenharmony_ci} 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci/** 32288c2ecf20Sopenharmony_ci * t3_stop_sge_timers - stop SGE timer call backs 32298c2ecf20Sopenharmony_ci * @adap: the adapter 32308c2ecf20Sopenharmony_ci * 32318c2ecf20Sopenharmony_ci * Stops each SGE queue set's timer call back 32328c2ecf20Sopenharmony_ci */ 32338c2ecf20Sopenharmony_civoid t3_stop_sge_timers(struct adapter *adap) 32348c2ecf20Sopenharmony_ci{ 32358c2ecf20Sopenharmony_ci int i; 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) { 32388c2ecf20Sopenharmony_ci struct sge_qset *q = &adap->sge.qs[i]; 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci if (q->tx_reclaim_timer.function) 32418c2ecf20Sopenharmony_ci del_timer_sync(&q->tx_reclaim_timer); 32428c2ecf20Sopenharmony_ci if (q->rx_reclaim_timer.function) 32438c2ecf20Sopenharmony_ci del_timer_sync(&q->rx_reclaim_timer); 32448c2ecf20Sopenharmony_ci } 32458c2ecf20Sopenharmony_ci} 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci/** 32488c2ecf20Sopenharmony_ci * t3_free_sge_resources - free SGE resources 32498c2ecf20Sopenharmony_ci * @adap: the adapter 32508c2ecf20Sopenharmony_ci * 32518c2ecf20Sopenharmony_ci * Frees resources used by the SGE queue sets. 32528c2ecf20Sopenharmony_ci */ 32538c2ecf20Sopenharmony_civoid t3_free_sge_resources(struct adapter *adap) 32548c2ecf20Sopenharmony_ci{ 32558c2ecf20Sopenharmony_ci int i; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) 32588c2ecf20Sopenharmony_ci t3_free_qset(adap, &adap->sge.qs[i]); 32598c2ecf20Sopenharmony_ci} 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci/** 32628c2ecf20Sopenharmony_ci * t3_sge_start - enable SGE 32638c2ecf20Sopenharmony_ci * @adap: the adapter 32648c2ecf20Sopenharmony_ci * 32658c2ecf20Sopenharmony_ci * Enables the SGE for DMAs. This is the last step in starting packet 32668c2ecf20Sopenharmony_ci * transfers. 32678c2ecf20Sopenharmony_ci */ 32688c2ecf20Sopenharmony_civoid t3_sge_start(struct adapter *adap) 32698c2ecf20Sopenharmony_ci{ 32708c2ecf20Sopenharmony_ci t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE); 32718c2ecf20Sopenharmony_ci} 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci/** 32748c2ecf20Sopenharmony_ci * t3_sge_stop_dma - Disable SGE DMA engine operation 32758c2ecf20Sopenharmony_ci * @adap: the adapter 32768c2ecf20Sopenharmony_ci * 32778c2ecf20Sopenharmony_ci * Can be invoked from interrupt context e.g. error handler. 32788c2ecf20Sopenharmony_ci * 32798c2ecf20Sopenharmony_ci * Note that this function cannot disable the restart of tasklets as 32808c2ecf20Sopenharmony_ci * it cannot wait if called from interrupt context, however the 32818c2ecf20Sopenharmony_ci * tasklets will have no effect since the doorbells are disabled. The 32828c2ecf20Sopenharmony_ci * driver will call tg3_sge_stop() later from process context, at 32838c2ecf20Sopenharmony_ci * which time the tasklets will be stopped if they are still running. 32848c2ecf20Sopenharmony_ci */ 32858c2ecf20Sopenharmony_civoid t3_sge_stop_dma(struct adapter *adap) 32868c2ecf20Sopenharmony_ci{ 32878c2ecf20Sopenharmony_ci t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0); 32888c2ecf20Sopenharmony_ci} 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci/** 32918c2ecf20Sopenharmony_ci * t3_sge_stop - disable SGE operation completly 32928c2ecf20Sopenharmony_ci * @adap: the adapter 32938c2ecf20Sopenharmony_ci * 32948c2ecf20Sopenharmony_ci * Called from process context. Disables the DMA engine and any 32958c2ecf20Sopenharmony_ci * pending queue restart tasklets. 32968c2ecf20Sopenharmony_ci */ 32978c2ecf20Sopenharmony_civoid t3_sge_stop(struct adapter *adap) 32988c2ecf20Sopenharmony_ci{ 32998c2ecf20Sopenharmony_ci int i; 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci t3_sge_stop_dma(adap); 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) { 33048c2ecf20Sopenharmony_ci struct sge_qset *qs = &adap->sge.qs[i]; 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk); 33078c2ecf20Sopenharmony_ci tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk); 33088c2ecf20Sopenharmony_ci } 33098c2ecf20Sopenharmony_ci} 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci/** 33128c2ecf20Sopenharmony_ci * t3_sge_init - initialize SGE 33138c2ecf20Sopenharmony_ci * @adap: the adapter 33148c2ecf20Sopenharmony_ci * @p: the SGE parameters 33158c2ecf20Sopenharmony_ci * 33168c2ecf20Sopenharmony_ci * Performs SGE initialization needed every time after a chip reset. 33178c2ecf20Sopenharmony_ci * We do not initialize any of the queue sets here, instead the driver 33188c2ecf20Sopenharmony_ci * top-level must request those individually. We also do not enable DMA 33198c2ecf20Sopenharmony_ci * here, that should be done after the queues have been set up. 33208c2ecf20Sopenharmony_ci */ 33218c2ecf20Sopenharmony_civoid t3_sge_init(struct adapter *adap, struct sge_params *p) 33228c2ecf20Sopenharmony_ci{ 33238c2ecf20Sopenharmony_ci unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12); 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL | 33268c2ecf20Sopenharmony_ci F_CQCRDTCTRL | F_CONGMODE | F_TNLFLMODE | F_FATLPERREN | 33278c2ecf20Sopenharmony_ci V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS | 33288c2ecf20Sopenharmony_ci V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING; 33298c2ecf20Sopenharmony_ci#if SGE_NUM_GENBITS == 1 33308c2ecf20Sopenharmony_ci ctrl |= F_EGRGENCTRL; 33318c2ecf20Sopenharmony_ci#endif 33328c2ecf20Sopenharmony_ci if (adap->params.rev > 0) { 33338c2ecf20Sopenharmony_ci if (!(adap->flags & (USING_MSIX | USING_MSI))) 33348c2ecf20Sopenharmony_ci ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ; 33358c2ecf20Sopenharmony_ci } 33368c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_CONTROL, ctrl); 33378c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) | 33388c2ecf20Sopenharmony_ci V_LORCQDRBTHRSH(512)); 33398c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10); 33408c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) | 33418c2ecf20Sopenharmony_ci V_TIMEOUT(200 * core_ticks_per_usec(adap))); 33428c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 33438c2ecf20Sopenharmony_ci adap->params.rev < T3_REV_C ? 1000 : 500); 33448c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256); 33458c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000); 33468c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256); 33478c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff)); 33488c2ecf20Sopenharmony_ci t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024); 33498c2ecf20Sopenharmony_ci} 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci/** 33528c2ecf20Sopenharmony_ci * t3_sge_prep - one-time SGE initialization 33538c2ecf20Sopenharmony_ci * @adap: the associated adapter 33548c2ecf20Sopenharmony_ci * @p: SGE parameters 33558c2ecf20Sopenharmony_ci * 33568c2ecf20Sopenharmony_ci * Performs one-time initialization of SGE SW state. Includes determining 33578c2ecf20Sopenharmony_ci * defaults for the assorted SGE parameters, which admins can change until 33588c2ecf20Sopenharmony_ci * they are used to initialize the SGE. 33598c2ecf20Sopenharmony_ci */ 33608c2ecf20Sopenharmony_civoid t3_sge_prep(struct adapter *adap, struct sge_params *p) 33618c2ecf20Sopenharmony_ci{ 33628c2ecf20Sopenharmony_ci int i; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) - 33658c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) { 33688c2ecf20Sopenharmony_ci struct qset_params *q = p->qset + i; 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci q->polling = adap->params.rev > 0; 33718c2ecf20Sopenharmony_ci q->coalesce_usecs = 5; 33728c2ecf20Sopenharmony_ci q->rspq_size = 1024; 33738c2ecf20Sopenharmony_ci q->fl_size = 1024; 33748c2ecf20Sopenharmony_ci q->jumbo_size = 512; 33758c2ecf20Sopenharmony_ci q->txq_size[TXQ_ETH] = 1024; 33768c2ecf20Sopenharmony_ci q->txq_size[TXQ_OFLD] = 1024; 33778c2ecf20Sopenharmony_ci q->txq_size[TXQ_CTRL] = 256; 33788c2ecf20Sopenharmony_ci q->cong_thres = 0; 33798c2ecf20Sopenharmony_ci } 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci spin_lock_init(&adap->sge.reg_lock); 33828c2ecf20Sopenharmony_ci} 3383