Re: [PATCH 1/11] Add generic helpers for arch IPI function calls

Previous thread: [PATCH 0/4] Verification and debugging of memory initialisation V3 by Mel Gorman on Tuesday, April 22, 2008 - 11:31 am. (7 messages)

Next thread: drivers/net/ucc_geth.c compile error by Adrian Bunk on Tuesday, April 22, 2008 - 11:49 am. (1 message)
From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

Hi,

OK, so here's version #2 of the patchset. Changes since the last
posting:

- Better Kconfig setup, thanks Sam.
- Fix data leak, thanks Linus.
- Misplaced sparc64 bit in the s390 patch, thanks Martin.
- Arm should work, thanks Catalin.

-- 
Jens Axboe


--

From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts parisc to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single(). Not tested,
not even compiled.

Cc: Kyle McMartin <kyle@parisc-linux.org>
Cc: Matthew Wilcox <matthew@wil.cx>
Cc: Grant Grundler <grundler@parisc-linux.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/parisc/Kconfig      |    1 +
 arch/parisc/kernel/smp.c |  134 +++++++--------------------------------------
 2 files changed, 22 insertions(+), 113 deletions(-)

diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index bc7a19d..a7d4fd3 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -199,6 +199,7 @@ endchoice
 
 config SMP
 	bool "Symmetric multi-processing support"
+	select USE_GENERIC_SMP_HELPERS
 	---help---
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 85fc775..126105c 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -84,19 +84,11 @@ EXPORT_SYMBOL(cpu_possible_map);
 
 DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED;
 
