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

Commit b8c17620 authored by Amit Kumar Salecha's avatar Amit Kumar Salecha Committed by David S. Miller
Browse files

qlcnic: support quiescent mode



Put device in quiescent mode during internal loopback test.
Before running test, set state to NEED_QUISCENT. After getting
ack from all function, change state to QUISCENT and perform test.

Signed-off-by: default avatarAmit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f7ec804a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1313,6 +1313,8 @@ int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);

/* Functions from qlcnic_main.c */
int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter);
void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter);
int qlcnic_reset_context(struct qlcnic_adapter *);
u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
	u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
+6 −0
Original line number Diff line number Diff line
@@ -706,6 +706,11 @@ static int qlcnic_loopback_test(struct net_device *netdev)
	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
		return -EIO;

	if (qlcnic_request_quiscent_mode(adapter)) {
		clear_bit(__QLCNIC_RESETTING, &adapter->state);
		return -EIO;
	}

	ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
	if (ret)
		goto clear_it;
@@ -722,6 +727,7 @@ done:
	qlcnic_diag_free_res(netdev, max_sds_rings);

clear_it:
	qlcnic_clear_quiscent_mode(adapter);
	adapter->max_sds_rings = max_sds_rings;
	clear_bit(__QLCNIC_RESETTING, &adapter->state);
	return ret;
+66 −17
Original line number Diff line number Diff line
@@ -2712,7 +2712,8 @@ qlcnic_fwinit_work(struct work_struct *work)
		goto err_ret;

	dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
	if (dev_state ==  QLCNIC_DEV_QUISCENT) {
	if (dev_state == QLCNIC_DEV_QUISCENT ||
	    dev_state == QLCNIC_DEV_NEED_QUISCENT) {
		qlcnic_api_unlock(adapter);
		qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
						FW_POLL_DELAY * 2);
@@ -2734,18 +2735,6 @@ qlcnic_fwinit_work(struct work_struct *work)
skip_ack_check:
		dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);

		if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
			QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
						QLCNIC_DEV_QUISCENT);
			qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
						FW_POLL_DELAY * 2);
			QLCDB(adapter, DRV, "Quiscing the driver\n");
			qlcnic_idc_debug_info(adapter, 0);

			qlcnic_api_unlock(adapter);
			return;
		}

		if (dev_state == QLCNIC_DEV_NEED_RESET) {
			QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
						QLCNIC_DEV_INITIALIZING);
@@ -2802,6 +2791,11 @@ qlcnic_detach_work(struct work_struct *work)

	netif_device_detach(netdev);

	/* Dont grab rtnl lock during Quiscent mode */
	if (adapter->dev_state == QLCNIC_DEV_NEED_QUISCENT) {
		if (netif_running(netdev))
			__qlcnic_down(adapter, netdev);
	} else
		qlcnic_down(adapter, netdev);

	status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
@@ -2844,6 +2838,61 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
	qlcnic_api_unlock(adapter);
}

/* Caller should held RESETTING bit.
 * This should be call in sync with qlcnic_request_quiscent_mode.
 */
void qlcnic_clear_quiscent_mode(struct qlcnic_adapter *adapter)
{
	qlcnic_clr_drv_state(adapter);
	qlcnic_api_lock(adapter);
	QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
	qlcnic_api_unlock(adapter);
}

/* Caller should held RESETTING bit.
 */
int qlcnic_request_quiscent_mode(struct qlcnic_adapter *adapter)
{
	u8 timeo = adapter->dev_init_timeo / 2;
	u32 state;

	if (qlcnic_api_lock(adapter))
		return -EIO;

	state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
	if (state != QLCNIC_DEV_READY)
		return -EIO;

	QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_QUISCENT);
	qlcnic_api_unlock(adapter);
	QLCDB(adapter, DRV, "NEED QUISCENT state set\n");
	qlcnic_idc_debug_info(adapter, 0);

	qlcnic_set_drv_state(adapter, QLCNIC_DEV_NEED_QUISCENT);

	do {
		msleep(2000);
		state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
		if (state == QLCNIC_DEV_QUISCENT)
			return 0;
		if (!qlcnic_check_drv_state(adapter)) {
			if (qlcnic_api_lock(adapter))
				return -EIO;
			QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
							QLCNIC_DEV_QUISCENT);
			qlcnic_api_unlock(adapter);
			QLCDB(adapter, DRV, "QUISCENT mode set\n");
			return 0;
		}
	} while (--timeo);

	dev_err(&adapter->pdev->dev, "Failed to quiesce device, DRV_STATE=%08x"
		" DRV_ACTIVE=%08x\n", QLCRD32(adapter, QLCNIC_CRB_DRV_STATE),
		QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE));
	qlcnic_clear_quiscent_mode(adapter);
	return -EIO;
}

/*Transit to RESET state from READY state only */
static void
qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
@@ -2951,11 +3000,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
		qlcnic_dev_request_reset(adapter);

	state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
	if (state == QLCNIC_DEV_NEED_RESET ||
	    state == QLCNIC_DEV_NEED_QUISCENT) {
	if (state == QLCNIC_DEV_NEED_RESET) {
		qlcnic_set_npar_non_operational(adapter);
		adapter->need_fw_reset = 1;
	}
	} else if (state == QLCNIC_DEV_NEED_QUISCENT)
		goto detach;

	heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
	if (heartbeat != adapter->heartbeat) {