@@ -5,6 +5,7 @@
*
* Tests are executed in reverse order by igt/drm_mm
*/
+selftest(color, igt_color)
selftest(topdown_align, igt_topdown_align)
selftest(topdown, igt_topdown)
selftest(evict_range, igt_evict_range)
@@ -1403,6 +1403,189 @@ static int igt_topdown_align(void *ignored)
return ret;
}
+static void no_color_touching(struct drm_mm_node *node,
+ unsigned long color,
+ u64 *start,
+ u64 *end)
+{
+ if (node->allocated && node->color != color)
+ ++*start;
+
+ node = list_next_entry(node, node_list);
+ if (node->allocated && node->color != color)
+ --*end;
+}
+
+static int igt_color(void *ignored)
+{
+ const int count = 4096;
+ struct drm_mm mm;
+ struct drm_mm_node *node, *nn;
+ const struct modes {
+ const char *name;
+ unsigned int search;
+ unsigned int create;
+ } modes[] = {
+ { "default", DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT },
+ { "best", DRM_MM_SEARCH_BEST, DRM_MM_CREATE_DEFAULT },
+ { "top-down", DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP },
+ };
+ int ret = -EINVAL;
+ int n, m;
+
+ drm_mm_init(&mm, 0, ~0ull);
+
+ for (n = 1; n <= count; n++) {
+ int err;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ err = drm_mm_insert_node_generic(&mm, node, n, 0, n,
+ DRM_MM_SEARCH_DEFAULT,
+ DRM_MM_CREATE_DEFAULT);
+ if (err) {
+ pr_err("insert failed, step %d\n", n);
+ kfree(node);
+ ret = err;
+ goto out;
+ }
+ }
+
+ drm_mm_for_each_node_safe(node, nn, &mm) {
+ if (node->color != node->size) {
+ pr_err("invalid color stored: expected %lld, found %ld\n",
+ node->size, node->color);
+
+ goto out;
+ }
+
+ drm_mm_remove_node(node);
+ kfree(node);
+ }
+
+ /* Now, let's start experimenting with applying a color callback */
+ mm.color_adjust = no_color_touching;
+ for (m = 0; m < ARRAY_SIZE(modes); m++) {
+ u64 last;
+ int err;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ node->size = 1 + 2*count;
+ node->color = node->size;
+
+ err = drm_mm_reserve_node(&mm, node);
+ if (err) {
+ pr_err("initial reserve failed!\n");
+ goto out;
+ }
+
+ last = node->start + node->size;
+
+ for (n = 1; n <= count; n++) {
+ int rem;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ node->start = last;
+ node->size = n + count;
+ node->color = node->size;
+
+ err = drm_mm_reserve_node(&mm, node);
+ if (err != -ENOSPC) {
+ pr_err("reserve %d did not report color overlap! err=%d\n",
+ n, err);
+ goto out;
+ }
+
+ node->start += n + 1;
+ rem = node->start;
+ rem %= n + count;
+ node->start += n + count - rem;
+
+ err = drm_mm_reserve_node(&mm, node);
+ if (err) {
+ pr_err("reserve %d failed, err=%d\n", n, err);
+ goto out;
+ }
+
+ last = node->start + node->size;
+ }
+
+ for (n = 1; n <= count; n++) {
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ err = drm_mm_insert_node_generic(&mm, node, n, n, n,
+ modes[m].search,
+ modes[m].create);
+ if (err) {
+ pr_err("%s insert failed, step %d, err=%d\n",
+ modes[m].name, n, err);
+ kfree(node);
+ ret = err;
+ goto out;
+ }
+ }
+
+ drm_mm_for_each_node_safe(node, nn, &mm) {
+ u64 rem;
+
+ if (node->color != node->size) {
+ pr_err("%s invalid color stored: expected %lld, found %ld\n",
+ modes[m].name, node->size, node->color);
+
+ goto out;
+ }
+
+ if (!node->hole_follows &&
+ list_next_entry(node, node_list)->allocated) {
+ pr_err("%s colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n",
+ modes[m].name,
+ node->color, node->start, node->size,
+ list_next_entry(node, node_list)->color,
+ list_next_entry(node, node_list)->start,
+ list_next_entry(node, node_list)->size);
+ goto out;
+ }
+
+ div64_u64_rem(node->start, node->size, &rem);
+ if (rem) {
+ pr_err("%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n",
+ modes[m].name, node->start, node->size, rem);
+ goto out;
+ }
+
+ drm_mm_remove_node(node);
+ kfree(node);
+ }
+ }
+
+ ret = 0;
+out:
+ drm_mm_for_each_node_safe(node, nn, &mm) {
+ drm_mm_remove_node(node);
+ kfree(node);
+ }
+ drm_mm_takedown(&mm);
+ return ret;
+}
+
#include "drm_selftest.c"
static int __init test_drm_mm_init(void)
Check that after applying the driver's color adjustment, fitting of the node and its alignment are still correct. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/selftests/drm_mm_selftests.h | 1 + drivers/gpu/drm/selftests/test-drm_mm.c | 183 +++++++++++++++++++++++++++ 2 files changed, 184 insertions(+)