162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#include <linux/skbuff.h> 3362306a36Sopenharmony_ci#include <linux/netdevice.h> 3462306a36Sopenharmony_ci#include <linux/etherdevice.h> 3562306a36Sopenharmony_ci#include <linux/if_vlan.h> 3662306a36Sopenharmony_ci#include <linux/ip.h> 3762306a36Sopenharmony_ci#include <linux/tcp.h> 3862306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3962306a36Sopenharmony_ci#include <linux/slab.h> 4062306a36Sopenharmony_ci#include <linux/prefetch.h> 4162306a36Sopenharmony_ci#include <net/arp.h> 4262306a36Sopenharmony_ci#include "common.h" 4362306a36Sopenharmony_ci#include "regs.h" 4462306a36Sopenharmony_ci#include "sge_defs.h" 4562306a36Sopenharmony_ci#include "t3_cpl.h" 4662306a36Sopenharmony_ci#include "firmware_exports.h" 4762306a36Sopenharmony_ci#include "cxgb3_offload.h" 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define USE_GTS 0 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define SGE_RX_SM_BUF_SIZE 1536 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define SGE_RX_COPY_THRES 256 5462306a36Sopenharmony_ci#define SGE_RX_PULL_LEN 128 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define SGE_PG_RSVD SMP_CACHE_BYTES 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * Page chunk size for FL0 buffers if FL0 is to be populated with page chunks. 5962306a36Sopenharmony_ci * It must be a divisor of PAGE_SIZE. If set to 0 FL0 will use sk_buffs 6062306a36Sopenharmony_ci * directly. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci#define FL0_PG_CHUNK_SIZE 2048 6362306a36Sopenharmony_ci#define FL0_PG_ORDER 0 6462306a36Sopenharmony_ci#define FL0_PG_ALLOC_SIZE (PAGE_SIZE << FL0_PG_ORDER) 6562306a36Sopenharmony_ci#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) 6662306a36Sopenharmony_ci#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) 6762306a36Sopenharmony_ci#define FL1_PG_ALLOC_SIZE (PAGE_SIZE << FL1_PG_ORDER) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define SGE_RX_DROP_THRES 16 7062306a36Sopenharmony_ci#define RX_RECLAIM_PERIOD (HZ/4) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * Max number of Rx buffers we replenish at a time. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci#define MAX_RX_REFILL 16U 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * Period of the Tx buffer reclaim timer. This timer does not need to run 7862306a36Sopenharmony_ci * frequently as Tx buffers are usually reclaimed by new Tx packets. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci#define TX_RECLAIM_PERIOD (HZ / 4) 8162306a36Sopenharmony_ci#define TX_RECLAIM_TIMER_CHUNK 64U 8262306a36Sopenharmony_ci#define TX_RECLAIM_CHUNK 16U 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* WR size in bytes */ 8562306a36Sopenharmony_ci#define WR_LEN (WR_FLITS * 8) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* 8862306a36Sopenharmony_ci * Types of Tx queues in each queue set. Order here matters, do not change. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_cienum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL }; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* Values for sge_txq.flags */ 9362306a36Sopenharmony_cienum { 9462306a36Sopenharmony_ci TXQ_RUNNING = 1 << 0, /* fetch engine is running */ 9562306a36Sopenharmony_ci TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */ 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistruct tx_desc { 9962306a36Sopenharmony_ci __be64 flit[TX_DESC_FLITS]; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistruct rx_desc { 10362306a36Sopenharmony_ci __be32 addr_lo; 10462306a36Sopenharmony_ci __be32 len_gen; 10562306a36Sopenharmony_ci __be32 gen2; 10662306a36Sopenharmony_ci __be32 addr_hi; 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistruct tx_sw_desc { /* SW state per Tx descriptor */ 11062306a36Sopenharmony_ci struct sk_buff *skb; 11162306a36Sopenharmony_ci u8 eop; /* set if last descriptor for packet */ 11262306a36Sopenharmony_ci u8 addr_idx; /* buffer index of first SGL entry in descriptor */ 11362306a36Sopenharmony_ci u8 fragidx; /* first page fragment associated with descriptor */ 11462306a36Sopenharmony_ci s8 sflit; /* start flit of first SGL entry in descriptor */ 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistruct rx_sw_desc { /* SW state per Rx descriptor */ 11862306a36Sopenharmony_ci union { 11962306a36Sopenharmony_ci struct sk_buff *skb; 12062306a36Sopenharmony_ci struct fl_pg_chunk pg_chunk; 12162306a36Sopenharmony_ci }; 12262306a36Sopenharmony_ci DEFINE_DMA_UNMAP_ADDR(dma_addr); 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistruct rsp_desc { /* response queue descriptor */ 12662306a36Sopenharmony_ci struct rss_header rss_hdr; 12762306a36Sopenharmony_ci __be32 flags; 12862306a36Sopenharmony_ci __be32 len_cq; 12962306a36Sopenharmony_ci struct_group(immediate, 13062306a36Sopenharmony_ci u8 imm_data[47]; 13162306a36Sopenharmony_ci u8 intr_gen; 13262306a36Sopenharmony_ci ); 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* 13662306a36Sopenharmony_ci * Holds unmapping information for Tx packets that need deferred unmapping. 13762306a36Sopenharmony_ci * This structure lives at skb->head and must be allocated by callers. 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_cistruct deferred_unmap_info { 14062306a36Sopenharmony_ci struct pci_dev *pdev; 14162306a36Sopenharmony_ci dma_addr_t addr[MAX_SKB_FRAGS + 1]; 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * Maps a number of flits to the number of Tx descriptors that can hold them. 14662306a36Sopenharmony_ci * The formula is 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * desc = 1 + (flits - 2) / (WR_FLITS - 1). 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * HW allows up to 4 descriptors to be combined into a WR. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cistatic u8 flit_desc_map[] = { 15362306a36Sopenharmony_ci 0, 15462306a36Sopenharmony_ci#if SGE_NUM_GENBITS == 1 15562306a36Sopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15662306a36Sopenharmony_ci 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 15762306a36Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 15862306a36Sopenharmony_ci 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 15962306a36Sopenharmony_ci#elif SGE_NUM_GENBITS == 2 16062306a36Sopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16162306a36Sopenharmony_ci 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16262306a36Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16362306a36Sopenharmony_ci 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16462306a36Sopenharmony_ci#else 16562306a36Sopenharmony_ci# error "SGE_NUM_GENBITS must be 1 or 2" 16662306a36Sopenharmony_ci#endif 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci return container_of(q, struct sge_qset, rspq); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci return container_of(q, struct sge_qset, txq[qidx]); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/** 18062306a36Sopenharmony_ci * refill_rspq - replenish an SGE response queue 18162306a36Sopenharmony_ci * @adapter: the adapter 18262306a36Sopenharmony_ci * @q: the response queue to replenish 18362306a36Sopenharmony_ci * @credits: how many new responses to make available 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * Replenishes a response queue by making the supplied number of responses 18662306a36Sopenharmony_ci * available to HW. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_cistatic inline void refill_rspq(struct adapter *adapter, 18962306a36Sopenharmony_ci const struct sge_rspq *q, unsigned int credits) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci rmb(); 19262306a36Sopenharmony_ci t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN, 19362306a36Sopenharmony_ci V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/** 19762306a36Sopenharmony_ci * need_skb_unmap - does the platform need unmapping of sk_buffs? 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Returns true if the platform needs sk_buff unmapping. The compiler 20062306a36Sopenharmony_ci * optimizes away unnecessary code if this returns true. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic inline int need_skb_unmap(void) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci#ifdef CONFIG_NEED_DMA_MAP_STATE 20562306a36Sopenharmony_ci return 1; 20662306a36Sopenharmony_ci#else 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci#endif 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/** 21262306a36Sopenharmony_ci * unmap_skb - unmap a packet main body and its page fragments 21362306a36Sopenharmony_ci * @skb: the packet 21462306a36Sopenharmony_ci * @q: the Tx queue containing Tx descriptors for the packet 21562306a36Sopenharmony_ci * @cidx: index of Tx descriptor 21662306a36Sopenharmony_ci * @pdev: the PCI device 21762306a36Sopenharmony_ci * 21862306a36Sopenharmony_ci * Unmap the main body of an sk_buff and its page fragments, if any. 21962306a36Sopenharmony_ci * Because of the fairly complicated structure of our SGLs and the desire 22062306a36Sopenharmony_ci * to conserve space for metadata, the information necessary to unmap an 22162306a36Sopenharmony_ci * sk_buff is spread across the sk_buff itself (buffer lengths), the HW Tx 22262306a36Sopenharmony_ci * descriptors (the physical addresses of the various data buffers), and 22362306a36Sopenharmony_ci * the SW descriptor state (assorted indices). The send functions 22462306a36Sopenharmony_ci * initialize the indices for the first packet descriptor so we can unmap 22562306a36Sopenharmony_ci * the buffers held in the first Tx descriptor here, and we have enough 22662306a36Sopenharmony_ci * information at this point to set the state for the next Tx descriptor. 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * Note that it is possible to clean up the first descriptor of a packet 22962306a36Sopenharmony_ci * before the send routines have written the next descriptors, but this 23062306a36Sopenharmony_ci * race does not cause any problem. We just end up writing the unmapping 23162306a36Sopenharmony_ci * info for the descriptor first. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_cistatic inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, 23462306a36Sopenharmony_ci unsigned int cidx, struct pci_dev *pdev) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci const struct sg_ent *sgp; 23762306a36Sopenharmony_ci struct tx_sw_desc *d = &q->sdesc[cidx]; 23862306a36Sopenharmony_ci int nfrags, frag_idx, curflit, j = d->addr_idx; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci sgp = (struct sg_ent *)&q->desc[cidx].flit[d->sflit]; 24162306a36Sopenharmony_ci frag_idx = d->fragidx; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (frag_idx == 0 && skb_headlen(skb)) { 24462306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, be64_to_cpu(sgp->addr[0]), 24562306a36Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 24662306a36Sopenharmony_ci j = 1; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci curflit = d->sflit + 1 + j; 25062306a36Sopenharmony_ci nfrags = skb_shinfo(skb)->nr_frags; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci while (frag_idx < nfrags && curflit < WR_FLITS) { 25362306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, be64_to_cpu(sgp->addr[j]), 25462306a36Sopenharmony_ci skb_frag_size(&skb_shinfo(skb)->frags[frag_idx]), 25562306a36Sopenharmony_ci DMA_TO_DEVICE); 25662306a36Sopenharmony_ci j ^= 1; 25762306a36Sopenharmony_ci if (j == 0) { 25862306a36Sopenharmony_ci sgp++; 25962306a36Sopenharmony_ci curflit++; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci curflit++; 26262306a36Sopenharmony_ci frag_idx++; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ 26662306a36Sopenharmony_ci d = cidx + 1 == q->size ? q->sdesc : d + 1; 26762306a36Sopenharmony_ci d->fragidx = frag_idx; 26862306a36Sopenharmony_ci d->addr_idx = j; 26962306a36Sopenharmony_ci d->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/** 27462306a36Sopenharmony_ci * free_tx_desc - reclaims Tx descriptors and their buffers 27562306a36Sopenharmony_ci * @adapter: the adapter 27662306a36Sopenharmony_ci * @q: the Tx queue to reclaim descriptors from 27762306a36Sopenharmony_ci * @n: the number of descriptors to reclaim 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * Reclaims Tx descriptors from an SGE Tx queue and frees the associated 28062306a36Sopenharmony_ci * Tx buffers. Called with the Tx queue lock held. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_cistatic void free_tx_desc(struct adapter *adapter, struct sge_txq *q, 28362306a36Sopenharmony_ci unsigned int n) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct tx_sw_desc *d; 28662306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 28762306a36Sopenharmony_ci unsigned int cidx = q->cidx; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci const int need_unmap = need_skb_unmap() && 29062306a36Sopenharmony_ci q->cntxt_id >= FW_TUNNEL_SGEEC_START; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci d = &q->sdesc[cidx]; 29362306a36Sopenharmony_ci while (n--) { 29462306a36Sopenharmony_ci if (d->skb) { /* an SGL is present */ 29562306a36Sopenharmony_ci if (need_unmap) 29662306a36Sopenharmony_ci unmap_skb(d->skb, q, cidx, pdev); 29762306a36Sopenharmony_ci if (d->eop) { 29862306a36Sopenharmony_ci dev_consume_skb_any(d->skb); 29962306a36Sopenharmony_ci d->skb = NULL; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci ++d; 30362306a36Sopenharmony_ci if (++cidx == q->size) { 30462306a36Sopenharmony_ci cidx = 0; 30562306a36Sopenharmony_ci d = q->sdesc; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci q->cidx = cidx; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/** 31262306a36Sopenharmony_ci * reclaim_completed_tx - reclaims completed Tx descriptors 31362306a36Sopenharmony_ci * @adapter: the adapter 31462306a36Sopenharmony_ci * @q: the Tx queue to reclaim completed descriptors from 31562306a36Sopenharmony_ci * @chunk: maximum number of descriptors to reclaim 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * Reclaims Tx descriptors that the SGE has indicated it has processed, 31862306a36Sopenharmony_ci * and frees the associated buffers if possible. Called with the Tx 31962306a36Sopenharmony_ci * queue's lock held. 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_cistatic inline unsigned int reclaim_completed_tx(struct adapter *adapter, 32262306a36Sopenharmony_ci struct sge_txq *q, 32362306a36Sopenharmony_ci unsigned int chunk) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci unsigned int reclaim = q->processed - q->cleaned; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci reclaim = min(chunk, reclaim); 32862306a36Sopenharmony_ci if (reclaim) { 32962306a36Sopenharmony_ci free_tx_desc(adapter, q, reclaim); 33062306a36Sopenharmony_ci q->cleaned += reclaim; 33162306a36Sopenharmony_ci q->in_use -= reclaim; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci return q->processed - q->cleaned; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/** 33762306a36Sopenharmony_ci * should_restart_tx - are there enough resources to restart a Tx queue? 33862306a36Sopenharmony_ci * @q: the Tx queue 33962306a36Sopenharmony_ci * 34062306a36Sopenharmony_ci * Checks if there are enough descriptors to restart a suspended Tx queue. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_cistatic inline int should_restart_tx(const struct sge_txq *q) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci unsigned int r = q->processed - q->cleaned; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return q->in_use - r < (q->size >> 1); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic void clear_rx_desc(struct pci_dev *pdev, const struct sge_fl *q, 35062306a36Sopenharmony_ci struct rx_sw_desc *d) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci if (q->use_pages && d->pg_chunk.page) { 35362306a36Sopenharmony_ci (*d->pg_chunk.p_cnt)--; 35462306a36Sopenharmony_ci if (!*d->pg_chunk.p_cnt) 35562306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, d->pg_chunk.mapping, 35662306a36Sopenharmony_ci q->alloc_size, DMA_FROM_DEVICE); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci put_page(d->pg_chunk.page); 35962306a36Sopenharmony_ci d->pg_chunk.page = NULL; 36062306a36Sopenharmony_ci } else { 36162306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, dma_unmap_addr(d, dma_addr), 36262306a36Sopenharmony_ci q->buf_size, DMA_FROM_DEVICE); 36362306a36Sopenharmony_ci kfree_skb(d->skb); 36462306a36Sopenharmony_ci d->skb = NULL; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/** 36962306a36Sopenharmony_ci * free_rx_bufs - free the Rx buffers on an SGE free list 37062306a36Sopenharmony_ci * @pdev: the PCI device associated with the adapter 37162306a36Sopenharmony_ci * @q: the SGE free list to clean up 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * Release the buffers on an SGE free-buffer Rx queue. HW fetching from 37462306a36Sopenharmony_ci * this queue should be stopped before calling this function. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_cistatic void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci unsigned int cidx = q->cidx; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci while (q->credits--) { 38162306a36Sopenharmony_ci struct rx_sw_desc *d = &q->sdesc[cidx]; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci clear_rx_desc(pdev, q, d); 38562306a36Sopenharmony_ci if (++cidx == q->size) 38662306a36Sopenharmony_ci cidx = 0; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (q->pg_chunk.page) { 39062306a36Sopenharmony_ci __free_pages(q->pg_chunk.page, q->order); 39162306a36Sopenharmony_ci q->pg_chunk.page = NULL; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/** 39662306a36Sopenharmony_ci * add_one_rx_buf - add a packet buffer to a free-buffer list 39762306a36Sopenharmony_ci * @va: buffer start VA 39862306a36Sopenharmony_ci * @len: the buffer length 39962306a36Sopenharmony_ci * @d: the HW Rx descriptor to write 40062306a36Sopenharmony_ci * @sd: the SW Rx descriptor to write 40162306a36Sopenharmony_ci * @gen: the generation bit value 40262306a36Sopenharmony_ci * @pdev: the PCI device associated with the adapter 40362306a36Sopenharmony_ci * 40462306a36Sopenharmony_ci * Add a buffer of the given length to the supplied HW and SW Rx 40562306a36Sopenharmony_ci * descriptors. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_cistatic inline int add_one_rx_buf(void *va, unsigned int len, 40862306a36Sopenharmony_ci struct rx_desc *d, struct rx_sw_desc *sd, 40962306a36Sopenharmony_ci unsigned int gen, struct pci_dev *pdev) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci dma_addr_t mapping; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mapping = dma_map_single(&pdev->dev, va, len, DMA_FROM_DEVICE); 41462306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&pdev->dev, mapping))) 41562306a36Sopenharmony_ci return -ENOMEM; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci dma_unmap_addr_set(sd, dma_addr, mapping); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci d->addr_lo = cpu_to_be32(mapping); 42062306a36Sopenharmony_ci d->addr_hi = cpu_to_be32((u64) mapping >> 32); 42162306a36Sopenharmony_ci dma_wmb(); 42262306a36Sopenharmony_ci d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); 42362306a36Sopenharmony_ci d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic inline int add_one_rx_chunk(dma_addr_t mapping, struct rx_desc *d, 42862306a36Sopenharmony_ci unsigned int gen) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci d->addr_lo = cpu_to_be32(mapping); 43162306a36Sopenharmony_ci d->addr_hi = cpu_to_be32((u64) mapping >> 32); 43262306a36Sopenharmony_ci dma_wmb(); 43362306a36Sopenharmony_ci d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); 43462306a36Sopenharmony_ci d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q, 43962306a36Sopenharmony_ci struct rx_sw_desc *sd, gfp_t gfp, 44062306a36Sopenharmony_ci unsigned int order) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci if (!q->pg_chunk.page) { 44362306a36Sopenharmony_ci dma_addr_t mapping; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci q->pg_chunk.page = alloc_pages(gfp, order); 44662306a36Sopenharmony_ci if (unlikely(!q->pg_chunk.page)) 44762306a36Sopenharmony_ci return -ENOMEM; 44862306a36Sopenharmony_ci q->pg_chunk.va = page_address(q->pg_chunk.page); 44962306a36Sopenharmony_ci q->pg_chunk.p_cnt = q->pg_chunk.va + (PAGE_SIZE << order) - 45062306a36Sopenharmony_ci SGE_PG_RSVD; 45162306a36Sopenharmony_ci q->pg_chunk.offset = 0; 45262306a36Sopenharmony_ci mapping = dma_map_page(&adapter->pdev->dev, q->pg_chunk.page, 45362306a36Sopenharmony_ci 0, q->alloc_size, DMA_FROM_DEVICE); 45462306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&adapter->pdev->dev, mapping))) { 45562306a36Sopenharmony_ci __free_pages(q->pg_chunk.page, order); 45662306a36Sopenharmony_ci q->pg_chunk.page = NULL; 45762306a36Sopenharmony_ci return -EIO; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci q->pg_chunk.mapping = mapping; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci sd->pg_chunk = q->pg_chunk; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci prefetch(sd->pg_chunk.p_cnt); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci q->pg_chunk.offset += q->buf_size; 46662306a36Sopenharmony_ci if (q->pg_chunk.offset == (PAGE_SIZE << order)) 46762306a36Sopenharmony_ci q->pg_chunk.page = NULL; 46862306a36Sopenharmony_ci else { 46962306a36Sopenharmony_ci q->pg_chunk.va += q->buf_size; 47062306a36Sopenharmony_ci get_page(q->pg_chunk.page); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (sd->pg_chunk.offset == 0) 47462306a36Sopenharmony_ci *sd->pg_chunk.p_cnt = 1; 47562306a36Sopenharmony_ci else 47662306a36Sopenharmony_ci *sd->pg_chunk.p_cnt += 1; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci if (q->pend_cred >= q->credits / 4) { 48462306a36Sopenharmony_ci q->pend_cred = 0; 48562306a36Sopenharmony_ci wmb(); 48662306a36Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/** 49162306a36Sopenharmony_ci * refill_fl - refill an SGE free-buffer list 49262306a36Sopenharmony_ci * @adap: the adapter 49362306a36Sopenharmony_ci * @q: the free-list to refill 49462306a36Sopenharmony_ci * @n: the number of new buffers to allocate 49562306a36Sopenharmony_ci * @gfp: the gfp flags for allocating new buffers 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * (Re)populate an SGE free-buffer list with up to @n new packet buffers, 49862306a36Sopenharmony_ci * allocated with the supplied gfp flags. The caller must assure that 49962306a36Sopenharmony_ci * @n does not exceed the queue's capacity. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_cistatic int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct rx_sw_desc *sd = &q->sdesc[q->pidx]; 50462306a36Sopenharmony_ci struct rx_desc *d = &q->desc[q->pidx]; 50562306a36Sopenharmony_ci unsigned int count = 0; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci while (n--) { 50862306a36Sopenharmony_ci dma_addr_t mapping; 50962306a36Sopenharmony_ci int err; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (q->use_pages) { 51262306a36Sopenharmony_ci if (unlikely(alloc_pg_chunk(adap, q, sd, gfp, 51362306a36Sopenharmony_ci q->order))) { 51462306a36Sopenharmony_cinomem: q->alloc_failed++; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci mapping = sd->pg_chunk.mapping + sd->pg_chunk.offset; 51862306a36Sopenharmony_ci dma_unmap_addr_set(sd, dma_addr, mapping); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci add_one_rx_chunk(mapping, d, q->gen); 52162306a36Sopenharmony_ci dma_sync_single_for_device(&adap->pdev->dev, mapping, 52262306a36Sopenharmony_ci q->buf_size - SGE_PG_RSVD, 52362306a36Sopenharmony_ci DMA_FROM_DEVICE); 52462306a36Sopenharmony_ci } else { 52562306a36Sopenharmony_ci void *buf_start; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci struct sk_buff *skb = alloc_skb(q->buf_size, gfp); 52862306a36Sopenharmony_ci if (!skb) 52962306a36Sopenharmony_ci goto nomem; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci sd->skb = skb; 53262306a36Sopenharmony_ci buf_start = skb->data; 53362306a36Sopenharmony_ci err = add_one_rx_buf(buf_start, q->buf_size, d, sd, 53462306a36Sopenharmony_ci q->gen, adap->pdev); 53562306a36Sopenharmony_ci if (unlikely(err)) { 53662306a36Sopenharmony_ci clear_rx_desc(adap->pdev, q, sd); 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci d++; 54262306a36Sopenharmony_ci sd++; 54362306a36Sopenharmony_ci if (++q->pidx == q->size) { 54462306a36Sopenharmony_ci q->pidx = 0; 54562306a36Sopenharmony_ci q->gen ^= 1; 54662306a36Sopenharmony_ci sd = q->sdesc; 54762306a36Sopenharmony_ci d = q->desc; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci count++; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci q->credits += count; 55362306a36Sopenharmony_ci q->pend_cred += count; 55462306a36Sopenharmony_ci ring_fl_db(adap, q); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci return count; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits), 56262306a36Sopenharmony_ci GFP_ATOMIC | __GFP_COMP); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/** 56662306a36Sopenharmony_ci * recycle_rx_buf - recycle a receive buffer 56762306a36Sopenharmony_ci * @adap: the adapter 56862306a36Sopenharmony_ci * @q: the SGE free list 56962306a36Sopenharmony_ci * @idx: index of buffer to recycle 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * Recycles the specified buffer on the given free list by adding it at 57262306a36Sopenharmony_ci * the next available slot on the list. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_cistatic void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, 57562306a36Sopenharmony_ci unsigned int idx) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct rx_desc *from = &q->desc[idx]; 57862306a36Sopenharmony_ci struct rx_desc *to = &q->desc[q->pidx]; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci q->sdesc[q->pidx] = q->sdesc[idx]; 58162306a36Sopenharmony_ci to->addr_lo = from->addr_lo; /* already big endian */ 58262306a36Sopenharmony_ci to->addr_hi = from->addr_hi; /* likewise */ 58362306a36Sopenharmony_ci dma_wmb(); 58462306a36Sopenharmony_ci to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen)); 58562306a36Sopenharmony_ci to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen)); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (++q->pidx == q->size) { 58862306a36Sopenharmony_ci q->pidx = 0; 58962306a36Sopenharmony_ci q->gen ^= 1; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci q->credits++; 59362306a36Sopenharmony_ci q->pend_cred++; 59462306a36Sopenharmony_ci ring_fl_db(adap, q); 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci/** 59862306a36Sopenharmony_ci * alloc_ring - allocate resources for an SGE descriptor ring 59962306a36Sopenharmony_ci * @pdev: the PCI device 60062306a36Sopenharmony_ci * @nelem: the number of descriptors 60162306a36Sopenharmony_ci * @elem_size: the size of each descriptor 60262306a36Sopenharmony_ci * @sw_size: the size of the SW state associated with each ring element 60362306a36Sopenharmony_ci * @phys: the physical address of the allocated ring 60462306a36Sopenharmony_ci * @metadata: address of the array holding the SW state for the ring 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * Allocates resources for an SGE descriptor ring, such as Tx queues, 60762306a36Sopenharmony_ci * free buffer lists, or response queues. Each SGE ring requires 60862306a36Sopenharmony_ci * space for its HW descriptors plus, optionally, space for the SW state 60962306a36Sopenharmony_ci * associated with each HW entry (the metadata). The function returns 61062306a36Sopenharmony_ci * three values: the virtual address for the HW ring (the return value 61162306a36Sopenharmony_ci * of the function), the physical address of the HW ring, and the address 61262306a36Sopenharmony_ci * of the SW ring. 61362306a36Sopenharmony_ci */ 61462306a36Sopenharmony_cistatic void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, 61562306a36Sopenharmony_ci size_t sw_size, dma_addr_t * phys, void *metadata) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci size_t len = nelem * elem_size; 61862306a36Sopenharmony_ci void *s = NULL; 61962306a36Sopenharmony_ci void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (!p) 62262306a36Sopenharmony_ci return NULL; 62362306a36Sopenharmony_ci if (sw_size && metadata) { 62462306a36Sopenharmony_ci s = kcalloc(nelem, sw_size, GFP_KERNEL); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (!s) { 62762306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, len, p, *phys); 62862306a36Sopenharmony_ci return NULL; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci *(void **)metadata = s; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci return p; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci/** 63662306a36Sopenharmony_ci * t3_reset_qset - reset a sge qset 63762306a36Sopenharmony_ci * @q: the queue set 63862306a36Sopenharmony_ci * 63962306a36Sopenharmony_ci * Reset the qset structure. 64062306a36Sopenharmony_ci * the NAPI structure is preserved in the event of 64162306a36Sopenharmony_ci * the qset's reincarnation, for example during EEH recovery. 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_cistatic void t3_reset_qset(struct sge_qset *q) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci if (q->adap && 64662306a36Sopenharmony_ci !(q->adap->flags & NAPI_INIT)) { 64762306a36Sopenharmony_ci memset(q, 0, sizeof(*q)); 64862306a36Sopenharmony_ci return; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci q->adap = NULL; 65262306a36Sopenharmony_ci memset(&q->rspq, 0, sizeof(q->rspq)); 65362306a36Sopenharmony_ci memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET); 65462306a36Sopenharmony_ci memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); 65562306a36Sopenharmony_ci q->txq_stopped = 0; 65662306a36Sopenharmony_ci q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ 65762306a36Sopenharmony_ci q->rx_reclaim_timer.function = NULL; 65862306a36Sopenharmony_ci q->nomem = 0; 65962306a36Sopenharmony_ci napi_free_frags(&q->napi); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci/** 66462306a36Sopenharmony_ci * t3_free_qset - free the resources of an SGE queue set 66562306a36Sopenharmony_ci * @adapter: the adapter owning the queue set 66662306a36Sopenharmony_ci * @q: the queue set 66762306a36Sopenharmony_ci * 66862306a36Sopenharmony_ci * Release the HW and SW resources associated with an SGE queue set, such 66962306a36Sopenharmony_ci * as HW contexts, packet buffers, and descriptor rings. Traffic to the 67062306a36Sopenharmony_ci * queue set must be quiesced prior to calling this. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_cistatic void t3_free_qset(struct adapter *adapter, struct sge_qset *q) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci int i; 67562306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci for (i = 0; i < SGE_RXQ_PER_SET; ++i) 67862306a36Sopenharmony_ci if (q->fl[i].desc) { 67962306a36Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 68062306a36Sopenharmony_ci t3_sge_disable_fl(adapter, q->fl[i].cntxt_id); 68162306a36Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 68262306a36Sopenharmony_ci free_rx_bufs(pdev, &q->fl[i]); 68362306a36Sopenharmony_ci kfree(q->fl[i].sdesc); 68462306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, 68562306a36Sopenharmony_ci q->fl[i].size * 68662306a36Sopenharmony_ci sizeof(struct rx_desc), q->fl[i].desc, 68762306a36Sopenharmony_ci q->fl[i].phys_addr); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci for (i = 0; i < SGE_TXQ_PER_SET; ++i) 69162306a36Sopenharmony_ci if (q->txq[i].desc) { 69262306a36Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 69362306a36Sopenharmony_ci t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0); 69462306a36Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 69562306a36Sopenharmony_ci if (q->txq[i].sdesc) { 69662306a36Sopenharmony_ci free_tx_desc(adapter, &q->txq[i], 69762306a36Sopenharmony_ci q->txq[i].in_use); 69862306a36Sopenharmony_ci kfree(q->txq[i].sdesc); 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, 70162306a36Sopenharmony_ci q->txq[i].size * 70262306a36Sopenharmony_ci sizeof(struct tx_desc), 70362306a36Sopenharmony_ci q->txq[i].desc, q->txq[i].phys_addr); 70462306a36Sopenharmony_ci __skb_queue_purge(&q->txq[i].sendq); 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (q->rspq.desc) { 70862306a36Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 70962306a36Sopenharmony_ci t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id); 71062306a36Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 71162306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, 71262306a36Sopenharmony_ci q->rspq.size * sizeof(struct rsp_desc), 71362306a36Sopenharmony_ci q->rspq.desc, q->rspq.phys_addr); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci t3_reset_qset(q); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci/** 72062306a36Sopenharmony_ci * init_qset_cntxt - initialize an SGE queue set context info 72162306a36Sopenharmony_ci * @qs: the queue set 72262306a36Sopenharmony_ci * @id: the queue set id 72362306a36Sopenharmony_ci * 72462306a36Sopenharmony_ci * Initializes the TIDs and context ids for the queues of a queue set. 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_cistatic void init_qset_cntxt(struct sge_qset *qs, unsigned int id) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci qs->rspq.cntxt_id = id; 72962306a36Sopenharmony_ci qs->fl[0].cntxt_id = 2 * id; 73062306a36Sopenharmony_ci qs->fl[1].cntxt_id = 2 * id + 1; 73162306a36Sopenharmony_ci qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id; 73262306a36Sopenharmony_ci qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id; 73362306a36Sopenharmony_ci qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id; 73462306a36Sopenharmony_ci qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id; 73562306a36Sopenharmony_ci qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci/** 73962306a36Sopenharmony_ci * sgl_len - calculates the size of an SGL of the given capacity 74062306a36Sopenharmony_ci * @n: the number of SGL entries 74162306a36Sopenharmony_ci * 74262306a36Sopenharmony_ci * Calculates the number of flits needed for a scatter/gather list that 74362306a36Sopenharmony_ci * can hold the given number of entries. 74462306a36Sopenharmony_ci */ 74562306a36Sopenharmony_cistatic inline unsigned int sgl_len(unsigned int n) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci /* alternatively: 3 * (n / 2) + 2 * (n & 1) */ 74862306a36Sopenharmony_ci return (3 * n) / 2 + (n & 1); 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci/** 75262306a36Sopenharmony_ci * flits_to_desc - returns the num of Tx descriptors for the given flits 75362306a36Sopenharmony_ci * @n: the number of flits 75462306a36Sopenharmony_ci * 75562306a36Sopenharmony_ci * Calculates the number of Tx descriptors needed for the supplied number 75662306a36Sopenharmony_ci * of flits. 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_cistatic inline unsigned int flits_to_desc(unsigned int n) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci BUG_ON(n >= ARRAY_SIZE(flit_desc_map)); 76162306a36Sopenharmony_ci return flit_desc_map[n]; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci/** 76562306a36Sopenharmony_ci * get_packet - return the next ingress packet buffer from a free list 76662306a36Sopenharmony_ci * @adap: the adapter that received the packet 76762306a36Sopenharmony_ci * @fl: the SGE free list holding the packet 76862306a36Sopenharmony_ci * @len: the packet length including any SGE padding 76962306a36Sopenharmony_ci * @drop_thres: # of remaining buffers before we start dropping packets 77062306a36Sopenharmony_ci * 77162306a36Sopenharmony_ci * Get the next packet from a free list and complete setup of the 77262306a36Sopenharmony_ci * sk_buff. If the packet is small we make a copy and recycle the 77362306a36Sopenharmony_ci * original buffer, otherwise we use the original buffer itself. If a 77462306a36Sopenharmony_ci * positive drop threshold is supplied packets are dropped and their 77562306a36Sopenharmony_ci * buffers recycled if (a) the number of remaining buffers is under the 77662306a36Sopenharmony_ci * threshold and the packet is too big to copy, or (b) the packet should 77762306a36Sopenharmony_ci * be copied but there is no memory for the copy. 77862306a36Sopenharmony_ci */ 77962306a36Sopenharmony_cistatic struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, 78062306a36Sopenharmony_ci unsigned int len, unsigned int drop_thres) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci struct sk_buff *skb = NULL; 78362306a36Sopenharmony_ci struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci prefetch(sd->skb->data); 78662306a36Sopenharmony_ci fl->credits--; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (len <= SGE_RX_COPY_THRES) { 78962306a36Sopenharmony_ci skb = alloc_skb(len, GFP_ATOMIC); 79062306a36Sopenharmony_ci if (likely(skb != NULL)) { 79162306a36Sopenharmony_ci __skb_put(skb, len); 79262306a36Sopenharmony_ci dma_sync_single_for_cpu(&adap->pdev->dev, 79362306a36Sopenharmony_ci dma_unmap_addr(sd, dma_addr), 79462306a36Sopenharmony_ci len, DMA_FROM_DEVICE); 79562306a36Sopenharmony_ci memcpy(skb->data, sd->skb->data, len); 79662306a36Sopenharmony_ci dma_sync_single_for_device(&adap->pdev->dev, 79762306a36Sopenharmony_ci dma_unmap_addr(sd, dma_addr), 79862306a36Sopenharmony_ci len, DMA_FROM_DEVICE); 79962306a36Sopenharmony_ci } else if (!drop_thres) 80062306a36Sopenharmony_ci goto use_orig_buf; 80162306a36Sopenharmony_cirecycle: 80262306a36Sopenharmony_ci recycle_rx_buf(adap, fl, fl->cidx); 80362306a36Sopenharmony_ci return skb; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (unlikely(fl->credits < drop_thres) && 80762306a36Sopenharmony_ci refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits - 1), 80862306a36Sopenharmony_ci GFP_ATOMIC | __GFP_COMP) == 0) 80962306a36Sopenharmony_ci goto recycle; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ciuse_orig_buf: 81262306a36Sopenharmony_ci dma_unmap_single(&adap->pdev->dev, dma_unmap_addr(sd, dma_addr), 81362306a36Sopenharmony_ci fl->buf_size, DMA_FROM_DEVICE); 81462306a36Sopenharmony_ci skb = sd->skb; 81562306a36Sopenharmony_ci skb_put(skb, len); 81662306a36Sopenharmony_ci __refill_fl(adap, fl); 81762306a36Sopenharmony_ci return skb; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci/** 82162306a36Sopenharmony_ci * get_packet_pg - return the next ingress packet buffer from a free list 82262306a36Sopenharmony_ci * @adap: the adapter that received the packet 82362306a36Sopenharmony_ci * @fl: the SGE free list holding the packet 82462306a36Sopenharmony_ci * @q: the queue 82562306a36Sopenharmony_ci * @len: the packet length including any SGE padding 82662306a36Sopenharmony_ci * @drop_thres: # of remaining buffers before we start dropping packets 82762306a36Sopenharmony_ci * 82862306a36Sopenharmony_ci * Get the next packet from a free list populated with page chunks. 82962306a36Sopenharmony_ci * If the packet is small we make a copy and recycle the original buffer, 83062306a36Sopenharmony_ci * otherwise we attach the original buffer as a page fragment to a fresh 83162306a36Sopenharmony_ci * sk_buff. If a positive drop threshold is supplied packets are dropped 83262306a36Sopenharmony_ci * and their buffers recycled if (a) the number of remaining buffers is 83362306a36Sopenharmony_ci * under the threshold and the packet is too big to copy, or (b) there's 83462306a36Sopenharmony_ci * no system memory. 83562306a36Sopenharmony_ci * 83662306a36Sopenharmony_ci * Note: this function is similar to @get_packet but deals with Rx buffers 83762306a36Sopenharmony_ci * that are page chunks rather than sk_buffs. 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_cistatic struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, 84062306a36Sopenharmony_ci struct sge_rspq *q, unsigned int len, 84162306a36Sopenharmony_ci unsigned int drop_thres) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci struct sk_buff *newskb, *skb; 84462306a36Sopenharmony_ci struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci dma_addr_t dma_addr = dma_unmap_addr(sd, dma_addr); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci newskb = skb = q->pg_skb; 84962306a36Sopenharmony_ci if (!skb && (len <= SGE_RX_COPY_THRES)) { 85062306a36Sopenharmony_ci newskb = alloc_skb(len, GFP_ATOMIC); 85162306a36Sopenharmony_ci if (likely(newskb != NULL)) { 85262306a36Sopenharmony_ci __skb_put(newskb, len); 85362306a36Sopenharmony_ci dma_sync_single_for_cpu(&adap->pdev->dev, dma_addr, 85462306a36Sopenharmony_ci len, DMA_FROM_DEVICE); 85562306a36Sopenharmony_ci memcpy(newskb->data, sd->pg_chunk.va, len); 85662306a36Sopenharmony_ci dma_sync_single_for_device(&adap->pdev->dev, dma_addr, 85762306a36Sopenharmony_ci len, DMA_FROM_DEVICE); 85862306a36Sopenharmony_ci } else if (!drop_thres) 85962306a36Sopenharmony_ci return NULL; 86062306a36Sopenharmony_cirecycle: 86162306a36Sopenharmony_ci fl->credits--; 86262306a36Sopenharmony_ci recycle_rx_buf(adap, fl, fl->cidx); 86362306a36Sopenharmony_ci q->rx_recycle_buf++; 86462306a36Sopenharmony_ci return newskb; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) 86862306a36Sopenharmony_ci goto recycle; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci prefetch(sd->pg_chunk.p_cnt); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (!skb) 87362306a36Sopenharmony_ci newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (unlikely(!newskb)) { 87662306a36Sopenharmony_ci if (!drop_thres) 87762306a36Sopenharmony_ci return NULL; 87862306a36Sopenharmony_ci goto recycle; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci dma_sync_single_for_cpu(&adap->pdev->dev, dma_addr, len, 88262306a36Sopenharmony_ci DMA_FROM_DEVICE); 88362306a36Sopenharmony_ci (*sd->pg_chunk.p_cnt)--; 88462306a36Sopenharmony_ci if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) 88562306a36Sopenharmony_ci dma_unmap_page(&adap->pdev->dev, sd->pg_chunk.mapping, 88662306a36Sopenharmony_ci fl->alloc_size, DMA_FROM_DEVICE); 88762306a36Sopenharmony_ci if (!skb) { 88862306a36Sopenharmony_ci __skb_put(newskb, SGE_RX_PULL_LEN); 88962306a36Sopenharmony_ci memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); 89062306a36Sopenharmony_ci skb_fill_page_desc(newskb, 0, sd->pg_chunk.page, 89162306a36Sopenharmony_ci sd->pg_chunk.offset + SGE_RX_PULL_LEN, 89262306a36Sopenharmony_ci len - SGE_RX_PULL_LEN); 89362306a36Sopenharmony_ci newskb->len = len; 89462306a36Sopenharmony_ci newskb->data_len = len - SGE_RX_PULL_LEN; 89562306a36Sopenharmony_ci newskb->truesize += newskb->data_len; 89662306a36Sopenharmony_ci } else { 89762306a36Sopenharmony_ci skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags, 89862306a36Sopenharmony_ci sd->pg_chunk.page, 89962306a36Sopenharmony_ci sd->pg_chunk.offset, len); 90062306a36Sopenharmony_ci newskb->len += len; 90162306a36Sopenharmony_ci newskb->data_len += len; 90262306a36Sopenharmony_ci newskb->truesize += len; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci fl->credits--; 90662306a36Sopenharmony_ci /* 90762306a36Sopenharmony_ci * We do not refill FLs here, we let the caller do it to overlap a 90862306a36Sopenharmony_ci * prefetch. 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_ci return newskb; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci/** 91462306a36Sopenharmony_ci * get_imm_packet - return the next ingress packet buffer from a response 91562306a36Sopenharmony_ci * @resp: the response descriptor containing the packet data 91662306a36Sopenharmony_ci * 91762306a36Sopenharmony_ci * Return a packet containing the immediate data of the given response. 91862306a36Sopenharmony_ci */ 91962306a36Sopenharmony_cistatic inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (skb) { 92462306a36Sopenharmony_ci __skb_put(skb, IMMED_PKT_SIZE); 92562306a36Sopenharmony_ci BUILD_BUG_ON(IMMED_PKT_SIZE != sizeof(resp->immediate)); 92662306a36Sopenharmony_ci skb_copy_to_linear_data(skb, &resp->immediate, IMMED_PKT_SIZE); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci return skb; 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci/** 93262306a36Sopenharmony_ci * calc_tx_descs - calculate the number of Tx descriptors for a packet 93362306a36Sopenharmony_ci * @skb: the packet 93462306a36Sopenharmony_ci * 93562306a36Sopenharmony_ci * Returns the number of Tx descriptors needed for the given Ethernet 93662306a36Sopenharmony_ci * packet. Ethernet packets require addition of WR and CPL headers. 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_cistatic inline unsigned int calc_tx_descs(const struct sk_buff *skb) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci unsigned int flits; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt)) 94362306a36Sopenharmony_ci return 1; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2; 94662306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size) 94762306a36Sopenharmony_ci flits++; 94862306a36Sopenharmony_ci return flits_to_desc(flits); 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci/* map_skb - map a packet main body and its page fragments 95262306a36Sopenharmony_ci * @pdev: the PCI device 95362306a36Sopenharmony_ci * @skb: the packet 95462306a36Sopenharmony_ci * @addr: placeholder to save the mapped addresses 95562306a36Sopenharmony_ci * 95662306a36Sopenharmony_ci * map the main body of an sk_buff and its page fragments, if any. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_cistatic int map_skb(struct pci_dev *pdev, const struct sk_buff *skb, 95962306a36Sopenharmony_ci dma_addr_t *addr) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci const skb_frag_t *fp, *end; 96262306a36Sopenharmony_ci const struct skb_shared_info *si; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (skb_headlen(skb)) { 96562306a36Sopenharmony_ci *addr = dma_map_single(&pdev->dev, skb->data, 96662306a36Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 96762306a36Sopenharmony_ci if (dma_mapping_error(&pdev->dev, *addr)) 96862306a36Sopenharmony_ci goto out_err; 96962306a36Sopenharmony_ci addr++; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci si = skb_shinfo(skb); 97362306a36Sopenharmony_ci end = &si->frags[si->nr_frags]; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci for (fp = si->frags; fp < end; fp++) { 97662306a36Sopenharmony_ci *addr = skb_frag_dma_map(&pdev->dev, fp, 0, skb_frag_size(fp), 97762306a36Sopenharmony_ci DMA_TO_DEVICE); 97862306a36Sopenharmony_ci if (dma_mapping_error(&pdev->dev, *addr)) 97962306a36Sopenharmony_ci goto unwind; 98062306a36Sopenharmony_ci addr++; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci return 0; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ciunwind: 98562306a36Sopenharmony_ci while (fp-- > si->frags) 98662306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, *--addr, skb_frag_size(fp), 98762306a36Sopenharmony_ci DMA_TO_DEVICE); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, addr[-1], skb_headlen(skb), 99062306a36Sopenharmony_ci DMA_TO_DEVICE); 99162306a36Sopenharmony_ciout_err: 99262306a36Sopenharmony_ci return -ENOMEM; 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci/** 99662306a36Sopenharmony_ci * write_sgl - populate a scatter/gather list for a packet 99762306a36Sopenharmony_ci * @skb: the packet 99862306a36Sopenharmony_ci * @sgp: the SGL to populate 99962306a36Sopenharmony_ci * @start: start address of skb main body data to include in the SGL 100062306a36Sopenharmony_ci * @len: length of skb main body data to include in the SGL 100162306a36Sopenharmony_ci * @addr: the list of the mapped addresses 100262306a36Sopenharmony_ci * 100362306a36Sopenharmony_ci * Copies the scatter/gather list for the buffers that make up a packet 100462306a36Sopenharmony_ci * and returns the SGL size in 8-byte words. The caller must size the SGL 100562306a36Sopenharmony_ci * appropriately. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_cistatic inline unsigned int write_sgl(const struct sk_buff *skb, 100862306a36Sopenharmony_ci struct sg_ent *sgp, unsigned char *start, 100962306a36Sopenharmony_ci unsigned int len, const dma_addr_t *addr) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci unsigned int i, j = 0, k = 0, nfrags; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (len) { 101462306a36Sopenharmony_ci sgp->len[0] = cpu_to_be32(len); 101562306a36Sopenharmony_ci sgp->addr[j++] = cpu_to_be64(addr[k++]); 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci nfrags = skb_shinfo(skb)->nr_frags; 101962306a36Sopenharmony_ci for (i = 0; i < nfrags; i++) { 102062306a36Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci sgp->len[j] = cpu_to_be32(skb_frag_size(frag)); 102362306a36Sopenharmony_ci sgp->addr[j] = cpu_to_be64(addr[k++]); 102462306a36Sopenharmony_ci j ^= 1; 102562306a36Sopenharmony_ci if (j == 0) 102662306a36Sopenharmony_ci ++sgp; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci if (j) 102962306a36Sopenharmony_ci sgp->len[j] = 0; 103062306a36Sopenharmony_ci return ((nfrags + (len != 0)) * 3) / 2 + j; 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci/** 103462306a36Sopenharmony_ci * check_ring_tx_db - check and potentially ring a Tx queue's doorbell 103562306a36Sopenharmony_ci * @adap: the adapter 103662306a36Sopenharmony_ci * @q: the Tx queue 103762306a36Sopenharmony_ci * 103862306a36Sopenharmony_ci * Ring the doorbel if a Tx queue is asleep. There is a natural race, 103962306a36Sopenharmony_ci * where the HW is going to sleep just after we checked, however, 104062306a36Sopenharmony_ci * then the interrupt handler will detect the outstanding TX packet 104162306a36Sopenharmony_ci * and ring the doorbell for us. 104262306a36Sopenharmony_ci * 104362306a36Sopenharmony_ci * When GTS is disabled we unconditionally ring the doorbell. 104462306a36Sopenharmony_ci */ 104562306a36Sopenharmony_cistatic inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci#if USE_GTS 104862306a36Sopenharmony_ci clear_bit(TXQ_LAST_PKT_DB, &q->flags); 104962306a36Sopenharmony_ci if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) { 105062306a36Sopenharmony_ci set_bit(TXQ_LAST_PKT_DB, &q->flags); 105162306a36Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, 105262306a36Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci#else 105562306a36Sopenharmony_ci wmb(); /* write descriptors before telling HW */ 105662306a36Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, 105762306a36Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 105862306a36Sopenharmony_ci#endif 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic inline void wr_gen2(struct tx_desc *d, unsigned int gen) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci#if SGE_NUM_GENBITS == 2 106462306a36Sopenharmony_ci d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen); 106562306a36Sopenharmony_ci#endif 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci/** 106962306a36Sopenharmony_ci * write_wr_hdr_sgl - write a WR header and, optionally, SGL 107062306a36Sopenharmony_ci * @ndesc: number of Tx descriptors spanned by the SGL 107162306a36Sopenharmony_ci * @skb: the packet corresponding to the WR 107262306a36Sopenharmony_ci * @d: first Tx descriptor to be written 107362306a36Sopenharmony_ci * @pidx: index of above descriptors 107462306a36Sopenharmony_ci * @q: the SGE Tx queue 107562306a36Sopenharmony_ci * @sgl: the SGL 107662306a36Sopenharmony_ci * @flits: number of flits to the start of the SGL in the first descriptor 107762306a36Sopenharmony_ci * @sgl_flits: the SGL size in flits 107862306a36Sopenharmony_ci * @gen: the Tx descriptor generation 107962306a36Sopenharmony_ci * @wr_hi: top 32 bits of WR header based on WR type (big endian) 108062306a36Sopenharmony_ci * @wr_lo: low 32 bits of WR header based on WR type (big endian) 108162306a36Sopenharmony_ci * 108262306a36Sopenharmony_ci * Write a work request header and an associated SGL. If the SGL is 108362306a36Sopenharmony_ci * small enough to fit into one Tx descriptor it has already been written 108462306a36Sopenharmony_ci * and we just need to write the WR header. Otherwise we distribute the 108562306a36Sopenharmony_ci * SGL across the number of descriptors it spans. 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_cistatic void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, 108862306a36Sopenharmony_ci struct tx_desc *d, unsigned int pidx, 108962306a36Sopenharmony_ci const struct sge_txq *q, 109062306a36Sopenharmony_ci const struct sg_ent *sgl, 109162306a36Sopenharmony_ci unsigned int flits, unsigned int sgl_flits, 109262306a36Sopenharmony_ci unsigned int gen, __be32 wr_hi, 109362306a36Sopenharmony_ci __be32 wr_lo) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci struct work_request_hdr *wrp = (struct work_request_hdr *)d; 109662306a36Sopenharmony_ci struct tx_sw_desc *sd = &q->sdesc[pidx]; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci sd->skb = skb; 109962306a36Sopenharmony_ci if (need_skb_unmap()) { 110062306a36Sopenharmony_ci sd->fragidx = 0; 110162306a36Sopenharmony_ci sd->addr_idx = 0; 110262306a36Sopenharmony_ci sd->sflit = flits; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (likely(ndesc == 1)) { 110662306a36Sopenharmony_ci sd->eop = 1; 110762306a36Sopenharmony_ci wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | 110862306a36Sopenharmony_ci V_WR_SGLSFLT(flits)) | wr_hi; 110962306a36Sopenharmony_ci dma_wmb(); 111062306a36Sopenharmony_ci wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) | 111162306a36Sopenharmony_ci V_WR_GEN(gen)) | wr_lo; 111262306a36Sopenharmony_ci wr_gen2(d, gen); 111362306a36Sopenharmony_ci } else { 111462306a36Sopenharmony_ci unsigned int ogen = gen; 111562306a36Sopenharmony_ci const u64 *fp = (const u64 *)sgl; 111662306a36Sopenharmony_ci struct work_request_hdr *wp = wrp; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) | 111962306a36Sopenharmony_ci V_WR_SGLSFLT(flits)) | wr_hi; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci while (sgl_flits) { 112262306a36Sopenharmony_ci unsigned int avail = WR_FLITS - flits; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (avail > sgl_flits) 112562306a36Sopenharmony_ci avail = sgl_flits; 112662306a36Sopenharmony_ci memcpy(&d->flit[flits], fp, avail * sizeof(*fp)); 112762306a36Sopenharmony_ci sgl_flits -= avail; 112862306a36Sopenharmony_ci ndesc--; 112962306a36Sopenharmony_ci if (!sgl_flits) 113062306a36Sopenharmony_ci break; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci fp += avail; 113362306a36Sopenharmony_ci d++; 113462306a36Sopenharmony_ci sd->eop = 0; 113562306a36Sopenharmony_ci sd++; 113662306a36Sopenharmony_ci if (++pidx == q->size) { 113762306a36Sopenharmony_ci pidx = 0; 113862306a36Sopenharmony_ci gen ^= 1; 113962306a36Sopenharmony_ci d = q->desc; 114062306a36Sopenharmony_ci sd = q->sdesc; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci sd->skb = skb; 114462306a36Sopenharmony_ci wrp = (struct work_request_hdr *)d; 114562306a36Sopenharmony_ci wrp->wr_hi = htonl(V_WR_DATATYPE(1) | 114662306a36Sopenharmony_ci V_WR_SGLSFLT(1)) | wr_hi; 114762306a36Sopenharmony_ci wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS, 114862306a36Sopenharmony_ci sgl_flits + 1)) | 114962306a36Sopenharmony_ci V_WR_GEN(gen)) | wr_lo; 115062306a36Sopenharmony_ci wr_gen2(d, gen); 115162306a36Sopenharmony_ci flits = 1; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci sd->eop = 1; 115462306a36Sopenharmony_ci wrp->wr_hi |= htonl(F_WR_EOP); 115562306a36Sopenharmony_ci dma_wmb(); 115662306a36Sopenharmony_ci wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; 115762306a36Sopenharmony_ci wr_gen2((struct tx_desc *)wp, ogen); 115862306a36Sopenharmony_ci WARN_ON(ndesc != 0); 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci/** 116362306a36Sopenharmony_ci * write_tx_pkt_wr - write a TX_PKT work request 116462306a36Sopenharmony_ci * @adap: the adapter 116562306a36Sopenharmony_ci * @skb: the packet to send 116662306a36Sopenharmony_ci * @pi: the egress interface 116762306a36Sopenharmony_ci * @pidx: index of the first Tx descriptor to write 116862306a36Sopenharmony_ci * @gen: the generation value to use 116962306a36Sopenharmony_ci * @q: the Tx queue 117062306a36Sopenharmony_ci * @ndesc: number of descriptors the packet will occupy 117162306a36Sopenharmony_ci * @compl: the value of the COMPL bit to use 117262306a36Sopenharmony_ci * @addr: address 117362306a36Sopenharmony_ci * 117462306a36Sopenharmony_ci * Generate a TX_PKT work request to send the supplied packet. 117562306a36Sopenharmony_ci */ 117662306a36Sopenharmony_cistatic void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, 117762306a36Sopenharmony_ci const struct port_info *pi, 117862306a36Sopenharmony_ci unsigned int pidx, unsigned int gen, 117962306a36Sopenharmony_ci struct sge_txq *q, unsigned int ndesc, 118062306a36Sopenharmony_ci unsigned int compl, const dma_addr_t *addr) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci unsigned int flits, sgl_flits, cntrl, tso_info; 118362306a36Sopenharmony_ci struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; 118462306a36Sopenharmony_ci struct tx_desc *d = &q->desc[pidx]; 118562306a36Sopenharmony_ci struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci cpl->len = htonl(skb->len); 118862306a36Sopenharmony_ci cntrl = V_TXPKT_INTF(pi->port_id); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) 119162306a36Sopenharmony_ci cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(skb_vlan_tag_get(skb)); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size); 119462306a36Sopenharmony_ci if (tso_info) { 119562306a36Sopenharmony_ci int eth_type; 119662306a36Sopenharmony_ci struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci d->flit[2] = 0; 119962306a36Sopenharmony_ci cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO); 120062306a36Sopenharmony_ci hdr->cntrl = htonl(cntrl); 120162306a36Sopenharmony_ci eth_type = skb_network_offset(skb) == ETH_HLEN ? 120262306a36Sopenharmony_ci CPL_ETH_II : CPL_ETH_II_VLAN; 120362306a36Sopenharmony_ci tso_info |= V_LSO_ETH_TYPE(eth_type) | 120462306a36Sopenharmony_ci V_LSO_IPHDR_WORDS(ip_hdr(skb)->ihl) | 120562306a36Sopenharmony_ci V_LSO_TCPHDR_WORDS(tcp_hdr(skb)->doff); 120662306a36Sopenharmony_ci hdr->lso_info = htonl(tso_info); 120762306a36Sopenharmony_ci flits = 3; 120862306a36Sopenharmony_ci } else { 120962306a36Sopenharmony_ci cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT); 121062306a36Sopenharmony_ci cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */ 121162306a36Sopenharmony_ci cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL); 121262306a36Sopenharmony_ci cpl->cntrl = htonl(cntrl); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (skb->len <= WR_LEN - sizeof(*cpl)) { 121562306a36Sopenharmony_ci q->sdesc[pidx].skb = NULL; 121662306a36Sopenharmony_ci if (!skb->data_len) 121762306a36Sopenharmony_ci skb_copy_from_linear_data(skb, &d->flit[2], 121862306a36Sopenharmony_ci skb->len); 121962306a36Sopenharmony_ci else 122062306a36Sopenharmony_ci skb_copy_bits(skb, 0, &d->flit[2], skb->len); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci flits = (skb->len + 7) / 8 + 2; 122362306a36Sopenharmony_ci cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) | 122462306a36Sopenharmony_ci V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) 122562306a36Sopenharmony_ci | F_WR_SOP | F_WR_EOP | compl); 122662306a36Sopenharmony_ci dma_wmb(); 122762306a36Sopenharmony_ci cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) | 122862306a36Sopenharmony_ci V_WR_TID(q->token)); 122962306a36Sopenharmony_ci wr_gen2(d, gen); 123062306a36Sopenharmony_ci dev_consume_skb_any(skb); 123162306a36Sopenharmony_ci return; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci flits = 2; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; 123862306a36Sopenharmony_ci sgl_flits = write_sgl(skb, sgp, skb->data, skb_headlen(skb), addr); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, 124162306a36Sopenharmony_ci htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), 124262306a36Sopenharmony_ci htonl(V_WR_TID(q->token))); 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_cistatic inline void t3_stop_tx_queue(struct netdev_queue *txq, 124662306a36Sopenharmony_ci struct sge_qset *qs, struct sge_txq *q) 124762306a36Sopenharmony_ci{ 124862306a36Sopenharmony_ci netif_tx_stop_queue(txq); 124962306a36Sopenharmony_ci set_bit(TXQ_ETH, &qs->txq_stopped); 125062306a36Sopenharmony_ci q->stops++; 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci/** 125462306a36Sopenharmony_ci * t3_eth_xmit - add a packet to the Ethernet Tx queue 125562306a36Sopenharmony_ci * @skb: the packet 125662306a36Sopenharmony_ci * @dev: the egress net device 125762306a36Sopenharmony_ci * 125862306a36Sopenharmony_ci * Add a packet to an SGE Tx queue. Runs with softirqs disabled. 125962306a36Sopenharmony_ci */ 126062306a36Sopenharmony_cinetdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci int qidx; 126362306a36Sopenharmony_ci unsigned int ndesc, pidx, credits, gen, compl; 126462306a36Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 126562306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 126662306a36Sopenharmony_ci struct netdev_queue *txq; 126762306a36Sopenharmony_ci struct sge_qset *qs; 126862306a36Sopenharmony_ci struct sge_txq *q; 126962306a36Sopenharmony_ci dma_addr_t addr[MAX_SKB_FRAGS + 1]; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci /* 127262306a36Sopenharmony_ci * The chip min packet length is 9 octets but play safe and reject 127362306a36Sopenharmony_ci * anything shorter than an Ethernet header. 127462306a36Sopenharmony_ci */ 127562306a36Sopenharmony_ci if (unlikely(skb->len < ETH_HLEN)) { 127662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 127762306a36Sopenharmony_ci return NETDEV_TX_OK; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci qidx = skb_get_queue_mapping(skb); 128162306a36Sopenharmony_ci qs = &pi->qs[qidx]; 128262306a36Sopenharmony_ci q = &qs->txq[TXQ_ETH]; 128362306a36Sopenharmony_ci txq = netdev_get_tx_queue(dev, qidx); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci credits = q->size - q->in_use; 128862306a36Sopenharmony_ci ndesc = calc_tx_descs(skb); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (unlikely(credits < ndesc)) { 129162306a36Sopenharmony_ci t3_stop_tx_queue(txq, qs, q); 129262306a36Sopenharmony_ci dev_err(&adap->pdev->dev, 129362306a36Sopenharmony_ci "%s: Tx ring %u full while queue awake!\n", 129462306a36Sopenharmony_ci dev->name, q->cntxt_id & 7); 129562306a36Sopenharmony_ci return NETDEV_TX_BUSY; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* Check if ethernet packet can't be sent as immediate data */ 129962306a36Sopenharmony_ci if (skb->len > (WR_LEN - sizeof(struct cpl_tx_pkt))) { 130062306a36Sopenharmony_ci if (unlikely(map_skb(adap->pdev, skb, addr) < 0)) { 130162306a36Sopenharmony_ci dev_kfree_skb(skb); 130262306a36Sopenharmony_ci return NETDEV_TX_OK; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci q->in_use += ndesc; 130762306a36Sopenharmony_ci if (unlikely(credits - ndesc < q->stop_thres)) { 130862306a36Sopenharmony_ci t3_stop_tx_queue(txq, qs, q); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (should_restart_tx(q) && 131162306a36Sopenharmony_ci test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { 131262306a36Sopenharmony_ci q->restarts++; 131362306a36Sopenharmony_ci netif_tx_start_queue(txq); 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci gen = q->gen; 131862306a36Sopenharmony_ci q->unacked += ndesc; 131962306a36Sopenharmony_ci compl = (q->unacked & 8) << (S_WR_COMPL - 3); 132062306a36Sopenharmony_ci q->unacked &= 7; 132162306a36Sopenharmony_ci pidx = q->pidx; 132262306a36Sopenharmony_ci q->pidx += ndesc; 132362306a36Sopenharmony_ci if (q->pidx >= q->size) { 132462306a36Sopenharmony_ci q->pidx -= q->size; 132562306a36Sopenharmony_ci q->gen ^= 1; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci /* update port statistics */ 132962306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 133062306a36Sopenharmony_ci qs->port_stats[SGE_PSTAT_TX_CSUM]++; 133162306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size) 133262306a36Sopenharmony_ci qs->port_stats[SGE_PSTAT_TSO]++; 133362306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) 133462306a36Sopenharmony_ci qs->port_stats[SGE_PSTAT_VLANINS]++; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci /* 133762306a36Sopenharmony_ci * We do not use Tx completion interrupts to free DMAd Tx packets. 133862306a36Sopenharmony_ci * This is good for performance but means that we rely on new Tx 133962306a36Sopenharmony_ci * packets arriving to run the destructors of completed packets, 134062306a36Sopenharmony_ci * which open up space in their sockets' send queues. Sometimes 134162306a36Sopenharmony_ci * we do not get such new packets causing Tx to stall. A single 134262306a36Sopenharmony_ci * UDP transmitter is a good example of this situation. We have 134362306a36Sopenharmony_ci * a clean up timer that periodically reclaims completed packets 134462306a36Sopenharmony_ci * but it doesn't run often enough (nor do we want it to) to prevent 134562306a36Sopenharmony_ci * lengthy stalls. A solution to this problem is to run the 134662306a36Sopenharmony_ci * destructor early, after the packet is queued but before it's DMAd. 134762306a36Sopenharmony_ci * A cons is that we lie to socket memory accounting, but the amount 134862306a36Sopenharmony_ci * of extra memory is reasonable (limited by the number of Tx 134962306a36Sopenharmony_ci * descriptors), the packets do actually get freed quickly by new 135062306a36Sopenharmony_ci * packets almost always, and for protocols like TCP that wait for 135162306a36Sopenharmony_ci * acks to really free up the data the extra memory is even less. 135262306a36Sopenharmony_ci * On the positive side we run the destructors on the sending CPU 135362306a36Sopenharmony_ci * rather than on a potentially different completing CPU, usually a 135462306a36Sopenharmony_ci * good thing. We also run them without holding our Tx queue lock, 135562306a36Sopenharmony_ci * unlike what reclaim_completed_tx() would otherwise do. 135662306a36Sopenharmony_ci * 135762306a36Sopenharmony_ci * Run the destructor before telling the DMA engine about the packet 135862306a36Sopenharmony_ci * to make sure it doesn't complete and get freed prematurely. 135962306a36Sopenharmony_ci */ 136062306a36Sopenharmony_ci if (likely(!skb_shared(skb))) 136162306a36Sopenharmony_ci skb_orphan(skb); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl, addr); 136462306a36Sopenharmony_ci check_ring_tx_db(adap, q); 136562306a36Sopenharmony_ci return NETDEV_TX_OK; 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci/** 136962306a36Sopenharmony_ci * write_imm - write a packet into a Tx descriptor as immediate data 137062306a36Sopenharmony_ci * @d: the Tx descriptor to write 137162306a36Sopenharmony_ci * @skb: the packet 137262306a36Sopenharmony_ci * @len: the length of packet data to write as immediate data 137362306a36Sopenharmony_ci * @gen: the generation bit value to write 137462306a36Sopenharmony_ci * 137562306a36Sopenharmony_ci * Writes a packet as immediate data into a Tx descriptor. The packet 137662306a36Sopenharmony_ci * contains a work request at its beginning. We must write the packet 137762306a36Sopenharmony_ci * carefully so the SGE doesn't read it accidentally before it's written 137862306a36Sopenharmony_ci * in its entirety. 137962306a36Sopenharmony_ci */ 138062306a36Sopenharmony_cistatic inline void write_imm(struct tx_desc *d, struct sk_buff *skb, 138162306a36Sopenharmony_ci unsigned int len, unsigned int gen) 138262306a36Sopenharmony_ci{ 138362306a36Sopenharmony_ci struct work_request_hdr *from = (struct work_request_hdr *)skb->data; 138462306a36Sopenharmony_ci struct work_request_hdr *to = (struct work_request_hdr *)d; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (likely(!skb->data_len)) 138762306a36Sopenharmony_ci memcpy(&to[1], &from[1], len - sizeof(*from)); 138862306a36Sopenharmony_ci else 138962306a36Sopenharmony_ci skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from)); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | 139262306a36Sopenharmony_ci V_WR_BCNTLFLT(len & 7)); 139362306a36Sopenharmony_ci dma_wmb(); 139462306a36Sopenharmony_ci to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) | 139562306a36Sopenharmony_ci V_WR_LEN((len + 7) / 8)); 139662306a36Sopenharmony_ci wr_gen2(d, gen); 139762306a36Sopenharmony_ci kfree_skb(skb); 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci/** 140162306a36Sopenharmony_ci * check_desc_avail - check descriptor availability on a send queue 140262306a36Sopenharmony_ci * @adap: the adapter 140362306a36Sopenharmony_ci * @q: the send queue 140462306a36Sopenharmony_ci * @skb: the packet needing the descriptors 140562306a36Sopenharmony_ci * @ndesc: the number of Tx descriptors needed 140662306a36Sopenharmony_ci * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL) 140762306a36Sopenharmony_ci * 140862306a36Sopenharmony_ci * Checks if the requested number of Tx descriptors is available on an 140962306a36Sopenharmony_ci * SGE send queue. If the queue is already suspended or not enough 141062306a36Sopenharmony_ci * descriptors are available the packet is queued for later transmission. 141162306a36Sopenharmony_ci * Must be called with the Tx queue locked. 141262306a36Sopenharmony_ci * 141362306a36Sopenharmony_ci * Returns 0 if enough descriptors are available, 1 if there aren't 141462306a36Sopenharmony_ci * enough descriptors and the packet has been queued, and 2 if the caller 141562306a36Sopenharmony_ci * needs to retry because there weren't enough descriptors at the 141662306a36Sopenharmony_ci * beginning of the call but some freed up in the mean time. 141762306a36Sopenharmony_ci */ 141862306a36Sopenharmony_cistatic inline int check_desc_avail(struct adapter *adap, struct sge_txq *q, 141962306a36Sopenharmony_ci struct sk_buff *skb, unsigned int ndesc, 142062306a36Sopenharmony_ci unsigned int qid) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci if (unlikely(!skb_queue_empty(&q->sendq))) { 142362306a36Sopenharmony_ci addq_exit:__skb_queue_tail(&q->sendq, skb); 142462306a36Sopenharmony_ci return 1; 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci if (unlikely(q->size - q->in_use < ndesc)) { 142762306a36Sopenharmony_ci struct sge_qset *qs = txq_to_qset(q, qid); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci set_bit(qid, &qs->txq_stopped); 143062306a36Sopenharmony_ci smp_mb__after_atomic(); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci if (should_restart_tx(q) && 143362306a36Sopenharmony_ci test_and_clear_bit(qid, &qs->txq_stopped)) 143462306a36Sopenharmony_ci return 2; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci q->stops++; 143762306a36Sopenharmony_ci goto addq_exit; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci return 0; 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci/** 144362306a36Sopenharmony_ci * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs 144462306a36Sopenharmony_ci * @q: the SGE control Tx queue 144562306a36Sopenharmony_ci * 144662306a36Sopenharmony_ci * This is a variant of reclaim_completed_tx() that is used for Tx queues 144762306a36Sopenharmony_ci * that send only immediate data (presently just the control queues) and 144862306a36Sopenharmony_ci * thus do not have any sk_buffs to release. 144962306a36Sopenharmony_ci */ 145062306a36Sopenharmony_cistatic inline void reclaim_completed_tx_imm(struct sge_txq *q) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci unsigned int reclaim = q->processed - q->cleaned; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci q->in_use -= reclaim; 145562306a36Sopenharmony_ci q->cleaned += reclaim; 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_cistatic inline int immediate(const struct sk_buff *skb) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci return skb->len <= WR_LEN; 146162306a36Sopenharmony_ci} 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci/** 146462306a36Sopenharmony_ci * ctrl_xmit - send a packet through an SGE control Tx queue 146562306a36Sopenharmony_ci * @adap: the adapter 146662306a36Sopenharmony_ci * @q: the control queue 146762306a36Sopenharmony_ci * @skb: the packet 146862306a36Sopenharmony_ci * 146962306a36Sopenharmony_ci * Send a packet through an SGE control Tx queue. Packets sent through 147062306a36Sopenharmony_ci * a control queue must fit entirely as immediate data in a single Tx 147162306a36Sopenharmony_ci * descriptor and have no page fragments. 147262306a36Sopenharmony_ci */ 147362306a36Sopenharmony_cistatic int ctrl_xmit(struct adapter *adap, struct sge_txq *q, 147462306a36Sopenharmony_ci struct sk_buff *skb) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci int ret; 147762306a36Sopenharmony_ci struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci if (unlikely(!immediate(skb))) { 148062306a36Sopenharmony_ci WARN_ON(1); 148162306a36Sopenharmony_ci dev_kfree_skb(skb); 148262306a36Sopenharmony_ci return NET_XMIT_SUCCESS; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP); 148662306a36Sopenharmony_ci wrp->wr_lo = htonl(V_WR_TID(q->token)); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci spin_lock(&q->lock); 148962306a36Sopenharmony_ci again:reclaim_completed_tx_imm(q); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL); 149262306a36Sopenharmony_ci if (unlikely(ret)) { 149362306a36Sopenharmony_ci if (ret == 1) { 149462306a36Sopenharmony_ci spin_unlock(&q->lock); 149562306a36Sopenharmony_ci return NET_XMIT_CN; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci goto again; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci q->in_use++; 150362306a36Sopenharmony_ci if (++q->pidx >= q->size) { 150462306a36Sopenharmony_ci q->pidx = 0; 150562306a36Sopenharmony_ci q->gen ^= 1; 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci spin_unlock(&q->lock); 150862306a36Sopenharmony_ci wmb(); 150962306a36Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, 151062306a36Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 151162306a36Sopenharmony_ci return NET_XMIT_SUCCESS; 151262306a36Sopenharmony_ci} 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci/** 151562306a36Sopenharmony_ci * restart_ctrlq - restart a suspended control queue 151662306a36Sopenharmony_ci * @w: pointer to the work associated with this handler 151762306a36Sopenharmony_ci * 151862306a36Sopenharmony_ci * Resumes transmission on a suspended Tx control queue. 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_cistatic void restart_ctrlq(struct work_struct *w) 152162306a36Sopenharmony_ci{ 152262306a36Sopenharmony_ci struct sk_buff *skb; 152362306a36Sopenharmony_ci struct sge_qset *qs = container_of(w, struct sge_qset, 152462306a36Sopenharmony_ci txq[TXQ_CTRL].qresume_task); 152562306a36Sopenharmony_ci struct sge_txq *q = &qs->txq[TXQ_CTRL]; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci spin_lock(&q->lock); 152862306a36Sopenharmony_ci again:reclaim_completed_tx_imm(q); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci while (q->in_use < q->size && 153162306a36Sopenharmony_ci (skb = __skb_dequeue(&q->sendq)) != NULL) { 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci if (++q->pidx >= q->size) { 153662306a36Sopenharmony_ci q->pidx = 0; 153762306a36Sopenharmony_ci q->gen ^= 1; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci q->in_use++; 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci if (!skb_queue_empty(&q->sendq)) { 154362306a36Sopenharmony_ci set_bit(TXQ_CTRL, &qs->txq_stopped); 154462306a36Sopenharmony_ci smp_mb__after_atomic(); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci if (should_restart_tx(q) && 154762306a36Sopenharmony_ci test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) 154862306a36Sopenharmony_ci goto again; 154962306a36Sopenharmony_ci q->stops++; 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci spin_unlock(&q->lock); 155362306a36Sopenharmony_ci wmb(); 155462306a36Sopenharmony_ci t3_write_reg(qs->adap, A_SG_KDOORBELL, 155562306a36Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 155662306a36Sopenharmony_ci} 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci/* 155962306a36Sopenharmony_ci * Send a management message through control queue 0 156062306a36Sopenharmony_ci */ 156162306a36Sopenharmony_ciint t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci int ret; 156462306a36Sopenharmony_ci local_bh_disable(); 156562306a36Sopenharmony_ci ret = ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb); 156662306a36Sopenharmony_ci local_bh_enable(); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci return ret; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci/** 157262306a36Sopenharmony_ci * deferred_unmap_destructor - unmap a packet when it is freed 157362306a36Sopenharmony_ci * @skb: the packet 157462306a36Sopenharmony_ci * 157562306a36Sopenharmony_ci * This is the packet destructor used for Tx packets that need to remain 157662306a36Sopenharmony_ci * mapped until they are freed rather than until their Tx descriptors are 157762306a36Sopenharmony_ci * freed. 157862306a36Sopenharmony_ci */ 157962306a36Sopenharmony_cistatic void deferred_unmap_destructor(struct sk_buff *skb) 158062306a36Sopenharmony_ci{ 158162306a36Sopenharmony_ci int i; 158262306a36Sopenharmony_ci const dma_addr_t *p; 158362306a36Sopenharmony_ci const struct skb_shared_info *si; 158462306a36Sopenharmony_ci const struct deferred_unmap_info *dui; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci dui = (struct deferred_unmap_info *)skb->head; 158762306a36Sopenharmony_ci p = dui->addr; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci if (skb_tail_pointer(skb) - skb_transport_header(skb)) 159062306a36Sopenharmony_ci dma_unmap_single(&dui->pdev->dev, *p++, 159162306a36Sopenharmony_ci skb_tail_pointer(skb) - skb_transport_header(skb), 159262306a36Sopenharmony_ci DMA_TO_DEVICE); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci si = skb_shinfo(skb); 159562306a36Sopenharmony_ci for (i = 0; i < si->nr_frags; i++) 159662306a36Sopenharmony_ci dma_unmap_page(&dui->pdev->dev, *p++, 159762306a36Sopenharmony_ci skb_frag_size(&si->frags[i]), DMA_TO_DEVICE); 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev, 160162306a36Sopenharmony_ci const struct sg_ent *sgl, int sgl_flits) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci dma_addr_t *p; 160462306a36Sopenharmony_ci struct deferred_unmap_info *dui; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci dui = (struct deferred_unmap_info *)skb->head; 160762306a36Sopenharmony_ci dui->pdev = pdev; 160862306a36Sopenharmony_ci for (p = dui->addr; sgl_flits >= 3; sgl++, sgl_flits -= 3) { 160962306a36Sopenharmony_ci *p++ = be64_to_cpu(sgl->addr[0]); 161062306a36Sopenharmony_ci *p++ = be64_to_cpu(sgl->addr[1]); 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci if (sgl_flits) 161362306a36Sopenharmony_ci *p = be64_to_cpu(sgl->addr[0]); 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci/** 161762306a36Sopenharmony_ci * write_ofld_wr - write an offload work request 161862306a36Sopenharmony_ci * @adap: the adapter 161962306a36Sopenharmony_ci * @skb: the packet to send 162062306a36Sopenharmony_ci * @q: the Tx queue 162162306a36Sopenharmony_ci * @pidx: index of the first Tx descriptor to write 162262306a36Sopenharmony_ci * @gen: the generation value to use 162362306a36Sopenharmony_ci * @ndesc: number of descriptors the packet will occupy 162462306a36Sopenharmony_ci * @addr: the address 162562306a36Sopenharmony_ci * 162662306a36Sopenharmony_ci * Write an offload work request to send the supplied packet. The packet 162762306a36Sopenharmony_ci * data already carry the work request with most fields populated. 162862306a36Sopenharmony_ci */ 162962306a36Sopenharmony_cistatic void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, 163062306a36Sopenharmony_ci struct sge_txq *q, unsigned int pidx, 163162306a36Sopenharmony_ci unsigned int gen, unsigned int ndesc, 163262306a36Sopenharmony_ci const dma_addr_t *addr) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci unsigned int sgl_flits, flits; 163562306a36Sopenharmony_ci struct work_request_hdr *from; 163662306a36Sopenharmony_ci struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; 163762306a36Sopenharmony_ci struct tx_desc *d = &q->desc[pidx]; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci if (immediate(skb)) { 164062306a36Sopenharmony_ci q->sdesc[pidx].skb = NULL; 164162306a36Sopenharmony_ci write_imm(d, skb, skb->len, gen); 164262306a36Sopenharmony_ci return; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* Only TX_DATA builds SGLs */ 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci from = (struct work_request_hdr *)skb->data; 164862306a36Sopenharmony_ci memcpy(&d->flit[1], &from[1], 164962306a36Sopenharmony_ci skb_transport_offset(skb) - sizeof(*from)); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci flits = skb_transport_offset(skb) / 8; 165262306a36Sopenharmony_ci sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; 165362306a36Sopenharmony_ci sgl_flits = write_sgl(skb, sgp, skb_transport_header(skb), 165462306a36Sopenharmony_ci skb_tail_pointer(skb) - skb_transport_header(skb), 165562306a36Sopenharmony_ci addr); 165662306a36Sopenharmony_ci if (need_skb_unmap()) { 165762306a36Sopenharmony_ci setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); 165862306a36Sopenharmony_ci skb->destructor = deferred_unmap_destructor; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, 166262306a36Sopenharmony_ci gen, from->wr_hi, from->wr_lo); 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci/** 166662306a36Sopenharmony_ci * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet 166762306a36Sopenharmony_ci * @skb: the packet 166862306a36Sopenharmony_ci * 166962306a36Sopenharmony_ci * Returns the number of Tx descriptors needed for the given offload 167062306a36Sopenharmony_ci * packet. These packets are already fully constructed. 167162306a36Sopenharmony_ci */ 167262306a36Sopenharmony_cistatic inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) 167362306a36Sopenharmony_ci{ 167462306a36Sopenharmony_ci unsigned int flits, cnt; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci if (skb->len <= WR_LEN) 167762306a36Sopenharmony_ci return 1; /* packet fits as immediate data */ 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci flits = skb_transport_offset(skb) / 8; /* headers */ 168062306a36Sopenharmony_ci cnt = skb_shinfo(skb)->nr_frags; 168162306a36Sopenharmony_ci if (skb_tail_pointer(skb) != skb_transport_header(skb)) 168262306a36Sopenharmony_ci cnt++; 168362306a36Sopenharmony_ci return flits_to_desc(flits + sgl_len(cnt)); 168462306a36Sopenharmony_ci} 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci/** 168762306a36Sopenharmony_ci * ofld_xmit - send a packet through an offload queue 168862306a36Sopenharmony_ci * @adap: the adapter 168962306a36Sopenharmony_ci * @q: the Tx offload queue 169062306a36Sopenharmony_ci * @skb: the packet 169162306a36Sopenharmony_ci * 169262306a36Sopenharmony_ci * Send an offload packet through an SGE offload queue. 169362306a36Sopenharmony_ci */ 169462306a36Sopenharmony_cistatic int ofld_xmit(struct adapter *adap, struct sge_txq *q, 169562306a36Sopenharmony_ci struct sk_buff *skb) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci int ret; 169862306a36Sopenharmony_ci unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci spin_lock(&q->lock); 170162306a36Sopenharmony_ciagain: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD); 170462306a36Sopenharmony_ci if (unlikely(ret)) { 170562306a36Sopenharmony_ci if (ret == 1) { 170662306a36Sopenharmony_ci skb->priority = ndesc; /* save for restart */ 170762306a36Sopenharmony_ci spin_unlock(&q->lock); 170862306a36Sopenharmony_ci return NET_XMIT_CN; 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci goto again; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci if (!immediate(skb) && 171462306a36Sopenharmony_ci map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) { 171562306a36Sopenharmony_ci spin_unlock(&q->lock); 171662306a36Sopenharmony_ci return NET_XMIT_SUCCESS; 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci gen = q->gen; 172062306a36Sopenharmony_ci q->in_use += ndesc; 172162306a36Sopenharmony_ci pidx = q->pidx; 172262306a36Sopenharmony_ci q->pidx += ndesc; 172362306a36Sopenharmony_ci if (q->pidx >= q->size) { 172462306a36Sopenharmony_ci q->pidx -= q->size; 172562306a36Sopenharmony_ci q->gen ^= 1; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci spin_unlock(&q->lock); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci write_ofld_wr(adap, skb, q, pidx, gen, ndesc, (dma_addr_t *)skb->head); 173062306a36Sopenharmony_ci check_ring_tx_db(adap, q); 173162306a36Sopenharmony_ci return NET_XMIT_SUCCESS; 173262306a36Sopenharmony_ci} 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci/** 173562306a36Sopenharmony_ci * restart_offloadq - restart a suspended offload queue 173662306a36Sopenharmony_ci * @w: pointer to the work associated with this handler 173762306a36Sopenharmony_ci * 173862306a36Sopenharmony_ci * Resumes transmission on a suspended Tx offload queue. 173962306a36Sopenharmony_ci */ 174062306a36Sopenharmony_cistatic void restart_offloadq(struct work_struct *w) 174162306a36Sopenharmony_ci{ 174262306a36Sopenharmony_ci struct sk_buff *skb; 174362306a36Sopenharmony_ci struct sge_qset *qs = container_of(w, struct sge_qset, 174462306a36Sopenharmony_ci txq[TXQ_OFLD].qresume_task); 174562306a36Sopenharmony_ci struct sge_txq *q = &qs->txq[TXQ_OFLD]; 174662306a36Sopenharmony_ci const struct port_info *pi = netdev_priv(qs->netdev); 174762306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 174862306a36Sopenharmony_ci unsigned int written = 0; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci spin_lock(&q->lock); 175162306a36Sopenharmony_ciagain: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci while ((skb = skb_peek(&q->sendq)) != NULL) { 175462306a36Sopenharmony_ci unsigned int gen, pidx; 175562306a36Sopenharmony_ci unsigned int ndesc = skb->priority; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci if (unlikely(q->size - q->in_use < ndesc)) { 175862306a36Sopenharmony_ci set_bit(TXQ_OFLD, &qs->txq_stopped); 175962306a36Sopenharmony_ci smp_mb__after_atomic(); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci if (should_restart_tx(q) && 176262306a36Sopenharmony_ci test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) 176362306a36Sopenharmony_ci goto again; 176462306a36Sopenharmony_ci q->stops++; 176562306a36Sopenharmony_ci break; 176662306a36Sopenharmony_ci } 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci if (!immediate(skb) && 176962306a36Sopenharmony_ci map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) 177062306a36Sopenharmony_ci break; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci gen = q->gen; 177362306a36Sopenharmony_ci q->in_use += ndesc; 177462306a36Sopenharmony_ci pidx = q->pidx; 177562306a36Sopenharmony_ci q->pidx += ndesc; 177662306a36Sopenharmony_ci written += ndesc; 177762306a36Sopenharmony_ci if (q->pidx >= q->size) { 177862306a36Sopenharmony_ci q->pidx -= q->size; 177962306a36Sopenharmony_ci q->gen ^= 1; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci __skb_unlink(skb, &q->sendq); 178262306a36Sopenharmony_ci spin_unlock(&q->lock); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci write_ofld_wr(adap, skb, q, pidx, gen, ndesc, 178562306a36Sopenharmony_ci (dma_addr_t *)skb->head); 178662306a36Sopenharmony_ci spin_lock(&q->lock); 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci spin_unlock(&q->lock); 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci#if USE_GTS 179162306a36Sopenharmony_ci set_bit(TXQ_RUNNING, &q->flags); 179262306a36Sopenharmony_ci set_bit(TXQ_LAST_PKT_DB, &q->flags); 179362306a36Sopenharmony_ci#endif 179462306a36Sopenharmony_ci wmb(); 179562306a36Sopenharmony_ci if (likely(written)) 179662306a36Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, 179762306a36Sopenharmony_ci F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); 179862306a36Sopenharmony_ci} 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci/** 180162306a36Sopenharmony_ci * queue_set - return the queue set a packet should use 180262306a36Sopenharmony_ci * @skb: the packet 180362306a36Sopenharmony_ci * 180462306a36Sopenharmony_ci * Maps a packet to the SGE queue set it should use. The desired queue 180562306a36Sopenharmony_ci * set is carried in bits 1-3 in the packet's priority. 180662306a36Sopenharmony_ci */ 180762306a36Sopenharmony_cistatic inline int queue_set(const struct sk_buff *skb) 180862306a36Sopenharmony_ci{ 180962306a36Sopenharmony_ci return skb->priority >> 1; 181062306a36Sopenharmony_ci} 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci/** 181362306a36Sopenharmony_ci * is_ctrl_pkt - return whether an offload packet is a control packet 181462306a36Sopenharmony_ci * @skb: the packet 181562306a36Sopenharmony_ci * 181662306a36Sopenharmony_ci * Determines whether an offload packet should use an OFLD or a CTRL 181762306a36Sopenharmony_ci * Tx queue. This is indicated by bit 0 in the packet's priority. 181862306a36Sopenharmony_ci */ 181962306a36Sopenharmony_cistatic inline int is_ctrl_pkt(const struct sk_buff *skb) 182062306a36Sopenharmony_ci{ 182162306a36Sopenharmony_ci return skb->priority & 1; 182262306a36Sopenharmony_ci} 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci/** 182562306a36Sopenharmony_ci * t3_offload_tx - send an offload packet 182662306a36Sopenharmony_ci * @tdev: the offload device to send to 182762306a36Sopenharmony_ci * @skb: the packet 182862306a36Sopenharmony_ci * 182962306a36Sopenharmony_ci * Sends an offload packet. We use the packet priority to select the 183062306a36Sopenharmony_ci * appropriate Tx queue as follows: bit 0 indicates whether the packet 183162306a36Sopenharmony_ci * should be sent as regular or control, bits 1-3 select the queue set. 183262306a36Sopenharmony_ci */ 183362306a36Sopenharmony_ciint t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci struct adapter *adap = tdev2adap(tdev); 183662306a36Sopenharmony_ci struct sge_qset *qs = &adap->sge.qs[queue_set(skb)]; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci if (unlikely(is_ctrl_pkt(skb))) 183962306a36Sopenharmony_ci return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb); 184262306a36Sopenharmony_ci} 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci/** 184562306a36Sopenharmony_ci * offload_enqueue - add an offload packet to an SGE offload receive queue 184662306a36Sopenharmony_ci * @q: the SGE response queue 184762306a36Sopenharmony_ci * @skb: the packet 184862306a36Sopenharmony_ci * 184962306a36Sopenharmony_ci * Add a new offload packet to an SGE response queue's offload packet 185062306a36Sopenharmony_ci * queue. If the packet is the first on the queue it schedules the RX 185162306a36Sopenharmony_ci * softirq to process the queue. 185262306a36Sopenharmony_ci */ 185362306a36Sopenharmony_cistatic inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) 185462306a36Sopenharmony_ci{ 185562306a36Sopenharmony_ci int was_empty = skb_queue_empty(&q->rx_queue); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci __skb_queue_tail(&q->rx_queue, skb); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci if (was_empty) { 186062306a36Sopenharmony_ci struct sge_qset *qs = rspq_to_qset(q); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci napi_schedule(&qs->napi); 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci} 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci/** 186762306a36Sopenharmony_ci * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts 186862306a36Sopenharmony_ci * @tdev: the offload device that will be receiving the packets 186962306a36Sopenharmony_ci * @q: the SGE response queue that assembled the bundle 187062306a36Sopenharmony_ci * @skbs: the partial bundle 187162306a36Sopenharmony_ci * @n: the number of packets in the bundle 187262306a36Sopenharmony_ci * 187362306a36Sopenharmony_ci * Delivers a (partial) bundle of Rx offload packets to an offload device. 187462306a36Sopenharmony_ci */ 187562306a36Sopenharmony_cistatic inline void deliver_partial_bundle(struct t3cdev *tdev, 187662306a36Sopenharmony_ci struct sge_rspq *q, 187762306a36Sopenharmony_ci struct sk_buff *skbs[], int n) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci if (n) { 188062306a36Sopenharmony_ci q->offload_bundles++; 188162306a36Sopenharmony_ci tdev->recv(tdev, skbs, n); 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci} 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci/** 188662306a36Sopenharmony_ci * ofld_poll - NAPI handler for offload packets in interrupt mode 188762306a36Sopenharmony_ci * @napi: the network device doing the polling 188862306a36Sopenharmony_ci * @budget: polling budget 188962306a36Sopenharmony_ci * 189062306a36Sopenharmony_ci * The NAPI handler for offload packets when a response queue is serviced 189162306a36Sopenharmony_ci * by the hard interrupt handler, i.e., when it's operating in non-polling 189262306a36Sopenharmony_ci * mode. Creates small packet batches and sends them through the offload 189362306a36Sopenharmony_ci * receive handler. Batches need to be of modest size as we do prefetches 189462306a36Sopenharmony_ci * on the packets in each. 189562306a36Sopenharmony_ci */ 189662306a36Sopenharmony_cistatic int ofld_poll(struct napi_struct *napi, int budget) 189762306a36Sopenharmony_ci{ 189862306a36Sopenharmony_ci struct sge_qset *qs = container_of(napi, struct sge_qset, napi); 189962306a36Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 190062306a36Sopenharmony_ci struct adapter *adapter = qs->adap; 190162306a36Sopenharmony_ci int work_done = 0; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci while (work_done < budget) { 190462306a36Sopenharmony_ci struct sk_buff *skb, *tmp, *skbs[RX_BUNDLE_SIZE]; 190562306a36Sopenharmony_ci struct sk_buff_head queue; 190662306a36Sopenharmony_ci int ngathered; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci spin_lock_irq(&q->lock); 190962306a36Sopenharmony_ci __skb_queue_head_init(&queue); 191062306a36Sopenharmony_ci skb_queue_splice_init(&q->rx_queue, &queue); 191162306a36Sopenharmony_ci if (skb_queue_empty(&queue)) { 191262306a36Sopenharmony_ci napi_complete_done(napi, work_done); 191362306a36Sopenharmony_ci spin_unlock_irq(&q->lock); 191462306a36Sopenharmony_ci return work_done; 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci spin_unlock_irq(&q->lock); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci ngathered = 0; 191962306a36Sopenharmony_ci skb_queue_walk_safe(&queue, skb, tmp) { 192062306a36Sopenharmony_ci if (work_done >= budget) 192162306a36Sopenharmony_ci break; 192262306a36Sopenharmony_ci work_done++; 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci __skb_unlink(skb, &queue); 192562306a36Sopenharmony_ci prefetch(skb->data); 192662306a36Sopenharmony_ci skbs[ngathered] = skb; 192762306a36Sopenharmony_ci if (++ngathered == RX_BUNDLE_SIZE) { 192862306a36Sopenharmony_ci q->offload_bundles++; 192962306a36Sopenharmony_ci adapter->tdev.recv(&adapter->tdev, skbs, 193062306a36Sopenharmony_ci ngathered); 193162306a36Sopenharmony_ci ngathered = 0; 193262306a36Sopenharmony_ci } 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci if (!skb_queue_empty(&queue)) { 193562306a36Sopenharmony_ci /* splice remaining packets back onto Rx queue */ 193662306a36Sopenharmony_ci spin_lock_irq(&q->lock); 193762306a36Sopenharmony_ci skb_queue_splice(&queue, &q->rx_queue); 193862306a36Sopenharmony_ci spin_unlock_irq(&q->lock); 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci return work_done; 194462306a36Sopenharmony_ci} 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci/** 194762306a36Sopenharmony_ci * rx_offload - process a received offload packet 194862306a36Sopenharmony_ci * @tdev: the offload device receiving the packet 194962306a36Sopenharmony_ci * @rq: the response queue that received the packet 195062306a36Sopenharmony_ci * @skb: the packet 195162306a36Sopenharmony_ci * @rx_gather: a gather list of packets if we are building a bundle 195262306a36Sopenharmony_ci * @gather_idx: index of the next available slot in the bundle 195362306a36Sopenharmony_ci * 195462306a36Sopenharmony_ci * Process an ingress offload packet and add it to the offload ingress 195562306a36Sopenharmony_ci * queue. Returns the index of the next available slot in the bundle. 195662306a36Sopenharmony_ci */ 195762306a36Sopenharmony_cistatic inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq, 195862306a36Sopenharmony_ci struct sk_buff *skb, struct sk_buff *rx_gather[], 195962306a36Sopenharmony_ci unsigned int gather_idx) 196062306a36Sopenharmony_ci{ 196162306a36Sopenharmony_ci skb_reset_mac_header(skb); 196262306a36Sopenharmony_ci skb_reset_network_header(skb); 196362306a36Sopenharmony_ci skb_reset_transport_header(skb); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci if (rq->polling) { 196662306a36Sopenharmony_ci rx_gather[gather_idx++] = skb; 196762306a36Sopenharmony_ci if (gather_idx == RX_BUNDLE_SIZE) { 196862306a36Sopenharmony_ci tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE); 196962306a36Sopenharmony_ci gather_idx = 0; 197062306a36Sopenharmony_ci rq->offload_bundles++; 197162306a36Sopenharmony_ci } 197262306a36Sopenharmony_ci } else 197362306a36Sopenharmony_ci offload_enqueue(rq, skb); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci return gather_idx; 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci/** 197962306a36Sopenharmony_ci * restart_tx - check whether to restart suspended Tx queues 198062306a36Sopenharmony_ci * @qs: the queue set to resume 198162306a36Sopenharmony_ci * 198262306a36Sopenharmony_ci * Restarts suspended Tx queues of an SGE queue set if they have enough 198362306a36Sopenharmony_ci * free resources to resume operation. 198462306a36Sopenharmony_ci */ 198562306a36Sopenharmony_cistatic void restart_tx(struct sge_qset *qs) 198662306a36Sopenharmony_ci{ 198762306a36Sopenharmony_ci if (test_bit(TXQ_ETH, &qs->txq_stopped) && 198862306a36Sopenharmony_ci should_restart_tx(&qs->txq[TXQ_ETH]) && 198962306a36Sopenharmony_ci test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { 199062306a36Sopenharmony_ci qs->txq[TXQ_ETH].restarts++; 199162306a36Sopenharmony_ci if (netif_running(qs->netdev)) 199262306a36Sopenharmony_ci netif_tx_wake_queue(qs->tx_q); 199362306a36Sopenharmony_ci } 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci if (test_bit(TXQ_OFLD, &qs->txq_stopped) && 199662306a36Sopenharmony_ci should_restart_tx(&qs->txq[TXQ_OFLD]) && 199762306a36Sopenharmony_ci test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) { 199862306a36Sopenharmony_ci qs->txq[TXQ_OFLD].restarts++; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci /* The work can be quite lengthy so we use driver's own queue */ 200162306a36Sopenharmony_ci queue_work(cxgb3_wq, &qs->txq[TXQ_OFLD].qresume_task); 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ci if (test_bit(TXQ_CTRL, &qs->txq_stopped) && 200462306a36Sopenharmony_ci should_restart_tx(&qs->txq[TXQ_CTRL]) && 200562306a36Sopenharmony_ci test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) { 200662306a36Sopenharmony_ci qs->txq[TXQ_CTRL].restarts++; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci /* The work can be quite lengthy so we use driver's own queue */ 200962306a36Sopenharmony_ci queue_work(cxgb3_wq, &qs->txq[TXQ_CTRL].qresume_task); 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci} 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci/** 201462306a36Sopenharmony_ci * cxgb3_arp_process - process an ARP request probing a private IP address 201562306a36Sopenharmony_ci * @pi: the port info 201662306a36Sopenharmony_ci * @skb: the skbuff containing the ARP request 201762306a36Sopenharmony_ci * 201862306a36Sopenharmony_ci * Check if the ARP request is probing the private IP address 201962306a36Sopenharmony_ci * dedicated to iSCSI, generate an ARP reply if so. 202062306a36Sopenharmony_ci */ 202162306a36Sopenharmony_cistatic void cxgb3_arp_process(struct port_info *pi, struct sk_buff *skb) 202262306a36Sopenharmony_ci{ 202362306a36Sopenharmony_ci struct net_device *dev = skb->dev; 202462306a36Sopenharmony_ci struct arphdr *arp; 202562306a36Sopenharmony_ci unsigned char *arp_ptr; 202662306a36Sopenharmony_ci unsigned char *sha; 202762306a36Sopenharmony_ci __be32 sip, tip; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if (!dev) 203062306a36Sopenharmony_ci return; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci skb_reset_network_header(skb); 203362306a36Sopenharmony_ci arp = arp_hdr(skb); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci if (arp->ar_op != htons(ARPOP_REQUEST)) 203662306a36Sopenharmony_ci return; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci arp_ptr = (unsigned char *)(arp + 1); 203962306a36Sopenharmony_ci sha = arp_ptr; 204062306a36Sopenharmony_ci arp_ptr += dev->addr_len; 204162306a36Sopenharmony_ci memcpy(&sip, arp_ptr, sizeof(sip)); 204262306a36Sopenharmony_ci arp_ptr += sizeof(sip); 204362306a36Sopenharmony_ci arp_ptr += dev->addr_len; 204462306a36Sopenharmony_ci memcpy(&tip, arp_ptr, sizeof(tip)); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci if (tip != pi->iscsi_ipv4addr) 204762306a36Sopenharmony_ci return; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, 205062306a36Sopenharmony_ci pi->iscsic.mac_addr, sha); 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci} 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_cistatic inline int is_arp(struct sk_buff *skb) 205562306a36Sopenharmony_ci{ 205662306a36Sopenharmony_ci return skb->protocol == htons(ETH_P_ARP); 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_cistatic void cxgb3_process_iscsi_prov_pack(struct port_info *pi, 206062306a36Sopenharmony_ci struct sk_buff *skb) 206162306a36Sopenharmony_ci{ 206262306a36Sopenharmony_ci if (is_arp(skb)) { 206362306a36Sopenharmony_ci cxgb3_arp_process(pi, skb); 206462306a36Sopenharmony_ci return; 206562306a36Sopenharmony_ci } 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci if (pi->iscsic.recv) 206862306a36Sopenharmony_ci pi->iscsic.recv(pi, skb); 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci} 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci/** 207362306a36Sopenharmony_ci * rx_eth - process an ingress ethernet packet 207462306a36Sopenharmony_ci * @adap: the adapter 207562306a36Sopenharmony_ci * @rq: the response queue that received the packet 207662306a36Sopenharmony_ci * @skb: the packet 207762306a36Sopenharmony_ci * @pad: padding 207862306a36Sopenharmony_ci * @lro: large receive offload 207962306a36Sopenharmony_ci * 208062306a36Sopenharmony_ci * Process an ingress ethernet packet and deliver it to the stack. 208162306a36Sopenharmony_ci * The padding is 2 if the packet was delivered in an Rx buffer and 0 208262306a36Sopenharmony_ci * if it was immediate data in a response. 208362306a36Sopenharmony_ci */ 208462306a36Sopenharmony_cistatic void rx_eth(struct adapter *adap, struct sge_rspq *rq, 208562306a36Sopenharmony_ci struct sk_buff *skb, int pad, int lro) 208662306a36Sopenharmony_ci{ 208762306a36Sopenharmony_ci struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); 208862306a36Sopenharmony_ci struct sge_qset *qs = rspq_to_qset(rq); 208962306a36Sopenharmony_ci struct port_info *pi; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci skb_pull(skb, sizeof(*p) + pad); 209262306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, adap->port[p->iff]); 209362306a36Sopenharmony_ci pi = netdev_priv(skb->dev); 209462306a36Sopenharmony_ci if ((skb->dev->features & NETIF_F_RXCSUM) && p->csum_valid && 209562306a36Sopenharmony_ci p->csum == htons(0xffff) && !p->fragment) { 209662306a36Sopenharmony_ci qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; 209762306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 209862306a36Sopenharmony_ci } else 209962306a36Sopenharmony_ci skb_checksum_none_assert(skb); 210062306a36Sopenharmony_ci skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]); 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci if (p->vlan_valid) { 210362306a36Sopenharmony_ci qs->port_stats[SGE_PSTAT_VLANEX]++; 210462306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(p->vlan)); 210562306a36Sopenharmony_ci } 210662306a36Sopenharmony_ci if (rq->polling) { 210762306a36Sopenharmony_ci if (lro) 210862306a36Sopenharmony_ci napi_gro_receive(&qs->napi, skb); 210962306a36Sopenharmony_ci else { 211062306a36Sopenharmony_ci if (unlikely(pi->iscsic.flags)) 211162306a36Sopenharmony_ci cxgb3_process_iscsi_prov_pack(pi, skb); 211262306a36Sopenharmony_ci netif_receive_skb(skb); 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci } else 211562306a36Sopenharmony_ci netif_rx(skb); 211662306a36Sopenharmony_ci} 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_cistatic inline int is_eth_tcp(u32 rss) 211962306a36Sopenharmony_ci{ 212062306a36Sopenharmony_ci return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE; 212162306a36Sopenharmony_ci} 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci/** 212462306a36Sopenharmony_ci * lro_add_page - add a page chunk to an LRO session 212562306a36Sopenharmony_ci * @adap: the adapter 212662306a36Sopenharmony_ci * @qs: the associated queue set 212762306a36Sopenharmony_ci * @fl: the free list containing the page chunk to add 212862306a36Sopenharmony_ci * @len: packet length 212962306a36Sopenharmony_ci * @complete: Indicates the last fragment of a frame 213062306a36Sopenharmony_ci * 213162306a36Sopenharmony_ci * Add a received packet contained in a page chunk to an existing LRO 213262306a36Sopenharmony_ci * session. 213362306a36Sopenharmony_ci */ 213462306a36Sopenharmony_cistatic void lro_add_page(struct adapter *adap, struct sge_qset *qs, 213562306a36Sopenharmony_ci struct sge_fl *fl, int len, int complete) 213662306a36Sopenharmony_ci{ 213762306a36Sopenharmony_ci struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; 213862306a36Sopenharmony_ci struct port_info *pi = netdev_priv(qs->netdev); 213962306a36Sopenharmony_ci struct sk_buff *skb = NULL; 214062306a36Sopenharmony_ci struct cpl_rx_pkt *cpl; 214162306a36Sopenharmony_ci skb_frag_t *rx_frag; 214262306a36Sopenharmony_ci int nr_frags; 214362306a36Sopenharmony_ci int offset = 0; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (!qs->nomem) { 214662306a36Sopenharmony_ci skb = napi_get_frags(&qs->napi); 214762306a36Sopenharmony_ci qs->nomem = !skb; 214862306a36Sopenharmony_ci } 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci fl->credits--; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci dma_sync_single_for_cpu(&adap->pdev->dev, 215362306a36Sopenharmony_ci dma_unmap_addr(sd, dma_addr), 215462306a36Sopenharmony_ci fl->buf_size - SGE_PG_RSVD, DMA_FROM_DEVICE); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci (*sd->pg_chunk.p_cnt)--; 215762306a36Sopenharmony_ci if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) 215862306a36Sopenharmony_ci dma_unmap_page(&adap->pdev->dev, sd->pg_chunk.mapping, 215962306a36Sopenharmony_ci fl->alloc_size, DMA_FROM_DEVICE); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci if (!skb) { 216262306a36Sopenharmony_ci put_page(sd->pg_chunk.page); 216362306a36Sopenharmony_ci if (complete) 216462306a36Sopenharmony_ci qs->nomem = 0; 216562306a36Sopenharmony_ci return; 216662306a36Sopenharmony_ci } 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci rx_frag = skb_shinfo(skb)->frags; 216962306a36Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci if (!nr_frags) { 217262306a36Sopenharmony_ci offset = 2 + sizeof(struct cpl_rx_pkt); 217362306a36Sopenharmony_ci cpl = qs->lro_va = sd->pg_chunk.va + 2; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci if ((qs->netdev->features & NETIF_F_RXCSUM) && 217662306a36Sopenharmony_ci cpl->csum_valid && cpl->csum == htons(0xffff)) { 217762306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 217862306a36Sopenharmony_ci qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; 217962306a36Sopenharmony_ci } else 218062306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 218162306a36Sopenharmony_ci } else 218262306a36Sopenharmony_ci cpl = qs->lro_va; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci len -= offset; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci rx_frag += nr_frags; 218762306a36Sopenharmony_ci skb_frag_fill_page_desc(rx_frag, sd->pg_chunk.page, 218862306a36Sopenharmony_ci sd->pg_chunk.offset + offset, len); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci skb->len += len; 219162306a36Sopenharmony_ci skb->data_len += len; 219262306a36Sopenharmony_ci skb->truesize += len; 219362306a36Sopenharmony_ci skb_shinfo(skb)->nr_frags++; 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci if (!complete) 219662306a36Sopenharmony_ci return; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (cpl->vlan_valid) { 220162306a36Sopenharmony_ci qs->port_stats[SGE_PSTAT_VLANEX]++; 220262306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cpl->vlan)); 220362306a36Sopenharmony_ci } 220462306a36Sopenharmony_ci napi_gro_frags(&qs->napi); 220562306a36Sopenharmony_ci} 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci/** 220862306a36Sopenharmony_ci * handle_rsp_cntrl_info - handles control information in a response 220962306a36Sopenharmony_ci * @qs: the queue set corresponding to the response 221062306a36Sopenharmony_ci * @flags: the response control flags 221162306a36Sopenharmony_ci * 221262306a36Sopenharmony_ci * Handles the control information of an SGE response, such as GTS 221362306a36Sopenharmony_ci * indications and completion credits for the queue set's Tx queues. 221462306a36Sopenharmony_ci * HW coalesces credits, we don't do any extra SW coalescing. 221562306a36Sopenharmony_ci */ 221662306a36Sopenharmony_cistatic inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags) 221762306a36Sopenharmony_ci{ 221862306a36Sopenharmony_ci unsigned int credits; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci#if USE_GTS 222162306a36Sopenharmony_ci if (flags & F_RSPD_TXQ0_GTS) 222262306a36Sopenharmony_ci clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags); 222362306a36Sopenharmony_ci#endif 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci credits = G_RSPD_TXQ0_CR(flags); 222662306a36Sopenharmony_ci if (credits) 222762306a36Sopenharmony_ci qs->txq[TXQ_ETH].processed += credits; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci credits = G_RSPD_TXQ2_CR(flags); 223062306a36Sopenharmony_ci if (credits) 223162306a36Sopenharmony_ci qs->txq[TXQ_CTRL].processed += credits; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci# if USE_GTS 223462306a36Sopenharmony_ci if (flags & F_RSPD_TXQ1_GTS) 223562306a36Sopenharmony_ci clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags); 223662306a36Sopenharmony_ci# endif 223762306a36Sopenharmony_ci credits = G_RSPD_TXQ1_CR(flags); 223862306a36Sopenharmony_ci if (credits) 223962306a36Sopenharmony_ci qs->txq[TXQ_OFLD].processed += credits; 224062306a36Sopenharmony_ci} 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci/** 224362306a36Sopenharmony_ci * check_ring_db - check if we need to ring any doorbells 224462306a36Sopenharmony_ci * @adap: the adapter 224562306a36Sopenharmony_ci * @qs: the queue set whose Tx queues are to be examined 224662306a36Sopenharmony_ci * @sleeping: indicates which Tx queue sent GTS 224762306a36Sopenharmony_ci * 224862306a36Sopenharmony_ci * Checks if some of a queue set's Tx queues need to ring their doorbells 224962306a36Sopenharmony_ci * to resume transmission after idling while they still have unprocessed 225062306a36Sopenharmony_ci * descriptors. 225162306a36Sopenharmony_ci */ 225262306a36Sopenharmony_cistatic void check_ring_db(struct adapter *adap, struct sge_qset *qs, 225362306a36Sopenharmony_ci unsigned int sleeping) 225462306a36Sopenharmony_ci{ 225562306a36Sopenharmony_ci if (sleeping & F_RSPD_TXQ0_GTS) { 225662306a36Sopenharmony_ci struct sge_txq *txq = &qs->txq[TXQ_ETH]; 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci if (txq->cleaned + txq->in_use != txq->processed && 225962306a36Sopenharmony_ci !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { 226062306a36Sopenharmony_ci set_bit(TXQ_RUNNING, &txq->flags); 226162306a36Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | 226262306a36Sopenharmony_ci V_EGRCNTX(txq->cntxt_id)); 226362306a36Sopenharmony_ci } 226462306a36Sopenharmony_ci } 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci if (sleeping & F_RSPD_TXQ1_GTS) { 226762306a36Sopenharmony_ci struct sge_txq *txq = &qs->txq[TXQ_OFLD]; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci if (txq->cleaned + txq->in_use != txq->processed && 227062306a36Sopenharmony_ci !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { 227162306a36Sopenharmony_ci set_bit(TXQ_RUNNING, &txq->flags); 227262306a36Sopenharmony_ci t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | 227362306a36Sopenharmony_ci V_EGRCNTX(txq->cntxt_id)); 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci } 227662306a36Sopenharmony_ci} 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci/** 227962306a36Sopenharmony_ci * is_new_response - check if a response is newly written 228062306a36Sopenharmony_ci * @r: the response descriptor 228162306a36Sopenharmony_ci * @q: the response queue 228262306a36Sopenharmony_ci * 228362306a36Sopenharmony_ci * Returns true if a response descriptor contains a yet unprocessed 228462306a36Sopenharmony_ci * response. 228562306a36Sopenharmony_ci */ 228662306a36Sopenharmony_cistatic inline int is_new_response(const struct rsp_desc *r, 228762306a36Sopenharmony_ci const struct sge_rspq *q) 228862306a36Sopenharmony_ci{ 228962306a36Sopenharmony_ci return (r->intr_gen & F_RSPD_GEN2) == q->gen; 229062306a36Sopenharmony_ci} 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_cistatic inline void clear_rspq_bufstate(struct sge_rspq * const q) 229362306a36Sopenharmony_ci{ 229462306a36Sopenharmony_ci q->pg_skb = NULL; 229562306a36Sopenharmony_ci q->rx_recycle_buf = 0; 229662306a36Sopenharmony_ci} 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) 229962306a36Sopenharmony_ci#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ 230062306a36Sopenharmony_ci V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ 230162306a36Sopenharmony_ci V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \ 230262306a36Sopenharmony_ci V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR)) 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */ 230562306a36Sopenharmony_ci#define NOMEM_INTR_DELAY 2500 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci/** 230862306a36Sopenharmony_ci * process_responses - process responses from an SGE response queue 230962306a36Sopenharmony_ci * @adap: the adapter 231062306a36Sopenharmony_ci * @qs: the queue set to which the response queue belongs 231162306a36Sopenharmony_ci * @budget: how many responses can be processed in this round 231262306a36Sopenharmony_ci * 231362306a36Sopenharmony_ci * Process responses from an SGE response queue up to the supplied budget. 231462306a36Sopenharmony_ci * Responses include received packets as well as credits and other events 231562306a36Sopenharmony_ci * for the queues that belong to the response queue's queue set. 231662306a36Sopenharmony_ci * A negative budget is effectively unlimited. 231762306a36Sopenharmony_ci * 231862306a36Sopenharmony_ci * Additionally choose the interrupt holdoff time for the next interrupt 231962306a36Sopenharmony_ci * on this queue. If the system is under memory shortage use a fairly 232062306a36Sopenharmony_ci * long delay to help recovery. 232162306a36Sopenharmony_ci */ 232262306a36Sopenharmony_cistatic int process_responses(struct adapter *adap, struct sge_qset *qs, 232362306a36Sopenharmony_ci int budget) 232462306a36Sopenharmony_ci{ 232562306a36Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 232662306a36Sopenharmony_ci struct rsp_desc *r = &q->desc[q->cidx]; 232762306a36Sopenharmony_ci int budget_left = budget; 232862306a36Sopenharmony_ci unsigned int sleeping = 0; 232962306a36Sopenharmony_ci struct sk_buff *offload_skbs[RX_BUNDLE_SIZE]; 233062306a36Sopenharmony_ci int ngathered = 0; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci q->next_holdoff = q->holdoff_tmr; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci while (likely(budget_left && is_new_response(r, q))) { 233562306a36Sopenharmony_ci int packet_complete, eth, ethpad = 2; 233662306a36Sopenharmony_ci int lro = !!(qs->netdev->features & NETIF_F_GRO); 233762306a36Sopenharmony_ci struct sk_buff *skb = NULL; 233862306a36Sopenharmony_ci u32 len, flags; 233962306a36Sopenharmony_ci __be32 rss_hi, rss_lo; 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci dma_rmb(); 234262306a36Sopenharmony_ci eth = r->rss_hdr.opcode == CPL_RX_PKT; 234362306a36Sopenharmony_ci rss_hi = *(const __be32 *)r; 234462306a36Sopenharmony_ci rss_lo = r->rss_hdr.rss_hash_val; 234562306a36Sopenharmony_ci flags = ntohl(r->flags); 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) { 234862306a36Sopenharmony_ci skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC); 234962306a36Sopenharmony_ci if (!skb) 235062306a36Sopenharmony_ci goto no_mem; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci __skb_put_data(skb, r, AN_PKT_SIZE); 235362306a36Sopenharmony_ci skb->data[0] = CPL_ASYNC_NOTIF; 235462306a36Sopenharmony_ci rss_hi = htonl(CPL_ASYNC_NOTIF << 24); 235562306a36Sopenharmony_ci q->async_notif++; 235662306a36Sopenharmony_ci } else if (flags & F_RSPD_IMM_DATA_VALID) { 235762306a36Sopenharmony_ci skb = get_imm_packet(r); 235862306a36Sopenharmony_ci if (unlikely(!skb)) { 235962306a36Sopenharmony_cino_mem: 236062306a36Sopenharmony_ci q->next_holdoff = NOMEM_INTR_DELAY; 236162306a36Sopenharmony_ci q->nomem++; 236262306a36Sopenharmony_ci /* consume one credit since we tried */ 236362306a36Sopenharmony_ci budget_left--; 236462306a36Sopenharmony_ci break; 236562306a36Sopenharmony_ci } 236662306a36Sopenharmony_ci q->imm_data++; 236762306a36Sopenharmony_ci ethpad = 0; 236862306a36Sopenharmony_ci } else if ((len = ntohl(r->len_cq)) != 0) { 236962306a36Sopenharmony_ci struct sge_fl *fl; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci lro &= eth && is_eth_tcp(rss_hi); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; 237462306a36Sopenharmony_ci if (fl->use_pages) { 237562306a36Sopenharmony_ci void *addr = fl->sdesc[fl->cidx].pg_chunk.va; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci net_prefetch(addr); 237862306a36Sopenharmony_ci __refill_fl(adap, fl); 237962306a36Sopenharmony_ci if (lro > 0) { 238062306a36Sopenharmony_ci lro_add_page(adap, qs, fl, 238162306a36Sopenharmony_ci G_RSPD_LEN(len), 238262306a36Sopenharmony_ci flags & F_RSPD_EOP); 238362306a36Sopenharmony_ci goto next_fl; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci skb = get_packet_pg(adap, fl, q, 238762306a36Sopenharmony_ci G_RSPD_LEN(len), 238862306a36Sopenharmony_ci eth ? 238962306a36Sopenharmony_ci SGE_RX_DROP_THRES : 0); 239062306a36Sopenharmony_ci q->pg_skb = skb; 239162306a36Sopenharmony_ci } else 239262306a36Sopenharmony_ci skb = get_packet(adap, fl, G_RSPD_LEN(len), 239362306a36Sopenharmony_ci eth ? SGE_RX_DROP_THRES : 0); 239462306a36Sopenharmony_ci if (unlikely(!skb)) { 239562306a36Sopenharmony_ci if (!eth) 239662306a36Sopenharmony_ci goto no_mem; 239762306a36Sopenharmony_ci q->rx_drops++; 239862306a36Sopenharmony_ci } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT)) 239962306a36Sopenharmony_ci __skb_pull(skb, 2); 240062306a36Sopenharmony_cinext_fl: 240162306a36Sopenharmony_ci if (++fl->cidx == fl->size) 240262306a36Sopenharmony_ci fl->cidx = 0; 240362306a36Sopenharmony_ci } else 240462306a36Sopenharmony_ci q->pure_rsps++; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci if (flags & RSPD_CTRL_MASK) { 240762306a36Sopenharmony_ci sleeping |= flags & RSPD_GTS_MASK; 240862306a36Sopenharmony_ci handle_rsp_cntrl_info(qs, flags); 240962306a36Sopenharmony_ci } 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci r++; 241262306a36Sopenharmony_ci if (unlikely(++q->cidx == q->size)) { 241362306a36Sopenharmony_ci q->cidx = 0; 241462306a36Sopenharmony_ci q->gen ^= 1; 241562306a36Sopenharmony_ci r = q->desc; 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci prefetch(r); 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci if (++q->credits >= (q->size / 4)) { 242062306a36Sopenharmony_ci refill_rspq(adap, q, q->credits); 242162306a36Sopenharmony_ci q->credits = 0; 242262306a36Sopenharmony_ci } 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci packet_complete = flags & 242562306a36Sopenharmony_ci (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID | 242662306a36Sopenharmony_ci F_RSPD_ASYNC_NOTIF); 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci if (skb != NULL && packet_complete) { 242962306a36Sopenharmony_ci if (eth) 243062306a36Sopenharmony_ci rx_eth(adap, q, skb, ethpad, lro); 243162306a36Sopenharmony_ci else { 243262306a36Sopenharmony_ci q->offload_pkts++; 243362306a36Sopenharmony_ci /* Preserve the RSS info in csum & priority */ 243462306a36Sopenharmony_ci skb->csum = rss_hi; 243562306a36Sopenharmony_ci skb->priority = rss_lo; 243662306a36Sopenharmony_ci ngathered = rx_offload(&adap->tdev, q, skb, 243762306a36Sopenharmony_ci offload_skbs, 243862306a36Sopenharmony_ci ngathered); 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (flags & F_RSPD_EOP) 244262306a36Sopenharmony_ci clear_rspq_bufstate(q); 244362306a36Sopenharmony_ci } 244462306a36Sopenharmony_ci --budget_left; 244562306a36Sopenharmony_ci } 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered); 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci if (sleeping) 245062306a36Sopenharmony_ci check_ring_db(adap, qs, sleeping); 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci smp_mb(); /* commit Tx queue .processed updates */ 245362306a36Sopenharmony_ci if (unlikely(qs->txq_stopped != 0)) 245462306a36Sopenharmony_ci restart_tx(qs); 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci budget -= budget_left; 245762306a36Sopenharmony_ci return budget; 245862306a36Sopenharmony_ci} 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_cistatic inline int is_pure_response(const struct rsp_desc *r) 246162306a36Sopenharmony_ci{ 246262306a36Sopenharmony_ci __be32 n = r->flags & htonl(F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci return (n | r->len_cq) == 0; 246562306a36Sopenharmony_ci} 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci/** 246862306a36Sopenharmony_ci * napi_rx_handler - the NAPI handler for Rx processing 246962306a36Sopenharmony_ci * @napi: the napi instance 247062306a36Sopenharmony_ci * @budget: how many packets we can process in this round 247162306a36Sopenharmony_ci * 247262306a36Sopenharmony_ci * Handler for new data events when using NAPI. 247362306a36Sopenharmony_ci */ 247462306a36Sopenharmony_cistatic int napi_rx_handler(struct napi_struct *napi, int budget) 247562306a36Sopenharmony_ci{ 247662306a36Sopenharmony_ci struct sge_qset *qs = container_of(napi, struct sge_qset, napi); 247762306a36Sopenharmony_ci struct adapter *adap = qs->adap; 247862306a36Sopenharmony_ci int work_done = process_responses(adap, qs, budget); 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci if (likely(work_done < budget)) { 248162306a36Sopenharmony_ci napi_complete_done(napi, work_done); 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci /* 248462306a36Sopenharmony_ci * Because we don't atomically flush the following 248562306a36Sopenharmony_ci * write it is possible that in very rare cases it can 248662306a36Sopenharmony_ci * reach the device in a way that races with a new 248762306a36Sopenharmony_ci * response being written plus an error interrupt 248862306a36Sopenharmony_ci * causing the NAPI interrupt handler below to return 248962306a36Sopenharmony_ci * unhandled status to the OS. To protect against 249062306a36Sopenharmony_ci * this would require flushing the write and doing 249162306a36Sopenharmony_ci * both the write and the flush with interrupts off. 249262306a36Sopenharmony_ci * Way too expensive and unjustifiable given the 249362306a36Sopenharmony_ci * rarity of the race. 249462306a36Sopenharmony_ci * 249562306a36Sopenharmony_ci * The race cannot happen at all with MSI-X. 249662306a36Sopenharmony_ci */ 249762306a36Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | 249862306a36Sopenharmony_ci V_NEWTIMER(qs->rspq.next_holdoff) | 249962306a36Sopenharmony_ci V_NEWINDEX(qs->rspq.cidx)); 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ci return work_done; 250262306a36Sopenharmony_ci} 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci/* 250562306a36Sopenharmony_ci * Returns true if the device is already scheduled for polling. 250662306a36Sopenharmony_ci */ 250762306a36Sopenharmony_cistatic inline int napi_is_scheduled(struct napi_struct *napi) 250862306a36Sopenharmony_ci{ 250962306a36Sopenharmony_ci return test_bit(NAPI_STATE_SCHED, &napi->state); 251062306a36Sopenharmony_ci} 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci/** 251362306a36Sopenharmony_ci * process_pure_responses - process pure responses from a response queue 251462306a36Sopenharmony_ci * @adap: the adapter 251562306a36Sopenharmony_ci * @qs: the queue set owning the response queue 251662306a36Sopenharmony_ci * @r: the first pure response to process 251762306a36Sopenharmony_ci * 251862306a36Sopenharmony_ci * A simpler version of process_responses() that handles only pure (i.e., 251962306a36Sopenharmony_ci * non data-carrying) responses. Such respones are too light-weight to 252062306a36Sopenharmony_ci * justify calling a softirq under NAPI, so we handle them specially in 252162306a36Sopenharmony_ci * the interrupt handler. The function is called with a pointer to a 252262306a36Sopenharmony_ci * response, which the caller must ensure is a valid pure response. 252362306a36Sopenharmony_ci * 252462306a36Sopenharmony_ci * Returns 1 if it encounters a valid data-carrying response, 0 otherwise. 252562306a36Sopenharmony_ci */ 252662306a36Sopenharmony_cistatic int process_pure_responses(struct adapter *adap, struct sge_qset *qs, 252762306a36Sopenharmony_ci struct rsp_desc *r) 252862306a36Sopenharmony_ci{ 252962306a36Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 253062306a36Sopenharmony_ci unsigned int sleeping = 0; 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci do { 253362306a36Sopenharmony_ci u32 flags = ntohl(r->flags); 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci r++; 253662306a36Sopenharmony_ci if (unlikely(++q->cidx == q->size)) { 253762306a36Sopenharmony_ci q->cidx = 0; 253862306a36Sopenharmony_ci q->gen ^= 1; 253962306a36Sopenharmony_ci r = q->desc; 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci prefetch(r); 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci if (flags & RSPD_CTRL_MASK) { 254462306a36Sopenharmony_ci sleeping |= flags & RSPD_GTS_MASK; 254562306a36Sopenharmony_ci handle_rsp_cntrl_info(qs, flags); 254662306a36Sopenharmony_ci } 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci q->pure_rsps++; 254962306a36Sopenharmony_ci if (++q->credits >= (q->size / 4)) { 255062306a36Sopenharmony_ci refill_rspq(adap, q, q->credits); 255162306a36Sopenharmony_ci q->credits = 0; 255262306a36Sopenharmony_ci } 255362306a36Sopenharmony_ci if (!is_new_response(r, q)) 255462306a36Sopenharmony_ci break; 255562306a36Sopenharmony_ci dma_rmb(); 255662306a36Sopenharmony_ci } while (is_pure_response(r)); 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci if (sleeping) 255962306a36Sopenharmony_ci check_ring_db(adap, qs, sleeping); 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci smp_mb(); /* commit Tx queue .processed updates */ 256262306a36Sopenharmony_ci if (unlikely(qs->txq_stopped != 0)) 256362306a36Sopenharmony_ci restart_tx(qs); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci return is_new_response(r, q); 256662306a36Sopenharmony_ci} 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci/** 256962306a36Sopenharmony_ci * handle_responses - decide what to do with new responses in NAPI mode 257062306a36Sopenharmony_ci * @adap: the adapter 257162306a36Sopenharmony_ci * @q: the response queue 257262306a36Sopenharmony_ci * 257362306a36Sopenharmony_ci * This is used by the NAPI interrupt handlers to decide what to do with 257462306a36Sopenharmony_ci * new SGE responses. If there are no new responses it returns -1. If 257562306a36Sopenharmony_ci * there are new responses and they are pure (i.e., non-data carrying) 257662306a36Sopenharmony_ci * it handles them straight in hard interrupt context as they are very 257762306a36Sopenharmony_ci * cheap and don't deliver any packets. Finally, if there are any data 257862306a36Sopenharmony_ci * signaling responses it schedules the NAPI handler. Returns 1 if it 257962306a36Sopenharmony_ci * schedules NAPI, 0 if all new responses were pure. 258062306a36Sopenharmony_ci * 258162306a36Sopenharmony_ci * The caller must ascertain NAPI is not already running. 258262306a36Sopenharmony_ci */ 258362306a36Sopenharmony_cistatic inline int handle_responses(struct adapter *adap, struct sge_rspq *q) 258462306a36Sopenharmony_ci{ 258562306a36Sopenharmony_ci struct sge_qset *qs = rspq_to_qset(q); 258662306a36Sopenharmony_ci struct rsp_desc *r = &q->desc[q->cidx]; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci if (!is_new_response(r, q)) 258962306a36Sopenharmony_ci return -1; 259062306a36Sopenharmony_ci dma_rmb(); 259162306a36Sopenharmony_ci if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { 259262306a36Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | 259362306a36Sopenharmony_ci V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); 259462306a36Sopenharmony_ci return 0; 259562306a36Sopenharmony_ci } 259662306a36Sopenharmony_ci napi_schedule(&qs->napi); 259762306a36Sopenharmony_ci return 1; 259862306a36Sopenharmony_ci} 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci/* 260162306a36Sopenharmony_ci * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case 260262306a36Sopenharmony_ci * (i.e., response queue serviced in hard interrupt). 260362306a36Sopenharmony_ci */ 260462306a36Sopenharmony_cistatic irqreturn_t t3_sge_intr_msix(int irq, void *cookie) 260562306a36Sopenharmony_ci{ 260662306a36Sopenharmony_ci struct sge_qset *qs = cookie; 260762306a36Sopenharmony_ci struct adapter *adap = qs->adap; 260862306a36Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci spin_lock(&q->lock); 261162306a36Sopenharmony_ci if (process_responses(adap, qs, -1) == 0) 261262306a36Sopenharmony_ci q->unhandled_irqs++; 261362306a36Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | 261462306a36Sopenharmony_ci V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); 261562306a36Sopenharmony_ci spin_unlock(&q->lock); 261662306a36Sopenharmony_ci return IRQ_HANDLED; 261762306a36Sopenharmony_ci} 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci/* 262062306a36Sopenharmony_ci * The MSI-X interrupt handler for an SGE response queue for the NAPI case 262162306a36Sopenharmony_ci * (i.e., response queue serviced by NAPI polling). 262262306a36Sopenharmony_ci */ 262362306a36Sopenharmony_cistatic irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) 262462306a36Sopenharmony_ci{ 262562306a36Sopenharmony_ci struct sge_qset *qs = cookie; 262662306a36Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci spin_lock(&q->lock); 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci if (handle_responses(qs->adap, q) < 0) 263162306a36Sopenharmony_ci q->unhandled_irqs++; 263262306a36Sopenharmony_ci spin_unlock(&q->lock); 263362306a36Sopenharmony_ci return IRQ_HANDLED; 263462306a36Sopenharmony_ci} 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci/* 263762306a36Sopenharmony_ci * The non-NAPI MSI interrupt handler. This needs to handle data events from 263862306a36Sopenharmony_ci * SGE response queues as well as error and other async events as they all use 263962306a36Sopenharmony_ci * the same MSI vector. We use one SGE response queue per port in this mode 264062306a36Sopenharmony_ci * and protect all response queues with queue 0's lock. 264162306a36Sopenharmony_ci */ 264262306a36Sopenharmony_cistatic irqreturn_t t3_intr_msi(int irq, void *cookie) 264362306a36Sopenharmony_ci{ 264462306a36Sopenharmony_ci int new_packets = 0; 264562306a36Sopenharmony_ci struct adapter *adap = cookie; 264662306a36Sopenharmony_ci struct sge_rspq *q = &adap->sge.qs[0].rspq; 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci spin_lock(&q->lock); 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci if (process_responses(adap, &adap->sge.qs[0], -1)) { 265162306a36Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | 265262306a36Sopenharmony_ci V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); 265362306a36Sopenharmony_ci new_packets = 1; 265462306a36Sopenharmony_ci } 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci if (adap->params.nports == 2 && 265762306a36Sopenharmony_ci process_responses(adap, &adap->sge.qs[1], -1)) { 265862306a36Sopenharmony_ci struct sge_rspq *q1 = &adap->sge.qs[1].rspq; 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) | 266162306a36Sopenharmony_ci V_NEWTIMER(q1->next_holdoff) | 266262306a36Sopenharmony_ci V_NEWINDEX(q1->cidx)); 266362306a36Sopenharmony_ci new_packets = 1; 266462306a36Sopenharmony_ci } 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci if (!new_packets && t3_slow_intr_handler(adap) == 0) 266762306a36Sopenharmony_ci q->unhandled_irqs++; 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci spin_unlock(&q->lock); 267062306a36Sopenharmony_ci return IRQ_HANDLED; 267162306a36Sopenharmony_ci} 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_cistatic int rspq_check_napi(struct sge_qset *qs) 267462306a36Sopenharmony_ci{ 267562306a36Sopenharmony_ci struct sge_rspq *q = &qs->rspq; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci if (!napi_is_scheduled(&qs->napi) && 267862306a36Sopenharmony_ci is_new_response(&q->desc[q->cidx], q)) { 267962306a36Sopenharmony_ci napi_schedule(&qs->napi); 268062306a36Sopenharmony_ci return 1; 268162306a36Sopenharmony_ci } 268262306a36Sopenharmony_ci return 0; 268362306a36Sopenharmony_ci} 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci/* 268662306a36Sopenharmony_ci * The MSI interrupt handler for the NAPI case (i.e., response queues serviced 268762306a36Sopenharmony_ci * by NAPI polling). Handles data events from SGE response queues as well as 268862306a36Sopenharmony_ci * error and other async events as they all use the same MSI vector. We use 268962306a36Sopenharmony_ci * one SGE response queue per port in this mode and protect all response 269062306a36Sopenharmony_ci * queues with queue 0's lock. 269162306a36Sopenharmony_ci */ 269262306a36Sopenharmony_cistatic irqreturn_t t3_intr_msi_napi(int irq, void *cookie) 269362306a36Sopenharmony_ci{ 269462306a36Sopenharmony_ci int new_packets; 269562306a36Sopenharmony_ci struct adapter *adap = cookie; 269662306a36Sopenharmony_ci struct sge_rspq *q = &adap->sge.qs[0].rspq; 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci spin_lock(&q->lock); 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci new_packets = rspq_check_napi(&adap->sge.qs[0]); 270162306a36Sopenharmony_ci if (adap->params.nports == 2) 270262306a36Sopenharmony_ci new_packets += rspq_check_napi(&adap->sge.qs[1]); 270362306a36Sopenharmony_ci if (!new_packets && t3_slow_intr_handler(adap) == 0) 270462306a36Sopenharmony_ci q->unhandled_irqs++; 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci spin_unlock(&q->lock); 270762306a36Sopenharmony_ci return IRQ_HANDLED; 270862306a36Sopenharmony_ci} 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci/* 271162306a36Sopenharmony_ci * A helper function that processes responses and issues GTS. 271262306a36Sopenharmony_ci */ 271362306a36Sopenharmony_cistatic inline int process_responses_gts(struct adapter *adap, 271462306a36Sopenharmony_ci struct sge_rspq *rq) 271562306a36Sopenharmony_ci{ 271662306a36Sopenharmony_ci int work; 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci work = process_responses(adap, rspq_to_qset(rq), -1); 271962306a36Sopenharmony_ci t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) | 272062306a36Sopenharmony_ci V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx)); 272162306a36Sopenharmony_ci return work; 272262306a36Sopenharmony_ci} 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci/* 272562306a36Sopenharmony_ci * The legacy INTx interrupt handler. This needs to handle data events from 272662306a36Sopenharmony_ci * SGE response queues as well as error and other async events as they all use 272762306a36Sopenharmony_ci * the same interrupt pin. We use one SGE response queue per port in this mode 272862306a36Sopenharmony_ci * and protect all response queues with queue 0's lock. 272962306a36Sopenharmony_ci */ 273062306a36Sopenharmony_cistatic irqreturn_t t3_intr(int irq, void *cookie) 273162306a36Sopenharmony_ci{ 273262306a36Sopenharmony_ci int work_done, w0, w1; 273362306a36Sopenharmony_ci struct adapter *adap = cookie; 273462306a36Sopenharmony_ci struct sge_rspq *q0 = &adap->sge.qs[0].rspq; 273562306a36Sopenharmony_ci struct sge_rspq *q1 = &adap->sge.qs[1].rspq; 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci spin_lock(&q0->lock); 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci w0 = is_new_response(&q0->desc[q0->cidx], q0); 274062306a36Sopenharmony_ci w1 = adap->params.nports == 2 && 274162306a36Sopenharmony_ci is_new_response(&q1->desc[q1->cidx], q1); 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci if (likely(w0 | w1)) { 274462306a36Sopenharmony_ci t3_write_reg(adap, A_PL_CLI, 0); 274562306a36Sopenharmony_ci t3_read_reg(adap, A_PL_CLI); /* flush */ 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci if (likely(w0)) 274862306a36Sopenharmony_ci process_responses_gts(adap, q0); 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci if (w1) 275162306a36Sopenharmony_ci process_responses_gts(adap, q1); 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci work_done = w0 | w1; 275462306a36Sopenharmony_ci } else 275562306a36Sopenharmony_ci work_done = t3_slow_intr_handler(adap); 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci spin_unlock(&q0->lock); 275862306a36Sopenharmony_ci return IRQ_RETVAL(work_done != 0); 275962306a36Sopenharmony_ci} 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci/* 276262306a36Sopenharmony_ci * Interrupt handler for legacy INTx interrupts for T3B-based cards. 276362306a36Sopenharmony_ci * Handles data events from SGE response queues as well as error and other 276462306a36Sopenharmony_ci * async events as they all use the same interrupt pin. We use one SGE 276562306a36Sopenharmony_ci * response queue per port in this mode and protect all response queues with 276662306a36Sopenharmony_ci * queue 0's lock. 276762306a36Sopenharmony_ci */ 276862306a36Sopenharmony_cistatic irqreturn_t t3b_intr(int irq, void *cookie) 276962306a36Sopenharmony_ci{ 277062306a36Sopenharmony_ci u32 map; 277162306a36Sopenharmony_ci struct adapter *adap = cookie; 277262306a36Sopenharmony_ci struct sge_rspq *q0 = &adap->sge.qs[0].rspq; 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci t3_write_reg(adap, A_PL_CLI, 0); 277562306a36Sopenharmony_ci map = t3_read_reg(adap, A_SG_DATA_INTR); 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci if (unlikely(!map)) /* shared interrupt, most likely */ 277862306a36Sopenharmony_ci return IRQ_NONE; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci spin_lock(&q0->lock); 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci if (unlikely(map & F_ERRINTR)) 278362306a36Sopenharmony_ci t3_slow_intr_handler(adap); 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci if (likely(map & 1)) 278662306a36Sopenharmony_ci process_responses_gts(adap, q0); 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci if (map & 2) 278962306a36Sopenharmony_ci process_responses_gts(adap, &adap->sge.qs[1].rspq); 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci spin_unlock(&q0->lock); 279262306a36Sopenharmony_ci return IRQ_HANDLED; 279362306a36Sopenharmony_ci} 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci/* 279662306a36Sopenharmony_ci * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards. 279762306a36Sopenharmony_ci * Handles data events from SGE response queues as well as error and other 279862306a36Sopenharmony_ci * async events as they all use the same interrupt pin. We use one SGE 279962306a36Sopenharmony_ci * response queue per port in this mode and protect all response queues with 280062306a36Sopenharmony_ci * queue 0's lock. 280162306a36Sopenharmony_ci */ 280262306a36Sopenharmony_cistatic irqreturn_t t3b_intr_napi(int irq, void *cookie) 280362306a36Sopenharmony_ci{ 280462306a36Sopenharmony_ci u32 map; 280562306a36Sopenharmony_ci struct adapter *adap = cookie; 280662306a36Sopenharmony_ci struct sge_qset *qs0 = &adap->sge.qs[0]; 280762306a36Sopenharmony_ci struct sge_rspq *q0 = &qs0->rspq; 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci t3_write_reg(adap, A_PL_CLI, 0); 281062306a36Sopenharmony_ci map = t3_read_reg(adap, A_SG_DATA_INTR); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci if (unlikely(!map)) /* shared interrupt, most likely */ 281362306a36Sopenharmony_ci return IRQ_NONE; 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci spin_lock(&q0->lock); 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci if (unlikely(map & F_ERRINTR)) 281862306a36Sopenharmony_ci t3_slow_intr_handler(adap); 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci if (likely(map & 1)) 282162306a36Sopenharmony_ci napi_schedule(&qs0->napi); 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci if (map & 2) 282462306a36Sopenharmony_ci napi_schedule(&adap->sge.qs[1].napi); 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci spin_unlock(&q0->lock); 282762306a36Sopenharmony_ci return IRQ_HANDLED; 282862306a36Sopenharmony_ci} 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci/** 283162306a36Sopenharmony_ci * t3_intr_handler - select the top-level interrupt handler 283262306a36Sopenharmony_ci * @adap: the adapter 283362306a36Sopenharmony_ci * @polling: whether using NAPI to service response queues 283462306a36Sopenharmony_ci * 283562306a36Sopenharmony_ci * Selects the top-level interrupt handler based on the type of interrupts 283662306a36Sopenharmony_ci * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the 283762306a36Sopenharmony_ci * response queues. 283862306a36Sopenharmony_ci */ 283962306a36Sopenharmony_ciirq_handler_t t3_intr_handler(struct adapter *adap, int polling) 284062306a36Sopenharmony_ci{ 284162306a36Sopenharmony_ci if (adap->flags & USING_MSIX) 284262306a36Sopenharmony_ci return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix; 284362306a36Sopenharmony_ci if (adap->flags & USING_MSI) 284462306a36Sopenharmony_ci return polling ? t3_intr_msi_napi : t3_intr_msi; 284562306a36Sopenharmony_ci if (adap->params.rev > 0) 284662306a36Sopenharmony_ci return polling ? t3b_intr_napi : t3b_intr; 284762306a36Sopenharmony_ci return t3_intr; 284862306a36Sopenharmony_ci} 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci#define SGE_PARERR (F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ 285162306a36Sopenharmony_ci F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ 285262306a36Sopenharmony_ci V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ 285362306a36Sopenharmony_ci F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ 285462306a36Sopenharmony_ci F_HIRCQPARITYERROR) 285562306a36Sopenharmony_ci#define SGE_FRAMINGERR (F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR) 285662306a36Sopenharmony_ci#define SGE_FATALERR (SGE_PARERR | SGE_FRAMINGERR | F_RSPQCREDITOVERFOW | \ 285762306a36Sopenharmony_ci F_RSPQDISABLED) 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci/** 286062306a36Sopenharmony_ci * t3_sge_err_intr_handler - SGE async event interrupt handler 286162306a36Sopenharmony_ci * @adapter: the adapter 286262306a36Sopenharmony_ci * 286362306a36Sopenharmony_ci * Interrupt handler for SGE asynchronous (non-data) events. 286462306a36Sopenharmony_ci */ 286562306a36Sopenharmony_civoid t3_sge_err_intr_handler(struct adapter *adapter) 286662306a36Sopenharmony_ci{ 286762306a36Sopenharmony_ci unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE) & 286862306a36Sopenharmony_ci ~F_FLEMPTY; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci if (status & SGE_PARERR) 287162306a36Sopenharmony_ci CH_ALERT(adapter, "SGE parity error (0x%x)\n", 287262306a36Sopenharmony_ci status & SGE_PARERR); 287362306a36Sopenharmony_ci if (status & SGE_FRAMINGERR) 287462306a36Sopenharmony_ci CH_ALERT(adapter, "SGE framing error (0x%x)\n", 287562306a36Sopenharmony_ci status & SGE_FRAMINGERR); 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci if (status & F_RSPQCREDITOVERFOW) 287862306a36Sopenharmony_ci CH_ALERT(adapter, "SGE response queue credit overflow\n"); 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci if (status & F_RSPQDISABLED) { 288162306a36Sopenharmony_ci v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS); 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci CH_ALERT(adapter, 288462306a36Sopenharmony_ci "packet delivered to disabled response queue " 288562306a36Sopenharmony_ci "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff); 288662306a36Sopenharmony_ci } 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) 288962306a36Sopenharmony_ci queue_work(cxgb3_wq, &adapter->db_drop_task); 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci if (status & (F_HIPRIORITYDBFULL | F_LOPRIORITYDBFULL)) 289262306a36Sopenharmony_ci queue_work(cxgb3_wq, &adapter->db_full_task); 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci if (status & (F_HIPRIORITYDBEMPTY | F_LOPRIORITYDBEMPTY)) 289562306a36Sopenharmony_ci queue_work(cxgb3_wq, &adapter->db_empty_task); 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci t3_write_reg(adapter, A_SG_INT_CAUSE, status); 289862306a36Sopenharmony_ci if (status & SGE_FATALERR) 289962306a36Sopenharmony_ci t3_fatal_err(adapter); 290062306a36Sopenharmony_ci} 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci/** 290362306a36Sopenharmony_ci * sge_timer_tx - perform periodic maintenance of an SGE qset 290462306a36Sopenharmony_ci * @t: a timer list containing the SGE queue set to maintain 290562306a36Sopenharmony_ci * 290662306a36Sopenharmony_ci * Runs periodically from a timer to perform maintenance of an SGE queue 290762306a36Sopenharmony_ci * set. It performs two tasks: 290862306a36Sopenharmony_ci * 290962306a36Sopenharmony_ci * Cleans up any completed Tx descriptors that may still be pending. 291062306a36Sopenharmony_ci * Normal descriptor cleanup happens when new packets are added to a Tx 291162306a36Sopenharmony_ci * queue so this timer is relatively infrequent and does any cleanup only 291262306a36Sopenharmony_ci * if the Tx queue has not seen any new packets in a while. We make a 291362306a36Sopenharmony_ci * best effort attempt to reclaim descriptors, in that we don't wait 291462306a36Sopenharmony_ci * around if we cannot get a queue's lock (which most likely is because 291562306a36Sopenharmony_ci * someone else is queueing new packets and so will also handle the clean 291662306a36Sopenharmony_ci * up). Since control queues use immediate data exclusively we don't 291762306a36Sopenharmony_ci * bother cleaning them up here. 291862306a36Sopenharmony_ci * 291962306a36Sopenharmony_ci */ 292062306a36Sopenharmony_cistatic void sge_timer_tx(struct timer_list *t) 292162306a36Sopenharmony_ci{ 292262306a36Sopenharmony_ci struct sge_qset *qs = from_timer(qs, t, tx_reclaim_timer); 292362306a36Sopenharmony_ci struct port_info *pi = netdev_priv(qs->netdev); 292462306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 292562306a36Sopenharmony_ci unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0}; 292662306a36Sopenharmony_ci unsigned long next_period; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci if (__netif_tx_trylock(qs->tx_q)) { 292962306a36Sopenharmony_ci tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], 293062306a36Sopenharmony_ci TX_RECLAIM_TIMER_CHUNK); 293162306a36Sopenharmony_ci __netif_tx_unlock(qs->tx_q); 293262306a36Sopenharmony_ci } 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { 293562306a36Sopenharmony_ci tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD], 293662306a36Sopenharmony_ci TX_RECLAIM_TIMER_CHUNK); 293762306a36Sopenharmony_ci spin_unlock(&qs->txq[TXQ_OFLD].lock); 293862306a36Sopenharmony_ci } 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci next_period = TX_RECLAIM_PERIOD >> 294162306a36Sopenharmony_ci (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / 294262306a36Sopenharmony_ci TX_RECLAIM_TIMER_CHUNK); 294362306a36Sopenharmony_ci mod_timer(&qs->tx_reclaim_timer, jiffies + next_period); 294462306a36Sopenharmony_ci} 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci/** 294762306a36Sopenharmony_ci * sge_timer_rx - perform periodic maintenance of an SGE qset 294862306a36Sopenharmony_ci * @t: the timer list containing the SGE queue set to maintain 294962306a36Sopenharmony_ci * 295062306a36Sopenharmony_ci * a) Replenishes Rx queues that have run out due to memory shortage. 295162306a36Sopenharmony_ci * Normally new Rx buffers are added when existing ones are consumed but 295262306a36Sopenharmony_ci * when out of memory a queue can become empty. We try to add only a few 295362306a36Sopenharmony_ci * buffers here, the queue will be replenished fully as these new buffers 295462306a36Sopenharmony_ci * are used up if memory shortage has subsided. 295562306a36Sopenharmony_ci * 295662306a36Sopenharmony_ci * b) Return coalesced response queue credits in case a response queue is 295762306a36Sopenharmony_ci * starved. 295862306a36Sopenharmony_ci * 295962306a36Sopenharmony_ci */ 296062306a36Sopenharmony_cistatic void sge_timer_rx(struct timer_list *t) 296162306a36Sopenharmony_ci{ 296262306a36Sopenharmony_ci spinlock_t *lock; 296362306a36Sopenharmony_ci struct sge_qset *qs = from_timer(qs, t, rx_reclaim_timer); 296462306a36Sopenharmony_ci struct port_info *pi = netdev_priv(qs->netdev); 296562306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 296662306a36Sopenharmony_ci u32 status; 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci lock = adap->params.rev > 0 ? 296962306a36Sopenharmony_ci &qs->rspq.lock : &adap->sge.qs[0].rspq.lock; 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci if (!spin_trylock_irq(lock)) 297262306a36Sopenharmony_ci goto out; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci if (napi_is_scheduled(&qs->napi)) 297562306a36Sopenharmony_ci goto unlock; 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci if (adap->params.rev < 4) { 297862306a36Sopenharmony_ci status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS); 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci if (status & (1 << qs->rspq.cntxt_id)) { 298162306a36Sopenharmony_ci qs->rspq.starved++; 298262306a36Sopenharmony_ci if (qs->rspq.credits) { 298362306a36Sopenharmony_ci qs->rspq.credits--; 298462306a36Sopenharmony_ci refill_rspq(adap, &qs->rspq, 1); 298562306a36Sopenharmony_ci qs->rspq.restarted++; 298662306a36Sopenharmony_ci t3_write_reg(adap, A_SG_RSPQ_FL_STATUS, 298762306a36Sopenharmony_ci 1 << qs->rspq.cntxt_id); 298862306a36Sopenharmony_ci } 298962306a36Sopenharmony_ci } 299062306a36Sopenharmony_ci } 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci if (qs->fl[0].credits < qs->fl[0].size) 299362306a36Sopenharmony_ci __refill_fl(adap, &qs->fl[0]); 299462306a36Sopenharmony_ci if (qs->fl[1].credits < qs->fl[1].size) 299562306a36Sopenharmony_ci __refill_fl(adap, &qs->fl[1]); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ciunlock: 299862306a36Sopenharmony_ci spin_unlock_irq(lock); 299962306a36Sopenharmony_ciout: 300062306a36Sopenharmony_ci mod_timer(&qs->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); 300162306a36Sopenharmony_ci} 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci/** 300462306a36Sopenharmony_ci * t3_update_qset_coalesce - update coalescing settings for a queue set 300562306a36Sopenharmony_ci * @qs: the SGE queue set 300662306a36Sopenharmony_ci * @p: new queue set parameters 300762306a36Sopenharmony_ci * 300862306a36Sopenharmony_ci * Update the coalescing settings for an SGE queue set. Nothing is done 300962306a36Sopenharmony_ci * if the queue set is not initialized yet. 301062306a36Sopenharmony_ci */ 301162306a36Sopenharmony_civoid t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) 301262306a36Sopenharmony_ci{ 301362306a36Sopenharmony_ci qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */ 301462306a36Sopenharmony_ci qs->rspq.polling = p->polling; 301562306a36Sopenharmony_ci qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll; 301662306a36Sopenharmony_ci} 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci/** 301962306a36Sopenharmony_ci * t3_sge_alloc_qset - initialize an SGE queue set 302062306a36Sopenharmony_ci * @adapter: the adapter 302162306a36Sopenharmony_ci * @id: the queue set id 302262306a36Sopenharmony_ci * @nports: how many Ethernet ports will be using this queue set 302362306a36Sopenharmony_ci * @irq_vec_idx: the IRQ vector index for response queue interrupts 302462306a36Sopenharmony_ci * @p: configuration parameters for this queue set 302562306a36Sopenharmony_ci * @ntxq: number of Tx queues for the queue set 302662306a36Sopenharmony_ci * @dev: net device associated with this queue set 302762306a36Sopenharmony_ci * @netdevq: net device TX queue associated with this queue set 302862306a36Sopenharmony_ci * 302962306a36Sopenharmony_ci * Allocate resources and initialize an SGE queue set. A queue set 303062306a36Sopenharmony_ci * comprises a response queue, two Rx free-buffer queues, and up to 3 303162306a36Sopenharmony_ci * Tx queues. The Tx queues are assigned roles in the order Ethernet 303262306a36Sopenharmony_ci * queue, offload queue, and control queue. 303362306a36Sopenharmony_ci */ 303462306a36Sopenharmony_ciint t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, 303562306a36Sopenharmony_ci int irq_vec_idx, const struct qset_params *p, 303662306a36Sopenharmony_ci int ntxq, struct net_device *dev, 303762306a36Sopenharmony_ci struct netdev_queue *netdevq) 303862306a36Sopenharmony_ci{ 303962306a36Sopenharmony_ci int i, avail, ret = -ENOMEM; 304062306a36Sopenharmony_ci struct sge_qset *q = &adapter->sge.qs[id]; 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci init_qset_cntxt(q, id); 304362306a36Sopenharmony_ci timer_setup(&q->tx_reclaim_timer, sge_timer_tx, 0); 304462306a36Sopenharmony_ci timer_setup(&q->rx_reclaim_timer, sge_timer_rx, 0); 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size, 304762306a36Sopenharmony_ci sizeof(struct rx_desc), 304862306a36Sopenharmony_ci sizeof(struct rx_sw_desc), 304962306a36Sopenharmony_ci &q->fl[0].phys_addr, &q->fl[0].sdesc); 305062306a36Sopenharmony_ci if (!q->fl[0].desc) 305162306a36Sopenharmony_ci goto err; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size, 305462306a36Sopenharmony_ci sizeof(struct rx_desc), 305562306a36Sopenharmony_ci sizeof(struct rx_sw_desc), 305662306a36Sopenharmony_ci &q->fl[1].phys_addr, &q->fl[1].sdesc); 305762306a36Sopenharmony_ci if (!q->fl[1].desc) 305862306a36Sopenharmony_ci goto err; 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size, 306162306a36Sopenharmony_ci sizeof(struct rsp_desc), 0, 306262306a36Sopenharmony_ci &q->rspq.phys_addr, NULL); 306362306a36Sopenharmony_ci if (!q->rspq.desc) 306462306a36Sopenharmony_ci goto err; 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci for (i = 0; i < ntxq; ++i) { 306762306a36Sopenharmony_ci /* 306862306a36Sopenharmony_ci * The control queue always uses immediate data so does not 306962306a36Sopenharmony_ci * need to keep track of any sk_buffs. 307062306a36Sopenharmony_ci */ 307162306a36Sopenharmony_ci size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc); 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i], 307462306a36Sopenharmony_ci sizeof(struct tx_desc), sz, 307562306a36Sopenharmony_ci &q->txq[i].phys_addr, 307662306a36Sopenharmony_ci &q->txq[i].sdesc); 307762306a36Sopenharmony_ci if (!q->txq[i].desc) 307862306a36Sopenharmony_ci goto err; 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci q->txq[i].gen = 1; 308162306a36Sopenharmony_ci q->txq[i].size = p->txq_size[i]; 308262306a36Sopenharmony_ci spin_lock_init(&q->txq[i].lock); 308362306a36Sopenharmony_ci skb_queue_head_init(&q->txq[i].sendq); 308462306a36Sopenharmony_ci } 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_ci INIT_WORK(&q->txq[TXQ_OFLD].qresume_task, restart_offloadq); 308762306a36Sopenharmony_ci INIT_WORK(&q->txq[TXQ_CTRL].qresume_task, restart_ctrlq); 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_ci q->fl[0].gen = q->fl[1].gen = 1; 309062306a36Sopenharmony_ci q->fl[0].size = p->fl_size; 309162306a36Sopenharmony_ci q->fl[1].size = p->jumbo_size; 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_ci q->rspq.gen = 1; 309462306a36Sopenharmony_ci q->rspq.size = p->rspq_size; 309562306a36Sopenharmony_ci spin_lock_init(&q->rspq.lock); 309662306a36Sopenharmony_ci skb_queue_head_init(&q->rspq.rx_queue); 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci q->txq[TXQ_ETH].stop_thres = nports * 309962306a36Sopenharmony_ci flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3); 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci#if FL0_PG_CHUNK_SIZE > 0 310262306a36Sopenharmony_ci q->fl[0].buf_size = FL0_PG_CHUNK_SIZE; 310362306a36Sopenharmony_ci#else 310462306a36Sopenharmony_ci q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); 310562306a36Sopenharmony_ci#endif 310662306a36Sopenharmony_ci#if FL1_PG_CHUNK_SIZE > 0 310762306a36Sopenharmony_ci q->fl[1].buf_size = FL1_PG_CHUNK_SIZE; 310862306a36Sopenharmony_ci#else 310962306a36Sopenharmony_ci q->fl[1].buf_size = is_offload(adapter) ? 311062306a36Sopenharmony_ci (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : 311162306a36Sopenharmony_ci MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt); 311262306a36Sopenharmony_ci#endif 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; 311562306a36Sopenharmony_ci q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0; 311662306a36Sopenharmony_ci q->fl[0].order = FL0_PG_ORDER; 311762306a36Sopenharmony_ci q->fl[1].order = FL1_PG_ORDER; 311862306a36Sopenharmony_ci q->fl[0].alloc_size = FL0_PG_ALLOC_SIZE; 311962306a36Sopenharmony_ci q->fl[1].alloc_size = FL1_PG_ALLOC_SIZE; 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci /* FL threshold comparison uses < */ 312462306a36Sopenharmony_ci ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx, 312562306a36Sopenharmony_ci q->rspq.phys_addr, q->rspq.size, 312662306a36Sopenharmony_ci q->fl[0].buf_size - SGE_PG_RSVD, 1, 0); 312762306a36Sopenharmony_ci if (ret) 312862306a36Sopenharmony_ci goto err_unlock; 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci for (i = 0; i < SGE_RXQ_PER_SET; ++i) { 313162306a36Sopenharmony_ci ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0, 313262306a36Sopenharmony_ci q->fl[i].phys_addr, q->fl[i].size, 313362306a36Sopenharmony_ci q->fl[i].buf_size - SGE_PG_RSVD, 313462306a36Sopenharmony_ci p->cong_thres, 1, 0); 313562306a36Sopenharmony_ci if (ret) 313662306a36Sopenharmony_ci goto err_unlock; 313762306a36Sopenharmony_ci } 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS, 314062306a36Sopenharmony_ci SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr, 314162306a36Sopenharmony_ci q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token, 314262306a36Sopenharmony_ci 1, 0); 314362306a36Sopenharmony_ci if (ret) 314462306a36Sopenharmony_ci goto err_unlock; 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci if (ntxq > 1) { 314762306a36Sopenharmony_ci ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id, 314862306a36Sopenharmony_ci USE_GTS, SGE_CNTXT_OFLD, id, 314962306a36Sopenharmony_ci q->txq[TXQ_OFLD].phys_addr, 315062306a36Sopenharmony_ci q->txq[TXQ_OFLD].size, 0, 1, 0); 315162306a36Sopenharmony_ci if (ret) 315262306a36Sopenharmony_ci goto err_unlock; 315362306a36Sopenharmony_ci } 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci if (ntxq > 2) { 315662306a36Sopenharmony_ci ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0, 315762306a36Sopenharmony_ci SGE_CNTXT_CTRL, id, 315862306a36Sopenharmony_ci q->txq[TXQ_CTRL].phys_addr, 315962306a36Sopenharmony_ci q->txq[TXQ_CTRL].size, 316062306a36Sopenharmony_ci q->txq[TXQ_CTRL].token, 1, 0); 316162306a36Sopenharmony_ci if (ret) 316262306a36Sopenharmony_ci goto err_unlock; 316362306a36Sopenharmony_ci } 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci q->adap = adapter; 316862306a36Sopenharmony_ci q->netdev = dev; 316962306a36Sopenharmony_ci q->tx_q = netdevq; 317062306a36Sopenharmony_ci t3_update_qset_coalesce(q, p); 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, 317362306a36Sopenharmony_ci GFP_KERNEL | __GFP_COMP); 317462306a36Sopenharmony_ci if (!avail) { 317562306a36Sopenharmony_ci CH_ALERT(adapter, "free list queue 0 initialization failed\n"); 317662306a36Sopenharmony_ci ret = -ENOMEM; 317762306a36Sopenharmony_ci goto err; 317862306a36Sopenharmony_ci } 317962306a36Sopenharmony_ci if (avail < q->fl[0].size) 318062306a36Sopenharmony_ci CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", 318162306a36Sopenharmony_ci avail); 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, 318462306a36Sopenharmony_ci GFP_KERNEL | __GFP_COMP); 318562306a36Sopenharmony_ci if (avail < q->fl[1].size) 318662306a36Sopenharmony_ci CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", 318762306a36Sopenharmony_ci avail); 318862306a36Sopenharmony_ci refill_rspq(adapter, &q->rspq, q->rspq.size - 1); 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) | 319162306a36Sopenharmony_ci V_NEWTIMER(q->rspq.holdoff_tmr)); 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci return 0; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_cierr_unlock: 319662306a36Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 319762306a36Sopenharmony_cierr: 319862306a36Sopenharmony_ci t3_free_qset(adapter, q); 319962306a36Sopenharmony_ci return ret; 320062306a36Sopenharmony_ci} 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci/** 320362306a36Sopenharmony_ci * t3_start_sge_timers - start SGE timer call backs 320462306a36Sopenharmony_ci * @adap: the adapter 320562306a36Sopenharmony_ci * 320662306a36Sopenharmony_ci * Starts each SGE queue set's timer call back 320762306a36Sopenharmony_ci */ 320862306a36Sopenharmony_civoid t3_start_sge_timers(struct adapter *adap) 320962306a36Sopenharmony_ci{ 321062306a36Sopenharmony_ci int i; 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) { 321362306a36Sopenharmony_ci struct sge_qset *q = &adap->sge.qs[i]; 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci if (q->tx_reclaim_timer.function) 321662306a36Sopenharmony_ci mod_timer(&q->tx_reclaim_timer, 321762306a36Sopenharmony_ci jiffies + TX_RECLAIM_PERIOD); 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci if (q->rx_reclaim_timer.function) 322062306a36Sopenharmony_ci mod_timer(&q->rx_reclaim_timer, 322162306a36Sopenharmony_ci jiffies + RX_RECLAIM_PERIOD); 322262306a36Sopenharmony_ci } 322362306a36Sopenharmony_ci} 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci/** 322662306a36Sopenharmony_ci * t3_stop_sge_timers - stop SGE timer call backs 322762306a36Sopenharmony_ci * @adap: the adapter 322862306a36Sopenharmony_ci * 322962306a36Sopenharmony_ci * Stops each SGE queue set's timer call back 323062306a36Sopenharmony_ci */ 323162306a36Sopenharmony_civoid t3_stop_sge_timers(struct adapter *adap) 323262306a36Sopenharmony_ci{ 323362306a36Sopenharmony_ci int i; 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) { 323662306a36Sopenharmony_ci struct sge_qset *q = &adap->sge.qs[i]; 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci if (q->tx_reclaim_timer.function) 323962306a36Sopenharmony_ci del_timer_sync(&q->tx_reclaim_timer); 324062306a36Sopenharmony_ci if (q->rx_reclaim_timer.function) 324162306a36Sopenharmony_ci del_timer_sync(&q->rx_reclaim_timer); 324262306a36Sopenharmony_ci } 324362306a36Sopenharmony_ci} 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci/** 324662306a36Sopenharmony_ci * t3_free_sge_resources - free SGE resources 324762306a36Sopenharmony_ci * @adap: the adapter 324862306a36Sopenharmony_ci * 324962306a36Sopenharmony_ci * Frees resources used by the SGE queue sets. 325062306a36Sopenharmony_ci */ 325162306a36Sopenharmony_civoid t3_free_sge_resources(struct adapter *adap) 325262306a36Sopenharmony_ci{ 325362306a36Sopenharmony_ci int i; 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) 325662306a36Sopenharmony_ci t3_free_qset(adap, &adap->sge.qs[i]); 325762306a36Sopenharmony_ci} 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci/** 326062306a36Sopenharmony_ci * t3_sge_start - enable SGE 326162306a36Sopenharmony_ci * @adap: the adapter 326262306a36Sopenharmony_ci * 326362306a36Sopenharmony_ci * Enables the SGE for DMAs. This is the last step in starting packet 326462306a36Sopenharmony_ci * transfers. 326562306a36Sopenharmony_ci */ 326662306a36Sopenharmony_civoid t3_sge_start(struct adapter *adap) 326762306a36Sopenharmony_ci{ 326862306a36Sopenharmony_ci t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE); 326962306a36Sopenharmony_ci} 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci/** 327262306a36Sopenharmony_ci * t3_sge_stop_dma - Disable SGE DMA engine operation 327362306a36Sopenharmony_ci * @adap: the adapter 327462306a36Sopenharmony_ci * 327562306a36Sopenharmony_ci * Can be invoked from interrupt context e.g. error handler. 327662306a36Sopenharmony_ci * 327762306a36Sopenharmony_ci * Note that this function cannot disable the restart of works as 327862306a36Sopenharmony_ci * it cannot wait if called from interrupt context, however the 327962306a36Sopenharmony_ci * works will have no effect since the doorbells are disabled. The 328062306a36Sopenharmony_ci * driver will call tg3_sge_stop() later from process context, at 328162306a36Sopenharmony_ci * which time the works will be stopped if they are still running. 328262306a36Sopenharmony_ci */ 328362306a36Sopenharmony_civoid t3_sge_stop_dma(struct adapter *adap) 328462306a36Sopenharmony_ci{ 328562306a36Sopenharmony_ci t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0); 328662306a36Sopenharmony_ci} 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci/** 328962306a36Sopenharmony_ci * t3_sge_stop - disable SGE operation completly 329062306a36Sopenharmony_ci * @adap: the adapter 329162306a36Sopenharmony_ci * 329262306a36Sopenharmony_ci * Called from process context. Disables the DMA engine and any 329362306a36Sopenharmony_ci * pending queue restart works. 329462306a36Sopenharmony_ci */ 329562306a36Sopenharmony_civoid t3_sge_stop(struct adapter *adap) 329662306a36Sopenharmony_ci{ 329762306a36Sopenharmony_ci int i; 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci t3_sge_stop_dma(adap); 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci /* workqueues aren't initialized otherwise */ 330262306a36Sopenharmony_ci if (!(adap->flags & FULL_INIT_DONE)) 330362306a36Sopenharmony_ci return; 330462306a36Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) { 330562306a36Sopenharmony_ci struct sge_qset *qs = &adap->sge.qs[i]; 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci cancel_work_sync(&qs->txq[TXQ_OFLD].qresume_task); 330862306a36Sopenharmony_ci cancel_work_sync(&qs->txq[TXQ_CTRL].qresume_task); 330962306a36Sopenharmony_ci } 331062306a36Sopenharmony_ci} 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_ci/** 331362306a36Sopenharmony_ci * t3_sge_init - initialize SGE 331462306a36Sopenharmony_ci * @adap: the adapter 331562306a36Sopenharmony_ci * @p: the SGE parameters 331662306a36Sopenharmony_ci * 331762306a36Sopenharmony_ci * Performs SGE initialization needed every time after a chip reset. 331862306a36Sopenharmony_ci * We do not initialize any of the queue sets here, instead the driver 331962306a36Sopenharmony_ci * top-level must request those individually. We also do not enable DMA 332062306a36Sopenharmony_ci * here, that should be done after the queues have been set up. 332162306a36Sopenharmony_ci */ 332262306a36Sopenharmony_civoid t3_sge_init(struct adapter *adap, struct sge_params *p) 332362306a36Sopenharmony_ci{ 332462306a36Sopenharmony_ci unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12); 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_ci ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL | 332762306a36Sopenharmony_ci F_CQCRDTCTRL | F_CONGMODE | F_TNLFLMODE | F_FATLPERREN | 332862306a36Sopenharmony_ci V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS | 332962306a36Sopenharmony_ci V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING; 333062306a36Sopenharmony_ci#if SGE_NUM_GENBITS == 1 333162306a36Sopenharmony_ci ctrl |= F_EGRGENCTRL; 333262306a36Sopenharmony_ci#endif 333362306a36Sopenharmony_ci if (adap->params.rev > 0) { 333462306a36Sopenharmony_ci if (!(adap->flags & (USING_MSIX | USING_MSI))) 333562306a36Sopenharmony_ci ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ; 333662306a36Sopenharmony_ci } 333762306a36Sopenharmony_ci t3_write_reg(adap, A_SG_CONTROL, ctrl); 333862306a36Sopenharmony_ci t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) | 333962306a36Sopenharmony_ci V_LORCQDRBTHRSH(512)); 334062306a36Sopenharmony_ci t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10); 334162306a36Sopenharmony_ci t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) | 334262306a36Sopenharmony_ci V_TIMEOUT(200 * core_ticks_per_usec(adap))); 334362306a36Sopenharmony_ci t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 334462306a36Sopenharmony_ci adap->params.rev < T3_REV_C ? 1000 : 500); 334562306a36Sopenharmony_ci t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256); 334662306a36Sopenharmony_ci t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000); 334762306a36Sopenharmony_ci t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256); 334862306a36Sopenharmony_ci t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff)); 334962306a36Sopenharmony_ci t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024); 335062306a36Sopenharmony_ci} 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci/** 335362306a36Sopenharmony_ci * t3_sge_prep - one-time SGE initialization 335462306a36Sopenharmony_ci * @adap: the associated adapter 335562306a36Sopenharmony_ci * @p: SGE parameters 335662306a36Sopenharmony_ci * 335762306a36Sopenharmony_ci * Performs one-time initialization of SGE SW state. Includes determining 335862306a36Sopenharmony_ci * defaults for the assorted SGE parameters, which admins can change until 335962306a36Sopenharmony_ci * they are used to initialize the SGE. 336062306a36Sopenharmony_ci */ 336162306a36Sopenharmony_civoid t3_sge_prep(struct adapter *adap, struct sge_params *p) 336262306a36Sopenharmony_ci{ 336362306a36Sopenharmony_ci int i; 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_ci p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) - 336662306a36Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci for (i = 0; i < SGE_QSETS; ++i) { 336962306a36Sopenharmony_ci struct qset_params *q = p->qset + i; 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci q->polling = adap->params.rev > 0; 337262306a36Sopenharmony_ci q->coalesce_usecs = 5; 337362306a36Sopenharmony_ci q->rspq_size = 1024; 337462306a36Sopenharmony_ci q->fl_size = 1024; 337562306a36Sopenharmony_ci q->jumbo_size = 512; 337662306a36Sopenharmony_ci q->txq_size[TXQ_ETH] = 1024; 337762306a36Sopenharmony_ci q->txq_size[TXQ_OFLD] = 1024; 337862306a36Sopenharmony_ci q->txq_size[TXQ_CTRL] = 256; 337962306a36Sopenharmony_ci q->cong_thres = 0; 338062306a36Sopenharmony_ci } 338162306a36Sopenharmony_ci 338262306a36Sopenharmony_ci spin_lock_init(&adap->sge.reg_lock); 338362306a36Sopenharmony_ci} 3384