mt76: introduce single-sku support for mt7663/mt7921
authorLorenzo Bianconi <lorenzo@kernel.org>
Tue, 13 Apr 2021 09:08:40 +0000 (11:08 +0200)
committerFelix Fietkau <nbd@nbd.name>
Wed, 21 Apr 2021 09:42:21 +0000 (11:42 +0200)
Introduce support for rate-txpower compensation for mt7663/mt7921 chipsets.
Rate-txpower limit is specified through dts

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7615/init.c
drivers/net/wireless/mediatek/mt76/mt7615/main.c
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
drivers/net/wireless/mediatek/mt76/mt7921/init.c
drivers/net/wireless/mediatek/mt76/mt7921/main.c

index e58f46d..d84662f 100644 (file)
@@ -323,8 +323,11 @@ mt7615_regd_notifier(struct wiphy *wiphy,
 
        if (chandef->chan->flags & IEEE80211_CHAN_RADAR)
                mt7615_dfs_init_radar_detector(phy);
-       if (mt7615_firmware_offload(phy->dev))
+
+       if (mt7615_firmware_offload(phy->dev)) {
                mt76_connac_mcu_set_channel_domain(mphy);
+               mt76_connac_mcu_set_rate_txpower(mphy);
+       }
 
        mt7615_mutex_release(dev);
 }
index e30b256..62d9df4 100644 (file)
@@ -66,6 +66,10 @@ static int mt7615_start(struct ieee80211_hw *hw)
                ret = mt76_connac_mcu_set_channel_domain(phy->mt76);
                if (ret)
                        goto out;
+
+               ret = mt76_connac_mcu_set_rate_txpower(phy->mt76);
+               if (ret)
+                       goto out;
        }
 
        ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);
index cc842e3..e057347 100644 (file)
@@ -1560,6 +1560,139 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
 }
 EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);
 
