diff mbox series

[04/17] staging: wfx: fix support for AP that do not support PS-Poll

Message ID 20200427134031.323403-5-Jerome.Pouiller@silabs.com
State New
Headers show
Series staging: wfx: misc fixes | expand

Commit Message

Jérôme Pouiller April 27, 2020, 1:40 p.m. UTC
From: Jérôme Pouiller <jerome.pouiller@silabs.com>

When multiple virtual interfaces (on different channels) are in use, the
device ask to activate Power Save on station interfaces. The device
developers recommends to use legacy PS-Poll in this case since it is the
mode that disturb the less the other interface. However, some AP start
to not answer anymore to PS-Poll. The device is able to detect this case
and return a special warning in this case.

So, this commit catch the warning and force usage of FastPS in this
case.

In order to confuse the less possible the other interface a small FastPS
period is used (30ms).

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
---
 drivers/staging/wfx/hif_rx.c |  8 +++++++-
 drivers/staging/wfx/sta.c    | 16 +++++++++++++++-
 drivers/staging/wfx/wfx.h    |  2 ++
 3 files changed, 24 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index 6dbe289a368f..a2ac6c098163 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -176,7 +176,13 @@  static int hif_event_indication(struct wfx_dev *wdev,
 		dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n");
 		break;
 	case HIF_EVENT_IND_PS_MODE_ERROR:
-		dev_warn(wdev->dev, "error while processing power save request\n");
+		dev_warn(wdev->dev, "error while processing power save request: %d\n",
+			 body->event_data.ps_mode_error);
+		if (body->event_data.ps_mode_error ==
+		    HIF_PS_ERROR_AP_NOT_RESP_TO_POLL) {
+			wvif->bss_not_support_ps_poll = true;
+			schedule_work(&wvif->update_pm_work);
+		}
 		break;
 	default:
 		dev_warn(wdev->dev, "unhandled event indication: %.2x\n",
diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
index 2262e1de37f6..77d5ff17a59a 100644
--- a/drivers/staging/wfx/sta.c
+++ b/drivers/staging/wfx/sta.c
@@ -205,7 +205,10 @@  static int wfx_update_pm(struct wfx_vif *wvif)
 	if (chan0 && chan1 && chan0->hw_value != chan1->hw_value &&
 	    wvif->vif->type != NL80211_IFTYPE_AP) {
 		ps = true;
-		ps_timeout = 0;
+		if (wvif->bss_not_support_ps_poll)
+			ps_timeout = 30;
+		else
+			ps_timeout = 0;
 	}
 
 	if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete,
@@ -215,6 +218,14 @@  static int wfx_update_pm(struct wfx_vif *wvif)
 	return hif_set_pm(wvif, ps, ps_timeout);
 }
 
+static void wfx_update_pm_work(struct work_struct *work)
+{
+	struct wfx_vif *wvif = container_of(work, struct wfx_vif,
+					    update_pm_work);
+
+	wfx_update_pm(wvif);
+}
+
 int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		   u16 queue, const struct ieee80211_tx_queue_params *params)
 {
@@ -293,6 +304,7 @@  static void wfx_do_unjoin(struct wfx_vif *wvif)
 	if (wvif_count(wvif->wdev) <= 1)
 		hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
 	wfx_tx_unlock(wvif->wdev);
+	wvif->bss_not_support_ps_poll = false;
 	cancel_delayed_work_sync(&wvif->beacon_loss_work);
 }
 
@@ -453,6 +465,7 @@  void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 	wfx_tx_policy_init(wvif);
 	if (wvif_count(wvif->wdev) <= 1)
 		hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
+	wvif->bss_not_support_ps_poll = false;
 }
 
 static void wfx_join_finalize(struct wfx_vif *wvif,
@@ -737,6 +750,7 @@  int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
 	init_completion(&wvif->set_pm_mode_complete);
 	complete(&wvif->set_pm_mode_complete);
+	INIT_WORK(&wvif->update_pm_work, wfx_update_pm_work);
 	INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work);
 
 	mutex_init(&wvif->scan_lock);
diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index 77bb6c617546..c7a58ab3beaa 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -89,6 +89,8 @@  struct wfx_vif {
 	bool			scan_abort;
 	struct ieee80211_scan_request *scan_req;
 
+	bool			bss_not_support_ps_poll;
+	struct work_struct	update_pm_work;
 	struct completion	set_pm_mode_complete;
 };