]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mt76: mt7925: cqm rssi low/high event notify
authorJack Kao <jack.kao@mediatek.com>
Wed, 1 Oct 2025 01:25:06 +0000 (09:25 +0800)
committerFelix Fietkau <nbd@nbd.name>
Mon, 24 Nov 2025 13:59:11 +0000 (14:59 +0100)
The implementation amounts to setting the driver flag
IEEE80211_VIF_SUPPORTS_CQM_RSSI, and then providing
mechanisms for continuously updating enough information
to be able to provide notifications to userspace when
RSSI drops below a certain threshold

Signed-off-by: Jack Kao <jack.kao@mediatek.com>
Signed-off-by: Ming Yen Hsieh <mingyen.hsieh@mediatek.com>
Link: https://patch.msgid.link/20251001012506.2168037-1-mingyen.hsieh@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
drivers/net/wireless/mediatek/mt76/mt7925/main.c
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h

index 92713813084246269a2348f0ce2e4b7cd00c879c..8d59cf43f0e2dc8d8e42d6b2ec7565ad69a79ff8 100644 (file)
@@ -1062,6 +1062,7 @@ enum {
        MCU_UNI_EVENT_ROC = 0x27,
        MCU_UNI_EVENT_TX_DONE = 0x2d,
        MCU_UNI_EVENT_THERMAL = 0x35,
+       MCU_UNI_EVENT_RSSI_MONITOR = 0x41,
        MCU_UNI_EVENT_NIC_CAPAB = 0x43,
        MCU_UNI_EVENT_WED_RRO = 0x57,
        MCU_UNI_EVENT_PER_STA_INFO = 0x6d,
@@ -1300,6 +1301,7 @@ enum {
        MCU_UNI_CMD_THERMAL = 0x35,
        MCU_UNI_CMD_VOW = 0x37,
        MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
+       MCU_UNI_CMD_RSSI_MONITOR = 0x41,
        MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
        MCU_UNI_CMD_RRO = 0x57,
        MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
index cb913dfedcdab18b0c2a2587534ed8acb5122832..add4c8d59e93061a4b8dd5a11c706c80cb266190 100644 (file)
@@ -431,6 +431,9 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                goto out;
 
        vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+       if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN)
+               vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI;
+
 out:
        mt792x_mutex_release(dev);
 
@@ -1936,6 +1939,9 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw,
                mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76,
                                      link_conf, NULL);
 
+       if (changed & BSS_CHANGED_CQM)
+               mt7925_mcu_set_rssimonitor(dev, vif);
+
        mt792x_mutex_release(dev);
 }
 
index b6ef9d9e5f7f31a764d19ed23fea36c332f5e34c..d8f5ecebf5dc29b5769e18e2be1cea47e3658fa7 100644 (file)
@@ -447,6 +447,56 @@ mt7925_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb)
        }
 }
 
