Commit 9fac865d authored by David S. Miller's avatar David S. Miller

Merge branch 'qlcnic'

Himanshu Madhani says:

====================
qlcnic: Refactoring and enhancements for all adapters.

This patch series contains following patches.

o Enhanced debug data collection when we are in Tx-timeout situation.
o Enhanced MSI-x vector calculation for defualt load path as well
  as for TSS/RSS ring change path.
o Refactored interrupt coalescing code for all adapters.
o Refactored interrupt handling as well as cleanup of poll controller
  code patch for all adapters.
o changed rx_mac_learn type to boolean.

Please apply to net-next.
====================
Signed-off-by: default avatarZoltan Kiss <zoltan.kiss@citrix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0681a282 18cae184
......@@ -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))
......
......@@ -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,
......
......@@ -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 *);
......
......@@ -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);
......
......@@ -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;
......
......@@ -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,
......
......@@ -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
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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 @@ void qlcnic_diag_free_res(struct net_device *netdev, int drv_sds_rings)
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);
......
......@@ -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 = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment