Netdev List
 help / color / mirror / Atom feed
* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Andrew Morton @ 2006-01-27 23:16 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <43DAA586.5050609@cosmosbay.com>

Eric Dumazet <dada1@cosmosbay.com> wrote:
>
> Ravikiran G Thirumalai a écrit :
> > On Fri, Jan 27, 2006 at 12:16:02PM -0800, Andrew Morton wrote:
> >> Ravikiran G Thirumalai <kiran@scalex86.org> wrote:
> >>> which can be assumed as not frequent.  
> >>> At sk_stream_mem_schedule(), read_sockets_allocated() is invoked only 
> >>> certain conditions, under memory pressure -- on a large CPU count machine, 
> >>> you'd have large memory, and I don't think read_sockets_allocated would get 
> >>> called often.  It did not atleast on our 8cpu/16G box.  So this should be OK 
> >>> I think.
> >> That being said, the percpu_counters aren't a terribly successful concept
> >> and probably do need a revisit due to the high inaccuracy at high CPU
> >> counts.  It might be better to do some generic version of vm_acct_memory()
> >> instead.
> > 
> > AFAICS vm_acct_memory is no better.  The deviation on large cpu counts is the 
> > same as percpu_counters -- (NR_CPUS * NR_CPUS * 2) ...
> 
> Ah... yes you are right, I read min(16, NR_CPUS*2)

So did I ;)

> I wonder if it is not a typo... I mean, I understand the more cpus you have, 
> the less updates on central atomic_t is desirable, but a quadratic offset 
> seems too much...

I'm not sure whether it was a mistake or if I intended it and didn't do the
sums on accuracy :(

An advantage of retaining a spinlock in percpu_counter is that if accuracy
is needed at a low rate (say, /proc reading) we can take the lock and then
go spill each CPU's local count into the main one.  It would need to be a
very low rate though.   Or we make the cpu-local counters atomic too.

Certainly it's sensible to delegate the tuning to the creator of the
percpu_counter, but it'll be a difficult thing to get right.

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Eric Dumazet @ 2006-01-27 23:21 UTC (permalink / raw)
  To: Ravikiran G Thirumalai
  Cc: Andrew Morton, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060127225036.GC3565@localhost.localdomain>

Ravikiran G Thirumalai a écrit :
> On Fri, Jan 27, 2006 at 11:30:23PM +0100, Eric Dumazet wrote:
>> There are several issues here :
>>
>> alloc_percpu() current implementation is a a waste of ram. (because it uses 
>> slab allocations that have a minimum size of 32 bytes)
> 
> Oh there was a solution for that :).  
> 
> http://lwn.net/Articles/119532/
> 
> I can quickly revive it if there is interest.
> 

Well, nice work ! :)

Maybe a litle bit complicated if expected percpu space is 50 KB per cpu ?

Why not use a boot time allocated percpu area (as done today in 
setup_per_cpu_areas()), but instead of reserving extra space for module's 
percpu data, being able to serve alloc_percpu() from this reserved area (ie no 
kmalloced data anymore), and keeping your

#define per_cpu_ptr(ptr, cpu)  ((__typeof__(ptr))         \
	(RELOC_HIDE(ptr,  PCPU_BLKSIZE * cpu)))

Some code from kernel/module.c could be reworked to serve both as an allocator 
when a module percpudata must be relocated (insmod)/freed (rmmod), and serve 
alloc_percpu() for 'dynamic allocations'

Eric

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Ravikiran G Thirumalai @ 2006-01-28  0:01 UTC (permalink / raw)
  To: Andrew Morton; +Cc: dada1, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060127150847.48c312c0.akpm@osdl.org>

On Fri, Jan 27, 2006 at 03:08:47PM -0800, Andrew Morton wrote:
> Andrew Morton <akpm@osdl.org> wrote:
> >
> > Oh, and because vm_acct_memory() is counting a singleton object, it can use
> > DEFINE_PER_CPU rather than alloc_percpu(), so it saves on a bit of kmalloc
> > overhead.
> 
> Actually, I don't think that's true.  we're allocating a sizeof(long) with
> kmalloc_node() so there shouldn't be memory wastage.

Oh yeah there is. Each dynamic per-cpu object would have been  atleast
(NR_CPUS * sizeof (void *) + num_cpus_possible * cacheline_size ).  
Now kmalloc_node will fall back on size-32 for allocation of long, so
replace the cacheline_size above with 32 -- which then means dynamic per-cpu
data are not on a cacheline boundary anymore (most modern cpus have 64byte/128 
byte cache lines) which means per-cpu data could end up false shared....

Kiran

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Andrew Morton @ 2006-01-28  0:26 UTC (permalink / raw)
  To: Ravikiran G Thirumalai; +Cc: dada1, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060128000100.GD3565@localhost.localdomain>

Ravikiran G Thirumalai <kiran@scalex86.org> wrote:
>
> On Fri, Jan 27, 2006 at 03:08:47PM -0800, Andrew Morton wrote:
> > Andrew Morton <akpm@osdl.org> wrote:
> > >
> > > Oh, and because vm_acct_memory() is counting a singleton object, it can use
> > > DEFINE_PER_CPU rather than alloc_percpu(), so it saves on a bit of kmalloc
> > > overhead.
> > 
> > Actually, I don't think that's true.  we're allocating a sizeof(long) with
> > kmalloc_node() so there shouldn't be memory wastage.
> 
> Oh yeah there is. Each dynamic per-cpu object would have been  atleast
> (NR_CPUS * sizeof (void *) + num_cpus_possible * cacheline_size ).  
> Now kmalloc_node will fall back on size-32 for allocation of long, so
> replace the cacheline_size above with 32 -- which then means dynamic per-cpu
> data are not on a cacheline boundary anymore (most modern cpus have 64byte/128 
> byte cache lines) which means per-cpu data could end up false shared....
> 

OK.  But isn't the core of the problem the fact that __alloc_percpu() is
using kmalloc_node() rather than a (new, as-yet-unimplemented)
kmalloc_cpu()?  kmalloc_cpu() wouldn't need the L1 cache alignment.

It might be worth creating just a small number of per-cpu slabs (4-byte,
8-byte).  A kmalloc_cpu() would just need a per-cpu array of
kmem_cache_t*'s and it'd internally use kmalloc_node(cpu_to_node), no?

Or we could just give __alloc_percpu() a custom, hand-rolled,
not-cacheline-padded sizeof(long) slab per CPU and use that if (size ==
sizeof(long)).  Or something.

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Eric Dumazet @ 2006-01-28  0:28 UTC (permalink / raw)
  To: Andrew Morton; +Cc: kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060127151635.3a149fe2.akpm@osdl.org>

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

