1: bef2154798e7 ! 1: d8321b34479c wifi: rtw88: download the beacon the reserved page was built with @@ Commit message keeps fetching its own.  Signed-off-by: Mehmet Fide  + Acked-by: Ping-Ke Shih   ## drivers/net/wireless/realtek/rtw88/fw.c ##  @@ drivers/net/wireless/realtek/rtw88/fw.c: static int __rtw_build_rsvd_page_from_vifs(struct rtw_dev *rtwdev) @@ drivers/net/wireless/realtek/rtw88/fw.c: static int rtw_download_beacon(struct r int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev) {  - u8 *buf; -+ struct sk_buff *beacon; ++ struct sk_buff *beacon = NULL; u32 size;  + u8 *buf; int ret; 2: 48b873b2843b ! 2: 5e1d57015f2a wifi: rtw88: support channel switch in AP mode @@ Commit message and ieee80211_csa_finish() is called once it completes. IBSS, which the flag enables too, shares the page and the work.  - The work is a wiphy delayed work of the device, like - update_beacon_work: rtw88 runs one beaconing interface, a hw restart - replays add_interface without remove_interface, and the wiphy lock - serializes it with the mac80211 state it reads. It is cancelled when - the AP stops, when the vif goes away and on WoWLAN suspend, and a - hardware scan is refused while a switch is announced, since it would - take the AP off the channel its stations count down to. + The work is a wiphy delayed work of the interface; the wiphy lock + serializes it with the mac80211 state it reads and the driver mutex + with the page build. It is cancelled when the AP stops, when the + interface goes away and on WoWLAN suspend, and a hardware restart, + which replays add_interface with the work still armed, does not + initialise it again. The other page downloads + that can run during a countdown, the TIM update and the PG backup on + set_key, are skipped then, since every beacon fetch advances the + countdown. A hardware scan is refused while a switch is announced: it + would take the AP off the channel its stations count down to.  Signed-off-by: Mehmet Fide   ## drivers/net/wireless/realtek/rtw88/fw.c ## -@@ drivers/net/wireless/realtek/rtw88/fw.c: void rtw_fw_update_beacon_work(struct work_struct *work) - mutex_unlock(&rtwdev->mutex); +@@ drivers/net/wireless/realtek/rtw88/fw.c: int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev) + return ret; }  -+/* renew the countdown in the firmware's beacon page until it completes */ ++static struct ieee80211_vif *rtw_fw_beacon_vif(struct rtw_dev *rtwdev) ++{ ++ struct rtw_rsvd_page *rsvd_pkt; ++ ++ rsvd_pkt = list_first_entry_or_null(&rtwdev->rsvd_page_list, ++ struct rtw_rsvd_page, build_list); ++ if (!rsvd_pkt || rsvd_pkt->type != RSVD_BEACON) ++ return NULL; ++ ++ return rtwvif_to_vif(rsvd_pkt->rtwvif); ++} ++ ++bool rtw_fw_csa_active(struct rtw_dev *rtwdev) ++{ ++ struct ieee80211_vif *vif = rtw_fw_beacon_vif(rtwdev); ++ ++ return vif && vif->bss_conf.csa_active; ++} ++ + void rtw_fw_update_beacon_work(struct work_struct *work) + { + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, + update_beacon_work); +  + mutex_lock(&rtwdev->mutex); ++ ++ if (rtw_fw_csa_active(rtwdev)) ++ goto out; ++ + rtw_fw_download_rsvd_page(rtwdev); + rtw_send_rsvd_page_h2c(rtwdev); ++ ++out: ++ 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, ++ struct rtw_vif *rtwvif = container_of(work, struct rtw_vif,  + csa_beacon_work.work); -+ struct rtw_rsvd_page *rsvd_pkt; -+ struct ieee80211_vif *vif; ++ struct rtw_dev *rtwdev = wiphy_to_ieee80211_hw(wiphy)->priv; ++ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);  + unsigned int delay;  +  + lockdep_assert_wiphy(wiphy); @@ drivers/net/wireless/realtek/rtw88/fw.c: void rtw_fw_update_beacon_work(struct w  + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags))  + goto out;  + -+ rsvd_pkt = list_first_entry_or_null(&rtwdev->rsvd_page_list, -+ struct rtw_rsvd_page, build_list); -+ if (!rsvd_pkt || rsvd_pkt->type != RSVD_BEACON) -+ goto out; -+ -+ vif = rtwvif_to_vif(rsvd_pkt->rtwvif);  + if (!vif->bss_conf.csa_active)  + goto out;  + @@ drivers/net/wireless/realtek/rtw88/fw.c: void rtw_fw_update_beacon_work(struct w  + rtw_fw_download_rsvd_page(rtwdev);  + rtw_send_rsvd_page_h2c(rtwdev);  + -+ wiphy_delayed_work_queue(wiphy, &rtwdev->csa_beacon_work, ++ wiphy_delayed_work_queue(wiphy, &rtwvif->csa_beacon_work,  + usecs_to_jiffies(delay));  + } else {  + ieee80211_csa_finish(vif, 0);  + }  +  +out: -+ 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) - { + mutex_unlock(&rtwdev->mutex); + } +   ## drivers/net/wireless/realtek/rtw88/fw.h ## -@@ drivers/net/wireless/realtek/rtw88/fw.h: void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev, +@@ drivers/net/wireless/realtek/rtw88/fw.h: void rtw_add_rsvd_page_pno(struct rtw_dev *rtwdev, + void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev); ++bool rtw_fw_csa_active(struct rtw_dev *rtwdev); void rtw_fw_update_beacon_work(struct work_struct *work);  +void rtw_fw_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev); @@ drivers/net/wireless/realtek/rtw88/fw.h: void rtw_add_rsvd_page_sta(struct rtw_d u32 offset, u32 size, u32 *buf);  ## drivers/net/wireless/realtek/rtw88/mac80211.c ## +@@ drivers/net/wireless/realtek/rtw88/mac80211.c: static int rtw_ops_add_interface(struct ieee80211_hw *hw, + memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee)); + rtw_txq_init(rtwdev, vif->txq); + INIT_LIST_HEAD(&rtwvif->rsvd_page_list); ++ if (!test_bit(RTW_FLAG_RESTARTING, rtwdev->flags)) ++ wiphy_delayed_work_init(&rtwvif->csa_beacon_work, ++ rtw_fw_csa_beacon_work); +  + mutex_lock(&rtwdev->mutex); +   @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static void rtw_ops_remove_interface(struct ieee80211_hw *hw, rtw_dbg(rtwdev, RTW_DBG_STATE, "stop vif %pM mac_id %d on port %d\n", vif->addr, rtwvif->mac_id, rtwvif->port);  -+ if (rtwvif->net_type == RTW_NET_AP_MODE || -+ rtwvif->net_type == RTW_NET_AD_HOC) -+ wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->csa_beacon_work); ++ wiphy_delayed_work_cancel(hw->wiphy, &rtwvif->csa_beacon_work);  + mutex_lock(&rtwdev->mutex);  rtw_leave_lps_deep(rtwdev); -@@ drivers/net/wireless/realtek/rtw88/mac80211.c: static void rtw_conf_tx(struct rtw_dev *rtwdev, - __rtw_conf_tx(rtwdev, rtwvif, ac); - } -  -+/* renew the channel switch countdown one beacon interval from now */ -+static void rtw_csa_beacon_queue(struct rtw_dev *rtwdev, u16 beacon_int) -+{ -+ wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->csa_beacon_work, -+ usecs_to_jiffies(ieee80211_tu_to_usec(beacon_int))); -+} -+ - static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf,  @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, rtw_set_dtim_period(rtwdev, conf->dtim_period); rtw_fw_download_rsvd_page(rtwdev); rtw_send_rsvd_page_h2c(rtwdev); -+ /* a hw restart replays the beacon, not channel_switch_beacon */ -+ if (conf->csa_active) -+ rtw_csa_beacon_queue(rtwdev, conf->beacon_int); ++ if (conf->csa_active) { ++ u32 interval = ieee80211_tu_to_usec(conf->beacon_int); ++ ++ wiphy_delayed_work_queue(hw->wiphy, ++ &rtwvif->csa_beacon_work, ++ usecs_to_jiffies(interval)); ++ } }  if (changed & BSS_CHANGED_BEACON_ENABLED) {  @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static void rtw_ops_stop_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { ++ struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; struct rtw_dev *rtwdev = hw->priv;  -+ wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->csa_beacon_work); ++ wiphy_delayed_work_cancel(hw->wiphy, &rtwvif->csa_beacon_work);  + mutex_lock(&rtwdev->mutex); rtw_write32_clr(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD); @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static int rtw_ops_set_tim(struct  + struct ieee80211_vif *vif,  + struct cfg80211_chan_def *chandef)  +{ -+ struct rtw_dev *rtwdev = hw->priv; ++ u32 interval = ieee80211_tu_to_usec(vif->bss_conf.beacon_int); ++ struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;  + -+ /* the beacon that starts the countdown was just downloaded */ -+ rtw_csa_beacon_queue(rtwdev, vif->bss_conf.beacon_int); ++ wiphy_delayed_work_queue(hw->wiphy, &rtwvif->csa_beacon_work, ++ usecs_to_jiffies(interval));  +}  + static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) +@@ drivers/net/wireless/realtek/rtw88/mac80211.c: static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + } +  + /* download new cam settings for PG to backup */ +- if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG) ++ if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG && ++ !rtw_fw_csa_active(rtwdev)) + rtw_fw_download_rsvd_page(rtwdev); +  + out: +@@ drivers/net/wireless/realtek/rtw88/mac80211.c: static int rtw_ops_get_antenna(struct ieee80211_hw *hw, + } +  + #ifdef CONFIG_PM ++static void rtw_csa_cancel_iter(void *data, struct ieee80211_vif *vif) ++{ ++ struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; ++ struct rtw_dev *rtwdev = data; ++ ++ wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwvif->csa_beacon_work); ++} ++ + static int rtw_ops_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) + {  @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static int rtw_ops_suspend(struct ieee80211_hw *hw, - struct rtw_dev *rtwdev = hw->priv; int ret;  -+ wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->csa_beacon_work); -+ mutex_lock(&rtwdev->mutex); ++ rtw_iterate_vifs(rtwdev, rtw_csa_cancel_iter, rtwdev); ret = rtw_wow_suspend(rtwdev, wowlan); if (ret) + rtw_err(rtwdev, "failed to suspend for wow %d\n", ret);  @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static void rtw_reconfig_complete(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } @@ drivers/net/wireless/realtek/rtw88/mac80211.c: static int rtw_ops_hw_scan(struct  mutex_lock(&rtwdev->mutex);  + -+ /* the stations count down to the new channel and expect the AP there */  + rtw_iterate_vifs(rtwdev, rtw_csa_active_iter, &csa_active);  + if (csa_active) {  + mutex_unlock(&rtwdev->mutex); @@ drivers/net/wireless/realtek/rtw88/mac80211.c: const struct ieee80211_ops rtw_op .can_aggregate_in_amsdu = rtw_ops_can_aggregate_in_amsdu,  ## drivers/net/wireless/realtek/rtw88/main.c ## -@@ 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_delayed_work_init(&rtwdev->csa_beacon_work, rtw_fw_csa_beacon_work); - INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work); - skb_queue_head_init(&rtwdev->c2h_queue); - skb_queue_head_init(&rtwdev->coex.queue);  @@ drivers/net/wireless/realtek/rtw88/main.c: int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) hw->wiphy->available_antennas_rx = hal->antenna_rx;  @@ drivers/net/wireless/realtek/rtw88/main.c: int rtw_register_hw(struct rtw_dev *r hw->wiphy->max_scan_ssids = RTW_SCAN_MAX_SSIDS;  ## 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; +@@ drivers/net/wireless/realtek/rtw88/main.h: struct rtw_vif { + struct rtw_traffic_stats stats; +  + struct rtw_bfee bfee; ++  + struct wiphy_delayed_work csa_beacon_work; + };  - /* used to protect txqs list */ - spinlock_t txq_lock; + struct rtw_regulatory {