Netdev List
 help / color / mirror / Atom feed
* [PATCH 1/2] Runtime configuration of HTB's HYSTERESIS option (kernel)
From: Russell Stuart @ 2006-06-15  9:01 UTC (permalink / raw)
  To: Jamal Hadi Salim, Stephen Hemminger, Martin Devera, netdev, lartc
  Cc: Jesper Dangaard Brouer

[-- Attachment #1: Type: text/plain, Size: 5285 bytes --]

The HTB qdisc has a compile time option, HTB_HYSTERESIS, 
that trades accuracy of traffic classification for CPU 
time.  These patches change hysteresis to be a runtime 
option under the control of "tc".

The effects of HYSTERESIS on HTB's accuracy are significant 
(see chapter 7, section 7.3.1, pp 69-70 in Jesper Brouer's
thesis: http://www.adsl-optimizer.dk/thesis/ ), whereas 
HTB's CPU usage on modern machines using broadband links 
is minimal.  Currently HYSTERESIS is on by default, and 
requires a kernel re-compile to change.  Altering it to 
be a runtime option will make life easier for the bulk of 
its users.

Further documentation on the patch and its usage can be
found here:
  http://www.stuart.id.au/russell/files/tc/tc-atm

Signed-off-by: Russell Stuart <russell-tcatm@stuart.id.au>
Signed-off-by: Jesper Dangaard Brouer <hawk@comx.dk>
---

diff -Nurp kernel-source-2.6.11.orig/include/linux/pkt_sched.h kernel-source-2.6.11/include/linux/pkt_sched.h
--- kernel-source-2.6.11.orig/include/linux/pkt_sched.h	2005-03-02 17:38:13.000000000 +1000
+++ kernel-source-2.6.11/include/linux/pkt_sched.h	2006-06-13 11:34:25.000000000 +1000
@@ -231,6 +231,10 @@ struct tc_gred_sopt
 #define TC_HTB_MAXDEPTH		8
 #define TC_HTB_PROTOVER		3 /* the same as HTB and TC's major */
 
+struct tc_htb_hopt
+{
+	__u32	nohyst;
+};
 struct tc_htb_opt
 {
 	struct tc_ratespec 	rate;
@@ -258,6 +262,7 @@ enum
 	TCA_HTB_INIT,
 	TCA_HTB_CTAB,
 	TCA_HTB_RTAB,
+	TCA_HTB_NOHYST,
 	__TCA_HTB_MAX,
 };
 
diff -Nurp kernel-source-2.6.11.orig/net/sched/sch_htb.c kernel-source-2.6.11/net/sched/sch_htb.c
--- kernel-source-2.6.11.orig/net/sched/sch_htb.c	2005-03-02 17:38:12.000000000 +1000
+++ kernel-source-2.6.11/net/sched/sch_htb.c	2006-06-13 11:34:25.000000000 +1000
@@ -73,7 +73,6 @@
 #define HTB_EWMAC 2	/* rate average over HTB_EWMAC*HTB_HSIZE sec */
 #undef HTB_DEBUG	/* compile debugging support (activated by tc tool) */
 #define HTB_RATECM 1    /* whether to use rate computer */
-#define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */
 #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock)
 #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock)
 #define HTB_VER 0x30011	/* major must be matched with number suplied by TC as version */
@@ -190,6 +189,7 @@ struct htb_class
     /* class attached filters */
     struct tcf_proto *filter_list;
     int filter_cnt;
+    int nohyst;		/* Don't use hysteresis htb_class_mode */
 
     int warned;		/* only one warning about non work conserving .. */
 
@@ -622,20 +622,14 @@ static __inline__ enum htb_cmode 
 htb_class_mode(struct htb_class *cl,long *diff)
 {
     long toks;
+    long hysteresis =
+	    (cl->nohyst || cl->cmode == HTB_CANT_SEND) ? 0 : -cl->cbuffer;
 
-    if ((toks = (cl->ctokens + *diff)) < (
-#if HTB_HYSTERESIS
-	    cl->cmode != HTB_CANT_SEND ? -cl->cbuffer :
-#endif
-       	    0)) {
+    if ((toks = (cl->ctokens + *diff)) < hysteresis) {
 	    *diff = -toks;
 	    return HTB_CANT_SEND;
     }
-    if ((toks = (cl->tokens + *diff)) >= (
-#if HTB_HYSTERESIS
-	    cl->cmode == HTB_CAN_SEND ? -cl->buffer :
-#endif
-	    0))
+    if ((toks = (cl->tokens + *diff)) >= hysteresis)
 	    return HTB_CAN_SEND;
 
     *diff = -toks;
@@ -1323,6 +1317,7 @@ static int htb_dump_class(struct Qdisc *
 	unsigned char	 *b = skb->tail;
 	struct rtattr *rta;
 	struct tc_htb_opt opt;
+	struct tc_htb_hopt hopt;
 
 	HTB_DBG(0,1,"htb_dump_class handle=%X clid=%X\n",sch->handle,cl->classid);
 
@@ -1342,6 +1337,8 @@ static int htb_dump_class(struct Qdisc *
 	opt.quantum = cl->un.leaf.quantum; opt.prio = cl->un.leaf.prio;
 	opt.level = cl->level; 
 	RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt);
+	hopt.nohyst = cl->nohyst;
+	RTA_PUT(skb, TCA_HTB_NOHYST, sizeof(hopt), &hopt);
 	rta->rta_len = skb->tail - b;
 	HTB_QUNLOCK(sch);
 	return skb->len;
@@ -1527,11 +1524,12 @@ static int htb_change_class(struct Qdisc
 	struct htb_class *cl = (struct htb_class*)*arg,*parent;
 	struct rtattr *opt = tca[TCA_OPTIONS-1];
 	struct qdisc_rate_table *rtab = NULL, *ctab = NULL;
-	struct rtattr *tb[TCA_HTB_RTAB];
+	struct rtattr *tb[TCA_HTB_MAX];
 	struct tc_htb_opt *hopt;
+	struct tc_htb_hopt *uhopt;
 
 	/* extract all subattrs from opt attr */
-	if (!opt || rtattr_parse_nested(tb, TCA_HTB_RTAB, opt) ||
+	if (!opt || rtattr_parse_nested(tb, TCA_HTB_MAX, opt) ||
 			tb[TCA_HTB_PARMS-1] == NULL ||
 			RTA_PAYLOAD(tb[TCA_HTB_PARMS-1]) < sizeof(*hopt))
 		goto failure;
@@ -1544,6 +1542,10 @@ static int htb_change_class(struct Qdisc
 	ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]);
 	if (!rtab || !ctab) goto failure;
 
+	uhopt = RTA_DATA(tb[TCA_HTB_NOHYST-1]);
+	if (uhopt != NULL && RTA_PAYLOAD(tb[TCA_HTB_NOHYST-1]) < sizeof(*uhopt))
+		goto failure;
+
 	if (!cl) { /* new class */
 		struct Qdisc *new_q;
 		/* check for valid classid */
@@ -1636,6 +1638,7 @@ static int htb_change_class(struct Qdisc
 	cl->cbuffer = hopt->cbuffer;
 	if (cl->rate) qdisc_put_rtab(cl->rate); cl->rate = rtab;
 	if (cl->ceil) qdisc_put_rtab(cl->ceil); cl->ceil = ctab;
+	if (uhopt) cl->nohyst = uhopt->nohyst;
 	sch_tree_unlock(sch);
 
 	*arg = (unsigned long)cl;




[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* [PATCH 2/2] Runtime configuration of HTB's HYSTERESIS option (userspace)
From: Russell Stuart @ 2006-06-15  9:01 UTC (permalink / raw)
  To: Jamal Hadi Salim, Stephen Hemminger, Martin Devera, netdev, lartc
  Cc: Jesper Dangaard Brouer

[-- Attachment #1: Type: text/plain, Size: 4893 bytes --]

The HTB qdisc has a compile time option, HTB_HYSTERESIS, 
that trades accuracy of traffic classification for CPU 
time.  These patches change hysteresis to be a runtime 
option under the control of "tc".

The effects of HYSTERESIS on HTB's accuracy are significant 
(see chapter 7, section 7.3.1, pp 69-70 in Jesper Brouer's
thesis: http://www.adsl-optimizer.dk/thesis/ ), whereas 
HTB's CPU usage on modern machines using broadband links 
is minimal.  Currently HYSTERESIS is on by default, and 
requires a kernel re-compile to change.  Altering it to 
be a runtime option will make life easier for the bulk of 
its users.

Further documentation on the patch and its usage can be
found here:
  http://www.stuart.id.au/russell/files/tc/tc-atm

Signed-off-by: Russell Stuart <russell-tcatm@stuart.id.au>
Signed-off-by: Jesper Dangaard Brouer <hawk@comx.dk>
---

diff -Nurp iproute2.orig/include/linux/pkt_sched.h iproute2/include/linux/pkt_sched.h
--- iproute2.orig/include/linux/pkt_sched.h	2006-06-13 11:53:27.000000000 +1000
+++ iproute2/include/linux/pkt_sched.h	2006-06-13 11:54:50.000000000 +1000
@@ -232,6 +232,10 @@ struct tc_gred_sopt
 #define TC_HTB_MAXDEPTH		8
 #define TC_HTB_PROTOVER		3 /* the same as HTB and TC's major */
 
+struct tc_htb_hopt
+{
+	__u32	nohyst;
+};
 struct tc_htb_opt
 {
 	struct tc_ratespec 	rate;
@@ -259,6 +263,7 @@ enum
 	TCA_HTB_INIT,
 	TCA_HTB_CTAB,
 	TCA_HTB_RTAB,
+	TCA_HTB_NOHYST,
 	__TCA_HTB_MAX,
 };
 
diff -Nurp iproute2.orig/tc/q_htb.c iproute2/tc/q_htb.c
--- iproute2.orig/tc/q_htb.c	2006-06-13 11:53:27.000000000 +1000
+++ iproute2/tc/q_htb.c	2006-06-13 11:54:50.000000000 +1000
@@ -35,7 +35,7 @@ static void explain(void)
 		" r2q      DRR quantums are computed as rate in Bps/r2q {10}\n"
 		" debug    string of 16 numbers each 0-3 {0}\n\n"
 		"... class add ... htb rate R1 [burst B1] [mpu B] [overhead O] [atm]\n"
-		"                      [prio P] [slot S] [pslot PS]\n"
+		"                      [prio P] [slot S] [pslot PS] [nohyst]\n"
 		"                      [ceil R2] [cburst B2] [mtu MTU] [quantum Q]\n"
 		" rate     rate allocated to this class (class can still borrow)\n"
 		" burst    max bytes burst which can be accumulated during idle period {computed}\n"
@@ -46,6 +46,7 @@ static void explain(void)
 		" cburst   burst but for ceil {computed}\n"
 		" mtu      max packet size we create rate map for {1600}\n"
 		" prio     priority of leaf; lower are served first {0}\n"
+		" nohyst   disable hysteresis (heavier on CPU but more accurate)\n"
 		" quantum  how much bytes to serve from leaf at once {use r2q}\n"
 		"\nTC HTB version %d.%d\n",HTB_TC_VER>>16,HTB_TC_VER&0xffff
 		);
@@ -104,6 +105,7 @@ static int htb_parse_class_opt(struct qd
 {
 	int ok=0;
 	struct tc_htb_opt opt;
+	struct tc_htb_hopt hopt;
 	__u32 rtab[256],ctab[256];
 	unsigned buffer=0,cbuffer=0;
 	int cell_log=-1,ccell_log = -1;
@@ -114,6 +116,7 @@ static int htb_parse_class_opt(struct qd
 	struct rtattr *tail;
 
 	memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */
+	memset(&hopt, 0, sizeof(hopt));
 
 	while (argc > 0) {
 		if (matches(*argv, "prio") == 0) {
@@ -132,6 +135,8 @@ static int htb_parse_class_opt(struct qd
 			if (get_u8(&mpu8, *argv, 10)) {
 				explain1("mpu"); return -1;
 			}
+		} else if (matches(*argv, "nohyst") == 0) {
+		  	hopt.nohyst = 1;
 		} else if (matches(*argv, "overhead") == 0) {
 			NEXT_ARG();
 			if (get_s8(&overhead, *argv, 10)) {
@@ -221,14 +226,16 @@ static int htb_parse_class_opt(struct qd
 	addattr_l(n, 2024, TCA_HTB_PARMS, &opt, sizeof(opt));
 	addattr_l(n, 3024, TCA_HTB_RTAB, rtab, 1024);
 	addattr_l(n, 4024, TCA_HTB_CTAB, ctab, 1024);
+	addattr_l(n, 5024, TCA_HTB_NOHYST, &hopt, sizeof(hopt));
 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
 	return 0;
 }
 
 static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 {
-	struct rtattr *tb[TCA_HTB_RTAB+1];
+	struct rtattr *tb[TCA_HTB_MAX+1];
 	struct tc_htb_opt *hopt;
+	struct tc_htb_hopt *uhopt;
 	struct tc_htb_glob *gopt;
 	double buffer,cbuffer;
 	SPRINT_BUF(b1);
@@ -238,7 +245,7 @@ static int htb_print_opt(struct qdisc_ut
 	if (opt == NULL)
 		return 0;
 
-	parse_rtattr_nested(tb, TCA_HTB_RTAB, opt);
+	parse_rtattr_nested(tb, TCA_HTB_MAX, opt);
 
 	if (tb[TCA_HTB_PARMS]) {
 
@@ -278,6 +285,13 @@ static int htb_print_opt(struct qdisc_ut
 		fprintf(f, "buffer [%08x] cbuffer [%08x] ", 
 			hopt->buffer,hopt->cbuffer);
 	}
+	if (tb[TCA_HTB_NOHYST]) {
+	    uhopt = RTA_DATA(tb[TCA_HTB_NOHYST]);
+	    if (RTA_PAYLOAD(tb[TCA_HTB_NOHYST]) < sizeof(*uhopt)) return -1;
+
+	    if (uhopt->nohyst)
+	        fprintf(f, "nohyst ");
+	}
 	if (tb[TCA_HTB_INIT]) {
 	    gopt = RTA_DATA(tb[TCA_HTB_INIT]);
 	    if (RTA_PAYLOAD(tb[TCA_HTB_INIT])  < sizeof(*gopt)) return -1;

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: driver for pptp
From: xeb @ 2006-06-15  9:49 UTC (permalink / raw)
  To: netdev

Thanks for critique.

>Please read Documentation/SubmittingPatches (and CodingStyle) and submit your kernel patch to netdev.

OK.


>1) why wasn't it possible to use the PPPoX infrastructure of the kernel which is already being used by PPPoE ?  Or at least model it somehow similar to the existing PPPoE/PPPoX infrastructure?

I agree, I will rebuild module.


>2) why are you using a timer for asynchronous processing of GRE frames?
   First of all, why does it have to happen asynchronously at all?
   Secondly, why using a timer when there's nothing time related (or do
   I miss something)?  If deferred, out-of-context execution is
   required, there are other primitives such as tasklets.

Because it is the mechanism of processing reordered packets. On timeout (i.e. there was a loss of packets) buffered packets continue to be processed. It for reduction of traffic if client is under firewall which may reorder packets.


>3) you conflict with the ip_gre.c genric GRE encapsulation driver.  this
   is because both want to reigster a proto handler for GRE.  Ideally,
   there needs to be another demultiplex between the GRE protocl and its
   users.  The code registered for GRE would look at the packet and
   determine whether e.g. it is a PPTP GRE packet and then pass it on to
   the pptp module.

I contacted to the developer ip_gre.c and it has told too most but while there are no results.


4) your code doesn't look nonlinear skb clean

Please give me more comments.


5) why did you chose to implement  /dev/pptp rather than a socket family
   like the existing pppox/pppoe code?

I agree, I will rebuild module.



^ permalink raw reply

* Re: [PATCH 0/2] Runtime configuration of HTB's HYSTERESIS option
From: Martin Devera @ 2006-06-15  9:49 UTC (permalink / raw)
  To: Russell Stuart
  Cc: Jamal Hadi Salim, Stephen Hemminger, netdev, lartc,
	Jesper Dangaard Brouer
In-Reply-To: <1150362059.5578.13.camel@ras.pc.brisbane.lube>

Russell Stuart wrote:
> The HTB qdisc has a compile time option, HTB_HYSTERESIS, 
> that trades accuracy of traffic classification for CPU 
> time.  These patches change hysteresis to be a runtime 
> option under the control of "tc".
> 
> The effects of HYSTERESIS on HTB's accuracy are significant 
> (see chapter 7, section 7.3.1, pp 69-70 in Jesper Brouer's
> thesis: http://www.adsl-optimizer.dk/thesis/ ), whereas 
> HTB's CPU usage on modern machines using broadband links 
> is minimal.  Currently HYSTERESIS is on by default, and 
> requires a kernel re-compile to change.  Altering it to 
> be a runtime option will make life easier for the bulk of 
> its users.

At time of HTB implementation I needed to reach 100MBit speed on 
relatively slow box. The hysteresis was a way. On other side I used 
hand-made TSC based measure tool to compute exact (15%) performance 
gain. Today I'd measure it using oprofile.

When rethinking it again I'd suggest to re-measure real performance 
impact for both flat and deep class hierarchy and consider switching the 
hysteresis off by default (or even to remove the code if the gain is 
negligible). If it is the case then it is the cleanest solution IMHO.

On other side I see no problem with attached patches. Have you tested 
patched kernel with old "tc" tool ?

thanks for your effort,
Martin

^ permalink raw reply

* Re: [patch] ipv4: fix lock usage in udp_ioctl
From: Ingo Molnar @ 2006-06-15 10:52 UTC (permalink / raw)
  To: Heiko Carstens
  Cc: Herbert Xu, davem, jgarzik, akpm, linux-kernel, netdev, fpavlic
In-Reply-To: <20060615065531.GA10411@osiris.ibm.com>


* Heiko Carstens <heiko.carstens@de.ibm.com> wrote:

> How about the patch below? The warning goes away and I assume 
> "tmp_list" needs lockdep_reinit_key too, since it should have the same 
> locking rules as the rest of qeth's skb-queue management.

yeah, looks good.

	Ingo

^ permalink raw reply

* Re: [Ubuntu PATCH] Broadcom wireless patch, PCIE/Mactel support
From: Stefano Brivio @ 2006-06-15 11:32 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: lkml, netdev, mb, akpm
In-Reply-To: <44909A3F.4090905@oracle.com>

On Wed, 14 Jun 2006 16:22:39 -0700
Randy Dunlap <randy.dunlap@oracle.com> wrote:

> From: Matthew Garrett <mjg59@srcf.ucam.org>
> 
> Broadcom wireless patch, PCIE/Mactel support
> 
> http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=1373a8487e911b5ee204f4422ddea00929c8a4cc
> 
> This patch adds support for PCIE cores to the bcm43xx driver. This is
> needed for wireless to work on the Intel imacs. I've submitted it to
> bcm43xx upstream.

NACK.
This has been superseded by my patchset:
http://www.mail-archive.com/bcm43xx-dev@lists.berlios.de/msg01267.html

I'm still waiting for more testing so I didn't request merging to mainline
yet. Plus, this patch is copied from this one:
http://www.mail-archive.com/bcm43xx-dev@lists.berlios.de/msg00919.html
which is wrong. Please see my patchset and new specs for reference.

PS: Next time, don't be rude and send patches to the maintainers.


-- 
Ciao
Stefano

^ permalink raw reply

* Re: [PATCH 1/2] e1000: fix netpoll with NAPI
From: John W. Linville @ 2006-06-15 12:44 UTC (permalink / raw)
  To: Mitch Williams
  Cc: Neil Horman, Jeff Moyer, Kok, Auke-jan H, Matt Mackall,
	Garzik, Jeff, netdev, Brandeburg, Jesse, Kok, Auke
In-Reply-To: <Pine.CYG.4.58.0606141635440.2888@mawilli1-desk2.amr.corp.intel.com>

On Wed, Jun 14, 2006 at 04:44:56PM -0700, Mitch Williams wrote:

> One of our engineers (on the I/O AT team) has been tasked with modifying
> the Linux kernel to properly support multiple hardware queues (both TX and
> RX).  We'll make sure that he looks at the netpoll interface as part of
> that process.

Might I ask who this is?  I might like to ping him/her on this topic.
There is potentially some overlap with wireless, at least on the
transmit side.

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply

* Re: [PATCH 0/2] NET: Accurate packet scheduling for ATM/ADSL
From: jamal @ 2006-06-15 12:57 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: Stephen Hemminger, netdev, lartc, russell-tcatm, hawk
In-Reply-To: <1150289724.26181.74.camel@localhost.localdomain>

On Wed, 2006-14-06 at 14:55 +0200, Jesper Dangaard Brouer wrote:
> On Wed, 2006-06-14 at 08:06 -0400, jamal wrote:

> > - Have you tried to do a long-lived session such as a large FTP and 
> > seen how far off the deviation was? That would provide some interesting
> > data point.
> 
> The deviation can be calculated.  The impact is of cause small for large
> packets.  
>
> But the argument that bulk TCP transfers is not as badly
> affected, is wrong because all the TCP ACK packets gets maximum penalty.
> 

ACKs have always played a prominent role. The last numbers i have seen
for North America (but i think probably valid globaly) show in the range
of 40% ACKs in internet traffic
http://netweb.usc.edu/~rsinha/pkt-sizes/
I suspect a lot of these stats are on their way to change with voip, p2p
etc.
But i dont think it is ACKs perse that you or Russell are contending
cause these issues. It's the presence of ATM . And all evidence seems to
point to the fact that ISPs bill you for something other than your
point of view, no?

> On an ADSL link with more than 8 bytes overhead, a 40 bytes TCP ACK will
> use more that one ATM frame, causing 2 ATM frames to be send that
> consumes 106 bytes, eg. 62% overhead.  On a small upstream ADSL line
> that hurts! (See thesis page 53, table 5.3 "Overhead summary").
> 

But how are you connected to the DSLAM? In north America it is typically
ethernet. If i use the current tables i dont see much of a problem with
say cable modems. Are you trying to compensate for the accounting
differences between what your service provider measures (accounting for
their ATM cells) and what you do accounting for your ethernet frames? 
I guess i am lost as to where the ATM is in the topology and more
importantly whether we (Linux) mis-account or whether your approach is
trying to compensate for the ISPs mis-accounting.

> 
> > - To be a devil's advocate (and not claim there is no issue), where do
> > you draw the line with "overhead"? 
> > Example the smallest ethernet packet is 64 bytes of which 14 bytes are
> > ethernet headers ("overhead" for IP) - and this is not counting CRC etc.
> > If you were to set an MTU of say 64 bytes and tried to do a http or ftp,
> > how accurate do you think the calculation would be? I would think not
> > very different.
> 
> I do think we handle this situation, but I'm not quite sure that I fully
> understand the question (sorry).
> 

Assume the following:
- You had ethernet end to end. Is there still a problem?
- Take it a notch up and assume you had ethernet with MTU of 64B. This
way you will have all your packets being small and having high overhead.
Do you still have a problem?

> 
> > Does it matter if it is accurate on the majority of the cases?
> > - For further reflection: Have you considered the case where the rate
> > table has already been considered on some link speed in user space and
> > then somewhere post-config the physical link speed changes? This would
> > happen in the case where ethernet AN is involved and the partner makes
> > some changes (use ethtool). 
> >
> > I would say the last bullet is a more interesting problem than a corner
> > case of some link layer technology that has high overhead.
> 
> We only claim to do magic on ATM/ADSL links... nothing else ;-)
> 

This is well and good given the focus of your thesis. Up/down here we
need something more generic. Your masters-thesis is a good start but
consider doing the phd next and complete this work;->

> 
> > Your work would be more interesting if it was generic for many link
> > layers instead of just ATM.
> 
> Well, we did consider to do so, but we though that it would be harder to
> get it into the kernel.
> 
> Actually thats the reason for the defines:
>  #define	ATM_CELL_SIZE		53
>  #define	ATM_CELL_PAYLOAD	48
> 
> Changing these should should make it possible to adapt to any other SAR
> (Segment And Reasembly) link layer.  
> 

You are still speaking ATM (and the above may still be valid), but: 
Could you for example look at the netdevice->type and from that figure
out the link layer overhead and compensate for it.
Obviously a lot more useful if such activity is doable in user space
without any knowledge of the kernel? and therefore zero change to the
kernel and everything then becomes forward and backward compatible.

cheers,
jamal


^ permalink raw reply

* Re: [PATCH 2/2] NET: Accurate packet scheduling for ATM/ADSL (userspace)
From: jamal @ 2006-06-15 13:03 UTC (permalink / raw)
  To: Russell Stuart; +Cc: Alan Cox, Stephen Hemminger, netdev
In-Reply-To: <1150332449.8605.40.camel@ras.pc.brisbane.lube>

On Thu, 2006-15-06 at 10:47 +1000, Russell Stuart wrote:
> On Wed, 2006-06-14 at 11:57 +0100, Alan Cox wrote:
> > The other problem I see with this code is it is very tightly tied to ATM
> > cell sizes, not to solving the generic question of packetisation.
> 
> Others have made this point also.  I can't speak for Jesper,
> but I did consider making it generic.  The issue was that 
> doing so would add more code, but I don't personally know 
> of any real world situation that would use the generic 
> solution.  I didn't fancy the thought of arguing on these
> lists for code that no one would actually use.
> 
> If someone could put up their hand and say "Hey, I need
> this," then expanding the patch to accommodate them would
> be a pleasure.  I like generic code too.
> 

It is probably doable by just looking at netdevice->type and figuring
the link layer technology. Totally in user space and building the
compensated for tables there before telling the kernel (advantage is no
kernel changes and therefore it would work with older kernels as well).

cheers,
jamal




^ permalink raw reply

* Re: [PATCH 0/2] NET: Accurate packet scheduling for ATM/ADSL
From: jamal @ 2006-06-15 13:16 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: Stephen Hemminger, netdev, lartc, russell-tcatm, hawk
In-Reply-To: <1150289724.26181.74.camel@localhost.localdomain>

On Wed, 2006-14-06 at 14:55 +0200, Jesper Dangaard Brouer wrote:
> On Wed, 2006-06-14 at 08:06 -0400, jamal wrote:

> > - Have you tried to do a long-lived session such as a large FTP and 
> > seen how far off the deviation was? That would provide some interesting
> > data point.
> 
> The deviation can be calculated.  The impact is of cause small for large
> packets.  
>
> But the argument that bulk TCP transfers is not as badly
> affected, is wrong because all the TCP ACK packets gets maximum penalty.
> 

ACKs have always played a prominent role. The last numbers i have seen
for North America (but i think probably valid globaly) show in the range
of 40% ACKs in internet traffic
http://netweb.usc.edu/~rsinha/pkt-sizes/
I suspect a lot of these stats are on their way to change with voip, p2p
etc.
But i dont think it is ACKs perse that you or Russell are contending
cause these issues. It's the presence of ATM . And all evidence seems to
point to the fact that ISPs bill you for something other than your
point of view, no?

> On an ADSL link with more than 8 bytes overhead, a 40 bytes TCP ACK will
> use more that one ATM frame, causing 2 ATM frames to be send that
> consumes 106 bytes, eg. 62% overhead.  On a small upstream ADSL line
> that hurts! (See thesis page 53, table 5.3 "Overhead summary").
> 

But how are you connected to the DSLAM? In north America it is typically
ethernet. If i use the current tables i dont see much of a problem with
say cable modems. Are you trying to compensate for the accounting
differences between what your service provider measures (accounting for
their ATM cells) and what you do accounting for your ethernet frames? 
I guess i am lost as to where the ATM is in the topology and more
importantly whether we (Linux) mis-account or whether your approach is
trying to compensate for the ISPs mis-accounting.

> 
> > - To be a devil's advocate (and not claim there is no issue), where do
> > you draw the line with "overhead"? 
> > Example the smallest ethernet packet is 64 bytes of which 14 bytes are
> > ethernet headers ("overhead" for IP) - and this is not counting CRC etc.
> > If you were to set an MTU of say 64 bytes and tried to do a http or ftp,
> > how accurate do you think the calculation would be? I would think not
> > very different.
> 
> I do think we handle this situation, but I'm not quite sure that I fully
> understand the question (sorry).
> 

Assume the following:
- You had ethernet end to end. Is there still a problem?
- Take it a notch up and assume you had ethernet with MTU of 64B. This
way you will have all your packets being small and having high overhead.
Do you still have a problem?

> 
> > Does it matter if it is accurate on the majority of the cases?
> > - For further reflection: Have you considered the case where the rate
> > table has already been considered on some link speed in user space and
> > then somewhere post-config the physical link speed changes? This would
> > happen in the case where ethernet AN is involved and the partner makes
> > some changes (use ethtool). 
> >
> > I would say the last bullet is a more interesting problem than a corner
> > case of some link layer technology that has high overhead.
> 
> We only claim to do magic on ATM/ADSL links... nothing else ;-)
> 

This is well and good given the focus of your thesis. Up/down here we
need something more generic. Your masters-thesis is a good start but
consider doing the phd next and complete this work;->

> 
> > Your work would be more interesting if it was generic for many link
> > layers instead of just ATM.
> 
> Well, we did consider to do so, but we though that it would be harder to
> get it into the kernel.
> 
> Actually thats the reason for the defines:
>  #define	ATM_CELL_SIZE		53
>  #define	ATM_CELL_PAYLOAD	48
> 
> Changing these should should make it possible to adapt to any other SAR
> (Segment And Reasembly) link layer.  
> 

You are still speaking ATM (and the above may still be valid), but: 
Could you for example look at the netdevice->type and from that figure
out the link layer overhead and compensate for it.
Obviously a lot more useful if such activity is doable in user space
without any knowledge of the kernel? and therefore zero change to the
kernel and everything then becomes forward and backward compatible.

cheers,
jamal


^ permalink raw reply

* SO_REUSEPORT and multicasting
From: Jason @ 2006-06-15 13:31 UTC (permalink / raw)
  To: netdev

Hello,

I wrote a program that uses multicasting to send data.
 It works great on HP-UX but does not work on Fedora
Core 5.  I emailed the fedora list but they were of
little to no help.  

Does the kernel support SO_REUSEPORT?  If so can
anyone give me some suggestions why my program does
not work on Linux?  I did a route add -net 224.0.0.0/4
dev eth0 but that did not do anything.

I have found out since I posted this message to
linux-kernel that SO_REUSEPORT is a BSDism.  The Linux
equivalent is SO_REUSEADDR which I did try.  My
program compiles cleanly using SO_REUSEADDR, but the
server does not receive any messages.  

I am trying to run the client and server on the same
PC.  This is just for faster development.  I can code
faster on my home Linux system than I can on the
remote HP-UX system.

Thanks,

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam
protection around 
http://mail.yahoo.com 

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 

^ permalink raw reply

* RE: [openib-general] [PATCH v2 1/7] AMSO1100 Low Level Driver.
From: Steve Wise @ 2006-06-15 13:41 UTC (permalink / raw)
  To: Bob Sharp; +Cc: openib-general, linux-kernel, netdev
In-Reply-To: <5E701717F2B2ED4EA60F87C8AA57B7CC05D4E2D8@venom2>

On Wed, 2006-06-14 at 20:35 -0500, Bob Sharp wrote:

> > +void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
> > +{
> > +

<snip>

> > +	case C2_RES_IND_EP:{
> > +
> > +		struct c2wr_ae_connection_request *req =
> > +			&wr->ae.ae_connection_request;
> > +		struct iw_cm_id *cm_id =
> > +			(struct iw_cm_id *)resource_user_context;
> > +
> > +		pr_debug("C2_RES_IND_EP event_id=%d\n", event_id);
> > +		if (event_id != CCAE_CONNECTION_REQUEST) {
> > +			pr_debug("%s: Invalid event_id: %d\n",
> > +				__FUNCTION__, event_id);
> > +			break;
> > +		}
> > +		cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
> > +		cm_event.provider_data = (void*)(unsigned
> long)req->cr_handle;
> > +		cm_event.local_addr.sin_addr.s_addr = req->laddr;
> > +		cm_event.remote_addr.sin_addr.s_addr = req->raddr;
> > +		cm_event.local_addr.sin_port = req->lport;
> > +		cm_event.remote_addr.sin_port = req->rport;
> > +		cm_event.private_data_len =
> > +			be32_to_cpu(req->private_data_length);
> > +
> > +		if (cm_event.private_data_len) {
> 
> 
> It looks to me as if pdata is leaking here since it is not tracked and
> the upper layers do not free it.  Also, if pdata is freed after the call
> to cm_id->event_handler returns, it exposes an issue in user space where
> the private data is garbage.  I suspect the iwarp cm should be copying
> this data before it returns.
> 

Good catch.  

Yes, I think the IWCM should copy the private data in the upcall.  If it
does, then the amso driver doesn't need to kmalloc()/copy at all.  It
can pass a ptr to its MQ entry directly...

Thanks,

Steve.


^ permalink raw reply

* RE: [openib-general] [PATCH v2 1/7] AMSO1100 Low Level Driver.
From: Steve Wise @ 2006-06-15 14:03 UTC (permalink / raw)
  To: Bob Sharp; +Cc: openib-general, linux-kernel, netdev
In-Reply-To: <1150378863.22603.12.camel@stevo-desktop>

On Thu, 2006-06-15 at 08:41 -0500, Steve Wise wrote:
> On Wed, 2006-06-14 at 20:35 -0500, Bob Sharp wrote:
> 
> > > +void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
> > > +{
> > > +
> 
> <snip>
> 
> > > +	case C2_RES_IND_EP:{
> > > +
> > > +		struct c2wr_ae_connection_request *req =
> > > +			&wr->ae.ae_connection_request;
> > > +		struct iw_cm_id *cm_id =
> > > +			(struct iw_cm_id *)resource_user_context;
> > > +
> > > +		pr_debug("C2_RES_IND_EP event_id=%d\n", event_id);
> > > +		if (event_id != CCAE_CONNECTION_REQUEST) {
> > > +			pr_debug("%s: Invalid event_id: %d\n",
> > > +				__FUNCTION__, event_id);
> > > +			break;
> > > +		}
> > > +		cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
> > > +		cm_event.provider_data = (void*)(unsigned
> > long)req->cr_handle;
> > > +		cm_event.local_addr.sin_addr.s_addr = req->laddr;
> > > +		cm_event.remote_addr.sin_addr.s_addr = req->raddr;
> > > +		cm_event.local_addr.sin_port = req->lport;
> > > +		cm_event.remote_addr.sin_port = req->rport;
> > > +		cm_event.private_data_len =
> > > +			be32_to_cpu(req->private_data_length);
> > > +
> > > +		if (cm_event.private_data_len) {
> > 
> > 
> > It looks to me as if pdata is leaking here since it is not tracked and
> > the upper layers do not free it.  Also, if pdata is freed after the call
> > to cm_id->event_handler returns, it exposes an issue in user space where
> > the private data is garbage.  I suspect the iwarp cm should be copying
> > this data before it returns.
> > 
> 
> Good catch.  
> 
> Yes, I think the IWCM should copy the private data in the upcall.  If it
> does, then the amso driver doesn't need to kmalloc()/copy at all.  It
> can pass a ptr to its MQ entry directly...
> 

Now that I've looked more into this, I'm not sure there's a simple way
for the IWCM to copy the pdata on the upcall.  Currently, the IWCM's
event upcall, cm_event_handler(), simply queues the work for processing
on a workqueue thread.  So there's no per-event logic at all there.
Lemme think on this more.  Stay tuned.  

Either way, the amso driver has a memory leak...

Steve.



^ permalink raw reply

* Re: [PATCH] Make in-kernel hostap less annoying
From: Dan Williams @ 2006-06-15 14:07 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: Kyle McMartin, netdev
In-Reply-To: <20060615034102.GF9611@jm.kir.nu>

On Wed, 2006-06-14 at 20:41 -0700, Jouni Malinen wrote: 
> On Mon, Jun 12, 2006 at 03:13:02PM -0400, Kyle McMartin wrote:
> 
> > Most user don't want their kern.log/dmesg filled with
> > debugging gibberish, and could turn it on if prompted.
> > 
> > ( Example:
> > wifi0: TXEXC - status=0x0004 ([Discon]) tx_control=000c
> > retry_count=0 tx_rate=0 fc=0x0108 (Data::0 ToDS)
> > A1=00:0f:66:43:d7:0a A2=00:05:3c:06:63:01 A3=33:33:00:00:00:16 
> > A4=00:00:00:00:00:00 )
> 
> I agree with removing these by default. However, I would prefer to do
> this in more selective manor than disabling all debugging information at
> build time. This would probably involve going through all debug messages
> using this mechanism and selecting whether they are reasonable to enable
> by default or not and ideally doing this as a run-time option.
> 
> > Also make hostap default to managed mode, instead of master mode, which
> > has bitten a few users expecting it to behave like the orinoco driver
> > it is replacing.
> 
> NAK. Host AP has been configured to use master mode by default for the
> past six years and that is what most users would expect it to continue
> to do. I do understand that this default differs from all drivers that
> do not support AP mode, but I think it is too late to change this now.
> The default could change once Host AP gets replaced with
> net/d80211-based implementation for Prism2/2.5/3, but I would not change
> this for Host AP driver.

Furthermore, if your network scripts and/or network daemon don't know to
change the card to Managed mode before they starts trying to make a
connection, they need to be fixed.  It shouldn't really matter to users
what mode the driver starts up in, since the mode needs to get
unconditionally set on the card anyway for each connection you try to
make.  That doesn't matter if it's a human or a script.

Dan



^ permalink raw reply

* Re: [Ubuntu PATCH] Broadcom wireless patch, PCIE/Mactel support
From: Michael Buesch @ 2006-06-15 14:07 UTC (permalink / raw)
  To: Stefano Brivio; +Cc: Randy Dunlap, lkml, netdev, mb, akpm
In-Reply-To: <20060615133220.57d8dd26@localhost>

On Thursday 15 June 2006 13:32, Stefano Brivio wrote:
> On Wed, 14 Jun 2006 16:22:39 -0700
> Randy Dunlap <randy.dunlap@oracle.com> wrote:
> 
> > From: Matthew Garrett <mjg59@srcf.ucam.org>
> > 
> > Broadcom wireless patch, PCIE/Mactel support
> > 
> > http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=1373a8487e911b5ee204f4422ddea00929c8a4cc
> > 
> > This patch adds support for PCIE cores to the bcm43xx driver. This is
> > needed for wireless to work on the Intel imacs. I've submitted it to
> > bcm43xx upstream.
> 
> NACK.
> This has been superseded by my patchset:
> http://www.mail-archive.com/bcm43xx-dev@lists.berlios.de/msg01267.html
> 
> I'm still waiting for more testing so I didn't request merging to mainline
> yet. Plus, this patch is copied from this one:
> http://www.mail-archive.com/bcm43xx-dev@lists.berlios.de/msg00919.html
> which is wrong. Please see my patchset and new specs for reference.

I told by local computer stuff distributor to order a PCIe card.
He was not able to find one, yet. But I would like to test the patch
first. Well, if someone could tell me the exact name of a bcm43xx PCIe
card, it would be easier, perhaps.

-- 
Greetings Michael.

^ permalink raw reply

* Re: [Ubuntu PATCH] Broadcom wireless patch, PCIE/Mactel support
From: Randy Dunlap @ 2006-06-15 17:12 UTC (permalink / raw)
  To: Stefano Brivio; +Cc: lkml, netdev, mb, akpm
In-Reply-To: <20060615133220.57d8dd26@localhost>

Stefano Brivio wrote:
> On Wed, 14 Jun 2006 16:22:39 -0700
> Randy Dunlap <randy.dunlap@oracle.com> wrote:
> 
>> From: Matthew Garrett <mjg59@srcf.ucam.org>
>>
>> Broadcom wireless patch, PCIE/Mactel support
>>
>> http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=1373a8487e911b5ee204f4422ddea00929c8a4cc
>>
>> This patch adds support for PCIE cores to the bcm43xx driver. This is
>> needed for wireless to work on the Intel imacs. I've submitted it to
>> bcm43xx upstream.
> 
> NACK.
> This has been superseded by my patchset:
> http://www.mail-archive.com/bcm43xx-dev@lists.berlios.de/msg01267.html
> 
> I'm still waiting for more testing so I didn't request merging to mainline
> yet. Plus, this patch is copied from this one:
> http://www.mail-archive.com/bcm43xx-dev@lists.berlios.de/msg00919.html
> which is wrong. Please see my patchset and new specs for reference.
> 
> PS: Next time, don't be rude and send patches to the maintainers.

Noted.

Thanks for your comments.

~Randy


^ permalink raw reply

* [BUG] HTB panic
From: Stephen Hemminger @ 2006-06-15 16:47 UTC (permalink / raw)
  To: Jamal; +Cc: netdev

Could some one who has used HTB fix this bug? Looks like a simple use after
free.

http://bugzilla.kernel.org/show_bug.cgi?id=6681

^ permalink raw reply

* Re: [PATCH 5/5] bcm43xx-d80211: fix sending of fragments
From: Michael Buesch @ 2006-06-15 16:55 UTC (permalink / raw)
  To: John W. Linville; +Cc: Jiri Benc, netdev
In-Reply-To: <200606122135.17198.mb@bu3sch.de>

On Monday 12 June 2006 21:35, Michael Buesch wrote:
> On Monday 12 June 2006 21:16, Jiri Benc wrote:
> > This makes fragmentation work with bcm43xx.
> > 
> > Signed-off-by: Jiri Benc <jbenc@suse.cz>
> 
> Signed-off-by: Michael Buesch <mb@bu3sch.de>
> 
> The other patch will get my sign-off tomorrow (I think modified, though).
> I don't have time to look at it more close, now.

Please also merge the other patch. It is too hard to figure out
the dependencies for me now. So simply merge it and I will submit
a fixup patch later, after you pushed it out.
The Subject was:
[incomplete 2/5] bcm43xx-d80211: per-queue TX flow control

It's not so much of trouble, if we break wireless-dev for one or
two days, so this is easiest.
Please notify me after you pushed the stuff to public repository,
so I can pull and fix it.

-- 
Greetings Michael.

^ permalink raw reply

* Re[1]: Ave
From: Galinka @ 2006-06-15 18:24 UTC (permalink / raw)
  To: netdev

Ave ….	

I want to start my first letter from a question: "Is it possible to be happy without LOVE?"
I think that you will agree with me if the answer will be "NO WAY". Love is the most beautiful and exciting thing
that may happen between man and woman! It inspires us only for doing positive things towards each other.
One very famous writer said: "The beauty will rescue the world" i agree with his words but still i would add :
" LOVE and Beauty will rescure the world". 
I hope you agree with me that Love is a big notion.
There's love to  God, to Mother, to a child to the country where you were born, and there's love that joins a man
and woman for all their life. That is the LOVE i'm looking for! And i'm seeking for the man who is also eager to have
this life long adventure full of surprises and new experience we can share together! Will you join me for this trip?
I do realise that it should be very difficult to say "Yes" from the first letter having no idea about me.
That's why i just offer to get to know each other better though correspondence that will help us to reveal many things
about each other whether we mach perfectly or not. In addition you can look at my pictures and read some info about me here
http://oW5g4PWfB9D98gNu.im-waiting-4you.net/
I hope you'll like what you see and read there.
Well closing my first letter to you i just want to thank you for reading it and i really hope that you'll share
my point of view on what i said above. I do really hope that you'll answer me soon.

au revoir...
Galinka



^ permalink raw reply

* Re: [PATCH] s2io: netpoll support
From: Brian Haley @ 2006-06-15 18:36 UTC (permalink / raw)
  To: netdev
  Cc: ravinandan.arakali, jgarzik, Ananda. Raju (E-mail),
	Leonid. Grossman (E-mail)
In-Reply-To: <005401c68f41$bc4bfaa0$3e10100a@pc.s2io.com>

[-- Attachment #1: Type: text/plain, Size: 135 bytes --]

This adds netpoll support for things like netconsole/kgdboe to the s2io
10GbE driver.

Signed-off-by: Brian Haley <brian.haley@hp.com>

[-- Attachment #2: s2io.netpoll.patch --]
[-- Type: text/x-patch, Size: 1694 bytes --]

diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 79208f4..f2b8dba 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -2575,6 +2575,50 @@ no_rx:
 #endif
 
 /**
+ * s2io_netpoll - Rx interrupt service handler for netpoll support
+ * @dev : pointer to the device structure.
+ * Description:
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void s2io_netpoll(struct net_device *dev)
+{
+	nic_t *nic = dev->priv;
+	mac_info_t *mac_control;
+	struct config_param *config;
+	XENA_dev_config_t __iomem *bar0 = nic->bar0;
+	u64 val64;
+	int i;
+
+	disable_irq(dev->irq);
+
+	atomic_inc(&nic->isr_cnt);
+	mac_control = &nic->mac_control;
+	config = &nic->config;
+
+	val64 = readq(&bar0->rx_traffic_int);
+	writeq(val64, &bar0->rx_traffic_int);
+
+	for (i = 0; i < config->rx_ring_num; i++)
+		rx_intr_handler(&mac_control->rings[i]);
+
+	for (i = 0; i < config->rx_ring_num; i++) {
+		if (fill_rx_buffers(nic, i) == -ENOMEM) {
+			DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
+			DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
+			break;
+		}
+	}
+	atomic_dec(&nic->isr_cnt);
+	enable_irq(dev->irq);
+	return;
+}
+#endif
+
+/**
  *  rx_intr_handler - Rx interrupt handler
  *  @nic: device private variable.
  *  Description:
@@ -6210,6 +6254,10 @@ Defaulting to INTA\n");
 	dev->weight = 32;
 #endif
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = s2io_netpoll;
+#endif
+
 	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 	if (sp->high_dma_flag == TRUE)
 		dev->features |= NETIF_F_HIGHDMA;

^ permalink raw reply related

* Suspending 802.11 drivers
From: Michael Buesch @ 2006-06-15 19:58 UTC (permalink / raw)
  To: Jiri Benc; +Cc: John W. Linville, netdev, bcm43xx-dev

Hi,

I am currently thinking about the best way to correctly
implement PM suspending for wireless drivers.
Currently, the 802.11 stack is not suspend aware (if I talk
about "stack" here, I mostly mean devicescape).
For example, if we suspend the bcm43xx driver, we don't
notify the stack before doing so. That's a bug.

I would say, we should have two functions, which are called
from the driver suspend and resume callbacks.
Let's call them
ieee80211_suspend() and ieee80211_resume() for now.
The suspend would save all status information, for example
to which AP we are associated and so on. After that it would
cleanly disassociate from the AP and do other cleanups which
are needed.
The resume function would try to re-esablish the connection.
Of course, that will not always be possible (the notebook
owner traveled around half the world between suspend and
resume ;) ). But that does not matter. We simply return silently
without a new association (Do a new scan, or whatever).

Are such functions generally desireable?

-- 
Greetings Michael.

^ permalink raw reply

* Please pull 'upstream' branch of wireless-2.6
From: John W. Linville @ 2006-06-15 20:03 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 76df73ff90e99681a99e457aec4cfe0a240b7982:
  John W. Linville:
        Merge branch 'from-linus' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Jiri Slaby:
      pci: bcm43xx avoid pci_find_device

Larry Finger:
      wireless: Changes to ieee80211.h for user space regulatory daemon
      wireless: correct dump of WPA IE

Michael Buesch:
      bcm43xx: redesign locking
      bcm43xx: preemptible periodic work

Zhu Yi:
      ipw2200 locking fix

 drivers/net/wireless/bcm43xx/bcm43xx.h         |  100 +++++++----
 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c |   33 ++--
 drivers/net/wireless/bcm43xx/bcm43xx_leds.c    |    4 
 drivers/net/wireless/bcm43xx/bcm43xx_main.c    |  221 ++++++++++++++++--------
 drivers/net/wireless/bcm43xx/bcm43xx_phy.c     |    9 +
 drivers/net/wireless/bcm43xx/bcm43xx_pio.c     |   44 ++++-
 drivers/net/wireless/bcm43xx/bcm43xx_pio.h     |   13 +
 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c   |   38 ++--
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c      |  107 ++++++------
 drivers/net/wireless/ipw2200.c                 |   41 +++-
 drivers/net/wireless/ipw2200.h                 |    1 
 include/net/ieee80211.h                        |    5 -
 net/ieee80211/softmac/ieee80211softmac_wx.c    |    2 
 13 files changed, 402 insertions(+), 216 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index e66fdb1..d8f917c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -636,6 +636,17 @@ struct bcm43xx_key {
 	u8 algorithm;
 };
 
+/* Driver initialization status. */
+enum {
+	BCM43xx_STAT_UNINIT,		/* Uninitialized. */
+	BCM43xx_STAT_INITIALIZING,	/* init_board() in progress. */
+	BCM43xx_STAT_INITIALIZED,	/* Fully operational. */
+	BCM43xx_STAT_SHUTTINGDOWN,	/* free_board() in progress. */
+	BCM43xx_STAT_RESTARTING,	/* controller_restart() called. */
+};
+#define bcm43xx_status(bcm)		atomic_read(&(bcm)->init_status)
+#define bcm43xx_set_status(bcm, stat)	atomic_set(&(bcm)->init_status, (stat))
+
 struct bcm43xx_private {
 	struct ieee80211_device *ieee;
 	struct ieee80211softmac_device *softmac;
@@ -646,18 +657,17 @@ struct bcm43xx_private {
 
 	void __iomem *mmio_addr;
 
-	/* Do not use the lock directly. Use the bcm43xx_lock* helper
-	 * functions, to be MMIO-safe. */
-	spinlock_t _lock;
+	/* Locking, see "theory of locking" text below. */
+	spinlock_t irq_lock;
+	struct mutex mutex;
 
-	/* Driver status flags. */
-	u32 initialized:1,		/* init_board() succeed */
-	    was_initialized:1,		/* for PCI suspend/resume. */
-	    shutting_down:1,		/* free_board() in progress */
+	/* Driver initialization status BCM43xx_STAT_*** */
+	atomic_t init_status;
+
+	u16 was_initialized:1,		/* for PCI suspend/resume. */
 	    __using_pio:1,		/* Internal, use bcm43xx_using_pio(). */
 	    bad_frames_preempt:1,	/* Use "Bad Frames Preemption" (default off) */
 	    reg124_set_0x4:1,		/* Some variable to keep track of IRQ stuff. */
-	    powersaving:1,		/* TRUE if we are in PowerSaving mode. FALSE otherwise. */
 	    short_preamble:1,		/* TRUE, if short preamble is enabled. */
 	    firmware_norelease:1;	/* Do not release the firmware. Used on suspend. */
 
@@ -721,7 +731,7 @@ #endif
 	struct tasklet_struct isr_tasklet;
 
 	/* Periodic tasks */
-	struct timer_list periodic_tasks;
+	struct work_struct periodic_work;
 	unsigned int periodic_state;
 
 	struct work_struct restart_work;
@@ -746,21 +756,55 @@ #ifdef CONFIG_BCM43XX_DEBUG
 #endif
 };
 
-/* bcm43xx_(un)lock() protect struct bcm43xx_private.
- * Note that _NO_ MMIO writes are allowed. If you want to
- * write to the device through MMIO in the critical section, use
- * the *_mmio lock functions.
- * MMIO read-access is allowed, though.
- */
-#define bcm43xx_lock(bcm, flags)	spin_lock_irqsave(&(bcm)->_lock, flags)
-#define bcm43xx_unlock(bcm, flags)	spin_unlock_irqrestore(&(bcm)->_lock, flags)
-/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
- * MMIO write-access to the device is allowed.
- * All MMIO writes are flushed on unlock, so it is guaranteed to not
- * interfere with other threads writing MMIO registers.
+
+/*    *** THEORY OF LOCKING ***
+ *
+ * We have two different locks in the bcm43xx driver.
+ * => bcm->mutex:    General sleeping mutex. Protects struct bcm43xx_private
+ *                   and the device registers.
+ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+ *
+ * We have three types of helper function pairs to utilize these locks.
+ *     (Always use the helper functions.)
+ * 1) bcm43xx_{un}lock_noirq():
+ *     Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
+ *     so it is almost always unsafe, if device IRQs are enabled.
+ *     So only use this, if device IRQs are masked.
+ *     Locking may sleep.
+ *     You can sleep within the critical section.
+ * 2) bcm43xx_{un}lock_irqonly():
+ *     Takes bcm->irq_lock. Does _not_ protect against
+ *     bcm43xx_lock_noirq() critical sections.
+ *     Does only protect against the IRQ handler path and other
+ *     irqonly() critical sections.
+ *     Locking does not sleep.
+ *     You must not sleep within the critical section.
+ * 3) bcm43xx_{un}lock_irqsafe():
+ *     This is the cummulative lock and takes both, mutex and irq_lock.
+ *     Protects against noirq() and irqonly() critical sections (and
+ *     the IRQ handler path).
+ *     Locking may sleep.
+ *     You must not sleep within the critical section.
  */
-#define bcm43xx_lock_mmio(bcm, flags)	bcm43xx_lock(bcm, flags)
-#define bcm43xx_unlock_mmio(bcm, flags)	do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0)
+
+/* Lock type 1 */
+#define bcm43xx_lock_noirq(bcm)		mutex_lock(&(bcm)->mutex)
+#define bcm43xx_unlock_noirq(bcm)	mutex_unlock(&(bcm)->mutex)
+/* Lock type 2 */
+#define bcm43xx_lock_irqonly(bcm, flags)	\
+	spin_lock_irqsave(&(bcm)->irq_lock, flags)
+#define bcm43xx_unlock_irqonly(bcm, flags)	\
+	spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
+/* Lock type 3 */
+#define bcm43xx_lock_irqsafe(bcm, flags) do {	\
+	bcm43xx_lock_noirq(bcm);		\
+	bcm43xx_lock_irqonly(bcm, flags);	\
+		} while (0)
+#define bcm43xx_unlock_irqsafe(bcm, flags) do {	\
+	bcm43xx_unlock_irqonly(bcm, flags);	\
+	bcm43xx_unlock_noirq(bcm);		\
+		} while (0)
+
 
 static inline
 struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
@@ -843,16 +887,6 @@ struct bcm43xx_radioinfo * bcm43xx_curre
 	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
 }
 
-/* Are we running in init_board() context? */
-static inline
-int bcm43xx_is_initializing(struct bcm43xx_private *bcm)
-{
-	if (bcm->initialized)
-		return 0;
-	if (bcm->shutting_down)
-		return 0;
-	return 1;
-}
 
 static inline
 struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index 7497fb1..ce2e40b 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -77,8 +77,8 @@ static ssize_t devinfo_read_file(struct 
 
 	down(&big_buffer_sem);
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
 	}
@@ -121,7 +121,7 @@ #undef fappend_core
 	fappend("\n");
 
 out:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -159,8 +159,8 @@ static ssize_t spromdump_read_file(struc
 	unsigned long flags;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
 	}
@@ -169,7 +169,7 @@ static ssize_t spromdump_read_file(struc
 	fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
 
 out:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -188,8 +188,8 @@ static ssize_t tsf_read_file(struct file
 	u64 tsf;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
 	}
@@ -199,7 +199,7 @@ static ssize_t tsf_read_file(struct file
 		(unsigned int)(tsf & 0xFFFFFFFFULL));
 
 out:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -221,8 +221,8 @@ static ssize_t tsf_write_file(struct fil
 	        res = -EFAULT;
 		goto out_up;
 	}
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
 		res = -EFAULT;
 		goto out_unlock;
@@ -233,10 +233,11 @@ static ssize_t tsf_write_file(struct fil
 		goto out_unlock;
 	}
 	bcm43xx_tsf_write(bcm, tsf);
+	mmiowb();
 	res = buf_size;
 	
 out_unlock:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 out_up:
 	up(&big_buffer_sem);
 	return res;
@@ -257,7 +258,7 @@ static ssize_t txstat_read_file(struct f
 	int i, cnt, j = 0;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 
 	fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
 		BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -293,14 +294,14 @@ static ssize_t txstat_read_file(struct f
 			i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
 	}
 
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	if (*ppos == pos) {
 		/* Done. Drop the copied data. */
 		e->xmitstatus_printing = 0;
 	}
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	up(&big_buffer_sem);
 	return res;
 }
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 4b2c02c..ec80692 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned l
 	struct bcm43xx_private *bcm = led->bcm;
 	unsigned long flags;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
 	if (led->blink_interval) {
 		bcm43xx_led_changestate(led);
 		mod_timer(&led->blink_timer, jiffies + led->blink_interval);
 	}
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 736dde9..085d785 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -498,20 +498,31 @@ static inline u32 bcm43xx_interrupt_disa
 	return old_mask;
 }
 
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
+{
+	synchronize_irq(bcm->irq);
+	tasklet_disable(&bcm->isr_tasklet);
+}
+
 /* Make sure we don't receive more data from the device. */
 static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
 {
-	u32 old;
 	unsigned long flags;
+	u32 old;
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
-		bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
+	if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
+		bcm43xx_unlock_irqonly(bcm, flags);
 		return -EBUSY;
 	}
 	old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-	tasklet_disable(&bcm->isr_tasklet);
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
+	bcm43xx_synchronize_irq(bcm);
+
 	if (oldstate)
 		*oldstate = old;
 
@@ -1389,7 +1400,7 @@ #ifndef CONFIG_BCM947XX
 			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
 #endif
 	}
-	if (bcm->shutting_down) {
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
 		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
 				& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
@@ -1709,7 +1720,7 @@ #else
 # define bcmirq_handled(irq)	do { /* nothing */ } while (0)
 #endif /* CONFIG_BCM43XX_DEBUG*/
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
 	reason = bcm->irq_reason;
 	dma_reason[0] = bcm->dma_reason[0];
 	dma_reason[1] = bcm->dma_reason[1];
@@ -1734,7 +1745,8 @@ #endif /* CONFIG_BCM43XX_DEBUG*/
 		        dma_reason[0], dma_reason[1],
 			dma_reason[2], dma_reason[3]);
 		bcm43xx_controller_restart(bcm, "DMA error");
-		bcm43xx_unlock_mmio(bcm, flags);
+		mmiowb();
+		bcm43xx_unlock_irqonly(bcm, flags);
 		return;
 	}
 	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
@@ -1821,7 +1833,8 @@ #undef bcmirq_handled
 	if (!modparam_noleds)
 		bcm43xx_leds_update(bcm, activity);
 	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
-	bcm43xx_unlock_mmio(bcm, flags);
+	mmiowb();
+	bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1870,7 +1883,7 @@ static irqreturn_t bcm43xx_interrupt_han
 	if (!bcm)
 		return IRQ_NONE;
 
-	spin_lock(&bcm->_lock);
+	spin_lock(&bcm->irq_lock);
 
 	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 	if (reason == 0xffffffff) {
@@ -1899,7 +1912,7 @@ static irqreturn_t bcm43xx_interrupt_han
 	 * completely, but some careful work is needed to fix this. I think it
 	 * is best to stay with this cheap workaround for now... .
 	 */
-	if (likely(bcm->initialized)) {
+	if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
 		/* disable all IRQs. They are enabled again in the bottom half. */
 		bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 		/* save the reason code and call our bottom half. */
@@ -1909,7 +1922,7 @@ static irqreturn_t bcm43xx_interrupt_han
 
 out:
 	mmiowb();
-	spin_unlock(&bcm->_lock);
+	spin_unlock(&bcm->irq_lock);
 
 	return ret;
 }
@@ -2133,6 +2146,13 @@ out:
 	return err;
 }
 
+#ifdef CONFIG_BCM947XX
+static struct pci_device_id bcm43xx_47xx_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
+	{ 0 }
+};
+#endif
+
 static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
 {
 	int res;
@@ -2142,11 +2162,15 @@ static int bcm43xx_initialize_irq(struct
 	bcm->irq = bcm->pci_dev->irq;
 #ifdef CONFIG_BCM947XX
 	if (bcm->pci_dev->bus->number == 0) {
-		struct pci_dev *d = NULL;
-		/* FIXME: we will probably need more device IDs here... */
-		d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
-		if (d != NULL) {
-			bcm->irq = d->irq;
+		struct pci_dev *d;
+		struct pci_device_id *id;
+		for (id = bcm43xx_47xx_ids; id->vendor; id++) {
+			d = pci_get_device(id->vendor, id->device, NULL);
+			if (d != NULL) {
+				bcm->irq = d->irq;
+				pci_dev_put(d);
+				break;
+			}
 		}
 	}
 #endif
@@ -3106,15 +3130,10 @@ static void bcm43xx_periodic_every15sec(
 	//TODO for APHY (temperature?)
 }
 
-static void bcm43xx_periodic_task_handler(unsigned long d)
+static void do_periodic_work(struct bcm43xx_private *bcm)
 {
-	struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
-	unsigned long flags;
 	unsigned int state;
 
-	bcm43xx_lock_mmio(bcm, flags);
-
-	assert(bcm->initialized);
 	state = bcm->periodic_state;
 	if (state % 8 == 0)
 		bcm43xx_periodic_every120sec(bcm);
@@ -3122,29 +3141,93 @@ static void bcm43xx_periodic_task_handle
 		bcm43xx_periodic_every60sec(bcm);
 	if (state % 2 == 0)
 		bcm43xx_periodic_every30sec(bcm);
-	bcm43xx_periodic_every15sec(bcm);
+	if (state % 1 == 0)
+		bcm43xx_periodic_every15sec(bcm);
 	bcm->periodic_state = state + 1;
 
-	mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
+	schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+}
+
+/* Estimate a "Badness" value based on the periodic work
+ * state-machine state. "Badness" is worse (bigger), if the
+ * periodic work will take longer.
+ */
+static int estimate_periodic_work_badness(unsigned int state)
+{
+	int badness = 0;
+
+	if (state % 8 == 0) /* every 120 sec */
+		badness += 10;
+	if (state % 4 == 0) /* every 60 sec */
+		badness += 5;
+	if (state % 2 == 0) /* every 30 sec */
+		badness += 1;
+	if (state % 1 == 0) /* every 15 sec */
+		badness += 1;
 
-	bcm43xx_unlock_mmio(bcm, flags);
+#define BADNESS_LIMIT	4
+	return badness;
+}
+
+static void bcm43xx_periodic_work_handler(void *d)
+{
+	struct bcm43xx_private *bcm = d;
+	unsigned long flags;
+	u32 savedirqs = 0;
+	int badness;
+
+	badness = estimate_periodic_work_badness(bcm->periodic_state);
+	if (badness > BADNESS_LIMIT) {
+		/* Periodic work will take a long time, so we want it to
+		 * be preemtible.
+		 */
+		bcm43xx_lock_irqonly(bcm, flags);
+		netif_stop_queue(bcm->net_dev);
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_freeze_txqueues(bcm);
+		savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+		bcm43xx_unlock_irqonly(bcm, flags);
+		bcm43xx_lock_noirq(bcm);
+		bcm43xx_synchronize_irq(bcm);
+	} else {
+		/* Periodic work should take short time, so we want low
+		 * locking overhead.
+		 */
+		bcm43xx_lock_irqsafe(bcm, flags);
+	}
+
+	do_periodic_work(bcm);
+
+	if (badness > BADNESS_LIMIT) {
+		bcm43xx_lock_irqonly(bcm, flags);
+		if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
+			tasklet_enable(&bcm->isr_tasklet);
+			bcm43xx_interrupt_enable(bcm, savedirqs);
+			if (bcm43xx_using_pio(bcm))
+				bcm43xx_pio_thaw_txqueues(bcm);
+		}
+		netif_wake_queue(bcm->net_dev);
+		mmiowb();
+		bcm43xx_unlock_irqonly(bcm, flags);
+		bcm43xx_unlock_noirq(bcm);
+	} else {
+		mmiowb();
+		bcm43xx_unlock_irqsafe(bcm, flags);
+	}
 }
 
 static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
 {
-	del_timer_sync(&bcm->periodic_tasks);
+	cancel_rearming_delayed_work(&bcm->periodic_work);
 }
 
 static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
 {
-	struct timer_list *timer = &(bcm->periodic_tasks);
+	struct work_struct *work = &(bcm->periodic_work);
 
-	assert(bcm->initialized);
-	setup_timer(timer,
-		    bcm43xx_periodic_task_handler,
-		    (unsigned long)bcm);
-	timer->expires = jiffies;
-	add_timer(timer);
+	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+	INIT_WORK(work, bcm43xx_periodic_work_handler, bcm);
+	schedule_work(work);
 }
 
 static void bcm43xx_security_init(struct bcm43xx_private *bcm)
@@ -3158,16 +3241,12 @@ static void bcm43xx_security_init(struct
 static void bcm43xx_free_board(struct bcm43xx_private *bcm)
 {
 	int i, err;
-	unsigned long flags;
 
+	bcm43xx_lock_noirq(bcm);
 	bcm43xx_sysfs_unregister(bcm);
-
 	bcm43xx_periodic_tasks_delete(bcm);
 
-	bcm43xx_lock(bcm, flags);
-	bcm->initialized = 0;
-	bcm->shutting_down = 1;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
 
 	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
 		if (!bcm->core_80211[i].available)
@@ -3182,23 +3261,19 @@ static void bcm43xx_free_board(struct bc
 
 	bcm43xx_pctl_set_crystal(bcm, 0);
 
-	bcm43xx_lock(bcm, flags);
-	bcm->shutting_down = 0;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+	bcm43xx_unlock_noirq(bcm);
 }
 
 static int bcm43xx_init_board(struct bcm43xx_private *bcm)
 {
 	int i, err;
 	int connect_phy;
-	unsigned long flags;
 
 	might_sleep();
 
-	bcm43xx_lock(bcm, flags);
-	bcm->initialized = 0;
-	bcm->shutting_down = 0;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_lock_noirq(bcm);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
 
 	err = bcm43xx_pctl_set_crystal(bcm, 1);
 	if (err)
@@ -3265,9 +3340,7 @@ static int bcm43xx_init_board(struct bcm
 	}
 
 	/* Initialization of the board is done. Flag it as such. */
-	bcm43xx_lock(bcm, flags);
-	bcm->initialized = 1;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
 
 	bcm43xx_periodic_tasks_setup(bcm);
 	bcm43xx_sysfs_register(bcm);
@@ -3278,6 +3351,8 @@ static int bcm43xx_init_board(struct bcm
 
 	assert(err == 0);
 out:
+	bcm43xx_unlock_noirq(bcm);
+
 	return err;
 
 err_80211_unwind:
@@ -3534,8 +3609,8 @@ static void bcm43xx_ieee80211_set_chan(s
 	struct bcm43xx_radioinfo *radio;
 	unsigned long flags;
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		bcm43xx_mac_suspend(bcm);
 		bcm43xx_radio_selectchannel(bcm, channel, 0);
 		bcm43xx_mac_enable(bcm);
@@ -3543,7 +3618,7 @@ static void bcm43xx_ieee80211_set_chan(s
 		radio = bcm43xx_current_radio(bcm);
 		radio->initial_channel = channel;
 	}
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 }
 
 /* set_security() callback in struct ieee80211_device */
@@ -3557,7 +3632,7 @@ static void bcm43xx_ieee80211_set_securi
 	
 	dprintk(KERN_INFO PFX "set security called");
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 
 	for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
 		if (sec->flags & (1<<keyidx)) {
@@ -3587,7 +3662,8 @@ static void bcm43xx_ieee80211_set_securi
 		dprintk(", .encrypt = %d", sec->encrypt);
 	}
 	dprintk("\n");
-	if (bcm->initialized && !bcm->ieee->host_encrypt) {
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
+	    !bcm->ieee->host_encrypt) {
 		if (secinfo->enabled) {
 			/* upload WEP keys to hardware */
 			char null_address[6] = { 0 };
@@ -3621,7 +3697,7 @@ static void bcm43xx_ieee80211_set_securi
 		} else
 				bcm43xx_clear_keys(bcm);
 	}
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 }
 
 /* hard_start_xmit() callback in struct ieee80211_device */
@@ -3633,10 +3709,10 @@ static int bcm43xx_ieee80211_hard_start_
 	int err = -ENODEV;
 	unsigned long flags;
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (likely(bcm->initialized))
+	bcm43xx_lock_irqonly(bcm, flags);
+	if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
 		err = bcm43xx_tx(bcm, txb);
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
 
 	return err;
 }
@@ -3651,9 +3727,9 @@ static void bcm43xx_net_tx_timeout(struc
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
 	bcm43xx_controller_restart(bcm, "TX timeout");
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3678,9 +3754,11 @@ static int bcm43xx_net_open(struct net_d
 static int bcm43xx_net_stop(struct net_device *net_dev)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err;
 
 	ieee80211softmac_stop(net_dev);
-	bcm43xx_disable_interrupts_sync(bcm, NULL);
+	err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+	assert(!err);
 	bcm43xx_free_board(bcm);
 
 	return 0;
@@ -3692,6 +3770,7 @@ static int bcm43xx_init_private(struct b
 {
 	int err;
 
+	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
 	bcm->ieee = netdev_priv(net_dev);
 	bcm->softmac = ieee80211_priv(net_dev);
 	bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
@@ -3700,7 +3779,8 @@ static int bcm43xx_init_private(struct b
 	bcm->pci_dev = pci_dev;
 	bcm->net_dev = net_dev;
 	bcm->bad_frames_preempt = modparam_bad_frames_preempt;
-	spin_lock_init(&bcm->_lock);
+	spin_lock_init(&bcm->irq_lock);
+	mutex_init(&bcm->mutex);
 	tasklet_init(&bcm->isr_tasklet,
 		     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
 		     (unsigned long)bcm);
@@ -3831,7 +3911,7 @@ static void bcm43xx_chip_reset(void *_bc
 	struct net_device *net_dev = bcm->net_dev;
 	struct pci_dev *pci_dev = bcm->pci_dev;
 	int err;
-	int was_initialized = bcm->initialized;
+	int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 
 	netif_stop_queue(bcm->net_dev);
 	tasklet_disable(&bcm->isr_tasklet);
@@ -3866,6 +3946,7 @@ failure:
 */
 void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
 {
+	bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
 	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
 	printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
@@ -3884,11 +3965,11 @@ static int bcm43xx_suspend(struct pci_de
 
 	dprintk(KERN_INFO PFX "Suspending...\n");
 
-	bcm43xx_lock(bcm, flags);
-	bcm->was_initialized = bcm->initialized;
-	if (bcm->initialized)
+	bcm43xx_lock_irqsafe(bcm, flags);
+	bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+	if (bcm->was_initialized)
 		try_to_shutdown = 1;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	netif_device_detach(net_dev);
 	if (try_to_shutdown) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index b0abac5..f8200de 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1410,7 +1410,10 @@ static inline
 u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 ret;
+	unsigned long flags;
 
+	local_irq_save(flags);
 	if (phy->connected) {
 		bcm43xx_phy_write(bcm, 0x15, 0xE300);
 		control <<= 8;
@@ -1430,8 +1433,10 @@ u16 bcm43xx_phy_lo_g_deviation_subval(st
 		bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
 		udelay(8);
 	}
+	ret = bcm43xx_phy_read(bcm, 0x002D);
+	local_irq_restore(flags);
 
-	return bcm43xx_phy_read(bcm, 0x002D);
+	return ret;
 }
 
 static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control)
@@ -1648,7 +1653,7 @@ void bcm43xx_phy_set_baseband_attenuatio
 void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
 {
 	static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
-	const int is_initializing = bcm43xx_is_initializing(bcm);
+	const int is_initializing = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZING);
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
 	u16 h, i, oldi = 0, j;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index 0aa1bd2..574085c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -262,8 +262,10 @@ static void tx_tasklet(unsigned long d)
 	int err;
 	u16 txctl;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
 
+	if (queue->tx_frozen)
+		goto out_unlock;
 	txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
 	if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
 		goto out_unlock;
@@ -298,7 +300,7 @@ static void tx_tasklet(unsigned long d)
 		continue;
 	}
 out_unlock:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void setup_txqueues(struct bcm43xx_pioqueue *queue)
@@ -374,7 +376,6 @@ static void cancel_transfers(struct bcm4
 	struct bcm43xx_pio_txpacket *packet, *tmp_packet;
 
 	netif_tx_disable(queue->bcm->net_dev);
-	assert(queue->bcm->shutting_down);
 	tasklet_disable(&queue->txtask);
 
 	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
@@ -634,5 +635,40 @@ void bcm43xx_pio_tx_resume(struct bcm43x
 			  bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
 			  & ~BCM43xx_PIO_TXCTL_SUSPEND);
 	bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1);
-	tasklet_schedule(&queue->txtask);
+	if (!list_empty(&queue->txqueue))
+		tasklet_schedule(&queue->txtask);
+}
+
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_pio *pio;
+
+	assert(bcm43xx_using_pio(bcm));
+	pio = bcm43xx_current_pio(bcm);
+	pio->queue0->tx_frozen = 1;
+	pio->queue1->tx_frozen = 1;
+	pio->queue2->tx_frozen = 1;
+	pio->queue3->tx_frozen = 1;
 }
+
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_pio *pio;
+
+	assert(bcm43xx_using_pio(bcm));
+	pio = bcm43xx_current_pio(bcm);
+	pio->queue0->tx_frozen = 0;
+	pio->queue1->tx_frozen = 0;
+	pio->queue2->tx_frozen = 0;
+	pio->queue3->tx_frozen = 0;
+	if (!list_empty(&pio->queue0->txqueue))
+		tasklet_schedule(&pio->queue0->txtask);
+	if (!list_empty(&pio->queue1->txqueue))
+		tasklet_schedule(&pio->queue1->txtask);
+	if (!list_empty(&pio->queue2->txqueue))
+		tasklet_schedule(&pio->queue2->txtask);
+	if (!list_empty(&pio->queue3->txqueue))
+		tasklet_schedule(&pio->queue3->txtask);
+}
+
+
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
index dfc7820..bc78a3c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -54,6 +54,7 @@ struct bcm43xx_pioqueue {
 	u16 mmio_base;
 
 	u8 tx_suspended:1,
+	   tx_frozen:1,
 	   need_workarounds:1; /* Workarounds needed for core.rev < 3 */
 
 	/* Adjusted size of the device internal TX buffer. */
@@ -108,8 +109,12 @@ void bcm43xx_pio_handle_xmitstatus(struc
 				   struct bcm43xx_xmitstatus *status);
 void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
 
+/* Suspend a TX queue on hardware level. */
 void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue);
 void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm);
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm);
 
 #else /* CONFIG_BCM43XX_PIO */
 
@@ -145,6 +150,14 @@ static inline
 void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
 {
 }
+static inline
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+}
+static inline
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+}
 
 #endif /* CONFIG_BCM43XX_PIO */
 #endif /* BCM43xx_PIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index b438f48..6a23bdc 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,12 @@ static ssize_t bcm43xx_attr_sprom_show(s
 			GFP_KERNEL);
 	if (!sprom)
 		return -ENOMEM;
-	bcm43xx_lock_mmio(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	err = bcm43xx_sprom_read(bcm, sprom);
 	if (!err)
 		err = sprom2hex(sprom, buf, PAGE_SIZE);
-	bcm43xx_unlock_mmio(bcm, flags);
+	mmiowb();
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	kfree(sprom);
 
 	return err;
@@ -150,10 +150,10 @@ static ssize_t bcm43xx_attr_sprom_store(
 	err = hex2sprom(sprom, buf, count);
 	if (err)
 		goto out_kfree;
-	bcm43xx_lock_mmio(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	err = bcm43xx_sprom_write(bcm, sprom);
-	bcm43xx_unlock_mmio(bcm, flags);
+	mmiowb();
+	bcm43xx_unlock_irqsafe(bcm, flags);
 out_kfree:
 	kfree(sprom);
 
@@ -170,15 +170,13 @@ static ssize_t bcm43xx_attr_interfmode_s
 					    char *buf)
 {
 	struct bcm43xx_private *bcm = dev_to_bcm(dev);
-	unsigned long flags;
 	int err;
 	ssize_t count = 0;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	bcm43xx_lock(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_noirq(bcm);
 
 	switch (bcm43xx_current_radio(bcm)->interfmode) {
 	case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -195,7 +193,7 @@ static ssize_t bcm43xx_attr_interfmode_s
 	}
 	err = 0;
 
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_noirq(bcm);
 
 	return err ? err : count;
 
@@ -231,16 +229,15 @@ static ssize_t bcm43xx_attr_interfmode_s
 		return -EINVAL;
 	}
 
-	bcm43xx_lock_mmio(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_irqsafe(bcm, flags);
 
 	err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 	if (err) {
 		printk(KERN_ERR PFX "Interference Mitigation not "
 				    "supported by device\n");
 	}
-
-	bcm43xx_unlock_mmio(bcm, flags);
+	mmiowb();
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err ? err : count;
 }
@@ -254,15 +251,13 @@ static ssize_t bcm43xx_attr_preamble_sho
 					  char *buf)
 {
 	struct bcm43xx_private *bcm = dev_to_bcm(dev);
-	unsigned long flags;
 	int err;
 	ssize_t count;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	bcm43xx_lock(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_noirq(bcm);
 
 	if (bcm->short_preamble)
 		count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
@@ -270,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_sho
 		count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
 
 	err = 0;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_noirq(bcm);
 
 	return err ? err : count;
 }
@@ -290,13 +285,12 @@ static ssize_t bcm43xx_attr_preamble_sto
 	value = get_boolean(buf, count);
 	if (value < 0)
 		return value;
-	bcm43xx_lock(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_irqsafe(bcm, flags);
 
 	bcm->short_preamble = !!value;
 
 	err = 0;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err ? err : count;
 }
@@ -310,7 +304,7 @@ int bcm43xx_sysfs_register(struct bcm43x
 	struct device *dev = &bcm->pci_dev->dev;
 	int err;
 
-	assert(bcm->initialized);
+	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 
 	err = device_create_file(dev, &dev_attr_sprom);
 	if (err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index b450639..c35cb3a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -55,13 +55,13 @@ static int bcm43xx_wx_get_name(struct ne
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int i;
+	unsigned long flags;
 	struct bcm43xx_phyinfo *phy;
 	char suffix[7] = { 0 };
 	int have_a = 0, have_b = 0, have_g = 0;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	for (i = 0; i < bcm->nr_80211_available; i++) {
 		phy = &(bcm->core_80211_ext[i].phy);
 		switch (phy->type) {
@@ -77,7 +77,7 @@ static int bcm43xx_wx_get_name(struct ne
 			assert(0);
 		}
 	}
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	i = 0;
 	if (have_a) {
@@ -111,7 +111,7 @@ static int bcm43xx_wx_set_channelfreq(st
 	int freq;
 	int err = -EINVAL;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
 		channel = data->freq.m;
 		freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -121,7 +121,7 @@ static int bcm43xx_wx_set_channelfreq(st
 	}
 	if (!bcm43xx_is_valid_channel(bcm, channel))
 		goto out_unlock;
-	if (bcm->initialized) {
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		//ieee80211softmac_disassoc(softmac, $REASON);
 		bcm43xx_mac_suspend(bcm);
 		err = bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -131,7 +131,7 @@ static int bcm43xx_wx_set_channelfreq(st
 		err = 0;
 	}
 out_unlock:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -147,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(st
 	int err = -ENODEV;
 	u16 channel;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	radio = bcm43xx_current_radio(bcm);
 	channel = radio->channel;
 	if (channel == 0xFF) {
-		assert(!bcm->initialized);
 		channel = radio->initial_channel;
 		if (channel == 0xFF)
 			goto out_unlock;
@@ -163,7 +162,7 @@ static int bcm43xx_wx_get_channelfreq(st
 
 	err = 0;
 out_unlock:
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -181,13 +180,13 @@ static int bcm43xx_wx_set_mode(struct ne
 	if (mode == IW_MODE_AUTO)
 		mode = BCM43xx_INITIAL_IWMODE;
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		if (bcm->ieee->iw_mode != mode)
 			bcm43xx_set_iwmode(bcm, mode);
 	} else
 		bcm->ieee->iw_mode = mode;
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -200,9 +199,9 @@ static int bcm43xx_wx_get_mode(struct ne
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	data->mode = bcm->ieee->iw_mode;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -255,7 +254,7 @@ static int bcm43xx_wx_get_rangeparams(st
 			  IW_ENC_CAPA_CIPHER_TKIP |
 			  IW_ENC_CAPA_CIPHER_CCMP;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	phy = bcm43xx_current_phy(bcm);
 
 	range->num_bitrates = 0;
@@ -302,7 +301,7 @@ static int bcm43xx_wx_get_rangeparams(st
 	}
 	range->num_frequency = j;
 
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -313,14 +312,13 @@ static int bcm43xx_wx_set_nick(struct ne
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	size_t len;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_noirq(bcm);
 	len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
 	memcpy(bcm->nick, extra, len);
 	bcm->nick[len] = '\0';
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_noirq(bcm);
 
 	return 0;
 }
@@ -331,15 +329,14 @@ static int bcm43xx_wx_get_nick(struct ne
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	size_t len;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_noirq(bcm);
 	len = strlen(bcm->nick) + 1;
 	memcpy(extra, bcm->nick, len);
 	data->data.length = (__u16)len;
 	data->data.flags = 1;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_noirq(bcm);
 
 	return 0;
 }
@@ -353,7 +350,7 @@ static int bcm43xx_wx_set_rts(struct net
 	unsigned long flags;
 	int err = -EINVAL;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	if (data->rts.disabled) {
 		bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
 		err = 0;
@@ -364,7 +361,7 @@ static int bcm43xx_wx_set_rts(struct net
 			err = 0;
 		}
 	}
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -377,11 +374,11 @@ static int bcm43xx_wx_get_rts(struct net
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	data->rts.value = bcm->rts_threshold;
 	data->rts.fixed = 0;
 	data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -395,7 +392,7 @@ static int bcm43xx_wx_set_frag(struct ne
 	unsigned long flags;
 	int err = -EINVAL;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	if (data->frag.disabled) {
 		bcm->ieee->fts = MAX_FRAG_THRESHOLD;
 		err = 0;
@@ -406,7 +403,7 @@ static int bcm43xx_wx_set_frag(struct ne
 			err = 0;
 		}
 	}
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -419,11 +416,11 @@ static int bcm43xx_wx_get_frag(struct ne
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	data->frag.value = bcm->ieee->fts;
 	data->frag.fixed = 0;
 	data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -445,8 +442,8 @@ static int bcm43xx_wx_set_xmitpower(stru
 		return -EOPNOTSUPP;
 	}
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized)
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 		goto out_unlock;
 	radio = bcm43xx_current_radio(bcm);
 	phy = bcm43xx_current_phy(bcm);
@@ -469,7 +466,7 @@ static int bcm43xx_wx_set_xmitpower(stru
 	err = 0;
 
 out_unlock:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -484,8 +481,8 @@ static int bcm43xx_wx_get_xmitpower(stru
 	unsigned long flags;
 	int err = -ENODEV;
 
-	bcm43xx_lock(bcm, flags);
-	if (!bcm->initialized)
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 		goto out_unlock;
 	radio = bcm43xx_current_radio(bcm);
 	/* desired dBm value is in Q5.2 */
@@ -496,7 +493,7 @@ static int bcm43xx_wx_get_xmitpower(stru
 
 	err = 0;
 out_unlock:
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -583,8 +580,8 @@ static int bcm43xx_wx_set_interfmode(str
 		return -EINVAL;
 	}
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 		if (err) {
 			printk(KERN_ERR PFX "Interference Mitigation not "
@@ -598,7 +595,7 @@ static int bcm43xx_wx_set_interfmode(str
 		} else
 			bcm43xx_current_radio(bcm)->interfmode = mode;
 	}
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -612,9 +609,9 @@ static int bcm43xx_wx_get_interfmode(str
 	unsigned long flags;
 	int mode;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	mode = bcm43xx_current_radio(bcm)->interfmode;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	switch (mode) {
 	case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -644,9 +641,9 @@ static int bcm43xx_wx_set_shortpreamble(
 	int on;
 
 	on = *((int *)extra);
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	bcm->short_preamble = !!on;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -660,9 +657,9 @@ static int bcm43xx_wx_get_shortpreamble(
 	unsigned long flags;
 	int on;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	on = bcm->short_preamble;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	if (on)
 		strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -684,11 +681,11 @@ static int bcm43xx_wx_set_swencryption(s
 	
 	on = *((int *)extra);
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	bcm->ieee->host_encrypt = !!on;
 	bcm->ieee->host_decrypt = !!on;
 	bcm->ieee->host_build_iv = !on;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -702,9 +699,9 @@ static int bcm43xx_wx_get_swencryption(s
 	unsigned long flags;
 	int on;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	on = bcm->ieee->host_encrypt;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	if (on)
 		strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -767,11 +764,11 @@ static int bcm43xx_wx_sprom_read(struct 
 	if (!sprom)
 		goto out;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	err = -ENODEV;
-	if (bcm->initialized)
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 		err = bcm43xx_sprom_read(bcm, sprom);
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	if (!err)
 		data->data.length = sprom2hex(sprom, extra);
 	kfree(sprom);
@@ -812,11 +809,11 @@ static int bcm43xx_wx_sprom_write(struct
 	if (err)
 		goto out_kfree;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	err = -ENODEV;
-	if (bcm->initialized)
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 		err = bcm43xx_sprom_write(bcm, sprom);
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 out_kfree:
 	kfree(sprom);
 out:
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 39f82f2..081a899 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -533,7 +533,7 @@ static inline void ipw_clear_bit(struct 
 	ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
 }
 
-static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+static inline void __ipw_enable_interrupts(struct ipw_priv *priv)
 {
 	if (priv->status & STATUS_INT_ENABLED)
 		return;
@@ -541,7 +541,7 @@ static inline void ipw_enable_interrupts
 	ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
 }
 
-static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+static inline void __ipw_disable_interrupts(struct ipw_priv *priv)
 {
 	if (!(priv->status & STATUS_INT_ENABLED))
 		return;
@@ -549,6 +549,24 @@ static inline void ipw_disable_interrupt
 	ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
 }
 
+static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->irq_lock, flags);
+	__ipw_enable_interrupts(priv);
+	spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->irq_lock, flags);
+	__ipw_disable_interrupts(priv);
+	spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
 #ifdef CONFIG_IPW2200_DEBUG
 static char *ipw_error_desc(u32 val)
 {
@@ -1856,7 +1874,7 @@ static void ipw_irq_tasklet(struct ipw_p
 	unsigned long flags;
 	int rc = 0;
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irqsave(&priv->irq_lock, flags);
 
 	inta = ipw_read32(priv, IPW_INTA_RW);
 	inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
@@ -1865,6 +1883,10 @@ static void ipw_irq_tasklet(struct ipw_p
 	/* Add any cached INTA values that need to be handled */
 	inta |= priv->isr_inta;
 
+	spin_unlock_irqrestore(&priv->irq_lock, flags);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
 	/* handle all the justifications for the interrupt */
 	if (inta & IPW_INTA_BIT_RX_TRANSFER) {
 		ipw_rx(priv);
@@ -1993,10 +2015,10 @@ #endif
 		IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
 	}
 
+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	/* enable all interrupts */
 	ipw_enable_interrupts(priv);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 #define IPW_CMD(x) case IPW_CMD_ ## x : return #x
@@ -10460,7 +10482,7 @@ static irqreturn_t ipw_isr(int irq, void
 	if (!priv)
 		return IRQ_NONE;
 
-	spin_lock(&priv->lock);
+	spin_lock(&priv->irq_lock);
 
 	if (!(priv->status & STATUS_INT_ENABLED)) {
 		/* Shared IRQ */
@@ -10482,7 +10504,7 @@ static irqreturn_t ipw_isr(int irq, void
 	}
 
 	/* tell the device to stop sending interrupts */
-	ipw_disable_interrupts(priv);
+	__ipw_disable_interrupts(priv);
 
 	/* ack current interrupts */
 	inta &= (IPW_INTA_MASK_ALL & inta_mask);
@@ -10493,11 +10515,11 @@ static irqreturn_t ipw_isr(int irq, void
 
 	tasklet_schedule(&priv->irq_tasklet);
 
-	spin_unlock(&priv->lock);
+	spin_unlock(&priv->irq_lock);
 
 	return IRQ_HANDLED;
       none:
-	spin_unlock(&priv->lock);
+	spin_unlock(&priv->irq_lock);
 	return IRQ_NONE;
 }
 
@@ -11477,6 +11499,7 @@ static int ipw_pci_probe(struct pci_dev 
 #ifdef CONFIG_IPW2200_DEBUG
 	ipw_debug_level = debug;
 #endif
+	spin_lock_init(&priv->irq_lock);
 	spin_lock_init(&priv->lock);
 	for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
 		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 6044c0b..ea12ad6 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1173,6 +1173,7 @@ struct ipw_priv {
 	struct ieee80211_device *ieee;
 
 	spinlock_t lock;
+	spinlock_t irq_lock;
 	struct mutex mutex;
 
 	/* basic pci-network driver stuff */
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index d514777..ecc4286 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -968,6 +968,7 @@ #define IEEE80211_52GHZ_CHANNELS (IEEE80
 
 enum {
 	IEEE80211_CH_PASSIVE_ONLY = (1 << 0),
+	IEEE80211_CH_80211H_RULES = (1 << 1),
 	IEEE80211_CH_B_ONLY = (1 << 2),
 	IEEE80211_CH_NO_IBSS = (1 << 3),
 	IEEE80211_CH_UNIFORM_SPREADING = (1 << 4),
@@ -976,10 +977,10 @@ enum {
 };
 
 struct ieee80211_channel {
-	u32 freq;
+	u32 freq;	/* in MHz */
 	u8 channel;
 	u8 flags;
-	u8 max_power;
+	u8 max_power;	/* in dBm */
 };
 
 struct ieee80211_geo {
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 22aa619..0e65ff4 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -388,7 +388,7 @@ ieee80211softmac_wx_set_genie(struct net
 		memcpy(mac->wpa.IE, extra, wrqu->data.length);
 		dprintk(KERN_INFO PFX "generic IE set to ");
 		for (i=0;i<wrqu->data.length;i++)
-			dprintk("%.2x", mac->wpa.IE[i]);
+			dprintk("%.2x", (u8)mac->wpa.IE[i]);
 		dprintk("\n");
 		mac->wpa.IElen = wrqu->data.length;
 	} else {
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related

* Re: [PATCH 2.6.17-rc6] Remove Prism II support from Orinoco
From: John W. Linville @ 2006-06-15 20:07 UTC (permalink / raw)
  To: Faidon Liambotis; +Cc: Pavel Roskin, Dave Jones, netdev, hermes
In-Reply-To: <4490ECDE.2030600@cube.gr>

On Thu, Jun 15, 2006 at 08:15:10AM +0300, Faidon Liambotis wrote:

> Regarding the disabling of IDs, I could prepare a patch for orinoco_cs
> that would disable Prism2 support via a configuration option. Would that
> be helpful/acceptable?

I'm going to 'officially' drop this patch, while you and Pavel work-out
this issue.

Thanks,

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply

* Re: [patch] workaround zd1201 interference problem
From: John W. Linville @ 2006-06-15 20:10 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Daniel Drake, Jiri Benc, kernel list, netdev
In-Reply-To: <20060609223804.GB3252@elf.ucw.cz>

On Sat, Jun 10, 2006 at 12:38:04AM +0200, Pavel Machek wrote:

> > Which operation is the one which stops the interference, the enable or 
> > the disable?
> 
> Disable alone was not enough to stop interference.

I'm going to drop this patch for now, in the hopes that with Daniel's
ZyDas contacts you can devise a more palatable solution.

Thanks,

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply

* Re: Suspending 802.11 drivers
From: Ivo van Doorn @ 2006-06-15 20:14 UTC (permalink / raw)
  To: Michael Buesch; +Cc: Jiri Benc, John W. Linville, netdev, bcm43xx-dev
In-Reply-To: <200606152158.10079.mb@bu3sch.de>

[-- Attachment #1: Type: text/plain, Size: 1379 bytes --]

Hi,

> I am currently thinking about the best way to correctly
> implement PM suspending for wireless drivers.
> Currently, the 802.11 stack is not suspend aware (if I talk
> about "stack" here, I mostly mean devicescape).
> For example, if we suspend the bcm43xx driver, we don't
> notify the stack before doing so. That's a bug.

Similar in rt2x00. The basic approach in there is calling
netdev->open() and netdev->stop() which is not the most clean
or correct thing to do.

> I would say, we should have two functions, which are called
> from the driver suspend and resume callbacks.
> Let's call them
> ieee80211_suspend() and ieee80211_resume() for now.
> The suspend would save all status information, for example
> to which AP we are associated and so on. After that it would
> cleanly disassociate from the AP and do other cleanups which
> are needed.
> The resume function would try to re-esablish the connection.
> Of course, that will not always be possible (the notebook
> owner traveled around half the world between suspend and
> resume ;) ). But that does not matter. We simply return silently
> without a new association (Do a new scan, or whatever).
> 
> Are such functions generally desireable?

Absolutely, I have been looking into this some time ago as well,
but due to lack of time haven't managed to get anything done.

Ivo

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox