162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2020 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_cistatic struct intel_ring *mock_ring(unsigned long sz) 762306a36Sopenharmony_ci{ 862306a36Sopenharmony_ci struct intel_ring *ring; 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL); 1162306a36Sopenharmony_ci if (!ring) 1262306a36Sopenharmony_ci return NULL; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci kref_init(&ring->ref); 1562306a36Sopenharmony_ci ring->size = sz; 1662306a36Sopenharmony_ci ring->wrap = BITS_PER_TYPE(ring->size) - ilog2(sz); 1762306a36Sopenharmony_ci ring->effective_size = sz; 1862306a36Sopenharmony_ci ring->vaddr = (void *)(ring + 1); 1962306a36Sopenharmony_ci atomic_set(&ring->pin_count, 1); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci intel_ring_update_space(ring); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci return ring; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void mock_ring_free(struct intel_ring *ring) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci kfree(ring); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int check_ring_direction(struct intel_ring *ring, 3262306a36Sopenharmony_ci u32 next, u32 prev, 3362306a36Sopenharmony_ci int expected) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci int result; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci result = intel_ring_direction(ring, next, prev); 3862306a36Sopenharmony_ci if (result < 0) 3962306a36Sopenharmony_ci result = -1; 4062306a36Sopenharmony_ci else if (result > 0) 4162306a36Sopenharmony_ci result = 1; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (result != expected) { 4462306a36Sopenharmony_ci pr_err("intel_ring_direction(%u, %u):%d != %d\n", 4562306a36Sopenharmony_ci next, prev, result, expected); 4662306a36Sopenharmony_ci return -EINVAL; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int check_ring_step(struct intel_ring *ring, u32 x, u32 step) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci u32 prev = x, next = intel_ring_wrap(ring, x + step); 5562306a36Sopenharmony_ci int err = 0; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci err |= check_ring_direction(ring, next, next, 0); 5862306a36Sopenharmony_ci err |= check_ring_direction(ring, prev, prev, 0); 5962306a36Sopenharmony_ci err |= check_ring_direction(ring, next, prev, 1); 6062306a36Sopenharmony_ci err |= check_ring_direction(ring, prev, next, -1); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return err; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int check_ring_offset(struct intel_ring *ring, u32 x, u32 step) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci int err = 0; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci err |= check_ring_step(ring, x, step); 7062306a36Sopenharmony_ci err |= check_ring_step(ring, intel_ring_wrap(ring, x + 1), step); 7162306a36Sopenharmony_ci err |= check_ring_step(ring, intel_ring_wrap(ring, x - 1), step); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return err; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int igt_ring_direction(void *dummy) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct intel_ring *ring; 7962306a36Sopenharmony_ci unsigned int half = 2048; 8062306a36Sopenharmony_ci int step, err = 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ring = mock_ring(2 * half); 8362306a36Sopenharmony_ci if (!ring) 8462306a36Sopenharmony_ci return -ENOMEM; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci GEM_BUG_ON(ring->size != 2 * half); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* Precision of wrap detection is limited to ring->size / 2 */ 8962306a36Sopenharmony_ci for (step = 1; step < half; step <<= 1) { 9062306a36Sopenharmony_ci err |= check_ring_offset(ring, 0, step); 9162306a36Sopenharmony_ci err |= check_ring_offset(ring, half, step); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci err |= check_ring_step(ring, 0, half - 64); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* And check unwrapped handling for good measure */ 9662306a36Sopenharmony_ci err |= check_ring_offset(ring, 0, 2 * half + 64); 9762306a36Sopenharmony_ci err |= check_ring_offset(ring, 3 * half, 1); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci mock_ring_free(ring); 10062306a36Sopenharmony_ci return err; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ciint intel_ring_mock_selftests(void) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci static const struct i915_subtest tests[] = { 10662306a36Sopenharmony_ci SUBTEST(igt_ring_direction), 10762306a36Sopenharmony_ci }; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return i915_subtests(tests, NULL); 11062306a36Sopenharmony_ci} 111