diff options
-rw-r--r-- | drivers/net/wireless/ath/wil6210/cfg80211.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/p2p.c | 150 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wil6210.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wmi.c | 4 |
5 files changed, 149 insertions, 61 deletions
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 22078b0ffc8c..6aa3ff4240a9 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -354,14 +354,6 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, wil_dbg_misc(wil, "%s(), wdev=0x%p iftype=%d\n", __func__, wdev, wdev->iftype); - mutex_lock(&wil->p2p_wdev_mutex); - if (wil->scan_request) { - wil_err(wil, "Already scanning\n"); - mutex_unlock(&wil->p2p_wdev_mutex); - return -EAGAIN; - } - mutex_unlock(&wil->p2p_wdev_mutex); - /* check we are client side */ switch (wdev->iftype) { case NL80211_IFTYPE_STATION: @@ -378,12 +370,24 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, return -EBUSY; } + mutex_lock(&wil->mutex); + + mutex_lock(&wil->p2p_wdev_mutex); + if (wil->scan_request || wil->p2p.discovery_started) { + wil_err(wil, "Already scanning\n"); + mutex_unlock(&wil->p2p_wdev_mutex); + rc = -EAGAIN; + goto out; + } + mutex_unlock(&wil->p2p_wdev_mutex); + /* social scan on P2P_DEVICE is handled as p2p search */ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE && wil_p2p_is_social_scan(request)) { if (!wil->p2p.p2p_dev_started) { wil_err(wil, "P2P search requested on stopped P2P device\n"); - return -EIO; + rc = -EIO; + goto out; } wil->scan_request = request; wil->radio_wdev = wdev; @@ -392,7 +396,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, wil->radio_wdev = wil_to_wdev(wil); wil->scan_request = NULL; } - return rc; + goto out; } (void)wil_p2p_stop_discovery(wil); @@ -415,7 +419,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, if (rc) { wil_err(wil, "set SSID for scan request failed: %d\n", rc); - return rc; + goto out; } wil->scan_request = request; @@ -448,7 +452,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); if (rc) - goto out; + goto out_restore; if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) { cmd.cmd.discovery_mode = 1; @@ -459,13 +463,14 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); -out: +out_restore: if (rc) { del_timer_sync(&wil->scan_timer); wil->radio_wdev = wil_to_wdev(wil); wil->scan_request = NULL; } - +out: + mutex_unlock(&wil->mutex); return rc; } @@ -988,16 +993,8 @@ static int wil_remain_on_channel(struct wiphy *wiphy, wil_dbg_misc(wil, "%s() center_freq=%d, duration=%d iftype=%d\n", __func__, chan->center_freq, duration, wdev->iftype); - rc = wil_p2p_listen(wil, duration, chan, cookie); - if (rc) - return rc; - - wil->radio_wdev = wdev; - - cfg80211_ready_on_channel(wdev, *cookie, chan, duration, - GFP_KERNEL); - - return 0; + rc = wil_p2p_listen(wil, wdev, duration, chan, cookie); + return rc; } static int wil_cancel_remain_on_channel(struct wiphy *wiphy, diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 70f9c07749e3..e2e021bcaa03 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -518,6 +518,7 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); + INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work); INIT_LIST_HEAD(&wil->pending_wmi_ev); INIT_LIST_HEAD(&wil->probe_client_pending); @@ -579,6 +580,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->fw_error_worker); cancel_work_sync(&wil->p2p.discovery_expired_work); + cancel_work_sync(&wil->p2p.delayed_listen_work); mutex_lock(&wil->mutex); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); mutex_unlock(&wil->mutex); diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c index 4f0eab015a20..fbae99525e01 100644 --- a/drivers/net/wireless/ath/wil6210/p2p.c +++ b/drivers/net/wireless/ath/wil6210/p2p.c @@ -22,6 +22,43 @@ #define P2P_SEARCH_DURATION_MS 500 #define P2P_DEFAULT_BI 100 +static int wil_p2p_start_listen(struct wil6210_priv *wil) +{ + struct wil_p2p_info *p2p = &wil->p2p; + u8 channel = p2p->listen_chan.hw_value; + int rc; + + lockdep_assert_held(&wil->mutex); + + rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI); + if (rc) { + wil_err(wil, "wmi_p2p_cfg failed\n"); + goto out; + } + + rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); + if (rc) { + wil_err(wil, "wmi_set_ssid failed\n"); + goto out_stop; + } + + rc = wmi_start_listen(wil); + if (rc) { + wil_err(wil, "wmi_start_listen failed\n"); + goto out_stop; + } + + INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired); + mod_timer(&p2p->discovery_timer, + jiffies + msecs_to_jiffies(p2p->listen_duration)); +out_stop: + if (rc) + wmi_stop_discovery(wil); + +out: + return rc; +} + bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request) { return (request->n_channels == 1) && @@ -46,7 +83,7 @@ int wil_p2p_search(struct wil6210_priv *wil, wil_dbg_misc(wil, "%s: channel %d\n", __func__, P2P_DMG_SOCIAL_CHANNEL); - mutex_lock(&wil->mutex); + lockdep_assert_held(&wil->mutex); if (p2p->discovery_started) { wil_err(wil, "%s: search failed. discovery already ongoing\n", @@ -103,22 +140,19 @@ out_stop: wmi_stop_discovery(wil); out: - mutex_unlock(&wil->mutex); return rc; } -int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, - struct ieee80211_channel *chan, u64 *cookie) +int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, + unsigned int duration, struct ieee80211_channel *chan, + u64 *cookie) { struct wil_p2p_info *p2p = &wil->p2p; - u8 channel = P2P_DMG_SOCIAL_CHANNEL; int rc; if (!chan) return -EINVAL; - channel = chan->hw_value; - wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration); mutex_lock(&wil->mutex); @@ -129,35 +163,30 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, goto out; } - rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI); - if (rc) { - wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__); - goto out; - } - - rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); - if (rc) { - wil_err(wil, "%s: wmi_set_ssid failed\n", __func__); - goto out_stop; - } + memcpy(&p2p->listen_chan, chan, sizeof(*chan)); + *cookie = ++p2p->cookie; + p2p->listen_duration = duration; - rc = wmi_start_listen(wil); - if (rc) { - wil_err(wil, "%s: wmi_start_listen failed\n", __func__); - goto out_stop; + mutex_lock(&wil->p2p_wdev_mutex); + if (wil->scan_request) { + wil_dbg_misc(wil, "Delaying p2p listen until scan done\n"); + p2p->pending_listen_wdev = wdev; + p2p->discovery_started = 1; + rc = 0; + mutex_unlock(&wil->p2p_wdev_mutex); + goto out; } + mutex_unlock(&wil->p2p_wdev_mutex); - memcpy(&p2p->listen_chan, chan, sizeof(*chan)); - *cookie = ++p2p->cookie; + rc = wil_p2p_start_listen(wil); + if (rc) + goto out; p2p->discovery_started = 1; - INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired); - mod_timer(&p2p->discovery_timer, - jiffies + msecs_to_jiffies(duration)); + wil->radio_wdev = wdev; -out_stop: - if (rc) - wmi_stop_discovery(wil); + cfg80211_ready_on_channel(wdev, *cookie, chan, duration, + GFP_KERNEL); out: mutex_unlock(&wil->mutex); @@ -170,9 +199,14 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil) u8 started = p2p->discovery_started; if (p2p->discovery_started) { - del_timer_sync(&p2p->discovery_timer); + if (p2p->pending_listen_wdev) { + /* discovery not really started, only pending */ + p2p->pending_listen_wdev = NULL; + } else { + del_timer_sync(&p2p->discovery_timer); + wmi_stop_discovery(wil); + } p2p->discovery_started = 0; - wmi_stop_discovery(wil); } return started; @@ -257,11 +291,57 @@ void wil_p2p_search_expired(struct work_struct *work) }; mutex_lock(&wil->p2p_wdev_mutex); - cfg80211_scan_done(wil->scan_request, &info); - wil->scan_request = NULL; - wil->radio_wdev = wil->wdev; + if (wil->scan_request) { + cfg80211_scan_done(wil->scan_request, &info); + wil->scan_request = NULL; + wil->radio_wdev = wil->wdev; + } + mutex_unlock(&wil->p2p_wdev_mutex); + } +} + +void wil_p2p_delayed_listen_work(struct work_struct *work) +{ + struct wil_p2p_info *p2p = container_of(work, + struct wil_p2p_info, delayed_listen_work); + struct wil6210_priv *wil = container_of(p2p, + struct wil6210_priv, p2p); + int rc; + + mutex_lock(&wil->mutex); + + wil_dbg_misc(wil, "Checking delayed p2p listen\n"); + if (!p2p->discovery_started || !p2p->pending_listen_wdev) + goto out; + + mutex_lock(&wil->p2p_wdev_mutex); + if (wil->scan_request) { + /* another scan started, wait again... */ mutex_unlock(&wil->p2p_wdev_mutex); + goto out; } + mutex_unlock(&wil->p2p_wdev_mutex); + + rc = wil_p2p_start_listen(wil); + + mutex_lock(&wil->p2p_wdev_mutex); + if (rc) { + cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev, + p2p->cookie, + &p2p->listen_chan, + GFP_KERNEL); + wil->radio_wdev = wil->wdev; + } else { + cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie, + &p2p->listen_chan, + p2p->listen_duration, GFP_KERNEL); + wil->radio_wdev = p2p->pending_listen_wdev; + } + p2p->pending_listen_wdev = NULL; + mutex_unlock(&wil->p2p_wdev_mutex); + +out: + mutex_unlock(&wil->mutex); } void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b449f84bcc68..ef95db977bc6 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -461,8 +461,11 @@ struct wil_p2p_info { u8 discovery_started; u8 p2p_dev_started; u64 cookie; + struct wireless_dev *pending_listen_wdev; + unsigned int listen_duration; struct timer_list discovery_timer; /* listen/search duration */ struct work_struct discovery_expired_work; /* listen/search expire */ + struct work_struct delayed_listen_work; /* listen after scan done */ }; enum wil_sta_status { @@ -843,13 +846,15 @@ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request); void wil_p2p_discovery_timer_fn(ulong x); int wil_p2p_search(struct wil6210_priv *wil, struct cfg80211_scan_request *request); -int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, - struct ieee80211_channel *chan, u64 *cookie); +int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, + unsigned int duration, struct ieee80211_channel *chan, + u64 *cookie); u8 wil_p2p_stop_discovery(struct wil6210_priv *wil); int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie); void wil_p2p_listen_expired(struct work_struct *work); void wil_p2p_search_expired(struct work_struct *work); void wil_p2p_stop_radio_operations(struct wil6210_priv *wil); +void wil_p2p_delayed_listen_work(struct work_struct *work); /* WMI for P2P */ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 2971ddf0bc44..d289a4d999b7 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -441,6 +441,10 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, wil->radio_wdev = wil->wdev; wil->scan_request = NULL; wake_up_interruptible(&wil->wq); + if (wil->p2p.pending_listen_wdev) { + wil_dbg_misc(wil, "Scheduling delayed listen\n"); + schedule_work(&wil->p2p.delayed_listen_work); + } } else { wil_err(wil, "SCAN_COMPLETE while not scanning\n"); } |