diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c index a2ac6c098163..6de210139d8a 100644 --- a/drivers/staging/wfx/hif_rx.c +++ b/drivers/staging/wfx/hif_rx.c @@ -235,12 +235,20 @@ static int hif_suspend_resume_indication(struct wfx_dev *wdev, struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); const struct hif_ind_suspend_resume_tx *body = buf; - WARN_ON(!wvif); - WARN(!body->suspend_resume_flags.bc_mc_only, "unsupported suspend/resume notification"); - if (body->suspend_resume_flags.resume) - wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE); - else - wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP); + if (body->suspend_resume_flags.bc_mc_only) { + WARN_ON(!wvif); + if (body->suspend_resume_flags.resume) + wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE); + else + wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP); + } else { + WARN(body->peer_sta_set, "misunderstood indication"); + WARN(hif->interface != 2, "misunderstood indication"); + if (body->suspend_resume_flags.resume) + wfx_suspend_hot_dev(wdev, STA_NOTIFY_AWAKE); + else + wfx_suspend_hot_dev(wdev, STA_NOTIFY_SLEEP); + } return 0; } diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c index cc7f924f3106..1093584373ad 100644 --- a/drivers/staging/wfx/main.c +++ b/drivers/staging/wfx/main.c @@ -341,6 +341,8 @@ struct wfx_dev *wfx_init_common(struct device *dev, mutex_init(&wdev->conf_mutex); mutex_init(&wdev->rx_stats_lock); init_completion(&wdev->firmware_ready); + INIT_DELAYED_WORK(&wdev->cooling_timeout_work, + wfx_cooling_timeout_work); wfx_init_hif_cmd(&wdev->hif_cmd); wfx_tx_queues_init(wdev); diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c index 5132c19e0367..67eb4a6e176b 100644 --- a/drivers/staging/wfx/sta.c +++ b/drivers/staging/wfx/sta.c @@ -38,6 +38,29 @@ u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates) return ret; } +void wfx_cooling_timeout_work(struct work_struct *work) +{ + struct wfx_dev *wdev = container_of(to_delayed_work(work), + struct wfx_dev, + cooling_timeout_work); + + wdev->chip_frozen = true; + wfx_tx_unlock(wdev); +} + +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd) +{ + if (cmd == STA_NOTIFY_AWAKE) { + // Device recover normal temperature + if (cancel_delayed_work(&wdev->cooling_timeout_work)) + wfx_tx_unlock(wdev); + } else { + // Device is too hot + schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ); + wfx_tx_lock(wdev); + } +} + static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon) { const struct hif_ie_table_entry filter_ies[] = { diff --git a/drivers/staging/wfx/sta.h b/drivers/staging/wfx/sta.h index e814fe743b7d..f7e876d1b031 100644 --- a/drivers/staging/wfx/sta.h +++ b/drivers/staging/wfx/sta.h @@ -67,6 +67,8 @@ void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf); // WSM Callbacks +void wfx_cooling_timeout_work(struct work_struct *work); +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd); void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd cmd); void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi); diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h index c7a58ab3beaa..09bbb5da4f06 100644 --- a/drivers/staging/wfx/wfx.h +++ b/drivers/staging/wfx/wfx.h @@ -45,6 +45,7 @@ struct wfx_dev { struct hif_ind_startup hw_caps; struct wfx_hif hif; struct sl_context sl; + struct delayed_work cooling_timeout_work; bool chip_frozen; struct mutex conf_mutex;