[WCNCR00169319] misc: Refine USB state to control USB WiFi path TX

[Description]
Change USB state to control USB WiFi path transmission
- Add spinlock_t rStateLock and related functions glUsbSetState() and
  glUsbSubmitUrb().
- Forbid any TX urb to be submitted when USB WiFi path not allowed.
- Refine spin locks used by USB.

Change-Id: Id7f36f0904d4a344d4c95140ca4ff86cb6171a52
CR-Id: WCNCR00169319
Feature: misc
Signed-off-by: Desmond Lin <desmond.lin@mediatek.com>
Reviewed-on: http://gerrit.mediatek.inc:8080/1241091
CheckPatch: Check Patch <srv_checkpatch@mediatek.com>
Reviewed-by: George Kuo <george.kuo@mediatek.com>
Reviewed-by: ZD Hu <zd.hu@mediatek.com>
Build: srv_neptune_adm <srv_neptune_adm@mediatek.com>
diff --git a/common/wlan_lib.c b/common/wlan_lib.c
index 81cd8a2..661a122 100644
--- a/common/wlan_lib.c
+++ b/common/wlan_lib.c
@@ -824,7 +824,7 @@
 	fgTimeout = FALSE;
 
 #if defined(_HIF_USB)
-	if (prAdapter->prGlueInfo->rHifInfo.state != USB_STATE_LINK_UP)
+	if (prAdapter->prGlueInfo->rHifInfo.state == USB_STATE_LINK_DOWN)
 		return WLAN_STATUS_FAILURE;
 #endif
 
diff --git a/os/linux/hif/usb/hal_api.c b/os/linux/hif/usb/hal_api.c
index a06b909..f5d31cc 100644
--- a/os/linux/hif/usb/hal_api.c
+++ b/os/linux/hif/usb/hal_api.c
@@ -250,10 +250,6 @@
 	P_HW_MAC_TX_DESC_T prTxDesc;
 	UINT_8 ucQueIdx;
 
-	if (prHifInfo->state != USB_STATE_LINK_UP &&
-	    !(prHifInfo->state == USB_STATE_PRE_RESUME && prCmdInfo->ucCID == 0))
-		return WLAN_STATUS_FAILURE;
-
 	prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxCmdFreeQ, &prHifInfo->rTxCmdQLock);
 	if (prUsbReq == NULL)
 		return WLAN_STATUS_RESOURCES;
@@ -301,16 +297,13 @@
 	prUsbReq->prUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 #endif
 	spin_lock_irqsave(&prHifInfo->rTxCmdQLock, flags);
-	u4Status = usb_submit_urb(prUsbReq->prUrb, GFP_ATOMIC);
+	u4Status = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb, SUBMIT_TYPE_TX_CMD);
 	if (u4Status) {
-		DBGLOG(HAL, ERROR, "usb_submit_urb() reports error (%d)\n", u4Status);
-		/* glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxCmdFreeQ, &prHifInfo->rTxCmdQLock, prUsbReq); */
+		DBGLOG(HAL, ERROR, "glUsbSubmitUrb() reports error (%d)\n", u4Status);
 		list_add_tail(&prUsbReq->list, &prHifInfo->rTxCmdFreeQ);
 		spin_unlock_irqrestore(&prHifInfo->rTxCmdQLock, flags);
 		return WLAN_STATUS_FAILURE;
 	}
-
-	/* glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxCmdSendingQ, &prHifInfo->rTxCmdQLock, prUsbReq); */
 	list_add_tail(&prUsbReq->list, &prHifInfo->rTxCmdSendingQ);
 	spin_unlock_irqrestore(&prHifInfo->rTxCmdQLock, flags);
 
@@ -427,19 +420,6 @@
 	memset(prBufCtrl->pucBuf + prBufCtrl->u4WrIdx, 0, LEN_USB_UDMA_TX_TERMINATOR);
 	prBufCtrl->u4WrIdx += LEN_USB_UDMA_TX_TERMINATOR;
 
