staging: wfx: fix support for AP that do not support PS-Poll
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> Link: https://lore.kernel.org/r/20200427134031.323403-5-Jerome.Pouiller@silabs.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
7acf88f864
commit
dd5eba1bb5
@@ -176,7 +176,13 @@ static int hif_event_indication(struct wfx_dev *wdev,
|
|||||||
dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n");
|
dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n");
|
||||||
break;
|
break;
|
||||||
case HIF_EVENT_IND_PS_MODE_ERROR:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_warn(wdev->dev, "unhandled event indication: %.2x\n",
|
dev_warn(wdev->dev, "unhandled event indication: %.2x\n",
|
||||||
|
|||||||
@@ -205,7 +205,10 @@ static int wfx_update_pm(struct wfx_vif *wvif)
|
|||||||
if (chan0 && chan1 && chan0->hw_value != chan1->hw_value &&
|
if (chan0 && chan1 && chan0->hw_value != chan1->hw_value &&
|
||||||
wvif->vif->type != NL80211_IFTYPE_AP) {
|
wvif->vif->type != NL80211_IFTYPE_AP) {
|
||||||
ps = true;
|
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,
|
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);
|
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,
|
int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
u16 queue, const struct ieee80211_tx_queue_params *params)
|
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)
|
if (wvif_count(wvif->wdev) <= 1)
|
||||||
hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
|
hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
|
||||||
wfx_tx_unlock(wvif->wdev);
|
wfx_tx_unlock(wvif->wdev);
|
||||||
|
wvif->bss_not_support_ps_poll = false;
|
||||||
cancel_delayed_work_sync(&wvif->beacon_loss_work);
|
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);
|
wfx_tx_policy_init(wvif);
|
||||||
if (wvif_count(wvif->wdev) <= 1)
|
if (wvif_count(wvif->wdev) <= 1)
|
||||||
hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
|
hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
|
||||||
|
wvif->bss_not_support_ps_poll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wfx_join_finalize(struct wfx_vif *wvif,
|
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);
|
init_completion(&wvif->set_pm_mode_complete);
|
||||||
complete(&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);
|
INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work);
|
||||||
|
|
||||||
mutex_init(&wvif->scan_lock);
|
mutex_init(&wvif->scan_lock);
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ struct wfx_vif {
|
|||||||
bool scan_abort;
|
bool scan_abort;
|
||||||
struct ieee80211_scan_request *scan_req;
|
struct ieee80211_scan_request *scan_req;
|
||||||
|
|
||||||
|
bool bss_not_support_ps_poll;
|
||||||
|
struct work_struct update_pm_work;
|
||||||
struct completion set_pm_mode_complete;
|
struct completion set_pm_mode_complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user