/******************************************************************************
|
*
|
* Copyright(c) 2019 Realtek Corporation.
|
*
|
* 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 the GNU General Public License for
|
* more details.
|
*
|
*****************************************************************************/
|
#define _HAL_BTC_FW_C_
|
#include "../hal_headers_le.h"
|
#include "hal_btc.h"
|
#include "halbtc_fw.h"
|
#include "halbtc_def.h"
|
|
#ifdef CONFIG_BTCOEX
|
|
void _chk_btc_err(struct btc_t *btc, u8 type, u32 cnt)
|
{
|
struct btc_cx *cx = &btc->cx;
|
struct btc_dm *dm = &btc->dm;
|
struct btc_wl_info *wl = &cx->wl;
|
struct btc_bt_info *bt = &cx->bt;
|
|
switch (type) {
|
case BTC_DCNT_RPT_FREEZE:
|
if (wl->status.map.lps == BTC_LPS_RF_OFF ||
|
wl->status.map.rf_off)
|
return;
|
|
if (dm->cnt_dm[BTC_DCNT_RPT] == cnt && btc->fwinfo.rpt_en_map)
|
dm->cnt_dm[BTC_DCNT_RPT_FREEZE]++;
|
else
|
dm->cnt_dm[BTC_DCNT_RPT_FREEZE] = 0;
|
|
if (dm->cnt_dm[BTC_DCNT_RPT_FREEZE] >= BTC_CHK_HANG_MAX)
|
dm->error.map.wl_fw_hang = true;
|
else
|
dm->error.map.wl_fw_hang = false;
|
|
dm->cnt_dm[BTC_DCNT_RPT] = cnt;
|
break;
|
case BTC_DCNT_CYCLE_FREEZE:
|
if (dm->cnt_dm[BTC_DCNT_CYCLE] == cnt &&
|
(dm->tdma_now.type != CXTDMA_OFF ||
|
dm->tdma_now.ext_ctrl == CXECTL_EXT))
|
dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE]++;
|
else
|
dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE] = 0;
|
|
if (dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE] >= BTC_CHK_HANG_MAX)
|
dm->error.map.cycle_hang = true;
|
else
|
dm->error.map.cycle_hang = false;
|
|
dm->cnt_dm[BTC_DCNT_CYCLE] = cnt;
|
break;
|
case BTC_DCNT_W1_FREEZE:
|
if (dm->cnt_dm[BTC_DCNT_W1] == cnt &&
|
dm->tdma_now.type != CXTDMA_OFF)
|
dm->cnt_dm[BTC_DCNT_W1_FREEZE]++;
|
else
|
dm->cnt_dm[BTC_DCNT_W1_FREEZE] = 0;
|
|
if (dm->cnt_dm[BTC_DCNT_W1_FREEZE] >= BTC_CHK_HANG_MAX)
|
dm->error.map.w1_hang = true;
|
else
|
dm->error.map.w1_hang = false;
|
|
dm->cnt_dm[BTC_DCNT_W1] = cnt;
|
break;
|
case BTC_DCNT_B1_FREEZE:
|
if (dm->cnt_dm[BTC_DCNT_B1] == cnt &&
|
dm->tdma_now.type != CXTDMA_OFF)
|
dm->cnt_dm[BTC_DCNT_B1_FREEZE]++;
|
else
|
dm->cnt_dm[BTC_DCNT_B1_FREEZE] = 0;
|
|
if (dm->cnt_dm[BTC_DCNT_B1_FREEZE] >= BTC_CHK_HANG_MAX)
|
dm->error.map.b1_hang = true;
|
else
|
dm->error.map.b1_hang = false;
|
|
dm->cnt_dm[BTC_DCNT_B1] = cnt;
|
break;
|
case BTC_DCNT_TDMA_NONSYNC:
|
if (cnt != 0) /* if tdma not sync between drv/fw */
|
dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC]++;
|
else
|
dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] = 0;
|
|
if (dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] >= BTC_CHK_HANG_MAX)
|
dm->error.map.tdma_no_sync = true;
|
else
|
dm->error.map.tdma_no_sync = false;
|
break;
|
case BTC_DCNT_SLOT_NONSYNC:
|
if (cnt != 0) /* if slot not sync between drv/fw */
|
dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC]++;
|
else
|
dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] = 0;
|
|
if (dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] >= BTC_CHK_HANG_MAX)
|
dm->error.map.tdma_no_sync = true;
|
else
|
dm->error.map.tdma_no_sync = false;
|
break;
|
case BTC_DCNT_BTCNT_FREEZE:
|
cnt = cx->cnt_bt[BTC_BCNT_HIPRI_RX] +
|
cx->cnt_bt[BTC_BCNT_HIPRI_TX] +
|
cx->cnt_bt[BTC_BCNT_LOPRI_RX] +
|
cx->cnt_bt[BTC_BCNT_LOPRI_TX];
|
|
if (cnt == 0)
|
dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE]++;
|
else
|
dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] = 0;
|
|
if ((dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] >= BTC_CHK_HANG_MAX &&
|
bt->enable.now) || (!dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] &&
|
!bt->enable.now))
|
_update_bt_scbd(btc, false);
|
break;
|
case BTC_DCNT_WL_SLOT_DRIFT:
|
if (cnt >= BTC_CHK_WLSLOT_DRIFT_MAX)
|
dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT]++;
|
else
|
dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] = 0;
|
|
if (dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
|
dm->error.map.wl_slot_drift = true;
|
else
|
dm->error.map.wl_slot_drift = false;
|
break;
|
case BTC_DCNT_BT_SLOT_DRIFT:
|
if (cnt >= BTC_CHK_BTSLOT_DRIFT_MAX)
|
dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT]++;
|
else
|
dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT] = 0;
|
|
if (dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
|
dm->error.map.bt_slot_drift = true;
|
else
|
dm->error.map.bt_slot_drift = false;
|
break;
|
}
|
}
|
|
static void _update_bt_report(struct btc_t *btc, u8 rpt_type, u8* pfinfo)
|
{
|
struct rtw_hal_com_t *h = btc->hal;
|
struct btc_bt_info *bt = &btc->cx.bt;
|
struct btc_bt_link_info *bt_linfo = &bt->link_info;
|
struct btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc;
|
|
struct fbtc_btver* pver = (struct fbtc_btver*) pfinfo;
|
struct fbtc_btscan* pscan = (struct fbtc_btscan*) pfinfo;
|
struct fbtc_btafh* pafh = (struct fbtc_btafh*) pfinfo;
|
struct fbtc_btdevinfo* pdev = (struct fbtc_btdevinfo*) pfinfo;
|
|
switch (rpt_type) {
|
case BTC_RPT_TYPE_BT_VER:
|
bt->ver_info.fw = pver->fw_ver;
|
bt->ver_info.fw_coex = (pver->coex_ver & bMASKB0);
|
bt->feature = pver->feature;
|
break;
|
case BTC_RPT_TYPE_BT_SCAN:
|
hal_mem_cpy(h, bt->scan_info, pscan->scan, BTC_SCAN_MAX1);
|
break;
|
case BTC_RPT_TYPE_BT_AFH:
|
hal_mem_cpy(h, &bt_linfo->afh_map[0], pafh->afh_l, 4);
|
hal_mem_cpy(h, &bt_linfo->afh_map[4], pafh->afh_m, 4);
|
hal_mem_cpy(h, &bt_linfo->afh_map[8], pafh->afh_h, 2);
|
break;
|
case BTC_RPT_TYPE_BT_DEVICE:
|
a2dp->device_name = pdev->dev_name;
|
a2dp->vendor_id = pdev->vendor_id;
|
a2dp->flush_time = pdev->flush_time;
|
break;
|
default:
|
break;
|
}
|
}
|
|
static u32 _chk_btc_report(struct btc_t *btc, struct btf_fwinfo *pfwinfo,
|
u8 *prptbuf, u32 index)
|
{
|
struct btc_dm *dm = &btc->dm;
|
struct rtw_hal_com_t *hal = btc->hal;
|
struct btc_rpt_cmn_info *pcinfo = NULL;
|
struct btc_wl_info *wl = &btc->cx.wl;
|
struct btc_bt_info *bt = &btc->cx.bt;
|
struct fbtc_rpt_ctrl *prpt = NULL;
|
struct fbtc_cysta *pcysta = NULL;
|
u8 rpt_type = 0, *rpt_content = NULL, *pfinfo = NULL;
|
u16 wl_slot_set = 0, polt_cnt = 0;
|
u32 rpt_len = 0, diff_t, bt_slot_real = 0;
|
|
if (!prptbuf) {
|
pfwinfo->err[BTFRE_INVALID_INPUT]++;
|
return 0;
|
}
|
|
rpt_type = prptbuf[index];
|
rpt_len = (prptbuf[index+2] << 8) + prptbuf[index+1];
|
rpt_content = &prptbuf[index+3];
|
|
switch (rpt_type) {
|
case BTC_RPT_TYPE_CTRL:
|
pcinfo = &pfwinfo->rpt_ctrl.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_ctrl.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_rpt_ctrl);
|
pcinfo->req_fver = FCX_BTCRPT_VER;
|
pcinfo->rsp_fver = *rpt_content;
|
break;
|
case BTC_RPT_TYPE_TDMA:
|
pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_tdma.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_1tdma);
|
pcinfo->req_fver = FCX_TDMA_VER;
|
break;
|
case BTC_RPT_TYPE_SLOT:
|
pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_slots.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_slots);
|
pcinfo->req_fver = FCX_SLOT_VER;
|
break;
|
case BTC_RPT_TYPE_CYSTA:
|
pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_cysta.finfo);
|
pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
|
pcinfo->req_len = sizeof(struct fbtc_cysta);
|
pcinfo->req_fver = FCX_CYSTA_VER;
|
break;
|
case BTC_RPT_TYPE_STEP:
|
pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_step.finfo);
|
pcinfo->req_len = 8 + sizeof(struct fbtc_step) * FCXDEF_STEP;
|
pcinfo->req_fver = FCX_STEP_VER;
|
break;
|
case BTC_RPT_TYPE_NULLSTA:
|
pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_nullsta.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_cynullsta);
|
pcinfo->req_fver = FCX_NULLSTA_VER;
|
break;
|
case BTC_RPT_TYPE_MREG:
|
pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_mregval.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_mreg_val);
|
pcinfo->req_fver = FCX_MREG_VER;
|
break;
|
case BTC_RPT_TYPE_GPIO_DBG:
|
pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_gpio_dbg.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_gpio_dbg);
|
pcinfo->req_fver = FCX_GPIODBG_VER;
|
break;
|
case BTC_RPT_TYPE_BT_VER:
|
pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btver.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_btver);
|
pcinfo->req_fver = FCX_BTVER_VER;
|
break;
|
case BTC_RPT_TYPE_BT_SCAN:
|
pcinfo = &pfwinfo->rpt_fbtc_btscan.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btscan.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_btscan);
|
pcinfo->req_fver = FCX_BTSCAN_VER;
|
break;
|
case BTC_RPT_TYPE_BT_AFH:
|
pcinfo = &pfwinfo->rpt_fbtc_btafh.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btafh.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_btafh);
|
pcinfo->req_fver = FCX_BTAFH_VER;
|
break;
|
case BTC_RPT_TYPE_BT_DEVICE:
|
pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo;
|
pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btdev.finfo);
|
pcinfo->req_len = sizeof(struct fbtc_btdevinfo);
|
pcinfo->req_fver = FCX_BTDEVINFO_VER;
|
break;
|
default:
|
pfwinfo->err[BTFRE_UNDEF_TYPE]++;
|
return 0;
|
}
|
|
pcinfo->rsp_fver = *rpt_content;
|
pcinfo->rx_len = rpt_len;
|
pcinfo->rx_cnt++;
|
|
if (rpt_len != pcinfo->req_len) {
|
if (rpt_type < BTC_RPT_TYPE_MAX)
|
pfwinfo->len_mismch |= (0x1 << rpt_type);
|
else
|
pfwinfo->len_mismch |= BIT31;
|
|
pcinfo->valid = 0;
|
return 0;
|
} else if (pcinfo->req_fver != pcinfo->rsp_fver) {
|
if (rpt_type < BTC_RPT_TYPE_MAX)
|
pfwinfo->fver_mismch |= (0x1 << rpt_type);
|
else
|
pfwinfo->fver_mismch |= BIT31;
|
pcinfo->valid = 0;
|
return 0;
|
} else if (!pfinfo || !rpt_content || !pcinfo->req_len) {
|
pfwinfo->err[BTFRE_EXCEPTION]++;
|
pcinfo->valid = 0;
|
return 0;
|
}
|
|
|
hal_mem_cpy(hal, (void *)pfinfo, (void *)rpt_content, pcinfo->req_len);
|
pcinfo->valid = 1;
|
|
if (rpt_type == BTC_RPT_TYPE_TDMA) {
|
#if BTC_CX_FW_OFFLOAD /* update tdma_now if fw offload for debug */
|
_tdma_cpy(&dm->tdma_now, &pfwinfo->rpt_fbtc_tdma.finfo.tdma);
|
#else
|
_chk_btc_err(btc, BTC_DCNT_TDMA_NONSYNC,
|
_tdma_cmp(&dm->tdma_now,
|
&pfwinfo->rpt_fbtc_tdma.finfo.tdma));
|
#endif
|
}
|
|
if (rpt_type == BTC_RPT_TYPE_SLOT) {
|
#if BTC_CX_FW_OFFLOAD /* update slot_now if fw offload for debug */
|
_slots_cpy(dm->slot_now, pfwinfo->rpt_fbtc_slots.finfo.slot);
|
#else
|
_chk_btc_err(btc, BTC_DCNT_SLOT_NONSYNC,
|
_tdma_cmp(dm->slot_now,
|
pfwinfo->rpt_fbtc_slots.finfo.slot));
|
#endif
|
}
|
|
if (rpt_type == BTC_RPT_TYPE_CYSTA &&
|
pcysta->cycles >= BTC_CYSTA_CHK_PERIOD) {
|
/* Check Leak-AP */
|
if (pcysta->slot_cnt[CXST_LK] != 0 &&
|
pcysta->leak_slot.cnt_rximr != 0 && dm->tdma_now.rxflctrl) {
|
if (pcysta->slot_cnt[CXST_LK] <
|
BTC_LEAK_AP_TH * pcysta->leak_slot.cnt_rximr)
|
dm->leak_ap = 1;
|
}
|
|
/* Check diff time between real WL slot and W1 slot */
|
if (dm->tdma_now.type != CXTDMA_OFF) {
|
wl_slot_set = dm->slot_now[CXST_W1].dur;
|
|
if (pcysta->cycle_time.tavg[CXT_WL] > wl_slot_set) {
|
diff_t = pcysta->cycle_time.tavg[CXT_WL] -
|
wl_slot_set;
|
_chk_btc_err(btc, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
|
}
|
}
|
|
/* Check diff time between real BT slot and EBT/E5G slot */
|
if (dm->tdma_now.type == CXTDMA_OFF &&
|
dm->tdma_now.ext_ctrl == CXECTL_EXT &&
|
btc->bt_req_len != 0) {
|
bt_slot_real = pcysta->cycle_time.tavg[CXT_BT];
|
|
if (btc->bt_req_len > bt_slot_real) {
|
diff_t = btc->bt_req_len - bt_slot_real;
|
_chk_btc_err(btc, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
|
}
|
|
}
|
|
_chk_btc_err(btc, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_W1]);
|
_chk_btc_err(btc, BTC_DCNT_B1_FREEZE, pcysta->slot_cnt[CXST_B1]);
|
_chk_btc_err(btc, BTC_DCNT_CYCLE_FREEZE, (u32)pcysta->cycles);
|
}
|
|
if (rpt_type == BTC_RPT_TYPE_CTRL) {
|
prpt = &pfwinfo->rpt_ctrl.finfo;
|
btc->fwinfo.rpt_en_map = prpt->rpt_info.en;
|
wl->ver_info.fw_coex = prpt->wl_fw_info.cx_ver;
|
wl->ver_info.fw = prpt->wl_fw_info.fw_ver;
|
dm->wl_fw_cx_offload = !!(prpt->wl_fw_info.cx_offload);
|
|
if (dm->wl_fw_cx_offload != BTC_CX_FW_OFFLOAD)
|
dm->error.map.offload_mismatch = true;
|
else
|
dm->error.map.offload_mismatch = false;
|
|
if (prpt->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT] > 0)
|
bt->rfk_info.map.timeout = 1;
|
else
|
bt->rfk_info.map.timeout = 0;
|
|
dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
|
|
_chk_btc_err(btc, BTC_DCNT_RPT_FREEZE,
|
pfwinfo->event[BTF_EVNT_RPT]);
|
|
/* To avoid I/O if WL LPS or power-off */
|
if (wl->status.map.lps != BTC_LPS_RF_OFF &&
|
!wl->status.map.rf_off) {
|
btc->chip->ops->update_bt_cnt(btc);
|
_chk_btc_err(btc, BTC_DCNT_BTCNT_FREEZE, 0);
|
rtw_hal_mac_get_bt_polt_cnt(btc->hal, HW_PHY_0,
|
&polt_cnt);
|
btc->cx.cnt_bt[BTC_BCNT_POLUT] = polt_cnt;
|
}
|
}
|
|
if (rpt_type >= BTC_RPT_TYPE_BT_VER &&
|
rpt_type <= BTC_RPT_TYPE_BT_DEVICE)
|
_update_bt_report(btc, rpt_type, pfinfo);
|
|
return (rpt_len + BTC_RPT_HDR_SIZE);
|
}
|
|
static void _parse_btc_report(struct btc_t *btc, struct btf_fwinfo *pfwinfo,
|
u8 *pbuf, u32 buf_len)
|
{
|
u32 index = 0, rpt_len = 0;
|
|
while (pbuf) {
|
if (index+2 >= RTW_PHL_BTC_FWINFO_BUF)
|
break;
|
/* At least 3 bytes: type(1) & len(2) */
|
rpt_len = (pbuf[index+2] << 8) + pbuf[index+1];
|
if ((index + rpt_len + BTC_RPT_HDR_SIZE) > buf_len)
|
break;
|
|
rpt_len = _chk_btc_report(btc, pfwinfo, pbuf, index);
|
if (!rpt_len)
|
break;
|
index += rpt_len;
|
}
|
}
|
|
static void _append_tdma(struct btc_t *btc, bool force_exec)
|
{
|
struct btc_dm *dm = &btc->dm;
|
struct btf_tlv *tlv = NULL;
|
struct fbtc_1tdma *v = NULL;
|
u16 len = btc->policy_len;
|
|
if (!force_exec && !_tdma_cmp(&dm->tdma, &dm->tdma_now)) {
|
PHL_TRACE(COMP_PHL_BTC, _PHL_DEBUG_, "[BTC], %s(): tdma no change!\n",
|
__func__);
|
return;
|
}
|
|
tlv = (struct btf_tlv *)&btc->policy[len];
|
tlv->type = CXPOLICY_TDMA;
|
tlv->len = sizeof(struct fbtc_1tdma);
|
v = (struct fbtc_1tdma *)&tlv->val[0];
|
v->fver = FCX_TDMA_VER;
|
|
_tdma_cpy(&v->tdma, &dm->tdma);
|
|
btc->policy_len = len + 2 + sizeof(struct fbtc_1tdma);
|
|
PHL_INFO("[BTC], %s: type:%d, rxflctrl=%d, txflctrl=%d, wtgle_n=%d, leak_n=%d, ext_ctrl=%d, rxflctrl_role=0x%x\n",
|
__func__, dm->tdma.type, dm->tdma.rxflctrl, dm->tdma.txflctrl,
|
dm->tdma.wtgle_n, dm->tdma.leak_n, dm->tdma.ext_ctrl,
|
dm->tdma.rxflctrl_role);
|
}
|
|
static void _append_slot(struct btc_t *btc, bool force_exec)
|
{
|
struct btc_dm *dm = &btc->dm;
|
struct btf_tlv *tlv = NULL;
|
struct fbtc_1slot *v = NULL;
|
u16 len = 0;
|
u8 i, cnt = 0;
|
|
for (i = 0; i < CXST_MAX; i++) {
|
if (!force_exec && !_slot_cmp(&dm->slot[i], &dm->slot_now[i]))
|
continue;
|
|
len = btc->policy_len;
|
|
tlv = (struct btf_tlv *)&btc->policy[len];
|
tlv->type = CXPOLICY_SLOT;
|
tlv->len = sizeof(struct fbtc_1slot);
|
v = (struct fbtc_1slot *)&tlv->val[0];
|
|
v->fver = FCX_SLOT_VER;
|
v->sid = i;
|
_slot_cpy(&v->slot, &dm->slot[i]);
|
|
PHL_INFO("[BTC], %s: slot-%d: dur=%d, table=0x%08x, type=%d\n",
|
__func__, i,dm->slot[i].dur, dm->slot[i].cxtbl,
|
dm->slot[i].cxtype);
|
cnt++;
|
btc->policy_len = len + 2 + sizeof(struct fbtc_1slot);
|
}
|
|
if (cnt > 0)
|
PHL_INFO("[BTC], %s: slot update (cnt=%d)!!\n", __func__, cnt);
|
}
|
|
/*
|
* extern functions
|
*/
|
|
void hal_btc_fw_en_rpt(struct btc_t *btc, u32 rpt_map, u32 rpt_state)
|
{
|
struct btc_ops *ops = btc->ops;
|
struct btf_set_report r = {0};
|
struct btf_fwinfo* fwinfo = &btc->fwinfo;
|
u32 val = 0;
|
u8 en;
|
|
if (!ops || !ops->fw_cmd)
|
return;
|
|
en = rpt_state & 0x1;
|
if (en)
|
val = fwinfo->rpt_en_map | rpt_map;
|
else
|
val = fwinfo->rpt_en_map & (~rpt_map);
|
|
if (val == fwinfo->rpt_en_map)
|
return;
|
|
fwinfo->rpt_en_map = val;
|
|
r.fver = FCX_BTCRPT_VER;
|
r.enable = val;
|
r.para = en;
|
|
ops->fw_cmd(btc, BTFC_SET, SET_REPORT_EN, (u8 *)&r, sizeof(r));
|
}
|
|
void hal_btc_fw_set_slots(struct btc_t *btc, u8 num, struct fbtc_slot *s)
|
{
|
#if !BTC_CX_FW_OFFLOAD
|
struct rtw_hal_com_t *h = btc->hal;
|
struct btc_ops *ops = btc->ops;
|
struct btf_set_slot_table *tbl = NULL;
|
u8 *ptr = NULL;
|
u16 n = 0;
|
|
if (!ops || !ops->fw_cmd)
|
return;
|
|
n = (sizeof(struct fbtc_slot) * num) + sizeof(*tbl) - 1;
|
tbl = hal_mem_alloc(h, n);
|
if (!tbl)
|
return;
|
|
tbl->fver = FCX_SLOT_VER;
|
tbl->tbl_num = num;
|
ptr = &tbl->buf[0];
|
hal_mem_cpy(h, (void*)ptr, s, num * sizeof(struct fbtc_slot));
|
|
ops->fw_cmd(btc, BTFC_SET, SET_SLOT_TABLE, (u8*)tbl, n);
|
hal_mem_free(h, (void*)tbl, n);
|
#endif
|
}
|
|
/* set RPT_EN_MREG = 0 to stop 2s monitor timer in WL FW,
|
* before SET_MREG_TABLE, and set RPT_EN_MREG = 1 after
|
* SET_MREG_TABLE
|
*/
|
void hal_btc_fw_set_monreg(struct btc_t *btc)
|
{
|
struct rtw_hal_com_t *h = btc->hal;
|
struct btc_ops *ops = btc->ops;
|
struct btf_set_mon_reg *monreg = NULL;
|
u8 n, *ptr = NULL, ulen;
|
u16 sz = 0;
|
|
if (!ops || !ops->fw_cmd)
|
return;
|
|
n = btc->chip->mon_reg_num;
|
|
if (n > CXMREG_MAX) {
|
PHL_TRACE(COMP_PHL_BTC, _PHL_ERR_, "[BTC], mon reg count %d > %d\n",
|
n, CXMREG_MAX);
|
return;
|
}
|
|
ulen = sizeof(struct fbtc_mreg);
|
sz = (ulen * n) + sizeof(*monreg) - 1;
|
monreg = hal_mem_alloc(h, sz);
|
if (!monreg)
|
return;
|
|
monreg->fver = FCX_MREG_VER;
|
monreg->reg_num = n;
|
ptr = &monreg->buf[0];
|
hal_mem_cpy(h, (void *)ptr, btc->chip->mon_reg, n * ulen);
|
|
ops->fw_cmd(btc, BTFC_SET, SET_MREG_TABLE, (u8 *)monreg, sz);
|
hal_mem_free(h, (void *)monreg, sz);
|
hal_btc_fw_en_rpt(btc, RPT_EN_MREG, 1);
|
}
|
|
bool hal_btc_fw_set_1tdma(struct btc_t *btc, u16 len, u8 *buf)
|
{ /* for wlcli manual control */
|
struct btc_dm *dm = &btc->dm;
|
|
if (len != sizeof(struct fbtc_tdma)) {
|
PHL_TRACE(COMP_PHL_BTC, _PHL_ERR_, "[BTC], %s(): return because len != %d\n",
|
__func__, (int)sizeof(struct fbtc_tdma));
|
return false;
|
} else if (buf[0] >= CXTDMA_MAX) {
|
PHL_TRACE(COMP_PHL_BTC, _PHL_ERR_, "[BTC], %s(): return because tdma_type >= %d\n",
|
__func__, CXTDMA_MAX);
|
return false;
|
}
|
|
_tdma_cpy(&dm->tdma, buf);
|
return true;
|
}
|
|
bool hal_btc_fw_set_1slot(struct btc_t *btc, u16 len, u8 *buf)
|
{ /* for wlcli manual control */
|
struct btc_dm *dm = &btc->dm;
|
|
if (len != sizeof(struct fbtc_slot) + 1) {
|
PHL_TRACE(COMP_PHL_BTC, _PHL_ERR_, "[BTC], %s(): return because len != %d\n",
|
__func__, (int)sizeof(struct fbtc_slot) + 1);
|
return false;
|
} else if (buf[0] >= CXST_MAX) {
|
PHL_TRACE(COMP_PHL_BTC, _PHL_ERR_, "[BTC], %s(): return because slot_id >= %d\n",
|
__func__, CXST_MAX);
|
return false;
|
}
|
|
_slot_cpy(&dm->slot[buf[0]], &buf[1]);
|
return true;
|
}
|
|
bool hal_btc_fw_set_policy(struct btc_t *btc, bool force_exec, u16 policy_type,
|
const char* action)
|
{
|
struct btc_dm *dm = &btc->dm;
|
struct btc_ops *ops = btc->ops;
|
|
if (!ops || !ops->fw_cmd)
|
return false;
|
|
_act_cpy(dm->run_action, (char*)action);
|
_update_dm_step(btc, action);
|
_update_dm_step(btc, id_to_str(BTC_STR_POLICY, (u32)policy_type));
|
|
btc->policy_len = 0; /* clear length before append */
|
btc->policy_type = policy_type;
|
|
_append_tdma(btc, force_exec);
|
_append_slot(btc, force_exec);
|
|
if (btc->policy_len == 0 || btc->policy_len > BTC_POLICY_MAXLEN)
|
return false;
|
|
PHL_INFO("[BTC], %s(): action=%s -> policy type/len: 0x%04x/%d\n",
|
__func__, action, policy_type, btc->policy_len);
|
|
if (dm->tdma.rxflctrl == CXFLC_NULLP)
|
btc->hal->btc_ctrl.lps = 1;
|
else
|
btc->hal->btc_ctrl.lps = 0;
|
|
if (btc->hal->btc_ctrl.lps == 1)
|
hal_btc_notify_ps_tdma(btc, btc->hal->btc_ctrl.lps);
|
|
ops->fw_cmd(btc, BTFC_SET, SET_CX_POLICY, btc->policy, btc->policy_len);
|
|
_tdma_cpy(&dm->tdma_now, &dm->tdma);
|
_slots_cpy(dm->slot_now, dm->slot);
|
|
if (btc->hal->btc_ctrl.lps == 0)
|
hal_btc_notify_ps_tdma(btc, btc->hal->btc_ctrl.lps);
|
|
return true;
|
}
|
|
void hal_btc_fw_set_gpio_dbg(struct btc_t *btc, u8 type, u32 val)
|
{
|
struct rtw_hal_com_t *h = btc->hal;
|
struct btc_ops *ops = btc->ops;
|
u8 data[7] = {0}, len = 0;
|
|
if (!ops || !ops->fw_cmd || type >= CXDGPIO_MAX)
|
return;
|
|
PHL_TRACE(COMP_PHL_BTC, _PHL_DEBUG_, "[BTC], %s()\n", __func__);
|
|
data[0] = FCX_GPIODBG_VER;
|
data[1] = 0;
|
data[2] = type;
|
|
switch(type) {
|
case CXDGPIO_EN_MAP:
|
len = sizeof(u32) + 3;
|
hal_mem_cpy(h, &data[3], &val, sizeof(u32));
|
break;
|
case CXDGPIO_MUX_MAP:
|
len = sizeof(8) * 2 + 3;
|
data[3] = (u8)(val & bMASKB0);
|
data[4] = (u8)((val & bMASKB1) >> 8);
|
break;
|
default:
|
return;
|
}
|
|
ops->fw_cmd(btc, BTFC_SET, SET_GPIO_DBG, data, len);
|
}
|
|
void hal_btc_fw_set_drv_info(struct btc_t *btc, u8 type)
|
{
|
struct rtw_hal_com_t *h = btc->hal;
|
struct btc_wl_info *wl = &btc->cx.wl;
|
struct btc_dm *dm = &btc->dm;
|
struct btc_ops *ops = btc->ops;
|
u8 buf[256] = {0};
|
u8 sz = 0, n = 0;
|
|
if (!ops || !ops->fw_cmd || type >= CXDRVINFO_MAX)
|
return;
|
|
switch (type) {
|
case CXDRVINFO_INIT:
|
n = sizeof(dm->init_info);
|
sz = n + 2;
|
|
if (sz > sizeof(buf))
|
return;
|
|
buf[0] = CXDRVINFO_INIT;
|
buf[1] = n;
|
hal_mem_cpy(h, (void *)&buf[2], &dm->init_info, n);
|
break;
|
case CXDRVINFO_ROLE:
|
n = sizeof(wl->role_info);
|
sz = n + 2;
|
|
if (sz > sizeof(buf))
|
return;
|
|
buf[0] = CXDRVINFO_ROLE;
|
buf[1] = n;
|
hal_mem_cpy(h, (void *)&buf[2], &wl->role_info, n);
|
break;
|
case CXDRVINFO_CTRL:
|
n = sizeof(btc->ctrl);
|
sz = n + 2;
|
|
if (sz > sizeof(buf))
|
return;
|
|
buf[0] = CXDRVINFO_CTRL;
|
buf[1] = n;
|
hal_mem_cpy(h, (void *)&buf[2], &btc->ctrl, n);
|
break;
|
case CXDRVINFO_RFK:
|
n = sizeof(wl->rfk_info);
|
sz = n + 2;
|
|
if (sz > sizeof(buf))
|
return;
|
|
buf[0] = CXDRVINFO_RFK;
|
buf[1] = n;
|
hal_mem_cpy(h, (void *)&buf[2], &wl->rfk_info, n);
|
break;
|
#if BTC_CX_FW_OFFLOAD
|
case CXDRVINFO_DBCC:
|
n = sizeof(wl->dbcc_info);
|
sz = n + 2;
|
|
if (sz > sizeof(buf))
|
return;
|
|
buf[0] = CXDRVINFO_DBCC;
|
buf[1] = n;
|
hal_mem_cpy(h, (void *)&buf[2], &wl->dbcc_info, n);
|
break;
|
case CXDRVINFO_SMAP:
|
n = sizeof(wl->status);
|
sz = n + 2;
|
|
if (sz > sizeof(buf))
|
return;
|
|
buf[0] = CXDRVINFO_SMAP;
|
buf[1] = n;
|
hal_mem_cpy(h, (void *)&buf[2], &wl->status, n);
|
break;
|
case CXDRVINFO_RUN:
|
n = BTC_RSN_MAXLEN;
|
sz = n + 2;
|
|
if (sz > sizeof(buf))
|
return;
|
|
buf[0] = CXDRVINFO_RUN;
|
buf[1] = n;
|
hal_mem_cpy(h, (void *)&buf[2], dm->run_reason, n);
|
break;
|
case CXDRVINFO_SCAN:
|
n = sizeof(wl->scan_info);
|
sz = n + 2;
|
|
if (sz > sizeof(buf))
|
return;
|
|
buf[0] = CXDRVINFO_SCAN;
|
buf[1] = n;
|
hal_mem_cpy(h, (void *)&buf[2], &wl->scan_info, n);
|
break;
|
#endif
|
default:
|
return;
|
}
|
|
ops->fw_cmd(btc, BTFC_SET, SET_DRV_INFO, (u8*)buf, sz);
|
}
|
|
void hal_btc_fw_set_drv_event(struct btc_t *btc, u8 type)
|
{
|
struct btc_ops *ops = btc->ops;
|
|
if (!ops || !ops->fw_cmd)
|
return;
|
|
ops->fw_cmd(btc, BTFC_SET, SET_DRV_EVENT, &type, 1);
|
}
|
|
void hal_btc_fw_set_bt(struct btc_t *btc, u8 type, u16 len, u8* buf)
|
{
|
struct btc_ops *ops = btc->ops;
|
|
if (!ops || !ops->fw_cmd ||
|
(type < SET_BT_WREG_ADDR || type > SET_BT_GOLDEN_RX_RANGE))
|
return;
|
|
PHL_TRACE(COMP_PHL_BTC, _PHL_DEBUG_, "[BTC], %s()\n", __func__);
|
|
ops->fw_cmd(btc, BTFC_SET, type, buf, len);
|
}
|
|
void hal_btc_fw_event(struct btc_t *btc, u8 evt_id, void *data, u32 len)
|
{
|
struct btf_fwinfo *pfwinfo = &btc->fwinfo;
|
|
if (!len || !data)
|
return;
|
|
switch (evt_id) {
|
case BTF_EVNT_RPT:
|
_parse_btc_report(btc, pfwinfo, data, len);
|
break;
|
default:
|
break;
|
}
|
}
|
|
#endif
|