staging: wfx: add support for 'device too hot' indication
authorJérôme Pouiller <jerome.pouiller@silabs.com>
Mon, 27 Apr 2020 13:40:20 +0000 (15:40 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Apr 2020 12:14:27 +0000 (14:14 +0200)
Device is able to detect a high temperature. In this case, the traffic
is not allowed to be sent until the temperature decrease.

This patch detects the warnings raised by the device and stop the
traffic accordingly. It also add a delayed task as safeguard in case the
chip would never send the indication that the temperature decrease.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://lore.kernel.org/r/20200427134031.323403-7-Jerome.Pouiller@silabs.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/wfx/hif_rx.c
drivers/staging/wfx/main.c
drivers/staging/wfx/sta.c
drivers/staging/wfx/sta.h
drivers/staging/wfx/wfx.h

index a2ac6c0981637d000cd486d1699e3a534864cfff..6de210139d8af070bcc1ef5d494b4837de6c41e7 100644 (file)
@@ -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;
 }
index cc7f924f3106834b3cf79ae6badc36d8cb77f330..1093584373ad32ad718b49b1f03e140de42959be 100644 (file)
@@ -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);
 
index 5132c19e0367bd933c6c235a4446b6968882b8ae..67eb4a6e176bf0fb545731a32548619ced68b14b 100644 (file)
@@ -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[] = {
index e814fe743b7d0c3117c6a432e53b3ad412f8d8c3..f7e876d1b03184c06e1c272675852e1eca42a07c 100644 (file)
@@ -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);
 
index c7a58ab3beaa346737b699b5c6ea49cdf5765a45..09bbb5da4f066c62ddbcbbbdb54df2bbcee43055 100644 (file)
@@ -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;