Received: by 2002:a05:7412:5112:b0:fa:6e18:a558 with SMTP id fm18csp976884rdb; Wed, 24 Jan 2024 00:27:15 -0800 (PST) X-Google-Smtp-Source: AGHT+IE49730Of30MJP3H03aU9bXMgvkSHWShD0oCNWInkYNZocOcd/n1YlXEwPPhFuHDrehc69b X-Received: by 2002:a05:6902:1005:b0:dc2:22e1:246a with SMTP id w5-20020a056902100500b00dc222e1246amr290352ybt.70.1706084835448; Wed, 24 Jan 2024 00:27:15 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706084835; cv=pass; d=google.com; s=arc-20160816; b=nC+pWtFB2WIz/fTK0sptjjBbUXsODVaZJX3L+jynPiUV/H/CoyLde5wOEg0a5dFAPp 67NBm1mUYzunWg3R4t2ygzxbl+Ijs5+YntTj0pNhW1RVcGlNumj9uQF3uftzN+WhanLT 4RaYvEaOEFN4Vb72F+LR0FsIdVGmFDbwAiN4jK7+5ilgtdQDoeCyazkY/Xl+nckhDhr5 BplwUDObTSZHawnz9M8EVwVe12bAxwZACLPeXKZq0k/6gqNgZwcZDzA4mWQd8yOePk+5 4lX0JEK3wAdI059vo7lPncy3OdhY8Fwkn6iBeoLklTLgna5RWHhsMesR5VDqcpALsEHp +uxA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:date:subject:cc:to :dkim-signature:dkim-signature:from; bh=3ZE6vSjKNJEIkykAa8DptE1tqbkwB3zP1SKxVBzkByk=; fh=KsoNWtazjfstHns8t6UZ1pulwZL69aEO39vRs0LPvyo=; b=UhPentaFw84gjErlstyWnklRysqYeKvMqnfj5DSfccdh5/WM8xwkQLDFJus4ynCq0l FM+Dt7959R+5dkOEQpg6nhSHxcuCf+B8IPsEHw57ZYFLRZJ2EwO5/NLc2xX5PYwprOY/ u0s8koSm/rBQYZk7xV+8tRsG2Dn6HRvwKXZzkfvldvkJ3tPACe0X5hPJA2i/4KODlYV2 FajPzbgd8Z9NCTrua9r6uqKO/lGZ+SjdIEHYSHW/JvegZ5/8gS7yqCfHkyTOLqhktzeg 977f093ILECHzJVIP9ZvTlXeDPOP3X4SgZG9TG6Mbi3ieH+hUPpnya5xZPekXvO7pimd yTeA== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=oSNJEHiA; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e; arc=pass (i=1 spf=pass spfdomain=linutronix.de dkim=pass dkdomain=linutronix.de dmarc=pass fromdomain=linutronix.de); spf=pass (google.com: domain of linux-wireless+bounces-2437-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-wireless+bounces-2437-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id r16-20020a0ccc10000000b0068687624743si7340991qvk.523.2024.01.24.00.27.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Jan 2024 00:27:15 -0800 (PST) Received-SPF: pass (google.com: domain of linux-wireless+bounces-2437-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=oSNJEHiA; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e; arc=pass (i=1 spf=pass spfdomain=linutronix.de dkim=pass dkdomain=linutronix.de dmarc=pass fromdomain=linutronix.de); spf=pass (google.com: domain of linux-wireless+bounces-2437-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-wireless+bounces-2437-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 29B161C216EC for ; Wed, 24 Jan 2024 08:27:15 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 0BA3317585; Wed, 24 Jan 2024 08:27:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="oSNJEHiA"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="7icn8vYI" X-Original-To: linux-wireless@vger.kernel.org Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BB53D1758C for ; Wed, 24 Jan 2024 08:27:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706084833; cv=none; b=l+vdNF2FTEfewCM34dSbJ73TG3BVIXcChbwPHWFL82+wSz6KU3VDKtqFP3xoVdy5yjf98mLJm4vXmbG6R7/kn9Lj2tQaz6zbB9MnGv84h/7+X7usE17lv4IgdD4VpjSCa9P4Op8vOGMUmr9TLwxHZN9iSNKiVZxaMBRIAUzTsj4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706084833; c=relaxed/simple; bh=/k/PR7v6U1O4y+FsW0lNVAQICAbPPffLM7arYqdDi14=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=ASzc8PR6hylrtXZPcrFag0eeq3NtLt2CwN5C6ko5PNKrYEux95pCq/BxbmrsXlkT53uVx4SyfvbfF88iYOw1UJwPcRdDyoIOjcvLyAzIbOwz1N1g53DaJOM4oRuMZ+3YnQhRdl4wkLAX87hAxSKM5k/m5EzR4ipPQRKrpUDcfyc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=oSNJEHiA; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=7icn8vYI; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de From: Martin Kaistra DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1706084829; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=3ZE6vSjKNJEIkykAa8DptE1tqbkwB3zP1SKxVBzkByk=; b=oSNJEHiAT8Xq3iZkn0pXZBwkszedJr6KUv9wcUD2FezfZiqqltITaRyiiFQP95N1JOSWgI m75rNJ68I5Z3XPgT+hkcURdgdcC8CTYknRC9Me0aNjMFhsC1zf6ORcnrq7sxxcXmW+E8i6 9wbWwgmiXE4uOkep6VC7R2q4Njwxv002YOeSLtLBPT5ocF93yhMDQv1ohgql0WGALpG/hD HnHaCbfHMsH/r3eK9E7b1N1bjtrT8qqjzRcbtbKtpaWh1EgJgjpvLMAkre9umEkdS937O2 6OfxB3oMUkUwm+j/WUcQ6BsvGYKagoJTbqc7iZe8R/ndGs5j2TfQVhqD8sEXrg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1706084829; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=3ZE6vSjKNJEIkykAa8DptE1tqbkwB3zP1SKxVBzkByk=; b=7icn8vYItaNQUsQpmtMzuMq/1JSuMiM60YgBf/00DQtZO8RpWFtMGipxhH9sQLzPu7WlZI 4y4bwISx5Q2gPPAg== To: linux-wireless@vger.kernel.org Cc: Jes Sorensen , Kalle Valo , Ping-Ke Shih , Bitterblue Smith , Sebastian Andrzej Siewior Subject: [PATCH v2] wifi: rtl8xxxu: update rate mask per sta Date: Wed, 24 Jan 2024 09:27:05 +0100 Message-Id: <20240124082705.1098960-1-martin.kaistra@linutronix.de> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Until now, rtl8xxxu_watchdog_callback() only fetches RSSI and updates the rate mask in station mode. This means, in AP mode only the default rate mask is used. In order to have the rate mask reflect the actual connection quality, extend rtl8xxxu_watchdog_callback() to iterate over every sta. Like in the rtw88 driver, add a function to collect all currently present stas and then iterate over a list of copies to ensure no RCU lock problems for register access via USB. Remove the existing RCU lock in rtl8xxxu_refresh_rate_mask(). Since the currently used ieee80211_ave_rssi() is only for 'vif', add driver-level tracking of RSSI per sta. Signed-off-by: Martin Kaistra --- changes v1->v2: move 'rssi_level' into struct rtl8xxxu_sta_info v1: https://lore.kernel.org/linux-wireless/20240117145516.497966-1-martin.kaistra@linutronix.de/ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 +- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 187 ++++++++++++++---- 2 files changed, 157 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 03307da67c2c3..fd92d23c43d91 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -6,6 +6,7 @@ */ #include +#include #define RTL8XXXU_DEBUG_REG_WRITE 0x01 #define RTL8XXXU_DEBUG_REG_READ 0x02 @@ -1858,6 +1859,8 @@ struct rtl8xxxu_priv { int next_mbox; int nr_out_eps; + /* Ensure no added or deleted stas while iterating */ + struct mutex sta_mutex; struct mutex h2c_mutex; /* Protect the indirect register accesses of RTL8710BU. */ struct mutex syson_indirect_access_mutex; @@ -1892,7 +1895,6 @@ struct rtl8xxxu_priv { u8 pi_enabled:1; u8 no_pape:1; u8 int_buf[USB_INTR_CONTENT_LENGTH]; - u8 rssi_level; DECLARE_BITMAP(tx_aggr_started, IEEE80211_NUM_TIDS); DECLARE_BITMAP(tid_tx_operational, IEEE80211_NUM_TIDS); @@ -1913,11 +1915,15 @@ struct rtl8xxxu_priv { DECLARE_BITMAP(cam_map, RTL8XXXU_MAX_SEC_CAM_NUM); }; +DECLARE_EWMA(rssi, 10, 16); + struct rtl8xxxu_sta_info { struct ieee80211_sta *sta; struct ieee80211_vif *vif; u8 macid; + struct ewma_rssi avg_rssi; + u8 rssi_level; }; struct rtl8xxxu_vif { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 3b954c2fe448f..3820d3c308759 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4993,8 +4993,8 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct device *dev = &priv->udev->dev; struct ieee80211_sta *sta; struct rtl8xxxu_ra_report *rarpt; + u8 val8, macid; u32 val32; - u8 val8; rarpt = &priv->ra_report; @@ -5004,6 +5004,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_set_linktype(priv, vif->type, rtlvif->port_num); if (vif->cfg.assoc) { + struct rtl8xxxu_sta_info *sta_info; u32 ramask; int sgi = 0; u8 highest_rate; @@ -5017,6 +5018,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rcu_read_unlock(); goto error; } + macid = rtl8xxxu_get_macid(priv, sta); if (sta->deflink.ht_cap.ht_supported) dev_info(dev, "%s: HT supported\n", __func__); @@ -5037,14 +5039,15 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bw = RATE_INFO_BW_40; else bw = RATE_INFO_BW_20; + + sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + sta_info->rssi_level = RTL8XXXU_RATR_STA_INIT; rcu_read_unlock(); rtl8xxxu_update_ra_report(rarpt, highest_rate, sgi, bw); - priv->rssi_level = RTL8XXXU_RATR_STA_INIT; - priv->fops->update_rate_mask(priv, ramask, 0, sgi, - bw == RATE_INFO_BW_40, 0); + bw == RATE_INFO_BW_40, macid); rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); @@ -6317,6 +6320,76 @@ static void rtl8188e_c2hcmd_callback(struct work_struct *work) } } +#define rtl8xxxu_iterate_vifs_atomic(priv, iterator, data) \ + ieee80211_iterate_active_interfaces_atomic((priv)->hw, \ + IEEE80211_IFACE_ITER_NORMAL, iterator, data) + +struct rtl8xxxu_rx_addr_match_data { + struct rtl8xxxu_priv *priv; + struct ieee80211_hdr *hdr; + struct ieee80211_rx_status *rx_status; + u8 *bssid; +}; + +static void rtl8xxxu_rx_addr_match_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct rtl8xxxu_rx_addr_match_data *iter_data = data; + struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr = iter_data->hdr; + struct rtl8xxxu_priv *priv = iter_data->priv; + struct rtl8xxxu_sta_info *sta_info; + struct ieee80211_rx_status *rx_status = iter_data->rx_status; + u8 *bssid = iter_data->bssid; + + if (!ether_addr_equal(vif->bss_conf.bssid, bssid)) + return; + + if (!(ether_addr_equal(vif->addr, hdr->addr1) || + ieee80211_is_beacon(hdr->frame_control))) + return; + + sta = ieee80211_find_sta_by_ifaddr(priv->hw, hdr->addr2, + vif->addr); + if (!sta) + return; + + sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + ewma_rssi_add(&sta_info->avg_rssi, -rx_status->signal); +} + +static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) +{ + __le16 fc = hdr->frame_control; + u8 *bssid; + + if (ieee80211_has_tods(fc)) + bssid = hdr->addr1; + else if (ieee80211_has_fromds(fc)) + bssid = hdr->addr2; + else + bssid = hdr->addr3; + + return bssid; +} + +static void rtl8xxxu_rx_addr_match(struct rtl8xxxu_priv *priv, + struct ieee80211_rx_status *rx_status, + struct ieee80211_hdr *hdr) +{ + struct rtl8xxxu_rx_addr_match_data data = {}; + + if (ieee80211_is_ctl(hdr->frame_control)) + return; + + data.priv = priv; + data.hdr = hdr; + data.rx_status = rx_status; + data.bssid = get_hdr_bssid(hdr); + + rtl8xxxu_iterate_vifs_atomic(priv, rtl8xxxu_rx_addr_match_iter, &data); +} + int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { struct ieee80211_hw *hw = priv->hw; @@ -6376,18 +6449,26 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) skb_queue_tail(&priv->c2hcmd_queue, skb); schedule_work(&priv->c2hcmd_work); } else { + struct ieee80211_hdr *hdr; + phy_stats = (struct rtl8723au_phy_stats *)skb->data; skb_pull(skb, drvinfo_sz + desc_shift); skb_trim(skb, pkt_len); - if (rx_desc->phy_stats) + hdr = (struct ieee80211_hdr *)skb->data; + if (rx_desc->phy_stats) { priv->fops->parse_phystats( priv, rx_status, phy_stats, rx_desc->rxmcs, - (struct ieee80211_hdr *)skb->data, + hdr, rx_desc->crc32 || rx_desc->icverr); + if (!rx_desc->crc32 && !rx_desc->icverr) + rtl8xxxu_rx_addr_match(priv, + rx_status, + hdr); + } rx_status->mactime = rx_desc->tsfl; rx_status->flag |= RX_FLAG_MACTIME_START; @@ -6484,10 +6565,15 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) } else { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - if (rx_desc->phy_stats) + if (rx_desc->phy_stats) { priv->fops->parse_phystats(priv, rx_status, phy_stats, rx_desc->rxmcs, hdr, rx_desc->crc32 || rx_desc->icverr); + if (!rx_desc->crc32 && !rx_desc->icverr) + rtl8xxxu_rx_addr_match(priv, + rx_status, + hdr); + } rx_status->mactime = rx_desc->tsfl; rx_status->flag |= RX_FLAG_MACTIME_START; @@ -7111,6 +7197,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, int signal, struct ieee80211_sta *sta, bool force) { + struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; struct ieee80211_hw *hw = priv->hw; u16 wireless_mode; u8 rssi_level, ratr_idx; @@ -7119,7 +7206,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, u8 go_up_gap = 5; u8 macid = rtl8xxxu_get_macid(priv, sta); - rssi_level = priv->rssi_level; + rssi_level = sta_info->rssi_level; snr = rtl8xxxu_signal_to_snr(signal); snr_thresh_high = RTL8XXXU_SNR_THRESH_HIGH; snr_thresh_low = RTL8XXXU_SNR_THRESH_LOW; @@ -7144,18 +7231,16 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, else rssi_level = RTL8XXXU_RATR_STA_LOW; - if (rssi_level != priv->rssi_level || force) { + if (rssi_level != sta_info->rssi_level || force) { int sgi = 0; u32 rate_bitmap = 0; - rcu_read_lock(); rate_bitmap = (sta->deflink.supp_rates[0] & 0xfff) | (sta->deflink.ht_cap.mcs.rx_mask[0] << 12) | (sta->deflink.ht_cap.mcs.rx_mask[1] << 20); if (sta->deflink.ht_cap.cap & (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20)) sgi = 1; - rcu_read_unlock(); wireless_mode = rtl8xxxu_wireless_mode(hw, sta); switch (wireless_mode) { @@ -7236,7 +7321,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, break; } - priv->rssi_level = rssi_level; + sta_info->rssi_level = rssi_level; priv->fops->update_rate_mask(priv, rate_bitmap, ratr_idx, sgi, txbw_40mhz, macid); } } @@ -7329,40 +7414,60 @@ static void rtl8xxxu_track_cfo(struct rtl8xxxu_priv *priv) rtl8xxxu_set_atc_status(priv, abs(cfo_average) >= CFO_TH_ATC); } -static void rtl8xxxu_watchdog_callback(struct work_struct *work) +static void rtl8xxxu_ra_iter(void *data, struct ieee80211_sta *sta) { - struct ieee80211_vif *vif; - struct rtl8xxxu_priv *priv; - int i; + struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + struct rtl8xxxu_priv *priv = data; + int signal = -ewma_rssi_read(&sta_info->avg_rssi); - priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); - for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) { - vif = priv->vifs[i]; + priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta), + rtl8xxxu_signal_to_snr(signal)); + rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); +} - if (!vif || vif->type != NL80211_IFTYPE_STATION) - continue; +struct rtl8xxxu_stas_entry { + struct list_head list; + struct ieee80211_sta *sta; +}; - int signal; - struct ieee80211_sta *sta; +struct rtl8xxxu_iter_stas_data { + struct rtl8xxxu_priv *priv; + struct list_head list; +}; - rcu_read_lock(); - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); - if (!sta) { - struct device *dev = &priv->udev->dev; +static void rtl8xxxu_collect_sta_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtl8xxxu_iter_stas_data *iter_stas = data; + struct rtl8xxxu_stas_entry *stas_entry; - dev_dbg(dev, "%s: no sta found\n", __func__); - rcu_read_unlock(); - continue; - } - rcu_read_unlock(); + stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC); + if (!stas_entry) + return; - signal = ieee80211_ave_rssi(vif); + stas_entry->sta = sta; + list_add_tail(&stas_entry->list, &iter_stas->list); +} + +static void rtl8xxxu_watchdog_callback(struct work_struct *work) +{ - priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta), - rtl8xxxu_signal_to_snr(signal)); + struct rtl8xxxu_iter_stas_data iter_data; + struct rtl8xxxu_stas_entry *sta_entry, *tmp; + struct rtl8xxxu_priv *priv; + + priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); + iter_data.priv = priv; + INIT_LIST_HEAD(&iter_data.list); - rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); + mutex_lock(&priv->sta_mutex); + ieee80211_iterate_stations_atomic(priv->hw, rtl8xxxu_collect_sta_iter, + &iter_data); + list_for_each_entry_safe(sta_entry, tmp, &iter_data.list, list) { + list_del_init(&sta_entry->list); + rtl8xxxu_ra_iter(priv, sta_entry->sta); + kfree(sta_entry); } + mutex_unlock(&priv->sta_mutex); if (priv->fops->set_crystal_cap) rtl8xxxu_track_cfo(priv); @@ -7504,10 +7609,14 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; + mutex_lock(&priv->sta_mutex); + ewma_rssi_init(&sta_info->avg_rssi); if (vif->type == NL80211_IFTYPE_AP) { sta_info->macid = rtl8xxxu_acquire_macid(priv); - if (sta_info->macid >= RTL8XXXU_MAX_MAC_ID_NUM) + if (sta_info->macid >= RTL8XXXU_MAX_MAC_ID_NUM) { + mutex_unlock(&priv->sta_mutex); return -ENOSPC; + } rtl8xxxu_refresh_rate_mask(priv, 0, sta, true); priv->fops->report_connect(priv, sta_info->macid, H2C_MACID_ROLE_STA, true); @@ -7523,6 +7632,7 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, break; } } + mutex_unlock(&priv->sta_mutex); return 0; } @@ -7534,8 +7644,10 @@ static int rtl8xxxu_sta_remove(struct ieee80211_hw *hw, struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; + mutex_lock(&priv->sta_mutex); if (vif->type == NL80211_IFTYPE_AP) rtl8xxxu_release_macid(priv, sta_info->macid); + mutex_unlock(&priv->sta_mutex); return 0; } @@ -7767,6 +7879,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, mutex_init(&priv->usb_buf_mutex); mutex_init(&priv->syson_indirect_access_mutex); mutex_init(&priv->h2c_mutex); + mutex_init(&priv->sta_mutex); INIT_LIST_HEAD(&priv->tx_urb_free_list); spin_lock_init(&priv->tx_urb_lock); INIT_LIST_HEAD(&priv->rx_urb_pending_list); -- 2.39.2