Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7c12639 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'qlcnic'



Himanshu Madhani says:

====================
qlcnic: Bug fixes.

This series contains bug fixes for mailbox handling and multi Tx queue support
for all supported adapters.

changes from v1 -> v2
o updated patch to fix usage of netif_tx_{wake,stop} api during link change
  as per David Miller's suggestion.
o Dropped patch to use spinklock per tx queue for more work.
o Added reworked patch for memory allocation failures.
o Added patch to allow capturing of dump, when auto recovery is disabled in firmware.
o Added patches for mailbox interrupt handling and debugging data for mailbox failure.

Please apply to net.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7022ef8b 0951c5c2
Loading
Loading
Loading
Loading
+21 −26
Original line number Diff line number Diff line
@@ -447,7 +447,8 @@ irqreturn_t qlcnic_83xx_intr(int irq, void *data)

	qlcnic_83xx_poll_process_aen(adapter);

	if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
	if (ahw->diag_test) {
		if (ahw->diag_test == QLCNIC_INTERRUPT_TEST)
			ahw->diag_cnt++;
		qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
		return IRQ_HANDLED;
@@ -1345,11 +1346,6 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test,
	}

	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
		/* disable and free mailbox interrupt */
		if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
			qlcnic_83xx_enable_mbx_poll(adapter);
			qlcnic_83xx_free_mbx_intr(adapter);
		}
		adapter->ahw->loopback_state = 0;
		adapter->ahw->hw_ops->setup_link_event(adapter, 1);
	}
@@ -1363,33 +1359,20 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
{
	struct qlcnic_adapter *adapter = netdev_priv(netdev);
	struct qlcnic_host_sds_ring *sds_ring;
	int ring, err;
	int ring;

	clear_bit(__QLCNIC_DEV_UP, &adapter->state);
	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];
			if (adapter->flags & QLCNIC_MSIX_ENABLED)
				qlcnic_83xx_disable_intr(adapter, sds_ring);
			if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
				qlcnic_83xx_enable_mbx_poll(adapter);
		}
	}

	qlcnic_fw_destroy_ctx(adapter);
	qlcnic_detach(adapter);

	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
		if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
			err = qlcnic_83xx_setup_mbx_intr(adapter);
			qlcnic_83xx_disable_mbx_poll(adapter);
			if (err) {
				dev_err(&adapter->pdev->dev,
					"%s: failed to setup mbx interrupt\n",
					__func__);
				goto out;
			}
		}
	}
	adapter->ahw->diag_test = 0;
	adapter->drv_sds_rings = drv_sds_rings;

@@ -1399,9 +1382,6 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
	if (netif_running(netdev))
		__qlcnic_up(adapter, netdev);

	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST &&
	    !(adapter->flags & QLCNIC_MSIX_ENABLED))
		qlcnic_83xx_disable_mbx_poll(adapter);
out:
	netif_device_attach(netdev);
}
@@ -3754,6 +3734,19 @@ static void qlcnic_83xx_decode_mbx_rsp(struct qlcnic_adapter *adapter,
	return;
}

static inline void qlcnic_dump_mailbox_registers(struct qlcnic_adapter *adapter)
{
	struct qlcnic_hardware_context *ahw = adapter->ahw;
	u32 offset;

	offset = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
	dev_info(&adapter->pdev->dev, "Mbx interrupt mask=0x%x, Mbx interrupt enable=0x%x, Host mbx control=0x%x, Fw mbx control=0x%x",
		 readl(ahw->pci_base0 + offset),
		 QLCRDX(ahw, QLCNIC_MBX_INTR_ENBL),
		 QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL),
		 QLCRDX(ahw, QLCNIC_FW_MBX_CTRL));
}

static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
{
	struct qlcnic_mailbox *mbx = container_of(work, struct qlcnic_mailbox,
@@ -3798,6 +3791,8 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
				__func__, cmd->cmd_op, cmd->type, ahw->pci_func,
				ahw->op_mode);
			clear_bit(QLC_83XX_MBX_READY, &mbx->status);
			qlcnic_dump_mailbox_registers(adapter);
			qlcnic_83xx_get_mbx_data(adapter, cmd);
			qlcnic_dump_mbx(adapter, cmd);
			qlcnic_83xx_idc_request_reset(adapter,
						      QLCNIC_FORCE_FW_DUMP_KEY);
+1 −0
Original line number Diff line number Diff line
@@ -662,4 +662,5 @@ pci_ers_result_t qlcnic_83xx_io_error_detected(struct pci_dev *,
					       pci_channel_state_t);
pci_ers_result_t qlcnic_83xx_io_slot_reset(struct pci_dev *);
void qlcnic_83xx_io_resume(struct pci_dev *);
void qlcnic_83xx_stop_hw(struct qlcnic_adapter *);
#endif
+40 −25
Original line number Diff line number Diff line
@@ -740,6 +740,7 @@ static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)
	adapter->ahw->idc.err_code = -EIO;
	dev_err(&adapter->pdev->dev,
		"%s: Device in unknown state\n", __func__);
	clear_bit(__QLCNIC_RESETTING, &adapter->state);
	return 0;
}

@@ -818,7 +819,6 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
	struct qlcnic_hardware_context *ahw = adapter->ahw;
	struct qlcnic_mailbox *mbx = ahw->mailbox;
	int ret = 0;
	u32 owner;
	u32 val;

	/* Perform NIC configuration based ready state entry actions */
@@ -848,9 +848,9 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
			set_bit(__QLCNIC_RESETTING, &adapter->state);
			qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
		}  else {
			owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
			if (ahw->pci_func == owner)
				qlcnic_dump_fw(adapter);
			netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n",
				    __func__);
			qlcnic_83xx_idc_enter_failed_state(adapter, 1);
		}
		return -EIO;
	}
@@ -948,13 +948,26 @@ static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter)
	return 0;
}

static int qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter)
static void qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter)
{
	dev_err(&adapter->pdev->dev, "%s: please restart!!\n", __func__);
	struct qlcnic_hardware_context *ahw = adapter->ahw;
	u32 val, owner;

	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) {
		owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
		if (ahw->pci_func == owner) {
			qlcnic_83xx_stop_hw(adapter);
			qlcnic_dump_fw(adapter);
		}
	}

	netdev_warn(adapter->netdev, "%s: Reboot will be required to recover the adapter!!\n",
		    __func__);
	clear_bit(__QLCNIC_RESETTING, &adapter->state);
	adapter->ahw->idc.err_code = -EIO;
	ahw->idc.err_code = -EIO;

	return 0;
	return;
}

static int qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter *adapter)
@@ -1063,12 +1076,6 @@ void qlcnic_83xx_idc_poll_dev_state(struct work_struct *work)
	adapter->ahw->idc.prev_state = adapter->ahw->idc.curr_state;
	qlcnic_83xx_periodic_tasks(adapter);

	/* Do not reschedule if firmaware is in hanged state and auto
	 * recovery is disabled
	 */
	if ((adapter->flags & QLCNIC_FW_HANG) && !qlcnic_auto_fw_reset)
		return;

	/* Re-schedule the function */
	if (test_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status))
		qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,
@@ -1219,10 +1226,10 @@ void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key)
	}

	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
	if ((val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) ||
	    !qlcnic_auto_fw_reset) {
		dev_err(&adapter->pdev->dev,
			"%s:failed, device in non reset mode\n", __func__);
	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) {
		netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n",
			    __func__);
		qlcnic_83xx_idc_enter_failed_state(adapter, 0);
		qlcnic_83xx_unlock_driver(adapter);
		return;
	}
@@ -1254,24 +1261,24 @@ static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter)
	if (size & 0xF)
		size = (size + 16) & ~0xF;

	p_cache = kzalloc(size, GFP_KERNEL);
	p_cache = vzalloc(size);
	if (p_cache == NULL)
		return -ENOMEM;

	ret = qlcnic_83xx_lockless_flash_read32(adapter, src, p_cache,
						size / sizeof(u32));
	if (ret) {
		kfree(p_cache);
		vfree(p_cache);
		return ret;
	}
	/* 16 byte write to MS memory */
	ret = qlcnic_83xx_ms_mem_write128(adapter, dest, (u32 *)p_cache,
					  size / 16);
	if (ret) {
		kfree(p_cache);
		vfree(p_cache);
		return ret;
	}
	kfree(p_cache);
	vfree(p_cache);

	return ret;
}
@@ -1939,7 +1946,7 @@ static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev,
	p_dev->ahw->reset.seq_index = index;
}

