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				    &param, &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, &param, &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