-	if (prHifInfo->state != USB_STATE_LINK_UP) {
-		list_del_init(&prUsbReq->list);
-		list_add_tail(&prUsbReq->list, &prHifInfo->rTxDataCompleteQ);
-
-#if CFG_USB_TX_HANDLE_IN_HIF_THREAD
-		kalSetIntEvent(prGlueInfo);
-#else
-		/*tasklet_hi_schedule(&prGlueInfo->rTxCompleteTask);*/
-		tasklet_schedule(&prGlueInfo->rTxCompleteTask);
-#endif
-		return WLAN_STATUS_FAILURE;
-	}
-
 	list_del_init(&prUsbReq->list);
 
 	usb_fill_bulk_urb(prUsbReq->prUrb,
@@ -451,13 +431,19 @@
 #endif
 
 	usb_anchor_urb(prUsbReq->prUrb, &prHifInfo->rTxDataAnchor[ucTc]);
-	u4Status = usb_submit_urb(prUsbReq->prUrb, GFP_ATOMIC);
+	u4Status = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb, SUBMIT_TYPE_TX_DATA);
 	if (u4Status) {
-		DBGLOG(HAL, ERROR, "usb_submit_urb() reports error (%d) [%s]\n", u4Status, __func__);
+		DBGLOG(HAL, ERROR, "glUsbSubmitUrb() reports error (%d)\n", u4Status);
 		halTxUSBProcessMsduDone(prHifInfo->prGlueInfo, prUsbReq);
 		prBufCtrl->u4WrIdx = 0;
 		usb_unanchor_urb(prUsbReq->prUrb);
-		list_add_tail(&prUsbReq->list, &prHifInfo->rTxDataFreeQ[ucTc]);
+		list_add_tail(&prUsbReq->list, &prHifInfo->rTxDataCompleteQ);
+#if CFG_USB_TX_HANDLE_IN_HIF_THREAD
+		kalSetIntEvent(prGlueInfo);
+#else
+		/*tasklet_hi_schedule(&prGlueInfo->rTxCompleteTask);*/
+		tasklet_schedule(&prGlueInfo->rTxCompleteTask);
+#endif
 		return WLAN_STATUS_FAILURE;
 	}
 
@@ -485,11 +471,11 @@
 	u4Length = skb->len;
 	ucTc = USB_TRANS_MSDU_TC(prMsduInfo);
 #if CFG_USB_TX_AGG
-	spin_lock_irqsave(&prHifInfo->rTxDataFreeQLock, flags);
+	spin_lock_irqsave(&prHifInfo->rTxDataQLock, flags);
 
 	if (list_empty(&prHifInfo->rTxDataFreeQ[ucTc])) {
 		if (glUsbBorrowFfaReq(prHifInfo, ucTc) == FALSE) {
-			spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+			spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 			DBGLOG(HAL, ERROR, "run out of rTxDataFreeQ #1!!\n");
 			wlanProcessQueuedMsduInfo(prGlueInfo->prAdapter, prMsduInfo);
 			return WLAN_STATUS_RESOURCES;
@@ -508,7 +494,7 @@
 
 		if (list_empty(&prHifInfo->rTxDataFreeQ[ucTc])) {
 			if (glUsbBorrowFfaReq(prHifInfo, ucTc) == FALSE) {
-				spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+				spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 				DBGLOG(HAL, ERROR, "run out of rTxDataFreeQ #2!!\n");
 				wlanProcessQueuedMsduInfo(prGlueInfo->prAdapter, prMsduInfo);
 				return WLAN_STATUS_FAILURE;
@@ -534,9 +520,9 @@
 	if (usb_anchor_empty(&prHifInfo->rTxDataAnchor[ucTc]))
 		halTxUSBSendAggData(prHifInfo, ucTc, prUsbReq);
 
-	spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+	spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 #else
-	prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataFreeQ, &prHifInfo->rTxDataFreeQLock);
+	prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataFreeQ, &prHifInfo->rTxDataQLock);
 	if (prUsbReq == NULL) {
 		DBGLOG(HAL, ERROR, "run out of rTxDataFreeQ!!\n");
 		wlanProcessQueuedMsduInfo(prGlueInfo->prAdapter, prMsduInfo);
@@ -572,13 +558,13 @@
 #endif
 
 	usb_anchor_urb(prUsbReq->prUrb, &prHifInfo->rTxDataAnchor);
-	u4Status = usb_submit_urb(prUsbReq->prUrb, GFP_ATOMIC);
+	u4Status = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb, SUBMIT_TYPE_TX_DATA);
 	if (u4Status) {
-		DBGLOG(HAL, ERROR, "usb_submit_urb() reports error (%d) [%s]\n", u4Status, __func__);
+		DBGLOG(HAL, ERROR, "glUsbSubmitUrb() reports error (%d)\n", u4Status);
 		halTxUSBProcessMsduDone(prHifInfo->prGlueInfo, prUsbReq);
 		prBufCtrl->u4WrIdx = 0;
 		usb_unanchor_urb(prUsbReq->prUrb);
-		glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxDataFreeQ, prUsbReq, &prHifInfo->rTxDataFreeQLock, FALSE);
+		glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxDataFreeQ, prUsbReq, &prHifInfo->rTxDataQLock, FALSE);
 		return WLAN_STATUS_FAILURE;
 	}
 #endif
@@ -605,7 +591,7 @@
 	UINT_8 ucTc;
 	unsigned long flags;
 
-	spin_lock_irqsave(&prHifInfo->rTxDataFreeQLock, flags);
+	spin_lock_irqsave(&prHifInfo->rTxDataQLock, flags);
 
 	for (ucTc = TC0_INDEX; ucTc < USB_TC_NUM; ucTc++) {
 		if (list_empty(&prHifInfo->rTxDataFreeQ[ucTc]))
@@ -618,7 +604,7 @@
 			halTxUSBSendAggData(prHifInfo, ucTc, prUsbReq);
 	}
 
-	spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+	spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 #endif
 
 	return WLAN_STATUS_SUCCESS;
@@ -681,7 +667,7 @@
 
 	halTxUSBProcessMsduDone(prAdapter->prGlueInfo, prUsbReq);
 
-	spin_lock_irqsave(&prHifInfo->rTxDataFreeQLock, flags);
+	spin_lock_irqsave(&prHifInfo->rTxDataQLock, flags);
 #if CFG_USB_TX_AGG
 	prBufCtrl->u4WrIdx = 0;
 
@@ -700,7 +686,7 @@
 #else
 	list_add_tail(&prUsbReq->list, &prHifInfo->rTxDataFreeQ);
 #endif
-	spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+	spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 
 	if (!HAL_IS_TX_DIRECT(prAdapter)) {
 		if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0)
@@ -805,9 +791,6 @@
 	P_USB_REQ_T prUsbReq;
 	WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
 
-	if (/*prGlueInfo->ulFlag & GLUE_FLAG_HALT || */prHifInfo->state != USB_STATE_LINK_UP)
-		return WLAN_STATUS_FAILURE;
-
 	while (1) {
 		prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, &prHifInfo->rRxEventQLock);
 		if (prUsbReq == NULL)
@@ -829,10 +812,9 @@
 					  (void *)prUsbReq->prBufCtrl->pucBuf, prUsbReq->prBufCtrl->u4BufSize,
 					  halRxUSBReceiveEventComplete, (void *)prUsbReq);
 		}
-		u4Status = usb_submit_urb(prUsbReq->prUrb, GFP_ATOMIC);
-
+		u4Status = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb, SUBMIT_TYPE_RX_EVENT);
 		if (u4Status) {
-			DBGLOG(HAL, ERROR, "usb_submit_urb() reports error (%d) [%s]\n", u4Status, __func__);
+			DBGLOG(HAL, ERROR, "glUsbSubmitUrb() reports error (%d)\n", u4Status);
 			usb_unanchor_urb(prUsbReq->prUrb);
 			glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, prUsbReq,
 					&prHifInfo->rRxEventQLock, FALSE);
@@ -849,7 +831,7 @@
 	P_GL_HIF_INFO_T prHifInfo = prUsbReq->prHifInfo;
 	P_GLUE_INFO_T prGlueInfo = prHifInfo->prGlueInfo;
 
