|
@@ -241,24 +241,31 @@ static ssize_t __init setup_pcpu_remap(size_t static_size)
|
|
* Embedding allocator
|
|
* Embedding allocator
|
|
*
|
|
*
|
|
* The first chunk is sized to just contain the static area plus
|
|
* The first chunk is sized to just contain the static area plus
|
|
- * PERCPU_DYNAMIC_RESERVE and allocated as a contiguous area using
|
|
|
|
- * bootmem allocator and used as-is without being mapped into vmalloc
|
|
|
|
- * area. This enables the first chunk to piggy back on the linear
|
|
|
|
- * physical PMD mapping and doesn't add any additional pressure to
|
|
|
|
- * TLB.
|
|
|
|
|
|
+ * module and dynamic reserves, and allocated as a contiguous area
|
|
|
|
+ * using bootmem allocator and used as-is without being mapped into
|
|
|
|
+ * vmalloc area. This enables the first chunk to piggy back on the
|
|
|
|
+ * linear physical PMD mapping and doesn't add any additional pressure
|
|
|
|
+ * to TLB. Note that if the needed size is smaller than the minimum
|
|
|
|
+ * unit size, the leftover is returned to the bootmem allocator.
|
|
*/
|
|
*/
|
|
static void *pcpue_ptr __initdata;
|
|
static void *pcpue_ptr __initdata;
|
|
|
|
+static size_t pcpue_size __initdata;
|
|
static size_t pcpue_unit_size __initdata;
|
|
static size_t pcpue_unit_size __initdata;
|
|
|
|
|
|
static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
|
|
static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
|
|
{
|
|
{
|
|
- return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size
|
|
|
|
- + ((size_t)pageno << PAGE_SHIFT));
|
|
|
|
|
|
+ size_t off = (size_t)pageno << PAGE_SHIFT;
|
|
|
|
+
|
|
|
|
+ if (off >= pcpue_size)
|
|
|
|
+ return NULL;
|
|
|
|
+
|
|
|
|
+ return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size + off);
|
|
}
|
|
}
|
|
|
|
|
|
static ssize_t __init setup_pcpu_embed(size_t static_size)
|
|
static ssize_t __init setup_pcpu_embed(size_t static_size)
|
|
{
|
|
{
|
|
unsigned int cpu;
|
|
unsigned int cpu;
|
|
|
|
+ size_t dyn_size;
|
|
|
|
|
|
/*
|
|
/*
|
|
* If large page isn't supported, there's no benefit in doing
|
|
* If large page isn't supported, there's no benefit in doing
|
|
@@ -269,25 +276,30 @@ static ssize_t __init setup_pcpu_embed(size_t static_size)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
/* allocate and copy */
|
|
/* allocate and copy */
|
|
- pcpue_unit_size = PFN_ALIGN(static_size + PERCPU_DYNAMIC_RESERVE);
|
|
|
|
- pcpue_unit_size = max_t(size_t, pcpue_unit_size, PCPU_MIN_UNIT_SIZE);
|
|
|
|
|
|
+ pcpue_size = PFN_ALIGN(static_size + PERCPU_DYNAMIC_RESERVE);
|
|
|
|
+ pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE);
|
|
|
|
+ dyn_size = pcpue_size - static_size;
|
|
|
|
+
|
|
pcpue_ptr = pcpu_alloc_bootmem(0, num_possible_cpus() * pcpue_unit_size,
|
|
pcpue_ptr = pcpu_alloc_bootmem(0, num_possible_cpus() * pcpue_unit_size,
|
|
PAGE_SIZE);
|
|
PAGE_SIZE);
|
|
if (!pcpue_ptr)
|
|
if (!pcpue_ptr)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
- for_each_possible_cpu(cpu)
|
|
|
|
- memcpy(pcpue_ptr + cpu * pcpue_unit_size, __per_cpu_load,
|
|
|
|
- static_size);
|
|
|
|
|
|
+ for_each_possible_cpu(cpu) {
|
|
|
|
+ void *ptr = pcpue_ptr + cpu * pcpue_unit_size;
|
|
|
|
+
|
|
|
|
+ free_bootmem(__pa(ptr + pcpue_size),
|
|
|
|
+ pcpue_unit_size - pcpue_size);
|
|
|
|
+ memcpy(ptr, __per_cpu_load, static_size);
|
|
|
|
+ }
|
|
|
|
|
|
/* we're ready, commit */
|
|
/* we're ready, commit */
|
|
pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n",
|
|
pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n",
|
|
- pcpue_unit_size >> PAGE_SHIFT, pcpue_ptr, static_size);
|
|
|
|
|
|
+ pcpue_size >> PAGE_SHIFT, pcpue_ptr, static_size);
|
|
|
|
|
|
return pcpu_setup_first_chunk(pcpue_get_page, static_size,
|
|
return pcpu_setup_first_chunk(pcpue_get_page, static_size,
|
|
- pcpue_unit_size,
|
|
|
|
- pcpue_unit_size - static_size, pcpue_ptr,
|
|
|
|
- NULL);
|
|
|
|
|
|
+ pcpue_unit_size, dyn_size,
|
|
|
|
+ pcpue_ptr, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|