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