-	if (/*prGlueInfo->ulFlag & GLUE_FLAG_HALT || */prHifInfo->state != USB_STATE_LINK_UP) {
+	if (prHifInfo->state != USB_STATE_LINK_UP) {
 		glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, prUsbReq, &prHifInfo->rRxEventQLock, FALSE);
 		return;
 	}
@@ -895,9 +877,6 @@
 	P_USB_REQ_T prUsbReq;
 	WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
 
-	if (/*prGlueInfo->ulFlag & GLUE_FLAG_HALT || */prHifInfo->state != USB_STATE_LINK_UP)
-		return WLAN_STATUS_FAILURE;
-
 	while (1) {
 		prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, &prHifInfo->rRxDataQLock);
 		if (prUsbReq == NULL)
@@ -911,9 +890,9 @@
 				  usb_rcvbulkpipe(prHifInfo->udev, USB_DATA_EP_IN),
 				  (void *)prUsbReq->prBufCtrl->pucBuf,
 				  prUsbReq->prBufCtrl->u4BufSize, halRxUSBReceiveDataComplete, (void *)prUsbReq);
-		u4Status = usb_submit_urb(prUsbReq->prUrb, GFP_ATOMIC);
+		u4Status = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb, SUBMIT_TYPE_RX_DATA);
 		if (u4Status) {
-			DBGLOG(HAL, ERROR, "usb_submit_urb() reports error (%d) [%s]\n", u4Status, __func__);
+			DBGLOG(HAL, ERROR, "glUsbSubmitUrb() reports error (%d)\n", u4Status);
 			usb_unanchor_urb(prUsbReq->prUrb);
 			glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
 			break;
@@ -929,7 +908,7 @@
 	P_GL_HIF_INFO_T prHifInfo = prUsbReq->prHifInfo;
 	P_GLUE_INFO_T prGlueInfo = prHifInfo->prGlueInfo;
 
-	if (/*prGlueInfo->ulFlag & GLUE_FLAG_HALT || */prHifInfo->state != USB_STATE_LINK_UP) {
+	if (prHifInfo->state != USB_STATE_LINK_UP) {
 		glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
 		return;
 	}
@@ -1206,12 +1185,12 @@
 	u4Length = skb->len;
 	ucTc = USB_TRANS_MSDU_TC(prMsduInfo);
 
-	spin_lock_irqsave(&prHifInfo->rTxDataFreeQLock, flags);
+	spin_lock_irqsave(&prHifInfo->rTxDataQLock, flags);
 
 #if CFG_USB_TX_AGG
 	if (list_empty(&prHifInfo->rTxDataFreeQ[ucTc])) {
 		if (glUsbBorrowFfaReq(prHifInfo, ucTc) == FALSE) {
-			spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+			spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 			return FALSE;
 		}
 	}
@@ -1225,7 +1204,7 @@
 		    prBufCtrl->u4BufSize - prHifInfo->u4AggRsvSize[ucTc] - LEN_USB_UDMA_TX_TERMINATOR) {
 			/* Buffer is not enough */
 			if (glUsbBorrowFfaReq(prHifInfo, ucTc) == FALSE) {
-				spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+				spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 				return FALSE;
 			}
 		}
@@ -1233,13 +1212,13 @@
 	prHifInfo->u4AggRsvSize[ucTc] += ALIGN_4(u4Length);
 #else
 	if (list_empty(&prHifInfo->rTxDataFreeQ)) {
-		spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+		spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 
 		return FALSE;
 	}
 #endif
 
-	spin_unlock_irqrestore(&prHifInfo->rTxDataFreeQLock, flags);
+	spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
 	return TRUE;
 }
 
@@ -1257,10 +1236,10 @@
 	}
 
 	/* Process complete Tx data */
-	prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataCompleteQ, &prHifInfo->rTxCmdQLock);
+	prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataCompleteQ, &prHifInfo->rTxDataQLock);
 	while (prUsbReq) {
 		halTxUSBProcessDataComplete(prAdapter, prUsbReq);
-		prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataCompleteQ, &prHifInfo->rTxCmdQLock);
+		prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataCompleteQ, &prHifInfo->rTxDataQLock);
 	}
 #endif
 }
