blob: 7320f77a6ac4abca7b7a26c7b906e66c9b2f054a [file] [log] [blame]
From 0f6ae2024ce001cf003239b3aaa56cb4a279bba9 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 22 Feb 2024 15:21:49 +0800
Subject: [PATCH 75/89] mtk: mac80211: add per-link txpower config
Add per-link txpower config & info dump
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
include/net/cfg80211.h | 5 ++--
include/net/mac80211.h | 2 +-
net/mac80211/cfg.c | 48 +++++++++++++++++++++++++++-----------
net/mac80211/chan.c | 4 ++--
net/mac80211/driver-ops.h | 7 +++---
net/mac80211/ieee80211_i.h | 5 ++--
net/mac80211/iface.c | 23 +++++++++---------
net/mac80211/link.c | 3 +++
net/mac80211/mlme.c | 2 +-
net/mac80211/trace.h | 10 ++++----
net/wireless/nl80211.c | 17 +++++++++++---
net/wireless/rdev-ops.h | 12 ++++++----
net/wireless/trace.h | 30 ++++++++++++++++++------
net/wireless/wext-compat.c | 4 ++--
14 files changed, 116 insertions(+), 56 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bedf711..a63f5bb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4749,9 +4749,10 @@ struct cfg80211_ops {
int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
int (*set_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
- enum nl80211_tx_power_setting type, int mbm);
+ unsigned int link_id, enum nl80211_tx_power_setting type,
+ int mbm);
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
- int *dbm);
+ unsigned int link_id, int *dbm);
void (*rfkill_poll)(struct wiphy *wiphy);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index bb4f12f..30aa436 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4746,7 +4746,7 @@ struct ieee80211_ops {
u32 (*get_expected_throughput)(struct ieee80211_hw *hw,
struct ieee80211_sta *sta);
int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- int *dbm);
+ unsigned int link_id, int *dbm);
int (*tdls_channel_switch)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 02374b0..19171b0 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3048,10 +3048,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
static int ieee80211_set_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
+ unsigned int link_id,
enum nl80211_tx_power_setting type, int mbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_link_data *link;
+ struct ieee80211_bss_conf *link_conf;
enum nl80211_tx_power_setting txp_type = type;
bool update_txp_type = false;
bool has_monitor = false;
@@ -3060,6 +3063,11 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
if (wdev) {
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
+ link_conf = link->conf;
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
sdata = wiphy_dereference(local->hw.wiphy,
@@ -3070,7 +3078,7 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
- sdata->deflink.user_power_level =
+ link->user_power_level =
IEEE80211_UNSET_POWER_LEVEL;
txp_type = NL80211_TX_POWER_LIMITED;
break;
@@ -3078,20 +3086,24 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
case NL80211_TX_POWER_FIXED:
if (mbm < 0 || (mbm % 100))
return -EOPNOTSUPP;
- sdata->deflink.user_power_level = MBM_TO_DBM(mbm);
+ link->user_power_level = MBM_TO_DBM(mbm);
break;
}
- if (txp_type != sdata->vif.bss_conf.txpower_type) {
+ if (txp_type != link_conf->txpower_type) {
update_txp_type = true;
- sdata->vif.bss_conf.txpower_type = txp_type;
+ link_conf->txpower_type = txp_type;
}
- ieee80211_recalc_txpower(sdata, update_txp_type);
+ ieee80211_recalc_txpower(sdata, update_txp_type, link);
return 0;
}
+ /*TODO: handle single wiphy */
+ wiphy_info(wiphy, "Setting txpower for the entire band is not supported\n");
+ return -EOPNOTSUPP;
+
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
@@ -3118,7 +3130,12 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
continue;
- ieee80211_recalc_txpower(sdata, update_txp_type);
+ /* Due to mac80211 not pass link id to here, use first link for now */
+ if (ieee80211_vif_is_mld(&sdata->vif))
+ ieee80211_recalc_txpower(sdata, update_txp_type, sdata->link[0]);
+ else
+ ieee80211_recalc_txpower(sdata, update_txp_type, &sdata->deflink);
+
}
if (has_monitor) {
@@ -3130,7 +3147,7 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
update_txp_type = true;
sdata->vif.bss_conf.txpower_type = txp_type;
- ieee80211_recalc_txpower(sdata, update_txp_type);
+ ieee80211_recalc_txpower(sdata, update_txp_type, &sdata->deflink);
}
}
@@ -3139,18 +3156,23 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
static int ieee80211_get_tx_power(struct wiphy *wiphy,
struct wireless_dev *wdev,
- int *dbm)
+ unsigned int link_id, int *dbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ struct ieee80211_link_data *link;
if (local->ops->get_txpower)
- return drv_get_txpower(local, sdata, dbm);
+ return drv_get_txpower(local, sdata, link_id, dbm);
- if (local->emulate_chanctx)
- *dbm = local->hw.conf.power_level;
- else
- *dbm = sdata->vif.bss_conf.txpower;
+ *dbm = local->hw.conf.power_level;
+ if (!local->emulate_chanctx) {
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
+ *dbm = link->conf->txpower;
+ }
/* INT_MIN indicates no power level was set yet */
if (*dbm == INT_MIN)
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 31d7fa8..e7d2ee2 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -913,7 +913,7 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
}
if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
- ieee80211_recalc_txpower(sdata, false);
+ ieee80211_recalc_txpower(sdata, false, link);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
}
@@ -1730,7 +1730,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
link,
changed);
- ieee80211_recalc_txpower(sdata, false);
+ ieee80211_recalc_txpower(sdata, false, link);
}
ieee80211_recalc_chanctx_chantype(local, ctx);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d226e31..aca4426 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1273,7 +1273,8 @@ static inline u32 drv_get_expected_throughput(struct ieee80211_local *local,
}
static inline int drv_get_txpower(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata, int *dbm)
+ struct ieee80211_sub_if_data *sdata,
+ unsigned int link_id, int *dbm)
{
int ret;
@@ -1283,8 +1284,8 @@ static inline int drv_get_txpower(struct ieee80211_local *local,
if (!local->ops->get_txpower)
return -EOPNOTSUPP;
- ret = local->ops->get_txpower(&local->hw, &sdata->vif, dbm);
- trace_drv_get_txpower(local, sdata, *dbm, ret);
+ ret = local->ops->get_txpower(&local->hw, &sdata->vif, link_id, dbm);
+ trace_drv_get_txpower(local, sdata, link_id, *dbm, ret);
return ret;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2cb80c3..6f9a9a6 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2050,9 +2050,10 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
int ieee80211_add_virtual_monitor(struct ieee80211_local *local);
void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
-bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
+bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_data *link);
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
- bool update_bss);
+ bool update_bss, struct ieee80211_link_data *link);
void ieee80211_recalc_offload(struct ieee80211_local *local);
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index d959901..eb7a05d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -44,13 +44,14 @@
static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work);
-bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
+bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_data *link)
{
struct ieee80211_chanctx_conf *chanctx_conf;
int power;
rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return false;
@@ -59,14 +60,14 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
power = ieee80211_chandef_max_power(&chanctx_conf->def);
rcu_read_unlock();
- if (sdata->deflink.user_power_level != IEEE80211_UNSET_POWER_LEVEL)
- power = min(power, sdata->deflink.user_power_level);
+ if (link->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
+ power = min(power, link->user_power_level);
- if (sdata->deflink.ap_power_level != IEEE80211_UNSET_POWER_LEVEL)
- power = min(power, sdata->deflink.ap_power_level);
+ if (link->ap_power_level != IEEE80211_UNSET_POWER_LEVEL)
+ power = min(power, link->ap_power_level);
- if (power != sdata->vif.bss_conf.txpower) {
- sdata->vif.bss_conf.txpower = power;
+ if (power != link->conf->txpower) {
+ link->conf->txpower = power;
ieee80211_hw_config(sdata->local, 0);
return true;
}
@@ -75,11 +76,11 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
}
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
- bool update_bss)
+ bool update_bss, struct ieee80211_link_data *link)
{
- if (__ieee80211_recalc_txpower(sdata) ||
+ if (__ieee80211_recalc_txpower(sdata, link) ||
(update_bss && ieee80211_sdata_running(sdata)))
- ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_TXPOWER);
}
diff --git a/net/mac80211/link.c b/net/mac80211/link.c
index 11502da..349f596 100644
--- a/net/mac80211/link.c
+++ b/net/mac80211/link.c
@@ -37,6 +37,9 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
link_conf->link_id = link_id;
link_conf->vif = &sdata->vif;
+ link->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
+ link->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
+
wiphy_work_init(&link->csa.finalize_work,
ieee80211_csa_finalize_work);
wiphy_work_init(&link->color_change_finalize_work,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b684fed..a3873d2 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2802,7 +2802,7 @@ static u64 ieee80211_handle_pwr_constr(struct ieee80211_link_data *link,
}
link->ap_power_level = new_ap_level;
- if (__ieee80211_recalc_txpower(sdata))
+ if (__ieee80211_recalc_txpower(sdata, link))
return BSS_CHANGED_TXPOWER;
return 0;
}
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 36e500d..3e06017 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2170,13 +2170,14 @@ DEFINE_EVENT(chanswitch_evt, drv_channel_switch_rx_beacon,
TRACE_EVENT(drv_get_txpower,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- int dbm, int ret),
+ unsigned int link_id, int dbm, int ret),
- TP_ARGS(local, sdata, dbm, ret),
+ TP_ARGS(local, sdata, link_id, dbm, ret),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
+ __field(unsigned int, link_id)
__field(int, dbm)
__field(int, ret)
),
@@ -2184,13 +2185,14 @@ TRACE_EVENT(drv_get_txpower,
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
+ __entry->link_id = link_id;
__entry->dbm = dbm;
__entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " dbm:%d ret:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, __entry->dbm, __entry->ret
+ LOCAL_PR_FMT VIF_PR_FMT " link_id:%d dbm:%d ret:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id, __entry->dbm, __entry->ret
)
);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 756a29a..36d35f0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3753,6 +3753,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
struct wireless_dev *txp_wdev = wdev;
enum nl80211_tx_power_setting type;
int idx, mbm = 0;
+ unsigned int link_id = nl80211_link_id(info->attrs);
if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
txp_wdev = NULL;
@@ -3776,7 +3777,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
mbm = nla_get_u32(info->attrs[idx]);
}
- result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
+ result = rdev_set_tx_power(rdev, txp_wdev, link_id, type, mbm);
if (result)
goto out;
}
@@ -4047,10 +4048,10 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
goto nla_put_failure;
}
- if (rdev->ops->get_tx_power) {
+ if (!wdev->valid_links && rdev->ops->get_tx_power) {
int dbm, ret;
- ret = rdev_get_tx_power(rdev, wdev, &dbm);
+ ret = rdev_get_tx_power(rdev, wdev, 0, &dbm);
if (ret == 0 &&
nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
DBM_TO_MBM(dbm)))
@@ -4119,6 +4120,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
if (ret == 0 && nl80211_send_chandef(msg, &chandef))
goto nla_put_failure;
+ if (rdev->ops->get_tx_power) {
+ int dbm, ret;
+
+ ret = rdev_get_tx_power(rdev, wdev, link_id, &dbm);
+ if (ret == 0 &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+ DBM_TO_MBM(dbm)))
+ goto nla_put_failure;
+ }
+
nla_nest_end(msg, link);
}
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 5b3c94f..9b411db 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -589,21 +589,23 @@ rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed)
static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
+ unsigned int link_id,
enum nl80211_tx_power_setting type, int mbm)
{
int ret;
- trace_rdev_set_tx_power(&rdev->wiphy, wdev, type, mbm);
- ret = rdev->ops->set_tx_power(&rdev->wiphy, wdev, type, mbm);
+ trace_rdev_set_tx_power(&rdev->wiphy, wdev, link_id, type, mbm);
+ ret = rdev->ops->set_tx_power(&rdev->wiphy, wdev, link_id, type, mbm);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, int *dbm)
+ struct wireless_dev *wdev,
+ unsigned int link_id, int *dbm)
{
int ret;
- trace_rdev_get_tx_power(&rdev->wiphy, wdev);
- ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm);
+ trace_rdev_get_tx_power(&rdev->wiphy, wdev, link_id);
+ ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, link_id, dbm);
trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm);
return ret;
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 6ff6091..6af432e 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1688,29 +1688,45 @@ TRACE_EVENT(rdev_set_wiphy_params,
WIPHY_PR_ARG, __entry->changed)
);
-DEFINE_EVENT(wiphy_wdev_evt, rdev_get_tx_power,
- TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
- TP_ARGS(wiphy, wdev)
+TRACE_EVENT(rdev_get_tx_power,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ unsigned int link_id),
+ TP_ARGS(wiphy, wdev, link_id),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ __field(unsigned int, link_id)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ __entry->link_id = link_id;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %d",
+ WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id)
);
TRACE_EVENT(rdev_set_tx_power,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
- enum nl80211_tx_power_setting type, int mbm),
- TP_ARGS(wiphy, wdev, type, mbm),
+ unsigned int link_id, enum nl80211_tx_power_setting type,
+ int mbm),
+ TP_ARGS(wiphy, wdev, link_id, type, mbm),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
+ __field(unsigned int, link_id)
__field(enum nl80211_tx_power_setting, type)
__field(int, mbm)
),
TP_fast_assign(
WIPHY_ASSIGN;
WDEV_ASSIGN;
+ __entry->link_id = link_id;
__entry->type = type;
__entry->mbm = mbm;
),
- TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", type: %u, mbm: %d",
- WIPHY_PR_ARG, WDEV_PR_ARG,__entry->type, __entry->mbm)
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %d, type: %u, mbm: %d",
+ WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id, __entry->type, __entry->mbm)
);
TRACE_EVENT(rdev_return_int_int,
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 2371069..73ef854 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -952,7 +952,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev,
}
wiphy_lock(&rdev->wiphy);
- ret = rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm));
+ ret = rdev_set_tx_power(rdev, wdev, 0, type, DBM_TO_MBM(dbm));
wiphy_unlock(&rdev->wiphy);
return ret;
@@ -975,7 +975,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,
return -EOPNOTSUPP;
wiphy_lock(&rdev->wiphy);
- err = rdev_get_tx_power(rdev, wdev, &val);
+ err = rdev_get_tx_power(rdev, wdev, 0, &val);
wiphy_unlock(&rdev->wiphy);
if (err)
return err;
--
2.18.0