1: 0243ea038a1a = 1: 553d4178355a wifi: rtw88: download the beacon the reserved page was built with -: ------------ > 2: a3b2c672a61f wifi: rtw88: update the beacon from a wiphy work 2: 209585bd5f65 ! 3: f434e2535709 wifi: rtw88: support channel switch in AP mode @@ drivers/net/wireless/realtek/rtw88/fw.c: int rtw_fw_download_rsvd_page(struct rt   +bool rtw_fw_csa_active(struct rtw_dev *rtwdev)  +{ ++ lockdep_assert_wiphy(rtwdev->hw->wiphy); ++  + return rtwdev->csa_vif && rtwdev->csa_vif->bss_conf.csa_active;  +}  + @@ drivers/net/wireless/realtek/rtw88/fw.c: int rtw_fw_download_rsvd_page(struct rt  +{  + u32 interval = ieee80211_tu_to_usec(vif->bss_conf.beacon_int);  + ++ lockdep_assert_wiphy(rtwdev->hw->wiphy); ++  + rtwdev->csa_vif = vif;  + wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->csa_beacon_work,  + usecs_to_jiffies(interval)); @@ drivers/net/wireless/realtek/rtw88/fw.c: int rtw_fw_download_rsvd_page(struct rt  +  +void rtw_fw_csa_stop(struct rtw_dev *rtwdev, struct ieee80211_vif *vif)  +{ ++ lockdep_assert_wiphy(rtwdev->hw->wiphy); ++  + if (!vif || rtwdev->csa_vif != vif)  + return;  + @@ drivers/net/wireless/realtek/rtw88/fw.c: int rtw_fw_download_rsvd_page(struct rt  + rtwdev->csa_vif = NULL;  +}  + - void rtw_fw_update_beacon_work(struct work_struct *work) + void rtw_fw_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) { struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, - update_beacon_work); +@@ drivers/net/wireless/realtek/rtw88/fw.c: void rtw_fw_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work)  mutex_lock(&rtwdev->mutex); -+ -+ if (rtw_fw_csa_active(rtwdev)) -+ goto out; -+ +  +- if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) ++ if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags) || ++ rtw_fw_csa_active(rtwdev)) + goto out; +  rtw_fw_download_rsvd_page(rtwdev); - rtw_send_rsvd_page_h2c(rtwdev); -+ -+out: -+ mutex_unlock(&rtwdev->mutex); -+} -+ +@@ drivers/net/wireless/realtek/rtw88/fw.c: void rtw_fw_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) + mutex_unlock(&rtwdev->mutex); + } +   +void rtw_fw_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work)  +{  + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, @@ drivers/net/wireless/realtek/rtw88/fw.c: int rtw_fw_download_rsvd_page(struct rt  + }  +  +out: - mutex_unlock(&rtwdev->mutex); - } -  ++ mutex_unlock(&rtwdev->mutex); ++} ++ + static void rtw_fw_read_fifo_page(struct rtw_dev *rtwdev, u32 offset, u32 size, + u32 *buf, u32 residue, u16 start_pg) + {  ## drivers/net/wireless/realtek/rtw88/fw.h ##  @@ drivers/net/wireless/realtek/rtw88/fw.h: void rtw_add_rsvd_page_pno(struct rtw_dev *rtwdev, @@ drivers/net/wireless/realtek/rtw88/fw.h: void rtw_add_rsvd_page_pno(struct rtw_d  +bool rtw_fw_csa_active(struct rtw_dev *rtwdev);  +void rtw_fw_csa_start(struct rtw_dev *rtwdev, struct ieee80211_vif *vif);  +void rtw_fw_csa_stop(struct rtw_dev *rtwdev, struct ieee80211_vif *vif); - void rtw_fw_update_beacon_work(struct work_struct *work); + void rtw_fw_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work);  +void rtw_fw_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev); int rtw_dump_drv_rsvd_page(struct rtw_dev *rtwdev, @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static void rtw_ops_bss_info_chan   - rtw_fw_download_rsvd_page(rtwdev);  - rtw_send_rsvd_page_h2c(rtwdev); ++ /* a station of the STA+AP combination: keep the AP's countdown */  + if (!rtw_fw_csa_active(rtwdev)) {  + rtw_fw_download_rsvd_page(rtwdev);  + rtw_send_rsvd_page_h2c(rtwdev); @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static int rtw_ops_hw_scan(struct struct rtw_dev *rtwdev = hw->priv; int ret;  -- if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD)) -- return 1; -+ mutex_lock(&rtwdev->mutex); -  -- if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) -- return -EBUSY; -+ if (rtw_fw_csa_active(rtwdev)) { -+ ret = -EBUSY; -+ goto out; -+ } ++ guard(mutex)(&rtwdev->mutex);  + -+ if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD)) { -+ ret = 1; -+ goto out; -+ } ++ if (rtw_fw_csa_active(rtwdev)) ++ return -EBUSY;  + -+ if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) { -+ ret = -EBUSY; -+ goto out; -+ } + if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD)) + return 1; +  + if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) + return -EBUSY;   - mutex_lock(&rtwdev->mutex); rtw_hw_scan_start(rtwdev, vif, req); @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static int rtw_ops_hw_scan(struct rtw_hw_scan_abort(rtwdev); rtw_err(rtwdev, "HW scan failed with status: %d\n", ret); } -+out: - mutex_unlock(&rtwdev->mutex); +- mutex_unlock(&rtwdev->mutex);  return ret; + }  @@ drivers/net/wireless/realtek/rtw88/mac80211.c: const struct ieee80211_ops rtw_ops = { .sta_add = rtw_ops_sta_add, .sta_remove = rtw_ops_sta_remove, @@ drivers/net/wireless/realtek/rtw88/main.c: static void rtw_fw_recovery_work(stru __fw_recovery_work(rtwdev); mutex_unlock(&rtwdev->mutex);  @@ drivers/net/wireless/realtek/rtw88/main.c: int rtw_core_init(struct rtw_dev *rtwdev) - INIT_WORK(&rtwdev->ips_work, rtw_ips_work); INIT_WORK(&rtwdev->fw_recovery_work, rtw_fw_recovery_work); - INIT_WORK(&rtwdev->update_beacon_work, rtw_fw_update_beacon_work); + wiphy_work_init(&rtwdev->update_beacon_work, + rtw_fw_update_beacon_work);  + wiphy_delayed_work_init(&rtwdev->csa_beacon_work,  + rtw_fw_csa_beacon_work); INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work); @@ drivers/net/wireless/realtek/rtw88/main.h  @@ drivers/net/wireless/realtek/rtw88/main.h: struct rtw_dev { struct work_struct ips_work; struct work_struct fw_recovery_work; - struct work_struct update_beacon_work; + struct wiphy_work update_beacon_work;  + struct wiphy_delayed_work csa_beacon_work;  + struct ieee80211_vif *csa_vif;