diff options
-rw-r--r-- | arch/sparc/mm/init_64.c | 208 |
1 files changed, 113 insertions, 95 deletions
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 16c1e46e8603..77446eaf1395 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -829,13 +829,23 @@ static void __init find_ramdisk(unsigned long phys_base) | |||
829 | 829 | ||
830 | struct node_mem_mask { | 830 | struct node_mem_mask { |
831 | unsigned long mask; | 831 | unsigned long mask; |
832 | unsigned long val; | 832 | unsigned long match; |
833 | }; | 833 | }; |
834 | static struct node_mem_mask node_masks[MAX_NUMNODES]; | 834 | static struct node_mem_mask node_masks[MAX_NUMNODES]; |
835 | static int num_node_masks; | 835 | static int num_node_masks; |
836 | 836 | ||
837 | #ifdef CONFIG_NEED_MULTIPLE_NODES | 837 | #ifdef CONFIG_NEED_MULTIPLE_NODES |
838 | 838 | ||
839 | struct mdesc_mlgroup { | ||
840 | u64 node; | ||
841 | u64 latency; | ||
842 | u64 match; | ||
843 | u64 mask; | ||
844 | }; | ||
845 | |||
846 | static struct mdesc_mlgroup *mlgroups; | ||
847 | static int num_mlgroups; | ||
848 | |||
839 | int numa_cpu_lookup_table[NR_CPUS]; | 849 | int numa_cpu_lookup_table[NR_CPUS]; |
840 | cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; | 850 | cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; |
841 | 851 | ||
@@ -846,78 +856,129 @@ struct mdesc_mblock { | |||
846 | }; | 856 | }; |
847 | static struct mdesc_mblock *mblocks; | 857 | static struct mdesc_mblock *mblocks; |
848 | static int num_mblocks; | 858 | static int num_mblocks; |
849 | static int find_numa_node_for_addr(unsigned long pa, | ||
850 | struct node_mem_mask *pnode_mask); | ||
851 | 859 | ||
852 | static unsigned long __init ra_to_pa(unsigned long addr) | 860 | static struct mdesc_mblock * __init addr_to_mblock(unsigned long addr) |
853 | { | 861 | { |
862 | struct mdesc_mblock *m = NULL; | ||
854 | int i; | 863 | int i; |
855 | 864 | ||
856 | for (i = 0; i < num_mblocks; i++) { | 865 | for (i = 0; i < num_mblocks; i++) { |
857 | struct mdesc_mblock *m = &mblocks[i]; | 866 | m = &mblocks[i]; |
858 | 867 | ||
859 | if (addr >= m->base && | 868 | if (addr >= m->base && |
860 | addr < (m->base + m->size)) { | 869 | addr < (m->base + m->size)) { |
861 | addr += m->offset; | ||
862 | break; | 870 | break; |
863 | } | 871 | } |
864 | } | 872 | } |
865 | return addr; | 873 | |
874 | return m; | ||
866 | } | 875 | } |
867 | 876 | ||
868 | static int __init find_node(unsigned long addr) | 877 | static u64 __init memblock_nid_range_sun4u(u64 start, u64 end, int *nid) |
869 | { | 878 | { |
870 | static bool search_mdesc = true; | 879 | int prev_nid, new_nid; |
871 | static struct node_mem_mask last_mem_mask = { ~0UL, ~0UL }; | ||
872 | static int last_index; | ||
873 | int i; | ||
874 | 880 | ||
875 | addr = ra_to_pa(addr); | 881 | prev_nid = -1; |
876 | for (i = 0; i < num_node_masks; i++) { | 882 | for ( ; start < end; start += PAGE_SIZE) { |
877 | struct node_mem_mask *p = &node_masks[i]; | 883 | for (new_nid = 0; new_nid < num_node_masks; new_nid++) { |
884 | struct node_mem_mask *p = &node_masks[new_nid]; | ||
878 | 885 | ||
879 | if ((addr & p->mask) == p->val) | 886 | if ((start & p->mask) == p->match) { |
880 | return i; | 887 | if (prev_nid == -1) |
881 | } | 888 | prev_nid = new_nid; |
882 | /* The following condition has been observed on LDOM guests because | 889 | break; |
883 | * node_masks only contains the best latency mask and value. | 890 | } |
884 | * LDOM guest's mdesc can contain a single latency group to | ||
885 | * cover multiple address range. Print warning message only if the | ||
886 | * address cannot be found in node_masks nor mdesc. | ||
887 | */ | ||
888 | if ((search_mdesc) && | ||
889 | ((addr & last_mem_mask.mask) != last_mem_mask.val)) { | ||
890 | /* find the available node in the mdesc */ | ||
891 | last_index = find_numa_node_for_addr(addr, &last_mem_mask); | ||
892 | numadbg("find_node: latency group for address 0x%lx is %d\n", | ||
893 | addr, last_index); | ||
894 | if ((last_index < 0) || (last_index >= num_node_masks)) { | ||
895 | /* WARN_ONCE() and use default group 0 */ | ||
896 | WARN_ONCE(1, "find_node: A physical address doesn't match a NUMA node rule. Some physical memory will be owned by node 0."); | ||
897 | search_mdesc = false; | ||
898 | last_index = 0; | ||
899 | } | 891 | } |
892 | |||
893 | if (new_nid == num_node_masks) { | ||
894 | prev_nid = 0; | ||
895 | WARN_ONCE(1, "addr[%Lx] doesn't match a NUMA node rule. Some memory will be owned by node 0.", | ||
896 | start); | ||
897 | break; | ||
898 | } | ||
899 | |||
900 | if (prev_nid != new_nid) | ||
901 | break; | ||
900 | } | 902 | } |
903 | *nid = prev_nid; | ||
901 | 904 | ||
902 | return last_index; | 905 | return start > end ? end : start; |
903 | } | 906 | } |
904 | 907 | ||
905 | static u64 __init memblock_nid_range(u64 start, u64 end, int *nid) | 908 | static u64 __init memblock_nid_range(u64 start, u64 end, int *nid) |
906 | { | 909 | { |
907 | *nid = find_node(start); | 910 | u64 ret_end, pa_start, m_mask, m_match, m_end; |
908 | start += PAGE_SIZE; | 911 | struct mdesc_mblock *mblock; |
909 | while (start < end) { | 912 | int _nid, i; |
910 | int n = find_node(start); | 913 | |
914 | if (tlb_type != hypervisor) | ||
915 | return memblock_nid_range_sun4u(start, end, nid); | ||
916 | |||
917 | mblock = addr_to_mblock(start); | ||
918 | if (!mblock) { | ||
919 | WARN_ONCE(1, "memblock_nid_range: Can't find mblock addr[%Lx]", | ||
920 | start); | ||
921 | |||
922 | _nid = 0; | ||
923 | ret_end = end; | ||
924 | goto done; | ||
925 | } | ||
926 | |||
927 | pa_start = start + mblock->offset; | ||
928 | m_match = 0; | ||
929 | m_mask = 0; | ||
930 | |||
931 | for (_nid = 0; _nid < num_node_masks; _nid++) { | ||
932 | struct node_mem_mask *const m = &node_masks[_nid]; | ||
911 | 933 | ||
912 | if (n != *nid) | 934 | if ((pa_start & m->mask) == m->match) { |
935 | m_match = m->match; | ||
936 | m_mask = m->mask; | ||
913 | break; | 937 | break; |
914 | start += PAGE_SIZE; | 938 | } |
915 | } | 939 | } |
916 | 940 | ||
917 | if (start > end) | 941 | if (num_node_masks == _nid) { |
918 | start = end; | 942 | /* We could not find NUMA group, so default to 0, but lets |
943 | * search for latency group, so we could calculate the correct | ||
944 | * end address that we return | ||
945 | */ | ||
946 | _nid = 0; | ||
919 | 947 | ||
920 | return start; | 948 | for (i = 0; i < num_mlgroups; i++) { |
949 | struct mdesc_mlgroup *const m = &mlgroups[i]; | ||
950 | |||
951 | if ((pa_start & m->mask) == m->match) { | ||
952 | m_match = m->match; | ||
953 | m_mask = m->mask; | ||
954 | break; | ||
955 | } | ||
956 | } | ||
957 | |||
958 | if (i == num_mlgroups) { | ||
959 | WARN_ONCE(1, "memblock_nid_range: Can't find latency group addr[%Lx]", | ||
960 | start); | ||
961 | |||
962 | ret_end = end; | ||
963 | goto done; | ||
964 | } | ||
965 | } | ||
966 | |||
967 | /* | ||
968 | * Each latency group has match and mask, and each memory block has an | ||
969 | * offset. An address belongs to a latency group if its address matches | ||
970 | * the following formula: ((addr + offset) & mask) == match | ||
971 | * It is, however, slow to check every single page if it matches a | ||
972 | * particular latency group. As optimization we calculate end value by | ||
973 | * using bit arithmetics. | ||
974 | */ | ||
975 | m_end = m_match + (1ul << __ffs(m_mask)) - mblock->offset; | ||
976 | m_end += pa_start & ~((1ul << fls64(m_mask)) - 1); | ||
977 | ret_end = m_end > end ? end : m_end; | ||
978 | |||
979 | done: | ||
980 | *nid = _nid; | ||
981 | return ret_end; | ||
921 | } | 982 | } |
922 | #endif | 983 | #endif |
923 | 984 | ||
@@ -958,7 +1019,8 @@ static void init_node_masks_nonnuma(void) | |||
958 | 1019 | ||
959 | numadbg("Initializing tables for non-numa.\n"); | 1020 | numadbg("Initializing tables for non-numa.\n"); |
960 | 1021 | ||
961 | node_masks[0].mask = node_masks[0].val = 0; | 1022 | node_masks[0].mask = 0; |
1023 | node_masks[0].match = 0; | ||
962 | num_node_masks = 1; | 1024 | num_node_masks = 1; |
963 | 1025 | ||
964 | #ifdef CONFIG_NEED_MULTIPLE_NODES | 1026 | #ifdef CONFIG_NEED_MULTIPLE_NODES |
@@ -976,15 +1038,6 @@ EXPORT_SYMBOL(numa_cpu_lookup_table); | |||
976 | EXPORT_SYMBOL(numa_cpumask_lookup_table); | 1038 | EXPORT_SYMBOL(numa_cpumask_lookup_table); |
977 | EXPORT_SYMBOL(node_data); | 1039 | EXPORT_SYMBOL(node_data); |
978 | 1040 | ||
979 | struct mdesc_mlgroup { | ||
980 | u64 node; | ||
981 | u64 latency; | ||
982 | u64 match; | ||
983 | u64 mask; | ||
984 | }; | ||
985 | static struct mdesc_mlgroup *mlgroups; | ||
986 | static int num_mlgroups; | ||
987 | |||
988 | static int scan_pio_for_cfg_handle(struct mdesc_handle *md, u64 pio, | 1041 | static int scan_pio_for_cfg_handle(struct mdesc_handle *md, u64 pio, |
989 | u32 cfg_handle) | 1042 | u32 cfg_handle) |
990 | { | 1043 | { |
@@ -1226,41 +1279,6 @@ int __node_distance(int from, int to) | |||
1226 | return numa_latency[from][to]; | 1279 | return numa_latency[from][to]; |
1227 | } | 1280 | } |
1228 | 1281 | ||
1229 | static int find_numa_node_for_addr(unsigned long pa, | ||
1230 | struct node_mem_mask *pnode_mask) | ||
1231 | { | ||
1232 | struct mdesc_handle *md = mdesc_grab(); | ||
1233 | u64 node, arc; | ||
1234 | int i = 0; | ||
1235 | |||
1236 | node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups"); | ||
1237 | if (node == MDESC_NODE_NULL) | ||
1238 | goto out; | ||
1239 | |||
1240 | mdesc_for_each_node_by_name(md, node, "group") { | ||
1241 | mdesc_for_each_arc(arc, md, node, MDESC_ARC_TYPE_FWD) { | ||
1242 | u64 target = mdesc_arc_target(md, arc); | ||
1243 | struct mdesc_mlgroup *m = find_mlgroup(target); | ||
1244 | |||
1245 | if (!m) | ||
1246 | continue; | ||
1247 | if ((pa & m->mask) == m->match) { | ||
1248 | if (pnode_mask) { | ||
1249 | pnode_mask->mask = m->mask; | ||
1250 | pnode_mask->val = m->match; | ||
1251 | } | ||
1252 | mdesc_release(md); | ||
1253 | return i; | ||
1254 | } | ||
1255 | } | ||
1256 | i++; | ||
1257 | } | ||
1258 | |||
1259 | out: | ||
1260 | mdesc_release(md); | ||
1261 | return -1; | ||
1262 | } | ||
1263 | |||
1264 | static int __init find_best_numa_node_for_mlgroup(struct mdesc_mlgroup *grp) | 1282 | static int __init find_best_numa_node_for_mlgroup(struct mdesc_mlgroup *grp) |
1265 | { | 1283 | { |
1266 | int i; | 1284 | int i; |
@@ -1268,7 +1286,7 @@ static int __init find_best_numa_node_for_mlgroup(struct mdesc_mlgroup *grp) | |||
1268 | for (i = 0; i < MAX_NUMNODES; i++) { | 1286 | for (i = 0; i < MAX_NUMNODES; i++) { |
1269 | struct node_mem_mask *n = &node_masks[i]; | 1287 | struct node_mem_mask *n = &node_masks[i]; |
1270 | 1288 | ||
1271 | if ((grp->mask == n->mask) && (grp->match == n->val)) | 1289 | if ((grp->mask == n->mask) && (grp->match == n->match)) |
1272 | break; | 1290 | break; |
1273 | } | 1291 | } |
1274 | return i; | 1292 | return i; |
@@ -1323,10 +1341,10 @@ static int __init numa_attach_mlgroup(struct mdesc_handle *md, u64 grp, | |||
1323 | n = &node_masks[num_node_masks++]; | 1341 | n = &node_masks[num_node_masks++]; |
1324 | 1342 | ||
1325 | n->mask = candidate->mask; | 1343 | n->mask = candidate->mask; |
1326 | n->val = candidate->match; | 1344 | n->match = candidate->match; |
1327 | 1345 | ||
1328 | numadbg("NUMA NODE[%d]: mask[%lx] val[%lx] (latency[%llx])\n", | 1346 | numadbg("NUMA NODE[%d]: mask[%lx] match[%lx] (latency[%llx])\n", |
1329 | index, n->mask, n->val, candidate->latency); | 1347 | index, n->mask, n->match, candidate->latency); |
1330 | 1348 | ||
1331 | return 0; | 1349 | return 0; |
1332 | } | 1350 | } |
@@ -1423,7 +1441,7 @@ static int __init numa_parse_jbus(void) | |||
1423 | numa_cpu_lookup_table[cpu] = index; | 1441 | numa_cpu_lookup_table[cpu] = index; |
1424 | cpumask_copy(&numa_cpumask_lookup_table[index], cpumask_of(cpu)); | 1442 | cpumask_copy(&numa_cpumask_lookup_table[index], cpumask_of(cpu)); |
1425 | node_masks[index].mask = ~((1UL << 36UL) - 1UL); | 1443 | node_masks[index].mask = ~((1UL << 36UL) - 1UL); |
1426 | node_masks[index].val = cpu << 36UL; | 1444 | node_masks[index].match = cpu << 36UL; |
1427 | 1445 | ||
1428 | index++; | 1446 | index++; |
1429 | } | 1447 | } |