]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: mt76: mt7925: add handler to hif suspend/resume event
authorQuan Zhou <quan.zhou@mediatek.com>
Mon, 5 Jan 2026 11:16:28 +0000 (12:16 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 8 Jan 2026 09:15:02 +0000 (10:15 +0100)
[ Upstream commit 8f6571ad470feb242dcef36e53f7cf1bba03780f ]

When the system suspend or resume, the WiFi driver sends
an hif_ctrl command to the firmware and waits for an event.
Due to changes in the event format reported by the chip, the
current mt7925's driver does not account for these changes,
resulting in command timeout. Add flow to handle hif_ctrl
event to avoid command timeout. We also exented API
mt76_connac_mcu_set_hif_suspend for connac3 this time.

Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
Link: https://patch.msgid.link/3a0844ff5162142c4a9f3cf7104f75076ddd3b87.1735910562.git.quan.zhou@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
14 files changed:
drivers/net/wireless/mediatek/mt76/mt7615/main.c
drivers/net/wireless/mediatek/mt76/mt7615/pci.c
drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
drivers/net/wireless/mediatek/mt76/mt7615/usb.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/pci.c
drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
drivers/net/wireless/mediatek/mt76/mt7921/usb.c
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
drivers/net/wireless/mediatek/mt76/mt7925/pci.c
drivers/net/wireless/mediatek/mt76/mt7925/usb.c
drivers/net/wireless/mediatek/mt76/mt792x.h

index 3769753880075730dea0d01d051993f7c60e3825..4f0c840ef93de7d6a9f4f2834c66d1c7ba1470f8 100644 (file)
@@ -1249,7 +1249,7 @@ static int mt7615_suspend(struct ieee80211_hw *hw,
                                            phy->mt76);
 
        if (!mt7615_dev_running(dev))
-               err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true);
+               err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, true);
 
        mt7615_mutex_release(dev);
 
@@ -1271,7 +1271,7 @@ static int mt7615_resume(struct ieee80211_hw *hw)
        if (!running) {
                int err;
 
-               err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false);
+               err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, true);
                if (err < 0) {
                        mt7615_mutex_release(dev);
                        return err;
index 9f43e673518b8858a965ea4bd9cb34d4cc9ca59f..9a278589df4ef7129f03fb403c19c5093efba6e2 100644 (file)
@@ -83,7 +83,7 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) &&
                      mt7615_firmware_offload(dev);
        if (hif_suspend) {
-               err = mt76_connac_mcu_set_hif_suspend(mdev, true);
+               err = mt76_connac_mcu_set_hif_suspend(mdev, true, true);
                if (err)
                        return err;
        }
@@ -131,7 +131,7 @@ restore:
        }
        napi_enable(&mdev->tx_napi);
        if (hif_suspend)
-               mt76_connac_mcu_set_hif_suspend(mdev, false);
+               mt76_connac_mcu_set_hif_suspend(mdev, false, true);
 
        return err;
 }
@@ -175,7 +175,7 @@ static int mt7615_pci_resume(struct pci_dev *pdev)
 
        if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) &&
            mt7615_firmware_offload(dev))
-               err = mt76_connac_mcu_set_hif_suspend(mdev, false);
+               err = mt76_connac_mcu_set_hif_suspend(mdev, false, true);
 
        return err;
 }
index aebfc4576aa494e91915039350d3c4dac44bb9c9..f56038cd4d3af0819da0391f75ecbfdada26d9e5 100644 (file)
@@ -191,7 +191,7 @@ static int mt7663s_suspend(struct device *dev)
            mt7615_firmware_offload(mdev)) {
                int err;
 
-               err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, true);
+               err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, true, true);
                if (err < 0)
                        return err;
        }
@@ -230,7 +230,7 @@ static int mt7663s_resume(struct device *dev)
 
        if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&
            mt7615_firmware_offload(mdev))
-               err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, false);
+               err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, false, true);
 
        return err;
 }
index 5020af52c68c1327ea27b9d7ef329783ed1693f7..4aa9fa1c4a23b5c6607225e3e44870ca3b2d3f0a 100644 (file)
@@ -225,7 +225,7 @@ static int mt7663u_suspend(struct usb_interface *intf, pm_message_t state)
            mt7615_firmware_offload(dev)) {
                int err;
 
-               err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true);
+               err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, true);
                if (err < 0)
                        return err;
        }
@@ -253,7 +253,7 @@ static int mt7663u_resume(struct usb_interface *intf)
 
        if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) &&
            mt7615_firmware_offload(dev))
