On 9/22/2013 6:23 PM, Linus Torvalds wrote: > Alternatively, make %r13 point to the percpu side, but make sure that > you always use an asm accessor to fetch the value. In particular, I > think you need to make __my_cpu_offset be an inline asm that fetches > %r13 into some other register. Otherwise you can never get it right.
We just came up against this on tilegx with a customer bug report in a PREEMPT environment. On tile, %tp is a GPR that points to the percpu area. The following seems to be the right abstraction -- though I'd also argue that letting barrier() clobber not just memory, but %tp, might be a better solution, but it's not clear what the best way is to do per-architecture overrides of per-compiler definitions like barrier(). See also the ARM v7 code, which has to do something similar, though their percpu pointer is not a GPR, which changes the tradeoffs somewhat. register unsigned long my_cpu_offset_reg asm("tp"); #ifdef CONFIG_PREEMPT /* * For full preemption, we can't just use the register variable * directly, since we need barrier() to hazard against it, causing the * compiler to reload anything computed from a previous "tp" value. * But we also don't want to use volatile asm, since we'd like the * compiler to be able to cache the value across multiple percpu reads. * So we use a fake stack read as a hazard against barrier(). */ static inline unsigned long __my_cpu_offset(void) { unsigned long tp; register unsigned long *sp asm("sp"); asm("move %0, tp" : "=r" (tp) : "m" (*sp)); return tp; } #define __my_cpu_offset __my_cpu_offset() #else /* * We don't need to hazard against barrier() since "tp" doesn't ever * change with PREEMPT_NONE, and with PREEMPT_VOLUNTARY it only * changes at function call points, at which we are already re-reading * the value of "tp" due to "my_cpu_offset_reg" being a global variable. */ #define __my_cpu_offset my_cpu_offset_reg #endif #define set_my_cpu_offset(tp) (my_cpu_offset_reg = (tp)) -- Chris Metcalf, Tilera Corp. http://www.tilera.com -- 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/