/******************************************************************************
|
*
|
* 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_TRX_8852BE_C_
|
#include "../rtl8852b_hal.h"
|
#include "hal_trx_8852be.h"
|
|
/**
|
* this function will query total hw tx dma channels number
|
*
|
* returns the number of hw tx dma channel
|
*/
|
static u8 hal_query_txch_num_8852be(void)
|
{
|
u8 ch_num = 0;
|
|
ch_num = TX_DMA_CHANNEL_ENTRY_8852BE;
|
|
return ch_num;
|
}
|
|
/**
|
* this function will query total hw rx dma channels number
|
*
|
* returns the number of hw rx dma channel
|
*/
|
static u8 hal_query_rxch_num_8852be(void)
|
{
|
u8 ch_num = 0;
|
|
ch_num = RX_DMA_CHANNEL_ENTRY_8852BE;
|
|
return ch_num;
|
}
|
static u8 hal_qsel_to_tid_8852be(struct hal_info_t *hal, u8 qsel_id, u8 tid_indic)
|
{
|
u8 tid = 0;
|
|
switch (qsel_id) {
|
case RTW_TXDESC_QSEL_BE_0:
|
case RTW_TXDESC_QSEL_BE_1:
|
case RTW_TXDESC_QSEL_BE_2:
|
case RTW_TXDESC_QSEL_BE_3:
|
tid = (1 == tid_indic) ? RTW_PHL_RING_CAT_TID3 : RTW_PHL_RING_CAT_TID0;
|
break;
|
case RTW_TXDESC_QSEL_BK_0:
|
case RTW_TXDESC_QSEL_BK_1:
|
case RTW_TXDESC_QSEL_BK_2:
|
case RTW_TXDESC_QSEL_BK_3:
|
tid = (1 == tid_indic) ? RTW_PHL_RING_CAT_TID2 : RTW_PHL_RING_CAT_TID1;
|
break;
|
case RTW_TXDESC_QSEL_VI_0:
|
case RTW_TXDESC_QSEL_VI_1:
|
case RTW_TXDESC_QSEL_VI_2:
|
case RTW_TXDESC_QSEL_VI_3:
|
tid = (1 == tid_indic) ? RTW_PHL_RING_CAT_TID5 : RTW_PHL_RING_CAT_TID4;
|
break;
|
case RTW_TXDESC_QSEL_VO_0:
|
case RTW_TXDESC_QSEL_VO_1:
|
case RTW_TXDESC_QSEL_VO_2:
|
case RTW_TXDESC_QSEL_VO_3:
|
tid = (1 == tid_indic) ? RTW_PHL_RING_CAT_TID7 : RTW_PHL_RING_CAT_TID6;
|
break;
|
case RTW_TXDESC_QSEL_MGT_0:
|
case RTW_TXDESC_QSEL_MGT_1:
|
tid = RTW_PHL_RING_CAT_MGNT;
|
break;
|
case RTW_TXDESC_QSEL_HIGH_0:
|
case RTW_TXDESC_QSEL_HIGH_1:
|
tid = RTW_PHL_RING_CAT_HIQ;
|
break;
|
default :
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown qsel_id (%d)\n",
|
qsel_id);
|
tid = 0;
|
break;
|
}
|
|
return tid;
|
}
|
|
/**
|
* Get target DMA channel's BD ram hw register of rtl8852b
|
* @dma_ch: input target dma channel with the hw definition of rtl8852BE
|
* return the BD ram hw register
|
*/
|
static u32 _hal_get_bd_ram_reg_8852be(u8 dma_ch)
|
{
|
u32 reg = 0;
|
|
switch (dma_ch) {
|
case ACH0_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH0_BDRAM_CTRL;
|
break;
|
case ACH1_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH1_BDRAM_CTRL;
|
break;
|
case ACH2_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH2_BDRAM_CTRL;
|
break;
|
case ACH3_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH3_BDRAM_CTRL;
|
break;
|
case ACH4_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH4_BDRAM_CTRL;
|
break;
|
case ACH5_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH5_BDRAM_CTRL;
|
break;
|
case ACH6_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH6_BDRAM_CTRL;
|
break;
|
case ACH7_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH7_BDRAM_CTRL;
|
break;
|
case MGQ_B0_QUEUE_IDX_8852BE:
|
reg = R_AX_CH8_BDRAM_CTRL;
|
break;
|
case HIQ_B0_QUEUE_IDX_8852BE:
|
reg = R_AX_CH9_BDRAM_CTRL;
|
break;
|
case MGQ_B1_QUEUE_IDX_8852BE:
|
reg = R_AX_CH10_BDRAM_CTRL;
|
break;
|
case HIQ_B1_QUEUE_IDX_8852BE:
|
reg = R_AX_CH11_BDRAM_CTRL;
|
break;
|
case FWCMD_QUEUE_IDX_8852BE:
|
reg = R_AX_CH12_BDRAM_CTRL;
|
break;
|
default :
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown channel (%d)\n",
|
dma_ch);
|
reg = 0xFFFF;
|
break;
|
}
|
|
return reg;
|
}
|
|
|
|
/**
|
* Get target DMA channel's BD num hw register of rtl8852b
|
* @dma_ch: input target dma channel with the hw definition of rtl8852BE
|
* return the BD num hw register
|
*/
|
static u32 _hal_get_bd_num_reg_8852be(u8 dma_ch)
|
{
|
u32 reg = 0;
|
|
switch (dma_ch) {
|
case ACH0_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH0_TXBD_NUM;
|
break;
|
case ACH1_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH1_TXBD_NUM;
|
break;
|
case ACH2_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH2_TXBD_NUM;
|
break;
|
case ACH3_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH3_TXBD_NUM;
|
break;
|
case ACH4_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH4_TXBD_NUM;
|
break;
|
case ACH5_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH5_TXBD_NUM;
|
break;
|
case ACH6_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH6_TXBD_NUM;
|
break;
|
case ACH7_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH7_TXBD_NUM;
|
break;
|
case MGQ_B0_QUEUE_IDX_8852BE:
|
reg = R_AX_CH8_TXBD_NUM;
|
break;
|
case HIQ_B0_QUEUE_IDX_8852BE:
|
reg = R_AX_CH9_TXBD_NUM;
|
break;
|
case MGQ_B1_QUEUE_IDX_8852BE:
|
reg = R_AX_CH10_TXBD_NUM;
|
break;
|
case HIQ_B1_QUEUE_IDX_8852BE:
|
reg = R_AX_CH11_TXBD_NUM;
|
break;
|
case FWCMD_QUEUE_IDX_8852BE:
|
reg = R_AX_CH12_TXBD_NUM;
|
break;
|
case RX_QUEUE_IDX_8852BE:
|
reg = R_AX_RXQ_RXBD_NUM;
|
break;
|
case RP_QUEUE_IDX_8852BE:
|
reg = R_AX_RPQ_RXBD_NUM;
|
break;
|
default :
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown channel (%d)\n",
|
dma_ch);
|
reg = 0xFFFF;
|
break;
|
}
|
|
return reg;
|
}
|
|
|
/**
|
* Get target DMA channel's BD Desc hw register of rtl8852b
|
* @dma_ch: input target dma channel with the hw definition of rtl8852BE
|
* return the BD Desc hw register
|
*/
|
static void _hal_get_bd_desc_reg_8852be(u8 dma_ch, u32 *addr_l, u32 *addr_h)
|
{
|
u32 reg = 0;
|
|
switch (dma_ch) {
|
case ACH0_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_ACH0_TXBD_DESA_L;
|
*addr_h = R_AX_ACH0_TXBD_DESA_H;
|
break;
|
case ACH1_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_ACH1_TXBD_DESA_L;
|
*addr_h = R_AX_ACH1_TXBD_DESA_H;
|
break;
|
case ACH2_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_ACH2_TXBD_DESA_L;
|
*addr_h = R_AX_ACH2_TXBD_DESA_H;
|
break;
|
case ACH3_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_ACH3_TXBD_DESA_L;
|
*addr_h = R_AX_ACH3_TXBD_DESA_H;
|
break;
|
case ACH4_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_ACH4_TXBD_DESA_L;
|
*addr_h = R_AX_ACH4_TXBD_DESA_H;
|
break;
|
case ACH5_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_ACH5_TXBD_DESA_L;
|
*addr_h = R_AX_ACH5_TXBD_DESA_H;
|
break;
|
case ACH6_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_ACH6_TXBD_DESA_L;
|
*addr_h = R_AX_ACH6_TXBD_DESA_H;
|
break;
|
case ACH7_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_ACH7_TXBD_DESA_L;
|
*addr_h = R_AX_ACH7_TXBD_DESA_H;
|
break;
|
case MGQ_B0_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_CH8_TXBD_DESA_L;
|
*addr_h = R_AX_CH8_TXBD_DESA_H;
|
break;
|
case HIQ_B0_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_CH9_TXBD_DESA_L;
|
*addr_h = R_AX_CH9_TXBD_DESA_H;
|
break;
|
case MGQ_B1_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_CH10_TXBD_DESA_L;
|
*addr_h = R_AX_CH10_TXBD_DESA_H;
|
break;
|
case HIQ_B1_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_CH11_TXBD_DESA_L;
|
*addr_h = R_AX_CH11_TXBD_DESA_H;
|
break;
|
case FWCMD_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_CH12_TXBD_DESA_L;
|
*addr_h = R_AX_CH12_TXBD_DESA_H;
|
break;
|
case RX_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_RXQ_RXBD_DESA_L;
|
*addr_h = R_AX_RXQ_RXBD_DESA_H;
|
break;
|
case RP_QUEUE_IDX_8852BE:
|
*addr_l = R_AX_RPQ_RXBD_DESA_L;
|
*addr_h = R_AX_RPQ_RXBD_DESA_H;
|
break;
|
default :
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown channel (%d)\n",
|
dma_ch);
|
reg = 0xFFFF;
|
break;
|
}
|
|
}
|
|
|
|
/**
|
* Get target DMA channel's BD Index hw register of rtl8852b
|
* @dma_ch: input target dma channel with the hw definition of rtl8852BE
|
* return the BD Index hw register
|
*/
|
static u32 _hal_get_bd_idx_reg_8852be(u8 dma_ch)
|
{
|
u32 reg = 0;
|
|
switch (dma_ch) {
|
case ACH0_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH0_TXBD_IDX;
|
break;
|
case ACH1_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH1_TXBD_IDX;
|
break;
|
case ACH2_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH2_TXBD_IDX;
|
break;
|
case ACH3_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH3_TXBD_IDX;
|
break;
|
case ACH4_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH4_TXBD_IDX;
|
break;
|
case ACH5_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH5_TXBD_IDX;
|
break;
|
case ACH6_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH6_TXBD_IDX;
|
break;
|
case ACH7_QUEUE_IDX_8852BE:
|
reg = R_AX_ACH7_TXBD_IDX;
|
break;
|
case MGQ_B0_QUEUE_IDX_8852BE:
|
reg = R_AX_CH8_TXBD_IDX;
|
break;
|
case HIQ_B0_QUEUE_IDX_8852BE:
|
reg = R_AX_CH9_TXBD_IDX;
|
break;
|
case MGQ_B1_QUEUE_IDX_8852BE:
|
reg = R_AX_CH10_TXBD_IDX;
|
break;
|
case HIQ_B1_QUEUE_IDX_8852BE:
|
reg = R_AX_CH11_TXBD_IDX;
|
break;
|
case FWCMD_QUEUE_IDX_8852BE:
|
reg = R_AX_CH12_TXBD_IDX;
|
break;
|
case RX_QUEUE_IDX_8852BE:
|
reg = R_AX_RXQ_RXBD_IDX;
|
break;
|
case RP_QUEUE_IDX_8852BE:
|
reg = R_AX_RPQ_RXBD_IDX;
|
break;
|
default :
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown channel (%d)\n",
|
dma_ch);
|
reg = 0xFFFF;
|
break;
|
}
|
|
return reg;
|
}
|
|
|
/**
|
* this function maps the sw xmit ring identified by macid, tid and band
|
* to rtl8852BE hw tx dma channel
|
* @macid: input target macid range is 0 ~ 127
|
* @cat: input target packet category, see enum rtw_phl_ring_cat
|
* @band: input target band, 0 for band 0 / 1 for band 1
|
*
|
* returns the mapping hw dma channel defined by XXX_QUEUE_IDX_8852BE
|
* if the input parameter is unknown value, returns ACH0_QUEUE_IDX_8852BE
|
*/
|
static u8 hal_mapping_hw_tx_chnl_8852be(struct hal_info_t *hal,
|
u16 macid, enum rtw_phl_ring_cat cat, u8 band)
|
{
|
u8 dma_ch = 0;
|
|
/* hana_todo, decided by tid only currently,
|
we should consider more situation later */
|
|
if (0 == band) {
|
switch (cat) {
|
case RTW_PHL_RING_CAT_TID0:
|
case RTW_PHL_RING_CAT_TID3:
|
dma_ch = ACH0_QUEUE_IDX_8852BE;
|
break;
|
case RTW_PHL_RING_CAT_TID1:
|
case RTW_PHL_RING_CAT_TID2:
|
dma_ch = ACH1_QUEUE_IDX_8852BE;
|
break;
|
case RTW_PHL_RING_CAT_TID4:
|
case RTW_PHL_RING_CAT_TID5:
|
dma_ch = ACH2_QUEUE_IDX_8852BE;
|
break;
|
case RTW_PHL_RING_CAT_TID6:
|
case RTW_PHL_RING_CAT_TID7:
|
dma_ch = ACH3_QUEUE_IDX_8852BE;
|
break;
|
case RTW_PHL_RING_CAT_MGNT:
|
dma_ch = MGQ_B0_QUEUE_IDX_8852BE;
|
break;
|
case RTW_PHL_RING_CAT_HIQ:
|
dma_ch = HIQ_B0_QUEUE_IDX_8852BE;
|
break;
|
default:
|
dma_ch = ACH0_QUEUE_IDX_8852BE;
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown category (%d)\n",
|
cat);
|
break;
|
}
|
} else {
|
dma_ch = ACH0_QUEUE_IDX_8852BE;
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]unknown band (%d)\n",
|
band);
|
}
|
|
return dma_ch;
|
}
|
|
static void hal_query_txch_map_8852be(enum phl_band_idx band, void *ch_map)
|
{
|
struct mac_ax_txdma_ch_map *txch_map = (struct mac_ax_txdma_ch_map *)ch_map;
|
|
if(band == HW_BAND_0) {
|
txch_map->ch0 = MAC_AX_PCIE_ENABLE;
|
txch_map->ch1 = MAC_AX_PCIE_ENABLE;
|
txch_map->ch2 = MAC_AX_PCIE_ENABLE;
|
txch_map->ch3 = MAC_AX_PCIE_ENABLE;
|
|
txch_map->ch8 = MAC_AX_PCIE_ENABLE;
|
txch_map->ch9 = MAC_AX_PCIE_ENABLE;
|
}
|
|
txch_map->ch4 = MAC_AX_PCIE_IGNORE;
|
txch_map->ch5 = MAC_AX_PCIE_IGNORE;
|
txch_map->ch6 = MAC_AX_PCIE_IGNORE;
|
txch_map->ch7 = MAC_AX_PCIE_IGNORE;
|
|
txch_map->ch10 = MAC_AX_PCIE_IGNORE;
|
txch_map->ch11 = MAC_AX_PCIE_IGNORE;
|
|
txch_map->ch12 = MAC_AX_PCIE_IGNORE;
|
}
|
|
static u8 hal_query_txch_hwband_8852be(u8 dma_ch)
|
{
|
u8 band = 0;
|
return band;
|
}
|
|
/**
|
* this function will return available txbd number of target dma channel
|
* @ch_idx: input, target dma channel index
|
* @host_idx: the ptr of current host index of this channel
|
* @hw_idx: the ptr of current hw index of this channel
|
*
|
* NOTE, input host_idx and hw_idx ptr shall NOT be NULL
|
*/
|
static u16 hal_get_avail_txbd_8852be(struct rtw_hal_com_t *hal_com, u8 ch_idx,
|
u16 *host_idx, u16 *hw_idx)
|
{
|
struct bus_cap_t *bus_cap = &hal_com->bus_cap;
|
u16 avail_txbd = 0;
|
u32 tmp32 = 0, reg = 0;
|
u8 tx_dma_ch = 0;
|
|
tx_dma_ch = ACH0_QUEUE_IDX_8852BE + ch_idx;
|
|
reg = _hal_get_bd_idx_reg_8852be(tx_dma_ch);
|
if (0xFFFF == reg) {
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
|
"[WARNING]get dma channel register fail\n");
|
avail_txbd = 0;
|
} else {
|
tmp32 = hal_read32(hal_com, reg);
|
|
*host_idx = (u16)(tmp32 & 0x0FFF);
|
*hw_idx = (u16)((tmp32 >> 16) & 0x0FFF);
|
|
avail_txbd = hal_calc_avail_wptr(*hw_idx, *host_idx,
|
bus_cap->txbd_num);
|
PHL_TRACE(COMP_PHL_XMIT, _PHL_DEBUG_,
|
"hal_get_avail_txbd_8852be => dma_ch %d, host_idx %d, "
|
"hw_idx %d, avail_txbd %d\n",
|
ch_idx, *host_idx, *hw_idx, avail_txbd);
|
}
|
|
return avail_txbd;
|
}
|
|
static u16 hal_get_rxbd_num_8852be(struct rtw_hal_com_t *hal_com, u8 ch_idx)
|
{
|
u16 res = 0;
|
|
if (ch_idx == MAC_AX_RX_CH_RXQ)
|
res = (u16)hal_com->bus_cap.rxbd_num;
|
else if (ch_idx == MAC_AX_RX_CH_RPQ)
|
res = (u16)hal_com->bus_cap.rpbd_num;
|
else
|
PHL_ERR("[%s] Invalid rx ch idx:%d\n", __func__, ch_idx);
|
|
return res;
|
}
|
|
static u16 hal_get_rxbuf_num_8852be(struct rtw_hal_com_t *hal_com, u8 ch_idx)
|
{
|
u16 res = 0;
|
|
if (ch_idx == MAC_AX_RX_CH_RXQ)
|
res = (u16)hal_com->bus_cap.rxbuf_num;
|
else if (ch_idx == MAC_AX_RX_CH_RPQ)
|
res = (u16)hal_com->bus_cap.rpbuf_num;
|
else
|
PHL_ERR("[%s] Invalid rx ch idx:%d\n", __func__, ch_idx);
|
|
return res;
|
}
|
|
static u16 hal_get_rxbuf_size_8852be(struct rtw_hal_com_t *hal_com, u8 ch_idx)
|
{
|
u16 res = 0;
|
|
if (ch_idx == MAC_AX_RX_CH_RXQ)
|
res = (u16)hal_com->bus_cap.rxbuf_size;
|
else if (ch_idx == MAC_AX_RX_CH_RPQ)
|
res = (u16)hal_com->bus_cap.rpbuf_size;
|
else
|
PHL_ERR("[%s] Invalid rx ch idx:%d\n", __func__, ch_idx);
|
|
return res;
|
}
|
|
/**
|
* this function will return available txbd number of target dma channel
|
* @ch_idx: input, target dma channel index
|
* @host_idx: the ptr of current host index of this channel
|
* @hw_idx: the ptr of current hw index of this channel
|
*
|
* NOTE, input host_idx and hw_idx ptr shall NOT be NULL
|
*/
|
static u16 hal_get_avail_rxbd_8852be(struct rtw_hal_com_t *hal_com, u8 ch_idx,
|
u16 *host_idx, u16 *hw_idx)
|
{
|
u16 avail_rxbd = 0;
|
u32 tmp32 = 0, reg = 0;
|
u8 rx_dma_ch = 0;
|
u16 rxbd_num = hal_get_rxbd_num_8852be(hal_com, ch_idx);
|
|
rx_dma_ch = RX_QUEUE_IDX_8852BE + ch_idx;
|
|
reg = _hal_get_bd_idx_reg_8852be(rx_dma_ch);
|
if (0xFFFF == reg) {
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING]get dma channel register fail\n");
|
avail_rxbd = 0;
|
} else {
|
tmp32 = hal_read32(hal_com, reg);
|
|
*host_idx = (u16)(tmp32 & 0x0FFF);
|
*hw_idx = (u16)((tmp32 >> 16) & 0x0FFF);
|
|
avail_rxbd = hal_calc_avail_rptr(*host_idx, *hw_idx, rxbd_num);
|
}
|
|
return avail_rxbd;
|
}
|
|
void _hal_fill_wp_seq_field_8852be(u8 *seq_info, u16 wp_seq)
|
{
|
/* update sw wp seq */
|
SET_PCIE_SEQ_INFO_0(seq_info, wp_seq);
|
SET_PCIE_SEQ_INFO_0_VALID(seq_info, 1);
|
}
|
|
void _hal_fill_wp_addr_info_8852be(struct rtw_hal_com_t *hal_com,
|
u8 *addr_info, struct rtw_pkt_buf_list *pkt,
|
u8 num, u8 mpdu_ls, u8 msdu_ls)
|
{
|
SET_ADDR_INFO_LEN(addr_info, pkt->length);
|
SET_ADDR_INFO_NUM(addr_info, num);
|
SET_ADDR_INFO_MSDU_LS(addr_info, msdu_ls);
|
SET_ADDR_INFO_ADDR_LOW(addr_info, pkt->phy_addr_l);
|
SET_ADDR_INFO_ADDR_HIGH(addr_info, pkt->phy_addr_h);
|
}
|
|
u8 _hal_get_tid_indic_8852be(u8 tid)
|
{
|
u8 tid_indic = 0;
|
switch (tid) {
|
case RTW_PHL_RING_CAT_TID0:
|
case RTW_PHL_RING_CAT_TID1:
|
case RTW_PHL_RING_CAT_TID4:
|
case RTW_PHL_RING_CAT_TID6:
|
case RTW_PHL_RING_CAT_MGNT:
|
case RTW_PHL_RING_CAT_HIQ:
|
tid_indic = 0;
|
break;
|
case RTW_PHL_RING_CAT_TID3:
|
case RTW_PHL_RING_CAT_TID2:
|
case RTW_PHL_RING_CAT_TID5:
|
case RTW_PHL_RING_CAT_TID7:
|
tid_indic = 1;
|
break;
|
default:
|
PHL_ERR("unknown tid %d\n", tid);
|
break;
|
}
|
|
return tid_indic;
|
}
|
|
#ifdef CONFIG_PHL_TXSC
|
static u8 qsel_tbl[] = {
|
TID_0_QSEL/*0*/, TID_1_QSEL/*1*/, TID_2_QSEL/*1*/, TID_3_QSEL/*0*/,
|
TID_4_QSEL/*2*/, TID_5_QSEL/*2*/, TID_6_QSEL/*3*/, TID_7_QSEL/*2*/
|
};
|
|
static u8 tid_ind[] = {
|
TID_0_IND, TID_1_IND, TID_2_IND, TID_3_IND,
|
TID_4_IND, TID_5_IND, TID_6_IND, TID_7_IND
|
};
|
|
static enum rtw_hal_status
|
_hal_txsc_update_wd_8852be(struct hal_info_t *hal,
|
struct rtw_phl_pkt_req *req, u32 *wd_len)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
|
struct rtw_xmit_req *tx_req = req->tx_req;
|
struct rtw_t_meta_data *mdata = &tx_req->mdata;
|
u8 dma_ch;
|
u32 *wd_words;
|
u32 w0, w2, w3, w7, w10;
|
|
#ifdef CONFIG_RTW_TXSC_USE_HW_SEQ
|
/* HW SEQ EN policy. Temporarily map TID to 4 Q and use QSEL as HWSEQ index. */
|
if (mdata->hw_seq_mode) {
|
static const u8 tid_2_qsel[8] = {0, 1, 1, 0, 2, 2, 3, 3};
|
mdata->hw_ssn_sel = tid_2_qsel[mdata->tid];
|
}
|
#endif /* CONFIG_RTW_TXSC_USE_HW_SEQ */
|
dma_ch = hal_mapping_hw_tx_chnl_8852be(hal, mdata->macid,
|
mdata->cat,
|
mdata->band);
|
if (mdata->dma_ch != dma_ch) {
|
PHL_WARN("DMA channel mismatch! (%u/%u/M%u/T%u)\n",
|
dma_ch, mdata->dma_ch, mdata->macid, mdata->tid);
|
}
|
|
if (req->wd_seq_offset == 0) {
|
hstatus = rtw_hal_mac_fill_txdesc(hal->mac,
|
tx_req,
|
req->wd_page,
|
wd_len);
|
req->wd_len = req->wd_seq_offset = (u8)*wd_len;
|
} else {
|
wd_words = (u32 *)req->wd_page;
|
w0 = le32_to_cpu(wd_words[0])
|
& ~((AX_TXD_HW_SSN_SEL_MSK << AX_TXD_HW_SSN_SEL_SH)
|
| (AX_TXD_CH_DMA_MSK << AX_TXD_CH_DMA_SH));
|
w2 = le32_to_cpu(wd_words[2])
|
& ~(AX_TXD_TID_IND
|
| (AX_TXD_QSEL_MSK << AX_TXD_QSEL_SH)
|
| (AX_TXD_TXPKTSIZE_MSK << AX_TXD_TXPKTSIZE_SH));
|
w7 = le32_to_cpu(wd_words[7])
|
& ~(AX_TXD_DATA_RTY_LOWEST_RATE_MSK
|
<< AX_TXD_DATA_RTY_LOWEST_RATE_SH);
|
w10 = le32_to_cpu(wd_words[10])
|
& ~(AX_TXD_RTS_EN | AX_TXD_HW_RTS_EN | AX_TXD_CTS2SELF | (AX_TXD_CCA_RTS_MSK << AX_TXD_CCA_RTS_SH));
|
|
/* Update SSN SEL, DMA CH, QSEL, and TID indicator in WD cache */
|
w0 |= (((mdata->hw_ssn_sel & AX_TXD_HW_SSN_SEL_MSK) << AX_TXD_HW_SSN_SEL_SH)
|
| ((mdata->dma_ch & AX_TXD_CH_DMA_MSK) << AX_TXD_CH_DMA_SH));
|
wd_words[0] = cpu_to_le32(w0);
|
|
if (mdata->hw_seq_mode == 0) {
|
w3 = cpu_to_le32((mdata->sw_seq & 0xFFF) |
|
(mdata->ampdu_en ? BIT(12) : 0) |
|
((mdata->bk || mdata->ack_ch_info) ? BIT(13) : 0));
|
wd_words[3] = w3;
|
}
|
|
if (tid_ind[mdata->tid])
|
w2 |= AX_TXD_TID_IND;
|
|
w2 |= (qsel_tbl[mdata->tid] & AX_TXD_QSEL_MSK) << AX_TXD_QSEL_SH;
|
w2 |= (mdata->pktlen & AX_TXD_TXPKTSIZE_MSK) << AX_TXD_TXPKTSIZE_SH;
|
wd_words[2] = cpu_to_le32(w2);
|
|
w7 |= (mdata->data_rty_lowest_rate
|
& AX_TXD_DATA_RTY_LOWEST_RATE_MSK)
|
<< AX_TXD_DATA_RTY_LOWEST_RATE_SH;
|
wd_words[7] = cpu_to_le32(w7);
|
|
if (mdata->rts_en)
|
w10 |= AX_TXD_RTS_EN;
|
|
if (mdata->cts2self)
|
w10 |= AX_TXD_CTS2SELF;
|
|
if (mdata->rts_cca_mode)
|
w10 |= ((mdata->rts_cca_mode & AX_TXD_CCA_RTS_MSK) << AX_TXD_CCA_RTS_SH);
|
|
if (mdata->hw_rts_en)
|
w10 |= AX_TXD_HW_RTS_EN;
|
|
wd_words[10] = cpu_to_le32(w10);
|
|
*wd_len = req->wd_seq_offset;
|
|
hstatus = RTW_HAL_STATUS_SUCCESS;
|
}
|
|
return hstatus;
|
}
|
#endif
|
|
/**
|
* the function update wd page, including wd info, wd body, seq info, addr info
|
* @hal: see struct hal_info_t
|
* @phl_pkt_req: see struct rtw_phl_pkt_req
|
*/
|
static enum rtw_hal_status
|
hal_update_wd_8852be(struct hal_info_t *hal,
|
struct rtw_phl_pkt_req *req)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
|
struct rtw_hal_com_t *hal_com = hal->hal_com;
|
struct bus_hw_cap_t *bus_hw_cap = &hal_com->bus_hw_cap;
|
struct rtw_xmit_req *tx_req = req ? req->tx_req : NULL;
|
struct rtw_pkt_buf_list *pkt_list = NULL;
|
u32 wd_len = 0, seq_ofst = 0, addr_info_ofst = 0;
|
u16 wp_seq = 0;
|
u8 i = 0, wp_num = 0, mpdu_ls = 0, msdu_ls = 0, tid_indic = 0;
|
FUNCIN_WSTS(hstatus);
|
do {
|
if (NULL == req || NULL == tx_req)
|
break;
|
|
pkt_list = (struct rtw_pkt_buf_list *)tx_req->pkt_list;
|
|
#ifdef CONFIG_PHL_TXSC
|
hstatus = _hal_txsc_update_wd_8852be(hal, req, &wd_len);
|
#else
|
/* connect with halmac */
|
hstatus = rtw_hal_mac_fill_txdesc(hal->mac,
|
tx_req,
|
req->wd_page,
|
&wd_len);
|
#endif
|
tid_indic = _hal_get_tid_indic_8852be(tx_req->mdata.tid);
|
|
seq_ofst = wd_len;
|
wp_seq = (1 == tid_indic) ?
|
(req->wp_seq | WP_TID_INDIC_RESERVED_BIT) : req->wp_seq;
|
_hal_fill_wp_seq_field_8852be(req->wd_page + seq_ofst, wp_seq);
|
|
addr_info_ofst = seq_ofst + bus_hw_cap->seq_info_size;
|
for (i = 0; i < tx_req->mdata.addr_info_num; i++) {
|
if (0 == i)
|
wp_num = tx_req->mdata.addr_info_num;
|
else
|
wp_num = 0;
|
|
if ((tx_req->mdata.addr_info_num - 1) == i)
|
msdu_ls = 1;
|
else
|
msdu_ls = 0;
|
|
_hal_fill_wp_addr_info_8852be(hal_com,
|
req->wd_page + addr_info_ofst,
|
&pkt_list[i], wp_num, mpdu_ls, msdu_ls);
|
|
addr_info_ofst += bus_hw_cap->addr_info_size;
|
|
//debug_dump_data(pkt_list[i].vir_addr, pkt_list[i].length, "dump wp");
|
}
|
|
/* 8852BE length in txbd(wd_len) should be fix to 128 */
|
if (addr_info_ofst != bus_hw_cap->max_wd_page_size)
|
req->wd_len = bus_hw_cap->max_wd_page_size;
|
|
} while (false);
|
|
#if 0 /* remove this for saving cpu cycle */
|
if (RTW_HAL_STATUS_SUCCESS == hstatus) {
|
debug_dump_data(req->wd_page, (u16)addr_info_ofst, "dump wd page");
|
}
|
#endif
|
FUNCOUT_WSTS(hstatus);
|
return hstatus;
|
}
|
|
/**
|
* the function update txbd
|
* @hal: see struct hal_info_t
|
* @txbd_ring: the target txbd ring buffer going to update, see struct tx_base_desc
|
* @wd: the wd page going to be filled in txbd, see struct rtw_wd_page
|
*/
|
static enum rtw_hal_status
|
hal_update_txbd_8852be(struct hal_info_t *hal,
|
struct tx_base_desc *txbd_ring,
|
struct rtw_wd_page *wd_page,
|
u8 ch_idx, u16 wd_num)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
|
struct rtw_hal_com_t *hal_com = hal->hal_com;
|
struct bus_hw_cap_t *bus_hw_cap = &hal_com->bus_hw_cap;
|
struct dvobj_priv *pobj = (struct dvobj_priv *)hal_com->drv_priv;
|
struct pci_dev *pdev = dvobj_to_pci(pobj)->ppcidev;
|
u8 *ring_head = 0;
|
u8 *target_txbd = 0;
|
u16 host_idx = 0;
|
u16 txbd_num = hal_com->bus_cap.txbd_num;
|
|
do {
|
if (NULL == wd_page)
|
break;
|
if (NULL == txbd_ring)
|
break;
|
|
/* connect with halmac */
|
host_idx = txbd_ring[ch_idx].host_idx;
|
|
PHL_TRACE(COMP_PHL_XMIT, _PHL_DEBUG_,
|
"hal_update_txbd_8852be => ch_idx %d, wd_num %d\n",
|
ch_idx, wd_num);
|
|
while (wd_num > 0) {
|
|
ring_head = txbd_ring[ch_idx].vir_addr;
|
target_txbd = ring_head + (host_idx *
|
bus_hw_cap->txbd_len);
|
|
SET_TXBUFFER_DESC_LEN(target_txbd, wd_page->buf_len);
|
SET_TXBUFFER_DESC_LS(target_txbd, wd_page->ls);
|
SET_TXBUFFER_DESC_ADD_LOW(target_txbd,
|
wd_page->phy_addr_l);
|
SET_TXBUFFER_DESC_ADD_HIGH(target_txbd,
|
wd_page->phy_addr_h);
|
host_idx = (host_idx + 1) % txbd_num;
|
wd_page->host_idx = host_idx;
|
wd_num--;
|
|
//multi wd page in one update txbd
|
#if 0//S_TODO
|
if(wd_num > 0){
|
wd_page = list_first_entry(wd_page->list,
|
struct rtw_wd_page,
|
wd_page->list);
|
if(NULL == wd_page)
|
break;
|
}
|
#endif
|
}
|
|
txbd_ring[ch_idx].host_idx = host_idx;
|
|
if (txbd_ring[ch_idx].cache == CACHE_ADDR)
|
pci_cache_wback(pdev, (dma_addr_t *)&txbd_ring[ch_idx].phy_addr_l, txbd_ring[ch_idx].buf_len, DMA_TO_DEVICE);
|
|
} while (false);
|
|
return hstatus;
|
}
|
|
/**
|
* the function trigger tx start
|
* @hal: see struct hal_info_t
|
* @txbd_ring: the target txbd ring buffer going to update, see struct tx_base_desc
|
* @ch_idx: the dma channel index of this txbd_ring
|
*/
|
static enum rtw_hal_status
|
hal_trigger_txdma_8852be(struct hal_info_t *hal,
|
struct tx_base_desc *txbd_ring, u8 ch_idx)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
|
u8 tx_dma_ch;
|
u32 txbd_reg;
|
|
do {
|
/* connect with halmac */
|
tx_dma_ch = ACH0_QUEUE_IDX_8852BE + ch_idx;
|
txbd_reg = _hal_get_bd_idx_reg_8852be(tx_dma_ch);
|
if (0xFFFF == txbd_reg)
|
break;
|
PHL_TRACE(COMP_PHL_XMIT, _PHL_DEBUG_,
|
"hal_trigger_txdma_8852be => dma_ch %d, host_idx %d.\n",
|
ch_idx, txbd_ring[ch_idx].host_idx);
|
hal_write16(hal->hal_com, txbd_reg, txbd_ring[ch_idx].host_idx);
|
hstatus = RTW_HAL_STATUS_SUCCESS;
|
} while (false);
|
|
return hstatus;
|
}
|
|
|
static enum rtw_hal_status hal_pltfm_tx_8852be(void *hal, struct rtw_h2c_pkt *h2c_pkt)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
|
#if 0
|
|
struct hal_info_t *hal_info = (struct hal_info_t *)hal;
|
struct rtw_wd_page wd_page;
|
struct tx_base_desc *txbd_ring = NULL;
|
|
_os_mem_set(hal_to_drvpriv(hal_info), &wd_page, 0, sizeof(wd_page));
|
|
txbd_ring = (struct tx_base_desc *)hal_info->hal_com->fw_txbd;
|
wd_page.vir_addr = h2c_pkt->vir_addr;
|
wd_page.phy_addr_l = h2c_pkt->phy_addr_l;
|
wd_page.phy_addr_h= h2c_pkt->phy_addr_h;
|
wd_page.buf_len = h2c_pkt->buf_len;
|
wd_page.cache = 1;
|
|
_os_spinlock(hal_to_drvpriv(hal_info), &txbd_ring[FWCMD_QUEUE_IDX_8852BE].txbd_lock, _ps, NULL);
|
hstatus = hal_update_txbd_8852BE(hal_info, txbd_ring, &wd_page,
|
FWCMD_QUEUE_IDX_8852BE, 1);
|
_os_spinunlock(hal_to_drvpriv(hal_info), &txbd_ring[FWCMD_QUEUE_IDX_8852BE].txbd_lock, _ps, NULL);
|
|
/* enqueue busy queue */
|
|
hstatus = hal_trigger_txdma_8852BE(hal_info, txbd_ring, FWCMD_QUEUE_IDX_8852BE);
|
#endif
|
return hstatus;
|
}
|
|
u8 hal_get_fwcmd_queue_idx_8852be(void)
|
{
|
return FWCMD_QUEUE_IDX_8852BE;
|
}
|
|
static u8 hal_check_rxrdy_8852be(struct rtw_phl_com_t *phl_com,
|
struct rtw_rx_buf *rx_buf,
|
u8 ch_idx)
|
{
|
u8 *rxbd_info = rx_buf->vir_addr;
|
u8 res = false;
|
struct hal_spec_t *hal_spec = &phl_com->hal_spec;
|
u16 tag = 0, target_tag = 0;
|
int read_cnt = 0;
|
#ifdef PHL_DMA_NONCOHERENT
|
u8 cache = rx_buf->cache;
|
void *drv_priv = phl_com->drv_priv;
|
#endif /* PHL_DMA_NONCOHERENT */
|
|
if (rxbd_info == NULL) {
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
|
"[WARNING] input rx bd info is NULL!\n");
|
return false;
|
}
|
|
if (hal_spec->rx_tag[ch_idx] == 0x1fff)
|
target_tag = 1;
|
else
|
target_tag = hal_spec->rx_tag[ch_idx] + 1;
|
|
#if defined(PHL_DMA_NONCOHERENT) \
|
&& defined(HAL_TO_NONCACHE_ADDR)
|
/* Use non-cache address to polling RXBD info if available */
|
if (cache == CACHE_ADDR)
|
rxbd_info = (u8 *)HAL_TO_NONCACHE_ADDR(rxbd_info);
|
#endif /* HAL_TO_NONCACHE_ADDR */
|
|
while (read_cnt < RX_TAG_POLLING_TIMES) {
|
u32 rxbd_info_32;
|
|
/* Invalidate cache for RXBD info before polling
|
* RX tag from it if required */
|
#if defined(PHL_DMA_NONCOHERENT) \
|
&& !defined(HAL_TO_NONCACHE_ADDR)
|
if (cache == CACHE_ADDR) {
|
_os_cache_inv(drv_priv,
|
&rx_buf->phy_addr_l,
|
&rx_buf->phy_addr_h,
|
hal_spec->rx_bd_info_sz,
|
DMA_FROM_DEVICE);
|
}
|
#endif /* PHL_DMA_NONCOHERENT */
|
|
rxbd_info_32 = le32_to_cpu(*(volatile u32 *)rxbd_info);
|
|
read_cnt++;
|
/* tag: RXBD_INFO[28:16] */
|
tag = (u16)((rxbd_info_32 >> 16) & 0x1FFF);
|
|
if (tag == target_tag) {
|
res = true;
|
break;
|
}
|
}
|
|
if (true == res) {
|
hal_spec->rx_tag[ch_idx] = tag;
|
} else {
|
PHL_TRACE_LMT(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING] polling Rx Tag fail, tag = %d, target_tag = %d\n",
|
tag, target_tag);
|
}
|
|
/* RX ready. Ensure cache is cleared for RX payload. */
|
#if defined(PHL_DMA_NONCOHERENT)
|
/* ToDo: Add $ clear flag to prevent from unecessary $ clear as
|
fresh mapped RX buffer should be $ chean. For now, considering
|
RX buffer recycle, $ is always cleared for RX DMA length
|
right after RX ready to minimize $ clear cost. */
|
if ((res == true) && cache == CACHE_ADDR) {
|
u16 pld_size = (u16)GET_RX_BD_INFO_HW_W_SIZE(rxbd_info);
|
|
if (pld_size != 0)
|
_os_cache_inv(drv_priv,
|
&rx_buf->phy_addr_l,
|
&rx_buf->phy_addr_h,
|
pld_size,
|
DMA_FROM_DEVICE);
|
else
|
PHL_ERR("RX zero length payload.\n");
|
}
|
#endif /* PHL_DMA_NONCOHERENT */
|
|
return res;
|
}
|
|
|
u16 hal_handle_rx_report_8852be(struct hal_info_t *hal, u8 *rp, u16 len,
|
u8 *sw_retry, u8 *dma_ch, u16 *wp_seq,
|
u8 *macid, u8 *ac_queue, u8 *txsts)
|
{
|
u8 polluted = false;
|
u16 rsize = 0;
|
u8 tid = 0, qsel_value = 0, band = 0, tid_indic = 0;
|
|
do {
|
if (len < RX_RP_PACKET_SIZE)
|
break;
|
|
*macid = (u8)GET_RX_RP_PKT_MAC_ID(rp);
|
qsel_value = (u8)GET_RX_RP_PKT_QSEL(rp);
|
*ac_queue = qsel_value % RTW_MAX_AC_QUEUE_NUM;
|
*txsts = (u8)GET_RX_RP_PKT_TX_STS(rp);
|
*wp_seq = (u16)GET_RX_RP_PKT_PCIE_SEQ(rp);
|
polluted = (u8)GET_RX_RP_PKT_POLLUTED(rp);
|
|
|
band = (qsel_value & BIT3) ? 1 : 0;
|
tid_indic = (*wp_seq & WP_TID_INDIC_RESERVED_BIT) ? 1 : 0;
|
*wp_seq &= (WP_RESERVED_SEQ);
|
tid = hal_qsel_to_tid_8852be(hal, qsel_value, tid_indic);
|
*dma_ch = hal_mapping_hw_tx_chnl_8852be(hal, *macid, tid, band);
|
|
PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "Get recycle report: qsel = %d, macid = %d, wp_seq = 0x%x, tid_indic = %d,"
|
" tid = %d, band = %d, dma_ch = %d\n",
|
qsel_value, *macid, *wp_seq, tid_indic, tid, band, *dma_ch);
|
|
if (TX_STATUS_TX_DONE != *txsts) {
|
*sw_retry = true;
|
/* hana_todo handle sw retry */
|
} else if (true == polluted) {
|
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "this wp is polluted\n");
|
*sw_retry = true;
|
/* hana_todo handle sw retry */
|
} else {
|
*sw_retry = false;
|
}
|
|
rsize = RX_RP_PACKET_SIZE;
|
} while (false);
|
|
return rsize;
|
}
|
|
|
/**
|
* Process Rx PPDU Status with HALMAC API and PHYDM API
|
*/
|
static enum rtw_hal_status
|
hal_handle_ppdusts_8852be(void *hal, u8 *psbuf, u16 sz,
|
struct rtw_r_meta_data *mdata, struct rx_ppdu_status *rxps)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
|
|
if (mdata->mac_info_vld) {
|
/*Call HALMAC API HALMAC API*/
|
rxps->mac_info_length = 4; //To DO
|
}
|
|
rxps->phy_info_length = sz - rxps->mac_info_length;
|
if (rxps->phy_info_length > 0) {
|
/* the remaining length > 4 the phy info is valid */
|
/* CALL PHYDM API Here*/
|
//rx_desc->mac_id
|
|
}
|
hstatus = RTW_HAL_STATUS_SUCCESS;
|
return hstatus;
|
}
|
|
/**
|
* SW Parsing Rx Desc
|
**/
|
static enum rtw_hal_status
|
_hal_parsing_rx_wd_8852be(struct hal_info_t *hal, u8 *desc,
|
struct rtw_r_meta_data *mdata)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
|
|
mdata->pktlen = GET_RX_AX_DESC_PKT_LEN_8852B(desc);
|
mdata->shift = GET_RX_AX_DESC_SHIFT_8852B(desc);
|
mdata->wl_hd_iv_len = GET_RX_AX_DESC_HDR_IV_L_8852B(desc);
|
mdata->bb_sel = GET_RX_AX_DESC_BB_SEL_8852B(desc);
|
mdata->mac_info_vld = GET_RX_AX_DESC_MAC_INFO_VLD_8852B(desc);
|
mdata->rpkt_type = GET_RX_AX_DESC_RPKT_TYPE_8852B(desc);
|
mdata->drv_info_size = GET_RX_AX_DESC_DRV_INFO_SIZE_8852B(desc);
|
mdata->long_rxd = GET_RX_AX_DESC_LONG_RXD_8852B(desc);
|
|
mdata->ppdu_type = GET_RX_AX_DESC_PPDU_TYPE_8852B(desc);
|
mdata->ppdu_cnt = GET_RX_AX_DESC_PPDU_CNT_8852B(desc);
|
mdata->sr_en = GET_RX_AX_DESC_SR_EN_8852B(desc);
|
mdata->user_id = GET_RX_AX_DESC_USER_ID_8852B(desc);
|
mdata->rx_rate = GET_RX_AX_DESC_RX_DATARATE_8852B(desc);
|
mdata->rx_gi_ltf = GET_RX_AX_DESC_RX_GI_LTF_8852B(desc);
|
mdata->non_srg_ppdu = GET_RX_AX_DESC_NON_SRG_PPDU_8852B(desc);
|
mdata->inter_ppdu = GET_RX_AX_DESC_INTER_PPDU_8852B(desc);
|
mdata->bw = GET_RX_AX_DESC_BW_8852B(desc);
|
|
mdata->freerun_cnt = GET_RX_AX_DESC_FREERUN_CNT_8852B(desc);
|
|
mdata->a1_match = GET_RX_AX_DESC_A1_MATCH_8852B(desc);
|
mdata->sw_dec = GET_RX_AX_DESC_SW_DEC_8852B(desc);
|
mdata->hw_dec = GET_RX_AX_DESC_HW_DEC_8852B(desc);
|
mdata->ampdu = GET_RX_AX_DESC_AMPDU_8852B(desc);
|
mdata->ampdu_end_pkt = GET_RX_AX_DESC_AMPDU_EDN_PKT_8852B(desc);
|
mdata->amsdu = GET_RX_AX_DESC_AMSDU_8852B(desc);
|
mdata->amsdu_cut = GET_RX_AX_DESC_AMSDU_CUT_8852B(desc);
|
mdata->last_msdu = GET_RX_AX_DESC_LAST_MSDU_8852B(desc);
|
mdata->bypass = GET_RX_AX_DESC_BYPASS_8852B(desc);
|
mdata->crc32 = GET_RX_AX_DESC_CRC32_8852B(desc);
|
mdata->icverr = GET_RX_AX_DESC_ICVERR_8852B(desc);
|
mdata->magic_wake = GET_RX_AX_DESC_MAGIC_WAKE_8852B(desc);
|
mdata->unicast_wake = GET_RX_AX_DESC_UNICAST_WAKE_8852B(desc);
|
mdata->pattern_wake = GET_RX_AX_DESC_PATTERN_WAKE_8852B(desc);
|
|
if (mdata->long_rxd==1) {
|
mdata->macid = GET_RX_AX_DESC_MACID_8852B(desc);
|
}
|
|
hstatus = RTW_HAL_STATUS_SUCCESS;
|
return hstatus;
|
}
|
|
static u8 hal_handle_rxbd_info_8852be(struct hal_info_t *hal,
|
u8 *rxbd_info, u16 *size)
|
{
|
u8 res = false;
|
u16 pld_size = 0;
|
u8 fs = 0, ls = 0;
|
u8 pkt_rdy = false;
|
|
do {
|
if (NULL == rxbd_info)
|
break;
|
if (NULL == size)
|
break;
|
|
fs = (u8)GET_RX_BD_INFO_FS(rxbd_info);
|
ls = (u8)GET_RX_BD_INFO_LS(rxbd_info);
|
pld_size = (u16)GET_RX_BD_INFO_HW_W_SIZE(rxbd_info);
|
|
if (fs == 1) {
|
if (ls == 1)
|
pkt_rdy = true;
|
else
|
pkt_rdy = false;
|
|
} else if (fs == 0) {
|
if (ls == 1)
|
pkt_rdy = false;
|
else
|
pkt_rdy = false;
|
}
|
|
if (pkt_rdy) {
|
*size = pld_size;
|
res = true;
|
} else {
|
*size = 0;
|
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "[WARNING] need to handle RX FS/LS\n");
|
res = false;
|
}
|
}while(false);
|
return res;
|
}
|
|
|
|
/**
|
* the function update rxbd
|
*/
|
static enum rtw_hal_status
|
hal_update_rxbd_8852be(struct hal_info_t *hal, struct rx_base_desc *rxbd,
|
struct rtw_rx_buf *rx_buf, u8 ch_idx)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
|
struct rtw_hal_com_t *hal_com = hal->hal_com;
|
struct bus_hw_cap_t *bus_hw_cap = &hal_com->bus_hw_cap;
|
u8 *ring_head = NULL;
|
u8 *target_rxbd = NULL;
|
u16 rxbd_num = hal_get_rxbd_num_8852be(hal_com, ch_idx);
|
|
do {
|
if (NULL == rxbd)
|
break;
|
if (NULL == rx_buf)
|
break;
|
|
ring_head = rxbd->vir_addr;
|
target_rxbd = ring_head + (rxbd->host_idx *
|
bus_hw_cap->rxbd_len);
|
/* connect with halmac */
|
SET_RX_BD_RXBUFFSIZE(target_rxbd, rx_buf->buf_len);
|
SET_RX_BD_PHYSICAL_ADDR_LOW(target_rxbd,
|
(u32)rx_buf->phy_addr_l);
|
SET_RX_BD_PHYSICAL_ADDR_HIGH(target_rxbd,
|
(u32)rx_buf->phy_addr_h);
|
rxbd->host_idx = (rxbd->host_idx + 1) % rxbd_num;
|
} while (false);
|
|
return hstatus;
|
}
|
|
|
/**
|
* the function notify rx done
|
*/
|
static enum rtw_hal_status
|
hal_notify_rxdone_8852be(struct hal_info_t *hal,
|
struct rx_base_desc *rxbd, u8 ch, u16 rxcnt)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
|
u32 reg = 0;
|
u8 rx_dma_ch = 0;
|
|
do {
|
rx_dma_ch = RX_QUEUE_IDX_8852BE + ch;
|
reg = _hal_get_bd_idx_reg_8852be(rx_dma_ch);
|
/* connect with halmac */
|
if (0xFFFF == reg)
|
break;
|
hal_write16(hal->hal_com, reg, rxbd->host_idx);
|
hstatus = RTW_HAL_STATUS_SUCCESS;
|
} while (false);
|
|
return hstatus;
|
}
|
|
|
struct bd_ram bdram_table_8852b[] = {
|
/* ACH0_QUEUE_IDX_8852BE */ {0, 25, 4},
|
/* ACH1_QUEUE_IDX_8852BE */ {25, 25, 4},
|
/* ACH2_QUEUE_IDX_8852BE */ {50, 25, 4},
|
/* ACH3_QUEUE_IDX_8852BE */ {75, 25, 4},
|
/* ACH4_QUEUE_IDX_8852BE */ {100, 25, 4},
|
/* ACH5_QUEUE_IDX_8852BE */ {125, 25, 4},
|
/* ACH6_QUEUE_IDX_8852BE */ {150, 25, 4},
|
/* ACH7_QUEUE_IDX_8852BE */ {175, 25, 4},
|
/* MGQ_B0_QUEUE_IDX_8852BE */ {185, 10, 4},
|
/* HIQ_B0_QUEUE_IDX_8852BE */ {195, 10, 4},
|
/* MGQ_B1_QUEUE_IDX_8852BE */ {205, 10, 4},
|
/* HIQ_B1_QUEUE_IDX_8852BE */ {215, 10, 4},
|
/* FWCMD_QUEUE_IDX_8852BE */ {225, 10, 4}
|
};
|
|
static void _hal_tx_init_bd_ram_8852be(struct hal_info_t *hal)
|
{
|
u32 reg = 0;
|
u32 value = 0;
|
u8 i = 0;
|
|
for (i = 0; i < TX_DMA_CHANNEL_ENTRY_8852BE; i++) {
|
/*if (FWCMD_QUEUE_IDX_8852BE == i)
|
continue;*/
|
value = 0;
|
value = bdram_table_8852b[i].sidx +
|
((bdram_table_8852b[i].max << 8) & 0xFF00) +
|
((bdram_table_8852b[i].min << 16) & 0xFF0000);
|
|
reg = _hal_get_bd_ram_reg_8852be(i);
|
if (0 != reg)
|
hal_write32(hal->hal_com, reg, value);
|
else
|
PHL_ERR("query txbd num reg fail (ch_idx = %d)\n", i);
|
}
|
|
value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
|
value |= (B_AX_RST_BDRAM);
|
hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);
|
|
}
|
static void _hal_trx_init_bd_num_8852be(struct hal_info_t *hal)
|
{
|
struct rtw_hal_com_t *hal_com = hal->hal_com;
|
u16 txbd_num = hal_com->bus_cap.txbd_num;
|
u16 rxbd_num = 0;
|
u32 reg = 0;
|
u16 value = 0;
|
u8 i = 0, ch_idx = 0;
|
|
for (i = 0; i < TX_DMA_CHANNEL_ENTRY_8852BE; i++) {
|
/*if (FWCMD_QUEUE_IDX_8852BE == i)
|
continue;*/
|
|
value = txbd_num & B_AX_DESC_NUM_MSK;
|
|
reg = _hal_get_bd_num_reg_8852be(i);
|
if (0 != reg)
|
hal_write16(hal->hal_com, reg, value);
|
else
|
PHL_ERR("query txbd num reg fail (ch_idx = %d)\n", i);
|
}
|
|
for (i = RX_QUEUE_IDX_8852BE;
|
i < RX_QUEUE_IDX_8852BE + RX_DMA_CHANNEL_ENTRY_8852BE; i++) {
|
/*if (FWCMD_QUEUE_IDX_8852BE == i)
|
continue;*/
|
|
ch_idx = (u8)(i - RX_QUEUE_IDX_8852BE);
|
rxbd_num = hal_get_rxbd_num_8852be(hal_com, ch_idx);
|
|
value = rxbd_num & B_AX_DESC_NUM_MSK;
|
|
reg = _hal_get_bd_num_reg_8852be(i);
|
if (0 != reg)
|
hal_write16(hal->hal_com, reg, value);
|
else
|
PHL_ERR("query rxbd num reg fail (ch_idx = %d)\n", i);
|
}
|
}
|
|
|
static void _hal_trx_init_bd_8852be(struct hal_info_t *hal, u8 *txbd_buf, u8 *rxbd_buf)
|
{
|
struct tx_base_desc *txbd = NULL;
|
struct rx_base_desc *rxbd = NULL;
|
u32 reg_addr_l = 0, reg_addr_h = 0;
|
u8 i = 0, rxch_idx = 0;
|
|
if (NULL != txbd_buf && NULL != rxbd_buf) {
|
txbd = (struct tx_base_desc *)txbd_buf;
|
rxbd = (struct rx_base_desc *)rxbd_buf;
|
|
for (i = 0; i < TX_DMA_CHANNEL_ENTRY_8852BE; i++) {
|
/*if (FWCMD_QUEUE_IDX_8852BE == i)
|
continue;*/
|
|
_hal_get_bd_desc_reg_8852be(i, ®_addr_l, ®_addr_h);
|
if (0 != reg_addr_l)
|
hal_write32(hal->hal_com, reg_addr_l, txbd[i].phy_addr_l);
|
else
|
PHL_ERR("query txbd desc reg_addr_l fail (ch_idx = %d)\n", i);
|
|
if (0 != reg_addr_h)
|
hal_write32(hal->hal_com, reg_addr_h, txbd[i].phy_addr_h);
|
else
|
PHL_ERR("query txbd desc reg_addr_h fail (ch_idx = %d)\n", i);
|
}
|
|
for (i = 0; i < RX_DMA_CHANNEL_ENTRY_8852BE; i++) {
|
rxch_idx = i + RX_QUEUE_IDX_8852BE;
|
_hal_get_bd_desc_reg_8852be(rxch_idx, ®_addr_l, ®_addr_h);
|
if (0 != reg_addr_l)
|
hal_write32(hal->hal_com, reg_addr_l, rxbd[i].phy_addr_l);
|
else
|
PHL_ERR("query rxbd desc reg_addr_l fail (ch_idx = %d)\n", i);
|
if (0 != reg_addr_h)
|
hal_write32(hal->hal_com, reg_addr_h, rxbd[i].phy_addr_h);
|
else
|
PHL_ERR("query rxbd desc reg_addr_h fail (ch_idx = %d)\n", i);
|
}
|
|
}
|
}
|
|
static void _hal_tx_enable_truncate_mode(struct hal_info_t *hal, u8 *txbd_buf,
|
u8 *rxbd_buf)
|
{
|
struct tx_base_desc *txbd = NULL;
|
struct rx_base_desc *rxbd = NULL;
|
u32 value = 0;
|
|
txbd = (struct tx_base_desc *)txbd_buf;
|
rxbd = (struct rx_base_desc *)rxbd_buf;
|
|
value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
|
value |= (B_AX_TX_TRUNC_MODE | B_AX_RX_TRUNC_MODE);
|
hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);
|
|
hal_write32(hal->hal_com, R_AX_TXDMA_ADDR_H, txbd->phy_addr_h);
|
hal_write32(hal->hal_com, R_AX_RXDMA_ADDR_H, rxbd->phy_addr_h);
|
}
|
|
static void _hal_tx_disable_truncate_mode(struct hal_info_t *hal)
|
{
|
u32 value = 0;
|
|
value = hal_read32(hal->hal_com, R_AX_TX_ADDRESS_INFO_MODE_SETTING);
|
value &= ~(B_AX_HOST_ADDR_INFO_8B_SEL);
|
hal_write32(hal->hal_com, R_AX_TX_ADDRESS_INFO_MODE_SETTING, value);
|
|
value = hal_read32(hal->hal_com, R_AX_PKTIN_SETTING);
|
value |= (B_AX_WD_ADDR_INFO_LENGTH);
|
hal_write32(hal->hal_com, R_AX_PKTIN_SETTING, value);
|
}
|
|
|
static void _hal_select_rxbd_mode(struct hal_info_t *hal,
|
enum rxbd_mode_8852BE mode)
|
{
|
u32 value = 0;
|
|
if (RXBD_MODE_PACKET == mode) {
|
value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
|
value &= ~(B_AX_RXBD_MODE);
|
hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);
|
} else if (RXBD_MODE_SEPARATION == mode) {
|
/*
|
value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
|
value |= (B_AX_RXBD_MODE);
|
hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);
|
*/
|
/* hana_todo, append length setting */
|
} else {
|
PHL_WARN("Unknown Rx BD mode (%d)\n", mode);
|
}
|
}
|
|
static void _hal_clear_trx_state(struct hal_info_t *hal)
|
{
|
u32 value = 0;
|
|
/* disable hci */
|
value = hal_read32(hal->hal_com, R_AX_PCIE_INIT_CFG1);
|
value &= ~(B_AX_RXHCI_EN | B_AX_TXHCI_EN);
|
hal_write32(hal->hal_com, R_AX_PCIE_INIT_CFG1, value);
|
|
/* check mac power on status */
|
|
/* clear hci idx */
|
value = hal_read32(hal->hal_com, R_AX_TXBD_RWPTR_CLR1);
|
value |= (B_AX_CLR_ACH0_IDX | B_AX_CLR_ACH1_IDX | B_AX_CLR_ACH2_IDX |
|
B_AX_CLR_ACH3_IDX | B_AX_CLR_ACH4_IDX | B_AX_CLR_ACH5_IDX |
|
B_AX_CLR_ACH6_IDX | B_AX_CLR_ACH7_IDX | B_AX_CLR_CH8_IDX |
|
B_AX_CLR_CH9_IDX | B_AX_CLR_CH12_IDX);
|
hal_write32(hal->hal_com, R_AX_TXBD_RWPTR_CLR1, value);
|
|
value = hal_read32(hal->hal_com, R_AX_TXBD_RWPTR_CLR2);
|
value |= (B_AX_CLR_CH10_IDX | B_AX_CLR_CH11_IDX);
|
hal_write32(hal->hal_com, R_AX_TXBD_RWPTR_CLR2, value);
|
|
value = hal_read32(hal->hal_com, R_AX_RXBD_RWPTR_CLR);
|
value |= (B_AX_CLR_RXQ_IDX | B_AX_CLR_RPQ_IDX);
|
hal_write32(hal->hal_com, R_AX_RXBD_RWPTR_CLR, value);
|
}
|
|
/**
|
* the function will deinitializing 8852BE specific data and hw configuration
|
*/
|
static void hal_trx_deinit_8852be(struct hal_info_t *hal)
|
{
|
/*struct rtw_hal_com_t *hal_com = hal->hal_com;*/
|
}
|
|
/**
|
* the function will initializing 8852BE specific data and hw configuration
|
*/
|
static enum rtw_hal_status hal_trx_init_8852be(struct hal_info_t *hal, u8 *txbd_buf, u8 *rxbd_buf)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
|
/* Set AMPDU max agg number to 128 */
|
/* CR setting*/
|
rtw_hal_mac_set_hw_ampdu_cfg(hal, 0, 0x80, 0xA0);
|
return hstatus;
|
}
|
|
static struct hal_trx_ops ops = {0};
|
void hal_trx_ops_init_8852be(void)
|
{
|
ops.init = hal_trx_init_8852be;
|
ops.deinit = hal_trx_deinit_8852be;
|
ops.query_tx_res = hal_get_avail_txbd_8852be;
|
ops.query_rx_res = hal_get_avail_rxbd_8852be;
|
ops.get_rxbd_num = hal_get_rxbd_num_8852be;
|
ops.get_rxbuf_num = hal_get_rxbuf_num_8852be;
|
ops.get_rxbuf_size = hal_get_rxbuf_size_8852be;
|
ops.map_hw_tx_chnl = hal_mapping_hw_tx_chnl_8852be;
|
ops.qsel_to_tid = hal_qsel_to_tid_8852be;
|
ops.query_txch_hwband = hal_query_txch_hwband_8852be;
|
ops.query_txch_map = hal_query_txch_map_8852be;
|
ops.query_txch_num = hal_query_txch_num_8852be;
|
ops.query_rxch_num = hal_query_rxch_num_8852be;
|
ops.update_wd = hal_update_wd_8852be;
|
ops.update_txbd = hal_update_txbd_8852be;
|
ops.tx_start = hal_trigger_txdma_8852be;
|
ops.check_rxrdy = hal_check_rxrdy_8852be;
|
ops.handle_rxbd_info = hal_handle_rxbd_info_8852be;
|
ops.handle_rx_buffer = hal_handle_rx_buffer_8852b;
|
ops.update_rxbd = hal_update_rxbd_8852be;
|
ops.notify_rxdone = hal_notify_rxdone_8852be;
|
ops.handle_wp_rpt = hal_handle_rx_report_8852be;
|
ops.get_fwcmd_queue_idx = hal_get_fwcmd_queue_idx_8852be;
|
}
|
|
|
|
u32 hal_hook_trx_ops_8852be(struct rtw_phl_com_t *phl_com,
|
struct hal_info_t *hal_info)
|
{
|
enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
|
|
if (NULL != hal_info) {
|
hal_trx_ops_init_8852be();
|
hal_info->trx_ops = &ops;
|
hstatus = RTW_HAL_STATUS_SUCCESS;
|
}
|
|
return hstatus;
|
}
|