wl1271: Add handling for failing hardware scan command

Currently, the driver does not handle a failing hardware command to scan in
any way - effectively, the scan machine will jam until the driver is shut down,
and future scan requests will just return -EBUSY to user space, resulting in
a type of busy-loop. The same problem occurs if the firmware fails to deliver
the scan completion event - add timeout for this.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
This commit is contained in:
Juuso Oikarinen 2010-09-21 06:23:32 +02:00 committed by Luciano Coelho
parent 52b0e7a61f
commit 78abd32074
4 changed files with 32 additions and 7 deletions

View File

@ -296,6 +296,7 @@ struct wl1271_rx_mem_pool_addr {
struct wl1271_scan {
struct cfg80211_scan_request *req;
bool *scanned_ch;
bool failed;
u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1];
size_t ssid_len;
@ -419,7 +420,7 @@ struct wl1271 {
/* Are we currently scanning */
struct wl1271_scan scan;
struct work_struct scan_complete_work;
struct delayed_work scan_complete_work;
/* Our association ID */
u16 aid;

View File

@ -657,8 +657,8 @@ static int wl1271_setup(struct wl1271 *wl)
INIT_WORK(&wl->irq_work, wl1271_irq_work);
INIT_WORK(&wl->tx_work, wl1271_tx_work);
INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
return 0;
}
@ -1013,7 +1013,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->scan_complete_work);
cancel_delayed_work_sync(&wl->scan_complete_work);
cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work);
cancel_delayed_work_sync(&wl->pspoll_work);

View File

@ -30,8 +30,11 @@
void wl1271_scan_complete_work(struct work_struct *work)
{
struct wl1271 *wl =
container_of(work, struct wl1271, scan_complete_work);
struct delayed_work *dwork;
struct wl1271 *wl;
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work);
wl1271_debug(DEBUG_SCAN, "Scanning complete");
@ -48,6 +51,11 @@ void wl1271_scan_complete_work(struct work_struct *work)
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
if (wl->scan.failed) {
wl1271_info("Scan completed due to error.");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
}
}
@ -191,7 +199,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
void wl1271_scan_stm(struct wl1271 *wl)
{
int ret;
int ret = 0;
switch (wl->scan.state) {
case WL1271_SCAN_STATE_IDLE:
@ -241,13 +249,22 @@ void wl1271_scan_stm(struct wl1271 *wl)
break;
case WL1271_SCAN_STATE_DONE:
ieee80211_queue_work(wl->hw, &wl->scan_complete_work);
wl->scan.failed = false;
cancel_delayed_work(&wl->scan_complete_work);
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(0));
break;
default:
wl1271_error("invalid scan state");
break;
}
if (ret < 0) {
cancel_delayed_work(&wl->scan_complete_work);
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(0));
}
}
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
@ -270,6 +287,11 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
wl->scan.scanned_ch = kzalloc(req->n_channels *
sizeof(*wl->scan.scanned_ch),
GFP_KERNEL);
/* we assume failure so that timeout scenarios are handled correctly */
wl->scan.failed = true;
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
wl1271_scan_stm(wl);
return 0;

View File

@ -46,6 +46,8 @@ void wl1271_scan_complete_work(struct work_struct *work);
#define WL1271_SCAN_BAND_5_GHZ 1
#define WL1271_SCAN_PROBE_REQS 3
#define WL1271_SCAN_TIMEOUT 10000 /* msec */
enum {
WL1271_SCAN_STATE_IDLE,
WL1271_SCAN_STATE_2GHZ_ACTIVE,