]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mt76: mt7925: add handler to hif suspend/resume event
authorQuan Zhou <quan.zhou@mediatek.com>
Fri, 3 Jan 2025 13:44:54 +0000 (21:44 +0800)
committerFelix Fietkau <nbd@nbd.name>
Tue, 14 Jan 2025 12:42:30 +0000 (13:42 +0100)
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>
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 7acf3f4ad3c9f55e13b3e68eb845f931fc3d8c61..2e7b05eeef7a048ff5c41fc690f483d2301a28d5 100644 (file)
@@ -1248,7 +1248,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);
 
@@ -1270,7 +1270,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 e9ec9b7e0acb223762ab7dfd6f6615fce9775ee8..f30cf9e716105d3aa05a68713e9c857d9df510f8 100644 (file)
@@ -2534,7 +2534,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 {
@@ -2566,7 +2566,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 894b27cb61853368d560584268bfab629c3b05b1..43237e518373f6b017bb113c7f77386f8b4c3df1 100644 (file)
@@ -1050,6 +1050,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,
@@ -1992,7 +1993,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 b76660325599c242a478a3ddff571042a117de42..ba870e1b05fb888eeeb23bd198a36e90621b18c7 100644 (file)
@@ -439,7 +439,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;
 
@@ -485,7 +485,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;
@@ -536,7 +536,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 e3459295ad884e5543ab718fdafca033ff820c18..fe9751851ff7479fc59019e4f4913bca064fcd07 100644 (file)
@@ -260,7 +260,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;
 
@@ -310,7 +310,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 4c378af715e2e05e9517b85ce41f9c9cd1295fab..15815ad84713a414e7632801f5f3e8e761cb8d39 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 a7325ec13c70e1db76fef0d73d2610d90ad606b9..8707b5d04743bd91875d05f67927953ffa9697b7 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 5c9282b7652279f48455c5e582fad65dceb817ec..f36893e20c617fe8e61ebdcc844de65cb6332704 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);
@@ -509,8 +514,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;
 
@@ -526,8 +534,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;
@@ -556,9 +565,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 682db1bab21c6aeec452097e4e24cc34efb63c10..4dfbc1b6cfddb4c8226029c545e7d8d2588e1b21 100644 (file)
@@ -243,14 +243,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);
@@ -271,8 +276,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);
 
@@ -298,7 +304,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 e331a056950f25e30520a59323228a314dfa1d0f..f0e7b555269111cce5c4f1bc390bef3c606ae260 100644 (file)
@@ -222,6 +222,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;