18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * SPDX-License-Identifier: MIT
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2016-2018 Intel Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "i915_drv.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "i915_active.h"
108c2ecf20Sopenharmony_ci#include "i915_syncmap.h"
118c2ecf20Sopenharmony_ci#include "intel_gt.h"
128c2ecf20Sopenharmony_ci#include "intel_ring.h"
138c2ecf20Sopenharmony_ci#include "intel_timeline.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define ptr_set_bit(ptr, bit) ((typeof(ptr))((unsigned long)(ptr) | BIT(bit)))
168c2ecf20Sopenharmony_ci#define ptr_test_bit(ptr, bit) ((unsigned long)(ptr) & BIT(bit))
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define CACHELINE_BITS 6
198c2ecf20Sopenharmony_ci#define CACHELINE_FREE CACHELINE_BITS
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct intel_timeline_hwsp {
228c2ecf20Sopenharmony_ci	struct intel_gt *gt;
238c2ecf20Sopenharmony_ci	struct intel_gt_timelines *gt_timelines;
248c2ecf20Sopenharmony_ci	struct list_head free_link;
258c2ecf20Sopenharmony_ci	struct i915_vma *vma;
268c2ecf20Sopenharmony_ci	u64 free_bitmap;
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic struct i915_vma *__hwsp_alloc(struct intel_gt *gt)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = gt->i915;
328c2ecf20Sopenharmony_ci	struct drm_i915_gem_object *obj;
338c2ecf20Sopenharmony_ci	struct i915_vma *vma;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
368c2ecf20Sopenharmony_ci	if (IS_ERR(obj))
378c2ecf20Sopenharmony_ci		return ERR_CAST(obj);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	i915_gem_object_set_cache_coherency(obj, I915_CACHE_LLC);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	vma = i915_vma_instance(obj, &gt->ggtt->vm, NULL);
428c2ecf20Sopenharmony_ci	if (IS_ERR(vma))
438c2ecf20Sopenharmony_ci		i915_gem_object_put(obj);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	return vma;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic struct i915_vma *
498c2ecf20Sopenharmony_cihwsp_alloc(struct intel_timeline *timeline, unsigned int *cacheline)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct intel_gt_timelines *gt = &timeline->gt->timelines;
528c2ecf20Sopenharmony_ci	struct intel_timeline_hwsp *hwsp;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	BUILD_BUG_ON(BITS_PER_TYPE(u64) * CACHELINE_BYTES > PAGE_SIZE);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	spin_lock_irq(&gt->hwsp_lock);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* hwsp_free_list only contains HWSP that have available cachelines */
598c2ecf20Sopenharmony_ci	hwsp = list_first_entry_or_null(&gt->hwsp_free_list,
608c2ecf20Sopenharmony_ci					typeof(*hwsp), free_link);
618c2ecf20Sopenharmony_ci	if (!hwsp) {
628c2ecf20Sopenharmony_ci		struct i915_vma *vma;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		spin_unlock_irq(&gt->hwsp_lock);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		hwsp = kmalloc(sizeof(*hwsp), GFP_KERNEL);
678c2ecf20Sopenharmony_ci		if (!hwsp)
688c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		vma = __hwsp_alloc(timeline->gt);
718c2ecf20Sopenharmony_ci		if (IS_ERR(vma)) {
728c2ecf20Sopenharmony_ci			kfree(hwsp);
738c2ecf20Sopenharmony_ci			return vma;
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci		GT_TRACE(timeline->gt, "new HWSP allocated\n");
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		vma->private = hwsp;
798c2ecf20Sopenharmony_ci		hwsp->gt = timeline->gt;
808c2ecf20Sopenharmony_ci		hwsp->vma = vma;
818c2ecf20Sopenharmony_ci		hwsp->free_bitmap = ~0ull;
828c2ecf20Sopenharmony_ci		hwsp->gt_timelines = gt;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci		spin_lock_irq(&gt->hwsp_lock);
858c2ecf20Sopenharmony_ci		list_add(&hwsp->free_link, &gt->hwsp_free_list);
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	GEM_BUG_ON(!hwsp->free_bitmap);
898c2ecf20Sopenharmony_ci	*cacheline = __ffs64(hwsp->free_bitmap);
908c2ecf20Sopenharmony_ci	hwsp->free_bitmap &= ~BIT_ULL(*cacheline);
918c2ecf20Sopenharmony_ci	if (!hwsp->free_bitmap)
928c2ecf20Sopenharmony_ci		list_del(&hwsp->free_link);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	spin_unlock_irq(&gt->hwsp_lock);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	GEM_BUG_ON(hwsp->vma->private != hwsp);
978c2ecf20Sopenharmony_ci	return hwsp->vma;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic void __idle_hwsp_free(struct intel_timeline_hwsp *hwsp, int cacheline)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct intel_gt_timelines *gt = hwsp->gt_timelines;
1038c2ecf20Sopenharmony_ci	unsigned long flags;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gt->hwsp_lock, flags);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* As a cacheline becomes available, publish the HWSP on the freelist */
1088c2ecf20Sopenharmony_ci	if (!hwsp->free_bitmap)
1098c2ecf20Sopenharmony_ci		list_add_tail(&hwsp->free_link, &gt->hwsp_free_list);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	GEM_BUG_ON(cacheline >= BITS_PER_TYPE(hwsp->free_bitmap));
1128c2ecf20Sopenharmony_ci	hwsp->free_bitmap |= BIT_ULL(cacheline);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* And if no one is left using it, give the page back to the system */
1158c2ecf20Sopenharmony_ci	if (hwsp->free_bitmap == ~0ull) {
1168c2ecf20Sopenharmony_ci		i915_vma_put(hwsp->vma);
1178c2ecf20Sopenharmony_ci		list_del(&hwsp->free_link);
1188c2ecf20Sopenharmony_ci		kfree(hwsp);
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gt->hwsp_lock, flags);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic void __rcu_cacheline_free(struct rcu_head *rcu)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	struct intel_timeline_cacheline *cl =
1278c2ecf20Sopenharmony_ci		container_of(rcu, typeof(*cl), rcu);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* Must wait until after all *rq->hwsp are complete before removing */
1308c2ecf20Sopenharmony_ci	i915_gem_object_unpin_map(cl->hwsp->vma->obj);
1318c2ecf20Sopenharmony_ci	__idle_hwsp_free(cl->hwsp, ptr_unmask_bits(cl->vaddr, CACHELINE_BITS));
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	i915_active_fini(&cl->active);
1348c2ecf20Sopenharmony_ci	kfree(cl);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void __idle_cacheline_free(struct intel_timeline_cacheline *cl)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	GEM_BUG_ON(!i915_active_is_idle(&cl->active));
1408c2ecf20Sopenharmony_ci	call_rcu(&cl->rcu, __rcu_cacheline_free);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci__i915_active_call
1448c2ecf20Sopenharmony_cistatic void __cacheline_retire(struct i915_active *active)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct intel_timeline_cacheline *cl =
1478c2ecf20Sopenharmony_ci		container_of(active, typeof(*cl), active);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	i915_vma_unpin(cl->hwsp->vma);
1508c2ecf20Sopenharmony_ci	if (ptr_test_bit(cl->vaddr, CACHELINE_FREE))
1518c2ecf20Sopenharmony_ci		__idle_cacheline_free(cl);
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic int __cacheline_active(struct i915_active *active)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct intel_timeline_cacheline *cl =
1578c2ecf20Sopenharmony_ci		container_of(active, typeof(*cl), active);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	__i915_vma_pin(cl->hwsp->vma);
1608c2ecf20Sopenharmony_ci	return 0;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic struct intel_timeline_cacheline *
1648c2ecf20Sopenharmony_cicacheline_alloc(struct intel_timeline_hwsp *hwsp, unsigned int cacheline)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct intel_timeline_cacheline *cl;
1678c2ecf20Sopenharmony_ci	void *vaddr;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	GEM_BUG_ON(cacheline >= BIT(CACHELINE_BITS));
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	cl = kmalloc(sizeof(*cl), GFP_KERNEL);
1728c2ecf20Sopenharmony_ci	if (!cl)
1738c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	vaddr = i915_gem_object_pin_map(hwsp->vma->obj, I915_MAP_WB);
1768c2ecf20Sopenharmony_ci	if (IS_ERR(vaddr)) {
1778c2ecf20Sopenharmony_ci		kfree(cl);
1788c2ecf20Sopenharmony_ci		return ERR_CAST(vaddr);
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	cl->hwsp = hwsp;
1828c2ecf20Sopenharmony_ci	cl->vaddr = page_pack_bits(vaddr, cacheline);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	i915_active_init(&cl->active, __cacheline_active, __cacheline_retire);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return cl;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void cacheline_acquire(struct intel_timeline_cacheline *cl,
1908c2ecf20Sopenharmony_ci			      u32 ggtt_offset)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	if (!cl)
1938c2ecf20Sopenharmony_ci		return;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	cl->ggtt_offset = ggtt_offset;
1968c2ecf20Sopenharmony_ci	i915_active_acquire(&cl->active);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic void cacheline_release(struct intel_timeline_cacheline *cl)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	if (cl)
2028c2ecf20Sopenharmony_ci		i915_active_release(&cl->active);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic void cacheline_free(struct intel_timeline_cacheline *cl)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	if (!i915_active_acquire_if_busy(&cl->active)) {
2088c2ecf20Sopenharmony_ci		__idle_cacheline_free(cl);
2098c2ecf20Sopenharmony_ci		return;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	GEM_BUG_ON(ptr_test_bit(cl->vaddr, CACHELINE_FREE));
2138c2ecf20Sopenharmony_ci	cl->vaddr = ptr_set_bit(cl->vaddr, CACHELINE_FREE);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	i915_active_release(&cl->active);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic int intel_timeline_init(struct intel_timeline *timeline,
2198c2ecf20Sopenharmony_ci			       struct intel_gt *gt,
2208c2ecf20Sopenharmony_ci			       struct i915_vma *hwsp,
2218c2ecf20Sopenharmony_ci			       unsigned int offset)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	void *vaddr;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	kref_init(&timeline->kref);
2268c2ecf20Sopenharmony_ci	atomic_set(&timeline->pin_count, 0);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	timeline->gt = gt;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	timeline->has_initial_breadcrumb = !hwsp;
2318c2ecf20Sopenharmony_ci	timeline->hwsp_cacheline = NULL;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if (!hwsp) {
2348c2ecf20Sopenharmony_ci		struct intel_timeline_cacheline *cl;
2358c2ecf20Sopenharmony_ci		unsigned int cacheline;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		hwsp = hwsp_alloc(timeline, &cacheline);
2388c2ecf20Sopenharmony_ci		if (IS_ERR(hwsp))
2398c2ecf20Sopenharmony_ci			return PTR_ERR(hwsp);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		cl = cacheline_alloc(hwsp->private, cacheline);
2428c2ecf20Sopenharmony_ci		if (IS_ERR(cl)) {
2438c2ecf20Sopenharmony_ci			__idle_hwsp_free(hwsp->private, cacheline);
2448c2ecf20Sopenharmony_ci			return PTR_ERR(cl);
2458c2ecf20Sopenharmony_ci		}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		timeline->hwsp_cacheline = cl;
2488c2ecf20Sopenharmony_ci		timeline->hwsp_offset = cacheline * CACHELINE_BYTES;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		vaddr = page_mask_bits(cl->vaddr);
2518c2ecf20Sopenharmony_ci	} else {
2528c2ecf20Sopenharmony_ci		timeline->hwsp_offset = offset;
2538c2ecf20Sopenharmony_ci		vaddr = i915_gem_object_pin_map(hwsp->obj, I915_MAP_WB);
2548c2ecf20Sopenharmony_ci		if (IS_ERR(vaddr))
2558c2ecf20Sopenharmony_ci			return PTR_ERR(vaddr);
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	timeline->hwsp_seqno =
2598c2ecf20Sopenharmony_ci		memset(vaddr + timeline->hwsp_offset, 0, CACHELINE_BYTES);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	timeline->hwsp_ggtt = i915_vma_get(hwsp);
2628c2ecf20Sopenharmony_ci	GEM_BUG_ON(timeline->hwsp_offset >= hwsp->size);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	timeline->fence_context = dma_fence_context_alloc(1);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	mutex_init(&timeline->mutex);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	INIT_ACTIVE_FENCE(&timeline->last_request);
2698c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&timeline->requests);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	i915_syncmap_init(&timeline->sync);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return 0;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_civoid intel_gt_init_timelines(struct intel_gt *gt)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct intel_gt_timelines *timelines = &gt->timelines;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	spin_lock_init(&timelines->lock);
2818c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&timelines->active_list);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	spin_lock_init(&timelines->hwsp_lock);
2848c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&timelines->hwsp_free_list);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic void intel_timeline_fini(struct intel_timeline *timeline)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	GEM_BUG_ON(atomic_read(&timeline->pin_count));
2908c2ecf20Sopenharmony_ci	GEM_BUG_ON(!list_empty(&timeline->requests));
2918c2ecf20Sopenharmony_ci	GEM_BUG_ON(timeline->retire);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (timeline->hwsp_cacheline)
2948c2ecf20Sopenharmony_ci		cacheline_free(timeline->hwsp_cacheline);
2958c2ecf20Sopenharmony_ci	else
2968c2ecf20Sopenharmony_ci		i915_gem_object_unpin_map(timeline->hwsp_ggtt->obj);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	i915_vma_put(timeline->hwsp_ggtt);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/*
3018c2ecf20Sopenharmony_ci	 * A small race exists between intel_gt_retire_requests_timeout and
3028c2ecf20Sopenharmony_ci	 * intel_timeline_exit which could result in the syncmap not getting
3038c2ecf20Sopenharmony_ci	 * free'd. Rather than work to hard to seal this race, simply cleanup
3048c2ecf20Sopenharmony_ci	 * the syncmap on fini.
3058c2ecf20Sopenharmony_ci	 */
3068c2ecf20Sopenharmony_ci	i915_syncmap_free(&timeline->sync);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistruct intel_timeline *
3108c2ecf20Sopenharmony_ci__intel_timeline_create(struct intel_gt *gt,
3118c2ecf20Sopenharmony_ci			struct i915_vma *global_hwsp,
3128c2ecf20Sopenharmony_ci			unsigned int offset)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct intel_timeline *timeline;
3158c2ecf20Sopenharmony_ci	int err;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	timeline = kzalloc(sizeof(*timeline), GFP_KERNEL);
3188c2ecf20Sopenharmony_ci	if (!timeline)
3198c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	err = intel_timeline_init(timeline, gt, global_hwsp, offset);
3228c2ecf20Sopenharmony_ci	if (err) {
3238c2ecf20Sopenharmony_ci		kfree(timeline);
3248c2ecf20Sopenharmony_ci		return ERR_PTR(err);
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return timeline;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_civoid __intel_timeline_pin(struct intel_timeline *tl)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	GEM_BUG_ON(!atomic_read(&tl->pin_count));
3338c2ecf20Sopenharmony_ci	atomic_inc(&tl->pin_count);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ciint intel_timeline_pin(struct intel_timeline *tl, struct i915_gem_ww_ctx *ww)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	int err;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	if (atomic_add_unless(&tl->pin_count, 1, 0))
3418c2ecf20Sopenharmony_ci		return 0;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	err = i915_ggtt_pin(tl->hwsp_ggtt, ww, 0, PIN_HIGH);
3448c2ecf20Sopenharmony_ci	if (err)
3458c2ecf20Sopenharmony_ci		return err;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	tl->hwsp_offset =
3488c2ecf20Sopenharmony_ci		i915_ggtt_offset(tl->hwsp_ggtt) +
3498c2ecf20Sopenharmony_ci		offset_in_page(tl->hwsp_offset);
3508c2ecf20Sopenharmony_ci	GT_TRACE(tl->gt, "timeline:%llx using HWSP offset:%x\n",
3518c2ecf20Sopenharmony_ci		 tl->fence_context, tl->hwsp_offset);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	cacheline_acquire(tl->hwsp_cacheline, tl->hwsp_offset);
3548c2ecf20Sopenharmony_ci	if (atomic_fetch_inc(&tl->pin_count)) {
3558c2ecf20Sopenharmony_ci		cacheline_release(tl->hwsp_cacheline);
3568c2ecf20Sopenharmony_ci		__i915_vma_unpin(tl->hwsp_ggtt);
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return 0;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_civoid intel_timeline_reset_seqno(const struct intel_timeline *tl)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	/* Must be pinned to be writable, and no requests in flight. */
3658c2ecf20Sopenharmony_ci	GEM_BUG_ON(!atomic_read(&tl->pin_count));
3668c2ecf20Sopenharmony_ci	WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_civoid intel_timeline_enter(struct intel_timeline *tl)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct intel_gt_timelines *timelines = &tl->gt->timelines;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/*
3748c2ecf20Sopenharmony_ci	 * Pretend we are serialised by the timeline->mutex.
3758c2ecf20Sopenharmony_ci	 *
3768c2ecf20Sopenharmony_ci	 * While generally true, there are a few exceptions to the rule
3778c2ecf20Sopenharmony_ci	 * for the engine->kernel_context being used to manage power
3788c2ecf20Sopenharmony_ci	 * transitions. As the engine_park may be called from under any
3798c2ecf20Sopenharmony_ci	 * timeline, it uses the power mutex as a global serialisation
3808c2ecf20Sopenharmony_ci	 * lock to prevent any other request entering its timeline.
3818c2ecf20Sopenharmony_ci	 *
3828c2ecf20Sopenharmony_ci	 * The rule is generally tl->mutex, otherwise engine->wakeref.mutex.
3838c2ecf20Sopenharmony_ci	 *
3848c2ecf20Sopenharmony_ci	 * However, intel_gt_retire_request() does not know which engine
3858c2ecf20Sopenharmony_ci	 * it is retiring along and so cannot partake in the engine-pm
3868c2ecf20Sopenharmony_ci	 * barrier, and there we use the tl->active_count as a means to
3878c2ecf20Sopenharmony_ci	 * pin the timeline in the active_list while the locks are dropped.
3888c2ecf20Sopenharmony_ci	 * Ergo, as that is outside of the engine-pm barrier, we need to
3898c2ecf20Sopenharmony_ci	 * use atomic to manipulate tl->active_count.
3908c2ecf20Sopenharmony_ci	 */
3918c2ecf20Sopenharmony_ci	lockdep_assert_held(&tl->mutex);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (atomic_add_unless(&tl->active_count, 1, 0))
3948c2ecf20Sopenharmony_ci		return;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	spin_lock(&timelines->lock);
3978c2ecf20Sopenharmony_ci	if (!atomic_fetch_inc(&tl->active_count)) {
3988c2ecf20Sopenharmony_ci		/*
3998c2ecf20Sopenharmony_ci		 * The HWSP is volatile, and may have been lost while inactive,
4008c2ecf20Sopenharmony_ci		 * e.g. across suspend/resume. Be paranoid, and ensure that
4018c2ecf20Sopenharmony_ci		 * the HWSP value matches our seqno so we don't proclaim
4028c2ecf20Sopenharmony_ci		 * the next request as already complete.
4038c2ecf20Sopenharmony_ci		 */
4048c2ecf20Sopenharmony_ci		intel_timeline_reset_seqno(tl);
4058c2ecf20Sopenharmony_ci		list_add_tail(&tl->link, &timelines->active_list);
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci	spin_unlock(&timelines->lock);
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_civoid intel_timeline_exit(struct intel_timeline *tl)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct intel_gt_timelines *timelines = &tl->gt->timelines;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* See intel_timeline_enter() */
4158c2ecf20Sopenharmony_ci	lockdep_assert_held(&tl->mutex);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	GEM_BUG_ON(!atomic_read(&tl->active_count));
4188c2ecf20Sopenharmony_ci	if (atomic_add_unless(&tl->active_count, -1, 1))
4198c2ecf20Sopenharmony_ci		return;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	spin_lock(&timelines->lock);
4228c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&tl->active_count))
4238c2ecf20Sopenharmony_ci		list_del(&tl->link);
4248c2ecf20Sopenharmony_ci	spin_unlock(&timelines->lock);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/*
4278c2ecf20Sopenharmony_ci	 * Since this timeline is idle, all bariers upon which we were waiting
4288c2ecf20Sopenharmony_ci	 * must also be complete and so we can discard the last used barriers
4298c2ecf20Sopenharmony_ci	 * without loss of information.
4308c2ecf20Sopenharmony_ci	 */
4318c2ecf20Sopenharmony_ci	i915_syncmap_free(&tl->sync);
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic u32 timeline_advance(struct intel_timeline *tl)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	GEM_BUG_ON(!atomic_read(&tl->pin_count));
4378c2ecf20Sopenharmony_ci	GEM_BUG_ON(tl->seqno & tl->has_initial_breadcrumb);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return tl->seqno += 1 + tl->has_initial_breadcrumb;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic void timeline_rollback(struct intel_timeline *tl)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	tl->seqno -= 1 + tl->has_initial_breadcrumb;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic noinline int
4488c2ecf20Sopenharmony_ci__intel_timeline_get_seqno(struct intel_timeline *tl,
4498c2ecf20Sopenharmony_ci			   struct i915_request *rq,
4508c2ecf20Sopenharmony_ci			   u32 *seqno)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct intel_timeline_cacheline *cl;
4538c2ecf20Sopenharmony_ci	unsigned int cacheline;
4548c2ecf20Sopenharmony_ci	struct i915_vma *vma;
4558c2ecf20Sopenharmony_ci	void *vaddr;
4568c2ecf20Sopenharmony_ci	int err;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	might_lock(&tl->gt->ggtt->vm.mutex);
4598c2ecf20Sopenharmony_ci	GT_TRACE(tl->gt, "timeline:%llx wrapped\n", tl->fence_context);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/*
4628c2ecf20Sopenharmony_ci	 * If there is an outstanding GPU reference to this cacheline,
4638c2ecf20Sopenharmony_ci	 * such as it being sampled by a HW semaphore on another timeline,
4648c2ecf20Sopenharmony_ci	 * we cannot wraparound our seqno value (the HW semaphore does
4658c2ecf20Sopenharmony_ci	 * a strict greater-than-or-equals compare, not i915_seqno_passed).
4668c2ecf20Sopenharmony_ci	 * So if the cacheline is still busy, we must detach ourselves
4678c2ecf20Sopenharmony_ci	 * from it and leave it inflight alongside its users.
4688c2ecf20Sopenharmony_ci	 *
4698c2ecf20Sopenharmony_ci	 * However, if nobody is watching and we can guarantee that nobody
4708c2ecf20Sopenharmony_ci	 * will, we could simply reuse the same cacheline.
4718c2ecf20Sopenharmony_ci	 *
4728c2ecf20Sopenharmony_ci	 * if (i915_active_request_is_signaled(&tl->last_request) &&
4738c2ecf20Sopenharmony_ci	 *     i915_active_is_signaled(&tl->hwsp_cacheline->active))
4748c2ecf20Sopenharmony_ci	 *	return 0;
4758c2ecf20Sopenharmony_ci	 *
4768c2ecf20Sopenharmony_ci	 * That seems unlikely for a busy timeline that needed to wrap in
4778c2ecf20Sopenharmony_ci	 * the first place, so just replace the cacheline.
4788c2ecf20Sopenharmony_ci	 */
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	vma = hwsp_alloc(tl, &cacheline);
4818c2ecf20Sopenharmony_ci	if (IS_ERR(vma)) {
4828c2ecf20Sopenharmony_ci		err = PTR_ERR(vma);
4838c2ecf20Sopenharmony_ci		goto err_rollback;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	err = i915_ggtt_pin(vma, NULL, 0, PIN_HIGH);
4878c2ecf20Sopenharmony_ci	if (err) {
4888c2ecf20Sopenharmony_ci		__idle_hwsp_free(vma->private, cacheline);
4898c2ecf20Sopenharmony_ci		goto err_rollback;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	cl = cacheline_alloc(vma->private, cacheline);
4938c2ecf20Sopenharmony_ci	if (IS_ERR(cl)) {
4948c2ecf20Sopenharmony_ci		err = PTR_ERR(cl);
4958c2ecf20Sopenharmony_ci		__idle_hwsp_free(vma->private, cacheline);
4968c2ecf20Sopenharmony_ci		goto err_unpin;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci	GEM_BUG_ON(cl->hwsp->vma != vma);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	/*
5018c2ecf20Sopenharmony_ci	 * Attach the old cacheline to the current request, so that we only
5028c2ecf20Sopenharmony_ci	 * free it after the current request is retired, which ensures that
5038c2ecf20Sopenharmony_ci	 * all writes into the cacheline from previous requests are complete.
5048c2ecf20Sopenharmony_ci	 */
5058c2ecf20Sopenharmony_ci	err = i915_active_ref(&tl->hwsp_cacheline->active,
5068c2ecf20Sopenharmony_ci			      tl->fence_context,
5078c2ecf20Sopenharmony_ci			      &rq->fence);
5088c2ecf20Sopenharmony_ci	if (err)
5098c2ecf20Sopenharmony_ci		goto err_cacheline;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	cacheline_release(tl->hwsp_cacheline); /* ownership now xfered to rq */
5128c2ecf20Sopenharmony_ci	cacheline_free(tl->hwsp_cacheline);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	i915_vma_unpin(tl->hwsp_ggtt); /* binding kept alive by old cacheline */
5158c2ecf20Sopenharmony_ci	i915_vma_put(tl->hwsp_ggtt);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	tl->hwsp_ggtt = i915_vma_get(vma);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	vaddr = page_mask_bits(cl->vaddr);
5208c2ecf20Sopenharmony_ci	tl->hwsp_offset = cacheline * CACHELINE_BYTES;
5218c2ecf20Sopenharmony_ci	tl->hwsp_seqno =
5228c2ecf20Sopenharmony_ci		memset(vaddr + tl->hwsp_offset, 0, CACHELINE_BYTES);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	tl->hwsp_offset += i915_ggtt_offset(vma);
5258c2ecf20Sopenharmony_ci	GT_TRACE(tl->gt, "timeline:%llx using HWSP offset:%x\n",
5268c2ecf20Sopenharmony_ci		 tl->fence_context, tl->hwsp_offset);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	cacheline_acquire(cl, tl->hwsp_offset);
5298c2ecf20Sopenharmony_ci	tl->hwsp_cacheline = cl;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	*seqno = timeline_advance(tl);
5328c2ecf20Sopenharmony_ci	GEM_BUG_ON(i915_seqno_passed(*tl->hwsp_seqno, *seqno));
5338c2ecf20Sopenharmony_ci	return 0;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cierr_cacheline:
5368c2ecf20Sopenharmony_ci	cacheline_free(cl);
5378c2ecf20Sopenharmony_cierr_unpin:
5388c2ecf20Sopenharmony_ci	i915_vma_unpin(vma);
5398c2ecf20Sopenharmony_cierr_rollback:
5408c2ecf20Sopenharmony_ci	timeline_rollback(tl);
5418c2ecf20Sopenharmony_ci	return err;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ciint intel_timeline_get_seqno(struct intel_timeline *tl,
5458c2ecf20Sopenharmony_ci			     struct i915_request *rq,
5468c2ecf20Sopenharmony_ci			     u32 *seqno)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	*seqno = timeline_advance(tl);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* Replace the HWSP on wraparound for HW semaphores */
5518c2ecf20Sopenharmony_ci	if (unlikely(!*seqno && tl->hwsp_cacheline))
5528c2ecf20Sopenharmony_ci		return __intel_timeline_get_seqno(tl, rq, seqno);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	return 0;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic int cacheline_ref(struct intel_timeline_cacheline *cl,
5588c2ecf20Sopenharmony_ci			 struct i915_request *rq)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	return i915_active_add_request(&cl->active, rq);
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ciint intel_timeline_read_hwsp(struct i915_request *from,
5648c2ecf20Sopenharmony_ci			     struct i915_request *to,
5658c2ecf20Sopenharmony_ci			     u32 *hwsp)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct intel_timeline_cacheline *cl;
5688c2ecf20Sopenharmony_ci	int err;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	GEM_BUG_ON(!rcu_access_pointer(from->hwsp_cacheline));
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	rcu_read_lock();
5738c2ecf20Sopenharmony_ci	cl = rcu_dereference(from->hwsp_cacheline);
5748c2ecf20Sopenharmony_ci	if (i915_request_completed(from)) /* confirm cacheline is valid */
5758c2ecf20Sopenharmony_ci		goto unlock;
5768c2ecf20Sopenharmony_ci	if (unlikely(!i915_active_acquire_if_busy(&cl->active)))
5778c2ecf20Sopenharmony_ci		goto unlock; /* seqno wrapped and completed! */
5788c2ecf20Sopenharmony_ci	if (unlikely(i915_request_completed(from)))
5798c2ecf20Sopenharmony_ci		goto release;
5808c2ecf20Sopenharmony_ci	rcu_read_unlock();
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	err = cacheline_ref(cl, to);
5838c2ecf20Sopenharmony_ci	if (err)
5848c2ecf20Sopenharmony_ci		goto out;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	*hwsp = cl->ggtt_offset;
5878c2ecf20Sopenharmony_ciout:
5888c2ecf20Sopenharmony_ci	i915_active_release(&cl->active);
5898c2ecf20Sopenharmony_ci	return err;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cirelease:
5928c2ecf20Sopenharmony_ci	i915_active_release(&cl->active);
5938c2ecf20Sopenharmony_ciunlock:
5948c2ecf20Sopenharmony_ci	rcu_read_unlock();
5958c2ecf20Sopenharmony_ci	return 1;
5968c2ecf20Sopenharmony_ci}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_civoid intel_timeline_unpin(struct intel_timeline *tl)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	GEM_BUG_ON(!atomic_read(&tl->pin_count));
6018c2ecf20Sopenharmony_ci	if (!atomic_dec_and_test(&tl->pin_count))
6028c2ecf20Sopenharmony_ci		return;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	cacheline_release(tl->hwsp_cacheline);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	__i915_vma_unpin(tl->hwsp_ggtt);
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_civoid __intel_timeline_free(struct kref *kref)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	struct intel_timeline *timeline =
6128c2ecf20Sopenharmony_ci		container_of(kref, typeof(*timeline), kref);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	intel_timeline_fini(timeline);
6158c2ecf20Sopenharmony_ci	kfree_rcu(timeline, rcu);
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_civoid intel_gt_fini_timelines(struct intel_gt *gt)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	struct intel_gt_timelines *timelines = &gt->timelines;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	GEM_BUG_ON(!list_empty(&timelines->active_list));
6238c2ecf20Sopenharmony_ci	GEM_BUG_ON(!list_empty(&timelines->hwsp_free_list));
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
6278c2ecf20Sopenharmony_ci#include "gt/selftests/mock_timeline.c"
6288c2ecf20Sopenharmony_ci#include "gt/selftest_timeline.c"
6298c2ecf20Sopenharmony_ci#endif
630