mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
wifi: rtw89: read link_sta corresponding to the link
Tweak code to not always access sta->deflink directly. Instead, according to link_id, read target link_sta from sta->link[]. For now, rtwsta_link->link_id keeps 0. When driver starts to support MLO, the link_id will be assigned. Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20240916053158.47350-5-pkshih@realtek.com
This commit is contained in:
parent
89bac818bb
commit
04911c0fe8
|
|
@ -712,11 +712,21 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
|
|||
struct rtw89_addr_cam_entry *addr_cam =
|
||||
rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link);
|
||||
struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta_link);
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif_link->mac_addr;
|
||||
u8 sma_hash, tma_hash, addr_msk_start;
|
||||
u8 sma_start = 0;
|
||||
u8 tma_start = 0;
|
||||
u8 *tma = sta ? sta->addr : rtwvif_link->bssid;
|
||||
const u8 *tma;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (sta) {
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
tma = link_sta->addr;
|
||||
} else {
|
||||
tma = rtwvif_link->bssid;
|
||||
}
|
||||
|
||||
if (addr_cam->addr_mask != 0) {
|
||||
addr_msk_start = __ffs(addr_cam->addr_mask);
|
||||
|
|
@ -791,6 +801,8 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
|
|||
FWCMD_SET_ADDR_SEC_ENT4(cmd, addr_cam->sec_ent[4]);
|
||||
FWCMD_SET_ADDR_SEC_ENT5(cmd, addr_cam->sec_ent[5]);
|
||||
FWCMD_SET_ADDR_SEC_ENT6(cmd, addr_cam->sec_ent[6]);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev,
|
||||
|
|
|
|||
|
|
@ -7487,8 +7487,8 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
|
|||
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
|
||||
rtwvif_link->chanctx_idx);
|
||||
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif_link);
|
||||
struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta_link);
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct rtw89_btc *btc = &rtwdev->btc;
|
||||
const struct rtw89_btc_ver *ver = btc->ver;
|
||||
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
|
||||
|
|
@ -7514,19 +7514,21 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
|
|||
bss_conf->beacon_int, bss_conf->dtim_period);
|
||||
|
||||
if (rtwsta_link) {
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n",
|
||||
rtwsta_link->mac_id);
|
||||
|
||||
rtw89_debug(rtwdev, RTW89_DBG_BTC,
|
||||
"[BTC], STA support HE=%d VHT=%d HT=%d\n",
|
||||
sta->deflink.he_cap.has_he,
|
||||
sta->deflink.vht_cap.vht_supported,
|
||||
sta->deflink.ht_cap.ht_supported);
|
||||
if (sta->deflink.he_cap.has_he)
|
||||
link_sta->he_cap.has_he,
|
||||
link_sta->vht_cap.vht_supported,
|
||||
link_sta->ht_cap.ht_supported);
|
||||
if (link_sta->he_cap.has_he)
|
||||
mode |= BIT(BTC_WL_MODE_HE);
|
||||
if (sta->deflink.vht_cap.vht_supported)
|
||||
if (link_sta->vht_cap.vht_supported)
|
||||
mode |= BIT(BTC_WL_MODE_VHT);
|
||||
if (sta->deflink.ht_cap.ht_supported)
|
||||
if (link_sta->ht_cap.ht_supported)
|
||||
mode |= BIT(BTC_WL_MODE_HT);
|
||||
|
||||
r.mode = mode;
|
||||
|
|
|
|||
|
|
@ -465,6 +465,7 @@ rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev,
|
|||
{
|
||||
struct ieee80211_sta *sta = tx_req->sta;
|
||||
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct sk_buff *skb = tx_req->skb;
|
||||
struct rtw89_sta_link *rtwsta_link;
|
||||
u8 ampdu_num;
|
||||
|
|
@ -486,13 +487,18 @@ rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev,
|
|||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
|
||||
ampdu_num = (u8)((rtwsta_link->ampdu_params[tid].agg_num ?
|
||||
rtwsta_link->ampdu_params[tid].agg_num :
|
||||
4 << sta->deflink.ht_cap.ampdu_factor) - 1);
|
||||
4 << link_sta->ht_cap.ampdu_factor) - 1);
|
||||
|
||||
desc_info->agg_en = true;
|
||||
desc_info->ampdu_density = sta->deflink.ht_cap.ampdu_density;
|
||||
desc_info->ampdu_density = link_sta->ht_cap.ampdu_density;
|
||||
desc_info->ampdu_num = ampdu_num;
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -721,15 +727,26 @@ __rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev,
|
|||
struct rtw89_sta_link *rtwsta_link = sta_to_rtwsta_safe(sta);
|
||||
struct sk_buff *skb = tx_req->skb;
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
__le16 fc = hdr->frame_control;
|
||||
|
||||
/* AP IOT issue with EAPoL, ARP and DHCP */
|
||||
if (pkt_type < PACKET_MAX)
|
||||
return false;
|
||||
|
||||
if (!sta || !sta->deflink.he_cap.has_he)
|
||||
if (!rtwsta_link)
|
||||
return false;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
|
||||
if (!link_sta->he_cap.has_he) {
|
||||
rcu_read_unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!ieee80211_is_data_qos(fc))
|
||||
return false;
|
||||
|
||||
|
|
@ -802,10 +819,13 @@ static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev,
|
|||
struct ieee80211_vif *vif = tx_req->vif;
|
||||
struct ieee80211_sta *sta = tx_req->sta;
|
||||
struct rtw89_vif_link *rtwvif_link = (struct rtw89_vif_link *)vif->drv_priv;
|
||||
struct rtw89_sta_link *rtwsta_link = sta_to_rtwsta_safe(sta);
|
||||
struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern;
|
||||
enum rtw89_chanctx_idx idx = rtwvif_link->chanctx_idx;
|
||||
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, idx);
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u16 lowest_rate;
|
||||
u16 rate;
|
||||
|
||||
if (rate_pattern->enable)
|
||||
return rate_pattern->rate;
|
||||
|
|
@ -817,10 +837,23 @@ static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev,
|
|||
else
|
||||
lowest_rate = RTW89_HW_RATE_OFDM6;
|
||||
|
||||
if (!sta || !sta->deflink.supp_rates[chan->band_type])
|
||||
if (!rtwsta_link)
|
||||
return lowest_rate;
|
||||
|
||||
return __ffs(sta->deflink.supp_rates[chan->band_type]) + lowest_rate;
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
|
||||
if (!link_sta->supp_rates[chan->band_type]) {
|
||||
rate = lowest_rate;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rate = __ffs(link_sta->supp_rates[chan->band_type]) + lowest_rate;
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -3645,12 +3678,20 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
|
|||
|
||||
if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
|
||||
if (sta->tdls) {
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif_link, bssid_cam,
|
||||
sta->addr);
|
||||
link_sta->addr);
|
||||
if (ret) {
|
||||
rtw89_warn(rtwdev, "failed to send h2c init bssid cam for TDLS\n");
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
ret = rtw89_cam_init_addr_cam(rtwdev, &rtwsta_link->addr_cam, bssid_cam);
|
||||
|
|
|
|||
|
|
@ -3355,6 +3355,8 @@ struct rtw89_sec_cam_entry {
|
|||
};
|
||||
|
||||
struct rtw89_sta_link {
|
||||
unsigned int link_id;
|
||||
|
||||
u8 mac_id;
|
||||
bool disassoc;
|
||||
bool er_cap;
|
||||
|
|
@ -6027,6 +6029,36 @@ __rtw89_vif_rcu_dereference_link(struct rtw89_vif_link *rtwvif_link, bool *nolin
|
|||
bss_conf; \
|
||||
})
|
||||
|
||||
static inline struct ieee80211_link_sta *
|
||||
__rtw89_sta_rcu_dereference_link(struct rtw89_sta_link *rtwsta_link, bool *nolink)
|
||||
{
|
||||
struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta_link);
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
|
||||
link_sta = rcu_dereference(sta->link[rtwsta_link->link_id]);
|
||||
if (unlikely(!link_sta)) {
|
||||
*nolink = true;
|
||||
return &sta->deflink;
|
||||
}
|
||||
|
||||
*nolink = false;
|
||||
return link_sta;
|
||||
}
|
||||
|
||||
#define rtw89_sta_rcu_dereference_link(rtwsta_link, assert) \
|
||||
({ \
|
||||
typeof(rtwsta_link) p = rtwsta_link; \
|
||||
struct ieee80211_link_sta *link_sta; \
|
||||
bool nolink; \
|
||||
\
|
||||
link_sta = __rtw89_sta_rcu_dereference_link(p, &nolink); \
|
||||
if (unlikely(nolink) && (assert)) \
|
||||
rtw89_err(p->rtwdev, \
|
||||
"%s: cannot find exact link_sta for link_id %u\n",\
|
||||
__func__, p->link_id); \
|
||||
link_sta; \
|
||||
})
|
||||
|
||||
static inline u8 rtw89_hw_to_rate_info_bw(enum rtw89_bandwidth hw_bw)
|
||||
{
|
||||
if (hw_bw == RTW89_CHANNEL_WIDTH_160)
|
||||
|
|
@ -6498,13 +6530,14 @@ static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
|
|||
return hdr->addr3;
|
||||
}
|
||||
|
||||
static inline bool rtw89_sta_has_beamformer_cap(struct ieee80211_sta *sta)
|
||||
static inline
|
||||
bool rtw89_sta_has_beamformer_cap(struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
|
||||
(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) ||
|
||||
(sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] &
|
||||
if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
|
||||
(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) ||
|
||||
(link_sta->he_cap.he_cap_elem.phy_cap_info[3] &
|
||||
IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) ||
|
||||
(sta->deflink.he_cap.he_cap_elem.phy_cap_info[4] &
|
||||
(link_sta->he_cap.he_cap_elem.phy_cap_info[4] &
|
||||
IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER))
|
||||
return true;
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -3526,11 +3526,20 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
|
|||
struct rtw89_hal *hal = &rtwdev->hal;
|
||||
u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num;
|
||||
bool ant_asterisk = hal->tx_path_diversity || hal->ant_diversity;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u8 evm_min, evm_max, evm_1ss;
|
||||
u16 max_rc_amsdu_len;
|
||||
u8 rssi;
|
||||
u8 snr;
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
max_rc_amsdu_len = link_sta->agg.max_rc_amsdu_len;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
seq_printf(m, "TX rate [%d]: ", rtwsta_link->mac_id);
|
||||
|
||||
if (rate->flags & RATE_INFO_FLAGS_MCS)
|
||||
|
|
@ -3553,7 +3562,7 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
|
|||
seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(rate->bw));
|
||||
seq_printf(m, "\t(hw_rate=0x%x)", rtwsta_link->ra_report.hw_rate);
|
||||
seq_printf(m, "\t==> agg_wait=%d (%d)\n", rtwsta_link->max_agg_wait,
|
||||
sta->deflink.agg.max_rc_amsdu_len);
|
||||
max_rc_amsdu_len);
|
||||
|
||||
seq_printf(m, "RX rate [%d]: ", rtwsta_link->mac_id);
|
||||
|
||||
|
|
@ -3777,9 +3786,17 @@ static void rtw89_sta_ids_get_iter(void *data, struct ieee80211_sta *sta)
|
|||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
struct rtw89_dev *rtwdev = rtwsta_link->rtwdev;
|
||||
struct seq_file *m = (struct seq_file *)data;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
|
||||
seq_printf(m, "STA [%d] %pM %s\n", rtwsta_link->mac_id, sta->addr,
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
|
||||
seq_printf(m, "STA [%d] %pM %s\n", rtwsta_link->mac_id, link_sta->addr,
|
||||
sta->tdls ? "(TDLS)" : "");
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
rtw89_dump_addr_cam(m, rtwdev, &rtwsta_link->addr_cam);
|
||||
rtw89_dump_ba_cam(m, rtwsta_link);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2777,24 +2777,25 @@ int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev,
|
|||
EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7);
|
||||
|
||||
static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
|
||||
struct ieee80211_sta *sta, u8 *pads)
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
u8 *pads)
|
||||
{
|
||||
bool ppe_th;
|
||||
u8 ppe16, ppe8;
|
||||
u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
|
||||
u8 ppe_thres_hdr = sta->deflink.he_cap.ppe_thres[0];
|
||||
u8 nss = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1;
|
||||
u8 ppe_thres_hdr = link_sta->he_cap.ppe_thres[0];
|
||||
u8 ru_bitmap;
|
||||
u8 n, idx, sh;
|
||||
u16 ppe;
|
||||
int i;
|
||||
|
||||
ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
|
||||
sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]);
|
||||
link_sta->he_cap.he_cap_elem.phy_cap_info[6]);
|
||||
if (!ppe_th) {
|
||||
u8 pad;
|
||||
|
||||
pad = FIELD_GET(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK,
|
||||
sta->deflink.he_cap.he_cap_elem.phy_cap_info[9]);
|
||||
link_sta->he_cap.he_cap_elem.phy_cap_info[9]);
|
||||
|
||||
for (i = 0; i < RTW89_PPE_BW_NUM; i++)
|
||||
pads[i] = pad;
|
||||
|
|
@ -2816,7 +2817,7 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
|
|||
sh = n & 7;
|
||||
n += IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2;
|
||||
|
||||
ppe = le16_to_cpu(*((__le16 *)&sta->deflink.he_cap.ppe_thres[idx]));
|
||||
ppe = le16_to_cpu(*((__le16 *)&link_sta->he_cap.ppe_thres[idx]));
|
||||
ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
|
||||
sh += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
|
||||
ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
|
||||
|
|
@ -2839,6 +2840,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
|
|||
struct rtw89_vif_link *rtwvif_link = (struct rtw89_vif_link *)vif->drv_priv;
|
||||
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
|
||||
rtwvif_link->chanctx_idx);
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct sk_buff *skb;
|
||||
u8 pads[RTW89_PPE_BW_NUM];
|
||||
u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
|
||||
|
|
@ -2846,8 +2848,20 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
|
|||
int ret;
|
||||
|
||||
memset(pads, 0, sizeof(pads));
|
||||
if (sta && sta->deflink.he_cap.has_he)
|
||||
__get_sta_he_pkt_padding(rtwdev, sta, pads);
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (rtwsta_link)
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
|
||||
if (rtwsta_link && link_sta->he_cap.has_he)
|
||||
__get_sta_he_pkt_padding(rtwdev, link_sta, pads);
|
||||
|
||||
if (vif->p2p)
|
||||
lowest_rate = RTW89_HW_RATE_OFDM6;
|
||||
|
|
@ -2856,11 +2870,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
|
|||
else
|
||||
lowest_rate = RTW89_HW_RATE_OFDM6;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_put(skb, H2C_CMC_TBL_LEN);
|
||||
SET_CTRL_INFO_MACID(skb->data, mac_id);
|
||||
SET_CTRL_INFO_OPERATION(skb->data, 1);
|
||||
|
|
@ -2885,12 +2894,14 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
|
|||
SET_CMC_TBL_NOMINAL_PKT_PADDING80(skb->data, pads[RTW89_CHANNEL_WIDTH_80]);
|
||||
SET_CMC_TBL_NOMINAL_PKT_PADDING160(skb->data, pads[RTW89_CHANNEL_WIDTH_160]);
|
||||
}
|
||||
if (sta)
|
||||
if (rtwsta_link)
|
||||
SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(skb->data,
|
||||
sta->deflink.he_cap.has_he);
|
||||
link_sta->he_cap.has_he);
|
||||
if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE)
|
||||
SET_CMC_TBL_DATA_DCM(skb->data, 0);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
|
||||
H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
|
||||
chip->h2c_cctl_func_id, 0, 1,
|
||||
|
|
@ -2911,9 +2922,10 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
|
|||
EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl);
|
||||
|
||||
static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
|
||||
struct ieee80211_sta *sta, u8 *pads)
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
u8 *pads)
|
||||
{
|
||||
u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
|
||||
u8 nss = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1;
|
||||
u16 ppe_thres_hdr;
|
||||
u8 ppe16, ppe8;
|
||||
u8 n, idx, sh;
|
||||
|
|
@ -2922,12 +2934,12 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
|
|||
u16 ppe;
|
||||
int i;
|
||||
|
||||
ppe_th = !!u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5],
|
||||
ppe_th = !!u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5],
|
||||
IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT);
|
||||
if (!ppe_th) {
|
||||
u8 pad;
|
||||
|
||||
pad = u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5],
|
||||
pad = u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5],
|
||||
IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK);
|
||||
|
||||
for (i = 0; i < RTW89_PPE_BW_NUM; i++)
|
||||
|
|
@ -2936,7 +2948,7 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
|
|||
return;
|
||||
}
|
||||
|
||||
ppe_thres_hdr = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres);
|
||||
ppe_thres_hdr = get_unaligned_le16(link_sta->eht_cap.eht_ppe_thres);
|
||||
ru_bitmap = u16_get_bits(ppe_thres_hdr,
|
||||
IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK);
|
||||
n = hweight8(ru_bitmap);
|
||||
|
|
@ -2953,7 +2965,7 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
|
|||
sh = n & 7;
|
||||
n += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2;
|
||||
|
||||
ppe = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres + idx);
|
||||
ppe = get_unaligned_le16(link_sta->eht_cap.eht_ppe_thres + idx);
|
||||
ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
|
||||
sh += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE;
|
||||
ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
|
||||
|
|
@ -2977,6 +2989,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
|
|||
u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
|
||||
struct rtw89_h2c_cctlinfo_ud_g7 *h2c;
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u8 pads[RTW89_PPE_BW_NUM];
|
||||
u32 len = sizeof(*h2c);
|
||||
struct sk_buff *skb;
|
||||
|
|
@ -2984,12 +2997,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
|
|||
int ret;
|
||||
|
||||
memset(pads, 0, sizeof(pads));
|
||||
if (sta) {
|
||||
if (sta->deflink.eht_cap.has_eht)
|
||||
__get_sta_eht_pkt_padding(rtwdev, sta, pads);
|
||||
else if (sta->deflink.he_cap.has_he)
|
||||
__get_sta_he_pkt_padding(rtwdev, sta, pads);
|
||||
}
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
|
||||
if (!skb) {
|
||||
|
|
@ -3001,6 +3008,15 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
|
|||
|
||||
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
|
||||
|
||||
if (rtwsta_link) {
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
|
||||
if (link_sta->eht_cap.has_eht)
|
||||
__get_sta_eht_pkt_padding(rtwdev, link_sta, pads);
|
||||
else if (link_sta->he_cap.has_he)
|
||||
__get_sta_he_pkt_padding(rtwdev, link_sta, pads);
|
||||
}
|
||||
|
||||
if (vif->p2p)
|
||||
lowest_rate = RTW89_HW_RATE_OFDM6;
|
||||
else if (chan->band_type == RTW89_BAND_2G)
|
||||
|
|
@ -3064,8 +3080,8 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
|
|||
CCTLINFO_G7_W6_ULDL);
|
||||
h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ULDL);
|
||||
|
||||
if (sta) {
|
||||
h2c->w8 = le32_encode_bits(sta->deflink.he_cap.has_he,
|
||||
if (rtwsta_link) {
|
||||
h2c->w8 = le32_encode_bits(link_sta->he_cap.has_he,
|
||||
CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT);
|
||||
h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT);
|
||||
}
|
||||
|
|
@ -3454,23 +3470,27 @@ static enum rtw89_fw_sta_type
|
|||
rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
|
||||
struct rtw89_sta_link *rtwsta_link)
|
||||
{
|
||||
struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta_link);
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
enum rtw89_fw_sta_type type;
|
||||
|
||||
if (!sta)
|
||||
goto by_vif;
|
||||
|
||||
if (sta->deflink.eht_cap.has_eht)
|
||||
return RTW89_FW_BE_STA;
|
||||
else if (sta->deflink.he_cap.has_he)
|
||||
return RTW89_FW_AX_STA;
|
||||
else
|
||||
return RTW89_FW_N_AC_STA;
|
||||
|
||||
by_vif:
|
||||
rcu_read_lock();
|
||||
|
||||
if (!rtwsta_link)
|
||||
goto by_vif;
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
|
||||
if (link_sta->eht_cap.has_eht)
|
||||
type = RTW89_FW_BE_STA;
|
||||
else if (link_sta->he_cap.has_he)
|
||||
type = RTW89_FW_AX_STA;
|
||||
else
|
||||
type = RTW89_FW_N_AC_STA;
|
||||
|
||||
goto out;
|
||||
|
||||
by_vif:
|
||||
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
|
||||
|
||||
if (bss_conf->eht_support)
|
||||
|
|
@ -3480,6 +3500,7 @@ rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_li
|
|||
else
|
||||
type = RTW89_FW_N_AC_STA;
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return type;
|
||||
|
|
|
|||
|
|
@ -5993,11 +5993,13 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev,
|
|||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_vif_link *rtwvif_link = (struct rtw89_vif_link *)vif->drv_priv;
|
||||
u8 mac_idx = rtwvif_link->mac_idx;
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
u8 nc = 1, nr = 3, ng = 0, cb = 1, cs = 1, ldpc_en = 1, stbc_en = 1;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u8 mac_idx = rtwvif_link->mac_idx;
|
||||
u8 port_sel = rtwvif_link->port;
|
||||
u8 sound_dim = 3, t;
|
||||
u8 *phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info;
|
||||
u8 *phy_cap;
|
||||
u32 reg;
|
||||
u16 val;
|
||||
int ret;
|
||||
|
|
@ -6006,6 +6008,11 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info;
|
||||
|
||||
if ((phy_cap[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) ||
|
||||
(phy_cap[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) {
|
||||
ldpc_en &= !!(phy_cap[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD);
|
||||
|
|
@ -6014,17 +6021,19 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev,
|
|||
phy_cap[5]);
|
||||
sound_dim = min(sound_dim, t);
|
||||
}
|
||||
if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
|
||||
(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
|
||||
ldpc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
|
||||
stbc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK);
|
||||
if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
|
||||
(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
|
||||
ldpc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
|
||||
stbc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK);
|
||||
t = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
|
||||
sta->deflink.vht_cap.cap);
|
||||
link_sta->vht_cap.cap);
|
||||
sound_dim = min(sound_dim, t);
|
||||
}
|
||||
nc = min(nc, sound_dim);
|
||||
nr = min(nr, sound_dim);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
|
||||
rtw89_write32_set(rtwdev, reg, B_AX_BFMEE_BFPARAM_SEL);
|
||||
|
||||
|
|
@ -6051,30 +6060,39 @@ static int rtw89_mac_csi_rrsc_ax(struct rtw89_dev *rtwdev,
|
|||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_vif_link *rtwvif_link = (struct rtw89_vif_link *)vif->drv_priv;
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
u32 rrsc = BIT(RTW89_MAC_BF_RRSC_6M) | BIT(RTW89_MAC_BF_RRSC_24M);
|
||||
u32 reg;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u8 mac_idx = rtwvif_link->mac_idx;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sta->deflink.he_cap.has_he) {
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
|
||||
if (link_sta->he_cap.has_he) {
|
||||
rrsc |= (BIT(RTW89_MAC_BF_RRSC_HE_MSC0) |
|
||||
BIT(RTW89_MAC_BF_RRSC_HE_MSC3) |
|
||||
BIT(RTW89_MAC_BF_RRSC_HE_MSC5));
|
||||
}
|
||||
if (sta->deflink.vht_cap.vht_supported) {
|
||||
if (link_sta->vht_cap.vht_supported) {
|
||||
rrsc |= (BIT(RTW89_MAC_BF_RRSC_VHT_MSC0) |
|
||||
BIT(RTW89_MAC_BF_RRSC_VHT_MSC3) |
|
||||
BIT(RTW89_MAC_BF_RRSC_VHT_MSC5));
|
||||
}
|
||||
if (sta->deflink.ht_cap.ht_supported) {
|
||||
if (link_sta->ht_cap.ht_supported) {
|
||||
rrsc |= (BIT(RTW89_MAC_BF_RRSC_HT_MSC0) |
|
||||
BIT(RTW89_MAC_BF_RRSC_HT_MSC3) |
|
||||
BIT(RTW89_MAC_BF_RRSC_HT_MSC5));
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
|
||||
rtw89_write32_set(rtwdev, reg, B_AX_BFMEE_BFPARAM_SEL);
|
||||
rtw89_write32_clr(rtwdev, reg, B_AX_BFMEE_CSI_FORCE_RETE_EN);
|
||||
|
|
@ -6090,8 +6108,18 @@ static void rtw89_mac_bf_assoc_ax(struct rtw89_dev *rtwdev,
|
|||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_vif_link *rtwvif_link = (struct rtw89_vif_link *)vif->drv_priv;
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
bool has_beamformer_cap;
|
||||
|
||||
if (rtw89_sta_has_beamformer_cap(sta)) {
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
has_beamformer_cap = rtw89_sta_has_beamformer_cap(link_sta);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (has_beamformer_cap) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_BF,
|
||||
"initialize bfee for new association\n");
|
||||
rtw89_mac_init_bfee_ax(rtwdev, rtwvif_link->mac_idx);
|
||||
|
|
@ -6145,16 +6173,23 @@ struct rtw89_mac_bf_monitor_iter_data {
|
|||
static
|
||||
void rtw89_mac_bf_monitor_calc_iter(void *data, struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
struct rtw89_mac_bf_monitor_iter_data *iter_data =
|
||||
(struct rtw89_mac_bf_monitor_iter_data *)data;
|
||||
struct ieee80211_sta *down_sta = iter_data->down_sta;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
int *count = &iter_data->count;
|
||||
|
||||
if (down_sta == sta)
|
||||
return;
|
||||
|
||||
if (rtw89_sta_has_beamformer_cap(sta))
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
|
||||
if (rtw89_sta_has_beamformer_cap(link_sta))
|
||||
(*count)++;
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev,
|
||||
|
|
|
|||
|
|
@ -2095,7 +2095,9 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
|
|||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_vif_link *rtwvif_link = (struct rtw89_vif_link *)vif->drv_priv;
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
u8 nc = 1, nr = 3, ng = 0, cb = 1, cs = 1, ldpc_en = 1, stbc_en = 1;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u8 mac_idx = rtwvif_link->mac_idx;
|
||||
u8 port_sel = rtwvif_link->port;
|
||||
u8 sound_dim = 3, t;
|
||||
|
|
@ -2108,7 +2110,10 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info;
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info;
|
||||
|
||||
if ((phy_cap[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) ||
|
||||
(phy_cap[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) {
|
||||
|
|
@ -2119,11 +2124,11 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
|
|||
sound_dim = min(sound_dim, t);
|
||||
}
|
||||
|
||||
if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
|
||||
(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
|
||||
ldpc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
|
||||
stbc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK);
|
||||
t = u32_get_bits(sta->deflink.vht_cap.cap,
|
||||
if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
|
||||
(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
|
||||
ldpc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
|
||||
stbc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK);
|
||||
t = u32_get_bits(link_sta->vht_cap.cap,
|
||||
IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK);
|
||||
sound_dim = min(sound_dim, t);
|
||||
}
|
||||
|
|
@ -2131,6 +2136,8 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
|
|||
nc = min(nc, sound_dim);
|
||||
nr = min(nr, sound_dim);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
|
||||
rtw89_write32_set(rtwdev, reg, B_BE_BFMEE_BFPARAM_SEL);
|
||||
|
||||
|
|
@ -2159,7 +2166,9 @@ static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev,
|
|||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_vif_link *rtwvif_link = (struct rtw89_vif_link *)vif->drv_priv;
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
u32 rrsc = BIT(RTW89_MAC_BF_RRSC_6M) | BIT(RTW89_MAC_BF_RRSC_24M);
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
u8 mac_idx = rtwvif_link->mac_idx;
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
|
@ -2168,22 +2177,28 @@ static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sta->deflink.he_cap.has_he) {
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
|
||||
if (link_sta->he_cap.has_he) {
|
||||
rrsc |= (BIT(RTW89_MAC_BF_RRSC_HE_MSC0) |
|
||||
BIT(RTW89_MAC_BF_RRSC_HE_MSC3) |
|
||||
BIT(RTW89_MAC_BF_RRSC_HE_MSC5));
|
||||
}
|
||||
if (sta->deflink.vht_cap.vht_supported) {
|
||||
if (link_sta->vht_cap.vht_supported) {
|
||||
rrsc |= (BIT(RTW89_MAC_BF_RRSC_VHT_MSC0) |
|
||||
BIT(RTW89_MAC_BF_RRSC_VHT_MSC3) |
|
||||
BIT(RTW89_MAC_BF_RRSC_VHT_MSC5));
|
||||
}
|
||||
if (sta->deflink.ht_cap.ht_supported) {
|
||||
if (link_sta->ht_cap.ht_supported) {
|
||||
rrsc |= (BIT(RTW89_MAC_BF_RRSC_HT_MSC0) |
|
||||
BIT(RTW89_MAC_BF_RRSC_HT_MSC3) |
|
||||
BIT(RTW89_MAC_BF_RRSC_HT_MSC5));
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
|
||||
rtw89_write32_set(rtwdev, reg, B_BE_BFMEE_BFPARAM_SEL);
|
||||
rtw89_write32_clr(rtwdev, reg, B_BE_BFMEE_CSI_FORCE_RETE_EN);
|
||||
|
|
@ -2199,8 +2214,18 @@ static void rtw89_mac_bf_assoc_be(struct rtw89_dev *rtwdev,
|
|||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_vif_link *rtwvif_link = (struct rtw89_vif_link *)vif->drv_priv;
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
bool has_beamformer_cap;
|
||||
|
||||
if (rtw89_sta_has_beamformer_cap(sta)) {
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
has_beamformer_cap = rtw89_sta_has_beamformer_cap(link_sta);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (has_beamformer_cap) {
|
||||
rtw89_debug(rtwdev, RTW89_DBG_BF,
|
||||
"initialize bfee for new association\n");
|
||||
rtw89_mac_init_bfee_be(rtwdev, rtwvif_link->mac_idx);
|
||||
|
|
|
|||
|
|
@ -75,12 +75,12 @@ static u64 get_mcs_ra_mask(u16 mcs_map, u8 highest_mcs, u8 gap)
|
|||
return ra_mask;
|
||||
}
|
||||
|
||||
static u64 get_he_ra_mask(struct ieee80211_sta *sta)
|
||||
static u64 get_he_ra_mask(struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
struct ieee80211_sta_he_cap cap = sta->deflink.he_cap;
|
||||
struct ieee80211_sta_he_cap cap = link_sta->he_cap;
|
||||
u16 mcs_map;
|
||||
|
||||
switch (sta->deflink.bandwidth) {
|
||||
switch (link_sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
if (cap.he_cap_elem.phy_cap_info[0] &
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
|
||||
|
|
@ -118,14 +118,14 @@ static u64 get_eht_mcs_ra_mask(u8 *max_nss, u8 start_mcs, u8 n_nss)
|
|||
return mask;
|
||||
}
|
||||
|
||||
static u64 get_eht_ra_mask(struct ieee80211_sta *sta)
|
||||
static u64 get_eht_ra_mask(struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap;
|
||||
struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap;
|
||||
struct ieee80211_eht_mcs_nss_supp_20mhz_only *mcs_nss_20mhz;
|
||||
struct ieee80211_eht_mcs_nss_supp_bw *mcs_nss;
|
||||
u8 *he_phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info;
|
||||
u8 *he_phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info;
|
||||
|
||||
switch (sta->deflink.bandwidth) {
|
||||
switch (link_sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_320:
|
||||
mcs_nss = &eht_cap->eht_mcs_nss_supp.bw._320;
|
||||
/* MCS 9, 11, 13 */
|
||||
|
|
@ -197,9 +197,9 @@ static u64 rtw89_phy_ra_mask_recover(u64 ra_mask, u64 ra_mask_bak)
|
|||
|
||||
static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_sta_link *rtwsta_link,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
const struct rtw89_chan *chan)
|
||||
{
|
||||
struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta_link);
|
||||
struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask;
|
||||
enum nl80211_band band;
|
||||
u64 cfg_mask;
|
||||
|
|
@ -228,17 +228,17 @@ static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (sta->deflink.he_cap.has_he) {
|
||||
if (link_sta->he_cap.has_he) {
|
||||
cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[0],
|
||||
RA_MASK_HE_1SS_RATES);
|
||||
cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[1],
|
||||
RA_MASK_HE_2SS_RATES);
|
||||
} else if (sta->deflink.vht_cap.vht_supported) {
|
||||
} else if (link_sta->vht_cap.vht_supported) {
|
||||
cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0],
|
||||
RA_MASK_VHT_1SS_RATES);
|
||||
cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1],
|
||||
RA_MASK_VHT_2SS_RATES);
|
||||
} else if (sta->deflink.ht_cap.ht_supported) {
|
||||
} else if (link_sta->ht_cap.ht_supported) {
|
||||
cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0],
|
||||
RA_MASK_HT_1SS_RATES);
|
||||
cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1],
|
||||
|
|
@ -296,15 +296,15 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev,
|
|||
}
|
||||
|
||||
static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
|
||||
struct ieee80211_sta *sta, bool csi)
|
||||
struct rtw89_vif_link *rtwvif_link,
|
||||
struct rtw89_sta_link *rtwsta_link,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
bool p2p, bool csi)
|
||||
{
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link;
|
||||
struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern;
|
||||
struct rtw89_ra_info *ra = &rtwsta_link->ra;
|
||||
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
|
||||
rtwvif_link->chanctx_idx);
|
||||
struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta_link->rtwvif_link);
|
||||
const u64 *high_rate_masks = rtw89_ra_mask_ht_rates;
|
||||
u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi);
|
||||
u64 ra_mask = 0;
|
||||
|
|
@ -321,65 +321,65 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
|
|||
|
||||
memset(ra, 0, sizeof(*ra));
|
||||
/* Set the ra mask from sta's capability */
|
||||
if (sta->deflink.eht_cap.has_eht) {
|
||||
if (link_sta->eht_cap.has_eht) {
|
||||
mode |= RTW89_RA_MODE_EHT;
|
||||
ra_mask |= get_eht_ra_mask(sta);
|
||||
ra_mask |= get_eht_ra_mask(link_sta);
|
||||
high_rate_masks = rtw89_ra_mask_eht_rates;
|
||||
} else if (sta->deflink.he_cap.has_he) {
|
||||
} else if (link_sta->he_cap.has_he) {
|
||||
mode |= RTW89_RA_MODE_HE;
|
||||
csi_mode = RTW89_RA_RPT_MODE_HE;
|
||||
ra_mask |= get_he_ra_mask(sta);
|
||||
ra_mask |= get_he_ra_mask(link_sta);
|
||||
high_rate_masks = rtw89_ra_mask_he_rates;
|
||||
if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[2] &
|
||||
if (link_sta->he_cap.he_cap_elem.phy_cap_info[2] &
|
||||
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
|
||||
stbc_en = 1;
|
||||
if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[1] &
|
||||
if (link_sta->he_cap.he_cap_elem.phy_cap_info[1] &
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)
|
||||
ldpc_en = 1;
|
||||
rtw89_phy_ra_gi_ltf(rtwdev, rtwsta_link, chan, &fix_giltf_en, &fix_giltf);
|
||||
} else if (sta->deflink.vht_cap.vht_supported) {
|
||||
u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
|
||||
} else if (link_sta->vht_cap.vht_supported) {
|
||||
u16 mcs_map = le16_to_cpu(link_sta->vht_cap.vht_mcs.rx_mcs_map);
|
||||
|
||||
mode |= RTW89_RA_MODE_VHT;
|
||||
csi_mode = RTW89_RA_RPT_MODE_VHT;
|
||||
/* MCS9 (non-20MHz), MCS8, MCS7 */
|
||||
if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
|
||||
if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20)
|
||||
ra_mask |= get_mcs_ra_mask(mcs_map, 8, 1);
|
||||
else
|
||||
ra_mask |= get_mcs_ra_mask(mcs_map, 9, 1);
|
||||
high_rate_masks = rtw89_ra_mask_vht_rates;
|
||||
if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
|
||||
if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
|
||||
stbc_en = 1;
|
||||
if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
|
||||
if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
|
||||
ldpc_en = 1;
|
||||
} else if (sta->deflink.ht_cap.ht_supported) {
|
||||
} else if (link_sta->ht_cap.ht_supported) {
|
||||
mode |= RTW89_RA_MODE_HT;
|
||||
csi_mode = RTW89_RA_RPT_MODE_HT;
|
||||
ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 48) |
|
||||
((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 36) |
|
||||
((u64)sta->deflink.ht_cap.mcs.rx_mask[1] << 24) |
|
||||
((u64)sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
|
||||
ra_mask |= ((u64)link_sta->ht_cap.mcs.rx_mask[3] << 48) |
|
||||
((u64)link_sta->ht_cap.mcs.rx_mask[2] << 36) |
|
||||
((u64)link_sta->ht_cap.mcs.rx_mask[1] << 24) |
|
||||
((u64)link_sta->ht_cap.mcs.rx_mask[0] << 12);
|
||||
high_rate_masks = rtw89_ra_mask_ht_rates;
|
||||
if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
|
||||
if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
|
||||
stbc_en = 1;
|
||||
if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
|
||||
if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
|
||||
ldpc_en = 1;
|
||||
}
|
||||
|
||||
switch (chan->band_type) {
|
||||
case RTW89_BAND_2G:
|
||||
ra_mask |= sta->deflink.supp_rates[NL80211_BAND_2GHZ];
|
||||
if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xf)
|
||||
ra_mask |= link_sta->supp_rates[NL80211_BAND_2GHZ];
|
||||
if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xf)
|
||||
mode |= RTW89_RA_MODE_CCK;
|
||||
if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xff0)
|
||||
if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xff0)
|
||||
mode |= RTW89_RA_MODE_OFDM;
|
||||
break;
|
||||
case RTW89_BAND_5G:
|
||||
ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4;
|
||||
ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_5GHZ] << 4;
|
||||
mode |= RTW89_RA_MODE_OFDM;
|
||||
break;
|
||||
case RTW89_BAND_6G:
|
||||
ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_6GHZ] << 4;
|
||||
ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_6GHZ] << 4;
|
||||
mode |= RTW89_RA_MODE_OFDM;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -406,37 +406,37 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
|
|||
ra_mask &= rtw89_phy_ra_mask_rssi(rtwdev, rssi, 0);
|
||||
|
||||
ra_mask = rtw89_phy_ra_mask_recover(ra_mask, ra_mask_bak);
|
||||
ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, chan);
|
||||
ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan);
|
||||
|
||||
switch (sta->deflink.bandwidth) {
|
||||
switch (link_sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
bw_mode = RTW89_CHANNEL_WIDTH_160;
|
||||
sgi = sta->deflink.vht_cap.vht_supported &&
|
||||
(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
|
||||
sgi = link_sta->vht_cap.vht_supported &&
|
||||
(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_80:
|
||||
bw_mode = RTW89_CHANNEL_WIDTH_80;
|
||||
sgi = sta->deflink.vht_cap.vht_supported &&
|
||||
(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
|
||||
sgi = link_sta->vht_cap.vht_supported &&
|
||||
(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_40:
|
||||
bw_mode = RTW89_CHANNEL_WIDTH_40;
|
||||
sgi = sta->deflink.ht_cap.ht_supported &&
|
||||
(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
|
||||
sgi = link_sta->ht_cap.ht_supported &&
|
||||
(link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
|
||||
break;
|
||||
default:
|
||||
bw_mode = RTW89_CHANNEL_WIDTH_20;
|
||||
sgi = sta->deflink.ht_cap.ht_supported &&
|
||||
(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
|
||||
sgi = link_sta->ht_cap.ht_supported &&
|
||||
(link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] &
|
||||
if (link_sta->he_cap.he_cap_elem.phy_cap_info[3] &
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM)
|
||||
ra->dcm_cap = 1;
|
||||
|
||||
if (rate_pattern->enable && !vif->p2p) {
|
||||
ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, chan);
|
||||
if (rate_pattern->enable && !p2p) {
|
||||
ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan);
|
||||
ra_mask &= rate_pattern->ra_mask;
|
||||
mode = rate_pattern->ra_mode;
|
||||
}
|
||||
|
|
@ -447,7 +447,7 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
|
|||
ra->macid = rtwsta_link->mac_id;
|
||||
ra->stbc_cap = stbc_en;
|
||||
ra->ldpc_cap = ldpc_en;
|
||||
ra->ss_num = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
|
||||
ra->ss_num = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1;
|
||||
ra->en_sgi = sgi;
|
||||
ra->ra_mask = ra_mask;
|
||||
ra->fix_giltf_en = fix_giltf_en;
|
||||
|
|
@ -470,9 +470,18 @@ void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta
|
|||
u32 changed)
|
||||
{
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link;
|
||||
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif_link);
|
||||
struct rtw89_ra_info *ra = &rtwsta_link->ra;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
|
||||
rtw89_phy_ra_sta_update(rtwdev, sta, false);
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
|
||||
rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link,
|
||||
link_sta, vif->p2p, false);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED)
|
||||
ra->upd_mask = 1;
|
||||
|
|
@ -631,11 +640,22 @@ void rtw89_phy_ra_update(struct rtw89_dev *rtwdev)
|
|||
void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link;
|
||||
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif_link);
|
||||
struct rtw89_ra_info *ra = &rtwsta_link->ra;
|
||||
u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR;
|
||||
bool csi = rtw89_sta_has_beamformer_cap(sta);
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
bool csi;
|
||||
|
||||
rtw89_phy_ra_sta_update(rtwdev, sta, csi);
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
|
||||
csi = rtw89_sta_has_beamformer_cap(link_sta);
|
||||
|
||||
rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link,
|
||||
link_sta, vif->p2p, csi);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (rssi > 40)
|
||||
ra->init_rate_lv = 1;
|
||||
|
|
@ -2554,11 +2574,11 @@ struct rtw89_phy_iter_ra_data {
|
|||
struct sk_buff *c2h;
|
||||
};
|
||||
|
||||
static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
|
||||
static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct rtw89_phy_iter_ra_data *ra_data)
|
||||
{
|
||||
struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data;
|
||||
struct rtw89_dev *rtwdev = ra_data->rtwdev;
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
const struct rtw89_c2h_ra_rpt *c2h =
|
||||
(const struct rtw89_c2h_ra_rpt *)ra_data->c2h->data;
|
||||
struct rtw89_ra_report *ra_report = &rtwsta_link->ra_report;
|
||||
|
|
@ -2662,8 +2682,22 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
|
|||
u16_encode_bits(mode, RTW89_HW_RATE_MASK_MOD) |
|
||||
u16_encode_bits(rate, RTW89_HW_RATE_MASK_VAL);
|
||||
ra_report->might_fallback_legacy = mcs <= 2;
|
||||
sta->deflink.agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
|
||||
rtwsta_link->max_agg_wait = sta->deflink.agg.max_rc_amsdu_len / 1500 - 1;
|
||||
link_sta->agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
|
||||
rtwsta_link->max_agg_wait = link_sta->agg.max_rc_amsdu_len / 1500 - 1;
|
||||
}
|
||||
|
||||
static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
|
||||
{
|
||||
struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data;
|
||||
struct rtw89_sta_link *rtwsta_link = (struct rtw89_sta_link *)sta->drv_priv;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
|
||||
__rtw89_phy_c2h_ra_rpt_iter(rtwsta_link, link_sta, ra_data);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user