.. | .. |
---|
| 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 | |
---|