linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] airo driver: fix races, oops, etc..
@ 2003-07-29 13:02 Benjamin Herrenschmidt
  2003-08-05  8:53 ` Javier Achirica
  0 siblings, 1 reply; 8+ messages in thread
From: Benjamin Herrenschmidt @ 2003-07-29 13:02 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: achirica, linux-kernel mailing list

Hi !

Here's a patch against Linus current airo.c, it adds back some fixes I
did during OLS on the previous version of this driver. I couldn't test
this new 'fixed' version though as I don't have the airo card anymore:

 - Initialize the work_struct structures used by the driver
 - Change most of schedule_work() to schedule_delayed_work(). The
   problem with schedule_work() is that the worker_thread will never
   schedule() if the work keeps getting added back to the list by the
   callback, which typically happened with this driver when the xmit
   work gets scheduled while the semaphore was used by a pending
   command. Note that -ac tree has a modified version of this driver
   that gets rid of this "over-smart" work queue stuff and uses normal
   spinlock instead, probably at the expense of some latency...
 - Fix a small signed vs. unsigned char issue
 - Remove bogus pci_module_init(), use pci_register_driver() instead and
   add missing pci_unregister_driver() so the module can now be removed
   without leaving stale references (and thus avoid an oops next time
   the driver list is walked by the device core).

Jeff, if you are ok with these, please send to Linus,

Ben


diff -urN linux-2.5/drivers/net/wireless/airo.c linuxppc-2.5-benh/drivers/net/wireless/airo.c
--- linux-2.5/drivers/net/wireless/airo.c	2003-07-29 08:51:06.000000000 -0400
+++ linuxppc-2.5-benh/drivers/net/wireless/airo.c	2003-07-29 08:54:26.000000000 -0400
@@ -633,7 +633,7 @@
 	u16 SSIDlen;
 	char SSID[32];
 	char apName[16];
-	char bssid[4][ETH_ALEN];
+	unsigned char bssid[4][ETH_ALEN];
 	u16 beaconPeriod;
 	u16 dimPeriod;
 	u16 atimDuration;
@@ -1031,7 +1031,7 @@
 	struct work_struct promisc_task;
 	struct {
 		struct sk_buff *skb;
-		int fid;
+		int fid, hardirq;
 		struct work_struct task;
 	} xmit, xmit11;
 	struct net_device *wifidev;
@@ -1348,7 +1348,12 @@
 		netif_stop_queue(dev);
 		priv->xmit.task.func = (void (*)(void *))airo_do_xmit;
 		priv->xmit.task.data = (void *)dev;
-		schedule_work(&priv->xmit.task);
+		if (priv->xmit.hardirq) {
+			priv->xmit.hardirq = 0;
+			schedule_work(&priv->xmit.task);
+			return;
+		}
+		schedule_delayed_work(&priv->xmit.task, 1);
 		return;
 	}
 	status = transmit_802_3_packet (priv, fids[fid], skb->data);
@@ -1393,6 +1398,7 @@
 		fids[i] |= (len << 16);
 		priv->xmit.skb = skb;
 		priv->xmit.fid = i;
+		priv->xmit.hardirq = 1;
 		airo_do_xmit(dev);
 	}
 	return 0;
@@ -1410,7 +1416,12 @@
 		netif_stop_queue(dev);
 		priv->xmit11.task.func = (void (*)(void *))airo_do_xmit11;
 		priv->xmit11.task.data = (void *)dev;
-		schedule_work(&priv->xmit11.task);
+		if (priv->xmit11.hardirq) {
+			priv->xmit11.hardirq = 0;
+			schedule_work(&priv->xmit11.task);
+			return;
+		}
+		schedule_delayed_work(&priv->xmit11.task, 1);
 		return;
 	}
 	status = transmit_802_11_packet (priv, fids[fid], skb->data);
@@ -1485,7 +1496,7 @@
 	} else {
 		ai->stats_task.func = (void (*)(void *))airo_read_stats;
 		ai->stats_task.data = (void *)ai;
-		schedule_work(&ai->stats_task);
+		schedule_delayed_work(&ai->stats_task, 1);
 	}
 }
 
@@ -1508,7 +1519,7 @@
 	} else {
 		ai->promisc_task.func = (void (*)(void *))airo_end_promisc;
 		ai->promisc_task.data = (void *)ai;
-		schedule_work(&ai->promisc_task);
+		schedule_delayed_work(&ai->promisc_task, 1);
 	}
 }
 
@@ -1524,7 +1535,7 @@
 	} else {
 		ai->promisc_task.func = (void (*)(void *))airo_set_promisc;
 		ai->promisc_task.data = (void *)ai;
-		schedule_work(&ai->promisc_task);
+		schedule_delayed_work(&ai->promisc_task, 1);
 	}
 }
 
@@ -1710,6 +1721,14 @@
 	sema_init(&ai->sem, 1);
 	ai->need_commit = 0;
 	ai->config.len = 0;
+	INIT_WORK(&ai->stats_task, NULL, NULL);
+	INIT_WORK(&ai->promisc_task, NULL, NULL);
+	INIT_WORK(&ai->xmit.task, NULL, NULL);
+	INIT_WORK(&ai->xmit11.task, NULL, NULL);
+	INIT_WORK(&ai->mic_task, NULL, NULL);
+#ifdef WIRELESS_EXT
+	INIT_WORK(&ai->event_task, NULL, NULL);
+#endif
 	rc = add_airo_dev( dev );
 	if (rc)
 		goto err_out_free;
@@ -1859,7 +1878,7 @@
 	} else {
 		ai->event_task.func = (void (*)(void *))airo_send_event;
 		ai->event_task.data = (void *)dev;
-		schedule_work(&ai->event_task);
+		schedule_delayed_work(&ai->event_task, 1);
 	}
 }
 #endif
@@ -1876,7 +1895,7 @@
 	} else {
 		ai->mic_task.func = (void (*)(void *))airo_read_mic;
 		ai->mic_task.data = (void *)ai;
-		schedule_work(&ai->mic_task);
+		schedule_delayed_work(&ai->mic_task, 1);
 	}
 }
 
@@ -4090,7 +4109,7 @@
 
 #ifdef CONFIG_PCI
 	printk( KERN_INFO "airo:  Probing for PCI adapters\n" );
-	rc = pci_module_init(&airo_driver);
+	rc = pci_register_driver(&airo_driver);
 	printk( KERN_INFO "airo:  Finished probing for PCI adapters\n" );
 #endif
 
@@ -4102,6 +4121,7 @@
 
 static void __exit airo_cleanup_module( void )
 {
+	pci_unregister_driver(&airo_driver);
 	while( airo_devices ) {
 		printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
 		stop_airo_card( airo_devices->dev, 1 );
@@ -5160,7 +5180,7 @@
 			      & status_rid.bssid[i][2]
 			      & status_rid.bssid[i][3]
 			      & status_rid.bssid[i][4]
-			      & status_rid.bssid[i][5])!=-1 &&
+			      & status_rid.bssid[i][5])!=0xff &&
 			     (status_rid.bssid[i][0]
 			      | status_rid.bssid[i][1]
 			      | status_rid.bssid[i][2]


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] airo driver: fix races, oops, etc..
  2003-07-29 13:02 [PATCH] airo driver: fix races, oops, etc Benjamin Herrenschmidt
@ 2003-08-05  8:53 ` Javier Achirica
  2003-08-05  9:48   ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 8+ messages in thread
From: Javier Achirica @ 2003-08-05  8:53 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Jeff Garzik, linux-kernel mailing list


I've integrated this patch in my code. I've done a major change: Instead
of using schedule_delayed_work(), I create a new workqueue and use
queue_work() on that queue. As all tasks sleep in the same lock, I can
queue them there and make them sleep instead of requeueing them.