+static void
+mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,
+                         struct mt76_power_limits *limits,
+                         enum nl80211_band band)
+{
+       int max_power = is_mt7921(dev) ? 127 : 63;
+       int i, offset = sizeof(limits->cck);
+
+       memset(sku, max_power, MT_SKU_POWER_LIMIT);
+
+       if (band == NL80211_BAND_2GHZ) {
+               /* cck */
+               memcpy(sku, limits->cck, sizeof(limits->cck));
+       }
+
+       /* ofdm */
+       memcpy(&sku[offset], limits->ofdm, sizeof(limits->ofdm));
+       offset += sizeof(limits->ofdm);
+
+       /* ht */
+       for (i = 0; i < 2; i++) {
+               memcpy(&sku[offset], limits->mcs[i], 8);
+               offset += 8;
+       }
+       sku[offset++] = limits->mcs[0][0];
+
+       /* vht */
+       for (i = 0; i < ARRAY_SIZE(limits->mcs); i++) {
+               memcpy(&sku[offset], limits->mcs[i],
+                      ARRAY_SIZE(limits->mcs[i]));
+               offset += 12;
+       }
+
+       if (!is_mt7921(dev))
+               return;
+
+       /* he */
+       for (i = 0; i < ARRAY_SIZE(limits->ru); i++) {
+               memcpy(&sku[offset], limits->ru[i], ARRAY_SIZE(limits->ru[i]));
+               offset += ARRAY_SIZE(limits->ru[i]);
+       }
+}
+
+static int
+mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
+                                 enum nl80211_band band)
+{
+       struct mt76_dev *dev = phy->dev;
+       int sku_len, batch_len = is_mt7921(dev) ? 8 : 16;
+       static const u8 chan_list_2ghz[] = {
+               1, 2,  3,  4,  5,  6,  7,
+               8, 9, 10, 11, 12, 13, 14
+       };
+       static const u8 chan_list_5ghz[] = {
+                36,  38,  40,  42,  44,  46,  48,
+                50,  52,  54,  56,  58,  60,  62,
+                64, 100, 102, 104, 106, 108, 110,
+               112, 114, 116, 118, 120, 122, 124,
+               126, 128, 132, 134, 136, 138, 140,
+               142, 144, 149, 151, 153, 155, 157,
+               159, 161, 165
+       };
+       struct mt76_connac_sku_tlv sku_tlbv;
+       int i, n_chan, batch_size, idx = 0;
+       struct mt76_power_limits limits;
+       const u8 *ch_list;
+
+       sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;
+
+       if (band == NL80211_BAND_2GHZ) {
+               n_chan = ARRAY_SIZE(chan_list_2ghz);
+               ch_list = chan_list_2ghz;
+       } else {
+               n_chan = ARRAY_SIZE(chan_list_5ghz);
+               ch_list = chan_list_5ghz;
+       }
+       batch_size = DIV_ROUND_UP(n_chan, batch_len);
+
+       for (i = 0; i < batch_size; i++) {
+               bool last_msg = i == batch_size - 1;
+               int num_ch = last_msg ? n_chan % batch_len : batch_len;
+               struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {
+                       .band = band == NL80211_BAND_2GHZ ? 1 : 2,
+                       .n_chan = num_ch,
+                       .last_msg = last_msg,
+               };
+               struct sk_buff *skb;
+               int j, err, msg_len;
+
+               msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv);
+               skb = mt76_mcu_msg_alloc(dev, NULL, msg_len);
+               if (!skb)
+                       return -ENOMEM;
+
+               BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2));
+               memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2));
+
+               skb_put_data(skb, &tx_power_tlv, sizeof(tx_power_tlv));
+               for (j = 0; j < num_ch; j++, idx++) {
+                       struct ieee80211_channel chan = {
+                               .hw_value = ch_list[idx],
+                               .band = band,
+                       };
+
+                       mt76_get_rate_power_limits(phy, &chan, &limits, 127);
+
+                       sku_tlbv.channel = ch_list[idx];
+                       mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit,
+                                                 &limits, band);
+                       skb_put_data(skb, &sku_tlbv, sku_len);
+               }
+
+               err = mt76_mcu_skb_send_msg(dev, skb,
+                                           MCU_CMD_SET_RATE_TX_POWER, false);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy)
+{
+       int err;
+
+       err = mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_2GHZ);
+       if (err < 0)
+               return err;
+
+       return mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_5GHZ);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);
+
 #ifdef CONFIG_PM
 
 const struct wiphy_wowlan_support mt76_connac_wowlan_support = {
index 5870974..8d1b8e0 100644 (file)
@@ -895,6 +895,28 @@ struct mt76_sta_cmd_info {
        u8 rcpi;
 };
 
+#define MT_SKU_POWER_LIMIT     161
+
+struct mt76_connac_sku_tlv {
+       u8 channel;
+       s8 pwr_limit[MT_SKU_POWER_LIMIT];
+} __packed;
+
+struct mt76_connac_tx_power_limit_tlv {
+       /* DW0 - common info*/
+       u8 ver;
+       u8 pad0;
+       __le16 len;
+       /* DW1 - cmd hint */
+       u8 n_chan; /* # channel */
+       u8 band; /* 2.4GHz - 5GHz */
+       u8 last_msg;
+       u8 pad1;
+       /* DW3 */
+       u8 alpha2[4]; /* regulatory_request.alpha2 */
+       u8 pad2[32];
+} __packed;
+
 #define to_wcid_lo(id)         FIELD_GET(GENMASK(7, 0), (u16)id)
 #define to_wcid_hi(id)         FIELD_GET(GENMASK(9, 8), (u16)id)
 
@@ -996,4 +1018,5 @@ void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
 int mt76_connac_mcu_chip_config(struct mt76_dev *dev);
 void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
                                    struct mt76_connac_coredump *coredump);
+int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy);
 #endif /* __MT76_CONNAC_MCU_H */
index 94fe2ea..0aedddb 100644 (file)
@@ -58,12 +58,14 @@ mt7921_regd_notifier(struct wiphy *wiphy,
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct mt7921_dev *dev = mt7921_hw_dev(hw);
+       struct mt7921_phy *phy = mt7921_hw_phy(hw);
 
        memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
        dev->mt76.region = request->dfs_region;
 
        mt7921_mutex_acquire(dev);
        mt76_connac_mcu_set_channel_domain(hw->priv);
+       mt76_connac_mcu_set_rate_txpower(phy->mt76);
        mt7921_mutex_release(dev);
 }
 
index c888e82..13910ac 100644 (file)
@@ -182,6 +182,10 @@ int __mt7921_start(struct mt7921_phy *phy)
        if (err)
                return err;
 
+       err = mt76_connac_mcu_set_rate_txpower(phy->mt76);
+       if (err)
+               return err;
+
        mt7921_mac_reset_counters(phy);
        set_bit(MT76_STATE_RUNNING, &mphy->state);