@@ -1414,20 +1393,7 @@
 	rCmdHifCtrl.ucHifType = ENUM_HIF_TYPE_USB;
 	rCmdHifCtrl.ucHifDirection = ENUM_HIF_TX;
 	rCmdHifCtrl.ucHifStop = 1;
-#if 0
-	rStatus = wlanSendSetQueryCmd(prAdapter,	/* prAdapter */
-				      CMD_ID_HIF_CTRL,	/* ucCID */
-				      FALSE,	/* fgSetQuery */
-				      TRUE,	/* fgNeedResp */
-				      FALSE,	/* fgIsOid */
-				      usbPreSuspendDone,	/* pfCmdDoneHandler */
-				      usbPreSuspendTimeout,	/* pfCmdTimeoutHandler */
-				      sizeof(CMD_HIF_CTRL_T),	/* u4SetQueryInfoLen */
-				      (PUINT_8)&rCmdHifCtrl,	/* pucInfoBuffer */
-				      NULL,	/* pvSetQueryBuffer */
-				      0	/* u4SetQueryBufferLen */
-	    );
-#else
+
 	rStatus = wlanSendSetQueryCmd(prAdapter,	/* prAdapter */
 				      CMD_ID_HIF_CTRL,	/* ucCID */
 				      TRUE,	/* fgSetQuery */
@@ -1439,24 +1405,45 @@
 				      (PUINT_8)&rCmdHifCtrl,	/* pucInfoBuffer */
 				      NULL,	/* pvSetQueryBuffer */
 				      0	/* u4SetQueryBufferLen */
-	    );
-#endif
+				     );
 
 	ASSERT(rStatus == WLAN_STATUS_PENDING);
 }
 
 VOID halUSBPreSuspendDone(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf)
 {
-	ASSERT(prAdapter);
+	unsigned long flags;
+	P_GL_HIF_INFO_T prHifInfo;
 
-	prAdapter->prGlueInfo->rHifInfo.state = USB_STATE_PRE_SUSPEND_DONE;
+	ASSERT(prAdapter);
+	prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
+
+	spin_lock_irqsave(&prHifInfo->rStateLock, flags);
+
+	if (prHifInfo->state == USB_STATE_LINK_UP)
+		prHifInfo->state = USB_STATE_PRE_SUSPEND_DONE;
+	else
+		DBGLOG(HAL, ERROR, "Previous USB state (%d)!\n", prHifInfo->state);
+
+	spin_unlock_irqrestore(&prHifInfo->rStateLock, flags);
 }
 
 VOID halUSBPreSuspendTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo)
 {
-	ASSERT(prAdapter);
+	unsigned long flags;
+	P_GL_HIF_INFO_T prHifInfo;
 
-	prAdapter->prGlueInfo->rHifInfo.state = USB_STATE_PRE_SUSPEND_FAIL;
+	ASSERT(prAdapter);
+	prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
+
+	spin_lock_irqsave(&prHifInfo->rStateLock, flags);
+
+	if (prHifInfo->state == USB_STATE_LINK_UP)
+		prHifInfo->state = USB_STATE_PRE_SUSPEND_FAIL;
+	else
+		DBGLOG(HAL, ERROR, "Previous USB state (%d)!\n", prHifInfo->state);
+
+	spin_unlock_irqrestore(&prHifInfo->rStateLock, flags);
 }
 
 UINT_32 halGetValidCoalescingBufSize(IN P_ADAPTER_T prAdapter)
@@ -1527,7 +1514,7 @@
 
 	rStatus = wlanCheckWifiFunc(prAdapter, FALSE);
 
-	prAdapter->prGlueInfo->rHifInfo.state = USB_STATE_WIFI_OFF;
+	glUsbSetState(&prAdapter->prGlueInfo->rHifInfo, USB_STATE_WIFI_OFF);
 
 	nicDisableInterrupt(prAdapter);
 
diff --git a/os/linux/hif/usb/include/hif.h b/os/linux/hif/usb/include/hif.h
index b415885..3e78ad6 100644
--- a/os/linux/hif/usb/include/hif.h
+++ b/os/linux/hif/usb/include/hif.h
@@ -217,6 +217,13 @@
 	USB_STATE_WIFI_OFF /* Hif power off wifi */
 };
 
