We need the boot CPU's tvec_bases[] entry to be initialised super-early in boot, for early_serial_setup(). That runs within setup_arch(), before even per-cpu areas are initialised. The patch changes tvec_bases to use compile-time initialisation, and adds a separate array `tvec_base_done' to keep track of which CPU has had its tvec_bases[] entry initialised (because we can no longer use the zeroness of that tvec_bases[] entry to determine whether it has been initialised). Thanks to Eugene Surovegin <ebs@ebshome.net> for diagnosing this.
Unified · Split
| @@ -81,9 +81,10 @@ struct tvec_t_base_s { · 80 unmodified lines | ||
| 81 | 81 | } ____cacheline_aligned_in_smp; |
| 82 | 82 | |
| 83 | 83 | typedef struct tvec_t_base_s tvec_base_t; |
| 84 | −static DEFINE_PER_CPU(tvec_base_t *, tvec_bases); | |
| 84 | + | |
| 85 | 85 | tvec_base_t boot_tvec_bases; |
| 86 | 86 | EXPORT_SYMBOL(boot_tvec_bases); |
| 87 | +static DEFINE_PER_CPU(tvec_base_t *, tvec_bases) = { &boot_tvec_bases }; | |
| 87 | 88 | |
| 88 | 89 | static inline void set_running_timer(tvec_base_t *base, |
| 89 | 90 | struct timer_list *timer) |
| @@ -1224,28 +1225,36 @@ static int __devinit init_timers_cpu(int cpu) · 1134 unmodified lines | ||
| 1224 | 1225 | { |
| 1225 | 1226 | int j; |
| 1226 | 1227 | tvec_base_t *base; |
| 1228 | + static char __devinitdata tvec_base_done[NR_CPUS]; | |
| 1227 | 1229 | |
| 1228 | − base = per_cpu(tvec_bases, cpu); | |
| 1229 | − if (!base) { | |
| 1230 | + if (!tvec_base_done[cpu]) { | |
| 1230 | 1231 | static char boot_done; |
| 1231 | 1232 | |
| 1232 | − /* | |
| 1233 | − * Cannot do allocation in init_timers as that runs before the | |
| 1234 | − * allocator initializes (and would waste memory if there are | |
| 1235 | − * more possible CPUs than will ever be installed/brought up). | |
| 1236 | − */ | |
| 1237 | 1233 | if (boot_done) { |
| 1234 | + /* | |
| 1235 | + * The APs use this path later in boot | |
| 1236 | + */ | |
| 1238 | 1237 | base = kmalloc_node(sizeof(*base), GFP_KERNEL, |
| 1239 | 1238 | cpu_to_node(cpu)); |
| 1240 | 1239 | if (!base) |
| 1241 | 1240 | return -ENOMEM; |
| 1242 | 1241 | memset(base, 0, sizeof(*base)); |
| 1242 | + per_cpu(tvec_bases, cpu) = base; | |
| 1243 | 1243 | } else { |
| 1244 | − base = &boot_tvec_bases; | |
| 1244 | + /* | |
| 1245 | + * This is for the boot CPU - we use compile-time | |
| 1246 | + * static initialisation because per-cpu memory isn't | |
| 1247 | + * ready yet and because the memory allocators are not | |
| 1248 | + * initialised either. | |
| 1249 | + */ | |
| 1245 | 1250 | boot_done = 1; |
| 1251 | + base = &boot_tvec_bases; | |
| 1246 | 1252 | } |
| 1247 | − per_cpu(tvec_bases, cpu) = base; | |
| 1253 | + tvec_base_done[cpu] = 1; | |
| 1254 | + } else { | |
| 1255 | + base = per_cpu(tvec_bases, cpu); | |
| 1248 | 1256 | } |
| 1257 | + | |
| 1249 | 1258 | spin_lock_init(&base->lock); |
| 1250 | 1259 | for (j = 0; j < TVN_SIZE; j++) { |
| 1251 | 1260 | INIT_LIST_HEAD(base->tv5.vec + j); |