Skip to content

Commit

Permalink
wl1271: Add handling for failing hardware scan command
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Juuso Oikarinen authored and Luciano Coelho committed Sep 28, 2010
1 parent 52b0e7a commit 78abd32
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 7 deletions.
3 changes: 2 additions & 1 deletion drivers/net/wireless/wl12xx/wl1271.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/wl12xx/wl1271_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
30 changes: 26 additions & 4 deletions drivers/net/wireless/wl12xx/wl1271_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand All @@ -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);
}
}


Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand All @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/wl12xx/wl1271_scan.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 78abd32

Please sign in to comment.