I haven't sent them to Jeff yet, as I want to do more testing. If you want
to help testing them, please tell me.

Javier Achirica

On 29 Jul 2003, Benjamin Herrenschmidt wrote:

> Hi !
>
> Here's a patch against Linus current airo.c, it adds back some fixes I
> did during OLS on the previous version of this driver. I couldn't test
> this new 'fixed' version though as I don't have the airo card anymore:
>
>  - Initialize the work_struct structures used by the driver
>  - Change most of schedule_work() to schedule_delayed_work(). The
>    problem with schedule_work() is that the worker_thread will never
>    schedule() if the work keeps getting added back to the list by the
>    callback, which typically happened with this driver when the xmit
>    work gets scheduled while the semaphore was used by a pending
>    command. Note that -ac tree has a modified version of this driver
>    that gets rid of this "over-smart" work queue stuff and uses normal
>    spinlock instead, probably at the expense of some latency...
>  - Fix a small signed vs. unsigned char issue
>  - Remove bogus pci_module_init(), use pci_register_driver() instead and
>    add missing pci_unregister_driver() so the module can now be removed
>    without leaving stale references (and thus avoid an oops next time
>    the driver list is walked by the device core).
>
> Jeff, if you are ok with these, please send to Linus,
>
> Ben
>
>
> diff -urN linux-2.5/drivers/net/wireless/airo.c linuxppc-2.5-benh/drivers/net/wireless/airo.c
> --- linux-2.5/drivers/net/wireless/airo.c	2003-07-29 08:51:06.000000000 -0400
> +++ linuxppc-2.5-benh/drivers/net/wireless/airo.c	2003-07-29 08:54:26.000000000 -0400
> @@ -633,7 +633,7 @@
>  	u16 SSIDlen;
>  	char SSID[32];
>  	char apName[16];
> -	char bssid[4][ETH_ALEN];
> +	unsigned char bssid[4][ETH_ALEN];
>  	u16 beaconPeriod;
>  	u16 dimPeriod;
>  	u16 atimDuration;
> @@ -1031,7 +1031,7 @@
>  	struct work_struct promisc_task;
>  	struct {
>  		struct sk_buff *skb;
> -		int fid;
> +		int fid, hardirq;
>  		struct work_struct task;
>  	} xmit, xmit11;
>  	struct net_device *wifidev;
> @@ -1348,7 +1348,12 @@
>  		netif_stop_queue(dev);
>  		priv->xmit.task.func = (void (*)(void *))airo_do_xmit;
>  		priv->xmit.task.data = (void *)dev;
> -		schedule_work(&priv->xmit.task);
> +		if (priv->xmit.hardirq) {
> +			priv->xmit.hardirq = 0;
> +			schedule_work(&priv->xmit.task);
> +			return;
> +		}
> +		schedule_delayed_work(&priv->xmit.task, 1);
>  		return;
>  	}
>  	status = transmit_802_3_packet (priv, fids[fid], skb->data);
> @@ -1393,6 +1398,7 @@
>  		fids[i] |= (len << 16);
>  		priv->xmit.skb = skb;
>  		priv->xmit.fid = i;
> +		priv->xmit.hardirq = 1;
>  		airo_do_xmit(dev);
>  	}
>  	return 0;
> @@ -1410,7 +1416,12 @@
>  		netif_stop_queue(dev);
>  		priv->xmit11.task.func = (void (*)(void *))airo_do_xmit11;
>  		priv->xmit11.task.data = (void *)dev;
> -		schedule_work(&priv->xmit11.task);
> +		if (priv->xmit11.hardirq) {
> +			priv->xmit11.hardirq = 0;
> +			schedule_work(&priv->xmit11.task);
> +			return;
> +		}
> +		schedule_delayed_work(&priv->xmit11.task, 1);
>  		return;
>  	}
>  	status = transmit_802_11_packet (priv, fids[fid], skb->data);
> @@ -1485,7 +1496,7 @@
>  	} else {
>  		ai->stats_task.func = (void (*)(void *))airo_read_stats;
>  		ai->stats_task.data = (void *)ai;
> -		schedule_work(&ai->stats_task);
> +		schedule_delayed_work(&ai->stats_task, 1);
>  	}
>  }
>
> @@ -1508,7 +1519,7 @@
>  	} else {
>  		ai->promisc_task.func = (void (*)(void *))airo_end_promisc;
>  		ai->promisc_task.data = (void *)ai;
> -		schedule_work(&ai->promisc_task);
> +		schedule_delayed_work(&ai->promisc_task, 1);
>  	}
>  }
>
> @@ -1524,7 +1535,7 @@
>  	} else {
>  		ai->promisc_task.func = (void (*)(void *))airo_set_promisc;
>  		ai->promisc_task.data = (void *)ai;
> -		schedule_work(&ai->promisc_task);
> +		schedule_delayed_work(&ai->promisc_task, 1);
>  	}
>  }
>
> @@ -1710,6 +1721,14 @@
>  	sema_init(&ai->sem, 1);
>  	ai->need_commit = 0;
>  	ai->config.len = 0;
> +	INIT_WORK(&ai->stats_task, NULL, NULL);
> +	INIT_WORK(&ai->promisc_task, NULL, NULL);
> +	INIT_WORK(&ai->xmit.task, NULL, NULL);
> +	INIT_WORK(&ai->xmit11.task, NULL, NULL);
> +	INIT_WORK(&ai->mic_task, NULL, NULL);
> +#ifdef WIRELESS_EXT
> +	INIT_WORK(&ai->event_task, NULL, NULL);
> +#endif
>  	rc = add_airo_dev( dev );
>  	if (rc)
>  		goto err_out_free;
> @@ -1859,7 +1878,7 @@
>  	} else {
>  		ai->event_task.func = (void (*)(void *))airo_send_event;
>  		ai->event_task.data = (void *)dev;
> -		schedule_work(&ai->event_task);
> +		schedule_delayed_work(&ai->event_task, 1);
>  	}
>  }
>  #endif
> @@ -1876,7 +1895,7 @@
>  	} else {
>  		ai->mic_task.func = (void (*)(void *))airo_read_mic;
>  		ai->mic_task.data = (void *)ai;
> -		schedule_work(&ai->mic_task);
> +		schedule_delayed_work(&ai->mic_task, 1);
>  	}
>  }
>
> @@ -4090,7 +4109,7 @@
>
>  #ifdef CONFIG_PCI
>  	printk( KERN_INFO "airo:  Probing for PCI adapters\n" );
> -	rc = pci_module_init(&airo_driver);
> +	rc = pci_register_driver(&airo_driver);
>  	printk( KERN_INFO "airo:  Finished probing for PCI adapters\n" );
>  #endif
>
> @@ -4102,6 +4121,7 @@
>
>  static void __exit airo_cleanup_module( void )
>  {
> +	pci_unregister_driver(&airo_driver);
>  	while( airo_devices ) {
>  		printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
>  		stop_airo_card( airo_devices->dev, 1 );
> @@ -5160,7 +5180,7 @@
>  			      & status_rid.bssid[i][2]
>  			      & status_rid.bssid[i][3]
>  			      & status_rid.bssid[i][4]
> -			      & status_rid.bssid[i][5])!=-1 &&
> +			      & status_rid.bssid[i][5])!=0xff &&
>  			     (status_rid.bssid[i][0]
>  			      | status_rid.bssid[i][1]
>  			      | status_rid.bssid[i][2]
>
>
>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] airo driver: fix races, oops, etc..
  2003-08-05  8:53 ` Javier Achirica
@ 2003-08-05  9:48   ` Benjamin Herrenschmidt
  2003-08-05 10:18     ` Javier Achirica
  2003-08-07  7:49     ` Javier Achirica
  0 siblings, 2 replies; 8+ messages in thread
