162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is part of the Chelsio T4 Ethernet driver for Linux.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2003-2016 Chelsio Communications, Inc. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This software is available to you under a choice of one of two
762306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
1062306a36Sopenharmony_ci * OpenIB.org BSD license below:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1362306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1462306a36Sopenharmony_ci *     conditions are met:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1762306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1862306a36Sopenharmony_ci *        disclaimer.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2162306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2262306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2362306a36Sopenharmony_ci *        provided with the distribution.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3262306a36Sopenharmony_ci * SOFTWARE.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <linux/bitmap.h>
3862306a36Sopenharmony_ci#include <linux/crc32.h>
3962306a36Sopenharmony_ci#include <linux/ctype.h>
4062306a36Sopenharmony_ci#include <linux/debugfs.h>
4162306a36Sopenharmony_ci#include <linux/err.h>
4262306a36Sopenharmony_ci#include <linux/etherdevice.h>
4362306a36Sopenharmony_ci#include <linux/firmware.h>
4462306a36Sopenharmony_ci#include <linux/if.h>
4562306a36Sopenharmony_ci#include <linux/if_vlan.h>
4662306a36Sopenharmony_ci#include <linux/init.h>
4762306a36Sopenharmony_ci#include <linux/log2.h>
4862306a36Sopenharmony_ci#include <linux/mdio.h>
4962306a36Sopenharmony_ci#include <linux/module.h>
5062306a36Sopenharmony_ci#include <linux/moduleparam.h>
5162306a36Sopenharmony_ci#include <linux/mutex.h>
5262306a36Sopenharmony_ci#include <linux/netdevice.h>
5362306a36Sopenharmony_ci#include <linux/pci.h>
5462306a36Sopenharmony_ci#include <linux/rtnetlink.h>
5562306a36Sopenharmony_ci#include <linux/sched.h>
5662306a36Sopenharmony_ci#include <linux/seq_file.h>
5762306a36Sopenharmony_ci#include <linux/sockios.h>
5862306a36Sopenharmony_ci#include <linux/vmalloc.h>
5962306a36Sopenharmony_ci#include <linux/workqueue.h>
6062306a36Sopenharmony_ci#include <net/neighbour.h>
6162306a36Sopenharmony_ci#include <net/netevent.h>
6262306a36Sopenharmony_ci#include <net/addrconf.h>
6362306a36Sopenharmony_ci#include <net/bonding.h>
6462306a36Sopenharmony_ci#include <linux/uaccess.h>
6562306a36Sopenharmony_ci#include <linux/crash_dump.h>
6662306a36Sopenharmony_ci#include <net/udp_tunnel.h>
6762306a36Sopenharmony_ci#include <net/xfrm.h>
6862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
6962306a36Sopenharmony_ci#include <net/tls.h>
7062306a36Sopenharmony_ci#endif
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#include "cxgb4.h"
7362306a36Sopenharmony_ci#include "cxgb4_filter.h"
7462306a36Sopenharmony_ci#include "t4_regs.h"
7562306a36Sopenharmony_ci#include "t4_values.h"
7662306a36Sopenharmony_ci#include "t4_msg.h"
7762306a36Sopenharmony_ci#include "t4fw_api.h"
7862306a36Sopenharmony_ci#include "t4fw_version.h"
7962306a36Sopenharmony_ci#include "cxgb4_dcb.h"
8062306a36Sopenharmony_ci#include "srq.h"
8162306a36Sopenharmony_ci#include "cxgb4_debugfs.h"
8262306a36Sopenharmony_ci#include "clip_tbl.h"
8362306a36Sopenharmony_ci#include "l2t.h"
8462306a36Sopenharmony_ci#include "smt.h"
8562306a36Sopenharmony_ci#include "sched.h"
8662306a36Sopenharmony_ci#include "cxgb4_tc_u32.h"
8762306a36Sopenharmony_ci#include "cxgb4_tc_flower.h"
8862306a36Sopenharmony_ci#include "cxgb4_tc_mqprio.h"
8962306a36Sopenharmony_ci#include "cxgb4_tc_matchall.h"
9062306a36Sopenharmony_ci#include "cxgb4_ptp.h"
9162306a36Sopenharmony_ci#include "cxgb4_cudbg.h"
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cichar cxgb4_driver_name[] = KBUILD_MODNAME;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define DRV_DESC "Chelsio T4/T5/T6 Network Driver"
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
9862306a36Sopenharmony_ci			 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
9962306a36Sopenharmony_ci			 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* Macros needed to support the PCI Device ID Table ...
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_ci#define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \
10462306a36Sopenharmony_ci	static const struct pci_device_id cxgb4_pci_tbl[] = {
10562306a36Sopenharmony_ci#define CXGB4_UNIFIED_PF 0x4
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define CH_PCI_DEVICE_ID_FUNCTION CXGB4_UNIFIED_PF
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* Include PCI Device IDs for both PF4 and PF0-3 so our PCI probe() routine is
11062306a36Sopenharmony_ci * called for both.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_ci#define CH_PCI_DEVICE_ID_FUNCTION2 0x0
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define CH_PCI_ID_TABLE_ENTRY(devid) \
11562306a36Sopenharmony_ci		{PCI_VDEVICE(CHELSIO, (devid)), CXGB4_UNIFIED_PF}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define CH_PCI_DEVICE_ID_TABLE_DEFINE_END \
11862306a36Sopenharmony_ci		{ 0, } \
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#include "t4_pci_id_tbl.h"
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define FW4_FNAME "cxgb4/t4fw.bin"
12462306a36Sopenharmony_ci#define FW5_FNAME "cxgb4/t5fw.bin"
12562306a36Sopenharmony_ci#define FW6_FNAME "cxgb4/t6fw.bin"
12662306a36Sopenharmony_ci#define FW4_CFNAME "cxgb4/t4-config.txt"
12762306a36Sopenharmony_ci#define FW5_CFNAME "cxgb4/t5-config.txt"
12862306a36Sopenharmony_ci#define FW6_CFNAME "cxgb4/t6-config.txt"
12962306a36Sopenharmony_ci#define PHY_AQ1202_FIRMWARE "cxgb4/aq1202_fw.cld"
13062306a36Sopenharmony_ci#define PHY_BCM84834_FIRMWARE "cxgb4/bcm8483.bin"
13162306a36Sopenharmony_ci#define PHY_AQ1202_DEVICEID 0x4409
13262306a36Sopenharmony_ci#define PHY_BCM84834_DEVICEID 0x4486
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESC);
13562306a36Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications");
13662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
13762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl);
13862306a36Sopenharmony_ciMODULE_FIRMWARE(FW4_FNAME);
13962306a36Sopenharmony_ciMODULE_FIRMWARE(FW5_FNAME);
14062306a36Sopenharmony_ciMODULE_FIRMWARE(FW6_FNAME);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/*
14362306a36Sopenharmony_ci * The driver uses the best interrupt scheme available on a platform in the
14462306a36Sopenharmony_ci * order MSI-X, MSI, legacy INTx interrupts.  This parameter determines which
14562306a36Sopenharmony_ci * of these schemes the driver may consider as follows:
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * msi = 2: choose from among all three options
14862306a36Sopenharmony_ci * msi = 1: only consider MSI and INTx interrupts
14962306a36Sopenharmony_ci * msi = 0: force INTx interrupts
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_cistatic int msi = 2;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cimodule_param(msi, int, 0644);
15462306a36Sopenharmony_ciMODULE_PARM_DESC(msi, "whether to use INTx (0), MSI (1) or MSI-X (2)");
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci * Normally we tell the chip to deliver Ingress Packets into our DMA buffers
15862306a36Sopenharmony_ci * offset by 2 bytes in order to have the IP headers line up on 4-byte
15962306a36Sopenharmony_ci * boundaries.  This is a requirement for many architectures which will throw
16062306a36Sopenharmony_ci * a machine check fault if an attempt is made to access one of the 4-byte IP
16162306a36Sopenharmony_ci * header fields on a non-4-byte boundary.  And it's a major performance issue
16262306a36Sopenharmony_ci * even on some architectures which allow it like some implementations of the
16362306a36Sopenharmony_ci * x86 ISA.  However, some architectures don't mind this and for some very
16462306a36Sopenharmony_ci * edge-case performance sensitive applications (like forwarding large volumes
16562306a36Sopenharmony_ci * of small packets), setting this DMA offset to 0 will decrease the number of
16662306a36Sopenharmony_ci * PCI-E Bus transfers enough to measurably affect performance.
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistatic int rx_dma_offset = 2;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* TX Queue select used to determine what algorithm to use for selecting TX
17162306a36Sopenharmony_ci * queue. Select between the kernel provided function (select_queue=0) or user
17262306a36Sopenharmony_ci * cxgb_select_queue function (select_queue=1)
17362306a36Sopenharmony_ci *
17462306a36Sopenharmony_ci * Default: select_queue=0
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_cistatic int select_queue;
17762306a36Sopenharmony_cimodule_param(select_queue, int, 0644);
17862306a36Sopenharmony_ciMODULE_PARM_DESC(select_queue,
17962306a36Sopenharmony_ci		 "Select between kernel provided method of selecting or driver method of selecting TX queue. Default is kernel method.");
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic struct dentry *cxgb4_debugfs_root;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ciLIST_HEAD(adapter_list);
18462306a36Sopenharmony_ciDEFINE_MUTEX(uld_mutex);
18562306a36Sopenharmony_ciLIST_HEAD(uld_list);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int cfg_queues(struct adapter *adap);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic void link_report(struct net_device *dev)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	if (!netif_carrier_ok(dev))
19262306a36Sopenharmony_ci		netdev_info(dev, "link down\n");
19362306a36Sopenharmony_ci	else {
19462306a36Sopenharmony_ci		static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" };
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		const char *s;
19762306a36Sopenharmony_ci		const struct port_info *p = netdev_priv(dev);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		switch (p->link_cfg.speed) {
20062306a36Sopenharmony_ci		case 100:
20162306a36Sopenharmony_ci			s = "100Mbps";
20262306a36Sopenharmony_ci			break;
20362306a36Sopenharmony_ci		case 1000:
20462306a36Sopenharmony_ci			s = "1Gbps";
20562306a36Sopenharmony_ci			break;
20662306a36Sopenharmony_ci		case 10000:
20762306a36Sopenharmony_ci			s = "10Gbps";
20862306a36Sopenharmony_ci			break;
20962306a36Sopenharmony_ci		case 25000:
21062306a36Sopenharmony_ci			s = "25Gbps";
21162306a36Sopenharmony_ci			break;
21262306a36Sopenharmony_ci		case 40000:
21362306a36Sopenharmony_ci			s = "40Gbps";
21462306a36Sopenharmony_ci			break;
21562306a36Sopenharmony_ci		case 50000:
21662306a36Sopenharmony_ci			s = "50Gbps";
21762306a36Sopenharmony_ci			break;
21862306a36Sopenharmony_ci		case 100000:
21962306a36Sopenharmony_ci			s = "100Gbps";
22062306a36Sopenharmony_ci			break;
22162306a36Sopenharmony_ci		default:
22262306a36Sopenharmony_ci			pr_info("%s: unsupported speed: %d\n",
22362306a36Sopenharmony_ci				dev->name, p->link_cfg.speed);
22462306a36Sopenharmony_ci			return;
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s,
22862306a36Sopenharmony_ci			    fc[p->link_cfg.fc]);
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
23362306a36Sopenharmony_ci/* Set up/tear down Data Center Bridging Priority mapping for a net device. */
23462306a36Sopenharmony_cistatic void dcb_tx_queue_prio_enable(struct net_device *dev, int enable)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
23762306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
23862306a36Sopenharmony_ci	struct sge_eth_txq *txq = &adap->sge.ethtxq[pi->first_qset];
23962306a36Sopenharmony_ci	int i;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* We use a simple mapping of Port TX Queue Index to DCB
24262306a36Sopenharmony_ci	 * Priority when we're enabling DCB.
24362306a36Sopenharmony_ci	 */
24462306a36Sopenharmony_ci	for (i = 0; i < pi->nqsets; i++, txq++) {
24562306a36Sopenharmony_ci		u32 name, value;
24662306a36Sopenharmony_ci		int err;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		name = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) |
24962306a36Sopenharmony_ci			FW_PARAMS_PARAM_X_V(
25062306a36Sopenharmony_ci				FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH) |
25162306a36Sopenharmony_ci			FW_PARAMS_PARAM_YZ_V(txq->q.cntxt_id));
25262306a36Sopenharmony_ci		value = enable ? i : 0xffffffff;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		/* Since we can be called while atomic (from "interrupt
25562306a36Sopenharmony_ci		 * level") we need to issue the Set Parameters Commannd
25662306a36Sopenharmony_ci		 * without sleeping (timeout < 0).
25762306a36Sopenharmony_ci		 */
25862306a36Sopenharmony_ci		err = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1,
25962306a36Sopenharmony_ci					    &name, &value,
26062306a36Sopenharmony_ci					    -FW_CMD_MAX_TIMEOUT);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		if (err)
26362306a36Sopenharmony_ci			dev_err(adap->pdev_dev,
26462306a36Sopenharmony_ci				"Can't %s DCB Priority on port %d, TX Queue %d: err=%d\n",
26562306a36Sopenharmony_ci				enable ? "set" : "unset", pi->port_id, i, -err);
26662306a36Sopenharmony_ci		else
26762306a36Sopenharmony_ci			txq->dcb_prio = enable ? value : 0;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ciint cxgb4_dcb_enabled(const struct net_device *dev)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (!pi->dcb.enabled)
27662306a36Sopenharmony_ci		return 0;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return ((pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED) ||
27962306a36Sopenharmony_ci		(pi->dcb.state == CXGB4_DCB_STATE_HOST));
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_civoid t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct net_device *dev = adapter->port[port_id];
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* Skip changes from disabled ports. */
28862306a36Sopenharmony_ci	if (netif_running(dev) && link_stat != netif_carrier_ok(dev)) {
28962306a36Sopenharmony_ci		if (link_stat)
29062306a36Sopenharmony_ci			netif_carrier_on(dev);
29162306a36Sopenharmony_ci		else {
29262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
29362306a36Sopenharmony_ci			if (cxgb4_dcb_enabled(dev)) {
29462306a36Sopenharmony_ci				cxgb4_dcb_reset(dev);
29562306a36Sopenharmony_ci				dcb_tx_queue_prio_enable(dev, false);
29662306a36Sopenharmony_ci			}
29762306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */
29862306a36Sopenharmony_ci			netif_carrier_off(dev);
29962306a36Sopenharmony_ci		}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		link_report(dev);
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_civoid t4_os_portmod_changed(struct adapter *adap, int port_id)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	static const char *mod_str[] = {
30862306a36Sopenharmony_ci		NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM"
30962306a36Sopenharmony_ci	};
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	struct net_device *dev = adap->port[port_id];
31262306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
31562306a36Sopenharmony_ci		netdev_info(dev, "port module unplugged\n");
31662306a36Sopenharmony_ci	else if (pi->mod_type < ARRAY_SIZE(mod_str))
31762306a36Sopenharmony_ci		netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]);
31862306a36Sopenharmony_ci	else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
31962306a36Sopenharmony_ci		netdev_info(dev, "%s: unsupported port module inserted\n",
32062306a36Sopenharmony_ci			    dev->name);
32162306a36Sopenharmony_ci	else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
32262306a36Sopenharmony_ci		netdev_info(dev, "%s: unknown port module inserted\n",
32362306a36Sopenharmony_ci			    dev->name);
32462306a36Sopenharmony_ci	else if (pi->mod_type == FW_PORT_MOD_TYPE_ERROR)
32562306a36Sopenharmony_ci		netdev_info(dev, "%s: transceiver module error\n", dev->name);
32662306a36Sopenharmony_ci	else
32762306a36Sopenharmony_ci		netdev_info(dev, "%s: unknown module type %d inserted\n",
32862306a36Sopenharmony_ci			    dev->name, pi->mod_type);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* If the interface is running, then we'll need any "sticky" Link
33162306a36Sopenharmony_ci	 * Parameters redone with a new Transceiver Module.
33262306a36Sopenharmony_ci	 */
33362306a36Sopenharmony_ci	pi->link_cfg.redo_l1cfg = netif_running(dev);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ciint dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
33762306a36Sopenharmony_cimodule_param(dbfifo_int_thresh, int, 0644);
33862306a36Sopenharmony_ciMODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/*
34162306a36Sopenharmony_ci * usecs to sleep while draining the dbfifo
34262306a36Sopenharmony_ci */
34362306a36Sopenharmony_cistatic int dbfifo_drain_delay = 1000;
34462306a36Sopenharmony_cimodule_param(dbfifo_drain_delay, int, 0644);
34562306a36Sopenharmony_ciMODULE_PARM_DESC(dbfifo_drain_delay,
34662306a36Sopenharmony_ci		 "usecs to sleep while draining the dbfifo");
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic inline int cxgb4_set_addr_hash(struct port_info *pi)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
35162306a36Sopenharmony_ci	u64 vec = 0;
35262306a36Sopenharmony_ci	bool ucast = false;
35362306a36Sopenharmony_ci	struct hash_mac_addr *entry;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Calculate the hash vector for the updated list and program it */
35662306a36Sopenharmony_ci	list_for_each_entry(entry, &adap->mac_hlist, list) {
35762306a36Sopenharmony_ci		ucast |= is_unicast_ether_addr(entry->addr);
35862306a36Sopenharmony_ci		vec |= (1ULL << hash_mac_addr(entry->addr));
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci	return t4_set_addr_hash(adap, adap->mbox, pi->viid, ucast,
36162306a36Sopenharmony_ci				vec, false);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic int cxgb4_mac_sync(struct net_device *netdev, const u8 *mac_addr)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
36762306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
36862306a36Sopenharmony_ci	int ret;
36962306a36Sopenharmony_ci	u64 mhash = 0;
37062306a36Sopenharmony_ci	u64 uhash = 0;
37162306a36Sopenharmony_ci	/* idx stores the index of allocated filters,
37262306a36Sopenharmony_ci	 * its size should be modified based on the number of
37362306a36Sopenharmony_ci	 * MAC addresses that we allocate filters for
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	u16 idx[1] = {};
37762306a36Sopenharmony_ci	bool free = false;
37862306a36Sopenharmony_ci	bool ucast = is_unicast_ether_addr(mac_addr);
37962306a36Sopenharmony_ci	const u8 *maclist[1] = {mac_addr};
38062306a36Sopenharmony_ci	struct hash_mac_addr *new_entry;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	ret = cxgb4_alloc_mac_filt(adap, pi->viid, free, 1, maclist,
38362306a36Sopenharmony_ci				   idx, ucast ? &uhash : &mhash, false);
38462306a36Sopenharmony_ci	if (ret < 0)
38562306a36Sopenharmony_ci		goto out;
38662306a36Sopenharmony_ci	/* if hash != 0, then add the addr to hash addr list
38762306a36Sopenharmony_ci	 * so on the end we will calculate the hash for the
38862306a36Sopenharmony_ci	 * list and program it
38962306a36Sopenharmony_ci	 */
39062306a36Sopenharmony_ci	if (uhash || mhash) {
39162306a36Sopenharmony_ci		new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
39262306a36Sopenharmony_ci		if (!new_entry)
39362306a36Sopenharmony_ci			return -ENOMEM;
39462306a36Sopenharmony_ci		ether_addr_copy(new_entry->addr, mac_addr);
39562306a36Sopenharmony_ci		list_add_tail(&new_entry->list, &adap->mac_hlist);
39662306a36Sopenharmony_ci		ret = cxgb4_set_addr_hash(pi);
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ciout:
39962306a36Sopenharmony_ci	return ret < 0 ? ret : 0;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int cxgb4_mac_unsync(struct net_device *netdev, const u8 *mac_addr)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
40562306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
40662306a36Sopenharmony_ci	int ret;
40762306a36Sopenharmony_ci	const u8 *maclist[1] = {mac_addr};
40862306a36Sopenharmony_ci	struct hash_mac_addr *entry, *tmp;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* If the MAC address to be removed is in the hash addr
41162306a36Sopenharmony_ci	 * list, delete it from the list and update hash vector
41262306a36Sopenharmony_ci	 */
41362306a36Sopenharmony_ci	list_for_each_entry_safe(entry, tmp, &adap->mac_hlist, list) {
41462306a36Sopenharmony_ci		if (ether_addr_equal(entry->addr, mac_addr)) {
41562306a36Sopenharmony_ci			list_del(&entry->list);
41662306a36Sopenharmony_ci			kfree(entry);
41762306a36Sopenharmony_ci			return cxgb4_set_addr_hash(pi);
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	ret = cxgb4_free_mac_filt(adap, pi->viid, 1, maclist, false);
42262306a36Sopenharmony_ci	return ret < 0 ? -EINVAL : 0;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci/*
42662306a36Sopenharmony_ci * Set Rx properties of a port, such as promiscruity, address filters, and MTU.
42762306a36Sopenharmony_ci * If @mtu is -1 it is left unchanged.
42862306a36Sopenharmony_ci */
42962306a36Sopenharmony_cistatic int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
43262306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	__dev_uc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync);
43562306a36Sopenharmony_ci	__dev_mc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return t4_set_rxmode(adapter, adapter->mbox, pi->viid, pi->viid_mirror,
43862306a36Sopenharmony_ci			     mtu, (dev->flags & IFF_PROMISC) ? 1 : 0,
43962306a36Sopenharmony_ci			     (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
44062306a36Sopenharmony_ci			     sleep_ok);
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci/**
44462306a36Sopenharmony_ci *	cxgb4_change_mac - Update match filter for a MAC address.
44562306a36Sopenharmony_ci *	@pi: the port_info
44662306a36Sopenharmony_ci *	@viid: the VI id
44762306a36Sopenharmony_ci *	@tcam_idx: TCAM index of existing filter for old value of MAC address,
44862306a36Sopenharmony_ci *		   or -1
44962306a36Sopenharmony_ci *	@addr: the new MAC address value
45062306a36Sopenharmony_ci *	@persist: whether a new MAC allocation should be persistent
45162306a36Sopenharmony_ci *	@smt_idx: the destination to store the new SMT index.
45262306a36Sopenharmony_ci *
45362306a36Sopenharmony_ci *	Modifies an MPS filter and sets it to the new MAC address if
45462306a36Sopenharmony_ci *	@tcam_idx >= 0, or adds the MAC address to a new filter if
45562306a36Sopenharmony_ci *	@tcam_idx < 0. In the latter case the address is added persistently
45662306a36Sopenharmony_ci *	if @persist is %true.
45762306a36Sopenharmony_ci *	Addresses are programmed to hash region, if tcam runs out of entries.
45862306a36Sopenharmony_ci *
45962306a36Sopenharmony_ci */
46062306a36Sopenharmony_ciint cxgb4_change_mac(struct port_info *pi, unsigned int viid,
46162306a36Sopenharmony_ci		     int *tcam_idx, const u8 *addr, bool persist,
46262306a36Sopenharmony_ci		     u8 *smt_idx)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
46562306a36Sopenharmony_ci	struct hash_mac_addr *entry, *new_entry;
46662306a36Sopenharmony_ci	int ret;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	ret = t4_change_mac(adapter, adapter->mbox, viid,
46962306a36Sopenharmony_ci			    *tcam_idx, addr, persist, smt_idx);
47062306a36Sopenharmony_ci	/* We ran out of TCAM entries. try programming hash region. */
47162306a36Sopenharmony_ci	if (ret == -ENOMEM) {
47262306a36Sopenharmony_ci		/* If the MAC address to be updated is in the hash addr
47362306a36Sopenharmony_ci		 * list, update it from the list
47462306a36Sopenharmony_ci		 */
47562306a36Sopenharmony_ci		list_for_each_entry(entry, &adapter->mac_hlist, list) {
47662306a36Sopenharmony_ci			if (entry->iface_mac) {
47762306a36Sopenharmony_ci				ether_addr_copy(entry->addr, addr);
47862306a36Sopenharmony_ci				goto set_hash;
47962306a36Sopenharmony_ci			}
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci		new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
48262306a36Sopenharmony_ci		if (!new_entry)
48362306a36Sopenharmony_ci			return -ENOMEM;
48462306a36Sopenharmony_ci		ether_addr_copy(new_entry->addr, addr);
48562306a36Sopenharmony_ci		new_entry->iface_mac = true;
48662306a36Sopenharmony_ci		list_add_tail(&new_entry->list, &adapter->mac_hlist);
48762306a36Sopenharmony_ciset_hash:
48862306a36Sopenharmony_ci		ret = cxgb4_set_addr_hash(pi);
48962306a36Sopenharmony_ci	} else if (ret >= 0) {
49062306a36Sopenharmony_ci		*tcam_idx = ret;
49162306a36Sopenharmony_ci		ret = 0;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return ret;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/*
49862306a36Sopenharmony_ci *	link_start - enable a port
49962306a36Sopenharmony_ci *	@dev: the port to enable
50062306a36Sopenharmony_ci *
50162306a36Sopenharmony_ci *	Performs the MAC and PHY actions needed to enable a port.
50262306a36Sopenharmony_ci */
50362306a36Sopenharmony_cistatic int link_start(struct net_device *dev)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
50662306a36Sopenharmony_ci	unsigned int mb = pi->adapter->mbox;
50762306a36Sopenharmony_ci	int ret;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/*
51062306a36Sopenharmony_ci	 * We do not set address filters and promiscuity here, the stack does
51162306a36Sopenharmony_ci	 * that step explicitly.
51262306a36Sopenharmony_ci	 */
51362306a36Sopenharmony_ci	ret = t4_set_rxmode(pi->adapter, mb, pi->viid, pi->viid_mirror,
51462306a36Sopenharmony_ci			    dev->mtu, -1, -1, -1,
51562306a36Sopenharmony_ci			    !!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true);
51662306a36Sopenharmony_ci	if (ret == 0)
51762306a36Sopenharmony_ci		ret = cxgb4_update_mac_filt(pi, pi->viid, &pi->xact_addr_filt,
51862306a36Sopenharmony_ci					    dev->dev_addr, true, &pi->smt_idx);
51962306a36Sopenharmony_ci	if (ret == 0)
52062306a36Sopenharmony_ci		ret = t4_link_l1cfg(pi->adapter, mb, pi->tx_chan,
52162306a36Sopenharmony_ci				    &pi->link_cfg);
52262306a36Sopenharmony_ci	if (ret == 0) {
52362306a36Sopenharmony_ci		local_bh_disable();
52462306a36Sopenharmony_ci		ret = t4_enable_pi_params(pi->adapter, mb, pi, true,
52562306a36Sopenharmony_ci					  true, CXGB4_DCB_ENABLED);
52662306a36Sopenharmony_ci		local_bh_enable();
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	return ret;
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
53362306a36Sopenharmony_ci/* Handle a Data Center Bridging update message from the firmware. */
53462306a36Sopenharmony_cistatic void dcb_rpl(struct adapter *adap, const struct fw_port_cmd *pcmd)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	int port = FW_PORT_CMD_PORTID_G(ntohl(pcmd->op_to_portid));
53762306a36Sopenharmony_ci	struct net_device *dev = adap->port[adap->chan_map[port]];
53862306a36Sopenharmony_ci	int old_dcb_enabled = cxgb4_dcb_enabled(dev);
53962306a36Sopenharmony_ci	int new_dcb_enabled;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	cxgb4_dcb_handle_fw_update(adap, pcmd);
54262306a36Sopenharmony_ci	new_dcb_enabled = cxgb4_dcb_enabled(dev);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* If the DCB has become enabled or disabled on the port then we're
54562306a36Sopenharmony_ci	 * going to need to set up/tear down DCB Priority parameters for the
54662306a36Sopenharmony_ci	 * TX Queues associated with the port.
54762306a36Sopenharmony_ci	 */
54862306a36Sopenharmony_ci	if (new_dcb_enabled != old_dcb_enabled)
54962306a36Sopenharmony_ci		dcb_tx_queue_prio_enable(dev, new_dcb_enabled);
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci/* Response queue handler for the FW event queue.
55462306a36Sopenharmony_ci */
55562306a36Sopenharmony_cistatic int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
55662306a36Sopenharmony_ci			  const struct pkt_gl *gl)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	u8 opcode = ((const struct rss_header *)rsp)->opcode;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	rsp++;                                          /* skip RSS header */
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG.
56362306a36Sopenharmony_ci	 */
56462306a36Sopenharmony_ci	if (unlikely(opcode == CPL_FW4_MSG &&
56562306a36Sopenharmony_ci	   ((const struct cpl_fw4_msg *)rsp)->type == FW_TYPE_RSSCPL)) {
56662306a36Sopenharmony_ci		rsp++;
56762306a36Sopenharmony_ci		opcode = ((const struct rss_header *)rsp)->opcode;
56862306a36Sopenharmony_ci		rsp++;
56962306a36Sopenharmony_ci		if (opcode != CPL_SGE_EGR_UPDATE) {
57062306a36Sopenharmony_ci			dev_err(q->adap->pdev_dev, "unexpected FW4/CPL %#x on FW event queue\n"
57162306a36Sopenharmony_ci				, opcode);
57262306a36Sopenharmony_ci			goto out;
57362306a36Sopenharmony_ci		}
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (likely(opcode == CPL_SGE_EGR_UPDATE)) {
57762306a36Sopenharmony_ci		const struct cpl_sge_egr_update *p = (void *)rsp;
57862306a36Sopenharmony_ci		unsigned int qid = EGR_QID_G(ntohl(p->opcode_qid));
57962306a36Sopenharmony_ci		struct sge_txq *txq;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci		txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start];
58262306a36Sopenharmony_ci		txq->restarts++;
58362306a36Sopenharmony_ci		if (txq->q_type == CXGB4_TXQ_ETH) {
58462306a36Sopenharmony_ci			struct sge_eth_txq *eq;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci			eq = container_of(txq, struct sge_eth_txq, q);
58762306a36Sopenharmony_ci			t4_sge_eth_txq_egress_update(q->adap, eq, -1);
58862306a36Sopenharmony_ci		} else {
58962306a36Sopenharmony_ci			struct sge_uld_txq *oq;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci			oq = container_of(txq, struct sge_uld_txq, q);
59262306a36Sopenharmony_ci			tasklet_schedule(&oq->qresume_tsk);
59362306a36Sopenharmony_ci		}
59462306a36Sopenharmony_ci	} else if (opcode == CPL_FW6_MSG || opcode == CPL_FW4_MSG) {
59562306a36Sopenharmony_ci		const struct cpl_fw6_msg *p = (void *)rsp;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
59862306a36Sopenharmony_ci		const struct fw_port_cmd *pcmd = (const void *)p->data;
59962306a36Sopenharmony_ci		unsigned int cmd = FW_CMD_OP_G(ntohl(pcmd->op_to_portid));
60062306a36Sopenharmony_ci		unsigned int action =
60162306a36Sopenharmony_ci			FW_PORT_CMD_ACTION_G(ntohl(pcmd->action_to_len16));
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci		if (cmd == FW_PORT_CMD &&
60462306a36Sopenharmony_ci		    (action == FW_PORT_ACTION_GET_PORT_INFO ||
60562306a36Sopenharmony_ci		     action == FW_PORT_ACTION_GET_PORT_INFO32)) {
60662306a36Sopenharmony_ci			int port = FW_PORT_CMD_PORTID_G(
60762306a36Sopenharmony_ci					be32_to_cpu(pcmd->op_to_portid));
60862306a36Sopenharmony_ci			struct net_device *dev;
60962306a36Sopenharmony_ci			int dcbxdis, state_input;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci			dev = q->adap->port[q->adap->chan_map[port]];
61262306a36Sopenharmony_ci			dcbxdis = (action == FW_PORT_ACTION_GET_PORT_INFO
61362306a36Sopenharmony_ci			  ? !!(pcmd->u.info.dcbxdis_pkd & FW_PORT_CMD_DCBXDIS_F)
61462306a36Sopenharmony_ci			  : !!(be32_to_cpu(pcmd->u.info32.lstatus32_to_cbllen32)
61562306a36Sopenharmony_ci			       & FW_PORT_CMD_DCBXDIS32_F));
61662306a36Sopenharmony_ci			state_input = (dcbxdis
61762306a36Sopenharmony_ci				       ? CXGB4_DCB_INPUT_FW_DISABLED
61862306a36Sopenharmony_ci				       : CXGB4_DCB_INPUT_FW_ENABLED);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci			cxgb4_dcb_state_fsm(dev, state_input);
62162306a36Sopenharmony_ci		}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		if (cmd == FW_PORT_CMD &&
62462306a36Sopenharmony_ci		    action == FW_PORT_ACTION_L2_DCB_CFG)
62562306a36Sopenharmony_ci			dcb_rpl(q->adap, pcmd);
62662306a36Sopenharmony_ci		else
62762306a36Sopenharmony_ci#endif
62862306a36Sopenharmony_ci			if (p->type == 0)
62962306a36Sopenharmony_ci				t4_handle_fw_rpl(q->adap, p->data);
63062306a36Sopenharmony_ci	} else if (opcode == CPL_L2T_WRITE_RPL) {
63162306a36Sopenharmony_ci		const struct cpl_l2t_write_rpl *p = (void *)rsp;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci		do_l2t_write_rpl(q->adap, p);
63462306a36Sopenharmony_ci	} else if (opcode == CPL_SMT_WRITE_RPL) {
63562306a36Sopenharmony_ci		const struct cpl_smt_write_rpl *p = (void *)rsp;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		do_smt_write_rpl(q->adap, p);
63862306a36Sopenharmony_ci	} else if (opcode == CPL_SET_TCB_RPL) {
63962306a36Sopenharmony_ci		const struct cpl_set_tcb_rpl *p = (void *)rsp;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci		filter_rpl(q->adap, p);
64262306a36Sopenharmony_ci	} else if (opcode == CPL_ACT_OPEN_RPL) {
64362306a36Sopenharmony_ci		const struct cpl_act_open_rpl *p = (void *)rsp;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		hash_filter_rpl(q->adap, p);
64662306a36Sopenharmony_ci	} else if (opcode == CPL_ABORT_RPL_RSS) {
64762306a36Sopenharmony_ci		const struct cpl_abort_rpl_rss *p = (void *)rsp;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci		hash_del_filter_rpl(q->adap, p);
65062306a36Sopenharmony_ci	} else if (opcode == CPL_SRQ_TABLE_RPL) {
65162306a36Sopenharmony_ci		const struct cpl_srq_table_rpl *p = (void *)rsp;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci		do_srq_table_rpl(q->adap, p);
65462306a36Sopenharmony_ci	} else
65562306a36Sopenharmony_ci		dev_err(q->adap->pdev_dev,
65662306a36Sopenharmony_ci			"unexpected CPL %#x on FW event queue\n", opcode);
65762306a36Sopenharmony_ciout:
65862306a36Sopenharmony_ci	return 0;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic void disable_msi(struct adapter *adapter)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	if (adapter->flags & CXGB4_USING_MSIX) {
66462306a36Sopenharmony_ci		pci_disable_msix(adapter->pdev);
66562306a36Sopenharmony_ci		adapter->flags &= ~CXGB4_USING_MSIX;
66662306a36Sopenharmony_ci	} else if (adapter->flags & CXGB4_USING_MSI) {
66762306a36Sopenharmony_ci		pci_disable_msi(adapter->pdev);
66862306a36Sopenharmony_ci		adapter->flags &= ~CXGB4_USING_MSI;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci/*
67362306a36Sopenharmony_ci * Interrupt handler for non-data events used with MSI-X.
67462306a36Sopenharmony_ci */
67562306a36Sopenharmony_cistatic irqreturn_t t4_nondata_intr(int irq, void *cookie)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	struct adapter *adap = cookie;
67862306a36Sopenharmony_ci	u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A));
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (v & PFSW_F) {
68162306a36Sopenharmony_ci		adap->swintr = 1;
68262306a36Sopenharmony_ci		t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A), v);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci	if (adap->flags & CXGB4_MASTER_PF)
68562306a36Sopenharmony_ci		t4_slow_intr_handler(adap);
68662306a36Sopenharmony_ci	return IRQ_HANDLED;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ciint cxgb4_set_msix_aff(struct adapter *adap, unsigned short vec,
69062306a36Sopenharmony_ci		       cpumask_var_t *aff_mask, int idx)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	int rv;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	if (!zalloc_cpumask_var(aff_mask, GFP_KERNEL)) {
69562306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "alloc_cpumask_var failed\n");
69662306a36Sopenharmony_ci		return -ENOMEM;
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	cpumask_set_cpu(cpumask_local_spread(idx, dev_to_node(adap->pdev_dev)),
70062306a36Sopenharmony_ci			*aff_mask);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	rv = irq_set_affinity_hint(vec, *aff_mask);
70362306a36Sopenharmony_ci	if (rv)
70462306a36Sopenharmony_ci		dev_warn(adap->pdev_dev,
70562306a36Sopenharmony_ci			 "irq_set_affinity_hint %u failed %d\n",
70662306a36Sopenharmony_ci			 vec, rv);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	return 0;
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_civoid cxgb4_clear_msix_aff(unsigned short vec, cpumask_var_t aff_mask)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	irq_set_affinity_hint(vec, NULL);
71462306a36Sopenharmony_ci	free_cpumask_var(aff_mask);
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic int request_msix_queue_irqs(struct adapter *adap)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	struct sge *s = &adap->sge;
72062306a36Sopenharmony_ci	struct msix_info *minfo;
72162306a36Sopenharmony_ci	int err, ethqidx;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	if (s->fwevtq_msix_idx < 0)
72462306a36Sopenharmony_ci		return -ENOMEM;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	err = request_irq(adap->msix_info[s->fwevtq_msix_idx].vec,
72762306a36Sopenharmony_ci			  t4_sge_intr_msix, 0,
72862306a36Sopenharmony_ci			  adap->msix_info[s->fwevtq_msix_idx].desc,
72962306a36Sopenharmony_ci			  &s->fw_evtq);
73062306a36Sopenharmony_ci	if (err)
73162306a36Sopenharmony_ci		return err;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	for_each_ethrxq(s, ethqidx) {
73462306a36Sopenharmony_ci		minfo = s->ethrxq[ethqidx].msix;
73562306a36Sopenharmony_ci		err = request_irq(minfo->vec,
73662306a36Sopenharmony_ci				  t4_sge_intr_msix, 0,
73762306a36Sopenharmony_ci				  minfo->desc,
73862306a36Sopenharmony_ci				  &s->ethrxq[ethqidx].rspq);
73962306a36Sopenharmony_ci		if (err)
74062306a36Sopenharmony_ci			goto unwind;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		cxgb4_set_msix_aff(adap, minfo->vec,
74362306a36Sopenharmony_ci				   &minfo->aff_mask, ethqidx);
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci	return 0;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ciunwind:
74862306a36Sopenharmony_ci	while (--ethqidx >= 0) {
74962306a36Sopenharmony_ci		minfo = s->ethrxq[ethqidx].msix;
75062306a36Sopenharmony_ci		cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask);
75162306a36Sopenharmony_ci		free_irq(minfo->vec, &s->ethrxq[ethqidx].rspq);
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci	free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq);
75462306a36Sopenharmony_ci	return err;
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic void free_msix_queue_irqs(struct adapter *adap)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	struct sge *s = &adap->sge;
76062306a36Sopenharmony_ci	struct msix_info *minfo;
76162306a36Sopenharmony_ci	int i;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq);
76462306a36Sopenharmony_ci	for_each_ethrxq(s, i) {
76562306a36Sopenharmony_ci		minfo = s->ethrxq[i].msix;
76662306a36Sopenharmony_ci		cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask);
76762306a36Sopenharmony_ci		free_irq(minfo->vec, &s->ethrxq[i].rspq);
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic int setup_ppod_edram(struct adapter *adap)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	unsigned int param, val;
77462306a36Sopenharmony_ci	int ret;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	/* Driver sends FW_PARAMS_PARAM_DEV_PPOD_EDRAM read command to check
77762306a36Sopenharmony_ci	 * if firmware supports ppod edram feature or not. If firmware
77862306a36Sopenharmony_ci	 * returns 1, then driver can enable this feature by sending
77962306a36Sopenharmony_ci	 * FW_PARAMS_PARAM_DEV_PPOD_EDRAM write command with value 1 to
78062306a36Sopenharmony_ci	 * enable ppod edram feature.
78162306a36Sopenharmony_ci	 */
78262306a36Sopenharmony_ci	param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
78362306a36Sopenharmony_ci		FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PPOD_EDRAM));
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, &param, &val);
78662306a36Sopenharmony_ci	if (ret < 0) {
78762306a36Sopenharmony_ci		dev_warn(adap->pdev_dev,
78862306a36Sopenharmony_ci			 "querying PPOD_EDRAM support failed: %d\n",
78962306a36Sopenharmony_ci			 ret);
79062306a36Sopenharmony_ci		return -1;
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	if (val != 1)
79462306a36Sopenharmony_ci		return -1;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, &param, &val);
79762306a36Sopenharmony_ci	if (ret < 0) {
79862306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
79962306a36Sopenharmony_ci			"setting PPOD_EDRAM failed: %d\n", ret);
80062306a36Sopenharmony_ci		return -1;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci	return 0;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic void adap_config_hpfilter(struct adapter *adapter)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	u32 param, val = 0;
80862306a36Sopenharmony_ci	int ret;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/* Enable HP filter region. Older fw will fail this request and
81162306a36Sopenharmony_ci	 * it is fine.
81262306a36Sopenharmony_ci	 */
81362306a36Sopenharmony_ci	param = FW_PARAM_DEV(HPFILTER_REGION_SUPPORT);
81462306a36Sopenharmony_ci	ret = t4_set_params(adapter, adapter->mbox, adapter->pf, 0,
81562306a36Sopenharmony_ci			    1, &param, &val);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* An error means FW doesn't know about HP filter support,
81862306a36Sopenharmony_ci	 * it's not a problem, don't return an error.
81962306a36Sopenharmony_ci	 */
82062306a36Sopenharmony_ci	if (ret < 0)
82162306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
82262306a36Sopenharmony_ci			"HP filter region isn't supported by FW\n");
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic int cxgb4_config_rss(const struct port_info *pi, u16 *rss,
82662306a36Sopenharmony_ci			    u16 rss_size, u16 viid)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
82962306a36Sopenharmony_ci	int ret;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	ret = t4_config_rss_range(adap, adap->mbox, viid, 0, rss_size, rss,
83262306a36Sopenharmony_ci				  rss_size);
83362306a36Sopenharmony_ci	if (ret)
83462306a36Sopenharmony_ci		return ret;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* If Tunnel All Lookup isn't specified in the global RSS
83762306a36Sopenharmony_ci	 * Configuration, then we need to specify a default Ingress
83862306a36Sopenharmony_ci	 * Queue for any ingress packets which aren't hashed.  We'll
83962306a36Sopenharmony_ci	 * use our first ingress queue ...
84062306a36Sopenharmony_ci	 */
84162306a36Sopenharmony_ci	return t4_config_vi_rss(adap, adap->mbox, viid,
84262306a36Sopenharmony_ci				FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F |
84362306a36Sopenharmony_ci				FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F |
84462306a36Sopenharmony_ci				FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F |
84562306a36Sopenharmony_ci				FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F |
84662306a36Sopenharmony_ci				FW_RSS_VI_CONFIG_CMD_UDPEN_F,
84762306a36Sopenharmony_ci				rss[0]);
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci/**
85162306a36Sopenharmony_ci *	cxgb4_write_rss - write the RSS table for a given port
85262306a36Sopenharmony_ci *	@pi: the port
85362306a36Sopenharmony_ci *	@queues: array of queue indices for RSS
85462306a36Sopenharmony_ci *
85562306a36Sopenharmony_ci *	Sets up the portion of the HW RSS table for the port's VI to distribute
85662306a36Sopenharmony_ci *	packets to the Rx queues in @queues.
85762306a36Sopenharmony_ci *	Should never be called before setting up sge eth rx queues
85862306a36Sopenharmony_ci */
85962306a36Sopenharmony_ciint cxgb4_write_rss(const struct port_info *pi, const u16 *queues)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
86262306a36Sopenharmony_ci	const struct sge_eth_rxq *rxq;
86362306a36Sopenharmony_ci	int i, err;
86462306a36Sopenharmony_ci	u16 *rss;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	rxq = &adapter->sge.ethrxq[pi->first_qset];
86762306a36Sopenharmony_ci	rss = kmalloc_array(pi->rss_size, sizeof(u16), GFP_KERNEL);
86862306a36Sopenharmony_ci	if (!rss)
86962306a36Sopenharmony_ci		return -ENOMEM;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	/* map the queue indices to queue ids */
87262306a36Sopenharmony_ci	for (i = 0; i < pi->rss_size; i++, queues++)
87362306a36Sopenharmony_ci		rss[i] = rxq[*queues].rspq.abs_id;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	err = cxgb4_config_rss(pi, rss, pi->rss_size, pi->viid);
87662306a36Sopenharmony_ci	kfree(rss);
87762306a36Sopenharmony_ci	return err;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci/**
88162306a36Sopenharmony_ci *	setup_rss - configure RSS
88262306a36Sopenharmony_ci *	@adap: the adapter
88362306a36Sopenharmony_ci *
88462306a36Sopenharmony_ci *	Sets up RSS for each port.
88562306a36Sopenharmony_ci */
88662306a36Sopenharmony_cistatic int setup_rss(struct adapter *adap)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	int i, j, err;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	for_each_port(adap, i) {
89162306a36Sopenharmony_ci		const struct port_info *pi = adap2pinfo(adap, i);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci		/* Fill default values with equal distribution */
89462306a36Sopenharmony_ci		for (j = 0; j < pi->rss_size; j++)
89562306a36Sopenharmony_ci			pi->rss[j] = j % pi->nqsets;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci		err = cxgb4_write_rss(pi, pi->rss);
89862306a36Sopenharmony_ci		if (err)
89962306a36Sopenharmony_ci			return err;
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci	return 0;
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci/*
90562306a36Sopenharmony_ci * Return the channel of the ingress queue with the given qid.
90662306a36Sopenharmony_ci */
90762306a36Sopenharmony_cistatic unsigned int rxq_to_chan(const struct sge *p, unsigned int qid)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	qid -= p->ingr_start;
91062306a36Sopenharmony_ci	return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_civoid cxgb4_quiesce_rx(struct sge_rspq *q)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	if (q->handler)
91662306a36Sopenharmony_ci		napi_disable(&q->napi);
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci/*
92062306a36Sopenharmony_ci * Wait until all NAPI handlers are descheduled.
92162306a36Sopenharmony_ci */
92262306a36Sopenharmony_cistatic void quiesce_rx(struct adapter *adap)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	int i;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	for (i = 0; i < adap->sge.ingr_sz; i++) {
92762306a36Sopenharmony_ci		struct sge_rspq *q = adap->sge.ingr_map[i];
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		if (!q)
93062306a36Sopenharmony_ci			continue;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		cxgb4_quiesce_rx(q);
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci/* Disable interrupt and napi handler */
93762306a36Sopenharmony_cistatic void disable_interrupts(struct adapter *adap)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	struct sge *s = &adap->sge;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (adap->flags & CXGB4_FULL_INIT_DONE) {
94262306a36Sopenharmony_ci		t4_intr_disable(adap);
94362306a36Sopenharmony_ci		if (adap->flags & CXGB4_USING_MSIX) {
94462306a36Sopenharmony_ci			free_msix_queue_irqs(adap);
94562306a36Sopenharmony_ci			free_irq(adap->msix_info[s->nd_msix_idx].vec,
94662306a36Sopenharmony_ci				 adap);
94762306a36Sopenharmony_ci		} else {
94862306a36Sopenharmony_ci			free_irq(adap->pdev->irq, adap);
94962306a36Sopenharmony_ci		}
95062306a36Sopenharmony_ci		quiesce_rx(adap);
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_civoid cxgb4_enable_rx(struct adapter *adap, struct sge_rspq *q)
95562306a36Sopenharmony_ci{
95662306a36Sopenharmony_ci	if (q->handler)
95762306a36Sopenharmony_ci		napi_enable(&q->napi);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	/* 0-increment GTS to start the timer and enable interrupts */
96062306a36Sopenharmony_ci	t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A),
96162306a36Sopenharmony_ci		     SEINTARM_V(q->intr_params) |
96262306a36Sopenharmony_ci		     INGRESSQID_V(q->cntxt_id));
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci/*
96662306a36Sopenharmony_ci * Enable NAPI scheduling and interrupt generation for all Rx queues.
96762306a36Sopenharmony_ci */
96862306a36Sopenharmony_cistatic void enable_rx(struct adapter *adap)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	int i;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	for (i = 0; i < adap->sge.ingr_sz; i++) {
97362306a36Sopenharmony_ci		struct sge_rspq *q = adap->sge.ingr_map[i];
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci		if (!q)
97662306a36Sopenharmony_ci			continue;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		cxgb4_enable_rx(adap, q);
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic int setup_non_data_intr(struct adapter *adap)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	int msix;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	adap->sge.nd_msix_idx = -1;
98762306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_USING_MSIX))
98862306a36Sopenharmony_ci		return 0;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	/* Request MSI-X vector for non-data interrupt */
99162306a36Sopenharmony_ci	msix = cxgb4_get_msix_idx_from_bmap(adap);
99262306a36Sopenharmony_ci	if (msix < 0)
99362306a36Sopenharmony_ci		return -ENOMEM;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	snprintf(adap->msix_info[msix].desc,
99662306a36Sopenharmony_ci		 sizeof(adap->msix_info[msix].desc),
99762306a36Sopenharmony_ci		 "%s", adap->port[0]->name);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	adap->sge.nd_msix_idx = msix;
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic int setup_fw_sge_queues(struct adapter *adap)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	struct sge *s = &adap->sge;
100662306a36Sopenharmony_ci	int msix, err = 0;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	bitmap_zero(s->starving_fl, s->egr_sz);
100962306a36Sopenharmony_ci	bitmap_zero(s->txq_maperr, s->egr_sz);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (adap->flags & CXGB4_USING_MSIX) {
101262306a36Sopenharmony_ci		s->fwevtq_msix_idx = -1;
101362306a36Sopenharmony_ci		msix = cxgb4_get_msix_idx_from_bmap(adap);
101462306a36Sopenharmony_ci		if (msix < 0)
101562306a36Sopenharmony_ci			return -ENOMEM;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci		snprintf(adap->msix_info[msix].desc,
101862306a36Sopenharmony_ci			 sizeof(adap->msix_info[msix].desc),
101962306a36Sopenharmony_ci			 "%s-FWeventq", adap->port[0]->name);
102062306a36Sopenharmony_ci	} else {
102162306a36Sopenharmony_ci		err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0,
102262306a36Sopenharmony_ci				       NULL, NULL, NULL, -1);
102362306a36Sopenharmony_ci		if (err)
102462306a36Sopenharmony_ci			return err;
102562306a36Sopenharmony_ci		msix = -((int)s->intrq.abs_id + 1);
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0],
102962306a36Sopenharmony_ci			       msix, NULL, fwevtq_handler, NULL, -1);
103062306a36Sopenharmony_ci	if (err && msix >= 0)
103162306a36Sopenharmony_ci		cxgb4_free_msix_idx_in_bmap(adap, msix);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	s->fwevtq_msix_idx = msix;
103462306a36Sopenharmony_ci	return err;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci/**
103862306a36Sopenharmony_ci *	setup_sge_queues - configure SGE Tx/Rx/response queues
103962306a36Sopenharmony_ci *	@adap: the adapter
104062306a36Sopenharmony_ci *
104162306a36Sopenharmony_ci *	Determines how many sets of SGE queues to use and initializes them.
104262306a36Sopenharmony_ci *	We support multiple queue sets per port if we have MSI-X, otherwise
104362306a36Sopenharmony_ci *	just one queue set per port.
104462306a36Sopenharmony_ci */
104562306a36Sopenharmony_cistatic int setup_sge_queues(struct adapter *adap)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct sge_uld_rxq_info *rxq_info = NULL;
104862306a36Sopenharmony_ci	struct sge *s = &adap->sge;
104962306a36Sopenharmony_ci	unsigned int cmplqid = 0;
105062306a36Sopenharmony_ci	int err, i, j, msix = 0;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (is_uld(adap))
105362306a36Sopenharmony_ci		rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA];
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_USING_MSIX))
105662306a36Sopenharmony_ci		msix = -((int)s->intrq.abs_id + 1);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	for_each_port(adap, i) {
105962306a36Sopenharmony_ci		struct net_device *dev = adap->port[i];
106062306a36Sopenharmony_ci		struct port_info *pi = netdev_priv(dev);
106162306a36Sopenharmony_ci		struct sge_eth_rxq *q = &s->ethrxq[pi->first_qset];
106262306a36Sopenharmony_ci		struct sge_eth_txq *t = &s->ethtxq[pi->first_qset];
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci		for (j = 0; j < pi->nqsets; j++, q++) {
106562306a36Sopenharmony_ci			if (msix >= 0) {
106662306a36Sopenharmony_ci				msix = cxgb4_get_msix_idx_from_bmap(adap);
106762306a36Sopenharmony_ci				if (msix < 0) {
106862306a36Sopenharmony_ci					err = msix;
106962306a36Sopenharmony_ci					goto freeout;
107062306a36Sopenharmony_ci				}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci				snprintf(adap->msix_info[msix].desc,
107362306a36Sopenharmony_ci					 sizeof(adap->msix_info[msix].desc),
107462306a36Sopenharmony_ci					 "%s-Rx%d", dev->name, j);
107562306a36Sopenharmony_ci				q->msix = &adap->msix_info[msix];
107662306a36Sopenharmony_ci			}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci			err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev,
107962306a36Sopenharmony_ci					       msix, &q->fl,
108062306a36Sopenharmony_ci					       t4_ethrx_handler,
108162306a36Sopenharmony_ci					       NULL,
108262306a36Sopenharmony_ci					       t4_get_tp_ch_map(adap,
108362306a36Sopenharmony_ci								pi->tx_chan));
108462306a36Sopenharmony_ci			if (err)
108562306a36Sopenharmony_ci				goto freeout;
108662306a36Sopenharmony_ci			q->rspq.idx = j;
108762306a36Sopenharmony_ci			memset(&q->stats, 0, sizeof(q->stats));
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci		q = &s->ethrxq[pi->first_qset];
109162306a36Sopenharmony_ci		for (j = 0; j < pi->nqsets; j++, t++, q++) {
109262306a36Sopenharmony_ci			err = t4_sge_alloc_eth_txq(adap, t, dev,
109362306a36Sopenharmony_ci					netdev_get_tx_queue(dev, j),
109462306a36Sopenharmony_ci					q->rspq.cntxt_id,
109562306a36Sopenharmony_ci					!!(adap->flags & CXGB4_SGE_DBQ_TIMER));
109662306a36Sopenharmony_ci			if (err)
109762306a36Sopenharmony_ci				goto freeout;
109862306a36Sopenharmony_ci		}
109962306a36Sopenharmony_ci	}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	for_each_port(adap, i) {
110262306a36Sopenharmony_ci		/* Note that cmplqid below is 0 if we don't
110362306a36Sopenharmony_ci		 * have RDMA queues, and that's the right value.
110462306a36Sopenharmony_ci		 */
110562306a36Sopenharmony_ci		if (rxq_info)
110662306a36Sopenharmony_ci			cmplqid	= rxq_info->uldrxq[i].rspq.cntxt_id;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci		err = t4_sge_alloc_ctrl_txq(adap, &s->ctrlq[i], adap->port[i],
110962306a36Sopenharmony_ci					    s->fw_evtq.cntxt_id, cmplqid);
111062306a36Sopenharmony_ci		if (err)
111162306a36Sopenharmony_ci			goto freeout;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	if (!is_t4(adap->params.chip)) {
111562306a36Sopenharmony_ci		err = t4_sge_alloc_eth_txq(adap, &s->ptptxq, adap->port[0],
111662306a36Sopenharmony_ci					   netdev_get_tx_queue(adap->port[0], 0)
111762306a36Sopenharmony_ci					   , s->fw_evtq.cntxt_id, false);
111862306a36Sopenharmony_ci		if (err)
111962306a36Sopenharmony_ci			goto freeout;
112062306a36Sopenharmony_ci	}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	t4_write_reg(adap, is_t4(adap->params.chip) ?
112362306a36Sopenharmony_ci				MPS_TRC_RSS_CONTROL_A :
112462306a36Sopenharmony_ci				MPS_T5_TRC_RSS_CONTROL_A,
112562306a36Sopenharmony_ci		     RSSCONTROL_V(netdev2pinfo(adap->port[0])->tx_chan) |
112662306a36Sopenharmony_ci		     QUEUENUMBER_V(s->ethrxq[0].rspq.abs_id));
112762306a36Sopenharmony_ci	return 0;
112862306a36Sopenharmony_cifreeout:
112962306a36Sopenharmony_ci	dev_err(adap->pdev_dev, "Can't allocate queues, err=%d\n", -err);
113062306a36Sopenharmony_ci	t4_free_sge_resources(adap);
113162306a36Sopenharmony_ci	return err;
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb,
113562306a36Sopenharmony_ci			     struct net_device *sb_dev)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	int txq;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
114062306a36Sopenharmony_ci	/* If a Data Center Bridging has been successfully negotiated on this
114162306a36Sopenharmony_ci	 * link then we'll use the skb's priority to map it to a TX Queue.
114262306a36Sopenharmony_ci	 * The skb's priority is determined via the VLAN Tag Priority Code
114362306a36Sopenharmony_ci	 * Point field.
114462306a36Sopenharmony_ci	 */
114562306a36Sopenharmony_ci	if (cxgb4_dcb_enabled(dev) && !is_kdump_kernel()) {
114662306a36Sopenharmony_ci		u16 vlan_tci;
114762306a36Sopenharmony_ci		int err;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci		err = vlan_get_tag(skb, &vlan_tci);
115062306a36Sopenharmony_ci		if (unlikely(err)) {
115162306a36Sopenharmony_ci			if (net_ratelimit())
115262306a36Sopenharmony_ci				netdev_warn(dev,
115362306a36Sopenharmony_ci					    "TX Packet without VLAN Tag on DCB Link\n");
115462306a36Sopenharmony_ci			txq = 0;
115562306a36Sopenharmony_ci		} else {
115662306a36Sopenharmony_ci			txq = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
115762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE
115862306a36Sopenharmony_ci			if (skb->protocol == htons(ETH_P_FCOE))
115962306a36Sopenharmony_ci				txq = skb->priority & 0x7;
116062306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */
116162306a36Sopenharmony_ci		}
116262306a36Sopenharmony_ci		return txq;
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	if (dev->num_tc) {
116762306a36Sopenharmony_ci		struct port_info *pi = netdev2pinfo(dev);
116862306a36Sopenharmony_ci		u8 ver, proto;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci		ver = ip_hdr(skb)->version;
117162306a36Sopenharmony_ci		proto = (ver == 6) ? ipv6_hdr(skb)->nexthdr :
117262306a36Sopenharmony_ci				     ip_hdr(skb)->protocol;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		/* Send unsupported traffic pattern to normal NIC queues. */
117562306a36Sopenharmony_ci		txq = netdev_pick_tx(dev, skb, sb_dev);
117662306a36Sopenharmony_ci		if (xfrm_offload(skb) || is_ptp_enabled(skb, dev) ||
117762306a36Sopenharmony_ci		    skb->encapsulation ||
117862306a36Sopenharmony_ci		    tls_is_skb_tx_device_offloaded(skb) ||
117962306a36Sopenharmony_ci		    (proto != IPPROTO_TCP && proto != IPPROTO_UDP))
118062306a36Sopenharmony_ci			txq = txq % pi->nqsets;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		return txq;
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (select_queue) {
118662306a36Sopenharmony_ci		txq = (skb_rx_queue_recorded(skb)
118762306a36Sopenharmony_ci			? skb_get_rx_queue(skb)
118862306a36Sopenharmony_ci			: smp_processor_id());
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci		while (unlikely(txq >= dev->real_num_tx_queues))
119162306a36Sopenharmony_ci			txq -= dev->real_num_tx_queues;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci		return txq;
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return netdev_pick_tx(dev, skb, NULL) % dev->real_num_tx_queues;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic int closest_timer(const struct sge *s, int time)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	int i, delta, match = 0, min_delta = INT_MAX;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) {
120462306a36Sopenharmony_ci		delta = time - s->timer_val[i];
120562306a36Sopenharmony_ci		if (delta < 0)
120662306a36Sopenharmony_ci			delta = -delta;
120762306a36Sopenharmony_ci		if (delta < min_delta) {
120862306a36Sopenharmony_ci			min_delta = delta;
120962306a36Sopenharmony_ci			match = i;
121062306a36Sopenharmony_ci		}
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci	return match;
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic int closest_thres(const struct sge *s, int thres)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	int i, delta, match = 0, min_delta = INT_MAX;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) {
122062306a36Sopenharmony_ci		delta = thres - s->counter_val[i];
122162306a36Sopenharmony_ci		if (delta < 0)
122262306a36Sopenharmony_ci			delta = -delta;
122362306a36Sopenharmony_ci		if (delta < min_delta) {
122462306a36Sopenharmony_ci			min_delta = delta;
122562306a36Sopenharmony_ci			match = i;
122662306a36Sopenharmony_ci		}
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci	return match;
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci/**
123262306a36Sopenharmony_ci *	cxgb4_set_rspq_intr_params - set a queue's interrupt holdoff parameters
123362306a36Sopenharmony_ci *	@q: the Rx queue
123462306a36Sopenharmony_ci *	@us: the hold-off time in us, or 0 to disable timer
123562306a36Sopenharmony_ci *	@cnt: the hold-off packet count, or 0 to disable counter
123662306a36Sopenharmony_ci *
123762306a36Sopenharmony_ci *	Sets an Rx queue's interrupt hold-off time and packet count.  At least
123862306a36Sopenharmony_ci *	one of the two needs to be enabled for the queue to generate interrupts.
123962306a36Sopenharmony_ci */
124062306a36Sopenharmony_ciint cxgb4_set_rspq_intr_params(struct sge_rspq *q,
124162306a36Sopenharmony_ci			       unsigned int us, unsigned int cnt)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	struct adapter *adap = q->adap;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if ((us | cnt) == 0)
124662306a36Sopenharmony_ci		cnt = 1;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	if (cnt) {
124962306a36Sopenharmony_ci		int err;
125062306a36Sopenharmony_ci		u32 v, new_idx;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci		new_idx = closest_thres(&adap->sge, cnt);
125362306a36Sopenharmony_ci		if (q->desc && q->pktcnt_idx != new_idx) {
125462306a36Sopenharmony_ci			/* the queue has already been created, update it */
125562306a36Sopenharmony_ci			v = FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) |
125662306a36Sopenharmony_ci			    FW_PARAMS_PARAM_X_V(
125762306a36Sopenharmony_ci					FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) |
125862306a36Sopenharmony_ci			    FW_PARAMS_PARAM_YZ_V(q->cntxt_id);
125962306a36Sopenharmony_ci			err = t4_set_params(adap, adap->mbox, adap->pf, 0, 1,
126062306a36Sopenharmony_ci					    &v, &new_idx);
126162306a36Sopenharmony_ci			if (err)
126262306a36Sopenharmony_ci				return err;
126362306a36Sopenharmony_ci		}
126462306a36Sopenharmony_ci		q->pktcnt_idx = new_idx;
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	us = us == 0 ? 6 : closest_timer(&adap->sge, us);
126862306a36Sopenharmony_ci	q->intr_params = QINTR_TIMER_IDX_V(us) | QINTR_CNT_EN_V(cnt > 0);
126962306a36Sopenharmony_ci	return 0;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic int cxgb_set_features(struct net_device *dev, netdev_features_t features)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	netdev_features_t changed = dev->features ^ features;
127562306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
127662306a36Sopenharmony_ci	int err;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	if (!(changed & NETIF_F_HW_VLAN_CTAG_RX))
127962306a36Sopenharmony_ci		return 0;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	err = t4_set_rxmode(pi->adapter, pi->adapter->mbox, pi->viid,
128262306a36Sopenharmony_ci			    pi->viid_mirror, -1, -1, -1, -1,
128362306a36Sopenharmony_ci			    !!(features & NETIF_F_HW_VLAN_CTAG_RX), true);
128462306a36Sopenharmony_ci	if (unlikely(err))
128562306a36Sopenharmony_ci		dev->features = features ^ NETIF_F_HW_VLAN_CTAG_RX;
128662306a36Sopenharmony_ci	return err;
128762306a36Sopenharmony_ci}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_cistatic int setup_debugfs(struct adapter *adap)
129062306a36Sopenharmony_ci{
129162306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(adap->debugfs_root))
129262306a36Sopenharmony_ci		return -1;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
129562306a36Sopenharmony_ci	t4_setup_debugfs(adap);
129662306a36Sopenharmony_ci#endif
129762306a36Sopenharmony_ci	return 0;
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic void cxgb4_port_mirror_free_rxq(struct adapter *adap,
130162306a36Sopenharmony_ci				       struct sge_eth_rxq *mirror_rxq)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	if ((adap->flags & CXGB4_FULL_INIT_DONE) &&
130462306a36Sopenharmony_ci	    !(adap->flags & CXGB4_SHUTTING_DOWN))
130562306a36Sopenharmony_ci		cxgb4_quiesce_rx(&mirror_rxq->rspq);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	if (adap->flags & CXGB4_USING_MSIX) {
130862306a36Sopenharmony_ci		cxgb4_clear_msix_aff(mirror_rxq->msix->vec,
130962306a36Sopenharmony_ci				     mirror_rxq->msix->aff_mask);
131062306a36Sopenharmony_ci		free_irq(mirror_rxq->msix->vec, &mirror_rxq->rspq);
131162306a36Sopenharmony_ci		cxgb4_free_msix_idx_in_bmap(adap, mirror_rxq->msix->idx);
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	free_rspq_fl(adap, &mirror_rxq->rspq, &mirror_rxq->fl);
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic int cxgb4_port_mirror_alloc_queues(struct net_device *dev)
131862306a36Sopenharmony_ci{
131962306a36Sopenharmony_ci	struct port_info *pi = netdev2pinfo(dev);
132062306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
132162306a36Sopenharmony_ci	struct sge_eth_rxq *mirror_rxq;
132262306a36Sopenharmony_ci	struct sge *s = &adap->sge;
132362306a36Sopenharmony_ci	int ret = 0, msix = 0;
132462306a36Sopenharmony_ci	u16 i, rxqid;
132562306a36Sopenharmony_ci	u16 *rss;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	if (!pi->vi_mirror_count)
132862306a36Sopenharmony_ci		return 0;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	if (s->mirror_rxq[pi->port_id])
133162306a36Sopenharmony_ci		return 0;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	mirror_rxq = kcalloc(pi->nmirrorqsets, sizeof(*mirror_rxq), GFP_KERNEL);
133462306a36Sopenharmony_ci	if (!mirror_rxq)
133562306a36Sopenharmony_ci		return -ENOMEM;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	s->mirror_rxq[pi->port_id] = mirror_rxq;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_USING_MSIX))
134062306a36Sopenharmony_ci		msix = -((int)adap->sge.intrq.abs_id + 1);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	for (i = 0, rxqid = 0; i < pi->nmirrorqsets; i++, rxqid++) {
134362306a36Sopenharmony_ci		mirror_rxq = &s->mirror_rxq[pi->port_id][i];
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci		/* Allocate Mirror Rxqs */
134662306a36Sopenharmony_ci		if (msix >= 0) {
134762306a36Sopenharmony_ci			msix = cxgb4_get_msix_idx_from_bmap(adap);
134862306a36Sopenharmony_ci			if (msix < 0) {
134962306a36Sopenharmony_ci				ret = msix;
135062306a36Sopenharmony_ci				goto out_free_queues;
135162306a36Sopenharmony_ci			}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci			mirror_rxq->msix = &adap->msix_info[msix];
135462306a36Sopenharmony_ci			snprintf(mirror_rxq->msix->desc,
135562306a36Sopenharmony_ci				 sizeof(mirror_rxq->msix->desc),
135662306a36Sopenharmony_ci				 "%s-mirrorrxq%d", dev->name, i);
135762306a36Sopenharmony_ci		}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		init_rspq(adap, &mirror_rxq->rspq,
136062306a36Sopenharmony_ci			  CXGB4_MIRROR_RXQ_DEFAULT_INTR_USEC,
136162306a36Sopenharmony_ci			  CXGB4_MIRROR_RXQ_DEFAULT_PKT_CNT,
136262306a36Sopenharmony_ci			  CXGB4_MIRROR_RXQ_DEFAULT_DESC_NUM,
136362306a36Sopenharmony_ci			  CXGB4_MIRROR_RXQ_DEFAULT_DESC_SIZE);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci		mirror_rxq->fl.size = CXGB4_MIRROR_FLQ_DEFAULT_DESC_NUM;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci		ret = t4_sge_alloc_rxq(adap, &mirror_rxq->rspq, false,
136862306a36Sopenharmony_ci				       dev, msix, &mirror_rxq->fl,
136962306a36Sopenharmony_ci				       t4_ethrx_handler, NULL, 0);
137062306a36Sopenharmony_ci		if (ret)
137162306a36Sopenharmony_ci			goto out_free_msix_idx;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci		/* Setup MSI-X vectors for Mirror Rxqs */
137462306a36Sopenharmony_ci		if (adap->flags & CXGB4_USING_MSIX) {
137562306a36Sopenharmony_ci			ret = request_irq(mirror_rxq->msix->vec,
137662306a36Sopenharmony_ci					  t4_sge_intr_msix, 0,
137762306a36Sopenharmony_ci					  mirror_rxq->msix->desc,
137862306a36Sopenharmony_ci					  &mirror_rxq->rspq);
137962306a36Sopenharmony_ci			if (ret)
138062306a36Sopenharmony_ci				goto out_free_rxq;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci			cxgb4_set_msix_aff(adap, mirror_rxq->msix->vec,
138362306a36Sopenharmony_ci					   &mirror_rxq->msix->aff_mask, i);
138462306a36Sopenharmony_ci		}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci		/* Start NAPI for Mirror Rxqs */
138762306a36Sopenharmony_ci		cxgb4_enable_rx(adap, &mirror_rxq->rspq);
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	/* Setup RSS for Mirror Rxqs */
139162306a36Sopenharmony_ci	rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL);
139262306a36Sopenharmony_ci	if (!rss) {
139362306a36Sopenharmony_ci		ret = -ENOMEM;
139462306a36Sopenharmony_ci		goto out_free_queues;
139562306a36Sopenharmony_ci	}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	mirror_rxq = &s->mirror_rxq[pi->port_id][0];
139862306a36Sopenharmony_ci	for (i = 0; i < pi->rss_size; i++)
139962306a36Sopenharmony_ci		rss[i] = mirror_rxq[i % pi->nmirrorqsets].rspq.abs_id;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	ret = cxgb4_config_rss(pi, rss, pi->rss_size, pi->viid_mirror);
140262306a36Sopenharmony_ci	kfree(rss);
140362306a36Sopenharmony_ci	if (ret)
140462306a36Sopenharmony_ci		goto out_free_queues;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	return 0;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ciout_free_rxq:
140962306a36Sopenharmony_ci	free_rspq_fl(adap, &mirror_rxq->rspq, &mirror_rxq->fl);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ciout_free_msix_idx:
141262306a36Sopenharmony_ci	cxgb4_free_msix_idx_in_bmap(adap, mirror_rxq->msix->idx);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ciout_free_queues:
141562306a36Sopenharmony_ci	while (rxqid-- > 0)
141662306a36Sopenharmony_ci		cxgb4_port_mirror_free_rxq(adap,
141762306a36Sopenharmony_ci					   &s->mirror_rxq[pi->port_id][rxqid]);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	kfree(s->mirror_rxq[pi->port_id]);
142062306a36Sopenharmony_ci	s->mirror_rxq[pi->port_id] = NULL;
142162306a36Sopenharmony_ci	return ret;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic void cxgb4_port_mirror_free_queues(struct net_device *dev)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	struct port_info *pi = netdev2pinfo(dev);
142762306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
142862306a36Sopenharmony_ci	struct sge *s = &adap->sge;
142962306a36Sopenharmony_ci	u16 i;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (!pi->vi_mirror_count)
143262306a36Sopenharmony_ci		return;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	if (!s->mirror_rxq[pi->port_id])
143562306a36Sopenharmony_ci		return;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	for (i = 0; i < pi->nmirrorqsets; i++)
143862306a36Sopenharmony_ci		cxgb4_port_mirror_free_rxq(adap,
143962306a36Sopenharmony_ci					   &s->mirror_rxq[pi->port_id][i]);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	kfree(s->mirror_rxq[pi->port_id]);
144262306a36Sopenharmony_ci	s->mirror_rxq[pi->port_id] = NULL;
144362306a36Sopenharmony_ci}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_cistatic int cxgb4_port_mirror_start(struct net_device *dev)
144662306a36Sopenharmony_ci{
144762306a36Sopenharmony_ci	struct port_info *pi = netdev2pinfo(dev);
144862306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
144962306a36Sopenharmony_ci	int ret, idx = -1;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	if (!pi->vi_mirror_count)
145262306a36Sopenharmony_ci		return 0;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	/* Mirror VIs can be created dynamically after stack had
145562306a36Sopenharmony_ci	 * already setup Rx modes like MTU, promisc, allmulti, etc.
145662306a36Sopenharmony_ci	 * on main VI. So, parse what the stack had setup on the
145762306a36Sopenharmony_ci	 * main VI and update the same on the mirror VI.
145862306a36Sopenharmony_ci	 */
145962306a36Sopenharmony_ci	ret = t4_set_rxmode(adap, adap->mbox, pi->viid, pi->viid_mirror,
146062306a36Sopenharmony_ci			    dev->mtu, (dev->flags & IFF_PROMISC) ? 1 : 0,
146162306a36Sopenharmony_ci			    (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1,
146262306a36Sopenharmony_ci			    !!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true);
146362306a36Sopenharmony_ci	if (ret) {
146462306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
146562306a36Sopenharmony_ci			"Failed start up Rx mode for Mirror VI 0x%x, ret: %d\n",
146662306a36Sopenharmony_ci			pi->viid_mirror, ret);
146762306a36Sopenharmony_ci		return ret;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	/* Enable replication bit for the device's MAC address
147162306a36Sopenharmony_ci	 * in MPS TCAM, so that the packets for the main VI are
147262306a36Sopenharmony_ci	 * replicated to mirror VI.
147362306a36Sopenharmony_ci	 */
147462306a36Sopenharmony_ci	ret = cxgb4_update_mac_filt(pi, pi->viid_mirror, &idx,
147562306a36Sopenharmony_ci				    dev->dev_addr, true, NULL);
147662306a36Sopenharmony_ci	if (ret) {
147762306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
147862306a36Sopenharmony_ci			"Failed updating MAC filter for Mirror VI 0x%x, ret: %d\n",
147962306a36Sopenharmony_ci			pi->viid_mirror, ret);
148062306a36Sopenharmony_ci		return ret;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	/* Enabling a Virtual Interface can result in an interrupt
148462306a36Sopenharmony_ci	 * during the processing of the VI Enable command and, in some
148562306a36Sopenharmony_ci	 * paths, result in an attempt to issue another command in the
148662306a36Sopenharmony_ci	 * interrupt context. Thus, we disable interrupts during the
148762306a36Sopenharmony_ci	 * course of the VI Enable command ...
148862306a36Sopenharmony_ci	 */
148962306a36Sopenharmony_ci	local_bh_disable();
149062306a36Sopenharmony_ci	ret = t4_enable_vi_params(adap, adap->mbox, pi->viid_mirror, true, true,
149162306a36Sopenharmony_ci				  false);
149262306a36Sopenharmony_ci	local_bh_enable();
149362306a36Sopenharmony_ci	if (ret)
149462306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
149562306a36Sopenharmony_ci			"Failed starting Mirror VI 0x%x, ret: %d\n",
149662306a36Sopenharmony_ci			pi->viid_mirror, ret);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	return ret;
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistatic void cxgb4_port_mirror_stop(struct net_device *dev)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	struct port_info *pi = netdev2pinfo(dev);
150462306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	if (!pi->vi_mirror_count)
150762306a36Sopenharmony_ci		return;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	t4_enable_vi_params(adap, adap->mbox, pi->viid_mirror, false, false,
151062306a36Sopenharmony_ci			    false);
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ciint cxgb4_port_mirror_alloc(struct net_device *dev)
151462306a36Sopenharmony_ci{
151562306a36Sopenharmony_ci	struct port_info *pi = netdev2pinfo(dev);
151662306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
151762306a36Sopenharmony_ci	int ret = 0;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	if (!pi->nmirrorqsets)
152062306a36Sopenharmony_ci		return -EOPNOTSUPP;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	mutex_lock(&pi->vi_mirror_mutex);
152362306a36Sopenharmony_ci	if (pi->viid_mirror) {
152462306a36Sopenharmony_ci		pi->vi_mirror_count++;
152562306a36Sopenharmony_ci		goto out_unlock;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	ret = t4_init_port_mirror(pi, adap->mbox, pi->port_id, adap->pf, 0,
152962306a36Sopenharmony_ci				  &pi->viid_mirror);
153062306a36Sopenharmony_ci	if (ret)
153162306a36Sopenharmony_ci		goto out_unlock;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	pi->vi_mirror_count = 1;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (adap->flags & CXGB4_FULL_INIT_DONE) {
153662306a36Sopenharmony_ci		ret = cxgb4_port_mirror_alloc_queues(dev);
153762306a36Sopenharmony_ci		if (ret)
153862306a36Sopenharmony_ci			goto out_free_vi;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci		ret = cxgb4_port_mirror_start(dev);
154162306a36Sopenharmony_ci		if (ret)
154262306a36Sopenharmony_ci			goto out_free_queues;
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	mutex_unlock(&pi->vi_mirror_mutex);
154662306a36Sopenharmony_ci	return 0;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ciout_free_queues:
154962306a36Sopenharmony_ci	cxgb4_port_mirror_free_queues(dev);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ciout_free_vi:
155262306a36Sopenharmony_ci	pi->vi_mirror_count = 0;
155362306a36Sopenharmony_ci	t4_free_vi(adap, adap->mbox, adap->pf, 0, pi->viid_mirror);
155462306a36Sopenharmony_ci	pi->viid_mirror = 0;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ciout_unlock:
155762306a36Sopenharmony_ci	mutex_unlock(&pi->vi_mirror_mutex);
155862306a36Sopenharmony_ci	return ret;
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_civoid cxgb4_port_mirror_free(struct net_device *dev)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct port_info *pi = netdev2pinfo(dev);
156462306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	mutex_lock(&pi->vi_mirror_mutex);
156762306a36Sopenharmony_ci	if (!pi->viid_mirror)
156862306a36Sopenharmony_ci		goto out_unlock;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	if (pi->vi_mirror_count > 1) {
157162306a36Sopenharmony_ci		pi->vi_mirror_count--;
157262306a36Sopenharmony_ci		goto out_unlock;
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	cxgb4_port_mirror_stop(dev);
157662306a36Sopenharmony_ci	cxgb4_port_mirror_free_queues(dev);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	pi->vi_mirror_count = 0;
157962306a36Sopenharmony_ci	t4_free_vi(adap, adap->mbox, adap->pf, 0, pi->viid_mirror);
158062306a36Sopenharmony_ci	pi->viid_mirror = 0;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ciout_unlock:
158362306a36Sopenharmony_ci	mutex_unlock(&pi->vi_mirror_mutex);
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci/*
158762306a36Sopenharmony_ci * upper-layer driver support
158862306a36Sopenharmony_ci */
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci/*
159162306a36Sopenharmony_ci * Allocate an active-open TID and set it to the supplied value.
159262306a36Sopenharmony_ci */
159362306a36Sopenharmony_ciint cxgb4_alloc_atid(struct tid_info *t, void *data)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	int atid = -1;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	spin_lock_bh(&t->atid_lock);
159862306a36Sopenharmony_ci	if (t->afree) {
159962306a36Sopenharmony_ci		union aopen_entry *p = t->afree;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci		atid = (p - t->atid_tab) + t->atid_base;
160262306a36Sopenharmony_ci		t->afree = p->next;
160362306a36Sopenharmony_ci		p->data = data;
160462306a36Sopenharmony_ci		t->atids_in_use++;
160562306a36Sopenharmony_ci	}
160662306a36Sopenharmony_ci	spin_unlock_bh(&t->atid_lock);
160762306a36Sopenharmony_ci	return atid;
160862306a36Sopenharmony_ci}
160962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_atid);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci/*
161262306a36Sopenharmony_ci * Release an active-open TID.
161362306a36Sopenharmony_ci */
161462306a36Sopenharmony_civoid cxgb4_free_atid(struct tid_info *t, unsigned int atid)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	union aopen_entry *p = &t->atid_tab[atid - t->atid_base];
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	spin_lock_bh(&t->atid_lock);
161962306a36Sopenharmony_ci	p->next = t->afree;
162062306a36Sopenharmony_ci	t->afree = p;
162162306a36Sopenharmony_ci	t->atids_in_use--;
162262306a36Sopenharmony_ci	spin_unlock_bh(&t->atid_lock);
162362306a36Sopenharmony_ci}
162462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_free_atid);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci/*
162762306a36Sopenharmony_ci * Allocate a server TID and set it to the supplied value.
162862306a36Sopenharmony_ci */
162962306a36Sopenharmony_ciint cxgb4_alloc_stid(struct tid_info *t, int family, void *data)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	int stid;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	spin_lock_bh(&t->stid_lock);
163462306a36Sopenharmony_ci	if (family == PF_INET) {
163562306a36Sopenharmony_ci		stid = find_first_zero_bit(t->stid_bmap, t->nstids);
163662306a36Sopenharmony_ci		if (stid < t->nstids)
163762306a36Sopenharmony_ci			__set_bit(stid, t->stid_bmap);
163862306a36Sopenharmony_ci		else
163962306a36Sopenharmony_ci			stid = -1;
164062306a36Sopenharmony_ci	} else {
164162306a36Sopenharmony_ci		stid = bitmap_find_free_region(t->stid_bmap, t->nstids, 1);
164262306a36Sopenharmony_ci		if (stid < 0)
164362306a36Sopenharmony_ci			stid = -1;
164462306a36Sopenharmony_ci	}
164562306a36Sopenharmony_ci	if (stid >= 0) {
164662306a36Sopenharmony_ci		t->stid_tab[stid].data = data;
164762306a36Sopenharmony_ci		stid += t->stid_base;
164862306a36Sopenharmony_ci		/* IPv6 requires max of 520 bits or 16 cells in TCAM
164962306a36Sopenharmony_ci		 * This is equivalent to 4 TIDs. With CLIP enabled it
165062306a36Sopenharmony_ci		 * needs 2 TIDs.
165162306a36Sopenharmony_ci		 */
165262306a36Sopenharmony_ci		if (family == PF_INET6) {
165362306a36Sopenharmony_ci			t->stids_in_use += 2;
165462306a36Sopenharmony_ci			t->v6_stids_in_use += 2;
165562306a36Sopenharmony_ci		} else {
165662306a36Sopenharmony_ci			t->stids_in_use++;
165762306a36Sopenharmony_ci		}
165862306a36Sopenharmony_ci	}
165962306a36Sopenharmony_ci	spin_unlock_bh(&t->stid_lock);
166062306a36Sopenharmony_ci	return stid;
166162306a36Sopenharmony_ci}
166262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_stid);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci/* Allocate a server filter TID and set it to the supplied value.
166562306a36Sopenharmony_ci */
166662306a36Sopenharmony_ciint cxgb4_alloc_sftid(struct tid_info *t, int family, void *data)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	int stid;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	spin_lock_bh(&t->stid_lock);
167162306a36Sopenharmony_ci	if (family == PF_INET) {
167262306a36Sopenharmony_ci		stid = find_next_zero_bit(t->stid_bmap,
167362306a36Sopenharmony_ci				t->nstids + t->nsftids, t->nstids);
167462306a36Sopenharmony_ci		if (stid < (t->nstids + t->nsftids))
167562306a36Sopenharmony_ci			__set_bit(stid, t->stid_bmap);
167662306a36Sopenharmony_ci		else
167762306a36Sopenharmony_ci			stid = -1;
167862306a36Sopenharmony_ci	} else {
167962306a36Sopenharmony_ci		stid = -1;
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci	if (stid >= 0) {
168262306a36Sopenharmony_ci		t->stid_tab[stid].data = data;
168362306a36Sopenharmony_ci		stid -= t->nstids;
168462306a36Sopenharmony_ci		stid += t->sftid_base;
168562306a36Sopenharmony_ci		t->sftids_in_use++;
168662306a36Sopenharmony_ci	}
168762306a36Sopenharmony_ci	spin_unlock_bh(&t->stid_lock);
168862306a36Sopenharmony_ci	return stid;
168962306a36Sopenharmony_ci}
169062306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_sftid);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci/* Release a server TID.
169362306a36Sopenharmony_ci */
169462306a36Sopenharmony_civoid cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family)
169562306a36Sopenharmony_ci{
169662306a36Sopenharmony_ci	/* Is it a server filter TID? */
169762306a36Sopenharmony_ci	if (t->nsftids && (stid >= t->sftid_base)) {
169862306a36Sopenharmony_ci		stid -= t->sftid_base;
169962306a36Sopenharmony_ci		stid += t->nstids;
170062306a36Sopenharmony_ci	} else {
170162306a36Sopenharmony_ci		stid -= t->stid_base;
170262306a36Sopenharmony_ci	}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	spin_lock_bh(&t->stid_lock);
170562306a36Sopenharmony_ci	if (family == PF_INET)
170662306a36Sopenharmony_ci		__clear_bit(stid, t->stid_bmap);
170762306a36Sopenharmony_ci	else
170862306a36Sopenharmony_ci		bitmap_release_region(t->stid_bmap, stid, 1);
170962306a36Sopenharmony_ci	t->stid_tab[stid].data = NULL;
171062306a36Sopenharmony_ci	if (stid < t->nstids) {
171162306a36Sopenharmony_ci		if (family == PF_INET6) {
171262306a36Sopenharmony_ci			t->stids_in_use -= 2;
171362306a36Sopenharmony_ci			t->v6_stids_in_use -= 2;
171462306a36Sopenharmony_ci		} else {
171562306a36Sopenharmony_ci			t->stids_in_use--;
171662306a36Sopenharmony_ci		}
171762306a36Sopenharmony_ci	} else {
171862306a36Sopenharmony_ci		t->sftids_in_use--;
171962306a36Sopenharmony_ci	}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	spin_unlock_bh(&t->stid_lock);
172262306a36Sopenharmony_ci}
172362306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_free_stid);
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci/*
172662306a36Sopenharmony_ci * Populate a TID_RELEASE WR.  Caller must properly size the skb.
172762306a36Sopenharmony_ci */
172862306a36Sopenharmony_cistatic void mk_tid_release(struct sk_buff *skb, unsigned int chan,
172962306a36Sopenharmony_ci			   unsigned int tid)
173062306a36Sopenharmony_ci{
173162306a36Sopenharmony_ci	struct cpl_tid_release *req;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_SETUP, chan);
173462306a36Sopenharmony_ci	req = __skb_put(skb, sizeof(*req));
173562306a36Sopenharmony_ci	INIT_TP_WR(req, tid);
173662306a36Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
173762306a36Sopenharmony_ci}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci/*
174062306a36Sopenharmony_ci * Queue a TID release request and if necessary schedule a work queue to
174162306a36Sopenharmony_ci * process it.
174262306a36Sopenharmony_ci */
174362306a36Sopenharmony_cistatic void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
174462306a36Sopenharmony_ci				    unsigned int tid)
174562306a36Sopenharmony_ci{
174662306a36Sopenharmony_ci	struct adapter *adap = container_of(t, struct adapter, tids);
174762306a36Sopenharmony_ci	void **p = &t->tid_tab[tid - t->tid_base];
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	spin_lock_bh(&adap->tid_release_lock);
175062306a36Sopenharmony_ci	*p = adap->tid_release_head;
175162306a36Sopenharmony_ci	/* Low 2 bits encode the Tx channel number */
175262306a36Sopenharmony_ci	adap->tid_release_head = (void **)((uintptr_t)p | chan);
175362306a36Sopenharmony_ci	if (!adap->tid_release_task_busy) {
175462306a36Sopenharmony_ci		adap->tid_release_task_busy = true;
175562306a36Sopenharmony_ci		queue_work(adap->workq, &adap->tid_release_task);
175662306a36Sopenharmony_ci	}
175762306a36Sopenharmony_ci	spin_unlock_bh(&adap->tid_release_lock);
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci/*
176162306a36Sopenharmony_ci * Process the list of pending TID release requests.
176262306a36Sopenharmony_ci */
176362306a36Sopenharmony_cistatic void process_tid_release_list(struct work_struct *work)
176462306a36Sopenharmony_ci{
176562306a36Sopenharmony_ci	struct sk_buff *skb;
176662306a36Sopenharmony_ci	struct adapter *adap;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	adap = container_of(work, struct adapter, tid_release_task);
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	spin_lock_bh(&adap->tid_release_lock);
177162306a36Sopenharmony_ci	while (adap->tid_release_head) {
177262306a36Sopenharmony_ci		void **p = adap->tid_release_head;
177362306a36Sopenharmony_ci		unsigned int chan = (uintptr_t)p & 3;
177462306a36Sopenharmony_ci		p = (void *)p - chan;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci		adap->tid_release_head = *p;
177762306a36Sopenharmony_ci		*p = NULL;
177862306a36Sopenharmony_ci		spin_unlock_bh(&adap->tid_release_lock);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci		while (!(skb = alloc_skb(sizeof(struct cpl_tid_release),
178162306a36Sopenharmony_ci					 GFP_KERNEL)))
178262306a36Sopenharmony_ci			schedule_timeout_uninterruptible(1);
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci		mk_tid_release(skb, chan, p - adap->tids.tid_tab);
178562306a36Sopenharmony_ci		t4_ofld_send(adap, skb);
178662306a36Sopenharmony_ci		spin_lock_bh(&adap->tid_release_lock);
178762306a36Sopenharmony_ci	}
178862306a36Sopenharmony_ci	adap->tid_release_task_busy = false;
178962306a36Sopenharmony_ci	spin_unlock_bh(&adap->tid_release_lock);
179062306a36Sopenharmony_ci}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci/*
179362306a36Sopenharmony_ci * Release a TID and inform HW.  If we are unable to allocate the release
179462306a36Sopenharmony_ci * message we defer to a work queue.
179562306a36Sopenharmony_ci */
179662306a36Sopenharmony_civoid cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid,
179762306a36Sopenharmony_ci		      unsigned short family)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	struct adapter *adap = container_of(t, struct adapter, tids);
180062306a36Sopenharmony_ci	struct sk_buff *skb;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	WARN_ON(tid_out_of_range(&adap->tids, tid));
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	if (t->tid_tab[tid - adap->tids.tid_base]) {
180562306a36Sopenharmony_ci		t->tid_tab[tid - adap->tids.tid_base] = NULL;
180662306a36Sopenharmony_ci		atomic_dec(&t->conns_in_use);
180762306a36Sopenharmony_ci		if (t->hash_base && (tid >= t->hash_base)) {
180862306a36Sopenharmony_ci			if (family == AF_INET6)
180962306a36Sopenharmony_ci				atomic_sub(2, &t->hash_tids_in_use);
181062306a36Sopenharmony_ci			else
181162306a36Sopenharmony_ci				atomic_dec(&t->hash_tids_in_use);
181262306a36Sopenharmony_ci		} else {
181362306a36Sopenharmony_ci			if (family == AF_INET6)
181462306a36Sopenharmony_ci				atomic_sub(2, &t->tids_in_use);
181562306a36Sopenharmony_ci			else
181662306a36Sopenharmony_ci				atomic_dec(&t->tids_in_use);
181762306a36Sopenharmony_ci		}
181862306a36Sopenharmony_ci	}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC);
182162306a36Sopenharmony_ci	if (likely(skb)) {
182262306a36Sopenharmony_ci		mk_tid_release(skb, chan, tid);
182362306a36Sopenharmony_ci		t4_ofld_send(adap, skb);
182462306a36Sopenharmony_ci	} else
182562306a36Sopenharmony_ci		cxgb4_queue_tid_release(t, chan, tid);
182662306a36Sopenharmony_ci}
182762306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_tid);
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci/*
183062306a36Sopenharmony_ci * Allocate and initialize the TID tables.  Returns 0 on success.
183162306a36Sopenharmony_ci */
183262306a36Sopenharmony_cistatic int tid_init(struct tid_info *t)
183362306a36Sopenharmony_ci{
183462306a36Sopenharmony_ci	struct adapter *adap = container_of(t, struct adapter, tids);
183562306a36Sopenharmony_ci	unsigned int max_ftids = t->nftids + t->nsftids;
183662306a36Sopenharmony_ci	unsigned int natids = t->natids;
183762306a36Sopenharmony_ci	unsigned int hpftid_bmap_size;
183862306a36Sopenharmony_ci	unsigned int eotid_bmap_size;
183962306a36Sopenharmony_ci	unsigned int stid_bmap_size;
184062306a36Sopenharmony_ci	unsigned int ftid_bmap_size;
184162306a36Sopenharmony_ci	size_t size;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	stid_bmap_size = BITS_TO_LONGS(t->nstids + t->nsftids);
184462306a36Sopenharmony_ci	ftid_bmap_size = BITS_TO_LONGS(t->nftids);
184562306a36Sopenharmony_ci	hpftid_bmap_size = BITS_TO_LONGS(t->nhpftids);
184662306a36Sopenharmony_ci	eotid_bmap_size = BITS_TO_LONGS(t->neotids);
184762306a36Sopenharmony_ci	size = t->ntids * sizeof(*t->tid_tab) +
184862306a36Sopenharmony_ci	       natids * sizeof(*t->atid_tab) +
184962306a36Sopenharmony_ci	       t->nstids * sizeof(*t->stid_tab) +
185062306a36Sopenharmony_ci	       t->nsftids * sizeof(*t->stid_tab) +
185162306a36Sopenharmony_ci	       stid_bmap_size * sizeof(long) +
185262306a36Sopenharmony_ci	       t->nhpftids * sizeof(*t->hpftid_tab) +
185362306a36Sopenharmony_ci	       hpftid_bmap_size * sizeof(long) +
185462306a36Sopenharmony_ci	       max_ftids * sizeof(*t->ftid_tab) +
185562306a36Sopenharmony_ci	       ftid_bmap_size * sizeof(long) +
185662306a36Sopenharmony_ci	       t->neotids * sizeof(*t->eotid_tab) +
185762306a36Sopenharmony_ci	       eotid_bmap_size * sizeof(long);
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	t->tid_tab = kvzalloc(size, GFP_KERNEL);
186062306a36Sopenharmony_ci	if (!t->tid_tab)
186162306a36Sopenharmony_ci		return -ENOMEM;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids];
186462306a36Sopenharmony_ci	t->stid_tab = (struct serv_entry *)&t->atid_tab[natids];
186562306a36Sopenharmony_ci	t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids + t->nsftids];
186662306a36Sopenharmony_ci	t->hpftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size];
186762306a36Sopenharmony_ci	t->hpftid_bmap = (unsigned long *)&t->hpftid_tab[t->nhpftids];
186862306a36Sopenharmony_ci	t->ftid_tab = (struct filter_entry *)&t->hpftid_bmap[hpftid_bmap_size];
186962306a36Sopenharmony_ci	t->ftid_bmap = (unsigned long *)&t->ftid_tab[max_ftids];
187062306a36Sopenharmony_ci	t->eotid_tab = (struct eotid_entry *)&t->ftid_bmap[ftid_bmap_size];
187162306a36Sopenharmony_ci	t->eotid_bmap = (unsigned long *)&t->eotid_tab[t->neotids];
187262306a36Sopenharmony_ci	spin_lock_init(&t->stid_lock);
187362306a36Sopenharmony_ci	spin_lock_init(&t->atid_lock);
187462306a36Sopenharmony_ci	spin_lock_init(&t->ftid_lock);
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	t->stids_in_use = 0;
187762306a36Sopenharmony_ci	t->v6_stids_in_use = 0;
187862306a36Sopenharmony_ci	t->sftids_in_use = 0;
187962306a36Sopenharmony_ci	t->afree = NULL;
188062306a36Sopenharmony_ci	t->atids_in_use = 0;
188162306a36Sopenharmony_ci	atomic_set(&t->tids_in_use, 0);
188262306a36Sopenharmony_ci	atomic_set(&t->conns_in_use, 0);
188362306a36Sopenharmony_ci	atomic_set(&t->hash_tids_in_use, 0);
188462306a36Sopenharmony_ci	atomic_set(&t->eotids_in_use, 0);
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	/* Setup the free list for atid_tab and clear the stid bitmap. */
188762306a36Sopenharmony_ci	if (natids) {
188862306a36Sopenharmony_ci		while (--natids)
188962306a36Sopenharmony_ci			t->atid_tab[natids - 1].next = &t->atid_tab[natids];
189062306a36Sopenharmony_ci		t->afree = t->atid_tab;
189162306a36Sopenharmony_ci	}
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	if (is_offload(adap)) {
189462306a36Sopenharmony_ci		bitmap_zero(t->stid_bmap, t->nstids + t->nsftids);
189562306a36Sopenharmony_ci		/* Reserve stid 0 for T4/T5 adapters */
189662306a36Sopenharmony_ci		if (!t->stid_base &&
189762306a36Sopenharmony_ci		    CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
189862306a36Sopenharmony_ci			__set_bit(0, t->stid_bmap);
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci		if (t->neotids)
190162306a36Sopenharmony_ci			bitmap_zero(t->eotid_bmap, t->neotids);
190262306a36Sopenharmony_ci	}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	if (t->nhpftids)
190562306a36Sopenharmony_ci		bitmap_zero(t->hpftid_bmap, t->nhpftids);
190662306a36Sopenharmony_ci	bitmap_zero(t->ftid_bmap, t->nftids);
190762306a36Sopenharmony_ci	return 0;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci/**
191162306a36Sopenharmony_ci *	cxgb4_create_server - create an IP server
191262306a36Sopenharmony_ci *	@dev: the device
191362306a36Sopenharmony_ci *	@stid: the server TID
191462306a36Sopenharmony_ci *	@sip: local IP address to bind server to
191562306a36Sopenharmony_ci *	@sport: the server's TCP port
191662306a36Sopenharmony_ci *	@vlan: the VLAN header information
191762306a36Sopenharmony_ci *	@queue: queue to direct messages from this server to
191862306a36Sopenharmony_ci *
191962306a36Sopenharmony_ci *	Create an IP server for the given port and address.
192062306a36Sopenharmony_ci *	Returns <0 on error and one of the %NET_XMIT_* values on success.
192162306a36Sopenharmony_ci */
192262306a36Sopenharmony_ciint cxgb4_create_server(const struct net_device *dev, unsigned int stid,
192362306a36Sopenharmony_ci			__be32 sip, __be16 sport, __be16 vlan,
192462306a36Sopenharmony_ci			unsigned int queue)
192562306a36Sopenharmony_ci{
192662306a36Sopenharmony_ci	unsigned int chan;
192762306a36Sopenharmony_ci	struct sk_buff *skb;
192862306a36Sopenharmony_ci	struct adapter *adap;
192962306a36Sopenharmony_ci	struct cpl_pass_open_req *req;
193062306a36Sopenharmony_ci	int ret;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	skb = alloc_skb(sizeof(*req), GFP_KERNEL);
193362306a36Sopenharmony_ci	if (!skb)
193462306a36Sopenharmony_ci		return -ENOMEM;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	adap = netdev2adap(dev);
193762306a36Sopenharmony_ci	req = __skb_put(skb, sizeof(*req));
193862306a36Sopenharmony_ci	INIT_TP_WR(req, 0);
193962306a36Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid));
194062306a36Sopenharmony_ci	req->local_port = sport;
194162306a36Sopenharmony_ci	req->peer_port = htons(0);
194262306a36Sopenharmony_ci	req->local_ip = sip;
194362306a36Sopenharmony_ci	req->peer_ip = htonl(0);
194462306a36Sopenharmony_ci	chan = rxq_to_chan(&adap->sge, queue);
194562306a36Sopenharmony_ci	req->opt0 = cpu_to_be64(TX_CHAN_V(chan));
194662306a36Sopenharmony_ci	req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) |
194762306a36Sopenharmony_ci				SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue));
194862306a36Sopenharmony_ci	ret = t4_mgmt_tx(adap, skb);
194962306a36Sopenharmony_ci	return net_xmit_eval(ret);
195062306a36Sopenharmony_ci}
195162306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server);
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci/*	cxgb4_create_server6 - create an IPv6 server
195462306a36Sopenharmony_ci *	@dev: the device
195562306a36Sopenharmony_ci *	@stid: the server TID
195662306a36Sopenharmony_ci *	@sip: local IPv6 address to bind server to
195762306a36Sopenharmony_ci *	@sport: the server's TCP port
195862306a36Sopenharmony_ci *	@queue: queue to direct messages from this server to
195962306a36Sopenharmony_ci *
196062306a36Sopenharmony_ci *	Create an IPv6 server for the given port and address.
196162306a36Sopenharmony_ci *	Returns <0 on error and one of the %NET_XMIT_* values on success.
196262306a36Sopenharmony_ci */
196362306a36Sopenharmony_ciint cxgb4_create_server6(const struct net_device *dev, unsigned int stid,
196462306a36Sopenharmony_ci			 const struct in6_addr *sip, __be16 sport,
196562306a36Sopenharmony_ci			 unsigned int queue)
196662306a36Sopenharmony_ci{
196762306a36Sopenharmony_ci	unsigned int chan;
196862306a36Sopenharmony_ci	struct sk_buff *skb;
196962306a36Sopenharmony_ci	struct adapter *adap;
197062306a36Sopenharmony_ci	struct cpl_pass_open_req6 *req;
197162306a36Sopenharmony_ci	int ret;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	skb = alloc_skb(sizeof(*req), GFP_KERNEL);
197462306a36Sopenharmony_ci	if (!skb)
197562306a36Sopenharmony_ci		return -ENOMEM;
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	adap = netdev2adap(dev);
197862306a36Sopenharmony_ci	req = __skb_put(skb, sizeof(*req));
197962306a36Sopenharmony_ci	INIT_TP_WR(req, 0);
198062306a36Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ6, stid));
198162306a36Sopenharmony_ci	req->local_port = sport;
198262306a36Sopenharmony_ci	req->peer_port = htons(0);
198362306a36Sopenharmony_ci	req->local_ip_hi = *(__be64 *)(sip->s6_addr);
198462306a36Sopenharmony_ci	req->local_ip_lo = *(__be64 *)(sip->s6_addr + 8);
198562306a36Sopenharmony_ci	req->peer_ip_hi = cpu_to_be64(0);
198662306a36Sopenharmony_ci	req->peer_ip_lo = cpu_to_be64(0);
198762306a36Sopenharmony_ci	chan = rxq_to_chan(&adap->sge, queue);
198862306a36Sopenharmony_ci	req->opt0 = cpu_to_be64(TX_CHAN_V(chan));
198962306a36Sopenharmony_ci	req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) |
199062306a36Sopenharmony_ci				SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue));
199162306a36Sopenharmony_ci	ret = t4_mgmt_tx(adap, skb);
199262306a36Sopenharmony_ci	return net_xmit_eval(ret);
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server6);
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ciint cxgb4_remove_server(const struct net_device *dev, unsigned int stid,
199762306a36Sopenharmony_ci			unsigned int queue, bool ipv6)
199862306a36Sopenharmony_ci{
199962306a36Sopenharmony_ci	struct sk_buff *skb;
200062306a36Sopenharmony_ci	struct adapter *adap;
200162306a36Sopenharmony_ci	struct cpl_close_listsvr_req *req;
200262306a36Sopenharmony_ci	int ret;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	adap = netdev2adap(dev);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	skb = alloc_skb(sizeof(*req), GFP_KERNEL);
200762306a36Sopenharmony_ci	if (!skb)
200862306a36Sopenharmony_ci		return -ENOMEM;
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	req = __skb_put(skb, sizeof(*req));
201162306a36Sopenharmony_ci	INIT_TP_WR(req, 0);
201262306a36Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid));
201362306a36Sopenharmony_ci	req->reply_ctrl = htons(NO_REPLY_V(0) | (ipv6 ? LISTSVR_IPV6_V(1) :
201462306a36Sopenharmony_ci				LISTSVR_IPV6_V(0)) | QUEUENO_V(queue));
201562306a36Sopenharmony_ci	ret = t4_mgmt_tx(adap, skb);
201662306a36Sopenharmony_ci	return net_xmit_eval(ret);
201762306a36Sopenharmony_ci}
201862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_server);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci/**
202162306a36Sopenharmony_ci *	cxgb4_best_mtu - find the entry in the MTU table closest to an MTU
202262306a36Sopenharmony_ci *	@mtus: the HW MTU table
202362306a36Sopenharmony_ci *	@mtu: the target MTU
202462306a36Sopenharmony_ci *	@idx: index of selected entry in the MTU table
202562306a36Sopenharmony_ci *
202662306a36Sopenharmony_ci *	Returns the index and the value in the HW MTU table that is closest to
202762306a36Sopenharmony_ci *	but does not exceed @mtu, unless @mtu is smaller than any value in the
202862306a36Sopenharmony_ci *	table, in which case that smallest available value is selected.
202962306a36Sopenharmony_ci */
203062306a36Sopenharmony_ciunsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu,
203162306a36Sopenharmony_ci			    unsigned int *idx)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	unsigned int i = 0;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	while (i < NMTUS - 1 && mtus[i + 1] <= mtu)
203662306a36Sopenharmony_ci		++i;
203762306a36Sopenharmony_ci	if (idx)
203862306a36Sopenharmony_ci		*idx = i;
203962306a36Sopenharmony_ci	return mtus[i];
204062306a36Sopenharmony_ci}
204162306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_best_mtu);
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci/**
204462306a36Sopenharmony_ci *     cxgb4_best_aligned_mtu - find best MTU, [hopefully] data size aligned
204562306a36Sopenharmony_ci *     @mtus: the HW MTU table
204662306a36Sopenharmony_ci *     @header_size: Header Size
204762306a36Sopenharmony_ci *     @data_size_max: maximum Data Segment Size
204862306a36Sopenharmony_ci *     @data_size_align: desired Data Segment Size Alignment (2^N)
204962306a36Sopenharmony_ci *     @mtu_idxp: HW MTU Table Index return value pointer (possibly NULL)
205062306a36Sopenharmony_ci *
205162306a36Sopenharmony_ci *     Similar to cxgb4_best_mtu() but instead of searching the Hardware
205262306a36Sopenharmony_ci *     MTU Table based solely on a Maximum MTU parameter, we break that
205362306a36Sopenharmony_ci *     parameter up into a Header Size and Maximum Data Segment Size, and
205462306a36Sopenharmony_ci *     provide a desired Data Segment Size Alignment.  If we find an MTU in
205562306a36Sopenharmony_ci *     the Hardware MTU Table which will result in a Data Segment Size with
205662306a36Sopenharmony_ci *     the requested alignment _and_ that MTU isn't "too far" from the
205762306a36Sopenharmony_ci *     closest MTU, then we'll return that rather than the closest MTU.
205862306a36Sopenharmony_ci */
205962306a36Sopenharmony_ciunsigned int cxgb4_best_aligned_mtu(const unsigned short *mtus,
206062306a36Sopenharmony_ci				    unsigned short header_size,
206162306a36Sopenharmony_ci				    unsigned short data_size_max,
206262306a36Sopenharmony_ci				    unsigned short data_size_align,
206362306a36Sopenharmony_ci				    unsigned int *mtu_idxp)
206462306a36Sopenharmony_ci{
206562306a36Sopenharmony_ci	unsigned short max_mtu = header_size + data_size_max;
206662306a36Sopenharmony_ci	unsigned short data_size_align_mask = data_size_align - 1;
206762306a36Sopenharmony_ci	int mtu_idx, aligned_mtu_idx;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	/* Scan the MTU Table till we find an MTU which is larger than our
207062306a36Sopenharmony_ci	 * Maximum MTU or we reach the end of the table.  Along the way,
207162306a36Sopenharmony_ci	 * record the last MTU found, if any, which will result in a Data
207262306a36Sopenharmony_ci	 * Segment Length matching the requested alignment.
207362306a36Sopenharmony_ci	 */
207462306a36Sopenharmony_ci	for (mtu_idx = 0, aligned_mtu_idx = -1; mtu_idx < NMTUS; mtu_idx++) {
207562306a36Sopenharmony_ci		unsigned short data_size = mtus[mtu_idx] - header_size;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci		/* If this MTU minus the Header Size would result in a
207862306a36Sopenharmony_ci		 * Data Segment Size of the desired alignment, remember it.
207962306a36Sopenharmony_ci		 */
208062306a36Sopenharmony_ci		if ((data_size & data_size_align_mask) == 0)
208162306a36Sopenharmony_ci			aligned_mtu_idx = mtu_idx;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci		/* If we're not at the end of the Hardware MTU Table and the
208462306a36Sopenharmony_ci		 * next element is larger than our Maximum MTU, drop out of
208562306a36Sopenharmony_ci		 * the loop.
208662306a36Sopenharmony_ci		 */
208762306a36Sopenharmony_ci		if (mtu_idx+1 < NMTUS && mtus[mtu_idx+1] > max_mtu)
208862306a36Sopenharmony_ci			break;
208962306a36Sopenharmony_ci	}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	/* If we fell out of the loop because we ran to the end of the table,
209262306a36Sopenharmony_ci	 * then we just have to use the last [largest] entry.
209362306a36Sopenharmony_ci	 */
209462306a36Sopenharmony_ci	if (mtu_idx == NMTUS)
209562306a36Sopenharmony_ci		mtu_idx--;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	/* If we found an MTU which resulted in the requested Data Segment
209862306a36Sopenharmony_ci	 * Length alignment and that's "not far" from the largest MTU which is
209962306a36Sopenharmony_ci	 * less than or equal to the maximum MTU, then use that.
210062306a36Sopenharmony_ci	 */
210162306a36Sopenharmony_ci	if (aligned_mtu_idx >= 0 &&
210262306a36Sopenharmony_ci	    mtu_idx - aligned_mtu_idx <= 1)
210362306a36Sopenharmony_ci		mtu_idx = aligned_mtu_idx;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	/* If the caller has passed in an MTU Index pointer, pass the
210662306a36Sopenharmony_ci	 * MTU Index back.  Return the MTU value.
210762306a36Sopenharmony_ci	 */
210862306a36Sopenharmony_ci	if (mtu_idxp)
210962306a36Sopenharmony_ci		*mtu_idxp = mtu_idx;
211062306a36Sopenharmony_ci	return mtus[mtu_idx];
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_best_aligned_mtu);
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci/**
211562306a36Sopenharmony_ci *	cxgb4_port_chan - get the HW channel of a port
211662306a36Sopenharmony_ci *	@dev: the net device for the port
211762306a36Sopenharmony_ci *
211862306a36Sopenharmony_ci *	Return the HW Tx channel of the given port.
211962306a36Sopenharmony_ci */
212062306a36Sopenharmony_ciunsigned int cxgb4_port_chan(const struct net_device *dev)
212162306a36Sopenharmony_ci{
212262306a36Sopenharmony_ci	return netdev2pinfo(dev)->tx_chan;
212362306a36Sopenharmony_ci}
212462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_chan);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci/**
212762306a36Sopenharmony_ci *      cxgb4_port_e2cchan - get the HW c-channel of a port
212862306a36Sopenharmony_ci *      @dev: the net device for the port
212962306a36Sopenharmony_ci *
213062306a36Sopenharmony_ci *      Return the HW RX c-channel of the given port.
213162306a36Sopenharmony_ci */
213262306a36Sopenharmony_ciunsigned int cxgb4_port_e2cchan(const struct net_device *dev)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	return netdev2pinfo(dev)->rx_cchan;
213562306a36Sopenharmony_ci}
213662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_e2cchan);
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ciunsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo)
213962306a36Sopenharmony_ci{
214062306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
214162306a36Sopenharmony_ci	u32 v1, v2, lp_count, hp_count;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A);
214462306a36Sopenharmony_ci	v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A);
214562306a36Sopenharmony_ci	if (is_t4(adap->params.chip)) {
214662306a36Sopenharmony_ci		lp_count = LP_COUNT_G(v1);
214762306a36Sopenharmony_ci		hp_count = HP_COUNT_G(v1);
214862306a36Sopenharmony_ci	} else {
214962306a36Sopenharmony_ci		lp_count = LP_COUNT_T5_G(v1);
215062306a36Sopenharmony_ci		hp_count = HP_COUNT_T5_G(v2);
215162306a36Sopenharmony_ci	}
215262306a36Sopenharmony_ci	return lpfifo ? lp_count : hp_count;
215362306a36Sopenharmony_ci}
215462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_dbfifo_count);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci/**
215762306a36Sopenharmony_ci *	cxgb4_port_viid - get the VI id of a port
215862306a36Sopenharmony_ci *	@dev: the net device for the port
215962306a36Sopenharmony_ci *
216062306a36Sopenharmony_ci *	Return the VI id of the given port.
216162306a36Sopenharmony_ci */
216262306a36Sopenharmony_ciunsigned int cxgb4_port_viid(const struct net_device *dev)
216362306a36Sopenharmony_ci{
216462306a36Sopenharmony_ci	return netdev2pinfo(dev)->viid;
216562306a36Sopenharmony_ci}
216662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_viid);
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci/**
216962306a36Sopenharmony_ci *	cxgb4_port_idx - get the index of a port
217062306a36Sopenharmony_ci *	@dev: the net device for the port
217162306a36Sopenharmony_ci *
217262306a36Sopenharmony_ci *	Return the index of the given port.
217362306a36Sopenharmony_ci */
217462306a36Sopenharmony_ciunsigned int cxgb4_port_idx(const struct net_device *dev)
217562306a36Sopenharmony_ci{
217662306a36Sopenharmony_ci	return netdev2pinfo(dev)->port_id;
217762306a36Sopenharmony_ci}
217862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_idx);
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_civoid cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4,
218162306a36Sopenharmony_ci			 struct tp_tcp_stats *v6)
218262306a36Sopenharmony_ci{
218362306a36Sopenharmony_ci	struct adapter *adap = pci_get_drvdata(pdev);
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	spin_lock(&adap->stats_lock);
218662306a36Sopenharmony_ci	t4_tp_get_tcp_stats(adap, v4, v6, false);
218762306a36Sopenharmony_ci	spin_unlock(&adap->stats_lock);
218862306a36Sopenharmony_ci}
218962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_get_tcp_stats);
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_civoid cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask,
219262306a36Sopenharmony_ci		      const unsigned int *pgsz_order)
219362306a36Sopenharmony_ci{
219462306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK_A, tag_mask);
219762306a36Sopenharmony_ci	t4_write_reg(adap, ULP_RX_ISCSI_PSZ_A, HPZ0_V(pgsz_order[0]) |
219862306a36Sopenharmony_ci		     HPZ1_V(pgsz_order[1]) | HPZ2_V(pgsz_order[2]) |
219962306a36Sopenharmony_ci		     HPZ3_V(pgsz_order[3]));
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_iscsi_init);
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ciint cxgb4_flush_eq_cache(struct net_device *dev)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	return t4_sge_ctxt_flush(adap, adap->mbox, CTXT_EGRESS);
220862306a36Sopenharmony_ci}
220962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_flush_eq_cache);
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_cistatic int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx)
221262306a36Sopenharmony_ci{
221362306a36Sopenharmony_ci	u32 addr = t4_read_reg(adap, SGE_DBQ_CTXT_BADDR_A) + 24 * qid + 8;
221462306a36Sopenharmony_ci	__be64 indices;
221562306a36Sopenharmony_ci	int ret;
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	spin_lock(&adap->win0_lock);
221862306a36Sopenharmony_ci	ret = t4_memory_rw(adap, 0, MEM_EDC0, addr,
221962306a36Sopenharmony_ci			   sizeof(indices), (__be32 *)&indices,
222062306a36Sopenharmony_ci			   T4_MEMORY_READ);
222162306a36Sopenharmony_ci	spin_unlock(&adap->win0_lock);
222262306a36Sopenharmony_ci	if (!ret) {
222362306a36Sopenharmony_ci		*cidx = (be64_to_cpu(indices) >> 25) & 0xffff;
222462306a36Sopenharmony_ci		*pidx = (be64_to_cpu(indices) >> 9) & 0xffff;
222562306a36Sopenharmony_ci	}
222662306a36Sopenharmony_ci	return ret;
222762306a36Sopenharmony_ci}
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ciint cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx,
223062306a36Sopenharmony_ci			u16 size)
223162306a36Sopenharmony_ci{
223262306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
223362306a36Sopenharmony_ci	u16 hw_pidx, hw_cidx;
223462306a36Sopenharmony_ci	int ret;
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	ret = read_eq_indices(adap, qid, &hw_pidx, &hw_cidx);
223762306a36Sopenharmony_ci	if (ret)
223862306a36Sopenharmony_ci		goto out;
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	if (pidx != hw_pidx) {
224162306a36Sopenharmony_ci		u16 delta;
224262306a36Sopenharmony_ci		u32 val;
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci		if (pidx >= hw_pidx)
224562306a36Sopenharmony_ci			delta = pidx - hw_pidx;
224662306a36Sopenharmony_ci		else
224762306a36Sopenharmony_ci			delta = size - hw_pidx + pidx;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci		if (is_t4(adap->params.chip))
225062306a36Sopenharmony_ci			val = PIDX_V(delta);
225162306a36Sopenharmony_ci		else
225262306a36Sopenharmony_ci			val = PIDX_T5_V(delta);
225362306a36Sopenharmony_ci		wmb();
225462306a36Sopenharmony_ci		t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A),
225562306a36Sopenharmony_ci			     QID_V(qid) | val);
225662306a36Sopenharmony_ci	}
225762306a36Sopenharmony_ciout:
225862306a36Sopenharmony_ci	return ret;
225962306a36Sopenharmony_ci}
226062306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_sync_txq_pidx);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ciint cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte)
226362306a36Sopenharmony_ci{
226462306a36Sopenharmony_ci	u32 edc0_size, edc1_size, mc0_size, mc1_size, size;
226562306a36Sopenharmony_ci	u32 edc0_end, edc1_end, mc0_end, mc1_end;
226662306a36Sopenharmony_ci	u32 offset, memtype, memaddr;
226762306a36Sopenharmony_ci	struct adapter *adap;
226862306a36Sopenharmony_ci	u32 hma_size = 0;
226962306a36Sopenharmony_ci	int ret;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	adap = netdev2adap(dev);
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	offset = ((stag >> 8) * 32) + adap->vres.stag.start;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	/* Figure out where the offset lands in the Memory Type/Address scheme.
227662306a36Sopenharmony_ci	 * This code assumes that the memory is laid out starting at offset 0
227762306a36Sopenharmony_ci	 * with no breaks as: EDC0, EDC1, MC0, MC1. All cards have both EDC0
227862306a36Sopenharmony_ci	 * and EDC1.  Some cards will have neither MC0 nor MC1, most cards have
227962306a36Sopenharmony_ci	 * MC0, and some have both MC0 and MC1.
228062306a36Sopenharmony_ci	 */
228162306a36Sopenharmony_ci	size = t4_read_reg(adap, MA_EDRAM0_BAR_A);
228262306a36Sopenharmony_ci	edc0_size = EDRAM0_SIZE_G(size) << 20;
228362306a36Sopenharmony_ci	size = t4_read_reg(adap, MA_EDRAM1_BAR_A);
228462306a36Sopenharmony_ci	edc1_size = EDRAM1_SIZE_G(size) << 20;
228562306a36Sopenharmony_ci	size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A);
228662306a36Sopenharmony_ci	mc0_size = EXT_MEM0_SIZE_G(size) << 20;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	if (t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A) & HMA_MUX_F) {
228962306a36Sopenharmony_ci		size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
229062306a36Sopenharmony_ci		hma_size = EXT_MEM1_SIZE_G(size) << 20;
229162306a36Sopenharmony_ci	}
229262306a36Sopenharmony_ci	edc0_end = edc0_size;
229362306a36Sopenharmony_ci	edc1_end = edc0_end + edc1_size;
229462306a36Sopenharmony_ci	mc0_end = edc1_end + mc0_size;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	if (offset < edc0_end) {
229762306a36Sopenharmony_ci		memtype = MEM_EDC0;
229862306a36Sopenharmony_ci		memaddr = offset;
229962306a36Sopenharmony_ci	} else if (offset < edc1_end) {
230062306a36Sopenharmony_ci		memtype = MEM_EDC1;
230162306a36Sopenharmony_ci		memaddr = offset - edc0_end;
230262306a36Sopenharmony_ci	} else {
230362306a36Sopenharmony_ci		if (hma_size && (offset < (edc1_end + hma_size))) {
230462306a36Sopenharmony_ci			memtype = MEM_HMA;
230562306a36Sopenharmony_ci			memaddr = offset - edc1_end;
230662306a36Sopenharmony_ci		} else if (offset < mc0_end) {
230762306a36Sopenharmony_ci			memtype = MEM_MC0;
230862306a36Sopenharmony_ci			memaddr = offset - edc1_end;
230962306a36Sopenharmony_ci		} else if (is_t5(adap->params.chip)) {
231062306a36Sopenharmony_ci			size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
231162306a36Sopenharmony_ci			mc1_size = EXT_MEM1_SIZE_G(size) << 20;
231262306a36Sopenharmony_ci			mc1_end = mc0_end + mc1_size;
231362306a36Sopenharmony_ci			if (offset < mc1_end) {
231462306a36Sopenharmony_ci				memtype = MEM_MC1;
231562306a36Sopenharmony_ci				memaddr = offset - mc0_end;
231662306a36Sopenharmony_ci			} else {
231762306a36Sopenharmony_ci				/* offset beyond the end of any memory */
231862306a36Sopenharmony_ci				goto err;
231962306a36Sopenharmony_ci			}
232062306a36Sopenharmony_ci		} else {
232162306a36Sopenharmony_ci			/* T4/T6 only has a single memory channel */
232262306a36Sopenharmony_ci			goto err;
232362306a36Sopenharmony_ci		}
232462306a36Sopenharmony_ci	}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	spin_lock(&adap->win0_lock);
232762306a36Sopenharmony_ci	ret = t4_memory_rw(adap, 0, memtype, memaddr, 32, tpte, T4_MEMORY_READ);
232862306a36Sopenharmony_ci	spin_unlock(&adap->win0_lock);
232962306a36Sopenharmony_ci	return ret;
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_cierr:
233262306a36Sopenharmony_ci	dev_err(adap->pdev_dev, "stag %#x, offset %#x out of range\n",
233362306a36Sopenharmony_ci		stag, offset);
233462306a36Sopenharmony_ci	return -EINVAL;
233562306a36Sopenharmony_ci}
233662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_read_tpte);
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ciu64 cxgb4_read_sge_timestamp(struct net_device *dev)
233962306a36Sopenharmony_ci{
234062306a36Sopenharmony_ci	u32 hi, lo;
234162306a36Sopenharmony_ci	struct adapter *adap;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	adap = netdev2adap(dev);
234462306a36Sopenharmony_ci	lo = t4_read_reg(adap, SGE_TIMESTAMP_LO_A);
234562306a36Sopenharmony_ci	hi = TSVAL_G(t4_read_reg(adap, SGE_TIMESTAMP_HI_A));
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	return ((u64)hi << 32) | (u64)lo;
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_read_sge_timestamp);
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ciint cxgb4_bar2_sge_qregs(struct net_device *dev,
235262306a36Sopenharmony_ci			 unsigned int qid,
235362306a36Sopenharmony_ci			 enum cxgb4_bar2_qtype qtype,
235462306a36Sopenharmony_ci			 int user,
235562306a36Sopenharmony_ci			 u64 *pbar2_qoffset,
235662306a36Sopenharmony_ci			 unsigned int *pbar2_qid)
235762306a36Sopenharmony_ci{
235862306a36Sopenharmony_ci	return t4_bar2_sge_qregs(netdev2adap(dev),
235962306a36Sopenharmony_ci				 qid,
236062306a36Sopenharmony_ci				 (qtype == CXGB4_BAR2_QTYPE_EGRESS
236162306a36Sopenharmony_ci				  ? T4_BAR2_QTYPE_EGRESS
236262306a36Sopenharmony_ci				  : T4_BAR2_QTYPE_INGRESS),
236362306a36Sopenharmony_ci				 user,
236462306a36Sopenharmony_ci				 pbar2_qoffset,
236562306a36Sopenharmony_ci				 pbar2_qid);
236662306a36Sopenharmony_ci}
236762306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_bar2_sge_qregs);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_cistatic struct pci_driver cxgb4_driver;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_cistatic void check_neigh_update(struct neighbour *neigh)
237262306a36Sopenharmony_ci{
237362306a36Sopenharmony_ci	const struct device *parent;
237462306a36Sopenharmony_ci	const struct net_device *netdev = neigh->dev;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	if (is_vlan_dev(netdev))
237762306a36Sopenharmony_ci		netdev = vlan_dev_real_dev(netdev);
237862306a36Sopenharmony_ci	parent = netdev->dev.parent;
237962306a36Sopenharmony_ci	if (parent && parent->driver == &cxgb4_driver.driver)
238062306a36Sopenharmony_ci		t4_l2t_update(dev_get_drvdata(parent), neigh);
238162306a36Sopenharmony_ci}
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_cistatic int netevent_cb(struct notifier_block *nb, unsigned long event,
238462306a36Sopenharmony_ci		       void *data)
238562306a36Sopenharmony_ci{
238662306a36Sopenharmony_ci	switch (event) {
238762306a36Sopenharmony_ci	case NETEVENT_NEIGH_UPDATE:
238862306a36Sopenharmony_ci		check_neigh_update(data);
238962306a36Sopenharmony_ci		break;
239062306a36Sopenharmony_ci	case NETEVENT_REDIRECT:
239162306a36Sopenharmony_ci	default:
239262306a36Sopenharmony_ci		break;
239362306a36Sopenharmony_ci	}
239462306a36Sopenharmony_ci	return 0;
239562306a36Sopenharmony_ci}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_cistatic bool netevent_registered;
239862306a36Sopenharmony_cistatic struct notifier_block cxgb4_netevent_nb = {
239962306a36Sopenharmony_ci	.notifier_call = netevent_cb
240062306a36Sopenharmony_ci};
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_cistatic void drain_db_fifo(struct adapter *adap, int usecs)
240362306a36Sopenharmony_ci{
240462306a36Sopenharmony_ci	u32 v1, v2, lp_count, hp_count;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	do {
240762306a36Sopenharmony_ci		v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A);
240862306a36Sopenharmony_ci		v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A);
240962306a36Sopenharmony_ci		if (is_t4(adap->params.chip)) {
241062306a36Sopenharmony_ci			lp_count = LP_COUNT_G(v1);
241162306a36Sopenharmony_ci			hp_count = HP_COUNT_G(v1);
241262306a36Sopenharmony_ci		} else {
241362306a36Sopenharmony_ci			lp_count = LP_COUNT_T5_G(v1);
241462306a36Sopenharmony_ci			hp_count = HP_COUNT_T5_G(v2);
241562306a36Sopenharmony_ci		}
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci		if (lp_count == 0 && hp_count == 0)
241862306a36Sopenharmony_ci			break;
241962306a36Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
242062306a36Sopenharmony_ci		schedule_timeout(usecs_to_jiffies(usecs));
242162306a36Sopenharmony_ci	} while (1);
242262306a36Sopenharmony_ci}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_cistatic void disable_txq_db(struct sge_txq *q)
242562306a36Sopenharmony_ci{
242662306a36Sopenharmony_ci	unsigned long flags;
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	spin_lock_irqsave(&q->db_lock, flags);
242962306a36Sopenharmony_ci	q->db_disabled = 1;
243062306a36Sopenharmony_ci	spin_unlock_irqrestore(&q->db_lock, flags);
243162306a36Sopenharmony_ci}
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_cistatic void enable_txq_db(struct adapter *adap, struct sge_txq *q)
243462306a36Sopenharmony_ci{
243562306a36Sopenharmony_ci	spin_lock_irq(&q->db_lock);
243662306a36Sopenharmony_ci	if (q->db_pidx_inc) {
243762306a36Sopenharmony_ci		/* Make sure that all writes to the TX descriptors
243862306a36Sopenharmony_ci		 * are committed before we tell HW about them.
243962306a36Sopenharmony_ci		 */
244062306a36Sopenharmony_ci		wmb();
244162306a36Sopenharmony_ci		t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A),
244262306a36Sopenharmony_ci			     QID_V(q->cntxt_id) | PIDX_V(q->db_pidx_inc));
244362306a36Sopenharmony_ci		q->db_pidx_inc = 0;
244462306a36Sopenharmony_ci	}
244562306a36Sopenharmony_ci	q->db_disabled = 0;
244662306a36Sopenharmony_ci	spin_unlock_irq(&q->db_lock);
244762306a36Sopenharmony_ci}
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_cistatic void disable_dbs(struct adapter *adap)
245062306a36Sopenharmony_ci{
245162306a36Sopenharmony_ci	int i;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	for_each_ethrxq(&adap->sge, i)
245462306a36Sopenharmony_ci		disable_txq_db(&adap->sge.ethtxq[i].q);
245562306a36Sopenharmony_ci	if (is_offload(adap)) {
245662306a36Sopenharmony_ci		struct sge_uld_txq_info *txq_info =
245762306a36Sopenharmony_ci			adap->sge.uld_txq_info[CXGB4_TX_OFLD];
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci		if (txq_info) {
246062306a36Sopenharmony_ci			for_each_ofldtxq(&adap->sge, i) {
246162306a36Sopenharmony_ci				struct sge_uld_txq *txq = &txq_info->uldtxq[i];
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci				disable_txq_db(&txq->q);
246462306a36Sopenharmony_ci			}
246562306a36Sopenharmony_ci		}
246662306a36Sopenharmony_ci	}
246762306a36Sopenharmony_ci	for_each_port(adap, i)
246862306a36Sopenharmony_ci		disable_txq_db(&adap->sge.ctrlq[i].q);
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_cistatic void enable_dbs(struct adapter *adap)
247262306a36Sopenharmony_ci{
247362306a36Sopenharmony_ci	int i;
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	for_each_ethrxq(&adap->sge, i)
247662306a36Sopenharmony_ci		enable_txq_db(adap, &adap->sge.ethtxq[i].q);
247762306a36Sopenharmony_ci	if (is_offload(adap)) {
247862306a36Sopenharmony_ci		struct sge_uld_txq_info *txq_info =
247962306a36Sopenharmony_ci			adap->sge.uld_txq_info[CXGB4_TX_OFLD];
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci		if (txq_info) {
248262306a36Sopenharmony_ci			for_each_ofldtxq(&adap->sge, i) {
248362306a36Sopenharmony_ci				struct sge_uld_txq *txq = &txq_info->uldtxq[i];
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci				enable_txq_db(adap, &txq->q);
248662306a36Sopenharmony_ci			}
248762306a36Sopenharmony_ci		}
248862306a36Sopenharmony_ci	}
248962306a36Sopenharmony_ci	for_each_port(adap, i)
249062306a36Sopenharmony_ci		enable_txq_db(adap, &adap->sge.ctrlq[i].q);
249162306a36Sopenharmony_ci}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_cistatic void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
249462306a36Sopenharmony_ci{
249562306a36Sopenharmony_ci	enum cxgb4_uld type = CXGB4_ULD_RDMA;
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	if (adap->uld && adap->uld[type].handle)
249862306a36Sopenharmony_ci		adap->uld[type].control(adap->uld[type].handle, cmd);
249962306a36Sopenharmony_ci}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_cistatic void process_db_full(struct work_struct *work)
250262306a36Sopenharmony_ci{
250362306a36Sopenharmony_ci	struct adapter *adap;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	adap = container_of(work, struct adapter, db_full_task);
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	drain_db_fifo(adap, dbfifo_drain_delay);
250862306a36Sopenharmony_ci	enable_dbs(adap);
250962306a36Sopenharmony_ci	notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
251062306a36Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
251162306a36Sopenharmony_ci		t4_set_reg_field(adap, SGE_INT_ENABLE3_A,
251262306a36Sopenharmony_ci				 DBFIFO_HP_INT_F | DBFIFO_LP_INT_F,
251362306a36Sopenharmony_ci				 DBFIFO_HP_INT_F | DBFIFO_LP_INT_F);
251462306a36Sopenharmony_ci	else
251562306a36Sopenharmony_ci		t4_set_reg_field(adap, SGE_INT_ENABLE3_A,
251662306a36Sopenharmony_ci				 DBFIFO_LP_INT_F, DBFIFO_LP_INT_F);
251762306a36Sopenharmony_ci}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_cistatic void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	u16 hw_pidx, hw_cidx;
252262306a36Sopenharmony_ci	int ret;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	spin_lock_irq(&q->db_lock);
252562306a36Sopenharmony_ci	ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx);
252662306a36Sopenharmony_ci	if (ret)
252762306a36Sopenharmony_ci		goto out;
252862306a36Sopenharmony_ci	if (q->db_pidx != hw_pidx) {
252962306a36Sopenharmony_ci		u16 delta;
253062306a36Sopenharmony_ci		u32 val;
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci		if (q->db_pidx >= hw_pidx)
253362306a36Sopenharmony_ci			delta = q->db_pidx - hw_pidx;
253462306a36Sopenharmony_ci		else
253562306a36Sopenharmony_ci			delta = q->size - hw_pidx + q->db_pidx;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci		if (is_t4(adap->params.chip))
253862306a36Sopenharmony_ci			val = PIDX_V(delta);
253962306a36Sopenharmony_ci		else
254062306a36Sopenharmony_ci			val = PIDX_T5_V(delta);
254162306a36Sopenharmony_ci		wmb();
254262306a36Sopenharmony_ci		t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A),
254362306a36Sopenharmony_ci			     QID_V(q->cntxt_id) | val);
254462306a36Sopenharmony_ci	}
254562306a36Sopenharmony_ciout:
254662306a36Sopenharmony_ci	q->db_disabled = 0;
254762306a36Sopenharmony_ci	q->db_pidx_inc = 0;
254862306a36Sopenharmony_ci	spin_unlock_irq(&q->db_lock);
254962306a36Sopenharmony_ci	if (ret)
255062306a36Sopenharmony_ci		CH_WARN(adap, "DB drop recovery failed.\n");
255162306a36Sopenharmony_ci}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_cistatic void recover_all_queues(struct adapter *adap)
255462306a36Sopenharmony_ci{
255562306a36Sopenharmony_ci	int i;
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	for_each_ethrxq(&adap->sge, i)
255862306a36Sopenharmony_ci		sync_txq_pidx(adap, &adap->sge.ethtxq[i].q);
255962306a36Sopenharmony_ci	if (is_offload(adap)) {
256062306a36Sopenharmony_ci		struct sge_uld_txq_info *txq_info =
256162306a36Sopenharmony_ci			adap->sge.uld_txq_info[CXGB4_TX_OFLD];
256262306a36Sopenharmony_ci		if (txq_info) {
256362306a36Sopenharmony_ci			for_each_ofldtxq(&adap->sge, i) {
256462306a36Sopenharmony_ci				struct sge_uld_txq *txq = &txq_info->uldtxq[i];
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci				sync_txq_pidx(adap, &txq->q);
256762306a36Sopenharmony_ci			}
256862306a36Sopenharmony_ci		}
256962306a36Sopenharmony_ci	}
257062306a36Sopenharmony_ci	for_each_port(adap, i)
257162306a36Sopenharmony_ci		sync_txq_pidx(adap, &adap->sge.ctrlq[i].q);
257262306a36Sopenharmony_ci}
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_cistatic void process_db_drop(struct work_struct *work)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	struct adapter *adap;
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	adap = container_of(work, struct adapter, db_drop_task);
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	if (is_t4(adap->params.chip)) {
258162306a36Sopenharmony_ci		drain_db_fifo(adap, dbfifo_drain_delay);
258262306a36Sopenharmony_ci		notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP);
258362306a36Sopenharmony_ci		drain_db_fifo(adap, dbfifo_drain_delay);
258462306a36Sopenharmony_ci		recover_all_queues(adap);
258562306a36Sopenharmony_ci		drain_db_fifo(adap, dbfifo_drain_delay);
258662306a36Sopenharmony_ci		enable_dbs(adap);
258762306a36Sopenharmony_ci		notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
258862306a36Sopenharmony_ci	} else if (is_t5(adap->params.chip)) {
258962306a36Sopenharmony_ci		u32 dropped_db = t4_read_reg(adap, 0x010ac);
259062306a36Sopenharmony_ci		u16 qid = (dropped_db >> 15) & 0x1ffff;
259162306a36Sopenharmony_ci		u16 pidx_inc = dropped_db & 0x1fff;
259262306a36Sopenharmony_ci		u64 bar2_qoffset;
259362306a36Sopenharmony_ci		unsigned int bar2_qid;
259462306a36Sopenharmony_ci		int ret;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci		ret = t4_bar2_sge_qregs(adap, qid, T4_BAR2_QTYPE_EGRESS,
259762306a36Sopenharmony_ci					0, &bar2_qoffset, &bar2_qid);
259862306a36Sopenharmony_ci		if (ret)
259962306a36Sopenharmony_ci			dev_err(adap->pdev_dev, "doorbell drop recovery: "
260062306a36Sopenharmony_ci				"qid=%d, pidx_inc=%d\n", qid, pidx_inc);
260162306a36Sopenharmony_ci		else
260262306a36Sopenharmony_ci			writel(PIDX_T5_V(pidx_inc) | QID_V(bar2_qid),
260362306a36Sopenharmony_ci			       adap->bar2 + bar2_qoffset + SGE_UDB_KDOORBELL);
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci		/* Re-enable BAR2 WC */
260662306a36Sopenharmony_ci		t4_set_reg_field(adap, 0x10b0, 1<<15, 1<<15);
260762306a36Sopenharmony_ci	}
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)
261062306a36Sopenharmony_ci		t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, DROPPED_DB_F, 0);
261162306a36Sopenharmony_ci}
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_civoid t4_db_full(struct adapter *adap)
261462306a36Sopenharmony_ci{
261562306a36Sopenharmony_ci	if (is_t4(adap->params.chip)) {
261662306a36Sopenharmony_ci		disable_dbs(adap);
261762306a36Sopenharmony_ci		notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
261862306a36Sopenharmony_ci		t4_set_reg_field(adap, SGE_INT_ENABLE3_A,
261962306a36Sopenharmony_ci				 DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, 0);
262062306a36Sopenharmony_ci		queue_work(adap->workq, &adap->db_full_task);
262162306a36Sopenharmony_ci	}
262262306a36Sopenharmony_ci}
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_civoid t4_db_dropped(struct adapter *adap)
262562306a36Sopenharmony_ci{
262662306a36Sopenharmony_ci	if (is_t4(adap->params.chip)) {
262762306a36Sopenharmony_ci		disable_dbs(adap);
262862306a36Sopenharmony_ci		notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
262962306a36Sopenharmony_ci	}
263062306a36Sopenharmony_ci	queue_work(adap->workq, &adap->db_drop_task);
263162306a36Sopenharmony_ci}
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_civoid t4_register_netevent_notifier(void)
263462306a36Sopenharmony_ci{
263562306a36Sopenharmony_ci	if (!netevent_registered) {
263662306a36Sopenharmony_ci		register_netevent_notifier(&cxgb4_netevent_nb);
263762306a36Sopenharmony_ci		netevent_registered = true;
263862306a36Sopenharmony_ci	}
263962306a36Sopenharmony_ci}
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_cistatic void detach_ulds(struct adapter *adap)
264262306a36Sopenharmony_ci{
264362306a36Sopenharmony_ci	unsigned int i;
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci	if (!is_uld(adap))
264662306a36Sopenharmony_ci		return;
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	mutex_lock(&uld_mutex);
264962306a36Sopenharmony_ci	list_del(&adap->list_node);
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	for (i = 0; i < CXGB4_ULD_MAX; i++)
265262306a36Sopenharmony_ci		if (adap->uld && adap->uld[i].handle)
265362306a36Sopenharmony_ci			adap->uld[i].state_change(adap->uld[i].handle,
265462306a36Sopenharmony_ci					     CXGB4_STATE_DETACH);
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	if (netevent_registered && list_empty(&adapter_list)) {
265762306a36Sopenharmony_ci		unregister_netevent_notifier(&cxgb4_netevent_nb);
265862306a36Sopenharmony_ci		netevent_registered = false;
265962306a36Sopenharmony_ci	}
266062306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
266162306a36Sopenharmony_ci}
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_cistatic void notify_ulds(struct adapter *adap, enum cxgb4_state new_state)
266462306a36Sopenharmony_ci{
266562306a36Sopenharmony_ci	unsigned int i;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	mutex_lock(&uld_mutex);
266862306a36Sopenharmony_ci	for (i = 0; i < CXGB4_ULD_MAX; i++)
266962306a36Sopenharmony_ci		if (adap->uld && adap->uld[i].handle)
267062306a36Sopenharmony_ci			adap->uld[i].state_change(adap->uld[i].handle,
267162306a36Sopenharmony_ci						  new_state);
267262306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
267362306a36Sopenharmony_ci}
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
267662306a36Sopenharmony_cistatic int cxgb4_inet6addr_handler(struct notifier_block *this,
267762306a36Sopenharmony_ci				   unsigned long event, void *data)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	struct inet6_ifaddr *ifa = data;
268062306a36Sopenharmony_ci	struct net_device *event_dev = ifa->idev->dev;
268162306a36Sopenharmony_ci	const struct device *parent = NULL;
268262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BONDING)
268362306a36Sopenharmony_ci	struct adapter *adap;
268462306a36Sopenharmony_ci#endif
268562306a36Sopenharmony_ci	if (is_vlan_dev(event_dev))
268662306a36Sopenharmony_ci		event_dev = vlan_dev_real_dev(event_dev);
268762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BONDING)
268862306a36Sopenharmony_ci	if (event_dev->flags & IFF_MASTER) {
268962306a36Sopenharmony_ci		list_for_each_entry(adap, &adapter_list, list_node) {
269062306a36Sopenharmony_ci			switch (event) {
269162306a36Sopenharmony_ci			case NETDEV_UP:
269262306a36Sopenharmony_ci				cxgb4_clip_get(adap->port[0],
269362306a36Sopenharmony_ci					       (const u32 *)ifa, 1);
269462306a36Sopenharmony_ci				break;
269562306a36Sopenharmony_ci			case NETDEV_DOWN:
269662306a36Sopenharmony_ci				cxgb4_clip_release(adap->port[0],
269762306a36Sopenharmony_ci						   (const u32 *)ifa, 1);
269862306a36Sopenharmony_ci				break;
269962306a36Sopenharmony_ci			default:
270062306a36Sopenharmony_ci				break;
270162306a36Sopenharmony_ci			}
270262306a36Sopenharmony_ci		}
270362306a36Sopenharmony_ci		return NOTIFY_OK;
270462306a36Sopenharmony_ci	}
270562306a36Sopenharmony_ci#endif
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	if (event_dev)
270862306a36Sopenharmony_ci		parent = event_dev->dev.parent;
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	if (parent && parent->driver == &cxgb4_driver.driver) {
271162306a36Sopenharmony_ci		switch (event) {
271262306a36Sopenharmony_ci		case NETDEV_UP:
271362306a36Sopenharmony_ci			cxgb4_clip_get(event_dev, (const u32 *)ifa, 1);
271462306a36Sopenharmony_ci			break;
271562306a36Sopenharmony_ci		case NETDEV_DOWN:
271662306a36Sopenharmony_ci			cxgb4_clip_release(event_dev, (const u32 *)ifa, 1);
271762306a36Sopenharmony_ci			break;
271862306a36Sopenharmony_ci		default:
271962306a36Sopenharmony_ci			break;
272062306a36Sopenharmony_ci		}
272162306a36Sopenharmony_ci	}
272262306a36Sopenharmony_ci	return NOTIFY_OK;
272362306a36Sopenharmony_ci}
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_cistatic bool inet6addr_registered;
272662306a36Sopenharmony_cistatic struct notifier_block cxgb4_inet6addr_notifier = {
272762306a36Sopenharmony_ci	.notifier_call = cxgb4_inet6addr_handler
272862306a36Sopenharmony_ci};
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_cistatic void update_clip(const struct adapter *adap)
273162306a36Sopenharmony_ci{
273262306a36Sopenharmony_ci	int i;
273362306a36Sopenharmony_ci	struct net_device *dev;
273462306a36Sopenharmony_ci	int ret;
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	rcu_read_lock();
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	for (i = 0; i < MAX_NPORTS; i++) {
273962306a36Sopenharmony_ci		dev = adap->port[i];
274062306a36Sopenharmony_ci		ret = 0;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci		if (dev)
274362306a36Sopenharmony_ci			ret = cxgb4_update_root_dev_clip(dev);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci		if (ret < 0)
274662306a36Sopenharmony_ci			break;
274762306a36Sopenharmony_ci	}
274862306a36Sopenharmony_ci	rcu_read_unlock();
274962306a36Sopenharmony_ci}
275062306a36Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_IPV6) */
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci/**
275362306a36Sopenharmony_ci *	cxgb_up - enable the adapter
275462306a36Sopenharmony_ci *	@adap: adapter being enabled
275562306a36Sopenharmony_ci *
275662306a36Sopenharmony_ci *	Called when the first port is enabled, this function performs the
275762306a36Sopenharmony_ci *	actions necessary to make an adapter operational, such as completing
275862306a36Sopenharmony_ci *	the initialization of HW modules, and enabling interrupts.
275962306a36Sopenharmony_ci *
276062306a36Sopenharmony_ci *	Must be called with the rtnl lock held.
276162306a36Sopenharmony_ci */
276262306a36Sopenharmony_cistatic int cxgb_up(struct adapter *adap)
276362306a36Sopenharmony_ci{
276462306a36Sopenharmony_ci	struct sge *s = &adap->sge;
276562306a36Sopenharmony_ci	int err;
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	mutex_lock(&uld_mutex);
276862306a36Sopenharmony_ci	err = setup_sge_queues(adap);
276962306a36Sopenharmony_ci	if (err)
277062306a36Sopenharmony_ci		goto rel_lock;
277162306a36Sopenharmony_ci	err = setup_rss(adap);
277262306a36Sopenharmony_ci	if (err)
277362306a36Sopenharmony_ci		goto freeq;
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	if (adap->flags & CXGB4_USING_MSIX) {
277662306a36Sopenharmony_ci		if (s->nd_msix_idx < 0) {
277762306a36Sopenharmony_ci			err = -ENOMEM;
277862306a36Sopenharmony_ci			goto irq_err;
277962306a36Sopenharmony_ci		}
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci		err = request_irq(adap->msix_info[s->nd_msix_idx].vec,
278262306a36Sopenharmony_ci				  t4_nondata_intr, 0,
278362306a36Sopenharmony_ci				  adap->msix_info[s->nd_msix_idx].desc, adap);
278462306a36Sopenharmony_ci		if (err)
278562306a36Sopenharmony_ci			goto irq_err;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci		err = request_msix_queue_irqs(adap);
278862306a36Sopenharmony_ci		if (err)
278962306a36Sopenharmony_ci			goto irq_err_free_nd_msix;
279062306a36Sopenharmony_ci	} else {
279162306a36Sopenharmony_ci		err = request_irq(adap->pdev->irq, t4_intr_handler(adap),
279262306a36Sopenharmony_ci				  (adap->flags & CXGB4_USING_MSI) ? 0
279362306a36Sopenharmony_ci								  : IRQF_SHARED,
279462306a36Sopenharmony_ci				  adap->port[0]->name, adap);
279562306a36Sopenharmony_ci		if (err)
279662306a36Sopenharmony_ci			goto irq_err;
279762306a36Sopenharmony_ci	}
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	enable_rx(adap);
280062306a36Sopenharmony_ci	t4_sge_start(adap);
280162306a36Sopenharmony_ci	t4_intr_enable(adap);
280262306a36Sopenharmony_ci	adap->flags |= CXGB4_FULL_INIT_DONE;
280362306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	notify_ulds(adap, CXGB4_STATE_UP);
280662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
280762306a36Sopenharmony_ci	update_clip(adap);
280862306a36Sopenharmony_ci#endif
280962306a36Sopenharmony_ci	return err;
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ciirq_err_free_nd_msix:
281262306a36Sopenharmony_ci	free_irq(adap->msix_info[s->nd_msix_idx].vec, adap);
281362306a36Sopenharmony_ciirq_err:
281462306a36Sopenharmony_ci	dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err);
281562306a36Sopenharmony_cifreeq:
281662306a36Sopenharmony_ci	t4_free_sge_resources(adap);
281762306a36Sopenharmony_cirel_lock:
281862306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
281962306a36Sopenharmony_ci	return err;
282062306a36Sopenharmony_ci}
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_cistatic void cxgb_down(struct adapter *adapter)
282362306a36Sopenharmony_ci{
282462306a36Sopenharmony_ci	cancel_work_sync(&adapter->tid_release_task);
282562306a36Sopenharmony_ci	cancel_work_sync(&adapter->db_full_task);
282662306a36Sopenharmony_ci	cancel_work_sync(&adapter->db_drop_task);
282762306a36Sopenharmony_ci	adapter->tid_release_task_busy = false;
282862306a36Sopenharmony_ci	adapter->tid_release_head = NULL;
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	t4_sge_stop(adapter);
283162306a36Sopenharmony_ci	t4_free_sge_resources(adapter);
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	adapter->flags &= ~CXGB4_FULL_INIT_DONE;
283462306a36Sopenharmony_ci}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci/*
283762306a36Sopenharmony_ci * net_device operations
283862306a36Sopenharmony_ci */
283962306a36Sopenharmony_cistatic int cxgb_open(struct net_device *dev)
284062306a36Sopenharmony_ci{
284162306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
284262306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
284362306a36Sopenharmony_ci	int err;
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	netif_carrier_off(dev);
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) {
284862306a36Sopenharmony_ci		err = cxgb_up(adapter);
284962306a36Sopenharmony_ci		if (err < 0)
285062306a36Sopenharmony_ci			return err;
285162306a36Sopenharmony_ci	}
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	/* It's possible that the basic port information could have
285462306a36Sopenharmony_ci	 * changed since we first read it.
285562306a36Sopenharmony_ci	 */
285662306a36Sopenharmony_ci	err = t4_update_port_info(pi);
285762306a36Sopenharmony_ci	if (err < 0)
285862306a36Sopenharmony_ci		return err;
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	err = link_start(dev);
286162306a36Sopenharmony_ci	if (err)
286262306a36Sopenharmony_ci		return err;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	if (pi->nmirrorqsets) {
286562306a36Sopenharmony_ci		mutex_lock(&pi->vi_mirror_mutex);
286662306a36Sopenharmony_ci		err = cxgb4_port_mirror_alloc_queues(dev);
286762306a36Sopenharmony_ci		if (err)
286862306a36Sopenharmony_ci			goto out_unlock;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci		err = cxgb4_port_mirror_start(dev);
287162306a36Sopenharmony_ci		if (err)
287262306a36Sopenharmony_ci			goto out_free_queues;
287362306a36Sopenharmony_ci		mutex_unlock(&pi->vi_mirror_mutex);
287462306a36Sopenharmony_ci	}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	netif_tx_start_all_queues(dev);
287762306a36Sopenharmony_ci	return 0;
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ciout_free_queues:
288062306a36Sopenharmony_ci	cxgb4_port_mirror_free_queues(dev);
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ciout_unlock:
288362306a36Sopenharmony_ci	mutex_unlock(&pi->vi_mirror_mutex);
288462306a36Sopenharmony_ci	return err;
288562306a36Sopenharmony_ci}
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_cistatic int cxgb_close(struct net_device *dev)
288862306a36Sopenharmony_ci{
288962306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
289062306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
289162306a36Sopenharmony_ci	int ret;
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	netif_tx_stop_all_queues(dev);
289462306a36Sopenharmony_ci	netif_carrier_off(dev);
289562306a36Sopenharmony_ci	ret = t4_enable_pi_params(adapter, adapter->pf, pi,
289662306a36Sopenharmony_ci				  false, false, false);
289762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
289862306a36Sopenharmony_ci	cxgb4_dcb_reset(dev);
289962306a36Sopenharmony_ci	dcb_tx_queue_prio_enable(dev, false);
290062306a36Sopenharmony_ci#endif
290162306a36Sopenharmony_ci	if (ret)
290262306a36Sopenharmony_ci		return ret;
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	if (pi->nmirrorqsets) {
290562306a36Sopenharmony_ci		mutex_lock(&pi->vi_mirror_mutex);
290662306a36Sopenharmony_ci		cxgb4_port_mirror_stop(dev);
290762306a36Sopenharmony_ci		cxgb4_port_mirror_free_queues(dev);
290862306a36Sopenharmony_ci		mutex_unlock(&pi->vi_mirror_mutex);
290962306a36Sopenharmony_ci	}
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ci	return 0;
291262306a36Sopenharmony_ci}
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ciint cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
291562306a36Sopenharmony_ci		__be32 sip, __be16 sport, __be16 vlan,
291662306a36Sopenharmony_ci		unsigned int queue, unsigned char port, unsigned char mask)
291762306a36Sopenharmony_ci{
291862306a36Sopenharmony_ci	int ret;
291962306a36Sopenharmony_ci	struct filter_entry *f;
292062306a36Sopenharmony_ci	struct adapter *adap;
292162306a36Sopenharmony_ci	int i;
292262306a36Sopenharmony_ci	u8 *val;
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	adap = netdev2adap(dev);
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	/* Adjust stid to correct filter index */
292762306a36Sopenharmony_ci	stid -= adap->tids.sftid_base;
292862306a36Sopenharmony_ci	stid += adap->tids.nftids;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	/* Check to make sure the filter requested is writable ...
293162306a36Sopenharmony_ci	 */
293262306a36Sopenharmony_ci	f = &adap->tids.ftid_tab[stid];
293362306a36Sopenharmony_ci	ret = writable_filter(f);
293462306a36Sopenharmony_ci	if (ret)
293562306a36Sopenharmony_ci		return ret;
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci	/* Clear out any old resources being used by the filter before
293862306a36Sopenharmony_ci	 * we start constructing the new filter.
293962306a36Sopenharmony_ci	 */
294062306a36Sopenharmony_ci	if (f->valid)
294162306a36Sopenharmony_ci		clear_filter(adap, f);
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	/* Clear out filter specifications */
294462306a36Sopenharmony_ci	memset(&f->fs, 0, sizeof(struct ch_filter_specification));
294562306a36Sopenharmony_ci	f->fs.val.lport = be16_to_cpu(sport);
294662306a36Sopenharmony_ci	f->fs.mask.lport  = ~0;
294762306a36Sopenharmony_ci	val = (u8 *)&sip;
294862306a36Sopenharmony_ci	if ((val[0] | val[1] | val[2] | val[3]) != 0) {
294962306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
295062306a36Sopenharmony_ci			f->fs.val.lip[i] = val[i];
295162306a36Sopenharmony_ci			f->fs.mask.lip[i] = ~0;
295262306a36Sopenharmony_ci		}
295362306a36Sopenharmony_ci		if (adap->params.tp.vlan_pri_map & PORT_F) {
295462306a36Sopenharmony_ci			f->fs.val.iport = port;
295562306a36Sopenharmony_ci			f->fs.mask.iport = mask;
295662306a36Sopenharmony_ci		}
295762306a36Sopenharmony_ci	}
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	if (adap->params.tp.vlan_pri_map & PROTOCOL_F) {
296062306a36Sopenharmony_ci		f->fs.val.proto = IPPROTO_TCP;
296162306a36Sopenharmony_ci		f->fs.mask.proto = ~0;
296262306a36Sopenharmony_ci	}
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	f->fs.dirsteer = 1;
296562306a36Sopenharmony_ci	f->fs.iq = queue;
296662306a36Sopenharmony_ci	/* Mark filter as locked */
296762306a36Sopenharmony_ci	f->locked = 1;
296862306a36Sopenharmony_ci	f->fs.rpttid = 1;
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ci	/* Save the actual tid. We need this to get the corresponding
297162306a36Sopenharmony_ci	 * filter entry structure in filter_rpl.
297262306a36Sopenharmony_ci	 */
297362306a36Sopenharmony_ci	f->tid = stid + adap->tids.ftid_base;
297462306a36Sopenharmony_ci	ret = set_filter_wr(adap, stid);
297562306a36Sopenharmony_ci	if (ret) {
297662306a36Sopenharmony_ci		clear_filter(adap, f);
297762306a36Sopenharmony_ci		return ret;
297862306a36Sopenharmony_ci	}
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	return 0;
298162306a36Sopenharmony_ci}
298262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server_filter);
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ciint cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid,
298562306a36Sopenharmony_ci		unsigned int queue, bool ipv6)
298662306a36Sopenharmony_ci{
298762306a36Sopenharmony_ci	struct filter_entry *f;
298862306a36Sopenharmony_ci	struct adapter *adap;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	adap = netdev2adap(dev);
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	/* Adjust stid to correct filter index */
299362306a36Sopenharmony_ci	stid -= adap->tids.sftid_base;
299462306a36Sopenharmony_ci	stid += adap->tids.nftids;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	f = &adap->tids.ftid_tab[stid];
299762306a36Sopenharmony_ci	/* Unlock the filter */
299862306a36Sopenharmony_ci	f->locked = 0;
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_ci	return delete_filter(adap, stid);
300162306a36Sopenharmony_ci}
300262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_server_filter);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_cistatic void cxgb_get_stats(struct net_device *dev,
300562306a36Sopenharmony_ci			   struct rtnl_link_stats64 *ns)
300662306a36Sopenharmony_ci{
300762306a36Sopenharmony_ci	struct port_stats stats;
300862306a36Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
300962306a36Sopenharmony_ci	struct adapter *adapter = p->adapter;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	/* Block retrieving statistics during EEH error
301262306a36Sopenharmony_ci	 * recovery. Otherwise, the recovery might fail
301362306a36Sopenharmony_ci	 * and the PCI device will be removed permanently
301462306a36Sopenharmony_ci	 */
301562306a36Sopenharmony_ci	spin_lock(&adapter->stats_lock);
301662306a36Sopenharmony_ci	if (!netif_device_present(dev)) {
301762306a36Sopenharmony_ci		spin_unlock(&adapter->stats_lock);
301862306a36Sopenharmony_ci		return;
301962306a36Sopenharmony_ci	}
302062306a36Sopenharmony_ci	t4_get_port_stats_offset(adapter, p->tx_chan, &stats,
302162306a36Sopenharmony_ci				 &p->stats_base);
302262306a36Sopenharmony_ci	spin_unlock(&adapter->stats_lock);
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	ns->tx_bytes   = stats.tx_octets;
302562306a36Sopenharmony_ci	ns->tx_packets = stats.tx_frames;
302662306a36Sopenharmony_ci	ns->rx_bytes   = stats.rx_octets;
302762306a36Sopenharmony_ci	ns->rx_packets = stats.rx_frames;
302862306a36Sopenharmony_ci	ns->multicast  = stats.rx_mcast_frames;
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_ci	/* detailed rx_errors */
303162306a36Sopenharmony_ci	ns->rx_length_errors = stats.rx_jabber + stats.rx_too_long +
303262306a36Sopenharmony_ci			       stats.rx_runt;
303362306a36Sopenharmony_ci	ns->rx_over_errors   = 0;
303462306a36Sopenharmony_ci	ns->rx_crc_errors    = stats.rx_fcs_err;
303562306a36Sopenharmony_ci	ns->rx_frame_errors  = stats.rx_symbol_err;
303662306a36Sopenharmony_ci	ns->rx_dropped	     = stats.rx_ovflow0 + stats.rx_ovflow1 +
303762306a36Sopenharmony_ci			       stats.rx_ovflow2 + stats.rx_ovflow3 +
303862306a36Sopenharmony_ci			       stats.rx_trunc0 + stats.rx_trunc1 +
303962306a36Sopenharmony_ci			       stats.rx_trunc2 + stats.rx_trunc3;
304062306a36Sopenharmony_ci	ns->rx_missed_errors = 0;
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	/* detailed tx_errors */
304362306a36Sopenharmony_ci	ns->tx_aborted_errors   = 0;
304462306a36Sopenharmony_ci	ns->tx_carrier_errors   = 0;
304562306a36Sopenharmony_ci	ns->tx_fifo_errors      = 0;
304662306a36Sopenharmony_ci	ns->tx_heartbeat_errors = 0;
304762306a36Sopenharmony_ci	ns->tx_window_errors    = 0;
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	ns->tx_errors = stats.tx_error_frames;
305062306a36Sopenharmony_ci	ns->rx_errors = stats.rx_symbol_err + stats.rx_fcs_err +
305162306a36Sopenharmony_ci		ns->rx_length_errors + stats.rx_len_err + ns->rx_fifo_errors;
305262306a36Sopenharmony_ci}
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_cistatic int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
305562306a36Sopenharmony_ci{
305662306a36Sopenharmony_ci	unsigned int mbox;
305762306a36Sopenharmony_ci	int ret = 0, prtad, devad;
305862306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
305962306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
306062306a36Sopenharmony_ci	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	switch (cmd) {
306362306a36Sopenharmony_ci	case SIOCGMIIPHY:
306462306a36Sopenharmony_ci		if (pi->mdio_addr < 0)
306562306a36Sopenharmony_ci			return -EOPNOTSUPP;
306662306a36Sopenharmony_ci		data->phy_id = pi->mdio_addr;
306762306a36Sopenharmony_ci		break;
306862306a36Sopenharmony_ci	case SIOCGMIIREG:
306962306a36Sopenharmony_ci	case SIOCSMIIREG:
307062306a36Sopenharmony_ci		if (mdio_phy_id_is_c45(data->phy_id)) {
307162306a36Sopenharmony_ci			prtad = mdio_phy_id_prtad(data->phy_id);
307262306a36Sopenharmony_ci			devad = mdio_phy_id_devad(data->phy_id);
307362306a36Sopenharmony_ci		} else if (data->phy_id < 32) {
307462306a36Sopenharmony_ci			prtad = data->phy_id;
307562306a36Sopenharmony_ci			devad = 0;
307662306a36Sopenharmony_ci			data->reg_num &= 0x1f;
307762306a36Sopenharmony_ci		} else
307862306a36Sopenharmony_ci			return -EINVAL;
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci		mbox = pi->adapter->pf;
308162306a36Sopenharmony_ci		if (cmd == SIOCGMIIREG)
308262306a36Sopenharmony_ci			ret = t4_mdio_rd(pi->adapter, mbox, prtad, devad,
308362306a36Sopenharmony_ci					 data->reg_num, &data->val_out);
308462306a36Sopenharmony_ci		else
308562306a36Sopenharmony_ci			ret = t4_mdio_wr(pi->adapter, mbox, prtad, devad,
308662306a36Sopenharmony_ci					 data->reg_num, data->val_in);
308762306a36Sopenharmony_ci		break;
308862306a36Sopenharmony_ci	case SIOCGHWTSTAMP:
308962306a36Sopenharmony_ci		return copy_to_user(req->ifr_data, &pi->tstamp_config,
309062306a36Sopenharmony_ci				    sizeof(pi->tstamp_config)) ?
309162306a36Sopenharmony_ci			-EFAULT : 0;
309262306a36Sopenharmony_ci	case SIOCSHWTSTAMP:
309362306a36Sopenharmony_ci		if (copy_from_user(&pi->tstamp_config, req->ifr_data,
309462306a36Sopenharmony_ci				   sizeof(pi->tstamp_config)))
309562306a36Sopenharmony_ci			return -EFAULT;
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_ci		if (!is_t4(adapter->params.chip)) {
309862306a36Sopenharmony_ci			switch (pi->tstamp_config.tx_type) {
309962306a36Sopenharmony_ci			case HWTSTAMP_TX_OFF:
310062306a36Sopenharmony_ci			case HWTSTAMP_TX_ON:
310162306a36Sopenharmony_ci				break;
310262306a36Sopenharmony_ci			default:
310362306a36Sopenharmony_ci				return -ERANGE;
310462306a36Sopenharmony_ci			}
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci			switch (pi->tstamp_config.rx_filter) {
310762306a36Sopenharmony_ci			case HWTSTAMP_FILTER_NONE:
310862306a36Sopenharmony_ci				pi->rxtstamp = false;
310962306a36Sopenharmony_ci				break;
311062306a36Sopenharmony_ci			case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
311162306a36Sopenharmony_ci			case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
311262306a36Sopenharmony_ci				cxgb4_ptprx_timestamping(pi, pi->port_id,
311362306a36Sopenharmony_ci							 PTP_TS_L4);
311462306a36Sopenharmony_ci				break;
311562306a36Sopenharmony_ci			case HWTSTAMP_FILTER_PTP_V2_EVENT:
311662306a36Sopenharmony_ci				cxgb4_ptprx_timestamping(pi, pi->port_id,
311762306a36Sopenharmony_ci							 PTP_TS_L2_L4);
311862306a36Sopenharmony_ci				break;
311962306a36Sopenharmony_ci			case HWTSTAMP_FILTER_ALL:
312062306a36Sopenharmony_ci			case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
312162306a36Sopenharmony_ci			case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
312262306a36Sopenharmony_ci			case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
312362306a36Sopenharmony_ci			case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
312462306a36Sopenharmony_ci				pi->rxtstamp = true;
312562306a36Sopenharmony_ci				break;
312662306a36Sopenharmony_ci			default:
312762306a36Sopenharmony_ci				pi->tstamp_config.rx_filter =
312862306a36Sopenharmony_ci					HWTSTAMP_FILTER_NONE;
312962306a36Sopenharmony_ci				return -ERANGE;
313062306a36Sopenharmony_ci			}
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci			if ((pi->tstamp_config.tx_type == HWTSTAMP_TX_OFF) &&
313362306a36Sopenharmony_ci			    (pi->tstamp_config.rx_filter ==
313462306a36Sopenharmony_ci				HWTSTAMP_FILTER_NONE)) {
313562306a36Sopenharmony_ci				if (cxgb4_ptp_txtype(adapter, pi->port_id) >= 0)
313662306a36Sopenharmony_ci					pi->ptp_enable = false;
313762306a36Sopenharmony_ci			}
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci			if (pi->tstamp_config.rx_filter !=
314062306a36Sopenharmony_ci				HWTSTAMP_FILTER_NONE) {
314162306a36Sopenharmony_ci				if (cxgb4_ptp_redirect_rx_packet(adapter,
314262306a36Sopenharmony_ci								 pi) >= 0)
314362306a36Sopenharmony_ci					pi->ptp_enable = true;
314462306a36Sopenharmony_ci			}
314562306a36Sopenharmony_ci		} else {
314662306a36Sopenharmony_ci			/* For T4 Adapters */
314762306a36Sopenharmony_ci			switch (pi->tstamp_config.rx_filter) {
314862306a36Sopenharmony_ci			case HWTSTAMP_FILTER_NONE:
314962306a36Sopenharmony_ci			pi->rxtstamp = false;
315062306a36Sopenharmony_ci			break;
315162306a36Sopenharmony_ci			case HWTSTAMP_FILTER_ALL:
315262306a36Sopenharmony_ci			pi->rxtstamp = true;
315362306a36Sopenharmony_ci			break;
315462306a36Sopenharmony_ci			default:
315562306a36Sopenharmony_ci			pi->tstamp_config.rx_filter =
315662306a36Sopenharmony_ci			HWTSTAMP_FILTER_NONE;
315762306a36Sopenharmony_ci			return -ERANGE;
315862306a36Sopenharmony_ci			}
315962306a36Sopenharmony_ci		}
316062306a36Sopenharmony_ci		return copy_to_user(req->ifr_data, &pi->tstamp_config,
316162306a36Sopenharmony_ci				    sizeof(pi->tstamp_config)) ?
316262306a36Sopenharmony_ci			-EFAULT : 0;
316362306a36Sopenharmony_ci	default:
316462306a36Sopenharmony_ci		return -EOPNOTSUPP;
316562306a36Sopenharmony_ci	}
316662306a36Sopenharmony_ci	return ret;
316762306a36Sopenharmony_ci}
316862306a36Sopenharmony_ci
316962306a36Sopenharmony_cistatic void cxgb_set_rxmode(struct net_device *dev)
317062306a36Sopenharmony_ci{
317162306a36Sopenharmony_ci	/* unfortunately we can't return errors to the stack */
317262306a36Sopenharmony_ci	set_rxmode(dev, -1, false);
317362306a36Sopenharmony_ci}
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_cistatic int cxgb_change_mtu(struct net_device *dev, int new_mtu)
317662306a36Sopenharmony_ci{
317762306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
317862306a36Sopenharmony_ci	int ret;
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci	ret = t4_set_rxmode(pi->adapter, pi->adapter->mbox, pi->viid,
318162306a36Sopenharmony_ci			    pi->viid_mirror, new_mtu, -1, -1, -1, -1, true);
318262306a36Sopenharmony_ci	if (!ret)
318362306a36Sopenharmony_ci		dev->mtu = new_mtu;
318462306a36Sopenharmony_ci	return ret;
318562306a36Sopenharmony_ci}
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
318862306a36Sopenharmony_cistatic int cxgb4_mgmt_open(struct net_device *dev)
318962306a36Sopenharmony_ci{
319062306a36Sopenharmony_ci	/* Turn carrier off since we don't have to transmit anything on this
319162306a36Sopenharmony_ci	 * interface.
319262306a36Sopenharmony_ci	 */
319362306a36Sopenharmony_ci	netif_carrier_off(dev);
319462306a36Sopenharmony_ci	return 0;
319562306a36Sopenharmony_ci}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci/* Fill MAC address that will be assigned by the FW */
319862306a36Sopenharmony_cistatic void cxgb4_mgmt_fill_vf_station_mac_addr(struct adapter *adap)
319962306a36Sopenharmony_ci{
320062306a36Sopenharmony_ci	u8 hw_addr[ETH_ALEN], macaddr[ETH_ALEN];
320162306a36Sopenharmony_ci	unsigned int i, vf, nvfs;
320262306a36Sopenharmony_ci	u16 a, b;
320362306a36Sopenharmony_ci	int err;
320462306a36Sopenharmony_ci	u8 *na;
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	err = t4_get_raw_vpd_params(adap, &adap->params.vpd);
320762306a36Sopenharmony_ci	if (err)
320862306a36Sopenharmony_ci		return;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	na = adap->params.vpd.na;
321162306a36Sopenharmony_ci	for (i = 0; i < ETH_ALEN; i++)
321262306a36Sopenharmony_ci		hw_addr[i] = (hex2val(na[2 * i + 0]) * 16 +
321362306a36Sopenharmony_ci			      hex2val(na[2 * i + 1]));
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	a = (hw_addr[0] << 8) | hw_addr[1];
321662306a36Sopenharmony_ci	b = (hw_addr[1] << 8) | hw_addr[2];
321762306a36Sopenharmony_ci	a ^= b;
321862306a36Sopenharmony_ci	a |= 0x0200;    /* locally assigned Ethernet MAC address */
321962306a36Sopenharmony_ci	a &= ~0x0100;   /* not a multicast Ethernet MAC address */
322062306a36Sopenharmony_ci	macaddr[0] = a >> 8;
322162306a36Sopenharmony_ci	macaddr[1] = a & 0xff;
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	for (i = 2; i < 5; i++)
322462306a36Sopenharmony_ci		macaddr[i] = hw_addr[i + 1];
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	for (vf = 0, nvfs = pci_sriov_get_totalvfs(adap->pdev);
322762306a36Sopenharmony_ci		vf < nvfs; vf++) {
322862306a36Sopenharmony_ci		macaddr[5] = adap->pf * nvfs + vf;
322962306a36Sopenharmony_ci		ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, macaddr);
323062306a36Sopenharmony_ci	}
323162306a36Sopenharmony_ci}
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_cistatic int cxgb4_mgmt_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
323462306a36Sopenharmony_ci{
323562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
323662306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
323762306a36Sopenharmony_ci	int ret;
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	/* verify MAC addr is valid */
324062306a36Sopenharmony_ci	if (!is_valid_ether_addr(mac)) {
324162306a36Sopenharmony_ci		dev_err(pi->adapter->pdev_dev,
324262306a36Sopenharmony_ci			"Invalid Ethernet address %pM for VF %d\n",
324362306a36Sopenharmony_ci			mac, vf);
324462306a36Sopenharmony_ci		return -EINVAL;
324562306a36Sopenharmony_ci	}
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci	dev_info(pi->adapter->pdev_dev,
324862306a36Sopenharmony_ci		 "Setting MAC %pM on VF %d\n", mac, vf);
324962306a36Sopenharmony_ci	ret = t4_set_vf_mac_acl(adap, vf + 1, 1, mac);
325062306a36Sopenharmony_ci	if (!ret)
325162306a36Sopenharmony_ci		ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, mac);
325262306a36Sopenharmony_ci	return ret;
325362306a36Sopenharmony_ci}
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_cistatic int cxgb4_mgmt_get_vf_config(struct net_device *dev,
325662306a36Sopenharmony_ci				    int vf, struct ifla_vf_info *ivi)
325762306a36Sopenharmony_ci{
325862306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
325962306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
326062306a36Sopenharmony_ci	struct vf_info *vfinfo;
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	if (vf >= adap->num_vfs)
326362306a36Sopenharmony_ci		return -EINVAL;
326462306a36Sopenharmony_ci	vfinfo = &adap->vfinfo[vf];
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	ivi->vf = vf;
326762306a36Sopenharmony_ci	ivi->max_tx_rate = vfinfo->tx_rate;
326862306a36Sopenharmony_ci	ivi->min_tx_rate = 0;
326962306a36Sopenharmony_ci	ether_addr_copy(ivi->mac, vfinfo->vf_mac_addr);
327062306a36Sopenharmony_ci	ivi->vlan = vfinfo->vlan;
327162306a36Sopenharmony_ci	ivi->linkstate = vfinfo->link_state;
327262306a36Sopenharmony_ci	return 0;
327362306a36Sopenharmony_ci}
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_cistatic int cxgb4_mgmt_get_phys_port_id(struct net_device *dev,
327662306a36Sopenharmony_ci				       struct netdev_phys_item_id *ppid)
327762306a36Sopenharmony_ci{
327862306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
327962306a36Sopenharmony_ci	unsigned int phy_port_id;
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	phy_port_id = pi->adapter->adap_idx * 10 + pi->port_id;
328262306a36Sopenharmony_ci	ppid->id_len = sizeof(phy_port_id);
328362306a36Sopenharmony_ci	memcpy(ppid->id, &phy_port_id, ppid->id_len);
328462306a36Sopenharmony_ci	return 0;
328562306a36Sopenharmony_ci}
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_cistatic int cxgb4_mgmt_set_vf_rate(struct net_device *dev, int vf,
328862306a36Sopenharmony_ci				  int min_tx_rate, int max_tx_rate)
328962306a36Sopenharmony_ci{
329062306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
329162306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
329262306a36Sopenharmony_ci	unsigned int link_ok, speed, mtu;
329362306a36Sopenharmony_ci	u32 fw_pfvf, fw_class;
329462306a36Sopenharmony_ci	int class_id = vf;
329562306a36Sopenharmony_ci	int ret;
329662306a36Sopenharmony_ci	u16 pktsize;
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	if (vf >= adap->num_vfs)
329962306a36Sopenharmony_ci		return -EINVAL;
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci	if (min_tx_rate) {
330262306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
330362306a36Sopenharmony_ci			"Min tx rate (%d) (> 0) for VF %d is Invalid.\n",
330462306a36Sopenharmony_ci			min_tx_rate, vf);
330562306a36Sopenharmony_ci		return -EINVAL;
330662306a36Sopenharmony_ci	}
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	if (max_tx_rate == 0) {
330962306a36Sopenharmony_ci		/* unbind VF to to any Traffic Class */
331062306a36Sopenharmony_ci		fw_pfvf =
331162306a36Sopenharmony_ci		    (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) |
331262306a36Sopenharmony_ci		     FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH));
331362306a36Sopenharmony_ci		fw_class = 0xffffffff;
331462306a36Sopenharmony_ci		ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1,
331562306a36Sopenharmony_ci				    &fw_pfvf, &fw_class);
331662306a36Sopenharmony_ci		if (ret) {
331762306a36Sopenharmony_ci			dev_err(adap->pdev_dev,
331862306a36Sopenharmony_ci				"Err %d in unbinding PF %d VF %d from TX Rate Limiting\n",
331962306a36Sopenharmony_ci				ret, adap->pf, vf);
332062306a36Sopenharmony_ci			return -EINVAL;
332162306a36Sopenharmony_ci		}
332262306a36Sopenharmony_ci		dev_info(adap->pdev_dev,
332362306a36Sopenharmony_ci			 "PF %d VF %d is unbound from TX Rate Limiting\n",
332462306a36Sopenharmony_ci			 adap->pf, vf);
332562306a36Sopenharmony_ci		adap->vfinfo[vf].tx_rate = 0;
332662306a36Sopenharmony_ci		return 0;
332762306a36Sopenharmony_ci	}
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_ci	ret = t4_get_link_params(pi, &link_ok, &speed, &mtu);
333062306a36Sopenharmony_ci	if (ret != FW_SUCCESS) {
333162306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
333262306a36Sopenharmony_ci			"Failed to get link information for VF %d\n", vf);
333362306a36Sopenharmony_ci		return -EINVAL;
333462306a36Sopenharmony_ci	}
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	if (!link_ok) {
333762306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "Link down for VF %d\n", vf);
333862306a36Sopenharmony_ci		return -EINVAL;
333962306a36Sopenharmony_ci	}
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	if (max_tx_rate > speed) {
334262306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
334362306a36Sopenharmony_ci			"Max tx rate %d for VF %d can't be > link-speed %u",
334462306a36Sopenharmony_ci			max_tx_rate, vf, speed);
334562306a36Sopenharmony_ci		return -EINVAL;
334662306a36Sopenharmony_ci	}
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	pktsize = mtu;
334962306a36Sopenharmony_ci	/* subtract ethhdr size and 4 bytes crc since, f/w appends it */
335062306a36Sopenharmony_ci	pktsize = pktsize - sizeof(struct ethhdr) - 4;
335162306a36Sopenharmony_ci	/* subtract ipv4 hdr size, tcp hdr size to get typical IPv4 MSS size */
335262306a36Sopenharmony_ci	pktsize = pktsize - sizeof(struct iphdr) - sizeof(struct tcphdr);
335362306a36Sopenharmony_ci	/* configure Traffic Class for rate-limiting */
335462306a36Sopenharmony_ci	ret = t4_sched_params(adap, SCHED_CLASS_TYPE_PACKET,
335562306a36Sopenharmony_ci			      SCHED_CLASS_LEVEL_CL_RL,
335662306a36Sopenharmony_ci			      SCHED_CLASS_MODE_CLASS,
335762306a36Sopenharmony_ci			      SCHED_CLASS_RATEUNIT_BITS,
335862306a36Sopenharmony_ci			      SCHED_CLASS_RATEMODE_ABS,
335962306a36Sopenharmony_ci			      pi->tx_chan, class_id, 0,
336062306a36Sopenharmony_ci			      max_tx_rate * 1000, 0, pktsize, 0);
336162306a36Sopenharmony_ci	if (ret) {
336262306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "Err %d for Traffic Class config\n",
336362306a36Sopenharmony_ci			ret);
336462306a36Sopenharmony_ci		return -EINVAL;
336562306a36Sopenharmony_ci	}
336662306a36Sopenharmony_ci	dev_info(adap->pdev_dev,
336762306a36Sopenharmony_ci		 "Class %d with MSS %u configured with rate %u\n",
336862306a36Sopenharmony_ci		 class_id, pktsize, max_tx_rate);
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	/* bind VF to configured Traffic Class */
337162306a36Sopenharmony_ci	fw_pfvf = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) |
337262306a36Sopenharmony_ci		   FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH));
337362306a36Sopenharmony_ci	fw_class = class_id;
337462306a36Sopenharmony_ci	ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, &fw_pfvf,
337562306a36Sopenharmony_ci			    &fw_class);
337662306a36Sopenharmony_ci	if (ret) {
337762306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
337862306a36Sopenharmony_ci			"Err %d in binding PF %d VF %d to Traffic Class %d\n",
337962306a36Sopenharmony_ci			ret, adap->pf, vf, class_id);
338062306a36Sopenharmony_ci		return -EINVAL;
338162306a36Sopenharmony_ci	}
338262306a36Sopenharmony_ci	dev_info(adap->pdev_dev, "PF %d VF %d is bound to Class %d\n",
338362306a36Sopenharmony_ci		 adap->pf, vf, class_id);
338462306a36Sopenharmony_ci	adap->vfinfo[vf].tx_rate = max_tx_rate;
338562306a36Sopenharmony_ci	return 0;
338662306a36Sopenharmony_ci}
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_cistatic int cxgb4_mgmt_set_vf_vlan(struct net_device *dev, int vf,
338962306a36Sopenharmony_ci				  u16 vlan, u8 qos, __be16 vlan_proto)
339062306a36Sopenharmony_ci{
339162306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
339262306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
339362306a36Sopenharmony_ci	int ret;
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci	if (vf >= adap->num_vfs || vlan > 4095 || qos > 7)
339662306a36Sopenharmony_ci		return -EINVAL;
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	if (vlan_proto != htons(ETH_P_8021Q) || qos != 0)
339962306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	ret = t4_set_vlan_acl(adap, adap->mbox, vf + 1, vlan);
340262306a36Sopenharmony_ci	if (!ret) {
340362306a36Sopenharmony_ci		adap->vfinfo[vf].vlan = vlan;
340462306a36Sopenharmony_ci		return 0;
340562306a36Sopenharmony_ci	}
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	dev_err(adap->pdev_dev, "Err %d %s VLAN ACL for PF/VF %d/%d\n",
340862306a36Sopenharmony_ci		ret, (vlan ? "setting" : "clearing"), adap->pf, vf);
340962306a36Sopenharmony_ci	return ret;
341062306a36Sopenharmony_ci}
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_cistatic int cxgb4_mgmt_set_vf_link_state(struct net_device *dev, int vf,
341362306a36Sopenharmony_ci					int link)
341462306a36Sopenharmony_ci{
341562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
341662306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
341762306a36Sopenharmony_ci	u32 param, val;
341862306a36Sopenharmony_ci	int ret = 0;
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci	if (vf >= adap->num_vfs)
342162306a36Sopenharmony_ci		return -EINVAL;
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci	switch (link) {
342462306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_AUTO:
342562306a36Sopenharmony_ci		val = FW_VF_LINK_STATE_AUTO;
342662306a36Sopenharmony_ci		break;
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_ENABLE:
342962306a36Sopenharmony_ci		val = FW_VF_LINK_STATE_ENABLE;
343062306a36Sopenharmony_ci		break;
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_DISABLE:
343362306a36Sopenharmony_ci		val = FW_VF_LINK_STATE_DISABLE;
343462306a36Sopenharmony_ci		break;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	default:
343762306a36Sopenharmony_ci		return -EINVAL;
343862306a36Sopenharmony_ci	}
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) |
344162306a36Sopenharmony_ci		 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_LINK_STATE));
344262306a36Sopenharmony_ci	ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1,
344362306a36Sopenharmony_ci			    &param, &val);
344462306a36Sopenharmony_ci	if (ret) {
344562306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
344662306a36Sopenharmony_ci			"Error %d in setting PF %d VF %d link state\n",
344762306a36Sopenharmony_ci			ret, adap->pf, vf);
344862306a36Sopenharmony_ci		return -EINVAL;
344962306a36Sopenharmony_ci	}
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_ci	adap->vfinfo[vf].link_state = link;
345262306a36Sopenharmony_ci	return ret;
345362306a36Sopenharmony_ci}
345462306a36Sopenharmony_ci#endif /* CONFIG_PCI_IOV */
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_cistatic int cxgb_set_mac_addr(struct net_device *dev, void *p)
345762306a36Sopenharmony_ci{
345862306a36Sopenharmony_ci	int ret;
345962306a36Sopenharmony_ci	struct sockaddr *addr = p;
346062306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
346362306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci	ret = cxgb4_update_mac_filt(pi, pi->viid, &pi->xact_addr_filt,
346662306a36Sopenharmony_ci				    addr->sa_data, true, &pi->smt_idx);
346762306a36Sopenharmony_ci	if (ret < 0)
346862306a36Sopenharmony_ci		return ret;
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci	eth_hw_addr_set(dev, addr->sa_data);
347162306a36Sopenharmony_ci	return 0;
347262306a36Sopenharmony_ci}
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
347562306a36Sopenharmony_cistatic void cxgb_netpoll(struct net_device *dev)
347662306a36Sopenharmony_ci{
347762306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
347862306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci	if (adap->flags & CXGB4_USING_MSIX) {
348162306a36Sopenharmony_ci		int i;
348262306a36Sopenharmony_ci		struct sge_eth_rxq *rx = &adap->sge.ethrxq[pi->first_qset];
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci		for (i = pi->nqsets; i; i--, rx++)
348562306a36Sopenharmony_ci			t4_sge_intr_msix(0, &rx->rspq);
348662306a36Sopenharmony_ci	} else
348762306a36Sopenharmony_ci		t4_intr_handler(adap)(0, adap);
348862306a36Sopenharmony_ci}
348962306a36Sopenharmony_ci#endif
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_cistatic int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate)
349262306a36Sopenharmony_ci{
349362306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
349462306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
349562306a36Sopenharmony_ci	struct ch_sched_queue qe = { 0 };
349662306a36Sopenharmony_ci	struct ch_sched_params p = { 0 };
349762306a36Sopenharmony_ci	struct sched_class *e;
349862306a36Sopenharmony_ci	u32 req_rate;
349962306a36Sopenharmony_ci	int err = 0;
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci	if (!can_sched(dev))
350262306a36Sopenharmony_ci		return -ENOTSUPP;
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci	if (index < 0 || index > pi->nqsets - 1)
350562306a36Sopenharmony_ci		return -EINVAL;
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_FULL_INIT_DONE)) {
350862306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
350962306a36Sopenharmony_ci			"Failed to rate limit on queue %d. Link Down?\n",
351062306a36Sopenharmony_ci			index);
351162306a36Sopenharmony_ci		return -EINVAL;
351262306a36Sopenharmony_ci	}
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	qe.queue = index;
351562306a36Sopenharmony_ci	e = cxgb4_sched_queue_lookup(dev, &qe);
351662306a36Sopenharmony_ci	if (e && e->info.u.params.level != SCHED_CLASS_LEVEL_CL_RL) {
351762306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
351862306a36Sopenharmony_ci			"Queue %u already bound to class %u of type: %u\n",
351962306a36Sopenharmony_ci			index, e->idx, e->info.u.params.level);
352062306a36Sopenharmony_ci		return -EBUSY;
352162306a36Sopenharmony_ci	}
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci	/* Convert from Mbps to Kbps */
352462306a36Sopenharmony_ci	req_rate = rate * 1000;
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci	/* Max rate is 100 Gbps */
352762306a36Sopenharmony_ci	if (req_rate > SCHED_MAX_RATE_KBPS) {
352862306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
352962306a36Sopenharmony_ci			"Invalid rate %u Mbps, Max rate is %u Mbps\n",
353062306a36Sopenharmony_ci			rate, SCHED_MAX_RATE_KBPS / 1000);
353162306a36Sopenharmony_ci		return -ERANGE;
353262306a36Sopenharmony_ci	}
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	/* First unbind the queue from any existing class */
353562306a36Sopenharmony_ci	memset(&qe, 0, sizeof(qe));
353662306a36Sopenharmony_ci	qe.queue = index;
353762306a36Sopenharmony_ci	qe.class = SCHED_CLS_NONE;
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_ci	err = cxgb4_sched_class_unbind(dev, (void *)(&qe), SCHED_QUEUE);
354062306a36Sopenharmony_ci	if (err) {
354162306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
354262306a36Sopenharmony_ci			"Unbinding Queue %d on port %d fail. Err: %d\n",
354362306a36Sopenharmony_ci			index, pi->port_id, err);
354462306a36Sopenharmony_ci		return err;
354562306a36Sopenharmony_ci	}
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	/* Queue already unbound */
354862306a36Sopenharmony_ci	if (!req_rate)
354962306a36Sopenharmony_ci		return 0;
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci	/* Fetch any available unused or matching scheduling class */
355262306a36Sopenharmony_ci	p.type = SCHED_CLASS_TYPE_PACKET;
355362306a36Sopenharmony_ci	p.u.params.level    = SCHED_CLASS_LEVEL_CL_RL;
355462306a36Sopenharmony_ci	p.u.params.mode     = SCHED_CLASS_MODE_CLASS;
355562306a36Sopenharmony_ci	p.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS;
355662306a36Sopenharmony_ci	p.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS;
355762306a36Sopenharmony_ci	p.u.params.channel  = pi->tx_chan;
355862306a36Sopenharmony_ci	p.u.params.class    = SCHED_CLS_NONE;
355962306a36Sopenharmony_ci	p.u.params.minrate  = 0;
356062306a36Sopenharmony_ci	p.u.params.maxrate  = req_rate;
356162306a36Sopenharmony_ci	p.u.params.weight   = 0;
356262306a36Sopenharmony_ci	p.u.params.pktsize  = dev->mtu;
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	e = cxgb4_sched_class_alloc(dev, &p);
356562306a36Sopenharmony_ci	if (!e)
356662306a36Sopenharmony_ci		return -ENOMEM;
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	/* Bind the queue to a scheduling class */
356962306a36Sopenharmony_ci	memset(&qe, 0, sizeof(qe));
357062306a36Sopenharmony_ci	qe.queue = index;
357162306a36Sopenharmony_ci	qe.class = e->idx;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci	err = cxgb4_sched_class_bind(dev, (void *)(&qe), SCHED_QUEUE);
357462306a36Sopenharmony_ci	if (err)
357562306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
357662306a36Sopenharmony_ci			"Queue rate limiting failed. Err: %d\n", err);
357762306a36Sopenharmony_ci	return err;
357862306a36Sopenharmony_ci}
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_cistatic int cxgb_setup_tc_flower(struct net_device *dev,
358162306a36Sopenharmony_ci				struct flow_cls_offload *cls_flower)
358262306a36Sopenharmony_ci{
358362306a36Sopenharmony_ci	switch (cls_flower->command) {
358462306a36Sopenharmony_ci	case FLOW_CLS_REPLACE:
358562306a36Sopenharmony_ci		return cxgb4_tc_flower_replace(dev, cls_flower);
358662306a36Sopenharmony_ci	case FLOW_CLS_DESTROY:
358762306a36Sopenharmony_ci		return cxgb4_tc_flower_destroy(dev, cls_flower);
358862306a36Sopenharmony_ci	case FLOW_CLS_STATS:
358962306a36Sopenharmony_ci		return cxgb4_tc_flower_stats(dev, cls_flower);
359062306a36Sopenharmony_ci	default:
359162306a36Sopenharmony_ci		return -EOPNOTSUPP;
359262306a36Sopenharmony_ci	}
359362306a36Sopenharmony_ci}
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_cistatic int cxgb_setup_tc_cls_u32(struct net_device *dev,
359662306a36Sopenharmony_ci				 struct tc_cls_u32_offload *cls_u32)
359762306a36Sopenharmony_ci{
359862306a36Sopenharmony_ci	switch (cls_u32->command) {
359962306a36Sopenharmony_ci	case TC_CLSU32_NEW_KNODE:
360062306a36Sopenharmony_ci	case TC_CLSU32_REPLACE_KNODE:
360162306a36Sopenharmony_ci		return cxgb4_config_knode(dev, cls_u32);
360262306a36Sopenharmony_ci	case TC_CLSU32_DELETE_KNODE:
360362306a36Sopenharmony_ci		return cxgb4_delete_knode(dev, cls_u32);
360462306a36Sopenharmony_ci	default:
360562306a36Sopenharmony_ci		return -EOPNOTSUPP;
360662306a36Sopenharmony_ci	}
360762306a36Sopenharmony_ci}
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_cistatic int cxgb_setup_tc_matchall(struct net_device *dev,
361062306a36Sopenharmony_ci				  struct tc_cls_matchall_offload *cls_matchall,
361162306a36Sopenharmony_ci				  bool ingress)
361262306a36Sopenharmony_ci{
361362306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	if (!adap->tc_matchall)
361662306a36Sopenharmony_ci		return -ENOMEM;
361762306a36Sopenharmony_ci
361862306a36Sopenharmony_ci	switch (cls_matchall->command) {
361962306a36Sopenharmony_ci	case TC_CLSMATCHALL_REPLACE:
362062306a36Sopenharmony_ci		return cxgb4_tc_matchall_replace(dev, cls_matchall, ingress);
362162306a36Sopenharmony_ci	case TC_CLSMATCHALL_DESTROY:
362262306a36Sopenharmony_ci		return cxgb4_tc_matchall_destroy(dev, cls_matchall, ingress);
362362306a36Sopenharmony_ci	case TC_CLSMATCHALL_STATS:
362462306a36Sopenharmony_ci		if (ingress)
362562306a36Sopenharmony_ci			return cxgb4_tc_matchall_stats(dev, cls_matchall);
362662306a36Sopenharmony_ci		break;
362762306a36Sopenharmony_ci	default:
362862306a36Sopenharmony_ci		break;
362962306a36Sopenharmony_ci	}
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	return -EOPNOTSUPP;
363262306a36Sopenharmony_ci}
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_cistatic int cxgb_setup_tc_block_ingress_cb(enum tc_setup_type type,
363562306a36Sopenharmony_ci					  void *type_data, void *cb_priv)
363662306a36Sopenharmony_ci{
363762306a36Sopenharmony_ci	struct net_device *dev = cb_priv;
363862306a36Sopenharmony_ci	struct port_info *pi = netdev2pinfo(dev);
363962306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_FULL_INIT_DONE)) {
364262306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
364362306a36Sopenharmony_ci			"Failed to setup tc on port %d. Link Down?\n",
364462306a36Sopenharmony_ci			pi->port_id);
364562306a36Sopenharmony_ci		return -EINVAL;
364662306a36Sopenharmony_ci	}
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci	if (!tc_cls_can_offload_and_chain0(dev, type_data))
364962306a36Sopenharmony_ci		return -EOPNOTSUPP;
365062306a36Sopenharmony_ci
365162306a36Sopenharmony_ci	switch (type) {
365262306a36Sopenharmony_ci	case TC_SETUP_CLSU32:
365362306a36Sopenharmony_ci		return cxgb_setup_tc_cls_u32(dev, type_data);
365462306a36Sopenharmony_ci	case TC_SETUP_CLSFLOWER:
365562306a36Sopenharmony_ci		return cxgb_setup_tc_flower(dev, type_data);
365662306a36Sopenharmony_ci	case TC_SETUP_CLSMATCHALL:
365762306a36Sopenharmony_ci		return cxgb_setup_tc_matchall(dev, type_data, true);
365862306a36Sopenharmony_ci	default:
365962306a36Sopenharmony_ci		return -EOPNOTSUPP;
366062306a36Sopenharmony_ci	}
366162306a36Sopenharmony_ci}
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_cistatic int cxgb_setup_tc_block_egress_cb(enum tc_setup_type type,
366462306a36Sopenharmony_ci					 void *type_data, void *cb_priv)
366562306a36Sopenharmony_ci{
366662306a36Sopenharmony_ci	struct net_device *dev = cb_priv;
366762306a36Sopenharmony_ci	struct port_info *pi = netdev2pinfo(dev);
366862306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_FULL_INIT_DONE)) {
367162306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
367262306a36Sopenharmony_ci			"Failed to setup tc on port %d. Link Down?\n",
367362306a36Sopenharmony_ci			pi->port_id);
367462306a36Sopenharmony_ci		return -EINVAL;
367562306a36Sopenharmony_ci	}
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci	if (!tc_cls_can_offload_and_chain0(dev, type_data))
367862306a36Sopenharmony_ci		return -EOPNOTSUPP;
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_ci	switch (type) {
368162306a36Sopenharmony_ci	case TC_SETUP_CLSMATCHALL:
368262306a36Sopenharmony_ci		return cxgb_setup_tc_matchall(dev, type_data, false);
368362306a36Sopenharmony_ci	default:
368462306a36Sopenharmony_ci		break;
368562306a36Sopenharmony_ci	}
368662306a36Sopenharmony_ci
368762306a36Sopenharmony_ci	return -EOPNOTSUPP;
368862306a36Sopenharmony_ci}
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_cistatic int cxgb_setup_tc_mqprio(struct net_device *dev,
369162306a36Sopenharmony_ci				struct tc_mqprio_qopt_offload *mqprio)
369262306a36Sopenharmony_ci{
369362306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_ci	if (!is_ethofld(adap) || !adap->tc_mqprio)
369662306a36Sopenharmony_ci		return -ENOMEM;
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci	return cxgb4_setup_tc_mqprio(dev, mqprio);
369962306a36Sopenharmony_ci}
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_cistatic LIST_HEAD(cxgb_block_cb_list);
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_cistatic int cxgb_setup_tc_block(struct net_device *dev,
370462306a36Sopenharmony_ci			       struct flow_block_offload *f)
370562306a36Sopenharmony_ci{
370662306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
370762306a36Sopenharmony_ci	flow_setup_cb_t *cb;
370862306a36Sopenharmony_ci	bool ingress_only;
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_ci	pi->tc_block_shared = f->block_shared;
371162306a36Sopenharmony_ci	if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
371262306a36Sopenharmony_ci		cb = cxgb_setup_tc_block_egress_cb;
371362306a36Sopenharmony_ci		ingress_only = false;
371462306a36Sopenharmony_ci	} else {
371562306a36Sopenharmony_ci		cb = cxgb_setup_tc_block_ingress_cb;
371662306a36Sopenharmony_ci		ingress_only = true;
371762306a36Sopenharmony_ci	}
371862306a36Sopenharmony_ci
371962306a36Sopenharmony_ci	return flow_block_cb_setup_simple(f, &cxgb_block_cb_list,
372062306a36Sopenharmony_ci					  cb, pi, dev, ingress_only);
372162306a36Sopenharmony_ci}
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_cistatic int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type,
372462306a36Sopenharmony_ci			 void *type_data)
372562306a36Sopenharmony_ci{
372662306a36Sopenharmony_ci	switch (type) {
372762306a36Sopenharmony_ci	case TC_SETUP_QDISC_MQPRIO:
372862306a36Sopenharmony_ci		return cxgb_setup_tc_mqprio(dev, type_data);
372962306a36Sopenharmony_ci	case TC_SETUP_BLOCK:
373062306a36Sopenharmony_ci		return cxgb_setup_tc_block(dev, type_data);
373162306a36Sopenharmony_ci	default:
373262306a36Sopenharmony_ci		return -EOPNOTSUPP;
373362306a36Sopenharmony_ci	}
373462306a36Sopenharmony_ci}
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_cistatic int cxgb_udp_tunnel_unset_port(struct net_device *netdev,
373762306a36Sopenharmony_ci				      unsigned int table, unsigned int entry,
373862306a36Sopenharmony_ci				      struct udp_tunnel_info *ti)
373962306a36Sopenharmony_ci{
374062306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
374162306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
374262306a36Sopenharmony_ci	u8 match_all_mac[] = { 0, 0, 0, 0, 0, 0 };
374362306a36Sopenharmony_ci	int ret = 0, i;
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	switch (ti->type) {
374662306a36Sopenharmony_ci	case UDP_TUNNEL_TYPE_VXLAN:
374762306a36Sopenharmony_ci		adapter->vxlan_port = 0;
374862306a36Sopenharmony_ci		t4_write_reg(adapter, MPS_RX_VXLAN_TYPE_A, 0);
374962306a36Sopenharmony_ci		break;
375062306a36Sopenharmony_ci	case UDP_TUNNEL_TYPE_GENEVE:
375162306a36Sopenharmony_ci		adapter->geneve_port = 0;
375262306a36Sopenharmony_ci		t4_write_reg(adapter, MPS_RX_GENEVE_TYPE_A, 0);
375362306a36Sopenharmony_ci		break;
375462306a36Sopenharmony_ci	default:
375562306a36Sopenharmony_ci		return -EINVAL;
375662306a36Sopenharmony_ci	}
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	/* Matchall mac entries can be deleted only after all tunnel ports
375962306a36Sopenharmony_ci	 * are brought down or removed.
376062306a36Sopenharmony_ci	 */
376162306a36Sopenharmony_ci	if (!adapter->rawf_cnt)
376262306a36Sopenharmony_ci		return 0;
376362306a36Sopenharmony_ci	for_each_port(adapter, i) {
376462306a36Sopenharmony_ci		pi = adap2pinfo(adapter, i);
376562306a36Sopenharmony_ci		ret = t4_free_raw_mac_filt(adapter, pi->viid,
376662306a36Sopenharmony_ci					   match_all_mac, match_all_mac,
376762306a36Sopenharmony_ci					   adapter->rawf_start + pi->port_id,
376862306a36Sopenharmony_ci					   1, pi->port_id, false);
376962306a36Sopenharmony_ci		if (ret < 0) {
377062306a36Sopenharmony_ci			netdev_info(netdev, "Failed to free mac filter entry, for port %d\n",
377162306a36Sopenharmony_ci				    i);
377262306a36Sopenharmony_ci			return ret;
377362306a36Sopenharmony_ci		}
377462306a36Sopenharmony_ci	}
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	return 0;
377762306a36Sopenharmony_ci}
377862306a36Sopenharmony_ci
377962306a36Sopenharmony_cistatic int cxgb_udp_tunnel_set_port(struct net_device *netdev,
378062306a36Sopenharmony_ci				    unsigned int table, unsigned int entry,
378162306a36Sopenharmony_ci				    struct udp_tunnel_info *ti)
378262306a36Sopenharmony_ci{
378362306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
378462306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
378562306a36Sopenharmony_ci	u8 match_all_mac[] = { 0, 0, 0, 0, 0, 0 };
378662306a36Sopenharmony_ci	int i, ret;
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci	switch (ti->type) {
378962306a36Sopenharmony_ci	case UDP_TUNNEL_TYPE_VXLAN:
379062306a36Sopenharmony_ci		adapter->vxlan_port = ti->port;
379162306a36Sopenharmony_ci		t4_write_reg(adapter, MPS_RX_VXLAN_TYPE_A,
379262306a36Sopenharmony_ci			     VXLAN_V(be16_to_cpu(ti->port)) | VXLAN_EN_F);
379362306a36Sopenharmony_ci		break;
379462306a36Sopenharmony_ci	case UDP_TUNNEL_TYPE_GENEVE:
379562306a36Sopenharmony_ci		adapter->geneve_port = ti->port;
379662306a36Sopenharmony_ci		t4_write_reg(adapter, MPS_RX_GENEVE_TYPE_A,
379762306a36Sopenharmony_ci			     GENEVE_V(be16_to_cpu(ti->port)) | GENEVE_EN_F);
379862306a36Sopenharmony_ci		break;
379962306a36Sopenharmony_ci	default:
380062306a36Sopenharmony_ci		return -EINVAL;
380162306a36Sopenharmony_ci	}
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	/* Create a 'match all' mac filter entry for inner mac,
380462306a36Sopenharmony_ci	 * if raw mac interface is supported. Once the linux kernel provides
380562306a36Sopenharmony_ci	 * driver entry points for adding/deleting the inner mac addresses,
380662306a36Sopenharmony_ci	 * we will remove this 'match all' entry and fallback to adding
380762306a36Sopenharmony_ci	 * exact match filters.
380862306a36Sopenharmony_ci	 */
380962306a36Sopenharmony_ci	for_each_port(adapter, i) {
381062306a36Sopenharmony_ci		pi = adap2pinfo(adapter, i);
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci		ret = t4_alloc_raw_mac_filt(adapter, pi->viid,
381362306a36Sopenharmony_ci					    match_all_mac,
381462306a36Sopenharmony_ci					    match_all_mac,
381562306a36Sopenharmony_ci					    adapter->rawf_start + pi->port_id,
381662306a36Sopenharmony_ci					    1, pi->port_id, false);
381762306a36Sopenharmony_ci		if (ret < 0) {
381862306a36Sopenharmony_ci			netdev_info(netdev, "Failed to allocate a mac filter entry, not adding port %d\n",
381962306a36Sopenharmony_ci				    be16_to_cpu(ti->port));
382062306a36Sopenharmony_ci			return ret;
382162306a36Sopenharmony_ci		}
382262306a36Sopenharmony_ci	}
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci	return 0;
382562306a36Sopenharmony_ci}
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_cistatic const struct udp_tunnel_nic_info cxgb_udp_tunnels = {
382862306a36Sopenharmony_ci	.set_port	= cxgb_udp_tunnel_set_port,
382962306a36Sopenharmony_ci	.unset_port	= cxgb_udp_tunnel_unset_port,
383062306a36Sopenharmony_ci	.tables		= {
383162306a36Sopenharmony_ci		{ .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN,  },
383262306a36Sopenharmony_ci		{ .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_GENEVE, },
383362306a36Sopenharmony_ci	},
383462306a36Sopenharmony_ci};
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_cistatic netdev_features_t cxgb_features_check(struct sk_buff *skb,
383762306a36Sopenharmony_ci					     struct net_device *dev,
383862306a36Sopenharmony_ci					     netdev_features_t features)
383962306a36Sopenharmony_ci{
384062306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
384162306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
384262306a36Sopenharmony_ci
384362306a36Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(adapter->params.chip) < CHELSIO_T6)
384462306a36Sopenharmony_ci		return features;
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci	/* Check if hw supports offload for this packet */
384762306a36Sopenharmony_ci	if (!skb->encapsulation || cxgb_encap_offload_supported(skb))
384862306a36Sopenharmony_ci		return features;
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci	/* Offload is not supported for this encapsulated packet */
385162306a36Sopenharmony_ci	return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
385262306a36Sopenharmony_ci}
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_cistatic netdev_features_t cxgb_fix_features(struct net_device *dev,
385562306a36Sopenharmony_ci					   netdev_features_t features)
385662306a36Sopenharmony_ci{
385762306a36Sopenharmony_ci	/* Disable GRO, if RX_CSUM is disabled */
385862306a36Sopenharmony_ci	if (!(features & NETIF_F_RXCSUM))
385962306a36Sopenharmony_ci		features &= ~NETIF_F_GRO;
386062306a36Sopenharmony_ci
386162306a36Sopenharmony_ci	return features;
386262306a36Sopenharmony_ci}
386362306a36Sopenharmony_ci
386462306a36Sopenharmony_cistatic const struct net_device_ops cxgb4_netdev_ops = {
386562306a36Sopenharmony_ci	.ndo_open             = cxgb_open,
386662306a36Sopenharmony_ci	.ndo_stop             = cxgb_close,
386762306a36Sopenharmony_ci	.ndo_start_xmit       = t4_start_xmit,
386862306a36Sopenharmony_ci	.ndo_select_queue     =	cxgb_select_queue,
386962306a36Sopenharmony_ci	.ndo_get_stats64      = cxgb_get_stats,
387062306a36Sopenharmony_ci	.ndo_set_rx_mode      = cxgb_set_rxmode,
387162306a36Sopenharmony_ci	.ndo_set_mac_address  = cxgb_set_mac_addr,
387262306a36Sopenharmony_ci	.ndo_set_features     = cxgb_set_features,
387362306a36Sopenharmony_ci	.ndo_validate_addr    = eth_validate_addr,
387462306a36Sopenharmony_ci	.ndo_eth_ioctl         = cxgb_ioctl,
387562306a36Sopenharmony_ci	.ndo_change_mtu       = cxgb_change_mtu,
387662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
387762306a36Sopenharmony_ci	.ndo_poll_controller  = cxgb_netpoll,
387862306a36Sopenharmony_ci#endif
387962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE
388062306a36Sopenharmony_ci	.ndo_fcoe_enable      = cxgb_fcoe_enable,
388162306a36Sopenharmony_ci	.ndo_fcoe_disable     = cxgb_fcoe_disable,
388262306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */
388362306a36Sopenharmony_ci	.ndo_set_tx_maxrate   = cxgb_set_tx_maxrate,
388462306a36Sopenharmony_ci	.ndo_setup_tc         = cxgb_setup_tc,
388562306a36Sopenharmony_ci	.ndo_features_check   = cxgb_features_check,
388662306a36Sopenharmony_ci	.ndo_fix_features     = cxgb_fix_features,
388762306a36Sopenharmony_ci};
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
389062306a36Sopenharmony_cistatic const struct net_device_ops cxgb4_mgmt_netdev_ops = {
389162306a36Sopenharmony_ci	.ndo_open               = cxgb4_mgmt_open,
389262306a36Sopenharmony_ci	.ndo_set_vf_mac         = cxgb4_mgmt_set_vf_mac,
389362306a36Sopenharmony_ci	.ndo_get_vf_config      = cxgb4_mgmt_get_vf_config,
389462306a36Sopenharmony_ci	.ndo_set_vf_rate        = cxgb4_mgmt_set_vf_rate,
389562306a36Sopenharmony_ci	.ndo_get_phys_port_id   = cxgb4_mgmt_get_phys_port_id,
389662306a36Sopenharmony_ci	.ndo_set_vf_vlan        = cxgb4_mgmt_set_vf_vlan,
389762306a36Sopenharmony_ci	.ndo_set_vf_link_state	= cxgb4_mgmt_set_vf_link_state,
389862306a36Sopenharmony_ci};
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_cistatic void cxgb4_mgmt_get_drvinfo(struct net_device *dev,
390162306a36Sopenharmony_ci				   struct ethtool_drvinfo *info)
390262306a36Sopenharmony_ci{
390362306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(dev);
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci	strscpy(info->driver, cxgb4_driver_name, sizeof(info->driver));
390662306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(adapter->pdev),
390762306a36Sopenharmony_ci		sizeof(info->bus_info));
390862306a36Sopenharmony_ci}
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_cistatic const struct ethtool_ops cxgb4_mgmt_ethtool_ops = {
391162306a36Sopenharmony_ci	.get_drvinfo       = cxgb4_mgmt_get_drvinfo,
391262306a36Sopenharmony_ci};
391362306a36Sopenharmony_ci#endif
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_cistatic void notify_fatal_err(struct work_struct *work)
391662306a36Sopenharmony_ci{
391762306a36Sopenharmony_ci	struct adapter *adap;
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci	adap = container_of(work, struct adapter, fatal_err_notify_task);
392062306a36Sopenharmony_ci	notify_ulds(adap, CXGB4_STATE_FATAL_ERROR);
392162306a36Sopenharmony_ci}
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_civoid t4_fatal_err(struct adapter *adap)
392462306a36Sopenharmony_ci{
392562306a36Sopenharmony_ci	int port;
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ci	if (pci_channel_offline(adap->pdev))
392862306a36Sopenharmony_ci		return;
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_ci	/* Disable the SGE since ULDs are going to free resources that
393162306a36Sopenharmony_ci	 * could be exposed to the adapter.  RDMA MWs for example...
393262306a36Sopenharmony_ci	 */
393362306a36Sopenharmony_ci	t4_shutdown_adapter(adap);
393462306a36Sopenharmony_ci	for_each_port(adap, port) {
393562306a36Sopenharmony_ci		struct net_device *dev = adap->port[port];
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci		/* If we get here in very early initialization the network
393862306a36Sopenharmony_ci		 * devices may not have been set up yet.
393962306a36Sopenharmony_ci		 */
394062306a36Sopenharmony_ci		if (!dev)
394162306a36Sopenharmony_ci			continue;
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci		netif_tx_stop_all_queues(dev);
394462306a36Sopenharmony_ci		netif_carrier_off(dev);
394562306a36Sopenharmony_ci	}
394662306a36Sopenharmony_ci	dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n");
394762306a36Sopenharmony_ci	queue_work(adap->workq, &adap->fatal_err_notify_task);
394862306a36Sopenharmony_ci}
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_cistatic void setup_memwin(struct adapter *adap)
395162306a36Sopenharmony_ci{
395262306a36Sopenharmony_ci	u32 nic_win_base = t4_get_util_window(adap);
395362306a36Sopenharmony_ci
395462306a36Sopenharmony_ci	t4_setup_memwin(adap, nic_win_base, MEMWIN_NIC);
395562306a36Sopenharmony_ci}
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_cistatic void setup_memwin_rdma(struct adapter *adap)
395862306a36Sopenharmony_ci{
395962306a36Sopenharmony_ci	if (adap->vres.ocq.size) {
396062306a36Sopenharmony_ci		u32 start;
396162306a36Sopenharmony_ci		unsigned int sz_kb;
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_ci		start = t4_read_pcie_cfg4(adap, PCI_BASE_ADDRESS_2);
396462306a36Sopenharmony_ci		start &= PCI_BASE_ADDRESS_MEM_MASK;
396562306a36Sopenharmony_ci		start += OCQ_WIN_OFFSET(adap->pdev, &adap->vres);
396662306a36Sopenharmony_ci		sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10;
396762306a36Sopenharmony_ci		t4_write_reg(adap,
396862306a36Sopenharmony_ci			     PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 3),
396962306a36Sopenharmony_ci			     start | BIR_V(1) | WINDOW_V(ilog2(sz_kb)));
397062306a36Sopenharmony_ci		t4_write_reg(adap,
397162306a36Sopenharmony_ci			     PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3),
397262306a36Sopenharmony_ci			     adap->vres.ocq.start);
397362306a36Sopenharmony_ci		t4_read_reg(adap,
397462306a36Sopenharmony_ci			    PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3));
397562306a36Sopenharmony_ci	}
397662306a36Sopenharmony_ci}
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci/* HMA Definitions */
397962306a36Sopenharmony_ci
398062306a36Sopenharmony_ci/* The maximum number of address that can be send in a single FW cmd */
398162306a36Sopenharmony_ci#define HMA_MAX_ADDR_IN_CMD	5
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci#define HMA_PAGE_SIZE		PAGE_SIZE
398462306a36Sopenharmony_ci
398562306a36Sopenharmony_ci#define HMA_MAX_NO_FW_ADDRESS	(16 << 10)  /* FW supports 16K addresses */
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci#define HMA_PAGE_ORDER					\
398862306a36Sopenharmony_ci	((HMA_PAGE_SIZE < HMA_MAX_NO_FW_ADDRESS) ?	\
398962306a36Sopenharmony_ci	ilog2(HMA_MAX_NO_FW_ADDRESS / HMA_PAGE_SIZE) : 0)
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci/* The minimum and maximum possible HMA sizes that can be specified in the FW
399262306a36Sopenharmony_ci * configuration(in units of MB).
399362306a36Sopenharmony_ci */
399462306a36Sopenharmony_ci#define HMA_MIN_TOTAL_SIZE	1
399562306a36Sopenharmony_ci#define HMA_MAX_TOTAL_SIZE				\
399662306a36Sopenharmony_ci	(((HMA_PAGE_SIZE << HMA_PAGE_ORDER) *		\
399762306a36Sopenharmony_ci	  HMA_MAX_NO_FW_ADDRESS) >> 20)
399862306a36Sopenharmony_ci
399962306a36Sopenharmony_cistatic void adap_free_hma_mem(struct adapter *adapter)
400062306a36Sopenharmony_ci{
400162306a36Sopenharmony_ci	struct scatterlist *iter;
400262306a36Sopenharmony_ci	struct page *page;
400362306a36Sopenharmony_ci	int i;
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci	if (!adapter->hma.sgt)
400662306a36Sopenharmony_ci		return;
400762306a36Sopenharmony_ci
400862306a36Sopenharmony_ci	if (adapter->hma.flags & HMA_DMA_MAPPED_FLAG) {
400962306a36Sopenharmony_ci		dma_unmap_sg(adapter->pdev_dev, adapter->hma.sgt->sgl,
401062306a36Sopenharmony_ci			     adapter->hma.sgt->nents, DMA_BIDIRECTIONAL);
401162306a36Sopenharmony_ci		adapter->hma.flags &= ~HMA_DMA_MAPPED_FLAG;
401262306a36Sopenharmony_ci	}
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_ci	for_each_sg(adapter->hma.sgt->sgl, iter,
401562306a36Sopenharmony_ci		    adapter->hma.sgt->orig_nents, i) {
401662306a36Sopenharmony_ci		page = sg_page(iter);
401762306a36Sopenharmony_ci		if (page)
401862306a36Sopenharmony_ci			__free_pages(page, HMA_PAGE_ORDER);
401962306a36Sopenharmony_ci	}
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci	kfree(adapter->hma.phy_addr);
402262306a36Sopenharmony_ci	sg_free_table(adapter->hma.sgt);
402362306a36Sopenharmony_ci	kfree(adapter->hma.sgt);
402462306a36Sopenharmony_ci	adapter->hma.sgt = NULL;
402562306a36Sopenharmony_ci}
402662306a36Sopenharmony_ci
402762306a36Sopenharmony_cistatic int adap_config_hma(struct adapter *adapter)
402862306a36Sopenharmony_ci{
402962306a36Sopenharmony_ci	struct scatterlist *sgl, *iter;
403062306a36Sopenharmony_ci	struct sg_table *sgt;
403162306a36Sopenharmony_ci	struct page *newpage;
403262306a36Sopenharmony_ci	unsigned int i, j, k;
403362306a36Sopenharmony_ci	u32 param, hma_size;
403462306a36Sopenharmony_ci	unsigned int ncmds;
403562306a36Sopenharmony_ci	size_t page_size;
403662306a36Sopenharmony_ci	u32 page_order;
403762306a36Sopenharmony_ci	int node, ret;
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci	/* HMA is supported only for T6+ cards.
404062306a36Sopenharmony_ci	 * Avoid initializing HMA in kdump kernels.
404162306a36Sopenharmony_ci	 */
404262306a36Sopenharmony_ci	if (is_kdump_kernel() ||
404362306a36Sopenharmony_ci	    CHELSIO_CHIP_VERSION(adapter->params.chip) < CHELSIO_T6)
404462306a36Sopenharmony_ci		return 0;
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci	/* Get the HMA region size required by fw */
404762306a36Sopenharmony_ci	param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
404862306a36Sopenharmony_ci		 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_HMA_SIZE));
404962306a36Sopenharmony_ci	ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0,
405062306a36Sopenharmony_ci			      1, &param, &hma_size);
405162306a36Sopenharmony_ci	/* An error means card has its own memory or HMA is not supported by
405262306a36Sopenharmony_ci	 * the firmware. Return without any errors.
405362306a36Sopenharmony_ci	 */
405462306a36Sopenharmony_ci	if (ret || !hma_size)
405562306a36Sopenharmony_ci		return 0;
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	if (hma_size < HMA_MIN_TOTAL_SIZE ||
405862306a36Sopenharmony_ci	    hma_size > HMA_MAX_TOTAL_SIZE) {
405962306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
406062306a36Sopenharmony_ci			"HMA size %uMB beyond bounds(%u-%lu)MB\n",
406162306a36Sopenharmony_ci			hma_size, HMA_MIN_TOTAL_SIZE, HMA_MAX_TOTAL_SIZE);
406262306a36Sopenharmony_ci		return -EINVAL;
406362306a36Sopenharmony_ci	}
406462306a36Sopenharmony_ci
406562306a36Sopenharmony_ci	page_size = HMA_PAGE_SIZE;
406662306a36Sopenharmony_ci	page_order = HMA_PAGE_ORDER;
406762306a36Sopenharmony_ci	adapter->hma.sgt = kzalloc(sizeof(*adapter->hma.sgt), GFP_KERNEL);
406862306a36Sopenharmony_ci	if (unlikely(!adapter->hma.sgt)) {
406962306a36Sopenharmony_ci		dev_err(adapter->pdev_dev, "HMA SG table allocation failed\n");
407062306a36Sopenharmony_ci		return -ENOMEM;
407162306a36Sopenharmony_ci	}
407262306a36Sopenharmony_ci	sgt = adapter->hma.sgt;
407362306a36Sopenharmony_ci	/* FW returned value will be in MB's
407462306a36Sopenharmony_ci	 */
407562306a36Sopenharmony_ci	sgt->orig_nents = (hma_size << 20) / (page_size << page_order);
407662306a36Sopenharmony_ci	if (sg_alloc_table(sgt, sgt->orig_nents, GFP_KERNEL)) {
407762306a36Sopenharmony_ci		dev_err(adapter->pdev_dev, "HMA SGL allocation failed\n");
407862306a36Sopenharmony_ci		kfree(adapter->hma.sgt);
407962306a36Sopenharmony_ci		adapter->hma.sgt = NULL;
408062306a36Sopenharmony_ci		return -ENOMEM;
408162306a36Sopenharmony_ci	}
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	sgl = adapter->hma.sgt->sgl;
408462306a36Sopenharmony_ci	node = dev_to_node(adapter->pdev_dev);
408562306a36Sopenharmony_ci	for_each_sg(sgl, iter, sgt->orig_nents, i) {
408662306a36Sopenharmony_ci		newpage = alloc_pages_node(node, __GFP_NOWARN | GFP_KERNEL |
408762306a36Sopenharmony_ci					   __GFP_ZERO, page_order);
408862306a36Sopenharmony_ci		if (!newpage) {
408962306a36Sopenharmony_ci			dev_err(adapter->pdev_dev,
409062306a36Sopenharmony_ci				"Not enough memory for HMA page allocation\n");
409162306a36Sopenharmony_ci			ret = -ENOMEM;
409262306a36Sopenharmony_ci			goto free_hma;
409362306a36Sopenharmony_ci		}
409462306a36Sopenharmony_ci		sg_set_page(iter, newpage, page_size << page_order, 0);
409562306a36Sopenharmony_ci	}
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_ci	sgt->nents = dma_map_sg(adapter->pdev_dev, sgl, sgt->orig_nents,
409862306a36Sopenharmony_ci				DMA_BIDIRECTIONAL);
409962306a36Sopenharmony_ci	if (!sgt->nents) {
410062306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
410162306a36Sopenharmony_ci			"Not enough memory for HMA DMA mapping");
410262306a36Sopenharmony_ci		ret = -ENOMEM;
410362306a36Sopenharmony_ci		goto free_hma;
410462306a36Sopenharmony_ci	}
410562306a36Sopenharmony_ci	adapter->hma.flags |= HMA_DMA_MAPPED_FLAG;
410662306a36Sopenharmony_ci
410762306a36Sopenharmony_ci	adapter->hma.phy_addr = kcalloc(sgt->nents, sizeof(dma_addr_t),
410862306a36Sopenharmony_ci					GFP_KERNEL);
410962306a36Sopenharmony_ci	if (unlikely(!adapter->hma.phy_addr))
411062306a36Sopenharmony_ci		goto free_hma;
411162306a36Sopenharmony_ci
411262306a36Sopenharmony_ci	for_each_sg(sgl, iter, sgt->nents, i) {
411362306a36Sopenharmony_ci		newpage = sg_page(iter);
411462306a36Sopenharmony_ci		adapter->hma.phy_addr[i] = sg_dma_address(iter);
411562306a36Sopenharmony_ci	}
411662306a36Sopenharmony_ci
411762306a36Sopenharmony_ci	ncmds = DIV_ROUND_UP(sgt->nents, HMA_MAX_ADDR_IN_CMD);
411862306a36Sopenharmony_ci	/* Pass on the addresses to firmware */
411962306a36Sopenharmony_ci	for (i = 0, k = 0; i < ncmds; i++, k += HMA_MAX_ADDR_IN_CMD) {
412062306a36Sopenharmony_ci		struct fw_hma_cmd hma_cmd;
412162306a36Sopenharmony_ci		u8 naddr = HMA_MAX_ADDR_IN_CMD;
412262306a36Sopenharmony_ci		u8 soc = 0, eoc = 0;
412362306a36Sopenharmony_ci		u8 hma_mode = 1; /* Presently we support only Page table mode */
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci		soc = (i == 0) ? 1 : 0;
412662306a36Sopenharmony_ci		eoc = (i == ncmds - 1) ? 1 : 0;
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci		/* For last cmd, set naddr corresponding to remaining
412962306a36Sopenharmony_ci		 * addresses
413062306a36Sopenharmony_ci		 */
413162306a36Sopenharmony_ci		if (i == ncmds - 1) {
413262306a36Sopenharmony_ci			naddr = sgt->nents % HMA_MAX_ADDR_IN_CMD;
413362306a36Sopenharmony_ci			naddr = naddr ? naddr : HMA_MAX_ADDR_IN_CMD;
413462306a36Sopenharmony_ci		}
413562306a36Sopenharmony_ci		memset(&hma_cmd, 0, sizeof(hma_cmd));
413662306a36Sopenharmony_ci		hma_cmd.op_pkd = htonl(FW_CMD_OP_V(FW_HMA_CMD) |
413762306a36Sopenharmony_ci				       FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
413862306a36Sopenharmony_ci		hma_cmd.retval_len16 = htonl(FW_LEN16(hma_cmd));
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_ci		hma_cmd.mode_to_pcie_params =
414162306a36Sopenharmony_ci			htonl(FW_HMA_CMD_MODE_V(hma_mode) |
414262306a36Sopenharmony_ci			      FW_HMA_CMD_SOC_V(soc) | FW_HMA_CMD_EOC_V(eoc));
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_ci		/* HMA cmd size specified in MB's */
414562306a36Sopenharmony_ci		hma_cmd.naddr_size =
414662306a36Sopenharmony_ci			htonl(FW_HMA_CMD_SIZE_V(hma_size) |
414762306a36Sopenharmony_ci			      FW_HMA_CMD_NADDR_V(naddr));
414862306a36Sopenharmony_ci
414962306a36Sopenharmony_ci		/* Total Page size specified in units of 4K */
415062306a36Sopenharmony_ci		hma_cmd.addr_size_pkd =
415162306a36Sopenharmony_ci			htonl(FW_HMA_CMD_ADDR_SIZE_V
415262306a36Sopenharmony_ci				((page_size << page_order) >> 12));
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci		/* Fill the 5 addresses */
415562306a36Sopenharmony_ci		for (j = 0; j < naddr; j++) {
415662306a36Sopenharmony_ci			hma_cmd.phy_address[j] =
415762306a36Sopenharmony_ci				cpu_to_be64(adapter->hma.phy_addr[j + k]);
415862306a36Sopenharmony_ci		}
415962306a36Sopenharmony_ci		ret = t4_wr_mbox(adapter, adapter->mbox, &hma_cmd,
416062306a36Sopenharmony_ci				 sizeof(hma_cmd), &hma_cmd);
416162306a36Sopenharmony_ci		if (ret) {
416262306a36Sopenharmony_ci			dev_err(adapter->pdev_dev,
416362306a36Sopenharmony_ci				"HMA FW command failed with err %d\n", ret);
416462306a36Sopenharmony_ci			goto free_hma;
416562306a36Sopenharmony_ci		}
416662306a36Sopenharmony_ci	}
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_ci	if (!ret)
416962306a36Sopenharmony_ci		dev_info(adapter->pdev_dev,
417062306a36Sopenharmony_ci			 "Reserved %uMB host memory for HMA\n", hma_size);
417162306a36Sopenharmony_ci	return ret;
417262306a36Sopenharmony_ci
417362306a36Sopenharmony_cifree_hma:
417462306a36Sopenharmony_ci	adap_free_hma_mem(adapter);
417562306a36Sopenharmony_ci	return ret;
417662306a36Sopenharmony_ci}
417762306a36Sopenharmony_ci
417862306a36Sopenharmony_cistatic int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
417962306a36Sopenharmony_ci{
418062306a36Sopenharmony_ci	u32 v;
418162306a36Sopenharmony_ci	int ret;
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ci	/* Now that we've successfully configured and initialized the adapter
418462306a36Sopenharmony_ci	 * can ask the Firmware what resources it has provisioned for us.
418562306a36Sopenharmony_ci	 */
418662306a36Sopenharmony_ci	ret = t4_get_pfres(adap);
418762306a36Sopenharmony_ci	if (ret) {
418862306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
418962306a36Sopenharmony_ci			"Unable to retrieve resource provisioning information\n");
419062306a36Sopenharmony_ci		return ret;
419162306a36Sopenharmony_ci	}
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	/* get device capabilities */
419462306a36Sopenharmony_ci	memset(c, 0, sizeof(*c));
419562306a36Sopenharmony_ci	c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
419662306a36Sopenharmony_ci			       FW_CMD_REQUEST_F | FW_CMD_READ_F);
419762306a36Sopenharmony_ci	c->cfvalid_to_len16 = htonl(FW_LEN16(*c));
419862306a36Sopenharmony_ci	ret = t4_wr_mbox(adap, adap->mbox, c, sizeof(*c), c);
419962306a36Sopenharmony_ci	if (ret < 0)
420062306a36Sopenharmony_ci		return ret;
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci	c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
420362306a36Sopenharmony_ci			       FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
420462306a36Sopenharmony_ci	ret = t4_wr_mbox(adap, adap->mbox, c, sizeof(*c), NULL);
420562306a36Sopenharmony_ci	if (ret < 0)
420662306a36Sopenharmony_ci		return ret;
420762306a36Sopenharmony_ci
420862306a36Sopenharmony_ci	ret = t4_config_glbl_rss(adap, adap->pf,
420962306a36Sopenharmony_ci				 FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
421062306a36Sopenharmony_ci				 FW_RSS_GLB_CONFIG_CMD_TNLMAPEN_F |
421162306a36Sopenharmony_ci				 FW_RSS_GLB_CONFIG_CMD_TNLALLLKP_F);
421262306a36Sopenharmony_ci	if (ret < 0)
421362306a36Sopenharmony_ci		return ret;
421462306a36Sopenharmony_ci
421562306a36Sopenharmony_ci	ret = t4_cfg_pfvf(adap, adap->mbox, adap->pf, 0, adap->sge.egr_sz, 64,
421662306a36Sopenharmony_ci			  MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF,
421762306a36Sopenharmony_ci			  FW_CMD_CAP_PF);
421862306a36Sopenharmony_ci	if (ret < 0)
421962306a36Sopenharmony_ci		return ret;
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci	t4_sge_init(adap);
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_ci	/* tweak some settings */
422462306a36Sopenharmony_ci	t4_write_reg(adap, TP_SHIFT_CNT_A, 0x64f8849);
422562306a36Sopenharmony_ci	t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(PAGE_SHIFT - 12));
422662306a36Sopenharmony_ci	t4_write_reg(adap, TP_PIO_ADDR_A, TP_INGRESS_CONFIG_A);
422762306a36Sopenharmony_ci	v = t4_read_reg(adap, TP_PIO_DATA_A);
422862306a36Sopenharmony_ci	t4_write_reg(adap, TP_PIO_DATA_A, v & ~CSUM_HAS_PSEUDO_HDR_F);
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_ci	/* first 4 Tx modulation queues point to consecutive Tx channels */
423162306a36Sopenharmony_ci	adap->params.tp.tx_modq_map = 0xE4;
423262306a36Sopenharmony_ci	t4_write_reg(adap, TP_TX_MOD_QUEUE_REQ_MAP_A,
423362306a36Sopenharmony_ci		     TX_MOD_QUEUE_REQ_MAP_V(adap->params.tp.tx_modq_map));
423462306a36Sopenharmony_ci
423562306a36Sopenharmony_ci	/* associate each Tx modulation queue with consecutive Tx channels */
423662306a36Sopenharmony_ci	v = 0x84218421;
423762306a36Sopenharmony_ci	t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
423862306a36Sopenharmony_ci			  &v, 1, TP_TX_SCHED_HDR_A);
423962306a36Sopenharmony_ci	t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
424062306a36Sopenharmony_ci			  &v, 1, TP_TX_SCHED_FIFO_A);
424162306a36Sopenharmony_ci	t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
424262306a36Sopenharmony_ci			  &v, 1, TP_TX_SCHED_PCMD_A);
424362306a36Sopenharmony_ci
424462306a36Sopenharmony_ci#define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */
424562306a36Sopenharmony_ci	if (is_offload(adap)) {
424662306a36Sopenharmony_ci		t4_write_reg(adap, TP_TX_MOD_QUEUE_WEIGHT0_A,
424762306a36Sopenharmony_ci			     TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
424862306a36Sopenharmony_ci			     TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
424962306a36Sopenharmony_ci			     TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
425062306a36Sopenharmony_ci			     TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
425162306a36Sopenharmony_ci		t4_write_reg(adap, TP_TX_MOD_CHANNEL_WEIGHT_A,
425262306a36Sopenharmony_ci			     TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
425362306a36Sopenharmony_ci			     TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
425462306a36Sopenharmony_ci			     TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
425562306a36Sopenharmony_ci			     TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
425662306a36Sopenharmony_ci	}
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci	/* get basic stuff going */
425962306a36Sopenharmony_ci	return t4_early_init(adap, adap->pf);
426062306a36Sopenharmony_ci}
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci/*
426362306a36Sopenharmony_ci * Max # of ATIDs.  The absolute HW max is 16K but we keep it lower.
426462306a36Sopenharmony_ci */
426562306a36Sopenharmony_ci#define MAX_ATIDS 8192U
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci/*
426862306a36Sopenharmony_ci * Phase 0 of initialization: contact FW, obtain config, perform basic init.
426962306a36Sopenharmony_ci *
427062306a36Sopenharmony_ci * If the firmware we're dealing with has Configuration File support, then
427162306a36Sopenharmony_ci * we use that to perform all configuration
427262306a36Sopenharmony_ci */
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_ci/*
427562306a36Sopenharmony_ci * Tweak configuration based on module parameters, etc.  Most of these have
427662306a36Sopenharmony_ci * defaults assigned to them by Firmware Configuration Files (if we're using
427762306a36Sopenharmony_ci * them) but need to be explicitly set if we're using hard-coded
427862306a36Sopenharmony_ci * initialization.  But even in the case of using Firmware Configuration
427962306a36Sopenharmony_ci * Files, we'd like to expose the ability to change these via module
428062306a36Sopenharmony_ci * parameters so these are essentially common tweaks/settings for
428162306a36Sopenharmony_ci * Configuration Files and hard-coded initialization ...
428262306a36Sopenharmony_ci */
428362306a36Sopenharmony_cistatic int adap_init0_tweaks(struct adapter *adapter)
428462306a36Sopenharmony_ci{
428562306a36Sopenharmony_ci	/*
428662306a36Sopenharmony_ci	 * Fix up various Host-Dependent Parameters like Page Size, Cache
428762306a36Sopenharmony_ci	 * Line Size, etc.  The firmware default is for a 4KB Page Size and
428862306a36Sopenharmony_ci	 * 64B Cache Line Size ...
428962306a36Sopenharmony_ci	 */
429062306a36Sopenharmony_ci	t4_fixup_host_params(adapter, PAGE_SIZE, L1_CACHE_BYTES);
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci	/*
429362306a36Sopenharmony_ci	 * Process module parameters which affect early initialization.
429462306a36Sopenharmony_ci	 */
429562306a36Sopenharmony_ci	if (rx_dma_offset != 2 && rx_dma_offset != 0) {
429662306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
429762306a36Sopenharmony_ci			"Ignoring illegal rx_dma_offset=%d, using 2\n",
429862306a36Sopenharmony_ci			rx_dma_offset);
429962306a36Sopenharmony_ci		rx_dma_offset = 2;
430062306a36Sopenharmony_ci	}
430162306a36Sopenharmony_ci	t4_set_reg_field(adapter, SGE_CONTROL_A,
430262306a36Sopenharmony_ci			 PKTSHIFT_V(PKTSHIFT_M),
430362306a36Sopenharmony_ci			 PKTSHIFT_V(rx_dma_offset));
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	/*
430662306a36Sopenharmony_ci	 * Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux
430762306a36Sopenharmony_ci	 * adds the pseudo header itself.
430862306a36Sopenharmony_ci	 */
430962306a36Sopenharmony_ci	t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG_A,
431062306a36Sopenharmony_ci			       CSUM_HAS_PSEUDO_HDR_F, 0);
431162306a36Sopenharmony_ci
431262306a36Sopenharmony_ci	return 0;
431362306a36Sopenharmony_ci}
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_ci/* 10Gb/s-BT PHY Support. chip-external 10Gb/s-BT PHYs are complex chips
431662306a36Sopenharmony_ci * unto themselves and they contain their own firmware to perform their
431762306a36Sopenharmony_ci * tasks ...
431862306a36Sopenharmony_ci */
431962306a36Sopenharmony_cistatic int phy_aq1202_version(const u8 *phy_fw_data,
432062306a36Sopenharmony_ci			      size_t phy_fw_size)
432162306a36Sopenharmony_ci{
432262306a36Sopenharmony_ci	int offset;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	/* At offset 0x8 you're looking for the primary image's
432562306a36Sopenharmony_ci	 * starting offset which is 3 Bytes wide
432662306a36Sopenharmony_ci	 *
432762306a36Sopenharmony_ci	 * At offset 0xa of the primary image, you look for the offset
432862306a36Sopenharmony_ci	 * of the DRAM segment which is 3 Bytes wide.
432962306a36Sopenharmony_ci	 *
433062306a36Sopenharmony_ci	 * The FW version is at offset 0x27e of the DRAM and is 2 Bytes
433162306a36Sopenharmony_ci	 * wide
433262306a36Sopenharmony_ci	 */
433362306a36Sopenharmony_ci	#define be16(__p) (((__p)[0] << 8) | (__p)[1])
433462306a36Sopenharmony_ci	#define le16(__p) ((__p)[0] | ((__p)[1] << 8))
433562306a36Sopenharmony_ci	#define le24(__p) (le16(__p) | ((__p)[2] << 16))
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_ci	offset = le24(phy_fw_data + 0x8) << 12;
433862306a36Sopenharmony_ci	offset = le24(phy_fw_data + offset + 0xa);
433962306a36Sopenharmony_ci	return be16(phy_fw_data + offset + 0x27e);
434062306a36Sopenharmony_ci
434162306a36Sopenharmony_ci	#undef be16
434262306a36Sopenharmony_ci	#undef le16
434362306a36Sopenharmony_ci	#undef le24
434462306a36Sopenharmony_ci}
434562306a36Sopenharmony_ci
434662306a36Sopenharmony_cistatic struct info_10gbt_phy_fw {
434762306a36Sopenharmony_ci	unsigned int phy_fw_id;		/* PCI Device ID */
434862306a36Sopenharmony_ci	char *phy_fw_file;		/* /lib/firmware/ PHY Firmware file */
434962306a36Sopenharmony_ci	int (*phy_fw_version)(const u8 *phy_fw_data, size_t phy_fw_size);
435062306a36Sopenharmony_ci	int phy_flash;			/* Has FLASH for PHY Firmware */
435162306a36Sopenharmony_ci} phy_info_array[] = {
435262306a36Sopenharmony_ci	{
435362306a36Sopenharmony_ci		PHY_AQ1202_DEVICEID,
435462306a36Sopenharmony_ci		PHY_AQ1202_FIRMWARE,
435562306a36Sopenharmony_ci		phy_aq1202_version,
435662306a36Sopenharmony_ci		1,
435762306a36Sopenharmony_ci	},
435862306a36Sopenharmony_ci	{
435962306a36Sopenharmony_ci		PHY_BCM84834_DEVICEID,
436062306a36Sopenharmony_ci		PHY_BCM84834_FIRMWARE,
436162306a36Sopenharmony_ci		NULL,
436262306a36Sopenharmony_ci		0,
436362306a36Sopenharmony_ci	},
436462306a36Sopenharmony_ci	{ 0, NULL, NULL },
436562306a36Sopenharmony_ci};
436662306a36Sopenharmony_ci
436762306a36Sopenharmony_cistatic struct info_10gbt_phy_fw *find_phy_info(int devid)
436862306a36Sopenharmony_ci{
436962306a36Sopenharmony_ci	int i;
437062306a36Sopenharmony_ci
437162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(phy_info_array); i++) {
437262306a36Sopenharmony_ci		if (phy_info_array[i].phy_fw_id == devid)
437362306a36Sopenharmony_ci			return &phy_info_array[i];
437462306a36Sopenharmony_ci	}
437562306a36Sopenharmony_ci	return NULL;
437662306a36Sopenharmony_ci}
437762306a36Sopenharmony_ci
437862306a36Sopenharmony_ci/* Handle updating of chip-external 10Gb/s-BT PHY firmware.  This needs to
437962306a36Sopenharmony_ci * happen after the FW_RESET_CMD but before the FW_INITIALIZE_CMD.  On error
438062306a36Sopenharmony_ci * we return a negative error number.  If we transfer new firmware we return 1
438162306a36Sopenharmony_ci * (from t4_load_phy_fw()).  If we don't do anything we return 0.
438262306a36Sopenharmony_ci */
438362306a36Sopenharmony_cistatic int adap_init0_phy(struct adapter *adap)
438462306a36Sopenharmony_ci{
438562306a36Sopenharmony_ci	const struct firmware *phyf;
438662306a36Sopenharmony_ci	int ret;
438762306a36Sopenharmony_ci	struct info_10gbt_phy_fw *phy_info;
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci	/* Use the device ID to determine which PHY file to flash.
439062306a36Sopenharmony_ci	 */
439162306a36Sopenharmony_ci	phy_info = find_phy_info(adap->pdev->device);
439262306a36Sopenharmony_ci	if (!phy_info) {
439362306a36Sopenharmony_ci		dev_warn(adap->pdev_dev,
439462306a36Sopenharmony_ci			 "No PHY Firmware file found for this PHY\n");
439562306a36Sopenharmony_ci		return -EOPNOTSUPP;
439662306a36Sopenharmony_ci	}
439762306a36Sopenharmony_ci
439862306a36Sopenharmony_ci	/* If we have a T4 PHY firmware file under /lib/firmware/cxgb4/, then
439962306a36Sopenharmony_ci	 * use that. The adapter firmware provides us with a memory buffer
440062306a36Sopenharmony_ci	 * where we can load a PHY firmware file from the host if we want to
440162306a36Sopenharmony_ci	 * override the PHY firmware File in flash.
440262306a36Sopenharmony_ci	 */
440362306a36Sopenharmony_ci	ret = request_firmware_direct(&phyf, phy_info->phy_fw_file,
440462306a36Sopenharmony_ci				      adap->pdev_dev);
440562306a36Sopenharmony_ci	if (ret < 0) {
440662306a36Sopenharmony_ci		/* For adapters without FLASH attached to PHY for their
440762306a36Sopenharmony_ci		 * firmware, it's obviously a fatal error if we can't get the
440862306a36Sopenharmony_ci		 * firmware to the adapter.  For adapters with PHY firmware
440962306a36Sopenharmony_ci		 * FLASH storage, it's worth a warning if we can't find the
441062306a36Sopenharmony_ci		 * PHY Firmware but we'll neuter the error ...
441162306a36Sopenharmony_ci		 */
441262306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "unable to find PHY Firmware image "
441362306a36Sopenharmony_ci			"/lib/firmware/%s, error %d\n",
441462306a36Sopenharmony_ci			phy_info->phy_fw_file, -ret);
441562306a36Sopenharmony_ci		if (phy_info->phy_flash) {
441662306a36Sopenharmony_ci			int cur_phy_fw_ver = 0;
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_ci			t4_phy_fw_ver(adap, &cur_phy_fw_ver);
441962306a36Sopenharmony_ci			dev_warn(adap->pdev_dev, "continuing with, on-adapter "
442062306a36Sopenharmony_ci				 "FLASH copy, version %#x\n", cur_phy_fw_ver);
442162306a36Sopenharmony_ci			ret = 0;
442262306a36Sopenharmony_ci		}
442362306a36Sopenharmony_ci
442462306a36Sopenharmony_ci		return ret;
442562306a36Sopenharmony_ci	}
442662306a36Sopenharmony_ci
442762306a36Sopenharmony_ci	/* Load PHY Firmware onto adapter.
442862306a36Sopenharmony_ci	 */
442962306a36Sopenharmony_ci	ret = t4_load_phy_fw(adap, MEMWIN_NIC, phy_info->phy_fw_version,
443062306a36Sopenharmony_ci			     (u8 *)phyf->data, phyf->size);
443162306a36Sopenharmony_ci	if (ret < 0)
443262306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "PHY Firmware transfer error %d\n",
443362306a36Sopenharmony_ci			-ret);
443462306a36Sopenharmony_ci	else if (ret > 0) {
443562306a36Sopenharmony_ci		int new_phy_fw_ver = 0;
443662306a36Sopenharmony_ci
443762306a36Sopenharmony_ci		if (phy_info->phy_fw_version)
443862306a36Sopenharmony_ci			new_phy_fw_ver = phy_info->phy_fw_version(phyf->data,
443962306a36Sopenharmony_ci								  phyf->size);
444062306a36Sopenharmony_ci		dev_info(adap->pdev_dev, "Successfully transferred PHY "
444162306a36Sopenharmony_ci			 "Firmware /lib/firmware/%s, version %#x\n",
444262306a36Sopenharmony_ci			 phy_info->phy_fw_file, new_phy_fw_ver);
444362306a36Sopenharmony_ci	}
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci	release_firmware(phyf);
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci	return ret;
444862306a36Sopenharmony_ci}
444962306a36Sopenharmony_ci
445062306a36Sopenharmony_ci/*
445162306a36Sopenharmony_ci * Attempt to initialize the adapter via a Firmware Configuration File.
445262306a36Sopenharmony_ci */
445362306a36Sopenharmony_cistatic int adap_init0_config(struct adapter *adapter, int reset)
445462306a36Sopenharmony_ci{
445562306a36Sopenharmony_ci	char *fw_config_file, fw_config_file_path[256];
445662306a36Sopenharmony_ci	u32 finiver, finicsum, cfcsum, param, val;
445762306a36Sopenharmony_ci	struct fw_caps_config_cmd caps_cmd;
445862306a36Sopenharmony_ci	unsigned long mtype = 0, maddr = 0;
445962306a36Sopenharmony_ci	const struct firmware *cf;
446062306a36Sopenharmony_ci	char *config_name = NULL;
446162306a36Sopenharmony_ci	int config_issued = 0;
446262306a36Sopenharmony_ci	int ret;
446362306a36Sopenharmony_ci
446462306a36Sopenharmony_ci	/*
446562306a36Sopenharmony_ci	 * Reset device if necessary.
446662306a36Sopenharmony_ci	 */
446762306a36Sopenharmony_ci	if (reset) {
446862306a36Sopenharmony_ci		ret = t4_fw_reset(adapter, adapter->mbox,
446962306a36Sopenharmony_ci				  PIORSTMODE_F | PIORST_F);
447062306a36Sopenharmony_ci		if (ret < 0)
447162306a36Sopenharmony_ci			goto bye;
447262306a36Sopenharmony_ci	}
447362306a36Sopenharmony_ci
447462306a36Sopenharmony_ci	/* If this is a 10Gb/s-BT adapter make sure the chip-external
447562306a36Sopenharmony_ci	 * 10Gb/s-BT PHYs have up-to-date firmware.  Note that this step needs
447662306a36Sopenharmony_ci	 * to be performed after any global adapter RESET above since some
447762306a36Sopenharmony_ci	 * PHYs only have local RAM copies of the PHY firmware.
447862306a36Sopenharmony_ci	 */
447962306a36Sopenharmony_ci	if (is_10gbt_device(adapter->pdev->device)) {
448062306a36Sopenharmony_ci		ret = adap_init0_phy(adapter);
448162306a36Sopenharmony_ci		if (ret < 0)
448262306a36Sopenharmony_ci			goto bye;
448362306a36Sopenharmony_ci	}
448462306a36Sopenharmony_ci	/*
448562306a36Sopenharmony_ci	 * If we have a T4 configuration file under /lib/firmware/cxgb4/,
448662306a36Sopenharmony_ci	 * then use that.  Otherwise, use the configuration file stored
448762306a36Sopenharmony_ci	 * in the adapter flash ...
448862306a36Sopenharmony_ci	 */
448962306a36Sopenharmony_ci	switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) {
449062306a36Sopenharmony_ci	case CHELSIO_T4:
449162306a36Sopenharmony_ci		fw_config_file = FW4_CFNAME;
449262306a36Sopenharmony_ci		break;
449362306a36Sopenharmony_ci	case CHELSIO_T5:
449462306a36Sopenharmony_ci		fw_config_file = FW5_CFNAME;
449562306a36Sopenharmony_ci		break;
449662306a36Sopenharmony_ci	case CHELSIO_T6:
449762306a36Sopenharmony_ci		fw_config_file = FW6_CFNAME;
449862306a36Sopenharmony_ci		break;
449962306a36Sopenharmony_ci	default:
450062306a36Sopenharmony_ci		dev_err(adapter->pdev_dev, "Device %d is not supported\n",
450162306a36Sopenharmony_ci		       adapter->pdev->device);
450262306a36Sopenharmony_ci		ret = -EINVAL;
450362306a36Sopenharmony_ci		goto bye;
450462306a36Sopenharmony_ci	}
450562306a36Sopenharmony_ci
450662306a36Sopenharmony_ci	ret = request_firmware(&cf, fw_config_file, adapter->pdev_dev);
450762306a36Sopenharmony_ci	if (ret < 0) {
450862306a36Sopenharmony_ci		config_name = "On FLASH";
450962306a36Sopenharmony_ci		mtype = FW_MEMTYPE_CF_FLASH;
451062306a36Sopenharmony_ci		maddr = t4_flash_cfg_addr(adapter);
451162306a36Sopenharmony_ci	} else {
451262306a36Sopenharmony_ci		u32 params[7], val[7];
451362306a36Sopenharmony_ci
451462306a36Sopenharmony_ci		sprintf(fw_config_file_path,
451562306a36Sopenharmony_ci			"/lib/firmware/%s", fw_config_file);
451662306a36Sopenharmony_ci		config_name = fw_config_file_path;
451762306a36Sopenharmony_ci
451862306a36Sopenharmony_ci		if (cf->size >= FLASH_CFG_MAX_SIZE)
451962306a36Sopenharmony_ci			ret = -ENOMEM;
452062306a36Sopenharmony_ci		else {
452162306a36Sopenharmony_ci			params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
452262306a36Sopenharmony_ci			     FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF));
452362306a36Sopenharmony_ci			ret = t4_query_params(adapter, adapter->mbox,
452462306a36Sopenharmony_ci					      adapter->pf, 0, 1, params, val);
452562306a36Sopenharmony_ci			if (ret == 0) {
452662306a36Sopenharmony_ci				/*
452762306a36Sopenharmony_ci				 * For t4_memory_rw() below addresses and
452862306a36Sopenharmony_ci				 * sizes have to be in terms of multiples of 4
452962306a36Sopenharmony_ci				 * bytes.  So, if the Configuration File isn't
453062306a36Sopenharmony_ci				 * a multiple of 4 bytes in length we'll have
453162306a36Sopenharmony_ci				 * to write that out separately since we can't
453262306a36Sopenharmony_ci				 * guarantee that the bytes following the
453362306a36Sopenharmony_ci				 * residual byte in the buffer returned by
453462306a36Sopenharmony_ci				 * request_firmware() are zeroed out ...
453562306a36Sopenharmony_ci				 */
453662306a36Sopenharmony_ci				size_t resid = cf->size & 0x3;
453762306a36Sopenharmony_ci				size_t size = cf->size & ~0x3;
453862306a36Sopenharmony_ci				__be32 *data = (__be32 *)cf->data;
453962306a36Sopenharmony_ci
454062306a36Sopenharmony_ci				mtype = FW_PARAMS_PARAM_Y_G(val[0]);
454162306a36Sopenharmony_ci				maddr = FW_PARAMS_PARAM_Z_G(val[0]) << 16;
454262306a36Sopenharmony_ci
454362306a36Sopenharmony_ci				spin_lock(&adapter->win0_lock);
454462306a36Sopenharmony_ci				ret = t4_memory_rw(adapter, 0, mtype, maddr,
454562306a36Sopenharmony_ci						   size, data, T4_MEMORY_WRITE);
454662306a36Sopenharmony_ci				if (ret == 0 && resid != 0) {
454762306a36Sopenharmony_ci					union {
454862306a36Sopenharmony_ci						__be32 word;
454962306a36Sopenharmony_ci						char buf[4];
455062306a36Sopenharmony_ci					} last;
455162306a36Sopenharmony_ci					int i;
455262306a36Sopenharmony_ci
455362306a36Sopenharmony_ci					last.word = data[size >> 2];
455462306a36Sopenharmony_ci					for (i = resid; i < 4; i++)
455562306a36Sopenharmony_ci						last.buf[i] = 0;
455662306a36Sopenharmony_ci					ret = t4_memory_rw(adapter, 0, mtype,
455762306a36Sopenharmony_ci							   maddr + size,
455862306a36Sopenharmony_ci							   4, &last.word,
455962306a36Sopenharmony_ci							   T4_MEMORY_WRITE);
456062306a36Sopenharmony_ci				}
456162306a36Sopenharmony_ci				spin_unlock(&adapter->win0_lock);
456262306a36Sopenharmony_ci			}
456362306a36Sopenharmony_ci		}
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci		release_firmware(cf);
456662306a36Sopenharmony_ci		if (ret)
456762306a36Sopenharmony_ci			goto bye;
456862306a36Sopenharmony_ci	}
456962306a36Sopenharmony_ci
457062306a36Sopenharmony_ci	val = 0;
457162306a36Sopenharmony_ci
457262306a36Sopenharmony_ci	/* Ofld + Hash filter is supported. Older fw will fail this request and
457362306a36Sopenharmony_ci	 * it is fine.
457462306a36Sopenharmony_ci	 */
457562306a36Sopenharmony_ci	param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
457662306a36Sopenharmony_ci		 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_HASHFILTER_WITH_OFLD));
457762306a36Sopenharmony_ci	ret = t4_set_params(adapter, adapter->mbox, adapter->pf, 0,
457862306a36Sopenharmony_ci			    1, &param, &val);
457962306a36Sopenharmony_ci
458062306a36Sopenharmony_ci	/* FW doesn't know about Hash filter + ofld support,
458162306a36Sopenharmony_ci	 * it's not a problem, don't return an error.
458262306a36Sopenharmony_ci	 */
458362306a36Sopenharmony_ci	if (ret < 0) {
458462306a36Sopenharmony_ci		dev_warn(adapter->pdev_dev,
458562306a36Sopenharmony_ci			 "Hash filter with ofld is not supported by FW\n");
458662306a36Sopenharmony_ci	}
458762306a36Sopenharmony_ci
458862306a36Sopenharmony_ci	/*
458962306a36Sopenharmony_ci	 * Issue a Capability Configuration command to the firmware to get it
459062306a36Sopenharmony_ci	 * to parse the Configuration File.  We don't use t4_fw_config_file()
459162306a36Sopenharmony_ci	 * because we want the ability to modify various features after we've
459262306a36Sopenharmony_ci	 * processed the configuration file ...
459362306a36Sopenharmony_ci	 */
459462306a36Sopenharmony_ci	memset(&caps_cmd, 0, sizeof(caps_cmd));
459562306a36Sopenharmony_ci	caps_cmd.op_to_write =
459662306a36Sopenharmony_ci		htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
459762306a36Sopenharmony_ci		      FW_CMD_REQUEST_F |
459862306a36Sopenharmony_ci		      FW_CMD_READ_F);
459962306a36Sopenharmony_ci	caps_cmd.cfvalid_to_len16 =
460062306a36Sopenharmony_ci		htonl(FW_CAPS_CONFIG_CMD_CFVALID_F |
460162306a36Sopenharmony_ci		      FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) |
460262306a36Sopenharmony_ci		      FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) |
460362306a36Sopenharmony_ci		      FW_LEN16(caps_cmd));
460462306a36Sopenharmony_ci	ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
460562306a36Sopenharmony_ci			 &caps_cmd);
460662306a36Sopenharmony_ci
460762306a36Sopenharmony_ci	/* If the CAPS_CONFIG failed with an ENOENT (for a Firmware
460862306a36Sopenharmony_ci	 * Configuration File in FLASH), our last gasp effort is to use the
460962306a36Sopenharmony_ci	 * Firmware Configuration File which is embedded in the firmware.  A
461062306a36Sopenharmony_ci	 * very few early versions of the firmware didn't have one embedded
461162306a36Sopenharmony_ci	 * but we can ignore those.
461262306a36Sopenharmony_ci	 */
461362306a36Sopenharmony_ci	if (ret == -ENOENT) {
461462306a36Sopenharmony_ci		memset(&caps_cmd, 0, sizeof(caps_cmd));
461562306a36Sopenharmony_ci		caps_cmd.op_to_write =
461662306a36Sopenharmony_ci			htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
461762306a36Sopenharmony_ci					FW_CMD_REQUEST_F |
461862306a36Sopenharmony_ci					FW_CMD_READ_F);
461962306a36Sopenharmony_ci		caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
462062306a36Sopenharmony_ci		ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd,
462162306a36Sopenharmony_ci				sizeof(caps_cmd), &caps_cmd);
462262306a36Sopenharmony_ci		config_name = "Firmware Default";
462362306a36Sopenharmony_ci	}
462462306a36Sopenharmony_ci
462562306a36Sopenharmony_ci	config_issued = 1;
462662306a36Sopenharmony_ci	if (ret < 0)
462762306a36Sopenharmony_ci		goto bye;
462862306a36Sopenharmony_ci
462962306a36Sopenharmony_ci	finiver = ntohl(caps_cmd.finiver);
463062306a36Sopenharmony_ci	finicsum = ntohl(caps_cmd.finicsum);
463162306a36Sopenharmony_ci	cfcsum = ntohl(caps_cmd.cfcsum);
463262306a36Sopenharmony_ci	if (finicsum != cfcsum)
463362306a36Sopenharmony_ci		dev_warn(adapter->pdev_dev, "Configuration File checksum "\
463462306a36Sopenharmony_ci			 "mismatch: [fini] csum=%#x, computed csum=%#x\n",
463562306a36Sopenharmony_ci			 finicsum, cfcsum);
463662306a36Sopenharmony_ci
463762306a36Sopenharmony_ci	/*
463862306a36Sopenharmony_ci	 * And now tell the firmware to use the configuration we just loaded.
463962306a36Sopenharmony_ci	 */
464062306a36Sopenharmony_ci	caps_cmd.op_to_write =
464162306a36Sopenharmony_ci		htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
464262306a36Sopenharmony_ci		      FW_CMD_REQUEST_F |
464362306a36Sopenharmony_ci		      FW_CMD_WRITE_F);
464462306a36Sopenharmony_ci	caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
464562306a36Sopenharmony_ci	ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
464662306a36Sopenharmony_ci			 NULL);
464762306a36Sopenharmony_ci	if (ret < 0)
464862306a36Sopenharmony_ci		goto bye;
464962306a36Sopenharmony_ci
465062306a36Sopenharmony_ci	/*
465162306a36Sopenharmony_ci	 * Tweak configuration based on system architecture, module
465262306a36Sopenharmony_ci	 * parameters, etc.
465362306a36Sopenharmony_ci	 */
465462306a36Sopenharmony_ci	ret = adap_init0_tweaks(adapter);
465562306a36Sopenharmony_ci	if (ret < 0)
465662306a36Sopenharmony_ci		goto bye;
465762306a36Sopenharmony_ci
465862306a36Sopenharmony_ci	/* We will proceed even if HMA init fails. */
465962306a36Sopenharmony_ci	ret = adap_config_hma(adapter);
466062306a36Sopenharmony_ci	if (ret)
466162306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
466262306a36Sopenharmony_ci			"HMA configuration failed with error %d\n", ret);
466362306a36Sopenharmony_ci
466462306a36Sopenharmony_ci	if (is_t6(adapter->params.chip)) {
466562306a36Sopenharmony_ci		adap_config_hpfilter(adapter);
466662306a36Sopenharmony_ci		ret = setup_ppod_edram(adapter);
466762306a36Sopenharmony_ci		if (!ret)
466862306a36Sopenharmony_ci			dev_info(adapter->pdev_dev, "Successfully enabled "
466962306a36Sopenharmony_ci				 "ppod edram feature\n");
467062306a36Sopenharmony_ci	}
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci	/*
467362306a36Sopenharmony_ci	 * And finally tell the firmware to initialize itself using the
467462306a36Sopenharmony_ci	 * parameters from the Configuration File.
467562306a36Sopenharmony_ci	 */
467662306a36Sopenharmony_ci	ret = t4_fw_initialize(adapter, adapter->mbox);
467762306a36Sopenharmony_ci	if (ret < 0)
467862306a36Sopenharmony_ci		goto bye;
467962306a36Sopenharmony_ci
468062306a36Sopenharmony_ci	/* Emit Firmware Configuration File information and return
468162306a36Sopenharmony_ci	 * successfully.
468262306a36Sopenharmony_ci	 */
468362306a36Sopenharmony_ci	dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\
468462306a36Sopenharmony_ci		 "Configuration File \"%s\", version %#x, computed checksum %#x\n",
468562306a36Sopenharmony_ci		 config_name, finiver, cfcsum);
468662306a36Sopenharmony_ci	return 0;
468762306a36Sopenharmony_ci
468862306a36Sopenharmony_ci	/*
468962306a36Sopenharmony_ci	 * Something bad happened.  Return the error ...  (If the "error"
469062306a36Sopenharmony_ci	 * is that there's no Configuration File on the adapter we don't
469162306a36Sopenharmony_ci	 * want to issue a warning since this is fairly common.)
469262306a36Sopenharmony_ci	 */
469362306a36Sopenharmony_cibye:
469462306a36Sopenharmony_ci	if (config_issued && ret != -ENOENT)
469562306a36Sopenharmony_ci		dev_warn(adapter->pdev_dev, "\"%s\" configuration file error %d\n",
469662306a36Sopenharmony_ci			 config_name, -ret);
469762306a36Sopenharmony_ci	return ret;
469862306a36Sopenharmony_ci}
469962306a36Sopenharmony_ci
470062306a36Sopenharmony_cistatic struct fw_info fw_info_array[] = {
470162306a36Sopenharmony_ci	{
470262306a36Sopenharmony_ci		.chip = CHELSIO_T4,
470362306a36Sopenharmony_ci		.fs_name = FW4_CFNAME,
470462306a36Sopenharmony_ci		.fw_mod_name = FW4_FNAME,
470562306a36Sopenharmony_ci		.fw_hdr = {
470662306a36Sopenharmony_ci			.chip = FW_HDR_CHIP_T4,
470762306a36Sopenharmony_ci			.fw_ver = __cpu_to_be32(FW_VERSION(T4)),
470862306a36Sopenharmony_ci			.intfver_nic = FW_INTFVER(T4, NIC),
470962306a36Sopenharmony_ci			.intfver_vnic = FW_INTFVER(T4, VNIC),
471062306a36Sopenharmony_ci			.intfver_ri = FW_INTFVER(T4, RI),
471162306a36Sopenharmony_ci			.intfver_iscsi = FW_INTFVER(T4, ISCSI),
471262306a36Sopenharmony_ci			.intfver_fcoe = FW_INTFVER(T4, FCOE),
471362306a36Sopenharmony_ci		},
471462306a36Sopenharmony_ci	}, {
471562306a36Sopenharmony_ci		.chip = CHELSIO_T5,
471662306a36Sopenharmony_ci		.fs_name = FW5_CFNAME,
471762306a36Sopenharmony_ci		.fw_mod_name = FW5_FNAME,
471862306a36Sopenharmony_ci		.fw_hdr = {
471962306a36Sopenharmony_ci			.chip = FW_HDR_CHIP_T5,
472062306a36Sopenharmony_ci			.fw_ver = __cpu_to_be32(FW_VERSION(T5)),
472162306a36Sopenharmony_ci			.intfver_nic = FW_INTFVER(T5, NIC),
472262306a36Sopenharmony_ci			.intfver_vnic = FW_INTFVER(T5, VNIC),
472362306a36Sopenharmony_ci			.intfver_ri = FW_INTFVER(T5, RI),
472462306a36Sopenharmony_ci			.intfver_iscsi = FW_INTFVER(T5, ISCSI),
472562306a36Sopenharmony_ci			.intfver_fcoe = FW_INTFVER(T5, FCOE),
472662306a36Sopenharmony_ci		},
472762306a36Sopenharmony_ci	}, {
472862306a36Sopenharmony_ci		.chip = CHELSIO_T6,
472962306a36Sopenharmony_ci		.fs_name = FW6_CFNAME,
473062306a36Sopenharmony_ci		.fw_mod_name = FW6_FNAME,
473162306a36Sopenharmony_ci		.fw_hdr = {
473262306a36Sopenharmony_ci			.chip = FW_HDR_CHIP_T6,
473362306a36Sopenharmony_ci			.fw_ver = __cpu_to_be32(FW_VERSION(T6)),
473462306a36Sopenharmony_ci			.intfver_nic = FW_INTFVER(T6, NIC),
473562306a36Sopenharmony_ci			.intfver_vnic = FW_INTFVER(T6, VNIC),
473662306a36Sopenharmony_ci			.intfver_ofld = FW_INTFVER(T6, OFLD),
473762306a36Sopenharmony_ci			.intfver_ri = FW_INTFVER(T6, RI),
473862306a36Sopenharmony_ci			.intfver_iscsipdu = FW_INTFVER(T6, ISCSIPDU),
473962306a36Sopenharmony_ci			.intfver_iscsi = FW_INTFVER(T6, ISCSI),
474062306a36Sopenharmony_ci			.intfver_fcoepdu = FW_INTFVER(T6, FCOEPDU),
474162306a36Sopenharmony_ci			.intfver_fcoe = FW_INTFVER(T6, FCOE),
474262306a36Sopenharmony_ci		},
474362306a36Sopenharmony_ci	}
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci};
474662306a36Sopenharmony_ci
474762306a36Sopenharmony_cistatic struct fw_info *find_fw_info(int chip)
474862306a36Sopenharmony_ci{
474962306a36Sopenharmony_ci	int i;
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(fw_info_array); i++) {
475262306a36Sopenharmony_ci		if (fw_info_array[i].chip == chip)
475362306a36Sopenharmony_ci			return &fw_info_array[i];
475462306a36Sopenharmony_ci	}
475562306a36Sopenharmony_ci	return NULL;
475662306a36Sopenharmony_ci}
475762306a36Sopenharmony_ci
475862306a36Sopenharmony_ci/*
475962306a36Sopenharmony_ci * Phase 0 of initialization: contact FW, obtain config, perform basic init.
476062306a36Sopenharmony_ci */
476162306a36Sopenharmony_cistatic int adap_init0(struct adapter *adap, int vpd_skip)
476262306a36Sopenharmony_ci{
476362306a36Sopenharmony_ci	struct fw_caps_config_cmd caps_cmd;
476462306a36Sopenharmony_ci	u32 params[7], val[7];
476562306a36Sopenharmony_ci	enum dev_state state;
476662306a36Sopenharmony_ci	u32 v, port_vec;
476762306a36Sopenharmony_ci	int reset = 1;
476862306a36Sopenharmony_ci	int ret;
476962306a36Sopenharmony_ci
477062306a36Sopenharmony_ci	/* Grab Firmware Device Log parameters as early as possible so we have
477162306a36Sopenharmony_ci	 * access to it for debugging, etc.
477262306a36Sopenharmony_ci	 */
477362306a36Sopenharmony_ci	ret = t4_init_devlog_params(adap);
477462306a36Sopenharmony_ci	if (ret < 0)
477562306a36Sopenharmony_ci		return ret;
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_ci	/* Contact FW, advertising Master capability */
477862306a36Sopenharmony_ci	ret = t4_fw_hello(adap, adap->mbox, adap->mbox,
477962306a36Sopenharmony_ci			  is_kdump_kernel() ? MASTER_MUST : MASTER_MAY, &state);
478062306a36Sopenharmony_ci	if (ret < 0) {
478162306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "could not connect to FW, error %d\n",
478262306a36Sopenharmony_ci			ret);
478362306a36Sopenharmony_ci		return ret;
478462306a36Sopenharmony_ci	}
478562306a36Sopenharmony_ci	if (ret == adap->mbox)
478662306a36Sopenharmony_ci		adap->flags |= CXGB4_MASTER_PF;
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_ci	/*
478962306a36Sopenharmony_ci	 * If we're the Master PF Driver and the device is uninitialized,
479062306a36Sopenharmony_ci	 * then let's consider upgrading the firmware ...  (We always want
479162306a36Sopenharmony_ci	 * to check the firmware version number in order to A. get it for
479262306a36Sopenharmony_ci	 * later reporting and B. to warn if the currently loaded firmware
479362306a36Sopenharmony_ci	 * is excessively mismatched relative to the driver.)
479462306a36Sopenharmony_ci	 */
479562306a36Sopenharmony_ci
479662306a36Sopenharmony_ci	t4_get_version_info(adap);
479762306a36Sopenharmony_ci	ret = t4_check_fw_version(adap);
479862306a36Sopenharmony_ci	/* If firmware is too old (not supported by driver) force an update. */
479962306a36Sopenharmony_ci	if (ret)
480062306a36Sopenharmony_ci		state = DEV_STATE_UNINIT;
480162306a36Sopenharmony_ci	if ((adap->flags & CXGB4_MASTER_PF) && state != DEV_STATE_INIT) {
480262306a36Sopenharmony_ci		struct fw_info *fw_info;
480362306a36Sopenharmony_ci		struct fw_hdr *card_fw;
480462306a36Sopenharmony_ci		const struct firmware *fw;
480562306a36Sopenharmony_ci		const u8 *fw_data = NULL;
480662306a36Sopenharmony_ci		unsigned int fw_size = 0;
480762306a36Sopenharmony_ci
480862306a36Sopenharmony_ci		/* This is the firmware whose headers the driver was compiled
480962306a36Sopenharmony_ci		 * against
481062306a36Sopenharmony_ci		 */
481162306a36Sopenharmony_ci		fw_info = find_fw_info(CHELSIO_CHIP_VERSION(adap->params.chip));
481262306a36Sopenharmony_ci		if (fw_info == NULL) {
481362306a36Sopenharmony_ci			dev_err(adap->pdev_dev,
481462306a36Sopenharmony_ci				"unable to get firmware info for chip %d.\n",
481562306a36Sopenharmony_ci				CHELSIO_CHIP_VERSION(adap->params.chip));
481662306a36Sopenharmony_ci			return -EINVAL;
481762306a36Sopenharmony_ci		}
481862306a36Sopenharmony_ci
481962306a36Sopenharmony_ci		/* allocate memory to read the header of the firmware on the
482062306a36Sopenharmony_ci		 * card
482162306a36Sopenharmony_ci		 */
482262306a36Sopenharmony_ci		card_fw = kvzalloc(sizeof(*card_fw), GFP_KERNEL);
482362306a36Sopenharmony_ci		if (!card_fw) {
482462306a36Sopenharmony_ci			ret = -ENOMEM;
482562306a36Sopenharmony_ci			goto bye;
482662306a36Sopenharmony_ci		}
482762306a36Sopenharmony_ci
482862306a36Sopenharmony_ci		/* Get FW from from /lib/firmware/ */
482962306a36Sopenharmony_ci		ret = request_firmware(&fw, fw_info->fw_mod_name,
483062306a36Sopenharmony_ci				       adap->pdev_dev);
483162306a36Sopenharmony_ci		if (ret < 0) {
483262306a36Sopenharmony_ci			dev_err(adap->pdev_dev,
483362306a36Sopenharmony_ci				"unable to load firmware image %s, error %d\n",
483462306a36Sopenharmony_ci				fw_info->fw_mod_name, ret);
483562306a36Sopenharmony_ci		} else {
483662306a36Sopenharmony_ci			fw_data = fw->data;
483762306a36Sopenharmony_ci			fw_size = fw->size;
483862306a36Sopenharmony_ci		}
483962306a36Sopenharmony_ci
484062306a36Sopenharmony_ci		/* upgrade FW logic */
484162306a36Sopenharmony_ci		ret = t4_prep_fw(adap, fw_info, fw_data, fw_size, card_fw,
484262306a36Sopenharmony_ci				 state, &reset);
484362306a36Sopenharmony_ci
484462306a36Sopenharmony_ci		/* Cleaning up */
484562306a36Sopenharmony_ci		release_firmware(fw);
484662306a36Sopenharmony_ci		kvfree(card_fw);
484762306a36Sopenharmony_ci
484862306a36Sopenharmony_ci		if (ret < 0)
484962306a36Sopenharmony_ci			goto bye;
485062306a36Sopenharmony_ci	}
485162306a36Sopenharmony_ci
485262306a36Sopenharmony_ci	/* If the firmware is initialized already, emit a simply note to that
485362306a36Sopenharmony_ci	 * effect. Otherwise, it's time to try initializing the adapter.
485462306a36Sopenharmony_ci	 */
485562306a36Sopenharmony_ci	if (state == DEV_STATE_INIT) {
485662306a36Sopenharmony_ci		ret = adap_config_hma(adap);
485762306a36Sopenharmony_ci		if (ret)
485862306a36Sopenharmony_ci			dev_err(adap->pdev_dev,
485962306a36Sopenharmony_ci				"HMA configuration failed with error %d\n",
486062306a36Sopenharmony_ci				ret);
486162306a36Sopenharmony_ci		dev_info(adap->pdev_dev, "Coming up as %s: "\
486262306a36Sopenharmony_ci			 "Adapter already initialized\n",
486362306a36Sopenharmony_ci			 adap->flags & CXGB4_MASTER_PF ? "MASTER" : "SLAVE");
486462306a36Sopenharmony_ci	} else {
486562306a36Sopenharmony_ci		dev_info(adap->pdev_dev, "Coming up as MASTER: "\
486662306a36Sopenharmony_ci			 "Initializing adapter\n");
486762306a36Sopenharmony_ci
486862306a36Sopenharmony_ci		/* Find out whether we're dealing with a version of the
486962306a36Sopenharmony_ci		 * firmware which has configuration file support.
487062306a36Sopenharmony_ci		 */
487162306a36Sopenharmony_ci		params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
487262306a36Sopenharmony_ci			     FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF));
487362306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
487462306a36Sopenharmony_ci				      params, val);
487562306a36Sopenharmony_ci
487662306a36Sopenharmony_ci		/* If the firmware doesn't support Configuration Files,
487762306a36Sopenharmony_ci		 * return an error.
487862306a36Sopenharmony_ci		 */
487962306a36Sopenharmony_ci		if (ret < 0) {
488062306a36Sopenharmony_ci			dev_err(adap->pdev_dev, "firmware doesn't support "
488162306a36Sopenharmony_ci				"Firmware Configuration Files\n");
488262306a36Sopenharmony_ci			goto bye;
488362306a36Sopenharmony_ci		}
488462306a36Sopenharmony_ci
488562306a36Sopenharmony_ci		/* The firmware provides us with a memory buffer where we can
488662306a36Sopenharmony_ci		 * load a Configuration File from the host if we want to
488762306a36Sopenharmony_ci		 * override the Configuration File in flash.
488862306a36Sopenharmony_ci		 */
488962306a36Sopenharmony_ci		ret = adap_init0_config(adap, reset);
489062306a36Sopenharmony_ci		if (ret == -ENOENT) {
489162306a36Sopenharmony_ci			dev_err(adap->pdev_dev, "no Configuration File "
489262306a36Sopenharmony_ci				"present on adapter.\n");
489362306a36Sopenharmony_ci			goto bye;
489462306a36Sopenharmony_ci		}
489562306a36Sopenharmony_ci		if (ret < 0) {
489662306a36Sopenharmony_ci			dev_err(adap->pdev_dev, "could not initialize "
489762306a36Sopenharmony_ci				"adapter, error %d\n", -ret);
489862306a36Sopenharmony_ci			goto bye;
489962306a36Sopenharmony_ci		}
490062306a36Sopenharmony_ci	}
490162306a36Sopenharmony_ci
490262306a36Sopenharmony_ci	/* Now that we've successfully configured and initialized the adapter
490362306a36Sopenharmony_ci	 * (or found it already initialized), we can ask the Firmware what
490462306a36Sopenharmony_ci	 * resources it has provisioned for us.
490562306a36Sopenharmony_ci	 */
490662306a36Sopenharmony_ci	ret = t4_get_pfres(adap);
490762306a36Sopenharmony_ci	if (ret) {
490862306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
490962306a36Sopenharmony_ci			"Unable to retrieve resource provisioning information\n");
491062306a36Sopenharmony_ci		goto bye;
491162306a36Sopenharmony_ci	}
491262306a36Sopenharmony_ci
491362306a36Sopenharmony_ci	/* Grab VPD parameters.  This should be done after we establish a
491462306a36Sopenharmony_ci	 * connection to the firmware since some of the VPD parameters
491562306a36Sopenharmony_ci	 * (notably the Core Clock frequency) are retrieved via requests to
491662306a36Sopenharmony_ci	 * the firmware.  On the other hand, we need these fairly early on
491762306a36Sopenharmony_ci	 * so we do this right after getting ahold of the firmware.
491862306a36Sopenharmony_ci	 *
491962306a36Sopenharmony_ci	 * We need to do this after initializing the adapter because someone
492062306a36Sopenharmony_ci	 * could have FLASHed a new VPD which won't be read by the firmware
492162306a36Sopenharmony_ci	 * until we do the RESET ...
492262306a36Sopenharmony_ci	 */
492362306a36Sopenharmony_ci	if (!vpd_skip) {
492462306a36Sopenharmony_ci		ret = t4_get_vpd_params(adap, &adap->params.vpd);
492562306a36Sopenharmony_ci		if (ret < 0)
492662306a36Sopenharmony_ci			goto bye;
492762306a36Sopenharmony_ci	}
492862306a36Sopenharmony_ci
492962306a36Sopenharmony_ci	/* Find out what ports are available to us.  Note that we need to do
493062306a36Sopenharmony_ci	 * this before calling adap_init0_no_config() since it needs nports
493162306a36Sopenharmony_ci	 * and portvec ...
493262306a36Sopenharmony_ci	 */
493362306a36Sopenharmony_ci	v =
493462306a36Sopenharmony_ci	    FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
493562306a36Sopenharmony_ci	    FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PORTVEC);
493662306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, &v, &port_vec);
493762306a36Sopenharmony_ci	if (ret < 0)
493862306a36Sopenharmony_ci		goto bye;
493962306a36Sopenharmony_ci
494062306a36Sopenharmony_ci	adap->params.nports = hweight32(port_vec);
494162306a36Sopenharmony_ci	adap->params.portvec = port_vec;
494262306a36Sopenharmony_ci
494362306a36Sopenharmony_ci	/* Give the SGE code a chance to pull in anything that it needs ...
494462306a36Sopenharmony_ci	 * Note that this must be called after we retrieve our VPD parameters
494562306a36Sopenharmony_ci	 * in order to know how to convert core ticks to seconds, etc.
494662306a36Sopenharmony_ci	 */
494762306a36Sopenharmony_ci	ret = t4_sge_init(adap);
494862306a36Sopenharmony_ci	if (ret < 0)
494962306a36Sopenharmony_ci		goto bye;
495062306a36Sopenharmony_ci
495162306a36Sopenharmony_ci	/* Grab the SGE Doorbell Queue Timer values.  If successful, that
495262306a36Sopenharmony_ci	 * indicates that the Firmware and Hardware support this.
495362306a36Sopenharmony_ci	 */
495462306a36Sopenharmony_ci	params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
495562306a36Sopenharmony_ci		    FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK));
495662306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
495762306a36Sopenharmony_ci			      1, params, val);
495862306a36Sopenharmony_ci
495962306a36Sopenharmony_ci	if (!ret) {
496062306a36Sopenharmony_ci		adap->sge.dbqtimer_tick = val[0];
496162306a36Sopenharmony_ci		ret = t4_read_sge_dbqtimers(adap,
496262306a36Sopenharmony_ci					    ARRAY_SIZE(adap->sge.dbqtimer_val),
496362306a36Sopenharmony_ci					    adap->sge.dbqtimer_val);
496462306a36Sopenharmony_ci	}
496562306a36Sopenharmony_ci
496662306a36Sopenharmony_ci	if (!ret)
496762306a36Sopenharmony_ci		adap->flags |= CXGB4_SGE_DBQ_TIMER;
496862306a36Sopenharmony_ci
496962306a36Sopenharmony_ci	if (is_bypass_device(adap->pdev->device))
497062306a36Sopenharmony_ci		adap->params.bypass = 1;
497162306a36Sopenharmony_ci
497262306a36Sopenharmony_ci	/*
497362306a36Sopenharmony_ci	 * Grab some of our basic fundamental operating parameters.
497462306a36Sopenharmony_ci	 */
497562306a36Sopenharmony_ci	params[0] = FW_PARAM_PFVF(EQ_START);
497662306a36Sopenharmony_ci	params[1] = FW_PARAM_PFVF(L2T_START);
497762306a36Sopenharmony_ci	params[2] = FW_PARAM_PFVF(L2T_END);
497862306a36Sopenharmony_ci	params[3] = FW_PARAM_PFVF(FILTER_START);
497962306a36Sopenharmony_ci	params[4] = FW_PARAM_PFVF(FILTER_END);
498062306a36Sopenharmony_ci	params[5] = FW_PARAM_PFVF(IQFLINT_START);
498162306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, params, val);
498262306a36Sopenharmony_ci	if (ret < 0)
498362306a36Sopenharmony_ci		goto bye;
498462306a36Sopenharmony_ci	adap->sge.egr_start = val[0];
498562306a36Sopenharmony_ci	adap->l2t_start = val[1];
498662306a36Sopenharmony_ci	adap->l2t_end = val[2];
498762306a36Sopenharmony_ci	adap->tids.ftid_base = val[3];
498862306a36Sopenharmony_ci	adap->tids.nftids = val[4] - val[3] + 1;
498962306a36Sopenharmony_ci	adap->sge.ingr_start = val[5];
499062306a36Sopenharmony_ci
499162306a36Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) {
499262306a36Sopenharmony_ci		params[0] = FW_PARAM_PFVF(HPFILTER_START);
499362306a36Sopenharmony_ci		params[1] = FW_PARAM_PFVF(HPFILTER_END);
499462306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
499562306a36Sopenharmony_ci				      params, val);
499662306a36Sopenharmony_ci		if (ret < 0)
499762306a36Sopenharmony_ci			goto bye;
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci		adap->tids.hpftid_base = val[0];
500062306a36Sopenharmony_ci		adap->tids.nhpftids = val[1] - val[0] + 1;
500162306a36Sopenharmony_ci
500262306a36Sopenharmony_ci		/* Read the raw mps entries. In T6, the last 2 tcam entries
500362306a36Sopenharmony_ci		 * are reserved for raw mac addresses (rawf = 2, one per port).
500462306a36Sopenharmony_ci		 */
500562306a36Sopenharmony_ci		params[0] = FW_PARAM_PFVF(RAWF_START);
500662306a36Sopenharmony_ci		params[1] = FW_PARAM_PFVF(RAWF_END);
500762306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
500862306a36Sopenharmony_ci				      params, val);
500962306a36Sopenharmony_ci		if (ret == 0) {
501062306a36Sopenharmony_ci			adap->rawf_start = val[0];
501162306a36Sopenharmony_ci			adap->rawf_cnt = val[1] - val[0] + 1;
501262306a36Sopenharmony_ci		}
501362306a36Sopenharmony_ci
501462306a36Sopenharmony_ci		adap->tids.tid_base =
501562306a36Sopenharmony_ci			t4_read_reg(adap, LE_DB_ACTIVE_TABLE_START_INDEX_A);
501662306a36Sopenharmony_ci	}
501762306a36Sopenharmony_ci
501862306a36Sopenharmony_ci	/* qids (ingress/egress) returned from firmware can be anywhere
501962306a36Sopenharmony_ci	 * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END.
502062306a36Sopenharmony_ci	 * Hence driver needs to allocate memory for this range to
502162306a36Sopenharmony_ci	 * store the queue info. Get the highest IQFLINT/EQ index returned
502262306a36Sopenharmony_ci	 * in FW_EQ_*_CMD.alloc command.
502362306a36Sopenharmony_ci	 */
502462306a36Sopenharmony_ci	params[0] = FW_PARAM_PFVF(EQ_END);
502562306a36Sopenharmony_ci	params[1] = FW_PARAM_PFVF(IQFLINT_END);
502662306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val);
502762306a36Sopenharmony_ci	if (ret < 0)
502862306a36Sopenharmony_ci		goto bye;
502962306a36Sopenharmony_ci	adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1;
503062306a36Sopenharmony_ci	adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1;
503162306a36Sopenharmony_ci
503262306a36Sopenharmony_ci	adap->sge.egr_map = kcalloc(adap->sge.egr_sz,
503362306a36Sopenharmony_ci				    sizeof(*adap->sge.egr_map), GFP_KERNEL);
503462306a36Sopenharmony_ci	if (!adap->sge.egr_map) {
503562306a36Sopenharmony_ci		ret = -ENOMEM;
503662306a36Sopenharmony_ci		goto bye;
503762306a36Sopenharmony_ci	}
503862306a36Sopenharmony_ci
503962306a36Sopenharmony_ci	adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz,
504062306a36Sopenharmony_ci				     sizeof(*adap->sge.ingr_map), GFP_KERNEL);
504162306a36Sopenharmony_ci	if (!adap->sge.ingr_map) {
504262306a36Sopenharmony_ci		ret = -ENOMEM;
504362306a36Sopenharmony_ci		goto bye;
504462306a36Sopenharmony_ci	}
504562306a36Sopenharmony_ci
504662306a36Sopenharmony_ci	/* Allocate the memory for the vaious egress queue bitmaps
504762306a36Sopenharmony_ci	 * ie starving_fl, txq_maperr and blocked_fl.
504862306a36Sopenharmony_ci	 */
504962306a36Sopenharmony_ci	adap->sge.starving_fl = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL);
505062306a36Sopenharmony_ci	if (!adap->sge.starving_fl) {
505162306a36Sopenharmony_ci		ret = -ENOMEM;
505262306a36Sopenharmony_ci		goto bye;
505362306a36Sopenharmony_ci	}
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci	adap->sge.txq_maperr = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL);
505662306a36Sopenharmony_ci	if (!adap->sge.txq_maperr) {
505762306a36Sopenharmony_ci		ret = -ENOMEM;
505862306a36Sopenharmony_ci		goto bye;
505962306a36Sopenharmony_ci	}
506062306a36Sopenharmony_ci
506162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
506262306a36Sopenharmony_ci	adap->sge.blocked_fl = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL);
506362306a36Sopenharmony_ci	if (!adap->sge.blocked_fl) {
506462306a36Sopenharmony_ci		ret = -ENOMEM;
506562306a36Sopenharmony_ci		goto bye;
506662306a36Sopenharmony_ci	}
506762306a36Sopenharmony_ci#endif
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_ci	params[0] = FW_PARAM_PFVF(CLIP_START);
507062306a36Sopenharmony_ci	params[1] = FW_PARAM_PFVF(CLIP_END);
507162306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val);
507262306a36Sopenharmony_ci	if (ret < 0)
507362306a36Sopenharmony_ci		goto bye;
507462306a36Sopenharmony_ci	adap->clipt_start = val[0];
507562306a36Sopenharmony_ci	adap->clipt_end = val[1];
507662306a36Sopenharmony_ci
507762306a36Sopenharmony_ci	/* Get the supported number of traffic classes */
507862306a36Sopenharmony_ci	params[0] = FW_PARAM_DEV(NUM_TM_CLASS);
507962306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, val);
508062306a36Sopenharmony_ci	if (ret < 0) {
508162306a36Sopenharmony_ci		/* We couldn't retrieve the number of Traffic Classes
508262306a36Sopenharmony_ci		 * supported by the hardware/firmware. So we hard
508362306a36Sopenharmony_ci		 * code it here.
508462306a36Sopenharmony_ci		 */
508562306a36Sopenharmony_ci		adap->params.nsched_cls = is_t4(adap->params.chip) ? 15 : 16;
508662306a36Sopenharmony_ci	} else {
508762306a36Sopenharmony_ci		adap->params.nsched_cls = val[0];
508862306a36Sopenharmony_ci	}
508962306a36Sopenharmony_ci
509062306a36Sopenharmony_ci	/* query params related to active filter region */
509162306a36Sopenharmony_ci	params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START);
509262306a36Sopenharmony_ci	params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END);
509362306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val);
509462306a36Sopenharmony_ci	/* If Active filter size is set we enable establishing
509562306a36Sopenharmony_ci	 * offload connection through firmware work request
509662306a36Sopenharmony_ci	 */
509762306a36Sopenharmony_ci	if ((val[0] != val[1]) && (ret >= 0)) {
509862306a36Sopenharmony_ci		adap->flags |= CXGB4_FW_OFLD_CONN;
509962306a36Sopenharmony_ci		adap->tids.aftid_base = val[0];
510062306a36Sopenharmony_ci		adap->tids.aftid_end = val[1];
510162306a36Sopenharmony_ci	}
510262306a36Sopenharmony_ci
510362306a36Sopenharmony_ci	/* If we're running on newer firmware, let it know that we're
510462306a36Sopenharmony_ci	 * prepared to deal with encapsulated CPL messages.  Older
510562306a36Sopenharmony_ci	 * firmware won't understand this and we'll just get
510662306a36Sopenharmony_ci	 * unencapsulated messages ...
510762306a36Sopenharmony_ci	 */
510862306a36Sopenharmony_ci	params[0] = FW_PARAM_PFVF(CPLFW4MSG_ENCAP);
510962306a36Sopenharmony_ci	val[0] = 1;
511062306a36Sopenharmony_ci	(void)t4_set_params(adap, adap->mbox, adap->pf, 0, 1, params, val);
511162306a36Sopenharmony_ci
511262306a36Sopenharmony_ci	/*
511362306a36Sopenharmony_ci	 * Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL
511462306a36Sopenharmony_ci	 * capability.  Earlier versions of the firmware didn't have the
511562306a36Sopenharmony_ci	 * ULPTX_MEMWRITE_DSGL so we'll interpret a query failure as no
511662306a36Sopenharmony_ci	 * permission to use ULPTX MEMWRITE DSGL.
511762306a36Sopenharmony_ci	 */
511862306a36Sopenharmony_ci	if (is_t4(adap->params.chip)) {
511962306a36Sopenharmony_ci		adap->params.ulptx_memwrite_dsgl = false;
512062306a36Sopenharmony_ci	} else {
512162306a36Sopenharmony_ci		params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL);
512262306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
512362306a36Sopenharmony_ci				      1, params, val);
512462306a36Sopenharmony_ci		adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0);
512562306a36Sopenharmony_ci	}
512662306a36Sopenharmony_ci
512762306a36Sopenharmony_ci	/* See if FW supports FW_RI_FR_NSMR_TPTE_WR work request */
512862306a36Sopenharmony_ci	params[0] = FW_PARAM_DEV(RI_FR_NSMR_TPTE_WR);
512962306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
513062306a36Sopenharmony_ci			      1, params, val);
513162306a36Sopenharmony_ci	adap->params.fr_nsmr_tpte_wr_support = (ret == 0 && val[0] != 0);
513262306a36Sopenharmony_ci
513362306a36Sopenharmony_ci	/* See if FW supports FW_FILTER2 work request */
513462306a36Sopenharmony_ci	if (is_t4(adap->params.chip)) {
513562306a36Sopenharmony_ci		adap->params.filter2_wr_support = false;
513662306a36Sopenharmony_ci	} else {
513762306a36Sopenharmony_ci		params[0] = FW_PARAM_DEV(FILTER2_WR);
513862306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
513962306a36Sopenharmony_ci				      1, params, val);
514062306a36Sopenharmony_ci		adap->params.filter2_wr_support = (ret == 0 && val[0] != 0);
514162306a36Sopenharmony_ci	}
514262306a36Sopenharmony_ci
514362306a36Sopenharmony_ci	/* Check if FW supports returning vin and smt index.
514462306a36Sopenharmony_ci	 * If this is not supported, driver will interpret
514562306a36Sopenharmony_ci	 * these values from viid.
514662306a36Sopenharmony_ci	 */
514762306a36Sopenharmony_ci	params[0] = FW_PARAM_DEV(OPAQUE_VIID_SMT_EXTN);
514862306a36Sopenharmony_ci	ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
514962306a36Sopenharmony_ci			      1, params, val);
515062306a36Sopenharmony_ci	adap->params.viid_smt_extn_support = (ret == 0 && val[0] != 0);
515162306a36Sopenharmony_ci
515262306a36Sopenharmony_ci	/*
515362306a36Sopenharmony_ci	 * Get device capabilities so we can determine what resources we need
515462306a36Sopenharmony_ci	 * to manage.
515562306a36Sopenharmony_ci	 */
515662306a36Sopenharmony_ci	memset(&caps_cmd, 0, sizeof(caps_cmd));
515762306a36Sopenharmony_ci	caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
515862306a36Sopenharmony_ci				     FW_CMD_REQUEST_F | FW_CMD_READ_F);
515962306a36Sopenharmony_ci	caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
516062306a36Sopenharmony_ci	ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
516162306a36Sopenharmony_ci			 &caps_cmd);
516262306a36Sopenharmony_ci	if (ret < 0)
516362306a36Sopenharmony_ci		goto bye;
516462306a36Sopenharmony_ci
516562306a36Sopenharmony_ci	/* hash filter has some mandatory register settings to be tested and for
516662306a36Sopenharmony_ci	 * that it needs to test whether offload is enabled or not, hence
516762306a36Sopenharmony_ci	 * checking and setting it here.
516862306a36Sopenharmony_ci	 */
516962306a36Sopenharmony_ci	if (caps_cmd.ofldcaps)
517062306a36Sopenharmony_ci		adap->params.offload = 1;
517162306a36Sopenharmony_ci
517262306a36Sopenharmony_ci	if (caps_cmd.ofldcaps ||
517362306a36Sopenharmony_ci	    (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) ||
517462306a36Sopenharmony_ci	    (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_ETHOFLD))) {
517562306a36Sopenharmony_ci		/* query offload-related parameters */
517662306a36Sopenharmony_ci		params[0] = FW_PARAM_DEV(NTID);
517762306a36Sopenharmony_ci		params[1] = FW_PARAM_PFVF(SERVER_START);
517862306a36Sopenharmony_ci		params[2] = FW_PARAM_PFVF(SERVER_END);
517962306a36Sopenharmony_ci		params[3] = FW_PARAM_PFVF(TDDP_START);
518062306a36Sopenharmony_ci		params[4] = FW_PARAM_PFVF(TDDP_END);
518162306a36Sopenharmony_ci		params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
518262306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6,
518362306a36Sopenharmony_ci				      params, val);
518462306a36Sopenharmony_ci		if (ret < 0)
518562306a36Sopenharmony_ci			goto bye;
518662306a36Sopenharmony_ci		adap->tids.ntids = val[0];
518762306a36Sopenharmony_ci		adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS);
518862306a36Sopenharmony_ci		adap->tids.stid_base = val[1];
518962306a36Sopenharmony_ci		adap->tids.nstids = val[2] - val[1] + 1;
519062306a36Sopenharmony_ci		/*
519162306a36Sopenharmony_ci		 * Setup server filter region. Divide the available filter
519262306a36Sopenharmony_ci		 * region into two parts. Regular filters get 1/3rd and server
519362306a36Sopenharmony_ci		 * filters get 2/3rd part. This is only enabled if workarond
519462306a36Sopenharmony_ci		 * path is enabled.
519562306a36Sopenharmony_ci		 * 1. For regular filters.
519662306a36Sopenharmony_ci		 * 2. Server filter: This are special filters which are used
519762306a36Sopenharmony_ci		 * to redirect SYN packets to offload queue.
519862306a36Sopenharmony_ci		 */
519962306a36Sopenharmony_ci		if (adap->flags & CXGB4_FW_OFLD_CONN && !is_bypass(adap)) {
520062306a36Sopenharmony_ci			adap->tids.sftid_base = adap->tids.ftid_base +
520162306a36Sopenharmony_ci					DIV_ROUND_UP(adap->tids.nftids, 3);
520262306a36Sopenharmony_ci			adap->tids.nsftids = adap->tids.nftids -
520362306a36Sopenharmony_ci					 DIV_ROUND_UP(adap->tids.nftids, 3);
520462306a36Sopenharmony_ci			adap->tids.nftids = adap->tids.sftid_base -
520562306a36Sopenharmony_ci						adap->tids.ftid_base;
520662306a36Sopenharmony_ci		}
520762306a36Sopenharmony_ci		adap->vres.ddp.start = val[3];
520862306a36Sopenharmony_ci		adap->vres.ddp.size = val[4] - val[3] + 1;
520962306a36Sopenharmony_ci		adap->params.ofldq_wr_cred = val[5];
521062306a36Sopenharmony_ci
521162306a36Sopenharmony_ci		if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) {
521262306a36Sopenharmony_ci			init_hash_filter(adap);
521362306a36Sopenharmony_ci		} else {
521462306a36Sopenharmony_ci			adap->num_ofld_uld += 1;
521562306a36Sopenharmony_ci		}
521662306a36Sopenharmony_ci
521762306a36Sopenharmony_ci		if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_ETHOFLD)) {
521862306a36Sopenharmony_ci			params[0] = FW_PARAM_PFVF(ETHOFLD_START);
521962306a36Sopenharmony_ci			params[1] = FW_PARAM_PFVF(ETHOFLD_END);
522062306a36Sopenharmony_ci			ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
522162306a36Sopenharmony_ci					      params, val);
522262306a36Sopenharmony_ci			if (!ret) {
522362306a36Sopenharmony_ci				adap->tids.eotid_base = val[0];
522462306a36Sopenharmony_ci				adap->tids.neotids = min_t(u32, MAX_ATIDS,
522562306a36Sopenharmony_ci							   val[1] - val[0] + 1);
522662306a36Sopenharmony_ci				adap->params.ethofld = 1;
522762306a36Sopenharmony_ci			}
522862306a36Sopenharmony_ci		}
522962306a36Sopenharmony_ci	}
523062306a36Sopenharmony_ci	if (caps_cmd.rdmacaps) {
523162306a36Sopenharmony_ci		params[0] = FW_PARAM_PFVF(STAG_START);
523262306a36Sopenharmony_ci		params[1] = FW_PARAM_PFVF(STAG_END);
523362306a36Sopenharmony_ci		params[2] = FW_PARAM_PFVF(RQ_START);
523462306a36Sopenharmony_ci		params[3] = FW_PARAM_PFVF(RQ_END);
523562306a36Sopenharmony_ci		params[4] = FW_PARAM_PFVF(PBL_START);
523662306a36Sopenharmony_ci		params[5] = FW_PARAM_PFVF(PBL_END);
523762306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6,
523862306a36Sopenharmony_ci				      params, val);
523962306a36Sopenharmony_ci		if (ret < 0)
524062306a36Sopenharmony_ci			goto bye;
524162306a36Sopenharmony_ci		adap->vres.stag.start = val[0];
524262306a36Sopenharmony_ci		adap->vres.stag.size = val[1] - val[0] + 1;
524362306a36Sopenharmony_ci		adap->vres.rq.start = val[2];
524462306a36Sopenharmony_ci		adap->vres.rq.size = val[3] - val[2] + 1;
524562306a36Sopenharmony_ci		adap->vres.pbl.start = val[4];
524662306a36Sopenharmony_ci		adap->vres.pbl.size = val[5] - val[4] + 1;
524762306a36Sopenharmony_ci
524862306a36Sopenharmony_ci		params[0] = FW_PARAM_PFVF(SRQ_START);
524962306a36Sopenharmony_ci		params[1] = FW_PARAM_PFVF(SRQ_END);
525062306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
525162306a36Sopenharmony_ci				      params, val);
525262306a36Sopenharmony_ci		if (!ret) {
525362306a36Sopenharmony_ci			adap->vres.srq.start = val[0];
525462306a36Sopenharmony_ci			adap->vres.srq.size = val[1] - val[0] + 1;
525562306a36Sopenharmony_ci		}
525662306a36Sopenharmony_ci		if (adap->vres.srq.size) {
525762306a36Sopenharmony_ci			adap->srq = t4_init_srq(adap->vres.srq.size);
525862306a36Sopenharmony_ci			if (!adap->srq)
525962306a36Sopenharmony_ci				dev_warn(&adap->pdev->dev, "could not allocate SRQ, continuing\n");
526062306a36Sopenharmony_ci		}
526162306a36Sopenharmony_ci
526262306a36Sopenharmony_ci		params[0] = FW_PARAM_PFVF(SQRQ_START);
526362306a36Sopenharmony_ci		params[1] = FW_PARAM_PFVF(SQRQ_END);
526462306a36Sopenharmony_ci		params[2] = FW_PARAM_PFVF(CQ_START);
526562306a36Sopenharmony_ci		params[3] = FW_PARAM_PFVF(CQ_END);
526662306a36Sopenharmony_ci		params[4] = FW_PARAM_PFVF(OCQ_START);
526762306a36Sopenharmony_ci		params[5] = FW_PARAM_PFVF(OCQ_END);
526862306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, params,
526962306a36Sopenharmony_ci				      val);
527062306a36Sopenharmony_ci		if (ret < 0)
527162306a36Sopenharmony_ci			goto bye;
527262306a36Sopenharmony_ci		adap->vres.qp.start = val[0];
527362306a36Sopenharmony_ci		adap->vres.qp.size = val[1] - val[0] + 1;
527462306a36Sopenharmony_ci		adap->vres.cq.start = val[2];
527562306a36Sopenharmony_ci		adap->vres.cq.size = val[3] - val[2] + 1;
527662306a36Sopenharmony_ci		adap->vres.ocq.start = val[4];
527762306a36Sopenharmony_ci		adap->vres.ocq.size = val[5] - val[4] + 1;
527862306a36Sopenharmony_ci
527962306a36Sopenharmony_ci		params[0] = FW_PARAM_DEV(MAXORDIRD_QP);
528062306a36Sopenharmony_ci		params[1] = FW_PARAM_DEV(MAXIRD_ADAPTER);
528162306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params,
528262306a36Sopenharmony_ci				      val);
528362306a36Sopenharmony_ci		if (ret < 0) {
528462306a36Sopenharmony_ci			adap->params.max_ordird_qp = 8;
528562306a36Sopenharmony_ci			adap->params.max_ird_adapter = 32 * adap->tids.ntids;
528662306a36Sopenharmony_ci			ret = 0;
528762306a36Sopenharmony_ci		} else {
528862306a36Sopenharmony_ci			adap->params.max_ordird_qp = val[0];
528962306a36Sopenharmony_ci			adap->params.max_ird_adapter = val[1];
529062306a36Sopenharmony_ci		}
529162306a36Sopenharmony_ci		dev_info(adap->pdev_dev,
529262306a36Sopenharmony_ci			 "max_ordird_qp %d max_ird_adapter %d\n",
529362306a36Sopenharmony_ci			 adap->params.max_ordird_qp,
529462306a36Sopenharmony_ci			 adap->params.max_ird_adapter);
529562306a36Sopenharmony_ci
529662306a36Sopenharmony_ci		/* Enable write_with_immediate if FW supports it */
529762306a36Sopenharmony_ci		params[0] = FW_PARAM_DEV(RDMA_WRITE_WITH_IMM);
529862306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params,
529962306a36Sopenharmony_ci				      val);
530062306a36Sopenharmony_ci		adap->params.write_w_imm_support = (ret == 0 && val[0] != 0);
530162306a36Sopenharmony_ci
530262306a36Sopenharmony_ci		/* Enable write_cmpl if FW supports it */
530362306a36Sopenharmony_ci		params[0] = FW_PARAM_DEV(RI_WRITE_CMPL_WR);
530462306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params,
530562306a36Sopenharmony_ci				      val);
530662306a36Sopenharmony_ci		adap->params.write_cmpl_support = (ret == 0 && val[0] != 0);
530762306a36Sopenharmony_ci		adap->num_ofld_uld += 2;
530862306a36Sopenharmony_ci	}
530962306a36Sopenharmony_ci	if (caps_cmd.iscsicaps) {
531062306a36Sopenharmony_ci		params[0] = FW_PARAM_PFVF(ISCSI_START);
531162306a36Sopenharmony_ci		params[1] = FW_PARAM_PFVF(ISCSI_END);
531262306a36Sopenharmony_ci		ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
531362306a36Sopenharmony_ci				      params, val);
531462306a36Sopenharmony_ci		if (ret < 0)
531562306a36Sopenharmony_ci			goto bye;
531662306a36Sopenharmony_ci		adap->vres.iscsi.start = val[0];
531762306a36Sopenharmony_ci		adap->vres.iscsi.size = val[1] - val[0] + 1;
531862306a36Sopenharmony_ci		if (is_t6(adap->params.chip)) {
531962306a36Sopenharmony_ci			params[0] = FW_PARAM_PFVF(PPOD_EDRAM_START);
532062306a36Sopenharmony_ci			params[1] = FW_PARAM_PFVF(PPOD_EDRAM_END);
532162306a36Sopenharmony_ci			ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
532262306a36Sopenharmony_ci					      params, val);
532362306a36Sopenharmony_ci			if (!ret) {
532462306a36Sopenharmony_ci				adap->vres.ppod_edram.start = val[0];
532562306a36Sopenharmony_ci				adap->vres.ppod_edram.size =
532662306a36Sopenharmony_ci					val[1] - val[0] + 1;
532762306a36Sopenharmony_ci
532862306a36Sopenharmony_ci				dev_info(adap->pdev_dev,
532962306a36Sopenharmony_ci					 "ppod edram start 0x%x end 0x%x size 0x%x\n",
533062306a36Sopenharmony_ci					 val[0], val[1],
533162306a36Sopenharmony_ci					 adap->vres.ppod_edram.size);
533262306a36Sopenharmony_ci			}
533362306a36Sopenharmony_ci		}
533462306a36Sopenharmony_ci		/* LIO target and cxgb4i initiaitor */
533562306a36Sopenharmony_ci		adap->num_ofld_uld += 2;
533662306a36Sopenharmony_ci	}
533762306a36Sopenharmony_ci	if (caps_cmd.cryptocaps) {
533862306a36Sopenharmony_ci		if (ntohs(caps_cmd.cryptocaps) &
533962306a36Sopenharmony_ci		    FW_CAPS_CONFIG_CRYPTO_LOOKASIDE) {
534062306a36Sopenharmony_ci			params[0] = FW_PARAM_PFVF(NCRYPTO_LOOKASIDE);
534162306a36Sopenharmony_ci			ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
534262306a36Sopenharmony_ci					      2, params, val);
534362306a36Sopenharmony_ci			if (ret < 0) {
534462306a36Sopenharmony_ci				if (ret != -EINVAL)
534562306a36Sopenharmony_ci					goto bye;
534662306a36Sopenharmony_ci			} else {
534762306a36Sopenharmony_ci				adap->vres.ncrypto_fc = val[0];
534862306a36Sopenharmony_ci			}
534962306a36Sopenharmony_ci			adap->num_ofld_uld += 1;
535062306a36Sopenharmony_ci		}
535162306a36Sopenharmony_ci		if (ntohs(caps_cmd.cryptocaps) &
535262306a36Sopenharmony_ci		    FW_CAPS_CONFIG_TLS_INLINE) {
535362306a36Sopenharmony_ci			params[0] = FW_PARAM_PFVF(TLS_START);
535462306a36Sopenharmony_ci			params[1] = FW_PARAM_PFVF(TLS_END);
535562306a36Sopenharmony_ci			ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
535662306a36Sopenharmony_ci					      2, params, val);
535762306a36Sopenharmony_ci			if (ret < 0)
535862306a36Sopenharmony_ci				goto bye;
535962306a36Sopenharmony_ci			adap->vres.key.start = val[0];
536062306a36Sopenharmony_ci			adap->vres.key.size = val[1] - val[0] + 1;
536162306a36Sopenharmony_ci			adap->num_uld += 1;
536262306a36Sopenharmony_ci		}
536362306a36Sopenharmony_ci		adap->params.crypto = ntohs(caps_cmd.cryptocaps);
536462306a36Sopenharmony_ci	}
536562306a36Sopenharmony_ci
536662306a36Sopenharmony_ci	/* The MTU/MSS Table is initialized by now, so load their values.  If
536762306a36Sopenharmony_ci	 * we're initializing the adapter, then we'll make any modifications
536862306a36Sopenharmony_ci	 * we want to the MTU/MSS Table and also initialize the congestion
536962306a36Sopenharmony_ci	 * parameters.
537062306a36Sopenharmony_ci	 */
537162306a36Sopenharmony_ci	t4_read_mtu_tbl(adap, adap->params.mtus, NULL);
537262306a36Sopenharmony_ci	if (state != DEV_STATE_INIT) {
537362306a36Sopenharmony_ci		int i;
537462306a36Sopenharmony_ci
537562306a36Sopenharmony_ci		/* The default MTU Table contains values 1492 and 1500.
537662306a36Sopenharmony_ci		 * However, for TCP, it's better to have two values which are
537762306a36Sopenharmony_ci		 * a multiple of 8 +/- 4 bytes apart near this popular MTU.
537862306a36Sopenharmony_ci		 * This allows us to have a TCP Data Payload which is a
537962306a36Sopenharmony_ci		 * multiple of 8 regardless of what combination of TCP Options
538062306a36Sopenharmony_ci		 * are in use (always a multiple of 4 bytes) which is
538162306a36Sopenharmony_ci		 * important for performance reasons.  For instance, if no
538262306a36Sopenharmony_ci		 * options are in use, then we have a 20-byte IP header and a
538362306a36Sopenharmony_ci		 * 20-byte TCP header.  In this case, a 1500-byte MSS would
538462306a36Sopenharmony_ci		 * result in a TCP Data Payload of 1500 - 40 == 1460 bytes
538562306a36Sopenharmony_ci		 * which is not a multiple of 8.  So using an MSS of 1488 in
538662306a36Sopenharmony_ci		 * this case results in a TCP Data Payload of 1448 bytes which
538762306a36Sopenharmony_ci		 * is a multiple of 8.  On the other hand, if 12-byte TCP Time
538862306a36Sopenharmony_ci		 * Stamps have been negotiated, then an MTU of 1500 bytes
538962306a36Sopenharmony_ci		 * results in a TCP Data Payload of 1448 bytes which, as
539062306a36Sopenharmony_ci		 * above, is a multiple of 8 bytes ...
539162306a36Sopenharmony_ci		 */
539262306a36Sopenharmony_ci		for (i = 0; i < NMTUS; i++)
539362306a36Sopenharmony_ci			if (adap->params.mtus[i] == 1492) {
539462306a36Sopenharmony_ci				adap->params.mtus[i] = 1488;
539562306a36Sopenharmony_ci				break;
539662306a36Sopenharmony_ci			}
539762306a36Sopenharmony_ci
539862306a36Sopenharmony_ci		t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
539962306a36Sopenharmony_ci			     adap->params.b_wnd);
540062306a36Sopenharmony_ci	}
540162306a36Sopenharmony_ci	t4_init_sge_params(adap);
540262306a36Sopenharmony_ci	adap->flags |= CXGB4_FW_OK;
540362306a36Sopenharmony_ci	t4_init_tp_params(adap, true);
540462306a36Sopenharmony_ci	return 0;
540562306a36Sopenharmony_ci
540662306a36Sopenharmony_ci	/*
540762306a36Sopenharmony_ci	 * Something bad happened.  If a command timed out or failed with EIO
540862306a36Sopenharmony_ci	 * FW does not operate within its spec or something catastrophic
540962306a36Sopenharmony_ci	 * happened to HW/FW, stop issuing commands.
541062306a36Sopenharmony_ci	 */
541162306a36Sopenharmony_cibye:
541262306a36Sopenharmony_ci	adap_free_hma_mem(adap);
541362306a36Sopenharmony_ci	kfree(adap->sge.egr_map);
541462306a36Sopenharmony_ci	kfree(adap->sge.ingr_map);
541562306a36Sopenharmony_ci	bitmap_free(adap->sge.starving_fl);
541662306a36Sopenharmony_ci	bitmap_free(adap->sge.txq_maperr);
541762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
541862306a36Sopenharmony_ci	bitmap_free(adap->sge.blocked_fl);
541962306a36Sopenharmony_ci#endif
542062306a36Sopenharmony_ci	if (ret != -ETIMEDOUT && ret != -EIO)
542162306a36Sopenharmony_ci		t4_fw_bye(adap, adap->mbox);
542262306a36Sopenharmony_ci	return ret;
542362306a36Sopenharmony_ci}
542462306a36Sopenharmony_ci
542562306a36Sopenharmony_ci/* EEH callbacks */
542662306a36Sopenharmony_ci
542762306a36Sopenharmony_cistatic pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
542862306a36Sopenharmony_ci					 pci_channel_state_t state)
542962306a36Sopenharmony_ci{
543062306a36Sopenharmony_ci	int i;
543162306a36Sopenharmony_ci	struct adapter *adap = pci_get_drvdata(pdev);
543262306a36Sopenharmony_ci
543362306a36Sopenharmony_ci	if (!adap)
543462306a36Sopenharmony_ci		goto out;
543562306a36Sopenharmony_ci
543662306a36Sopenharmony_ci	rtnl_lock();
543762306a36Sopenharmony_ci	adap->flags &= ~CXGB4_FW_OK;
543862306a36Sopenharmony_ci	notify_ulds(adap, CXGB4_STATE_START_RECOVERY);
543962306a36Sopenharmony_ci	spin_lock(&adap->stats_lock);
544062306a36Sopenharmony_ci	for_each_port(adap, i) {
544162306a36Sopenharmony_ci		struct net_device *dev = adap->port[i];
544262306a36Sopenharmony_ci		if (dev) {
544362306a36Sopenharmony_ci			netif_device_detach(dev);
544462306a36Sopenharmony_ci			netif_carrier_off(dev);
544562306a36Sopenharmony_ci		}
544662306a36Sopenharmony_ci	}
544762306a36Sopenharmony_ci	spin_unlock(&adap->stats_lock);
544862306a36Sopenharmony_ci	disable_interrupts(adap);
544962306a36Sopenharmony_ci	if (adap->flags & CXGB4_FULL_INIT_DONE)
545062306a36Sopenharmony_ci		cxgb_down(adap);
545162306a36Sopenharmony_ci	rtnl_unlock();
545262306a36Sopenharmony_ci	if ((adap->flags & CXGB4_DEV_ENABLED)) {
545362306a36Sopenharmony_ci		pci_disable_device(pdev);
545462306a36Sopenharmony_ci		adap->flags &= ~CXGB4_DEV_ENABLED;
545562306a36Sopenharmony_ci	}
545662306a36Sopenharmony_ciout:	return state == pci_channel_io_perm_failure ?
545762306a36Sopenharmony_ci		PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
545862306a36Sopenharmony_ci}
545962306a36Sopenharmony_ci
546062306a36Sopenharmony_cistatic pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
546162306a36Sopenharmony_ci{
546262306a36Sopenharmony_ci	int i, ret;
546362306a36Sopenharmony_ci	struct fw_caps_config_cmd c;
546462306a36Sopenharmony_ci	struct adapter *adap = pci_get_drvdata(pdev);
546562306a36Sopenharmony_ci
546662306a36Sopenharmony_ci	if (!adap) {
546762306a36Sopenharmony_ci		pci_restore_state(pdev);
546862306a36Sopenharmony_ci		pci_save_state(pdev);
546962306a36Sopenharmony_ci		return PCI_ERS_RESULT_RECOVERED;
547062306a36Sopenharmony_ci	}
547162306a36Sopenharmony_ci
547262306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_DEV_ENABLED)) {
547362306a36Sopenharmony_ci		if (pci_enable_device(pdev)) {
547462306a36Sopenharmony_ci			dev_err(&pdev->dev, "Cannot reenable PCI "
547562306a36Sopenharmony_ci					    "device after reset\n");
547662306a36Sopenharmony_ci			return PCI_ERS_RESULT_DISCONNECT;
547762306a36Sopenharmony_ci		}
547862306a36Sopenharmony_ci		adap->flags |= CXGB4_DEV_ENABLED;
547962306a36Sopenharmony_ci	}
548062306a36Sopenharmony_ci
548162306a36Sopenharmony_ci	pci_set_master(pdev);
548262306a36Sopenharmony_ci	pci_restore_state(pdev);
548362306a36Sopenharmony_ci	pci_save_state(pdev);
548462306a36Sopenharmony_ci
548562306a36Sopenharmony_ci	if (t4_wait_dev_ready(adap->regs) < 0)
548662306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
548762306a36Sopenharmony_ci	if (t4_fw_hello(adap, adap->mbox, adap->pf, MASTER_MUST, NULL) < 0)
548862306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
548962306a36Sopenharmony_ci	adap->flags |= CXGB4_FW_OK;
549062306a36Sopenharmony_ci	if (adap_init1(adap, &c))
549162306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
549262306a36Sopenharmony_ci
549362306a36Sopenharmony_ci	for_each_port(adap, i) {
549462306a36Sopenharmony_ci		struct port_info *pi = adap2pinfo(adap, i);
549562306a36Sopenharmony_ci		u8 vivld = 0, vin = 0;
549662306a36Sopenharmony_ci
549762306a36Sopenharmony_ci		ret = t4_alloc_vi(adap, adap->mbox, pi->tx_chan, adap->pf, 0, 1,
549862306a36Sopenharmony_ci				  NULL, NULL, &vivld, &vin);
549962306a36Sopenharmony_ci		if (ret < 0)
550062306a36Sopenharmony_ci			return PCI_ERS_RESULT_DISCONNECT;
550162306a36Sopenharmony_ci		pi->viid = ret;
550262306a36Sopenharmony_ci		pi->xact_addr_filt = -1;
550362306a36Sopenharmony_ci		/* If fw supports returning the VIN as part of FW_VI_CMD,
550462306a36Sopenharmony_ci		 * save the returned values.
550562306a36Sopenharmony_ci		 */
550662306a36Sopenharmony_ci		if (adap->params.viid_smt_extn_support) {
550762306a36Sopenharmony_ci			pi->vivld = vivld;
550862306a36Sopenharmony_ci			pi->vin = vin;
550962306a36Sopenharmony_ci		} else {
551062306a36Sopenharmony_ci			/* Retrieve the values from VIID */
551162306a36Sopenharmony_ci			pi->vivld = FW_VIID_VIVLD_G(pi->viid);
551262306a36Sopenharmony_ci			pi->vin = FW_VIID_VIN_G(pi->viid);
551362306a36Sopenharmony_ci		}
551462306a36Sopenharmony_ci	}
551562306a36Sopenharmony_ci
551662306a36Sopenharmony_ci	t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
551762306a36Sopenharmony_ci		     adap->params.b_wnd);
551862306a36Sopenharmony_ci	setup_memwin(adap);
551962306a36Sopenharmony_ci	if (cxgb_up(adap))
552062306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
552162306a36Sopenharmony_ci	return PCI_ERS_RESULT_RECOVERED;
552262306a36Sopenharmony_ci}
552362306a36Sopenharmony_ci
552462306a36Sopenharmony_cistatic void eeh_resume(struct pci_dev *pdev)
552562306a36Sopenharmony_ci{
552662306a36Sopenharmony_ci	int i;
552762306a36Sopenharmony_ci	struct adapter *adap = pci_get_drvdata(pdev);
552862306a36Sopenharmony_ci
552962306a36Sopenharmony_ci	if (!adap)
553062306a36Sopenharmony_ci		return;
553162306a36Sopenharmony_ci
553262306a36Sopenharmony_ci	rtnl_lock();
553362306a36Sopenharmony_ci	for_each_port(adap, i) {
553462306a36Sopenharmony_ci		struct net_device *dev = adap->port[i];
553562306a36Sopenharmony_ci		if (dev) {
553662306a36Sopenharmony_ci			if (netif_running(dev)) {
553762306a36Sopenharmony_ci				link_start(dev);
553862306a36Sopenharmony_ci				cxgb_set_rxmode(dev);
553962306a36Sopenharmony_ci			}
554062306a36Sopenharmony_ci			netif_device_attach(dev);
554162306a36Sopenharmony_ci		}
554262306a36Sopenharmony_ci	}
554362306a36Sopenharmony_ci	rtnl_unlock();
554462306a36Sopenharmony_ci}
554562306a36Sopenharmony_ci
554662306a36Sopenharmony_cistatic void eeh_reset_prepare(struct pci_dev *pdev)
554762306a36Sopenharmony_ci{
554862306a36Sopenharmony_ci	struct adapter *adapter = pci_get_drvdata(pdev);
554962306a36Sopenharmony_ci	int i;
555062306a36Sopenharmony_ci
555162306a36Sopenharmony_ci	if (adapter->pf != 4)
555262306a36Sopenharmony_ci		return;
555362306a36Sopenharmony_ci
555462306a36Sopenharmony_ci	adapter->flags &= ~CXGB4_FW_OK;
555562306a36Sopenharmony_ci
555662306a36Sopenharmony_ci	notify_ulds(adapter, CXGB4_STATE_DOWN);
555762306a36Sopenharmony_ci
555862306a36Sopenharmony_ci	for_each_port(adapter, i)
555962306a36Sopenharmony_ci		if (adapter->port[i]->reg_state == NETREG_REGISTERED)
556062306a36Sopenharmony_ci			cxgb_close(adapter->port[i]);
556162306a36Sopenharmony_ci
556262306a36Sopenharmony_ci	disable_interrupts(adapter);
556362306a36Sopenharmony_ci	cxgb4_free_mps_ref_entries(adapter);
556462306a36Sopenharmony_ci
556562306a36Sopenharmony_ci	adap_free_hma_mem(adapter);
556662306a36Sopenharmony_ci
556762306a36Sopenharmony_ci	if (adapter->flags & CXGB4_FULL_INIT_DONE)
556862306a36Sopenharmony_ci		cxgb_down(adapter);
556962306a36Sopenharmony_ci}
557062306a36Sopenharmony_ci
557162306a36Sopenharmony_cistatic void eeh_reset_done(struct pci_dev *pdev)
557262306a36Sopenharmony_ci{
557362306a36Sopenharmony_ci	struct adapter *adapter = pci_get_drvdata(pdev);
557462306a36Sopenharmony_ci	int err, i;
557562306a36Sopenharmony_ci
557662306a36Sopenharmony_ci	if (adapter->pf != 4)
557762306a36Sopenharmony_ci		return;
557862306a36Sopenharmony_ci
557962306a36Sopenharmony_ci	err = t4_wait_dev_ready(adapter->regs);
558062306a36Sopenharmony_ci	if (err < 0) {
558162306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
558262306a36Sopenharmony_ci			"Device not ready, err %d", err);
558362306a36Sopenharmony_ci		return;
558462306a36Sopenharmony_ci	}
558562306a36Sopenharmony_ci
558662306a36Sopenharmony_ci	setup_memwin(adapter);
558762306a36Sopenharmony_ci
558862306a36Sopenharmony_ci	err = adap_init0(adapter, 1);
558962306a36Sopenharmony_ci	if (err) {
559062306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
559162306a36Sopenharmony_ci			"Adapter init failed, err %d", err);
559262306a36Sopenharmony_ci		return;
559362306a36Sopenharmony_ci	}
559462306a36Sopenharmony_ci
559562306a36Sopenharmony_ci	setup_memwin_rdma(adapter);
559662306a36Sopenharmony_ci
559762306a36Sopenharmony_ci	if (adapter->flags & CXGB4_FW_OK) {
559862306a36Sopenharmony_ci		err = t4_port_init(adapter, adapter->pf, adapter->pf, 0);
559962306a36Sopenharmony_ci		if (err) {
560062306a36Sopenharmony_ci			dev_err(adapter->pdev_dev,
560162306a36Sopenharmony_ci				"Port init failed, err %d", err);
560262306a36Sopenharmony_ci			return;
560362306a36Sopenharmony_ci		}
560462306a36Sopenharmony_ci	}
560562306a36Sopenharmony_ci
560662306a36Sopenharmony_ci	err = cfg_queues(adapter);
560762306a36Sopenharmony_ci	if (err) {
560862306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
560962306a36Sopenharmony_ci			"Config queues failed, err %d", err);
561062306a36Sopenharmony_ci		return;
561162306a36Sopenharmony_ci	}
561262306a36Sopenharmony_ci
561362306a36Sopenharmony_ci	cxgb4_init_mps_ref_entries(adapter);
561462306a36Sopenharmony_ci
561562306a36Sopenharmony_ci	err = setup_fw_sge_queues(adapter);
561662306a36Sopenharmony_ci	if (err) {
561762306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
561862306a36Sopenharmony_ci			"FW sge queue allocation failed, err %d", err);
561962306a36Sopenharmony_ci		return;
562062306a36Sopenharmony_ci	}
562162306a36Sopenharmony_ci
562262306a36Sopenharmony_ci	for_each_port(adapter, i)
562362306a36Sopenharmony_ci		if (adapter->port[i]->reg_state == NETREG_REGISTERED)
562462306a36Sopenharmony_ci			cxgb_open(adapter->port[i]);
562562306a36Sopenharmony_ci}
562662306a36Sopenharmony_ci
562762306a36Sopenharmony_cistatic const struct pci_error_handlers cxgb4_eeh = {
562862306a36Sopenharmony_ci	.error_detected = eeh_err_detected,
562962306a36Sopenharmony_ci	.slot_reset     = eeh_slot_reset,
563062306a36Sopenharmony_ci	.resume         = eeh_resume,
563162306a36Sopenharmony_ci	.reset_prepare  = eeh_reset_prepare,
563262306a36Sopenharmony_ci	.reset_done     = eeh_reset_done,
563362306a36Sopenharmony_ci};
563462306a36Sopenharmony_ci
563562306a36Sopenharmony_ci/* Return true if the Link Configuration supports "High Speeds" (those greater
563662306a36Sopenharmony_ci * than 1Gb/s).
563762306a36Sopenharmony_ci */
563862306a36Sopenharmony_cistatic inline bool is_x_10g_port(const struct link_config *lc)
563962306a36Sopenharmony_ci{
564062306a36Sopenharmony_ci	unsigned int speeds, high_speeds;
564162306a36Sopenharmony_ci
564262306a36Sopenharmony_ci	speeds = FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_G(lc->pcaps));
564362306a36Sopenharmony_ci	high_speeds = speeds &
564462306a36Sopenharmony_ci			~(FW_PORT_CAP32_SPEED_100M | FW_PORT_CAP32_SPEED_1G);
564562306a36Sopenharmony_ci
564662306a36Sopenharmony_ci	return high_speeds != 0;
564762306a36Sopenharmony_ci}
564862306a36Sopenharmony_ci
564962306a36Sopenharmony_ci/* Perform default configuration of DMA queues depending on the number and type
565062306a36Sopenharmony_ci * of ports we found and the number of available CPUs.  Most settings can be
565162306a36Sopenharmony_ci * modified by the admin prior to actual use.
565262306a36Sopenharmony_ci */
565362306a36Sopenharmony_cistatic int cfg_queues(struct adapter *adap)
565462306a36Sopenharmony_ci{
565562306a36Sopenharmony_ci	u32 avail_qsets, avail_eth_qsets, avail_uld_qsets;
565662306a36Sopenharmony_ci	u32 ncpus = num_online_cpus();
565762306a36Sopenharmony_ci	u32 niqflint, neq, num_ulds;
565862306a36Sopenharmony_ci	struct sge *s = &adap->sge;
565962306a36Sopenharmony_ci	u32 i, n10g = 0, qidx = 0;
566062306a36Sopenharmony_ci	u32 q10g = 0, q1g;
566162306a36Sopenharmony_ci
566262306a36Sopenharmony_ci	/* Reduce memory usage in kdump environment, disable all offload. */
566362306a36Sopenharmony_ci	if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) {
566462306a36Sopenharmony_ci		adap->params.offload = 0;
566562306a36Sopenharmony_ci		adap->params.crypto = 0;
566662306a36Sopenharmony_ci		adap->params.ethofld = 0;
566762306a36Sopenharmony_ci	}
566862306a36Sopenharmony_ci
566962306a36Sopenharmony_ci	/* Calculate the number of Ethernet Queue Sets available based on
567062306a36Sopenharmony_ci	 * resources provisioned for us.  We always have an Asynchronous
567162306a36Sopenharmony_ci	 * Firmware Event Ingress Queue.  If we're operating in MSI or Legacy
567262306a36Sopenharmony_ci	 * IRQ Pin Interrupt mode, then we'll also have a Forwarded Interrupt
567362306a36Sopenharmony_ci	 * Ingress Queue.  Meanwhile, we need two Egress Queues for each
567462306a36Sopenharmony_ci	 * Queue Set: one for the Free List and one for the Ethernet TX Queue.
567562306a36Sopenharmony_ci	 *
567662306a36Sopenharmony_ci	 * Note that we should also take into account all of the various
567762306a36Sopenharmony_ci	 * Offload Queues.  But, in any situation where we're operating in
567862306a36Sopenharmony_ci	 * a Resource Constrained Provisioning environment, doing any Offload
567962306a36Sopenharmony_ci	 * at all is problematic ...
568062306a36Sopenharmony_ci	 */
568162306a36Sopenharmony_ci	niqflint = adap->params.pfres.niqflint - 1;
568262306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_USING_MSIX))
568362306a36Sopenharmony_ci		niqflint--;
568462306a36Sopenharmony_ci	neq = adap->params.pfres.neq / 2;
568562306a36Sopenharmony_ci	avail_qsets = min(niqflint, neq);
568662306a36Sopenharmony_ci
568762306a36Sopenharmony_ci	if (avail_qsets < adap->params.nports) {
568862306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "avail_eth_qsets=%d < nports=%d\n",
568962306a36Sopenharmony_ci			avail_qsets, adap->params.nports);
569062306a36Sopenharmony_ci		return -ENOMEM;
569162306a36Sopenharmony_ci	}
569262306a36Sopenharmony_ci
569362306a36Sopenharmony_ci	/* Count the number of 10Gb/s or better ports */
569462306a36Sopenharmony_ci	for_each_port(adap, i)
569562306a36Sopenharmony_ci		n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg);
569662306a36Sopenharmony_ci
569762306a36Sopenharmony_ci	avail_eth_qsets = min_t(u32, avail_qsets, MAX_ETH_QSETS);
569862306a36Sopenharmony_ci
569962306a36Sopenharmony_ci	/* We default to 1 queue per non-10G port and up to # of cores queues
570062306a36Sopenharmony_ci	 * per 10G port.
570162306a36Sopenharmony_ci	 */
570262306a36Sopenharmony_ci	if (n10g)
570362306a36Sopenharmony_ci		q10g = (avail_eth_qsets - (adap->params.nports - n10g)) / n10g;
570462306a36Sopenharmony_ci
570562306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
570662306a36Sopenharmony_ci	/* For Data Center Bridging support we need to be able to support up
570762306a36Sopenharmony_ci	 * to 8 Traffic Priorities; each of which will be assigned to its
570862306a36Sopenharmony_ci	 * own TX Queue in order to prevent Head-Of-Line Blocking.
570962306a36Sopenharmony_ci	 */
571062306a36Sopenharmony_ci	q1g = 8;
571162306a36Sopenharmony_ci	if (adap->params.nports * 8 > avail_eth_qsets) {
571262306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "DCB avail_eth_qsets=%d < %d!\n",
571362306a36Sopenharmony_ci			avail_eth_qsets, adap->params.nports * 8);
571462306a36Sopenharmony_ci		return -ENOMEM;
571562306a36Sopenharmony_ci	}
571662306a36Sopenharmony_ci
571762306a36Sopenharmony_ci	if (adap->params.nports * ncpus < avail_eth_qsets)
571862306a36Sopenharmony_ci		q10g = max(8U, ncpus);
571962306a36Sopenharmony_ci	else
572062306a36Sopenharmony_ci		q10g = max(8U, q10g);
572162306a36Sopenharmony_ci
572262306a36Sopenharmony_ci	while ((q10g * n10g) >
572362306a36Sopenharmony_ci	       (avail_eth_qsets - (adap->params.nports - n10g) * q1g))
572462306a36Sopenharmony_ci		q10g--;
572562306a36Sopenharmony_ci
572662306a36Sopenharmony_ci#else /* !CONFIG_CHELSIO_T4_DCB */
572762306a36Sopenharmony_ci	q1g = 1;
572862306a36Sopenharmony_ci	q10g = min(q10g, ncpus);
572962306a36Sopenharmony_ci#endif /* !CONFIG_CHELSIO_T4_DCB */
573062306a36Sopenharmony_ci	if (is_kdump_kernel()) {
573162306a36Sopenharmony_ci		q10g = 1;
573262306a36Sopenharmony_ci		q1g = 1;
573362306a36Sopenharmony_ci	}
573462306a36Sopenharmony_ci
573562306a36Sopenharmony_ci	for_each_port(adap, i) {
573662306a36Sopenharmony_ci		struct port_info *pi = adap2pinfo(adap, i);
573762306a36Sopenharmony_ci
573862306a36Sopenharmony_ci		pi->first_qset = qidx;
573962306a36Sopenharmony_ci		pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : q1g;
574062306a36Sopenharmony_ci		qidx += pi->nqsets;
574162306a36Sopenharmony_ci	}
574262306a36Sopenharmony_ci
574362306a36Sopenharmony_ci	s->ethqsets = qidx;
574462306a36Sopenharmony_ci	s->max_ethqsets = qidx;   /* MSI-X may lower it later */
574562306a36Sopenharmony_ci	avail_qsets -= qidx;
574662306a36Sopenharmony_ci
574762306a36Sopenharmony_ci	if (is_uld(adap)) {
574862306a36Sopenharmony_ci		/* For offload we use 1 queue/channel if all ports are up to 1G,
574962306a36Sopenharmony_ci		 * otherwise we divide all available queues amongst the channels
575062306a36Sopenharmony_ci		 * capped by the number of available cores.
575162306a36Sopenharmony_ci		 */
575262306a36Sopenharmony_ci		num_ulds = adap->num_uld + adap->num_ofld_uld;
575362306a36Sopenharmony_ci		i = min_t(u32, MAX_OFLD_QSETS, ncpus);
575462306a36Sopenharmony_ci		avail_uld_qsets = roundup(i, adap->params.nports);
575562306a36Sopenharmony_ci		if (avail_qsets < num_ulds * adap->params.nports) {
575662306a36Sopenharmony_ci			adap->params.offload = 0;
575762306a36Sopenharmony_ci			adap->params.crypto = 0;
575862306a36Sopenharmony_ci			s->ofldqsets = 0;
575962306a36Sopenharmony_ci		} else if (avail_qsets < num_ulds * avail_uld_qsets || !n10g) {
576062306a36Sopenharmony_ci			s->ofldqsets = adap->params.nports;
576162306a36Sopenharmony_ci		} else {
576262306a36Sopenharmony_ci			s->ofldqsets = avail_uld_qsets;
576362306a36Sopenharmony_ci		}
576462306a36Sopenharmony_ci
576562306a36Sopenharmony_ci		avail_qsets -= num_ulds * s->ofldqsets;
576662306a36Sopenharmony_ci	}
576762306a36Sopenharmony_ci
576862306a36Sopenharmony_ci	/* ETHOFLD Queues used for QoS offload should follow same
576962306a36Sopenharmony_ci	 * allocation scheme as normal Ethernet Queues.
577062306a36Sopenharmony_ci	 */
577162306a36Sopenharmony_ci	if (is_ethofld(adap)) {
577262306a36Sopenharmony_ci		if (avail_qsets < s->max_ethqsets) {
577362306a36Sopenharmony_ci			adap->params.ethofld = 0;
577462306a36Sopenharmony_ci			s->eoqsets = 0;
577562306a36Sopenharmony_ci		} else {
577662306a36Sopenharmony_ci			s->eoqsets = s->max_ethqsets;
577762306a36Sopenharmony_ci		}
577862306a36Sopenharmony_ci		avail_qsets -= s->eoqsets;
577962306a36Sopenharmony_ci	}
578062306a36Sopenharmony_ci
578162306a36Sopenharmony_ci	/* Mirror queues must follow same scheme as normal Ethernet
578262306a36Sopenharmony_ci	 * Queues, when there are enough queues available. Otherwise,
578362306a36Sopenharmony_ci	 * allocate at least 1 queue per port. If even 1 queue is not
578462306a36Sopenharmony_ci	 * available, then disable mirror queues support.
578562306a36Sopenharmony_ci	 */
578662306a36Sopenharmony_ci	if (avail_qsets >= s->max_ethqsets)
578762306a36Sopenharmony_ci		s->mirrorqsets = s->max_ethqsets;
578862306a36Sopenharmony_ci	else if (avail_qsets >= adap->params.nports)
578962306a36Sopenharmony_ci		s->mirrorqsets = adap->params.nports;
579062306a36Sopenharmony_ci	else
579162306a36Sopenharmony_ci		s->mirrorqsets = 0;
579262306a36Sopenharmony_ci	avail_qsets -= s->mirrorqsets;
579362306a36Sopenharmony_ci
579462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) {
579562306a36Sopenharmony_ci		struct sge_eth_rxq *r = &s->ethrxq[i];
579662306a36Sopenharmony_ci
579762306a36Sopenharmony_ci		init_rspq(adap, &r->rspq, 5, 10, 1024, 64);
579862306a36Sopenharmony_ci		r->fl.size = 72;
579962306a36Sopenharmony_ci	}
580062306a36Sopenharmony_ci
580162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(s->ethtxq); i++)
580262306a36Sopenharmony_ci		s->ethtxq[i].q.size = 1024;
580362306a36Sopenharmony_ci
580462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++)
580562306a36Sopenharmony_ci		s->ctrlq[i].q.size = 512;
580662306a36Sopenharmony_ci
580762306a36Sopenharmony_ci	if (!is_t4(adap->params.chip))
580862306a36Sopenharmony_ci		s->ptptxq.q.size = 8;
580962306a36Sopenharmony_ci
581062306a36Sopenharmony_ci	init_rspq(adap, &s->fw_evtq, 0, 1, 1024, 64);
581162306a36Sopenharmony_ci	init_rspq(adap, &s->intrq, 0, 1, 512, 64);
581262306a36Sopenharmony_ci
581362306a36Sopenharmony_ci	return 0;
581462306a36Sopenharmony_ci}
581562306a36Sopenharmony_ci
581662306a36Sopenharmony_ci/*
581762306a36Sopenharmony_ci * Reduce the number of Ethernet queues across all ports to at most n.
581862306a36Sopenharmony_ci * n provides at least one queue per port.
581962306a36Sopenharmony_ci */
582062306a36Sopenharmony_cistatic void reduce_ethqs(struct adapter *adap, int n)
582162306a36Sopenharmony_ci{
582262306a36Sopenharmony_ci	int i;
582362306a36Sopenharmony_ci	struct port_info *pi;
582462306a36Sopenharmony_ci
582562306a36Sopenharmony_ci	while (n < adap->sge.ethqsets)
582662306a36Sopenharmony_ci		for_each_port(adap, i) {
582762306a36Sopenharmony_ci			pi = adap2pinfo(adap, i);
582862306a36Sopenharmony_ci			if (pi->nqsets > 1) {
582962306a36Sopenharmony_ci				pi->nqsets--;
583062306a36Sopenharmony_ci				adap->sge.ethqsets--;
583162306a36Sopenharmony_ci				if (adap->sge.ethqsets <= n)
583262306a36Sopenharmony_ci					break;
583362306a36Sopenharmony_ci			}
583462306a36Sopenharmony_ci		}
583562306a36Sopenharmony_ci
583662306a36Sopenharmony_ci	n = 0;
583762306a36Sopenharmony_ci	for_each_port(adap, i) {
583862306a36Sopenharmony_ci		pi = adap2pinfo(adap, i);
583962306a36Sopenharmony_ci		pi->first_qset = n;
584062306a36Sopenharmony_ci		n += pi->nqsets;
584162306a36Sopenharmony_ci	}
584262306a36Sopenharmony_ci}
584362306a36Sopenharmony_ci
584462306a36Sopenharmony_cistatic int alloc_msix_info(struct adapter *adap, u32 num_vec)
584562306a36Sopenharmony_ci{
584662306a36Sopenharmony_ci	struct msix_info *msix_info;
584762306a36Sopenharmony_ci
584862306a36Sopenharmony_ci	msix_info = kcalloc(num_vec, sizeof(*msix_info), GFP_KERNEL);
584962306a36Sopenharmony_ci	if (!msix_info)
585062306a36Sopenharmony_ci		return -ENOMEM;
585162306a36Sopenharmony_ci
585262306a36Sopenharmony_ci	adap->msix_bmap.msix_bmap = bitmap_zalloc(num_vec, GFP_KERNEL);
585362306a36Sopenharmony_ci	if (!adap->msix_bmap.msix_bmap) {
585462306a36Sopenharmony_ci		kfree(msix_info);
585562306a36Sopenharmony_ci		return -ENOMEM;
585662306a36Sopenharmony_ci	}
585762306a36Sopenharmony_ci
585862306a36Sopenharmony_ci	spin_lock_init(&adap->msix_bmap.lock);
585962306a36Sopenharmony_ci	adap->msix_bmap.mapsize = num_vec;
586062306a36Sopenharmony_ci
586162306a36Sopenharmony_ci	adap->msix_info = msix_info;
586262306a36Sopenharmony_ci	return 0;
586362306a36Sopenharmony_ci}
586462306a36Sopenharmony_ci
586562306a36Sopenharmony_cistatic void free_msix_info(struct adapter *adap)
586662306a36Sopenharmony_ci{
586762306a36Sopenharmony_ci	bitmap_free(adap->msix_bmap.msix_bmap);
586862306a36Sopenharmony_ci	kfree(adap->msix_info);
586962306a36Sopenharmony_ci}
587062306a36Sopenharmony_ci
587162306a36Sopenharmony_ciint cxgb4_get_msix_idx_from_bmap(struct adapter *adap)
587262306a36Sopenharmony_ci{
587362306a36Sopenharmony_ci	struct msix_bmap *bmap = &adap->msix_bmap;
587462306a36Sopenharmony_ci	unsigned int msix_idx;
587562306a36Sopenharmony_ci	unsigned long flags;
587662306a36Sopenharmony_ci
587762306a36Sopenharmony_ci	spin_lock_irqsave(&bmap->lock, flags);
587862306a36Sopenharmony_ci	msix_idx = find_first_zero_bit(bmap->msix_bmap, bmap->mapsize);
587962306a36Sopenharmony_ci	if (msix_idx < bmap->mapsize) {
588062306a36Sopenharmony_ci		__set_bit(msix_idx, bmap->msix_bmap);
588162306a36Sopenharmony_ci	} else {
588262306a36Sopenharmony_ci		spin_unlock_irqrestore(&bmap->lock, flags);
588362306a36Sopenharmony_ci		return -ENOSPC;
588462306a36Sopenharmony_ci	}
588562306a36Sopenharmony_ci
588662306a36Sopenharmony_ci	spin_unlock_irqrestore(&bmap->lock, flags);
588762306a36Sopenharmony_ci	return msix_idx;
588862306a36Sopenharmony_ci}
588962306a36Sopenharmony_ci
589062306a36Sopenharmony_civoid cxgb4_free_msix_idx_in_bmap(struct adapter *adap,
589162306a36Sopenharmony_ci				 unsigned int msix_idx)
589262306a36Sopenharmony_ci{
589362306a36Sopenharmony_ci	struct msix_bmap *bmap = &adap->msix_bmap;
589462306a36Sopenharmony_ci	unsigned long flags;
589562306a36Sopenharmony_ci
589662306a36Sopenharmony_ci	spin_lock_irqsave(&bmap->lock, flags);
589762306a36Sopenharmony_ci	__clear_bit(msix_idx, bmap->msix_bmap);
589862306a36Sopenharmony_ci	spin_unlock_irqrestore(&bmap->lock, flags);
589962306a36Sopenharmony_ci}
590062306a36Sopenharmony_ci
590162306a36Sopenharmony_ci/* 2 MSI-X vectors needed for the FW queue and non-data interrupts */
590262306a36Sopenharmony_ci#define EXTRA_VECS 2
590362306a36Sopenharmony_ci
590462306a36Sopenharmony_cistatic int enable_msix(struct adapter *adap)
590562306a36Sopenharmony_ci{
590662306a36Sopenharmony_ci	u32 eth_need, uld_need = 0, ethofld_need = 0, mirror_need = 0;
590762306a36Sopenharmony_ci	u32 ethqsets = 0, ofldqsets = 0, eoqsets = 0, mirrorqsets = 0;
590862306a36Sopenharmony_ci	u8 num_uld = 0, nchan = adap->params.nports;
590962306a36Sopenharmony_ci	u32 i, want, need, num_vec;
591062306a36Sopenharmony_ci	struct sge *s = &adap->sge;
591162306a36Sopenharmony_ci	struct msix_entry *entries;
591262306a36Sopenharmony_ci	struct port_info *pi;
591362306a36Sopenharmony_ci	int allocated, ret;
591462306a36Sopenharmony_ci
591562306a36Sopenharmony_ci	want = s->max_ethqsets;
591662306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
591762306a36Sopenharmony_ci	/* For Data Center Bridging we need 8 Ethernet TX Priority Queues for
591862306a36Sopenharmony_ci	 * each port.
591962306a36Sopenharmony_ci	 */
592062306a36Sopenharmony_ci	need = 8 * nchan;
592162306a36Sopenharmony_ci#else
592262306a36Sopenharmony_ci	need = nchan;
592362306a36Sopenharmony_ci#endif
592462306a36Sopenharmony_ci	eth_need = need;
592562306a36Sopenharmony_ci	if (is_uld(adap)) {
592662306a36Sopenharmony_ci		num_uld = adap->num_ofld_uld + adap->num_uld;
592762306a36Sopenharmony_ci		want += num_uld * s->ofldqsets;
592862306a36Sopenharmony_ci		uld_need = num_uld * nchan;
592962306a36Sopenharmony_ci		need += uld_need;
593062306a36Sopenharmony_ci	}
593162306a36Sopenharmony_ci
593262306a36Sopenharmony_ci	if (is_ethofld(adap)) {
593362306a36Sopenharmony_ci		want += s->eoqsets;
593462306a36Sopenharmony_ci		ethofld_need = eth_need;
593562306a36Sopenharmony_ci		need += ethofld_need;
593662306a36Sopenharmony_ci	}
593762306a36Sopenharmony_ci
593862306a36Sopenharmony_ci	if (s->mirrorqsets) {
593962306a36Sopenharmony_ci		want += s->mirrorqsets;
594062306a36Sopenharmony_ci		mirror_need = nchan;
594162306a36Sopenharmony_ci		need += mirror_need;
594262306a36Sopenharmony_ci	}
594362306a36Sopenharmony_ci
594462306a36Sopenharmony_ci	want += EXTRA_VECS;
594562306a36Sopenharmony_ci	need += EXTRA_VECS;
594662306a36Sopenharmony_ci
594762306a36Sopenharmony_ci	entries = kmalloc_array(want, sizeof(*entries), GFP_KERNEL);
594862306a36Sopenharmony_ci	if (!entries)
594962306a36Sopenharmony_ci		return -ENOMEM;
595062306a36Sopenharmony_ci
595162306a36Sopenharmony_ci	for (i = 0; i < want; i++)
595262306a36Sopenharmony_ci		entries[i].entry = i;
595362306a36Sopenharmony_ci
595462306a36Sopenharmony_ci	allocated = pci_enable_msix_range(adap->pdev, entries, need, want);
595562306a36Sopenharmony_ci	if (allocated < 0) {
595662306a36Sopenharmony_ci		/* Disable offload and attempt to get vectors for NIC
595762306a36Sopenharmony_ci		 * only mode.
595862306a36Sopenharmony_ci		 */
595962306a36Sopenharmony_ci		want = s->max_ethqsets + EXTRA_VECS;
596062306a36Sopenharmony_ci		need = eth_need + EXTRA_VECS;
596162306a36Sopenharmony_ci		allocated = pci_enable_msix_range(adap->pdev, entries,
596262306a36Sopenharmony_ci						  need, want);
596362306a36Sopenharmony_ci		if (allocated < 0) {
596462306a36Sopenharmony_ci			dev_info(adap->pdev_dev,
596562306a36Sopenharmony_ci				 "Disabling MSI-X due to insufficient MSI-X vectors\n");
596662306a36Sopenharmony_ci			ret = allocated;
596762306a36Sopenharmony_ci			goto out_free;
596862306a36Sopenharmony_ci		}
596962306a36Sopenharmony_ci
597062306a36Sopenharmony_ci		dev_info(adap->pdev_dev,
597162306a36Sopenharmony_ci			 "Disabling offload due to insufficient MSI-X vectors\n");
597262306a36Sopenharmony_ci		adap->params.offload = 0;
597362306a36Sopenharmony_ci		adap->params.crypto = 0;
597462306a36Sopenharmony_ci		adap->params.ethofld = 0;
597562306a36Sopenharmony_ci		s->ofldqsets = 0;
597662306a36Sopenharmony_ci		s->eoqsets = 0;
597762306a36Sopenharmony_ci		s->mirrorqsets = 0;
597862306a36Sopenharmony_ci		uld_need = 0;
597962306a36Sopenharmony_ci		ethofld_need = 0;
598062306a36Sopenharmony_ci		mirror_need = 0;
598162306a36Sopenharmony_ci	}
598262306a36Sopenharmony_ci
598362306a36Sopenharmony_ci	num_vec = allocated;
598462306a36Sopenharmony_ci	if (num_vec < want) {
598562306a36Sopenharmony_ci		/* Distribute available vectors to the various queue groups.
598662306a36Sopenharmony_ci		 * Every group gets its minimum requirement and NIC gets top
598762306a36Sopenharmony_ci		 * priority for leftovers.
598862306a36Sopenharmony_ci		 */
598962306a36Sopenharmony_ci		ethqsets = eth_need;
599062306a36Sopenharmony_ci		if (is_uld(adap))
599162306a36Sopenharmony_ci			ofldqsets = nchan;
599262306a36Sopenharmony_ci		if (is_ethofld(adap))
599362306a36Sopenharmony_ci			eoqsets = ethofld_need;
599462306a36Sopenharmony_ci		if (s->mirrorqsets)
599562306a36Sopenharmony_ci			mirrorqsets = mirror_need;
599662306a36Sopenharmony_ci
599762306a36Sopenharmony_ci		num_vec -= need;
599862306a36Sopenharmony_ci		while (num_vec) {
599962306a36Sopenharmony_ci			if (num_vec < eth_need + ethofld_need ||
600062306a36Sopenharmony_ci			    ethqsets > s->max_ethqsets)
600162306a36Sopenharmony_ci				break;
600262306a36Sopenharmony_ci
600362306a36Sopenharmony_ci			for_each_port(adap, i) {
600462306a36Sopenharmony_ci				pi = adap2pinfo(adap, i);
600562306a36Sopenharmony_ci				if (pi->nqsets < 2)
600662306a36Sopenharmony_ci					continue;
600762306a36Sopenharmony_ci
600862306a36Sopenharmony_ci				ethqsets++;
600962306a36Sopenharmony_ci				num_vec--;
601062306a36Sopenharmony_ci				if (ethofld_need) {
601162306a36Sopenharmony_ci					eoqsets++;
601262306a36Sopenharmony_ci					num_vec--;
601362306a36Sopenharmony_ci				}
601462306a36Sopenharmony_ci			}
601562306a36Sopenharmony_ci		}
601662306a36Sopenharmony_ci
601762306a36Sopenharmony_ci		if (is_uld(adap)) {
601862306a36Sopenharmony_ci			while (num_vec) {
601962306a36Sopenharmony_ci				if (num_vec < uld_need ||
602062306a36Sopenharmony_ci				    ofldqsets > s->ofldqsets)
602162306a36Sopenharmony_ci					break;
602262306a36Sopenharmony_ci
602362306a36Sopenharmony_ci				ofldqsets++;
602462306a36Sopenharmony_ci				num_vec -= uld_need;
602562306a36Sopenharmony_ci			}
602662306a36Sopenharmony_ci		}
602762306a36Sopenharmony_ci
602862306a36Sopenharmony_ci		if (s->mirrorqsets) {
602962306a36Sopenharmony_ci			while (num_vec) {
603062306a36Sopenharmony_ci				if (num_vec < mirror_need ||
603162306a36Sopenharmony_ci				    mirrorqsets > s->mirrorqsets)
603262306a36Sopenharmony_ci					break;
603362306a36Sopenharmony_ci
603462306a36Sopenharmony_ci				mirrorqsets++;
603562306a36Sopenharmony_ci				num_vec -= mirror_need;
603662306a36Sopenharmony_ci			}
603762306a36Sopenharmony_ci		}
603862306a36Sopenharmony_ci	} else {
603962306a36Sopenharmony_ci		ethqsets = s->max_ethqsets;
604062306a36Sopenharmony_ci		if (is_uld(adap))
604162306a36Sopenharmony_ci			ofldqsets = s->ofldqsets;
604262306a36Sopenharmony_ci		if (is_ethofld(adap))
604362306a36Sopenharmony_ci			eoqsets = s->eoqsets;
604462306a36Sopenharmony_ci		if (s->mirrorqsets)
604562306a36Sopenharmony_ci			mirrorqsets = s->mirrorqsets;
604662306a36Sopenharmony_ci	}
604762306a36Sopenharmony_ci
604862306a36Sopenharmony_ci	if (ethqsets < s->max_ethqsets) {
604962306a36Sopenharmony_ci		s->max_ethqsets = ethqsets;
605062306a36Sopenharmony_ci		reduce_ethqs(adap, ethqsets);
605162306a36Sopenharmony_ci	}
605262306a36Sopenharmony_ci
605362306a36Sopenharmony_ci	if (is_uld(adap)) {
605462306a36Sopenharmony_ci		s->ofldqsets = ofldqsets;
605562306a36Sopenharmony_ci		s->nqs_per_uld = s->ofldqsets;
605662306a36Sopenharmony_ci	}
605762306a36Sopenharmony_ci
605862306a36Sopenharmony_ci	if (is_ethofld(adap))
605962306a36Sopenharmony_ci		s->eoqsets = eoqsets;
606062306a36Sopenharmony_ci
606162306a36Sopenharmony_ci	if (s->mirrorqsets) {
606262306a36Sopenharmony_ci		s->mirrorqsets = mirrorqsets;
606362306a36Sopenharmony_ci		for_each_port(adap, i) {
606462306a36Sopenharmony_ci			pi = adap2pinfo(adap, i);
606562306a36Sopenharmony_ci			pi->nmirrorqsets = s->mirrorqsets / nchan;
606662306a36Sopenharmony_ci			mutex_init(&pi->vi_mirror_mutex);
606762306a36Sopenharmony_ci		}
606862306a36Sopenharmony_ci	}
606962306a36Sopenharmony_ci
607062306a36Sopenharmony_ci	/* map for msix */
607162306a36Sopenharmony_ci	ret = alloc_msix_info(adap, allocated);
607262306a36Sopenharmony_ci	if (ret)
607362306a36Sopenharmony_ci		goto out_disable_msix;
607462306a36Sopenharmony_ci
607562306a36Sopenharmony_ci	for (i = 0; i < allocated; i++) {
607662306a36Sopenharmony_ci		adap->msix_info[i].vec = entries[i].vector;
607762306a36Sopenharmony_ci		adap->msix_info[i].idx = i;
607862306a36Sopenharmony_ci	}
607962306a36Sopenharmony_ci
608062306a36Sopenharmony_ci	dev_info(adap->pdev_dev,
608162306a36Sopenharmony_ci		 "%d MSI-X vectors allocated, nic %d eoqsets %d per uld %d mirrorqsets %d\n",
608262306a36Sopenharmony_ci		 allocated, s->max_ethqsets, s->eoqsets, s->nqs_per_uld,
608362306a36Sopenharmony_ci		 s->mirrorqsets);
608462306a36Sopenharmony_ci
608562306a36Sopenharmony_ci	kfree(entries);
608662306a36Sopenharmony_ci	return 0;
608762306a36Sopenharmony_ci
608862306a36Sopenharmony_ciout_disable_msix:
608962306a36Sopenharmony_ci	pci_disable_msix(adap->pdev);
609062306a36Sopenharmony_ci
609162306a36Sopenharmony_ciout_free:
609262306a36Sopenharmony_ci	kfree(entries);
609362306a36Sopenharmony_ci	return ret;
609462306a36Sopenharmony_ci}
609562306a36Sopenharmony_ci
609662306a36Sopenharmony_ci#undef EXTRA_VECS
609762306a36Sopenharmony_ci
609862306a36Sopenharmony_cistatic int init_rss(struct adapter *adap)
609962306a36Sopenharmony_ci{
610062306a36Sopenharmony_ci	unsigned int i;
610162306a36Sopenharmony_ci	int err;
610262306a36Sopenharmony_ci
610362306a36Sopenharmony_ci	err = t4_init_rss_mode(adap, adap->mbox);
610462306a36Sopenharmony_ci	if (err)
610562306a36Sopenharmony_ci		return err;
610662306a36Sopenharmony_ci
610762306a36Sopenharmony_ci	for_each_port(adap, i) {
610862306a36Sopenharmony_ci		struct port_info *pi = adap2pinfo(adap, i);
610962306a36Sopenharmony_ci
611062306a36Sopenharmony_ci		pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL);
611162306a36Sopenharmony_ci		if (!pi->rss)
611262306a36Sopenharmony_ci			return -ENOMEM;
611362306a36Sopenharmony_ci	}
611462306a36Sopenharmony_ci	return 0;
611562306a36Sopenharmony_ci}
611662306a36Sopenharmony_ci
611762306a36Sopenharmony_ci/* Dump basic information about the adapter */
611862306a36Sopenharmony_cistatic void print_adapter_info(struct adapter *adapter)
611962306a36Sopenharmony_ci{
612062306a36Sopenharmony_ci	/* Hardware/Firmware/etc. Version/Revision IDs */
612162306a36Sopenharmony_ci	t4_dump_version_info(adapter);
612262306a36Sopenharmony_ci
612362306a36Sopenharmony_ci	/* Software/Hardware configuration */
612462306a36Sopenharmony_ci	dev_info(adapter->pdev_dev, "Configuration: %sNIC %s, %s capable\n",
612562306a36Sopenharmony_ci		 is_offload(adapter) ? "R" : "",
612662306a36Sopenharmony_ci		 ((adapter->flags & CXGB4_USING_MSIX) ? "MSI-X" :
612762306a36Sopenharmony_ci		  (adapter->flags & CXGB4_USING_MSI) ? "MSI" : ""),
612862306a36Sopenharmony_ci		 is_offload(adapter) ? "Offload" : "non-Offload");
612962306a36Sopenharmony_ci}
613062306a36Sopenharmony_ci
613162306a36Sopenharmony_cistatic void print_port_info(const struct net_device *dev)
613262306a36Sopenharmony_ci{
613362306a36Sopenharmony_ci	char buf[80];
613462306a36Sopenharmony_ci	char *bufp = buf;
613562306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
613662306a36Sopenharmony_ci	const struct adapter *adap = pi->adapter;
613762306a36Sopenharmony_ci
613862306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100M)
613962306a36Sopenharmony_ci		bufp += sprintf(bufp, "100M/");
614062306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_1G)
614162306a36Sopenharmony_ci		bufp += sprintf(bufp, "1G/");
614262306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_10G)
614362306a36Sopenharmony_ci		bufp += sprintf(bufp, "10G/");
614462306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_25G)
614562306a36Sopenharmony_ci		bufp += sprintf(bufp, "25G/");
614662306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_40G)
614762306a36Sopenharmony_ci		bufp += sprintf(bufp, "40G/");
614862306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_50G)
614962306a36Sopenharmony_ci		bufp += sprintf(bufp, "50G/");
615062306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100G)
615162306a36Sopenharmony_ci		bufp += sprintf(bufp, "100G/");
615262306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_200G)
615362306a36Sopenharmony_ci		bufp += sprintf(bufp, "200G/");
615462306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_400G)
615562306a36Sopenharmony_ci		bufp += sprintf(bufp, "400G/");
615662306a36Sopenharmony_ci	if (bufp != buf)
615762306a36Sopenharmony_ci		--bufp;
615862306a36Sopenharmony_ci	sprintf(bufp, "BASE-%s", t4_get_port_type_description(pi->port_type));
615962306a36Sopenharmony_ci
616062306a36Sopenharmony_ci	netdev_info(dev, "Chelsio %s %s\n", adap->params.vpd.id, buf);
616162306a36Sopenharmony_ci}
616262306a36Sopenharmony_ci
616362306a36Sopenharmony_ci/*
616462306a36Sopenharmony_ci * Free the following resources:
616562306a36Sopenharmony_ci * - memory used for tables
616662306a36Sopenharmony_ci * - MSI/MSI-X
616762306a36Sopenharmony_ci * - net devices
616862306a36Sopenharmony_ci * - resources FW is holding for us
616962306a36Sopenharmony_ci */
617062306a36Sopenharmony_cistatic void free_some_resources(struct adapter *adapter)
617162306a36Sopenharmony_ci{
617262306a36Sopenharmony_ci	unsigned int i;
617362306a36Sopenharmony_ci
617462306a36Sopenharmony_ci	kvfree(adapter->smt);
617562306a36Sopenharmony_ci	kvfree(adapter->l2t);
617662306a36Sopenharmony_ci	kvfree(adapter->srq);
617762306a36Sopenharmony_ci	t4_cleanup_sched(adapter);
617862306a36Sopenharmony_ci	kvfree(adapter->tids.tid_tab);
617962306a36Sopenharmony_ci	cxgb4_cleanup_tc_matchall(adapter);
618062306a36Sopenharmony_ci	cxgb4_cleanup_tc_mqprio(adapter);
618162306a36Sopenharmony_ci	cxgb4_cleanup_tc_flower(adapter);
618262306a36Sopenharmony_ci	cxgb4_cleanup_tc_u32(adapter);
618362306a36Sopenharmony_ci	cxgb4_cleanup_ethtool_filters(adapter);
618462306a36Sopenharmony_ci	kfree(adapter->sge.egr_map);
618562306a36Sopenharmony_ci	kfree(adapter->sge.ingr_map);
618662306a36Sopenharmony_ci	bitmap_free(adapter->sge.starving_fl);
618762306a36Sopenharmony_ci	bitmap_free(adapter->sge.txq_maperr);
618862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
618962306a36Sopenharmony_ci	bitmap_free(adapter->sge.blocked_fl);
619062306a36Sopenharmony_ci#endif
619162306a36Sopenharmony_ci	disable_msi(adapter);
619262306a36Sopenharmony_ci
619362306a36Sopenharmony_ci	for_each_port(adapter, i)
619462306a36Sopenharmony_ci		if (adapter->port[i]) {
619562306a36Sopenharmony_ci			struct port_info *pi = adap2pinfo(adapter, i);
619662306a36Sopenharmony_ci
619762306a36Sopenharmony_ci			if (pi->viid != 0)
619862306a36Sopenharmony_ci				t4_free_vi(adapter, adapter->mbox, adapter->pf,
619962306a36Sopenharmony_ci					   0, pi->viid);
620062306a36Sopenharmony_ci			kfree(adap2pinfo(adapter, i)->rss);
620162306a36Sopenharmony_ci			free_netdev(adapter->port[i]);
620262306a36Sopenharmony_ci		}
620362306a36Sopenharmony_ci	if (adapter->flags & CXGB4_FW_OK)
620462306a36Sopenharmony_ci		t4_fw_bye(adapter, adapter->pf);
620562306a36Sopenharmony_ci}
620662306a36Sopenharmony_ci
620762306a36Sopenharmony_ci#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | \
620862306a36Sopenharmony_ci		   NETIF_F_GSO_UDP_L4)
620962306a36Sopenharmony_ci#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \
621062306a36Sopenharmony_ci		   NETIF_F_GRO | NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
621162306a36Sopenharmony_ci#define SEGMENT_SIZE 128
621262306a36Sopenharmony_ci
621362306a36Sopenharmony_cistatic int t4_get_chip_type(struct adapter *adap, int ver)
621462306a36Sopenharmony_ci{
621562306a36Sopenharmony_ci	u32 pl_rev = REV_G(t4_read_reg(adap, PL_REV_A));
621662306a36Sopenharmony_ci
621762306a36Sopenharmony_ci	switch (ver) {
621862306a36Sopenharmony_ci	case CHELSIO_T4:
621962306a36Sopenharmony_ci		return CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev);
622062306a36Sopenharmony_ci	case CHELSIO_T5:
622162306a36Sopenharmony_ci		return CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev);
622262306a36Sopenharmony_ci	case CHELSIO_T6:
622362306a36Sopenharmony_ci		return CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev);
622462306a36Sopenharmony_ci	default:
622562306a36Sopenharmony_ci		break;
622662306a36Sopenharmony_ci	}
622762306a36Sopenharmony_ci	return -EINVAL;
622862306a36Sopenharmony_ci}
622962306a36Sopenharmony_ci
623062306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
623162306a36Sopenharmony_cistatic void cxgb4_mgmt_setup(struct net_device *dev)
623262306a36Sopenharmony_ci{
623362306a36Sopenharmony_ci	dev->type = ARPHRD_NONE;
623462306a36Sopenharmony_ci	dev->mtu = 0;
623562306a36Sopenharmony_ci	dev->hard_header_len = 0;
623662306a36Sopenharmony_ci	dev->addr_len = 0;
623762306a36Sopenharmony_ci	dev->tx_queue_len = 0;
623862306a36Sopenharmony_ci	dev->flags |= IFF_NOARP;
623962306a36Sopenharmony_ci	dev->priv_flags |= IFF_NO_QUEUE;
624062306a36Sopenharmony_ci
624162306a36Sopenharmony_ci	/* Initialize the device structure. */
624262306a36Sopenharmony_ci	dev->netdev_ops = &cxgb4_mgmt_netdev_ops;
624362306a36Sopenharmony_ci	dev->ethtool_ops = &cxgb4_mgmt_ethtool_ops;
624462306a36Sopenharmony_ci}
624562306a36Sopenharmony_ci
624662306a36Sopenharmony_cistatic int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
624762306a36Sopenharmony_ci{
624862306a36Sopenharmony_ci	struct adapter *adap = pci_get_drvdata(pdev);
624962306a36Sopenharmony_ci	int err = 0;
625062306a36Sopenharmony_ci	int current_vfs = pci_num_vf(pdev);
625162306a36Sopenharmony_ci	u32 pcie_fw;
625262306a36Sopenharmony_ci
625362306a36Sopenharmony_ci	pcie_fw = readl(adap->regs + PCIE_FW_A);
625462306a36Sopenharmony_ci	/* Check if fw is initialized */
625562306a36Sopenharmony_ci	if (!(pcie_fw & PCIE_FW_INIT_F)) {
625662306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Device not initialized\n");
625762306a36Sopenharmony_ci		return -EOPNOTSUPP;
625862306a36Sopenharmony_ci	}
625962306a36Sopenharmony_ci
626062306a36Sopenharmony_ci	/* If any of the VF's is already assigned to Guest OS, then
626162306a36Sopenharmony_ci	 * SRIOV for the same cannot be modified
626262306a36Sopenharmony_ci	 */
626362306a36Sopenharmony_ci	if (current_vfs && pci_vfs_assigned(pdev)) {
626462306a36Sopenharmony_ci		dev_err(&pdev->dev,
626562306a36Sopenharmony_ci			"Cannot modify SR-IOV while VFs are assigned\n");
626662306a36Sopenharmony_ci		return current_vfs;
626762306a36Sopenharmony_ci	}
626862306a36Sopenharmony_ci	/* Note that the upper-level code ensures that we're never called with
626962306a36Sopenharmony_ci	 * a non-zero "num_vfs" when we already have VFs instantiated.  But
627062306a36Sopenharmony_ci	 * it never hurts to code defensively.
627162306a36Sopenharmony_ci	 */
627262306a36Sopenharmony_ci	if (num_vfs != 0 && current_vfs != 0)
627362306a36Sopenharmony_ci		return -EBUSY;
627462306a36Sopenharmony_ci
627562306a36Sopenharmony_ci	/* Nothing to do for no change. */
627662306a36Sopenharmony_ci	if (num_vfs == current_vfs)
627762306a36Sopenharmony_ci		return num_vfs;
627862306a36Sopenharmony_ci
627962306a36Sopenharmony_ci	/* Disable SRIOV when zero is passed. */
628062306a36Sopenharmony_ci	if (!num_vfs) {
628162306a36Sopenharmony_ci		pci_disable_sriov(pdev);
628262306a36Sopenharmony_ci		/* free VF Management Interface */
628362306a36Sopenharmony_ci		unregister_netdev(adap->port[0]);
628462306a36Sopenharmony_ci		free_netdev(adap->port[0]);
628562306a36Sopenharmony_ci		adap->port[0] = NULL;
628662306a36Sopenharmony_ci
628762306a36Sopenharmony_ci		/* free VF resources */
628862306a36Sopenharmony_ci		adap->num_vfs = 0;
628962306a36Sopenharmony_ci		kfree(adap->vfinfo);
629062306a36Sopenharmony_ci		adap->vfinfo = NULL;
629162306a36Sopenharmony_ci		return 0;
629262306a36Sopenharmony_ci	}
629362306a36Sopenharmony_ci
629462306a36Sopenharmony_ci	if (!current_vfs) {
629562306a36Sopenharmony_ci		struct fw_pfvf_cmd port_cmd, port_rpl;
629662306a36Sopenharmony_ci		struct net_device *netdev;
629762306a36Sopenharmony_ci		unsigned int pmask, port;
629862306a36Sopenharmony_ci		struct pci_dev *pbridge;
629962306a36Sopenharmony_ci		struct port_info *pi;
630062306a36Sopenharmony_ci		char name[IFNAMSIZ];
630162306a36Sopenharmony_ci		u32 devcap2;
630262306a36Sopenharmony_ci		u16 flags;
630362306a36Sopenharmony_ci
630462306a36Sopenharmony_ci		/* If we want to instantiate Virtual Functions, then our
630562306a36Sopenharmony_ci		 * parent bridge's PCI-E needs to support Alternative Routing
630662306a36Sopenharmony_ci		 * ID (ARI) because our VFs will show up at function offset 8
630762306a36Sopenharmony_ci		 * and above.
630862306a36Sopenharmony_ci		 */
630962306a36Sopenharmony_ci		pbridge = pdev->bus->self;
631062306a36Sopenharmony_ci		pcie_capability_read_word(pbridge, PCI_EXP_FLAGS, &flags);
631162306a36Sopenharmony_ci		pcie_capability_read_dword(pbridge, PCI_EXP_DEVCAP2, &devcap2);
631262306a36Sopenharmony_ci
631362306a36Sopenharmony_ci		if ((flags & PCI_EXP_FLAGS_VERS) < 2 ||
631462306a36Sopenharmony_ci		    !(devcap2 & PCI_EXP_DEVCAP2_ARI)) {
631562306a36Sopenharmony_ci			/* Our parent bridge does not support ARI so issue a
631662306a36Sopenharmony_ci			 * warning and skip instantiating the VFs.  They
631762306a36Sopenharmony_ci			 * won't be reachable.
631862306a36Sopenharmony_ci			 */
631962306a36Sopenharmony_ci			dev_warn(&pdev->dev, "Parent bridge %02x:%02x.%x doesn't support ARI; can't instantiate Virtual Functions\n",
632062306a36Sopenharmony_ci				 pbridge->bus->number, PCI_SLOT(pbridge->devfn),
632162306a36Sopenharmony_ci				 PCI_FUNC(pbridge->devfn));
632262306a36Sopenharmony_ci			return -ENOTSUPP;
632362306a36Sopenharmony_ci		}
632462306a36Sopenharmony_ci		memset(&port_cmd, 0, sizeof(port_cmd));
632562306a36Sopenharmony_ci		port_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) |
632662306a36Sopenharmony_ci						 FW_CMD_REQUEST_F |
632762306a36Sopenharmony_ci						 FW_CMD_READ_F |
632862306a36Sopenharmony_ci						 FW_PFVF_CMD_PFN_V(adap->pf) |
632962306a36Sopenharmony_ci						 FW_PFVF_CMD_VFN_V(0));
633062306a36Sopenharmony_ci		port_cmd.retval_len16 = cpu_to_be32(FW_LEN16(port_cmd));
633162306a36Sopenharmony_ci		err = t4_wr_mbox(adap, adap->mbox, &port_cmd, sizeof(port_cmd),
633262306a36Sopenharmony_ci				 &port_rpl);
633362306a36Sopenharmony_ci		if (err)
633462306a36Sopenharmony_ci			return err;
633562306a36Sopenharmony_ci		pmask = FW_PFVF_CMD_PMASK_G(be32_to_cpu(port_rpl.type_to_neq));
633662306a36Sopenharmony_ci		port = ffs(pmask) - 1;
633762306a36Sopenharmony_ci		/* Allocate VF Management Interface. */
633862306a36Sopenharmony_ci		snprintf(name, IFNAMSIZ, "mgmtpf%d,%d", adap->adap_idx,
633962306a36Sopenharmony_ci			 adap->pf);
634062306a36Sopenharmony_ci		netdev = alloc_netdev(sizeof(struct port_info),
634162306a36Sopenharmony_ci				      name, NET_NAME_UNKNOWN, cxgb4_mgmt_setup);
634262306a36Sopenharmony_ci		if (!netdev)
634362306a36Sopenharmony_ci			return -ENOMEM;
634462306a36Sopenharmony_ci
634562306a36Sopenharmony_ci		pi = netdev_priv(netdev);
634662306a36Sopenharmony_ci		pi->adapter = adap;
634762306a36Sopenharmony_ci		pi->lport = port;
634862306a36Sopenharmony_ci		pi->tx_chan = port;
634962306a36Sopenharmony_ci		SET_NETDEV_DEV(netdev, &pdev->dev);
635062306a36Sopenharmony_ci
635162306a36Sopenharmony_ci		adap->port[0] = netdev;
635262306a36Sopenharmony_ci		pi->port_id = 0;
635362306a36Sopenharmony_ci
635462306a36Sopenharmony_ci		err = register_netdev(adap->port[0]);
635562306a36Sopenharmony_ci		if (err) {
635662306a36Sopenharmony_ci			pr_info("Unable to register VF mgmt netdev %s\n", name);
635762306a36Sopenharmony_ci			free_netdev(adap->port[0]);
635862306a36Sopenharmony_ci			adap->port[0] = NULL;
635962306a36Sopenharmony_ci			return err;
636062306a36Sopenharmony_ci		}
636162306a36Sopenharmony_ci		/* Allocate and set up VF Information. */
636262306a36Sopenharmony_ci		adap->vfinfo = kcalloc(pci_sriov_get_totalvfs(pdev),
636362306a36Sopenharmony_ci				       sizeof(struct vf_info), GFP_KERNEL);
636462306a36Sopenharmony_ci		if (!adap->vfinfo) {
636562306a36Sopenharmony_ci			unregister_netdev(adap->port[0]);
636662306a36Sopenharmony_ci			free_netdev(adap->port[0]);
636762306a36Sopenharmony_ci			adap->port[0] = NULL;
636862306a36Sopenharmony_ci			return -ENOMEM;
636962306a36Sopenharmony_ci		}
637062306a36Sopenharmony_ci		cxgb4_mgmt_fill_vf_station_mac_addr(adap);
637162306a36Sopenharmony_ci	}
637262306a36Sopenharmony_ci	/* Instantiate the requested number of VFs. */
637362306a36Sopenharmony_ci	err = pci_enable_sriov(pdev, num_vfs);
637462306a36Sopenharmony_ci	if (err) {
637562306a36Sopenharmony_ci		pr_info("Unable to instantiate %d VFs\n", num_vfs);
637662306a36Sopenharmony_ci		if (!current_vfs) {
637762306a36Sopenharmony_ci			unregister_netdev(adap->port[0]);
637862306a36Sopenharmony_ci			free_netdev(adap->port[0]);
637962306a36Sopenharmony_ci			adap->port[0] = NULL;
638062306a36Sopenharmony_ci			kfree(adap->vfinfo);
638162306a36Sopenharmony_ci			adap->vfinfo = NULL;
638262306a36Sopenharmony_ci		}
638362306a36Sopenharmony_ci		return err;
638462306a36Sopenharmony_ci	}
638562306a36Sopenharmony_ci
638662306a36Sopenharmony_ci	adap->num_vfs = num_vfs;
638762306a36Sopenharmony_ci	return num_vfs;
638862306a36Sopenharmony_ci}
638962306a36Sopenharmony_ci#endif /* CONFIG_PCI_IOV */
639062306a36Sopenharmony_ci
639162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) || IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE)
639262306a36Sopenharmony_ci
639362306a36Sopenharmony_cistatic int chcr_offload_state(struct adapter *adap,
639462306a36Sopenharmony_ci			      enum cxgb4_netdev_tls_ops op_val)
639562306a36Sopenharmony_ci{
639662306a36Sopenharmony_ci	switch (op_val) {
639762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
639862306a36Sopenharmony_ci	case CXGB4_TLSDEV_OPS:
639962306a36Sopenharmony_ci		if (!adap->uld[CXGB4_ULD_KTLS].handle) {
640062306a36Sopenharmony_ci			dev_dbg(adap->pdev_dev, "ch_ktls driver is not loaded\n");
640162306a36Sopenharmony_ci			return -EOPNOTSUPP;
640262306a36Sopenharmony_ci		}
640362306a36Sopenharmony_ci		if (!adap->uld[CXGB4_ULD_KTLS].tlsdev_ops) {
640462306a36Sopenharmony_ci			dev_dbg(adap->pdev_dev,
640562306a36Sopenharmony_ci				"ch_ktls driver has no registered tlsdev_ops\n");
640662306a36Sopenharmony_ci			return -EOPNOTSUPP;
640762306a36Sopenharmony_ci		}
640862306a36Sopenharmony_ci		break;
640962306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */
641062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE)
641162306a36Sopenharmony_ci	case CXGB4_XFRMDEV_OPS:
641262306a36Sopenharmony_ci		if (!adap->uld[CXGB4_ULD_IPSEC].handle) {
641362306a36Sopenharmony_ci			dev_dbg(adap->pdev_dev, "chipsec driver is not loaded\n");
641462306a36Sopenharmony_ci			return -EOPNOTSUPP;
641562306a36Sopenharmony_ci		}
641662306a36Sopenharmony_ci		if (!adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops) {
641762306a36Sopenharmony_ci			dev_dbg(adap->pdev_dev,
641862306a36Sopenharmony_ci				"chipsec driver has no registered xfrmdev_ops\n");
641962306a36Sopenharmony_ci			return -EOPNOTSUPP;
642062306a36Sopenharmony_ci		}
642162306a36Sopenharmony_ci		break;
642262306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */
642362306a36Sopenharmony_ci	default:
642462306a36Sopenharmony_ci		dev_dbg(adap->pdev_dev,
642562306a36Sopenharmony_ci			"driver has no support for offload %d\n", op_val);
642662306a36Sopenharmony_ci		return -EOPNOTSUPP;
642762306a36Sopenharmony_ci	}
642862306a36Sopenharmony_ci
642962306a36Sopenharmony_ci	return 0;
643062306a36Sopenharmony_ci}
643162306a36Sopenharmony_ci
643262306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE || CONFIG_CHELSIO_IPSEC_INLINE */
643362306a36Sopenharmony_ci
643462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
643562306a36Sopenharmony_ci
643662306a36Sopenharmony_cistatic int cxgb4_ktls_dev_add(struct net_device *netdev, struct sock *sk,
643762306a36Sopenharmony_ci			      enum tls_offload_ctx_dir direction,
643862306a36Sopenharmony_ci			      struct tls_crypto_info *crypto_info,
643962306a36Sopenharmony_ci			      u32 tcp_sn)
644062306a36Sopenharmony_ci{
644162306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(netdev);
644262306a36Sopenharmony_ci	int ret;
644362306a36Sopenharmony_ci
644462306a36Sopenharmony_ci	mutex_lock(&uld_mutex);
644562306a36Sopenharmony_ci	ret = chcr_offload_state(adap, CXGB4_TLSDEV_OPS);
644662306a36Sopenharmony_ci	if (ret)
644762306a36Sopenharmony_ci		goto out_unlock;
644862306a36Sopenharmony_ci
644962306a36Sopenharmony_ci	ret = cxgb4_set_ktls_feature(adap, FW_PARAMS_PARAM_DEV_KTLS_HW_ENABLE);
645062306a36Sopenharmony_ci	if (ret)
645162306a36Sopenharmony_ci		goto out_unlock;
645262306a36Sopenharmony_ci
645362306a36Sopenharmony_ci	ret = adap->uld[CXGB4_ULD_KTLS].tlsdev_ops->tls_dev_add(netdev, sk,
645462306a36Sopenharmony_ci								direction,
645562306a36Sopenharmony_ci								crypto_info,
645662306a36Sopenharmony_ci								tcp_sn);
645762306a36Sopenharmony_ci	/* if there is a failure, clear the refcount */
645862306a36Sopenharmony_ci	if (ret)
645962306a36Sopenharmony_ci		cxgb4_set_ktls_feature(adap,
646062306a36Sopenharmony_ci				       FW_PARAMS_PARAM_DEV_KTLS_HW_DISABLE);
646162306a36Sopenharmony_ciout_unlock:
646262306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
646362306a36Sopenharmony_ci	return ret;
646462306a36Sopenharmony_ci}
646562306a36Sopenharmony_ci
646662306a36Sopenharmony_cistatic void cxgb4_ktls_dev_del(struct net_device *netdev,
646762306a36Sopenharmony_ci			       struct tls_context *tls_ctx,
646862306a36Sopenharmony_ci			       enum tls_offload_ctx_dir direction)
646962306a36Sopenharmony_ci{
647062306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(netdev);
647162306a36Sopenharmony_ci
647262306a36Sopenharmony_ci	mutex_lock(&uld_mutex);
647362306a36Sopenharmony_ci	if (chcr_offload_state(adap, CXGB4_TLSDEV_OPS))
647462306a36Sopenharmony_ci		goto out_unlock;
647562306a36Sopenharmony_ci
647662306a36Sopenharmony_ci	adap->uld[CXGB4_ULD_KTLS].tlsdev_ops->tls_dev_del(netdev, tls_ctx,
647762306a36Sopenharmony_ci							  direction);
647862306a36Sopenharmony_ci
647962306a36Sopenharmony_ciout_unlock:
648062306a36Sopenharmony_ci	cxgb4_set_ktls_feature(adap, FW_PARAMS_PARAM_DEV_KTLS_HW_DISABLE);
648162306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
648262306a36Sopenharmony_ci}
648362306a36Sopenharmony_ci
648462306a36Sopenharmony_cistatic const struct tlsdev_ops cxgb4_ktls_ops = {
648562306a36Sopenharmony_ci	.tls_dev_add = cxgb4_ktls_dev_add,
648662306a36Sopenharmony_ci	.tls_dev_del = cxgb4_ktls_dev_del,
648762306a36Sopenharmony_ci};
648862306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */
648962306a36Sopenharmony_ci
649062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE)
649162306a36Sopenharmony_ci
649262306a36Sopenharmony_cistatic int cxgb4_xfrm_add_state(struct xfrm_state *x,
649362306a36Sopenharmony_ci				struct netlink_ext_ack *extack)
649462306a36Sopenharmony_ci{
649562306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(x->xso.dev);
649662306a36Sopenharmony_ci	int ret;
649762306a36Sopenharmony_ci
649862306a36Sopenharmony_ci	if (!mutex_trylock(&uld_mutex)) {
649962306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "crypto uld critical resource is under use");
650062306a36Sopenharmony_ci		return -EBUSY;
650162306a36Sopenharmony_ci	}
650262306a36Sopenharmony_ci	ret = chcr_offload_state(adap, CXGB4_XFRMDEV_OPS);
650362306a36Sopenharmony_ci	if (ret)
650462306a36Sopenharmony_ci		goto out_unlock;
650562306a36Sopenharmony_ci
650662306a36Sopenharmony_ci	ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_add(x, extack);
650762306a36Sopenharmony_ci
650862306a36Sopenharmony_ciout_unlock:
650962306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
651062306a36Sopenharmony_ci
651162306a36Sopenharmony_ci	return ret;
651262306a36Sopenharmony_ci}
651362306a36Sopenharmony_ci
651462306a36Sopenharmony_cistatic void cxgb4_xfrm_del_state(struct xfrm_state *x)
651562306a36Sopenharmony_ci{
651662306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(x->xso.dev);
651762306a36Sopenharmony_ci
651862306a36Sopenharmony_ci	if (!mutex_trylock(&uld_mutex)) {
651962306a36Sopenharmony_ci		dev_dbg(adap->pdev_dev,
652062306a36Sopenharmony_ci			"crypto uld critical resource is under use\n");
652162306a36Sopenharmony_ci		return;
652262306a36Sopenharmony_ci	}
652362306a36Sopenharmony_ci	if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS))
652462306a36Sopenharmony_ci		goto out_unlock;
652562306a36Sopenharmony_ci
652662306a36Sopenharmony_ci	adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_delete(x);
652762306a36Sopenharmony_ci
652862306a36Sopenharmony_ciout_unlock:
652962306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
653062306a36Sopenharmony_ci}
653162306a36Sopenharmony_ci
653262306a36Sopenharmony_cistatic void cxgb4_xfrm_free_state(struct xfrm_state *x)
653362306a36Sopenharmony_ci{
653462306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(x->xso.dev);
653562306a36Sopenharmony_ci
653662306a36Sopenharmony_ci	if (!mutex_trylock(&uld_mutex)) {
653762306a36Sopenharmony_ci		dev_dbg(adap->pdev_dev,
653862306a36Sopenharmony_ci			"crypto uld critical resource is under use\n");
653962306a36Sopenharmony_ci		return;
654062306a36Sopenharmony_ci	}
654162306a36Sopenharmony_ci	if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS))
654262306a36Sopenharmony_ci		goto out_unlock;
654362306a36Sopenharmony_ci
654462306a36Sopenharmony_ci	adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_free(x);
654562306a36Sopenharmony_ci
654662306a36Sopenharmony_ciout_unlock:
654762306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
654862306a36Sopenharmony_ci}
654962306a36Sopenharmony_ci
655062306a36Sopenharmony_cistatic bool cxgb4_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
655162306a36Sopenharmony_ci{
655262306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(x->xso.dev);
655362306a36Sopenharmony_ci	bool ret = false;
655462306a36Sopenharmony_ci
655562306a36Sopenharmony_ci	if (!mutex_trylock(&uld_mutex)) {
655662306a36Sopenharmony_ci		dev_dbg(adap->pdev_dev,
655762306a36Sopenharmony_ci			"crypto uld critical resource is under use\n");
655862306a36Sopenharmony_ci		return ret;
655962306a36Sopenharmony_ci	}
656062306a36Sopenharmony_ci	if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS))
656162306a36Sopenharmony_ci		goto out_unlock;
656262306a36Sopenharmony_ci
656362306a36Sopenharmony_ci	ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_offload_ok(skb, x);
656462306a36Sopenharmony_ci
656562306a36Sopenharmony_ciout_unlock:
656662306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
656762306a36Sopenharmony_ci	return ret;
656862306a36Sopenharmony_ci}
656962306a36Sopenharmony_ci
657062306a36Sopenharmony_cistatic void cxgb4_advance_esn_state(struct xfrm_state *x)
657162306a36Sopenharmony_ci{
657262306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(x->xso.dev);
657362306a36Sopenharmony_ci
657462306a36Sopenharmony_ci	if (!mutex_trylock(&uld_mutex)) {
657562306a36Sopenharmony_ci		dev_dbg(adap->pdev_dev,
657662306a36Sopenharmony_ci			"crypto uld critical resource is under use\n");
657762306a36Sopenharmony_ci		return;
657862306a36Sopenharmony_ci	}
657962306a36Sopenharmony_ci	if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS))
658062306a36Sopenharmony_ci		goto out_unlock;
658162306a36Sopenharmony_ci
658262306a36Sopenharmony_ci	adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_advance_esn(x);
658362306a36Sopenharmony_ci
658462306a36Sopenharmony_ciout_unlock:
658562306a36Sopenharmony_ci	mutex_unlock(&uld_mutex);
658662306a36Sopenharmony_ci}
658762306a36Sopenharmony_ci
658862306a36Sopenharmony_cistatic const struct xfrmdev_ops cxgb4_xfrmdev_ops = {
658962306a36Sopenharmony_ci	.xdo_dev_state_add      = cxgb4_xfrm_add_state,
659062306a36Sopenharmony_ci	.xdo_dev_state_delete   = cxgb4_xfrm_del_state,
659162306a36Sopenharmony_ci	.xdo_dev_state_free     = cxgb4_xfrm_free_state,
659262306a36Sopenharmony_ci	.xdo_dev_offload_ok     = cxgb4_ipsec_offload_ok,
659362306a36Sopenharmony_ci	.xdo_dev_state_advance_esn = cxgb4_advance_esn_state,
659462306a36Sopenharmony_ci};
659562306a36Sopenharmony_ci
659662306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */
659762306a36Sopenharmony_ci
659862306a36Sopenharmony_cistatic int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
659962306a36Sopenharmony_ci{
660062306a36Sopenharmony_ci	struct net_device *netdev;
660162306a36Sopenharmony_ci	struct adapter *adapter;
660262306a36Sopenharmony_ci	static int adap_idx = 1;
660362306a36Sopenharmony_ci	int s_qpp, qpp, num_seg;
660462306a36Sopenharmony_ci	struct port_info *pi;
660562306a36Sopenharmony_ci	enum chip_type chip;
660662306a36Sopenharmony_ci	void __iomem *regs;
660762306a36Sopenharmony_ci	int func, chip_ver;
660862306a36Sopenharmony_ci	u16 device_id;
660962306a36Sopenharmony_ci	int i, err;
661062306a36Sopenharmony_ci	u32 whoami;
661162306a36Sopenharmony_ci
661262306a36Sopenharmony_ci	err = pci_request_regions(pdev, KBUILD_MODNAME);
661362306a36Sopenharmony_ci	if (err) {
661462306a36Sopenharmony_ci		/* Just info, some other driver may have claimed the device. */
661562306a36Sopenharmony_ci		dev_info(&pdev->dev, "cannot obtain PCI resources\n");
661662306a36Sopenharmony_ci		return err;
661762306a36Sopenharmony_ci	}
661862306a36Sopenharmony_ci
661962306a36Sopenharmony_ci	err = pci_enable_device(pdev);
662062306a36Sopenharmony_ci	if (err) {
662162306a36Sopenharmony_ci		dev_err(&pdev->dev, "cannot enable PCI device\n");
662262306a36Sopenharmony_ci		goto out_release_regions;
662362306a36Sopenharmony_ci	}
662462306a36Sopenharmony_ci
662562306a36Sopenharmony_ci	regs = pci_ioremap_bar(pdev, 0);
662662306a36Sopenharmony_ci	if (!regs) {
662762306a36Sopenharmony_ci		dev_err(&pdev->dev, "cannot map device registers\n");
662862306a36Sopenharmony_ci		err = -ENOMEM;
662962306a36Sopenharmony_ci		goto out_disable_device;
663062306a36Sopenharmony_ci	}
663162306a36Sopenharmony_ci
663262306a36Sopenharmony_ci	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
663362306a36Sopenharmony_ci	if (!adapter) {
663462306a36Sopenharmony_ci		err = -ENOMEM;
663562306a36Sopenharmony_ci		goto out_unmap_bar0;
663662306a36Sopenharmony_ci	}
663762306a36Sopenharmony_ci
663862306a36Sopenharmony_ci	adapter->regs = regs;
663962306a36Sopenharmony_ci	err = t4_wait_dev_ready(regs);
664062306a36Sopenharmony_ci	if (err < 0)
664162306a36Sopenharmony_ci		goto out_free_adapter;
664262306a36Sopenharmony_ci
664362306a36Sopenharmony_ci	/* We control everything through one PF */
664462306a36Sopenharmony_ci	whoami = t4_read_reg(adapter, PL_WHOAMI_A);
664562306a36Sopenharmony_ci	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
664662306a36Sopenharmony_ci	chip = t4_get_chip_type(adapter, CHELSIO_PCI_ID_VER(device_id));
664762306a36Sopenharmony_ci	if ((int)chip < 0) {
664862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Device %d is not supported\n", device_id);
664962306a36Sopenharmony_ci		err = chip;
665062306a36Sopenharmony_ci		goto out_free_adapter;
665162306a36Sopenharmony_ci	}
665262306a36Sopenharmony_ci	chip_ver = CHELSIO_CHIP_VERSION(chip);
665362306a36Sopenharmony_ci	func = chip_ver <= CHELSIO_T5 ?
665462306a36Sopenharmony_ci	       SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami);
665562306a36Sopenharmony_ci
665662306a36Sopenharmony_ci	adapter->pdev = pdev;
665762306a36Sopenharmony_ci	adapter->pdev_dev = &pdev->dev;
665862306a36Sopenharmony_ci	adapter->name = pci_name(pdev);
665962306a36Sopenharmony_ci	adapter->mbox = func;
666062306a36Sopenharmony_ci	adapter->pf = func;
666162306a36Sopenharmony_ci	adapter->params.chip = chip;
666262306a36Sopenharmony_ci	adapter->adap_idx = adap_idx;
666362306a36Sopenharmony_ci	adapter->msg_enable = DFLT_MSG_ENABLE;
666462306a36Sopenharmony_ci	adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) +
666562306a36Sopenharmony_ci				    (sizeof(struct mbox_cmd) *
666662306a36Sopenharmony_ci				     T4_OS_LOG_MBOX_CMDS),
666762306a36Sopenharmony_ci				    GFP_KERNEL);
666862306a36Sopenharmony_ci	if (!adapter->mbox_log) {
666962306a36Sopenharmony_ci		err = -ENOMEM;
667062306a36Sopenharmony_ci		goto out_free_adapter;
667162306a36Sopenharmony_ci	}
667262306a36Sopenharmony_ci	spin_lock_init(&adapter->mbox_lock);
667362306a36Sopenharmony_ci	INIT_LIST_HEAD(&adapter->mlist.list);
667462306a36Sopenharmony_ci	adapter->mbox_log->size = T4_OS_LOG_MBOX_CMDS;
667562306a36Sopenharmony_ci	pci_set_drvdata(pdev, adapter);
667662306a36Sopenharmony_ci
667762306a36Sopenharmony_ci	if (func != ent->driver_data) {
667862306a36Sopenharmony_ci		pci_disable_device(pdev);
667962306a36Sopenharmony_ci		pci_save_state(pdev);        /* to restore SR-IOV later */
668062306a36Sopenharmony_ci		return 0;
668162306a36Sopenharmony_ci	}
668262306a36Sopenharmony_ci
668362306a36Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
668462306a36Sopenharmony_ci	if (err) {
668562306a36Sopenharmony_ci		dev_err(&pdev->dev, "no usable DMA configuration\n");
668662306a36Sopenharmony_ci		goto out_free_adapter;
668762306a36Sopenharmony_ci	}
668862306a36Sopenharmony_ci
668962306a36Sopenharmony_ci	pci_set_master(pdev);
669062306a36Sopenharmony_ci	pci_save_state(pdev);
669162306a36Sopenharmony_ci	adap_idx++;
669262306a36Sopenharmony_ci	adapter->workq = create_singlethread_workqueue("cxgb4");
669362306a36Sopenharmony_ci	if (!adapter->workq) {
669462306a36Sopenharmony_ci		err = -ENOMEM;
669562306a36Sopenharmony_ci		goto out_free_adapter;
669662306a36Sopenharmony_ci	}
669762306a36Sopenharmony_ci
669862306a36Sopenharmony_ci	/* PCI device has been enabled */
669962306a36Sopenharmony_ci	adapter->flags |= CXGB4_DEV_ENABLED;
670062306a36Sopenharmony_ci	memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map));
670162306a36Sopenharmony_ci
670262306a36Sopenharmony_ci	/* If possible, we use PCIe Relaxed Ordering Attribute to deliver
670362306a36Sopenharmony_ci	 * Ingress Packet Data to Free List Buffers in order to allow for
670462306a36Sopenharmony_ci	 * chipset performance optimizations between the Root Complex and
670562306a36Sopenharmony_ci	 * Memory Controllers.  (Messages to the associated Ingress Queue
670662306a36Sopenharmony_ci	 * notifying new Packet Placement in the Free Lists Buffers will be
670762306a36Sopenharmony_ci	 * send without the Relaxed Ordering Attribute thus guaranteeing that
670862306a36Sopenharmony_ci	 * all preceding PCIe Transaction Layer Packets will be processed
670962306a36Sopenharmony_ci	 * first.)  But some Root Complexes have various issues with Upstream
671062306a36Sopenharmony_ci	 * Transaction Layer Packets with the Relaxed Ordering Attribute set.
671162306a36Sopenharmony_ci	 * The PCIe devices which under the Root Complexes will be cleared the
671262306a36Sopenharmony_ci	 * Relaxed Ordering bit in the configuration space, So we check our
671362306a36Sopenharmony_ci	 * PCIe configuration space to see if it's flagged with advice against
671462306a36Sopenharmony_ci	 * using Relaxed Ordering.
671562306a36Sopenharmony_ci	 */
671662306a36Sopenharmony_ci	if (!pcie_relaxed_ordering_enabled(pdev))
671762306a36Sopenharmony_ci		adapter->flags |= CXGB4_ROOT_NO_RELAXED_ORDERING;
671862306a36Sopenharmony_ci
671962306a36Sopenharmony_ci	spin_lock_init(&adapter->stats_lock);
672062306a36Sopenharmony_ci	spin_lock_init(&adapter->tid_release_lock);
672162306a36Sopenharmony_ci	spin_lock_init(&adapter->win0_lock);
672262306a36Sopenharmony_ci
672362306a36Sopenharmony_ci	INIT_WORK(&adapter->tid_release_task, process_tid_release_list);
672462306a36Sopenharmony_ci	INIT_WORK(&adapter->db_full_task, process_db_full);
672562306a36Sopenharmony_ci	INIT_WORK(&adapter->db_drop_task, process_db_drop);
672662306a36Sopenharmony_ci	INIT_WORK(&adapter->fatal_err_notify_task, notify_fatal_err);
672762306a36Sopenharmony_ci
672862306a36Sopenharmony_ci	err = t4_prep_adapter(adapter);
672962306a36Sopenharmony_ci	if (err)
673062306a36Sopenharmony_ci		goto out_free_adapter;
673162306a36Sopenharmony_ci
673262306a36Sopenharmony_ci	if (is_kdump_kernel()) {
673362306a36Sopenharmony_ci		/* Collect hardware state and append to /proc/vmcore */
673462306a36Sopenharmony_ci		err = cxgb4_cudbg_vmcore_add_dump(adapter);
673562306a36Sopenharmony_ci		if (err) {
673662306a36Sopenharmony_ci			dev_warn(adapter->pdev_dev,
673762306a36Sopenharmony_ci				 "Fail collecting vmcore device dump, err: %d. Continuing\n",
673862306a36Sopenharmony_ci				 err);
673962306a36Sopenharmony_ci			err = 0;
674062306a36Sopenharmony_ci		}
674162306a36Sopenharmony_ci	}
674262306a36Sopenharmony_ci
674362306a36Sopenharmony_ci	if (!is_t4(adapter->params.chip)) {
674462306a36Sopenharmony_ci		s_qpp = (QUEUESPERPAGEPF0_S +
674562306a36Sopenharmony_ci			(QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) *
674662306a36Sopenharmony_ci			adapter->pf);
674762306a36Sopenharmony_ci		qpp = 1 << QUEUESPERPAGEPF0_G(t4_read_reg(adapter,
674862306a36Sopenharmony_ci		      SGE_EGRESS_QUEUES_PER_PAGE_PF_A) >> s_qpp);
674962306a36Sopenharmony_ci		num_seg = PAGE_SIZE / SEGMENT_SIZE;
675062306a36Sopenharmony_ci
675162306a36Sopenharmony_ci		/* Each segment size is 128B. Write coalescing is enabled only
675262306a36Sopenharmony_ci		 * when SGE_EGRESS_QUEUES_PER_PAGE_PF reg value for the
675362306a36Sopenharmony_ci		 * queue is less no of segments that can be accommodated in
675462306a36Sopenharmony_ci		 * a page size.
675562306a36Sopenharmony_ci		 */
675662306a36Sopenharmony_ci		if (qpp > num_seg) {
675762306a36Sopenharmony_ci			dev_err(&pdev->dev,
675862306a36Sopenharmony_ci				"Incorrect number of egress queues per page\n");
675962306a36Sopenharmony_ci			err = -EINVAL;
676062306a36Sopenharmony_ci			goto out_free_adapter;
676162306a36Sopenharmony_ci		}
676262306a36Sopenharmony_ci		adapter->bar2 = ioremap_wc(pci_resource_start(pdev, 2),
676362306a36Sopenharmony_ci		pci_resource_len(pdev, 2));
676462306a36Sopenharmony_ci		if (!adapter->bar2) {
676562306a36Sopenharmony_ci			dev_err(&pdev->dev, "cannot map device bar2 region\n");
676662306a36Sopenharmony_ci			err = -ENOMEM;
676762306a36Sopenharmony_ci			goto out_free_adapter;
676862306a36Sopenharmony_ci		}
676962306a36Sopenharmony_ci	}
677062306a36Sopenharmony_ci
677162306a36Sopenharmony_ci	setup_memwin(adapter);
677262306a36Sopenharmony_ci	err = adap_init0(adapter, 0);
677362306a36Sopenharmony_ci	if (err)
677462306a36Sopenharmony_ci		goto out_unmap_bar;
677562306a36Sopenharmony_ci
677662306a36Sopenharmony_ci	setup_memwin_rdma(adapter);
677762306a36Sopenharmony_ci
677862306a36Sopenharmony_ci	/* configure SGE_STAT_CFG_A to read WC stats */
677962306a36Sopenharmony_ci	if (!is_t4(adapter->params.chip))
678062306a36Sopenharmony_ci		t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7) |
678162306a36Sopenharmony_ci			     (is_t5(adapter->params.chip) ? STATMODE_V(0) :
678262306a36Sopenharmony_ci			      T6_STATMODE_V(0)));
678362306a36Sopenharmony_ci
678462306a36Sopenharmony_ci	/* Initialize hash mac addr list */
678562306a36Sopenharmony_ci	INIT_LIST_HEAD(&adapter->mac_hlist);
678662306a36Sopenharmony_ci
678762306a36Sopenharmony_ci	for_each_port(adapter, i) {
678862306a36Sopenharmony_ci		/* For supporting MQPRIO Offload, need some extra
678962306a36Sopenharmony_ci		 * queues for each ETHOFLD TIDs. Keep it equal to
679062306a36Sopenharmony_ci		 * MAX_ATIDs for now. Once we connect to firmware
679162306a36Sopenharmony_ci		 * later and query the EOTID params, we'll come to
679262306a36Sopenharmony_ci		 * know the actual # of EOTIDs supported.
679362306a36Sopenharmony_ci		 */
679462306a36Sopenharmony_ci		netdev = alloc_etherdev_mq(sizeof(struct port_info),
679562306a36Sopenharmony_ci					   MAX_ETH_QSETS + MAX_ATIDS);
679662306a36Sopenharmony_ci		if (!netdev) {
679762306a36Sopenharmony_ci			err = -ENOMEM;
679862306a36Sopenharmony_ci			goto out_free_dev;
679962306a36Sopenharmony_ci		}
680062306a36Sopenharmony_ci
680162306a36Sopenharmony_ci		SET_NETDEV_DEV(netdev, &pdev->dev);
680262306a36Sopenharmony_ci
680362306a36Sopenharmony_ci		adapter->port[i] = netdev;
680462306a36Sopenharmony_ci		pi = netdev_priv(netdev);
680562306a36Sopenharmony_ci		pi->adapter = adapter;
680662306a36Sopenharmony_ci		pi->xact_addr_filt = -1;
680762306a36Sopenharmony_ci		pi->port_id = i;
680862306a36Sopenharmony_ci		netdev->irq = pdev->irq;
680962306a36Sopenharmony_ci
681062306a36Sopenharmony_ci		netdev->hw_features = NETIF_F_SG | TSO_FLAGS |
681162306a36Sopenharmony_ci			NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
681262306a36Sopenharmony_ci			NETIF_F_RXCSUM | NETIF_F_RXHASH | NETIF_F_GRO |
681362306a36Sopenharmony_ci			NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
681462306a36Sopenharmony_ci			NETIF_F_HW_TC | NETIF_F_NTUPLE | NETIF_F_HIGHDMA;
681562306a36Sopenharmony_ci
681662306a36Sopenharmony_ci		if (chip_ver > CHELSIO_T5) {
681762306a36Sopenharmony_ci			netdev->hw_enc_features |= NETIF_F_IP_CSUM |
681862306a36Sopenharmony_ci						   NETIF_F_IPV6_CSUM |
681962306a36Sopenharmony_ci						   NETIF_F_RXCSUM |
682062306a36Sopenharmony_ci						   NETIF_F_GSO_UDP_TUNNEL |
682162306a36Sopenharmony_ci						   NETIF_F_GSO_UDP_TUNNEL_CSUM |
682262306a36Sopenharmony_ci						   NETIF_F_TSO | NETIF_F_TSO6;
682362306a36Sopenharmony_ci
682462306a36Sopenharmony_ci			netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL |
682562306a36Sopenharmony_ci					       NETIF_F_GSO_UDP_TUNNEL_CSUM |
682662306a36Sopenharmony_ci					       NETIF_F_HW_TLS_RECORD;
682762306a36Sopenharmony_ci
682862306a36Sopenharmony_ci			if (adapter->rawf_cnt)
682962306a36Sopenharmony_ci				netdev->udp_tunnel_nic_info = &cxgb_udp_tunnels;
683062306a36Sopenharmony_ci		}
683162306a36Sopenharmony_ci
683262306a36Sopenharmony_ci		netdev->features |= netdev->hw_features;
683362306a36Sopenharmony_ci		netdev->vlan_features = netdev->features & VLAN_FEAT;
683462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
683562306a36Sopenharmony_ci		if (pi->adapter->params.crypto & FW_CAPS_CONFIG_TLS_HW) {
683662306a36Sopenharmony_ci			netdev->hw_features |= NETIF_F_HW_TLS_TX;
683762306a36Sopenharmony_ci			netdev->tlsdev_ops = &cxgb4_ktls_ops;
683862306a36Sopenharmony_ci			/* initialize the refcount */
683962306a36Sopenharmony_ci			refcount_set(&pi->adapter->chcr_ktls.ktls_refcount, 0);
684062306a36Sopenharmony_ci		}
684162306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */
684262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE)
684362306a36Sopenharmony_ci		if (pi->adapter->params.crypto & FW_CAPS_CONFIG_IPSEC_INLINE) {
684462306a36Sopenharmony_ci			netdev->hw_enc_features |= NETIF_F_HW_ESP;
684562306a36Sopenharmony_ci			netdev->features |= NETIF_F_HW_ESP;
684662306a36Sopenharmony_ci			netdev->xfrmdev_ops = &cxgb4_xfrmdev_ops;
684762306a36Sopenharmony_ci		}
684862306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */
684962306a36Sopenharmony_ci
685062306a36Sopenharmony_ci		netdev->priv_flags |= IFF_UNICAST_FLT;
685162306a36Sopenharmony_ci
685262306a36Sopenharmony_ci		/* MTU range: 81 - 9600 */
685362306a36Sopenharmony_ci		netdev->min_mtu = 81;              /* accommodate SACK */
685462306a36Sopenharmony_ci		netdev->max_mtu = MAX_MTU;
685562306a36Sopenharmony_ci
685662306a36Sopenharmony_ci		netdev->netdev_ops = &cxgb4_netdev_ops;
685762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
685862306a36Sopenharmony_ci		netdev->dcbnl_ops = &cxgb4_dcb_ops;
685962306a36Sopenharmony_ci		cxgb4_dcb_state_init(netdev);
686062306a36Sopenharmony_ci		cxgb4_dcb_version_init(netdev);
686162306a36Sopenharmony_ci#endif
686262306a36Sopenharmony_ci		cxgb4_set_ethtool_ops(netdev);
686362306a36Sopenharmony_ci	}
686462306a36Sopenharmony_ci
686562306a36Sopenharmony_ci	cxgb4_init_ethtool_dump(adapter);
686662306a36Sopenharmony_ci
686762306a36Sopenharmony_ci	pci_set_drvdata(pdev, adapter);
686862306a36Sopenharmony_ci
686962306a36Sopenharmony_ci	if (adapter->flags & CXGB4_FW_OK) {
687062306a36Sopenharmony_ci		err = t4_port_init(adapter, func, func, 0);
687162306a36Sopenharmony_ci		if (err)
687262306a36Sopenharmony_ci			goto out_free_dev;
687362306a36Sopenharmony_ci	} else if (adapter->params.nports == 1) {
687462306a36Sopenharmony_ci		/* If we don't have a connection to the firmware -- possibly
687562306a36Sopenharmony_ci		 * because of an error -- grab the raw VPD parameters so we
687662306a36Sopenharmony_ci		 * can set the proper MAC Address on the debug network
687762306a36Sopenharmony_ci		 * interface that we've created.
687862306a36Sopenharmony_ci		 */
687962306a36Sopenharmony_ci		u8 hw_addr[ETH_ALEN];
688062306a36Sopenharmony_ci		u8 *na = adapter->params.vpd.na;
688162306a36Sopenharmony_ci
688262306a36Sopenharmony_ci		err = t4_get_raw_vpd_params(adapter, &adapter->params.vpd);
688362306a36Sopenharmony_ci		if (!err) {
688462306a36Sopenharmony_ci			for (i = 0; i < ETH_ALEN; i++)
688562306a36Sopenharmony_ci				hw_addr[i] = (hex2val(na[2 * i + 0]) * 16 +
688662306a36Sopenharmony_ci					      hex2val(na[2 * i + 1]));
688762306a36Sopenharmony_ci			t4_set_hw_addr(adapter, 0, hw_addr);
688862306a36Sopenharmony_ci		}
688962306a36Sopenharmony_ci	}
689062306a36Sopenharmony_ci
689162306a36Sopenharmony_ci	if (!(adapter->flags & CXGB4_FW_OK))
689262306a36Sopenharmony_ci		goto fw_attach_fail;
689362306a36Sopenharmony_ci
689462306a36Sopenharmony_ci	/* Configure queues and allocate tables now, they can be needed as
689562306a36Sopenharmony_ci	 * soon as the first register_netdev completes.
689662306a36Sopenharmony_ci	 */
689762306a36Sopenharmony_ci	err = cfg_queues(adapter);
689862306a36Sopenharmony_ci	if (err)
689962306a36Sopenharmony_ci		goto out_free_dev;
690062306a36Sopenharmony_ci
690162306a36Sopenharmony_ci	adapter->smt = t4_init_smt();
690262306a36Sopenharmony_ci	if (!adapter->smt) {
690362306a36Sopenharmony_ci		/* We tolerate a lack of SMT, giving up some functionality */
690462306a36Sopenharmony_ci		dev_warn(&pdev->dev, "could not allocate SMT, continuing\n");
690562306a36Sopenharmony_ci	}
690662306a36Sopenharmony_ci
690762306a36Sopenharmony_ci	adapter->l2t = t4_init_l2t(adapter->l2t_start, adapter->l2t_end);
690862306a36Sopenharmony_ci	if (!adapter->l2t) {
690962306a36Sopenharmony_ci		/* We tolerate a lack of L2T, giving up some functionality */
691062306a36Sopenharmony_ci		dev_warn(&pdev->dev, "could not allocate L2T, continuing\n");
691162306a36Sopenharmony_ci		adapter->params.offload = 0;
691262306a36Sopenharmony_ci	}
691362306a36Sopenharmony_ci
691462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
691562306a36Sopenharmony_ci	if (chip_ver <= CHELSIO_T5 &&
691662306a36Sopenharmony_ci	    (!(t4_read_reg(adapter, LE_DB_CONFIG_A) & ASLIPCOMPEN_F))) {
691762306a36Sopenharmony_ci		/* CLIP functionality is not present in hardware,
691862306a36Sopenharmony_ci		 * hence disable all offload features
691962306a36Sopenharmony_ci		 */
692062306a36Sopenharmony_ci		dev_warn(&pdev->dev,
692162306a36Sopenharmony_ci			 "CLIP not enabled in hardware, continuing\n");
692262306a36Sopenharmony_ci		adapter->params.offload = 0;
692362306a36Sopenharmony_ci	} else {
692462306a36Sopenharmony_ci		adapter->clipt = t4_init_clip_tbl(adapter->clipt_start,
692562306a36Sopenharmony_ci						  adapter->clipt_end);
692662306a36Sopenharmony_ci		if (!adapter->clipt) {
692762306a36Sopenharmony_ci			/* We tolerate a lack of clip_table, giving up
692862306a36Sopenharmony_ci			 * some functionality
692962306a36Sopenharmony_ci			 */
693062306a36Sopenharmony_ci			dev_warn(&pdev->dev,
693162306a36Sopenharmony_ci				 "could not allocate Clip table, continuing\n");
693262306a36Sopenharmony_ci			adapter->params.offload = 0;
693362306a36Sopenharmony_ci		}
693462306a36Sopenharmony_ci	}
693562306a36Sopenharmony_ci#endif
693662306a36Sopenharmony_ci
693762306a36Sopenharmony_ci	for_each_port(adapter, i) {
693862306a36Sopenharmony_ci		pi = adap2pinfo(adapter, i);
693962306a36Sopenharmony_ci		pi->sched_tbl = t4_init_sched(adapter->params.nsched_cls);
694062306a36Sopenharmony_ci		if (!pi->sched_tbl)
694162306a36Sopenharmony_ci			dev_warn(&pdev->dev,
694262306a36Sopenharmony_ci				 "could not activate scheduling on port %d\n",
694362306a36Sopenharmony_ci				 i);
694462306a36Sopenharmony_ci	}
694562306a36Sopenharmony_ci
694662306a36Sopenharmony_ci	if (is_offload(adapter) || is_hashfilter(adapter)) {
694762306a36Sopenharmony_ci		if (t4_read_reg(adapter, LE_DB_CONFIG_A) & HASHEN_F) {
694862306a36Sopenharmony_ci			u32 v;
694962306a36Sopenharmony_ci
695062306a36Sopenharmony_ci			v = t4_read_reg(adapter, LE_DB_HASH_CONFIG_A);
695162306a36Sopenharmony_ci			if (chip_ver <= CHELSIO_T5) {
695262306a36Sopenharmony_ci				adapter->tids.nhash = 1 << HASHTIDSIZE_G(v);
695362306a36Sopenharmony_ci				v = t4_read_reg(adapter, LE_DB_TID_HASHBASE_A);
695462306a36Sopenharmony_ci				adapter->tids.hash_base = v / 4;
695562306a36Sopenharmony_ci			} else {
695662306a36Sopenharmony_ci				adapter->tids.nhash = HASHTBLSIZE_G(v) << 3;
695762306a36Sopenharmony_ci				v = t4_read_reg(adapter,
695862306a36Sopenharmony_ci						T6_LE_DB_HASH_TID_BASE_A);
695962306a36Sopenharmony_ci				adapter->tids.hash_base = v;
696062306a36Sopenharmony_ci			}
696162306a36Sopenharmony_ci		}
696262306a36Sopenharmony_ci	}
696362306a36Sopenharmony_ci
696462306a36Sopenharmony_ci	if (tid_init(&adapter->tids) < 0) {
696562306a36Sopenharmony_ci		dev_warn(&pdev->dev, "could not allocate TID table, "
696662306a36Sopenharmony_ci			 "continuing\n");
696762306a36Sopenharmony_ci		adapter->params.offload = 0;
696862306a36Sopenharmony_ci	} else {
696962306a36Sopenharmony_ci		adapter->tc_u32 = cxgb4_init_tc_u32(adapter);
697062306a36Sopenharmony_ci		if (!adapter->tc_u32)
697162306a36Sopenharmony_ci			dev_warn(&pdev->dev,
697262306a36Sopenharmony_ci				 "could not offload tc u32, continuing\n");
697362306a36Sopenharmony_ci
697462306a36Sopenharmony_ci		if (cxgb4_init_tc_flower(adapter))
697562306a36Sopenharmony_ci			dev_warn(&pdev->dev,
697662306a36Sopenharmony_ci				 "could not offload tc flower, continuing\n");
697762306a36Sopenharmony_ci
697862306a36Sopenharmony_ci		if (cxgb4_init_tc_mqprio(adapter))
697962306a36Sopenharmony_ci			dev_warn(&pdev->dev,
698062306a36Sopenharmony_ci				 "could not offload tc mqprio, continuing\n");
698162306a36Sopenharmony_ci
698262306a36Sopenharmony_ci		if (cxgb4_init_tc_matchall(adapter))
698362306a36Sopenharmony_ci			dev_warn(&pdev->dev,
698462306a36Sopenharmony_ci				 "could not offload tc matchall, continuing\n");
698562306a36Sopenharmony_ci		if (cxgb4_init_ethtool_filters(adapter))
698662306a36Sopenharmony_ci			dev_warn(&pdev->dev,
698762306a36Sopenharmony_ci				 "could not initialize ethtool filters, continuing\n");
698862306a36Sopenharmony_ci	}
698962306a36Sopenharmony_ci
699062306a36Sopenharmony_ci	/* See what interrupts we'll be using */
699162306a36Sopenharmony_ci	if (msi > 1 && enable_msix(adapter) == 0)
699262306a36Sopenharmony_ci		adapter->flags |= CXGB4_USING_MSIX;
699362306a36Sopenharmony_ci	else if (msi > 0 && pci_enable_msi(pdev) == 0) {
699462306a36Sopenharmony_ci		adapter->flags |= CXGB4_USING_MSI;
699562306a36Sopenharmony_ci		if (msi > 1)
699662306a36Sopenharmony_ci			free_msix_info(adapter);
699762306a36Sopenharmony_ci	}
699862306a36Sopenharmony_ci
699962306a36Sopenharmony_ci	/* check for PCI Express bandwidth capabiltites */
700062306a36Sopenharmony_ci	pcie_print_link_status(pdev);
700162306a36Sopenharmony_ci
700262306a36Sopenharmony_ci	cxgb4_init_mps_ref_entries(adapter);
700362306a36Sopenharmony_ci
700462306a36Sopenharmony_ci	err = init_rss(adapter);
700562306a36Sopenharmony_ci	if (err)
700662306a36Sopenharmony_ci		goto out_free_dev;
700762306a36Sopenharmony_ci
700862306a36Sopenharmony_ci	err = setup_non_data_intr(adapter);
700962306a36Sopenharmony_ci	if (err) {
701062306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
701162306a36Sopenharmony_ci			"Non Data interrupt allocation failed, err: %d\n", err);
701262306a36Sopenharmony_ci		goto out_free_dev;
701362306a36Sopenharmony_ci	}
701462306a36Sopenharmony_ci
701562306a36Sopenharmony_ci	err = setup_fw_sge_queues(adapter);
701662306a36Sopenharmony_ci	if (err) {
701762306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
701862306a36Sopenharmony_ci			"FW sge queue allocation failed, err %d", err);
701962306a36Sopenharmony_ci		goto out_free_dev;
702062306a36Sopenharmony_ci	}
702162306a36Sopenharmony_ci
702262306a36Sopenharmony_cifw_attach_fail:
702362306a36Sopenharmony_ci	/*
702462306a36Sopenharmony_ci	 * The card is now ready to go.  If any errors occur during device
702562306a36Sopenharmony_ci	 * registration we do not fail the whole card but rather proceed only
702662306a36Sopenharmony_ci	 * with the ports we manage to register successfully.  However we must
702762306a36Sopenharmony_ci	 * register at least one net device.
702862306a36Sopenharmony_ci	 */
702962306a36Sopenharmony_ci	for_each_port(adapter, i) {
703062306a36Sopenharmony_ci		pi = adap2pinfo(adapter, i);
703162306a36Sopenharmony_ci		adapter->port[i]->dev_port = pi->lport;
703262306a36Sopenharmony_ci		netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets);
703362306a36Sopenharmony_ci		netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets);
703462306a36Sopenharmony_ci
703562306a36Sopenharmony_ci		netif_carrier_off(adapter->port[i]);
703662306a36Sopenharmony_ci
703762306a36Sopenharmony_ci		err = register_netdev(adapter->port[i]);
703862306a36Sopenharmony_ci		if (err)
703962306a36Sopenharmony_ci			break;
704062306a36Sopenharmony_ci		adapter->chan_map[pi->tx_chan] = i;
704162306a36Sopenharmony_ci		print_port_info(adapter->port[i]);
704262306a36Sopenharmony_ci	}
704362306a36Sopenharmony_ci	if (i == 0) {
704462306a36Sopenharmony_ci		dev_err(&pdev->dev, "could not register any net devices\n");
704562306a36Sopenharmony_ci		goto out_free_dev;
704662306a36Sopenharmony_ci	}
704762306a36Sopenharmony_ci	if (err) {
704862306a36Sopenharmony_ci		dev_warn(&pdev->dev, "only %d net devices registered\n", i);
704962306a36Sopenharmony_ci		err = 0;
705062306a36Sopenharmony_ci	}
705162306a36Sopenharmony_ci
705262306a36Sopenharmony_ci	if (cxgb4_debugfs_root) {
705362306a36Sopenharmony_ci		adapter->debugfs_root = debugfs_create_dir(pci_name(pdev),
705462306a36Sopenharmony_ci							   cxgb4_debugfs_root);
705562306a36Sopenharmony_ci		setup_debugfs(adapter);
705662306a36Sopenharmony_ci	}
705762306a36Sopenharmony_ci
705862306a36Sopenharmony_ci	/* PCIe EEH recovery on powerpc platforms needs fundamental reset */
705962306a36Sopenharmony_ci	pdev->needs_freset = 1;
706062306a36Sopenharmony_ci
706162306a36Sopenharmony_ci	if (is_uld(adapter))
706262306a36Sopenharmony_ci		cxgb4_uld_enable(adapter);
706362306a36Sopenharmony_ci
706462306a36Sopenharmony_ci	if (!is_t4(adapter->params.chip))
706562306a36Sopenharmony_ci		cxgb4_ptp_init(adapter);
706662306a36Sopenharmony_ci
706762306a36Sopenharmony_ci	if (IS_REACHABLE(CONFIG_THERMAL) &&
706862306a36Sopenharmony_ci	    !is_t4(adapter->params.chip) && (adapter->flags & CXGB4_FW_OK))
706962306a36Sopenharmony_ci		cxgb4_thermal_init(adapter);
707062306a36Sopenharmony_ci
707162306a36Sopenharmony_ci	print_adapter_info(adapter);
707262306a36Sopenharmony_ci	return 0;
707362306a36Sopenharmony_ci
707462306a36Sopenharmony_ci out_free_dev:
707562306a36Sopenharmony_ci	t4_free_sge_resources(adapter);
707662306a36Sopenharmony_ci	free_some_resources(adapter);
707762306a36Sopenharmony_ci	if (adapter->flags & CXGB4_USING_MSIX)
707862306a36Sopenharmony_ci		free_msix_info(adapter);
707962306a36Sopenharmony_ci	if (adapter->num_uld || adapter->num_ofld_uld)
708062306a36Sopenharmony_ci		t4_uld_mem_free(adapter);
708162306a36Sopenharmony_ci out_unmap_bar:
708262306a36Sopenharmony_ci	if (!is_t4(adapter->params.chip))
708362306a36Sopenharmony_ci		iounmap(adapter->bar2);
708462306a36Sopenharmony_ci out_free_adapter:
708562306a36Sopenharmony_ci	if (adapter->workq)
708662306a36Sopenharmony_ci		destroy_workqueue(adapter->workq);
708762306a36Sopenharmony_ci
708862306a36Sopenharmony_ci	kfree(adapter->mbox_log);
708962306a36Sopenharmony_ci	kfree(adapter);
709062306a36Sopenharmony_ci out_unmap_bar0:
709162306a36Sopenharmony_ci	iounmap(regs);
709262306a36Sopenharmony_ci out_disable_device:
709362306a36Sopenharmony_ci	pci_disable_device(pdev);
709462306a36Sopenharmony_ci out_release_regions:
709562306a36Sopenharmony_ci	pci_release_regions(pdev);
709662306a36Sopenharmony_ci	return err;
709762306a36Sopenharmony_ci}
709862306a36Sopenharmony_ci
709962306a36Sopenharmony_cistatic void remove_one(struct pci_dev *pdev)
710062306a36Sopenharmony_ci{
710162306a36Sopenharmony_ci	struct adapter *adapter = pci_get_drvdata(pdev);
710262306a36Sopenharmony_ci	struct hash_mac_addr *entry, *tmp;
710362306a36Sopenharmony_ci
710462306a36Sopenharmony_ci	if (!adapter) {
710562306a36Sopenharmony_ci		pci_release_regions(pdev);
710662306a36Sopenharmony_ci		return;
710762306a36Sopenharmony_ci	}
710862306a36Sopenharmony_ci
710962306a36Sopenharmony_ci	/* If we allocated filters, free up state associated with any
711062306a36Sopenharmony_ci	 * valid filters ...
711162306a36Sopenharmony_ci	 */
711262306a36Sopenharmony_ci	clear_all_filters(adapter);
711362306a36Sopenharmony_ci
711462306a36Sopenharmony_ci	adapter->flags |= CXGB4_SHUTTING_DOWN;
711562306a36Sopenharmony_ci
711662306a36Sopenharmony_ci	if (adapter->pf == 4) {
711762306a36Sopenharmony_ci		int i;
711862306a36Sopenharmony_ci
711962306a36Sopenharmony_ci		/* Tear down per-adapter Work Queue first since it can contain
712062306a36Sopenharmony_ci		 * references to our adapter data structure.
712162306a36Sopenharmony_ci		 */
712262306a36Sopenharmony_ci		destroy_workqueue(adapter->workq);
712362306a36Sopenharmony_ci
712462306a36Sopenharmony_ci		detach_ulds(adapter);
712562306a36Sopenharmony_ci
712662306a36Sopenharmony_ci		for_each_port(adapter, i)
712762306a36Sopenharmony_ci			if (adapter->port[i]->reg_state == NETREG_REGISTERED)
712862306a36Sopenharmony_ci				unregister_netdev(adapter->port[i]);
712962306a36Sopenharmony_ci
713062306a36Sopenharmony_ci		t4_uld_clean_up(adapter);
713162306a36Sopenharmony_ci
713262306a36Sopenharmony_ci		adap_free_hma_mem(adapter);
713362306a36Sopenharmony_ci
713462306a36Sopenharmony_ci		disable_interrupts(adapter);
713562306a36Sopenharmony_ci
713662306a36Sopenharmony_ci		cxgb4_free_mps_ref_entries(adapter);
713762306a36Sopenharmony_ci
713862306a36Sopenharmony_ci		debugfs_remove_recursive(adapter->debugfs_root);
713962306a36Sopenharmony_ci
714062306a36Sopenharmony_ci		if (!is_t4(adapter->params.chip))
714162306a36Sopenharmony_ci			cxgb4_ptp_stop(adapter);
714262306a36Sopenharmony_ci		if (IS_REACHABLE(CONFIG_THERMAL))
714362306a36Sopenharmony_ci			cxgb4_thermal_remove(adapter);
714462306a36Sopenharmony_ci
714562306a36Sopenharmony_ci		if (adapter->flags & CXGB4_FULL_INIT_DONE)
714662306a36Sopenharmony_ci			cxgb_down(adapter);
714762306a36Sopenharmony_ci
714862306a36Sopenharmony_ci		if (adapter->flags & CXGB4_USING_MSIX)
714962306a36Sopenharmony_ci			free_msix_info(adapter);
715062306a36Sopenharmony_ci		if (adapter->num_uld || adapter->num_ofld_uld)
715162306a36Sopenharmony_ci			t4_uld_mem_free(adapter);
715262306a36Sopenharmony_ci		free_some_resources(adapter);
715362306a36Sopenharmony_ci		list_for_each_entry_safe(entry, tmp, &adapter->mac_hlist,
715462306a36Sopenharmony_ci					 list) {
715562306a36Sopenharmony_ci			list_del(&entry->list);
715662306a36Sopenharmony_ci			kfree(entry);
715762306a36Sopenharmony_ci		}
715862306a36Sopenharmony_ci
715962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
716062306a36Sopenharmony_ci		t4_cleanup_clip_tbl(adapter);
716162306a36Sopenharmony_ci#endif
716262306a36Sopenharmony_ci		if (!is_t4(adapter->params.chip))
716362306a36Sopenharmony_ci			iounmap(adapter->bar2);
716462306a36Sopenharmony_ci	}
716562306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
716662306a36Sopenharmony_ci	else {
716762306a36Sopenharmony_ci		cxgb4_iov_configure(adapter->pdev, 0);
716862306a36Sopenharmony_ci	}
716962306a36Sopenharmony_ci#endif
717062306a36Sopenharmony_ci	iounmap(adapter->regs);
717162306a36Sopenharmony_ci	if ((adapter->flags & CXGB4_DEV_ENABLED)) {
717262306a36Sopenharmony_ci		pci_disable_device(pdev);
717362306a36Sopenharmony_ci		adapter->flags &= ~CXGB4_DEV_ENABLED;
717462306a36Sopenharmony_ci	}
717562306a36Sopenharmony_ci	pci_release_regions(pdev);
717662306a36Sopenharmony_ci	kfree(adapter->mbox_log);
717762306a36Sopenharmony_ci	synchronize_rcu();
717862306a36Sopenharmony_ci	kfree(adapter);
717962306a36Sopenharmony_ci}
718062306a36Sopenharmony_ci
718162306a36Sopenharmony_ci/* "Shutdown" quiesces the device, stopping Ingress Packet and Interrupt
718262306a36Sopenharmony_ci * delivery.  This is essentially a stripped down version of the PCI remove()
718362306a36Sopenharmony_ci * function where we do the minimal amount of work necessary to shutdown any
718462306a36Sopenharmony_ci * further activity.
718562306a36Sopenharmony_ci */
718662306a36Sopenharmony_cistatic void shutdown_one(struct pci_dev *pdev)
718762306a36Sopenharmony_ci{
718862306a36Sopenharmony_ci	struct adapter *adapter = pci_get_drvdata(pdev);
718962306a36Sopenharmony_ci
719062306a36Sopenharmony_ci	/* As with remove_one() above (see extended comment), we only want do
719162306a36Sopenharmony_ci	 * do cleanup on PCI Devices which went all the way through init_one()
719262306a36Sopenharmony_ci	 * ...
719362306a36Sopenharmony_ci	 */
719462306a36Sopenharmony_ci	if (!adapter) {
719562306a36Sopenharmony_ci		pci_release_regions(pdev);
719662306a36Sopenharmony_ci		return;
719762306a36Sopenharmony_ci	}
719862306a36Sopenharmony_ci
719962306a36Sopenharmony_ci	adapter->flags |= CXGB4_SHUTTING_DOWN;
720062306a36Sopenharmony_ci
720162306a36Sopenharmony_ci	if (adapter->pf == 4) {
720262306a36Sopenharmony_ci		int i;
720362306a36Sopenharmony_ci
720462306a36Sopenharmony_ci		for_each_port(adapter, i)
720562306a36Sopenharmony_ci			if (adapter->port[i]->reg_state == NETREG_REGISTERED)
720662306a36Sopenharmony_ci				cxgb_close(adapter->port[i]);
720762306a36Sopenharmony_ci
720862306a36Sopenharmony_ci		rtnl_lock();
720962306a36Sopenharmony_ci		cxgb4_mqprio_stop_offload(adapter);
721062306a36Sopenharmony_ci		rtnl_unlock();
721162306a36Sopenharmony_ci
721262306a36Sopenharmony_ci		if (is_uld(adapter)) {
721362306a36Sopenharmony_ci			detach_ulds(adapter);
721462306a36Sopenharmony_ci			t4_uld_clean_up(adapter);
721562306a36Sopenharmony_ci		}
721662306a36Sopenharmony_ci
721762306a36Sopenharmony_ci		disable_interrupts(adapter);
721862306a36Sopenharmony_ci		disable_msi(adapter);
721962306a36Sopenharmony_ci
722062306a36Sopenharmony_ci		t4_sge_stop(adapter);
722162306a36Sopenharmony_ci		if (adapter->flags & CXGB4_FW_OK)
722262306a36Sopenharmony_ci			t4_fw_bye(adapter, adapter->mbox);
722362306a36Sopenharmony_ci	}
722462306a36Sopenharmony_ci}
722562306a36Sopenharmony_ci
722662306a36Sopenharmony_cistatic struct pci_driver cxgb4_driver = {
722762306a36Sopenharmony_ci	.name     = KBUILD_MODNAME,
722862306a36Sopenharmony_ci	.id_table = cxgb4_pci_tbl,
722962306a36Sopenharmony_ci	.probe    = init_one,
723062306a36Sopenharmony_ci	.remove   = remove_one,
723162306a36Sopenharmony_ci	.shutdown = shutdown_one,
723262306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
723362306a36Sopenharmony_ci	.sriov_configure = cxgb4_iov_configure,
723462306a36Sopenharmony_ci#endif
723562306a36Sopenharmony_ci	.err_handler = &cxgb4_eeh,
723662306a36Sopenharmony_ci};
723762306a36Sopenharmony_ci
723862306a36Sopenharmony_cistatic int __init cxgb4_init_module(void)
723962306a36Sopenharmony_ci{
724062306a36Sopenharmony_ci	int ret;
724162306a36Sopenharmony_ci
724262306a36Sopenharmony_ci	cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
724362306a36Sopenharmony_ci
724462306a36Sopenharmony_ci	ret = pci_register_driver(&cxgb4_driver);
724562306a36Sopenharmony_ci	if (ret < 0)
724662306a36Sopenharmony_ci		goto err_pci;
724762306a36Sopenharmony_ci
724862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
724962306a36Sopenharmony_ci	if (!inet6addr_registered) {
725062306a36Sopenharmony_ci		ret = register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
725162306a36Sopenharmony_ci		if (ret)
725262306a36Sopenharmony_ci			pci_unregister_driver(&cxgb4_driver);
725362306a36Sopenharmony_ci		else
725462306a36Sopenharmony_ci			inet6addr_registered = true;
725562306a36Sopenharmony_ci	}
725662306a36Sopenharmony_ci#endif
725762306a36Sopenharmony_ci
725862306a36Sopenharmony_ci	if (ret == 0)
725962306a36Sopenharmony_ci		return ret;
726062306a36Sopenharmony_ci
726162306a36Sopenharmony_cierr_pci:
726262306a36Sopenharmony_ci	debugfs_remove(cxgb4_debugfs_root);
726362306a36Sopenharmony_ci
726462306a36Sopenharmony_ci	return ret;
726562306a36Sopenharmony_ci}
726662306a36Sopenharmony_ci
726762306a36Sopenharmony_cistatic void __exit cxgb4_cleanup_module(void)
726862306a36Sopenharmony_ci{
726962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
727062306a36Sopenharmony_ci	if (inet6addr_registered) {
727162306a36Sopenharmony_ci		unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier);
727262306a36Sopenharmony_ci		inet6addr_registered = false;
727362306a36Sopenharmony_ci	}
727462306a36Sopenharmony_ci#endif
727562306a36Sopenharmony_ci	pci_unregister_driver(&cxgb4_driver);
727662306a36Sopenharmony_ci	debugfs_remove(cxgb4_debugfs_root);  /* NULL ok */
727762306a36Sopenharmony_ci}
727862306a36Sopenharmony_ci
727962306a36Sopenharmony_cimodule_init(cxgb4_init_module);
728062306a36Sopenharmony_cimodule_exit(cxgb4_cleanup_module);
7281