162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "gem/i915_gem_internal.h" 762306a36Sopenharmony_ci#include "gem/i915_gem_lmem.h" 862306a36Sopenharmony_ci#include "gem/i915_gem_object.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "i915_drv.h" 1162306a36Sopenharmony_ci#include "i915_vma.h" 1262306a36Sopenharmony_ci#include "intel_engine.h" 1362306a36Sopenharmony_ci#include "intel_engine_regs.h" 1462306a36Sopenharmony_ci#include "intel_gpu_commands.h" 1562306a36Sopenharmony_ci#include "intel_ring.h" 1662306a36Sopenharmony_ci#include "intel_gt.h" 1762306a36Sopenharmony_ci#include "intel_timeline.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciunsigned int intel_ring_update_space(struct intel_ring *ring) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci unsigned int space; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci space = __intel_ring_space(ring->head, ring->emit, ring->size); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci ring->space = space; 2662306a36Sopenharmony_ci return space; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_civoid __intel_ring_pin(struct intel_ring *ring) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci GEM_BUG_ON(!atomic_read(&ring->pin_count)); 3262306a36Sopenharmony_ci atomic_inc(&ring->pin_count); 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint intel_ring_pin(struct intel_ring *ring, struct i915_gem_ww_ctx *ww) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct i915_vma *vma = ring->vma; 3862306a36Sopenharmony_ci unsigned int flags; 3962306a36Sopenharmony_ci void *addr; 4062306a36Sopenharmony_ci int ret; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (atomic_fetch_inc(&ring->pin_count)) 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* Ring wraparound at offset 0 sometimes hangs. No idea why. */ 4662306a36Sopenharmony_ci flags = PIN_OFFSET_BIAS | i915_ggtt_pin_bias(vma); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (i915_gem_object_is_stolen(vma->obj)) 4962306a36Sopenharmony_ci flags |= PIN_MAPPABLE; 5062306a36Sopenharmony_ci else 5162306a36Sopenharmony_ci flags |= PIN_HIGH; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci ret = i915_ggtt_pin(vma, ww, 0, flags); 5462306a36Sopenharmony_ci if (unlikely(ret)) 5562306a36Sopenharmony_ci goto err_unpin; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (i915_vma_is_map_and_fenceable(vma) && !HAS_LLC(vma->vm->i915)) { 5862306a36Sopenharmony_ci addr = (void __force *)i915_vma_pin_iomap(vma); 5962306a36Sopenharmony_ci } else { 6062306a36Sopenharmony_ci int type = intel_gt_coherent_map_type(vma->vm->gt, vma->obj, false); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci addr = i915_gem_object_pin_map(vma->obj, type); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (IS_ERR(addr)) { 6662306a36Sopenharmony_ci ret = PTR_ERR(addr); 6762306a36Sopenharmony_ci goto err_ring; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci i915_vma_make_unshrinkable(vma); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* Discard any unused bytes beyond that submitted to hw. */ 7362306a36Sopenharmony_ci intel_ring_reset(ring, ring->emit); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci ring->vaddr = addr; 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cierr_ring: 7962306a36Sopenharmony_ci i915_vma_unpin(vma); 8062306a36Sopenharmony_cierr_unpin: 8162306a36Sopenharmony_ci atomic_dec(&ring->pin_count); 8262306a36Sopenharmony_ci return ret; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_civoid intel_ring_reset(struct intel_ring *ring, u32 tail) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci tail = intel_ring_wrap(ring, tail); 8862306a36Sopenharmony_ci ring->tail = tail; 8962306a36Sopenharmony_ci ring->head = tail; 9062306a36Sopenharmony_ci ring->emit = tail; 9162306a36Sopenharmony_ci intel_ring_update_space(ring); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_civoid intel_ring_unpin(struct intel_ring *ring) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct i915_vma *vma = ring->vma; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (!atomic_dec_and_test(&ring->pin_count)) 9962306a36Sopenharmony_ci return; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci i915_vma_unset_ggtt_write(vma); 10262306a36Sopenharmony_ci if (i915_vma_is_map_and_fenceable(vma) && !HAS_LLC(vma->vm->i915)) 10362306a36Sopenharmony_ci i915_vma_unpin_iomap(vma); 10462306a36Sopenharmony_ci else 10562306a36Sopenharmony_ci i915_gem_object_unpin_map(vma->obj); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci i915_vma_make_purgeable(vma); 10862306a36Sopenharmony_ci i915_vma_unpin(vma); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct i915_vma *create_ring_vma(struct i915_ggtt *ggtt, int size) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct i915_address_space *vm = &ggtt->vm; 11462306a36Sopenharmony_ci struct drm_i915_private *i915 = vm->i915; 11562306a36Sopenharmony_ci struct drm_i915_gem_object *obj; 11662306a36Sopenharmony_ci struct i915_vma *vma; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci obj = i915_gem_object_create_lmem(i915, size, I915_BO_ALLOC_VOLATILE | 11962306a36Sopenharmony_ci I915_BO_ALLOC_PM_VOLATILE); 12062306a36Sopenharmony_ci if (IS_ERR(obj) && i915_ggtt_has_aperture(ggtt) && !HAS_LLC(i915)) 12162306a36Sopenharmony_ci obj = i915_gem_object_create_stolen(i915, size); 12262306a36Sopenharmony_ci if (IS_ERR(obj)) 12362306a36Sopenharmony_ci obj = i915_gem_object_create_internal(i915, size); 12462306a36Sopenharmony_ci if (IS_ERR(obj)) 12562306a36Sopenharmony_ci return ERR_CAST(obj); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * Mark ring buffers as read-only from GPU side (so no stray overwrites) 12962306a36Sopenharmony_ci * if supported by the platform's GGTT. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci if (vm->has_read_only) 13262306a36Sopenharmony_ci i915_gem_object_set_readonly(obj); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci vma = i915_vma_instance(obj, vm, NULL); 13562306a36Sopenharmony_ci if (IS_ERR(vma)) 13662306a36Sopenharmony_ci goto err; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return vma; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cierr: 14162306a36Sopenharmony_ci i915_gem_object_put(obj); 14262306a36Sopenharmony_ci return vma; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistruct intel_ring * 14662306a36Sopenharmony_ciintel_engine_create_ring(struct intel_engine_cs *engine, int size) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct drm_i915_private *i915 = engine->i915; 14962306a36Sopenharmony_ci struct intel_ring *ring; 15062306a36Sopenharmony_ci struct i915_vma *vma; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci GEM_BUG_ON(!is_power_of_2(size)); 15362306a36Sopenharmony_ci GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci ring = kzalloc(sizeof(*ring), GFP_KERNEL); 15662306a36Sopenharmony_ci if (!ring) 15762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci kref_init(&ring->ref); 16062306a36Sopenharmony_ci ring->size = size; 16162306a36Sopenharmony_ci ring->wrap = BITS_PER_TYPE(ring->size) - ilog2(size); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* 16462306a36Sopenharmony_ci * Workaround an erratum on the i830 which causes a hang if 16562306a36Sopenharmony_ci * the TAIL pointer points to within the last 2 cachelines 16662306a36Sopenharmony_ci * of the buffer. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci ring->effective_size = size; 16962306a36Sopenharmony_ci if (IS_I830(i915) || IS_I845G(i915)) 17062306a36Sopenharmony_ci ring->effective_size -= 2 * CACHELINE_BYTES; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci intel_ring_update_space(ring); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci vma = create_ring_vma(engine->gt->ggtt, size); 17562306a36Sopenharmony_ci if (IS_ERR(vma)) { 17662306a36Sopenharmony_ci kfree(ring); 17762306a36Sopenharmony_ci return ERR_CAST(vma); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci ring->vma = vma; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return ring; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_civoid intel_ring_free(struct kref *ref) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct intel_ring *ring = container_of(ref, typeof(*ring), ref); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci i915_vma_put(ring->vma); 18962306a36Sopenharmony_ci kfree(ring); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic noinline int 19362306a36Sopenharmony_ciwait_for_space(struct intel_ring *ring, 19462306a36Sopenharmony_ci struct intel_timeline *tl, 19562306a36Sopenharmony_ci unsigned int bytes) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct i915_request *target; 19862306a36Sopenharmony_ci long timeout; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (intel_ring_update_space(ring) >= bytes) 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci GEM_BUG_ON(list_empty(&tl->requests)); 20462306a36Sopenharmony_ci list_for_each_entry(target, &tl->requests, link) { 20562306a36Sopenharmony_ci if (target->ring != ring) 20662306a36Sopenharmony_ci continue; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Would completion of this request free enough space? */ 20962306a36Sopenharmony_ci if (bytes <= __intel_ring_space(target->postfix, 21062306a36Sopenharmony_ci ring->emit, ring->size)) 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (GEM_WARN_ON(&target->link == &tl->requests)) 21562306a36Sopenharmony_ci return -ENOSPC; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci timeout = i915_request_wait(target, 21862306a36Sopenharmony_ci I915_WAIT_INTERRUPTIBLE, 21962306a36Sopenharmony_ci MAX_SCHEDULE_TIMEOUT); 22062306a36Sopenharmony_ci if (timeout < 0) 22162306a36Sopenharmony_ci return timeout; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci i915_request_retire_upto(target); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci intel_ring_update_space(ring); 22662306a36Sopenharmony_ci GEM_BUG_ON(ring->space < bytes); 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ciu32 *intel_ring_begin(struct i915_request *rq, unsigned int num_dwords) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct intel_ring *ring = rq->ring; 23362306a36Sopenharmony_ci const unsigned int remain_usable = ring->effective_size - ring->emit; 23462306a36Sopenharmony_ci const unsigned int bytes = num_dwords * sizeof(u32); 23562306a36Sopenharmony_ci unsigned int need_wrap = 0; 23662306a36Sopenharmony_ci unsigned int total_bytes; 23762306a36Sopenharmony_ci u32 *cs; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Packets must be qword aligned. */ 24062306a36Sopenharmony_ci GEM_BUG_ON(num_dwords & 1); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci total_bytes = bytes + rq->reserved_space; 24362306a36Sopenharmony_ci GEM_BUG_ON(total_bytes > ring->effective_size); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (unlikely(total_bytes > remain_usable)) { 24662306a36Sopenharmony_ci const int remain_actual = ring->size - ring->emit; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (bytes > remain_usable) { 24962306a36Sopenharmony_ci /* 25062306a36Sopenharmony_ci * Not enough space for the basic request. So need to 25162306a36Sopenharmony_ci * flush out the remainder and then wait for 25262306a36Sopenharmony_ci * base + reserved. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci total_bytes += remain_actual; 25562306a36Sopenharmony_ci need_wrap = remain_actual | 1; 25662306a36Sopenharmony_ci } else { 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * The base request will fit but the reserved space 25962306a36Sopenharmony_ci * falls off the end. So we don't need an immediate 26062306a36Sopenharmony_ci * wrap and only need to effectively wait for the 26162306a36Sopenharmony_ci * reserved size from the start of ringbuffer. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci total_bytes = rq->reserved_space + remain_actual; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (unlikely(total_bytes > ring->space)) { 26862306a36Sopenharmony_ci int ret; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* 27162306a36Sopenharmony_ci * Space is reserved in the ringbuffer for finalising the 27262306a36Sopenharmony_ci * request, as that cannot be allowed to fail. During request 27362306a36Sopenharmony_ci * finalisation, reserved_space is set to 0 to stop the 27462306a36Sopenharmony_ci * overallocation and the assumption is that then we never need 27562306a36Sopenharmony_ci * to wait (which has the risk of failing with EINTR). 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * See also i915_request_alloc() and i915_request_add(). 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci GEM_BUG_ON(!rq->reserved_space); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ret = wait_for_space(ring, 28262306a36Sopenharmony_ci i915_request_timeline(rq), 28362306a36Sopenharmony_ci total_bytes); 28462306a36Sopenharmony_ci if (unlikely(ret)) 28562306a36Sopenharmony_ci return ERR_PTR(ret); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (unlikely(need_wrap)) { 28962306a36Sopenharmony_ci need_wrap &= ~1; 29062306a36Sopenharmony_ci GEM_BUG_ON(need_wrap > ring->space); 29162306a36Sopenharmony_ci GEM_BUG_ON(ring->emit + need_wrap > ring->size); 29262306a36Sopenharmony_ci GEM_BUG_ON(!IS_ALIGNED(need_wrap, sizeof(u64))); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Fill the tail with MI_NOOP */ 29562306a36Sopenharmony_ci memset64(ring->vaddr + ring->emit, 0, need_wrap / sizeof(u64)); 29662306a36Sopenharmony_ci ring->space -= need_wrap; 29762306a36Sopenharmony_ci ring->emit = 0; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci GEM_BUG_ON(ring->emit > ring->size - bytes); 30162306a36Sopenharmony_ci GEM_BUG_ON(ring->space < bytes); 30262306a36Sopenharmony_ci cs = ring->vaddr + ring->emit; 30362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) 30462306a36Sopenharmony_ci memset32(cs, POISON_INUSE, bytes / sizeof(*cs)); 30562306a36Sopenharmony_ci ring->emit += bytes; 30662306a36Sopenharmony_ci ring->space -= bytes; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return cs; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* Align the ring tail to a cacheline boundary */ 31262306a36Sopenharmony_ciint intel_ring_cacheline_align(struct i915_request *rq) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci int num_dwords; 31562306a36Sopenharmony_ci void *cs; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci num_dwords = (rq->ring->emit & (CACHELINE_BYTES - 1)) / sizeof(u32); 31862306a36Sopenharmony_ci if (num_dwords == 0) 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci num_dwords = CACHELINE_DWORDS - num_dwords; 32262306a36Sopenharmony_ci GEM_BUG_ON(num_dwords & 1); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci cs = intel_ring_begin(rq, num_dwords); 32562306a36Sopenharmony_ci if (IS_ERR(cs)) 32662306a36Sopenharmony_ci return PTR_ERR(cs); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci memset64(cs, (u64)MI_NOOP << 32 | MI_NOOP, num_dwords / 2); 32962306a36Sopenharmony_ci intel_ring_advance(rq, cs + num_dwords); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci GEM_BUG_ON(rq->ring->emit & (CACHELINE_BYTES - 1)); 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 33662306a36Sopenharmony_ci#include "selftest_ring.c" 33762306a36Sopenharmony_ci#endif 338