From: Benjamin Herrenschmidt @ 2003-08-05  9:48 UTC (permalink / raw)
  To: Javier Achirica; +Cc: Jeff Garzik, linux-kernel mailing list

On Tue, 2003-08-05 at 10:53, Javier Achirica wrote:
> I've integrated this patch in my code. I've done a major change: Instead
> of using schedule_delayed_work(), I create a new workqueue and use
> queue_work() on that queue. As all tasks sleep in the same lock, I can
> queue them there and make them sleep instead of requeueing them.
> 
> I haven't sent them to Jeff yet, as I want to do more testing. If you want
> to help testing them, please tell me.

Well... creating a work queue means you create one thread per CPU, that
sucks a bit don't think ? Maybe using a single thread for the driver
with your own queuing primitives...

Ben.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] airo driver: fix races, oops, etc..
  2003-08-05  9:48   ` Benjamin Herrenschmidt
@ 2003-08-05 10:18     ` Javier Achirica
  2003-08-07  7:49     ` Javier Achirica
  1 sibling, 0 replies; 8+ messages in thread
From: Javier Achirica @ 2003-08-05 10:18 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Jeff Garzik, linux-kernel mailing list



On 5 Aug 2003, Benjamin Herrenschmidt wrote:

> On Tue, 2003-08-05 at 10:53, Javier Achirica wrote:
> > I've integrated this patch in my code. I've done a major change: Instead
> > of using schedule_delayed_work(), I create a new workqueue and use
> > queue_work() on that queue. As all tasks sleep in the same lock, I can
> > queue them there and make them sleep instead of requeueing them.
> >
> > I haven't sent them to Jeff yet, as I want to do more testing. If you want
> > to help testing them, please tell me.
>
> Well... creating a work queue means you create one thread per CPU, that
> sucks a bit don't think ? Maybe using a single thread for the driver
> with your own queuing primitives...

You're right. In my PC, with just one CPU, it doesn't make a difference
:-)

Anyway, I took a look at the workqueue code and looks like I only need a
"create_workqueue()" that only creates one thread. This is what
create_workqueue_thread() does, but it's static. Oh, well. I can also
destroy all threads but one or, as you say, write my own code. I have to
think about it....

Javier Achirica




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] airo driver: fix races, oops, etc..
  2003-08-05  9:48   ` Benjamin Herrenschmidt
  2003-08-05 10:18     ` Javier Achirica
@ 2003-08-07  7:49     ` Javier Achirica
  2003-08-07 14:51       ` Jeff Garzik
  1 sibling, 1 reply; 8+ messages in thread
From: Javier Achirica @ 2003-08-07  7:49 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Jeff Garzik, linux-kernel mailing list



On 5 Aug 2003, Benjamin Herrenschmidt wrote:

> On Tue, 2003-08-05 at 10:53, Javier Achirica wrote:
> > I've integrated this patch in my code. I've done a major change: Instead
> > of using schedule_delayed_work(), I create a new workqueue and use
> > queue_work() on that queue. As all tasks sleep in the same lock, I can
> > queue them there and make them sleep instead of requeueing them.
> >
> > I haven't sent them to Jeff yet, as I want to do more testing. If you want
> > to help testing them, please tell me.
>
> Well... creating a work queue means you create one thread per CPU, that
> sucks a bit don't think ? Maybe using a single thread for the driver
> with your own queuing primitives...

I've been studying the problem for a while and I've implemented a solution
using a single kernel thread and a wait queue for synchronization. I've
tested it and looks like it works fine. It can be used both in 2.4
and 2.6 kernels. Before submitting a patch with it I'd like someone with
experience in this kind of code to take a look at it just in case I'm
doing something dumb. Jeff? :-)

Javier Achirica


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] airo driver: fix races, oops, etc..
  2003-08-07  7:49     ` Javier Achirica
@ 2003-08-07 14:51       ` Jeff Garzik
  2003-08-08  8:54         ` Javier Achirica
  0 siblings, 1 reply; 8+ messages in thread
From: Jeff Garzik @ 2003-08-07 14:51 UTC (permalink / raw)
  To: Javier Achirica; +Cc: Benjamin Herrenschmidt, linux-kernel mailing list

Javier Achirica wrote:
> I've been studying the problem for a while and I've implemented a solution
> using a single kernel thread and a wait queue for synchronization. I've
> tested it and looks like it works fine. It can be used both in 2.4
> and 2.6 kernels. Before submitting a patch with it I'd like someone with
> experience in this kind of code to take a look at it just in case I'm
> doing something dumb. Jeff? :-)


Unless the patch is huge (100K or more), post it to linux-kernel, and CC 
it to me and Benjamin Herrenschmidt.

	Jeff




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] airo driver: fix races, oops, etc..
  2003-08-07 14:51       ` Jeff Garzik
@ 2003-08-08  8:54         ` Javier Achirica
  0 siblings, 0 replies; 8+ messages in thread
From: Javier Achirica @ 2003-08-08  8:54 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Benjamin Herrenschmidt, linux-kernel mailing list

[-- Attachment #1: Type: TEXT/PLAIN, Size: 739 bytes --]



On Thu, 7 Aug 2003, Jeff Garzik wrote:

> Javier Achirica wrote:
> > I've been studying the problem for a while and I've implemented a solution
> > using a single kernel thread and a wait queue for synchronization. I've
> > tested it and looks like it works fine. It can be used both in 2.4
> > and 2.6 kernels. Before submitting a patch with it I'd like someone with
> > experience in this kind of code to take a look at it just in case I'm
> > doing something dumb. Jeff? :-)
>
> Unless the patch is huge (100K or more), post it to linux-kernel, and CC
> it to me and Benjamin Herrenschmidt.

Here it goes. This version should be applied to the latest patches I sent
you in the 2.4 tree. Comments are welcome.

Thanks,
Javier Achirica

[-- Attachment #2: Type: TEXT/PLAIN, Size: 32243 bytes --]

--- linux/drivers/net/wireless/airo.c.orig	2003-08-06 22:28:40 +0200
+++ linux/drivers/net/wireless/airo.c	2003-08-06 22:30:31 +0200
@@ -32,7 +32,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
-#include <linux/tqueue.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -965,8 +964,6 @@
 static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
 static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
-static u16 sendcommand(struct airo_info *ai, Cmd *pCmd);
-static void completecommand(struct airo_info *ai, Resp *pRsp);
 static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
 static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
@@ -986,6 +983,8 @@
 
 static void airo_interrupt( int irq, void* dev_id, struct pt_regs
 			    *regs);
+static int airo_thread(void *data);
+static void timer_func( struct net_device *dev );
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 #ifdef WIRELESS_EXT
 struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
@@ -996,8 +995,8 @@
 int flashcard(struct net_device *dev, aironet_ioctl *comp);
 #endif /* CISCO_EXT */
 #ifdef MICSUPPORT
-static void micinit(struct airo_info *ai, MICRid *micr);
-static void micsetup(struct airo_info *ai);
+static void micinit(struct airo_info *ai);
+static int micsetup(struct airo_info *ai);
 static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
 static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
 #endif
@@ -1015,41 +1014,50 @@
 	int need_commit;	// Need to set config
 	char keyindex; // Used with auto wep
 	char defindex; // Used with auto wep
-	struct timer_list timer;
 	struct proc_dir_entry *proc_entry;
 	struct airo_info *next;
         spinlock_t aux_lock;
         unsigned long flags;
-#define FLAG_PROMISC   IFF_PROMISC	/* 0x100 - include/linux/if.h */
-#define FLAG_RADIO_OFF 0x02		/* User disabling of MAC */
-#define FLAG_RADIO_DOWN 0x08		/* ifup/ifdown disabling of MAC */
-#define FLAG_FLASHING  0x10
-#define FLAG_ADHOC        0x01 /* Needed by MIC */
-#define FLAG_MIC_CAPABLE  0x20
-#define FLAG_UPDATE_MULTI 0x40
-#define FLAG_UPDATE_UNI   0x80
-#define FLAG_802_11    0x200
-#define FLAG_PENDING_XMIT   0x400
-#define FLAG_PENDING_XMIT11 0x800
-#define FLAG_PCI    0x1000
+#define FLAG_PROMISC	8	/* IFF_PROMISC 0x100 - include/linux/if.h */
+#define FLAG_RADIO_OFF	0	/* User disabling of MAC */
+#define FLAG_RADIO_DOWN	1	/* ifup/ifdown disabling of MAC */
+#define FLAG_RADIO_MASK 0x03
+#define FLAG_FLASHING	2
+#define FLAG_ADHOC	3	/* Needed by MIC */
+#define FLAG_MIC_CAPABLE 4
+#define FLAG_UPDATE_MULTI 5
+#define FLAG_UPDATE_UNI 6
+#define FLAG_802_11	7
+#define FLAG_PENDING_XMIT 9
+#define FLAG_PENDING_XMIT11 10
+#define FLAG_PCI	11
+#define JOB_MASK	0xff0000
+#define JOB_DIE		16
+#define JOB_XMIT	17
+#define JOB_XMIT11	18
+#define JOB_STATS	19
+#define JOB_PROMISC	20
+#define JOB_MIC		21
+#define JOB_EVENT	22
+#define JOB_AUTOWEP	23
 	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
 	unsigned short *flash;
 	tdsRssiEntry *rssi;
-	struct semaphore sem;
 	struct task_struct *task;
-	struct tq_struct stats_task;
-	struct tq_struct promisc_task;
+	struct semaphore sem;
+	pid_t thr_pid;
+	wait_queue_head_t thr_wait;
+	struct completion thr_exited;
+	unsigned long expires;
 	struct {
 		struct sk_buff *skb;
 		int fid;
-		struct tq_struct task;
 	} xmit, xmit11;
 	struct net_device *wifidev;
 #ifdef WIRELESS_EXT
 	struct iw_statistics	wstats;		// wireless stats
 	unsigned long		scan_timestamp;	/* Time started to scan */
-	struct tq_struct	event_task;
 #if WIRELESS_EXT > 15
 	struct iw_spy_data	spy_data;
 #else /* WIRELESS_EXT > 15 */
@@ -1063,7 +1071,6 @@
 	/* MIC stuff */
 	mic_module		mod[2];
 	mic_statistics		micstats;
-	struct tq_struct 	mic_task;
 };
 
 static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
@@ -1213,9 +1220,9 @@
 	cfgr = ai->config;
 
 	if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
-		ai->flags |= FLAG_ADHOC;
+		set_bit(FLAG_ADHOC, &ai->flags);
 	else
-		ai->flags &= ~FLAG_ADHOC;
+		clear_bit(FLAG_ADHOC, &ai->flags);
 
 	for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
 
@@ -1279,7 +1286,7 @@
 	struct airo_info *info = dev->priv;
 	Resp rsp;
 
-	if (info->flags & FLAG_FLASHING)
+	if (test_bit(FLAG_FLASHING, &info->flags))
 		return -EIO;
 
 	/* Make sure the card is configured.
@@ -1293,7 +1300,7 @@
 
 	if (info->wifidev != dev) {
 		/* Power on the MAC controller (which may have been disabled) */
-		info->flags &= ~FLAG_RADIO_DOWN;
+		clear_bit(FLAG_RADIO_DOWN, &info->flags);
 		enable_interrupts(info);
 	}
 	enable_MAC(info, &rsp, 1);
@@ -1351,7 +1358,7 @@
 	}
 }
 
