diff options
Diffstat (limited to 'arch/x86/mm')
-rw-r--r-- | arch/x86/mm/numa_64.c | 56 |
1 files changed, 33 insertions, 23 deletions
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 6e4ee96d1b11..980d51458c4b 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c | |||
@@ -789,17 +789,20 @@ static int __init split_nodes_size_interleave(struct numa_meminfo *ei, | |||
789 | * Sets up the system RAM area from start_pfn to last_pfn according to the | 789 | * Sets up the system RAM area from start_pfn to last_pfn according to the |
790 | * numa=fake command-line option. | 790 | * numa=fake command-line option. |
791 | */ | 791 | */ |
792 | static bool __init numa_emulation(void) | 792 | static void __init numa_emulation(struct numa_meminfo *numa_meminfo, |
793 | int numa_dist_cnt) | ||
793 | { | 794 | { |
794 | static struct numa_meminfo ei __initdata; | 795 | static struct numa_meminfo ei __initdata; |
795 | static struct numa_meminfo pi __initdata; | 796 | static struct numa_meminfo pi __initdata; |
796 | const u64 max_addr = max_pfn << PAGE_SHIFT; | 797 | const u64 max_addr = max_pfn << PAGE_SHIFT; |
797 | int phys_dist_cnt = numa_distance_cnt; | ||
798 | u8 *phys_dist = NULL; | 798 | u8 *phys_dist = NULL; |
799 | int i, j, ret; | 799 | int i, j, ret; |
800 | 800 | ||
801 | if (!emu_cmdline) | ||
802 | goto no_emu; | ||
803 | |||
801 | memset(&ei, 0, sizeof(ei)); | 804 | memset(&ei, 0, sizeof(ei)); |
802 | pi = numa_meminfo; | 805 | pi = *numa_meminfo; |
803 | 806 | ||
804 | for (i = 0; i < MAX_NUMNODES; i++) | 807 | for (i = 0; i < MAX_NUMNODES; i++) |
805 | emu_nid_to_phys[i] = NUMA_NO_NODE; | 808 | emu_nid_to_phys[i] = NUMA_NO_NODE; |
@@ -822,19 +825,19 @@ static bool __init numa_emulation(void) | |||
822 | } | 825 | } |
823 | 826 | ||
824 | if (ret < 0) | 827 | if (ret < 0) |
825 | return false; | 828 | goto no_emu; |
826 | 829 | ||
827 | if (numa_cleanup_meminfo(&ei) < 0) { | 830 | if (numa_cleanup_meminfo(&ei) < 0) { |
828 | pr_warning("NUMA: Warning: constructed meminfo invalid, disabling emulation\n"); | 831 | pr_warning("NUMA: Warning: constructed meminfo invalid, disabling emulation\n"); |
829 | return false; | 832 | goto no_emu; |
830 | } | 833 | } |
831 | 834 | ||
832 | /* | 835 | /* |
833 | * Copy the original distance table. It's temporary so no need to | 836 | * Copy the original distance table. It's temporary so no need to |
834 | * reserve it. | 837 | * reserve it. |
835 | */ | 838 | */ |
836 | if (phys_dist_cnt) { | 839 | if (numa_dist_cnt) { |
837 | size_t size = phys_dist_cnt * sizeof(numa_distance[0]); | 840 | size_t size = numa_dist_cnt * sizeof(phys_dist[0]); |
838 | u64 phys; | 841 | u64 phys; |
839 | 842 | ||
840 | phys = memblock_find_in_range(0, | 843 | phys = memblock_find_in_range(0, |
@@ -842,14 +845,18 @@ static bool __init numa_emulation(void) | |||
842 | size, PAGE_SIZE); | 845 | size, PAGE_SIZE); |
843 | if (phys == MEMBLOCK_ERROR) { | 846 | if (phys == MEMBLOCK_ERROR) { |
844 | pr_warning("NUMA: Warning: can't allocate copy of distance table, disabling emulation\n"); | 847 | pr_warning("NUMA: Warning: can't allocate copy of distance table, disabling emulation\n"); |
845 | return false; | 848 | goto no_emu; |
846 | } | 849 | } |
847 | phys_dist = __va(phys); | 850 | phys_dist = __va(phys); |
848 | memcpy(phys_dist, numa_distance, size); | 851 | |
852 | for (i = 0; i < numa_dist_cnt; i++) | ||
853 | for (j = 0; j < numa_dist_cnt; j++) | ||
854 | phys_dist[i * numa_dist_cnt + j] = | ||
855 | node_distance(i, j); | ||
849 | } | 856 | } |
850 | 857 | ||
851 | /* commit */ | 858 | /* commit */ |
852 | numa_meminfo = ei; | 859 | *numa_meminfo = ei; |
853 | 860 | ||
854 | /* | 861 | /* |
855 | * Transform __apicid_to_node table to use emulated nids by | 862 | * Transform __apicid_to_node table to use emulated nids by |
@@ -878,18 +885,27 @@ static bool __init numa_emulation(void) | |||
878 | int physj = emu_nid_to_phys[j]; | 885 | int physj = emu_nid_to_phys[j]; |
879 | int dist; | 886 | int dist; |
880 | 887 | ||
881 | if (physi >= phys_dist_cnt || physj >= phys_dist_cnt) | 888 | if (physi >= numa_dist_cnt || physj >= numa_dist_cnt) |
882 | dist = physi == physj ? | 889 | dist = physi == physj ? |
883 | LOCAL_DISTANCE : REMOTE_DISTANCE; | 890 | LOCAL_DISTANCE : REMOTE_DISTANCE; |
884 | else | 891 | else |
885 | dist = phys_dist[physi * phys_dist_cnt + physj]; | 892 | dist = phys_dist[physi * numa_dist_cnt + physj]; |
886 | 893 | ||
887 | numa_set_distance(i, j, dist); | 894 | numa_set_distance(i, j, dist); |
888 | } | 895 | } |
889 | } | 896 | } |
890 | return true; | 897 | return; |
898 | |||
899 | no_emu: | ||
900 | /* No emulation. Build identity emu_nid_to_phys[] for numa_add_cpu() */ | ||
901 | for (i = 0; i < ARRAY_SIZE(emu_nid_to_phys); i++) | ||
902 | emu_nid_to_phys[i] = i; | ||
891 | } | 903 | } |
892 | #endif /* CONFIG_NUMA_EMU */ | 904 | #else /* CONFIG_NUMA_EMU */ |
905 | static inline void numa_emulation(struct numa_meminfo *numa_meminfo, | ||
906 | int numa_dist_cnt) | ||
907 | { } | ||
908 | #endif /* CONFIG_NUMA_EMU */ | ||
893 | 909 | ||
894 | static int __init dummy_numa_init(void) | 910 | static int __init dummy_numa_init(void) |
895 | { | 911 | { |
@@ -937,15 +953,9 @@ void __init initmem_init(void) | |||
937 | 953 | ||
938 | if (numa_cleanup_meminfo(&numa_meminfo) < 0) | 954 | if (numa_cleanup_meminfo(&numa_meminfo) < 0) |
939 | continue; | 955 | continue; |
940 | #ifdef CONFIG_NUMA_EMU | 956 | |
941 | /* | 957 | numa_emulation(&numa_meminfo, numa_distance_cnt); |
942 | * If requested, try emulation. If emulation is not used, | 958 | |
943 | * build identity emu_nid_to_phys[] for numa_add_cpu() | ||
944 | */ | ||
945 | if (!emu_cmdline || !numa_emulation()) | ||
946 | for (j = 0; j < ARRAY_SIZE(emu_nid_to_phys); j++) | ||
947 | emu_nid_to_phys[j] = j; | ||
948 | #endif | ||
949 | if (numa_register_memblks(&numa_meminfo) < 0) | 959 | if (numa_register_memblks(&numa_meminfo) < 0) |
950 | continue; | 960 | continue; |
951 | 961 | ||