* [PATCH 2/2] mt76: mt76x02: do not copy beacon skb in mt76x02_mac_set_beacon_enable
From: Lorenzo Bianconi @ 2019-08-01 8:26 UTC (permalink / raw)
To: nbd; +Cc: lorenzo.bianconi, sgruszka, linux-wireless
In-Reply-To: <cover.1564647482.git.lorenzo@kernel.org>
Do not copy beacon skb in mt76x02_mac_set_beacon_enable for usb devices
since it will be done in mt76x02_update_beacon_iter. Moreover squash
mt76x02_mac_set_beacon_enable and __mt76x02_mac_set_beacon_enable since
the latter is run just by mt76x02_mac_set_beacon_enable
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
.../wireless/mediatek/mt76/mt76x02_beacon.c | 61 ++++++++-----------
.../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 +-
2 files changed, 26 insertions(+), 37 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index 089aab74ae99..ae2565071137 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -115,51 +115,40 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
}
EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon);
-static void
-__mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx,
- bool val, struct sk_buff *skb)
-{
- u8 old_mask = dev->mt76.beacon_mask;
- bool en;
- u32 reg;
-
- if (val) {
- dev->mt76.beacon_mask |= BIT(vif_idx);
- if (skb)
- mt76x02_mac_set_beacon(dev, vif_idx, skb);
- } else {
- dev->mt76.beacon_mask &= ~BIT(vif_idx);
- mt76x02_mac_set_beacon(dev, vif_idx, NULL);
- }
-
- if (!!old_mask == !!dev->mt76.beacon_mask)
- return;
-
- en = dev->mt76.beacon_mask;
-
- reg = MT_BEACON_TIME_CFG_BEACON_TX |
- MT_BEACON_TIME_CFG_TBTT_EN |
- MT_BEACON_TIME_CFG_TIMER_EN;
- mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);
- mt76x02_beacon_enable(dev, en);
-}
-
void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
- struct ieee80211_vif *vif, bool val)
+ struct ieee80211_vif *vif, bool enable)
{
- u8 vif_idx = ((struct mt76x02_vif *)vif->drv_priv)->idx;
- struct sk_buff *skb = NULL;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
+ u8 old_mask = dev->mt76.beacon_mask;
mt76x02_pre_tbtt_enable(dev, false);
- if (mt76_is_usb(dev))
- skb = ieee80211_beacon_get(mt76_hw(dev), vif);
-
if (!dev->mt76.beacon_mask)
dev->tbtt_count = 0;
- __mt76x02_mac_set_beacon_enable(dev, vif_idx, val, skb);
+ if (enable) {
+ dev->mt76.beacon_mask |= BIT(mvif->idx);
+ } else {
+ dev->mt76.beacon_mask &= ~BIT(mvif->idx);
+ mt76x02_mac_set_beacon(dev, mvif->idx, NULL);
+ }
+ if (!!old_mask == !!dev->mt76.beacon_mask)
+ goto out;
+
+ if (dev->mt76.beacon_mask)
+ mt76_set(dev, MT_BEACON_TIME_CFG,
+ MT_BEACON_TIME_CFG_BEACON_TX |
+ MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_TIMER_EN);
+ else
+ mt76_clear(dev, MT_BEACON_TIME_CFG,
+ MT_BEACON_TIME_CFG_BEACON_TX |
+ MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_TIMER_EN);
+ mt76x02_beacon_enable(dev, !!dev->mt76.beacon_mask);
+
+out:
mt76x02_pre_tbtt_enable(dev, true);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
index cb39da79527a..4a84db7e8522 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
@@ -207,7 +207,7 @@ void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr);
int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
struct sk_buff *skb);
void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
- struct ieee80211_vif *vif, bool val);
+ struct ieee80211_vif *vif, bool enable);
void mt76x02_edcca_init(struct mt76x02_dev *dev);
#endif
--
2.21.0
^ permalink raw reply related
* [PATCH 1/2] mt76: mt76x02: introduce mt76x02_pre_tbtt_enable and mt76x02_beacon_enable macros
From: Lorenzo Bianconi @ 2019-08-01 8:26 UTC (permalink / raw)
To: nbd; +Cc: lorenzo.bianconi, sgruszka, linux-wireless
In-Reply-To: <cover.1564647482.git.lorenzo@kernel.org>
Improve code readability introducing mt76x02_pre_tbtt_enable and
mt76x02_beacon_enable utility macros
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 4 ++--
drivers/net/wireless/mediatek/mt76/mt76x02.h | 5 +++++
drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c | 7 +++----
drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 4 ++--
4 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
index d7bf7bc15e52..3bc665643e51 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
@@ -14,7 +14,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
int ret;
cancel_delayed_work_sync(&dev->cal_work);
- dev->beacon_ops->pre_tbtt_enable(dev, false);
+ mt76x02_pre_tbtt_enable(dev, false);
if (mt76_is_mmio(dev))
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
@@ -31,7 +31,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
mt76x02_dfs_init_params(dev);
tasklet_enable(&dev->dfs_pd.dfs_tasklet);
}
- dev->beacon_ops->pre_tbtt_enable(dev, true);
+ mt76x02_pre_tbtt_enable(dev, true);
mt76_txq_schedule_all(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index f7fd53a1738a..0d562d8e4be0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -75,6 +75,11 @@ struct mt76x02_beacon_ops {
void (*beacon_enable) (struct mt76x02_dev *, bool);
};
+#define mt76x02_beacon_enable(dev, enable) \
+ (dev)->beacon_ops->beacon_enable((dev), (enable))
+#define mt76x02_pre_tbtt_enable(dev, enable) \
+ (dev)->beacon_ops->pre_tbtt_enable((dev), (enable))
+
struct mt76x02_dev {
struct mt76_dev mt76; /* must be first */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index d61c686e08de..089aab74ae99 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -141,8 +141,7 @@ __mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx,
MT_BEACON_TIME_CFG_TBTT_EN |
MT_BEACON_TIME_CFG_TIMER_EN;
mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);
-
- dev->beacon_ops->beacon_enable(dev, en);
+ mt76x02_beacon_enable(dev, en);
}
void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
@@ -151,7 +150,7 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
u8 vif_idx = ((struct mt76x02_vif *)vif->drv_priv)->idx;
struct sk_buff *skb = NULL;
- dev->beacon_ops->pre_tbtt_enable(dev, false);
+ mt76x02_pre_tbtt_enable(dev, false);
if (mt76_is_usb(dev))
skb = ieee80211_beacon_get(mt76_hw(dev), vif);
@@ -161,7 +160,7 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
__mt76x02_mac_set_beacon_enable(dev, vif_idx, val, skb);
- dev->beacon_ops->pre_tbtt_enable(dev, true);
+ mt76x02_pre_tbtt_enable(dev, true);
}
void
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
index e4dfc3bea3c5..7e9e44b96671 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
@@ -48,7 +48,7 @@ mt76x2u_set_channel(struct mt76x02_dev *dev,
int err;
cancel_delayed_work_sync(&dev->cal_work);
- dev->beacon_ops->pre_tbtt_enable(dev, false);
+ mt76x02_pre_tbtt_enable(dev, false);
mutex_lock(&dev->mt76.mutex);
set_bit(MT76_RESET, &dev->mt76.state);
@@ -64,7 +64,7 @@ mt76x2u_set_channel(struct mt76x02_dev *dev,
clear_bit(MT76_RESET, &dev->mt76.state);
mutex_unlock(&dev->mt76.mutex);
- dev->beacon_ops->pre_tbtt_enable(dev, true);
+ mt76x02_pre_tbtt_enable(dev, true);
mt76_txq_schedule_all(&dev->mt76);
return err;
--
2.21.0
^ permalink raw reply related
* [PATCH 0/2] mt76x02: tidy up beacon shared code
From: Lorenzo Bianconi @ 2019-08-01 8:26 UTC (permalink / raw)
To: nbd; +Cc: lorenzo.bianconi, sgruszka, linux-wireless
Do not copy beacon skb in mt76x02_mac_set_beacon_enable for usb devices
since it will be done in tbtt tasklet. Moreover tidy up a bit beacon
shared code
Lorenzo Bianconi (2):
mt76: mt76x02: introduce mt76x02_pre_tbtt_enable and
mt76x02_beacon_enable macros
mt76: mt76x02: do not copy beacon skb in mt76x02_mac_set_beacon_enable
.../net/wireless/mediatek/mt76/mt76x0/main.c | 4 +-
drivers/net/wireless/mediatek/mt76/mt76x02.h | 5 ++
.../wireless/mediatek/mt76/mt76x02_beacon.c | 66 ++++++++-----------
.../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 +-
.../wireless/mediatek/mt76/mt76x2/usb_main.c | 4 +-
5 files changed, 37 insertions(+), 44 deletions(-)
--
2.21.0
^ permalink raw reply
* [PATCH] mac80211: fix possible sta leak
From: Johannes Berg @ 2019-08-01 7:30 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
If TDLS station addition is rejected, the sta memory is leaked.
Avoid this by moving the check before the allocation.
Fixes: 7ed5285396c2 ("mac80211: don't initiate TDLS connection if station is not associated to AP")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/cfg.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4d458067d80d..111c400199ec 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1546,6 +1546,11 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
if (is_multicast_ether_addr(mac))
return -EINVAL;
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER) &&
+ sdata->vif.type == NL80211_IFTYPE_STATION &&
+ !sdata->u.mgd.associated)
+ return -EINVAL;
+
sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
if (!sta)
return -ENOMEM;
@@ -1553,10 +1558,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
sta->sta.tdls = true;
- if (sta->sta.tdls && sdata->vif.type == NL80211_IFTYPE_STATION &&
- !sdata->u.mgd.associated)
- return -EINVAL;
-
err = sta_apply_parameters(local, sta, params);
if (err) {
sta_info_free(local, sta);
--
2.20.1
^ permalink raw reply related
* [RFCv1 2/2] nl80211: Don't split-dump for clients with large buffers
From: Denis Kenzior @ 2019-08-01 7:14 UTC (permalink / raw)
To: johannes, linux-wireless; +Cc: Denis Kenzior
In-Reply-To: <20190801071455.4974-1-denkenz@gmail.com>
---
net/wireless/nl80211.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6774072e836f..e1707cfd9076 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2496,6 +2496,22 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
rtnl_unlock();
return ret;
}
+
+ /*
+ * auto-detect support for large buffer sizes: af_netlink
+ * will allocate skbufs larger than 4096 in cases where
+ * it detects that the client receive buffer (given to
+ * recvmsg) is bigger. In such cases we can assume that
+ * performing split dumps is wasteful since the client
+ * can likely safely consume the entire un-split wiphy
+ * message in one go without the extra message header
+ * overhead.
+ */
+ if (skb_tailroom(skb) > 4096) {
+ state->large_message = true;
+ state->split = false;
+ }
+
cb->args[0] = (long)state;
}
@@ -2529,6 +2545,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
* We can then retry with the larger buffer.
*/
if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
+ !state->large_message &&
!skb->len && !state->split &&
cb->min_dump_alloc < 4096) {
cb->min_dump_alloc = 4096;
--
2.21.0
^ permalink raw reply related
* [RFCv1 1/2] nl80211: Support >4096 byte NEW_WIPHY event nlmsg
From: Denis Kenzior @ 2019-08-01 7:14 UTC (permalink / raw)
To: johannes, linux-wireless; +Cc: Denis Kenzior
For historical reasons, NEW_WIPHY messages generated by dumps or
GET_WIPHY commands were limited to 4096 bytes due to userspace tools
using limited buffers. Once the sizes NEW_WIPHY messages exceeded these
sizes, split dumps were introduced. All any non-legacy data was added
only to messages using split-dumps (including filtered dumps).
When unsolicited NEW_WIPHY events were introduced they inherited the
4096 byte limitation. These messages thus do not contain any non-legacy
wiphy dump data. This means that userspace still needs to re-dump the
information from the kernel after receiving such NEW_WIPHY event since
some of the information is missing. Thus it is desirable to relax such
restrictions for these messages and include the non-legacy data in these
events.
It should be safe to assume that any users of these new unsolicited
NEW_WIPHY events are non-legacy clients, which can use a
larger receive buffer for netlink messages. Since older, legacy clients
did not utilize NEW_WIPHY events (they did not exist), it is assumed
that even if the client receives such a message (even if truncated), no
harm would result and backwards-compatibility would be kept.
---
net/wireless/nl80211.c | 49 ++++++++++++++++++++++++++++++++++--------
1 file changed, 40 insertions(+), 9 deletions(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1a107f29016b..6774072e836f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1839,6 +1839,7 @@ struct nl80211_dump_wiphy_state {
long start;
long split_start, band_start, chan_start, capa_start;
bool split;
+ bool large_message;
};
static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
@@ -2168,12 +2169,23 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
* helps ensure that newly added capabilities don't break
* older tools by overrunning their buffers.
*
+ * For unsolicited NEW_WIPHY notifications, it is assumed
+ * that the client can handle larger messages. Unsolicited
+ * NEW_WIPHY notifications were added relatively recently
+ * and it is not expected that older tools with limited
+ * buffers would utilize these messages anyway. E.g. even
+ * if the message is truncated, it would not have been
+ * used regardless.
+ *
* We still increment split_start so that in the split
* case we'll continue with more data in the next round,
- * but break unconditionally so unsplit data stops here.
+ * but break unless large_messages are requested, so
+ * legacy unsplit data stops here.
*/
state->split_start++;
- break;
+ if (state->split || !state->large_message)
+ break;
+ /* Fall through */
case 9:
if (rdev->wiphy.extended_capabilities &&
(nla_put(msg, NL80211_ATTR_EXT_CAPA,
@@ -2215,7 +2227,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
}
state->split_start++;
- break;
+ if (state->split)
+ break;
+ /* Fall through */
case 10:
if (nl80211_send_coalesce(msg, rdev))
goto nla_put_failure;
@@ -2231,7 +2245,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
goto nla_put_failure;
state->split_start++;
- break;
+ if (state->split)
+ break;
+ /* Fall through */
case 11:
if (rdev->wiphy.n_vendor_commands) {
const struct nl80211_vendor_cmd_info *info;
@@ -2267,7 +2283,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
nla_nest_end(msg, nested);
}
state->split_start++;
- break;
+ if (state->split)
+ break;
+ /* Fall through */
case 12:
if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -2309,7 +2327,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
}
state->split_start++;
- break;
+ if (state->split)
+ break;
+ /* Fall through */
case 13:
if (rdev->wiphy.num_iftype_ext_capab &&
rdev->wiphy.iftype_ext_capab) {
@@ -2377,13 +2397,17 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
}
state->split_start++;
- break;
+ if (state->split)
+ break;
+ /* Fall through */
case 14:
if (nl80211_send_pmsr_capa(rdev, msg))
goto nla_put_failure;
state->split_start++;
- break;
+ if (state->split)
+ break;
+ /* Fall through */
case 15:
if (rdev->wiphy.akm_suites &&
nla_put(msg, NL80211_ATTR_AKM_SUITES,
@@ -14687,12 +14711,19 @@ void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
enum nl80211_commands cmd)
{
struct sk_buff *msg;
+ size_t alloc_size;
struct nl80211_dump_wiphy_state state = {};
WARN_ON(cmd != NL80211_CMD_NEW_WIPHY &&
cmd != NL80211_CMD_DEL_WIPHY);
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (cmd == NL80211_CMD_NEW_WIPHY) {
+ state.large_message = true;
+ alloc_size = 8192UL;
+ } else
+ alloc_size = NLMSG_DEFAULT_SIZE;
+
+ msg = nlmsg_new(alloc_size, GFP_KERNEL);
if (!msg)
return;
--
2.21.0
^ permalink raw reply related
* Re: [PATCH -next] iwlwifi: dbg: work around clang bug by marking debug strings static
From: Johannes Berg @ 2019-08-01 7:11 UTC (permalink / raw)
To: Michael Ellerman, Nick Desaulniers, kvalo, Luca Coelho
Cc: Arnd Bergmann, Nathan Chancellor, Emmanuel Grumbach,
Intel Linux Wireless, David S. Miller, Shahar S Matityahu,
Sara Sharon, linux-wireless, netdev, linux-kernel,
clang-built-linux
In-Reply-To: <874l31r88y.fsf@concordia.ellerman.id.au>
> Luca, you said this was already fixed in your internal tree, and the fix
> would appear soon in next, but I don't see anything in linux-next?
Luca is still on vacation, but I just sent out a version of the patch we
had applied internally.
Also turns out it wasn't actually _fixed_, just _moved_, so those
internal patches wouldn't have helped anyway.
johannes
^ permalink raw reply
* [PATCH] iwlwifi: dbg_ini: fix compile time assert build errors
From: Johannes Berg @ 2019-08-01 7:04 UTC (permalink / raw)
To: linux-wireless; +Cc: Mauro Rossi
From: Mauro Rossi <issor.oruam@gmail.com>
This patch fixes and preserves existing code style, and readability,
for IWL_ERR() and IWL_WARN() macros invocations recently added in dbg.c
Fixes the following build errors with Android build system:
/home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c: In function '_iwl_fw_dbg_apply_point':
/home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2445:3:
error: call to '__compiletime_assert_2446' declared with attribute error: BUILD_BUG_ON failed: err_str[sizeof(err_str) - 2] != '\n'
/home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2451:3:
error: call to '__compiletime_assert_2452' declared with attribute error: BUILD_BUG_ON failed: err_str[sizeof(err_str) - 2] != '\n'
...
/home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2789:5:
error: call to '__compiletime_assert_2790' declared with attribute error: BUILD_BUG_ON failed: invalid_ap_str[sizeof(invalid_ap_str) - 2] != '\n'
/home/utente/pie-x86_kernel/kernel/drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2800:5:
error: call to '__compiletime_assert_2801' declared with attribute error: BUILD_BUG_ON failed: invalid_ap_str[sizeof(invalid_ap_str) - 2] != '\n'
Fixes: 427ab6385cf3 ("iwlwifi: dbg_ini: enforce apply point early on buffer allocation tlv")
Fixes: 57d88b116175 ("iwlwifi: dbg_ini: support debug info TLV")
Signed-off-by: Mauro Rossi <issor.oruam@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 22 +++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index e411ac98290d..4d81776f576d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -2438,17 +2438,19 @@ static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt,
{
u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);
- const char err_str[] =
- "WRT: ext=%d. Invalid %s name length %d, expected %d\n";
if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
- IWL_WARN(fwrt, err_str, ext, "image", img_name_len,
+ IWL_WARN(fwrt,
+ "WRT: ext=%d. Invalid image name length %d, expected %d\n",
+ ext, img_name_len,
IWL_FW_INI_MAX_IMG_NAME_LEN);
return;
}
if (dbg_cfg_name_len != IWL_FW_INI_MAX_DBG_CFG_NAME_LEN) {
- IWL_WARN(fwrt, err_str, ext, "debug cfg", dbg_cfg_name_len,
+ IWL_WARN(fwrt,
+ "WRT: ext=%d. Invalid debug cfg name length %d, expected %d\n",
+ ext, dbg_cfg_name_len,
IWL_FW_INI_MAX_DBG_CFG_NAME_LEN);
return;
}
@@ -2775,8 +2777,6 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
struct iwl_ucode_tlv *tlv = iter;
void *ini_tlv = (void *)tlv->data;
u32 type = le32_to_cpu(tlv->type);
- const char invalid_ap_str[] =
- "WRT: ext=%d. Invalid apply point %d for %s\n";
switch (type) {
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
@@ -2786,8 +2786,9 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_allocation_data *buf_alloc = ini_tlv;
if (pnt != IWL_FW_INI_APPLY_EARLY) {
- IWL_ERR(fwrt, invalid_ap_str, ext, pnt,
- "buffer allocation");
+ IWL_ERR(fwrt,
+ "WRT: ext=%d. Invalid apply point %d for buffer allocation\n",
+ ext, pnt);
goto next;
}
@@ -2797,8 +2798,9 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
}
case IWL_UCODE_TLV_TYPE_HCMD:
if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
- IWL_ERR(fwrt, invalid_ap_str, ext, pnt,
- "host command");
+ IWL_ERR(fwrt,
+ "WRT: ext=%d. Invalid apply point %d for host command\n",
+ ext, pnt);
goto next;
}
iwl_fw_dbg_send_hcmd(fwrt, tlv, ext);
--
2.20.1
^ permalink raw reply related
* Re: [RFC/RFT] cfg80211: decouple us from the RTNL
From: Sid Hayn @ 2019-08-01 3:59 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Florian Westphal, Johannes Berg
In-Reply-To: <20190731220848.1045-1-johannes@sipsolutions.net>
To give an indication of what this does. I built a small nuc computer
with 13 USB wifi cards and 1 pci-e wifi card. I used kismet to
channel hop every card twice per second while in monitor mode.
Before this patch, the load average of my 4 core nuc was 11-12 (fairly
stable, with actual cpu use fairly low, 2-10%)
After this patch, the load average is 3.5-4 under the same usage
conditions. Quick math suggest this is a very worthwhile improvement.
Interestingly, with the patch I bumped it back up to the default hop
speed of 5 per second and the load average only hit 5-6
I'll leave the code review to those who are much better at this than
I, but hopefully this demonstrates at least some of the need. I have
another computer with ~15 wifi clients connecting and disconnecting
once per minute and it hits D state long enough to time out
connections. I look forward to testing this patch on that system as
well.
Thanks Johannes!
-Zero
On Wed, Jul 31, 2019 at 6:21 PM Johannes Berg <johannes@sipsolutions.net> wrote:
>
> From: Johannes Berg <johannes.berg@intel.com>
>
> Currently, _everything_ in cfg80211 holds the RTNL, and if you
> have a slow USB device (or a few) you can get some bad lock
> contention on that.
>
> Fix that by re-adding a mutex to each wiphy/rdev as we had at
> some point, so we have locking for the wireless_dev lists and
> all the other things in there, and also so that drivers still
> don't have to worry too much about it (they still won't get
> parallel calls for a single device).
>
> Then, we can restrict the RTNL to a few cases where we add or
> remove interfaces and really need the added protection. Some
> of the global list management still also uses the RTNL, since
> we need to have it anyway for netdev management.
>
> TODO:
> - re-read everything a few times to make sure it seems right
> - use wiphy_lock()/wiphy_unlock() in all drivers as the code
> changed in mac80211 does
> - address the FIXME
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> ---
> include/net/cfg80211.h | 24 +-
> net/mac80211/main.c | 2 +
> net/wireless/chan.c | 5 +-
> net/wireless/core.c | 45 +++-
> net/wireless/core.h | 4 +-
> net/wireless/ibss.c | 2 +-
> net/wireless/mlme.c | 6 +-
> net/wireless/nl80211.c | 547 +++++++++++++++++++++--------------------
> net/wireless/sme.c | 1 -
> net/wireless/util.c | 2 +-
> 10 files changed, 353 insertions(+), 285 deletions(-)
>
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index 35ec1f0a2bf9..2ac6cb79f67d 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -4726,6 +4726,25 @@ struct cfg80211_internal_bss;
> struct cfg80211_cached_keys;
> struct cfg80211_cqm_config;
>
> +/**
> + * wiphy_lock - lock the wiphy
> + * @wiphy: the wiphy to lock
> + *
> + * This is mostly exposed so it can be done around registering and
> + * unregistering netdevs that aren't created through cfg80211 calls,
> + * since that requires locking in cfg80211 when the notifiers is
> + * called, but that cannot differentiate which way it's called.
> + *
> + * When cfg80211 ops are called, the wiphy is already locked.
> + */
> +void wiphy_lock(struct wiphy *wiphy);
> +
> +/**
> + * wiphy_unlock - unlock the wiphy again
> + * @wiphy: the wiphy to unlock
> + */
> +void wiphy_unlock(struct wiphy *wiphy);
> +
> /**
> * struct wireless_dev - wireless device state
> *
> @@ -4733,7 +4752,10 @@ struct cfg80211_cqm_config;
> * that uses the ieee80211_ptr field in struct net_device (this
> * is intentional so it can be allocated along with the netdev.)
> * It need not be registered then as netdev registration will
> - * be intercepted by cfg80211 to see the new wireless device.
> + * be intercepted by cfg80211 to see the new wireless device,
> + * however, drivers must lock the wiphy before registering or
> + * unregistering netdevs if they pre-create any netdevs (in ops
> + * called from cfg80211, the wiphy is already locked.)
> *
> * For non-netdev uses, it must also be allocated by the driver
> * in response to the cfg80211 callbacks that require it, as
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 29b9d57df1a3..03fc52587bff 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -1252,8 +1252,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
> !ieee80211_hw_check(hw, NO_AUTO_VIF)) {
> struct vif_params params = {0};
>
> + wiphy_lock(hw->wiphy);
> result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL,
> NL80211_IFTYPE_STATION, ¶ms);
> + wiphy_unlock(hw->wiphy);
> if (result)
> wiphy_warn(local->hw.wiphy,
> "Failed to add default virtual iface\n");
> diff --git a/net/wireless/chan.c b/net/wireless/chan.c
> index 7dc1bbd0888f..ac83c9030c17 100644
> --- a/net/wireless/chan.c
> +++ b/net/wireless/chan.c
> @@ -839,7 +839,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
> struct wireless_dev *wdev;
> struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
>
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
>
> if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
> !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
> @@ -961,9 +961,10 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
> struct cfg80211_chan_def *chandef,
> enum nl80211_iftype iftype)
> {
> + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
> bool check_no_ir;
>
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
>
> /*
> * Under certain conditions suggested by some regulatory bodies a
> diff --git a/net/wireless/core.c b/net/wireless/core.c
> index 742986c73490..2d5bd07ae11f 100644
> --- a/net/wireless/core.c
> +++ b/net/wireless/core.c
> @@ -39,7 +39,7 @@ MODULE_LICENSE("GPL");
> MODULE_DESCRIPTION("wireless configuration support");
> MODULE_ALIAS_GENL_FAMILY(NL80211_GENL_NAME);
>
> -/* RCU-protected (and RTNL for writers) */
> +/* RTNL-protected for writing, RCU-based lookup */
> LIST_HEAD(cfg80211_rdev_list);
> int cfg80211_rdev_list_generation;
>
> @@ -222,7 +222,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
> void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
> struct wireless_dev *wdev)
> {
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
>
> if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
> return;
> @@ -245,7 +245,7 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
> void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
> struct wireless_dev *wdev)
> {
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
>
> if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN))
> return;
> @@ -472,6 +472,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
> }
> }
>
> + mutex_init(&rdev->mtx);
> INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
> INIT_LIST_HEAD(&rdev->beacon_registrations);
> spin_lock_init(&rdev->beacon_registrations_lock);
> @@ -978,21 +979,38 @@ void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
> }
> EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
>
> +void wiphy_lock(struct wiphy *wiphy)
> +{
> + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
> +
> + mutex_lock(&rdev->mtx);
> +}
> +EXPORT_SYMBOL(wiphy_lock);
> +
> +void wiphy_unlock(struct wiphy *wiphy)
> +{
> + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
> +
> + mutex_unlock(&rdev->mtx);
> +}
> +EXPORT_SYMBOL(wiphy_unlock);
> +
> void wiphy_unregister(struct wiphy *wiphy)
> {
> struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
>
> wait_event(rdev->dev_wait, ({
> int __count;
> - rtnl_lock();
> + mutex_lock(&rdev->mtx);
> __count = rdev->opencount;
> - rtnl_unlock();
> + mutex_unlock(&rdev->mtx);
> __count == 0; }));
>
> if (rdev->rfkill)
> rfkill_unregister(rdev->rfkill);
>
> rtnl_lock();
> + mutex_lock(&rdev->mtx);
> nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
> rdev->wiphy.registered = false;
>
> @@ -1015,6 +1033,7 @@ void wiphy_unregister(struct wiphy *wiphy)
> cfg80211_rdev_list_generation++;
> device_del(&rdev->wiphy.dev);
>
> + mutex_unlock(&rdev->mtx);
> rtnl_unlock();
>
> flush_work(&rdev->scan_done_wk);
> @@ -1047,6 +1066,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
> }
> list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
> cfg80211_put_bss(&rdev->wiphy, &scan->pub);
> + mutex_destroy(&rdev->mtx);
> kfree(rdev);
> }
>
> @@ -1125,7 +1145,7 @@ static const struct device_type wiphy_type = {
> void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
> enum nl80211_iftype iftype, int num)
> {
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
>
> rdev->num_running_ifaces += num;
> if (iftype == NL80211_IFTYPE_MONITOR)
> @@ -1138,7 +1158,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
> struct net_device *dev = wdev->netdev;
> struct cfg80211_sched_scan_request *pos, *tmp;
>
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
> ASSERT_WDEV_LOCK(wdev);
>
> cfg80211_pmsr_wdev_down(wdev);
> @@ -1234,6 +1254,9 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev,
> spin_lock_init(&wdev->pmsr_lock);
> INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
>
> + ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
> +
> /*
> * We get here also when the interface changes network namespaces,
> * as it's registered into the new one, but we don't want it to
> @@ -1269,6 +1292,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
> SET_NETDEV_DEVTYPE(dev, &wiphy_type);
> break;
> case NETDEV_REGISTER:
> + lockdep_assert_held(&rdev->mtx);
> /*
> * NB: cannot take rdev->mtx here because this may be
> * called within code protected by it when interfaces
> @@ -1305,9 +1329,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
> cfg80211_init_wdev(rdev, wdev);
> break;
> case NETDEV_GOING_DOWN:
> + mutex_lock(&rdev->mtx);
> cfg80211_leave(rdev, wdev);
> + mutex_unlock(&rdev->mtx);
> break;
> case NETDEV_DOWN:
> + mutex_lock(&rdev->mtx);
> cfg80211_update_iface_num(rdev, wdev->iftype, -1);
> if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
> if (WARN_ON(!rdev->scan_req->notified))
> @@ -1322,9 +1349,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
> }
>
> rdev->opencount--;
> + mutex_unlock(&rdev->mtx);
> wake_up(&rdev->dev_wait);
> break;
> case NETDEV_UP:
> + mutex_lock(&rdev->mtx);
> cfg80211_update_iface_num(rdev, wdev->iftype, 1);
> wdev_lock(wdev);
> switch (wdev->iftype) {
> @@ -1371,8 +1400,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
> /* assume this means it's off */
> wdev->ps = false;
> }
> + mutex_unlock(&rdev->mtx);
> break;
> case NETDEV_UNREGISTER:
> + lockdep_assert_held(&rdev->mtx);
> /*
> * It is possible to get NETDEV_UNREGISTER
> * multiple times. To detect that, check
> diff --git a/net/wireless/core.h b/net/wireless/core.h
> index 77556c58d9ac..9ad586fd7939 100644
> --- a/net/wireless/core.h
> +++ b/net/wireless/core.h
> @@ -25,6 +25,8 @@ struct cfg80211_registered_device {
> const struct cfg80211_ops *ops;
> struct list_head list;
>
> + struct mutex mtx;
> +
> /* rfkill support */
> struct rfkill_ops rfkill_ops;
> struct rfkill *rfkill;
> @@ -231,7 +233,7 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
>
> static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
> {
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
>
> return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
> rdev->num_running_ifaces > 0;
> diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
> index d1743e6abc34..e8d9162f9010 100644
> --- a/net/wireless/ibss.c
> +++ b/net/wireless/ibss.c
> @@ -92,7 +92,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
> struct wireless_dev *wdev = dev->ieee80211_ptr;
> int err;
>
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
> ASSERT_WDEV_LOCK(wdev);
>
> if (wdev->ssid_len)
> diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
> index f9462010575f..808821d521f9 100644
> --- a/net/wireless/mlme.c
> +++ b/net/wireless/mlme.c
> @@ -433,7 +433,7 @@ cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev)
> {
> struct cfg80211_mgmt_registration *reg;
>
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
>
> spin_lock_bh(&rdev->mlme_unreg_lock);
> while ((reg = list_first_entry_or_null(&rdev->mlme_unreg,
> @@ -463,9 +463,9 @@ void cfg80211_mlme_unreg_wk(struct work_struct *wk)
> rdev = container_of(wk, struct cfg80211_registered_device,
> mlme_unreg_wk);
>
> - rtnl_lock();
> + mutex_lock(&rdev->mtx);
> cfg80211_process_mlme_unregistrations(rdev);
> - rtnl_unlock();
> + mutex_unlock(&rdev->mtx);
> }
>
> int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index 1a107f29016b..b79ab55f1f53 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -63,9 +63,9 @@ static const struct genl_multicast_group nl80211_mcgrps[] = {
>
> /* returns ERR_PTR values */
> static struct wireless_dev *
> -__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
> +__cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev,
> + struct net *netns, struct nlattr **attrs)
> {
> - struct cfg80211_registered_device *rdev;
> struct wireless_dev *result = NULL;
> bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
> bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
> @@ -73,8 +73,6 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
> int wiphy_idx = -1;
> int ifidx = -1;
>
> - ASSERT_RTNL();
> -
> if (!have_ifidx && !have_wdev_id)
> return ERR_PTR(-EINVAL);
>
> @@ -85,6 +83,28 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
> wiphy_idx = wdev_id >> 32;
> }
>
> + if (rdev) {
> + struct wireless_dev *wdev;
> +
> + lockdep_assert_held(&rdev->mtx);
> +
> + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
> + if (have_ifidx && wdev->netdev &&
> + wdev->netdev->ifindex == ifidx) {
> + result = wdev;
> + break;
> + }
> + if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
> + result = wdev;
> + break;
> + }
> + }
> +
> + return result ?: ERR_PTR(-ENODEV);
> + }
> +
> + ASSERT_RTNL();
> +
> list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
> struct wireless_dev *wdev;
>
> @@ -775,22 +795,31 @@ int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
> return err;
> }
>
> - *wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
> + rtnl_lock();
> + *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(cb->skb->sk),
> attrbuf);
> kfree(attrbuf);
> - if (IS_ERR(*wdev))
> + if (IS_ERR(*wdev)) {
> + rtnl_unlock();
> return PTR_ERR(*wdev);
> + }
> *rdev = wiphy_to_rdev((*wdev)->wiphy);
> + mutex_lock(&(*rdev)->mtx);
> + rtnl_unlock();
> /* 0 is the first index - add 1 to parse only once */
> cb->args[0] = (*rdev)->wiphy_idx + 1;
> cb->args[1] = (*wdev)->identifier;
> } else {
> /* subtract the 1 again here */
> - struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
> + struct wiphy *wiphy;
> struct wireless_dev *tmp;
>
> - if (!wiphy)
> + rtnl_lock();
> + wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
> + if (!wiphy) {
> + rtnl_unlock();
> return -ENODEV;
> + }
> *rdev = wiphy_to_rdev(wiphy);
> *wdev = NULL;
>
> @@ -801,8 +830,12 @@ int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
> }
> }
>
> - if (!*wdev)
> + if (!*wdev) {
> + rtnl_unlock();
> return -ENODEV;
> + }
> + mutex_lock(&(*rdev)->mtx);
> + rtnl_unlock();
> }
>
> return 0;
> @@ -2791,7 +2824,7 @@ static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
>
> static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
> {
> - struct cfg80211_registered_device *rdev;
> + struct cfg80211_registered_device *rdev = NULL;
> struct net_device *netdev = NULL;
> struct wireless_dev *wdev;
> int result = 0, rem_txq_params = 0;
> @@ -2802,8 +2835,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
> u8 coverage_class = 0;
> u32 txq_limit = 0, txq_memory_limit = 0, txq_quantum = 0;
>
> - ASSERT_RTNL();
> -
> + rtnl_lock();
> /*
> * Try to find the wiphy and netdev. Normally this
> * function shouldn't need the netdev, but this is
> @@ -2827,14 +2859,20 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
> if (!netdev) {
> rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
> info->attrs);
> - if (IS_ERR(rdev))
> + if (IS_ERR(rdev)) {
> + rtnl_unlock();
> return PTR_ERR(rdev);
> + }
> wdev = NULL;
> netdev = NULL;
> result = 0;
> } else
> wdev = netdev->ieee80211_ptr;
>
> + if (rdev)
> + mutex_lock(&rdev->mtx);
> + rtnl_unlock();
> +
> /*
> * end workaround code, by now the rdev is available
> * and locked, and wdev may or may not be NULL.
> @@ -2844,6 +2882,10 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
> result = cfg80211_dev_rename(
> rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
>
> + // FIXME - push this through to all the error paths below
> + if (rdev)
> + mutex_unlock(&rdev->mtx);
> +
> if (result)
> return result;
>
> @@ -3607,6 +3649,17 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
> if (!rdev->ops->del_virtual_intf)
> return -EOPNOTSUPP;
>
> + /*
> + * We hold RTNL, so this is safe, without RTNL opencount cannot
> + * reach 0, and thus the rdev cannot be deleted.
> + *
> + * We need to do it for the dev_close(), since that will call
> + * the netdev notifiers, and we need to acquire the mutex there
> + * but don't know if we get there from here or from some other
> + * place (e.g. "ip link set ... down").
> + */
> + mutex_unlock(&rdev->mtx);
> +
> /*
> * If we remove a wireless device without a netdev then clear
> * user_ptr[1] so that nl80211_post_doit won't dereference it
> @@ -3616,6 +3669,10 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
> */
> if (!wdev->netdev)
> info->user_ptr[1] = NULL;
> + else
> + dev_close(wdev->netdev);
> +
> + mutex_lock(&rdev->mtx);
>
> return rdev_del_virtual_intf(rdev, wdev);
> }
> @@ -5216,10 +5273,9 @@ static int nl80211_dump_station(struct sk_buff *skb,
> int sta_idx = cb->args[2];
> int err;
>
> - rtnl_lock();
> err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
> if (err)
> - goto out_err;
> + return err;
>
> if (!wdev->netdev) {
> err = -EINVAL;
> @@ -5254,7 +5310,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
> cb->args[2] = sta_idx;
> err = skb->len;
> out_err:
> - rtnl_unlock();
> + mutex_unlock(&rdev->mtx);
>
> return err;
> }
> @@ -6099,10 +6155,9 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
> int path_idx = cb->args[2];
> int err;
>
> - rtnl_lock();
> err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
> if (err)
> - goto out_err;
> + return err;
>
> if (!rdev->ops->dump_mpath) {
> err = -EOPNOTSUPP;
> @@ -6135,7 +6190,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
> cb->args[2] = path_idx;
> err = skb->len;
> out_err:
> - rtnl_unlock();
> + mutex_unlock(&rdev->mtx);
> return err;
> }
>
> @@ -6295,10 +6350,9 @@ static int nl80211_dump_mpp(struct sk_buff *skb,
> int path_idx = cb->args[2];
> int err;
>
> - rtnl_lock();
> err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
> if (err)
> - goto out_err;
> + return err;
>
> if (!rdev->ops->dump_mpp) {
> err = -EOPNOTSUPP;
> @@ -6331,7 +6385,7 @@ static int nl80211_dump_mpp(struct sk_buff *skb,
> cb->args[2] = path_idx;
> err = skb->len;
> out_err:
> - rtnl_unlock();
> + mutex_unlock(&rdev->mtx);
> return err;
> }
>
> @@ -6939,12 +6993,15 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
> if (!hdr)
> goto put_failure;
>
> + rtnl_lock();
> +
> if (info->attrs[NL80211_ATTR_WIPHY]) {
> bool self_managed;
>
> rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
> if (IS_ERR(rdev)) {
> nlmsg_free(msg);
> + rtnl_unlock();
> return PTR_ERR(rdev);
> }
>
> @@ -6953,9 +7010,11 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
> REGULATORY_WIPHY_SELF_MANAGED;
> regdom = get_wiphy_regdom(wiphy);
>
> +
> /* a self-managed-reg device must have a private regdom */
> if (WARN_ON(!regdom && self_managed)) {
> nlmsg_free(msg);
> + rtnl_unlock();
> return -EINVAL;
> }
>
> @@ -6980,11 +7039,13 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
> rcu_read_unlock();
>
> genlmsg_end(msg, hdr);
> + rtnl_unlock();
> return genlmsg_reply(msg, info);
>
> nla_put_failure_rcu:
> rcu_read_unlock();
> nla_put_failure:
> + rtnl_unlock();
> put_failure:
> nlmsg_free(msg);
> return -EMSGSIZE;
> @@ -7147,12 +7208,17 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
> return -EINVAL;
> }
>
> - if (!reg_is_valid_request(alpha2))
> - return -EINVAL;
> + rtnl_lock();
> + if (!reg_is_valid_request(alpha2)) {
> + r = -EINVAL;
> + goto out;
> + }
>
> rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
> - if (!rd)
> - return -ENOMEM;
> + if (!rd) {
> + r = -ENOMEM;
> + goto out;
> + }
>
> rd->n_reg_rules = num_rules;
> rd->alpha2[0] = alpha2[0];
> @@ -7184,10 +7250,13 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
> }
> }
>
> + r = set_regdom(rd, REGD_SOURCE_CRDA);
> /* set_regdom takes ownership of rd */
> - return set_regdom(rd, REGD_SOURCE_CRDA);
> + rd = NULL;
> bad_reg:
> kfree(rd);
> + out:
> + rtnl_unlock();
> return r;
> }
> #endif /* CONFIG_CFG80211_CRDA_SUPPORT */
> @@ -8367,10 +8436,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
> struct net_device *dev = info->user_ptr[1];
> struct wireless_dev *wdev = dev->ieee80211_ptr;
> struct cfg80211_csa_settings params;
> - /* csa_attrs is defined static to avoid waste of stack size - this
> - * function is called under RTNL lock, so this should not be a problem.
> - */
> - static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
> + struct nlattr **csa_attrs;
> int err;
> bool need_new_beacon = false;
> bool need_handle_dfs_flag = true;
> @@ -8435,28 +8501,39 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
> if (err)
> return err;
>
> + csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs),
> + GFP_KERNEL);
> + if (!csa_attrs)
> + return -ENOMEM;
> +
> err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
> info->attrs[NL80211_ATTR_CSA_IES],
> nl80211_policy, info->extack);
> if (err)
> - return err;
> + goto free;
>
> err = nl80211_parse_beacon(rdev, csa_attrs, ¶ms.beacon_csa);
> if (err)
> - return err;
> + goto free;
>
> - if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
> - return -EINVAL;
> + if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]) {
> + err = -EINVAL;
> + goto free;
> + }
>
> len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
> - if (!len || (len % sizeof(u16)))
> - return -EINVAL;
> + if (!len || (len % sizeof(u16))) {
> + err = -EINVAL;
> + goto free;
> + }
>
> params.n_counter_offsets_beacon = len / sizeof(u16);
> if (rdev->wiphy.max_num_csa_counters &&
> (params.n_counter_offsets_beacon >
> - rdev->wiphy.max_num_csa_counters))
> - return -EINVAL;
> + rdev->wiphy.max_num_csa_counters)) {
> + err = -EINVAL;
> + goto free;
> + }
>
> params.counter_offsets_beacon =
> nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
> @@ -8465,23 +8542,31 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
> for (i = 0; i < params.n_counter_offsets_beacon; i++) {
> u16 offset = params.counter_offsets_beacon[i];
>
> - if (offset >= params.beacon_csa.tail_len)
> - return -EINVAL;
> + if (offset >= params.beacon_csa.tail_len) {
> + err = -EINVAL;
> + goto free;
> + }
>
> - if (params.beacon_csa.tail[offset] != params.count)
> - return -EINVAL;
> + if (params.beacon_csa.tail[offset] != params.count) {
> + err = -EINVAL;
> + goto free;
> + }
> }
>
> if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
> len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
> - if (!len || (len % sizeof(u16)))
> - return -EINVAL;
> + if (!len || (len % sizeof(u16))) {
> + err = -EINVAL;
> + goto free;
> + }
>
> params.n_counter_offsets_presp = len / sizeof(u16);
> if (rdev->wiphy.max_num_csa_counters &&
> (params.n_counter_offsets_presp >
> - rdev->wiphy.max_num_csa_counters))
> - return -EINVAL;
> + rdev->wiphy.max_num_csa_counters)) {
> + err = -EINVAL;
> + goto free;
> + }
>
> params.counter_offsets_presp =
> nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
> @@ -8490,35 +8575,42 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
> for (i = 0; i < params.n_counter_offsets_presp; i++) {
> u16 offset = params.counter_offsets_presp[i];
>
> - if (offset >= params.beacon_csa.probe_resp_len)
> - return -EINVAL;
> + if (offset >= params.beacon_csa.probe_resp_len) {
> + err = -EINVAL;
> + goto free;
> + }
>
> if (params.beacon_csa.probe_resp[offset] !=
> - params.count)
> - return -EINVAL;
> + params.count) {
> + err = -EINVAL;
> + goto free;
> + }
> }
> }
>
> skip_beacons:
> err = nl80211_parse_chandef(rdev, info, ¶ms.chandef);
> if (err)
> - return err;
> + goto free;
>
> if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
> - wdev->iftype))
> - return -EINVAL;
> + wdev->iftype)) {
> + err = -EINVAL;
> + goto free;
> + }
>
> err = cfg80211_chandef_dfs_required(wdev->wiphy,
> ¶ms.chandef,
> wdev->iftype);
> if (err < 0)
> - return err;
> + goto free;
>
> if (err > 0) {
> params.radar_required = true;
> if (need_handle_dfs_flag &&
> !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
> - return -EINVAL;
> + err = -EINVAL;
> + goto free;
> }
> }
>
> @@ -8529,6 +8621,8 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
> err = rdev_channel_switch(rdev, dev, ¶ms);
> wdev_unlock(wdev);
>
> +free:
> + kfree(csa_attrs);
> return err;
> }
>
> @@ -8677,12 +8771,9 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
> int start = cb->args[2], idx = 0;
> int err;
>
> - rtnl_lock();
> err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
> - if (err) {
> - rtnl_unlock();
> + if (err)
> return err;
> - }
>
> wdev_lock(wdev);
> spin_lock_bh(&rdev->bss_lock);
> @@ -8713,7 +8804,7 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
> wdev_unlock(wdev);
>
> cb->args[2] = idx;
> - rtnl_unlock();
> + mutex_unlock(&rdev->mtx);
>
> return skb->len;
> }
> @@ -8802,10 +8893,11 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
> if (!attrbuf)
> return -ENOMEM;
>
> - rtnl_lock();
> res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
> - if (res)
> - goto out_err;
> + if (res) {
> + kfree(attrbuf);
> + return res;
> + }
>
> /* prepare_wdev_dump parsed the attributes */
> radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
> @@ -8847,7 +8939,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
> res = skb->len;
> out_err:
> kfree(attrbuf);
> - rtnl_unlock();
> + mutex_unlock(&rdev->mtx);
> return res;
> }
>
> @@ -9674,10 +9766,14 @@ EXPORT_SYMBOL(__cfg80211_send_event_skb);
> static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
> {
> struct cfg80211_registered_device *rdev = info->user_ptr[0];
> - struct wireless_dev *wdev =
> - __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
> + struct wireless_dev *wdev;
> int err;
>
> + lockdep_assert_held(&rdev->mtx);
> +
> + wdev = __cfg80211_wdev_from_attrs(rdev, genl_info_net(info),
> + info->attrs);
> +
> if (!rdev->ops->testmode_cmd)
> return -EOPNOTSUPP;
>
> @@ -12817,7 +12913,8 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
> {
> struct cfg80211_registered_device *rdev = info->user_ptr[0];
> struct wireless_dev *wdev =
> - __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
> + __cfg80211_wdev_from_attrs(rdev, genl_info_net(info),
> + info->attrs);
> int i, err;
> u32 vid, subcmd;
>
> @@ -12941,7 +13038,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
> goto out;
> }
>
> - *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
> + *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(skb->sk), attrbuf);
> if (IS_ERR(*wdev))
> *wdev = NULL;
>
> @@ -13723,31 +13820,24 @@ static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info)
> static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
> struct genl_info *info)
> {
> - struct cfg80211_registered_device *rdev;
> + struct cfg80211_registered_device *rdev = NULL;
> struct wireless_dev *wdev;
> struct net_device *dev;
> - bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
> -
> - if (rtnl)
> - rtnl_lock();
>
> + rtnl_lock();
> if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
> rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
> if (IS_ERR(rdev)) {
> - if (rtnl)
> - rtnl_unlock();
> + rtnl_unlock();
> return PTR_ERR(rdev);
> }
> info->user_ptr[0] = rdev;
> } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
> ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
> - ASSERT_RTNL();
> -
> - wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
> + wdev = __cfg80211_wdev_from_attrs(NULL, genl_info_net(info),
> info->attrs);
> if (IS_ERR(wdev)) {
> - if (rtnl)
> - rtnl_unlock();
> + rtnl_unlock();
> return PTR_ERR(wdev);
> }
>
> @@ -13756,8 +13846,7 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
>
> if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
> if (!dev) {
> - if (rtnl)
> - rtnl_unlock();
> + rtnl_unlock();
> return -EINVAL;
> }
>
> @@ -13768,8 +13857,7 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
>
> if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
> !wdev_running(wdev)) {
> - if (rtnl)
> - rtnl_unlock();
> + rtnl_unlock();
> return -ENETDOWN;
> }
>
> @@ -13779,6 +13867,11 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
> info->user_ptr[0] = rdev;
> }
>
> + if (rdev)
> + mutex_lock(&rdev->mtx);
> + if (!(ops->internal_flags & NL80211_FLAG_NEED_RTNL))
> + rtnl_unlock();
> +
> return 0;
> }
>
> @@ -13796,6 +13889,12 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
> }
> }
>
> + if (info->user_ptr[0]) {
> + struct cfg80211_registered_device *rdev = info->user_ptr[0];
> +
> + mutex_unlock(&rdev->mtx);
> + }
> +
> if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
> rtnl_unlock();
>
> @@ -13819,15 +13918,13 @@ static const struct genl_ops nl80211_ops[] = {
> .dumpit = nl80211_dump_wiphy,
> .done = nl80211_dump_wiphy_done,
> /* can be retrieved by unprivileged users */
> - .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WIPHY,
> },
> {
> .cmd = NL80211_CMD_SET_WIPHY,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_wiphy,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_RTNL,
> },
> {
> .cmd = NL80211_CMD_GET_INTERFACE,
> @@ -13835,8 +13932,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_get_interface,
> .dumpit = nl80211_dump_interface,
> /* can be retrieved by unprivileged users */
> - .internal_flags = NL80211_FLAG_NEED_WDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV,
> },
> {
> .cmd = NL80211_CMD_SET_INTERFACE,
> @@ -13867,8 +13963,7 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_get_key,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_KEY,
> @@ -13876,7 +13971,6 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_set_key,
> .flags = GENL_UNS_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -13885,7 +13979,6 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_new_key,
> .flags = GENL_UNS_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -13893,64 +13986,56 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_del_key,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_BEACON,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .flags = GENL_UNS_ADMIN_PERM,
> .doit = nl80211_set_beacon,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_START_AP,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .flags = GENL_UNS_ADMIN_PERM,
> .doit = nl80211_start_ap,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_STOP_AP,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .flags = GENL_UNS_ADMIN_PERM,
> .doit = nl80211_stop_ap,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_GET_STATION,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_get_station,
> .dumpit = nl80211_dump_station,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_SET_STATION,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_station,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_NEW_STATION,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_new_station,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_DEL_STATION,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_del_station,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_GET_MPATH,
> @@ -13958,8 +14043,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_get_mpath,
> .dumpit = nl80211_dump_mpath,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_GET_MPP,
> @@ -13967,47 +14051,42 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_get_mpp,
> .dumpit = nl80211_dump_mpp,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_MPATH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_mpath,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_NEW_MPATH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_new_mpath,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_DEL_MPATH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_del_mpath,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_BSS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_bss,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_GET_REG,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_get_reg_do,
> .dumpit = nl80211_get_reg_dump,
> - .internal_flags = NL80211_FLAG_NEED_RTNL,
> + .internal_flags = 0,
> /* can be retrieved by unprivileged users */
> },
> #ifdef CONFIG_CFG80211_CRDA_SUPPORT
> @@ -14016,7 +14095,7 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_reg,
> .flags = GENL_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_RTNL,
> + .internal_flags = 0,
> },
> #endif
> {
> @@ -14036,32 +14115,28 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_get_mesh_config,
> /* can be retrieved by unprivileged users */
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_MESH_CONFIG,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_update_mesh_config,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_TRIGGER_SCAN,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_trigger_scan,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_ABORT_SCAN,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_abort_scan,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_GET_SCAN,
> @@ -14073,16 +14148,14 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_start_sched_scan,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_STOP_SCHED_SCAN,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_stop_sched_scan,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_AUTHENTICATE,
> @@ -14090,7 +14163,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_authenticate,
> .flags = GENL_UNS_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> + 0 |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -14099,7 +14172,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_associate,
> .flags = GENL_UNS_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> + 0 |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -14107,32 +14180,28 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_deauthenticate,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_DISASSOCIATE,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_disassociate,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_JOIN_IBSS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_join_ibss,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_LEAVE_IBSS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_leave_ibss,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> #ifdef CONFIG_NL80211_TESTMODE
> {
> @@ -14141,8 +14210,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_testmode_do,
> .dumpit = nl80211_testmode_dump,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WIPHY,
> },
> #endif
> {
> @@ -14151,7 +14219,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_connect,
> .flags = GENL_UNS_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> + 0 |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -14160,7 +14228,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_update_connect_params,
> .flags = GENL_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> + 0 |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -14168,16 +14236,14 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_disconnect,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_WIPHY_NETNS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_wiphy_netns,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WIPHY,
> },
> {
> .cmd = NL80211_CMD_GET_SURVEY,
> @@ -14190,7 +14256,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_setdel_pmksa,
> .flags = GENL_UNS_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> + 0 |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -14198,136 +14264,119 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_setdel_pmksa,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_FLUSH_PMKSA,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_flush_pmksa,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_remain_on_channel,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_cancel_remain_on_channel,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_tx_bitrate_mask,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_REGISTER_FRAME,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_register_mgmt,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV,
> },
> {
> .cmd = NL80211_CMD_FRAME,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_tx_mgmt,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_tx_mgmt_cancel_wait,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_POWER_SAVE,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_power_save,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_GET_POWER_SAVE,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_get_power_save,
> /* can be retrieved by unprivileged users */
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_SET_CQM,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_cqm,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_SET_CHANNEL,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_channel,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_SET_WDS_PEER,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_wds_peer,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_JOIN_MESH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_join_mesh,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_LEAVE_MESH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_leave_mesh,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_JOIN_OCB,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_join_ocb,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_LEAVE_OCB,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_leave_ocb,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> #ifdef CONFIG_PM
> {
> @@ -14335,16 +14384,14 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_get_wowlan,
> /* can be retrieved by unprivileged users */
> - .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WIPHY,
> },
> {
> .cmd = NL80211_CMD_SET_WOWLAN,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_wowlan,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WIPHY,
> },
> #endif
> {
> @@ -14353,7 +14400,7 @@ static const struct genl_ops nl80211_ops[] = {
> .doit = nl80211_set_rekey_data,
> .flags = GENL_UNS_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> + 0 |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -14361,128 +14408,112 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_tdls_mgmt,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_TDLS_OPER,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_tdls_oper,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_UNEXPECTED_FRAME,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_register_unexpected_frame,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_PROBE_CLIENT,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_probe_client,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_REGISTER_BEACONS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_register_beacons,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WIPHY,
> },
> {
> .cmd = NL80211_CMD_SET_NOACK_MAP,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_noack_map,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_START_P2P_DEVICE,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_start_p2p_device,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV,
> },
> {
> .cmd = NL80211_CMD_STOP_P2P_DEVICE,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_stop_p2p_device,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_START_NAN,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_start_nan,
> .flags = GENL_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV,
> },
> {
> .cmd = NL80211_CMD_STOP_NAN,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_stop_nan,
> .flags = GENL_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_ADD_NAN_FUNCTION,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_nan_add_func,
> .flags = GENL_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_nan_del_func,
> .flags = GENL_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_nan_change_config,
> .flags = GENL_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_MCAST_RATE,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_mcast_rate,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_SET_MAC_ACL,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_mac_acl,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_RADAR_DETECT,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_start_radar_detection,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
> @@ -14494,47 +14525,41 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_update_ft_ies,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_crit_protocol_start,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_crit_protocol_stop,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_GET_COALESCE,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_get_coalesce,
> - .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WIPHY,
> },
> {
> .cmd = NL80211_CMD_SET_COALESCE,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_coalesce,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WIPHY,
> },
> {
> .cmd = NL80211_CMD_CHANNEL_SWITCH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_channel_switch,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_VENDOR,
> @@ -14543,7 +14568,7 @@ static const struct genl_ops nl80211_ops[] = {
> .dumpit = nl80211_vendor_cmd_dump,
> .flags = GENL_UNS_ADMIN_PERM,
> .internal_flags = NL80211_FLAG_NEED_WIPHY |
> - NL80211_FLAG_NEED_RTNL |
> + 0 |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> @@ -14551,116 +14576,102 @@ static const struct genl_ops nl80211_ops[] = {
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_qos_map,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_ADD_TX_TS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_add_tx_ts,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_DEL_TX_TS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_del_tx_ts,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_tdls_channel_switch,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_tdls_cancel_channel_switch,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_multicast_to_unicast,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_SET_PMK,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_set_pmk,
> .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL |
> + 0 |
> NL80211_FLAG_CLEAR_SKB,
> },
> {
> .cmd = NL80211_CMD_DEL_PMK,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_del_pmk,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_EXTERNAL_AUTH,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_external_auth,
> .flags = GENL_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_CONTROL_PORT_FRAME,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_tx_control_port,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_get_ftm_responder_stats,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV,
> },
> {
> .cmd = NL80211_CMD_PEER_MEASUREMENT_START,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_pmsr_start,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
> },
> {
> .cmd = NL80211_CMD_NOTIFY_RADAR,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> .doit = nl80211_notify_radar_detection,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_UPDATE_OWE_INFO,
> .doit = nl80211_update_owe_info,
> .flags = GENL_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> {
> .cmd = NL80211_CMD_PROBE_MESH_LINK,
> .doit = nl80211_probe_mesh_link,
> .flags = GENL_UNS_ADMIN_PERM,
> - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> - NL80211_FLAG_NEED_RTNL,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
> },
> };
>
> diff --git a/net/wireless/sme.c b/net/wireless/sme.c
> index 7a6c38ddc65a..f6b68685189f 100644
> --- a/net/wireless/sme.c
> +++ b/net/wireless/sme.c
> @@ -67,7 +67,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
> struct cfg80211_scan_request *request;
> int n_channels, err;
>
> - ASSERT_RTNL();
> ASSERT_WDEV_LOCK(wdev);
>
> if (rdev->scan_req || rdev->scan_msg)
> diff --git a/net/wireless/util.c b/net/wireless/util.c
> index 1c39d6a2e850..39587ad2fb48 100644
> --- a/net/wireless/util.c
> +++ b/net/wireless/util.c
> @@ -891,7 +891,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
> {
> struct wireless_dev *wdev;
>
> - ASSERT_RTNL();
> + lockdep_assert_held(&rdev->mtx);
>
> list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
> cfg80211_process_wdev_events(wdev);
> --
> 2.20.1
>
^ permalink raw reply
* Re: [PATCH -next] iwlwifi: dbg: work around clang bug by marking debug strings static
From: Michael Ellerman @ 2019-08-01 1:21 UTC (permalink / raw)
To: Nick Desaulniers, kvalo, Luca Coelho
Cc: Nick Desaulniers, Arnd Bergmann, Nathan Chancellor, Johannes Berg,
Emmanuel Grumbach, Intel Linux Wireless, David S. Miller,
Shahar S Matityahu, Sara Sharon, linux-wireless, netdev,
linux-kernel, clang-built-linux
In-Reply-To: <20190712001708.170259-1-ndesaulniers@google.com>
Nick Desaulniers <ndesaulniers@google.com> writes:
> Commit r353569 in prerelease Clang-9 is producing a linkage failure:
>
> ld: drivers/net/wireless/intel/iwlwifi/fw/dbg.o:
> in function `_iwl_fw_dbg_apply_point':
> dbg.c:(.text+0x827a): undefined reference to `__compiletime_assert_2387'
This breakage is also seen in older GCC versions (v4.6.3 at least):
drivers/net/wireless/intel/iwlwifi/fw/dbg.c: In function 'iwl_fw_dbg_info_apply.isra.10':
drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2445:3: error: call to '__compiletime_assert_2446' declared with attribute error: BUILD_BUG_ON failed: err_str[sizeof(err_str) - 2] != '\n'
drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2451:3: error: call to '__compiletime_assert_2452' declared with attribute error: BUILD_BUG_ON failed: err_str[sizeof(err_str) - 2] != '\n'
drivers/net/wireless/intel/iwlwifi/fw/dbg.c: In function '_iwl_fw_dbg_apply_point':
drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2789:5: error: call to '__compiletime_assert_2790' declared with attribute error: BUILD_BUG_ON failed: invalid_ap_str[sizeof(invalid_ap_str) - 2] != '\n'
drivers/net/wireless/intel/iwlwifi/fw/dbg.c:2800:5: error: call to '__compiletime_assert_2801' declared with attribute error: BUILD_BUG_ON failed: invalid_ap_str[sizeof(invalid_ap_str) - 2] != '\n'
http://kisskb.ellerman.id.au/kisskb/buildresult/13902155/
Luca, you said this was already fixed in your internal tree, and the fix
would appear soon in next, but I don't see anything in linux-next?
cheers
^ permalink raw reply
* [RFC/RFT] cfg80211: decouple us from the RTNL
From: Johannes Berg @ 2019-07-31 22:08 UTC (permalink / raw)
To: linux-wireless; +Cc: Florian Westphal, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Currently, _everything_ in cfg80211 holds the RTNL, and if you
have a slow USB device (or a few) you can get some bad lock
contention on that.
Fix that by re-adding a mutex to each wiphy/rdev as we had at
some point, so we have locking for the wireless_dev lists and
all the other things in there, and also so that drivers still
don't have to worry too much about it (they still won't get
parallel calls for a single device).
Then, we can restrict the RTNL to a few cases where we add or
remove interfaces and really need the added protection. Some
of the global list management still also uses the RTNL, since
we need to have it anyway for netdev management.
TODO:
- re-read everything a few times to make sure it seems right
- use wiphy_lock()/wiphy_unlock() in all drivers as the code
changed in mac80211 does
- address the FIXME
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/cfg80211.h | 24 +-
net/mac80211/main.c | 2 +
net/wireless/chan.c | 5 +-
net/wireless/core.c | 45 +++-
net/wireless/core.h | 4 +-
net/wireless/ibss.c | 2 +-
net/wireless/mlme.c | 6 +-
net/wireless/nl80211.c | 547 +++++++++++++++++++++--------------------
net/wireless/sme.c | 1 -
net/wireless/util.c | 2 +-
10 files changed, 353 insertions(+), 285 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 35ec1f0a2bf9..2ac6cb79f67d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4726,6 +4726,25 @@ struct cfg80211_internal_bss;
struct cfg80211_cached_keys;
struct cfg80211_cqm_config;
+/**
+ * wiphy_lock - lock the wiphy
+ * @wiphy: the wiphy to lock
+ *
+ * This is mostly exposed so it can be done around registering and
+ * unregistering netdevs that aren't created through cfg80211 calls,
+ * since that requires locking in cfg80211 when the notifiers is
+ * called, but that cannot differentiate which way it's called.
+ *
+ * When cfg80211 ops are called, the wiphy is already locked.
+ */
+void wiphy_lock(struct wiphy *wiphy);
+
+/**
+ * wiphy_unlock - unlock the wiphy again
+ * @wiphy: the wiphy to unlock
+ */
+void wiphy_unlock(struct wiphy *wiphy);
+
/**
* struct wireless_dev - wireless device state
*
@@ -4733,7 +4752,10 @@ struct cfg80211_cqm_config;
* that uses the ieee80211_ptr field in struct net_device (this
* is intentional so it can be allocated along with the netdev.)
* It need not be registered then as netdev registration will
- * be intercepted by cfg80211 to see the new wireless device.
+ * be intercepted by cfg80211 to see the new wireless device,
+ * however, drivers must lock the wiphy before registering or
+ * unregistering netdevs if they pre-create any netdevs (in ops
+ * called from cfg80211, the wiphy is already locked.)
*
* For non-netdev uses, it must also be allocated by the driver
* in response to the cfg80211 callbacks that require it, as
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 29b9d57df1a3..03fc52587bff 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1252,8 +1252,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
!ieee80211_hw_check(hw, NO_AUTO_VIF)) {
struct vif_params params = {0};
+ wiphy_lock(hw->wiphy);
result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL,
NL80211_IFTYPE_STATION, ¶ms);
+ wiphy_unlock(hw->wiphy);
if (result)
wiphy_warn(local->hw.wiphy,
"Failed to add default virtual iface\n");
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 7dc1bbd0888f..ac83c9030c17 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -839,7 +839,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
struct wireless_dev *wdev;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
!(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
@@ -961,9 +961,10 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype)
{
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
bool check_no_ir;
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
/*
* Under certain conditions suggested by some regulatory bodies a
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 742986c73490..2d5bd07ae11f 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -39,7 +39,7 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("wireless configuration support");
MODULE_ALIAS_GENL_FAMILY(NL80211_GENL_NAME);
-/* RCU-protected (and RTNL for writers) */
+/* RTNL-protected for writing, RCU-based lookup */
LIST_HEAD(cfg80211_rdev_list);
int cfg80211_rdev_list_generation;
@@ -222,7 +222,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
return;
@@ -245,7 +245,7 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN))
return;
@@ -472,6 +472,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
}
}
+ mutex_init(&rdev->mtx);
INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
INIT_LIST_HEAD(&rdev->beacon_registrations);
spin_lock_init(&rdev->beacon_registrations_lock);
@@ -978,21 +979,38 @@ void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
}
EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
+void wiphy_lock(struct wiphy *wiphy)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+
+ mutex_lock(&rdev->mtx);
+}
+EXPORT_SYMBOL(wiphy_lock);
+
+void wiphy_unlock(struct wiphy *wiphy)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+
+ mutex_unlock(&rdev->mtx);
+}
+EXPORT_SYMBOL(wiphy_unlock);
+
void wiphy_unregister(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
wait_event(rdev->dev_wait, ({
int __count;
- rtnl_lock();
+ mutex_lock(&rdev->mtx);
__count = rdev->opencount;
- rtnl_unlock();
+ mutex_unlock(&rdev->mtx);
__count == 0; }));
if (rdev->rfkill)
rfkill_unregister(rdev->rfkill);
rtnl_lock();
+ mutex_lock(&rdev->mtx);
nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
rdev->wiphy.registered = false;
@@ -1015,6 +1033,7 @@ void wiphy_unregister(struct wiphy *wiphy)
cfg80211_rdev_list_generation++;
device_del(&rdev->wiphy.dev);
+ mutex_unlock(&rdev->mtx);
rtnl_unlock();
flush_work(&rdev->scan_done_wk);
@@ -1047,6 +1066,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
}
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&rdev->wiphy, &scan->pub);
+ mutex_destroy(&rdev->mtx);
kfree(rdev);
}
@@ -1125,7 +1145,7 @@ static const struct device_type wiphy_type = {
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num)
{
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
rdev->num_running_ifaces += num;
if (iftype == NL80211_IFTYPE_MONITOR)
@@ -1138,7 +1158,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
struct net_device *dev = wdev->netdev;
struct cfg80211_sched_scan_request *pos, *tmp;
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
ASSERT_WDEV_LOCK(wdev);
cfg80211_pmsr_wdev_down(wdev);
@@ -1234,6 +1254,9 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev,
spin_lock_init(&wdev->pmsr_lock);
INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
+ ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
+
/*
* We get here also when the interface changes network namespaces,
* as it's registered into the new one, but we don't want it to
@@ -1269,6 +1292,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
SET_NETDEV_DEVTYPE(dev, &wiphy_type);
break;
case NETDEV_REGISTER:
+ lockdep_assert_held(&rdev->mtx);
/*
* NB: cannot take rdev->mtx here because this may be
* called within code protected by it when interfaces
@@ -1305,9 +1329,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
cfg80211_init_wdev(rdev, wdev);
break;
case NETDEV_GOING_DOWN:
+ mutex_lock(&rdev->mtx);
cfg80211_leave(rdev, wdev);
+ mutex_unlock(&rdev->mtx);
break;
case NETDEV_DOWN:
+ mutex_lock(&rdev->mtx);
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
if (WARN_ON(!rdev->scan_req->notified))
@@ -1322,9 +1349,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
}
rdev->opencount--;
+ mutex_unlock(&rdev->mtx);
wake_up(&rdev->dev_wait);
break;
case NETDEV_UP:
+ mutex_lock(&rdev->mtx);
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
wdev_lock(wdev);
switch (wdev->iftype) {
@@ -1371,8 +1400,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
/* assume this means it's off */
wdev->ps = false;
}
+ mutex_unlock(&rdev->mtx);
break;
case NETDEV_UNREGISTER:
+ lockdep_assert_held(&rdev->mtx);
/*
* It is possible to get NETDEV_UNREGISTER
* multiple times. To detect that, check
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 77556c58d9ac..9ad586fd7939 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -25,6 +25,8 @@ struct cfg80211_registered_device {
const struct cfg80211_ops *ops;
struct list_head list;
+ struct mutex mtx;
+
/* rfkill support */
struct rfkill_ops rfkill_ops;
struct rfkill *rfkill;
@@ -231,7 +233,7 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
{
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
rdev->num_running_ifaces > 0;
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index d1743e6abc34..e8d9162f9010 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -92,7 +92,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev = dev->ieee80211_ptr;
int err;
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
ASSERT_WDEV_LOCK(wdev);
if (wdev->ssid_len)
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index f9462010575f..808821d521f9 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -433,7 +433,7 @@ cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev)
{
struct cfg80211_mgmt_registration *reg;
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
spin_lock_bh(&rdev->mlme_unreg_lock);
while ((reg = list_first_entry_or_null(&rdev->mlme_unreg,
@@ -463,9 +463,9 @@ void cfg80211_mlme_unreg_wk(struct work_struct *wk)
rdev = container_of(wk, struct cfg80211_registered_device,
mlme_unreg_wk);
- rtnl_lock();
+ mutex_lock(&rdev->mtx);
cfg80211_process_mlme_unregistrations(rdev);
- rtnl_unlock();
+ mutex_unlock(&rdev->mtx);
}
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1a107f29016b..b79ab55f1f53 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -63,9 +63,9 @@ static const struct genl_multicast_group nl80211_mcgrps[] = {
/* returns ERR_PTR values */
static struct wireless_dev *
-__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
+__cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev,
+ struct net *netns, struct nlattr **attrs)
{
- struct cfg80211_registered_device *rdev;
struct wireless_dev *result = NULL;
bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
@@ -73,8 +73,6 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
int wiphy_idx = -1;
int ifidx = -1;
- ASSERT_RTNL();
-
if (!have_ifidx && !have_wdev_id)
return ERR_PTR(-EINVAL);
@@ -85,6 +83,28 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
wiphy_idx = wdev_id >> 32;
}
+ if (rdev) {
+ struct wireless_dev *wdev;
+
+ lockdep_assert_held(&rdev->mtx);
+
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
+ if (have_ifidx && wdev->netdev &&
+ wdev->netdev->ifindex == ifidx) {
+ result = wdev;
+ break;
+ }
+ if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
+ result = wdev;
+ break;
+ }
+ }
+
+ return result ?: ERR_PTR(-ENODEV);
+ }
+
+ ASSERT_RTNL();
+
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
struct wireless_dev *wdev;
@@ -775,22 +795,31 @@ int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
return err;
}
- *wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
+ rtnl_lock();
+ *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(cb->skb->sk),
attrbuf);
kfree(attrbuf);
- if (IS_ERR(*wdev))
+ if (IS_ERR(*wdev)) {
+ rtnl_unlock();
return PTR_ERR(*wdev);
+ }
*rdev = wiphy_to_rdev((*wdev)->wiphy);
+ mutex_lock(&(*rdev)->mtx);
+ rtnl_unlock();
/* 0 is the first index - add 1 to parse only once */
cb->args[0] = (*rdev)->wiphy_idx + 1;
cb->args[1] = (*wdev)->identifier;
} else {
/* subtract the 1 again here */
- struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
+ struct wiphy *wiphy;
struct wireless_dev *tmp;
- if (!wiphy)
+ rtnl_lock();
+ wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
+ if (!wiphy) {
+ rtnl_unlock();
return -ENODEV;
+ }
*rdev = wiphy_to_rdev(wiphy);
*wdev = NULL;
@@ -801,8 +830,12 @@ int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
}
}
- if (!*wdev)
+ if (!*wdev) {
+ rtnl_unlock();
return -ENODEV;
+ }
+ mutex_lock(&(*rdev)->mtx);
+ rtnl_unlock();
}
return 0;
@@ -2791,7 +2824,7 @@ static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = NULL;
struct net_device *netdev = NULL;
struct wireless_dev *wdev;
int result = 0, rem_txq_params = 0;
@@ -2802,8 +2835,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
u8 coverage_class = 0;
u32 txq_limit = 0, txq_memory_limit = 0, txq_quantum = 0;
- ASSERT_RTNL();
-
+ rtnl_lock();
/*
* Try to find the wiphy and netdev. Normally this
* function shouldn't need the netdev, but this is
@@ -2827,14 +2859,20 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
if (!netdev) {
rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
info->attrs);
- if (IS_ERR(rdev))
+ if (IS_ERR(rdev)) {
+ rtnl_unlock();
return PTR_ERR(rdev);
+ }
wdev = NULL;
netdev = NULL;
result = 0;
} else
wdev = netdev->ieee80211_ptr;
+ if (rdev)
+ mutex_lock(&rdev->mtx);
+ rtnl_unlock();
+
/*
* end workaround code, by now the rdev is available
* and locked, and wdev may or may not be NULL.
@@ -2844,6 +2882,10 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
result = cfg80211_dev_rename(
rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
+ // FIXME - push this through to all the error paths below
+ if (rdev)
+ mutex_unlock(&rdev->mtx);
+
if (result)
return result;
@@ -3607,6 +3649,17 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->del_virtual_intf)
return -EOPNOTSUPP;
+ /*
+ * We hold RTNL, so this is safe, without RTNL opencount cannot
+ * reach 0, and thus the rdev cannot be deleted.
+ *
+ * We need to do it for the dev_close(), since that will call
+ * the netdev notifiers, and we need to acquire the mutex there
+ * but don't know if we get there from here or from some other
+ * place (e.g. "ip link set ... down").
+ */
+ mutex_unlock(&rdev->mtx);
+
/*
* If we remove a wireless device without a netdev then clear
* user_ptr[1] so that nl80211_post_doit won't dereference it
@@ -3616,6 +3669,10 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
*/
if (!wdev->netdev)
info->user_ptr[1] = NULL;
+ else
+ dev_close(wdev->netdev);
+
+ mutex_lock(&rdev->mtx);
return rdev_del_virtual_intf(rdev, wdev);
}
@@ -5216,10 +5273,9 @@ static int nl80211_dump_station(struct sk_buff *skb,
int sta_idx = cb->args[2];
int err;
- rtnl_lock();
err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
if (err)
- goto out_err;
+ return err;
if (!wdev->netdev) {
err = -EINVAL;
@@ -5254,7 +5310,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
cb->args[2] = sta_idx;
err = skb->len;
out_err:
- rtnl_unlock();
+ mutex_unlock(&rdev->mtx);
return err;
}
@@ -6099,10 +6155,9 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
int path_idx = cb->args[2];
int err;
- rtnl_lock();
err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
if (err)
- goto out_err;
+ return err;
if (!rdev->ops->dump_mpath) {
err = -EOPNOTSUPP;
@@ -6135,7 +6190,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
cb->args[2] = path_idx;
err = skb->len;
out_err:
- rtnl_unlock();
+ mutex_unlock(&rdev->mtx);
return err;
}
@@ -6295,10 +6350,9 @@ static int nl80211_dump_mpp(struct sk_buff *skb,
int path_idx = cb->args[2];
int err;
- rtnl_lock();
err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
if (err)
- goto out_err;
+ return err;
if (!rdev->ops->dump_mpp) {
err = -EOPNOTSUPP;
@@ -6331,7 +6385,7 @@ static int nl80211_dump_mpp(struct sk_buff *skb,
cb->args[2] = path_idx;
err = skb->len;
out_err:
- rtnl_unlock();
+ mutex_unlock(&rdev->mtx);
return err;
}
@@ -6939,12 +6993,15 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
if (!hdr)
goto put_failure;
+ rtnl_lock();
+
if (info->attrs[NL80211_ATTR_WIPHY]) {
bool self_managed;
rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
if (IS_ERR(rdev)) {
nlmsg_free(msg);
+ rtnl_unlock();
return PTR_ERR(rdev);
}
@@ -6953,9 +7010,11 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
REGULATORY_WIPHY_SELF_MANAGED;
regdom = get_wiphy_regdom(wiphy);
+
/* a self-managed-reg device must have a private regdom */
if (WARN_ON(!regdom && self_managed)) {
nlmsg_free(msg);
+ rtnl_unlock();
return -EINVAL;
}
@@ -6980,11 +7039,13 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
rcu_read_unlock();
genlmsg_end(msg, hdr);
+ rtnl_unlock();
return genlmsg_reply(msg, info);
nla_put_failure_rcu:
rcu_read_unlock();
nla_put_failure:
+ rtnl_unlock();
put_failure:
nlmsg_free(msg);
return -EMSGSIZE;
@@ -7147,12 +7208,17 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
- if (!reg_is_valid_request(alpha2))
- return -EINVAL;
+ rtnl_lock();
+ if (!reg_is_valid_request(alpha2)) {
+ r = -EINVAL;
+ goto out;
+ }
rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
- if (!rd)
- return -ENOMEM;
+ if (!rd) {
+ r = -ENOMEM;
+ goto out;
+ }
rd->n_reg_rules = num_rules;
rd->alpha2[0] = alpha2[0];
@@ -7184,10 +7250,13 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
}
}
+ r = set_regdom(rd, REGD_SOURCE_CRDA);
/* set_regdom takes ownership of rd */
- return set_regdom(rd, REGD_SOURCE_CRDA);
+ rd = NULL;
bad_reg:
kfree(rd);
+ out:
+ rtnl_unlock();
return r;
}
#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
@@ -8367,10 +8436,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_csa_settings params;
- /* csa_attrs is defined static to avoid waste of stack size - this
- * function is called under RTNL lock, so this should not be a problem.
- */
- static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
+ struct nlattr **csa_attrs;
int err;
bool need_new_beacon = false;
bool need_handle_dfs_flag = true;
@@ -8435,28 +8501,39 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
+ csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs),
+ GFP_KERNEL);
+ if (!csa_attrs)
+ return -ENOMEM;
+
err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
info->attrs[NL80211_ATTR_CSA_IES],
nl80211_policy, info->extack);
if (err)
- return err;
+ goto free;
err = nl80211_parse_beacon(rdev, csa_attrs, ¶ms.beacon_csa);
if (err)
- return err;
+ goto free;
- if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
- return -EINVAL;
+ if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]) {
+ err = -EINVAL;
+ goto free;
+ }
len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
- if (!len || (len % sizeof(u16)))
- return -EINVAL;
+ if (!len || (len % sizeof(u16))) {
+ err = -EINVAL;
+ goto free;
+ }
params.n_counter_offsets_beacon = len / sizeof(u16);
if (rdev->wiphy.max_num_csa_counters &&
(params.n_counter_offsets_beacon >
- rdev->wiphy.max_num_csa_counters))
- return -EINVAL;
+ rdev->wiphy.max_num_csa_counters)) {
+ err = -EINVAL;
+ goto free;
+ }
params.counter_offsets_beacon =
nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
@@ -8465,23 +8542,31 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
for (i = 0; i < params.n_counter_offsets_beacon; i++) {
u16 offset = params.counter_offsets_beacon[i];
- if (offset >= params.beacon_csa.tail_len)
- return -EINVAL;
+ if (offset >= params.beacon_csa.tail_len) {
+ err = -EINVAL;
+ goto free;
+ }
- if (params.beacon_csa.tail[offset] != params.count)
- return -EINVAL;
+ if (params.beacon_csa.tail[offset] != params.count) {
+ err = -EINVAL;
+ goto free;
+ }
}
if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
- if (!len || (len % sizeof(u16)))
- return -EINVAL;
+ if (!len || (len % sizeof(u16))) {
+ err = -EINVAL;
+ goto free;
+ }
params.n_counter_offsets_presp = len / sizeof(u16);
if (rdev->wiphy.max_num_csa_counters &&
(params.n_counter_offsets_presp >
- rdev->wiphy.max_num_csa_counters))
- return -EINVAL;
+ rdev->wiphy.max_num_csa_counters)) {
+ err = -EINVAL;
+ goto free;
+ }
params.counter_offsets_presp =
nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
@@ -8490,35 +8575,42 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
for (i = 0; i < params.n_counter_offsets_presp; i++) {
u16 offset = params.counter_offsets_presp[i];
- if (offset >= params.beacon_csa.probe_resp_len)
- return -EINVAL;
+ if (offset >= params.beacon_csa.probe_resp_len) {
+ err = -EINVAL;
+ goto free;
+ }
if (params.beacon_csa.probe_resp[offset] !=
- params.count)
- return -EINVAL;
+ params.count) {
+ err = -EINVAL;
+ goto free;
+ }
}
}
skip_beacons:
err = nl80211_parse_chandef(rdev, info, ¶ms.chandef);
if (err)
- return err;
+ goto free;
if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
- wdev->iftype))
- return -EINVAL;
+ wdev->iftype)) {
+ err = -EINVAL;
+ goto free;
+ }
err = cfg80211_chandef_dfs_required(wdev->wiphy,
¶ms.chandef,
wdev->iftype);
if (err < 0)
- return err;
+ goto free;
if (err > 0) {
params.radar_required = true;
if (need_handle_dfs_flag &&
!nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
- return -EINVAL;
+ err = -EINVAL;
+ goto free;
}
}
@@ -8529,6 +8621,8 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
err = rdev_channel_switch(rdev, dev, ¶ms);
wdev_unlock(wdev);
+free:
+ kfree(csa_attrs);
return err;
}
@@ -8677,12 +8771,9 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
int start = cb->args[2], idx = 0;
int err;
- rtnl_lock();
err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
- if (err) {
- rtnl_unlock();
+ if (err)
return err;
- }
wdev_lock(wdev);
spin_lock_bh(&rdev->bss_lock);
@@ -8713,7 +8804,7 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
wdev_unlock(wdev);
cb->args[2] = idx;
- rtnl_unlock();
+ mutex_unlock(&rdev->mtx);
return skb->len;
}
@@ -8802,10 +8893,11 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
if (!attrbuf)
return -ENOMEM;
- rtnl_lock();
res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
- if (res)
- goto out_err;
+ if (res) {
+ kfree(attrbuf);
+ return res;
+ }
/* prepare_wdev_dump parsed the attributes */
radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
@@ -8847,7 +8939,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
res = skb->len;
out_err:
kfree(attrbuf);
- rtnl_unlock();
+ mutex_unlock(&rdev->mtx);
return res;
}
@@ -9674,10 +9766,14 @@ EXPORT_SYMBOL(__cfg80211_send_event_skb);
static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
- struct wireless_dev *wdev =
- __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
+ struct wireless_dev *wdev;
int err;
+ lockdep_assert_held(&rdev->mtx);
+
+ wdev = __cfg80211_wdev_from_attrs(rdev, genl_info_net(info),
+ info->attrs);
+
if (!rdev->ops->testmode_cmd)
return -EOPNOTSUPP;
@@ -12817,7 +12913,8 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev =
- __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
+ __cfg80211_wdev_from_attrs(rdev, genl_info_net(info),
+ info->attrs);
int i, err;
u32 vid, subcmd;
@@ -12941,7 +13038,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
goto out;
}
- *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
+ *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(skb->sk), attrbuf);
if (IS_ERR(*wdev))
*wdev = NULL;
@@ -13723,31 +13820,24 @@ static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info)
static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info)
{
- struct cfg80211_registered_device *rdev;
+ struct cfg80211_registered_device *rdev = NULL;
struct wireless_dev *wdev;
struct net_device *dev;
- bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
-
- if (rtnl)
- rtnl_lock();
+ rtnl_lock();
if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
if (IS_ERR(rdev)) {
- if (rtnl)
- rtnl_unlock();
+ rtnl_unlock();
return PTR_ERR(rdev);
}
info->user_ptr[0] = rdev;
} else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
- ASSERT_RTNL();
-
- wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
+ wdev = __cfg80211_wdev_from_attrs(NULL, genl_info_net(info),
info->attrs);
if (IS_ERR(wdev)) {
- if (rtnl)
- rtnl_unlock();
+ rtnl_unlock();
return PTR_ERR(wdev);
}
@@ -13756,8 +13846,7 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
if (!dev) {
- if (rtnl)
- rtnl_unlock();
+ rtnl_unlock();
return -EINVAL;
}
@@ -13768,8 +13857,7 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
!wdev_running(wdev)) {
- if (rtnl)
- rtnl_unlock();
+ rtnl_unlock();
return -ENETDOWN;
}
@@ -13779,6 +13867,11 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
info->user_ptr[0] = rdev;
}
+ if (rdev)
+ mutex_lock(&rdev->mtx);
+ if (!(ops->internal_flags & NL80211_FLAG_NEED_RTNL))
+ rtnl_unlock();
+
return 0;
}
@@ -13796,6 +13889,12 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
}
}
+ if (info->user_ptr[0]) {
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+ mutex_unlock(&rdev->mtx);
+ }
+
if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
rtnl_unlock();
@@ -13819,15 +13918,13 @@ static const struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_wiphy,
.done = nl80211_dump_wiphy_done,
/* can be retrieved by unprivileged users */
- .internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
{
.cmd = NL80211_CMD_SET_WIPHY,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_wiphy,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_GET_INTERFACE,
@@ -13835,8 +13932,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_get_interface,
.dumpit = nl80211_dump_interface,
/* can be retrieved by unprivileged users */
- .internal_flags = NL80211_FLAG_NEED_WDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV,
},
{
.cmd = NL80211_CMD_SET_INTERFACE,
@@ -13867,8 +13963,7 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_get_key,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_SET_KEY,
@@ -13876,7 +13971,6 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_set_key,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -13885,7 +13979,6 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_new_key,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -13893,64 +13986,56 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_del_key,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_SET_BEACON,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = nl80211_set_beacon,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_START_AP,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = nl80211_start_ap,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_STOP_AP,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = nl80211_stop_ap,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_GET_STATION,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_get_station,
.dumpit = nl80211_dump_station,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_SET_STATION,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_station,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_NEW_STATION,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_new_station,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_DEL_STATION,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_del_station,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_GET_MPATH,
@@ -13958,8 +14043,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_get_mpath,
.dumpit = nl80211_dump_mpath,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_GET_MPP,
@@ -13967,47 +14051,42 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_get_mpp,
.dumpit = nl80211_dump_mpp,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_SET_MPATH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_mpath,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_NEW_MPATH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_new_mpath,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_DEL_MPATH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_del_mpath,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_SET_BSS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_bss,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_GET_REG,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_get_reg_do,
.dumpit = nl80211_get_reg_dump,
- .internal_flags = NL80211_FLAG_NEED_RTNL,
+ .internal_flags = 0,
/* can be retrieved by unprivileged users */
},
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
@@ -14016,7 +14095,7 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_reg,
.flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_RTNL,
+ .internal_flags = 0,
},
#endif
{
@@ -14036,32 +14115,28 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_get_mesh_config,
/* can be retrieved by unprivileged users */
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_SET_MESH_CONFIG,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_update_mesh_config,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_TRIGGER_SCAN,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_trigger_scan,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_ABORT_SCAN,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_abort_scan,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_GET_SCAN,
@@ -14073,16 +14148,14 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_start_sched_scan,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_STOP_SCHED_SCAN,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_stop_sched_scan,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_AUTHENTICATE,
@@ -14090,7 +14163,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_authenticate,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
+ 0 |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -14099,7 +14172,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_associate,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
+ 0 |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -14107,32 +14180,28 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_deauthenticate,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_DISASSOCIATE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_disassociate,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_JOIN_IBSS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_join_ibss,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_LEAVE_IBSS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_leave_ibss,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
#ifdef CONFIG_NL80211_TESTMODE
{
@@ -14141,8 +14210,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_testmode_do,
.dumpit = nl80211_testmode_dump,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
#endif
{
@@ -14151,7 +14219,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_connect,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
+ 0 |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -14160,7 +14228,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_update_connect_params,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
+ 0 |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -14168,16 +14236,14 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_disconnect,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_SET_WIPHY_NETNS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_wiphy_netns,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
{
.cmd = NL80211_CMD_GET_SURVEY,
@@ -14190,7 +14256,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_setdel_pmksa,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
+ 0 |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -14198,136 +14264,119 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_setdel_pmksa,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_FLUSH_PMKSA,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_flush_pmksa,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_remain_on_channel,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_cancel_remain_on_channel,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_tx_bitrate_mask,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_REGISTER_FRAME,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_register_mgmt,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV,
},
{
.cmd = NL80211_CMD_FRAME,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_tx_mgmt,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_tx_mgmt_cancel_wait,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_SET_POWER_SAVE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_power_save,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_GET_POWER_SAVE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_get_power_save,
/* can be retrieved by unprivileged users */
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_SET_CQM,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_cqm,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_SET_CHANNEL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_channel,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_SET_WDS_PEER,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_wds_peer,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_JOIN_MESH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_join_mesh,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_LEAVE_MESH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_leave_mesh,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_JOIN_OCB,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_join_ocb,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_LEAVE_OCB,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_leave_ocb,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
#ifdef CONFIG_PM
{
@@ -14335,16 +14384,14 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_get_wowlan,
/* can be retrieved by unprivileged users */
- .internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
{
.cmd = NL80211_CMD_SET_WOWLAN,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_wowlan,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
#endif
{
@@ -14353,7 +14400,7 @@ static const struct genl_ops nl80211_ops[] = {
.doit = nl80211_set_rekey_data,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
+ 0 |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -14361,128 +14408,112 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_tdls_mgmt,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_TDLS_OPER,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_tdls_oper,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_UNEXPECTED_FRAME,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_register_unexpected_frame,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_PROBE_CLIENT,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_probe_client,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_REGISTER_BEACONS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_register_beacons,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
{
.cmd = NL80211_CMD_SET_NOACK_MAP,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_noack_map,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_START_P2P_DEVICE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_start_p2p_device,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV,
},
{
.cmd = NL80211_CMD_STOP_P2P_DEVICE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_stop_p2p_device,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_START_NAN,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_start_nan,
.flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV,
},
{
.cmd = NL80211_CMD_STOP_NAN,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_stop_nan,
.flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_ADD_NAN_FUNCTION,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_nan_add_func,
.flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_DEL_NAN_FUNCTION,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_nan_del_func,
.flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_nan_change_config,
.flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_SET_MCAST_RATE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_mcast_rate,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_SET_MAC_ACL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_mac_acl,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_RADAR_DETECT,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_start_radar_detection,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
@@ -14494,47 +14525,41 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_update_ft_ies,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_CRIT_PROTOCOL_START,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_crit_protocol_start,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_crit_protocol_stop,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_GET_COALESCE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_get_coalesce,
- .internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
{
.cmd = NL80211_CMD_SET_COALESCE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_coalesce,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY,
},
{
.cmd = NL80211_CMD_CHANNEL_SWITCH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_channel_switch,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_VENDOR,
@@ -14543,7 +14568,7 @@ static const struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_vendor_cmd_dump,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY |
- NL80211_FLAG_NEED_RTNL |
+ 0 |
NL80211_FLAG_CLEAR_SKB,
},
{
@@ -14551,116 +14576,102 @@ static const struct genl_ops nl80211_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_qos_map,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_ADD_TX_TS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_add_tx_ts,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_DEL_TX_TS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_del_tx_ts,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_tdls_channel_switch,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_tdls_cancel_channel_switch,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_multicast_to_unicast,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_SET_PMK,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_pmk,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL |
+ 0 |
NL80211_FLAG_CLEAR_SKB,
},
{
.cmd = NL80211_CMD_DEL_PMK,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_del_pmk,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_EXTERNAL_AUTH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_external_auth,
.flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_CONTROL_PORT_FRAME,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_tx_control_port,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_get_ftm_responder_stats,
- .internal_flags = NL80211_FLAG_NEED_NETDEV |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV,
},
{
.cmd = NL80211_CMD_PEER_MEASUREMENT_START,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_pmsr_start,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
},
{
.cmd = NL80211_CMD_NOTIFY_RADAR,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_notify_radar_detection,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_UPDATE_OWE_INFO,
.doit = nl80211_update_owe_info,
.flags = GENL_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
{
.cmd = NL80211_CMD_PROBE_MESH_LINK,
.doit = nl80211_probe_mesh_link,
.flags = GENL_UNS_ADMIN_PERM,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NEED_RTNL,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
},
};
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 7a6c38ddc65a..f6b68685189f 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -67,7 +67,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
struct cfg80211_scan_request *request;
int n_channels, err;
- ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev);
if (rdev->scan_req || rdev->scan_msg)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 1c39d6a2e850..39587ad2fb48 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -891,7 +891,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
{
struct wireless_dev *wdev;
- ASSERT_RTNL();
+ lockdep_assert_held(&rdev->mtx);
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
cfg80211_process_wdev_events(wdev);
--
2.20.1
^ permalink raw reply related
* [PATCH] staging: wilc1000: remove unused function
From: Adham.Abozaeid @ 2019-07-31 21:01 UTC (permalink / raw)
To: linux-wireless; +Cc: devel, gregkh, johannes, Ajay.Kathat, Adham.Abozaeid
From: Adham Abozaeid <adham.abozaeid@microchip.com>
function wilc_resolve_disconnect_aberration isn't referenced, so
removing it
Signed-off-by: Adham Abozaeid <adham.abozaeid@microchip.com>
---
drivers/staging/wilc1000/wilc_hif.c | 9 ---------
drivers/staging/wilc1000/wilc_hif.h | 1 -
2 files changed, 10 deletions(-)
diff --git a/drivers/staging/wilc1000/wilc_hif.c b/drivers/staging/wilc1000/wilc_hif.c
index ca252a43cd8c..4d809804c784 100644
--- a/drivers/staging/wilc1000/wilc_hif.c
+++ b/drivers/staging/wilc1000/wilc_hif.c
@@ -798,15 +798,6 @@ int wilc_disconnect(struct wilc_vif *vif)
return 0;
}
-void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
-{
- if (!vif->hif_drv)
- return;
- if (vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
- vif->hif_drv->hif_state == HOST_IF_CONNECTING)
- wilc_disconnect(vif);
-}
-
int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
{
struct wid wid_list[5];
diff --git a/drivers/staging/wilc1000/wilc_hif.h b/drivers/staging/wilc1000/wilc_hif.h
index 3bc305151651..ac5fe57f872b 100644
--- a/drivers/staging/wilc1000/wilc_hif.h
+++ b/drivers/staging/wilc1000/wilc_hif.h
@@ -222,7 +222,6 @@ void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
u8 ifc_id);
int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
-void wilc_resolve_disconnect_aberration(struct wilc_vif *vif);
int wilc_get_vif_idx(struct wilc_vif *vif);
int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
--
2.17.1
^ permalink raw reply related
* [PATCH] staging: wilc1000: merge drv_handle and operation_mode wids
From: Adham.Abozaeid @ 2019-07-31 20:58 UTC (permalink / raw)
To: linux-wireless; +Cc: devel, gregkh, johannes, Ajay.Kathat, Adham.Abozaeid
From: Adham Abozaeid <adham.abozaeid@microchip.com>
wilc_set_wfi_drv_handler and wilc_set_operation_mode sends the same
parameters to the FW, so it's better to combine them together.
Kept wilc_set_wfi_drv_handler implementation since it sends all the
required parameters, and renamed it to wilc_set_operation_mode to be
more descriptive.
Signed-off-by: Adham Abozaeid <adham.abozaeid@microchip.com>
---
drivers/staging/wilc1000/wilc_hif.c | 29 ++-----------------
drivers/staging/wilc1000/wilc_hif.h | 5 ++--
drivers/staging/wilc1000/wilc_netdev.c | 6 ++--
.../staging/wilc1000/wilc_wfi_cfgoperations.c | 24 +++++++--------
drivers/staging/wilc1000/wilc_wlan_if.h | 3 +-
5 files changed, 20 insertions(+), 47 deletions(-)
diff --git a/drivers/staging/wilc1000/wilc_hif.c b/drivers/staging/wilc1000/wilc_hif.c
index f8646ea3b0c4..ca252a43cd8c 100644
--- a/drivers/staging/wilc1000/wilc_hif.c
+++ b/drivers/staging/wilc1000/wilc_hif.c
@@ -1409,18 +1409,15 @@ int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
return result;
}
-int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
- u8 ifc_id)
+int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id)
{
struct wid wid;
- struct host_if_drv *hif_drv = vif->hif_drv;
int result;
struct wilc_drv_handler drv;
- if (!hif_drv)
- return -EFAULT;
- wid.id = WID_SET_DRV_HANDLER;
+ wid.id = WID_SET_OPERATION_MODE;
wid.type = WID_STR;
wid.size = sizeof(drv);
wid.val = (u8 *)&drv;
@@ -1435,26 +1432,6 @@ int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
return result;
}
-int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
-{
- struct wid wid;
- struct wilc_op_mode op_mode;
- int result;
-
- wid.id = WID_SET_OPERATION_MODE;
- wid.type = WID_INT;
- wid.size = sizeof(op_mode);
- wid.val = (u8 *)&op_mode;
-
- op_mode.mode = cpu_to_le32(mode);
-
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
- if (result)
- netdev_err(vif->ndev, "Failed to set operation mode\n");
-
- return result;
-}
-
s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
{
struct wid wid;
diff --git a/drivers/staging/wilc1000/wilc_hif.h b/drivers/staging/wilc1000/wilc_hif.h
index be1d2497cde9..3bc305151651 100644
--- a/drivers/staging/wilc1000/wilc_hif.h
+++ b/drivers/staging/wilc1000/wilc_hif.h
@@ -219,9 +219,8 @@ int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
void *user_arg);
int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
-int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
- u8 ifc_id);
-int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode);
+int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
+ u8 ifc_id);
int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats);
void wilc_resolve_disconnect_aberration(struct wilc_vif *vif);
int wilc_get_vif_idx(struct wilc_vif *vif);
diff --git a/drivers/staging/wilc1000/wilc_netdev.c b/drivers/staging/wilc1000/wilc_netdev.c
index 68129a0ba55f..bd848fdf7f8a 100644
--- a/drivers/staging/wilc1000/wilc_netdev.c
+++ b/drivers/staging/wilc1000/wilc_netdev.c
@@ -626,10 +626,8 @@ static int wilc_mac_open(struct net_device *ndev)
return ret;
}
- wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), vif->iftype,
- vif->idx);
- wilc_set_operation_mode(vif, vif->iftype);
-
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ vif->iftype, vif->idx);
wilc_get_mac_address(vif, mac_add);
netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
ether_addr_copy(ndev->dev_addr, mac_add);
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
index e2d9efed36b0..cf661e8ab1c8 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
@@ -1419,7 +1419,8 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)
wilc_wfi_deinit_mon_interface(wl, true);
vif->iftype = WILC_STATION_MODE;
- wilc_set_operation_mode(vif, WILC_STATION_MODE);
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_STATION_MODE, vif->idx);
memset(priv->assoc_stainfo.sta_associated_bss, 0,
WILC_MAX_NUM_STA * ETH_ALEN);
@@ -1431,8 +1432,8 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
priv->wdev.iftype = type;
vif->monitor_flag = 0;
vif->iftype = WILC_CLIENT_MODE;
- wilc_set_operation_mode(vif, WILC_STATION_MODE);
-
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_STATION_MODE, vif->idx);
break;
case NL80211_IFTYPE_AP:
@@ -1440,18 +1441,17 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
priv->wdev.iftype = type;
vif->iftype = WILC_AP_MODE;
- if (wl->initialized) {
- wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
- 0, vif->idx);
- wilc_set_operation_mode(vif, WILC_AP_MODE);
- }
+ if (wl->initialized)
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_AP_MODE, vif->idx);
break;
case NL80211_IFTYPE_P2P_GO:
- wilc_set_operation_mode(vif, WILC_AP_MODE);
dev->ieee80211_ptr->iftype = type;
priv->wdev.iftype = type;
vif->iftype = WILC_GO_MODE;
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
+ WILC_AP_MODE, vif->idx);
break;
default:
@@ -1659,15 +1659,15 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
vif->monitor_flag = 0;
mutex_lock(&wl->vif_mutex);
- wilc_set_wfi_drv_handler(vif, 0, 0, 0);
- for (i = vif->idx; i < wl->vif_num ; i++) {
+ wilc_set_operation_mode(vif, 0, 0, 0);
+ for (i = vif->idx; i < wl->vif_num; i++) {
if ((i + 1) >= wl->vif_num) {
wl->vif[i] = NULL;
} else {
vif = wl->vif[i + 1];
vif->idx = i;
wl->vif[i] = vif;
- wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
vif->iftype, vif->idx);
}
}
diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h
index b89d0e0f04cc..70eac586f80c 100644
--- a/drivers/staging/wilc1000/wilc_wlan_if.h
+++ b/drivers/staging/wilc1000/wilc_wlan_if.h
@@ -724,7 +724,6 @@ enum {
/* NMAC Integer WID list */
/* Custom Integer WID list */
WID_GET_INACTIVE_TIME = 0x2084,
- WID_SET_OPERATION_MODE = 0X2086,
/* EMAC String WID list */
WID_SSID = 0x3000,
WID_FIRMWARE_VERSION = 0x3001,
@@ -755,9 +754,9 @@ enum {
WID_MODEL_NAME = 0x3027, /*Added for CAPI tool */
WID_MODEL_NUM = 0x3028, /*Added for CAPI tool */
WID_DEVICE_NAME = 0x3029, /*Added for CAPI tool */
- WID_SET_DRV_HANDLER = 0x3079,
/* NMAC String WID list */
+ WID_SET_OPERATION_MODE = 0x3079,
WID_11N_P_ACTION_REQ = 0x3080,
WID_HUT_TEST_ID = 0x3081,
WID_PMKID_INFO = 0x3082,
--
2.17.1
^ permalink raw reply related
* Re: pull-request: mac80211-next 2019-07-31
From: David Miller @ 2019-07-31 16:00 UTC (permalink / raw)
To: johannes; +Cc: netdev, linux-wireless
In-Reply-To: <20190731155057.23035-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes@sipsolutions.net>
Date: Wed, 31 Jul 2019 17:50:56 +0200
> There's a fair number of changes here, so I thought I'd get them out.
> I've included two Intel driver cleanups because Luca is on vacation,
> I'm covering for him, and doing it all in one tree let me merge all
> of the patches at once (including mac80211 that depends on that);
> Kalle is aware.
>
> Also, though this isn't very interesting yet, I've started looking at
> weaning the wireless subsystem off the RTNL for all operations, as it
> can cause significant lock contention, especially with slow USB devices.
> The real patches for that are some way off, but one preparation here is
> to use generic netlink's parallel_ops=true, to avoid trading one place
> with contention for another in the future, and to avoid adding more
> genl_family_attrbuf() usage (since that's no longer possible with the
> parallel_ops setting).
>
> Please pull and let me know if there's any problem.
Pulled, thanks Johannes.
I'm sure people like Florian Westphal will also appreciate your RTNL
elimination work...
^ permalink raw reply
* Re: pull-request: mac80211 2019-07-31
From: David Miller @ 2019-07-31 15:51 UTC (permalink / raw)
To: johannes; +Cc: netdev, linux-wireless
In-Reply-To: <20190731124933.19420-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes@sipsolutions.net>
Date: Wed, 31 Jul 2019 14:49:32 +0200
> We have few fixes, most importantly probably the NETIF_F_LLTX revert,
> we thought we were now more layered like VLAN or such since we do all
> of the queue control internally, but it caused problems, evidently not.
>
> Please pull and let me know if there's any problem.
Pulled, thanks Johannes.
^ permalink raw reply
* pull-request: mac80211-next 2019-07-31
From: Johannes Berg @ 2019-07-31 15:50 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-wireless
Hi Dave,
There's a fair number of changes here, so I thought I'd get them out.
I've included two Intel driver cleanups because Luca is on vacation,
I'm covering for him, and doing it all in one tree let me merge all
of the patches at once (including mac80211 that depends on that);
Kalle is aware.
Also, though this isn't very interesting yet, I've started looking at
weaning the wireless subsystem off the RTNL for all operations, as it
can cause significant lock contention, especially with slow USB devices.
The real patches for that are some way off, but one preparation here is
to use generic netlink's parallel_ops=true, to avoid trading one place
with contention for another in the future, and to avoid adding more
genl_family_attrbuf() usage (since that's no longer possible with the
parallel_ops setting).
Please pull and let me know if there's any problem.
Thanks,
johannes
The following changes since commit 00c33afbf9dd06f77a2f15117cd4bdc2a54b51d7:
net: mvneta: use devm_platform_ioremap_resource() to simplify code (2019-07-25 17:28:11 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git tags/mac80211-next-for-davem-2019-07-31
for you to fetch changes up to f39b07fdfb688724fedabf5507e15eaf398f2500:
mac80211: HE STA disassoc due to QOS NULL not sent (2019-07-31 13:26:41 +0200)
----------------------------------------------------------------
We have a reasonably large number of changes:
* lots more HE (802.11ax) support, particularly things
relevant for the the AP side, but also mesh support
* debugfs cleanups from Greg
* some more work on extended key ID
* start using genl parallel_ops, as preparation for
weaning ourselves off RTNL and getting parallelism
* various other changes all over
----------------------------------------------------------------
Alexander Wetzel (3):
mac80211_hwsim: Extended Key ID API update
mac80211: Simplify Extended Key ID API
mac80211: AMPDU handling for rekeys with Extended Key ID
Ard Biesheuvel (1):
lib80211: use crypto API ccm(aes) transform for CCMP processing
Christophe JAILLET (1):
mac80211_hwsim: Fix a typo in the name of function 'mac80211_hswim_he_capab()'
Colin Ian King (1):
mac80211: add missing null return check from call to ieee80211_get_sband
Denis Kenzior (2):
nl80211: document uapi for CMD_FRAME_WAIT_CANCEL
nl80211: Include wiphy address setup in NEW_WIPHY
Emmanuel Grumbach (1):
mac80211: pass the vif to cancel_remain_on_channel
Erik Stromdahl (1):
mac80211: add tx dequeue function for process context
Greg Kroah-Hartman (4):
iwlwifi: dvm: no need to check return value of debugfs_create functions
iwlwifi: mvm: remove unused .remove_sta_debugfs callback
mac80211: remove unused and unneeded remove_sta_debugfs callback
cfg80211: no need to check return value of debugfs_create functions
Johannes Berg (6):
cfg80211: clean up cfg80211_inform_single_bss_frame_data()
cfg80211: don't parse MBSSID if transmitting BSS isn't created
cfg80211: give all multi-BSSID BSS entries the same timestamp
mac80211_hwsim: fill boottime_ns in netlink RX path
cfg80211: use parallel_ops for genl
nl80211: add strict start type
John Crispin (10):
mac80211: add support for parsing ADDBA_EXT IEs
mac80211: add xmit rate to struct ieee80211_tx_status
mac80211: propagate struct ieee80211_tx_status into ieee80211_tx_monitor()
mac80211: add struct ieee80211_tx_status support to ieee80211_add_tx_radiotap_header
mac80211: HE: add Spatial Reuse element parsing support
mac80211: fix ieee80211_he_oper_size() comment
mac80211: propagate HE operation info into bss_conf
mac80211: add support for the ADDBA extension element
cfg80211: add support for parsing OBBS_PD attributes
mac80211: allow setting spatial reuse parameters from bss_conf
Karthikeyan Periyasamy (1):
mac80211: reject zero MAC address in add station
Lorenzo Bianconi (1):
mac80211: add IEEE80211_KEY_FLAG_GENERATE_MMIE to ieee80211_key_flags
Michael Vassernis (1):
cfg80211: fix dfs channels remain DFS_AVAILABLE after ch_switch
Sergey Matyukevich (2):
cfg80211: refactor cfg80211_bss_update
cfg80211: fix duplicated scan entries after channel switch
Shay Bar (1):
mac80211: HE STA disassoc due to QOS NULL not sent
Sven Eckelmann (1):
mac80211: implement HE support for mesh
drivers/net/wireless/ath/ath10k/mac.c | 3 +-
drivers/net/wireless/ath/ath9k/main.c | 3 +-
drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 29 +--
drivers/net/wireless/intel/iwlwifi/dvm/rs.h | 4 -
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +-
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 5 -
drivers/net/wireless/mac80211_hwsim.c | 20 +-
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 3 +-
drivers/net/wireless/ti/wlcore/main.c | 3 +-
include/linux/ieee80211.h | 63 ++++-
include/net/cfg80211.h | 15 ++
include/net/mac80211.h | 53 ++++-
include/uapi/linux/nl80211.h | 31 ++-
net/mac80211/agg-rx.c | 72 +++++-
net/mac80211/cfg.c | 7 +-
net/mac80211/debugfs.c | 3 +-
net/mac80211/driver-ops.h | 8 +-
net/mac80211/he.c | 39 ++++
net/mac80211/ht.c | 2 +-
net/mac80211/ieee80211_i.h | 17 +-
net/mac80211/key.c | 16 +-
net/mac80211/main.c | 18 +-
net/mac80211/mesh.c | 62 +++++
net/mac80211/mesh.h | 4 +
net/mac80211/mesh_plink.c | 12 +-
net/mac80211/mlme.c | 7 +-
net/mac80211/offchannel.c | 5 +-
net/mac80211/rate.h | 9 -
net/mac80211/sta_info.c | 1 -
net/mac80211/status.c | 180 +++++++++++++--
net/mac80211/trace.h | 7 +-
net/mac80211/tx.c | 5 +-
net/mac80211/util.c | 60 +++++
net/mac80211/wpa.c | 6 +-
net/wireless/Kconfig | 2 +
net/wireless/core.c | 17 +-
net/wireless/core.h | 2 +
net/wireless/lib80211_crypt_ccmp.c | 197 +++++++---------
net/wireless/nl80211.c | 182 ++++++++++++---
net/wireless/scan.c | 269 ++++++++++++++--------
40 files changed, 1070 insertions(+), 374 deletions(-)
^ permalink raw reply
* pull-request: mac80211 2019-07-31
From: Johannes Berg @ 2019-07-31 12:49 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-wireless
Hi Dave,
We have few fixes, most importantly probably the NETIF_F_LLTX revert,
we thought we were now more layered like VLAN or such since we do all
of the queue control internally, but it caused problems, evidently not.
Please pull and let me know if there's any problem.
Thanks,
johannes
The following changes since commit 47d858d0bdcd47cc1c6c9eeca91b091dd9e55637:
ipip: validate header length in ipip_tunnel_xmit (2019-07-25 17:23:40 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git tags/mac80211-for-davem-2019-07-31
for you to fetch changes up to eef347f846ee8f7296a6f84e3866c057ca6bcce0:
Revert "mac80211: set NETIF_F_LLTX when using intermediate tx queues" (2019-07-30 14:52:50 +0200)
----------------------------------------------------------------
Just a few fixes:
* revert NETIF_F_LLTX usage as it caused problems
* avoid warning on WMM parameters from AP that are too short
* fix possible null-ptr dereference in hwsim
* fix interface combinations with 4-addr and crypto control
----------------------------------------------------------------
Brian Norris (1):
mac80211: don't WARN on short WMM parameters from AP
Jia-Ju Bai (1):
mac80211_hwsim: Fix possible null-pointer dereferences in hwsim_dump_radio_nl()
Johannes Berg (1):
Revert "mac80211: set NETIF_F_LLTX when using intermediate tx queues"
Manikanta Pubbisetty (1):
{nl,mac}80211: fix interface combinations on crypto controlled devices
drivers/net/wireless/mac80211_hwsim.c | 8 +++++---
include/net/cfg80211.h | 15 +++++++++++++++
net/mac80211/iface.c | 1 -
net/mac80211/mlme.c | 10 ++++++++++
net/mac80211/util.c | 7 +++----
net/wireless/core.c | 6 ++----
net/wireless/nl80211.c | 4 +---
net/wireless/util.c | 27 +++++++++++++++++++++++++--
8 files changed, 61 insertions(+), 17 deletions(-)
^ permalink raw reply
* [PATCH v3 3/3] rtw88: add BT co-existence support
From: yhchuang @ 2019-07-31 12:22 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, briannorris, sgruszka
In-Reply-To: <1564575767-27557-1-git-send-email-yhchuang@realtek.com>
From: Yan-Hsuan Chuang <yhchuang@realtek.com>
Both RTL8822BE/RTL8822CE are WiFi + BT combo chips. Since
WiFi and BT use 2.4GHz to transmit, it is important to
make sure they run concurrently without interfering each
other. To achieve this, WiFi driver requires a mechanism
to collaborate with BT, whether they share the antenna(s)
or not.
The final decision made by the co-existence mechanism is
to choose a proper strategy, or called "tdma/table", and
inform either firmware or hardware of the strategy.
To choose a strategy, co-existence mechanism needs to
have enough information from WiFi and BT.
BT information is provided through firmware C2H.
The contents describe the current status of BT, such as
if BT is connected or is idle, or the profile that is
being used.
WiFi information can be provided by WiFi itself. The WiFi
driver will call various of "notify" functions each time
the state of WiFi changed, such as WiFi is going to switch
channel or is connected. Also WiFi driver can know if it
shares antenna with BT by reading efuse content. Antenna
configuration of the module will finally get a different
strategy.
Upon receiving any information from WiFi or BT, the WiFi
driver will run the co-existence mechanism immediately.
It will set the RF antenna configuration according to the
strategy through the TDMA H2C to firmware and a hardware
table. Based on the tdma/table, WiFi + BT should work with
each other, and having a better user experience.
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
v1 -> v2
- no change
v2 -> v3
- add TDMA mode with 4 slots
- free skbs from rtw_coex_info_request
drivers/net/wireless/realtek/rtw88/Makefile | 1 +
drivers/net/wireless/realtek/rtw88/coex.c | 2507 +++++++++++++++++++++++++
drivers/net/wireless/realtek/rtw88/coex.h | 369 ++++
drivers/net/wireless/realtek/rtw88/fw.c | 106 ++
drivers/net/wireless/realtek/rtw88/fw.h | 71 +
drivers/net/wireless/realtek/rtw88/mac80211.c | 19 +
drivers/net/wireless/realtek/rtw88/main.c | 45 +-
drivers/net/wireless/realtek/rtw88/main.h | 233 +++
drivers/net/wireless/realtek/rtw88/ps.c | 9 +
drivers/net/wireless/realtek/rtw88/reg.h | 62 +
drivers/net/wireless/realtek/rtw88/rtw8822b.c | 460 ++++-
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 355 +++-
12 files changed, 4209 insertions(+), 28 deletions(-)
create mode 100644 drivers/net/wireless/realtek/rtw88/coex.c
create mode 100644 drivers/net/wireless/realtek/rtw88/coex.h
diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile
index e0bfefd..77edee2 100644
--- a/drivers/net/wireless/realtek/rtw88/Makefile
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -9,6 +9,7 @@ rtw88-y += main.o \
rx.o \
mac.o \
phy.o \
+ coex.o \
efuse.o \
fw.o \
ps.o \
diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c
new file mode 100644
index 0000000..4577fce
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/coex.c
@@ -0,0 +1,2507 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2018-2019 Realtek Corporation
+ */
+
+#include "main.h"
+#include "coex.h"
+#include "fw.h"
+#include "ps.h"
+#include "debug.h"
+#include "reg.h"
+
+static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state,
+ u8 rssi, u8 rssi_thresh)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 tol = chip->rssi_tolerance;
+ u8 next_state;
+
+ if (pre_state == COEX_RSSI_STATE_LOW ||
+ pre_state == COEX_RSSI_STATE_STAY_LOW) {
+ if (rssi >= (rssi_thresh + tol))
+ next_state = COEX_RSSI_STATE_HIGH;
+ else
+ next_state = COEX_RSSI_STATE_STAY_LOW;
+ } else {
+ if (rssi < rssi_thresh)
+ next_state = COEX_RSSI_STATE_LOW;
+ else
+ next_state = COEX_RSSI_STATE_STAY_HIGH;
+ }
+
+ return next_state;
+}
+
+static void rtw_coex_limited_tx(struct rtw_dev *rtwdev,
+ bool tx_limit_en, bool ampdu_limit_en)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ bool wifi_under_b_mode = false;
+
+ if (!chip->scbd_support)
+ return;
+
+ /* force max tx retry limit = 8 */
+ if (coex_stat->wl_tx_limit_en == tx_limit_en &&
+ coex_stat->wl_ampdu_limit_en == ampdu_limit_en)
+ return;
+
+ if (!coex_stat->wl_tx_limit_en) {
+ coex_stat->darfrc = rtw_read32(rtwdev, REG_DARFRC);
+ coex_stat->darfrch = rtw_read32(rtwdev, REG_DARFRCH);
+ coex_stat->retry_limit = rtw_read16(rtwdev, REG_RETRY_LIMIT);
+ }
+
+ if (!coex_stat->wl_ampdu_limit_en)
+ coex_stat->ampdu_max_time =
+ rtw_read8(rtwdev, REG_AMPDU_MAX_TIME_V1);
+
+ coex_stat->wl_tx_limit_en = tx_limit_en;
+ coex_stat->wl_ampdu_limit_en = ampdu_limit_en;
+
+ if (tx_limit_en) {
+ /* set BT polluted packet on for tx rate adaptive,
+ * not including tx retry broken by PTA
+ */
+ rtw_write8_set(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);
+
+ /* set queue life time to avoid can't reach tx retry limit
+ * if tx is always broken by GNT_BT
+ */
+ rtw_write8_set(rtwdev, REG_LIFETIME_EN, 0xf);
+ rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x0808);
+
+ /* auto rate fallback step within 8 retries */
+ if (wifi_under_b_mode) {
+ rtw_write32(rtwdev, REG_DARFRC, 0x1000000);
+ rtw_write32(rtwdev, REG_DARFRCH, 0x1010101);
+ } else {
+ rtw_write32(rtwdev, REG_DARFRC, 0x1000000);
+ rtw_write32(rtwdev, REG_DARFRCH, 0x4030201);
+ }
+ } else {
+ rtw_write8_clr(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);
+ rtw_write8_clr(rtwdev, REG_LIFETIME_EN, 0xf);
+
+ rtw_write16(rtwdev, REG_RETRY_LIMIT, coex_stat->retry_limit);
+ rtw_write32(rtwdev, REG_DARFRC, coex_stat->darfrc);
+ rtw_write32(rtwdev, REG_DARFRCH, coex_stat->darfrch);
+ }
+
+ if (ampdu_limit_en)
+ rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, 0x20);
+ else
+ rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1,
+ coex_stat->ampdu_max_time);
+}
+
+static void rtw_coex_limited_wl(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ bool tx_limit = false;
+ bool tx_agg_ctrl = false;
+
+ if (coex->under_5g ||
+ coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
+ /* no need to limit tx */
+ } else {
+ tx_limit = true;
+ if (coex_stat->bt_hid_exist || coex_stat->bt_hfp_exist ||
+ coex_stat->bt_hid_pair_num > 0)
+ tx_agg_ctrl = true;
+ }
+
+ rtw_coex_limited_tx(rtwdev, tx_limit, tx_agg_ctrl);
+}
+
+static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ u8 para[6] = {0};
+
+ if (coex->stop_dm)
+ return;
+
+ para[0] = COEX_H2C69_WL_LEAKAP;
+
+ if (coex_stat->tdma_timer_base == 3 && coex_stat->wl_slot_extend) {
+ para[1] = PARA1_H2C69_DIS_5MS; /* disable 5ms extend */
+ rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]);
+ coex_stat->wl_slot_extend = false;
+ coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
+ return;
+ }
+
+ if (coex_stat->wl_slot_extend && coex_stat->wl_force_lps_ctrl &&
+ !coex_stat->wl_cck_lock_ever) {
+ if (coex_stat->wl_fw_dbg_info[7] <= 5)
+ coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]++;
+ else
+ coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
+
+ if (coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] == 7) {
+ para[1] = 0x1; /* disable 5ms extend */
+ rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]);
+ coex_stat->wl_slot_extend = false;
+ coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;
+ }
+ } else if (!coex_stat->wl_slot_extend && coex_stat->wl_cck_lock) {
+ para[1] = 0x0; /* enable 5ms extend */
+ rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]);
+ coex_stat->wl_slot_extend = true;
+ }
+}
+
+static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+
+ /* TODO: wait for rx_rate_change_notify implement */
+ coex_stat->wl_cck_lock = false;
+ coex_stat->wl_cck_lock_pre = false;
+ coex_stat->wl_cck_lock_ever = false;
+}
+
+static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u32 cnt_cck;
+
+ /* wifi noisy environment identification */
+ cnt_cck = dm_info->cck_ok_cnt + dm_info->cck_err_cnt;
+
+ if (!coex_stat->wl_gl_busy) {
+ if (cnt_cck > 250) {
+ if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] < 5)
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY2]++;
+
+ if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5) {
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0;
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0;
+ }
+ } else if (cnt_cck < 100) {
+ if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] < 5)
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY0]++;
+
+ if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] == 5) {
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0;
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0;
+ }
+ } else {
+ if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] < 5)
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY1]++;
+
+ if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5) {
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0;
+ coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0;
+ }
+ }
+
+ if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5)
+ coex_stat->wl_noisy_level = 2;
+ else if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5)
+ coex_stat->wl_noisy_level = 1;
+ else
+ coex_stat->wl_noisy_level = 0;
+ }
+}
+
+static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ u8 para[2] = {0};
+
+ if (coex_stat->tdma_timer_base == type)
+ return;
+
+ coex_stat->tdma_timer_base = type;
+
+ para[0] = COEX_H2C69_TDMA_SLOT;
+
+ if (type == 3) /* 4-slot */
+ para[1] = PARA1_H2C69_TDMA_4SLOT; /* 4-slot */
+ else /* 2-slot */
+ para[1] = PARA1_H2C69_TDMA_2SLOT;
+
+ rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]);
+
+ /* no 5ms_wl_slot_extend for 4-slot mode */
+ if (coex_stat->tdma_timer_base == 3)
+ rtw_coex_wl_ccklock_action(rtwdev);
+}
+
+static void rtw_coex_set_wl_pri_mask(struct rtw_dev *rtwdev, u8 bitmap,
+ u8 data)
+{
+ u32 addr;
+
+ addr = REG_BT_COEX_TABLE_H + (bitmap / 8);
+ bitmap = bitmap % 8;
+
+ rtw_write8_mask(rtwdev, addr, BIT(bitmap), data);
+}
+
+void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ u16 val = 0x2;
+
+ if (!chip->scbd_support)
+ return;
+
+ val |= coex_stat->score_board;
+
+ /* for 8822b, scbd[10] is CQDDR on
+ * for 8822c, scbd[10] is no fix 2M
+ */
+ if (!chip->new_scbd10_def && (bitpos & COEX_SCBD_FIX2M)) {
+ if (set)
+ val &= ~COEX_SCBD_FIX2M;
+ else
+ val |= COEX_SCBD_FIX2M;
+ } else {
+ if (set)
+ val |= bitpos;
+ else
+ val &= ~bitpos;
+ }
+
+ if (val != coex_stat->score_board) {
+ coex_stat->score_board = val;
+ val |= BIT_BT_INT_EN;
+ rtw_write16(rtwdev, REG_WIFI_BT_INFO, val);
+ }
+}
+
+static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ if (!chip->scbd_support)
+ return 0;
+
+ return (rtw_read16(rtwdev, REG_WIFI_BT_INFO)) & ~(BIT_BT_INT_EN);
+}
+
+static void rtw_coex_check_rfk(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_rfe *coex_rfe = &coex->rfe;
+ u8 cnt = 0;
+ u32 wait_cnt;
+ bool btk, wlk;
+
+ if (coex_rfe->wlg_at_btg && chip->scbd_support &&
+ coex_stat->bt_iqk_state != 0xff) {
+ wait_cnt = COEX_RFK_TIMEOUT / COEX_MIN_DELAY;
+ do {
+ /* BT RFK */
+ btk = !!(rtw_coex_read_scbd(rtwdev) & COEX_SCBD_BT_RFK);
+
+ /* WL RFK */
+ wlk = !!(rtw_read8(rtwdev, REG_ARFR4) & BIT_WL_RFK);
+
+ if (!btk && !wlk)
+ break;
+
+ mdelay(COEX_MIN_DELAY);
+ } while (++cnt < wait_cnt);
+
+ if (cnt >= wait_cnt)
+ coex_stat->bt_iqk_state = 0xff;
+ }
+}
+
+static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+
+ if (coex_stat->bt_disabled)
+ return;
+
+ rtw_fw_query_bt_info(rtwdev);
+}
+
+static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ bool bt_disabled = false;
+ u16 score_board;
+
+ if (chip->scbd_support) {
+ score_board = rtw_coex_read_scbd(rtwdev);
+ bt_disabled = !(score_board & COEX_SCBD_ONOFF);
+ }
+
+ if (coex_stat->bt_disabled != bt_disabled) {
+ rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: BT state changed (%d) -> (%d)\n",
+ coex_stat->bt_disabled, bt_disabled);
+
+ coex_stat->bt_disabled = bt_disabled;
+ coex_stat->bt_ble_scan_type = 0;
+ coex_dm->cur_bt_lna_lvl = 0;
+ }
+
+ if (!coex_stat->bt_disabled) {
+ coex_stat->bt_reenable = true;
+ ieee80211_queue_delayed_work(rtwdev->hw,
+ &coex->bt_reenable_work, 15 * HZ);
+ } else {
+ coex_stat->bt_mailbox_reply = false;
+ coex_stat->bt_reenable = false;
+ }
+}
+
+static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_traffic_stats *stats = &rtwdev->stats;
+ bool is_5G = false;
+ bool scan = false, link = false;
+ int i;
+ u8 rssi_state;
+ u8 rssi_step;
+ u8 rssi;
+
+ scan = rtw_flag_check(rtwdev, RTW_FLAG_SCANNING);
+ coex_stat->wl_connected = !!rtwdev->sta_cnt;
+ coex_stat->wl_gl_busy = rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC);
+
+ if (stats->tx_throughput > stats->rx_throughput)
+ coex_stat->wl_tput_dir = COEX_WL_TPUT_TX;
+ else
+ coex_stat->wl_tput_dir = COEX_WL_TPUT_RX;
+
+ if (scan || link || reason == COEX_RSN_2GCONSTART ||
+ reason == COEX_RSN_2GSCANSTART || reason == COEX_RSN_2GSWITCHBAND)
+ coex_stat->wl_linkscan_proc = true;
+ else
+ coex_stat->wl_linkscan_proc = false;
+
+ rtw_coex_wl_noisy_detect(rtwdev);
+
+ for (i = 0; i < 4; i++) {
+ rssi_state = coex_dm->wl_rssi_state[i];
+ rssi_step = chip->wl_rssi_step[i];
+ rssi = rtwdev->dm_info.min_rssi;
+ rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
+ rssi, rssi_step);
+ coex_dm->wl_rssi_state[i] = rssi_state;
+ }
+
+ switch (reason) {
+ case COEX_RSN_5GSCANSTART:
+ case COEX_RSN_5GSWITCHBAND:
+ case COEX_RSN_5GCONSTART:
+
+ is_5G = true;
+ break;
+ case COEX_RSN_2GSCANSTART:
+ case COEX_RSN_2GSWITCHBAND:
+ case COEX_RSN_2GCONSTART:
+
+ is_5G = false;
+ break;
+ default:
+ if (rtwdev->hal.current_band_type == RTW_BAND_5G)
+ is_5G = true;
+ else
+ is_5G = false;
+ break;
+ }
+
+ coex->under_5g = is_5G;
+}
+
+static inline u8 *get_payload_from_coex_resp(struct sk_buff *resp)
+{
+ struct rtw_c2h_cmd *c2h;
+ u32 pkt_offset;
+
+ pkt_offset = *((u32 *)resp->cb);
+ c2h = (struct rtw_c2h_cmd *)(resp->data + pkt_offset);
+
+ return c2h->payload;
+}
+
+void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ u8 *payload = get_payload_from_coex_resp(skb);
+
+ if (payload[0] != COEX_RESP_ACK_BY_WL_FW)
+ return;
+
+ skb_queue_tail(&coex->queue, skb);
+ wake_up(&coex->wait);
+}
+
+static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,
+ struct rtw_coex_info_req *req)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct sk_buff *skb_resp = NULL;
+
+ mutex_lock(&coex->mutex);
+
+ rtw_fw_query_bt_mp_info(rtwdev, req);
+
+ if (!wait_event_timeout(coex->wait, !skb_queue_empty(&coex->queue),
+ COEX_REQUEST_TIMEOUT)) {
+ rtw_err(rtwdev, "coex request time out\n");
+ goto out;
+ }
+
+ skb_resp = skb_dequeue(&coex->queue);
+ if (!skb_resp) {
+ rtw_err(rtwdev, "failed to get coex info response\n");
+ goto out;
+ }
+
+out:
+ mutex_unlock(&coex->mutex);
+ return skb_resp;
+}
+
+static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type)
+{
+ struct rtw_coex_info_req req = {0};
+ struct sk_buff *skb;
+ u8 *payload;
+ bool ret = false;
+
+ req.op_code = BT_MP_INFO_OP_SCAN_TYPE;
+ skb = rtw_coex_info_request(rtwdev, &req);
+ if (!skb)
+ goto out;
+
+ payload = get_payload_from_coex_resp(skb);
+ *scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload);
+ dev_kfree_skb_any(skb);
+ ret = true;
+
+out:
+ return ret;
+}
+
+static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev,
+ u8 lna_constrain_level)
+{
+ struct rtw_coex_info_req req = {0};
+ struct sk_buff *skb;
+ bool ret = false;
+
+ req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT;
+ req.para1 = lna_constrain_level;
+ skb = rtw_coex_info_request(rtwdev, &req);
+ if (!skb)
+ goto out;
+
+ dev_kfree_skb_any(skb);
+ ret = true;
+
+out:
+ return ret;
+}
+
+static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 i;
+ u8 rssi_state;
+ u8 rssi_step;
+ u8 rssi;
+
+ /* update wl/bt rssi by btinfo */
+ for (i = 0; i < COEX_RSSI_STEP; i++) {
+ rssi_state = coex_dm->bt_rssi_state[i];
+ rssi_step = chip->bt_rssi_step[i];
+ rssi = coex_stat->bt_rssi;
+ rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
+ rssi, rssi_step);
+ coex_dm->bt_rssi_state[i] = rssi_state;
+ }
+
+ for (i = 0; i < COEX_RSSI_STEP; i++) {
+ rssi_state = coex_dm->wl_rssi_state[i];
+ rssi_step = chip->wl_rssi_step[i];
+ rssi = rtwdev->dm_info.min_rssi;
+ rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,
+ rssi, rssi_step);
+ coex_dm->wl_rssi_state[i] = rssi_state;
+ }
+
+ if (coex_stat->bt_ble_scan_en &&
+ coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE] % 3 == 0) {
+ u8 scan_type;
+
+ if (rtw_coex_get_bt_scan_type(rtwdev, &scan_type)) {
+ coex_stat->bt_ble_scan_type = scan_type;
+ if ((coex_stat->bt_ble_scan_type & 0x1) == 0x1)
+ coex_stat->bt_init_scan = true;
+ else
+ coex_stat->bt_init_scan = false;
+ }
+ }
+
+ coex_stat->bt_profile_num = 0;
+
+ /* set link exist status */
+ if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {
+ coex_stat->bt_link_exist = false;
+ coex_stat->bt_pan_exist = false;
+ coex_stat->bt_a2dp_exist = false;
+ coex_stat->bt_hid_exist = false;
+ coex_stat->bt_hfp_exist = false;
+ } else {
+ /* connection exists */
+ coex_stat->bt_link_exist = true;
+ if (coex_stat->bt_info_lb2 & COEX_INFO_FTP) {
+ coex_stat->bt_pan_exist = true;
+ coex_stat->bt_profile_num++;
+ } else {
+ coex_stat->bt_pan_exist = false;
+ }
+
+ if (coex_stat->bt_info_lb2 & COEX_INFO_A2DP) {
+ coex_stat->bt_a2dp_exist = true;
+ coex_stat->bt_profile_num++;
+ } else {
+ coex_stat->bt_a2dp_exist = false;
+ }
+
+ if (coex_stat->bt_info_lb2 & COEX_INFO_HID) {
+ coex_stat->bt_hid_exist = true;
+ coex_stat->bt_profile_num++;
+ } else {
+ coex_stat->bt_hid_exist = false;
+ }
+
+ if (coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) {
+ coex_stat->bt_hfp_exist = true;
+ coex_stat->bt_profile_num++;
+ } else {
+ coex_stat->bt_hfp_exist = false;
+ }
+ }
+
+ if (coex_stat->bt_info_lb2 & COEX_INFO_INQ_PAGE) {
+ coex_dm->bt_status = COEX_BTSTATUS_INQ_PAGE;
+ } else if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {
+ coex_dm->bt_status = COEX_BTSTATUS_NCON_IDLE;
+ } else if (coex_stat->bt_info_lb2 == COEX_INFO_CONNECTION) {
+ coex_dm->bt_status = COEX_BTSTATUS_CON_IDLE;
+ } else if ((coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) ||
+ (coex_stat->bt_info_lb2 & COEX_INFO_SCO_BUSY)) {
+ if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY)
+ coex_dm->bt_status = COEX_BTSTATUS_ACL_SCO_BUSY;
+ else
+ coex_dm->bt_status = COEX_BTSTATUS_SCO_BUSY;
+ } else if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY) {
+ coex_dm->bt_status = COEX_BTSTATUS_ACL_BUSY;
+ } else {
+ coex_dm->bt_status = COEX_BTSTATUS_MAX;
+ }
+
+ coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE]++;
+
+ rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: bt status(%d)\n", coex_dm->bt_status);
+}
+
+static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ u8 link = 0;
+ u8 center_chan = 0;
+ u8 bw;
+ int i;
+
+ bw = rtwdev->hal.current_band_width;
+
+ if (type != COEX_MEDIA_DISCONNECT)
+ center_chan = rtwdev->hal.current_channel;
+
+ if (center_chan == 0 || (efuse->share_ant && center_chan <= 14)) {
+ link = 0;
+ } else if (center_chan <= 14) {
+ link = 0x1;
+
+ if (bw == RTW_CHANNEL_WIDTH_40)
+ bw = chip->bt_afh_span_bw40;
+ else
+ bw = chip->bt_afh_span_bw20;
+ } else if (chip->afh_5g_num > 1) {
+ for (i = 0; i < chip->afh_5g_num; i++) {
+ if (center_chan == chip->afh_5g[i].wl_5g_ch) {
+ link = 0x3;
+ center_chan = chip->afh_5g[i].bt_skip_ch;
+ bw = chip->afh_5g[i].bt_skip_span;
+ break;
+ }
+ }
+ }
+
+ coex_dm->wl_ch_info[0] = link;
+ coex_dm->wl_ch_info[1] = center_chan;
+ coex_dm->wl_ch_info[2] = bw;
+
+ rtw_fw_wl_ch_info(rtwdev, link, center_chan, bw);
+}
+
+static void rtw_coex_set_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+
+ if (bt_pwr_dec_lvl == coex_dm->cur_bt_pwr_lvl)
+ return;
+
+ coex_dm->cur_bt_pwr_lvl = bt_pwr_dec_lvl;
+
+ rtw_fw_force_bt_tx_power(rtwdev, bt_pwr_dec_lvl);
+}
+
+static void rtw_coex_set_bt_rx_gain(struct rtw_dev *rtwdev, u8 bt_lna_lvl)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+
+ if (bt_lna_lvl == coex_dm->cur_bt_lna_lvl)
+ return;
+
+ coex_dm->cur_bt_lna_lvl = bt_lna_lvl;
+
+ /* notify BT rx gain table changed */
+ if (bt_lna_lvl < 7) {
+ rtw_coex_set_lna_constrain_level(rtwdev, bt_lna_lvl);
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, true);
+ } else {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, false);
+ }
+}
+
+static void rtw_coex_set_rf_para(struct rtw_dev *rtwdev,
+ struct coex_rf_para para)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ u8 offset = 0;
+
+ if (coex->freerun && coex_stat->wl_noisy_level <= 1)
+ offset = 3;
+
+ rtw_coex_set_wl_tx_power(rtwdev, para.wl_pwr_dec_lvl);
+ rtw_coex_set_bt_tx_power(rtwdev, para.bt_pwr_dec_lvl + offset);
+ rtw_coex_set_wl_rx_gain(rtwdev, para.wl_low_gain_en);
+ rtw_coex_set_bt_rx_gain(rtwdev, para.bt_lna_lvl);
+}
+
+static u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr)
+{
+ u32 val;
+
+ if (!ltecoex_read_reg(rtwdev, addr, &val)) {
+ rtw_err(rtwdev, "failed to read indirect register\n");
+ return 0;
+ }
+
+ return val;
+}
+
+void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr,
+ u32 mask, u32 val)
+{
+ u32 shift = __ffs(mask);
+ u32 tmp;
+
+ tmp = rtw_coex_read_indirect_reg(rtwdev, addr);
+ tmp = (tmp & (~mask)) | ((val << shift) & mask);
+
+ if (!ltecoex_reg_write(rtwdev, addr, tmp))
+ rtw_err(rtwdev, "failed to write indirect register\n");
+}
+
+static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control)
+{
+ if (wifi_control)
+ rtw_write32_set(rtwdev, REG_SYS_SDIO_CTRL, BIT_LTE_MUX_CTRL_PATH);
+ else
+ rtw_write32_clr(rtwdev, REG_SYS_SDIO_CTRL, BIT_LTE_MUX_CTRL_PATH);
+}
+
+static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state)
+{
+ rtw_coex_write_indirect_reg(rtwdev, 0x38, 0xc000, state);
+ rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x0c00, state);
+}
+
+static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state)
+{
+ rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x3000, state);
+ rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x0300, state);
+}
+
+static void rtw_coex_set_table(struct rtw_dev *rtwdev, u32 table0, u32 table1)
+{
+#define DEF_BRK_TABLE_VAL 0xf0ffffff
+ rtw_write32(rtwdev, REG_BT_COEX_TABLE0, table0);
+ rtw_write32(rtwdev, REG_BT_COEX_TABLE1, table1);
+ rtw_write32(rtwdev, REG_BT_COEX_BRK_TABLE, DEF_BRK_TABLE_VAL);
+}
+
+static void rtw_coex_table(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+
+ coex_dm->cur_table = type;
+
+ if (efuse->share_ant) {
+ if (type < chip->table_sant_num)
+ rtw_coex_set_table(rtwdev,
+ chip->table_sant[type].bt,
+ chip->table_sant[type].wl);
+ } else {
+ type = type - 100;
+ if (type < chip->table_nsant_num)
+ rtw_coex_set_table(rtwdev,
+ chip->table_nsant[type].bt,
+ chip->table_nsant[type].wl);
+ }
+}
+
+static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+
+ if (coex->stop_dm)
+ return;
+
+ rtw_fw_bt_ignore_wlan_action(rtwdev, enable);
+}
+
+static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type,
+ u8 lps_val, u8 rpwm_val)
+{
+ struct rtw_lps_conf *lps_conf = &rtwdev->lps_conf;
+ struct rtw_vif *rtwvif;
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ u8 lps_mode = 0x0;
+
+ lps_mode = rtwdev->lps_conf.mode;
+
+ switch (ps_type) {
+ case COEX_PS_WIFI_NATIVE:
+ /* recover to original 32k low power setting */
+ coex_stat->wl_force_lps_ctrl = false;
+
+ rtwvif = lps_conf->rtwvif;
+ if (rtwvif && rtw_in_lps(rtwdev))
+ rtw_leave_lps(rtwdev, rtwvif);
+ break;
+ case COEX_PS_LPS_OFF:
+ coex_stat->wl_force_lps_ctrl = true;
+ if (lps_mode)
+ rtw_fw_coex_tdma_type(rtwdev, 0x8, 0, 0, 0, 0);
+
+ rtwvif = lps_conf->rtwvif;
+ if (rtwvif && rtw_in_lps(rtwdev))
+ rtw_leave_lps(rtwdev, rtwvif);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
+ u8 byte3, u8 byte4, u8 byte5)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 ps_type = COEX_PS_WIFI_NATIVE;
+ bool ap_enable = false;
+
+ if (ap_enable && (byte1 & BIT(4) && !(byte1 & BIT(5)))) {
+ byte1 &= ~BIT(4);
+ byte1 |= BIT(5);
+
+ byte5 |= BIT(5);
+ byte5 &= ~BIT(6);
+
+ ps_type = COEX_PS_WIFI_NATIVE;
+ rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
+ } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) {
+ if (chip->pstdma_type == COEX_PSTDMA_FORCE_LPSOFF)
+ ps_type = COEX_PS_LPS_OFF;
+ else
+ ps_type = COEX_PS_LPS_ON;
+ rtw_coex_power_save_state(rtwdev, ps_type, 0x50, 0x4);
+ } else {
+ ps_type = COEX_PS_WIFI_NATIVE;
+ rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
+ }
+
+ coex_dm->ps_tdma_para[0] = byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = byte5;
+
+ rtw_fw_coex_tdma_type(rtwdev, byte1, byte2, byte3, byte4, byte5);
+}
+
+static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ u8 n, type;
+ bool turn_on;
+
+ if (tcase & TDMA_4SLOT)/* 4-slot (50ms) mode */
+ rtw_coex_tdma_timer_base(rtwdev, 3);
+ else
+ rtw_coex_tdma_timer_base(rtwdev, 0);
+
+ type = (u8)(tcase & 0xff);
+
+ turn_on = (type == 0 || type == 100) ? false : true;
+
+ if (!force) {
+ if (turn_on == coex_dm->cur_ps_tdma_on &&
+ type == coex_dm->cur_ps_tdma) {
+ return;
+ }
+ }
+
+ if (turn_on) {
+ /* enable TBTT interrupt */
+ rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true);
+ } else {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, false);
+ }
+
+ if (efuse->share_ant) {
+ if (type < chip->tdma_sant_num)
+ rtw_coex_set_tdma(rtwdev,
+ chip->tdma_sant[type].para[0],
+ chip->tdma_sant[type].para[1],
+ chip->tdma_sant[type].para[2],
+ chip->tdma_sant[type].para[3],
+ chip->tdma_sant[type].para[4]);
+ } else {
+ n = type - 100;
+ if (n < chip->tdma_nsant_num)
+ rtw_coex_set_tdma(rtwdev,
+ chip->tdma_nsant[n].para[0],
+ chip->tdma_nsant[n].para[1],
+ chip->tdma_nsant[n].para[2],
+ chip->tdma_nsant[n].para[3],
+ chip->tdma_nsant[n].para[4]);
+ }
+
+ /* update pre state */
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: coex tdma type (%d)\n", type);
+}
+
+static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ u8 ctrl_type = COEX_SWITCH_CTRL_MAX;
+ u8 pos_type = COEX_SWITCH_TO_MAX;
+
+ if (!force && coex_dm->cur_ant_pos_type == phase)
+ return;
+
+ coex_dm->cur_ant_pos_type = phase;
+
+ /* avoid switch coex_ctrl_owner during BT IQK */
+ rtw_coex_check_rfk(rtwdev);
+
+ switch (phase) {
+ case COEX_SET_ANT_POWERON:
+ /* set path control owner to BT at power-on */
+ if (coex_stat->bt_disabled)
+ rtw_coex_coex_ctrl_owner(rtwdev, true);
+ else
+ rtw_coex_coex_ctrl_owner(rtwdev, false);
+
+ ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
+ pos_type = COEX_SWITCH_TO_BT;
+ break;
+ case COEX_SET_ANT_INIT:
+ if (coex_stat->bt_disabled) {
+ /* set GNT_BT to SW low */
+ rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);
+
+ /* set GNT_WL to SW high */
+ rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
+ } else {
+ /* set GNT_BT to SW high */
+ rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
+
+ /* set GNT_WL to SW low */
+ rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_LOW);
+ }
+
+ /* set path control owner to wl at initial step */
+ rtw_coex_coex_ctrl_owner(rtwdev, true);
+
+ ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
+ pos_type = COEX_SWITCH_TO_BT;
+ break;
+ case COEX_SET_ANT_WONLY:
+ /* set GNT_BT to SW Low */
+ rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);
+
+ /* Set GNT_WL to SW high */
+ rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
+
+ /* set path control owner to wl at initial step */
+ rtw_coex_coex_ctrl_owner(rtwdev, true);
+
+ ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
+ pos_type = COEX_SWITCH_TO_WLG;
+ break;
+ case COEX_SET_ANT_WOFF:
+ /* set path control owner to BT */
+ rtw_coex_coex_ctrl_owner(rtwdev, false);
+
+ ctrl_type = COEX_SWITCH_CTRL_BY_BT;
+ pos_type = COEX_SWITCH_TO_NOCARE;
+ break;
+ case COEX_SET_ANT_2G:
+ /* set GNT_BT to PTA */
+ rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
+
+ /* set GNT_WL to PTA */
+ rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);
+
+ /* set path control owner to wl at runtime step */
+ rtw_coex_coex_ctrl_owner(rtwdev, true);
+
+ ctrl_type = COEX_SWITCH_CTRL_BY_PTA;
+ pos_type = COEX_SWITCH_TO_NOCARE;
+ break;
+ case COEX_SET_ANT_5G:
+ /* set GNT_BT to PTA */
+ rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
+
+ /* set GNT_WL to SW high */
+ rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
+
+ /* set path control owner to wl at runtime step */
+ rtw_coex_coex_ctrl_owner(rtwdev, true);
+
+ ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
+ pos_type = COEX_SWITCH_TO_WLA;
+ break;
+ case COEX_SET_ANT_2G_FREERUN:
+ /* set GNT_BT to SW high */
+ rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);
+
+ /* Set GNT_WL to SW high */
+ rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);
+
+ /* set path control owner to wl at runtime step */
+ rtw_coex_coex_ctrl_owner(rtwdev, true);
+
+ ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
+ pos_type = COEX_SWITCH_TO_WLG_BT;
+ break;
+ case COEX_SET_ANT_2G_WLBT:
+ /* set GNT_BT to SW high */
+ rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);
+
+ /* Set GNT_WL to SW high */
+ rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);
+
+ /* set path control owner to wl at runtime step */
+ rtw_coex_coex_ctrl_owner(rtwdev, true);
+
+ ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
+ pos_type = COEX_SWITCH_TO_WLG_BT;
+ break;
+ default:
+ WARN_ON("unknown phase when setting antenna path\n");
+ return;
+ }
+
+ if (ctrl_type < COEX_SWITCH_CTRL_MAX && pos_type < COEX_SWITCH_TO_MAX)
+ rtw_coex_set_ant_switch(rtwdev, ctrl_type, pos_type);
+}
+
+static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ u8 algorithm = COEX_ALGO_NOPROFILE;
+ u8 profile_map = 0;
+
+ if (coex_stat->bt_hfp_exist)
+ profile_map |= BPM_HFP;
+ if (coex_stat->bt_hid_exist)
+ profile_map |= BPM_HID;
+ if (coex_stat->bt_a2dp_exist)
+ profile_map |= BPM_A2DP;
+ if (coex_stat->bt_pan_exist)
+ profile_map |= BPM_PAN;
+
+ switch (profile_map) {
+ case BPM_HFP:
+ algorithm = COEX_ALGO_HFP;
+ break;
+ case BPM_HID:
+ case BPM_HFP + BPM_HID:
+ algorithm = COEX_ALGO_HID;
+ break;
+ case BPM_HFP + BPM_A2DP:
+ case BPM_HID + BPM_A2DP:
+ case BPM_HFP + BPM_HID + BPM_A2DP:
+ algorithm = COEX_ALGO_A2DP_HID;
+ break;
+ case BPM_HFP + BPM_PAN:
+ case BPM_HID + BPM_PAN:
+ case BPM_HFP + BPM_HID + BPM_PAN:
+ algorithm = COEX_ALGO_PAN_HID;
+ break;
+ case BPM_HFP + BPM_A2DP + BPM_PAN:
+ case BPM_HID + BPM_A2DP + BPM_PAN:
+ case BPM_HFP + BPM_HID + BPM_A2DP + BPM_PAN:
+ algorithm = COEX_ALGO_A2DP_PAN_HID;
+ break;
+ case BPM_PAN:
+ algorithm = COEX_ALGO_PAN;
+ break;
+ case BPM_A2DP + BPM_PAN:
+ algorithm = COEX_ALGO_A2DP_PAN;
+ break;
+ case BPM_A2DP:
+ if (coex_stat->bt_multi_link) {
+ if (coex_stat->bt_hid_pair_num > 0)
+ algorithm = COEX_ALGO_A2DP_HID;
+ else
+ algorithm = COEX_ALGO_A2DP_PAN;
+ } else {
+ algorithm = COEX_ALGO_A2DP;
+ }
+ break;
+ default:
+ algorithm = COEX_ALGO_NOPROFILE;
+ break;
+ }
+
+ return algorithm;
+}
+
+static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 2;
+ tdma_case = 0;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 100;
+ tdma_case = 100;
+ }
+
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_freerun(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 level = 0;
+
+ if (efuse->share_ant)
+ return;
+
+ coex->freerun = true;
+
+ if (coex_stat->wl_connected)
+ rtw_coex_update_wl_ch_info(rtwdev, COEX_MEDIA_CONNECT);
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);
+
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
+
+ if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[0]))
+ level = 2;
+ else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
+ level = 3;
+ else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[2]))
+ level = 4;
+ else
+ level = 5;
+
+ if (level > chip->wl_rf_para_num - 1)
+ level = chip->wl_rf_para_num - 1;
+
+ if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[level]);
+ else
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[level]);
+
+ rtw_coex_table(rtwdev, 100);
+ rtw_coex_tdma(rtwdev, false, 100);
+}
+
+static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 2;
+ tdma_case = 0;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 100;
+ tdma_case = 100;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 1;
+ tdma_case = 0;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 100;
+ tdma_case = 100;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_coex_rfe *coex_rfe = &coex->rfe;
+ u8 table_case = 0xff, tdma_case = 0xff;
+
+ if (coex_rfe->ant_switch_with_bt &&
+ coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
+ if (efuse->share_ant &&
+ COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) {
+ table_case = 0;
+ tdma_case = 0;
+ } else if (!efuse->share_ant) {
+ table_case = 100;
+ tdma_case = 100;
+ }
+ }
+
+ if (table_case != 0xff && tdma_case != 0xff) {
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+ return;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (!coex_stat->wl_gl_busy) {
+ table_case = 10;
+ tdma_case = 3;
+ } else if (coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
+ table_case = 6;
+ tdma_case = 7;
+ } else {
+ table_case = 12;
+ tdma_case = 7;
+ }
+ } else {
+ /* Non-Shared-Ant */
+ if (!coex_stat->wl_gl_busy) {
+ table_case = 112;
+ tdma_case = 104;
+ } else if ((coex_stat->bt_ble_scan_type & 0x2) &&
+ coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {
+ table_case = 114;
+ tdma_case = 103;
+ } else {
+ table_case = 112;
+ tdma_case = 103;
+ }
+ }
+
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ bool wl_hi_pri = false;
+ u8 table_case, tdma_case;
+
+ if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 ||
+ coex_stat->wl_hi_pri_task2)
+ wl_hi_pri = true;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (wl_hi_pri) {
+ table_case = 15;
+ if (coex_stat->bt_a2dp_exist &&
+ !coex_stat->bt_pan_exist)
+ tdma_case = 11;
+ else if (coex_stat->wl_hi_pri_task1)
+ tdma_case = 6;
+ else if (!coex_stat->bt_page)
+ tdma_case = 8;
+ else
+ tdma_case = 9;
+ } else if (coex_stat->wl_connected) {
+ table_case = 10;
+ tdma_case = 10;
+ } else {
+ table_case = 1;
+ tdma_case = 0;
+ }
+ } else {
+ /* Non_Shared-Ant */
+ if (wl_hi_pri) {
+ table_case = 113;
+ if (coex_stat->bt_a2dp_exist &&
+ !coex_stat->bt_pan_exist)
+ tdma_case = 111;
+ else if (coex_stat->wl_hi_pri_task1)
+ tdma_case = 106;
+ else if (!coex_stat->bt_page)
+ tdma_case = 108;
+ else
+ tdma_case = 109;
+ } else if (coex_stat->wl_connected) {
+ table_case = 101;
+ tdma_case = 110;
+ } else {
+ table_case = 100;
+ tdma_case = 100;
+ }
+ }
+
+ rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: wifi hi(%d), bt page(%d)\n",
+ wl_hi_pri, coex_stat->bt_page);
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (coex_stat->bt_multi_link) {
+ table_case = 10;
+ tdma_case = 17;
+ } else {
+ table_case = 10;
+ tdma_case = 5;
+ }
+ } else {
+ /* Non-Shared-Ant */
+ if (coex_stat->bt_multi_link) {
+ table_case = 112;
+ tdma_case = 117;
+ } else {
+ table_case = 105;
+ tdma_case = 100;
+ }
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+ u32 wl_bw;
+
+ wl_bw = rtwdev->hal.current_band_width;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (coex_stat->bt_ble_exist) {
+ /* RCU */
+ if (!coex_stat->wl_gl_busy)
+ table_case = 14;
+ else
+ table_case = 15;
+
+ if (coex_stat->bt_a2dp_active || wl_bw == 0)
+ tdma_case = 18;
+ else if (coex_stat->wl_gl_busy)
+ tdma_case = 8;
+ else
+ tdma_case = 4;
+ } else {
+ if (coex_stat->bt_a2dp_active || wl_bw == 0) {
+ table_case = 8;
+ tdma_case = 4;
+ } else {
+ /* for 4/18 HID */
+ if (coex_stat->bt_418_hid_exist &&
+ coex_stat->wl_gl_busy)
+ table_case = 12;
+ else
+ table_case = 10;
+ tdma_case = 4;
+ }
+ }
+ } else {
+ /* Non-Shared-Ant */
+ if (coex_stat->bt_a2dp_active) {
+ table_case = 113;
+ tdma_case = 118;
+ } else if (coex_stat->bt_ble_exist) {
+ /* BLE */
+ table_case = 113;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 106;
+ else
+ tdma_case = 104;
+ } else {
+ table_case = 113;
+ tdma_case = 104;
+ }
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+ u32 slot_type = 0;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)
+ table_case = 10;
+ else
+ table_case = 9;
+
+ slot_type = TDMA_4SLOT;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 13;
+ else
+ tdma_case = 14;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 112;
+
+ if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
+ tdma_case = 112;
+ else
+ tdma_case = 113;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
+}
+
+static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+ bool ap_enable = false;
+
+ if (efuse->share_ant) { /* Shared-Ant */
+ if (ap_enable) {
+ table_case = 2;
+ tdma_case = 0;
+ } else if (coex_stat->wl_gl_busy) {
+ table_case = 28;
+ tdma_case = 20;
+ } else {
+ table_case = 28;
+ tdma_case = 26;
+ }
+ } else { /* Non-Shared-Ant */
+ if (ap_enable) {
+ table_case = 100;
+ tdma_case = 100;
+ } else {
+ table_case = 119;
+ tdma_case = 120;
+ }
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)
+ table_case = 14;
+ else
+ table_case = 10;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 17;
+ else
+ tdma_case = 19;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 112;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 117;
+ else
+ tdma_case = 119;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+ u32 slot_type = 0;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (coex_stat->bt_ble_exist)
+ table_case = 26;
+ else
+ table_case = 9;
+
+ if (coex_stat->wl_gl_busy) {
+ slot_type = TDMA_4SLOT;
+ tdma_case = 13;
+ } else {
+ tdma_case = 14;
+ }
+ } else {
+ /* Non-Shared-Ant */
+ if (coex_stat->bt_ble_exist)
+ table_case = 121;
+ else
+ table_case = 113;
+
+ if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
+ tdma_case = 112;
+ else
+ tdma_case = 113;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
+}
+
+static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (coex_stat->wl_gl_busy &&
+ coex_stat->wl_noisy_level == 0)
+ table_case = 14;
+ else
+ table_case = 10;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 15;
+ else
+ tdma_case = 20;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 112;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 115;
+ else
+ tdma_case = 120;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 9;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 18;
+ else
+ tdma_case = 19;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 113;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 117;
+ else
+ tdma_case = 119;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 10;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 15;
+ else
+ tdma_case = 20;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 113;
+
+ if (coex_stat->wl_gl_busy)
+ tdma_case = 115;
+ else
+ tdma_case = 120;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 0;
+ tdma_case = 0;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 100;
+ tdma_case = 100;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 2;
+ tdma_case = 0;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 100;
+ tdma_case = 100;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (coex->under_5g)
+ return;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 28;
+ tdma_case = 0;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 100;
+ tdma_case = 100;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ if (coex_stat->bt_a2dp_exist) {
+ table_case = 9;
+ tdma_case = 11;
+ } else {
+ table_case = 9;
+ tdma_case = 7;
+ }
+ } else {
+ /* Non-Shared-Ant */
+ if (coex_stat->bt_a2dp_exist) {
+ table_case = 112;
+ tdma_case = 111;
+ } else {
+ table_case = 112;
+ tdma_case = 107;
+ }
+ }
+
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ u8 table_case, tdma_case;
+
+ if (efuse->share_ant) {
+ /* Shared-Ant */
+ table_case = 1;
+ tdma_case = 0;
+ } else {
+ /* Non-Shared-Ant */
+ table_case = 100;
+ tdma_case = 100;
+ }
+
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
+ rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ rtw_coex_table(rtwdev, table_case);
+ rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
+static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ u8 algorithm;
+
+ /* Non-Shared-Ant */
+ if (!efuse->share_ant && coex_stat->wl_gl_busy &&
+ COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&
+ COEX_RSSI_HIGH(coex_dm->bt_rssi_state[0])) {
+ rtw_coex_action_freerun(rtwdev);
+ return;
+ }
+
+ algorithm = rtw_coex_algorithm(rtwdev);
+
+ switch (algorithm) {
+ case COEX_ALGO_HFP:
+ rtw_coex_action_bt_hfp(rtwdev);
+ break;
+ case COEX_ALGO_HID:
+ rtw_coex_action_bt_hid(rtwdev);
+ break;
+ case COEX_ALGO_A2DP:
+ if (coex_stat->bt_a2dp_sink)
+ rtw_coex_action_bt_a2dpsink(rtwdev);
+ else
+ rtw_coex_action_bt_a2dp(rtwdev);
+ break;
+ case COEX_ALGO_PAN:
+ rtw_coex_action_bt_pan(rtwdev);
+ break;
+ case COEX_ALGO_A2DP_HID:
+ rtw_coex_action_bt_a2dp_hid(rtwdev);
+ break;
+ case COEX_ALGO_A2DP_PAN:
+ rtw_coex_action_bt_a2dp_pan(rtwdev);
+ break;
+ case COEX_ALGO_PAN_HID:
+ rtw_coex_action_bt_pan_hid(rtwdev);
+ break;
+ case COEX_ALGO_A2DP_PAN_HID:
+ rtw_coex_action_bt_a2dp_pan_hid(rtwdev);
+ break;
+ default:
+ case COEX_ALGO_NOPROFILE:
+ rtw_coex_action_bt_idle(rtwdev);
+ break;
+ }
+}
+
+static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ coex_dm->reason = reason;
+
+ /* update wifi_link_info_ext variable */
+ rtw_coex_update_wl_link_info(rtwdev, reason);
+
+ rtw_coex_monitor_bt_enable(rtwdev);
+
+ if (coex->stop_dm)
+ return;
+
+ if (coex_stat->wl_under_ips)
+ return;
+
+ if (coex->freeze && !coex_stat->bt_setup_link)
+ return;
+
+ coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++;
+ coex->freerun = false;
+
+ /* Pure-5G Coex Process */
+ if (coex->under_5g) {
+ coex_stat->wl_coex_mode = COEX_WLINK_5G;
+ rtw_coex_action_wl_under5g(rtwdev);
+ goto exit;
+ }
+
+ coex_stat->wl_coex_mode = COEX_WLINK_2G1PORT;
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
+ if (coex_stat->bt_disabled) {
+ rtw_coex_action_wl_only(rtwdev);
+ goto exit;
+ }
+
+ if (coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) {
+ rtw_coex_action_wl_native_lps(rtwdev);
+ goto exit;
+ }
+
+ if (coex_stat->bt_whck_test) {
+ rtw_coex_action_bt_whql_test(rtwdev);
+ goto exit;
+ }
+
+ if (coex_stat->bt_setup_link) {
+ rtw_coex_action_bt_relink(rtwdev);
+ goto exit;
+ }
+
+ if (coex_stat->bt_inq_page) {
+ rtw_coex_action_bt_inquiry(rtwdev);
+ goto exit;
+ }
+
+ if ((coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE ||
+ coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE) &&
+ coex_stat->wl_connected) {
+ rtw_coex_action_bt_idle(rtwdev);
+ goto exit;
+ }
+
+ if (coex_stat->wl_linkscan_proc) {
+ rtw_coex_action_wl_linkscan(rtwdev);
+ goto exit;
+ }
+
+ if (coex_stat->wl_connected)
+ rtw_coex_action_wl_connected(rtwdev);
+ else
+ rtw_coex_action_wl_not_connected(rtwdev);
+
+exit:
+ rtw_coex_set_gnt_fix(rtwdev);
+ rtw_coex_limited_wl(rtwdev);
+}
+
+static void rtw_coex_init_coex_var(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ u8 i;
+
+ memset(coex_dm, 0, sizeof(*coex_dm));
+ memset(coex_stat, 0, sizeof(*coex_stat));
+
+ for (i = 0; i < COEX_CNT_WL_MAX; i++)
+ coex_stat->cnt_wl[i] = 0;
+
+ for (i = 0; i < COEX_CNT_BT_MAX; i++)
+ coex_stat->cnt_bt[i] = 0;
+
+ for (i = 0; i < ARRAY_SIZE(coex_dm->bt_rssi_state); i++)
+ coex_dm->bt_rssi_state[i] = COEX_RSSI_STATE_LOW;
+
+ for (i = 0; i < ARRAY_SIZE(coex_dm->wl_rssi_state); i++)
+ coex_dm->wl_rssi_state[i] = COEX_RSSI_STATE_LOW;
+
+ coex_stat->wl_coex_mode = COEX_WLINK_MAX;
+}
+
+static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+
+ rtw_coex_init_coex_var(rtwdev);
+ rtw_coex_monitor_bt_enable(rtwdev);
+ rtw_coex_set_rfe_type(rtwdev);
+ rtw_coex_set_init(rtwdev);
+
+ /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */
+ rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_RSP, 1);
+
+ /* set Tx beacon = Hi-Pri */
+ rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACON, 1);
+
+ /* set Tx beacon queue = Hi-Pri */
+ rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACONQ, 1);
+
+ /* antenna config */
+ if (coex->wl_rf_off) {
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);
+ coex->stop_dm = true;
+ } else if (wifi_only) {
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WONLY);
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN,
+ true);
+ coex->stop_dm = true;
+ } else {
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_INIT);
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN,
+ true);
+ coex->stop_dm = false;
+ coex->freeze = true;
+ }
+
+ /* PTA parameter */
+ rtw_coex_table(rtwdev, 0);
+ rtw_coex_tdma(rtwdev, true, 0);
+ rtw_coex_query_bt_info(rtwdev);
+}
+
+void rtw_coex_power_on_setting(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+
+ coex->stop_dm = true;
+ coex->wl_rf_off = false;
+
+ /* enable BB, we can write 0x948 */
+ rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1));
+
+ rtw_coex_monitor_bt_enable(rtwdev);
+ rtw_coex_set_rfe_type(rtwdev);
+
+ /* set antenna path to BT */
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_POWERON);
+
+ /* red x issue */
+ rtw_write8(rtwdev, 0xff1a, 0x0);
+}
+
+void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
+{
+ __rtw_coex_init_hw_config(rtwdev, wifi_only);
+}
+
+void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+
+ if (coex->stop_dm)
+ return;
+
+ if (type == COEX_IPS_ENTER) {
+ coex_stat->wl_under_ips = true;
+
+ /* for lps off */
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);
+
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);
+ rtw_coex_action_coex_all_off(rtwdev);
+ } else if (type == COEX_IPS_LEAVE) {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);
+
+ /* run init hw config (exclude wifi only) */
+ __rtw_coex_init_hw_config(rtwdev, false);
+ /* sw all off */
+
+ coex_stat->wl_under_ips = false;
+ }
+}
+
+void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+
+ if (coex->stop_dm)
+ return;
+
+ if (type == COEX_LPS_ENABLE) {
+ coex_stat->wl_under_lps = true;
+
+ if (coex_stat->wl_force_lps_ctrl) {
+ /* for ps-tdma */
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
+ } else {
+ /* for native ps */
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false);
+
+ rtw_coex_run_coex(rtwdev, COEX_RSN_LPS);
+ }
+ } else if (type == COEX_LPS_DISABLE) {
+ coex_stat->wl_under_lps = false;
+
+ /* for lps off */
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
+
+ if (!coex_stat->wl_force_lps_ctrl)
+ rtw_coex_query_bt_info(rtwdev);
+ }
+}
+
+void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+
+ if (coex->stop_dm)
+ return;
+
+ coex->freeze = false;
+
+ if (type != COEX_SCAN_FINISH)
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN |
+ COEX_SCBD_ONOFF, true);
+
+ if (type == COEX_SCAN_START_5G) {
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
+ rtw_coex_run_coex(rtwdev, COEX_RSN_5GSCANSTART);
+ } else if ((type == COEX_SCAN_START_2G) || (type == COEX_SCAN_START)) {
+ coex_stat->wl_hi_pri_task2 = true;
+
+ /* Force antenna setup for no scan result issue */
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
+ rtw_coex_run_coex(rtwdev, COEX_RSN_2GSCANSTART);
+ } else {
+ coex_stat->wl_hi_pri_task2 = false;
+ rtw_coex_run_coex(rtwdev, COEX_RSN_SCANFINISH);
+ }
+}
+
+void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+
+ if (coex->stop_dm)
+ return;
+
+ if (type == COEX_SWITCH_TO_5G)
+ rtw_coex_run_coex(rtwdev, COEX_RSN_5GSWITCHBAND);
+ else if (type == COEX_SWITCH_TO_24G_NOFORSCAN)
+ rtw_coex_run_coex(rtwdev, COEX_RSN_2GSWITCHBAND);
+ else
+ rtw_coex_scan_notify(rtwdev, COEX_SCAN_START_2G);
+}
+
+void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+
+ if (coex->stop_dm)
+ return;
+
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN |
+ COEX_SCBD_ONOFF, true);
+
+ if (type == COEX_ASSOCIATE_5G_START) {
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
+ rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONSTART);
+ } else if (type == COEX_ASSOCIATE_5G_FINISH) {
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
+ rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONFINISH);
+ } else if (type == COEX_ASSOCIATE_START) {
+ coex_stat->wl_hi_pri_task1 = true;
+ coex_stat->cnt_wl[COEX_CNT_WL_CONNPKT] = 2;
+
+ /* Force antenna setup for no scan result issue */
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
+
+ rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONSTART);
+
+ /* To keep TDMA case during connect process,
+ * to avoid changed by Btinfo and runcoexmechanism
+ */
+ coex->freeze = true;
+ ieee80211_queue_delayed_work(rtwdev->hw, &coex->defreeze_work,
+ 5 * HZ);
+ } else {
+ coex_stat->wl_hi_pri_task1 = false;
+ coex->freeze = false;
+
+ rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONFINISH);
+ }
+}
+
+void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ u8 para[6] = {0};
+
+ if (coex->stop_dm)
+ return;
+
+ if (type == COEX_MEDIA_CONNECT_5G) {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
+
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);
+ rtw_coex_run_coex(rtwdev, COEX_RSN_5GMEDIA);
+ } else if (type == COEX_MEDIA_CONNECT) {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);
+
+ /* Force antenna setup for no scan result issue */
+ rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);
+
+ /* Set CCK Rx high Pri */
+ rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 1);
+
+ /* always enable 5ms extend if connect */
+ para[0] = COEX_H2C69_WL_LEAKAP;
+ para[1] = PARA1_H2C69_EN_5MS; /* enable 5ms extend */
+ rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]);
+ coex_stat->wl_slot_extend = true;
+ rtw_coex_run_coex(rtwdev, COEX_RSN_2GMEDIA);
+ } else {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false);
+
+ rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 0);
+
+ rtw_coex_run_coex(rtwdev, COEX_RSN_MEDIADISCON);
+ }
+
+ rtw_coex_update_wl_ch_info(rtwdev, type);
+}
+
+void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_chip_info *chip = rtwdev->chip;
+ unsigned long bt_relink_time;
+ u8 i, rsp_source = 0, type;
+
+ rsp_source = buf[0] & 0xf;
+ if (rsp_source >= COEX_BTINFO_SRC_MAX)
+ rsp_source = COEX_BTINFO_SRC_WL_FW;
+
+ if (rsp_source == COEX_BTINFO_SRC_BT_IQK) {
+ coex_stat->bt_iqk_state = buf[1];
+ if (coex_stat->bt_iqk_state == 1)
+ coex_stat->cnt_bt[COEX_CNT_BT_IQK]++;
+ else if (coex_stat->bt_iqk_state == 2)
+ coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]++;
+
+ return;
+ }
+
+ if (rsp_source == COEX_BTINFO_SRC_BT_SCBD) {
+ rtw_coex_monitor_bt_enable(rtwdev);
+ if (coex_stat->bt_disabled != coex_stat->bt_disabled_pre) {
+ coex_stat->bt_disabled_pre = coex_stat->bt_disabled;
+ rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
+ }
+ return;
+ }
+
+ if (rsp_source == COEX_BTINFO_SRC_BT_RSP ||
+ rsp_source == COEX_BTINFO_SRC_BT_ACT) {
+ if (coex_stat->bt_disabled) {
+ coex_stat->bt_disabled = false;
+ coex_stat->bt_reenable = true;
+ ieee80211_queue_delayed_work(rtwdev->hw,
+ &coex->bt_reenable_work,
+ 15 * HZ);
+ }
+ }
+
+ for (i = 0; i < length; i++) {
+ if (i < COEX_BTINFO_LENGTH_MAX)
+ coex_stat->bt_info_c2h[rsp_source][i] = buf[i];
+ else
+ break;
+ }
+
+ if (rsp_source == COEX_BTINFO_SRC_WL_FW) {
+ rtw_coex_update_bt_link_info(rtwdev);
+ rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
+ return;
+ }
+
+ /* get the same info from bt, skip it */
+ if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 &&
+ coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 &&
+ coex_stat->bt_info_c2h[rsp_source][3] == coex_stat->bt_info_hb0 &&
+ coex_stat->bt_info_c2h[rsp_source][4] == coex_stat->bt_info_hb1 &&
+ coex_stat->bt_info_c2h[rsp_source][5] == coex_stat->bt_info_hb2 &&
+ coex_stat->bt_info_c2h[rsp_source][6] == coex_stat->bt_info_hb3)
+ return;
+
+ coex_stat->bt_info_lb2 = coex_stat->bt_info_c2h[rsp_source][1];
+ coex_stat->bt_info_lb3 = coex_stat->bt_info_c2h[rsp_source][2];
+ coex_stat->bt_info_hb0 = coex_stat->bt_info_c2h[rsp_source][3];
+ coex_stat->bt_info_hb1 = coex_stat->bt_info_c2h[rsp_source][4];
+ coex_stat->bt_info_hb2 = coex_stat->bt_info_c2h[rsp_source][5];
+ coex_stat->bt_info_hb3 = coex_stat->bt_info_c2h[rsp_source][6];
+
+ /* 0xff means BT is under WHCK test */
+ coex_stat->bt_whck_test = (coex_stat->bt_info_lb2 == 0xff);
+ coex_stat->bt_inq_page = ((coex_stat->bt_info_lb2 & BIT(2)) == BIT(2));
+ coex_stat->bt_acl_busy = ((coex_stat->bt_info_lb2 & BIT(3)) == BIT(3));
+ coex_stat->cnt_bt[COEX_CNT_BT_RETRY] = coex_stat->bt_info_lb3 & 0xf;
+ if (coex_stat->cnt_bt[COEX_CNT_BT_RETRY] >= 1)
+ coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]++;
+
+ coex_stat->bt_fix_2M = ((coex_stat->bt_info_lb3 & BIT(4)) == BIT(4));
+ coex_stat->bt_inq = ((coex_stat->bt_info_lb3 & BIT(5)) == BIT(5));
+ if (coex_stat->bt_inq)
+ coex_stat->cnt_bt[COEX_CNT_BT_INQ]++;
+
+ coex_stat->bt_page = ((coex_stat->bt_info_lb3 & BIT(7)) == BIT(7));
+ if (coex_stat->bt_page) {
+ coex_stat->cnt_bt[COEX_CNT_BT_PAGE]++;
+ if (coex_stat->wl_linkscan_proc ||
+ coex_stat->wl_hi_pri_task1 ||
+ coex_stat->wl_hi_pri_task2 || coex_stat->wl_gl_busy)
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, true);
+ else
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);
+ } else {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);
+ }
+
+ /* unit: % (value-100 to translate to unit: dBm in coex info) */
+ if (chip->bt_rssi_type == COEX_BTRSSI_RATIO) {
+ coex_stat->bt_rssi = coex_stat->bt_info_hb0 * 2 + 10;
+ } else { /* original unit: dbm -> unit: % -> value-100 in coex info */
+ if (coex_stat->bt_info_hb0 <= 127)
+ coex_stat->bt_rssi = 100;
+ else if (256 - coex_stat->bt_info_hb0 <= 100)
+ coex_stat->bt_rssi = 100 - (256 - coex_stat->bt_info_hb0);
+ else
+ coex_stat->bt_rssi = 0;
+ }
+
+ coex_stat->bt_ble_exist = ((coex_stat->bt_info_hb1 & BIT(0)) == BIT(0));
+ if (coex_stat->bt_info_hb1 & BIT(1))
+ coex_stat->cnt_bt[COEX_CNT_BT_REINIT]++;
+
+ if (coex_stat->bt_info_hb1 & BIT(2)) {
+ coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK]++;
+ coex_stat->bt_setup_link = true;
+ if (coex_stat->bt_reenable)
+ bt_relink_time = 6 * HZ;
+ else
+ bt_relink_time = 2 * HZ;
+
+ ieee80211_queue_delayed_work(rtwdev->hw,
+ &coex->bt_relink_work,
+ bt_relink_time);
+ }
+
+ if (coex_stat->bt_info_hb1 & BIT(3))
+ coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT]++;
+
+ coex_stat->bt_ble_voice = ((coex_stat->bt_info_hb1 & BIT(4)) == BIT(4));
+ coex_stat->bt_ble_scan_en = ((coex_stat->bt_info_hb1 & BIT(5)) == BIT(5));
+ if (coex_stat->bt_info_hb1 & BIT(6))
+ coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH]++;
+
+ coex_stat->bt_multi_link = ((coex_stat->bt_info_hb1 & BIT(7)) == BIT(7));
+ /* resend wifi info to bt, it is reset and lost the info */
+ if ((coex_stat->bt_info_hb1 & BIT(1))) {
+ if (coex_stat->wl_connected)
+ type = COEX_MEDIA_CONNECT;
+ else
+ type = COEX_MEDIA_DISCONNECT;
+ rtw_coex_update_wl_ch_info(rtwdev, type);
+ }
+
+ /* if ignore_wlan_act && not set_up_link */
+ if ((coex_stat->bt_info_hb1 & BIT(3)) &&
+ (!(coex_stat->bt_info_hb1 & BIT(2))))
+ rtw_coex_ignore_wlan_act(rtwdev, false);
+
+ coex_stat->bt_opp_exist = ((coex_stat->bt_info_hb2 & BIT(0)) == BIT(0));
+ if (coex_stat->bt_info_hb2 & BIT(1))
+ coex_stat->cnt_bt[COEX_CNT_BT_AFHUPDATE]++;
+
+ coex_stat->bt_a2dp_active = (coex_stat->bt_info_hb2 & BIT(2)) == BIT(2);
+ coex_stat->bt_slave = ((coex_stat->bt_info_hb2 & BIT(3)) == BIT(3));
+ coex_stat->bt_hid_slot = (coex_stat->bt_info_hb2 & 0x30) >> 4;
+ coex_stat->bt_hid_pair_num = (coex_stat->bt_info_hb2 & 0xc0) >> 6;
+ if (coex_stat->bt_hid_pair_num > 0 && coex_stat->bt_hid_slot >= 2)
+ coex_stat->bt_418_hid_exist = true;
+ else if (coex_stat->bt_hid_pair_num == 0)
+ coex_stat->bt_418_hid_exist = false;
+
+ if ((coex_stat->bt_info_lb2 & 0x49) == 0x49)
+ coex_stat->bt_a2dp_bitpool = (coex_stat->bt_info_hb3 & 0x7f);
+ else
+ coex_stat->bt_a2dp_bitpool = 0;
+
+ coex_stat->bt_a2dp_sink = ((coex_stat->bt_info_hb3 & BIT(7)) == BIT(7));
+
+ rtw_coex_update_bt_link_info(rtwdev);
+ rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
+}
+
+void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ u8 val;
+ int i;
+
+ if (WARN(length < 8, "invalid wl info c2h length\n"))
+ return;
+
+ if (buf[0] != 0x08)
+ return;
+
+ for (i = 1; i < 8; i++) {
+ val = coex_stat->wl_fw_dbg_info_pre[i];
+ if (buf[i] >= val)
+ coex_stat->wl_fw_dbg_info[i] = buf[i] - val;
+ else
+ coex_stat->wl_fw_dbg_info[i] = val - buf[i];
+
+ coex_stat->wl_fw_dbg_info_pre[i] = buf[i];
+ }
+
+ coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]++;
+ rtw_coex_wl_ccklock_action(rtwdev);
+ rtw_coex_wl_ccklock_detect(rtwdev);
+}
+
+void rtw_coex_coex_dm_reset(struct rtw_dev *rtwdev)
+{
+ __rtw_coex_init_hw_config(rtwdev, false);
+}
+
+void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+
+ if (coex->stop_dm)
+ return;
+
+ rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
+}
+
+void rtw_coex_bt_relink_work(struct work_struct *work)
+{
+ struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
+ coex.bt_relink_work.work);
+ struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
+
+ mutex_lock(&rtwdev->mutex);
+ coex_stat->bt_setup_link = false;
+ rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
+ mutex_unlock(&rtwdev->mutex);
+}
+
+void rtw_coex_bt_reenable_work(struct work_struct *work)
+{
+ struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
+ coex.bt_reenable_work.work);
+ struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
+
+ mutex_lock(&rtwdev->mutex);
+ coex_stat->bt_reenable = false;
+ mutex_unlock(&rtwdev->mutex);
+}
+
+void rtw_coex_defreeze_work(struct work_struct *work)
+{
+ struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
+ coex.defreeze_work.work);
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
+
+ mutex_lock(&rtwdev->mutex);
+ coex->freeze = false;
+ coex_stat->wl_hi_pri_task1 = false;
+ rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
+ mutex_unlock(&rtwdev->mutex);
+}
diff --git a/drivers/net/wireless/realtek/rtw88/coex.h b/drivers/net/wireless/realtek/rtw88/coex.h
new file mode 100644
index 0000000..56e871b
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/coex.h
@@ -0,0 +1,369 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2018-2019 Realtek Corporation
+ */
+
+#ifndef __RTW_COEX_H__
+#define __RTW_COEX_H__
+
+/* BT profile map bit definition */
+#define BPM_HFP BIT(0)
+#define BPM_HID BIT(1)
+#define BPM_A2DP BIT(2)
+#define BPM_PAN BIT(3)
+
+#define COEX_RESP_ACK_BY_WL_FW 0x1
+#define COEX_REQUEST_TIMEOUT msecs_to_jiffies(10)
+
+#define COEX_MIN_DELAY 10 /* delay unit in ms */
+#define COEX_RFK_TIMEOUT 600 /* RFK timeout in ms */
+
+#define COEX_RF_OFF 0x0
+#define COEX_RF_ON 0x1
+
+#define COEX_H2C69_WL_LEAKAP 0xc
+#define PARA1_H2C69_DIS_5MS 0x1
+#define PARA1_H2C69_EN_5MS 0x0
+
+#define COEX_H2C69_TDMA_SLOT 0xb
+#define PARA1_H2C69_TDMA_4SLOT 0xc1
+#define PARA1_H2C69_TDMA_2SLOT 0x1
+
+#define TDMA_4SLOT BIT(8)
+
+#define COEX_RSSI_STEP 4
+#define COEX_RSSI_HIGH(rssi) \
+ ({ typeof(rssi) __rssi__ = rssi; \
+ (__rssi__ == COEX_RSSI_STATE_HIGH || \
+ __rssi__ == COEX_RSSI_STATE_STAY_HIGH ? true : false); })
+
+#define COEX_RSSI_MEDIUM(rssi) \
+ ({ typeof(rssi) __rssi__ = rssi; \
+ (__rssi__ == COEX_RSSI_STATE_MEDIUM || \
+ __rssi__ == COEX_RSSI_STATE_STAY_MEDIUM ? true : false); })
+
+#define COEX_RSSI_LOW(rssi) \
+ ({ typeof(rssi) __rssi__ = rssi; \
+ (__rssi__ == COEX_RSSI_STATE_LOW || \
+ __rssi__ == COEX_RSSI_STATE_STAY_LOW ? true : false); })
+
+#define GET_COEX_RESP_BT_SCAN_TYPE(payload) \
+ le64_get_bits(*((__le64 *)(payload)), GENMASK(31, 24))
+
+enum coex_mp_info_op {
+ BT_MP_INFO_OP_PATCH_VER = 0x00,
+ BT_MP_INFO_OP_READ_REG = 0x11,
+ BT_MP_INFO_OP_SUPP_FEAT = 0x2a,
+ BT_MP_INFO_OP_SUPP_VER = 0x2b,
+ BT_MP_INFO_OP_SCAN_TYPE = 0x2d,
+ BT_MP_INFO_OP_LNA_CONSTRAINT = 0x32,
+};
+
+enum coex_set_ant_phase {
+ COEX_SET_ANT_INIT,
+ COEX_SET_ANT_WONLY,
+ COEX_SET_ANT_WOFF,
+ COEX_SET_ANT_2G,
+ COEX_SET_ANT_5G,
+ COEX_SET_ANT_POWERON,
+ COEX_SET_ANT_2G_WLBT,
+ COEX_SET_ANT_2G_FREERUN,
+
+ COEX_SET_ANT_MAX
+};
+
+enum coex_runreason {
+ COEX_RSN_2GSCANSTART = 0,
+ COEX_RSN_5GSCANSTART = 1,
+ COEX_RSN_SCANFINISH = 2,
+ COEX_RSN_2GSWITCHBAND = 3,
+ COEX_RSN_5GSWITCHBAND = 4,
+ COEX_RSN_2GCONSTART = 5,
+ COEX_RSN_5GCONSTART = 6,
+ COEX_RSN_2GCONFINISH = 7,
+ COEX_RSN_5GCONFINISH = 8,
+ COEX_RSN_2GMEDIA = 9,
+ COEX_RSN_5GMEDIA = 10,
+ COEX_RSN_MEDIADISCON = 11,
+ COEX_RSN_BTINFO = 12,
+ COEX_RSN_LPS = 13,
+ COEX_RSN_WLSTATUS = 14,
+
+ COEX_RSN_MAX
+};
+
+enum coex_lte_coex_table_type {
+ COEX_CTT_WL_VS_LTE,
+ COEX_CTT_BT_VS_LTE,
+};
+
+enum coex_gnt_setup_state {
+ COEX_GNT_SET_HW_PTA = 0x0,
+ COEX_GNT_SET_SW_LOW = 0x1,
+ COEX_GNT_SET_SW_HIGH = 0x3,
+};
+
+enum coex_ext_ant_switch_pos_type {
+ COEX_SWITCH_TO_BT,
+ COEX_SWITCH_TO_WLG,
+ COEX_SWITCH_TO_WLA,
+ COEX_SWITCH_TO_NOCARE,
+ COEX_SWITCH_TO_WLG_BT,
+
+ COEX_SWITCH_TO_MAX
+};
+
+enum coex_ext_ant_switch_ctrl_type {
+ COEX_SWITCH_CTRL_BY_BBSW,
+ COEX_SWITCH_CTRL_BY_PTA,
+ COEX_SWITCH_CTRL_BY_ANTDIV,
+ COEX_SWITCH_CTRL_BY_MAC,
+ COEX_SWITCH_CTRL_BY_BT,
+ COEX_SWITCH_CTRL_BY_FW,
+
+ COEX_SWITCH_CTRL_MAX
+};
+
+enum coex_algorithm {
+ COEX_ALGO_NOPROFILE = 0,
+ COEX_ALGO_HFP = 1,
+ COEX_ALGO_HID = 2,
+ COEX_ALGO_A2DP = 3,
+ COEX_ALGO_PAN = 4,
+ COEX_ALGO_A2DP_HID = 5,
+ COEX_ALGO_A2DP_PAN = 6,
+ COEX_ALGO_PAN_HID = 7,
+ COEX_ALGO_A2DP_PAN_HID = 8,
+
+ COEX_ALGO_MAX
+};
+
+enum coex_wl_link_mode {
+ COEX_WLINK_2G1PORT = 0x0,
+ COEX_WLINK_5G = 0x3,
+ COEX_WLINK_MAX
+};
+
+enum coex_wl2bt_scoreboard {
+ COEX_SCBD_ACTIVE = BIT(0),
+ COEX_SCBD_ONOFF = BIT(1),
+ COEX_SCBD_SCAN = BIT(2),
+ COEX_SCBD_UNDERTEST = BIT(3),
+ COEX_SCBD_RXGAIN = BIT(4),
+ COEX_SCBD_BT_RFK = BIT(5),
+ COEX_SCBD_WLBUSY = BIT(6),
+ COEX_SCBD_EXTFEM = BIT(8),
+ COEX_SCBD_TDMA = BIT(9),
+ COEX_SCBD_FIX2M = BIT(10),
+ COEX_SCBD_ALL = GENMASK(15, 0),
+};
+
+enum coex_power_save_type {
+ COEX_PS_WIFI_NATIVE = 0,
+ COEX_PS_LPS_ON = 1,
+ COEX_PS_LPS_OFF = 2,
+};
+
+enum coex_rssi_state {
+ COEX_RSSI_STATE_HIGH,
+ COEX_RSSI_STATE_MEDIUM,
+ COEX_RSSI_STATE_LOW,
+ COEX_RSSI_STATE_STAY_HIGH,
+ COEX_RSSI_STATE_STAY_MEDIUM,
+ COEX_RSSI_STATE_STAY_LOW,
+};
+
+enum coex_notify_type_ips {
+ COEX_IPS_LEAVE = 0x0,
+ COEX_IPS_ENTER = 0x1,
+};
+
+enum coex_notify_type_lps {
+ COEX_LPS_DISABLE = 0x0,
+ COEX_LPS_ENABLE = 0x1,
+};
+
+enum coex_notify_type_scan {
+ COEX_SCAN_FINISH,
+ COEX_SCAN_START,
+ COEX_SCAN_START_2G,
+ COEX_SCAN_START_5G,
+};
+
+enum coex_notify_type_switchband {
+ COEX_NOT_SWITCH,
+ COEX_SWITCH_TO_24G,
+ COEX_SWITCH_TO_5G,
+ COEX_SWITCH_TO_24G_NOFORSCAN,
+};
+
+enum coex_notify_type_associate {
+ COEX_ASSOCIATE_FINISH,
+ COEX_ASSOCIATE_START,
+ COEX_ASSOCIATE_5G_FINISH,
+ COEX_ASSOCIATE_5G_START,
+};
+
+enum coex_notify_type_media_status {
+ COEX_MEDIA_DISCONNECT,
+ COEX_MEDIA_CONNECT,
+ COEX_MEDIA_CONNECT_5G,
+};
+
+enum coex_bt_status {
+ COEX_BTSTATUS_NCON_IDLE = 0,
+ COEX_BTSTATUS_CON_IDLE = 1,
+ COEX_BTSTATUS_INQ_PAGE = 2,
+ COEX_BTSTATUS_ACL_BUSY = 3,
+ COEX_BTSTATUS_SCO_BUSY = 4,
+ COEX_BTSTATUS_ACL_SCO_BUSY = 5,
+
+ COEX_BTSTATUS_MAX
+};
+
+enum coex_wl_tput_dir {
+ COEX_WL_TPUT_TX = 0x0,
+ COEX_WL_TPUT_RX = 0x1,
+ COEX_WL_TPUT_MAX
+};
+
+enum coex_wl_priority_mask {
+ COEX_WLPRI_RX_RSP = 2,
+ COEX_WLPRI_TX_RSP = 3,
+ COEX_WLPRI_TX_BEACON = 4,
+ COEX_WLPRI_TX_OFDM = 11,
+ COEX_WLPRI_TX_CCK = 12,
+ COEX_WLPRI_TX_BEACONQ = 27,
+ COEX_WLPRI_RX_CCK = 28,
+ COEX_WLPRI_RX_OFDM = 29,
+ COEX_WLPRI_MAX
+};
+
+enum coex_commom_chip_setup {
+ COEX_CSETUP_INIT_HW = 0x0,
+ COEX_CSETUP_ANT_SWITCH = 0x1,
+ COEX_CSETUP_GNT_FIX = 0x2,
+ COEX_CSETUP_GNT_DEBUG = 0x3,
+ COEX_CSETUP_RFE_TYPE = 0x4,
+ COEX_CSETUP_COEXINFO_HW = 0x5,
+ COEX_CSETUP_WL_TX_POWER = 0x6,
+ COEX_CSETUP_WL_RX_GAIN = 0x7,
+ COEX_CSETUP_WLAN_ACT_IPS = 0x8,
+ COEX_CSETUP_MAX
+};
+
+enum coex_indirect_reg_type {
+ COEX_INDIRECT_1700 = 0x0,
+ COEX_INDIRECT_7C0 = 0x1,
+ COEX_INDIRECT_MAX
+};
+
+enum coex_pstdma_type {
+ COEX_PSTDMA_FORCE_LPSOFF = 0x0,
+ COEX_PSTDMA_FORCE_LPSON = 0x1,
+ COEX_PSTDMA_MAX
+};
+
+enum coex_btrssi_type {
+ COEX_BTRSSI_RATIO = 0x0,
+ COEX_BTRSSI_DBM = 0x1,
+ COEX_BTRSSI_MAX
+};
+
+struct coex_table_para {
+ u32 bt;
+ u32 wl;
+};
+
+struct coex_tdma_para {
+ u8 para[5];
+};
+
+struct coex_5g_afh_map {
+ u32 wl_5g_ch;
+ u8 bt_skip_ch;
+ u8 bt_skip_span;
+};
+
+struct coex_rf_para {
+ u8 wl_pwr_dec_lvl;
+ u8 bt_pwr_dec_lvl;
+ bool wl_low_gain_en;
+ u8 bt_lna_lvl;
+};
+
+static inline void rtw_coex_set_init(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ chip->ops->coex_set_init(rtwdev);
+}
+
+static inline
+void rtw_coex_set_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, u8 pos_type)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ if (!chip->ops->coex_set_ant_switch)
+ return;
+
+ chip->ops->coex_set_ant_switch(rtwdev, ctrl_type, pos_type);
+}
+
+static inline void rtw_coex_set_gnt_fix(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ chip->ops->coex_set_gnt_fix(rtwdev);
+}
+
+static inline void rtw_coex_set_gnt_debug(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ chip->ops->coex_set_gnt_debug(rtwdev);
+}
+
+static inline void rtw_coex_set_rfe_type(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ chip->ops->coex_set_rfe_type(rtwdev);
+}
+
+static inline void rtw_coex_set_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ chip->ops->coex_set_wl_tx_power(rtwdev, wl_pwr);
+}
+
+static inline
+void rtw_coex_set_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ chip->ops->coex_set_wl_rx_gain(rtwdev, low_gain);
+}
+
+void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb);
+void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr,
+ u32 mask, u32 val);
+void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set);
+
+void rtw_coex_bt_relink_work(struct work_struct *work);
+void rtw_coex_bt_reenable_work(struct work_struct *work);
+void rtw_coex_defreeze_work(struct work_struct *work);
+
+void rtw_coex_power_on_setting(struct rtw_dev *rtwdev);
+void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only);
+void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type);
+void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type);
+void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type);
+void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 action);
+void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 status);
+void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 len);
+void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
+void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type);
+void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev);
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index 3b06f71..b082e2c 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -3,6 +3,7 @@
*/
#include "main.h"
+#include "coex.h"
#include "fw.h"
#include "tx.h"
#include "reg.h"
@@ -39,6 +40,12 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
mutex_lock(&rtwdev->mutex);
switch (c2h->id) {
+ case C2H_BT_INFO:
+ rtw_coex_bt_info_notify(rtwdev, c2h->payload, len);
+ break;
+ case C2H_WLAN_INFO:
+ rtw_coex_wl_fwdbginfo_notify(rtwdev, c2h->payload, len);
+ break;
case C2H_HALMAC:
rtw_fw_c2h_cmd_handle_ext(rtwdev, skb);
break;
@@ -63,6 +70,9 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
c2h->id, c2h->seq, len);
switch (c2h->id) {
+ case C2H_BT_MP_INFO:
+ rtw_coex_info_response(rtwdev, skb);
+ break;
default:
/* pass offset for further operation */
*((u32 *)skb->cb) = pkt_offset;
@@ -206,6 +216,102 @@ void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para)
rtw_fw_send_h2c_packet(rtwdev, h2c_pkt);
}
+void rtw_fw_query_bt_info(struct rtw_dev *rtwdev)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_QUERY_BT_INFO);
+
+ SET_QUERY_BT_INFO(h2c_pkt, true);
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+
+void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_WL_CH_INFO);
+
+ SET_WL_CH_INFO_LINK(h2c_pkt, link);
+ SET_WL_CH_INFO_CHNL(h2c_pkt, ch);
+ SET_WL_CH_INFO_BW(h2c_pkt, bw);
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+
+void rtw_fw_query_bt_mp_info(struct rtw_dev *rtwdev,
+ struct rtw_coex_info_req *req)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_QUERY_BT_MP_INFO);
+
+ SET_BT_MP_INFO_SEQ(h2c_pkt, req->seq);
+ SET_BT_MP_INFO_OP_CODE(h2c_pkt, req->op_code);
+ SET_BT_MP_INFO_PARA1(h2c_pkt, req->para1);
+ SET_BT_MP_INFO_PARA2(h2c_pkt, req->para2);
+ SET_BT_MP_INFO_PARA3(h2c_pkt, req->para3);
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+
+void rtw_fw_force_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+ u8 index = 0 - bt_pwr_dec_lvl;
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_FORCE_BT_TX_POWER);
+
+ SET_BT_TX_POWER_INDEX(h2c_pkt, index);
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+
+void rtw_fw_bt_ignore_wlan_action(struct rtw_dev *rtwdev, bool enable)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_IGNORE_WLAN_ACTION);
+
+ SET_IGNORE_WLAN_ACTION_EN(h2c_pkt, enable);
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+
+void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev,
+ u8 para1, u8 para2, u8 para3, u8 para4, u8 para5)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_COEX_TDMA_TYPE);
+
+ SET_COEX_TDMA_TYPE_PARA1(h2c_pkt, para1);
+ SET_COEX_TDMA_TYPE_PARA2(h2c_pkt, para2);
+ SET_COEX_TDMA_TYPE_PARA3(h2c_pkt, para3);
+ SET_COEX_TDMA_TYPE_PARA4(h2c_pkt, para4);
+ SET_COEX_TDMA_TYPE_PARA5(h2c_pkt, para5);
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+
+void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BT_WIFI_CONTROL);
+
+ SET_BT_WIFI_CONTROL_OP_CODE(h2c_pkt, op_code);
+
+ SET_BT_WIFI_CONTROL_DATA1(h2c_pkt, *data);
+ SET_BT_WIFI_CONTROL_DATA2(h2c_pkt, *(data + 1));
+ SET_BT_WIFI_CONTROL_DATA3(h2c_pkt, *(data + 2));
+ SET_BT_WIFI_CONTROL_DATA4(h2c_pkt, *(data + 3));
+ SET_BT_WIFI_CONTROL_DATA5(h2c_pkt, *(data + 4));
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+
void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si)
{
u8 h2c_pkt[H2C_PKT_SIZE] = {0};
diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h
index 67f6cf7..e95d85b 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.h
+++ b/drivers/net/wireless/realtek/rtw88/fw.h
@@ -35,7 +35,9 @@
enum rtw_c2h_cmd_id {
C2H_BT_INFO = 0x09,
+ C2H_BT_MP_INFO = 0x0b,
C2H_HW_FEATURE_REPORT = 0x19,
+ C2H_WLAN_INFO = 0x27,
C2H_HW_FEATURE_DUMP = 0xfd,
C2H_HALMAC = 0xff,
};
@@ -71,6 +73,14 @@ enum rtw_fw_rf_type {
FW_RF_MAX_TYPE = 0xF,
};
+struct rtw_coex_info_req {
+ u8 seq;
+ u8 op_code;
+ u8 para1;
+ u8 para2;
+ u8 para3;
+};
+
struct rtw_iqk_para {
u8 clear;
u8 segment_iqk;
@@ -139,6 +149,14 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define H2C_CMD_RA_INFO 0x40
#define H2C_CMD_RSSI_MONITOR 0x42
+#define H2C_CMD_COEX_TDMA_TYPE 0x60
+#define H2C_CMD_QUERY_BT_INFO 0x61
+#define H2C_CMD_FORCE_BT_TX_POWER 0x62
+#define H2C_CMD_IGNORE_WLAN_ACTION 0x63
+#define H2C_CMD_WL_CH_INFO 0x66
+#define H2C_CMD_QUERY_BT_MP_INFO 0x67
+#define H2C_CMD_BT_WIFI_CONTROL 0x69
+
#define SET_H2C_CMD_ID_CLASS(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(7, 0))
@@ -191,6 +209,50 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16))
#define SET_RA_INFO_RA_MASK3(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(31, 24))
+#define SET_QUERY_BT_INFO(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
+#define SET_WL_CH_INFO_LINK(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
+#define SET_WL_CH_INFO_CHNL(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
+#define SET_WL_CH_INFO_BW(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
+#define SET_BT_MP_INFO_SEQ(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 12))
+#define SET_BT_MP_INFO_OP_CODE(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
+#define SET_BT_MP_INFO_PARA1(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
+#define SET_BT_MP_INFO_PARA2(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
+#define SET_BT_MP_INFO_PARA3(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
+#define SET_BT_TX_POWER_INDEX(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
+#define SET_IGNORE_WLAN_ACTION_EN(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
+#define SET_COEX_TDMA_TYPE_PARA1(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
+#define SET_COEX_TDMA_TYPE_PARA2(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
+#define SET_COEX_TDMA_TYPE_PARA3(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
+#define SET_COEX_TDMA_TYPE_PARA4(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
+#define SET_COEX_TDMA_TYPE_PARA5(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
+#define SET_BT_WIFI_CONTROL_OP_CODE(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
+#define SET_BT_WIFI_CONTROL_DATA1(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
+#define SET_BT_WIFI_CONTROL_DATA2(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
+#define SET_BT_WIFI_CONTROL_DATA3(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
+#define SET_BT_WIFI_CONTROL_DATA4(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
+#define SET_BT_WIFI_CONTROL_DATA5(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16))
static inline struct rtw_c2h_cmd *get_c2h_from_skb(struct sk_buff *skb)
{
@@ -208,6 +270,15 @@ void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev);
void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para);
void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev);
+void rtw_fw_query_bt_info(struct rtw_dev *rtwdev);
+void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw);
+void rtw_fw_query_bt_mp_info(struct rtw_dev *rtwdev,
+ struct rtw_coex_info_req *req);
+void rtw_fw_force_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl);
+void rtw_fw_bt_ignore_wlan_action(struct rtw_dev *rtwdev, bool enable);
+void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev,
+ u8 para1, u8 para2, u8 para3, u8 para4, u8 para5);
+void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data);
void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool conn);
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index abe6a14..fedea28 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -7,6 +7,7 @@
#include "tx.h"
#include "fw.h"
#include "mac.h"
+#include "coex.h"
#include "ps.h"
#include "reg.h"
#include "debug.h"
@@ -253,6 +254,7 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
enum rtw_net_type net_type;
if (conf->assoc) {
+ rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH);
net_type = RTW_NET_MGD_LINKED;
chip->ops->do_iqk(rtwdev);
@@ -262,6 +264,7 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
rtw_add_rsvd_page(rtwdev, RSVD_NULL, true);
rtw_fw_download_rsvd_page(rtwdev, vif);
rtw_send_rsvd_page_h2c(rtwdev);
+ rtw_coex_media_status_notify(rtwdev, conf->assoc);
} else {
net_type = RTW_NET_NO_LINK;
rtwvif->aid = 0;
@@ -469,6 +472,8 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw,
config |= PORT_SET_MAC_ADDR;
rtw_vif_port_config(rtwdev, rtwvif, config);
+ rtw_coex_scan_notify(rtwdev, COEX_SCAN_START);
+
rtw_flag_set(rtwdev, RTW_FLAG_DIG_DISABLE);
rtw_flag_set(rtwdev, RTW_FLAG_SCANNING);
@@ -491,6 +496,19 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,
config |= PORT_SET_MAC_ADDR;
rtw_vif_port_config(rtwdev, rtwvif, config);
+ rtw_coex_scan_notify(rtwdev, COEX_SCAN_FINISH);
+
+ mutex_unlock(&rtwdev->mutex);
+}
+
+static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u16 duration)
+{
+ struct rtw_dev *rtwdev = hw->priv;
+
+ mutex_lock(&rtwdev->mutex);
+ rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START);
mutex_unlock(&rtwdev->mutex);
}
@@ -509,5 +527,6 @@ const struct ieee80211_ops rtw_ops = {
.ampdu_action = rtw_ops_ampdu_action,
.sw_scan_start = rtw_ops_sw_scan_start,
.sw_scan_complete = rtw_ops_sw_scan_complete,
+ .mgd_prepare_tx = rtw_ops_mgd_prepare_tx,
};
EXPORT_SYMBOL(rtw_ops);
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 5a2c062..e5a6bc0 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -8,6 +8,7 @@
#include "ps.h"
#include "sec.h"
#include "mac.h"
+#include "coex.h"
#include "phy.h"
#include "reg.h"
#include "efuse.h"
@@ -149,6 +150,7 @@ static void rtw_watch_dog_work(struct work_struct *work)
struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
watch_dog_work.work);
struct rtw_watch_dog_iter_data data = {};
+ bool busy_traffic = rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC);
if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING))
return;
@@ -156,6 +158,14 @@ static void rtw_watch_dog_work(struct work_struct *work)
ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work,
RTW_WATCH_DOG_DELAY_TIME);
+ if (rtwdev->stats.tx_cnt > 100 || rtwdev->stats.rx_cnt > 100)
+ rtw_flag_set(rtwdev, RTW_FLAG_BUSY_TRAFFIC);
+ else
+ rtw_flag_clear(rtwdev, RTW_FLAG_BUSY_TRAFFIC);
+
+ if (busy_traffic != rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC))
+ rtw_coex_wl_status_change_notify(rtwdev);
+
/* reset tx/rx statictics */
rtwdev->stats.tx_unicast = 0;
rtwdev->stats.rx_unicast = 0;
@@ -298,6 +308,15 @@ void rtw_set_channel(struct rtw_dev *rtwdev)
chip->ops->set_channel(rtwdev, center_chan, bandwidth, primary_chan_idx);
+ if (hal->current_band_type == RTW_BAND_5G) {
+ rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_5G);
+ } else {
+ if (rtw_flag_check(rtwdev, RTW_FLAG_SCANNING))
+ rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G);
+ else
+ rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G_NOFORSCAN);
+ }
+
rtw_phy_set_tx_power_level(rtwdev, center_chan);
}
@@ -641,6 +660,7 @@ static int rtw_power_on(struct rtw_dev *rtwdev)
{
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fw_state *fw = &rtwdev->fw;
+ bool wifi_only;
int ret;
ret = rtw_hci_setup(rtwdev);
@@ -684,6 +704,10 @@ static int rtw_power_on(struct rtw_dev *rtwdev)
goto err_off;
}
+ wifi_only = !rtwdev->efuse.btcoex;
+ rtw_coex_power_on_setting(rtwdev);
+ rtw_coex_init_hw_config(rtwdev, wifi_only);
+
return 0;
err_off:
@@ -722,10 +746,15 @@ static void rtw_power_off(struct rtw_dev *rtwdev)
void rtw_core_stop(struct rtw_dev *rtwdev)
{
+ struct rtw_coex *coex = &rtwdev->coex;
+
rtw_flag_clear(rtwdev, RTW_FLAG_RUNNING);
rtw_flag_clear(rtwdev, RTW_FLAG_FW_RUNNING);
cancel_delayed_work_sync(&rtwdev->watch_dog_work);
+ cancel_delayed_work_sync(&coex->bt_relink_work);
+ cancel_delayed_work_sync(&coex->bt_reenable_work);
+ cancel_delayed_work_sync(&coex->defreeze_work);
rtw_power_off(rtwdev);
}
@@ -876,7 +905,6 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev)
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_efuse *efuse = &rtwdev->efuse;
- u32 wl_bt_pwr_ctrl;
int ret = 0;
switch (rtw_hci_type(rtwdev)) {
@@ -888,9 +916,6 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev)
return -EINVAL;
}
- wl_bt_pwr_ctrl = rtw_read32(rtwdev, REG_WL_BT_PWR_CTRL);
- if (wl_bt_pwr_ctrl & BIT_BT_FUNC_EN)
- rtwdev->efuse.btcoex = true;
hal->chip_version = rtw_read32(rtwdev, REG_SYS_CFG1);
hal->fab_version = BIT_GET_VENDOR_ID(hal->chip_version) >> 2;
hal->cut_version = BIT_GET_CHIP_VER(hal->chip_version);
@@ -1044,11 +1069,14 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev)
efuse->lna_type_5g = 0;
if (efuse->channel_plan == 0xff)
efuse->channel_plan = 0x7f;
+ if (efuse->rf_board_option == 0xff)
+ efuse->rf_board_option = 0;
if (efuse->bt_setting & BIT(0))
efuse->share_ant = true;
if (efuse->regd == 0xff)
efuse->regd = 0;
+ efuse->btcoex = (efuse->rf_board_option & 0xe0) == 0x20;
efuse->ext_pa_2g = efuse->pa_type_2g & BIT(4) ? 1 : 0;
efuse->ext_lna_2g = efuse->lna_type_2g & BIT(3) ? 1 : 0;
efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0;
@@ -1111,6 +1139,7 @@ EXPORT_SYMBOL(rtw_chip_info_setup);
int rtw_core_init(struct rtw_dev *rtwdev)
{
+ struct rtw_coex *coex = &rtwdev->coex;
int ret;
INIT_LIST_HEAD(&rtwdev->rsvd_page_list);
@@ -1120,8 +1149,12 @@ int rtw_core_init(struct rtw_dev *rtwdev)
INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work);
INIT_DELAYED_WORK(&rtwdev->lps_work, rtw_lps_work);
+ INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work);
+ INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work);
+ INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work);
INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work);
skb_queue_head_init(&rtwdev->c2h_queue);
+ skb_queue_head_init(&rtwdev->coex.queue);
skb_queue_head_init(&rtwdev->tx_report.queue);
spin_lock_init(&rtwdev->dm_lock);
@@ -1130,8 +1163,11 @@ int rtw_core_init(struct rtw_dev *rtwdev)
spin_lock_init(&rtwdev->tx_report.q_lock);
mutex_init(&rtwdev->mutex);
+ mutex_init(&rtwdev->coex.mutex);
mutex_init(&rtwdev->hal.tx_power_mutex);
+ init_waitqueue_head(&rtwdev->coex.wait);
+
rtwdev->sec.total_cam_num = 32;
rtwdev->hal.current_channel = 1;
set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map);
@@ -1174,6 +1210,7 @@ void rtw_core_deinit(struct rtw_dev *rtwdev)
}
mutex_destroy(&rtwdev->mutex);
+ mutex_destroy(&rtwdev->coex.mutex);
mutex_destroy(&rtwdev->hal.tx_power_mutex);
}
EXPORT_SYMBOL(rtw_core_deinit);
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 8fa0575..9208b9c 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -310,6 +310,7 @@ enum rtw_flags {
RTW_FLAG_INACTIVE_PS,
RTW_FLAG_LEISURE_PS,
RTW_FLAG_DIG_DISABLE,
+ RTW_FLAG_BUSY_TRAFFIC,
NUM_OF_RTW_FLAGS,
};
@@ -640,6 +641,16 @@ struct rtw_chip_ops {
void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable);
void (*false_alarm_statistics)(struct rtw_dev *rtwdev);
void (*do_iqk)(struct rtw_dev *rtwdev);
+
+ /* for coex */
+ void (*coex_set_init)(struct rtw_dev *rtwdev);
+ void (*coex_set_ant_switch)(struct rtw_dev *rtwdev,
+ u8 ctrl_type, u8 pos_type);
+ void (*coex_set_gnt_fix)(struct rtw_dev *rtwdev);
+ void (*coex_set_gnt_debug)(struct rtw_dev *rtwdev);
+ void (*coex_set_rfe_type)(struct rtw_dev *rtwdev);
+ void (*coex_set_wl_tx_power)(struct rtw_dev *rtwdev, u8 wl_pwr);
+ void (*coex_set_wl_rx_gain)(struct rtw_dev *rtwdev, bool low_gain);
};
#define RTW_PWR_POLLING_CNT 20000
@@ -852,6 +863,216 @@ struct rtw_chip_info {
const struct rtw_rfe_def *rfe_defs;
u32 rfe_defs_size;
+
+ /* coex paras */
+ u32 coex_para_ver;
+ u8 bt_desired_ver;
+ bool scbd_support;
+ bool new_scbd10_def; /* true: fix 2M(8822c) */
+ u8 pstdma_type; /* 0: LPSoff, 1:LPSon */
+ u8 bt_rssi_type;
+ u8 ant_isolation;
+ u8 rssi_tolerance;
+ u8 table_sant_num;
+ u8 table_nsant_num;
+ u8 tdma_sant_num;
+ u8 tdma_nsant_num;
+ u8 bt_afh_span_bw20;
+ u8 bt_afh_span_bw40;
+ u8 afh_5g_num;
+ u8 wl_rf_para_num;
+ const u8 *bt_rssi_step;
+ const u8 *wl_rssi_step;
+ const struct coex_table_para *table_nsant;
+ const struct coex_table_para *table_sant;
+ const struct coex_tdma_para *tdma_sant;
+ const struct coex_tdma_para *tdma_nsant;
+ const struct coex_rf_para *wl_rf_para_tx;
+ const struct coex_rf_para *wl_rf_para_rx;
+ const struct coex_5g_afh_map *afh_5g;
+};
+
+enum rtw_coex_bt_state_cnt {
+ COEX_CNT_BT_RETRY,
+ COEX_CNT_BT_REINIT,
+ COEX_CNT_BT_REENABLE,
+ COEX_CNT_BT_POPEVENT,
+ COEX_CNT_BT_SETUPLINK,
+ COEX_CNT_BT_IGNWLANACT,
+ COEX_CNT_BT_INQ,
+ COEX_CNT_BT_PAGE,
+ COEX_CNT_BT_ROLESWITCH,
+ COEX_CNT_BT_AFHUPDATE,
+ COEX_CNT_BT_INFOUPDATE,
+ COEX_CNT_BT_IQK,
+ COEX_CNT_BT_IQKFAIL,
+
+ COEX_CNT_BT_MAX
+};
+
+enum rtw_coex_wl_state_cnt {
+ COEX_CNT_WL_CONNPKT,
+ COEX_CNT_WL_COEXRUN,
+ COEX_CNT_WL_NOISY0,
+ COEX_CNT_WL_NOISY1,
+ COEX_CNT_WL_NOISY2,
+ COEX_CNT_WL_5MS_NOEXTEND,
+ COEX_CNT_WL_FW_NOTIFY,
+
+ COEX_CNT_WL_MAX
+};
+
+struct rtw_coex_rfe {
+ bool ant_switch_exist;
+ bool ant_switch_diversity;
+ bool ant_switch_with_bt;
+ u8 rfe_module_type;
+ u8 ant_switch_polarity;
+
+ /* true if WLG at BTG, else at WLAG */
+ bool wlg_at_btg;
+};
+
+struct rtw_coex_dm {
+ bool cur_ps_tdma_on;
+ bool cur_wl_rx_low_gain_en;
+
+ u8 reason;
+ u8 bt_rssi_state[4];
+ u8 wl_rssi_state[4];
+ u8 wl_ch_info[3];
+ u8 cur_ps_tdma;
+ u8 cur_table;
+ u8 ps_tdma_para[5];
+ u8 cur_bt_pwr_lvl;
+ u8 cur_bt_lna_lvl;
+ u8 cur_wl_pwr_lvl;
+ u8 bt_status;
+ u32 cur_ant_pos_type;
+ u32 cur_switch_status;
+ u32 setting_tdma;
+};
+
+#define COEX_BTINFO_SRC_WL_FW 0x0
+#define COEX_BTINFO_SRC_BT_RSP 0x1
+#define COEX_BTINFO_SRC_BT_ACT 0x2
+#define COEX_BTINFO_SRC_BT_IQK 0x3
+#define COEX_BTINFO_SRC_BT_SCBD 0x4
+#define COEX_BTINFO_SRC_MAX 0x5
+
+#define COEX_INFO_FTP BIT(7)
+#define COEX_INFO_A2DP BIT(6)
+#define COEX_INFO_HID BIT(5)
+#define COEX_INFO_SCO_BUSY BIT(4)
+#define COEX_INFO_ACL_BUSY BIT(3)
+#define COEX_INFO_INQ_PAGE BIT(2)
+#define COEX_INFO_SCO_ESCO BIT(1)
+#define COEX_INFO_CONNECTION BIT(0)
+#define COEX_BTINFO_LENGTH_MAX 10
+
+struct rtw_coex_stat {
+ bool bt_disabled;
+ bool bt_disabled_pre;
+ bool bt_link_exist;
+ bool bt_whck_test;
+ bool bt_inq_page;
+ bool bt_inq;
+ bool bt_page;
+ bool bt_ble_voice;
+ bool bt_ble_exist;
+ bool bt_hfp_exist;
+ bool bt_a2dp_exist;
+ bool bt_hid_exist;
+ bool bt_pan_exist; /* PAN or OPP */
+ bool bt_opp_exist; /* OPP only */
+ bool bt_acl_busy;
+ bool bt_fix_2M;
+ bool bt_setup_link;
+ bool bt_multi_link;
+ bool bt_a2dp_sink;
+ bool bt_a2dp_active;
+ bool bt_reenable;
+ bool bt_ble_scan_en;
+ bool bt_init_scan;
+ bool bt_slave;
+ bool bt_418_hid_exist;
+ bool bt_mailbox_reply;
+
+ bool wl_under_lps;
+ bool wl_under_ips;
+ bool wl_hi_pri_task1;
+ bool wl_hi_pri_task2;
+ bool wl_force_lps_ctrl;
+ bool wl_gl_busy;
+ bool wl_linkscan_proc;
+ bool wl_ps_state_fail;
+ bool wl_tx_limit_en;
+ bool wl_ampdu_limit_en;
+ bool wl_connected;
+ bool wl_slot_extend;
+ bool wl_cck_lock;
+ bool wl_cck_lock_pre;
+ bool wl_cck_lock_ever;
+
+ u32 bt_supported_version;
+ u32 bt_supported_feature;
+ s8 bt_rssi;
+ u8 kt_ver;
+ u8 gnt_workaround_state;
+ u8 tdma_timer_base;
+ u8 bt_profile_num;
+ u8 bt_info_c2h[COEX_BTINFO_SRC_MAX][COEX_BTINFO_LENGTH_MAX];
+ u8 bt_info_lb2;
+ u8 bt_info_lb3;
+ u8 bt_info_hb0;
+ u8 bt_info_hb1;
+ u8 bt_info_hb2;
+ u8 bt_info_hb3;
+ u8 bt_ble_scan_type;
+ u8 bt_hid_pair_num;
+ u8 bt_hid_slot;
+ u8 bt_a2dp_bitpool;
+ u8 bt_iqk_state;
+
+ u8 wl_noisy_level;
+ u8 wl_fw_dbg_info[10];
+ u8 wl_fw_dbg_info_pre[10];
+ u8 wl_coex_mode;
+ u8 ampdu_max_time;
+ u8 wl_tput_dir;
+
+ u16 score_board;
+ u16 retry_limit;
+
+ /* counters to record bt states */
+ u32 cnt_bt[COEX_CNT_BT_MAX];
+
+ /* counters to record wifi states */
+ u32 cnt_wl[COEX_CNT_WL_MAX];
+
+ u32 darfrc;
+ u32 darfrch;
+};
+
+struct rtw_coex {
+ /* protects coex info request section */
+ struct mutex mutex;
+ struct sk_buff_head queue;
+ wait_queue_head_t wait;
+
+ bool under_5g;
+ bool stop_dm;
+ bool freeze;
+ bool freerun;
+ bool wl_rf_off;
+
+ struct rtw_coex_stat stat;
+ struct rtw_coex_dm dm;
+ struct rtw_coex_rfe rfe;
+
+ struct delayed_work bt_relink_work;
+ struct delayed_work bt_reenable_work;
+ struct delayed_work defreeze_work;
};
#define DACK_MSBK_BACKUP_NUM 0xf
@@ -861,6 +1082,16 @@ struct rtw_dm_info {
u32 cck_fa_cnt;
u32 ofdm_fa_cnt;
u32 total_fa_cnt;
+
+ u32 cck_ok_cnt;
+ u32 cck_err_cnt;
+ u32 ofdm_ok_cnt;
+ u32 ofdm_err_cnt;
+ u32 ht_ok_cnt;
+ u32 ht_err_cnt;
+ u32 vht_ok_cnt;
+ u32 vht_err_cnt;
+
u8 min_rssi;
u8 pre_min_rssi;
u16 fa_history[4];
@@ -888,6 +1119,7 @@ struct rtw_efuse {
u8 addr[ETH_ALEN];
u8 channel_plan;
u8 country_code[2];
+ u8 rf_board_option;
u8 rfe_option;
u8 thermal_meter;
u8 crystal_cap;
@@ -1047,6 +1279,7 @@ struct rtw_dev {
struct rtw_regulatory regd;
struct rtw_dm_info dm_info;
+ struct rtw_coex coex;
/* ensures exclusive access from mac80211 callbacks */
struct mutex mutex;
diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c
index 607bfa4..9ecd14fe 100644
--- a/drivers/net/wireless/realtek/rtw88/ps.c
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
@@ -6,6 +6,7 @@
#include "fw.h"
#include "ps.h"
#include "mac.h"
+#include "coex.h"
#include "debug.h"
static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
@@ -26,6 +27,8 @@ int rtw_enter_ips(struct rtw_dev *rtwdev)
{
rtw_flag_set(rtwdev, RTW_FLAG_INACTIVE_PS);
+ rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
+
rtw_core_stop(rtwdev);
return 0;
@@ -53,6 +56,8 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
+ rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
+
return 0;
}
@@ -67,6 +72,8 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
rtw_fw_set_pwr_mode(rtwdev);
rtw_flag_clear(rtwdev, RTW_FLAG_LEISURE_PS);
+
+ rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
}
static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
@@ -78,6 +85,8 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
conf->rlbm = 1;
conf->smart_ps = 2;
+ rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
+
rtw_fw_set_pwr_mode(rtwdev);
rtw_flag_set(rtwdev, RTW_FLAG_LEISURE_PS);
}
diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
index e2628f0..0bd0717 100644
--- a/drivers/net/wireless/realtek/rtw88/reg.h
+++ b/drivers/net/wireless/realtek/rtw88/reg.h
@@ -37,17 +37,28 @@
#define REG_GPIO_MUXCFG 0x0040
#define BIT_FSPI_EN BIT(19)
+#define BIT_BT_AOD_GPIO3 BIT(9)
+#define BIT_BT_PTA_EN BIT(5)
#define BIT_WLRFE_4_5_EN BIT(2)
#define REG_LED_CFG 0x004C
#define BIT_LNAON_SEL_EN BIT(26)
#define BIT_PAPE_SEL_EN BIT(25)
+#define BIT_DPDT_WL_SEL BIT(24)
+#define BIT_DPDT_SEL_EN BIT(23)
#define REG_PAD_CTRL1 0x0064
#define BIT_PAPE_WLBT_SEL BIT(29)
#define BIT_LNAON_WLBT_SEL BIT(28)
+#define BIT_BTGP_JTAG_EN BIT(24)
+#define BIT_BTGP_SPI_EN BIT(20)
+#define BIT_LED1DIS BIT(15)
+#define BIT_SW_DPDT_SEL_DATA BIT(0)
#define REG_WL_BT_PWR_CTRL 0x0068
#define BIT_BT_FUNC_EN BIT(18)
#define BIT_BT_DIG_CLK_EN BIT(8)
+#define REG_SYS_SDIO_CTRL 0x0070
+#define BIT_DBG_GNT_WL_BT BIT(27)
+#define BIT_LTE_MUX_CTRL_PATH BIT(26)
#define REG_HCI_OPT_CTRL 0x0074
#define REG_MCUFW_CTRL 0x0080
@@ -70,6 +81,8 @@
#define FW_READY_MASK 0xffff
#define REG_WLRF1 0x00EC
+#define REG_WIFI_BT_INFO 0x00AA
+#define BIT_BT_INT_EN BIT(15)
#define REG_SYS_CFG1 0x00F0
#define BIT_RTL_ID BIT(23)
#define BIT_RF_TYPE_ID BIT(27)
@@ -187,6 +200,7 @@
#define REG_LIFETIME_EN 0x0426
#define BIT_BA_PARSER_EN BIT(5)
#define REG_SPEC_SIFS 0x0428
+#define REG_RETRY_LIMIT 0x042a
#define REG_DARFRC 0x0430
#define REG_DARFRCH 0x0434
#define REG_RARFRCH 0x043C
@@ -199,18 +213,25 @@
#define REG_AMPDU_MAX_TIME_V1 0x0455
#define REG_BCNQ1_BDNY_V1 0x0456
#define REG_TX_HANG_CTRL 0x045E
+#define BIT_EN_GNT_BT_AWAKE BIT(3)
#define BIT_EN_EOF_V1 BIT(2)
#define REG_DATA_SC 0x0483
#define REG_ARFR4 0x049C
+#define BIT_WL_RFK BIT(0)
#define REG_ARFRH4 0x04A0
#define REG_ARFR5 0x04A4
#define REG_ARFRH5 0x04A8
#define REG_SW_AMPDU_BURST_MODE_CTRL 0x04BC
#define BIT_PRE_TX_CMD BIT(6)
+#define REG_QUEUE_CTRL 0x04C6
+#define BIT_PTA_WL_TX_EN BIT(4)
+#define BIT_PTA_EDCCA_EN BIT(5)
#define REG_PROT_MODE_CTRL 0x04C8
#define REG_BAR_MODE_CTRL 0x04CC
#define REG_PRECNT_CTRL 0x04E5
+#define BIT_BTCCA_CTRL (BIT(0) | BIT(1))
#define BIT_EN_PRECNT BIT(11)
+#define REG_DUMMY_PAGE4_V1 0x04FC
#define REG_EDCA_VO_PARAM 0x0500
#define REG_EDCA_VI_PARAM 0x0504
@@ -297,11 +318,34 @@
#define REG_RXFLTMAP0 0x06A0
#define REG_RXFLTMAP1 0x06A2
#define REG_RXFLTMAP2 0x06A4
+#define REG_BT_COEX_TABLE0 0x06C0
+#define REG_BT_COEX_TABLE1 0x06C4
+#define REG_BT_COEX_BRK_TABLE 0x06C8
+#define REG_BT_COEX_TABLE_H 0x06CC
+#define REG_BT_COEX_TABLE_H1 0x06CD
+#define REG_BT_COEX_TABLE_H2 0x06CE
+#define REG_BT_COEX_TABLE_H3 0x06CF
#define REG_BBPSF_CTRL 0x06DC
+#define REG_BT_COEX_V2 0x0763
+#define BIT_GNT_BT_POLARITY BIT(4)
+#define BIT_LTE_COEX_EN BIT(7)
+#define REG_BT_STAT_CTRL 0x0778
+#define REG_BT_TDMA_TIME 0x0790
#define REG_WMAC_OPTION_FUNCTION 0x07D0
#define REG_WMAC_OPTION_FUNCTION_1 0x07D4
+#define REG_RX_GAIN_EN 0x081c
+
+#define REG_RFE_CTRL_E 0x0974
+
+#define REG_RFE_CTRL8 0x0cb4
+#define BIT_MASK_RFE_SEL89 GENMASK(7, 0)
+#define REG_RFE_INV8 0x0cbd
+#define BIT_MASK_RFE_INV89 GENMASK(1, 0)
+#define REG_RFE_INV16 0x0cbe
+#define BIT_RFE_BUF_EN BIT(3)
+
#define REG_ANAPAR_XTAL_0 0x1040
#define REG_CPU_DMEM_CON 0x1080
#define BIT_WL_PLATFORM_RST BIT(16)
@@ -407,15 +451,33 @@
#define LTECOEX_WRITE_DATA REG_WL2LTECOEX_INDIRECT_ACCESS_WRITE_DATA_V1
#define LTECOEX_READ_DATA REG_WL2LTECOEX_INDIRECT_ACCESS_READ_DATA_V1
+#define REG_IGN_GNT_BT1 0x1860
+
+#define REG_RFESEL_CTRL 0x1990
+
+#define REG_NOMASK_TXBT 0x1ca7
+#define REG_ANAPAR 0x1c30
+#define BIT_ANAPAR_BTPS BIT(22)
+#define REG_RSTB_SEL 0x1c38
+
+#define REG_IGN_GNTBT4 0x4160
+
+#define RF_MODOPT 0x01
#define RF_DTXLOK 0x08
#define RF_CFGCH 0x18
+#define RF_RCK 0x1d
#define RF_LUTWA 0x33
#define RF_LUTWD1 0x3e
#define RF_LUTWD0 0x3f
#define RF_XTALX2 0xb8
#define RF_MALSEL 0xbe
+#define RF_RCKD 0xde
#define RF_LUTDBG 0xdf
#define RF_LUTWE2 0xee
#define RF_LUTWE 0xef
+#define LTE_COEX_CTRL 0x38
+#define LTE_WL_TRX_CTRL 0xa0
+#define LTE_BT_TRX_CTRL 0xa4
+
#endif
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
index d61d534..568033a 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
@@ -3,6 +3,7 @@
*/
#include "main.h"
+#include "coex.h"
#include "fw.h"
#include "tx.h"
#include "rx.h"
@@ -31,6 +32,7 @@ static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
map = (struct rtw8822b_efuse *)log_map;
efuse->rfe_option = map->rfe_option;
+ efuse->rf_board_option = map->rf_board_option;
efuse->crystal_cap = map->xtal_k;
efuse->pa_type_2g = map->pa_type;
efuse->pa_type_5g = map->pa_type;
@@ -104,24 +106,6 @@ static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev)
rtw_phy_init(rtwdev);
rtw8822b_phy_rfe_init(rtwdev);
-
- /* wifi path controller */
- rtw_write32_mask(rtwdev, 0x70, 0x4000000, 1);
- /* BB control */
- rtw_write32_mask(rtwdev, 0x4c, 0x01800000, 0x2);
- /* antenna mux switch */
- rtw_write8(rtwdev, 0x974, 0xff);
- rtw_write32_mask(rtwdev, 0x1990, 0x300, 0);
- rtw_write32_mask(rtwdev, 0xcbc, 0x80000, 0x0);
- /* SW control */
- rtw_write8(rtwdev, 0xcb4, 0x77);
- /* switch to WL side controller and gnt_wl gnt_bt debug signal */
- rtw_write32_mask(rtwdev, 0x70, 0xff000000, 0x0e);
- /* gnt_wl = 1, gnt_bt = 0 */
- rtw_write32(rtwdev, 0x1704, 0x7700);
- rtw_write32(rtwdev, 0x1700, 0xc00f0038);
- /* switch for WL 2G */
- rtw_write8(rtwdev, 0xcbd, 0x2);
}
#define WLAN_SLOT_TIME 0x09
@@ -960,6 +944,7 @@ static void rtw8822b_false_alarm_statistics(struct rtw_dev *rtwdev)
u32 cck_enable;
u32 cck_fa_cnt;
u32 ofdm_fa_cnt;
+ u32 crc32_cnt;
cck_enable = rtw_read32(rtwdev, 0x808) & BIT(28);
cck_fa_cnt = rtw_read16(rtwdev, 0xa5c);
@@ -970,6 +955,19 @@ static void rtw8822b_false_alarm_statistics(struct rtw_dev *rtwdev)
dm_info->total_fa_cnt = ofdm_fa_cnt;
dm_info->total_fa_cnt += cck_enable ? cck_fa_cnt : 0;
+ crc32_cnt = rtw_read32(rtwdev, 0xf04);
+ dm_info->cck_ok_cnt = crc32_cnt & 0xffff;
+ dm_info->cck_err_cnt = (crc32_cnt & 0xffff0000) >> 16;
+ crc32_cnt = rtw_read32(rtwdev, 0xf14);
+ dm_info->ofdm_ok_cnt = crc32_cnt & 0xffff;
+ dm_info->ofdm_err_cnt = (crc32_cnt & 0xffff0000) >> 16;
+ crc32_cnt = rtw_read32(rtwdev, 0xf10);
+ dm_info->ht_ok_cnt = crc32_cnt & 0xffff;
+ dm_info->ht_err_cnt = (crc32_cnt & 0xffff0000) >> 16;
+ crc32_cnt = rtw_read32(rtwdev, 0xf0c);
+ dm_info->vht_ok_cnt = crc32_cnt & 0xffff;
+ dm_info->vht_err_cnt = (crc32_cnt & 0xffff0000) >> 16;
+
rtw_write32_set(rtwdev, 0x9a4, BIT(17));
rtw_write32_clr(rtwdev, 0x9a4, BIT(17));
rtw_write32_clr(rtwdev, 0xa2c, BIT(15));
@@ -1003,6 +1001,254 @@ static void rtw8822b_do_iqk(struct rtw_dev *rtwdev)
counter, reload, ++do_iqk_cnt, iqk_fail_mask);
}
+static void rtw8822b_coex_cfg_init(struct rtw_dev *rtwdev)
+{
+ /* enable TBTT nterrupt */
+ rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
+
+ /* BT report packet sample rate */
+ /* 0x790[5:0]=0x5 */
+ rtw_write8_set(rtwdev, REG_BT_TDMA_TIME, 0x05);
+
+ /* enable BT counter statistics */
+ rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x1);
+
+ /* enable PTA (3-wire function form BT side) */
+ rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN);
+ rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_AOD_GPIO3);
+
+ /* enable PTA (tx/rx signal form WiFi side) */
+ rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN);
+ /* wl tx signal to PTA not case EDCCA */
+ rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT_PTA_EDCCA_EN);
+ /* GNT_BT=1 while select both */
+ rtw_write8_set(rtwdev, REG_BT_COEX_V2, BIT_GNT_BT_POLARITY);
+}
+
+static void rtw8822b_coex_cfg_ant_switch(struct rtw_dev *rtwdev,
+ u8 ctrl_type, u8 pos_type)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_coex_rfe *coex_rfe = &coex->rfe;
+ bool polarity_inverse;
+ u8 regval = 0;
+
+ if (((ctrl_type << 8) + pos_type) == coex_dm->cur_switch_status)
+ return;
+
+ coex_dm->cur_switch_status = (ctrl_type << 8) + pos_type;
+
+ if (coex_rfe->ant_switch_diversity &&
+ ctrl_type == COEX_SWITCH_CTRL_BY_BBSW)
+ ctrl_type = COEX_SWITCH_CTRL_BY_ANTDIV;
+
+ polarity_inverse = (coex_rfe->ant_switch_polarity == 1);
+
+ switch (ctrl_type) {
+ default:
+ case COEX_SWITCH_CTRL_BY_BBSW:
+ /* 0x4c[23] = 0 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 2, BIT_DPDT_SEL_EN >> 16, 0x0);
+ /* 0x4c[24] = 1 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 3, BIT_DPDT_WL_SEL >> 24, 0x1);
+ /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as ctrl pin */
+ rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, 0x77);
+
+ if (pos_type == COEX_SWITCH_TO_WLG_BT) {
+ if (coex_rfe->rfe_module_type != 0x4 &&
+ coex_rfe->rfe_module_type != 0x2)
+ regval = 0x3;
+ else
+ regval = (!polarity_inverse ? 0x2 : 0x1);
+ } else if (pos_type == COEX_SWITCH_TO_WLG) {
+ regval = (!polarity_inverse ? 0x2 : 0x1);
+ } else {
+ regval = (!polarity_inverse ? 0x1 : 0x2);
+ }
+
+ rtw_write8_mask(rtwdev, REG_RFE_INV8, BIT_MASK_RFE_INV89, regval);
+ break;
+ case COEX_SWITCH_CTRL_BY_PTA:
+ /* 0x4c[23] = 0 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 2, BIT_DPDT_SEL_EN >> 16, 0x0);
+ /* 0x4c[24] = 1 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 3, BIT_DPDT_WL_SEL >> 24, 0x1);
+ /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as ctrl pin */
+ rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, 0x66);
+
+ regval = (!polarity_inverse ? 0x2 : 0x1);
+ rtw_write8_mask(rtwdev, REG_RFE_INV8, BIT_MASK_RFE_INV89, regval);
+ break;
+ case COEX_SWITCH_CTRL_BY_ANTDIV:
+ /* 0x4c[23] = 0 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 2, BIT_DPDT_SEL_EN >> 16, 0x0);
+ /* 0x4c[24] = 1 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 3, BIT_DPDT_WL_SEL >> 24, 0x1);
+ rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, 0x88);
+ break;
+ case COEX_SWITCH_CTRL_BY_MAC:
+ /* 0x4c[23] = 1 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 2, BIT_DPDT_SEL_EN >> 16, 0x1);
+
+ regval = (!polarity_inverse ? 0x0 : 0x1);
+ rtw_write8_mask(rtwdev, REG_PAD_CTRL1, BIT_SW_DPDT_SEL_DATA, regval);
+ break;
+ case COEX_SWITCH_CTRL_BY_FW:
+ /* 0x4c[23] = 0 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 2, BIT_DPDT_SEL_EN >> 16, 0x0);
+ /* 0x4c[24] = 1 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 3, BIT_DPDT_WL_SEL >> 24, 0x1);
+ break;
+ case COEX_SWITCH_CTRL_BY_BT:
+ /* 0x4c[23] = 0 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 2, BIT_DPDT_SEL_EN >> 16, 0x0);
+ /* 0x4c[24] = 0 */
+ rtw_write8_mask(rtwdev, REG_LED_CFG + 3, BIT_DPDT_WL_SEL >> 24, 0x0);
+ break;
+ }
+}
+
+static void rtw8822b_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8822b_coex_cfg_gnt_debug(struct rtw_dev *rtwdev)
+{
+ rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 2, BIT_BTGP_SPI_EN >> 16, 0);
+ rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 3, BIT_BTGP_JTAG_EN >> 24, 0);
+ rtw_write8_mask(rtwdev, REG_GPIO_MUXCFG + 2, BIT_FSPI_EN >> 16, 0);
+ rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 1, BIT_LED1DIS >> 8, 0);
+ rtw_write8_mask(rtwdev, REG_SYS_SDIO_CTRL + 3, BIT_DBG_GNT_WL_BT >> 24, 0);
+}
+
+static void rtw8822b_coex_cfg_rfe_type(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_rfe *coex_rfe = &coex->rfe;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ bool is_ext_fem = false;
+
+ coex_rfe->rfe_module_type = rtwdev->efuse.rfe_option;
+ coex_rfe->ant_switch_polarity = 0;
+ coex_rfe->ant_switch_diversity = false;
+ if (coex_rfe->rfe_module_type == 0x12 ||
+ coex_rfe->rfe_module_type == 0x15 ||
+ coex_rfe->rfe_module_type == 0x16)
+ coex_rfe->ant_switch_exist = false;
+ else
+ coex_rfe->ant_switch_exist = true;
+
+ if (coex_rfe->rfe_module_type == 2 ||
+ coex_rfe->rfe_module_type == 4) {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_EXTFEM, true);
+ is_ext_fem = true;
+ } else {
+ rtw_coex_write_scbd(rtwdev, COEX_SCBD_EXTFEM, false);
+ }
+
+ coex_rfe->wlg_at_btg = false;
+
+ if (efuse->share_ant &&
+ coex_rfe->ant_switch_exist && !is_ext_fem)
+ coex_rfe->ant_switch_with_bt = true;
+ else
+ coex_rfe->ant_switch_with_bt = false;
+
+ /* Ext switch buffer mux */
+ rtw_write8(rtwdev, REG_RFE_CTRL_E, 0xff);
+ rtw_write8_mask(rtwdev, REG_RFESEL_CTRL + 1, 0x3, 0x0);
+ rtw_write8_mask(rtwdev, REG_RFE_INV16, BIT_RFE_BUF_EN, 0x0);
+
+ /* Disable LTE Coex Function in WiFi side */
+ rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, BIT_LTE_COEX_EN, 0);
+
+ /* BTC_CTT_WL_VS_LTE */
+ rtw_coex_write_indirect_reg(rtwdev, LTE_WL_TRX_CTRL, MASKLWORD, 0xffff);
+
+ /* BTC_CTT_BT_VS_LTE */
+ rtw_coex_write_indirect_reg(rtwdev, LTE_BT_TRX_CTRL, MASKLWORD, 0xffff);
+}
+
+static void rtw8822b_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ static const u16 reg_addr[] = {0xc58, 0xe58};
+ static const u8 wl_tx_power[] = {0xd8, 0xd4, 0xd0, 0xcc, 0xc8};
+ u8 i, pwr;
+
+ if (wl_pwr == coex_dm->cur_wl_pwr_lvl)
+ return;
+
+ coex_dm->cur_wl_pwr_lvl = wl_pwr;
+
+ if (coex_dm->cur_wl_pwr_lvl >= ARRAY_SIZE(wl_tx_power))
+ coex_dm->cur_wl_pwr_lvl = ARRAY_SIZE(wl_tx_power) - 1;
+
+ pwr = wl_tx_power[coex_dm->cur_wl_pwr_lvl];
+
+ for (i = 0; i < ARRAY_SIZE(reg_addr); i++)
+ rtw_write8_mask(rtwdev, reg_addr[i], 0xff, pwr);
+}
+
+static void rtw8822b_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ /* WL Rx Low gain on */
+ static const u32 wl_rx_low_gain_on[] = {
+ 0xff000003, 0xbd120003, 0xbe100003, 0xbf080003, 0xbf060003,
+ 0xbf050003, 0xbc140003, 0xbb160003, 0xba180003, 0xb91a0003,
+ 0xb81c0003, 0xb71e0003, 0xb4200003, 0xb5220003, 0xb4240003,
+ 0xb3260003, 0xb2280003, 0xb12a0003, 0xb02c0003, 0xaf2e0003,
+ 0xae300003, 0xad320003, 0xac340003, 0xab360003, 0x8d380003,
+ 0x8c3a0003, 0x8b3c0003, 0x8a3e0003, 0x6e400003, 0x6d420003,
+ 0x6c440003, 0x6b460003, 0x6a480003, 0x694a0003, 0x684c0003,
+ 0x674e0003, 0x66500003, 0x65520003, 0x64540003, 0x64560003,
+ 0x007e0403
+ };
+
+ /* WL Rx Low gain off */
+ static const u32 wl_rx_low_gain_off[] = {
+ 0xff000003, 0xf4120003, 0xf5100003, 0xf60e0003, 0xf70c0003,
+ 0xf80a0003, 0xf3140003, 0xf2160003, 0xf1180003, 0xf01a0003,
+ 0xef1c0003, 0xee1e0003, 0xed200003, 0xec220003, 0xeb240003,
+ 0xea260003, 0xe9280003, 0xe82a0003, 0xe72c0003, 0xe62e0003,
+ 0xe5300003, 0xc8320003, 0xc7340003, 0xc6360003, 0xc5380003,
+ 0xc43a0003, 0xc33c0003, 0xc23e0003, 0xc1400003, 0xc0420003,
+ 0xa5440003, 0xa4460003, 0xa3480003, 0xa24a0003, 0xa14c0003,
+ 0x834e0003, 0x82500003, 0x81520003, 0x80540003, 0x65560003,
+ 0x007e0403
+ };
+ u8 i;
+
+ if (low_gain == coex_dm->cur_wl_rx_low_gain_en)
+ return;
+
+ coex_dm->cur_wl_rx_low_gain_en = low_gain;
+
+ if (coex_dm->cur_wl_rx_low_gain_en) {
+ for (i = 0; i < ARRAY_SIZE(wl_rx_low_gain_on); i++)
+ rtw_write32(rtwdev, REG_RX_GAIN_EN, wl_rx_low_gain_on[i]);
+
+ /* set Rx filter corner RCK offset */
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RCKD, 0x2, 0x1);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RCK, 0x3f, 0x3f);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_RCKD, 0x2, 0x1);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_RCK, 0x3f, 0x3f);
+ } else {
+ for (i = 0; i < ARRAY_SIZE(wl_rx_low_gain_off); i++)
+ rtw_write32(rtwdev, 0x81c, wl_rx_low_gain_off[i]);
+
+ /* set Rx filter corner RCK offset */
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RCK, 0x3f, 0x4);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RCKD, 0x2, 0x0);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_RCK, 0x3f, 0x4);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_RCKD, 0x2, 0x0);
+ }
+}
+
static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = {
{0x0086,
RTW_PWR_CUT_ALL_MSK,
@@ -1549,8 +1795,160 @@ static struct rtw_chip_ops rtw8822b_ops = {
.cfg_ldo25 = rtw8822b_cfg_ldo25,
.false_alarm_statistics = rtw8822b_false_alarm_statistics,
.do_iqk = rtw8822b_do_iqk,
+
+ .coex_set_init = rtw8822b_coex_cfg_init,
+ .coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch,
+ .coex_set_gnt_fix = rtw8822b_coex_cfg_gnt_fix,
+ .coex_set_gnt_debug = rtw8822b_coex_cfg_gnt_debug,
+ .coex_set_rfe_type = rtw8822b_coex_cfg_rfe_type,
+ .coex_set_wl_tx_power = rtw8822b_coex_cfg_wl_tx_power,
+ .coex_set_wl_rx_gain = rtw8822b_coex_cfg_wl_rx_gain,
+};
+
+/* Shared-Antenna Coex Table */
+static const struct coex_table_para table_sant_8822b[] = {
+ {0xffffffff, 0xffffffff}, /* case-0 */
+ {0x55555555, 0x55555555},
+ {0x66555555, 0x66555555},
+ {0xaaaaaaaa, 0xaaaaaaaa},
+ {0x5a5a5a5a, 0x5a5a5a5a},
+ {0xfafafafa, 0xfafafafa}, /* case-5 */
+ {0x6a5a6a5a, 0xaaaaaaaa},
+ {0x6a5a56aa, 0x6a5a56aa},
+ {0x6a5a5a5a, 0x6a5a5a5a},
+ {0x66555555, 0x5a5a5a5a},
+ {0x66555555, 0x6a5a5a5a}, /* case-10 */
+ {0x66555555, 0xfafafafa},
+ {0x66555555, 0x6a5a5aaa},
+ {0x66555555, 0x5aaa5aaa},
+ {0x66555555, 0xaaaa5aaa},
+ {0x66555555, 0xaaaaaaaa}, /* case-15 */
+ {0xffff55ff, 0xfafafafa},
+ {0xffff55ff, 0x6afa5afa},
+ {0xaaffffaa, 0xfafafafa},
+ {0xaa5555aa, 0x5a5a5a5a},
+ {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */
+ {0xaa5555aa, 0xaaaaaaaa},
+ {0xffffffff, 0x5a5a5a5a},
+ {0xffffffff, 0x6a5a5a5a},
+ {0xffffffff, 0x55555555},
+ {0xffffffff, 0x6a5a5aaa}, /* case-25 */
+ {0x55555555, 0x5a5a5a5a},
+ {0x55555555, 0xaaaaaaaa},
+ {0x55555555, 0x6a5a6a5a},
+ {0x66556655, 0x66556655}
+};
+
+/* Non-Shared-Antenna Coex Table */
+static const struct coex_table_para table_nsant_8822b[] = {
+ {0xffffffff, 0xffffffff}, /* case-100 */
+ {0x55555555, 0x55555555},
+ {0x66555555, 0x66555555},
+ {0xaaaaaaaa, 0xaaaaaaaa},
+ {0x5a5a5a5a, 0x5a5a5a5a},
+ {0xfafafafa, 0xfafafafa}, /* case-105 */
+ {0x5afa5afa, 0x5afa5afa},
+ {0x55555555, 0xfafafafa},
+ {0x66555555, 0xfafafafa},
+ {0x66555555, 0x5a5a5a5a},
+ {0x66555555, 0x6a5a5a5a}, /* case-110 */
+ {0x66555555, 0xaaaaaaaa},
+ {0xffff55ff, 0xfafafafa},
+ {0xffff55ff, 0x5afa5afa},
+ {0xffff55ff, 0xaaaaaaaa},
+ {0xaaffffaa, 0xfafafafa}, /* case-115 */
+ {0xaaffffaa, 0x5afa5afa},
+ {0xaaffffaa, 0xaaaaaaaa},
+ {0xffffffff, 0xfafafafa},
+ {0xffffffff, 0x5afa5afa},
+ {0xffffffff, 0xaaaaaaaa}, /* case-120 */
+ {0x55ff55ff, 0x5afa5afa},
+ {0x55ff55ff, 0xaaaaaaaa},
+ {0x55ff55ff, 0x55ff55ff}
};
+/* Shared-Antenna TDMA */
+static const struct coex_tdma_para tdma_sant_8822b[] = {
+ { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */
+ { {0x61, 0x45, 0x03, 0x11, 0x11} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x11} },
+ { {0x61, 0x30, 0x03, 0x11, 0x11} },
+ { {0x61, 0x20, 0x03, 0x11, 0x11} },
+ { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-5 */
+ { {0x61, 0x45, 0x03, 0x11, 0x10} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x10} },
+ { {0x61, 0x30, 0x03, 0x11, 0x10} },
+ { {0x61, 0x20, 0x03, 0x11, 0x10} },
+ { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */
+ { {0x61, 0x08, 0x03, 0x11, 0x14} },
+ { {0x61, 0x08, 0x03, 0x10, 0x14} },
+ { {0x51, 0x08, 0x03, 0x10, 0x54} },
+ { {0x51, 0x08, 0x03, 0x10, 0x55} },
+ { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */
+ { {0x51, 0x45, 0x03, 0x10, 0x10} },
+ { {0x51, 0x3a, 0x03, 0x10, 0x50} },
+ { {0x51, 0x30, 0x03, 0x10, 0x50} },
+ { {0x51, 0x20, 0x03, 0x10, 0x50} },
+ { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */
+ { {0x51, 0x4a, 0x03, 0x10, 0x50} },
+ { {0x51, 0x0c, 0x03, 0x10, 0x54} },
+ { {0x55, 0x08, 0x03, 0x10, 0x54} },
+ { {0x65, 0x10, 0x03, 0x11, 0x11} },
+ { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */
+ { {0x51, 0x08, 0x03, 0x10, 0x50} }
+};
+
+/* Non-Shared-Antenna TDMA */
+static const struct coex_tdma_para tdma_nsant_8822b[] = {
+ { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-100 */
+ { {0x61, 0x45, 0x03, 0x11, 0x11} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x11} },
+ { {0x61, 0x30, 0x03, 0x11, 0x11} },
+ { {0x61, 0x20, 0x03, 0x11, 0x11} },
+ { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */
+ { {0x61, 0x45, 0x03, 0x11, 0x10} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x10} },
+ { {0x61, 0x30, 0x03, 0x11, 0x10} },
+ { {0x61, 0x20, 0x03, 0x11, 0x10} },
+ { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */
+ { {0x61, 0x08, 0x03, 0x11, 0x14} },
+ { {0x61, 0x08, 0x03, 0x10, 0x14} },
+ { {0x51, 0x08, 0x03, 0x10, 0x54} },
+ { {0x51, 0x08, 0x03, 0x10, 0x55} },
+ { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */
+ { {0x51, 0x45, 0x03, 0x10, 0x50} },
+ { {0x51, 0x3a, 0x03, 0x10, 0x50} },
+ { {0x51, 0x30, 0x03, 0x10, 0x50} },
+ { {0x51, 0x20, 0x03, 0x10, 0x50} },
+ { {0x51, 0x10, 0x03, 0x10, 0x50} } /* case-120 */
+};
+
+/* rssi in percentage % (dbm = % - 100) */
+static const u8 wl_rssi_step_8822b[] = {60, 50, 44, 30};
+static const u8 bt_rssi_step_8822b[] = {30, 30, 30, 30};
+static const struct coex_5g_afh_map afh_5g_8822b[] = { {0, 0, 0} };
+
+/* wl_tx_dec_power, bt_tx_dec_power, wl_rx_gain, bt_rx_lna_constrain */
+static const struct coex_rf_para rf_para_tx_8822b[] = {
+ {0, 0, false, 7}, /* for normal */
+ {0, 16, false, 7}, /* for WL-CPT */
+ {4, 0, true, 1},
+ {3, 6, true, 1},
+ {2, 9, true, 1},
+ {1, 13, true, 1}
+};
+
+static const struct coex_rf_para rf_para_rx_8822b[] = {
+ {0, 0, false, 7}, /* for normal */
+ {0, 16, false, 7}, /* for WL-CPT */
+ {4, 0, true, 1},
+ {3, 6, true, 1},
+ {2, 9, true, 1},
+ {1, 13, true, 1}
+};
+
+static_assert(ARRAY_SIZE(rf_para_tx_8822b) == ARRAY_SIZE(rf_para_rx_8822b));
+
struct rtw_chip_info rtw8822b_hw_spec = {
.ops = &rtw8822b_ops,
.id = RTW_CHIP_TYPE_8822B,
@@ -1588,6 +1986,32 @@ struct rtw_chip_info rtw8822b_hw_spec = {
.rf_tbl = {&rtw8822b_rf_a_tbl, &rtw8822b_rf_b_tbl},
.rfe_defs = rtw8822b_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8822b_rfe_defs),
+
+ .coex_para_ver = 0x19062706,
+ .bt_desired_ver = 0x6,
+ .scbd_support = true,
+ .new_scbd10_def = false,
+ .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
+ .bt_rssi_type = COEX_BTRSSI_RATIO,
+ .ant_isolation = 15,
+ .rssi_tolerance = 2,
+ .wl_rssi_step = wl_rssi_step_8822b,
+ .bt_rssi_step = bt_rssi_step_8822b,
+ .table_sant_num = ARRAY_SIZE(table_sant_8822b),
+ .table_sant = table_sant_8822b,
+ .table_nsant_num = ARRAY_SIZE(table_nsant_8822b),
+ .table_nsant = table_nsant_8822b,
+ .tdma_sant_num = ARRAY_SIZE(tdma_sant_8822b),
+ .tdma_sant = tdma_sant_8822b,
+ .tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8822b),
+ .tdma_nsant = tdma_nsant_8822b,
+ .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8822b),
+ .wl_rf_para_tx = rf_para_tx_8822b,
+ .wl_rf_para_rx = rf_para_rx_8822b,
+ .bt_afh_span_bw20 = 0x24,
+ .bt_afh_span_bw40 = 0x36,
+ .afh_5g_num = ARRAY_SIZE(afh_5g_8822b),
+ .afh_5g = afh_5g_8822b,
};
EXPORT_SYMBOL(rtw8822b_hw_spec);
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index f6214ff..207f64c 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -3,6 +3,7 @@
*/
#include "main.h"
+#include "coex.h"
#include "fw.h"
#include "tx.h"
#include "rx.h"
@@ -31,6 +32,7 @@ static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
map = (struct rtw8822c_efuse *)log_map;
efuse->rfe_option = map->rfe_option;
+ efuse->rf_board_option = map->rf_board_option;
efuse->crystal_cap = map->xtal_k;
efuse->channel_plan = map->channel_plan;
efuse->country_code[0] = map->country_code[0];
@@ -1041,12 +1043,6 @@ static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev)
dm_info->cck_gi_l_bnd = ((cck_gi_l_bnd_msb << 4) | (cck_gi_l_bnd_lsb));
rtw8822c_rf_init(rtwdev);
- /* wifi path controller */
- rtw_write32_mask(rtwdev, 0x70, 0xff000000, 0x0e);
- rtw_write32_mask(rtwdev, 0x1704, 0xffffffff, 0x7700);
- rtw_write32_mask(rtwdev, 0x1700, 0xffffffff, 0xc00f0038);
- rtw_write32_mask(rtwdev, 0x6c0, 0xffffffff, 0xaaaaaaaa);
- rtw_write32_mask(rtwdev, 0x6c4, 0xffffffff, 0xaaaaaaaa);
}
#define WLAN_TXQ_RPT_EN 0x1F
@@ -1817,6 +1813,7 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev)
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u32 cck_enable;
u32 cck_fa_cnt;
+ u32 crc32_cnt;
u32 ofdm_fa_cnt;
u32 ofdm_fa_cnt1, ofdm_fa_cnt2, ofdm_fa_cnt3, ofdm_fa_cnt4, ofdm_fa_cnt5;
u16 parity_fail, rate_illegal, crc8_fail, mcs_fail, sb_search_fail,
@@ -1848,6 +1845,19 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev)
dm_info->total_fa_cnt = ofdm_fa_cnt;
dm_info->total_fa_cnt += cck_enable ? cck_fa_cnt : 0;
+ crc32_cnt = rtw_read32(rtwdev, 0x2c04);
+ dm_info->cck_ok_cnt = crc32_cnt & 0xffff;
+ dm_info->cck_err_cnt = (crc32_cnt & 0xffff0000) >> 16;
+ crc32_cnt = rtw_read32(rtwdev, 0x2c14);
+ dm_info->ofdm_ok_cnt = crc32_cnt & 0xffff;
+ dm_info->ofdm_err_cnt = (crc32_cnt & 0xffff0000) >> 16;
+ crc32_cnt = rtw_read32(rtwdev, 0x2c10);
+ dm_info->ht_ok_cnt = crc32_cnt & 0xffff;
+ dm_info->ht_err_cnt = (crc32_cnt & 0xffff0000) >> 16;
+ crc32_cnt = rtw_read32(rtwdev, 0x2c0c);
+ dm_info->vht_ok_cnt = crc32_cnt & 0xffff;
+ dm_info->vht_err_cnt = (crc32_cnt & 0xffff0000) >> 16;
+
rtw_write32_mask(rtwdev, REG_CCANRX, BIT_CCK_FA_RST, 0);
rtw_write32_mask(rtwdev, REG_CCANRX, BIT_CCK_FA_RST, 2);
rtw_write32_mask(rtwdev, REG_CCANRX, BIT_OFDM_FA_RST, 0);
@@ -1864,6 +1874,161 @@ static void rtw8822c_do_iqk(struct rtw_dev *rtwdev)
{
}
+/* for coex */
+static void rtw8822c_coex_cfg_init(struct rtw_dev *rtwdev)
+{
+ /* enable TBTT nterrupt */
+ rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
+
+ /* BT report packet sample rate */
+ /* 0x790[5:0]=0x5 */
+ rtw_write8_set(rtwdev, REG_BT_TDMA_TIME, 0x05);
+
+ /* enable BT counter statistics */
+ rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x1);
+
+ /* enable PTA (3-wire function form BT side) */
+ rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN);
+ rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_AOD_GPIO3);
+
+ /* enable PTA (tx/rx signal form WiFi side) */
+ rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN);
+ /* wl tx signal to PTA not case EDCCA */
+ rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT_PTA_EDCCA_EN);
+ /* GNT_BT=1 while select both */
+ rtw_write8_set(rtwdev, REG_BT_COEX_V2, BIT_GNT_BT_POLARITY);
+ /* BT_CCA = ~GNT_WL_BB, (not or GNT_BT_BB, LTE_Rx */
+ rtw_write8_clr(rtwdev, REG_DUMMY_PAGE4_V1, BIT_BTCCA_CTRL);
+
+ /* to avoid RF parameter error */
+ rtw_write_rf(rtwdev, RF_PATH_B, 0x1, 0xfffff, 0x40000);
+}
+
+static void rtw8822c_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_stat *coex_stat = &coex->stat;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ u32 rf_0x1;
+
+ if (coex_stat->gnt_workaround_state == coex_stat->wl_coex_mode)
+ return;
+
+ coex_stat->gnt_workaround_state = coex_stat->wl_coex_mode;
+
+ if ((coex_stat->kt_ver == 0 && coex->under_5g) || coex->freerun)
+ rf_0x1 = 0x40021;
+ else
+ rf_0x1 = 0x40000;
+
+ /* BT at S1 for Shared-Ant */
+ if (efuse->share_ant)
+ rf_0x1 |= BIT(13);
+
+ rtw_write_rf(rtwdev, RF_PATH_B, 0x1, 0xfffff, rf_0x1);
+
+ /* WL-S0 2G RF TRX cannot be masked by GNT_BT
+ * enable "WLS0 BB chage RF mode if GNT_BT = 1" for shared-antenna type
+ * disable:0x1860[3] = 1, enable:0x1860[3] = 0
+ *
+ * enable "DAC off if GNT_WL = 0" for non-shared-antenna
+ * disable 0x1c30[22] = 0,
+ * enable: 0x1c30[22] = 1, 0x1c38[12] = 0, 0x1c38[28] = 1
+ *
+ * disable WL-S1 BB chage RF mode if GNT_BT
+ * since RF TRx mask can do it
+ */
+ rtw_write8_mask(rtwdev, 0x1c32, BIT(6), 1);
+ rtw_write8_mask(rtwdev, 0x1c39, BIT(4), 0);
+ rtw_write8_mask(rtwdev, 0x1c3b, BIT(4), 1);
+ rtw_write8_mask(rtwdev, 0x4160, BIT(3), 1);
+
+ /* disable WL-S0 BB chage RF mode if wifi is at 5G,
+ * or antenna path is separated
+ */
+ if (coex_stat->wl_coex_mode == COEX_WLINK_5G ||
+ coex->under_5g || !efuse->share_ant) {
+ if (coex_stat->kt_ver >= 3) {
+ rtw_write8_mask(rtwdev, 0x1860, BIT(3), 0);
+ rtw_write8_mask(rtwdev, 0x1ca7, BIT(3), 1);
+ } else {
+ rtw_write8_mask(rtwdev, 0x1860, BIT(3), 1);
+ }
+ } else {
+ /* shared-antenna */
+ rtw_write8_mask(rtwdev, 0x1860, BIT(3), 0);
+ if (coex_stat->kt_ver >= 3)
+ rtw_write8_mask(rtwdev, 0x1ca7, BIT(3), 0);
+ }
+}
+
+static void rtw8822c_coex_cfg_gnt_debug(struct rtw_dev *rtwdev)
+{
+ rtw_write8_mask(rtwdev, 0x66, BIT(4), 0);
+ rtw_write8_mask(rtwdev, 0x67, BIT(0), 0);
+ rtw_write8_mask(rtwdev, 0x42, BIT(3), 0);
+ rtw_write8_mask(rtwdev, 0x65, BIT(7), 0);
+ rtw_write8_mask(rtwdev, 0x73, BIT(3), 0);
+}
+
+static void rtw8822c_coex_cfg_rfe_type(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_rfe *coex_rfe = &coex->rfe;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+
+ coex_rfe->rfe_module_type = rtwdev->efuse.rfe_option;
+ coex_rfe->ant_switch_polarity = 0;
+ coex_rfe->ant_switch_exist = false;
+ coex_rfe->ant_switch_with_bt = false;
+ coex_rfe->ant_switch_diversity = false;
+
+ if (efuse->share_ant)
+ coex_rfe->wlg_at_btg = true;
+ else
+ coex_rfe->wlg_at_btg = false;
+
+ /* disable LTE coex in wifi side */
+ rtw_coex_write_indirect_reg(rtwdev, 0x38, BIT_LTE_COEX_EN, 0x0);
+ rtw_coex_write_indirect_reg(rtwdev, 0xa0, MASKLWORD, 0xffff);
+ rtw_coex_write_indirect_reg(rtwdev, 0xa4, MASKLWORD, 0xffff);
+}
+
+static void rtw8822c_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+
+ if (wl_pwr == coex_dm->cur_wl_pwr_lvl)
+ return;
+
+ coex_dm->cur_wl_pwr_lvl = wl_pwr;
+}
+
+static void rtw8822c_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+
+ if (low_gain == coex_dm->cur_wl_rx_low_gain_en)
+ return;
+
+ coex_dm->cur_wl_rx_low_gain_en = low_gain;
+
+ if (coex_dm->cur_wl_rx_low_gain_en) {
+ /* set Rx filter corner RCK offset */
+ rtw_write_rf(rtwdev, RF_PATH_A, 0xde, 0xfffff, 0x22);
+ rtw_write_rf(rtwdev, RF_PATH_A, 0x1d, 0xfffff, 0x36);
+ rtw_write_rf(rtwdev, RF_PATH_B, 0xde, 0xfffff, 0x22);
+ rtw_write_rf(rtwdev, RF_PATH_B, 0x1d, 0xfffff, 0x36);
+ } else {
+ /* set Rx filter corner RCK offset */
+ rtw_write_rf(rtwdev, RF_PATH_A, 0xde, 0xfffff, 0x20);
+ rtw_write_rf(rtwdev, RF_PATH_A, 0x1d, 0xfffff, 0x0);
+ rtw_write_rf(rtwdev, RF_PATH_B, 0x1d, 0xfffff, 0x0);
+ }
+}
+
static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = {
{0x0086,
RTW_PWR_CUT_ALL_MSK,
@@ -2232,8 +2397,160 @@ static struct rtw_chip_ops rtw8822c_ops = {
.cfg_ldo25 = rtw8822c_cfg_ldo25,
.false_alarm_statistics = rtw8822c_false_alarm_statistics,
.do_iqk = rtw8822c_do_iqk,
+
+ .coex_set_init = rtw8822c_coex_cfg_init,
+ .coex_set_ant_switch = NULL,
+ .coex_set_gnt_fix = rtw8822c_coex_cfg_gnt_fix,
+ .coex_set_gnt_debug = rtw8822c_coex_cfg_gnt_debug,
+ .coex_set_rfe_type = rtw8822c_coex_cfg_rfe_type,
+ .coex_set_wl_tx_power = rtw8822c_coex_cfg_wl_tx_power,
+ .coex_set_wl_rx_gain = rtw8822c_coex_cfg_wl_rx_gain,
+};
+
+/* Shared-Antenna Coex Table */
+static const struct coex_table_para table_sant_8822c[] = {
+ {0xffffffff, 0xffffffff}, /* case-0 */
+ {0x55555555, 0x55555555},
+ {0x66555555, 0x66555555},
+ {0xaaaaaaaa, 0xaaaaaaaa},
+ {0x5a5a5a5a, 0x5a5a5a5a},
+ {0xfafafafa, 0xfafafafa}, /* case-5 */
+ {0x6a5a6a5a, 0xaaaaaaaa},
+ {0x6a5a56aa, 0x6a5a56aa},
+ {0x6a5a5a5a, 0x6a5a5a5a},
+ {0x66555555, 0x5a5a5a5a},
+ {0x66555555, 0x6a5a5a5a}, /* case-10 */
+ {0x66555555, 0xfafafafa},
+ {0x66555555, 0x6a5a5aaa},
+ {0x66555555, 0x5aaa5aaa},
+ {0x66555555, 0xaaaa5aaa},
+ {0x66555555, 0xaaaaaaaa}, /* case-15 */
+ {0xffff55ff, 0xfafafafa},
+ {0xffff55ff, 0x6afa5afa},
+ {0xaaffffaa, 0xfafafafa},
+ {0xaa5555aa, 0x5a5a5a5a},
+ {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */
+ {0xaa5555aa, 0xaaaaaaaa},
+ {0xffffffff, 0x5a5a5a5a},
+ {0xffffffff, 0x6a5a5a5a},
+ {0xffffffff, 0x55555555},
+ {0xffffffff, 0x6a5a5aaa}, /* case-25 */
+ {0x55555555, 0x5a5a5a5a},
+ {0x55555555, 0xaaaaaaaa},
+ {0x55555555, 0x6a5a6a5a},
+ {0x66556655, 0x66556655}
+};
+
+/* Non-Shared-Antenna Coex Table */
+static const struct coex_table_para table_nsant_8822c[] = {
+ {0xffffffff, 0xffffffff}, /* case-100 */
+ {0x55555555, 0x55555555},
+ {0x66555555, 0x66555555},
+ {0xaaaaaaaa, 0xaaaaaaaa},
+ {0x5a5a5a5a, 0x5a5a5a5a},
+ {0xfafafafa, 0xfafafafa}, /* case-105 */
+ {0x5afa5afa, 0x5afa5afa},
+ {0x55555555, 0xfafafafa},
+ {0x66555555, 0xfafafafa},
+ {0x66555555, 0x5a5a5a5a},
+ {0x66555555, 0x6a5a5a5a}, /* case-110 */
+ {0x66555555, 0xaaaaaaaa},
+ {0xffff55ff, 0xfafafafa},
+ {0xffff55ff, 0x5afa5afa},
+ {0xffff55ff, 0xaaaaaaaa},
+ {0xaaffffaa, 0xfafafafa}, /* case-115 */
+ {0xaaffffaa, 0x5afa5afa},
+ {0xaaffffaa, 0xaaaaaaaa},
+ {0xffffffff, 0xfafafafa},
+ {0xffffffff, 0x5afa5afa},
+ {0xffffffff, 0xaaaaaaaa},/* case-120 */
+ {0x55ff55ff, 0x5afa5afa},
+ {0x55ff55ff, 0xaaaaaaaa},
+ {0x55ff55ff, 0x55ff55ff}
+};
+
+/* Shared-Antenna TDMA */
+static const struct coex_tdma_para tdma_sant_8822c[] = {
+ { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */
+ { {0x61, 0x45, 0x03, 0x11, 0x11} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x11} },
+ { {0x61, 0x30, 0x03, 0x11, 0x11} },
+ { {0x61, 0x20, 0x03, 0x11, 0x11} },
+ { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-5 */
+ { {0x61, 0x45, 0x03, 0x11, 0x10} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x10} },
+ { {0x61, 0x30, 0x03, 0x11, 0x10} },
+ { {0x61, 0x20, 0x03, 0x11, 0x10} },
+ { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */
+ { {0x61, 0x08, 0x03, 0x11, 0x14} },
+ { {0x61, 0x08, 0x03, 0x10, 0x14} },
+ { {0x51, 0x08, 0x03, 0x10, 0x54} },
+ { {0x51, 0x08, 0x03, 0x10, 0x55} },
+ { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */
+ { {0x51, 0x45, 0x03, 0x10, 0x10} },
+ { {0x51, 0x3a, 0x03, 0x10, 0x50} },
+ { {0x51, 0x30, 0x03, 0x10, 0x50} },
+ { {0x51, 0x20, 0x03, 0x10, 0x50} },
+ { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */
+ { {0x51, 0x4a, 0x03, 0x10, 0x50} },
+ { {0x51, 0x0c, 0x03, 0x10, 0x54} },
+ { {0x55, 0x08, 0x03, 0x10, 0x54} },
+ { {0x65, 0x10, 0x03, 0x11, 0x11} },
+ { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */
+ { {0x51, 0x08, 0x03, 0x10, 0x50} }
};
+/* Non-Shared-Antenna TDMA */
+static const struct coex_tdma_para tdma_nsant_8822c[] = {
+ { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-100 */
+ { {0x61, 0x45, 0x03, 0x11, 0x11} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x11} },
+ { {0x61, 0x30, 0x03, 0x11, 0x11} },
+ { {0x61, 0x20, 0x03, 0x11, 0x11} },
+ { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */
+ { {0x61, 0x45, 0x03, 0x11, 0x10} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x10} },
+ { {0x61, 0x30, 0x03, 0x11, 0x10} },
+ { {0x61, 0x20, 0x03, 0x11, 0x10} },
+ { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */
+ { {0x61, 0x08, 0x03, 0x11, 0x14} },
+ { {0x61, 0x08, 0x03, 0x10, 0x14} },
+ { {0x51, 0x08, 0x03, 0x10, 0x54} },
+ { {0x51, 0x08, 0x03, 0x10, 0x55} },
+ { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */
+ { {0x51, 0x45, 0x03, 0x10, 0x50} },
+ { {0x51, 0x3a, 0x03, 0x10, 0x50} },
+ { {0x51, 0x30, 0x03, 0x10, 0x50} },
+ { {0x51, 0x20, 0x03, 0x10, 0x50} },
+ { {0x51, 0x10, 0x03, 0x10, 0x50} } /* case-120 */
+};
+
+/* rssi in percentage % (dbm = % - 100) */
+static const u8 wl_rssi_step_8822c[] = {60, 50, 44, 30};
+static const u8 bt_rssi_step_8822c[] = {8, 15, 20, 25};
+static const struct coex_5g_afh_map afh_5g_8822c[] = { {0, 0, 0} };
+
+/* wl_tx_dec_power, bt_tx_dec_power, wl_rx_gain, bt_rx_lna_constrain */
+static const struct coex_rf_para rf_para_tx_8822c[] = {
+ {0, 0, false, 7}, /* for normal */
+ {0, 16, false, 7}, /* for WL-CPT */
+ {8, 17, true, 4},
+ {7, 18, true, 4},
+ {6, 19, true, 4},
+ {5, 20, true, 4}
+};
+
+static const struct coex_rf_para rf_para_rx_8822c[] = {
+ {0, 0, false, 7}, /* for normal */
+ {0, 16, false, 7}, /* for WL-CPT */
+ {3, 24, true, 5},
+ {2, 26, true, 5},
+ {1, 27, true, 5},
+ {0, 28, true, 5}
+};
+
+static_assert(ARRAY_SIZE(rf_para_tx_8822c) == ARRAY_SIZE(rf_para_rx_8822c));
+
struct rtw_chip_info rtw8822c_hw_spec = {
.ops = &rtw8822c_ops,
.id = RTW_CHIP_TYPE_8822C,
@@ -2272,6 +2589,32 @@ struct rtw_chip_info rtw8822c_hw_spec = {
.rf_tbl = {&rtw8822c_rf_a_tbl, &rtw8822c_rf_b_tbl},
.rfe_defs = rtw8822c_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8822c_rfe_defs),
+
+ .coex_para_ver = 0x19062706,
+ .bt_desired_ver = 0x6,
+ .scbd_support = true,
+ .new_scbd10_def = true,
+ .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
+ .bt_rssi_type = COEX_BTRSSI_DBM,
+ .ant_isolation = 15,
+ .rssi_tolerance = 2,
+ .wl_rssi_step = wl_rssi_step_8822c,
+ .bt_rssi_step = bt_rssi_step_8822c,
+ .table_sant_num = ARRAY_SIZE(table_sant_8822c),
+ .table_sant = table_sant_8822c,
+ .table_nsant_num = ARRAY_SIZE(table_nsant_8822c),
+ .table_nsant = table_nsant_8822c,
+ .tdma_sant_num = ARRAY_SIZE(tdma_sant_8822c),
+ .tdma_sant = tdma_sant_8822c,
+ .tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8822c),
+ .tdma_nsant = tdma_nsant_8822c,
+ .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8822c),
+ .wl_rf_para_tx = rf_para_tx_8822c,
+ .wl_rf_para_rx = rf_para_rx_8822c,
+ .bt_afh_span_bw20 = 0x24,
+ .bt_afh_span_bw40 = 0x36,
+ .afh_5g_num = ARRAY_SIZE(afh_5g_8822c),
+ .afh_5g = afh_5g_8822c,
};
EXPORT_SYMBOL(rtw8822c_hw_spec);
--
2.7.4
^ permalink raw reply related
* [PATCH v3 0/3] rtw88: add support for BT co-existence mechanism
From: yhchuang @ 2019-07-31 12:22 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, briannorris, sgruszka
From: Yan-Hsuan Chuang <yhchuang@realtek.com>
This patch set mainly adds a BT co-existence mechanism, which
helps WiFi device to work with BT device concurrently without
interfering each other. For Realtek's WiFi/BT combo devices,
the co-existence mechanism is on the WiFi side.
The rest of the patches add BTcoex support. BTcoex needs to
wake up events that is waiting for some C2H reported in IRQ
context, so these C2H skbs do not required to be queued into
workqueues to be processed. What we need to do is to simply
wake it uin IRQ context.
And actually C2H workqueue context should be protected by
rtwdev->mutex lock to perform some hardware operations
against mac80211 callbacks.
The final patch contains the most of the BTcoex logic.
It is not that complicated, just to gather information and
make decision on WiFi driver side. What makes the code so
much is that the mechanism needs to take care of a lot of
WiFi/BT combinations. Such as if WiFi is at 2G or is having
a lot of traffic or is connecting to AP. And BT has many
profiles such as A2DP/HID/PAN or it is slave or not.
v1 -> v2
rebase onto the latest wireless-drivers-next
the conflicts is in pci.c with patch
"rtw88: pci: Rearrange the memory usage for skb in RX ISR"
v2 -> v3
- free skbs responded for coex information
- remove BT efuse check related patches, because it is not
recommended to read BT's efuse at WiFi side. If the efuse
bank is switched at WiFi side, BT is not able to read its
own efuse content
- add TDMA mode with 4 slots, to deal with some BT earphones
that have small buffer
Yan-Hsuan Chuang (3):
rtw88: allow c2h operation in irq context
rtw88: enclose c2h cmd handle with mutex
rtw88: add BT co-existence support
drivers/net/wireless/realtek/rtw88/Makefile | 1 +
drivers/net/wireless/realtek/rtw88/coex.c | 2507 +++++++++++++++++++++++++
drivers/net/wireless/realtek/rtw88/coex.h | 369 ++++
drivers/net/wireless/realtek/rtw88/fw.c | 135 +-
drivers/net/wireless/realtek/rtw88/fw.h | 73 +
drivers/net/wireless/realtek/rtw88/mac80211.c | 19 +
drivers/net/wireless/realtek/rtw88/main.c | 45 +-
drivers/net/wireless/realtek/rtw88/main.h | 233 +++
drivers/net/wireless/realtek/rtw88/pci.c | 6 +-
drivers/net/wireless/realtek/rtw88/ps.c | 9 +
drivers/net/wireless/realtek/rtw88/reg.h | 62 +
drivers/net/wireless/realtek/rtw88/rtw8822b.c | 460 ++++-
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 355 +++-
13 files changed, 4240 insertions(+), 34 deletions(-)
create mode 100644 drivers/net/wireless/realtek/rtw88/coex.c
create mode 100644 drivers/net/wireless/realtek/rtw88/coex.h
--
2.7.4
^ permalink raw reply
* [PATCH v3 1/3] rtw88: allow c2h operation in irq context
From: yhchuang @ 2019-07-31 12:22 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, briannorris, sgruszka
In-Reply-To: <1564575767-27557-1-git-send-email-yhchuang@realtek.com>
From: Yan-Hsuan Chuang <yhchuang@realtek.com>
Some of the c2h operations are small and can be done
under interrupt context. For the rest that requires
more operations or can go sleep, enqueue onto c2h queue.
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
v1 -> v2
rebase onto the latest wireless-drivers-next
fixed conflicts in pci.c
v2 -> v3
no change
drivers/net/wireless/realtek/rtw88/fw.c | 27 ++++++++++++++++++++++++---
drivers/net/wireless/realtek/rtw88/fw.h | 2 ++
drivers/net/wireless/realtek/rtw88/pci.c | 6 ++----
3 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index 62847797..3c4dcb7 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -36,9 +36,6 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
c2h = (struct rtw_c2h_cmd *)(skb->data + pkt_offset);
len = skb->len - pkt_offset - 2;
- rtw_dbg(rtwdev, RTW_DBG_FW, "recv C2H, id=0x%02x, seq=0x%02x, len=%d\n",
- c2h->id, c2h->seq, len);
-
switch (c2h->id) {
case C2H_HALMAC:
rtw_fw_c2h_cmd_handle_ext(rtwdev, skb);
@@ -48,6 +45,30 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
}
}
+void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
+ struct sk_buff *skb)
+{
+ struct rtw_c2h_cmd *c2h;
+ u8 len;
+
+ c2h = (struct rtw_c2h_cmd *)(skb->data + pkt_offset);
+ len = skb->len - pkt_offset - 2;
+ *((u32 *)skb->cb) = pkt_offset;
+
+ rtw_dbg(rtwdev, RTW_DBG_FW, "recv C2H, id=0x%02x, seq=0x%02x, len=%d\n",
+ c2h->id, c2h->seq, len);
+
+ switch (c2h->id) {
+ default:
+ /* pass offset for further operation */
+ *((u32 *)skb->cb) = pkt_offset;
+ skb_queue_tail(&rtwdev->c2h_queue, skb);
+ ieee80211_queue_work(rtwdev->hw, &rtwdev->c2h_work);
+ break;
+ }
+}
+EXPORT_SYMBOL(rtw_fw_c2h_cmd_rx_irqsafe);
+
static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
u8 *h2c)
{
diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h
index 7034663..67f6cf7 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.h
+++ b/drivers/net/wireless/realtek/rtw88/fw.h
@@ -200,6 +200,8 @@ static inline struct rtw_c2h_cmd *get_c2h_from_skb(struct sk_buff *skb)
return (struct rtw_c2h_cmd *)(skb->data + pkt_offset);
}
+void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
+ struct sk_buff *skb);
void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb);
void rtw_fw_send_general_info(struct rtw_dev *rtwdev);
void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 23dd06a..4776195 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -8,6 +8,7 @@
#include "pci.h"
#include "tx.h"
#include "rx.h"
+#include "fw.h"
#include "debug.h"
static u32 rtw_pci_tx_queue_idx_addr[] = {
@@ -822,10 +823,7 @@ static void rtw_pci_rx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
skb_put_data(new, skb->data, new_len);
if (pkt_stat.is_c2h) {
- /* pass rx_desc & offset for further operation */
- *((u32 *)new->cb) = pkt_offset;
- skb_queue_tail(&rtwdev->c2h_queue, new);
- ieee80211_queue_work(rtwdev->hw, &rtwdev->c2h_work);
+ rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, new);
} else {
/* remove rx_desc */
skb_pull(new, pkt_offset);
--
2.7.4
^ permalink raw reply related
* [PATCH v3 2/3] rtw88: enclose c2h cmd handle with mutex
From: yhchuang @ 2019-07-31 12:22 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, briannorris, sgruszka
In-Reply-To: <1564575767-27557-1-git-send-email-yhchuang@realtek.com>
From: Yan-Hsuan Chuang <yhchuang@realtek.com>
C2H commands that cannot be handled in IRQ context should
be protected by rtwdev->mutex. Because they might have a
sequece of hardware operations that does not want to be
interfered.
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
v1 -> v2
no change
v2 -> v3
no change
drivers/net/wireless/realtek/rtw88/fw.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index 3c4dcb7..3b06f71 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -36,6 +36,8 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
c2h = (struct rtw_c2h_cmd *)(skb->data + pkt_offset);
len = skb->len - pkt_offset - 2;
+ mutex_lock(&rtwdev->mutex);
+
switch (c2h->id) {
case C2H_HALMAC:
rtw_fw_c2h_cmd_handle_ext(rtwdev, skb);
@@ -43,6 +45,8 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
default:
break;
}
+
+ mutex_unlock(&rtwdev->mutex);
}
void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
--
2.7.4
^ permalink raw reply related
* [PATCH v2] arm64: dts: qcom: qcs404: Add wifi rails in QCS404 dt node for proxy votes
From: Govind Singh @ 2019-07-31 12:07 UTC (permalink / raw)
To: bjorn.andersson, linux-arm-msm, devicetree, ath10k
Cc: linux-wireless, Govind Singh
Add wifi regulators in qcs404 dt node for proxy vote. Proxy votes are
required for handling driver recovery scenarios to prevent
un-clocked register access during driver recovery.
Signed-off-by: Govind Singh <govinds@codeaurora.org>
---
arch/arm64/boot/dts/qcom/qcs404-evb.dtsi | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
index 11c0a7137823..2289b01ee9f0 100644
--- a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
@@ -270,6 +270,9 @@
&wifi {
status = "okay";
+ vdd-0.8-cx-mx-supply = <&vreg_l2_1p275>;
+ vdd-1.8-xo-supply = <&vreg_l5_1p8>;
+ vdd-1.3-rfa-supply = <&vreg_l1_1p3>;
};
/* PINCTRL - additions to nodes defined in qcs404.dtsi */
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* Re: pull-request: iwlwifi-fixes 2019-07-30
From: Kalle Valo @ 2019-07-31 11:58 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <20190730171210.16570-1-johannes@sipsolutions.net>
Johannes Berg <johannes@sipsolutions.net> writes:
> Hi Kalle,
>
> Resending, with all sign-offs again ... sorry, that's because Luca
> handled the previous part and then I just added stuff.
>
> Please pull and let me know if there's any problem.
>
> Thanks,
> johannes
>
>
>
> The following changes since commit 5f9e832c137075045d15cd6899ab0505cfb2ca4b:
>
> Linus 5.3-rc1 (2019-07-21 14:05:38 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-fixes.git tags/iwlwifi-fixes-for-kvalo-2019-07-30
>
> for you to fetch changes up to 71b256f8f7a5c09810d2c3ed6165629c2cc0a652:
>
> iwlwifi: mvm: fix a use-after-free bug in iwl_mvm_tx_tso_segment (2019-07-30 18:34:32 +0200)
>
> ----------------------------------------------------------------
> We have a lot of fixes, most of them are also applicable to stable.
> Notably:
> * fix use-after-free issues
> * fix DMA mapping API usage errors
> * fix frame drop occurring due to reorder buffer handling in
> RSS in certain conditions
> * fix rate scale locking issues
> * disable TX A-MSDU on older NICs as it causes problems and was
> never supposed to be supported
> * new PCI IDs
> * GEO_TX_POWER_LIMIT API issue that many people were hitting
>
> ----------------------------------------------------------------
Thanks, looks good now. Pulled.
--
Kalle Valo
^ permalink raw reply
* [PATCH] ath10k: revalidate the msa region coming from firmware
From: Govind Singh @ 2019-07-31 11:42 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Govind Singh
driver sends QMI_WLFW_MSA_INFO_REQ_V01 QMI request to firmware
and in response expects range of addresses and size to be mapped.
Add condition to check whether addresses in response falls
under valid range otherwise return failure.
Testing: Tested on WCN3990 HW
Tested FW: WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1
Signed-off-by: Govind Singh <govinds@codeaurora.org>
---
drivers/net/wireless/ath/ath10k/qmi.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 2e678780df5d..3457509a003f 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -111,6 +111,7 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
struct wlfw_msa_info_resp_msg_v01 resp = {};
struct wlfw_msa_info_req_msg_v01 req = {};
struct ath10k *ar = qmi->ar;
+ phys_addr_t max_mapped_addr;
struct qmi_txn txn;
int ret;
int i;
@@ -150,8 +151,20 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
goto out;
}
+ max_mapped_addr = qmi->msa_pa + qmi->msa_mem_size;
qmi->nr_mem_region = resp.mem_region_info_len;
for (i = 0; i < resp.mem_region_info_len; i++) {
+ if (resp.mem_region_info[i].size > qmi->msa_mem_size ||
+ resp.mem_region_info[i].region_addr > max_mapped_addr ||
+ resp.mem_region_info[i].region_addr < qmi->msa_pa ||
+ resp.mem_region_info[i].size +
+ resp.mem_region_info[i].region_addr > max_mapped_addr) {
+ ath10k_err(ar, "received out of range memory region address 0x%llx with size 0x%x, aborting\n",
+ resp.mem_region_info[i].region_addr,
+ resp.mem_region_info[i].size);
+ ret = -EINVAL;
+ goto fail_unwind;
+ }
qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr;
qmi->mem_region[i].size = resp.mem_region_info[i].size;
qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag;
@@ -165,6 +178,8 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n");
return 0;
+fail_unwind:
+ memset(&qmi->mem_region[0], 0, sizeof(qmi->mem_region[0]) * i);
out:
return ret;
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* Re: [PATCH] Revert "mac80211: set NETIF_F_LLTX when using intermediate tx queues"
From: Peter Lebbing @ 2019-07-31 11:29 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <20190730125412.1446-1-johannes@sipsolutions.net>
On 30/07/2019 14:54, Johannes Berg wrote:
> Revert this for now, it has been reported multiple times that it
> completely breaks connectivity on various devices.
That was quick! Thank you!
Peter.
--
I use the GNU Privacy Guard (GnuPG) in combination with Enigmail.
You can send me encrypted mail if you want some privacy.
My key is available at <http://digitalbrains.com/2012/openpgp-key-peter>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox