percpu: generalize first chunk allocator selection
Tejun Heo [Fri, 14 Aug 2009 06:00:50 +0000 (15:00 +0900)]
Now that all first chunk allocators are in mm/percpu.c, it makes sense
to make generalize percpu_alloc kernel parameter.  Define PCPU_FC_*
and set pcpu_chosen_fc using early_param() in mm/percpu.c.  Arch code
can use the set value to determine which first chunk allocator to use.

Signed-off-by: Tejun Heo <tj@kernel.org>

Documentation/kernel-parameters.txt
arch/x86/kernel/setup_percpu.c
include/linux/percpu.h
mm/percpu.c

index 12e9eb7..dee9ce2 100644 (file)
@@ -1919,11 +1919,12 @@ and is between 256 and 4096 characters. It is defined in the file
                        Format: { 0 | 1 }
                        See arch/parisc/kernel/pdc_chassis.c
 
-       percpu_alloc=   [X86] Select which percpu first chunk allocator to use.
-                       Allowed values are one of "lpage", "embed" and "page".
-                       See comments in arch/x86/kernel/setup_percpu.c for
-                       details on each allocator.  This parameter is primarily
-                       for debugging and performance comparison.
+       percpu_alloc=   Select which percpu first chunk allocator to use.
+                       Currently supported values are "embed", "page" and
+                       "lpage".  Archs may support subset or none of the
+                       selections.  See comments in mm/percpu.c for details
+                       on each allocator.  This parameter is primarily for
+                       debugging and performance comparison.
 
        pf.             [PARIDE]
                        See Documentation/blockdev/paride.txt.
index 1e17711..b961d99 100644 (file)
@@ -267,16 +267,6 @@ static ssize_t __init setup_pcpu_page(size_t static_size)
                                     pcpup_populate_pte);
 }
 
-/* for explicit first chunk allocator selection */
-static char pcpu_chosen_alloc[16] __initdata;
-
-static int __init percpu_alloc_setup(char *str)
-{
-       strncpy(pcpu_chosen_alloc, str, sizeof(pcpu_chosen_alloc) - 1);
-       return 0;
-}
-early_param("percpu_alloc", percpu_alloc_setup);
-
 static inline void setup_percpu_segment(int cpu)
 {
 #ifdef CONFIG_X86_32
@@ -307,19 +297,17 @@ void __init setup_per_cpu_areas(void)
         * each allocator for details.
         */
        ret = -EINVAL;
-       if (strlen(pcpu_chosen_alloc)) {
-               if (strcmp(pcpu_chosen_alloc, "page")) {
-                       if (!strcmp(pcpu_chosen_alloc, "lpage"))
+       if (pcpu_chosen_fc != PCPU_FC_AUTO) {
+               if (pcpu_chosen_fc != PCPU_FC_PAGE) {
+                       if (pcpu_chosen_fc == PCPU_FC_LPAGE)
                                ret = setup_pcpu_lpage(static_size, true);
-                       else if (!strcmp(pcpu_chosen_alloc, "embed"))
-                               ret = setup_pcpu_embed(static_size, true);
                        else
-                               pr_warning("PERCPU: unknown allocator %s "
-                                          "specified\n", pcpu_chosen_alloc);
+                               ret = setup_pcpu_embed(static_size, true);
+
                        if (ret < 0)
                                pr_warning("PERCPU: %s allocator failed (%zd), "
                                           "falling back to page size\n",
-                                          pcpu_chosen_alloc, ret);
+                                          pcpu_fc_names[pcpu_chosen_fc], ret);
                }
        } else {
                ret = setup_pcpu_lpage(static_size, false);
index e26788e..9be05cb 100644 (file)
 extern void *pcpu_base_addr;
 extern const int *pcpu_unit_map;
 
+enum pcpu_fc {
+       PCPU_FC_AUTO,
+       PCPU_FC_EMBED,
+       PCPU_FC_PAGE,
+       PCPU_FC_LPAGE,
+
+       PCPU_FC_NR,
+};
+extern const char *pcpu_fc_names[PCPU_FC_NR];
+
+extern enum pcpu_fc pcpu_chosen_fc;
+
 typedef void * (*pcpu_fc_alloc_fn_t)(unsigned int cpu, size_t size);
 typedef void (*pcpu_fc_free_fn_t)(void *ptr, size_t size);
 typedef void (*pcpu_fc_populate_pte_fn_t)(unsigned long addr);
index 7971997..7fb40bb 100644 (file)
@@ -1414,6 +1414,38 @@ size_t __init pcpu_setup_first_chunk(size_t static_size, size_t reserved_size,
        return pcpu_unit_size;
 }
 
+const char *pcpu_fc_names[PCPU_FC_NR] __initdata = {
+       [PCPU_FC_AUTO]  = "auto",
+       [PCPU_FC_EMBED] = "embed",
+       [PCPU_FC_PAGE]  = "page",
+       [PCPU_FC_LPAGE] = "lpage",
+};
+
+enum pcpu_fc pcpu_chosen_fc __initdata = PCPU_FC_AUTO;
+
+static int __init percpu_alloc_setup(char *str)
+{
+       if (0)
+               /* nada */;
+#ifdef CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK
+       else if (!strcmp(str, "embed"))
+               pcpu_chosen_fc = PCPU_FC_EMBED;
+#endif
+#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
+       else if (!strcmp(str, "page"))
+               pcpu_chosen_fc = PCPU_FC_PAGE;
+#endif
+#ifdef CONFIG_NEED_PER_CPU_LPAGE_FIRST_CHUNK
+       else if (!strcmp(str, "lpage"))
+               pcpu_chosen_fc = PCPU_FC_LPAGE;
+#endif
+       else
+               pr_warning("PERCPU: unknown allocator %s specified\n", str);
+
+       return 0;
+}
+early_param("percpu_alloc", percpu_alloc_setup);
+
 static inline size_t pcpu_calc_fc_sizes(size_t static_size,
                                        size_t reserved_size,
                                        ssize_t *dyn_sizep)