Andrew Morton a écrit :
> Eric Dumazet <dada1@cosmosbay.com> wrote:
>> Ravikiran G Thirumalai a écrit :
>>> On Fri, Jan 27, 2006 at 12:16:02PM -0800, Andrew Morton wrote:
>>>> Ravikiran G Thirumalai <kiran@scalex86.org> wrote:
>>>>> which can be assumed as not frequent.  
>>>>> At sk_stream_mem_schedule(), read_sockets_allocated() is invoked only 
>>>>> certain conditions, under memory pressure -- on a large CPU count machine, 
>>>>> you'd have large memory, and I don't think read_sockets_allocated would get 
>>>>> called often.  It did not atleast on our 8cpu/16G box.  So this should be OK 
>>>>> I think.
>>>> That being said, the percpu_counters aren't a terribly successful concept
>>>> and probably do need a revisit due to the high inaccuracy at high CPU
>>>> counts.  It might be better to do some generic version of vm_acct_memory()
>>>> instead.
>>> AFAICS vm_acct_memory is no better.  The deviation on large cpu counts is the 
>>> same as percpu_counters -- (NR_CPUS * NR_CPUS * 2) ...
>> Ah... yes you are right, I read min(16, NR_CPUS*2)
> 
> So did I ;)
> 
>> I wonder if it is not a typo... I mean, I understand the more cpus you have, 
>> the less updates on central atomic_t is desirable, but a quadratic offset 
>> seems too much...
> 
> I'm not sure whether it was a mistake or if I intended it and didn't do the
> sums on accuracy :(
> 
> An advantage of retaining a spinlock in percpu_counter is that if accuracy
> is needed at a low rate (say, /proc reading) we can take the lock and then
> go spill each CPU's local count into the main one.  It would need to be a
> very low rate though.   Or we make the cpu-local counters atomic too.

We might use atomic_long_t only (and no spinlocks)
Something like this ?


[-- Attachment #2: functions --]
[-- Type: text/plain, Size: 949 bytes --]

struct percpu_counter {
	atomic_long_t count;
	atomic_long_t *counters;
};

#ifdef CONFIG_SMP
void percpu_counter_mod(struct percpu_counter *fbc, long amount)
{
	long old, new;
	atomic_long_t *pcount;

	pcount = per_cpu_ptr(fbc->counters, get_cpu());
start:
	old = atomic_long_read(pcount);
	new = old + amount;
	if (new >= FBC_BATCH || new <= -FBC_BATCH) {
		if (unlikely(atomic_long_cmpxchg(pcount, old, 0) != old))
			goto start;
		atomic_long_add(new, &fbc->count);
	} else
		atomic_long_add(amount, pcount);

	put_cpu();
}
EXPORT_SYMBOL(percpu_counter_mod);

long percpu_counter_read_accurate(struct percpu_counter *fbc)
{
	long res = 0;
	int cpu;
	atomic_long_t *pcount;

	for_each_cpu(cpu) {
		pcount = per_cpu_ptr(fbc->counters, cpu);
		/* dont dirty cache line if not necessary */
		if (atomic_long_read(pcount))
			res += atomic_long_xchg(pcount, 0);
	}
	return res;
}
EXPORT_SYMBOL(percpu_counter_read_accurate);
#endif /* CONFIG_SMP */


^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Eric Dumazet @ 2006-01-28  0:35 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Andrew Morton, kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <43DABAA4.8040208@cosmosbay.com>

Eric Dumazet a écrit :
> Andrew Morton a écrit :
>> Eric Dumazet <dada1@cosmosbay.com> wrote:
>>> Ravikiran G Thirumalai a écrit :
>>>> On Fri, Jan 27, 2006 at 12:16:02PM -0800, Andrew Morton wrote:
>>>>> Ravikiran G Thirumalai <kiran@scalex86.org> wrote:
>>>>>> which can be assumed as not frequent.  At 
>>>>>> sk_stream_mem_schedule(), read_sockets_allocated() is invoked only 
>>>>>> certain conditions, under memory pressure -- on a large CPU count 
>>>>>> machine, you'd have large memory, and I don't think 
>>>>>> read_sockets_allocated would get called often.  It did not atleast 
>>>>>> on our 8cpu/16G box.  So this should be OK I think.
>>>>> That being said, the percpu_counters aren't a terribly successful 
>>>>> concept
>>>>> and probably do need a revisit due to the high inaccuracy at high CPU
>>>>> counts.  It might be better to do some generic version of 
>>>>> vm_acct_memory()
>>>>> instead.
>>>> AFAICS vm_acct_memory is no better.  The deviation on large cpu 
>>>> counts is the same as percpu_counters -- (NR_CPUS * NR_CPUS * 2) ...
>>> Ah... yes you are right, I read min(16, NR_CPUS*2)
>>
>> So did I ;)
>>
>>> I wonder if it is not a typo... I mean, I understand the more cpus 
>>> you have, the less updates on central atomic_t is desirable, but a 
>>> quadratic offset seems too much...
>>
>> I'm not sure whether it was a mistake or if I intended it and didn't 
>> do the
>> sums on accuracy :(
>>
>> An advantage of retaining a spinlock in percpu_counter is that if 
>> accuracy
>> is needed at a low rate (say, /proc reading) we can take the lock and 
>> then
>> go spill each CPU's local count into the main one.  It would need to be a
>> very low rate though.   Or we make the cpu-local counters atomic too.
> 
> We might use atomic_long_t only (and no spinlocks)
> Something like this ?
> 
> 
> ------------------------------------------------------------------------
> 
> struct percpu_counter {
> 	atomic_long_t count;
> 	atomic_long_t *counters;
> };
> 
> #ifdef CONFIG_SMP
> void percpu_counter_mod(struct percpu_counter *fbc, long amount)
> {
> 	long old, new;
> 	atomic_long_t *pcount;
> 
> 	pcount = per_cpu_ptr(fbc->counters, get_cpu());
> start:
> 	old = atomic_long_read(pcount);
> 	new = old + amount;
> 	if (new >= FBC_BATCH || new <= -FBC_BATCH) {
> 		if (unlikely(atomic_long_cmpxchg(pcount, old, 0) != old))
> 			goto start;
> 		atomic_long_add(new, &fbc->count);
> 	} else
> 		atomic_long_add(amount, pcount);
> 
> 	put_cpu();
> }
> EXPORT_SYMBOL(percpu_counter_mod);
> 
> long percpu_counter_read_accurate(struct percpu_counter *fbc)
> {
> 	long res = 0;
> 	int cpu;
> 	atomic_long_t *pcount;
> 
> 	for_each_cpu(cpu) {
> 		pcount = per_cpu_ptr(fbc->counters, cpu);
> 		/* dont dirty cache line if not necessary */
> 		if (atomic_long_read(pcount))
> 			res += atomic_long_xchg(pcount, 0);
> 	}

	atomic_long_add(res, &fbc->count);
	res = atomic_long_read(&fbc->count);

> 	return res;
> }
> EXPORT_SYMBOL(percpu_counter_read_accurate);
> #endif /* CONFIG_SMP */
> 

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Ravikiran G Thirumalai @ 2006-01-28  0:40 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Andrew Morton, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <43DAAAE3.2030107@cosmosbay.com>

On Sat, Jan 28, 2006 at 12:21:07AM +0100, Eric Dumazet wrote:
> Ravikiran G Thirumalai a écrit :
> >On Fri, Jan 27, 2006 at 11:30:23PM +0100, Eric Dumazet wrote:
> 
> Why not use a boot time allocated percpu area (as done today in 
> setup_per_cpu_areas()), but instead of reserving extra space for module's 
> percpu data, being able to serve alloc_percpu() from this reserved area (ie 
> no kmalloced data anymore), and keeping your

At that time ia64 placed a limit on the max size of per-CPU area 
(PERCPU_ENOUGH_ROOM).  I think that the limit is still there, But hopefully
64K per-CPU should be enough for static + dynamic + modules?

Let me do a allyesconfig on my box and verify.

Thanks,
Kiran

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Andrew Morton @ 2006-01-28  0:43 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <43DABAA4.8040208@cosmosbay.com>

Eric Dumazet <dada1@cosmosbay.com> wrote:
>
> > 
> > An advantage of retaining a spinlock in percpu_counter is that if accuracy
> > is needed at a low rate (say, /proc reading) we can take the lock and then
> > go spill each CPU's local count into the main one.  It would need to be a
> > very low rate though.   Or we make the cpu-local counters atomic too.
> 
> We might use atomic_long_t only (and no spinlocks)

Yup, that's it.

> Something like this ?
> 

It'd be a lot neater if we had atomic_long_xchg().

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Eric Dumazet @ 2006-01-28  1:10 UTC (permalink / raw)
  To: Andrew Morton; +Cc: kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060127164308.1ea4c3e5.akpm@osdl.org>

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

Andrew Morton a écrit :
> Eric Dumazet <dada1@cosmosbay.com> wrote:
>>> An advantage of retaining a spinlock in percpu_counter is that if accuracy
>>> is needed at a low rate (say, /proc reading) we can take the lock and then
>>> go spill each CPU's local count into the main one.  It would need to be a
>>> very low rate though.   Or we make the cpu-local counters atomic too.
>> We might use atomic_long_t only (and no spinlocks)
> 
> Yup, that's it.
> 
>> Something like this ?
>>
> 
> It'd be a lot neater if we had atomic_long_xchg().

You are my guest :)

[PATCH] Add atomic_long_xchg() and atomic_long_cmpxchg() wrappers

Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>



[-- Attachment #2: atomic.patch --]
[-- Type: text/plain, Size: 882 bytes --]

--- a/include/asm-generic/atomic.h	2006-01-28 02:59:49.000000000 +0100
+++ b/include/asm-generic/atomic.h	2006-01-28 02:57:36.000000000 +0100
@@ -66,6 +66,18 @@
 	atomic64_sub(i, v);
 }
 
+static inline long atomic_long_xchg(atomic_long_t *l, long val)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	return atomic64_xchg(v, val);
+}
+
+static inline long atomic_long_cmpxchg(atomic_long_t *l, long old, long new)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	return atomic64_cmpxchg(v, old, new);
+}
+
 #else
 
 typedef atomic_t atomic_long_t;
@@ -113,5 +125,17 @@
 	atomic_sub(i, v);
 }
 
+static inline long atomic_long_xchg(atomic_long_t *l, long val)
+{
+	atomic_t *v = (atomic_t *)l;
+	return atomic_xchg(v, val);
+}
+
+static inline long atomic_long_cmpxchg(atomic_long_t *l, long old, long new)
+{
+	atomic_t *v = (atomic_t *)l;
+	return atomic_cmpxchg(v, old, new);
+}
+
 #endif
 #endif

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Andrew Morton @ 2006-01-28  1:18 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <43DAC46B.3010200@cosmosbay.com>

Eric Dumazet <dada1@cosmosbay.com> wrote:
>
> [PATCH] Add atomic_long_xchg() and atomic_long_cmpxchg() wrappers
> 
> ...
>  
> +static inline long atomic_long_xchg(atomic_long_t *l, long val)
> +{
> +	atomic64_t *v = (atomic64_t *)l;
> +	return atomic64_xchg(v, val);

All we need now is some implementations of atomic64_xchg()  ;)

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Ravikiran G Thirumalai @ 2006-01-28  4:52 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Andrew Morton, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <43DABC37.6070603@cosmosbay.com>