-               err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false);
+               err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, true);
 
        return err;
 }
index a6324f6ead781f032b396f8f2eb01a48c5f00846..462b4a68c4f0f14f1878d540b99fa1918b6b25ad 100644 (file)
@@ -2527,7 +2527,7 @@ mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif,
 }
 EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_wow_ctrl);
 
-int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend)
+int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend, bool wait_resp)
 {
        struct {
                struct {
@@ -2559,7 +2559,7 @@ int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend)
                req.hdr.hif_type = 0;
 
        return mt76_mcu_send_msg(dev, MCU_UNI_CMD(HIF_CTRL), &req,
-                                sizeof(req), true);
+                                sizeof(req), wait_resp);
 }
 EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_hif_suspend);
 
index 57a8340fa70097c62039fe3e8da5c4d3d1b47549..6901971f5da6b8b7024159b2388b1b292ae5afde 100644 (file)
@@ -1049,6 +1049,7 @@ enum {
 /* unified event table */
 enum {
        MCU_UNI_EVENT_RESULT = 0x01,
+       MCU_UNI_EVENT_HIF_CTRL = 0x03,
        MCU_UNI_EVENT_FW_LOG_2_HOST = 0x04,
        MCU_UNI_EVENT_ACCESS_REG = 0x6,
        MCU_UNI_EVENT_IE_COUNTDOWN = 0x09,
@@ -1989,7 +1990,7 @@ int mt76_connac_mcu_set_suspend_mode(struct mt76_dev *dev,
                                     struct ieee80211_vif *vif,
                                     bool enable, u8 mdtim,
                                     bool wow_suspend);
-int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend);
+int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend, bool wait_resp);
 void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
                                      struct ieee80211_vif *vif);
 int mt76_connac_sta_state_dp(struct mt76_dev *dev,
index 67723c22aea6cec3e25bb762ea9a1df97a51d920..6da90c6238de27f34b599ab49a224aba964e3b43 100644 (file)
@@ -435,7 +435,7 @@ static int mt7921_pci_suspend(struct device *device)
        if (err < 0)
                goto restore_suspend;
 
-       err = mt76_connac_mcu_set_hif_suspend(mdev, true);
+       err = mt76_connac_mcu_set_hif_suspend(mdev, true, true);
        if (err)
                goto restore_suspend;
 
@@ -481,7 +481,7 @@ restore_napi:
        if (!pm->ds_enable)
                mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
 
-       mt76_connac_mcu_set_hif_suspend(mdev, false);
+       mt76_connac_mcu_set_hif_suspend(mdev, false, true);
 
 restore_suspend:
        pm->suspended = false;
@@ -532,7 +532,7 @@ static int mt7921_pci_resume(struct device *device)
        if (!pm->ds_enable)
                mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
 
-       err = mt76_connac_mcu_set_hif_suspend(mdev, false);
+       err = mt76_connac_mcu_set_hif_suspend(mdev, false, true);
        if (err < 0)
                goto failed;
 
index 95f526f7bb991d265ee41e26e237f56e953efbba..45b9f35aab178c25c996c497c75e3c501f1d9f77 100644 (file)
@@ -240,7 +240,7 @@ static int mt7921s_suspend(struct device *__dev)
                           mt76s_txqs_empty(&dev->mt76), 5 * HZ);
 
        /* It is supposed that SDIO bus is idle at the point */
-       err = mt76_connac_mcu_set_hif_suspend(mdev, true);
+       err = mt76_connac_mcu_set_hif_suspend(mdev, true, true);
        if (err)
                goto restore_worker;
 
@@ -258,7 +258,7 @@ static int mt7921s_suspend(struct device *__dev)
 restore_txrx_worker:
        mt76_worker_enable(&mdev->sdio.net_worker);
        mt76_worker_enable(&mdev->sdio.txrx_worker);
-       mt76_connac_mcu_set_hif_suspend(mdev, false);
+       mt76_connac_mcu_set_hif_suspend(mdev, false, true);
 
 restore_worker:
        mt76_worker_enable(&mdev->tx_worker);
@@ -302,7 +302,7 @@ static int mt7921s_resume(struct device *__dev)
        if (!pm->ds_enable)
                mt76_connac_mcu_set_deep_sleep(mdev, false);
 
-       err = mt76_connac_mcu_set_hif_suspend(mdev, false);
+       err = mt76_connac_mcu_set_hif_suspend(mdev, false, true);
 failed:
        pm->suspended = false;
 
