18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/module.h>
368c2ecf20Sopenharmony_ci#include <linux/init.h>
378c2ecf20Sopenharmony_ci#include <linux/pci.h>
388c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
398c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
408c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
418c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
428c2ecf20Sopenharmony_ci#include <linux/mdio.h>
438c2ecf20Sopenharmony_ci#include <linux/sockios.h>
448c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
458c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
468c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
478c2ecf20Sopenharmony_ci#include <linux/firmware.h>
488c2ecf20Sopenharmony_ci#include <linux/log2.h>
498c2ecf20Sopenharmony_ci#include <linux/stringify.h>
508c2ecf20Sopenharmony_ci#include <linux/sched.h>
518c2ecf20Sopenharmony_ci#include <linux/slab.h>
528c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
538c2ecf20Sopenharmony_ci#include <linux/nospec.h>
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#include "common.h"
568c2ecf20Sopenharmony_ci#include "cxgb3_ioctl.h"
578c2ecf20Sopenharmony_ci#include "regs.h"
588c2ecf20Sopenharmony_ci#include "cxgb3_offload.h"
598c2ecf20Sopenharmony_ci#include "version.h"
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#include "cxgb3_ctl_defs.h"
628c2ecf20Sopenharmony_ci#include "t3_cpl.h"
638c2ecf20Sopenharmony_ci#include "firmware_exports.h"
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cienum {
668c2ecf20Sopenharmony_ci	MAX_TXQ_ENTRIES = 16384,
678c2ecf20Sopenharmony_ci	MAX_CTRL_TXQ_ENTRIES = 1024,
688c2ecf20Sopenharmony_ci	MAX_RSPQ_ENTRIES = 16384,
698c2ecf20Sopenharmony_ci	MAX_RX_BUFFERS = 16384,
708c2ecf20Sopenharmony_ci	MAX_RX_JUMBO_BUFFERS = 16384,
718c2ecf20Sopenharmony_ci	MIN_TXQ_ENTRIES = 4,
728c2ecf20Sopenharmony_ci	MIN_CTRL_TXQ_ENTRIES = 4,
738c2ecf20Sopenharmony_ci	MIN_RSPQ_ENTRIES = 32,
748c2ecf20Sopenharmony_ci	MIN_FL_ENTRIES = 32
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define PORT_MASK ((1 << MAX_NPORTS) - 1)
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
808c2ecf20Sopenharmony_ci			 NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
818c2ecf20Sopenharmony_ci			 NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define EEPROM_MAGIC 0x38E2F10C
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define CH_DEVICE(devid, idx) \
868c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic const struct pci_device_id cxgb3_pci_tbl[] = {
898c2ecf20Sopenharmony_ci	CH_DEVICE(0x20, 0),	/* PE9000 */
908c2ecf20Sopenharmony_ci	CH_DEVICE(0x21, 1),	/* T302E */
918c2ecf20Sopenharmony_ci	CH_DEVICE(0x22, 2),	/* T310E */
928c2ecf20Sopenharmony_ci	CH_DEVICE(0x23, 3),	/* T320X */
938c2ecf20Sopenharmony_ci	CH_DEVICE(0x24, 1),	/* T302X */
948c2ecf20Sopenharmony_ci	CH_DEVICE(0x25, 3),	/* T320E */
958c2ecf20Sopenharmony_ci	CH_DEVICE(0x26, 2),	/* T310X */
968c2ecf20Sopenharmony_ci	CH_DEVICE(0x30, 2),	/* T3B10 */
978c2ecf20Sopenharmony_ci	CH_DEVICE(0x31, 3),	/* T3B20 */
988c2ecf20Sopenharmony_ci	CH_DEVICE(0x32, 1),	/* T3B02 */
998c2ecf20Sopenharmony_ci	CH_DEVICE(0x35, 6),	/* T3C20-derived T3C10 */
1008c2ecf20Sopenharmony_ci	CH_DEVICE(0x36, 3),	/* S320E-CR */
1018c2ecf20Sopenharmony_ci	CH_DEVICE(0x37, 7),	/* N320E-G2 */
1028c2ecf20Sopenharmony_ci	{0,}
1038c2ecf20Sopenharmony_ci};
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESC);
1068c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications");
1078c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
1088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int dflt_msg_enable = DFLT_MSG_ENABLE;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cimodule_param(dflt_msg_enable, int, 0644);
1138c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/*
1168c2ecf20Sopenharmony_ci * The driver uses the best interrupt scheme available on a platform in the
1178c2ecf20Sopenharmony_ci * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
1188c2ecf20Sopenharmony_ci * of these schemes the driver may consider as follows:
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * msi = 2: choose from among all three options
1218c2ecf20Sopenharmony_ci * msi = 1: only consider MSI and pin interrupts
1228c2ecf20Sopenharmony_ci * msi = 0: force pin interrupts
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_cistatic int msi = 2;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cimodule_param(msi, int, 0644);
1278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/*
1308c2ecf20Sopenharmony_ci * The driver enables offload as a default.
1318c2ecf20Sopenharmony_ci * To disable it, use ofld_disable = 1.
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic int ofld_disable = 0;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cimodule_param(ofld_disable, int, 0644);
1378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/*
1408c2ecf20Sopenharmony_ci * We have work elements that we need to cancel when an interface is taken
1418c2ecf20Sopenharmony_ci * down.  Normally the work elements would be executed by keventd but that
1428c2ecf20Sopenharmony_ci * can deadlock because of linkwatch.  If our close method takes the rtnl
1438c2ecf20Sopenharmony_ci * lock and linkwatch is ahead of our work elements in keventd, linkwatch
1448c2ecf20Sopenharmony_ci * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
1458c2ecf20Sopenharmony_ci * for our work to complete.  Get our own work queue to solve this.
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_cistruct workqueue_struct *cxgb3_wq;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/**
1508c2ecf20Sopenharmony_ci *	link_report - show link status and link speed/duplex
1518c2ecf20Sopenharmony_ci *	@dev: the port whose settings are to be reported
1528c2ecf20Sopenharmony_ci *
1538c2ecf20Sopenharmony_ci *	Shows the link status, speed, and duplex of a port.
1548c2ecf20Sopenharmony_ci */
1558c2ecf20Sopenharmony_cistatic void link_report(struct net_device *dev)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	if (!netif_carrier_ok(dev))
1588c2ecf20Sopenharmony_ci		netdev_info(dev, "link down\n");
1598c2ecf20Sopenharmony_ci	else {
1608c2ecf20Sopenharmony_ci		const char *s = "10Mbps";
1618c2ecf20Sopenharmony_ci		const struct port_info *p = netdev_priv(dev);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		switch (p->link_config.speed) {
1648c2ecf20Sopenharmony_ci		case SPEED_10000:
1658c2ecf20Sopenharmony_ci			s = "10Gbps";
1668c2ecf20Sopenharmony_ci			break;
1678c2ecf20Sopenharmony_ci		case SPEED_1000:
1688c2ecf20Sopenharmony_ci			s = "1000Mbps";
1698c2ecf20Sopenharmony_ci			break;
1708c2ecf20Sopenharmony_ci		case SPEED_100:
1718c2ecf20Sopenharmony_ci			s = "100Mbps";
1728c2ecf20Sopenharmony_ci			break;
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		netdev_info(dev, "link up, %s, %s-duplex\n",
1768c2ecf20Sopenharmony_ci			    s, p->link_config.duplex == DUPLEX_FULL
1778c2ecf20Sopenharmony_ci			    ? "full" : "half");
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic void enable_tx_fifo_drain(struct adapter *adapter,
1828c2ecf20Sopenharmony_ci				 struct port_info *pi)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
1858c2ecf20Sopenharmony_ci			 F_ENDROPPKT);
1868c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
1878c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
1888c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void disable_tx_fifo_drain(struct adapter *adapter,
1928c2ecf20Sopenharmony_ci				  struct port_info *pi)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
1958c2ecf20Sopenharmony_ci			 F_ENDROPPKT, 0);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_civoid t3_os_link_fault(struct adapter *adap, int port_id, int state)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct net_device *dev = adap->port[port_id];
2018c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (state == netif_carrier_ok(dev))
2048c2ecf20Sopenharmony_ci		return;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (state) {
2078c2ecf20Sopenharmony_ci		struct cmac *mac = &pi->mac;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		netif_carrier_on(dev);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		disable_tx_fifo_drain(adap, pi);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		/* Clear local faults */
2148c2ecf20Sopenharmony_ci		t3_xgm_intr_disable(adap, pi->port_id);
2158c2ecf20Sopenharmony_ci		t3_read_reg(adap, A_XGM_INT_STATUS +
2168c2ecf20Sopenharmony_ci				    pi->mac.offset);
2178c2ecf20Sopenharmony_ci		t3_write_reg(adap,
2188c2ecf20Sopenharmony_ci			     A_XGM_INT_CAUSE + pi->mac.offset,
2198c2ecf20Sopenharmony_ci			     F_XGM_INT);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		t3_set_reg_field(adap,
2228c2ecf20Sopenharmony_ci				 A_XGM_INT_ENABLE +
2238c2ecf20Sopenharmony_ci				 pi->mac.offset,
2248c2ecf20Sopenharmony_ci				 F_XGM_INT, F_XGM_INT);
2258c2ecf20Sopenharmony_ci		t3_xgm_intr_enable(adap, pi->port_id);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		t3_mac_enable(mac, MAC_DIRECTION_TX);
2288c2ecf20Sopenharmony_ci	} else {
2298c2ecf20Sopenharmony_ci		netif_carrier_off(dev);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		/* Flush TX FIFO */
2328c2ecf20Sopenharmony_ci		enable_tx_fifo_drain(adap, pi);
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci	link_report(dev);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/**
2388c2ecf20Sopenharmony_ci *	t3_os_link_changed - handle link status changes
2398c2ecf20Sopenharmony_ci *	@adapter: the adapter associated with the link change
2408c2ecf20Sopenharmony_ci *	@port_id: the port index whose limk status has changed
2418c2ecf20Sopenharmony_ci *	@link_stat: the new status of the link
2428c2ecf20Sopenharmony_ci *	@speed: the new speed setting
2438c2ecf20Sopenharmony_ci *	@duplex: the new duplex setting
2448c2ecf20Sopenharmony_ci *	@pause: the new flow-control setting
2458c2ecf20Sopenharmony_ci *
2468c2ecf20Sopenharmony_ci *	This is the OS-dependent handler for link status changes.  The OS
2478c2ecf20Sopenharmony_ci *	neutral handler takes care of most of the processing for these events,
2488c2ecf20Sopenharmony_ci *	then calls this handler for any OS-specific processing.
2498c2ecf20Sopenharmony_ci */
2508c2ecf20Sopenharmony_civoid t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
2518c2ecf20Sopenharmony_ci			int speed, int duplex, int pause)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct net_device *dev = adapter->port[port_id];
2548c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
2558c2ecf20Sopenharmony_ci	struct cmac *mac = &pi->mac;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* Skip changes from disabled ports. */
2588c2ecf20Sopenharmony_ci	if (!netif_running(dev))
2598c2ecf20Sopenharmony_ci		return;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (link_stat != netif_carrier_ok(dev)) {
2628c2ecf20Sopenharmony_ci		if (link_stat) {
2638c2ecf20Sopenharmony_ci			disable_tx_fifo_drain(adapter, pi);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci			t3_mac_enable(mac, MAC_DIRECTION_RX);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci			/* Clear local faults */
2688c2ecf20Sopenharmony_ci			t3_xgm_intr_disable(adapter, pi->port_id);
2698c2ecf20Sopenharmony_ci			t3_read_reg(adapter, A_XGM_INT_STATUS +
2708c2ecf20Sopenharmony_ci				    pi->mac.offset);
2718c2ecf20Sopenharmony_ci			t3_write_reg(adapter,
2728c2ecf20Sopenharmony_ci				     A_XGM_INT_CAUSE + pi->mac.offset,
2738c2ecf20Sopenharmony_ci				     F_XGM_INT);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci			t3_set_reg_field(adapter,
2768c2ecf20Sopenharmony_ci					 A_XGM_INT_ENABLE + pi->mac.offset,
2778c2ecf20Sopenharmony_ci					 F_XGM_INT, F_XGM_INT);
2788c2ecf20Sopenharmony_ci			t3_xgm_intr_enable(adapter, pi->port_id);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci			netif_carrier_on(dev);
2818c2ecf20Sopenharmony_ci		} else {
2828c2ecf20Sopenharmony_ci			netif_carrier_off(dev);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci			t3_xgm_intr_disable(adapter, pi->port_id);
2858c2ecf20Sopenharmony_ci			t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
2868c2ecf20Sopenharmony_ci			t3_set_reg_field(adapter,
2878c2ecf20Sopenharmony_ci					 A_XGM_INT_ENABLE + pi->mac.offset,
2888c2ecf20Sopenharmony_ci					 F_XGM_INT, 0);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci			if (is_10G(adapter))
2918c2ecf20Sopenharmony_ci				pi->phy.ops->power_down(&pi->phy, 1);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci			t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
2948c2ecf20Sopenharmony_ci			t3_mac_disable(mac, MAC_DIRECTION_RX);
2958c2ecf20Sopenharmony_ci			t3_link_start(&pi->phy, mac, &pi->link_config);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci			/* Flush TX FIFO */
2988c2ecf20Sopenharmony_ci			enable_tx_fifo_drain(adapter, pi);
2998c2ecf20Sopenharmony_ci		}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		link_report(dev);
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci/**
3068c2ecf20Sopenharmony_ci *	t3_os_phymod_changed - handle PHY module changes
3078c2ecf20Sopenharmony_ci *	@adap: the adapter associated with the link change
3088c2ecf20Sopenharmony_ci *	@port_id: the port index whose limk status has changed
3098c2ecf20Sopenharmony_ci *
3108c2ecf20Sopenharmony_ci *	This is the OS-dependent handler for PHY module changes.  It is
3118c2ecf20Sopenharmony_ci *	invoked when a PHY module is removed or inserted for any OS-specific
3128c2ecf20Sopenharmony_ci *	processing.
3138c2ecf20Sopenharmony_ci */
3148c2ecf20Sopenharmony_civoid t3_os_phymod_changed(struct adapter *adap, int port_id)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	static const char *mod_str[] = {
3178c2ecf20Sopenharmony_ci		NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
3188c2ecf20Sopenharmony_ci	};
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	const struct net_device *dev = adap->port[port_id];
3218c2ecf20Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (pi->phy.modtype == phy_modtype_none)
3248c2ecf20Sopenharmony_ci		netdev_info(dev, "PHY module unplugged\n");
3258c2ecf20Sopenharmony_ci	else
3268c2ecf20Sopenharmony_ci		netdev_info(dev, "%s PHY module inserted\n",
3278c2ecf20Sopenharmony_ci			    mod_str[pi->phy.modtype]);
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic void cxgb_set_rxmode(struct net_device *dev)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	t3_mac_set_rx_mode(&pi->mac, dev);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/**
3388c2ecf20Sopenharmony_ci *	link_start - enable a port
3398c2ecf20Sopenharmony_ci *	@dev: the device to enable
3408c2ecf20Sopenharmony_ci *
3418c2ecf20Sopenharmony_ci *	Performs the MAC and PHY actions needed to enable a port.
3428c2ecf20Sopenharmony_ci */
3438c2ecf20Sopenharmony_cistatic void link_start(struct net_device *dev)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
3468c2ecf20Sopenharmony_ci	struct cmac *mac = &pi->mac;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	t3_mac_reset(mac);
3498c2ecf20Sopenharmony_ci	t3_mac_set_num_ucast(mac, MAX_MAC_IDX);
3508c2ecf20Sopenharmony_ci	t3_mac_set_mtu(mac, dev->mtu);
3518c2ecf20Sopenharmony_ci	t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
3528c2ecf20Sopenharmony_ci	t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr);
3538c2ecf20Sopenharmony_ci	t3_mac_set_rx_mode(mac, dev);
3548c2ecf20Sopenharmony_ci	t3_link_start(&pi->phy, mac, &pi->link_config);
3558c2ecf20Sopenharmony_ci	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic inline void cxgb_disable_msi(struct adapter *adapter)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	if (adapter->flags & USING_MSIX) {
3618c2ecf20Sopenharmony_ci		pci_disable_msix(adapter->pdev);
3628c2ecf20Sopenharmony_ci		adapter->flags &= ~USING_MSIX;
3638c2ecf20Sopenharmony_ci	} else if (adapter->flags & USING_MSI) {
3648c2ecf20Sopenharmony_ci		pci_disable_msi(adapter->pdev);
3658c2ecf20Sopenharmony_ci		adapter->flags &= ~USING_MSI;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/*
3708c2ecf20Sopenharmony_ci * Interrupt handler for asynchronous events used with MSI-X.
3718c2ecf20Sopenharmony_ci */
3728c2ecf20Sopenharmony_cistatic irqreturn_t t3_async_intr_handler(int irq, void *cookie)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	t3_slow_intr_handler(cookie);
3758c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci/*
3798c2ecf20Sopenharmony_ci * Name the MSI-X interrupts.
3808c2ecf20Sopenharmony_ci */
3818c2ecf20Sopenharmony_cistatic void name_msix_vecs(struct adapter *adap)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
3868c2ecf20Sopenharmony_ci	adap->msix_info[0].desc[n] = 0;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	for_each_port(adap, j) {
3898c2ecf20Sopenharmony_ci		struct net_device *d = adap->port[j];
3908c2ecf20Sopenharmony_ci		const struct port_info *pi = netdev_priv(d);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci		for (i = 0; i < pi->nqsets; i++, msi_idx++) {
3938c2ecf20Sopenharmony_ci			snprintf(adap->msix_info[msi_idx].desc, n,
3948c2ecf20Sopenharmony_ci				 "%s-%d", d->name, pi->first_qset + i);
3958c2ecf20Sopenharmony_ci			adap->msix_info[msi_idx].desc[n] = 0;
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int request_msix_data_irqs(struct adapter *adap)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	int i, j, err, qidx = 0;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	for_each_port(adap, i) {
4058c2ecf20Sopenharmony_ci		int nqsets = adap2pinfo(adap, i)->nqsets;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		for (j = 0; j < nqsets; ++j) {
4088c2ecf20Sopenharmony_ci			err = request_irq(adap->msix_info[qidx + 1].vec,
4098c2ecf20Sopenharmony_ci					  t3_intr_handler(adap,
4108c2ecf20Sopenharmony_ci							  adap->sge.qs[qidx].
4118c2ecf20Sopenharmony_ci							  rspq.polling), 0,
4128c2ecf20Sopenharmony_ci					  adap->msix_info[qidx + 1].desc,
4138c2ecf20Sopenharmony_ci					  &adap->sge.qs[qidx]);
4148c2ecf20Sopenharmony_ci			if (err) {
4158c2ecf20Sopenharmony_ci				while (--qidx >= 0)
4168c2ecf20Sopenharmony_ci					free_irq(adap->msix_info[qidx + 1].vec,
4178c2ecf20Sopenharmony_ci						 &adap->sge.qs[qidx]);
4188c2ecf20Sopenharmony_ci				return err;
4198c2ecf20Sopenharmony_ci			}
4208c2ecf20Sopenharmony_ci			qidx++;
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	return 0;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic void free_irq_resources(struct adapter *adapter)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	if (adapter->flags & USING_MSIX) {
4298c2ecf20Sopenharmony_ci		int i, n = 0;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		free_irq(adapter->msix_info[0].vec, adapter);
4328c2ecf20Sopenharmony_ci		for_each_port(adapter, i)
4338c2ecf20Sopenharmony_ci			n += adap2pinfo(adapter, i)->nqsets;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		for (i = 0; i < n; ++i)
4368c2ecf20Sopenharmony_ci			free_irq(adapter->msix_info[i + 1].vec,
4378c2ecf20Sopenharmony_ci				 &adapter->sge.qs[i]);
4388c2ecf20Sopenharmony_ci	} else
4398c2ecf20Sopenharmony_ci		free_irq(adapter->pdev->irq, adapter);
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
4438c2ecf20Sopenharmony_ci			      unsigned long n)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	int attempts = 10;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
4488c2ecf20Sopenharmony_ci		if (!--attempts)
4498c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
4508c2ecf20Sopenharmony_ci		msleep(10);
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci	return 0;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic int init_tp_parity(struct adapter *adap)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	int i;
4588c2ecf20Sopenharmony_ci	struct sk_buff *skb;
4598c2ecf20Sopenharmony_ci	struct cpl_set_tcb_field *greq;
4608c2ecf20Sopenharmony_ci	unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	t3_tp_set_offload_mode(adap, 1);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++) {
4658c2ecf20Sopenharmony_ci		struct cpl_smt_write_req *req;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci		skb = alloc_skb(sizeof(*req), GFP_KERNEL);
4688c2ecf20Sopenharmony_ci		if (!skb)
4698c2ecf20Sopenharmony_ci			skb = adap->nofail_skb;
4708c2ecf20Sopenharmony_ci		if (!skb)
4718c2ecf20Sopenharmony_ci			goto alloc_skb_fail;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		req = __skb_put_zero(skb, sizeof(*req));
4748c2ecf20Sopenharmony_ci		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
4758c2ecf20Sopenharmony_ci		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
4768c2ecf20Sopenharmony_ci		req->mtu_idx = NMTUS - 1;
4778c2ecf20Sopenharmony_ci		req->iff = i;
4788c2ecf20Sopenharmony_ci		t3_mgmt_tx(adap, skb);
4798c2ecf20Sopenharmony_ci		if (skb == adap->nofail_skb) {
4808c2ecf20Sopenharmony_ci			await_mgmt_replies(adap, cnt, i + 1);
4818c2ecf20Sopenharmony_ci			adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
4828c2ecf20Sopenharmony_ci			if (!adap->nofail_skb)
4838c2ecf20Sopenharmony_ci				goto alloc_skb_fail;
4848c2ecf20Sopenharmony_ci		}
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	for (i = 0; i < 2048; i++) {
4888c2ecf20Sopenharmony_ci		struct cpl_l2t_write_req *req;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		skb = alloc_skb(sizeof(*req), GFP_KERNEL);
4918c2ecf20Sopenharmony_ci		if (!skb)
4928c2ecf20Sopenharmony_ci			skb = adap->nofail_skb;
4938c2ecf20Sopenharmony_ci		if (!skb)
4948c2ecf20Sopenharmony_ci			goto alloc_skb_fail;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		req = __skb_put_zero(skb, sizeof(*req));
4978c2ecf20Sopenharmony_ci		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
4988c2ecf20Sopenharmony_ci		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
4998c2ecf20Sopenharmony_ci		req->params = htonl(V_L2T_W_IDX(i));
5008c2ecf20Sopenharmony_ci		t3_mgmt_tx(adap, skb);
5018c2ecf20Sopenharmony_ci		if (skb == adap->nofail_skb) {
5028c2ecf20Sopenharmony_ci			await_mgmt_replies(adap, cnt, 16 + i + 1);
5038c2ecf20Sopenharmony_ci			adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
5048c2ecf20Sopenharmony_ci			if (!adap->nofail_skb)
5058c2ecf20Sopenharmony_ci				goto alloc_skb_fail;
5068c2ecf20Sopenharmony_ci		}
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	for (i = 0; i < 2048; i++) {
5108c2ecf20Sopenharmony_ci		struct cpl_rte_write_req *req;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		skb = alloc_skb(sizeof(*req), GFP_KERNEL);
5138c2ecf20Sopenharmony_ci		if (!skb)
5148c2ecf20Sopenharmony_ci			skb = adap->nofail_skb;
5158c2ecf20Sopenharmony_ci		if (!skb)
5168c2ecf20Sopenharmony_ci			goto alloc_skb_fail;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci		req = __skb_put_zero(skb, sizeof(*req));
5198c2ecf20Sopenharmony_ci		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
5208c2ecf20Sopenharmony_ci		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
5218c2ecf20Sopenharmony_ci		req->l2t_idx = htonl(V_L2T_W_IDX(i));
5228c2ecf20Sopenharmony_ci		t3_mgmt_tx(adap, skb);
5238c2ecf20Sopenharmony_ci		if (skb == adap->nofail_skb) {
5248c2ecf20Sopenharmony_ci			await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1);
5258c2ecf20Sopenharmony_ci			adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
5268c2ecf20Sopenharmony_ci			if (!adap->nofail_skb)
5278c2ecf20Sopenharmony_ci				goto alloc_skb_fail;
5288c2ecf20Sopenharmony_ci		}
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
5328c2ecf20Sopenharmony_ci	if (!skb)
5338c2ecf20Sopenharmony_ci		skb = adap->nofail_skb;
5348c2ecf20Sopenharmony_ci	if (!skb)
5358c2ecf20Sopenharmony_ci		goto alloc_skb_fail;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	greq = __skb_put_zero(skb, sizeof(*greq));
5388c2ecf20Sopenharmony_ci	greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
5398c2ecf20Sopenharmony_ci	OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
5408c2ecf20Sopenharmony_ci	greq->mask = cpu_to_be64(1);
5418c2ecf20Sopenharmony_ci	t3_mgmt_tx(adap, skb);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
5448c2ecf20Sopenharmony_ci	if (skb == adap->nofail_skb) {
5458c2ecf20Sopenharmony_ci		i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
5468c2ecf20Sopenharmony_ci		adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	t3_tp_set_offload_mode(adap, 0);
5508c2ecf20Sopenharmony_ci	return i;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cialloc_skb_fail:
5538c2ecf20Sopenharmony_ci	t3_tp_set_offload_mode(adap, 0);
5548c2ecf20Sopenharmony_ci	return -ENOMEM;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci/**
5588c2ecf20Sopenharmony_ci *	setup_rss - configure RSS
5598c2ecf20Sopenharmony_ci *	@adap: the adapter
5608c2ecf20Sopenharmony_ci *
5618c2ecf20Sopenharmony_ci *	Sets up RSS to distribute packets to multiple receive queues.  We
5628c2ecf20Sopenharmony_ci *	configure the RSS CPU lookup table to distribute to the number of HW
5638c2ecf20Sopenharmony_ci *	receive queues, and the response queue lookup table to narrow that
5648c2ecf20Sopenharmony_ci *	down to the response queues actually configured for each port.
5658c2ecf20Sopenharmony_ci *	We always configure the RSS mapping for two ports since the mapping
5668c2ecf20Sopenharmony_ci *	table has plenty of entries.
5678c2ecf20Sopenharmony_ci */
5688c2ecf20Sopenharmony_cistatic void setup_rss(struct adapter *adap)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	int i;
5718c2ecf20Sopenharmony_ci	unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
5728c2ecf20Sopenharmony_ci	unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
5738c2ecf20Sopenharmony_ci	u8 cpus[SGE_QSETS + 1];
5748c2ecf20Sopenharmony_ci	u16 rspq_map[RSS_TABLE_SIZE + 1];
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	for (i = 0; i < SGE_QSETS; ++i)
5778c2ecf20Sopenharmony_ci		cpus[i] = i;
5788c2ecf20Sopenharmony_ci	cpus[SGE_QSETS] = 0xff;	/* terminator */
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
5818c2ecf20Sopenharmony_ci		rspq_map[i] = i % nq0;
5828c2ecf20Sopenharmony_ci		rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci	rspq_map[RSS_TABLE_SIZE] = 0xffff; /* terminator */
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
5878c2ecf20Sopenharmony_ci		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
5888c2ecf20Sopenharmony_ci		      V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic void ring_dbs(struct adapter *adap)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	int i, j;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	for (i = 0; i < SGE_QSETS; i++) {
5968c2ecf20Sopenharmony_ci		struct sge_qset *qs = &adap->sge.qs[i];
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		if (qs->adap)
5998c2ecf20Sopenharmony_ci			for (j = 0; j < SGE_TXQ_PER_SET; j++)
6008c2ecf20Sopenharmony_ci				t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(qs->txq[j].cntxt_id));
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic void init_napi(struct adapter *adap)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	int i;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	for (i = 0; i < SGE_QSETS; i++) {
6098c2ecf20Sopenharmony_ci		struct sge_qset *qs = &adap->sge.qs[i];
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci		if (qs->adap)
6128c2ecf20Sopenharmony_ci			netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
6138c2ecf20Sopenharmony_ci				       64);
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	/*
6178c2ecf20Sopenharmony_ci	 * netif_napi_add() can be called only once per napi_struct because it
6188c2ecf20Sopenharmony_ci	 * adds each new napi_struct to a list.  Be careful not to call it a
6198c2ecf20Sopenharmony_ci	 * second time, e.g., during EEH recovery, by making a note of it.
6208c2ecf20Sopenharmony_ci	 */
6218c2ecf20Sopenharmony_ci	adap->flags |= NAPI_INIT;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci/*
6258c2ecf20Sopenharmony_ci * Wait until all NAPI handlers are descheduled.  This includes the handlers of
6268c2ecf20Sopenharmony_ci * both netdevices representing interfaces and the dummy ones for the extra
6278c2ecf20Sopenharmony_ci * queues.
6288c2ecf20Sopenharmony_ci */
6298c2ecf20Sopenharmony_cistatic void quiesce_rx(struct adapter *adap)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	int i;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	for (i = 0; i < SGE_QSETS; i++)
6348c2ecf20Sopenharmony_ci		if (adap->sge.qs[i].adap)
6358c2ecf20Sopenharmony_ci			napi_disable(&adap->sge.qs[i].napi);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic void enable_all_napi(struct adapter *adap)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	int i;
6418c2ecf20Sopenharmony_ci	for (i = 0; i < SGE_QSETS; i++)
6428c2ecf20Sopenharmony_ci		if (adap->sge.qs[i].adap)
6438c2ecf20Sopenharmony_ci			napi_enable(&adap->sge.qs[i].napi);
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci/**
6478c2ecf20Sopenharmony_ci *	setup_sge_qsets - configure SGE Tx/Rx/response queues
6488c2ecf20Sopenharmony_ci *	@adap: the adapter
6498c2ecf20Sopenharmony_ci *
6508c2ecf20Sopenharmony_ci *	Determines how many sets of SGE queues to use and initializes them.
6518c2ecf20Sopenharmony_ci *	We support multiple queue sets per port if we have MSI-X, otherwise
6528c2ecf20Sopenharmony_ci *	just one queue set per port.
6538c2ecf20Sopenharmony_ci */
6548c2ecf20Sopenharmony_cistatic int setup_sge_qsets(struct adapter *adap)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	int i, j, err, irq_idx = 0, qset_idx = 0;
6578c2ecf20Sopenharmony_ci	unsigned int ntxq = SGE_TXQ_PER_SET;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
6608c2ecf20Sopenharmony_ci		irq_idx = -1;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	for_each_port(adap, i) {
6638c2ecf20Sopenharmony_ci		struct net_device *dev = adap->port[i];
6648c2ecf20Sopenharmony_ci		struct port_info *pi = netdev_priv(dev);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci		pi->qs = &adap->sge.qs[pi->first_qset];
6678c2ecf20Sopenharmony_ci		for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
6688c2ecf20Sopenharmony_ci			err = t3_sge_alloc_qset(adap, qset_idx, 1,
6698c2ecf20Sopenharmony_ci				(adap->flags & USING_MSIX) ? qset_idx + 1 :
6708c2ecf20Sopenharmony_ci							     irq_idx,
6718c2ecf20Sopenharmony_ci				&adap->params.sge.qset[qset_idx], ntxq, dev,
6728c2ecf20Sopenharmony_ci				netdev_get_tx_queue(dev, j));
6738c2ecf20Sopenharmony_ci			if (err) {
6748c2ecf20Sopenharmony_ci				t3_free_sge_resources(adap);
6758c2ecf20Sopenharmony_ci				return err;
6768c2ecf20Sopenharmony_ci			}
6778c2ecf20Sopenharmony_ci		}
6788c2ecf20Sopenharmony_ci	}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	return 0;
6818c2ecf20Sopenharmony_ci}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_cistatic ssize_t attr_show(struct device *d, char *buf,
6848c2ecf20Sopenharmony_ci			 ssize_t(*format) (struct net_device *, char *))
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	ssize_t len;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	/* Synchronize with ioctls that may shut down the device */
6898c2ecf20Sopenharmony_ci	rtnl_lock();
6908c2ecf20Sopenharmony_ci	len = (*format) (to_net_dev(d), buf);
6918c2ecf20Sopenharmony_ci	rtnl_unlock();
6928c2ecf20Sopenharmony_ci	return len;
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cistatic ssize_t attr_store(struct device *d,
6968c2ecf20Sopenharmony_ci			  const char *buf, size_t len,
6978c2ecf20Sopenharmony_ci			  ssize_t(*set) (struct net_device *, unsigned int),
6988c2ecf20Sopenharmony_ci			  unsigned int min_val, unsigned int max_val)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	ssize_t ret;
7018c2ecf20Sopenharmony_ci	unsigned int val;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	if (!capable(CAP_NET_ADMIN))
7048c2ecf20Sopenharmony_ci		return -EPERM;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	ret = kstrtouint(buf, 0, &val);
7078c2ecf20Sopenharmony_ci	if (ret)
7088c2ecf20Sopenharmony_ci		return ret;
7098c2ecf20Sopenharmony_ci	if (val < min_val || val > max_val)
7108c2ecf20Sopenharmony_ci		return -EINVAL;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	rtnl_lock();
7138c2ecf20Sopenharmony_ci	ret = (*set) (to_net_dev(d), val);
7148c2ecf20Sopenharmony_ci	if (!ret)
7158c2ecf20Sopenharmony_ci		ret = len;
7168c2ecf20Sopenharmony_ci	rtnl_unlock();
7178c2ecf20Sopenharmony_ci	return ret;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci#define CXGB3_SHOW(name, val_expr) \
7218c2ecf20Sopenharmony_cistatic ssize_t format_##name(struct net_device *dev, char *buf) \
7228c2ecf20Sopenharmony_ci{ \
7238c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev); \
7248c2ecf20Sopenharmony_ci	struct adapter *adap = pi->adapter; \
7258c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", val_expr); \
7268c2ecf20Sopenharmony_ci} \
7278c2ecf20Sopenharmony_cistatic ssize_t show_##name(struct device *d, struct device_attribute *attr, \
7288c2ecf20Sopenharmony_ci			   char *buf) \
7298c2ecf20Sopenharmony_ci{ \
7308c2ecf20Sopenharmony_ci	return attr_show(d, buf, format_##name); \
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_cistatic ssize_t set_nfilters(struct net_device *dev, unsigned int val)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
7368c2ecf20Sopenharmony_ci	struct adapter *adap = pi->adapter;
7378c2ecf20Sopenharmony_ci	int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	if (adap->flags & FULL_INIT_DONE)
7408c2ecf20Sopenharmony_ci		return -EBUSY;
7418c2ecf20Sopenharmony_ci	if (val && adap->params.rev == 0)
7428c2ecf20Sopenharmony_ci		return -EINVAL;
7438c2ecf20Sopenharmony_ci	if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
7448c2ecf20Sopenharmony_ci	    min_tids)
7458c2ecf20Sopenharmony_ci		return -EINVAL;
7468c2ecf20Sopenharmony_ci	adap->params.mc5.nfilters = val;
7478c2ecf20Sopenharmony_ci	return 0;
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
7518c2ecf20Sopenharmony_ci			      const char *buf, size_t len)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	return attr_store(d, buf, len, set_nfilters, 0, ~0);
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic ssize_t set_nservers(struct net_device *dev, unsigned int val)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
7598c2ecf20Sopenharmony_ci	struct adapter *adap = pi->adapter;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (adap->flags & FULL_INIT_DONE)
7628c2ecf20Sopenharmony_ci		return -EBUSY;
7638c2ecf20Sopenharmony_ci	if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters -
7648c2ecf20Sopenharmony_ci	    MC5_MIN_TIDS)
7658c2ecf20Sopenharmony_ci		return -EINVAL;
7668c2ecf20Sopenharmony_ci	adap->params.mc5.nservers = val;
7678c2ecf20Sopenharmony_ci	return 0;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic ssize_t store_nservers(struct device *d, struct device_attribute *attr,
7718c2ecf20Sopenharmony_ci			      const char *buf, size_t len)
7728c2ecf20Sopenharmony_ci{
7738c2ecf20Sopenharmony_ci	return attr_store(d, buf, len, set_nservers, 0, ~0);
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci#define CXGB3_ATTR_R(name, val_expr) \
7778c2ecf20Sopenharmony_ciCXGB3_SHOW(name, val_expr) \
7788c2ecf20Sopenharmony_cistatic DEVICE_ATTR(name, 0444, show_##name, NULL)
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci#define CXGB3_ATTR_RW(name, val_expr, store_method) \
7818c2ecf20Sopenharmony_ciCXGB3_SHOW(name, val_expr) \
7828c2ecf20Sopenharmony_cistatic DEVICE_ATTR(name, 0644, show_##name, store_method)
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ciCXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
7858c2ecf20Sopenharmony_ciCXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
7868c2ecf20Sopenharmony_ciCXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_cistatic struct attribute *cxgb3_attrs[] = {
7898c2ecf20Sopenharmony_ci	&dev_attr_cam_size.attr,
7908c2ecf20Sopenharmony_ci	&dev_attr_nfilters.attr,
7918c2ecf20Sopenharmony_ci	&dev_attr_nservers.attr,
7928c2ecf20Sopenharmony_ci	NULL
7938c2ecf20Sopenharmony_ci};
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_cistatic const struct attribute_group cxgb3_attr_group = {
7968c2ecf20Sopenharmony_ci	.attrs = cxgb3_attrs,
7978c2ecf20Sopenharmony_ci};
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic ssize_t tm_attr_show(struct device *d,
8008c2ecf20Sopenharmony_ci			    char *buf, int sched)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(to_net_dev(d));
8038c2ecf20Sopenharmony_ci	struct adapter *adap = pi->adapter;
8048c2ecf20Sopenharmony_ci	unsigned int v, addr, bpt, cpt;
8058c2ecf20Sopenharmony_ci	ssize_t len;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
8088c2ecf20Sopenharmony_ci	rtnl_lock();
8098c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
8108c2ecf20Sopenharmony_ci	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
8118c2ecf20Sopenharmony_ci	if (sched & 1)
8128c2ecf20Sopenharmony_ci		v >>= 16;
8138c2ecf20Sopenharmony_ci	bpt = (v >> 8) & 0xff;
8148c2ecf20Sopenharmony_ci	cpt = v & 0xff;
8158c2ecf20Sopenharmony_ci	if (!cpt)
8168c2ecf20Sopenharmony_ci		len = sprintf(buf, "disabled\n");
8178c2ecf20Sopenharmony_ci	else {
8188c2ecf20Sopenharmony_ci		v = (adap->params.vpd.cclk * 1000) / cpt;
8198c2ecf20Sopenharmony_ci		len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci	rtnl_unlock();
8228c2ecf20Sopenharmony_ci	return len;
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cistatic ssize_t tm_attr_store(struct device *d,
8268c2ecf20Sopenharmony_ci			     const char *buf, size_t len, int sched)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(to_net_dev(d));
8298c2ecf20Sopenharmony_ci	struct adapter *adap = pi->adapter;
8308c2ecf20Sopenharmony_ci	unsigned int val;
8318c2ecf20Sopenharmony_ci	ssize_t ret;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (!capable(CAP_NET_ADMIN))
8348c2ecf20Sopenharmony_ci		return -EPERM;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	ret = kstrtouint(buf, 0, &val);
8378c2ecf20Sopenharmony_ci	if (ret)
8388c2ecf20Sopenharmony_ci		return ret;
8398c2ecf20Sopenharmony_ci	if (val > 10000000)
8408c2ecf20Sopenharmony_ci		return -EINVAL;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	rtnl_lock();
8438c2ecf20Sopenharmony_ci	ret = t3_config_sched(adap, val, sched);
8448c2ecf20Sopenharmony_ci	if (!ret)
8458c2ecf20Sopenharmony_ci		ret = len;
8468c2ecf20Sopenharmony_ci	rtnl_unlock();
8478c2ecf20Sopenharmony_ci	return ret;
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci#define TM_ATTR(name, sched) \
8518c2ecf20Sopenharmony_cistatic ssize_t show_##name(struct device *d, struct device_attribute *attr, \
8528c2ecf20Sopenharmony_ci			   char *buf) \
8538c2ecf20Sopenharmony_ci{ \
8548c2ecf20Sopenharmony_ci	return tm_attr_show(d, buf, sched); \
8558c2ecf20Sopenharmony_ci} \
8568c2ecf20Sopenharmony_cistatic ssize_t store_##name(struct device *d, struct device_attribute *attr, \
8578c2ecf20Sopenharmony_ci			    const char *buf, size_t len) \
8588c2ecf20Sopenharmony_ci{ \
8598c2ecf20Sopenharmony_ci	return tm_attr_store(d, buf, len, sched); \
8608c2ecf20Sopenharmony_ci} \
8618c2ecf20Sopenharmony_cistatic DEVICE_ATTR(name, 0644, show_##name, store_##name)
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ciTM_ATTR(sched0, 0);
8648c2ecf20Sopenharmony_ciTM_ATTR(sched1, 1);
8658c2ecf20Sopenharmony_ciTM_ATTR(sched2, 2);
8668c2ecf20Sopenharmony_ciTM_ATTR(sched3, 3);
8678c2ecf20Sopenharmony_ciTM_ATTR(sched4, 4);
8688c2ecf20Sopenharmony_ciTM_ATTR(sched5, 5);
8698c2ecf20Sopenharmony_ciTM_ATTR(sched6, 6);
8708c2ecf20Sopenharmony_ciTM_ATTR(sched7, 7);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_cistatic struct attribute *offload_attrs[] = {
8738c2ecf20Sopenharmony_ci	&dev_attr_sched0.attr,
8748c2ecf20Sopenharmony_ci	&dev_attr_sched1.attr,
8758c2ecf20Sopenharmony_ci	&dev_attr_sched2.attr,
8768c2ecf20Sopenharmony_ci	&dev_attr_sched3.attr,
8778c2ecf20Sopenharmony_ci	&dev_attr_sched4.attr,
8788c2ecf20Sopenharmony_ci	&dev_attr_sched5.attr,
8798c2ecf20Sopenharmony_ci	&dev_attr_sched6.attr,
8808c2ecf20Sopenharmony_ci	&dev_attr_sched7.attr,
8818c2ecf20Sopenharmony_ci	NULL
8828c2ecf20Sopenharmony_ci};
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic const struct attribute_group offload_attr_group = {
8858c2ecf20Sopenharmony_ci	.attrs = offload_attrs,
8868c2ecf20Sopenharmony_ci};
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci/*
8898c2ecf20Sopenharmony_ci * Sends an sk_buff to an offload queue driver
8908c2ecf20Sopenharmony_ci * after dealing with any active network taps.
8918c2ecf20Sopenharmony_ci */
8928c2ecf20Sopenharmony_cistatic inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	int ret;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	local_bh_disable();
8978c2ecf20Sopenharmony_ci	ret = t3_offload_tx(tdev, skb);
8988c2ecf20Sopenharmony_ci	local_bh_enable();
8998c2ecf20Sopenharmony_ci	return ret;
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_cistatic int write_smt_entry(struct adapter *adapter, int idx)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	struct cpl_smt_write_req *req;
9058c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(adapter->port[idx]);
9068c2ecf20Sopenharmony_ci	struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	if (!skb)
9098c2ecf20Sopenharmony_ci		return -ENOMEM;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	req = __skb_put(skb, sizeof(*req));
9128c2ecf20Sopenharmony_ci	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
9138c2ecf20Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
9148c2ecf20Sopenharmony_ci	req->mtu_idx = NMTUS - 1;	/* should be 0 but there's a T3 bug */
9158c2ecf20Sopenharmony_ci	req->iff = idx;
9168c2ecf20Sopenharmony_ci	memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
9178c2ecf20Sopenharmony_ci	memcpy(req->src_mac1, pi->iscsic.mac_addr, ETH_ALEN);
9188c2ecf20Sopenharmony_ci	skb->priority = 1;
9198c2ecf20Sopenharmony_ci	offload_tx(&adapter->tdev, skb);
9208c2ecf20Sopenharmony_ci	return 0;
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_cistatic int init_smt(struct adapter *adapter)
9248c2ecf20Sopenharmony_ci{
9258c2ecf20Sopenharmony_ci	int i;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	for_each_port(adapter, i)
9288c2ecf20Sopenharmony_ci	    write_smt_entry(adapter, i);
9298c2ecf20Sopenharmony_ci	return 0;
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic void init_port_mtus(struct adapter *adapter)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	unsigned int mtus = adapter->port[0]->mtu;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	if (adapter->port[1])
9378c2ecf20Sopenharmony_ci		mtus |= adapter->port[1]->mtu << 16;
9388c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
9428c2ecf20Sopenharmony_ci			      int hi, int port)
9438c2ecf20Sopenharmony_ci{
9448c2ecf20Sopenharmony_ci	struct sk_buff *skb;
9458c2ecf20Sopenharmony_ci	struct mngt_pktsched_wr *req;
9468c2ecf20Sopenharmony_ci	int ret;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	skb = alloc_skb(sizeof(*req), GFP_KERNEL);
9498c2ecf20Sopenharmony_ci	if (!skb)
9508c2ecf20Sopenharmony_ci		skb = adap->nofail_skb;
9518c2ecf20Sopenharmony_ci	if (!skb)
9528c2ecf20Sopenharmony_ci		return -ENOMEM;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	req = skb_put(skb, sizeof(*req));
9558c2ecf20Sopenharmony_ci	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
9568c2ecf20Sopenharmony_ci	req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
9578c2ecf20Sopenharmony_ci	req->sched = sched;
9588c2ecf20Sopenharmony_ci	req->idx = qidx;
9598c2ecf20Sopenharmony_ci	req->min = lo;
9608c2ecf20Sopenharmony_ci	req->max = hi;
9618c2ecf20Sopenharmony_ci	req->binding = port;
9628c2ecf20Sopenharmony_ci	ret = t3_mgmt_tx(adap, skb);
9638c2ecf20Sopenharmony_ci	if (skb == adap->nofail_skb) {
9648c2ecf20Sopenharmony_ci		adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field),
9658c2ecf20Sopenharmony_ci					     GFP_KERNEL);
9668c2ecf20Sopenharmony_ci		if (!adap->nofail_skb)
9678c2ecf20Sopenharmony_ci			ret = -ENOMEM;
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	return ret;
9718c2ecf20Sopenharmony_ci}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_cistatic int bind_qsets(struct adapter *adap)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	int i, j, err = 0;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	for_each_port(adap, i) {
9788c2ecf20Sopenharmony_ci		const struct port_info *pi = adap2pinfo(adap, i);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci		for (j = 0; j < pi->nqsets; ++j) {
9818c2ecf20Sopenharmony_ci			int ret = send_pktsched_cmd(adap, 1,
9828c2ecf20Sopenharmony_ci						    pi->first_qset + j, -1,
9838c2ecf20Sopenharmony_ci						    -1, i);
9848c2ecf20Sopenharmony_ci			if (ret)
9858c2ecf20Sopenharmony_ci				err = ret;
9868c2ecf20Sopenharmony_ci		}
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	return err;
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci#define FW_VERSION __stringify(FW_VERSION_MAJOR) "."			\
9938c2ecf20Sopenharmony_ci	__stringify(FW_VERSION_MINOR) "." __stringify(FW_VERSION_MICRO)
9948c2ecf20Sopenharmony_ci#define FW_FNAME "cxgb3/t3fw-" FW_VERSION ".bin"
9958c2ecf20Sopenharmony_ci#define TPSRAM_VERSION __stringify(TP_VERSION_MAJOR) "."		\
9968c2ecf20Sopenharmony_ci	__stringify(TP_VERSION_MINOR) "." __stringify(TP_VERSION_MICRO)
9978c2ecf20Sopenharmony_ci#define TPSRAM_NAME "cxgb3/t3%c_psram-" TPSRAM_VERSION ".bin"
9988c2ecf20Sopenharmony_ci#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
9998c2ecf20Sopenharmony_ci#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
10008c2ecf20Sopenharmony_ci#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin"
10018c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW_FNAME);
10028c2ecf20Sopenharmony_ciMODULE_FIRMWARE("cxgb3/t3b_psram-" TPSRAM_VERSION ".bin");
10038c2ecf20Sopenharmony_ciMODULE_FIRMWARE("cxgb3/t3c_psram-" TPSRAM_VERSION ".bin");
10048c2ecf20Sopenharmony_ciMODULE_FIRMWARE(AEL2005_OPT_EDC_NAME);
10058c2ecf20Sopenharmony_ciMODULE_FIRMWARE(AEL2005_TWX_EDC_NAME);
10068c2ecf20Sopenharmony_ciMODULE_FIRMWARE(AEL2020_TWX_EDC_NAME);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_cistatic inline const char *get_edc_fw_name(int edc_idx)
10098c2ecf20Sopenharmony_ci{
10108c2ecf20Sopenharmony_ci	const char *fw_name = NULL;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	switch (edc_idx) {
10138c2ecf20Sopenharmony_ci	case EDC_OPT_AEL2005:
10148c2ecf20Sopenharmony_ci		fw_name = AEL2005_OPT_EDC_NAME;
10158c2ecf20Sopenharmony_ci		break;
10168c2ecf20Sopenharmony_ci	case EDC_TWX_AEL2005:
10178c2ecf20Sopenharmony_ci		fw_name = AEL2005_TWX_EDC_NAME;
10188c2ecf20Sopenharmony_ci		break;
10198c2ecf20Sopenharmony_ci	case EDC_TWX_AEL2020:
10208c2ecf20Sopenharmony_ci		fw_name = AEL2020_TWX_EDC_NAME;
10218c2ecf20Sopenharmony_ci		break;
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci	return fw_name;
10248c2ecf20Sopenharmony_ci}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ciint t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	struct adapter *adapter = phy->adapter;
10298c2ecf20Sopenharmony_ci	const struct firmware *fw;
10308c2ecf20Sopenharmony_ci	const char *fw_name;
10318c2ecf20Sopenharmony_ci	u32 csum;
10328c2ecf20Sopenharmony_ci	const __be32 *p;
10338c2ecf20Sopenharmony_ci	u16 *cache = phy->phy_cache;
10348c2ecf20Sopenharmony_ci	int i, ret = -EINVAL;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	fw_name = get_edc_fw_name(edc_idx);
10378c2ecf20Sopenharmony_ci	if (fw_name)
10388c2ecf20Sopenharmony_ci		ret = request_firmware(&fw, fw_name, &adapter->pdev->dev);
10398c2ecf20Sopenharmony_ci	if (ret < 0) {
10408c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
10418c2ecf20Sopenharmony_ci			"could not upgrade firmware: unable to load %s\n",
10428c2ecf20Sopenharmony_ci			fw_name);
10438c2ecf20Sopenharmony_ci		return ret;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	/* check size, take checksum in account */
10478c2ecf20Sopenharmony_ci	if (fw->size > size + 4) {
10488c2ecf20Sopenharmony_ci		CH_ERR(adapter, "firmware image too large %u, expected %d\n",
10498c2ecf20Sopenharmony_ci		       (unsigned int)fw->size, size + 4);
10508c2ecf20Sopenharmony_ci		ret = -EINVAL;
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	/* compute checksum */
10548c2ecf20Sopenharmony_ci	p = (const __be32 *)fw->data;
10558c2ecf20Sopenharmony_ci	for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
10568c2ecf20Sopenharmony_ci		csum += ntohl(p[i]);
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	if (csum != 0xffffffff) {
10598c2ecf20Sopenharmony_ci		CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
10608c2ecf20Sopenharmony_ci		       csum);
10618c2ecf20Sopenharmony_ci		ret = -EINVAL;
10628c2ecf20Sopenharmony_ci	}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	for (i = 0; i < size / 4 ; i++) {
10658c2ecf20Sopenharmony_ci		*cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
10668c2ecf20Sopenharmony_ci		*cache++ = be32_to_cpu(p[i]) & 0xffff;
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	release_firmware(fw);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	return ret;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic int upgrade_fw(struct adapter *adap)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	int ret;
10778c2ecf20Sopenharmony_ci	const struct firmware *fw;
10788c2ecf20Sopenharmony_ci	struct device *dev = &adap->pdev->dev;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	ret = request_firmware(&fw, FW_FNAME, dev);
10818c2ecf20Sopenharmony_ci	if (ret < 0) {
10828c2ecf20Sopenharmony_ci		dev_err(dev, "could not upgrade firmware: unable to load %s\n",
10838c2ecf20Sopenharmony_ci			FW_FNAME);
10848c2ecf20Sopenharmony_ci		return ret;
10858c2ecf20Sopenharmony_ci	}
10868c2ecf20Sopenharmony_ci	ret = t3_load_fw(adap, fw->data, fw->size);
10878c2ecf20Sopenharmony_ci	release_firmware(fw);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (ret == 0)
10908c2ecf20Sopenharmony_ci		dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
10918c2ecf20Sopenharmony_ci			 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
10928c2ecf20Sopenharmony_ci	else
10938c2ecf20Sopenharmony_ci		dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
10948c2ecf20Sopenharmony_ci			FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	return ret;
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic inline char t3rev2char(struct adapter *adapter)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	char rev = 0;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	switch(adapter->params.rev) {
11048c2ecf20Sopenharmony_ci	case T3_REV_B:
11058c2ecf20Sopenharmony_ci	case T3_REV_B2:
11068c2ecf20Sopenharmony_ci		rev = 'b';
11078c2ecf20Sopenharmony_ci		break;
11088c2ecf20Sopenharmony_ci	case T3_REV_C:
11098c2ecf20Sopenharmony_ci		rev = 'c';
11108c2ecf20Sopenharmony_ci		break;
11118c2ecf20Sopenharmony_ci	}
11128c2ecf20Sopenharmony_ci	return rev;
11138c2ecf20Sopenharmony_ci}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cistatic int update_tpsram(struct adapter *adap)
11168c2ecf20Sopenharmony_ci{
11178c2ecf20Sopenharmony_ci	const struct firmware *tpsram;
11188c2ecf20Sopenharmony_ci	char buf[64];
11198c2ecf20Sopenharmony_ci	struct device *dev = &adap->pdev->dev;
11208c2ecf20Sopenharmony_ci	int ret;
11218c2ecf20Sopenharmony_ci	char rev;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	rev = t3rev2char(adap);
11248c2ecf20Sopenharmony_ci	if (!rev)
11258c2ecf20Sopenharmony_ci		return 0;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf), TPSRAM_NAME, rev);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	ret = request_firmware(&tpsram, buf, dev);
11308c2ecf20Sopenharmony_ci	if (ret < 0) {
11318c2ecf20Sopenharmony_ci		dev_err(dev, "could not load TP SRAM: unable to load %s\n",
11328c2ecf20Sopenharmony_ci			buf);
11338c2ecf20Sopenharmony_ci		return ret;
11348c2ecf20Sopenharmony_ci	}
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
11378c2ecf20Sopenharmony_ci	if (ret)
11388c2ecf20Sopenharmony_ci		goto release_tpsram;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	ret = t3_set_proto_sram(adap, tpsram->data);
11418c2ecf20Sopenharmony_ci	if (ret == 0)
11428c2ecf20Sopenharmony_ci		dev_info(dev,
11438c2ecf20Sopenharmony_ci			 "successful update of protocol engine "
11448c2ecf20Sopenharmony_ci			 "to %d.%d.%d\n",
11458c2ecf20Sopenharmony_ci			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
11468c2ecf20Sopenharmony_ci	else
11478c2ecf20Sopenharmony_ci		dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
11488c2ecf20Sopenharmony_ci			TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
11498c2ecf20Sopenharmony_ci	if (ret)
11508c2ecf20Sopenharmony_ci		dev_err(dev, "loading protocol SRAM failed\n");
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cirelease_tpsram:
11538c2ecf20Sopenharmony_ci	release_firmware(tpsram);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	return ret;
11568c2ecf20Sopenharmony_ci}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci/**
11598c2ecf20Sopenharmony_ci * t3_synchronize_rx - wait for current Rx processing on a port to complete
11608c2ecf20Sopenharmony_ci * @adap: the adapter
11618c2ecf20Sopenharmony_ci * @p: the port
11628c2ecf20Sopenharmony_ci *
11638c2ecf20Sopenharmony_ci * Ensures that current Rx processing on any of the queues associated with
11648c2ecf20Sopenharmony_ci * the given port completes before returning.  We do this by acquiring and
11658c2ecf20Sopenharmony_ci * releasing the locks of the response queues associated with the port.
11668c2ecf20Sopenharmony_ci */
11678c2ecf20Sopenharmony_cistatic void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
11688c2ecf20Sopenharmony_ci{
11698c2ecf20Sopenharmony_ci	int i;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
11728c2ecf20Sopenharmony_ci		struct sge_rspq *q = &adap->sge.qs[i].rspq;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci		spin_lock_irq(&q->lock);
11758c2ecf20Sopenharmony_ci		spin_unlock_irq(&q->lock);
11768c2ecf20Sopenharmony_ci	}
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistatic void cxgb_vlan_mode(struct net_device *dev, netdev_features_t features)
11808c2ecf20Sopenharmony_ci{
11818c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
11828c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	if (adapter->params.rev > 0) {
11858c2ecf20Sopenharmony_ci		t3_set_vlan_accel(adapter, 1 << pi->port_id,
11868c2ecf20Sopenharmony_ci				  features & NETIF_F_HW_VLAN_CTAG_RX);
11878c2ecf20Sopenharmony_ci	} else {
11888c2ecf20Sopenharmony_ci		/* single control for all ports */
11898c2ecf20Sopenharmony_ci		unsigned int i, have_vlans = features & NETIF_F_HW_VLAN_CTAG_RX;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci		for_each_port(adapter, i)
11928c2ecf20Sopenharmony_ci			have_vlans |=
11938c2ecf20Sopenharmony_ci				adapter->port[i]->features &
11948c2ecf20Sopenharmony_ci				NETIF_F_HW_VLAN_CTAG_RX;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci		t3_set_vlan_accel(adapter, 1, have_vlans);
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci	t3_synchronize_rx(adapter, pi);
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci/**
12028c2ecf20Sopenharmony_ci *	cxgb_up - enable the adapter
12038c2ecf20Sopenharmony_ci *	@adap: adapter being enabled
12048c2ecf20Sopenharmony_ci *
12058c2ecf20Sopenharmony_ci *	Called when the first port is enabled, this function performs the
12068c2ecf20Sopenharmony_ci *	actions necessary to make an adapter operational, such as completing
12078c2ecf20Sopenharmony_ci *	the initialization of HW modules, and enabling interrupts.
12088c2ecf20Sopenharmony_ci *
12098c2ecf20Sopenharmony_ci *	Must be called with the rtnl lock held.
12108c2ecf20Sopenharmony_ci */
12118c2ecf20Sopenharmony_cistatic int cxgb_up(struct adapter *adap)
12128c2ecf20Sopenharmony_ci{
12138c2ecf20Sopenharmony_ci	int i, err;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	if (!(adap->flags & FULL_INIT_DONE)) {
12168c2ecf20Sopenharmony_ci		err = t3_check_fw_version(adap);
12178c2ecf20Sopenharmony_ci		if (err == -EINVAL) {
12188c2ecf20Sopenharmony_ci			err = upgrade_fw(adap);
12198c2ecf20Sopenharmony_ci			CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n",
12208c2ecf20Sopenharmony_ci				FW_VERSION_MAJOR, FW_VERSION_MINOR,
12218c2ecf20Sopenharmony_ci				FW_VERSION_MICRO, err ? "failed" : "succeeded");
12228c2ecf20Sopenharmony_ci		}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci		err = t3_check_tpsram_version(adap);
12258c2ecf20Sopenharmony_ci		if (err == -EINVAL) {
12268c2ecf20Sopenharmony_ci			err = update_tpsram(adap);
12278c2ecf20Sopenharmony_ci			CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n",
12288c2ecf20Sopenharmony_ci				TP_VERSION_MAJOR, TP_VERSION_MINOR,
12298c2ecf20Sopenharmony_ci				TP_VERSION_MICRO, err ? "failed" : "succeeded");
12308c2ecf20Sopenharmony_ci		}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci		/*
12338c2ecf20Sopenharmony_ci		 * Clear interrupts now to catch errors if t3_init_hw fails.
12348c2ecf20Sopenharmony_ci		 * We clear them again later as initialization may trigger
12358c2ecf20Sopenharmony_ci		 * conditions that can interrupt.
12368c2ecf20Sopenharmony_ci		 */
12378c2ecf20Sopenharmony_ci		t3_intr_clear(adap);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci		err = t3_init_hw(adap, 0);
12408c2ecf20Sopenharmony_ci		if (err)
12418c2ecf20Sopenharmony_ci			goto out;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
12448c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci		err = setup_sge_qsets(adap);
12478c2ecf20Sopenharmony_ci		if (err)
12488c2ecf20Sopenharmony_ci			goto out;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci		for_each_port(adap, i)
12518c2ecf20Sopenharmony_ci			cxgb_vlan_mode(adap->port[i], adap->port[i]->features);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci		setup_rss(adap);
12548c2ecf20Sopenharmony_ci		if (!(adap->flags & NAPI_INIT))
12558c2ecf20Sopenharmony_ci			init_napi(adap);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci		t3_start_sge_timers(adap);
12588c2ecf20Sopenharmony_ci		adap->flags |= FULL_INIT_DONE;
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	t3_intr_clear(adap);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	if (adap->flags & USING_MSIX) {
12648c2ecf20Sopenharmony_ci		name_msix_vecs(adap);
12658c2ecf20Sopenharmony_ci		err = request_irq(adap->msix_info[0].vec,
12668c2ecf20Sopenharmony_ci				  t3_async_intr_handler, 0,
12678c2ecf20Sopenharmony_ci				  adap->msix_info[0].desc, adap);
12688c2ecf20Sopenharmony_ci		if (err)
12698c2ecf20Sopenharmony_ci			goto irq_err;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci		err = request_msix_data_irqs(adap);
12728c2ecf20Sopenharmony_ci		if (err) {
12738c2ecf20Sopenharmony_ci			free_irq(adap->msix_info[0].vec, adap);
12748c2ecf20Sopenharmony_ci			goto irq_err;
12758c2ecf20Sopenharmony_ci		}
12768c2ecf20Sopenharmony_ci	} else if ((err = request_irq(adap->pdev->irq,
12778c2ecf20Sopenharmony_ci				      t3_intr_handler(adap,
12788c2ecf20Sopenharmony_ci						      adap->sge.qs[0].rspq.
12798c2ecf20Sopenharmony_ci						      polling),
12808c2ecf20Sopenharmony_ci				      (adap->flags & USING_MSI) ?
12818c2ecf20Sopenharmony_ci				       0 : IRQF_SHARED,
12828c2ecf20Sopenharmony_ci				      adap->name, adap)))
12838c2ecf20Sopenharmony_ci		goto irq_err;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	enable_all_napi(adap);
12868c2ecf20Sopenharmony_ci	t3_sge_start(adap);
12878c2ecf20Sopenharmony_ci	t3_intr_enable(adap);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) &&
12908c2ecf20Sopenharmony_ci	    is_offload(adap) && init_tp_parity(adap) == 0)
12918c2ecf20Sopenharmony_ci		adap->flags |= TP_PARITY_INIT;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	if (adap->flags & TP_PARITY_INIT) {
12948c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_INT_CAUSE,
12958c2ecf20Sopenharmony_ci			     F_CMCACHEPERR | F_ARPLUTPERR);
12968c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
12978c2ecf20Sopenharmony_ci	}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	if (!(adap->flags & QUEUES_BOUND)) {
13008c2ecf20Sopenharmony_ci		int ret = bind_qsets(adap);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci		if (ret < 0) {
13038c2ecf20Sopenharmony_ci			CH_ERR(adap, "failed to bind qsets, err %d\n", ret);
13048c2ecf20Sopenharmony_ci			t3_intr_disable(adap);
13058c2ecf20Sopenharmony_ci			quiesce_rx(adap);
13068c2ecf20Sopenharmony_ci			free_irq_resources(adap);
13078c2ecf20Sopenharmony_ci			err = ret;
13088c2ecf20Sopenharmony_ci			goto out;
13098c2ecf20Sopenharmony_ci		}
13108c2ecf20Sopenharmony_ci		adap->flags |= QUEUES_BOUND;
13118c2ecf20Sopenharmony_ci	}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ciout:
13148c2ecf20Sopenharmony_ci	return err;
13158c2ecf20Sopenharmony_ciirq_err:
13168c2ecf20Sopenharmony_ci	CH_ERR(adap, "request_irq failed, err %d\n", err);
13178c2ecf20Sopenharmony_ci	goto out;
13188c2ecf20Sopenharmony_ci}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci/*
13218c2ecf20Sopenharmony_ci * Release resources when all the ports and offloading have been stopped.
13228c2ecf20Sopenharmony_ci */
13238c2ecf20Sopenharmony_cistatic void cxgb_down(struct adapter *adapter, int on_wq)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	t3_sge_stop(adapter);
13268c2ecf20Sopenharmony_ci	spin_lock_irq(&adapter->work_lock);	/* sync with PHY intr task */
13278c2ecf20Sopenharmony_ci	t3_intr_disable(adapter);
13288c2ecf20Sopenharmony_ci	spin_unlock_irq(&adapter->work_lock);
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	free_irq_resources(adapter);
13318c2ecf20Sopenharmony_ci	quiesce_rx(adapter);
13328c2ecf20Sopenharmony_ci	t3_sge_stop(adapter);
13338c2ecf20Sopenharmony_ci	if (!on_wq)
13348c2ecf20Sopenharmony_ci		flush_workqueue(cxgb3_wq);/* wait for external IRQ handler */
13358c2ecf20Sopenharmony_ci}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_cistatic void schedule_chk_task(struct adapter *adap)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	unsigned int timeo;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	timeo = adap->params.linkpoll_period ?
13428c2ecf20Sopenharmony_ci	    (HZ * adap->params.linkpoll_period) / 10 :
13438c2ecf20Sopenharmony_ci	    adap->params.stats_update_period * HZ;
13448c2ecf20Sopenharmony_ci	if (timeo)
13458c2ecf20Sopenharmony_ci		queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
13468c2ecf20Sopenharmony_ci}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_cistatic int offload_open(struct net_device *dev)
13498c2ecf20Sopenharmony_ci{
13508c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
13518c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
13528c2ecf20Sopenharmony_ci	struct t3cdev *tdev = dev2t3cdev(dev);
13538c2ecf20Sopenharmony_ci	int adap_up = adapter->open_device_map & PORT_MASK;
13548c2ecf20Sopenharmony_ci	int err;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
13578c2ecf20Sopenharmony_ci		return 0;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	if (!adap_up && (err = cxgb_up(adapter)) < 0)
13608c2ecf20Sopenharmony_ci		goto out;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	t3_tp_set_offload_mode(adapter, 1);
13638c2ecf20Sopenharmony_ci	tdev->lldev = adapter->port[0];
13648c2ecf20Sopenharmony_ci	err = cxgb3_offload_activate(adapter);
13658c2ecf20Sopenharmony_ci	if (err)
13668c2ecf20Sopenharmony_ci		goto out;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	init_port_mtus(adapter);
13698c2ecf20Sopenharmony_ci	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
13708c2ecf20Sopenharmony_ci		     adapter->params.b_wnd,
13718c2ecf20Sopenharmony_ci		     adapter->params.rev == 0 ?
13728c2ecf20Sopenharmony_ci		     adapter->port[0]->mtu : 0xffff);
13738c2ecf20Sopenharmony_ci	init_smt(adapter);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group))
13768c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "cannot create sysfs group\n");
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	/* Call back all registered clients */
13798c2ecf20Sopenharmony_ci	cxgb3_add_clients(tdev);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ciout:
13828c2ecf20Sopenharmony_ci	/* restore them in case the offload module has changed them */
13838c2ecf20Sopenharmony_ci	if (err) {
13848c2ecf20Sopenharmony_ci		t3_tp_set_offload_mode(adapter, 0);
13858c2ecf20Sopenharmony_ci		clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
13868c2ecf20Sopenharmony_ci		cxgb3_set_dummy_ops(tdev);
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci	return err;
13898c2ecf20Sopenharmony_ci}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_cistatic int offload_close(struct t3cdev *tdev)
13928c2ecf20Sopenharmony_ci{
13938c2ecf20Sopenharmony_ci	struct adapter *adapter = tdev2adap(tdev);
13948c2ecf20Sopenharmony_ci	struct t3c_data *td = T3C_DATA(tdev);
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
13978c2ecf20Sopenharmony_ci		return 0;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	/* Call back all registered clients */
14008c2ecf20Sopenharmony_ci	cxgb3_remove_clients(tdev);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	/* Flush work scheduled while releasing TIDs */
14058c2ecf20Sopenharmony_ci	flush_work(&td->tid_release_task);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	tdev->lldev = NULL;
14088c2ecf20Sopenharmony_ci	cxgb3_set_dummy_ops(tdev);
14098c2ecf20Sopenharmony_ci	t3_tp_set_offload_mode(adapter, 0);
14108c2ecf20Sopenharmony_ci	clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (!adapter->open_device_map)
14138c2ecf20Sopenharmony_ci		cxgb_down(adapter, 0);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	cxgb3_offload_deactivate(adapter);
14168c2ecf20Sopenharmony_ci	return 0;
14178c2ecf20Sopenharmony_ci}
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_cistatic int cxgb_open(struct net_device *dev)
14208c2ecf20Sopenharmony_ci{
14218c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
14228c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
14238c2ecf20Sopenharmony_ci	int other_ports = adapter->open_device_map & PORT_MASK;
14248c2ecf20Sopenharmony_ci	int err;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
14278c2ecf20Sopenharmony_ci		return err;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	set_bit(pi->port_id, &adapter->open_device_map);
14308c2ecf20Sopenharmony_ci	if (is_offload(adapter) && !ofld_disable) {
14318c2ecf20Sopenharmony_ci		err = offload_open(dev);
14328c2ecf20Sopenharmony_ci		if (err)
14338c2ecf20Sopenharmony_ci			pr_warn("Could not initialize offload capabilities\n");
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	netif_set_real_num_tx_queues(dev, pi->nqsets);
14378c2ecf20Sopenharmony_ci	err = netif_set_real_num_rx_queues(dev, pi->nqsets);
14388c2ecf20Sopenharmony_ci	if (err)
14398c2ecf20Sopenharmony_ci		return err;
14408c2ecf20Sopenharmony_ci	link_start(dev);
14418c2ecf20Sopenharmony_ci	t3_port_intr_enable(adapter, pi->port_id);
14428c2ecf20Sopenharmony_ci	netif_tx_start_all_queues(dev);
14438c2ecf20Sopenharmony_ci	if (!other_ports)
14448c2ecf20Sopenharmony_ci		schedule_chk_task(adapter);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_UP, pi->port_id);
14478c2ecf20Sopenharmony_ci	return 0;
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic int __cxgb_close(struct net_device *dev, int on_wq)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
14538c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	if (!adapter->open_device_map)
14578c2ecf20Sopenharmony_ci		return 0;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	/* Stop link fault interrupts */
14608c2ecf20Sopenharmony_ci	t3_xgm_intr_disable(adapter, pi->port_id);
14618c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	t3_port_intr_disable(adapter, pi->port_id);
14648c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(dev);
14658c2ecf20Sopenharmony_ci	pi->phy.ops->power_down(&pi->phy, 1);
14668c2ecf20Sopenharmony_ci	netif_carrier_off(dev);
14678c2ecf20Sopenharmony_ci	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	spin_lock_irq(&adapter->work_lock);	/* sync with update task */
14708c2ecf20Sopenharmony_ci	clear_bit(pi->port_id, &adapter->open_device_map);
14718c2ecf20Sopenharmony_ci	spin_unlock_irq(&adapter->work_lock);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (!(adapter->open_device_map & PORT_MASK))
14748c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&adapter->adap_check_task);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	if (!adapter->open_device_map)
14778c2ecf20Sopenharmony_ci		cxgb_down(adapter, on_wq);
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id);
14808c2ecf20Sopenharmony_ci	return 0;
14818c2ecf20Sopenharmony_ci}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_cistatic int cxgb_close(struct net_device *dev)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	return __cxgb_close(dev, 0);
14868c2ecf20Sopenharmony_ci}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_cistatic struct net_device_stats *cxgb_get_stats(struct net_device *dev)
14898c2ecf20Sopenharmony_ci{
14908c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
14918c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
14928c2ecf20Sopenharmony_ci	struct net_device_stats *ns = &dev->stats;
14938c2ecf20Sopenharmony_ci	const struct mac_stats *pstats;
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	spin_lock(&adapter->stats_lock);
14968c2ecf20Sopenharmony_ci	pstats = t3_mac_update_stats(&pi->mac);
14978c2ecf20Sopenharmony_ci	spin_unlock(&adapter->stats_lock);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	ns->tx_bytes = pstats->tx_octets;
15008c2ecf20Sopenharmony_ci	ns->tx_packets = pstats->tx_frames;
15018c2ecf20Sopenharmony_ci	ns->rx_bytes = pstats->rx_octets;
15028c2ecf20Sopenharmony_ci	ns->rx_packets = pstats->rx_frames;
15038c2ecf20Sopenharmony_ci	ns->multicast = pstats->rx_mcast_frames;
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	ns->tx_errors = pstats->tx_underrun;
15068c2ecf20Sopenharmony_ci	ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
15078c2ecf20Sopenharmony_ci	    pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
15088c2ecf20Sopenharmony_ci	    pstats->rx_fifo_ovfl;
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	/* detailed rx_errors */
15118c2ecf20Sopenharmony_ci	ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
15128c2ecf20Sopenharmony_ci	ns->rx_over_errors = 0;
15138c2ecf20Sopenharmony_ci	ns->rx_crc_errors = pstats->rx_fcs_errs;
15148c2ecf20Sopenharmony_ci	ns->rx_frame_errors = pstats->rx_symbol_errs;
15158c2ecf20Sopenharmony_ci	ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
15168c2ecf20Sopenharmony_ci	ns->rx_missed_errors = pstats->rx_cong_drops;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	/* detailed tx_errors */
15198c2ecf20Sopenharmony_ci	ns->tx_aborted_errors = 0;
15208c2ecf20Sopenharmony_ci	ns->tx_carrier_errors = 0;
15218c2ecf20Sopenharmony_ci	ns->tx_fifo_errors = pstats->tx_underrun;
15228c2ecf20Sopenharmony_ci	ns->tx_heartbeat_errors = 0;
15238c2ecf20Sopenharmony_ci	ns->tx_window_errors = 0;
15248c2ecf20Sopenharmony_ci	return ns;
15258c2ecf20Sopenharmony_ci}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_cistatic u32 get_msglevel(struct net_device *dev)
15288c2ecf20Sopenharmony_ci{
15298c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
15308c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	return adapter->msg_enable;
15338c2ecf20Sopenharmony_ci}
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_cistatic void set_msglevel(struct net_device *dev, u32 val)
15368c2ecf20Sopenharmony_ci{
15378c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
15388c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	adapter->msg_enable = val;
15418c2ecf20Sopenharmony_ci}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_cistatic const char stats_strings[][ETH_GSTRING_LEN] = {
15448c2ecf20Sopenharmony_ci	"TxOctetsOK         ",
15458c2ecf20Sopenharmony_ci	"TxFramesOK         ",
15468c2ecf20Sopenharmony_ci	"TxMulticastFramesOK",
15478c2ecf20Sopenharmony_ci	"TxBroadcastFramesOK",
15488c2ecf20Sopenharmony_ci	"TxPauseFrames      ",
15498c2ecf20Sopenharmony_ci	"TxUnderrun         ",
15508c2ecf20Sopenharmony_ci	"TxExtUnderrun      ",
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	"TxFrames64         ",
15538c2ecf20Sopenharmony_ci	"TxFrames65To127    ",
15548c2ecf20Sopenharmony_ci	"TxFrames128To255   ",
15558c2ecf20Sopenharmony_ci	"TxFrames256To511   ",
15568c2ecf20Sopenharmony_ci	"TxFrames512To1023  ",
15578c2ecf20Sopenharmony_ci	"TxFrames1024To1518 ",
15588c2ecf20Sopenharmony_ci	"TxFrames1519ToMax  ",
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	"RxOctetsOK         ",
15618c2ecf20Sopenharmony_ci	"RxFramesOK         ",
15628c2ecf20Sopenharmony_ci	"RxMulticastFramesOK",
15638c2ecf20Sopenharmony_ci	"RxBroadcastFramesOK",
15648c2ecf20Sopenharmony_ci	"RxPauseFrames      ",
15658c2ecf20Sopenharmony_ci	"RxFCSErrors        ",
15668c2ecf20Sopenharmony_ci	"RxSymbolErrors     ",
15678c2ecf20Sopenharmony_ci	"RxShortErrors      ",
15688c2ecf20Sopenharmony_ci	"RxJabberErrors     ",
15698c2ecf20Sopenharmony_ci	"RxLengthErrors     ",
15708c2ecf20Sopenharmony_ci	"RxFIFOoverflow     ",
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	"RxFrames64         ",
15738c2ecf20Sopenharmony_ci	"RxFrames65To127    ",
15748c2ecf20Sopenharmony_ci	"RxFrames128To255   ",
15758c2ecf20Sopenharmony_ci	"RxFrames256To511   ",
15768c2ecf20Sopenharmony_ci	"RxFrames512To1023  ",
15778c2ecf20Sopenharmony_ci	"RxFrames1024To1518 ",
15788c2ecf20Sopenharmony_ci	"RxFrames1519ToMax  ",
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	"PhyFIFOErrors      ",
15818c2ecf20Sopenharmony_ci	"TSO                ",
15828c2ecf20Sopenharmony_ci	"VLANextractions    ",
15838c2ecf20Sopenharmony_ci	"VLANinsertions     ",
15848c2ecf20Sopenharmony_ci	"TxCsumOffload      ",
15858c2ecf20Sopenharmony_ci	"RxCsumGood         ",
15868c2ecf20Sopenharmony_ci	"LroAggregated      ",
15878c2ecf20Sopenharmony_ci	"LroFlushed         ",
15888c2ecf20Sopenharmony_ci	"LroNoDesc          ",
15898c2ecf20Sopenharmony_ci	"RxDrops            ",
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	"CheckTXEnToggled   ",
15928c2ecf20Sopenharmony_ci	"CheckResets        ",
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	"LinkFaults         ",
15958c2ecf20Sopenharmony_ci};
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_cistatic int get_sset_count(struct net_device *dev, int sset)
15988c2ecf20Sopenharmony_ci{
15998c2ecf20Sopenharmony_ci	switch (sset) {
16008c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
16018c2ecf20Sopenharmony_ci		return ARRAY_SIZE(stats_strings);
16028c2ecf20Sopenharmony_ci	default:
16038c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
16048c2ecf20Sopenharmony_ci	}
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci#define T3_REGMAP_SIZE (3 * 1024)
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_cistatic int get_regs_len(struct net_device *dev)
16108c2ecf20Sopenharmony_ci{
16118c2ecf20Sopenharmony_ci	return T3_REGMAP_SIZE;
16128c2ecf20Sopenharmony_ci}
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_cistatic int get_eeprom_len(struct net_device *dev)
16158c2ecf20Sopenharmony_ci{
16168c2ecf20Sopenharmony_ci	return EEPROMSIZE;
16178c2ecf20Sopenharmony_ci}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_cistatic void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
16228c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
16238c2ecf20Sopenharmony_ci	u32 fw_vers = 0;
16248c2ecf20Sopenharmony_ci	u32 tp_vers = 0;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	spin_lock(&adapter->stats_lock);
16278c2ecf20Sopenharmony_ci	t3_get_fw_version(adapter, &fw_vers);
16288c2ecf20Sopenharmony_ci	t3_get_tp_version(adapter, &tp_vers);
16298c2ecf20Sopenharmony_ci	spin_unlock(&adapter->stats_lock);
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
16328c2ecf20Sopenharmony_ci	strlcpy(info->bus_info, pci_name(adapter->pdev),
16338c2ecf20Sopenharmony_ci		sizeof(info->bus_info));
16348c2ecf20Sopenharmony_ci	if (fw_vers)
16358c2ecf20Sopenharmony_ci		snprintf(info->fw_version, sizeof(info->fw_version),
16368c2ecf20Sopenharmony_ci			 "%s %u.%u.%u TP %u.%u.%u",
16378c2ecf20Sopenharmony_ci			 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
16388c2ecf20Sopenharmony_ci			 G_FW_VERSION_MAJOR(fw_vers),
16398c2ecf20Sopenharmony_ci			 G_FW_VERSION_MINOR(fw_vers),
16408c2ecf20Sopenharmony_ci			 G_FW_VERSION_MICRO(fw_vers),
16418c2ecf20Sopenharmony_ci			 G_TP_VERSION_MAJOR(tp_vers),
16428c2ecf20Sopenharmony_ci			 G_TP_VERSION_MINOR(tp_vers),
16438c2ecf20Sopenharmony_ci			 G_TP_VERSION_MICRO(tp_vers));
16448c2ecf20Sopenharmony_ci}
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_cistatic void get_strings(struct net_device *dev, u32 stringset, u8 * data)
16478c2ecf20Sopenharmony_ci{
16488c2ecf20Sopenharmony_ci	if (stringset == ETH_SS_STATS)
16498c2ecf20Sopenharmony_ci		memcpy(data, stats_strings, sizeof(stats_strings));
16508c2ecf20Sopenharmony_ci}
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_cistatic unsigned long collect_sge_port_stats(struct adapter *adapter,
16538c2ecf20Sopenharmony_ci					    struct port_info *p, int idx)
16548c2ecf20Sopenharmony_ci{
16558c2ecf20Sopenharmony_ci	int i;
16568c2ecf20Sopenharmony_ci	unsigned long tot = 0;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i)
16598c2ecf20Sopenharmony_ci		tot += adapter->sge.qs[i].port_stats[idx];
16608c2ecf20Sopenharmony_ci	return tot;
16618c2ecf20Sopenharmony_ci}
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_cistatic void get_stats(struct net_device *dev, struct ethtool_stats *stats,
16648c2ecf20Sopenharmony_ci		      u64 *data)
16658c2ecf20Sopenharmony_ci{
16668c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
16678c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
16688c2ecf20Sopenharmony_ci	const struct mac_stats *s;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	spin_lock(&adapter->stats_lock);
16718c2ecf20Sopenharmony_ci	s = t3_mac_update_stats(&pi->mac);
16728c2ecf20Sopenharmony_ci	spin_unlock(&adapter->stats_lock);
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	*data++ = s->tx_octets;
16758c2ecf20Sopenharmony_ci	*data++ = s->tx_frames;
16768c2ecf20Sopenharmony_ci	*data++ = s->tx_mcast_frames;
16778c2ecf20Sopenharmony_ci	*data++ = s->tx_bcast_frames;
16788c2ecf20Sopenharmony_ci	*data++ = s->tx_pause;
16798c2ecf20Sopenharmony_ci	*data++ = s->tx_underrun;
16808c2ecf20Sopenharmony_ci	*data++ = s->tx_fifo_urun;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	*data++ = s->tx_frames_64;
16838c2ecf20Sopenharmony_ci	*data++ = s->tx_frames_65_127;
16848c2ecf20Sopenharmony_ci	*data++ = s->tx_frames_128_255;
16858c2ecf20Sopenharmony_ci	*data++ = s->tx_frames_256_511;
16868c2ecf20Sopenharmony_ci	*data++ = s->tx_frames_512_1023;
16878c2ecf20Sopenharmony_ci	*data++ = s->tx_frames_1024_1518;
16888c2ecf20Sopenharmony_ci	*data++ = s->tx_frames_1519_max;
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	*data++ = s->rx_octets;
16918c2ecf20Sopenharmony_ci	*data++ = s->rx_frames;
16928c2ecf20Sopenharmony_ci	*data++ = s->rx_mcast_frames;
16938c2ecf20Sopenharmony_ci	*data++ = s->rx_bcast_frames;
16948c2ecf20Sopenharmony_ci	*data++ = s->rx_pause;
16958c2ecf20Sopenharmony_ci	*data++ = s->rx_fcs_errs;
16968c2ecf20Sopenharmony_ci	*data++ = s->rx_symbol_errs;
16978c2ecf20Sopenharmony_ci	*data++ = s->rx_short;
16988c2ecf20Sopenharmony_ci	*data++ = s->rx_jabber;
16998c2ecf20Sopenharmony_ci	*data++ = s->rx_too_long;
17008c2ecf20Sopenharmony_ci	*data++ = s->rx_fifo_ovfl;
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	*data++ = s->rx_frames_64;
17038c2ecf20Sopenharmony_ci	*data++ = s->rx_frames_65_127;
17048c2ecf20Sopenharmony_ci	*data++ = s->rx_frames_128_255;
17058c2ecf20Sopenharmony_ci	*data++ = s->rx_frames_256_511;
17068c2ecf20Sopenharmony_ci	*data++ = s->rx_frames_512_1023;
17078c2ecf20Sopenharmony_ci	*data++ = s->rx_frames_1024_1518;
17088c2ecf20Sopenharmony_ci	*data++ = s->rx_frames_1519_max;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	*data++ = pi->phy.fifo_errors;
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
17138c2ecf20Sopenharmony_ci	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
17148c2ecf20Sopenharmony_ci	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
17158c2ecf20Sopenharmony_ci	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
17168c2ecf20Sopenharmony_ci	*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
17178c2ecf20Sopenharmony_ci	*data++ = 0;
17188c2ecf20Sopenharmony_ci	*data++ = 0;
17198c2ecf20Sopenharmony_ci	*data++ = 0;
17208c2ecf20Sopenharmony_ci	*data++ = s->rx_cong_drops;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	*data++ = s->num_toggled;
17238c2ecf20Sopenharmony_ci	*data++ = s->num_resets;
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	*data++ = s->link_faults;
17268c2ecf20Sopenharmony_ci}
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_cistatic inline void reg_block_dump(struct adapter *ap, void *buf,
17298c2ecf20Sopenharmony_ci				  unsigned int start, unsigned int end)
17308c2ecf20Sopenharmony_ci{
17318c2ecf20Sopenharmony_ci	u32 *p = buf + start;
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	for (; start <= end; start += sizeof(u32))
17348c2ecf20Sopenharmony_ci		*p++ = t3_read_reg(ap, start);
17358c2ecf20Sopenharmony_ci}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_cistatic void get_regs(struct net_device *dev, struct ethtool_regs *regs,
17388c2ecf20Sopenharmony_ci		     void *buf)
17398c2ecf20Sopenharmony_ci{
17408c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
17418c2ecf20Sopenharmony_ci	struct adapter *ap = pi->adapter;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	/*
17448c2ecf20Sopenharmony_ci	 * Version scheme:
17458c2ecf20Sopenharmony_ci	 * bits 0..9: chip version
17468c2ecf20Sopenharmony_ci	 * bits 10..15: chip revision
17478c2ecf20Sopenharmony_ci	 * bit 31: set for PCIe cards
17488c2ecf20Sopenharmony_ci	 */
17498c2ecf20Sopenharmony_ci	regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	/*
17528c2ecf20Sopenharmony_ci	 * We skip the MAC statistics registers because they are clear-on-read.
17538c2ecf20Sopenharmony_ci	 * Also reading multi-register stats would need to synchronize with the
17548c2ecf20Sopenharmony_ci	 * periodic mac stats accumulation.  Hard to justify the complexity.
17558c2ecf20Sopenharmony_ci	 */
17568c2ecf20Sopenharmony_ci	memset(buf, 0, T3_REGMAP_SIZE);
17578c2ecf20Sopenharmony_ci	reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
17588c2ecf20Sopenharmony_ci	reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
17598c2ecf20Sopenharmony_ci	reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
17608c2ecf20Sopenharmony_ci	reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
17618c2ecf20Sopenharmony_ci	reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
17628c2ecf20Sopenharmony_ci	reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
17638c2ecf20Sopenharmony_ci		       XGM_REG(A_XGM_SERDES_STAT3, 1));
17648c2ecf20Sopenharmony_ci	reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
17658c2ecf20Sopenharmony_ci		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
17668c2ecf20Sopenharmony_ci}
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_cistatic int restart_autoneg(struct net_device *dev)
17698c2ecf20Sopenharmony_ci{
17708c2ecf20Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	if (!netif_running(dev))
17738c2ecf20Sopenharmony_ci		return -EAGAIN;
17748c2ecf20Sopenharmony_ci	if (p->link_config.autoneg != AUTONEG_ENABLE)
17758c2ecf20Sopenharmony_ci		return -EINVAL;
17768c2ecf20Sopenharmony_ci	p->phy.ops->autoneg_restart(&p->phy);
17778c2ecf20Sopenharmony_ci	return 0;
17788c2ecf20Sopenharmony_ci}
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_cistatic int set_phys_id(struct net_device *dev,
17818c2ecf20Sopenharmony_ci		       enum ethtool_phys_id_state state)
17828c2ecf20Sopenharmony_ci{
17838c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
17848c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	switch (state) {
17878c2ecf20Sopenharmony_ci	case ETHTOOL_ID_ACTIVE:
17888c2ecf20Sopenharmony_ci		return 1;	/* cycle on/off once per second */
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	case ETHTOOL_ID_OFF:
17918c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0);
17928c2ecf20Sopenharmony_ci		break;
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	case ETHTOOL_ID_ON:
17958c2ecf20Sopenharmony_ci	case ETHTOOL_ID_INACTIVE:
17968c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
17978c2ecf20Sopenharmony_ci			 F_GPIO0_OUT_VAL);
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	return 0;
18018c2ecf20Sopenharmony_ci}
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_cistatic int get_link_ksettings(struct net_device *dev,
18048c2ecf20Sopenharmony_ci			      struct ethtool_link_ksettings *cmd)
18058c2ecf20Sopenharmony_ci{
18068c2ecf20Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
18078c2ecf20Sopenharmony_ci	u32 supported;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
18108c2ecf20Sopenharmony_ci						p->link_config.supported);
18118c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
18128c2ecf20Sopenharmony_ci						p->link_config.advertising);
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	if (netif_carrier_ok(dev)) {
18158c2ecf20Sopenharmony_ci		cmd->base.speed = p->link_config.speed;
18168c2ecf20Sopenharmony_ci		cmd->base.duplex = p->link_config.duplex;
18178c2ecf20Sopenharmony_ci	} else {
18188c2ecf20Sopenharmony_ci		cmd->base.speed = SPEED_UNKNOWN;
18198c2ecf20Sopenharmony_ci		cmd->base.duplex = DUPLEX_UNKNOWN;
18208c2ecf20Sopenharmony_ci	}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	ethtool_convert_link_mode_to_legacy_u32(&supported,
18238c2ecf20Sopenharmony_ci						cmd->link_modes.supported);
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	cmd->base.port = (supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
18268c2ecf20Sopenharmony_ci	cmd->base.phy_address = p->phy.mdio.prtad;
18278c2ecf20Sopenharmony_ci	cmd->base.autoneg = p->link_config.autoneg;
18288c2ecf20Sopenharmony_ci	return 0;
18298c2ecf20Sopenharmony_ci}
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_cistatic int speed_duplex_to_caps(int speed, int duplex)
18328c2ecf20Sopenharmony_ci{
18338c2ecf20Sopenharmony_ci	int cap = 0;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	switch (speed) {
18368c2ecf20Sopenharmony_ci	case SPEED_10:
18378c2ecf20Sopenharmony_ci		if (duplex == DUPLEX_FULL)
18388c2ecf20Sopenharmony_ci			cap = SUPPORTED_10baseT_Full;
18398c2ecf20Sopenharmony_ci		else
18408c2ecf20Sopenharmony_ci			cap = SUPPORTED_10baseT_Half;
18418c2ecf20Sopenharmony_ci		break;
18428c2ecf20Sopenharmony_ci	case SPEED_100:
18438c2ecf20Sopenharmony_ci		if (duplex == DUPLEX_FULL)
18448c2ecf20Sopenharmony_ci			cap = SUPPORTED_100baseT_Full;
18458c2ecf20Sopenharmony_ci		else
18468c2ecf20Sopenharmony_ci			cap = SUPPORTED_100baseT_Half;
18478c2ecf20Sopenharmony_ci		break;
18488c2ecf20Sopenharmony_ci	case SPEED_1000:
18498c2ecf20Sopenharmony_ci		if (duplex == DUPLEX_FULL)
18508c2ecf20Sopenharmony_ci			cap = SUPPORTED_1000baseT_Full;
18518c2ecf20Sopenharmony_ci		else
18528c2ecf20Sopenharmony_ci			cap = SUPPORTED_1000baseT_Half;
18538c2ecf20Sopenharmony_ci		break;
18548c2ecf20Sopenharmony_ci	case SPEED_10000:
18558c2ecf20Sopenharmony_ci		if (duplex == DUPLEX_FULL)
18568c2ecf20Sopenharmony_ci			cap = SUPPORTED_10000baseT_Full;
18578c2ecf20Sopenharmony_ci	}
18588c2ecf20Sopenharmony_ci	return cap;
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
18628c2ecf20Sopenharmony_ci		      ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
18638c2ecf20Sopenharmony_ci		      ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
18648c2ecf20Sopenharmony_ci		      ADVERTISED_10000baseT_Full)
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_cistatic int set_link_ksettings(struct net_device *dev,
18678c2ecf20Sopenharmony_ci			      const struct ethtool_link_ksettings *cmd)
18688c2ecf20Sopenharmony_ci{
18698c2ecf20Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
18708c2ecf20Sopenharmony_ci	struct link_config *lc = &p->link_config;
18718c2ecf20Sopenharmony_ci	u32 advertising;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	ethtool_convert_link_mode_to_legacy_u32(&advertising,
18748c2ecf20Sopenharmony_ci						cmd->link_modes.advertising);
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	if (!(lc->supported & SUPPORTED_Autoneg)) {
18778c2ecf20Sopenharmony_ci		/*
18788c2ecf20Sopenharmony_ci		 * PHY offers a single speed/duplex.  See if that's what's
18798c2ecf20Sopenharmony_ci		 * being requested.
18808c2ecf20Sopenharmony_ci		 */
18818c2ecf20Sopenharmony_ci		if (cmd->base.autoneg == AUTONEG_DISABLE) {
18828c2ecf20Sopenharmony_ci			u32 speed = cmd->base.speed;
18838c2ecf20Sopenharmony_ci			int cap = speed_duplex_to_caps(speed, cmd->base.duplex);
18848c2ecf20Sopenharmony_ci			if (lc->supported & cap)
18858c2ecf20Sopenharmony_ci				return 0;
18868c2ecf20Sopenharmony_ci		}
18878c2ecf20Sopenharmony_ci		return -EINVAL;
18888c2ecf20Sopenharmony_ci	}
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	if (cmd->base.autoneg == AUTONEG_DISABLE) {
18918c2ecf20Sopenharmony_ci		u32 speed = cmd->base.speed;
18928c2ecf20Sopenharmony_ci		int cap = speed_duplex_to_caps(speed, cmd->base.duplex);
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci		if (!(lc->supported & cap) || (speed == SPEED_1000))
18958c2ecf20Sopenharmony_ci			return -EINVAL;
18968c2ecf20Sopenharmony_ci		lc->requested_speed = speed;
18978c2ecf20Sopenharmony_ci		lc->requested_duplex = cmd->base.duplex;
18988c2ecf20Sopenharmony_ci		lc->advertising = 0;
18998c2ecf20Sopenharmony_ci	} else {
19008c2ecf20Sopenharmony_ci		advertising &= ADVERTISED_MASK;
19018c2ecf20Sopenharmony_ci		advertising &= lc->supported;
19028c2ecf20Sopenharmony_ci		if (!advertising)
19038c2ecf20Sopenharmony_ci			return -EINVAL;
19048c2ecf20Sopenharmony_ci		lc->requested_speed = SPEED_INVALID;
19058c2ecf20Sopenharmony_ci		lc->requested_duplex = DUPLEX_INVALID;
19068c2ecf20Sopenharmony_ci		lc->advertising = advertising | ADVERTISED_Autoneg;
19078c2ecf20Sopenharmony_ci	}
19088c2ecf20Sopenharmony_ci	lc->autoneg = cmd->base.autoneg;
19098c2ecf20Sopenharmony_ci	if (netif_running(dev))
19108c2ecf20Sopenharmony_ci		t3_link_start(&p->phy, &p->mac, lc);
19118c2ecf20Sopenharmony_ci	return 0;
19128c2ecf20Sopenharmony_ci}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_cistatic void get_pauseparam(struct net_device *dev,
19158c2ecf20Sopenharmony_ci			   struct ethtool_pauseparam *epause)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
19208c2ecf20Sopenharmony_ci	epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
19218c2ecf20Sopenharmony_ci	epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
19228c2ecf20Sopenharmony_ci}
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_cistatic int set_pauseparam(struct net_device *dev,
19258c2ecf20Sopenharmony_ci			  struct ethtool_pauseparam *epause)
19268c2ecf20Sopenharmony_ci{
19278c2ecf20Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
19288c2ecf20Sopenharmony_ci	struct link_config *lc = &p->link_config;
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	if (epause->autoneg == AUTONEG_DISABLE)
19318c2ecf20Sopenharmony_ci		lc->requested_fc = 0;
19328c2ecf20Sopenharmony_ci	else if (lc->supported & SUPPORTED_Autoneg)
19338c2ecf20Sopenharmony_ci		lc->requested_fc = PAUSE_AUTONEG;
19348c2ecf20Sopenharmony_ci	else
19358c2ecf20Sopenharmony_ci		return -EINVAL;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	if (epause->rx_pause)
19388c2ecf20Sopenharmony_ci		lc->requested_fc |= PAUSE_RX;
19398c2ecf20Sopenharmony_ci	if (epause->tx_pause)
19408c2ecf20Sopenharmony_ci		lc->requested_fc |= PAUSE_TX;
19418c2ecf20Sopenharmony_ci	if (lc->autoneg == AUTONEG_ENABLE) {
19428c2ecf20Sopenharmony_ci		if (netif_running(dev))
19438c2ecf20Sopenharmony_ci			t3_link_start(&p->phy, &p->mac, lc);
19448c2ecf20Sopenharmony_ci	} else {
19458c2ecf20Sopenharmony_ci		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
19468c2ecf20Sopenharmony_ci		if (netif_running(dev))
19478c2ecf20Sopenharmony_ci			t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
19488c2ecf20Sopenharmony_ci	}
19498c2ecf20Sopenharmony_ci	return 0;
19508c2ecf20Sopenharmony_ci}
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_cistatic void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
19538c2ecf20Sopenharmony_ci{
19548c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
19558c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
19568c2ecf20Sopenharmony_ci	const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci	e->rx_max_pending = MAX_RX_BUFFERS;
19598c2ecf20Sopenharmony_ci	e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
19608c2ecf20Sopenharmony_ci	e->tx_max_pending = MAX_TXQ_ENTRIES;
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci	e->rx_pending = q->fl_size;
19638c2ecf20Sopenharmony_ci	e->rx_mini_pending = q->rspq_size;
19648c2ecf20Sopenharmony_ci	e->rx_jumbo_pending = q->jumbo_size;
19658c2ecf20Sopenharmony_ci	e->tx_pending = q->txq_size[0];
19668c2ecf20Sopenharmony_ci}
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_cistatic int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
19698c2ecf20Sopenharmony_ci{
19708c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
19718c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
19728c2ecf20Sopenharmony_ci	struct qset_params *q;
19738c2ecf20Sopenharmony_ci	int i;
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	if (e->rx_pending > MAX_RX_BUFFERS ||
19768c2ecf20Sopenharmony_ci	    e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
19778c2ecf20Sopenharmony_ci	    e->tx_pending > MAX_TXQ_ENTRIES ||
19788c2ecf20Sopenharmony_ci	    e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
19798c2ecf20Sopenharmony_ci	    e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
19808c2ecf20Sopenharmony_ci	    e->rx_pending < MIN_FL_ENTRIES ||
19818c2ecf20Sopenharmony_ci	    e->rx_jumbo_pending < MIN_FL_ENTRIES ||
19828c2ecf20Sopenharmony_ci	    e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
19838c2ecf20Sopenharmony_ci		return -EINVAL;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	if (adapter->flags & FULL_INIT_DONE)
19868c2ecf20Sopenharmony_ci		return -EBUSY;
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	q = &adapter->params.sge.qset[pi->first_qset];
19898c2ecf20Sopenharmony_ci	for (i = 0; i < pi->nqsets; ++i, ++q) {
19908c2ecf20Sopenharmony_ci		q->rspq_size = e->rx_mini_pending;
19918c2ecf20Sopenharmony_ci		q->fl_size = e->rx_pending;
19928c2ecf20Sopenharmony_ci		q->jumbo_size = e->rx_jumbo_pending;
19938c2ecf20Sopenharmony_ci		q->txq_size[0] = e->tx_pending;
19948c2ecf20Sopenharmony_ci		q->txq_size[1] = e->tx_pending;
19958c2ecf20Sopenharmony_ci		q->txq_size[2] = e->tx_pending;
19968c2ecf20Sopenharmony_ci	}
19978c2ecf20Sopenharmony_ci	return 0;
19988c2ecf20Sopenharmony_ci}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_cistatic int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
20018c2ecf20Sopenharmony_ci{
20028c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
20038c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
20048c2ecf20Sopenharmony_ci	struct qset_params *qsp;
20058c2ecf20Sopenharmony_ci	struct sge_qset *qs;
20068c2ecf20Sopenharmony_ci	int i;
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
20098c2ecf20Sopenharmony_ci		return -EINVAL;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	for (i = 0; i < pi->nqsets; i++) {
20128c2ecf20Sopenharmony_ci		qsp = &adapter->params.sge.qset[i];
20138c2ecf20Sopenharmony_ci		qs = &adapter->sge.qs[i];
20148c2ecf20Sopenharmony_ci		qsp->coalesce_usecs = c->rx_coalesce_usecs;
20158c2ecf20Sopenharmony_ci		t3_update_qset_coalesce(qs, qsp);
20168c2ecf20Sopenharmony_ci	}
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	return 0;
20198c2ecf20Sopenharmony_ci}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_cistatic int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
20228c2ecf20Sopenharmony_ci{
20238c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
20248c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
20258c2ecf20Sopenharmony_ci	struct qset_params *q = adapter->params.sge.qset;
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	c->rx_coalesce_usecs = q->coalesce_usecs;
20288c2ecf20Sopenharmony_ci	return 0;
20298c2ecf20Sopenharmony_ci}
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_cistatic int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
20328c2ecf20Sopenharmony_ci		      u8 * data)
20338c2ecf20Sopenharmony_ci{
20348c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
20358c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
20368c2ecf20Sopenharmony_ci	int i, err = 0;
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
20398c2ecf20Sopenharmony_ci	if (!buf)
20408c2ecf20Sopenharmony_ci		return -ENOMEM;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	e->magic = EEPROM_MAGIC;
20438c2ecf20Sopenharmony_ci	for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
20448c2ecf20Sopenharmony_ci		err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	if (!err)
20478c2ecf20Sopenharmony_ci		memcpy(data, buf + e->offset, e->len);
20488c2ecf20Sopenharmony_ci	kfree(buf);
20498c2ecf20Sopenharmony_ci	return err;
20508c2ecf20Sopenharmony_ci}
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_cistatic int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
20538c2ecf20Sopenharmony_ci		      u8 * data)
20548c2ecf20Sopenharmony_ci{
20558c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
20568c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
20578c2ecf20Sopenharmony_ci	u32 aligned_offset, aligned_len;
20588c2ecf20Sopenharmony_ci	__le32 *p;
20598c2ecf20Sopenharmony_ci	u8 *buf;
20608c2ecf20Sopenharmony_ci	int err;
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	if (eeprom->magic != EEPROM_MAGIC)
20638c2ecf20Sopenharmony_ci		return -EINVAL;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	aligned_offset = eeprom->offset & ~3;
20668c2ecf20Sopenharmony_ci	aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
20698c2ecf20Sopenharmony_ci		buf = kmalloc(aligned_len, GFP_KERNEL);
20708c2ecf20Sopenharmony_ci		if (!buf)
20718c2ecf20Sopenharmony_ci			return -ENOMEM;
20728c2ecf20Sopenharmony_ci		err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
20738c2ecf20Sopenharmony_ci		if (!err && aligned_len > 4)
20748c2ecf20Sopenharmony_ci			err = t3_seeprom_read(adapter,
20758c2ecf20Sopenharmony_ci					      aligned_offset + aligned_len - 4,
20768c2ecf20Sopenharmony_ci					      (__le32 *) & buf[aligned_len - 4]);
20778c2ecf20Sopenharmony_ci		if (err)
20788c2ecf20Sopenharmony_ci			goto out;
20798c2ecf20Sopenharmony_ci		memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
20808c2ecf20Sopenharmony_ci	} else
20818c2ecf20Sopenharmony_ci		buf = data;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	err = t3_seeprom_wp(adapter, 0);
20848c2ecf20Sopenharmony_ci	if (err)
20858c2ecf20Sopenharmony_ci		goto out;
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
20888c2ecf20Sopenharmony_ci		err = t3_seeprom_write(adapter, aligned_offset, *p);
20898c2ecf20Sopenharmony_ci		aligned_offset += 4;
20908c2ecf20Sopenharmony_ci	}
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	if (!err)
20938c2ecf20Sopenharmony_ci		err = t3_seeprom_wp(adapter, 1);
20948c2ecf20Sopenharmony_ciout:
20958c2ecf20Sopenharmony_ci	if (buf != data)
20968c2ecf20Sopenharmony_ci		kfree(buf);
20978c2ecf20Sopenharmony_ci	return err;
20988c2ecf20Sopenharmony_ci}
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_cistatic void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
21018c2ecf20Sopenharmony_ci{
21028c2ecf20Sopenharmony_ci	wol->supported = 0;
21038c2ecf20Sopenharmony_ci	wol->wolopts = 0;
21048c2ecf20Sopenharmony_ci	memset(&wol->sopass, 0, sizeof(wol->sopass));
21058c2ecf20Sopenharmony_ci}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_cistatic const struct ethtool_ops cxgb_ethtool_ops = {
21088c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS,
21098c2ecf20Sopenharmony_ci	.get_drvinfo = get_drvinfo,
21108c2ecf20Sopenharmony_ci	.get_msglevel = get_msglevel,
21118c2ecf20Sopenharmony_ci	.set_msglevel = set_msglevel,
21128c2ecf20Sopenharmony_ci	.get_ringparam = get_sge_param,
21138c2ecf20Sopenharmony_ci	.set_ringparam = set_sge_param,
21148c2ecf20Sopenharmony_ci	.get_coalesce = get_coalesce,
21158c2ecf20Sopenharmony_ci	.set_coalesce = set_coalesce,
21168c2ecf20Sopenharmony_ci	.get_eeprom_len = get_eeprom_len,
21178c2ecf20Sopenharmony_ci	.get_eeprom = get_eeprom,
21188c2ecf20Sopenharmony_ci	.set_eeprom = set_eeprom,
21198c2ecf20Sopenharmony_ci	.get_pauseparam = get_pauseparam,
21208c2ecf20Sopenharmony_ci	.set_pauseparam = set_pauseparam,
21218c2ecf20Sopenharmony_ci	.get_link = ethtool_op_get_link,
21228c2ecf20Sopenharmony_ci	.get_strings = get_strings,
21238c2ecf20Sopenharmony_ci	.set_phys_id = set_phys_id,
21248c2ecf20Sopenharmony_ci	.nway_reset = restart_autoneg,
21258c2ecf20Sopenharmony_ci	.get_sset_count = get_sset_count,
21268c2ecf20Sopenharmony_ci	.get_ethtool_stats = get_stats,
21278c2ecf20Sopenharmony_ci	.get_regs_len = get_regs_len,
21288c2ecf20Sopenharmony_ci	.get_regs = get_regs,
21298c2ecf20Sopenharmony_ci	.get_wol = get_wol,
21308c2ecf20Sopenharmony_ci	.get_link_ksettings = get_link_ksettings,
21318c2ecf20Sopenharmony_ci	.set_link_ksettings = set_link_ksettings,
21328c2ecf20Sopenharmony_ci};
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_cistatic int in_range(int val, int lo, int hi)
21358c2ecf20Sopenharmony_ci{
21368c2ecf20Sopenharmony_ci	return val < 0 || (val <= hi && val >= lo);
21378c2ecf20Sopenharmony_ci}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_cistatic int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
21408c2ecf20Sopenharmony_ci{
21418c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
21428c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
21438c2ecf20Sopenharmony_ci	u32 cmd;
21448c2ecf20Sopenharmony_ci	int ret;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
21478c2ecf20Sopenharmony_ci		return -EFAULT;
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	switch (cmd) {
21508c2ecf20Sopenharmony_ci	case CHELSIO_SET_QSET_PARAMS:{
21518c2ecf20Sopenharmony_ci		int i;
21528c2ecf20Sopenharmony_ci		struct qset_params *q;
21538c2ecf20Sopenharmony_ci		struct ch_qset_params t;
21548c2ecf20Sopenharmony_ci		int q1 = pi->first_qset;
21558c2ecf20Sopenharmony_ci		int nqsets = pi->nqsets;
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci		if (!capable(CAP_NET_ADMIN))
21588c2ecf20Sopenharmony_ci			return -EPERM;
21598c2ecf20Sopenharmony_ci		if (copy_from_user(&t, useraddr, sizeof(t)))
21608c2ecf20Sopenharmony_ci			return -EFAULT;
21618c2ecf20Sopenharmony_ci		if (t.cmd != CHELSIO_SET_QSET_PARAMS)
21628c2ecf20Sopenharmony_ci			return -EINVAL;
21638c2ecf20Sopenharmony_ci		if (t.qset_idx >= SGE_QSETS)
21648c2ecf20Sopenharmony_ci			return -EINVAL;
21658c2ecf20Sopenharmony_ci		if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
21668c2ecf20Sopenharmony_ci		    !in_range(t.cong_thres, 0, 255) ||
21678c2ecf20Sopenharmony_ci		    !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
21688c2ecf20Sopenharmony_ci			      MAX_TXQ_ENTRIES) ||
21698c2ecf20Sopenharmony_ci		    !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
21708c2ecf20Sopenharmony_ci			      MAX_TXQ_ENTRIES) ||
21718c2ecf20Sopenharmony_ci		    !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
21728c2ecf20Sopenharmony_ci			      MAX_CTRL_TXQ_ENTRIES) ||
21738c2ecf20Sopenharmony_ci		    !in_range(t.fl_size[0], MIN_FL_ENTRIES,
21748c2ecf20Sopenharmony_ci			      MAX_RX_BUFFERS) ||
21758c2ecf20Sopenharmony_ci		    !in_range(t.fl_size[1], MIN_FL_ENTRIES,
21768c2ecf20Sopenharmony_ci			      MAX_RX_JUMBO_BUFFERS) ||
21778c2ecf20Sopenharmony_ci		    !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
21788c2ecf20Sopenharmony_ci			      MAX_RSPQ_ENTRIES))
21798c2ecf20Sopenharmony_ci			return -EINVAL;
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci		if ((adapter->flags & FULL_INIT_DONE) &&
21828c2ecf20Sopenharmony_ci			(t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
21838c2ecf20Sopenharmony_ci			t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
21848c2ecf20Sopenharmony_ci			t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
21858c2ecf20Sopenharmony_ci			t.polling >= 0 || t.cong_thres >= 0))
21868c2ecf20Sopenharmony_ci			return -EBUSY;
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci		/* Allow setting of any available qset when offload enabled */
21898c2ecf20Sopenharmony_ci		if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
21908c2ecf20Sopenharmony_ci			q1 = 0;
21918c2ecf20Sopenharmony_ci			for_each_port(adapter, i) {
21928c2ecf20Sopenharmony_ci				pi = adap2pinfo(adapter, i);
21938c2ecf20Sopenharmony_ci				nqsets += pi->first_qset + pi->nqsets;
21948c2ecf20Sopenharmony_ci			}
21958c2ecf20Sopenharmony_ci		}
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci		if (t.qset_idx < q1)
21988c2ecf20Sopenharmony_ci			return -EINVAL;
21998c2ecf20Sopenharmony_ci		if (t.qset_idx > q1 + nqsets - 1)
22008c2ecf20Sopenharmony_ci			return -EINVAL;
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci		q = &adapter->params.sge.qset[t.qset_idx];
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci		if (t.rspq_size >= 0)
22058c2ecf20Sopenharmony_ci			q->rspq_size = t.rspq_size;
22068c2ecf20Sopenharmony_ci		if (t.fl_size[0] >= 0)
22078c2ecf20Sopenharmony_ci			q->fl_size = t.fl_size[0];
22088c2ecf20Sopenharmony_ci		if (t.fl_size[1] >= 0)
22098c2ecf20Sopenharmony_ci			q->jumbo_size = t.fl_size[1];
22108c2ecf20Sopenharmony_ci		if (t.txq_size[0] >= 0)
22118c2ecf20Sopenharmony_ci			q->txq_size[0] = t.txq_size[0];
22128c2ecf20Sopenharmony_ci		if (t.txq_size[1] >= 0)
22138c2ecf20Sopenharmony_ci			q->txq_size[1] = t.txq_size[1];
22148c2ecf20Sopenharmony_ci		if (t.txq_size[2] >= 0)
22158c2ecf20Sopenharmony_ci			q->txq_size[2] = t.txq_size[2];
22168c2ecf20Sopenharmony_ci		if (t.cong_thres >= 0)
22178c2ecf20Sopenharmony_ci			q->cong_thres = t.cong_thres;
22188c2ecf20Sopenharmony_ci		if (t.intr_lat >= 0) {
22198c2ecf20Sopenharmony_ci			struct sge_qset *qs =
22208c2ecf20Sopenharmony_ci				&adapter->sge.qs[t.qset_idx];
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci			q->coalesce_usecs = t.intr_lat;
22238c2ecf20Sopenharmony_ci			t3_update_qset_coalesce(qs, q);
22248c2ecf20Sopenharmony_ci		}
22258c2ecf20Sopenharmony_ci		if (t.polling >= 0) {
22268c2ecf20Sopenharmony_ci			if (adapter->flags & USING_MSIX)
22278c2ecf20Sopenharmony_ci				q->polling = t.polling;
22288c2ecf20Sopenharmony_ci			else {
22298c2ecf20Sopenharmony_ci				/* No polling with INTx for T3A */
22308c2ecf20Sopenharmony_ci				if (adapter->params.rev == 0 &&
22318c2ecf20Sopenharmony_ci					!(adapter->flags & USING_MSI))
22328c2ecf20Sopenharmony_ci					t.polling = 0;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci				for (i = 0; i < SGE_QSETS; i++) {
22358c2ecf20Sopenharmony_ci					q = &adapter->params.sge.
22368c2ecf20Sopenharmony_ci						qset[i];
22378c2ecf20Sopenharmony_ci					q->polling = t.polling;
22388c2ecf20Sopenharmony_ci				}
22398c2ecf20Sopenharmony_ci			}
22408c2ecf20Sopenharmony_ci		}
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci		if (t.lro >= 0) {
22438c2ecf20Sopenharmony_ci			if (t.lro)
22448c2ecf20Sopenharmony_ci				dev->wanted_features |= NETIF_F_GRO;
22458c2ecf20Sopenharmony_ci			else
22468c2ecf20Sopenharmony_ci				dev->wanted_features &= ~NETIF_F_GRO;
22478c2ecf20Sopenharmony_ci			netdev_update_features(dev);
22488c2ecf20Sopenharmony_ci		}
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci		break;
22518c2ecf20Sopenharmony_ci	}
22528c2ecf20Sopenharmony_ci	case CHELSIO_GET_QSET_PARAMS:{
22538c2ecf20Sopenharmony_ci		struct qset_params *q;
22548c2ecf20Sopenharmony_ci		struct ch_qset_params t;
22558c2ecf20Sopenharmony_ci		int q1 = pi->first_qset;
22568c2ecf20Sopenharmony_ci		int nqsets = pi->nqsets;
22578c2ecf20Sopenharmony_ci		int i;
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci		if (copy_from_user(&t, useraddr, sizeof(t)))
22608c2ecf20Sopenharmony_ci			return -EFAULT;
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci		if (t.cmd != CHELSIO_GET_QSET_PARAMS)
22638c2ecf20Sopenharmony_ci			return -EINVAL;
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci		/* Display qsets for all ports when offload enabled */
22668c2ecf20Sopenharmony_ci		if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
22678c2ecf20Sopenharmony_ci			q1 = 0;
22688c2ecf20Sopenharmony_ci			for_each_port(adapter, i) {
22698c2ecf20Sopenharmony_ci				pi = adap2pinfo(adapter, i);
22708c2ecf20Sopenharmony_ci				nqsets = pi->first_qset + pi->nqsets;
22718c2ecf20Sopenharmony_ci			}
22728c2ecf20Sopenharmony_ci		}
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci		if (t.qset_idx >= nqsets)
22758c2ecf20Sopenharmony_ci			return -EINVAL;
22768c2ecf20Sopenharmony_ci		t.qset_idx = array_index_nospec(t.qset_idx, nqsets);
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci		q = &adapter->params.sge.qset[q1 + t.qset_idx];
22798c2ecf20Sopenharmony_ci		t.rspq_size = q->rspq_size;
22808c2ecf20Sopenharmony_ci		t.txq_size[0] = q->txq_size[0];
22818c2ecf20Sopenharmony_ci		t.txq_size[1] = q->txq_size[1];
22828c2ecf20Sopenharmony_ci		t.txq_size[2] = q->txq_size[2];
22838c2ecf20Sopenharmony_ci		t.fl_size[0] = q->fl_size;
22848c2ecf20Sopenharmony_ci		t.fl_size[1] = q->jumbo_size;
22858c2ecf20Sopenharmony_ci		t.polling = q->polling;
22868c2ecf20Sopenharmony_ci		t.lro = !!(dev->features & NETIF_F_GRO);
22878c2ecf20Sopenharmony_ci		t.intr_lat = q->coalesce_usecs;
22888c2ecf20Sopenharmony_ci		t.cong_thres = q->cong_thres;
22898c2ecf20Sopenharmony_ci		t.qnum = q1;
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci		if (adapter->flags & USING_MSIX)
22928c2ecf20Sopenharmony_ci			t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec;
22938c2ecf20Sopenharmony_ci		else
22948c2ecf20Sopenharmony_ci			t.vector = adapter->pdev->irq;
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci		if (copy_to_user(useraddr, &t, sizeof(t)))
22978c2ecf20Sopenharmony_ci			return -EFAULT;
22988c2ecf20Sopenharmony_ci		break;
22998c2ecf20Sopenharmony_ci	}
23008c2ecf20Sopenharmony_ci	case CHELSIO_SET_QSET_NUM:{
23018c2ecf20Sopenharmony_ci		struct ch_reg edata;
23028c2ecf20Sopenharmony_ci		unsigned int i, first_qset = 0, other_qsets = 0;
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci		if (!capable(CAP_NET_ADMIN))
23058c2ecf20Sopenharmony_ci			return -EPERM;
23068c2ecf20Sopenharmony_ci		if (adapter->flags & FULL_INIT_DONE)
23078c2ecf20Sopenharmony_ci			return -EBUSY;
23088c2ecf20Sopenharmony_ci		if (copy_from_user(&edata, useraddr, sizeof(edata)))
23098c2ecf20Sopenharmony_ci			return -EFAULT;
23108c2ecf20Sopenharmony_ci		if (edata.cmd != CHELSIO_SET_QSET_NUM)
23118c2ecf20Sopenharmony_ci			return -EINVAL;
23128c2ecf20Sopenharmony_ci		if (edata.val < 1 ||
23138c2ecf20Sopenharmony_ci			(edata.val > 1 && !(adapter->flags & USING_MSIX)))
23148c2ecf20Sopenharmony_ci			return -EINVAL;
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci		for_each_port(adapter, i)
23178c2ecf20Sopenharmony_ci			if (adapter->port[i] && adapter->port[i] != dev)
23188c2ecf20Sopenharmony_ci				other_qsets += adap2pinfo(adapter, i)->nqsets;
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci		if (edata.val + other_qsets > SGE_QSETS)
23218c2ecf20Sopenharmony_ci			return -EINVAL;
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci		pi->nqsets = edata.val;
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci		for_each_port(adapter, i)
23268c2ecf20Sopenharmony_ci			if (adapter->port[i]) {
23278c2ecf20Sopenharmony_ci				pi = adap2pinfo(adapter, i);
23288c2ecf20Sopenharmony_ci				pi->first_qset = first_qset;
23298c2ecf20Sopenharmony_ci				first_qset += pi->nqsets;
23308c2ecf20Sopenharmony_ci			}
23318c2ecf20Sopenharmony_ci		break;
23328c2ecf20Sopenharmony_ci	}
23338c2ecf20Sopenharmony_ci	case CHELSIO_GET_QSET_NUM:{
23348c2ecf20Sopenharmony_ci		struct ch_reg edata;
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci		memset(&edata, 0, sizeof(struct ch_reg));
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci		edata.cmd = CHELSIO_GET_QSET_NUM;
23398c2ecf20Sopenharmony_ci		edata.val = pi->nqsets;
23408c2ecf20Sopenharmony_ci		if (copy_to_user(useraddr, &edata, sizeof(edata)))
23418c2ecf20Sopenharmony_ci			return -EFAULT;
23428c2ecf20Sopenharmony_ci		break;
23438c2ecf20Sopenharmony_ci	}
23448c2ecf20Sopenharmony_ci	case CHELSIO_LOAD_FW:{
23458c2ecf20Sopenharmony_ci		u8 *fw_data;
23468c2ecf20Sopenharmony_ci		struct ch_mem_range t;
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_RAWIO))
23498c2ecf20Sopenharmony_ci			return -EPERM;
23508c2ecf20Sopenharmony_ci		if (copy_from_user(&t, useraddr, sizeof(t)))
23518c2ecf20Sopenharmony_ci			return -EFAULT;
23528c2ecf20Sopenharmony_ci		if (t.cmd != CHELSIO_LOAD_FW)
23538c2ecf20Sopenharmony_ci			return -EINVAL;
23548c2ecf20Sopenharmony_ci		/* Check t.len sanity ? */
23558c2ecf20Sopenharmony_ci		fw_data = memdup_user(useraddr + sizeof(t), t.len);
23568c2ecf20Sopenharmony_ci		if (IS_ERR(fw_data))
23578c2ecf20Sopenharmony_ci			return PTR_ERR(fw_data);
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci		ret = t3_load_fw(adapter, fw_data, t.len);
23608c2ecf20Sopenharmony_ci		kfree(fw_data);
23618c2ecf20Sopenharmony_ci		if (ret)
23628c2ecf20Sopenharmony_ci			return ret;
23638c2ecf20Sopenharmony_ci		break;
23648c2ecf20Sopenharmony_ci	}
23658c2ecf20Sopenharmony_ci	case CHELSIO_SETMTUTAB:{
23668c2ecf20Sopenharmony_ci		struct ch_mtus m;
23678c2ecf20Sopenharmony_ci		int i;
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci		if (!is_offload(adapter))
23708c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
23718c2ecf20Sopenharmony_ci		if (!capable(CAP_NET_ADMIN))
23728c2ecf20Sopenharmony_ci			return -EPERM;
23738c2ecf20Sopenharmony_ci		if (offload_running(adapter))
23748c2ecf20Sopenharmony_ci			return -EBUSY;
23758c2ecf20Sopenharmony_ci		if (copy_from_user(&m, useraddr, sizeof(m)))
23768c2ecf20Sopenharmony_ci			return -EFAULT;
23778c2ecf20Sopenharmony_ci		if (m.cmd != CHELSIO_SETMTUTAB)
23788c2ecf20Sopenharmony_ci			return -EINVAL;
23798c2ecf20Sopenharmony_ci		if (m.nmtus != NMTUS)
23808c2ecf20Sopenharmony_ci			return -EINVAL;
23818c2ecf20Sopenharmony_ci		if (m.mtus[0] < 81)	/* accommodate SACK */
23828c2ecf20Sopenharmony_ci			return -EINVAL;
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci		/* MTUs must be in ascending order */
23858c2ecf20Sopenharmony_ci		for (i = 1; i < NMTUS; ++i)
23868c2ecf20Sopenharmony_ci			if (m.mtus[i] < m.mtus[i - 1])
23878c2ecf20Sopenharmony_ci				return -EINVAL;
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci		memcpy(adapter->params.mtus, m.mtus,
23908c2ecf20Sopenharmony_ci			sizeof(adapter->params.mtus));
23918c2ecf20Sopenharmony_ci		break;
23928c2ecf20Sopenharmony_ci	}
23938c2ecf20Sopenharmony_ci	case CHELSIO_GET_PM:{
23948c2ecf20Sopenharmony_ci		struct tp_params *p = &adapter->params.tp;
23958c2ecf20Sopenharmony_ci		struct ch_pm m = {.cmd = CHELSIO_GET_PM };
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci		if (!is_offload(adapter))
23988c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
23998c2ecf20Sopenharmony_ci		m.tx_pg_sz = p->tx_pg_size;
24008c2ecf20Sopenharmony_ci		m.tx_num_pg = p->tx_num_pgs;
24018c2ecf20Sopenharmony_ci		m.rx_pg_sz = p->rx_pg_size;
24028c2ecf20Sopenharmony_ci		m.rx_num_pg = p->rx_num_pgs;
24038c2ecf20Sopenharmony_ci		m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
24048c2ecf20Sopenharmony_ci		if (copy_to_user(useraddr, &m, sizeof(m)))
24058c2ecf20Sopenharmony_ci			return -EFAULT;
24068c2ecf20Sopenharmony_ci		break;
24078c2ecf20Sopenharmony_ci	}
24088c2ecf20Sopenharmony_ci	case CHELSIO_SET_PM:{
24098c2ecf20Sopenharmony_ci		struct ch_pm m;
24108c2ecf20Sopenharmony_ci		struct tp_params *p = &adapter->params.tp;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci		if (!is_offload(adapter))
24138c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
24148c2ecf20Sopenharmony_ci		if (!capable(CAP_NET_ADMIN))
24158c2ecf20Sopenharmony_ci			return -EPERM;
24168c2ecf20Sopenharmony_ci		if (adapter->flags & FULL_INIT_DONE)
24178c2ecf20Sopenharmony_ci			return -EBUSY;
24188c2ecf20Sopenharmony_ci		if (copy_from_user(&m, useraddr, sizeof(m)))
24198c2ecf20Sopenharmony_ci			return -EFAULT;
24208c2ecf20Sopenharmony_ci		if (m.cmd != CHELSIO_SET_PM)
24218c2ecf20Sopenharmony_ci			return -EINVAL;
24228c2ecf20Sopenharmony_ci		if (!is_power_of_2(m.rx_pg_sz) ||
24238c2ecf20Sopenharmony_ci			!is_power_of_2(m.tx_pg_sz))
24248c2ecf20Sopenharmony_ci			return -EINVAL;	/* not power of 2 */
24258c2ecf20Sopenharmony_ci		if (!(m.rx_pg_sz & 0x14000))
24268c2ecf20Sopenharmony_ci			return -EINVAL;	/* not 16KB or 64KB */
24278c2ecf20Sopenharmony_ci		if (!(m.tx_pg_sz & 0x1554000))
24288c2ecf20Sopenharmony_ci			return -EINVAL;
24298c2ecf20Sopenharmony_ci		if (m.tx_num_pg == -1)
24308c2ecf20Sopenharmony_ci			m.tx_num_pg = p->tx_num_pgs;
24318c2ecf20Sopenharmony_ci		if (m.rx_num_pg == -1)
24328c2ecf20Sopenharmony_ci			m.rx_num_pg = p->rx_num_pgs;
24338c2ecf20Sopenharmony_ci		if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
24348c2ecf20Sopenharmony_ci			return -EINVAL;
24358c2ecf20Sopenharmony_ci		if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
24368c2ecf20Sopenharmony_ci			m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
24378c2ecf20Sopenharmony_ci			return -EINVAL;
24388c2ecf20Sopenharmony_ci		p->rx_pg_size = m.rx_pg_sz;
24398c2ecf20Sopenharmony_ci		p->tx_pg_size = m.tx_pg_sz;
24408c2ecf20Sopenharmony_ci		p->rx_num_pgs = m.rx_num_pg;
24418c2ecf20Sopenharmony_ci		p->tx_num_pgs = m.tx_num_pg;
24428c2ecf20Sopenharmony_ci		break;
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci	case CHELSIO_GET_MEM:{
24458c2ecf20Sopenharmony_ci		struct ch_mem_range t;
24468c2ecf20Sopenharmony_ci		struct mc7 *mem;
24478c2ecf20Sopenharmony_ci		u64 buf[32];
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci		if (!is_offload(adapter))
24508c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
24518c2ecf20Sopenharmony_ci		if (!capable(CAP_NET_ADMIN))
24528c2ecf20Sopenharmony_ci			return -EPERM;
24538c2ecf20Sopenharmony_ci		if (!(adapter->flags & FULL_INIT_DONE))
24548c2ecf20Sopenharmony_ci			return -EIO;	/* need the memory controllers */
24558c2ecf20Sopenharmony_ci		if (copy_from_user(&t, useraddr, sizeof(t)))
24568c2ecf20Sopenharmony_ci			return -EFAULT;
24578c2ecf20Sopenharmony_ci		if (t.cmd != CHELSIO_GET_MEM)
24588c2ecf20Sopenharmony_ci			return -EINVAL;
24598c2ecf20Sopenharmony_ci		if ((t.addr & 7) || (t.len & 7))
24608c2ecf20Sopenharmony_ci			return -EINVAL;
24618c2ecf20Sopenharmony_ci		if (t.mem_id == MEM_CM)
24628c2ecf20Sopenharmony_ci			mem = &adapter->cm;
24638c2ecf20Sopenharmony_ci		else if (t.mem_id == MEM_PMRX)
24648c2ecf20Sopenharmony_ci			mem = &adapter->pmrx;
24658c2ecf20Sopenharmony_ci		else if (t.mem_id == MEM_PMTX)
24668c2ecf20Sopenharmony_ci			mem = &adapter->pmtx;
24678c2ecf20Sopenharmony_ci		else
24688c2ecf20Sopenharmony_ci			return -EINVAL;
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci		/*
24718c2ecf20Sopenharmony_ci		 * Version scheme:
24728c2ecf20Sopenharmony_ci		 * bits 0..9: chip version
24738c2ecf20Sopenharmony_ci		 * bits 10..15: chip revision
24748c2ecf20Sopenharmony_ci		 */
24758c2ecf20Sopenharmony_ci		t.version = 3 | (adapter->params.rev << 10);
24768c2ecf20Sopenharmony_ci		if (copy_to_user(useraddr, &t, sizeof(t)))
24778c2ecf20Sopenharmony_ci			return -EFAULT;
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci		/*
24808c2ecf20Sopenharmony_ci		 * Read 256 bytes at a time as len can be large and we don't
24818c2ecf20Sopenharmony_ci		 * want to use huge intermediate buffers.
24828c2ecf20Sopenharmony_ci		 */
24838c2ecf20Sopenharmony_ci		useraddr += sizeof(t);	/* advance to start of buffer */
24848c2ecf20Sopenharmony_ci		while (t.len) {
24858c2ecf20Sopenharmony_ci			unsigned int chunk =
24868c2ecf20Sopenharmony_ci				min_t(unsigned int, t.len, sizeof(buf));
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci			ret =
24898c2ecf20Sopenharmony_ci				t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
24908c2ecf20Sopenharmony_ci						buf);
24918c2ecf20Sopenharmony_ci			if (ret)
24928c2ecf20Sopenharmony_ci				return ret;
24938c2ecf20Sopenharmony_ci			if (copy_to_user(useraddr, buf, chunk))
24948c2ecf20Sopenharmony_ci				return -EFAULT;
24958c2ecf20Sopenharmony_ci			useraddr += chunk;
24968c2ecf20Sopenharmony_ci			t.addr += chunk;
24978c2ecf20Sopenharmony_ci			t.len -= chunk;
24988c2ecf20Sopenharmony_ci		}
24998c2ecf20Sopenharmony_ci		break;
25008c2ecf20Sopenharmony_ci	}
25018c2ecf20Sopenharmony_ci	case CHELSIO_SET_TRACE_FILTER:{
25028c2ecf20Sopenharmony_ci		struct ch_trace t;
25038c2ecf20Sopenharmony_ci		const struct trace_params *tp;
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci		if (!capable(CAP_NET_ADMIN))
25068c2ecf20Sopenharmony_ci			return -EPERM;
25078c2ecf20Sopenharmony_ci		if (!offload_running(adapter))
25088c2ecf20Sopenharmony_ci			return -EAGAIN;
25098c2ecf20Sopenharmony_ci		if (copy_from_user(&t, useraddr, sizeof(t)))
25108c2ecf20Sopenharmony_ci			return -EFAULT;
25118c2ecf20Sopenharmony_ci		if (t.cmd != CHELSIO_SET_TRACE_FILTER)
25128c2ecf20Sopenharmony_ci			return -EINVAL;
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci		tp = (const struct trace_params *)&t.sip;
25158c2ecf20Sopenharmony_ci		if (t.config_tx)
25168c2ecf20Sopenharmony_ci			t3_config_trace_filter(adapter, tp, 0,
25178c2ecf20Sopenharmony_ci						t.invert_match,
25188c2ecf20Sopenharmony_ci						t.trace_tx);
25198c2ecf20Sopenharmony_ci		if (t.config_rx)
25208c2ecf20Sopenharmony_ci			t3_config_trace_filter(adapter, tp, 1,
25218c2ecf20Sopenharmony_ci						t.invert_match,
25228c2ecf20Sopenharmony_ci						t.trace_rx);
25238c2ecf20Sopenharmony_ci		break;
25248c2ecf20Sopenharmony_ci	}
25258c2ecf20Sopenharmony_ci	default:
25268c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
25278c2ecf20Sopenharmony_ci	}
25288c2ecf20Sopenharmony_ci	return 0;
25298c2ecf20Sopenharmony_ci}
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_cistatic int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
25328c2ecf20Sopenharmony_ci{
25338c2ecf20Sopenharmony_ci	struct mii_ioctl_data *data = if_mii(req);
25348c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
25358c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	switch (cmd) {
25388c2ecf20Sopenharmony_ci	case SIOCGMIIREG:
25398c2ecf20Sopenharmony_ci	case SIOCSMIIREG:
25408c2ecf20Sopenharmony_ci		/* Convert phy_id from older PRTAD/DEVAD format */
25418c2ecf20Sopenharmony_ci		if (is_10G(adapter) &&
25428c2ecf20Sopenharmony_ci		    !mdio_phy_id_is_c45(data->phy_id) &&
25438c2ecf20Sopenharmony_ci		    (data->phy_id & 0x1f00) &&
25448c2ecf20Sopenharmony_ci		    !(data->phy_id & 0xe0e0))
25458c2ecf20Sopenharmony_ci			data->phy_id = mdio_phy_id_c45(data->phy_id >> 8,
25468c2ecf20Sopenharmony_ci						       data->phy_id & 0x1f);
25478c2ecf20Sopenharmony_ci		fallthrough;
25488c2ecf20Sopenharmony_ci	case SIOCGMIIPHY:
25498c2ecf20Sopenharmony_ci		return mdio_mii_ioctl(&pi->phy.mdio, data, cmd);
25508c2ecf20Sopenharmony_ci	case SIOCCHIOCTL:
25518c2ecf20Sopenharmony_ci		return cxgb_extension_ioctl(dev, req->ifr_data);
25528c2ecf20Sopenharmony_ci	default:
25538c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
25548c2ecf20Sopenharmony_ci	}
25558c2ecf20Sopenharmony_ci}
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_cistatic int cxgb_change_mtu(struct net_device *dev, int new_mtu)
25588c2ecf20Sopenharmony_ci{
25598c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
25608c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
25618c2ecf20Sopenharmony_ci	int ret;
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci	if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
25648c2ecf20Sopenharmony_ci		return ret;
25658c2ecf20Sopenharmony_ci	dev->mtu = new_mtu;
25668c2ecf20Sopenharmony_ci	init_port_mtus(adapter);
25678c2ecf20Sopenharmony_ci	if (adapter->params.rev == 0 && offload_running(adapter))
25688c2ecf20Sopenharmony_ci		t3_load_mtus(adapter, adapter->params.mtus,
25698c2ecf20Sopenharmony_ci			     adapter->params.a_wnd, adapter->params.b_wnd,
25708c2ecf20Sopenharmony_ci			     adapter->port[0]->mtu);
25718c2ecf20Sopenharmony_ci	return 0;
25728c2ecf20Sopenharmony_ci}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_cistatic int cxgb_set_mac_addr(struct net_device *dev, void *p)
25758c2ecf20Sopenharmony_ci{
25768c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
25778c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
25788c2ecf20Sopenharmony_ci	struct sockaddr *addr = p;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
25818c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
25848c2ecf20Sopenharmony_ci	t3_mac_set_address(&pi->mac, LAN_MAC_IDX, dev->dev_addr);
25858c2ecf20Sopenharmony_ci	if (offload_running(adapter))
25868c2ecf20Sopenharmony_ci		write_smt_entry(adapter, pi->port_id);
25878c2ecf20Sopenharmony_ci	return 0;
25888c2ecf20Sopenharmony_ci}
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_cistatic netdev_features_t cxgb_fix_features(struct net_device *dev,
25918c2ecf20Sopenharmony_ci	netdev_features_t features)
25928c2ecf20Sopenharmony_ci{
25938c2ecf20Sopenharmony_ci	/*
25948c2ecf20Sopenharmony_ci	 * Since there is no support for separate rx/tx vlan accel
25958c2ecf20Sopenharmony_ci	 * enable/disable make sure tx flag is always in same state as rx.
25968c2ecf20Sopenharmony_ci	 */
25978c2ecf20Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_RX)
25988c2ecf20Sopenharmony_ci		features |= NETIF_F_HW_VLAN_CTAG_TX;
25998c2ecf20Sopenharmony_ci	else
26008c2ecf20Sopenharmony_ci		features &= ~NETIF_F_HW_VLAN_CTAG_TX;
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci	return features;
26038c2ecf20Sopenharmony_ci}
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_cistatic int cxgb_set_features(struct net_device *dev, netdev_features_t features)
26068c2ecf20Sopenharmony_ci{
26078c2ecf20Sopenharmony_ci	netdev_features_t changed = dev->features ^ features;
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_RX)
26108c2ecf20Sopenharmony_ci		cxgb_vlan_mode(dev, features);
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	return 0;
26138c2ecf20Sopenharmony_ci}
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
26168c2ecf20Sopenharmony_cistatic void cxgb_netpoll(struct net_device *dev)
26178c2ecf20Sopenharmony_ci{
26188c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
26198c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
26208c2ecf20Sopenharmony_ci	int qidx;
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
26238c2ecf20Sopenharmony_ci		struct sge_qset *qs = &adapter->sge.qs[qidx];
26248c2ecf20Sopenharmony_ci		void *source;
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci		if (adapter->flags & USING_MSIX)
26278c2ecf20Sopenharmony_ci			source = qs;
26288c2ecf20Sopenharmony_ci		else
26298c2ecf20Sopenharmony_ci			source = adapter;
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci		t3_intr_handler(adapter, qs->rspq.polling) (0, source);
26328c2ecf20Sopenharmony_ci	}
26338c2ecf20Sopenharmony_ci}
26348c2ecf20Sopenharmony_ci#endif
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci/*
26378c2ecf20Sopenharmony_ci * Periodic accumulation of MAC statistics.
26388c2ecf20Sopenharmony_ci */
26398c2ecf20Sopenharmony_cistatic void mac_stats_update(struct adapter *adapter)
26408c2ecf20Sopenharmony_ci{
26418c2ecf20Sopenharmony_ci	int i;
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
26448c2ecf20Sopenharmony_ci		struct net_device *dev = adapter->port[i];
26458c2ecf20Sopenharmony_ci		struct port_info *p = netdev_priv(dev);
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci		if (netif_running(dev)) {
26488c2ecf20Sopenharmony_ci			spin_lock(&adapter->stats_lock);
26498c2ecf20Sopenharmony_ci			t3_mac_update_stats(&p->mac);
26508c2ecf20Sopenharmony_ci			spin_unlock(&adapter->stats_lock);
26518c2ecf20Sopenharmony_ci		}
26528c2ecf20Sopenharmony_ci	}
26538c2ecf20Sopenharmony_ci}
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_cistatic void check_link_status(struct adapter *adapter)
26568c2ecf20Sopenharmony_ci{
26578c2ecf20Sopenharmony_ci	int i;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
26608c2ecf20Sopenharmony_ci		struct net_device *dev = adapter->port[i];
26618c2ecf20Sopenharmony_ci		struct port_info *p = netdev_priv(dev);
26628c2ecf20Sopenharmony_ci		int link_fault;
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci		spin_lock_irq(&adapter->work_lock);
26658c2ecf20Sopenharmony_ci		link_fault = p->link_fault;
26668c2ecf20Sopenharmony_ci		spin_unlock_irq(&adapter->work_lock);
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci		if (link_fault) {
26698c2ecf20Sopenharmony_ci			t3_link_fault(adapter, i);
26708c2ecf20Sopenharmony_ci			continue;
26718c2ecf20Sopenharmony_ci		}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci		if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
26748c2ecf20Sopenharmony_ci			t3_xgm_intr_disable(adapter, i);
26758c2ecf20Sopenharmony_ci			t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_ci			t3_link_changed(adapter, i);
26788c2ecf20Sopenharmony_ci			t3_xgm_intr_enable(adapter, i);
26798c2ecf20Sopenharmony_ci		}
26808c2ecf20Sopenharmony_ci	}
26818c2ecf20Sopenharmony_ci}
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_cistatic void check_t3b2_mac(struct adapter *adapter)
26848c2ecf20Sopenharmony_ci{
26858c2ecf20Sopenharmony_ci	int i;
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci	if (!rtnl_trylock())	/* synchronize with ifdown */
26888c2ecf20Sopenharmony_ci		return;
26898c2ecf20Sopenharmony_ci
26908c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
26918c2ecf20Sopenharmony_ci		struct net_device *dev = adapter->port[i];
26928c2ecf20Sopenharmony_ci		struct port_info *p = netdev_priv(dev);
26938c2ecf20Sopenharmony_ci		int status;
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci		if (!netif_running(dev))
26968c2ecf20Sopenharmony_ci			continue;
26978c2ecf20Sopenharmony_ci
26988c2ecf20Sopenharmony_ci		status = 0;
26998c2ecf20Sopenharmony_ci		if (netif_running(dev) && netif_carrier_ok(dev))
27008c2ecf20Sopenharmony_ci			status = t3b2_mac_watchdog_task(&p->mac);
27018c2ecf20Sopenharmony_ci		if (status == 1)
27028c2ecf20Sopenharmony_ci			p->mac.stats.num_toggled++;
27038c2ecf20Sopenharmony_ci		else if (status == 2) {
27048c2ecf20Sopenharmony_ci			struct cmac *mac = &p->mac;
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci			t3_mac_set_mtu(mac, dev->mtu);
27078c2ecf20Sopenharmony_ci			t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
27088c2ecf20Sopenharmony_ci			cxgb_set_rxmode(dev);
27098c2ecf20Sopenharmony_ci			t3_link_start(&p->phy, mac, &p->link_config);
27108c2ecf20Sopenharmony_ci			t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
27118c2ecf20Sopenharmony_ci			t3_port_intr_enable(adapter, p->port_id);
27128c2ecf20Sopenharmony_ci			p->mac.stats.num_resets++;
27138c2ecf20Sopenharmony_ci		}
27148c2ecf20Sopenharmony_ci	}
27158c2ecf20Sopenharmony_ci	rtnl_unlock();
27168c2ecf20Sopenharmony_ci}
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_cistatic void t3_adap_check_task(struct work_struct *work)
27208c2ecf20Sopenharmony_ci{
27218c2ecf20Sopenharmony_ci	struct adapter *adapter = container_of(work, struct adapter,
27228c2ecf20Sopenharmony_ci					       adap_check_task.work);
27238c2ecf20Sopenharmony_ci	const struct adapter_params *p = &adapter->params;
27248c2ecf20Sopenharmony_ci	int port;
27258c2ecf20Sopenharmony_ci	unsigned int v, status, reset;
27268c2ecf20Sopenharmony_ci
27278c2ecf20Sopenharmony_ci	adapter->check_task_cnt++;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	check_link_status(adapter);
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	/* Accumulate MAC stats if needed */
27328c2ecf20Sopenharmony_ci	if (!p->linkpoll_period ||
27338c2ecf20Sopenharmony_ci	    (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
27348c2ecf20Sopenharmony_ci	    p->stats_update_period) {
27358c2ecf20Sopenharmony_ci		mac_stats_update(adapter);
27368c2ecf20Sopenharmony_ci		adapter->check_task_cnt = 0;
27378c2ecf20Sopenharmony_ci	}
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci	if (p->rev == T3_REV_B2)
27408c2ecf20Sopenharmony_ci		check_t3b2_mac(adapter);
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_ci	/*
27438c2ecf20Sopenharmony_ci	 * Scan the XGMAC's to check for various conditions which we want to
27448c2ecf20Sopenharmony_ci	 * monitor in a periodic polling manner rather than via an interrupt
27458c2ecf20Sopenharmony_ci	 * condition.  This is used for conditions which would otherwise flood
27468c2ecf20Sopenharmony_ci	 * the system with interrupts and we only really need to know that the
27478c2ecf20Sopenharmony_ci	 * conditions are "happening" ...  For each condition we count the
27488c2ecf20Sopenharmony_ci	 * detection of the condition and reset it for the next polling loop.
27498c2ecf20Sopenharmony_ci	 */
27508c2ecf20Sopenharmony_ci	for_each_port(adapter, port) {
27518c2ecf20Sopenharmony_ci		struct cmac *mac =  &adap2pinfo(adapter, port)->mac;
27528c2ecf20Sopenharmony_ci		u32 cause;
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_ci		cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset);
27558c2ecf20Sopenharmony_ci		reset = 0;
27568c2ecf20Sopenharmony_ci		if (cause & F_RXFIFO_OVERFLOW) {
27578c2ecf20Sopenharmony_ci			mac->stats.rx_fifo_ovfl++;
27588c2ecf20Sopenharmony_ci			reset |= F_RXFIFO_OVERFLOW;
27598c2ecf20Sopenharmony_ci		}
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset);
27628c2ecf20Sopenharmony_ci	}
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ci	/*
27658c2ecf20Sopenharmony_ci	 * We do the same as above for FL_EMPTY interrupts.
27668c2ecf20Sopenharmony_ci	 */
27678c2ecf20Sopenharmony_ci	status = t3_read_reg(adapter, A_SG_INT_CAUSE);
27688c2ecf20Sopenharmony_ci	reset = 0;
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	if (status & F_FLEMPTY) {
27718c2ecf20Sopenharmony_ci		struct sge_qset *qs = &adapter->sge.qs[0];
27728c2ecf20Sopenharmony_ci		int i = 0;
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci		reset |= F_FLEMPTY;
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci		v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) &
27778c2ecf20Sopenharmony_ci		    0xffff;
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_ci		while (v) {
27808c2ecf20Sopenharmony_ci			qs->fl[i].empty += (v & 1);
27818c2ecf20Sopenharmony_ci			if (i)
27828c2ecf20Sopenharmony_ci				qs++;
27838c2ecf20Sopenharmony_ci			i ^= 1;
27848c2ecf20Sopenharmony_ci			v >>= 1;
27858c2ecf20Sopenharmony_ci		}
27868c2ecf20Sopenharmony_ci	}
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_INT_CAUSE, reset);
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_ci	/* Schedule the next check update if any port is active. */
27918c2ecf20Sopenharmony_ci	spin_lock_irq(&adapter->work_lock);
27928c2ecf20Sopenharmony_ci	if (adapter->open_device_map & PORT_MASK)
27938c2ecf20Sopenharmony_ci		schedule_chk_task(adapter);
27948c2ecf20Sopenharmony_ci	spin_unlock_irq(&adapter->work_lock);
27958c2ecf20Sopenharmony_ci}
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_cistatic void db_full_task(struct work_struct *work)
27988c2ecf20Sopenharmony_ci{
27998c2ecf20Sopenharmony_ci	struct adapter *adapter = container_of(work, struct adapter,
28008c2ecf20Sopenharmony_ci					       db_full_task);
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_FULL, 0);
28038c2ecf20Sopenharmony_ci}
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_cistatic void db_empty_task(struct work_struct *work)
28068c2ecf20Sopenharmony_ci{
28078c2ecf20Sopenharmony_ci	struct adapter *adapter = container_of(work, struct adapter,
28088c2ecf20Sopenharmony_ci					       db_empty_task);
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_EMPTY, 0);
28118c2ecf20Sopenharmony_ci}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_cistatic void db_drop_task(struct work_struct *work)
28148c2ecf20Sopenharmony_ci{
28158c2ecf20Sopenharmony_ci	struct adapter *adapter = container_of(work, struct adapter,
28168c2ecf20Sopenharmony_ci					       db_drop_task);
28178c2ecf20Sopenharmony_ci	unsigned long delay = 1000;
28188c2ecf20Sopenharmony_ci	unsigned short r;
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci	cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_DROP, 0);
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci	/*
28238c2ecf20Sopenharmony_ci	 * Sleep a while before ringing the driver qset dbs.
28248c2ecf20Sopenharmony_ci	 * The delay is between 1000-2023 usecs.
28258c2ecf20Sopenharmony_ci	 */
28268c2ecf20Sopenharmony_ci	get_random_bytes(&r, 2);
28278c2ecf20Sopenharmony_ci	delay += r & 1023;
28288c2ecf20Sopenharmony_ci	set_current_state(TASK_UNINTERRUPTIBLE);
28298c2ecf20Sopenharmony_ci	schedule_timeout(usecs_to_jiffies(delay));
28308c2ecf20Sopenharmony_ci	ring_dbs(adapter);
28318c2ecf20Sopenharmony_ci}
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci/*
28348c2ecf20Sopenharmony_ci * Processes external (PHY) interrupts in process context.
28358c2ecf20Sopenharmony_ci */
28368c2ecf20Sopenharmony_cistatic void ext_intr_task(struct work_struct *work)
28378c2ecf20Sopenharmony_ci{
28388c2ecf20Sopenharmony_ci	struct adapter *adapter = container_of(work, struct adapter,
28398c2ecf20Sopenharmony_ci					       ext_intr_handler_task);
28408c2ecf20Sopenharmony_ci	int i;
28418c2ecf20Sopenharmony_ci
28428c2ecf20Sopenharmony_ci	/* Disable link fault interrupts */
28438c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
28448c2ecf20Sopenharmony_ci		struct net_device *dev = adapter->port[i];
28458c2ecf20Sopenharmony_ci		struct port_info *p = netdev_priv(dev);
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci		t3_xgm_intr_disable(adapter, i);
28488c2ecf20Sopenharmony_ci		t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
28498c2ecf20Sopenharmony_ci	}
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ci	/* Re-enable link fault interrupts */
28528c2ecf20Sopenharmony_ci	t3_phy_intr_handler(adapter);
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	for_each_port(adapter, i)
28558c2ecf20Sopenharmony_ci		t3_xgm_intr_enable(adapter, i);
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	/* Now reenable external interrupts */
28588c2ecf20Sopenharmony_ci	spin_lock_irq(&adapter->work_lock);
28598c2ecf20Sopenharmony_ci	if (adapter->slow_intr_mask) {
28608c2ecf20Sopenharmony_ci		adapter->slow_intr_mask |= F_T3DBG;
28618c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
28628c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_PL_INT_ENABLE0,
28638c2ecf20Sopenharmony_ci			     adapter->slow_intr_mask);
28648c2ecf20Sopenharmony_ci	}
28658c2ecf20Sopenharmony_ci	spin_unlock_irq(&adapter->work_lock);
28668c2ecf20Sopenharmony_ci}
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci/*
28698c2ecf20Sopenharmony_ci * Interrupt-context handler for external (PHY) interrupts.
28708c2ecf20Sopenharmony_ci */
28718c2ecf20Sopenharmony_civoid t3_os_ext_intr_handler(struct adapter *adapter)
28728c2ecf20Sopenharmony_ci{
28738c2ecf20Sopenharmony_ci	/*
28748c2ecf20Sopenharmony_ci	 * Schedule a task to handle external interrupts as they may be slow
28758c2ecf20Sopenharmony_ci	 * and we use a mutex to protect MDIO registers.  We disable PHY
28768c2ecf20Sopenharmony_ci	 * interrupts in the meantime and let the task reenable them when
28778c2ecf20Sopenharmony_ci	 * it's done.
28788c2ecf20Sopenharmony_ci	 */
28798c2ecf20Sopenharmony_ci	spin_lock(&adapter->work_lock);
28808c2ecf20Sopenharmony_ci	if (adapter->slow_intr_mask) {
28818c2ecf20Sopenharmony_ci		adapter->slow_intr_mask &= ~F_T3DBG;
28828c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_PL_INT_ENABLE0,
28838c2ecf20Sopenharmony_ci			     adapter->slow_intr_mask);
28848c2ecf20Sopenharmony_ci		queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
28858c2ecf20Sopenharmony_ci	}
28868c2ecf20Sopenharmony_ci	spin_unlock(&adapter->work_lock);
28878c2ecf20Sopenharmony_ci}
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_civoid t3_os_link_fault_handler(struct adapter *adapter, int port_id)
28908c2ecf20Sopenharmony_ci{
28918c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->port[port_id];
28928c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci	spin_lock(&adapter->work_lock);
28958c2ecf20Sopenharmony_ci	pi->link_fault = 1;
28968c2ecf20Sopenharmony_ci	spin_unlock(&adapter->work_lock);
28978c2ecf20Sopenharmony_ci}
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_cistatic int t3_adapter_error(struct adapter *adapter, int reset, int on_wq)
29008c2ecf20Sopenharmony_ci{
29018c2ecf20Sopenharmony_ci	int i, ret = 0;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	if (is_offload(adapter) &&
29048c2ecf20Sopenharmony_ci	    test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
29058c2ecf20Sopenharmony_ci		cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0);
29068c2ecf20Sopenharmony_ci		offload_close(&adapter->tdev);
29078c2ecf20Sopenharmony_ci	}
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci	/* Stop all ports */
29108c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
29118c2ecf20Sopenharmony_ci		struct net_device *netdev = adapter->port[i];
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci		if (netif_running(netdev))
29148c2ecf20Sopenharmony_ci			__cxgb_close(netdev, on_wq);
29158c2ecf20Sopenharmony_ci	}
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	/* Stop SGE timers */
29188c2ecf20Sopenharmony_ci	t3_stop_sge_timers(adapter);
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci	adapter->flags &= ~FULL_INIT_DONE;
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci	if (reset)
29238c2ecf20Sopenharmony_ci		ret = t3_reset_adapter(adapter);
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	pci_disable_device(adapter->pdev);
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci	return ret;
29288c2ecf20Sopenharmony_ci}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_cistatic int t3_reenable_adapter(struct adapter *adapter)
29318c2ecf20Sopenharmony_ci{
29328c2ecf20Sopenharmony_ci	if (pci_enable_device(adapter->pdev)) {
29338c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
29348c2ecf20Sopenharmony_ci			"Cannot re-enable PCI device after reset.\n");
29358c2ecf20Sopenharmony_ci		goto err;
29368c2ecf20Sopenharmony_ci	}
29378c2ecf20Sopenharmony_ci	pci_set_master(adapter->pdev);
29388c2ecf20Sopenharmony_ci	pci_restore_state(adapter->pdev);
29398c2ecf20Sopenharmony_ci	pci_save_state(adapter->pdev);
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ci	/* Free sge resources */
29428c2ecf20Sopenharmony_ci	t3_free_sge_resources(adapter);
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_ci	if (t3_replay_prep_adapter(adapter))
29458c2ecf20Sopenharmony_ci		goto err;
29468c2ecf20Sopenharmony_ci
29478c2ecf20Sopenharmony_ci	return 0;
29488c2ecf20Sopenharmony_cierr:
29498c2ecf20Sopenharmony_ci	return -1;
29508c2ecf20Sopenharmony_ci}
29518c2ecf20Sopenharmony_ci
29528c2ecf20Sopenharmony_cistatic void t3_resume_ports(struct adapter *adapter)
29538c2ecf20Sopenharmony_ci{
29548c2ecf20Sopenharmony_ci	int i;
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci	/* Restart the ports */
29578c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
29588c2ecf20Sopenharmony_ci		struct net_device *netdev = adapter->port[i];
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_ci		if (netif_running(netdev)) {
29618c2ecf20Sopenharmony_ci			if (cxgb_open(netdev)) {
29628c2ecf20Sopenharmony_ci				dev_err(&adapter->pdev->dev,
29638c2ecf20Sopenharmony_ci					"can't bring device back up"
29648c2ecf20Sopenharmony_ci					" after reset\n");
29658c2ecf20Sopenharmony_ci				continue;
29668c2ecf20Sopenharmony_ci			}
29678c2ecf20Sopenharmony_ci		}
29688c2ecf20Sopenharmony_ci	}
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	if (is_offload(adapter) && !ofld_disable)
29718c2ecf20Sopenharmony_ci		cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0);
29728c2ecf20Sopenharmony_ci}
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci/*
29758c2ecf20Sopenharmony_ci * processes a fatal error.
29768c2ecf20Sopenharmony_ci * Bring the ports down, reset the chip, bring the ports back up.
29778c2ecf20Sopenharmony_ci */
29788c2ecf20Sopenharmony_cistatic void fatal_error_task(struct work_struct *work)
29798c2ecf20Sopenharmony_ci{
29808c2ecf20Sopenharmony_ci	struct adapter *adapter = container_of(work, struct adapter,
29818c2ecf20Sopenharmony_ci					       fatal_error_handler_task);
29828c2ecf20Sopenharmony_ci	int err = 0;
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ci	rtnl_lock();
29858c2ecf20Sopenharmony_ci	err = t3_adapter_error(adapter, 1, 1);
29868c2ecf20Sopenharmony_ci	if (!err)
29878c2ecf20Sopenharmony_ci		err = t3_reenable_adapter(adapter);
29888c2ecf20Sopenharmony_ci	if (!err)
29898c2ecf20Sopenharmony_ci		t3_resume_ports(adapter);
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_ci	CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded");
29928c2ecf20Sopenharmony_ci	rtnl_unlock();
29938c2ecf20Sopenharmony_ci}
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_civoid t3_fatal_err(struct adapter *adapter)
29968c2ecf20Sopenharmony_ci{
29978c2ecf20Sopenharmony_ci	unsigned int fw_status[4];
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	if (adapter->flags & FULL_INIT_DONE) {
30008c2ecf20Sopenharmony_ci		t3_sge_stop_dma(adapter);
30018c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
30028c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
30038c2ecf20Sopenharmony_ci		t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
30048c2ecf20Sopenharmony_ci		t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_ci		spin_lock(&adapter->work_lock);
30078c2ecf20Sopenharmony_ci		t3_intr_disable(adapter);
30088c2ecf20Sopenharmony_ci		queue_work(cxgb3_wq, &adapter->fatal_error_handler_task);
30098c2ecf20Sopenharmony_ci		spin_unlock(&adapter->work_lock);
30108c2ecf20Sopenharmony_ci	}
30118c2ecf20Sopenharmony_ci	CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
30128c2ecf20Sopenharmony_ci	if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
30138c2ecf20Sopenharmony_ci		CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
30148c2ecf20Sopenharmony_ci			 fw_status[0], fw_status[1],
30158c2ecf20Sopenharmony_ci			 fw_status[2], fw_status[3]);
30168c2ecf20Sopenharmony_ci}
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci/**
30198c2ecf20Sopenharmony_ci * t3_io_error_detected - called when PCI error is detected
30208c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
30218c2ecf20Sopenharmony_ci * @state: The current pci connection state
30228c2ecf20Sopenharmony_ci *
30238c2ecf20Sopenharmony_ci * This function is called after a PCI bus error affecting
30248c2ecf20Sopenharmony_ci * this device has been detected.
30258c2ecf20Sopenharmony_ci */
30268c2ecf20Sopenharmony_cistatic pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
30278c2ecf20Sopenharmony_ci					     pci_channel_state_t state)
30288c2ecf20Sopenharmony_ci{
30298c2ecf20Sopenharmony_ci	struct adapter *adapter = pci_get_drvdata(pdev);
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci	if (state == pci_channel_io_perm_failure)
30328c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_ci	t3_adapter_error(adapter, 0, 0);
30358c2ecf20Sopenharmony_ci
30368c2ecf20Sopenharmony_ci	/* Request a slot reset. */
30378c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_NEED_RESET;
30388c2ecf20Sopenharmony_ci}
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_ci/**
30418c2ecf20Sopenharmony_ci * t3_io_slot_reset - called after the pci bus has been reset.
30428c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
30438c2ecf20Sopenharmony_ci *
30448c2ecf20Sopenharmony_ci * Restart the card from scratch, as if from a cold-boot.
30458c2ecf20Sopenharmony_ci */
30468c2ecf20Sopenharmony_cistatic pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
30478c2ecf20Sopenharmony_ci{
30488c2ecf20Sopenharmony_ci	struct adapter *adapter = pci_get_drvdata(pdev);
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_ci	if (!t3_reenable_adapter(adapter))
30518c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_RECOVERED;
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_DISCONNECT;
30548c2ecf20Sopenharmony_ci}
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_ci/**
30578c2ecf20Sopenharmony_ci * t3_io_resume - called when traffic can start flowing again.
30588c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
30598c2ecf20Sopenharmony_ci *
30608c2ecf20Sopenharmony_ci * This callback is called when the error recovery driver tells us that
30618c2ecf20Sopenharmony_ci * its OK to resume normal operation.
30628c2ecf20Sopenharmony_ci */
30638c2ecf20Sopenharmony_cistatic void t3_io_resume(struct pci_dev *pdev)
30648c2ecf20Sopenharmony_ci{
30658c2ecf20Sopenharmony_ci	struct adapter *adapter = pci_get_drvdata(pdev);
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci	CH_ALERT(adapter, "adapter recovering, PEX ERR 0x%x\n",
30688c2ecf20Sopenharmony_ci		 t3_read_reg(adapter, A_PCIE_PEX_ERR));
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	rtnl_lock();
30718c2ecf20Sopenharmony_ci	t3_resume_ports(adapter);
30728c2ecf20Sopenharmony_ci	rtnl_unlock();
30738c2ecf20Sopenharmony_ci}
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_cistatic const struct pci_error_handlers t3_err_handler = {
30768c2ecf20Sopenharmony_ci	.error_detected = t3_io_error_detected,
30778c2ecf20Sopenharmony_ci	.slot_reset = t3_io_slot_reset,
30788c2ecf20Sopenharmony_ci	.resume = t3_io_resume,
30798c2ecf20Sopenharmony_ci};
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ci/*
30828c2ecf20Sopenharmony_ci * Set the number of qsets based on the number of CPUs and the number of ports,
30838c2ecf20Sopenharmony_ci * not to exceed the number of available qsets, assuming there are enough qsets
30848c2ecf20Sopenharmony_ci * per port in HW.
30858c2ecf20Sopenharmony_ci */
30868c2ecf20Sopenharmony_cistatic void set_nqsets(struct adapter *adap)
30878c2ecf20Sopenharmony_ci{
30888c2ecf20Sopenharmony_ci	int i, j = 0;
30898c2ecf20Sopenharmony_ci	int num_cpus = netif_get_num_default_rss_queues();
30908c2ecf20Sopenharmony_ci	int hwports = adap->params.nports;
30918c2ecf20Sopenharmony_ci	int nqsets = adap->msix_nvectors - 1;
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ci	if (adap->params.rev > 0 && adap->flags & USING_MSIX) {
30948c2ecf20Sopenharmony_ci		if (hwports == 2 &&
30958c2ecf20Sopenharmony_ci		    (hwports * nqsets > SGE_QSETS ||
30968c2ecf20Sopenharmony_ci		     num_cpus >= nqsets / hwports))
30978c2ecf20Sopenharmony_ci			nqsets /= hwports;
30988c2ecf20Sopenharmony_ci		if (nqsets > num_cpus)
30998c2ecf20Sopenharmony_ci			nqsets = num_cpus;
31008c2ecf20Sopenharmony_ci		if (nqsets < 1 || hwports == 4)
31018c2ecf20Sopenharmony_ci			nqsets = 1;
31028c2ecf20Sopenharmony_ci	} else
31038c2ecf20Sopenharmony_ci		nqsets = 1;
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	for_each_port(adap, i) {
31068c2ecf20Sopenharmony_ci		struct port_info *pi = adap2pinfo(adap, i);
31078c2ecf20Sopenharmony_ci
31088c2ecf20Sopenharmony_ci		pi->first_qset = j;
31098c2ecf20Sopenharmony_ci		pi->nqsets = nqsets;
31108c2ecf20Sopenharmony_ci		j = pi->first_qset + nqsets;
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ci		dev_info(&adap->pdev->dev,
31138c2ecf20Sopenharmony_ci			 "Port %d using %d queue sets.\n", i, nqsets);
31148c2ecf20Sopenharmony_ci	}
31158c2ecf20Sopenharmony_ci}
31168c2ecf20Sopenharmony_ci
31178c2ecf20Sopenharmony_cistatic int cxgb_enable_msix(struct adapter *adap)
31188c2ecf20Sopenharmony_ci{
31198c2ecf20Sopenharmony_ci	struct msix_entry entries[SGE_QSETS + 1];
31208c2ecf20Sopenharmony_ci	int vectors;
31218c2ecf20Sopenharmony_ci	int i;
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci	vectors = ARRAY_SIZE(entries);
31248c2ecf20Sopenharmony_ci	for (i = 0; i < vectors; ++i)
31258c2ecf20Sopenharmony_ci		entries[i].entry = i;
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci	vectors = pci_enable_msix_range(adap->pdev, entries,
31288c2ecf20Sopenharmony_ci					adap->params.nports + 1, vectors);
31298c2ecf20Sopenharmony_ci	if (vectors < 0)
31308c2ecf20Sopenharmony_ci		return vectors;
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_ci	for (i = 0; i < vectors; ++i)
31338c2ecf20Sopenharmony_ci		adap->msix_info[i].vec = entries[i].vector;
31348c2ecf20Sopenharmony_ci	adap->msix_nvectors = vectors;
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_ci	return 0;
31378c2ecf20Sopenharmony_ci}
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_cistatic void print_port_info(struct adapter *adap, const struct adapter_info *ai)
31408c2ecf20Sopenharmony_ci{
31418c2ecf20Sopenharmony_ci	static const char *pci_variant[] = {
31428c2ecf20Sopenharmony_ci		"PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
31438c2ecf20Sopenharmony_ci	};
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci	int i;
31468c2ecf20Sopenharmony_ci	char buf[80];
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci	if (is_pcie(adap))
31498c2ecf20Sopenharmony_ci		snprintf(buf, sizeof(buf), "%s x%d",
31508c2ecf20Sopenharmony_ci			 pci_variant[adap->params.pci.variant],
31518c2ecf20Sopenharmony_ci			 adap->params.pci.width);
31528c2ecf20Sopenharmony_ci	else
31538c2ecf20Sopenharmony_ci		snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
31548c2ecf20Sopenharmony_ci			 pci_variant[adap->params.pci.variant],
31558c2ecf20Sopenharmony_ci			 adap->params.pci.speed, adap->params.pci.width);
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	for_each_port(adap, i) {
31588c2ecf20Sopenharmony_ci		struct net_device *dev = adap->port[i];
31598c2ecf20Sopenharmony_ci		const struct port_info *pi = netdev_priv(dev);
31608c2ecf20Sopenharmony_ci
31618c2ecf20Sopenharmony_ci		if (!test_bit(i, &adap->registered_device_map))
31628c2ecf20Sopenharmony_ci			continue;
31638c2ecf20Sopenharmony_ci		netdev_info(dev, "%s %s %sNIC (rev %d) %s%s\n",
31648c2ecf20Sopenharmony_ci			    ai->desc, pi->phy.desc,
31658c2ecf20Sopenharmony_ci			    is_offload(adap) ? "R" : "", adap->params.rev, buf,
31668c2ecf20Sopenharmony_ci			    (adap->flags & USING_MSIX) ? " MSI-X" :
31678c2ecf20Sopenharmony_ci			    (adap->flags & USING_MSI) ? " MSI" : "");
31688c2ecf20Sopenharmony_ci		if (adap->name == dev->name && adap->params.vpd.mclk)
31698c2ecf20Sopenharmony_ci			pr_info("%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
31708c2ecf20Sopenharmony_ci			       adap->name, t3_mc7_size(&adap->cm) >> 20,
31718c2ecf20Sopenharmony_ci			       t3_mc7_size(&adap->pmtx) >> 20,
31728c2ecf20Sopenharmony_ci			       t3_mc7_size(&adap->pmrx) >> 20,
31738c2ecf20Sopenharmony_ci			       adap->params.vpd.sn);
31748c2ecf20Sopenharmony_ci	}
31758c2ecf20Sopenharmony_ci}
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_cistatic const struct net_device_ops cxgb_netdev_ops = {
31788c2ecf20Sopenharmony_ci	.ndo_open		= cxgb_open,
31798c2ecf20Sopenharmony_ci	.ndo_stop		= cxgb_close,
31808c2ecf20Sopenharmony_ci	.ndo_start_xmit		= t3_eth_xmit,
31818c2ecf20Sopenharmony_ci	.ndo_get_stats		= cxgb_get_stats,
31828c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
31838c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= cxgb_set_rxmode,
31848c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= cxgb_ioctl,
31858c2ecf20Sopenharmony_ci	.ndo_change_mtu		= cxgb_change_mtu,
31868c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= cxgb_set_mac_addr,
31878c2ecf20Sopenharmony_ci	.ndo_fix_features	= cxgb_fix_features,
31888c2ecf20Sopenharmony_ci	.ndo_set_features	= cxgb_set_features,
31898c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
31908c2ecf20Sopenharmony_ci	.ndo_poll_controller	= cxgb_netpoll,
31918c2ecf20Sopenharmony_ci#endif
31928c2ecf20Sopenharmony_ci};
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_cistatic void cxgb3_init_iscsi_mac(struct net_device *dev)
31958c2ecf20Sopenharmony_ci{
31968c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	memcpy(pi->iscsic.mac_addr, dev->dev_addr, ETH_ALEN);
31998c2ecf20Sopenharmony_ci	pi->iscsic.mac_addr[3] |= 0x80;
32008c2ecf20Sopenharmony_ci}
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
32038c2ecf20Sopenharmony_ci#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \
32048c2ecf20Sopenharmony_ci			NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
32058c2ecf20Sopenharmony_cistatic int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
32068c2ecf20Sopenharmony_ci{
32078c2ecf20Sopenharmony_ci	int i, err, pci_using_dac = 0;
32088c2ecf20Sopenharmony_ci	resource_size_t mmio_start, mmio_len;
32098c2ecf20Sopenharmony_ci	const struct adapter_info *ai;
32108c2ecf20Sopenharmony_ci	struct adapter *adapter = NULL;
32118c2ecf20Sopenharmony_ci	struct port_info *pi;
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci	if (!cxgb3_wq) {
32148c2ecf20Sopenharmony_ci		cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
32158c2ecf20Sopenharmony_ci		if (!cxgb3_wq) {
32168c2ecf20Sopenharmony_ci			pr_err("cannot initialize work queue\n");
32178c2ecf20Sopenharmony_ci			return -ENOMEM;
32188c2ecf20Sopenharmony_ci		}
32198c2ecf20Sopenharmony_ci	}
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_ci	err = pci_enable_device(pdev);
32228c2ecf20Sopenharmony_ci	if (err) {
32238c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot enable PCI device\n");
32248c2ecf20Sopenharmony_ci		goto out;
32258c2ecf20Sopenharmony_ci	}
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_ci	err = pci_request_regions(pdev, DRV_NAME);
32288c2ecf20Sopenharmony_ci	if (err) {
32298c2ecf20Sopenharmony_ci		/* Just info, some other driver may have claimed the device. */
32308c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "cannot obtain PCI resources\n");
32318c2ecf20Sopenharmony_ci		goto out_disable_device;
32328c2ecf20Sopenharmony_ci	}
32338c2ecf20Sopenharmony_ci
32348c2ecf20Sopenharmony_ci	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
32358c2ecf20Sopenharmony_ci		pci_using_dac = 1;
32368c2ecf20Sopenharmony_ci		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
32378c2ecf20Sopenharmony_ci		if (err) {
32388c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
32398c2ecf20Sopenharmony_ci			       "coherent allocations\n");
32408c2ecf20Sopenharmony_ci			goto out_release_regions;
32418c2ecf20Sopenharmony_ci		}
32428c2ecf20Sopenharmony_ci	} else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
32438c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no usable DMA configuration\n");
32448c2ecf20Sopenharmony_ci		goto out_release_regions;
32458c2ecf20Sopenharmony_ci	}
32468c2ecf20Sopenharmony_ci
32478c2ecf20Sopenharmony_ci	pci_set_master(pdev);
32488c2ecf20Sopenharmony_ci	pci_save_state(pdev);
32498c2ecf20Sopenharmony_ci
32508c2ecf20Sopenharmony_ci	mmio_start = pci_resource_start(pdev, 0);
32518c2ecf20Sopenharmony_ci	mmio_len = pci_resource_len(pdev, 0);
32528c2ecf20Sopenharmony_ci	ai = t3_get_adapter_info(ent->driver_data);
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_ci	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
32558c2ecf20Sopenharmony_ci	if (!adapter) {
32568c2ecf20Sopenharmony_ci		err = -ENOMEM;
32578c2ecf20Sopenharmony_ci		goto out_release_regions;
32588c2ecf20Sopenharmony_ci	}
32598c2ecf20Sopenharmony_ci
32608c2ecf20Sopenharmony_ci	adapter->nofail_skb =
32618c2ecf20Sopenharmony_ci		alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL);
32628c2ecf20Sopenharmony_ci	if (!adapter->nofail_skb) {
32638c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot allocate nofail buffer\n");
32648c2ecf20Sopenharmony_ci		err = -ENOMEM;
32658c2ecf20Sopenharmony_ci		goto out_free_adapter;
32668c2ecf20Sopenharmony_ci	}
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	adapter->regs = ioremap(mmio_start, mmio_len);
32698c2ecf20Sopenharmony_ci	if (!adapter->regs) {
32708c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot map device registers\n");
32718c2ecf20Sopenharmony_ci		err = -ENOMEM;
32728c2ecf20Sopenharmony_ci		goto out_free_adapter_nofail;
32738c2ecf20Sopenharmony_ci	}
32748c2ecf20Sopenharmony_ci
32758c2ecf20Sopenharmony_ci	adapter->pdev = pdev;
32768c2ecf20Sopenharmony_ci	adapter->name = pci_name(pdev);
32778c2ecf20Sopenharmony_ci	adapter->msg_enable = dflt_msg_enable;
32788c2ecf20Sopenharmony_ci	adapter->mmio_len = mmio_len;
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci	mutex_init(&adapter->mdio_lock);
32818c2ecf20Sopenharmony_ci	spin_lock_init(&adapter->work_lock);
32828c2ecf20Sopenharmony_ci	spin_lock_init(&adapter->stats_lock);
32838c2ecf20Sopenharmony_ci
32848c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&adapter->adapter_list);
32858c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
32868c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->db_full_task, db_full_task);
32898c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->db_empty_task, db_empty_task);
32908c2ecf20Sopenharmony_ci	INIT_WORK(&adapter->db_drop_task, db_drop_task);
32918c2ecf20Sopenharmony_ci
32928c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
32938c2ecf20Sopenharmony_ci
32948c2ecf20Sopenharmony_ci	for (i = 0; i < ai->nports0 + ai->nports1; ++i) {
32958c2ecf20Sopenharmony_ci		struct net_device *netdev;
32968c2ecf20Sopenharmony_ci
32978c2ecf20Sopenharmony_ci		netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS);
32988c2ecf20Sopenharmony_ci		if (!netdev) {
32998c2ecf20Sopenharmony_ci			err = -ENOMEM;
33008c2ecf20Sopenharmony_ci			goto out_free_dev;
33018c2ecf20Sopenharmony_ci		}
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci		SET_NETDEV_DEV(netdev, &pdev->dev);
33048c2ecf20Sopenharmony_ci
33058c2ecf20Sopenharmony_ci		adapter->port[i] = netdev;
33068c2ecf20Sopenharmony_ci		pi = netdev_priv(netdev);
33078c2ecf20Sopenharmony_ci		pi->adapter = adapter;
33088c2ecf20Sopenharmony_ci		pi->port_id = i;
33098c2ecf20Sopenharmony_ci		netif_carrier_off(netdev);
33108c2ecf20Sopenharmony_ci		netdev->irq = pdev->irq;
33118c2ecf20Sopenharmony_ci		netdev->mem_start = mmio_start;
33128c2ecf20Sopenharmony_ci		netdev->mem_end = mmio_start + mmio_len - 1;
33138c2ecf20Sopenharmony_ci		netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
33148c2ecf20Sopenharmony_ci			NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX;
33158c2ecf20Sopenharmony_ci		netdev->features |= netdev->hw_features |
33168c2ecf20Sopenharmony_ci				    NETIF_F_HW_VLAN_CTAG_TX;
33178c2ecf20Sopenharmony_ci		netdev->vlan_features |= netdev->features & VLAN_FEAT;
33188c2ecf20Sopenharmony_ci		if (pci_using_dac)
33198c2ecf20Sopenharmony_ci			netdev->features |= NETIF_F_HIGHDMA;
33208c2ecf20Sopenharmony_ci
33218c2ecf20Sopenharmony_ci		netdev->netdev_ops = &cxgb_netdev_ops;
33228c2ecf20Sopenharmony_ci		netdev->ethtool_ops = &cxgb_ethtool_ops;
33238c2ecf20Sopenharmony_ci		netdev->min_mtu = 81;
33248c2ecf20Sopenharmony_ci		netdev->max_mtu = ETH_MAX_MTU;
33258c2ecf20Sopenharmony_ci		netdev->dev_port = pi->port_id;
33268c2ecf20Sopenharmony_ci	}
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, adapter);
33298c2ecf20Sopenharmony_ci	if (t3_prep_adapter(adapter, ai, 1) < 0) {
33308c2ecf20Sopenharmony_ci		err = -ENODEV;
33318c2ecf20Sopenharmony_ci		goto out_free_dev;
33328c2ecf20Sopenharmony_ci	}
33338c2ecf20Sopenharmony_ci
33348c2ecf20Sopenharmony_ci	/*
33358c2ecf20Sopenharmony_ci	 * The card is now ready to go.  If any errors occur during device
33368c2ecf20Sopenharmony_ci	 * registration we do not fail the whole card but rather proceed only
33378c2ecf20Sopenharmony_ci	 * with the ports we manage to register successfully.  However we must
33388c2ecf20Sopenharmony_ci	 * register at least one net device.
33398c2ecf20Sopenharmony_ci	 */
33408c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
33418c2ecf20Sopenharmony_ci		err = register_netdev(adapter->port[i]);
33428c2ecf20Sopenharmony_ci		if (err)
33438c2ecf20Sopenharmony_ci			dev_warn(&pdev->dev,
33448c2ecf20Sopenharmony_ci				 "cannot register net device %s, skipping\n",
33458c2ecf20Sopenharmony_ci				 adapter->port[i]->name);
33468c2ecf20Sopenharmony_ci		else {
33478c2ecf20Sopenharmony_ci			/*
33488c2ecf20Sopenharmony_ci			 * Change the name we use for messages to the name of
33498c2ecf20Sopenharmony_ci			 * the first successfully registered interface.
33508c2ecf20Sopenharmony_ci			 */
33518c2ecf20Sopenharmony_ci			if (!adapter->registered_device_map)
33528c2ecf20Sopenharmony_ci				adapter->name = adapter->port[i]->name;
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_ci			__set_bit(i, &adapter->registered_device_map);
33558c2ecf20Sopenharmony_ci		}
33568c2ecf20Sopenharmony_ci	}
33578c2ecf20Sopenharmony_ci	if (!adapter->registered_device_map) {
33588c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "could not register any net devices\n");
33598c2ecf20Sopenharmony_ci		goto out_free_dev;
33608c2ecf20Sopenharmony_ci	}
33618c2ecf20Sopenharmony_ci
33628c2ecf20Sopenharmony_ci	for_each_port(adapter, i)
33638c2ecf20Sopenharmony_ci		cxgb3_init_iscsi_mac(adapter->port[i]);
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci	/* Driver's ready. Reflect it on LEDs */
33668c2ecf20Sopenharmony_ci	t3_led_ready(adapter);
33678c2ecf20Sopenharmony_ci
33688c2ecf20Sopenharmony_ci	if (is_offload(adapter)) {
33698c2ecf20Sopenharmony_ci		__set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
33708c2ecf20Sopenharmony_ci		cxgb3_adapter_ofld(adapter);
33718c2ecf20Sopenharmony_ci	}
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_ci	/* See what interrupts we'll be using */
33748c2ecf20Sopenharmony_ci	if (msi > 1 && cxgb_enable_msix(adapter) == 0)
33758c2ecf20Sopenharmony_ci		adapter->flags |= USING_MSIX;
33768c2ecf20Sopenharmony_ci	else if (msi > 0 && pci_enable_msi(pdev) == 0)
33778c2ecf20Sopenharmony_ci		adapter->flags |= USING_MSI;
33788c2ecf20Sopenharmony_ci
33798c2ecf20Sopenharmony_ci	set_nqsets(adapter);
33808c2ecf20Sopenharmony_ci
33818c2ecf20Sopenharmony_ci	err = sysfs_create_group(&adapter->port[0]->dev.kobj,
33828c2ecf20Sopenharmony_ci				 &cxgb3_attr_group);
33838c2ecf20Sopenharmony_ci	if (err) {
33848c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot create sysfs group\n");
33858c2ecf20Sopenharmony_ci		goto out_close_led;
33868c2ecf20Sopenharmony_ci	}
33878c2ecf20Sopenharmony_ci
33888c2ecf20Sopenharmony_ci	print_port_info(adapter, ai);
33898c2ecf20Sopenharmony_ci	return 0;
33908c2ecf20Sopenharmony_ci
33918c2ecf20Sopenharmony_ciout_close_led:
33928c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0);
33938c2ecf20Sopenharmony_ci
33948c2ecf20Sopenharmony_ciout_free_dev:
33958c2ecf20Sopenharmony_ci	iounmap(adapter->regs);
33968c2ecf20Sopenharmony_ci	for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i)
33978c2ecf20Sopenharmony_ci		if (adapter->port[i])
33988c2ecf20Sopenharmony_ci			free_netdev(adapter->port[i]);
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ciout_free_adapter_nofail:
34018c2ecf20Sopenharmony_ci	kfree_skb(adapter->nofail_skb);
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_ciout_free_adapter:
34048c2ecf20Sopenharmony_ci	kfree(adapter);
34058c2ecf20Sopenharmony_ci
34068c2ecf20Sopenharmony_ciout_release_regions:
34078c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
34088c2ecf20Sopenharmony_ciout_disable_device:
34098c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
34108c2ecf20Sopenharmony_ciout:
34118c2ecf20Sopenharmony_ci	return err;
34128c2ecf20Sopenharmony_ci}
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_cistatic void remove_one(struct pci_dev *pdev)
34158c2ecf20Sopenharmony_ci{
34168c2ecf20Sopenharmony_ci	struct adapter *adapter = pci_get_drvdata(pdev);
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci	if (adapter) {
34198c2ecf20Sopenharmony_ci		int i;
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci		t3_sge_stop(adapter);
34228c2ecf20Sopenharmony_ci		sysfs_remove_group(&adapter->port[0]->dev.kobj,
34238c2ecf20Sopenharmony_ci				   &cxgb3_attr_group);
34248c2ecf20Sopenharmony_ci
34258c2ecf20Sopenharmony_ci		if (is_offload(adapter)) {
34268c2ecf20Sopenharmony_ci			cxgb3_adapter_unofld(adapter);
34278c2ecf20Sopenharmony_ci			if (test_bit(OFFLOAD_DEVMAP_BIT,
34288c2ecf20Sopenharmony_ci				     &adapter->open_device_map))
34298c2ecf20Sopenharmony_ci				offload_close(&adapter->tdev);
34308c2ecf20Sopenharmony_ci		}
34318c2ecf20Sopenharmony_ci
34328c2ecf20Sopenharmony_ci		for_each_port(adapter, i)
34338c2ecf20Sopenharmony_ci		    if (test_bit(i, &adapter->registered_device_map))
34348c2ecf20Sopenharmony_ci			unregister_netdev(adapter->port[i]);
34358c2ecf20Sopenharmony_ci
34368c2ecf20Sopenharmony_ci		t3_stop_sge_timers(adapter);
34378c2ecf20Sopenharmony_ci		t3_free_sge_resources(adapter);
34388c2ecf20Sopenharmony_ci		cxgb_disable_msi(adapter);
34398c2ecf20Sopenharmony_ci
34408c2ecf20Sopenharmony_ci		for_each_port(adapter, i)
34418c2ecf20Sopenharmony_ci			if (adapter->port[i])
34428c2ecf20Sopenharmony_ci				free_netdev(adapter->port[i]);
34438c2ecf20Sopenharmony_ci
34448c2ecf20Sopenharmony_ci		iounmap(adapter->regs);
34458c2ecf20Sopenharmony_ci		kfree_skb(adapter->nofail_skb);
34468c2ecf20Sopenharmony_ci		kfree(adapter);
34478c2ecf20Sopenharmony_ci		pci_release_regions(pdev);
34488c2ecf20Sopenharmony_ci		pci_disable_device(pdev);
34498c2ecf20Sopenharmony_ci	}
34508c2ecf20Sopenharmony_ci}
34518c2ecf20Sopenharmony_ci
34528c2ecf20Sopenharmony_cistatic struct pci_driver driver = {
34538c2ecf20Sopenharmony_ci	.name = DRV_NAME,
34548c2ecf20Sopenharmony_ci	.id_table = cxgb3_pci_tbl,
34558c2ecf20Sopenharmony_ci	.probe = init_one,
34568c2ecf20Sopenharmony_ci	.remove = remove_one,
34578c2ecf20Sopenharmony_ci	.err_handler = &t3_err_handler,
34588c2ecf20Sopenharmony_ci};
34598c2ecf20Sopenharmony_ci
34608c2ecf20Sopenharmony_cistatic int __init cxgb3_init_module(void)
34618c2ecf20Sopenharmony_ci{
34628c2ecf20Sopenharmony_ci	int ret;
34638c2ecf20Sopenharmony_ci
34648c2ecf20Sopenharmony_ci	cxgb3_offload_init();
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_ci	ret = pci_register_driver(&driver);
34678c2ecf20Sopenharmony_ci	return ret;
34688c2ecf20Sopenharmony_ci}
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_cistatic void __exit cxgb3_cleanup_module(void)
34718c2ecf20Sopenharmony_ci{
34728c2ecf20Sopenharmony_ci	pci_unregister_driver(&driver);
34738c2ecf20Sopenharmony_ci	if (cxgb3_wq)
34748c2ecf20Sopenharmony_ci		destroy_workqueue(cxgb3_wq);
34758c2ecf20Sopenharmony_ci}
34768c2ecf20Sopenharmony_ci
34778c2ecf20Sopenharmony_cimodule_init(cxgb3_init_module);
34788c2ecf20Sopenharmony_cimodule_exit(cxgb3_cleanup_module);
3479