On Sat, Jan 28, 2006 at 01:35:03AM +0100, Eric Dumazet wrote:
> Eric Dumazet a écrit :
> >Andrew Morton a écrit :
> >>Eric Dumazet <dada1@cosmosbay.com> wrote:
> >
> >#ifdef CONFIG_SMP
> >void percpu_counter_mod(struct percpu_counter *fbc, long amount)
> >{
> >	long old, new;
> >	atomic_long_t *pcount;
> >
> >	pcount = per_cpu_ptr(fbc->counters, get_cpu());
> >start:
> >	old = atomic_long_read(pcount);
> >	new = old + amount;
> >	if (new >= FBC_BATCH || new <= -FBC_BATCH) {
> >		if (unlikely(atomic_long_cmpxchg(pcount, old, 0) != old))
> >			goto start;
> >		atomic_long_add(new, &fbc->count);
> >	} else
> >		atomic_long_add(amount, pcount);
> >
> >	put_cpu();
> >}
> >EXPORT_SYMBOL(percpu_counter_mod);
> >
> >long percpu_counter_read_accurate(struct percpu_counter *fbc)
> >{
> >	long res = 0;
> >	int cpu;
> >	atomic_long_t *pcount;
> >
> >	for_each_cpu(cpu) {
> >		pcount = per_cpu_ptr(fbc->counters, cpu);
> >		/* dont dirty cache line if not necessary */
> >		if (atomic_long_read(pcount))
> >			res += atomic_long_xchg(pcount, 0);
				--------------------------->  (A)
> >	}
> 

> 	atomic_long_add(res, &fbc->count);
				--------------------------->  (B)
> 	res = atomic_long_read(&fbc->count);
> 
> >	return res;
> >}

The read is still theoritically FBC_BATCH * NR_CPUS inaccurate no?
What happens when other cpus update  their local counters at (A) and (B)?

(I am hoping we don't need percpu_counter_read_accurate anywhere yet and
this is just demo ;).  I certainly don't want to go on all cpus for read / 
add cmpxchg on the write path for the proto counters that started this 
discussion)

Thanks,
Kiran

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Eric Dumazet @ 2006-01-28  7:19 UTC (permalink / raw)
  To: Ravikiran G Thirumalai
  Cc: Andrew Morton, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060128045248.GA3584@localhost.localdomain>

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

Ravikiran G Thirumalai a écrit :
> On Sat, Jan 28, 2006 at 01:35:03AM +0100, Eric Dumazet wrote:
>> Eric Dumazet a écrit :
>>> Andrew Morton a écrit :
>>>> Eric Dumazet <dada1@cosmosbay.com> wrote:
>>>
>>> long percpu_counter_read_accurate(struct percpu_counter *fbc)
>>> {
>>> 	long res = 0;
>>> 	int cpu;
>>> 	atomic_long_t *pcount;
>>>
>>> 	for_each_cpu(cpu) {
>>> 		pcount = per_cpu_ptr(fbc->counters, cpu);
>>> 		/* dont dirty cache line if not necessary */
>>> 		if (atomic_long_read(pcount))
>>> 			res += atomic_long_xchg(pcount, 0);
> 				--------------------------->  (A)
>>> 	}
> 
>> 	atomic_long_add(res, &fbc->count);
> 				--------------------------->  (B)
>> 	res = atomic_long_read(&fbc->count);
>>
>>> 	return res;
>>> }
> 
> The read is still theoritically FBC_BATCH * NR_CPUS inaccurate no?
> What happens when other cpus update  their local counters at (A) and (B)?

Well, after  atomic_read(&some_atomic) or percpu_counter_read_accurate(&s) the 
  'value' you got may be inaccurate by whatever... You cannot 'freeze the 
atomic / percpu_counter and gets its accurate value'. All you can do is 
'atomically add/remove some value from this counter (atomic or percpu_counter))

See percpu_counter_read_accurate() as an attempt to collect all local offset 
(and atomically set them to 0) and atomically reajust the central fbc->count 
to with the sum of all these offsets. Kind of a consolidation that might be 
driven by a user request (read /proc/sys/...) or a periodic timer.



> 
> (I am hoping we don't need percpu_counter_read_accurate anywhere yet and
> this is just demo ;).  I certainly don't want to go on all cpus for read / 
> add cmpxchg on the write path for the proto counters that started this 
> discussion)

As pointed by Andrew (If you decode carefully its short sentences :) ), all 
you really need is atomic_long_xchg() (only in slow path), and 
atomic_long_{read/add} in fast path)


Eric

[-- Attachment #2: functions --]
[-- Type: text/plain, Size: 1050 bytes --]

struct percpu_counter {
	atomic_long_t count;
	atomic_long_t *counters;
};

#ifdef CONFIG_SMP
void percpu_counter_mod(struct percpu_counter *fbc, long amount)
{
        long new;
	atomic_long_t *pcount;

	pcount = per_cpu_ptr(fbc->counters, get_cpu());

        new = atomic_long_read(pcount) + amount;
 
	if (new >= FBC_BATCH || new <= -FBC_BATCH) {
                new = atomic_long_xchg(pcount, 0) + amount;
                if (new)
                        atomic_long_add(new, &fbc->count);
	} else
		atomic_long_add(amount, pcount);

	put_cpu();
}
EXPORT_SYMBOL(percpu_counter_mod);

long percpu_counter_read_accurate(struct percpu_counter *fbc)
{
	long res = 0;
	int cpu;
	atomic_long_t *pcount;

	for_each_cpu(cpu) {
		pcount = per_cpu_ptr(fbc->counters, cpu);
		/* dont dirty cache line if not necessary */
		if (atomic_long_read(pcount))
			res += atomic_long_xchg(pcount, 0);
	}
        atomic_long_add(res, &fbc->count);
        return atomic_long_read(&fbc->count);
}
EXPORT_SYMBOL(percpu_counter_read_accurate);
#endif /* CONFIG_SMP */


^ permalink raw reply

* Re: e100 oops on resume
From: Mattia Dongili @ 2006-01-28 11:53 UTC (permalink / raw)
  To: Stefan Seyfried
  Cc: Jesse Brandeburg, Olaf Kirch, Linux Kernel Mailing List, netdev
In-Reply-To: <20060126190236.GA12481@suse.de>

On Thu, Jan 26, 2006 at 08:02:37PM +0100, Stefan Seyfried wrote:
> On Wed, Jan 25, 2006 at 04:28:48PM -0800, Jesse Brandeburg wrote:
>  
> > Okay I reproduced the issue on 2.6.15.1 (with S1 sleep) and was able
> > to show that my patch that just removes e100_init_hw works okay for
> > me.  Let me know how it goes for you, I think this is a good fix.
> 
> worked for me in the Compaq Armada e500 and reportedly also fixed the
> SONY that originally uncovered it.

confirmed here too. The patch fixes S3 resume on this Sony (GR7/K)
running 2.6.16-rc1-mm3.

0000:02:08.0 Ethernet controller: Intel Corporation 82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller (rev 41)
	Subsystem: Sony Corporation Vaio PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
	Flags: bus master, medium devsel, latency 66, IRQ 9
	Memory at d0204000 (32-bit, non-prefetchable) [size=4K]
	I/O ports at 4000 [size=64]
	Capabilities: <available only to root>

thanks
-- 
mattia
:wq!

^ permalink raw reply

* Re: e100 oops on resume
From: Jesse Brandeburg @ 2006-01-28 19:53 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Stefan Seyfried, Jesse Brandeburg, Olaf Kirch,
	Linux Kernel Mailing List, netdev, Jesse Brandeburg, Jeff Kirsher
In-Reply-To: <20060128115335.GA4511@inferi.kami.home>

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

On 1/28/06, Mattia Dongili <malattia@linux.it> wrote:
> On Thu, Jan 26, 2006 at 08:02:37PM +0100, Stefan Seyfried wrote:
> > On Wed, Jan 25, 2006 at 04:28:48PM -0800, Jesse Brandeburg wrote:
> >
> > > Okay I reproduced the issue on 2.6.15.1 (with S1 sleep) and was able
> > > to show that my patch that just removes e100_init_hw works okay for
> > > me.  Let me know how it goes for you, I think this is a good fix.
> >
> > worked for me in the Compaq Armada e500 and reportedly also fixed the
> > SONY that originally uncovered it.
>
> confirmed here too. The patch fixes S3 resume on this Sony (GR7/K)
> running 2.6.16-rc1-mm3.

excellent news! thanks for testing.

Jeff, could you please apply to 2.6.16-rcX

Jesse

[-- Attachment #2: e100_resume_no_init.patch --]
[-- Type: application/octet-stream, Size: 818 bytes --]

e100: remove init_hw call to fix panic

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>

e100 seems to have had a long standing bug where e100_init_hw was being
called when it should not have been.  This caused a panic due to recent
changes that rely on correct set up in the driver, and more robust error
paths.
---

 drivers/net/e100.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/net/e100.c b/drivers/net/e100.c
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2752,8 +2752,6 @@ static int e100_resume(struct pci_dev *p
 	retval = pci_enable_wake(pdev, 0, 0);
 	if (retval)
 		DPRINTK(PROBE,ERR, "Error clearing wake events\n");
-	if(e100_hw_init(nic))
-		DPRINTK(HW, ERR, "e100_hw_init failed\n");
 
 	netif_device_attach(netdev);
 	if(netif_running(netdev))

^ permalink raw reply

* [git patches] net driver fixes
From: Jeff Garzik @ 2006-01-28 21:44 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds; +Cc: netdev, linux-kernel


Please pull from 'upstream-fixes' branch of
master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git

to receive the following updates:

 arch/ppc/syslib/mv64x60.c         |    4 -
 drivers/net/acenic.c              |    4 +
 drivers/net/b44.c                 |    5 +
 drivers/net/bonding/bond_main.c   |    2 
 drivers/net/mv643xx_eth.c         |  108 ++++++++++++++++----------------------
 drivers/net/s2io.c                |    2 
 drivers/net/wireless/orinoco_cs.c |    4 -
 include/net/ieee80211.h           |    4 -
 net/ieee80211/ieee80211_rx.c      |   22 +++++--
 net/ieee80211/ieee80211_wx.c      |   12 +++-
 10 files changed, 89 insertions(+), 78 deletions(-)

Ananda Raju:
      s2io: scatter-gather fix

Dale Farnsworth:
      mv643xx_eth: Fix spinlock recursion bug
      mv643xx_eth: Whitespace cleanup
      mv643xx_eth: Fix for building as a module

Eric Sesterhenn:
      bonding: fix ->get_settings error checking
      acenic: fix checking of read_eeprom_byte() return values

Paolo Galtieri:
      mv643xx_eth: Update dev->last_rx on packet receive

Stephen Hemminger:
      b44: fix laptop carrier detect

Valdis.Kletnieks@vt.edu:
      orinoco_cs: tweak Vcc debugging messages

Zhu Yi:
      ieee80211: Fix problem with not decrypting broadcast packets
      ieee80211: Fix iwlist scan can only show about 20 APs
      ieee80211: Fix A band min and max channel definitions

diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c
index 94ea346..1f01b7e 100644
--- a/arch/ppc/syslib/mv64x60.c
+++ b/arch/ppc/syslib/mv64x60.c
@@ -313,7 +313,7 @@ static struct platform_device mpsc1_devi
 };
 #endif
 
-#ifdef CONFIG_MV643XX_ETH
+#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
 static struct resource mv64x60_eth_shared_resources[] = {
 	[0] = {
 		.name	= "ethernet shared base",
@@ -456,7 +456,7 @@ static struct platform_device *mv64x60_p
 	&mpsc0_device,
 	&mpsc1_device,
 #endif
-#ifdef CONFIG_MV643XX_ETH
+#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
 	&mv64x60_eth_shared_device,
 #endif
 #ifdef CONFIG_MV643XX_ETH_0
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index b8953de..b508812 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -1002,6 +1002,8 @@ static int __devinit ace_init(struct net
 
 	mac1 = 0;
 	for(i = 0; i < 4; i++) {
+		int tmp;
+
 		mac1 = mac1 << 8;
 		tmp = read_eeprom_byte(dev, 0x8c+i);
 		if (tmp < 0) {
@@ -1012,6 +1014,8 @@ static int __devinit ace_init(struct net
 	}
 	mac2 = 0;
 	for(i = 4; i < 8; i++) {
+		int tmp;
+
 		mac2 = mac2 << 8;
 		tmp = read_eeprom_byte(dev, 0x8c+i);
 		if (tmp < 0) {
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index df9d6e8..c3267e4 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1399,7 +1399,6 @@ static int b44_open(struct net_device *d
 	b44_init_rings(bp);
 	b44_init_hw(bp);
 
-	netif_carrier_off(dev);
 	b44_check_phy(bp);
 
 	err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
@@ -1464,7 +1463,7 @@ static int b44_close(struct net_device *
 #endif
 	b44_halt(bp);
 	b44_free_rings(bp);
-	netif_carrier_off(bp->dev);
+	netif_carrier_off(dev);
 
 	spin_unlock_irq(&bp->lock);
 
@@ -2000,6 +1999,8 @@ static int __devinit b44_init_one(struct
 	dev->irq = pdev->irq;
 	SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
 
+	netif_carrier_off(dev);
+
 	err = b44_get_invariants(bp);
 	if (err) {
 		printk(KERN_ERR PFX "Problem fetching invariants of chip, "
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 2582d98..4ff006c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -576,7 +576,7 @@ static int bond_update_speed_duplex(stru
 	slave->duplex = DUPLEX_FULL;
 
 	if (slave_dev->ethtool_ops) {
-		u32 res;
+		int res;
 
 		if (!slave_dev->ethtool_ops->get_settings) {
 			return -1;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 40ae36b..7ef4b04 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -444,6 +444,7 @@ static int mv643xx_eth_receive_queue(str
 			netif_rx(skb);
 #endif
 		}
+		dev->last_rx = jiffies;
 	}
 
 	return received_packets;
@@ -461,7 +462,7 @@ static int mv643xx_eth_receive_queue(str
  */
 
 static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
-							struct pt_regs *regs)
+						struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
 	struct mv643xx_private *mp = netdev_priv(dev);
@@ -1047,16 +1048,15 @@ static int mv643xx_poll(struct net_devic
 
 static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb)
 {
-        unsigned int frag;
-        skb_frag_t *fragp;
+	unsigned int frag;
+	skb_frag_t *fragp;
 
-        for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
-                fragp = &skb_shinfo(skb)->frags[frag];
-                if (fragp->size <= 8 && fragp->page_offset & 0x7)
-                        return 1;
-
-        }
-        return 0;
+	for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+		fragp = &skb_shinfo(skb)->frags[frag];
+		if (fragp->size <= 8 && fragp->page_offset & 0x7)
+			return 1;
+	}
+	return 0;
 }
 
 
@@ -2137,26 +2137,26 @@ static void eth_port_set_multicast_list(
 	 */
 	if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) {
 		for (table_index = 0; table_index <= 0xFC; table_index += 4) {
-			 /* Set all entries in DA filter special multicast
-			  * table (Ex_dFSMT)
-			  * Set for ETH_Q0 for now
-			  * Bits
-			  * 0	  Accept=1, Drop=0
-			  * 3-1  Queue	 ETH_Q0=0
-			  * 7-4  Reserved = 0;
-			  */
-			 mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
-
-			 /* Set all entries in DA filter other multicast
-			  * table (Ex_dFOMT)
-			  * Set for ETH_Q0 for now
-			  * Bits
-			  * 0	  Accept=1, Drop=0
-			  * 3-1  Queue	 ETH_Q0=0
-			  * 7-4  Reserved = 0;
-			  */
-			 mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
-       	}
+			/* Set all entries in DA filter special multicast
+			 * table (Ex_dFSMT)
+			 * Set for ETH_Q0 for now
+			 * Bits
+			 * 0	  Accept=1, Drop=0
+			 * 3-1  Queue	 ETH_Q0=0
+			 * 7-4  Reserved = 0;
+			 */
+			mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
+
+			/* Set all entries in DA filter other multicast
+			 * table (Ex_dFOMT)
+			 * Set for ETH_Q0 for now
+			 * Bits
+			 * 0	  Accept=1, Drop=0
+			 * 3-1  Queue	 ETH_Q0=0
+			 * 7-4  Reserved = 0;
+			 */
+			mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
+		}
 		return;
 	}
 
@@ -2617,7 +2617,6 @@ static ETH_FUNC_RET_STATUS eth_port_send
 	struct eth_tx_desc *current_descriptor;
 	struct eth_tx_desc *first_descriptor;
 	u32 command;
-	unsigned long flags;
 
 	/* Do not process Tx ring in case of Tx ring resource error */
 	if (mp->tx_resource_err)
@@ -2634,8 +2633,6 @@ static ETH_FUNC_RET_STATUS eth_port_send
 		return ETH_ERROR;
 	}
 
-	spin_lock_irqsave(&mp->lock, flags);
-
 	mp->tx_ring_skbs++;
 	BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
 
@@ -2685,15 +2682,11 @@ static ETH_FUNC_RET_STATUS eth_port_send
 		mp->tx_resource_err = 1;
 		mp->tx_curr_desc_q = tx_first_desc;
 
-		spin_unlock_irqrestore(&mp->lock, flags);
-
 		return ETH_QUEUE_LAST_RESOURCE;
 	}
 
 	mp->tx_curr_desc_q = tx_next_desc;
 
-	spin_unlock_irqrestore(&mp->lock, flags);
-
 	return ETH_OK;
 }
 #else
@@ -2704,14 +2697,11 @@ static ETH_FUNC_RET_STATUS eth_port_send
 	int tx_desc_used;
 	struct eth_tx_desc *current_descriptor;
 	unsigned int command_status;
-	unsigned long flags;
 
 	/* Do not process Tx ring in case of Tx ring resource error */
 	if (mp->tx_resource_err)
 		return ETH_QUEUE_FULL;
 
-	spin_lock_irqsave(&mp->lock, flags);
-
 	mp->tx_ring_skbs++;
 	BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
 
@@ -2742,12 +2732,9 @@ static ETH_FUNC_RET_STATUS eth_port_send
 	/* Check for ring index overlap in the Tx desc ring */
 	if (tx_desc_curr == tx_desc_used) {
 		mp->tx_resource_err = 1;
-
-		spin_unlock_irqrestore(&mp->lock, flags);
 		return ETH_QUEUE_LAST_RESOURCE;
 	}
 
-	spin_unlock_irqrestore(&mp->lock, flags);
 	return ETH_OK;
 }
 #endif
@@ -2898,8 +2885,10 @@ static ETH_FUNC_RET_STATUS eth_port_rece
 	p_pkt_info->return_info = mp->rx_skb[rx_curr_desc];
 	p_pkt_info->l4i_chk = p_rx_desc->buf_size;
 
-	/* Clean the return info field to indicate that the packet has been */
-	/* moved to the upper layers					    */
+	/*
+	 * Clean the return info field to indicate that the
+	 * packet has been moved to the upper layers
+	 */
 	mp->rx_skb[rx_curr_desc] = NULL;
 
 	/* Update current index in data structure */
@@ -2980,7 +2969,7 @@ struct mv643xx_stats {
 };
 
 #define MV643XX_STAT(m) sizeof(((struct mv643xx_private *)0)->m), \
-		      offsetof(struct mv643xx_private, m)
+					offsetof(struct mv643xx_private, m)
 
 static const struct mv643xx_stats mv643xx_gstrings_stats[] = {
 	{ "rx_packets", MV643XX_STAT(stats.rx_packets) },
@@ -3131,9 +3120,8 @@ mv643xx_get_settings(struct net_device *
 	return 0;
 }
 
-static void
-mv643xx_get_drvinfo(struct net_device *netdev,
-                       struct ethtool_drvinfo *drvinfo)
+static void mv643xx_get_drvinfo(struct net_device *netdev,
+				struct ethtool_drvinfo *drvinfo)
 {
 	strncpy(drvinfo->driver,  mv643xx_driver_name, 32);
 	strncpy(drvinfo->version, mv643xx_driver_version, 32);
@@ -3142,39 +3130,37 @@ mv643xx_get_drvinfo(struct net_device *n
 	drvinfo->n_stats = MV643XX_STATS_LEN;
 }
 
-static int 
-mv643xx_get_stats_count(struct net_device *netdev)
+static int mv643xx_get_stats_count(struct net_device *netdev)
 {
 	return MV643XX_STATS_LEN;
 }
 
-static void 
-mv643xx_get_ethtool_stats(struct net_device *netdev, 
-		struct ethtool_stats *stats, uint64_t *data)
+static void mv643xx_get_ethtool_stats(struct net_device *netdev,
+				struct ethtool_stats *stats, uint64_t *data)
 {
 	struct mv643xx_private *mp = netdev->priv;
 	int i;
 
 	eth_update_mib_counters(mp);
 
-	for(i = 0; i < MV643XX_STATS_LEN; i++) {
+	for (i = 0; i < MV643XX_STATS_LEN; i++) {
 		char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset;	
-		data[i] = (mv643xx_gstrings_stats[i].sizeof_stat == 
+		data[i] = (mv643xx_gstrings_stats[i].sizeof_stat ==
 			sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p;
 	}
 }
 
-static void 
-mv643xx_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
+static void mv643xx_get_strings(struct net_device *netdev, uint32_t stringset,
+				uint8_t *data)
 {
 	int i;
 
 	switch(stringset) {
 	case ETH_SS_STATS:
 		for (i=0; i < MV643XX_STATS_LEN; i++) {
-			memcpy(data + i * ETH_GSTRING_LEN, 
-			mv643xx_gstrings_stats[i].stat_string,
-			ETH_GSTRING_LEN);
+			memcpy(data + i * ETH_GSTRING_LEN,
+					mv643xx_gstrings_stats[i].stat_string,
+					ETH_GSTRING_LEN);
 		}
 		break;
 	}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 89c4678..49b597c 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -3586,7 +3586,7 @@ static int s2io_xmit(struct sk_buff *skb
 		txdp->Buffer_Pointer = (u64) pci_map_page
 		    (sp->pdev, frag->page, frag->page_offset,
 		     frag->size, PCI_DMA_TODEVICE);
-		txdp->Control_1 |= TXD_BUFFER0_SIZE(frag->size);
+		txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
 		if (skb_shinfo(skb)->ufo_size)
 			txdp->Control_1 |= TXD_UFO_EN;
 	}
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index b664708..3c128b6 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -261,13 +261,13 @@ orinoco_cs_config(dev_link_t *link)
 		/* Note that the CIS values need to be rescaled */
 		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
 			if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, cfg CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
 				if (!ignore_cis_vcc)
 					goto next_entry;
 			}
 		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
 			if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
+				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, dflt CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
 				if(!ignore_cis_vcc)
 					goto next_entry;
 			}
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index df05f46..9a92aef 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -803,9 +803,9 @@ enum ieee80211_state {
 #define IEEE80211_24GHZ_MAX_CHANNEL 14
 #define IEEE80211_24GHZ_CHANNELS    14
 
-#define IEEE80211_52GHZ_MIN_CHANNEL 36
+#define IEEE80211_52GHZ_MIN_CHANNEL 34
 #define IEEE80211_52GHZ_MAX_CHANNEL 165
-#define IEEE80211_52GHZ_CHANNELS    32
+#define IEEE80211_52GHZ_CHANNELS    131
 
 enum {
 	IEEE80211_CH_PASSIVE_ONLY = (1 << 0),
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 7a12180..695d047 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -350,6 +350,7 @@ int ieee80211_rx(struct ieee80211_device
 	u8 src[ETH_ALEN];
 	struct ieee80211_crypt_data *crypt = NULL;
 	int keyidx = 0;
+	int can_be_decrypted = 0;
 
 	hdr = (struct ieee80211_hdr_4addr *)skb->data;
 	stats = &ieee->stats;
@@ -410,12 +411,23 @@ int ieee80211_rx(struct ieee80211_device
 		return 1;
 	}
 
-	if (is_multicast_ether_addr(hdr->addr1)
-	    ? ieee->host_mc_decrypt : ieee->host_decrypt) {
+	can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||
+			    is_broadcast_ether_addr(hdr->addr2)) ?
+	    ieee->host_mc_decrypt : ieee->host_decrypt;
+
+	if (can_be_decrypted) {
 		int idx = 0;
-		if (skb->len >= hdrlen + 3)
+		if (skb->len >= hdrlen + 3) {
+			/* Top two-bits of byte 3 are the key index */
 			idx = skb->data[hdrlen + 3] >> 6;
+		}
+
+		/* ieee->crypt[] is WEP_KEY (4) in length.  Given that idx
+		 * is only allowed 2-bits of storage, no value of idx can
+		 * be provided via above code that would result in idx
+		 * being out of range */
 		crypt = ieee->crypt[idx];
+
 #ifdef NOT_YET
 		sta = NULL;
 
@@ -553,7 +565,7 @@ int ieee80211_rx(struct ieee80211_device
 
 	/* skb: hdr + (possibly fragmented, possibly encrypted) payload */
 
-	if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+	if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
 	    (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
 		goto rx_dropped;
 
@@ -617,7 +629,7 @@ int ieee80211_rx(struct ieee80211_device
 
 	/* skb: hdr + (possible reassembled) full MSDU payload; possibly still
 	 * encrypted/authenticated */
-	if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+	if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
 	    ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
 		goto rx_dropped;
 
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 23e1630..f87c6b8 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -232,15 +232,18 @@ static char *ipw2100_translate_scan(stru
 	return start;
 }
 
+#define SCAN_ITEM_SIZE 128
+
 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 			  struct iw_request_info *info,
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ieee80211_network *network;
 	unsigned long flags;
+	int err = 0;
 
 	char *ev = extra;
-	char *stop = ev + IW_SCAN_MAX_DATA;
+	char *stop = ev + wrqu->data.length;
 	int i = 0;
 
 	IEEE80211_DEBUG_WX("Getting scan\n");
@@ -249,6 +252,11 @@ int ieee80211_wx_get_scan(struct ieee802
 
 	list_for_each_entry(network, &ieee->network_list, list) {
 		i++;
+		if (stop - ev < SCAN_ITEM_SIZE) {
+			err = -E2BIG;
+			break;
+		}
+
 		if (ieee->scan_age == 0 ||
 		    time_after(network->last_scanned + ieee->scan_age, jiffies))
 			ev = ipw2100_translate_scan(ieee, ev, stop, network);
@@ -270,7 +278,7 @@ int ieee80211_wx_get_scan(struct ieee802
 
 	IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
 
-	return 0;
+	return err;
 }
 
 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,

^ permalink raw reply related

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Benjamin LaHaise @ 2006-01-29  0:44 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Andrew Morton, kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <43DABAA4.8040208@cosmosbay.com>

On Sat, Jan 28, 2006 at 01:28:20AM +0100, Eric Dumazet wrote:
> We might use atomic_long_t only (and no spinlocks)
> Something like this ?

Erk, complex and slow...  Try using local_t instead, which is substantially 
cheaper on the P4 as it doesn't use the lock prefix and act as a memory 
barrier.  See asm/local.h.

		-ben

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Andrew Morton @ 2006-01-29  0:55 UTC (permalink / raw)
  To: Benjamin LaHaise; +Cc: dada1, kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060129004459.GA24099@kvack.org>

Benjamin LaHaise <bcrl@kvack.org> wrote:
>
> On Sat, Jan 28, 2006 at 01:28:20AM +0100, Eric Dumazet wrote:
> > We might use atomic_long_t only (and no spinlocks)
> > Something like this ?
> 
> Erk, complex and slow...  Try using local_t instead, which is substantially 
> cheaper on the P4 as it doesn't use the lock prefix and act as a memory 
> barrier.  See asm/local.h.
> 

local_t isn't much use until we get rid of asm-generic/local.h.  Bloaty,
racy with nested interrupts.

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Benjamin LaHaise @ 2006-01-29  1:19 UTC (permalink / raw)
  To: Andrew Morton; +Cc: dada1, kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060128165549.262f2b90.akpm@osdl.org>

On Sat, Jan 28, 2006 at 04:55:49PM -0800, Andrew Morton wrote:
> local_t isn't much use until we get rid of asm-generic/local.h.  Bloaty,
> racy with nested interrupts.

The overuse of atomics is horrific in what is being proposed.  All the
major architectures except powerpc (i386, x86-64, ia64, and sparc64) 
implement local_t.  It would make far more sense to push the last few 
stragglers (which mostly seem to be uniprocessor) into writing the 
appropriate implementations.  Perhaps it's time to add a #error in 
asm-generic/local.h?

		-ben
-- 
"Ladies and gentlemen, I'm sorry to interrupt, but the police are here 
and they've asked us to stop the party."  Don't Email: <dont@kvack.org>.

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Andrew Morton @ 2006-01-29  1:29 UTC (permalink / raw)
  To: Benjamin LaHaise; +Cc: dada1, kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060129011944.GB24099@kvack.org>

Benjamin LaHaise <bcrl@kvack.org> wrote:
>
> On Sat, Jan 28, 2006 at 04:55:49PM -0800, Andrew Morton wrote:
> > local_t isn't much use until we get rid of asm-generic/local.h.  Bloaty,
> > racy with nested interrupts.
> 
> The overuse of atomics is horrific in what is being proposed.

Well yeah, it wasn't really a very serious proposal.  There's some
significant work yet to be done on this stuff.

> Perhaps it's time to add a #error in asm-generic/local.h?

heh, or #warning "you suck" or something.

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Kyle McMartin @ 2006-01-29  1:45 UTC (permalink / raw)
  To: Benjamin LaHaise
  Cc: Andrew Morton, dada1, kiran, davem, linux-kernel, shai, netdev,
	pravins
In-Reply-To: <20060129011944.GB24099@kvack.org>

On Sat, Jan 28, 2006 at 08:19:44PM -0500, Benjamin LaHaise wrote:
> The overuse of atomics is horrific in what is being proposed.  All the
> major architectures except powerpc (i386, x86-64, ia64, and sparc64) 
> implement local_t.  It would make far more sense to push the last few 
> stragglers (which mostly seem to be uniprocessor) into writing the 
> appropriate implementations.  Perhaps it's time to add a #error in 
> asm-generic/local.h?
>

Surely asm-generic/local.h could now be reimplemented using atomic_long_t
to kill that aberration that is the BITS_PER_LONG != 32 case currently...? 

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Andi Kleen @ 2006-01-29  5:38 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Benjamin LaHaise, dada1, kiran, davem, linux-kernel, shai, netdev,
	pravins, linux-arch
In-Reply-To: <20060128165549.262f2b90.akpm@osdl.org>

[adding linux-arch]

On Sunday 29 January 2006 01:55, Andrew Morton wrote:
> Benjamin LaHaise <bcrl@kvack.org> wrote:
> > On Sat, Jan 28, 2006 at 01:28:20AM +0100, Eric Dumazet wrote:
> > > We might use atomic_long_t only (and no spinlocks)
> > > Something like this ?
> >
> > Erk, complex and slow...  Try using local_t instead, which is
> > substantially cheaper on the P4 as it doesn't use the lock prefix and act
> > as a memory barrier.  See asm/local.h.
>
> local_t isn't much use until we get rid of asm-generic/local.h.  Bloaty,
> racy with nested interrupts.

It is just implemented wrong. It should use 
local_irq_save()/local_irq_restore() instead. But my bigger problem
with local_t is these few architectures (IA64, PPC64) who implement it 
with atomic_t. This means we can't replace local statistics counters
with local_t because it would be regression for them. I haven't done the
benchmarks yet, but I suspect both IA64 and PPC64 really should
just turn off interrupts.

-Andi

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Eric Dumazet @ 2006-01-29  6:54 UTC (permalink / raw)
  To: Benjamin LaHaise
  Cc: Andrew Morton, kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <20060129004459.GA24099@kvack.org>

Benjamin LaHaise a écrit :
> On Sat, Jan 28, 2006 at 01:28:20AM +0100, Eric Dumazet wrote:
>> We might use atomic_long_t only (and no spinlocks)
>> Something like this ?
> 
> Erk, complex and slow...  Try using local_t instead, which is substantially 
> cheaper on the P4 as it doesn't use the lock prefix and act as a memory 
> barrier.  See asm/local.h.
> 

Well, I think that might be doable, maybe RCU magic ?

1) local_t are not that nice on all archs.

2) The consolidation phase (summing all the cpus local offset to consolidate 
the central counter) might be more difficult to do (we would need kind of 2 
counters per cpu, and a index that can be changed by the cpu that wants a 
consolidation (still 'expensive'))

struct cpu_offset {
	local_t   offset[2];
	};

struct percpu_counter {
	atomic_long_t count;
	unsigned int offidx;
	spinlock_t   lock; /* to guard offidx changes */
	cpu_offset *counters;
};

void percpu_counter_mod(struct percpu_counter *fbc, long amount)
{
         long val;
	struct cpu_offset *cp;
	local_t *l;

	cp = per_cpu_ptr(fbc->counters, get_cpu());
	l = &cp[fbc->offidx];

         local_add(amount, l);
	val = local_read(l);
	if (new >= FBC_BATCH || new <= -FBC_BATCH) {
                 local_set(l, 0);
                 atomic_long_add(val, &fbc->count);
	}
	put_cpu();
}

long percpu_counter_read_accurate(struct percpu_counter *fbc)
{
	long res = 0, val;
	int cpu;
	struct cpu_offset *cp;
	local_t *l;

	spin_lock(&fbc->lock);
	idx = fbc->offidx;
	fbc->offidx ^= 1;
	mb();
	/*
	 * FIXME :
	 *	must 'wait' other cpus dont touch anymore their old local_t
	 */
	for_each_cpu(cpu) {
		cp = per_cpu_ptr(fbc->counters, cpu);
		l = &cp[idx];
		val = local_read(l);
		/* dont dirty alien cache line if not necessary */
		if (val)
			local_set(l, 0);
		res += val;
	}
	spin_unlock(&fbc->lock);
         atomic_long_add(res, &fbc->count);
         return atomic_long_read(&fbc->count);
}



3) Are the locked ops so expensive if done on a cache line that is mostly in 
exclusive state in cpu cache ?

Thank you
Eric

^ permalink raw reply

* Re: [GIT PULL] bcm43xx update
From: Michael Buesch @ 2006-01-29 10:38 UTC (permalink / raw)
  To: John W. Linville
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, bcm43xx-dev-0fE9KPoRgkgATYTw5x5z8w
In-Reply-To: <200601271842.54347.mbuesch-KuiJ5kEpwI6ELgA04lAiVw@public.gmane.org>

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

On Friday 27 January 2006 18:42, you wrote:
> Please do a
> git pull git://bu3sch.de/bcm43xx.git master-upstream
> to pull the bcm43xx-softmac branch.
> 
> Please do a
> git pull git://bu3sch.de/bcm43xx.git dscape-upstream
> to pull the bcm43xx-dscape branch.

Did you already pull? I did not see it in your git logs.
I have to do some maintainance work on my public repository
and I am waiting for your pull, before I shut down the server.

-- 
Greetings Michael.

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

^ permalink raw reply

* [PATH] acxsm: Move WEP code into softmac
From: Carlos Martín @ 2006-01-29 14:26 UTC (permalink / raw)
  To: acx100-devel; +Cc: netdev


[-- Attachment #1.1: Type: text/plain, Size: 650 bytes --]

Hi,

 This patch moves the WEP handling code to use the softmac layer and 
implements acx_e_ieee80211_set_security(), based on the rt2x00 project's one.

 I do have a couple of questions though:

1) adev->wep_restricted = 0 is the same as an open auth system, and 
adev->wep_restricted = 1 is the same as having a shared key auth system, 
right?

2) What is the purpose of the index field in key_struct_t? I've assumed it is 
the same as adev->wep_current_index, but I'm not sure this is correct.

   cmn
-- 
Carlos Martín       http://www.cmartin.tk

"Erdbeben? Sicherlich etwas, das mit Erdberen zu tun hat." -- me, paraphrased

[-- Attachment #1.2: acxsm-move-wep-into-softmac.patch --]
[-- Type: text/x-diff, Size: 13570 bytes --]

diff -urp acxsm-0123.orig/acx_struct.h acxsm-0123/acx_struct.h
--- acxsm-0123.orig/acx_struct.h	2006-01-16 15:25:41.000000000 +0100
+++ acxsm-0123/acx_struct.h	2006-01-29 14:06:17.000000000 +0100
@@ -603,31 +603,6 @@ typedef struct fw_ver {
 
 #define FW_ID_SIZE 20
 
-
-/*--- WEP stuff --------------------------------------------------------------*/
-#define DOT11_MAX_DEFAULT_WEP_KEYS	4
-
-/* non-firmware struct, no packing necessary */
-typedef struct wep_key {
-	size_t	size; /* most often used member first */
-	u8	index;
-	u8	key[29];
-	u16	strange_filler;
-} wep_key_t;			/* size = 264 bytes (33*8) */
-/* FIXME: We don't have size 264! Or is there 2 bytes beyond the key
- * (strange_filler)? */
-
-/* non-firmware struct, no packing necessary */
-typedef struct key_struct {
-	u8	addr[ETH_ALEN];	/* 0x00 */
-	u16	filler1;	/* 0x06 */
-	u32	filler2;	/* 0x08 */
-	u32	index;		/* 0x0c */
-	u16	len;		/* 0x10 */
-	u8	key[29];	/* 0x12; is this long enough??? */
-} key_struct_t;			/* size = 276. FIXME: where is the remaining space?? */
-
-
 /*--- Client (peer) info -----------------------------------------------------*/
 /* adev->sta_list[] is used for:
 ** accumulating and processing of scan results
@@ -1286,14 +1261,6 @@ struct acx_device {
 	u8		rate_supported_len;
 	u8		rate_supported[13];
 
-	/*** Encryption settings (WEP) ***/
-	u32		auth_alg;		/* used in transmit_authen1 */
-	u8		wep_enabled;
-	u8		wep_restricted;
-	u8		wep_current_index;
-	wep_key_t	wep_keys[DOT11_MAX_DEFAULT_WEP_KEYS];	/* the default WEP keys */
-	key_struct_t	wep_key_struct[10];
-
 	/*** Unknown ***/
 	u8		dtim_interval;
 
diff -urp acxsm-0123.orig/common.c acxsm-0123/common.c
--- acxsm-0123.orig/common.c	2006-01-19 11:28:23.000000000 +0100
+++ acxsm-0123/common.c	2006-01-29 14:59:46.000000000 +0100
@@ -1137,8 +1137,8 @@ acx_s_proc_diag_output(char *buf, acx_de
 		"WEP ena %d, restricted %d, idx %d\n",
 		adev->essid, adev->essid_active, (int)adev->essid_len,
 		adev->essid_for_assoc, adev->nick,
-		adev->wep_enabled, adev->wep_restricted,
-		adev->wep_current_index);
+		adev->ieee->sec.enabled, adev->ieee->sec.auth_mode,
+		adev->ieee->sec.active_key);
 	p += sprintf(p, "dev_addr  "MACSTR"\n", MAC(adev->dev_addr));
 	p += sprintf(p, "bssid     "MACSTR"\n", MAC(adev->bssid));
 	p += sprintf(p, "ap_filter "MACSTR"\n", MAC(adev->ap));
@@ -2143,7 +2143,7 @@ acx_s_set_defaults(acx_device_t *adev)
 	/* reported to break scanning: adev->scan_probe_delay = adev->cfgopt_probe_delay; */
 	adev->scan_rate = ACX_SCAN_RATE_1;
 
-	adev->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
+	adev->ieee->sec.auth_mode = WLAN_AUTH_OPEN;
 	adev->preamble_mode = 2; /* auto */
 	adev->listen_interval = 100;
 	adev->beacon_interval = DEFAULT_BEACON_INTERVAL;
@@ -5435,14 +5435,14 @@ acx100_s_set_wepkey(acx_device_t *adev)
 	ie_dot11WEPDefaultKey_t dk;
 	int i;
 
-	for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
-		if (adev->wep_keys[i].size != 0) {
+	for (i = 0; i < WEP_KEYS; i++) {
+		if (adev->ieee->sec.key_sizes[i] != 0) {
 			log(L_INIT, "setting WEP key: %d with "
-				"total size: %d\n", i, (int) adev->wep_keys[i].size);
+				"total size: %d\n", i, (int) adev->ieee->sec.key_sizes[i]);
 			dk.action = 1;
-			dk.keySize = adev->wep_keys[i].size;
+			dk.keySize = adev->ieee->sec.key_sizes[i];
 			dk.defaultKeyNum = i;
-			memcpy(dk.key, adev->wep_keys[i].key, dk.keySize);
+			memcpy(dk.key, adev->ieee->sec.keys[i], dk.keySize);
 			acx_s_configure(adev, &dk, ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE);
 		}
 	}
@@ -5454,20 +5454,20 @@ acx111_s_set_wepkey(acx_device_t *adev)
 	acx111WEPDefaultKey_t dk;
 	int i;
 
-	for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
-		if (adev->wep_keys[i].size != 0) {
+	for (i = 0; i < WEP_KEYS; i++) {
+		if (adev->ieee->sec.key_sizes[i] != 0) {
 			log(L_INIT, "setting WEP key: %d with "
-				"total size: %d\n", i, (int) adev->wep_keys[i].size);
+				"total size: %d\n", i, (int) adev->ieee->sec.key_sizes[i]);
 			memset(&dk, 0, sizeof(dk));
 			dk.action = cpu_to_le16(1); /* "add key"; yes, that's a 16bit value */
-			dk.keySize = adev->wep_keys[i].size;
+			dk.keySize = adev->ieee->sec.key_sizes[i];
 
 			/* are these two lines necessary? */
 			dk.type = 0;              /* default WEP key */
 			dk.index = 0;             /* ignored when setting default key */
 
 			dk.defaultKeyNum = i;
-			memcpy(dk.key, adev->wep_keys[i].key, dk.keySize);
+			memcpy(dk.key, adev->ieee->sec.keys[i], dk.keySize);
 			acx_s_issue_cmd(adev, ACX1xx_CMD_WEP_MGMT, &dk, sizeof(dk));
 		}
 	}
@@ -5514,7 +5514,7 @@ acx100_s_init_wep(acx_device_t *adev)
 	}
 
 	/* let's choose maximum setting: 4 default keys, plus 10 other keys: */
-	options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
+	options.NumKeys = cpu_to_le16(WEP_KEYS + 10);
 	options.WEPOption = 0x00;
 
 	log(L_ASSOC, "%s: writing WEP options\n", __func__);
@@ -5522,10 +5522,10 @@ acx100_s_init_wep(acx_device_t *adev)
 
 	acx100_s_set_wepkey(adev);
 
-	if (adev->wep_keys[adev->wep_current_index].size != 0) {
+	if (adev->ieee->sec.key_sizes[adev->ieee->sec.active_key] != 0) {
 		log(L_ASSOC, "setting active default WEP key number: %d\n",
-				adev->wep_current_index);
-		dk.KeyID = adev->wep_current_index;
+				adev->ieee->sec.active_key);
+		dk.KeyID = adev->ieee->sec.active_key;
 		acx_s_configure(adev, &dk, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET); /* 0x1010 */
 	}
 	/* FIXME!!! wep_key_struct is filled nowhere! But adev
@@ -6581,7 +6581,7 @@ acx_s_update_card_settings(acx_device_t 
 
 		acx_s_set_wepkey(adev);
 
-		dkey.KeyID = adev->wep_current_index;
+		dkey.KeyID = adev->ieee->sec.active_key;
 		log(L_INIT, "setting WEP key %u as default\n", dkey.KeyID);
 		acx_s_configure(adev, &dkey, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET);
 #ifdef DEBUG_WEP
@@ -6602,7 +6602,7 @@ acx_s_update_card_settings(acx_device_t 
 
 			/* let's choose maximum setting: 4 default keys,
 			 * plus 10 other keys: */
-			options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
+			options.NumKeys = cpu_to_le16(WEP_KEYS + 10);
 			/* don't decrypt default key only,
 			 * don't override decryption: */
 			options.WEPOption = 0;
@@ -6905,7 +6905,7 @@ acx_update_capabilities(acx_device_t *ad
 	/* other types of stations do not emit beacons */
 	}
 
-	if (adev->wep_restricted) {
+	if (adev->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY) {
 		SET_BIT(cap, WF_MGMT_CAP_PRIVACY);
 	}
 	if (adev->cfgopt_dot11ShortPreambleOption) {
@@ -7135,10 +7135,74 @@ module_exit(acx_e_cleanup_module)
 
 //SM
 void
-acx_e_ieee80211_set_security(struct net_device *dev,
+acx_e_ieee80211_set_security(struct net_device *ndev,
 		struct ieee80211_security *sec)
 {
-//todo
+/* Shamelessly copied from the rt2x00 project. */
+	acx_device_t *adev = ndev2adev(ndev);
+	unsigned long flags;
+	int i;
+
+	acx_sem_lock(adev);
+	acx_lock(adev, flags);
+
+	for (i = 0; i < WEP_KEYS; ++i) {
+		/* This gives us the flag for the 4 WEP keys. */
+		if (sec->flags & (1 << i)) {
+			adev->ieee->sec.encode_alg[i] = sec->encode_alg[i];
+			adev->ieee->sec.key_sizes[i] = sec->key_sizes[i];
+
+			if (sec->key_sizes[i] != 0) {
+				memcpy(adev->ieee->sec.keys[i], sec->keys[i],
+				       sec->key_sizes[i]);
+				/* Make sure WEP flag is set. */
+				adev->ieee->sec.flags |= (1 << i);
+			} else if (sec->level != SEC_LEVEL_1)
+				/* Make sure WEP flag isn't set. */
+				adev->ieee->sec.flags &= ~(1 << i);
+		}
+		SET_BIT(adev->set_mask, SET_WEP_OPTIONS);
+	}
+
+	if (sec->flags & SEC_ACTIVE_KEY) {
+		/* Check the key number is valid. */
+		if (sec->active_key < WEP_KEYS) {
+			adev->ieee->sec.active_key = sec->active_key;
+			adev->ieee->sec.flags |= SEC_ACTIVE_KEY;
+		} else
+			adev->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
+		
+	} else
+		adev->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
+
+	if (sec->flags & SEC_AUTH_MODE) {
+		adev->ieee->sec.auth_mode = sec->auth_mode;
+		adev->ieee->sec.flags |= SEC_AUTH_MODE;
+		SET_BIT(adev->set_mask, SET_WEP_OPTIONS);
+	}
+
+	if (sec->flags & SEC_ENCRYPT) {
+		adev->ieee->sec.encrypt = sec->encrypt;
+		adev->ieee->sec.flags |= SEC_ENCRYPT;
+		SET_BIT(adev->set_mask, GETSET_WEP);
+	}
+
+	if (sec->flags & SEC_ENABLED) {
+		adev->ieee->sec.enabled = sec->enabled;
+		adev->ieee->sec.flags |= SEC_ENABLED;
+		SET_BIT(adev->set_mask, GETSET_WEP);
+	}
+
+	if (sec->flags & SEC_LEVEL) {
+		adev->ieee->sec.level = sec->level;
+		adev->ieee->sec.flags |= SEC_LEVEL;
+		SET_BIT(adev->set_mask, GETSET_WEP);
+	}
+	
+	acx_unlock(adev, flags);
+	acx_sem_unlock(adev);
+
+	acx_s_update_card_settings(adev);
 }
 
 
diff -urp acxsm-0123.orig/ioctl.c acxsm-0123/ioctl.c
--- acxsm-0123.orig/ioctl.c	2006-01-16 15:25:41.000000000 +0100
+++ acxsm-0123/ioctl.c	2006-01-29 14:07:08.000000000 +0100
@@ -1024,7 +1024,7 @@ acx_ioctl_set_encode(
 	if (dwrq->length > 0) {
 		/* if index is 0 or invalid, use default key */
 		if ((index < 0) || (index > 3))
-			index = (int)adev->wep_current_index;
+			index = (int)adev->ieee->sec.active_key;
 
 		if (0 == (dwrq->flags & IW_ENCODE_NOKEY)) {
 			if (dwrq->length > 29)
@@ -1032,26 +1032,26 @@ acx_ioctl_set_encode(
 
 			if (dwrq->length > 13) {
 				/* 29*8 == 232, WEP256 */
-				adev->wep_keys[index].size = 29;
+				adev->ieee->sec.key_sizes[index] = 29;
 			} else if (dwrq->length > 5) {
 				/* 13*8 == 104bit, WEP128 */
-				adev->wep_keys[index].size = 13;
+				adev->ieee->sec.key_sizes[index] = 13;
 			} else if (dwrq->length > 0) {
 				/* 5*8 == 40bit, WEP64 */
-				adev->wep_keys[index].size = 5;
+				adev->ieee->sec.key_sizes[index] = 5;
 			} else {
 				/* disable key */
-				adev->wep_keys[index].size = 0;
+				adev->ieee->sec.key_sizes[index] = 0;
 			}
 
-			memset(adev->wep_keys[index].key, 0,
-				sizeof(adev->wep_keys[index].key));
-			memcpy(adev->wep_keys[index].key, extra, dwrq->length);
+			memset(adev->ieee->sec.keys[index], 0,
+				sizeof(adev->ieee->sec.keys[index]));
+			memcpy(adev->ieee->sec.keys[index], extra, dwrq->length);
 		}
 	} else {
 		/* set transmit key */
 		if ((index >= 0) && (index <= 3))
-			adev->wep_current_index = index;
+			adev->ieee->sec.active_key = index;
 		else if (0 == (dwrq->flags & IW_ENCODE_MODE)) {
 			/* complain if we were not just setting
 			 * the key mode */
@@ -1060,15 +1060,13 @@ acx_ioctl_set_encode(
 		}
 	}
 
-	adev->wep_enabled = !(dwrq->flags & IW_ENCODE_DISABLED);
+	adev->ieee->sec.enabled = !(dwrq->flags & IW_ENCODE_DISABLED);
 
 	if (dwrq->flags & IW_ENCODE_OPEN) {
-		adev->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
-		adev->wep_restricted = 0;
+		adev->ieee->sec.auth_mode = WLAN_AUTH_OPEN;
 
 	} else if (dwrq->flags & IW_ENCODE_RESTRICTED) {
-		adev->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
-		adev->wep_restricted = 1;
+	  adev->ieee->sec.auth_mode = WLAN_AUTH_SHARED_KEY;
 	}
 
 	/* set flag to make sure the card WEP settings get updated */
@@ -1078,11 +1076,11 @@ acx_ioctl_set_encode(
 		dwrq->length, extra, dwrq->flags);
 
 	for (index = 0; index <= 3; index++) {
-		if (adev->wep_keys[index].size) {
+		if (adev->ieee->sec.key_sizes[index]) {
 			log(L_IOCTL,	"index=%d, size=%d, key at 0x%p\n",
-				adev->wep_keys[index].index,
-				(int) adev->wep_keys[index].size,
-				adev->wep_keys[index].key);
+				adev->ieee->sec.active_key,
+				(int) adev->ieee->sec.key_sizes[index],
+				adev->ieee->sec.keys[index]);
 		}
 	}
 	result = -EINPROGRESS;
@@ -1111,18 +1109,18 @@ acx_ioctl_get_encode(
 
 	FN_ENTER;
 
-	if (adev->wep_enabled == 0) {
+	if (adev->ieee->sec.enabled == 0) {
 		dwrq->flags = IW_ENCODE_DISABLED;
 	} else {
 		if ((index < 0) || (index > 3))
-			index = (int)adev->wep_current_index;
+			index = (int)adev->ieee->sec.active_key;
 
-		dwrq->flags = (adev->wep_restricted == 1) ?
+		dwrq->flags = (adev->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY) ?
 				IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN;
-		dwrq->length = adev->wep_keys[index].size;
+		dwrq->length = adev->ieee->sec.key_sizes[index];
 
-		memcpy(extra, adev->wep_keys[index].key,
-			      adev->wep_keys[index].size);
+		memcpy(extra, adev->ieee->sec.keys[index],
+			      adev->ieee->sec.key_sizes[index]);
 	}
 
 	/* set the current index */
diff -urp acxsm-0123.orig/pci.c acxsm-0123/pci.c
--- acxsm-0123.orig/pci.c	2006-01-22 16:48:35.000000000 +0100
+++ acxsm-0123/pci.c	2006-01-29 15:23:51.000000000 +0100
@@ -1641,6 +1641,10 @@ acxpci_e_probe(struct pci_dev *pdev, con
 	adev->softmac = ieee80211_priv(ndev);
 	adev->softmac->set_channel = acx_e_ieee80211_set_chan;
 
+	adev->ieee->sec.encrypt = 0;
+	adev->ieee->sec.enabled = 0;
+	adev->ieee->sec.auth_mode = WLAN_AUTH_OPEN;
+
 #ifdef NONESSENTIAL_FEATURES
 	acx_show_card_eeprom_id(adev);
 #endif /* NONESSENTIAL_FEATURES */
diff -urp acxsm-0123.orig/usb.c acxsm-0123/usb.c
--- acxsm-0123.orig/usb.c	2006-01-15 23:55:25.000000000 +0100
+++ acxsm-0123/usb.c	2006-01-28 20:59:40.000000000 +0100
@@ -677,6 +677,10 @@ acxusb_e_probe(struct usb_interface *int
 	adev->softmac = ieee80211_priv(ndev);
 	adev->softmac->set_channel = acx_e_ieee80211_set_chan;
 
+	adev->ieee->sec.enabled = 0;
+	adev->ieee->sec.encrypt = 0;
+	adev->ieee->sec.auth_mode = WLAN_AUTH_OPEN;
+
 	/* Check that this is really the hardware we know about.
 	** If not sure, at least notify the user that he
 	** may be in trouble...

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

^ permalink raw reply

* Re: [patch 3/4] net: Percpufy frequently used variables -- proto.sockets_allocated
From: Benjamin LaHaise @ 2006-01-29 19:52 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Andrew Morton, kiran, davem, linux-kernel, shai, netdev, pravins
In-Reply-To: <43DC6691.9000001@cosmosbay.com>

On Sun, Jan 29, 2006 at 07:54:09AM +0100, Eric Dumazet wrote:
> Well, I think that might be doable, maybe RCU magic ?
> 
> 1) local_t are not that nice on all archs.

It is for the users that matter, and the hooks are there if someone finds 
it to be a performance problem.

> 2) The consolidation phase (summing all the cpus local offset to 
> consolidate the central counter) might be more difficult to do (we would 
> need kind of 2 counters per cpu, and a index that can be changed by the cpu 
> that wants a consolidation (still 'expensive'))

For the vast majority of these sorts of statistics counters, we don't 
need 100% accurate counts.  And I think it should be possible to choose 
between a lightweight implementation and the expensive implementation.  
On a chip like the Core Duo the cost of bouncing between the two cores 
is minimal, so all the extra code and data is a waste.

> 3) Are the locked ops so expensive if done on a cache line that is mostly 
> in exclusive state in cpu cache ?

Yes.  What happens on the P4 is that it forces outstanding memory 
transactions in the reorder buffer to be flushed so that the memory barrier 
semantics of the lock prefix are observed.  This can take a long time as
there can be over a hundred instructions in flight.

		-ben
-- 
"Ladies and gentlemen, I'm sorry to interrupt, but the police are here 
and they've asked us to stop the party."  Don't Email: <dont@kvack.org>.

^ 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