]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: rtw88: iterate over vif/sta list non-atomically
authorSascha Hauer <s.hauer@pengutronix.de>
Fri, 2 Dec 2022 08:12:19 +0000 (09:12 +0100)
committerKalle Valo <kvalo@kernel.org>
Thu, 8 Dec 2022 14:48:41 +0000 (16:48 +0200)
The driver uses ieee80211_iterate_active_interfaces_atomic()
and ieee80211_iterate_stations_atomic() in several places and does
register accesses in the iterators. This doesn't cope with upcoming
USB support as registers can only be accessed non-atomically.

Split these into a two stage process: First use the atomic iterator
functions to collect all active interfaces or stations on a list, then
iterate over the list non-atomically and call the iterator on each
entry.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Suggested-by: Ping-Ke shih <pkshih@realtek.com>
Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20221202081224.2779981-7-s.hauer@pengutronix.de
drivers/net/wireless/realtek/rtw88/phy.c
drivers/net/wireless/realtek/rtw88/ps.c
drivers/net/wireless/realtek/rtw88/util.c
drivers/net/wireless/realtek/rtw88/util.h

index bd7d05e0808483d301f7e3cf7b81c1743b8ddf0d..128e75a81bf3cc98f12d6af61610fd78b2815a4e 100644 (file)
@@ -300,7 +300,7 @@ static void rtw_phy_stat_rssi(struct rtw_dev *rtwdev)
 
        data.rtwdev = rtwdev;
        data.min_rssi = U8_MAX;
-       rtw_iterate_stas_atomic(rtwdev, rtw_phy_stat_rssi_iter, &data);
+       rtw_iterate_stas(rtwdev, rtw_phy_stat_rssi_iter, &data);
 
        dm_info->pre_min_rssi = dm_info->min_rssi;
        dm_info->min_rssi = data.min_rssi;
@@ -544,7 +544,7 @@ static void rtw_phy_ra_info_update(struct rtw_dev *rtwdev)
        if (rtwdev->watch_dog_cnt & 0x3)
                return;
 
-       rtw_iterate_stas_atomic(rtwdev, rtw_phy_ra_info_update_iter, rtwdev);
+       rtw_iterate_stas(rtwdev, rtw_phy_ra_info_update_iter, rtwdev);
 }
 
 static u32 rtw_phy_get_rrsr_mask(struct rtw_dev *rtwdev, u8 rate_idx)
@@ -597,7 +597,7 @@ static void rtw_phy_rrsr_update(struct rtw_dev *rtwdev)
        struct rtw_dm_info *dm_info = &rtwdev->dm_info;
 
        dm_info->rrsr_mask_min = RRSR_RATE_ORDER_MAX;
-       rtw_iterate_stas_atomic(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev);
+       rtw_iterate_stas(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev);
        rtw_write32(rtwdev, REG_RRSR, dm_info->rrsr_val_init & dm_info->rrsr_mask_min);
 }
 
index c93da743681fc51954f635f4c1455f70a6e77196..11594940d6b000295061142c67673f87ef737313 100644 (file)
@@ -61,7 +61,7 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
                return ret;
        }
 
-       rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
+       rtw_iterate_vifs(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
 
        rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
 
index cdfd66a85075aca310fe2069d1896650e3336583..ff3c269fb1a727ca0b1fd0d06cdc0d9f2cc740a4 100644 (file)
@@ -105,3 +105,106 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
                *mcs = rate - DESC_RATEMCS0;
        }
 }