-static void airo_do_xmit(struct net_device *dev) {
+static void airo_end_xmit(struct net_device *dev) {
 	u16 status;
 	int i;
 	struct airo_info *priv = dev->priv;
@@ -1359,17 +1366,10 @@
 	int fid = priv->xmit.fid;
 	u32 *fids = priv->fids;
 
-	if (down_trylock(&priv->sem) != 0) {
-		priv->flags |= FLAG_PENDING_XMIT;
-		netif_stop_queue(dev);
-		priv->xmit.task.routine = (void (*)(void *))airo_do_xmit;
-		priv->xmit.task.data = (void *)dev;
-		schedule_task(&priv->xmit.task);
-		return;
-	}
+	clear_bit(JOB_XMIT, &priv->flags);
+	clear_bit(FLAG_PENDING_XMIT, &priv->flags);
 	status = transmit_802_3_packet (priv, fids[fid], skb->data);
 	up(&priv->sem);
-	priv->flags &= ~FLAG_PENDING_XMIT;
 
 	i = 0;
 	if ( status == SUCCESS ) {
@@ -1413,11 +1413,17 @@
 	fids[i] |= (len << 16);
 	priv->xmit.skb = skb;
 	priv->xmit.fid = i;
-	airo_do_xmit(dev);
+	if (down_trylock(&priv->sem) != 0) {
+		set_bit(FLAG_PENDING_XMIT, &priv->flags);
+		netif_stop_queue(dev);
+		set_bit(JOB_XMIT, &priv->flags);
+		wake_up_interruptible(&priv->thr_wait);
+	} else
+		airo_end_xmit(dev);
 	return 0;
 }
 
-static void airo_do_xmit11(struct net_device *dev) {
+static void airo_end_xmit11(struct net_device *dev) {
 	u16 status;
 	int i;
 	struct airo_info *priv = dev->priv;
@@ -1425,17 +1431,10 @@
 	int fid = priv->xmit11.fid;
 	u32 *fids = priv->fids;
 
-	if (down_trylock(&priv->sem) != 0) {
-		priv->flags |= FLAG_PENDING_XMIT11;
-		netif_stop_queue(dev);
-		priv->xmit11.task.routine = (void (*)(void *))airo_do_xmit11;
-		priv->xmit11.task.data = (void *)dev;
-		schedule_task(&priv->xmit11.task);
-		return;
-	}
+	clear_bit(JOB_XMIT11, &priv->flags);
+	clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
 	status = transmit_802_11_packet (priv, fids[fid], skb->data);
 	up(&priv->sem);
-	priv->flags &= ~FLAG_PENDING_XMIT11;
 
 	i = MAX_FIDS / 2;
 	if ( status == SUCCESS ) {
@@ -1479,7 +1478,13 @@
 	fids[i] |= (len << 16);
 	priv->xmit11.skb = skb;
 	priv->xmit11.fid = i;
-	airo_do_xmit11(dev);
+	if (down_trylock(&priv->sem) != 0) {
+		set_bit(FLAG_PENDING_XMIT11, &priv->flags);
+		netif_stop_queue(dev);
+		set_bit(JOB_XMIT11, &priv->flags);
+		wake_up_interruptible(&priv->thr_wait);
+	} else
+		airo_end_xmit11(dev);
 	return 0;
 }
 
@@ -1487,29 +1492,24 @@
 	StatsRid stats_rid;
 	u32 *vals = stats_rid.vals;
 
-	if (down_trylock(&ai->sem) == 0) {
-		readStatsRid(ai, &stats_rid, RID_STATS, 0);
-		up(&ai->sem);
+	clear_bit(JOB_STATS, &ai->flags);
+	readStatsRid(ai, &stats_rid, RID_STATS, 0);
+	up(&ai->sem);
 
-		ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
-		ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
-		ai->stats.rx_bytes = vals[92];
-		ai->stats.tx_bytes = vals[91];
-		ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
-		ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
-		ai->stats.multicast = vals[43];
-		ai->stats.collisions = vals[89];
-
-		/* detailed rx_errors: */
-		ai->stats.rx_length_errors = vals[3];
-		ai->stats.rx_crc_errors = vals[4];
-		ai->stats.rx_frame_errors = vals[2];
-		ai->stats.rx_fifo_errors = vals[0];
-	} else {
-		ai->stats_task.routine = (void (*)(void *))airo_read_stats;
-		ai->stats_task.data = (void *)ai;
-		schedule_task(&ai->stats_task);
-	}
+	ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
+	ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
+	ai->stats.rx_bytes = vals[92];
+	ai->stats.tx_bytes = vals[91];
+	ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
+	ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
+	ai->stats.multicast = vals[43];
+	ai->stats.collisions = vals[89];
+
+	/* detailed rx_errors: */
+	ai->stats.rx_length_errors = vals[3];
+	ai->stats.rx_crc_errors = vals[4];
+	ai->stats.rx_frame_errors = vals[2];
+	ai->stats.rx_fifo_errors = vals[0];
 }
 
 struct net_device_stats *airo_get_stats(struct net_device *dev)
@@ -1517,46 +1517,37 @@
 	struct airo_info *local =  dev->priv;
 
 	/* Get stats out of the card if available */
-	airo_read_stats(local);
+	if (down_trylock(&local->sem) != 0) {
+		set_bit(JOB_STATS, &local->flags);
+		wake_up_interruptible(&local->thr_wait);
+	} else
+		airo_read_stats(local);
 
 	return &local->stats;
 }
 
-static void airo_end_promisc(struct airo_info *ai) {
-	Resp rsp;
-
-	if ((IN4500(ai, EVSTAT) & EV_CMD) != 0) {
-		completecommand(ai, &rsp);
-		up(&ai->sem);
-	} else {
-		ai->promisc_task.routine = (void (*)(void *))airo_end_promisc;
-		ai->promisc_task.data = (void *)ai;
-		schedule_task(&ai->promisc_task);
-	}
-}
-
 static void airo_set_promisc(struct airo_info *ai) {
 	Cmd cmd;
+	Resp rsp;
 
-	if (down_trylock(&ai->sem) == 0) {
-		memset(&cmd, 0, sizeof(cmd));
-		cmd.cmd=CMD_SETMODE;
-		cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
-		sendcommand(ai, &cmd);
-		airo_end_promisc(ai);
-	} else {
-		ai->promisc_task.routine = (void (*)(void *))airo_set_promisc;
-		ai->promisc_task.data = (void *)ai;
-		schedule_task(&ai->promisc_task);
-	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd=CMD_SETMODE;
+	clear_bit(JOB_PROMISC, &ai->flags);
+	cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
+	issuecommand(ai, &cmd, &rsp);
+	up(&ai->sem);
 }
 
 static void airo_set_multicast_list(struct net_device *dev) {
 	struct airo_info *ai = dev->priv;
 
 	if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
-		ai->flags ^= IFF_PROMISC;
-		airo_set_promisc(ai);
+		change_bit(FLAG_PROMISC, &ai->flags);
+		if (down_trylock(&ai->sem) != 0) {
+			set_bit(JOB_PROMISC, &ai->flags);
+			wake_up_interruptible(&ai->thr_wait);
+		} else
+			airo_set_promisc(ai);
 	}
 
 	if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
@@ -1602,7 +1593,7 @@
 		 * That's the method that is most friendly towards the network
 		 * stack (i.e. the network stack won't try to broadcast
 		 * anything on the interface and routes are gone. Jean II */
-		ai->flags |= FLAG_RADIO_DOWN;
+		set_bit(FLAG_RADIO_DOWN, &ai->flags);
 		disable_MAC(ai, 1);
 #endif
 		disable_interrupts( ai );
@@ -1617,8 +1608,6 @@
 	struct airo_info *ai = dev->priv;
 	disable_interrupts(ai);
 	free_irq( dev->irq, dev );
-	if (auto_wep)
-		del_timer_sync(&ai->timer);
 	takedown_proc_entry( dev, ai );
 	if (ai->registered) {
 		unregister_netdev( dev );
@@ -1629,7 +1618,9 @@
 		}
 		ai->registered = 0;
 	}
-	flush_scheduled_tasks();
+	set_bit(JOB_DIE, &ai->flags);
+	kill_proc(ai->thr_pid, SIGTERM, 1);
+	wait_for_completion(&ai->thr_exited);
 	if (ai->flash)
 		kfree(ai->flash);
 	if (ai->rssi)
@@ -1734,9 +1725,14 @@
 	sema_init(&ai->sem, 1);
 	ai->need_commit = 0;
 	ai->config.len = 0;
+	init_waitqueue_head (&ai->thr_wait);
+	init_completion (&ai->thr_exited);
+	ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
+	if (ai->thr_pid < 0)
+		goto err_out_free;
 	rc = add_airo_dev( dev );
 	if (rc)
-		goto err_out_free;
+		goto err_out_thr;
 
 	/* The Airo-specific entries in the device structure. */
 	dev->hard_start_xmit = &airo_start_xmit;
@@ -1776,7 +1772,7 @@
 		}
 	} else {
 		ai->bap_read = fast_bap_read;
-		ai->flags |= FLAG_FLASHING;
+		set_bit(FLAG_FLASHING, &ai->flags);
 	}
 
 	rc = register_netdev(dev);
@@ -1807,6 +1803,10 @@
 	free_irq(dev->irq, dev);
 err_out_unlink:
 	del_airo_dev(dev);
+err_out_thr:
+	set_bit(JOB_DIE, &ai->flags);
+	kill_proc(ai->thr_pid, SIGTERM, 1);
+	wait_for_completion(&ai->thr_exited);
 err_out_free:
 	kfree(dev);
 	return NULL;
@@ -1870,38 +1870,103 @@
 	union iwreq_data wrqu;
 	StatusRid status_rid;
 
-	if (down_trylock(&ai->sem) == 0) {
-		PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
-		up(&ai->sem);
-		wrqu.data.length = 0;
-		wrqu.data.flags = 0;
-		memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
-		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	clear_bit(JOB_EVENT, &ai->flags);
+	PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
+	up(&ai->sem);
+	wrqu.data.length = 0;
+	wrqu.data.flags = 0;
+	memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 
-		/* Send event to user space */
-		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-	} else {
-		ai->event_task.routine = (void (*)(void *))airo_send_event;
-		ai->event_task.data = (void *)dev;
-		schedule_task(&ai->event_task);
-	}
+	/* Send event to user space */
+	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 }
 #endif
 
