diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index ab1f85f0f626..b3ad4e86d9cc 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -928,6 +928,59 @@ fail: return -EBUSY; } +#define H2C_BCN_BASE_LEN 12 +int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + struct rtw89_hal *hal = &rtwdev->hal; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct sk_buff *skb; + struct sk_buff *skb_beacon; + u16 tim_offset; + int bcn_total_len; + + skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset, NULL); + if (!skb_beacon) { + rtw89_err(rtwdev, "failed to get beacon skb\n"); + return -ENOMEM; + } + + bcn_total_len = H2C_BCN_BASE_LEN + skb_beacon->len; + skb = rtw89_fw_h2c_alloc_skb_with_hdr(bcn_total_len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); + dev_kfree_skb_any(skb_beacon); + return -ENOMEM; + } + skb_put(skb, H2C_BCN_BASE_LEN); + + SET_BCN_UPD_PORT(skb->data, rtwvif->port); + SET_BCN_UPD_MBSSID(skb->data, 0); + SET_BCN_UPD_BAND(skb->data, rtwvif->mac_idx); + SET_BCN_UPD_GRP_IE_OFST(skb->data, tim_offset); + SET_BCN_UPD_MACID(skb->data, rtwvif->mac_id); + SET_BCN_UPD_SSN_SEL(skb->data, RTW89_MGMT_HW_SSN_SEL); + SET_BCN_UPD_SSN_MODE(skb->data, RTW89_MGMT_HW_SEQ_MODE); + SET_BCN_UPD_RATE(skb->data, hal->current_band_type == RTW89_BAND_2G ? + RTW89_HW_RATE_CCK1 : RTW89_HW_RATE_OFDM6); + + skb_put_data(skb, skb_beacon->data, skb_beacon->len); + dev_kfree_skb_any(skb_beacon); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_BCN_UPD, 0, 1, + bcn_total_len); + + if (rtw89_h2c_tx(rtwdev, skb, false)) { + rtw89_err(rtwdev, "failed to send h2c\n"); + dev_kfree_skb_any(skb); + return -EBUSY; + } + + return 0; +} + #define H2C_VIF_MAINTAIN_LEN 4 int rtw89_fw_h2c_vif_maintain(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b10f6e6a534c..c6e83e4e49fa 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1056,6 +1056,106 @@ static inline void SET_CMC_TBL_CSI_BW(void *table, u32 val) GENMASK(31, 30)); } +static inline void SET_BCN_UPD_PORT(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); +} + +static inline void SET_BCN_UPD_MBSSID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); +} + +static inline void SET_BCN_UPD_BAND(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)); +} + +static inline void SET_BCN_UPD_GRP_IE_OFST(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, (val - 24) | BIT(7), GENMASK(31, 24)); +} + +static inline void SET_BCN_UPD_MACID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(7, 0)); +} + +static inline void SET_BCN_UPD_SSN_SEL(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(9, 8)); +} + +static inline void SET_BCN_UPD_SSN_MODE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(11, 10)); +} + +static inline void SET_BCN_UPD_RATE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(20, 12)); +} + +static inline void SET_BCN_UPD_TXPWR(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(23, 21)); +} + +static inline void SET_BCN_UPD_TXINFO_CTRL_EN(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(0)); +} + +static inline void SET_BCN_UPD_NTX_PATH_EN(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(4, 1)); +} + +static inline void SET_BCN_UPD_PATH_MAP_A(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(6, 5)); +} + +static inline void SET_BCN_UPD_PATH_MAP_B(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(8, 7)); +} + +static inline void SET_BCN_UPD_PATH_MAP_C(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(10, 9)); +} + +static inline void SET_BCN_UPD_PATH_MAP_D(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(12, 11)); +} + +static inline void SET_BCN_UPD_PATH_ANTSEL_A(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(13)); +} + +static inline void SET_BCN_UPD_PATH_ANTSEL_B(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(14)); +} + +static inline void SET_BCN_UPD_PATH_ANTSEL_C(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(15)); +} + +static inline void SET_BCN_UPD_PATH_ANTSEL_D(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(16)); +} + +static inline void SET_BCN_UPD_CSA_OFST(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(31, 17)); +} + static inline void SET_FWROLE_MAINTAIN_MACID(void *h2c, u32 val) { le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); @@ -1729,6 +1829,7 @@ struct rtw89_fw_h2c_rf_reg_info { /* CLASS 5 - Frame Exchange */ #define H2C_CL_MAC_FR_EXCHG 0x5 #define H2C_FUNC_MAC_CCTLINFO_UD 0x2 +#define H2C_FUNC_MAC_BCN_UPD 0x5 /* CLASS 6 - Address CAM */ #define H2C_CL_MAC_ADDR_CAM_UPDATE 0x6 @@ -1776,6 +1877,8 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta); +int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif); int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif, struct rtw89_sta *rtwsta, const u8 *scan_mac_addr); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 3e4a47642459..8883d406649f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -349,6 +349,9 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); } + if (changed & BSS_CHANGED_BEACON) + rtw89_fw_h2c_update_beacon(rtwdev, rtwvif); + if (changed & BSS_CHANGED_ERP_SLOT) rtw89_conf_tx(rtwdev, rtwvif);