brintos

brintos / linux-shallow public Read only

0
0
Text · 113.3 KiB · d7cdea8 Raw
4243 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * QLogic qlcnic NIC Driver4 * Copyright (c) 2009-2013 QLogic Corporation5 */6 7#include <linux/if_vlan.h>8#include <linux/ipv6.h>9#include <linux/ethtool.h>10#include <linux/interrupt.h>11 12#include "qlcnic.h"13#include "qlcnic_sriov.h"14 15static void __qlcnic_83xx_process_aen(struct qlcnic_adapter *);16static int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8);17static void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8,18				      struct qlcnic_cmd_args *);19static int qlcnic_83xx_get_port_config(struct qlcnic_adapter *);20static irqreturn_t qlcnic_83xx_handle_aen(int, void *);21static pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *,22						      pci_channel_state_t);23static int qlcnic_83xx_set_port_config(struct qlcnic_adapter *);24static pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *);25static void qlcnic_83xx_io_resume(struct pci_dev *);26static int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8);27static void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *);28static int qlcnic_83xx_resume(struct qlcnic_adapter *);29static int qlcnic_83xx_shutdown(struct pci_dev *);30static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *);31 32#define RSS_HASHTYPE_IP_TCP		0x333#define QLC_83XX_FW_MBX_CMD		034#define QLC_SKIP_INACTIVE_PCI_REGS	735#define QLC_MAX_LEGACY_FUNC_SUPP	836 37/* 83xx Module type */38#define QLC_83XX_MODULE_FIBRE_10GBASE_LRM	0x1 /* 10GBase-LRM */39#define QLC_83XX_MODULE_FIBRE_10GBASE_LR	0x2 /* 10GBase-LR */40#define QLC_83XX_MODULE_FIBRE_10GBASE_SR	0x3 /* 10GBase-SR */41#define QLC_83XX_MODULE_DA_10GE_PASSIVE_CP	0x4 /* 10GE passive42						     * copper(compliant)43						     */44#define QLC_83XX_MODULE_DA_10GE_ACTIVE_CP	0x5 /* 10GE active limiting45						     * copper(compliant)46						     */47#define QLC_83XX_MODULE_DA_10GE_LEGACY_CP	0x6 /* 10GE passive copper48						     * (legacy, best effort)49						     */50#define QLC_83XX_MODULE_FIBRE_1000BASE_SX	0x7 /* 1000Base-SX */51#define QLC_83XX_MODULE_FIBRE_1000BASE_LX	0x8 /* 1000Base-LX */52#define QLC_83XX_MODULE_FIBRE_1000BASE_CX	0x9 /* 1000Base-CX */53#define QLC_83XX_MODULE_TP_1000BASE_T		0xa /* 1000Base-T*/54#define QLC_83XX_MODULE_DA_1GE_PASSIVE_CP	0xb /* 1GE passive copper55						     * (legacy, best effort)56						     */57#define QLC_83XX_MODULE_UNKNOWN			0xf /* Unknown module type */58 59/* Port types */60#define QLC_83XX_10_CAPABLE	 BIT_861#define QLC_83XX_100_CAPABLE	 BIT_962#define QLC_83XX_1G_CAPABLE	 BIT_1063#define QLC_83XX_10G_CAPABLE	 BIT_1164#define QLC_83XX_AUTONEG_ENABLE	 BIT_1565 66static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {67	{QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},68	{QLCNIC_CMD_CONFIG_INTRPT, 18, 34},69	{QLCNIC_CMD_CREATE_RX_CTX, 136, 27},70	{QLCNIC_CMD_DESTROY_RX_CTX, 2, 1},71	{QLCNIC_CMD_CREATE_TX_CTX, 54, 18},72	{QLCNIC_CMD_DESTROY_TX_CTX, 2, 1},73	{QLCNIC_CMD_CONFIGURE_MAC_LEARNING, 2, 1},74	{QLCNIC_CMD_INTRPT_TEST, 22, 12},75	{QLCNIC_CMD_SET_MTU, 3, 1},76	{QLCNIC_CMD_READ_PHY, 4, 2},77	{QLCNIC_CMD_WRITE_PHY, 5, 1},78	{QLCNIC_CMD_READ_HW_REG, 4, 1},79	{QLCNIC_CMD_GET_FLOW_CTL, 4, 2},80	{QLCNIC_CMD_SET_FLOW_CTL, 4, 1},81	{QLCNIC_CMD_READ_MAX_MTU, 4, 2},82	{QLCNIC_CMD_READ_MAX_LRO, 4, 2},83	{QLCNIC_CMD_MAC_ADDRESS, 4, 3},84	{QLCNIC_CMD_GET_PCI_INFO, 1, 129},85	{QLCNIC_CMD_GET_NIC_INFO, 2, 19},86	{QLCNIC_CMD_SET_NIC_INFO, 32, 1},87	{QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3},88	{QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1},89	{QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3},90	{QLCNIC_CMD_SET_PORTMIRRORING, 4, 1},91	{QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1},92	{QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3},93	{QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1},94	{QLCNIC_CMD_CONFIG_PORT, 4, 1},95	{QLCNIC_CMD_TEMP_SIZE, 1, 4},96	{QLCNIC_CMD_GET_TEMP_HDR, 5, 5},97	{QLCNIC_CMD_GET_LINK_EVENT, 2, 1},98	{QLCNIC_CMD_CONFIG_MAC_VLAN, 4, 3},99	{QLCNIC_CMD_CONFIG_INTR_COAL, 6, 1},100	{QLCNIC_CMD_CONFIGURE_RSS, 14, 1},101	{QLCNIC_CMD_CONFIGURE_LED, 2, 1},102	{QLCNIC_CMD_CONFIGURE_MAC_RX_MODE, 2, 1},103	{QLCNIC_CMD_CONFIGURE_HW_LRO, 2, 1},104	{QLCNIC_CMD_GET_STATISTICS, 2, 80},105	{QLCNIC_CMD_SET_PORT_CONFIG, 2, 1},106	{QLCNIC_CMD_GET_PORT_CONFIG, 2, 2},107	{QLCNIC_CMD_GET_LINK_STATUS, 2, 4},108	{QLCNIC_CMD_IDC_ACK, 5, 1},109	{QLCNIC_CMD_INIT_NIC_FUNC, 3, 1},110	{QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},111	{QLCNIC_CMD_SET_LED_CONFIG, 5, 1},112	{QLCNIC_CMD_GET_LED_CONFIG, 1, 5},113	{QLCNIC_CMD_83XX_SET_DRV_VER, 4, 1},114	{QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},115	{QLCNIC_CMD_CONFIG_VPORT, 4, 4},116	{QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},117	{QLCNIC_CMD_DCB_QUERY_CAP, 1, 2},118	{QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50},119	{QLCNIC_CMD_SET_INGRESS_ENCAP, 2, 1},120	{QLCNIC_CMD_83XX_EXTEND_ISCSI_DUMP_CAP, 4, 1},121};122 123const u32 qlcnic_83xx_ext_reg_tbl[] = {124	0x38CC,		/* Global Reset */125	0x38F0,		/* Wildcard */126	0x38FC,		/* Informant */127	0x3038,		/* Host MBX ctrl */128	0x303C,		/* FW MBX ctrl */129	0x355C,		/* BOOT LOADER ADDRESS REG */130	0x3560,		/* BOOT LOADER SIZE REG */131	0x3564,		/* FW IMAGE ADDR REG */132	0x1000,		/* MBX intr enable */133	0x1200,		/* Default Intr mask */134	0x1204,		/* Default Interrupt ID */135	0x3780,		/* QLC_83XX_IDC_MAJ_VERSION */136	0x3784,		/* QLC_83XX_IDC_DEV_STATE */137	0x3788,		/* QLC_83XX_IDC_DRV_PRESENCE */138	0x378C,		/* QLC_83XX_IDC_DRV_ACK */139	0x3790,		/* QLC_83XX_IDC_CTRL */140	0x3794,		/* QLC_83XX_IDC_DRV_AUDIT */141	0x3798,		/* QLC_83XX_IDC_MIN_VERSION */142	0x379C,		/* QLC_83XX_RECOVER_DRV_LOCK */143	0x37A0,		/* QLC_83XX_IDC_PF_0 */144	0x37A4,		/* QLC_83XX_IDC_PF_1 */145	0x37A8,		/* QLC_83XX_IDC_PF_2 */146	0x37AC,		/* QLC_83XX_IDC_PF_3 */147	0x37B0,		/* QLC_83XX_IDC_PF_4 */148	0x37B4,		/* QLC_83XX_IDC_PF_5 */149	0x37B8,		/* QLC_83XX_IDC_PF_6 */150	0x37BC,		/* QLC_83XX_IDC_PF_7 */151	0x37C0,		/* QLC_83XX_IDC_PF_8 */152	0x37C4,		/* QLC_83XX_IDC_PF_9 */153	0x37C8,		/* QLC_83XX_IDC_PF_10 */154	0x37CC,		/* QLC_83XX_IDC_PF_11 */155	0x37D0,		/* QLC_83XX_IDC_PF_12 */156	0x37D4,		/* QLC_83XX_IDC_PF_13 */157	0x37D8,		/* QLC_83XX_IDC_PF_14 */158	0x37DC,		/* QLC_83XX_IDC_PF_15 */159	0x37E0,		/* QLC_83XX_IDC_DEV_PARTITION_INFO_1 */160	0x37E4,		/* QLC_83XX_IDC_DEV_PARTITION_INFO_2 */161	0x37F0,		/* QLC_83XX_DRV_OP_MODE */162	0x37F4,		/* QLC_83XX_VNIC_STATE */163	0x3868,		/* QLC_83XX_DRV_LOCK */164	0x386C,		/* QLC_83XX_DRV_UNLOCK */165	0x3504,		/* QLC_83XX_DRV_LOCK_ID */166	0x34A4,		/* QLC_83XX_ASIC_TEMP */167};168 169const u32 qlcnic_83xx_reg_tbl[] = {170	0x34A8,		/* PEG_HALT_STAT1 */171	0x34AC,		/* PEG_HALT_STAT2 */172	0x34B0,		/* FW_HEARTBEAT */173	0x3500,		/* FLASH LOCK_ID */174	0x3528,		/* FW_CAPABILITIES */175	0x3538,		/* Driver active, DRV_REG0 */176	0x3540,		/* Device state, DRV_REG1 */177	0x3544,		/* Driver state, DRV_REG2 */178	0x3548,		/* Driver scratch, DRV_REG3 */179	0x354C,		/* Device partition info, DRV_REG4 */180	0x3524,		/* Driver IDC ver, DRV_REG5 */181	0x3550,		/* FW_VER_MAJOR */182	0x3554,		/* FW_VER_MINOR */183	0x3558,		/* FW_VER_SUB */184	0x359C,		/* NPAR STATE */185	0x35FC,		/* FW_IMG_VALID */186	0x3650,		/* CMD_PEG_STATE */187	0x373C,		/* RCV_PEG_STATE */188	0x37B4,		/* ASIC TEMP */189	0x356C,		/* FW API */190	0x3570,		/* DRV OP MODE */191	0x3850,		/* FLASH LOCK */192	0x3854,		/* FLASH UNLOCK */193};194 195static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {196	.read_crb			= qlcnic_83xx_read_crb,197	.write_crb			= qlcnic_83xx_write_crb,198	.read_reg			= qlcnic_83xx_rd_reg_indirect,199	.write_reg			= qlcnic_83xx_wrt_reg_indirect,200	.get_mac_address		= qlcnic_83xx_get_mac_address,201	.setup_intr			= qlcnic_83xx_setup_intr,202	.alloc_mbx_args			= qlcnic_83xx_alloc_mbx_args,203	.mbx_cmd			= qlcnic_83xx_issue_cmd,204	.get_func_no			= qlcnic_83xx_get_func_no,205	.api_lock			= qlcnic_83xx_cam_lock,206	.api_unlock			= qlcnic_83xx_cam_unlock,207	.add_sysfs			= qlcnic_83xx_add_sysfs,208	.remove_sysfs			= qlcnic_83xx_remove_sysfs,209	.process_lb_rcv_ring_diag	= qlcnic_83xx_process_rcv_ring_diag,210	.create_rx_ctx			= qlcnic_83xx_create_rx_ctx,211	.create_tx_ctx			= qlcnic_83xx_create_tx_ctx,212	.del_rx_ctx			= qlcnic_83xx_del_rx_ctx,213	.del_tx_ctx			= qlcnic_83xx_del_tx_ctx,214	.setup_link_event		= qlcnic_83xx_setup_link_event,215	.get_nic_info			= qlcnic_83xx_get_nic_info,216	.get_pci_info			= qlcnic_83xx_get_pci_info,217	.set_nic_info			= qlcnic_83xx_set_nic_info,218	.change_macvlan			= qlcnic_83xx_sre_macaddr_change,219	.napi_enable			= qlcnic_83xx_napi_enable,220	.napi_disable			= qlcnic_83xx_napi_disable,221	.config_intr_coal		= qlcnic_83xx_config_intr_coal,222	.config_rss			= qlcnic_83xx_config_rss,223	.config_hw_lro			= qlcnic_83xx_config_hw_lro,224	.config_promisc_mode		= qlcnic_83xx_nic_set_promisc,225	.change_l2_filter		= qlcnic_83xx_change_l2_filter,226	.get_board_info			= qlcnic_83xx_get_port_info,227	.set_mac_filter_count		= qlcnic_83xx_set_mac_filter_count,228	.free_mac_list			= qlcnic_82xx_free_mac_list,229	.io_error_detected		= qlcnic_83xx_io_error_detected,230	.io_slot_reset			= qlcnic_83xx_io_slot_reset,231	.io_resume			= qlcnic_83xx_io_resume,232	.get_beacon_state		= qlcnic_83xx_get_beacon_state,233	.enable_sds_intr		= qlcnic_83xx_enable_sds_intr,234	.disable_sds_intr		= qlcnic_83xx_disable_sds_intr,235	.enable_tx_intr			= qlcnic_83xx_enable_tx_intr,236	.disable_tx_intr		= qlcnic_83xx_disable_tx_intr,237	.get_saved_state		= qlcnic_83xx_get_saved_state,238	.set_saved_state		= qlcnic_83xx_set_saved_state,239	.cache_tmpl_hdr_values		= qlcnic_83xx_cache_tmpl_hdr_values,240	.get_cap_size			= qlcnic_83xx_get_cap_size,241	.set_sys_info			= qlcnic_83xx_set_sys_info,242	.store_cap_mask			= qlcnic_83xx_store_cap_mask,243	.encap_rx_offload		= qlcnic_83xx_encap_rx_offload,244	.encap_tx_offload		= qlcnic_83xx_encap_tx_offload,245};246 247static struct qlcnic_nic_template qlcnic_83xx_ops = {248	.config_bridged_mode	= qlcnic_config_bridged_mode,249	.config_led		= qlcnic_config_led,250	.request_reset          = qlcnic_83xx_idc_request_reset,251	.cancel_idc_work        = qlcnic_83xx_idc_exit,252	.napi_add		= qlcnic_83xx_napi_add,253	.napi_del		= qlcnic_83xx_napi_del,254	.config_ipaddr		= qlcnic_83xx_config_ipaddr,255	.clear_legacy_intr	= qlcnic_83xx_clear_legacy_intr,256	.shutdown		= qlcnic_83xx_shutdown,257	.resume			= qlcnic_83xx_resume,258};259 260void qlcnic_83xx_register_map(struct qlcnic_hardware_context *ahw)261{262	ahw->hw_ops		= &qlcnic_83xx_hw_ops;263	ahw->reg_tbl		= (u32 *)qlcnic_83xx_reg_tbl;264	ahw->ext_reg_tbl	= (u32 *)qlcnic_83xx_ext_reg_tbl;265}266 267int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *adapter)268{269	u32 fw_major, fw_minor, fw_build;270	struct pci_dev *pdev = adapter->pdev;271 272	fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);273	fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);274	fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);275	adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);276 277	dev_info(&pdev->dev, "Driver v%s, firmware version %d.%d.%d\n",278		 QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);279 280	return adapter->fw_version;281}282 283static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr)284{285	void __iomem *base;286	u32 val;287 288	base = adapter->ahw->pci_base0 +289	       QLC_83XX_CRB_WIN_FUNC(adapter->ahw->pci_func);290	writel(addr, base);291	val = readl(base);292	if (val != addr)293		return -EIO;294 295	return 0;296}297 298int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,299				int *err)300{301	struct qlcnic_hardware_context *ahw = adapter->ahw;302 303	*err = __qlcnic_set_win_base(adapter, (u32) addr);304	if (!*err) {305		return QLCRDX(ahw, QLCNIC_WILDCARD);306	} else {307		dev_err(&adapter->pdev->dev,308			"%s failed, addr = 0x%lx\n", __func__, addr);309		return -EIO;310	}311}312 313int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,314				 u32 data)315{316	int err;317	struct qlcnic_hardware_context *ahw = adapter->ahw;318 319	err = __qlcnic_set_win_base(adapter, (u32) addr);320	if (!err) {321		QLCWRX(ahw, QLCNIC_WILDCARD, data);322		return 0;323	} else {324		dev_err(&adapter->pdev->dev,325			"%s failed, addr = 0x%x data = 0x%x\n",326			__func__, (int)addr, data);327		return err;328	}329}330 331static void qlcnic_83xx_enable_legacy(struct qlcnic_adapter *adapter)332{333	struct qlcnic_hardware_context *ahw = adapter->ahw;334 335	/* MSI-X enablement failed, use legacy interrupt */336	adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR;337	adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK;338	adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR;339	adapter->msix_entries[0].vector = adapter->pdev->irq;340	dev_info(&adapter->pdev->dev, "using legacy interrupt\n");341}342 343static int qlcnic_83xx_calculate_msix_vector(struct qlcnic_adapter *adapter)344{345	int num_msix;346 347	num_msix = adapter->drv_sds_rings;348 349	/* account for AEN interrupt MSI-X based interrupts */350	num_msix += 1;351 352	if (!(adapter->flags & QLCNIC_TX_INTR_SHARED))353		num_msix += adapter->drv_tx_rings;354 355	return num_msix;356}357 358int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter)359{360	struct qlcnic_hardware_context *ahw = adapter->ahw;361	int err, i, num_msix;362 363	if (adapter->flags & QLCNIC_TSS_RSS) {364		err = qlcnic_setup_tss_rss_intr(adapter);365		if (err < 0)366			return err;367		num_msix = ahw->num_msix;368	} else {369		num_msix = qlcnic_83xx_calculate_msix_vector(adapter);370 371		err = qlcnic_enable_msix(adapter, num_msix);372		if (err == -ENOMEM)373			return err;374 375		if (adapter->flags & QLCNIC_MSIX_ENABLED) {376			num_msix = ahw->num_msix;377		} else {378			if (qlcnic_sriov_vf_check(adapter))379				return -EINVAL;380			num_msix = 1;381			adapter->drv_sds_rings = QLCNIC_SINGLE_RING;382			adapter->drv_tx_rings = QLCNIC_SINGLE_RING;383		}384	}385 386	/* setup interrupt mapping table for fw */387	ahw->intr_tbl =388		vzalloc(array_size(num_msix,389				   sizeof(struct qlcnic_intrpt_config)));390	if (!ahw->intr_tbl)391		return -ENOMEM;392 393	if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {394		if (adapter->ahw->pci_func >= QLC_MAX_LEGACY_FUNC_SUPP) {395			dev_err(&adapter->pdev->dev, "PCI function number 8 and higher are not supported with legacy interrupt, func 0x%x\n",396				ahw->pci_func);397			return -EOPNOTSUPP;398		}399 400		qlcnic_83xx_enable_legacy(adapter);401	}402 403	for (i = 0; i < num_msix; i++) {404		if (adapter->flags & QLCNIC_MSIX_ENABLED)405			ahw->intr_tbl[i].type = QLCNIC_INTRPT_MSIX;406		else407			ahw->intr_tbl[i].type = QLCNIC_INTRPT_INTX;408		ahw->intr_tbl[i].id = i;409		ahw->intr_tbl[i].src = 0;410	}411 412	return 0;413}414 415static inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)416{417	writel(0, adapter->tgt_mask_reg);418}419 420static inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapter)421{422	if (adapter->tgt_mask_reg)423		writel(1, adapter->tgt_mask_reg);424}425 426static inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter427						    *adapter)428{429	u32 mask;430 431	/* Mailbox in MSI-x mode and Legacy Interrupt share the same432	 * source register. We could be here before contexts are created433	 * and sds_ring->crb_intr_mask has not been initialized, calculate434	 * BAR offset for Interrupt Source Register435	 */436	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);437	writel(0, adapter->ahw->pci_base0 + mask);438}439 440void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter)441{442	u32 mask;443 444	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);445	writel(1, adapter->ahw->pci_base0 + mask);446	QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0);447}448 449static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,450				     struct qlcnic_cmd_args *cmd)451{452	int i;453 454	if (cmd->op_type == QLC_83XX_MBX_POST_BC_OP)455		return;456 457	for (i = 0; i < cmd->rsp.num; i++)458		cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i));459}460 461irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)462{463	u32 intr_val;464	struct qlcnic_hardware_context *ahw = adapter->ahw;465	int retries = 0;466 467	intr_val = readl(adapter->tgt_status_reg);468 469	if (!QLC_83XX_VALID_INTX_BIT31(intr_val))470		return IRQ_NONE;471 472	if (QLC_83XX_INTX_FUNC(intr_val) != adapter->ahw->pci_func) {473		adapter->stats.spurious_intr++;474		return IRQ_NONE;475	}476	/* The barrier is required to ensure writes to the registers */477	wmb();478 479	/* clear the interrupt trigger control register */480	writel_relaxed(0, adapter->isr_int_vec);481	intr_val = readl(adapter->isr_int_vec);482	do {483		intr_val = readl(adapter->tgt_status_reg);484		if (QLC_83XX_INTX_FUNC(intr_val) != ahw->pci_func)485			break;486		retries++;487	} while (QLC_83XX_VALID_INTX_BIT30(intr_val) &&488		 (retries < QLC_83XX_LEGACY_INTX_MAX_RETRY));489 490	return IRQ_HANDLED;491}492 493static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx)494{495	mbx->rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;496	complete(&mbx->completion);497}498 499static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)500{501	u32 resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;502	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;503	unsigned long flags;504 505	spin_lock_irqsave(&mbx->aen_lock, flags);506	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);507	if (!(resp & QLCNIC_SET_OWNER))508		goto out;509 510	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));511	if (event &  QLCNIC_MBX_ASYNC_EVENT) {512		__qlcnic_83xx_process_aen(adapter);513	} else {514		if (mbx->rsp_status != rsp_status)515			qlcnic_83xx_notify_mbx_response(mbx);516	}517out:518	qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);519	spin_unlock_irqrestore(&mbx->aen_lock, flags);520}521 522irqreturn_t qlcnic_83xx_intr(int irq, void *data)523{524	struct qlcnic_adapter *adapter = data;525	struct qlcnic_host_sds_ring *sds_ring;526	struct qlcnic_hardware_context *ahw = adapter->ahw;527 528	if (qlcnic_83xx_clear_legacy_intr(adapter) == IRQ_NONE)529		return IRQ_NONE;530 531	qlcnic_83xx_poll_process_aen(adapter);532 533	if (ahw->diag_test) {534		if (ahw->diag_test == QLCNIC_INTERRUPT_TEST)535			ahw->diag_cnt++;536		qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);537		return IRQ_HANDLED;538	}539 540	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {541		qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);542	} else {543		sds_ring = &adapter->recv_ctx->sds_rings[0];544		napi_schedule(&sds_ring->napi);545	}546 547	return IRQ_HANDLED;548}549 550irqreturn_t qlcnic_83xx_tmp_intr(int irq, void *data)551{552	struct qlcnic_host_sds_ring *sds_ring = data;553	struct qlcnic_adapter *adapter = sds_ring->adapter;554 555	if (adapter->flags & QLCNIC_MSIX_ENABLED)556		goto done;557 558	if (adapter->nic_ops->clear_legacy_intr(adapter) == IRQ_NONE)559		return IRQ_NONE;560 561done:562	adapter->ahw->diag_cnt++;563	qlcnic_enable_sds_intr(adapter, sds_ring);564 565	return IRQ_HANDLED;566}567 568void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)569{570	u32 num_msix;571 572	if (!(adapter->flags & QLCNIC_MSIX_ENABLED))573		qlcnic_83xx_set_legacy_intr_mask(adapter);574 575	qlcnic_83xx_disable_mbx_intr(adapter);576 577	if (adapter->flags & QLCNIC_MSIX_ENABLED)578		num_msix = adapter->ahw->num_msix - 1;579	else580		num_msix = 0;581 582	msleep(20);583 584	if (adapter->msix_entries) {585		synchronize_irq(adapter->msix_entries[num_msix].vector);586		free_irq(adapter->msix_entries[num_msix].vector, adapter);587	}588}589 590int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)591{592	irq_handler_t handler;593	u32 val;594	int err = 0;595	unsigned long flags = 0;596 597	if (!(adapter->flags & QLCNIC_MSI_ENABLED) &&598	    !(adapter->flags & QLCNIC_MSIX_ENABLED))599		flags |= IRQF_SHARED;600 601	if (adapter->flags & QLCNIC_MSIX_ENABLED) {602		handler = qlcnic_83xx_handle_aen;603		val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;604		err = request_irq(val, handler, flags, "qlcnic-MB", adapter);605		if (err) {606			dev_err(&adapter->pdev->dev,607				"failed to register MBX interrupt\n");608			return err;609		}610	} else {611		handler = qlcnic_83xx_intr;612		val = adapter->msix_entries[0].vector;613		err = request_irq(val, handler, flags, "qlcnic", adapter);614		if (err) {615			dev_err(&adapter->pdev->dev,616				"failed to register INTx interrupt\n");617			return err;618		}619		qlcnic_83xx_clear_legacy_intr_mask(adapter);620	}621 622	/* Enable mailbox interrupt */623	qlcnic_83xx_enable_mbx_interrupt(adapter);624 625	return err;626}627 628void qlcnic_83xx_get_func_no(struct qlcnic_adapter *adapter)629{630	u32 val = QLCRDX(adapter->ahw, QLCNIC_INFORMANT);631	adapter->ahw->pci_func = (val >> 24) & 0xff;632}633 634int qlcnic_83xx_cam_lock(struct qlcnic_adapter *adapter)635{636	void __iomem *addr;637	u32 val, limit = 0;638 639	struct qlcnic_hardware_context *ahw = adapter->ahw;640 641	addr = ahw->pci_base0 + QLC_83XX_SEM_LOCK_FUNC(ahw->pci_func);642	do {643		val = readl(addr);644		if (val) {645			/* write the function number to register */646			QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,647					    ahw->pci_func);648			return 0;649		}650		usleep_range(1000, 2000);651	} while (++limit <= QLCNIC_PCIE_SEM_TIMEOUT);652 653	return -EIO;654}655 656void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter)657{658	void __iomem *addr;659	struct qlcnic_hardware_context *ahw = adapter->ahw;660 661	addr = ahw->pci_base0 + QLC_83XX_SEM_UNLOCK_FUNC(ahw->pci_func);662	readl(addr);663}664 665void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,666			  loff_t offset, size_t size)667{668	int ret = 0;669	u32 data;670 671	if (qlcnic_api_lock(adapter)) {672		dev_err(&adapter->pdev->dev,673			"%s: failed to acquire lock. addr offset 0x%x\n",674			__func__, (u32)offset);675		return;676	}677 678	data = QLCRD32(adapter, (u32) offset, &ret);679	qlcnic_api_unlock(adapter);680 681	if (ret == -EIO) {682		dev_err(&adapter->pdev->dev,683			"%s: failed. addr offset 0x%x\n",684			__func__, (u32)offset);685		return;686	}687	memcpy(buf, &data, size);688}689 690void qlcnic_83xx_write_crb(struct qlcnic_adapter *adapter, char *buf,691			   loff_t offset, size_t size)692{693	u32 data;694 695	memcpy(&data, buf, size);696	qlcnic_83xx_wrt_reg_indirect(adapter, (u32) offset, data);697}698 699int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)700{701	struct qlcnic_hardware_context *ahw = adapter->ahw;702	int status;703 704	status = qlcnic_83xx_get_port_config(adapter);705	if (status) {706		dev_err(&adapter->pdev->dev,707			"Get Port Info failed\n");708	} else {709 710		if (ahw->port_config & QLC_83XX_10G_CAPABLE) {711			ahw->port_type = QLCNIC_XGBE;712		} else if (ahw->port_config & QLC_83XX_10_CAPABLE ||713			   ahw->port_config & QLC_83XX_100_CAPABLE ||714			   ahw->port_config & QLC_83XX_1G_CAPABLE) {715			ahw->port_type = QLCNIC_GBE;716		} else {717			ahw->port_type = QLCNIC_XGBE;718		}719 720		if (QLC_83XX_AUTONEG(ahw->port_config))721			ahw->link_autoneg = AUTONEG_ENABLE;722 723	}724	return status;725}726 727static void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter)728{729	struct qlcnic_hardware_context *ahw = adapter->ahw;730	u16 act_pci_fn = ahw->total_nic_func;731	u16 count;732 733	ahw->max_mc_count = QLC_83XX_MAX_MC_COUNT;734	if (act_pci_fn <= 2)735		count = (QLC_83XX_MAX_UC_COUNT - QLC_83XX_MAX_MC_COUNT) /736			 act_pci_fn;737	else738		count = (QLC_83XX_LB_MAX_FILTERS - QLC_83XX_MAX_MC_COUNT) /739			 act_pci_fn;740	ahw->max_uc_count = count;741}742 743void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *adapter)744{745	u32 val;746 747	if (adapter->flags & QLCNIC_MSIX_ENABLED)748		val = BIT_2 | ((adapter->ahw->num_msix - 1) << 8);749	else750		val = BIT_2;751 752	QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);753	qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);754}755 756void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter,757			  const struct pci_device_id *ent)758{759	u32 op_mode, priv_level;760	struct qlcnic_hardware_context *ahw = adapter->ahw;761 762	ahw->fw_hal_version = 2;763	qlcnic_get_func_no(adapter);764 765	if (qlcnic_sriov_vf_check(adapter)) {766		qlcnic_sriov_vf_set_ops(adapter);767		return;768	}769 770	/* Determine function privilege level */771	op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);772	if (op_mode == QLC_83XX_DEFAULT_OPMODE)773		priv_level = QLCNIC_MGMT_FUNC;774	else775		priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,776							 ahw->pci_func);777 778	if (priv_level == QLCNIC_NON_PRIV_FUNC) {779		ahw->op_mode = QLCNIC_NON_PRIV_FUNC;780		dev_info(&adapter->pdev->dev,781			 "HAL Version: %d Non Privileged function\n",782			 ahw->fw_hal_version);783		adapter->nic_ops = &qlcnic_vf_ops;784	} else {785		if (pci_find_ext_capability(adapter->pdev,786					    PCI_EXT_CAP_ID_SRIOV))787			set_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state);788		adapter->nic_ops = &qlcnic_83xx_ops;789	}790}791 792static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,793					u32 data[]);794static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,795					    u32 data[]);796 797void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,798		     struct qlcnic_cmd_args *cmd)799{800	int i;801 802	if (cmd->op_type == QLC_83XX_MBX_POST_BC_OP)803		return;804 805	dev_info(&adapter->pdev->dev,806		 "Host MBX regs(%d)\n", cmd->req.num);807	for (i = 0; i < cmd->req.num; i++) {808		if (i && !(i % 8))809			pr_info("\n");810		pr_info("%08x ", cmd->req.arg[i]);811	}812	pr_info("\n");813	dev_info(&adapter->pdev->dev,814		 "FW MBX regs(%d)\n", cmd->rsp.num);815	for (i = 0; i < cmd->rsp.num; i++) {816		if (i && !(i % 8))817			pr_info("\n");818		pr_info("%08x ", cmd->rsp.arg[i]);819	}820	pr_info("\n");821}822 823static void qlcnic_83xx_poll_for_mbx_completion(struct qlcnic_adapter *adapter,824						struct qlcnic_cmd_args *cmd)825{826	struct qlcnic_hardware_context *ahw = adapter->ahw;827	int opcode = LSW(cmd->req.arg[0]);828	unsigned long max_loops;829 830	max_loops = cmd->total_cmds * QLC_83XX_MBX_CMD_LOOP;831 832	for (; max_loops; max_loops--) {833		if (atomic_read(&cmd->rsp_status) ==834		    QLC_83XX_MBX_RESPONSE_ARRIVED)835			return;836 837		udelay(1);838	}839 840	dev_err(&adapter->pdev->dev,841		"%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",842		__func__, opcode, cmd->type, ahw->pci_func, ahw->op_mode);843	flush_workqueue(ahw->mailbox->work_q);844	return;845}846 847int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *adapter,848			  struct qlcnic_cmd_args *cmd)849{850	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;851	struct qlcnic_hardware_context *ahw = adapter->ahw;852	int cmd_type, err, opcode;853	unsigned long timeout;854 855	if (!mbx)856		return -EIO;857 858	opcode = LSW(cmd->req.arg[0]);859	cmd_type = cmd->type;860	err = mbx->ops->enqueue_cmd(adapter, cmd, &timeout);861	if (err) {862		dev_err(&adapter->pdev->dev,863			"%s: Mailbox not available, cmd_op=0x%x, cmd_context=0x%x, pci_func=0x%x, op_mode=0x%x\n",864			__func__, opcode, cmd->type, ahw->pci_func,865			ahw->op_mode);866		return err;867	}868 869	switch (cmd_type) {870	case QLC_83XX_MBX_CMD_WAIT:871		if (!wait_for_completion_timeout(&cmd->completion, timeout)) {872			dev_err(&adapter->pdev->dev,873				"%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",874				__func__, opcode, cmd_type, ahw->pci_func,875				ahw->op_mode);876			flush_workqueue(mbx->work_q);877		}878		break;879	case QLC_83XX_MBX_CMD_NO_WAIT:880		return 0;881	case QLC_83XX_MBX_CMD_BUSY_WAIT:882		qlcnic_83xx_poll_for_mbx_completion(adapter, cmd);883		break;884	default:885		dev_err(&adapter->pdev->dev,886			"%s: Invalid mailbox command, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",887			__func__, opcode, cmd_type, ahw->pci_func,888			ahw->op_mode);889		qlcnic_83xx_detach_mailbox_work(adapter);890	}891 892	return cmd->rsp_opcode;893}894 895int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,896			       struct qlcnic_adapter *adapter, u32 type)897{898	int i, size;899	u32 temp;900	const struct qlcnic_mailbox_metadata *mbx_tbl;901 902	memset(mbx, 0, sizeof(struct qlcnic_cmd_args));903	mbx_tbl = qlcnic_83xx_mbx_tbl;904	size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);905	for (i = 0; i < size; i++) {906		if (type == mbx_tbl[i].cmd) {907			mbx->op_type = QLC_83XX_FW_MBX_CMD;908			mbx->req.num = mbx_tbl[i].in_args;909			mbx->rsp.num = mbx_tbl[i].out_args;910			mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),911					       GFP_ATOMIC);912			if (!mbx->req.arg)913				return -ENOMEM;914			mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32),915					       GFP_ATOMIC);916			if (!mbx->rsp.arg) {917				kfree(mbx->req.arg);918				mbx->req.arg = NULL;919				return -ENOMEM;920			}921			temp = adapter->ahw->fw_hal_version << 29;922			mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);923			mbx->cmd_op = type;924			return 0;925		}926	}927 928	dev_err(&adapter->pdev->dev, "%s: Invalid mailbox command opcode 0x%x\n",929		__func__, type);930	return -EINVAL;931}932 933void qlcnic_83xx_idc_aen_work(struct work_struct *work)934{935	struct qlcnic_adapter *adapter;936	struct qlcnic_cmd_args cmd;937	int i, err = 0;938 939	adapter = container_of(work, struct qlcnic_adapter, idc_aen_work.work);940	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_IDC_ACK);941	if (err)942		return;943 944	for (i = 1; i < QLC_83XX_MBX_AEN_CNT; i++)945		cmd.req.arg[i] = adapter->ahw->mbox_aen[i];946 947	err = qlcnic_issue_cmd(adapter, &cmd);948	if (err)949		dev_info(&adapter->pdev->dev,950			 "%s: Mailbox IDC ACK failed.\n", __func__);951	qlcnic_free_mbx_args(&cmd);952}953 954static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,955					    u32 data[])956{957	dev_dbg(&adapter->pdev->dev, "Completion AEN:0x%x.\n",958		QLCNIC_MBX_RSP(data[0]));959	clear_bit(QLC_83XX_IDC_COMP_AEN, &adapter->ahw->idc.status);960	return;961}962 963static void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)964{965	struct qlcnic_hardware_context *ahw = adapter->ahw;966	u32 event[QLC_83XX_MBX_AEN_CNT];967	int i;968 969	for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)970		event[i] = readl(QLCNIC_MBX_FW(ahw, i));971 972	switch (QLCNIC_MBX_RSP(event[0])) {973 974	case QLCNIC_MBX_LINK_EVENT:975		qlcnic_83xx_handle_link_aen(adapter, event);976		break;977	case QLCNIC_MBX_COMP_EVENT:978		qlcnic_83xx_handle_idc_comp_aen(adapter, event);979		break;980	case QLCNIC_MBX_REQUEST_EVENT:981		for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)982			adapter->ahw->mbox_aen[i] = QLCNIC_MBX_RSP(event[i]);983		queue_delayed_work(adapter->qlcnic_wq,984				   &adapter->idc_aen_work, 0);985		break;986	case QLCNIC_MBX_TIME_EXTEND_EVENT:987		ahw->extend_lb_time = event[1] >> 8 & 0xf;988		break;989	case QLCNIC_MBX_BC_EVENT:990		qlcnic_sriov_handle_bc_event(adapter, event[1]);991		break;992	case QLCNIC_MBX_SFP_INSERT_EVENT:993		dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n",994			 QLCNIC_MBX_RSP(event[0]));995		break;996	case QLCNIC_MBX_SFP_REMOVE_EVENT:997		dev_info(&adapter->pdev->dev, "SFP Removed AEN:0x%x.\n",998			 QLCNIC_MBX_RSP(event[0]));999		break;1000	case QLCNIC_MBX_DCBX_CONFIG_CHANGE_EVENT:1001		qlcnic_dcb_aen_handler(adapter->dcb, (void *)&event[1]);1002		break;1003	default:1004		dev_dbg(&adapter->pdev->dev, "Unsupported AEN:0x%x.\n",1005			QLCNIC_MBX_RSP(event[0]));1006		break;1007	}1008 1009	QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);1010}1011 1012static void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)1013{1014	u32 resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;1015	struct qlcnic_hardware_context *ahw = adapter->ahw;1016	struct qlcnic_mailbox *mbx = ahw->mailbox;1017	unsigned long flags;1018 1019	spin_lock_irqsave(&mbx->aen_lock, flags);1020	resp = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);1021	if (resp & QLCNIC_SET_OWNER) {1022		event = readl(QLCNIC_MBX_FW(ahw, 0));1023		if (event &  QLCNIC_MBX_ASYNC_EVENT) {1024			__qlcnic_83xx_process_aen(adapter);1025		} else {1026			if (mbx->rsp_status != rsp_status)1027				qlcnic_83xx_notify_mbx_response(mbx);1028		}1029	}1030	spin_unlock_irqrestore(&mbx->aen_lock, flags);1031}1032 1033static void qlcnic_83xx_mbx_poll_work(struct work_struct *work)1034{1035	struct qlcnic_adapter *adapter;1036 1037	adapter = container_of(work, struct qlcnic_adapter, mbx_poll_work.work);1038 1039	if (!test_bit(__QLCNIC_MBX_POLL_ENABLE, &adapter->state))1040		return;1041 1042	qlcnic_83xx_process_aen(adapter);1043	queue_delayed_work(adapter->qlcnic_wq, &adapter->mbx_poll_work,1044			   (HZ / 10));1045}1046 1047void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *adapter)1048{1049	if (test_and_set_bit(__QLCNIC_MBX_POLL_ENABLE, &adapter->state))1050		return;1051 1052	INIT_DELAYED_WORK(&adapter->mbx_poll_work, qlcnic_83xx_mbx_poll_work);1053	queue_delayed_work(adapter->qlcnic_wq, &adapter->mbx_poll_work, 0);1054}1055 1056void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *adapter)1057{1058	if (!test_and_clear_bit(__QLCNIC_MBX_POLL_ENABLE, &adapter->state))1059		return;1060	cancel_delayed_work_sync(&adapter->mbx_poll_work);1061}1062 1063static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)1064{1065	int index, i, err, sds_mbx_size;1066	u32 *buf, intrpt_id, intr_mask;1067	u16 context_id;1068	u8 num_sds;1069	struct qlcnic_cmd_args cmd;1070	struct qlcnic_host_sds_ring *sds;1071	struct qlcnic_sds_mbx sds_mbx;1072	struct qlcnic_add_rings_mbx_out *mbx_out;1073	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;1074	struct qlcnic_hardware_context *ahw = adapter->ahw;1075 1076	sds_mbx_size = sizeof(struct qlcnic_sds_mbx);1077	context_id = recv_ctx->context_id;1078	num_sds = adapter->drv_sds_rings - QLCNIC_MAX_SDS_RINGS;1079	err = ahw->hw_ops->alloc_mbx_args(&cmd, adapter,1080					QLCNIC_CMD_ADD_RCV_RINGS);1081	if (err) {1082		dev_err(&adapter->pdev->dev,1083			"Failed to alloc mbx args %d\n", err);1084		return err;1085	}1086 1087	cmd.req.arg[1] = 0 | (num_sds << 8) | (context_id << 16);1088 1089	/* set up status rings, mbx 2-81 */1090	index = 2;1091	for (i = 8; i < adapter->drv_sds_rings; i++) {1092		memset(&sds_mbx, 0, sds_mbx_size);1093		sds = &recv_ctx->sds_rings[i];1094		sds->consumer = 0;1095		memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));1096		sds_mbx.phy_addr_low = LSD(sds->phys_addr);1097		sds_mbx.phy_addr_high = MSD(sds->phys_addr);1098		sds_mbx.sds_ring_size = sds->num_desc;1099 1100		if (adapter->flags & QLCNIC_MSIX_ENABLED)1101			intrpt_id = ahw->intr_tbl[i].id;1102		else1103			intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);1104 1105		if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)1106			sds_mbx.intrpt_id = intrpt_id;1107		else1108			sds_mbx.intrpt_id = 0xffff;1109		sds_mbx.intrpt_val = 0;1110		buf = &cmd.req.arg[index];1111		memcpy(buf, &sds_mbx, sds_mbx_size);1112		index += sds_mbx_size / sizeof(u32);1113	}1114 1115	/* send the mailbox command */1116	err = ahw->hw_ops->mbx_cmd(adapter, &cmd);1117	if (err) {1118		dev_err(&adapter->pdev->dev,1119			"Failed to add rings %d\n", err);1120		goto out;1121	}1122 1123	mbx_out = (struct qlcnic_add_rings_mbx_out *)&cmd.rsp.arg[1];1124	index = 0;1125	/* status descriptor ring */1126	for (i = 8; i < adapter->drv_sds_rings; i++) {1127		sds = &recv_ctx->sds_rings[i];1128		sds->crb_sts_consumer = ahw->pci_base0 +1129					mbx_out->host_csmr[index];1130		if (adapter->flags & QLCNIC_MSIX_ENABLED)1131			intr_mask = ahw->intr_tbl[i].src;1132		else1133			intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);1134 1135		sds->crb_intr_mask = ahw->pci_base0 + intr_mask;1136		index++;1137	}1138out:1139	qlcnic_free_mbx_args(&cmd);1140	return err;1141}1142 1143void qlcnic_83xx_del_rx_ctx(struct qlcnic_adapter *adapter)1144{1145	int err;1146	u32 temp = 0;1147	struct qlcnic_cmd_args cmd;1148	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;1149 1150	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX))1151		return;1152 1153	if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))1154		cmd.req.arg[0] |= (0x3 << 29);1155 1156	if (qlcnic_sriov_pf_check(adapter))1157		qlcnic_pf_set_interface_id_del_rx_ctx(adapter, &temp);1158 1159	cmd.req.arg[1] = recv_ctx->context_id | temp;1160	err = qlcnic_issue_cmd(adapter, &cmd);1161	if (err)1162		dev_err(&adapter->pdev->dev,1163			"Failed to destroy rx ctx in firmware\n");1164 1165	recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;1166	qlcnic_free_mbx_args(&cmd);1167}1168 1169int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)1170{1171	int i, err, index, sds_mbx_size, rds_mbx_size;1172	u8 num_sds, num_rds;1173	u32 *buf, intrpt_id, intr_mask, cap = 0;1174	struct qlcnic_host_sds_ring *sds;1175	struct qlcnic_host_rds_ring *rds;1176	struct qlcnic_sds_mbx sds_mbx;1177	struct qlcnic_rds_mbx rds_mbx;1178	struct qlcnic_cmd_args cmd;1179	struct qlcnic_rcv_mbx_out *mbx_out;1180	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;1181	struct qlcnic_hardware_context *ahw = adapter->ahw;1182	num_rds = adapter->max_rds_rings;1183 1184	if (adapter->drv_sds_rings <= QLCNIC_MAX_SDS_RINGS)1185		num_sds = adapter->drv_sds_rings;1186	else1187		num_sds = QLCNIC_MAX_SDS_RINGS;1188 1189	sds_mbx_size = sizeof(struct qlcnic_sds_mbx);1190	rds_mbx_size = sizeof(struct qlcnic_rds_mbx);1191	cap = QLCNIC_CAP0_LEGACY_CONTEXT;1192 1193	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)1194		cap |= QLC_83XX_FW_CAP_LRO_MSS;1195 1196	/* set mailbox hdr and capabilities */1197	err = qlcnic_alloc_mbx_args(&cmd, adapter,1198				    QLCNIC_CMD_CREATE_RX_CTX);1199	if (err)1200		return err;1201 1202	if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))1203		cmd.req.arg[0] |= (0x3 << 29);1204 1205	cmd.req.arg[1] = cap;1206	cmd.req.arg[5] = 1 | (num_rds << 5) | (num_sds << 8) |1207			 (QLC_83XX_HOST_RDS_MODE_UNIQUE << 16);1208 1209	if (qlcnic_sriov_pf_check(adapter))1210		qlcnic_pf_set_interface_id_create_rx_ctx(adapter,1211							 &cmd.req.arg[6]);1212	/* set up status rings, mbx 8-57/87 */1213	index = QLC_83XX_HOST_SDS_MBX_IDX;1214	for (i = 0; i < num_sds; i++) {1215		memset(&sds_mbx, 0, sds_mbx_size);1216		sds = &recv_ctx->sds_rings[i];1217		sds->consumer = 0;1218		memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));1219		sds_mbx.phy_addr_low = LSD(sds->phys_addr);1220		sds_mbx.phy_addr_high = MSD(sds->phys_addr);1221		sds_mbx.sds_ring_size = sds->num_desc;1222		if (adapter->flags & QLCNIC_MSIX_ENABLED)1223			intrpt_id = ahw->intr_tbl[i].id;1224		else1225			intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);1226		if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)1227			sds_mbx.intrpt_id = intrpt_id;1228		else1229			sds_mbx.intrpt_id = 0xffff;1230		sds_mbx.intrpt_val = 0;1231		buf = &cmd.req.arg[index];1232		memcpy(buf, &sds_mbx, sds_mbx_size);1233		index += sds_mbx_size / sizeof(u32);1234	}1235	/* set up receive rings, mbx 88-111/135 */1236	index = QLCNIC_HOST_RDS_MBX_IDX;1237	rds = &recv_ctx->rds_rings[0];1238	rds->producer = 0;1239	memset(&rds_mbx, 0, rds_mbx_size);1240	rds_mbx.phy_addr_reg_low = LSD(rds->phys_addr);1241	rds_mbx.phy_addr_reg_high = MSD(rds->phys_addr);1242	rds_mbx.reg_ring_sz = rds->dma_size;1243	rds_mbx.reg_ring_len = rds->num_desc;1244	/* Jumbo ring */1245	rds = &recv_ctx->rds_rings[1];1246	rds->producer = 0;1247	rds_mbx.phy_addr_jmb_low = LSD(rds->phys_addr);1248	rds_mbx.phy_addr_jmb_high = MSD(rds->phys_addr);1249	rds_mbx.jmb_ring_sz = rds->dma_size;1250	rds_mbx.jmb_ring_len = rds->num_desc;1251	buf = &cmd.req.arg[index];1252	memcpy(buf, &rds_mbx, rds_mbx_size);1253 1254	/* send the mailbox command */1255	err = ahw->hw_ops->mbx_cmd(adapter, &cmd);1256	if (err) {1257		dev_err(&adapter->pdev->dev,1258			"Failed to create Rx ctx in firmware%d\n", err);1259		goto out;1260	}1261	mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd.rsp.arg[1];1262	recv_ctx->context_id = mbx_out->ctx_id;1263	recv_ctx->state = mbx_out->state;1264	recv_ctx->virt_port = mbx_out->vport_id;1265	dev_info(&adapter->pdev->dev, "Rx Context[%d] Created, state:0x%x\n",1266		 recv_ctx->context_id, recv_ctx->state);1267	/* Receive descriptor ring */1268	/* Standard ring */1269	rds = &recv_ctx->rds_rings[0];1270	rds->crb_rcv_producer = ahw->pci_base0 +1271				mbx_out->host_prod[0].reg_buf;1272	/* Jumbo ring */1273	rds = &recv_ctx->rds_rings[1];1274	rds->crb_rcv_producer = ahw->pci_base0 +1275				mbx_out->host_prod[0].jmb_buf;1276	/* status descriptor ring */1277	for (i = 0; i < num_sds; i++) {1278		sds = &recv_ctx->sds_rings[i];1279		sds->crb_sts_consumer = ahw->pci_base0 +1280					mbx_out->host_csmr[i];1281		if (adapter->flags & QLCNIC_MSIX_ENABLED)1282			intr_mask = ahw->intr_tbl[i].src;1283		else1284			intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);1285		sds->crb_intr_mask = ahw->pci_base0 + intr_mask;1286	}1287 1288	if (adapter->drv_sds_rings > QLCNIC_MAX_SDS_RINGS)1289		err = qlcnic_83xx_add_rings(adapter);1290out:1291	qlcnic_free_mbx_args(&cmd);1292	return err;1293}1294 1295void qlcnic_83xx_del_tx_ctx(struct qlcnic_adapter *adapter,1296			    struct qlcnic_host_tx_ring *tx_ring)1297{1298	struct qlcnic_cmd_args cmd;1299	u32 temp = 0;1300 1301	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX))1302		return;1303 1304	if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))1305		cmd.req.arg[0] |= (0x3 << 29);1306 1307	if (qlcnic_sriov_pf_check(adapter))1308		qlcnic_pf_set_interface_id_del_tx_ctx(adapter, &temp);1309 1310	cmd.req.arg[1] = tx_ring->ctx_id | temp;1311	if (qlcnic_issue_cmd(adapter, &cmd))1312		dev_err(&adapter->pdev->dev,1313			"Failed to destroy tx ctx in firmware\n");1314	qlcnic_free_mbx_args(&cmd);1315}1316 1317int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,1318			      struct qlcnic_host_tx_ring *tx, int ring)1319{1320	int err;1321	u16 msix_id;1322	u32 *buf, intr_mask, temp = 0;1323	struct qlcnic_cmd_args cmd;1324	struct qlcnic_tx_mbx mbx;1325	struct qlcnic_tx_mbx_out *mbx_out;1326	struct qlcnic_hardware_context *ahw = adapter->ahw;1327	u32 msix_vector;1328 1329	/* Reset host resources */1330	tx->producer = 0;1331	tx->sw_consumer = 0;1332	*(tx->hw_consumer) = 0;1333 1334	memset(&mbx, 0, sizeof(struct qlcnic_tx_mbx));1335 1336	/* setup mailbox inbox registerss */1337	mbx.phys_addr_low = LSD(tx->phys_addr);1338	mbx.phys_addr_high = MSD(tx->phys_addr);1339	mbx.cnsmr_index_low = LSD(tx->hw_cons_phys_addr);1340	mbx.cnsmr_index_high = MSD(tx->hw_cons_phys_addr);1341	mbx.size = tx->num_desc;1342	if (adapter->flags & QLCNIC_MSIX_ENABLED) {1343		if (!(adapter->flags & QLCNIC_TX_INTR_SHARED))1344			msix_vector = adapter->drv_sds_rings + ring;1345		else1346			msix_vector = adapter->drv_sds_rings - 1;1347		msix_id = ahw->intr_tbl[msix_vector].id;1348	} else {1349		msix_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);1350	}1351 1352	if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)1353		mbx.intr_id = msix_id;1354	else1355		mbx.intr_id = 0xffff;1356	mbx.src = 0;1357 1358	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);1359	if (err)1360		return err;1361 1362	if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))1363		cmd.req.arg[0] |= (0x3 << 29);1364 1365	if (qlcnic_sriov_pf_check(adapter))1366		qlcnic_pf_set_interface_id_create_tx_ctx(adapter, &temp);1367 1368	cmd.req.arg[1] = QLCNIC_CAP0_LEGACY_CONTEXT;1369	cmd.req.arg[5] = QLCNIC_SINGLE_RING | temp;1370 1371	buf = &cmd.req.arg[6];1372	memcpy(buf, &mbx, sizeof(struct qlcnic_tx_mbx));1373	/* send the mailbox command*/1374	err = qlcnic_issue_cmd(adapter, &cmd);1375	if (err) {1376		netdev_err(adapter->netdev,1377			   "Failed to create Tx ctx in firmware 0x%x\n", err);1378		goto out;1379	}1380	mbx_out = (struct qlcnic_tx_mbx_out *)&cmd.rsp.arg[2];1381	tx->crb_cmd_producer = ahw->pci_base0 + mbx_out->host_prod;1382	tx->ctx_id = mbx_out->ctx_id;1383	if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&1384	    !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {1385		intr_mask = ahw->intr_tbl[adapter->drv_sds_rings + ring].src;1386		tx->crb_intr_mask = ahw->pci_base0 + intr_mask;1387	}1388	netdev_info(adapter->netdev,1389		    "Tx Context[0x%x] Created, state:0x%x\n",1390		    tx->ctx_id, mbx_out->state);1391out:1392	qlcnic_free_mbx_args(&cmd);1393	return err;1394}1395 1396static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test,1397				      u8 num_sds_ring)1398{1399	struct qlcnic_adapter *adapter = netdev_priv(netdev);1400	struct qlcnic_host_sds_ring *sds_ring;1401	struct qlcnic_host_rds_ring *rds_ring;1402	u16 adapter_state = adapter->is_up;1403	u8 ring;1404	int ret;1405 1406	netif_device_detach(netdev);1407 1408	if (netif_running(netdev))1409		__qlcnic_down(adapter, netdev);1410 1411	qlcnic_detach(adapter);1412 1413	adapter->drv_sds_rings = QLCNIC_SINGLE_RING;1414	adapter->ahw->diag_test = test;1415	adapter->ahw->linkup = 0;1416 1417	ret = qlcnic_attach(adapter);1418	if (ret) {1419		netif_device_attach(netdev);1420		return ret;1421	}1422 1423	ret = qlcnic_fw_create_ctx(adapter);1424	if (ret) {1425		qlcnic_detach(adapter);1426		if (adapter_state == QLCNIC_ADAPTER_UP_MAGIC) {1427			adapter->drv_sds_rings = num_sds_ring;1428			qlcnic_attach(adapter);1429		}1430		netif_device_attach(netdev);1431		return ret;1432	}1433 1434	for (ring = 0; ring < adapter->max_rds_rings; ring++) {1435		rds_ring = &adapter->recv_ctx->rds_rings[ring];1436		qlcnic_post_rx_buffers(adapter, rds_ring, ring);1437	}1438 1439	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {1440		for (ring = 0; ring < adapter->drv_sds_rings; ring++) {1441			sds_ring = &adapter->recv_ctx->sds_rings[ring];1442			qlcnic_enable_sds_intr(adapter, sds_ring);1443		}1444	}1445 1446	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {1447		adapter->ahw->loopback_state = 0;1448		adapter->ahw->hw_ops->setup_link_event(adapter, 1);1449	}1450 1451	set_bit(__QLCNIC_DEV_UP, &adapter->state);1452	return 0;1453}1454 1455static void qlcnic_83xx_diag_free_res(struct net_device *netdev,1456				      u8 drv_sds_rings)1457{1458	struct qlcnic_adapter *adapter = netdev_priv(netdev);1459	struct qlcnic_host_sds_ring *sds_ring;1460	int ring;1461 1462	clear_bit(__QLCNIC_DEV_UP, &adapter->state);1463	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {1464		for (ring = 0; ring < adapter->drv_sds_rings; ring++) {1465			sds_ring = &adapter->recv_ctx->sds_rings[ring];1466			if (adapter->flags & QLCNIC_MSIX_ENABLED)1467				qlcnic_disable_sds_intr(adapter, sds_ring);1468		}1469	}1470 1471	qlcnic_fw_destroy_ctx(adapter);1472	qlcnic_detach(adapter);1473 1474	adapter->ahw->diag_test = 0;1475	adapter->drv_sds_rings = drv_sds_rings;1476 1477	if (qlcnic_attach(adapter))1478		goto out;1479 1480	if (netif_running(netdev))1481		__qlcnic_up(adapter, netdev);1482 1483out:1484	netif_device_attach(netdev);1485}1486 1487static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *adapter)1488{1489	struct qlcnic_hardware_context *ahw = adapter->ahw;1490	struct qlcnic_cmd_args cmd;1491	u8 beacon_state;1492	int err = 0;1493 1494	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_CONFIG);1495	if (!err) {1496		err = qlcnic_issue_cmd(adapter, &cmd);1497		if (!err) {1498			beacon_state = cmd.rsp.arg[4];1499			if (beacon_state == QLCNIC_BEACON_DISABLE)1500				ahw->beacon_state = QLC_83XX_BEACON_OFF;1501			else if (beacon_state == QLC_83XX_ENABLE_BEACON)1502				ahw->beacon_state = QLC_83XX_BEACON_ON;1503		}1504	} else {1505		netdev_err(adapter->netdev, "Get beacon state failed, err=%d\n",1506			   err);1507	}1508 1509	qlcnic_free_mbx_args(&cmd);1510 1511	return;1512}1513 1514int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,1515			   u32 beacon)1516{1517	struct qlcnic_cmd_args cmd;1518	u32 mbx_in;1519	int i, status = 0;1520 1521	if (state) {1522		/* Get LED configuration */1523		status = qlcnic_alloc_mbx_args(&cmd, adapter,1524					       QLCNIC_CMD_GET_LED_CONFIG);1525		if (status)1526			return status;1527 1528		status = qlcnic_issue_cmd(adapter, &cmd);1529		if (status) {1530			dev_err(&adapter->pdev->dev,1531				"Get led config failed.\n");1532			goto mbx_err;1533		} else {1534			for (i = 0; i < 4; i++)1535				adapter->ahw->mbox_reg[i] = cmd.rsp.arg[i+1];1536		}1537		qlcnic_free_mbx_args(&cmd);1538		/* Set LED Configuration */1539		mbx_in = (LSW(QLC_83XX_LED_CONFIG) << 16) |1540			  LSW(QLC_83XX_LED_CONFIG);1541		status = qlcnic_alloc_mbx_args(&cmd, adapter,1542					       QLCNIC_CMD_SET_LED_CONFIG);1543		if (status)1544			return status;1545 1546		cmd.req.arg[1] = mbx_in;1547		cmd.req.arg[2] = mbx_in;1548		cmd.req.arg[3] = mbx_in;1549		if (beacon)1550			cmd.req.arg[4] = QLC_83XX_ENABLE_BEACON;1551		status = qlcnic_issue_cmd(adapter, &cmd);1552		if (status) {1553			dev_err(&adapter->pdev->dev,1554				"Set led config failed.\n");1555		}1556mbx_err:1557		qlcnic_free_mbx_args(&cmd);1558		return status;1559 1560	} else {1561		/* Restoring default LED configuration */1562		status = qlcnic_alloc_mbx_args(&cmd, adapter,1563					       QLCNIC_CMD_SET_LED_CONFIG);1564		if (status)1565			return status;1566 1567		cmd.req.arg[1] = adapter->ahw->mbox_reg[0];1568		cmd.req.arg[2] = adapter->ahw->mbox_reg[1];1569		cmd.req.arg[3] = adapter->ahw->mbox_reg[2];1570		if (beacon)1571			cmd.req.arg[4] = adapter->ahw->mbox_reg[3];1572		status = qlcnic_issue_cmd(adapter, &cmd);1573		if (status)1574			dev_err(&adapter->pdev->dev,1575				"Restoring led config failed.\n");1576		qlcnic_free_mbx_args(&cmd);1577		return status;1578	}1579}1580 1581int  qlcnic_83xx_set_led(struct net_device *netdev,1582			 enum ethtool_phys_id_state state)1583{1584	struct qlcnic_adapter *adapter = netdev_priv(netdev);1585	int err = -EIO, active = 1;1586 1587	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {1588		netdev_warn(netdev,1589			    "LED test is not supported in non-privileged mode\n");1590		return -EOPNOTSUPP;1591	}1592 1593	switch (state) {1594	case ETHTOOL_ID_ACTIVE:1595		if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))1596			return -EBUSY;1597 1598		if (test_bit(__QLCNIC_RESETTING, &adapter->state))1599			break;1600 1601		err = qlcnic_83xx_config_led(adapter, active, 0);1602		if (err)1603			netdev_err(netdev, "Failed to set LED blink state\n");1604		break;1605	case ETHTOOL_ID_INACTIVE:1606		active = 0;1607 1608		if (test_bit(__QLCNIC_RESETTING, &adapter->state))1609			break;1610 1611		err = qlcnic_83xx_config_led(adapter, active, 0);1612		if (err)1613			netdev_err(netdev, "Failed to reset LED blink state\n");1614		break;1615 1616	default:1617		return -EINVAL;1618	}1619 1620	if (!active || err)1621		clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);1622 1623	return err;1624}1625 1626void qlcnic_83xx_initialize_nic(struct qlcnic_adapter *adapter, int enable)1627{1628	struct qlcnic_cmd_args cmd;1629	int status;1630 1631	if (qlcnic_sriov_vf_check(adapter))1632		return;1633 1634	if (enable)1635		status = qlcnic_alloc_mbx_args(&cmd, adapter,1636					       QLCNIC_CMD_INIT_NIC_FUNC);1637	else1638		status = qlcnic_alloc_mbx_args(&cmd, adapter,1639					       QLCNIC_CMD_STOP_NIC_FUNC);1640 1641	if (status)1642		return;1643 1644	cmd.req.arg[1] = QLC_REGISTER_LB_IDC | QLC_INIT_FW_RESOURCES;1645 1646	if (adapter->dcb)1647		cmd.req.arg[1] |= QLC_REGISTER_DCB_AEN;1648 1649	status = qlcnic_issue_cmd(adapter, &cmd);1650	if (status)1651		dev_err(&adapter->pdev->dev,1652			"Failed to %s in NIC IDC function event.\n",1653			(enable ? "register" : "unregister"));1654 1655	qlcnic_free_mbx_args(&cmd);1656}1657 1658static int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter)1659{1660	struct qlcnic_cmd_args cmd;1661	int err;1662 1663	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORT_CONFIG);1664	if (err)1665		return err;1666 1667	cmd.req.arg[1] = adapter->ahw->port_config;1668	err = qlcnic_issue_cmd(adapter, &cmd);1669	if (err)1670		dev_info(&adapter->pdev->dev, "Set Port Config failed.\n");1671	qlcnic_free_mbx_args(&cmd);1672	return err;1673}1674 1675static int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter)1676{1677	struct qlcnic_cmd_args cmd;1678	int err;1679 1680	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PORT_CONFIG);1681	if (err)1682		return err;1683 1684	err = qlcnic_issue_cmd(adapter, &cmd);1685	if (err)1686		dev_info(&adapter->pdev->dev, "Get Port config failed\n");1687	else1688		adapter->ahw->port_config = cmd.rsp.arg[1];1689	qlcnic_free_mbx_args(&cmd);1690	return err;1691}1692 1693int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *adapter, int enable)1694{1695	int err;1696	u32 temp;1697	struct qlcnic_cmd_args cmd;1698 1699	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_EVENT);1700	if (err)1701		return err;1702 1703	temp = adapter->recv_ctx->context_id << 16;1704	cmd.req.arg[1] = (enable ? 1 : 0) | BIT_8 | temp;1705	err = qlcnic_issue_cmd(adapter, &cmd);1706	if (err)1707		dev_info(&adapter->pdev->dev,1708			 "Setup linkevent mailbox failed\n");1709	qlcnic_free_mbx_args(&cmd);1710	return err;1711}1712 1713static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter,1714						 u32 *interface_id)1715{1716	if (qlcnic_sriov_pf_check(adapter)) {1717		qlcnic_alloc_lb_filters_mem(adapter);1718		qlcnic_pf_set_interface_id_promisc(adapter, interface_id);1719		adapter->rx_mac_learn = true;1720	} else {1721		if (!qlcnic_sriov_vf_check(adapter))1722			*interface_id = adapter->recv_ctx->context_id << 16;1723	}1724}1725 1726int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)1727{1728	struct qlcnic_cmd_args *cmd = NULL;1729	u32 temp = 0;1730	int err;1731 1732	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)1733		return -EIO;1734 1735	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);1736	if (!cmd)1737		return -ENOMEM;1738 1739	err = qlcnic_alloc_mbx_args(cmd, adapter,1740				    QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);1741	if (err)1742		goto out;1743 1744	cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;1745	qlcnic_83xx_set_interface_id_promisc(adapter, &temp);1746 1747	if (qlcnic_84xx_check(adapter) && qlcnic_sriov_pf_check(adapter))1748		mode = VPORT_MISS_MODE_ACCEPT_ALL;1749 1750	cmd->req.arg[1] = mode | temp;1751	err = qlcnic_issue_cmd(adapter, cmd);1752	if (!err)1753		return err;1754 1755	qlcnic_free_mbx_args(cmd);1756 1757out:1758	kfree(cmd);1759	return err;1760}1761 1762int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)1763{1764	struct qlcnic_adapter *adapter = netdev_priv(netdev);1765	struct qlcnic_hardware_context *ahw = adapter->ahw;1766	u8 drv_sds_rings = adapter->drv_sds_rings;1767	u8 drv_tx_rings = adapter->drv_tx_rings;1768	int ret = 0, loop = 0;1769 1770	if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {1771		netdev_warn(netdev,1772			    "Loopback test not supported in non privileged mode\n");1773		return -ENOTSUPP;1774	}1775 1776	if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {1777		netdev_info(netdev, "Device is resetting\n");1778		return -EBUSY;1779	}1780 1781	if (qlcnic_get_diag_lock(adapter)) {1782		netdev_info(netdev, "Device is in diagnostics mode\n");1783		return -EBUSY;1784	}1785 1786	netdev_info(netdev, "%s loopback test in progress\n",1787		    mode == QLCNIC_ILB_MODE ? "internal" : "external");1788 1789	ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST,1790					 drv_sds_rings);1791	if (ret)1792		goto fail_diag_alloc;1793 1794	ret = qlcnic_83xx_set_lb_mode(adapter, mode);1795	if (ret)1796		goto free_diag_res;1797 1798	/* Poll for link up event before running traffic */1799	do {1800		msleep(QLC_83XX_LB_MSLEEP_COUNT);1801 1802		if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {1803			netdev_info(netdev,1804				    "Device is resetting, free LB test resources\n");1805			ret = -EBUSY;1806			goto free_diag_res;1807		}1808		if (loop++ > QLC_83XX_LB_WAIT_COUNT) {1809			netdev_info(netdev,1810				    "Firmware didn't sent link up event to loopback request\n");1811			ret = -ETIMEDOUT;1812			qlcnic_83xx_clear_lb_mode(adapter, mode);1813			goto free_diag_res;1814		}1815	} while ((adapter->ahw->linkup && ahw->has_link_events) != 1);1816 1817	ret = qlcnic_do_lb_test(adapter, mode);1818 1819	qlcnic_83xx_clear_lb_mode(adapter, mode);1820 1821free_diag_res:1822	qlcnic_83xx_diag_free_res(netdev, drv_sds_rings);1823 1824fail_diag_alloc:1825	adapter->drv_sds_rings = drv_sds_rings;1826	adapter->drv_tx_rings = drv_tx_rings;1827	qlcnic_release_diag_lock(adapter);1828	return ret;1829}1830 1831static void qlcnic_extend_lb_idc_cmpltn_wait(struct qlcnic_adapter *adapter,1832					     u32 *max_wait_count)1833{1834	struct qlcnic_hardware_context *ahw = adapter->ahw;1835	int temp;1836 1837	netdev_info(adapter->netdev, "Received loopback IDC time extend event for 0x%x seconds\n",1838		    ahw->extend_lb_time);1839	temp = ahw->extend_lb_time * 1000;1840	*max_wait_count += temp / QLC_83XX_LB_MSLEEP_COUNT;1841	ahw->extend_lb_time = 0;1842}1843 1844static int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)1845{1846	struct qlcnic_hardware_context *ahw = adapter->ahw;1847	struct net_device *netdev = adapter->netdev;1848	u32 config, max_wait_count;1849	int status = 0, loop = 0;1850 1851	ahw->extend_lb_time = 0;1852	max_wait_count = QLC_83XX_LB_WAIT_COUNT;1853	status = qlcnic_83xx_get_port_config(adapter);1854	if (status)1855		return status;1856 1857	config = ahw->port_config;1858 1859	/* Check if port is already in loopback mode */1860	if ((config & QLC_83XX_CFG_LOOPBACK_HSS) ||1861	    (config & QLC_83XX_CFG_LOOPBACK_EXT)) {1862		netdev_err(netdev,1863			   "Port already in Loopback mode.\n");1864		return -EINPROGRESS;1865	}1866 1867	set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);1868 1869	if (mode == QLCNIC_ILB_MODE)1870		ahw->port_config |= QLC_83XX_CFG_LOOPBACK_HSS;1871	if (mode == QLCNIC_ELB_MODE)1872		ahw->port_config |= QLC_83XX_CFG_LOOPBACK_EXT;1873 1874	status = qlcnic_83xx_set_port_config(adapter);1875	if (status) {1876		netdev_err(netdev,1877			   "Failed to Set Loopback Mode = 0x%x.\n",1878			   ahw->port_config);1879		ahw->port_config = config;1880		clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);1881		return status;1882	}1883 1884	/* Wait for Link and IDC Completion AEN */1885	do {1886		msleep(QLC_83XX_LB_MSLEEP_COUNT);1887 1888		if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {1889			netdev_info(netdev,1890				    "Device is resetting, free LB test resources\n");1891			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);1892			return -EBUSY;1893		}1894 1895		if (ahw->extend_lb_time)1896			qlcnic_extend_lb_idc_cmpltn_wait(adapter,1897							 &max_wait_count);1898 1899		if (loop++ > max_wait_count) {1900			netdev_err(netdev, "%s: Did not receive loopback IDC completion AEN\n",1901				   __func__);1902			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);1903			qlcnic_83xx_clear_lb_mode(adapter, mode);1904			return -ETIMEDOUT;1905		}1906	} while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));1907 1908	qlcnic_sre_macaddr_change(adapter, adapter->mac_addr, 0,1909				  QLCNIC_MAC_ADD);1910	return status;1911}1912 1913static int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)1914{1915	struct qlcnic_hardware_context *ahw = adapter->ahw;1916	u32 config = ahw->port_config, max_wait_count;1917	struct net_device *netdev = adapter->netdev;1918	int status = 0, loop = 0;1919 1920	ahw->extend_lb_time = 0;1921	max_wait_count = QLC_83XX_LB_WAIT_COUNT;1922	set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);1923	if (mode == QLCNIC_ILB_MODE)1924		ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_HSS;1925	if (mode == QLCNIC_ELB_MODE)1926		ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_EXT;1927 1928	status = qlcnic_83xx_set_port_config(adapter);1929	if (status) {1930		netdev_err(netdev,1931			   "Failed to Clear Loopback Mode = 0x%x.\n",1932			   ahw->port_config);1933		ahw->port_config = config;1934		clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);1935		return status;1936	}1937 1938	/* Wait for Link and IDC Completion AEN */1939	do {1940		msleep(QLC_83XX_LB_MSLEEP_COUNT);1941 1942		if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {1943			netdev_info(netdev,1944				    "Device is resetting, free LB test resources\n");1945			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);1946			return -EBUSY;1947		}1948 1949		if (ahw->extend_lb_time)1950			qlcnic_extend_lb_idc_cmpltn_wait(adapter,1951							 &max_wait_count);1952 1953		if (loop++ > max_wait_count) {1954			netdev_err(netdev, "%s: Did not receive loopback IDC completion AEN\n",1955				   __func__);1956			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);1957			return -ETIMEDOUT;1958		}1959	} while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));1960 1961	qlcnic_sre_macaddr_change(adapter, adapter->mac_addr, 0,1962				  QLCNIC_MAC_DEL);1963	return status;1964}1965 1966static void qlcnic_83xx_set_interface_id_ipaddr(struct qlcnic_adapter *adapter,1967						u32 *interface_id)1968{1969	if (qlcnic_sriov_pf_check(adapter)) {1970		qlcnic_pf_set_interface_id_ipaddr(adapter, interface_id);1971	} else {1972		if (!qlcnic_sriov_vf_check(adapter))1973			*interface_id = adapter->recv_ctx->context_id << 16;1974	}1975}1976 1977void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip,1978			       int mode)1979{1980	int err;1981	u32 temp = 0, temp_ip;1982	struct qlcnic_cmd_args cmd;1983 1984	err = qlcnic_alloc_mbx_args(&cmd, adapter,1985				    QLCNIC_CMD_CONFIGURE_IP_ADDR);1986	if (err)1987		return;1988 1989	qlcnic_83xx_set_interface_id_ipaddr(adapter, &temp);1990 1991	if (mode == QLCNIC_IP_UP)1992		cmd.req.arg[1] = 1 | temp;1993	else1994		cmd.req.arg[1] = 2 | temp;1995 1996	/*1997	 * Adapter needs IP address in network byte order.1998	 * But hardware mailbox registers go through writel(), hence IP address1999	 * gets swapped on big endian architecture.2000	 * To negate swapping of writel() on big endian architecture2001	 * use swab32(value).2002	 */2003 2004	temp_ip = swab32(ntohl(ip));2005	memcpy(&cmd.req.arg[2], &temp_ip, sizeof(u32));2006	err = qlcnic_issue_cmd(adapter, &cmd);2007	if (err != QLCNIC_RCODE_SUCCESS)2008		dev_err(&adapter->netdev->dev,2009			"could not notify %s IP 0x%x request\n",2010			(mode == QLCNIC_IP_UP) ? "Add" : "Remove", ip);2011 2012	qlcnic_free_mbx_args(&cmd);2013}2014 2015int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *adapter, int mode)2016{2017	int err;2018	u32 temp, arg1;2019	struct qlcnic_cmd_args cmd;2020	int lro_bit_mask;2021 2022	lro_bit_mask = (mode ? (BIT_0 | BIT_1 | BIT_2 | BIT_3) : 0);2023 2024	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)2025		return 0;2026 2027	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_HW_LRO);2028	if (err)2029		return err;2030 2031	temp = adapter->recv_ctx->context_id << 16;2032	arg1 = lro_bit_mask | temp;2033	cmd.req.arg[1] = arg1;2034 2035	err = qlcnic_issue_cmd(adapter, &cmd);2036	if (err)2037		dev_info(&adapter->pdev->dev, "LRO config failed\n");2038	qlcnic_free_mbx_args(&cmd);2039 2040	return err;2041}2042 2043int qlcnic_83xx_config_rss(struct qlcnic_adapter *adapter, int enable)2044{2045	struct qlcnic_cmd_args cmd;2046	static const u64 key[] = {2047		0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,2048		0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,2049		0x255b0ec26d5a56daULL2050	};2051	u32 word;2052	int err;2053 2054	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_RSS);2055	if (err)2056		return err;2057	/*2058	 * RSS request:2059	 * bits 3-0: Rsvd2060	 *      5-4: hash_type_ipv42061	 *	7-6: hash_type_ipv62062	 *	  8: enable2063	 *        9: use indirection table2064	 *    16-31: indirection table mask2065	 */2066	word =  ((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |2067		((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |2068		((u32)(enable & 0x1) << 8) |2069		((0x7ULL) << 16);2070	cmd.req.arg[1] = (adapter->recv_ctx->context_id);2071	cmd.req.arg[2] = word;2072	memcpy(&cmd.req.arg[4], key, sizeof(key));2073 2074	err = qlcnic_issue_cmd(adapter, &cmd);2075 2076	if (err)2077		dev_info(&adapter->pdev->dev, "RSS config failed\n");2078	qlcnic_free_mbx_args(&cmd);2079 2080	return err;2081 2082}2083 2084static void qlcnic_83xx_set_interface_id_macaddr(struct qlcnic_adapter *adapter,2085						 u32 *interface_id)2086{2087	if (qlcnic_sriov_pf_check(adapter)) {2088		qlcnic_pf_set_interface_id_macaddr(adapter, interface_id);2089	} else {2090		if (!qlcnic_sriov_vf_check(adapter))2091			*interface_id = adapter->recv_ctx->context_id << 16;2092	}2093}2094 2095int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,2096				   u16 vlan_id, u8 op)2097{2098	struct qlcnic_cmd_args *cmd = NULL;2099	struct qlcnic_macvlan_mbx mv;2100	u32 *buf, temp = 0;2101	int err;2102 2103	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)2104		return -EIO;2105 2106	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);2107	if (!cmd)2108		return -ENOMEM;2109 2110	err = qlcnic_alloc_mbx_args(cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);2111	if (err)2112		goto out;2113 2114	cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;2115 2116	if (vlan_id)2117		op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?2118		     QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL;2119 2120	cmd->req.arg[1] = op | (1 << 8);2121	qlcnic_83xx_set_interface_id_macaddr(adapter, &temp);2122	cmd->req.arg[1] |= temp;2123	mv.vlan = vlan_id;2124	mv.mac_addr0 = addr[0];2125	mv.mac_addr1 = addr[1];2126	mv.mac_addr2 = addr[2];2127	mv.mac_addr3 = addr[3];2128	mv.mac_addr4 = addr[4];2129	mv.mac_addr5 = addr[5];2130	buf = &cmd->req.arg[2];2131	memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));2132	err = qlcnic_issue_cmd(adapter, cmd);2133	if (!err)2134		return err;2135 2136	qlcnic_free_mbx_args(cmd);2137out:2138	kfree(cmd);2139	return err;2140}2141 2142void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,2143				  u16 vlan_id,2144				  struct qlcnic_host_tx_ring *tx_ring)2145{2146	u8 mac[ETH_ALEN];2147	memcpy(&mac, addr, ETH_ALEN);2148	qlcnic_83xx_sre_macaddr_change(adapter, mac, vlan_id, QLCNIC_MAC_ADD);2149}2150 2151static void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac,2152				      u8 type, struct qlcnic_cmd_args *cmd)2153{2154	switch (type) {2155	case QLCNIC_SET_STATION_MAC:2156	case QLCNIC_SET_FAC_DEF_MAC:2157		memcpy(&cmd->req.arg[2], mac, sizeof(u32));2158		memcpy(&cmd->req.arg[3], &mac[4], sizeof(u16));2159		break;2160	}2161	cmd->req.arg[1] = type;2162}2163 2164int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac,2165				u8 function)2166{2167	int err, i;2168	struct qlcnic_cmd_args cmd;2169	u32 mac_low, mac_high;2170 2171	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);2172	if (err)2173		return err;2174 2175	qlcnic_83xx_configure_mac(adapter, mac, QLCNIC_GET_CURRENT_MAC, &cmd);2176	err = qlcnic_issue_cmd(adapter, &cmd);2177 2178	if (err == QLCNIC_RCODE_SUCCESS) {2179		mac_low = cmd.rsp.arg[1];2180		mac_high = cmd.rsp.arg[2];2181 2182		for (i = 0; i < 2; i++)2183			mac[i] = (u8) (mac_high >> ((1 - i) * 8));2184		for (i = 2; i < 6; i++)2185			mac[i] = (u8) (mac_low >> ((5 - i) * 8));2186	} else {2187		dev_err(&adapter->pdev->dev, "Failed to get mac address%d\n",2188			err);2189		err = -EIO;2190	}2191	qlcnic_free_mbx_args(&cmd);2192	return err;2193}2194 2195static int qlcnic_83xx_set_rx_intr_coal(struct qlcnic_adapter *adapter)2196{2197	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;2198	struct qlcnic_cmd_args cmd;2199	u16 temp;2200	int err;2201 2202	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);2203	if (err)2204		return err;2205 2206	temp = adapter->recv_ctx->context_id;2207	cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_RX | temp << 16;2208	temp = coal->rx_time_us;2209	cmd.req.arg[2] = coal->rx_packets | temp << 16;2210	cmd.req.arg[3] = coal->flag;2211 2212	err = qlcnic_issue_cmd(adapter, &cmd);2213	if (err != QLCNIC_RCODE_SUCCESS)2214		netdev_err(adapter->netdev,2215			   "failed to set interrupt coalescing parameters\n");2216 2217	qlcnic_free_mbx_args(&cmd);2218 2219	return err;2220}2221 2222static int qlcnic_83xx_set_tx_intr_coal(struct qlcnic_adapter *adapter)2223{2224	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;2225	struct qlcnic_cmd_args cmd;2226	u16 temp;2227	int err;2228 2229	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);2230	if (err)2231		return err;2232 2233	temp = adapter->tx_ring->ctx_id;2234	cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_TX | temp << 16;2235	temp = coal->tx_time_us;2236	cmd.req.arg[2] = coal->tx_packets | temp << 16;2237	cmd.req.arg[3] = coal->flag;2238 2239	err = qlcnic_issue_cmd(adapter, &cmd);2240	if (err != QLCNIC_RCODE_SUCCESS)2241		netdev_err(adapter->netdev,2242			   "failed to set interrupt coalescing  parameters\n");2243 2244	qlcnic_free_mbx_args(&cmd);2245 2246	return err;2247}2248 2249int qlcnic_83xx_set_rx_tx_intr_coal(struct qlcnic_adapter *adapter)2250{2251	int err = 0;2252 2253	err = qlcnic_83xx_set_rx_intr_coal(adapter);2254	if (err)2255		netdev_err(adapter->netdev,2256			   "failed to set Rx coalescing parameters\n");2257 2258	err = qlcnic_83xx_set_tx_intr_coal(adapter);2259	if (err)2260		netdev_err(adapter->netdev,2261			   "failed to set Tx coalescing parameters\n");2262 2263	return err;2264}2265 2266int qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter,2267				 struct ethtool_coalesce *ethcoal)2268{2269	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;2270	u32 rx_coalesce_usecs, rx_max_frames;2271	u32 tx_coalesce_usecs, tx_max_frames;2272	int err;2273 2274	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)2275		return -EIO;2276 2277	tx_coalesce_usecs = ethcoal->tx_coalesce_usecs;2278	tx_max_frames = ethcoal->tx_max_coalesced_frames;2279	rx_coalesce_usecs = ethcoal->rx_coalesce_usecs;2280	rx_max_frames = ethcoal->rx_max_coalesced_frames;2281	coal->flag = QLCNIC_INTR_DEFAULT;2282 2283	if ((coal->rx_time_us == rx_coalesce_usecs) &&2284	    (coal->rx_packets == rx_max_frames)) {2285		coal->type = QLCNIC_INTR_COAL_TYPE_TX;2286		coal->tx_time_us = tx_coalesce_usecs;2287		coal->tx_packets = tx_max_frames;2288	} else if ((coal->tx_time_us == tx_coalesce_usecs) &&2289		   (coal->tx_packets == tx_max_frames)) {2290		coal->type = QLCNIC_INTR_COAL_TYPE_RX;2291		coal->rx_time_us = rx_coalesce_usecs;2292		coal->rx_packets = rx_max_frames;2293	} else {2294		coal->type = QLCNIC_INTR_COAL_TYPE_RX_TX;2295		coal->rx_time_us = rx_coalesce_usecs;2296		coal->rx_packets = rx_max_frames;2297		coal->tx_time_us = tx_coalesce_usecs;2298		coal->tx_packets = tx_max_frames;2299	}2300 2301	switch (coal->type) {2302	case QLCNIC_INTR_COAL_TYPE_RX:2303		err = qlcnic_83xx_set_rx_intr_coal(adapter);2304		break;2305	case QLCNIC_INTR_COAL_TYPE_TX:2306		err = qlcnic_83xx_set_tx_intr_coal(adapter);2307		break;2308	case QLCNIC_INTR_COAL_TYPE_RX_TX:2309		err = qlcnic_83xx_set_rx_tx_intr_coal(adapter);2310		break;2311	default:2312		err = -EINVAL;2313		netdev_err(adapter->netdev,2314			   "Invalid Interrupt coalescing type\n");2315		break;2316	}2317 2318	return err;2319}2320 2321static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,2322					u32 data[])2323{2324	struct qlcnic_hardware_context *ahw = adapter->ahw;2325	u8 link_status, duplex;2326	/* link speed */2327	link_status = LSB(data[3]) & 1;2328	if (link_status) {2329		ahw->link_speed = MSW(data[2]);2330		duplex = LSB(MSW(data[3]));2331		if (duplex)2332			ahw->link_duplex = DUPLEX_FULL;2333		else2334			ahw->link_duplex = DUPLEX_HALF;2335	} else {2336		ahw->link_speed = SPEED_UNKNOWN;2337		ahw->link_duplex = DUPLEX_UNKNOWN;2338	}2339 2340	ahw->link_autoneg = MSB(MSW(data[3]));2341	ahw->module_type = MSB(LSW(data[3]));2342	ahw->has_link_events = 1;2343	ahw->lb_mode = data[4] & QLCNIC_LB_MODE_MASK;2344	qlcnic_advert_link_change(adapter, link_status);2345}2346 2347static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)2348{2349	u32 mask, resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;2350	struct qlcnic_adapter *adapter = data;2351	struct qlcnic_mailbox *mbx;2352	unsigned long flags;2353 2354	mbx = adapter->ahw->mailbox;2355	spin_lock_irqsave(&mbx->aen_lock, flags);2356	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);2357	if (!(resp & QLCNIC_SET_OWNER))2358		goto out;2359 2360	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));2361	if (event &  QLCNIC_MBX_ASYNC_EVENT) {2362		__qlcnic_83xx_process_aen(adapter);2363	} else {2364		if (mbx->rsp_status != rsp_status)2365			qlcnic_83xx_notify_mbx_response(mbx);2366		else2367			adapter->stats.mbx_spurious_intr++;2368	}2369 2370out:2371	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);2372	writel(0, adapter->ahw->pci_base0 + mask);2373	spin_unlock_irqrestore(&mbx->aen_lock, flags);2374	return IRQ_HANDLED;2375}2376 2377int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *adapter,2378			     struct qlcnic_info *nic)2379{2380	int i, err = -EIO;2381	struct qlcnic_cmd_args cmd;2382 2383	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {2384		dev_err(&adapter->pdev->dev,2385			"%s: Error, invoked by non management func\n",2386			__func__);2387		return err;2388	}2389 2390	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);2391	if (err)2392		return err;2393 2394	cmd.req.arg[1] = (nic->pci_func << 16);2395	cmd.req.arg[2] = 0x1 << 16;2396	cmd.req.arg[3] = nic->phys_port | (nic->switch_mode << 16);2397	cmd.req.arg[4] = nic->capabilities;2398	cmd.req.arg[5] = (nic->max_mac_filters & 0xFF) | ((nic->max_mtu) << 16);2399	cmd.req.arg[6] = (nic->max_tx_ques) | ((nic->max_rx_ques) << 16);2400	cmd.req.arg[7] = (nic->min_tx_bw) | ((nic->max_tx_bw) << 16);2401	for (i = 8; i < 32; i++)2402		cmd.req.arg[i] = 0;2403 2404	err = qlcnic_issue_cmd(adapter, &cmd);2405 2406	if (err != QLCNIC_RCODE_SUCCESS) {2407		dev_err(&adapter->pdev->dev, "Failed to set nic info%d\n",2408			err);2409		err = -EIO;2410	}2411 2412	qlcnic_free_mbx_args(&cmd);2413 2414	return err;2415}2416 2417int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *adapter,2418			     struct qlcnic_info *npar_info, u8 func_id)2419{2420	int err;2421	u32 temp;2422	u8 op = 0;2423	struct qlcnic_cmd_args cmd;2424	struct qlcnic_hardware_context *ahw = adapter->ahw;2425 2426	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);2427	if (err)2428		return err;2429 2430	if (func_id != ahw->pci_func) {2431		temp = func_id << 16;2432		cmd.req.arg[1] = op | BIT_31 | temp;2433	} else {2434		cmd.req.arg[1] = ahw->pci_func << 16;2435	}2436	err = qlcnic_issue_cmd(adapter, &cmd);2437	if (err) {2438		dev_info(&adapter->pdev->dev,2439			 "Failed to get nic info %d\n", err);2440		goto out;2441	}2442 2443	npar_info->op_type = cmd.rsp.arg[1];2444	npar_info->pci_func = cmd.rsp.arg[2] & 0xFFFF;2445	npar_info->op_mode = (cmd.rsp.arg[2] & 0xFFFF0000) >> 16;2446	npar_info->phys_port = cmd.rsp.arg[3] & 0xFFFF;2447	npar_info->switch_mode = (cmd.rsp.arg[3] & 0xFFFF0000) >> 16;2448	npar_info->capabilities = cmd.rsp.arg[4];2449	npar_info->max_mac_filters = cmd.rsp.arg[5] & 0xFF;2450	npar_info->max_mtu = (cmd.rsp.arg[5] & 0xFFFF0000) >> 16;2451	npar_info->max_tx_ques = cmd.rsp.arg[6] & 0xFFFF;2452	npar_info->max_rx_ques = (cmd.rsp.arg[6] & 0xFFFF0000) >> 16;2453	npar_info->min_tx_bw = cmd.rsp.arg[7] & 0xFFFF;2454	npar_info->max_tx_bw = (cmd.rsp.arg[7] & 0xFFFF0000) >> 16;2455	if (cmd.rsp.arg[8] & 0x1)2456		npar_info->max_bw_reg_offset = (cmd.rsp.arg[8] & 0x7FFE) >> 1;2457	if (cmd.rsp.arg[8] & 0x10000) {2458		temp = (cmd.rsp.arg[8] & 0x7FFE0000) >> 17;2459		npar_info->max_linkspeed_reg_offset = temp;2460	}2461 2462	memcpy(ahw->extra_capability, &cmd.rsp.arg[16],2463	       sizeof(ahw->extra_capability));2464 2465out:2466	qlcnic_free_mbx_args(&cmd);2467	return err;2468}2469 2470int qlcnic_get_pci_func_type(struct qlcnic_adapter *adapter, u16 type,2471			     u16 *nic, u16 *fcoe, u16 *iscsi)2472{2473	struct device *dev = &adapter->pdev->dev;2474	int err = 0;2475 2476	switch (type) {2477	case QLCNIC_TYPE_NIC:2478		(*nic)++;2479		break;2480	case QLCNIC_TYPE_FCOE:2481		(*fcoe)++;2482		break;2483	case QLCNIC_TYPE_ISCSI:2484		(*iscsi)++;2485		break;2486	default:2487		dev_err(dev, "%s: Unknown PCI type[%x]\n",2488			__func__, type);2489		err = -EIO;2490	}2491 2492	return err;2493}2494 2495int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,2496			     struct qlcnic_pci_info *pci_info)2497{2498	struct qlcnic_hardware_context *ahw = adapter->ahw;2499	struct device *dev = &adapter->pdev->dev;2500	u16 nic = 0, fcoe = 0, iscsi = 0;2501	struct qlcnic_cmd_args cmd;2502	int i, err = 0, j = 0;2503	u32 temp;2504 2505	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);2506	if (err)2507		return err;2508 2509	err = qlcnic_issue_cmd(adapter, &cmd);2510 2511	ahw->total_nic_func = 0;2512	if (err == QLCNIC_RCODE_SUCCESS) {2513		ahw->max_pci_func = cmd.rsp.arg[1] & 0xFF;2514		for (i = 2, j = 0; j < ahw->max_vnic_func; j++, pci_info++) {2515			pci_info->id = cmd.rsp.arg[i] & 0xFFFF;2516			pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;2517			i++;2518			if (!pci_info->active) {2519				i += QLC_SKIP_INACTIVE_PCI_REGS;2520				continue;2521			}2522			pci_info->type = cmd.rsp.arg[i] & 0xFFFF;2523			err = qlcnic_get_pci_func_type(adapter, pci_info->type,2524						       &nic, &fcoe, &iscsi);2525			temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;2526			pci_info->default_port = temp;2527			i++;2528			pci_info->tx_min_bw = cmd.rsp.arg[i] & 0xFFFF;2529			temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;2530			pci_info->tx_max_bw = temp;2531			i = i + 2;2532			memcpy(pci_info->mac, &cmd.rsp.arg[i], ETH_ALEN - 2);2533			i++;2534			memcpy(pci_info->mac + sizeof(u32), &cmd.rsp.arg[i], 2);2535			i = i + 3;2536		}2537	} else {2538		dev_err(dev, "Failed to get PCI Info, error = %d\n", err);2539		err = -EIO;2540	}2541 2542	ahw->total_nic_func = nic;2543	ahw->total_pci_func = nic + fcoe + iscsi;2544	if (ahw->total_nic_func == 0 || ahw->total_pci_func == 0) {2545		dev_err(dev, "%s: Invalid function count: total nic func[%x], total pci func[%x]\n",2546			__func__, ahw->total_nic_func, ahw->total_pci_func);2547		err = -EIO;2548	}2549	qlcnic_free_mbx_args(&cmd);2550 2551	return err;2552}2553 2554int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type)2555{2556	int i, index, err;2557	u8 max_ints;2558	u32 val, temp, type;2559	struct qlcnic_cmd_args cmd;2560 2561	max_ints = adapter->ahw->num_msix - 1;2562	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT);2563	if (err)2564		return err;2565 2566	cmd.req.arg[1] = max_ints;2567 2568	if (qlcnic_sriov_vf_check(adapter))2569		cmd.req.arg[1] |= (adapter->ahw->pci_func << 8) | BIT_16;2570 2571	for (i = 0, index = 2; i < max_ints; i++) {2572		type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;2573		val = type | (adapter->ahw->intr_tbl[i].type << 4);2574		if (adapter->ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)2575			val |= (adapter->ahw->intr_tbl[i].id << 16);2576		cmd.req.arg[index++] = val;2577	}2578	err = qlcnic_issue_cmd(adapter, &cmd);2579	if (err) {2580		dev_err(&adapter->pdev->dev,2581			"Failed to configure interrupts 0x%x\n", err);2582		goto out;2583	}2584 2585	max_ints = cmd.rsp.arg[1];2586	for (i = 0, index = 2; i < max_ints; i++, index += 2) {2587		val = cmd.rsp.arg[index];2588		if (LSB(val)) {2589			dev_info(&adapter->pdev->dev,2590				 "Can't configure interrupt %d\n",2591				 adapter->ahw->intr_tbl[i].id);2592			continue;2593		}2594		if (op_type) {2595			adapter->ahw->intr_tbl[i].id = MSW(val);2596			adapter->ahw->intr_tbl[i].enabled = 1;2597			temp = cmd.rsp.arg[index + 1];2598			adapter->ahw->intr_tbl[i].src = temp;2599		} else {2600			adapter->ahw->intr_tbl[i].id = i;2601			adapter->ahw->intr_tbl[i].enabled = 0;2602			adapter->ahw->intr_tbl[i].src = 0;2603		}2604	}2605out:2606	qlcnic_free_mbx_args(&cmd);2607	return err;2608}2609 2610int qlcnic_83xx_lock_flash(struct qlcnic_adapter *adapter)2611{2612	int id, timeout = 0;2613	u32 status = 0;2614 2615	while (status == 0) {2616		status = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);2617		if (status)2618			break;2619 2620		if (++timeout >= QLC_83XX_FLASH_LOCK_TIMEOUT) {2621			id = QLC_SHARED_REG_RD32(adapter,2622						 QLCNIC_FLASH_LOCK_OWNER);2623			dev_err(&adapter->pdev->dev,2624				"%s: failed, lock held by %d\n", __func__, id);2625			return -EIO;2626		}2627		usleep_range(1000, 2000);2628	}2629 2630	QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER, adapter->portnum);2631	return 0;2632}2633 2634void qlcnic_83xx_unlock_flash(struct qlcnic_adapter *adapter)2635{2636	QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);2637	QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER, 0xFF);2638}2639 2640int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,2641				      u32 flash_addr, u8 *p_data,2642				      int count)2643{2644	u32 word, range, flash_offset, addr = flash_addr, ret;2645	ulong indirect_add, direct_window;2646	int i, err = 0;2647 2648	flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1);2649	if (addr & 0x3) {2650		dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);2651		return -EIO;2652	}2653 2654	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_DIRECT_WINDOW,2655				     (addr & 0xFFFF0000));2656 2657	range = flash_offset + (count * sizeof(u32));2658	/* Check if data is spread across multiple sectors */2659	if (range > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {2660 2661		/* Multi sector read */2662		for (i = 0; i < count; i++) {2663			indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);2664			ret = QLCRD32(adapter, indirect_add, &err);2665			if (err == -EIO)2666				return err;2667 2668			word = ret;2669			*(u32 *)p_data  = word;2670			p_data = p_data + 4;2671			addr = addr + 4;2672			flash_offset = flash_offset + 4;2673 2674			if (flash_offset > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {2675				direct_window = QLC_83XX_FLASH_DIRECT_WINDOW;2676				/* This write is needed once for each sector */2677				qlcnic_83xx_wrt_reg_indirect(adapter,2678							     direct_window,2679							     (addr));2680				flash_offset = 0;2681			}2682		}2683	} else {2684		/* Single sector read */2685		for (i = 0; i < count; i++) {2686			indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);2687			ret = QLCRD32(adapter, indirect_add, &err);2688			if (err == -EIO)2689				return err;2690 2691			word = ret;2692			*(u32 *)p_data  = word;2693			p_data = p_data + 4;2694			addr = addr + 4;2695		}2696	}2697 2698	return 0;2699}2700 2701static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)2702{2703	u32 status;2704	int retries = QLC_83XX_FLASH_READ_RETRY_COUNT;2705	int err = 0;2706 2707	do {2708		status = QLCRD32(adapter, QLC_83XX_FLASH_STATUS, &err);2709		if (err == -EIO)2710			return err;2711 2712		if ((status & QLC_83XX_FLASH_STATUS_READY) ==2713		    QLC_83XX_FLASH_STATUS_READY)2714			break;2715 2716		usleep_range(1000, 1100);2717	} while (--retries);2718 2719	if (!retries)2720		return -EIO;2721 2722	return 0;2723}2724 2725int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *adapter)2726{2727	int ret;2728	u32 cmd;2729	cmd = adapter->ahw->fdt.write_statusreg_cmd;2730	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,2731				     (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG | cmd));2732	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,2733				     adapter->ahw->fdt.write_enable_bits);2734	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,2735				     QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);2736	ret = qlcnic_83xx_poll_flash_status_reg(adapter);2737	if (ret)2738		return -EIO;2739 2740	return 0;2741}2742 2743int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter)2744{2745	int ret;2746 2747	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,2748				     (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG |2749				     adapter->ahw->fdt.write_statusreg_cmd));2750	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,2751				     adapter->ahw->fdt.write_disable_bits);2752	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,2753				     QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);2754	ret = qlcnic_83xx_poll_flash_status_reg(adapter);2755	if (ret)2756		return -EIO;2757 2758	return 0;2759}2760 2761int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)2762{2763	int ret, err = 0;2764	u32 mfg_id;2765 2766	if (qlcnic_83xx_lock_flash(adapter))2767		return -EIO;2768 2769	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,2770				     QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL);2771	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,2772				     QLC_83XX_FLASH_READ_CTRL);2773	ret = qlcnic_83xx_poll_flash_status_reg(adapter);2774	if (ret) {2775		qlcnic_83xx_unlock_flash(adapter);2776		return -EIO;2777	}2778 2779	mfg_id = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err);2780	if (err == -EIO) {2781		qlcnic_83xx_unlock_flash(adapter);2782		return err;2783	}2784 2785	adapter->flash_mfg_id = (mfg_id & 0xFF);2786	qlcnic_83xx_unlock_flash(adapter);2787 2788	return 0;2789}2790 2791int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *adapter)2792{2793	int count, fdt_size, ret = 0;2794 2795	fdt_size = sizeof(struct qlcnic_fdt);2796	count = fdt_size / sizeof(u32);2797 2798	if (qlcnic_83xx_lock_flash(adapter))2799		return -EIO;2800 2801	memset(&adapter->ahw->fdt, 0, fdt_size);2802	ret = qlcnic_83xx_lockless_flash_read32(adapter, QLCNIC_FDT_LOCATION,2803						(u8 *)&adapter->ahw->fdt,2804						count);2805	qlcnic_swap32_buffer((u32 *)&adapter->ahw->fdt, count);2806	qlcnic_83xx_unlock_flash(adapter);2807	return ret;2808}2809 2810int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,2811				   u32 sector_start_addr)2812{2813	u32 reversed_addr, addr1, addr2, cmd;2814	int ret = -EIO;2815 2816	if (qlcnic_83xx_lock_flash(adapter) != 0)2817		return -EIO;2818 2819	if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {2820		ret = qlcnic_83xx_enable_flash_write(adapter);2821		if (ret) {2822			qlcnic_83xx_unlock_flash(adapter);2823			dev_err(&adapter->pdev->dev,2824				"%s failed at %d\n",2825				__func__, __LINE__);2826			return ret;2827		}2828	}2829 2830	ret = qlcnic_83xx_poll_flash_status_reg(adapter);2831	if (ret) {2832		qlcnic_83xx_unlock_flash(adapter);2833		dev_err(&adapter->pdev->dev,2834			"%s: failed at %d\n", __func__, __LINE__);2835		return -EIO;2836	}2837 2838	addr1 = (sector_start_addr & 0xFF) << 16;2839	addr2 = (sector_start_addr & 0xFF0000) >> 16;2840	reversed_addr = addr1 | addr2 | (sector_start_addr & 0xFF00);2841 2842	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,2843				     reversed_addr);2844	cmd = QLC_83XX_FLASH_FDT_ERASE_DEF_SIG | adapter->ahw->fdt.erase_cmd;2845	if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id)2846		qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, cmd);2847	else2848		qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,2849					     QLC_83XX_FLASH_OEM_ERASE_SIG);2850	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,2851				     QLC_83XX_FLASH_LAST_ERASE_MS_VAL);2852 2853	ret = qlcnic_83xx_poll_flash_status_reg(adapter);2854	if (ret) {2855		qlcnic_83xx_unlock_flash(adapter);2856		dev_err(&adapter->pdev->dev,2857			"%s: failed at %d\n", __func__, __LINE__);2858		return -EIO;2859	}2860 2861	if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {2862		ret = qlcnic_83xx_disable_flash_write(adapter);2863		if (ret) {2864			qlcnic_83xx_unlock_flash(adapter);2865			dev_err(&adapter->pdev->dev,2866				"%s: failed at %d\n", __func__, __LINE__);2867			return ret;2868		}2869	}2870 2871	qlcnic_83xx_unlock_flash(adapter);2872 2873	return 0;2874}2875 2876int qlcnic_83xx_flash_write32(struct qlcnic_adapter *adapter, u32 addr,2877			      u32 *p_data)2878{2879	int ret = -EIO;2880	u32 addr1 = 0x00800000 | (addr >> 2);2881 2882	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, addr1);2883	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data);2884	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,2885				     QLC_83XX_FLASH_LAST_ERASE_MS_VAL);2886	ret = qlcnic_83xx_poll_flash_status_reg(adapter);2887	if (ret) {2888		dev_err(&adapter->pdev->dev,2889			"%s: failed at %d\n", __func__, __LINE__);2890		return -EIO;2891	}2892 2893	return 0;2894}2895 2896int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,2897				 u32 *p_data, int count)2898{2899	u32 temp;2900	int ret = -EIO, err = 0;2901 2902	if ((count < QLC_83XX_FLASH_WRITE_MIN) ||2903	    (count > QLC_83XX_FLASH_WRITE_MAX)) {2904		dev_err(&adapter->pdev->dev,2905			"%s: Invalid word count\n", __func__);2906		return -EIO;2907	}2908 2909	temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err);2910	if (err == -EIO)2911		return err;2912 2913	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL,2914				     (temp | QLC_83XX_FLASH_SPI_CTRL));2915	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,2916				     QLC_83XX_FLASH_ADDR_TEMP_VAL);2917 2918	/* First DWORD write */2919	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);2920	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,2921				     QLC_83XX_FLASH_FIRST_MS_PATTERN);2922	ret = qlcnic_83xx_poll_flash_status_reg(adapter);2923	if (ret) {2924		dev_err(&adapter->pdev->dev,2925			"%s: failed at %d\n", __func__, __LINE__);2926		return -EIO;2927	}2928 2929	count--;2930	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,2931				     QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL);2932	/* Second to N-1 DWORD writes */2933	while (count != 1) {2934		qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,2935					     *p_data++);2936		qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,2937					     QLC_83XX_FLASH_SECOND_MS_PATTERN);2938		ret = qlcnic_83xx_poll_flash_status_reg(adapter);2939		if (ret) {2940			dev_err(&adapter->pdev->dev,2941				"%s: failed at %d\n", __func__, __LINE__);2942			return -EIO;2943		}2944		count--;2945	}2946 2947	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,2948				     QLC_83XX_FLASH_ADDR_TEMP_VAL |2949				     (addr >> 2));2950	/* Last DWORD write */2951	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);2952	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,2953				     QLC_83XX_FLASH_LAST_MS_PATTERN);2954	ret = qlcnic_83xx_poll_flash_status_reg(adapter);2955	if (ret) {2956		dev_err(&adapter->pdev->dev,2957			"%s: failed at %d\n", __func__, __LINE__);2958		return -EIO;2959	}2960 2961	ret = QLCRD32(adapter, QLC_83XX_FLASH_SPI_STATUS, &err);2962	if (err == -EIO)2963		return err;2964 2965	if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) {2966		dev_err(&adapter->pdev->dev, "%s: failed at %d\n",2967			__func__, __LINE__);2968		/* Operation failed, clear error bit */2969		temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err);2970		if (err == -EIO)2971			return err;2972 2973		qlcnic_83xx_wrt_reg_indirect(adapter,2974					     QLC_83XX_FLASH_SPI_CONTROL,2975					     (temp | QLC_83XX_FLASH_SPI_CTRL));2976	}2977 2978	return 0;2979}2980 2981static void qlcnic_83xx_recover_driver_lock(struct qlcnic_adapter *adapter)2982{2983	u32 val, id;2984 2985	val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);2986 2987	/* Check if recovery need to be performed by the calling function */2988	if ((val & QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK) == 0) {2989		val = val & ~0x3F;2990		val = val | ((adapter->portnum << 2) |2991			     QLC_83XX_NEED_DRV_LOCK_RECOVERY);2992		QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);2993		dev_info(&adapter->pdev->dev,2994			 "%s: lock recovery initiated\n", __func__);2995		mdelay(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);2996		val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);2997		id = ((val >> 2) & 0xF);2998		if (id == adapter->portnum) {2999			val = val & ~QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK;3000			val = val | QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS;3001			QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);3002			/* Force release the lock */3003			QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);3004			/* Clear recovery bits */3005			val = val & ~0x3F;3006			QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);3007			dev_info(&adapter->pdev->dev,3008				 "%s: lock recovery completed\n", __func__);3009		} else {3010			dev_info(&adapter->pdev->dev,3011				 "%s: func %d to resume lock recovery process\n",3012				 __func__, id);3013		}3014	} else {3015		dev_info(&adapter->pdev->dev,3016			 "%s: lock recovery initiated by other functions\n",3017			 __func__);3018	}3019}3020 3021int qlcnic_83xx_lock_driver(struct qlcnic_adapter *adapter)3022{3023	u32 lock_alive_counter, val, id, i = 0, status = 0, temp = 0;3024	int max_attempt = 0;3025 3026	while (status == 0) {3027		status = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK);3028		if (status)3029			break;3030 3031		mdelay(QLC_83XX_DRV_LOCK_WAIT_DELAY);3032		i++;3033 3034		if (i == 1)3035			temp = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);3036 3037		if (i == QLC_83XX_DRV_LOCK_WAIT_COUNTER) {3038			val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);3039			if (val == temp) {3040				id = val & 0xFF;3041				dev_info(&adapter->pdev->dev,3042					 "%s: lock to be recovered from %d\n",3043					 __func__, id);3044				qlcnic_83xx_recover_driver_lock(adapter);3045				i = 0;3046				max_attempt++;3047			} else {3048				dev_err(&adapter->pdev->dev,3049					"%s: failed to get lock\n", __func__);3050				return -EIO;3051			}3052		}3053 3054		/* Force exit from while loop after few attempts */3055		if (max_attempt == QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT) {3056			dev_err(&adapter->pdev->dev,3057				"%s: failed to get lock\n", __func__);3058			return -EIO;3059		}3060	}3061 3062	val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);3063	lock_alive_counter = val >> 8;3064	lock_alive_counter++;3065	val = lock_alive_counter << 8 | adapter->portnum;3066	QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);3067 3068	return 0;3069}3070 3071void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *adapter)3072{3073	u32 val, lock_alive_counter, id;3074 3075	val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);3076	id = val & 0xFF;3077	lock_alive_counter = val >> 8;3078 3079	if (id != adapter->portnum)3080		dev_err(&adapter->pdev->dev,3081			"%s:Warning func %d is unlocking lock owned by %d\n",3082			__func__, adapter->portnum, id);3083 3084	val = (lock_alive_counter << 8) | 0xFF;3085	QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);3086	QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);3087}3088 3089int qlcnic_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,3090				u32 *data, u32 count)3091{3092	int i, j, ret = 0;3093	u32 temp;3094 3095	/* Check alignment */3096	if (addr & 0xF)3097		return -EIO;3098 3099	mutex_lock(&adapter->ahw->mem_lock);3100	qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);3101 3102	for (i = 0; i < count; i++, addr += 16) {3103		if (!((ADDR_IN_RANGE(addr, QLCNIC_ADDR_QDR_NET,3104				     QLCNIC_ADDR_QDR_NET_MAX)) ||3105		      (ADDR_IN_RANGE(addr, QLCNIC_ADDR_DDR_NET,3106				     QLCNIC_ADDR_DDR_NET_MAX)))) {3107			mutex_unlock(&adapter->ahw->mem_lock);3108			return -EIO;3109		}3110 3111		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr);3112		qlcnic_ind_wr(adapter, QLCNIC_MS_WRTDATA_LO, *data++);3113		qlcnic_ind_wr(adapter, QLCNIC_MS_WRTDATA_HI, *data++);3114		qlcnic_ind_wr(adapter, QLCNIC_MS_WRTDATA_ULO, *data++);3115		qlcnic_ind_wr(adapter, QLCNIC_MS_WRTDATA_UHI, *data++);3116		qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_WRITE_ENABLE);3117		qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_WRITE_START);3118 3119		for (j = 0; j < MAX_CTL_CHECK; j++) {3120			temp = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);3121 3122			if ((temp & TA_CTL_BUSY) == 0)3123				break;3124		}3125 3126		/* Status check failure */3127		if (j >= MAX_CTL_CHECK) {3128			printk_ratelimited(KERN_WARNING3129					   "MS memory write failed\n");3130			mutex_unlock(&adapter->ahw->mem_lock);3131			return -EIO;3132		}3133	}3134 3135	mutex_unlock(&adapter->ahw->mem_lock);3136 3137	return ret;3138}3139 3140int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,3141			     u8 *p_data, int count)3142{3143	u32 word, addr = flash_addr, ret;3144	ulong  indirect_addr;3145	int i, err = 0;3146 3147	if (qlcnic_83xx_lock_flash(adapter) != 0)3148		return -EIO;3149 3150	if (addr & 0x3) {3151		dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);3152		qlcnic_83xx_unlock_flash(adapter);3153		return -EIO;3154	}3155 3156	for (i = 0; i < count; i++) {3157		if (qlcnic_83xx_wrt_reg_indirect(adapter,3158						 QLC_83XX_FLASH_DIRECT_WINDOW,3159						 (addr))) {3160			qlcnic_83xx_unlock_flash(adapter);3161			return -EIO;3162		}3163 3164		indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);3165		ret = QLCRD32(adapter, indirect_addr, &err);3166		if (err == -EIO) {3167			qlcnic_83xx_unlock_flash(adapter);3168			return err;3169		}3170 3171		word = ret;3172		*(u32 *)p_data  = word;3173		p_data = p_data + 4;3174		addr = addr + 4;3175	}3176 3177	qlcnic_83xx_unlock_flash(adapter);3178 3179	return 0;3180}3181 3182void qlcnic_83xx_get_port_type(struct qlcnic_adapter *adapter)3183{3184	struct qlcnic_hardware_context *ahw = adapter->ahw;3185	struct qlcnic_cmd_args cmd;3186	u32 config;3187	int err;3188 3189	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_STATUS);3190	if (err)3191		return;3192 3193	err = qlcnic_issue_cmd(adapter, &cmd);3194	if (err) {3195		dev_info(&adapter->pdev->dev,3196			 "Get Link Status Command failed: 0x%x\n", err);3197		goto out;3198	} else {3199		config = cmd.rsp.arg[3];3200 3201		switch (QLC_83XX_SFP_MODULE_TYPE(config)) {3202		case QLC_83XX_MODULE_FIBRE_1000BASE_SX:3203		case QLC_83XX_MODULE_FIBRE_1000BASE_LX:3204		case QLC_83XX_MODULE_FIBRE_1000BASE_CX:3205		case QLC_83XX_MODULE_TP_1000BASE_T:3206			ahw->port_type = QLCNIC_GBE;3207			break;3208		default:3209			ahw->port_type = QLCNIC_XGBE;3210		}3211	}3212out:3213	qlcnic_free_mbx_args(&cmd);3214}3215 3216int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)3217{3218	u8 pci_func;3219	int err;3220	u32 config = 0, state;3221	struct qlcnic_cmd_args cmd;3222	struct qlcnic_hardware_context *ahw = adapter->ahw;3223 3224	if (qlcnic_sriov_vf_check(adapter))3225		pci_func = adapter->portnum;3226	else3227		pci_func = ahw->pci_func;3228 3229	state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(pci_func));3230	if (!QLC_83xx_FUNC_VAL(state, pci_func)) {3231		dev_info(&adapter->pdev->dev, "link state down\n");3232		return config;3233	}3234 3235	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_STATUS);3236	if (err)3237		return err;3238 3239	err = qlcnic_issue_cmd(adapter, &cmd);3240	if (err) {3241		dev_info(&adapter->pdev->dev,3242			 "Get Link Status Command failed: 0x%x\n", err);3243		goto out;3244	} else {3245		config = cmd.rsp.arg[1];3246		switch (QLC_83XX_CURRENT_LINK_SPEED(config)) {3247		case QLC_83XX_10M_LINK:3248			ahw->link_speed = SPEED_10;3249			break;3250		case QLC_83XX_100M_LINK:3251			ahw->link_speed = SPEED_100;3252			break;3253		case QLC_83XX_1G_LINK:3254			ahw->link_speed = SPEED_1000;3255			break;3256		case QLC_83XX_10G_LINK:3257			ahw->link_speed = SPEED_10000;3258			break;3259		default:3260			ahw->link_speed = 0;3261			break;3262		}3263		config = cmd.rsp.arg[3];3264		switch (QLC_83XX_SFP_MODULE_TYPE(config)) {3265		case QLC_83XX_MODULE_FIBRE_10GBASE_LRM:3266		case QLC_83XX_MODULE_FIBRE_10GBASE_LR:3267		case QLC_83XX_MODULE_FIBRE_10GBASE_SR:3268			ahw->supported_type = PORT_FIBRE;3269			ahw->port_type = QLCNIC_XGBE;3270			break;3271		case QLC_83XX_MODULE_FIBRE_1000BASE_SX:3272		case QLC_83XX_MODULE_FIBRE_1000BASE_LX:3273		case QLC_83XX_MODULE_FIBRE_1000BASE_CX:3274			ahw->supported_type = PORT_FIBRE;3275			ahw->port_type = QLCNIC_GBE;3276			break;3277		case QLC_83XX_MODULE_TP_1000BASE_T:3278			ahw->supported_type = PORT_TP;3279			ahw->port_type = QLCNIC_GBE;3280			break;3281		case QLC_83XX_MODULE_DA_10GE_PASSIVE_CP:3282		case QLC_83XX_MODULE_DA_10GE_ACTIVE_CP:3283		case QLC_83XX_MODULE_DA_10GE_LEGACY_CP:3284		case QLC_83XX_MODULE_DA_1GE_PASSIVE_CP:3285			ahw->supported_type = PORT_DA;3286			ahw->port_type = QLCNIC_XGBE;3287			break;3288		default:3289			ahw->supported_type = PORT_OTHER;3290			ahw->port_type = QLCNIC_XGBE;3291		}3292		if (config & 1)3293			err = 1;3294	}3295out:3296	qlcnic_free_mbx_args(&cmd);3297	return config;3298}3299 3300int qlcnic_83xx_get_link_ksettings(struct qlcnic_adapter *adapter,3301				   struct ethtool_link_ksettings *ecmd)3302{3303	struct qlcnic_hardware_context *ahw = adapter->ahw;3304	u32 config = 0;3305	int status = 0;3306	u32 supported, advertising;3307 3308	if (!test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {3309		/* Get port configuration info */3310		status = qlcnic_83xx_get_port_info(adapter);3311		/* Get Link Status related info */3312		config = qlcnic_83xx_test_link(adapter);3313		ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);3314	}3315 3316	/* hard code until there is a way to get it from flash */3317	ahw->board_type = QLCNIC_BRDTYPE_83XX_10G;3318 3319	if (netif_running(adapter->netdev) && ahw->has_link_events) {3320		ecmd->base.speed = ahw->link_speed;3321		ecmd->base.duplex = ahw->link_duplex;3322		ecmd->base.autoneg = ahw->link_autoneg;3323	} else {3324		ecmd->base.speed = SPEED_UNKNOWN;3325		ecmd->base.duplex = DUPLEX_UNKNOWN;3326		ecmd->base.autoneg = AUTONEG_DISABLE;3327	}3328 3329	supported = (SUPPORTED_10baseT_Full |3330			   SUPPORTED_100baseT_Full |3331			   SUPPORTED_1000baseT_Full |3332			   SUPPORTED_10000baseT_Full |3333			   SUPPORTED_Autoneg);3334 3335	ethtool_convert_link_mode_to_legacy_u32(&advertising,3336						ecmd->link_modes.advertising);3337 3338	if (ecmd->base.autoneg == AUTONEG_ENABLE) {3339		if (ahw->port_config & QLC_83XX_10_CAPABLE)3340			advertising |= SUPPORTED_10baseT_Full;3341		if (ahw->port_config & QLC_83XX_100_CAPABLE)3342			advertising |= SUPPORTED_100baseT_Full;3343		if (ahw->port_config & QLC_83XX_1G_CAPABLE)3344			advertising |= SUPPORTED_1000baseT_Full;3345		if (ahw->port_config & QLC_83XX_10G_CAPABLE)3346			advertising |= SUPPORTED_10000baseT_Full;3347		if (ahw->port_config & QLC_83XX_AUTONEG_ENABLE)3348			advertising |= ADVERTISED_Autoneg;3349	} else {3350		switch (ahw->link_speed) {3351		case SPEED_10:3352			advertising = SUPPORTED_10baseT_Full;3353			break;3354		case SPEED_100:3355			advertising = SUPPORTED_100baseT_Full;3356			break;3357		case SPEED_1000:3358			advertising = SUPPORTED_1000baseT_Full;3359			break;3360		case SPEED_10000:3361			advertising = SUPPORTED_10000baseT_Full;3362			break;3363		default:3364			break;3365		}3366 3367	}3368 3369	switch (ahw->supported_type) {3370	case PORT_FIBRE:3371		supported |= SUPPORTED_FIBRE;3372		advertising |= ADVERTISED_FIBRE;3373		ecmd->base.port = PORT_FIBRE;3374		break;3375	case PORT_TP:3376		supported |= SUPPORTED_TP;3377		advertising |= ADVERTISED_TP;3378		ecmd->base.port = PORT_TP;3379		break;3380	case PORT_DA:3381		supported |= SUPPORTED_FIBRE;3382		advertising |= ADVERTISED_FIBRE;3383		ecmd->base.port = PORT_DA;3384		break;3385	default:3386		supported |= SUPPORTED_FIBRE;3387		advertising |= ADVERTISED_FIBRE;3388		ecmd->base.port = PORT_OTHER;3389		break;3390	}3391	ecmd->base.phy_address = ahw->physical_port;3392 3393	ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,3394						supported);3395	ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.advertising,3396						advertising);3397 3398	return status;3399}3400 3401int qlcnic_83xx_set_link_ksettings(struct qlcnic_adapter *adapter,3402				   const struct ethtool_link_ksettings *ecmd)3403{3404	struct qlcnic_hardware_context *ahw = adapter->ahw;3405	u32 config = adapter->ahw->port_config;3406	int status = 0;3407 3408	/* 83xx devices do not support Half duplex */3409	if (ecmd->base.duplex == DUPLEX_HALF) {3410		netdev_info(adapter->netdev,3411			    "Half duplex mode not supported\n");3412		return -EINVAL;3413	}3414 3415	if (ecmd->base.autoneg) {3416		ahw->port_config |= QLC_83XX_AUTONEG_ENABLE;3417		ahw->port_config |= (QLC_83XX_100_CAPABLE |3418				     QLC_83XX_1G_CAPABLE |3419				     QLC_83XX_10G_CAPABLE);3420	} else { /* force speed */3421		ahw->port_config &= ~QLC_83XX_AUTONEG_ENABLE;3422		switch (ecmd->base.speed) {3423		case SPEED_10:3424			ahw->port_config &= ~(QLC_83XX_100_CAPABLE |3425					      QLC_83XX_1G_CAPABLE |3426					      QLC_83XX_10G_CAPABLE);3427			ahw->port_config |= QLC_83XX_10_CAPABLE;3428			break;3429		case SPEED_100:3430			ahw->port_config &= ~(QLC_83XX_10_CAPABLE |3431					      QLC_83XX_1G_CAPABLE |3432					      QLC_83XX_10G_CAPABLE);3433			ahw->port_config |= QLC_83XX_100_CAPABLE;3434			break;3435		case SPEED_1000:3436			ahw->port_config &= ~(QLC_83XX_10_CAPABLE |3437					      QLC_83XX_100_CAPABLE |3438					      QLC_83XX_10G_CAPABLE);3439			ahw->port_config |= QLC_83XX_1G_CAPABLE;3440			break;3441		case SPEED_10000:3442			ahw->port_config &= ~(QLC_83XX_10_CAPABLE |3443					      QLC_83XX_100_CAPABLE |3444					      QLC_83XX_1G_CAPABLE);3445			ahw->port_config |= QLC_83XX_10G_CAPABLE;3446			break;3447		default:3448			return -EINVAL;3449		}3450	}3451	status = qlcnic_83xx_set_port_config(adapter);3452	if (status) {3453		netdev_info(adapter->netdev,3454			    "Failed to Set Link Speed and autoneg.\n");3455		ahw->port_config = config;3456	}3457 3458	return status;3459}3460 3461static inline u64 *qlcnic_83xx_copy_stats(struct qlcnic_cmd_args *cmd,3462					  u64 *data, int index)3463{3464	u32 low, hi;3465	u64 val;3466 3467	low = cmd->rsp.arg[index];3468	hi = cmd->rsp.arg[index + 1];3469	val = (((u64) low) | (((u64) hi) << 32));3470	*data++ = val;3471	return data;3472}3473 3474static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,3475				   struct qlcnic_cmd_args *cmd, u64 *data,3476				   int type, int *ret)3477{3478	int err, k, total_regs;3479 3480	*ret = 0;3481	err = qlcnic_issue_cmd(adapter, cmd);3482	if (err != QLCNIC_RCODE_SUCCESS) {3483		dev_info(&adapter->pdev->dev,3484			 "Error in get statistics mailbox command\n");3485		*ret = -EIO;3486		return data;3487	}3488	total_regs = cmd->rsp.num;3489	switch (type) {3490	case QLC_83XX_STAT_MAC:3491		/* fill in MAC tx counters */3492		for (k = 2; k < 28; k += 2)3493			data = qlcnic_83xx_copy_stats(cmd, data, k);3494		/* skip 24 bytes of reserved area */3495		/* fill in MAC rx counters */3496		for (k += 6; k < 60; k += 2)3497			data = qlcnic_83xx_copy_stats(cmd, data, k);3498		/* skip 24 bytes of reserved area */3499		/* fill in MAC rx frame stats */3500		for (k += 6; k < 80; k += 2)3501			data = qlcnic_83xx_copy_stats(cmd, data, k);3502		/* fill in eSwitch stats */3503		for (; k < total_regs; k += 2)3504			data = qlcnic_83xx_copy_stats(cmd, data, k);3505		break;3506	case QLC_83XX_STAT_RX:3507		for (k = 2; k < 8; k += 2)3508			data = qlcnic_83xx_copy_stats(cmd, data, k);3509		/* skip 8 bytes of reserved data */3510		for (k += 2; k < 24; k += 2)3511			data = qlcnic_83xx_copy_stats(cmd, data, k);3512		/* skip 8 bytes containing RE1FBQ error data */3513		for (k += 2; k < total_regs; k += 2)3514			data = qlcnic_83xx_copy_stats(cmd, data, k);3515		break;3516	case QLC_83XX_STAT_TX:3517		for (k = 2; k < 10; k += 2)3518			data = qlcnic_83xx_copy_stats(cmd, data, k);3519		/* skip 8 bytes of reserved data */3520		for (k += 2; k < total_regs; k += 2)3521			data = qlcnic_83xx_copy_stats(cmd, data, k);3522		break;3523	default:3524		dev_warn(&adapter->pdev->dev, "Unknown get statistics mode\n");3525		*ret = -EIO;3526	}3527	return data;3528}3529 3530void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)3531{3532	struct qlcnic_cmd_args cmd;3533	struct net_device *netdev = adapter->netdev;3534	int ret = 0;3535 3536	ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);3537	if (ret)3538		return;3539	/* Get Tx stats */3540	cmd.req.arg[1] = BIT_1 | (adapter->tx_ring->ctx_id << 16);3541	cmd.rsp.num = QLC_83XX_TX_STAT_REGS;3542	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,3543				      QLC_83XX_STAT_TX, &ret);3544	if (ret) {3545		netdev_err(netdev, "Error getting Tx stats\n");3546		goto out;3547	}3548	/* Get MAC stats */3549	cmd.req.arg[1] = BIT_2 | (adapter->portnum << 16);3550	cmd.rsp.num = QLC_83XX_MAC_STAT_REGS;3551	memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);3552	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,3553				      QLC_83XX_STAT_MAC, &ret);3554	if (ret) {3555		netdev_err(netdev, "Error getting MAC stats\n");3556		goto out;3557	}3558	/* Get Rx stats */3559	cmd.req.arg[1] = adapter->recv_ctx->context_id << 16;3560	cmd.rsp.num = QLC_83XX_RX_STAT_REGS;3561	memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);3562	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,3563				      QLC_83XX_STAT_RX, &ret);3564	if (ret)3565		netdev_err(netdev, "Error getting Rx stats\n");3566out:3567	qlcnic_free_mbx_args(&cmd);3568}3569 3570#define QLCNIC_83XX_ADD_PORT0		BIT_03571#define QLCNIC_83XX_ADD_PORT1		BIT_13572#define QLCNIC_83XX_EXTENDED_MEM_SIZE	13 /* In MB */3573int qlcnic_83xx_extend_md_capab(struct qlcnic_adapter *adapter)3574{3575	struct qlcnic_cmd_args cmd;3576	int err;3577 3578	err = qlcnic_alloc_mbx_args(&cmd, adapter,3579				    QLCNIC_CMD_83XX_EXTEND_ISCSI_DUMP_CAP);3580	if (err)3581		return err;3582 3583	cmd.req.arg[1] = (QLCNIC_83XX_ADD_PORT0 | QLCNIC_83XX_ADD_PORT1);3584	cmd.req.arg[2] = QLCNIC_83XX_EXTENDED_MEM_SIZE;3585	cmd.req.arg[3] = QLCNIC_83XX_EXTENDED_MEM_SIZE;3586 3587	err = qlcnic_issue_cmd(adapter, &cmd);3588	if (err)3589		dev_err(&adapter->pdev->dev,3590			"failed to issue extend iSCSI minidump capability\n");3591 3592	return err;3593}3594 3595int qlcnic_83xx_reg_test(struct qlcnic_adapter *adapter)3596{3597	u32 major, minor, sub;3598 3599	major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);3600	minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);3601	sub = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);3602 3603	if (adapter->fw_version != QLCNIC_VERSION_CODE(major, minor, sub)) {3604		dev_info(&adapter->pdev->dev, "%s: Reg test failed\n",3605			 __func__);3606		return 1;3607	}3608	return 0;3609}3610 3611inline int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *adapter)3612{3613	return (ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl) *3614		sizeof(*adapter->ahw->ext_reg_tbl)) +3615		(ARRAY_SIZE(qlcnic_83xx_reg_tbl) *3616		sizeof(*adapter->ahw->reg_tbl));3617}3618 3619int qlcnic_83xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff)3620{3621	int i, j = 0;3622 3623	for (i = QLCNIC_DEV_INFO_SIZE + 1;3624	     j < ARRAY_SIZE(qlcnic_83xx_reg_tbl); i++, j++)3625		regs_buff[i] = QLC_SHARED_REG_RD32(adapter, j);3626 3627	for (j = 0; j < ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl); j++)3628		regs_buff[i++] = QLCRDX(adapter->ahw, j);3629	return i;3630}3631 3632int qlcnic_83xx_interrupt_test(struct net_device *netdev)3633{3634	struct qlcnic_adapter *adapter = netdev_priv(netdev);3635	struct qlcnic_hardware_context *ahw = adapter->ahw;3636	struct qlcnic_cmd_args cmd;3637	u8 val, drv_sds_rings = adapter->drv_sds_rings;3638	u8 drv_tx_rings = adapter->drv_tx_rings;3639	u32 data;3640	u16 intrpt_id, id;3641	int ret;3642 3643	if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {3644		netdev_info(netdev, "Device is resetting\n");3645		return -EBUSY;3646	}3647 3648	if (qlcnic_get_diag_lock(adapter)) {3649		netdev_info(netdev, "Device in diagnostics mode\n");3650		return -EBUSY;3651	}3652 3653	ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST,3654					 drv_sds_rings);3655	if (ret)3656		goto fail_diag_irq;3657 3658	ahw->diag_cnt = 0;3659	ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);3660	if (ret)3661		goto fail_mbx_args;3662 3663	if (adapter->flags & QLCNIC_MSIX_ENABLED)3664		intrpt_id = ahw->intr_tbl[0].id;3665	else3666		intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);3667 3668	cmd.req.arg[1] = 1;3669	cmd.req.arg[2] = intrpt_id;3670	cmd.req.arg[3] = BIT_0;3671 3672	ret = qlcnic_issue_cmd(adapter, &cmd);3673	data = cmd.rsp.arg[2];3674	id = LSW(data);3675	val = LSB(MSW(data));3676	if (id != intrpt_id)3677		dev_info(&adapter->pdev->dev,3678			 "Interrupt generated: 0x%x, requested:0x%x\n",3679			 id, intrpt_id);3680	if (val)3681		dev_err(&adapter->pdev->dev,3682			 "Interrupt test error: 0x%x\n", val);3683	if (ret)3684		goto done;3685 3686	msleep(20);3687	ret = !ahw->diag_cnt;3688 3689done:3690	qlcnic_free_mbx_args(&cmd);3691 3692fail_mbx_args:3693	qlcnic_83xx_diag_free_res(netdev, drv_sds_rings);3694 3695fail_diag_irq:3696	adapter->drv_sds_rings = drv_sds_rings;3697	adapter->drv_tx_rings = drv_tx_rings;3698	qlcnic_release_diag_lock(adapter);3699	return ret;3700}3701 3702void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *adapter,3703				struct ethtool_pauseparam *pause)3704{3705	struct qlcnic_hardware_context *ahw = adapter->ahw;3706	int status = 0;3707	u32 config;3708 3709	status = qlcnic_83xx_get_port_config(adapter);3710	if (status) {3711		dev_err(&adapter->pdev->dev,3712			"%s: Get Pause Config failed\n", __func__);3713		return;3714	}3715	config = ahw->port_config;3716	if (config & QLC_83XX_CFG_STD_PAUSE) {3717		switch (MSW(config)) {3718		case QLC_83XX_TX_PAUSE:3719			pause->tx_pause = 1;3720			break;3721		case QLC_83XX_RX_PAUSE:3722			pause->rx_pause = 1;3723			break;3724		case QLC_83XX_TX_RX_PAUSE:3725		default:3726			/* Backward compatibility for existing3727			 * flash definitions3728			 */3729			pause->tx_pause = 1;3730			pause->rx_pause = 1;3731		}3732	}3733 3734	if (QLC_83XX_AUTONEG(config))3735		pause->autoneg = 1;3736}3737 3738int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,3739			       struct ethtool_pauseparam *pause)3740{3741	struct qlcnic_hardware_context *ahw = adapter->ahw;3742	int status = 0;3743	u32 config;3744 3745	status = qlcnic_83xx_get_port_config(adapter);3746	if (status) {3747		dev_err(&adapter->pdev->dev,3748			"%s: Get Pause Config failed.\n", __func__);3749		return status;3750	}3751	config = ahw->port_config;3752 3753	if (ahw->port_type == QLCNIC_GBE) {3754		if (pause->autoneg)3755			ahw->port_config |= QLC_83XX_ENABLE_AUTONEG;3756		if (!pause->autoneg)3757			ahw->port_config &= ~QLC_83XX_ENABLE_AUTONEG;3758	} else if ((ahw->port_type == QLCNIC_XGBE) && (pause->autoneg)) {3759		return -EOPNOTSUPP;3760	}3761 3762	if (!(config & QLC_83XX_CFG_STD_PAUSE))3763		ahw->port_config |= QLC_83XX_CFG_STD_PAUSE;3764 3765	if (pause->rx_pause && pause->tx_pause) {3766		ahw->port_config |= QLC_83XX_CFG_STD_TX_RX_PAUSE;3767	} else if (pause->rx_pause && !pause->tx_pause) {3768		ahw->port_config &= ~QLC_83XX_CFG_STD_TX_PAUSE;3769		ahw->port_config |= QLC_83XX_CFG_STD_RX_PAUSE;3770	} else if (pause->tx_pause && !pause->rx_pause) {3771		ahw->port_config &= ~QLC_83XX_CFG_STD_RX_PAUSE;3772		ahw->port_config |= QLC_83XX_CFG_STD_TX_PAUSE;3773	} else if (!pause->rx_pause && !pause->tx_pause) {3774		ahw->port_config &= ~(QLC_83XX_CFG_STD_TX_RX_PAUSE |3775				      QLC_83XX_CFG_STD_PAUSE);3776	}3777	status = qlcnic_83xx_set_port_config(adapter);3778	if (status) {3779		dev_err(&adapter->pdev->dev,3780			"%s: Set Pause Config failed.\n", __func__);3781		ahw->port_config = config;3782	}3783	return status;3784}3785 3786static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)3787{3788	int ret, err = 0;3789	u32 temp;3790 3791	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,3792				     QLC_83XX_FLASH_OEM_READ_SIG);3793	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,3794				     QLC_83XX_FLASH_READ_CTRL);3795	ret = qlcnic_83xx_poll_flash_status_reg(adapter);3796	if (ret)3797		return -EIO;3798 3799	temp = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err);3800	if (err == -EIO)3801		return err;3802 3803	return temp & 0xFF;3804}3805 3806int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)3807{3808	int status;3809 3810	status = qlcnic_83xx_read_flash_status_reg(adapter);3811	if (status == -EIO) {3812		dev_info(&adapter->pdev->dev, "%s: EEPROM test failed.\n",3813			 __func__);3814		return 1;3815	}3816	return 0;3817}3818 3819static int qlcnic_83xx_shutdown(struct pci_dev *pdev)3820{3821	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);3822	struct net_device *netdev = adapter->netdev;3823 3824	netif_device_detach(netdev);3825	qlcnic_cancel_idc_work(adapter);3826 3827	if (netif_running(netdev))3828		qlcnic_down(adapter, netdev);3829 3830	qlcnic_83xx_disable_mbx_intr(adapter);3831	cancel_delayed_work_sync(&adapter->idc_aen_work);3832 3833	return pci_save_state(pdev);3834}3835 3836static int qlcnic_83xx_resume(struct qlcnic_adapter *adapter)3837{3838	struct qlcnic_hardware_context *ahw = adapter->ahw;3839	struct qlc_83xx_idc *idc = &ahw->idc;3840	int err = 0;3841 3842	err = qlcnic_83xx_idc_init(adapter);3843	if (err)3844		return err;3845 3846	if (ahw->nic_mode == QLCNIC_VNIC_MODE) {3847		if (ahw->op_mode == QLCNIC_MGMT_FUNC) {3848			qlcnic_83xx_set_vnic_opmode(adapter);3849		} else {3850			err = qlcnic_83xx_check_vnic_state(adapter);3851			if (err)3852				return err;3853		}3854	}3855 3856	err = qlcnic_83xx_idc_reattach_driver(adapter);3857	if (err)3858		return err;3859 3860	qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,3861			     idc->delay);3862	return err;3863}3864 3865void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx)3866{3867	reinit_completion(&mbx->completion);3868	set_bit(QLC_83XX_MBX_READY, &mbx->status);3869}3870 3871void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx)3872{3873	if (!mbx)3874		return;3875 3876	destroy_workqueue(mbx->work_q);3877	kfree(mbx);3878}3879 3880static inline void3881qlcnic_83xx_notify_cmd_completion(struct qlcnic_adapter *adapter,3882				  struct qlcnic_cmd_args *cmd)3883{3884	atomic_set(&cmd->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED);3885 3886	if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) {3887		qlcnic_free_mbx_args(cmd);3888		kfree(cmd);3889		return;3890	}3891	complete(&cmd->completion);3892}3893 3894static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter)3895{3896	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;3897	struct list_head *head = &mbx->cmd_q;3898	struct qlcnic_cmd_args *cmd = NULL;3899 3900	spin_lock_bh(&mbx->queue_lock);3901 3902	while (!list_empty(head)) {3903		cmd = list_entry(head->next, struct qlcnic_cmd_args, list);3904		dev_info(&adapter->pdev->dev, "%s: Mailbox command 0x%x\n",3905			 __func__, cmd->cmd_op);3906		list_del(&cmd->list);3907		mbx->num_cmds--;3908		qlcnic_83xx_notify_cmd_completion(adapter, cmd);3909	}3910 3911	spin_unlock_bh(&mbx->queue_lock);3912}3913 3914static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter)3915{3916	struct qlcnic_hardware_context *ahw = adapter->ahw;3917	struct qlcnic_mailbox *mbx = ahw->mailbox;3918	u32 host_mbx_ctrl;3919 3920	if (!test_bit(QLC_83XX_MBX_READY, &mbx->status))3921		return -EBUSY;3922 3923	host_mbx_ctrl = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);3924	if (host_mbx_ctrl) {3925		clear_bit(QLC_83XX_MBX_READY, &mbx->status);3926		ahw->idc.collect_dump = 1;3927		return -EIO;3928	}3929 3930	return 0;3931}3932 3933static inline void qlcnic_83xx_signal_mbx_cmd(struct qlcnic_adapter *adapter,3934					      u8 issue_cmd)3935{3936	if (issue_cmd)3937		QLCWRX(adapter->ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);3938	else3939		QLCWRX(adapter->ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);3940}3941 3942static void qlcnic_83xx_dequeue_mbx_cmd(struct qlcnic_adapter *adapter,3943					struct qlcnic_cmd_args *cmd)3944{3945	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;3946 3947	spin_lock_bh(&mbx->queue_lock);3948 3949	list_del(&cmd->list);3950	mbx->num_cmds--;3951 3952	spin_unlock_bh(&mbx->queue_lock);3953 3954	qlcnic_83xx_notify_cmd_completion(adapter, cmd);3955}3956 3957static void qlcnic_83xx_encode_mbx_cmd(struct qlcnic_adapter *adapter,3958				       struct qlcnic_cmd_args *cmd)3959{3960	u32 mbx_cmd, fw_hal_version, hdr_size, total_size, tmp;3961	struct qlcnic_hardware_context *ahw = adapter->ahw;3962	int i, j;3963 3964	if (cmd->op_type != QLC_83XX_MBX_POST_BC_OP) {3965		mbx_cmd = cmd->req.arg[0];3966		writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));3967		for (i = 1; i < cmd->req.num; i++)3968			writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));3969	} else {3970		fw_hal_version = ahw->fw_hal_version;3971		hdr_size = sizeof(struct qlcnic_bc_hdr) / sizeof(u32);3972		total_size = cmd->pay_size + hdr_size;3973		tmp = QLCNIC_CMD_BC_EVENT_SETUP | total_size << 16;3974		mbx_cmd = tmp | fw_hal_version << 29;3975		writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));3976 3977		/* Back channel specific operations bits */3978		mbx_cmd = 0x1 | 1 << 4;3979 3980		if (qlcnic_sriov_pf_check(adapter))3981			mbx_cmd |= cmd->func_num << 5;3982 3983		writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1));3984 3985		for (i = 2, j = 0; j < hdr_size; i++, j++)3986			writel(*(cmd->hdr++), QLCNIC_MBX_HOST(ahw, i));3987		for (j = 0; j < cmd->pay_size; j++, i++)3988			writel(*(cmd->pay++), QLCNIC_MBX_HOST(ahw, i));3989	}3990}3991 3992void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *adapter)3993{3994	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;3995 3996	if (!mbx)3997		return;3998 3999	clear_bit(QLC_83XX_MBX_READY, &mbx->status);4000	complete(&mbx->completion);4001	cancel_work_sync(&mbx->work);4002	flush_workqueue(mbx->work_q);4003	qlcnic_83xx_flush_mbx_queue(adapter);4004}4005 4006static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter,4007				       struct qlcnic_cmd_args *cmd,4008				       unsigned long *timeout)4009{4010	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;4011 4012	if (test_bit(QLC_83XX_MBX_READY, &mbx->status)) {4013		atomic_set(&cmd->rsp_status, QLC_83XX_MBX_RESPONSE_WAIT);4014		init_completion(&cmd->completion);4015		cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN;4016 4017		spin_lock_bh(&mbx->queue_lock);4018 4019		list_add_tail(&cmd->list, &mbx->cmd_q);4020		mbx->num_cmds++;4021		cmd->total_cmds = mbx->num_cmds;4022		*timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT;4023		queue_work(mbx->work_q, &mbx->work);4024 4025		spin_unlock_bh(&mbx->queue_lock);4026 4027		return 0;4028	}4029 4030	return -EBUSY;4031}4032 4033static int qlcnic_83xx_check_mac_rcode(struct qlcnic_adapter *adapter,4034				       struct qlcnic_cmd_args *cmd)4035{4036	u8 mac_cmd_rcode;4037	u32 fw_data;4038 4039	if (cmd->cmd_op == QLCNIC_CMD_CONFIG_MAC_VLAN) {4040		fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2));4041		mac_cmd_rcode = (u8)fw_data;4042		if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE ||4043		    mac_cmd_rcode == QLC_83XX_MAC_PRESENT ||4044		    mac_cmd_rcode == QLC_83XX_MAC_ABSENT) {4045			cmd->rsp_opcode = QLCNIC_RCODE_SUCCESS;4046			return QLCNIC_RCODE_SUCCESS;4047		}4048	}4049 4050	return -EINVAL;4051}4052 4053static void qlcnic_83xx_decode_mbx_rsp(struct qlcnic_adapter *adapter,4054				       struct qlcnic_cmd_args *cmd)4055{4056	struct qlcnic_hardware_context *ahw = adapter->ahw;4057	struct device *dev = &adapter->pdev->dev;4058	u8 mbx_err_code;4059	u32 fw_data;4060 4061	fw_data = readl(QLCNIC_MBX_FW(ahw, 0));4062	mbx_err_code = QLCNIC_MBX_STATUS(fw_data);4063	qlcnic_83xx_get_mbx_data(adapter, cmd);4064 4065	switch (mbx_err_code) {4066	case QLCNIC_MBX_RSP_OK:4067	case QLCNIC_MBX_PORT_RSP_OK:4068		cmd->rsp_opcode = QLCNIC_RCODE_SUCCESS;4069		break;4070	default:4071		if (!qlcnic_83xx_check_mac_rcode(adapter, cmd))4072			break;4073 4074		dev_err(dev, "%s: Mailbox command failed, opcode=0x%x, cmd_type=0x%x, func=0x%x, op_mode=0x%x, error=0x%x\n",4075			__func__, cmd->cmd_op, cmd->type, ahw->pci_func,4076			ahw->op_mode, mbx_err_code);4077		cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_FAILED;4078		qlcnic_dump_mbx(adapter, cmd);4079	}4080 4081	return;4082}4083 4084static inline void qlcnic_dump_mailbox_registers(struct qlcnic_adapter *adapter)4085{4086	struct qlcnic_hardware_context *ahw = adapter->ahw;4087	u32 offset;4088 4089	offset = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);4090	dev_info(&adapter->pdev->dev, "Mbx interrupt mask=0x%x, Mbx interrupt enable=0x%x, Host mbx control=0x%x, Fw mbx control=0x%x",4091		 readl(ahw->pci_base0 + offset),4092		 QLCRDX(ahw, QLCNIC_MBX_INTR_ENBL),4093		 QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL),4094		 QLCRDX(ahw, QLCNIC_FW_MBX_CTRL));4095}4096 4097static void qlcnic_83xx_mailbox_worker(struct work_struct *work)4098{4099	struct qlcnic_mailbox *mbx = container_of(work, struct qlcnic_mailbox,4100						  work);4101	struct qlcnic_adapter *adapter = mbx->adapter;4102	const struct qlcnic_mbx_ops *mbx_ops = mbx->ops;4103	struct device *dev = &adapter->pdev->dev;4104	struct list_head *head = &mbx->cmd_q;4105	struct qlcnic_hardware_context *ahw;4106	struct qlcnic_cmd_args *cmd = NULL;4107	unsigned long flags;4108 4109	ahw = adapter->ahw;4110 4111	while (true) {4112		if (qlcnic_83xx_check_mbx_status(adapter)) {4113			qlcnic_83xx_flush_mbx_queue(adapter);4114			return;4115		}4116 4117		spin_lock_irqsave(&mbx->aen_lock, flags);4118		mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;4119		spin_unlock_irqrestore(&mbx->aen_lock, flags);4120 4121		spin_lock_bh(&mbx->queue_lock);4122 4123		if (list_empty(head)) {4124			spin_unlock_bh(&mbx->queue_lock);4125			return;4126		}4127		cmd = list_entry(head->next, struct qlcnic_cmd_args, list);4128 4129		spin_unlock_bh(&mbx->queue_lock);4130 4131		mbx_ops->encode_cmd(adapter, cmd);4132		mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST);4133 4134		if (wait_for_completion_timeout(&mbx->completion,4135						QLC_83XX_MBX_TIMEOUT)) {4136			mbx_ops->decode_resp(adapter, cmd);4137			mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_COMPLETION);4138		} else {4139			dev_err(dev, "%s: Mailbox command timeout, opcode=0x%x, cmd_type=0x%x, func=0x%x, op_mode=0x%x\n",4140				__func__, cmd->cmd_op, cmd->type, ahw->pci_func,4141				ahw->op_mode);4142			clear_bit(QLC_83XX_MBX_READY, &mbx->status);4143			qlcnic_dump_mailbox_registers(adapter);4144			qlcnic_83xx_get_mbx_data(adapter, cmd);4145			qlcnic_dump_mbx(adapter, cmd);4146			qlcnic_83xx_idc_request_reset(adapter,4147						      QLCNIC_FORCE_FW_DUMP_KEY);4148			cmd->rsp_opcode = QLCNIC_RCODE_TIMEOUT;4149		}4150		mbx_ops->dequeue_cmd(adapter, cmd);4151	}4152}4153 4154static const struct qlcnic_mbx_ops qlcnic_83xx_mbx_ops = {4155	.enqueue_cmd    = qlcnic_83xx_enqueue_mbx_cmd,4156	.dequeue_cmd    = qlcnic_83xx_dequeue_mbx_cmd,4157	.decode_resp    = qlcnic_83xx_decode_mbx_rsp,4158	.encode_cmd     = qlcnic_83xx_encode_mbx_cmd,4159	.nofity_fw      = qlcnic_83xx_signal_mbx_cmd,4160};4161 4162int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *adapter)4163{4164	struct qlcnic_hardware_context *ahw = adapter->ahw;4165	struct qlcnic_mailbox *mbx;4166 4167	ahw->mailbox = kzalloc(sizeof(*mbx), GFP_KERNEL);4168	if (!ahw->mailbox)4169		return -ENOMEM;4170 4171	mbx = ahw->mailbox;4172	mbx->ops = &qlcnic_83xx_mbx_ops;4173	mbx->adapter = adapter;4174 4175	spin_lock_init(&mbx->queue_lock);4176	spin_lock_init(&mbx->aen_lock);4177	INIT_LIST_HEAD(&mbx->cmd_q);4178	init_completion(&mbx->completion);4179 4180	mbx->work_q = create_singlethread_workqueue("qlcnic_mailbox");4181	if (mbx->work_q == NULL) {4182		kfree(mbx);4183		return -ENOMEM;4184	}4185 4186	INIT_WORK(&mbx->work, qlcnic_83xx_mailbox_worker);4187	set_bit(QLC_83XX_MBX_READY, &mbx->status);4188	return 0;4189}4190 4191static pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *pdev,4192						      pci_channel_state_t state)4193{4194	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);4195 4196	if (state == pci_channel_io_perm_failure)4197		return PCI_ERS_RESULT_DISCONNECT;4198 4199	if (state == pci_channel_io_normal)4200		return PCI_ERS_RESULT_RECOVERED;4201 4202	set_bit(__QLCNIC_AER, &adapter->state);4203	set_bit(__QLCNIC_RESETTING, &adapter->state);4204 4205	qlcnic_83xx_aer_stop_poll_work(adapter);4206 4207	pci_save_state(pdev);4208	pci_disable_device(pdev);4209 4210	return PCI_ERS_RESULT_NEED_RESET;4211}4212 4213static pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *pdev)4214{4215	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);4216	int err = 0;4217 4218	pdev->error_state = pci_channel_io_normal;4219	err = pci_enable_device(pdev);4220	if (err)4221		goto disconnect;4222 4223	pci_set_power_state(pdev, PCI_D0);4224	pci_set_master(pdev);4225	pci_restore_state(pdev);4226 4227	err = qlcnic_83xx_aer_reset(adapter);4228	if (err == 0)4229		return PCI_ERS_RESULT_RECOVERED;4230disconnect:4231	clear_bit(__QLCNIC_AER, &adapter->state);4232	clear_bit(__QLCNIC_RESETTING, &adapter->state);4233	return PCI_ERS_RESULT_DISCONNECT;4234}4235 4236static void qlcnic_83xx_io_resume(struct pci_dev *pdev)4237{4238	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);4239 4240	if (test_and_clear_bit(__QLCNIC_AER, &adapter->state))4241		qlcnic_83xx_aer_start_poll_work(adapter);4242}4243