+enum usb_submit_type {
+	SUBMIT_TYPE_TX_CMD,
+	SUBMIT_TYPE_TX_DATA,
+	SUBMIT_TYPE_RX_EVENT,
+	SUBMIT_TYPE_RX_DATA
+};
+
 typedef enum _EVENT_EP_TYPE {
 	EVENT_EP_TYPE_UNKONW,
 	EVENT_EP_TYPE_BULK,
@@ -242,6 +249,7 @@
 	spinlock_t rTxCmdQLock;
 	spinlock_t rRxEventQLock;
 	spinlock_t rRxDataQLock;
+	spinlock_t rStateLock;
 
 	PVOID prTxCmdReqHead;
 	PVOID arTxDataFfaReqHead;
@@ -261,17 +269,17 @@
 	struct list_head rTxDataFreeQ;
 	struct usb_anchor rTxDataAnchor;
 #endif
-	spinlock_t rTxDataFreeQLock;
+	/*spinlock_t rTxDataFreeQLock;*/
 	struct list_head rRxEventFreeQ;
-	spinlock_t rRxEventFreeQLock;
+	/*spinlock_t rRxEventFreeQLock;*/
 	struct usb_anchor rRxEventAnchor;
 	struct list_head rRxDataFreeQ;
-	spinlock_t rRxDataFreeQLock;
+	/*spinlock_t rRxDataFreeQLock;*/
 	struct usb_anchor rRxDataAnchor;
 	struct list_head rRxEventCompleteQ;
-	spinlock_t rRxEventCompleteQLock;
+	/*spinlock_t rRxEventCompleteQLock;*/
 	struct list_head rRxDataCompleteQ;
-	spinlock_t rRxDataCompleteQLock;
+	/*spinlock_t rRxDataCompleteQLock;*/
 	struct list_head rTxCmdCompleteQ;
 	struct list_head rTxDataCompleteQ;
 
@@ -362,6 +370,10 @@
 P_USB_REQ_T glUsbDequeueReq(P_GL_HIF_INFO_T prHifInfo, struct list_head *prHead, spinlock_t *prLock);
 BOOLEAN glUsbBorrowFfaReq(P_GL_HIF_INFO_T prHifInfo, UINT_8 ucTc);
 
+VOID glUsbSetState(P_GL_HIF_INFO_T prHifInfo, enum usb_state state);
+
+INT_32 glUsbSubmitUrb(P_GL_HIF_INFO_T prHifInfo, struct urb *urb, enum usb_submit_type type);
+
 WLAN_STATUS halTxUSBSendCmd(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucTc, IN P_CMD_INFO_T prCmdInfo);
 VOID halTxUSBSendCmdComplete(struct urb *urb);
 VOID halTxUSBProcessCmdComplete(IN P_ADAPTER_T prAdapter, P_USB_REQ_T prUsbReq);
diff --git a/os/linux/hif/usb/usb.c b/os/linux/hif/usb/usb.c
index fdfa851..9fae786 100644
--- a/os/linux/hif/usb/usb.c
+++ b/os/linux/hif/usb/usb.c
@@ -167,6 +167,14 @@
 *                   F U N C T I O N   D E C L A R A T I O N S
 ********************************************************************************
 */
+static int mtk_usb_probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void mtk_usb_disconnect(struct usb_interface *intf);
+static int mtk_usb_suspend(struct usb_interface *intf, pm_message_t message);
+static int mtk_usb_resume(struct usb_interface *intf);
+static int mtk_usb_reset_resume(struct usb_interface *intf);
+static int mtk_usb_bulk_in_msg(IN P_GL_HIF_INFO_T prHifInfo, IN UINT_32 len, OUT UCHAR * buffer, int InEp);
+static int mtk_usb_intr_in_msg(IN P_GL_HIF_INFO_T prHifInfo, IN UINT_32 len, OUT UCHAR * buffer, int InEp);
+static int mtk_usb_bulk_out_msg(IN P_GL_HIF_INFO_T prHifInfo, IN UINT_32 len, IN UCHAR * buffer, int OutEp);
 
 /*******************************************************************************
 *                              F U N C T I O N S
@@ -227,7 +235,7 @@
 	ASSERT(intf);
 	prGlueInfo  = (P_GLUE_INFO_T)usb_get_intfdata(intf);
 
-	prGlueInfo->rHifInfo.state = USB_STATE_LINK_DOWN;
+	glUsbSetState(&prGlueInfo->rHifInfo, USB_STATE_LINK_DOWN);
 
 	if (g_fgDriverProbed)
 		pfWlanRemove();
@@ -240,7 +248,7 @@
 	DBGLOG(HAL, STATE, "mtk_usb_disconnect() done\n");
 }
 
-int mtk_usb_suspend(struct usb_interface *intf, pm_message_t message)
+static int mtk_usb_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)usb_get_intfdata(intf);
 	UINT_8 count = 0;
@@ -262,17 +270,19 @@
 		count++;
 	}
 
-	prGlueInfo->rHifInfo.state = USB_STATE_SUSPEND;
+	glUsbSetState(&prGlueInfo->rHifInfo, USB_STATE_SUSPEND);
 	halDisableInterrupt(prGlueInfo->prAdapter);
 	halTxCancelAllSending(prGlueInfo->prAdapter);
 
 	DBGLOG(HAL, STATE, "mtk_usb_suspend() done!\n");
 
-	/* TODO */
+	if (ret && PMSG_IS_AUTO(message))
+		mtk_usb_resume(intf);
+
 	return ret;
 }
 
-int mtk_usb_resume(struct usb_interface *intf)
+static int mtk_usb_resume(struct usb_interface *intf)
 {
 	int ret = 0;
 	P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)usb_get_intfdata(intf);
@@ -287,11 +297,11 @@
 	if (ret)
 		DBGLOG(HAL, ERROR, "VendorRequest FeatureSetResume ERROR: %x\n", (unsigned int)ret);
 
-	prGlueInfo->rHifInfo.state = USB_STATE_PRE_RESUME;
+	glUsbSetState(&prGlueInfo->rHifInfo, USB_STATE_PRE_RESUME);
 	/* To trigger CR4 path */
 	wlanSendDummyCmd(prGlueInfo->prAdapter, FALSE);
 
-	prGlueInfo->rHifInfo.state = USB_STATE_LINK_UP;
+	glUsbSetState(&prGlueInfo->rHifInfo, USB_STATE_LINK_UP);
 	halEnableInterrupt(prGlueInfo->prAdapter);
 
 	wlanResumePmHandle(prGlueInfo);
@@ -302,7 +312,7 @@
 	return 0;
 }
 
-int mtk_usb_reset_resume(struct usb_interface *intf)
+static int mtk_usb_reset_resume(struct usb_interface *intf)
 {
 	DBGLOG(HAL, STATE, "mtk_usb_reset_resume()\n");
 
@@ -347,16 +357,6 @@
 		return -EFAULT;
 	}
 
