Commit 2afc0c5d authored by Dan Williams's avatar Dan Williams Committed by David S. Miller

[PATCH] libertas: push WEXT scan requests to a work queue

Push WEXT scan requests to a workqueue and have each partial scan queue
the next part, then only report results when the complete scan has finished.
Full scans don't go through the work queue.
Signed-off-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b031ac10
...@@ -17,7 +17,7 @@ static inline void wlan_postpone_association_work(wlan_private *priv) ...@@ -17,7 +17,7 @@ static inline void wlan_postpone_association_work(wlan_private *priv)
if (priv->adapter->surpriseremoved) if (priv->adapter->surpriseremoved)
return; return;
cancel_delayed_work(&priv->assoc_work); cancel_delayed_work(&priv->assoc_work);
queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY); queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY);
} }
static inline void wlan_cancel_association_work(wlan_private *priv) static inline void wlan_cancel_association_work(wlan_private *priv)
......
...@@ -148,9 +148,10 @@ struct _wlan_private { ...@@ -148,9 +148,10 @@ struct _wlan_private {
/** thread to service interrupts */ /** thread to service interrupts */
struct task_struct *main_thread; struct task_struct *main_thread;
wait_queue_head_t waitq; wait_queue_head_t waitq;
struct workqueue_struct *work_thread;
struct delayed_work scan_work;
struct delayed_work assoc_work; struct delayed_work assoc_work;
struct workqueue_struct *assoc_thread;
struct work_struct sync_channel; struct work_struct sync_channel;
/** Hardware access */ /** Hardware access */
......
...@@ -1269,9 +1269,10 @@ int libertas_activate_card(wlan_private *priv) ...@@ -1269,9 +1269,10 @@ int libertas_activate_card(wlan_private *priv)
goto done; goto done;
} }
priv->assoc_thread = priv->work_thread = create_singlethread_workqueue("libertas_worker");
create_singlethread_workqueue("libertas_assoc");
INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker);
INIT_WORK(&priv->sync_channel, libertas_sync_channel); INIT_WORK(&priv->sync_channel, libertas_sync_channel);
/* /*
...@@ -1305,7 +1306,7 @@ int libertas_activate_card(wlan_private *priv) ...@@ -1305,7 +1306,7 @@ int libertas_activate_card(wlan_private *priv)
err_init_fw: err_init_fw:
priv->hw_unregister_dev(priv); priv->hw_unregister_dev(priv);
err_registerdev: err_registerdev:
destroy_workqueue(priv->assoc_thread); destroy_workqueue(priv->work_thread);
/* Stop the thread servicing the interrupts */ /* Stop the thread servicing the interrupts */
wake_up_interruptible(&priv->waitq); wake_up_interruptible(&priv->waitq);
kthread_stop(priv->main_thread); kthread_stop(priv->main_thread);
...@@ -1426,8 +1427,9 @@ int libertas_remove_card(wlan_private *priv) ...@@ -1426,8 +1427,9 @@ int libertas_remove_card(wlan_private *priv)
unregister_netdev(dev); unregister_netdev(dev);
cancel_delayed_work(&priv->scan_work);
cancel_delayed_work(&priv->assoc_work); cancel_delayed_work(&priv->assoc_work);
destroy_workqueue(priv->assoc_thread); destroy_workqueue(priv->work_thread);
if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
adapter->psmode = WLAN802_11POWERMODECAM; adapter->psmode = WLAN802_11POWERMODECAM;
......
...@@ -314,6 +314,16 @@ static void wlan_scan_create_channel_list(wlan_private * priv, ...@@ -314,6 +314,16 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
} }
} }
/* Delayed partial scan worker */
void libertas_scan_worker(struct work_struct *work)
{
wlan_private *priv = container_of(work, wlan_private, scan_work.work);
wlan_scan_networks(priv, NULL, 0);
}
/** /**
* @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
* *
...@@ -408,7 +418,6 @@ wlan_scan_setup_scan_config(wlan_private * priv, ...@@ -408,7 +418,6 @@ wlan_scan_setup_scan_config(wlan_private * priv,
*pscancurrentonly = 0; *pscancurrentonly = 0;
if (puserscanin) { if (puserscanin) {
/* Set the bss type scan filter, use adapter setting if unset */ /* Set the bss type scan filter, use adapter setting if unset */
pscancfgout->bsstype = pscancfgout->bsstype =
puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY; puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
...@@ -468,59 +477,57 @@ wlan_scan_setup_scan_config(wlan_private * priv, ...@@ -468,59 +477,57 @@ wlan_scan_setup_scan_config(wlan_private * priv,
*/ */
*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
if (puserscanin && puserscanin->chanlist[0].channumber) { if (!puserscanin || !puserscanin->chanlist[0].channumber) {
/* Create a default channel scan list */
lbs_deb_scan("Scan: Creating full region channel list\n");
wlan_scan_create_channel_list(priv, pscanchanlist,
*pfilteredscan);
goto out;
}
lbs_deb_scan("Scan: Using supplied channel list\n"); lbs_deb_scan("Scan: Using supplied channel list\n");
for (chanidx = 0;
chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
&& puserscanin->chanlist[chanidx].channumber; chanidx++) {
for (chanidx = 0; channel = puserscanin->chanlist[chanidx].channumber;
chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX (pscanchanlist + chanidx)->channumber = channel;
&& puserscanin->chanlist[chanidx].channumber; chanidx++) {
channel = puserscanin->chanlist[chanidx].channumber; radiotype = puserscanin->chanlist[chanidx].radiotype;
(pscanchanlist + chanidx)->channumber = channel; (pscanchanlist + chanidx)->radiotype = radiotype;
radiotype = puserscanin->chanlist[chanidx].radiotype; scantype = puserscanin->chanlist[chanidx].scantype;
(pscanchanlist + chanidx)->radiotype = radiotype;
scantype = puserscanin->chanlist[chanidx].scantype; if (scantype == CMD_SCAN_TYPE_PASSIVE) {
(pscanchanlist +
chanidx)->chanscanmode.passivescan = 1;
} else {
(pscanchanlist +
chanidx)->chanscanmode.passivescan = 0;
}
if (puserscanin->chanlist[chanidx].scantime) {
scandur = puserscanin->chanlist[chanidx].scantime;
} else {
if (scantype == CMD_SCAN_TYPE_PASSIVE) { if (scantype == CMD_SCAN_TYPE_PASSIVE) {
(pscanchanlist + scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
chanidx)->chanscanmode.passivescan = 1;
} else {
(pscanchanlist +
chanidx)->chanscanmode.passivescan = 0;
}
if (puserscanin->chanlist[chanidx].scantime) {
scandur =
puserscanin->chanlist[chanidx].scantime;
} else { } else {
if (scantype == CMD_SCAN_TYPE_PASSIVE) { scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
} else {
scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
}
} }
(pscanchanlist + chanidx)->minscantime =
cpu_to_le16(scandur);
(pscanchanlist + chanidx)->maxscantime =
cpu_to_le16(scandur);
} }
/* Check if we are only scanning the current channel */ (pscanchanlist + chanidx)->minscantime =
if ((chanidx == 1) && (puserscanin->chanlist[0].channumber cpu_to_le16(scandur);
== (pscanchanlist + chanidx)->maxscantime =
priv->adapter->curbssparams.channel)) { cpu_to_le16(scandur);
*pscancurrentonly = 1; }
lbs_deb_scan("Scan: Scanning current channel only");
}
} else { /* Check if we are only scanning the current channel */
lbs_deb_scan("Scan: Creating full region channel list\n"); if ((chanidx == 1) &&
wlan_scan_create_channel_list(priv, pscanchanlist, (puserscanin->chanlist[0].channumber ==
*pfilteredscan); priv->adapter->curbssparams.channel)) {
*pscancurrentonly = 1;
lbs_deb_scan("Scan: Scanning current channel only");
} }
out: out:
...@@ -604,12 +611,12 @@ static int wlan_scan_channel_list(wlan_private * priv, ...@@ -604,12 +611,12 @@ static int wlan_scan_channel_list(wlan_private * priv,
while (tlvidx < maxchanperscan && ptmpchan->channumber while (tlvidx < maxchanperscan && ptmpchan->channumber
&& !doneearly && scanned < 2) { && !doneearly && scanned < 2) {
lbs_deb_scan( lbs_deb_scan("Scan: Chan(%3d), Radio(%d), mode(%d,%d), "
"Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n", "Dur(%d)\n",
ptmpchan->channumber, ptmpchan->radiotype, ptmpchan->channumber, ptmpchan->radiotype,
ptmpchan->chanscanmode.passivescan, ptmpchan->chanscanmode.passivescan,
ptmpchan->chanscanmode.disablechanfilt, ptmpchan->chanscanmode.disablechanfilt,
ptmpchan->maxscantime); ptmpchan->maxscantime);
/* Copy the current channel TLV to the command being prepared */ /* Copy the current channel TLV to the command being prepared */
memcpy(pchantlvout->chanscanparam + tlvidx, memcpy(pchantlvout->chanscanparam + tlvidx,
...@@ -678,9 +685,18 @@ static int wlan_scan_channel_list(wlan_private * priv, ...@@ -678,9 +685,18 @@ static int wlan_scan_channel_list(wlan_private * priv,
done: done:
priv->adapter->last_scanned_channel = ptmpchan->channumber; priv->adapter->last_scanned_channel = ptmpchan->channumber;
/* Tell userspace the scan table has been updated */ if (priv->adapter->last_scanned_channel) {
memset(&wrqu, 0, sizeof(union iwreq_data)); /* Schedule the next part of the partial scan */
wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); if (!full_scan && !priv->adapter->surpriseremoved) {
cancel_delayed_work(&priv->scan_work);
queue_delayed_work(priv->work_thread, &priv->scan_work,
msecs_to_jiffies(300));
}
} else {
/* All done, tell userspace the scan table has been updated */
memset(&wrqu, 0, sizeof(union iwreq_data));
wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
}
lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
return ret; return ret;
...@@ -747,8 +763,8 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, ...@@ -747,8 +763,8 @@ clear_selected_scan_list_entries(wlan_adapter * adapter,
* @return 0 or < 0 if error * @return 0 or < 0 if error
*/ */
int wlan_scan_networks(wlan_private * priv, int wlan_scan_networks(wlan_private * priv,
const struct wlan_ioctl_user_scan_cfg * puserscanin, const struct wlan_ioctl_user_scan_cfg * puserscanin,
int full_scan) int full_scan)
{ {
wlan_adapter * adapter = priv->adapter; wlan_adapter * adapter = priv->adapter;
struct mrvlietypes_chanlistparamset *pchantlvout; struct mrvlietypes_chanlistparamset *pchantlvout;
...@@ -763,7 +779,13 @@ int wlan_scan_networks(wlan_private * priv, ...@@ -763,7 +779,13 @@ int wlan_scan_networks(wlan_private * priv,
int i = 0; int i = 0;
#endif #endif
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_SCAN);
/* Cancel any partial outstanding partial scans if this scan
* is a full scan.
*/
if (full_scan && delayed_work_pending(&priv->scan_work))
cancel_delayed_work(&priv->scan_work);
scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
...@@ -1289,7 +1311,10 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, ...@@ -1289,7 +1311,10 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_SCAN); lbs_deb_enter(LBS_DEB_SCAN);
wlan_scan_networks(priv, NULL, 0); if (!delayed_work_pending(&priv->scan_work)) {
queue_delayed_work(priv->work_thread, &priv->scan_work,
msecs_to_jiffies(50));
}
if (adapter->surpriseremoved) if (adapter->surpriseremoved)
return -1; return -1;
...@@ -1508,10 +1533,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, ...@@ -1508,10 +1533,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
/* If we've got an uncompleted scan, schedule the next part */
if (!adapter->nr_cmd_pending && adapter->last_scanned_channel)
wlan_scan_networks(priv, NULL, 0);
/* Update RSSI if current BSS is a locally created ad-hoc BSS */ /* Update RSSI if current BSS is a locally created ad-hoc BSS */
if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
......
...@@ -210,4 +210,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, ...@@ -210,4 +210,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra); struct iw_param *vwrq, char *extra);
void libertas_scan_worker(struct work_struct *work);
#endif /* _WLAN_SCAN_H */ #endif /* _WLAN_SCAN_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment