aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2006-03-16 13:46:29 -0500
committerJohn W. Linville <linville@tuxdriver.com>2006-03-23 16:13:58 -0500
commit9e75af30d529d54fc650586776c100d0665c0c93 (patch)
tree978006aea21e2ccfd133f9131b3b98e0b19d5325 /drivers
parent15db2763202b9479f3d30ea61a283be4fc48559d (diff)
[PATCH] wireless/airo: cache wireless scans
Observed problems when multiple processes request scans and subsequently scan results. This causes a scan result request to hit card registers before the scan is complete, returning an incomplete scan list and possibly making the card very angry. Instead, cache the results of a wireless scan and serve result requests from the cache, rather than hitting the hardware for them. 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/airo.c231
1 files changed, 172 insertions, 59 deletions
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 6f591abacfdc..108d9fed8f07 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -770,6 +770,11 @@ typedef struct {
770} BSSListRid; 770} BSSListRid;
771 771
772typedef struct { 772typedef struct {
773 BSSListRid bss;
774 struct list_head list;
775} BSSListElement;
776
777typedef struct {
773 u8 rssipct; 778 u8 rssipct;
774 u8 rssidBm; 779 u8 rssidBm;
775} tdsRssiEntry; 780} tdsRssiEntry;
@@ -1120,6 +1125,8 @@ static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket,
1120static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi); 1125static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
1121static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm); 1126static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
1122 1127
1128static void airo_networks_free(struct airo_info *ai);
1129
1123struct airo_info { 1130struct airo_info {
1124 struct net_device_stats stats; 1131 struct net_device_stats stats;
1125 struct net_device *dev; 1132 struct net_device *dev;
@@ -1151,7 +1158,7 @@ struct airo_info {
1151#define FLAG_COMMIT 13 1158#define FLAG_COMMIT 13
1152#define FLAG_RESET 14 1159#define FLAG_RESET 14
1153#define FLAG_FLASHING 15 1160#define FLAG_FLASHING 15
1154#define JOB_MASK 0x1ff0000 1161#define JOB_MASK 0x2ff0000
1155#define JOB_DIE 16 1162#define JOB_DIE 16
1156#define JOB_XMIT 17 1163#define JOB_XMIT 17
1157#define JOB_XMIT11 18 1164#define JOB_XMIT11 18
@@ -1161,6 +1168,7 @@ struct airo_info {
1161#define JOB_EVENT 22 1168#define JOB_EVENT 22
1162#define JOB_AUTOWEP 23 1169#define JOB_AUTOWEP 23
1163#define JOB_WSTATS 24 1170#define JOB_WSTATS 24
1171#define JOB_SCAN_RESULTS 25
1164 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, 1172 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
1165 int whichbap); 1173 int whichbap);
1166 unsigned short *flash; 1174 unsigned short *flash;
@@ -1177,7 +1185,7 @@ struct airo_info {
1177 } xmit, xmit11; 1185 } xmit, xmit11;
1178 struct net_device *wifidev; 1186 struct net_device *wifidev;
1179 struct iw_statistics wstats; // wireless stats 1187 struct iw_statistics wstats; // wireless stats
1180 unsigned long scan_timestamp; /* Time started to scan */ 1188 unsigned long scan_timeout; /* Time scan should be read */
1181 struct iw_spy_data spy_data; 1189 struct iw_spy_data spy_data;
1182 struct iw_public_data wireless_data; 1190 struct iw_public_data wireless_data;
1183 /* MIC stuff */ 1191 /* MIC stuff */
@@ -1199,6 +1207,10 @@ struct airo_info {
1199 APListRid *APList; 1207 APListRid *APList;
1200#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE 1208#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
1201 char proc_name[IFNAMSIZ]; 1209 char proc_name[IFNAMSIZ];
1210
1211 struct list_head network_list;
1212 struct list_head network_free_list;
1213 BSSListElement *networks;
1202}; 1214};
1203 1215
1204static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, 1216static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
@@ -2381,6 +2393,8 @@ void stop_airo_card( struct net_device *dev, int freeres )
2381 dev_kfree_skb(skb); 2393 dev_kfree_skb(skb);
2382 } 2394 }
2383 2395
2396 airo_networks_free (ai);
2397
2384 kfree(ai->flash); 2398 kfree(ai->flash);
2385 kfree(ai->rssi); 2399 kfree(ai->rssi);
2386 kfree(ai->APList); 2400 kfree(ai->APList);
@@ -2687,6 +2701,42 @@ static int reset_card( struct net_device *dev , int lock) {
2687 return 0; 2701 return 0;
2688} 2702}
2689 2703
2704#define MAX_NETWORK_COUNT 64
2705static int airo_networks_allocate(struct airo_info *ai)
2706{
2707 if (ai->networks)
2708 return 0;
2709
2710 ai->networks =
2711 kzalloc(MAX_NETWORK_COUNT * sizeof(BSSListElement),
2712 GFP_KERNEL);
2713 if (!ai->networks) {
2714 airo_print_warn(ai->dev->name, "Out of memory allocating beacons");
2715 return -ENOMEM;
2716 }
2717
2718 return 0;
2719}
2720
2721static void airo_networks_free(struct airo_info *ai)
2722{
2723 if (!ai->networks)
2724 return;
2725 kfree(ai->networks);
2726 ai->networks = NULL;
2727}
2728
2729static void airo_networks_initialize(struct airo_info *ai)
2730{
2731 int i;
2732
2733 INIT_LIST_HEAD(&ai->network_free_list);
2734 INIT_LIST_HEAD(&ai->network_list);
2735 for (i = 0; i < MAX_NETWORK_COUNT; i++)
2736 list_add_tail(&ai->networks[i].list,
2737 &ai->network_free_list);
2738}
2739
2690static struct net_device *_init_airo_card( unsigned short irq, int port, 2740static struct net_device *_init_airo_card( unsigned short irq, int port,
2691 int is_pcmcia, struct pci_dev *pci, 2741 int is_pcmcia, struct pci_dev *pci,
2692 struct device *dmdev ) 2742 struct device *dmdev )
@@ -2728,6 +2778,10 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
2728 if (rc) 2778 if (rc)
2729 goto err_out_thr; 2779 goto err_out_thr;
2730 2780
2781 if (airo_networks_allocate (ai))
2782 goto err_out_unlink;
2783 airo_networks_initialize (ai);
2784
2731 /* The Airo-specific entries in the device structure. */ 2785 /* The Airo-specific entries in the device structure. */
2732 if (test_bit(FLAG_MPI,&ai->flags)) { 2786 if (test_bit(FLAG_MPI,&ai->flags)) {
2733 skb_queue_head_init (&ai->txq); 2787 skb_queue_head_init (&ai->txq);
@@ -2749,7 +2803,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
2749 2803
2750 SET_NETDEV_DEV(dev, dmdev); 2804 SET_NETDEV_DEV(dev, dmdev);
2751 2805
2752
2753 reset_card (dev, 1); 2806 reset_card (dev, 1);
2754 msleep(400); 2807 msleep(400);
2755 2808
@@ -2892,6 +2945,65 @@ static void airo_send_event(struct net_device *dev) {
2892 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 2945 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
2893} 2946}
2894 2947
2948static void airo_process_scan_results (struct airo_info *ai) {
2949 union iwreq_data wrqu;
2950 BSSListRid BSSList;
2951 int rc;
2952 BSSListElement * loop_net;
2953 BSSListElement * tmp_net;
2954
2955 /* Blow away current list of scan results */
2956 list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) {
2957 list_move_tail (&loop_net->list, &ai->network_free_list);
2958 /* Don't blow away ->list, just BSS data */
2959 memset (loop_net, 0, sizeof (loop_net->bss));
2960 }
2961
2962 /* Try to read the first entry of the scan result */
2963 rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 0);
2964 if((rc) || (BSSList.index == 0xffff)) {
2965 /* No scan results */
2966 goto out;
2967 }
2968
2969 /* Read and parse all entries */
2970 tmp_net = NULL;
2971 while((!rc) && (BSSList.index != 0xffff)) {
2972 /* Grab a network off the free list */
2973 if (!list_empty(&ai->network_free_list)) {
2974 tmp_net = list_entry(ai->network_free_list.next,
2975 BSSListElement, list);
2976 list_del(ai->network_free_list.next);
2977 }
2978
2979 if (tmp_net != NULL) {
2980 memcpy(tmp_net, &BSSList, sizeof(tmp_net->bss));
2981 list_add_tail(&tmp_net->list, &ai->network_list);
2982 tmp_net = NULL;
2983 }
2984
2985 /* Read next entry */
2986 rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
2987 &BSSList, sizeof(BSSList), 0);
2988 }
2989
2990out:
2991 ai->scan_timeout = 0;
2992 clear_bit(JOB_SCAN_RESULTS, &ai->flags);
2993 up(&ai->sem);
2994
2995 /* Send an empty event to user space.
2996 * We don't send the received data on
2997 * the event because it would require
2998 * us to do complex transcoding, and
2999 * we want to minimise the work done in
3000 * the irq handler. Use a request to
3001 * extract the data - Jean II */
3002 wrqu.data.length = 0;
3003 wrqu.data.flags = 0;
3004 wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
3005}
3006
2895static int airo_thread(void *data) { 3007static int airo_thread(void *data) {
2896 struct net_device *dev = data; 3008 struct net_device *dev = data;
2897 struct airo_info *ai = dev->priv; 3009 struct airo_info *ai = dev->priv;
@@ -2921,13 +3033,26 @@ static int airo_thread(void *data) {
2921 set_current_state(TASK_INTERRUPTIBLE); 3033 set_current_state(TASK_INTERRUPTIBLE);
2922 if (ai->flags & JOB_MASK) 3034 if (ai->flags & JOB_MASK)
2923 break; 3035 break;
2924 if (ai->expires) { 3036 if (ai->expires || ai->scan_timeout) {
2925 if (time_after_eq(jiffies,ai->expires)){ 3037 if (ai->scan_timeout &&
3038 time_after_eq(jiffies,ai->scan_timeout)){
3039 set_bit(JOB_SCAN_RESULTS,&ai->flags);
3040 break;
3041 } else if (ai->expires &&
3042 time_after_eq(jiffies,ai->expires)){
2926 set_bit(JOB_AUTOWEP,&ai->flags); 3043 set_bit(JOB_AUTOWEP,&ai->flags);
2927 break; 3044 break;
2928 } 3045 }
2929 if (!signal_pending(current)) { 3046 if (!signal_pending(current)) {
2930 schedule_timeout(ai->expires - jiffies); 3047 unsigned long wake_at;
3048 if (!ai->expires || !ai->scan_timeout) {
3049 wake_at = max(ai->expires,
3050 ai->scan_timeout);
3051 } else {
3052 wake_at = min(ai->expires,
3053 ai->scan_timeout);
3054 }
3055 schedule_timeout(wake_at - jiffies);
2931 continue; 3056 continue;
2932 } 3057 }
2933 } else if (!signal_pending(current)) { 3058 } else if (!signal_pending(current)) {
@@ -2970,6 +3095,10 @@ static int airo_thread(void *data) {
2970 airo_send_event(dev); 3095 airo_send_event(dev);
2971 else if (test_bit(JOB_AUTOWEP, &ai->flags)) 3096 else if (test_bit(JOB_AUTOWEP, &ai->flags))
2972 timer_func(dev); 3097 timer_func(dev);
3098 else if (test_bit(JOB_SCAN_RESULTS, &ai->flags))
3099 airo_process_scan_results(ai);
3100 else /* Shouldn't get here, but we make sure to unlock */
3101 up(&ai->sem);
2973 } 3102 }
2974 complete_and_exit (&ai->thr_exited, 0); 3103 complete_and_exit (&ai->thr_exited, 0);
2975} 3104}
@@ -3064,19 +3193,15 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
3064 * and reassociations as valid status 3193 * and reassociations as valid status
3065 * Jean II */ 3194 * Jean II */
3066 if(newStatus == ASSOCIATED) { 3195 if(newStatus == ASSOCIATED) {
3067 if (apriv->scan_timestamp) { 3196#if 0
3068 /* Send an empty event to user space. 3197 /* FIXME: Grabbing scan results here
3069 * We don't send the received data on 3198 * seems to be too early??? Just wait for
3070 * the event because it would require 3199 * timeout instead. */
3071 * us to do complex transcoding, and 3200 if (apriv->scan_timeout > 0) {
3072 * we want to minimise the work done in 3201 set_bit(JOB_SCAN_RESULTS, &apriv->flags);
3073 * the irq handler. Use a request to 3202 wake_up_interruptible(&apriv->thr_wait);
3074 * extract the data - Jean II */
3075 wrqu.data.length = 0;
3076 wrqu.data.flags = 0;
3077 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
3078 apriv->scan_timestamp = 0;
3079 } 3203 }
3204#endif
3080 if (down_trylock(&apriv->sem) != 0) { 3205 if (down_trylock(&apriv->sem) != 0) {
3081 set_bit(JOB_EVENT, &apriv->flags); 3206 set_bit(JOB_EVENT, &apriv->flags);
3082 wake_up_interruptible(&apriv->thr_wait); 3207 wake_up_interruptible(&apriv->thr_wait);
@@ -6992,6 +7117,7 @@ static int airo_set_scan(struct net_device *dev,
6992 struct airo_info *ai = dev->priv; 7117 struct airo_info *ai = dev->priv;
6993 Cmd cmd; 7118 Cmd cmd;
6994 Resp rsp; 7119 Resp rsp;
7120 int wake = 0;
6995 7121
6996 /* Note : you may have realised that, as this is a SET operation, 7122 /* Note : you may have realised that, as this is a SET operation,
6997 * this is privileged and therefore a normal user can't 7123 * this is privileged and therefore a normal user can't
@@ -7001,17 +7127,25 @@ static int airo_set_scan(struct net_device *dev,
7001 * Jean II */ 7127 * Jean II */
7002 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; 7128 if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
7003 7129
7130 if (down_interruptible(&ai->sem))
7131 return -ERESTARTSYS;
7132
7133 /* If there's already a scan in progress, don't
7134 * trigger another one. */
7135 if (ai->scan_timeout > 0)
7136 goto out;
7137
7004 /* Initiate a scan command */ 7138 /* Initiate a scan command */
7005 memset(&cmd, 0, sizeof(cmd)); 7139 memset(&cmd, 0, sizeof(cmd));
7006 cmd.cmd=CMD_LISTBSS; 7140 cmd.cmd=CMD_LISTBSS;
7007 if (down_interruptible(&ai->sem))
7008 return -ERESTARTSYS;
7009 issuecommand(ai, &cmd, &rsp); 7141 issuecommand(ai, &cmd, &rsp);
7010 ai->scan_timestamp = jiffies; 7142 ai->scan_timeout = RUN_AT(3*HZ);
7011 up(&ai->sem); 7143 wake = 1;
7012
7013 /* At this point, just return to the user. */
7014 7144
7145out:
7146 up(&ai->sem);
7147 if (wake)
7148 wake_up_interruptible(&ai->thr_wait);
7015 return 0; 7149 return 0;
7016} 7150}
7017 7151
@@ -7131,59 +7265,38 @@ static int airo_get_scan(struct net_device *dev,
7131 char *extra) 7265 char *extra)
7132{ 7266{
7133 struct airo_info *ai = dev->priv; 7267 struct airo_info *ai = dev->priv;
7134 BSSListRid BSSList; 7268 BSSListElement *net;
7135 int rc; 7269 int err = 0;
7136 char *current_ev = extra; 7270 char *current_ev = extra;
7137 7271
7138 /* When we are associated again, the scan has surely finished. 7272 /* If a scan is in-progress, return -EAGAIN */
7139 * Just in case, let's make sure enough time has elapsed since 7273 if (ai->scan_timeout > 0)
7140 * we started the scan. - Javier */
7141 if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) {
7142 /* Important note : we don't want to block the caller
7143 * until results are ready for various reasons.
7144 * First, managing wait queues is complex and racy
7145 * (there may be multiple simultaneous callers).
7146 * Second, we grab some rtnetlink lock before comming
7147 * here (in dev_ioctl()).
7148 * Third, the caller can wait on the Wireless Event
7149 * - Jean II */
7150 return -EAGAIN; 7274 return -EAGAIN;
7151 }
7152 ai->scan_timestamp = 0;
7153
7154 /* There's only a race with proc_BSSList_open(), but its
7155 * consequences are begnign. So I don't bother fixing it - Javier */
7156 7275
7157 /* Try to read the first entry of the scan result */ 7276 if (down_interruptible(&ai->sem))
7158 rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1); 7277 return -EAGAIN;
7159 if((rc) || (BSSList.index == 0xffff)) {
7160 /* Client error, no scan results...
7161 * The caller need to restart the scan. */
7162 return -ENODATA;
7163 }
7164 7278
7165 /* Read and parse all entries */ 7279 list_for_each_entry (net, &ai->network_list, list) {
7166 while((!rc) && (BSSList.index != 0xffff)) {
7167 /* Translate to WE format this entry */ 7280 /* Translate to WE format this entry */
7168 current_ev = airo_translate_scan(dev, current_ev, 7281 current_ev = airo_translate_scan(dev, current_ev,
7169 extra + dwrq->length, 7282 extra + dwrq->length,
7170 &BSSList); 7283 &net->bss);
7171 7284
7172 /* Check if there is space for one more entry */ 7285 /* Check if there is space for one more entry */
7173 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { 7286 if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
7174 /* Ask user space to try again with a bigger buffer */ 7287 /* Ask user space to try again with a bigger buffer */
7175 return -E2BIG; 7288 err = -E2BIG;
7289 goto out;
7176 } 7290 }
7177
7178 /* Read next entry */
7179 rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
7180 &BSSList, sizeof(BSSList), 1);
7181 } 7291 }
7292
7182 /* Length of data */ 7293 /* Length of data */
7183 dwrq->length = (current_ev - extra); 7294 dwrq->length = (current_ev - extra);
7184 dwrq->flags = 0; /* todo */ 7295 dwrq->flags = 0; /* todo */
7185 7296
7186 return 0; 7297out:
7298 up(&ai->sem);
7299 return err;
7187} 7300}
7188 7301
7189/*------------------------------------------------------------------*/ 7302/*------------------------------------------------------------------*/