-static void airo_read_mic(struct airo_info *ai) {
-	MICRid mic_rid;
+static int airo_thread(void *data) {
+	struct net_device *dev = data;
+	struct airo_info *ai = dev->priv;
+	int locked;
+	
+	daemonize();
+	reparent_to_init();
+	sigemptyset(&current->blocked);
+	recalc_sigpending(current);
+
+	strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
+	current->comm[sizeof(current->comm) - 1] = '\0';
+
+	while(1) {
+		if (signal_pending(current))
+			flush_signals(current);
 
-	if (down_trylock(&ai->sem) == 0) {
-		PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
-		up(&ai->sem);
+		if (test_bit(JOB_DIE, &ai->flags))
+			break;
+
+		if (ai->flags & JOB_MASK) {
+			locked = down_interruptible(&ai->sem);
+		} else {
+			wait_queue_t wait;
+
+			init_waitqueue_entry(&wait, current);
+			add_wait_queue(&ai->thr_wait, &wait);
+			for (;;) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (ai->flags & JOB_MASK)
+					break;
+				if (ai->expires) {
+					if (time_after_eq(jiffies,ai->expires)){
+						set_bit(JOB_AUTOWEP,&ai->flags);
+						break;
+					}
+					if (!signal_pending(current)) {
+						schedule_timeout(ai->expires - jiffies);
+						continue;
+					}
+				} else if (!signal_pending(current)) {
+					schedule();
+					continue;
+				}
+				break;
+			}
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&ai->thr_wait, &wait);
+			locked = 1;
+		}
+
+		if (locked)
+			continue;
+
+		if (test_bit(JOB_DIE, &ai->flags)) {
+			up(&ai->sem);
+			break;
+		}
+
+		if (test_bit(FLAG_FLASHING, &ai->flags)) {
+			up(&ai->sem);
+			continue;
+		}
+
+		if (test_bit(JOB_XMIT, &ai->flags))
+			airo_end_xmit(dev);
+		else if (test_bit(JOB_XMIT11, &ai->flags))
+			airo_end_xmit11(dev);
+		else if (test_bit(JOB_STATS, &ai->flags))
+			airo_read_stats(ai);
+		else if (test_bit(JOB_PROMISC, &ai->flags))
+			airo_set_promisc(ai);
 #ifdef MICSUPPORT
-		micinit (ai, &mic_rid);
+		else if (test_bit(JOB_MIC, &ai->flags))
+			micinit(ai);
 #endif
-	} else {
-		ai->mic_task.routine = (void (*)(void *))airo_read_mic;
-		ai->mic_task.data = (void *)ai;
-		schedule_task(&ai->mic_task);
+#if WIRELESS_EXT > 13
+		else if (test_bit(JOB_EVENT, &ai->flags))
+			airo_send_event(dev);
+#endif
+		else if (test_bit(JOB_AUTOWEP, &ai->flags))
+			timer_func(dev);
 	}
+	complete_and_exit (&ai->thr_exited, 0);
 }
 
 static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
@@ -1930,8 +1995,15 @@
 
 		if ( status & EV_MIC ) {
 			OUT4500( apriv, EVACK, EV_MIC );
-			if (apriv->flags & FLAG_MIC_CAPABLE)
-				airo_read_mic( apriv );
+#ifdef MICSUPPORT
+			if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
+				if (down_trylock(&apriv->sem) != 0) {
+					set_bit(JOB_MIC, &apriv->flags);
+					wake_up_interruptible(&apriv->thr_wait);
+				} else
+					micinit (apriv);
+			}
+#endif
 		}
 		if ( status & EV_LINK ) {
 #if WIRELESS_EXT > 13
@@ -1973,15 +2045,18 @@
 #define RC_NOAUTH 9 /* Station requesting (Re)Association is not
 		       Authenticated with the responding station */
 			if (newStatus != ASSOCIATED) {
-				if (auto_wep && !timer_pending(&apriv->timer)) {
-					apriv->timer.expires = RUN_AT(HZ*3);
-		      			add_timer(&apriv->timer);
+				if (auto_wep && !apriv->expires) {
+					apriv->expires = RUN_AT(3*HZ);
+					wake_up_interruptible(&apriv->thr_wait);
 				}
 			} else {
 				struct task_struct *task = apriv->task;
+				if (auto_wep)
+					apriv->expires = 0;
 				if (task)
 					wake_up_process (task);
-				apriv->flags|=FLAG_UPDATE_UNI|FLAG_UPDATE_MULTI;
+				set_bit(FLAG_UPDATE_UNI, &apriv->flags);
+				set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
 			}
 #if WIRELESS_EXT > 13
 			/* Question : is ASSOCIATED the only status
@@ -2002,7 +2077,11 @@
 					wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 					apriv->scan_timestamp = 0;
 				}
-				airo_send_event(dev);
+				if (down_trylock(&apriv->sem) != 0) {
+					set_bit(JOB_EVENT, &apriv->flags);
+					wake_up_interruptible(&apriv->thr_wait);
+				} else
+					airo_send_event(dev);
 			} else {
 				memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
 				wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -2033,7 +2112,7 @@
 			fid = IN4500( apriv, RXFID );
 
 			/* Get the packet length */
-			if (apriv->flags & FLAG_802_11) {
+			if (test_bit(FLAG_802_11, &apriv->flags)) {
 				bap_setup (apriv, fid, 4, BAP0);
 				bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
 				/* Bad CRC. Ignore packet */
@@ -2052,7 +2131,7 @@
 				len = 0;
 			}
 			if (len) {
-				if (apriv->flags & FLAG_802_11) {
+				if (test_bit(FLAG_802_11, &apriv->flags)) {
 					bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
 					fc = le16_to_cpu(fc);
 					switch (fc & 0xc) {
@@ -2081,7 +2160,7 @@
 			}
 			if (len) {
 				buffer = (u16*)skb_put (skb, len + hdrlen);
-				if (apriv->flags & FLAG_802_11) {
+				if (test_bit(FLAG_802_11, &apriv->flags)) {
 					buffer[0] = fc;
 					bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
 					if (hdrlen == 24)
@@ -2128,11 +2207,12 @@
 					char *sa;
 					struct iw_quality wstats;
 					/* Prepare spy data : addr + qual */
-					sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6);
-					if (!(apriv->flags & FLAG_802_11)) {
+					if (!test_bit(FLAG_802_11, &apriv->flags)) {
+						sa = (char*)buffer + 6;
 						bap_setup (apriv, fid, 8, BAP0);
 						bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
-					}
+					} else
+						sa = (char*)buffer + 10;
 					wstats.qual = hdr.rssi[0];
 					if (apriv->rssi)
 						wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
@@ -2149,12 +2229,12 @@
 					int i;
 					char *sa;
 
-					sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6);
+					sa = (char*)buffer + (test_bit(FLAG_802_11, &apriv->flags) ? 10 : 6);
 
 					for (i=0; i<apriv->spy_number; i++)
 						if (!memcmp(sa,apriv->spy_address[i],ETH_ALEN))
 						{
-							if (!(apriv->flags & FLAG_802_11)) {
+							if (!test_bit(FLAG_802_11, &apriv->flags)) {
 								bap_setup (apriv, fid, 8, BAP0);
 								bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
 							}
@@ -2172,7 +2252,7 @@
 #endif /* WIRELESS_EXT > 15 */
 				OUT4500( apriv, EVACK, EV_RX);
 
-				if (apriv->flags & FLAG_802_11) {
+				if (test_bit(FLAG_802_11, &apriv->flags)) {
 					skb->mac.raw = skb->data;
 					skb->pkt_type = PACKET_OTHERHOST;
 					skb->dev = apriv->wifidev;
@@ -2210,10 +2290,10 @@
 				/* Set up to be used again */
 				apriv->fids[index] &= 0xffff;
 				if (index < MAX_FIDS / 2) {
-					if (!(apriv->flags & FLAG_PENDING_XMIT))
+					if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags))
 						netif_wake_queue(dev);
 				} else {
-					if (!(apriv->flags & FLAG_PENDING_XMIT11))
+					if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags))
 						netif_wake_queue(apriv->wifidev);
 				}
 			} else {
@@ -2273,7 +2353,7 @@
 	 * instead of this flag, but I don't trust it *within* the
 	 * open/close functions, and testing both flags together is
 	 * "cheaper" - Jean II */
-	if (ai->flags & (FLAG_RADIO_OFF|FLAG_RADIO_DOWN)) return SUCCESS;
+	if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_ENABLE;
 	if (!lock)
@@ -2394,10 +2474,10 @@
 		ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
 
 #ifdef MICSUPPORT
-		if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1)) {
+		if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) &&
+		    (micsetup(ai) == SUCCESS)) {
 			ai->config.opmode |= MODE_MIC;
-			ai->flags |= FLAG_MIC_CAPABLE;
-			micsetup(ai);
+			set_bit(FLAG_MIC_CAPABLE, &ai->flags);
 		}
 #endif
 
@@ -2463,34 +2543,15 @@
 		rc = readWepKeyRid(ai, &wkr, 0);
 	} while(lastindex != wkr.kindex);
 
-	if (auto_wep && !timer_pending(&ai->timer)) {
-		ai->timer.expires = RUN_AT(HZ*3);
-		add_timer(&ai->timer);
+	if (auto_wep) {
+		ai->expires = RUN_AT(3*HZ);
+		wake_up_interruptible(&ai->thr_wait);
 	}
-	return SUCCESS;
-}
-
-static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
-        // Im really paranoid about letting it run forever!
-	int max_tries = 600000;
-
-	if (sendcommand(ai, pCmd) == (u16)ERROR)
-		return ERROR;
 
-	while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
-		if (!in_interrupt() && (max_tries & 255) == 0)
-			schedule();
-	}
-	if ( max_tries == -1 ) {
-		printk( KERN_ERR
-			"airo: Max tries exceeded waiting for command\n" );
-                return ERROR;
-	}
-	completecommand(ai, pRsp);
 	return SUCCESS;
 }
 
-static u16 sendcommand(struct airo_info *ai, Cmd *pCmd) {
+static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
         // Im really paranoid about letting it run forever!
 	int max_tries = 600000;
 	u16 cmd;
@@ -2509,10 +2570,16 @@
 			"airo: Max tries exceeded when issueing command\n" );
                 return ERROR;
 	}
-	return SUCCESS;
-}
 
-static void completecommand(struct airo_info *ai, Resp *pRsp) {
+	while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
+		if (!in_interrupt() && (max_tries & 255) == 0)
+			schedule();
+	}
+	if ( max_tries == -1 ) {
+		printk( KERN_ERR
+			"airo: Max tries exceeded waiting for command\n" );
+                return ERROR;
+	}
 	// command completed
 	pRsp->status = IN4500(ai, STATUS);
 	pRsp->rsp0 = IN4500(ai, RESP0);
@@ -2525,6 +2592,8 @@
 	}
 	// acknowledge processing the status/response
 	OUT4500(ai, EVACK, EV_CMD);
+
+	return SUCCESS;
 }
 
 /* Sets up the bap to start exchange data.  whichbap should
@@ -2811,7 +2880,7 @@
 	len -= ETH_ALEN * 2;
 
 #ifdef MICSUPPORT
-	if ((ai->flags & FLAG_MIC_CAPABLE) && ai->micstats.enabled && 
+	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && 
 	    (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
 		if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
 			return ERROR;
@@ -3314,7 +3383,7 @@
 			if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
 					ai->need_commit = 2;
 			ai->config.rmode &= 0xfe00;
-			ai->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &ai->flags);
 			ai->config.opmode &= 0xFF00;
 			ai->config.scanMode = SCANMODE_ACTIVE;
 			if ( line[0] == 'a' ) {
@@ -3324,11 +3393,11 @@
 				if ( line[0] == 'r' ) {
 					ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
 					ai->config.scanMode = SCANMODE_PASSIVE;
-					ai->flags |= FLAG_802_11;
+					set_bit (FLAG_802_11, &ai->flags);
 				} else if ( line[0] == 'y' ) {
 					ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
 					ai->config.scanMode = SCANMODE_PASSIVE;
-					ai->flags |= FLAG_802_11;
+					set_bit (FLAG_802_11, &ai->flags);
 				} else if ( line[0] == 'l' )
 					ai->config.rmode |= RXMODE_LANMON;
 			}
@@ -3339,9 +3408,9 @@
 		else if (!strncmp(line,"Radio: ", 7)) {
 			line += 7;
 			if (!strncmp(line,"off",3)) {
-				ai->flags |= FLAG_RADIO_OFF;
+				set_bit (FLAG_RADIO_OFF, &ai->flags);
 			} else {
-				ai->flags &= ~FLAG_RADIO_OFF;
+				clear_bit (FLAG_RADIO_OFF, &ai->flags);
 			}
 		}
 /*** NodeName processing */
