aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2007-10-09 13:55:24 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:55:06 -0400
commit0b5316769774d1dc2fdd702e095f9e6992af269a (patch)
treef8fc71978ab739b86295440fd67feef80aeddf1c /drivers
parent04dd9d39b48636d2698049304fdfb9ca59a88b54 (diff)
[PATCH] ipw2200: batch non-user-requested scan result notifications
ipw2200 makes extensive use of background scanning when unassociated or down. Unfortunately, the firmware sends scan completed events many times per second, which the driver pushes directly up to userspace. This needlessly wakes up processes listening for wireless events many times per second. Batch together scan completed events for non-user-requested scans and send them up to userspace every 4 seconds. Scan completed events resulting from an SIOCSIWSCAN call are pushed up without delay. Signed-off-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ipw2200.c56
-rw-r--r--drivers/net/wireless/ipw2200.h3
2 files changed, 49 insertions, 10 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 2119a79dcc86..feb8fcbab2d5 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1740,8 +1740,10 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
1740 if (disable_radio) { 1740 if (disable_radio) {
1741 priv->status |= STATUS_RF_KILL_SW; 1741 priv->status |= STATUS_RF_KILL_SW;
1742 1742
1743 if (priv->workqueue) 1743 if (priv->workqueue) {
1744 cancel_delayed_work(&priv->request_scan); 1744 cancel_delayed_work(&priv->request_scan);
1745 cancel_delayed_work(&priv->scan_event);
1746 }
1745 queue_work(priv->workqueue, &priv->down); 1747 queue_work(priv->workqueue, &priv->down);
1746 } else { 1748 } else {
1747 priv->status &= ~STATUS_RF_KILL_SW; 1749 priv->status &= ~STATUS_RF_KILL_SW;
@@ -1992,6 +1994,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
1992 wake_up_interruptible(&priv->wait_command_queue); 1994 wake_up_interruptible(&priv->wait_command_queue);
1993 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); 1995 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1994 cancel_delayed_work(&priv->request_scan); 1996 cancel_delayed_work(&priv->request_scan);
1997 cancel_delayed_work(&priv->scan_event);
1995 schedule_work(&priv->link_down); 1998 schedule_work(&priv->link_down);
1996 queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); 1999 queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
1997 handled |= IPW_INTA_BIT_RF_KILL_DONE; 2000 handled |= IPW_INTA_BIT_RF_KILL_DONE;
@@ -4343,6 +4346,37 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
4343 IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); 4346 IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
4344} 4347}
4345 4348
4349static void ipw_scan_event(struct work_struct *work)
4350{
4351 union iwreq_data wrqu;
4352
4353 struct ipw_priv *priv =
4354 container_of(work, struct ipw_priv, scan_event.work);
4355
4356 wrqu.data.length = 0;
4357 wrqu.data.flags = 0;
4358 wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
4359}
4360
4361static void handle_scan_event(struct ipw_priv *priv)
4362{
4363 /* Only userspace-requested scan completion events go out immediately */
4364 if (!priv->user_requested_scan) {
4365 if (!delayed_work_pending(&priv->scan_event))
4366 queue_delayed_work(priv->workqueue, &priv->scan_event,
4367 round_jiffies(msecs_to_jiffies(4000)));
4368 } else {
4369 union iwreq_data wrqu;
4370
4371 priv->user_requested_scan = 0;
4372 cancel_delayed_work(&priv->scan_event);
4373
4374 wrqu.data.length = 0;
4375 wrqu.data.flags = 0;
4376 wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
4377 }
4378}
4379
4346/** 4380/**
4347 * Handle host notification packet. 4381 * Handle host notification packet.
4348 * Called from interrupt routine 4382 * Called from interrupt routine
@@ -4705,14 +4739,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
4705 * on how the scan was initiated. User space can just 4739 * on how the scan was initiated. User space can just
4706 * sync on periodic scan to get fresh data... 4740 * sync on periodic scan to get fresh data...
4707 * Jean II */ 4741 * Jean II */
4708 if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) { 4742 if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
4709 union iwreq_data wrqu; 4743 handle_scan_event(priv);
4710
4711 wrqu.data.length = 0;
4712 wrqu.data.flags = 0;
4713 wireless_send_event(priv->net_dev, SIOCGIWSCAN,
4714 &wrqu, NULL);
4715 }
4716 break; 4744 break;
4717 } 4745 }
4718 4746
@@ -9490,6 +9518,10 @@ static int ipw_wx_set_scan(struct net_device *dev,
9490 struct ipw_priv *priv = ieee80211_priv(dev); 9518 struct ipw_priv *priv = ieee80211_priv(dev);
9491 struct iw_scan_req *req = (struct iw_scan_req *)extra; 9519 struct iw_scan_req *req = (struct iw_scan_req *)extra;
9492 9520
9521 mutex_lock(&priv->mutex);
9522 priv->user_requested_scan = 1;
9523 mutex_unlock(&priv->mutex);
9524
9493 if (wrqu->data.length == sizeof(struct iw_scan_req)) { 9525 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
9494 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { 9526 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
9495 ipw_request_direct_scan(priv, req->essid, 9527 ipw_request_direct_scan(priv, req->essid,
@@ -10668,6 +10700,7 @@ static void ipw_link_up(struct ipw_priv *priv)
10668 } 10700 }
10669 10701
10670 cancel_delayed_work(&priv->request_scan); 10702 cancel_delayed_work(&priv->request_scan);
10703 cancel_delayed_work(&priv->scan_event);
10671 ipw_reset_stats(priv); 10704 ipw_reset_stats(priv);
10672 /* Ensure the rate is updated immediately */ 10705 /* Ensure the rate is updated immediately */
10673 priv->last_rate = ipw_get_current_rate(priv); 10706 priv->last_rate = ipw_get_current_rate(priv);
@@ -10705,7 +10738,8 @@ static void ipw_link_down(struct ipw_priv *priv)
10705 if (!(priv->status & STATUS_EXIT_PENDING)) { 10738 if (!(priv->status & STATUS_EXIT_PENDING)) {
10706 /* Queue up another scan... */ 10739 /* Queue up another scan... */
10707 queue_delayed_work(priv->workqueue, &priv->request_scan, 0); 10740 queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
10708 } 10741 } else
10742 cancel_delayed_work(&priv->scan_event);
10709} 10743}
10710 10744
10711static void ipw_bg_link_down(struct work_struct *work) 10745static void ipw_bg_link_down(struct work_struct *work)
@@ -10735,6 +10769,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv)
10735 INIT_WORK(&priv->up, ipw_bg_up); 10769 INIT_WORK(&priv->up, ipw_bg_up);
10736 INIT_WORK(&priv->down, ipw_bg_down); 10770 INIT_WORK(&priv->down, ipw_bg_down);
10737 INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); 10771 INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
10772 INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
10738 INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan); 10773 INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
10739 INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); 10774 INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
10740 INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); 10775 INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
@@ -11766,6 +11801,7 @@ static void ipw_pci_remove(struct pci_dev *pdev)
11766 cancel_delayed_work(&priv->adhoc_check); 11801 cancel_delayed_work(&priv->adhoc_check);
11767 cancel_delayed_work(&priv->gather_stats); 11802 cancel_delayed_work(&priv->gather_stats);
11768 cancel_delayed_work(&priv->request_scan); 11803 cancel_delayed_work(&priv->request_scan);
11804 cancel_delayed_work(&priv->scan_event);
11769 cancel_delayed_work(&priv->rf_kill); 11805 cancel_delayed_work(&priv->rf_kill);
11770 cancel_delayed_work(&priv->scan_check); 11806 cancel_delayed_work(&priv->scan_check);
11771 destroy_workqueue(priv->workqueue); 11807 destroy_workqueue(priv->workqueue);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 9c973b96bb42..bec8e37a1738 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1287,6 +1287,8 @@ struct ipw_priv {
1287 1287
1288 struct iw_public_data wireless_data; 1288 struct iw_public_data wireless_data;
1289 1289
1290 int user_requested_scan;
1291
1290 struct workqueue_struct *workqueue; 1292 struct workqueue_struct *workqueue;
1291 1293
1292 struct delayed_work adhoc_check; 1294 struct delayed_work adhoc_check;
@@ -1295,6 +1297,7 @@ struct ipw_priv {
1295 struct work_struct system_config; 1297 struct work_struct system_config;
1296 struct work_struct rx_replenish; 1298 struct work_struct rx_replenish;
1297 struct delayed_work request_scan; 1299 struct delayed_work request_scan;
1300 struct delayed_work scan_event;
1298 struct work_struct request_passive_scan; 1301 struct work_struct request_passive_scan;
1299 struct work_struct adapter_restart; 1302 struct work_struct adapter_restart;
1300 struct delayed_work rf_kill; 1303 struct delayed_work rf_kill;