diff options
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 129 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 235 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 106 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 31 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 55 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 343 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 2 |
11 files changed, 601 insertions, 321 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 69a6ca086d5c..f19f81cde134 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 3 -#define _QLCNIC_LINUX_SUBVERSION 54 -#define QLCNIC_LINUX_VERSIONID "5.3.54" +#define _QLCNIC_LINUX_SUBVERSION 55 +#define QLCNIC_LINUX_VERSIONID "5.3.55" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -105,6 +105,8 @@ #define QLCNIC_DEF_TX_RINGS 4 #define QLCNIC_MAX_VNIC_TX_RINGS 4 #define QLCNIC_MAX_VNIC_SDS_RINGS 4 +#define QLCNIC_83XX_MINIMUM_VECTOR 3 +#define QLCNIC_82XX_MINIMUM_VECTOR 2 enum qlcnic_queue_type { QLCNIC_TX_QUEUE = 1, @@ -369,6 +371,7 @@ struct qlcnic_rx_buffer { */ #define QLCNIC_INTR_COAL_TYPE_RX 1 #define QLCNIC_INTR_COAL_TYPE_TX 2 +#define QLCNIC_INTR_COAL_TYPE_RX_TX 3 #define QLCNIC_DEF_INTR_COALESCE_RX_TIME_US 3 #define QLCNIC_DEF_INTR_COALESCE_RX_PACKETS 256 @@ -961,6 +964,7 @@ struct qlcnic_ipaddr { #define QLCNIC_TX_INTR_SHARED 0x10000 #define QLCNIC_APP_CHANGED_FLAGS 0x20000 #define QLCNIC_HAS_PHYS_PORT_ID 0x40000 +#define QLCNIC_TSS_RSS 0x80000 #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) @@ -1057,6 +1061,9 @@ struct qlcnic_adapter { u8 drv_tx_rings; /* max tx rings supported by driver */ u8 drv_sds_rings; /* max sds rings supported by driver */ + u8 drv_tss_rings; /* tss ring input */ + u8 drv_rss_rings; /* rss ring input */ + u8 rx_csum; u8 portnum; @@ -1082,7 +1089,7 @@ struct qlcnic_adapter { u64 dev_rst_time; bool drv_mac_learn; bool fdb_mac_learn; - u8 rx_mac_learn; + bool rx_mac_learn; unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)]; u8 flash_mfg_id; struct qlcnic_npar_info *npars; @@ -1573,7 +1580,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int); netdev_tx_t qlcnic_xmit_frame(struct sk_buff *, struct net_device *); void qlcnic_set_tx_ring_count(struct qlcnic_adapter *, u8); void qlcnic_set_sds_ring_count(struct qlcnic_adapter *, u8); -int qlcnic_setup_rings(struct qlcnic_adapter *, u8, u8); +int qlcnic_setup_rings(struct qlcnic_adapter *); int qlcnic_validate_rings(struct qlcnic_adapter *, __u32, int); void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter); int qlcnic_enable_msix(struct qlcnic_adapter *, u32); @@ -1613,7 +1620,7 @@ void qlcnic_set_vlan_config(struct qlcnic_adapter *, struct qlcnic_esw_func_cfg *); void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *, struct qlcnic_esw_func_cfg *); - +int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *); void qlcnic_down(struct qlcnic_adapter *, struct net_device *); int qlcnic_up(struct qlcnic_adapter *, struct net_device *); void __qlcnic_down(struct qlcnic_adapter *, struct net_device *); @@ -1670,11 +1677,8 @@ static inline int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter, err = netif_set_real_num_tx_queues(netdev, adapter->drv_tx_rings); if (err) - dev_err(&adapter->pdev->dev, "failed to set %d Tx queues\n", - adapter->drv_tx_rings); - else - dev_info(&adapter->pdev->dev, "Set %d Tx queues\n", - adapter->drv_tx_rings); + netdev_err(netdev, "failed to set %d Tx queues\n", + adapter->drv_tx_rings); return err; } @@ -1740,7 +1744,8 @@ struct qlcnic_hardware_ops { int (*change_macvlan) (struct qlcnic_adapter *, u8*, u16, u8); void (*napi_enable) (struct qlcnic_adapter *); void (*napi_disable) (struct qlcnic_adapter *); - void (*config_intr_coal) (struct qlcnic_adapter *); + int (*config_intr_coal) (struct qlcnic_adapter *, + struct ethtool_coalesce *); int (*config_rss) (struct qlcnic_adapter *, int); int (*config_hw_lro) (struct qlcnic_adapter *, int); int (*config_loopback) (struct qlcnic_adapter *, u8); @@ -1756,6 +1761,14 @@ struct qlcnic_hardware_ops { pci_ers_result_t (*io_slot_reset) (struct pci_dev *); void (*io_resume) (struct pci_dev *); void (*get_beacon_state)(struct qlcnic_adapter *); + void (*enable_sds_intr) (struct qlcnic_adapter *, + struct qlcnic_host_sds_ring *); + void (*disable_sds_intr) (struct qlcnic_adapter *, + struct qlcnic_host_sds_ring *); + void (*enable_tx_intr) (struct qlcnic_adapter *, + struct qlcnic_host_tx_ring *); + void (*disable_tx_intr) (struct qlcnic_adapter *, + struct qlcnic_host_tx_ring *); }; extern struct qlcnic_nic_template qlcnic_vf_ops; @@ -1928,9 +1941,10 @@ static inline void qlcnic_napi_disable(struct qlcnic_adapter *adapter) adapter->ahw->hw_ops->napi_disable(adapter); } -static inline void qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) +static inline int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter, + struct ethtool_coalesce *ethcoal) { - adapter->ahw->hw_ops->config_intr_coal(adapter); + return adapter->ahw->hw_ops->config_intr_coal(adapter, ethcoal); } static inline int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable) @@ -2029,6 +2043,54 @@ static inline bool qlcnic_check_multi_tx(struct qlcnic_adapter *adapter) return test_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state); } +static inline void +qlcnic_82xx_enable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + if (qlcnic_check_multi_tx(adapter) && + !adapter->ahw->diag_test) + writel(0x0, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_82xx_disable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + if (qlcnic_check_multi_tx(adapter) && + !adapter->ahw->diag_test) + writel(1, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + writel(0, tx_ring->crb_intr_mask); +} + +static inline void +qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + writel(1, tx_ring->crb_intr_mask); +} + +/* Enable MSI-x and INT-x interrupts */ +static inline void +qlcnic_83xx_enable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) +{ + writel(0, sds_ring->crb_intr_mask); +} + +/* Disable MSI-x and INT-x interrupts */ +static inline void +qlcnic_83xx_disable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) +{ + writel(1, sds_ring->crb_intr_mask); +} + static inline void qlcnic_disable_multi_tx(struct qlcnic_adapter *adapter) { test_and_clear_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state); @@ -2038,10 +2100,10 @@ static inline void qlcnic_disable_multi_tx(struct qlcnic_adapter *adapter) /* When operating in a muti tx mode, driver needs to write 0x1 * to src register, instead of 0x0 to disable receiving interrupt. */ -static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring) +static inline void +qlcnic_82xx_disable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) { - struct qlcnic_adapter *adapter = sds_ring->adapter; - if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test && (adapter->flags & QLCNIC_MSIX_ENABLED)) @@ -2050,13 +2112,42 @@ static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring) writel(0, sds_ring->crb_intr_mask); } +static inline void qlcnic_enable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) +{ + if (adapter->ahw->hw_ops->enable_sds_intr) + adapter->ahw->hw_ops->enable_sds_intr(adapter, sds_ring); +} + +static inline void +qlcnic_disable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) +{ + if (adapter->ahw->hw_ops->disable_sds_intr) + adapter->ahw->hw_ops->disable_sds_intr(adapter, sds_ring); +} + +static inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + if (adapter->ahw->hw_ops->enable_tx_intr) + adapter->ahw->hw_ops->enable_tx_intr(adapter, tx_ring); +} + +static inline void qlcnic_disable_tx_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + if (adapter->ahw->hw_ops->disable_tx_intr) + adapter->ahw->hw_ops->disable_tx_intr(adapter, tx_ring); +} + /* When operating in a muti tx mode, driver needs to write 0x0 * to src register, instead of 0x1 to enable receiving interrupts. */ -static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring) +static inline void +qlcnic_82xx_enable_sds_intr(struct qlcnic_adapter *adapter, + struct qlcnic_host_sds_ring *sds_ring) { - struct qlcnic_adapter *adapter = sds_ring->adapter; - if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test && (adapter->flags & QLCNIC_MSIX_ENABLED)) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 294984584d1a..4146664d4d6a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -199,6 +199,11 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { .io_slot_reset = qlcnic_83xx_io_slot_reset, .io_resume = qlcnic_83xx_io_resume, .get_beacon_state = qlcnic_83xx_get_beacon_state, + .enable_sds_intr = qlcnic_83xx_enable_sds_intr, + .disable_sds_intr = qlcnic_83xx_disable_sds_intr, + .enable_tx_intr = qlcnic_83xx_enable_tx_intr, + .disable_tx_intr = qlcnic_83xx_disable_tx_intr, + }; static struct qlcnic_nic_template qlcnic_83xx_ops = { @@ -285,11 +290,22 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr, } } -int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) +static void qlcnic_83xx_enable_legacy(struct qlcnic_adapter *adapter) { - int err, i, num_msix; struct qlcnic_hardware_context *ahw = adapter->ahw; + /* MSI-X enablement failed, use legacy interrupt */ + adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR; + adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK; + adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR; + adapter->msix_entries[0].vector = adapter->pdev->irq; + dev_info(&adapter->pdev->dev, "using legacy interrupt\n"); +} + +static int qlcnic_83xx_calculate_msix_vector(struct qlcnic_adapter *adapter) +{ + int num_msix; + num_msix = adapter->drv_sds_rings; /* account for AEN interrupt MSI-X based interrupts */ @@ -298,30 +314,44 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) if (!(adapter->flags & QLCNIC_TX_INTR_SHARED)) num_msix += adapter->drv_tx_rings; - err = qlcnic_enable_msix(adapter, num_msix); - if (err == -ENOMEM) - return err; - if (adapter->flags & QLCNIC_MSIX_ENABLED) - num_msix = adapter->ahw->num_msix; - else { - if (qlcnic_sriov_vf_check(adapter)) - return -EINVAL; - num_msix = 1; - adapter->drv_tx_rings = QLCNIC_SINGLE_RING; + return num_msix; +} + +int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + int err, i, num_msix; + + if (adapter->flags & QLCNIC_TSS_RSS) { + err = qlcnic_setup_tss_rss_intr(adapter); + if (err < 0) + return err; + num_msix = ahw->num_msix; + } else { + num_msix = qlcnic_83xx_calculate_msix_vector(adapter); + + err = qlcnic_enable_msix(adapter, num_msix); + if (err == -ENOMEM) + return err; + + if (adapter->flags & QLCNIC_MSIX_ENABLED) { + num_msix = ahw->num_msix; + } else { + if (qlcnic_sriov_vf_check(adapter)) + return -EINVAL; + num_msix = 1; + adapter->drv_tx_rings = QLCNIC_SINGLE_RING; + } } + /* setup interrupt mapping table for fw */ ahw->intr_tbl = vzalloc(num_msix * sizeof(struct qlcnic_intrpt_config)); if (!ahw->intr_tbl) return -ENOMEM; - if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { - /* MSI-X enablement failed, use legacy interrupt */ - adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR; - adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK; - adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR; - adapter->msix_entries[0].vector = adapter->pdev->irq; - dev_info(&adapter->pdev->dev, "using legacy interrupt\n"); - } + + if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) + qlcnic_83xx_enable_legacy(adapter); for (i = 0; i < num_msix; i++) { if (adapter->flags & QLCNIC_MSIX_ENABLED) @@ -331,6 +361,7 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) ahw->intr_tbl[i].id = i; ahw->intr_tbl[i].src = 0; } + return 0; } @@ -345,20 +376,6 @@ static inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapt 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) -{ - writel(0, sds_ring->crb_intr_mask); -} - -/* Disable MSI-x and INT-x interrupts */ -void qlcnic_83xx_disable_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_sds_ring *sds_ring) -{ - writel(1, sds_ring->crb_intr_mask); -} - static inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter *adapter) { @@ -496,7 +513,7 @@ irqreturn_t qlcnic_83xx_tmp_intr(int irq, void *data) done: adapter->ahw->diag_cnt++; - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); return IRQ_HANDLED; } @@ -1295,8 +1312,8 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter, /* send the mailbox command*/ err = qlcnic_issue_cmd(adapter, &cmd); if (err) { - dev_err(&adapter->pdev->dev, - "Failed to create Tx ctx in firmware 0x%x\n", err); + netdev_err(adapter->netdev, + "Failed to create Tx ctx in firmware 0x%x\n", err); goto out; } mbx_out = (struct qlcnic_tx_mbx_out *)&cmd.rsp.arg[2]; @@ -1307,8 +1324,9 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter, intr_mask = ahw->intr_tbl[adapter->drv_sds_rings + ring].src; tx->crb_intr_mask = ahw->pci_base0 + intr_mask; } - dev_info(&adapter->pdev->dev, "Tx Context[0x%x] Created, state:0x%x\n", - tx->ctx_id, mbx_out->state); + netdev_info(adapter->netdev, + "Tx Context[0x%x] Created, state:0x%x\n", + tx->ctx_id, mbx_out->state); out: qlcnic_free_mbx_args(&cmd); return err; @@ -1360,7 +1378,7 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test, if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } } @@ -1385,7 +1403,7 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev, for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; if (adapter->flags & QLCNIC_MSIX_ENABLED) - qlcnic_83xx_disable_intr(adapter, sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); } } @@ -1637,7 +1655,7 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter, if (qlcnic_sriov_pf_check(adapter)) { qlcnic_alloc_lb_filters_mem(adapter); qlcnic_pf_set_interface_id_promisc(adapter, interface_id); - adapter->rx_mac_learn = 1; + adapter->rx_mac_learn = true; } else { if (!qlcnic_sriov_vf_check(adapter)) *interface_id = adapter->recv_ctx->context_id << 16; @@ -2111,37 +2129,130 @@ int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac, return err; } -void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_set_rx_intr_coal(struct qlcnic_adapter *adapter) { - int err; - u16 temp; - struct qlcnic_cmd_args cmd; struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + struct qlcnic_cmd_args cmd; + u16 temp; + int err; - if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) - return; + err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL); + if (err) + return err; + + temp = adapter->recv_ctx->context_id; + cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_RX | temp << 16; + temp = coal->rx_time_us; + cmd.req.arg[2] = coal->rx_packets | temp << 16; + cmd.req.arg[3] = coal->flag; + + err = qlcnic_issue_cmd(adapter, &cmd); + if (err != QLCNIC_RCODE_SUCCESS) + netdev_err(adapter->netdev, + "failed to set interrupt coalescing parameters\n"); + + qlcnic_free_mbx_args(&cmd); + + return err; +} + +static int qlcnic_83xx_set_tx_intr_coal(struct qlcnic_adapter *adapter) +{ + struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + struct qlcnic_cmd_args cmd; + u16 temp; + int err; err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL); if (err) - return; + return err; - 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; - temp = coal->rx_time_us; - cmd.req.arg[2] = coal->rx_packets | temp << 16; - } else if (coal->type == QLCNIC_INTR_COAL_TYPE_TX) { - temp = adapter->tx_ring->ctx_id; - cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_TX | temp << 16; - temp = coal->tx_time_us; - cmd.req.arg[2] = coal->tx_packets | temp << 16; - } + temp = adapter->tx_ring->ctx_id; + cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_TX | temp << 16; + temp = coal->tx_time_us; + cmd.req.arg[2] = coal->tx_packets | temp << 16; cmd.req.arg[3] = coal->flag; + err = qlcnic_issue_cmd(adapter, &cmd); if (err != QLCNIC_RCODE_SUCCESS) - dev_info(&adapter->pdev->dev, - "Failed to send interrupt coalescence parameters\n"); + netdev_err(adapter->netdev, + "failed to set interrupt coalescing parameters\n"); + qlcnic_free_mbx_args(&cmd); + + return err; +} + +int qlcnic_83xx_set_rx_tx_intr_coal(struct qlcnic_adapter *adapter) +{ + int err = 0; + + err = qlcnic_83xx_set_rx_intr_coal(adapter); + if (err) + netdev_err(adapter->netdev, + "failed to set Rx coalescing parameters\n"); + + err = qlcnic_83xx_set_tx_intr_coal(adapter); + if (err) + netdev_err(adapter->netdev, + "failed to set Tx coalescing parameters\n"); + + return err; +} + +int qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter, + struct ethtool_coalesce *ethcoal) +{ + struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + u32 rx_coalesce_usecs, rx_max_frames; + u32 tx_coalesce_usecs, tx_max_frames; + int err; + + if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) + return -EIO; + + tx_coalesce_usecs = ethcoal->tx_coalesce_usecs; + tx_max_frames = ethcoal->tx_max_coalesced_frames; + rx_coalesce_usecs = ethcoal->rx_coalesce_usecs; + rx_max_frames = ethcoal->rx_max_coalesced_frames; + coal->flag = QLCNIC_INTR_DEFAULT; + + if ((coal->rx_time_us == rx_coalesce_usecs) && + (coal->rx_packets == rx_max_frames)) { + coal->type = QLCNIC_INTR_COAL_TYPE_TX; + coal->tx_time_us = tx_coalesce_usecs; + coal->tx_packets = tx_max_frames; + } else if ((coal->tx_time_us == tx_coalesce_usecs) && + (coal->tx_packets == tx_max_frames)) { + coal->type = QLCNIC_INTR_COAL_TYPE_RX; + coal->rx_time_us = rx_coalesce_usecs; + coal->rx_packets = rx_max_frames; + } else { + coal->type = QLCNIC_INTR_COAL_TYPE_RX_TX; + coal->rx_time_us = rx_coalesce_usecs; + coal->rx_packets = rx_max_frames; + coal->tx_time_us = tx_coalesce_usecs; + coal->tx_packets = tx_max_frames; + } + + switch (coal->type) { + case QLCNIC_INTR_COAL_TYPE_RX: + err = qlcnic_83xx_set_rx_intr_coal(adapter); + break; + case QLCNIC_INTR_COAL_TYPE_TX: + err = qlcnic_83xx_set_tx_intr_coal(adapter); + break; + case QLCNIC_INTR_COAL_TYPE_RX_TX: + err = qlcnic_83xx_set_rx_tx_intr_coal(adapter); + break; + default: + err = -EINVAL; + netdev_err(adapter->netdev, + "Invalid Interrupt coalescing type\n"); + break; + } + + return err; } static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index a5ca3f460b2d..f92485ca21d1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -547,7 +547,6 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32); int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32); int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int); int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int); -int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *); void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, u16); int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *); int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *); @@ -577,17 +576,15 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *, void qlcnic_free_mbx_args(struct qlcnic_cmd_args *); void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *, struct qlcnic_info *); -void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *); +int qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *, + struct ethtool_coalesce *); +int qlcnic_83xx_set_rx_tx_intr_coal(struct qlcnic_adapter *); int qlcnic_83xx_get_port_info(struct qlcnic_adapter *); void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *); void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *); irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *); irqreturn_t qlcnic_83xx_intr(int, void *); irqreturn_t qlcnic_83xx_tmp_intr(int, void *); -void qlcnic_83xx_enable_intr(struct qlcnic_adapter *, - struct qlcnic_host_sds_ring *); -void qlcnic_83xx_disable_intr(struct qlcnic_adapter *, - struct qlcnic_host_sds_ring *); void qlcnic_83xx_check_vf(struct qlcnic_adapter *, const struct pci_device_id *); int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 6d7f6a170869..90a2dda351ec 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -383,7 +383,7 @@ static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter) qlcnic_up(adapter, netdev); netif_device_attach(netdev); clear_bit(__QLCNIC_RESETTING, &adapter->state); - dev_err(&adapter->pdev->dev, "%s:\n", __func__); + netdev_info(adapter->netdev, "%s: soft reset complete.\n", __func__); return 0; } @@ -2217,7 +2217,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) struct qlcnic_hardware_context *ahw = adapter->ahw; int err = 0; - adapter->rx_mac_learn = 0; + adapter->rx_mac_learn = false; ahw->msix_supported = !!qlcnic_use_msi_x; qlcnic_83xx_init_rings(adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c index e26c49fa87ab..be7d7a62cc0d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c @@ -227,10 +227,10 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter) if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) { adapter->flags |= QLCNIC_ESWITCH_ENABLED; if (adapter->drv_mac_learn) - adapter->rx_mac_learn = 1; + adapter->rx_mac_learn = true; } else { adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; - adapter->rx_mac_learn = 0; + adapter->rx_mac_learn = false; } ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 45961e310194..acee1a5d80c6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -736,6 +736,7 @@ static int qlcnic_set_channels(struct net_device *dev, channel->rx_count); return err; } + adapter->drv_rss_rings = channel->rx_count; } if (channel->tx_count) { @@ -746,10 +747,12 @@ static int qlcnic_set_channels(struct net_device *dev, channel->tx_count); return err; } + adapter->drv_tss_rings = channel->tx_count; } - err = qlcnic_setup_rings(adapter, channel->rx_count, - channel->tx_count); + adapter->flags |= QLCNIC_TSS_RSS; + + err = qlcnic_setup_rings(adapter); netdev_info(dev, "Allocated %d SDS rings and %d Tx rings\n", adapter->drv_sds_rings, adapter->drv_tx_rings); @@ -1495,9 +1498,7 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, struct ethtool_coalesce *ethcoal) { struct qlcnic_adapter *adapter = netdev_priv(netdev); - struct qlcnic_nic_intr_coalesce *coal; - u32 rx_coalesce_usecs, rx_max_frames; - u32 tx_coalesce_usecs, tx_max_frames; + int err; if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) return -EINVAL; @@ -1507,82 +1508,31 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, * unsupported parameters are set. */ if (ethcoal->rx_coalesce_usecs > 0xffff || - ethcoal->rx_max_coalesced_frames > 0xffff || - ethcoal->tx_coalesce_usecs > 0xffff || - ethcoal->tx_max_coalesced_frames > 0xffff || - ethcoal->rx_coalesce_usecs_irq || - ethcoal->rx_max_coalesced_frames_irq || - ethcoal->tx_coalesce_usecs_irq || - ethcoal->tx_max_coalesced_frames_irq || - ethcoal->stats_block_coalesce_usecs || - ethcoal->use_adaptive_rx_coalesce || - ethcoal->use_adaptive_tx_coalesce || - ethcoal->pkt_rate_low || - ethcoal->rx_coalesce_usecs_low || - ethcoal->rx_max_coalesced_frames_low || - ethcoal->tx_coalesce_usecs_low || - ethcoal->tx_max_coalesced_frames_low || - ethcoal->pkt_rate_high || - ethcoal->rx_coalesce_usecs_high || - ethcoal->rx_max_coalesced_frames_high || - ethcoal->tx_coalesce_usecs_high || - ethcoal->tx_max_coalesced_frames_high) + ethcoal->rx_max_coalesced_frames > 0xffff || + ethcoal->tx_coalesce_usecs > 0xffff || + ethcoal->tx_max_coalesced_frames > 0xffff || + ethcoal->rx_coalesce_usecs_irq || + ethcoal->rx_max_coalesced_frames_irq || + ethcoal->tx_coalesce_usecs_irq || + ethcoal->tx_max_coalesced_frames_irq || + ethcoal->stats_block_coalesce_usecs || + ethcoal->use_adaptive_rx_coalesce || + ethcoal->use_adaptive_tx_coalesce || + ethcoal->pkt_rate_low || + ethcoal->rx_coalesce_usecs_low || + ethcoal->rx_max_coalesced_frames_low || + ethcoal->tx_coalesce_usecs_low || + ethcoal->tx_max_coalesced_frames_low || + ethcoal->pkt_rate_high || + ethcoal->rx_coalesce_usecs_high || + ethcoal->rx_max_coalesced_frames_high || + ethcoal->tx_coalesce_usecs_high || + ethcoal->tx_max_coalesced_frames_high) return -EINVAL; - coal = &adapter->ahw->coal; - - if (qlcnic_83xx_check(adapter)) { - if (!ethcoal->tx_coalesce_usecs || - !ethcoal->tx_max_coalesced_frames || - !ethcoal->rx_coalesce_usecs || - !ethcoal->rx_max_coalesced_frames) { - coal->flag = QLCNIC_INTR_DEFAULT; - coal->type = QLCNIC_INTR_COAL_TYPE_RX; - coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; - coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; - coal->tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; - coal->tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; - } else { - tx_coalesce_usecs = ethcoal->tx_coalesce_usecs; - tx_max_frames = ethcoal->tx_max_coalesced_frames; - rx_coalesce_usecs = ethcoal->rx_coalesce_usecs; - rx_max_frames = ethcoal->rx_max_coalesced_frames; - coal->flag = 0; - - if ((coal->rx_time_us == rx_coalesce_usecs) && - (coal->rx_packets == rx_max_frames)) { - coal->type = QLCNIC_INTR_COAL_TYPE_TX; - coal->tx_time_us = tx_coalesce_usecs; - coal->tx_packets = tx_max_frames; - } else if ((coal->tx_time_us == tx_coalesce_usecs) && - (coal->tx_packets == tx_max_frames)) { - coal->type = QLCNIC_INTR_COAL_TYPE_RX; - coal->rx_time_us = rx_coalesce_usecs; - coal->rx_packets = rx_max_frames; - } else { - coal->type = QLCNIC_INTR_COAL_TYPE_RX; - coal->rx_time_us = rx_coalesce_usecs; - coal->rx_packets = rx_max_frames; - coal->tx_time_us = tx_coalesce_usecs; - coal->tx_packets = tx_max_frames; - } - } - } else { - if (!ethcoal->rx_coalesce_usecs || - !ethcoal->rx_max_coalesced_frames) { - coal->flag = QLCNIC_INTR_DEFAULT; - coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; - coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; - } else { - coal->flag = 0; - coal->rx_time_us = ethcoal->rx_coalesce_usecs; - coal->rx_packets = ethcoal->rx_max_coalesced_frames; - } - } - - qlcnic_config_intr_coalesce(adapter); + err = qlcnic_config_intr_coalesce(adapter, ethcoal); - return 0; + return err; } static int qlcnic_get_intr_coalesce(struct net_device *netdev, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index e86147912922..03d18a0be6ce 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -547,10 +547,10 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) qlcnic_alloc_lb_filters_mem(adapter); adapter->drv_mac_learn = 1; if (adapter->flags & QLCNIC_ESWITCH_ENABLED) - adapter->rx_mac_learn = 1; + adapter->rx_mac_learn = true; } else { adapter->drv_mac_learn = 0; - adapter->rx_mac_learn = 0; + adapter->rx_mac_learn = false; } qlcnic_nic_set_promisc(adapter, mode); @@ -755,10 +755,7 @@ int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *adapter) return 0; } -/* - * Send the interrupt coalescing parameter set by ethtool to the card. - */ -void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter) +int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *adapter) { struct qlcnic_nic_req req; int rv; @@ -780,6 +777,28 @@ void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter) if (rv != 0) dev_err(&adapter->netdev->dev, "Could not send interrupt coalescing parameters\n"); + + return rv; +} + +/* Send the interrupt coalescing parameter set by ethtool to the card. */ +int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter, + struct ethtool_coalesce *ethcoal) +{ + struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + int rv; + + coal->flag = QLCNIC_INTR_DEFAULT; + coal->rx_time_us = ethcoal->rx_coalesce_usecs; + coal->rx_packets = ethcoal->rx_max_coalesced_frames; + + rv = qlcnic_82xx_set_rx_coalesce(adapter); + + if (rv) + netdev_err(adapter->netdev, + "Failed to set Rx coalescing parametrs\n"); + + return rv; } #define QLCNIC_ENABLE_IPV4_LRO BIT_0 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 17f563de90f1..63d75617d445 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -171,7 +171,9 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter, void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *); void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, u16 vlan_id); -void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter); +int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *, + struct ethtool_coalesce *); +int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *); int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int); void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32, int); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 0df6988e42a9..30874cda8476 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -131,35 +131,6 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *, struct qlcnic_host_rds_ring *, u16, u16); -static inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) -{ - if (qlcnic_check_multi_tx(adapter) && - !adapter->ahw->diag_test) - writel(0x0, tx_ring->crb_intr_mask); -} - - -static inline void qlcnic_disable_tx_int(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) -{ - if (qlcnic_check_multi_tx(adapter) && - !adapter->ahw->diag_test) - writel(1, tx_ring->crb_intr_mask); -} - -static inline void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) -{ - writel(0, tx_ring->crb_intr_mask); -} - -static inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) -{ - writel(1, tx_ring->crb_intr_mask); -} - static inline u8 qlcnic_mac_hash(u64 mac, u16 vlan) { return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff)); @@ -885,7 +856,7 @@ static int qlcnic_poll(struct napi_struct *napi, int budget) if ((work_done < budget) && tx_complete) { napi_complete(&sds_ring->napi); if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); qlcnic_enable_tx_intr(adapter, tx_ring); } } @@ -926,7 +897,7 @@ static int qlcnic_rx_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete(&sds_ring->napi); if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } return work_done; @@ -1557,7 +1528,7 @@ void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; napi_enable(&sds_ring->napi); - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } if (qlcnic_check_multi_tx(adapter) && @@ -1583,7 +1554,7 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - qlcnic_disable_int(sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); napi_synchronize(&sds_ring->napi); napi_disable(&sds_ring->napi); } @@ -1593,7 +1564,7 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter) qlcnic_check_multi_tx(adapter)) { for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; - qlcnic_disable_tx_int(adapter, tx_ring); + qlcnic_disable_tx_intr(adapter, tx_ring); napi_synchronize(&tx_ring->napi); napi_disable(&tx_ring->napi); } @@ -1856,7 +1827,7 @@ static int qlcnic_83xx_msix_sriov_vf_poll(struct napi_struct *napi, int budget) work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); if ((work_done < budget) && tx_complete) { napi_complete(&sds_ring->napi); - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } return work_done; @@ -1879,7 +1850,7 @@ static int qlcnic_83xx_poll(struct napi_struct *napi, int budget) work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); if ((work_done < budget) && tx_complete) { napi_complete(&sds_ring->napi); - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } return work_done; @@ -1898,7 +1869,7 @@ static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget) if (work_done) { napi_complete(&tx_ring->napi); if (test_bit(__QLCNIC_DEV_UP , &adapter->state)) - qlcnic_83xx_enable_tx_intr(adapter, tx_ring); + qlcnic_enable_tx_intr(adapter, tx_ring); } return work_done; @@ -1916,7 +1887,7 @@ static int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete(&sds_ring->napi); if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } return work_done; @@ -1936,7 +1907,7 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter) sds_ring = &recv_ctx->sds_rings[ring]; napi_enable(&sds_ring->napi); if (adapter->flags & QLCNIC_MSIX_ENABLED) - qlcnic_83xx_enable_intr(adapter, sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } if ((adapter->flags & QLCNIC_MSIX_ENABLED) && @@ -1944,7 +1915,7 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; napi_enable(&tx_ring->napi); - qlcnic_83xx_enable_tx_intr(adapter, tx_ring); + qlcnic_enable_tx_intr(adapter, tx_ring); } } } @@ -1962,7 +1933,7 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; if (adapter->flags & QLCNIC_MSIX_ENABLED) - qlcnic_83xx_disable_intr(adapter, sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); napi_synchronize(&sds_ring->napi); napi_disable(&sds_ring->napi); } @@ -1971,7 +1942,7 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter) !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; - qlcnic_83xx_disable_tx_intr(adapter, tx_ring); + qlcnic_disable_tx_intr(adapter, tx_ring); napi_synchronize(&tx_ring->napi); napi_disable(&tx_ring->napi); } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index e2ee2bb5cd5c..1f79d47c45fa 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -557,6 +557,10 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = { .io_slot_reset = qlcnic_82xx_io_slot_reset, .io_resume = qlcnic_82xx_io_resume, .get_beacon_state = qlcnic_82xx_get_beacon_state, + .enable_sds_intr = qlcnic_82xx_enable_sds_intr, + .disable_sds_intr = qlcnic_82xx_disable_sds_intr, + .enable_tx_intr = qlcnic_82xx_enable_tx_intr, + .disable_tx_intr = qlcnic_82xx_disable_tx_intr, }; static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter) @@ -599,9 +603,6 @@ void qlcnic_set_tx_ring_count(struct qlcnic_adapter *adapter, u8 tx_cnt) QLCNIC_TX_QUEUE); else adapter->drv_tx_rings = tx_cnt; - - dev_info(&adapter->pdev->dev, "Set %d Tx rings\n", - adapter->drv_tx_rings); } void qlcnic_set_sds_ring_count(struct qlcnic_adapter *adapter, u8 rx_cnt) @@ -612,25 +613,79 @@ void qlcnic_set_sds_ring_count(struct qlcnic_adapter *adapter, u8 rx_cnt) QLCNIC_RX_QUEUE); else adapter->drv_sds_rings = rx_cnt; - - dev_info(&adapter->pdev->dev, "Set %d SDS rings\n", - adapter->drv_sds_rings); } -int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) +int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; - int drv_tx_rings, drv_sds_rings, tx_vector; - int err = -1, i; + int num_msix = 0, err = 0, vector; + + adapter->flags &= ~QLCNIC_TSS_RSS; + + if (adapter->drv_tss_rings > 0) + num_msix += adapter->drv_tss_rings; + else + num_msix += adapter->drv_tx_rings; + + if (adapter->drv_rss_rings > 0) + num_msix += adapter->drv_rss_rings; + else + num_msix += adapter->drv_sds_rings; - if (adapter->flags & QLCNIC_TX_INTR_SHARED) { - drv_tx_rings = 0; - tx_vector = 0; + if (qlcnic_83xx_check(adapter)) + num_msix += 1; + + if (!adapter->msix_entries) { + adapter->msix_entries = kcalloc(num_msix, + sizeof(struct msix_entry), + GFP_KERNEL); + if (!adapter->msix_entries) + return -ENOMEM; + } + +restore: + for (vector = 0; vector < num_msix; vector++) + adapter->msix_entries[vector].entry = vector; + + err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); + if (err == 0) { + adapter->ahw->num_msix = num_msix; + if (adapter->drv_tss_rings > 0) + adapter->drv_tx_rings = adapter->drv_tss_rings; + + if (adapter->drv_rss_rings > 0) + adapter->drv_sds_rings = adapter->drv_rss_rings; } else { - drv_tx_rings = adapter->drv_tx_rings; - tx_vector = 1; + netdev_info(adapter->netdev, + "Unable to allocate %d MSI-X vectors, Available vectors %d\n", + num_msix, err); + + num_msix = adapter->drv_tx_rings + adapter->drv_sds_rings; + + /* Set rings to 0 so we can restore original TSS/RSS count */ + adapter->drv_tss_rings = 0; + adapter->drv_rss_rings = 0; + + if (qlcnic_83xx_check(adapter)) + num_msix += 1; + + netdev_info(adapter->netdev, + "Restoring %d Tx, %d SDS rings for total %d vectors.\n", + adapter->drv_tx_rings, adapter->drv_sds_rings, + num_msix); + goto restore; + + err = -EIO; } + return err; +} + +int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) +{ + struct pci_dev *pdev = adapter->pdev; + int err = -1, vector; + if (!adapter->msix_entries) { adapter->msix_entries = kcalloc(num_msix, sizeof(struct msix_entry), @@ -639,47 +694,43 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) return -ENOMEM; } - adapter->drv_sds_rings = QLCNIC_SINGLE_RING; adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); if (adapter->ahw->msix_supported) { - enable_msix: - for (i = 0; i < num_msix; i++) - adapter->msix_entries[i].entry = i; +enable_msix: + for (vector = 0; vector < num_msix; vector++) + adapter->msix_entries[vector].entry = vector; + err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); if (err == 0) { adapter->flags |= QLCNIC_MSIX_ENABLED; - if (qlcnic_83xx_check(adapter)) { - adapter->ahw->num_msix = num_msix; - /* subtract mail box and tx ring vectors */ - adapter->drv_sds_rings = num_msix - - drv_tx_rings - 1; - } else { - adapter->ahw->num_msix = num_msix; - if (qlcnic_check_multi_tx(adapter) && - !adapter->ahw->diag_test) - drv_sds_rings = num_msix - drv_tx_rings; - else - drv_sds_rings = num_msix; - - adapter->drv_sds_rings = drv_sds_rings; - } + adapter->ahw->num_msix = num_msix; dev_info(&pdev->dev, "using msi-x interrupts\n"); return err; } else if (err > 0) { dev_info(&pdev->dev, - "Unable to allocate %d MSI-X interrupt vectors\n", - num_msix); - if (qlcnic_83xx_check(adapter)) { - if (err < (QLC_83XX_MINIMUM_VECTOR - tx_vector)) - return err; - err -= drv_tx_rings + 1; + "Unable to allocate %d MSI-X vectors, Available vectors %d\n", + num_msix, err); + + if (qlcnic_82xx_check(adapter)) { num_msix = rounddown_pow_of_two(err); - num_msix += drv_tx_rings + 1; + if (err < QLCNIC_82XX_MINIMUM_VECTOR) + return -EIO; } else { - num_msix = rounddown_pow_of_two(err); - if (qlcnic_check_multi_tx(adapter)) - num_msix += drv_tx_rings; + num_msix = rounddown_pow_of_two(err - 1); + num_msix += 1; + if (err < QLCNIC_83XX_MINIMUM_VECTOR) + return -EIO; + } + + if (qlcnic_82xx_check(adapter) && + !qlcnic_check_multi_tx(adapter)) { + adapter->drv_sds_rings = num_msix; + adapter->drv_tx_rings = QLCNIC_SINGLE_RING; + } else { + /* Distribute vectors equally */ + adapter->drv_tx_rings = num_msix / 2; + adapter->drv_sds_rings = adapter->drv_tx_rings; } if (num_msix) { @@ -690,14 +741,29 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) } } else { dev_info(&pdev->dev, - "Unable to allocate %d MSI-X interrupt vectors\n", - num_msix); + "Unable to allocate %d MSI-X vectors, err=%d\n", + num_msix, err); + return err; } } return err; } +static int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter) +{ + int num_msix; + + num_msix = adapter->drv_sds_rings; + + if (qlcnic_check_multi_tx(adapter)) + num_msix += adapter->drv_tx_rings; + else + num_msix += QLCNIC_SINGLE_RING; + + return num_msix; +} + static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter) { int err = 0; @@ -736,21 +802,25 @@ static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter) { int num_msix, err = 0; - num_msix = adapter->drv_sds_rings; - - if (qlcnic_check_multi_tx(adapter)) - num_msix += adapter->drv_tx_rings; + if (adapter->flags & QLCNIC_TSS_RSS) { + err = qlcnic_setup_tss_rss_intr(adapter); + if (err < 0) + return err; + num_msix = adapter->ahw->num_msix; + } else { + num_msix = qlcnic_82xx_calculate_msix_vector(adapter); - err = qlcnic_enable_msix(adapter, num_msix); - if (err == -ENOMEM) - return err; + err = qlcnic_enable_msix(adapter, num_msix); + if (err == -ENOMEM) + return err; - if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { - qlcnic_disable_multi_tx(adapter); + if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { + qlcnic_disable_multi_tx(adapter); - err = qlcnic_enable_msi_legacy(adapter); - if (!err) - return err; + err = qlcnic_enable_msi_legacy(adapter); + if (!err) + return err; + } } return 0; @@ -1697,6 +1767,33 @@ static void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter) } } +static int qlcnic_config_def_intr_coalesce(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + int err; + + /* Initialize interrupt coalesce parameters */ + ahw->coal.flag = QLCNIC_INTR_DEFAULT; + + if (qlcnic_83xx_check(adapter)) { + ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX; + ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; + ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; + ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; + ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; + + err = qlcnic_83xx_set_rx_tx_intr_coal(adapter); + } else { + ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; + ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; + ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; + + err = qlcnic_82xx_set_rx_coalesce(adapter); + } + + return err; +} + int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) { int ring; @@ -1729,7 +1826,7 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) if (adapter->drv_sds_rings > 1) qlcnic_config_rss(adapter, 1); - qlcnic_config_intr_coalesce(adapter); + qlcnic_config_def_intr_coalesce(adapter); if (netdev->features & NETIF_F_LRO) qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED); @@ -1874,7 +1971,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int drv_sds_rings) if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; - qlcnic_disable_int(sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); } } @@ -1897,7 +1994,6 @@ out: static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) { - struct qlcnic_hardware_context *ahw = adapter->ahw; int err = 0; adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context), @@ -1906,15 +2002,7 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) err = -ENOMEM; goto err_out; } - /* Initialize interrupt coalesce parameters */ - ahw->coal.flag = QLCNIC_INTR_DEFAULT; - ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX; - ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US; - ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS; - if (qlcnic_83xx_check(adapter)) { - ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US; - ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS; - } + /* clear stats */ memset(&adapter->stats, 0, sizeof(adapter->stats)); err_out: @@ -1975,7 +2063,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &adapter->recv_ctx->sds_rings[ring]; - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); } } @@ -2007,7 +2095,7 @@ qlcnic_reset_hw_context(struct qlcnic_adapter *adapter) netif_device_attach(netdev); clear_bit(__QLCNIC_RESETTING, &adapter->state); - dev_err(&adapter->pdev->dev, "%s:\n", __func__); + netdev_info(adapter->netdev, "%s: soft reset complete\n", __func__); return 0; } @@ -2747,12 +2835,58 @@ int qlcnic_check_temp(struct qlcnic_adapter *adapter) return rv; } -static void qlcnic_tx_timeout(struct net_device *netdev) +static inline void dump_tx_ring_desc(struct qlcnic_host_tx_ring *tx_ring) { - struct qlcnic_adapter *adapter = netdev_priv(netdev); + int i; + struct cmd_desc_type0 *tx_desc_info; + + for (i = 0; i < tx_ring->num_desc; i++) { + tx_desc_info = &tx_ring->desc_head[i]; + pr_info("TX Desc: %d\n", i); + print_hex_dump(KERN_INFO, "TX: ", DUMP_PREFIX_OFFSET, 16, 1, + &tx_ring->desc_head[i], + sizeof(struct cmd_desc_type0), true); + } +} + +static void qlcnic_dump_tx_rings(struct qlcnic_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; struct qlcnic_host_tx_ring *tx_ring; int ring; + if (!netdev || !netif_running(netdev)) + return; + + for (ring = 0; ring < adapter->drv_tx_rings; ring++) { + tx_ring = &adapter->tx_ring[ring]; + netdev_info(netdev, "Tx ring=%d Context Id=0x%x\n", + ring, tx_ring->ctx_id); + netdev_info(netdev, + "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n", + tx_ring->tx_stats.xmit_finished, + tx_ring->tx_stats.xmit_called, + tx_ring->tx_stats.xmit_on, + tx_ring->tx_stats.xmit_off); + netdev_info(netdev, + "crb_intr_mask=%d, hw_producer=%d, sw_producer=%d sw_consumer=%d, hw_consumer=%d\n", + readl(tx_ring->crb_intr_mask), + readl(tx_ring->crb_cmd_producer), + tx_ring->producer, tx_ring->sw_consumer, + le32_to_cpu(*(tx_ring->hw_consumer))); + + netdev_info(netdev, "Total desc=%d, Available desc=%d\n", + tx_ring->num_desc, qlcnic_tx_avail(tx_ring)); + + if (netif_msg_tx_done(adapter->ahw)) + dump_tx_ring_desc(tx_ring); + } +} + +static void qlcnic_tx_timeout(struct net_device *netdev) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + if (test_bit(__QLCNIC_RESETTING, &adapter->state)) return; @@ -2765,22 +2899,7 @@ static void qlcnic_tx_timeout(struct net_device *netdev) QLCNIC_FORCE_FW_DUMP_KEY); } else { netdev_info(netdev, "Tx timeout, reset adapter context.\n"); - for (ring = 0; ring < adapter->drv_tx_rings; ring++) { - tx_ring = &adapter->tx_ring[ring]; - netdev_info(netdev, "Tx ring=%d\n", ring); - netdev_info(netdev, - "crb_intr_mask=%d, producer=%d, sw_consumer=%d, hw_consumer=%d\n", - readl(tx_ring->crb_intr_mask), - readl(tx_ring->crb_cmd_producer), - tx_ring->sw_consumer, - le32_to_cpu(*(tx_ring->hw_consumer))); - netdev_info(netdev, - "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n", - tx_ring->tx_stats.xmit_finished, - tx_ring->tx_stats.xmit_called, - tx_ring->tx_stats.xmit_on, - tx_ring->tx_stats.xmit_off); - } + qlcnic_dump_tx_rings(adapter); adapter->ahw->reset_context = 1; } } @@ -2842,7 +2961,7 @@ static irqreturn_t qlcnic_tmp_intr(int irq, void *data) done: adapter->ahw->diag_cnt++; - qlcnic_enable_int(sds_ring); + qlcnic_enable_sds_intr(adapter, sds_ring); return IRQ_HANDLED; } @@ -2890,17 +3009,39 @@ static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data) #ifdef CONFIG_NET_POLL_CONTROLLER static void qlcnic_poll_controller(struct net_device *netdev) { - int ring; - struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_adapter *adapter = netdev_priv(netdev); - struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; + struct qlcnic_host_sds_ring *sds_ring; + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_tx_ring *tx_ring; + int ring; + + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) + return; + + recv_ctx = adapter->recv_ctx; - disable_irq(adapter->irq); for (ring = 0; ring < adapter->drv_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - qlcnic_intr(adapter->irq, sds_ring); + qlcnic_disable_sds_intr(adapter, sds_ring); + napi_schedule(&sds_ring->napi); + } + + if (adapter->flags & QLCNIC_MSIX_ENABLED) { + /* Only Multi-Tx queue capable devices need to + * schedule NAPI for TX rings + */ + if ((qlcnic_83xx_check(adapter) && + (adapter->flags & QLCNIC_TX_INTR_SHARED)) || + (qlcnic_82xx_check(adapter) && + !qlcnic_check_multi_tx(adapter))) + return; + + for (ring = 0; ring < adapter->drv_tx_rings; ring++) { + tx_ring = &adapter->tx_ring[ring]; + qlcnic_disable_tx_intr(adapter, tx_ring); + napi_schedule(&tx_ring->napi); + } } - enable_irq(adapter->irq); } #endif @@ -3759,7 +3900,7 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt, return 0; } -int qlcnic_setup_rings(struct qlcnic_adapter *adapter, u8 rx_cnt, u8 tx_cnt) +int qlcnic_setup_rings(struct qlcnic_adapter *adapter) { struct net_device *netdev = adapter->netdev; int err; @@ -3780,12 +3921,6 @@ int qlcnic_setup_rings(struct qlcnic_adapter *adapter, u8 rx_cnt, u8 tx_cnt) qlcnic_teardown_intr(adapter); - /* compute and set default and max tx/sds rings */ - qlcnic_set_tx_ring_count(adapter, tx_cnt); - qlcnic_set_sds_ring_count(adapter, rx_cnt); - - netif_set_real_num_tx_queues(netdev, adapter->drv_tx_rings); - err = qlcnic_setup_intr(adapter); if (err) { kfree(adapter->msix_entries); @@ -3793,6 +3928,8 @@ int qlcnic_setup_rings(struct qlcnic_adapter *adapter, u8 rx_cnt, u8 tx_cnt) return err; } + netif_set_real_num_tx_queues(netdev, adapter->drv_tx_rings); + if (qlcnic_83xx_check(adapter)) { qlcnic_83xx_initialize_nic(adapter, 1); err = qlcnic_83xx_setup_mbx_intr(adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index db819e1b9469..17a1ca2050f4 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -71,6 +71,8 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { .change_l2_filter = qlcnic_83xx_change_l2_filter, .get_board_info = qlcnic_83xx_get_port_info, .free_mac_list = qlcnic_sriov_vf_free_mac_list, + .enable_sds_intr = qlcnic_83xx_enable_sds_intr, + .disable_sds_intr = qlcnic_83xx_disable_sds_intr, }; static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { |