/******************************************************************************
*
* 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 _PHL_INIT_C_
#include "phl_headers.h"
void _phl_com_init_rssi_stat(struct rtw_phl_com_t *phl_com)
{
u8 i = 0, j = 0;
for (i = 0; i < RTW_RSSI_TYPE_MAX; i++) {
phl_com->rssi_stat.ma_rssi_ele_idx[i] = 0;
phl_com->rssi_stat.ma_rssi_ele_cnt[i] = 0;
phl_com->rssi_stat.ma_rssi_ele_sum[i] = 0;
phl_com->rssi_stat.ma_rssi[i] = 0;
for (j = 0; j < PHL_RSSI_MAVG_NUM; j++)
phl_com->rssi_stat.ma_rssi_ele[i][j] = 0;
}
_os_spinlock_init(phl_com->drv_priv, &(phl_com->rssi_stat.lock));
}
void _phl_com_deinit_rssi_stat(struct rtw_phl_com_t *phl_com)
{
_os_spinlock_free(phl_com->drv_priv, &(phl_com->rssi_stat.lock));
}
/**
* rtw_phl_init_ppdu_sts_para(...)
* Description:
* 1. Do not call this api after rx started.
* 2. PPDU Status per PKT settings
**/
void rtw_phl_init_ppdu_sts_para(struct rtw_phl_com_t *phl_com,
bool en_psts_per_pkt, bool psts_ampdu,
u8 rx_fltr)
{
#ifdef CONFIG_PHL_RX_PSTS_PER_PKT
phl_com->ppdu_sts_info.en_psts_per_pkt = en_psts_per_pkt;
phl_com->ppdu_sts_info.psts_ampdu = psts_ampdu;
#ifdef RTW_WKARD_DISABLE_PSTS_PER_PKT_DATA
/* Forced disable PSTS for DATA frame, to avoid unknown performance issue */
rx_fltr &= (~RTW_PHL_PSTS_FLTR_DATA);
#endif
phl_com->ppdu_sts_info.ppdu_sts_filter = rx_fltr;
#else
return;
#endif
}
void _phl_com_deinit_ppdu_sts(struct rtw_phl_com_t *phl_com)
{
#ifdef CONFIG_PHL_RX_PSTS_PER_PKT
u8 i = 0;
u8 j = 0;
for (j = 0; j < HW_BAND_MAX; j++) {
for (i = 0; i < PHL_MAX_PPDU_CNT; i++) {
if (phl_com->ppdu_sts_info.sts_ent[j][i].frames.cnt != 0) {
PHL_INFO("[Error] deinit_ppdu_sts : frame queue is not empty\n");
}
pq_deinit(phl_com->drv_priv,
&(phl_com->ppdu_sts_info.sts_ent[j][i].frames));
}
}
#else
return;
#endif
}
void _phl_com_init_ppdu_sts(struct rtw_phl_com_t *phl_com)
{
#ifdef CONFIG_PHL_RX_PSTS_PER_PKT
u8 i = 0;
#endif
u8 j = 0;
for (j = 0; j < HW_BAND_MAX; j++) {
phl_com->ppdu_sts_info.cur_rx_ppdu_cnt[j] = 0xFF;
}
#ifdef CONFIG_PHL_RX_PSTS_PER_PKT
/* Default enable when compile flag is set. */
phl_com->ppdu_sts_info.en_psts_per_pkt = true;
/**
* Filter of buffer pkt for phy status:
* if the correspond bit is set to 1,
* the pkt will be buffer till ppdu sts or next ppdu is processed.
**/
phl_com->ppdu_sts_info.ppdu_sts_filter =
RTW_PHL_PSTS_FLTR_MGNT | RTW_PHL_PSTS_FLTR_CTRL |
RTW_PHL_PSTS_FLTR_EXT_RSVD;
/* if set to false, only the first mpdu in ppdu has phy status */
phl_com->ppdu_sts_info.psts_ampdu = false;
phl_com->ppdu_sts_info.en_fake_psts = false;
for (j = 0; j < HW_BAND_MAX; j++) {
for (i = 0; i < PHL_MAX_PPDU_CNT; i++) {
pq_init(phl_com->drv_priv,
&(phl_com->ppdu_sts_info.sts_ent[j][i].frames));
}
}
#endif
#ifdef CONFIG_PHY_INFO_NTFY
phl_com->ppdu_sts_info.msg_aggr_cnt = 0;
#endif
}
static void phl_msg_entry(void* priv, struct phl_msg *msg)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
u8 mdl_id = MSG_MDL_ID_FIELD(msg->msg_id);
u16 evt_id = MSG_EVT_ID_FIELD(msg->msg_id);
PHL_DBG("[PHL]%s, mdl_id(%d)\n", __FUNCTION__, mdl_id);
/* dispatch received PHY msg here */
switch(mdl_id) {
case PHL_MDL_PHY_MGNT:
phl_msg_hub_phy_mgnt_evt_hdlr(phl_info, evt_id);
break;
case PHL_MDL_RX:
phl_msg_hub_rx_evt_hdlr(phl_info, evt_id, msg->inbuf, msg->inlen);
break;
case PHL_MDL_BTC:
rtw_phl_btc_hub_msg_hdl(phl_info, msg);
break;
default:
break;
}
}
static enum rtw_phl_status phl_register_msg_entry(struct phl_info_t *phl_info)
{
struct phl_msg_receiver ctx;
void *d = phl_to_drvpriv(phl_info);
u8 imr[] = {PHL_MDL_PHY_MGNT, PHL_MDL_RX, PHL_MDL_MRC, PHL_MDL_POWER_MGNT
, PHL_MDL_BTC};
_os_mem_set(d, &ctx, 0, sizeof(struct phl_msg_receiver));
ctx.incoming_evt_notify = phl_msg_entry;
ctx.priv = (void*)phl_info;
if( phl_msg_hub_register_recver((void*)phl_info,
&ctx, MSG_RECV_PHL) == RTW_PHL_STATUS_SUCCESS) {
/* PHL layer module should set IMR for receiving
desired PHY msg and handle it in phl_phy_evt_entry*/
phl_msg_hub_update_recver_mask((void*)phl_info, MSG_RECV_PHL,
imr, sizeof(imr), false);
return RTW_PHL_STATUS_SUCCESS;
}
else
return RTW_PHL_STATUS_FAILURE;
}
static enum rtw_phl_status phl_deregister_msg_entry(
struct phl_info_t *phl_info)
{
return phl_msg_hub_deregister_recver((void*)phl_info, MSG_RECV_PHL);
}
static enum rtw_phl_status phl_fw_init(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_RESOURCE;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_fw_info_t *fw_info = &phl_com->fw_info;
FUNCIN_WSTS(phl_status);
fw_info->rom_buff = _os_mem_alloc(phl_to_drvpriv(phl_info), RTW_MAX_FW_SIZE);
if (!fw_info->rom_buff) {
PHL_ERR("%s : rom buff allocate fail!!\n", __func__);
goto mem_alloc_fail;
}
fw_info->ram_buff = _os_mem_alloc(phl_to_drvpriv(phl_info), RTW_MAX_FW_SIZE);
if (!fw_info->ram_buff) {
PHL_ERR("%s : ram buff allocate fail!!\n", __func__);
goto mem_alloc_fail;
}
#ifdef CONFIG_PHL_REUSED_FWDL_BUF
fw_info->buf = _os_mem_alloc(phl_to_drvpriv(phl_info), RTW_MAX_FW_SIZE);
/* if allocating failed, fw bin files will be reading every time */
if (!fw_info->buf)
PHL_WARN("%s : buf for fw storage allocate fail!!\n", __func__);
fw_info->wow_buf = _os_mem_alloc(phl_to_drvpriv(phl_info), RTW_MAX_FW_SIZE);
/* if allocating failed, fw bin files will be reading every time */
if (!fw_info->wow_buf)
PHL_WARN("%s : wow buf for wowlan fw storage allocate fail!!\n", __func__);
#endif
phl_status = RTW_PHL_STATUS_SUCCESS;
FUNCOUT_WSTS(phl_status);
mem_alloc_fail:
return phl_status;
}
static void phl_fw_deinit(struct phl_info_t *phl_info)
{
struct rtw_fw_info_t *fw_info = &phl_info->phl_com->fw_info;
if (fw_info->rom_buff)
_os_mem_free(phl_to_drvpriv(phl_info), fw_info->rom_buff,
RTW_MAX_FW_SIZE);
if (fw_info->ram_buff)
_os_mem_free(phl_to_drvpriv(phl_info), fw_info->ram_buff,
RTW_MAX_FW_SIZE);
#ifdef CONFIG_REUSED_FWDL_BUF
if (fw_info->buf)
_os_mem_free(phl_to_drvpriv(phl_info), fw_info->buf,
RTW_MAX_FW_SIZE);
if (fw_info->wow_buf)
_os_mem_free(phl_to_drvpriv(phl_info), fw_info->wow_buf,
RTW_MAX_FW_SIZE);
#endif
/* allocate in rtw_hal_ld_fw_symbol */
if (fw_info->sym_buf)
_os_mem_free(phl_to_drvpriv(phl_info), fw_info->sym_buf,
RTW_MAX_FW_SIZE);
}
static enum rtw_phl_status
phl_register_background_module_entry(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
#ifdef CONFIG_CMD_DISP
/*
* setup struct phl_module_ops & call dispr_register_module
* to register background module instance.
* call dispr_deregister_module if you need to dynamically
* deregister the instance of background module.
*/
/* 1,2,3 cmd controller section */
/* 41 ~ 70 mandatory background module section*/
#ifdef CONFIG_PHL_CMD_SER
phl_status = phl_register_ser_module(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
return phl_status;
#endif
#ifdef CONFIG_POWER_SAVE
phl_status = phl_register_ps_module(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
return phl_status;
#endif
/* 70 ~ 127 optional background module section*/
#ifdef CONFIG_PHL_CMD_BTC
phl_status = phl_register_btc_module(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
return phl_status;
#endif
phl_status = phl_register_custom_module(phl_info, HW_BAND_0);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
return phl_status;
phl_status = phl_register_led_module(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
return phl_status;
phl_status = phl_register_cmd_general(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
return phl_status;
/* 10 ~ 40 protocol, wifi role section*/
phl_status = phl_register_mrc_module(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
return phl_status;
phl_status = phl_snd_cmd_register_module(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
return phl_status;
#else
phl_status = RTW_PHL_STATUS_SUCCESS;
#endif
return phl_status;
}
static enum rtw_phl_status phl_com_init(void *drv_priv,
struct phl_info_t *phl_info,
struct rtw_ic_info *ic_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
phl_info->phl_com = _os_mem_alloc(drv_priv,
sizeof(struct rtw_phl_com_t));
if (phl_info->phl_com == NULL) {
phl_status = RTW_PHL_STATUS_RESOURCE;
PHL_ERR("alloc phl_com failed\n");
goto error_phl_com_mem;
}
phl_info->phl_com->phl_priv = phl_info;
phl_info->phl_com->drv_priv = drv_priv;
phl_info->phl_com->hci_type = ic_info->hci_type;
phl_info->phl_com->edcca_mode = RTW_EDCCA_NORMAL;
phl_sw_cap_init(phl_info->phl_com);
_os_spinlock_init(drv_priv, &phl_info->phl_com->evt_info.evt_lock);
phl_fw_init(phl_info);
#ifdef CONFIG_PHL_CHANNEL_INFO
phl_status = phl_chaninfo_init(phl_info);
if (phl_status)
goto error_phl_com_mem;
#endif /* CONFIG_PHL_CHANNEL_INFO */
_phl_com_init_rssi_stat(phl_info->phl_com);
_phl_com_init_ppdu_sts(phl_info->phl_com);
phl_status = RTW_PHL_STATUS_SUCCESS;
return phl_status;
error_phl_com_mem:
return phl_status;
}
static enum rtw_phl_status phl_hci_init(struct phl_info_t *phl_info,
struct rtw_ic_info *ic_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
phl_info->hci = _os_mem_alloc(phl_to_drvpriv(phl_info),
sizeof(struct hci_info_t));
if (phl_info->hci == NULL) {
phl_status = RTW_PHL_STATUS_RESOURCE;
goto error_hci_mem;
}
#ifdef CONFIG_USB_HCI
phl_info->hci->usb_bulkout_size = ic_info->usb_info.usb_bulkout_size;
#endif
/* init variable of hci_info_t struct */
phl_status = RTW_PHL_STATUS_SUCCESS;
error_hci_mem:
return phl_status;
}
static void phl_com_deinit(struct phl_info_t *phl_info,
struct rtw_phl_com_t *phl_com)
{
void *drv_priv = phl_to_drvpriv(phl_info);
/* deinit variable or stop mechanism. */
if (phl_com) {
phl_sw_cap_deinit(phl_info->phl_com);
_os_spinlock_free(drv_priv, &phl_com->evt_info.evt_lock);
_phl_com_deinit_rssi_stat(phl_info->phl_com);
_phl_com_deinit_ppdu_sts(phl_info->phl_com);
phl_fw_deinit(phl_info);
#ifdef CONFIG_PHL_CHANNEL_INFO
phl_chaninfo_deinit(phl_info);
#endif /* CONFIG_PHL_CHANNEL_INFO */
_os_mem_free(drv_priv, phl_com, sizeof(struct rtw_phl_com_t));
}
}
static void phl_hci_deinit(struct phl_info_t *phl_info, struct hci_info_t *hci)
{
/* deinit variable or stop mechanism. */
if (hci)
_os_mem_free(phl_to_drvpriv(phl_info), hci,
sizeof(struct hci_info_t));
}
static enum rtw_phl_status _phl_hci_ops_check(struct phl_info_t *phl_info)
{
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
struct phl_hci_trx_ops *trx_ops = phl_info->hci_trx_ops;
if (!trx_ops->hci_trx_init) {
phl_ops_error_msg("hci_trx_init");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->hci_trx_deinit) {
phl_ops_error_msg("hci_trx_deinit");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->prepare_tx) {
phl_ops_error_msg("prepare_tx");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->recycle_rx_buf) {
phl_ops_error_msg("recycle_rx_buf");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->tx) {
phl_ops_error_msg("tx");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->rx) {
phl_ops_error_msg("rx");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->trx_cfg) {
phl_ops_error_msg("trx_cfg");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->pltfm_tx) {
phl_ops_error_msg("pltfm_tx");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->alloc_h2c_pkt_buf) {
phl_ops_error_msg("alloc_h2c_pkt_buf");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->free_h2c_pkt_buf) {
phl_ops_error_msg("free_h2c_pkt_buf");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->trx_reset) {
phl_ops_error_msg("trx_reset");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->trx_resume) {
phl_ops_error_msg("trx_resume");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->req_tx_stop) {
phl_ops_error_msg("req_tx_stop");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->req_rx_stop) {
phl_ops_error_msg("req_rx_stop");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->is_tx_pause) {
phl_ops_error_msg("is_tx_pause");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->is_rx_pause) {
phl_ops_error_msg("is_rx_pause");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->get_txbd_buf) {
phl_ops_error_msg("get_txbd_buf");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->get_rxbd_buf) {
phl_ops_error_msg("get_rxbd_buf");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->recycle_rx_pkt) {
phl_ops_error_msg("recycle_rx_pkt");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->register_trx_hdlr) {
phl_ops_error_msg("register_trx_hdlr");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->rx_handle_normal) {
phl_ops_error_msg("rx_handle_normal");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->tx_watchdog) {
phl_ops_error_msg("tx_watchdog");
status = RTW_PHL_STATUS_FAILURE;
}
#ifdef CONFIG_PCI_HCI
if (!trx_ops->recycle_busy_wd) {
phl_ops_error_msg("recycle_busy_wd");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->recycle_busy_h2c) {
phl_ops_error_msg("recycle_busy_h2c");
status = RTW_PHL_STATUS_FAILURE;
}
#endif
#ifdef CONFIG_USB_HCI
if (!trx_ops->pend_rxbuf) {
phl_ops_error_msg("pend_rxbuf");
status = RTW_PHL_STATUS_FAILURE;
}
if (!trx_ops->recycle_tx_buf) {
phl_ops_error_msg("recycle_tx_buf");
status = RTW_PHL_STATUS_FAILURE;
}
#endif
return status;
}
static enum rtw_phl_status phl_set_hci_ops(struct phl_info_t *phl_info)
{
#ifdef CONFIG_PCI_HCI
if (phl_get_hci_type(phl_info->phl_com) == RTW_HCI_PCIE)
phl_hook_trx_ops_pci(phl_info);
#endif
#ifdef CONFIG_USB_HCI
if (phl_get_hci_type(phl_info->phl_com) == RTW_HCI_USB)
phl_hook_trx_ops_usb(phl_info);
#endif
#ifdef CONFIG_SDIO_HCI
if (phl_get_hci_type(phl_info->phl_com) == RTW_HCI_SDIO)
phl_hook_trx_ops_sdio(phl_info);
#endif
return _phl_hci_ops_check(phl_info);
}
#ifdef CONFIG_FSM
static enum rtw_phl_status phl_cmd_init(struct phl_info_t *phl_info)
{
if (phl_info->cmd_fsm != NULL)
return RTW_PHL_STATUS_FAILURE;
phl_info->cmd_fsm = phl_cmd_new_fsm(phl_info->fsm_root, phl_info);
if (phl_info->cmd_fsm == NULL)
return RTW_PHL_STATUS_FAILURE;
if (phl_info->cmd_obj != NULL)
goto obj_fail;
phl_info->cmd_obj = phl_cmd_new_obj(phl_info->cmd_fsm, phl_info);
if (phl_info->cmd_obj == NULL)
goto obj_fail;
return RTW_PHL_STATUS_SUCCESS;
obj_fail:
phl_fsm_deinit_fsm(phl_info->cmd_fsm);
phl_info->cmd_fsm = NULL;
return RTW_PHL_STATUS_FAILURE;
}
static void phl_cmd_deinit(struct phl_info_t *phl_info)
{
phl_cmd_destory_obj(phl_info->cmd_obj);
phl_info->cmd_obj = NULL;
phl_cmd_destory_fsm(phl_info->cmd_fsm);
phl_info->cmd_fsm = NULL;
}
static enum rtw_phl_status phl_ser_init(struct phl_info_t *phl_info)
{
if (phl_info->ser_fsm != NULL)
return RTW_PHL_STATUS_FAILURE;
phl_info->ser_fsm = phl_ser_new_fsm(phl_info->fsm_root, phl_info);
if (phl_info->ser_fsm == NULL)
return RTW_PHL_STATUS_FAILURE;
if (phl_info->ser_obj != NULL)
goto obj_fail;
phl_info->ser_obj = phl_ser_new_obj(phl_info->ser_fsm, phl_info);
if (phl_info->ser_obj == NULL)
goto obj_fail;
return RTW_PHL_STATUS_SUCCESS;
obj_fail:
phl_ser_destory_fsm(phl_info->ser_fsm);
phl_info->ser_fsm = NULL;
return RTW_PHL_STATUS_FAILURE;
}
static void phl_ser_deinit(struct phl_info_t *phl_info)
{
phl_ser_destory_obj(phl_info->ser_obj);
phl_info->ser_obj = NULL;
phl_ser_destory_fsm(phl_info->ser_fsm);
phl_info->ser_fsm = NULL;
}
static enum rtw_phl_status phl_btc_init(struct phl_info_t *phl_info)
{
if (phl_info->btc_fsm != NULL)
return RTW_PHL_STATUS_FAILURE;
phl_info->btc_fsm = phl_btc_new_fsm(phl_info->fsm_root, phl_info);
if (phl_info->btc_fsm == NULL)
return RTW_PHL_STATUS_FAILURE;
phl_info->btc_obj = phl_btc_new_obj(phl_info->btc_fsm, phl_info);
if (phl_info->btc_obj == NULL)
goto obj_fail;
return RTW_PHL_STATUS_SUCCESS;
obj_fail:
phl_fsm_deinit_fsm(phl_info->btc_fsm);
phl_info->btc_fsm = NULL;
return RTW_PHL_STATUS_FAILURE;
}
static void phl_btc_deinit(struct phl_info_t *phl_info)
{
phl_btc_destory_obj(phl_info->btc_obj);
phl_info->btc_obj = NULL;
phl_btc_destory_fsm(phl_info->btc_fsm);
phl_info->btc_fsm = NULL;
}
static enum rtw_phl_status phl_scan_init(struct phl_info_t *phl_info)
{
if (phl_info->scan_fsm != NULL)
return RTW_PHL_STATUS_FAILURE;
phl_info->scan_fsm = phl_scan_new_fsm(phl_info->fsm_root, phl_info);
if (phl_info->scan_fsm == NULL)
return RTW_PHL_STATUS_FAILURE;
if (phl_info->scan_obj != NULL)
goto obj_fail;
phl_info->scan_obj = phl_scan_new_obj(phl_info->scan_fsm, phl_info);
if (phl_info->scan_obj == NULL)
goto obj_fail;
return RTW_PHL_STATUS_SUCCESS;
obj_fail:
phl_fsm_deinit_fsm(phl_info->scan_fsm);
phl_info->scan_fsm = NULL;
return RTW_PHL_STATUS_FAILURE;
}
static void phl_scan_deinit(struct phl_info_t *phl_info)
{
phl_scan_destory_obj(phl_info->scan_obj);
phl_info->scan_obj = NULL;
phl_scan_destory_fsm(phl_info->scan_fsm);
phl_info->scan_fsm = NULL;
}
static enum rtw_phl_status phl_sound_init(struct phl_info_t *phl_info)
{
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
if (phl_info->snd_fsm!= NULL)
return RTW_PHL_STATUS_FAILURE;
phl_info->snd_fsm = phl_sound_new_fsm(phl_info->fsm_root, phl_info);
if (phl_info->snd_fsm == NULL)
return RTW_PHL_STATUS_FAILURE;
pstatus = phl_snd_new_obj(phl_info->snd_fsm, phl_info);
if (pstatus != RTW_PHL_STATUS_SUCCESS)
goto obj_fail;
return pstatus;
obj_fail:
phl_fsm_deinit_fsm(phl_info->snd_fsm);
phl_info->snd_fsm = NULL;
return RTW_PHL_STATUS_FAILURE;
}
static void phl_sound_deinit(struct phl_info_t *phl_info)
{
phl_snd_destory_obj(phl_info->snd_obj);
phl_info->snd_obj = NULL;
phl_snd_destory_fsm(phl_info->snd_fsm);
phl_info->snd_fsm = NULL;
}
static enum rtw_phl_status phl_fsm_init(struct phl_info_t *phl_info)
{
if (phl_info->fsm_root != NULL)
return RTW_PHL_STATUS_FAILURE;
/* allocate memory for fsm to do version control */
phl_info->fsm_root = phl_fsm_init_root(phl_info);
if (phl_info->fsm_root == NULL)
return RTW_PHL_STATUS_FAILURE;
return RTW_PHL_STATUS_SUCCESS;
}
static void phl_fsm_deinit(struct phl_info_t *phl_info)
{
/* free memory for fsm */
phl_fsm_deinit_root(phl_info->fsm_root);
phl_info->fsm_root = NULL;
}
static enum rtw_phl_status phl_fsm_module_init(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
phl_status = phl_cmd_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_cmd_init failed\n");
goto cmd_fail;
}
phl_status = phl_ser_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_ser_init failed\n");
goto ser_fail;
}
phl_status = phl_btc_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_btc_init failed\n");
goto btc_fail;
}
phl_status = phl_scan_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_scan_init failed\n");
goto scan_fail;
}
phl_status = phl_sound_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_sound_init failed\n");
goto sound_fail;
}
return phl_status;
sound_fail:
phl_scan_deinit(phl_info);
scan_fail:
phl_btc_deinit(phl_info);
btc_fail:
phl_ser_deinit(phl_info);
ser_fail:
phl_cmd_deinit(phl_info);
cmd_fail:
return phl_status;
}
static void phl_fsm_module_deinit(struct phl_info_t *phl_info)
{
phl_sound_deinit(phl_info);
phl_scan_deinit(phl_info);
phl_btc_deinit(phl_info);
phl_ser_deinit(phl_info);
phl_cmd_deinit(phl_info);
}
static enum rtw_phl_status phl_fsm_start(struct phl_info_t *phl_info)
{
return phl_fsm_start_root(phl_info->fsm_root);
}
static enum rtw_phl_status phl_fsm_stop(struct phl_info_t *phl_info)
{
return phl_fsm_stop_root(phl_info->fsm_root);
}
static enum rtw_phl_status phl_fsm_module_start(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
phl_status = phl_fsm_start_fsm(phl_info->ser_fsm);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto ser_fail;
phl_status = phl_btc_start(phl_info->btc_obj);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto btc_fail;
phl_status = phl_fsm_start_fsm(phl_info->scan_fsm);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto scan_fail;
phl_status = phl_cmd_start(phl_info->cmd_obj);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto cmd_fail;
phl_status = phl_fsm_start_fsm(phl_info->snd_fsm);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto snd_fail;
return phl_status;
snd_fail:
phl_fsm_stop_fsm(phl_info->cmd_fsm);
phl_fsm_stop_fsm(phl_info->scan_fsm);
scan_fail:
phl_fsm_stop_fsm(phl_info->btc_fsm);
btc_fail:
phl_fsm_stop_fsm(phl_info->ser_fsm);
ser_fail:
phl_fsm_cmd_stop(phl_info);
cmd_fail:
return phl_status;
}
static enum rtw_phl_status phl_fsm_module_stop(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
phl_fsm_stop_fsm(phl_info->snd_fsm);
phl_fsm_stop_fsm(phl_info->scan_fsm);
phl_fsm_stop_fsm(phl_info->btc_fsm);
phl_fsm_stop_fsm(phl_info->ser_fsm);
phl_fsm_cmd_stop(phl_info);
return phl_status;
}
#endif /*CONFIG_FSM*/
static enum rtw_phl_status phl_module_init(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
phl_status = phl_msg_hub_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_msg_hub_init failed\n");
goto msg_hub_fail;
}
phl_status = phl_wow_mdl_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_wow_mdl_init failed\n");
goto wow_init_fail;
}
phl_status = phl_pkt_ofld_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_pkt_ofld_init failed\n");
goto pkt_ofld_init_fail;
}
if (!phl_test_module_init(phl_info)) {
PHL_ERR("phl_test_module_init failed\n");
phl_status = RTW_PHL_STATUS_FAILURE;
goto error_test_module_init;
}
phl_status = phl_p2pps_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_p2pps_init failed\n");
goto error_p2pps_init;
}
phl_status = phl_disp_eng_init(phl_info, HW_BAND_MAX);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_disp_eng_init failed\n");
goto error_disp_eng_init;
}
phl_status = phl_register_background_module_entry(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_register_disp_eng_module_entry failed\n");
goto error_disp_eng_reg_init;
}
phl_status = phl_ecsa_ctrl_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_ecsa_ctrl_init failed\n");
goto error_ecsa_ctrl_init;
}
return phl_status;
error_ecsa_ctrl_init:
error_disp_eng_reg_init:
phl_disp_eng_deinit(phl_info);
error_disp_eng_init:
phl_p2pps_deinit(phl_info);
error_p2pps_init:
phl_test_module_deinit(phl_info->phl_com);
error_test_module_init:
phl_pkt_ofld_deinit(phl_info);
pkt_ofld_init_fail:
phl_wow_mdl_deinit(phl_info);
wow_init_fail:
phl_msg_hub_deinit(phl_info);
msg_hub_fail:
return phl_status;
}
static void phl_module_deinit(struct phl_info_t *phl_info)
{
phl_ecsa_ctrl_deinit(phl_info);
phl_disp_eng_deinit(phl_info);
phl_test_module_deinit(phl_info->phl_com);
phl_pkt_ofld_deinit(phl_info);
phl_wow_mdl_deinit(phl_info);
phl_msg_hub_deinit(phl_info);
phl_p2pps_deinit(phl_info);
}
static enum rtw_phl_status phl_module_start(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
if (!phl_test_module_start(phl_info->phl_com)) {
PHL_ERR("phl_test_module_start failed\n");
phl_status = RTW_PHL_STATUS_FAILURE;
goto error_test_mdl_start;
}
phl_status = phl_disp_eng_start(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_disp_eng_start failed\n");
goto error_disp_eng_start;
}
if(phl_info->msg_hub) {
phl_msg_hub_start(phl_info);
phl_register_msg_entry(phl_info);
}
return phl_status;
error_disp_eng_start:
phl_test_module_stop(phl_info->phl_com);
error_test_mdl_start:
return phl_status;
}
static enum rtw_phl_status phl_module_stop(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
phl_status = phl_cmd_enqueue(phl_info, HW_BAND_0, MSG_EVT_MDL_CHECK_STOP,
NULL, 0, NULL, PHL_CMD_WAIT, 500);
phl_disp_eng_stop(phl_info);
phl_test_module_stop(phl_info->phl_com);
if(phl_info->msg_hub) {
phl_deregister_msg_entry(phl_info);
phl_msg_hub_stop(phl_info);
}
return phl_status;
}
static enum rtw_phl_status phl_var_init(struct phl_info_t *phl_info)
{
return RTW_PHL_STATUS_SUCCESS;
}
static void phl_var_deinit(struct phl_info_t *phl_info)
{
}
struct rtw_phl_com_t *rtw_phl_get_com(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return phl_info->phl_com;
}
static void phl_regulation_init(void *drv_priv, void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_regulation *rg = NULL;
if (!drv_priv || !phl)
return;
rg = &phl_info->regulation;
_os_spinlock_init(drv_priv, &rg->lock);
rg->init = 1;
rg->domain.code = INVALID_DOMAIN_CODE;
rg->domain_6g.code = INVALID_DOMAIN_CODE;
rg->tpo = TPO_NA;
}
static void phl_regulation_deinit(void *drv_priv, void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_regulation *rg = NULL;
if (!drv_priv || !phl)
return;
rg = &phl_info->regulation;
_os_spinlock_free(drv_priv, &rg->lock);
}
enum rtw_phl_status rtw_phl_init(void *drv_priv, void **phl,
struct rtw_ic_info *ic_info)
{
struct phl_info_t *phl_info = NULL;
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
FUNCIN();
phl_info = _os_mem_alloc(drv_priv, sizeof(struct phl_info_t));
if (phl_info == NULL) {
phl_status = RTW_PHL_STATUS_RESOURCE;
PHL_ERR("alloc phl_info failed\n");
goto error_phl_mem;
}
_os_mem_set(drv_priv, phl_info, 0, sizeof(struct phl_info_t));
*phl = phl_info;
phl_regulation_init(drv_priv, phl_info);
phl_status = phl_com_init(drv_priv, phl_info, ic_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
phl_status = RTW_PHL_STATUS_RESOURCE;
PHL_ERR("alloc phl_com failed\n");
goto error_phl_com_mem;
}
phl_status = phl_hci_init(phl_info, ic_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_hci_init failed\n");
goto error_hci_init;
}
phl_status = phl_set_hci_ops(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_set_hci_ops failed\n");
goto error_set_hci_ops;
}
#ifdef CONFIG_FSM
phl_status = phl_fsm_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_fsm_init failed\n");
goto error_fsm_init;
}
/* init FSM modules */
phl_status = phl_fsm_module_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_fsm_module_init failed\n");
goto error_fsm_module_init;
}
#endif
phl_status = phl_twt_init(*phl);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_twt_init failed\n");
goto error_phl_twt_init;
}
hal_status = rtw_hal_init(drv_priv, phl_info->phl_com,
&(phl_info->hal), ic_info->ic_id);
if ((hal_status != RTW_HAL_STATUS_SUCCESS) || (phl_info->hal == NULL)) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
PHL_ERR("rtw_hal_init failed status(%d),phl_info->hal(%p)\n",
hal_status, phl_info->hal);
goto error_hal_init;
}
/*send bus info to hal*/
rtw_hal_hci_cfg(phl_info->phl_com, phl_info->hal, ic_info);
/*get hw capability from mac/bb/rf/btc/efuse/fw-defeature-rpt*/
hal_status = rtw_hal_read_chip_info(phl_info->phl_com, phl_info->hal);
if (hal_status != RTW_HAL_STATUS_SUCCESS) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
PHL_ERR("rtw_hal_read_chip_info failed\n");
goto error_hal_read_chip_info;
}
hal_status = rtw_hal_var_init(phl_info->phl_com, phl_info->hal);
if (hal_status != RTW_HAL_STATUS_SUCCESS) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
PHL_ERR("rtw_hal_var_init failed\n");
goto error_hal_var_init;
}
phl_status = phl_var_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_var_init failed\n");
goto error_phl_var_init;
}
/* init mr_ctrl, wifi_role[] */
phl_status = phl_mr_ctrl_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_mr_ctrl_init failed\n");
goto error_wifi_role_ctrl_init;
}
/* init modules */
phl_status = phl_module_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_module_init failed\n");
goto error_module_init;
}
/* init macid_ctrl , stainfo_ctrl*/
/* init after get hw cap - macid number*/
phl_status = phl_macid_ctrl_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_macid_ctrl_init failed\n");
goto error_macid_ctrl_init;
}
/*init after hal_init - hal_sta_info*/
phl_status = phl_stainfo_ctrl_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_stainfo_ctrl_init failed\n");
goto error_stainfo_ctrl_init;
}
FUNCOUT();
return phl_status;
error_stainfo_ctrl_init:
phl_macid_ctrl_deinit(phl_info);
error_macid_ctrl_init:
phl_module_deinit(phl_info);
error_module_init:
phl_mr_ctrl_deinit(phl_info);
error_wifi_role_ctrl_init:
phl_var_deinit(phl_info);
error_phl_var_init:
error_hal_var_init:
error_hal_read_chip_info:
rtw_hal_deinit(phl_info->phl_com, phl_info->hal);
error_hal_init:
error_phl_twt_init:
phl_twt_deinit(phl);
#ifdef CONFIG_FSM
phl_fsm_module_deinit(phl_info);
error_fsm_module_init:
phl_fsm_deinit(phl_info);
error_fsm_init:
/* Do nothing */
#endif
error_set_hci_ops:
phl_hci_deinit(phl_info, phl_info->hci);
error_hci_init:
phl_com_deinit(phl_info, phl_info->phl_com);
error_phl_com_mem:
if (phl_info) {
phl_regulation_deinit(drv_priv, phl_info);
_os_mem_free(drv_priv, phl_info, sizeof(struct phl_info_t));
*phl = phl_info = NULL;
}
error_phl_mem:
return phl_status;
}
void rtw_phl_deinit(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
void *drv_priv = phl_to_drvpriv(phl_info);
if (phl_info) {
phl_twt_deinit(phl);
phl_stainfo_ctrl_deinie(phl_info);
phl_macid_ctrl_deinit(phl_info);
/*deinit mr_ctrl, wifi_role[]*/
phl_module_deinit(phl_info);
phl_mr_ctrl_deinit(phl_info);
rtw_hal_deinit(phl_info->phl_com, phl_info->hal);
phl_var_deinit(phl_info);
#ifdef CONFIG_FSM
phl_fsm_module_deinit(phl_info);
phl_fsm_deinit(phl_info);
#endif
phl_hci_deinit(phl_info, phl_info->hci);
phl_com_deinit(phl_info, phl_info->phl_com);
phl_regulation_deinit(drv_priv, phl_info);
_os_mem_free(drv_priv, phl_info,
sizeof(struct phl_info_t));
}
}
enum rtw_phl_status
rtw_phl_trx_alloc(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
phl_status = phl_datapath_init(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_datapath_init failed\n");
goto error_datapath;
}
phl_status = phl_trx_test_init(phl);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("phl_trx_test_init failed\n");
goto error_trx_test;
}
return phl_status;
error_trx_test:
phl_datapath_deinit(phl_info);
error_datapath:
return phl_status;
}
void
rtw_phl_trx_free_handler(void *phl)
{
phl_trx_free_handler(phl);
}
void
rtw_phl_trx_free_sw_rsc(void *phl)
{
phl_trx_free_sw_rsc(phl);
phl_trx_test_deinit(phl);
}
void
rtw_phl_trx_free(void *phl)
{
rtw_phl_trx_free_handler(phl);
rtw_phl_trx_free_sw_rsc(phl);
}
bool rtw_phl_is_init_completed(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return rtw_hal_is_inited(phl_info->phl_com, phl_info->hal);
}
#ifdef RTW_PHL_BCN
enum rtw_phl_status
phl_add_beacon(struct phl_info_t *phl_info, struct rtw_bcn_info_cmn *bcn_cmn)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
void *hal = phl_info->hal;
if(rtw_hal_add_beacon(phl_com, hal, bcn_cmn) == RTW_HAL_STATUS_SUCCESS)
return RTW_PHL_STATUS_SUCCESS;
else
return RTW_PHL_STATUS_FAILURE;
}
enum rtw_phl_status phl_update_beacon(struct phl_info_t *phl_info, u8 bcn_id)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
void *hal = phl_info->hal;
if(rtw_hal_update_beacon(phl_com, hal, bcn_id) == RTW_HAL_STATUS_SUCCESS)
return RTW_PHL_STATUS_SUCCESS;
else
return RTW_PHL_STATUS_FAILURE;
}
enum rtw_phl_status rtw_phl_free_bcn_entry(void *phl, struct rtw_wifi_role_t *wrole)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_bcn_info_cmn *bcn_cmn = &wrole->bcn_cmn;
void *hal = phl_info->hal;
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
if (bcn_cmn->bcn_added == 1) {
if (rtw_hal_free_beacon(phl_com, hal, bcn_cmn->bcn_id) == RTW_HAL_STATUS_SUCCESS) {
bcn_cmn->bcn_added = 0;
phl_status = RTW_PHL_STATUS_SUCCESS;
} else {
phl_status = RTW_PHL_STATUS_FAILURE;
}
}
return phl_status;
}
enum rtw_phl_status
phl_beacon_stop(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, u8 stop)
{
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
hstatus = rtw_hal_beacon_stop(phl_info->hal, wrole, stop);
if (hstatus != RTW_HAL_STATUS_SUCCESS)
pstatus = RTW_PHL_STATUS_FAILURE;
return pstatus;
}
enum rtw_phl_status
phl_issue_beacon(struct phl_info_t *phl_info, struct rtw_bcn_info_cmn *bcn_cmn)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_bcn_info_cmn *wrole_bcn_cmn;
struct rtw_wifi_role_t *wifi_role;
void *drv = phl_com->drv_priv;
u8 bcn_id, role_idx, bcn_added;
role_idx = bcn_cmn->role_idx;
if (role_idx > MAX_WIFI_ROLE_NUMBER) {
PHL_ERR("%s: role idx err(%d)\n", __func__, role_idx);
return RTW_PHL_STATUS_FAILURE;
}
wifi_role = &phl_com->wifi_roles[role_idx];
wrole_bcn_cmn = &wifi_role->bcn_cmn;
bcn_added = wrole_bcn_cmn->bcn_added;
_os_mem_cpy(drv, wrole_bcn_cmn, bcn_cmn, sizeof(struct rtw_bcn_info_cmn));
/* BCN add */
if (!bcn_added) {
if(phl_add_beacon(phl_info, wrole_bcn_cmn) == RTW_PHL_STATUS_SUCCESS) {
wrole_bcn_cmn->bcn_added = true;
return RTW_PHL_STATUS_SUCCESS;
} else {
return RTW_PHL_STATUS_FAILURE;
}
} else {
/* BCN update */
bcn_id = wrole_bcn_cmn->bcn_id;
if(phl_update_beacon(phl_info, bcn_id) == RTW_PHL_STATUS_SUCCESS)
return RTW_PHL_STATUS_SUCCESS;
else
return RTW_PHL_STATUS_FAILURE;
}
}
#ifdef CONFIG_CMD_DISP
enum rtw_phl_status
phl_cmd_issue_bcn_hdl(struct phl_info_t *phl_info, u8 *param)
{
struct rtw_bcn_info_cmn *bcn_cmn = (struct rtw_bcn_info_cmn *)param;
return phl_issue_beacon(phl_info, bcn_cmn);
}
static void _phl_issue_bcn_done(void *drv_priv, u8 *buf, u32 buf_len,
enum rtw_phl_status status)
{
if (buf) {
_os_kmem_free(drv_priv, buf, buf_len);
buf = NULL;
PHL_INFO("%s.....\n", __func__);
}
}
enum rtw_phl_status
rtw_phl_cmd_issue_beacon(void *phl,
struct rtw_wifi_role_t *wifi_role,
struct rtw_bcn_info_cmn *bcn_cmn,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
void *drv = wifi_role->phl_com->drv_priv;
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct rtw_bcn_info_cmn *param = NULL;
u32 param_len;
if (cmd_type == PHL_CMD_DIRECTLY) {
psts = phl_issue_beacon(phl_info, bcn_cmn);
goto _exit;
}
param_len = sizeof(struct rtw_bcn_info_cmn);
param = _os_kmem_alloc(drv, param_len);
if (param == NULL) {
PHL_ERR("%s: alloc param failed!\n", __func__);
goto _exit;
}
_os_mem_cpy(drv, param, bcn_cmn, param_len);
psts = phl_cmd_enqueue(phl_info,
wifi_role->hw_band,
MSG_EVT_ISSUE_BCN,
(u8 *)param, param_len,
_phl_issue_bcn_done,
cmd_type, cmd_timeout);
if (is_cmd_failure(psts)) {
/* Send cmd success, but wait cmd fail*/
psts = RTW_PHL_STATUS_FAILURE;
} else if (psts != RTW_PHL_STATUS_SUCCESS) {
/* Send cmd fail */
_os_kmem_free(phl_to_drvpriv(phl_info), param, param_len);
psts = RTW_PHL_STATUS_FAILURE;
}
_exit:
return psts;
}
struct stop_bcn_param {
struct rtw_wifi_role_t *wrole;
u8 stop;
};
enum rtw_phl_status
phl_cmd_stop_bcn_hdl(struct phl_info_t *phl_info, u8 *param)
{
struct stop_bcn_param *bcn_param = (struct stop_bcn_param *)param;
return phl_beacon_stop(phl_info, bcn_param->wrole, bcn_param->stop);
}
static void _phl_stop_bcn_done(void *drv_priv, u8 *buf, u32 buf_len,
enum rtw_phl_status status)
{
if (buf) {
_os_kmem_free(drv_priv, buf, buf_len);
buf = NULL;
PHL_INFO("%s.....\n", __func__);
}
}
enum rtw_phl_status
rtw_phl_cmd_stop_beacon(void *phl,
struct rtw_wifi_role_t *wifi_role,
u8 stop,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
void *drv = wifi_role->phl_com->drv_priv;
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct stop_bcn_param *param = NULL;
u32 param_len;
if (cmd_type == PHL_CMD_DIRECTLY) {
psts = phl_beacon_stop(phl_info, wifi_role, stop);
goto _exit;
}
param_len = sizeof(struct stop_bcn_param);
param = _os_kmem_alloc(drv, param_len);
if (param == NULL) {
PHL_ERR("%s: alloc param failed!\n", __func__);
goto _exit;
}
param->wrole = wifi_role;
param->stop = stop;
psts = phl_cmd_enqueue(phl_info,
wifi_role->hw_band,
MSG_EVT_STOP_BCN,
(u8 *)param, param_len,
_phl_stop_bcn_done,
cmd_type, cmd_timeout);
if (is_cmd_failure(psts)) {
/* Send cmd success, but wait cmd fail*/
psts = RTW_PHL_STATUS_FAILURE;
} else if (psts != RTW_PHL_STATUS_SUCCESS) {
/* Send cmd fail */
_os_kmem_free(phl_to_drvpriv(phl_info), param, param_len);
psts = RTW_PHL_STATUS_FAILURE;
}
_exit:
return psts;
}
#else /*for FSM*/
enum rtw_phl_status
rtw_phl_cmd_stop_beacon(void *phl,
struct rtw_wifi_role_t *wifi_role,
u8 stop,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return phl_beacon_stop(phl_info, wifi_role, stop);
}
enum rtw_phl_status
rtw_phl_cmd_issue_beacon(void *phl,
struct rtw_wifi_role_t *wifi_role,
struct rtw_bcn_info_cmn *bcn_cmn,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return phl_issue_beacon(phl_info, bcn_cmn);
}
#endif /*CONFIG_CMD_DISP*/
#endif /*RTW_PHL_BCN*/
void rtw_phl_cap_pre_config(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
/* FW Pre-config */
rtw_hal_fw_cap_pre_config(phl_info->phl_com,phl_info->hal);
/* Bus Pre-config */
rtw_hal_bus_cap_pre_config(phl_info->phl_com,phl_info->hal);
}
enum rtw_phl_status rtw_phl_preload(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
#ifdef RTW_WKARD_PRELOAD_TRX_RESET
struct phl_hci_trx_ops *ops = phl_info->hci_trx_ops;
#endif
FUNCIN();
hal_status = rtw_hal_preload(phl_info->phl_com, phl_info->hal);
#ifdef RTW_WKARD_PRELOAD_TRX_RESET
ops->trx_reset(phl_info, PHL_CTRL_TX|PHL_CTRL_RX);
#endif
if (hal_status != RTW_HAL_STATUS_SUCCESS)
return RTW_PHL_STATUS_FAILURE;
return RTW_PHL_STATUS_SUCCESS;
}
enum rtw_phl_status rtw_phl_start(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
#ifdef CONFIG_SYNC_INTERRUPT
struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */
hal_status = rtw_hal_start(phl_info->phl_com, phl_info->hal);
if (hal_status == RTW_HAL_STATUS_MAC_INIT_FAILURE) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
} else if (hal_status == RTW_HAL_STATUS_BB_INIT_FAILURE) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
} else if (hal_status == RTW_HAL_STATUS_RF_INIT_FAILURE) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
} else if (hal_status == RTW_HAL_STATUS_BTC_INIT_FAILURE) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
} else if (hal_status != RTW_HAL_STATUS_SUCCESS) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
}
#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
/* if no need keep para buf, phl_com->dev_sw_cap->keep_para_info = false*/
rtw_phl_init_free_para_buf(phl_info->phl_com);
#endif
#ifdef CONFIG_FSM
/* start FSM framework */
phl_status = phl_fsm_start(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto error_phl_fsm_start;
/* start FSM modules */
phl_status = phl_fsm_module_start(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto error_phl_fsm_module_start;
#endif
/* start modules */
phl_status = phl_module_start(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto error_phl_module_start;
phl_status = phl_datapath_start(phl_info);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
goto error_phl_datapath_start;
#ifdef CONFIG_SYNC_INTERRUPT
evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), true);
#else
rtw_hal_enable_interrupt(phl_info->phl_com, phl_info->hal);
#endif /* CONFIG_SYNC_INTERRUPT */
phl_info->phl_com->dev_state = RTW_DEV_WORKING;
phl_status = RTW_PHL_STATUS_SUCCESS;
return phl_status;
error_phl_datapath_start:
phl_module_stop(phl_info);
error_phl_module_start:
#ifdef CONFIG_FSM
phl_fsm_module_stop(phl_info);
error_phl_fsm_module_start:
phl_fsm_stop(phl_info);
error_phl_fsm_start:
#endif
rtw_hal_stop(phl_info->phl_com, phl_info->hal);
error_hal_start:
return phl_status;
}
static void _phl_interrupt_stop(struct phl_info_t *phl_info)
{
#ifdef CONFIG_SYNC_INTERRUPT
struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
do {
if (false == TEST_STATUS_FLAG(phl_info->phl_com->dev_state,
RTW_DEV_SURPRISE_REMOVAL))
evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), false);
} while (false);
#else
do {
if (false == TEST_STATUS_FLAG(phl_info->phl_com->dev_state,
RTW_DEV_SURPRISE_REMOVAL))
rtw_hal_disable_interrupt(phl_info->phl_com, phl_info->hal);
} while (false);
#endif /* CONFIG_SYNC_INTERRUPT */
}
static enum rtw_phl_status _phl_cmd_send_msg_phy_on(struct phl_info_t *phl_info)
{
enum rtw_phl_status sts = RTW_PHL_STATUS_FAILURE;
#ifdef DBG_PHY_ON_TIME
u32 phyon_start = 0, phyon_t = 0;
#endif /* DBG_PHY_ON_TIME */
#ifdef DBG_PHY_ON_TIME
phyon_start = _os_get_cur_time_ms();
#endif /* DBG_PHY_ON_TIME */
sts = phl_cmd_enqueue(phl_info, HW_BAND_0, MSG_EVT_PHY_ON, NULL, 0, NULL,
PHL_CMD_WAIT, 3000);
#ifdef DBG_PHY_ON_TIME
phyon_t = phl_get_passing_time_ms(phyon_start);
if (phyon_t > 1000) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "%s : phy on takes %u (ms).\n"
, __func__, phyon_t);
}
#endif /* DBG_PHY_ON_TIME */
if (is_cmd_failure(sts)) {
/* send cmd success, but wait cmd fail */
sts = RTW_PHL_STATUS_FAILURE;
} else if (sts != RTW_PHL_STATUS_SUCCESS) {
/* send cmd fail */
sts = RTW_PHL_STATUS_FAILURE;
}
return sts;
}
void rtw_phl_stop(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
_phl_cmd_send_msg_phy_on(phl_info);
_phl_interrupt_stop(phl_info);
phl_module_stop(phl_info);
#ifdef DBG_PHL_MR
phl_mr_info_dbg(phl_info);
#endif
#ifdef CONFIG_FSM
phl_fsm_module_stop(phl_info);
phl_fsm_stop(phl_info);
#endif
rtw_hal_stop(phl_info->phl_com, phl_info->hal);
phl_datapath_stop(phl_info);
phl_info->phl_com->dev_state = 0;
}
enum rtw_phl_status phl_wow_start(struct phl_info_t *phl_info, struct rtw_phl_stainfo_t *sta)
{
#ifdef CONFIG_WOWLAN
enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
struct phl_wow_info *wow_info = phl_to_wow_info(phl_info);
#ifdef CONFIG_SYNC_INTERRUPT
struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */
PHL_TRACE(COMP_PHL_WOW, _PHL_INFO_, "[wow] %s enter with sta state(%d)\n.", __func__, sta->wrole->mstate);
phl_wow_decide_op_mode(wow_info, sta);
if (wow_info->op_mode == RTW_WOW_OP_PWR_DOWN) {
phl_cmd_role_suspend(phl_info);
rtw_phl_stop(phl_info);
/* since control path stopped after rtw_phl_stop,
below action don't have to migrate to general module */
hstatus = rtw_hal_set_wowlan(phl_info->phl_com, phl_info->hal, true);
if (RTW_HAL_STATUS_SUCCESS != hstatus)
PHL_WARN("[wow] rtw_hal_set_wowlan failed, status(%u)\n", hstatus);
pstatus = RTW_PHL_STATUS_SUCCESS;
} else {
/* stop all active features */
#ifdef CONFIG_WOW_WITH_SER
rtw_hal_ser_ctrl(phl_info->hal, false);
#endif
pstatus = phl_module_stop(phl_info);
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
PHL_ERR("[wow] phl_module_stop failed.\n");
goto end;
}
/* since control path stopped after phl_module_stop,
below action don't have to migrate to general module */
#ifdef CONFIG_FSM
pstatus = phl_fsm_module_stop(phl_info);
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
PHL_ERR("[wow] phl_fsm_module_stop failed.\n");
goto end;
}
pstatus = phl_fsm_stop(phl_info);
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
PHL_ERR("[wow] phl_fsm_stop failed.\n");
goto end;
}
#endif
hstatus = rtw_hal_set_wowlan(phl_info->phl_com, phl_info->hal, true);
if (RTW_HAL_STATUS_SUCCESS != hstatus)
PHL_WARN("[wow] rtw_hal_set_wowlan failed, status(%u)\n", hstatus);
pstatus = phl_wow_init_precfg(wow_info);
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
PHL_ERR("[wow] phl_wow_init_precfg failed.\n");
goto end;
}
hstatus = rtw_hal_wow_init(phl_info->phl_com, phl_info->hal, sta);
if (RTW_HAL_STATUS_SUCCESS != hstatus) {
pstatus = RTW_PHL_STATUS_FAILURE;
goto end;
}
pstatus = phl_wow_func_en(wow_info);
if (RTW_PHL_STATUS_SUCCESS != pstatus)
goto end;
#ifdef CONFIG_POWER_SAVE
/* power saving */
phl_wow_ps_proto_cfg(wow_info, true);
phl_wow_ps_pwr_ntfy(wow_info, true);
#endif
pstatus = phl_wow_init_postcfg(wow_info);
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
PHL_ERR("[wow] phl_wow_init_postcfg failed.\n");
goto end;
}
#ifdef CONFIG_WOW_WITH_SER
rtw_hal_ser_ctrl(phl_info->hal, true);
#endif
#ifdef CONFIG_POWER_SAVE
/* power saving */
phl_wow_ps_pwr_cfg(wow_info, true);
#endif
pstatus = RTW_PHL_STATUS_SUCCESS;
}
end:
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
#ifdef CONFIG_SYNC_INTERRUPT
evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), false);
#else
rtw_hal_disable_interrupt(phl_info->phl_com, phl_info->hal);
#endif /* CONFIG_SYNC_INTERRUPT */
rtw_hal_stop(phl_info->phl_com, phl_info->hal);
phl_datapath_stop(phl_info);
wow_info->op_mode = RTW_WOW_OP_PWR_DOWN;
PHL_ERR("[wow] %s fail, set op_mode %d!\n", __func__, wow_info->op_mode);
} else {
PHL_TRACE(COMP_PHL_WOW, _PHL_INFO_,
"[wow] %s success, with func_en %d, op_mode %d.\n",
__func__, wow_info->func_en, wow_info->op_mode);
}
return pstatus;
#else
return RTW_PHL_STATUS_SUCCESS;
#endif /* CONFIG_WOWLAN */
}
static void _wow_stop_reinit(struct phl_info_t *phl_info)
{
enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
PHL_WARN("%s : reset hw!\n", __func__);
rtw_hal_hal_deinit(phl_info->phl_com, phl_info->hal);
phl_datapath_stop(phl_info);
pstatus = rtw_phl_start(phl_info);
if (pstatus)
PHL_ERR("%s : rtw_phl_start fail!\n", __func__);
phl_cmd_role_recover(phl_info);
}
void phl_wow_stop(struct phl_info_t *phl_info, struct rtw_phl_stainfo_t *sta, u8 *hw_reinit)
{
#ifdef CONFIG_WOWLAN
enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
struct phl_wow_info *wow_info = phl_to_wow_info(phl_info);
u8 reset = 0;
if (rtw_hal_get_pwr_state(phl_info->hal, &wow_info->mac_pwr)
!= RTW_HAL_STATUS_SUCCESS)
return;
PHL_TRACE(COMP_PHL_WOW, _PHL_INFO_, "%s enter with mac power %d\n.",
__func__, wow_info->mac_pwr);
if (wow_info->mac_pwr != RTW_MAC_PWR_OFF) {
#ifdef CONFIG_WOW_WITH_SER
rtw_hal_ser_ctrl(phl_info->hal, false);
#endif
#ifdef CONFIG_POWER_SAVE
/* leave clock/power gating */
pstatus = phl_wow_ps_pwr_cfg(wow_info, false);
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
PHL_ERR("[wow] HW leave power saving failed.\n");
_wow_stop_reinit(phl_info);
*hw_reinit = true;
return;
}
#endif
}
hstatus = rtw_hal_set_wowlan(phl_info->phl_com, phl_info->hal, false);
if (RTW_HAL_STATUS_SUCCESS != hstatus) {
PHL_WARN("[wow] rtw_hal_set_wowlan failed, status(%u)\n", hstatus);
}
if (wow_info->mac_pwr == RTW_MAC_PWR_OFF) {
if (wow_info->op_mode == RTW_WOW_OP_PWR_DOWN) {
pstatus = rtw_phl_start(phl_info);
phl_role_recover(phl_info);
*hw_reinit = true;
} else {
PHL_WARN("[wow] enter suspend with wow enabled but mac is power down\n");
_wow_stop_reinit(phl_info);
*hw_reinit = true;
}
} else if (wow_info->mac_pwr == RTW_MAC_PWR_ON ||
wow_info->mac_pwr == RTW_MAC_PWR_LPS) {
phl_wow_handle_wake_rsn(wow_info, &reset);
if (reset) {
_wow_stop_reinit(phl_info);
*hw_reinit = true;
return;
}
phl_wow_deinit_precfg(wow_info);
rtw_hal_fw_dbg_dump(phl_info->hal, false);
#ifdef CONFIG_POWER_SAVE
phl_wow_ps_pwr_ntfy(wow_info, false);
/* leave power saving */
phl_wow_ps_proto_cfg(wow_info, false);
#endif
phl_wow_func_dis(wow_info);
hstatus = rtw_hal_wow_deinit(phl_info->phl_com, phl_info->hal, sta);
if (hstatus)
PHL_ERR("%s : rtw_hal_wow_deinit failed.\n", __func__);
phl_module_start(phl_info);
#ifdef CONFIG_FSM
phl_fsm_start(phl_info);
phl_fsm_module_start(phl_info);
#endif
phl_wow_deinit_postcfg(wow_info);
#ifdef CONFIG_WOW_WITH_SER
rtw_hal_ser_ctrl(phl_info->hal, true);
#endif
*hw_reinit = false;
} else {
PHL_ERR("%s : unexpected mac pwr state %d.\n", __func__, wow_info->mac_pwr);
}
#endif /* CONFIG_WOWLAN */
}
enum rtw_phl_status rtw_phl_rf_on(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
#ifdef CONFIG_SYNC_INTERRUPT
struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */
struct phl_data_ctl_t ctl = {0};
hal_status = rtw_hal_start(phl_info->phl_com, phl_info->hal);
if (hal_status == RTW_HAL_STATUS_MAC_INIT_FAILURE) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
} else if (hal_status == RTW_HAL_STATUS_BB_INIT_FAILURE) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
} else if (hal_status == RTW_HAL_STATUS_RF_INIT_FAILURE) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
} else if (hal_status == RTW_HAL_STATUS_BTC_INIT_FAILURE) {
phl_status = RTW_PHL_STATUS_HAL_INIT_FAILURE;
goto error_hal_start;
}
phl_role_recover(phl_info);
#ifdef CONFIG_SYNC_INTERRUPT
evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), true);
#else
rtw_hal_enable_interrupt(phl_info->phl_com, phl_info->hal);
#endif /* CONFIG_SYNC_INTERRUPT */
ctl.id = PHL_MDL_POWER_MGNT;
ctl.cmd = PHL_DATA_CTL_SW_TX_RESUME;
if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
PHL_WARN("%s: tx resume fail!\n", __func__);
ctl.cmd = PHL_DATA_CTL_SW_RX_RESUME;
if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
PHL_WARN("%s: rx resume fail!\n", __func__);
return RTW_PHL_STATUS_SUCCESS;
error_hal_start:
PHL_ERR("error_hal_start\n");
return phl_status;
}
#define MAX_RF_OFF_STOP_TRX_TIME 100 /* ms */
enum rtw_phl_status rtw_phl_rf_off(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
#ifdef CONFIG_SYNC_INTERRUPT
struct rtw_phl_evt_ops *evt_ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */
struct phl_data_ctl_t ctl = {0};
#ifdef CONFIG_SYNC_INTERRUPT
evt_ops->set_interrupt_caps(phl_to_drvpriv(phl_info), false);
#else
rtw_hal_disable_interrupt(phl_info->phl_com, phl_info->hal);
#endif /* CONFIG_SYNC_INTERRUPT */
ctl.id = PHL_MDL_POWER_MGNT;
ctl.cmd = PHL_DATA_CTL_SW_TX_PAUSE;
if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
PHL_WARN("%s: tx pause fail!\n", __func__);
ctl.cmd = PHL_DATA_CTL_SW_RX_PAUSE;
if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
PHL_WARN("%s: rx pause fail!\n", __func__);
phl_role_suspend(phl_info);
rtw_hal_stop(phl_info->phl_com, phl_info->hal);
ctl.cmd = PHL_DATA_CTL_SW_TX_RESET;
if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
PHL_WARN("%s: tx reset fail!\n", __func__);
ctl.cmd = PHL_DATA_CTL_SW_RX_RESET;
if (phl_data_ctrler(phl_info, &ctl, NULL) != RTW_PHL_STATUS_SUCCESS)
PHL_WARN("%s: rx reset fail!\n", __func__);
return RTW_PHL_STATUS_SUCCESS;
}
enum rtw_phl_status rtw_phl_suspend(void *phl, struct rtw_phl_stainfo_t *sta, u8 wow_en)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
PHL_INFO("%s enter with wow_en(%d)\n.", __func__, wow_en);
#ifdef CONFIG_WOWLAN
pstatus = _phl_cmd_send_msg_phy_on(phl_info);
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
PHL_ERR("[wow] _phl_cmd_send_msg_phy_on fail!\n");
wow_en = false;
}
if (wow_en) {
pstatus = phl_wow_start(phl_info, sta);
} else {
phl_cmd_role_suspend(phl_info);
rtw_phl_stop(phl);
}
#else
PHL_INFO("%s enter with wow_en(%d)\n.", __func__, wow_en);
phl_cmd_role_suspend(phl_info);
rtw_phl_stop(phl);
#endif
FUNCOUT_WSTS(pstatus);
return pstatus;
}
enum rtw_phl_status rtw_phl_resume(void *phl, struct rtw_phl_stainfo_t *sta, u8 *hw_reinit)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
#ifdef CONFIG_WOWLAN
struct phl_wow_info *wow_info = phl_to_wow_info(phl_info);
#endif
/**
* Since some platforms require performance when device resuming, we need
* to finish "rtw_phl_resume" as fast as possible. In this situation, we
* prevent ps module entering any power saving mechanisms and try to do I/O
* operations directly without issue commands to cmd dispatcher. Therefore,
* ps module will not enter power saving if device state "RTW_DEV_RESUMING"
* is set. If device state "RTW_DEV_RESUMING" is set, operations of I/O
* should check whether the current power state can perform I/O or not and
* perform I/O directly without issuing commands to cmd dispatcher if device
* power state is I/O allowable. This kind of flow is only suitable for
* "rtw_phl_resume" because core layer will not perform any other tasks when
* calling rtw_phl_resume which is relatively simple enough.
*/
PHL_INFO("%s enter...\n.", __func__);
SET_STATUS_FLAG(phl_info->phl_com->dev_state, RTW_DEV_RESUMING);
#ifdef CONFIG_WOWLAN
if (wow_info->op_mode != RTW_WOW_OP_NONE) {
phl_wow_stop(phl_info, sta, hw_reinit);
} else {
pstatus = rtw_phl_start(phl);
#ifdef CONFIG_POWER_SAVE
if (phl_ps_get_cur_pwr_lvl(phl_info) == PS_PWR_LVL_PWRON)
#endif
phl_role_recover(phl_info);
*hw_reinit = true;
}
#if defined(RTW_WKARD_WOW_L2_PWR) && defined(CONFIG_PCI_HCI)
rtw_hal_set_l2_leave(phl_info->hal);
#endif
phl_record_wow_stat(wow_info);
phl_reset_wow_info(wow_info);
#else
pstatus = rtw_phl_start(phl);
#ifdef CONFIG_POWER_SAVE
if (phl_ps_get_cur_pwr_lvl(phl_info) == PS_PWR_LVL_PWRON)
#endif
phl_role_recover(phl_info);
*hw_reinit = true;
#endif
CLEAR_STATUS_FLAG(phl_info->phl_com->dev_state, RTW_DEV_RESUMING);
PHL_INFO("%s exit with hw_reinit %d.\n.", __func__, *hw_reinit);
return pstatus;
}
enum rtw_phl_status rtw_phl_reset(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct phl_hci_trx_ops *ops = phl_info->hci_trx_ops;
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
if(rtw_phl_is_init_completed(phl_info))
phl_status = RTW_PHL_STATUS_SUCCESS;
rtw_hal_stop(phl_info->phl_com, phl_info->hal);
ops->trx_reset(phl_info, PHL_CTRL_TX|PHL_CTRL_RX);
ops->trx_resume(phl_info, PHL_CTRL_TX|PHL_CTRL_RX);
rtw_hal_start(phl_info->phl_com, phl_info->hal);
/* Leave power save */
/* scan abort */
/* STA disconnect/stop AP/Stop p2p function */
return phl_status;
}
enum rtw_phl_status rtw_phl_restart(void *phl)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
phl_status = RTW_PHL_STATUS_SUCCESS;
return phl_status;
}
/******************* IO APIs *******************/
u8 rtw_phl_read8(void *phl, u32 addr)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return rtw_hal_read8(phl_info->hal, addr);
}
u16 rtw_phl_read16(void *phl, u32 addr)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return rtw_hal_read16(phl_info->hal, addr);
}
u32 rtw_phl_read32(void *phl, u32 addr)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return rtw_hal_read32(phl_info->hal, addr);
}
void rtw_phl_write8(void *phl, u32 addr, u8 val)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_write8(phl_info->hal, addr, val);
}
void rtw_phl_write16(void *phl, u32 addr, u16 val)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_write16(phl_info->hal, addr, val);
}
void rtw_phl_write32(void *phl, u32 addr, u32 val)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_write32(phl_info->hal, addr, val);
}
u32 rtw_phl_read_macreg(void *phl, u32 offset, u32 bit_mask)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return rtw_hal_read_macreg(phl_info->hal, offset, bit_mask);
}
void rtw_phl_write_macreg(void *phl,
u32 offset, u32 bit_mask, u32 data)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_write_macreg(phl_info->hal, offset, bit_mask, data);
}
u32 rtw_phl_read_bbreg(void *phl, u32 offset, u32 bit_mask)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return rtw_hal_read_bbreg(phl_info->hal, offset, bit_mask);
}
void rtw_phl_write_bbreg(void *phl,
u32 offset, u32 bit_mask, u32 data)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_write_bbreg(phl_info->hal, offset, bit_mask, data);
}
u32 rtw_phl_read_rfreg(void *phl,
enum rf_path path, u32 offset, u32 bit_mask)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return rtw_hal_read_rfreg(phl_info->hal, path, offset, bit_mask);
}
void rtw_phl_write_rfreg(void *phl,
enum rf_path path, u32 offset, u32 bit_mask, u32 data)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_write_rfreg(phl_info->hal, path, offset, bit_mask, data);
}
void rtw_phl_restore_interrupt(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_restore_interrupt(phl_info->phl_com, phl_info->hal);
}
enum rtw_phl_status rtw_phl_interrupt_handler(void *phl)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
u32 int_hdler_msk = 0x0;
#ifdef CONFIG_SYNC_INTERRUPT
struct rtw_phl_evt_ops *ops = &phl_info->phl_com->evt_ops;
#endif /* CONFIG_SYNC_INTERRUPT */
int_hdler_msk = rtw_hal_interrupt_handler(phl_info->hal);
if (!int_hdler_msk) {
PHL_WARN("%s : 0x%x\n", __func__, int_hdler_msk);
phl_status = RTW_PHL_STATUS_FAILURE;
goto end;
}
PHL_DBG("%s : 0x%x\n", __func__, int_hdler_msk);
/* beacon interrupt */
if (int_hdler_msk & BIT0)
;/* todo */
/* rx interrupt */
if (int_hdler_msk & BIT1) {
#if defined(CONFIG_SDIO_HCI) && defined(CONFIG_PHL_SDIO_READ_RXFF_IN_INT)
phl_info->hci_trx_ops->recv_rxfifo(phl);
#else
phl_status = rtw_phl_start_rx_process(phl);
#endif
#if defined(CONFIG_PCI_HCI) && !defined(CONFIG_DYNAMIC_RX_BUF)
/* phl_status = hci_trx_ops->recycle_busy_wd(phl); */
#endif
}
/* tx interrupt */
if (int_hdler_msk & BIT2)
;
/* cmd interrupt */
if (int_hdler_msk & BIT3)
;/* todo */
/* halt c2h interrupt */
if (int_hdler_msk & BIT4)
phl_status = phl_ser_send_msg(phl, RTW_PHL_SER_EVENT_CHK);
/* halt c2h interrupt */
if (int_hdler_msk & BIT5)
phl_status = phl_fw_watchdog_timeout_notify(phl);
/* halt c2h interrupt - send msg to SER FSM to check ser event */
if (int_hdler_msk & BIT6)
phl_status = phl_ser_send_msg(phl, RTW_PHL_SER_EVENT_CHK);
if (phl_status != RTW_PHL_STATUS_SUCCESS)
PHL_INFO("rtw_phl_interrupt_handler fail !!\n");
/* schedule tx process */
phl_status = phl_schedule_handler(phl_info->phl_com, &phl_info->phl_tx_handler);
end:
#ifdef CONFIG_SYNC_INTERRUPT
ops->interrupt_restore(phl_to_drvpriv(phl_info), false);
#endif
return phl_status;
}
void rtw_phl_enable_interrupt(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_enable_interrupt(phl_info->phl_com, phl_info->hal);
}
void rtw_phl_disable_interrupt(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_disable_interrupt(phl_info->phl_com, phl_info->hal);
}
bool rtw_phl_recognize_interrupt(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return rtw_hal_recognize_interrupt(phl_info->hal);
}
void rtw_phl_clear_interrupt(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_clear_interrupt(phl_info->hal);
}
enum rtw_phl_status rtw_phl_msg_hub_register_recver(void* phl,
struct phl_msg_receiver* ctx, enum phl_msg_recver_layer layer)
{
return phl_msg_hub_register_recver(phl, ctx, layer);
}
enum rtw_phl_status rtw_phl_msg_hub_update_recver_mask(void* phl,
enum phl_msg_recver_layer layer, u8* mdl_id, u32 len, u8 clr)
{
return phl_msg_hub_update_recver_mask(phl, layer, mdl_id, len, clr);
}
enum rtw_phl_status rtw_phl_msg_hub_deregister_recver(void* phl,
enum phl_msg_recver_layer layer)
{
return phl_msg_hub_deregister_recver(phl, layer);
}
enum rtw_phl_status rtw_phl_msg_hub_send(void* phl,
struct phl_msg_attribute* attr, struct phl_msg* msg)
{
return phl_msg_hub_send((struct phl_info_t*)phl, attr, msg);
}
#ifdef PHL_PLATFORM_LINUX
void rtw_phl_mac_reg_dump(void *sel, void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_mac_reg_dump(sel, phl_info->hal);
}
void rtw_phl_bb_reg_dump(void *sel, void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_bb_reg_dump(sel, phl_info->hal);
}
void rtw_phl_bb_reg_dump_ex(void *sel, void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_bb_reg_dump_ex(sel, phl_info->hal);
}
void rtw_phl_rf_reg_dump(void *sel, void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
rtw_hal_rf_reg_dump(sel, phl_info->hal);
}
#endif
/**
* rtw_phl_get_sec_cam() - get the security cam raw data from HW
* @phl: struct phl_info_t *
* @num: How many cam you wnat to dump from the first one.
* @buf: ptr to buffer which store the content from HW.
* If buf is NULL, use console as debug path.
* @size Size of allocated memroy for @buf.
* The size should be @num * size of security cam offset(0x20).
*
* Return true when function successfully works, otherwise, return fail.
*/
bool rtw_phl_get_sec_cam(void *phl, u16 num, u8 *buf, u16 size)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_hal_status ret = RTW_HAL_STATUS_SUCCESS;
ret = rtw_hal_get_sec_cam(phl_info->hal, num, buf, size);
if (ret != RTW_HAL_STATUS_SUCCESS)
return false;
return true;
}
/**
* rtw_phl_get_addr_cam() - get the address cam raw data from HW
* @phl: struct phl_info_t *
* @num: How many cam you wnat to dump from the first one.
* @buf: ptr to buffer which store the content from HW.
* If buf is NULL, use console as debug path.
* @size Size of allocated memroy for @buf.
* The size should be @num * size of Addr cam offset(0x40).
*
* Return true when function successfully works, otherwise, return fail.
*/
bool rtw_phl_get_addr_cam(void *phl, u16 num, u8 *buf, u16 size)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_hal_status ret = RTW_HAL_STATUS_SUCCESS;
ret = rtw_hal_get_addr_cam(phl_info->hal, num, buf, size);
if (ret != RTW_HAL_STATUS_SUCCESS)
return false;
return true;
}
void rtw_phl_mac_dbg_status_dump(void *phl, u32 *val, u8 *en)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct hal_mac_dbg_dump_cfg cfg = {0};
cfg.ss_dbg_0 = val[0];
cfg.ss_dbg_1 = val[1];
cfg.ss_dbg = (*en & BIT0);
cfg.dle_dbg = (*en & BIT1) >> 1;
cfg.dmac_dbg = (*en & BIT2) >> 2;
cfg.cmac_dbg = (*en & BIT3) >> 3;
cfg.mac_dbg_port = (*en & BIT4) >> 4;
cfg.plersvd_dbg = (*en & BIT5) >> 5;
cfg.tx_flow_dbg = (*en & BIT6) >> 6;
rtw_hal_dbg_status_dump(phl_info->hal, &cfg);
}
enum rtw_phl_status rtw_phl_get_mac_addr_efuse(void* phl, u8 *addr)
{
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
void *d = phl_to_drvpriv(phl_info);
u8 addr_efuse[MAC_ADDRESS_LENGTH] = {0};
hstatus = rtw_hal_get_efuse_info(phl_info->hal,
EFUSE_INFO_MAC_ADDR,
(void *)addr_efuse,
MAC_ADDRESS_LENGTH);
if (is_broadcast_mac_addr(addr_efuse)) {
PHL_INFO("[WARNING] MAC Address from EFUSE is FF:FF:FF:FF:FF:FF\n");
hstatus = RTW_HAL_STATUS_FAILURE;
}
if (RTW_HAL_STATUS_SUCCESS != hstatus) {
pstatus = RTW_PHL_STATUS_FAILURE;
} else {
_os_mem_cpy(d, addr, addr_efuse, MAC_ADDRESS_LENGTH);
PHL_INFO("%s : 0x%2x - 0x%2x - 0x%2x - 0x%2x - 0x%2x - 0x%2x\n",
__func__, addr[0], addr[1], addr[2],
addr[3], addr[4], addr[5]);
}
return pstatus;
}
enum rtw_phl_status
rtw_phl_cfg_trx_path(void* phl, enum rf_path tx, u8 tx_nss,
enum rf_path rx, u8 rx_nss)
{
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
hstatus = rtw_hal_cfg_trx_path(phl_info->hal, tx, tx_nss, rx, rx_nss);
if (RTW_HAL_STATUS_SUCCESS != hstatus)
pstatus = RTW_PHL_STATUS_FAILURE;
return pstatus;
}
void rtw_phl_reset_stat_ma_rssi(struct rtw_phl_com_t *phl_com)
{
u8 i = 0, j = 0;
PHL_INFO("--> %s\n", __func__);
do{
if (NULL == phl_com)
break;
_os_spinlock(phl_com->drv_priv,
&(phl_com->rssi_stat.lock), _bh, NULL);
for (i = 0; i < RTW_RSSI_TYPE_MAX; i++) {
phl_com->rssi_stat.ma_rssi_ele_idx[i] = 0;
phl_com->rssi_stat.ma_rssi_ele_cnt[i] = 0;
phl_com->rssi_stat.ma_rssi_ele_sum[i] = 0;
phl_com->rssi_stat.ma_rssi[i] = 0;
for (j = 0; j < PHL_RSSI_MAVG_NUM; j++)
phl_com->rssi_stat.ma_rssi_ele[i][j] = 0;
}
_os_spinunlock(phl_com->drv_priv,
&(phl_com->rssi_stat.lock), _bh, NULL);
} while (0);
PHL_INFO("<-- %s\n", __func__);
}
u8
rtw_phl_get_ma_rssi(struct rtw_phl_com_t *phl_com,
enum rtw_rssi_type rssi_type)
{
u8 ret = 0;
if (NULL == phl_com)
return ret;
_os_spinlock(phl_com->drv_priv,
&(phl_com->rssi_stat.lock), _bh, NULL);
ret = phl_com->rssi_stat.ma_rssi[rssi_type];
_os_spinunlock(phl_com->drv_priv,
&(phl_com->rssi_stat.lock), _bh, NULL);
return ret;
}
#ifdef RTW_WKARD_DYNAMIC_BFEE_CAP
enum rtw_phl_status
rtw_phl_bfee_ctrl(void *phl, struct rtw_wifi_role_t *wrole, bool ctrl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
if (RTW_HAL_STATUS_SUCCESS !=
rtw_hal_bf_bfee_ctrl(phl_info->hal, wrole->hw_band, ctrl)) {
pstatus = RTW_PHL_STATUS_FAILURE;
}
return pstatus;
}
#endif
u8
rtw_phl_get_sta_mgnt_rssi(struct rtw_phl_stainfo_t *psta)
{
u8 ret = PHL_MAX_RSSI;
if (psta != NULL) {
ret = psta->hal_sta->rssi_stat.ma_rssi_mgnt;
}
return ret;
}