summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/qlogic/qlcnic
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic')
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h59
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c346
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h13
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c59
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c62
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c172
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c6
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c103
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h8
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c226
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c225
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c60
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c36
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c126
16 files changed, 1139 insertions, 367 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index c1b693cb3df3..b00cf5665eab 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -38,8 +38,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 2
-#define _QLCNIC_LINUX_SUBVERSION 42
-#define QLCNIC_LINUX_VERSIONID "5.2.42"
+#define _QLCNIC_LINUX_SUBVERSION 44
+#define QLCNIC_LINUX_VERSIONID "5.2.44"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -303,7 +303,6 @@ extern int qlcnic_use_msi;
extern int qlcnic_use_msi_x;
extern int qlcnic_auto_fw_reset;
extern int qlcnic_load_fw_file;
-extern int qlcnic_config_npars;
/* Number of status descriptors to handle per interrupt */
#define MAX_STATUS_HANDLE (64)
@@ -394,6 +393,9 @@ struct qlcnic_fw_dump {
u32 size; /* total size of the dump */
void *data; /* dump data area */
struct qlcnic_dump_template_hdr *tmpl_hdr;
+ dma_addr_t phys_addr;
+ void *dma_buffer;
+ bool use_pex_dma;
};
/*
@@ -427,6 +429,7 @@ struct qlcnic_hardware_context {
u8 nic_mode;
char diag_cnt;
+ u16 max_uc_count;
u16 port_type;
u16 board_type;
u16 supported_type;
@@ -443,9 +446,10 @@ struct qlcnic_hardware_context {
u16 max_mtu;
u32 msg_enable;
u16 act_pci_func;
+ u16 max_pci_func;
u32 capabilities;
- u32 capabilities2;
+ u32 extra_capability[3];
u32 temp;
u32 int_vec_bit;
u32 fw_hal_version;
@@ -815,7 +819,8 @@ struct qlcnic_mac_list_s {
#define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG BIT_2
#define QLCNIC_FW_CAP2_HW_LRO_IPV6 BIT_3
-#define QLCNIC_FW_CAPABILITY_2_OCBB BIT_5
+#define QLCNIC_FW_CAPABILITY_SET_DRV_VER BIT_5
+#define QLCNIC_FW_CAPABILITY_2_BEACON BIT_7
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
@@ -913,6 +918,9 @@ struct qlcnic_ipaddr {
#define QLCNIC_IS_TSO_CAPABLE(adapter) \
((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+#define QLCNIC_BEACON_EANBLE 0xC
+#define QLCNIC_BEACON_DISABLE 0xD
+
#define QLCNIC_DEF_NUM_STS_DESC_RINGS 4
#define QLCNIC_MSIX_TBL_SPACE 8192
#define QLCNIC_PCI_REG_MSIX_TBL 0x44
@@ -932,6 +940,7 @@ struct qlcnic_ipaddr {
#define __QLCNIC_SRIOV_ENABLE 10
#define __QLCNIC_SRIOV_CAPABLE 11
#define __QLCNIC_MBX_POLL_ENABLE 12
+#define __QLCNIC_DIAG_MODE 13
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
@@ -1467,7 +1476,7 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);
void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter);
int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
-int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *);
+int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *, u32);
int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
netdev_features_t qlcnic_fix_features(struct net_device *netdev,
netdev_features_t features);
@@ -1489,7 +1498,9 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t);
int qlcnic_validate_max_rss(struct qlcnic_adapter *, __u32);
void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
+void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);
int qlcnic_enable_msix(struct qlcnic_adapter *, u32);
+void qlcnic_set_drv_version(struct qlcnic_adapter *);
/* eSwitch management functions */
int qlcnic_config_switch_port(struct qlcnic_adapter *,
@@ -1543,6 +1554,7 @@ int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
int qlcnic_reset_npar_config(struct qlcnic_adapter *);
int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16);
+int qlcnic_get_beacon_state(struct qlcnic_adapter *, u8 *);
int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
int qlcnic_read_mac_addr(struct qlcnic_adapter *);
int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int);
@@ -1584,6 +1596,8 @@ struct qlcnic_nic_template {
void (*napi_del)(struct qlcnic_adapter *);
void (*config_ipaddr)(struct qlcnic_adapter *, __be32, int);
irqreturn_t (*clear_legacy_intr)(struct qlcnic_adapter *);
+ int (*shutdown)(struct pci_dev *);
+ int (*resume)(struct qlcnic_adapter *);
};
/* Adapter hardware abstraction */
@@ -1625,6 +1639,7 @@ struct qlcnic_hardware_ops {
int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16);
int (*get_board_info) (struct qlcnic_adapter *);
+ void (*set_mac_filter_count) (struct qlcnic_adapter *);
void (*free_mac_list) (struct qlcnic_adapter *);
};
@@ -1787,6 +1802,18 @@ static inline void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
adapter->ahw->hw_ops->napi_enable(adapter);
}
+static inline int __qlcnic_shutdown(struct pci_dev *pdev)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+
+ return adapter->nic_ops->shutdown(pdev);
+}
+
+static inline int __qlcnic_resume(struct qlcnic_adapter *adapter)
+{
+ return adapter->nic_ops->resume(adapter);
+}
+
static inline void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
{
adapter->ahw->hw_ops->napi_disable(adapter);
@@ -1840,6 +1867,11 @@ static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
return adapter->ahw->hw_ops->free_mac_list(adapter);
}
+static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->hw_ops->set_mac_filter_count(adapter);
+}
+
static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
u32 key)
{
@@ -1886,6 +1918,21 @@ static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
writel(0xfbff, adapter->tgt_mask_reg);
}
+static inline int qlcnic_get_diag_lock(struct qlcnic_adapter *adapter)
+{
+ return test_and_set_bit(__QLCNIC_DIAG_MODE, &adapter->state);
+}
+
+static inline void qlcnic_release_diag_lock(struct qlcnic_adapter *adapter)
+{
+ clear_bit(__QLCNIC_DIAG_MODE, &adapter->state);
+}
+
+static inline int qlcnic_check_diag_status(struct qlcnic_adapter *adapter)
+{
+ return test_bit(__QLCNIC_DIAG_MODE, &adapter->state);
+}
+
extern const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index b4ff1e35a11d..0913c623a67e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -63,6 +63,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},
{QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
{QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
+ {QLCNIC_CMD_83XX_SET_DRV_VER, 4, 1},
{QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
{QLCNIC_CMD_CONFIG_VPORT, 4, 4},
{QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},
@@ -172,6 +173,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
.config_promisc_mode = qlcnic_83xx_nic_set_promisc,
.change_l2_filter = qlcnic_83xx_change_l2_filter,
.get_board_info = qlcnic_83xx_get_port_info,
+ .set_mac_filter_count = qlcnic_83xx_set_mac_filter_count,
.free_mac_list = qlcnic_82xx_free_mac_list,
};
@@ -184,6 +186,8 @@ static struct qlcnic_nic_template qlcnic_83xx_ops = {
.napi_del = qlcnic_83xx_napi_del,
.config_ipaddr = qlcnic_83xx_config_ipaddr,
.clear_legacy_intr = qlcnic_83xx_clear_legacy_intr,
+ .shutdown = qlcnic_83xx_shutdown,
+ .resume = qlcnic_83xx_resume,
};
void qlcnic_83xx_register_map(struct qlcnic_hardware_context *ahw)
@@ -312,6 +316,11 @@ inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)
writel(0, adapter->tgt_mask_reg);
}
+inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapter)
+{
+ writel(1, adapter->tgt_mask_reg);
+}
+
/* Enable MSI-x and INT-x interrupts */
void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
struct qlcnic_host_sds_ring *sds_ring)
@@ -458,6 +467,9 @@ void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
{
u32 num_msix;
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+ qlcnic_83xx_set_legacy_intr_mask(adapter);
+
qlcnic_83xx_disable_mbx_intr(adapter);
if (adapter->flags & QLCNIC_MSIX_ENABLED)
@@ -474,7 +486,6 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
{
irq_handler_t handler;
u32 val;
- char name[32];
int err = 0;
unsigned long flags = 0;
@@ -485,9 +496,7 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
if (adapter->flags & QLCNIC_MSIX_ENABLED) {
handler = qlcnic_83xx_handle_aen;
val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;
- snprintf(name, (IFNAMSIZ + 4),
- "%s[%s]", "qlcnic", "aen");
- err = request_irq(val, handler, flags, name, adapter);
+ err = request_irq(val, handler, flags, "qlcnic-MB", adapter);
if (err) {
dev_err(&adapter->pdev->dev,
"failed to register MBX interrupt\n");
@@ -604,6 +613,22 @@ int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
return status;
}
+void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ u16 act_pci_fn = ahw->act_pci_func;
+ u16 count;
+
+ ahw->max_mc_count = QLC_83XX_MAX_MC_COUNT;
+ if (act_pci_fn <= 2)
+ count = (QLC_83XX_MAX_UC_COUNT - QLC_83XX_MAX_MC_COUNT) /
+ act_pci_fn;
+ else
+ count = (QLC_83XX_LB_MAX_FILTERS - QLC_83XX_MAX_MC_COUNT) /
+ act_pci_fn;
+ ahw->max_uc_count = count;
+}
+
void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
{
u32 val;
@@ -839,7 +864,9 @@ void qlcnic_83xx_idc_aen_work(struct work_struct *work)
int i, err = 0;
adapter = container_of(work, struct qlcnic_adapter, idc_aen_work.work);
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_IDC_ACK);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_IDC_ACK);
+ if (err)
+ return;
for (i = 1; i < QLC_83XX_MBX_AEN_CNT; i++)
cmd.req.arg[i] = adapter->ahw->mbox_aen[i];
@@ -1080,8 +1107,10 @@ int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
cap |= QLC_83XX_FW_CAP_LRO_MSS;
/* set mailbox hdr and capabilities */
- qlcnic_alloc_mbx_args(&cmd, adapter,
- QLCNIC_CMD_CREATE_RX_CTX);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_CREATE_RX_CTX);
+ if (err)
+ return err;
if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))
cmd.req.arg[0] |= (0x3 << 29);
@@ -1239,7 +1268,9 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
mbx.intr_id = 0xffff;
mbx.src = 0;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+ if (err)
+ return err;
if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))
cmd.req.arg[0] |= (0x3 << 29);
@@ -1385,8 +1416,11 @@ int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,
if (state) {
/* Get LED configuration */
- qlcnic_alloc_mbx_args(&cmd, adapter,
- QLCNIC_CMD_GET_LED_CONFIG);
+ status = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_GET_LED_CONFIG);
+ if (status)
+ return status;
+
status = qlcnic_issue_cmd(adapter, &cmd);
if (status) {
dev_err(&adapter->pdev->dev,
@@ -1400,8 +1434,11 @@ int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,
/* Set LED Configuration */
mbx_in = (LSW(QLC_83XX_LED_CONFIG) << 16) |
LSW(QLC_83XX_LED_CONFIG);
- qlcnic_alloc_mbx_args(&cmd, adapter,
- QLCNIC_CMD_SET_LED_CONFIG);
+ status = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_SET_LED_CONFIG);
+ if (status)
+ return status;
+
cmd.req.arg[1] = mbx_in;
cmd.req.arg[2] = mbx_in;
cmd.req.arg[3] = mbx_in;
@@ -1418,8 +1455,11 @@ mbx_err:
} else {
/* Restoring default LED configuration */
- qlcnic_alloc_mbx_args(&cmd, adapter,
- QLCNIC_CMD_SET_LED_CONFIG);
+ status = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_SET_LED_CONFIG);
+ if (status)
+ return status;
+
cmd.req.arg[1] = adapter->ahw->mbox_reg[0];
cmd.req.arg[2] = adapter->ahw->mbox_reg[1];
cmd.req.arg[3] = adapter->ahw->mbox_reg[2];
@@ -1489,10 +1529,18 @@ void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter,
return;
if (enable) {
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INIT_NIC_FUNC);
+ status = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_INIT_NIC_FUNC);
+ if (status)
+ return;
+
cmd.req.arg[1] = BIT_0 | BIT_31;
} else {
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+ status = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_STOP_NIC_FUNC);
+ if (status)
+ return;
+
cmd.req.arg[1] = BIT_0 | BIT_31;
}
status = qlcnic_issue_cmd(adapter, &cmd);
@@ -1509,7 +1557,10 @@ int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter)
struct qlcnic_cmd_args cmd;
int err;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORT_CONFIG);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORT_CONFIG);
+ if (err)
+ return err;
+
cmd.req.arg[1] = adapter->ahw->port_config;
err = qlcnic_issue_cmd(adapter, &cmd);
if (err)
@@ -1523,7 +1574,10 @@ int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter)
struct qlcnic_cmd_args cmd;
int err;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PORT_CONFIG);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PORT_CONFIG);
+ if (err)
+ return err;
+
err = qlcnic_issue_cmd(adapter, &cmd);
if (err)
dev_info(&adapter->pdev->dev, "Get Port config failed\n");
@@ -1539,7 +1593,10 @@ int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *adapter, int enable)
u32 temp;
struct qlcnic_cmd_args cmd;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_EVENT);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_EVENT);
+ if (err)
+ return err;
+
temp = adapter->recv_ctx->context_id << 16;
cmd.req.arg[1] = (enable ? 1 : 0) | BIT_8 | temp;
err = qlcnic_issue_cmd(adapter, &cmd);
@@ -1570,7 +1627,11 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
return -EIO;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
+ if (err)
+ return err;
+
qlcnic_83xx_set_interface_id_promisc(adapter, &temp);
cmd.req.arg[1] = (mode ? 1 : 0) | temp;
err = qlcnic_issue_cmd(adapter, &cmd);
@@ -1588,16 +1649,24 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
struct qlcnic_hardware_context *ahw = adapter->ahw;
int ret = 0, loop = 0, max_sds_rings = adapter->max_sds_rings;
- QLCDB(adapter, DRV, "%s loopback test in progress\n",
- mode == QLCNIC_ILB_MODE ? "internal" : "external");
if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
- dev_warn(&adapter->pdev->dev,
- "Loopback test not supported for non privilege function\n");
+ netdev_warn(netdev,
+ "Loopback test not supported in non privileged mode\n");
return ret;
}
- if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+ netdev_info(netdev, "Device is resetting\n");
return -EBUSY;
+ }
+
+ if (qlcnic_get_diag_lock(adapter)) {
+ netdev_info(netdev, "Device is in diagnostics mode\n");
+ return -EBUSY;
+ }
+
+ netdev_info(netdev, "%s loopback test in progress\n",
+ mode == QLCNIC_ILB_MODE ? "internal" : "external");
ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST,
max_sds_rings);
@@ -1610,13 +1679,19 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
/* Poll for link up event before running traffic */
do {
- msleep(500);
+ msleep(QLC_83XX_LB_MSLEEP_COUNT);
if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
qlcnic_83xx_process_aen(adapter);
- if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
- dev_info(&adapter->pdev->dev,
- "Firmware didn't sent link up event to loopback request\n");
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+ netdev_info(netdev,
+ "Device is resetting, free LB test resources\n");
+ ret = -EIO;
+ goto free_diag_res;
+ }
+ if (loop++ > QLC_83XX_LB_WAIT_COUNT) {
+ netdev_info(netdev,
+ "Firmware didn't sent link up event to loopback request\n");
ret = -QLCNIC_FW_NOT_RESPOND;
qlcnic_83xx_clear_lb_mode(adapter, mode);
goto free_diag_res;
@@ -1638,13 +1713,14 @@ free_diag_res:
fail_diag_alloc:
adapter->max_sds_rings = max_sds_rings;
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ qlcnic_release_diag_lock(adapter);
return ret;
}
int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct net_device *netdev = adapter->netdev;
int status = 0, loop = 0;
u32 config;
@@ -1662,9 +1738,9 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
status = qlcnic_83xx_set_port_config(adapter);
if (status) {
- dev_err(&adapter->pdev->dev,
- "Failed to Set Loopback Mode = 0x%x.\n",
- ahw->port_config);
+ netdev_err(netdev,
+ "Failed to Set Loopback Mode = 0x%x.\n",
+ ahw->port_config);
ahw->port_config = config;
clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
return status;
@@ -1672,13 +1748,19 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
/* Wait for Link and IDC Completion AEN */
do {
- msleep(300);
+ msleep(QLC_83XX_LB_MSLEEP_COUNT);
if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
qlcnic_83xx_process_aen(adapter);
- if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
- dev_err(&adapter->pdev->dev,
- "FW did not generate IDC completion AEN\n");
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+ netdev_info(netdev,
+ "Device is resetting, free LB test resources\n");
+ clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+ return -EIO;
+ }
+ if (loop++ > QLC_83XX_LB_WAIT_COUNT) {
+ netdev_err(netdev,
+ "Did not receive IDC completion AEN\n");
clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
qlcnic_83xx_clear_lb_mode(adapter, mode);
return -EIO;
@@ -1693,6 +1775,7 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct net_device *netdev = adapter->netdev;
int status = 0, loop = 0;
u32 config = ahw->port_config;
@@ -1704,9 +1787,9 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
status = qlcnic_83xx_set_port_config(adapter);
if (status) {
- dev_err(&adapter->pdev->dev,
- "Failed to Clear Loopback Mode = 0x%x.\n",
- ahw->port_config);
+ netdev_err(netdev,
+ "Failed to Clear Loopback Mode = 0x%x.\n",
+ ahw->port_config);
ahw->port_config = config;
clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
return status;
@@ -1714,13 +1797,20 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
/* Wait for Link and IDC Completion AEN */
do {
- msleep(300);
+ msleep(QLC_83XX_LB_MSLEEP_COUNT);
if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
qlcnic_83xx_process_aen(adapter);
- if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
- dev_err(&adapter->pdev->dev,
- "Firmware didn't sent IDC completion AEN\n");
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+ netdev_info(netdev,
+ "Device is resetting, free LB test resources\n");
+ clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+ return -EIO;
+ }
+
+ if (loop++ > QLC_83XX_LB_WAIT_COUNT) {
+ netdev_err(netdev,
+ "Did not receive IDC completion AEN\n");
clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
return -EIO;
}
@@ -1749,7 +1839,11 @@ void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip,
u32 temp = 0, temp_ip;
struct qlcnic_cmd_args cmd;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_IP_ADDR);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_CONFIGURE_IP_ADDR);
+ if (err)
+ return;
+
qlcnic_83xx_set_interface_id_ipaddr(adapter, &temp);
if (mode == QLCNIC_IP_UP)
@@ -1788,7 +1882,10 @@ int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *adapter, int mode)
if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
return 0;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_HW_LRO);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_HW_LRO);
+ if (err)
+ return err;
+
temp = adapter->recv_ctx->context_id << 16;
arg1 = lro_bit_mask | temp;
cmd.req.arg[1] = arg1;
@@ -1810,8 +1907,9 @@ int qlcnic_83xx_config_rss(struct qlcnic_adapter *adapter, int enable)
0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
0x255b0ec26d5a56daULL };
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_RSS);
-
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_RSS);
+ if (err)
+ return err;
/*
* RSS request:
* bits 3-0: Rsvd
@@ -1917,7 +2015,10 @@ int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
struct qlcnic_cmd_args cmd;
u32 mac_low, mac_high;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+ if (err)
+ return err;
+
qlcnic_83xx_configure_mac(adapter, mac, QLCNIC_GET_CURRENT_MAC, &cmd);
err = qlcnic_issue_cmd(adapter, &cmd);
@@ -1948,7 +2049,10 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
return;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);
+ if (err)
+ return;
+
if (coal->type == QLCNIC_INTR_COAL_TYPE_RX) {
temp = adapter->recv_ctx->context_id;
cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_RX | temp << 16;
@@ -2020,7 +2124,10 @@ int qlcnic_enable_eswitch(struct qlcnic_adapter *adapter, u8 port, u8 enable)
return err;
}
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH);
+ if (err)
+ return err;
+
cmd.req.arg[1] = (port & 0xf) | BIT_4;
err = qlcnic_issue_cmd(adapter, &cmd);
@@ -2048,7 +2155,10 @@ int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *adapter,
return err;
}
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+ if (err)
+ return err;
+
cmd.req.arg[1] = (nic->pci_func << 16);
cmd.req.arg[2] = 0x1 << 16;
cmd.req.arg[3] = nic->phys_port | (nic->switch_mode << 16);
@@ -2079,13 +2189,17 @@ int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *adapter,
u32 temp;
u8 op = 0;
struct qlcnic_cmd_args cmd;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
- if (func_id != adapter->ahw->pci_func) {
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+ if (err)
+ return err;
+
+ if (func_id != ahw->pci_func) {
temp = func_id << 16;
cmd.req.arg[1] = op | BIT_31 | temp;
} else {
- cmd.req.arg[1] = adapter->ahw->pci_func << 16;
+ cmd.req.arg[1] = ahw->pci_func << 16;
}
err = qlcnic_issue_cmd(adapter, &cmd);
if (err) {
@@ -2112,6 +2226,9 @@ int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *adapter,
temp = (cmd.rsp.arg[8] & 0x7FFE0000) >> 17;
npar_info->max_linkspeed_reg_offset = temp;
}
+ if (npar_info->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS)
+ memcpy(ahw->extra_capability, &cmd.rsp.arg[16],
+ sizeof(ahw->extra_capability));
out:
qlcnic_free_mbx_args(&cmd);
@@ -2121,26 +2238,28 @@ out:
int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
struct qlcnic_pci_info *pci_info)
{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct device *dev = &adapter->pdev->dev;
+ struct qlcnic_cmd_args cmd;
int i, err = 0, j = 0;
u32 temp;
- struct qlcnic_cmd_args cmd;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+ if (err)
+ return err;
+
err = qlcnic_issue_cmd(adapter, &cmd);
- adapter->ahw->act_pci_func = 0;
+ ahw->act_pci_func = 0;
if (err == QLCNIC_RCODE_SUCCESS) {
- pci_info->func_count = cmd.rsp.arg[1] & 0xFF;
- dev_info(&adapter->pdev->dev,
- "%s: total functions = %d\n",
- __func__, pci_info->func_count);
+ ahw->max_pci_func = cmd.rsp.arg[1] & 0xFF;
for (i = 2, j = 0; j < QLCNIC_MAX_PCI_FUNC; j++, pci_info++) {
pci_info->id = cmd.rsp.arg[i] & 0xFFFF;
pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
i++;
pci_info->type = cmd.rsp.arg[i] & 0xFFFF;
if (pci_info->type == QLCNIC_TYPE_NIC)
- adapter->ahw->act_pci_func++;
+ ahw->act_pci_func++;
temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
pci_info->default_port = temp;
i++;
@@ -2152,18 +2271,21 @@ int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
i++;
memcpy(pci_info->mac + sizeof(u32), &cmd.rsp.arg[i], 2);
i = i + 3;
-
- dev_info(&adapter->pdev->dev, "%s:\n"
- "\tid = %d active = %d type = %d\n"
- "\tport = %d min bw = %d max bw = %d\n"
- "\tmac_addr = %pM\n", __func__,
- pci_info->id, pci_info->active, pci_info->type,
- pci_info->default_port, pci_info->tx_min_bw,
- pci_info->tx_max_bw, pci_info->mac);
+ if (ahw->op_mode == QLCNIC_MGMT_FUNC)
+ dev_info(dev, "id = %d active = %d type = %d\n"
+ "\tport = %d min bw = %d max bw = %d\n"
+ "\tmac_addr = %pM\n", pci_info->id,
+ pci_info->active, pci_info->type,
+ pci_info->default_port,
+ pci_info->tx_min_bw,
+ pci_info->tx_max_bw, pci_info->mac);
}
+ if (ahw->op_mode == QLCNIC_MGMT_FUNC)
+ dev_info(dev, "Max vNIC functions = %d, active vNIC functions = %d\n",
+ ahw->max_pci_func, ahw->act_pci_func);
+
} else {
- dev_err(&adapter->pdev->dev, "Failed to get PCI Info%d\n",
- err);
+ dev_err(dev, "Failed to get PCI Info, error = %d\n", err);
err = -EIO;
}
@@ -2180,7 +2302,10 @@ int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type)
struct qlcnic_cmd_args cmd;
max_ints = adapter->ahw->num_msix - 1;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT);
+ if (err)
+ return err;
+
cmd.req.arg[1] = max_ints;
if (qlcnic_sriov_vf_check(adapter))
@@ -2808,7 +2933,11 @@ int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
dev_info(&adapter->pdev->dev, "link state down\n");
return config;
}
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_STATUS);
+
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_STATUS);
+ if (err)
+ return err;
+
err = qlcnic_issue_cmd(adapter, &cmd);
if (err) {
dev_info(&adapter->pdev->dev,
@@ -3034,7 +3163,9 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
struct net_device *netdev = adapter->netdev;
int ret = 0;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);
+ ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);
+ if (ret)
+ return;
/* Get Tx stats */
cmd.req.arg[1] = BIT_1 | (adapter->tx_ring->ctx_id << 16);
cmd.rsp.num = QLC_83XX_TX_STAT_REGS;
@@ -3113,8 +3244,10 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev)
u8 val;
int ret, max_sds_rings = adapter->max_sds_rings;
- if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
- return -EIO;
+ if (qlcnic_get_diag_lock(adapter)) {
+ netdev_info(netdev, "Device in diagnostics mode\n");
+ return -EBUSY;
+ }
ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST,
max_sds_rings);
@@ -3122,7 +3255,9 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev)
goto fail_diag_irq;
ahw->diag_cnt = 0;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+ ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+ if (ret)
+ goto fail_diag_irq;
if (adapter->flags & QLCNIC_MSIX_ENABLED)
intrpt_id = ahw->intr_tbl[0].id;
@@ -3156,7 +3291,7 @@ done:
fail_diag_irq:
adapter->max_sds_rings = max_sds_rings;
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ qlcnic_release_diag_lock(adapter);
return ret;
}
@@ -3260,3 +3395,54 @@ int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)
}
return 0;
}
+
+int qlcnic_83xx_shutdown(struct pci_dev *pdev)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+ int retval;
+
+ netif_device_detach(netdev);
+ qlcnic_cancel_idc_work(adapter);
+
+ if (netif_running(netdev))
+ qlcnic_down(adapter, netdev);
+
+ qlcnic_83xx_disable_mbx_intr(adapter);
+ cancel_delayed_work_sync(&adapter->idc_aen_work);
+
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+int qlcnic_83xx_resume(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlc_83xx_idc *idc = &ahw->idc;
+ int err = 0;
+
+ err = qlcnic_83xx_idc_init(adapter);
+ if (err)
+ return err;
+
+ if (ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) {
+ if (ahw->op_mode == QLCNIC_MGMT_FUNC) {
+ qlcnic_83xx_set_vnic_opmode(adapter);
+ } else {
+ err = qlcnic_83xx_check_vnic_state(adapter);
+ if (err)
+ return err;
+ }
+ }
+
+ err = qlcnic_83xx_idc_reattach_driver(adapter);
+ if (err)
+ return err;
+
+ qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,
+ idc->delay);
+ return err;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index f5db67fc9f55..2548d1403d75 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -36,7 +36,8 @@
#define QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT 3
#define QLC_83XX_DRV_LOCK_RECOVERY_DELAY 200
#define QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK 0x3
-
+#define QLC_83XX_LB_WAIT_COUNT 250
+#define QLC_83XX_LB_MSLEEP_COUNT 20
#define QLC_83XX_NO_NIC_RESOURCE 0x5
#define QLC_83XX_MAC_PRESENT 0xC
#define QLC_83XX_MAC_ABSENT 0xD
@@ -314,6 +315,7 @@ struct qlc_83xx_idc {
u8 vnic_state;
u8 vnic_wait_limit;
u8 quiesce_req;
+ u8 delay_reset;
char **name;
};
@@ -392,6 +394,8 @@ enum qlcnic_83xx_states {
#define QLC_83XX_LB_MAX_FILTERS 2048
#define QLC_83XX_LB_BUCKET_SIZE 256
#define QLC_83XX_MINIMUM_VECTOR 3
+#define QLC_83XX_MAX_MC_COUNT 38
+#define QLC_83XX_MAX_UC_COUNT 4096
#define QLC_83XX_GET_FUNC_MODE_FROM_NPAR_INFO(val) (val & 0x80000000)
#define QLC_83XX_GET_LRO_CAPABILITY(val) (val & 0x20)
@@ -623,4 +627,11 @@ u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *);
u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *, u32 *);
void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *);
void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *);
+void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *);
+int qlcnic_83xx_shutdown(struct pci_dev *);
+int qlcnic_83xx_resume(struct qlcnic_adapter *);
+int qlcnic_83xx_idc_init(struct qlcnic_adapter *);
+int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *);
+int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *);
#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index 5e7fb1dfb97b..f41dfab1e9a3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -606,7 +606,7 @@ static int qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter *adapter)
return 0;
}
-static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
+int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
{
int err;
@@ -629,6 +629,7 @@ static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
return -EIO;
}
+ qlcnic_set_drv_version(adapter);
qlcnic_83xx_idc_attach_driver(adapter);
return 0;
@@ -649,6 +650,7 @@ static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
ahw->idc.collect_dump = 0;
ahw->reset_context = 0;
adapter->tx_timeo_cnt = 0;
+ ahw->idc.delay_reset = 0;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
}
@@ -883,21 +885,41 @@ static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
int ret = 0;
if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
- qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
set_bit(__QLCNIC_RESETTING, &adapter->state);
clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
qlcnic_83xx_disable_vnic_mode(adapter, 1);
- qlcnic_83xx_idc_detach_driver(adapter);
+
+ if (qlcnic_check_diag_status(adapter)) {
+ dev_info(&adapter->pdev->dev,
+ "%s: Wait for diag completion\n", __func__);
+ adapter->ahw->idc.delay_reset = 1;
+ return 0;
+ } else {
+ qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+ qlcnic_83xx_idc_detach_driver(adapter);
+ }
}
- /* Check ACK from other functions */
- ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
- if (ret) {
+ if (qlcnic_check_diag_status(adapter)) {
dev_info(&adapter->pdev->dev,
- "%s: Waiting for reset ACK\n", __func__);
- return 0;
+ "%s: Wait for diag completion\n", __func__);
+ return -1;
+ } else {
+ if (adapter->ahw->idc.delay_reset) {
+ qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+ qlcnic_83xx_idc_detach_driver(adapter);
+ adapter->ahw->idc.delay_reset = 0;
+ }
+
+ /* Check for ACK from other functions */
+ ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
+ if (ret) {
+ dev_info(&adapter->pdev->dev,
+ "%s: Waiting for reset ACK\n", __func__);
+ return -1;
+ }
}
/* Transit to INIT state and restart the HW */
@@ -1113,7 +1135,7 @@ qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter *adapter)
return 0;
}
-static int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
+int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
{
int ret = -EIO;
@@ -1532,9 +1554,18 @@ static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev)
int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
{
- u8 *p_buff;
- u32 addr, count;
struct qlcnic_hardware_context *ahw = p_dev->ahw;
+ u32 addr, count, prev_ver, curr_ver;
+ u8 *p_buff;
+
+ if (ahw->reset.buff != NULL) {
+ prev_ver = p_dev->fw_version;
+ curr_ver = qlcnic_83xx_get_fw_version(p_dev);
+ if (curr_ver > prev_ver)
+ kfree(ahw->reset.buff);
+ else
+ return 0;
+ }
ahw->reset.seq_error = 0;
ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
@@ -2062,7 +2093,11 @@ static void qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter)
audit_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT);
if (IS_QLC_83XX_USED(adapter, presence_mask, audit_mask)) {
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+ status = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_STOP_NIC_FUNC);
+ if (status)
+ return;
+
cmd.req.arg[1] = BIT_31;
status = qlcnic_issue_cmd(adapter, &cmd);
if (status)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
index b0c3de9ede03..599d1fda52f2 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
@@ -39,30 +39,21 @@ int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
return 0;
}
-static int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
+int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
{
u8 id;
- int i, ret = -EBUSY;
+ int ret = -EBUSY;
u32 data = QLCNIC_MGMT_FUNC;
struct qlcnic_hardware_context *ahw = adapter->ahw;
if (qlcnic_83xx_lock_driver(adapter))
return ret;
- if (qlcnic_config_npars) {
- for (i = 0; i < ahw->act_pci_func; i++) {
- id = adapter->npars[i].pci_func;
- if (id == ahw->pci_func)
- continue;
- data |= qlcnic_config_npars &
- QLC_83XX_SET_FUNC_OPMODE(0x3, id);
- }
- } else {
- data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
- data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, ahw->pci_func)) |
- QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC,
- ahw->pci_func);
- }
+ id = ahw->pci_func;
+ data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+ data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, id)) |
+ QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC, id);
+
QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data);
qlcnic_83xx_unlock_driver(adapter);
@@ -196,20 +187,24 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
else
priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
ahw->pci_func);
-
- if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+ switch (priv_level) {
+ case QLCNIC_NON_PRIV_FUNC:
ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic;
- } else if (priv_level == QLCNIC_PRIV_FUNC) {
+ break;
+ case QLCNIC_PRIV_FUNC:
ahw->op_mode = QLCNIC_PRIV_FUNC;
ahw->idc.state_entry = qlcnic_83xx_idc_vnic_pf_entry;
nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic;
- } else if (priv_level == QLCNIC_MGMT_FUNC) {
+ break;
+ case QLCNIC_MGMT_FUNC:
ahw->op_mode = QLCNIC_MGMT_FUNC;
ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic;
- } else {
+ break;
+ default:
+ dev_err(&adapter->pdev->dev, "Invalid Virtual NIC opmode\n");
return -EIO;
}
@@ -218,8 +213,29 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
else
adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
- adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
- adapter->ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+ ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+ ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+
+ return 0;
+}
+
+int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlc_83xx_idc *idc = &ahw->idc;
+ u32 state;
+
+ state = QLCRDX(ahw, QLC_83XX_VNIC_STATE);
+ while (state != QLCNIC_DEV_NPAR_OPER && idc->vnic_wait_limit--) {
+ msleep(1000);
+ state = QLCRDX(ahw, QLC_83XX_VNIC_STATE);
+ }
+
+ if (!idc->vnic_wait_limit) {
+ dev_err(&adapter->pdev->dev,
+ "vNIC mode not operational, state check timed out.\n");
+ return -EIO;
+ }
return 0;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index 6acf82b9f018..0581a484ceb5 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -36,7 +36,8 @@ static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
{QLCNIC_CMD_CONFIG_PORT, 4, 1},
{QLCNIC_CMD_TEMP_SIZE, 4, 4},
{QLCNIC_CMD_GET_TEMP_HDR, 4, 1},
- {QLCNIC_CMD_SET_DRV_VER, 4, 1},
+ {QLCNIC_CMD_82XX_SET_DRV_VER, 4, 1},
+ {QLCNIC_CMD_GET_LED_STATUS, 4, 2},
};
static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw)
@@ -181,7 +182,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
return cmd->rsp.arg[0];
}
-int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter)
+int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter, u32 fw_cmd)
{
struct qlcnic_cmd_args cmd;
u32 arg1, arg2, arg3;
@@ -193,7 +194,10 @@ int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter)
_QLCNIC_LINUX_MAJOR, _QLCNIC_LINUX_MINOR,
_QLCNIC_LINUX_SUBVERSION);
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_DRV_VER);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, fw_cmd);
+ if (err)
+ return err;
+
memcpy(&arg1, drv_string, sizeof(u32));
memcpy(&arg2, drv_string + 4, sizeof(u32));
memcpy(&arg3, drv_string + 8, sizeof(u32));
@@ -221,7 +225,10 @@ qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
if (recv_ctx->state != QLCNIC_HOST_CTX_STATE_ACTIVE)
return err;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_MTU);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_MTU);
+ if (err)
+ return err;
+
cmd.req.arg[1] = recv_ctx->context_id;
cmd.req.arg[2] = mtu;
@@ -335,7 +342,10 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
}
phys_addr = hostrq_phys_addr;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_RX_CTX);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_RX_CTX);
+ if (err)
+ goto out_free_rsp;
+
cmd.req.arg[1] = MSD(phys_addr);
cmd.req.arg[2] = LSD(phys_addr);
cmd.req.arg[3] = rq_size;
@@ -373,10 +383,10 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
recv_ctx->context_id = le16_to_cpu(prsp->context_id);
recv_ctx->virt_port = prsp->virt_port;
+ qlcnic_free_mbx_args(&cmd);
out_free_rsp:
dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp,
- cardrsp_phys_addr);
- qlcnic_free_mbx_args(&cmd);
+ cardrsp_phys_addr);
out_free_rq:
dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr);
return err;
@@ -388,7 +398,10 @@ void qlcnic_82xx_fw_cmd_del_rx_ctx(struct qlcnic_adapter *adapter)
struct qlcnic_cmd_args cmd;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX);
+ if (err)
+ return;
+
cmd.req.arg[1] = recv_ctx->context_id;
err = qlcnic_issue_cmd(adapter, &cmd);
if (err)
@@ -457,7 +470,10 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
phys_addr = rq_phys_addr;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+ if (err)
+ goto out_free_rsp;
+
cmd.req.arg[1] = MSD(phys_addr);
cmd.req.arg[2] = LSD(phys_addr);
cmd.req.arg[3] = rq_size;
@@ -473,12 +489,13 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
err = -EIO;
}
+ qlcnic_free_mbx_args(&cmd);
+
+out_free_rsp:
dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr,
rsp_phys_addr);
-
out_free_rq:
dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr);
- qlcnic_free_mbx_args(&cmd);
return err;
}
@@ -487,8 +504,11 @@ void qlcnic_82xx_fw_cmd_del_tx_ctx(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring)
{
struct qlcnic_cmd_args cmd;
+ int ret;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX);
+ ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX);
+ if (ret)
+ return;
cmd.req.arg[1] = tx_ring->ctx_id;
if (qlcnic_issue_cmd(adapter, &cmd))
@@ -503,7 +523,10 @@ qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config)
int err;
struct qlcnic_cmd_args cmd;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_PORT);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_PORT);
+ if (err)
+ return err;
+
cmd.req.arg[1] = config;
err = qlcnic_issue_cmd(adapter, &cmd);
qlcnic_free_mbx_args(&cmd);
@@ -707,7 +730,10 @@ int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
struct qlcnic_cmd_args cmd;
u32 mac_low, mac_high;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+ if (err)
+ return err;
+
cmd.req.arg[1] = adapter->ahw->pci_func | BIT_8;
err = qlcnic_issue_cmd(adapter, &cmd);
@@ -746,7 +772,10 @@ int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter,
nic_info = nic_info_addr;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+ if (err)
+ goto out_free_dma;
+
cmd.req.arg[1] = MSD(nic_dma_t);
cmd.req.arg[2] = LSD(nic_dma_t);
cmd.req.arg[3] = (func_id << 16 | nic_size);
@@ -768,9 +797,10 @@ int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter,
npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
}
+ qlcnic_free_mbx_args(&cmd);
+out_free_dma:
dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
nic_dma_t);
- qlcnic_free_mbx_args(&cmd);
return err;
}
@@ -807,7 +837,10 @@ int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter,
nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+ if (err)
+ goto out_free_dma;
+
cmd.req.arg[1] = MSD(nic_dma_t);
cmd.req.arg[2] = LSD(nic_dma_t);
cmd.req.arg[3] = ((nic->pci_func << 16) | nic_size);
@@ -819,9 +852,10 @@ int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter,
err = -EIO;
}
- dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
- nic_dma_t);
qlcnic_free_mbx_args(&cmd);
+out_free_dma:
+ dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
+ nic_dma_t);
return err;
}
@@ -845,7 +879,10 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,
return -ENOMEM;
npar = pci_info_addr;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+ if (err)
+ goto out_free_dma;
+
cmd.req.arg[1] = MSD(pci_info_dma_t);
cmd.req.arg[2] = LSD(pci_info_dma_t);
cmd.req.arg[3] = pci_size;
@@ -873,20 +910,22 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,
err = -EIO;
}
+ qlcnic_free_mbx_args(&cmd);
+out_free_dma:
dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr,
pci_info_dma_t);
- qlcnic_free_mbx_args(&cmd);
return err;
}
/* Configure eSwitch for port mirroring */
int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
- u8 enable_mirroring, u8 pci_func)
+ u8 enable_mirroring, u8 pci_func)
{
+ struct device *dev = &adapter->pdev->dev;
+ struct qlcnic_cmd_args cmd;
int err = -EIO;
u32 arg1;
- struct qlcnic_cmd_args cmd;
if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC ||
!(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
@@ -895,18 +934,20 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
arg1 = id | (enable_mirroring ? BIT_4 : 0);
arg1 |= pci_func << 8;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORTMIRRORING);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_SET_PORTMIRRORING);
+ if (err)
+ return err;
+
cmd.req.arg[1] = arg1;
err = qlcnic_issue_cmd(adapter, &cmd);
if (err != QLCNIC_RCODE_SUCCESS)
- dev_err(&adapter->pdev->dev,
- "Failed to configure port mirroring%d on eswitch:%d\n",
+ dev_err(dev, "Failed to configure port mirroring for vNIC function %d on eSwitch %d\n",
pci_func, id);
else
- dev_info(&adapter->pdev->dev,
- "Configured eSwitch %d for port mirroring:%d\n",
- id, pci_func);
+ dev_info(dev, "Configured port mirroring for vNIC function %d on eSwitch %d\n",
+ pci_func, id);
qlcnic_free_mbx_args(&cmd);
return err;
@@ -941,7 +982,11 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
arg1 |= rx_tx << 15 | stats_size << 16;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_GET_ESWITCH_STATS);
+ if (err)
+ goto out_free_dma;
+
cmd.req.arg[1] = arg1;
cmd.req.arg[2] = MSD(stats_dma_t);
cmd.req.arg[3] = LSD(stats_dma_t);
@@ -963,9 +1008,10 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
esw_stats->numbytes = le64_to_cpu(stats->numbytes);
}
- dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
- stats_dma_t);
qlcnic_free_mbx_args(&cmd);
+out_free_dma:
+ dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
+ stats_dma_t);
return err;
}
@@ -989,7 +1035,10 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
if (!stats_addr)
return -ENOMEM;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_MAC_STATS);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_MAC_STATS);
+ if (err)
+ goto out_free_dma;
+
cmd.req.arg[1] = stats_size << 16;
cmd.req.arg[2] = MSD(stats_dma_t);
cmd.req.arg[3] = LSD(stats_dma_t);
@@ -1020,11 +1069,12 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
"%s: Get mac stats failed, err=%d.\n", __func__, err);
}
- dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
- stats_dma_t);
-
qlcnic_free_mbx_args(&cmd);
+out_free_dma:
+ dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
+ stats_dma_t);
+
return err;
}
@@ -1108,7 +1158,11 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
arg1 |= BIT_14 | rx_tx << 15;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_GET_ESWITCH_STATS);
+ if (err)
+ return err;
+
cmd.req.arg[1] = arg1;
err = qlcnic_issue_cmd(adapter, &cmd);
qlcnic_free_mbx_args(&cmd);
@@ -1121,17 +1175,19 @@ err_ret:
return -EIO;
}
-static int
-__qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
- u32 *arg1, u32 *arg2)
+static int __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
+ u32 *arg1, u32 *arg2)
{
- int err = -EIO;
+ struct device *dev = &adapter->pdev->dev;
struct qlcnic_cmd_args cmd;
- u8 pci_func;
- pci_func = (*arg1 >> 8);
+ u8 pci_func = *arg1 >> 8;
+ int err;
+
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG);
+ if (err)
+ return err;
- qlcnic_alloc_mbx_args(&cmd, adapter,
- QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG);
cmd.req.arg[1] = *arg1;
err = qlcnic_issue_cmd(adapter, &cmd);
*arg1 = cmd.rsp.arg[1];
@@ -1139,12 +1195,11 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
qlcnic_free_mbx_args(&cmd);
if (err == QLCNIC_RCODE_SUCCESS)
- dev_info(&adapter->pdev->dev,
- "eSwitch port config for pci func %d\n", pci_func);
+ dev_info(dev, "Get eSwitch port config for vNIC function %d\n",
+ pci_func);
else
- dev_err(&adapter->pdev->dev,
- "Failed to get eswitch port config for pci func %d\n",
- pci_func);
+ dev_err(dev, "Failed to get eswitch port config for vNIC function %d\n",
+ pci_func);
return err;
}
/* Configure eSwitch port
@@ -1157,9 +1212,10 @@ op_type = 1 for port vlan_id
int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
struct qlcnic_esw_func_cfg *esw_cfg)
{
+ struct device *dev = &adapter->pdev->dev;
+ struct qlcnic_cmd_args cmd;
int err = -EIO, index;
u32 arg1, arg2 = 0;
- struct qlcnic_cmd_args cmd;
u8 pci_func;
if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
@@ -1209,18 +1265,22 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
return err;
}
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_ESWITCH);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_CONFIGURE_ESWITCH);
+ if (err)
+ return err;
+
cmd.req.arg[1] = arg1;
cmd.req.arg[2] = arg2;
err = qlcnic_issue_cmd(adapter, &cmd);
qlcnic_free_mbx_args(&cmd);
if (err != QLCNIC_RCODE_SUCCESS)
- dev_err(&adapter->pdev->dev,
- "Failed to configure eswitch pci func %d\n", pci_func);
+ dev_err(dev, "Failed to configure eswitch for vNIC function %d\n",
+ pci_func);
else
- dev_info(&adapter->pdev->dev,
- "Configured eSwitch for pci func %d\n", pci_func);
+ dev_info(dev, "Configured eSwitch for vNIC function %d\n",
+ pci_func);
return err;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index f67652de5a63..700a46324d09 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -846,7 +846,9 @@ static int qlcnic_irq_test(struct net_device *netdev)
goto clear_diag_irq;
ahw->diag_cnt = 0;
- qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+ ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+ if (ret)
+ goto free_diag_res;
cmd.req.arg[1] = ahw->pci_func;
ret = qlcnic_issue_cmd(adapter, &cmd);
@@ -858,6 +860,8 @@ static int qlcnic_irq_test(struct net_device *netdev)
done:
qlcnic_free_mbx_args(&cmd);
+
+free_diag_res:
qlcnic_diag_free_res(netdev, max_sds_rings);
clear_diag_irq:
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
index c0f0c0d0a790..d262211b03b3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
@@ -672,6 +672,7 @@ enum {
#define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT 10
#define QLCNIC_MAX_MC_COUNT 38
+#define QLCNIC_MAX_UC_COUNT 512
#define QLCNIC_WATCHDOG_TIMEOUTVALUE 5
#define ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 106a12f2a02f..5b5d2edf125d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -499,6 +499,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
struct netdev_hw_addr *ha;
static const u8 bcast_addr[ETH_ALEN] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
@@ -515,25 +516,30 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
if (netdev->flags & IFF_PROMISC) {
if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
mode = VPORT_MISS_MODE_ACCEPT_ALL;
- goto send_fw_cmd;
- }
-
- if ((netdev->flags & IFF_ALLMULTI) ||
- (netdev_mc_count(netdev) > adapter->ahw->max_mc_count)) {
- mode = VPORT_MISS_MODE_ACCEPT_MULTI;
- goto send_fw_cmd;
+ } else if (netdev->flags & IFF_ALLMULTI) {
+ if (netdev_mc_count(netdev) > ahw->max_mc_count) {
+ mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+ } else if (!netdev_mc_empty(netdev) &&
+ !qlcnic_sriov_vf_check(adapter)) {
+ netdev_for_each_mc_addr(ha, netdev)
+ qlcnic_nic_add_mac(adapter, ha->addr,
+ vlan);
+ }
+ if (mode != VPORT_MISS_MODE_ACCEPT_MULTI &&
+ qlcnic_sriov_vf_check(adapter))
+ qlcnic_vf_add_mc_list(netdev, vlan);
}
- if (!netdev_mc_empty(netdev) && !qlcnic_sriov_vf_check(adapter)) {
- netdev_for_each_mc_addr(ha, netdev) {
+ /* configure unicast MAC address, if there is not sufficient space
+ * to store all the unicast addresses then enable promiscuous mode
+ */
+ if (netdev_uc_count(netdev) > ahw->max_uc_count) {
+ mode = VPORT_MISS_MODE_ACCEPT_ALL;
+ } else if (!netdev_uc_empty(netdev)) {
+ netdev_for_each_uc_addr(ha, netdev)
qlcnic_nic_add_mac(adapter, ha->addr, vlan);
- }
}
- if (qlcnic_sriov_vf_check(adapter))
- qlcnic_vf_add_mc_list(netdev, vlan);
-
-send_fw_cmd:
if (!qlcnic_sriov_vf_check(adapter)) {
if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
!adapter->fdb_mac_learn) {
@@ -780,7 +786,8 @@ int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
word = 0;
if (enable) {
word = QLCNIC_ENABLE_IPV4_LRO | QLCNIC_NO_DEST_IPV4_CHECK;
- if (adapter->ahw->capabilities2 & QLCNIC_FW_CAP2_HW_LRO_IPV6)
+ if (adapter->ahw->extra_capability[0] &
+ QLCNIC_FW_CAP2_HW_LRO_IPV6)
word |= QLCNIC_ENABLE_IPV6_LRO |
QLCNIC_NO_DEST_IPV6_CHECK;
}
@@ -1503,6 +1510,21 @@ int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
return rv;
}
+int qlcnic_get_beacon_state(struct qlcnic_adapter *adapter, u8 *h_state)
+{
+ struct qlcnic_cmd_args cmd;
+ int err;
+
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_STATUS);
+ if (!err) {
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (!err)
+ *h_state = cmd.rsp.arg[1];
+ }
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
{
void __iomem *msix_base_addr;
@@ -1555,3 +1577,54 @@ void qlcnic_82xx_api_unlock(struct qlcnic_adapter *adapter)
{
qlcnic_pcie_sem_unlock(adapter, 5);
}
+
+int qlcnic_82xx_shutdown(struct pci_dev *pdev)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+ int retval;
+
+ netif_device_detach(netdev);
+
+ qlcnic_cancel_idc_work(adapter);
+
+ if (netif_running(netdev))
+ qlcnic_down(adapter, netdev);
+
+ qlcnic_clr_all_drv_state(adapter, 0);
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+
+ if (qlcnic_wol_supported(adapter)) {
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ }
+
+ return 0;
+}
+
+int qlcnic_82xx_resume(struct qlcnic_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int err;
+
+ err = qlcnic_start_firmware(adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev, "failed to start firmware\n");
+ return err;
+ }
+
+ if (netif_running(netdev)) {
+ err = qlcnic_up(adapter, netdev);
+ if (!err)
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+ }
+
+ netif_device_attach(netdev);
+ qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+ return err;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index b6818f4356b9..2c22504f57aa 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -86,7 +86,8 @@ enum qlcnic_regs {
#define QLCNIC_CMD_BC_EVENT_SETUP 0x31
#define QLCNIC_CMD_CONFIG_VPORT 0x32
#define QLCNIC_CMD_GET_MAC_STATS 0x37
-#define QLCNIC_CMD_SET_DRV_VER 0x38
+#define QLCNIC_CMD_82XX_SET_DRV_VER 0x38
+#define QLCNIC_CMD_GET_LED_STATUS 0x3C
#define QLCNIC_CMD_CONFIGURE_RSS 0x41
#define QLCNIC_CMD_CONFIG_INTR_COAL 0x43
#define QLCNIC_CMD_CONFIGURE_LED 0x44
@@ -102,6 +103,7 @@ enum qlcnic_regs {
#define QLCNIC_CMD_GET_LINK_STATUS 0x68
#define QLCNIC_CMD_SET_LED_CONFIG 0x69
#define QLCNIC_CMD_GET_LED_CONFIG 0x6A
+#define QLCNIC_CMD_83XX_SET_DRV_VER 0x6F
#define QLCNIC_CMD_ADD_RCV_RINGS 0x0B
#define QLCNIC_INTRPT_INTX 1
@@ -197,4 +199,8 @@ void qlcnic_82xx_api_unlock(struct qlcnic_adapter *);
void qlcnic_82xx_napi_enable(struct qlcnic_adapter *);
void qlcnic_82xx_napi_disable(struct qlcnic_adapter *);
void qlcnic_82xx_napi_del(struct qlcnic_adapter *);
+int qlcnic_82xx_shutdown(struct pci_dev *);
+int qlcnic_82xx_resume(struct qlcnic_adapter *);
+void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed);
+void qlcnic_fw_poll_work(struct work_struct *work);
#endif /* __QLCNIC_HW_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index aeb26a850679..4528f8ec333b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -52,10 +52,6 @@ int qlcnic_load_fw_file;
MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file)");
module_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444);
-int qlcnic_config_npars;
-module_param(qlcnic_config_npars, int, 0444);
-MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled)");
-
static int qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void qlcnic_remove(struct pci_dev *pdev);
static int qlcnic_open(struct net_device *netdev);
@@ -63,13 +59,11 @@ static int qlcnic_close(struct net_device *netdev);
static void qlcnic_tx_timeout(struct net_device *netdev);
static void qlcnic_attach_work(struct work_struct *work);
static void qlcnic_fwinit_work(struct work_struct *work);
-static void qlcnic_fw_poll_work(struct work_struct *work);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void qlcnic_poll_controller(struct net_device *netdev);
#endif
static void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
-static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8);
static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
@@ -364,12 +358,15 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
return ndo_dflt_fdb_del(ndm, tb, netdev, addr);
if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
- if (is_unicast_ether_addr(addr))
- err = qlcnic_nic_del_mac(adapter, addr);
- else if (is_multicast_ether_addr(addr))
+ if (is_unicast_ether_addr(addr)) {
+ err = dev_uc_del(netdev, addr);
+ if (!err)
+ err = qlcnic_nic_del_mac(adapter, addr);
+ } else if (is_multicast_ether_addr(addr)) {
err = dev_mc_del(netdev, addr);
- else
+ } else {
err = -EINVAL;
+ }
}
return err;
}
@@ -392,12 +389,16 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
if (ether_addr_equal(addr, adapter->mac_addr))
return err;
- if (is_unicast_ether_addr(addr))
- err = qlcnic_nic_add_mac(adapter, addr, 0);
- else if (is_multicast_ether_addr(addr))
+ if (is_unicast_ether_addr(addr)) {
+ if (netdev_uc_count(netdev) < adapter->ahw->max_uc_count)
+ err = dev_uc_add_excl(netdev, addr);
+ else
+ err = -ENOMEM;
+ } else if (is_multicast_ether_addr(addr)) {
err = dev_mc_add_excl(netdev, addr);
- else
+ } else {
err = -EINVAL;
+ }
return err;
}
@@ -449,6 +450,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_set_vf_tx_rate = qlcnic_sriov_set_vf_tx_rate,
.ndo_get_vf_config = qlcnic_sriov_get_vf_config,
.ndo_set_vf_vlan = qlcnic_sriov_set_vf_vlan,
+ .ndo_set_vf_spoofchk = qlcnic_sriov_set_vf_spoofchk,
#endif
};
@@ -465,6 +467,8 @@ static struct qlcnic_nic_template qlcnic_ops = {
.napi_add = qlcnic_82xx_napi_add,
.napi_del = qlcnic_82xx_napi_del,
.config_ipaddr = qlcnic_82xx_config_ipaddr,
+ .shutdown = qlcnic_82xx_shutdown,
+ .resume = qlcnic_82xx_resume,
.clear_legacy_intr = qlcnic_82xx_clear_legacy_intr,
};
@@ -508,6 +512,7 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
.config_promisc_mode = qlcnic_82xx_nic_set_promisc,
.change_l2_filter = qlcnic_82xx_change_filter,
.get_board_info = qlcnic_82xx_get_board_info,
+ .set_mac_filter_count = qlcnic_82xx_set_mac_filter_count,
.free_mac_list = qlcnic_82xx_free_mac_list,
};
@@ -768,7 +773,7 @@ static int
qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
{
u8 id;
- int i, ret = 1;
+ int ret;
u32 data = QLCNIC_MGMT_FUNC;
struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -776,20 +781,10 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
if (ret)
goto err_lock;
- if (qlcnic_config_npars) {
- for (i = 0; i < ahw->act_pci_func; i++) {
- id = adapter->npars[i].pci_func;
- if (id == ahw->pci_func)
- continue;
- data |= (qlcnic_config_npars &
- QLC_DEV_SET_DRV(0xf, id));
- }
- } else {
- data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
- data = (data & ~QLC_DEV_SET_DRV(0xf, ahw->pci_func)) |
- (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
- ahw->pci_func));
- }
+ id = ahw->pci_func;
+ data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
+ data = (data & ~QLC_DEV_SET_DRV(0xf, id)) |
+ QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, id);
QLC_SHARED_REG_WR32(adapter, QLCNIC_DRV_OP_MODE, data);
qlcnic_api_unlock(adapter);
err_lock:
@@ -875,6 +870,27 @@ static int qlcnic_setup_pci_map(struct pci_dev *pdev,
return 0;
}
+static inline bool qlcnic_validate_subsystem_id(struct qlcnic_adapter *adapter,
+ int index)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned short subsystem_vendor;
+ bool ret = true;
+
+ subsystem_vendor = pdev->subsystem_vendor;
+
+ if (pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X) {
+ if (qlcnic_boards[index].sub_vendor == subsystem_vendor &&
+ qlcnic_boards[index].sub_device == pdev->subsystem_device)
+ ret = true;
+ else
+ ret = false;
+ }
+
+ return ret;
+}
+
static void qlcnic_get_board_name(struct qlcnic_adapter *adapter, char *name)
{
struct pci_dev *pdev = adapter->pdev;
@@ -882,20 +898,18 @@ static void qlcnic_get_board_name(struct qlcnic_adapter *adapter, char *name)
for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
if (qlcnic_boards[i].vendor == pdev->vendor &&
- qlcnic_boards[i].device == pdev->device &&
- qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor &&
- qlcnic_boards[i].sub_device == pdev->subsystem_device) {
- sprintf(name, "%pM: %s" ,
- adapter->mac_addr,
- qlcnic_boards[i].short_name);
- found = 1;
- break;
+ qlcnic_boards[i].device == pdev->device &&
+ qlcnic_validate_subsystem_id(adapter, i)) {
+ found = 1;
+ break;
}
-
}
if (!found)
sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
+ else
+ sprintf(name, "%pM: %s" , adapter->mac_addr,
+ qlcnic_boards[i].short_name);
}
static void
@@ -980,7 +994,7 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
u32 temp;
temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
- adapter->ahw->capabilities2 = temp;
+ adapter->ahw->extra_capability[0] = temp;
}
adapter->ahw->max_mac_filters = nic_info.max_mac_filters;
adapter->ahw->max_mtu = nic_info.max_mtu;
@@ -1395,16 +1409,23 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
for (ring = 0; ring < num_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
if (qlcnic_82xx_check(adapter) &&
- (ring == (num_sds_rings - 1)))
- snprintf(sds_ring->name,
- sizeof(sds_ring->name),
- "qlcnic-%s[Tx0+Rx%d]",
- netdev->name, ring);
- else
+ (ring == (num_sds_rings - 1))) {
+ if (!(adapter->flags &
+ QLCNIC_MSIX_ENABLED))
+ snprintf(sds_ring->name,
+ sizeof(sds_ring->name),
+ "qlcnic");
+ else
+ snprintf(sds_ring->name,
+ sizeof(sds_ring->name),
+ "%s-tx-0-rx-%d",
+ netdev->name, ring);
+ } else {
snprintf(sds_ring->name,
sizeof(sds_ring->name),
- "qlcnic-%s[Rx%d]",
+ "%s-rx-%d",
netdev->name, ring);
+ }
err = request_irq(sds_ring->irq, handler, flags,
sds_ring->name, sds_ring);
if (err)
@@ -1419,7 +1440,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
ring++) {
tx_ring = &adapter->tx_ring[ring];
snprintf(tx_ring->name, sizeof(tx_ring->name),
- "qlcnic-%s[Tx%d]", netdev->name, ring);
+ "%s-tx-%d", netdev->name, ring);
err = request_irq(tx_ring->irq, handler, flags,
tx_ring->name, tx_ring);
if (err)
@@ -1465,7 +1486,7 @@ static void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter)
u32 capab = 0;
if (qlcnic_82xx_check(adapter)) {
- if (adapter->ahw->capabilities2 &
+ if (adapter->ahw->extra_capability[0] &
QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
} else {
@@ -1816,6 +1837,22 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter)
return err;
}
+void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ u16 act_pci_fn = ahw->act_pci_func;
+ u16 count;
+
+ ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
+ if (act_pci_fn <= 2)
+ count = (QLCNIC_MAX_UC_COUNT - QLCNIC_MAX_MC_COUNT) /
+ act_pci_fn;
+ else
+ count = (QLCNIC_LB_MAX_FILTERS - QLCNIC_MAX_MC_COUNT) /
+ act_pci_fn;
+ ahw->max_uc_count = count;
+}
+
int
qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
int pci_using_dac)
@@ -1825,7 +1862,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
adapter->rx_csum = 1;
adapter->ahw->mc_enabled = 0;
- adapter->ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
+ qlcnic_set_mac_filter_count(adapter);
netdev->netdev_ops = &qlcnic_netdev_ops;
netdev->watchdog_timeo = QLCNIC_WATCHDOG_TIMEOUTVALUE * HZ;
@@ -1863,6 +1900,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
netdev->features |= NETIF_F_LRO;
netdev->hw_features = netdev->features;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->irq = adapter->msix_entries[0].vector;
err = register_netdev(netdev);
@@ -1947,6 +1985,21 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
return 0;
}
+void qlcnic_set_drv_version(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ u32 fw_cmd = 0;
+
+ if (qlcnic_82xx_check(adapter))
+ fw_cmd = QLCNIC_CMD_82XX_SET_DRV_VER;
+ else if (qlcnic_83xx_check(adapter))
+ fw_cmd = QLCNIC_CMD_83XX_SET_DRV_VER;
+
+ if ((ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) &&
+ (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_SET_DRV_VER))
+ qlcnic_fw_cmd_set_drv_version(adapter, fw_cmd);
+}
+
static int
qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -1954,7 +2007,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct qlcnic_adapter *adapter = NULL;
struct qlcnic_hardware_context *ahw;
int err, pci_using_dac = -1;
- u32 capab2;
char board_name[QLCNIC_MAX_BOARD_NAME_LEN + 19]; /* MAC + ": " + name */
if (pdev->is_virtfn)
@@ -2109,13 +2161,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_out_disable_mbx_intr;
- if (qlcnic_82xx_check(adapter)) {
- if (ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
- capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
- if (capab2 & QLCNIC_FW_CAPABILITY_2_OCBB)
- qlcnic_fw_cmd_set_drv_version(adapter);
- }
- }
+ qlcnic_set_drv_version(adapter);
pci_set_drvdata(pdev, adapter);
@@ -2231,37 +2277,6 @@ static void qlcnic_remove(struct pci_dev *pdev)
kfree(ahw);
free_netdev(netdev);
}
-static int __qlcnic_shutdown(struct pci_dev *pdev)
-{
- struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
- struct net_device *netdev = adapter->netdev;
- int retval;
-
- netif_device_detach(netdev);
-
- qlcnic_cancel_idc_work(adapter);
-
- if (netif_running(netdev))
- qlcnic_down(adapter, netdev);
-
- qlcnic_sriov_cleanup(adapter);
- if (qlcnic_82xx_check(adapter))
- qlcnic_clr_all_drv_state(adapter, 0);
-
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
-
- retval = pci_save_state(pdev);
- if (retval)
- return retval;
- if (qlcnic_82xx_check(adapter)) {
- if (qlcnic_wol_supported(adapter)) {
- pci_enable_wake(pdev, PCI_D3cold, 1);
- pci_enable_wake(pdev, PCI_D3hot, 1);
- }
- }
-
- return 0;
-}
static void qlcnic_shutdown(struct pci_dev *pdev)
{
@@ -2272,8 +2287,7 @@ static void qlcnic_shutdown(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
-static int
-qlcnic_suspend(struct pci_dev *pdev, pm_message_t state)
+static int qlcnic_suspend(struct pci_dev *pdev, pm_message_t state)
{
int retval;
@@ -2285,11 +2299,9 @@ qlcnic_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
-static int
-qlcnic_resume(struct pci_dev *pdev)
+static int qlcnic_resume(struct pci_dev *pdev)
{
struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
- struct net_device *netdev = adapter->netdev;
int err;
err = pci_enable_device(pdev);
@@ -2300,23 +2312,7 @@ qlcnic_resume(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
- err = qlcnic_start_firmware(adapter);
- if (err) {
- dev_err(&pdev->dev, "failed to start firmware\n");
- return err;
- }
-
- if (netif_running(netdev)) {
- err = qlcnic_up(adapter, netdev);
- if (err)
- goto done;
-
- qlcnic_restore_indev_addr(netdev, NETDEV_UP);
- }
-done:
- netif_device_attach(netdev);
- qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
- return 0;
+ return __qlcnic_resume(adapter);
}
#endif
@@ -2655,8 +2651,7 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
return 0;
}
-static void
-qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
+void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
{
u32 val;
@@ -3086,6 +3081,7 @@ done:
adapter->fw_fail_cnt = 0;
adapter->flags &= ~QLCNIC_FW_HANG;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ qlcnic_set_drv_version(adapter);
if (!qlcnic_clr_drv_state(adapter))
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
@@ -3166,8 +3162,7 @@ detach:
return 1;
}
-static void
-qlcnic_fw_poll_work(struct work_struct *work)
+void qlcnic_fw_poll_work(struct work_struct *work)
{
struct qlcnic_adapter *adapter = container_of(work,
struct qlcnic_adapter, fw_work.work);
@@ -3219,7 +3214,6 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
if (err)
return err;
- pci_set_power_state(pdev, PCI_D0);
pci_set_master(pdev);
pci_restore_state(pdev);
@@ -3517,7 +3511,7 @@ static int qlcnic_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct qlcnic_adapter *adapter;
- struct net_device *dev = (struct net_device *)ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
recheck:
if (dev == NULL)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index 4b9bab18ebd9..ab8a6744d402 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -15,6 +15,7 @@
#define QLC_83XX_MINIDUMP_FLASH 0x520000
#define QLC_83XX_OCM_INDEX 3
#define QLC_83XX_PCI_INDEX 0
+#define QLC_83XX_DMA_ENGINE_INDEX 8
static const u32 qlcnic_ms_read_data[] = {
0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC
@@ -32,6 +33,16 @@ static const u32 qlcnic_ms_read_data[] = {
#define QLCNIC_DUMP_MASK_MAX 0xff
+struct qlcnic_pex_dma_descriptor {
+ u32 read_data_size;
+ u32 dma_desc_cmd;
+ u32 src_addr_low;
+ u32 src_addr_high;
+ u32 dma_bus_addr_low;
+ u32 dma_bus_addr_high;
+ u32 rsvd[6];
+} __packed;
+
struct qlcnic_common_entry_hdr {
u32 type;
u32 offset;
@@ -90,7 +101,10 @@ struct __ocm {
} __packed;
struct __mem {
- u8 rsvd[24];
+ u32 desc_card_addr;
+ u32 dma_desc_cmd;
+ u32 start_dma_cmd;
+ u32 rsvd[3];
u32 addr;
u32 size;
} __packed;
@@ -466,12 +480,12 @@ skip_poll:
return l2->no_ops * l2->read_addr_num * sizeof(u32);
}
-static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
+static u32 qlcnic_read_memory_test_agent(struct qlcnic_adapter *adapter,
+ struct __mem *mem, __le32 *buffer,
+ int *ret)
{
- u32 addr, data, test, ret = 0;
+ u32 addr, data, test;
int i, reg_read;
- struct __mem *mem = &entry->region.mem;
reg_read = mem->size;
addr = mem->addr;
@@ -480,7 +494,8 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
dev_info(&adapter->pdev->dev,
"Unaligned memory addr:0x%x size:0x%x\n",
addr, reg_read);
- return -EINVAL;
+ *ret = -EINVAL;
+ return 0;
}
mutex_lock(&adapter->ahw->mem_lock);
@@ -499,7 +514,7 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
if (printk_ratelimit()) {
dev_err(&adapter->pdev->dev,
"failed to read through agent\n");
- ret = -EINVAL;
+ *ret = -EIO;
goto out;
}
}
@@ -516,6 +531,181 @@ out:
return mem->size;
}
+/* DMA register base address */
+#define QLC_DMA_REG_BASE_ADDR(dma_no) (0x77320000 + (dma_no * 0x10000))
+
+/* DMA register offsets w.r.t base address */
+#define QLC_DMA_CMD_BUFF_ADDR_LOW 0
+#define QLC_DMA_CMD_BUFF_ADDR_HI 4
+#define QLC_DMA_CMD_STATUS_CTRL 8
+
+#define QLC_PEX_DMA_READ_SIZE (PAGE_SIZE * 16)
+
+static int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter,
+ struct __mem *mem)
+{
+ struct qlcnic_dump_template_hdr *tmpl_hdr;
+ struct device *dev = &adapter->pdev->dev;
+ u32 dma_no, dma_base_addr, temp_addr;
+ int i, ret, dma_sts;
+
+ tmpl_hdr = adapter->ahw->fw_dump.tmpl_hdr;
+ dma_no = tmpl_hdr->saved_state[QLC_83XX_DMA_ENGINE_INDEX];
+ dma_base_addr = QLC_DMA_REG_BASE_ADDR(dma_no);
+
+ temp_addr = dma_base_addr + QLC_DMA_CMD_BUFF_ADDR_LOW;
+ ret = qlcnic_83xx_wrt_reg_indirect(adapter, temp_addr,
+ mem->desc_card_addr);
+ if (ret)
+ return ret;
+
+ temp_addr = dma_base_addr + QLC_DMA_CMD_BUFF_ADDR_HI;
+ ret = qlcnic_83xx_wrt_reg_indirect(adapter, temp_addr, 0);
+ if (ret)
+ return ret;
+
+ temp_addr = dma_base_addr + QLC_DMA_CMD_STATUS_CTRL;
+ ret = qlcnic_83xx_wrt_reg_indirect(adapter, temp_addr,
+ mem->start_dma_cmd);
+ if (ret)
+ return ret;
+
+ /* Wait for DMA to complete */
+ temp_addr = dma_base_addr + QLC_DMA_CMD_STATUS_CTRL;
+ for (i = 0; i < 400; i++) {
+ dma_sts = qlcnic_ind_rd(adapter, temp_addr);
+
+ if (dma_sts & BIT_1)
+ usleep_range(250, 500);
+ else
+ break;
+ }
+
+ if (i >= 400) {
+ dev_info(dev, "PEX DMA operation timed out");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,
+ struct __mem *mem,
+ __le32 *buffer, int *ret)
+{
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ u32 temp, dma_base_addr, size = 0, read_size = 0;
+ struct qlcnic_pex_dma_descriptor *dma_descr;
+ struct qlcnic_dump_template_hdr *tmpl_hdr;
+ struct device *dev = &adapter->pdev->dev;
+ dma_addr_t dma_phys_addr;
+ void *dma_buffer;
+
+ tmpl_hdr = fw_dump->tmpl_hdr;
+
+ /* Check if DMA engine is available */
+ temp = tmpl_hdr->saved_state[QLC_83XX_DMA_ENGINE_INDEX];
+ dma_base_addr = QLC_DMA_REG_BASE_ADDR(temp);
+ temp = qlcnic_ind_rd(adapter,
+ dma_base_addr + QLC_DMA_CMD_STATUS_CTRL);
+
+ if (!(temp & BIT_31)) {
+ dev_info(dev, "%s: DMA engine is not available\n", __func__);
+ *ret = -EIO;
+ return 0;
+ }
+
+ /* Create DMA descriptor */
+ dma_descr = kzalloc(sizeof(struct qlcnic_pex_dma_descriptor),
+ GFP_KERNEL);
+ if (!dma_descr) {
+ *ret = -ENOMEM;
+ return 0;
+ }
+
+ /* dma_desc_cmd 0:15 = 0
+ * dma_desc_cmd 16:19 = mem->dma_desc_cmd 0:3
+ * dma_desc_cmd 20:23 = pci function number
+ * dma_desc_cmd 24:31 = mem->dma_desc_cmd 8:15
+ */
+ dma_phys_addr = fw_dump->phys_addr;
+ dma_buffer = fw_dump->dma_buffer;
+ temp = 0;
+ temp = mem->dma_desc_cmd & 0xff0f;
+ temp |= (adapter->ahw->pci_func & 0xf) << 4;
+ dma_descr->dma_desc_cmd = (temp << 16) & 0xffff0000;
+ dma_descr->dma_bus_addr_low = LSD(dma_phys_addr);
+ dma_descr->dma_bus_addr_high = MSD(dma_phys_addr);
+ dma_descr->src_addr_high = 0;
+
+ /* Collect memory dump using multiple DMA operations if required */
+ while (read_size < mem->size) {
+ if (mem->size - read_size >= QLC_PEX_DMA_READ_SIZE)
+ size = QLC_PEX_DMA_READ_SIZE;
+ else
+ size = mem->size - read_size;
+
+ dma_descr->src_addr_low = mem->addr + read_size;
+ dma_descr->read_data_size = size;
+
+ /* Write DMA descriptor to MS memory*/
+ temp = sizeof(struct qlcnic_pex_dma_descriptor) / 16;
+ *ret = qlcnic_83xx_ms_mem_write128(adapter, mem->desc_card_addr,
+ (u32 *)dma_descr, temp);
+ if (*ret) {
+ dev_info(dev, "Failed to write DMA descriptor to MS memory at address 0x%x\n",
+ mem->desc_card_addr);
+ goto free_dma_descr;
+ }
+
+ *ret = qlcnic_start_pex_dma(adapter, mem);
+ if (*ret) {
+ dev_info(dev, "Failed to start PEX DMA operation\n");
+ goto free_dma_descr;
+ }
+
+ memcpy(buffer, dma_buffer, size);
+ buffer += size / 4;
+ read_size += size;
+ }
+
+free_dma_descr:
+ kfree(dma_descr);
+
+ return read_size;
+}
+
+static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ struct device *dev = &adapter->pdev->dev;
+ struct __mem *mem = &entry->region.mem;
+ u32 data_size;
+ int ret = 0;
+
+ if (fw_dump->use_pex_dma) {
+ data_size = qlcnic_read_memory_pexdma(adapter, mem, buffer,
+ &ret);
+ if (ret)
+ dev_info(dev,
+ "Failed to read memory dump using PEX DMA: mask[0x%x]\n",
+ entry->hdr.mask);
+ else
+ return data_size;
+ }
+
+ data_size = qlcnic_read_memory_test_agent(adapter, mem, buffer, &ret);
+ if (ret) {
+ dev_info(dev,
+ "Failed to read memory dump using test agent method: mask[0x%x]\n",
+ entry->hdr.mask);
+ return 0;
+ } else {
+ return data_size;
+ }
+}
+
static u32 qlcnic_dump_nop(struct qlcnic_adapter *adapter,
struct qlcnic_dump_entry *entry, __le32 *buffer)
{
@@ -893,6 +1083,12 @@ flash_temp:
tmpl_hdr = ahw->fw_dump.tmpl_hdr;
tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
+
+ if ((tmpl_hdr->version & 0xffffff) >= 0x20001)
+ ahw->fw_dump.use_pex_dma = true;
+ else
+ ahw->fw_dump.use_pex_dma = false;
+
ahw->fw_dump.enable = 1;
return 0;
@@ -910,7 +1106,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
static const struct qlcnic_dump_operations *fw_dump_ops;
+ struct device *dev = &adapter->pdev->dev;
struct qlcnic_hardware_context *ahw;
+ void *temp_buffer;
ahw = adapter->ahw;
@@ -944,6 +1142,16 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
tmpl_hdr->sys_info[1] = adapter->fw_version;
+ if (fw_dump->use_pex_dma) {
+ temp_buffer = dma_alloc_coherent(dev, QLC_PEX_DMA_READ_SIZE,
+ &fw_dump->phys_addr,
+ GFP_KERNEL);
+ if (!temp_buffer)
+ fw_dump->use_pex_dma = false;
+ else
+ fw_dump->dma_buffer = temp_buffer;
+ }
+
if (qlcnic_82xx_check(adapter)) {
ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
fw_dump_ops = qlcnic_fw_dump_ops;
@@ -1002,6 +1210,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
return 0;
}
error:
+ if (fw_dump->use_pex_dma)
+ dma_free_coherent(dev, QLC_PEX_DMA_READ_SIZE,
+ fw_dump->dma_buffer, fw_dump->phys_addr);
vfree(fw_dump->data);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
index d85fbb57c25b..0daf660e12a1 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
@@ -129,6 +129,7 @@ struct qlcnic_vport {
u8 vlan_mode;
u16 vlan;
u8 qos;
+ bool spoofchk;
u8 mac[6];
};
@@ -194,6 +195,8 @@ int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *, struct qlcnic_vf_info *,
int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *,
struct qlcnic_info *, u16);
int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8);
+int qlcnic_sriov_vf_shutdown(struct pci_dev *);
+int qlcnic_sriov_vf_resume(struct qlcnic_adapter *);
static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
{
@@ -225,6 +228,7 @@ int qlcnic_sriov_set_vf_tx_rate(struct net_device *, int, int);
int qlcnic_sriov_get_vf_config(struct net_device *, int ,
struct ifla_vf_info *);
int qlcnic_sriov_set_vf_vlan(struct net_device *, int, u16, u8);
+int qlcnic_sriov_set_vf_spoofchk(struct net_device *, int, bool);
#else
static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {}
static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 8b59a710a4a5..62380ce89905 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -35,6 +35,7 @@ static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *);
static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);
static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *,
struct qlcnic_cmd_args *);
+static void qlcnic_sriov_process_bc_cmd(struct work_struct *);
static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
.read_crb = qlcnic_83xx_read_crb,
@@ -75,6 +76,8 @@ static struct qlcnic_nic_template qlcnic_sriov_vf_ops = {
.cancel_idc_work = qlcnic_sriov_vf_cancel_fw_work,
.napi_add = qlcnic_83xx_napi_add,
.napi_del = qlcnic_83xx_napi_del,
+ .shutdown = qlcnic_sriov_vf_shutdown,
+ .resume = qlcnic_sriov_vf_resume,
.config_ipaddr = qlcnic_83xx_config_ipaddr,
.clear_legacy_intr = qlcnic_83xx_clear_legacy_intr,
};
@@ -179,6 +182,8 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
spin_lock_init(&vf->rcv_pend.lock);
init_completion(&vf->ch_free_cmpl);
+ INIT_WORK(&vf->trans_work, qlcnic_sriov_process_bc_cmd);
+
if (qlcnic_sriov_pf_check(adapter)) {
vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL);
if (!vp) {
@@ -187,6 +192,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
}
sriov->vf_info[i].vp = vp;
vp->max_tx_bw = MAX_BW;
+ vp->spoofchk = true;
random_ether_addr(vp->mac);
dev_info(&adapter->pdev->dev,
"MAC Address %pM is configured for VF %d\n",
@@ -652,6 +658,8 @@ int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter, int pci_using_dac)
if (qlcnic_read_mac_addr(adapter))
dev_warn(&adapter->pdev->dev, "failed to read mac addr\n");
+ INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return 0;
}
@@ -864,7 +872,6 @@ static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov,
vf->adapter->need_fw_reset)
return;
- INIT_WORK(&vf->trans_work, func);
queue_work(sriov->bc.bc_trans_wq, &vf->trans_work);
}
@@ -1949,3 +1956,54 @@ static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter)
kfree(cur);
}
}
+
+int qlcnic_sriov_vf_shutdown(struct pci_dev *pdev)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+ int retval;
+
+ netif_device_detach(netdev);
+ qlcnic_cancel_idc_work(adapter);
+
+ if (netif_running(netdev))
+ qlcnic_down(adapter, netdev);
+
+ qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
+ qlcnic_sriov_cfg_bc_intr(adapter, 0);
+ qlcnic_83xx_disable_mbx_intr(adapter);
+ cancel_delayed_work_sync(&adapter->idc_aen_work);
+
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)
+{
+ struct qlc_83xx_idc *idc = &adapter->ahw->idc;
+ struct net_device *netdev = adapter->netdev;
+ int err;
+
+ set_bit(QLC_83XX_MODULE_LOADED, &idc->status);
+ qlcnic_83xx_enable_mbx_intrpt(adapter);
+ err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
+ if (err)
+ return err;
+
+ err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT);
+ if (!err) {
+ if (netif_running(netdev)) {
+ err = qlcnic_up(adapter, netdev);
+ if (!err)
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+ }
+ }
+
+ netif_device_attach(netdev);
+ qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state,
+ idc->delay);
+ return err;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index 1a66ccded235..ee0c1d307966 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -580,6 +580,7 @@ static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func)
struct qlcnic_cmd_args cmd;
struct qlcnic_vport *vp;
int err, id;
+ u8 *mac;
id = qlcnic_sriov_func_to_index(adapter, func);
if (id < 0)
@@ -591,6 +592,14 @@ static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func)
return err;
cmd.req.arg[1] = 0x3 | func << 16;
+ if (vp->spoofchk == true) {
+ mac = vp->mac;
+ cmd.req.arg[2] |= BIT_1 | BIT_3 | BIT_8;
+ cmd.req.arg[4] = mac[5] | mac[4] << 8 | mac[3] << 16 |
+ mac[2] << 24;
+ cmd.req.arg[5] = mac[1] | mac[0] << 8;
+ }
+
if (vp->vlan_mode == QLC_PVID_MODE) {
cmd.req.arg[2] |= BIT_6;
cmd.req.arg[3] |= vp->vlan << 8;
@@ -1767,6 +1776,7 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,
memcpy(&ivi->mac, vp->mac, ETH_ALEN);
ivi->vlan = vp->vlan;
ivi->qos = vp->qos;
+ ivi->spoofchk = vp->spoofchk;
if (vp->max_tx_bw == MAX_BW)
ivi->tx_rate = 0;
else
@@ -1775,3 +1785,29 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,
ivi->vf = vf;
return 0;
}
+
+int qlcnic_sriov_set_vf_spoofchk(struct net_device *netdev, int vf, bool chk)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_vf_info *vf_info;
+ struct qlcnic_vport *vp;
+
+ if (!qlcnic_sriov_pf_check(adapter))
+ return -EOPNOTSUPP;
+
+ if (vf >= sriov->num_vfs)
+ return -EINVAL;
+
+ vf_info = &sriov->vf_info[vf];
+ vp = vf_info->vp;
+ if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) {
+ netdev_err(netdev,
+ "Spoof check change failed for VF %d, as VF driver is loaded. Please unload VF driver and retry the operation\n",
+ vf);
+ return -EOPNOTSUPP;
+ }
+
+ vp->spoofchk = chk;
+ return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index e7a2fe21b649..10ed82b3baca 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -47,7 +47,7 @@ static ssize_t qlcnic_store_bridged_mode(struct device *dev,
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
goto err_out;
- if (strict_strtoul(buf, 2, &new))
+ if (kstrtoul(buf, 2, &new))
goto err_out;
if (!qlcnic_config_bridged_mode(adapter, !!new))
@@ -77,7 +77,7 @@ static ssize_t qlcnic_store_diag_mode(struct device *dev,
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
unsigned long new;
- if (strict_strtoul(buf, 2, &new))
+ if (kstrtoul(buf, 2, &new))
return -EINVAL;
if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
@@ -114,57 +114,51 @@ static int qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon,
return 0;
}
-static ssize_t qlcnic_store_beacon(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static int qlcnic_83xx_store_beacon(struct qlcnic_adapter *adapter,
+ const char *buf, size_t len)
{
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
struct qlcnic_hardware_context *ahw = adapter->ahw;
- int err, max_sds_rings = adapter->max_sds_rings;
- u16 beacon;
- u8 b_state, b_rate;
unsigned long h_beacon;
+ int err;
- if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
- dev_warn(dev,
- "LED test not supported in non privileged mode\n");
- return -EOPNOTSUPP;
- }
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EIO;
- if (qlcnic_83xx_check(adapter) &&
- !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
- if (kstrtoul(buf, 2, &h_beacon))
- return -EINVAL;
+ if (kstrtoul(buf, 2, &h_beacon))
+ return -EINVAL;
- if (ahw->beacon_state == h_beacon)
- return len;
+ if (ahw->beacon_state == h_beacon)
+ return len;
- rtnl_lock();
- if (!ahw->beacon_state) {
- if (test_and_set_bit(__QLCNIC_LED_ENABLE,
- &adapter->state)) {
- rtnl_unlock();
- return -EBUSY;
- }
- }
- if (h_beacon) {
- err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
- if (err)
- goto beacon_err;
- } else {
- err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
- if (err)
- goto beacon_err;
+ rtnl_lock();
+ if (!ahw->beacon_state) {
+ if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
+ rtnl_unlock();
+ return -EBUSY;
}
- /* set the current beacon state */
+ }
+
+ if (h_beacon)
+ err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
+ else
+ err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
+ if (!err)
ahw->beacon_state = h_beacon;
-beacon_err:
- if (!ahw->beacon_state)
- clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
- rtnl_unlock();
- return len;
- }
+ if (!ahw->beacon_state)
+ clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+ rtnl_unlock();
+ return len;
+}
+
+static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,
+ const char *buf, size_t len)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int err, max_sds_rings = adapter->max_sds_rings;
+ u16 beacon;
+ u8 h_beacon_state, b_state, b_rate;
if (len != sizeof(u16))
return QL_STATUS_INVALID_PARAM;
@@ -174,16 +168,29 @@ beacon_err:
if (err)
return err;
- if (adapter->ahw->beacon_state == b_state)
+ if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) {
+ err = qlcnic_get_beacon_state(adapter, &h_beacon_state);
+ if (!err) {
+ dev_info(&adapter->pdev->dev,
+ "Failed to get current beacon state\n");
+ } else {
+ if (h_beacon_state == QLCNIC_BEACON_DISABLE)
+ ahw->beacon_state = 0;
+ else if (h_beacon_state == QLCNIC_BEACON_EANBLE)
+ ahw->beacon_state = 2;
+ }
+ }
+
+ if (ahw->beacon_state == b_state)
return len;
rtnl_lock();
-
- if (!adapter->ahw->beacon_state)
+ if (!ahw->beacon_state) {
if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
rtnl_unlock();
return -EBUSY;
}
+ }
if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
err = -EIO;
@@ -206,14 +213,37 @@ beacon_err:
if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
- out:
- if (!adapter->ahw->beacon_state)
+out:
+ if (!ahw->beacon_state)
clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
rtnl_unlock();
return err;
}
+static ssize_t qlcnic_store_beacon(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int err = 0;
+
+ if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ dev_warn(dev,
+ "LED test not supported in non privileged mode\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (qlcnic_82xx_check(adapter))
+ err = qlcnic_82xx_store_beacon(adapter, buf, len);
+ else if (qlcnic_83xx_check(adapter))
+ err = qlcnic_83xx_store_beacon(adapter, buf, len);
+ else
+ return -EIO;
+
+ return err;
+}
+
static ssize_t qlcnic_show_beacon(struct device *dev,
struct device_attribute *attr, char *buf)
{