in mm/discontig.c [180:250]
void __init setup_per_cpu_areas(void)
{
struct pcpu_alloc_info *ai;
struct pcpu_group_info *gi;
unsigned int *cpu_map;
void *base;
unsigned long base_offset;
unsigned int cpu;
ssize_t static_size, reserved_size, dyn_size;
int node, prev_node, unit, nr_units;
ai = pcpu_alloc_alloc_info(MAX_NUMNODES, nr_cpu_ids);
if (!ai)
panic("failed to allocate pcpu_alloc_info");
cpu_map = ai->groups[0].cpu_map;
/* determine base */
base = (void *)ULONG_MAX;
for_each_possible_cpu(cpu)
base = min(base,
(void *)(__per_cpu_offset[cpu] + __per_cpu_start));
base_offset = (void *)__per_cpu_start - base;
/* build cpu_map, units are grouped by node */
unit = 0;
for_each_node(node)
for_each_possible_cpu(cpu)
if (node == node_cpuid[cpu].nid)
cpu_map[unit++] = cpu;
nr_units = unit;
/* set basic parameters */
static_size = __per_cpu_end - __per_cpu_start;
reserved_size = PERCPU_MODULE_RESERVE;
dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size;
if (dyn_size < 0)
panic("percpu area overflow static=%zd reserved=%zd\n",
static_size, reserved_size);
ai->static_size = static_size;
ai->reserved_size = reserved_size;
ai->dyn_size = dyn_size;
ai->unit_size = PERCPU_PAGE_SIZE;
ai->atom_size = PAGE_SIZE;
ai->alloc_size = PERCPU_PAGE_SIZE;
/*
* CPUs are put into groups according to node. Walk cpu_map
* and create new groups at node boundaries.
*/
prev_node = NUMA_NO_NODE;
ai->nr_groups = 0;
for (unit = 0; unit < nr_units; unit++) {
cpu = cpu_map[unit];
node = node_cpuid[cpu].nid;
if (node == prev_node) {
gi->nr_units++;
continue;
}
prev_node = node;
gi = &ai->groups[ai->nr_groups++];
gi->nr_units = 1;
gi->base_offset = __per_cpu_offset[cpu] + base_offset;
gi->cpu_map = &cpu_map[unit];
}
pcpu_setup_first_chunk(ai, base);
pcpu_free_alloc_info(ai);
}