project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp: Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem. sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately. sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades. sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for fastboot. Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
1314 lines
39 KiB
C
1314 lines
39 KiB
C
#include <net/atbm_mac80211.h>
|
||
#include <linux/kthread.h>
|
||
|
||
#include "apollo.h"
|
||
#include "bh.h"
|
||
#include "bh_usb.h"
|
||
#include "hwio.h"
|
||
#include "wsm.h"
|
||
#include "sbus.h"
|
||
#include "debug.h"
|
||
#include "apollo_plat.h"
|
||
#include "sta.h"
|
||
#include "ap.h"
|
||
#include "scan.h"
|
||
//#define DBG_EVENT_LOG
|
||
#include "dbg_event.h"
|
||
#if defined(CONFIG_ATBM_APOLLO_BH_DEBUG)
|
||
#define bh_printk atbm_printk_always
|
||
#else
|
||
#define bh_printk(...)
|
||
#endif
|
||
extern void atbm_hif_status_set(int status);
|
||
static int usb_atbm_bh(void *arg);
|
||
void atbm_monitor_pc(struct atbm_common *hw_priv);
|
||
extern int atbm_usb_pm(struct sbus_priv *self, bool suspend);
|
||
|
||
int atbm_register_bh(struct atbm_common *hw_priv)
|
||
{
|
||
int err = 0;
|
||
struct sched_param param = { .sched_priority = 1 };
|
||
bh_printk( "[BH] register.\n");
|
||
// BUG_ON(hw_priv->bh_thread);
|
||
if(hw_priv->bh_thread){
|
||
atbm_printk_err("%s %d ,ERROR !!! hw_priv->bh_thread is runing\n",__func__,__LINE__);
|
||
WARN_ON(hw_priv->bh_thread);
|
||
return 0;
|
||
}
|
||
atomic_set(&hw_priv->bh_rx, 0);
|
||
atomic_set(&hw_priv->bh_suspend_usb, 1);
|
||
atomic_set(&hw_priv->bh_tx, 0);
|
||
atomic_set(&hw_priv->bh_halt,0);
|
||
atomic_set(&hw_priv->bh_term, 0);
|
||
atomic_set(&hw_priv->bh_suspend, ATBM_APOLLO_BH_RESUMED);
|
||
|
||
hw_priv->wsm_rx_seq = 0;
|
||
hw_priv->wsm_tx_seq = 0;
|
||
hw_priv->buf_id_tx = 0;
|
||
hw_priv->buf_id_rx = 0;
|
||
init_waitqueue_head(&hw_priv->bh_wq);
|
||
init_waitqueue_head(&hw_priv->bh_evt_wq);
|
||
|
||
hw_priv->bh_thread = kthread_create(&usb_atbm_bh, hw_priv, ieee80211_alloc_name(hw_priv->hw,"usb_atbm_bh"));
|
||
|
||
if (IS_ERR(hw_priv->bh_thread)) {
|
||
err = PTR_ERR(hw_priv->bh_thread);
|
||
hw_priv->bh_thread = NULL;
|
||
} else {
|
||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 9, 8))
|
||
sched_set_fifo_low(hw_priv->bh_thread);
|
||
#else
|
||
sched_setscheduler(hw_priv->bh_thread,
|
||
SCHED_FIFO, ¶m);
|
||
#endif
|
||
#ifdef HAS_PUT_TASK_STRUCT
|
||
get_task_struct(hw_priv->bh_thread);
|
||
#endif
|
||
wake_up_process(hw_priv->bh_thread);
|
||
}
|
||
return err;
|
||
}
|
||
|
||
void atbm_unregister_bh(struct atbm_common *hw_priv)
|
||
{
|
||
struct task_struct *thread = hw_priv->bh_thread;
|
||
if (WARN_ON(!thread))
|
||
return;
|
||
|
||
hw_priv->bh_thread = NULL;
|
||
bh_printk(KERN_ERR "[BH] unregister.\n");
|
||
atomic_add(1, &hw_priv->bh_term);
|
||
wake_up(&hw_priv->bh_wq);
|
||
kthread_stop(thread);
|
||
#ifdef HAS_PUT_TASK_STRUCT
|
||
put_task_struct(thread);
|
||
#endif
|
||
}
|
||
|
||
int atbm_reset_driver(struct atbm_common *hw_priv)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int atbm_bh_suspend(struct atbm_common *hw_priv)
|
||
{
|
||
|
||
bh_printk( "[BH] suspend.\n");
|
||
if (hw_priv->bh_error) {
|
||
atbm_printk_err("BH error -- can't suspend\n");
|
||
return -EINVAL;
|
||
}
|
||
|
||
atomic_set(&hw_priv->bh_suspend, ATBM_APOLLO_BH_SUSPEND);
|
||
wake_up(&hw_priv->bh_wq);
|
||
return atbm_wait_event_timeout_stay_awake(hw_priv,hw_priv->bh_evt_wq, hw_priv->bh_error ||
|
||
(ATBM_APOLLO_BH_SUSPENDED == atomic_read(&hw_priv->bh_suspend)),
|
||
1 * HZ,false) ? 0 : -ETIMEDOUT;
|
||
}
|
||
|
||
int atbm_bh_resume(struct atbm_common *hw_priv)
|
||
{
|
||
|
||
bh_printk( "[BH] resume.\n");
|
||
if (hw_priv->bh_error) {
|
||
atbm_printk_err("BH error -- can't resume\n");
|
||
return -EINVAL;
|
||
}
|
||
|
||
atomic_set(&hw_priv->bh_suspend, ATBM_APOLLO_BH_RESUME);
|
||
wake_up(&hw_priv->bh_wq);
|
||
|
||
return atbm_wait_event_timeout_stay_awake(hw_priv,hw_priv->bh_evt_wq,hw_priv->bh_error ||
|
||
(ATBM_APOLLO_BH_RESUMED == atomic_read(&hw_priv->bh_suspend)),
|
||
1 * HZ,false) ? 0 : -ETIMEDOUT;
|
||
|
||
}
|
||
|
||
|
||
void wsm_alloc_tx_buffer(struct atbm_common *hw_priv)
|
||
{
|
||
spin_lock_bh(&hw_priv->tx_com_lock);
|
||
++hw_priv->hw_bufs_used;
|
||
spin_unlock_bh(&hw_priv->tx_com_lock);
|
||
}
|
||
|
||
int wsm_release_tx_buffer(struct atbm_common *hw_priv, int count)
|
||
{
|
||
int ret = 0;
|
||
|
||
spin_lock_bh(&hw_priv->tx_com_lock);
|
||
hw_priv->hw_bufs_used -= count;
|
||
spin_unlock_bh(&hw_priv->tx_com_lock);
|
||
if (!(hw_priv->hw_bufs_used )){
|
||
//atbm_usb_pm(hw_priv->sbus_priv,1);
|
||
wake_up(&hw_priv->bh_evt_wq);
|
||
}
|
||
ret = 1;
|
||
return ret;
|
||
}
|
||
|
||
|
||
void wsm_alloc_tx_buffer_NoLock(struct atbm_common *hw_priv)
|
||
{
|
||
++hw_priv->hw_bufs_used;
|
||
}
|
||
|
||
int wsm_release_tx_buffer_NoLock(struct atbm_common *hw_priv, int count)
|
||
{
|
||
int ret = 0;
|
||
|
||
hw_priv->hw_bufs_used -= count;
|
||
//printk( "wsm_release_tx_buffer(%d)(%d)\n",count,hw_priv->hw_bufs_used);
|
||
if (!(hw_priv->hw_bufs_used )){
|
||
wake_up(&hw_priv->bh_evt_wq);
|
||
}
|
||
ret = 1;
|
||
return ret;
|
||
}
|
||
int atbm_rx_bh_cb(struct atbm_common *hw_priv,struct sk_buff *skb)
|
||
{
|
||
struct wsm_hdr *wsm;
|
||
u32 wsm_len;
|
||
int wsm_id;
|
||
u8 wsm_seq;
|
||
|
||
wsm = (struct wsm_hdr *)skb->data;
|
||
|
||
wsm_len = __le32_to_cpu(wsm->len);
|
||
|
||
wsm_id = __le32_to_cpu(wsm->id) & 0xFFF;
|
||
wsm_seq = (__le32_to_cpu(wsm->id) >> 13) & 7;
|
||
|
||
// BUG_ON(wsm_len > 4096);
|
||
atbm_skb_trim(skb,0);
|
||
atbm_skb_put(skb,wsm_len);
|
||
|
||
if (unlikely(wsm_id == 0x0800)) {
|
||
wsm_handle_exception(hw_priv, &skb->data[sizeof(*wsm)],wsm_len - sizeof(*wsm));
|
||
if(wsm_recovery(hw_priv)== RECOVERY_ERR)
|
||
{
|
||
hw_priv->bh_error = 1;
|
||
wake_up(&hw_priv->bh_wq);
|
||
}
|
||
goto __free;
|
||
}
|
||
//
|
||
//add because usb not reset when rmmod driver, just drop error frame
|
||
//
|
||
if((hw_priv->wsm_caps.firmwareReady==0)
|
||
&&((wsm_seq != hw_priv->wsm_rx_seq)
|
||
||((wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)) != WSM_STARTUP_IND_ID))){
|
||
atbm_printk_err("rx wsm_seq err1 (rxseq=%d need_rxseq=%d) len(%d) wsm_id %x firmwareReady %d\n",wsm_seq,hw_priv->wsm_rx_seq,skb->len,wsm_id,hw_priv->wsm_caps.firmwareReady);
|
||
//BUG_ON(1);
|
||
if((wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)) == WSM_STARTUP_IND_ID)
|
||
atbm_bh_halt(hw_priv);
|
||
goto __free;
|
||
}
|
||
else if (WARN_ON(wsm_seq != hw_priv->wsm_rx_seq)) {
|
||
atbm_printk_err("rx wsm_seq error wsm_seq[%d] wsm_rx_seq[%d] skb->len[%d] wsm_id[%x],wsm_len[%d]\n",
|
||
wsm_seq,hw_priv->wsm_rx_seq,skb->len,wsm_id,wsm_len);
|
||
//frame_hexdump("rxdata",wsm,64);
|
||
//BUG_ON(1);
|
||
atbm_hif_status_set(1);
|
||
atbm_bh_halt(hw_priv);
|
||
goto __free;
|
||
}
|
||
hw_priv->wsm_rx_seq = (wsm_seq + 1) & 7;
|
||
|
||
//frame_hexdump("dump wsm rx ->",wsm,32);
|
||
if (wsm_id & 0x0400) {
|
||
int rc = wsm_release_tx_buffer(hw_priv, 1);
|
||
if (WARN_ON(rc < 0))
|
||
goto __free;
|
||
}
|
||
|
||
/* atbm_wsm_rx takes care on SKB livetime */
|
||
if (WARN_ON(wsm_handle_rx(hw_priv, wsm_id, wsm,&skb))){
|
||
atbm_printk_err("%s %d \n",__func__,__LINE__);
|
||
goto __free;
|
||
}
|
||
|
||
__free:
|
||
if(skb != NULL){
|
||
atbm_dev_kfree_skb(skb);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
int atbm_rx_single_channel_bh_cb(struct atbm_common *hw_priv,struct sk_buff *skb)
|
||
{
|
||
struct wsm_hdr *wsm;
|
||
u32 wsm_len;
|
||
int wsm_id;
|
||
|
||
wsm = (struct wsm_hdr *)skb->data;
|
||
|
||
wsm_len = __le16_to_cpu(wsm->len);
|
||
|
||
wsm_id = __le16_to_cpu(wsm->id) & 0xFFF;
|
||
|
||
//BUG_ON(wsm_len > 4096);
|
||
atbm_skb_trim(skb,0);
|
||
atbm_skb_put(skb,wsm_len);
|
||
|
||
if (unlikely(wsm_id == 0x0800)) {
|
||
wsm_handle_exception(hw_priv, &skb->data[sizeof(*wsm)],wsm_len - sizeof(*wsm));
|
||
if(wsm_recovery(hw_priv)== RECOVERY_ERR)
|
||
{
|
||
hw_priv->bh_error = 1;
|
||
wake_up(&hw_priv->bh_wq);
|
||
}
|
||
goto __free;
|
||
}
|
||
//frame_hexdump("dump wsm rx ->",wsm,32);
|
||
if (wsm_id & 0x0400) {
|
||
int rc = wsm_release_tx_buffer(hw_priv, 1);
|
||
if (WARN_ON(rc < 0))
|
||
goto __free;
|
||
}
|
||
|
||
/* atbm_wsm_rx takes care on SKB livetime */
|
||
if (WARN_ON(wsm_handle_rx(hw_priv, wsm_id, wsm,&skb))){
|
||
atbm_printk_err("%s %d \n",__func__,__LINE__);
|
||
goto __free;
|
||
}
|
||
|
||
__free:
|
||
if(skb != NULL){
|
||
atbm_dev_kfree_skb(skb);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
void atbm_tx_tasklet(unsigned long priv)
|
||
{
|
||
struct atbm_common *hw_priv = (struct atbm_common *)priv;
|
||
int status =0;
|
||
hw_priv->sbus_ops->lock(hw_priv->sbus_priv);
|
||
|
||
do {
|
||
|
||
if(atomic_read(&hw_priv->bh_term)|| hw_priv->bh_error || (hw_priv->bh_thread == NULL))
|
||
{
|
||
hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
|
||
atbm_printk_err("atbm_tx_tasklet term(%d),err(%d)\n",atomic_read(&hw_priv->bh_term),hw_priv->bh_error);
|
||
return;
|
||
}
|
||
|
||
/*atbm transmit packet to device*/
|
||
status = hw_priv->sbus_ops->sbus_memcpy_toio(hw_priv->sbus_priv,0x1,NULL,TX_BUFFER_SIZE);
|
||
|
||
}while(status > 0);
|
||
hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
|
||
|
||
}
|
||
|
||
static u8 atbm_rx_need_alloc_skb(int wsm_id)
|
||
{
|
||
int id = (wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX));
|
||
|
||
return (id==WSM_RECEIVE_INDICATION_ID)||(id == WSM_SMARTCONFIG_INDICATION_ID);
|
||
}
|
||
//#define ALLOC_SKB_NULL_TEST
|
||
static struct sk_buff *atbm_get_skb(unsigned int length)
|
||
{
|
||
#ifdef USB_USE_TASTLET_TXRX
|
||
#define __atbm_get_skb(_length) atbm_dev_alloc_skb(_length)
|
||
#else
|
||
#define __atbm_get_skb(_length) __atbm_dev_alloc_skb(_length,GFP_KERNEL);
|
||
#endif
|
||
#ifdef ALLOC_SKB_NULL_TEST
|
||
static u32 skb_alloc_cnt = 0;
|
||
|
||
skb_alloc_cnt++;
|
||
if((skb_alloc_cnt%4096) == 0)
|
||
return NULL;
|
||
#endif
|
||
return __atbm_get_skb(length);
|
||
}
|
||
static bool atbm_rx_serial(struct atbm_common *hw_priv,u8 wsm_seq,int wsm_id)
|
||
{
|
||
bool serial_rx = true;
|
||
|
||
if(wsm_id == 0x0800){
|
||
goto ret;
|
||
}
|
||
//
|
||
//add because usb not reset when rmmod driver, just drop error frame
|
||
//
|
||
if((hw_priv->wsm_caps.firmwareReady==0)
|
||
&&((wsm_seq != hw_priv->wsm_rx_seq)
|
||
||((wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)) != WSM_STARTUP_IND_ID))){
|
||
atbm_printk_err("rx wsm_seq err1 (rxseq=%d need_rxseq=%d) wsm_id %x firmwareReady %d\n",wsm_seq,hw_priv->wsm_rx_seq,wsm_id,hw_priv->wsm_caps.firmwareReady);
|
||
if((wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)) != WSM_STARTUP_IND_ID){
|
||
serial_rx = false;
|
||
goto ret;
|
||
}
|
||
atbm_printk_err("startup seq(%d)\n",wsm_seq);
|
||
}
|
||
else if (WARN_ON(wsm_seq != hw_priv->wsm_rx_seq)) {
|
||
atbm_printk_err("rx wsm_seq error wsm_seq[%d] wsm_rx_seq[%d] wsm_id[%x]\n",
|
||
wsm_seq,hw_priv->wsm_rx_seq,wsm_id);
|
||
|
||
atbm_printk_err("change hw_priv->wsm_rx_seq form wsm_seq \n");
|
||
hw_priv->wsm_rx_seq = wsm_seq;
|
||
//frame_hexdump("rxdata",wsm,64);
|
||
//BUG_ON(1);
|
||
|
||
/*******yzh *******
|
||
atbm_hif_status_set(1);
|
||
atbm_bh_halt(hw_priv);
|
||
serial_rx = false;
|
||
|
||
goto ret;
|
||
*/
|
||
}
|
||
hw_priv->wsm_rx_seq = (wsm_seq + 1) & 7;
|
||
ret:
|
||
return serial_rx;
|
||
}
|
||
static void atbm_rx_multi_rx(struct atbm_common *hw_priv,struct sk_buff *skb,
|
||
int (*rx_func)(struct atbm_common *hw_priv,struct sk_buff *skb),bool serial_check)
|
||
{
|
||
|
||
#define RX_ALLOC_BUFF_OFFLOAD ( (36+16)/*RX_DESC_OVERHEAD*/+4/*FCS_LEN*/ -16 /*WSM_HI_RX_IND*/)
|
||
struct wsm_multi_rx * multi_rx = (struct wsm_multi_rx *)skb->data;
|
||
int RxFrameNum = multi_rx->RxFrameNum;
|
||
struct sk_buff *atbm_skb_copy;
|
||
struct wsm_hdr *wsm;
|
||
u32 wsm_len;
|
||
int wsm_id;
|
||
int data_len;
|
||
u8 wsm_seq;
|
||
|
||
data_len = __le32_to_cpu(multi_rx->MsgLen);
|
||
|
||
data_len -= sizeof(struct wsm_multi_rx);
|
||
wsm = (struct wsm_hdr *)(multi_rx+1);
|
||
wsm_len = __le32_to_cpu(wsm->len);
|
||
wsm_id = __le32_to_cpu(wsm->id) & 0xFFF;
|
||
do {
|
||
|
||
if(data_len < wsm_len){
|
||
atbm_printk_err("skb->len %x,wsm_len %x\n",skb->len,wsm_len);
|
||
break;
|
||
}
|
||
//BUG_ON((wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)) != WSM_RECEIVE_INDICATION_ID);
|
||
if((wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)) != WSM_RECEIVE_INDICATION_ID){
|
||
atbm_printk_err("%s %d ,ERROR !!! (wsm_id=%d & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)) = %d != 0x0804\n",__func__,__LINE__,
|
||
wsm_id,(wsm_id & ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)));
|
||
return;
|
||
}
|
||
|
||
wsm_seq = (__le32_to_cpu(wsm->id) >> 13) & 7;
|
||
|
||
if((serial_check == true)&&
|
||
(WARN_ON(atbm_rx_serial(hw_priv,wsm_seq,wsm_id) == false))){
|
||
goto next_skb;
|
||
}
|
||
atbm_skb_copy = atbm_get_skb(wsm_len + 16);
|
||
if (!atbm_skb_copy){
|
||
atbm_printk_err("alloc--skb Error(%d)1,move to next skb\n",wsm_len + 16);
|
||
WARN_ON(1);
|
||
goto next_skb;
|
||
}
|
||
|
||
/* In AP mode RXed SKB can be looped back as a broadcast.
|
||
* Here we reserve enough space for headers. */
|
||
atbm_skb_reserve(atbm_skb_copy, (8 - (((unsigned long)atbm_skb_copy->data)&7))/*ALIGN 8*/);
|
||
|
||
memmove(atbm_skb_copy->data, wsm, wsm_len);
|
||
atbm_skb_put(atbm_skb_copy,wsm_len);
|
||
atbm_skb_copy->pkt_type = skb->pkt_type;
|
||
rx_func(hw_priv,atbm_skb_copy);
|
||
next_skb:
|
||
data_len -= ALIGN(wsm_len + RX_ALLOC_BUFF_OFFLOAD,4);
|
||
RxFrameNum--;
|
||
wsm = (struct wsm_hdr *)((u8 *)wsm +ALIGN(( wsm_len + RX_ALLOC_BUFF_OFFLOAD),4));
|
||
wsm_len = __le32_to_cpu(wsm->len);
|
||
wsm_id = __le32_to_cpu(wsm->id) & 0xFFF;
|
||
|
||
}while((RxFrameNum>0) && (data_len > 32));
|
||
//BUG_ON(RxFrameNum != 0);
|
||
if(RxFrameNum != 0){
|
||
atbm_printk_err("%s : RxFrameNum = %d <20><> data_len(%d)\n",__FUNCTION__,RxFrameNum,data_len);
|
||
}
|
||
}
|
||
static bool atbm_process_ieee80211_frame(struct atbm_common *hw_priv,struct sk_buff *skb,
|
||
int (*rx_func)(struct atbm_common *hw_priv,struct sk_buff *skb))
|
||
{
|
||
struct sk_buff *atbm_skb_copy;
|
||
struct wsm_hdr *wsm;
|
||
u32 wsm_len;
|
||
int wsm_id;
|
||
u8 wsm_seq;
|
||
|
||
wsm = (struct wsm_hdr *)skb->data;
|
||
wsm_len = __le32_to_cpu(wsm->len);
|
||
wsm_id = __le32_to_cpu(wsm->id) & 0xFFF;
|
||
|
||
if(wsm_id == WSM_MULTI_RECEIVE_INDICATION_ID){
|
||
/*
|
||
*rx muilt data package
|
||
*/
|
||
atbm_rx_multi_rx(hw_priv,skb,rx_func,true);
|
||
goto processed;
|
||
|
||
}else if(WSM_SINGLE_CHANNEL_MULTI_RECEIVE_INDICATION_ID == wsm_id){
|
||
/*
|
||
*rx single channel but mult data package
|
||
*/
|
||
struct wsm_multi_rx *singlech_multirx = (struct wsm_multi_rx *)skb->data;
|
||
|
||
wsm_seq = (__le32_to_cpu(singlech_multirx->MsgId) >> 13) & 7;
|
||
|
||
if (WARN_ON(atbm_rx_serial(hw_priv,wsm_seq,wsm_id) == false)) {
|
||
atbm_printk_err("rx wsm_seq error wsm_seq[%d] wsm_rx_seq[%d] skb->len[%d] wsm_id[%x],wsm_len[%d]\n",
|
||
wsm_seq,hw_priv->wsm_rx_seq,skb->len,wsm_id,wsm_len);
|
||
|
||
atbm_hif_status_set(1);
|
||
atbm_bh_halt(hw_priv);
|
||
goto processed;
|
||
}
|
||
atbm_rx_multi_rx(hw_priv,skb,rx_func,false);
|
||
goto processed;
|
||
} else if (atbm_rx_need_alloc_skb(wsm_id)){
|
||
/*
|
||
*rx single data package
|
||
*/
|
||
wsm_seq = (__le32_to_cpu(wsm->id) >> 13) & 7;
|
||
if (WARN_ON(atbm_rx_serial(hw_priv,wsm_seq,wsm_id) == false)) {
|
||
atbm_printk_err("rx wsm_seq error wsm_seq[%d] wsm_rx_seq[%d] skb->len[%d] wsm_id[%x],wsm_len[%d]\n",
|
||
wsm_seq,hw_priv->wsm_rx_seq,skb->len,wsm_id,wsm_len);
|
||
|
||
atbm_hif_status_set(1);
|
||
atbm_bh_halt(hw_priv);
|
||
goto processed;
|
||
}
|
||
atbm_skb_copy = atbm_get_skb(wsm_len + 16);
|
||
if (!atbm_skb_copy){
|
||
atbm_printk_err("alloc--skb Error(%d)\n",wsm_len + 16);
|
||
WARN_ON(1);
|
||
goto processed;
|
||
}
|
||
memmove(atbm_skb_copy->data, wsm, wsm_len);
|
||
atbm_skb_put(atbm_skb_copy,wsm_len);
|
||
atbm_skb_copy->pkt_type = skb->pkt_type;
|
||
rx_func(hw_priv,atbm_skb_copy);
|
||
goto processed;
|
||
}
|
||
/*
|
||
*others frame is wsm cmd ,not process here
|
||
*/
|
||
return false;
|
||
processed:
|
||
return true;
|
||
}
|
||
|
||
static bool atbm_process_wsm_cmd_frame(struct atbm_common *hw_priv,struct sk_buff *skb,
|
||
int (*rx_func)(struct atbm_common *hw_priv,struct sk_buff *skb))
|
||
{
|
||
struct wsm_hdr *wsm;
|
||
u32 wsm_len;
|
||
int wsm_id;
|
||
struct sk_buff *atbm_skb_copy;
|
||
|
||
wsm = (struct wsm_hdr *)skb->data;
|
||
wsm_len = __le32_to_cpu(wsm->len);
|
||
wsm_id = __le32_to_cpu(wsm->id) & 0xFFF;
|
||
|
||
WARN_ON(atbm_rx_need_alloc_skb(wsm_id));
|
||
|
||
atbm_skb_copy = atbm_skb_get(skb);
|
||
atbm_skb_put(atbm_skb_copy,wsm_len);
|
||
atbm_skb_copy->pkt_type = skb->pkt_type;
|
||
rx_func(hw_priv,atbm_skb_copy);
|
||
atbm_skb_tx_debug(atbm_skb_copy);
|
||
|
||
return true;
|
||
}
|
||
|
||
static bool atbm_process_raw_frame(struct atbm_common *hw_priv,struct sk_buff *skb)
|
||
{
|
||
if(atbm_process_ieee80211_frame(hw_priv,skb,atbm_rx_single_channel_bh_cb) == false){
|
||
atbm_process_wsm_cmd_frame(hw_priv,skb,atbm_rx_bh_cb);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool atbm_rx_directly(struct atbm_common *hw_priv,struct sk_buff *skb,
|
||
int (*rx_func)(struct atbm_common *hw_priv,struct sk_buff *skb))
|
||
{
|
||
struct wsm_hdr *wsm;
|
||
u8 wsm_seq;
|
||
|
||
if(atbm_process_ieee80211_frame(hw_priv,skb,rx_func) == true){
|
||
return true;
|
||
}
|
||
|
||
wsm = (struct wsm_hdr *)skb->data;
|
||
wsm_seq = (__le32_to_cpu(wsm->id) >> 13) & 7;
|
||
|
||
if (WARN_ON(atbm_rx_serial(hw_priv,wsm_seq,__le32_to_cpu(wsm->id) & 0xFFF) == false)) {
|
||
atbm_hif_status_set(1);
|
||
atbm_bh_halt(hw_priv);
|
||
return false;
|
||
}
|
||
skb->pkt_type = ATBM_RX_WSM_CMD_FRAME;
|
||
return false;
|
||
}
|
||
|
||
void atbm_rx_tasklet(unsigned long priv)
|
||
{
|
||
struct atbm_common *hw_priv = (struct atbm_common *)priv;
|
||
struct sk_buff *skb ;
|
||
enum atbm_rx_frame_type frame_type;
|
||
struct sk_buff_head local_list;
|
||
unsigned long flags;
|
||
|
||
__atbm_skb_queue_head_init(&local_list);
|
||
|
||
spin_lock_irqsave(&hw_priv->rx_frame_queue.lock,flags);
|
||
hw_priv->bh_running = true;
|
||
restart:
|
||
bh_printk("%s: restart\n",__func__);
|
||
atbm_skb_queue_splice_tail_init(&hw_priv->rx_frame_queue, &local_list);
|
||
spin_unlock_irqrestore(&hw_priv->rx_frame_queue.lock,flags);
|
||
|
||
|
||
while ((skb = __atbm_skb_dequeue(&local_list)) != NULL) {
|
||
if(atomic_read(&hw_priv->bh_term)|| hw_priv->bh_error || (hw_priv->bh_thread == NULL)||
|
||
(atomic_read(&hw_priv->atbm_pluged)==0))
|
||
{
|
||
atbm_dev_kfree_skb(skb);
|
||
continue;
|
||
}
|
||
frame_type = (enum atbm_rx_frame_type)skb->pkt_type;
|
||
switch (frame_type) {
|
||
case ATBM_RX_RAW_FRAME:
|
||
bh_printk("%s:RX_RAW_FRAME\n",__func__);
|
||
atbm_process_raw_frame(hw_priv,skb);
|
||
atbm_skb_queue_tail(&hw_priv->rx_frame_free, skb);
|
||
break;
|
||
case ATBM_RX_WSM_CMD_FRAME:
|
||
bh_printk("%s:WSM_CMD_FRAME\n",__func__);
|
||
atbm_process_wsm_cmd_frame(hw_priv,skb,atbm_rx_single_channel_bh_cb);
|
||
atbm_skb_queue_tail(&hw_priv->rx_frame_free, skb);
|
||
break;
|
||
case ATBM_RX_WSM_DATA_FRAME:
|
||
case ATBM_RX_SLOW_MGMT_FRAME:
|
||
bh_printk("%s:RX_SLOW_MGMT_FRAME\n",__func__);
|
||
atbm_rx_single_channel_bh_cb(hw_priv,skb);
|
||
break;
|
||
case ATBM_RX_DERICTLY_DATA_FRAME:
|
||
WARN_ON(1);
|
||
atbm_dev_kfree_skb(skb);
|
||
break;
|
||
case ATBM_RX_WSM_FREE:
|
||
bh_printk("ATBM_RX_WSM_FREE");
|
||
skb->pkt_type = 0;
|
||
atbm_skb_queue_tail(&hw_priv->rx_frame_free, skb);
|
||
break;
|
||
default:
|
||
//BUG_ON(1);
|
||
atbm_printk_err("%s %d , unknow frame_type = %x\n",__func__,__LINE__,frame_type);
|
||
//break;
|
||
atbm_dev_kfree_skb(skb);
|
||
break;;
|
||
}
|
||
}
|
||
while ((skb = atbm_skb_dequeue(&hw_priv->rx_frame_free)) != NULL) {
|
||
/*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,NULL);
|
||
hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
|
||
}
|
||
|
||
spin_lock_irqsave(&hw_priv->rx_frame_queue.lock,flags);
|
||
if(!atbm_skb_queue_empty(&hw_priv->rx_frame_queue))
|
||
goto restart;
|
||
hw_priv->bh_running = false;
|
||
spin_unlock_irqrestore(&hw_priv->rx_frame_queue.lock,flags);
|
||
bh_printk("%s:end\n",__func__);
|
||
}
|
||
int atbm_reset_lmc_cpu(struct atbm_common *hw_priv)
|
||
{
|
||
return -1;
|
||
}
|
||
extern int wifi_module_exit;
|
||
static int usb_atbm_bh(void *arg)
|
||
{
|
||
struct atbm_common *hw_priv = arg;
|
||
struct atbm_vif *priv = NULL;
|
||
int rx, tx=0, term, suspend;
|
||
int pending_tx = 0;
|
||
long status;
|
||
bool powersave_enabled;
|
||
int i;
|
||
int prink_test =0;
|
||
|
||
|
||
#define __ALL_HW_BUFS_USED (hw_priv->hw_bufs_used)
|
||
|
||
|
||
while (1) {
|
||
|
||
powersave_enabled = 1;
|
||
atbm_hw_vif_read_lock(&hw_priv->vif_list_lock);
|
||
atbm_for_each_vif_safe(hw_priv, priv, i) {
|
||
if (!priv)
|
||
continue;
|
||
powersave_enabled &= !!priv->powersave_enabled;
|
||
}
|
||
atbm_hw_vif_read_unlock(&hw_priv->vif_list_lock);
|
||
|
||
if (!__ALL_HW_BUFS_USED
|
||
&& powersave_enabled
|
||
&& !hw_priv->device_can_sleep
|
||
&& !atomic_read(&hw_priv->recent_scan)) {
|
||
status = HZ*2;
|
||
bh_printk( "[BH] No Device wakedown.\n");
|
||
|
||
} else {
|
||
status = HZ*2;
|
||
}
|
||
status = wait_event_interruptible_timeout(hw_priv->bh_wq, ({
|
||
rx = atomic_xchg(&hw_priv->bh_rx, 0);
|
||
tx = atomic_xchg(&hw_priv->bh_tx, 0);
|
||
term = atomic_xchg(&hw_priv->bh_term, 0);
|
||
suspend = pending_tx ?
|
||
0 : atomic_read(&hw_priv->bh_suspend);
|
||
(rx || tx || term || suspend || hw_priv->bh_error||atomic_read(&hw_priv->bh_halt));
|
||
}), status);
|
||
|
||
if (status < 0 || term || hw_priv->bh_error){
|
||
atbm_printk_err("%s BH thread break %ld %d %d\n",__func__,status,term,hw_priv->bh_error);
|
||
break;
|
||
}
|
||
|
||
if(atomic_read(&hw_priv->bh_halt)){
|
||
atomic_set(&hw_priv->atbm_pluged,0);
|
||
atbm_printk_err("%s:bh_halt\n",__func__);
|
||
if(hw_priv->sbus_ops->lmac_restart(hw_priv->sbus_priv) != 0){
|
||
atomic_xchg(&hw_priv->bh_halt,0);
|
||
hw_priv->bh_error = 1;
|
||
break;
|
||
}
|
||
}
|
||
#if 1
|
||
if(1){
|
||
unsigned long timestamp = jiffies;
|
||
long timeout;
|
||
bool pending = false;
|
||
int i;
|
||
|
||
for (i = 0; i < 4; ++i)
|
||
pending |= atbm_queue_get_xmit_timestamp(
|
||
&hw_priv->tx_queue[i],
|
||
×tamp, -1,
|
||
hw_priv->pending_frame_id);
|
||
|
||
/* Check if frame transmission is timed out.
|
||
* Add an extra second with respect to possible
|
||
* interrupt loss. */
|
||
timeout = timestamp +
|
||
2 * HZ -
|
||
jiffies;
|
||
|
||
/* And terminate BH tread if the frame is "stuck" */
|
||
if (pending && timeout < 0) {
|
||
extern void atbm_usb_urb_map_show(struct sbus_priv *self);
|
||
atbm_printk_err("tx rx schedule timeout................?\n");
|
||
atbm_usb_urb_map_show(hw_priv->sbus_priv);
|
||
}
|
||
}
|
||
#endif
|
||
if (!status && __ALL_HW_BUFS_USED)
|
||
{
|
||
unsigned long timestamp = jiffies;
|
||
long timeout;
|
||
bool pending = false;
|
||
int i;
|
||
|
||
//wiphy_warn(hw_priv->hw->wiphy, "Missed interrupt?\n");
|
||
rx = 1;
|
||
/* Get a timestamp of "oldest" frame */
|
||
for (i = 0; i < 4; ++i)
|
||
pending |= atbm_queue_get_xmit_timestamp(
|
||
&hw_priv->tx_queue[i],
|
||
×tamp, -1,
|
||
hw_priv->pending_frame_id);
|
||
|
||
/* Check if frame transmission is timed out.
|
||
* Add an extra second with respect to possible
|
||
* interrupt loss. */
|
||
timeout = timestamp +
|
||
WSM_CMD_LAST_CHANCE_TIMEOUT +
|
||
1 * HZ -
|
||
jiffies;
|
||
|
||
|
||
/* And terminate BH tread if the frame is "stuck" */
|
||
if (pending && timeout < 0) {
|
||
//wiphy_warn(priv->hw->wiphy,
|
||
// "Timeout waiting for TX confirm.\n");
|
||
prink_test++;
|
||
//if(prink_test <10){
|
||
atbm_printk_err("atbm_bh: Timeout waiting for TX confirm. hw_bufs_used %d,hw_noconfirm_tx(%d)\n",hw_priv->hw_bufs_used,hw_priv->hw_noconfirm_tx);
|
||
// }
|
||
wsm_recovery(hw_priv);
|
||
//break;
|
||
}
|
||
} else if (!status) {
|
||
//printk("%s %d ++ !!\n",__func__,__LINE__);
|
||
|
||
/* Do not suspend when datapath is not idle */
|
||
if ( !hw_priv->tx_queue[0].num_queued
|
||
&& !hw_priv->tx_queue[1].num_queued
|
||
&& !hw_priv->tx_queue[2].num_queued
|
||
&& !hw_priv->tx_queue[3].num_queued
|
||
&&(atomic_xchg(&hw_priv->bh_suspend_usb, 1)==0)){
|
||
//usb suspend
|
||
hw_priv->sbus_ops->power_mgmt(hw_priv->sbus_priv, true);
|
||
//printk( "[BH] USB suspend. true.\n");
|
||
}
|
||
|
||
if (!hw_priv->device_can_sleep
|
||
&& !atomic_read(&hw_priv->recent_scan)) {
|
||
bh_printk( "[BH] Device wakedown. Timeout.\n");
|
||
}
|
||
continue;
|
||
} else if (suspend) {
|
||
bh_printk( "[BH] Device suspend.\n");
|
||
atbm_printk_err("%s %d ++ !!\n",__func__,__LINE__);
|
||
powersave_enabled = 1;
|
||
atbm_hw_vif_read_lock(&hw_priv->vif_list_lock);
|
||
atbm_for_each_vif_safe(hw_priv, priv, i) {
|
||
if (!priv)
|
||
continue;
|
||
powersave_enabled &= !!priv->powersave_enabled;
|
||
}
|
||
atbm_hw_vif_read_unlock(&hw_priv->vif_list_lock);
|
||
if (powersave_enabled) {
|
||
bh_printk( "[BH] No Device wakedown. Suspend.\n");
|
||
}
|
||
|
||
atomic_set(&hw_priv->bh_suspend, ATBM_APOLLO_BH_SUSPENDED);
|
||
wake_up(&hw_priv->bh_evt_wq);
|
||
status = wait_event_interruptible(hw_priv->bh_wq,
|
||
ATBM_APOLLO_BH_RESUME == atomic_read(
|
||
&hw_priv->bh_suspend));
|
||
if (status < 0) {
|
||
atbm_printk_err("Failed to wait for resume: %ld.\n", status);
|
||
break;
|
||
}
|
||
bh_printk( "[BH] Device resume.\n");
|
||
atomic_set(&hw_priv->bh_suspend, ATBM_APOLLO_BH_RESUMED);
|
||
//wake_up(&hw_priv->bh_evt_wq);
|
||
//atomic_add(1, &hw_priv->bh_rx);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
atbm_printk_exit("%s %d \n",__func__,__LINE__);
|
||
atbm_hif_status_set(1);
|
||
|
||
//free rx buffer
|
||
atbm_rx_bh_flush(hw_priv);
|
||
atomic_set(&hw_priv->bh_term, term);
|
||
if ((!term)) {
|
||
int loop = 100;
|
||
atbm_printk_exit("%s %d ++ !!\n",__func__,__LINE__);
|
||
atbm_dbg(ATBM_APOLLO_DBG_ERROR, "[BH] Fatal error, exitting.\n");
|
||
|
||
if(!wifi_module_exit){
|
||
hw_priv->bh_error = 1;
|
||
while(loop-->0){
|
||
atbm_monitor_pc(hw_priv);
|
||
msleep(1);
|
||
}
|
||
|
||
#ifdef ATBM_USB_RESET
|
||
hw_priv->bh_error = 0;
|
||
atomic_set(&hw_priv->usb_reset,0);
|
||
// hw_priv->sbus_ops->wtd_wakeup(hw_priv->sbus_priv);
|
||
hw_priv->sbus_ops->usb_reset(hw_priv->sbus_priv);
|
||
status = HZ;
|
||
status = wait_event_interruptible_timeout(hw_priv->bh_wq, ({
|
||
term = atomic_xchg(&hw_priv->bh_term, 0);
|
||
(term || hw_priv->bh_error);
|
||
}), status);
|
||
if(term)
|
||
goto process_term;
|
||
if(!status)
|
||
atbm_printk_exit("%s:reset time out\n",__func__);
|
||
if(hw_priv->bh_error)
|
||
atbm_printk_exit("%s:hw_priv->bh_error\n",__func__);
|
||
#endif
|
||
}
|
||
else {
|
||
term = 1;
|
||
}
|
||
atbm_hw_vif_read_lock(&hw_priv->vif_list_lock);
|
||
atbm_for_each_vif_safe(hw_priv, priv, i) {
|
||
if (!priv)
|
||
continue;
|
||
// ieee80211_driver_hang_notify(priv->vif, GFP_KERNEL);
|
||
}
|
||
atbm_hw_vif_read_unlock(&hw_priv->vif_list_lock);
|
||
#ifdef CONFIG_PM
|
||
atbm_pm_stay_awake(&hw_priv->pm_state, 3*HZ);
|
||
#endif
|
||
/* TODO: schedule_work(recovery) */
|
||
#ifndef HAS_PUT_TASK_STRUCT
|
||
/* The only reason of having this stupid code here is
|
||
* that __put_task_struct is not exported by kernel. */
|
||
for (;;) {
|
||
int status = wait_event_interruptible(hw_priv->bh_wq, ({
|
||
term = atomic_xchg(&hw_priv->bh_term, 0);
|
||
(term);
|
||
}));
|
||
|
||
if (status || term)
|
||
break;
|
||
}
|
||
#endif
|
||
}
|
||
atbm_printk_exit("atbm_wifi_BH_thread stop ++\n");
|
||
if(term)
|
||
{
|
||
//clear pendding cmd
|
||
if(!mutex_trylock(&hw_priv->wsm_cmd_mux))
|
||
{
|
||
spin_lock_bh(&hw_priv->wsm_cmd.lock);
|
||
if(hw_priv->wsm_cmd.cmd != 0xFFFF)
|
||
{
|
||
hw_priv->wsm_cmd.ret = -1;
|
||
hw_priv->wsm_cmd.done = 1;
|
||
spin_unlock_bh(&hw_priv->wsm_cmd.lock);
|
||
atbm_printk_exit("cancle current pendding cmd,release wsm_cmd.lock\n");
|
||
wake_up(&hw_priv->wsm_cmd_wq);
|
||
msleep(2);
|
||
spin_lock_bh(&hw_priv->wsm_cmd.lock);
|
||
}
|
||
spin_unlock_bh(&hw_priv->wsm_cmd.lock);
|
||
}
|
||
else
|
||
{
|
||
mutex_unlock(&hw_priv->wsm_cmd_mux);
|
||
}
|
||
|
||
/*
|
||
*cancle the current scanning process
|
||
*/
|
||
mutex_lock(&hw_priv->conf_mutex);
|
||
if(atomic_read(&hw_priv->scan.in_progress))
|
||
{
|
||
struct atbm_vif *scan_priv = ABwifi_hwpriv_to_vifpriv(hw_priv,
|
||
hw_priv->scan.if_id);
|
||
bool scanto_running = false;
|
||
atbm_priv_vif_list_read_unlock(&scan_priv->vif_lock);
|
||
mutex_unlock(&hw_priv->conf_mutex);
|
||
scanto_running = atbm_hw_cancel_delayed_work(&hw_priv->scan.timeout,true);
|
||
mutex_lock(&hw_priv->conf_mutex);
|
||
if(scanto_running>0)
|
||
{
|
||
u8 scan_fail=0;
|
||
atbm_printk_exit("scan is running , stop it right now\n");
|
||
/*
|
||
*let scan complete and then unlock wsm_oper_lock.
|
||
*/
|
||
|
||
if(hw_priv->scan.status == 0)
|
||
{
|
||
/*
|
||
*scan cmd has been send to lmac ,but we can not
|
||
*receive scan completion.In that case ,we must unlock
|
||
*wsm_oper_lock to make sure the scan process can run in later
|
||
*/
|
||
#ifndef OPER_CLOCK_USE_SEM
|
||
mutex_unlock(&hw_priv->wsm_oper_lock);
|
||
#else
|
||
up(&hw_priv->wsm_oper_lock);
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
*scan cmd send fail,so let hmac process the scan fail process in itself.
|
||
*/
|
||
scan_fail = 1;
|
||
}
|
||
hw_priv->scan.curr = hw_priv->scan.end;
|
||
|
||
if(scan_fail == 0)
|
||
{
|
||
mutex_unlock(&hw_priv->conf_mutex);
|
||
atbm_printk_exit("%s:atbm_scan_timeout\n",__func__);
|
||
atbm_scan_timeout(&hw_priv->scan.timeout.work);
|
||
mutex_lock(&hw_priv->conf_mutex);
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
mutex_unlock(&hw_priv->conf_mutex);
|
||
{
|
||
u8 i = 0;
|
||
//cancel pendding work
|
||
#define ATBM_CANCEL_PENDDING_WORK(work,work_func) \
|
||
do{ \
|
||
if(atbm_hw_cancel_queue_work(work,true)==true) \
|
||
{ \
|
||
work_func(work); \
|
||
} \
|
||
} \
|
||
while(0)
|
||
|
||
if(atbm_hw_cancel_delayed_work(&hw_priv->scan.probe_work,true))
|
||
atbm_probe_work(&hw_priv->scan.probe_work.work);
|
||
if(atbm_hw_cancel_delayed_work(&hw_priv->scan.timeout,true))
|
||
atbm_scan_timeout(&hw_priv->scan.timeout.work);
|
||
#ifdef CONFIG_ATBM_SUPPORT_P2P
|
||
if(atbm_hw_cancel_delayed_work(&hw_priv->rem_chan_timeout,true))
|
||
atbm_rem_chan_timeout(&hw_priv->rem_chan_timeout.work);
|
||
#endif
|
||
ATBM_CANCEL_PENDDING_WORK(&hw_priv->scan.work,atbm_scan_work);
|
||
ATBM_CANCEL_PENDDING_WORK(&hw_priv->event_handler,atbm_event_handler);
|
||
#ifdef CONFIG_ATBM_BA_STAT
|
||
ATBM_CANCEL_PENDDING_WORK(&hw_priv->ba_work,atbm_ba_work);
|
||
atbm_del_timer_sync(&hw_priv->ba_timer);
|
||
#endif
|
||
#ifdef ATBM_SUPPORT_WIDTH_40M
|
||
#ifdef CONFIG_ATBM_40M_AUTO_CCA
|
||
ATBM_CANCEL_PENDDING_WORK(&hw_priv->get_cca_work,atbm_get_cca_work);
|
||
atbm_del_timer_sync(&hw_priv->chantype_timer);
|
||
#endif
|
||
#endif
|
||
#ifdef ATBM_SUPPORT_SMARTCONFIG
|
||
ATBM_CANCEL_PENDDING_WORK(&hw_priv->scan.smartwork,atbm_smart_scan_work);
|
||
ATBM_CANCEL_PENDDING_WORK(&hw_priv->scan.smartsetChanwork,atbm_smart_setchan_work);
|
||
ATBM_CANCEL_PENDDING_WORK(&hw_priv->scan.smartstopwork,atbm_smart_stop_work);
|
||
atbm_del_timer_sync(&hw_priv->smartconfig_expire_timer);
|
||
#endif
|
||
#ifdef CONFIG_ATBM_BA_STATUS
|
||
atbm_del_timer_sync(&hw_priv->ba_timer);
|
||
#endif
|
||
#ifndef CONFIG_RATE_HW_CONTROL
|
||
ATBM_CANCEL_PENDDING_WORK(&hw_priv->tx_policy_upload_work,tx_policy_upload_work);
|
||
#endif
|
||
atbm_for_each_vif(hw_priv, priv, i) {
|
||
if(priv == NULL)
|
||
continue;
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->wep_key_work,atbm_wep_key_work);
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->join_work,atbm_join_work);
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->unjoin_work,atbm_unjoin_work);
|
||
#ifdef CONFIG_ATBM_SUPPORT_P2P
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->offchannel_work,atbm_offchannel_work);
|
||
#endif
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->link_id_work,atbm_link_id_work);
|
||
#ifndef CONFIG_TX_NO_CONFIRM
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->tx_failure_work,atbm_tx_failure_work);
|
||
#endif
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->set_tim_work, atbm_set_tim_work);
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->multicast_start_work,atbm_multicast_start_work);
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->multicast_stop_work, atbm_multicast_stop_work);
|
||
#if 0
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->linkid_reset_work, atbm_link_id_reset);
|
||
#endif
|
||
#ifdef CONFIG_ATBM_MAC80211_NO_USE
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->update_filtering_work, atbm_update_filtering_work);
|
||
#endif
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->set_beacon_wakeup_period_work,
|
||
atbm_set_beacon_wakeup_period_work);
|
||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0))
|
||
ATBM_CANCEL_PENDDING_WORK(&priv->ht_info_update_work, atbm_ht_info_update_work);
|
||
#endif
|
||
#ifdef ATBM_SUPPORT_WIDTH_40M
|
||
#ifdef CONFIG_ATBM_40M_AUTO_CCA
|
||
//ATBM_CANCEL_PENDDING_WORK(&priv->chantype_change_work, atbm_channel_type_change_work);
|
||
if(atbm_hw_cancel_delayed_work(&priv->chantype_change_work,true))
|
||
atbm_channel_type_change_work(&priv->chantype_change_work.work);
|
||
#endif
|
||
#endif
|
||
|
||
atbm_hw_cancel_delayed_work(&priv->dhcp_retry_work,true);
|
||
#ifndef CONFIG_TX_NO_CONFIRM
|
||
if(atbm_hw_cancel_delayed_work(&priv->bss_loss_work,true))
|
||
atbm_bss_loss_work(&priv->bss_loss_work.work);
|
||
if(atbm_hw_cancel_delayed_work(&priv->connection_loss_work,true))
|
||
atbm_connection_loss_work(&priv->connection_loss_work.work);
|
||
#endif
|
||
#if 0
|
||
if(atbm_hw_cancel_delayed_work(&priv->set_cts_work,true))
|
||
atbm_set_cts_work(&priv->set_cts_work.work);
|
||
#endif
|
||
if(atbm_hw_cancel_delayed_work(&priv->link_id_gc_work,true))
|
||
atbm_link_id_gc_work(&priv->link_id_gc_work.work);
|
||
#ifdef CONFIG_ATBM_SUPPORT_P2P
|
||
if(atbm_hw_cancel_delayed_work(&priv->pending_offchanneltx_work,true))
|
||
atbm_pending_offchanneltx_work(&priv->pending_offchanneltx_work.work);
|
||
#endif
|
||
if(atbm_hw_cancel_delayed_work(&priv->join_timeout,true))
|
||
atbm_join_timeout(&priv->join_timeout.work);
|
||
atbm_del_timer_sync(&priv->mcast_timeout);
|
||
}
|
||
}
|
||
}
|
||
/*
|
||
add this code just because 'linux kernel' need kthread not exit ,
|
||
before kthread_stop func call,
|
||
*/
|
||
while(term){
|
||
if(kthread_should_stop()){
|
||
break;
|
||
}
|
||
schedule_timeout_uninterruptible(msecs_to_jiffies(100));
|
||
}
|
||
atbm_printk_exit("atbm_wifi_BH_thread stop --\n");
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
//################################################################################################
|
||
//################################################################################################
|
||
//################################################################################################
|
||
//################################################################################################
|
||
//################################################################################################
|
||
//################################################################################################
|
||
|
||
#if 0
|
||
#define MAX_TX_TEST_LEN 1600
|
||
#define MIN_TX_TEST_LEN 10
|
||
struct sk_buff *test_skb[1000];
|
||
int test_skb_tx_id=0;
|
||
int test_skb_tx_end_id=0;
|
||
int test_len = MAX_TX_TEST_LEN;
|
||
int test_skb_rx_id =0;
|
||
|
||
#define TEST_MAX_CNT 1000000
|
||
extern int wsm_test_cmd(struct atbm_common *hw_priv,u8 *buffer,int size);
|
||
int atbm_usb_xmit_test(struct sbus_priv *self,unsigned int addr, const void *pdata, int len);
|
||
|
||
|
||
void atbm_device_tx_test_complete(void *priv,void *arg);
|
||
|
||
int atbm_device_tx_test(struct atbm_common *hw_priv)
|
||
{
|
||
int ret = 0;
|
||
struct wsm_hdr_tx *hdr;
|
||
u32 rand =0;
|
||
|
||
get_random_bytes(&rand, sizeof(u32));
|
||
rand = rand&0x3ff;
|
||
rand += rand&0x1ff;
|
||
rand += rand&0xff;
|
||
if(rand >MAX_TX_TEST_LEN)
|
||
rand = MAX_TX_TEST_LEN;
|
||
if(rand < MIN_TX_TEST_LEN)
|
||
rand = MIN_TX_TEST_LEN;
|
||
//test_len = rand;
|
||
hdr=(struct wsm_hdr_tx *)test_skb[test_skb_tx_id&0x7]->data;
|
||
hdr->len = test_len;
|
||
//txrx test
|
||
hdr->id = 0x1e;
|
||
//throughput test
|
||
//hdr->id = 0xf;
|
||
|
||
hw_priv->save_buf=(u8 *)hdr;
|
||
hw_priv->save_buf_len = test_len;
|
||
hw_priv->save_buf_vif_selected = 0;
|
||
//printk("hw_priv->save_buf %x\n",hw_priv->save_buf);
|
||
//printk( "test_tx_id %d len %d\n",test_skb_tx_id,test_len);
|
||
//hw_priv->sbus_ops->lock(hw_priv->sbus_priv);
|
||
ret = hw_priv->sbus_ops->sbus_write_async(hw_priv->sbus_priv,0x1,hdr,hdr->len,atbm_device_tx_test_complete);
|
||
//hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
|
||
if(ret){
|
||
return ret;
|
||
}
|
||
test_skb_tx_id++;
|
||
//test_skb_tx_id++;
|
||
//ret = atbm_usb_xmit_test(hw_priv->sbus_priv,0x2,hdr,hdr->len);
|
||
//test_skb_tx_id++;
|
||
//ret = atbm_usb_xmit_test(hw_priv->sbus_priv,0x3,hdr,hdr->len);
|
||
//test_skb_tx_id++;
|
||
//ret = atbm_usb_xmit_test(hw_priv->sbus_priv,0x4,hdr,hdr->len);
|
||
//test_skb_tx_id++;
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
void atbm_device_tx_test_complete(void *priv,void *arg)
|
||
{
|
||
struct atbm_common *hw_priv =priv;
|
||
|
||
//printk( "tx_test_complete %d %d \n",test_skb_tx_id,test_skb_tx_end_id);
|
||
if(++test_skb_tx_end_id < TEST_MAX_CNT){
|
||
atbm_device_tx_test(hw_priv);
|
||
}
|
||
else {
|
||
atbm_printk_bh("atbm_device_tx_test_complete %d \n",test_skb_tx_end_id);
|
||
atbm_printk_bh("atbm_device_tx_test_END\n");
|
||
}
|
||
|
||
}
|
||
void atbm_device_rx_test_complete(void *priv,void *arg);
|
||
#ifdef USB_BUS
|
||
|
||
typedef struct usb_reg_bit_t{
|
||
u32 addr;
|
||
u32 endbit;
|
||
u32 startbit;
|
||
u32 data;
|
||
}usb_reg_bit;
|
||
const usb_reg_bit usb_reg_table[]=
|
||
{
|
||
{0x16200024, 3, 0 , 1},
|
||
{0x1620002c, 7, 0 , 2},
|
||
{0x16400014, 15, 0 , 3},
|
||
{0x1640001c, 15, 0 , 4},
|
||
{0x16600000, 6, 0 , 5},
|
||
{0x16700000, 16, 0 , 6},
|
||
//{0x16700018, 7, 0 , 7},
|
||
{0x16800024, 10, 0 , 8},
|
||
//{0x1680005c, 2, 0 , 9 },
|
||
//{0x1680005c, 6, 4 , 10 },
|
||
//{0x1680005c, 10, 8 , 11},
|
||
//{0x1680005c, 14, 12, 12},
|
||
//{0x1680005c, 18, 16, 13},
|
||
//{0x1680005c, 22, 20, 14},
|
||
//{0x1680005c, 26, 24, 15},
|
||
//{0x1680005c, 30, 28, 16},
|
||
{0x16900014, 9, 0 , 17 },
|
||
{0x16900024, 12, 0 , 18},
|
||
{0x16a00010, 4, 0 , 19 },
|
||
{0x16a00020, 30, 0 , 20},
|
||
{0x16100040, 31, 0 , 21},
|
||
{0x16100020, 17, 0 , 22},
|
||
{0x0acc01e0, 15, 0 , 23},
|
||
{0x0acc0218, 31, 0 , 24},
|
||
{0x09000000, 31, 0 , 25},
|
||
{0x09003fff, 31, 0 , 26},
|
||
{0x09004000, 31, 0 , 27},
|
||
{0x09004fff, 31, 0 , 28},
|
||
{0x00000000, 31, 0 , 29},
|
||
{0x00003fff, 31, 0 , 30},
|
||
{0x00004000, 31, 0 , 31},
|
||
{0x00007fff, 31, 0 , 32},
|
||
{0x00800000, 31, 0 , 33},
|
||
{0x008027fc, 31, 0 , 34},
|
||
{0x0ab00000, 17,0, 35},
|
||
{0x0ab0011c, 14,0, 36},
|
||
{0x09c00004, 31,0, 37},
|
||
{0x09c000ac, 31,0, 38},
|
||
{0x0ac00004, 6,0, 39},
|
||
{0x16101004, 11,8, 15},
|
||
{0x16101004, 3,0, 15},
|
||
{0x1610100c, 21,0, 42},
|
||
//{0x0ac0036c, 31,0, 40},
|
||
{0xff,31,0,0xff},
|
||
};
|
||
int test_tt =0;
|
||
void atbm_test_usb_reg_bit(struct atbm_common *hw_priv,const usb_reg_bit * usb_reg_bit_table)
|
||
{
|
||
u32 uiRegValue=0;
|
||
u32 regmask=0;
|
||
u32 startbit,endbit;
|
||
u32 Value,RegAddr;
|
||
u32 const *Ptr;
|
||
int i=0;
|
||
|
||
//test_tt = 1;
|
||
atbm_printk_bh("%s\n",__func__);
|
||
Ptr = (u32*)usb_reg_bit_table;
|
||
while (*Ptr != 0xff)
|
||
{
|
||
RegAddr = *Ptr++;
|
||
endbit = *Ptr++;
|
||
startbit = *Ptr++;
|
||
Value = *Ptr++;
|
||
atbm_printk_bh("RegAddr=%x,bit%d~bit%d\n",RegAddr,endbit,startbit);
|
||
hw_priv->sbus_ops->sbus_read_sync(hw_priv->sbus_priv,RegAddr,&uiRegValue,4);
|
||
regmask = ~((1<<startbit) -1);
|
||
regmask &= ((1<<endbit) -1)|(1<<endbit);
|
||
uiRegValue &= ~regmask;
|
||
uiRegValue |= (Value<<startbit)®mask;
|
||
atbm_printk_bh("start write reg number=%d,value=0x%x,uiRegValue=%x\n",i,uiRegValue,(Value<<startbit));
|
||
hw_priv->sbus_ops->sbus_write_sync(hw_priv->sbus_priv,RegAddr,&uiRegValue,4);
|
||
mdelay(2);
|
||
hw_priv->sbus_ops->sbus_read_sync(hw_priv->sbus_priv,RegAddr,&uiRegValue,4);
|
||
atbm_printk_bh("start read reg number=%d,value=0x%x\n",i,uiRegValue);
|
||
i++;
|
||
|
||
};
|
||
}
|
||
#endif
|
||
int atbm_device_rx_test(struct atbm_common *hw_priv)
|
||
{
|
||
int ret = 0;
|
||
|
||
test_skb_rx_id++;
|
||
//printk( "test_rx_id %d\n",test_skb_rx_id);
|
||
|
||
hw_priv->sbus_ops->lock(hw_priv->sbus_priv);
|
||
hw_priv->sbus_ops->sbus_read_async(hw_priv->sbus_priv,0x2,NULL,RX_BUFFER_SIZE,atbm_device_rx_test_complete);
|
||
hw_priv->sbus_ops->unlock(hw_priv->sbus_priv);
|
||
|
||
return ret;
|
||
}
|
||
|
||
void atbm_device_rx_test_complete(void *priv,void *arg)
|
||
{
|
||
struct atbm_common *hw_priv =priv;
|
||
struct wsm_hdr *wsm=arg;
|
||
//printk( "rx_test_complete %d \n",test_skb_rx_id);
|
||
|
||
if(wsm->id == 0x2e){
|
||
test_skb_rx_id += wsm->len/4 -1;
|
||
}
|
||
|
||
if(test_skb_rx_id < TEST_MAX_CNT){
|
||
atbm_device_rx_test(hw_priv);
|
||
}
|
||
else {
|
||
atbm_printk_bh("atbm_device_rx_test END %d \n",test_skb_rx_id);
|
||
}
|
||
}
|
||
void atbm_usb_receive_data_cancel(struct sbus_priv *self);
|
||
int atbm_usb_pm(struct sbus_priv *self, bool suspend);
|
||
|
||
int atbm_device_txrx_test_init(struct atbm_common *hw_priv,int caseNum)
|
||
{
|
||
if(caseNum ==1){
|
||
memset(test_skb,0,sizeof(test_skb));
|
||
test_skb_tx_id=0;
|
||
test_skb_tx_end_id=0;
|
||
test_skb_rx_id = 0;
|
||
test_skb[0] = atbm_dev_alloc_skb(MAX_TX_TEST_LEN+64);
|
||
test_skb[1] = atbm_dev_alloc_skb(MAX_TX_TEST_LEN+64);
|
||
test_skb[2] = atbm_dev_alloc_skb(MAX_TX_TEST_LEN+64);
|
||
test_skb[3] = atbm_dev_alloc_skb(MAX_TX_TEST_LEN+64);
|
||
test_skb[4] = atbm_dev_alloc_skb(MAX_TX_TEST_LEN+64);
|
||
test_skb[5] = atbm_dev_alloc_skb(MAX_TX_TEST_LEN+64);
|
||
test_skb[6] = atbm_dev_alloc_skb(MAX_TX_TEST_LEN+64);
|
||
test_skb[7] = atbm_dev_alloc_skb(MAX_TX_TEST_LEN+64);
|
||
atbm_device_rx_test(hw_priv);
|
||
atbm_device_rx_test(hw_priv);
|
||
atbm_device_tx_test(hw_priv);
|
||
atbm_device_tx_test(hw_priv);
|
||
atbm_device_tx_test(hw_priv);
|
||
atbm_device_tx_test(hw_priv);
|
||
//atbm_usb_pm(hw_priv->sbus_priv,1);
|
||
}
|
||
else if(caseNum ==0){
|
||
//atbm_test_usb_reg_bit(hw_priv,usb_reg_table);
|
||
//atbm_usb_pm(hw_priv->sbus_priv,0);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
#endif
|
||
|