static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
{
	p_dev->ahw->reset.seq_index = 0;

@@ -1994,6 +2001,14 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
	if (!(val & QLC_83XX_IDC_GRACEFULL_RESET))
		qlcnic_dump_fw(adapter);

	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) {
		netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n",
			    __func__);
		qlcnic_83xx_idc_enter_failed_state(adapter, 1);
		return err;
	}

	qlcnic_83xx_init_hw(adapter);

	if (qlcnic_83xx_copy_bootloader(adapter))
@@ -2073,8 +2088,8 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
		ahw->nic_mode = QLCNIC_DEFAULT_MODE;
		adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver;
		ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
		adapter->max_sds_rings = ahw->max_rx_ques;
		adapter->max_tx_rings = ahw->max_tx_ques;
		adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS;
		adapter->max_tx_rings = QLCNIC_MAX_TX_RINGS;
	} else {
		return -EIO;
	}
+8 −11
Original line number Diff line number Diff line
@@ -667,30 +667,25 @@ qlcnic_set_ringparam(struct net_device *dev,
static int qlcnic_validate_ring_count(struct qlcnic_adapter *adapter,
				      u8 rx_ring, u8 tx_ring)
{
	if (rx_ring == 0 || tx_ring == 0)
		return -EINVAL;

	if (rx_ring != 0) {
		if (rx_ring > adapter->max_sds_rings) {
			netdev_err(adapter->netdev, "Invalid ring count, SDS ring count %d should not be greater than max %d driver sds rings.\n",
			netdev_err(adapter->netdev,
				   "Invalid ring count, SDS ring count %d should not be greater than max %d driver sds rings.\n",
				   rx_ring, adapter->max_sds_rings);
			return -EINVAL;
		}
	}

	 if (tx_ring != 0) {
		if (qlcnic_82xx_check(adapter) &&
		    (tx_ring > adapter->max_tx_rings)) {
		if (tx_ring > adapter->max_tx_rings) {
			netdev_err(adapter->netdev,
				   "Invalid ring count, Tx ring count %d should not be greater than max %d driver Tx rings.\n",
				   tx_ring, adapter->max_tx_rings);
			return -EINVAL;
		}

		if (qlcnic_83xx_check(adapter) &&
		    (tx_ring > QLCNIC_SINGLE_RING)) {
			netdev_err(adapter->netdev,
				   "Invalid ring count, Tx ring count %d should not be greater than %d driver Tx rings.\n",
				   tx_ring, QLCNIC_SINGLE_RING);
			 return -EINVAL;
		}
	}

	return 0;
@@ -948,6 +943,7 @@ static int qlcnic_irq_test(struct net_device *netdev)
	struct qlcnic_hardware_context *ahw = adapter->ahw;
	struct qlcnic_cmd_args cmd;
	int ret, drv_sds_rings = adapter->drv_sds_rings;
	int drv_tx_rings = adapter->drv_tx_rings;

	if (qlcnic_83xx_check(adapter))
		return qlcnic_83xx_interrupt_test(netdev);
@@ -980,6 +976,7 @@ static int qlcnic_irq_test(struct net_device *netdev)

clear_diag_irq:
	adapter->drv_sds_rings = drv_sds_rings;
	adapter->drv_tx_rings = drv_tx_rings;
	clear_bit(__QLCNIC_RESETTING, &adapter->state);

	return ret;
+2 −8
Original line number Diff line number Diff line
@@ -687,17 +687,11 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
	if (adapter->ahw->linkup && !linkup) {
		netdev_info(netdev, "NIC Link is down\n");
		adapter->ahw->linkup = 0;
		if (netif_running(netdev)) {
		netif_carrier_off(netdev);
			netif_tx_stop_all_queues(netdev);
		}
	} else if (!adapter->ahw->linkup && linkup) {
		netdev_info(netdev, "NIC Link is up\n");
		adapter->ahw->linkup = 1;
		if (netif_running(netdev)) {
		netif_carrier_on(netdev);
			netif_wake_queue(netdev);
		}
	}
}

Loading