2025-05-10 21:58:58 +08:00

552 lines
16 KiB
C
Executable File

/******************************************************************************
*
* 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_RX_C_
#include "hal_headers.h"
void rtw_hal_cfg_rxhci(void *hal, u8 en)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "%s : enable %d.\n", __func__, en);
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mac_cfg_rxhci(hal_info, en))
PHL_ERR("%s failure \n", __func__);
}
enum rtw_hal_status
rtw_hal_set_rxfltr_by_mode(void *hal, u8 band, enum rtw_rx_fltr_mode mode)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct rtw_hal_com_t *hal_com = hal_info->hal_com;
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
enum rtw_rx_fltr_mode set_mode = -1;
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s : band(%d), mode(%d)\n",
__func__, band, mode);
/* Note: @hal_info_t.rx_fltr_mode is used to recored any mode other than
* sniffer mode, it effectively records the mode before entering monitor
* mode and the subsequent modes set after entering monitor mode.
*/
if ((mode == RX_FLTR_MODE_SNIFFER && hal_info->monitor_mode) ||
(mode == RX_FLTR_MODE_RESTORE && !hal_info->monitor_mode))
return RTW_HAL_STATUS_FAILURE;
if (hal_info->monitor_mode && mode != RX_FLTR_MODE_RESTORE) {
hal_info->rx_fltr_mode = mode;
return RTW_HAL_STATUS_SUCCESS;
}
set_mode = (mode == RX_FLTR_MODE_RESTORE) ?
hal_info->rx_fltr_mode : mode;
hstatus = rtw_hal_mac_set_rxfltr_by_mode(hal_com, band, set_mode);
if (hstatus != RTW_HAL_STATUS_SUCCESS)
return hstatus;
hal_info->monitor_mode = (mode == RX_FLTR_MODE_SNIFFER);
/* Record @hal_info_t.rx_fltr_mode only when the mode is not monitor and
* restore, otherwise, it is kept intact.
* TODO: The rx fltr mode should be recorded separately for each band.
*/
if (mode != RX_FLTR_MODE_SNIFFER &&
mode != RX_FLTR_MODE_RESTORE)
hal_info->rx_fltr_mode = mode;
return RTW_HAL_STATUS_SUCCESS;
}
enum rtw_rx_fltr_mode rtw_hal_get_rxfltr_mode(void *hal, u8 band)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
return (hal_info->monitor_mode) ? RX_FLTR_MODE_SNIFFER :
hal_info->rx_fltr_mode;
}
enum rtw_hal_status rtw_hal_scan_set_rxfltr_by_mode(void *hinfo,
enum phl_phy_idx phy_idx, bool off_channel, u8 *mode)
{
enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
if (off_channel) {
/* backup rx filter mode */
*mode = rtw_hal_get_rxfltr_mode(hinfo, phy_idx);
hal_status = rtw_hal_set_rxfltr_by_mode(hinfo,
phy_idx, RX_FLTR_MODE_SCAN);
} else {
/* restore rx filter mode */
hal_status = rtw_hal_set_rxfltr_by_mode(hinfo,
phy_idx, *mode);
}
return hal_status;
}
enum rtw_hal_status
rtw_hal_enter_mon_mode(void *hinfo, enum phl_phy_idx phy_idx)
{
return rtw_hal_set_rxfltr_by_mode(hinfo, phy_idx, RX_FLTR_MODE_SNIFFER);
}
enum rtw_hal_status
rtw_hal_leave_mon_mode(void *hinfo, enum phl_phy_idx phy_idx)
{
return rtw_hal_set_rxfltr_by_mode(hinfo, phy_idx, RX_FLTR_MODE_RESTORE);
}
enum rtw_hal_status rtw_hal_acpt_crc_err_pkt(void *hal, u8 band, u8 enable)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct rtw_hal_com_t *hal_com = hal_info->hal_com;
return rtw_hal_mac_set_rxfltr_acpt_crc_err(hal_com, band, enable);
}
enum rtw_hal_status rtw_hal_set_rxfltr_mpdu_size(void *hal, u8 band, u16 size)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct rtw_hal_com_t *hal_com = hal_info->hal_com;
return rtw_hal_mac_set_rxfltr_mpdu_size(hal_com, band, size);
}
enum rtw_hal_status rtw_hal_set_rxfltr_by_type(void *hal, u8 band, u8 type, u8 target)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
enum rtw_hal_status hstats = RTW_HAL_STATUS_FAILURE;
hstats = rtw_hal_mac_set_rxfltr_by_type(hal_info->hal_com, band, type, target);
if (RTW_HAL_STATUS_SUCCESS != hstats)
PHL_ERR("%s : type %u status %u target %u.band %u \n", __func__, type, hstats, target, band);
return hstats;
}
enum rtw_hal_status
rtw_hal_poll_hw_rx_done(void *hal)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
enum rtw_hal_status sts = RTW_HAL_STATUS_SUCCESS;
sts = rtw_hal_mac_poll_hw_rx_done(hal_info);
return sts;
}
enum rtw_hal_status
rtw_hal_hw_rx_resume(void *hal)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
enum rtw_hal_status sts = RTW_HAL_STATUS_SUCCESS;
sts = rtw_hal_mac_hw_rx_resume(hal_info);
return sts;
}
#ifdef CONFIG_PCI_HCI
/**
* rtw_hal_rx_res_query - query current HW rx resource with specifc dma channel
* @hal: see struct hal_info_t
* @dma_ch: the target dma channel
* @host_idx: current host index of this channel
* @hw_idx: current hw index of this channel
*
* this function returns the number of available tx resource
* NOTE, input host_idx and hw_idx ptr shall NOT be NULL
*/
u16 rtw_hal_rx_res_query(void *hal, u8 dma_ch, u16 *host_idx, u16 *hw_idx)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
u16 res_num = 0;
res_num = trx_ops->query_rx_res(hal_info->hal_com, dma_ch, host_idx,
hw_idx);
return res_num;
}
/**
* rtw_hal_query_rxch_num - query total hw rx dma channels number
*
* returns the number of hw rx dma channel
*/
u8 rtw_hal_query_rxch_num(void *hal)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
u8 ch_num = 0;
ch_num = trx_ops->query_rxch_num();
return ch_num;
}
u8 rtw_hal_check_rxrdy(struct rtw_phl_com_t *phl_com, void* hal, u8 *rxbuf, u8 dma_ch)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
u8 res = 0;
res = trx_ops->check_rxrdy(phl_com, rxbuf, dma_ch);
return res;
}
u8 rtw_hal_handle_rxbd_info(void* hal, u8 *rxbuf, u16 *buf_size)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
u8 res = 0;
res = trx_ops->handle_rxbd_info(hal_info, rxbuf, buf_size);
return res;
}
enum rtw_hal_status
rtw_hal_update_rxbd(void *hal, struct rx_base_desc *rxbd,
struct rtw_rx_buf *rxbuf)
{
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
hstatus = trx_ops->update_rxbd(hal_info, rxbd, rxbuf);
return hstatus;
}
enum rtw_hal_status rtw_hal_notify_rxdone(void* hal,
struct rx_base_desc *rxbd, u8 ch, u16 rxcnt)
{
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
hstatus = trx_ops->notify_rxdone(hal_info, rxbd, ch, rxcnt);
return hstatus;
}
u16 rtw_hal_handle_wp_rpt(void *hal, u8 *rp, u16 len, u8 *sw_retry, u8 *dma_ch,
u16 *wp_seq, u8 *macid, u8 *ac_queue, u8 *txsts)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
u16 rsize = 0;
rsize = trx_ops->handle_wp_rpt(hal_info, rp, len, sw_retry, dma_ch,
wp_seq, macid, ac_queue, txsts);
return rsize;
}
#endif /*CONFIG_PCI_HCI*/
#ifdef CONFIG_USB_HCI
enum rtw_hal_status
rtw_hal_query_info(void* hal, u8 info_id, void *value)
{
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
hstatus = trx_ops->query_hal_info(hal_info, info_id, value);
return hstatus;
}
enum rtw_hal_status
rtw_hal_usb_rx_agg_cfg(void *hal, u8 mode, u8 agg_mode,
u8 drv_define, u8 timeout, u8 size, u8 pkt_num)
{
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
hstatus = trx_ops->usb_rx_agg_cfg(hal, mode, agg_mode,
drv_define, timeout, size, pkt_num);
return hstatus;
}
u16 rtw_hal_handle_wp_rpt_usb(void *hal, u8 *rp, u16 len, u8 *macid, u8 *ac_queue,
u8 *txsts)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
u16 rsize = 0;
rsize = trx_ops->handle_wp_rpt(hal_info, rp, len, macid, ac_queue, txsts);
return rsize;
}
#endif
enum rtw_hal_status
rtw_hal_handle_rx_buffer(struct rtw_phl_com_t *phl_com, void* hal,
u8 *buf, u32 buf_size,
struct rtw_phl_rx_pkt *rxpkt)
{
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
struct hal_trx_ops *trx_ops = hal_info->trx_ops;
hstatus = trx_ops->handle_rx_buffer(phl_com, hal_info,
buf, buf_size, rxpkt);
return hstatus;
}
#ifdef CONFIG_SDIO_HCI
void rtw_hal_sdio_rx_agg_cfg(void *hal, bool enable, u8 drv_define,
u8 timeout, u8 size, u8 pkt_num)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
rtw_hal_mac_sdio_rx_agg_cfg(hal_info->hal_com, enable, drv_define,
timeout, size, pkt_num);
}
int rtw_hal_sdio_rx(void *hal, struct rtw_rx_buf *rxbuf)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
return rtw_hal_mac_sdio_rx(hal_info->hal_com, rxbuf);
}
int rtw_hal_sdio_parse_rx(void *hal, struct rtw_rx_buf *rxbuf)
{
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
return rtw_hal_mac_sdio_parse_rx(hal_info->hal_com, rxbuf);
}
#endif /* CONFIG_SDIO_HCI */
void
hal_rx_ppdu_sts_normal_data(struct rtw_phl_com_t *phl_com,
void *hdr,
struct rtw_r_meta_data *meta)
{
struct rtw_phl_ppdu_sts_info *ppdu_info = NULL;
enum phl_band_idx band = HW_BAND_0;
do {
if ((NULL == phl_com) || (NULL == meta))
break;
ppdu_info = &phl_com->ppdu_sts_info;
band = (meta->bb_sel > 0) ? HW_BAND_1 : HW_BAND_0;
if ((ppdu_info->cur_rx_ppdu_cnt[band] == meta->ppdu_cnt) &&
(false == ppdu_info->latest_rx_is_psts[band])) {
/**
* add condition to avoid check fail for ppdu cnt run around 0 -> 1 -> ... -> 0
* example :
* [frame_A(ppdu_cnt = 0)] -> [ppdu_sts(ppdu_cnt = 0)]
* ->[ppdu_sts(ppdu_cnt = 1)] -> [ppdu_sts(ppdu_cnt = 2)] ...
* ... ->[ppdu_sts(ppdu_cnt = 7)] -> [frame_B(ppdu_cnt = 0)] ...
* Therefore, frame_B has same ppdu_cnt with frame_A.
* But they are different PPDU.
**/
break;
}
meta->ppdu_cnt_chg = true;
/* start of the PPDU */
ppdu_info->latest_rx_is_psts[band] = false;
ppdu_info->sts_ent[band][meta->ppdu_cnt].addr_cam_vld = meta->addr_cam_vld;
ppdu_info->sts_ent[band][meta->ppdu_cnt].frame_type = PHL_GET_80211_HDR_TYPE(hdr);
ppdu_info->sts_ent[band][meta->ppdu_cnt].crc32 = meta->crc32;
ppdu_info->sts_ent[band][meta->ppdu_cnt].rx_rate = meta->rx_rate;
ppdu_info->sts_ent[band][meta->ppdu_cnt].ppdu_type = meta->ppdu_type;
if(RTW_IS_BEACON_OR_PROBE_RESP_PKT(ppdu_info->sts_ent[band][meta->ppdu_cnt].frame_type)) {
PHL_GET_80211_HDR_ADDRESS3(phl_com->drv_priv, hdr,
ppdu_info->sts_ent[band][meta->ppdu_cnt].src_mac_addr);
}
else if (meta->a1_match &&
RTW_IS_ASOC_REQ_PKT(ppdu_info->sts_ent[band][meta->ppdu_cnt].frame_type)) {
PHL_GET_80211_HDR_ADDRESS2(phl_com->drv_priv, hdr,
ppdu_info->sts_ent[band][meta->ppdu_cnt].src_mac_addr);
#ifdef DBG_AP_CLIENT_ASSOC_RSSI
{
u8 *src = NULL;
src = ppdu_info->sts_ent[band][meta->ppdu_cnt].src_mac_addr;
PHL_INFO("%s [Rx-ASOC_REQ] - MAC-Addr:%02x-%02x-%02x-%02x-%02x-%02x, a1_match:%d ppdu_cnt:%d\n",
__func__,
src[0], src[1], src[2], src[3], src[4], src[5],
meta->a1_match,
meta->ppdu_cnt);
}
#endif
}
else {
_os_mem_cpy(phl_com->drv_priv,
ppdu_info->sts_ent[band][meta->ppdu_cnt].src_mac_addr,
meta->ta, MAC_ADDRESS_LENGTH);
}
ppdu_info->sts_ent[band][meta->ppdu_cnt].valid = false;
ppdu_info->cur_rx_ppdu_cnt[band] = meta->ppdu_cnt;
PHL_TRACE(COMP_PHL_PSTS, _PHL_INFO_,
"Start of the PPDU : band %d ; ppdu_cnt %d ; frame_type %d ; addr_cam_vld %d ; size %d ; rate 0x%x ; crc32 %d\n",
band,
ppdu_info->cur_rx_ppdu_cnt[band],
ppdu_info->sts_ent[band][meta->ppdu_cnt].frame_type,
ppdu_info->sts_ent[band][meta->ppdu_cnt].addr_cam_vld,
meta->pktlen,
meta->rx_rate,
meta->crc32);
} while (false);
}
void
hal_rx_ppdu_sts(struct rtw_phl_com_t *phl_com,
struct rtw_phl_rx_pkt *phl_rx,
struct hal_ppdu_sts *ppdu_sts)
{
struct rtw_phl_ppdu_sts_info *ppdu_info = NULL;
struct rtw_phl_rssi_stat *rssi_stat = NULL;
struct rtw_r_meta_data *meta = &(phl_rx->r.mdata);
struct rtw_phl_ppdu_phy_info *phy_info = &(phl_rx->r.phy_info);
u8 i = 0;
enum phl_band_idx band = HW_BAND_0;
struct rtw_phl_ppdu_sts_ent *sts_ent = NULL;
if ((NULL == phl_com) || (NULL == meta) || (NULL == ppdu_sts))
return;
ppdu_info = &phl_com->ppdu_sts_info;
rssi_stat = &phl_com->rssi_stat;
band = (meta->bb_sel > 0) ? HW_BAND_1 : HW_BAND_0;
ppdu_info->latest_rx_is_psts[band] = true;
if (0 == phy_info->is_valid)
return;
if (ppdu_info->cur_rx_ppdu_cnt[band] != meta->ppdu_cnt) {
PHL_TRACE(COMP_PHL_PSTS, _PHL_INFO_,
"[WARNING] ppdu cnt mis-match (band %d ; cur : %d , rxmeta : %d)\n",
band,
ppdu_info->cur_rx_ppdu_cnt[band],
meta->ppdu_cnt);
}
sts_ent = &(ppdu_info->sts_ent[band][meta->ppdu_cnt]);
if (meta->crc32 || sts_ent->crc32) {
UPDATE_MA_RSSI(rssi_stat, RTW_RSSI_UNKNOWN,
phy_info->rssi);
return;
}
if (sts_ent->rx_rate != meta->rx_rate) {
PHL_TRACE(COMP_PHL_PSTS, _PHL_INFO_,
"[WARNING] PPDU STS rx rate mis-match\n");
UPDATE_MA_RSSI(rssi_stat, RTW_RSSI_UNKNOWN,
phy_info->rssi);
return;
}
if (sts_ent->ppdu_type != meta->ppdu_type) {
PHL_TRACE(COMP_PHL_PSTS, _PHL_INFO_,
"[WARNING] PPDU STS ppdu_type mis-match\n");
UPDATE_MA_RSSI(rssi_stat, RTW_RSSI_UNKNOWN,
phy_info->rssi);
return;
}
if (sts_ent->valid == true) {
PHL_TRACE(COMP_PHL_PSTS, _PHL_INFO_,
"[WARNING] PPDU STS is already updated, skip this ppdu status\n");
return;
}
/* update ppdu_info entry */
sts_ent->freerun_cnt = meta->freerun_cnt;
_os_mem_cpy(phl_com->drv_priv,
&(sts_ent->phy_info),
phy_info, sizeof(struct rtw_phl_ppdu_phy_info));
sts_ent->usr_num = ppdu_sts->usr_num;
for (i = 0; i < ppdu_sts->usr_num; i++) {
if (ppdu_sts->usr[i].vld) {
sts_ent->sta[i].macid =
ppdu_sts->usr[i].macid;
sts_ent->sta[i].vld = 1;
} else {
sts_ent->sta[i].vld = 0;
}
}
sts_ent->phl_done = false;
sts_ent->valid = true;
/* update rssi stat */
_os_spinlock(phl_com->drv_priv, &rssi_stat->lock, _bh, NULL);
switch (sts_ent->frame_type &
(BIT(1) | BIT(0))) {
case RTW_FRAME_TYPE_MGNT :
if (sts_ent->addr_cam_vld) {
UPDATE_MA_RSSI(rssi_stat,
(1 == meta->a1_match) ?
RTW_RSSI_MGNT_ACAM_A1M :
RTW_RSSI_MGNT_ACAM,
phy_info->rssi);
} else {
UPDATE_MA_RSSI(rssi_stat, RTW_RSSI_MGNT_OTHER,
phy_info->rssi);
}
break;
case RTW_FRAME_TYPE_CTRL :
if (sts_ent->addr_cam_vld) {
UPDATE_MA_RSSI(rssi_stat,
(1 == meta->a1_match) ?
RTW_RSSI_CTRL_ACAM_A1M :
RTW_RSSI_CTRL_ACAM,
phy_info->rssi);
} else {
UPDATE_MA_RSSI(rssi_stat, RTW_RSSI_CTRL_OTHER,
phy_info->rssi);
}
break;
case RTW_FRAME_TYPE_DATA :
if (sts_ent->addr_cam_vld) {
UPDATE_MA_RSSI(rssi_stat,
(1 == meta->a1_match) ?
RTW_RSSI_DATA_ACAM_A1M :
RTW_RSSI_DATA_ACAM,
phy_info->rssi);
} else {
UPDATE_MA_RSSI(rssi_stat, RTW_RSSI_DATA_OTHER,
phy_info->rssi);
}
break;
default:
UPDATE_MA_RSSI(rssi_stat, RTW_RSSI_UNKNOWN,
phy_info->rssi);
break;
}
_os_spinunlock(phl_com->drv_priv, &rssi_stat->lock, _bh, NULL);
}