mt76: mt7921: add back connection monitor support
authorSean Wang <sean.wang@mediatek.com>
Mon, 10 May 2021 15:14:57 +0000 (23:14 +0800)
committerFelix Fietkau <nbd@nbd.name>
Sat, 19 Jun 2021 07:22:44 +0000 (09:22 +0200)
Hw beacon cmd to the mt7921 firmware doesn't only filter out the beacon,
but also performs its own connection monitoring, including periodic
keep-alives to the AP and probing the AP on beacon loss. Will indicate
the host with the event when the firmware detects the connection is lost.

Fixes: 1d8efc741df8 ("mt76: mt7921: introduce Runtime PM support")
Reviewed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Deren Wu <deren.wu@mediatek.com>
Signed-off-by: YN Chen <yn.chen@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7921/init.c
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c

index 9a28da5..a3517ed 100644 (file)
@@ -45,6 +45,7 @@ static void
 mt7921_init_wiphy(struct ieee80211_hw *hw)
 {
        struct mt7921_phy *phy = mt7921_hw_phy(hw);
+       struct mt7921_dev *dev = phy->dev;
        struct wiphy *wiphy = hw->wiphy;
 
        hw->queues = 4;
@@ -84,6 +85,9 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
        ieee80211_hw_set(hw, SUPPORTS_PS);
        ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
 
+       if (dev->pm.enable)
+               ieee80211_hw_set(hw, CONNECTION_MONITOR);
+
        hw->max_tx_fragments = 4;
 }
 
index ef3e454..06209d5 100644 (file)
@@ -450,22 +450,33 @@ mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
 }
 
 static void
-mt7921_mcu_beacon_loss_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_connection_loss_iter(void *priv, u8 *mac,
+                               struct ieee80211_vif *vif)
+{
+       struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+       struct mt76_connac_beacon_loss_event *event = priv;
+
+       if (mvif->idx != event->bss_idx)
+               return;
+
+       if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))
+               return;
+
+       ieee80211_connection_loss(vif);
+}
+
+static void
+mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb)
 {
        struct mt76_connac_beacon_loss_event *event;
-       struct mt76_phy *mphy;
-       u8 band_idx = 0; /* DBDC support */
+       struct mt76_phy *mphy = &dev->mt76.phy;
 
        skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
        event = (struct mt76_connac_beacon_loss_event *)skb->data;
-       if (band_idx && dev->mt76.phy2)
-               mphy = dev->mt76.phy2;
-       else
-               mphy = &dev->mt76.phy;
 
        ieee80211_iterate_active_interfaces_atomic(mphy->hw,
                                        IEEE80211_IFACE_ITER_RESUME_ALL,
-                                       mt76_connac_mcu_beacon_loss_iter, event);
+                                       mt7921_mcu_connection_loss_iter, event);
 }
 
 static void
@@ -530,7 +541,7 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
 
        switch (rxd->eid) {
        case MCU_EVENT_BSS_BEACON_LOSS:
-               mt7921_mcu_beacon_loss_event(dev, skb);
+               mt7921_mcu_connection_loss_event(dev, skb);
                break;
        case MCU_EVENT_SCHED_SCAN_DONE:
        case MCU_EVENT_SCAN_DONE:
@@ -1379,6 +1390,7 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
 {
        struct mt7921_phy *phy = priv;
        struct mt7921_dev *dev = phy->dev;
+       struct ieee80211_hw *hw = mt76_hw(dev);
        int ret;
 
        if (dev->pm.enable)
@@ -1391,9 +1403,11 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
 
        if (dev->pm.enable) {
                vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+               ieee80211_hw_set(hw, CONNECTION_MONITOR);
                mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
        } else {
                vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+               __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags);
                mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
        }
 }