| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Test cases for the drm_mm range manager |
|---|
| 3 | 4 | */ |
|---|
| .. | .. |
|---|
| 9 | 10 | #include <linux/slab.h> |
|---|
| 10 | 11 | #include <linux/random.h> |
|---|
| 11 | 12 | #include <linux/vmalloc.h> |
|---|
| 13 | +#include <linux/ktime.h> |
|---|
| 12 | 14 | |
|---|
| 13 | 15 | #include <drm/drm_mm.h> |
|---|
| 14 | 16 | |
|---|
| .. | .. |
|---|
| 853 | 855 | |
|---|
| 854 | 856 | if (start > 0) { |
|---|
| 855 | 857 | node = __drm_mm_interval_first(mm, 0, start - 1); |
|---|
| 856 | | - if (node->allocated) { |
|---|
| 858 | + if (drm_mm_node_allocated(node)) { |
|---|
| 857 | 859 | pr_err("node before start: node=%llx+%llu, start=%llx\n", |
|---|
| 858 | 860 | node->start, node->size, start); |
|---|
| 859 | 861 | return false; |
|---|
| .. | .. |
|---|
| 862 | 864 | |
|---|
| 863 | 865 | if (end < U64_MAX) { |
|---|
| 864 | 866 | node = __drm_mm_interval_first(mm, end, U64_MAX); |
|---|
| 865 | | - if (node->allocated) { |
|---|
| 867 | + if (drm_mm_node_allocated(node)) { |
|---|
| 866 | 868 | pr_err("node after end: node=%llx+%llu, end=%llx\n", |
|---|
| 867 | 869 | node->start, node->size, end); |
|---|
| 868 | 870 | return false; |
|---|
| .. | .. |
|---|
| 1032 | 1034 | return 0; |
|---|
| 1033 | 1035 | } |
|---|
| 1034 | 1036 | |
|---|
| 1037 | +static int prepare_igt_frag(struct drm_mm *mm, |
|---|
| 1038 | + struct drm_mm_node *nodes, |
|---|
| 1039 | + unsigned int num_insert, |
|---|
| 1040 | + const struct insert_mode *mode) |
|---|
| 1041 | +{ |
|---|
| 1042 | + unsigned int size = 4096; |
|---|
| 1043 | + unsigned int i; |
|---|
| 1044 | + |
|---|
| 1045 | + for (i = 0; i < num_insert; i++) { |
|---|
| 1046 | + if (!expect_insert(mm, &nodes[i], size, 0, i, |
|---|
| 1047 | + mode) != 0) { |
|---|
| 1048 | + pr_err("%s insert failed\n", mode->name); |
|---|
| 1049 | + return -EINVAL; |
|---|
| 1050 | + } |
|---|
| 1051 | + } |
|---|
| 1052 | + |
|---|
| 1053 | + /* introduce fragmentation by freeing every other node */ |
|---|
| 1054 | + for (i = 0; i < num_insert; i++) { |
|---|
| 1055 | + if (i % 2 == 0) |
|---|
| 1056 | + drm_mm_remove_node(&nodes[i]); |
|---|
| 1057 | + } |
|---|
| 1058 | + |
|---|
| 1059 | + return 0; |
|---|
| 1060 | + |
|---|
| 1061 | +} |
|---|
| 1062 | + |
|---|
| 1063 | +static u64 get_insert_time(struct drm_mm *mm, |
|---|
| 1064 | + unsigned int num_insert, |
|---|
| 1065 | + struct drm_mm_node *nodes, |
|---|
| 1066 | + const struct insert_mode *mode) |
|---|
| 1067 | +{ |
|---|
| 1068 | + unsigned int size = 8192; |
|---|
| 1069 | + ktime_t start; |
|---|
| 1070 | + unsigned int i; |
|---|
| 1071 | + |
|---|
| 1072 | + start = ktime_get(); |
|---|
| 1073 | + for (i = 0; i < num_insert; i++) { |
|---|
| 1074 | + if (!expect_insert(mm, &nodes[i], size, 0, i, mode) != 0) { |
|---|
| 1075 | + pr_err("%s insert failed\n", mode->name); |
|---|
| 1076 | + return 0; |
|---|
| 1077 | + } |
|---|
| 1078 | + } |
|---|
| 1079 | + |
|---|
| 1080 | + return ktime_to_ns(ktime_sub(ktime_get(), start)); |
|---|
| 1081 | +} |
|---|
| 1082 | + |
|---|
| 1083 | +static int igt_frag(void *ignored) |
|---|
| 1084 | +{ |
|---|
| 1085 | + struct drm_mm mm; |
|---|
| 1086 | + const struct insert_mode *mode; |
|---|
| 1087 | + struct drm_mm_node *nodes, *node, *next; |
|---|
| 1088 | + unsigned int insert_size = 10000; |
|---|
| 1089 | + unsigned int scale_factor = 4; |
|---|
| 1090 | + int ret = -EINVAL; |
|---|
| 1091 | + |
|---|
| 1092 | + /* We need 4 * insert_size nodes to hold intermediate allocated |
|---|
| 1093 | + * drm_mm nodes. |
|---|
| 1094 | + * 1 times for prepare_igt_frag() |
|---|
| 1095 | + * 1 times for get_insert_time() |
|---|
| 1096 | + * 2 times for get_insert_time() |
|---|
| 1097 | + */ |
|---|
| 1098 | + nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes))); |
|---|
| 1099 | + if (!nodes) |
|---|
| 1100 | + return -ENOMEM; |
|---|
| 1101 | + |
|---|
| 1102 | + /* For BOTTOMUP and TOPDOWN, we first fragment the |
|---|
| 1103 | + * address space using prepare_igt_frag() and then try to verify |
|---|
| 1104 | + * that that insertions scale quadratically from 10k to 20k insertions |
|---|
| 1105 | + */ |
|---|
| 1106 | + drm_mm_init(&mm, 1, U64_MAX - 2); |
|---|
| 1107 | + for (mode = insert_modes; mode->name; mode++) { |
|---|
| 1108 | + u64 insert_time1, insert_time2; |
|---|
| 1109 | + |
|---|
| 1110 | + if (mode->mode != DRM_MM_INSERT_LOW && |
|---|
| 1111 | + mode->mode != DRM_MM_INSERT_HIGH) |
|---|
| 1112 | + continue; |
|---|
| 1113 | + |
|---|
| 1114 | + ret = prepare_igt_frag(&mm, nodes, insert_size, mode); |
|---|
| 1115 | + if (ret) |
|---|
| 1116 | + goto err; |
|---|
| 1117 | + |
|---|
| 1118 | + insert_time1 = get_insert_time(&mm, insert_size, |
|---|
| 1119 | + nodes + insert_size, mode); |
|---|
| 1120 | + if (insert_time1 == 0) |
|---|
| 1121 | + goto err; |
|---|
| 1122 | + |
|---|
| 1123 | + insert_time2 = get_insert_time(&mm, (insert_size * 2), |
|---|
| 1124 | + nodes + insert_size * 2, mode); |
|---|
| 1125 | + if (insert_time2 == 0) |
|---|
| 1126 | + goto err; |
|---|
| 1127 | + |
|---|
| 1128 | + pr_info("%s fragmented insert of %u and %u insertions took %llu and %llu nsecs\n", |
|---|
| 1129 | + mode->name, insert_size, insert_size * 2, |
|---|
| 1130 | + insert_time1, insert_time2); |
|---|
| 1131 | + |
|---|
| 1132 | + if (insert_time2 > (scale_factor * insert_time1)) { |
|---|
| 1133 | + pr_err("%s fragmented insert took %llu nsecs more\n", |
|---|
| 1134 | + mode->name, |
|---|
| 1135 | + insert_time2 - (scale_factor * insert_time1)); |
|---|
| 1136 | + goto err; |
|---|
| 1137 | + } |
|---|
| 1138 | + |
|---|
| 1139 | + drm_mm_for_each_node_safe(node, next, &mm) |
|---|
| 1140 | + drm_mm_remove_node(node); |
|---|
| 1141 | + } |
|---|
| 1142 | + |
|---|
| 1143 | + ret = 0; |
|---|
| 1144 | +err: |
|---|
| 1145 | + drm_mm_for_each_node_safe(node, next, &mm) |
|---|
| 1146 | + drm_mm_remove_node(node); |
|---|
| 1147 | + drm_mm_takedown(&mm); |
|---|
| 1148 | + vfree(nodes); |
|---|
| 1149 | + |
|---|
| 1150 | + return ret; |
|---|
| 1151 | +} |
|---|
| 1152 | + |
|---|
| 1035 | 1153 | static int igt_align(void *ignored) |
|---|
| 1036 | 1154 | { |
|---|
| 1037 | 1155 | const struct insert_mode *mode; |
|---|
| .. | .. |
|---|
| 1155 | 1273 | struct drm_mm_node *next = list_next_entry(hole, node_list); |
|---|
| 1156 | 1274 | const char *node1 = NULL, *node2 = NULL; |
|---|
| 1157 | 1275 | |
|---|
| 1158 | | - if (hole->allocated) |
|---|
| 1276 | + if (drm_mm_node_allocated(hole)) |
|---|
| 1159 | 1277 | node1 = kasprintf(GFP_KERNEL, |
|---|
| 1160 | 1278 | "[%llx + %lld, color=%ld], ", |
|---|
| 1161 | 1279 | hole->start, hole->size, hole->color); |
|---|
| 1162 | 1280 | |
|---|
| 1163 | | - if (next->allocated) |
|---|
| 1281 | + if (drm_mm_node_allocated(next)) |
|---|
| 1164 | 1282 | node2 = kasprintf(GFP_KERNEL, |
|---|
| 1165 | 1283 | ", [%llx + %lld, color=%ld]", |
|---|
| 1166 | 1284 | next->start, next->size, next->color); |
|---|
| .. | .. |
|---|
| 1615 | 1733 | DRM_RND_STATE(prng, random_seed); |
|---|
| 1616 | 1734 | const unsigned int count = 8192; |
|---|
| 1617 | 1735 | unsigned int size; |
|---|
| 1618 | | - unsigned long *bitmap = NULL; |
|---|
| 1736 | + unsigned long *bitmap; |
|---|
| 1619 | 1737 | struct drm_mm mm; |
|---|
| 1620 | 1738 | struct drm_mm_node *nodes, *node, *next; |
|---|
| 1621 | 1739 | unsigned int *order, n, m, o = 0; |
|---|
| .. | .. |
|---|
| 1631 | 1749 | if (!nodes) |
|---|
| 1632 | 1750 | goto err; |
|---|
| 1633 | 1751 | |
|---|
| 1634 | | - bitmap = kcalloc(count / BITS_PER_LONG, sizeof(unsigned long), |
|---|
| 1635 | | - GFP_KERNEL); |
|---|
| 1752 | + bitmap = bitmap_zalloc(count, GFP_KERNEL); |
|---|
| 1636 | 1753 | if (!bitmap) |
|---|
| 1637 | 1754 | goto err_nodes; |
|---|
| 1638 | 1755 | |
|---|
| .. | .. |
|---|
| 1717 | 1834 | drm_mm_takedown(&mm); |
|---|
| 1718 | 1835 | kfree(order); |
|---|
| 1719 | 1836 | err_bitmap: |
|---|
| 1720 | | - kfree(bitmap); |
|---|
| 1837 | + bitmap_free(bitmap); |
|---|
| 1721 | 1838 | err_nodes: |
|---|
| 1722 | 1839 | vfree(nodes); |
|---|
| 1723 | 1840 | err: |
|---|
| .. | .. |
|---|
| 1745 | 1862 | if (!nodes) |
|---|
| 1746 | 1863 | goto err; |
|---|
| 1747 | 1864 | |
|---|
| 1748 | | - bitmap = kcalloc(count / BITS_PER_LONG, sizeof(unsigned long), |
|---|
| 1749 | | - GFP_KERNEL); |
|---|
| 1865 | + bitmap = bitmap_zalloc(count, GFP_KERNEL); |
|---|
| 1750 | 1866 | if (!bitmap) |
|---|
| 1751 | 1867 | goto err_nodes; |
|---|
| 1752 | 1868 | |
|---|
| .. | .. |
|---|
| 1818 | 1934 | drm_mm_takedown(&mm); |
|---|
| 1819 | 1935 | kfree(order); |
|---|
| 1820 | 1936 | err_bitmap: |
|---|
| 1821 | | - kfree(bitmap); |
|---|
| 1937 | + bitmap_free(bitmap); |
|---|
| 1822 | 1938 | err_nodes: |
|---|
| 1823 | 1939 | vfree(nodes); |
|---|
| 1824 | 1940 | err: |
|---|
| .. | .. |
|---|
| 1858 | 1974 | } |
|---|
| 1859 | 1975 | |
|---|
| 1860 | 1976 | memset(&node, 0, sizeof(node)); |
|---|
| 1861 | | - err = drm_mm_insert_node_generic(&mm, &node, |
|---|
| 1862 | | - 2, 0, 0, |
|---|
| 1863 | | - mode | DRM_MM_INSERT_ONCE); |
|---|
| 1864 | | - if (!err) { |
|---|
| 1865 | | - pr_err("Unexpectedly inserted the node into the wrong hole: node.start=%llx\n", |
|---|
| 1866 | | - node.start); |
|---|
| 1867 | | - err = -EINVAL; |
|---|
| 1868 | | - goto err_node; |
|---|
| 1869 | | - } |
|---|
| 1870 | | - |
|---|
| 1871 | 1977 | err = drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode); |
|---|
| 1872 | 1978 | if (err) { |
|---|
| 1873 | 1979 | pr_err("Could not insert the node into the available hole!\n"); |
|---|
| .. | .. |
|---|
| 1875 | 1981 | goto err_hi; |
|---|
| 1876 | 1982 | } |
|---|
| 1877 | 1983 | |
|---|
| 1878 | | -err_node: |
|---|
| 1879 | 1984 | drm_mm_remove_node(&node); |
|---|
| 1880 | 1985 | err_hi: |
|---|
| 1881 | 1986 | drm_mm_remove_node(&rsvd_hi); |
|---|
| .. | .. |
|---|
| 1901 | 2006 | u64 *start, |
|---|
| 1902 | 2007 | u64 *end) |
|---|
| 1903 | 2008 | { |
|---|
| 1904 | | - if (node->allocated && node->color != color) |
|---|
| 2009 | + if (drm_mm_node_allocated(node) && node->color != color) |
|---|
| 1905 | 2010 | ++*start; |
|---|
| 1906 | 2011 | |
|---|
| 1907 | 2012 | node = list_next_entry(node, node_list); |
|---|
| 1908 | | - if (node->allocated && node->color != color) |
|---|
| 2013 | + if (drm_mm_node_allocated(node) && node->color != color) |
|---|
| 1909 | 2014 | --*end; |
|---|
| 1910 | 2015 | } |
|---|
| 1911 | 2016 | |
|---|
| 1912 | 2017 | static bool colors_abutt(const struct drm_mm_node *node) |
|---|
| 1913 | 2018 | { |
|---|
| 1914 | 2019 | if (!drm_mm_hole_follows(node) && |
|---|
| 1915 | | - list_next_entry(node, node_list)->allocated) { |
|---|
| 2020 | + drm_mm_node_allocated(list_next_entry(node, node_list))) { |
|---|
| 1916 | 2021 | pr_err("colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n", |
|---|
| 1917 | 2022 | node->color, node->start, node->size, |
|---|
| 1918 | 2023 | list_next_entry(node, node_list)->color, |
|---|
| .. | .. |
|---|
| 2360 | 2465 | while (!random_seed) |
|---|
| 2361 | 2466 | random_seed = get_random_int(); |
|---|
| 2362 | 2467 | |
|---|
| 2363 | | - pr_info("Testing DRM range manger (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n", |
|---|
| 2468 | + pr_info("Testing DRM range manager (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n", |
|---|
| 2364 | 2469 | random_seed, max_iterations, max_prime); |
|---|
| 2365 | 2470 | err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL); |
|---|
| 2366 | 2471 | |
|---|