162306a36Sopenharmony_ci/* bnx2x_cmn.c: QLogic Everest network driver.
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * Copyright (c) 2007-2013 Broadcom Corporation
462306a36Sopenharmony_ci * Copyright (c) 2014 QLogic Corporation
562306a36Sopenharmony_ci * All rights reserved
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
862306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
962306a36Sopenharmony_ci * the Free Software Foundation.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Maintained by: Ariel Elior <ariel.elior@qlogic.com>
1262306a36Sopenharmony_ci * Written by: Eliezer Tamir
1362306a36Sopenharmony_ci * Based on code from Michael Chan's bnx2 driver
1462306a36Sopenharmony_ci * UDP CSUM errata workaround by Arik Gendelman
1562306a36Sopenharmony_ci * Slowpath and fastpath rework by Vladislav Zolotarov
1662306a36Sopenharmony_ci * Statistics and Link management by Yitchak Gertner
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/etherdevice.h>
2362306a36Sopenharmony_ci#include <linux/if_vlan.h>
2462306a36Sopenharmony_ci#include <linux/interrupt.h>
2562306a36Sopenharmony_ci#include <linux/ip.h>
2662306a36Sopenharmony_ci#include <linux/crash_dump.h>
2762306a36Sopenharmony_ci#include <net/tcp.h>
2862306a36Sopenharmony_ci#include <net/gro.h>
2962306a36Sopenharmony_ci#include <net/ipv6.h>
3062306a36Sopenharmony_ci#include <net/ip6_checksum.h>
3162306a36Sopenharmony_ci#include <linux/prefetch.h>
3262306a36Sopenharmony_ci#include "bnx2x_cmn.h"
3362306a36Sopenharmony_ci#include "bnx2x_init.h"
3462306a36Sopenharmony_ci#include "bnx2x_sp.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic void bnx2x_free_fp_mem_cnic(struct bnx2x *bp);
3762306a36Sopenharmony_cistatic int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp);
3862306a36Sopenharmony_cistatic int bnx2x_alloc_fp_mem(struct bnx2x *bp);
3962306a36Sopenharmony_cistatic int bnx2x_poll(struct napi_struct *napi, int budget);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void bnx2x_add_all_napi_cnic(struct bnx2x *bp)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	int i;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* Add NAPI objects */
4662306a36Sopenharmony_ci	for_each_rx_queue_cnic(bp, i) {
4762306a36Sopenharmony_ci		netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), bnx2x_poll);
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic void bnx2x_add_all_napi(struct bnx2x *bp)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	int i;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* Add NAPI objects */
5662306a36Sopenharmony_ci	for_each_eth_queue(bp, i) {
5762306a36Sopenharmony_ci		netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), bnx2x_poll);
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int bnx2x_calc_num_queues(struct bnx2x *bp)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	int nq = bnx2x_num_queues ? : netif_get_num_default_rss_queues();
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/* Reduce memory usage in kdump environment by using only one queue */
6662306a36Sopenharmony_ci	if (is_kdump_kernel())
6762306a36Sopenharmony_ci		nq = 1;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	nq = clamp(nq, 1, BNX2X_MAX_QUEUES(bp));
7062306a36Sopenharmony_ci	return nq;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/**
7462306a36Sopenharmony_ci * bnx2x_move_fp - move content of the fastpath structure.
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * @bp:		driver handle
7762306a36Sopenharmony_ci * @from:	source FP index
7862306a36Sopenharmony_ci * @to:		destination FP index
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * Makes sure the contents of the bp->fp[to].napi is kept
8162306a36Sopenharmony_ci * intact. This is done by first copying the napi struct from
8262306a36Sopenharmony_ci * the target to the source, and then mem copying the entire
8362306a36Sopenharmony_ci * source onto the target. Update txdata pointers and related
8462306a36Sopenharmony_ci * content.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_cistatic inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct bnx2x_fastpath *from_fp = &bp->fp[from];
8962306a36Sopenharmony_ci	struct bnx2x_fastpath *to_fp = &bp->fp[to];
9062306a36Sopenharmony_ci	struct bnx2x_sp_objs *from_sp_objs = &bp->sp_objs[from];
9162306a36Sopenharmony_ci	struct bnx2x_sp_objs *to_sp_objs = &bp->sp_objs[to];
9262306a36Sopenharmony_ci	struct bnx2x_fp_stats *from_fp_stats = &bp->fp_stats[from];
9362306a36Sopenharmony_ci	struct bnx2x_fp_stats *to_fp_stats = &bp->fp_stats[to];
9462306a36Sopenharmony_ci	int old_max_eth_txqs, new_max_eth_txqs;
9562306a36Sopenharmony_ci	int old_txdata_index = 0, new_txdata_index = 0;
9662306a36Sopenharmony_ci	struct bnx2x_agg_info *old_tpa_info = to_fp->tpa_info;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* Copy the NAPI object as it has been already initialized */
9962306a36Sopenharmony_ci	from_fp->napi = to_fp->napi;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* Move bnx2x_fastpath contents */
10262306a36Sopenharmony_ci	memcpy(to_fp, from_fp, sizeof(*to_fp));
10362306a36Sopenharmony_ci	to_fp->index = to;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* Retain the tpa_info of the original `to' version as we don't want
10662306a36Sopenharmony_ci	 * 2 FPs to contain the same tpa_info pointer.
10762306a36Sopenharmony_ci	 */
10862306a36Sopenharmony_ci	to_fp->tpa_info = old_tpa_info;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* move sp_objs contents as well, as their indices match fp ones */
11162306a36Sopenharmony_ci	memcpy(to_sp_objs, from_sp_objs, sizeof(*to_sp_objs));
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* move fp_stats contents as well, as their indices match fp ones */
11462306a36Sopenharmony_ci	memcpy(to_fp_stats, from_fp_stats, sizeof(*to_fp_stats));
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Update txdata pointers in fp and move txdata content accordingly:
11762306a36Sopenharmony_ci	 * Each fp consumes 'max_cos' txdata structures, so the index should be
11862306a36Sopenharmony_ci	 * decremented by max_cos x delta.
11962306a36Sopenharmony_ci	 */
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	old_max_eth_txqs = BNX2X_NUM_ETH_QUEUES(bp) * (bp)->max_cos;
12262306a36Sopenharmony_ci	new_max_eth_txqs = (BNX2X_NUM_ETH_QUEUES(bp) - from + to) *
12362306a36Sopenharmony_ci				(bp)->max_cos;
12462306a36Sopenharmony_ci	if (from == FCOE_IDX(bp)) {
12562306a36Sopenharmony_ci		old_txdata_index = old_max_eth_txqs + FCOE_TXQ_IDX_OFFSET;
12662306a36Sopenharmony_ci		new_txdata_index = new_max_eth_txqs + FCOE_TXQ_IDX_OFFSET;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	memcpy(&bp->bnx2x_txq[new_txdata_index],
13062306a36Sopenharmony_ci	       &bp->bnx2x_txq[old_txdata_index],
13162306a36Sopenharmony_ci	       sizeof(struct bnx2x_fp_txdata));
13262306a36Sopenharmony_ci	to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index];
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/**
13662306a36Sopenharmony_ci * bnx2x_fill_fw_str - Fill buffer with FW version string.
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci * @bp:        driver handle
13962306a36Sopenharmony_ci * @buf:       character buffer to fill with the fw name
14062306a36Sopenharmony_ci * @buf_len:   length of the above buffer
14162306a36Sopenharmony_ci *
14262306a36Sopenharmony_ci */
14362306a36Sopenharmony_civoid bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	if (IS_PF(bp)) {
14662306a36Sopenharmony_ci		u8 phy_fw_ver[PHY_FW_VER_LEN];
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		phy_fw_ver[0] = '\0';
14962306a36Sopenharmony_ci		bnx2x_get_ext_phy_fw_version(&bp->link_params,
15062306a36Sopenharmony_ci					     phy_fw_ver, PHY_FW_VER_LEN);
15162306a36Sopenharmony_ci		strscpy(buf, bp->fw_ver, buf_len);
15262306a36Sopenharmony_ci		snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
15362306a36Sopenharmony_ci			 "bc %d.%d.%d%s%s",
15462306a36Sopenharmony_ci			 (bp->common.bc_ver & 0xff0000) >> 16,
15562306a36Sopenharmony_ci			 (bp->common.bc_ver & 0xff00) >> 8,
15662306a36Sopenharmony_ci			 (bp->common.bc_ver & 0xff),
15762306a36Sopenharmony_ci			 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
15862306a36Sopenharmony_ci	} else {
15962306a36Sopenharmony_ci		bnx2x_vf_fill_fw_str(bp, buf, buf_len);
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/**
16462306a36Sopenharmony_ci * bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci * @bp:	driver handle
16762306a36Sopenharmony_ci * @delta:	number of eth queues which were not allocated
16862306a36Sopenharmony_ci */
16962306a36Sopenharmony_cistatic void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	int i, cos, old_eth_num = BNX2X_NUM_ETH_QUEUES(bp);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* Queue pointer cannot be re-set on an fp-basis, as moving pointer
17462306a36Sopenharmony_ci	 * backward along the array could cause memory to be overridden
17562306a36Sopenharmony_ci	 */
17662306a36Sopenharmony_ci	for (cos = 1; cos < bp->max_cos; cos++) {
17762306a36Sopenharmony_ci		for (i = 0; i < old_eth_num - delta; i++) {
17862306a36Sopenharmony_ci			struct bnx2x_fastpath *fp = &bp->fp[i];
17962306a36Sopenharmony_ci			int new_idx = cos * (old_eth_num - delta) + i;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci			memcpy(&bp->bnx2x_txq[new_idx], fp->txdata_ptr[cos],
18262306a36Sopenharmony_ci			       sizeof(struct bnx2x_fp_txdata));
18362306a36Sopenharmony_ci			fp->txdata_ptr[cos] = &bp->bnx2x_txq[new_idx];
18462306a36Sopenharmony_ci		}
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ciint bnx2x_load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* free skb in the packet ring at pos idx
19162306a36Sopenharmony_ci * return idx of last bd freed
19262306a36Sopenharmony_ci */
19362306a36Sopenharmony_cistatic u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
19462306a36Sopenharmony_ci			     u16 idx, unsigned int *pkts_compl,
19562306a36Sopenharmony_ci			     unsigned int *bytes_compl)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct sw_tx_bd *tx_buf = &txdata->tx_buf_ring[idx];
19862306a36Sopenharmony_ci	struct eth_tx_start_bd *tx_start_bd;
19962306a36Sopenharmony_ci	struct eth_tx_bd *tx_data_bd;
20062306a36Sopenharmony_ci	struct sk_buff *skb = tx_buf->skb;
20162306a36Sopenharmony_ci	u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
20262306a36Sopenharmony_ci	int nbd;
20362306a36Sopenharmony_ci	u16 split_bd_len = 0;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* prefetch skb end pointer to speedup dev_kfree_skb() */
20662306a36Sopenharmony_ci	prefetch(&skb->end);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	DP(NETIF_MSG_TX_DONE, "fp[%d]: pkt_idx %d  buff @(%p)->skb %p\n",
20962306a36Sopenharmony_ci	   txdata->txq_index, idx, tx_buf, skb);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	tx_start_bd = &txdata->tx_desc_ring[bd_idx].start_bd;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
21462306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
21562306a36Sopenharmony_ci	if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) {
21662306a36Sopenharmony_ci		BNX2X_ERR("BAD nbd!\n");
21762306a36Sopenharmony_ci		bnx2x_panic();
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci#endif
22062306a36Sopenharmony_ci	new_cons = nbd + tx_buf->first_bd;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* Get the next bd */
22362306a36Sopenharmony_ci	bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* Skip a parse bd... */
22662306a36Sopenharmony_ci	--nbd;
22762306a36Sopenharmony_ci	bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (tx_buf->flags & BNX2X_HAS_SECOND_PBD) {
23062306a36Sopenharmony_ci		/* Skip second parse bd... */
23162306a36Sopenharmony_ci		--nbd;
23262306a36Sopenharmony_ci		bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* TSO headers+data bds share a common mapping. See bnx2x_tx_split() */
23662306a36Sopenharmony_ci	if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
23762306a36Sopenharmony_ci		tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd;
23862306a36Sopenharmony_ci		split_bd_len = BD_UNMAP_LEN(tx_data_bd);
23962306a36Sopenharmony_ci		--nbd;
24062306a36Sopenharmony_ci		bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* unmap first bd */
24462306a36Sopenharmony_ci	dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
24562306a36Sopenharmony_ci			 BD_UNMAP_LEN(tx_start_bd) + split_bd_len,
24662306a36Sopenharmony_ci			 DMA_TO_DEVICE);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* now free frags */
24962306a36Sopenharmony_ci	while (nbd > 0) {
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd;
25262306a36Sopenharmony_ci		dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd),
25362306a36Sopenharmony_ci			       BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
25462306a36Sopenharmony_ci		if (--nbd)
25562306a36Sopenharmony_ci			bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* release skb */
25962306a36Sopenharmony_ci	WARN_ON(!skb);
26062306a36Sopenharmony_ci	if (likely(skb)) {
26162306a36Sopenharmony_ci		(*pkts_compl)++;
26262306a36Sopenharmony_ci		(*bytes_compl) += skb->len;
26362306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	tx_buf->first_bd = 0;
26762306a36Sopenharmony_ci	tx_buf->skb = NULL;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return new_cons;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ciint bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct netdev_queue *txq;
27562306a36Sopenharmony_ci	u16 hw_cons, sw_cons, bd_cons = txdata->tx_bd_cons;
27662306a36Sopenharmony_ci	unsigned int pkts_compl = 0, bytes_compl = 0;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
27962306a36Sopenharmony_ci	if (unlikely(bp->panic))
28062306a36Sopenharmony_ci		return -1;
28162306a36Sopenharmony_ci#endif
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	txq = netdev_get_tx_queue(bp->dev, txdata->txq_index);
28462306a36Sopenharmony_ci	hw_cons = le16_to_cpu(*txdata->tx_cons_sb);
28562306a36Sopenharmony_ci	sw_cons = txdata->tx_pkt_cons;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* Ensure subsequent loads occur after hw_cons */
28862306a36Sopenharmony_ci	smp_rmb();
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	while (sw_cons != hw_cons) {
29162306a36Sopenharmony_ci		u16 pkt_cons;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		pkt_cons = TX_BD(sw_cons);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		DP(NETIF_MSG_TX_DONE,
29662306a36Sopenharmony_ci		   "queue[%d]: hw_cons %u  sw_cons %u  pkt_cons %u\n",
29762306a36Sopenharmony_ci		   txdata->txq_index, hw_cons, sw_cons, pkt_cons);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		bd_cons = bnx2x_free_tx_pkt(bp, txdata, pkt_cons,
30062306a36Sopenharmony_ci					    &pkts_compl, &bytes_compl);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		sw_cons++;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	netdev_tx_completed_queue(txq, pkts_compl, bytes_compl);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	txdata->tx_pkt_cons = sw_cons;
30862306a36Sopenharmony_ci	txdata->tx_bd_cons = bd_cons;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* Need to make the tx_bd_cons update visible to start_xmit()
31162306a36Sopenharmony_ci	 * before checking for netif_tx_queue_stopped().  Without the
31262306a36Sopenharmony_ci	 * memory barrier, there is a small possibility that
31362306a36Sopenharmony_ci	 * start_xmit() will miss it and cause the queue to be stopped
31462306a36Sopenharmony_ci	 * forever.
31562306a36Sopenharmony_ci	 * On the other hand we need an rmb() here to ensure the proper
31662306a36Sopenharmony_ci	 * ordering of bit testing in the following
31762306a36Sopenharmony_ci	 * netif_tx_queue_stopped(txq) call.
31862306a36Sopenharmony_ci	 */
31962306a36Sopenharmony_ci	smp_mb();
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (unlikely(netif_tx_queue_stopped(txq))) {
32262306a36Sopenharmony_ci		/* Taking tx_lock() is needed to prevent re-enabling the queue
32362306a36Sopenharmony_ci		 * while it's empty. This could have happen if rx_action() gets
32462306a36Sopenharmony_ci		 * suspended in bnx2x_tx_int() after the condition before
32562306a36Sopenharmony_ci		 * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()):
32662306a36Sopenharmony_ci		 *
32762306a36Sopenharmony_ci		 * stops the queue->sees fresh tx_bd_cons->releases the queue->
32862306a36Sopenharmony_ci		 * sends some packets consuming the whole queue again->
32962306a36Sopenharmony_ci		 * stops the queue
33062306a36Sopenharmony_ci		 */
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci		__netif_tx_lock(txq, smp_processor_id());
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		if ((netif_tx_queue_stopped(txq)) &&
33562306a36Sopenharmony_ci		    (bp->state == BNX2X_STATE_OPEN) &&
33662306a36Sopenharmony_ci		    (bnx2x_tx_avail(bp, txdata) >= MAX_DESC_PER_TX_PKT))
33762306a36Sopenharmony_ci			netif_tx_wake_queue(txq);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		__netif_tx_unlock(txq);
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci	return 0;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic inline void bnx2x_update_last_max_sge(struct bnx2x_fastpath *fp,
34562306a36Sopenharmony_ci					     u16 idx)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	u16 last_max = fp->last_max_sge;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (SUB_S16(idx, last_max) > 0)
35062306a36Sopenharmony_ci		fp->last_max_sge = idx;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic inline void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
35462306a36Sopenharmony_ci					 u16 sge_len,
35562306a36Sopenharmony_ci					 struct eth_end_agg_rx_cqe *cqe)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct bnx2x *bp = fp->bp;
35862306a36Sopenharmony_ci	u16 last_max, last_elem, first_elem;
35962306a36Sopenharmony_ci	u16 delta = 0;
36062306a36Sopenharmony_ci	u16 i;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (!sge_len)
36362306a36Sopenharmony_ci		return;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* First mark all used pages */
36662306a36Sopenharmony_ci	for (i = 0; i < sge_len; i++)
36762306a36Sopenharmony_ci		BIT_VEC64_CLEAR_BIT(fp->sge_mask,
36862306a36Sopenharmony_ci			RX_SGE(le16_to_cpu(cqe->sgl_or_raw_data.sgl[i])));
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n",
37162306a36Sopenharmony_ci	   sge_len - 1, le16_to_cpu(cqe->sgl_or_raw_data.sgl[sge_len - 1]));
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Here we assume that the last SGE index is the biggest */
37462306a36Sopenharmony_ci	prefetch((void *)(fp->sge_mask));
37562306a36Sopenharmony_ci	bnx2x_update_last_max_sge(fp,
37662306a36Sopenharmony_ci		le16_to_cpu(cqe->sgl_or_raw_data.sgl[sge_len - 1]));
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	last_max = RX_SGE(fp->last_max_sge);
37962306a36Sopenharmony_ci	last_elem = last_max >> BIT_VEC64_ELEM_SHIFT;
38062306a36Sopenharmony_ci	first_elem = RX_SGE(fp->rx_sge_prod) >> BIT_VEC64_ELEM_SHIFT;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* If ring is not full */
38362306a36Sopenharmony_ci	if (last_elem + 1 != first_elem)
38462306a36Sopenharmony_ci		last_elem++;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* Now update the prod */
38762306a36Sopenharmony_ci	for (i = first_elem; i != last_elem; i = NEXT_SGE_MASK_ELEM(i)) {
38862306a36Sopenharmony_ci		if (likely(fp->sge_mask[i]))
38962306a36Sopenharmony_ci			break;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		fp->sge_mask[i] = BIT_VEC64_ELEM_ONE_MASK;
39262306a36Sopenharmony_ci		delta += BIT_VEC64_ELEM_SZ;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (delta > 0) {
39662306a36Sopenharmony_ci		fp->rx_sge_prod += delta;
39762306a36Sopenharmony_ci		/* clear page-end entries */
39862306a36Sopenharmony_ci		bnx2x_clear_sge_mask_next_elems(fp);
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	DP(NETIF_MSG_RX_STATUS,
40262306a36Sopenharmony_ci	   "fp->last_max_sge = %d  fp->rx_sge_prod = %d\n",
40362306a36Sopenharmony_ci	   fp->last_max_sge, fp->rx_sge_prod);
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci/* Get Toeplitz hash value in the skb using the value from the
40762306a36Sopenharmony_ci * CQE (calculated by HW).
40862306a36Sopenharmony_ci */
40962306a36Sopenharmony_cistatic u32 bnx2x_get_rxhash(const struct bnx2x *bp,
41062306a36Sopenharmony_ci			    const struct eth_fast_path_rx_cqe *cqe,
41162306a36Sopenharmony_ci			    enum pkt_hash_types *rxhash_type)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	/* Get Toeplitz hash from CQE */
41462306a36Sopenharmony_ci	if ((bp->dev->features & NETIF_F_RXHASH) &&
41562306a36Sopenharmony_ci	    (cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG)) {
41662306a36Sopenharmony_ci		enum eth_rss_hash_type htype;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		htype = cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE;
41962306a36Sopenharmony_ci		*rxhash_type = ((htype == TCP_IPV4_HASH_TYPE) ||
42062306a36Sopenharmony_ci				(htype == TCP_IPV6_HASH_TYPE)) ?
42162306a36Sopenharmony_ci			       PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		return le32_to_cpu(cqe->rss_hash_result);
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	*rxhash_type = PKT_HASH_TYPE_NONE;
42662306a36Sopenharmony_ci	return 0;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
43062306a36Sopenharmony_ci			    u16 cons, u16 prod,
43162306a36Sopenharmony_ci			    struct eth_fast_path_rx_cqe *cqe)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct bnx2x *bp = fp->bp;
43462306a36Sopenharmony_ci	struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
43562306a36Sopenharmony_ci	struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
43662306a36Sopenharmony_ci	struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
43762306a36Sopenharmony_ci	dma_addr_t mapping;
43862306a36Sopenharmony_ci	struct bnx2x_agg_info *tpa_info = &fp->tpa_info[queue];
43962306a36Sopenharmony_ci	struct sw_rx_bd *first_buf = &tpa_info->first_buf;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/* print error if current state != stop */
44262306a36Sopenharmony_ci	if (tpa_info->tpa_state != BNX2X_TPA_STOP)
44362306a36Sopenharmony_ci		BNX2X_ERR("start of bin not in stop [%d]\n", queue);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/* Try to map an empty data buffer from the aggregation info  */
44662306a36Sopenharmony_ci	mapping = dma_map_single(&bp->pdev->dev,
44762306a36Sopenharmony_ci				 first_buf->data + NET_SKB_PAD,
44862306a36Sopenharmony_ci				 fp->rx_buf_size, DMA_FROM_DEVICE);
44962306a36Sopenharmony_ci	/*
45062306a36Sopenharmony_ci	 *  ...if it fails - move the skb from the consumer to the producer
45162306a36Sopenharmony_ci	 *  and set the current aggregation state as ERROR to drop it
45262306a36Sopenharmony_ci	 *  when TPA_STOP arrives.
45362306a36Sopenharmony_ci	 */
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
45662306a36Sopenharmony_ci		/* Move the BD from the consumer to the producer */
45762306a36Sopenharmony_ci		bnx2x_reuse_rx_data(fp, cons, prod);
45862306a36Sopenharmony_ci		tpa_info->tpa_state = BNX2X_TPA_ERROR;
45962306a36Sopenharmony_ci		return;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* move empty data from pool to prod */
46362306a36Sopenharmony_ci	prod_rx_buf->data = first_buf->data;
46462306a36Sopenharmony_ci	dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
46562306a36Sopenharmony_ci	/* point prod_bd to new data */
46662306a36Sopenharmony_ci	prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
46762306a36Sopenharmony_ci	prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* move partial skb from cons to pool (don't unmap yet) */
47062306a36Sopenharmony_ci	*first_buf = *cons_rx_buf;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* mark bin state as START */
47362306a36Sopenharmony_ci	tpa_info->parsing_flags =
47462306a36Sopenharmony_ci		le16_to_cpu(cqe->pars_flags.flags);
47562306a36Sopenharmony_ci	tpa_info->vlan_tag = le16_to_cpu(cqe->vlan_tag);
47662306a36Sopenharmony_ci	tpa_info->tpa_state = BNX2X_TPA_START;
47762306a36Sopenharmony_ci	tpa_info->len_on_bd = le16_to_cpu(cqe->len_on_bd);
47862306a36Sopenharmony_ci	tpa_info->placement_offset = cqe->placement_offset;
47962306a36Sopenharmony_ci	tpa_info->rxhash = bnx2x_get_rxhash(bp, cqe, &tpa_info->rxhash_type);
48062306a36Sopenharmony_ci	if (fp->mode == TPA_MODE_GRO) {
48162306a36Sopenharmony_ci		u16 gro_size = le16_to_cpu(cqe->pkt_len_or_gro_seg_len);
48262306a36Sopenharmony_ci		tpa_info->full_page = SGE_PAGES / gro_size * gro_size;
48362306a36Sopenharmony_ci		tpa_info->gro_size = gro_size;
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
48762306a36Sopenharmony_ci	fp->tpa_queue_used |= (1 << queue);
48862306a36Sopenharmony_ci	DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
48962306a36Sopenharmony_ci	   fp->tpa_queue_used);
49062306a36Sopenharmony_ci#endif
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci/* Timestamp option length allowed for TPA aggregation:
49462306a36Sopenharmony_ci *
49562306a36Sopenharmony_ci *		nop nop kind length echo val
49662306a36Sopenharmony_ci */
49762306a36Sopenharmony_ci#define TPA_TSTAMP_OPT_LEN	12
49862306a36Sopenharmony_ci/**
49962306a36Sopenharmony_ci * bnx2x_set_gro_params - compute GRO values
50062306a36Sopenharmony_ci *
50162306a36Sopenharmony_ci * @skb:		packet skb
50262306a36Sopenharmony_ci * @parsing_flags:	parsing flags from the START CQE
50362306a36Sopenharmony_ci * @len_on_bd:		total length of the first packet for the
50462306a36Sopenharmony_ci *			aggregation.
50562306a36Sopenharmony_ci * @pkt_len:		length of all segments
50662306a36Sopenharmony_ci * @num_of_coalesced_segs: count of segments
50762306a36Sopenharmony_ci *
50862306a36Sopenharmony_ci * Approximate value of the MSS for this aggregation calculated using
50962306a36Sopenharmony_ci * the first packet of it.
51062306a36Sopenharmony_ci * Compute number of aggregated segments, and gso_type.
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_cistatic void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags,
51362306a36Sopenharmony_ci				 u16 len_on_bd, unsigned int pkt_len,
51462306a36Sopenharmony_ci				 u16 num_of_coalesced_segs)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	/* TPA aggregation won't have either IP options or TCP options
51762306a36Sopenharmony_ci	 * other than timestamp or IPv6 extension headers.
51862306a36Sopenharmony_ci	 */
51962306a36Sopenharmony_ci	u16 hdrs_len = ETH_HLEN + sizeof(struct tcphdr);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (GET_FLAG(parsing_flags, PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
52262306a36Sopenharmony_ci	    PRS_FLAG_OVERETH_IPV6) {
52362306a36Sopenharmony_ci		hdrs_len += sizeof(struct ipv6hdr);
52462306a36Sopenharmony_ci		skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
52562306a36Sopenharmony_ci	} else {
52662306a36Sopenharmony_ci		hdrs_len += sizeof(struct iphdr);
52762306a36Sopenharmony_ci		skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* Check if there was a TCP timestamp, if there is it's will
53162306a36Sopenharmony_ci	 * always be 12 bytes length: nop nop kind length echo val.
53262306a36Sopenharmony_ci	 *
53362306a36Sopenharmony_ci	 * Otherwise FW would close the aggregation.
53462306a36Sopenharmony_ci	 */
53562306a36Sopenharmony_ci	if (parsing_flags & PARSING_FLAGS_TIME_STAMP_EXIST_FLAG)
53662306a36Sopenharmony_ci		hdrs_len += TPA_TSTAMP_OPT_LEN;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	skb_shinfo(skb)->gso_size = len_on_bd - hdrs_len;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	/* tcp_gro_complete() will copy NAPI_GRO_CB(skb)->count
54162306a36Sopenharmony_ci	 * to skb_shinfo(skb)->gso_segs
54262306a36Sopenharmony_ci	 */
54362306a36Sopenharmony_ci	NAPI_GRO_CB(skb)->count = num_of_coalesced_segs;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic int bnx2x_alloc_rx_sge(struct bnx2x *bp, struct bnx2x_fastpath *fp,
54762306a36Sopenharmony_ci			      u16 index, gfp_t gfp_mask)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
55062306a36Sopenharmony_ci	struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
55162306a36Sopenharmony_ci	struct bnx2x_alloc_pool *pool = &fp->page_pool;
55262306a36Sopenharmony_ci	dma_addr_t mapping;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (!pool->page) {
55562306a36Sopenharmony_ci		pool->page = alloc_pages(gfp_mask, PAGES_PER_SGE_SHIFT);
55662306a36Sopenharmony_ci		if (unlikely(!pool->page))
55762306a36Sopenharmony_ci			return -ENOMEM;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		pool->offset = 0;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	mapping = dma_map_page(&bp->pdev->dev, pool->page,
56362306a36Sopenharmony_ci			       pool->offset, SGE_PAGE_SIZE, DMA_FROM_DEVICE);
56462306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
56562306a36Sopenharmony_ci		BNX2X_ERR("Can't map sge\n");
56662306a36Sopenharmony_ci		return -ENOMEM;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	sw_buf->page = pool->page;
57062306a36Sopenharmony_ci	sw_buf->offset = pool->offset;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	dma_unmap_addr_set(sw_buf, mapping, mapping);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	sge->addr_hi = cpu_to_le32(U64_HI(mapping));
57562306a36Sopenharmony_ci	sge->addr_lo = cpu_to_le32(U64_LO(mapping));
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	pool->offset += SGE_PAGE_SIZE;
57862306a36Sopenharmony_ci	if (PAGE_SIZE - pool->offset >= SGE_PAGE_SIZE)
57962306a36Sopenharmony_ci		get_page(pool->page);
58062306a36Sopenharmony_ci	else
58162306a36Sopenharmony_ci		pool->page = NULL;
58262306a36Sopenharmony_ci	return 0;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
58662306a36Sopenharmony_ci			       struct bnx2x_agg_info *tpa_info,
58762306a36Sopenharmony_ci			       u16 pages,
58862306a36Sopenharmony_ci			       struct sk_buff *skb,
58962306a36Sopenharmony_ci			       struct eth_end_agg_rx_cqe *cqe,
59062306a36Sopenharmony_ci			       u16 cqe_idx)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct sw_rx_page *rx_pg, old_rx_pg;
59362306a36Sopenharmony_ci	u32 i, frag_len, frag_size;
59462306a36Sopenharmony_ci	int err, j, frag_id = 0;
59562306a36Sopenharmony_ci	u16 len_on_bd = tpa_info->len_on_bd;
59662306a36Sopenharmony_ci	u16 full_page = 0, gro_size = 0;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	frag_size = le16_to_cpu(cqe->pkt_len) - len_on_bd;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (fp->mode == TPA_MODE_GRO) {
60162306a36Sopenharmony_ci		gro_size = tpa_info->gro_size;
60262306a36Sopenharmony_ci		full_page = tpa_info->full_page;
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* This is needed in order to enable forwarding support */
60662306a36Sopenharmony_ci	if (frag_size)
60762306a36Sopenharmony_ci		bnx2x_set_gro_params(skb, tpa_info->parsing_flags, len_on_bd,
60862306a36Sopenharmony_ci				     le16_to_cpu(cqe->pkt_len),
60962306a36Sopenharmony_ci				     le16_to_cpu(cqe->num_of_coalesced_segs));
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
61262306a36Sopenharmony_ci	if (pages > min_t(u32, 8, MAX_SKB_FRAGS) * SGE_PAGES) {
61362306a36Sopenharmony_ci		BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
61462306a36Sopenharmony_ci			  pages, cqe_idx);
61562306a36Sopenharmony_ci		BNX2X_ERR("cqe->pkt_len = %d\n", cqe->pkt_len);
61662306a36Sopenharmony_ci		bnx2x_panic();
61762306a36Sopenharmony_ci		return -EINVAL;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci#endif
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* Run through the SGL and compose the fragmented skb */
62262306a36Sopenharmony_ci	for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) {
62362306a36Sopenharmony_ci		u16 sge_idx = RX_SGE(le16_to_cpu(cqe->sgl_or_raw_data.sgl[j]));
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		/* FW gives the indices of the SGE as if the ring is an array
62662306a36Sopenharmony_ci		   (meaning that "next" element will consume 2 indices) */
62762306a36Sopenharmony_ci		if (fp->mode == TPA_MODE_GRO)
62862306a36Sopenharmony_ci			frag_len = min_t(u32, frag_size, (u32)full_page);
62962306a36Sopenharmony_ci		else /* LRO */
63062306a36Sopenharmony_ci			frag_len = min_t(u32, frag_size, (u32)SGE_PAGES);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		rx_pg = &fp->rx_page_ring[sge_idx];
63362306a36Sopenharmony_ci		old_rx_pg = *rx_pg;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		/* If we fail to allocate a substitute page, we simply stop
63662306a36Sopenharmony_ci		   where we are and drop the whole packet */
63762306a36Sopenharmony_ci		err = bnx2x_alloc_rx_sge(bp, fp, sge_idx, GFP_ATOMIC);
63862306a36Sopenharmony_ci		if (unlikely(err)) {
63962306a36Sopenharmony_ci			bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++;
64062306a36Sopenharmony_ci			return err;
64162306a36Sopenharmony_ci		}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		dma_unmap_page(&bp->pdev->dev,
64462306a36Sopenharmony_ci			       dma_unmap_addr(&old_rx_pg, mapping),
64562306a36Sopenharmony_ci			       SGE_PAGE_SIZE, DMA_FROM_DEVICE);
64662306a36Sopenharmony_ci		/* Add one frag and update the appropriate fields in the skb */
64762306a36Sopenharmony_ci		if (fp->mode == TPA_MODE_LRO)
64862306a36Sopenharmony_ci			skb_fill_page_desc(skb, j, old_rx_pg.page,
64962306a36Sopenharmony_ci					   old_rx_pg.offset, frag_len);
65062306a36Sopenharmony_ci		else { /* GRO */
65162306a36Sopenharmony_ci			int rem;
65262306a36Sopenharmony_ci			int offset = 0;
65362306a36Sopenharmony_ci			for (rem = frag_len; rem > 0; rem -= gro_size) {
65462306a36Sopenharmony_ci				int len = rem > gro_size ? gro_size : rem;
65562306a36Sopenharmony_ci				skb_fill_page_desc(skb, frag_id++,
65662306a36Sopenharmony_ci						   old_rx_pg.page,
65762306a36Sopenharmony_ci						   old_rx_pg.offset + offset,
65862306a36Sopenharmony_ci						   len);
65962306a36Sopenharmony_ci				if (offset)
66062306a36Sopenharmony_ci					get_page(old_rx_pg.page);
66162306a36Sopenharmony_ci				offset += len;
66262306a36Sopenharmony_ci			}
66362306a36Sopenharmony_ci		}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		skb->data_len += frag_len;
66662306a36Sopenharmony_ci		skb->truesize += SGE_PAGES;
66762306a36Sopenharmony_ci		skb->len += frag_len;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		frag_size -= frag_len;
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	return 0;
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic struct sk_buff *
67662306a36Sopenharmony_cibnx2x_build_skb(const struct bnx2x_fastpath *fp, void *data)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	struct sk_buff *skb;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (fp->rx_frag_size)
68162306a36Sopenharmony_ci		skb = build_skb(data, fp->rx_frag_size);
68262306a36Sopenharmony_ci	else
68362306a36Sopenharmony_ci		skb = slab_build_skb(data);
68462306a36Sopenharmony_ci	return skb;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic void bnx2x_frag_free(const struct bnx2x_fastpath *fp, void *data)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	if (fp->rx_frag_size)
69062306a36Sopenharmony_ci		skb_free_frag(data);
69162306a36Sopenharmony_ci	else
69262306a36Sopenharmony_ci		kfree(data);
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp, gfp_t gfp_mask)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	if (fp->rx_frag_size) {
69862306a36Sopenharmony_ci		/* GFP_KERNEL allocations are used only during initialization */
69962306a36Sopenharmony_ci		if (unlikely(gfpflags_allow_blocking(gfp_mask)))
70062306a36Sopenharmony_ci			return (void *)__get_free_page(gfp_mask);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		return napi_alloc_frag(fp->rx_frag_size);
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	return kmalloc(fp->rx_buf_size + NET_SKB_PAD, gfp_mask);
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci#ifdef CONFIG_INET
70962306a36Sopenharmony_cistatic void bnx2x_gro_ip_csum(struct bnx2x *bp, struct sk_buff *skb)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	const struct iphdr *iph = ip_hdr(skb);
71262306a36Sopenharmony_ci	struct tcphdr *th;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	skb_set_transport_header(skb, sizeof(struct iphdr));
71562306a36Sopenharmony_ci	th = tcp_hdr(skb);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
71862306a36Sopenharmony_ci				  iph->saddr, iph->daddr, 0);
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic void bnx2x_gro_ipv6_csum(struct bnx2x *bp, struct sk_buff *skb)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	struct ipv6hdr *iph = ipv6_hdr(skb);
72462306a36Sopenharmony_ci	struct tcphdr *th;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	skb_set_transport_header(skb, sizeof(struct ipv6hdr));
72762306a36Sopenharmony_ci	th = tcp_hdr(skb);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
73062306a36Sopenharmony_ci				  &iph->saddr, &iph->daddr, 0);
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic void bnx2x_gro_csum(struct bnx2x *bp, struct sk_buff *skb,
73462306a36Sopenharmony_ci			    void (*gro_func)(struct bnx2x*, struct sk_buff*))
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	skb_reset_network_header(skb);
73762306a36Sopenharmony_ci	gro_func(bp, skb);
73862306a36Sopenharmony_ci	tcp_gro_complete(skb);
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci#endif
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp,
74362306a36Sopenharmony_ci			       struct sk_buff *skb)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci#ifdef CONFIG_INET
74662306a36Sopenharmony_ci	if (skb_shinfo(skb)->gso_size) {
74762306a36Sopenharmony_ci		switch (be16_to_cpu(skb->protocol)) {
74862306a36Sopenharmony_ci		case ETH_P_IP:
74962306a36Sopenharmony_ci			bnx2x_gro_csum(bp, skb, bnx2x_gro_ip_csum);
75062306a36Sopenharmony_ci			break;
75162306a36Sopenharmony_ci		case ETH_P_IPV6:
75262306a36Sopenharmony_ci			bnx2x_gro_csum(bp, skb, bnx2x_gro_ipv6_csum);
75362306a36Sopenharmony_ci			break;
75462306a36Sopenharmony_ci		default:
75562306a36Sopenharmony_ci			netdev_WARN_ONCE(bp->dev,
75662306a36Sopenharmony_ci					 "Error: FW GRO supports only IPv4/IPv6, not 0x%04x\n",
75762306a36Sopenharmony_ci					 be16_to_cpu(skb->protocol));
75862306a36Sopenharmony_ci		}
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci#endif
76162306a36Sopenharmony_ci	skb_record_rx_queue(skb, fp->rx_queue);
76262306a36Sopenharmony_ci	napi_gro_receive(&fp->napi, skb);
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cistatic void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
76662306a36Sopenharmony_ci			   struct bnx2x_agg_info *tpa_info,
76762306a36Sopenharmony_ci			   u16 pages,
76862306a36Sopenharmony_ci			   struct eth_end_agg_rx_cqe *cqe,
76962306a36Sopenharmony_ci			   u16 cqe_idx)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	struct sw_rx_bd *rx_buf = &tpa_info->first_buf;
77262306a36Sopenharmony_ci	u8 pad = tpa_info->placement_offset;
77362306a36Sopenharmony_ci	u16 len = tpa_info->len_on_bd;
77462306a36Sopenharmony_ci	struct sk_buff *skb = NULL;
77562306a36Sopenharmony_ci	u8 *new_data, *data = rx_buf->data;
77662306a36Sopenharmony_ci	u8 old_tpa_state = tpa_info->tpa_state;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	tpa_info->tpa_state = BNX2X_TPA_STOP;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* If we there was an error during the handling of the TPA_START -
78162306a36Sopenharmony_ci	 * drop this aggregation.
78262306a36Sopenharmony_ci	 */
78362306a36Sopenharmony_ci	if (old_tpa_state == BNX2X_TPA_ERROR)
78462306a36Sopenharmony_ci		goto drop;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	/* Try to allocate the new data */
78762306a36Sopenharmony_ci	new_data = bnx2x_frag_alloc(fp, GFP_ATOMIC);
78862306a36Sopenharmony_ci	/* Unmap skb in the pool anyway, as we are going to change
78962306a36Sopenharmony_ci	   pool entry status to BNX2X_TPA_STOP even if new skb allocation
79062306a36Sopenharmony_ci	   fails. */
79162306a36Sopenharmony_ci	dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
79262306a36Sopenharmony_ci			 fp->rx_buf_size, DMA_FROM_DEVICE);
79362306a36Sopenharmony_ci	if (likely(new_data))
79462306a36Sopenharmony_ci		skb = bnx2x_build_skb(fp, data);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	if (likely(skb)) {
79762306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
79862306a36Sopenharmony_ci		if (pad + len > fp->rx_buf_size) {
79962306a36Sopenharmony_ci			BNX2X_ERR("skb_put is about to fail...  pad %d  len %d  rx_buf_size %d\n",
80062306a36Sopenharmony_ci				  pad, len, fp->rx_buf_size);
80162306a36Sopenharmony_ci			bnx2x_panic();
80262306a36Sopenharmony_ci			bnx2x_frag_free(fp, new_data);
80362306a36Sopenharmony_ci			return;
80462306a36Sopenharmony_ci		}
80562306a36Sopenharmony_ci#endif
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		skb_reserve(skb, pad + NET_SKB_PAD);
80862306a36Sopenharmony_ci		skb_put(skb, len);
80962306a36Sopenharmony_ci		skb_set_hash(skb, tpa_info->rxhash, tpa_info->rxhash_type);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, bp->dev);
81262306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		if (!bnx2x_fill_frag_skb(bp, fp, tpa_info, pages,
81562306a36Sopenharmony_ci					 skb, cqe, cqe_idx)) {
81662306a36Sopenharmony_ci			if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN)
81762306a36Sopenharmony_ci				__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tpa_info->vlan_tag);
81862306a36Sopenharmony_ci			bnx2x_gro_receive(bp, fp, skb);
81962306a36Sopenharmony_ci		} else {
82062306a36Sopenharmony_ci			DP(NETIF_MSG_RX_STATUS,
82162306a36Sopenharmony_ci			   "Failed to allocate new pages - dropping packet!\n");
82262306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
82362306a36Sopenharmony_ci		}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		/* put new data in bin */
82662306a36Sopenharmony_ci		rx_buf->data = new_data;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci		return;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci	if (new_data)
83162306a36Sopenharmony_ci		bnx2x_frag_free(fp, new_data);
83262306a36Sopenharmony_cidrop:
83362306a36Sopenharmony_ci	/* drop the packet and keep the buffer in the bin */
83462306a36Sopenharmony_ci	DP(NETIF_MSG_RX_STATUS,
83562306a36Sopenharmony_ci	   "Failed to allocate or map a new skb - dropping packet!\n");
83662306a36Sopenharmony_ci	bnx2x_fp_stats(bp, fp)->eth_q_stats.rx_skb_alloc_failed++;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int bnx2x_alloc_rx_data(struct bnx2x *bp, struct bnx2x_fastpath *fp,
84062306a36Sopenharmony_ci			       u16 index, gfp_t gfp_mask)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci	u8 *data;
84362306a36Sopenharmony_ci	struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
84462306a36Sopenharmony_ci	struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
84562306a36Sopenharmony_ci	dma_addr_t mapping;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	data = bnx2x_frag_alloc(fp, gfp_mask);
84862306a36Sopenharmony_ci	if (unlikely(data == NULL))
84962306a36Sopenharmony_ci		return -ENOMEM;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	mapping = dma_map_single(&bp->pdev->dev, data + NET_SKB_PAD,
85262306a36Sopenharmony_ci				 fp->rx_buf_size,
85362306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
85462306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
85562306a36Sopenharmony_ci		bnx2x_frag_free(fp, data);
85662306a36Sopenharmony_ci		BNX2X_ERR("Can't map rx data\n");
85762306a36Sopenharmony_ci		return -ENOMEM;
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	rx_buf->data = data;
86162306a36Sopenharmony_ci	dma_unmap_addr_set(rx_buf, mapping, mapping);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
86462306a36Sopenharmony_ci	rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	return 0;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic
87062306a36Sopenharmony_civoid bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe,
87162306a36Sopenharmony_ci				 struct bnx2x_fastpath *fp,
87262306a36Sopenharmony_ci				 struct bnx2x_eth_q_stats *qstats)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	/* Do nothing if no L4 csum validation was done.
87562306a36Sopenharmony_ci	 * We do not check whether IP csum was validated. For IPv4 we assume
87662306a36Sopenharmony_ci	 * that if the card got as far as validating the L4 csum, it also
87762306a36Sopenharmony_ci	 * validated the IP csum. IPv6 has no IP csum.
87862306a36Sopenharmony_ci	 */
87962306a36Sopenharmony_ci	if (cqe->fast_path_cqe.status_flags &
88062306a36Sopenharmony_ci	    ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG)
88162306a36Sopenharmony_ci		return;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* If L4 validation was done, check if an error was found. */
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	if (cqe->fast_path_cqe.type_error_flags &
88662306a36Sopenharmony_ci	    (ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG |
88762306a36Sopenharmony_ci	     ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG))
88862306a36Sopenharmony_ci		qstats->hw_csum_err++;
88962306a36Sopenharmony_ci	else
89062306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	struct bnx2x *bp = fp->bp;
89662306a36Sopenharmony_ci	u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons;
89762306a36Sopenharmony_ci	u16 sw_comp_cons, sw_comp_prod;
89862306a36Sopenharmony_ci	int rx_pkt = 0;
89962306a36Sopenharmony_ci	union eth_rx_cqe *cqe;
90062306a36Sopenharmony_ci	struct eth_fast_path_rx_cqe *cqe_fp;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
90362306a36Sopenharmony_ci	if (unlikely(bp->panic))
90462306a36Sopenharmony_ci		return 0;
90562306a36Sopenharmony_ci#endif
90662306a36Sopenharmony_ci	if (budget <= 0)
90762306a36Sopenharmony_ci		return rx_pkt;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	bd_cons = fp->rx_bd_cons;
91062306a36Sopenharmony_ci	bd_prod = fp->rx_bd_prod;
91162306a36Sopenharmony_ci	bd_prod_fw = bd_prod;
91262306a36Sopenharmony_ci	sw_comp_cons = fp->rx_comp_cons;
91362306a36Sopenharmony_ci	sw_comp_prod = fp->rx_comp_prod;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	comp_ring_cons = RCQ_BD(sw_comp_cons);
91662306a36Sopenharmony_ci	cqe = &fp->rx_comp_ring[comp_ring_cons];
91762306a36Sopenharmony_ci	cqe_fp = &cqe->fast_path_cqe;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	DP(NETIF_MSG_RX_STATUS,
92062306a36Sopenharmony_ci	   "queue[%d]: sw_comp_cons %u\n", fp->index, sw_comp_cons);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	while (BNX2X_IS_CQE_COMPLETED(cqe_fp)) {
92362306a36Sopenharmony_ci		struct sw_rx_bd *rx_buf = NULL;
92462306a36Sopenharmony_ci		struct sk_buff *skb;
92562306a36Sopenharmony_ci		u8 cqe_fp_flags;
92662306a36Sopenharmony_ci		enum eth_rx_cqe_type cqe_fp_type;
92762306a36Sopenharmony_ci		u16 len, pad, queue;
92862306a36Sopenharmony_ci		u8 *data;
92962306a36Sopenharmony_ci		u32 rxhash;
93062306a36Sopenharmony_ci		enum pkt_hash_types rxhash_type;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
93362306a36Sopenharmony_ci		if (unlikely(bp->panic))
93462306a36Sopenharmony_ci			return 0;
93562306a36Sopenharmony_ci#endif
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci		bd_prod = RX_BD(bd_prod);
93862306a36Sopenharmony_ci		bd_cons = RX_BD(bd_cons);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		/* A rmb() is required to ensure that the CQE is not read
94162306a36Sopenharmony_ci		 * before it is written by the adapter DMA.  PCI ordering
94262306a36Sopenharmony_ci		 * rules will make sure the other fields are written before
94362306a36Sopenharmony_ci		 * the marker at the end of struct eth_fast_path_rx_cqe
94462306a36Sopenharmony_ci		 * but without rmb() a weakly ordered processor can process
94562306a36Sopenharmony_ci		 * stale data.  Without the barrier TPA state-machine might
94662306a36Sopenharmony_ci		 * enter inconsistent state and kernel stack might be
94762306a36Sopenharmony_ci		 * provided with incorrect packet description - these lead
94862306a36Sopenharmony_ci		 * to various kernel crashed.
94962306a36Sopenharmony_ci		 */
95062306a36Sopenharmony_ci		rmb();
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		cqe_fp_flags = cqe_fp->type_error_flags;
95362306a36Sopenharmony_ci		cqe_fp_type = cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci		DP(NETIF_MSG_RX_STATUS,
95662306a36Sopenharmony_ci		   "CQE type %x  err %x  status %x  queue %x  vlan %x  len %u\n",
95762306a36Sopenharmony_ci		   CQE_TYPE(cqe_fp_flags),
95862306a36Sopenharmony_ci		   cqe_fp_flags, cqe_fp->status_flags,
95962306a36Sopenharmony_ci		   le32_to_cpu(cqe_fp->rss_hash_result),
96062306a36Sopenharmony_ci		   le16_to_cpu(cqe_fp->vlan_tag),
96162306a36Sopenharmony_ci		   le16_to_cpu(cqe_fp->pkt_len_or_gro_seg_len));
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		/* is this a slowpath msg? */
96462306a36Sopenharmony_ci		if (unlikely(CQE_TYPE_SLOW(cqe_fp_type))) {
96562306a36Sopenharmony_ci			bnx2x_sp_event(fp, cqe);
96662306a36Sopenharmony_ci			goto next_cqe;
96762306a36Sopenharmony_ci		}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		rx_buf = &fp->rx_buf_ring[bd_cons];
97062306a36Sopenharmony_ci		data = rx_buf->data;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci		if (!CQE_TYPE_FAST(cqe_fp_type)) {
97362306a36Sopenharmony_ci			struct bnx2x_agg_info *tpa_info;
97462306a36Sopenharmony_ci			u16 frag_size, pages;
97562306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
97662306a36Sopenharmony_ci			/* sanity check */
97762306a36Sopenharmony_ci			if (fp->mode == TPA_MODE_DISABLED &&
97862306a36Sopenharmony_ci			    (CQE_TYPE_START(cqe_fp_type) ||
97962306a36Sopenharmony_ci			     CQE_TYPE_STOP(cqe_fp_type)))
98062306a36Sopenharmony_ci				BNX2X_ERR("START/STOP packet while TPA disabled, type %x\n",
98162306a36Sopenharmony_ci					  CQE_TYPE(cqe_fp_type));
98262306a36Sopenharmony_ci#endif
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci			if (CQE_TYPE_START(cqe_fp_type)) {
98562306a36Sopenharmony_ci				u16 queue = cqe_fp->queue_index;
98662306a36Sopenharmony_ci				DP(NETIF_MSG_RX_STATUS,
98762306a36Sopenharmony_ci				   "calling tpa_start on queue %d\n",
98862306a36Sopenharmony_ci				   queue);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci				bnx2x_tpa_start(fp, queue,
99162306a36Sopenharmony_ci						bd_cons, bd_prod,
99262306a36Sopenharmony_ci						cqe_fp);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci				goto next_rx;
99562306a36Sopenharmony_ci			}
99662306a36Sopenharmony_ci			queue = cqe->end_agg_cqe.queue_index;
99762306a36Sopenharmony_ci			tpa_info = &fp->tpa_info[queue];
99862306a36Sopenharmony_ci			DP(NETIF_MSG_RX_STATUS,
99962306a36Sopenharmony_ci			   "calling tpa_stop on queue %d\n",
100062306a36Sopenharmony_ci			   queue);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci			frag_size = le16_to_cpu(cqe->end_agg_cqe.pkt_len) -
100362306a36Sopenharmony_ci				    tpa_info->len_on_bd;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci			if (fp->mode == TPA_MODE_GRO)
100662306a36Sopenharmony_ci				pages = (frag_size + tpa_info->full_page - 1) /
100762306a36Sopenharmony_ci					 tpa_info->full_page;
100862306a36Sopenharmony_ci			else
100962306a36Sopenharmony_ci				pages = SGE_PAGE_ALIGN(frag_size) >>
101062306a36Sopenharmony_ci					SGE_PAGE_SHIFT;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci			bnx2x_tpa_stop(bp, fp, tpa_info, pages,
101362306a36Sopenharmony_ci				       &cqe->end_agg_cqe, comp_ring_cons);
101462306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
101562306a36Sopenharmony_ci			if (bp->panic)
101662306a36Sopenharmony_ci				return 0;
101762306a36Sopenharmony_ci#endif
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci			bnx2x_update_sge_prod(fp, pages, &cqe->end_agg_cqe);
102062306a36Sopenharmony_ci			goto next_cqe;
102162306a36Sopenharmony_ci		}
102262306a36Sopenharmony_ci		/* non TPA */
102362306a36Sopenharmony_ci		len = le16_to_cpu(cqe_fp->pkt_len_or_gro_seg_len);
102462306a36Sopenharmony_ci		pad = cqe_fp->placement_offset;
102562306a36Sopenharmony_ci		dma_sync_single_for_cpu(&bp->pdev->dev,
102662306a36Sopenharmony_ci					dma_unmap_addr(rx_buf, mapping),
102762306a36Sopenharmony_ci					pad + RX_COPY_THRESH,
102862306a36Sopenharmony_ci					DMA_FROM_DEVICE);
102962306a36Sopenharmony_ci		pad += NET_SKB_PAD;
103062306a36Sopenharmony_ci		prefetch(data + pad); /* speedup eth_type_trans() */
103162306a36Sopenharmony_ci		/* is this an error packet? */
103262306a36Sopenharmony_ci		if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
103362306a36Sopenharmony_ci			DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS,
103462306a36Sopenharmony_ci			   "ERROR  flags %x  rx packet %u\n",
103562306a36Sopenharmony_ci			   cqe_fp_flags, sw_comp_cons);
103662306a36Sopenharmony_ci			bnx2x_fp_qstats(bp, fp)->rx_err_discard_pkt++;
103762306a36Sopenharmony_ci			goto reuse_rx;
103862306a36Sopenharmony_ci		}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci		/* Since we don't have a jumbo ring
104162306a36Sopenharmony_ci		 * copy small packets if mtu > 1500
104262306a36Sopenharmony_ci		 */
104362306a36Sopenharmony_ci		if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
104462306a36Sopenharmony_ci		    (len <= RX_COPY_THRESH)) {
104562306a36Sopenharmony_ci			skb = napi_alloc_skb(&fp->napi, len);
104662306a36Sopenharmony_ci			if (skb == NULL) {
104762306a36Sopenharmony_ci				DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS,
104862306a36Sopenharmony_ci				   "ERROR  packet dropped because of alloc failure\n");
104962306a36Sopenharmony_ci				bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++;
105062306a36Sopenharmony_ci				goto reuse_rx;
105162306a36Sopenharmony_ci			}
105262306a36Sopenharmony_ci			memcpy(skb->data, data + pad, len);
105362306a36Sopenharmony_ci			bnx2x_reuse_rx_data(fp, bd_cons, bd_prod);
105462306a36Sopenharmony_ci		} else {
105562306a36Sopenharmony_ci			if (likely(bnx2x_alloc_rx_data(bp, fp, bd_prod,
105662306a36Sopenharmony_ci						       GFP_ATOMIC) == 0)) {
105762306a36Sopenharmony_ci				dma_unmap_single(&bp->pdev->dev,
105862306a36Sopenharmony_ci						 dma_unmap_addr(rx_buf, mapping),
105962306a36Sopenharmony_ci						 fp->rx_buf_size,
106062306a36Sopenharmony_ci						 DMA_FROM_DEVICE);
106162306a36Sopenharmony_ci				skb = bnx2x_build_skb(fp, data);
106262306a36Sopenharmony_ci				if (unlikely(!skb)) {
106362306a36Sopenharmony_ci					bnx2x_frag_free(fp, data);
106462306a36Sopenharmony_ci					bnx2x_fp_qstats(bp, fp)->
106562306a36Sopenharmony_ci							rx_skb_alloc_failed++;
106662306a36Sopenharmony_ci					goto next_rx;
106762306a36Sopenharmony_ci				}
106862306a36Sopenharmony_ci				skb_reserve(skb, pad);
106962306a36Sopenharmony_ci			} else {
107062306a36Sopenharmony_ci				DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS,
107162306a36Sopenharmony_ci				   "ERROR  packet dropped because of alloc failure\n");
107262306a36Sopenharmony_ci				bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++;
107362306a36Sopenharmony_cireuse_rx:
107462306a36Sopenharmony_ci				bnx2x_reuse_rx_data(fp, bd_cons, bd_prod);
107562306a36Sopenharmony_ci				goto next_rx;
107662306a36Sopenharmony_ci			}
107762306a36Sopenharmony_ci		}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		skb_put(skb, len);
108062306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, bp->dev);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci		/* Set Toeplitz hash for a none-LRO skb */
108362306a36Sopenharmony_ci		rxhash = bnx2x_get_rxhash(bp, cqe_fp, &rxhash_type);
108462306a36Sopenharmony_ci		skb_set_hash(skb, rxhash, rxhash_type);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci		skb_checksum_none_assert(skb);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci		if (bp->dev->features & NETIF_F_RXCSUM)
108962306a36Sopenharmony_ci			bnx2x_csum_validate(skb, cqe, fp,
109062306a36Sopenharmony_ci					    bnx2x_fp_qstats(bp, fp));
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		skb_record_rx_queue(skb, fp->rx_queue);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci		/* Check if this packet was timestamped */
109562306a36Sopenharmony_ci		if (unlikely(cqe->fast_path_cqe.type_error_flags &
109662306a36Sopenharmony_ci			     (1 << ETH_FAST_PATH_RX_CQE_PTP_PKT_SHIFT)))
109762306a36Sopenharmony_ci			bnx2x_set_rx_ts(bp, skb);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci		if (le16_to_cpu(cqe_fp->pars_flags.flags) &
110062306a36Sopenharmony_ci		    PARSING_FLAGS_VLAN)
110162306a36Sopenharmony_ci			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
110262306a36Sopenharmony_ci					       le16_to_cpu(cqe_fp->vlan_tag));
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci		napi_gro_receive(&fp->napi, skb);
110562306a36Sopenharmony_cinext_rx:
110662306a36Sopenharmony_ci		rx_buf->data = NULL;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci		bd_cons = NEXT_RX_IDX(bd_cons);
110962306a36Sopenharmony_ci		bd_prod = NEXT_RX_IDX(bd_prod);
111062306a36Sopenharmony_ci		bd_prod_fw = NEXT_RX_IDX(bd_prod_fw);
111162306a36Sopenharmony_ci		rx_pkt++;
111262306a36Sopenharmony_cinext_cqe:
111362306a36Sopenharmony_ci		sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod);
111462306a36Sopenharmony_ci		sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci		/* mark CQE as free */
111762306a36Sopenharmony_ci		BNX2X_SEED_CQE(cqe_fp);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci		if (rx_pkt == budget)
112062306a36Sopenharmony_ci			break;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		comp_ring_cons = RCQ_BD(sw_comp_cons);
112362306a36Sopenharmony_ci		cqe = &fp->rx_comp_ring[comp_ring_cons];
112462306a36Sopenharmony_ci		cqe_fp = &cqe->fast_path_cqe;
112562306a36Sopenharmony_ci	} /* while */
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	fp->rx_bd_cons = bd_cons;
112862306a36Sopenharmony_ci	fp->rx_bd_prod = bd_prod_fw;
112962306a36Sopenharmony_ci	fp->rx_comp_cons = sw_comp_cons;
113062306a36Sopenharmony_ci	fp->rx_comp_prod = sw_comp_prod;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	/* Update producers */
113362306a36Sopenharmony_ci	bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod,
113462306a36Sopenharmony_ci			     fp->rx_sge_prod);
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	return rx_pkt;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_cistatic irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	struct bnx2x_fastpath *fp = fp_cookie;
114262306a36Sopenharmony_ci	struct bnx2x *bp = fp->bp;
114362306a36Sopenharmony_ci	u8 cos;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	DP(NETIF_MSG_INTR,
114662306a36Sopenharmony_ci	   "got an MSI-X interrupt on IDX:SB [fp %d fw_sd %d igusb %d]\n",
114762306a36Sopenharmony_ci	   fp->index, fp->fw_sb_id, fp->igu_sb_id);
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
115262306a36Sopenharmony_ci	if (unlikely(bp->panic))
115362306a36Sopenharmony_ci		return IRQ_HANDLED;
115462306a36Sopenharmony_ci#endif
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	/* Handle Rx and Tx according to MSI-X vector */
115762306a36Sopenharmony_ci	for_each_cos_in_tx_queue(fp, cos)
115862306a36Sopenharmony_ci		prefetch(fp->txdata_ptr[cos]->tx_cons_sb);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	prefetch(&fp->sb_running_index[SM_RX_ID]);
116162306a36Sopenharmony_ci	napi_schedule_irqoff(&bnx2x_fp(bp, fp->index, napi));
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	return IRQ_HANDLED;
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci/* HW Lock for shared dual port PHYs */
116762306a36Sopenharmony_civoid bnx2x_acquire_phy_lock(struct bnx2x *bp)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	mutex_lock(&bp->port.phy_mutex);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_civoid bnx2x_release_phy_lock(struct bnx2x *bp)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	mutex_unlock(&bp->port.phy_mutex);
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci/* calculates MF speed according to current linespeed and MF configuration */
118262306a36Sopenharmony_ciu16 bnx2x_get_mf_speed(struct bnx2x *bp)
118362306a36Sopenharmony_ci{
118462306a36Sopenharmony_ci	u16 line_speed = bp->link_vars.line_speed;
118562306a36Sopenharmony_ci	if (IS_MF(bp)) {
118662306a36Sopenharmony_ci		u16 maxCfg = bnx2x_extract_max_cfg(bp,
118762306a36Sopenharmony_ci						   bp->mf_config[BP_VN(bp)]);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci		/* Calculate the current MAX line speed limit for the MF
119062306a36Sopenharmony_ci		 * devices
119162306a36Sopenharmony_ci		 */
119262306a36Sopenharmony_ci		if (IS_MF_PERCENT_BW(bp))
119362306a36Sopenharmony_ci			line_speed = (line_speed * maxCfg) / 100;
119462306a36Sopenharmony_ci		else { /* SD mode */
119562306a36Sopenharmony_ci			u16 vn_max_rate = maxCfg * 100;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci			if (vn_max_rate < line_speed)
119862306a36Sopenharmony_ci				line_speed = vn_max_rate;
119962306a36Sopenharmony_ci		}
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	return line_speed;
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci/**
120662306a36Sopenharmony_ci * bnx2x_fill_report_data - fill link report data to report
120762306a36Sopenharmony_ci *
120862306a36Sopenharmony_ci * @bp:		driver handle
120962306a36Sopenharmony_ci * @data:	link state to update
121062306a36Sopenharmony_ci *
121162306a36Sopenharmony_ci * It uses a none-atomic bit operations because is called under the mutex.
121262306a36Sopenharmony_ci */
121362306a36Sopenharmony_cistatic void bnx2x_fill_report_data(struct bnx2x *bp,
121462306a36Sopenharmony_ci				   struct bnx2x_link_report_data *data)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	memset(data, 0, sizeof(*data));
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	if (IS_PF(bp)) {
121962306a36Sopenharmony_ci		/* Fill the report data: effective line speed */
122062306a36Sopenharmony_ci		data->line_speed = bnx2x_get_mf_speed(bp);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci		/* Link is down */
122362306a36Sopenharmony_ci		if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS))
122462306a36Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
122562306a36Sopenharmony_ci				  &data->link_report_flags);
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci		if (!BNX2X_NUM_ETH_QUEUES(bp))
122862306a36Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
122962306a36Sopenharmony_ci				  &data->link_report_flags);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci		/* Full DUPLEX */
123262306a36Sopenharmony_ci		if (bp->link_vars.duplex == DUPLEX_FULL)
123362306a36Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_FD,
123462306a36Sopenharmony_ci				  &data->link_report_flags);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci		/* Rx Flow Control is ON */
123762306a36Sopenharmony_ci		if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX)
123862306a36Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_RX_FC_ON,
123962306a36Sopenharmony_ci				  &data->link_report_flags);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		/* Tx Flow Control is ON */
124262306a36Sopenharmony_ci		if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
124362306a36Sopenharmony_ci			__set_bit(BNX2X_LINK_REPORT_TX_FC_ON,
124462306a36Sopenharmony_ci				  &data->link_report_flags);
124562306a36Sopenharmony_ci	} else { /* VF */
124662306a36Sopenharmony_ci		*data = bp->vf_link_vars;
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci/**
125162306a36Sopenharmony_ci * bnx2x_link_report - report link status to OS.
125262306a36Sopenharmony_ci *
125362306a36Sopenharmony_ci * @bp:		driver handle
125462306a36Sopenharmony_ci *
125562306a36Sopenharmony_ci * Calls the __bnx2x_link_report() under the same locking scheme
125662306a36Sopenharmony_ci * as a link/PHY state managing code to ensure a consistent link
125762306a36Sopenharmony_ci * reporting.
125862306a36Sopenharmony_ci */
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_civoid bnx2x_link_report(struct bnx2x *bp)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	bnx2x_acquire_phy_lock(bp);
126362306a36Sopenharmony_ci	__bnx2x_link_report(bp);
126462306a36Sopenharmony_ci	bnx2x_release_phy_lock(bp);
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci/**
126862306a36Sopenharmony_ci * __bnx2x_link_report - report link status to OS.
126962306a36Sopenharmony_ci *
127062306a36Sopenharmony_ci * @bp:		driver handle
127162306a36Sopenharmony_ci *
127262306a36Sopenharmony_ci * None atomic implementation.
127362306a36Sopenharmony_ci * Should be called under the phy_lock.
127462306a36Sopenharmony_ci */
127562306a36Sopenharmony_civoid __bnx2x_link_report(struct bnx2x *bp)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	struct bnx2x_link_report_data cur_data;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	if (bp->force_link_down) {
128062306a36Sopenharmony_ci		bp->link_vars.link_up = 0;
128162306a36Sopenharmony_ci		return;
128262306a36Sopenharmony_ci	}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	/* reread mf_cfg */
128562306a36Sopenharmony_ci	if (IS_PF(bp) && !CHIP_IS_E1(bp))
128662306a36Sopenharmony_ci		bnx2x_read_mf_cfg(bp);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	/* Read the current link report info */
128962306a36Sopenharmony_ci	bnx2x_fill_report_data(bp, &cur_data);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	/* Don't report link down or exactly the same link status twice */
129262306a36Sopenharmony_ci	if (!memcmp(&cur_data, &bp->last_reported_link, sizeof(cur_data)) ||
129362306a36Sopenharmony_ci	    (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
129462306a36Sopenharmony_ci		      &bp->last_reported_link.link_report_flags) &&
129562306a36Sopenharmony_ci	     test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
129662306a36Sopenharmony_ci		      &cur_data.link_report_flags)))
129762306a36Sopenharmony_ci		return;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	bp->link_cnt++;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	/* We are going to report a new link parameters now -
130262306a36Sopenharmony_ci	 * remember the current data for the next time.
130362306a36Sopenharmony_ci	 */
130462306a36Sopenharmony_ci	memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data));
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/* propagate status to VFs */
130762306a36Sopenharmony_ci	if (IS_PF(bp))
130862306a36Sopenharmony_ci		bnx2x_iov_link_update(bp);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
131162306a36Sopenharmony_ci		     &cur_data.link_report_flags)) {
131262306a36Sopenharmony_ci		netif_carrier_off(bp->dev);
131362306a36Sopenharmony_ci		netdev_err(bp->dev, "NIC Link is Down\n");
131462306a36Sopenharmony_ci		return;
131562306a36Sopenharmony_ci	} else {
131662306a36Sopenharmony_ci		const char *duplex;
131762306a36Sopenharmony_ci		const char *flow;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci		netif_carrier_on(bp->dev);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci		if (test_and_clear_bit(BNX2X_LINK_REPORT_FD,
132262306a36Sopenharmony_ci				       &cur_data.link_report_flags))
132362306a36Sopenharmony_ci			duplex = "full";
132462306a36Sopenharmony_ci		else
132562306a36Sopenharmony_ci			duplex = "half";
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci		/* Handle the FC at the end so that only these flags would be
132862306a36Sopenharmony_ci		 * possibly set. This way we may easily check if there is no FC
132962306a36Sopenharmony_ci		 * enabled.
133062306a36Sopenharmony_ci		 */
133162306a36Sopenharmony_ci		if (cur_data.link_report_flags) {
133262306a36Sopenharmony_ci			if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON,
133362306a36Sopenharmony_ci				     &cur_data.link_report_flags)) {
133462306a36Sopenharmony_ci				if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON,
133562306a36Sopenharmony_ci				     &cur_data.link_report_flags))
133662306a36Sopenharmony_ci					flow = "ON - receive & transmit";
133762306a36Sopenharmony_ci				else
133862306a36Sopenharmony_ci					flow = "ON - receive";
133962306a36Sopenharmony_ci			} else {
134062306a36Sopenharmony_ci				flow = "ON - transmit";
134162306a36Sopenharmony_ci			}
134262306a36Sopenharmony_ci		} else {
134362306a36Sopenharmony_ci			flow = "none";
134462306a36Sopenharmony_ci		}
134562306a36Sopenharmony_ci		netdev_info(bp->dev, "NIC Link is Up, %d Mbps %s duplex, Flow control: %s\n",
134662306a36Sopenharmony_ci			    cur_data.line_speed, duplex, flow);
134762306a36Sopenharmony_ci	}
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic void bnx2x_set_next_page_sgl(struct bnx2x_fastpath *fp)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	int i;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
135562306a36Sopenharmony_ci		struct eth_rx_sge *sge;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2];
135862306a36Sopenharmony_ci		sge->addr_hi =
135962306a36Sopenharmony_ci			cpu_to_le32(U64_HI(fp->rx_sge_mapping +
136062306a36Sopenharmony_ci			BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci		sge->addr_lo =
136362306a36Sopenharmony_ci			cpu_to_le32(U64_LO(fp->rx_sge_mapping +
136462306a36Sopenharmony_ci			BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic void bnx2x_free_tpa_pool(struct bnx2x *bp,
136962306a36Sopenharmony_ci				struct bnx2x_fastpath *fp, int last)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	int i;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	for (i = 0; i < last; i++) {
137462306a36Sopenharmony_ci		struct bnx2x_agg_info *tpa_info = &fp->tpa_info[i];
137562306a36Sopenharmony_ci		struct sw_rx_bd *first_buf = &tpa_info->first_buf;
137662306a36Sopenharmony_ci		u8 *data = first_buf->data;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci		if (data == NULL) {
137962306a36Sopenharmony_ci			DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i);
138062306a36Sopenharmony_ci			continue;
138162306a36Sopenharmony_ci		}
138262306a36Sopenharmony_ci		if (tpa_info->tpa_state == BNX2X_TPA_START)
138362306a36Sopenharmony_ci			dma_unmap_single(&bp->pdev->dev,
138462306a36Sopenharmony_ci					 dma_unmap_addr(first_buf, mapping),
138562306a36Sopenharmony_ci					 fp->rx_buf_size, DMA_FROM_DEVICE);
138662306a36Sopenharmony_ci		bnx2x_frag_free(fp, data);
138762306a36Sopenharmony_ci		first_buf->data = NULL;
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_civoid bnx2x_init_rx_rings_cnic(struct bnx2x *bp)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	int j;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	for_each_rx_queue_cnic(bp, j) {
139662306a36Sopenharmony_ci		struct bnx2x_fastpath *fp = &bp->fp[j];
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci		fp->rx_bd_cons = 0;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		/* Activate BD ring */
140162306a36Sopenharmony_ci		/* Warning!
140262306a36Sopenharmony_ci		 * this will generate an interrupt (to the TSTORM)
140362306a36Sopenharmony_ci		 * must only be done after chip is initialized
140462306a36Sopenharmony_ci		 */
140562306a36Sopenharmony_ci		bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod,
140662306a36Sopenharmony_ci				     fp->rx_sge_prod);
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_civoid bnx2x_init_rx_rings(struct bnx2x *bp)
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci	int func = BP_FUNC(bp);
141362306a36Sopenharmony_ci	u16 ring_prod;
141462306a36Sopenharmony_ci	int i, j;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	/* Allocate TPA resources */
141762306a36Sopenharmony_ci	for_each_eth_queue(bp, j) {
141862306a36Sopenharmony_ci		struct bnx2x_fastpath *fp = &bp->fp[j];
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci		DP(NETIF_MSG_IFUP,
142162306a36Sopenharmony_ci		   "mtu %d  rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci		if (fp->mode != TPA_MODE_DISABLED) {
142462306a36Sopenharmony_ci			/* Fill the per-aggregation pool */
142562306a36Sopenharmony_ci			for (i = 0; i < MAX_AGG_QS(bp); i++) {
142662306a36Sopenharmony_ci				struct bnx2x_agg_info *tpa_info =
142762306a36Sopenharmony_ci					&fp->tpa_info[i];
142862306a36Sopenharmony_ci				struct sw_rx_bd *first_buf =
142962306a36Sopenharmony_ci					&tpa_info->first_buf;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci				first_buf->data =
143262306a36Sopenharmony_ci					bnx2x_frag_alloc(fp, GFP_KERNEL);
143362306a36Sopenharmony_ci				if (!first_buf->data) {
143462306a36Sopenharmony_ci					BNX2X_ERR("Failed to allocate TPA skb pool for queue[%d] - disabling TPA on this queue!\n",
143562306a36Sopenharmony_ci						  j);
143662306a36Sopenharmony_ci					bnx2x_free_tpa_pool(bp, fp, i);
143762306a36Sopenharmony_ci					fp->mode = TPA_MODE_DISABLED;
143862306a36Sopenharmony_ci					break;
143962306a36Sopenharmony_ci				}
144062306a36Sopenharmony_ci				dma_unmap_addr_set(first_buf, mapping, 0);
144162306a36Sopenharmony_ci				tpa_info->tpa_state = BNX2X_TPA_STOP;
144262306a36Sopenharmony_ci			}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci			/* "next page" elements initialization */
144562306a36Sopenharmony_ci			bnx2x_set_next_page_sgl(fp);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci			/* set SGEs bit mask */
144862306a36Sopenharmony_ci			bnx2x_init_sge_ring_bit_mask(fp);
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci			/* Allocate SGEs and initialize the ring elements */
145162306a36Sopenharmony_ci			for (i = 0, ring_prod = 0;
145262306a36Sopenharmony_ci			     i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) {
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci				if (bnx2x_alloc_rx_sge(bp, fp, ring_prod,
145562306a36Sopenharmony_ci						       GFP_KERNEL) < 0) {
145662306a36Sopenharmony_ci					BNX2X_ERR("was only able to allocate %d rx sges\n",
145762306a36Sopenharmony_ci						  i);
145862306a36Sopenharmony_ci					BNX2X_ERR("disabling TPA for queue[%d]\n",
145962306a36Sopenharmony_ci						  j);
146062306a36Sopenharmony_ci					/* Cleanup already allocated elements */
146162306a36Sopenharmony_ci					bnx2x_free_rx_sge_range(bp, fp,
146262306a36Sopenharmony_ci								ring_prod);
146362306a36Sopenharmony_ci					bnx2x_free_tpa_pool(bp, fp,
146462306a36Sopenharmony_ci							    MAX_AGG_QS(bp));
146562306a36Sopenharmony_ci					fp->mode = TPA_MODE_DISABLED;
146662306a36Sopenharmony_ci					ring_prod = 0;
146762306a36Sopenharmony_ci					break;
146862306a36Sopenharmony_ci				}
146962306a36Sopenharmony_ci				ring_prod = NEXT_SGE_IDX(ring_prod);
147062306a36Sopenharmony_ci			}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci			fp->rx_sge_prod = ring_prod;
147362306a36Sopenharmony_ci		}
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	for_each_eth_queue(bp, j) {
147762306a36Sopenharmony_ci		struct bnx2x_fastpath *fp = &bp->fp[j];
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		fp->rx_bd_cons = 0;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci		/* Activate BD ring */
148262306a36Sopenharmony_ci		/* Warning!
148362306a36Sopenharmony_ci		 * this will generate an interrupt (to the TSTORM)
148462306a36Sopenharmony_ci		 * must only be done after chip is initialized
148562306a36Sopenharmony_ci		 */
148662306a36Sopenharmony_ci		bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod,
148762306a36Sopenharmony_ci				     fp->rx_sge_prod);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		if (j != 0)
149062306a36Sopenharmony_ci			continue;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci		if (CHIP_IS_E1(bp)) {
149362306a36Sopenharmony_ci			REG_WR(bp, BAR_USTRORM_INTMEM +
149462306a36Sopenharmony_ci			       USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func),
149562306a36Sopenharmony_ci			       U64_LO(fp->rx_comp_mapping));
149662306a36Sopenharmony_ci			REG_WR(bp, BAR_USTRORM_INTMEM +
149762306a36Sopenharmony_ci			       USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4,
149862306a36Sopenharmony_ci			       U64_HI(fp->rx_comp_mapping));
149962306a36Sopenharmony_ci		}
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_cistatic void bnx2x_free_tx_skbs_queue(struct bnx2x_fastpath *fp)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	u8 cos;
150662306a36Sopenharmony_ci	struct bnx2x *bp = fp->bp;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	for_each_cos_in_tx_queue(fp, cos) {
150962306a36Sopenharmony_ci		struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
151062306a36Sopenharmony_ci		unsigned pkts_compl = 0, bytes_compl = 0;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci		u16 sw_prod = txdata->tx_pkt_prod;
151362306a36Sopenharmony_ci		u16 sw_cons = txdata->tx_pkt_cons;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci		while (sw_cons != sw_prod) {
151662306a36Sopenharmony_ci			bnx2x_free_tx_pkt(bp, txdata, TX_BD(sw_cons),
151762306a36Sopenharmony_ci					  &pkts_compl, &bytes_compl);
151862306a36Sopenharmony_ci			sw_cons++;
151962306a36Sopenharmony_ci		}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci		netdev_tx_reset_queue(
152262306a36Sopenharmony_ci			netdev_get_tx_queue(bp->dev,
152362306a36Sopenharmony_ci					    txdata->txq_index));
152462306a36Sopenharmony_ci	}
152562306a36Sopenharmony_ci}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_cistatic void bnx2x_free_tx_skbs_cnic(struct bnx2x *bp)
152862306a36Sopenharmony_ci{
152962306a36Sopenharmony_ci	int i;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	for_each_tx_queue_cnic(bp, i) {
153262306a36Sopenharmony_ci		bnx2x_free_tx_skbs_queue(&bp->fp[i]);
153362306a36Sopenharmony_ci	}
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_cistatic void bnx2x_free_tx_skbs(struct bnx2x *bp)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	int i;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	for_each_eth_queue(bp, i) {
154162306a36Sopenharmony_ci		bnx2x_free_tx_skbs_queue(&bp->fp[i]);
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_cistatic void bnx2x_free_rx_bds(struct bnx2x_fastpath *fp)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct bnx2x *bp = fp->bp;
154862306a36Sopenharmony_ci	int i;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	/* ring wasn't allocated */
155162306a36Sopenharmony_ci	if (fp->rx_buf_ring == NULL)
155262306a36Sopenharmony_ci		return;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	for (i = 0; i < NUM_RX_BD; i++) {
155562306a36Sopenharmony_ci		struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i];
155662306a36Sopenharmony_ci		u8 *data = rx_buf->data;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci		if (data == NULL)
155962306a36Sopenharmony_ci			continue;
156062306a36Sopenharmony_ci		dma_unmap_single(&bp->pdev->dev,
156162306a36Sopenharmony_ci				 dma_unmap_addr(rx_buf, mapping),
156262306a36Sopenharmony_ci				 fp->rx_buf_size, DMA_FROM_DEVICE);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci		rx_buf->data = NULL;
156562306a36Sopenharmony_ci		bnx2x_frag_free(fp, data);
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic void bnx2x_free_rx_skbs_cnic(struct bnx2x *bp)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	int j;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	for_each_rx_queue_cnic(bp, j) {
157462306a36Sopenharmony_ci		bnx2x_free_rx_bds(&bp->fp[j]);
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_cistatic void bnx2x_free_rx_skbs(struct bnx2x *bp)
157962306a36Sopenharmony_ci{
158062306a36Sopenharmony_ci	int j;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	for_each_eth_queue(bp, j) {
158362306a36Sopenharmony_ci		struct bnx2x_fastpath *fp = &bp->fp[j];
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci		bnx2x_free_rx_bds(fp);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci		if (fp->mode != TPA_MODE_DISABLED)
158862306a36Sopenharmony_ci			bnx2x_free_tpa_pool(bp, fp, MAX_AGG_QS(bp));
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_cistatic void bnx2x_free_skbs_cnic(struct bnx2x *bp)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	bnx2x_free_tx_skbs_cnic(bp);
159562306a36Sopenharmony_ci	bnx2x_free_rx_skbs_cnic(bp);
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_civoid bnx2x_free_skbs(struct bnx2x *bp)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	bnx2x_free_tx_skbs(bp);
160162306a36Sopenharmony_ci	bnx2x_free_rx_skbs(bp);
160262306a36Sopenharmony_ci}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_civoid bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	/* load old values */
160762306a36Sopenharmony_ci	u32 mf_cfg = bp->mf_config[BP_VN(bp)];
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	if (value != bnx2x_extract_max_cfg(bp, mf_cfg)) {
161062306a36Sopenharmony_ci		/* leave all but MAX value */
161162306a36Sopenharmony_ci		mf_cfg &= ~FUNC_MF_CFG_MAX_BW_MASK;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci		/* set new MAX value */
161462306a36Sopenharmony_ci		mf_cfg |= (value << FUNC_MF_CFG_MAX_BW_SHIFT)
161562306a36Sopenharmony_ci				& FUNC_MF_CFG_MAX_BW_MASK;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci		bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW, mf_cfg);
161862306a36Sopenharmony_ci	}
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci/**
162262306a36Sopenharmony_ci * bnx2x_free_msix_irqs - free previously requested MSI-X IRQ vectors
162362306a36Sopenharmony_ci *
162462306a36Sopenharmony_ci * @bp:		driver handle
162562306a36Sopenharmony_ci * @nvecs:	number of vectors to be released
162662306a36Sopenharmony_ci */
162762306a36Sopenharmony_cistatic void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
162862306a36Sopenharmony_ci{
162962306a36Sopenharmony_ci	int i, offset = 0;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	if (nvecs == offset)
163262306a36Sopenharmony_ci		return;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	/* VFs don't have a default SB */
163562306a36Sopenharmony_ci	if (IS_PF(bp)) {
163662306a36Sopenharmony_ci		free_irq(bp->msix_table[offset].vector, bp->dev);
163762306a36Sopenharmony_ci		DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
163862306a36Sopenharmony_ci		   bp->msix_table[offset].vector);
163962306a36Sopenharmony_ci		offset++;
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	if (CNIC_SUPPORT(bp)) {
164362306a36Sopenharmony_ci		if (nvecs == offset)
164462306a36Sopenharmony_ci			return;
164562306a36Sopenharmony_ci		offset++;
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	for_each_eth_queue(bp, i) {
164962306a36Sopenharmony_ci		if (nvecs == offset)
165062306a36Sopenharmony_ci			return;
165162306a36Sopenharmony_ci		DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq\n",
165262306a36Sopenharmony_ci		   i, bp->msix_table[offset].vector);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		free_irq(bp->msix_table[offset++].vector, &bp->fp[i]);
165562306a36Sopenharmony_ci	}
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_civoid bnx2x_free_irq(struct bnx2x *bp)
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	if (bp->flags & USING_MSIX_FLAG &&
166162306a36Sopenharmony_ci	    !(bp->flags & USING_SINGLE_MSIX_FLAG)) {
166262306a36Sopenharmony_ci		int nvecs = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci		/* vfs don't have a default status block */
166562306a36Sopenharmony_ci		if (IS_PF(bp))
166662306a36Sopenharmony_ci			nvecs++;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci		bnx2x_free_msix_irqs(bp, nvecs);
166962306a36Sopenharmony_ci	} else {
167062306a36Sopenharmony_ci		free_irq(bp->dev->irq, bp->dev);
167162306a36Sopenharmony_ci	}
167262306a36Sopenharmony_ci}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ciint bnx2x_enable_msix(struct bnx2x *bp)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	int msix_vec = 0, i, rc;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	/* VFs don't have a default status block */
167962306a36Sopenharmony_ci	if (IS_PF(bp)) {
168062306a36Sopenharmony_ci		bp->msix_table[msix_vec].entry = msix_vec;
168162306a36Sopenharmony_ci		BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n",
168262306a36Sopenharmony_ci			       bp->msix_table[0].entry);
168362306a36Sopenharmony_ci		msix_vec++;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	/* Cnic requires an msix vector for itself */
168762306a36Sopenharmony_ci	if (CNIC_SUPPORT(bp)) {
168862306a36Sopenharmony_ci		bp->msix_table[msix_vec].entry = msix_vec;
168962306a36Sopenharmony_ci		BNX2X_DEV_INFO("msix_table[%d].entry = %d (CNIC)\n",
169062306a36Sopenharmony_ci			       msix_vec, bp->msix_table[msix_vec].entry);
169162306a36Sopenharmony_ci		msix_vec++;
169262306a36Sopenharmony_ci	}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	/* We need separate vectors for ETH queues only (not FCoE) */
169562306a36Sopenharmony_ci	for_each_eth_queue(bp, i) {
169662306a36Sopenharmony_ci		bp->msix_table[msix_vec].entry = msix_vec;
169762306a36Sopenharmony_ci		BNX2X_DEV_INFO("msix_table[%d].entry = %d (fastpath #%u)\n",
169862306a36Sopenharmony_ci			       msix_vec, msix_vec, i);
169962306a36Sopenharmony_ci		msix_vec++;
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n",
170362306a36Sopenharmony_ci	   msix_vec);
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0],
170662306a36Sopenharmony_ci				   BNX2X_MIN_MSIX_VEC_CNT(bp), msix_vec);
170762306a36Sopenharmony_ci	/*
170862306a36Sopenharmony_ci	 * reconfigure number of tx/rx queues according to available
170962306a36Sopenharmony_ci	 * MSI-X vectors
171062306a36Sopenharmony_ci	 */
171162306a36Sopenharmony_ci	if (rc == -ENOSPC) {
171262306a36Sopenharmony_ci		/* Get by with single vector */
171362306a36Sopenharmony_ci		rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0], 1, 1);
171462306a36Sopenharmony_ci		if (rc < 0) {
171562306a36Sopenharmony_ci			BNX2X_DEV_INFO("Single MSI-X is not attainable rc %d\n",
171662306a36Sopenharmony_ci				       rc);
171762306a36Sopenharmony_ci			goto no_msix;
171862306a36Sopenharmony_ci		}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci		BNX2X_DEV_INFO("Using single MSI-X vector\n");
172162306a36Sopenharmony_ci		bp->flags |= USING_SINGLE_MSIX_FLAG;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci		BNX2X_DEV_INFO("set number of queues to 1\n");
172462306a36Sopenharmony_ci		bp->num_ethernet_queues = 1;
172562306a36Sopenharmony_ci		bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
172662306a36Sopenharmony_ci	} else if (rc < 0) {
172762306a36Sopenharmony_ci		BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc);
172862306a36Sopenharmony_ci		goto no_msix;
172962306a36Sopenharmony_ci	} else if (rc < msix_vec) {
173062306a36Sopenharmony_ci		/* how less vectors we will have? */
173162306a36Sopenharmony_ci		int diff = msix_vec - rc;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci		BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci		/*
173662306a36Sopenharmony_ci		 * decrease number of queues by number of unallocated entries
173762306a36Sopenharmony_ci		 */
173862306a36Sopenharmony_ci		bp->num_ethernet_queues -= diff;
173962306a36Sopenharmony_ci		bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci		BNX2X_DEV_INFO("New queue configuration set: %d\n",
174262306a36Sopenharmony_ci			       bp->num_queues);
174362306a36Sopenharmony_ci	}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	bp->flags |= USING_MSIX_FLAG;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	return 0;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cino_msix:
175062306a36Sopenharmony_ci	/* fall to INTx if not enough memory */
175162306a36Sopenharmony_ci	if (rc == -ENOMEM)
175262306a36Sopenharmony_ci		bp->flags |= DISABLE_MSI_FLAG;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	return rc;
175562306a36Sopenharmony_ci}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_cistatic int bnx2x_req_msix_irqs(struct bnx2x *bp)
175862306a36Sopenharmony_ci{
175962306a36Sopenharmony_ci	int i, rc, offset = 0;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	/* no default status block for vf */
176262306a36Sopenharmony_ci	if (IS_PF(bp)) {
176362306a36Sopenharmony_ci		rc = request_irq(bp->msix_table[offset++].vector,
176462306a36Sopenharmony_ci				 bnx2x_msix_sp_int, 0,
176562306a36Sopenharmony_ci				 bp->dev->name, bp->dev);
176662306a36Sopenharmony_ci		if (rc) {
176762306a36Sopenharmony_ci			BNX2X_ERR("request sp irq failed\n");
176862306a36Sopenharmony_ci			return -EBUSY;
176962306a36Sopenharmony_ci		}
177062306a36Sopenharmony_ci	}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	if (CNIC_SUPPORT(bp))
177362306a36Sopenharmony_ci		offset++;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	for_each_eth_queue(bp, i) {
177662306a36Sopenharmony_ci		struct bnx2x_fastpath *fp = &bp->fp[i];
177762306a36Sopenharmony_ci		snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
177862306a36Sopenharmony_ci			 bp->dev->name, i);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci		rc = request_irq(bp->msix_table[offset].vector,
178162306a36Sopenharmony_ci				 bnx2x_msix_fp_int, 0, fp->name, fp);
178262306a36Sopenharmony_ci		if (rc) {
178362306a36Sopenharmony_ci			BNX2X_ERR("request fp #%d irq (%d) failed  rc %d\n", i,
178462306a36Sopenharmony_ci			      bp->msix_table[offset].vector, rc);
178562306a36Sopenharmony_ci			bnx2x_free_msix_irqs(bp, offset);
178662306a36Sopenharmony_ci			return -EBUSY;
178762306a36Sopenharmony_ci		}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci		offset++;
179062306a36Sopenharmony_ci	}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	i = BNX2X_NUM_ETH_QUEUES(bp);
179362306a36Sopenharmony_ci	if (IS_PF(bp)) {
179462306a36Sopenharmony_ci		offset = 1 + CNIC_SUPPORT(bp);
179562306a36Sopenharmony_ci		netdev_info(bp->dev,
179662306a36Sopenharmony_ci			    "using MSI-X  IRQs: sp %d  fp[%d] %d ... fp[%d] %d\n",
179762306a36Sopenharmony_ci			    bp->msix_table[0].vector,
179862306a36Sopenharmony_ci			    0, bp->msix_table[offset].vector,
179962306a36Sopenharmony_ci			    i - 1, bp->msix_table[offset + i - 1].vector);
180062306a36Sopenharmony_ci	} else {
180162306a36Sopenharmony_ci		offset = CNIC_SUPPORT(bp);
180262306a36Sopenharmony_ci		netdev_info(bp->dev,
180362306a36Sopenharmony_ci			    "using MSI-X  IRQs: fp[%d] %d ... fp[%d] %d\n",
180462306a36Sopenharmony_ci			    0, bp->msix_table[offset].vector,
180562306a36Sopenharmony_ci			    i - 1, bp->msix_table[offset + i - 1].vector);
180662306a36Sopenharmony_ci	}
180762306a36Sopenharmony_ci	return 0;
180862306a36Sopenharmony_ci}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ciint bnx2x_enable_msi(struct bnx2x *bp)
181162306a36Sopenharmony_ci{
181262306a36Sopenharmony_ci	int rc;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	rc = pci_enable_msi(bp->pdev);
181562306a36Sopenharmony_ci	if (rc) {
181662306a36Sopenharmony_ci		BNX2X_DEV_INFO("MSI is not attainable\n");
181762306a36Sopenharmony_ci		return -1;
181862306a36Sopenharmony_ci	}
181962306a36Sopenharmony_ci	bp->flags |= USING_MSI_FLAG;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	return 0;
182262306a36Sopenharmony_ci}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_cistatic int bnx2x_req_irq(struct bnx2x *bp)
182562306a36Sopenharmony_ci{
182662306a36Sopenharmony_ci	unsigned long flags;
182762306a36Sopenharmony_ci	unsigned int irq;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	if (bp->flags & (USING_MSI_FLAG | USING_MSIX_FLAG))
183062306a36Sopenharmony_ci		flags = 0;
183162306a36Sopenharmony_ci	else
183262306a36Sopenharmony_ci		flags = IRQF_SHARED;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	if (bp->flags & USING_MSIX_FLAG)
183562306a36Sopenharmony_ci		irq = bp->msix_table[0].vector;
183662306a36Sopenharmony_ci	else
183762306a36Sopenharmony_ci		irq = bp->pdev->irq;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	return request_irq(irq, bnx2x_interrupt, flags, bp->dev->name, bp->dev);
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_cistatic int bnx2x_setup_irqs(struct bnx2x *bp)
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	int rc = 0;
184562306a36Sopenharmony_ci	if (bp->flags & USING_MSIX_FLAG &&
184662306a36Sopenharmony_ci	    !(bp->flags & USING_SINGLE_MSIX_FLAG)) {
184762306a36Sopenharmony_ci		rc = bnx2x_req_msix_irqs(bp);
184862306a36Sopenharmony_ci		if (rc)
184962306a36Sopenharmony_ci			return rc;
185062306a36Sopenharmony_ci	} else {
185162306a36Sopenharmony_ci		rc = bnx2x_req_irq(bp);
185262306a36Sopenharmony_ci		if (rc) {
185362306a36Sopenharmony_ci			BNX2X_ERR("IRQ request failed  rc %d, aborting\n", rc);
185462306a36Sopenharmony_ci			return rc;
185562306a36Sopenharmony_ci		}
185662306a36Sopenharmony_ci		if (bp->flags & USING_MSI_FLAG) {
185762306a36Sopenharmony_ci			bp->dev->irq = bp->pdev->irq;
185862306a36Sopenharmony_ci			netdev_info(bp->dev, "using MSI IRQ %d\n",
185962306a36Sopenharmony_ci				    bp->dev->irq);
186062306a36Sopenharmony_ci		}
186162306a36Sopenharmony_ci		if (bp->flags & USING_MSIX_FLAG) {
186262306a36Sopenharmony_ci			bp->dev->irq = bp->msix_table[0].vector;
186362306a36Sopenharmony_ci			netdev_info(bp->dev, "using MSIX IRQ %d\n",
186462306a36Sopenharmony_ci				    bp->dev->irq);
186562306a36Sopenharmony_ci		}
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	return 0;
186962306a36Sopenharmony_ci}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_cistatic void bnx2x_napi_enable_cnic(struct bnx2x *bp)
187262306a36Sopenharmony_ci{
187362306a36Sopenharmony_ci	int i;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	for_each_rx_queue_cnic(bp, i) {
187662306a36Sopenharmony_ci		napi_enable(&bnx2x_fp(bp, i, napi));
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_cistatic void bnx2x_napi_enable(struct bnx2x *bp)
188162306a36Sopenharmony_ci{
188262306a36Sopenharmony_ci	int i;
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	for_each_eth_queue(bp, i) {
188562306a36Sopenharmony_ci		napi_enable(&bnx2x_fp(bp, i, napi));
188662306a36Sopenharmony_ci	}
188762306a36Sopenharmony_ci}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_cistatic void bnx2x_napi_disable_cnic(struct bnx2x *bp)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci	int i;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	for_each_rx_queue_cnic(bp, i) {
189462306a36Sopenharmony_ci		napi_disable(&bnx2x_fp(bp, i, napi));
189562306a36Sopenharmony_ci	}
189662306a36Sopenharmony_ci}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_cistatic void bnx2x_napi_disable(struct bnx2x *bp)
189962306a36Sopenharmony_ci{
190062306a36Sopenharmony_ci	int i;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	for_each_eth_queue(bp, i) {
190362306a36Sopenharmony_ci		napi_disable(&bnx2x_fp(bp, i, napi));
190462306a36Sopenharmony_ci	}
190562306a36Sopenharmony_ci}
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_civoid bnx2x_netif_start(struct bnx2x *bp)
190862306a36Sopenharmony_ci{
190962306a36Sopenharmony_ci	if (netif_running(bp->dev)) {
191062306a36Sopenharmony_ci		bnx2x_napi_enable(bp);
191162306a36Sopenharmony_ci		if (CNIC_LOADED(bp))
191262306a36Sopenharmony_ci			bnx2x_napi_enable_cnic(bp);
191362306a36Sopenharmony_ci		bnx2x_int_enable(bp);
191462306a36Sopenharmony_ci		if (bp->state == BNX2X_STATE_OPEN)
191562306a36Sopenharmony_ci			netif_tx_wake_all_queues(bp->dev);
191662306a36Sopenharmony_ci	}
191762306a36Sopenharmony_ci}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_civoid bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
192062306a36Sopenharmony_ci{
192162306a36Sopenharmony_ci	bnx2x_int_disable_sync(bp, disable_hw);
192262306a36Sopenharmony_ci	bnx2x_napi_disable(bp);
192362306a36Sopenharmony_ci	if (CNIC_LOADED(bp))
192462306a36Sopenharmony_ci		bnx2x_napi_disable_cnic(bp);
192562306a36Sopenharmony_ci}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ciu16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
192862306a36Sopenharmony_ci		       struct net_device *sb_dev)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (CNIC_LOADED(bp) && !NO_FCOE(bp)) {
193362306a36Sopenharmony_ci		struct ethhdr *hdr = (struct ethhdr *)skb->data;
193462306a36Sopenharmony_ci		u16 ether_type = ntohs(hdr->h_proto);
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		/* Skip VLAN tag if present */
193762306a36Sopenharmony_ci		if (ether_type == ETH_P_8021Q) {
193862306a36Sopenharmony_ci			struct vlan_ethhdr *vhdr = skb_vlan_eth_hdr(skb);
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci			ether_type = ntohs(vhdr->h_vlan_encapsulated_proto);
194162306a36Sopenharmony_ci		}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci		/* If ethertype is FCoE or FIP - use FCoE ring */
194462306a36Sopenharmony_ci		if ((ether_type == ETH_P_FCOE) || (ether_type == ETH_P_FIP))
194562306a36Sopenharmony_ci			return bnx2x_fcoe_tx(bp, txq_index);
194662306a36Sopenharmony_ci	}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	/* select a non-FCoE queue */
194962306a36Sopenharmony_ci	return netdev_pick_tx(dev, skb, NULL) %
195062306a36Sopenharmony_ci			(BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos);
195162306a36Sopenharmony_ci}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_civoid bnx2x_set_num_queues(struct bnx2x *bp)
195462306a36Sopenharmony_ci{
195562306a36Sopenharmony_ci	/* RSS queues */
195662306a36Sopenharmony_ci	bp->num_ethernet_queues = bnx2x_calc_num_queues(bp);
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	/* override in STORAGE SD modes */
195962306a36Sopenharmony_ci	if (IS_MF_STORAGE_ONLY(bp))
196062306a36Sopenharmony_ci		bp->num_ethernet_queues = 1;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	/* Add special queues */
196362306a36Sopenharmony_ci	bp->num_cnic_queues = CNIC_SUPPORT(bp); /* For FCOE */
196462306a36Sopenharmony_ci	bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	BNX2X_DEV_INFO("set number of queues to %d\n", bp->num_queues);
196762306a36Sopenharmony_ci}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci/**
197062306a36Sopenharmony_ci * bnx2x_set_real_num_queues - configure netdev->real_num_[tx,rx]_queues
197162306a36Sopenharmony_ci *
197262306a36Sopenharmony_ci * @bp:		Driver handle
197362306a36Sopenharmony_ci * @include_cnic: handle cnic case
197462306a36Sopenharmony_ci *
197562306a36Sopenharmony_ci * We currently support for at most 16 Tx queues for each CoS thus we will
197662306a36Sopenharmony_ci * allocate a multiple of 16 for ETH L2 rings according to the value of the
197762306a36Sopenharmony_ci * bp->max_cos.
197862306a36Sopenharmony_ci *
197962306a36Sopenharmony_ci * If there is an FCoE L2 queue the appropriate Tx queue will have the next
198062306a36Sopenharmony_ci * index after all ETH L2 indices.
198162306a36Sopenharmony_ci *
198262306a36Sopenharmony_ci * If the actual number of Tx queues (for each CoS) is less than 16 then there
198362306a36Sopenharmony_ci * will be the holes at the end of each group of 16 ETh L2 indices (0..15,
198462306a36Sopenharmony_ci * 16..31,...) with indices that are not coupled with any real Tx queue.
198562306a36Sopenharmony_ci *
198662306a36Sopenharmony_ci * The proper configuration of skb->queue_mapping is handled by
198762306a36Sopenharmony_ci * bnx2x_select_queue() and __skb_tx_hash().
198862306a36Sopenharmony_ci *
198962306a36Sopenharmony_ci * bnx2x_setup_tc() takes care of the proper TC mappings so that __skb_tx_hash()
199062306a36Sopenharmony_ci * will return a proper Tx index if TC is enabled (netdev->num_tc > 0).
199162306a36Sopenharmony_ci */
199262306a36Sopenharmony_cistatic int bnx2x_set_real_num_queues(struct bnx2x *bp, int include_cnic)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	int rc, tx, rx;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	tx = BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos;
199762306a36Sopenharmony_ci	rx = BNX2X_NUM_ETH_QUEUES(bp);
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci/* account for fcoe queue */
200062306a36Sopenharmony_ci	if (include_cnic && !NO_FCOE(bp)) {
200162306a36Sopenharmony_ci		rx++;
200262306a36Sopenharmony_ci		tx++;
200362306a36Sopenharmony_ci	}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	rc = netif_set_real_num_tx_queues(bp->dev, tx);
200662306a36Sopenharmony_ci	if (rc) {
200762306a36Sopenharmony_ci		BNX2X_ERR("Failed to set real number of Tx queues: %d\n", rc);
200862306a36Sopenharmony_ci		return rc;
200962306a36Sopenharmony_ci	}
201062306a36Sopenharmony_ci	rc = netif_set_real_num_rx_queues(bp->dev, rx);
201162306a36Sopenharmony_ci	if (rc) {
201262306a36Sopenharmony_ci		BNX2X_ERR("Failed to set real number of Rx queues: %d\n", rc);
201362306a36Sopenharmony_ci		return rc;
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "Setting real num queues to (tx, rx) (%d, %d)\n",
201762306a36Sopenharmony_ci			  tx, rx);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	return rc;
202062306a36Sopenharmony_ci}
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_cistatic void bnx2x_set_rx_buf_size(struct bnx2x *bp)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	int i;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	for_each_queue(bp, i) {
202762306a36Sopenharmony_ci		struct bnx2x_fastpath *fp = &bp->fp[i];
202862306a36Sopenharmony_ci		u32 mtu;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci		/* Always use a mini-jumbo MTU for the FCoE L2 ring */
203162306a36Sopenharmony_ci		if (IS_FCOE_IDX(i))
203262306a36Sopenharmony_ci			/*
203362306a36Sopenharmony_ci			 * Although there are no IP frames expected to arrive to
203462306a36Sopenharmony_ci			 * this ring we still want to add an
203562306a36Sopenharmony_ci			 * IP_HEADER_ALIGNMENT_PADDING to prevent a buffer
203662306a36Sopenharmony_ci			 * overrun attack.
203762306a36Sopenharmony_ci			 */
203862306a36Sopenharmony_ci			mtu = BNX2X_FCOE_MINI_JUMBO_MTU;
203962306a36Sopenharmony_ci		else
204062306a36Sopenharmony_ci			mtu = bp->dev->mtu;
204162306a36Sopenharmony_ci		fp->rx_buf_size = BNX2X_FW_RX_ALIGN_START +
204262306a36Sopenharmony_ci				  IP_HEADER_ALIGNMENT_PADDING +
204362306a36Sopenharmony_ci				  ETH_OVERHEAD +
204462306a36Sopenharmony_ci				  mtu +
204562306a36Sopenharmony_ci				  BNX2X_FW_RX_ALIGN_END;
204662306a36Sopenharmony_ci		fp->rx_buf_size = SKB_DATA_ALIGN(fp->rx_buf_size);
204762306a36Sopenharmony_ci		/* Note : rx_buf_size doesn't take into account NET_SKB_PAD */
204862306a36Sopenharmony_ci		if (fp->rx_buf_size + NET_SKB_PAD <= PAGE_SIZE)
204962306a36Sopenharmony_ci			fp->rx_frag_size = fp->rx_buf_size + NET_SKB_PAD;
205062306a36Sopenharmony_ci		else
205162306a36Sopenharmony_ci			fp->rx_frag_size = 0;
205262306a36Sopenharmony_ci	}
205362306a36Sopenharmony_ci}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_cistatic int bnx2x_init_rss(struct bnx2x *bp)
205662306a36Sopenharmony_ci{
205762306a36Sopenharmony_ci	int i;
205862306a36Sopenharmony_ci	u8 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp);
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	/* Prepare the initial contents for the indirection table if RSS is
206162306a36Sopenharmony_ci	 * enabled
206262306a36Sopenharmony_ci	 */
206362306a36Sopenharmony_ci	for (i = 0; i < sizeof(bp->rss_conf_obj.ind_table); i++)
206462306a36Sopenharmony_ci		bp->rss_conf_obj.ind_table[i] =
206562306a36Sopenharmony_ci			bp->fp->cl_id +
206662306a36Sopenharmony_ci			ethtool_rxfh_indir_default(i, num_eth_queues);
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	/*
206962306a36Sopenharmony_ci	 * For 57710 and 57711 SEARCHER configuration (rss_keys) is
207062306a36Sopenharmony_ci	 * per-port, so if explicit configuration is needed , do it only
207162306a36Sopenharmony_ci	 * for a PMF.
207262306a36Sopenharmony_ci	 *
207362306a36Sopenharmony_ci	 * For 57712 and newer on the other hand it's a per-function
207462306a36Sopenharmony_ci	 * configuration.
207562306a36Sopenharmony_ci	 */
207662306a36Sopenharmony_ci	return bnx2x_config_rss_eth(bp, bp->port.pmf || !CHIP_IS_E1x(bp));
207762306a36Sopenharmony_ci}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ciint bnx2x_rss(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
208062306a36Sopenharmony_ci	      bool config_hash, bool enable)
208162306a36Sopenharmony_ci{
208262306a36Sopenharmony_ci	struct bnx2x_config_rss_params params = {NULL};
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	/* Although RSS is meaningless when there is a single HW queue we
208562306a36Sopenharmony_ci	 * still need it enabled in order to have HW Rx hash generated.
208662306a36Sopenharmony_ci	 *
208762306a36Sopenharmony_ci	 * if (!is_eth_multi(bp))
208862306a36Sopenharmony_ci	 *      bp->multi_mode = ETH_RSS_MODE_DISABLED;
208962306a36Sopenharmony_ci	 */
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	params.rss_obj = rss_obj;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	__set_bit(RAMROD_COMP_WAIT, &params.ramrod_flags);
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	if (enable) {
209662306a36Sopenharmony_ci		__set_bit(BNX2X_RSS_MODE_REGULAR, &params.rss_flags);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci		/* RSS configuration */
209962306a36Sopenharmony_ci		__set_bit(BNX2X_RSS_IPV4, &params.rss_flags);
210062306a36Sopenharmony_ci		__set_bit(BNX2X_RSS_IPV4_TCP, &params.rss_flags);
210162306a36Sopenharmony_ci		__set_bit(BNX2X_RSS_IPV6, &params.rss_flags);
210262306a36Sopenharmony_ci		__set_bit(BNX2X_RSS_IPV6_TCP, &params.rss_flags);
210362306a36Sopenharmony_ci		if (rss_obj->udp_rss_v4)
210462306a36Sopenharmony_ci			__set_bit(BNX2X_RSS_IPV4_UDP, &params.rss_flags);
210562306a36Sopenharmony_ci		if (rss_obj->udp_rss_v6)
210662306a36Sopenharmony_ci			__set_bit(BNX2X_RSS_IPV6_UDP, &params.rss_flags);
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci		if (!CHIP_IS_E1x(bp)) {
210962306a36Sopenharmony_ci			/* valid only for TUNN_MODE_VXLAN tunnel mode */
211062306a36Sopenharmony_ci			__set_bit(BNX2X_RSS_IPV4_VXLAN, &params.rss_flags);
211162306a36Sopenharmony_ci			__set_bit(BNX2X_RSS_IPV6_VXLAN, &params.rss_flags);
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci			/* valid only for TUNN_MODE_GRE tunnel mode */
211462306a36Sopenharmony_ci			__set_bit(BNX2X_RSS_TUNN_INNER_HDRS, &params.rss_flags);
211562306a36Sopenharmony_ci		}
211662306a36Sopenharmony_ci	} else {
211762306a36Sopenharmony_ci		__set_bit(BNX2X_RSS_MODE_DISABLED, &params.rss_flags);
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	/* Hash bits */
212162306a36Sopenharmony_ci	params.rss_result_mask = MULTI_MASK;
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	memcpy(params.ind_table, rss_obj->ind_table, sizeof(params.ind_table));
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	if (config_hash) {
212662306a36Sopenharmony_ci		/* RSS keys */
212762306a36Sopenharmony_ci		netdev_rss_key_fill(params.rss_key, T_ETH_RSS_KEY * 4);
212862306a36Sopenharmony_ci		__set_bit(BNX2X_RSS_SET_SRCH, &params.rss_flags);
212962306a36Sopenharmony_ci	}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	if (IS_PF(bp))
213262306a36Sopenharmony_ci		return bnx2x_config_rss(bp, &params);
213362306a36Sopenharmony_ci	else
213462306a36Sopenharmony_ci		return bnx2x_vfpf_config_rss(bp, &params);
213562306a36Sopenharmony_ci}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_cistatic int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
213862306a36Sopenharmony_ci{
213962306a36Sopenharmony_ci	struct bnx2x_func_state_params func_params = {NULL};
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	/* Prepare parameters for function state transitions */
214262306a36Sopenharmony_ci	__set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	func_params.f_obj = &bp->func_obj;
214562306a36Sopenharmony_ci	func_params.cmd = BNX2X_F_CMD_HW_INIT;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	func_params.params.hw_init.load_phase = load_code;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	return bnx2x_func_state_change(bp, &func_params);
215062306a36Sopenharmony_ci}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci/*
215362306a36Sopenharmony_ci * Cleans the object that have internal lists without sending
215462306a36Sopenharmony_ci * ramrods. Should be run when interrupts are disabled.
215562306a36Sopenharmony_ci */
215662306a36Sopenharmony_civoid bnx2x_squeeze_objects(struct bnx2x *bp)
215762306a36Sopenharmony_ci{
215862306a36Sopenharmony_ci	int rc;
215962306a36Sopenharmony_ci	unsigned long ramrod_flags = 0, vlan_mac_flags = 0;
216062306a36Sopenharmony_ci	struct bnx2x_mcast_ramrod_params rparam = {NULL};
216162306a36Sopenharmony_ci	struct bnx2x_vlan_mac_obj *mac_obj = &bp->sp_objs->mac_obj;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	/***************** Cleanup MACs' object first *************************/
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	/* Wait for completion of requested */
216662306a36Sopenharmony_ci	__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
216762306a36Sopenharmony_ci	/* Perform a dry cleanup */
216862306a36Sopenharmony_ci	__set_bit(RAMROD_DRV_CLR_ONLY, &ramrod_flags);
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	/* Clean ETH primary MAC */
217162306a36Sopenharmony_ci	__set_bit(BNX2X_ETH_MAC, &vlan_mac_flags);
217262306a36Sopenharmony_ci	rc = mac_obj->delete_all(bp, &bp->sp_objs->mac_obj, &vlan_mac_flags,
217362306a36Sopenharmony_ci				 &ramrod_flags);
217462306a36Sopenharmony_ci	if (rc != 0)
217562306a36Sopenharmony_ci		BNX2X_ERR("Failed to clean ETH MACs: %d\n", rc);
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	/* Cleanup UC list */
217862306a36Sopenharmony_ci	vlan_mac_flags = 0;
217962306a36Sopenharmony_ci	__set_bit(BNX2X_UC_LIST_MAC, &vlan_mac_flags);
218062306a36Sopenharmony_ci	rc = mac_obj->delete_all(bp, mac_obj, &vlan_mac_flags,
218162306a36Sopenharmony_ci				 &ramrod_flags);
218262306a36Sopenharmony_ci	if (rc != 0)
218362306a36Sopenharmony_ci		BNX2X_ERR("Failed to clean UC list MACs: %d\n", rc);
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	/***************** Now clean mcast object *****************************/
218662306a36Sopenharmony_ci	rparam.mcast_obj = &bp->mcast_obj;
218762306a36Sopenharmony_ci	__set_bit(RAMROD_DRV_CLR_ONLY, &rparam.ramrod_flags);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	/* Add a DEL command... - Since we're doing a driver cleanup only,
219062306a36Sopenharmony_ci	 * we take a lock surrounding both the initial send and the CONTs,
219162306a36Sopenharmony_ci	 * as we don't want a true completion to disrupt us in the middle.
219262306a36Sopenharmony_ci	 */
219362306a36Sopenharmony_ci	netif_addr_lock_bh(bp->dev);
219462306a36Sopenharmony_ci	rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL);
219562306a36Sopenharmony_ci	if (rc < 0)
219662306a36Sopenharmony_ci		BNX2X_ERR("Failed to add a new DEL command to a multi-cast object: %d\n",
219762306a36Sopenharmony_ci			  rc);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	/* ...and wait until all pending commands are cleared */
220062306a36Sopenharmony_ci	rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
220162306a36Sopenharmony_ci	while (rc != 0) {
220262306a36Sopenharmony_ci		if (rc < 0) {
220362306a36Sopenharmony_ci			BNX2X_ERR("Failed to clean multi-cast object: %d\n",
220462306a36Sopenharmony_ci				  rc);
220562306a36Sopenharmony_ci			netif_addr_unlock_bh(bp->dev);
220662306a36Sopenharmony_ci			return;
220762306a36Sopenharmony_ci		}
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci		rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
221062306a36Sopenharmony_ci	}
221162306a36Sopenharmony_ci	netif_addr_unlock_bh(bp->dev);
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR
221562306a36Sopenharmony_ci#define LOAD_ERROR_EXIT(bp, label) \
221662306a36Sopenharmony_ci	do { \
221762306a36Sopenharmony_ci		(bp)->state = BNX2X_STATE_ERROR; \
221862306a36Sopenharmony_ci		goto label; \
221962306a36Sopenharmony_ci	} while (0)
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci#define LOAD_ERROR_EXIT_CNIC(bp, label) \
222262306a36Sopenharmony_ci	do { \
222362306a36Sopenharmony_ci		bp->cnic_loaded = false; \
222462306a36Sopenharmony_ci		goto label; \
222562306a36Sopenharmony_ci	} while (0)
222662306a36Sopenharmony_ci#else /*BNX2X_STOP_ON_ERROR*/
222762306a36Sopenharmony_ci#define LOAD_ERROR_EXIT(bp, label) \
222862306a36Sopenharmony_ci	do { \
222962306a36Sopenharmony_ci		(bp)->state = BNX2X_STATE_ERROR; \
223062306a36Sopenharmony_ci		(bp)->panic = 1; \
223162306a36Sopenharmony_ci		return -EBUSY; \
223262306a36Sopenharmony_ci	} while (0)
223362306a36Sopenharmony_ci#define LOAD_ERROR_EXIT_CNIC(bp, label) \
223462306a36Sopenharmony_ci	do { \
223562306a36Sopenharmony_ci		bp->cnic_loaded = false; \
223662306a36Sopenharmony_ci		(bp)->panic = 1; \
223762306a36Sopenharmony_ci		return -EBUSY; \
223862306a36Sopenharmony_ci	} while (0)
223962306a36Sopenharmony_ci#endif /*BNX2X_STOP_ON_ERROR*/
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_cistatic void bnx2x_free_fw_stats_mem(struct bnx2x *bp)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
224462306a36Sopenharmony_ci		       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
224562306a36Sopenharmony_ci	return;
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_cistatic int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
224962306a36Sopenharmony_ci{
225062306a36Sopenharmony_ci	int num_groups, vf_headroom = 0;
225162306a36Sopenharmony_ci	int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	/* number of queues for statistics is number of eth queues + FCoE */
225462306a36Sopenharmony_ci	u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	/* Total number of FW statistics requests =
225762306a36Sopenharmony_ci	 * 1 for port stats + 1 for PF stats + potential 2 for FCoE (fcoe proper
225862306a36Sopenharmony_ci	 * and fcoe l2 queue) stats + num of queues (which includes another 1
225962306a36Sopenharmony_ci	 * for fcoe l2 queue if applicable)
226062306a36Sopenharmony_ci	 */
226162306a36Sopenharmony_ci	bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	/* vf stats appear in the request list, but their data is allocated by
226462306a36Sopenharmony_ci	 * the VFs themselves. We don't include them in the bp->fw_stats_num as
226562306a36Sopenharmony_ci	 * it is used to determine where to place the vf stats queries in the
226662306a36Sopenharmony_ci	 * request struct
226762306a36Sopenharmony_ci	 */
226862306a36Sopenharmony_ci	if (IS_SRIOV(bp))
226962306a36Sopenharmony_ci		vf_headroom = bnx2x_vf_headroom(bp);
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	/* Request is built from stats_query_header and an array of
227262306a36Sopenharmony_ci	 * stats_query_cmd_group each of which contains
227362306a36Sopenharmony_ci	 * STATS_QUERY_CMD_COUNT rules. The real number or requests is
227462306a36Sopenharmony_ci	 * configured in the stats_query_header.
227562306a36Sopenharmony_ci	 */
227662306a36Sopenharmony_ci	num_groups =
227762306a36Sopenharmony_ci		(((bp->fw_stats_num + vf_headroom) / STATS_QUERY_CMD_COUNT) +
227862306a36Sopenharmony_ci		 (((bp->fw_stats_num + vf_headroom) % STATS_QUERY_CMD_COUNT) ?
227962306a36Sopenharmony_ci		 1 : 0));
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "stats fw_stats_num %d, vf headroom %d, num_groups %d\n",
228262306a36Sopenharmony_ci	   bp->fw_stats_num, vf_headroom, num_groups);
228362306a36Sopenharmony_ci	bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
228462306a36Sopenharmony_ci		num_groups * sizeof(struct stats_query_cmd_group);
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	/* Data for statistics requests + stats_counter
228762306a36Sopenharmony_ci	 * stats_counter holds per-STORM counters that are incremented
228862306a36Sopenharmony_ci	 * when STORM has finished with the current request.
228962306a36Sopenharmony_ci	 * memory for FCoE offloaded statistics are counted anyway,
229062306a36Sopenharmony_ci	 * even if they will not be sent.
229162306a36Sopenharmony_ci	 * VF stats are not accounted for here as the data of VF stats is stored
229262306a36Sopenharmony_ci	 * in memory allocated by the VF, not here.
229362306a36Sopenharmony_ci	 */
229462306a36Sopenharmony_ci	bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
229562306a36Sopenharmony_ci		sizeof(struct per_pf_stats) +
229662306a36Sopenharmony_ci		sizeof(struct fcoe_statistics_params) +
229762306a36Sopenharmony_ci		sizeof(struct per_queue_stats) * num_queue_stats +
229862306a36Sopenharmony_ci		sizeof(struct stats_counter);
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	bp->fw_stats = BNX2X_PCI_ALLOC(&bp->fw_stats_mapping,
230162306a36Sopenharmony_ci				       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
230262306a36Sopenharmony_ci	if (!bp->fw_stats)
230362306a36Sopenharmony_ci		goto alloc_mem_err;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	/* Set shortcuts */
230662306a36Sopenharmony_ci	bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
230762306a36Sopenharmony_ci	bp->fw_stats_req_mapping = bp->fw_stats_mapping;
230862306a36Sopenharmony_ci	bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
230962306a36Sopenharmony_ci		((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
231062306a36Sopenharmony_ci	bp->fw_stats_data_mapping = bp->fw_stats_mapping +
231162306a36Sopenharmony_ci		bp->fw_stats_req_sz;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "statistics request base address set to %x %x\n",
231462306a36Sopenharmony_ci	   U64_HI(bp->fw_stats_req_mapping),
231562306a36Sopenharmony_ci	   U64_LO(bp->fw_stats_req_mapping));
231662306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "statistics data base address set to %x %x\n",
231762306a36Sopenharmony_ci	   U64_HI(bp->fw_stats_data_mapping),
231862306a36Sopenharmony_ci	   U64_LO(bp->fw_stats_data_mapping));
231962306a36Sopenharmony_ci	return 0;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_cialloc_mem_err:
232262306a36Sopenharmony_ci	bnx2x_free_fw_stats_mem(bp);
232362306a36Sopenharmony_ci	BNX2X_ERR("Can't allocate FW stats memory\n");
232462306a36Sopenharmony_ci	return -ENOMEM;
232562306a36Sopenharmony_ci}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci/* send load request to mcp and analyze response */
232862306a36Sopenharmony_cistatic int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
232962306a36Sopenharmony_ci{
233062306a36Sopenharmony_ci	u32 param;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	/* init fw_seq */
233362306a36Sopenharmony_ci	bp->fw_seq =
233462306a36Sopenharmony_ci		(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
233562306a36Sopenharmony_ci		 DRV_MSG_SEQ_NUMBER_MASK);
233662306a36Sopenharmony_ci	BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	/* Get current FW pulse sequence */
233962306a36Sopenharmony_ci	bp->fw_drv_pulse_wr_seq =
234062306a36Sopenharmony_ci		(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
234162306a36Sopenharmony_ci		 DRV_PULSE_SEQ_MASK);
234262306a36Sopenharmony_ci	BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	param = DRV_MSG_CODE_LOAD_REQ_WITH_LFA;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	if (IS_MF_SD(bp) && bnx2x_port_after_undi(bp))
234762306a36Sopenharmony_ci		param |= DRV_MSG_CODE_LOAD_REQ_FORCE_LFA;
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	/* load request */
235062306a36Sopenharmony_ci	(*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ, param);
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	/* if mcp fails to respond we must abort */
235362306a36Sopenharmony_ci	if (!(*load_code)) {
235462306a36Sopenharmony_ci		BNX2X_ERR("MCP response failure, aborting\n");
235562306a36Sopenharmony_ci		return -EBUSY;
235662306a36Sopenharmony_ci	}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	/* If mcp refused (e.g. other port is in diagnostic mode) we
235962306a36Sopenharmony_ci	 * must abort
236062306a36Sopenharmony_ci	 */
236162306a36Sopenharmony_ci	if ((*load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED) {
236262306a36Sopenharmony_ci		BNX2X_ERR("MCP refused load request, aborting\n");
236362306a36Sopenharmony_ci		return -EBUSY;
236462306a36Sopenharmony_ci	}
236562306a36Sopenharmony_ci	return 0;
236662306a36Sopenharmony_ci}
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci/* check whether another PF has already loaded FW to chip. In
236962306a36Sopenharmony_ci * virtualized environments a pf from another VM may have already
237062306a36Sopenharmony_ci * initialized the device including loading FW
237162306a36Sopenharmony_ci */
237262306a36Sopenharmony_ciint bnx2x_compare_fw_ver(struct bnx2x *bp, u32 load_code, bool print_err)
237362306a36Sopenharmony_ci{
237462306a36Sopenharmony_ci	/* is another pf loaded on this engine? */
237562306a36Sopenharmony_ci	if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
237662306a36Sopenharmony_ci	    load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
237762306a36Sopenharmony_ci		u8 loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng;
237862306a36Sopenharmony_ci		u32 loaded_fw;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci		/* read loaded FW from chip */
238162306a36Sopenharmony_ci		loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci		loaded_fw_major = loaded_fw & 0xff;
238462306a36Sopenharmony_ci		loaded_fw_minor = (loaded_fw >> 8) & 0xff;
238562306a36Sopenharmony_ci		loaded_fw_rev = (loaded_fw >> 16) & 0xff;
238662306a36Sopenharmony_ci		loaded_fw_eng = (loaded_fw >> 24) & 0xff;
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "loaded fw 0x%x major 0x%x minor 0x%x rev 0x%x eng 0x%x\n",
238962306a36Sopenharmony_ci		   loaded_fw, loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng);
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci		/* abort nic load if version mismatch */
239262306a36Sopenharmony_ci		if (loaded_fw_major != BCM_5710_FW_MAJOR_VERSION ||
239362306a36Sopenharmony_ci		    loaded_fw_minor != BCM_5710_FW_MINOR_VERSION ||
239462306a36Sopenharmony_ci		    loaded_fw_eng != BCM_5710_FW_ENGINEERING_VERSION ||
239562306a36Sopenharmony_ci		    loaded_fw_rev < BCM_5710_FW_REVISION_VERSION_V15) {
239662306a36Sopenharmony_ci			if (print_err)
239762306a36Sopenharmony_ci				BNX2X_ERR("loaded FW incompatible. Aborting\n");
239862306a36Sopenharmony_ci			else
239962306a36Sopenharmony_ci				BNX2X_DEV_INFO("loaded FW incompatible, possibly due to MF UNDI\n");
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci			return -EBUSY;
240262306a36Sopenharmony_ci		}
240362306a36Sopenharmony_ci	}
240462306a36Sopenharmony_ci	return 0;
240562306a36Sopenharmony_ci}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci/* returns the "mcp load_code" according to global load_count array */
240862306a36Sopenharmony_cistatic int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port)
240962306a36Sopenharmony_ci{
241062306a36Sopenharmony_ci	int path = BP_PATH(bp);
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d]      %d, %d, %d\n",
241362306a36Sopenharmony_ci	   path, bnx2x_load_count[path][0], bnx2x_load_count[path][1],
241462306a36Sopenharmony_ci	   bnx2x_load_count[path][2]);
241562306a36Sopenharmony_ci	bnx2x_load_count[path][0]++;
241662306a36Sopenharmony_ci	bnx2x_load_count[path][1 + port]++;
241762306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d]  %d, %d, %d\n",
241862306a36Sopenharmony_ci	   path, bnx2x_load_count[path][0], bnx2x_load_count[path][1],
241962306a36Sopenharmony_ci	   bnx2x_load_count[path][2]);
242062306a36Sopenharmony_ci	if (bnx2x_load_count[path][0] == 1)
242162306a36Sopenharmony_ci		return FW_MSG_CODE_DRV_LOAD_COMMON;
242262306a36Sopenharmony_ci	else if (bnx2x_load_count[path][1 + port] == 1)
242362306a36Sopenharmony_ci		return FW_MSG_CODE_DRV_LOAD_PORT;
242462306a36Sopenharmony_ci	else
242562306a36Sopenharmony_ci		return FW_MSG_CODE_DRV_LOAD_FUNCTION;
242662306a36Sopenharmony_ci}
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci/* mark PMF if applicable */
242962306a36Sopenharmony_cistatic void bnx2x_nic_load_pmf(struct bnx2x *bp, u32 load_code)
243062306a36Sopenharmony_ci{
243162306a36Sopenharmony_ci	if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
243262306a36Sopenharmony_ci	    (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
243362306a36Sopenharmony_ci	    (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
243462306a36Sopenharmony_ci		bp->port.pmf = 1;
243562306a36Sopenharmony_ci		/* We need the barrier to ensure the ordering between the
243662306a36Sopenharmony_ci		 * writing to bp->port.pmf here and reading it from the
243762306a36Sopenharmony_ci		 * bnx2x_periodic_task().
243862306a36Sopenharmony_ci		 */
243962306a36Sopenharmony_ci		smp_mb();
244062306a36Sopenharmony_ci	} else {
244162306a36Sopenharmony_ci		bp->port.pmf = 0;
244262306a36Sopenharmony_ci	}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
244562306a36Sopenharmony_ci}
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_cistatic void bnx2x_nic_load_afex_dcc(struct bnx2x *bp, int load_code)
244862306a36Sopenharmony_ci{
244962306a36Sopenharmony_ci	if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
245062306a36Sopenharmony_ci	     (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
245162306a36Sopenharmony_ci	    (bp->common.shmem2_base)) {
245262306a36Sopenharmony_ci		if (SHMEM2_HAS(bp, dcc_support))
245362306a36Sopenharmony_ci			SHMEM2_WR(bp, dcc_support,
245462306a36Sopenharmony_ci				  (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
245562306a36Sopenharmony_ci				   SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
245662306a36Sopenharmony_ci		if (SHMEM2_HAS(bp, afex_driver_support))
245762306a36Sopenharmony_ci			SHMEM2_WR(bp, afex_driver_support,
245862306a36Sopenharmony_ci				  SHMEM_AFEX_SUPPORTED_VERSION_ONE);
245962306a36Sopenharmony_ci	}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	/* Set AFEX default VLAN tag to an invalid value */
246262306a36Sopenharmony_ci	bp->afex_def_vlan_tag = -1;
246362306a36Sopenharmony_ci}
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci/**
246662306a36Sopenharmony_ci * bnx2x_bz_fp - zero content of the fastpath structure.
246762306a36Sopenharmony_ci *
246862306a36Sopenharmony_ci * @bp:		driver handle
246962306a36Sopenharmony_ci * @index:	fastpath index to be zeroed
247062306a36Sopenharmony_ci *
247162306a36Sopenharmony_ci * Makes sure the contents of the bp->fp[index].napi is kept
247262306a36Sopenharmony_ci * intact.
247362306a36Sopenharmony_ci */
247462306a36Sopenharmony_cistatic void bnx2x_bz_fp(struct bnx2x *bp, int index)
247562306a36Sopenharmony_ci{
247662306a36Sopenharmony_ci	struct bnx2x_fastpath *fp = &bp->fp[index];
247762306a36Sopenharmony_ci	int cos;
247862306a36Sopenharmony_ci	struct napi_struct orig_napi = fp->napi;
247962306a36Sopenharmony_ci	struct bnx2x_agg_info *orig_tpa_info = fp->tpa_info;
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci	/* bzero bnx2x_fastpath contents */
248262306a36Sopenharmony_ci	if (fp->tpa_info)
248362306a36Sopenharmony_ci		memset(fp->tpa_info, 0, ETH_MAX_AGGREGATION_QUEUES_E1H_E2 *
248462306a36Sopenharmony_ci		       sizeof(struct bnx2x_agg_info));
248562306a36Sopenharmony_ci	memset(fp, 0, sizeof(*fp));
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	/* Restore the NAPI object as it has been already initialized */
248862306a36Sopenharmony_ci	fp->napi = orig_napi;
248962306a36Sopenharmony_ci	fp->tpa_info = orig_tpa_info;
249062306a36Sopenharmony_ci	fp->bp = bp;
249162306a36Sopenharmony_ci	fp->index = index;
249262306a36Sopenharmony_ci	if (IS_ETH_FP(fp))
249362306a36Sopenharmony_ci		fp->max_cos = bp->max_cos;
249462306a36Sopenharmony_ci	else
249562306a36Sopenharmony_ci		/* Special queues support only one CoS */
249662306a36Sopenharmony_ci		fp->max_cos = 1;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	/* Init txdata pointers */
249962306a36Sopenharmony_ci	if (IS_FCOE_FP(fp))
250062306a36Sopenharmony_ci		fp->txdata_ptr[0] = &bp->bnx2x_txq[FCOE_TXQ_IDX(bp)];
250162306a36Sopenharmony_ci	if (IS_ETH_FP(fp))
250262306a36Sopenharmony_ci		for_each_cos_in_tx_queue(fp, cos)
250362306a36Sopenharmony_ci			fp->txdata_ptr[cos] = &bp->bnx2x_txq[cos *
250462306a36Sopenharmony_ci				BNX2X_NUM_ETH_QUEUES(bp) + index];
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	/* set the tpa flag for each queue. The tpa flag determines the queue
250762306a36Sopenharmony_ci	 * minimal size so it must be set prior to queue memory allocation
250862306a36Sopenharmony_ci	 */
250962306a36Sopenharmony_ci	if (bp->dev->features & NETIF_F_LRO)
251062306a36Sopenharmony_ci		fp->mode = TPA_MODE_LRO;
251162306a36Sopenharmony_ci	else if (bp->dev->features & NETIF_F_GRO_HW)
251262306a36Sopenharmony_ci		fp->mode = TPA_MODE_GRO;
251362306a36Sopenharmony_ci	else
251462306a36Sopenharmony_ci		fp->mode = TPA_MODE_DISABLED;
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	/* We don't want TPA if it's disabled in bp
251762306a36Sopenharmony_ci	 * or if this is an FCoE L2 ring.
251862306a36Sopenharmony_ci	 */
251962306a36Sopenharmony_ci	if (bp->disable_tpa || IS_FCOE_FP(fp))
252062306a36Sopenharmony_ci		fp->mode = TPA_MODE_DISABLED;
252162306a36Sopenharmony_ci}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_civoid bnx2x_set_os_driver_state(struct bnx2x *bp, u32 state)
252462306a36Sopenharmony_ci{
252562306a36Sopenharmony_ci	u32 cur;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (!IS_MF_BD(bp) || !SHMEM2_HAS(bp, os_driver_state) || IS_VF(bp))
252862306a36Sopenharmony_ci		return;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	cur = SHMEM2_RD(bp, os_driver_state[BP_FW_MB_IDX(bp)]);
253162306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "Driver state %08x-->%08x\n",
253262306a36Sopenharmony_ci	   cur, state);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	SHMEM2_WR(bp, os_driver_state[BP_FW_MB_IDX(bp)], state);
253562306a36Sopenharmony_ci}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ciint bnx2x_load_cnic(struct bnx2x *bp)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	int i, rc, port = BP_PORT(bp);
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "Starting CNIC-related load\n");
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	mutex_init(&bp->cnic_mutex);
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	if (IS_PF(bp)) {
254662306a36Sopenharmony_ci		rc = bnx2x_alloc_mem_cnic(bp);
254762306a36Sopenharmony_ci		if (rc) {
254862306a36Sopenharmony_ci			BNX2X_ERR("Unable to allocate bp memory for cnic\n");
254962306a36Sopenharmony_ci			LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
255062306a36Sopenharmony_ci		}
255162306a36Sopenharmony_ci	}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	rc = bnx2x_alloc_fp_mem_cnic(bp);
255462306a36Sopenharmony_ci	if (rc) {
255562306a36Sopenharmony_ci		BNX2X_ERR("Unable to allocate memory for cnic fps\n");
255662306a36Sopenharmony_ci		LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
255762306a36Sopenharmony_ci	}
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	/* Update the number of queues with the cnic queues */
256062306a36Sopenharmony_ci	rc = bnx2x_set_real_num_queues(bp, 1);
256162306a36Sopenharmony_ci	if (rc) {
256262306a36Sopenharmony_ci		BNX2X_ERR("Unable to set real_num_queues including cnic\n");
256362306a36Sopenharmony_ci		LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
256462306a36Sopenharmony_ci	}
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	/* Add all CNIC NAPI objects */
256762306a36Sopenharmony_ci	bnx2x_add_all_napi_cnic(bp);
256862306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "cnic napi added\n");
256962306a36Sopenharmony_ci	bnx2x_napi_enable_cnic(bp);
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	rc = bnx2x_init_hw_func_cnic(bp);
257262306a36Sopenharmony_ci	if (rc)
257362306a36Sopenharmony_ci		LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic1);
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	bnx2x_nic_init_cnic(bp);
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	if (IS_PF(bp)) {
257862306a36Sopenharmony_ci		/* Enable Timer scan */
257962306a36Sopenharmony_ci		REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci		/* setup cnic queues */
258262306a36Sopenharmony_ci		for_each_cnic_queue(bp, i) {
258362306a36Sopenharmony_ci			rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
258462306a36Sopenharmony_ci			if (rc) {
258562306a36Sopenharmony_ci				BNX2X_ERR("Queue setup failed\n");
258662306a36Sopenharmony_ci				LOAD_ERROR_EXIT(bp, load_error_cnic2);
258762306a36Sopenharmony_ci			}
258862306a36Sopenharmony_ci		}
258962306a36Sopenharmony_ci	}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	/* Initialize Rx filter. */
259262306a36Sopenharmony_ci	bnx2x_set_rx_mode_inner(bp);
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	/* re-read iscsi info */
259562306a36Sopenharmony_ci	bnx2x_get_iscsi_info(bp);
259662306a36Sopenharmony_ci	bnx2x_setup_cnic_irq_info(bp);
259762306a36Sopenharmony_ci	bnx2x_setup_cnic_info(bp);
259862306a36Sopenharmony_ci	bp->cnic_loaded = true;
259962306a36Sopenharmony_ci	if (bp->state == BNX2X_STATE_OPEN)
260062306a36Sopenharmony_ci		bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "Ending successfully CNIC-related load\n");
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	return 0;
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR
260762306a36Sopenharmony_ciload_error_cnic2:
260862306a36Sopenharmony_ci	/* Disable Timer scan */
260962306a36Sopenharmony_ci	REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0);
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ciload_error_cnic1:
261262306a36Sopenharmony_ci	bnx2x_napi_disable_cnic(bp);
261362306a36Sopenharmony_ci	/* Update the number of queues without the cnic queues */
261462306a36Sopenharmony_ci	if (bnx2x_set_real_num_queues(bp, 0))
261562306a36Sopenharmony_ci		BNX2X_ERR("Unable to set real_num_queues not including cnic\n");
261662306a36Sopenharmony_ciload_error_cnic0:
261762306a36Sopenharmony_ci	BNX2X_ERR("CNIC-related load failed\n");
261862306a36Sopenharmony_ci	bnx2x_free_fp_mem_cnic(bp);
261962306a36Sopenharmony_ci	bnx2x_free_mem_cnic(bp);
262062306a36Sopenharmony_ci	return rc;
262162306a36Sopenharmony_ci#endif /* ! BNX2X_STOP_ON_ERROR */
262262306a36Sopenharmony_ci}
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci/* must be called with rtnl_lock */
262562306a36Sopenharmony_ciint bnx2x_nic_load(struct bnx2x *bp, int load_mode)
262662306a36Sopenharmony_ci{
262762306a36Sopenharmony_ci	int port = BP_PORT(bp);
262862306a36Sopenharmony_ci	int i, rc = 0, load_code = 0;
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "Starting NIC load\n");
263162306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP,
263262306a36Sopenharmony_ci	   "CNIC is %s\n", CNIC_ENABLED(bp) ? "enabled" : "disabled");
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
263562306a36Sopenharmony_ci	if (unlikely(bp->panic)) {
263662306a36Sopenharmony_ci		BNX2X_ERR("Can't load NIC when there is panic\n");
263762306a36Sopenharmony_ci		return -EPERM;
263862306a36Sopenharmony_ci	}
263962306a36Sopenharmony_ci#endif
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	/* zero the structure w/o any lock, before SP handler is initialized */
264462306a36Sopenharmony_ci	memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link));
264562306a36Sopenharmony_ci	__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
264662306a36Sopenharmony_ci		&bp->last_reported_link.link_report_flags);
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	if (IS_PF(bp))
264962306a36Sopenharmony_ci		/* must be called before memory allocation and HW init */
265062306a36Sopenharmony_ci		bnx2x_ilt_set_info(bp);
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	/*
265362306a36Sopenharmony_ci	 * Zero fastpath structures preserving invariants like napi, which are
265462306a36Sopenharmony_ci	 * allocated only once, fp index, max_cos, bp pointer.
265562306a36Sopenharmony_ci	 * Also set fp->mode and txdata_ptr.
265662306a36Sopenharmony_ci	 */
265762306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "num queues: %d", bp->num_queues);
265862306a36Sopenharmony_ci	for_each_queue(bp, i)
265962306a36Sopenharmony_ci		bnx2x_bz_fp(bp, i);
266062306a36Sopenharmony_ci	memset(bp->bnx2x_txq, 0, (BNX2X_MAX_RSS_COUNT(bp) * BNX2X_MULTI_TX_COS +
266162306a36Sopenharmony_ci				  bp->num_cnic_queues) *
266262306a36Sopenharmony_ci				  sizeof(struct bnx2x_fp_txdata));
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	bp->fcoe_init = false;
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci	/* Set the receive queues buffer size */
266762306a36Sopenharmony_ci	bnx2x_set_rx_buf_size(bp);
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	if (IS_PF(bp)) {
267062306a36Sopenharmony_ci		rc = bnx2x_alloc_mem(bp);
267162306a36Sopenharmony_ci		if (rc) {
267262306a36Sopenharmony_ci			BNX2X_ERR("Unable to allocate bp memory\n");
267362306a36Sopenharmony_ci			return rc;
267462306a36Sopenharmony_ci		}
267562306a36Sopenharmony_ci	}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	/* need to be done after alloc mem, since it's self adjusting to amount
267862306a36Sopenharmony_ci	 * of memory available for RSS queues
267962306a36Sopenharmony_ci	 */
268062306a36Sopenharmony_ci	rc = bnx2x_alloc_fp_mem(bp);
268162306a36Sopenharmony_ci	if (rc) {
268262306a36Sopenharmony_ci		BNX2X_ERR("Unable to allocate memory for fps\n");
268362306a36Sopenharmony_ci		LOAD_ERROR_EXIT(bp, load_error0);
268462306a36Sopenharmony_ci	}
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	/* Allocated memory for FW statistics  */
268762306a36Sopenharmony_ci	rc = bnx2x_alloc_fw_stats_mem(bp);
268862306a36Sopenharmony_ci	if (rc)
268962306a36Sopenharmony_ci		LOAD_ERROR_EXIT(bp, load_error0);
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	/* request pf to initialize status blocks */
269262306a36Sopenharmony_ci	if (IS_VF(bp)) {
269362306a36Sopenharmony_ci		rc = bnx2x_vfpf_init(bp);
269462306a36Sopenharmony_ci		if (rc)
269562306a36Sopenharmony_ci			LOAD_ERROR_EXIT(bp, load_error0);
269662306a36Sopenharmony_ci	}
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	/* As long as bnx2x_alloc_mem() may possibly update
269962306a36Sopenharmony_ci	 * bp->num_queues, bnx2x_set_real_num_queues() should always
270062306a36Sopenharmony_ci	 * come after it. At this stage cnic queues are not counted.
270162306a36Sopenharmony_ci	 */
270262306a36Sopenharmony_ci	rc = bnx2x_set_real_num_queues(bp, 0);
270362306a36Sopenharmony_ci	if (rc) {
270462306a36Sopenharmony_ci		BNX2X_ERR("Unable to set real_num_queues\n");
270562306a36Sopenharmony_ci		LOAD_ERROR_EXIT(bp, load_error0);
270662306a36Sopenharmony_ci	}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	/* configure multi cos mappings in kernel.
270962306a36Sopenharmony_ci	 * this configuration may be overridden by a multi class queue
271062306a36Sopenharmony_ci	 * discipline or by a dcbx negotiation result.
271162306a36Sopenharmony_ci	 */
271262306a36Sopenharmony_ci	bnx2x_setup_tc(bp->dev, bp->max_cos);
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	/* Add all NAPI objects */
271562306a36Sopenharmony_ci	bnx2x_add_all_napi(bp);
271662306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "napi added\n");
271762306a36Sopenharmony_ci	bnx2x_napi_enable(bp);
271862306a36Sopenharmony_ci	bp->nic_stopped = false;
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	if (IS_PF(bp)) {
272162306a36Sopenharmony_ci		/* set pf load just before approaching the MCP */
272262306a36Sopenharmony_ci		bnx2x_set_pf_load(bp);
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci		/* if mcp exists send load request and analyze response */
272562306a36Sopenharmony_ci		if (!BP_NOMCP(bp)) {
272662306a36Sopenharmony_ci			/* attempt to load pf */
272762306a36Sopenharmony_ci			rc = bnx2x_nic_load_request(bp, &load_code);
272862306a36Sopenharmony_ci			if (rc)
272962306a36Sopenharmony_ci				LOAD_ERROR_EXIT(bp, load_error1);
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci			/* what did mcp say? */
273262306a36Sopenharmony_ci			rc = bnx2x_compare_fw_ver(bp, load_code, true);
273362306a36Sopenharmony_ci			if (rc) {
273462306a36Sopenharmony_ci				bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
273562306a36Sopenharmony_ci				LOAD_ERROR_EXIT(bp, load_error2);
273662306a36Sopenharmony_ci			}
273762306a36Sopenharmony_ci		} else {
273862306a36Sopenharmony_ci			load_code = bnx2x_nic_load_no_mcp(bp, port);
273962306a36Sopenharmony_ci		}
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci		/* mark pmf if applicable */
274262306a36Sopenharmony_ci		bnx2x_nic_load_pmf(bp, load_code);
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci		/* Init Function state controlling object */
274562306a36Sopenharmony_ci		bnx2x__init_func_obj(bp);
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci		/* Initialize HW */
274862306a36Sopenharmony_ci		rc = bnx2x_init_hw(bp, load_code);
274962306a36Sopenharmony_ci		if (rc) {
275062306a36Sopenharmony_ci			BNX2X_ERR("HW init failed, aborting\n");
275162306a36Sopenharmony_ci			bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
275262306a36Sopenharmony_ci			LOAD_ERROR_EXIT(bp, load_error2);
275362306a36Sopenharmony_ci		}
275462306a36Sopenharmony_ci	}
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	bnx2x_pre_irq_nic_init(bp);
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	/* Connect to IRQs */
275962306a36Sopenharmony_ci	rc = bnx2x_setup_irqs(bp);
276062306a36Sopenharmony_ci	if (rc) {
276162306a36Sopenharmony_ci		BNX2X_ERR("setup irqs failed\n");
276262306a36Sopenharmony_ci		if (IS_PF(bp))
276362306a36Sopenharmony_ci			bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
276462306a36Sopenharmony_ci		LOAD_ERROR_EXIT(bp, load_error2);
276562306a36Sopenharmony_ci	}
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	/* Init per-function objects */
276862306a36Sopenharmony_ci	if (IS_PF(bp)) {
276962306a36Sopenharmony_ci		/* Setup NIC internals and enable interrupts */
277062306a36Sopenharmony_ci		bnx2x_post_irq_nic_init(bp, load_code);
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci		bnx2x_init_bp_objs(bp);
277362306a36Sopenharmony_ci		bnx2x_iov_nic_init(bp);
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci		/* Set AFEX default VLAN tag to an invalid value */
277662306a36Sopenharmony_ci		bp->afex_def_vlan_tag = -1;
277762306a36Sopenharmony_ci		bnx2x_nic_load_afex_dcc(bp, load_code);
277862306a36Sopenharmony_ci		bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
277962306a36Sopenharmony_ci		rc = bnx2x_func_start(bp);
278062306a36Sopenharmony_ci		if (rc) {
278162306a36Sopenharmony_ci			BNX2X_ERR("Function start failed!\n");
278262306a36Sopenharmony_ci			bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci			LOAD_ERROR_EXIT(bp, load_error3);
278562306a36Sopenharmony_ci		}
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci		/* Send LOAD_DONE command to MCP */
278862306a36Sopenharmony_ci		if (!BP_NOMCP(bp)) {
278962306a36Sopenharmony_ci			load_code = bnx2x_fw_command(bp,
279062306a36Sopenharmony_ci						     DRV_MSG_CODE_LOAD_DONE, 0);
279162306a36Sopenharmony_ci			if (!load_code) {
279262306a36Sopenharmony_ci				BNX2X_ERR("MCP response failure, aborting\n");
279362306a36Sopenharmony_ci				rc = -EBUSY;
279462306a36Sopenharmony_ci				LOAD_ERROR_EXIT(bp, load_error3);
279562306a36Sopenharmony_ci			}
279662306a36Sopenharmony_ci		}
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci		/* initialize FW coalescing state machines in RAM */
279962306a36Sopenharmony_ci		bnx2x_update_coalesce(bp);
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	/* setup the leading queue */
280362306a36Sopenharmony_ci	rc = bnx2x_setup_leading(bp);
280462306a36Sopenharmony_ci	if (rc) {
280562306a36Sopenharmony_ci		BNX2X_ERR("Setup leading failed!\n");
280662306a36Sopenharmony_ci		LOAD_ERROR_EXIT(bp, load_error3);
280762306a36Sopenharmony_ci	}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	/* set up the rest of the queues */
281062306a36Sopenharmony_ci	for_each_nondefault_eth_queue(bp, i) {
281162306a36Sopenharmony_ci		if (IS_PF(bp))
281262306a36Sopenharmony_ci			rc = bnx2x_setup_queue(bp, &bp->fp[i], false);
281362306a36Sopenharmony_ci		else /* VF */
281462306a36Sopenharmony_ci			rc = bnx2x_vfpf_setup_q(bp, &bp->fp[i], false);
281562306a36Sopenharmony_ci		if (rc) {
281662306a36Sopenharmony_ci			BNX2X_ERR("Queue %d setup failed\n", i);
281762306a36Sopenharmony_ci			LOAD_ERROR_EXIT(bp, load_error3);
281862306a36Sopenharmony_ci		}
281962306a36Sopenharmony_ci	}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	/* setup rss */
282262306a36Sopenharmony_ci	rc = bnx2x_init_rss(bp);
282362306a36Sopenharmony_ci	if (rc) {
282462306a36Sopenharmony_ci		BNX2X_ERR("PF RSS init failed\n");
282562306a36Sopenharmony_ci		LOAD_ERROR_EXIT(bp, load_error3);
282662306a36Sopenharmony_ci	}
282762306a36Sopenharmony_ci
282862306a36Sopenharmony_ci	/* Now when Clients are configured we are ready to work */
282962306a36Sopenharmony_ci	bp->state = BNX2X_STATE_OPEN;
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	/* Configure a ucast MAC */
283262306a36Sopenharmony_ci	if (IS_PF(bp))
283362306a36Sopenharmony_ci		rc = bnx2x_set_eth_mac(bp, true);
283462306a36Sopenharmony_ci	else /* vf */
283562306a36Sopenharmony_ci		rc = bnx2x_vfpf_config_mac(bp, bp->dev->dev_addr, bp->fp->index,
283662306a36Sopenharmony_ci					   true);
283762306a36Sopenharmony_ci	if (rc) {
283862306a36Sopenharmony_ci		BNX2X_ERR("Setting Ethernet MAC failed\n");
283962306a36Sopenharmony_ci		LOAD_ERROR_EXIT(bp, load_error3);
284062306a36Sopenharmony_ci	}
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	if (IS_PF(bp) && bp->pending_max) {
284362306a36Sopenharmony_ci		bnx2x_update_max_mf_config(bp, bp->pending_max);
284462306a36Sopenharmony_ci		bp->pending_max = 0;
284562306a36Sopenharmony_ci	}
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	bp->force_link_down = false;
284862306a36Sopenharmony_ci	if (bp->port.pmf) {
284962306a36Sopenharmony_ci		rc = bnx2x_initial_phy_init(bp, load_mode);
285062306a36Sopenharmony_ci		if (rc)
285162306a36Sopenharmony_ci			LOAD_ERROR_EXIT(bp, load_error3);
285262306a36Sopenharmony_ci	}
285362306a36Sopenharmony_ci	bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_BOOT_FROM_SAN;
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	/* Start fast path */
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	/* Re-configure vlan filters */
285862306a36Sopenharmony_ci	rc = bnx2x_vlan_reconfigure_vid(bp);
285962306a36Sopenharmony_ci	if (rc)
286062306a36Sopenharmony_ci		LOAD_ERROR_EXIT(bp, load_error3);
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	/* Initialize Rx filter. */
286362306a36Sopenharmony_ci	bnx2x_set_rx_mode_inner(bp);
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	if (bp->flags & PTP_SUPPORTED) {
286662306a36Sopenharmony_ci		bnx2x_register_phc(bp);
286762306a36Sopenharmony_ci		bnx2x_init_ptp(bp);
286862306a36Sopenharmony_ci		bnx2x_configure_ptp_filters(bp);
286962306a36Sopenharmony_ci	}
287062306a36Sopenharmony_ci	/* Start Tx */
287162306a36Sopenharmony_ci	switch (load_mode) {
287262306a36Sopenharmony_ci	case LOAD_NORMAL:
287362306a36Sopenharmony_ci		/* Tx queue should be only re-enabled */
287462306a36Sopenharmony_ci		netif_tx_wake_all_queues(bp->dev);
287562306a36Sopenharmony_ci		break;
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci	case LOAD_OPEN:
287862306a36Sopenharmony_ci		netif_tx_start_all_queues(bp->dev);
287962306a36Sopenharmony_ci		smp_mb__after_atomic();
288062306a36Sopenharmony_ci		break;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	case LOAD_DIAG:
288362306a36Sopenharmony_ci	case LOAD_LOOPBACK_EXT:
288462306a36Sopenharmony_ci		bp->state = BNX2X_STATE_DIAG;
288562306a36Sopenharmony_ci		break;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	default:
288862306a36Sopenharmony_ci		break;
288962306a36Sopenharmony_ci	}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci	if (bp->port.pmf)
289262306a36Sopenharmony_ci		bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_PORT_MASK, 0);
289362306a36Sopenharmony_ci	else
289462306a36Sopenharmony_ci		bnx2x__link_status_update(bp);
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci	/* start the timer */
289762306a36Sopenharmony_ci	mod_timer(&bp->timer, jiffies + bp->current_interval);
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	if (CNIC_ENABLED(bp))
290062306a36Sopenharmony_ci		bnx2x_load_cnic(bp);
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	if (IS_PF(bp))
290362306a36Sopenharmony_ci		bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci	if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
290662306a36Sopenharmony_ci		/* mark driver is loaded in shmem2 */
290762306a36Sopenharmony_ci		u32 val;
290862306a36Sopenharmony_ci		val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
290962306a36Sopenharmony_ci		val &= ~DRV_FLAGS_MTU_MASK;
291062306a36Sopenharmony_ci		val |= (bp->dev->mtu << DRV_FLAGS_MTU_SHIFT);
291162306a36Sopenharmony_ci		SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
291262306a36Sopenharmony_ci			  val | DRV_FLAGS_CAPABILITIES_LOADED_SUPPORTED |
291362306a36Sopenharmony_ci			  DRV_FLAGS_CAPABILITIES_LOADED_L2);
291462306a36Sopenharmony_ci	}
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci	/* Wait for all pending SP commands to complete */
291762306a36Sopenharmony_ci	if (IS_PF(bp) && !bnx2x_wait_sp_comp(bp, ~0x0UL)) {
291862306a36Sopenharmony_ci		BNX2X_ERR("Timeout waiting for SP elements to complete\n");
291962306a36Sopenharmony_ci		bnx2x_nic_unload(bp, UNLOAD_CLOSE, false);
292062306a36Sopenharmony_ci		return -EBUSY;
292162306a36Sopenharmony_ci	}
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	/* Update driver data for On-Chip MFW dump. */
292462306a36Sopenharmony_ci	if (IS_PF(bp))
292562306a36Sopenharmony_ci		bnx2x_update_mfw_dump(bp);
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci	/* If PMF - send ADMIN DCBX msg to MFW to initiate DCBX FSM */
292862306a36Sopenharmony_ci	if (bp->port.pmf && (bp->state != BNX2X_STATE_DIAG))
292962306a36Sopenharmony_ci		bnx2x_dcbx_init(bp, false);
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_ci	if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp))
293262306a36Sopenharmony_ci		bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_ACTIVE);
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "Ending successfully NIC load\n");
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	return 0;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR
293962306a36Sopenharmony_ciload_error3:
294062306a36Sopenharmony_ci	if (IS_PF(bp)) {
294162306a36Sopenharmony_ci		bnx2x_int_disable_sync(bp, 1);
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci		/* Clean queueable objects */
294462306a36Sopenharmony_ci		bnx2x_squeeze_objects(bp);
294562306a36Sopenharmony_ci	}
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	/* Free SKBs, SGEs, TPA pool and driver internals */
294862306a36Sopenharmony_ci	bnx2x_free_skbs(bp);
294962306a36Sopenharmony_ci	for_each_rx_queue(bp, i)
295062306a36Sopenharmony_ci		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci	/* Release IRQs */
295362306a36Sopenharmony_ci	bnx2x_free_irq(bp);
295462306a36Sopenharmony_ciload_error2:
295562306a36Sopenharmony_ci	if (IS_PF(bp) && !BP_NOMCP(bp)) {
295662306a36Sopenharmony_ci		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
295762306a36Sopenharmony_ci		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
295862306a36Sopenharmony_ci	}
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	bp->port.pmf = 0;
296162306a36Sopenharmony_ciload_error1:
296262306a36Sopenharmony_ci	bnx2x_napi_disable(bp);
296362306a36Sopenharmony_ci	bnx2x_del_all_napi(bp);
296462306a36Sopenharmony_ci	bp->nic_stopped = true;
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci	/* clear pf_load status, as it was already set */
296762306a36Sopenharmony_ci	if (IS_PF(bp))
296862306a36Sopenharmony_ci		bnx2x_clear_pf_load(bp);
296962306a36Sopenharmony_ciload_error0:
297062306a36Sopenharmony_ci	bnx2x_free_fw_stats_mem(bp);
297162306a36Sopenharmony_ci	bnx2x_free_fp_mem(bp);
297262306a36Sopenharmony_ci	bnx2x_free_mem(bp);
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	return rc;
297562306a36Sopenharmony_ci#endif /* ! BNX2X_STOP_ON_ERROR */
297662306a36Sopenharmony_ci}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ciint bnx2x_drain_tx_queues(struct bnx2x *bp)
297962306a36Sopenharmony_ci{
298062306a36Sopenharmony_ci	u8 rc = 0, cos, i;
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci	/* Wait until tx fastpath tasks complete */
298362306a36Sopenharmony_ci	for_each_tx_queue(bp, i) {
298462306a36Sopenharmony_ci		struct bnx2x_fastpath *fp = &bp->fp[i];
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci		for_each_cos_in_tx_queue(fp, cos)
298762306a36Sopenharmony_ci			rc = bnx2x_clean_tx_queue(bp, fp->txdata_ptr[cos]);
298862306a36Sopenharmony_ci		if (rc)
298962306a36Sopenharmony_ci			return rc;
299062306a36Sopenharmony_ci	}
299162306a36Sopenharmony_ci	return 0;
299262306a36Sopenharmony_ci}
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci/* must be called with rtnl_lock */
299562306a36Sopenharmony_ciint bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
299662306a36Sopenharmony_ci{
299762306a36Sopenharmony_ci	int i;
299862306a36Sopenharmony_ci	bool global = false;
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "Starting NIC unload\n");
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci	if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp))
300362306a36Sopenharmony_ci		bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_DISABLED);
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	/* mark driver is unloaded in shmem2 */
300662306a36Sopenharmony_ci	if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
300762306a36Sopenharmony_ci		u32 val;
300862306a36Sopenharmony_ci		val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
300962306a36Sopenharmony_ci		SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
301062306a36Sopenharmony_ci			  val & ~DRV_FLAGS_CAPABILITIES_LOADED_L2);
301162306a36Sopenharmony_ci	}
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	if (IS_PF(bp) && bp->recovery_state != BNX2X_RECOVERY_DONE &&
301462306a36Sopenharmony_ci	    (bp->state == BNX2X_STATE_CLOSED ||
301562306a36Sopenharmony_ci	     bp->state == BNX2X_STATE_ERROR)) {
301662306a36Sopenharmony_ci		/* We can get here if the driver has been unloaded
301762306a36Sopenharmony_ci		 * during parity error recovery and is either waiting for a
301862306a36Sopenharmony_ci		 * leader to complete or for other functions to unload and
301962306a36Sopenharmony_ci		 * then ifdown has been issued. In this case we want to
302062306a36Sopenharmony_ci		 * unload and let other functions to complete a recovery
302162306a36Sopenharmony_ci		 * process.
302262306a36Sopenharmony_ci		 */
302362306a36Sopenharmony_ci		bp->recovery_state = BNX2X_RECOVERY_DONE;
302462306a36Sopenharmony_ci		bp->is_leader = 0;
302562306a36Sopenharmony_ci		bnx2x_release_leader_lock(bp);
302662306a36Sopenharmony_ci		smp_mb();
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci		DP(NETIF_MSG_IFDOWN, "Releasing a leadership...\n");
302962306a36Sopenharmony_ci		BNX2X_ERR("Can't unload in closed or error state\n");
303062306a36Sopenharmony_ci		return -EINVAL;
303162306a36Sopenharmony_ci	}
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	/* Nothing to do during unload if previous bnx2x_nic_load()
303462306a36Sopenharmony_ci	 * have not completed successfully - all resources are released.
303562306a36Sopenharmony_ci	 *
303662306a36Sopenharmony_ci	 * we can get here only after unsuccessful ndo_* callback, during which
303762306a36Sopenharmony_ci	 * dev->IFF_UP flag is still on.
303862306a36Sopenharmony_ci	 */
303962306a36Sopenharmony_ci	if (bp->state == BNX2X_STATE_CLOSED || bp->state == BNX2X_STATE_ERROR)
304062306a36Sopenharmony_ci		return 0;
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	/* It's important to set the bp->state to the value different from
304362306a36Sopenharmony_ci	 * BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int()
304462306a36Sopenharmony_ci	 * may restart the Tx from the NAPI context (see bnx2x_tx_int()).
304562306a36Sopenharmony_ci	 */
304662306a36Sopenharmony_ci	bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
304762306a36Sopenharmony_ci	smp_mb();
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	/* indicate to VFs that the PF is going down */
305062306a36Sopenharmony_ci	bnx2x_iov_channel_down(bp);
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci	if (CNIC_LOADED(bp))
305362306a36Sopenharmony_ci		bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	/* Stop Tx */
305662306a36Sopenharmony_ci	bnx2x_tx_disable(bp);
305762306a36Sopenharmony_ci	netdev_reset_tc(bp->dev);
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	bp->rx_mode = BNX2X_RX_MODE_NONE;
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci	del_timer_sync(&bp->timer);
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ci	if (IS_PF(bp) && !BP_NOMCP(bp)) {
306462306a36Sopenharmony_ci		/* Set ALWAYS_ALIVE bit in shmem */
306562306a36Sopenharmony_ci		bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
306662306a36Sopenharmony_ci		bnx2x_drv_pulse(bp);
306762306a36Sopenharmony_ci		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
306862306a36Sopenharmony_ci		bnx2x_save_statistics(bp);
306962306a36Sopenharmony_ci	}
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	/* wait till consumers catch up with producers in all queues.
307262306a36Sopenharmony_ci	 * If we're recovering, FW can't write to host so no reason
307362306a36Sopenharmony_ci	 * to wait for the queues to complete all Tx.
307462306a36Sopenharmony_ci	 */
307562306a36Sopenharmony_ci	if (unload_mode != UNLOAD_RECOVERY)
307662306a36Sopenharmony_ci		bnx2x_drain_tx_queues(bp);
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	/* if VF indicate to PF this function is going down (PF will delete sp
307962306a36Sopenharmony_ci	 * elements and clear initializations
308062306a36Sopenharmony_ci	 */
308162306a36Sopenharmony_ci	if (IS_VF(bp)) {
308262306a36Sopenharmony_ci		bnx2x_clear_vlan_info(bp);
308362306a36Sopenharmony_ci		bnx2x_vfpf_close_vf(bp);
308462306a36Sopenharmony_ci	} else if (unload_mode != UNLOAD_RECOVERY) {
308562306a36Sopenharmony_ci		/* if this is a normal/close unload need to clean up chip*/
308662306a36Sopenharmony_ci		bnx2x_chip_cleanup(bp, unload_mode, keep_link);
308762306a36Sopenharmony_ci	} else {
308862306a36Sopenharmony_ci		/* Send the UNLOAD_REQUEST to the MCP */
308962306a36Sopenharmony_ci		bnx2x_send_unload_req(bp, unload_mode);
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci		/* Prevent transactions to host from the functions on the
309262306a36Sopenharmony_ci		 * engine that doesn't reset global blocks in case of global
309362306a36Sopenharmony_ci		 * attention once global blocks are reset and gates are opened
309462306a36Sopenharmony_ci		 * (the engine which leader will perform the recovery
309562306a36Sopenharmony_ci		 * last).
309662306a36Sopenharmony_ci		 */
309762306a36Sopenharmony_ci		if (!CHIP_IS_E1x(bp))
309862306a36Sopenharmony_ci			bnx2x_pf_disable(bp);
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci		if (!bp->nic_stopped) {
310162306a36Sopenharmony_ci			/* Disable HW interrupts, NAPI */
310262306a36Sopenharmony_ci			bnx2x_netif_stop(bp, 1);
310362306a36Sopenharmony_ci			/* Delete all NAPI objects */
310462306a36Sopenharmony_ci			bnx2x_del_all_napi(bp);
310562306a36Sopenharmony_ci			if (CNIC_LOADED(bp))
310662306a36Sopenharmony_ci				bnx2x_del_all_napi_cnic(bp);
310762306a36Sopenharmony_ci			/* Release IRQs */
310862306a36Sopenharmony_ci			bnx2x_free_irq(bp);
310962306a36Sopenharmony_ci			bp->nic_stopped = true;
311062306a36Sopenharmony_ci		}
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci		/* Report UNLOAD_DONE to MCP */
311362306a36Sopenharmony_ci		bnx2x_send_unload_done(bp, false);
311462306a36Sopenharmony_ci	}
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_ci	/*
311762306a36Sopenharmony_ci	 * At this stage no more interrupts will arrive so we may safely clean
311862306a36Sopenharmony_ci	 * the queueable objects here in case they failed to get cleaned so far.
311962306a36Sopenharmony_ci	 */
312062306a36Sopenharmony_ci	if (IS_PF(bp))
312162306a36Sopenharmony_ci		bnx2x_squeeze_objects(bp);
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci	/* There should be no more pending SP commands at this stage */
312462306a36Sopenharmony_ci	bp->sp_state = 0;
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci	bp->port.pmf = 0;
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	/* clear pending work in rtnl task */
312962306a36Sopenharmony_ci	bp->sp_rtnl_state = 0;
313062306a36Sopenharmony_ci	smp_mb();
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci	/* Free SKBs, SGEs, TPA pool and driver internals */
313362306a36Sopenharmony_ci	bnx2x_free_skbs(bp);
313462306a36Sopenharmony_ci	if (CNIC_LOADED(bp))
313562306a36Sopenharmony_ci		bnx2x_free_skbs_cnic(bp);
313662306a36Sopenharmony_ci	for_each_rx_queue(bp, i)
313762306a36Sopenharmony_ci		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	bnx2x_free_fp_mem(bp);
314062306a36Sopenharmony_ci	if (CNIC_LOADED(bp))
314162306a36Sopenharmony_ci		bnx2x_free_fp_mem_cnic(bp);
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_ci	if (IS_PF(bp)) {
314462306a36Sopenharmony_ci		if (CNIC_LOADED(bp))
314562306a36Sopenharmony_ci			bnx2x_free_mem_cnic(bp);
314662306a36Sopenharmony_ci	}
314762306a36Sopenharmony_ci	bnx2x_free_mem(bp);
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	bp->state = BNX2X_STATE_CLOSED;
315062306a36Sopenharmony_ci	bp->cnic_loaded = false;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	/* Clear driver version indication in shmem */
315362306a36Sopenharmony_ci	if (IS_PF(bp) && !BP_NOMCP(bp))
315462306a36Sopenharmony_ci		bnx2x_update_mng_version(bp);
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	/* Check if there are pending parity attentions. If there are - set
315762306a36Sopenharmony_ci	 * RECOVERY_IN_PROGRESS.
315862306a36Sopenharmony_ci	 */
315962306a36Sopenharmony_ci	if (IS_PF(bp) && bnx2x_chk_parity_attn(bp, &global, false)) {
316062306a36Sopenharmony_ci		bnx2x_set_reset_in_progress(bp);
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci		/* Set RESET_IS_GLOBAL if needed */
316362306a36Sopenharmony_ci		if (global)
316462306a36Sopenharmony_ci			bnx2x_set_reset_global(bp);
316562306a36Sopenharmony_ci	}
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	/* The last driver must disable a "close the gate" if there is no
316862306a36Sopenharmony_ci	 * parity attention or "process kill" pending.
316962306a36Sopenharmony_ci	 */
317062306a36Sopenharmony_ci	if (IS_PF(bp) &&
317162306a36Sopenharmony_ci	    !bnx2x_clear_pf_load(bp) &&
317262306a36Sopenharmony_ci	    bnx2x_reset_is_done(bp, BP_PATH(bp)))
317362306a36Sopenharmony_ci		bnx2x_disable_close_the_gate(bp);
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP, "Ending NIC unload\n");
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	return 0;
317862306a36Sopenharmony_ci}
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ciint bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
318162306a36Sopenharmony_ci{
318262306a36Sopenharmony_ci	u16 pmcsr;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci	/* If there is no power capability, silently succeed */
318562306a36Sopenharmony_ci	if (!bp->pdev->pm_cap) {
318662306a36Sopenharmony_ci		BNX2X_DEV_INFO("No power capability. Breaking.\n");
318762306a36Sopenharmony_ci		return 0;
318862306a36Sopenharmony_ci	}
318962306a36Sopenharmony_ci
319062306a36Sopenharmony_ci	pci_read_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL, &pmcsr);
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	switch (state) {
319362306a36Sopenharmony_ci	case PCI_D0:
319462306a36Sopenharmony_ci		pci_write_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL,
319562306a36Sopenharmony_ci				      ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
319662306a36Sopenharmony_ci				       PCI_PM_CTRL_PME_STATUS));
319762306a36Sopenharmony_ci
319862306a36Sopenharmony_ci		if (pmcsr & PCI_PM_CTRL_STATE_MASK)
319962306a36Sopenharmony_ci			/* delay required during transition out of D3hot */
320062306a36Sopenharmony_ci			msleep(20);
320162306a36Sopenharmony_ci		break;
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	case PCI_D3hot:
320462306a36Sopenharmony_ci		/* If there are other clients above don't
320562306a36Sopenharmony_ci		   shut down the power */
320662306a36Sopenharmony_ci		if (atomic_read(&bp->pdev->enable_cnt) != 1)
320762306a36Sopenharmony_ci			return 0;
320862306a36Sopenharmony_ci		/* Don't shut down the power for emulation and FPGA */
320962306a36Sopenharmony_ci		if (CHIP_REV_IS_SLOW(bp))
321062306a36Sopenharmony_ci			return 0;
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
321362306a36Sopenharmony_ci		pmcsr |= 3;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci		if (bp->wol)
321662306a36Sopenharmony_ci			pmcsr |= PCI_PM_CTRL_PME_ENABLE;
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_ci		pci_write_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL,
321962306a36Sopenharmony_ci				      pmcsr);
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci		/* No more memory access after this point until
322262306a36Sopenharmony_ci		* device is brought back to D0.
322362306a36Sopenharmony_ci		*/
322462306a36Sopenharmony_ci		break;
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	default:
322762306a36Sopenharmony_ci		dev_err(&bp->pdev->dev, "Can't support state = %d\n", state);
322862306a36Sopenharmony_ci		return -EINVAL;
322962306a36Sopenharmony_ci	}
323062306a36Sopenharmony_ci	return 0;
323162306a36Sopenharmony_ci}
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci/*
323462306a36Sopenharmony_ci * net_device service functions
323562306a36Sopenharmony_ci */
323662306a36Sopenharmony_cistatic int bnx2x_poll(struct napi_struct *napi, int budget)
323762306a36Sopenharmony_ci{
323862306a36Sopenharmony_ci	struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
323962306a36Sopenharmony_ci						 napi);
324062306a36Sopenharmony_ci	struct bnx2x *bp = fp->bp;
324162306a36Sopenharmony_ci	int rx_work_done;
324262306a36Sopenharmony_ci	u8 cos;
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
324562306a36Sopenharmony_ci	if (unlikely(bp->panic)) {
324662306a36Sopenharmony_ci		napi_complete(napi);
324762306a36Sopenharmony_ci		return 0;
324862306a36Sopenharmony_ci	}
324962306a36Sopenharmony_ci#endif
325062306a36Sopenharmony_ci	for_each_cos_in_tx_queue(fp, cos)
325162306a36Sopenharmony_ci		if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos]))
325262306a36Sopenharmony_ci			bnx2x_tx_int(bp, fp->txdata_ptr[cos]);
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	rx_work_done = (bnx2x_has_rx_work(fp)) ? bnx2x_rx_int(fp, budget) : 0;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	if (rx_work_done < budget) {
325762306a36Sopenharmony_ci		/* No need to update SB for FCoE L2 ring as long as
325862306a36Sopenharmony_ci		 * it's connected to the default SB and the SB
325962306a36Sopenharmony_ci		 * has been updated when NAPI was scheduled.
326062306a36Sopenharmony_ci		 */
326162306a36Sopenharmony_ci		if (IS_FCOE_FP(fp)) {
326262306a36Sopenharmony_ci			napi_complete_done(napi, rx_work_done);
326362306a36Sopenharmony_ci		} else {
326462306a36Sopenharmony_ci			bnx2x_update_fpsb_idx(fp);
326562306a36Sopenharmony_ci			/* bnx2x_has_rx_work() reads the status block,
326662306a36Sopenharmony_ci			 * thus we need to ensure that status block indices
326762306a36Sopenharmony_ci			 * have been actually read (bnx2x_update_fpsb_idx)
326862306a36Sopenharmony_ci			 * prior to this check (bnx2x_has_rx_work) so that
326962306a36Sopenharmony_ci			 * we won't write the "newer" value of the status block
327062306a36Sopenharmony_ci			 * to IGU (if there was a DMA right after
327162306a36Sopenharmony_ci			 * bnx2x_has_rx_work and if there is no rmb, the memory
327262306a36Sopenharmony_ci			 * reading (bnx2x_update_fpsb_idx) may be postponed
327362306a36Sopenharmony_ci			 * to right before bnx2x_ack_sb). In this case there
327462306a36Sopenharmony_ci			 * will never be another interrupt until there is
327562306a36Sopenharmony_ci			 * another update of the status block, while there
327662306a36Sopenharmony_ci			 * is still unhandled work.
327762306a36Sopenharmony_ci			 */
327862306a36Sopenharmony_ci			rmb();
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci			if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
328162306a36Sopenharmony_ci				if (napi_complete_done(napi, rx_work_done)) {
328262306a36Sopenharmony_ci					/* Re-enable interrupts */
328362306a36Sopenharmony_ci					DP(NETIF_MSG_RX_STATUS,
328462306a36Sopenharmony_ci					   "Update index to %d\n", fp->fp_hc_idx);
328562306a36Sopenharmony_ci					bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID,
328662306a36Sopenharmony_ci						     le16_to_cpu(fp->fp_hc_idx),
328762306a36Sopenharmony_ci						     IGU_INT_ENABLE, 1);
328862306a36Sopenharmony_ci				}
328962306a36Sopenharmony_ci			} else {
329062306a36Sopenharmony_ci				rx_work_done = budget;
329162306a36Sopenharmony_ci			}
329262306a36Sopenharmony_ci		}
329362306a36Sopenharmony_ci	}
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	return rx_work_done;
329662306a36Sopenharmony_ci}
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci/* we split the first BD into headers and data BDs
329962306a36Sopenharmony_ci * to ease the pain of our fellow microcode engineers
330062306a36Sopenharmony_ci * we use one mapping for both BDs
330162306a36Sopenharmony_ci */
330262306a36Sopenharmony_cistatic u16 bnx2x_tx_split(struct bnx2x *bp,
330362306a36Sopenharmony_ci			  struct bnx2x_fp_txdata *txdata,
330462306a36Sopenharmony_ci			  struct sw_tx_bd *tx_buf,
330562306a36Sopenharmony_ci			  struct eth_tx_start_bd **tx_bd, u16 hlen,
330662306a36Sopenharmony_ci			  u16 bd_prod)
330762306a36Sopenharmony_ci{
330862306a36Sopenharmony_ci	struct eth_tx_start_bd *h_tx_bd = *tx_bd;
330962306a36Sopenharmony_ci	struct eth_tx_bd *d_tx_bd;
331062306a36Sopenharmony_ci	dma_addr_t mapping;
331162306a36Sopenharmony_ci	int old_len = le16_to_cpu(h_tx_bd->nbytes);
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	/* first fix first BD */
331462306a36Sopenharmony_ci	h_tx_bd->nbytes = cpu_to_le16(hlen);
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED,	"TSO split header size is %d (%x:%x)\n",
331762306a36Sopenharmony_ci	   h_tx_bd->nbytes, h_tx_bd->addr_hi, h_tx_bd->addr_lo);
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci	/* now get a new data BD
332062306a36Sopenharmony_ci	 * (after the pbd) and fill it */
332162306a36Sopenharmony_ci	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
332262306a36Sopenharmony_ci	d_tx_bd = &txdata->tx_desc_ring[bd_prod].reg_bd;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi),
332562306a36Sopenharmony_ci			   le32_to_cpu(h_tx_bd->addr_lo)) + hlen;
332662306a36Sopenharmony_ci
332762306a36Sopenharmony_ci	d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
332862306a36Sopenharmony_ci	d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
332962306a36Sopenharmony_ci	d_tx_bd->nbytes = cpu_to_le16(old_len - hlen);
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	/* this marks the BD as one that has no individual mapping */
333262306a36Sopenharmony_ci	tx_buf->flags |= BNX2X_TSO_SPLIT_BD;
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED,
333562306a36Sopenharmony_ci	   "TSO split data size is %d (%x:%x)\n",
333662306a36Sopenharmony_ci	   d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo);
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ci	/* update tx_bd */
333962306a36Sopenharmony_ci	*tx_bd = (struct eth_tx_start_bd *)d_tx_bd;
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	return bd_prod;
334262306a36Sopenharmony_ci}
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci#define bswab32(b32) ((__force __le32) swab32((__force __u32) (b32)))
334562306a36Sopenharmony_ci#define bswab16(b16) ((__force __le16) swab16((__force __u16) (b16)))
334662306a36Sopenharmony_cistatic __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
334762306a36Sopenharmony_ci{
334862306a36Sopenharmony_ci	__sum16 tsum = (__force __sum16) csum;
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	if (fix > 0)
335162306a36Sopenharmony_ci		tsum = ~csum_fold(csum_sub((__force __wsum) csum,
335262306a36Sopenharmony_ci				  csum_partial(t_header - fix, fix, 0)));
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci	else if (fix < 0)
335562306a36Sopenharmony_ci		tsum = ~csum_fold(csum_add((__force __wsum) csum,
335662306a36Sopenharmony_ci				  csum_partial(t_header, -fix, 0)));
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci	return bswab16(tsum);
335962306a36Sopenharmony_ci}
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_cistatic u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
336262306a36Sopenharmony_ci{
336362306a36Sopenharmony_ci	u32 rc;
336462306a36Sopenharmony_ci	__u8 prot = 0;
336562306a36Sopenharmony_ci	__be16 protocol;
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	if (skb->ip_summed != CHECKSUM_PARTIAL)
336862306a36Sopenharmony_ci		return XMIT_PLAIN;
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	protocol = vlan_get_protocol(skb);
337162306a36Sopenharmony_ci	if (protocol == htons(ETH_P_IPV6)) {
337262306a36Sopenharmony_ci		rc = XMIT_CSUM_V6;
337362306a36Sopenharmony_ci		prot = ipv6_hdr(skb)->nexthdr;
337462306a36Sopenharmony_ci	} else {
337562306a36Sopenharmony_ci		rc = XMIT_CSUM_V4;
337662306a36Sopenharmony_ci		prot = ip_hdr(skb)->protocol;
337762306a36Sopenharmony_ci	}
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci	if (!CHIP_IS_E1x(bp) && skb->encapsulation) {
338062306a36Sopenharmony_ci		if (inner_ip_hdr(skb)->version == 6) {
338162306a36Sopenharmony_ci			rc |= XMIT_CSUM_ENC_V6;
338262306a36Sopenharmony_ci			if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
338362306a36Sopenharmony_ci				rc |= XMIT_CSUM_TCP;
338462306a36Sopenharmony_ci		} else {
338562306a36Sopenharmony_ci			rc |= XMIT_CSUM_ENC_V4;
338662306a36Sopenharmony_ci			if (inner_ip_hdr(skb)->protocol == IPPROTO_TCP)
338762306a36Sopenharmony_ci				rc |= XMIT_CSUM_TCP;
338862306a36Sopenharmony_ci		}
338962306a36Sopenharmony_ci	}
339062306a36Sopenharmony_ci	if (prot == IPPROTO_TCP)
339162306a36Sopenharmony_ci		rc |= XMIT_CSUM_TCP;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	if (skb_is_gso(skb)) {
339462306a36Sopenharmony_ci		if (skb_is_gso_v6(skb)) {
339562306a36Sopenharmony_ci			rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP);
339662306a36Sopenharmony_ci			if (rc & XMIT_CSUM_ENC)
339762306a36Sopenharmony_ci				rc |= XMIT_GSO_ENC_V6;
339862306a36Sopenharmony_ci		} else {
339962306a36Sopenharmony_ci			rc |= (XMIT_GSO_V4 | XMIT_CSUM_TCP);
340062306a36Sopenharmony_ci			if (rc & XMIT_CSUM_ENC)
340162306a36Sopenharmony_ci				rc |= XMIT_GSO_ENC_V4;
340262306a36Sopenharmony_ci		}
340362306a36Sopenharmony_ci	}
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	return rc;
340662306a36Sopenharmony_ci}
340762306a36Sopenharmony_ci
340862306a36Sopenharmony_ci/* VXLAN: 4 = 1 (for linear data BD) + 3 (2 for PBD and last BD) */
340962306a36Sopenharmony_ci#define BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS         4
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci/* Regular: 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
341262306a36Sopenharmony_ci#define BNX2X_NUM_TSO_WIN_SUB_BDS               3
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - BDS_PER_TX_PKT)
341562306a36Sopenharmony_ci/* check if packet requires linearization (packet is too fragmented)
341662306a36Sopenharmony_ci   no need to check fragmentation if page size > 8K (there will be no
341762306a36Sopenharmony_ci   violation to FW restrictions) */
341862306a36Sopenharmony_cistatic int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
341962306a36Sopenharmony_ci			     u32 xmit_type)
342062306a36Sopenharmony_ci{
342162306a36Sopenharmony_ci	int first_bd_sz = 0, num_tso_win_sub = BNX2X_NUM_TSO_WIN_SUB_BDS;
342262306a36Sopenharmony_ci	int to_copy = 0, hlen = 0;
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	if (xmit_type & XMIT_GSO_ENC)
342562306a36Sopenharmony_ci		num_tso_win_sub = BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS;
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - num_tso_win_sub)) {
342862306a36Sopenharmony_ci		if (xmit_type & XMIT_GSO) {
342962306a36Sopenharmony_ci			unsigned short lso_mss = skb_shinfo(skb)->gso_size;
343062306a36Sopenharmony_ci			int wnd_size = MAX_FETCH_BD - num_tso_win_sub;
343162306a36Sopenharmony_ci			/* Number of windows to check */
343262306a36Sopenharmony_ci			int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size;
343362306a36Sopenharmony_ci			int wnd_idx = 0;
343462306a36Sopenharmony_ci			int frag_idx = 0;
343562306a36Sopenharmony_ci			u32 wnd_sum = 0;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci			/* Headers length */
343862306a36Sopenharmony_ci			if (xmit_type & XMIT_GSO_ENC)
343962306a36Sopenharmony_ci				hlen = skb_inner_tcp_all_headers(skb);
344062306a36Sopenharmony_ci			else
344162306a36Sopenharmony_ci				hlen = skb_tcp_all_headers(skb);
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_ci			/* Amount of data (w/o headers) on linear part of SKB*/
344462306a36Sopenharmony_ci			first_bd_sz = skb_headlen(skb) - hlen;
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci			wnd_sum  = first_bd_sz;
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci			/* Calculate the first sum - it's special */
344962306a36Sopenharmony_ci			for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++)
345062306a36Sopenharmony_ci				wnd_sum +=
345162306a36Sopenharmony_ci					skb_frag_size(&skb_shinfo(skb)->frags[frag_idx]);
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci			/* If there was data on linear skb data - check it */
345462306a36Sopenharmony_ci			if (first_bd_sz > 0) {
345562306a36Sopenharmony_ci				if (unlikely(wnd_sum < lso_mss)) {
345662306a36Sopenharmony_ci					to_copy = 1;
345762306a36Sopenharmony_ci					goto exit_lbl;
345862306a36Sopenharmony_ci				}
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci				wnd_sum -= first_bd_sz;
346162306a36Sopenharmony_ci			}
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_ci			/* Others are easier: run through the frag list and
346462306a36Sopenharmony_ci			   check all windows */
346562306a36Sopenharmony_ci			for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) {
346662306a36Sopenharmony_ci				wnd_sum +=
346762306a36Sopenharmony_ci			  skb_frag_size(&skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1]);
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci				if (unlikely(wnd_sum < lso_mss)) {
347062306a36Sopenharmony_ci					to_copy = 1;
347162306a36Sopenharmony_ci					break;
347262306a36Sopenharmony_ci				}
347362306a36Sopenharmony_ci				wnd_sum -=
347462306a36Sopenharmony_ci					skb_frag_size(&skb_shinfo(skb)->frags[wnd_idx]);
347562306a36Sopenharmony_ci			}
347662306a36Sopenharmony_ci		} else {
347762306a36Sopenharmony_ci			/* in non-LSO too fragmented packet should always
347862306a36Sopenharmony_ci			   be linearized */
347962306a36Sopenharmony_ci			to_copy = 1;
348062306a36Sopenharmony_ci		}
348162306a36Sopenharmony_ci	}
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ciexit_lbl:
348462306a36Sopenharmony_ci	if (unlikely(to_copy))
348562306a36Sopenharmony_ci		DP(NETIF_MSG_TX_QUEUED,
348662306a36Sopenharmony_ci		   "Linearization IS REQUIRED for %s packet. num_frags %d  hlen %d  first_bd_sz %d\n",
348762306a36Sopenharmony_ci		   (xmit_type & XMIT_GSO) ? "LSO" : "non-LSO",
348862306a36Sopenharmony_ci		   skb_shinfo(skb)->nr_frags, hlen, first_bd_sz);
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci	return to_copy;
349162306a36Sopenharmony_ci}
349262306a36Sopenharmony_ci#endif
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci/**
349562306a36Sopenharmony_ci * bnx2x_set_pbd_gso - update PBD in GSO case.
349662306a36Sopenharmony_ci *
349762306a36Sopenharmony_ci * @skb:	packet skb
349862306a36Sopenharmony_ci * @pbd:	parse BD
349962306a36Sopenharmony_ci * @xmit_type:	xmit flags
350062306a36Sopenharmony_ci */
350162306a36Sopenharmony_cistatic void bnx2x_set_pbd_gso(struct sk_buff *skb,
350262306a36Sopenharmony_ci			      struct eth_tx_parse_bd_e1x *pbd,
350362306a36Sopenharmony_ci			      u32 xmit_type)
350462306a36Sopenharmony_ci{
350562306a36Sopenharmony_ci	pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
350662306a36Sopenharmony_ci	pbd->tcp_send_seq = bswab32(tcp_hdr(skb)->seq);
350762306a36Sopenharmony_ci	pbd->tcp_flags = pbd_tcp_flags(tcp_hdr(skb));
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci	if (xmit_type & XMIT_GSO_V4) {
351062306a36Sopenharmony_ci		pbd->ip_id = bswab16(ip_hdr(skb)->id);
351162306a36Sopenharmony_ci		pbd->tcp_pseudo_csum =
351262306a36Sopenharmony_ci			bswab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
351362306a36Sopenharmony_ci						   ip_hdr(skb)->daddr,
351462306a36Sopenharmony_ci						   0, IPPROTO_TCP, 0));
351562306a36Sopenharmony_ci	} else {
351662306a36Sopenharmony_ci		pbd->tcp_pseudo_csum =
351762306a36Sopenharmony_ci			bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
351862306a36Sopenharmony_ci						 &ipv6_hdr(skb)->daddr,
351962306a36Sopenharmony_ci						 0, IPPROTO_TCP, 0));
352062306a36Sopenharmony_ci	}
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_ci	pbd->global_data |=
352362306a36Sopenharmony_ci		cpu_to_le16(ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN);
352462306a36Sopenharmony_ci}
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci/**
352762306a36Sopenharmony_ci * bnx2x_set_pbd_csum_enc - update PBD with checksum and return header length
352862306a36Sopenharmony_ci *
352962306a36Sopenharmony_ci * @bp:			driver handle
353062306a36Sopenharmony_ci * @skb:		packet skb
353162306a36Sopenharmony_ci * @parsing_data:	data to be updated
353262306a36Sopenharmony_ci * @xmit_type:		xmit flags
353362306a36Sopenharmony_ci *
353462306a36Sopenharmony_ci * 57712/578xx related, when skb has encapsulation
353562306a36Sopenharmony_ci */
353662306a36Sopenharmony_cistatic u8 bnx2x_set_pbd_csum_enc(struct bnx2x *bp, struct sk_buff *skb,
353762306a36Sopenharmony_ci				 u32 *parsing_data, u32 xmit_type)
353862306a36Sopenharmony_ci{
353962306a36Sopenharmony_ci	*parsing_data |=
354062306a36Sopenharmony_ci		((((u8 *)skb_inner_transport_header(skb) - skb->data) >> 1) <<
354162306a36Sopenharmony_ci		ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT) &
354262306a36Sopenharmony_ci		ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W;
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	if (xmit_type & XMIT_CSUM_TCP) {
354562306a36Sopenharmony_ci		*parsing_data |= ((inner_tcp_hdrlen(skb) / 4) <<
354662306a36Sopenharmony_ci			ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
354762306a36Sopenharmony_ci			ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci		return skb_inner_tcp_all_headers(skb);
355062306a36Sopenharmony_ci	}
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci	/* We support checksum offload for TCP and UDP only.
355362306a36Sopenharmony_ci	 * No need to pass the UDP header length - it's a constant.
355462306a36Sopenharmony_ci	 */
355562306a36Sopenharmony_ci	return skb_inner_transport_offset(skb) + sizeof(struct udphdr);
355662306a36Sopenharmony_ci}
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci/**
355962306a36Sopenharmony_ci * bnx2x_set_pbd_csum_e2 - update PBD with checksum and return header length
356062306a36Sopenharmony_ci *
356162306a36Sopenharmony_ci * @bp:			driver handle
356262306a36Sopenharmony_ci * @skb:		packet skb
356362306a36Sopenharmony_ci * @parsing_data:	data to be updated
356462306a36Sopenharmony_ci * @xmit_type:		xmit flags
356562306a36Sopenharmony_ci *
356662306a36Sopenharmony_ci * 57712/578xx related
356762306a36Sopenharmony_ci */
356862306a36Sopenharmony_cistatic u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
356962306a36Sopenharmony_ci				u32 *parsing_data, u32 xmit_type)
357062306a36Sopenharmony_ci{
357162306a36Sopenharmony_ci	*parsing_data |=
357262306a36Sopenharmony_ci		((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
357362306a36Sopenharmony_ci		ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT) &
357462306a36Sopenharmony_ci		ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W;
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci	if (xmit_type & XMIT_CSUM_TCP) {
357762306a36Sopenharmony_ci		*parsing_data |= ((tcp_hdrlen(skb) / 4) <<
357862306a36Sopenharmony_ci			ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
357962306a36Sopenharmony_ci			ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci		return skb_tcp_all_headers(skb);
358262306a36Sopenharmony_ci	}
358362306a36Sopenharmony_ci	/* We support checksum offload for TCP and UDP only.
358462306a36Sopenharmony_ci	 * No need to pass the UDP header length - it's a constant.
358562306a36Sopenharmony_ci	 */
358662306a36Sopenharmony_ci	return skb_transport_offset(skb) + sizeof(struct udphdr);
358762306a36Sopenharmony_ci}
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_ci/* set FW indication according to inner or outer protocols if tunneled */
359062306a36Sopenharmony_cistatic void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb,
359162306a36Sopenharmony_ci			       struct eth_tx_start_bd *tx_start_bd,
359262306a36Sopenharmony_ci			       u32 xmit_type)
359362306a36Sopenharmony_ci{
359462306a36Sopenharmony_ci	tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM;
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci	if (xmit_type & (XMIT_CSUM_ENC_V6 | XMIT_CSUM_V6))
359762306a36Sopenharmony_ci		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IPV6;
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	if (!(xmit_type & XMIT_CSUM_TCP))
360062306a36Sopenharmony_ci		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IS_UDP;
360162306a36Sopenharmony_ci}
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci/**
360462306a36Sopenharmony_ci * bnx2x_set_pbd_csum - update PBD with checksum and return header length
360562306a36Sopenharmony_ci *
360662306a36Sopenharmony_ci * @bp:		driver handle
360762306a36Sopenharmony_ci * @skb:	packet skb
360862306a36Sopenharmony_ci * @pbd:	parse BD to be updated
360962306a36Sopenharmony_ci * @xmit_type:	xmit flags
361062306a36Sopenharmony_ci */
361162306a36Sopenharmony_cistatic u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
361262306a36Sopenharmony_ci			     struct eth_tx_parse_bd_e1x *pbd,
361362306a36Sopenharmony_ci			     u32 xmit_type)
361462306a36Sopenharmony_ci{
361562306a36Sopenharmony_ci	u8 hlen = (skb_network_header(skb) - skb->data) >> 1;
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	/* for now NS flag is not used in Linux */
361862306a36Sopenharmony_ci	pbd->global_data =
361962306a36Sopenharmony_ci		cpu_to_le16(hlen |
362062306a36Sopenharmony_ci			    ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
362162306a36Sopenharmony_ci			     ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
362262306a36Sopenharmony_ci
362362306a36Sopenharmony_ci	pbd->ip_hlen_w = (skb_transport_header(skb) -
362462306a36Sopenharmony_ci			skb_network_header(skb)) >> 1;
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	hlen += pbd->ip_hlen_w;
362762306a36Sopenharmony_ci
362862306a36Sopenharmony_ci	/* We support checksum offload for TCP and UDP only */
362962306a36Sopenharmony_ci	if (xmit_type & XMIT_CSUM_TCP)
363062306a36Sopenharmony_ci		hlen += tcp_hdrlen(skb) / 2;
363162306a36Sopenharmony_ci	else
363262306a36Sopenharmony_ci		hlen += sizeof(struct udphdr) / 2;
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_ci	pbd->total_hlen_w = cpu_to_le16(hlen);
363562306a36Sopenharmony_ci	hlen = hlen*2;
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	if (xmit_type & XMIT_CSUM_TCP) {
363862306a36Sopenharmony_ci		pbd->tcp_pseudo_csum = bswab16(tcp_hdr(skb)->check);
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci	} else {
364162306a36Sopenharmony_ci		s8 fix = SKB_CS_OFF(skb); /* signed! */
364262306a36Sopenharmony_ci
364362306a36Sopenharmony_ci		DP(NETIF_MSG_TX_QUEUED,
364462306a36Sopenharmony_ci		   "hlen %d  fix %d  csum before fix %x\n",
364562306a36Sopenharmony_ci		   le16_to_cpu(pbd->total_hlen_w), fix, SKB_CS(skb));
364662306a36Sopenharmony_ci
364762306a36Sopenharmony_ci		/* HW bug: fixup the CSUM */
364862306a36Sopenharmony_ci		pbd->tcp_pseudo_csum =
364962306a36Sopenharmony_ci			bnx2x_csum_fix(skb_transport_header(skb),
365062306a36Sopenharmony_ci				       SKB_CS(skb), fix);
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci		DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n",
365362306a36Sopenharmony_ci		   pbd->tcp_pseudo_csum);
365462306a36Sopenharmony_ci	}
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	return hlen;
365762306a36Sopenharmony_ci}
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_cistatic void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
366062306a36Sopenharmony_ci				      struct eth_tx_parse_bd_e2 *pbd_e2,
366162306a36Sopenharmony_ci				      struct eth_tx_parse_2nd_bd *pbd2,
366262306a36Sopenharmony_ci				      u16 *global_data,
366362306a36Sopenharmony_ci				      u32 xmit_type)
366462306a36Sopenharmony_ci{
366562306a36Sopenharmony_ci	u16 hlen_w = 0;
366662306a36Sopenharmony_ci	u8 outerip_off, outerip_len = 0;
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ci	/* from outer IP to transport */
366962306a36Sopenharmony_ci	hlen_w = (skb_inner_transport_header(skb) -
367062306a36Sopenharmony_ci		  skb_network_header(skb)) >> 1;
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci	/* transport len */
367362306a36Sopenharmony_ci	hlen_w += inner_tcp_hdrlen(skb) >> 1;
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	pbd2->fw_ip_hdr_to_payload_w = hlen_w;
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci	/* outer IP header info */
367862306a36Sopenharmony_ci	if (xmit_type & XMIT_CSUM_V4) {
367962306a36Sopenharmony_ci		struct iphdr *iph = ip_hdr(skb);
368062306a36Sopenharmony_ci		u32 csum = (__force u32)(~iph->check) -
368162306a36Sopenharmony_ci			   (__force u32)iph->tot_len -
368262306a36Sopenharmony_ci			   (__force u32)iph->frag_off;
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci		outerip_len = iph->ihl << 1;
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci		pbd2->fw_ip_csum_wo_len_flags_frag =
368762306a36Sopenharmony_ci			bswab16(csum_fold((__force __wsum)csum));
368862306a36Sopenharmony_ci	} else {
368962306a36Sopenharmony_ci		pbd2->fw_ip_hdr_to_payload_w =
369062306a36Sopenharmony_ci			hlen_w - ((sizeof(struct ipv6hdr)) >> 1);
369162306a36Sopenharmony_ci		pbd_e2->data.tunnel_data.flags |=
369262306a36Sopenharmony_ci			ETH_TUNNEL_DATA_IPV6_OUTER;
369362306a36Sopenharmony_ci	}
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_ci	pbd2->tcp_send_seq = bswab32(inner_tcp_hdr(skb)->seq);
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_ci	pbd2->tcp_flags = pbd_tcp_flags(inner_tcp_hdr(skb));
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci	/* inner IP header info */
370062306a36Sopenharmony_ci	if (xmit_type & XMIT_CSUM_ENC_V4) {
370162306a36Sopenharmony_ci		pbd2->hw_ip_id = bswab16(inner_ip_hdr(skb)->id);
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci		pbd_e2->data.tunnel_data.pseudo_csum =
370462306a36Sopenharmony_ci			bswab16(~csum_tcpudp_magic(
370562306a36Sopenharmony_ci					inner_ip_hdr(skb)->saddr,
370662306a36Sopenharmony_ci					inner_ip_hdr(skb)->daddr,
370762306a36Sopenharmony_ci					0, IPPROTO_TCP, 0));
370862306a36Sopenharmony_ci	} else {
370962306a36Sopenharmony_ci		pbd_e2->data.tunnel_data.pseudo_csum =
371062306a36Sopenharmony_ci			bswab16(~csum_ipv6_magic(
371162306a36Sopenharmony_ci					&inner_ipv6_hdr(skb)->saddr,
371262306a36Sopenharmony_ci					&inner_ipv6_hdr(skb)->daddr,
371362306a36Sopenharmony_ci					0, IPPROTO_TCP, 0));
371462306a36Sopenharmony_ci	}
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci	outerip_off = (skb_network_header(skb) - skb->data) >> 1;
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_ci	*global_data |=
371962306a36Sopenharmony_ci		outerip_off |
372062306a36Sopenharmony_ci		(outerip_len <<
372162306a36Sopenharmony_ci			ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT) |
372262306a36Sopenharmony_ci		((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
372362306a36Sopenharmony_ci			ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN_SHIFT);
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci	if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
372662306a36Sopenharmony_ci		SET_FLAG(*global_data, ETH_TX_PARSE_2ND_BD_TUNNEL_UDP_EXIST, 1);
372762306a36Sopenharmony_ci		pbd2->tunnel_udp_hdr_start_w = skb_transport_offset(skb) >> 1;
372862306a36Sopenharmony_ci	}
372962306a36Sopenharmony_ci}
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_cistatic inline void bnx2x_set_ipv6_ext_e2(struct sk_buff *skb, u32 *parsing_data,
373262306a36Sopenharmony_ci					 u32 xmit_type)
373362306a36Sopenharmony_ci{
373462306a36Sopenharmony_ci	struct ipv6hdr *ipv6;
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	if (!(xmit_type & (XMIT_GSO_ENC_V6 | XMIT_GSO_V6)))
373762306a36Sopenharmony_ci		return;
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci	if (xmit_type & XMIT_GSO_ENC_V6)
374062306a36Sopenharmony_ci		ipv6 = inner_ipv6_hdr(skb);
374162306a36Sopenharmony_ci	else /* XMIT_GSO_V6 */
374262306a36Sopenharmony_ci		ipv6 = ipv6_hdr(skb);
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci	if (ipv6->nexthdr == NEXTHDR_IPV6)
374562306a36Sopenharmony_ci		*parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
374662306a36Sopenharmony_ci}
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci/* called with netif_tx_lock
374962306a36Sopenharmony_ci * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
375062306a36Sopenharmony_ci * netif_wake_queue()
375162306a36Sopenharmony_ci */
375262306a36Sopenharmony_cinetdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
375362306a36Sopenharmony_ci{
375462306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_ci	struct netdev_queue *txq;
375762306a36Sopenharmony_ci	struct bnx2x_fp_txdata *txdata;
375862306a36Sopenharmony_ci	struct sw_tx_bd *tx_buf;
375962306a36Sopenharmony_ci	struct eth_tx_start_bd *tx_start_bd, *first_bd;
376062306a36Sopenharmony_ci	struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
376162306a36Sopenharmony_ci	struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
376262306a36Sopenharmony_ci	struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
376362306a36Sopenharmony_ci	struct eth_tx_parse_2nd_bd *pbd2 = NULL;
376462306a36Sopenharmony_ci	u32 pbd_e2_parsing_data = 0;
376562306a36Sopenharmony_ci	u16 pkt_prod, bd_prod;
376662306a36Sopenharmony_ci	int nbd, txq_index;
376762306a36Sopenharmony_ci	dma_addr_t mapping;
376862306a36Sopenharmony_ci	u32 xmit_type = bnx2x_xmit_type(bp, skb);
376962306a36Sopenharmony_ci	int i;
377062306a36Sopenharmony_ci	u8 hlen = 0;
377162306a36Sopenharmony_ci	__le16 pkt_size = 0;
377262306a36Sopenharmony_ci	struct ethhdr *eth;
377362306a36Sopenharmony_ci	u8 mac_type = UNICAST_ADDRESS;
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
377662306a36Sopenharmony_ci	if (unlikely(bp->panic))
377762306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
377862306a36Sopenharmony_ci#endif
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci	txq_index = skb_get_queue_mapping(skb);
378162306a36Sopenharmony_ci	txq = netdev_get_tx_queue(dev, txq_index);
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ci	BUG_ON(txq_index >= MAX_ETH_TXQ_IDX(bp) + (CNIC_LOADED(bp) ? 1 : 0));
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci	txdata = &bp->bnx2x_txq[txq_index];
378662306a36Sopenharmony_ci
378762306a36Sopenharmony_ci	/* enable this debug print to view the transmission queue being used
378862306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED, "indices: txq %d, fp %d, txdata %d\n",
378962306a36Sopenharmony_ci	   txq_index, fp_index, txdata_index); */
379062306a36Sopenharmony_ci
379162306a36Sopenharmony_ci	/* enable this debug print to view the transmission details
379262306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED,
379362306a36Sopenharmony_ci	   "transmitting packet cid %d fp index %d txdata_index %d tx_data ptr %p fp pointer %p\n",
379462306a36Sopenharmony_ci	   txdata->cid, fp_index, txdata_index, txdata, fp); */
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci	if (unlikely(bnx2x_tx_avail(bp, txdata) <
379762306a36Sopenharmony_ci			skb_shinfo(skb)->nr_frags +
379862306a36Sopenharmony_ci			BDS_PER_TX_PKT +
379962306a36Sopenharmony_ci			NEXT_CNT_PER_TX_PKT(MAX_BDS_PER_TX_PKT))) {
380062306a36Sopenharmony_ci		/* Handle special storage cases separately */
380162306a36Sopenharmony_ci		if (txdata->tx_ring_size == 0) {
380262306a36Sopenharmony_ci			struct bnx2x_eth_q_stats *q_stats =
380362306a36Sopenharmony_ci				bnx2x_fp_qstats(bp, txdata->parent_fp);
380462306a36Sopenharmony_ci			q_stats->driver_filtered_tx_pkt++;
380562306a36Sopenharmony_ci			dev_kfree_skb(skb);
380662306a36Sopenharmony_ci			return NETDEV_TX_OK;
380762306a36Sopenharmony_ci		}
380862306a36Sopenharmony_ci		bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
380962306a36Sopenharmony_ci		netif_tx_stop_queue(txq);
381062306a36Sopenharmony_ci		BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
381362306a36Sopenharmony_ci	}
381462306a36Sopenharmony_ci
381562306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED,
381662306a36Sopenharmony_ci	   "queue[%d]: SKB: summed %x  protocol %x protocol(%x,%x) gso type %x  xmit_type %x len %d\n",
381762306a36Sopenharmony_ci	   txq_index, skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
381862306a36Sopenharmony_ci	   ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type,
381962306a36Sopenharmony_ci	   skb->len);
382062306a36Sopenharmony_ci
382162306a36Sopenharmony_ci	eth = (struct ethhdr *)skb->data;
382262306a36Sopenharmony_ci
382362306a36Sopenharmony_ci	/* set flag according to packet type (UNICAST_ADDRESS is default)*/
382462306a36Sopenharmony_ci	if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
382562306a36Sopenharmony_ci		if (is_broadcast_ether_addr(eth->h_dest))
382662306a36Sopenharmony_ci			mac_type = BROADCAST_ADDRESS;
382762306a36Sopenharmony_ci		else
382862306a36Sopenharmony_ci			mac_type = MULTICAST_ADDRESS;
382962306a36Sopenharmony_ci	}
383062306a36Sopenharmony_ci
383162306a36Sopenharmony_ci#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - BDS_PER_TX_PKT)
383262306a36Sopenharmony_ci	/* First, check if we need to linearize the skb (due to FW
383362306a36Sopenharmony_ci	   restrictions). No need to check fragmentation if page size > 8K
383462306a36Sopenharmony_ci	   (there will be no violation to FW restrictions) */
383562306a36Sopenharmony_ci	if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) {
383662306a36Sopenharmony_ci		/* Statistics of linearization */
383762306a36Sopenharmony_ci		bp->lin_cnt++;
383862306a36Sopenharmony_ci		if (skb_linearize(skb) != 0) {
383962306a36Sopenharmony_ci			DP(NETIF_MSG_TX_QUEUED,
384062306a36Sopenharmony_ci			   "SKB linearization failed - silently dropping this SKB\n");
384162306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
384262306a36Sopenharmony_ci			return NETDEV_TX_OK;
384362306a36Sopenharmony_ci		}
384462306a36Sopenharmony_ci	}
384562306a36Sopenharmony_ci#endif
384662306a36Sopenharmony_ci	/* Map skb linear data for DMA */
384762306a36Sopenharmony_ci	mapping = dma_map_single(&bp->pdev->dev, skb->data,
384862306a36Sopenharmony_ci				 skb_headlen(skb), DMA_TO_DEVICE);
384962306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
385062306a36Sopenharmony_ci		DP(NETIF_MSG_TX_QUEUED,
385162306a36Sopenharmony_ci		   "SKB mapping failed - silently dropping this SKB\n");
385262306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
385362306a36Sopenharmony_ci		return NETDEV_TX_OK;
385462306a36Sopenharmony_ci	}
385562306a36Sopenharmony_ci	/*
385662306a36Sopenharmony_ci	Please read carefully. First we use one BD which we mark as start,
385762306a36Sopenharmony_ci	then we have a parsing info BD (used for TSO or xsum),
385862306a36Sopenharmony_ci	and only then we have the rest of the TSO BDs.
385962306a36Sopenharmony_ci	(don't forget to mark the last one as last,
386062306a36Sopenharmony_ci	and to unmap only AFTER you write to the BD ...)
386162306a36Sopenharmony_ci	And above all, all pdb sizes are in words - NOT DWORDS!
386262306a36Sopenharmony_ci	*/
386362306a36Sopenharmony_ci
386462306a36Sopenharmony_ci	/* get current pkt produced now - advance it just before sending packet
386562306a36Sopenharmony_ci	 * since mapping of pages may fail and cause packet to be dropped
386662306a36Sopenharmony_ci	 */
386762306a36Sopenharmony_ci	pkt_prod = txdata->tx_pkt_prod;
386862306a36Sopenharmony_ci	bd_prod = TX_BD(txdata->tx_bd_prod);
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci	/* get a tx_buf and first BD
387162306a36Sopenharmony_ci	 * tx_start_bd may be changed during SPLIT,
387262306a36Sopenharmony_ci	 * but first_bd will always stay first
387362306a36Sopenharmony_ci	 */
387462306a36Sopenharmony_ci	tx_buf = &txdata->tx_buf_ring[TX_BD(pkt_prod)];
387562306a36Sopenharmony_ci	tx_start_bd = &txdata->tx_desc_ring[bd_prod].start_bd;
387662306a36Sopenharmony_ci	first_bd = tx_start_bd;
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci	tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ci	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
388162306a36Sopenharmony_ci		if (!(bp->flags & TX_TIMESTAMPING_EN)) {
388262306a36Sopenharmony_ci			bp->eth_stats.ptp_skip_tx_ts++;
388362306a36Sopenharmony_ci			BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n");
388462306a36Sopenharmony_ci		} else if (bp->ptp_tx_skb) {
388562306a36Sopenharmony_ci			bp->eth_stats.ptp_skip_tx_ts++;
388662306a36Sopenharmony_ci			netdev_err_once(bp->dev,
388762306a36Sopenharmony_ci					"Device supports only a single outstanding packet to timestamp, this packet won't be timestamped\n");
388862306a36Sopenharmony_ci		} else {
388962306a36Sopenharmony_ci			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
389062306a36Sopenharmony_ci			/* schedule check for Tx timestamp */
389162306a36Sopenharmony_ci			bp->ptp_tx_skb = skb_get(skb);
389262306a36Sopenharmony_ci			bp->ptp_tx_start = jiffies;
389362306a36Sopenharmony_ci			schedule_work(&bp->ptp_task);
389462306a36Sopenharmony_ci		}
389562306a36Sopenharmony_ci	}
389662306a36Sopenharmony_ci
389762306a36Sopenharmony_ci	/* header nbd: indirectly zero other flags! */
389862306a36Sopenharmony_ci	tx_start_bd->general_data = 1 << ETH_TX_START_BD_HDR_NBDS_SHIFT;
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_ci	/* remember the first BD of the packet */
390162306a36Sopenharmony_ci	tx_buf->first_bd = txdata->tx_bd_prod;
390262306a36Sopenharmony_ci	tx_buf->skb = skb;
390362306a36Sopenharmony_ci	tx_buf->flags = 0;
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED,
390662306a36Sopenharmony_ci	   "sending pkt %u @%p  next_idx %u  bd %u @%p\n",
390762306a36Sopenharmony_ci	   pkt_prod, tx_buf, txdata->tx_pkt_prod, bd_prod, tx_start_bd);
390862306a36Sopenharmony_ci
390962306a36Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
391062306a36Sopenharmony_ci		tx_start_bd->vlan_or_ethertype =
391162306a36Sopenharmony_ci		    cpu_to_le16(skb_vlan_tag_get(skb));
391262306a36Sopenharmony_ci		tx_start_bd->bd_flags.as_bitfield |=
391362306a36Sopenharmony_ci		    (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
391462306a36Sopenharmony_ci	} else {
391562306a36Sopenharmony_ci		/* when transmitting in a vf, start bd must hold the ethertype
391662306a36Sopenharmony_ci		 * for fw to enforce it
391762306a36Sopenharmony_ci		 */
391862306a36Sopenharmony_ci		u16 vlan_tci = 0;
391962306a36Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR
392062306a36Sopenharmony_ci		if (IS_VF(bp)) {
392162306a36Sopenharmony_ci#endif
392262306a36Sopenharmony_ci			/* Still need to consider inband vlan for enforced */
392362306a36Sopenharmony_ci			if (__vlan_get_tag(skb, &vlan_tci)) {
392462306a36Sopenharmony_ci				tx_start_bd->vlan_or_ethertype =
392562306a36Sopenharmony_ci					cpu_to_le16(ntohs(eth->h_proto));
392662306a36Sopenharmony_ci			} else {
392762306a36Sopenharmony_ci				tx_start_bd->bd_flags.as_bitfield |=
392862306a36Sopenharmony_ci					(X_ETH_INBAND_VLAN <<
392962306a36Sopenharmony_ci					 ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
393062306a36Sopenharmony_ci				tx_start_bd->vlan_or_ethertype =
393162306a36Sopenharmony_ci					cpu_to_le16(vlan_tci);
393262306a36Sopenharmony_ci			}
393362306a36Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR
393462306a36Sopenharmony_ci		} else {
393562306a36Sopenharmony_ci			/* used by FW for packet accounting */
393662306a36Sopenharmony_ci			tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
393762306a36Sopenharmony_ci		}
393862306a36Sopenharmony_ci#endif
393962306a36Sopenharmony_ci	}
394062306a36Sopenharmony_ci
394162306a36Sopenharmony_ci	nbd = 2; /* start_bd + pbd + frags (updated when pages are mapped) */
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci	/* turn on parsing and get a BD */
394462306a36Sopenharmony_ci	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
394562306a36Sopenharmony_ci
394662306a36Sopenharmony_ci	if (xmit_type & XMIT_CSUM)
394762306a36Sopenharmony_ci		bnx2x_set_sbd_csum(bp, skb, tx_start_bd, xmit_type);
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci	if (!CHIP_IS_E1x(bp)) {
395062306a36Sopenharmony_ci		pbd_e2 = &txdata->tx_desc_ring[bd_prod].parse_bd_e2;
395162306a36Sopenharmony_ci		memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
395262306a36Sopenharmony_ci
395362306a36Sopenharmony_ci		if (xmit_type & XMIT_CSUM_ENC) {
395462306a36Sopenharmony_ci			u16 global_data = 0;
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci			/* Set PBD in enc checksum offload case */
395762306a36Sopenharmony_ci			hlen = bnx2x_set_pbd_csum_enc(bp, skb,
395862306a36Sopenharmony_ci						      &pbd_e2_parsing_data,
395962306a36Sopenharmony_ci						      xmit_type);
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci			/* turn on 2nd parsing and get a BD */
396262306a36Sopenharmony_ci			bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
396362306a36Sopenharmony_ci
396462306a36Sopenharmony_ci			pbd2 = &txdata->tx_desc_ring[bd_prod].parse_2nd_bd;
396562306a36Sopenharmony_ci
396662306a36Sopenharmony_ci			memset(pbd2, 0, sizeof(*pbd2));
396762306a36Sopenharmony_ci
396862306a36Sopenharmony_ci			pbd_e2->data.tunnel_data.ip_hdr_start_inner_w =
396962306a36Sopenharmony_ci				(skb_inner_network_header(skb) -
397062306a36Sopenharmony_ci				 skb->data) >> 1;
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_ci			if (xmit_type & XMIT_GSO_ENC)
397362306a36Sopenharmony_ci				bnx2x_update_pbds_gso_enc(skb, pbd_e2, pbd2,
397462306a36Sopenharmony_ci							  &global_data,
397562306a36Sopenharmony_ci							  xmit_type);
397662306a36Sopenharmony_ci
397762306a36Sopenharmony_ci			pbd2->global_data = cpu_to_le16(global_data);
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci			/* add addition parse BD indication to start BD */
398062306a36Sopenharmony_ci			SET_FLAG(tx_start_bd->general_data,
398162306a36Sopenharmony_ci				 ETH_TX_START_BD_PARSE_NBDS, 1);
398262306a36Sopenharmony_ci			/* set encapsulation flag in start BD */
398362306a36Sopenharmony_ci			SET_FLAG(tx_start_bd->general_data,
398462306a36Sopenharmony_ci				 ETH_TX_START_BD_TUNNEL_EXIST, 1);
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci			tx_buf->flags |= BNX2X_HAS_SECOND_PBD;
398762306a36Sopenharmony_ci
398862306a36Sopenharmony_ci			nbd++;
398962306a36Sopenharmony_ci		} else if (xmit_type & XMIT_CSUM) {
399062306a36Sopenharmony_ci			/* Set PBD in checksum offload case w/o encapsulation */
399162306a36Sopenharmony_ci			hlen = bnx2x_set_pbd_csum_e2(bp, skb,
399262306a36Sopenharmony_ci						     &pbd_e2_parsing_data,
399362306a36Sopenharmony_ci						     xmit_type);
399462306a36Sopenharmony_ci		}
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci		bnx2x_set_ipv6_ext_e2(skb, &pbd_e2_parsing_data, xmit_type);
399762306a36Sopenharmony_ci		/* Add the macs to the parsing BD if this is a vf or if
399862306a36Sopenharmony_ci		 * Tx Switching is enabled.
399962306a36Sopenharmony_ci		 */
400062306a36Sopenharmony_ci		if (IS_VF(bp)) {
400162306a36Sopenharmony_ci			/* override GRE parameters in BD */
400262306a36Sopenharmony_ci			bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
400362306a36Sopenharmony_ci					      &pbd_e2->data.mac_addr.src_mid,
400462306a36Sopenharmony_ci					      &pbd_e2->data.mac_addr.src_lo,
400562306a36Sopenharmony_ci					      eth->h_source);
400662306a36Sopenharmony_ci
400762306a36Sopenharmony_ci			bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
400862306a36Sopenharmony_ci					      &pbd_e2->data.mac_addr.dst_mid,
400962306a36Sopenharmony_ci					      &pbd_e2->data.mac_addr.dst_lo,
401062306a36Sopenharmony_ci					      eth->h_dest);
401162306a36Sopenharmony_ci		} else {
401262306a36Sopenharmony_ci			if (bp->flags & TX_SWITCHING)
401362306a36Sopenharmony_ci				bnx2x_set_fw_mac_addr(
401462306a36Sopenharmony_ci						&pbd_e2->data.mac_addr.dst_hi,
401562306a36Sopenharmony_ci						&pbd_e2->data.mac_addr.dst_mid,
401662306a36Sopenharmony_ci						&pbd_e2->data.mac_addr.dst_lo,
401762306a36Sopenharmony_ci						eth->h_dest);
401862306a36Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR
401962306a36Sopenharmony_ci			/* Enforce security is always set in Stop on Error -
402062306a36Sopenharmony_ci			 * source mac should be present in the parsing BD
402162306a36Sopenharmony_ci			 */
402262306a36Sopenharmony_ci			bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
402362306a36Sopenharmony_ci					      &pbd_e2->data.mac_addr.src_mid,
402462306a36Sopenharmony_ci					      &pbd_e2->data.mac_addr.src_lo,
402562306a36Sopenharmony_ci					      eth->h_source);
402662306a36Sopenharmony_ci#endif
402762306a36Sopenharmony_ci		}
402862306a36Sopenharmony_ci
402962306a36Sopenharmony_ci		SET_FLAG(pbd_e2_parsing_data,
403062306a36Sopenharmony_ci			 ETH_TX_PARSE_BD_E2_ETH_ADDR_TYPE, mac_type);
403162306a36Sopenharmony_ci	} else {
403262306a36Sopenharmony_ci		u16 global_data = 0;
403362306a36Sopenharmony_ci		pbd_e1x = &txdata->tx_desc_ring[bd_prod].parse_bd_e1x;
403462306a36Sopenharmony_ci		memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
403562306a36Sopenharmony_ci		/* Set PBD in checksum offload case */
403662306a36Sopenharmony_ci		if (xmit_type & XMIT_CSUM)
403762306a36Sopenharmony_ci			hlen = bnx2x_set_pbd_csum(bp, skb, pbd_e1x, xmit_type);
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci		SET_FLAG(global_data,
404062306a36Sopenharmony_ci			 ETH_TX_PARSE_BD_E1X_ETH_ADDR_TYPE, mac_type);
404162306a36Sopenharmony_ci		pbd_e1x->global_data |= cpu_to_le16(global_data);
404262306a36Sopenharmony_ci	}
404362306a36Sopenharmony_ci
404462306a36Sopenharmony_ci	/* Setup the data pointer of the first BD of the packet */
404562306a36Sopenharmony_ci	tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
404662306a36Sopenharmony_ci	tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
404762306a36Sopenharmony_ci	tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
404862306a36Sopenharmony_ci	pkt_size = tx_start_bd->nbytes;
404962306a36Sopenharmony_ci
405062306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED,
405162306a36Sopenharmony_ci	   "first bd @%p  addr (%x:%x)  nbytes %d  flags %x  vlan %x\n",
405262306a36Sopenharmony_ci	   tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo,
405362306a36Sopenharmony_ci	   le16_to_cpu(tx_start_bd->nbytes),
405462306a36Sopenharmony_ci	   tx_start_bd->bd_flags.as_bitfield,
405562306a36Sopenharmony_ci	   le16_to_cpu(tx_start_bd->vlan_or_ethertype));
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	if (xmit_type & XMIT_GSO) {
405862306a36Sopenharmony_ci
405962306a36Sopenharmony_ci		DP(NETIF_MSG_TX_QUEUED,
406062306a36Sopenharmony_ci		   "TSO packet len %d  hlen %d  total len %d  tso size %d\n",
406162306a36Sopenharmony_ci		   skb->len, hlen, skb_headlen(skb),
406262306a36Sopenharmony_ci		   skb_shinfo(skb)->gso_size);
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci		tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
406562306a36Sopenharmony_ci
406662306a36Sopenharmony_ci		if (unlikely(skb_headlen(skb) > hlen)) {
406762306a36Sopenharmony_ci			nbd++;
406862306a36Sopenharmony_ci			bd_prod = bnx2x_tx_split(bp, txdata, tx_buf,
406962306a36Sopenharmony_ci						 &tx_start_bd, hlen,
407062306a36Sopenharmony_ci						 bd_prod);
407162306a36Sopenharmony_ci		}
407262306a36Sopenharmony_ci		if (!CHIP_IS_E1x(bp))
407362306a36Sopenharmony_ci			pbd_e2_parsing_data |=
407462306a36Sopenharmony_ci				(skb_shinfo(skb)->gso_size <<
407562306a36Sopenharmony_ci				 ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
407662306a36Sopenharmony_ci				 ETH_TX_PARSE_BD_E2_LSO_MSS;
407762306a36Sopenharmony_ci		else
407862306a36Sopenharmony_ci			bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
407962306a36Sopenharmony_ci	}
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_ci	/* Set the PBD's parsing_data field if not zero
408262306a36Sopenharmony_ci	 * (for the chips newer than 57711).
408362306a36Sopenharmony_ci	 */
408462306a36Sopenharmony_ci	if (pbd_e2_parsing_data)
408562306a36Sopenharmony_ci		pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data);
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_ci	tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
408862306a36Sopenharmony_ci
408962306a36Sopenharmony_ci	/* Handle fragmented skb */
409062306a36Sopenharmony_ci	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
409162306a36Sopenharmony_ci		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_ci		mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0,
409462306a36Sopenharmony_ci					   skb_frag_size(frag), DMA_TO_DEVICE);
409562306a36Sopenharmony_ci		if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
409662306a36Sopenharmony_ci			unsigned int pkts_compl = 0, bytes_compl = 0;
409762306a36Sopenharmony_ci
409862306a36Sopenharmony_ci			DP(NETIF_MSG_TX_QUEUED,
409962306a36Sopenharmony_ci			   "Unable to map page - dropping packet...\n");
410062306a36Sopenharmony_ci
410162306a36Sopenharmony_ci			/* we need unmap all buffers already mapped
410262306a36Sopenharmony_ci			 * for this SKB;
410362306a36Sopenharmony_ci			 * first_bd->nbd need to be properly updated
410462306a36Sopenharmony_ci			 * before call to bnx2x_free_tx_pkt
410562306a36Sopenharmony_ci			 */
410662306a36Sopenharmony_ci			first_bd->nbd = cpu_to_le16(nbd);
410762306a36Sopenharmony_ci			bnx2x_free_tx_pkt(bp, txdata,
410862306a36Sopenharmony_ci					  TX_BD(txdata->tx_pkt_prod),
410962306a36Sopenharmony_ci					  &pkts_compl, &bytes_compl);
411062306a36Sopenharmony_ci			return NETDEV_TX_OK;
411162306a36Sopenharmony_ci		}
411262306a36Sopenharmony_ci
411362306a36Sopenharmony_ci		bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
411462306a36Sopenharmony_ci		tx_data_bd = &txdata->tx_desc_ring[bd_prod].reg_bd;
411562306a36Sopenharmony_ci		if (total_pkt_bd == NULL)
411662306a36Sopenharmony_ci			total_pkt_bd = &txdata->tx_desc_ring[bd_prod].reg_bd;
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_ci		tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
411962306a36Sopenharmony_ci		tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
412062306a36Sopenharmony_ci		tx_data_bd->nbytes = cpu_to_le16(skb_frag_size(frag));
412162306a36Sopenharmony_ci		le16_add_cpu(&pkt_size, skb_frag_size(frag));
412262306a36Sopenharmony_ci		nbd++;
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci		DP(NETIF_MSG_TX_QUEUED,
412562306a36Sopenharmony_ci		   "frag %d  bd @%p  addr (%x:%x)  nbytes %d\n",
412662306a36Sopenharmony_ci		   i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo,
412762306a36Sopenharmony_ci		   le16_to_cpu(tx_data_bd->nbytes));
412862306a36Sopenharmony_ci	}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd);
413162306a36Sopenharmony_ci
413262306a36Sopenharmony_ci	/* update with actual num BDs */
413362306a36Sopenharmony_ci	first_bd->nbd = cpu_to_le16(nbd);
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci	/* now send a tx doorbell, counting the next BD
413862306a36Sopenharmony_ci	 * if the packet contains or ends with it
413962306a36Sopenharmony_ci	 */
414062306a36Sopenharmony_ci	if (TX_BD_POFF(bd_prod) < nbd)
414162306a36Sopenharmony_ci		nbd++;
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci	/* total_pkt_bytes should be set on the first data BD if
414462306a36Sopenharmony_ci	 * it's not an LSO packet and there is more than one
414562306a36Sopenharmony_ci	 * data BD. In this case pkt_size is limited by an MTU value.
414662306a36Sopenharmony_ci	 * However we prefer to set it for an LSO packet (while we don't
414762306a36Sopenharmony_ci	 * have to) in order to save some CPU cycles in a none-LSO
414862306a36Sopenharmony_ci	 * case, when we much more care about them.
414962306a36Sopenharmony_ci	 */
415062306a36Sopenharmony_ci	if (total_pkt_bd != NULL)
415162306a36Sopenharmony_ci		total_pkt_bd->total_pkt_bytes = pkt_size;
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci	if (pbd_e1x)
415462306a36Sopenharmony_ci		DP(NETIF_MSG_TX_QUEUED,
415562306a36Sopenharmony_ci		   "PBD (E1X) @%p  ip_data %x  ip_hlen %u  ip_id %u  lso_mss %u  tcp_flags %x  xsum %x  seq %u  hlen %u\n",
415662306a36Sopenharmony_ci		   pbd_e1x, pbd_e1x->global_data, pbd_e1x->ip_hlen_w,
415762306a36Sopenharmony_ci		   pbd_e1x->ip_id, pbd_e1x->lso_mss, pbd_e1x->tcp_flags,
415862306a36Sopenharmony_ci		   pbd_e1x->tcp_pseudo_csum, pbd_e1x->tcp_send_seq,
415962306a36Sopenharmony_ci		    le16_to_cpu(pbd_e1x->total_hlen_w));
416062306a36Sopenharmony_ci	if (pbd_e2)
416162306a36Sopenharmony_ci		DP(NETIF_MSG_TX_QUEUED,
416262306a36Sopenharmony_ci		   "PBD (E2) @%p  dst %x %x %x src %x %x %x parsing_data %x\n",
416362306a36Sopenharmony_ci		   pbd_e2,
416462306a36Sopenharmony_ci		   pbd_e2->data.mac_addr.dst_hi,
416562306a36Sopenharmony_ci		   pbd_e2->data.mac_addr.dst_mid,
416662306a36Sopenharmony_ci		   pbd_e2->data.mac_addr.dst_lo,
416762306a36Sopenharmony_ci		   pbd_e2->data.mac_addr.src_hi,
416862306a36Sopenharmony_ci		   pbd_e2->data.mac_addr.src_mid,
416962306a36Sopenharmony_ci		   pbd_e2->data.mac_addr.src_lo,
417062306a36Sopenharmony_ci		   pbd_e2->parsing_data);
417162306a36Sopenharmony_ci	DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d  bd %u\n", nbd, bd_prod);
417262306a36Sopenharmony_ci
417362306a36Sopenharmony_ci	netdev_tx_sent_queue(txq, skb->len);
417462306a36Sopenharmony_ci
417562306a36Sopenharmony_ci	skb_tx_timestamp(skb);
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_ci	txdata->tx_pkt_prod++;
417862306a36Sopenharmony_ci	/*
417962306a36Sopenharmony_ci	 * Make sure that the BD data is updated before updating the producer
418062306a36Sopenharmony_ci	 * since FW might read the BD right after the producer is updated.
418162306a36Sopenharmony_ci	 * This is only applicable for weak-ordered memory model archs such
418262306a36Sopenharmony_ci	 * as IA-64. The following barrier is also mandatory since FW will
418362306a36Sopenharmony_ci	 * assumes packets must have BDs.
418462306a36Sopenharmony_ci	 */
418562306a36Sopenharmony_ci	wmb();
418662306a36Sopenharmony_ci
418762306a36Sopenharmony_ci	txdata->tx_db.data.prod += nbd;
418862306a36Sopenharmony_ci	/* make sure descriptor update is observed by HW */
418962306a36Sopenharmony_ci	wmb();
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_ci	DOORBELL_RELAXED(bp, txdata->cid, txdata->tx_db.raw);
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	txdata->tx_bd_prod += nbd;
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci	if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_DESC_PER_TX_PKT)) {
419662306a36Sopenharmony_ci		netif_tx_stop_queue(txq);
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ci		/* paired memory barrier is in bnx2x_tx_int(), we have to keep
419962306a36Sopenharmony_ci		 * ordering of set_bit() in netif_tx_stop_queue() and read of
420062306a36Sopenharmony_ci		 * fp->bd_tx_cons */
420162306a36Sopenharmony_ci		smp_mb();
420262306a36Sopenharmony_ci
420362306a36Sopenharmony_ci		bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
420462306a36Sopenharmony_ci		if (bnx2x_tx_avail(bp, txdata) >= MAX_DESC_PER_TX_PKT)
420562306a36Sopenharmony_ci			netif_tx_wake_queue(txq);
420662306a36Sopenharmony_ci	}
420762306a36Sopenharmony_ci	txdata->tx_pkt++;
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	return NETDEV_TX_OK;
421062306a36Sopenharmony_ci}
421162306a36Sopenharmony_ci
421262306a36Sopenharmony_civoid bnx2x_get_c2s_mapping(struct bnx2x *bp, u8 *c2s_map, u8 *c2s_default)
421362306a36Sopenharmony_ci{
421462306a36Sopenharmony_ci	int mfw_vn = BP_FW_MB_IDX(bp);
421562306a36Sopenharmony_ci	u32 tmp;
421662306a36Sopenharmony_ci
421762306a36Sopenharmony_ci	/* If the shmem shouldn't affect configuration, reflect */
421862306a36Sopenharmony_ci	if (!IS_MF_BD(bp)) {
421962306a36Sopenharmony_ci		int i;
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci		for (i = 0; i < BNX2X_MAX_PRIORITY; i++)
422262306a36Sopenharmony_ci			c2s_map[i] = i;
422362306a36Sopenharmony_ci		*c2s_default = 0;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci		return;
422662306a36Sopenharmony_ci	}
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_ci	tmp = SHMEM2_RD(bp, c2s_pcp_map_lower[mfw_vn]);
422962306a36Sopenharmony_ci	tmp = (__force u32)be32_to_cpu((__force __be32)tmp);
423062306a36Sopenharmony_ci	c2s_map[0] = tmp & 0xff;
423162306a36Sopenharmony_ci	c2s_map[1] = (tmp >> 8) & 0xff;
423262306a36Sopenharmony_ci	c2s_map[2] = (tmp >> 16) & 0xff;
423362306a36Sopenharmony_ci	c2s_map[3] = (tmp >> 24) & 0xff;
423462306a36Sopenharmony_ci
423562306a36Sopenharmony_ci	tmp = SHMEM2_RD(bp, c2s_pcp_map_upper[mfw_vn]);
423662306a36Sopenharmony_ci	tmp = (__force u32)be32_to_cpu((__force __be32)tmp);
423762306a36Sopenharmony_ci	c2s_map[4] = tmp & 0xff;
423862306a36Sopenharmony_ci	c2s_map[5] = (tmp >> 8) & 0xff;
423962306a36Sopenharmony_ci	c2s_map[6] = (tmp >> 16) & 0xff;
424062306a36Sopenharmony_ci	c2s_map[7] = (tmp >> 24) & 0xff;
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	tmp = SHMEM2_RD(bp, c2s_pcp_map_default[mfw_vn]);
424362306a36Sopenharmony_ci	tmp = (__force u32)be32_to_cpu((__force __be32)tmp);
424462306a36Sopenharmony_ci	*c2s_default = (tmp >> (8 * mfw_vn)) & 0xff;
424562306a36Sopenharmony_ci}
424662306a36Sopenharmony_ci
424762306a36Sopenharmony_ci/**
424862306a36Sopenharmony_ci * bnx2x_setup_tc - routine to configure net_device for multi tc
424962306a36Sopenharmony_ci *
425062306a36Sopenharmony_ci * @dev: net device to configure
425162306a36Sopenharmony_ci * @num_tc: number of traffic classes to enable
425262306a36Sopenharmony_ci *
425362306a36Sopenharmony_ci * callback connected to the ndo_setup_tc function pointer
425462306a36Sopenharmony_ci */
425562306a36Sopenharmony_ciint bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
425662306a36Sopenharmony_ci{
425762306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
425862306a36Sopenharmony_ci	u8 c2s_map[BNX2X_MAX_PRIORITY], c2s_def;
425962306a36Sopenharmony_ci	int cos, prio, count, offset;
426062306a36Sopenharmony_ci
426162306a36Sopenharmony_ci	/* setup tc must be called under rtnl lock */
426262306a36Sopenharmony_ci	ASSERT_RTNL();
426362306a36Sopenharmony_ci
426462306a36Sopenharmony_ci	/* no traffic classes requested. Aborting */
426562306a36Sopenharmony_ci	if (!num_tc) {
426662306a36Sopenharmony_ci		netdev_reset_tc(dev);
426762306a36Sopenharmony_ci		return 0;
426862306a36Sopenharmony_ci	}
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_ci	/* requested to support too many traffic classes */
427162306a36Sopenharmony_ci	if (num_tc > bp->max_cos) {
427262306a36Sopenharmony_ci		BNX2X_ERR("support for too many traffic classes requested: %d. Max supported is %d\n",
427362306a36Sopenharmony_ci			  num_tc, bp->max_cos);
427462306a36Sopenharmony_ci		return -EINVAL;
427562306a36Sopenharmony_ci	}
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	/* declare amount of supported traffic classes */
427862306a36Sopenharmony_ci	if (netdev_set_num_tc(dev, num_tc)) {
427962306a36Sopenharmony_ci		BNX2X_ERR("failed to declare %d traffic classes\n", num_tc);
428062306a36Sopenharmony_ci		return -EINVAL;
428162306a36Sopenharmony_ci	}
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	bnx2x_get_c2s_mapping(bp, c2s_map, &c2s_def);
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci	/* configure priority to traffic class mapping */
428662306a36Sopenharmony_ci	for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) {
428762306a36Sopenharmony_ci		int outer_prio = c2s_map[prio];
428862306a36Sopenharmony_ci
428962306a36Sopenharmony_ci		netdev_set_prio_tc_map(dev, prio, bp->prio_to_cos[outer_prio]);
429062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP | NETIF_MSG_IFUP,
429162306a36Sopenharmony_ci		   "mapping priority %d to tc %d\n",
429262306a36Sopenharmony_ci		   outer_prio, bp->prio_to_cos[outer_prio]);
429362306a36Sopenharmony_ci	}
429462306a36Sopenharmony_ci
429562306a36Sopenharmony_ci	/* Use this configuration to differentiate tc0 from other COSes
429662306a36Sopenharmony_ci	   This can be used for ets or pfc, and save the effort of setting
429762306a36Sopenharmony_ci	   up a multio class queue disc or negotiating DCBX with a switch
429862306a36Sopenharmony_ci	netdev_set_prio_tc_map(dev, 0, 0);
429962306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "mapping priority %d to tc %d\n", 0, 0);
430062306a36Sopenharmony_ci	for (prio = 1; prio < 16; prio++) {
430162306a36Sopenharmony_ci		netdev_set_prio_tc_map(dev, prio, 1);
430262306a36Sopenharmony_ci		DP(BNX2X_MSG_SP, "mapping priority %d to tc %d\n", prio, 1);
430362306a36Sopenharmony_ci	} */
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	/* configure traffic class to transmission queue mapping */
430662306a36Sopenharmony_ci	for (cos = 0; cos < bp->max_cos; cos++) {
430762306a36Sopenharmony_ci		count = BNX2X_NUM_ETH_QUEUES(bp);
430862306a36Sopenharmony_ci		offset = cos * BNX2X_NUM_NON_CNIC_QUEUES(bp);
430962306a36Sopenharmony_ci		netdev_set_tc_queue(dev, cos, count, offset);
431062306a36Sopenharmony_ci		DP(BNX2X_MSG_SP | NETIF_MSG_IFUP,
431162306a36Sopenharmony_ci		   "mapping tc %d to offset %d count %d\n",
431262306a36Sopenharmony_ci		   cos, offset, count);
431362306a36Sopenharmony_ci	}
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_ci	return 0;
431662306a36Sopenharmony_ci}
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ciint __bnx2x_setup_tc(struct net_device *dev, enum tc_setup_type type,
431962306a36Sopenharmony_ci		     void *type_data)
432062306a36Sopenharmony_ci{
432162306a36Sopenharmony_ci	struct tc_mqprio_qopt *mqprio = type_data;
432262306a36Sopenharmony_ci
432362306a36Sopenharmony_ci	if (type != TC_SETUP_QDISC_MQPRIO)
432462306a36Sopenharmony_ci		return -EOPNOTSUPP;
432562306a36Sopenharmony_ci
432662306a36Sopenharmony_ci	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
432762306a36Sopenharmony_ci
432862306a36Sopenharmony_ci	return bnx2x_setup_tc(dev, mqprio->num_tc);
432962306a36Sopenharmony_ci}
433062306a36Sopenharmony_ci
433162306a36Sopenharmony_ci/* called with rtnl_lock */
433262306a36Sopenharmony_ciint bnx2x_change_mac_addr(struct net_device *dev, void *p)
433362306a36Sopenharmony_ci{
433462306a36Sopenharmony_ci	struct sockaddr *addr = p;
433562306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
433662306a36Sopenharmony_ci	int rc = 0;
433762306a36Sopenharmony_ci
433862306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data)) {
433962306a36Sopenharmony_ci		BNX2X_ERR("Requested MAC address is not valid\n");
434062306a36Sopenharmony_ci		return -EINVAL;
434162306a36Sopenharmony_ci	}
434262306a36Sopenharmony_ci
434362306a36Sopenharmony_ci	if (IS_MF_STORAGE_ONLY(bp)) {
434462306a36Sopenharmony_ci		BNX2X_ERR("Can't change address on STORAGE ONLY function\n");
434562306a36Sopenharmony_ci		return -EINVAL;
434662306a36Sopenharmony_ci	}
434762306a36Sopenharmony_ci
434862306a36Sopenharmony_ci	if (netif_running(dev))  {
434962306a36Sopenharmony_ci		rc = bnx2x_set_eth_mac(bp, false);
435062306a36Sopenharmony_ci		if (rc)
435162306a36Sopenharmony_ci			return rc;
435262306a36Sopenharmony_ci	}
435362306a36Sopenharmony_ci
435462306a36Sopenharmony_ci	eth_hw_addr_set(dev, addr->sa_data);
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci	if (netif_running(dev))
435762306a36Sopenharmony_ci		rc = bnx2x_set_eth_mac(bp, true);
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci	if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg))
436062306a36Sopenharmony_ci		SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS);
436162306a36Sopenharmony_ci
436262306a36Sopenharmony_ci	return rc;
436362306a36Sopenharmony_ci}
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_cistatic void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index)
436662306a36Sopenharmony_ci{
436762306a36Sopenharmony_ci	union host_hc_status_block *sb = &bnx2x_fp(bp, fp_index, status_blk);
436862306a36Sopenharmony_ci	struct bnx2x_fastpath *fp = &bp->fp[fp_index];
436962306a36Sopenharmony_ci	u8 cos;
437062306a36Sopenharmony_ci
437162306a36Sopenharmony_ci	/* Common */
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	if (IS_FCOE_IDX(fp_index)) {
437462306a36Sopenharmony_ci		memset(sb, 0, sizeof(union host_hc_status_block));
437562306a36Sopenharmony_ci		fp->status_blk_mapping = 0;
437662306a36Sopenharmony_ci	} else {
437762306a36Sopenharmony_ci		/* status blocks */
437862306a36Sopenharmony_ci		if (!CHIP_IS_E1x(bp))
437962306a36Sopenharmony_ci			BNX2X_PCI_FREE(sb->e2_sb,
438062306a36Sopenharmony_ci				       bnx2x_fp(bp, fp_index,
438162306a36Sopenharmony_ci						status_blk_mapping),
438262306a36Sopenharmony_ci				       sizeof(struct host_hc_status_block_e2));
438362306a36Sopenharmony_ci		else
438462306a36Sopenharmony_ci			BNX2X_PCI_FREE(sb->e1x_sb,
438562306a36Sopenharmony_ci				       bnx2x_fp(bp, fp_index,
438662306a36Sopenharmony_ci						status_blk_mapping),
438762306a36Sopenharmony_ci				       sizeof(struct host_hc_status_block_e1x));
438862306a36Sopenharmony_ci	}
438962306a36Sopenharmony_ci
439062306a36Sopenharmony_ci	/* Rx */
439162306a36Sopenharmony_ci	if (!skip_rx_queue(bp, fp_index)) {
439262306a36Sopenharmony_ci		bnx2x_free_rx_bds(fp);
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci		/* fastpath rx rings: rx_buf rx_desc rx_comp */
439562306a36Sopenharmony_ci		BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_buf_ring));
439662306a36Sopenharmony_ci		BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_desc_ring),
439762306a36Sopenharmony_ci			       bnx2x_fp(bp, fp_index, rx_desc_mapping),
439862306a36Sopenharmony_ci			       sizeof(struct eth_rx_bd) * NUM_RX_BD);
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci		BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_comp_ring),
440162306a36Sopenharmony_ci			       bnx2x_fp(bp, fp_index, rx_comp_mapping),
440262306a36Sopenharmony_ci			       sizeof(struct eth_fast_path_rx_cqe) *
440362306a36Sopenharmony_ci			       NUM_RCQ_BD);
440462306a36Sopenharmony_ci
440562306a36Sopenharmony_ci		/* SGE ring */
440662306a36Sopenharmony_ci		BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_page_ring));
440762306a36Sopenharmony_ci		BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_sge_ring),
440862306a36Sopenharmony_ci			       bnx2x_fp(bp, fp_index, rx_sge_mapping),
440962306a36Sopenharmony_ci			       BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
441062306a36Sopenharmony_ci	}
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci	/* Tx */
441362306a36Sopenharmony_ci	if (!skip_tx_queue(bp, fp_index)) {
441462306a36Sopenharmony_ci		/* fastpath tx rings: tx_buf tx_desc */
441562306a36Sopenharmony_ci		for_each_cos_in_tx_queue(fp, cos) {
441662306a36Sopenharmony_ci			struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_ci			DP(NETIF_MSG_IFDOWN,
441962306a36Sopenharmony_ci			   "freeing tx memory of fp %d cos %d cid %d\n",
442062306a36Sopenharmony_ci			   fp_index, cos, txdata->cid);
442162306a36Sopenharmony_ci
442262306a36Sopenharmony_ci			BNX2X_FREE(txdata->tx_buf_ring);
442362306a36Sopenharmony_ci			BNX2X_PCI_FREE(txdata->tx_desc_ring,
442462306a36Sopenharmony_ci				txdata->tx_desc_mapping,
442562306a36Sopenharmony_ci				sizeof(union eth_tx_bd_types) * NUM_TX_BD);
442662306a36Sopenharmony_ci		}
442762306a36Sopenharmony_ci	}
442862306a36Sopenharmony_ci	/* end of fastpath */
442962306a36Sopenharmony_ci}
443062306a36Sopenharmony_ci
443162306a36Sopenharmony_cistatic void bnx2x_free_fp_mem_cnic(struct bnx2x *bp)
443262306a36Sopenharmony_ci{
443362306a36Sopenharmony_ci	int i;
443462306a36Sopenharmony_ci	for_each_cnic_queue(bp, i)
443562306a36Sopenharmony_ci		bnx2x_free_fp_mem_at(bp, i);
443662306a36Sopenharmony_ci}
443762306a36Sopenharmony_ci
443862306a36Sopenharmony_civoid bnx2x_free_fp_mem(struct bnx2x *bp)
443962306a36Sopenharmony_ci{
444062306a36Sopenharmony_ci	int i;
444162306a36Sopenharmony_ci	for_each_eth_queue(bp, i)
444262306a36Sopenharmony_ci		bnx2x_free_fp_mem_at(bp, i);
444362306a36Sopenharmony_ci}
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_cistatic void set_sb_shortcuts(struct bnx2x *bp, int index)
444662306a36Sopenharmony_ci{
444762306a36Sopenharmony_ci	union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk);
444862306a36Sopenharmony_ci	if (!CHIP_IS_E1x(bp)) {
444962306a36Sopenharmony_ci		bnx2x_fp(bp, index, sb_index_values) =
445062306a36Sopenharmony_ci			(__le16 *)status_blk.e2_sb->sb.index_values;
445162306a36Sopenharmony_ci		bnx2x_fp(bp, index, sb_running_index) =
445262306a36Sopenharmony_ci			(__le16 *)status_blk.e2_sb->sb.running_index;
445362306a36Sopenharmony_ci	} else {
445462306a36Sopenharmony_ci		bnx2x_fp(bp, index, sb_index_values) =
445562306a36Sopenharmony_ci			(__le16 *)status_blk.e1x_sb->sb.index_values;
445662306a36Sopenharmony_ci		bnx2x_fp(bp, index, sb_running_index) =
445762306a36Sopenharmony_ci			(__le16 *)status_blk.e1x_sb->sb.running_index;
445862306a36Sopenharmony_ci	}
445962306a36Sopenharmony_ci}
446062306a36Sopenharmony_ci
446162306a36Sopenharmony_ci/* Returns the number of actually allocated BDs */
446262306a36Sopenharmony_cistatic int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
446362306a36Sopenharmony_ci			      int rx_ring_size)
446462306a36Sopenharmony_ci{
446562306a36Sopenharmony_ci	struct bnx2x *bp = fp->bp;
446662306a36Sopenharmony_ci	u16 ring_prod, cqe_ring_prod;
446762306a36Sopenharmony_ci	int i, failure_cnt = 0;
446862306a36Sopenharmony_ci
446962306a36Sopenharmony_ci	fp->rx_comp_cons = 0;
447062306a36Sopenharmony_ci	cqe_ring_prod = ring_prod = 0;
447162306a36Sopenharmony_ci
447262306a36Sopenharmony_ci	/* This routine is called only during fo init so
447362306a36Sopenharmony_ci	 * fp->eth_q_stats.rx_skb_alloc_failed = 0
447462306a36Sopenharmony_ci	 */
447562306a36Sopenharmony_ci	for (i = 0; i < rx_ring_size; i++) {
447662306a36Sopenharmony_ci		if (bnx2x_alloc_rx_data(bp, fp, ring_prod, GFP_KERNEL) < 0) {
447762306a36Sopenharmony_ci			failure_cnt++;
447862306a36Sopenharmony_ci			continue;
447962306a36Sopenharmony_ci		}
448062306a36Sopenharmony_ci		ring_prod = NEXT_RX_IDX(ring_prod);
448162306a36Sopenharmony_ci		cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod);
448262306a36Sopenharmony_ci		WARN_ON(ring_prod <= (i - failure_cnt));
448362306a36Sopenharmony_ci	}
448462306a36Sopenharmony_ci
448562306a36Sopenharmony_ci	if (failure_cnt)
448662306a36Sopenharmony_ci		BNX2X_ERR("was only able to allocate %d rx skbs on queue[%d]\n",
448762306a36Sopenharmony_ci			  i - failure_cnt, fp->index);
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci	fp->rx_bd_prod = ring_prod;
449062306a36Sopenharmony_ci	/* Limit the CQE producer by the CQE ring size */
449162306a36Sopenharmony_ci	fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
449262306a36Sopenharmony_ci			       cqe_ring_prod);
449362306a36Sopenharmony_ci
449462306a36Sopenharmony_ci	bnx2x_fp_stats(bp, fp)->eth_q_stats.rx_skb_alloc_failed += failure_cnt;
449562306a36Sopenharmony_ci
449662306a36Sopenharmony_ci	return i - failure_cnt;
449762306a36Sopenharmony_ci}
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_cistatic void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp)
450062306a36Sopenharmony_ci{
450162306a36Sopenharmony_ci	int i;
450262306a36Sopenharmony_ci
450362306a36Sopenharmony_ci	for (i = 1; i <= NUM_RCQ_RINGS; i++) {
450462306a36Sopenharmony_ci		struct eth_rx_cqe_next_page *nextpg;
450562306a36Sopenharmony_ci
450662306a36Sopenharmony_ci		nextpg = (struct eth_rx_cqe_next_page *)
450762306a36Sopenharmony_ci			&fp->rx_comp_ring[RCQ_DESC_CNT * i - 1];
450862306a36Sopenharmony_ci		nextpg->addr_hi =
450962306a36Sopenharmony_ci			cpu_to_le32(U64_HI(fp->rx_comp_mapping +
451062306a36Sopenharmony_ci				   BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
451162306a36Sopenharmony_ci		nextpg->addr_lo =
451262306a36Sopenharmony_ci			cpu_to_le32(U64_LO(fp->rx_comp_mapping +
451362306a36Sopenharmony_ci				   BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
451462306a36Sopenharmony_ci	}
451562306a36Sopenharmony_ci}
451662306a36Sopenharmony_ci
451762306a36Sopenharmony_cistatic int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
451862306a36Sopenharmony_ci{
451962306a36Sopenharmony_ci	union host_hc_status_block *sb;
452062306a36Sopenharmony_ci	struct bnx2x_fastpath *fp = &bp->fp[index];
452162306a36Sopenharmony_ci	int ring_size = 0;
452262306a36Sopenharmony_ci	u8 cos;
452362306a36Sopenharmony_ci	int rx_ring_size = 0;
452462306a36Sopenharmony_ci
452562306a36Sopenharmony_ci	if (!bp->rx_ring_size && IS_MF_STORAGE_ONLY(bp)) {
452662306a36Sopenharmony_ci		rx_ring_size = MIN_RX_SIZE_NONTPA;
452762306a36Sopenharmony_ci		bp->rx_ring_size = rx_ring_size;
452862306a36Sopenharmony_ci	} else if (!bp->rx_ring_size) {
452962306a36Sopenharmony_ci		rx_ring_size = MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp);
453062306a36Sopenharmony_ci
453162306a36Sopenharmony_ci		if (CHIP_IS_E3(bp)) {
453262306a36Sopenharmony_ci			u32 cfg = SHMEM_RD(bp,
453362306a36Sopenharmony_ci					   dev_info.port_hw_config[BP_PORT(bp)].
453462306a36Sopenharmony_ci					   default_cfg);
453562306a36Sopenharmony_ci
453662306a36Sopenharmony_ci			/* Decrease ring size for 1G functions */
453762306a36Sopenharmony_ci			if ((cfg & PORT_HW_CFG_NET_SERDES_IF_MASK) ==
453862306a36Sopenharmony_ci			    PORT_HW_CFG_NET_SERDES_IF_SGMII)
453962306a36Sopenharmony_ci				rx_ring_size /= 10;
454062306a36Sopenharmony_ci		}
454162306a36Sopenharmony_ci
454262306a36Sopenharmony_ci		/* allocate at least number of buffers required by FW */
454362306a36Sopenharmony_ci		rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA :
454462306a36Sopenharmony_ci				     MIN_RX_SIZE_TPA, rx_ring_size);
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_ci		bp->rx_ring_size = rx_ring_size;
454762306a36Sopenharmony_ci	} else /* if rx_ring_size specified - use it */
454862306a36Sopenharmony_ci		rx_ring_size = bp->rx_ring_size;
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_ci	DP(BNX2X_MSG_SP, "calculated rx_ring_size %d\n", rx_ring_size);
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_ci	/* Common */
455362306a36Sopenharmony_ci	sb = &bnx2x_fp(bp, index, status_blk);
455462306a36Sopenharmony_ci
455562306a36Sopenharmony_ci	if (!IS_FCOE_IDX(index)) {
455662306a36Sopenharmony_ci		/* status blocks */
455762306a36Sopenharmony_ci		if (!CHIP_IS_E1x(bp)) {
455862306a36Sopenharmony_ci			sb->e2_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping),
455962306a36Sopenharmony_ci						    sizeof(struct host_hc_status_block_e2));
456062306a36Sopenharmony_ci			if (!sb->e2_sb)
456162306a36Sopenharmony_ci				goto alloc_mem_err;
456262306a36Sopenharmony_ci		} else {
456362306a36Sopenharmony_ci			sb->e1x_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping),
456462306a36Sopenharmony_ci						     sizeof(struct host_hc_status_block_e1x));
456562306a36Sopenharmony_ci			if (!sb->e1x_sb)
456662306a36Sopenharmony_ci				goto alloc_mem_err;
456762306a36Sopenharmony_ci		}
456862306a36Sopenharmony_ci	}
456962306a36Sopenharmony_ci
457062306a36Sopenharmony_ci	/* FCoE Queue uses Default SB and doesn't ACK the SB, thus no need to
457162306a36Sopenharmony_ci	 * set shortcuts for it.
457262306a36Sopenharmony_ci	 */
457362306a36Sopenharmony_ci	if (!IS_FCOE_IDX(index))
457462306a36Sopenharmony_ci		set_sb_shortcuts(bp, index);
457562306a36Sopenharmony_ci
457662306a36Sopenharmony_ci	/* Tx */
457762306a36Sopenharmony_ci	if (!skip_tx_queue(bp, index)) {
457862306a36Sopenharmony_ci		/* fastpath tx rings: tx_buf tx_desc */
457962306a36Sopenharmony_ci		for_each_cos_in_tx_queue(fp, cos) {
458062306a36Sopenharmony_ci			struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_ci			DP(NETIF_MSG_IFUP,
458362306a36Sopenharmony_ci			   "allocating tx memory of fp %d cos %d\n",
458462306a36Sopenharmony_ci			   index, cos);
458562306a36Sopenharmony_ci
458662306a36Sopenharmony_ci			txdata->tx_buf_ring = kcalloc(NUM_TX_BD,
458762306a36Sopenharmony_ci						      sizeof(struct sw_tx_bd),
458862306a36Sopenharmony_ci						      GFP_KERNEL);
458962306a36Sopenharmony_ci			if (!txdata->tx_buf_ring)
459062306a36Sopenharmony_ci				goto alloc_mem_err;
459162306a36Sopenharmony_ci			txdata->tx_desc_ring = BNX2X_PCI_ALLOC(&txdata->tx_desc_mapping,
459262306a36Sopenharmony_ci							       sizeof(union eth_tx_bd_types) * NUM_TX_BD);
459362306a36Sopenharmony_ci			if (!txdata->tx_desc_ring)
459462306a36Sopenharmony_ci				goto alloc_mem_err;
459562306a36Sopenharmony_ci		}
459662306a36Sopenharmony_ci	}
459762306a36Sopenharmony_ci
459862306a36Sopenharmony_ci	/* Rx */
459962306a36Sopenharmony_ci	if (!skip_rx_queue(bp, index)) {
460062306a36Sopenharmony_ci		/* fastpath rx rings: rx_buf rx_desc rx_comp */
460162306a36Sopenharmony_ci		bnx2x_fp(bp, index, rx_buf_ring) =
460262306a36Sopenharmony_ci			kcalloc(NUM_RX_BD, sizeof(struct sw_rx_bd), GFP_KERNEL);
460362306a36Sopenharmony_ci		if (!bnx2x_fp(bp, index, rx_buf_ring))
460462306a36Sopenharmony_ci			goto alloc_mem_err;
460562306a36Sopenharmony_ci		bnx2x_fp(bp, index, rx_desc_ring) =
460662306a36Sopenharmony_ci			BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_desc_mapping),
460762306a36Sopenharmony_ci					sizeof(struct eth_rx_bd) * NUM_RX_BD);
460862306a36Sopenharmony_ci		if (!bnx2x_fp(bp, index, rx_desc_ring))
460962306a36Sopenharmony_ci			goto alloc_mem_err;
461062306a36Sopenharmony_ci
461162306a36Sopenharmony_ci		/* Seed all CQEs by 1s */
461262306a36Sopenharmony_ci		bnx2x_fp(bp, index, rx_comp_ring) =
461362306a36Sopenharmony_ci			BNX2X_PCI_FALLOC(&bnx2x_fp(bp, index, rx_comp_mapping),
461462306a36Sopenharmony_ci					 sizeof(struct eth_fast_path_rx_cqe) * NUM_RCQ_BD);
461562306a36Sopenharmony_ci		if (!bnx2x_fp(bp, index, rx_comp_ring))
461662306a36Sopenharmony_ci			goto alloc_mem_err;
461762306a36Sopenharmony_ci
461862306a36Sopenharmony_ci		/* SGE ring */
461962306a36Sopenharmony_ci		bnx2x_fp(bp, index, rx_page_ring) =
462062306a36Sopenharmony_ci			kcalloc(NUM_RX_SGE, sizeof(struct sw_rx_page),
462162306a36Sopenharmony_ci				GFP_KERNEL);
462262306a36Sopenharmony_ci		if (!bnx2x_fp(bp, index, rx_page_ring))
462362306a36Sopenharmony_ci			goto alloc_mem_err;
462462306a36Sopenharmony_ci		bnx2x_fp(bp, index, rx_sge_ring) =
462562306a36Sopenharmony_ci			BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_sge_mapping),
462662306a36Sopenharmony_ci					BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
462762306a36Sopenharmony_ci		if (!bnx2x_fp(bp, index, rx_sge_ring))
462862306a36Sopenharmony_ci			goto alloc_mem_err;
462962306a36Sopenharmony_ci		/* RX BD ring */
463062306a36Sopenharmony_ci		bnx2x_set_next_page_rx_bd(fp);
463162306a36Sopenharmony_ci
463262306a36Sopenharmony_ci		/* CQ ring */
463362306a36Sopenharmony_ci		bnx2x_set_next_page_rx_cq(fp);
463462306a36Sopenharmony_ci
463562306a36Sopenharmony_ci		/* BDs */
463662306a36Sopenharmony_ci		ring_size = bnx2x_alloc_rx_bds(fp, rx_ring_size);
463762306a36Sopenharmony_ci		if (ring_size < rx_ring_size)
463862306a36Sopenharmony_ci			goto alloc_mem_err;
463962306a36Sopenharmony_ci	}
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_ci	return 0;
464262306a36Sopenharmony_ci
464362306a36Sopenharmony_ci/* handles low memory cases */
464462306a36Sopenharmony_cialloc_mem_err:
464562306a36Sopenharmony_ci	BNX2X_ERR("Unable to allocate full memory for queue %d (size %d)\n",
464662306a36Sopenharmony_ci						index, ring_size);
464762306a36Sopenharmony_ci	/* FW will drop all packets if queue is not big enough,
464862306a36Sopenharmony_ci	 * In these cases we disable the queue
464962306a36Sopenharmony_ci	 * Min size is different for OOO, TPA and non-TPA queues
465062306a36Sopenharmony_ci	 */
465162306a36Sopenharmony_ci	if (ring_size < (fp->mode == TPA_MODE_DISABLED ?
465262306a36Sopenharmony_ci				MIN_RX_SIZE_NONTPA : MIN_RX_SIZE_TPA)) {
465362306a36Sopenharmony_ci			/* release memory allocated for this queue */
465462306a36Sopenharmony_ci			bnx2x_free_fp_mem_at(bp, index);
465562306a36Sopenharmony_ci			return -ENOMEM;
465662306a36Sopenharmony_ci	}
465762306a36Sopenharmony_ci	return 0;
465862306a36Sopenharmony_ci}
465962306a36Sopenharmony_ci
466062306a36Sopenharmony_cistatic int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp)
466162306a36Sopenharmony_ci{
466262306a36Sopenharmony_ci	if (!NO_FCOE(bp))
466362306a36Sopenharmony_ci		/* FCoE */
466462306a36Sopenharmony_ci		if (bnx2x_alloc_fp_mem_at(bp, FCOE_IDX(bp)))
466562306a36Sopenharmony_ci			/* we will fail load process instead of mark
466662306a36Sopenharmony_ci			 * NO_FCOE_FLAG
466762306a36Sopenharmony_ci			 */
466862306a36Sopenharmony_ci			return -ENOMEM;
466962306a36Sopenharmony_ci
467062306a36Sopenharmony_ci	return 0;
467162306a36Sopenharmony_ci}
467262306a36Sopenharmony_ci
467362306a36Sopenharmony_cistatic int bnx2x_alloc_fp_mem(struct bnx2x *bp)
467462306a36Sopenharmony_ci{
467562306a36Sopenharmony_ci	int i;
467662306a36Sopenharmony_ci
467762306a36Sopenharmony_ci	/* 1. Allocate FP for leading - fatal if error
467862306a36Sopenharmony_ci	 * 2. Allocate RSS - fix number of queues if error
467962306a36Sopenharmony_ci	 */
468062306a36Sopenharmony_ci
468162306a36Sopenharmony_ci	/* leading */
468262306a36Sopenharmony_ci	if (bnx2x_alloc_fp_mem_at(bp, 0))
468362306a36Sopenharmony_ci		return -ENOMEM;
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_ci	/* RSS */
468662306a36Sopenharmony_ci	for_each_nondefault_eth_queue(bp, i)
468762306a36Sopenharmony_ci		if (bnx2x_alloc_fp_mem_at(bp, i))
468862306a36Sopenharmony_ci			break;
468962306a36Sopenharmony_ci
469062306a36Sopenharmony_ci	/* handle memory failures */
469162306a36Sopenharmony_ci	if (i != BNX2X_NUM_ETH_QUEUES(bp)) {
469262306a36Sopenharmony_ci		int delta = BNX2X_NUM_ETH_QUEUES(bp) - i;
469362306a36Sopenharmony_ci
469462306a36Sopenharmony_ci		WARN_ON(delta < 0);
469562306a36Sopenharmony_ci		bnx2x_shrink_eth_fp(bp, delta);
469662306a36Sopenharmony_ci		if (CNIC_SUPPORT(bp))
469762306a36Sopenharmony_ci			/* move non eth FPs next to last eth FP
469862306a36Sopenharmony_ci			 * must be done in that order
469962306a36Sopenharmony_ci			 * FCOE_IDX < FWD_IDX < OOO_IDX
470062306a36Sopenharmony_ci			 */
470162306a36Sopenharmony_ci
470262306a36Sopenharmony_ci			/* move FCoE fp even NO_FCOE_FLAG is on */
470362306a36Sopenharmony_ci			bnx2x_move_fp(bp, FCOE_IDX(bp), FCOE_IDX(bp) - delta);
470462306a36Sopenharmony_ci		bp->num_ethernet_queues -= delta;
470562306a36Sopenharmony_ci		bp->num_queues = bp->num_ethernet_queues +
470662306a36Sopenharmony_ci				 bp->num_cnic_queues;
470762306a36Sopenharmony_ci		BNX2X_ERR("Adjusted num of queues from %d to %d\n",
470862306a36Sopenharmony_ci			  bp->num_queues + delta, bp->num_queues);
470962306a36Sopenharmony_ci	}
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_ci	return 0;
471262306a36Sopenharmony_ci}
471362306a36Sopenharmony_ci
471462306a36Sopenharmony_civoid bnx2x_free_mem_bp(struct bnx2x *bp)
471562306a36Sopenharmony_ci{
471662306a36Sopenharmony_ci	int i;
471762306a36Sopenharmony_ci
471862306a36Sopenharmony_ci	for (i = 0; i < bp->fp_array_size; i++)
471962306a36Sopenharmony_ci		kfree(bp->fp[i].tpa_info);
472062306a36Sopenharmony_ci	kfree(bp->fp);
472162306a36Sopenharmony_ci	kfree(bp->sp_objs);
472262306a36Sopenharmony_ci	kfree(bp->fp_stats);
472362306a36Sopenharmony_ci	kfree(bp->bnx2x_txq);
472462306a36Sopenharmony_ci	kfree(bp->msix_table);
472562306a36Sopenharmony_ci	kfree(bp->ilt);
472662306a36Sopenharmony_ci}
472762306a36Sopenharmony_ci
472862306a36Sopenharmony_ciint bnx2x_alloc_mem_bp(struct bnx2x *bp)
472962306a36Sopenharmony_ci{
473062306a36Sopenharmony_ci	struct bnx2x_fastpath *fp;
473162306a36Sopenharmony_ci	struct msix_entry *tbl;
473262306a36Sopenharmony_ci	struct bnx2x_ilt *ilt;
473362306a36Sopenharmony_ci	int msix_table_size = 0;
473462306a36Sopenharmony_ci	int fp_array_size, txq_array_size;
473562306a36Sopenharmony_ci	int i;
473662306a36Sopenharmony_ci
473762306a36Sopenharmony_ci	/*
473862306a36Sopenharmony_ci	 * The biggest MSI-X table we might need is as a maximum number of fast
473962306a36Sopenharmony_ci	 * path IGU SBs plus default SB (for PF only).
474062306a36Sopenharmony_ci	 */
474162306a36Sopenharmony_ci	msix_table_size = bp->igu_sb_cnt;
474262306a36Sopenharmony_ci	if (IS_PF(bp))
474362306a36Sopenharmony_ci		msix_table_size++;
474462306a36Sopenharmony_ci	BNX2X_DEV_INFO("msix_table_size %d\n", msix_table_size);
474562306a36Sopenharmony_ci
474662306a36Sopenharmony_ci	/* fp array: RSS plus CNIC related L2 queues */
474762306a36Sopenharmony_ci	fp_array_size = BNX2X_MAX_RSS_COUNT(bp) + CNIC_SUPPORT(bp);
474862306a36Sopenharmony_ci	bp->fp_array_size = fp_array_size;
474962306a36Sopenharmony_ci	BNX2X_DEV_INFO("fp_array_size %d\n", bp->fp_array_size);
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ci	fp = kcalloc(bp->fp_array_size, sizeof(*fp), GFP_KERNEL);
475262306a36Sopenharmony_ci	if (!fp)
475362306a36Sopenharmony_ci		goto alloc_err;
475462306a36Sopenharmony_ci	for (i = 0; i < bp->fp_array_size; i++) {
475562306a36Sopenharmony_ci		fp[i].tpa_info =
475662306a36Sopenharmony_ci			kcalloc(ETH_MAX_AGGREGATION_QUEUES_E1H_E2,
475762306a36Sopenharmony_ci				sizeof(struct bnx2x_agg_info), GFP_KERNEL);
475862306a36Sopenharmony_ci		if (!(fp[i].tpa_info))
475962306a36Sopenharmony_ci			goto alloc_err;
476062306a36Sopenharmony_ci	}
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_ci	bp->fp = fp;
476362306a36Sopenharmony_ci
476462306a36Sopenharmony_ci	/* allocate sp objs */
476562306a36Sopenharmony_ci	bp->sp_objs = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_sp_objs),
476662306a36Sopenharmony_ci			      GFP_KERNEL);
476762306a36Sopenharmony_ci	if (!bp->sp_objs)
476862306a36Sopenharmony_ci		goto alloc_err;
476962306a36Sopenharmony_ci
477062306a36Sopenharmony_ci	/* allocate fp_stats */
477162306a36Sopenharmony_ci	bp->fp_stats = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_fp_stats),
477262306a36Sopenharmony_ci			       GFP_KERNEL);
477362306a36Sopenharmony_ci	if (!bp->fp_stats)
477462306a36Sopenharmony_ci		goto alloc_err;
477562306a36Sopenharmony_ci
477662306a36Sopenharmony_ci	/* Allocate memory for the transmission queues array */
477762306a36Sopenharmony_ci	txq_array_size =
477862306a36Sopenharmony_ci		BNX2X_MAX_RSS_COUNT(bp) * BNX2X_MULTI_TX_COS + CNIC_SUPPORT(bp);
477962306a36Sopenharmony_ci	BNX2X_DEV_INFO("txq_array_size %d", txq_array_size);
478062306a36Sopenharmony_ci
478162306a36Sopenharmony_ci	bp->bnx2x_txq = kcalloc(txq_array_size, sizeof(struct bnx2x_fp_txdata),
478262306a36Sopenharmony_ci				GFP_KERNEL);
478362306a36Sopenharmony_ci	if (!bp->bnx2x_txq)
478462306a36Sopenharmony_ci		goto alloc_err;
478562306a36Sopenharmony_ci
478662306a36Sopenharmony_ci	/* msix table */
478762306a36Sopenharmony_ci	tbl = kcalloc(msix_table_size, sizeof(*tbl), GFP_KERNEL);
478862306a36Sopenharmony_ci	if (!tbl)
478962306a36Sopenharmony_ci		goto alloc_err;
479062306a36Sopenharmony_ci	bp->msix_table = tbl;
479162306a36Sopenharmony_ci
479262306a36Sopenharmony_ci	/* ilt */
479362306a36Sopenharmony_ci	ilt = kzalloc(sizeof(*ilt), GFP_KERNEL);
479462306a36Sopenharmony_ci	if (!ilt)
479562306a36Sopenharmony_ci		goto alloc_err;
479662306a36Sopenharmony_ci	bp->ilt = ilt;
479762306a36Sopenharmony_ci
479862306a36Sopenharmony_ci	return 0;
479962306a36Sopenharmony_cialloc_err:
480062306a36Sopenharmony_ci	bnx2x_free_mem_bp(bp);
480162306a36Sopenharmony_ci	return -ENOMEM;
480262306a36Sopenharmony_ci}
480362306a36Sopenharmony_ci
480462306a36Sopenharmony_ciint bnx2x_reload_if_running(struct net_device *dev)
480562306a36Sopenharmony_ci{
480662306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
480762306a36Sopenharmony_ci
480862306a36Sopenharmony_ci	if (unlikely(!netif_running(dev)))
480962306a36Sopenharmony_ci		return 0;
481062306a36Sopenharmony_ci
481162306a36Sopenharmony_ci	bnx2x_nic_unload(bp, UNLOAD_NORMAL, true);
481262306a36Sopenharmony_ci	return bnx2x_nic_load(bp, LOAD_NORMAL);
481362306a36Sopenharmony_ci}
481462306a36Sopenharmony_ci
481562306a36Sopenharmony_ciint bnx2x_get_cur_phy_idx(struct bnx2x *bp)
481662306a36Sopenharmony_ci{
481762306a36Sopenharmony_ci	u32 sel_phy_idx = 0;
481862306a36Sopenharmony_ci	if (bp->link_params.num_phys <= 1)
481962306a36Sopenharmony_ci		return INT_PHY;
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_ci	if (bp->link_vars.link_up) {
482262306a36Sopenharmony_ci		sel_phy_idx = EXT_PHY1;
482362306a36Sopenharmony_ci		/* In case link is SERDES, check if the EXT_PHY2 is the one */
482462306a36Sopenharmony_ci		if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) &&
482562306a36Sopenharmony_ci		    (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE))
482662306a36Sopenharmony_ci			sel_phy_idx = EXT_PHY2;
482762306a36Sopenharmony_ci	} else {
482862306a36Sopenharmony_ci
482962306a36Sopenharmony_ci		switch (bnx2x_phy_selection(&bp->link_params)) {
483062306a36Sopenharmony_ci		case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
483162306a36Sopenharmony_ci		case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
483262306a36Sopenharmony_ci		case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
483362306a36Sopenharmony_ci		       sel_phy_idx = EXT_PHY1;
483462306a36Sopenharmony_ci		       break;
483562306a36Sopenharmony_ci		case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
483662306a36Sopenharmony_ci		case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
483762306a36Sopenharmony_ci		       sel_phy_idx = EXT_PHY2;
483862306a36Sopenharmony_ci		       break;
483962306a36Sopenharmony_ci		}
484062306a36Sopenharmony_ci	}
484162306a36Sopenharmony_ci
484262306a36Sopenharmony_ci	return sel_phy_idx;
484362306a36Sopenharmony_ci}
484462306a36Sopenharmony_ciint bnx2x_get_link_cfg_idx(struct bnx2x *bp)
484562306a36Sopenharmony_ci{
484662306a36Sopenharmony_ci	u32 sel_phy_idx = bnx2x_get_cur_phy_idx(bp);
484762306a36Sopenharmony_ci	/*
484862306a36Sopenharmony_ci	 * The selected activated PHY is always after swapping (in case PHY
484962306a36Sopenharmony_ci	 * swapping is enabled). So when swapping is enabled, we need to reverse
485062306a36Sopenharmony_ci	 * the configuration
485162306a36Sopenharmony_ci	 */
485262306a36Sopenharmony_ci
485362306a36Sopenharmony_ci	if (bp->link_params.multi_phy_config &
485462306a36Sopenharmony_ci	    PORT_HW_CFG_PHY_SWAPPED_ENABLED) {
485562306a36Sopenharmony_ci		if (sel_phy_idx == EXT_PHY1)
485662306a36Sopenharmony_ci			sel_phy_idx = EXT_PHY2;
485762306a36Sopenharmony_ci		else if (sel_phy_idx == EXT_PHY2)
485862306a36Sopenharmony_ci			sel_phy_idx = EXT_PHY1;
485962306a36Sopenharmony_ci	}
486062306a36Sopenharmony_ci	return LINK_CONFIG_IDX(sel_phy_idx);
486162306a36Sopenharmony_ci}
486262306a36Sopenharmony_ci
486362306a36Sopenharmony_ci#ifdef NETDEV_FCOE_WWNN
486462306a36Sopenharmony_ciint bnx2x_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type)
486562306a36Sopenharmony_ci{
486662306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
486762306a36Sopenharmony_ci	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
486862306a36Sopenharmony_ci
486962306a36Sopenharmony_ci	switch (type) {
487062306a36Sopenharmony_ci	case NETDEV_FCOE_WWNN:
487162306a36Sopenharmony_ci		*wwn = HILO_U64(cp->fcoe_wwn_node_name_hi,
487262306a36Sopenharmony_ci				cp->fcoe_wwn_node_name_lo);
487362306a36Sopenharmony_ci		break;
487462306a36Sopenharmony_ci	case NETDEV_FCOE_WWPN:
487562306a36Sopenharmony_ci		*wwn = HILO_U64(cp->fcoe_wwn_port_name_hi,
487662306a36Sopenharmony_ci				cp->fcoe_wwn_port_name_lo);
487762306a36Sopenharmony_ci		break;
487862306a36Sopenharmony_ci	default:
487962306a36Sopenharmony_ci		BNX2X_ERR("Wrong WWN type requested - %d\n", type);
488062306a36Sopenharmony_ci		return -EINVAL;
488162306a36Sopenharmony_ci	}
488262306a36Sopenharmony_ci
488362306a36Sopenharmony_ci	return 0;
488462306a36Sopenharmony_ci}
488562306a36Sopenharmony_ci#endif
488662306a36Sopenharmony_ci
488762306a36Sopenharmony_ci/* called with rtnl_lock */
488862306a36Sopenharmony_ciint bnx2x_change_mtu(struct net_device *dev, int new_mtu)
488962306a36Sopenharmony_ci{
489062306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
489162306a36Sopenharmony_ci
489262306a36Sopenharmony_ci	if (pci_num_vf(bp->pdev)) {
489362306a36Sopenharmony_ci		DP(BNX2X_MSG_IOV, "VFs are enabled, can not change MTU\n");
489462306a36Sopenharmony_ci		return -EPERM;
489562306a36Sopenharmony_ci	}
489662306a36Sopenharmony_ci
489762306a36Sopenharmony_ci	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
489862306a36Sopenharmony_ci		BNX2X_ERR("Can't perform change MTU during parity recovery\n");
489962306a36Sopenharmony_ci		return -EAGAIN;
490062306a36Sopenharmony_ci	}
490162306a36Sopenharmony_ci
490262306a36Sopenharmony_ci	/* This does not race with packet allocation
490362306a36Sopenharmony_ci	 * because the actual alloc size is
490462306a36Sopenharmony_ci	 * only updated as part of load
490562306a36Sopenharmony_ci	 */
490662306a36Sopenharmony_ci	dev->mtu = new_mtu;
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_ci	if (!bnx2x_mtu_allows_gro(new_mtu))
490962306a36Sopenharmony_ci		dev->features &= ~NETIF_F_GRO_HW;
491062306a36Sopenharmony_ci
491162306a36Sopenharmony_ci	if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg))
491262306a36Sopenharmony_ci		SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS);
491362306a36Sopenharmony_ci
491462306a36Sopenharmony_ci	return bnx2x_reload_if_running(dev);
491562306a36Sopenharmony_ci}
491662306a36Sopenharmony_ci
491762306a36Sopenharmony_cinetdev_features_t bnx2x_fix_features(struct net_device *dev,
491862306a36Sopenharmony_ci				     netdev_features_t features)
491962306a36Sopenharmony_ci{
492062306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
492162306a36Sopenharmony_ci
492262306a36Sopenharmony_ci	if (pci_num_vf(bp->pdev)) {
492362306a36Sopenharmony_ci		netdev_features_t changed = dev->features ^ features;
492462306a36Sopenharmony_ci
492562306a36Sopenharmony_ci		/* Revert the requested changes in features if they
492662306a36Sopenharmony_ci		 * would require internal reload of PF in bnx2x_set_features().
492762306a36Sopenharmony_ci		 */
492862306a36Sopenharmony_ci		if (!(features & NETIF_F_RXCSUM) && !bp->disable_tpa) {
492962306a36Sopenharmony_ci			features &= ~NETIF_F_RXCSUM;
493062306a36Sopenharmony_ci			features |= dev->features & NETIF_F_RXCSUM;
493162306a36Sopenharmony_ci		}
493262306a36Sopenharmony_ci
493362306a36Sopenharmony_ci		if (changed & NETIF_F_LOOPBACK) {
493462306a36Sopenharmony_ci			features &= ~NETIF_F_LOOPBACK;
493562306a36Sopenharmony_ci			features |= dev->features & NETIF_F_LOOPBACK;
493662306a36Sopenharmony_ci		}
493762306a36Sopenharmony_ci	}
493862306a36Sopenharmony_ci
493962306a36Sopenharmony_ci	/* TPA requires Rx CSUM offloading */
494062306a36Sopenharmony_ci	if (!(features & NETIF_F_RXCSUM))
494162306a36Sopenharmony_ci		features &= ~NETIF_F_LRO;
494262306a36Sopenharmony_ci
494362306a36Sopenharmony_ci	if (!(features & NETIF_F_GRO) || !bnx2x_mtu_allows_gro(dev->mtu))
494462306a36Sopenharmony_ci		features &= ~NETIF_F_GRO_HW;
494562306a36Sopenharmony_ci	if (features & NETIF_F_GRO_HW)
494662306a36Sopenharmony_ci		features &= ~NETIF_F_LRO;
494762306a36Sopenharmony_ci
494862306a36Sopenharmony_ci	return features;
494962306a36Sopenharmony_ci}
495062306a36Sopenharmony_ci
495162306a36Sopenharmony_ciint bnx2x_set_features(struct net_device *dev, netdev_features_t features)
495262306a36Sopenharmony_ci{
495362306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
495462306a36Sopenharmony_ci	netdev_features_t changes = features ^ dev->features;
495562306a36Sopenharmony_ci	bool bnx2x_reload = false;
495662306a36Sopenharmony_ci	int rc;
495762306a36Sopenharmony_ci
495862306a36Sopenharmony_ci	/* VFs or non SRIOV PFs should be able to change loopback feature */
495962306a36Sopenharmony_ci	if (!pci_num_vf(bp->pdev)) {
496062306a36Sopenharmony_ci		if (features & NETIF_F_LOOPBACK) {
496162306a36Sopenharmony_ci			if (bp->link_params.loopback_mode != LOOPBACK_BMAC) {
496262306a36Sopenharmony_ci				bp->link_params.loopback_mode = LOOPBACK_BMAC;
496362306a36Sopenharmony_ci				bnx2x_reload = true;
496462306a36Sopenharmony_ci			}
496562306a36Sopenharmony_ci		} else {
496662306a36Sopenharmony_ci			if (bp->link_params.loopback_mode != LOOPBACK_NONE) {
496762306a36Sopenharmony_ci				bp->link_params.loopback_mode = LOOPBACK_NONE;
496862306a36Sopenharmony_ci				bnx2x_reload = true;
496962306a36Sopenharmony_ci			}
497062306a36Sopenharmony_ci		}
497162306a36Sopenharmony_ci	}
497262306a36Sopenharmony_ci
497362306a36Sopenharmony_ci	/* Don't care about GRO changes */
497462306a36Sopenharmony_ci	changes &= ~NETIF_F_GRO;
497562306a36Sopenharmony_ci
497662306a36Sopenharmony_ci	if (changes)
497762306a36Sopenharmony_ci		bnx2x_reload = true;
497862306a36Sopenharmony_ci
497962306a36Sopenharmony_ci	if (bnx2x_reload) {
498062306a36Sopenharmony_ci		if (bp->recovery_state == BNX2X_RECOVERY_DONE) {
498162306a36Sopenharmony_ci			dev->features = features;
498262306a36Sopenharmony_ci			rc = bnx2x_reload_if_running(dev);
498362306a36Sopenharmony_ci			return rc ? rc : 1;
498462306a36Sopenharmony_ci		}
498562306a36Sopenharmony_ci		/* else: bnx2x_nic_load() will be called at end of recovery */
498662306a36Sopenharmony_ci	}
498762306a36Sopenharmony_ci
498862306a36Sopenharmony_ci	return 0;
498962306a36Sopenharmony_ci}
499062306a36Sopenharmony_ci
499162306a36Sopenharmony_civoid bnx2x_tx_timeout(struct net_device *dev, unsigned int txqueue)
499262306a36Sopenharmony_ci{
499362306a36Sopenharmony_ci	struct bnx2x *bp = netdev_priv(dev);
499462306a36Sopenharmony_ci
499562306a36Sopenharmony_ci	/* We want the information of the dump logged,
499662306a36Sopenharmony_ci	 * but calling bnx2x_panic() would kill all chances of recovery.
499762306a36Sopenharmony_ci	 */
499862306a36Sopenharmony_ci	if (!bp->panic)
499962306a36Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR
500062306a36Sopenharmony_ci		bnx2x_panic_dump(bp, false);
500162306a36Sopenharmony_ci#else
500262306a36Sopenharmony_ci		bnx2x_panic();
500362306a36Sopenharmony_ci#endif
500462306a36Sopenharmony_ci
500562306a36Sopenharmony_ci	/* This allows the netif to be shutdown gracefully before resetting */
500662306a36Sopenharmony_ci	bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_TIMEOUT, 0);
500762306a36Sopenharmony_ci}
500862306a36Sopenharmony_ci
500962306a36Sopenharmony_cistatic int __maybe_unused bnx2x_suspend(struct device *dev_d)
501062306a36Sopenharmony_ci{
501162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev_d);
501262306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
501362306a36Sopenharmony_ci	struct bnx2x *bp;
501462306a36Sopenharmony_ci
501562306a36Sopenharmony_ci	if (!dev) {
501662306a36Sopenharmony_ci		dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
501762306a36Sopenharmony_ci		return -ENODEV;
501862306a36Sopenharmony_ci	}
501962306a36Sopenharmony_ci	bp = netdev_priv(dev);
502062306a36Sopenharmony_ci
502162306a36Sopenharmony_ci	rtnl_lock();
502262306a36Sopenharmony_ci
502362306a36Sopenharmony_ci	if (!netif_running(dev)) {
502462306a36Sopenharmony_ci		rtnl_unlock();
502562306a36Sopenharmony_ci		return 0;
502662306a36Sopenharmony_ci	}
502762306a36Sopenharmony_ci
502862306a36Sopenharmony_ci	netif_device_detach(dev);
502962306a36Sopenharmony_ci
503062306a36Sopenharmony_ci	bnx2x_nic_unload(bp, UNLOAD_CLOSE, false);
503162306a36Sopenharmony_ci
503262306a36Sopenharmony_ci	rtnl_unlock();
503362306a36Sopenharmony_ci
503462306a36Sopenharmony_ci	return 0;
503562306a36Sopenharmony_ci}
503662306a36Sopenharmony_ci
503762306a36Sopenharmony_cistatic int __maybe_unused bnx2x_resume(struct device *dev_d)
503862306a36Sopenharmony_ci{
503962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev_d);
504062306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
504162306a36Sopenharmony_ci	struct bnx2x *bp;
504262306a36Sopenharmony_ci	int rc;
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci	if (!dev) {
504562306a36Sopenharmony_ci		dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
504662306a36Sopenharmony_ci		return -ENODEV;
504762306a36Sopenharmony_ci	}
504862306a36Sopenharmony_ci	bp = netdev_priv(dev);
504962306a36Sopenharmony_ci
505062306a36Sopenharmony_ci	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
505162306a36Sopenharmony_ci		BNX2X_ERR("Handling parity error recovery. Try again later\n");
505262306a36Sopenharmony_ci		return -EAGAIN;
505362306a36Sopenharmony_ci	}
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci	rtnl_lock();
505662306a36Sopenharmony_ci
505762306a36Sopenharmony_ci	if (!netif_running(dev)) {
505862306a36Sopenharmony_ci		rtnl_unlock();
505962306a36Sopenharmony_ci		return 0;
506062306a36Sopenharmony_ci	}
506162306a36Sopenharmony_ci
506262306a36Sopenharmony_ci	netif_device_attach(dev);
506362306a36Sopenharmony_ci
506462306a36Sopenharmony_ci	rc = bnx2x_nic_load(bp, LOAD_OPEN);
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci	rtnl_unlock();
506762306a36Sopenharmony_ci
506862306a36Sopenharmony_ci	return rc;
506962306a36Sopenharmony_ci}
507062306a36Sopenharmony_ci
507162306a36Sopenharmony_ciSIMPLE_DEV_PM_OPS(bnx2x_pm_ops, bnx2x_suspend, bnx2x_resume);
507262306a36Sopenharmony_ci
507362306a36Sopenharmony_civoid bnx2x_set_ctx_validation(struct bnx2x *bp, struct eth_context *cxt,
507462306a36Sopenharmony_ci			      u32 cid)
507562306a36Sopenharmony_ci{
507662306a36Sopenharmony_ci	if (!cxt) {
507762306a36Sopenharmony_ci		BNX2X_ERR("bad context pointer %p\n", cxt);
507862306a36Sopenharmony_ci		return;
507962306a36Sopenharmony_ci	}
508062306a36Sopenharmony_ci
508162306a36Sopenharmony_ci	/* ustorm cxt validation */
508262306a36Sopenharmony_ci	cxt->ustorm_ag_context.cdu_usage =
508362306a36Sopenharmony_ci		CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, cid),
508462306a36Sopenharmony_ci			CDU_REGION_NUMBER_UCM_AG, ETH_CONNECTION_TYPE);
508562306a36Sopenharmony_ci	/* xcontext validation */
508662306a36Sopenharmony_ci	cxt->xstorm_ag_context.cdu_reserved =
508762306a36Sopenharmony_ci		CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, cid),
508862306a36Sopenharmony_ci			CDU_REGION_NUMBER_XCM_AG, ETH_CONNECTION_TYPE);
508962306a36Sopenharmony_ci}
509062306a36Sopenharmony_ci
509162306a36Sopenharmony_cistatic void storm_memset_hc_timeout(struct bnx2x *bp, u8 port,
509262306a36Sopenharmony_ci				    u8 fw_sb_id, u8 sb_index,
509362306a36Sopenharmony_ci				    u8 ticks)
509462306a36Sopenharmony_ci{
509562306a36Sopenharmony_ci	u32 addr = BAR_CSTRORM_INTMEM +
509662306a36Sopenharmony_ci		   CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(fw_sb_id, sb_index);
509762306a36Sopenharmony_ci	REG_WR8(bp, addr, ticks);
509862306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP,
509962306a36Sopenharmony_ci	   "port %x fw_sb_id %d sb_index %d ticks %d\n",
510062306a36Sopenharmony_ci	   port, fw_sb_id, sb_index, ticks);
510162306a36Sopenharmony_ci}
510262306a36Sopenharmony_ci
510362306a36Sopenharmony_cistatic void storm_memset_hc_disable(struct bnx2x *bp, u8 port,
510462306a36Sopenharmony_ci				    u16 fw_sb_id, u8 sb_index,
510562306a36Sopenharmony_ci				    u8 disable)
510662306a36Sopenharmony_ci{
510762306a36Sopenharmony_ci	u32 enable_flag = disable ? 0 : (1 << HC_INDEX_DATA_HC_ENABLED_SHIFT);
510862306a36Sopenharmony_ci	u32 addr = BAR_CSTRORM_INTMEM +
510962306a36Sopenharmony_ci		   CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(fw_sb_id, sb_index);
511062306a36Sopenharmony_ci	u8 flags = REG_RD8(bp, addr);
511162306a36Sopenharmony_ci	/* clear and set */
511262306a36Sopenharmony_ci	flags &= ~HC_INDEX_DATA_HC_ENABLED;
511362306a36Sopenharmony_ci	flags |= enable_flag;
511462306a36Sopenharmony_ci	REG_WR8(bp, addr, flags);
511562306a36Sopenharmony_ci	DP(NETIF_MSG_IFUP,
511662306a36Sopenharmony_ci	   "port %x fw_sb_id %d sb_index %d disable %d\n",
511762306a36Sopenharmony_ci	   port, fw_sb_id, sb_index, disable);
511862306a36Sopenharmony_ci}
511962306a36Sopenharmony_ci
512062306a36Sopenharmony_civoid bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u8 fw_sb_id,
512162306a36Sopenharmony_ci				    u8 sb_index, u8 disable, u16 usec)
512262306a36Sopenharmony_ci{
512362306a36Sopenharmony_ci	int port = BP_PORT(bp);
512462306a36Sopenharmony_ci	u8 ticks = usec / BNX2X_BTR;
512562306a36Sopenharmony_ci
512662306a36Sopenharmony_ci	storm_memset_hc_timeout(bp, port, fw_sb_id, sb_index, ticks);
512762306a36Sopenharmony_ci
512862306a36Sopenharmony_ci	disable = disable ? 1 : (usec ? 0 : 1);
512962306a36Sopenharmony_ci	storm_memset_hc_disable(bp, port, fw_sb_id, sb_index, disable);
513062306a36Sopenharmony_ci}
513162306a36Sopenharmony_ci
513262306a36Sopenharmony_civoid bnx2x_schedule_sp_rtnl(struct bnx2x *bp, enum sp_rtnl_flag flag,
513362306a36Sopenharmony_ci			    u32 verbose)
513462306a36Sopenharmony_ci{
513562306a36Sopenharmony_ci	smp_mb__before_atomic();
513662306a36Sopenharmony_ci	set_bit(flag, &bp->sp_rtnl_state);
513762306a36Sopenharmony_ci	smp_mb__after_atomic();
513862306a36Sopenharmony_ci	DP((BNX2X_MSG_SP | verbose), "Scheduling sp_rtnl task [Flag: %d]\n",
513962306a36Sopenharmony_ci	   flag);
514062306a36Sopenharmony_ci	schedule_delayed_work(&bp->sp_rtnl_task, 0);
514162306a36Sopenharmony_ci}
5142