+static void
+mt7925_mcu_rssi_monitor_iter(void *priv, u8 *mac,
+                            struct ieee80211_vif *vif)
+{
+       struct mt7925_uni_rssi_monitor_event *event = priv;
+       enum nl80211_cqm_rssi_threshold_event nl_event;
+       s32 rssi = le32_to_cpu(event->rssi);
+
+       if (vif->type != NL80211_IFTYPE_STATION)
+               return;
+
+       if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))
+               return;
+
+       if (rssi > vif->bss_conf.cqm_rssi_thold)
+               nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
+       else
+               nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
+
+       ieee80211_cqm_rssi_notify(vif, nl_event, rssi, GFP_KERNEL);
+}
+
+static void
+mt7925_mcu_rssi_monitor_event(struct mt792x_dev *dev, struct sk_buff *skb)
+{
+       struct tlv *tlv;
+       u32 tlv_len;
+       struct mt7925_uni_rssi_monitor_event *event;
+
+       skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);
+       tlv = (struct tlv *)skb->data;
+       tlv_len = skb->len;
+
+       while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) {
+               switch (le16_to_cpu(tlv->tag)) {
+               case UNI_EVENT_RSSI_MONITOR_INFO:
+                       event = (struct mt7925_uni_rssi_monitor_event *)skb->data;
+                       ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw,
+                                                                  IEEE80211_IFACE_ITER_RESUME_ALL,
+                                                                  mt7925_mcu_rssi_monitor_iter,
+                                                                  event);
+                       break;
+               default:
+                       break;
+               }
+               tlv_len -= le16_to_cpu(tlv->len);
+               tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len));
+       }
+}
+
 static void
 mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
 {
@@ -543,6 +593,9 @@ mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,
        case MCU_UNI_EVENT_BSS_BEACON_LOSS:
                mt7925_mcu_connection_loss_event(dev, skb);
                break;
+       case MCU_UNI_EVENT_RSSI_MONITOR:
+               mt7925_mcu_rssi_monitor_event(dev, skb);
+               break;
        case MCU_UNI_EVENT_COREDUMP:
                dev->fw_assert = true;
                mt76_connac_mcu_coredump_event(&dev->mt76, skb, &dev->coredump);
@@ -3819,3 +3872,32 @@ int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,
        return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG),
                                 &req, sizeof(req), true);
 }
+
+int mt7925_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif)
+{
+       struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(&vif->bss_conf);
+       struct {
+               struct {
+                       u8 bss_idx;
+                       u8 pad[3];
+               } __packed hdr;
+               __le16 tag;
+               __le16 len;
+               u8 enable;
+               s8 cqm_rssi_high;
+               s8 cqm_rssi_low;
+               u8 rsv;
+       } req = {
+               .hdr = {
+                       .bss_idx = mconf->mt76.idx,
+               },
+               .tag = cpu_to_le16(UNI_CMD_RSSI_MONITOR_SET),
+               .len = cpu_to_le16(sizeof(req) - 4),
+               .enable = vif->cfg.assoc,
+               .cqm_rssi_high = (s8)(vif->bss_conf.cqm_rssi_thold + vif->bss_conf.cqm_rssi_hyst),
+               .cqm_rssi_low = (s8)(vif->bss_conf.cqm_rssi_thold - vif->bss_conf.cqm_rssi_hyst),
+       };
+
+       return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(RSSI_MONITOR), &req,
+                                sizeof(req), false);
+}
index 1a11e977a24481bd901ea106a57817fe35f0d5be..e09e0600534aa5d7de16a8869dea3d1e9086b10d 100644 (file)
@@ -152,6 +152,14 @@ enum {
        UNI_EVENT_SCAN_DONE_NLO = 3,
 };
 
+enum {
+       UNI_CMD_RSSI_MONITOR_SET = 0,
+};
+
+enum {
+       UNI_EVENT_RSSI_MONITOR_INFO = 0,
+};
+
 enum connac3_mcu_cipher_type {
        CONNAC3_CIPHER_NONE = 0,
        CONNAC3_CIPHER_WEP40 = 1,
index 6412969f0ac6dd8a33f0d048fa300ea675803c7b..6b9bf1b89032089e3db85e98cd0e0c6694450d38 100644 (file)
@@ -103,6 +103,12 @@ struct mt7925_uni_beacon_loss_event {
        struct mt7925_beacon_loss_tlv beacon_loss;
 } __packed;
 
+struct mt7925_uni_rssi_monitor_event {
+               __le16 tag;
+               __le16 len;
+               __le32 rssi;
+} __packed;
+
 #define to_rssi(field, rxv)            ((FIELD_GET(field, rxv) - 220) / 2)
 #define to_rcpi(rssi)                  (2 * (rssi) + 220)
 
@@ -370,4 +376,5 @@ int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 int mt7925_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
                         struct netlink_callback *cb, void *data, int len);
 
+int mt7925_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif);
 #endif