blob: d15a0f7ff008f8e0629468e3eea68d0985a99bc2 [file] [edit]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/******************************************************************************
*[File] hif_api.c
*[Version] v1.0
*[Revision Date] 2015-09-08
*[Author]
*[Description]
* The program provides USB HIF APIs
*[Copyright]
* Copyright (C) 2015 MediaTek Incorporation. All Rights Reserved.
******************************************************************************/
/*******************************************************************************
* C O M P I L E R F L A G S
********************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
#include "precomp.h"
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#ifndef CONFIG_X86
#include <asm/memory.h>
#endif
#include <linux/smp.h>
#include "mt66xx_reg.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
static const uint16_t arTcToUSBEP[USB_TC_NUM] = {
USB_DATA_BULK_OUT_EP4,
USB_DATA_BULK_OUT_EP5,
USB_DATA_BULK_OUT_EP6,
USB_DATA_BULK_OUT_EP7,
USB_DATA_BULK_OUT_EP8,
USB_DATA_BULK_OUT_EP9,
/* Second HW queue */
#if NIC_TX_ENABLE_SECOND_HW_QUEUE
USB_DATA_BULK_OUT_EP9,
USB_DATA_BULK_OUT_EP9,
USB_DATA_BULK_OUT_EP9,
USB_DATA_BULK_OUT_EP9,
#endif
};
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
/*----------------------------------------------------------------------------*/
/*!
* @brief Verify the CHIP ID
*
* @param prAdapter a pointer to adapter private data structure.
*
*
* @retval TRUE CHIP ID is the same as the setting compiled
* @retval FALSE CHIP ID is different from the setting compiled
*/
/*----------------------------------------------------------------------------*/
u_int8_t halVerifyChipID(IN struct ADAPTER *prAdapter)
{
uint32_t u4CIR = 0;
struct mt66xx_chip_info *prChipInfo;
ASSERT(prAdapter);
if (prAdapter->fgIsReadRevID)
return TRUE;
prChipInfo = prAdapter->chip_info;
HAL_MCR_RD(prAdapter, TOP_HCR, &u4CIR);
DBGLOG(INIT, TRACE, "Chip ID: 0x%4x\n", u4CIR);
if (u4CIR != prChipInfo->chip_id)
return FALSE;
HAL_MCR_RD(prAdapter, TOP_HVR, &u4CIR);
DBGLOG(INIT, TRACE, "Revision ID: 0x%4x\n", u4CIR);
prAdapter->ucRevID = (uint8_t) (u4CIR & 0xF);
prAdapter->fgIsReadRevID = TRUE;
return TRUE;
}
uint32_t
halRxWaitResponse(IN struct ADAPTER *prAdapter, IN uint8_t ucPortIdx, OUT uint8_t *pucRspBuffer,
IN uint32_t u4MaxRespBufferLen, OUT uint32_t *pu4Length)
{
struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
uint32_t u4Status = WLAN_STATUS_SUCCESS;
struct RX_CTRL *prRxCtrl;
u_int8_t ret = FALSE;
struct BUS_INFO *prBusInfo;
DEBUGFUNC("halRxWaitResponse");
ASSERT(prAdapter);
ASSERT(pucRspBuffer);
prRxCtrl = &prAdapter->rRxCtrl;
prBusInfo = prAdapter->chip_info->bus_info;
if (prBusInfo->asicUsbEventEpDetected)
ucPortIdx = prBusInfo->asicUsbEventEpDetected(prAdapter);
else {
if (prHifInfo->fgEventEpDetected == FALSE) {
/* NOTE: This is temporary compatiable code with old/new CR4 FW to detect
* which EVENT endpoint that.
* CR4 FW is using. If the new EP4IN-using CR4 FW works without
* any issue for a while,
* this code block will be removed.
*/
if (prAdapter->fgIsCr4FwDownloaded) {
ucPortIdx = USB_DATA_EP_IN;
ret = kalDevPortRead(prAdapter->prGlueInfo, ucPortIdx,
ALIGN_4(u4MaxRespBufferLen) + LEN_USB_RX_PADDING_CSO,
prRxCtrl->pucRxCoalescingBufPtr, HIF_RX_COALESCING_BUFFER_SIZE);
if (ret == TRUE) {
prHifInfo->eEventEpType = EVENT_EP_TYPE_DATA_EP;
} else {
ucPortIdx = USB_EVENT_EP_IN;
ret = kalDevPortRead(prAdapter->prGlueInfo, ucPortIdx,
ALIGN_4(u4MaxRespBufferLen) + LEN_USB_RX_PADDING_CSO,
prRxCtrl->pucRxCoalescingBufPtr, HIF_RX_COALESCING_BUFFER_SIZE);
}
prHifInfo->fgEventEpDetected = TRUE;
kalMemCopy(pucRspBuffer, prRxCtrl->pucRxCoalescingBufPtr, u4MaxRespBufferLen);
*pu4Length = u4MaxRespBufferLen;
if (ret == FALSE)
u4Status = WLAN_STATUS_FAILURE;
return u4Status;
}
ucPortIdx = USB_EVENT_EP_IN;
} else {
if (prHifInfo->eEventEpType == EVENT_EP_TYPE_DATA_EP)
if (prAdapter->fgIsCr4FwDownloaded)
ucPortIdx = USB_DATA_EP_IN;
else
ucPortIdx = USB_EVENT_EP_IN;
else
ucPortIdx = USB_EVENT_EP_IN;
}
}
ret = kalDevPortRead(prAdapter->prGlueInfo, ucPortIdx,
ALIGN_4(u4MaxRespBufferLen) + LEN_USB_RX_PADDING_CSO,
prRxCtrl->pucRxCoalescingBufPtr, HIF_RX_COALESCING_BUFFER_SIZE);
kalMemCopy(pucRspBuffer, prRxCtrl->pucRxCoalescingBufPtr, u4MaxRespBufferLen);
*pu4Length = u4MaxRespBufferLen;
if (ret == FALSE)
u4Status = WLAN_STATUS_FAILURE;
return u4Status;
}
uint32_t halTxUSBSendCmd(IN struct GLUE_INFO *prGlueInfo, IN uint8_t ucTc, IN struct CMD_INFO *prCmdInfo)
{
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
uint32_t u4Status = WLAN_STATUS_SUCCESS;
struct USB_REQ *prUsbReq;
struct BUF_CTRL *prBufCtrl;
uint16_t u2OverallBufferLength = 0;
unsigned long flags;
struct HW_MAC_TX_DESC *prTxDesc;
uint8_t ucQueIdx;
struct mt66xx_chip_info *prChipInfo;
int ret;
prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxCmdFreeQ, &prHifInfo->rTxCmdQLock);
if (prUsbReq == NULL) {
DBGLOG(HAL, ERROR, "TX CMD CID[0x%X] SEQ[%d] no URB!\n",
prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum);
return WLAN_STATUS_RESOURCES;
}
prBufCtrl = prUsbReq->prBufCtrl;
if ((TFCB_FRAME_PAD_TO_DW(prCmdInfo->u4TxdLen + prCmdInfo->u4TxpLen) + LEN_USB_UDMA_TX_TERMINATOR) >
prBufCtrl->u4BufSize) {
DBGLOG(HAL, ERROR, "Command TX buffer underflow!\n");
glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxCmdFreeQ, prUsbReq,
&prHifInfo->rTxCmdQLock, FALSE);
return WLAN_STATUS_RESOURCES;
}
DBGLOG(HAL, INFO, "TX CMD CID[0x%X] URB[0x%p] SEQ[%d]\n",
prCmdInfo->ucCID,
prUsbReq->prUrb, prCmdInfo->ucCmdSeqNum);
prChipInfo = prGlueInfo->prAdapter->chip_info;
HAL_WRITE_HIF_TXD(prChipInfo, prBufCtrl->pucBuf, (prCmdInfo->u4TxdLen + prCmdInfo->u4TxpLen));
u2OverallBufferLength += prChipInfo->u2HifTxdSize;
if (prCmdInfo->u4TxdLen) {
memcpy((prBufCtrl->pucBuf + u2OverallBufferLength), prCmdInfo->pucTxd, prCmdInfo->u4TxdLen);
u2OverallBufferLength += prCmdInfo->u4TxdLen;
}
if (prCmdInfo->u4TxpLen) {
memcpy((prBufCtrl->pucBuf + u2OverallBufferLength), prCmdInfo->pucTxp, prCmdInfo->u4TxpLen);
u2OverallBufferLength += prCmdInfo->u4TxpLen;
}
prTxDesc = (struct HW_MAC_TX_DESC *)prBufCtrl->pucBuf;
ucQueIdx = HAL_MAC_TX_DESC_GET_QUEUE_INDEX(prTxDesc);
/* For H2CDMA Tx CMD mapping */
/* Mapping port1 queue0~3 to queue28~31, and CR4 will unmask this */
HAL_MAC_TX_DESC_SET_QUEUE_INDEX(prTxDesc, (ucQueIdx | USB_TX_CMD_QUEUE_MASK));
/* DBGLOG_MEM32(SW4, INFO, prBufCtrl->pucBuf, 32); */
memset(prBufCtrl->pucBuf + u2OverallBufferLength, 0,
((TFCB_FRAME_PAD_TO_DW(u2OverallBufferLength) - u2OverallBufferLength) + LEN_USB_UDMA_TX_TERMINATOR));
prBufCtrl->u4WrIdx = TFCB_FRAME_PAD_TO_DW(u2OverallBufferLength) + LEN_USB_UDMA_TX_TERMINATOR;
prUsbReq->prPriv = (void *) prCmdInfo;
usb_fill_bulk_urb(prUsbReq->prUrb,
prHifInfo->udev,
usb_sndbulkpipe(prHifInfo->udev, arTcToUSBEP[ucTc]),
(void *)prUsbReq->prBufCtrl->pucBuf,
prBufCtrl->u4WrIdx, halTxUSBSendCmdComplete, (void *)prUsbReq);
#if CFG_USB_CONSISTENT_DMA
prUsbReq->prUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
#endif
spin_lock_irqsave(&prHifInfo->rTxCmdQLock, flags);
if (prHifInfo->prGlueInfo->prAdapter->ucSerState == SER_IDLE_DONE) {
ret = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb,
SUBMIT_TYPE_TX_CMD);
if (ret) {
DBGLOG(HAL, ERROR,
"glUsbSubmitUrb() error (0x%08X)(EP%d OUT)\n",
u4Status, arTcToUSBEP[ucTc]);
goto error;
}
} else {
DBGLOG(HAL, ERROR, "[SER] BYPASS USB send cmd\n");
/* THIS fw cmd would be dropped if SER is on-going. */
goto error;
}
list_add_tail(&prUsbReq->list, &prHifInfo->rTxCmdSendingQ);
spin_unlock_irqrestore(&prHifInfo->rTxCmdQLock, flags);
if (wlanIsChipRstRecEnabled(prGlueInfo->prAdapter)
&& wlanIsChipNoAck(prGlueInfo->prAdapter)) {
wlanChipRstPreAct(prGlueInfo->prAdapter);
DBGLOG(HAL, ERROR, "usb trigger whole reset\n");
HAL_WIFI_FUNC_CHIP_RESET(prGlueInfo->prAdapter);
}
return u4Status;
error:
list_add_tail(&prUsbReq->list, &prHifInfo->rTxCmdFreeQ);
spin_unlock_irqrestore(&prHifInfo->rTxCmdQLock, flags);
return WLAN_STATUS_FAILURE;
}
void halTxUSBSendCmdComplete(struct urb *urb)
{
struct USB_REQ *prUsbReq = urb->context;
struct GL_HIF_INFO *prHifInfo = prUsbReq->prHifInfo;
struct GLUE_INFO *prGlueInfo = prHifInfo->prGlueInfo;
unsigned long flags;
#if CFG_USB_TX_HANDLE_IN_HIF_THREAD
spin_lock_irqsave(&prHifInfo->rTxCmdQLock, flags);
list_del_init(&prUsbReq->list);
list_add_tail(&prUsbReq->list, &prHifInfo->rTxCmdCompleteQ);
spin_unlock_irqrestore(&prHifInfo->rTxCmdQLock, flags);
kalSetIntEvent(prGlueInfo);
#else
spin_lock_irqsave(&prHifInfo->rTxCmdQLock, flags);
list_del_init(&prUsbReq->list);
spin_unlock_irqrestore(&prHifInfo->rTxCmdQLock, flags);
halTxUSBProcessCmdComplete(prGlueInfo->prAdapter, prUsbReq);
#endif
}
void halTxUSBProcessCmdComplete(IN struct ADAPTER *prAdapter, struct USB_REQ *prUsbReq)
{
struct urb *urb = prUsbReq->prUrb;
uint32_t u4SentDataSize;
struct GL_HIF_INFO *prHifInfo = prUsbReq->prHifInfo;
if (urb->status != 0) {
DBGLOG(TX, ERROR, "[%s] send CMD fail (status = %d)\n", __func__, urb->status);
/* TODO: handle error */
}
DBGLOG(HAL, INFO, "TX CMD DONE: URB[0x%p]\n", urb);
glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxCmdFreeQ, prUsbReq, &prHifInfo->rTxCmdQLock, FALSE);
u4SentDataSize = urb->actual_length - LEN_USB_UDMA_TX_TERMINATOR;
nicTxReleaseResource_PSE(prAdapter, TC4_INDEX, nicTxGetPageCount(prAdapter, u4SentDataSize, TRUE), TRUE);
}
void halTxCancelSendingCmd(IN struct ADAPTER *prAdapter, IN struct CMD_INFO *prCmdInfo)
{
struct USB_REQ *prUsbReq, *prNext;
unsigned long flags;
struct urb *urb = NULL;
struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
spin_lock_irqsave(&prHifInfo->rTxCmdQLock, flags);
list_for_each_entry_safe(prUsbReq, prNext, &prHifInfo->rTxCmdSendingQ, list) {
if (prUsbReq->prPriv == (void *) prCmdInfo) {
list_del_init(&prUsbReq->list);
urb = prUsbReq->prUrb;
break;
}
}
spin_unlock_irqrestore(&prHifInfo->rTxCmdQLock, flags);
if (urb) {
prCmdInfo->pfHifTxCmdDoneCb = NULL;
usb_kill_urb(urb);
}
}
void halTxCancelAllSending(IN struct ADAPTER *prAdapter)
{
struct GLUE_INFO *prGlueInfo;
struct USB_REQ *prUsbReq, *prUsbReqNext;
struct GL_HIF_INFO *prHifInfo;
#if CFG_USB_TX_AGG
uint8_t ucTc;
#endif
ASSERT(prAdapter);
prGlueInfo = prAdapter->prGlueInfo;
prHifInfo = &prGlueInfo->rHifInfo;
list_for_each_entry_safe(prUsbReq, prUsbReqNext, &prHifInfo->rTxCmdSendingQ, list) {
usb_kill_urb(prUsbReq->prUrb);
}
#if CFG_USB_TX_AGG
for (ucTc = 0; ucTc < USB_TC_NUM; ++ucTc)
usb_kill_anchored_urbs(&prHifInfo->rTxDataAnchor[ucTc]);
#else
usb_kill_anchored_urbs(&prHifInfo->rTxDataAnchor);
#endif
nicTxReleaseSafe(prGlueInfo->prAdapter, FALSE);
}
#if CFG_USB_TX_AGG
uint32_t halTxUSBSendAggData(IN struct GL_HIF_INFO *prHifInfo, IN uint8_t ucTc, IN struct USB_REQ *prUsbReq)
{
struct GLUE_INFO *prGlueInfo = prHifInfo->prGlueInfo;
struct BUF_CTRL *prBufCtrl = prUsbReq->prBufCtrl;
uint32_t u4Status = WLAN_STATUS_SUCCESS;
int ret;
memset(prBufCtrl->pucBuf + prBufCtrl->u4WrIdx, 0, LEN_USB_UDMA_TX_TERMINATOR);
prBufCtrl->u4WrIdx += LEN_USB_UDMA_TX_TERMINATOR;
list_del_init(&prUsbReq->list);
usb_fill_bulk_urb(prUsbReq->prUrb,
prHifInfo->udev,
usb_sndbulkpipe(prHifInfo->udev, arTcToUSBEP[ucTc]),
(void *)prBufCtrl->pucBuf, prBufCtrl->u4WrIdx, halTxUSBSendDataComplete, (void *)prUsbReq);
#if CFG_USB_CONSISTENT_DMA
prUsbReq->prUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
#endif
usb_anchor_urb(prUsbReq->prUrb, &prHifInfo->rTxDataAnchor[ucTc]);
if (prHifInfo->prGlueInfo->prAdapter->ucSerState == SER_IDLE_DONE) {
ret = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb,
SUBMIT_TYPE_TX_DATA);
if (ret) {
DBGLOG(HAL, ERROR,
"glUsbSubmitUrb() error(0x%08X) (EP%d OUT)\n",
u4Status, arTcToUSBEP[ucTc]);
goto error;
}
} else {
DBGLOG(HAL, ERROR, "[SER] BYPASS USB send agg data\n");
goto error;
}
return u4Status;
error:
halTxUSBProcessMsduDone(prHifInfo->prGlueInfo, prUsbReq);
prBufCtrl->u4WrIdx = 0;
usb_unanchor_urb(prUsbReq->prUrb);
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;
}
#endif
uint32_t halTxUSBSendData(IN struct GLUE_INFO *prGlueInfo, IN struct MSDU_INFO *prMsduInfo)
{
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
struct mt66xx_chip_info *prChipInfo;
uint32_t u4Status = WLAN_STATUS_SUCCESS;
struct USB_REQ *prUsbReq;
struct BUF_CTRL *prBufCtrl;
uint32_t u4PaddingLength;
struct sk_buff *skb;
uint8_t ucTc;
uint8_t *pucBuf;
uint32_t u4Length;
uint32_t u4TotalLen;
unsigned long flags;
#if !CFG_USB_TX_AGG
int ret;
#endif
prChipInfo = prGlueInfo->prAdapter->chip_info;
skb = (struct sk_buff *)prMsduInfo->prPacket;
pucBuf = skb->data;
u4Length = skb->len;
u4TotalLen = u4Length + prChipInfo->u2HifTxdSize;
ucTc = USB_TRANS_MSDU_TC(prMsduInfo);
#if CFG_USB_TX_AGG
spin_lock_irqsave(&prHifInfo->rTxDataQLock, flags);
if (list_empty(&prHifInfo->rTxDataFreeQ[ucTc])) {
if (glUsbBorrowFfaReq(prHifInfo, ucTc) == FALSE) {
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
DBGLOG(HAL, ERROR, "run out of rTxDataFreeQ #1!!\n");
wlanProcessQueuedMsduInfo(prGlueInfo->prAdapter, prMsduInfo);
return WLAN_STATUS_RESOURCES;
}
}
prUsbReq = list_entry(prHifInfo->rTxDataFreeQ[ucTc].next, struct USB_REQ, list);
prBufCtrl = prUsbReq->prBufCtrl;
if (prHifInfo->u4AggRsvSize[ucTc] < ALIGN_4(u4TotalLen))
DBGLOG(HAL, ERROR, "u4AggRsvSize[%hhu] count FAIL (%u, %u)\n",
ucTc, prHifInfo->u4AggRsvSize[ucTc], u4TotalLen);
prHifInfo->u4AggRsvSize[ucTc] -= ALIGN_4(u4TotalLen);
if (prBufCtrl->u4WrIdx + ALIGN_4(u4TotalLen) + LEN_USB_UDMA_TX_TERMINATOR > prBufCtrl->u4BufSize) {
halTxUSBSendAggData(prHifInfo, ucTc, prUsbReq);
if (list_empty(&prHifInfo->rTxDataFreeQ[ucTc])) {
if (glUsbBorrowFfaReq(prHifInfo, ucTc) == FALSE) {
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock,
flags);
DBGLOG(HAL, ERROR, "run out of rTxDataFreeQ #2!!\n");
wlanProcessQueuedMsduInfo(prGlueInfo->prAdapter, prMsduInfo);
return WLAN_STATUS_FAILURE;
}
}
prUsbReq = list_entry(prHifInfo->rTxDataFreeQ[ucTc].next, struct USB_REQ, list);
prBufCtrl = prUsbReq->prBufCtrl;
}
HAL_WRITE_HIF_TXD(prChipInfo, prBufCtrl->pucBuf + prBufCtrl->u4WrIdx, u4Length);
prBufCtrl->u4WrIdx += prChipInfo->u2HifTxdSize;
memcpy(prBufCtrl->pucBuf + prBufCtrl->u4WrIdx, pucBuf, u4Length);
prBufCtrl->u4WrIdx += u4Length;
u4PaddingLength = (ALIGN_4(u4TotalLen) - u4TotalLen);
if (u4PaddingLength) {
memset(prBufCtrl->pucBuf + prBufCtrl->u4WrIdx, 0, u4PaddingLength);
prBufCtrl->u4WrIdx += u4PaddingLength;
}
if (!prMsduInfo->pfTxDoneHandler) {
QUEUE_INSERT_TAIL(&prUsbReq->rSendingDataMsduInfoList, (struct QUE_ENTRY *) prMsduInfo);
} else {
KAL_SPIN_LOCK_DECLARATION();
/* Record native packet pointer for Tx done log */
WLAN_GET_FIELD_32(&prMsduInfo->prPacket,
&prMsduInfo->u4TxDoneTag);
KAL_ACQUIRE_SPIN_LOCK(prGlueInfo->prAdapter,
SPIN_LOCK_TXING_MGMT_LIST);
QUEUE_INSERT_TAIL(
&(prGlueInfo->prAdapter->rTxCtrl.rTxMgmtTxingQueue),
(struct QUE_ENTRY *) prMsduInfo);
KAL_RELEASE_SPIN_LOCK(prGlueInfo->prAdapter,
SPIN_LOCK_TXING_MGMT_LIST);
}
if (usb_anchor_empty(&prHifInfo->rTxDataAnchor[ucTc]))
halTxUSBSendAggData(prHifInfo, ucTc, prUsbReq);
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
#else
prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataFreeQ,
&prHifInfo->rTxDataQLock);
if (prUsbReq == NULL) {
DBGLOG(HAL, ERROR, "run out of rTxDataFreeQ!!\n");
wlanProcessQueuedMsduInfo(prGlueInfo->prAdapter, prMsduInfo);
return WLAN_STATUS_RESOURCES;
}
prBufCtrl = prUsbReq->prBufCtrl;
prBufCtrl->u4WrIdx = 0;
HAL_WRITE_HIF_TXD(prChipInfo, prBufCtrl->pucBuf, u4Length);
prBufCtrl->u4WrIdx += prChipInfo->u2HifTxdSize;
memcpy(prBufCtrl->pucBuf + prChipInfo->u2HifTxdSize, pucBuf, u4Length);
prBufCtrl->u4WrIdx += u4Length;
u4PaddingLength = (ALIGN_4(u4TotalLen) - u4TotalLen);
if (u4PaddingLength) {
memset(prBufCtrl->pucBuf + prBufCtrl->u4WrIdx, 0, u4PaddingLength);
prBufCtrl->u4WrIdx += u4PaddingLength;
}
memset(prBufCtrl->pucBuf + prBufCtrl->u4WrIdx, 0, LEN_USB_UDMA_TX_TERMINATOR);
prBufCtrl->u4WrIdx += LEN_USB_UDMA_TX_TERMINATOR;
if (!prMsduInfo->pfTxDoneHandler) {
QUEUE_INSERT_TAIL(&prUsbReq->rSendingDataMsduInfoList, (struct QUE_ENTRY *) prMsduInfo);
} else {
KAL_SPIN_LOCK_DECLARATION();
/* Record native packet pointer for Tx done log */
WLAN_GET_FIELD_32(&prMsduInfo->prPacket,
&prMsduInfo->u4TxDoneTag);
KAL_ACQUIRE_SPIN_LOCK(prGlueInfo->prAdapter,
SPIN_LOCK_TXING_MGMT_LIST);
QUEUE_INSERT_TAIL(
&(prGlueInfo->prAdapter->rTxCtrl.rTxMgmtTxingQueue),
(struct QUE_ENTRY *) prMsduInfo);
KAL_RELEASE_SPIN_LOCK(prGlueInfo->prAdapter,
SPIN_LOCK_TXING_MGMT_LIST);
}
*((uint8_t *)&prUsbReq->prPriv) = ucTc;
usb_fill_bulk_urb(prUsbReq->prUrb,
prHifInfo->udev,
usb_sndbulkpipe(prHifInfo->udev, arTcToUSBEP[ucTc]),
(void *)prUsbReq->prBufCtrl->pucBuf,
prBufCtrl->u4WrIdx, halTxUSBSendDataComplete, (void *)prUsbReq);
#if CFG_USB_CONSISTENT_DMA
prUsbReq->prUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
#endif
usb_anchor_urb(prUsbReq->prUrb, &prHifInfo->rTxDataAnchor);
spin_lock_irqsave(&prHifInfo->rTxDataQLock, flags);
if (prHifInfo->prGlueInfo->prAdapter->ucSerState == SER_IDLE_DONE) {
ret = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb,
SUBMIT_TYPE_TX_DATA);
if (ret) {
DBGLOG(HAL, ERROR,
"glUsbSubmitUrb() error (0x%X) (EP%d OUT)\n",
ret, arTcToUSBEP[ucTc]);
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
halTxUSBProcessMsduDone(prHifInfo->prGlueInfo,
prUsbReq);
prBufCtrl->u4WrIdx = 0;
usb_unanchor_urb(prUsbReq->prUrb);
glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxDataFreeQ,
prUsbReq, &prHifInfo->rTxDataQLock,
FALSE);
return WLAN_STATUS_FAILURE;
}
} else {
DBGLOG(HAL, ERROR, "[SER] BYPASS USB send data\n");
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
halTxUSBProcessMsduDone(prHifInfo->prGlueInfo,
prUsbReq);
prBufCtrl->u4WrIdx = 0;
usb_unanchor_urb(prUsbReq->prUrb);
glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxDataFreeQ, prUsbReq,
&prHifInfo->rTxDataQLock, FALSE);
return WLAN_STATUS_FAILURE;
}
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
#endif
if (wlanIsChipRstRecEnabled(prGlueInfo->prAdapter)
&& wlanIsChipNoAck(prGlueInfo->prAdapter)) {
wlanChipRstPreAct(prGlueInfo->prAdapter);
DBGLOG(HAL, ERROR, "usb trigger whole reset\n");
HAL_WIFI_FUNC_CHIP_RESET(prGlueInfo->prAdapter);
}
return u4Status;
}
uint32_t halTxUSBKickData(IN struct GLUE_INFO *prGlueInfo)
{
#if CFG_USB_TX_AGG
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
struct USB_REQ *prUsbReq;
struct BUF_CTRL *prBufCtrl;
uint8_t ucTc;
unsigned long flags;
spin_lock_irqsave(&prHifInfo->rTxDataQLock, flags);
for (ucTc = TC0_INDEX; ucTc < USB_TC_NUM; ucTc++) {
if (list_empty(&prHifInfo->rTxDataFreeQ[ucTc]))
continue;
prUsbReq = list_entry(prHifInfo->rTxDataFreeQ[ucTc].next, struct USB_REQ, list);
prBufCtrl = prUsbReq->prBufCtrl;
if (prBufCtrl->u4WrIdx)
halTxUSBSendAggData(prHifInfo, ucTc, prUsbReq);
}
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
#endif
return WLAN_STATUS_SUCCESS;
}
void halTxUSBSendDataComplete(struct urb *urb)
{
struct USB_REQ *prUsbReq = urb->context;
struct GL_HIF_INFO *prHifInfo = prUsbReq->prHifInfo;
struct GLUE_INFO *prGlueInfo = prHifInfo->prGlueInfo;
glUsbEnqueueReq(prHifInfo, &prHifInfo->rTxDataCompleteQ, prUsbReq, &prHifInfo->rTxDataQLock, FALSE);
#if CFG_USB_TX_HANDLE_IN_HIF_THREAD
kalSetIntEvent(prGlueInfo);
#else
/*tasklet_hi_schedule(&prGlueInfo->rTxCompleteTask);*/
tasklet_schedule(&prGlueInfo->rTxCompleteTask);
#endif
}
void halTxUSBProcessMsduDone(IN struct GLUE_INFO *prGlueInfo, struct USB_REQ *prUsbReq)
{
uint8_t ucTc;
struct QUE rFreeQueue;
struct QUE *prFreeQueue;
struct urb *urb = prUsbReq->prUrb;
uint32_t u4SentDataSize;
if (g_u4HaltFlag) {
DBGLOG(TX, WARN, "wlan is halt\n");
return;
}
ucTc = *((uint8_t *)&prUsbReq->prPriv) & TC_MASK;
prFreeQueue = &rFreeQueue;
QUEUE_INITIALIZE(prFreeQueue);
QUEUE_MOVE_ALL((prFreeQueue), (&(prUsbReq->rSendingDataMsduInfoList)));
if (g_pfTxDataDoneCb)
g_pfTxDataDoneCb(prGlueInfo, prFreeQueue);
u4SentDataSize = urb->actual_length - LEN_USB_UDMA_TX_TERMINATOR;
nicTxReleaseResource_PSE(prGlueInfo->prAdapter, ucTc,
nicTxGetPageCount(prGlueInfo->prAdapter, u4SentDataSize, TRUE), TRUE);
}
void halTxUSBProcessDataComplete(IN struct ADAPTER *prAdapter, struct USB_REQ *prUsbReq)
{
uint8_t ucTc;
u_int8_t fgFfa;
struct urb *urb = prUsbReq->prUrb;
struct GL_HIF_INFO *prHifInfo = prUsbReq->prHifInfo;
#if CFG_USB_TX_AGG
struct BUF_CTRL *prBufCtrl = prUsbReq->prBufCtrl;
#endif
unsigned long flags;
ucTc = *((uint8_t *)&prUsbReq->prPriv) & TC_MASK;
fgFfa = *((uint8_t *)&prUsbReq->prPriv) & FFA_MASK;
if (urb->status != 0) {
DBGLOG(TX, ERROR, "[%s] send DATA fail (status = %d)\n", __func__, urb->status);
/* TODO: handle error */
}
halTxUSBProcessMsduDone(prAdapter->prGlueInfo, prUsbReq);
spin_lock_irqsave(&prHifInfo->rTxDataQLock, flags);
#if CFG_USB_TX_AGG
prBufCtrl->u4WrIdx = 0;
if ((fgFfa == FALSE) || list_empty(&prHifInfo->rTxDataFreeQ[ucTc]))
list_add_tail(&prUsbReq->list, &prHifInfo->rTxDataFreeQ[ucTc]);
else
list_add_tail(&prUsbReq->list, &prHifInfo->rTxDataFfaQ);
if (usb_anchor_empty(&prHifInfo->rTxDataAnchor[ucTc])) {
prUsbReq = list_entry(prHifInfo->rTxDataFreeQ[ucTc].next, struct USB_REQ, list);
prBufCtrl = prUsbReq->prBufCtrl;
if (prBufCtrl->u4WrIdx != 0)
halTxUSBSendAggData(prHifInfo, ucTc, prUsbReq); /* TODO */
}
#else
list_add_tail(&prUsbReq->list, &prHifInfo->rTxDataFreeQ);
#endif
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
if (!HAL_IS_TX_DIRECT(prAdapter)) {
if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0)
kalSetEvent(prAdapter->prGlueInfo);
kalSetTxEvent2Hif(prAdapter->prGlueInfo);
}
}
void halRxUSBSchedTask(void *info)
{
struct GLUE_INFO *prGlueInfo = (struct GLUE_INFO *)info;
/*tasklet_hi_schedule(&prGlueInfo->rRxTask);*/
tasklet_schedule(&prGlueInfo->rRxTask);
}
void halRxUSBDispatchCpu(struct GLUE_INFO *prGlueInfo)
{
#if CFG_USB_RX_DISPATCH_CPU
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
int cpuid, ret;
/* avoid possible deadlock when smp_call_function_single called
* with interrupts disabled.
*/
if (irqs_disabled()) {
tasklet_schedule(&prGlueInfo->rRxTask);
return;
}
if (unlikely(prHifInfo->rx_cpuid == INVALID_CPUID)) {
for_each_online_cpu(cpuid) {
if (cpuid != smp_processor_id()) {
prHifInfo->rx_cpuid = cpuid;
break;
}
}
if (prHifInfo->rx_cpuid == INVALID_CPUID)
prHifInfo->rx_cpuid = smp_processor_id();
DBGLOG(HAL, STATE, "Dipatch Rx cpuid (src, dst) = %d, %d\n",
smp_processor_id(), prHifInfo->rx_cpuid);
}
ret = smp_call_function_single(prHifInfo->rx_cpuid, halRxUSBSchedTask,
(void *)prGlueInfo, 0);
if (unlikely(ret != 0)) {
DBGLOG(HAL, ERROR, "smp_call_function_single ret = %d\n", ret);
halRxUSBSchedTask(prGlueInfo);
prHifInfo->rx_cpuid = INVALID_CPUID;
}
#else
halRxUSBSchedTask(prGlueInfo);
#endif /* CFG_USB_RX_DISPATCH_CPU */
}
uint32_t halRxUSBEnqueueRFB(IN struct ADAPTER *prAdapter, IN uint8_t *pucBuf, IN uint32_t u4Length,
IN uint32_t u4MinRfbCnt)
{
struct GLUE_INFO *prGlueInfo = prAdapter->prGlueInfo;
struct mt66xx_chip_info *prChipInfo;
struct RX_CTRL *prRxCtrl = &prAdapter->rRxCtrl;
struct SW_RFB *prSwRfb = (struct SW_RFB *) NULL;
struct HW_MAC_RX_DESC *prRxStatus;
uint32_t u4RemainCount;
uint16_t u2RxByteCount;
uint8_t *pucRxFrame;
uint32_t u4EnqCnt = 0;
#if CFG_TCP_IP_CHKSUM_OFFLOAD
uint32_t *pu4HwAppendDW;
#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */
KAL_SPIN_LOCK_DECLARATION();
ASSERT(prAdapter);
prChipInfo = prAdapter->chip_info;
pucRxFrame = pucBuf;
u4RemainCount = u4Length;
while (u4RemainCount > 4) {
u2RxByteCount = HAL_RX_STATUS_GET_RX_BYTE_CNT((struct HW_MAC_RX_DESC *) pucRxFrame);
u2RxByteCount = ALIGN_4(u2RxByteCount) + LEN_USB_RX_PADDING_CSO;
if (u2RxByteCount <= CFG_RX_MAX_PKT_SIZE) {
prSwRfb = NULL;
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
if (prRxCtrl->rFreeSwRfbList.u4NumElem > u4MinRfbCnt)
QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, struct SW_RFB *);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
if (!prSwRfb)
return u4Length - u4RemainCount;
kalMemCopy(prSwRfb->pucRecvBuff, pucRxFrame, u2RxByteCount);
prRxStatus = prSwRfb->prRxStatus;
ASSERT(prRxStatus);
prSwRfb->ucPacketType = (uint8_t) HAL_RX_STATUS_GET_PKT_TYPE(prRxStatus);
/* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */
#if CFG_TCP_IP_CHKSUM_OFFLOAD
pu4HwAppendDW = (uint32_t *) prRxStatus;
pu4HwAppendDW += (ALIGN_4(prRxStatus->u2RxByteCount) >> 2);
prSwRfb->u4TcpUdpIpCksStatus = *pu4HwAppendDW;
#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */
#if DBG
DBGLOG(RX, TRACE, "Rx status flag = %x wlan index = %d SecMode = %d\n",
prRxStatus->u2StatusFlag, prRxStatus->ucWlanIdx, HAL_RX_STATUS_GET_SEC_MODE(prRxStatus));
#endif
if (HAL_IS_RX_DIRECT(prAdapter)) {
switch (prSwRfb->ucPacketType) {
case RX_PKT_TYPE_RX_DATA:
if (HAL_MON_EN(prAdapter))
nicRxProcessMonitorPacket(
prAdapter, prSwRfb);
else
nicRxProcessDataPacket(
prAdapter, prSwRfb);
break;
default:
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE);
QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE);
u4EnqCnt++;
break;
}
} else {
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE);
QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE);
u4EnqCnt++;
}
RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT);
} else {
DBGLOG(RX, WARN, "Rx byte count:%u exceeds SW_RFB max length:%u\n!",
u2RxByteCount, CFG_RX_MAX_PKT_SIZE);
DBGLOG_MEM32(RX, WARN, pucRxFrame,
prChipInfo->rxd_size);
break;
}
u4RemainCount -= u2RxByteCount;
pucRxFrame += u2RxByteCount;
}
if (u4EnqCnt) {
set_bit(GLUE_FLAG_RX_BIT, &(prGlueInfo->ulFlag));
wake_up_interruptible(&(prGlueInfo->waitq));
}
return u4Length;
}
uint32_t halRxUSBReceiveEvent(IN struct ADAPTER *prAdapter, IN u_int8_t fgFillUrb)
{
struct GLUE_INFO *prGlueInfo = prAdapter->prGlueInfo;
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
struct USB_REQ *prUsbReq;
uint32_t u4Status = WLAN_STATUS_SUCCESS;
int ret;
while (1) {
prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, &prHifInfo->rRxEventQLock);
if (prUsbReq == NULL)
return WLAN_STATUS_RESOURCES;
usb_anchor_urb(prUsbReq->prUrb, &prHifInfo->rRxEventAnchor);
prUsbReq->prBufCtrl->u4ReadSize = 0;
if (prHifInfo->eEventEpType == EVENT_EP_TYPE_INTR && fgFillUrb) {
usb_fill_int_urb(prUsbReq->prUrb,
prHifInfo->udev,
usb_rcvintpipe(prHifInfo->udev,
USB_EVENT_EP_IN),
(void *)prUsbReq->prBufCtrl->pucBuf,
prUsbReq->prBufCtrl->u4BufSize,
halRxUSBReceiveEventComplete,
(void *)prUsbReq,
1);
} else if (prHifInfo->eEventEpType == EVENT_EP_TYPE_BULK) {
usb_fill_bulk_urb(prUsbReq->prUrb,
prHifInfo->udev,
usb_rcvbulkpipe(prHifInfo->udev,
USB_EVENT_EP_IN),
(void *)prUsbReq->prBufCtrl->pucBuf,
prUsbReq->prBufCtrl->u4BufSize,
halRxUSBReceiveEventComplete,
(void *)prUsbReq);
}
ret = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb,
SUBMIT_TYPE_RX_EVENT);
if (ret) {
DBGLOG(HAL, ERROR,
"glUsbSubmitUrb() reports error (%d) [%s] (EP%d IN)\n",
ret, __func__, (USB_EVENT_EP_IN & 0x0F));
usb_unanchor_urb(prUsbReq->prUrb);
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, prUsbReq,
&prHifInfo->rRxEventQLock, FALSE);
break;
}
}
return u4Status;
}
void halRxUSBReceiveEventComplete(struct urb *urb)
{
struct USB_REQ *prUsbReq = urb->context;
struct GL_HIF_INFO *prHifInfo = prUsbReq->prHifInfo;
struct GLUE_INFO *prGlueInfo = prHifInfo->prGlueInfo;
if (!(prHifInfo->state == USB_STATE_LINK_UP ||
prHifInfo->state == USB_STATE_READY ||
prHifInfo->state == USB_STATE_PRE_RESUME ||
prHifInfo->state == USB_STATE_PRE_SUSPEND_START)) {
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, prUsbReq, &prHifInfo->rRxEventQLock, FALSE);
return;
}
/* Hif power off wifi, drop rx packets and continue polling RX packets until RX path empty */
if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) {
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, prUsbReq, &prHifInfo->rRxEventQLock, FALSE);
halRxUSBReceiveEvent(prGlueInfo->prAdapter, FALSE);
return;
}
if (urb->status == -ESHUTDOWN || urb->status == -ENOENT) {
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, prUsbReq, &prHifInfo->rRxEventQLock, FALSE);
DBGLOG(RX, ERROR, "USB device shutdown skip Rx [%s]\n", __func__);
return;
}
#if CFG_USB_RX_HANDLE_IN_HIF_THREAD
DBGLOG(RX, TRACE, "[%s] Rx URB[0x%p] Len[%u] Sts[%u]\n", __func__, urb, urb->actual_length, urb->status);
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventCompleteQ, prUsbReq, &prHifInfo->rRxEventQLock, FALSE);
kalSetIntEvent(prGlueInfo);
#else
if (urb->status == 0) {
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventCompleteQ, prUsbReq, &prHifInfo->rRxEventQLock, FALSE);
halRxUSBDispatchCpu(prGlueInfo);
} else {
DBGLOG(RX, ERROR, "[%s] receive EVENT fail (status = %d)\n", __func__, urb->status);
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxEventFreeQ, prUsbReq, &prHifInfo->rRxEventQLock, FALSE);
halRxUSBReceiveEvent(prGlueInfo->prAdapter, FALSE);
}
#endif
}
uint32_t halRxUSBReceiveData(IN struct ADAPTER *prAdapter)
{
struct GLUE_INFO *prGlueInfo;
struct GL_HIF_INFO *prHifInfo;
struct USB_REQ *prUsbReq;
uint32_t u4Status = WLAN_STATUS_SUCCESS;
int ret;
if (!prAdapter) {
DBGLOG(INIT, WARN, "Adapter NULL\n");
return WLAN_STATUS_FAILURE;
}
prGlueInfo = prAdapter->prGlueInfo;
if (!prGlueInfo) {
DBGLOG(INIT, WARN, "prGlueInfo NULL\n");
return WLAN_STATUS_FAILURE;
}
prHifInfo = &prGlueInfo->rHifInfo;
while (1) {
prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, &prHifInfo->rRxDataQLock);
if (prUsbReq == NULL)
return WLAN_STATUS_RESOURCES;
usb_anchor_urb(prUsbReq->prUrb, &prHifInfo->rRxDataAnchor);
prUsbReq->prBufCtrl->u4ReadSize = 0;
usb_fill_bulk_urb(prUsbReq->prUrb,
prHifInfo->udev,
usb_rcvbulkpipe(prHifInfo->udev, USB_DATA_EP_IN),
(void *)prUsbReq->prBufCtrl->pucBuf,
prUsbReq->prBufCtrl->u4BufSize, halRxUSBReceiveDataComplete, (void *)prUsbReq);
ret = glUsbSubmitUrb(prHifInfo, prUsbReq->prUrb,
SUBMIT_TYPE_RX_DATA);
if (ret) {
DBGLOG(HAL, ERROR,
"glUsbSubmitUrb() reports error (%d) [%s] (EP%d IN)\n",
ret, __func__, (USB_EVENT_EP_IN & 0x0F));
usb_unanchor_urb(prUsbReq->prUrb);
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
break;
}
}
return u4Status;
}
void halRxUSBReceiveDataComplete(struct urb *urb)
{
struct USB_REQ *prUsbReq = urb->context;
struct GL_HIF_INFO *prHifInfo = prUsbReq->prHifInfo;
struct GLUE_INFO *prGlueInfo = prHifInfo->prGlueInfo;
if (!(prHifInfo->state == USB_STATE_LINK_UP ||
prHifInfo->state == USB_STATE_READY ||
prHifInfo->state == USB_STATE_PRE_RESUME ||
prHifInfo->state == USB_STATE_PRE_SUSPEND_START)) {
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
return;
}
/* Hif power off wifi, drop rx packets and continue polling RX packets until RX path empty */
if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) {
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
halRxUSBReceiveData(prGlueInfo->prAdapter);
return;
}
if (urb->status == -ESHUTDOWN || urb->status == -ENOENT) {
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
DBGLOG(RX, ERROR, "USB device shutdown skip Rx [%s]\n", __func__);
return;
}
#if CFG_USB_RX_HANDLE_IN_HIF_THREAD
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataCompleteQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
kalSetIntEvent(prGlueInfo);
#else
if (urb->status == 0) {
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataCompleteQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
halRxUSBDispatchCpu(prGlueInfo);
} else {
DBGLOG_LIMITED(RX, ERROR,
"Receive DATA fail (status = %d)\n", urb->status);
glUsbEnqueueReq(prHifInfo, &prHifInfo->rRxDataFreeQ, prUsbReq, &prHifInfo->rRxDataQLock, FALSE);
halRxUSBReceiveData(prGlueInfo->prAdapter);
}
#endif
}
void halRxUSBProcessEventDataComplete(IN struct ADAPTER *prAdapter,
enum usb_rx_type type)
{
struct USB_REQ *prUsbReq;
struct urb *prUrb;
struct BUF_CTRL *prBufCtrl;
struct GLUE_INFO *prGlueInfo = prAdapter->prGlueInfo;
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
uint8_t *pucBufAddr;
uint32_t u4BufLen;
static u_int8_t s_fgOutOfSwRfb = FALSE;
static uint32_t s_u4OutOfSwRfbPrintLimit;
struct list_head *prCompleteQ, *prFreeQ;
spinlock_t *prQLock;
uint32_t u4MinRfbCnt;
if (type == USB_RX_TYPE_DATA) {
prCompleteQ = &prHifInfo->rRxDataCompleteQ;
prFreeQ = &prHifInfo->rRxDataFreeQ;
prQLock = &prHifInfo->rRxDataQLock;
u4MinRfbCnt = USB_RX_DATA_RFB_RSV_CNT;
} else if (type == USB_RX_TYPE_EVENT) {
prCompleteQ = &prHifInfo->rRxEventCompleteQ;
prFreeQ = &prHifInfo->rRxEventFreeQ;
prQLock = &prHifInfo->rRxEventQLock;
u4MinRfbCnt = USB_RX_EVENT_RFB_RSV_CNT;
} else {
return;
}
/* Process complete event/data */
prUsbReq = glUsbDequeueReq(prHifInfo, prCompleteQ, prQLock);
while (prUsbReq) {
prUrb = prUsbReq->prUrb;
prBufCtrl = prUsbReq->prBufCtrl;
DBGLOG(RX, LOUD, "[%s] Rx URB[0x%p] Len[%u] Sts[%u]\n", __func__,
prUrb, prUrb->actual_length, prUrb->status);
if (prUrb->status != 0) {
DBGLOG(RX, ERROR, "[%s] receive EVENT/DATA fail (status = %d)\n", __func__, prUrb->status);
glUsbEnqueueReq(prHifInfo, prFreeQ, prUsbReq, prQLock,
FALSE);
prUsbReq = glUsbDequeueReq(prHifInfo, prCompleteQ,
prQLock);
continue;
}
pucBufAddr = prBufCtrl->pucBuf + prBufCtrl->u4ReadSize;
u4BufLen = prUrb->actual_length - prBufCtrl->u4ReadSize;
prBufCtrl->u4ReadSize += halRxUSBEnqueueRFB(prAdapter, pucBufAddr, u4BufLen, u4MinRfbCnt);
if (unlikely(prUrb->actual_length - prBufCtrl->u4ReadSize > 4)) {
if (s_fgOutOfSwRfb == FALSE) {
if ((long)jiffies - (long)s_u4OutOfSwRfbPrintLimit > 0) {
DBGLOG(RX, WARN, "Out of SwRfb!\n");
s_u4OutOfSwRfbPrintLimit = jiffies + MSEC_TO_JIFFIES(SW_RFB_LOG_LIMIT_MS);
}
s_fgOutOfSwRfb = TRUE;
}
glUsbEnqueueReq(prHifInfo, prCompleteQ, prUsbReq,
prQLock, TRUE);
set_bit(GLUE_FLAG_RX_BIT, &prGlueInfo->ulFlag);
wake_up_interruptible(&prGlueInfo->waitq);
schedule_delayed_work(&prGlueInfo->rRxPktDeAggWork, MSEC_TO_JIFFIES(SW_RFB_RECHECK_MS));
break;
}
if (unlikely(s_fgOutOfSwRfb == TRUE))
s_fgOutOfSwRfb = FALSE;
glUsbEnqueueReq(prHifInfo, prFreeQ, prUsbReq, prQLock, FALSE);
prUsbReq = glUsbDequeueReq(prHifInfo, prCompleteQ, prQLock);
}
}
/*----------------------------------------------------------------------------*/
/*!
* @brief enable global interrupt
*
* @param prAdapter pointer to the Adapter handler
*
* @return (none)
*/
/*----------------------------------------------------------------------------*/
void halEnableInterrupt(IN struct ADAPTER *prAdapter)
{
struct GLUE_INFO *prGlueInfo;
struct GL_HIF_INFO *prHifInfo;
ASSERT(prAdapter);
prGlueInfo = prAdapter->prGlueInfo;
prHifInfo = &prGlueInfo->rHifInfo;
halRxUSBReceiveData(prAdapter);
if (prHifInfo->eEventEpType != EVENT_EP_TYPE_DATA_EP)
halRxUSBReceiveEvent(prAdapter, TRUE);
glUdmaRxAggEnable(prGlueInfo, TRUE);
} /* end of halEnableInterrupt() */
/*----------------------------------------------------------------------------*/
/*!
* @brief disable global interrupt
*
* @param prAdapter pointer to the Adapter handler
*
* @return (none)
*/
/*----------------------------------------------------------------------------*/
void halDisableInterrupt(IN struct ADAPTER *prAdapter)
{
struct GLUE_INFO *prGlueInfo;
struct GL_HIF_INFO *prHifInfo;
ASSERT(prAdapter);
prGlueInfo = prAdapter->prGlueInfo;
prHifInfo = &prGlueInfo->rHifInfo;
usb_kill_anchored_urbs(&prHifInfo->rRxDataAnchor);
usb_kill_anchored_urbs(&prHifInfo->rRxEventAnchor);
glUdmaRxAggEnable(prGlueInfo, FALSE);
prAdapter->fgIsIntEnable = FALSE;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is used to process the POWER OFF procedure.
*
* \param[in] pvAdapter Pointer to the Adapter structure.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
u_int8_t halSetDriverOwn(IN struct ADAPTER *prAdapter)
{
return TRUE;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is used to process the POWER ON procedure.
*
* \param[in] pvAdapter Pointer to the Adapter structure.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
void halSetFWOwn(IN struct ADAPTER *prAdapter, IN u_int8_t fgEnableGlobalInt)
{
}
void halWakeUpWiFi(IN struct ADAPTER *prAdapter)
{
struct GL_HIF_INFO *prHifInfo;
u_int8_t fgResult;
uint8_t ucCount = 0;
DBGLOG(INIT, INFO, "Power on Wi-Fi....\n");
prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
HAL_WIFI_FUNC_READY_CHECK(prAdapter, WIFI_FUNC_INIT_DONE, &fgResult);
while (!fgResult) {
HAL_WIFI_FUNC_POWER_ON(prAdapter);
kalMdelay(50);
HAL_WIFI_FUNC_READY_CHECK(prAdapter, WIFI_FUNC_INIT_DONE, &fgResult);
ucCount++;
if (ucCount >= 5) {
DBGLOG(INIT, WARN, "Power on failed!!!\n");
break;
}
}
if (prHifInfo->state == USB_STATE_WIFI_OFF)
glUsbSetState(&prAdapter->prGlueInfo->rHifInfo,
USB_STATE_READY);
prAdapter->fgIsFwOwn = FALSE;
}
void halEnableFWDownload(IN struct ADAPTER *prAdapter, IN u_int8_t fgEnable)
{
#if (CFG_UMAC_GENERATION >= 0x20)
struct mt66xx_chip_info *prChipInfo;
ASSERT(prAdapter);
prChipInfo = prAdapter->chip_info;
if (prChipInfo->asicEnableFWDownload) {
prChipInfo->asicEnableFWDownload(prAdapter, fgEnable);
} else {
uint32_t u4Value = 0;
HAL_MCR_RD(prAdapter, UDMA_TX_QSEL, &u4Value);
if (fgEnable)
u4Value |= FW_DL_EN;
else
u4Value &= ~FW_DL_EN;
HAL_MCR_WR(prAdapter, UDMA_TX_QSEL, u4Value);
}
#endif
}
void halDevInit(IN struct ADAPTER *prAdapter)
{
struct GLUE_INFO *prGlueInfo;
ASSERT(prAdapter);
prGlueInfo = prAdapter->prGlueInfo;
glUdmaRxAggEnable(prGlueInfo, FALSE);
glUdmaTxRxEnable(prGlueInfo, TRUE);
asicUsbDmaShdlInit(prAdapter);
asicUdmaTxTimeoutEnable(prAdapter);
asicUdmaRxFlush(prAdapter, FALSE);
asicPdmaHifReset(prAdapter, TRUE);
}
u_int32_t halTxGetFreeCmdCnt(IN struct ADAPTER *prAdapter)
{
struct GLUE_INFO *prGlueInfo;
struct GL_HIF_INFO *prHifInfo;
struct USB_REQ *prUsbReq, *prNext;
unsigned long flags;
u_int16_t u2Cnt = 0;
if (prAdapter == NULL) {
DBGLOG(HAL, ERROR, "prAdapter is NULL error\n");
return 0;
}
prGlueInfo = prAdapter->prGlueInfo;
prHifInfo = &prGlueInfo->rHifInfo;
if (prHifInfo == NULL) {
DBGLOG(HAL, ERROR, "prHifInfo is NULL error\n");
return 0;
}
spin_lock_irqsave(&prHifInfo->rTxCmdQLock, flags);
list_for_each_entry_safe(prUsbReq,
prNext, &prHifInfo->rTxCmdFreeQ, list)
u2Cnt++;
spin_unlock_irqrestore(&prHifInfo->rTxCmdQLock, flags);
return u2Cnt;
}
u_int8_t halTxIsDataBufEnough(IN struct ADAPTER *prAdapter, IN struct MSDU_INFO *prMsduInfo)
{
struct GLUE_INFO *prGlueInfo = prAdapter->prGlueInfo;
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
#if CFG_USB_TX_AGG
struct USB_REQ *prUsbReq;
struct BUF_CTRL *prBufCtrl;
#endif
uint8_t ucTc;
struct sk_buff *skb;
uint32_t u4Length;
struct mt66xx_chip_info *prChipInfo;
unsigned long flags;
prChipInfo = prAdapter->chip_info;
skb = (struct sk_buff *)prMsduInfo->prPacket;
u4Length = skb->len;
u4Length += prChipInfo->u2HifTxdSize;
ucTc = USB_TRANS_MSDU_TC(prMsduInfo);
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->rTxDataQLock, flags);
return FALSE;
}
}
prUsbReq = list_entry(prHifInfo->rTxDataFreeQ[ucTc].next, struct USB_REQ, list);
prBufCtrl = prUsbReq->prBufCtrl;
if (prHifInfo->rTxDataFreeQ[ucTc].next->next == &prHifInfo->rTxDataFreeQ[ucTc]) {
/* length of rTxDataFreeQ equals 1 */
if (prBufCtrl->u4WrIdx + ALIGN_4(u4Length) >
prBufCtrl->u4BufSize - prHifInfo->u4AggRsvSize[ucTc] - LEN_USB_UDMA_TX_TERMINATOR) {
/* Buffer is not enough */
if (glUsbBorrowFfaReq(prHifInfo, ucTc) == FALSE) {
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock,
flags);
return FALSE;
}
}
}
prHifInfo->u4AggRsvSize[ucTc] += ALIGN_4(u4Length);
#else
if (list_empty(&prHifInfo->rTxDataFreeQ)) {
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
return FALSE;
}
#endif
spin_unlock_irqrestore(&prHifInfo->rTxDataQLock, flags);
return TRUE;
}
void halProcessTxInterrupt(IN struct ADAPTER *prAdapter)
{
#if CFG_USB_TX_HANDLE_IN_HIF_THREAD
struct USB_REQ *prUsbReq;
struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
/* Process complete Tx cmd */
prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxCmdCompleteQ, &prHifInfo->rTxCmdQLock);
while (prUsbReq) {
halTxUSBProcessCmdComplete(prAdapter, prUsbReq);
prUsbReq = glUsbDequeueReq(prHifInfo,
&prHifInfo->rTxCmdCompleteQ,
&prHifInfo->rTxCmdQLock);
}
/* Process complete Tx data */
prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataCompleteQ,
&prHifInfo->rTxDataQLock);
while (prUsbReq) {
halTxUSBProcessDataComplete(prAdapter, prUsbReq);
prUsbReq = glUsbDequeueReq(prHifInfo,
&prHifInfo->rTxDataCompleteQ,
&prHifInfo->rTxDataQLock);
}
#endif
}
bool halHifSwInfoInit(IN struct ADAPTER *prAdapter)
{
return true;
}
void halRxProcessMsduReport(IN struct ADAPTER *prAdapter, IN OUT struct SW_RFB *prSwRfb)
{
}
uint32_t halTxGetPageCount(IN struct ADAPTER *prAdapter, IN uint32_t u4FrameLength, IN u_int8_t fgIncludeDesc)
{
#if CFG_USB_TX_AGG
struct mt66xx_chip_info *prChipInfo = prAdapter->chip_info;
uint32_t u4RequiredBufferSize;
uint32_t u4PageCount;
uint32_t u4TxHeadRoomSize = NIC_TX_DESC_AND_PADDING_LENGTH + prChipInfo->txd_append_size;
/* Frame Buffer
* |<--Tx Descriptor-->|<--Tx descriptor padding-->|
* <--802.3/802.11 Header-->|<--Header padding-->|<--Payload-->|
*/
if (fgIncludeDesc)
u4RequiredBufferSize = u4FrameLength;
else
u4RequiredBufferSize = u4TxHeadRoomSize + u4FrameLength;
u4RequiredBufferSize = ALIGN_4(u4RequiredBufferSize);
if (NIC_TX_PAGE_SIZE_IS_POWER_OF_2)
u4PageCount = (u4RequiredBufferSize + (NIC_TX_PAGE_SIZE - 1)) >> NIC_TX_PAGE_SIZE_IN_POWER_OF_2;
else
u4PageCount = (u4RequiredBufferSize + (NIC_TX_PAGE_SIZE - 1)) / NIC_TX_PAGE_SIZE;
return u4PageCount;
#else
return 1;
#endif
}
uint32_t halTxPollingResource(IN struct ADAPTER *prAdapter, IN uint8_t ucTC)
{
return WLAN_STATUS_SUCCESS;
}
void halSerHifReset(IN struct ADAPTER *prAdapter)
{
uint32_t i;
/**
* usb_reset_endpoint - Reset an endpoint's state.
* @dev: the device whose endpoint is to be reset
* @epaddr: the endpoint's address. Endpoint number for output,
* endpoint number + USB_DIR_IN for input
*
* Resets any host-side endpoint state such as the toggle bit,
* sequence number or current window.
*
* void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
*/
/* reset ALL BULK OUT endpoints */
for (i = MTK_USB_BULK_OUT_MIN_EP; i <= MTK_USB_BULK_OUT_MAX_EP; i++)
usb_reset_endpoint(prAdapter->prGlueInfo->rHifInfo.udev, i);
/* reset ALL BULK IN endpoints */
for (i = MTK_USB_BULK_IN_MIN_EP; i <= MTK_USB_BULK_IN_MAX_EP; i++)
usb_reset_endpoint(prAdapter->prGlueInfo->rHifInfo.udev,
(i | USB_DIR_IN));
}
void halProcessRxInterrupt(IN struct ADAPTER *prAdapter)
{
struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
if (g_u4HaltFlag) {
DBGLOG(RX, WARN, "wlan is halt\n");
return;
}
/* Process complete data */
halRxUSBProcessEventDataComplete(prAdapter, USB_RX_TYPE_DATA);
halRxUSBReceiveData(prAdapter);
if (prHifInfo->eEventEpType != EVENT_EP_TYPE_DATA_EP) {
/* Process complete event */
halRxUSBProcessEventDataComplete(prAdapter, USB_RX_TYPE_EVENT);
halRxUSBReceiveEvent(prAdapter, FALSE);
}
}
uint32_t halDumpHifStatus(IN struct ADAPTER *prAdapter, IN uint8_t *pucBuf, IN uint32_t u4Max)
{
uint32_t u4CpuIdx, u4DmaIdx, u4Int, u4GloCfg, u4Reg;
uint32_t u4Len = 0;
struct GLUE_INFO *prGlueInfo = prAdapter->prGlueInfo;
uint8_t pBuffer[512] = {0};
HAL_MCR_RD(prAdapter, 0x820b0118, &u4CpuIdx);
HAL_MCR_RD(prAdapter, 0x820b011c, &u4DmaIdx);
HAL_MCR_RD(prAdapter, 0x820b0220, &u4Int);
HAL_MCR_RD(prAdapter, 0x820b0204, &u4GloCfg);
LOGBUF(pucBuf, u4Max, u4Len, "\n");
LOGBUF(pucBuf, u4Max, u4Len, "PDMA1R1 CPU[%u] DMA[%u] INT[0x%08x] CFG[0x%08x]\n", u4CpuIdx,
u4DmaIdx, u4Int, u4GloCfg);
HAL_MCR_RD(prAdapter, UDMA_WLCFG_0, &u4Reg);
LOGBUF(pucBuf, u4Max, u4Len, "UDMA WLCFG[0x%08x]\n", u4Reg);
LOGBUF(pucBuf, u4Max, u4Len, "\n");
LOGBUF(pucBuf, u4Max, u4Len, "VenderID: %04x\n",
glGetUsbDeviceVendorId(prGlueInfo->rHifInfo.udev));
LOGBUF(pucBuf, u4Max, u4Len, "ProductID: %04x\n",
glGetUsbDeviceProductId(prGlueInfo->rHifInfo.udev));
glGetUsbDeviceManufacturerName(prGlueInfo->rHifInfo.udev, pBuffer,
sizeof(pBuffer));
LOGBUF(pucBuf, u4Max, u4Len, "Manufacturer: %s\n",
pBuffer);
glGetUsbDeviceProductName(prGlueInfo->rHifInfo.udev, pBuffer,
sizeof(pBuffer));
LOGBUF(pucBuf, u4Max, u4Len, "Product: %s\n", pBuffer);
glGetUsbDeviceSerialNumber(prGlueInfo->rHifInfo.udev, pBuffer,
sizeof(pBuffer));
LOGBUF(pucBuf, u4Max, u4Len, "SerialNumber: %s\n",
pBuffer);
return u4Len;
}
void halGetCompleteStatus(IN struct ADAPTER *prAdapter, OUT uint32_t *pu4IntStatus)
{
#if CFG_USB_RX_HANDLE_IN_HIF_THREAD || CFG_USB_TX_HANDLE_IN_HIF_THREAD
struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
#endif
*pu4IntStatus = 0;
#if CFG_USB_RX_HANDLE_IN_HIF_THREAD
if (!list_empty(&prHifInfo->rRxDataCompleteQ) || !list_empty(&prHifInfo->rRxEventCompleteQ))
*pu4IntStatus |= WHISR_RX0_DONE_INT;
#endif
#if CFG_USB_TX_HANDLE_IN_HIF_THREAD
if (!list_empty(&prHifInfo->rTxDataCompleteQ) || !list_empty(&prHifInfo->rTxCmdCompleteQ))
*pu4IntStatus |= WHISR_TX_DONE_INT;
#endif
}
u_int8_t halIsPendingRx(IN struct ADAPTER *prAdapter)
{
#if CFG_USB_RX_HANDLE_IN_HIF_THREAD
struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
if (!list_empty(&prHifInfo->rRxDataCompleteQ) || !list_empty(&prHifInfo->rRxEventCompleteQ))
return TRUE;
else
return FALSE;
#else
return FALSE;
#endif
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Send HIF_CTRL command to inform FW stop send packet/event to host
* suspend = 1
*
* @param prAdapter Pointer to the Adapter structure.
*
* @return (void)
*/
/*----------------------------------------------------------------------------*/
void halPreSuspendCmd(IN struct ADAPTER *prAdapter)
{
struct CMD_HIF_CTRL rCmdHifCtrl;
uint32_t rStatus;
rCmdHifCtrl.ucHifType = ENUM_HIF_TYPE_USB;
rCmdHifCtrl.ucHifDirection = ENUM_HIF_TX;
rCmdHifCtrl.ucHifStop = 1;
rCmdHifCtrl.ucHifSuspend = 1;
rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */
CMD_ID_HIF_CTRL, /* ucCID */
TRUE, /* fgSetQuery */
FALSE, /* fgNeedResp */
FALSE, /* fgIsOid */
NULL, /* pfCmdDoneHandler */
NULL, /* pfCmdTimeoutHandler */
sizeof(struct CMD_HIF_CTRL),
(uint8_t *)&rCmdHifCtrl,
NULL, /* pvSetQueryBuffer */
0 /* u4SetQueryBufferLen */
);
if (kalIsResetting())
return;
ASSERT(rStatus == WLAN_STATUS_PENDING);
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Send HIF_CTRL command to inform FW allow send packet/event to host
* suspend = 0
*
* @param prAdapter Pointer to the Adapter structure.
*
* @return (void)
*/
/*----------------------------------------------------------------------------*/
void halPreResumeCmd(IN struct ADAPTER *prAdapter)
{
struct CMD_HIF_CTRL rCmdHifCtrl;
uint32_t rStatus;
rCmdHifCtrl.ucHifType = ENUM_HIF_TYPE_USB;
rCmdHifCtrl.ucHifDirection = ENUM_HIF_TX;
rCmdHifCtrl.ucHifStop = 0;
rCmdHifCtrl.ucHifSuspend = 0;
rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */
CMD_ID_HIF_CTRL, /* ucCID */
TRUE, /* fgSetQuery */
FALSE, /* fgNeedResp */
FALSE, /* fgIsOid */
NULL, /* nicEventHifCtrl */
NULL, /* pfCmdTimeoutHandler */
sizeof(struct CMD_HIF_CTRL),
(uint8_t *)&rCmdHifCtrl, /* pucInfoBuffer */
NULL, /* pvSetQueryBuffer */
0 /* u4SetQueryBufferLen */
);
if (kalIsResetting())
return;
ASSERT(rStatus == WLAN_STATUS_PENDING);
}
void halUSBPreSuspendDone(IN struct ADAPTER *prAdapter, IN struct CMD_INFO *prCmdInfo, IN uint8_t *pucEventBuf)
{
unsigned long flags;
struct GL_HIF_INFO *prHifInfo;
ASSERT(prAdapter);
prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
spin_lock_irqsave(&prHifInfo->rStateLock, flags);
if (prHifInfo->state == USB_STATE_LINK_UP ||
prHifInfo->state == USB_STATE_READY ||
prHifInfo->state == USB_STATE_PRE_SUSPEND_START)
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 struct ADAPTER *prAdapter, IN struct CMD_INFO *prCmdInfo)
{
unsigned long flags;
struct GL_HIF_INFO *prHifInfo;
ASSERT(prAdapter);
prHifInfo = &prAdapter->prGlueInfo->rHifInfo;
spin_lock_irqsave(&prHifInfo->rStateLock, flags);
if (prHifInfo->state == USB_STATE_LINK_UP ||
prHifInfo->state == USB_STATE_READY ||
prHifInfo->state == USB_STATE_PRE_SUSPEND_START)
prHifInfo->state = USB_STATE_PRE_SUSPEND_FAIL;
else
DBGLOG(HAL, ERROR, "Previous USB state (%d)!\n",
prHifInfo->state);
spin_unlock_irqrestore(&prHifInfo->rStateLock, flags);
}
uint32_t halGetValidCoalescingBufSize(IN struct ADAPTER *prAdapter)
{
uint32_t u4BufSize;
if (HIF_TX_COALESCING_BUFFER_SIZE > HIF_RX_COALESCING_BUFFER_SIZE)
u4BufSize = HIF_TX_COALESCING_BUFFER_SIZE;
else
u4BufSize = HIF_RX_COALESCING_BUFFER_SIZE;
return u4BufSize;
}
uint32_t halAllocateIOBuffer(IN struct ADAPTER *prAdapter)
{
return WLAN_STATUS_SUCCESS;
}
uint32_t halReleaseIOBuffer(IN struct ADAPTER *prAdapter)
{
return WLAN_STATUS_SUCCESS;
}
void halProcessAbnormalInterrupt(IN struct ADAPTER *prAdapter)
{
}
void halProcessSoftwareInterrupt(IN struct ADAPTER *prAdapter)
{
}
void halDeAggRxPktWorker(struct work_struct *work)
{
struct GLUE_INFO *prGlueInfo = ENTRY_OF(work, struct GLUE_INFO, rRxPktDeAggWork);
halRxUSBDispatchCpu(prGlueInfo);
}
void halRxTasklet(unsigned long data)
{
struct GLUE_INFO *prGlueInfo = (struct GLUE_INFO *)data;
#if CFG_USB_RX_DISPATCH_CPU
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
if (smp_processor_id() == prHifInfo->rx_cpuid)
halProcessRxInterrupt(prGlueInfo->prAdapter);
else
halRxUSBDispatchCpu(prGlueInfo);
#else
halProcessRxInterrupt(prGlueInfo->prAdapter);
#endif /* CFG_USB_RX_DISPATCH_CPU */
}
void halTxCompleteTasklet(unsigned long data)
{
struct GLUE_INFO *prGlueInfo = (struct GLUE_INFO *)data;
struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo;
struct USB_REQ *prUsbReq;
/* Process complete Tx data */
prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataCompleteQ, &prHifInfo->rTxDataQLock);
while (prUsbReq) {
halTxUSBProcessDataComplete(prGlueInfo->prAdapter, prUsbReq);
prUsbReq = glUsbDequeueReq(prHifInfo, &prHifInfo->rTxDataCompleteQ, &prHifInfo->rTxDataQLock);
}
}
/* Hif power off wifi */
uint32_t halHifPowerOffWifi(IN struct ADAPTER *prAdapter)
{
uint32_t rStatus = WLAN_STATUS_SUCCESS;
DBGLOG(INIT, INFO, "Power off Wi-Fi!\n");
/* Power off Wi-Fi */
wlanSendNicPowerCtrlCmd(prAdapter, TRUE);
rStatus = wlanCheckWifiFunc(prAdapter, FALSE);
glUsbSetState(&prAdapter->prGlueInfo->rHifInfo, USB_STATE_WIFI_OFF);
nicDisableInterrupt(prAdapter);
wlanClearPendingInterrupt(prAdapter);
halTxCancelAllSending(prAdapter);
return rStatus;
}
void halPrintHifDbgInfo(IN struct ADAPTER *prAdapter)
{
struct CHIP_DBG_OPS *prDbgOps;
prDbgOps = prAdapter->chip_info->prDebugOps;
if (prAdapter->u4HifDbgFlag & (DEG_HIF_ALL | DEG_HIF_PSE))
prDbgOps->showPseInfo(prAdapter);
if (prAdapter->u4HifDbgFlag & (DEG_HIF_ALL | DEG_HIF_PLE))
prDbgOps->showPleInfo(prAdapter);
prAdapter->u4HifDbgFlag = 0;
}
u_int8_t halIsTxResourceControlEn(IN struct ADAPTER *prAdapter)
{
return FALSE;
}
void halTxResourceResetHwTQCounter(IN struct ADAPTER *prAdapter)
{
}
uint32_t halGetHifTxPageSize(IN struct ADAPTER *prAdapter)
{
return HIF_TX_PAGE_SIZE;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Check if HIF state is READY for upper layer cfg80211
*
* @param prAdapter Pointer to the Adapter structure.
*
* @return (TRUE: ready, FALSE: not ready)
*/
/*----------------------------------------------------------------------------*/
bool halIsHifStateReady(IN struct ADAPTER *prAdapter, uint8_t *pucState)
{
if (!prAdapter)
return FALSE;
if (!prAdapter->prGlueInfo)
return FALSE;
if (prAdapter->prGlueInfo->u4ReadyFlag == 0)
return FALSE;
if (pucState)
*pucState = prAdapter->prGlueInfo->rHifInfo.state;
if (prAdapter->prGlueInfo->rHifInfo.state != USB_STATE_READY)
return FALSE;
return TRUE;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Check if HIF state is LINK_UP or READY for USB TX/RX
*
* @param prAdapter Pointer to the Adapter structure.
*
* @return (TRUE: ready, FALSE: not ready)
*/
/*----------------------------------------------------------------------------*/
bool halIsHifStateLinkup(IN struct ADAPTER *prAdapter)
{
if (!prAdapter)
return FALSE;
if (!prAdapter->prGlueInfo)
return FALSE;
if ((prAdapter->prGlueInfo->rHifInfo.state != USB_STATE_LINK_UP) &&
(prAdapter->prGlueInfo->rHifInfo.state != USB_STATE_READY))
return FALSE;
return TRUE;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief Check if HIF state is during supend process
*
* @param prAdapter Pointer to the Adapter structure.
*
* @return (TRUE: suspend, reject the caller action. FALSE: not suspend)
*/
/*----------------------------------------------------------------------------*/
bool halIsHifStateSuspend(IN struct ADAPTER *prAdapter)
{
enum usb_state state;
if (!prAdapter)
return FALSE;
if (!prAdapter->prGlueInfo)
return FALSE;
state = prAdapter->prGlueInfo->rHifInfo.state;
if (state == USB_STATE_SUSPEND)
return TRUE;
return FALSE;
}