index 5be0edb2fe9aad92c335d543cd613d00828542d9..100bdba32ba59ebf396c99dce23988822879ecb2 100644 (file)
@@ -263,7 +263,7 @@ static int mt7921u_suspend(struct usb_interface *intf, pm_message_t state)
        pm->suspended = true;
        flush_work(&dev->reset_work);
 
-       err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true);
+       err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, true);
        if (err)
                goto failed;
 
@@ -313,7 +313,7 @@ static int mt7921u_resume(struct usb_interface *intf)
        if (err < 0)
                goto failed;
 
-       err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false);
+       err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, true);
 failed:
        pm->suspended = false;
 
index c42b3b376f77e0cf9e4a84fac983361665ee0bcf..847a1069f41eb956da7270eacd4122c4d6fe91cd 100644 (file)
@@ -39,7 +39,6 @@ int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd,
        } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
                   cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
                   cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
-                  cmd == MCU_UNI_CMD(HIF_CTRL) ||
                   cmd == MCU_UNI_CMD(OFFLOAD) ||
                   cmd == MCU_UNI_CMD(SUSPEND)) {
                struct mt7925_mcu_uni_event *event;
@@ -341,6 +340,51 @@ static void mt7925_mcu_roc_handle_grant(struct mt792x_dev *dev,
                  jiffies + msecs_to_jiffies(duration));
 }
 
+static void
+mt7925_mcu_handle_hif_ctrl_basic(struct mt792x_dev *dev, struct tlv *tlv)
+{
+       struct mt7925_mcu_hif_ctrl_basic_tlv *basic;
+
+       basic = (struct mt7925_mcu_hif_ctrl_basic_tlv *)tlv;
+
+       if (basic->hifsuspend) {
+               if (basic->hif_tx_traffic_status == HIF_TRAFFIC_IDLE &&
+                   basic->hif_rx_traffic_status == HIF_TRAFFIC_IDLE)
+                       /* success */
+                       dev->hif_idle = true;
+               else
+                       /* busy */
+                       /* invalid */
+                       dev->hif_idle = false;
+       } else {
+               dev->hif_resumed = true;
+       }
+       wake_up(&dev->wait);
+}
+
+static void
+mt7925_mcu_uni_hif_ctrl_event(struct mt792x_dev *dev, struct sk_buff *skb)
+{
+       struct tlv *tlv;
+       u32 tlv_len;
+
+       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_HIF_CTRL_BASIC:
+                       mt7925_mcu_handle_hif_ctrl_basic(dev, tlv);
+                       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_roc_event(struct mt792x_dev *dev, struct sk_buff *skb)
 {
@@ -487,6 +531,9 @@ mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,
        rxd = (struct mt7925_mcu_rxd *)skb->data;
 
        switch (rxd->eid) {
+       case MCU_UNI_EVENT_HIF_CTRL:
+               mt7925_mcu_uni_hif_ctrl_event(dev, skb);
+               break;
        case MCU_UNI_EVENT_FW_LOG_2_HOST:
                mt7925_mcu_uni_debug_msg_event(dev, skb);
                break;
index 76f31abe91461b1ec7b53fe7c9edf38e12d3087c..27680ad28b600e6581c5f859c0fdd54a9699bd01 100644 (file)
 
 #define MCU_UNI_EVENT_ROC  0x27
 
+#define HIF_TRAFFIC_IDLE 0x2
+
+enum {
+       UNI_EVENT_HIF_CTRL_BASIC = 0,
+       UNI_EVENT_HIF_CTRL_TAG_NUM
+};
+
+struct mt7925_mcu_hif_ctrl_basic_tlv {
+       __le16 tag;
+       __le16 len;
+       u8 cid;
+       u8 pad[3];
+       u32 status;
+       u8 hif_type;
+       u8 hif_tx_traffic_status;
+       u8 hif_rx_traffic_status;
+       u8 hifsuspend;
+       u8 rsv[4];
+} __packed;
+
 enum {
        UNI_ROC_ACQUIRE,
        UNI_ROC_ABORT,
index ccb663bd9f5280a43a9f8610e4da0f81b7284e7f..a90e90131276e174b836673b2575f897e3145db2 100644 (file)
@@ -442,9 +442,10 @@ static int mt7925_pci_suspend(struct device *device)
        struct mt76_dev *mdev = pci_get_drvdata(pdev);
        struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
        struct mt76_connac_pm *pm = &dev->pm;
-       int i, err;
+       int i, err, ret;
 
        pm->suspended = true;
+       dev->hif_resumed = false;
        flush_work(&dev->reset_work);
        cancel_delayed_work_sync(&pm->ps_work);
        cancel_work_sync(&pm->wake_work);
@@ -463,9 +464,13 @@ static int mt7925_pci_suspend(struct device *device)
         */
        mt7925_mcu_set_deep_sleep(dev, true);
 
-       err = mt76_connac_mcu_set_hif_suspend(mdev, true);
-       if (err)
+       mt76_connac_mcu_set_hif_suspend(mdev, true, false);
+       ret = wait_event_timeout(dev->wait,
+                                dev->hif_idle, 3 * HZ);
+       if (!ret) {
+               err = -ETIMEDOUT;
                goto restore_suspend;
+       }
 
        napi_disable(&mdev->tx_napi);
        mt76_worker_disable(&mdev->tx_worker);
@@ -506,8 +511,11 @@ restore_napi:
        if (!pm->ds_enable)
                mt7925_mcu_set_deep_sleep(dev, false);
 
-       mt76_connac_mcu_set_hif_suspend(mdev, false);
-
+       mt76_connac_mcu_set_hif_suspend(mdev, false, false);
+       ret = wait_event_timeout(dev->wait,
+                                dev->hif_resumed, 3 * HZ);
+       if (!ret)
+               err = -ETIMEDOUT;
 restore_suspend:
        pm->suspended = false;
 
@@ -523,8 +531,9 @@ static int mt7925_pci_resume(struct device *device)
        struct mt76_dev *mdev = pci_get_drvdata(pdev);
        struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
        struct mt76_connac_pm *pm = &dev->pm;
-       int i, err;
+       int i, err, ret;
 
+       dev->hif_idle = false;
        err = mt792x_mcu_drv_pmctrl(dev);
        if (err < 0)
                goto failed;
@@ -553,9 +562,13 @@ static int mt7925_pci_resume(struct device *device)
        napi_schedule(&mdev->tx_napi);
        local_bh_enable();
 
-       err = mt76_connac_mcu_set_hif_suspend(mdev, false);
-       if (err < 0)
+       mt76_connac_mcu_set_hif_suspend(mdev, false, false);
+       ret = wait_event_timeout(dev->wait,
+                                dev->hif_resumed, 3 * HZ);
+       if (!ret) {
+               err = -ETIMEDOUT;
                goto failed;
+       }
 
        /* restore previous ds setting */
        if (!pm->ds_enable)
index a63ff630eaba9ffb95157caf4a9a3aa3a4c290ac..bf040f34e4b9f7bdf294fbb9c1579e052aba6afc 100644 (file)
@@ -246,14 +246,19 @@ static int mt7925u_suspend(struct usb_interface *intf, pm_message_t state)
 {
        struct mt792x_dev *dev = usb_get_intfdata(intf);
        struct mt76_connac_pm *pm = &dev->pm;
-       int err;
+       int err, ret;
 
        pm->suspended = true;
+       dev->hif_resumed = false;
        flush_work(&dev->reset_work);
 
-       err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true);
-       if (err)
+       mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, false);
+       ret = wait_event_timeout(dev->wait,
+                                dev->hif_idle, 3 * HZ);
+       if (!ret) {
+               err = -ETIMEDOUT;
                goto failed;
+       }
 
        mt76u_stop_rx(&dev->mt76);
        mt76u_stop_tx(&dev->mt76);
@@ -274,8 +279,9 @@ static int mt7925u_resume(struct usb_interface *intf)
        struct mt792x_dev *dev = usb_get_intfdata(intf);
        struct mt76_connac_pm *pm = &dev->pm;
        bool reinit = true;
-       int err, i;
+       int err, i, ret;
 
+       dev->hif_idle = false;
        for (i = 0; i < 10; i++) {
                u32 val = mt76_rr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT);
 
@@ -301,7 +307,11 @@ static int mt7925u_resume(struct usb_interface *intf)
        if (err < 0)
                goto failed;
 
-       err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false);
+       mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, false);
+       ret = wait_event_timeout(dev->wait,
+                                dev->hif_resumed, 3 * HZ);
+       if (!ret)
+               err = -ETIMEDOUT;
 failed:
        pm->suspended = false;
 
index 2b8b9b2977f74a17652ee65ee25e1926d30a1d96..cf1b6083cf2f0d32637a78d0140f518491b2e940 100644 (file)
@@ -216,6 +216,8 @@ struct mt792x_dev {
        bool has_eht:1;
        bool regd_in_progress:1;
        bool aspm_supported:1;
+       bool hif_idle:1;
+       bool hif_resumed:1;
        wait_queue_head_t wait;
 
        struct work_struct init_work;