@@ -3545,7 +3614,7 @@
 		     (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
 		     (ai->config.opmode & 0xFF) == 2 ? "AP" :
 		     (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
-		     ai->flags&FLAG_RADIO_OFF ? "off" : "on",
+		     test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
 		     ai->config.nodeName,
 		     ai->config.powerSaveMode == 0 ? "CAM" :
 		     ai->config.powerSaveMode == 1 ? "PSP" :
@@ -4012,23 +4081,14 @@
    will switch WEP modes to see if that will help.  If the card is
    associated we will check every minute to see if anything has
    changed. */
-static void timer_func( u_long data ) {
-	struct net_device *dev = (struct net_device*)data;
+static void timer_func( struct net_device *dev ) {
 	struct airo_info *apriv = dev->priv;
-	u16 linkstat = IN4500(apriv, LINKSTAT);
 	Resp rsp;
 
-	if (!(apriv->flags & FLAG_FLASHING) && (linkstat != 0x400)) {
 /* We don't have a link so try changing the authtype */
-		if (down_trylock(&apriv->sem) != 0) {
-			apriv->timer.expires = RUN_AT(1);
-			add_timer(&apriv->timer);
-			return;
-		}
-
-		readConfigRid(apriv, 0);
-		disable_MAC(apriv, 0);
-		switch(apriv->config.authType) {
+	readConfigRid(apriv, 0);
+	disable_MAC(apriv, 0);
+	switch(apriv->config.authType) {
 		case AUTH_ENCRYPT:
 /* So drop to OPEN */
 			apriv->config.authType = AUTH_OPEN;
@@ -4047,16 +4107,15 @@
 			break;
 		default:  /* We'll escalate to SHAREDKEY */
 			apriv->config.authType = AUTH_SHAREDKEY;
-		}
-		apriv->need_commit = 1;
-		writeConfigRid(apriv, 0);
-		enable_MAC(apriv, &rsp, 0);
-		up(&apriv->sem);
+	}
+	apriv->need_commit = 1;
+	writeConfigRid(apriv, 0);
+	enable_MAC(apriv, &rsp, 0);
+	up(&apriv->sem);
 
 /* Schedule check to see if the change worked */
-		apriv->timer.expires = RUN_AT(HZ*3);
-		add_timer(&apriv->timer);
-	}
+	clear_bit(JOB_AUTOWEP, &apriv->flags);
+	apriv->expires = RUN_AT(HZ*3);
 }
 
 static int add_airo_dev( struct net_device *dev ) {
@@ -4064,15 +4123,6 @@
 	if ( !node )
 		return -ENOMEM;
 
-	if ( auto_wep ) {
-		struct airo_info *apriv=dev->priv;
-		struct timer_list *timer = &apriv->timer;
-
-		timer->function = timer_func;
-		timer->data = (u_long)dev;
-		init_timer(timer);
-	}
-
 	node->dev = dev;
 	node->next = airo_devices;
 	airo_devices = node;
@@ -4103,7 +4153,7 @@
 		return -ENODEV;
 
 	pci_set_drvdata(pdev, dev);
-	((struct airo_info *)dev->priv)->flags |= FLAG_PCI;
+	clear_bit (FLAG_PCI, &((struct airo_info *)dev->priv)->flags);
 	return 0;
 }
 
@@ -4149,7 +4199,7 @@
 	while( airo_devices ) {
 		printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
 #ifdef CONFIG_PCI
-		if (((struct airo_info *)airo_devices->dev->priv)->flags & FLAG_PCI)
+		if (test_bit(FLAG_PCI, &((struct airo_info *)airo_devices->dev->priv)->flags))
 			is_pci = 1;
 #endif
 		stop_airo_card( airo_devices->dev, 1 );
@@ -4623,28 +4673,28 @@
 			local->config.opmode |= MODE_STA_IBSS;
 			local->config.rmode &= 0xfe00;
 			local->config.scanMode = SCANMODE_ACTIVE;
-			local->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_INFRA:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_STA_ESS;
 			local->config.rmode &= 0xfe00;
 			local->config.scanMode = SCANMODE_ACTIVE;
-			local->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_MASTER:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_AP;
 			local->config.rmode &= 0xfe00;
 			local->config.scanMode = SCANMODE_ACTIVE;
-			local->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_REPEAT:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_AP_RPTR;
 			local->config.rmode &= 0xfe00;
 			local->config.scanMode = SCANMODE_ACTIVE;
-			local->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_MONITOR:
 			local->config.opmode &= 0xFF00;
@@ -4652,7 +4702,7 @@
 			local->config.rmode &= 0xfe00;
 			local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
 			local->config.scanMode = SCANMODE_PASSIVE;
-			local->flags |= FLAG_802_11;
+			set_bit (FLAG_802_11, &local->flags);
 			break;
 		default:
 			return -EINVAL;
@@ -4841,14 +4891,14 @@
 	readCapabilityRid(local, &cap_rid);
 
 	if (vwrq->disabled) {
-		local->flags |= FLAG_RADIO_OFF;
+		set_bit (FLAG_RADIO_OFF, &local->flags);
 		local->need_commit = 1;
 		return -EINPROGRESS;		/* Call commit handler */
 	}
 	if (vwrq->flags != IW_TXPOW_MWATT) {
 		return -EINVAL;
 	}
-	local->flags &= ~FLAG_RADIO_OFF;
+	clear_bit (FLAG_RADIO_OFF, &local->flags);
 	for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
 		if ((vwrq->value==cap_rid.txPowerLevels[i])) {
 			local->config.txPower = vwrq->value;
@@ -4872,7 +4922,7 @@
 
 	vwrq->value = local->config.txPower;
 	vwrq->fixed = 1;	/* No power control */
-	vwrq->disabled = (local->flags & FLAG_RADIO_OFF);
+	vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
 	vwrq->flags = IW_TXPOW_MWATT;
 
 	return 0;
@@ -5522,10 +5572,14 @@
 		writeSsidRid(local, &SSID_rid);
 		writeAPListRid(local, &APList_rid);
 	}
-	writeConfigRid(local, 1);
-	enable_MAC(local, &rsp, 1);
+	if (down_interruptible(&local->sem))
+		return -ERESTARTSYS;
+	writeConfigRid(local, 0);
+	enable_MAC(local, &rsp, 0);
 	if (local->need_commit > 1)
 		airo_set_promisc(local);
+	else
+		up(&local->sem);
 
 	return 0;
 }
@@ -6063,7 +6117,7 @@
 	unsigned char *iobuf;
 	struct airo_info *ai = dev->priv;
 
-	if (ai->flags & FLAG_FLASHING)
+	if (test_bit(FLAG_FLASHING, &ai->flags))
 		return -EIO;
 
 	switch(comp->command)
@@ -6131,7 +6185,7 @@
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	if (ai->flags & FLAG_FLASHING)
+	if (test_bit(FLAG_FLASHING, &ai->flags))
 		return -EIO;
 
 	ridcode = 0;
@@ -6205,13 +6259,13 @@
 	if (comp->command == AIROPCFG) {
 		ConfigRid *cfg = (ConfigRid *)iobuf;
 
-		if (ai->flags & FLAG_MIC_CAPABLE)
+		if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
 			cfg->opmode |= MODE_MIC;
 
 		if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
-			ai->flags |= FLAG_ADHOC;
+			set_bit (FLAG_ADHOC, &ai->flags);
 		else
-			ai->flags &= ~FLAG_ADHOC;
+			clear_bit (FLAG_ADHOC, &ai->flags);
 	}
 
 	if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
@@ -6322,7 +6376,7 @@
  */
 
 int setflashmode (struct airo_info *ai) {
-	ai->flags |= FLAG_FLASHING;
+	set_bit (FLAG_FLASHING, &ai->flags);
 
 	OUT4500(ai, SWS0, FLASH_COMMAND);
 	OUT4500(ai, SWS1, FLASH_COMMAND);
@@ -6338,7 +6392,7 @@
 	schedule_timeout (HZ/2); /* 500ms delay */
 
 	if(!waitbusy(ai)) {
-		ai->flags &= ~FLAG_FLASHING;
+		clear_bit (FLAG_FLASHING, &ai->flags);
 		printk(KERN_INFO "Waitbusy hang after setflash mode\n");
 		return -EIO;
 	}
@@ -6444,7 +6498,7 @@
 
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	schedule_timeout (HZ);          /* Added 12/7/00 */
-	ai->flags &= ~FLAG_FLASHING;
+	clear_bit (FLAG_FLASHING, &ai->flags);
 	status = setup_card(ai, dev->dev_addr);
 
 	for( i = 0; i < MAX_FIDS; i++ ) {

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] airo driver: fix races, oops, etc..
@ 2003-07-29 16:26 Jean Tourrilhes
  0 siblings, 0 replies; 8+ messages in thread
From: Jean Tourrilhes @ 2003-07-29 16:26 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Linux kernel mailing list
  Cc: Javier Achirica, Jeff Garzik

Benjamin Herrenschmidt wrote :
> 
> Here's a patch against Linus current airo.c, it adds back some fixes I
> did during OLS on the previous version of this driver. I couldn't test
> this new 'fixed' version though as I don't have the airo card anymore:
> 
>  - Initialize the work_struct structures used by the driver
>  - Change most of schedule_work() to schedule_delayed_work(). The
>    problem with schedule_work() is that the worker_thread will never
>    schedule() if the work keeps getting added back to the list by the
>    callback, which typically happened with this driver when the xmit
>    work gets scheduled while the semaphore was used by a pending
>    command. Note that -ac tree has a modified version of this driver
>    that gets rid of this "over-smart" work queue stuff and uses normal
>    spinlock instead, probably at the expense of some latency...
>  - Fix a small signed vs. unsigned char issue
>  - Remove bogus pci_module_init(), use pci_register_driver() instead and
>    add missing pci_unregister_driver() so the module can now be removed
>    without leaving stale references (and thus avoid an oops next time
>    the driver list is walked by the device core).
> 
> Jeff, if you are ok with these, please send to Linus,

	Ben,

	Would you mind sending your patch to Javier (who is the
current maintainer). Javier did some work lately to fix some of those
problems, and I think your patch collides with it.
	Thanks...

	Jean

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2003-08-08  9:08 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-29 13:02 [PATCH] airo driver: fix races, oops, etc Benjamin Herrenschmidt
2003-08-05  8:53 ` Javier Achirica
2003-08-05  9:48   ` Benjamin Herrenschmidt
2003-08-05 10:18     ` Javier Achirica
2003-08-07  7:49     ` Javier Achirica
2003-08-07 14:51       ` Jeff Garzik
2003-08-08  8:54         ` Javier Achirica
2003-07-29 16:26 Jean Tourrilhes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).