| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright © 2020 Intel Corporation |
| */ |
| |
| static struct intel_ring *mock_ring(unsigned long sz) |
| { |
| struct intel_ring *ring; |
| |
| ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL); |
| if (!ring) |
| return NULL; |
| |
| kref_init(&ring->ref); |
| ring->size = sz; |
| ring->wrap = BITS_PER_TYPE(ring->size) - ilog2(sz); |
| ring->effective_size = sz; |
| ring->vaddr = (void *)(ring + 1); |
| atomic_set(&ring->pin_count, 1); |
| |
| intel_ring_update_space(ring); |
| |
| return ring; |
| } |
| |
| static void mock_ring_free(struct intel_ring *ring) |
| { |
| kfree(ring); |
| } |
| |
| static int check_ring_direction(struct intel_ring *ring, |
| u32 next, u32 prev, |
| int expected) |
| { |
| int result; |
| |
| result = intel_ring_direction(ring, next, prev); |
| if (result < 0) |
| result = -1; |
| else if (result > 0) |
| result = 1; |
| |
| if (result != expected) { |
| pr_err("intel_ring_direction(%u, %u):%d != %d\n", |
| next, prev, result, expected); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static int check_ring_step(struct intel_ring *ring, u32 x, u32 step) |
| { |
| u32 prev = x, next = intel_ring_wrap(ring, x + step); |
| int err = 0; |
| |
| err |= check_ring_direction(ring, next, next, 0); |
| err |= check_ring_direction(ring, prev, prev, 0); |
| err |= check_ring_direction(ring, next, prev, 1); |
| err |= check_ring_direction(ring, prev, next, -1); |
| |
| return err; |
| } |
| |
| static int check_ring_offset(struct intel_ring *ring, u32 x, u32 step) |
| { |
| int err = 0; |
| |
| err |= check_ring_step(ring, x, step); |
| err |= check_ring_step(ring, intel_ring_wrap(ring, x + 1), step); |
| err |= check_ring_step(ring, intel_ring_wrap(ring, x - 1), step); |
| |
| return err; |
| } |
| |
| static int igt_ring_direction(void *dummy) |
| { |
| struct intel_ring *ring; |
| unsigned int half = 2048; |
| int step, err = 0; |
| |
| ring = mock_ring(2 * half); |
| if (!ring) |
| return -ENOMEM; |
| |
| GEM_BUG_ON(ring->size != 2 * half); |
| |
| /* Precision of wrap detection is limited to ring->size / 2 */ |
| for (step = 1; step < half; step <<= 1) { |
| err |= check_ring_offset(ring, 0, step); |
| err |= check_ring_offset(ring, half, step); |
| } |
| err |= check_ring_step(ring, 0, half - 64); |
| |
| /* And check unwrapped handling for good measure */ |
| err |= check_ring_offset(ring, 0, 2 * half + 64); |
| err |= check_ring_offset(ring, 3 * half, 1); |
| |
| mock_ring_free(ring); |
| return err; |
| } |
| |
| int intel_ring_mock_selftests(void) |
| { |
| static const struct i915_subtest tests[] = { |
| SUBTEST(igt_ring_direction), |
| }; |
| |
| return i915_subtests(tests, NULL); |
| } |