| From fe38d546c8060b4b3c122f21bd625bdcdb7febad Mon Sep 17 00:00:00 2001 |
| From: YN Chen <YN.Chen@mediatek.com> |
| Date: Tue, 29 Jun 2021 07:05:53 +0800 |
| Subject: [PATCH] BACKPORT: FROMGIT: mt76: mt7921: add .set_sar_specs support |
| |
| add .set_sar_specs to allow configuring SAR power limitations on the |
| frequency ranges from the userland. |
| |
| Co-developed-by: Sean Wang <sean.wang@mediatek.com> |
| Signed-off-by: Sean Wang <sean.wang@mediatek.com> |
| Signed-off-by: YN Chen <YN.Chen@mediatek.com> |
| Signed-off-by: Felix Fietkau <nbd@nbd.name> |
| |
| (cherry picked from commit 2f283b6e139763cc6fc4dafa68dc987acbb0046b |
| https://github.com/nbd168/wireless.git mt76) |
| |
| Conflicts: |
| drivers/net/wireless/mediatek/mt76/mt76.h |
| drivers/net/wireless/mediatek/mt76/mt7921/main.c |
| |
| Backport Notes: |
| Those conflicts come from currrent mac80211 doesn't support hw rx-amsdu |
| de-aggregation, so we only merge those changes to the current context. |
| |
| BUG=b:178754244, b:188614537 |
| TEST=build on cherry |
| |
| Signed-off-by: Sean Wang <objelf@gmail.com> |
| Change-Id: I32b5da42a4036e81d71e477c13a572caa0275ac0 |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3151438 |
| Reviewed-by: Joshua Emele <jemele@chromium.org> |
| Tested-by: Joshua Emele <jemele@chromium.org> |
| Commit-Queue: Joshua Emele <jemele@chromium.org> |
| --- |
| drivers/net/wireless/mediatek/mt76/mac80211.c | 15 ++++++++ |
| drivers/net/wireless/mediatek/mt76/mt76.h | 8 ++++ |
| .../wireless/mediatek/mt76/mt76_connac_mcu.c | 30 ++++++++++++++- |
| .../net/wireless/mediatek/mt76/mt7921/init.c | 17 ++++++++- |
| .../net/wireless/mediatek/mt76/mt7921/main.c | 38 +++++++++++++++++++ |
| 5 files changed, 105 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c |
| --- a/drivers/net/wireless/mediatek/mt76/mac80211.c |
| +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c |
| @@ -99,6 +99,21 @@ struct ieee80211_rate mt76_rates[] = { |
| }; |
| EXPORT_SYMBOL_GPL(mt76_rates); |
| |
| +static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = { |
| + { .start_freq = 2402, .end_freq = 2494, }, |
| + { .start_freq = 5150, .end_freq = 5350, }, |
| + { .start_freq = 5350, .end_freq = 5470, }, |
| + { .start_freq = 5470, .end_freq = 5725, }, |
| + { .start_freq = 5725, .end_freq = 5950, }, |
| +}; |
| + |
| +const struct cfg80211_sar_capa mt76_sar_capa = { |
| + .type = NL80211_SAR_TYPE_POWER, |
| + .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges), |
| + .freq_ranges = &mt76_sar_freq_ranges[0], |
| +}; |
| +EXPORT_SYMBOL_GPL(mt76_sar_capa); |
| + |
| static int mt76_led_init(struct mt76_dev *dev) |
| { |
| struct device_node *np = dev->dev->of_node; |
| diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h |
| --- a/drivers/net/wireless/mediatek/mt76/mt76.h |
| +++ b/drivers/net/wireless/mediatek/mt76/mt76.h |
| @@ -545,6 +545,11 @@ struct mt76_rx_status { |
| s8 chain_signal[IEEE80211_MAX_CHAINS]; |
| }; |
| |
| +struct mt76_freq_range_power { |
| + const struct cfg80211_sar_freq_ranges *range; |
| + s8 power; |
| +}; |
| + |
| struct mt76_testmode_ops { |
| int (*set_state)(struct mt76_phy *phy, enum mt76_testmode_state state); |
| int (*set_params)(struct mt76_phy *phy, struct nlattr **tb, |
| @@ -636,6 +641,8 @@ struct mt76_phy { |
| struct sk_buff **tail; |
| u16 seqno; |
| } rx_amsdu[__MT_RXQ_MAX]; |
| + |
| + struct mt76_freq_range_power *frp; |
| }; |
| |
| struct mt76_dev { |
| @@ -769,6 +776,7 @@ enum mt76_phy_type { |
| } |
| |
| extern struct ieee80211_rate mt76_rates[12]; |
| +extern const struct cfg80211_sar_capa mt76_sar_capa; |
| |
| #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) |
| #define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__) |
| diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c |
| --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c |
| +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c |
| @@ -1749,6 +1749,30 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku, |
| } |
| } |
| |
| +static s8 mt76_connac_get_sar_power(struct mt76_phy *phy, |
| + struct ieee80211_channel *chan, |
| + s8 target_power) |
| +{ |
| + const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; |
| + struct mt76_freq_range_power *frp = phy->frp; |
| + int freq, i; |
| + |
| + if (!capa || !frp) |
| + return target_power; |
| + |
| + freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); |
| + for (i = 0 ; i < capa->num_freq_ranges; i++) { |
| + if (frp[i].range && |
| + freq >= frp[i].range->start_freq && |
| + freq < frp[i].range->end_freq) { |
| + target_power = min_t(s8, frp[i].power, target_power); |
| + break; |
| + } |
| + } |
| + |
| + return target_power; |
| +} |
| + |
| static int |
| mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, |
| enum nl80211_band band) |
| @@ -1816,9 +1840,13 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, |
| .hw_value = ch_list[idx], |
| .band = band, |
| }; |
| + s8 sar_power; |
| + |
| + sar_power = mt76_connac_get_sar_power(phy, &chan, |
| + tx_power); |
| |
| mt76_get_rate_power_limits(phy, &chan, &limits, |
| - tx_power); |
| + sar_power); |
| |
| tx_power_tlv.last_msg = ch_list[idx] == last_ch; |
| sku_tlbv.channel = ch_list[idx]; |
| diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c |
| --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c |
| +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c |
| @@ -41,7 +41,7 @@ mt7921_regd_notifier(struct wiphy *wiphy, |
| mt7921_mutex_release(dev); |
| } |
| |
| -static void |
| +static int |
| mt7921_init_wiphy(struct ieee80211_hw *hw) |
| { |
| struct mt7921_phy *phy = mt7921_hw_phy(hw); |
| @@ -75,6 +75,14 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) |
| wiphy->max_sched_scan_reqs = 1; |
| wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; |
| wiphy->reg_notifier = mt7921_regd_notifier; |
| + wiphy->sar_capa = &mt76_sar_capa; |
| + |
| + phy->mt76->frp = devm_kcalloc(dev->mt76.dev, |
| + wiphy->sar_capa->num_freq_ranges, |
| + sizeof(struct mt76_freq_range_power), |
| + GFP_KERNEL); |
| + if (!phy->mt76->frp) |
| + return -ENOMEM; |
| |
| wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | |
| NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; |
| @@ -92,6 +100,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) |
| ieee80211_hw_set(hw, CONNECTION_MONITOR); |
| |
| hw->max_tx_fragments = 4; |
| + |
| + return 0; |
| } |
| |
| static void |
| @@ -213,7 +223,10 @@ int mt7921_register_device(struct mt7921_dev *dev) |
| if (ret) |
| return ret; |
| |
| - mt7921_init_wiphy(hw); |
| + ret = mt7921_init_wiphy(hw); |
| + if (ret) |
| + return ret; |
| + |
| dev->mphy.sband_2g.sband.ht_cap.cap |= |
| IEEE80211_HT_CAP_LDPC_CODING | |
| IEEE80211_HT_CAP_MAX_AMSDU; |
| diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c |
| --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c |
| +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c |
| @@ -1155,6 +1155,43 @@ static void mt7921_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| HZ / 2); |
| } |
| |
| +static int mt7921_set_sar_specs(struct ieee80211_hw *hw, |
| + const struct cfg80211_sar_specs *sar) |
| +{ |
| + const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; |
| + struct mt7921_dev *dev = mt7921_hw_dev(hw); |
| + struct mt76_freq_range_power *data, *frp; |
| + struct mt76_phy *mphy = hw->priv; |
| + int err; |
| + u32 i; |
| + |
| + if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) |
| + return -EINVAL; |
| + |
| + mt7921_mutex_acquire(dev); |
| + |
| + data = mphy->frp; |
| + |
| + for (i = 0; i < sar->num_sub_specs; i++) { |
| + u32 index = sar->sub_specs[i].freq_range_index; |
| + /* SAR specifies power limitaton in 0.25dbm */ |
| + s32 power = sar->sub_specs[i].power >> 1; |
| + |
| + if (power > 127 || power < -127) |
| + power = 127; |
| + |
| + frp = &data[index]; |
| + frp->range = &capa->freq_ranges[index]; |
| + frp->power = power; |
| + } |
| + |
| + err = mt76_connac_mcu_set_rate_txpower(mphy); |
| + |
| + mt7921_mutex_release(dev); |
| + |
| + return err; |
| +} |
| + |
| static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw, |
| struct ieee80211_vif *vif, |
| struct ieee80211_sta *sta, |
| @@ -1212,4 +1249,5 @@ const struct ieee80211_ops mt7921_ops = { |
| .set_rekey_data = mt7921_set_rekey_data, |
| #endif /* CONFIG_PM */ |
| .flush = mt7921_flush, |
| + .set_sar_specs = mt7921_set_sar_specs, |
| }; |
| -- |
| 2.33.0.464.g1972c5931b-goog |
| |