-	/*
-	 * if (prHifInfo->state != USB_STATE_LINK_UP)
-	 *	return -EFAULT;
-	 */
-
-#if 0
-	if (prGlueInfo->ulFlag & GLUE_FLAG_HALT)
-		return FALSE;
-#endif
-
 	if (unlikely(TransferBufferLength > prHifInfo->vendor_req_buf_sz)) {
 		DBGLOG(REQ, ERROR, "len %u exceeds limit %zu\n", TransferBufferLength,
 			prHifInfo->vendor_req_buf_sz);
@@ -399,7 +399,7 @@
 /*!
 * \brief USB Bulk IN msg
 *
-* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure.
+* \param[in] prHifInfo  Pointer to the GL_HIF_INFO_T structure
 * \param[in] len
 * \param[in] buffer
 * \param[in] InEp
@@ -475,7 +475,7 @@
 /*!
 * \brief USB Bulk OUT msg
 *
-* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure.
+* \param[in] prHifInfo  Pointer to the GL_HIF_INFO_T structure
 * \param[in] len
 * \param[in] buffer
 * \param[in] OutEp
@@ -678,7 +678,7 @@
 /*!
 * \brief This function borrow UsbReq from Tx data FFA queue to the spcified TC Tx data free queue
 *
-* \param[in] prGlueInfo Pointer to HIF info structure
+* \param[in] prHifInfo  Pointer to the GL_HIF_INFO_T structure
 * \param[in] ucTc       Specify TC index
 *
 * \retval TRUE          operation success
@@ -702,6 +702,66 @@
 
 /*----------------------------------------------------------------------------*/
 /*!
+* \brief This function set USB state
+*
+* \param[in] prHifInfo  Pointer to the GL_HIF_INFO_T structure
+* \param[in] state      Specify TC index
+*
+* \retval TRUE          operation success
+* \retval FALSE         operation fail
+*/
+/*----------------------------------------------------------------------------*/
+VOID glUsbSetState(P_GL_HIF_INFO_T prHifInfo, enum usb_state state)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&prHifInfo->rStateLock, flags);
+	prHifInfo->state = state;
+	spin_unlock_irqrestore(&prHifInfo->rStateLock, flags);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+* \brief This function is a wrapper of submit urb to ensure driver can transmit
+*        WiFi packet when WiFi path of device is allowed.
+*
+* \param[in] prHifInfo  Pointer to the GL_HIF_INFO_T structure
+* \param[in] type       Specify submit type
+*
+* \retval 0		Successful submissions.
+* \retval negative	Error number.
+*/
+/*----------------------------------------------------------------------------*/
+INT_32 glUsbSubmitUrb(P_GL_HIF_INFO_T prHifInfo, struct urb *urb, enum usb_submit_type type)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (type == SUBMIT_TYPE_RX_EVENT || type == SUBMIT_TYPE_RX_DATA)
+		return usb_submit_urb(urb, GFP_ATOMIC);
+
+	spin_lock_irqsave(&prHifInfo->rStateLock, flags);
+	if (type == SUBMIT_TYPE_TX_CMD) {
+		if (!(prHifInfo->state == USB_STATE_LINK_UP || prHifInfo->state == USB_STATE_PRE_RESUME)) {
+			spin_unlock_irqrestore(&prHifInfo->rStateLock, flags);
+			DBGLOG(HAL, INFO, "WiFi path is not allowed to transmit CMD packet. (%d)\n", prHifInfo->state);
+			return -ESHUTDOWN;
+		}
+	} else if (type == SUBMIT_TYPE_TX_DATA) {
+		if (prHifInfo->state != USB_STATE_LINK_UP) {
+			spin_unlock_irqrestore(&prHifInfo->rStateLock, flags);
+			DBGLOG(HAL, INFO, "WiFi path is not allowed to transmit DATA packet. (%d)\n", prHifInfo->state);
+			return -ESHUTDOWN;
+		}
+	}
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	spin_unlock_irqrestore(&prHifInfo->rStateLock, flags);
+
+	return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
 * \brief This function stores hif related info, which is initialized before.
 *
 * \param[in] prGlueInfo Pointer to glue info structure
@@ -759,9 +819,9 @@
 
 	spin_lock_init(&prHifInfo->rTxCmdQLock);
 	spin_lock_init(&prHifInfo->rTxDataQLock);
-	spin_lock_init(&prHifInfo->rTxDataFreeQLock);
 	spin_lock_init(&prHifInfo->rRxEventQLock);
 	spin_lock_init(&prHifInfo->rRxDataQLock);
+	spin_lock_init(&prHifInfo->rStateLock);
 
 	mutex_init(&prHifInfo->vendor_req_sem);
 	prHifInfo->vendor_req_buf = kzalloc(VND_REQ_BUF_SIZE, GFP_KERNEL);
@@ -945,7 +1005,7 @@
 	glUsbInitQ(prHifInfo, &prHifInfo->rRxEventCompleteQ, 0);
 	glUsbInitQ(prHifInfo, &prHifInfo->rRxDataCompleteQ, 0);
 
-	prHifInfo->state = USB_STATE_LINK_UP;
+	glUsbSetState(prHifInfo, USB_STATE_LINK_UP);
 
 	return;