Files
luban-lite/bsp/peripheral/wireless/atbm603x/hal/usb/atbm_usb_bh.c
刘可亮 8bca5e8332 v1.0.4
2024-04-03 16:40:57 +08:00

291 lines
8.8 KiB
C

/**************************************************************************************************************
* altobeam RTOS
*
* Copyright (c) 2018, altobeam.inc All rights reserved.
*
* The source code contains proprietary information of AltoBeam, and shall not be distributed,
* copied, reproduced, or disclosed in whole or in part without prior written permission of AltoBeam.
*****************************************************************************************************************/
#include "atbm_hal.h"
extern int wsm_recovery(struct atbmwifi_common *hw_priv);
int atbm_rx_bh_cb(struct atbmwifi_common *hw_priv,struct atbm_buff *skb, ATBM_BOOL checkseq)
{
struct wsm_hdr *wsm;
atbm_uint32 wsm_len;
int wsm_id;
atbm_uint8 wsm_seq;
//wifi_printk(WIFI_DBG_ERROR, "%s ++\n",__func__);
wsm = (struct wsm_hdr *)ATBM_OS_SKB_DATA(skb);
wsm_len = __atbm_le32_to_cpu(wsm->len);
wsm_id = __atbm_le32_to_cpu(wsm->id) & 0xFFF;
ATBM_BUG_ON(wsm_len > 4096);
atbm_skb_trim(skb,0);
atbm_skb_put(skb,wsm_len);
if (atbm_unlikely(wsm_id == 0x0800)) {
wsm_handle_exception(hw_priv,
&ATBM_OS_SKB_DATA(skb)[sizeof(*wsm)],
wsm_len - sizeof(*wsm));
if(wsm_recovery(hw_priv)== RECOVERY_ERR){
ATBM_BUG_ON(1);
}
goto __free;
}
if(checkseq){
wsm_seq = (__atbm_le32_to_cpu(wsm->id) >> 13) & 7;
if (ATBM_WARN_ON(wsm_seq != hw_priv->wsm_rx_seq)) {
wifi_printk(WIFI_DBG_ERROR,"rx wsm_seq error %d %d \n",wsm_seq,hw_priv->wsm_rx_seq);
if(wsm_recovery(hw_priv)== RECOVERY_ERR){
ATBM_BUG_ON(1);
}
goto __free;
}
hw_priv->wsm_rx_seq = (wsm_seq + 1) & 7;
}
if (wsm_id & 0x0400) {
int rc = wsm_release_tx_buffer(hw_priv, 1);
if (ATBM_WARN_ON(rc < 0)){
wifi_printk(WIFI_ALWAYS,"%s %d \n",__FUNCTION__,__LINE__);
ATBM_BUG_ON(1);
goto __free;
}
}
/* atbm_wsm_rx takes care on SKB livetime */
if (ATBM_WARN_ON(wsm_handle_rx(hw_priv, wsm_id, wsm,&skb))){
wifi_printk(WIFI_ALWAYS,"%s %d \n",__FUNCTION__,__LINE__);
if(wsm_recovery(hw_priv)== RECOVERY_ERR){
ATBM_BUG_ON(1);
}
goto __free;
}
__free:
//wifi_printk(WIFI_DBG_ERROR, "%s %d\n",__func__,__LINE__);
if(skb != ATBM_NULL){
atbm_dev_kfree_skb(skb);
}
return 0;
}
/*Tx Task Func*/
atbm_void atbm_tx_task(struct atbmwifi_common *hw_priv)
{
int status =0;
do {
//if(hw_priv->bh_term)|| (hw_priv->bh_error))
//{
// wifi_printk(WIFI_IF,"atbm_tx_task term(%d),err(%d)\n",atbm_atomic_read(&hw_priv->bh_term),hw_priv->bh_error);
// return;
//}
/*atbm transmit packet to device*/
hw_priv->sbus_ops->lock(hw_priv->sbus_priv);
status = hw_priv->sbus_ops->sbus_memcpy_toio(hw_priv->sbus_priv,0x1,ATBM_NULL,TX_BUFFER_SIZE);
hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
}while(status > 0);
}
/*Rx Task Func*/
atbm_void atbm_rx_task(struct atbmwifi_common *hw_priv)
{
struct atbm_buff *skb;
#if HI_RX_MUTIL_FRAME
struct wsm_hdr *wsm;
atbm_uint32 wsm_len, wsm_id, data_len;
struct atbm_buff *skb_copy;
ATBM_BOOL checkseq;
ATBM_BOOL multirx;
#endif
#define RX_ALLOC_BUFF_OFFLOAD ( (36+16)/*RX_DESC_OVERHEAD*/+4/*FCS_LEN*/ -16 /*WSM_HI_RX_IND*/)
while ((skb = atbm_skb_dequeue(&hw_priv->rx_frame_queue)) != ATBM_NULL) {
if(hw_priv->bh_term|| hw_priv->bh_error)
break;
#if HI_RX_MUTIL_FRAME
multirx = ATBM_FALSE;
checkseq = ATBM_TRUE;
wsm = (struct wsm_hdr *)ATBM_OS_SKB_DATA(skb);
wsm_len = __atbm_le32_to_cpu(wsm->len);
wsm_id = __atbm_le32_to_cpu(wsm->id) & 0xFFF;
//wifi_printk(WIFI_DBG_ERROR, "%s rxdata %x\n",__func__,wsm_id);
if(wsm_id == WSM_MULTI_RECEIVE_INDICATION_ID){
multirx = ATBM_TRUE;
}else if(wsm_id == WSM_SINGLE_CHANNEL_MULTI_RECEIVE_INDICATION_ID){
atbm_uint8 wsm_seq;
multirx = ATBM_TRUE;
wsm_seq = (__atbm_le32_to_cpu(wsm->id) >> 13) & 7;
if (ATBM_WARN_ON(wsm_seq != hw_priv->wsm_rx_seq)) {
wifi_printk(WIFI_DBG_ERROR,"rx wsm_seq error %d %d \n",wsm_seq,hw_priv->wsm_rx_seq);
if(wsm_recovery(hw_priv)== RECOVERY_ERR){
ATBM_BUG_ON(1);
}
goto multirx_end;
}
hw_priv->wsm_rx_seq = (wsm_seq + 1) & 7;
checkseq = ATBM_FALSE;
}
if(multirx){
struct wsm_multi_rx * multi_rx = (struct wsm_multi_rx *)ATBM_OS_SKB_DATA(skb);
int RxFrameNum = multi_rx->RxFrameNum;
data_len = wsm_len ;
data_len -= sizeof(struct wsm_multi_rx);
wsm = (struct wsm_hdr *)(multi_rx+1);
wsm_len = __atbm_le32_to_cpu(wsm->len);
wsm_id = __atbm_le32_to_cpu(wsm->id) & 0xFFF;
do {
if(data_len < wsm_len){
wifi_printk(WIFI_DBG_ERROR,"skb->len %x,wsm_len %x\n",ATBM_OS_SKB_LEN(skb),wsm_len);
break;
}
ATBM_BUG_ON((wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)) != WSM_RECEIVE_INDICATION_ID);
skb_copy = atbm_dev_alloc_skb(wsm_len + 16);
/* In AP mode RXed SKB can be looped back as a broadcast.
* Here we reserve enough space for headers. */
atbm_skb_reserve(skb_copy, (8 - (((unsigned long)ATBM_OS_SKB_DATA(skb_copy))&7))/*ATBM_ALIGN 8*/);
atbm_memmove(ATBM_OS_SKB_DATA(skb_copy), wsm, wsm_len);
atbm_skb_put(skb_copy,wsm_len);
atbm_rx_bh_cb(hw_priv,skb_copy,checkseq);
data_len -= ATBM_ALIGN(wsm_len + RX_ALLOC_BUFF_OFFLOAD,4);
RxFrameNum--;
wsm = (struct wsm_hdr *)((atbm_uint8 *)wsm +ATBM_ALIGN(( wsm_len + RX_ALLOC_BUFF_OFFLOAD),4));
wsm_len = __atbm_le32_to_cpu(wsm->len);
wsm_id = __atbm_le32_to_cpu(wsm->id) & 0xFFF;
}while((RxFrameNum>0) && (data_len > 32));
ATBM_BUG_ON(RxFrameNum != 0);
multirx_end:
#if RX_QUEUE_IMMD
if(skb->Type == RX_SKB__RX_QUEUE_PACKAGE){
/*atbm transmit packet to device*/
hw_priv->sbus_ops->lock(hw_priv->sbus_priv);
hw_priv->sbus_priv->rx_queue_qnum--;
hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
atbm_dev_kfree_skb(skb);
}else
#endif
{
//wifi_printk(WIFI_ALWAYS, "1 zzzz\n");
/*atbm transmit packet to device*/
hw_priv->sbus_ops->lock(hw_priv->sbus_priv);
hw_priv->sbus_ops->sbus_read_async(hw_priv->sbus_priv,0x2,skb,RX_BUFFER_SIZE);
hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
}
}
else
#endif
{
atbm_rx_bh_cb(hw_priv,skb,checkseq);
/*atbm transmit packet to device*/
hw_priv->sbus_ops->lock(hw_priv->sbus_priv);
#if RX_QUEUE_IMMD
if(skb->Type == RX_SKB__RX_QUEUE_PACKAGE){
hw_priv->sbus_priv->rx_queue_qnum--;
}else
#endif
{
//wifi_printk(WIFI_ALWAYS, "2 zzzz\n");
hw_priv->sbus_ops->sbus_read_async(hw_priv->sbus_priv,0x2,ATBM_NULL,RX_BUFFER_SIZE);
}
hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
}
}
}
atbm_void atbm_usb_bh(atbm_void *arg)
{
struct atbmwifi_common *hw_priv = (struct atbmwifi_common *)arg;
int rx=0, tx=0,urb_compl=0;
//int pending_tx = 0;
//ATBM_BOOL powersave_enabled;
//int loop=0;
//int prink_test =0;
#define __ALL_HW_BUFS_USED (hw_priv->hw_bufs_used)
while (1){
do {
rx = atbm_atomic_xchg(&hw_priv->bh_rx, 0);
tx = atbm_atomic_xchg(&hw_priv->bh_tx, 0);
urb_compl = atbm_atomic_xchg(&hw_priv->urb_comp, 0);
//suspend = pending_tx ?0 : atbm_atomic_read(&hw_priv->bh_suspend);
if(tx || rx|| urb_compl){
//atbm_os_try_to_wait_event_timeout(&hw_priv->bh_wq,1);
break;
}
atbm_os_wait_event_timeout(&hw_priv->bh_wq,100*HZ);
//wifi_printk(WIFI_ALWAYS,"atbm_usb_bh waitevent ---atbm_usb_bh\n");
rx = atbm_atomic_xchg(&hw_priv->bh_rx, 0);
tx = atbm_atomic_xchg(&hw_priv->bh_tx, 0);
urb_compl = atbm_atomic_xchg(&hw_priv->urb_comp, 0);
}while(0);
if ( hw_priv->bh_term || hw_priv->bh_error){
wifi_printk(WIFI_DBG_ERROR,"%s BH thread break %d %d\n",__FUNCTION__,hw_priv->bh_term,hw_priv->bh_error);
break;
}
if(urb_compl){
//wifi_printk(WIFI_ALWAYS," urb_compl ----->.\n");
atbm_urb_coml(hw_priv);
}
if (rx){
atbm_rx_task(hw_priv);
}
if (tx){
atbm_tx_task(hw_priv);
}
wifi_printk(WIFI_BH,"atbm_usb_bh while--\n");
}
wifi_printk(WIFI_DBG_ERROR, "%s --\n",__func__);
atbm_ThreadStopEvent(hw_priv->bh_thread);
}
int atbm_register_bh(struct atbmwifi_common *hw_priv)
{
atbm_thread_internal_t *bh_thread;
int status =0;
atbm_atomic_set(&hw_priv->bh_rx, 0);
atbm_atomic_set(&hw_priv->bh_tx, 0);
atbm_os_init_waitevent(&hw_priv->bh_wq);
atbm_os_init_waitevent(&hw_priv->wsm_cmd_wq);
hw_priv->bh_term=0;
hw_priv->bh_error=0;
wifi_printk(WIFI_DBG_ERROR,"atbm_register_bh\n");
/*Create RxData Task*/
bh_thread=atbm_createThreadInternal("atbm_bh",atbm_usb_bh,(atbm_void*)hw_priv,BH_TASK_PRIO);
if (!bh_thread){
wifi_printk(WIFI_DBG_ERROR,"bh_thread Failed\n");
return -1;
}
hw_priv->bh_thread = bh_thread;
#if USE_MAIL_BOX
/*create the usb tx complete mailbox*/
atbm_createMailBox((atbm_void*)hw_priv);
#endif
return status;
}
atbm_void atbm_unregister_bh(struct atbmwifi_common *hw_priv)
{
//kill createThread
hw_priv->bh_term=1;
atbm_os_wakeup_event(&hw_priv->bh_wq);
atbm_stopThread(hw_priv->bh_thread);
atbm_os_delete_waitevent(&hw_priv->bh_wq);
atbm_os_delete_waitevent(&hw_priv->wsm_cmd_wq);
atbm_os_DeleteMutex(&hw_priv->wsm_cmd_mux);
}