On Wed, Dec 18, 2013 at 04:38:59PM +0100, Frederic Weisbecker wrote: > BTW this warning in __smp_call_function_single() looks wrong: > > WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled() > && !oops_in_progress) > > I think we want to warn on irqs_disabled() even if !wait, because we wait for > csd lock > anyway before raising the IPI. > > Anyway so what I need is an IPI that can be raised with irqs disabled. And > abusing the > scheduler IPI with ugliness after the other is obsviously not what we want.
Ah indeed, so you can actually make it work but its a little more involved. struct foo { struct call_single_data csd; unsigned int msg; }; static DEFINE_PER_CPU_ALIGNED(struct foo, foo_csd); /* * set @bit in @msg, return true if its the first bit set */ static bool foo_set_msg(unsigned int *msg, int bit) { unsigned int old_msg, new_msg; for (;;) { old_msg = new_msg = *msg; new_msg |= 1U << bit; if (cmpxchg(msg, old_msg, new_msg) == old_msg) break; } return old_msg == 0; } /* * clear @bit in @msg, return true if its the last bit cleared */ static bool foo_clear_msg(unsigned int *msg, int bit) { unsigned int old_msg, new_msg; for (;;) { old_msg = new_msg = *msg; new_msg &= ~(1U << bit); if (cmpxchg(msg, old_msg, new_msg) == old_msg) break; } return new_msg == 0; } /* * handle @bit msg */ static void foo_handle_msg(int bit) { switch (bit) { case 0: /* .... */ break; /* ... */ } } static void foo_call(void *info) { struct foo *foo_csd = info; int bit; for (;;) { for (bit = 0; bit < 32; bit++) { if (ACCESS_ONCE(foo_csd->msg) & (1U << bit)) { foo_handle_msg(bit); if (foo_clear_msg(bit)) return; } } } } int foo_init(void) { int cpu; for_each_possible_cpu(cpu) { struct foo *foo_csd = &per_cpu(foo_csd, cpu); foo_csd->csd.flags = 0; foo_csd->csd.func = foo_call; foo_csd->csd.info = foo_csd; foo_csd->msg = 0; } return 0; } void foo_msg(int cpu, int bit) { struct foo *foo_csd = &per_cpu(foo_csd, cpu); /* * Only send the IPI if this is the first msg bit set; * otherwise the handler is already pending/running and * will pick it up. * * This will not deadlock on csd_lock because the atomic * msg manipulation ensures there's only ever one csd per cpu * active. */ if (foo_set_msg(&foo_csd->msg, bit)) __smp_call_function_single(cpu, &foo_csd->csd, 0); } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/