luckfox-pico-sdk/sysdrv/drv_ko/wifi/atbm/hal_apollo/util.c
2023-08-08 20:36:47 +08:00

429 lines
11 KiB
C

#include <net/atbm_mac80211.h>
#include <linux/kthread.h>
#include <linux/dma-mapping.h>
#include <linux/skbuff.h>
#include "apollo.h"
#include "bh.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"
/* Must be called from BH thraed. */
void atbm_enable_powersave(struct atbm_vif *priv,
bool enable)
{
atbm_dbg(ATBM_APOLLO_DBG_MSG, "[BH] Powerave is %s.\n",
enable ? "enabled" : "disabled");
priv->powersave_enabled = enable;
}
void atbm_bh_wakeup(struct atbm_common *hw_priv)
{
atbm_dbg(ATBM_APOLLO_DBG_MSG, "[BH] wakeup.\n");
if(hw_priv->sbus_ops->sbus_xmit_schedule)
hw_priv->sbus_ops->sbus_xmit_schedule(hw_priv->sbus_priv);
else if (atomic_add_return(1, &hw_priv->bh_tx) == 1){
wake_up(&hw_priv->bh_wq);
}
}
int wsm_release_vif_tx_buffer(struct atbm_common *hw_priv, int if_id,
int count)
{
int ret = 0;
spin_lock_bh(&hw_priv->tx_com_lock);
hw_priv->hw_bufs_used_vif[if_id] -= count;
if (WARN_ON(hw_priv->hw_bufs_used_vif[if_id] < 0)){
atbm_printk_err( "%s:[%d][%d]\n",__func__,if_id,hw_priv->hw_bufs_used_vif[if_id]);
hw_priv->hw_bufs_used_vif[if_id] = 0;
//BUG_ON(1);
//ret = -1;
}
spin_unlock_bh(&hw_priv->tx_com_lock);
if (!hw_priv->hw_bufs_used_vif[if_id])
wake_up(&hw_priv->bh_evt_wq);
return ret;
}
int wsm_release_vif_tx_buffer_Nolock(struct atbm_common *hw_priv, int if_id,
int count)
{
int ret = 0;
hw_priv->hw_bufs_used_vif[if_id] -= count;
if (!hw_priv->hw_bufs_used_vif[if_id])
wake_up(&hw_priv->bh_evt_wq);
if (WARN_ON(hw_priv->hw_bufs_used_vif[if_id] < 0)){
atbm_printk_err( "%s:[%d][%d]\n",__func__,if_id,hw_priv->hw_bufs_used_vif[if_id]);
hw_priv->hw_bufs_used_vif[if_id] =0;
//BUG_ON(1);
//ret = -1;
}
return ret;
}
void atbm_monitor_pc(struct atbm_common *hw_priv)
{
u32 testreg1[10] = {0};
u32 testreg_pc = 0;
u32 testreg_ipc = 0;
u32 val28;
u32 val20;
int i = 0;
atbm_direct_write_reg_32(hw_priv,0x16100050,1);
//atbm_direct_read_reg_32(hw_priv,0x18e00014,&testreg1);
atbm_direct_read_reg_32(hw_priv,0x16100054,&testreg_pc);
atbm_direct_read_reg_32(hw_priv,0x16100058,&testreg_ipc);
atbm_direct_read_reg_32(hw_priv,0x16101028,&val28);
atbm_direct_read_reg_32(hw_priv,0x16101020,&val20);
//atbm_direct_read_reg_32(hw_priv,0x16400000,&testreg_uart);
for(i=0;i<10;i++){
atbm_direct_read_reg_32(hw_priv,hw_priv->wsm_caps.exceptionaddr+4*i+4,&testreg1[i]);
}
atbm_direct_write_reg_32(hw_priv,0x16100050,0);
atbm_printk_err("ERROR !! pc:[%x],ipc[%x] \n",testreg_pc,testreg_ipc);
atbm_printk_err("ERROR !! reg0:[%x],reg1[%x],reg2[%x],reg3[%x],reg4[%x],reg5[%x],reg6[%x] \n",
testreg1[0],
testreg1[1],
testreg1[2],
testreg1[3],
testreg1[4],
testreg1[5],
testreg1[6]);
atbm_printk_err( "[PC]:0x16101028(%x)\n",val28);
atbm_printk_err( "[PC]:0x16101020(%x)\n",val20);
}
#ifdef ATBM_WIFI_QUEUE_LOCK_BUG
void atbm_set_priv_queue_cap(struct atbm_vif *priv)
{
struct atbm_common *hw_priv = priv->hw_priv;
struct atbm_vif *other_priv;
u8 i = 0;
priv->queue_cap = ATBM_QUEUE_SINGLE_CAP;
atbm_for_each_vif(hw_priv, other_priv, i) {
if(other_priv == NULL)
continue;
if(other_priv == priv)
continue;
if(other_priv->join_status <= ATBM_APOLLO_JOIN_STATUS_MONITOR)
continue;
other_priv->queue_cap = ATBM_QUEUE_COMB_CAP;
priv->queue_cap = ATBM_QUEUE_COMB_CAP;
}
}
void atbm_clear_priv_queue_cap(struct atbm_vif *priv)
{
struct atbm_common *hw_priv = priv->hw_priv;
struct atbm_vif *other_priv;
struct atbm_vif *prev_priv = NULL;
u8 i = 0;
priv->queue_cap = ATBM_QUEUE_DEFAULT_CAP;
atbm_for_each_vif(hw_priv, other_priv, i) {
if(other_priv == NULL)
continue;
if(other_priv == priv)
continue;
if(other_priv->join_status <= ATBM_APOLLO_JOIN_STATUS_MONITOR)
continue;
other_priv->queue_cap = ATBM_QUEUE_SINGLE_CAP;
if(prev_priv == NULL){
prev_priv = other_priv;
continue;
}
prev_priv->queue_cap = ATBM_QUEUE_COMB_CAP;
other_priv->queue_cap = ATBM_QUEUE_COMB_CAP;
prev_priv = other_priv;
}
}
#endif
void atbm_xmit_linearize(struct atbm_common *hw_priv,
struct wsm_tx *wsm,char *xmit,int xmit_len)
{
int wsm_id = __le16_to_cpu(wsm->hdr.id) & 0x3F;
while(wsm_id == WSM_TRANSMIT_REQ_MSG_ID){
u8 queueId = wsm_queue_id_to_linux(wsm->queueId & 0x03);
struct atbm_queue *queue = &hw_priv->tx_queue[queueId];
const struct atbm_txpriv *txpriv = NULL;
struct sk_buff *skb = NULL;
int sg_len = 0;
int sg = 0;
struct ieee80211_tx_info *tx_info;
if(atbm_queue_get_skb(queue,wsm->packetID,
&skb, &txpriv) != 0){
WARN_ON(1);
break;
}
BUG_ON((void *)skb->data != (void *)wsm);
if(!skb_is_nonlinear(skb)){
break;
}
tx_info = IEEE80211_SKB_CB(skb);
printk_once(KERN_ERR "sg process\n");
memcpy(xmit,skb->data,skb_headlen(skb));
sg_len += skb_headlen(skb);
xmit += sg_len;
for (sg = 0; sg < skb_shinfo(skb)->nr_frags; sg++){
skb_frag_t *frag = &skb_shinfo(skb)->frags[sg];
#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 0, 0))
memcpy(xmit,page_address(frag->bv_page) + frag->bv_offset,frag->bv_len);
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
memcpy(xmit,page_address(frag->page) + frag->page_offset,frag->size);
#else
memcpy(xmit,page_address(frag->page.p) + frag->page_offset,frag->size);
#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 0, 0))
xmit += frag->bv_len;
sg_len += frag->bv_len;
#else
xmit += frag->size;
sg_len += frag->size;
#endif
}
if(tx_info->sg_tailneed){
printk_once(KERN_ERR "sg_tailneed(%d)\n",tx_info->sg_tailneed);
memset(xmit,0,tx_info->sg_tailneed);
if(sg_len + tx_info->sg_tailneed != xmit_len){
atbm_printk_err("sg_len(%d),xmit_len(%d),sg_tailneed(%d)\n",sg_len,xmit_len,tx_info->sg_tailneed);
WARN_ON_ONCE(1);
}
sg_len += tx_info->sg_tailneed;
}
WARN_ON_ONCE(sg_len != xmit_len);
return;
}
memcpy(xmit,wsm,xmit_len);
}
int atbm_save_efuse(struct atbm_common *hw_priv,struct efuse_headr *efuse_save)
{
int ret = 0;
int iResult=0;
//struct atbm_vif *vif;
struct efuse_headr efuse_bak;
/*
*LMC_STATUS_CODE__EFUSE_VERSION_CHANGE failed because efuse version change
*LMC_STATUS_CODE__EFUSE_FIRST_WRITE, failed because efuse by first write
*LMC_STATUS_CODE__EFUSE_PARSE_FAILED, failed because efuse data wrong, cannot be parase
*LMC_STATUS_CODE__EFUSE_FULL, failed because efuse have be writen full
*/
ret = wsm_efuse_change_data_cmd(hw_priv, efuse_save,0);
if (ret == LMC_STATUS_CODE__EFUSE_FIRST_WRITE)
{
atbm_printk_err("first write\n");
iResult = -3;
}else if (ret == LMC_STATUS_CODE__EFUSE_PARSE_FAILED)
{
atbm_printk_err("parse failed\n");
iResult = -4;
}else if (ret == LMC_STATUS_CODE__EFUSE_FULL)
{
atbm_printk_err("efuse full\n");
iResult = -5;
}else if (ret == LMC_STATUS_CODE__EFUSE_VERSION_CHANGE)
{
atbm_printk_err("efuse version change\n");
iResult = -6;
}else
{
iResult = 0;
}
if (iResult == 0)
{
//frame_hexdump("efuse_d", efuse_save, sizeof(struct efuse_headr));
memset(&efuse_bak,0,sizeof(struct efuse_headr));
wsm_get_efuse_data(hw_priv,(void *)&efuse_bak, sizeof(struct efuse_headr));
if(efuse_bak.specific != 0)
{
//sigmastar oid
efuse_save->specific = efuse_bak.specific;
}
if(memcmp((void *)&efuse_bak, efuse_save, sizeof(struct efuse_headr)) !=0)
{
frame_hexdump("efuse_bak", (u8 *)&efuse_bak, sizeof(struct efuse_headr));
iResult = -2;
}else
{
iResult = 0;
}
}
return iResult;
}
void atbm_destroy_wsm_cmd(struct atbm_common *hw_priv)
{
/*
*flush work
*/
atbm_flush_workqueue(hw_priv->workqueue);
atbm_printk_exit("Flush hw_priv->workqueue\n");
/*
*try to release wsm_oper_unlock
*/
#ifdef OPER_CLOCK_USE_SEM
atbm_del_timer_sync(&hw_priv->wsm_pm_timer);
spin_lock_bh(&hw_priv->wsm_pm_spin_lock);
if(atomic_read(&hw_priv->wsm_pm_running) == 1){
atomic_set(&hw_priv->wsm_pm_running, 0);
wsm_oper_unlock(hw_priv);
atbm_release_suspend(hw_priv);
atbm_printk_exit("%s,up pm lock\n",__func__);
}
spin_unlock_bh(&hw_priv->wsm_pm_spin_lock);
#endif
/*
*release scan
*/
if(atomic_read(&hw_priv->scan.in_progress)){
/*
*maybe scan work is runing,here flush it.
*/
atbm_printk_exit("scan running,maybe need cancle\n");
atbm_flush_workqueue(hw_priv->workqueue);
if(atomic_read(&hw_priv->scan.in_progress)&&(hw_priv->scan.status != -ETIMEDOUT) &&
(atbm_hw_cancel_delayed_work(&hw_priv->scan.timeout,true) > 0)){
atbm_printk_exit("scan running,try to cancle\n");
atbm_scan_timeout(&hw_priv->scan.timeout.work);
}
}
atbm_printk_exit("Flush pm and scan\n");
atbm_flush_workqueue(hw_to_local(hw_priv->hw)->workqueue);
atbm_flush_workqueue(hw_priv->workqueue);
synchronize_net();
}
int atbm_reinit_firmware(struct atbm_common *hw_priv)
{
struct wsm_operational_mode mode = {
.power_mode = wsm_power_mode_quiescent,
.disableMoreFlagUsage = true,
};
int ret = 0;
u8 if_id = 0;
/*
*load firmware
*/
hw_priv->wsm_caps.firmwareReady = 0;
ret = atbm_load_firmware(hw_priv);
if (ret){
atbm_printk_err( "atbm_load_firmware ERROR!\n");
goto error_reload;
}
atbm_printk_init("mdelay wait wsm_startup_done !!\n");
if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done,
hw_priv->wsm_caps.firmwareReady,3*HZ)<=0){
atbm_printk_err("%s: reload fw err\n",__func__);
goto error_reload;
}
atomic_xchg(&hw_priv->bh_halt,0);
atbm_firmware_init_check(hw_priv);
for (if_id = 0; if_id < ABwifi_get_nr_hw_ifaces(hw_priv); if_id++) {
/* Set low-power mode. */
ret = wsm_set_operational_mode(hw_priv, &mode, if_id);
if (ret) {
WARN_ON(1);
goto error_reload;
}
/* Enable multi-TX confirmation */
ret = wsm_use_multi_tx_conf(hw_priv, true, if_id);
if (ret) {
#ifndef CONFIG_TX_NO_CONFIRM
WARN_ON(1);
goto error_reload;
#else //CONFIG_TX_NO_CONFIRM
ret = 0;
#endif
}
}
error_reload:
return ret;
}
int atbm_rx_bh_flush(struct atbm_common *hw_priv)
{
struct sk_buff *skb ;
while ((skb = atbm_skb_dequeue(&hw_priv->rx_frame_queue)) != NULL) {
//printk("test=====>atbm_kfree skb %p \n",skb);
atbm_dev_kfree_skb(skb);
}
return 0;
}
void atbm_bh_halt(struct atbm_common *hw_priv)
{
if (atomic_add_return(1, &hw_priv->bh_halt) == 1){
atomic_set(&hw_priv->atbm_pluged,0);
wake_up(&hw_priv->bh_wq);
}
#if 0
spin_lock_bh(&hw_priv->wsm_cmd.lock);
if(hw_priv->wsm_cmd.ptr == NULL){
if(hw_priv->wsm_cmd.cmd != 0xFFFF){
atbm_printk_err("%s:release cmd [%x]\n",__func__,hw_priv->wsm_cmd.cmd);
hw_priv->wsm_cmd.ret = -1;
hw_priv->wsm_cmd.done = 1;
wake_up(&hw_priv->wsm_cmd_wq);
}else {
}
}else {
atbm_printk_err("%s:cmd[%x] not send\n",__func__,hw_priv->wsm_cmd.cmd);
}
spin_unlock_bh(&hw_priv->wsm_cmd.lock);
#endif
}
void atbm_bh_multrx_trace(struct atbm_common *hw_priv,u8 n_rx)
{
hw_priv->multrx_trace[hw_priv->multrx_index++] = n_rx;
hw_priv->multrx_index &= (64-1);
}