-struct smp_call_struct {
-	void (*func) (void *info);
-	void *info;
-	long wait;
-	atomic_t unstarted_count;
-	atomic_t unfinished_count;
-};
-static volatile struct smp_call_struct *smp_call_function_data;
-
 enum ipi_message_type {
 	IPI_NOP=0,
 	IPI_RESCHEDULE=1,
 	IPI_CALL_FUNC,
+	IPI_CALL_FUNC_SINGLE,
 	IPI_CPU_START,
 	IPI_CPU_STOP,
 	IPI_CPU_TEST
@@ -187,33 +179,12 @@ ipi_interrupt(int irq, void *dev_id)
 
 			case IPI_CALL_FUNC:
 				smp_debug(100, KERN_DEBUG "CPU%d IPI_CALL_FUNC\n", this_cpu);
-				{
-					volatile struct smp_call_struct *data;
-					void (*func)(void *info);
-					void *info;
-					int wait;
-
-					data = smp_call_function_data;
-					func = data->func;
-					info = data->info;
-					wait = data->wait;
-
-					mb();
-					atomic_dec ...
From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts sh to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single(). Not tested,
but it compiles.

Cc: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/sh/Kconfig      |    1 +
 arch/sh/kernel/smp.c |   48 ++++++++----------------------------------------
 include/asm-sh/smp.h |   12 ++----------
 3 files changed, 11 insertions(+), 50 deletions(-)

diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 6a679c3..60cfdf5 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -698,6 +698,7 @@ config CRASH_DUMP
 config SMP
 	bool "Symmetric multi-processing support"
 	depends on SYS_SUPPORTS_SMP
+	select USE_GENERIC_SMP_HELPERS
 	---help---
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 5d039d1..2ed8dce 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -36,13 +36,6 @@ EXPORT_SYMBOL(cpu_possible_map);
 cpumask_t cpu_online_map;
 EXPORT_SYMBOL(cpu_online_map);
 
-static atomic_t cpus_booted = ATOMIC_INIT(0);
-
-/*
- * Run specified function on a particular processor.
- */
-void __smp_call_function(unsigned int cpu);
-
 static inline void __init smp_store_cpu_info(unsigned int cpu)
 {
 	struct sh_cpuinfo *c = cpu_data + cpu;
@@ -178,42 +171,17 @@ void smp_send_stop(void)
 	smp_call_function(stop_this_cpu, 0, 1, 0);
 }
 
-struct smp_fn_call_struct smp_fn_call = {
-	.lock		= __SPIN_LOCK_UNLOCKED(smp_fn_call.lock),
-	.finished	= ATOMIC_INIT(0),
-};
-
-/*
- * The caller of this wants the passed function to run on every cpu.  If wait
- * is set, wait until all cpus have finished the function before returning.
- * The lock is here to protect the call structure.
- * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler or from a bottom half handler.
- ...
From: Paul Mundt
Date: Friday, April 25, 2008 - 1:56 am

Acked-by: Paul Mundt <lethal@linux-sh.org>
--

From: Jens Axboe
Date: Friday, April 25, 2008 - 2:16 am

Thanks Paul!

-- 
Jens Axboe

--

From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts s390 to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single(). Not tested,
but it compiles.

Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/s390/Kconfig       |    1 +
 arch/s390/kernel/smp.c  |  160 +++--------------------------------------------
 include/asm-s390/sigp.h |    1 +
 include/asm-s390/smp.h  |    2 -
 4 files changed, 10 insertions(+), 154 deletions(-)

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index f6a68e1..b8f5fda 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -90,6 +90,7 @@ config 32BIT
 
 config SMP
 	bool "Symmetric multi-processing support"
+	select USE_GENERIC_SMP_HELPERS
 	---help---
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 0dfa988..2ee3484 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -77,164 +77,18 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
 static void smp_ext_bitcall(int, ec_bit_sig);
 
-/*
- * Structure and data for __smp_call_function_map(). This is designed to
- * minimise static memory requirements. It also looks cleaner.
- */
-static DEFINE_SPINLOCK(call_lock);
-
-struct call_data_struct {
-	void (*func) (void *info);
-	void *info;
-	cpumask_t started;
-	cpumask_t finished;
-	int wait;
-};
-
-static struct call_data_struct *call_data;
-
-/*
- * 'Call function' interrupt callback
- */
-static void do_call_function(void)
+void arch_send_call_function_ipi(cpumask_t mask)
 {
-	void (*func) (void *info) = call_data->func;
-	void *info = call_data->info;
-	int wait = call_data->wait;
-
-	cpu_set(smp_processor_id(), call_data->started);
-	(*func)(info);
-	if (wait)
-		cpu_set(smp_processor_id(), call_data->finished);;
-}
-
-static ...
From: Heiko Carstens
Date: Wednesday, April 23, 2008 - 12:58 am

Your generic patch changes semantics of smp_call_function(). At least the
s390 version of smp_call_function() mask used to not return unless all IPIs
where received on the target cpus.
Your patch changes that. It will already return as soon as all IPIs have
been sent. Unfortunately Martin's etr code in arch/s390/kernel/time.c
relies on exactly the old semantics.
Since this seems to be an s390 only issue, could you just drop the s390
conversion patch? We'll have to think about how to change the err code
and convert later I guess.
--

From: Jens Axboe
Date: Wednesday, April 23, 2008 - 1:11 am

OK, I could not see anything which relied on that and I did think that
it was a somewhat odd interface. By the time that smp_call_function()
stops waiting for startups, we could easily be in the condition that the
N-1 CPUs executed the function part a long time ago. I just didn't see
much usefulness in that, you may as well just set wait == 1 in that

I'll drop the s390 bits. I can easily add something like
smp_call_function_foo() that has this behaviour.

-- 
Jens Axboe

--

From: Jens Axboe
Date: Wednesday, April 23, 2008 - 4:21 am

I added an smp_call_function_sync() for this purpose and kept the s390
conversion, I would very much appreciate if you could look it over. I
wont post the full patchset again today, but you can inspect it here:

http://git.kernel.dk/?p=linux-2.6-block.git;a=shortlog;h=refs/heads/generic-ipi

The interesting bits are patch #1 for the generic bits and patch #11 for
the s390 part. Thanks!

-- 
Jens Axboe

--

From: Heiko Carstens
Date: Wednesday, April 23, 2008 - 4:47 am

I don't think that works: the old code also relied on the fact that there
could be only one cpu sending an smp_call_* IPI (serialized by call_lock).
The current etr code exploits that to serialize all cpus:

Do smp_call_function() to force all other cpus into clock_sync_cpu_start()
where they sort of busy wait(!). Then the master cpu is syncing the clock
and when it finished the other cpus may continue again and finally leave
the smp_call_function interrupt handler.

Your patch series however doesn't make sure anymore that there is only
one cpu doing an smp_call_function*, so we may deadlock as soon as two
cpus are trying to synchronize all cpus this way.
After all I think the etr code should be converted to use stop_machine_run
instead. However that doesn't allow for master/slave cpus.
--

From: Martin Schwidefsky
Date: Wednesday, April 23, 2008 - 5:42 am

Changing the etr code to stop_machine_run() will require a common code
change. We can use the fn() parameter of stop_machine_run() for the cpu
that does the clock synchronization but all the other cpus are not just
disabled. They need to do something before going back to normal
operation,  namely waiting for the clock to get back into sync and then
reprogram the clock comparator before we can allow interrupts again.

Looking at the stop_machine() code it doesn't seem to be to hard to get
this implemented. stop_machine_run() would get a second function
argument that replaces the call to cpu_relax() in stopmachine().
The default if the additional function argument is NULL would be
cpu_relax(). For the etr sync code it would be etr_sync_cpu_start().

-- 
blue skies,
  Martin.

"Reality continues to ruin my life." - Calvin.


--

From: Rusty Russell
Date: Wednesday, April 23, 2008 - 8:56 am

Sure.  I've got changes for stop_machine planned, so please send a patch and 
I'll merge it in.

Cheers,
Rusty.
--

From: Jens Axboe
Date: Wednesday, April 23, 2008 - 4:54 am

You are right. I'll drop the code again, it would be nice to get rid of
this interface, I guess s390 can do that when they convert to the
generic helpers.

-- 
Jens Axboe

--

From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This adds kernel/smp.c which contains helpers for IPI function calls. In
addition to supporting the existing smp_call_function() in a more efficient
manner, it also adds a more scalable variant called smp_call_function_single()
for calling a given function on a single CPU only.

The core of this is based on the x86-64 patch from Nick Piggin, lots of
changes since then. "Alan D. Brunelle" <Alan.Brunelle@hp.com> has
contributed lots of fixes and suggestions as well.

Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/Kconfig        |    3 +
 include/linux/smp.h |   27 ++++-
 init/main.c         |    3 +
 kernel/Makefile     |    1 +
 kernel/smp.c        |  366 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 398 insertions(+), 2 deletions(-)
 create mode 100644 kernel/smp.c

diff --git a/arch/Kconfig b/arch/Kconfig
index 694c9af..a5a0184 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -36,3 +36,6 @@ config HAVE_KPROBES
 
 config HAVE_KRETPROBES
 	def_bool n
+
+config USE_GENERIC_SMP_HELPERS
+	def_bool n
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 55232cc..4a5418b 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -7,9 +7,19 @@
  */
 
 #include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/cpumask.h>
 
 extern void cpu_idle(void);
 
+struct call_single_data {
+	struct list_head list;
+	void (*func) (void *info);
+	void *info;
+	unsigned int flags;
+};
+
 #ifdef CONFIG_SMP
 
 #include <linux/preempt.h>
@@ -53,9 +63,23 @@ extern void smp_cpus_done(unsigned int max_cpus);
  * Call a function on all other processors
  */
 int smp_call_function(void(*func)(void *info), void *info, int retry, int wait);
-
+int smp_call_function_mask(cpumask_t mask, void(*func)(void *info), void *info,
+				int wait);
 int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
 				int retry, int wait);
+void ...
From: Peter Zijlstra
Date: Tuesday, April 22, 2008 - 1:17 pm

From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:07 pm

What deadlock are you concerned with here? Would making cfd_fallback
per-cpu make you feel better?

-- 
Jens Axboe

--

From: Peter Zijlstra
Date: Tuesday, April 22, 2008 - 11:32 pm

CPU0					  CPU1

local_irq_disable()			local_irq_disable()

					smp_call_function_single(0,..,0)
					  test_and_set_bit_lock()
					  send IPI
smp_call_function_single(1,..,0)
  while(test_and_set_bit_lock())
    cpu_relax();


This will spin forever, because it needs to handle the IPI in order to
free the cfd_fallback thingy, but can't for its waiting for it.

That particular deadlock can indeed be solved by making cfd_fallback
per-cpu.

But if you were to use multiple smp_call_function*() calls under a
single IRQ disabled, then that would not be sufficient. Now I can't
directly come up with a good reason to need to do that, but still.

You'd need somethine like:

local_irq_disable()

smp_call_function_single(n, func_a,..,0)
smp_call_function_single(m, func_b,..,0)

local_irq_enable()

And invite 3 cpus to the party while under memory pressure and you get
deadlock potential.

[ if it were both the same function, you'd want to use
  smp_call_function() and provide a mask; if it were the same cpu you'd
  want to call a function doing both ]



--

From: Jens Axboe
Date: Wednesday, April 23, 2008 - 12:49 am

Right, that is the case I was thinking of. I added per-cpu fallbacks to

I think that is plenty far off into theoretical country that we can get
by with just documenting this limitation. Nobody is doing that currently
in the kernel, and I see no practical use case for it.

-- 
Jens Axboe

--

From: Peter Zijlstra
Date: Wednesday, April 23, 2008 - 12:50 am

Agreed.

--

From: Russell King
Date: Thursday, April 24, 2008 - 3:01 pm

Probably a silly question, but what does data->refs do that
cpus_empty(data->cpumask) wouldn't do?  (as indeed ARM presently does.)

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:
--

From: Jens Axboe
Date: Friday, April 25, 2008 - 12:18 am

I guess it can be marginally slower for NR_CPUS > BITS_PER_LONG,
otherwise there's absolutely no reason to have a seperate ref counter.

-- 
Jens Axboe

--

From: Jeremy Fitzhardinge
Date: Friday, April 25, 2008 - 11:28 pm

Jes was concerned about scanning bitmasks on a 4096 CPU Altix.  I'm not 
sure its all that important, but a refcount check would definitely be 
quicker.

    J
--

From: Jes Sorensen
Date: Monday, April 28, 2008 - 12:38 am

I just felt it was silly to do a bigger test if it wasn't necessary.
Even on a 4096 CPU box it's probably barely noticeable, but if it adds
cost then I'd be in favor of keeping the slightly faster version. Maybe
it would be worth doing a branched version, one for
NR_CPUS <= BITS_PER_LONG and one for the other case?

Cheers,
Jes

--

From: Andrew Morton
Date: Friday, April 25, 2008 - 11:11 pm

and we can lose this ifdef here.

Also, init_call_single_data() is __cpuinit but isn't declared that way. 
There have been rare occasions (FRV was one) where this matters - iirc the
compiler was emitting a short-relative-addressing-form instruction which
which wasn't able to branch far enough once things were linked.  We hae
this problem in eight zillion other places, of course.  And it's a pita to
go adding __cpunit etc to the declaration because the compiler usually
won't tell us when it gets out of sync with reality.  So we could leave he

for_each_possible_cpu()?

Do we _have_ to consider all possible CPUs here?  That can be much larger


Is this a must-be-called-with-local-interrupts-enable function?  (It
doesn't say so in the covering comment) If so, a runtime check for that
would be needed - we screw that up regularly.  Ditto any other places where


A runtime check would be nice.  The get_cpu() will give us partial coverage

Sigh.  irqs are disabled, so this is a waste of CPU cycles.  With some of








cfd_fallback_used is rather mysterious - it could do with a comment at its
definition site.  I'm wondering if we should/could be doing bit_spin_lock


--

From: James Bottomley
Date: Saturday, April 26, 2008 - 7:13 am

Erm, that's a bug in the frv toolchain, isn't it?  The linker should
*never* rely on C code annotation for jump lengths ... mainly because
you can screw it all up again in the linker script, so the sectional
annotations should only be in the function body (think
-ffunction-sections)

We have exactly this problem on parisc: our standard relocation jumps
are only 17 bits (on ILP32). The linker actually lays down special
sandwich sections between individual functions (places where we jump to
as a 17 bit relative and then do another absolute jump via a pointer).
The sandwich sections should be added at final link time every place the
linker sees the relative jump is out of range.

James


--

From: David Howells
Date: Monday, April 28, 2008 - 7:25 am

The problem with FRV has to do with global variables, not functions.

With FRV, we attempt to pack as many small variables into the "small data
section" (.sdata) as we can, and then retain a pointer to it in a register.
Thus for small variables, we can use a single instruction, such as:

	LDI	@(GR16,%gprel(my_variable)),GRx

to access it.  However, this limits the offset of my_variable to be +/-2048
from GR16 because all the instructions are the same size, and that's the size
of the offset field therein.

Alternatively, we can use:

	SETHI.P	%hi(my_variable),GRy
	SETLO	%lo(my_variable),GRy
	LD	@(GRy,GR0),GRx

which obviously takes two more instructions, although they can be executed
simultaneously, and 8 more bytes of RAM/icache.

However, the compiler will assume that it should access _all_ global variables
using GPREL-addressing unless it is told otherwise.  This means that if a
global variable should not be GPREL-addressed, its *declaration* should be
annotated, as this affects how it is addressed.  Furthermore, if the variable
is *defined* in C, that definition should be annotated the same as the
declaration, otherwise it'll eat storage from .sdata rather than the
appropriate section.


Global functions are another matter.  The FRV's PC+offset call and branch
instructions have 24-bit displacements, which is fine for leaping about within
the kernel core with a single instruction.

In modules, we instead (a) suppress GPREL addressing entirely because we can't
put module variables in .sdata, and (b) make all interfunction jumps that the
assembler can't resolve into:

	SETHI.P	%hi(that_function),GRy
	SETLO	%lo(that_function),GRy
	JMPL	@(GRy,GR0)

because a 24-bit offset can only span 16MB, which isn't far enough.


We could use a GOT, but I believe that would add an extra memory access to any
memory access or jump - which I'd prefer to avoid.

David
--

From: James Bottomley
Date: Monday, April 28, 2008 - 7:43 am

Not necessarily; this is how we work on PARISC with a GOT as the ELF
spec defines.  The point is that the GOT is linker constructed, so we
only lay down GOT entries when the linker sees that relative
displacements fail, so they don't consume memory (or even get brought
into existence) in the ordinary case.  The flip side of this is that we
do double jump (relative to jump through got) for the long displacements
we can't reach.

James


--

From: Paul E. McKenney
Date: Saturday, April 26, 2008 - 5:58 pm

Where is the new smp_call_function() defined?  I see only the declaration.

Probably just blind...


But don't we need the smp_mb() -after- the CSD_FLAG_WAIT check?

We want the caller to see the effects of the on-other-CPU-called

Well, one question...  Is it really OK to clear this bit immediately?
Why don't you need to wait for a grace period to elapse before freeing it?

(OK, I eventually saw why you can't wait for a grace period, but you

To safely omit the rcu_read_lock(), Jens would need to use the in-flight
call_rcu_sched() instead of call_rcu().  In addition, if we ever get
threaded interrupts, this interrupt handler would need IRQ_NODELAY.


How about using list_for_each_entry_rcu() instead?

	list_for_each_entry_rcu(pos, &call_function_queue, csd.list) {
		int refs;

And then move the definition of "data" up to replace that of "pos".


Need an smp_mb() here, at least in the case where you are using the
fallback queue element.  See my comments in smp_call_function_mask()
for the justification -- the key point is that if the CPU sees itself
in the mask, it also needs to see the data element all filled out.

See below for a scenario requiring this.

Such a memory barrier is -not- needed for the normally allocated
queue elements.

But memory barriers are a bit ugly...  How about instead acquiring the

And the above statements are one reason that I believe you need to wait
for a grace period even when using the static fallback element.  Here
is the sequence of events that I am worried about:

o	CPU 0 is the last CPU to invoke a given queue element, and is just
	about to list_del_rcu() it.

o	CPU 1 gets the interrupt (but already did this block last time).
	It nevertheless finds the queue element, because CPU 0 has not
	yet list_del_rcu() it.

	CPU 1 is just about to execute the: 
	
		"if (!cpu_isset(cpu, data->cpumask))"

o	CPU 0 now does the list_del_rcu() that CPU 1 already has a
	reference to, and eventually invokes the ...
From: Jens Axboe
Date: Sunday, April 27, 2008 - 3:36 am

Thanks a lot! I'll go over these tomorrow, the fallback graceperiod
definitely looks valid.

-- 
Jens Axboe

--

From: Jens Axboe
Date: Sunday, April 27, 2008 - 3:30 am

We could do online CPUs and use a notifier for hotplug, but does it

If you think that is too large to inline, then can we inline anything?
It's a barrier and a andl basically, a handful of instructions perhaps?
That said, I don't care much either way. It's a sync wait, so it need




Yes I know, I can add it to the comment instead. And even if it wasn't


OK, will do. This one is to serialize data/csd stores so they are seen



Probably not for __smp_call_function_single(), but the others should be

The bit lock is smaller, but apart from that there should be zero
functional difference.

-- 
Jens Axboe

--

From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts x86 and x86-64 to use the new helpers for
smp_call_function() and friends, and adds support for
smp_call_function_single().

Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/x86/Kconfig                           |    1 +
 arch/x86/kernel/apic_32.c                  |    4 +
 arch/x86/kernel/entry_64.S                 |    3 +
 arch/x86/kernel/i8259_64.c                 |    4 +
 arch/x86/kernel/smp.c                      |  148 ++++------------------------
 arch/x86/kernel/smpcommon.c                |   56 -----------
 arch/x86/mach-voyager/voyager_smp.c        |   91 +++--------------
 arch/x86/xen/enlighten.c                   |    1 -
 arch/x86/xen/mmu.c                         |    2 +-
 arch/x86/xen/smp.c                         |  108 ++++++---------------
 include/asm-x86/hw_irq_32.h                |    1 +
 include/asm-x86/hw_irq_64.h                |    2 +
 include/asm-x86/mach-default/entry_arch.h  |    1 +
 include/asm-x86/mach-default/irq_vectors.h |    1 +
 include/asm-x86/mach-voyager/entry_arch.h  |    2 +-
 include/asm-x86/mach-voyager/irq_vectors.h |    4 +-
 include/asm-x86/smp.h                      |   10 --
 17 files changed, 84 insertions(+), 355 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 87a693c..033062e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -159,6 +159,7 @@ config GENERIC_PENDING_IRQ
 config X86_SMP
 	bool
 	depends on SMP && ((X86_32 && !X86_VOYAGER) || X86_64)
+	select USE_GENERIC_SMP_HELPERS
 	default y
 
 config X86_32_SMP
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index 6872081..750a555 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -1357,6 +1357,10 @@ void __init smp_intr_init(void)
 
 	/* IPI for generic function call */
 	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+
+	/* IPI for single call function ...
From: Jeremy Fitzhardinge
Date: Friday, April 25, 2008 - 11:44 pm

Xen vs native is a runtime choice, so you can't just statically define 
arch_send_call_function(_single)_ipi for each.  You need to define the 
arch_* functions once, make them call via smp_ops, and call into the 
respective native and Xen versions of the ipi functions.

Aside from that it looks good, with a very appealing code size reduction.

    J
--

From: Jens Axboe
Date: Sunday, April 27, 2008 - 3:23 am

Noted, I'll add it to smp_ops (like smp_call_function_mask() was

Thanks!

-- 
Jens Axboe

--

From: Jeremy Fitzhardinge
Date: Sunday, April 27, 2008 - 8:18 am

Yep, exactly.

    J
--

From: Linus Torvalds
Date: Tuesday, April 22, 2008 - 12:03 pm

[ Ingo added to cc, since this is x86-specific ]


Ok, one more comment..

Why bother with separate vectors for this?

Why not just make the single vector do

	void smp_call_function_interrupt(void)
	{
		ack_APIC_irq();
		irq_enter();
		generic_smp_call_function_single_interrupt();
		generic_smp_call_function_interrupt();
	#ifdef CONFIG_X86_32
		__get_cpu_var(irq_stat).irq_call_count++;
	#else
		add_pda(irq_call_count, 1);
	#endif
		irq_exit();
	}

since they are both doing the exact same thing anyway?

Do we really require us to be able to handle the "single" case _while_ a 
"multiple" case is busy? Aren't we running all of these things with 
interrupts disabled anyway, so that it cannot happen?

Or is it just a performance optimization?  Do we expect to really have so 
many of the multiple interrupts that it's expensive to walk the list just 
because we also had a single interrupt to another CPU? That sounds a bit 
unlikely, but if true, very interesting..

Inquiring minds want to know..

			Linus
--

From: Ingo Molnar
Date: Tuesday, April 22, 2008 - 12:12 pm

yes and i gave in - Nick and Jens wants to do some crazy stuff and they 
had the numbers. Here's the previous discussion:

  http://lkml.org/lkml/2008/2/27/125

	Ingo
--

From: Linus Torvalds
Date: Tuesday, April 22, 2008 - 12:22 pm

No, the previous discussion was about single *queues* vs single *vectors*.

I agree unconditionally with the decision to use a separate per-cpu queue 
from the shared queue (in fact, I would argue that the "mask" code might 
want to notice when the mask is just a single CPU, and turn a mask request 
into a targeted request). 

But I wonder why we want to then have two IPI target vectors, when it 
would appear to be perfectly fine and cheap to have just a single vector 
that can handle both the per-cpu case and the shared queue case (since the 
thing would tend to be one or the other, not both).

A single vector is still pefectly fine, if 99% of all usage cases are the 
targeted-to-a-single-cpu thing, because the shared queue will basically be 
empty (and you can test that without even taking any locks).

		Linus
--

From: Ingo Molnar
Date: Tuesday, April 22, 2008 - 12:26 pm

ok. In which case the reschedule vector could be consolidated into that 
as well (it's just a special single-CPU call). Then there would be no 
new vector allocations needed at all, just the renaming of 
RESCHEDULE_VECTOR to something more generic.

	Ingo
--

From: Linus Torvalds
Date: Tuesday, April 22, 2008 - 12:50 pm

Yes.

Btw, don't get me wrong - I'm not against multiple vectors per se. I just 
wonder if there is any real reason for the code duplication. 

And there certainly *can* be tons of valid reasons for it. For example, 
some of the LAPIC can only have something like two pending interrupts per 
vector, and after that IPI's would get lost.

However, since the queuing is actually done with the data structures, I 
don't think it matters for the IPI's - they don't need any hardware 
queuing at all, afaik, since even if two IPI's would be merged into one 
(due to lack of hw queueing) the IPI handling code still has its list of 
events, so it doesn't matter.

And performance can be a valid reason ("too expensive to check the shared 
queue if we only have per-cpu events"), although I$ issues can cause that 
argument to go both ways.

I was also wondering whether there are deadlock issues (ie one type of IPI 
has to complete even if a lock is held for the other type). 

So I don't dislike the patch per se, I just wanted to understand _why_ the 
IPI's wanted separate vectors.

		Linus
--

From: Nick Piggin
Date: Tuesday, April 22, 2008 - 6:11 pm

The "too expensive to check the shared queue" is one aspect of it. The
shared queue need not have events *for us* (at least, unless Jens has
changed the implementation a bit) but it can still have events that we
would need to check through.

I don't think deadlock is a problem (any more than with multiple vectors).


--

From: Jens Axboe
Date: Wednesday, April 23, 2008 - 12:08 am

That is still the case, the loop works the same way still.

To answer Linus' question on why it was done the way it was - the
thought of sharing the IPI just didn't occur to me. For performance
reasons I'd like to keep the current setup, but it's certainly a viable
alternative for archs with limited number of IPIs available (like the
mips case that Ralf has disclosed).

-- 
Jens Axboe

--

From: Linus Torvalds
Date: Tuesday, April 22, 2008 - 6:22 pm

I'm happy with it either way, but as pointed out by Ralf, for the MIPS 
version of the patch there aren't even other vectors available.

So sharing the vector is going to be a requirement on other architectures, 
maybe we should look at whether we can make it generic and peform well 
regardless?

			Linus
--

From: Nick Piggin
Date: Tuesday, April 22, 2008 - 6:36 pm

I don't think it will perform terribly _poorly_ by sharing the vector.
If you have a look at how serialised the old code is...

If there is a noticable slowdown anywhere, we could I suppose create a
2nd variant for small numbers of CPUs, or shared vector case, but I'd
say the existing code should be fine I think.
--

From: Jens Axboe
Date: Wednesday, April 23, 2008 - 5:54 am

Regarding that last comment... The reason why I'm doing this work is
because I want to use smp_call_function_single() to redirect IO
completions. So there WILL be lots of
smp_call_function_single_interrupt() interrupts, they will be a lot more
prevalent than smp_call_function() interrupts. I don't have any numbers
on this since I haven't tried collapsing them all, but I'd be surprised
if it wasn't noticable.

That said, some archs do use a single IPI for multiple actions and just
keep a bitmask of what to do in that IPI. So it would still be possible
to use a single hardware IPI to do various things, without resorting to
calling into the interrupt handler for each of them. The _single()
interrupt handler is a cheap check though, an smp memory barrier and a
list_empty() check is enough (like it currently does).

-- 
Jens Axboe

--

From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts ppc to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single().

ppc loses the timeout functionality of smp_call_function_mask() with
this change, as the generic code does not provide that.

Acked-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/powerpc/Kconfig                    |    1 +
 arch/powerpc/kernel/smp.c               |  220 ++-----------------------------
 arch/powerpc/platforms/cell/interrupt.c |    1 +
 arch/powerpc/platforms/ps3/smp.c        |    7 +-
 arch/powerpc/platforms/pseries/xics.c   |    6 +-
 arch/powerpc/sysdev/mpic.c              |    2 +-
 include/asm-powerpc/smp.h               |    5 +-
 7 files changed, 23 insertions(+), 219 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 4bb2e93..f2a985b 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -110,6 +110,7 @@ config PPC
 	select HAVE_KPROBES
 	select HAVE_KRETPROBES
 	select HAVE_LMB
+	select USE_GENERIC_SMP_HELPERS if SMP
 
 config EARLY_PRINTK
 	bool
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index be35ffa..facd49d 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -72,12 +72,8 @@ struct smp_ops_t *smp_ops;
 
 static volatile unsigned int cpu_callin_map[NR_CPUS];
 
-void smp_call_function_interrupt(void);
-
 int smt_enabled_at_boot = 1;
 
-static int ipi_fail_ok;
-
 static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
 
 #ifdef CONFIG_PPC64
@@ -99,12 +95,15 @@ void smp_message_recv(int msg)
 {
 	switch(msg) {
 	case PPC_MSG_CALL_FUNCTION:
-		smp_call_function_interrupt();
+		generic_smp_call_function_interrupt();
 		break;
 	case PPC_MSG_RESCHEDULE:
 		/* XXX Do we have to do this? */
 		set_need_resched();
 		break;
+	case PPC_MSG_CALL_FUNC_SINGLE:
+		generic_smp_call_function_single_interrupt();
+		break;
 	case PPC_MSG_DEBUGGER_BREAK:
 		if ...
From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts ia64 to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single().

Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/ia64/Kconfig      |    1 +
 arch/ia64/kernel/smp.c |  239 +++---------------------------------------------
 include/asm-ia64/smp.h |    3 -
 3 files changed, 16 insertions(+), 227 deletions(-)

diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index ed21737..beae928 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -296,6 +296,7 @@ config VIRT_CPU_ACCOUNTING
 
 config SMP
 	bool "Symmetric multi-processing support"
+	select USE_GENERIC_SMP_HELPERS
 	help
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, say N.  If you have a system with more
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index 9a9d4c4..c5dcd03 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -60,25 +60,9 @@ static struct local_tlb_flush_counts {
 
 static DEFINE_PER_CPU(unsigned int, shadow_flush_counts[NR_CPUS]) ____cacheline_aligned;
 
-
-/*
- * Structure and data for smp_call_function(). This is designed to minimise static memory
- * requirements. It also looks cleaner.
- */
-static  __cacheline_aligned DEFINE_SPINLOCK(call_lock);
-
-struct call_data_struct {
-	void (*func) (void *info);
-	void *info;
-	long wait;
-	atomic_t started;
-	atomic_t finished;
-};
-
-static volatile struct call_data_struct *call_data;
-
 #define IPI_CALL_FUNC		0
 #define IPI_CPU_STOP		1
+#define IPI_CALL_FUNC_SINGLE	2
 #define IPI_KDUMP_CPU_STOP	3
 
 /* This needs to be cacheline aligned because it is written to by *other* CPUs.  */
@@ -89,13 +73,13 @@ extern void cpu_halt (void);
 void
 lock_ipi_calllock(void)
 {
-	spin_lock_irq(&call_lock);
+	spin_lock_irq(&call_function_lock);
 }
 
 void
 unlock_ipi_calllock(void)
 ...
From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts alpha to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single().

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/alpha/Kconfig              |    1 +
 arch/alpha/kernel/core_marvel.c |    6 +-
 arch/alpha/kernel/smp.c         |  170 +++------------------------------------
 include/asm-alpha/smp.h         |    2 -
 4 files changed, 14 insertions(+), 165 deletions(-)

diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 729cdbd..dbe8c28 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -528,6 +528,7 @@ config ARCH_MAY_HAVE_PC_FDC
 config SMP
 	bool "Symmetric multi-processing support"
 	depends on ALPHA_SABLE || ALPHA_LYNX || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK || ALPHA_MARVEL
+	select USE_GENERIC_SMP_HELPERS
 	---help---
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c
index f10d2ed..45cc4f2 100644
--- a/arch/alpha/kernel/core_marvel.c
+++ b/arch/alpha/kernel/core_marvel.c
@@ -660,9 +660,9 @@ __marvel_rtc_io(u8 b, unsigned long addr, int write)
 
 #ifdef CONFIG_SMP
 		if (smp_processor_id() != boot_cpuid)
-			smp_call_function_on_cpu(__marvel_access_rtc,
-						 &rtc_access, 1, 1,
-						 cpumask_of_cpu(boot_cpuid));
+			smp_call_function_single(boot_cpuid,
+						 __marvel_access_rtc,
+						 &rtc_access, 1, 1);
 		else
 			__marvel_access_rtc(&rtc_access);
 #else
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 63c2073..95c905b 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -62,6 +62,7 @@ static struct {
 enum ipi_message_type {
 	IPI_RESCHEDULE,
 	IPI_CALL_FUNC,
+	IPI_CALL_FUNC_SINGLE,
 	IPI_CPU_STOP,
 };
 
@@ -558,51 +559,6 @@ send_ipi_message(cpumask_t to_whom, enum ipi_message_type ...
From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts arm to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single().

Fixups and testing done by Catalin Marinas <catalin.marinas@arm.com>

Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/arm/Kconfig      |    1 +
 arch/arm/kernel/smp.c |  157 +++++--------------------------------------------
 2 files changed, 16 insertions(+), 142 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d8d2532..fed48c4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -663,6 +663,7 @@ source "kernel/time/Kconfig"
 config SMP
 	bool "Symmetric Multi-Processing (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
+	select USE_GENERIC_SMP_HELPERS
 	help
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index eefae1d..6344466 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -68,20 +68,10 @@ enum ipi_msg_type {
 	IPI_TIMER,
 	IPI_RESCHEDULE,
 	IPI_CALL_FUNC,
+	IPI_CALL_FUNC_SINGLE,
 	IPI_CPU_STOP,
 };
 
-struct smp_call_struct {
-	void (*func)(void *info);
-	void *info;
-	int wait;
-	cpumask_t pending;
-	cpumask_t unfinished;
-};
-
-static struct smp_call_struct * volatile smp_call_function_data;
-static DEFINE_SPINLOCK(smp_call_function_lock);
-
 int __cpuinit __cpu_up(unsigned int cpu)
 {
 	struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
@@ -366,114 +356,15 @@ static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg)
 	local_irq_restore(flags);
 }
 
-/*
- * You must not call this function with disabled interrupts, from a
- * hardware interrupt handler, nor from a bottom half handler.
- */
-static int smp_call_function_on_cpu(void (*func)(void *info), void *info,
-				    int retry, int wait, cpumask_t callmap)
-{
-	struct ...
From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts m32r to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single(). Not tested,
not even compiled.

Cc: Hirokazu Takata <takata@linux-m32r.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/m32r/Kconfig        |    1 +
 arch/m32r/kernel/smp.c   |  128 +++++-----------------------------------------
 arch/m32r/kernel/traps.c |    3 +-
 include/asm-m32r/smp.h   |    1 +
 4 files changed, 17 insertions(+), 116 deletions(-)

diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index de153de..a5f864c 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -296,6 +296,7 @@ config PREEMPT
 
 config SMP
 	bool "Symmetric multi-processing support"
+	select USE_GENERIC_SMP_HELPERS
 	---help---
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
index c837bc1..74eb7bc 100644
--- a/arch/m32r/kernel/smp.c
+++ b/arch/m32r/kernel/smp.c
@@ -35,22 +35,6 @@
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
 
 /*
- * Structure and data for smp_call_function(). This is designed to minimise
- * static memory requirements. It also looks cleaner.
- */
-static DEFINE_SPINLOCK(call_lock);
-
-struct call_data_struct {
-	void (*func) (void *info);
-	void *info;
-	atomic_t started;
-	atomic_t finished;
-	int wait;
-} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
-
-static struct call_data_struct *call_data;
-
-/*
  * For flush_cache_all()
  */
 static DEFINE_SPINLOCK(flushcache_lock);
@@ -96,9 +80,6 @@ void smp_invalidate_interrupt(void);
 void smp_send_stop(void);
 static void stop_this_cpu(void *);
 
-int smp_call_function(void (*) (void *), void *, int, int);
-void smp_call_function_interrupt(void);
-
 void smp_send_timer(void);
 void smp_ipi_timer_interrupt(struct pt_regs *);
 void smp_local_timer_interrupt(void);
@@ ...
From: Jens Axboe
Date: Tuesday, April 22, 2008 - 11:50 am

This converts mips to use the new helpers for smp_call_function() and
friends, and adds support for smp_call_function_single(). Not tested,
but it compiles.

Cc: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
---
 arch/mips/Kconfig              |    1 +
 arch/mips/kernel/smp-mt.c      |   27 ++++++++-
 arch/mips/kernel/smp.c         |  133 +++-------------------------------------
 arch/mips/kernel/smtc.c        |    7 ++
 arch/mips/sibyte/bcm1480/smp.c |    3 +
 arch/mips/sibyte/sb1250/smp.c  |    2 +
 include/asm-mips/smp.h         |   12 +---
 7 files changed, 49 insertions(+), 136 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8724ed3..5092a9e 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1742,6 +1742,7 @@ config SMP
 	bool "Multi-Processing support"
 	depends on SYS_SUPPORTS_SMP
 	select IRQ_PER_CPU
+	select USE_GENERIC_SMP_HELPERS
 	help
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 89e6f6a..31049fc 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -38,8 +38,9 @@
 
 #define MIPS_CPU_IPI_RESCHED_IRQ 0
 #define MIPS_CPU_IPI_CALL_IRQ 1
+#define MIPS_CPU_IPI_CALL_SINGLE_IRQ 2
 
-static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
+static int cpu_ipi_resched_irq, cpu_ipi_call_irq, cpu_ipi_call_single_irq;
 
 #if 0
 static void dump_mtregisters(int vpe, int tc)
@@ -115,6 +116,11 @@ static void ipi_call_dispatch(void)
 	do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
 }
 
+static void ipi_call_single_dispatch(void)
+{
+	do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_SINGLE_IRQ);
+}
+
 static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 {
 	return IRQ_HANDLED;
@@ -127,6 +133,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static ...
From: Ralf Baechle
Date: Tuesday, April 22, 2008 - 4:18 pm

The smp-mt.c has no chance of working.  There are only two hardware
interrupts available so just using one more won't quite work.  But I like
the basic idea of this patch series.

  Ralf
--

From: Jens Axboe
Date: Wednesday, April 23, 2008 - 12:18 am

I'll switch mips over to sharing the IPI for both ipi function calls
then, thanks Ralf!

-- 
Jens Axboe

--

Previous thread: [PATCH 0/4] Verification and debugging of memory initialisation V3 by Mel Gorman on Tuesday, April 22, 2008 - 11:31 am. (7 messages)

Next thread: drivers/net/ucc_geth.c compile error by Adrian Bunk on Tuesday, April 22, 2008 - 11:49 am. (1 message)