162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is part of the Chelsio T4 Ethernet driver for Linux. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/skbuff.h> 3662306a36Sopenharmony_ci#include <linux/netdevice.h> 3762306a36Sopenharmony_ci#include <linux/etherdevice.h> 3862306a36Sopenharmony_ci#include <linux/if_vlan.h> 3962306a36Sopenharmony_ci#include <linux/ip.h> 4062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 4162306a36Sopenharmony_ci#include <linux/jiffies.h> 4262306a36Sopenharmony_ci#include <linux/prefetch.h> 4362306a36Sopenharmony_ci#include <linux/export.h> 4462306a36Sopenharmony_ci#include <net/xfrm.h> 4562306a36Sopenharmony_ci#include <net/ipv6.h> 4662306a36Sopenharmony_ci#include <net/tcp.h> 4762306a36Sopenharmony_ci#include <net/busy_poll.h> 4862306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 4962306a36Sopenharmony_ci#include <scsi/fc/fc_fcoe.h> 5062306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 5162306a36Sopenharmony_ci#include "cxgb4.h" 5262306a36Sopenharmony_ci#include "t4_regs.h" 5362306a36Sopenharmony_ci#include "t4_values.h" 5462306a36Sopenharmony_ci#include "t4_msg.h" 5562306a36Sopenharmony_ci#include "t4fw_api.h" 5662306a36Sopenharmony_ci#include "cxgb4_ptp.h" 5762306a36Sopenharmony_ci#include "cxgb4_uld.h" 5862306a36Sopenharmony_ci#include "cxgb4_tc_mqprio.h" 5962306a36Sopenharmony_ci#include "sched.h" 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Rx buffer size. We use largish buffers if possible but settle for single 6362306a36Sopenharmony_ci * pages under memory shortage. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci#if PAGE_SHIFT >= 16 6662306a36Sopenharmony_ci# define FL_PG_ORDER 0 6762306a36Sopenharmony_ci#else 6862306a36Sopenharmony_ci# define FL_PG_ORDER (16 - PAGE_SHIFT) 6962306a36Sopenharmony_ci#endif 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* RX_PULL_LEN should be <= RX_COPY_THRES */ 7262306a36Sopenharmony_ci#define RX_COPY_THRES 256 7362306a36Sopenharmony_ci#define RX_PULL_LEN 128 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Main body length for sk_buffs used for Rx Ethernet packets with fragments. 7762306a36Sopenharmony_ci * Should be >= RX_PULL_LEN but possibly bigger to give pskb_may_pull some room. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci#define RX_PKT_SKB_LEN 512 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * Max number of Tx descriptors we clean up at a time. Should be modest as 8362306a36Sopenharmony_ci * freeing skbs isn't cheap and it happens while holding locks. We just need 8462306a36Sopenharmony_ci * to free packets faster than they arrive, we eventually catch up and keep 8562306a36Sopenharmony_ci * the amortized cost reasonable. Must be >= 2 * TXQ_STOP_THRES. It should 8662306a36Sopenharmony_ci * also match the CIDX Flush Threshold. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci#define MAX_TX_RECLAIM 32 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * Max number of Rx buffers we replenish at a time. Again keep this modest, 9262306a36Sopenharmony_ci * allocating buffers isn't cheap either. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci#define MAX_RX_REFILL 16U 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci * Period of the Rx queue check timer. This timer is infrequent as it has 9862306a36Sopenharmony_ci * something to do only when the system experiences severe memory shortage. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci#define RX_QCHECK_PERIOD (HZ / 2) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * Period of the Tx queue check timer. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci#define TX_QCHECK_PERIOD (HZ / 2) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * Max number of Tx descriptors to be reclaimed by the Tx timer. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci#define MAX_TIMER_TX_RECLAIM 100 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * Timer index used when backing off due to memory shortage. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci#define NOMEM_TMR_IDX (SGE_NTIMERS - 1) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * Suspension threshold for non-Ethernet Tx queues. We require enough room 11962306a36Sopenharmony_ci * for a full sized WR. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci#define TXQ_STOP_THRES (SGE_MAX_WR_LEN / sizeof(struct tx_desc)) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * Max Tx descriptor space we allow for an Ethernet packet to be inlined 12562306a36Sopenharmony_ci * into a WR. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci#define MAX_IMM_TX_PKT_LEN 256 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* 13062306a36Sopenharmony_ci * Max size of a WR sent through a control Tx queue. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci#define MAX_CTRL_WR_LEN SGE_MAX_WR_LEN 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistruct rx_sw_desc { /* SW state per Rx descriptor */ 13562306a36Sopenharmony_ci struct page *page; 13662306a36Sopenharmony_ci dma_addr_t dma_addr; 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * Rx buffer sizes for "useskbs" Free List buffers (one ingress packet pe skb 14162306a36Sopenharmony_ci * buffer). We currently only support two sizes for 1500- and 9000-byte MTUs. 14262306a36Sopenharmony_ci * We could easily support more but there doesn't seem to be much need for 14362306a36Sopenharmony_ci * that ... 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci#define FL_MTU_SMALL 1500 14662306a36Sopenharmony_ci#define FL_MTU_LARGE 9000 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic inline unsigned int fl_mtu_bufsize(struct adapter *adapter, 14962306a36Sopenharmony_ci unsigned int mtu) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct sge *s = &adapter->sge; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return ALIGN(s->pktshift + ETH_HLEN + VLAN_HLEN + mtu, s->fl_align); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#define FL_MTU_SMALL_BUFSIZE(adapter) fl_mtu_bufsize(adapter, FL_MTU_SMALL) 15762306a36Sopenharmony_ci#define FL_MTU_LARGE_BUFSIZE(adapter) fl_mtu_bufsize(adapter, FL_MTU_LARGE) 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * Bits 0..3 of rx_sw_desc.dma_addr have special meaning. The hardware uses 16162306a36Sopenharmony_ci * these to specify the buffer size as an index into the SGE Free List Buffer 16262306a36Sopenharmony_ci * Size register array. We also use bit 4, when the buffer has been unmapped 16362306a36Sopenharmony_ci * for DMA, but this is of course never sent to the hardware and is only used 16462306a36Sopenharmony_ci * to prevent double unmappings. All of the above requires that the Free List 16562306a36Sopenharmony_ci * Buffers which we allocate have the bottom 5 bits free (0) -- i.e. are 16662306a36Sopenharmony_ci * 32-byte or or a power of 2 greater in alignment. Since the SGE's minimal 16762306a36Sopenharmony_ci * Free List Buffer alignment is 32 bytes, this works out for us ... 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_cienum { 17062306a36Sopenharmony_ci RX_BUF_FLAGS = 0x1f, /* bottom five bits are special */ 17162306a36Sopenharmony_ci RX_BUF_SIZE = 0x0f, /* bottom three bits are for buf sizes */ 17262306a36Sopenharmony_ci RX_UNMAPPED_BUF = 0x10, /* buffer is not mapped */ 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* 17562306a36Sopenharmony_ci * XXX We shouldn't depend on being able to use these indices. 17662306a36Sopenharmony_ci * XXX Especially when some other Master PF has initialized the 17762306a36Sopenharmony_ci * XXX adapter or we use the Firmware Configuration File. We 17862306a36Sopenharmony_ci * XXX should really search through the Host Buffer Size register 17962306a36Sopenharmony_ci * XXX array for the appropriately sized buffer indices. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci RX_SMALL_PG_BUF = 0x0, /* small (PAGE_SIZE) page buffer */ 18262306a36Sopenharmony_ci RX_LARGE_PG_BUF = 0x1, /* buffer large (FL_PG_ORDER) page buffer */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci RX_SMALL_MTU_BUF = 0x2, /* small MTU buffer */ 18562306a36Sopenharmony_ci RX_LARGE_MTU_BUF = 0x3, /* large MTU buffer */ 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int timer_pkt_quota[] = {1, 1, 2, 3, 4, 5}; 18962306a36Sopenharmony_ci#define MIN_NAPI_WORK 1 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic inline dma_addr_t get_buf_addr(const struct rx_sw_desc *d) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci return d->dma_addr & ~(dma_addr_t)RX_BUF_FLAGS; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic inline bool is_buf_mapped(const struct rx_sw_desc *d) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci return !(d->dma_addr & RX_UNMAPPED_BUF); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/** 20262306a36Sopenharmony_ci * txq_avail - return the number of available slots in a Tx queue 20362306a36Sopenharmony_ci * @q: the Tx queue 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * Returns the number of descriptors in a Tx queue available to write new 20662306a36Sopenharmony_ci * packets. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic inline unsigned int txq_avail(const struct sge_txq *q) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci return q->size - 1 - q->in_use; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/** 21462306a36Sopenharmony_ci * fl_cap - return the capacity of a free-buffer list 21562306a36Sopenharmony_ci * @fl: the FL 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * Returns the capacity of a free-buffer list. The capacity is less than 21862306a36Sopenharmony_ci * the size because one descriptor needs to be left unpopulated, otherwise 21962306a36Sopenharmony_ci * HW will think the FL is empty. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic inline unsigned int fl_cap(const struct sge_fl *fl) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci return fl->size - 8; /* 1 descriptor = 8 buffers */ 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/** 22762306a36Sopenharmony_ci * fl_starving - return whether a Free List is starving. 22862306a36Sopenharmony_ci * @adapter: pointer to the adapter 22962306a36Sopenharmony_ci * @fl: the Free List 23062306a36Sopenharmony_ci * 23162306a36Sopenharmony_ci * Tests specified Free List to see whether the number of buffers 23262306a36Sopenharmony_ci * available to the hardware has falled below our "starvation" 23362306a36Sopenharmony_ci * threshold. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_cistatic inline bool fl_starving(const struct adapter *adapter, 23662306a36Sopenharmony_ci const struct sge_fl *fl) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci const struct sge *s = &adapter->sge; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return fl->avail - fl->pend_cred <= s->fl_starve_thres; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciint cxgb4_map_skb(struct device *dev, const struct sk_buff *skb, 24462306a36Sopenharmony_ci dma_addr_t *addr) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci const skb_frag_t *fp, *end; 24762306a36Sopenharmony_ci const struct skb_shared_info *si; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci *addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); 25062306a36Sopenharmony_ci if (dma_mapping_error(dev, *addr)) 25162306a36Sopenharmony_ci goto out_err; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci si = skb_shinfo(skb); 25462306a36Sopenharmony_ci end = &si->frags[si->nr_frags]; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci for (fp = si->frags; fp < end; fp++) { 25762306a36Sopenharmony_ci *++addr = skb_frag_dma_map(dev, fp, 0, skb_frag_size(fp), 25862306a36Sopenharmony_ci DMA_TO_DEVICE); 25962306a36Sopenharmony_ci if (dma_mapping_error(dev, *addr)) 26062306a36Sopenharmony_ci goto unwind; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ciunwind: 26562306a36Sopenharmony_ci while (fp-- > si->frags) 26662306a36Sopenharmony_ci dma_unmap_page(dev, *--addr, skb_frag_size(fp), DMA_TO_DEVICE); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE); 26962306a36Sopenharmony_ciout_err: 27062306a36Sopenharmony_ci return -ENOMEM; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_map_skb); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void unmap_skb(struct device *dev, const struct sk_buff *skb, 27562306a36Sopenharmony_ci const dma_addr_t *addr) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci const skb_frag_t *fp, *end; 27862306a36Sopenharmony_ci const struct skb_shared_info *si; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci dma_unmap_single(dev, *addr++, skb_headlen(skb), DMA_TO_DEVICE); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci si = skb_shinfo(skb); 28362306a36Sopenharmony_ci end = &si->frags[si->nr_frags]; 28462306a36Sopenharmony_ci for (fp = si->frags; fp < end; fp++) 28562306a36Sopenharmony_ci dma_unmap_page(dev, *addr++, skb_frag_size(fp), DMA_TO_DEVICE); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci#ifdef CONFIG_NEED_DMA_MAP_STATE 28962306a36Sopenharmony_ci/** 29062306a36Sopenharmony_ci * deferred_unmap_destructor - unmap a packet when it is freed 29162306a36Sopenharmony_ci * @skb: the packet 29262306a36Sopenharmony_ci * 29362306a36Sopenharmony_ci * This is the packet destructor used for Tx packets that need to remain 29462306a36Sopenharmony_ci * mapped until they are freed rather than until their Tx descriptors are 29562306a36Sopenharmony_ci * freed. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistatic void deferred_unmap_destructor(struct sk_buff *skb) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci unmap_skb(skb->dev->dev.parent, skb, (dma_addr_t *)skb->head); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci#endif 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/** 30462306a36Sopenharmony_ci * free_tx_desc - reclaims Tx descriptors and their buffers 30562306a36Sopenharmony_ci * @adap: the adapter 30662306a36Sopenharmony_ci * @q: the Tx queue to reclaim descriptors from 30762306a36Sopenharmony_ci * @n: the number of descriptors to reclaim 30862306a36Sopenharmony_ci * @unmap: whether the buffers should be unmapped for DMA 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * Reclaims Tx descriptors from an SGE Tx queue and frees the associated 31162306a36Sopenharmony_ci * Tx buffers. Called with the Tx queue lock held. 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_civoid free_tx_desc(struct adapter *adap, struct sge_txq *q, 31462306a36Sopenharmony_ci unsigned int n, bool unmap) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci unsigned int cidx = q->cidx; 31762306a36Sopenharmony_ci struct tx_sw_desc *d; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci d = &q->sdesc[cidx]; 32062306a36Sopenharmony_ci while (n--) { 32162306a36Sopenharmony_ci if (d->skb) { /* an SGL is present */ 32262306a36Sopenharmony_ci if (unmap && d->addr[0]) { 32362306a36Sopenharmony_ci unmap_skb(adap->pdev_dev, d->skb, d->addr); 32462306a36Sopenharmony_ci memset(d->addr, 0, sizeof(d->addr)); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci dev_consume_skb_any(d->skb); 32762306a36Sopenharmony_ci d->skb = NULL; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci ++d; 33062306a36Sopenharmony_ci if (++cidx == q->size) { 33162306a36Sopenharmony_ci cidx = 0; 33262306a36Sopenharmony_ci d = q->sdesc; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci q->cidx = cidx; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci/* 33962306a36Sopenharmony_ci * Return the number of reclaimable descriptors in a Tx queue. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_cistatic inline int reclaimable(const struct sge_txq *q) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci int hw_cidx = ntohs(READ_ONCE(q->stat->cidx)); 34462306a36Sopenharmony_ci hw_cidx -= q->cidx; 34562306a36Sopenharmony_ci return hw_cidx < 0 ? hw_cidx + q->size : hw_cidx; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/** 34962306a36Sopenharmony_ci * reclaim_completed_tx - reclaims completed TX Descriptors 35062306a36Sopenharmony_ci * @adap: the adapter 35162306a36Sopenharmony_ci * @q: the Tx queue to reclaim completed descriptors from 35262306a36Sopenharmony_ci * @maxreclaim: the maximum number of TX Descriptors to reclaim or -1 35362306a36Sopenharmony_ci * @unmap: whether the buffers should be unmapped for DMA 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * Reclaims Tx Descriptors that the SGE has indicated it has processed, 35662306a36Sopenharmony_ci * and frees the associated buffers if possible. If @max == -1, then 35762306a36Sopenharmony_ci * we'll use a defaiult maximum. Called with the TX Queue locked. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_cistatic inline int reclaim_completed_tx(struct adapter *adap, struct sge_txq *q, 36062306a36Sopenharmony_ci int maxreclaim, bool unmap) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci int reclaim = reclaimable(q); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (reclaim) { 36562306a36Sopenharmony_ci /* 36662306a36Sopenharmony_ci * Limit the amount of clean up work we do at a time to keep 36762306a36Sopenharmony_ci * the Tx lock hold time O(1). 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci if (maxreclaim < 0) 37062306a36Sopenharmony_ci maxreclaim = MAX_TX_RECLAIM; 37162306a36Sopenharmony_ci if (reclaim > maxreclaim) 37262306a36Sopenharmony_ci reclaim = maxreclaim; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci free_tx_desc(adap, q, reclaim, unmap); 37562306a36Sopenharmony_ci q->in_use -= reclaim; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return reclaim; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/** 38262306a36Sopenharmony_ci * cxgb4_reclaim_completed_tx - reclaims completed Tx descriptors 38362306a36Sopenharmony_ci * @adap: the adapter 38462306a36Sopenharmony_ci * @q: the Tx queue to reclaim completed descriptors from 38562306a36Sopenharmony_ci * @unmap: whether the buffers should be unmapped for DMA 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci * Reclaims Tx descriptors that the SGE has indicated it has processed, 38862306a36Sopenharmony_ci * and frees the associated buffers if possible. Called with the Tx 38962306a36Sopenharmony_ci * queue locked. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_civoid cxgb4_reclaim_completed_tx(struct adapter *adap, struct sge_txq *q, 39262306a36Sopenharmony_ci bool unmap) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci (void)reclaim_completed_tx(adap, q, -1, unmap); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_reclaim_completed_tx); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic inline int get_buf_size(struct adapter *adapter, 39962306a36Sopenharmony_ci const struct rx_sw_desc *d) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct sge *s = &adapter->sge; 40262306a36Sopenharmony_ci unsigned int rx_buf_size_idx = d->dma_addr & RX_BUF_SIZE; 40362306a36Sopenharmony_ci int buf_size; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci switch (rx_buf_size_idx) { 40662306a36Sopenharmony_ci case RX_SMALL_PG_BUF: 40762306a36Sopenharmony_ci buf_size = PAGE_SIZE; 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci case RX_LARGE_PG_BUF: 41162306a36Sopenharmony_ci buf_size = PAGE_SIZE << s->fl_pg_order; 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci case RX_SMALL_MTU_BUF: 41562306a36Sopenharmony_ci buf_size = FL_MTU_SMALL_BUFSIZE(adapter); 41662306a36Sopenharmony_ci break; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci case RX_LARGE_MTU_BUF: 41962306a36Sopenharmony_ci buf_size = FL_MTU_LARGE_BUFSIZE(adapter); 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci default: 42362306a36Sopenharmony_ci BUG(); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return buf_size; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/** 43062306a36Sopenharmony_ci * free_rx_bufs - free the Rx buffers on an SGE free list 43162306a36Sopenharmony_ci * @adap: the adapter 43262306a36Sopenharmony_ci * @q: the SGE free list to free buffers from 43362306a36Sopenharmony_ci * @n: how many buffers to free 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * Release the next @n buffers on an SGE free-buffer Rx queue. The 43662306a36Sopenharmony_ci * buffers must be made inaccessible to HW before calling this function. 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_cistatic void free_rx_bufs(struct adapter *adap, struct sge_fl *q, int n) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci while (n--) { 44162306a36Sopenharmony_ci struct rx_sw_desc *d = &q->sdesc[q->cidx]; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (is_buf_mapped(d)) 44462306a36Sopenharmony_ci dma_unmap_page(adap->pdev_dev, get_buf_addr(d), 44562306a36Sopenharmony_ci get_buf_size(adap, d), 44662306a36Sopenharmony_ci DMA_FROM_DEVICE); 44762306a36Sopenharmony_ci put_page(d->page); 44862306a36Sopenharmony_ci d->page = NULL; 44962306a36Sopenharmony_ci if (++q->cidx == q->size) 45062306a36Sopenharmony_ci q->cidx = 0; 45162306a36Sopenharmony_ci q->avail--; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci/** 45662306a36Sopenharmony_ci * unmap_rx_buf - unmap the current Rx buffer on an SGE free list 45762306a36Sopenharmony_ci * @adap: the adapter 45862306a36Sopenharmony_ci * @q: the SGE free list 45962306a36Sopenharmony_ci * 46062306a36Sopenharmony_ci * Unmap the current buffer on an SGE free-buffer Rx queue. The 46162306a36Sopenharmony_ci * buffer must be made inaccessible to HW before calling this function. 46262306a36Sopenharmony_ci * 46362306a36Sopenharmony_ci * This is similar to @free_rx_bufs above but does not free the buffer. 46462306a36Sopenharmony_ci * Do note that the FL still loses any further access to the buffer. 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_cistatic void unmap_rx_buf(struct adapter *adap, struct sge_fl *q) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct rx_sw_desc *d = &q->sdesc[q->cidx]; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (is_buf_mapped(d)) 47162306a36Sopenharmony_ci dma_unmap_page(adap->pdev_dev, get_buf_addr(d), 47262306a36Sopenharmony_ci get_buf_size(adap, d), DMA_FROM_DEVICE); 47362306a36Sopenharmony_ci d->page = NULL; 47462306a36Sopenharmony_ci if (++q->cidx == q->size) 47562306a36Sopenharmony_ci q->cidx = 0; 47662306a36Sopenharmony_ci q->avail--; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci if (q->pend_cred >= 8) { 48262306a36Sopenharmony_ci u32 val = adap->params.arch.sge_fl_db; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 48562306a36Sopenharmony_ci val |= PIDX_V(q->pend_cred / 8); 48662306a36Sopenharmony_ci else 48762306a36Sopenharmony_ci val |= PIDX_T5_V(q->pend_cred / 8); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* Make sure all memory writes to the Free List queue are 49062306a36Sopenharmony_ci * committed before we tell the hardware about them. 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_ci wmb(); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* If we don't have access to the new User Doorbell (T5+), use 49562306a36Sopenharmony_ci * the old doorbell mechanism; otherwise use the new BAR2 49662306a36Sopenharmony_ci * mechanism. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci if (unlikely(q->bar2_addr == NULL)) { 49962306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), 50062306a36Sopenharmony_ci val | QID_V(q->cntxt_id)); 50162306a36Sopenharmony_ci } else { 50262306a36Sopenharmony_ci writel(val | QID_V(q->bar2_qid), 50362306a36Sopenharmony_ci q->bar2_addr + SGE_UDB_KDOORBELL); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* This Write memory Barrier will force the write to 50662306a36Sopenharmony_ci * the User Doorbell area to be flushed. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci wmb(); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci q->pend_cred &= 7; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic inline void set_rx_sw_desc(struct rx_sw_desc *sd, struct page *pg, 51562306a36Sopenharmony_ci dma_addr_t mapping) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci sd->page = pg; 51862306a36Sopenharmony_ci sd->dma_addr = mapping; /* includes size low bits */ 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/** 52262306a36Sopenharmony_ci * refill_fl - refill an SGE Rx buffer ring 52362306a36Sopenharmony_ci * @adap: the adapter 52462306a36Sopenharmony_ci * @q: the ring to refill 52562306a36Sopenharmony_ci * @n: the number of new buffers to allocate 52662306a36Sopenharmony_ci * @gfp: the gfp flags for the allocations 52762306a36Sopenharmony_ci * 52862306a36Sopenharmony_ci * (Re)populate an SGE free-buffer queue with up to @n new packet buffers, 52962306a36Sopenharmony_ci * allocated with the supplied gfp flags. The caller must assure that 53062306a36Sopenharmony_ci * @n does not exceed the queue's capacity. If afterwards the queue is 53162306a36Sopenharmony_ci * found critically low mark it as starving in the bitmap of starving FLs. 53262306a36Sopenharmony_ci * 53362306a36Sopenharmony_ci * Returns the number of buffers allocated. 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_cistatic unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n, 53662306a36Sopenharmony_ci gfp_t gfp) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct sge *s = &adap->sge; 53962306a36Sopenharmony_ci struct page *pg; 54062306a36Sopenharmony_ci dma_addr_t mapping; 54162306a36Sopenharmony_ci unsigned int cred = q->avail; 54262306a36Sopenharmony_ci __be64 *d = &q->desc[q->pidx]; 54362306a36Sopenharmony_ci struct rx_sw_desc *sd = &q->sdesc[q->pidx]; 54462306a36Sopenharmony_ci int node; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 54762306a36Sopenharmony_ci if (test_bit(q->cntxt_id - adap->sge.egr_start, adap->sge.blocked_fl)) 54862306a36Sopenharmony_ci goto out; 54962306a36Sopenharmony_ci#endif 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci gfp |= __GFP_NOWARN; 55262306a36Sopenharmony_ci node = dev_to_node(adap->pdev_dev); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (s->fl_pg_order == 0) 55562306a36Sopenharmony_ci goto alloc_small_pages; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* 55862306a36Sopenharmony_ci * Prefer large buffers 55962306a36Sopenharmony_ci */ 56062306a36Sopenharmony_ci while (n) { 56162306a36Sopenharmony_ci pg = alloc_pages_node(node, gfp | __GFP_COMP, s->fl_pg_order); 56262306a36Sopenharmony_ci if (unlikely(!pg)) { 56362306a36Sopenharmony_ci q->large_alloc_failed++; 56462306a36Sopenharmony_ci break; /* fall back to single pages */ 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci mapping = dma_map_page(adap->pdev_dev, pg, 0, 56862306a36Sopenharmony_ci PAGE_SIZE << s->fl_pg_order, 56962306a36Sopenharmony_ci DMA_FROM_DEVICE); 57062306a36Sopenharmony_ci if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) { 57162306a36Sopenharmony_ci __free_pages(pg, s->fl_pg_order); 57262306a36Sopenharmony_ci q->mapping_err++; 57362306a36Sopenharmony_ci goto out; /* do not try small pages for this error */ 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci mapping |= RX_LARGE_PG_BUF; 57662306a36Sopenharmony_ci *d++ = cpu_to_be64(mapping); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci set_rx_sw_desc(sd, pg, mapping); 57962306a36Sopenharmony_ci sd++; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci q->avail++; 58262306a36Sopenharmony_ci if (++q->pidx == q->size) { 58362306a36Sopenharmony_ci q->pidx = 0; 58462306a36Sopenharmony_ci sd = q->sdesc; 58562306a36Sopenharmony_ci d = q->desc; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci n--; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cialloc_small_pages: 59162306a36Sopenharmony_ci while (n--) { 59262306a36Sopenharmony_ci pg = alloc_pages_node(node, gfp, 0); 59362306a36Sopenharmony_ci if (unlikely(!pg)) { 59462306a36Sopenharmony_ci q->alloc_failed++; 59562306a36Sopenharmony_ci break; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci mapping = dma_map_page(adap->pdev_dev, pg, 0, PAGE_SIZE, 59962306a36Sopenharmony_ci DMA_FROM_DEVICE); 60062306a36Sopenharmony_ci if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) { 60162306a36Sopenharmony_ci put_page(pg); 60262306a36Sopenharmony_ci q->mapping_err++; 60362306a36Sopenharmony_ci goto out; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci *d++ = cpu_to_be64(mapping); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci set_rx_sw_desc(sd, pg, mapping); 60862306a36Sopenharmony_ci sd++; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci q->avail++; 61162306a36Sopenharmony_ci if (++q->pidx == q->size) { 61262306a36Sopenharmony_ci q->pidx = 0; 61362306a36Sopenharmony_ci sd = q->sdesc; 61462306a36Sopenharmony_ci d = q->desc; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ciout: cred = q->avail - cred; 61962306a36Sopenharmony_ci q->pend_cred += cred; 62062306a36Sopenharmony_ci ring_fl_db(adap, q); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (unlikely(fl_starving(adap, q))) { 62362306a36Sopenharmony_ci smp_wmb(); 62462306a36Sopenharmony_ci q->low++; 62562306a36Sopenharmony_ci set_bit(q->cntxt_id - adap->sge.egr_start, 62662306a36Sopenharmony_ci adap->sge.starving_fl); 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return cred; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci refill_fl(adap, fl, min(MAX_RX_REFILL, fl_cap(fl) - fl->avail), 63562306a36Sopenharmony_ci GFP_ATOMIC); 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci/** 63962306a36Sopenharmony_ci * alloc_ring - allocate resources for an SGE descriptor ring 64062306a36Sopenharmony_ci * @dev: the PCI device's core device 64162306a36Sopenharmony_ci * @nelem: the number of descriptors 64262306a36Sopenharmony_ci * @elem_size: the size of each descriptor 64362306a36Sopenharmony_ci * @sw_size: the size of the SW state associated with each ring element 64462306a36Sopenharmony_ci * @phys: the physical address of the allocated ring 64562306a36Sopenharmony_ci * @metadata: address of the array holding the SW state for the ring 64662306a36Sopenharmony_ci * @stat_size: extra space in HW ring for status information 64762306a36Sopenharmony_ci * @node: preferred node for memory allocations 64862306a36Sopenharmony_ci * 64962306a36Sopenharmony_ci * Allocates resources for an SGE descriptor ring, such as Tx queues, 65062306a36Sopenharmony_ci * free buffer lists, or response queues. Each SGE ring requires 65162306a36Sopenharmony_ci * space for its HW descriptors plus, optionally, space for the SW state 65262306a36Sopenharmony_ci * associated with each HW entry (the metadata). The function returns 65362306a36Sopenharmony_ci * three values: the virtual address for the HW ring (the return value 65462306a36Sopenharmony_ci * of the function), the bus address of the HW ring, and the address 65562306a36Sopenharmony_ci * of the SW ring. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_cistatic void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size, 65862306a36Sopenharmony_ci size_t sw_size, dma_addr_t *phys, void *metadata, 65962306a36Sopenharmony_ci size_t stat_size, int node) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci size_t len = nelem * elem_size + stat_size; 66262306a36Sopenharmony_ci void *s = NULL; 66362306a36Sopenharmony_ci void *p = dma_alloc_coherent(dev, len, phys, GFP_KERNEL); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (!p) 66662306a36Sopenharmony_ci return NULL; 66762306a36Sopenharmony_ci if (sw_size) { 66862306a36Sopenharmony_ci s = kcalloc_node(sw_size, nelem, GFP_KERNEL, node); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (!s) { 67162306a36Sopenharmony_ci dma_free_coherent(dev, len, p, *phys); 67262306a36Sopenharmony_ci return NULL; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci if (metadata) 67662306a36Sopenharmony_ci *(void **)metadata = s; 67762306a36Sopenharmony_ci return p; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci/** 68162306a36Sopenharmony_ci * sgl_len - calculates the size of an SGL of the given capacity 68262306a36Sopenharmony_ci * @n: the number of SGL entries 68362306a36Sopenharmony_ci * 68462306a36Sopenharmony_ci * Calculates the number of flits needed for a scatter/gather list that 68562306a36Sopenharmony_ci * can hold the given number of entries. 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_cistatic inline unsigned int sgl_len(unsigned int n) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci /* A Direct Scatter Gather List uses 32-bit lengths and 64-bit PCI DMA 69062306a36Sopenharmony_ci * addresses. The DSGL Work Request starts off with a 32-bit DSGL 69162306a36Sopenharmony_ci * ULPTX header, then Length0, then Address0, then, for 1 <= i <= N, 69262306a36Sopenharmony_ci * repeated sequences of { Length[i], Length[i+1], Address[i], 69362306a36Sopenharmony_ci * Address[i+1] } (this ensures that all addresses are on 64-bit 69462306a36Sopenharmony_ci * boundaries). If N is even, then Length[N+1] should be set to 0 and 69562306a36Sopenharmony_ci * Address[N+1] is omitted. 69662306a36Sopenharmony_ci * 69762306a36Sopenharmony_ci * The following calculation incorporates all of the above. It's 69862306a36Sopenharmony_ci * somewhat hard to follow but, briefly: the "+2" accounts for the 69962306a36Sopenharmony_ci * first two flits which include the DSGL header, Length0 and 70062306a36Sopenharmony_ci * Address0; the "(3*(n-1))/2" covers the main body of list entries (3 70162306a36Sopenharmony_ci * flits for every pair of the remaining N) +1 if (n-1) is odd; and 70262306a36Sopenharmony_ci * finally the "+((n-1)&1)" adds the one remaining flit needed if 70362306a36Sopenharmony_ci * (n-1) is odd ... 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci n--; 70662306a36Sopenharmony_ci return (3 * n) / 2 + (n & 1) + 2; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci/** 71062306a36Sopenharmony_ci * flits_to_desc - returns the num of Tx descriptors for the given flits 71162306a36Sopenharmony_ci * @n: the number of flits 71262306a36Sopenharmony_ci * 71362306a36Sopenharmony_ci * Returns the number of Tx descriptors needed for the supplied number 71462306a36Sopenharmony_ci * of flits. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_cistatic inline unsigned int flits_to_desc(unsigned int n) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci BUG_ON(n > SGE_MAX_WR_LEN / 8); 71962306a36Sopenharmony_ci return DIV_ROUND_UP(n, 8); 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci/** 72362306a36Sopenharmony_ci * is_eth_imm - can an Ethernet packet be sent as immediate data? 72462306a36Sopenharmony_ci * @skb: the packet 72562306a36Sopenharmony_ci * @chip_ver: chip version 72662306a36Sopenharmony_ci * 72762306a36Sopenharmony_ci * Returns whether an Ethernet packet is small enough to fit as 72862306a36Sopenharmony_ci * immediate data. Return value corresponds to headroom required. 72962306a36Sopenharmony_ci */ 73062306a36Sopenharmony_cistatic inline int is_eth_imm(const struct sk_buff *skb, unsigned int chip_ver) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci int hdrlen = 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (skb->encapsulation && skb_shinfo(skb)->gso_size && 73562306a36Sopenharmony_ci chip_ver > CHELSIO_T5) { 73662306a36Sopenharmony_ci hdrlen = sizeof(struct cpl_tx_tnl_lso); 73762306a36Sopenharmony_ci hdrlen += sizeof(struct cpl_tx_pkt_core); 73862306a36Sopenharmony_ci } else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci } else { 74162306a36Sopenharmony_ci hdrlen = skb_shinfo(skb)->gso_size ? 74262306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt_lso_core) : 0; 74362306a36Sopenharmony_ci hdrlen += sizeof(struct cpl_tx_pkt); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci if (skb->len <= MAX_IMM_TX_PKT_LEN - hdrlen) 74662306a36Sopenharmony_ci return hdrlen; 74762306a36Sopenharmony_ci return 0; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci/** 75162306a36Sopenharmony_ci * calc_tx_flits - calculate the number of flits for a packet Tx WR 75262306a36Sopenharmony_ci * @skb: the packet 75362306a36Sopenharmony_ci * @chip_ver: chip version 75462306a36Sopenharmony_ci * 75562306a36Sopenharmony_ci * Returns the number of flits needed for a Tx WR for the given Ethernet 75662306a36Sopenharmony_ci * packet, including the needed WR and CPL headers. 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_cistatic inline unsigned int calc_tx_flits(const struct sk_buff *skb, 75962306a36Sopenharmony_ci unsigned int chip_ver) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci unsigned int flits; 76262306a36Sopenharmony_ci int hdrlen = is_eth_imm(skb, chip_ver); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* If the skb is small enough, we can pump it out as a work request 76562306a36Sopenharmony_ci * with only immediate data. In that case we just have to have the 76662306a36Sopenharmony_ci * TX Packet header plus the skb data in the Work Request. 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (hdrlen) 77062306a36Sopenharmony_ci return DIV_ROUND_UP(skb->len + hdrlen, sizeof(__be64)); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Otherwise, we're going to have to construct a Scatter gather list 77362306a36Sopenharmony_ci * of the skb body and fragments. We also include the flits necessary 77462306a36Sopenharmony_ci * for the TX Packet Work Request and CPL. We always have a firmware 77562306a36Sopenharmony_ci * Write Header (incorporated as part of the cpl_tx_pkt_lso and 77662306a36Sopenharmony_ci * cpl_tx_pkt structures), followed by either a TX Packet Write CPL 77762306a36Sopenharmony_ci * message or, if we're doing a Large Send Offload, an LSO CPL message 77862306a36Sopenharmony_ci * with an embedded TX Packet Write CPL message. 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_ci flits = sgl_len(skb_shinfo(skb)->nr_frags + 1); 78162306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size) { 78262306a36Sopenharmony_ci if (skb->encapsulation && chip_ver > CHELSIO_T5) { 78362306a36Sopenharmony_ci hdrlen = sizeof(struct fw_eth_tx_pkt_wr) + 78462306a36Sopenharmony_ci sizeof(struct cpl_tx_tnl_lso); 78562306a36Sopenharmony_ci } else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { 78662306a36Sopenharmony_ci u32 pkt_hdrlen; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci pkt_hdrlen = eth_get_headlen(skb->dev, skb->data, 78962306a36Sopenharmony_ci skb_headlen(skb)); 79062306a36Sopenharmony_ci hdrlen = sizeof(struct fw_eth_tx_eo_wr) + 79162306a36Sopenharmony_ci round_up(pkt_hdrlen, 16); 79262306a36Sopenharmony_ci } else { 79362306a36Sopenharmony_ci hdrlen = sizeof(struct fw_eth_tx_pkt_wr) + 79462306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt_lso_core); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci hdrlen += sizeof(struct cpl_tx_pkt_core); 79862306a36Sopenharmony_ci flits += (hdrlen / sizeof(__be64)); 79962306a36Sopenharmony_ci } else { 80062306a36Sopenharmony_ci flits += (sizeof(struct fw_eth_tx_pkt_wr) + 80162306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci return flits; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/** 80762306a36Sopenharmony_ci * calc_tx_descs - calculate the number of Tx descriptors for a packet 80862306a36Sopenharmony_ci * @skb: the packet 80962306a36Sopenharmony_ci * @chip_ver: chip version 81062306a36Sopenharmony_ci * 81162306a36Sopenharmony_ci * Returns the number of Tx descriptors needed for the given Ethernet 81262306a36Sopenharmony_ci * packet, including the needed WR and CPL headers. 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_cistatic inline unsigned int calc_tx_descs(const struct sk_buff *skb, 81562306a36Sopenharmony_ci unsigned int chip_ver) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci return flits_to_desc(calc_tx_flits(skb, chip_ver)); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci/** 82162306a36Sopenharmony_ci * cxgb4_write_sgl - populate a scatter/gather list for a packet 82262306a36Sopenharmony_ci * @skb: the packet 82362306a36Sopenharmony_ci * @q: the Tx queue we are writing into 82462306a36Sopenharmony_ci * @sgl: starting location for writing the SGL 82562306a36Sopenharmony_ci * @end: points right after the end of the SGL 82662306a36Sopenharmony_ci * @start: start offset into skb main-body data to include in the SGL 82762306a36Sopenharmony_ci * @addr: the list of bus addresses for the SGL elements 82862306a36Sopenharmony_ci * 82962306a36Sopenharmony_ci * Generates a gather list for the buffers that make up a packet. 83062306a36Sopenharmony_ci * The caller must provide adequate space for the SGL that will be written. 83162306a36Sopenharmony_ci * The SGL includes all of the packet's page fragments and the data in its 83262306a36Sopenharmony_ci * main body except for the first @start bytes. @sgl must be 16-byte 83362306a36Sopenharmony_ci * aligned and within a Tx descriptor with available space. @end points 83462306a36Sopenharmony_ci * right after the end of the SGL but does not account for any potential 83562306a36Sopenharmony_ci * wrap around, i.e., @end > @sgl. 83662306a36Sopenharmony_ci */ 83762306a36Sopenharmony_civoid cxgb4_write_sgl(const struct sk_buff *skb, struct sge_txq *q, 83862306a36Sopenharmony_ci struct ulptx_sgl *sgl, u64 *end, unsigned int start, 83962306a36Sopenharmony_ci const dma_addr_t *addr) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci unsigned int i, len; 84262306a36Sopenharmony_ci struct ulptx_sge_pair *to; 84362306a36Sopenharmony_ci const struct skb_shared_info *si = skb_shinfo(skb); 84462306a36Sopenharmony_ci unsigned int nfrags = si->nr_frags; 84562306a36Sopenharmony_ci struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1]; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci len = skb_headlen(skb) - start; 84862306a36Sopenharmony_ci if (likely(len)) { 84962306a36Sopenharmony_ci sgl->len0 = htonl(len); 85062306a36Sopenharmony_ci sgl->addr0 = cpu_to_be64(addr[0] + start); 85162306a36Sopenharmony_ci nfrags++; 85262306a36Sopenharmony_ci } else { 85362306a36Sopenharmony_ci sgl->len0 = htonl(skb_frag_size(&si->frags[0])); 85462306a36Sopenharmony_ci sgl->addr0 = cpu_to_be64(addr[1]); 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | 85862306a36Sopenharmony_ci ULPTX_NSGE_V(nfrags)); 85962306a36Sopenharmony_ci if (likely(--nfrags == 0)) 86062306a36Sopenharmony_ci return; 86162306a36Sopenharmony_ci /* 86262306a36Sopenharmony_ci * Most of the complexity below deals with the possibility we hit the 86362306a36Sopenharmony_ci * end of the queue in the middle of writing the SGL. For this case 86462306a36Sopenharmony_ci * only we create the SGL in a temporary buffer and then copy it. 86562306a36Sopenharmony_ci */ 86662306a36Sopenharmony_ci to = (u8 *)end > (u8 *)q->stat ? buf : sgl->sge; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) { 86962306a36Sopenharmony_ci to->len[0] = cpu_to_be32(skb_frag_size(&si->frags[i])); 87062306a36Sopenharmony_ci to->len[1] = cpu_to_be32(skb_frag_size(&si->frags[++i])); 87162306a36Sopenharmony_ci to->addr[0] = cpu_to_be64(addr[i]); 87262306a36Sopenharmony_ci to->addr[1] = cpu_to_be64(addr[++i]); 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci if (nfrags) { 87562306a36Sopenharmony_ci to->len[0] = cpu_to_be32(skb_frag_size(&si->frags[i])); 87662306a36Sopenharmony_ci to->len[1] = cpu_to_be32(0); 87762306a36Sopenharmony_ci to->addr[0] = cpu_to_be64(addr[i + 1]); 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci if (unlikely((u8 *)end > (u8 *)q->stat)) { 88062306a36Sopenharmony_ci unsigned int part0 = (u8 *)q->stat - (u8 *)sgl->sge, part1; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (likely(part0)) 88362306a36Sopenharmony_ci memcpy(sgl->sge, buf, part0); 88462306a36Sopenharmony_ci part1 = (u8 *)end - (u8 *)q->stat; 88562306a36Sopenharmony_ci memcpy(q->desc, (u8 *)buf + part0, part1); 88662306a36Sopenharmony_ci end = (void *)q->desc + part1; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */ 88962306a36Sopenharmony_ci *end = 0; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_write_sgl); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci/* cxgb4_write_partial_sgl - populate SGL for partial packet 89462306a36Sopenharmony_ci * @skb: the packet 89562306a36Sopenharmony_ci * @q: the Tx queue we are writing into 89662306a36Sopenharmony_ci * @sgl: starting location for writing the SGL 89762306a36Sopenharmony_ci * @end: points right after the end of the SGL 89862306a36Sopenharmony_ci * @addr: the list of bus addresses for the SGL elements 89962306a36Sopenharmony_ci * @start: start offset in the SKB where partial data starts 90062306a36Sopenharmony_ci * @len: length of data from @start to send out 90162306a36Sopenharmony_ci * 90262306a36Sopenharmony_ci * This API will handle sending out partial data of a skb if required. 90362306a36Sopenharmony_ci * Unlike cxgb4_write_sgl, @start can be any offset into the skb data, 90462306a36Sopenharmony_ci * and @len will decide how much data after @start offset to send out. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_civoid cxgb4_write_partial_sgl(const struct sk_buff *skb, struct sge_txq *q, 90762306a36Sopenharmony_ci struct ulptx_sgl *sgl, u64 *end, 90862306a36Sopenharmony_ci const dma_addr_t *addr, u32 start, u32 len) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1] = {0}, *to; 91162306a36Sopenharmony_ci u32 frag_size, skb_linear_data_len = skb_headlen(skb); 91262306a36Sopenharmony_ci struct skb_shared_info *si = skb_shinfo(skb); 91362306a36Sopenharmony_ci u8 i = 0, frag_idx = 0, nfrags = 0; 91462306a36Sopenharmony_ci skb_frag_t *frag; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* Fill the first SGL either from linear data or from partial 91762306a36Sopenharmony_ci * frag based on @start. 91862306a36Sopenharmony_ci */ 91962306a36Sopenharmony_ci if (unlikely(start < skb_linear_data_len)) { 92062306a36Sopenharmony_ci frag_size = min(len, skb_linear_data_len - start); 92162306a36Sopenharmony_ci sgl->len0 = htonl(frag_size); 92262306a36Sopenharmony_ci sgl->addr0 = cpu_to_be64(addr[0] + start); 92362306a36Sopenharmony_ci len -= frag_size; 92462306a36Sopenharmony_ci nfrags++; 92562306a36Sopenharmony_ci } else { 92662306a36Sopenharmony_ci start -= skb_linear_data_len; 92762306a36Sopenharmony_ci frag = &si->frags[frag_idx]; 92862306a36Sopenharmony_ci frag_size = skb_frag_size(frag); 92962306a36Sopenharmony_ci /* find the first frag */ 93062306a36Sopenharmony_ci while (start >= frag_size) { 93162306a36Sopenharmony_ci start -= frag_size; 93262306a36Sopenharmony_ci frag_idx++; 93362306a36Sopenharmony_ci frag = &si->frags[frag_idx]; 93462306a36Sopenharmony_ci frag_size = skb_frag_size(frag); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci frag_size = min(len, skb_frag_size(frag) - start); 93862306a36Sopenharmony_ci sgl->len0 = cpu_to_be32(frag_size); 93962306a36Sopenharmony_ci sgl->addr0 = cpu_to_be64(addr[frag_idx + 1] + start); 94062306a36Sopenharmony_ci len -= frag_size; 94162306a36Sopenharmony_ci nfrags++; 94262306a36Sopenharmony_ci frag_idx++; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* If the entire partial data fit in one SGL, then send it out 94662306a36Sopenharmony_ci * now. 94762306a36Sopenharmony_ci */ 94862306a36Sopenharmony_ci if (!len) 94962306a36Sopenharmony_ci goto done; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* Most of the complexity below deals with the possibility we hit the 95262306a36Sopenharmony_ci * end of the queue in the middle of writing the SGL. For this case 95362306a36Sopenharmony_ci * only we create the SGL in a temporary buffer and then copy it. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_ci to = (u8 *)end > (u8 *)q->stat ? buf : sgl->sge; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci /* If the skb couldn't fit in first SGL completely, fill the 95862306a36Sopenharmony_ci * rest of the frags in subsequent SGLs. Note that each SGL 95962306a36Sopenharmony_ci * pair can store 2 frags. 96062306a36Sopenharmony_ci */ 96162306a36Sopenharmony_ci while (len) { 96262306a36Sopenharmony_ci frag_size = min(len, skb_frag_size(&si->frags[frag_idx])); 96362306a36Sopenharmony_ci to->len[i & 1] = cpu_to_be32(frag_size); 96462306a36Sopenharmony_ci to->addr[i & 1] = cpu_to_be64(addr[frag_idx + 1]); 96562306a36Sopenharmony_ci if (i && (i & 1)) 96662306a36Sopenharmony_ci to++; 96762306a36Sopenharmony_ci nfrags++; 96862306a36Sopenharmony_ci frag_idx++; 96962306a36Sopenharmony_ci i++; 97062306a36Sopenharmony_ci len -= frag_size; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* If we ended in an odd boundary, then set the second SGL's 97462306a36Sopenharmony_ci * length in the pair to 0. 97562306a36Sopenharmony_ci */ 97662306a36Sopenharmony_ci if (i & 1) 97762306a36Sopenharmony_ci to->len[1] = cpu_to_be32(0); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* Copy from temporary buffer to Tx ring, in case we hit the 98062306a36Sopenharmony_ci * end of the queue in the middle of writing the SGL. 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci if (unlikely((u8 *)end > (u8 *)q->stat)) { 98362306a36Sopenharmony_ci u32 part0 = (u8 *)q->stat - (u8 *)sgl->sge, part1; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (likely(part0)) 98662306a36Sopenharmony_ci memcpy(sgl->sge, buf, part0); 98762306a36Sopenharmony_ci part1 = (u8 *)end - (u8 *)q->stat; 98862306a36Sopenharmony_ci memcpy(q->desc, (u8 *)buf + part0, part1); 98962306a36Sopenharmony_ci end = (void *)q->desc + part1; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* 0-pad to multiple of 16 */ 99362306a36Sopenharmony_ci if ((uintptr_t)end & 8) 99462306a36Sopenharmony_ci *end = 0; 99562306a36Sopenharmony_cidone: 99662306a36Sopenharmony_ci sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | 99762306a36Sopenharmony_ci ULPTX_NSGE_V(nfrags)); 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_write_partial_sgl); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci/* This function copies 64 byte coalesced work request to 100262306a36Sopenharmony_ci * memory mapped BAR2 space. For coalesced WR SGE fetches 100362306a36Sopenharmony_ci * data from the FIFO instead of from Host. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_cistatic void cxgb_pio_copy(u64 __iomem *dst, u64 *src) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci int count = 8; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci while (count) { 101062306a36Sopenharmony_ci writeq(*src, dst); 101162306a36Sopenharmony_ci src++; 101262306a36Sopenharmony_ci dst++; 101362306a36Sopenharmony_ci count--; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci/** 101862306a36Sopenharmony_ci * cxgb4_ring_tx_db - check and potentially ring a Tx queue's doorbell 101962306a36Sopenharmony_ci * @adap: the adapter 102062306a36Sopenharmony_ci * @q: the Tx queue 102162306a36Sopenharmony_ci * @n: number of new descriptors to give to HW 102262306a36Sopenharmony_ci * 102362306a36Sopenharmony_ci * Ring the doorbel for a Tx queue. 102462306a36Sopenharmony_ci */ 102562306a36Sopenharmony_ciinline void cxgb4_ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci /* Make sure that all writes to the TX Descriptors are committed 102862306a36Sopenharmony_ci * before we tell the hardware about them. 102962306a36Sopenharmony_ci */ 103062306a36Sopenharmony_ci wmb(); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* If we don't have access to the new User Doorbell (T5+), use the old 103362306a36Sopenharmony_ci * doorbell mechanism; otherwise use the new BAR2 mechanism. 103462306a36Sopenharmony_ci */ 103562306a36Sopenharmony_ci if (unlikely(q->bar2_addr == NULL)) { 103662306a36Sopenharmony_ci u32 val = PIDX_V(n); 103762306a36Sopenharmony_ci unsigned long flags; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* For T4 we need to participate in the Doorbell Recovery 104062306a36Sopenharmony_ci * mechanism. 104162306a36Sopenharmony_ci */ 104262306a36Sopenharmony_ci spin_lock_irqsave(&q->db_lock, flags); 104362306a36Sopenharmony_ci if (!q->db_disabled) 104462306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), 104562306a36Sopenharmony_ci QID_V(q->cntxt_id) | val); 104662306a36Sopenharmony_ci else 104762306a36Sopenharmony_ci q->db_pidx_inc += n; 104862306a36Sopenharmony_ci q->db_pidx = q->pidx; 104962306a36Sopenharmony_ci spin_unlock_irqrestore(&q->db_lock, flags); 105062306a36Sopenharmony_ci } else { 105162306a36Sopenharmony_ci u32 val = PIDX_T5_V(n); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* T4 and later chips share the same PIDX field offset within 105462306a36Sopenharmony_ci * the doorbell, but T5 and later shrank the field in order to 105562306a36Sopenharmony_ci * gain a bit for Doorbell Priority. The field was absurdly 105662306a36Sopenharmony_ci * large in the first place (14 bits) so we just use the T5 105762306a36Sopenharmony_ci * and later limits and warn if a Queue ID is too large. 105862306a36Sopenharmony_ci */ 105962306a36Sopenharmony_ci WARN_ON(val & DBPRIO_F); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* If we're only writing a single TX Descriptor and we can use 106262306a36Sopenharmony_ci * Inferred QID registers, we can use the Write Combining 106362306a36Sopenharmony_ci * Gather Buffer; otherwise we use the simple doorbell. 106462306a36Sopenharmony_ci */ 106562306a36Sopenharmony_ci if (n == 1 && q->bar2_qid == 0) { 106662306a36Sopenharmony_ci int index = (q->pidx 106762306a36Sopenharmony_ci ? (q->pidx - 1) 106862306a36Sopenharmony_ci : (q->size - 1)); 106962306a36Sopenharmony_ci u64 *wr = (u64 *)&q->desc[index]; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci cxgb_pio_copy((u64 __iomem *) 107262306a36Sopenharmony_ci (q->bar2_addr + SGE_UDB_WCDOORBELL), 107362306a36Sopenharmony_ci wr); 107462306a36Sopenharmony_ci } else { 107562306a36Sopenharmony_ci writel(val | QID_V(q->bar2_qid), 107662306a36Sopenharmony_ci q->bar2_addr + SGE_UDB_KDOORBELL); 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* This Write Memory Barrier will force the write to the User 108062306a36Sopenharmony_ci * Doorbell area to be flushed. This is needed to prevent 108162306a36Sopenharmony_ci * writes on different CPUs for the same queue from hitting 108262306a36Sopenharmony_ci * the adapter out of order. This is required when some Work 108362306a36Sopenharmony_ci * Requests take the Write Combine Gather Buffer path (user 108462306a36Sopenharmony_ci * doorbell area offset [SGE_UDB_WCDOORBELL..+63]) and some 108562306a36Sopenharmony_ci * take the traditional path where we simply increment the 108662306a36Sopenharmony_ci * PIDX (User Doorbell area SGE_UDB_KDOORBELL) and have the 108762306a36Sopenharmony_ci * hardware DMA read the actual Work Request. 108862306a36Sopenharmony_ci */ 108962306a36Sopenharmony_ci wmb(); 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_ring_tx_db); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci/** 109562306a36Sopenharmony_ci * cxgb4_inline_tx_skb - inline a packet's data into Tx descriptors 109662306a36Sopenharmony_ci * @skb: the packet 109762306a36Sopenharmony_ci * @q: the Tx queue where the packet will be inlined 109862306a36Sopenharmony_ci * @pos: starting position in the Tx queue where to inline the packet 109962306a36Sopenharmony_ci * 110062306a36Sopenharmony_ci * Inline a packet's contents directly into Tx descriptors, starting at 110162306a36Sopenharmony_ci * the given position within the Tx DMA ring. 110262306a36Sopenharmony_ci * Most of the complexity of this operation is dealing with wrap arounds 110362306a36Sopenharmony_ci * in the middle of the packet we want to inline. 110462306a36Sopenharmony_ci */ 110562306a36Sopenharmony_civoid cxgb4_inline_tx_skb(const struct sk_buff *skb, 110662306a36Sopenharmony_ci const struct sge_txq *q, void *pos) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci int left = (void *)q->stat - pos; 110962306a36Sopenharmony_ci u64 *p; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (likely(skb->len <= left)) { 111262306a36Sopenharmony_ci if (likely(!skb->data_len)) 111362306a36Sopenharmony_ci skb_copy_from_linear_data(skb, pos, skb->len); 111462306a36Sopenharmony_ci else 111562306a36Sopenharmony_ci skb_copy_bits(skb, 0, pos, skb->len); 111662306a36Sopenharmony_ci pos += skb->len; 111762306a36Sopenharmony_ci } else { 111862306a36Sopenharmony_ci skb_copy_bits(skb, 0, pos, left); 111962306a36Sopenharmony_ci skb_copy_bits(skb, left, q->desc, skb->len - left); 112062306a36Sopenharmony_ci pos = (void *)q->desc + (skb->len - left); 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* 0-pad to multiple of 16 */ 112462306a36Sopenharmony_ci p = PTR_ALIGN(pos, 8); 112562306a36Sopenharmony_ci if ((uintptr_t)p & 8) 112662306a36Sopenharmony_ci *p = 0; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_inline_tx_skb); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic void *inline_tx_skb_header(const struct sk_buff *skb, 113162306a36Sopenharmony_ci const struct sge_txq *q, void *pos, 113262306a36Sopenharmony_ci int length) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci u64 *p; 113562306a36Sopenharmony_ci int left = (void *)q->stat - pos; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (likely(length <= left)) { 113862306a36Sopenharmony_ci memcpy(pos, skb->data, length); 113962306a36Sopenharmony_ci pos += length; 114062306a36Sopenharmony_ci } else { 114162306a36Sopenharmony_ci memcpy(pos, skb->data, left); 114262306a36Sopenharmony_ci memcpy(q->desc, skb->data + left, length - left); 114362306a36Sopenharmony_ci pos = (void *)q->desc + (length - left); 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci /* 0-pad to multiple of 16 */ 114662306a36Sopenharmony_ci p = PTR_ALIGN(pos, 8); 114762306a36Sopenharmony_ci if ((uintptr_t)p & 8) { 114862306a36Sopenharmony_ci *p = 0; 114962306a36Sopenharmony_ci return p + 1; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci return p; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci/* 115562306a36Sopenharmony_ci * Figure out what HW csum a packet wants and return the appropriate control 115662306a36Sopenharmony_ci * bits. 115762306a36Sopenharmony_ci */ 115862306a36Sopenharmony_cistatic u64 hwcsum(enum chip_type chip, const struct sk_buff *skb) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci int csum_type; 116162306a36Sopenharmony_ci bool inner_hdr_csum = false; 116262306a36Sopenharmony_ci u16 proto, ver; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (skb->encapsulation && 116562306a36Sopenharmony_ci (CHELSIO_CHIP_VERSION(chip) > CHELSIO_T5)) 116662306a36Sopenharmony_ci inner_hdr_csum = true; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (inner_hdr_csum) { 116962306a36Sopenharmony_ci ver = inner_ip_hdr(skb)->version; 117062306a36Sopenharmony_ci proto = (ver == 4) ? inner_ip_hdr(skb)->protocol : 117162306a36Sopenharmony_ci inner_ipv6_hdr(skb)->nexthdr; 117262306a36Sopenharmony_ci } else { 117362306a36Sopenharmony_ci ver = ip_hdr(skb)->version; 117462306a36Sopenharmony_ci proto = (ver == 4) ? ip_hdr(skb)->protocol : 117562306a36Sopenharmony_ci ipv6_hdr(skb)->nexthdr; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (ver == 4) { 117962306a36Sopenharmony_ci if (proto == IPPROTO_TCP) 118062306a36Sopenharmony_ci csum_type = TX_CSUM_TCPIP; 118162306a36Sopenharmony_ci else if (proto == IPPROTO_UDP) 118262306a36Sopenharmony_ci csum_type = TX_CSUM_UDPIP; 118362306a36Sopenharmony_ci else { 118462306a36Sopenharmony_cinocsum: /* 118562306a36Sopenharmony_ci * unknown protocol, disable HW csum 118662306a36Sopenharmony_ci * and hope a bad packet is detected 118762306a36Sopenharmony_ci */ 118862306a36Sopenharmony_ci return TXPKT_L4CSUM_DIS_F; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci } else { 119162306a36Sopenharmony_ci /* 119262306a36Sopenharmony_ci * this doesn't work with extension headers 119362306a36Sopenharmony_ci */ 119462306a36Sopenharmony_ci if (proto == IPPROTO_TCP) 119562306a36Sopenharmony_ci csum_type = TX_CSUM_TCPIP6; 119662306a36Sopenharmony_ci else if (proto == IPPROTO_UDP) 119762306a36Sopenharmony_ci csum_type = TX_CSUM_UDPIP6; 119862306a36Sopenharmony_ci else 119962306a36Sopenharmony_ci goto nocsum; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (likely(csum_type >= TX_CSUM_TCPIP)) { 120362306a36Sopenharmony_ci int eth_hdr_len, l4_len; 120462306a36Sopenharmony_ci u64 hdr_len; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci if (inner_hdr_csum) { 120762306a36Sopenharmony_ci /* This allows checksum offload for all encapsulated 120862306a36Sopenharmony_ci * packets like GRE etc.. 120962306a36Sopenharmony_ci */ 121062306a36Sopenharmony_ci l4_len = skb_inner_network_header_len(skb); 121162306a36Sopenharmony_ci eth_hdr_len = skb_inner_network_offset(skb) - ETH_HLEN; 121262306a36Sopenharmony_ci } else { 121362306a36Sopenharmony_ci l4_len = skb_network_header_len(skb); 121462306a36Sopenharmony_ci eth_hdr_len = skb_network_offset(skb) - ETH_HLEN; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci hdr_len = TXPKT_IPHDR_LEN_V(l4_len); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(chip) <= CHELSIO_T5) 121962306a36Sopenharmony_ci hdr_len |= TXPKT_ETHHDR_LEN_V(eth_hdr_len); 122062306a36Sopenharmony_ci else 122162306a36Sopenharmony_ci hdr_len |= T6_TXPKT_ETHHDR_LEN_V(eth_hdr_len); 122262306a36Sopenharmony_ci return TXPKT_CSUM_TYPE_V(csum_type) | hdr_len; 122362306a36Sopenharmony_ci } else { 122462306a36Sopenharmony_ci int start = skb_transport_offset(skb); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci return TXPKT_CSUM_TYPE_V(csum_type) | 122762306a36Sopenharmony_ci TXPKT_CSUM_START_V(start) | 122862306a36Sopenharmony_ci TXPKT_CSUM_LOC_V(start + skb->csum_offset); 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic void eth_txq_stop(struct sge_eth_txq *q) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci netif_tx_stop_queue(q->txq); 123562306a36Sopenharmony_ci q->q.stops++; 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic inline void txq_advance(struct sge_txq *q, unsigned int n) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci q->in_use += n; 124162306a36Sopenharmony_ci q->pidx += n; 124262306a36Sopenharmony_ci if (q->pidx >= q->size) 124362306a36Sopenharmony_ci q->pidx -= q->size; 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 124762306a36Sopenharmony_cistatic inline int 124862306a36Sopenharmony_cicxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap, 124962306a36Sopenharmony_ci const struct port_info *pi, u64 *cntrl) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci const struct cxgb_fcoe *fcoe = &pi->fcoe; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (!(fcoe->flags & CXGB_FCOE_ENABLED)) 125462306a36Sopenharmony_ci return 0; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci if (skb->protocol != htons(ETH_P_FCOE)) 125762306a36Sopenharmony_ci return 0; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci skb_reset_mac_header(skb); 126062306a36Sopenharmony_ci skb->mac_len = sizeof(struct ethhdr); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci skb_set_network_header(skb, skb->mac_len); 126362306a36Sopenharmony_ci skb_set_transport_header(skb, skb->mac_len + sizeof(struct fcoe_hdr)); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (!cxgb_fcoe_sof_eof_supported(adap, skb)) 126662306a36Sopenharmony_ci return -ENOTSUPP; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci /* FC CRC offload */ 126962306a36Sopenharmony_ci *cntrl = TXPKT_CSUM_TYPE_V(TX_CSUM_FCOE) | 127062306a36Sopenharmony_ci TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F | 127162306a36Sopenharmony_ci TXPKT_CSUM_START_V(CXGB_FCOE_TXPKT_CSUM_START) | 127262306a36Sopenharmony_ci TXPKT_CSUM_END_V(CXGB_FCOE_TXPKT_CSUM_END) | 127362306a36Sopenharmony_ci TXPKT_CSUM_LOC_V(CXGB_FCOE_TXPKT_CSUM_END); 127462306a36Sopenharmony_ci return 0; 127562306a36Sopenharmony_ci} 127662306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci/* Returns tunnel type if hardware supports offloading of the same. 127962306a36Sopenharmony_ci * It is called only for T5 and onwards. 128062306a36Sopenharmony_ci */ 128162306a36Sopenharmony_cienum cpl_tx_tnl_lso_type cxgb_encap_offload_supported(struct sk_buff *skb) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci u8 l4_hdr = 0; 128462306a36Sopenharmony_ci enum cpl_tx_tnl_lso_type tnl_type = TX_TNL_TYPE_OPAQUE; 128562306a36Sopenharmony_ci struct port_info *pi = netdev_priv(skb->dev); 128662306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (skb->inner_protocol_type != ENCAP_TYPE_ETHER || 128962306a36Sopenharmony_ci skb->inner_protocol != htons(ETH_P_TEB)) 129062306a36Sopenharmony_ci return tnl_type; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci switch (vlan_get_protocol(skb)) { 129362306a36Sopenharmony_ci case htons(ETH_P_IP): 129462306a36Sopenharmony_ci l4_hdr = ip_hdr(skb)->protocol; 129562306a36Sopenharmony_ci break; 129662306a36Sopenharmony_ci case htons(ETH_P_IPV6): 129762306a36Sopenharmony_ci l4_hdr = ipv6_hdr(skb)->nexthdr; 129862306a36Sopenharmony_ci break; 129962306a36Sopenharmony_ci default: 130062306a36Sopenharmony_ci return tnl_type; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci switch (l4_hdr) { 130462306a36Sopenharmony_ci case IPPROTO_UDP: 130562306a36Sopenharmony_ci if (adapter->vxlan_port == udp_hdr(skb)->dest) 130662306a36Sopenharmony_ci tnl_type = TX_TNL_TYPE_VXLAN; 130762306a36Sopenharmony_ci else if (adapter->geneve_port == udp_hdr(skb)->dest) 130862306a36Sopenharmony_ci tnl_type = TX_TNL_TYPE_GENEVE; 130962306a36Sopenharmony_ci break; 131062306a36Sopenharmony_ci default: 131162306a36Sopenharmony_ci return tnl_type; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return tnl_type; 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic inline void t6_fill_tnl_lso(struct sk_buff *skb, 131862306a36Sopenharmony_ci struct cpl_tx_tnl_lso *tnl_lso, 131962306a36Sopenharmony_ci enum cpl_tx_tnl_lso_type tnl_type) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci u32 val; 132262306a36Sopenharmony_ci int in_eth_xtra_len; 132362306a36Sopenharmony_ci int l3hdr_len = skb_network_header_len(skb); 132462306a36Sopenharmony_ci int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; 132562306a36Sopenharmony_ci const struct skb_shared_info *ssi = skb_shinfo(skb); 132662306a36Sopenharmony_ci bool v6 = (ip_hdr(skb)->version == 6); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci val = CPL_TX_TNL_LSO_OPCODE_V(CPL_TX_TNL_LSO) | 132962306a36Sopenharmony_ci CPL_TX_TNL_LSO_FIRST_F | 133062306a36Sopenharmony_ci CPL_TX_TNL_LSO_LAST_F | 133162306a36Sopenharmony_ci (v6 ? CPL_TX_TNL_LSO_IPV6OUT_F : 0) | 133262306a36Sopenharmony_ci CPL_TX_TNL_LSO_ETHHDRLENOUT_V(eth_xtra_len / 4) | 133362306a36Sopenharmony_ci CPL_TX_TNL_LSO_IPHDRLENOUT_V(l3hdr_len / 4) | 133462306a36Sopenharmony_ci (v6 ? 0 : CPL_TX_TNL_LSO_IPHDRCHKOUT_F) | 133562306a36Sopenharmony_ci CPL_TX_TNL_LSO_IPLENSETOUT_F | 133662306a36Sopenharmony_ci (v6 ? 0 : CPL_TX_TNL_LSO_IPIDINCOUT_F); 133762306a36Sopenharmony_ci tnl_lso->op_to_IpIdSplitOut = htonl(val); 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci tnl_lso->IpIdOffsetOut = 0; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci /* Get the tunnel header length */ 134262306a36Sopenharmony_ci val = skb_inner_mac_header(skb) - skb_mac_header(skb); 134362306a36Sopenharmony_ci in_eth_xtra_len = skb_inner_network_header(skb) - 134462306a36Sopenharmony_ci skb_inner_mac_header(skb) - ETH_HLEN; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci switch (tnl_type) { 134762306a36Sopenharmony_ci case TX_TNL_TYPE_VXLAN: 134862306a36Sopenharmony_ci case TX_TNL_TYPE_GENEVE: 134962306a36Sopenharmony_ci tnl_lso->UdpLenSetOut_to_TnlHdrLen = 135062306a36Sopenharmony_ci htons(CPL_TX_TNL_LSO_UDPCHKCLROUT_F | 135162306a36Sopenharmony_ci CPL_TX_TNL_LSO_UDPLENSETOUT_F); 135262306a36Sopenharmony_ci break; 135362306a36Sopenharmony_ci default: 135462306a36Sopenharmony_ci tnl_lso->UdpLenSetOut_to_TnlHdrLen = 0; 135562306a36Sopenharmony_ci break; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci tnl_lso->UdpLenSetOut_to_TnlHdrLen |= 135962306a36Sopenharmony_ci htons(CPL_TX_TNL_LSO_TNLHDRLEN_V(val) | 136062306a36Sopenharmony_ci CPL_TX_TNL_LSO_TNLTYPE_V(tnl_type)); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci tnl_lso->r1 = 0; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci val = CPL_TX_TNL_LSO_ETHHDRLEN_V(in_eth_xtra_len / 4) | 136562306a36Sopenharmony_ci CPL_TX_TNL_LSO_IPV6_V(inner_ip_hdr(skb)->version == 6) | 136662306a36Sopenharmony_ci CPL_TX_TNL_LSO_IPHDRLEN_V(skb_inner_network_header_len(skb) / 4) | 136762306a36Sopenharmony_ci CPL_TX_TNL_LSO_TCPHDRLEN_V(inner_tcp_hdrlen(skb) / 4); 136862306a36Sopenharmony_ci tnl_lso->Flow_to_TcpHdrLen = htonl(val); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci tnl_lso->IpIdOffset = htons(0); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci tnl_lso->IpIdSplit_to_Mss = htons(CPL_TX_TNL_LSO_MSS_V(ssi->gso_size)); 137362306a36Sopenharmony_ci tnl_lso->TCPSeqOffset = htonl(0); 137462306a36Sopenharmony_ci tnl_lso->EthLenOffset_Size = htonl(CPL_TX_TNL_LSO_SIZE_V(skb->len)); 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_cistatic inline void *write_tso_wr(struct adapter *adap, struct sk_buff *skb, 137862306a36Sopenharmony_ci struct cpl_tx_pkt_lso_core *lso) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; 138162306a36Sopenharmony_ci int l3hdr_len = skb_network_header_len(skb); 138262306a36Sopenharmony_ci const struct skb_shared_info *ssi; 138362306a36Sopenharmony_ci bool ipv6 = false; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci ssi = skb_shinfo(skb); 138662306a36Sopenharmony_ci if (ssi->gso_type & SKB_GSO_TCPV6) 138762306a36Sopenharmony_ci ipv6 = true; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci lso->lso_ctrl = htonl(LSO_OPCODE_V(CPL_TX_PKT_LSO) | 139062306a36Sopenharmony_ci LSO_FIRST_SLICE_F | LSO_LAST_SLICE_F | 139162306a36Sopenharmony_ci LSO_IPV6_V(ipv6) | 139262306a36Sopenharmony_ci LSO_ETHHDR_LEN_V(eth_xtra_len / 4) | 139362306a36Sopenharmony_ci LSO_IPHDR_LEN_V(l3hdr_len / 4) | 139462306a36Sopenharmony_ci LSO_TCPHDR_LEN_V(tcp_hdr(skb)->doff)); 139562306a36Sopenharmony_ci lso->ipid_ofst = htons(0); 139662306a36Sopenharmony_ci lso->mss = htons(ssi->gso_size); 139762306a36Sopenharmony_ci lso->seqno_offset = htonl(0); 139862306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 139962306a36Sopenharmony_ci lso->len = htonl(skb->len); 140062306a36Sopenharmony_ci else 140162306a36Sopenharmony_ci lso->len = htonl(LSO_T5_XFER_SIZE_V(skb->len)); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci return (void *)(lso + 1); 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci/** 140762306a36Sopenharmony_ci * t4_sge_eth_txq_egress_update - handle Ethernet TX Queue update 140862306a36Sopenharmony_ci * @adap: the adapter 140962306a36Sopenharmony_ci * @eq: the Ethernet TX Queue 141062306a36Sopenharmony_ci * @maxreclaim: the maximum number of TX Descriptors to reclaim or -1 141162306a36Sopenharmony_ci * 141262306a36Sopenharmony_ci * We're typically called here to update the state of an Ethernet TX 141362306a36Sopenharmony_ci * Queue with respect to the hardware's progress in consuming the TX 141462306a36Sopenharmony_ci * Work Requests that we've put on that Egress Queue. This happens 141562306a36Sopenharmony_ci * when we get Egress Queue Update messages and also prophylactically 141662306a36Sopenharmony_ci * in regular timer-based Ethernet TX Queue maintenance. 141762306a36Sopenharmony_ci */ 141862306a36Sopenharmony_ciint t4_sge_eth_txq_egress_update(struct adapter *adap, struct sge_eth_txq *eq, 141962306a36Sopenharmony_ci int maxreclaim) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci unsigned int reclaimed, hw_cidx; 142262306a36Sopenharmony_ci struct sge_txq *q = &eq->q; 142362306a36Sopenharmony_ci int hw_in_use; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci if (!q->in_use || !__netif_tx_trylock(eq->txq)) 142662306a36Sopenharmony_ci return 0; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* Reclaim pending completed TX Descriptors. */ 142962306a36Sopenharmony_ci reclaimed = reclaim_completed_tx(adap, &eq->q, maxreclaim, true); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci hw_cidx = ntohs(READ_ONCE(q->stat->cidx)); 143262306a36Sopenharmony_ci hw_in_use = q->pidx - hw_cidx; 143362306a36Sopenharmony_ci if (hw_in_use < 0) 143462306a36Sopenharmony_ci hw_in_use += q->size; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci /* If the TX Queue is currently stopped and there's now more than half 143762306a36Sopenharmony_ci * the queue available, restart it. Otherwise bail out since the rest 143862306a36Sopenharmony_ci * of what we want do here is with the possibility of shipping any 143962306a36Sopenharmony_ci * currently buffered Coalesced TX Work Request. 144062306a36Sopenharmony_ci */ 144162306a36Sopenharmony_ci if (netif_tx_queue_stopped(eq->txq) && hw_in_use < (q->size / 2)) { 144262306a36Sopenharmony_ci netif_tx_wake_queue(eq->txq); 144362306a36Sopenharmony_ci eq->q.restarts++; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci __netif_tx_unlock(eq->txq); 144762306a36Sopenharmony_ci return reclaimed; 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_cistatic inline int cxgb4_validate_skb(struct sk_buff *skb, 145162306a36Sopenharmony_ci struct net_device *dev, 145262306a36Sopenharmony_ci u32 min_pkt_len) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci u32 max_pkt_len; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci /* The chip min packet length is 10 octets but some firmware 145762306a36Sopenharmony_ci * commands have a minimum packet length requirement. So, play 145862306a36Sopenharmony_ci * safe and reject anything shorter than @min_pkt_len. 145962306a36Sopenharmony_ci */ 146062306a36Sopenharmony_ci if (unlikely(skb->len < min_pkt_len)) 146162306a36Sopenharmony_ci return -EINVAL; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* Discard the packet if the length is greater than mtu */ 146462306a36Sopenharmony_ci max_pkt_len = ETH_HLEN + dev->mtu; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (skb_vlan_tagged(skb)) 146762306a36Sopenharmony_ci max_pkt_len += VLAN_HLEN; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len))) 147062306a36Sopenharmony_ci return -EINVAL; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci return 0; 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic void *write_eo_udp_wr(struct sk_buff *skb, struct fw_eth_tx_eo_wr *wr, 147662306a36Sopenharmony_ci u32 hdr_len) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci wr->u.udpseg.type = FW_ETH_TX_EO_TYPE_UDPSEG; 147962306a36Sopenharmony_ci wr->u.udpseg.ethlen = skb_network_offset(skb); 148062306a36Sopenharmony_ci wr->u.udpseg.iplen = cpu_to_be16(skb_network_header_len(skb)); 148162306a36Sopenharmony_ci wr->u.udpseg.udplen = sizeof(struct udphdr); 148262306a36Sopenharmony_ci wr->u.udpseg.rtplen = 0; 148362306a36Sopenharmony_ci wr->u.udpseg.r4 = 0; 148462306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size) 148562306a36Sopenharmony_ci wr->u.udpseg.mss = cpu_to_be16(skb_shinfo(skb)->gso_size); 148662306a36Sopenharmony_ci else 148762306a36Sopenharmony_ci wr->u.udpseg.mss = cpu_to_be16(skb->len - hdr_len); 148862306a36Sopenharmony_ci wr->u.udpseg.schedpktsize = wr->u.udpseg.mss; 148962306a36Sopenharmony_ci wr->u.udpseg.plen = cpu_to_be32(skb->len - hdr_len); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci return (void *)(wr + 1); 149262306a36Sopenharmony_ci} 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci/** 149562306a36Sopenharmony_ci * cxgb4_eth_xmit - add a packet to an Ethernet Tx queue 149662306a36Sopenharmony_ci * @skb: the packet 149762306a36Sopenharmony_ci * @dev: the egress net device 149862306a36Sopenharmony_ci * 149962306a36Sopenharmony_ci * Add a packet to an SGE Ethernet Tx queue. Runs with softirqs disabled. 150062306a36Sopenharmony_ci */ 150162306a36Sopenharmony_cistatic netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci enum cpl_tx_tnl_lso_type tnl_type = TX_TNL_TYPE_OPAQUE; 150462306a36Sopenharmony_ci bool ptp_enabled = is_ptp_enabled(skb, dev); 150562306a36Sopenharmony_ci unsigned int last_desc, flits, ndesc; 150662306a36Sopenharmony_ci u32 wr_mid, ctrl0, op, sgl_off = 0; 150762306a36Sopenharmony_ci const struct skb_shared_info *ssi; 150862306a36Sopenharmony_ci int len, qidx, credits, ret, left; 150962306a36Sopenharmony_ci struct tx_sw_desc *sgl_sdesc; 151062306a36Sopenharmony_ci struct fw_eth_tx_eo_wr *eowr; 151162306a36Sopenharmony_ci struct fw_eth_tx_pkt_wr *wr; 151262306a36Sopenharmony_ci struct cpl_tx_pkt_core *cpl; 151362306a36Sopenharmony_ci const struct port_info *pi; 151462306a36Sopenharmony_ci bool immediate = false; 151562306a36Sopenharmony_ci u64 cntrl, *end, *sgl; 151662306a36Sopenharmony_ci struct sge_eth_txq *q; 151762306a36Sopenharmony_ci unsigned int chip_ver; 151862306a36Sopenharmony_ci struct adapter *adap; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci ret = cxgb4_validate_skb(skb, dev, ETH_HLEN); 152162306a36Sopenharmony_ci if (ret) 152262306a36Sopenharmony_ci goto out_free; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci pi = netdev_priv(dev); 152562306a36Sopenharmony_ci adap = pi->adapter; 152662306a36Sopenharmony_ci ssi = skb_shinfo(skb); 152762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 152862306a36Sopenharmony_ci if (xfrm_offload(skb) && !ssi->gso_size) 152962306a36Sopenharmony_ci return adap->uld[CXGB4_ULD_IPSEC].tx_handler(skb, dev); 153062306a36Sopenharmony_ci#endif /* CHELSIO_IPSEC_INLINE */ 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 153362306a36Sopenharmony_ci if (tls_is_skb_tx_device_offloaded(skb) && 153462306a36Sopenharmony_ci (skb->len - skb_tcp_all_headers(skb))) 153562306a36Sopenharmony_ci return adap->uld[CXGB4_ULD_KTLS].tx_handler(skb, dev); 153662306a36Sopenharmony_ci#endif /* CHELSIO_TLS_DEVICE */ 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci qidx = skb_get_queue_mapping(skb); 153962306a36Sopenharmony_ci if (ptp_enabled) { 154062306a36Sopenharmony_ci if (!(adap->ptp_tx_skb)) { 154162306a36Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 154262306a36Sopenharmony_ci adap->ptp_tx_skb = skb_get(skb); 154362306a36Sopenharmony_ci } else { 154462306a36Sopenharmony_ci goto out_free; 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci q = &adap->sge.ptptxq; 154762306a36Sopenharmony_ci } else { 154862306a36Sopenharmony_ci q = &adap->sge.ethtxq[qidx + pi->first_qset]; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci skb_tx_timestamp(skb); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci reclaim_completed_tx(adap, &q->q, -1, true); 155362306a36Sopenharmony_ci cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 155662306a36Sopenharmony_ci ret = cxgb_fcoe_offload(skb, adap, pi, &cntrl); 155762306a36Sopenharmony_ci if (unlikely(ret == -EOPNOTSUPP)) 155862306a36Sopenharmony_ci goto out_free; 155962306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); 156262306a36Sopenharmony_ci flits = calc_tx_flits(skb, chip_ver); 156362306a36Sopenharmony_ci ndesc = flits_to_desc(flits); 156462306a36Sopenharmony_ci credits = txq_avail(&q->q) - ndesc; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci if (unlikely(credits < 0)) { 156762306a36Sopenharmony_ci eth_txq_stop(q); 156862306a36Sopenharmony_ci dev_err(adap->pdev_dev, 156962306a36Sopenharmony_ci "%s: Tx ring %u full while queue awake!\n", 157062306a36Sopenharmony_ci dev->name, qidx); 157162306a36Sopenharmony_ci return NETDEV_TX_BUSY; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci if (is_eth_imm(skb, chip_ver)) 157562306a36Sopenharmony_ci immediate = true; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci if (skb->encapsulation && chip_ver > CHELSIO_T5) 157862306a36Sopenharmony_ci tnl_type = cxgb_encap_offload_supported(skb); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci last_desc = q->q.pidx + ndesc - 1; 158162306a36Sopenharmony_ci if (last_desc >= q->q.size) 158262306a36Sopenharmony_ci last_desc -= q->q.size; 158362306a36Sopenharmony_ci sgl_sdesc = &q->q.sdesc[last_desc]; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (!immediate && 158662306a36Sopenharmony_ci unlikely(cxgb4_map_skb(adap->pdev_dev, skb, sgl_sdesc->addr) < 0)) { 158762306a36Sopenharmony_ci memset(sgl_sdesc->addr, 0, sizeof(sgl_sdesc->addr)); 158862306a36Sopenharmony_ci q->mapping_err++; 158962306a36Sopenharmony_ci goto out_free; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci wr_mid = FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2)); 159362306a36Sopenharmony_ci if (unlikely(credits < ETHTXQ_STOP_THRES)) { 159462306a36Sopenharmony_ci /* After we're done injecting the Work Request for this 159562306a36Sopenharmony_ci * packet, we'll be below our "stop threshold" so stop the TX 159662306a36Sopenharmony_ci * Queue now and schedule a request for an SGE Egress Queue 159762306a36Sopenharmony_ci * Update message. The queue will get started later on when 159862306a36Sopenharmony_ci * the firmware processes this Work Request and sends us an 159962306a36Sopenharmony_ci * Egress Queue Status Update message indicating that space 160062306a36Sopenharmony_ci * has opened up. 160162306a36Sopenharmony_ci */ 160262306a36Sopenharmony_ci eth_txq_stop(q); 160362306a36Sopenharmony_ci if (chip_ver > CHELSIO_T5) 160462306a36Sopenharmony_ci wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci wr = (void *)&q->q.desc[q->q.pidx]; 160862306a36Sopenharmony_ci eowr = (void *)&q->q.desc[q->q.pidx]; 160962306a36Sopenharmony_ci wr->equiq_to_len16 = htonl(wr_mid); 161062306a36Sopenharmony_ci wr->r3 = cpu_to_be64(0); 161162306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 161262306a36Sopenharmony_ci end = (u64 *)eowr + flits; 161362306a36Sopenharmony_ci else 161462306a36Sopenharmony_ci end = (u64 *)wr + flits; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci len = immediate ? skb->len : 0; 161762306a36Sopenharmony_ci len += sizeof(*cpl); 161862306a36Sopenharmony_ci if (ssi->gso_size && !(ssi->gso_type & SKB_GSO_UDP_L4)) { 161962306a36Sopenharmony_ci struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); 162062306a36Sopenharmony_ci struct cpl_tx_tnl_lso *tnl_lso = (void *)(wr + 1); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (tnl_type) 162362306a36Sopenharmony_ci len += sizeof(*tnl_lso); 162462306a36Sopenharmony_ci else 162562306a36Sopenharmony_ci len += sizeof(*lso); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) | 162862306a36Sopenharmony_ci FW_WR_IMMDLEN_V(len)); 162962306a36Sopenharmony_ci if (tnl_type) { 163062306a36Sopenharmony_ci struct iphdr *iph = ip_hdr(skb); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci t6_fill_tnl_lso(skb, tnl_lso, tnl_type); 163362306a36Sopenharmony_ci cpl = (void *)(tnl_lso + 1); 163462306a36Sopenharmony_ci /* Driver is expected to compute partial checksum that 163562306a36Sopenharmony_ci * does not include the IP Total Length. 163662306a36Sopenharmony_ci */ 163762306a36Sopenharmony_ci if (iph->version == 4) { 163862306a36Sopenharmony_ci iph->check = 0; 163962306a36Sopenharmony_ci iph->tot_len = 0; 164062306a36Sopenharmony_ci iph->check = ~ip_fast_csum((u8 *)iph, iph->ihl); 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 164362306a36Sopenharmony_ci cntrl = hwcsum(adap->params.chip, skb); 164462306a36Sopenharmony_ci } else { 164562306a36Sopenharmony_ci cpl = write_tso_wr(adap, skb, lso); 164662306a36Sopenharmony_ci cntrl = hwcsum(adap->params.chip, skb); 164762306a36Sopenharmony_ci } 164862306a36Sopenharmony_ci sgl = (u64 *)(cpl + 1); /* sgl start here */ 164962306a36Sopenharmony_ci q->tso++; 165062306a36Sopenharmony_ci q->tx_cso += ssi->gso_segs; 165162306a36Sopenharmony_ci } else if (ssi->gso_size) { 165262306a36Sopenharmony_ci u64 *start; 165362306a36Sopenharmony_ci u32 hdrlen; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci hdrlen = eth_get_headlen(dev, skb->data, skb_headlen(skb)); 165662306a36Sopenharmony_ci len += hdrlen; 165762306a36Sopenharmony_ci wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_EO_WR) | 165862306a36Sopenharmony_ci FW_ETH_TX_EO_WR_IMMDLEN_V(len)); 165962306a36Sopenharmony_ci cpl = write_eo_udp_wr(skb, eowr, hdrlen); 166062306a36Sopenharmony_ci cntrl = hwcsum(adap->params.chip, skb); 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci start = (u64 *)(cpl + 1); 166362306a36Sopenharmony_ci sgl = (u64 *)inline_tx_skb_header(skb, &q->q, (void *)start, 166462306a36Sopenharmony_ci hdrlen); 166562306a36Sopenharmony_ci if (unlikely(start > sgl)) { 166662306a36Sopenharmony_ci left = (u8 *)end - (u8 *)q->q.stat; 166762306a36Sopenharmony_ci end = (void *)q->q.desc + left; 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci sgl_off = hdrlen; 167062306a36Sopenharmony_ci q->uso++; 167162306a36Sopenharmony_ci q->tx_cso += ssi->gso_segs; 167262306a36Sopenharmony_ci } else { 167362306a36Sopenharmony_ci if (ptp_enabled) 167462306a36Sopenharmony_ci op = FW_PTP_TX_PKT_WR; 167562306a36Sopenharmony_ci else 167662306a36Sopenharmony_ci op = FW_ETH_TX_PKT_WR; 167762306a36Sopenharmony_ci wr->op_immdlen = htonl(FW_WR_OP_V(op) | 167862306a36Sopenharmony_ci FW_WR_IMMDLEN_V(len)); 167962306a36Sopenharmony_ci cpl = (void *)(wr + 1); 168062306a36Sopenharmony_ci sgl = (u64 *)(cpl + 1); 168162306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 168262306a36Sopenharmony_ci cntrl = hwcsum(adap->params.chip, skb) | 168362306a36Sopenharmony_ci TXPKT_IPCSUM_DIS_F; 168462306a36Sopenharmony_ci q->tx_cso++; 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci if (unlikely((u8 *)sgl >= (u8 *)q->q.stat)) { 168962306a36Sopenharmony_ci /* If current position is already at the end of the 169062306a36Sopenharmony_ci * txq, reset the current to point to start of the queue 169162306a36Sopenharmony_ci * and update the end ptr as well. 169262306a36Sopenharmony_ci */ 169362306a36Sopenharmony_ci left = (u8 *)end - (u8 *)q->q.stat; 169462306a36Sopenharmony_ci end = (void *)q->q.desc + left; 169562306a36Sopenharmony_ci sgl = (void *)q->q.desc; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 169962306a36Sopenharmony_ci q->vlan_ins++; 170062306a36Sopenharmony_ci cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb)); 170162306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 170262306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_FCOE)) 170362306a36Sopenharmony_ci cntrl |= TXPKT_VLAN_V( 170462306a36Sopenharmony_ci ((skb->priority & 0x7) << VLAN_PRIO_SHIFT)); 170562306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci ctrl0 = TXPKT_OPCODE_V(CPL_TX_PKT_XT) | TXPKT_INTF_V(pi->tx_chan) | 170962306a36Sopenharmony_ci TXPKT_PF_V(adap->pf); 171062306a36Sopenharmony_ci if (ptp_enabled) 171162306a36Sopenharmony_ci ctrl0 |= TXPKT_TSTAMP_F; 171262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 171362306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 171462306a36Sopenharmony_ci ctrl0 |= TXPKT_OVLAN_IDX_V(q->dcb_prio); 171562306a36Sopenharmony_ci else 171662306a36Sopenharmony_ci ctrl0 |= TXPKT_T5_OVLAN_IDX_V(q->dcb_prio); 171762306a36Sopenharmony_ci#endif 171862306a36Sopenharmony_ci cpl->ctrl0 = htonl(ctrl0); 171962306a36Sopenharmony_ci cpl->pack = htons(0); 172062306a36Sopenharmony_ci cpl->len = htons(skb->len); 172162306a36Sopenharmony_ci cpl->ctrl1 = cpu_to_be64(cntrl); 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci if (immediate) { 172462306a36Sopenharmony_ci cxgb4_inline_tx_skb(skb, &q->q, sgl); 172562306a36Sopenharmony_ci dev_consume_skb_any(skb); 172662306a36Sopenharmony_ci } else { 172762306a36Sopenharmony_ci cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, sgl_off, 172862306a36Sopenharmony_ci sgl_sdesc->addr); 172962306a36Sopenharmony_ci skb_orphan(skb); 173062306a36Sopenharmony_ci sgl_sdesc->skb = skb; 173162306a36Sopenharmony_ci } 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci txq_advance(&q->q, ndesc); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci cxgb4_ring_tx_db(adap, &q->q, ndesc); 173662306a36Sopenharmony_ci return NETDEV_TX_OK; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ciout_free: 173962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 174062306a36Sopenharmony_ci return NETDEV_TX_OK; 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci/* Constants ... */ 174462306a36Sopenharmony_cienum { 174562306a36Sopenharmony_ci /* Egress Queue sizes, producer and consumer indices are all in units 174662306a36Sopenharmony_ci * of Egress Context Units bytes. Note that as far as the hardware is 174762306a36Sopenharmony_ci * concerned, the free list is an Egress Queue (the host produces free 174862306a36Sopenharmony_ci * buffers which the hardware consumes) and free list entries are 174962306a36Sopenharmony_ci * 64-bit PCI DMA addresses. 175062306a36Sopenharmony_ci */ 175162306a36Sopenharmony_ci EQ_UNIT = SGE_EQ_IDXSIZE, 175262306a36Sopenharmony_ci FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), 175362306a36Sopenharmony_ci TXD_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci T4VF_ETHTXQ_MAX_HDR = (sizeof(struct fw_eth_tx_pkt_vm_wr) + 175662306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt_lso_core) + 175762306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64), 175862306a36Sopenharmony_ci}; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci/** 176162306a36Sopenharmony_ci * t4vf_is_eth_imm - can an Ethernet packet be sent as immediate data? 176262306a36Sopenharmony_ci * @skb: the packet 176362306a36Sopenharmony_ci * 176462306a36Sopenharmony_ci * Returns whether an Ethernet packet is small enough to fit completely as 176562306a36Sopenharmony_ci * immediate data. 176662306a36Sopenharmony_ci */ 176762306a36Sopenharmony_cistatic inline int t4vf_is_eth_imm(const struct sk_buff *skb) 176862306a36Sopenharmony_ci{ 176962306a36Sopenharmony_ci /* The VF Driver uses the FW_ETH_TX_PKT_VM_WR firmware Work Request 177062306a36Sopenharmony_ci * which does not accommodate immediate data. We could dike out all 177162306a36Sopenharmony_ci * of the support code for immediate data but that would tie our hands 177262306a36Sopenharmony_ci * too much if we ever want to enhace the firmware. It would also 177362306a36Sopenharmony_ci * create more differences between the PF and VF Drivers. 177462306a36Sopenharmony_ci */ 177562306a36Sopenharmony_ci return false; 177662306a36Sopenharmony_ci} 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci/** 177962306a36Sopenharmony_ci * t4vf_calc_tx_flits - calculate the number of flits for a packet TX WR 178062306a36Sopenharmony_ci * @skb: the packet 178162306a36Sopenharmony_ci * 178262306a36Sopenharmony_ci * Returns the number of flits needed for a TX Work Request for the 178362306a36Sopenharmony_ci * given Ethernet packet, including the needed WR and CPL headers. 178462306a36Sopenharmony_ci */ 178562306a36Sopenharmony_cistatic inline unsigned int t4vf_calc_tx_flits(const struct sk_buff *skb) 178662306a36Sopenharmony_ci{ 178762306a36Sopenharmony_ci unsigned int flits; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* If the skb is small enough, we can pump it out as a work request 179062306a36Sopenharmony_ci * with only immediate data. In that case we just have to have the 179162306a36Sopenharmony_ci * TX Packet header plus the skb data in the Work Request. 179262306a36Sopenharmony_ci */ 179362306a36Sopenharmony_ci if (t4vf_is_eth_imm(skb)) 179462306a36Sopenharmony_ci return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 179562306a36Sopenharmony_ci sizeof(__be64)); 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci /* Otherwise, we're going to have to construct a Scatter gather list 179862306a36Sopenharmony_ci * of the skb body and fragments. We also include the flits necessary 179962306a36Sopenharmony_ci * for the TX Packet Work Request and CPL. We always have a firmware 180062306a36Sopenharmony_ci * Write Header (incorporated as part of the cpl_tx_pkt_lso and 180162306a36Sopenharmony_ci * cpl_tx_pkt structures), followed by either a TX Packet Write CPL 180262306a36Sopenharmony_ci * message or, if we're doing a Large Send Offload, an LSO CPL message 180362306a36Sopenharmony_ci * with an embedded TX Packet Write CPL message. 180462306a36Sopenharmony_ci */ 180562306a36Sopenharmony_ci flits = sgl_len(skb_shinfo(skb)->nr_frags + 1); 180662306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size) 180762306a36Sopenharmony_ci flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) + 180862306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt_lso_core) + 180962306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); 181062306a36Sopenharmony_ci else 181162306a36Sopenharmony_ci flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) + 181262306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); 181362306a36Sopenharmony_ci return flits; 181462306a36Sopenharmony_ci} 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci/** 181762306a36Sopenharmony_ci * cxgb4_vf_eth_xmit - add a packet to an Ethernet TX queue 181862306a36Sopenharmony_ci * @skb: the packet 181962306a36Sopenharmony_ci * @dev: the egress net device 182062306a36Sopenharmony_ci * 182162306a36Sopenharmony_ci * Add a packet to an SGE Ethernet TX queue. Runs with softirqs disabled. 182262306a36Sopenharmony_ci */ 182362306a36Sopenharmony_cistatic netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb, 182462306a36Sopenharmony_ci struct net_device *dev) 182562306a36Sopenharmony_ci{ 182662306a36Sopenharmony_ci unsigned int last_desc, flits, ndesc; 182762306a36Sopenharmony_ci const struct skb_shared_info *ssi; 182862306a36Sopenharmony_ci struct fw_eth_tx_pkt_vm_wr *wr; 182962306a36Sopenharmony_ci struct tx_sw_desc *sgl_sdesc; 183062306a36Sopenharmony_ci struct cpl_tx_pkt_core *cpl; 183162306a36Sopenharmony_ci const struct port_info *pi; 183262306a36Sopenharmony_ci struct sge_eth_txq *txq; 183362306a36Sopenharmony_ci struct adapter *adapter; 183462306a36Sopenharmony_ci int qidx, credits, ret; 183562306a36Sopenharmony_ci size_t fw_hdr_copy_len; 183662306a36Sopenharmony_ci unsigned int chip_ver; 183762306a36Sopenharmony_ci u64 cntrl, *end; 183862306a36Sopenharmony_ci u32 wr_mid; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci /* The chip minimum packet length is 10 octets but the firmware 184162306a36Sopenharmony_ci * command that we are using requires that we copy the Ethernet header 184262306a36Sopenharmony_ci * (including the VLAN tag) into the header so we reject anything 184362306a36Sopenharmony_ci * smaller than that ... 184462306a36Sopenharmony_ci */ 184562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(wr->firmware) != 184662306a36Sopenharmony_ci (sizeof(wr->ethmacdst) + sizeof(wr->ethmacsrc) + 184762306a36Sopenharmony_ci sizeof(wr->ethtype) + sizeof(wr->vlantci))); 184862306a36Sopenharmony_ci fw_hdr_copy_len = sizeof(wr->firmware); 184962306a36Sopenharmony_ci ret = cxgb4_validate_skb(skb, dev, fw_hdr_copy_len); 185062306a36Sopenharmony_ci if (ret) 185162306a36Sopenharmony_ci goto out_free; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci /* Figure out which TX Queue we're going to use. */ 185462306a36Sopenharmony_ci pi = netdev_priv(dev); 185562306a36Sopenharmony_ci adapter = pi->adapter; 185662306a36Sopenharmony_ci qidx = skb_get_queue_mapping(skb); 185762306a36Sopenharmony_ci WARN_ON(qidx >= pi->nqsets); 185862306a36Sopenharmony_ci txq = &adapter->sge.ethtxq[pi->first_qset + qidx]; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci /* Take this opportunity to reclaim any TX Descriptors whose DMA 186162306a36Sopenharmony_ci * transfers have completed. 186262306a36Sopenharmony_ci */ 186362306a36Sopenharmony_ci reclaim_completed_tx(adapter, &txq->q, -1, true); 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci /* Calculate the number of flits and TX Descriptors we're going to 186662306a36Sopenharmony_ci * need along with how many TX Descriptors will be left over after 186762306a36Sopenharmony_ci * we inject our Work Request. 186862306a36Sopenharmony_ci */ 186962306a36Sopenharmony_ci flits = t4vf_calc_tx_flits(skb); 187062306a36Sopenharmony_ci ndesc = flits_to_desc(flits); 187162306a36Sopenharmony_ci credits = txq_avail(&txq->q) - ndesc; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci if (unlikely(credits < 0)) { 187462306a36Sopenharmony_ci /* Not enough room for this packet's Work Request. Stop the 187562306a36Sopenharmony_ci * TX Queue and return a "busy" condition. The queue will get 187662306a36Sopenharmony_ci * started later on when the firmware informs us that space 187762306a36Sopenharmony_ci * has opened up. 187862306a36Sopenharmony_ci */ 187962306a36Sopenharmony_ci eth_txq_stop(txq); 188062306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 188162306a36Sopenharmony_ci "%s: TX ring %u full while queue awake!\n", 188262306a36Sopenharmony_ci dev->name, qidx); 188362306a36Sopenharmony_ci return NETDEV_TX_BUSY; 188462306a36Sopenharmony_ci } 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci last_desc = txq->q.pidx + ndesc - 1; 188762306a36Sopenharmony_ci if (last_desc >= txq->q.size) 188862306a36Sopenharmony_ci last_desc -= txq->q.size; 188962306a36Sopenharmony_ci sgl_sdesc = &txq->q.sdesc[last_desc]; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci if (!t4vf_is_eth_imm(skb) && 189262306a36Sopenharmony_ci unlikely(cxgb4_map_skb(adapter->pdev_dev, skb, 189362306a36Sopenharmony_ci sgl_sdesc->addr) < 0)) { 189462306a36Sopenharmony_ci /* We need to map the skb into PCI DMA space (because it can't 189562306a36Sopenharmony_ci * be in-lined directly into the Work Request) and the mapping 189662306a36Sopenharmony_ci * operation failed. Record the error and drop the packet. 189762306a36Sopenharmony_ci */ 189862306a36Sopenharmony_ci memset(sgl_sdesc->addr, 0, sizeof(sgl_sdesc->addr)); 189962306a36Sopenharmony_ci txq->mapping_err++; 190062306a36Sopenharmony_ci goto out_free; 190162306a36Sopenharmony_ci } 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip); 190462306a36Sopenharmony_ci wr_mid = FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2)); 190562306a36Sopenharmony_ci if (unlikely(credits < ETHTXQ_STOP_THRES)) { 190662306a36Sopenharmony_ci /* After we're done injecting the Work Request for this 190762306a36Sopenharmony_ci * packet, we'll be below our "stop threshold" so stop the TX 190862306a36Sopenharmony_ci * Queue now and schedule a request for an SGE Egress Queue 190962306a36Sopenharmony_ci * Update message. The queue will get started later on when 191062306a36Sopenharmony_ci * the firmware processes this Work Request and sends us an 191162306a36Sopenharmony_ci * Egress Queue Status Update message indicating that space 191262306a36Sopenharmony_ci * has opened up. 191362306a36Sopenharmony_ci */ 191462306a36Sopenharmony_ci eth_txq_stop(txq); 191562306a36Sopenharmony_ci if (chip_ver > CHELSIO_T5) 191662306a36Sopenharmony_ci wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F; 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci /* Start filling in our Work Request. Note that we do _not_ handle 192062306a36Sopenharmony_ci * the WR Header wrapping around the TX Descriptor Ring. If our 192162306a36Sopenharmony_ci * maximum header size ever exceeds one TX Descriptor, we'll need to 192262306a36Sopenharmony_ci * do something else here. 192362306a36Sopenharmony_ci */ 192462306a36Sopenharmony_ci WARN_ON(DIV_ROUND_UP(T4VF_ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1); 192562306a36Sopenharmony_ci wr = (void *)&txq->q.desc[txq->q.pidx]; 192662306a36Sopenharmony_ci wr->equiq_to_len16 = cpu_to_be32(wr_mid); 192762306a36Sopenharmony_ci wr->r3[0] = cpu_to_be32(0); 192862306a36Sopenharmony_ci wr->r3[1] = cpu_to_be32(0); 192962306a36Sopenharmony_ci skb_copy_from_linear_data(skb, &wr->firmware, fw_hdr_copy_len); 193062306a36Sopenharmony_ci end = (u64 *)wr + flits; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci /* If this is a Large Send Offload packet we'll put in an LSO CPL 193362306a36Sopenharmony_ci * message with an encapsulated TX Packet CPL message. Otherwise we 193462306a36Sopenharmony_ci * just use a TX Packet CPL message. 193562306a36Sopenharmony_ci */ 193662306a36Sopenharmony_ci ssi = skb_shinfo(skb); 193762306a36Sopenharmony_ci if (ssi->gso_size) { 193862306a36Sopenharmony_ci struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); 193962306a36Sopenharmony_ci bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0; 194062306a36Sopenharmony_ci int l3hdr_len = skb_network_header_len(skb); 194162306a36Sopenharmony_ci int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci wr->op_immdlen = 194462306a36Sopenharmony_ci cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_PKT_VM_WR) | 194562306a36Sopenharmony_ci FW_WR_IMMDLEN_V(sizeof(*lso) + 194662306a36Sopenharmony_ci sizeof(*cpl))); 194762306a36Sopenharmony_ci /* Fill in the LSO CPL message. */ 194862306a36Sopenharmony_ci lso->lso_ctrl = 194962306a36Sopenharmony_ci cpu_to_be32(LSO_OPCODE_V(CPL_TX_PKT_LSO) | 195062306a36Sopenharmony_ci LSO_FIRST_SLICE_F | 195162306a36Sopenharmony_ci LSO_LAST_SLICE_F | 195262306a36Sopenharmony_ci LSO_IPV6_V(v6) | 195362306a36Sopenharmony_ci LSO_ETHHDR_LEN_V(eth_xtra_len / 4) | 195462306a36Sopenharmony_ci LSO_IPHDR_LEN_V(l3hdr_len / 4) | 195562306a36Sopenharmony_ci LSO_TCPHDR_LEN_V(tcp_hdr(skb)->doff)); 195662306a36Sopenharmony_ci lso->ipid_ofst = cpu_to_be16(0); 195762306a36Sopenharmony_ci lso->mss = cpu_to_be16(ssi->gso_size); 195862306a36Sopenharmony_ci lso->seqno_offset = cpu_to_be32(0); 195962306a36Sopenharmony_ci if (is_t4(adapter->params.chip)) 196062306a36Sopenharmony_ci lso->len = cpu_to_be32(skb->len); 196162306a36Sopenharmony_ci else 196262306a36Sopenharmony_ci lso->len = cpu_to_be32(LSO_T5_XFER_SIZE_V(skb->len)); 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci /* Set up TX Packet CPL pointer, control word and perform 196562306a36Sopenharmony_ci * accounting. 196662306a36Sopenharmony_ci */ 196762306a36Sopenharmony_ci cpl = (void *)(lso + 1); 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci if (chip_ver <= CHELSIO_T5) 197062306a36Sopenharmony_ci cntrl = TXPKT_ETHHDR_LEN_V(eth_xtra_len); 197162306a36Sopenharmony_ci else 197262306a36Sopenharmony_ci cntrl = T6_TXPKT_ETHHDR_LEN_V(eth_xtra_len); 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci cntrl |= TXPKT_CSUM_TYPE_V(v6 ? 197562306a36Sopenharmony_ci TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | 197662306a36Sopenharmony_ci TXPKT_IPHDR_LEN_V(l3hdr_len); 197762306a36Sopenharmony_ci txq->tso++; 197862306a36Sopenharmony_ci txq->tx_cso += ssi->gso_segs; 197962306a36Sopenharmony_ci } else { 198062306a36Sopenharmony_ci int len; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci len = (t4vf_is_eth_imm(skb) 198362306a36Sopenharmony_ci ? skb->len + sizeof(*cpl) 198462306a36Sopenharmony_ci : sizeof(*cpl)); 198562306a36Sopenharmony_ci wr->op_immdlen = 198662306a36Sopenharmony_ci cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_PKT_VM_WR) | 198762306a36Sopenharmony_ci FW_WR_IMMDLEN_V(len)); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci /* Set up TX Packet CPL pointer, control word and perform 199062306a36Sopenharmony_ci * accounting. 199162306a36Sopenharmony_ci */ 199262306a36Sopenharmony_ci cpl = (void *)(wr + 1); 199362306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 199462306a36Sopenharmony_ci cntrl = hwcsum(adapter->params.chip, skb) | 199562306a36Sopenharmony_ci TXPKT_IPCSUM_DIS_F; 199662306a36Sopenharmony_ci txq->tx_cso++; 199762306a36Sopenharmony_ci } else { 199862306a36Sopenharmony_ci cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F; 199962306a36Sopenharmony_ci } 200062306a36Sopenharmony_ci } 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci /* If there's a VLAN tag present, add that to the list of things to 200362306a36Sopenharmony_ci * do in this Work Request. 200462306a36Sopenharmony_ci */ 200562306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 200662306a36Sopenharmony_ci txq->vlan_ins++; 200762306a36Sopenharmony_ci cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb)); 200862306a36Sopenharmony_ci } 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci /* Fill in the TX Packet CPL message header. */ 201162306a36Sopenharmony_ci cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE_V(CPL_TX_PKT_XT) | 201262306a36Sopenharmony_ci TXPKT_INTF_V(pi->port_id) | 201362306a36Sopenharmony_ci TXPKT_PF_V(0)); 201462306a36Sopenharmony_ci cpl->pack = cpu_to_be16(0); 201562306a36Sopenharmony_ci cpl->len = cpu_to_be16(skb->len); 201662306a36Sopenharmony_ci cpl->ctrl1 = cpu_to_be64(cntrl); 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci /* Fill in the body of the TX Packet CPL message with either in-lined 201962306a36Sopenharmony_ci * data or a Scatter/Gather List. 202062306a36Sopenharmony_ci */ 202162306a36Sopenharmony_ci if (t4vf_is_eth_imm(skb)) { 202262306a36Sopenharmony_ci /* In-line the packet's data and free the skb since we don't 202362306a36Sopenharmony_ci * need it any longer. 202462306a36Sopenharmony_ci */ 202562306a36Sopenharmony_ci cxgb4_inline_tx_skb(skb, &txq->q, cpl + 1); 202662306a36Sopenharmony_ci dev_consume_skb_any(skb); 202762306a36Sopenharmony_ci } else { 202862306a36Sopenharmony_ci /* Write the skb's Scatter/Gather list into the TX Packet CPL 202962306a36Sopenharmony_ci * message and retain a pointer to the skb so we can free it 203062306a36Sopenharmony_ci * later when its DMA completes. (We store the skb pointer 203162306a36Sopenharmony_ci * in the Software Descriptor corresponding to the last TX 203262306a36Sopenharmony_ci * Descriptor used by the Work Request.) 203362306a36Sopenharmony_ci * 203462306a36Sopenharmony_ci * The retained skb will be freed when the corresponding TX 203562306a36Sopenharmony_ci * Descriptors are reclaimed after their DMAs complete. 203662306a36Sopenharmony_ci * However, this could take quite a while since, in general, 203762306a36Sopenharmony_ci * the hardware is set up to be lazy about sending DMA 203862306a36Sopenharmony_ci * completion notifications to us and we mostly perform TX 203962306a36Sopenharmony_ci * reclaims in the transmit routine. 204062306a36Sopenharmony_ci * 204162306a36Sopenharmony_ci * This is good for performamce but means that we rely on new 204262306a36Sopenharmony_ci * TX packets arriving to run the destructors of completed 204362306a36Sopenharmony_ci * packets, which open up space in their sockets' send queues. 204462306a36Sopenharmony_ci * Sometimes we do not get such new packets causing TX to 204562306a36Sopenharmony_ci * stall. A single UDP transmitter is a good example of this 204662306a36Sopenharmony_ci * situation. We have a clean up timer that periodically 204762306a36Sopenharmony_ci * reclaims completed packets but it doesn't run often enough 204862306a36Sopenharmony_ci * (nor do we want it to) to prevent lengthy stalls. A 204962306a36Sopenharmony_ci * solution to this problem is to run the destructor early, 205062306a36Sopenharmony_ci * after the packet is queued but before it's DMAd. A con is 205162306a36Sopenharmony_ci * that we lie to socket memory accounting, but the amount of 205262306a36Sopenharmony_ci * extra memory is reasonable (limited by the number of TX 205362306a36Sopenharmony_ci * descriptors), the packets do actually get freed quickly by 205462306a36Sopenharmony_ci * new packets almost always, and for protocols like TCP that 205562306a36Sopenharmony_ci * wait for acks to really free up the data the extra memory 205662306a36Sopenharmony_ci * is even less. On the positive side we run the destructors 205762306a36Sopenharmony_ci * on the sending CPU rather than on a potentially different 205862306a36Sopenharmony_ci * completing CPU, usually a good thing. 205962306a36Sopenharmony_ci * 206062306a36Sopenharmony_ci * Run the destructor before telling the DMA engine about the 206162306a36Sopenharmony_ci * packet to make sure it doesn't complete and get freed 206262306a36Sopenharmony_ci * prematurely. 206362306a36Sopenharmony_ci */ 206462306a36Sopenharmony_ci struct ulptx_sgl *sgl = (struct ulptx_sgl *)(cpl + 1); 206562306a36Sopenharmony_ci struct sge_txq *tq = &txq->q; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci /* If the Work Request header was an exact multiple of our TX 206862306a36Sopenharmony_ci * Descriptor length, then it's possible that the starting SGL 206962306a36Sopenharmony_ci * pointer lines up exactly with the end of our TX Descriptor 207062306a36Sopenharmony_ci * ring. If that's the case, wrap around to the beginning 207162306a36Sopenharmony_ci * here ... 207262306a36Sopenharmony_ci */ 207362306a36Sopenharmony_ci if (unlikely((void *)sgl == (void *)tq->stat)) { 207462306a36Sopenharmony_ci sgl = (void *)tq->desc; 207562306a36Sopenharmony_ci end = (void *)((void *)tq->desc + 207662306a36Sopenharmony_ci ((void *)end - (void *)tq->stat)); 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci cxgb4_write_sgl(skb, tq, sgl, end, 0, sgl_sdesc->addr); 208062306a36Sopenharmony_ci skb_orphan(skb); 208162306a36Sopenharmony_ci sgl_sdesc->skb = skb; 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci /* Advance our internal TX Queue state, tell the hardware about 208562306a36Sopenharmony_ci * the new TX descriptors and return success. 208662306a36Sopenharmony_ci */ 208762306a36Sopenharmony_ci txq_advance(&txq->q, ndesc); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci cxgb4_ring_tx_db(adapter, &txq->q, ndesc); 209062306a36Sopenharmony_ci return NETDEV_TX_OK; 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ciout_free: 209362306a36Sopenharmony_ci /* An error of some sort happened. Free the TX skb and tell the 209462306a36Sopenharmony_ci * OS that we've "dealt" with the packet ... 209562306a36Sopenharmony_ci */ 209662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 209762306a36Sopenharmony_ci return NETDEV_TX_OK; 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci/** 210162306a36Sopenharmony_ci * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs 210262306a36Sopenharmony_ci * @q: the SGE control Tx queue 210362306a36Sopenharmony_ci * 210462306a36Sopenharmony_ci * This is a variant of cxgb4_reclaim_completed_tx() that is used 210562306a36Sopenharmony_ci * for Tx queues that send only immediate data (presently just 210662306a36Sopenharmony_ci * the control queues) and thus do not have any sk_buffs to release. 210762306a36Sopenharmony_ci */ 210862306a36Sopenharmony_cistatic inline void reclaim_completed_tx_imm(struct sge_txq *q) 210962306a36Sopenharmony_ci{ 211062306a36Sopenharmony_ci int hw_cidx = ntohs(READ_ONCE(q->stat->cidx)); 211162306a36Sopenharmony_ci int reclaim = hw_cidx - q->cidx; 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci if (reclaim < 0) 211462306a36Sopenharmony_ci reclaim += q->size; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci q->in_use -= reclaim; 211762306a36Sopenharmony_ci q->cidx = hw_cidx; 211862306a36Sopenharmony_ci} 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_cistatic inline void eosw_txq_advance_index(u32 *idx, u32 n, u32 max) 212162306a36Sopenharmony_ci{ 212262306a36Sopenharmony_ci u32 val = *idx + n; 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci if (val >= max) 212562306a36Sopenharmony_ci val -= max; 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci *idx = val; 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_civoid cxgb4_eosw_txq_free_desc(struct adapter *adap, 213162306a36Sopenharmony_ci struct sge_eosw_txq *eosw_txq, u32 ndesc) 213262306a36Sopenharmony_ci{ 213362306a36Sopenharmony_ci struct tx_sw_desc *d; 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci d = &eosw_txq->desc[eosw_txq->last_cidx]; 213662306a36Sopenharmony_ci while (ndesc--) { 213762306a36Sopenharmony_ci if (d->skb) { 213862306a36Sopenharmony_ci if (d->addr[0]) { 213962306a36Sopenharmony_ci unmap_skb(adap->pdev_dev, d->skb, d->addr); 214062306a36Sopenharmony_ci memset(d->addr, 0, sizeof(d->addr)); 214162306a36Sopenharmony_ci } 214262306a36Sopenharmony_ci dev_consume_skb_any(d->skb); 214362306a36Sopenharmony_ci d->skb = NULL; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci eosw_txq_advance_index(&eosw_txq->last_cidx, 1, 214662306a36Sopenharmony_ci eosw_txq->ndesc); 214762306a36Sopenharmony_ci d = &eosw_txq->desc[eosw_txq->last_cidx]; 214862306a36Sopenharmony_ci } 214962306a36Sopenharmony_ci} 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_cistatic inline void eosw_txq_advance(struct sge_eosw_txq *eosw_txq, u32 n) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci eosw_txq_advance_index(&eosw_txq->pidx, n, eosw_txq->ndesc); 215462306a36Sopenharmony_ci eosw_txq->inuse += n; 215562306a36Sopenharmony_ci} 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_cistatic inline int eosw_txq_enqueue(struct sge_eosw_txq *eosw_txq, 215862306a36Sopenharmony_ci struct sk_buff *skb) 215962306a36Sopenharmony_ci{ 216062306a36Sopenharmony_ci if (eosw_txq->inuse == eosw_txq->ndesc) 216162306a36Sopenharmony_ci return -ENOMEM; 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci eosw_txq->desc[eosw_txq->pidx].skb = skb; 216462306a36Sopenharmony_ci return 0; 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_cistatic inline struct sk_buff *eosw_txq_peek(struct sge_eosw_txq *eosw_txq) 216862306a36Sopenharmony_ci{ 216962306a36Sopenharmony_ci return eosw_txq->desc[eosw_txq->last_pidx].skb; 217062306a36Sopenharmony_ci} 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_cistatic inline u8 ethofld_calc_tx_flits(struct adapter *adap, 217362306a36Sopenharmony_ci struct sk_buff *skb, u32 hdr_len) 217462306a36Sopenharmony_ci{ 217562306a36Sopenharmony_ci u8 flits, nsgl = 0; 217662306a36Sopenharmony_ci u32 wrlen; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci wrlen = sizeof(struct fw_eth_tx_eo_wr) + sizeof(struct cpl_tx_pkt_core); 217962306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size && 218062306a36Sopenharmony_ci !(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)) 218162306a36Sopenharmony_ci wrlen += sizeof(struct cpl_tx_pkt_lso_core); 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci wrlen += roundup(hdr_len, 16); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci /* Packet headers + WR + CPLs */ 218662306a36Sopenharmony_ci flits = DIV_ROUND_UP(wrlen, 8); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci if (skb_shinfo(skb)->nr_frags > 0) { 218962306a36Sopenharmony_ci if (skb_headlen(skb) - hdr_len) 219062306a36Sopenharmony_ci nsgl = sgl_len(skb_shinfo(skb)->nr_frags + 1); 219162306a36Sopenharmony_ci else 219262306a36Sopenharmony_ci nsgl = sgl_len(skb_shinfo(skb)->nr_frags); 219362306a36Sopenharmony_ci } else if (skb->len - hdr_len) { 219462306a36Sopenharmony_ci nsgl = sgl_len(1); 219562306a36Sopenharmony_ci } 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci return flits + nsgl; 219862306a36Sopenharmony_ci} 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_cistatic void *write_eo_wr(struct adapter *adap, struct sge_eosw_txq *eosw_txq, 220162306a36Sopenharmony_ci struct sk_buff *skb, struct fw_eth_tx_eo_wr *wr, 220262306a36Sopenharmony_ci u32 hdr_len, u32 wrlen) 220362306a36Sopenharmony_ci{ 220462306a36Sopenharmony_ci const struct skb_shared_info *ssi = skb_shinfo(skb); 220562306a36Sopenharmony_ci struct cpl_tx_pkt_core *cpl; 220662306a36Sopenharmony_ci u32 immd_len, wrlen16; 220762306a36Sopenharmony_ci bool compl = false; 220862306a36Sopenharmony_ci u8 ver, proto; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci ver = ip_hdr(skb)->version; 221162306a36Sopenharmony_ci proto = (ver == 6) ? ipv6_hdr(skb)->nexthdr : ip_hdr(skb)->protocol; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci wrlen16 = DIV_ROUND_UP(wrlen, 16); 221462306a36Sopenharmony_ci immd_len = sizeof(struct cpl_tx_pkt_core); 221562306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size && 221662306a36Sopenharmony_ci !(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)) 221762306a36Sopenharmony_ci immd_len += sizeof(struct cpl_tx_pkt_lso_core); 221862306a36Sopenharmony_ci immd_len += hdr_len; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci if (!eosw_txq->ncompl || 222162306a36Sopenharmony_ci (eosw_txq->last_compl + wrlen16) >= 222262306a36Sopenharmony_ci (adap->params.ofldq_wr_cred / 2)) { 222362306a36Sopenharmony_ci compl = true; 222462306a36Sopenharmony_ci eosw_txq->ncompl++; 222562306a36Sopenharmony_ci eosw_txq->last_compl = 0; 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_EO_WR) | 222962306a36Sopenharmony_ci FW_ETH_TX_EO_WR_IMMDLEN_V(immd_len) | 223062306a36Sopenharmony_ci FW_WR_COMPL_V(compl)); 223162306a36Sopenharmony_ci wr->equiq_to_len16 = cpu_to_be32(FW_WR_LEN16_V(wrlen16) | 223262306a36Sopenharmony_ci FW_WR_FLOWID_V(eosw_txq->hwtid)); 223362306a36Sopenharmony_ci wr->r3 = 0; 223462306a36Sopenharmony_ci if (proto == IPPROTO_UDP) { 223562306a36Sopenharmony_ci cpl = write_eo_udp_wr(skb, wr, hdr_len); 223662306a36Sopenharmony_ci } else { 223762306a36Sopenharmony_ci wr->u.tcpseg.type = FW_ETH_TX_EO_TYPE_TCPSEG; 223862306a36Sopenharmony_ci wr->u.tcpseg.ethlen = skb_network_offset(skb); 223962306a36Sopenharmony_ci wr->u.tcpseg.iplen = cpu_to_be16(skb_network_header_len(skb)); 224062306a36Sopenharmony_ci wr->u.tcpseg.tcplen = tcp_hdrlen(skb); 224162306a36Sopenharmony_ci wr->u.tcpseg.tsclk_tsoff = 0; 224262306a36Sopenharmony_ci wr->u.tcpseg.r4 = 0; 224362306a36Sopenharmony_ci wr->u.tcpseg.r5 = 0; 224462306a36Sopenharmony_ci wr->u.tcpseg.plen = cpu_to_be32(skb->len - hdr_len); 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci if (ssi->gso_size) { 224762306a36Sopenharmony_ci struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci wr->u.tcpseg.mss = cpu_to_be16(ssi->gso_size); 225062306a36Sopenharmony_ci cpl = write_tso_wr(adap, skb, lso); 225162306a36Sopenharmony_ci } else { 225262306a36Sopenharmony_ci wr->u.tcpseg.mss = cpu_to_be16(0xffff); 225362306a36Sopenharmony_ci cpl = (void *)(wr + 1); 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci } 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci eosw_txq->cred -= wrlen16; 225862306a36Sopenharmony_ci eosw_txq->last_compl += wrlen16; 225962306a36Sopenharmony_ci return cpl; 226062306a36Sopenharmony_ci} 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_cistatic int ethofld_hard_xmit(struct net_device *dev, 226362306a36Sopenharmony_ci struct sge_eosw_txq *eosw_txq) 226462306a36Sopenharmony_ci{ 226562306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 226662306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 226762306a36Sopenharmony_ci u32 wrlen, wrlen16, hdr_len, data_len; 226862306a36Sopenharmony_ci enum sge_eosw_state next_state; 226962306a36Sopenharmony_ci u64 cntrl, *start, *end, *sgl; 227062306a36Sopenharmony_ci struct sge_eohw_txq *eohw_txq; 227162306a36Sopenharmony_ci struct cpl_tx_pkt_core *cpl; 227262306a36Sopenharmony_ci struct fw_eth_tx_eo_wr *wr; 227362306a36Sopenharmony_ci bool skip_eotx_wr = false; 227462306a36Sopenharmony_ci struct tx_sw_desc *d; 227562306a36Sopenharmony_ci struct sk_buff *skb; 227662306a36Sopenharmony_ci int left, ret = 0; 227762306a36Sopenharmony_ci u8 flits, ndesc; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci eohw_txq = &adap->sge.eohw_txq[eosw_txq->hwqid]; 228062306a36Sopenharmony_ci spin_lock(&eohw_txq->lock); 228162306a36Sopenharmony_ci reclaim_completed_tx_imm(&eohw_txq->q); 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci d = &eosw_txq->desc[eosw_txq->last_pidx]; 228462306a36Sopenharmony_ci skb = d->skb; 228562306a36Sopenharmony_ci skb_tx_timestamp(skb); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci wr = (struct fw_eth_tx_eo_wr *)&eohw_txq->q.desc[eohw_txq->q.pidx]; 228862306a36Sopenharmony_ci if (unlikely(eosw_txq->state != CXGB4_EO_STATE_ACTIVE && 228962306a36Sopenharmony_ci eosw_txq->last_pidx == eosw_txq->flowc_idx)) { 229062306a36Sopenharmony_ci hdr_len = skb->len; 229162306a36Sopenharmony_ci data_len = 0; 229262306a36Sopenharmony_ci flits = DIV_ROUND_UP(hdr_len, 8); 229362306a36Sopenharmony_ci if (eosw_txq->state == CXGB4_EO_STATE_FLOWC_OPEN_SEND) 229462306a36Sopenharmony_ci next_state = CXGB4_EO_STATE_FLOWC_OPEN_REPLY; 229562306a36Sopenharmony_ci else 229662306a36Sopenharmony_ci next_state = CXGB4_EO_STATE_FLOWC_CLOSE_REPLY; 229762306a36Sopenharmony_ci skip_eotx_wr = true; 229862306a36Sopenharmony_ci } else { 229962306a36Sopenharmony_ci hdr_len = eth_get_headlen(dev, skb->data, skb_headlen(skb)); 230062306a36Sopenharmony_ci data_len = skb->len - hdr_len; 230162306a36Sopenharmony_ci flits = ethofld_calc_tx_flits(adap, skb, hdr_len); 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci ndesc = flits_to_desc(flits); 230462306a36Sopenharmony_ci wrlen = flits * 8; 230562306a36Sopenharmony_ci wrlen16 = DIV_ROUND_UP(wrlen, 16); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci left = txq_avail(&eohw_txq->q) - ndesc; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci /* If there are no descriptors left in hardware queues or no 231062306a36Sopenharmony_ci * CPL credits left in software queues, then wait for them 231162306a36Sopenharmony_ci * to come back and retry again. Note that we always request 231262306a36Sopenharmony_ci * for credits update via interrupt for every half credits 231362306a36Sopenharmony_ci * consumed. So, the interrupt will eventually restore the 231462306a36Sopenharmony_ci * credits and invoke the Tx path again. 231562306a36Sopenharmony_ci */ 231662306a36Sopenharmony_ci if (unlikely(left < 0 || wrlen16 > eosw_txq->cred)) { 231762306a36Sopenharmony_ci ret = -ENOMEM; 231862306a36Sopenharmony_ci goto out_unlock; 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci if (unlikely(skip_eotx_wr)) { 232262306a36Sopenharmony_ci start = (u64 *)wr; 232362306a36Sopenharmony_ci eosw_txq->state = next_state; 232462306a36Sopenharmony_ci eosw_txq->cred -= wrlen16; 232562306a36Sopenharmony_ci eosw_txq->ncompl++; 232662306a36Sopenharmony_ci eosw_txq->last_compl = 0; 232762306a36Sopenharmony_ci goto write_wr_headers; 232862306a36Sopenharmony_ci } 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci cpl = write_eo_wr(adap, eosw_txq, skb, wr, hdr_len, wrlen); 233162306a36Sopenharmony_ci cntrl = hwcsum(adap->params.chip, skb); 233262306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) 233362306a36Sopenharmony_ci cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb)); 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE_V(CPL_TX_PKT_XT) | 233662306a36Sopenharmony_ci TXPKT_INTF_V(pi->tx_chan) | 233762306a36Sopenharmony_ci TXPKT_PF_V(adap->pf)); 233862306a36Sopenharmony_ci cpl->pack = 0; 233962306a36Sopenharmony_ci cpl->len = cpu_to_be16(skb->len); 234062306a36Sopenharmony_ci cpl->ctrl1 = cpu_to_be64(cntrl); 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci start = (u64 *)(cpl + 1); 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ciwrite_wr_headers: 234562306a36Sopenharmony_ci sgl = (u64 *)inline_tx_skb_header(skb, &eohw_txq->q, (void *)start, 234662306a36Sopenharmony_ci hdr_len); 234762306a36Sopenharmony_ci if (data_len) { 234862306a36Sopenharmony_ci ret = cxgb4_map_skb(adap->pdev_dev, skb, d->addr); 234962306a36Sopenharmony_ci if (unlikely(ret)) { 235062306a36Sopenharmony_ci memset(d->addr, 0, sizeof(d->addr)); 235162306a36Sopenharmony_ci eohw_txq->mapping_err++; 235262306a36Sopenharmony_ci goto out_unlock; 235362306a36Sopenharmony_ci } 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci end = (u64 *)wr + flits; 235662306a36Sopenharmony_ci if (unlikely(start > sgl)) { 235762306a36Sopenharmony_ci left = (u8 *)end - (u8 *)eohw_txq->q.stat; 235862306a36Sopenharmony_ci end = (void *)eohw_txq->q.desc + left; 235962306a36Sopenharmony_ci } 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci if (unlikely((u8 *)sgl >= (u8 *)eohw_txq->q.stat)) { 236262306a36Sopenharmony_ci /* If current position is already at the end of the 236362306a36Sopenharmony_ci * txq, reset the current to point to start of the queue 236462306a36Sopenharmony_ci * and update the end ptr as well. 236562306a36Sopenharmony_ci */ 236662306a36Sopenharmony_ci left = (u8 *)end - (u8 *)eohw_txq->q.stat; 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci end = (void *)eohw_txq->q.desc + left; 236962306a36Sopenharmony_ci sgl = (void *)eohw_txq->q.desc; 237062306a36Sopenharmony_ci } 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci cxgb4_write_sgl(skb, &eohw_txq->q, (void *)sgl, end, hdr_len, 237362306a36Sopenharmony_ci d->addr); 237462306a36Sopenharmony_ci } 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size) { 237762306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 237862306a36Sopenharmony_ci eohw_txq->uso++; 237962306a36Sopenharmony_ci else 238062306a36Sopenharmony_ci eohw_txq->tso++; 238162306a36Sopenharmony_ci eohw_txq->tx_cso += skb_shinfo(skb)->gso_segs; 238262306a36Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 238362306a36Sopenharmony_ci eohw_txq->tx_cso++; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) 238762306a36Sopenharmony_ci eohw_txq->vlan_ins++; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci txq_advance(&eohw_txq->q, ndesc); 239062306a36Sopenharmony_ci cxgb4_ring_tx_db(adap, &eohw_txq->q, ndesc); 239162306a36Sopenharmony_ci eosw_txq_advance_index(&eosw_txq->last_pidx, 1, eosw_txq->ndesc); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ciout_unlock: 239462306a36Sopenharmony_ci spin_unlock(&eohw_txq->lock); 239562306a36Sopenharmony_ci return ret; 239662306a36Sopenharmony_ci} 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_cistatic void ethofld_xmit(struct net_device *dev, struct sge_eosw_txq *eosw_txq) 239962306a36Sopenharmony_ci{ 240062306a36Sopenharmony_ci struct sk_buff *skb; 240162306a36Sopenharmony_ci int pktcount, ret; 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci switch (eosw_txq->state) { 240462306a36Sopenharmony_ci case CXGB4_EO_STATE_ACTIVE: 240562306a36Sopenharmony_ci case CXGB4_EO_STATE_FLOWC_OPEN_SEND: 240662306a36Sopenharmony_ci case CXGB4_EO_STATE_FLOWC_CLOSE_SEND: 240762306a36Sopenharmony_ci pktcount = eosw_txq->pidx - eosw_txq->last_pidx; 240862306a36Sopenharmony_ci if (pktcount < 0) 240962306a36Sopenharmony_ci pktcount += eosw_txq->ndesc; 241062306a36Sopenharmony_ci break; 241162306a36Sopenharmony_ci case CXGB4_EO_STATE_FLOWC_OPEN_REPLY: 241262306a36Sopenharmony_ci case CXGB4_EO_STATE_FLOWC_CLOSE_REPLY: 241362306a36Sopenharmony_ci case CXGB4_EO_STATE_CLOSED: 241462306a36Sopenharmony_ci default: 241562306a36Sopenharmony_ci return; 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci while (pktcount--) { 241962306a36Sopenharmony_ci skb = eosw_txq_peek(eosw_txq); 242062306a36Sopenharmony_ci if (!skb) { 242162306a36Sopenharmony_ci eosw_txq_advance_index(&eosw_txq->last_pidx, 1, 242262306a36Sopenharmony_ci eosw_txq->ndesc); 242362306a36Sopenharmony_ci continue; 242462306a36Sopenharmony_ci } 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci ret = ethofld_hard_xmit(dev, eosw_txq); 242762306a36Sopenharmony_ci if (ret) 242862306a36Sopenharmony_ci break; 242962306a36Sopenharmony_ci } 243062306a36Sopenharmony_ci} 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_cistatic netdev_tx_t cxgb4_ethofld_xmit(struct sk_buff *skb, 243362306a36Sopenharmony_ci struct net_device *dev) 243462306a36Sopenharmony_ci{ 243562306a36Sopenharmony_ci struct cxgb4_tc_port_mqprio *tc_port_mqprio; 243662306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 243762306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 243862306a36Sopenharmony_ci struct sge_eosw_txq *eosw_txq; 243962306a36Sopenharmony_ci u32 qid; 244062306a36Sopenharmony_ci int ret; 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci ret = cxgb4_validate_skb(skb, dev, ETH_HLEN); 244362306a36Sopenharmony_ci if (ret) 244462306a36Sopenharmony_ci goto out_free; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; 244762306a36Sopenharmony_ci qid = skb_get_queue_mapping(skb) - pi->nqsets; 244862306a36Sopenharmony_ci eosw_txq = &tc_port_mqprio->eosw_txq[qid]; 244962306a36Sopenharmony_ci spin_lock_bh(&eosw_txq->lock); 245062306a36Sopenharmony_ci if (eosw_txq->state != CXGB4_EO_STATE_ACTIVE) 245162306a36Sopenharmony_ci goto out_unlock; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci ret = eosw_txq_enqueue(eosw_txq, skb); 245462306a36Sopenharmony_ci if (ret) 245562306a36Sopenharmony_ci goto out_unlock; 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci /* SKB is queued for processing until credits are available. 245862306a36Sopenharmony_ci * So, call the destructor now and we'll free the skb later 245962306a36Sopenharmony_ci * after it has been successfully transmitted. 246062306a36Sopenharmony_ci */ 246162306a36Sopenharmony_ci skb_orphan(skb); 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci eosw_txq_advance(eosw_txq, 1); 246462306a36Sopenharmony_ci ethofld_xmit(dev, eosw_txq); 246562306a36Sopenharmony_ci spin_unlock_bh(&eosw_txq->lock); 246662306a36Sopenharmony_ci return NETDEV_TX_OK; 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ciout_unlock: 246962306a36Sopenharmony_ci spin_unlock_bh(&eosw_txq->lock); 247062306a36Sopenharmony_ciout_free: 247162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 247262306a36Sopenharmony_ci return NETDEV_TX_OK; 247362306a36Sopenharmony_ci} 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_cinetdev_tx_t t4_start_xmit(struct sk_buff *skb, struct net_device *dev) 247662306a36Sopenharmony_ci{ 247762306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 247862306a36Sopenharmony_ci u16 qid = skb_get_queue_mapping(skb); 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci if (unlikely(pi->eth_flags & PRIV_FLAG_PORT_TX_VM)) 248162306a36Sopenharmony_ci return cxgb4_vf_eth_xmit(skb, dev); 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci if (unlikely(qid >= pi->nqsets)) 248462306a36Sopenharmony_ci return cxgb4_ethofld_xmit(skb, dev); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci if (is_ptp_enabled(skb, dev)) { 248762306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 248862306a36Sopenharmony_ci netdev_tx_t ret; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci spin_lock(&adap->ptp_lock); 249162306a36Sopenharmony_ci ret = cxgb4_eth_xmit(skb, dev); 249262306a36Sopenharmony_ci spin_unlock(&adap->ptp_lock); 249362306a36Sopenharmony_ci return ret; 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci return cxgb4_eth_xmit(skb, dev); 249762306a36Sopenharmony_ci} 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_cistatic void eosw_txq_flush_pending_skbs(struct sge_eosw_txq *eosw_txq) 250062306a36Sopenharmony_ci{ 250162306a36Sopenharmony_ci int pktcount = eosw_txq->pidx - eosw_txq->last_pidx; 250262306a36Sopenharmony_ci int pidx = eosw_txq->pidx; 250362306a36Sopenharmony_ci struct sk_buff *skb; 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci if (!pktcount) 250662306a36Sopenharmony_ci return; 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci if (pktcount < 0) 250962306a36Sopenharmony_ci pktcount += eosw_txq->ndesc; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci while (pktcount--) { 251262306a36Sopenharmony_ci pidx--; 251362306a36Sopenharmony_ci if (pidx < 0) 251462306a36Sopenharmony_ci pidx += eosw_txq->ndesc; 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci skb = eosw_txq->desc[pidx].skb; 251762306a36Sopenharmony_ci if (skb) { 251862306a36Sopenharmony_ci dev_consume_skb_any(skb); 251962306a36Sopenharmony_ci eosw_txq->desc[pidx].skb = NULL; 252062306a36Sopenharmony_ci eosw_txq->inuse--; 252162306a36Sopenharmony_ci } 252262306a36Sopenharmony_ci } 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci eosw_txq->pidx = eosw_txq->last_pidx + 1; 252562306a36Sopenharmony_ci} 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci/** 252862306a36Sopenharmony_ci * cxgb4_ethofld_send_flowc - Send ETHOFLD flowc request to bind eotid to tc. 252962306a36Sopenharmony_ci * @dev: netdevice 253062306a36Sopenharmony_ci * @eotid: ETHOFLD tid to bind/unbind 253162306a36Sopenharmony_ci * @tc: traffic class. If set to FW_SCHED_CLS_NONE, then unbinds the @eotid 253262306a36Sopenharmony_ci * 253362306a36Sopenharmony_ci * Send a FLOWC work request to bind an ETHOFLD TID to a traffic class. 253462306a36Sopenharmony_ci * If @tc is set to FW_SCHED_CLS_NONE, then the @eotid is unbound from 253562306a36Sopenharmony_ci * a traffic class. 253662306a36Sopenharmony_ci */ 253762306a36Sopenharmony_ciint cxgb4_ethofld_send_flowc(struct net_device *dev, u32 eotid, u32 tc) 253862306a36Sopenharmony_ci{ 253962306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 254062306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 254162306a36Sopenharmony_ci enum sge_eosw_state next_state; 254262306a36Sopenharmony_ci struct sge_eosw_txq *eosw_txq; 254362306a36Sopenharmony_ci u32 len, len16, nparams = 6; 254462306a36Sopenharmony_ci struct fw_flowc_wr *flowc; 254562306a36Sopenharmony_ci struct eotid_entry *entry; 254662306a36Sopenharmony_ci struct sge_ofld_rxq *rxq; 254762306a36Sopenharmony_ci struct sk_buff *skb; 254862306a36Sopenharmony_ci int ret = 0; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci len = struct_size(flowc, mnemval, nparams); 255162306a36Sopenharmony_ci len16 = DIV_ROUND_UP(len, 16); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci entry = cxgb4_lookup_eotid(&adap->tids, eotid); 255462306a36Sopenharmony_ci if (!entry) 255562306a36Sopenharmony_ci return -ENOMEM; 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci eosw_txq = (struct sge_eosw_txq *)entry->data; 255862306a36Sopenharmony_ci if (!eosw_txq) 255962306a36Sopenharmony_ci return -ENOMEM; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci if (!(adap->flags & CXGB4_FW_OK)) { 256262306a36Sopenharmony_ci /* Don't stall caller when access to FW is lost */ 256362306a36Sopenharmony_ci complete(&eosw_txq->completion); 256462306a36Sopenharmony_ci return -EIO; 256562306a36Sopenharmony_ci } 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci skb = alloc_skb(len, GFP_KERNEL); 256862306a36Sopenharmony_ci if (!skb) 256962306a36Sopenharmony_ci return -ENOMEM; 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci spin_lock_bh(&eosw_txq->lock); 257262306a36Sopenharmony_ci if (tc != FW_SCHED_CLS_NONE) { 257362306a36Sopenharmony_ci if (eosw_txq->state != CXGB4_EO_STATE_CLOSED) 257462306a36Sopenharmony_ci goto out_free_skb; 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci next_state = CXGB4_EO_STATE_FLOWC_OPEN_SEND; 257762306a36Sopenharmony_ci } else { 257862306a36Sopenharmony_ci if (eosw_txq->state != CXGB4_EO_STATE_ACTIVE) 257962306a36Sopenharmony_ci goto out_free_skb; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci next_state = CXGB4_EO_STATE_FLOWC_CLOSE_SEND; 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci flowc = __skb_put(skb, len); 258562306a36Sopenharmony_ci memset(flowc, 0, len); 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci rxq = &adap->sge.eohw_rxq[eosw_txq->hwqid]; 258862306a36Sopenharmony_ci flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(len16) | 258962306a36Sopenharmony_ci FW_WR_FLOWID_V(eosw_txq->hwtid)); 259062306a36Sopenharmony_ci flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) | 259162306a36Sopenharmony_ci FW_FLOWC_WR_NPARAMS_V(nparams) | 259262306a36Sopenharmony_ci FW_WR_COMPL_V(1)); 259362306a36Sopenharmony_ci flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN; 259462306a36Sopenharmony_ci flowc->mnemval[0].val = cpu_to_be32(FW_PFVF_CMD_PFN_V(adap->pf)); 259562306a36Sopenharmony_ci flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH; 259662306a36Sopenharmony_ci flowc->mnemval[1].val = cpu_to_be32(pi->tx_chan); 259762306a36Sopenharmony_ci flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT; 259862306a36Sopenharmony_ci flowc->mnemval[2].val = cpu_to_be32(pi->tx_chan); 259962306a36Sopenharmony_ci flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID; 260062306a36Sopenharmony_ci flowc->mnemval[3].val = cpu_to_be32(rxq->rspq.abs_id); 260162306a36Sopenharmony_ci flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SCHEDCLASS; 260262306a36Sopenharmony_ci flowc->mnemval[4].val = cpu_to_be32(tc); 260362306a36Sopenharmony_ci flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_EOSTATE; 260462306a36Sopenharmony_ci flowc->mnemval[5].val = cpu_to_be32(tc == FW_SCHED_CLS_NONE ? 260562306a36Sopenharmony_ci FW_FLOWC_MNEM_EOSTATE_CLOSING : 260662306a36Sopenharmony_ci FW_FLOWC_MNEM_EOSTATE_ESTABLISHED); 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci /* Free up any pending skbs to ensure there's room for 260962306a36Sopenharmony_ci * termination FLOWC. 261062306a36Sopenharmony_ci */ 261162306a36Sopenharmony_ci if (tc == FW_SCHED_CLS_NONE) 261262306a36Sopenharmony_ci eosw_txq_flush_pending_skbs(eosw_txq); 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci ret = eosw_txq_enqueue(eosw_txq, skb); 261562306a36Sopenharmony_ci if (ret) 261662306a36Sopenharmony_ci goto out_free_skb; 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci eosw_txq->state = next_state; 261962306a36Sopenharmony_ci eosw_txq->flowc_idx = eosw_txq->pidx; 262062306a36Sopenharmony_ci eosw_txq_advance(eosw_txq, 1); 262162306a36Sopenharmony_ci ethofld_xmit(dev, eosw_txq); 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci spin_unlock_bh(&eosw_txq->lock); 262462306a36Sopenharmony_ci return 0; 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ciout_free_skb: 262762306a36Sopenharmony_ci dev_consume_skb_any(skb); 262862306a36Sopenharmony_ci spin_unlock_bh(&eosw_txq->lock); 262962306a36Sopenharmony_ci return ret; 263062306a36Sopenharmony_ci} 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci/** 263362306a36Sopenharmony_ci * is_imm - check whether a packet can be sent as immediate data 263462306a36Sopenharmony_ci * @skb: the packet 263562306a36Sopenharmony_ci * 263662306a36Sopenharmony_ci * Returns true if a packet can be sent as a WR with immediate data. 263762306a36Sopenharmony_ci */ 263862306a36Sopenharmony_cistatic inline int is_imm(const struct sk_buff *skb) 263962306a36Sopenharmony_ci{ 264062306a36Sopenharmony_ci return skb->len <= MAX_CTRL_WR_LEN; 264162306a36Sopenharmony_ci} 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci/** 264462306a36Sopenharmony_ci * ctrlq_check_stop - check if a control queue is full and should stop 264562306a36Sopenharmony_ci * @q: the queue 264662306a36Sopenharmony_ci * @wr: most recent WR written to the queue 264762306a36Sopenharmony_ci * 264862306a36Sopenharmony_ci * Check if a control queue has become full and should be stopped. 264962306a36Sopenharmony_ci * We clean up control queue descriptors very lazily, only when we are out. 265062306a36Sopenharmony_ci * If the queue is still full after reclaiming any completed descriptors 265162306a36Sopenharmony_ci * we suspend it and have the last WR wake it up. 265262306a36Sopenharmony_ci */ 265362306a36Sopenharmony_cistatic void ctrlq_check_stop(struct sge_ctrl_txq *q, struct fw_wr_hdr *wr) 265462306a36Sopenharmony_ci{ 265562306a36Sopenharmony_ci reclaim_completed_tx_imm(&q->q); 265662306a36Sopenharmony_ci if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) { 265762306a36Sopenharmony_ci wr->lo |= htonl(FW_WR_EQUEQ_F | FW_WR_EQUIQ_F); 265862306a36Sopenharmony_ci q->q.stops++; 265962306a36Sopenharmony_ci q->full = 1; 266062306a36Sopenharmony_ci } 266162306a36Sopenharmony_ci} 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci#define CXGB4_SELFTEST_LB_STR "CHELSIO_SELFTEST" 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ciint cxgb4_selftest_lb_pkt(struct net_device *netdev) 266662306a36Sopenharmony_ci{ 266762306a36Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 266862306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 266962306a36Sopenharmony_ci struct cxgb4_ethtool_lb_test *lb; 267062306a36Sopenharmony_ci int ret, i = 0, pkt_len, credits; 267162306a36Sopenharmony_ci struct fw_eth_tx_pkt_wr *wr; 267262306a36Sopenharmony_ci struct cpl_tx_pkt_core *cpl; 267362306a36Sopenharmony_ci u32 ctrl0, ndesc, flits; 267462306a36Sopenharmony_ci struct sge_eth_txq *q; 267562306a36Sopenharmony_ci u8 *sgl; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci pkt_len = ETH_HLEN + sizeof(CXGB4_SELFTEST_LB_STR); 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci flits = DIV_ROUND_UP(pkt_len + sizeof(*cpl) + sizeof(*wr), 268062306a36Sopenharmony_ci sizeof(__be64)); 268162306a36Sopenharmony_ci ndesc = flits_to_desc(flits); 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci lb = &pi->ethtool_lb; 268462306a36Sopenharmony_ci lb->loopback = 1; 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci q = &adap->sge.ethtxq[pi->first_qset]; 268762306a36Sopenharmony_ci __netif_tx_lock(q->txq, smp_processor_id()); 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci reclaim_completed_tx(adap, &q->q, -1, true); 269062306a36Sopenharmony_ci credits = txq_avail(&q->q) - ndesc; 269162306a36Sopenharmony_ci if (unlikely(credits < 0)) { 269262306a36Sopenharmony_ci __netif_tx_unlock(q->txq); 269362306a36Sopenharmony_ci return -ENOMEM; 269462306a36Sopenharmony_ci } 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci wr = (void *)&q->q.desc[q->q.pidx]; 269762306a36Sopenharmony_ci memset(wr, 0, sizeof(struct tx_desc)); 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) | 270062306a36Sopenharmony_ci FW_WR_IMMDLEN_V(pkt_len + 270162306a36Sopenharmony_ci sizeof(*cpl))); 270262306a36Sopenharmony_ci wr->equiq_to_len16 = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2))); 270362306a36Sopenharmony_ci wr->r3 = cpu_to_be64(0); 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci cpl = (void *)(wr + 1); 270662306a36Sopenharmony_ci sgl = (u8 *)(cpl + 1); 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci ctrl0 = TXPKT_OPCODE_V(CPL_TX_PKT_XT) | TXPKT_PF_V(adap->pf) | 270962306a36Sopenharmony_ci TXPKT_INTF_V(pi->tx_chan + 4); 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci cpl->ctrl0 = htonl(ctrl0); 271262306a36Sopenharmony_ci cpl->pack = htons(0); 271362306a36Sopenharmony_ci cpl->len = htons(pkt_len); 271462306a36Sopenharmony_ci cpl->ctrl1 = cpu_to_be64(TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F); 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci eth_broadcast_addr(sgl); 271762306a36Sopenharmony_ci i += ETH_ALEN; 271862306a36Sopenharmony_ci ether_addr_copy(&sgl[i], netdev->dev_addr); 271962306a36Sopenharmony_ci i += ETH_ALEN; 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci snprintf(&sgl[i], sizeof(CXGB4_SELFTEST_LB_STR), "%s", 272262306a36Sopenharmony_ci CXGB4_SELFTEST_LB_STR); 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci init_completion(&lb->completion); 272562306a36Sopenharmony_ci txq_advance(&q->q, ndesc); 272662306a36Sopenharmony_ci cxgb4_ring_tx_db(adap, &q->q, ndesc); 272762306a36Sopenharmony_ci __netif_tx_unlock(q->txq); 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci /* wait for the pkt to return */ 273062306a36Sopenharmony_ci ret = wait_for_completion_timeout(&lb->completion, 10 * HZ); 273162306a36Sopenharmony_ci if (!ret) 273262306a36Sopenharmony_ci ret = -ETIMEDOUT; 273362306a36Sopenharmony_ci else 273462306a36Sopenharmony_ci ret = lb->result; 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci lb->loopback = 0; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci return ret; 273962306a36Sopenharmony_ci} 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci/** 274262306a36Sopenharmony_ci * ctrl_xmit - send a packet through an SGE control Tx queue 274362306a36Sopenharmony_ci * @q: the control queue 274462306a36Sopenharmony_ci * @skb: the packet 274562306a36Sopenharmony_ci * 274662306a36Sopenharmony_ci * Send a packet through an SGE control Tx queue. Packets sent through 274762306a36Sopenharmony_ci * a control queue must fit entirely as immediate data. 274862306a36Sopenharmony_ci */ 274962306a36Sopenharmony_cistatic int ctrl_xmit(struct sge_ctrl_txq *q, struct sk_buff *skb) 275062306a36Sopenharmony_ci{ 275162306a36Sopenharmony_ci unsigned int ndesc; 275262306a36Sopenharmony_ci struct fw_wr_hdr *wr; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci if (unlikely(!is_imm(skb))) { 275562306a36Sopenharmony_ci WARN_ON(1); 275662306a36Sopenharmony_ci dev_kfree_skb(skb); 275762306a36Sopenharmony_ci return NET_XMIT_DROP; 275862306a36Sopenharmony_ci } 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci ndesc = DIV_ROUND_UP(skb->len, sizeof(struct tx_desc)); 276162306a36Sopenharmony_ci spin_lock(&q->sendq.lock); 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci if (unlikely(q->full)) { 276462306a36Sopenharmony_ci skb->priority = ndesc; /* save for restart */ 276562306a36Sopenharmony_ci __skb_queue_tail(&q->sendq, skb); 276662306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 276762306a36Sopenharmony_ci return NET_XMIT_CN; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx]; 277162306a36Sopenharmony_ci cxgb4_inline_tx_skb(skb, &q->q, wr); 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci txq_advance(&q->q, ndesc); 277462306a36Sopenharmony_ci if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) 277562306a36Sopenharmony_ci ctrlq_check_stop(q, wr); 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci cxgb4_ring_tx_db(q->adap, &q->q, ndesc); 277862306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci kfree_skb(skb); 278162306a36Sopenharmony_ci return NET_XMIT_SUCCESS; 278262306a36Sopenharmony_ci} 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci/** 278562306a36Sopenharmony_ci * restart_ctrlq - restart a suspended control queue 278662306a36Sopenharmony_ci * @t: pointer to the tasklet associated with this handler 278762306a36Sopenharmony_ci * 278862306a36Sopenharmony_ci * Resumes transmission on a suspended Tx control queue. 278962306a36Sopenharmony_ci */ 279062306a36Sopenharmony_cistatic void restart_ctrlq(struct tasklet_struct *t) 279162306a36Sopenharmony_ci{ 279262306a36Sopenharmony_ci struct sk_buff *skb; 279362306a36Sopenharmony_ci unsigned int written = 0; 279462306a36Sopenharmony_ci struct sge_ctrl_txq *q = from_tasklet(q, t, qresume_tsk); 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci spin_lock(&q->sendq.lock); 279762306a36Sopenharmony_ci reclaim_completed_tx_imm(&q->q); 279862306a36Sopenharmony_ci BUG_ON(txq_avail(&q->q) < TXQ_STOP_THRES); /* q should be empty */ 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci while ((skb = __skb_dequeue(&q->sendq)) != NULL) { 280162306a36Sopenharmony_ci struct fw_wr_hdr *wr; 280262306a36Sopenharmony_ci unsigned int ndesc = skb->priority; /* previously saved */ 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci written += ndesc; 280562306a36Sopenharmony_ci /* Write descriptors and free skbs outside the lock to limit 280662306a36Sopenharmony_ci * wait times. q->full is still set so new skbs will be queued. 280762306a36Sopenharmony_ci */ 280862306a36Sopenharmony_ci wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx]; 280962306a36Sopenharmony_ci txq_advance(&q->q, ndesc); 281062306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci cxgb4_inline_tx_skb(skb, &q->q, wr); 281362306a36Sopenharmony_ci kfree_skb(skb); 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) { 281662306a36Sopenharmony_ci unsigned long old = q->q.stops; 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci ctrlq_check_stop(q, wr); 281962306a36Sopenharmony_ci if (q->q.stops != old) { /* suspended anew */ 282062306a36Sopenharmony_ci spin_lock(&q->sendq.lock); 282162306a36Sopenharmony_ci goto ringdb; 282262306a36Sopenharmony_ci } 282362306a36Sopenharmony_ci } 282462306a36Sopenharmony_ci if (written > 16) { 282562306a36Sopenharmony_ci cxgb4_ring_tx_db(q->adap, &q->q, written); 282662306a36Sopenharmony_ci written = 0; 282762306a36Sopenharmony_ci } 282862306a36Sopenharmony_ci spin_lock(&q->sendq.lock); 282962306a36Sopenharmony_ci } 283062306a36Sopenharmony_ci q->full = 0; 283162306a36Sopenharmony_ciringdb: 283262306a36Sopenharmony_ci if (written) 283362306a36Sopenharmony_ci cxgb4_ring_tx_db(q->adap, &q->q, written); 283462306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 283562306a36Sopenharmony_ci} 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci/** 283862306a36Sopenharmony_ci * t4_mgmt_tx - send a management message 283962306a36Sopenharmony_ci * @adap: the adapter 284062306a36Sopenharmony_ci * @skb: the packet containing the management message 284162306a36Sopenharmony_ci * 284262306a36Sopenharmony_ci * Send a management message through control queue 0. 284362306a36Sopenharmony_ci */ 284462306a36Sopenharmony_ciint t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb) 284562306a36Sopenharmony_ci{ 284662306a36Sopenharmony_ci int ret; 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci local_bh_disable(); 284962306a36Sopenharmony_ci ret = ctrl_xmit(&adap->sge.ctrlq[0], skb); 285062306a36Sopenharmony_ci local_bh_enable(); 285162306a36Sopenharmony_ci return ret; 285262306a36Sopenharmony_ci} 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci/** 285562306a36Sopenharmony_ci * is_ofld_imm - check whether a packet can be sent as immediate data 285662306a36Sopenharmony_ci * @skb: the packet 285762306a36Sopenharmony_ci * 285862306a36Sopenharmony_ci * Returns true if a packet can be sent as an offload WR with immediate 285962306a36Sopenharmony_ci * data. 286062306a36Sopenharmony_ci * FW_OFLD_TX_DATA_WR limits the payload to 255 bytes due to 8-bit field. 286162306a36Sopenharmony_ci * However, FW_ULPTX_WR commands have a 256 byte immediate only 286262306a36Sopenharmony_ci * payload limit. 286362306a36Sopenharmony_ci */ 286462306a36Sopenharmony_cistatic inline int is_ofld_imm(const struct sk_buff *skb) 286562306a36Sopenharmony_ci{ 286662306a36Sopenharmony_ci struct work_request_hdr *req = (struct work_request_hdr *)skb->data; 286762306a36Sopenharmony_ci unsigned long opcode = FW_WR_OP_G(ntohl(req->wr_hi)); 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci if (unlikely(opcode == FW_ULPTX_WR)) 287062306a36Sopenharmony_ci return skb->len <= MAX_IMM_ULPTX_WR_LEN; 287162306a36Sopenharmony_ci else if (opcode == FW_CRYPTO_LOOKASIDE_WR) 287262306a36Sopenharmony_ci return skb->len <= SGE_MAX_WR_LEN; 287362306a36Sopenharmony_ci else 287462306a36Sopenharmony_ci return skb->len <= MAX_IMM_OFLD_TX_DATA_WR_LEN; 287562306a36Sopenharmony_ci} 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci/** 287862306a36Sopenharmony_ci * calc_tx_flits_ofld - calculate # of flits for an offload packet 287962306a36Sopenharmony_ci * @skb: the packet 288062306a36Sopenharmony_ci * 288162306a36Sopenharmony_ci * Returns the number of flits needed for the given offload packet. 288262306a36Sopenharmony_ci * These packets are already fully constructed and no additional headers 288362306a36Sopenharmony_ci * will be added. 288462306a36Sopenharmony_ci */ 288562306a36Sopenharmony_cistatic inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) 288662306a36Sopenharmony_ci{ 288762306a36Sopenharmony_ci unsigned int flits, cnt; 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci if (is_ofld_imm(skb)) 289062306a36Sopenharmony_ci return DIV_ROUND_UP(skb->len, 8); 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci flits = skb_transport_offset(skb) / 8U; /* headers */ 289362306a36Sopenharmony_ci cnt = skb_shinfo(skb)->nr_frags; 289462306a36Sopenharmony_ci if (skb_tail_pointer(skb) != skb_transport_header(skb)) 289562306a36Sopenharmony_ci cnt++; 289662306a36Sopenharmony_ci return flits + sgl_len(cnt); 289762306a36Sopenharmony_ci} 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci/** 290062306a36Sopenharmony_ci * txq_stop_maperr - stop a Tx queue due to I/O MMU exhaustion 290162306a36Sopenharmony_ci * @q: the queue to stop 290262306a36Sopenharmony_ci * 290362306a36Sopenharmony_ci * Mark a Tx queue stopped due to I/O MMU exhaustion and resulting 290462306a36Sopenharmony_ci * inability to map packets. A periodic timer attempts to restart 290562306a36Sopenharmony_ci * queues so marked. 290662306a36Sopenharmony_ci */ 290762306a36Sopenharmony_cistatic void txq_stop_maperr(struct sge_uld_txq *q) 290862306a36Sopenharmony_ci{ 290962306a36Sopenharmony_ci q->mapping_err++; 291062306a36Sopenharmony_ci q->q.stops++; 291162306a36Sopenharmony_ci set_bit(q->q.cntxt_id - q->adap->sge.egr_start, 291262306a36Sopenharmony_ci q->adap->sge.txq_maperr); 291362306a36Sopenharmony_ci} 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci/** 291662306a36Sopenharmony_ci * ofldtxq_stop - stop an offload Tx queue that has become full 291762306a36Sopenharmony_ci * @q: the queue to stop 291862306a36Sopenharmony_ci * @wr: the Work Request causing the queue to become full 291962306a36Sopenharmony_ci * 292062306a36Sopenharmony_ci * Stops an offload Tx queue that has become full and modifies the packet 292162306a36Sopenharmony_ci * being written to request a wakeup. 292262306a36Sopenharmony_ci */ 292362306a36Sopenharmony_cistatic void ofldtxq_stop(struct sge_uld_txq *q, struct fw_wr_hdr *wr) 292462306a36Sopenharmony_ci{ 292562306a36Sopenharmony_ci wr->lo |= htonl(FW_WR_EQUEQ_F | FW_WR_EQUIQ_F); 292662306a36Sopenharmony_ci q->q.stops++; 292762306a36Sopenharmony_ci q->full = 1; 292862306a36Sopenharmony_ci} 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci/** 293162306a36Sopenharmony_ci * service_ofldq - service/restart a suspended offload queue 293262306a36Sopenharmony_ci * @q: the offload queue 293362306a36Sopenharmony_ci * 293462306a36Sopenharmony_ci * Services an offload Tx queue by moving packets from its Pending Send 293562306a36Sopenharmony_ci * Queue to the Hardware TX ring. The function starts and ends with the 293662306a36Sopenharmony_ci * Send Queue locked, but drops the lock while putting the skb at the 293762306a36Sopenharmony_ci * head of the Send Queue onto the Hardware TX Ring. Dropping the lock 293862306a36Sopenharmony_ci * allows more skbs to be added to the Send Queue by other threads. 293962306a36Sopenharmony_ci * The packet being processed at the head of the Pending Send Queue is 294062306a36Sopenharmony_ci * left on the queue in case we experience DMA Mapping errors, etc. 294162306a36Sopenharmony_ci * and need to give up and restart later. 294262306a36Sopenharmony_ci * 294362306a36Sopenharmony_ci * service_ofldq() can be thought of as a task which opportunistically 294462306a36Sopenharmony_ci * uses other threads execution contexts. We use the Offload Queue 294562306a36Sopenharmony_ci * boolean "service_ofldq_running" to make sure that only one instance 294662306a36Sopenharmony_ci * is ever running at a time ... 294762306a36Sopenharmony_ci */ 294862306a36Sopenharmony_cistatic void service_ofldq(struct sge_uld_txq *q) 294962306a36Sopenharmony_ci __must_hold(&q->sendq.lock) 295062306a36Sopenharmony_ci{ 295162306a36Sopenharmony_ci u64 *pos, *before, *end; 295262306a36Sopenharmony_ci int credits; 295362306a36Sopenharmony_ci struct sk_buff *skb; 295462306a36Sopenharmony_ci struct sge_txq *txq; 295562306a36Sopenharmony_ci unsigned int left; 295662306a36Sopenharmony_ci unsigned int written = 0; 295762306a36Sopenharmony_ci unsigned int flits, ndesc; 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci /* If another thread is currently in service_ofldq() processing the 296062306a36Sopenharmony_ci * Pending Send Queue then there's nothing to do. Otherwise, flag 296162306a36Sopenharmony_ci * that we're doing the work and continue. Examining/modifying 296262306a36Sopenharmony_ci * the Offload Queue boolean "service_ofldq_running" must be done 296362306a36Sopenharmony_ci * while holding the Pending Send Queue Lock. 296462306a36Sopenharmony_ci */ 296562306a36Sopenharmony_ci if (q->service_ofldq_running) 296662306a36Sopenharmony_ci return; 296762306a36Sopenharmony_ci q->service_ofldq_running = true; 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci while ((skb = skb_peek(&q->sendq)) != NULL && !q->full) { 297062306a36Sopenharmony_ci /* We drop the lock while we're working with the skb at the 297162306a36Sopenharmony_ci * head of the Pending Send Queue. This allows more skbs to 297262306a36Sopenharmony_ci * be added to the Pending Send Queue while we're working on 297362306a36Sopenharmony_ci * this one. We don't need to lock to guard the TX Ring 297462306a36Sopenharmony_ci * updates because only one thread of execution is ever 297562306a36Sopenharmony_ci * allowed into service_ofldq() at a time. 297662306a36Sopenharmony_ci */ 297762306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci cxgb4_reclaim_completed_tx(q->adap, &q->q, false); 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci flits = skb->priority; /* previously saved */ 298262306a36Sopenharmony_ci ndesc = flits_to_desc(flits); 298362306a36Sopenharmony_ci credits = txq_avail(&q->q) - ndesc; 298462306a36Sopenharmony_ci BUG_ON(credits < 0); 298562306a36Sopenharmony_ci if (unlikely(credits < TXQ_STOP_THRES)) 298662306a36Sopenharmony_ci ofldtxq_stop(q, (struct fw_wr_hdr *)skb->data); 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci pos = (u64 *)&q->q.desc[q->q.pidx]; 298962306a36Sopenharmony_ci if (is_ofld_imm(skb)) 299062306a36Sopenharmony_ci cxgb4_inline_tx_skb(skb, &q->q, pos); 299162306a36Sopenharmony_ci else if (cxgb4_map_skb(q->adap->pdev_dev, skb, 299262306a36Sopenharmony_ci (dma_addr_t *)skb->head)) { 299362306a36Sopenharmony_ci txq_stop_maperr(q); 299462306a36Sopenharmony_ci spin_lock(&q->sendq.lock); 299562306a36Sopenharmony_ci break; 299662306a36Sopenharmony_ci } else { 299762306a36Sopenharmony_ci int last_desc, hdr_len = skb_transport_offset(skb); 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci /* The WR headers may not fit within one descriptor. 300062306a36Sopenharmony_ci * So we need to deal with wrap-around here. 300162306a36Sopenharmony_ci */ 300262306a36Sopenharmony_ci before = (u64 *)pos; 300362306a36Sopenharmony_ci end = (u64 *)pos + flits; 300462306a36Sopenharmony_ci txq = &q->q; 300562306a36Sopenharmony_ci pos = (void *)inline_tx_skb_header(skb, &q->q, 300662306a36Sopenharmony_ci (void *)pos, 300762306a36Sopenharmony_ci hdr_len); 300862306a36Sopenharmony_ci if (before > (u64 *)pos) { 300962306a36Sopenharmony_ci left = (u8 *)end - (u8 *)txq->stat; 301062306a36Sopenharmony_ci end = (void *)txq->desc + left; 301162306a36Sopenharmony_ci } 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci /* If current position is already at the end of the 301462306a36Sopenharmony_ci * ofld queue, reset the current to point to 301562306a36Sopenharmony_ci * start of the queue and update the end ptr as well. 301662306a36Sopenharmony_ci */ 301762306a36Sopenharmony_ci if (pos == (u64 *)txq->stat) { 301862306a36Sopenharmony_ci left = (u8 *)end - (u8 *)txq->stat; 301962306a36Sopenharmony_ci end = (void *)txq->desc + left; 302062306a36Sopenharmony_ci pos = (void *)txq->desc; 302162306a36Sopenharmony_ci } 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci cxgb4_write_sgl(skb, &q->q, (void *)pos, 302462306a36Sopenharmony_ci end, hdr_len, 302562306a36Sopenharmony_ci (dma_addr_t *)skb->head); 302662306a36Sopenharmony_ci#ifdef CONFIG_NEED_DMA_MAP_STATE 302762306a36Sopenharmony_ci skb->dev = q->adap->port[0]; 302862306a36Sopenharmony_ci skb->destructor = deferred_unmap_destructor; 302962306a36Sopenharmony_ci#endif 303062306a36Sopenharmony_ci last_desc = q->q.pidx + ndesc - 1; 303162306a36Sopenharmony_ci if (last_desc >= q->q.size) 303262306a36Sopenharmony_ci last_desc -= q->q.size; 303362306a36Sopenharmony_ci q->q.sdesc[last_desc].skb = skb; 303462306a36Sopenharmony_ci } 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci txq_advance(&q->q, ndesc); 303762306a36Sopenharmony_ci written += ndesc; 303862306a36Sopenharmony_ci if (unlikely(written > 32)) { 303962306a36Sopenharmony_ci cxgb4_ring_tx_db(q->adap, &q->q, written); 304062306a36Sopenharmony_ci written = 0; 304162306a36Sopenharmony_ci } 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci /* Reacquire the Pending Send Queue Lock so we can unlink the 304462306a36Sopenharmony_ci * skb we've just successfully transferred to the TX Ring and 304562306a36Sopenharmony_ci * loop for the next skb which may be at the head of the 304662306a36Sopenharmony_ci * Pending Send Queue. 304762306a36Sopenharmony_ci */ 304862306a36Sopenharmony_ci spin_lock(&q->sendq.lock); 304962306a36Sopenharmony_ci __skb_unlink(skb, &q->sendq); 305062306a36Sopenharmony_ci if (is_ofld_imm(skb)) 305162306a36Sopenharmony_ci kfree_skb(skb); 305262306a36Sopenharmony_ci } 305362306a36Sopenharmony_ci if (likely(written)) 305462306a36Sopenharmony_ci cxgb4_ring_tx_db(q->adap, &q->q, written); 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci /*Indicate that no thread is processing the Pending Send Queue 305762306a36Sopenharmony_ci * currently. 305862306a36Sopenharmony_ci */ 305962306a36Sopenharmony_ci q->service_ofldq_running = false; 306062306a36Sopenharmony_ci} 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci/** 306362306a36Sopenharmony_ci * ofld_xmit - send a packet through an offload queue 306462306a36Sopenharmony_ci * @q: the Tx offload queue 306562306a36Sopenharmony_ci * @skb: the packet 306662306a36Sopenharmony_ci * 306762306a36Sopenharmony_ci * Send an offload packet through an SGE offload queue. 306862306a36Sopenharmony_ci */ 306962306a36Sopenharmony_cistatic int ofld_xmit(struct sge_uld_txq *q, struct sk_buff *skb) 307062306a36Sopenharmony_ci{ 307162306a36Sopenharmony_ci skb->priority = calc_tx_flits_ofld(skb); /* save for restart */ 307262306a36Sopenharmony_ci spin_lock(&q->sendq.lock); 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci /* Queue the new skb onto the Offload Queue's Pending Send Queue. If 307562306a36Sopenharmony_ci * that results in this new skb being the only one on the queue, start 307662306a36Sopenharmony_ci * servicing it. If there are other skbs already on the list, then 307762306a36Sopenharmony_ci * either the queue is currently being processed or it's been stopped 307862306a36Sopenharmony_ci * for some reason and it'll be restarted at a later time. Restart 307962306a36Sopenharmony_ci * paths are triggered by events like experiencing a DMA Mapping Error 308062306a36Sopenharmony_ci * or filling the Hardware TX Ring. 308162306a36Sopenharmony_ci */ 308262306a36Sopenharmony_ci __skb_queue_tail(&q->sendq, skb); 308362306a36Sopenharmony_ci if (q->sendq.qlen == 1) 308462306a36Sopenharmony_ci service_ofldq(q); 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 308762306a36Sopenharmony_ci return NET_XMIT_SUCCESS; 308862306a36Sopenharmony_ci} 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci/** 309162306a36Sopenharmony_ci * restart_ofldq - restart a suspended offload queue 309262306a36Sopenharmony_ci * @t: pointer to the tasklet associated with this handler 309362306a36Sopenharmony_ci * 309462306a36Sopenharmony_ci * Resumes transmission on a suspended Tx offload queue. 309562306a36Sopenharmony_ci */ 309662306a36Sopenharmony_cistatic void restart_ofldq(struct tasklet_struct *t) 309762306a36Sopenharmony_ci{ 309862306a36Sopenharmony_ci struct sge_uld_txq *q = from_tasklet(q, t, qresume_tsk); 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ci spin_lock(&q->sendq.lock); 310162306a36Sopenharmony_ci q->full = 0; /* the queue actually is completely empty now */ 310262306a36Sopenharmony_ci service_ofldq(q); 310362306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 310462306a36Sopenharmony_ci} 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci/** 310762306a36Sopenharmony_ci * skb_txq - return the Tx queue an offload packet should use 310862306a36Sopenharmony_ci * @skb: the packet 310962306a36Sopenharmony_ci * 311062306a36Sopenharmony_ci * Returns the Tx queue an offload packet should use as indicated by bits 311162306a36Sopenharmony_ci * 1-15 in the packet's queue_mapping. 311262306a36Sopenharmony_ci */ 311362306a36Sopenharmony_cistatic inline unsigned int skb_txq(const struct sk_buff *skb) 311462306a36Sopenharmony_ci{ 311562306a36Sopenharmony_ci return skb->queue_mapping >> 1; 311662306a36Sopenharmony_ci} 311762306a36Sopenharmony_ci 311862306a36Sopenharmony_ci/** 311962306a36Sopenharmony_ci * is_ctrl_pkt - return whether an offload packet is a control packet 312062306a36Sopenharmony_ci * @skb: the packet 312162306a36Sopenharmony_ci * 312262306a36Sopenharmony_ci * Returns whether an offload packet should use an OFLD or a CTRL 312362306a36Sopenharmony_ci * Tx queue as indicated by bit 0 in the packet's queue_mapping. 312462306a36Sopenharmony_ci */ 312562306a36Sopenharmony_cistatic inline unsigned int is_ctrl_pkt(const struct sk_buff *skb) 312662306a36Sopenharmony_ci{ 312762306a36Sopenharmony_ci return skb->queue_mapping & 1; 312862306a36Sopenharmony_ci} 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_cistatic inline int uld_send(struct adapter *adap, struct sk_buff *skb, 313162306a36Sopenharmony_ci unsigned int tx_uld_type) 313262306a36Sopenharmony_ci{ 313362306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info; 313462306a36Sopenharmony_ci struct sge_uld_txq *txq; 313562306a36Sopenharmony_ci unsigned int idx = skb_txq(skb); 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci if (unlikely(is_ctrl_pkt(skb))) { 313862306a36Sopenharmony_ci /* Single ctrl queue is a requirement for LE workaround path */ 313962306a36Sopenharmony_ci if (adap->tids.nsftids) 314062306a36Sopenharmony_ci idx = 0; 314162306a36Sopenharmony_ci return ctrl_xmit(&adap->sge.ctrlq[idx], skb); 314262306a36Sopenharmony_ci } 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci txq_info = adap->sge.uld_txq_info[tx_uld_type]; 314562306a36Sopenharmony_ci if (unlikely(!txq_info)) { 314662306a36Sopenharmony_ci WARN_ON(true); 314762306a36Sopenharmony_ci kfree_skb(skb); 314862306a36Sopenharmony_ci return NET_XMIT_DROP; 314962306a36Sopenharmony_ci } 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci txq = &txq_info->uldtxq[idx]; 315262306a36Sopenharmony_ci return ofld_xmit(txq, skb); 315362306a36Sopenharmony_ci} 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci/** 315662306a36Sopenharmony_ci * t4_ofld_send - send an offload packet 315762306a36Sopenharmony_ci * @adap: the adapter 315862306a36Sopenharmony_ci * @skb: the packet 315962306a36Sopenharmony_ci * 316062306a36Sopenharmony_ci * Sends an offload packet. We use the packet queue_mapping to select the 316162306a36Sopenharmony_ci * appropriate Tx queue as follows: bit 0 indicates whether the packet 316262306a36Sopenharmony_ci * should be sent as regular or control, bits 1-15 select the queue. 316362306a36Sopenharmony_ci */ 316462306a36Sopenharmony_ciint t4_ofld_send(struct adapter *adap, struct sk_buff *skb) 316562306a36Sopenharmony_ci{ 316662306a36Sopenharmony_ci int ret; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci local_bh_disable(); 316962306a36Sopenharmony_ci ret = uld_send(adap, skb, CXGB4_TX_OFLD); 317062306a36Sopenharmony_ci local_bh_enable(); 317162306a36Sopenharmony_ci return ret; 317262306a36Sopenharmony_ci} 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci/** 317562306a36Sopenharmony_ci * cxgb4_ofld_send - send an offload packet 317662306a36Sopenharmony_ci * @dev: the net device 317762306a36Sopenharmony_ci * @skb: the packet 317862306a36Sopenharmony_ci * 317962306a36Sopenharmony_ci * Sends an offload packet. This is an exported version of @t4_ofld_send, 318062306a36Sopenharmony_ci * intended for ULDs. 318162306a36Sopenharmony_ci */ 318262306a36Sopenharmony_ciint cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb) 318362306a36Sopenharmony_ci{ 318462306a36Sopenharmony_ci return t4_ofld_send(netdev2adap(dev), skb); 318562306a36Sopenharmony_ci} 318662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_ofld_send); 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_cistatic void *inline_tx_header(const void *src, 318962306a36Sopenharmony_ci const struct sge_txq *q, 319062306a36Sopenharmony_ci void *pos, int length) 319162306a36Sopenharmony_ci{ 319262306a36Sopenharmony_ci int left = (void *)q->stat - pos; 319362306a36Sopenharmony_ci u64 *p; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci if (likely(length <= left)) { 319662306a36Sopenharmony_ci memcpy(pos, src, length); 319762306a36Sopenharmony_ci pos += length; 319862306a36Sopenharmony_ci } else { 319962306a36Sopenharmony_ci memcpy(pos, src, left); 320062306a36Sopenharmony_ci memcpy(q->desc, src + left, length - left); 320162306a36Sopenharmony_ci pos = (void *)q->desc + (length - left); 320262306a36Sopenharmony_ci } 320362306a36Sopenharmony_ci /* 0-pad to multiple of 16 */ 320462306a36Sopenharmony_ci p = PTR_ALIGN(pos, 8); 320562306a36Sopenharmony_ci if ((uintptr_t)p & 8) { 320662306a36Sopenharmony_ci *p = 0; 320762306a36Sopenharmony_ci return p + 1; 320862306a36Sopenharmony_ci } 320962306a36Sopenharmony_ci return p; 321062306a36Sopenharmony_ci} 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci/** 321362306a36Sopenharmony_ci * ofld_xmit_direct - copy a WR into offload queue 321462306a36Sopenharmony_ci * @q: the Tx offload queue 321562306a36Sopenharmony_ci * @src: location of WR 321662306a36Sopenharmony_ci * @len: WR length 321762306a36Sopenharmony_ci * 321862306a36Sopenharmony_ci * Copy an immediate WR into an uncontended SGE offload queue. 321962306a36Sopenharmony_ci */ 322062306a36Sopenharmony_cistatic int ofld_xmit_direct(struct sge_uld_txq *q, const void *src, 322162306a36Sopenharmony_ci unsigned int len) 322262306a36Sopenharmony_ci{ 322362306a36Sopenharmony_ci unsigned int ndesc; 322462306a36Sopenharmony_ci int credits; 322562306a36Sopenharmony_ci u64 *pos; 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci /* Use the lower limit as the cut-off */ 322862306a36Sopenharmony_ci if (len > MAX_IMM_OFLD_TX_DATA_WR_LEN) { 322962306a36Sopenharmony_ci WARN_ON(1); 323062306a36Sopenharmony_ci return NET_XMIT_DROP; 323162306a36Sopenharmony_ci } 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci /* Don't return NET_XMIT_CN here as the current 323462306a36Sopenharmony_ci * implementation doesn't queue the request 323562306a36Sopenharmony_ci * using an skb when the following conditions not met 323662306a36Sopenharmony_ci */ 323762306a36Sopenharmony_ci if (!spin_trylock(&q->sendq.lock)) 323862306a36Sopenharmony_ci return NET_XMIT_DROP; 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_ci if (q->full || !skb_queue_empty(&q->sendq) || 324162306a36Sopenharmony_ci q->service_ofldq_running) { 324262306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 324362306a36Sopenharmony_ci return NET_XMIT_DROP; 324462306a36Sopenharmony_ci } 324562306a36Sopenharmony_ci ndesc = flits_to_desc(DIV_ROUND_UP(len, 8)); 324662306a36Sopenharmony_ci credits = txq_avail(&q->q) - ndesc; 324762306a36Sopenharmony_ci pos = (u64 *)&q->q.desc[q->q.pidx]; 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci /* ofldtxq_stop modifies WR header in-situ */ 325062306a36Sopenharmony_ci inline_tx_header(src, &q->q, pos, len); 325162306a36Sopenharmony_ci if (unlikely(credits < TXQ_STOP_THRES)) 325262306a36Sopenharmony_ci ofldtxq_stop(q, (struct fw_wr_hdr *)pos); 325362306a36Sopenharmony_ci txq_advance(&q->q, ndesc); 325462306a36Sopenharmony_ci cxgb4_ring_tx_db(q->adap, &q->q, ndesc); 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_ci spin_unlock(&q->sendq.lock); 325762306a36Sopenharmony_ci return NET_XMIT_SUCCESS; 325862306a36Sopenharmony_ci} 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ciint cxgb4_immdata_send(struct net_device *dev, unsigned int idx, 326162306a36Sopenharmony_ci const void *src, unsigned int len) 326262306a36Sopenharmony_ci{ 326362306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info; 326462306a36Sopenharmony_ci struct sge_uld_txq *txq; 326562306a36Sopenharmony_ci struct adapter *adap; 326662306a36Sopenharmony_ci int ret; 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci adap = netdev2adap(dev); 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci local_bh_disable(); 327162306a36Sopenharmony_ci txq_info = adap->sge.uld_txq_info[CXGB4_TX_OFLD]; 327262306a36Sopenharmony_ci if (unlikely(!txq_info)) { 327362306a36Sopenharmony_ci WARN_ON(true); 327462306a36Sopenharmony_ci local_bh_enable(); 327562306a36Sopenharmony_ci return NET_XMIT_DROP; 327662306a36Sopenharmony_ci } 327762306a36Sopenharmony_ci txq = &txq_info->uldtxq[idx]; 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci ret = ofld_xmit_direct(txq, src, len); 328062306a36Sopenharmony_ci local_bh_enable(); 328162306a36Sopenharmony_ci return net_xmit_eval(ret); 328262306a36Sopenharmony_ci} 328362306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_immdata_send); 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci/** 328662306a36Sopenharmony_ci * t4_crypto_send - send crypto packet 328762306a36Sopenharmony_ci * @adap: the adapter 328862306a36Sopenharmony_ci * @skb: the packet 328962306a36Sopenharmony_ci * 329062306a36Sopenharmony_ci * Sends crypto packet. We use the packet queue_mapping to select the 329162306a36Sopenharmony_ci * appropriate Tx queue as follows: bit 0 indicates whether the packet 329262306a36Sopenharmony_ci * should be sent as regular or control, bits 1-15 select the queue. 329362306a36Sopenharmony_ci */ 329462306a36Sopenharmony_cistatic int t4_crypto_send(struct adapter *adap, struct sk_buff *skb) 329562306a36Sopenharmony_ci{ 329662306a36Sopenharmony_ci int ret; 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci local_bh_disable(); 329962306a36Sopenharmony_ci ret = uld_send(adap, skb, CXGB4_TX_CRYPTO); 330062306a36Sopenharmony_ci local_bh_enable(); 330162306a36Sopenharmony_ci return ret; 330262306a36Sopenharmony_ci} 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci/** 330562306a36Sopenharmony_ci * cxgb4_crypto_send - send crypto packet 330662306a36Sopenharmony_ci * @dev: the net device 330762306a36Sopenharmony_ci * @skb: the packet 330862306a36Sopenharmony_ci * 330962306a36Sopenharmony_ci * Sends crypto packet. This is an exported version of @t4_crypto_send, 331062306a36Sopenharmony_ci * intended for ULDs. 331162306a36Sopenharmony_ci */ 331262306a36Sopenharmony_ciint cxgb4_crypto_send(struct net_device *dev, struct sk_buff *skb) 331362306a36Sopenharmony_ci{ 331462306a36Sopenharmony_ci return t4_crypto_send(netdev2adap(dev), skb); 331562306a36Sopenharmony_ci} 331662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_crypto_send); 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_cistatic inline void copy_frags(struct sk_buff *skb, 331962306a36Sopenharmony_ci const struct pkt_gl *gl, unsigned int offset) 332062306a36Sopenharmony_ci{ 332162306a36Sopenharmony_ci int i; 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci /* usually there's just one frag */ 332462306a36Sopenharmony_ci __skb_fill_page_desc(skb, 0, gl->frags[0].page, 332562306a36Sopenharmony_ci gl->frags[0].offset + offset, 332662306a36Sopenharmony_ci gl->frags[0].size - offset); 332762306a36Sopenharmony_ci skb_shinfo(skb)->nr_frags = gl->nfrags; 332862306a36Sopenharmony_ci for (i = 1; i < gl->nfrags; i++) 332962306a36Sopenharmony_ci __skb_fill_page_desc(skb, i, gl->frags[i].page, 333062306a36Sopenharmony_ci gl->frags[i].offset, 333162306a36Sopenharmony_ci gl->frags[i].size); 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci /* get a reference to the last page, we don't own it */ 333462306a36Sopenharmony_ci get_page(gl->frags[gl->nfrags - 1].page); 333562306a36Sopenharmony_ci} 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci/** 333862306a36Sopenharmony_ci * cxgb4_pktgl_to_skb - build an sk_buff from a packet gather list 333962306a36Sopenharmony_ci * @gl: the gather list 334062306a36Sopenharmony_ci * @skb_len: size of sk_buff main body if it carries fragments 334162306a36Sopenharmony_ci * @pull_len: amount of data to move to the sk_buff's main body 334262306a36Sopenharmony_ci * 334362306a36Sopenharmony_ci * Builds an sk_buff from the given packet gather list. Returns the 334462306a36Sopenharmony_ci * sk_buff or %NULL if sk_buff allocation failed. 334562306a36Sopenharmony_ci */ 334662306a36Sopenharmony_cistruct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl, 334762306a36Sopenharmony_ci unsigned int skb_len, unsigned int pull_len) 334862306a36Sopenharmony_ci{ 334962306a36Sopenharmony_ci struct sk_buff *skb; 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci /* 335262306a36Sopenharmony_ci * Below we rely on RX_COPY_THRES being less than the smallest Rx buffer 335362306a36Sopenharmony_ci * size, which is expected since buffers are at least PAGE_SIZEd. 335462306a36Sopenharmony_ci * In this case packets up to RX_COPY_THRES have only one fragment. 335562306a36Sopenharmony_ci */ 335662306a36Sopenharmony_ci if (gl->tot_len <= RX_COPY_THRES) { 335762306a36Sopenharmony_ci skb = dev_alloc_skb(gl->tot_len); 335862306a36Sopenharmony_ci if (unlikely(!skb)) 335962306a36Sopenharmony_ci goto out; 336062306a36Sopenharmony_ci __skb_put(skb, gl->tot_len); 336162306a36Sopenharmony_ci skb_copy_to_linear_data(skb, gl->va, gl->tot_len); 336262306a36Sopenharmony_ci } else { 336362306a36Sopenharmony_ci skb = dev_alloc_skb(skb_len); 336462306a36Sopenharmony_ci if (unlikely(!skb)) 336562306a36Sopenharmony_ci goto out; 336662306a36Sopenharmony_ci __skb_put(skb, pull_len); 336762306a36Sopenharmony_ci skb_copy_to_linear_data(skb, gl->va, pull_len); 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci copy_frags(skb, gl, pull_len); 337062306a36Sopenharmony_ci skb->len = gl->tot_len; 337162306a36Sopenharmony_ci skb->data_len = skb->len - pull_len; 337262306a36Sopenharmony_ci skb->truesize += skb->data_len; 337362306a36Sopenharmony_ci } 337462306a36Sopenharmony_ciout: return skb; 337562306a36Sopenharmony_ci} 337662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_pktgl_to_skb); 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_ci/** 337962306a36Sopenharmony_ci * t4_pktgl_free - free a packet gather list 338062306a36Sopenharmony_ci * @gl: the gather list 338162306a36Sopenharmony_ci * 338262306a36Sopenharmony_ci * Releases the pages of a packet gather list. We do not own the last 338362306a36Sopenharmony_ci * page on the list and do not free it. 338462306a36Sopenharmony_ci */ 338562306a36Sopenharmony_cistatic void t4_pktgl_free(const struct pkt_gl *gl) 338662306a36Sopenharmony_ci{ 338762306a36Sopenharmony_ci int n; 338862306a36Sopenharmony_ci const struct page_frag *p; 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci for (p = gl->frags, n = gl->nfrags - 1; n--; p++) 339162306a36Sopenharmony_ci put_page(p->page); 339262306a36Sopenharmony_ci} 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci/* 339562306a36Sopenharmony_ci * Process an MPS trace packet. Give it an unused protocol number so it won't 339662306a36Sopenharmony_ci * be delivered to anyone and send it to the stack for capture. 339762306a36Sopenharmony_ci */ 339862306a36Sopenharmony_cistatic noinline int handle_trace_pkt(struct adapter *adap, 339962306a36Sopenharmony_ci const struct pkt_gl *gl) 340062306a36Sopenharmony_ci{ 340162306a36Sopenharmony_ci struct sk_buff *skb; 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci skb = cxgb4_pktgl_to_skb(gl, RX_PULL_LEN, RX_PULL_LEN); 340462306a36Sopenharmony_ci if (unlikely(!skb)) { 340562306a36Sopenharmony_ci t4_pktgl_free(gl); 340662306a36Sopenharmony_ci return 0; 340762306a36Sopenharmony_ci } 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 341062306a36Sopenharmony_ci __skb_pull(skb, sizeof(struct cpl_trace_pkt)); 341162306a36Sopenharmony_ci else 341262306a36Sopenharmony_ci __skb_pull(skb, sizeof(struct cpl_t5_trace_pkt)); 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci skb_reset_mac_header(skb); 341562306a36Sopenharmony_ci skb->protocol = htons(0xffff); 341662306a36Sopenharmony_ci skb->dev = adap->port[0]; 341762306a36Sopenharmony_ci netif_receive_skb(skb); 341862306a36Sopenharmony_ci return 0; 341962306a36Sopenharmony_ci} 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci/** 342262306a36Sopenharmony_ci * cxgb4_sgetim_to_hwtstamp - convert sge time stamp to hw time stamp 342362306a36Sopenharmony_ci * @adap: the adapter 342462306a36Sopenharmony_ci * @hwtstamps: time stamp structure to update 342562306a36Sopenharmony_ci * @sgetstamp: 60bit iqe timestamp 342662306a36Sopenharmony_ci * 342762306a36Sopenharmony_ci * Every ingress queue entry has the 60-bit timestamp, convert that timestamp 342862306a36Sopenharmony_ci * which is in Core Clock ticks into ktime_t and assign it 342962306a36Sopenharmony_ci **/ 343062306a36Sopenharmony_cistatic void cxgb4_sgetim_to_hwtstamp(struct adapter *adap, 343162306a36Sopenharmony_ci struct skb_shared_hwtstamps *hwtstamps, 343262306a36Sopenharmony_ci u64 sgetstamp) 343362306a36Sopenharmony_ci{ 343462306a36Sopenharmony_ci u64 ns; 343562306a36Sopenharmony_ci u64 tmp = (sgetstamp * 1000 * 1000 + adap->params.vpd.cclk / 2); 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci ns = div_u64(tmp, adap->params.vpd.cclk); 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ci memset(hwtstamps, 0, sizeof(*hwtstamps)); 344062306a36Sopenharmony_ci hwtstamps->hwtstamp = ns_to_ktime(ns); 344162306a36Sopenharmony_ci} 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_cistatic void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, 344462306a36Sopenharmony_ci const struct cpl_rx_pkt *pkt, unsigned long tnl_hdr_len) 344562306a36Sopenharmony_ci{ 344662306a36Sopenharmony_ci struct adapter *adapter = rxq->rspq.adap; 344762306a36Sopenharmony_ci struct sge *s = &adapter->sge; 344862306a36Sopenharmony_ci struct port_info *pi; 344962306a36Sopenharmony_ci int ret; 345062306a36Sopenharmony_ci struct sk_buff *skb; 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci skb = napi_get_frags(&rxq->rspq.napi); 345362306a36Sopenharmony_ci if (unlikely(!skb)) { 345462306a36Sopenharmony_ci t4_pktgl_free(gl); 345562306a36Sopenharmony_ci rxq->stats.rx_drops++; 345662306a36Sopenharmony_ci return; 345762306a36Sopenharmony_ci } 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ci copy_frags(skb, gl, s->pktshift); 346062306a36Sopenharmony_ci if (tnl_hdr_len) 346162306a36Sopenharmony_ci skb->csum_level = 1; 346262306a36Sopenharmony_ci skb->len = gl->tot_len - s->pktshift; 346362306a36Sopenharmony_ci skb->data_len = skb->len; 346462306a36Sopenharmony_ci skb->truesize += skb->data_len; 346562306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 346662306a36Sopenharmony_ci skb_record_rx_queue(skb, rxq->rspq.idx); 346762306a36Sopenharmony_ci pi = netdev_priv(skb->dev); 346862306a36Sopenharmony_ci if (pi->rxtstamp) 346962306a36Sopenharmony_ci cxgb4_sgetim_to_hwtstamp(adapter, skb_hwtstamps(skb), 347062306a36Sopenharmony_ci gl->sgetstamp); 347162306a36Sopenharmony_ci if (rxq->rspq.netdev->features & NETIF_F_RXHASH) 347262306a36Sopenharmony_ci skb_set_hash(skb, (__force u32)pkt->rsshdr.hash_val, 347362306a36Sopenharmony_ci PKT_HASH_TYPE_L3); 347462306a36Sopenharmony_ci 347562306a36Sopenharmony_ci if (unlikely(pkt->vlan_ex)) { 347662306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan)); 347762306a36Sopenharmony_ci rxq->stats.vlan_ex++; 347862306a36Sopenharmony_ci } 347962306a36Sopenharmony_ci ret = napi_gro_frags(&rxq->rspq.napi); 348062306a36Sopenharmony_ci if (ret == GRO_HELD) 348162306a36Sopenharmony_ci rxq->stats.lro_pkts++; 348262306a36Sopenharmony_ci else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE) 348362306a36Sopenharmony_ci rxq->stats.lro_merged++; 348462306a36Sopenharmony_ci rxq->stats.pkts++; 348562306a36Sopenharmony_ci rxq->stats.rx_cso++; 348662306a36Sopenharmony_ci} 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_cienum { 348962306a36Sopenharmony_ci RX_NON_PTP_PKT = 0, 349062306a36Sopenharmony_ci RX_PTP_PKT_SUC = 1, 349162306a36Sopenharmony_ci RX_PTP_PKT_ERR = 2 349262306a36Sopenharmony_ci}; 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci/** 349562306a36Sopenharmony_ci * t4_systim_to_hwstamp - read hardware time stamp 349662306a36Sopenharmony_ci * @adapter: the adapter 349762306a36Sopenharmony_ci * @skb: the packet 349862306a36Sopenharmony_ci * 349962306a36Sopenharmony_ci * Read Time Stamp from MPS packet and insert in skb which 350062306a36Sopenharmony_ci * is forwarded to PTP application 350162306a36Sopenharmony_ci */ 350262306a36Sopenharmony_cistatic noinline int t4_systim_to_hwstamp(struct adapter *adapter, 350362306a36Sopenharmony_ci struct sk_buff *skb) 350462306a36Sopenharmony_ci{ 350562306a36Sopenharmony_ci struct skb_shared_hwtstamps *hwtstamps; 350662306a36Sopenharmony_ci struct cpl_rx_mps_pkt *cpl = NULL; 350762306a36Sopenharmony_ci unsigned char *data; 350862306a36Sopenharmony_ci int offset; 350962306a36Sopenharmony_ci 351062306a36Sopenharmony_ci cpl = (struct cpl_rx_mps_pkt *)skb->data; 351162306a36Sopenharmony_ci if (!(CPL_RX_MPS_PKT_TYPE_G(ntohl(cpl->op_to_r1_hi)) & 351262306a36Sopenharmony_ci X_CPL_RX_MPS_PKT_TYPE_PTP)) 351362306a36Sopenharmony_ci return RX_PTP_PKT_ERR; 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci data = skb->data + sizeof(*cpl); 351662306a36Sopenharmony_ci skb_pull(skb, 2 * sizeof(u64) + sizeof(struct cpl_rx_mps_pkt)); 351762306a36Sopenharmony_ci offset = ETH_HLEN + IPV4_HLEN(skb->data) + UDP_HLEN; 351862306a36Sopenharmony_ci if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(short)) 351962306a36Sopenharmony_ci return RX_PTP_PKT_ERR; 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci hwtstamps = skb_hwtstamps(skb); 352262306a36Sopenharmony_ci memset(hwtstamps, 0, sizeof(*hwtstamps)); 352362306a36Sopenharmony_ci hwtstamps->hwtstamp = ns_to_ktime(get_unaligned_be64(data)); 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_ci return RX_PTP_PKT_SUC; 352662306a36Sopenharmony_ci} 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci/** 352962306a36Sopenharmony_ci * t4_rx_hststamp - Recv PTP Event Message 353062306a36Sopenharmony_ci * @adapter: the adapter 353162306a36Sopenharmony_ci * @rsp: the response queue descriptor holding the RX_PKT message 353262306a36Sopenharmony_ci * @rxq: the response queue holding the RX_PKT message 353362306a36Sopenharmony_ci * @skb: the packet 353462306a36Sopenharmony_ci * 353562306a36Sopenharmony_ci * PTP enabled and MPS packet, read HW timestamp 353662306a36Sopenharmony_ci */ 353762306a36Sopenharmony_cistatic int t4_rx_hststamp(struct adapter *adapter, const __be64 *rsp, 353862306a36Sopenharmony_ci struct sge_eth_rxq *rxq, struct sk_buff *skb) 353962306a36Sopenharmony_ci{ 354062306a36Sopenharmony_ci int ret; 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci if (unlikely((*(u8 *)rsp == CPL_RX_MPS_PKT) && 354362306a36Sopenharmony_ci !is_t4(adapter->params.chip))) { 354462306a36Sopenharmony_ci ret = t4_systim_to_hwstamp(adapter, skb); 354562306a36Sopenharmony_ci if (ret == RX_PTP_PKT_ERR) { 354662306a36Sopenharmony_ci kfree_skb(skb); 354762306a36Sopenharmony_ci rxq->stats.rx_drops++; 354862306a36Sopenharmony_ci } 354962306a36Sopenharmony_ci return ret; 355062306a36Sopenharmony_ci } 355162306a36Sopenharmony_ci return RX_NON_PTP_PKT; 355262306a36Sopenharmony_ci} 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_ci/** 355562306a36Sopenharmony_ci * t4_tx_hststamp - Loopback PTP Transmit Event Message 355662306a36Sopenharmony_ci * @adapter: the adapter 355762306a36Sopenharmony_ci * @skb: the packet 355862306a36Sopenharmony_ci * @dev: the ingress net device 355962306a36Sopenharmony_ci * 356062306a36Sopenharmony_ci * Read hardware timestamp for the loopback PTP Tx event message 356162306a36Sopenharmony_ci */ 356262306a36Sopenharmony_cistatic int t4_tx_hststamp(struct adapter *adapter, struct sk_buff *skb, 356362306a36Sopenharmony_ci struct net_device *dev) 356462306a36Sopenharmony_ci{ 356562306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci if (!is_t4(adapter->params.chip) && adapter->ptp_tx_skb) { 356862306a36Sopenharmony_ci cxgb4_ptp_read_hwstamp(adapter, pi); 356962306a36Sopenharmony_ci kfree_skb(skb); 357062306a36Sopenharmony_ci return 0; 357162306a36Sopenharmony_ci } 357262306a36Sopenharmony_ci return 1; 357362306a36Sopenharmony_ci} 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci/** 357662306a36Sopenharmony_ci * t4_tx_completion_handler - handle CPL_SGE_EGR_UPDATE messages 357762306a36Sopenharmony_ci * @rspq: Ethernet RX Response Queue associated with Ethernet TX Queue 357862306a36Sopenharmony_ci * @rsp: Response Entry pointer into Response Queue 357962306a36Sopenharmony_ci * @gl: Gather List pointer 358062306a36Sopenharmony_ci * 358162306a36Sopenharmony_ci * For adapters which support the SGE Doorbell Queue Timer facility, 358262306a36Sopenharmony_ci * we configure the Ethernet TX Queues to send CIDX Updates to the 358362306a36Sopenharmony_ci * Associated Ethernet RX Response Queue with CPL_SGE_EGR_UPDATE 358462306a36Sopenharmony_ci * messages. This adds a small load to PCIe Link RX bandwidth and, 358562306a36Sopenharmony_ci * potentially, higher CPU Interrupt load, but allows us to respond 358662306a36Sopenharmony_ci * much more quickly to the CIDX Updates. This is important for 358762306a36Sopenharmony_ci * Upper Layer Software which isn't willing to have a large amount 358862306a36Sopenharmony_ci * of TX Data outstanding before receiving DMA Completions. 358962306a36Sopenharmony_ci */ 359062306a36Sopenharmony_cistatic void t4_tx_completion_handler(struct sge_rspq *rspq, 359162306a36Sopenharmony_ci const __be64 *rsp, 359262306a36Sopenharmony_ci const struct pkt_gl *gl) 359362306a36Sopenharmony_ci{ 359462306a36Sopenharmony_ci u8 opcode = ((const struct rss_header *)rsp)->opcode; 359562306a36Sopenharmony_ci struct port_info *pi = netdev_priv(rspq->netdev); 359662306a36Sopenharmony_ci struct adapter *adapter = rspq->adap; 359762306a36Sopenharmony_ci struct sge *s = &adapter->sge; 359862306a36Sopenharmony_ci struct sge_eth_txq *txq; 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci /* skip RSS header */ 360162306a36Sopenharmony_ci rsp++; 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_ci /* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG. 360462306a36Sopenharmony_ci */ 360562306a36Sopenharmony_ci if (unlikely(opcode == CPL_FW4_MSG && 360662306a36Sopenharmony_ci ((const struct cpl_fw4_msg *)rsp)->type == 360762306a36Sopenharmony_ci FW_TYPE_RSSCPL)) { 360862306a36Sopenharmony_ci rsp++; 360962306a36Sopenharmony_ci opcode = ((const struct rss_header *)rsp)->opcode; 361062306a36Sopenharmony_ci rsp++; 361162306a36Sopenharmony_ci } 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci if (unlikely(opcode != CPL_SGE_EGR_UPDATE)) { 361462306a36Sopenharmony_ci pr_info("%s: unexpected FW4/CPL %#x on Rx queue\n", 361562306a36Sopenharmony_ci __func__, opcode); 361662306a36Sopenharmony_ci return; 361762306a36Sopenharmony_ci } 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci txq = &s->ethtxq[pi->first_qset + rspq->idx]; 362062306a36Sopenharmony_ci 362162306a36Sopenharmony_ci /* We've got the Hardware Consumer Index Update in the Egress Update 362262306a36Sopenharmony_ci * message. These Egress Update messages will be our sole CIDX Updates 362362306a36Sopenharmony_ci * we get since we don't want to chew up PCIe bandwidth for both Ingress 362462306a36Sopenharmony_ci * Messages and Status Page writes. However, The code which manages 362562306a36Sopenharmony_ci * reclaiming successfully DMA'ed TX Work Requests uses the CIDX value 362662306a36Sopenharmony_ci * stored in the Status Page at the end of the TX Queue. It's easiest 362762306a36Sopenharmony_ci * to simply copy the CIDX Update value from the Egress Update message 362862306a36Sopenharmony_ci * to the Status Page. Also note that no Endian issues need to be 362962306a36Sopenharmony_ci * considered here since both are Big Endian and we're just copying 363062306a36Sopenharmony_ci * bytes consistently ... 363162306a36Sopenharmony_ci */ 363262306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) { 363362306a36Sopenharmony_ci struct cpl_sge_egr_update *egr; 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci egr = (struct cpl_sge_egr_update *)rsp; 363662306a36Sopenharmony_ci WRITE_ONCE(txq->q.stat->cidx, egr->cidx); 363762306a36Sopenharmony_ci } 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci t4_sge_eth_txq_egress_update(adapter, txq, -1); 364062306a36Sopenharmony_ci} 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_cistatic int cxgb4_validate_lb_pkt(struct port_info *pi, const struct pkt_gl *si) 364362306a36Sopenharmony_ci{ 364462306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 364562306a36Sopenharmony_ci struct cxgb4_ethtool_lb_test *lb; 364662306a36Sopenharmony_ci struct sge *s = &adap->sge; 364762306a36Sopenharmony_ci struct net_device *netdev; 364862306a36Sopenharmony_ci u8 *data; 364962306a36Sopenharmony_ci int i; 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci netdev = adap->port[pi->port_id]; 365262306a36Sopenharmony_ci lb = &pi->ethtool_lb; 365362306a36Sopenharmony_ci data = si->va + s->pktshift; 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ci i = ETH_ALEN; 365662306a36Sopenharmony_ci if (!ether_addr_equal(data + i, netdev->dev_addr)) 365762306a36Sopenharmony_ci return -1; 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci i += ETH_ALEN; 366062306a36Sopenharmony_ci if (strcmp(&data[i], CXGB4_SELFTEST_LB_STR)) 366162306a36Sopenharmony_ci lb->result = -EIO; 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci complete(&lb->completion); 366462306a36Sopenharmony_ci return 0; 366562306a36Sopenharmony_ci} 366662306a36Sopenharmony_ci 366762306a36Sopenharmony_ci/** 366862306a36Sopenharmony_ci * t4_ethrx_handler - process an ingress ethernet packet 366962306a36Sopenharmony_ci * @q: the response queue that received the packet 367062306a36Sopenharmony_ci * @rsp: the response queue descriptor holding the RX_PKT message 367162306a36Sopenharmony_ci * @si: the gather list of packet fragments 367262306a36Sopenharmony_ci * 367362306a36Sopenharmony_ci * Process an ingress ethernet packet and deliver it to the stack. 367462306a36Sopenharmony_ci */ 367562306a36Sopenharmony_ciint t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, 367662306a36Sopenharmony_ci const struct pkt_gl *si) 367762306a36Sopenharmony_ci{ 367862306a36Sopenharmony_ci bool csum_ok; 367962306a36Sopenharmony_ci struct sk_buff *skb; 368062306a36Sopenharmony_ci const struct cpl_rx_pkt *pkt; 368162306a36Sopenharmony_ci struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); 368262306a36Sopenharmony_ci struct adapter *adapter = q->adap; 368362306a36Sopenharmony_ci struct sge *s = &q->adap->sge; 368462306a36Sopenharmony_ci int cpl_trace_pkt = is_t4(q->adap->params.chip) ? 368562306a36Sopenharmony_ci CPL_TRACE_PKT : CPL_TRACE_PKT_T5; 368662306a36Sopenharmony_ci u16 err_vec, tnl_hdr_len = 0; 368762306a36Sopenharmony_ci struct port_info *pi; 368862306a36Sopenharmony_ci int ret = 0; 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci pi = netdev_priv(q->netdev); 369162306a36Sopenharmony_ci /* If we're looking at TX Queue CIDX Update, handle that separately 369262306a36Sopenharmony_ci * and return. 369362306a36Sopenharmony_ci */ 369462306a36Sopenharmony_ci if (unlikely((*(u8 *)rsp == CPL_FW4_MSG) || 369562306a36Sopenharmony_ci (*(u8 *)rsp == CPL_SGE_EGR_UPDATE))) { 369662306a36Sopenharmony_ci t4_tx_completion_handler(q, rsp, si); 369762306a36Sopenharmony_ci return 0; 369862306a36Sopenharmony_ci } 369962306a36Sopenharmony_ci 370062306a36Sopenharmony_ci if (unlikely(*(u8 *)rsp == cpl_trace_pkt)) 370162306a36Sopenharmony_ci return handle_trace_pkt(q->adap, si); 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci pkt = (const struct cpl_rx_pkt *)rsp; 370462306a36Sopenharmony_ci /* Compressed error vector is enabled for T6 only */ 370562306a36Sopenharmony_ci if (q->adap->params.tp.rx_pkt_encap) { 370662306a36Sopenharmony_ci err_vec = T6_COMPR_RXERR_VEC_G(be16_to_cpu(pkt->err_vec)); 370762306a36Sopenharmony_ci tnl_hdr_len = T6_RX_TNLHDR_LEN_G(ntohs(pkt->err_vec)); 370862306a36Sopenharmony_ci } else { 370962306a36Sopenharmony_ci err_vec = be16_to_cpu(pkt->err_vec); 371062306a36Sopenharmony_ci } 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci csum_ok = pkt->csum_calc && !err_vec && 371362306a36Sopenharmony_ci (q->netdev->features & NETIF_F_RXCSUM); 371462306a36Sopenharmony_ci 371562306a36Sopenharmony_ci if (err_vec) 371662306a36Sopenharmony_ci rxq->stats.bad_rx_pkts++; 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci if (unlikely(pi->ethtool_lb.loopback && pkt->iff >= NCHAN)) { 371962306a36Sopenharmony_ci ret = cxgb4_validate_lb_pkt(pi, si); 372062306a36Sopenharmony_ci if (!ret) 372162306a36Sopenharmony_ci return 0; 372262306a36Sopenharmony_ci } 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ci if (((pkt->l2info & htonl(RXF_TCP_F)) || 372562306a36Sopenharmony_ci tnl_hdr_len) && 372662306a36Sopenharmony_ci (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { 372762306a36Sopenharmony_ci do_gro(rxq, si, pkt, tnl_hdr_len); 372862306a36Sopenharmony_ci return 0; 372962306a36Sopenharmony_ci } 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci skb = cxgb4_pktgl_to_skb(si, RX_PKT_SKB_LEN, RX_PULL_LEN); 373262306a36Sopenharmony_ci if (unlikely(!skb)) { 373362306a36Sopenharmony_ci t4_pktgl_free(si); 373462306a36Sopenharmony_ci rxq->stats.rx_drops++; 373562306a36Sopenharmony_ci return 0; 373662306a36Sopenharmony_ci } 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_ci /* Handle PTP Event Rx packet */ 373962306a36Sopenharmony_ci if (unlikely(pi->ptp_enable)) { 374062306a36Sopenharmony_ci ret = t4_rx_hststamp(adapter, rsp, rxq, skb); 374162306a36Sopenharmony_ci if (ret == RX_PTP_PKT_ERR) 374262306a36Sopenharmony_ci return 0; 374362306a36Sopenharmony_ci } 374462306a36Sopenharmony_ci if (likely(!ret)) 374562306a36Sopenharmony_ci __skb_pull(skb, s->pktshift); /* remove ethernet header pad */ 374662306a36Sopenharmony_ci 374762306a36Sopenharmony_ci /* Handle the PTP Event Tx Loopback packet */ 374862306a36Sopenharmony_ci if (unlikely(pi->ptp_enable && !ret && 374962306a36Sopenharmony_ci (pkt->l2info & htonl(RXF_UDP_F)) && 375062306a36Sopenharmony_ci cxgb4_ptp_is_ptp_rx(skb))) { 375162306a36Sopenharmony_ci if (!t4_tx_hststamp(adapter, skb, q->netdev)) 375262306a36Sopenharmony_ci return 0; 375362306a36Sopenharmony_ci } 375462306a36Sopenharmony_ci 375562306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, q->netdev); 375662306a36Sopenharmony_ci skb_record_rx_queue(skb, q->idx); 375762306a36Sopenharmony_ci if (skb->dev->features & NETIF_F_RXHASH) 375862306a36Sopenharmony_ci skb_set_hash(skb, (__force u32)pkt->rsshdr.hash_val, 375962306a36Sopenharmony_ci PKT_HASH_TYPE_L3); 376062306a36Sopenharmony_ci 376162306a36Sopenharmony_ci rxq->stats.pkts++; 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ci if (pi->rxtstamp) 376462306a36Sopenharmony_ci cxgb4_sgetim_to_hwtstamp(q->adap, skb_hwtstamps(skb), 376562306a36Sopenharmony_ci si->sgetstamp); 376662306a36Sopenharmony_ci if (csum_ok && (pkt->l2info & htonl(RXF_UDP_F | RXF_TCP_F))) { 376762306a36Sopenharmony_ci if (!pkt->ip_frag) { 376862306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 376962306a36Sopenharmony_ci rxq->stats.rx_cso++; 377062306a36Sopenharmony_ci } else if (pkt->l2info & htonl(RXF_IP_F)) { 377162306a36Sopenharmony_ci __sum16 c = (__force __sum16)pkt->csum; 377262306a36Sopenharmony_ci skb->csum = csum_unfold(c); 377362306a36Sopenharmony_ci 377462306a36Sopenharmony_ci if (tnl_hdr_len) { 377562306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 377662306a36Sopenharmony_ci skb->csum_level = 1; 377762306a36Sopenharmony_ci } else { 377862306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 377962306a36Sopenharmony_ci } 378062306a36Sopenharmony_ci rxq->stats.rx_cso++; 378162306a36Sopenharmony_ci } 378262306a36Sopenharmony_ci } else { 378362306a36Sopenharmony_ci skb_checksum_none_assert(skb); 378462306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 378562306a36Sopenharmony_ci#define CPL_RX_PKT_FLAGS (RXF_PSH_F | RXF_SYN_F | RXF_UDP_F | \ 378662306a36Sopenharmony_ci RXF_TCP_F | RXF_IP_F | RXF_IP6_F | RXF_LRO_F) 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci if (!(pkt->l2info & cpu_to_be32(CPL_RX_PKT_FLAGS))) { 378962306a36Sopenharmony_ci if ((pkt->l2info & cpu_to_be32(RXF_FCOE_F)) && 379062306a36Sopenharmony_ci (pi->fcoe.flags & CXGB_FCOE_ENABLED)) { 379162306a36Sopenharmony_ci if (q->adap->params.tp.rx_pkt_encap) 379262306a36Sopenharmony_ci csum_ok = err_vec & 379362306a36Sopenharmony_ci T6_COMPR_RXERR_SUM_F; 379462306a36Sopenharmony_ci else 379562306a36Sopenharmony_ci csum_ok = err_vec & RXERR_CSUM_F; 379662306a36Sopenharmony_ci if (!csum_ok) 379762306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 379862306a36Sopenharmony_ci } 379962306a36Sopenharmony_ci } 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci#undef CPL_RX_PKT_FLAGS 380262306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 380362306a36Sopenharmony_ci } 380462306a36Sopenharmony_ci 380562306a36Sopenharmony_ci if (unlikely(pkt->vlan_ex)) { 380662306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan)); 380762306a36Sopenharmony_ci rxq->stats.vlan_ex++; 380862306a36Sopenharmony_ci } 380962306a36Sopenharmony_ci skb_mark_napi_id(skb, &q->napi); 381062306a36Sopenharmony_ci netif_receive_skb(skb); 381162306a36Sopenharmony_ci return 0; 381262306a36Sopenharmony_ci} 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci/** 381562306a36Sopenharmony_ci * restore_rx_bufs - put back a packet's Rx buffers 381662306a36Sopenharmony_ci * @si: the packet gather list 381762306a36Sopenharmony_ci * @q: the SGE free list 381862306a36Sopenharmony_ci * @frags: number of FL buffers to restore 381962306a36Sopenharmony_ci * 382062306a36Sopenharmony_ci * Puts back on an FL the Rx buffers associated with @si. The buffers 382162306a36Sopenharmony_ci * have already been unmapped and are left unmapped, we mark them so to 382262306a36Sopenharmony_ci * prevent further unmapping attempts. 382362306a36Sopenharmony_ci * 382462306a36Sopenharmony_ci * This function undoes a series of @unmap_rx_buf calls when we find out 382562306a36Sopenharmony_ci * that the current packet can't be processed right away afterall and we 382662306a36Sopenharmony_ci * need to come back to it later. This is a very rare event and there's 382762306a36Sopenharmony_ci * no effort to make this particularly efficient. 382862306a36Sopenharmony_ci */ 382962306a36Sopenharmony_cistatic void restore_rx_bufs(const struct pkt_gl *si, struct sge_fl *q, 383062306a36Sopenharmony_ci int frags) 383162306a36Sopenharmony_ci{ 383262306a36Sopenharmony_ci struct rx_sw_desc *d; 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_ci while (frags--) { 383562306a36Sopenharmony_ci if (q->cidx == 0) 383662306a36Sopenharmony_ci q->cidx = q->size - 1; 383762306a36Sopenharmony_ci else 383862306a36Sopenharmony_ci q->cidx--; 383962306a36Sopenharmony_ci d = &q->sdesc[q->cidx]; 384062306a36Sopenharmony_ci d->page = si->frags[frags].page; 384162306a36Sopenharmony_ci d->dma_addr |= RX_UNMAPPED_BUF; 384262306a36Sopenharmony_ci q->avail++; 384362306a36Sopenharmony_ci } 384462306a36Sopenharmony_ci} 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci/** 384762306a36Sopenharmony_ci * is_new_response - check if a response is newly written 384862306a36Sopenharmony_ci * @r: the response descriptor 384962306a36Sopenharmony_ci * @q: the response queue 385062306a36Sopenharmony_ci * 385162306a36Sopenharmony_ci * Returns true if a response descriptor contains a yet unprocessed 385262306a36Sopenharmony_ci * response. 385362306a36Sopenharmony_ci */ 385462306a36Sopenharmony_cistatic inline bool is_new_response(const struct rsp_ctrl *r, 385562306a36Sopenharmony_ci const struct sge_rspq *q) 385662306a36Sopenharmony_ci{ 385762306a36Sopenharmony_ci return (r->type_gen >> RSPD_GEN_S) == q->gen; 385862306a36Sopenharmony_ci} 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci/** 386162306a36Sopenharmony_ci * rspq_next - advance to the next entry in a response queue 386262306a36Sopenharmony_ci * @q: the queue 386362306a36Sopenharmony_ci * 386462306a36Sopenharmony_ci * Updates the state of a response queue to advance it to the next entry. 386562306a36Sopenharmony_ci */ 386662306a36Sopenharmony_cistatic inline void rspq_next(struct sge_rspq *q) 386762306a36Sopenharmony_ci{ 386862306a36Sopenharmony_ci q->cur_desc = (void *)q->cur_desc + q->iqe_len; 386962306a36Sopenharmony_ci if (unlikely(++q->cidx == q->size)) { 387062306a36Sopenharmony_ci q->cidx = 0; 387162306a36Sopenharmony_ci q->gen ^= 1; 387262306a36Sopenharmony_ci q->cur_desc = q->desc; 387362306a36Sopenharmony_ci } 387462306a36Sopenharmony_ci} 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci/** 387762306a36Sopenharmony_ci * process_responses - process responses from an SGE response queue 387862306a36Sopenharmony_ci * @q: the ingress queue to process 387962306a36Sopenharmony_ci * @budget: how many responses can be processed in this round 388062306a36Sopenharmony_ci * 388162306a36Sopenharmony_ci * Process responses from an SGE response queue up to the supplied budget. 388262306a36Sopenharmony_ci * Responses include received packets as well as control messages from FW 388362306a36Sopenharmony_ci * or HW. 388462306a36Sopenharmony_ci * 388562306a36Sopenharmony_ci * Additionally choose the interrupt holdoff time for the next interrupt 388662306a36Sopenharmony_ci * on this queue. If the system is under memory shortage use a fairly 388762306a36Sopenharmony_ci * long delay to help recovery. 388862306a36Sopenharmony_ci */ 388962306a36Sopenharmony_cistatic int process_responses(struct sge_rspq *q, int budget) 389062306a36Sopenharmony_ci{ 389162306a36Sopenharmony_ci int ret, rsp_type; 389262306a36Sopenharmony_ci int budget_left = budget; 389362306a36Sopenharmony_ci const struct rsp_ctrl *rc; 389462306a36Sopenharmony_ci struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); 389562306a36Sopenharmony_ci struct adapter *adapter = q->adap; 389662306a36Sopenharmony_ci struct sge *s = &adapter->sge; 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci while (likely(budget_left)) { 389962306a36Sopenharmony_ci rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc)); 390062306a36Sopenharmony_ci if (!is_new_response(rc, q)) { 390162306a36Sopenharmony_ci if (q->flush_handler) 390262306a36Sopenharmony_ci q->flush_handler(q); 390362306a36Sopenharmony_ci break; 390462306a36Sopenharmony_ci } 390562306a36Sopenharmony_ci 390662306a36Sopenharmony_ci dma_rmb(); 390762306a36Sopenharmony_ci rsp_type = RSPD_TYPE_G(rc->type_gen); 390862306a36Sopenharmony_ci if (likely(rsp_type == RSPD_TYPE_FLBUF_X)) { 390962306a36Sopenharmony_ci struct page_frag *fp; 391062306a36Sopenharmony_ci struct pkt_gl si; 391162306a36Sopenharmony_ci const struct rx_sw_desc *rsd; 391262306a36Sopenharmony_ci u32 len = ntohl(rc->pldbuflen_qid), bufsz, frags; 391362306a36Sopenharmony_ci 391462306a36Sopenharmony_ci if (len & RSPD_NEWBUF_F) { 391562306a36Sopenharmony_ci if (likely(q->offset > 0)) { 391662306a36Sopenharmony_ci free_rx_bufs(q->adap, &rxq->fl, 1); 391762306a36Sopenharmony_ci q->offset = 0; 391862306a36Sopenharmony_ci } 391962306a36Sopenharmony_ci len = RSPD_LEN_G(len); 392062306a36Sopenharmony_ci } 392162306a36Sopenharmony_ci si.tot_len = len; 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_ci /* gather packet fragments */ 392462306a36Sopenharmony_ci for (frags = 0, fp = si.frags; ; frags++, fp++) { 392562306a36Sopenharmony_ci rsd = &rxq->fl.sdesc[rxq->fl.cidx]; 392662306a36Sopenharmony_ci bufsz = get_buf_size(adapter, rsd); 392762306a36Sopenharmony_ci fp->page = rsd->page; 392862306a36Sopenharmony_ci fp->offset = q->offset; 392962306a36Sopenharmony_ci fp->size = min(bufsz, len); 393062306a36Sopenharmony_ci len -= fp->size; 393162306a36Sopenharmony_ci if (!len) 393262306a36Sopenharmony_ci break; 393362306a36Sopenharmony_ci unmap_rx_buf(q->adap, &rxq->fl); 393462306a36Sopenharmony_ci } 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci si.sgetstamp = SGE_TIMESTAMP_G( 393762306a36Sopenharmony_ci be64_to_cpu(rc->last_flit)); 393862306a36Sopenharmony_ci /* 393962306a36Sopenharmony_ci * Last buffer remains mapped so explicitly make it 394062306a36Sopenharmony_ci * coherent for CPU access. 394162306a36Sopenharmony_ci */ 394262306a36Sopenharmony_ci dma_sync_single_for_cpu(q->adap->pdev_dev, 394362306a36Sopenharmony_ci get_buf_addr(rsd), 394462306a36Sopenharmony_ci fp->size, DMA_FROM_DEVICE); 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci si.va = page_address(si.frags[0].page) + 394762306a36Sopenharmony_ci si.frags[0].offset; 394862306a36Sopenharmony_ci prefetch(si.va); 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci si.nfrags = frags + 1; 395162306a36Sopenharmony_ci ret = q->handler(q, q->cur_desc, &si); 395262306a36Sopenharmony_ci if (likely(ret == 0)) 395362306a36Sopenharmony_ci q->offset += ALIGN(fp->size, s->fl_align); 395462306a36Sopenharmony_ci else 395562306a36Sopenharmony_ci restore_rx_bufs(&si, &rxq->fl, frags); 395662306a36Sopenharmony_ci } else if (likely(rsp_type == RSPD_TYPE_CPL_X)) { 395762306a36Sopenharmony_ci ret = q->handler(q, q->cur_desc, NULL); 395862306a36Sopenharmony_ci } else { 395962306a36Sopenharmony_ci ret = q->handler(q, (const __be64 *)rc, CXGB4_MSG_AN); 396062306a36Sopenharmony_ci } 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci if (unlikely(ret)) { 396362306a36Sopenharmony_ci /* couldn't process descriptor, back off for recovery */ 396462306a36Sopenharmony_ci q->next_intr_params = QINTR_TIMER_IDX_V(NOMEM_TMR_IDX); 396562306a36Sopenharmony_ci break; 396662306a36Sopenharmony_ci } 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci rspq_next(q); 396962306a36Sopenharmony_ci budget_left--; 397062306a36Sopenharmony_ci } 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_ci if (q->offset >= 0 && fl_cap(&rxq->fl) - rxq->fl.avail >= 16) 397362306a36Sopenharmony_ci __refill_fl(q->adap, &rxq->fl); 397462306a36Sopenharmony_ci return budget - budget_left; 397562306a36Sopenharmony_ci} 397662306a36Sopenharmony_ci 397762306a36Sopenharmony_ci/** 397862306a36Sopenharmony_ci * napi_rx_handler - the NAPI handler for Rx processing 397962306a36Sopenharmony_ci * @napi: the napi instance 398062306a36Sopenharmony_ci * @budget: how many packets we can process in this round 398162306a36Sopenharmony_ci * 398262306a36Sopenharmony_ci * Handler for new data events when using NAPI. This does not need any 398362306a36Sopenharmony_ci * locking or protection from interrupts as data interrupts are off at 398462306a36Sopenharmony_ci * this point and other adapter interrupts do not interfere (the latter 398562306a36Sopenharmony_ci * in not a concern at all with MSI-X as non-data interrupts then have 398662306a36Sopenharmony_ci * a separate handler). 398762306a36Sopenharmony_ci */ 398862306a36Sopenharmony_cistatic int napi_rx_handler(struct napi_struct *napi, int budget) 398962306a36Sopenharmony_ci{ 399062306a36Sopenharmony_ci unsigned int params; 399162306a36Sopenharmony_ci struct sge_rspq *q = container_of(napi, struct sge_rspq, napi); 399262306a36Sopenharmony_ci int work_done; 399362306a36Sopenharmony_ci u32 val; 399462306a36Sopenharmony_ci 399562306a36Sopenharmony_ci work_done = process_responses(q, budget); 399662306a36Sopenharmony_ci if (likely(work_done < budget)) { 399762306a36Sopenharmony_ci int timer_index; 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci napi_complete_done(napi, work_done); 400062306a36Sopenharmony_ci timer_index = QINTR_TIMER_IDX_G(q->next_intr_params); 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci if (q->adaptive_rx) { 400362306a36Sopenharmony_ci if (work_done > max(timer_pkt_quota[timer_index], 400462306a36Sopenharmony_ci MIN_NAPI_WORK)) 400562306a36Sopenharmony_ci timer_index = (timer_index + 1); 400662306a36Sopenharmony_ci else 400762306a36Sopenharmony_ci timer_index = timer_index - 1; 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_ci timer_index = clamp(timer_index, 0, SGE_TIMERREGS - 1); 401062306a36Sopenharmony_ci q->next_intr_params = 401162306a36Sopenharmony_ci QINTR_TIMER_IDX_V(timer_index) | 401262306a36Sopenharmony_ci QINTR_CNT_EN_V(0); 401362306a36Sopenharmony_ci params = q->next_intr_params; 401462306a36Sopenharmony_ci } else { 401562306a36Sopenharmony_ci params = q->next_intr_params; 401662306a36Sopenharmony_ci q->next_intr_params = q->intr_params; 401762306a36Sopenharmony_ci } 401862306a36Sopenharmony_ci } else 401962306a36Sopenharmony_ci params = QINTR_TIMER_IDX_V(7); 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci val = CIDXINC_V(work_done) | SEINTARM_V(params); 402262306a36Sopenharmony_ci 402362306a36Sopenharmony_ci /* If we don't have access to the new User GTS (T5+), use the old 402462306a36Sopenharmony_ci * doorbell mechanism; otherwise use the new BAR2 mechanism. 402562306a36Sopenharmony_ci */ 402662306a36Sopenharmony_ci if (unlikely(q->bar2_addr == NULL)) { 402762306a36Sopenharmony_ci t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS_A), 402862306a36Sopenharmony_ci val | INGRESSQID_V((u32)q->cntxt_id)); 402962306a36Sopenharmony_ci } else { 403062306a36Sopenharmony_ci writel(val | INGRESSQID_V(q->bar2_qid), 403162306a36Sopenharmony_ci q->bar2_addr + SGE_UDB_GTS); 403262306a36Sopenharmony_ci wmb(); 403362306a36Sopenharmony_ci } 403462306a36Sopenharmony_ci return work_done; 403562306a36Sopenharmony_ci} 403662306a36Sopenharmony_ci 403762306a36Sopenharmony_civoid cxgb4_ethofld_restart(struct tasklet_struct *t) 403862306a36Sopenharmony_ci{ 403962306a36Sopenharmony_ci struct sge_eosw_txq *eosw_txq = from_tasklet(eosw_txq, t, 404062306a36Sopenharmony_ci qresume_tsk); 404162306a36Sopenharmony_ci int pktcount; 404262306a36Sopenharmony_ci 404362306a36Sopenharmony_ci spin_lock(&eosw_txq->lock); 404462306a36Sopenharmony_ci pktcount = eosw_txq->cidx - eosw_txq->last_cidx; 404562306a36Sopenharmony_ci if (pktcount < 0) 404662306a36Sopenharmony_ci pktcount += eosw_txq->ndesc; 404762306a36Sopenharmony_ci 404862306a36Sopenharmony_ci if (pktcount) { 404962306a36Sopenharmony_ci cxgb4_eosw_txq_free_desc(netdev2adap(eosw_txq->netdev), 405062306a36Sopenharmony_ci eosw_txq, pktcount); 405162306a36Sopenharmony_ci eosw_txq->inuse -= pktcount; 405262306a36Sopenharmony_ci } 405362306a36Sopenharmony_ci 405462306a36Sopenharmony_ci /* There may be some packets waiting for completions. So, 405562306a36Sopenharmony_ci * attempt to send these packets now. 405662306a36Sopenharmony_ci */ 405762306a36Sopenharmony_ci ethofld_xmit(eosw_txq->netdev, eosw_txq); 405862306a36Sopenharmony_ci spin_unlock(&eosw_txq->lock); 405962306a36Sopenharmony_ci} 406062306a36Sopenharmony_ci 406162306a36Sopenharmony_ci/* cxgb4_ethofld_rx_handler - Process ETHOFLD Tx completions 406262306a36Sopenharmony_ci * @q: the response queue that received the packet 406362306a36Sopenharmony_ci * @rsp: the response queue descriptor holding the CPL message 406462306a36Sopenharmony_ci * @si: the gather list of packet fragments 406562306a36Sopenharmony_ci * 406662306a36Sopenharmony_ci * Process a ETHOFLD Tx completion. Increment the cidx here, but 406762306a36Sopenharmony_ci * free up the descriptors in a tasklet later. 406862306a36Sopenharmony_ci */ 406962306a36Sopenharmony_ciint cxgb4_ethofld_rx_handler(struct sge_rspq *q, const __be64 *rsp, 407062306a36Sopenharmony_ci const struct pkt_gl *si) 407162306a36Sopenharmony_ci{ 407262306a36Sopenharmony_ci u8 opcode = ((const struct rss_header *)rsp)->opcode; 407362306a36Sopenharmony_ci 407462306a36Sopenharmony_ci /* skip RSS header */ 407562306a36Sopenharmony_ci rsp++; 407662306a36Sopenharmony_ci 407762306a36Sopenharmony_ci if (opcode == CPL_FW4_ACK) { 407862306a36Sopenharmony_ci const struct cpl_fw4_ack *cpl; 407962306a36Sopenharmony_ci struct sge_eosw_txq *eosw_txq; 408062306a36Sopenharmony_ci struct eotid_entry *entry; 408162306a36Sopenharmony_ci struct sk_buff *skb; 408262306a36Sopenharmony_ci u32 hdr_len, eotid; 408362306a36Sopenharmony_ci u8 flits, wrlen16; 408462306a36Sopenharmony_ci int credits; 408562306a36Sopenharmony_ci 408662306a36Sopenharmony_ci cpl = (const struct cpl_fw4_ack *)rsp; 408762306a36Sopenharmony_ci eotid = CPL_FW4_ACK_FLOWID_G(ntohl(OPCODE_TID(cpl))) - 408862306a36Sopenharmony_ci q->adap->tids.eotid_base; 408962306a36Sopenharmony_ci entry = cxgb4_lookup_eotid(&q->adap->tids, eotid); 409062306a36Sopenharmony_ci if (!entry) 409162306a36Sopenharmony_ci goto out_done; 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci eosw_txq = (struct sge_eosw_txq *)entry->data; 409462306a36Sopenharmony_ci if (!eosw_txq) 409562306a36Sopenharmony_ci goto out_done; 409662306a36Sopenharmony_ci 409762306a36Sopenharmony_ci spin_lock(&eosw_txq->lock); 409862306a36Sopenharmony_ci credits = cpl->credits; 409962306a36Sopenharmony_ci while (credits > 0) { 410062306a36Sopenharmony_ci skb = eosw_txq->desc[eosw_txq->cidx].skb; 410162306a36Sopenharmony_ci if (!skb) 410262306a36Sopenharmony_ci break; 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci if (unlikely((eosw_txq->state == 410562306a36Sopenharmony_ci CXGB4_EO_STATE_FLOWC_OPEN_REPLY || 410662306a36Sopenharmony_ci eosw_txq->state == 410762306a36Sopenharmony_ci CXGB4_EO_STATE_FLOWC_CLOSE_REPLY) && 410862306a36Sopenharmony_ci eosw_txq->cidx == eosw_txq->flowc_idx)) { 410962306a36Sopenharmony_ci flits = DIV_ROUND_UP(skb->len, 8); 411062306a36Sopenharmony_ci if (eosw_txq->state == 411162306a36Sopenharmony_ci CXGB4_EO_STATE_FLOWC_OPEN_REPLY) 411262306a36Sopenharmony_ci eosw_txq->state = CXGB4_EO_STATE_ACTIVE; 411362306a36Sopenharmony_ci else 411462306a36Sopenharmony_ci eosw_txq->state = CXGB4_EO_STATE_CLOSED; 411562306a36Sopenharmony_ci complete(&eosw_txq->completion); 411662306a36Sopenharmony_ci } else { 411762306a36Sopenharmony_ci hdr_len = eth_get_headlen(eosw_txq->netdev, 411862306a36Sopenharmony_ci skb->data, 411962306a36Sopenharmony_ci skb_headlen(skb)); 412062306a36Sopenharmony_ci flits = ethofld_calc_tx_flits(q->adap, skb, 412162306a36Sopenharmony_ci hdr_len); 412262306a36Sopenharmony_ci } 412362306a36Sopenharmony_ci eosw_txq_advance_index(&eosw_txq->cidx, 1, 412462306a36Sopenharmony_ci eosw_txq->ndesc); 412562306a36Sopenharmony_ci wrlen16 = DIV_ROUND_UP(flits * 8, 16); 412662306a36Sopenharmony_ci credits -= wrlen16; 412762306a36Sopenharmony_ci } 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_ci eosw_txq->cred += cpl->credits; 413062306a36Sopenharmony_ci eosw_txq->ncompl--; 413162306a36Sopenharmony_ci 413262306a36Sopenharmony_ci spin_unlock(&eosw_txq->lock); 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci /* Schedule a tasklet to reclaim SKBs and restart ETHOFLD Tx, 413562306a36Sopenharmony_ci * if there were packets waiting for completion. 413662306a36Sopenharmony_ci */ 413762306a36Sopenharmony_ci tasklet_schedule(&eosw_txq->qresume_tsk); 413862306a36Sopenharmony_ci } 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ciout_done: 414162306a36Sopenharmony_ci return 0; 414262306a36Sopenharmony_ci} 414362306a36Sopenharmony_ci 414462306a36Sopenharmony_ci/* 414562306a36Sopenharmony_ci * The MSI-X interrupt handler for an SGE response queue. 414662306a36Sopenharmony_ci */ 414762306a36Sopenharmony_ciirqreturn_t t4_sge_intr_msix(int irq, void *cookie) 414862306a36Sopenharmony_ci{ 414962306a36Sopenharmony_ci struct sge_rspq *q = cookie; 415062306a36Sopenharmony_ci 415162306a36Sopenharmony_ci napi_schedule(&q->napi); 415262306a36Sopenharmony_ci return IRQ_HANDLED; 415362306a36Sopenharmony_ci} 415462306a36Sopenharmony_ci 415562306a36Sopenharmony_ci/* 415662306a36Sopenharmony_ci * Process the indirect interrupt entries in the interrupt queue and kick off 415762306a36Sopenharmony_ci * NAPI for each queue that has generated an entry. 415862306a36Sopenharmony_ci */ 415962306a36Sopenharmony_cistatic unsigned int process_intrq(struct adapter *adap) 416062306a36Sopenharmony_ci{ 416162306a36Sopenharmony_ci unsigned int credits; 416262306a36Sopenharmony_ci const struct rsp_ctrl *rc; 416362306a36Sopenharmony_ci struct sge_rspq *q = &adap->sge.intrq; 416462306a36Sopenharmony_ci u32 val; 416562306a36Sopenharmony_ci 416662306a36Sopenharmony_ci spin_lock(&adap->sge.intrq_lock); 416762306a36Sopenharmony_ci for (credits = 0; ; credits++) { 416862306a36Sopenharmony_ci rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc)); 416962306a36Sopenharmony_ci if (!is_new_response(rc, q)) 417062306a36Sopenharmony_ci break; 417162306a36Sopenharmony_ci 417262306a36Sopenharmony_ci dma_rmb(); 417362306a36Sopenharmony_ci if (RSPD_TYPE_G(rc->type_gen) == RSPD_TYPE_INTR_X) { 417462306a36Sopenharmony_ci unsigned int qid = ntohl(rc->pldbuflen_qid); 417562306a36Sopenharmony_ci 417662306a36Sopenharmony_ci qid -= adap->sge.ingr_start; 417762306a36Sopenharmony_ci napi_schedule(&adap->sge.ingr_map[qid]->napi); 417862306a36Sopenharmony_ci } 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ci rspq_next(q); 418162306a36Sopenharmony_ci } 418262306a36Sopenharmony_ci 418362306a36Sopenharmony_ci val = CIDXINC_V(credits) | SEINTARM_V(q->intr_params); 418462306a36Sopenharmony_ci 418562306a36Sopenharmony_ci /* If we don't have access to the new User GTS (T5+), use the old 418662306a36Sopenharmony_ci * doorbell mechanism; otherwise use the new BAR2 mechanism. 418762306a36Sopenharmony_ci */ 418862306a36Sopenharmony_ci if (unlikely(q->bar2_addr == NULL)) { 418962306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), 419062306a36Sopenharmony_ci val | INGRESSQID_V(q->cntxt_id)); 419162306a36Sopenharmony_ci } else { 419262306a36Sopenharmony_ci writel(val | INGRESSQID_V(q->bar2_qid), 419362306a36Sopenharmony_ci q->bar2_addr + SGE_UDB_GTS); 419462306a36Sopenharmony_ci wmb(); 419562306a36Sopenharmony_ci } 419662306a36Sopenharmony_ci spin_unlock(&adap->sge.intrq_lock); 419762306a36Sopenharmony_ci return credits; 419862306a36Sopenharmony_ci} 419962306a36Sopenharmony_ci 420062306a36Sopenharmony_ci/* 420162306a36Sopenharmony_ci * The MSI interrupt handler, which handles data events from SGE response queues 420262306a36Sopenharmony_ci * as well as error and other async events as they all use the same MSI vector. 420362306a36Sopenharmony_ci */ 420462306a36Sopenharmony_cistatic irqreturn_t t4_intr_msi(int irq, void *cookie) 420562306a36Sopenharmony_ci{ 420662306a36Sopenharmony_ci struct adapter *adap = cookie; 420762306a36Sopenharmony_ci 420862306a36Sopenharmony_ci if (adap->flags & CXGB4_MASTER_PF) 420962306a36Sopenharmony_ci t4_slow_intr_handler(adap); 421062306a36Sopenharmony_ci process_intrq(adap); 421162306a36Sopenharmony_ci return IRQ_HANDLED; 421262306a36Sopenharmony_ci} 421362306a36Sopenharmony_ci 421462306a36Sopenharmony_ci/* 421562306a36Sopenharmony_ci * Interrupt handler for legacy INTx interrupts. 421662306a36Sopenharmony_ci * Handles data events from SGE response queues as well as error and other 421762306a36Sopenharmony_ci * async events as they all use the same interrupt line. 421862306a36Sopenharmony_ci */ 421962306a36Sopenharmony_cistatic irqreturn_t t4_intr_intx(int irq, void *cookie) 422062306a36Sopenharmony_ci{ 422162306a36Sopenharmony_ci struct adapter *adap = cookie; 422262306a36Sopenharmony_ci 422362306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI_A), 0); 422462306a36Sopenharmony_ci if (((adap->flags & CXGB4_MASTER_PF) && t4_slow_intr_handler(adap)) | 422562306a36Sopenharmony_ci process_intrq(adap)) 422662306a36Sopenharmony_ci return IRQ_HANDLED; 422762306a36Sopenharmony_ci return IRQ_NONE; /* probably shared interrupt */ 422862306a36Sopenharmony_ci} 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_ci/** 423162306a36Sopenharmony_ci * t4_intr_handler - select the top-level interrupt handler 423262306a36Sopenharmony_ci * @adap: the adapter 423362306a36Sopenharmony_ci * 423462306a36Sopenharmony_ci * Selects the top-level interrupt handler based on the type of interrupts 423562306a36Sopenharmony_ci * (MSI-X, MSI, or INTx). 423662306a36Sopenharmony_ci */ 423762306a36Sopenharmony_ciirq_handler_t t4_intr_handler(struct adapter *adap) 423862306a36Sopenharmony_ci{ 423962306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) 424062306a36Sopenharmony_ci return t4_sge_intr_msix; 424162306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSI) 424262306a36Sopenharmony_ci return t4_intr_msi; 424362306a36Sopenharmony_ci return t4_intr_intx; 424462306a36Sopenharmony_ci} 424562306a36Sopenharmony_ci 424662306a36Sopenharmony_cistatic void sge_rx_timer_cb(struct timer_list *t) 424762306a36Sopenharmony_ci{ 424862306a36Sopenharmony_ci unsigned long m; 424962306a36Sopenharmony_ci unsigned int i; 425062306a36Sopenharmony_ci struct adapter *adap = from_timer(adap, t, sge.rx_timer); 425162306a36Sopenharmony_ci struct sge *s = &adap->sge; 425262306a36Sopenharmony_ci 425362306a36Sopenharmony_ci for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++) 425462306a36Sopenharmony_ci for (m = s->starving_fl[i]; m; m &= m - 1) { 425562306a36Sopenharmony_ci struct sge_eth_rxq *rxq; 425662306a36Sopenharmony_ci unsigned int id = __ffs(m) + i * BITS_PER_LONG; 425762306a36Sopenharmony_ci struct sge_fl *fl = s->egr_map[id]; 425862306a36Sopenharmony_ci 425962306a36Sopenharmony_ci clear_bit(id, s->starving_fl); 426062306a36Sopenharmony_ci smp_mb__after_atomic(); 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci if (fl_starving(adap, fl)) { 426362306a36Sopenharmony_ci rxq = container_of(fl, struct sge_eth_rxq, fl); 426462306a36Sopenharmony_ci if (napi_reschedule(&rxq->rspq.napi)) 426562306a36Sopenharmony_ci fl->starving++; 426662306a36Sopenharmony_ci else 426762306a36Sopenharmony_ci set_bit(id, s->starving_fl); 426862306a36Sopenharmony_ci } 426962306a36Sopenharmony_ci } 427062306a36Sopenharmony_ci /* The remainder of the SGE RX Timer Callback routine is dedicated to 427162306a36Sopenharmony_ci * global Master PF activities like checking for chip ingress stalls, 427262306a36Sopenharmony_ci * etc. 427362306a36Sopenharmony_ci */ 427462306a36Sopenharmony_ci if (!(adap->flags & CXGB4_MASTER_PF)) 427562306a36Sopenharmony_ci goto done; 427662306a36Sopenharmony_ci 427762306a36Sopenharmony_ci t4_idma_monitor(adap, &s->idma_monitor, HZ, RX_QCHECK_PERIOD); 427862306a36Sopenharmony_ci 427962306a36Sopenharmony_cidone: 428062306a36Sopenharmony_ci mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD); 428162306a36Sopenharmony_ci} 428262306a36Sopenharmony_ci 428362306a36Sopenharmony_cistatic void sge_tx_timer_cb(struct timer_list *t) 428462306a36Sopenharmony_ci{ 428562306a36Sopenharmony_ci struct adapter *adap = from_timer(adap, t, sge.tx_timer); 428662306a36Sopenharmony_ci struct sge *s = &adap->sge; 428762306a36Sopenharmony_ci unsigned long m, period; 428862306a36Sopenharmony_ci unsigned int i, budget; 428962306a36Sopenharmony_ci 429062306a36Sopenharmony_ci for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++) 429162306a36Sopenharmony_ci for (m = s->txq_maperr[i]; m; m &= m - 1) { 429262306a36Sopenharmony_ci unsigned long id = __ffs(m) + i * BITS_PER_LONG; 429362306a36Sopenharmony_ci struct sge_uld_txq *txq = s->egr_map[id]; 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_ci clear_bit(id, s->txq_maperr); 429662306a36Sopenharmony_ci tasklet_schedule(&txq->qresume_tsk); 429762306a36Sopenharmony_ci } 429862306a36Sopenharmony_ci 429962306a36Sopenharmony_ci if (!is_t4(adap->params.chip)) { 430062306a36Sopenharmony_ci struct sge_eth_txq *q = &s->ptptxq; 430162306a36Sopenharmony_ci int avail; 430262306a36Sopenharmony_ci 430362306a36Sopenharmony_ci spin_lock(&adap->ptp_lock); 430462306a36Sopenharmony_ci avail = reclaimable(&q->q); 430562306a36Sopenharmony_ci 430662306a36Sopenharmony_ci if (avail) { 430762306a36Sopenharmony_ci free_tx_desc(adap, &q->q, avail, false); 430862306a36Sopenharmony_ci q->q.in_use -= avail; 430962306a36Sopenharmony_ci } 431062306a36Sopenharmony_ci spin_unlock(&adap->ptp_lock); 431162306a36Sopenharmony_ci } 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_ci budget = MAX_TIMER_TX_RECLAIM; 431462306a36Sopenharmony_ci i = s->ethtxq_rover; 431562306a36Sopenharmony_ci do { 431662306a36Sopenharmony_ci budget -= t4_sge_eth_txq_egress_update(adap, &s->ethtxq[i], 431762306a36Sopenharmony_ci budget); 431862306a36Sopenharmony_ci if (!budget) 431962306a36Sopenharmony_ci break; 432062306a36Sopenharmony_ci 432162306a36Sopenharmony_ci if (++i >= s->ethqsets) 432262306a36Sopenharmony_ci i = 0; 432362306a36Sopenharmony_ci } while (i != s->ethtxq_rover); 432462306a36Sopenharmony_ci s->ethtxq_rover = i; 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_ci if (budget == 0) { 432762306a36Sopenharmony_ci /* If we found too many reclaimable packets schedule a timer 432862306a36Sopenharmony_ci * in the near future to continue where we left off. 432962306a36Sopenharmony_ci */ 433062306a36Sopenharmony_ci period = 2; 433162306a36Sopenharmony_ci } else { 433262306a36Sopenharmony_ci /* We reclaimed all reclaimable TX Descriptors, so reschedule 433362306a36Sopenharmony_ci * at the normal period. 433462306a36Sopenharmony_ci */ 433562306a36Sopenharmony_ci period = TX_QCHECK_PERIOD; 433662306a36Sopenharmony_ci } 433762306a36Sopenharmony_ci 433862306a36Sopenharmony_ci mod_timer(&s->tx_timer, jiffies + period); 433962306a36Sopenharmony_ci} 434062306a36Sopenharmony_ci 434162306a36Sopenharmony_ci/** 434262306a36Sopenharmony_ci * bar2_address - return the BAR2 address for an SGE Queue's Registers 434362306a36Sopenharmony_ci * @adapter: the adapter 434462306a36Sopenharmony_ci * @qid: the SGE Queue ID 434562306a36Sopenharmony_ci * @qtype: the SGE Queue Type (Egress or Ingress) 434662306a36Sopenharmony_ci * @pbar2_qid: BAR2 Queue ID or 0 for Queue ID inferred SGE Queues 434762306a36Sopenharmony_ci * 434862306a36Sopenharmony_ci * Returns the BAR2 address for the SGE Queue Registers associated with 434962306a36Sopenharmony_ci * @qid. If BAR2 SGE Registers aren't available, returns NULL. Also 435062306a36Sopenharmony_ci * returns the BAR2 Queue ID to be used with writes to the BAR2 SGE 435162306a36Sopenharmony_ci * Queue Registers. If the BAR2 Queue ID is 0, then "Inferred Queue ID" 435262306a36Sopenharmony_ci * Registers are supported (e.g. the Write Combining Doorbell Buffer). 435362306a36Sopenharmony_ci */ 435462306a36Sopenharmony_cistatic void __iomem *bar2_address(struct adapter *adapter, 435562306a36Sopenharmony_ci unsigned int qid, 435662306a36Sopenharmony_ci enum t4_bar2_qtype qtype, 435762306a36Sopenharmony_ci unsigned int *pbar2_qid) 435862306a36Sopenharmony_ci{ 435962306a36Sopenharmony_ci u64 bar2_qoffset; 436062306a36Sopenharmony_ci int ret; 436162306a36Sopenharmony_ci 436262306a36Sopenharmony_ci ret = t4_bar2_sge_qregs(adapter, qid, qtype, 0, 436362306a36Sopenharmony_ci &bar2_qoffset, pbar2_qid); 436462306a36Sopenharmony_ci if (ret) 436562306a36Sopenharmony_ci return NULL; 436662306a36Sopenharmony_ci 436762306a36Sopenharmony_ci return adapter->bar2 + bar2_qoffset; 436862306a36Sopenharmony_ci} 436962306a36Sopenharmony_ci 437062306a36Sopenharmony_ci/* @intr_idx: MSI/MSI-X vector if >=0, -(absolute qid + 1) if < 0 437162306a36Sopenharmony_ci * @cong: < 0 -> no congestion feedback, >= 0 -> congestion channel map 437262306a36Sopenharmony_ci */ 437362306a36Sopenharmony_ciint t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, 437462306a36Sopenharmony_ci struct net_device *dev, int intr_idx, 437562306a36Sopenharmony_ci struct sge_fl *fl, rspq_handler_t hnd, 437662306a36Sopenharmony_ci rspq_flush_handler_t flush_hnd, int cong) 437762306a36Sopenharmony_ci{ 437862306a36Sopenharmony_ci int ret, flsz = 0; 437962306a36Sopenharmony_ci struct fw_iq_cmd c; 438062306a36Sopenharmony_ci struct sge *s = &adap->sge; 438162306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 438262306a36Sopenharmony_ci int relaxed = !(adap->flags & CXGB4_ROOT_NO_RELAXED_ORDERING); 438362306a36Sopenharmony_ci 438462306a36Sopenharmony_ci /* Size needs to be multiple of 16, including status entry. */ 438562306a36Sopenharmony_ci iq->size = roundup(iq->size, 16); 438662306a36Sopenharmony_ci 438762306a36Sopenharmony_ci iq->desc = alloc_ring(adap->pdev_dev, iq->size, iq->iqe_len, 0, 438862306a36Sopenharmony_ci &iq->phys_addr, NULL, 0, 438962306a36Sopenharmony_ci dev_to_node(adap->pdev_dev)); 439062306a36Sopenharmony_ci if (!iq->desc) 439162306a36Sopenharmony_ci return -ENOMEM; 439262306a36Sopenharmony_ci 439362306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 439462306a36Sopenharmony_ci c.op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F | 439562306a36Sopenharmony_ci FW_CMD_WRITE_F | FW_CMD_EXEC_F | 439662306a36Sopenharmony_ci FW_IQ_CMD_PFN_V(adap->pf) | FW_IQ_CMD_VFN_V(0)); 439762306a36Sopenharmony_ci c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC_F | FW_IQ_CMD_IQSTART_F | 439862306a36Sopenharmony_ci FW_LEN16(c)); 439962306a36Sopenharmony_ci c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE_V(FW_IQ_TYPE_FL_INT_CAP) | 440062306a36Sopenharmony_ci FW_IQ_CMD_IQASYNCH_V(fwevtq) | FW_IQ_CMD_VIID_V(pi->viid) | 440162306a36Sopenharmony_ci FW_IQ_CMD_IQANDST_V(intr_idx < 0) | 440262306a36Sopenharmony_ci FW_IQ_CMD_IQANUD_V(UPDATEDELIVERY_INTERRUPT_X) | 440362306a36Sopenharmony_ci FW_IQ_CMD_IQANDSTINDEX_V(intr_idx >= 0 ? intr_idx : 440462306a36Sopenharmony_ci -intr_idx - 1)); 440562306a36Sopenharmony_ci c.iqdroprss_to_iqesize = htons(FW_IQ_CMD_IQPCIECH_V(pi->tx_chan) | 440662306a36Sopenharmony_ci FW_IQ_CMD_IQGTSMODE_F | 440762306a36Sopenharmony_ci FW_IQ_CMD_IQINTCNTTHRESH_V(iq->pktcnt_idx) | 440862306a36Sopenharmony_ci FW_IQ_CMD_IQESIZE_V(ilog2(iq->iqe_len) - 4)); 440962306a36Sopenharmony_ci c.iqsize = htons(iq->size); 441062306a36Sopenharmony_ci c.iqaddr = cpu_to_be64(iq->phys_addr); 441162306a36Sopenharmony_ci if (cong >= 0) 441262306a36Sopenharmony_ci c.iqns_to_fl0congen = htonl(FW_IQ_CMD_IQFLINTCONGEN_F | 441362306a36Sopenharmony_ci FW_IQ_CMD_IQTYPE_V(cong ? FW_IQ_IQTYPE_NIC 441462306a36Sopenharmony_ci : FW_IQ_IQTYPE_OFLD)); 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci if (fl) { 441762306a36Sopenharmony_ci unsigned int chip_ver = 441862306a36Sopenharmony_ci CHELSIO_CHIP_VERSION(adap->params.chip); 441962306a36Sopenharmony_ci 442062306a36Sopenharmony_ci /* Allocate the ring for the hardware free list (with space 442162306a36Sopenharmony_ci * for its status page) along with the associated software 442262306a36Sopenharmony_ci * descriptor ring. The free list size needs to be a multiple 442362306a36Sopenharmony_ci * of the Egress Queue Unit and at least 2 Egress Units larger 442462306a36Sopenharmony_ci * than the SGE's Egress Congrestion Threshold 442562306a36Sopenharmony_ci * (fl_starve_thres - 1). 442662306a36Sopenharmony_ci */ 442762306a36Sopenharmony_ci if (fl->size < s->fl_starve_thres - 1 + 2 * 8) 442862306a36Sopenharmony_ci fl->size = s->fl_starve_thres - 1 + 2 * 8; 442962306a36Sopenharmony_ci fl->size = roundup(fl->size, 8); 443062306a36Sopenharmony_ci fl->desc = alloc_ring(adap->pdev_dev, fl->size, sizeof(__be64), 443162306a36Sopenharmony_ci sizeof(struct rx_sw_desc), &fl->addr, 443262306a36Sopenharmony_ci &fl->sdesc, s->stat_len, 443362306a36Sopenharmony_ci dev_to_node(adap->pdev_dev)); 443462306a36Sopenharmony_ci if (!fl->desc) 443562306a36Sopenharmony_ci goto fl_nomem; 443662306a36Sopenharmony_ci 443762306a36Sopenharmony_ci flsz = fl->size / 8 + s->stat_len / sizeof(struct tx_desc); 443862306a36Sopenharmony_ci c.iqns_to_fl0congen |= htonl(FW_IQ_CMD_FL0PACKEN_F | 443962306a36Sopenharmony_ci FW_IQ_CMD_FL0FETCHRO_V(relaxed) | 444062306a36Sopenharmony_ci FW_IQ_CMD_FL0DATARO_V(relaxed) | 444162306a36Sopenharmony_ci FW_IQ_CMD_FL0PADEN_F); 444262306a36Sopenharmony_ci if (cong >= 0) 444362306a36Sopenharmony_ci c.iqns_to_fl0congen |= 444462306a36Sopenharmony_ci htonl(FW_IQ_CMD_FL0CNGCHMAP_V(cong) | 444562306a36Sopenharmony_ci FW_IQ_CMD_FL0CONGCIF_F | 444662306a36Sopenharmony_ci FW_IQ_CMD_FL0CONGEN_F); 444762306a36Sopenharmony_ci /* In T6, for egress queue type FL there is internal overhead 444862306a36Sopenharmony_ci * of 16B for header going into FLM module. Hence the maximum 444962306a36Sopenharmony_ci * allowed burst size is 448 bytes. For T4/T5, the hardware 445062306a36Sopenharmony_ci * doesn't coalesce fetch requests if more than 64 bytes of 445162306a36Sopenharmony_ci * Free List pointers are provided, so we use a 128-byte Fetch 445262306a36Sopenharmony_ci * Burst Minimum there (T6 implements coalescing so we can use 445362306a36Sopenharmony_ci * the smaller 64-byte value there). 445462306a36Sopenharmony_ci */ 445562306a36Sopenharmony_ci c.fl0dcaen_to_fl0cidxfthresh = 445662306a36Sopenharmony_ci htons(FW_IQ_CMD_FL0FBMIN_V(chip_ver <= CHELSIO_T5 ? 445762306a36Sopenharmony_ci FETCHBURSTMIN_128B_X : 445862306a36Sopenharmony_ci FETCHBURSTMIN_64B_T6_X) | 445962306a36Sopenharmony_ci FW_IQ_CMD_FL0FBMAX_V((chip_ver <= CHELSIO_T5) ? 446062306a36Sopenharmony_ci FETCHBURSTMAX_512B_X : 446162306a36Sopenharmony_ci FETCHBURSTMAX_256B_X)); 446262306a36Sopenharmony_ci c.fl0size = htons(flsz); 446362306a36Sopenharmony_ci c.fl0addr = cpu_to_be64(fl->addr); 446462306a36Sopenharmony_ci } 446562306a36Sopenharmony_ci 446662306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c); 446762306a36Sopenharmony_ci if (ret) 446862306a36Sopenharmony_ci goto err; 446962306a36Sopenharmony_ci 447062306a36Sopenharmony_ci netif_napi_add(dev, &iq->napi, napi_rx_handler); 447162306a36Sopenharmony_ci iq->cur_desc = iq->desc; 447262306a36Sopenharmony_ci iq->cidx = 0; 447362306a36Sopenharmony_ci iq->gen = 1; 447462306a36Sopenharmony_ci iq->next_intr_params = iq->intr_params; 447562306a36Sopenharmony_ci iq->cntxt_id = ntohs(c.iqid); 447662306a36Sopenharmony_ci iq->abs_id = ntohs(c.physiqid); 447762306a36Sopenharmony_ci iq->bar2_addr = bar2_address(adap, 447862306a36Sopenharmony_ci iq->cntxt_id, 447962306a36Sopenharmony_ci T4_BAR2_QTYPE_INGRESS, 448062306a36Sopenharmony_ci &iq->bar2_qid); 448162306a36Sopenharmony_ci iq->size--; /* subtract status entry */ 448262306a36Sopenharmony_ci iq->netdev = dev; 448362306a36Sopenharmony_ci iq->handler = hnd; 448462306a36Sopenharmony_ci iq->flush_handler = flush_hnd; 448562306a36Sopenharmony_ci 448662306a36Sopenharmony_ci memset(&iq->lro_mgr, 0, sizeof(struct t4_lro_mgr)); 448762306a36Sopenharmony_ci skb_queue_head_init(&iq->lro_mgr.lroq); 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci /* set offset to -1 to distinguish ingress queues without FL */ 449062306a36Sopenharmony_ci iq->offset = fl ? 0 : -1; 449162306a36Sopenharmony_ci 449262306a36Sopenharmony_ci adap->sge.ingr_map[iq->cntxt_id - adap->sge.ingr_start] = iq; 449362306a36Sopenharmony_ci 449462306a36Sopenharmony_ci if (fl) { 449562306a36Sopenharmony_ci fl->cntxt_id = ntohs(c.fl0id); 449662306a36Sopenharmony_ci fl->avail = fl->pend_cred = 0; 449762306a36Sopenharmony_ci fl->pidx = fl->cidx = 0; 449862306a36Sopenharmony_ci fl->alloc_failed = fl->large_alloc_failed = fl->starving = 0; 449962306a36Sopenharmony_ci adap->sge.egr_map[fl->cntxt_id - adap->sge.egr_start] = fl; 450062306a36Sopenharmony_ci 450162306a36Sopenharmony_ci /* Note, we must initialize the BAR2 Free List User Doorbell 450262306a36Sopenharmony_ci * information before refilling the Free List! 450362306a36Sopenharmony_ci */ 450462306a36Sopenharmony_ci fl->bar2_addr = bar2_address(adap, 450562306a36Sopenharmony_ci fl->cntxt_id, 450662306a36Sopenharmony_ci T4_BAR2_QTYPE_EGRESS, 450762306a36Sopenharmony_ci &fl->bar2_qid); 450862306a36Sopenharmony_ci refill_fl(adap, fl, fl_cap(fl), GFP_KERNEL); 450962306a36Sopenharmony_ci } 451062306a36Sopenharmony_ci 451162306a36Sopenharmony_ci /* For T5 and later we attempt to set up the Congestion Manager values 451262306a36Sopenharmony_ci * of the new RX Ethernet Queue. This should really be handled by 451362306a36Sopenharmony_ci * firmware because it's more complex than any host driver wants to 451462306a36Sopenharmony_ci * get involved with and it's different per chip and this is almost 451562306a36Sopenharmony_ci * certainly wrong. Firmware would be wrong as well, but it would be 451662306a36Sopenharmony_ci * a lot easier to fix in one place ... For now we do something very 451762306a36Sopenharmony_ci * simple (and hopefully less wrong). 451862306a36Sopenharmony_ci */ 451962306a36Sopenharmony_ci if (!is_t4(adap->params.chip) && cong >= 0) { 452062306a36Sopenharmony_ci u32 param, val, ch_map = 0; 452162306a36Sopenharmony_ci int i; 452262306a36Sopenharmony_ci u16 cng_ch_bits_log = adap->params.arch.cng_ch_bits_log; 452362306a36Sopenharmony_ci 452462306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 452562306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DMAQ_CONM_CTXT) | 452662306a36Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(iq->cntxt_id)); 452762306a36Sopenharmony_ci if (cong == 0) { 452862306a36Sopenharmony_ci val = CONMCTXT_CNGTPMODE_V(CONMCTXT_CNGTPMODE_QUEUE_X); 452962306a36Sopenharmony_ci } else { 453062306a36Sopenharmony_ci val = 453162306a36Sopenharmony_ci CONMCTXT_CNGTPMODE_V(CONMCTXT_CNGTPMODE_CHANNEL_X); 453262306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 453362306a36Sopenharmony_ci if (cong & (1 << i)) 453462306a36Sopenharmony_ci ch_map |= 1 << (i << cng_ch_bits_log); 453562306a36Sopenharmony_ci } 453662306a36Sopenharmony_ci val |= CONMCTXT_CNGCHMAP_V(ch_map); 453762306a36Sopenharmony_ci } 453862306a36Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, 453962306a36Sopenharmony_ci ¶m, &val); 454062306a36Sopenharmony_ci if (ret) 454162306a36Sopenharmony_ci dev_warn(adap->pdev_dev, "Failed to set Congestion" 454262306a36Sopenharmony_ci " Manager Context for Ingress Queue %d: %d\n", 454362306a36Sopenharmony_ci iq->cntxt_id, -ret); 454462306a36Sopenharmony_ci } 454562306a36Sopenharmony_ci 454662306a36Sopenharmony_ci return 0; 454762306a36Sopenharmony_ci 454862306a36Sopenharmony_cifl_nomem: 454962306a36Sopenharmony_ci ret = -ENOMEM; 455062306a36Sopenharmony_cierr: 455162306a36Sopenharmony_ci if (iq->desc) { 455262306a36Sopenharmony_ci dma_free_coherent(adap->pdev_dev, iq->size * iq->iqe_len, 455362306a36Sopenharmony_ci iq->desc, iq->phys_addr); 455462306a36Sopenharmony_ci iq->desc = NULL; 455562306a36Sopenharmony_ci } 455662306a36Sopenharmony_ci if (fl && fl->desc) { 455762306a36Sopenharmony_ci kfree(fl->sdesc); 455862306a36Sopenharmony_ci fl->sdesc = NULL; 455962306a36Sopenharmony_ci dma_free_coherent(adap->pdev_dev, flsz * sizeof(struct tx_desc), 456062306a36Sopenharmony_ci fl->desc, fl->addr); 456162306a36Sopenharmony_ci fl->desc = NULL; 456262306a36Sopenharmony_ci } 456362306a36Sopenharmony_ci return ret; 456462306a36Sopenharmony_ci} 456562306a36Sopenharmony_ci 456662306a36Sopenharmony_cistatic void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id) 456762306a36Sopenharmony_ci{ 456862306a36Sopenharmony_ci q->cntxt_id = id; 456962306a36Sopenharmony_ci q->bar2_addr = bar2_address(adap, 457062306a36Sopenharmony_ci q->cntxt_id, 457162306a36Sopenharmony_ci T4_BAR2_QTYPE_EGRESS, 457262306a36Sopenharmony_ci &q->bar2_qid); 457362306a36Sopenharmony_ci q->in_use = 0; 457462306a36Sopenharmony_ci q->cidx = q->pidx = 0; 457562306a36Sopenharmony_ci q->stops = q->restarts = 0; 457662306a36Sopenharmony_ci q->stat = (void *)&q->desc[q->size]; 457762306a36Sopenharmony_ci spin_lock_init(&q->db_lock); 457862306a36Sopenharmony_ci adap->sge.egr_map[id - adap->sge.egr_start] = q; 457962306a36Sopenharmony_ci} 458062306a36Sopenharmony_ci 458162306a36Sopenharmony_ci/** 458262306a36Sopenharmony_ci * t4_sge_alloc_eth_txq - allocate an Ethernet TX Queue 458362306a36Sopenharmony_ci * @adap: the adapter 458462306a36Sopenharmony_ci * @txq: the SGE Ethernet TX Queue to initialize 458562306a36Sopenharmony_ci * @dev: the Linux Network Device 458662306a36Sopenharmony_ci * @netdevq: the corresponding Linux TX Queue 458762306a36Sopenharmony_ci * @iqid: the Ingress Queue to which to deliver CIDX Update messages 458862306a36Sopenharmony_ci * @dbqt: whether this TX Queue will use the SGE Doorbell Queue Timers 458962306a36Sopenharmony_ci */ 459062306a36Sopenharmony_ciint t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, 459162306a36Sopenharmony_ci struct net_device *dev, struct netdev_queue *netdevq, 459262306a36Sopenharmony_ci unsigned int iqid, u8 dbqt) 459362306a36Sopenharmony_ci{ 459462306a36Sopenharmony_ci unsigned int chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); 459562306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 459662306a36Sopenharmony_ci struct sge *s = &adap->sge; 459762306a36Sopenharmony_ci struct fw_eq_eth_cmd c; 459862306a36Sopenharmony_ci int ret, nentries; 459962306a36Sopenharmony_ci 460062306a36Sopenharmony_ci /* Add status entries */ 460162306a36Sopenharmony_ci nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc); 460262306a36Sopenharmony_ci 460362306a36Sopenharmony_ci txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, 460462306a36Sopenharmony_ci sizeof(struct tx_desc), sizeof(struct tx_sw_desc), 460562306a36Sopenharmony_ci &txq->q.phys_addr, &txq->q.sdesc, s->stat_len, 460662306a36Sopenharmony_ci netdev_queue_numa_node_read(netdevq)); 460762306a36Sopenharmony_ci if (!txq->q.desc) 460862306a36Sopenharmony_ci return -ENOMEM; 460962306a36Sopenharmony_ci 461062306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 461162306a36Sopenharmony_ci c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_ETH_CMD) | FW_CMD_REQUEST_F | 461262306a36Sopenharmony_ci FW_CMD_WRITE_F | FW_CMD_EXEC_F | 461362306a36Sopenharmony_ci FW_EQ_ETH_CMD_PFN_V(adap->pf) | 461462306a36Sopenharmony_ci FW_EQ_ETH_CMD_VFN_V(0)); 461562306a36Sopenharmony_ci c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC_F | 461662306a36Sopenharmony_ci FW_EQ_ETH_CMD_EQSTART_F | FW_LEN16(c)); 461762306a36Sopenharmony_ci 461862306a36Sopenharmony_ci /* For TX Ethernet Queues using the SGE Doorbell Queue Timer 461962306a36Sopenharmony_ci * mechanism, we use Ingress Queue messages for Hardware Consumer 462062306a36Sopenharmony_ci * Index Updates on the TX Queue. Otherwise we have the Hardware 462162306a36Sopenharmony_ci * write the CIDX Updates into the Status Page at the end of the 462262306a36Sopenharmony_ci * TX Queue. 462362306a36Sopenharmony_ci */ 462462306a36Sopenharmony_ci c.autoequiqe_to_viid = htonl(((chip_ver <= CHELSIO_T5) ? 462562306a36Sopenharmony_ci FW_EQ_ETH_CMD_AUTOEQUIQE_F : 462662306a36Sopenharmony_ci FW_EQ_ETH_CMD_AUTOEQUEQE_F) | 462762306a36Sopenharmony_ci FW_EQ_ETH_CMD_VIID_V(pi->viid)); 462862306a36Sopenharmony_ci 462962306a36Sopenharmony_ci c.fetchszm_to_iqid = 463062306a36Sopenharmony_ci htonl(FW_EQ_ETH_CMD_HOSTFCMODE_V((chip_ver <= CHELSIO_T5) ? 463162306a36Sopenharmony_ci HOSTFCMODE_INGRESS_QUEUE_X : 463262306a36Sopenharmony_ci HOSTFCMODE_STATUS_PAGE_X) | 463362306a36Sopenharmony_ci FW_EQ_ETH_CMD_PCIECHN_V(pi->tx_chan) | 463462306a36Sopenharmony_ci FW_EQ_ETH_CMD_FETCHRO_F | FW_EQ_ETH_CMD_IQID_V(iqid)); 463562306a36Sopenharmony_ci 463662306a36Sopenharmony_ci /* Note that the CIDX Flush Threshold should match MAX_TX_RECLAIM. */ 463762306a36Sopenharmony_ci c.dcaen_to_eqsize = 463862306a36Sopenharmony_ci htonl(FW_EQ_ETH_CMD_FBMIN_V(chip_ver <= CHELSIO_T5 463962306a36Sopenharmony_ci ? FETCHBURSTMIN_64B_X 464062306a36Sopenharmony_ci : FETCHBURSTMIN_64B_T6_X) | 464162306a36Sopenharmony_ci FW_EQ_ETH_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) | 464262306a36Sopenharmony_ci FW_EQ_ETH_CMD_CIDXFTHRESH_V(CIDXFLUSHTHRESH_32_X) | 464362306a36Sopenharmony_ci FW_EQ_ETH_CMD_CIDXFTHRESHO_V(chip_ver == CHELSIO_T5) | 464462306a36Sopenharmony_ci FW_EQ_ETH_CMD_EQSIZE_V(nentries)); 464562306a36Sopenharmony_ci 464662306a36Sopenharmony_ci c.eqaddr = cpu_to_be64(txq->q.phys_addr); 464762306a36Sopenharmony_ci 464862306a36Sopenharmony_ci /* If we're using the SGE Doorbell Queue Timer mechanism, pass in the 464962306a36Sopenharmony_ci * currently configured Timer Index. THis can be changed later via an 465062306a36Sopenharmony_ci * ethtool -C tx-usecs {Timer Val} command. Note that the SGE 465162306a36Sopenharmony_ci * Doorbell Queue mode is currently automatically enabled in the 465262306a36Sopenharmony_ci * Firmware by setting either AUTOEQUEQE or AUTOEQUIQE ... 465362306a36Sopenharmony_ci */ 465462306a36Sopenharmony_ci if (dbqt) 465562306a36Sopenharmony_ci c.timeren_timerix = 465662306a36Sopenharmony_ci cpu_to_be32(FW_EQ_ETH_CMD_TIMEREN_F | 465762306a36Sopenharmony_ci FW_EQ_ETH_CMD_TIMERIX_V(txq->dbqtimerix)); 465862306a36Sopenharmony_ci 465962306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c); 466062306a36Sopenharmony_ci if (ret) { 466162306a36Sopenharmony_ci kfree(txq->q.sdesc); 466262306a36Sopenharmony_ci txq->q.sdesc = NULL; 466362306a36Sopenharmony_ci dma_free_coherent(adap->pdev_dev, 466462306a36Sopenharmony_ci nentries * sizeof(struct tx_desc), 466562306a36Sopenharmony_ci txq->q.desc, txq->q.phys_addr); 466662306a36Sopenharmony_ci txq->q.desc = NULL; 466762306a36Sopenharmony_ci return ret; 466862306a36Sopenharmony_ci } 466962306a36Sopenharmony_ci 467062306a36Sopenharmony_ci txq->q.q_type = CXGB4_TXQ_ETH; 467162306a36Sopenharmony_ci init_txq(adap, &txq->q, FW_EQ_ETH_CMD_EQID_G(ntohl(c.eqid_pkd))); 467262306a36Sopenharmony_ci txq->txq = netdevq; 467362306a36Sopenharmony_ci txq->tso = 0; 467462306a36Sopenharmony_ci txq->uso = 0; 467562306a36Sopenharmony_ci txq->tx_cso = 0; 467662306a36Sopenharmony_ci txq->vlan_ins = 0; 467762306a36Sopenharmony_ci txq->mapping_err = 0; 467862306a36Sopenharmony_ci txq->dbqt = dbqt; 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci return 0; 468162306a36Sopenharmony_ci} 468262306a36Sopenharmony_ci 468362306a36Sopenharmony_ciint t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq, 468462306a36Sopenharmony_ci struct net_device *dev, unsigned int iqid, 468562306a36Sopenharmony_ci unsigned int cmplqid) 468662306a36Sopenharmony_ci{ 468762306a36Sopenharmony_ci unsigned int chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); 468862306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 468962306a36Sopenharmony_ci struct sge *s = &adap->sge; 469062306a36Sopenharmony_ci struct fw_eq_ctrl_cmd c; 469162306a36Sopenharmony_ci int ret, nentries; 469262306a36Sopenharmony_ci 469362306a36Sopenharmony_ci /* Add status entries */ 469462306a36Sopenharmony_ci nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc); 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci txq->q.desc = alloc_ring(adap->pdev_dev, nentries, 469762306a36Sopenharmony_ci sizeof(struct tx_desc), 0, &txq->q.phys_addr, 469862306a36Sopenharmony_ci NULL, 0, dev_to_node(adap->pdev_dev)); 469962306a36Sopenharmony_ci if (!txq->q.desc) 470062306a36Sopenharmony_ci return -ENOMEM; 470162306a36Sopenharmony_ci 470262306a36Sopenharmony_ci c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST_F | 470362306a36Sopenharmony_ci FW_CMD_WRITE_F | FW_CMD_EXEC_F | 470462306a36Sopenharmony_ci FW_EQ_CTRL_CMD_PFN_V(adap->pf) | 470562306a36Sopenharmony_ci FW_EQ_CTRL_CMD_VFN_V(0)); 470662306a36Sopenharmony_ci c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC_F | 470762306a36Sopenharmony_ci FW_EQ_CTRL_CMD_EQSTART_F | FW_LEN16(c)); 470862306a36Sopenharmony_ci c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_CMPLIQID_V(cmplqid)); 470962306a36Sopenharmony_ci c.physeqid_pkd = htonl(0); 471062306a36Sopenharmony_ci c.fetchszm_to_iqid = 471162306a36Sopenharmony_ci htonl(FW_EQ_CTRL_CMD_HOSTFCMODE_V(HOSTFCMODE_STATUS_PAGE_X) | 471262306a36Sopenharmony_ci FW_EQ_CTRL_CMD_PCIECHN_V(pi->tx_chan) | 471362306a36Sopenharmony_ci FW_EQ_CTRL_CMD_FETCHRO_F | FW_EQ_CTRL_CMD_IQID_V(iqid)); 471462306a36Sopenharmony_ci c.dcaen_to_eqsize = 471562306a36Sopenharmony_ci htonl(FW_EQ_CTRL_CMD_FBMIN_V(chip_ver <= CHELSIO_T5 471662306a36Sopenharmony_ci ? FETCHBURSTMIN_64B_X 471762306a36Sopenharmony_ci : FETCHBURSTMIN_64B_T6_X) | 471862306a36Sopenharmony_ci FW_EQ_CTRL_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) | 471962306a36Sopenharmony_ci FW_EQ_CTRL_CMD_CIDXFTHRESH_V(CIDXFLUSHTHRESH_32_X) | 472062306a36Sopenharmony_ci FW_EQ_CTRL_CMD_EQSIZE_V(nentries)); 472162306a36Sopenharmony_ci c.eqaddr = cpu_to_be64(txq->q.phys_addr); 472262306a36Sopenharmony_ci 472362306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c); 472462306a36Sopenharmony_ci if (ret) { 472562306a36Sopenharmony_ci dma_free_coherent(adap->pdev_dev, 472662306a36Sopenharmony_ci nentries * sizeof(struct tx_desc), 472762306a36Sopenharmony_ci txq->q.desc, txq->q.phys_addr); 472862306a36Sopenharmony_ci txq->q.desc = NULL; 472962306a36Sopenharmony_ci return ret; 473062306a36Sopenharmony_ci } 473162306a36Sopenharmony_ci 473262306a36Sopenharmony_ci txq->q.q_type = CXGB4_TXQ_CTRL; 473362306a36Sopenharmony_ci init_txq(adap, &txq->q, FW_EQ_CTRL_CMD_EQID_G(ntohl(c.cmpliqid_eqid))); 473462306a36Sopenharmony_ci txq->adap = adap; 473562306a36Sopenharmony_ci skb_queue_head_init(&txq->sendq); 473662306a36Sopenharmony_ci tasklet_setup(&txq->qresume_tsk, restart_ctrlq); 473762306a36Sopenharmony_ci txq->full = 0; 473862306a36Sopenharmony_ci return 0; 473962306a36Sopenharmony_ci} 474062306a36Sopenharmony_ci 474162306a36Sopenharmony_ciint t4_sge_mod_ctrl_txq(struct adapter *adap, unsigned int eqid, 474262306a36Sopenharmony_ci unsigned int cmplqid) 474362306a36Sopenharmony_ci{ 474462306a36Sopenharmony_ci u32 param, val; 474562306a36Sopenharmony_ci 474662306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 474762306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_CTRL) | 474862306a36Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(eqid)); 474962306a36Sopenharmony_ci val = cmplqid; 475062306a36Sopenharmony_ci return t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); 475162306a36Sopenharmony_ci} 475262306a36Sopenharmony_ci 475362306a36Sopenharmony_cistatic int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_txq *q, 475462306a36Sopenharmony_ci struct net_device *dev, u32 cmd, u32 iqid) 475562306a36Sopenharmony_ci{ 475662306a36Sopenharmony_ci unsigned int chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); 475762306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 475862306a36Sopenharmony_ci struct sge *s = &adap->sge; 475962306a36Sopenharmony_ci struct fw_eq_ofld_cmd c; 476062306a36Sopenharmony_ci u32 fb_min, nentries; 476162306a36Sopenharmony_ci int ret; 476262306a36Sopenharmony_ci 476362306a36Sopenharmony_ci /* Add status entries */ 476462306a36Sopenharmony_ci nentries = q->size + s->stat_len / sizeof(struct tx_desc); 476562306a36Sopenharmony_ci q->desc = alloc_ring(adap->pdev_dev, q->size, sizeof(struct tx_desc), 476662306a36Sopenharmony_ci sizeof(struct tx_sw_desc), &q->phys_addr, 476762306a36Sopenharmony_ci &q->sdesc, s->stat_len, NUMA_NO_NODE); 476862306a36Sopenharmony_ci if (!q->desc) 476962306a36Sopenharmony_ci return -ENOMEM; 477062306a36Sopenharmony_ci 477162306a36Sopenharmony_ci if (chip_ver <= CHELSIO_T5) 477262306a36Sopenharmony_ci fb_min = FETCHBURSTMIN_64B_X; 477362306a36Sopenharmony_ci else 477462306a36Sopenharmony_ci fb_min = FETCHBURSTMIN_64B_T6_X; 477562306a36Sopenharmony_ci 477662306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 477762306a36Sopenharmony_ci c.op_to_vfn = htonl(FW_CMD_OP_V(cmd) | FW_CMD_REQUEST_F | 477862306a36Sopenharmony_ci FW_CMD_WRITE_F | FW_CMD_EXEC_F | 477962306a36Sopenharmony_ci FW_EQ_OFLD_CMD_PFN_V(adap->pf) | 478062306a36Sopenharmony_ci FW_EQ_OFLD_CMD_VFN_V(0)); 478162306a36Sopenharmony_ci c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC_F | 478262306a36Sopenharmony_ci FW_EQ_OFLD_CMD_EQSTART_F | FW_LEN16(c)); 478362306a36Sopenharmony_ci c.fetchszm_to_iqid = 478462306a36Sopenharmony_ci htonl(FW_EQ_OFLD_CMD_HOSTFCMODE_V(HOSTFCMODE_STATUS_PAGE_X) | 478562306a36Sopenharmony_ci FW_EQ_OFLD_CMD_PCIECHN_V(pi->tx_chan) | 478662306a36Sopenharmony_ci FW_EQ_OFLD_CMD_FETCHRO_F | FW_EQ_OFLD_CMD_IQID_V(iqid)); 478762306a36Sopenharmony_ci c.dcaen_to_eqsize = 478862306a36Sopenharmony_ci htonl(FW_EQ_OFLD_CMD_FBMIN_V(fb_min) | 478962306a36Sopenharmony_ci FW_EQ_OFLD_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) | 479062306a36Sopenharmony_ci FW_EQ_OFLD_CMD_CIDXFTHRESH_V(CIDXFLUSHTHRESH_32_X) | 479162306a36Sopenharmony_ci FW_EQ_OFLD_CMD_EQSIZE_V(nentries)); 479262306a36Sopenharmony_ci c.eqaddr = cpu_to_be64(q->phys_addr); 479362306a36Sopenharmony_ci 479462306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c); 479562306a36Sopenharmony_ci if (ret) { 479662306a36Sopenharmony_ci kfree(q->sdesc); 479762306a36Sopenharmony_ci q->sdesc = NULL; 479862306a36Sopenharmony_ci dma_free_coherent(adap->pdev_dev, 479962306a36Sopenharmony_ci nentries * sizeof(struct tx_desc), 480062306a36Sopenharmony_ci q->desc, q->phys_addr); 480162306a36Sopenharmony_ci q->desc = NULL; 480262306a36Sopenharmony_ci return ret; 480362306a36Sopenharmony_ci } 480462306a36Sopenharmony_ci 480562306a36Sopenharmony_ci init_txq(adap, q, FW_EQ_OFLD_CMD_EQID_G(ntohl(c.eqid_pkd))); 480662306a36Sopenharmony_ci return 0; 480762306a36Sopenharmony_ci} 480862306a36Sopenharmony_ci 480962306a36Sopenharmony_ciint t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, 481062306a36Sopenharmony_ci struct net_device *dev, unsigned int iqid, 481162306a36Sopenharmony_ci unsigned int uld_type) 481262306a36Sopenharmony_ci{ 481362306a36Sopenharmony_ci u32 cmd = FW_EQ_OFLD_CMD; 481462306a36Sopenharmony_ci int ret; 481562306a36Sopenharmony_ci 481662306a36Sopenharmony_ci if (unlikely(uld_type == CXGB4_TX_CRYPTO)) 481762306a36Sopenharmony_ci cmd = FW_EQ_CTRL_CMD; 481862306a36Sopenharmony_ci 481962306a36Sopenharmony_ci ret = t4_sge_alloc_ofld_txq(adap, &txq->q, dev, cmd, iqid); 482062306a36Sopenharmony_ci if (ret) 482162306a36Sopenharmony_ci return ret; 482262306a36Sopenharmony_ci 482362306a36Sopenharmony_ci txq->q.q_type = CXGB4_TXQ_ULD; 482462306a36Sopenharmony_ci txq->adap = adap; 482562306a36Sopenharmony_ci skb_queue_head_init(&txq->sendq); 482662306a36Sopenharmony_ci tasklet_setup(&txq->qresume_tsk, restart_ofldq); 482762306a36Sopenharmony_ci txq->full = 0; 482862306a36Sopenharmony_ci txq->mapping_err = 0; 482962306a36Sopenharmony_ci return 0; 483062306a36Sopenharmony_ci} 483162306a36Sopenharmony_ci 483262306a36Sopenharmony_ciint t4_sge_alloc_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq, 483362306a36Sopenharmony_ci struct net_device *dev, u32 iqid) 483462306a36Sopenharmony_ci{ 483562306a36Sopenharmony_ci int ret; 483662306a36Sopenharmony_ci 483762306a36Sopenharmony_ci ret = t4_sge_alloc_ofld_txq(adap, &txq->q, dev, FW_EQ_OFLD_CMD, iqid); 483862306a36Sopenharmony_ci if (ret) 483962306a36Sopenharmony_ci return ret; 484062306a36Sopenharmony_ci 484162306a36Sopenharmony_ci txq->q.q_type = CXGB4_TXQ_ULD; 484262306a36Sopenharmony_ci spin_lock_init(&txq->lock); 484362306a36Sopenharmony_ci txq->adap = adap; 484462306a36Sopenharmony_ci txq->tso = 0; 484562306a36Sopenharmony_ci txq->uso = 0; 484662306a36Sopenharmony_ci txq->tx_cso = 0; 484762306a36Sopenharmony_ci txq->vlan_ins = 0; 484862306a36Sopenharmony_ci txq->mapping_err = 0; 484962306a36Sopenharmony_ci return 0; 485062306a36Sopenharmony_ci} 485162306a36Sopenharmony_ci 485262306a36Sopenharmony_civoid free_txq(struct adapter *adap, struct sge_txq *q) 485362306a36Sopenharmony_ci{ 485462306a36Sopenharmony_ci struct sge *s = &adap->sge; 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_ci dma_free_coherent(adap->pdev_dev, 485762306a36Sopenharmony_ci q->size * sizeof(struct tx_desc) + s->stat_len, 485862306a36Sopenharmony_ci q->desc, q->phys_addr); 485962306a36Sopenharmony_ci q->cntxt_id = 0; 486062306a36Sopenharmony_ci q->sdesc = NULL; 486162306a36Sopenharmony_ci q->desc = NULL; 486262306a36Sopenharmony_ci} 486362306a36Sopenharmony_ci 486462306a36Sopenharmony_civoid free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, 486562306a36Sopenharmony_ci struct sge_fl *fl) 486662306a36Sopenharmony_ci{ 486762306a36Sopenharmony_ci struct sge *s = &adap->sge; 486862306a36Sopenharmony_ci unsigned int fl_id = fl ? fl->cntxt_id : 0xffff; 486962306a36Sopenharmony_ci 487062306a36Sopenharmony_ci adap->sge.ingr_map[rq->cntxt_id - adap->sge.ingr_start] = NULL; 487162306a36Sopenharmony_ci t4_iq_free(adap, adap->mbox, adap->pf, 0, FW_IQ_TYPE_FL_INT_CAP, 487262306a36Sopenharmony_ci rq->cntxt_id, fl_id, 0xffff); 487362306a36Sopenharmony_ci dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len, 487462306a36Sopenharmony_ci rq->desc, rq->phys_addr); 487562306a36Sopenharmony_ci netif_napi_del(&rq->napi); 487662306a36Sopenharmony_ci rq->netdev = NULL; 487762306a36Sopenharmony_ci rq->cntxt_id = rq->abs_id = 0; 487862306a36Sopenharmony_ci rq->desc = NULL; 487962306a36Sopenharmony_ci 488062306a36Sopenharmony_ci if (fl) { 488162306a36Sopenharmony_ci free_rx_bufs(adap, fl, fl->avail); 488262306a36Sopenharmony_ci dma_free_coherent(adap->pdev_dev, fl->size * 8 + s->stat_len, 488362306a36Sopenharmony_ci fl->desc, fl->addr); 488462306a36Sopenharmony_ci kfree(fl->sdesc); 488562306a36Sopenharmony_ci fl->sdesc = NULL; 488662306a36Sopenharmony_ci fl->cntxt_id = 0; 488762306a36Sopenharmony_ci fl->desc = NULL; 488862306a36Sopenharmony_ci } 488962306a36Sopenharmony_ci} 489062306a36Sopenharmony_ci 489162306a36Sopenharmony_ci/** 489262306a36Sopenharmony_ci * t4_free_ofld_rxqs - free a block of consecutive Rx queues 489362306a36Sopenharmony_ci * @adap: the adapter 489462306a36Sopenharmony_ci * @n: number of queues 489562306a36Sopenharmony_ci * @q: pointer to first queue 489662306a36Sopenharmony_ci * 489762306a36Sopenharmony_ci * Release the resources of a consecutive block of offload Rx queues. 489862306a36Sopenharmony_ci */ 489962306a36Sopenharmony_civoid t4_free_ofld_rxqs(struct adapter *adap, int n, struct sge_ofld_rxq *q) 490062306a36Sopenharmony_ci{ 490162306a36Sopenharmony_ci for ( ; n; n--, q++) 490262306a36Sopenharmony_ci if (q->rspq.desc) 490362306a36Sopenharmony_ci free_rspq_fl(adap, &q->rspq, 490462306a36Sopenharmony_ci q->fl.size ? &q->fl : NULL); 490562306a36Sopenharmony_ci} 490662306a36Sopenharmony_ci 490762306a36Sopenharmony_civoid t4_sge_free_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq) 490862306a36Sopenharmony_ci{ 490962306a36Sopenharmony_ci if (txq->q.desc) { 491062306a36Sopenharmony_ci t4_ofld_eq_free(adap, adap->mbox, adap->pf, 0, 491162306a36Sopenharmony_ci txq->q.cntxt_id); 491262306a36Sopenharmony_ci free_tx_desc(adap, &txq->q, txq->q.in_use, false); 491362306a36Sopenharmony_ci kfree(txq->q.sdesc); 491462306a36Sopenharmony_ci free_txq(adap, &txq->q); 491562306a36Sopenharmony_ci } 491662306a36Sopenharmony_ci} 491762306a36Sopenharmony_ci 491862306a36Sopenharmony_ci/** 491962306a36Sopenharmony_ci * t4_free_sge_resources - free SGE resources 492062306a36Sopenharmony_ci * @adap: the adapter 492162306a36Sopenharmony_ci * 492262306a36Sopenharmony_ci * Frees resources used by the SGE queue sets. 492362306a36Sopenharmony_ci */ 492462306a36Sopenharmony_civoid t4_free_sge_resources(struct adapter *adap) 492562306a36Sopenharmony_ci{ 492662306a36Sopenharmony_ci int i; 492762306a36Sopenharmony_ci struct sge_eth_rxq *eq; 492862306a36Sopenharmony_ci struct sge_eth_txq *etq; 492962306a36Sopenharmony_ci 493062306a36Sopenharmony_ci /* stop all Rx queues in order to start them draining */ 493162306a36Sopenharmony_ci for (i = 0; i < adap->sge.ethqsets; i++) { 493262306a36Sopenharmony_ci eq = &adap->sge.ethrxq[i]; 493362306a36Sopenharmony_ci if (eq->rspq.desc) 493462306a36Sopenharmony_ci t4_iq_stop(adap, adap->mbox, adap->pf, 0, 493562306a36Sopenharmony_ci FW_IQ_TYPE_FL_INT_CAP, 493662306a36Sopenharmony_ci eq->rspq.cntxt_id, 493762306a36Sopenharmony_ci eq->fl.size ? eq->fl.cntxt_id : 0xffff, 493862306a36Sopenharmony_ci 0xffff); 493962306a36Sopenharmony_ci } 494062306a36Sopenharmony_ci 494162306a36Sopenharmony_ci /* clean up Ethernet Tx/Rx queues */ 494262306a36Sopenharmony_ci for (i = 0; i < adap->sge.ethqsets; i++) { 494362306a36Sopenharmony_ci eq = &adap->sge.ethrxq[i]; 494462306a36Sopenharmony_ci if (eq->rspq.desc) 494562306a36Sopenharmony_ci free_rspq_fl(adap, &eq->rspq, 494662306a36Sopenharmony_ci eq->fl.size ? &eq->fl : NULL); 494762306a36Sopenharmony_ci if (eq->msix) { 494862306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, eq->msix->idx); 494962306a36Sopenharmony_ci eq->msix = NULL; 495062306a36Sopenharmony_ci } 495162306a36Sopenharmony_ci 495262306a36Sopenharmony_ci etq = &adap->sge.ethtxq[i]; 495362306a36Sopenharmony_ci if (etq->q.desc) { 495462306a36Sopenharmony_ci t4_eth_eq_free(adap, adap->mbox, adap->pf, 0, 495562306a36Sopenharmony_ci etq->q.cntxt_id); 495662306a36Sopenharmony_ci __netif_tx_lock_bh(etq->txq); 495762306a36Sopenharmony_ci free_tx_desc(adap, &etq->q, etq->q.in_use, true); 495862306a36Sopenharmony_ci __netif_tx_unlock_bh(etq->txq); 495962306a36Sopenharmony_ci kfree(etq->q.sdesc); 496062306a36Sopenharmony_ci free_txq(adap, &etq->q); 496162306a36Sopenharmony_ci } 496262306a36Sopenharmony_ci } 496362306a36Sopenharmony_ci 496462306a36Sopenharmony_ci /* clean up control Tx queues */ 496562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(adap->sge.ctrlq); i++) { 496662306a36Sopenharmony_ci struct sge_ctrl_txq *cq = &adap->sge.ctrlq[i]; 496762306a36Sopenharmony_ci 496862306a36Sopenharmony_ci if (cq->q.desc) { 496962306a36Sopenharmony_ci tasklet_kill(&cq->qresume_tsk); 497062306a36Sopenharmony_ci t4_ctrl_eq_free(adap, adap->mbox, adap->pf, 0, 497162306a36Sopenharmony_ci cq->q.cntxt_id); 497262306a36Sopenharmony_ci __skb_queue_purge(&cq->sendq); 497362306a36Sopenharmony_ci free_txq(adap, &cq->q); 497462306a36Sopenharmony_ci } 497562306a36Sopenharmony_ci } 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_ci if (adap->sge.fw_evtq.desc) { 497862306a36Sopenharmony_ci free_rspq_fl(adap, &adap->sge.fw_evtq, NULL); 497962306a36Sopenharmony_ci if (adap->sge.fwevtq_msix_idx >= 0) 498062306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, 498162306a36Sopenharmony_ci adap->sge.fwevtq_msix_idx); 498262306a36Sopenharmony_ci } 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_ci if (adap->sge.nd_msix_idx >= 0) 498562306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, adap->sge.nd_msix_idx); 498662306a36Sopenharmony_ci 498762306a36Sopenharmony_ci if (adap->sge.intrq.desc) 498862306a36Sopenharmony_ci free_rspq_fl(adap, &adap->sge.intrq, NULL); 498962306a36Sopenharmony_ci 499062306a36Sopenharmony_ci if (!is_t4(adap->params.chip)) { 499162306a36Sopenharmony_ci etq = &adap->sge.ptptxq; 499262306a36Sopenharmony_ci if (etq->q.desc) { 499362306a36Sopenharmony_ci t4_eth_eq_free(adap, adap->mbox, adap->pf, 0, 499462306a36Sopenharmony_ci etq->q.cntxt_id); 499562306a36Sopenharmony_ci spin_lock_bh(&adap->ptp_lock); 499662306a36Sopenharmony_ci free_tx_desc(adap, &etq->q, etq->q.in_use, true); 499762306a36Sopenharmony_ci spin_unlock_bh(&adap->ptp_lock); 499862306a36Sopenharmony_ci kfree(etq->q.sdesc); 499962306a36Sopenharmony_ci free_txq(adap, &etq->q); 500062306a36Sopenharmony_ci } 500162306a36Sopenharmony_ci } 500262306a36Sopenharmony_ci 500362306a36Sopenharmony_ci /* clear the reverse egress queue map */ 500462306a36Sopenharmony_ci memset(adap->sge.egr_map, 0, 500562306a36Sopenharmony_ci adap->sge.egr_sz * sizeof(*adap->sge.egr_map)); 500662306a36Sopenharmony_ci} 500762306a36Sopenharmony_ci 500862306a36Sopenharmony_civoid t4_sge_start(struct adapter *adap) 500962306a36Sopenharmony_ci{ 501062306a36Sopenharmony_ci adap->sge.ethtxq_rover = 0; 501162306a36Sopenharmony_ci mod_timer(&adap->sge.rx_timer, jiffies + RX_QCHECK_PERIOD); 501262306a36Sopenharmony_ci mod_timer(&adap->sge.tx_timer, jiffies + TX_QCHECK_PERIOD); 501362306a36Sopenharmony_ci} 501462306a36Sopenharmony_ci 501562306a36Sopenharmony_ci/** 501662306a36Sopenharmony_ci * t4_sge_stop - disable SGE operation 501762306a36Sopenharmony_ci * @adap: the adapter 501862306a36Sopenharmony_ci * 501962306a36Sopenharmony_ci * Stop tasklets and timers associated with the DMA engine. Note that 502062306a36Sopenharmony_ci * this is effective only if measures have been taken to disable any HW 502162306a36Sopenharmony_ci * events that may restart them. 502262306a36Sopenharmony_ci */ 502362306a36Sopenharmony_civoid t4_sge_stop(struct adapter *adap) 502462306a36Sopenharmony_ci{ 502562306a36Sopenharmony_ci int i; 502662306a36Sopenharmony_ci struct sge *s = &adap->sge; 502762306a36Sopenharmony_ci 502862306a36Sopenharmony_ci if (s->rx_timer.function) 502962306a36Sopenharmony_ci del_timer_sync(&s->rx_timer); 503062306a36Sopenharmony_ci if (s->tx_timer.function) 503162306a36Sopenharmony_ci del_timer_sync(&s->tx_timer); 503262306a36Sopenharmony_ci 503362306a36Sopenharmony_ci if (is_offload(adap)) { 503462306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info; 503562306a36Sopenharmony_ci 503662306a36Sopenharmony_ci txq_info = adap->sge.uld_txq_info[CXGB4_TX_OFLD]; 503762306a36Sopenharmony_ci if (txq_info) { 503862306a36Sopenharmony_ci struct sge_uld_txq *txq = txq_info->uldtxq; 503962306a36Sopenharmony_ci 504062306a36Sopenharmony_ci for_each_ofldtxq(&adap->sge, i) { 504162306a36Sopenharmony_ci if (txq->q.desc) 504262306a36Sopenharmony_ci tasklet_kill(&txq->qresume_tsk); 504362306a36Sopenharmony_ci } 504462306a36Sopenharmony_ci } 504562306a36Sopenharmony_ci } 504662306a36Sopenharmony_ci 504762306a36Sopenharmony_ci if (is_pci_uld(adap)) { 504862306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info; 504962306a36Sopenharmony_ci 505062306a36Sopenharmony_ci txq_info = adap->sge.uld_txq_info[CXGB4_TX_CRYPTO]; 505162306a36Sopenharmony_ci if (txq_info) { 505262306a36Sopenharmony_ci struct sge_uld_txq *txq = txq_info->uldtxq; 505362306a36Sopenharmony_ci 505462306a36Sopenharmony_ci for_each_ofldtxq(&adap->sge, i) { 505562306a36Sopenharmony_ci if (txq->q.desc) 505662306a36Sopenharmony_ci tasklet_kill(&txq->qresume_tsk); 505762306a36Sopenharmony_ci } 505862306a36Sopenharmony_ci } 505962306a36Sopenharmony_ci } 506062306a36Sopenharmony_ci 506162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) { 506262306a36Sopenharmony_ci struct sge_ctrl_txq *cq = &s->ctrlq[i]; 506362306a36Sopenharmony_ci 506462306a36Sopenharmony_ci if (cq->q.desc) 506562306a36Sopenharmony_ci tasklet_kill(&cq->qresume_tsk); 506662306a36Sopenharmony_ci } 506762306a36Sopenharmony_ci} 506862306a36Sopenharmony_ci 506962306a36Sopenharmony_ci/** 507062306a36Sopenharmony_ci * t4_sge_init_soft - grab core SGE values needed by SGE code 507162306a36Sopenharmony_ci * @adap: the adapter 507262306a36Sopenharmony_ci * 507362306a36Sopenharmony_ci * We need to grab the SGE operating parameters that we need to have 507462306a36Sopenharmony_ci * in order to do our job and make sure we can live with them. 507562306a36Sopenharmony_ci */ 507662306a36Sopenharmony_ci 507762306a36Sopenharmony_cistatic int t4_sge_init_soft(struct adapter *adap) 507862306a36Sopenharmony_ci{ 507962306a36Sopenharmony_ci struct sge *s = &adap->sge; 508062306a36Sopenharmony_ci u32 fl_small_pg, fl_large_pg, fl_small_mtu, fl_large_mtu; 508162306a36Sopenharmony_ci u32 timer_value_0_and_1, timer_value_2_and_3, timer_value_4_and_5; 508262306a36Sopenharmony_ci u32 ingress_rx_threshold; 508362306a36Sopenharmony_ci 508462306a36Sopenharmony_ci /* 508562306a36Sopenharmony_ci * Verify that CPL messages are going to the Ingress Queue for 508662306a36Sopenharmony_ci * process_responses() and that only packet data is going to the 508762306a36Sopenharmony_ci * Free Lists. 508862306a36Sopenharmony_ci */ 508962306a36Sopenharmony_ci if ((t4_read_reg(adap, SGE_CONTROL_A) & RXPKTCPLMODE_F) != 509062306a36Sopenharmony_ci RXPKTCPLMODE_V(RXPKTCPLMODE_SPLIT_X)) { 509162306a36Sopenharmony_ci dev_err(adap->pdev_dev, "bad SGE CPL MODE\n"); 509262306a36Sopenharmony_ci return -EINVAL; 509362306a36Sopenharmony_ci } 509462306a36Sopenharmony_ci 509562306a36Sopenharmony_ci /* 509662306a36Sopenharmony_ci * Validate the Host Buffer Register Array indices that we want to 509762306a36Sopenharmony_ci * use ... 509862306a36Sopenharmony_ci * 509962306a36Sopenharmony_ci * XXX Note that we should really read through the Host Buffer Size 510062306a36Sopenharmony_ci * XXX register array and find the indices of the Buffer Sizes which 510162306a36Sopenharmony_ci * XXX meet our needs! 510262306a36Sopenharmony_ci */ 510362306a36Sopenharmony_ci #define READ_FL_BUF(x) \ 510462306a36Sopenharmony_ci t4_read_reg(adap, SGE_FL_BUFFER_SIZE0_A+(x)*sizeof(u32)) 510562306a36Sopenharmony_ci 510662306a36Sopenharmony_ci fl_small_pg = READ_FL_BUF(RX_SMALL_PG_BUF); 510762306a36Sopenharmony_ci fl_large_pg = READ_FL_BUF(RX_LARGE_PG_BUF); 510862306a36Sopenharmony_ci fl_small_mtu = READ_FL_BUF(RX_SMALL_MTU_BUF); 510962306a36Sopenharmony_ci fl_large_mtu = READ_FL_BUF(RX_LARGE_MTU_BUF); 511062306a36Sopenharmony_ci 511162306a36Sopenharmony_ci /* We only bother using the Large Page logic if the Large Page Buffer 511262306a36Sopenharmony_ci * is larger than our Page Size Buffer. 511362306a36Sopenharmony_ci */ 511462306a36Sopenharmony_ci if (fl_large_pg <= fl_small_pg) 511562306a36Sopenharmony_ci fl_large_pg = 0; 511662306a36Sopenharmony_ci 511762306a36Sopenharmony_ci #undef READ_FL_BUF 511862306a36Sopenharmony_ci 511962306a36Sopenharmony_ci /* The Page Size Buffer must be exactly equal to our Page Size and the 512062306a36Sopenharmony_ci * Large Page Size Buffer should be 0 (per above) or a power of 2. 512162306a36Sopenharmony_ci */ 512262306a36Sopenharmony_ci if (fl_small_pg != PAGE_SIZE || 512362306a36Sopenharmony_ci (fl_large_pg & (fl_large_pg-1)) != 0) { 512462306a36Sopenharmony_ci dev_err(adap->pdev_dev, "bad SGE FL page buffer sizes [%d, %d]\n", 512562306a36Sopenharmony_ci fl_small_pg, fl_large_pg); 512662306a36Sopenharmony_ci return -EINVAL; 512762306a36Sopenharmony_ci } 512862306a36Sopenharmony_ci if (fl_large_pg) 512962306a36Sopenharmony_ci s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT; 513062306a36Sopenharmony_ci 513162306a36Sopenharmony_ci if (fl_small_mtu < FL_MTU_SMALL_BUFSIZE(adap) || 513262306a36Sopenharmony_ci fl_large_mtu < FL_MTU_LARGE_BUFSIZE(adap)) { 513362306a36Sopenharmony_ci dev_err(adap->pdev_dev, "bad SGE FL MTU sizes [%d, %d]\n", 513462306a36Sopenharmony_ci fl_small_mtu, fl_large_mtu); 513562306a36Sopenharmony_ci return -EINVAL; 513662306a36Sopenharmony_ci } 513762306a36Sopenharmony_ci 513862306a36Sopenharmony_ci /* 513962306a36Sopenharmony_ci * Retrieve our RX interrupt holdoff timer values and counter 514062306a36Sopenharmony_ci * threshold values from the SGE parameters. 514162306a36Sopenharmony_ci */ 514262306a36Sopenharmony_ci timer_value_0_and_1 = t4_read_reg(adap, SGE_TIMER_VALUE_0_AND_1_A); 514362306a36Sopenharmony_ci timer_value_2_and_3 = t4_read_reg(adap, SGE_TIMER_VALUE_2_AND_3_A); 514462306a36Sopenharmony_ci timer_value_4_and_5 = t4_read_reg(adap, SGE_TIMER_VALUE_4_AND_5_A); 514562306a36Sopenharmony_ci s->timer_val[0] = core_ticks_to_us(adap, 514662306a36Sopenharmony_ci TIMERVALUE0_G(timer_value_0_and_1)); 514762306a36Sopenharmony_ci s->timer_val[1] = core_ticks_to_us(adap, 514862306a36Sopenharmony_ci TIMERVALUE1_G(timer_value_0_and_1)); 514962306a36Sopenharmony_ci s->timer_val[2] = core_ticks_to_us(adap, 515062306a36Sopenharmony_ci TIMERVALUE2_G(timer_value_2_and_3)); 515162306a36Sopenharmony_ci s->timer_val[3] = core_ticks_to_us(adap, 515262306a36Sopenharmony_ci TIMERVALUE3_G(timer_value_2_and_3)); 515362306a36Sopenharmony_ci s->timer_val[4] = core_ticks_to_us(adap, 515462306a36Sopenharmony_ci TIMERVALUE4_G(timer_value_4_and_5)); 515562306a36Sopenharmony_ci s->timer_val[5] = core_ticks_to_us(adap, 515662306a36Sopenharmony_ci TIMERVALUE5_G(timer_value_4_and_5)); 515762306a36Sopenharmony_ci 515862306a36Sopenharmony_ci ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD_A); 515962306a36Sopenharmony_ci s->counter_val[0] = THRESHOLD_0_G(ingress_rx_threshold); 516062306a36Sopenharmony_ci s->counter_val[1] = THRESHOLD_1_G(ingress_rx_threshold); 516162306a36Sopenharmony_ci s->counter_val[2] = THRESHOLD_2_G(ingress_rx_threshold); 516262306a36Sopenharmony_ci s->counter_val[3] = THRESHOLD_3_G(ingress_rx_threshold); 516362306a36Sopenharmony_ci 516462306a36Sopenharmony_ci return 0; 516562306a36Sopenharmony_ci} 516662306a36Sopenharmony_ci 516762306a36Sopenharmony_ci/** 516862306a36Sopenharmony_ci * t4_sge_init - initialize SGE 516962306a36Sopenharmony_ci * @adap: the adapter 517062306a36Sopenharmony_ci * 517162306a36Sopenharmony_ci * Perform low-level SGE code initialization needed every time after a 517262306a36Sopenharmony_ci * chip reset. 517362306a36Sopenharmony_ci */ 517462306a36Sopenharmony_ciint t4_sge_init(struct adapter *adap) 517562306a36Sopenharmony_ci{ 517662306a36Sopenharmony_ci struct sge *s = &adap->sge; 517762306a36Sopenharmony_ci u32 sge_control, sge_conm_ctrl; 517862306a36Sopenharmony_ci int ret, egress_threshold; 517962306a36Sopenharmony_ci 518062306a36Sopenharmony_ci /* 518162306a36Sopenharmony_ci * Ingress Padding Boundary and Egress Status Page Size are set up by 518262306a36Sopenharmony_ci * t4_fixup_host_params(). 518362306a36Sopenharmony_ci */ 518462306a36Sopenharmony_ci sge_control = t4_read_reg(adap, SGE_CONTROL_A); 518562306a36Sopenharmony_ci s->pktshift = PKTSHIFT_G(sge_control); 518662306a36Sopenharmony_ci s->stat_len = (sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64; 518762306a36Sopenharmony_ci 518862306a36Sopenharmony_ci s->fl_align = t4_fl_pkt_align(adap); 518962306a36Sopenharmony_ci ret = t4_sge_init_soft(adap); 519062306a36Sopenharmony_ci if (ret < 0) 519162306a36Sopenharmony_ci return ret; 519262306a36Sopenharmony_ci 519362306a36Sopenharmony_ci /* 519462306a36Sopenharmony_ci * A FL with <= fl_starve_thres buffers is starving and a periodic 519562306a36Sopenharmony_ci * timer will attempt to refill it. This needs to be larger than the 519662306a36Sopenharmony_ci * SGE's Egress Congestion Threshold. If it isn't, then we can get 519762306a36Sopenharmony_ci * stuck waiting for new packets while the SGE is waiting for us to 519862306a36Sopenharmony_ci * give it more Free List entries. (Note that the SGE's Egress 519962306a36Sopenharmony_ci * Congestion Threshold is in units of 2 Free List pointers.) For T4, 520062306a36Sopenharmony_ci * there was only a single field to control this. For T5 there's the 520162306a36Sopenharmony_ci * original field which now only applies to Unpacked Mode Free List 520262306a36Sopenharmony_ci * buffers and a new field which only applies to Packed Mode Free List 520362306a36Sopenharmony_ci * buffers. 520462306a36Sopenharmony_ci */ 520562306a36Sopenharmony_ci sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL_A); 520662306a36Sopenharmony_ci switch (CHELSIO_CHIP_VERSION(adap->params.chip)) { 520762306a36Sopenharmony_ci case CHELSIO_T4: 520862306a36Sopenharmony_ci egress_threshold = EGRTHRESHOLD_G(sge_conm_ctrl); 520962306a36Sopenharmony_ci break; 521062306a36Sopenharmony_ci case CHELSIO_T5: 521162306a36Sopenharmony_ci egress_threshold = EGRTHRESHOLDPACKING_G(sge_conm_ctrl); 521262306a36Sopenharmony_ci break; 521362306a36Sopenharmony_ci case CHELSIO_T6: 521462306a36Sopenharmony_ci egress_threshold = T6_EGRTHRESHOLDPACKING_G(sge_conm_ctrl); 521562306a36Sopenharmony_ci break; 521662306a36Sopenharmony_ci default: 521762306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Unsupported Chip version %d\n", 521862306a36Sopenharmony_ci CHELSIO_CHIP_VERSION(adap->params.chip)); 521962306a36Sopenharmony_ci return -EINVAL; 522062306a36Sopenharmony_ci } 522162306a36Sopenharmony_ci s->fl_starve_thres = 2*egress_threshold + 1; 522262306a36Sopenharmony_ci 522362306a36Sopenharmony_ci t4_idma_monitor_init(adap, &s->idma_monitor); 522462306a36Sopenharmony_ci 522562306a36Sopenharmony_ci /* Set up timers used for recuring callbacks to process RX and TX 522662306a36Sopenharmony_ci * administrative tasks. 522762306a36Sopenharmony_ci */ 522862306a36Sopenharmony_ci timer_setup(&s->rx_timer, sge_rx_timer_cb, 0); 522962306a36Sopenharmony_ci timer_setup(&s->tx_timer, sge_tx_timer_cb, 0); 523062306a36Sopenharmony_ci 523162306a36Sopenharmony_ci spin_lock_init(&s->intrq_lock); 523262306a36Sopenharmony_ci 523362306a36Sopenharmony_ci return 0; 523462306a36Sopenharmony_ci} 5235