+
+struct rtw_stas_entry {
+       struct list_head list;
+       struct ieee80211_sta *sta;
+};
+
+struct rtw_iter_stas_data {
+       struct rtw_dev *rtwdev;
+       struct list_head list;
+};
+
+static void rtw_collect_sta_iter(void *data, struct ieee80211_sta *sta)
+{
+       struct rtw_iter_stas_data *iter_stas = data;
+       struct rtw_stas_entry *stas_entry;
+
+       stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC);
+       if (!stas_entry)
+               return;
+
+       stas_entry->sta = sta;
+       list_add_tail(&stas_entry->list, &iter_stas->list);
+}
+
+void rtw_iterate_stas(struct rtw_dev *rtwdev,
+                     void (*iterator)(void *data,
+                                      struct ieee80211_sta *sta),
+                     void *data)
+{
+       struct rtw_iter_stas_data iter_data;
+       struct rtw_stas_entry *sta_entry, *tmp;
+
+       /* &rtwdev->mutex makes sure no stations can be removed between
+        * collecting the stations and iterating over them.
+        */
+       lockdep_assert_held(&rtwdev->mutex);
+
+       iter_data.rtwdev = rtwdev;
+       INIT_LIST_HEAD(&iter_data.list);
+
+       ieee80211_iterate_stations_atomic(rtwdev->hw, rtw_collect_sta_iter,
+                                         &iter_data);
+
+       list_for_each_entry_safe(sta_entry, tmp, &iter_data.list,
+                                list) {
+               list_del_init(&sta_entry->list);
+               iterator(data, sta_entry->sta);
+               kfree(sta_entry);
+       }
+}
+
+struct rtw_vifs_entry {
+       struct list_head list;
+       struct ieee80211_vif *vif;
+       u8 mac[ETH_ALEN];
+};
+
+struct rtw_iter_vifs_data {
+       struct rtw_dev *rtwdev;
+       struct list_head list;
+};
+
+static void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct rtw_iter_vifs_data *iter_stas = data;
+       struct rtw_vifs_entry *vifs_entry;
+
+       vifs_entry = kmalloc(sizeof(*vifs_entry), GFP_ATOMIC);
+       if (!vifs_entry)
+               return;
+
+       vifs_entry->vif = vif;
+       ether_addr_copy(vifs_entry->mac, mac);
+       list_add_tail(&vifs_entry->list, &iter_stas->list);
+}
+
+void rtw_iterate_vifs(struct rtw_dev *rtwdev,
+                     void (*iterator)(void *data, u8 *mac,
+                                      struct ieee80211_vif *vif),
+                     void *data)
+{
+       struct rtw_iter_vifs_data iter_data;
+       struct rtw_vifs_entry *vif_entry, *tmp;
+
+       /* &rtwdev->mutex makes sure no interfaces can be removed between
+        * collecting the interfaces and iterating over them.
+        */
+       lockdep_assert_held(&rtwdev->mutex);
+
+       iter_data.rtwdev = rtwdev;
+       INIT_LIST_HEAD(&iter_data.list);
+
+       ieee80211_iterate_active_interfaces_atomic(rtwdev->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  rtw_collect_vif_iter, &iter_data);
+
+       list_for_each_entry_safe(vif_entry, tmp, &iter_data.list,
+                                list) {
+               list_del_init(&vif_entry->list);
+               iterator(data, vif_entry->mac, vif_entry->vif);
+               kfree(vif_entry);
+       }
+}
index 0c23b5069be0badfe8599a5d78647cc7d0c26bf1..dc896552540026a2461e6fbcbca67ee8d7a6082c 100644 (file)
@@ -7,9 +7,6 @@
 
 struct rtw_dev;
 
-#define rtw_iterate_vifs(rtwdev, iterator, data)                               \
-       ieee80211_iterate_active_interfaces(rtwdev->hw,                        \
-                       IEEE80211_IFACE_ITER_NORMAL, iterator, data)
 #define rtw_iterate_vifs_atomic(rtwdev, iterator, data)                        \
        ieee80211_iterate_active_interfaces_atomic(rtwdev->hw,                 \
                        IEEE80211_IFACE_ITER_NORMAL, iterator, data)
@@ -20,6 +17,15 @@ struct rtw_dev;
 #define rtw_iterate_keys_rcu(rtwdev, vif, iterator, data)                     \
        ieee80211_iter_keys_rcu((rtwdev)->hw, vif, iterator, data)
 
+void rtw_iterate_vifs(struct rtw_dev *rtwdev,
+                     void (*iterator)(void *data, u8 *mac,
+                                      struct ieee80211_vif *vif),
+                     void *data);
+void rtw_iterate_stas(struct rtw_dev *rtwdev,
+                     void (*iterator)(void *data,
+                                      struct ieee80211_sta *sta),
+                                      void *data);
+
 static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
 {
        __le16 fc = hdr->frame_control;