diff options
Diffstat (limited to 'mm/percpu.c')
| -rw-r--r-- | mm/percpu.c | 60 |
1 files changed, 56 insertions, 4 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index c76ef3891e0d..9734b184aaac 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
| @@ -76,6 +76,7 @@ | |||
| 76 | #define PCPU_SLOT_BASE_SHIFT 5 /* 1-31 shares the same slot */ | 76 | #define PCPU_SLOT_BASE_SHIFT 5 /* 1-31 shares the same slot */ |
| 77 | #define PCPU_DFL_MAP_ALLOC 16 /* start a map with 16 ents */ | 77 | #define PCPU_DFL_MAP_ALLOC 16 /* start a map with 16 ents */ |
| 78 | 78 | ||
| 79 | #ifdef CONFIG_SMP | ||
| 79 | /* default addr <-> pcpu_ptr mapping, override in asm/percpu.h if necessary */ | 80 | /* default addr <-> pcpu_ptr mapping, override in asm/percpu.h if necessary */ |
| 80 | #ifndef __addr_to_pcpu_ptr | 81 | #ifndef __addr_to_pcpu_ptr |
| 81 | #define __addr_to_pcpu_ptr(addr) \ | 82 | #define __addr_to_pcpu_ptr(addr) \ |
| @@ -89,6 +90,11 @@ | |||
| 89 | (unsigned long)pcpu_base_addr - \ | 90 | (unsigned long)pcpu_base_addr - \ |
| 90 | (unsigned long)__per_cpu_start) | 91 | (unsigned long)__per_cpu_start) |
| 91 | #endif | 92 | #endif |
| 93 | #else /* CONFIG_SMP */ | ||
| 94 | /* on UP, it's always identity mapped */ | ||
| 95 | #define __addr_to_pcpu_ptr(addr) (void __percpu *)(addr) | ||
| 96 | #define __pcpu_ptr_to_addr(ptr) (void __force *)(ptr) | ||
| 97 | #endif /* CONFIG_SMP */ | ||
| 92 | 98 | ||
| 93 | struct pcpu_chunk { | 99 | struct pcpu_chunk { |
| 94 | struct list_head list; /* linked to pcpu_slot lists */ | 100 | struct list_head list; /* linked to pcpu_slot lists */ |
| @@ -949,6 +955,7 @@ EXPORT_SYMBOL_GPL(free_percpu); | |||
| 949 | */ | 955 | */ |
| 950 | bool is_kernel_percpu_address(unsigned long addr) | 956 | bool is_kernel_percpu_address(unsigned long addr) |
| 951 | { | 957 | { |
| 958 | #ifdef CONFIG_SMP | ||
| 952 | const size_t static_size = __per_cpu_end - __per_cpu_start; | 959 | const size_t static_size = __per_cpu_end - __per_cpu_start; |
| 953 | void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr); | 960 | void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr); |
| 954 | unsigned int cpu; | 961 | unsigned int cpu; |
| @@ -959,6 +966,8 @@ bool is_kernel_percpu_address(unsigned long addr) | |||
| 959 | if ((void *)addr >= start && (void *)addr < start + static_size) | 966 | if ((void *)addr >= start && (void *)addr < start + static_size) |
| 960 | return true; | 967 | return true; |
| 961 | } | 968 | } |
| 969 | #endif | ||
| 970 | /* on UP, can't distinguish from other static vars, always false */ | ||
| 962 | return false; | 971 | return false; |
| 963 | } | 972 | } |
| 964 | 973 | ||
| @@ -1066,6 +1075,8 @@ void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai) | |||
| 1066 | free_bootmem(__pa(ai), ai->__ai_size); | 1075 | free_bootmem(__pa(ai), ai->__ai_size); |
| 1067 | } | 1076 | } |
| 1068 | 1077 | ||
| 1078 | #if defined(CONFIG_SMP) && (defined(CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK) || \ | ||
| 1079 | defined(CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK)) | ||
| 1069 | /** | 1080 | /** |
| 1070 | * pcpu_build_alloc_info - build alloc_info considering distances between CPUs | 1081 | * pcpu_build_alloc_info - build alloc_info considering distances between CPUs |
| 1071 | * @reserved_size: the size of reserved percpu area in bytes | 1082 | * @reserved_size: the size of reserved percpu area in bytes |
| @@ -1220,6 +1231,8 @@ static struct pcpu_alloc_info * __init pcpu_build_alloc_info( | |||
| 1220 | 1231 | ||
| 1221 | return ai; | 1232 | return ai; |
| 1222 | } | 1233 | } |
| 1234 | #endif /* CONFIG_SMP && (CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK || | ||
| 1235 | CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK) */ | ||
| 1223 | 1236 | ||
| 1224 | /** | 1237 | /** |
| 1225 | * pcpu_dump_alloc_info - print out information about pcpu_alloc_info | 1238 | * pcpu_dump_alloc_info - print out information about pcpu_alloc_info |
| @@ -1363,7 +1376,9 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, | |||
| 1363 | 1376 | ||
| 1364 | /* sanity checks */ | 1377 | /* sanity checks */ |
| 1365 | PCPU_SETUP_BUG_ON(ai->nr_groups <= 0); | 1378 | PCPU_SETUP_BUG_ON(ai->nr_groups <= 0); |
| 1379 | #ifdef CONFIG_SMP | ||
| 1366 | PCPU_SETUP_BUG_ON(!ai->static_size); | 1380 | PCPU_SETUP_BUG_ON(!ai->static_size); |
| 1381 | #endif | ||
| 1367 | PCPU_SETUP_BUG_ON(!base_addr); | 1382 | PCPU_SETUP_BUG_ON(!base_addr); |
| 1368 | PCPU_SETUP_BUG_ON(ai->unit_size < size_sum); | 1383 | PCPU_SETUP_BUG_ON(ai->unit_size < size_sum); |
| 1369 | PCPU_SETUP_BUG_ON(ai->unit_size & ~PAGE_MASK); | 1384 | PCPU_SETUP_BUG_ON(ai->unit_size & ~PAGE_MASK); |
| @@ -1488,6 +1503,8 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, | |||
| 1488 | return 0; | 1503 | return 0; |
| 1489 | } | 1504 | } |
| 1490 | 1505 | ||
| 1506 | #ifdef CONFIG_SMP | ||
| 1507 | |||
| 1491 | const char *pcpu_fc_names[PCPU_FC_NR] __initdata = { | 1508 | const char *pcpu_fc_names[PCPU_FC_NR] __initdata = { |
| 1492 | [PCPU_FC_AUTO] = "auto", | 1509 | [PCPU_FC_AUTO] = "auto", |
| 1493 | [PCPU_FC_EMBED] = "embed", | 1510 | [PCPU_FC_EMBED] = "embed", |
| @@ -1758,8 +1775,9 @@ out_free_ar: | |||
| 1758 | } | 1775 | } |
| 1759 | #endif /* CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK */ | 1776 | #endif /* CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK */ |
| 1760 | 1777 | ||
| 1778 | #ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA | ||
| 1761 | /* | 1779 | /* |
| 1762 | * Generic percpu area setup. | 1780 | * Generic SMP percpu area setup. |
| 1763 | * | 1781 | * |
| 1764 | * The embedding helper is used because its behavior closely resembles | 1782 | * The embedding helper is used because its behavior closely resembles |
| 1765 | * the original non-dynamic generic percpu area setup. This is | 1783 | * the original non-dynamic generic percpu area setup. This is |
| @@ -1770,7 +1788,6 @@ out_free_ar: | |||
| 1770 | * on the physical linear memory mapping which uses large page | 1788 | * on the physical linear memory mapping which uses large page |
| 1771 | * mappings on applicable archs. | 1789 | * mappings on applicable archs. |
| 1772 | */ | 1790 | */ |
| 1773 | #ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA | ||
| 1774 | unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; | 1791 | unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; |
| 1775 | EXPORT_SYMBOL(__per_cpu_offset); | 1792 | EXPORT_SYMBOL(__per_cpu_offset); |
| 1776 | 1793 | ||
| @@ -1799,13 +1816,48 @@ void __init setup_per_cpu_areas(void) | |||
| 1799 | PERCPU_DYNAMIC_RESERVE, PAGE_SIZE, NULL, | 1816 | PERCPU_DYNAMIC_RESERVE, PAGE_SIZE, NULL, |
| 1800 | pcpu_dfl_fc_alloc, pcpu_dfl_fc_free); | 1817 | pcpu_dfl_fc_alloc, pcpu_dfl_fc_free); |
| 1801 | if (rc < 0) | 1818 | if (rc < 0) |
| 1802 | panic("Failed to initialized percpu areas."); | 1819 | panic("Failed to initialize percpu areas."); |
| 1803 | 1820 | ||
| 1804 | delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; | 1821 | delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; |
| 1805 | for_each_possible_cpu(cpu) | 1822 | for_each_possible_cpu(cpu) |
| 1806 | __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; | 1823 | __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; |
| 1807 | } | 1824 | } |
| 1808 | #endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */ | 1825 | #endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */ |
| 1826 | |||
| 1827 | #else /* CONFIG_SMP */ | ||
| 1828 | |||
| 1829 | /* | ||
| 1830 | * UP percpu area setup. | ||
| 1831 | * | ||
| 1832 | * UP always uses km-based percpu allocator with identity mapping. | ||
| 1833 | * Static percpu variables are indistinguishable from the usual static | ||
| 1834 | * variables and don't require any special preparation. | ||
| 1835 | */ | ||
| 1836 | void __init setup_per_cpu_areas(void) | ||
| 1837 | { | ||
| 1838 | const size_t unit_size = | ||
| 1839 | roundup_pow_of_two(max_t(size_t, PCPU_MIN_UNIT_SIZE, | ||
| 1840 | PERCPU_DYNAMIC_RESERVE)); | ||
| 1841 | struct pcpu_alloc_info *ai; | ||
| 1842 | void *fc; | ||
| 1843 | |||
| 1844 | ai = pcpu_alloc_alloc_info(1, 1); | ||
| 1845 | fc = __alloc_bootmem(unit_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); | ||
| 1846 | if (!ai || !fc) | ||
| 1847 | panic("Failed to allocate memory for percpu areas."); | ||
| 1848 | |||
| 1849 | ai->dyn_size = unit_size; | ||
| 1850 | ai->unit_size = unit_size; | ||
| 1851 | ai->atom_size = unit_size; | ||
| 1852 | ai->alloc_size = unit_size; | ||
| 1853 | ai->groups[0].nr_units = 1; | ||
| 1854 | ai->groups[0].cpu_map[0] = 0; | ||
| 1855 | |||
| 1856 | if (pcpu_setup_first_chunk(ai, fc) < 0) | ||
| 1857 | panic("Failed to initialize percpu areas."); | ||
| 1858 | } | ||
| 1859 | |||
| 1860 | #endif /* CONFIG_SMP */ | ||
| 1809 | 1861 | ||
| 1810 | /* | 1862 | /* |
| 1811 | * First and reserved chunks are initialized with temporary allocation | 1863 | * First and reserved chunks are initialized with temporary allocation |
