Home | History | Annotate | Line # | Download | only in gt
      1  1.4  riastrad /*	$NetBSD: intel_ppgtt.c,v 1.4 2021/12/19 12:07:47 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad // SPDX-License-Identifier: MIT
      4  1.1  riastrad /*
      5  1.1  riastrad  * Copyright  2020 Intel Corporation
      6  1.1  riastrad  */
      7  1.1  riastrad 
      8  1.1  riastrad #include <sys/cdefs.h>
      9  1.4  riastrad __KERNEL_RCSID(0, "$NetBSD: intel_ppgtt.c,v 1.4 2021/12/19 12:07:47 riastradh Exp $");
     10  1.1  riastrad 
     11  1.1  riastrad #include <linux/slab.h>
     12  1.1  riastrad 
     13  1.1  riastrad #include "i915_trace.h"
     14  1.1  riastrad #include "intel_gtt.h"
     15  1.1  riastrad #include "gen6_ppgtt.h"
     16  1.1  riastrad #include "gen8_ppgtt.h"
     17  1.1  riastrad 
     18  1.1  riastrad struct i915_page_table *alloc_pt(struct i915_address_space *vm)
     19  1.1  riastrad {
     20  1.1  riastrad 	struct i915_page_table *pt;
     21  1.1  riastrad 
     22  1.1  riastrad 	pt = kmalloc(sizeof(*pt), I915_GFP_ALLOW_FAIL);
     23  1.1  riastrad 	if (unlikely(!pt))
     24  1.1  riastrad 		return ERR_PTR(-ENOMEM);
     25  1.1  riastrad 
     26  1.1  riastrad 	if (unlikely(setup_page_dma(vm, &pt->base))) {
     27  1.1  riastrad 		kfree(pt);
     28  1.1  riastrad 		return ERR_PTR(-ENOMEM);
     29  1.1  riastrad 	}
     30  1.1  riastrad 
     31  1.1  riastrad 	atomic_set(&pt->used, 0);
     32  1.1  riastrad 	return pt;
     33  1.1  riastrad }
     34  1.1  riastrad 
     35  1.1  riastrad struct i915_page_directory *__alloc_pd(size_t sz)
     36  1.1  riastrad {
     37  1.1  riastrad 	struct i915_page_directory *pd;
     38  1.1  riastrad 
     39  1.1  riastrad 	pd = kzalloc(sz, I915_GFP_ALLOW_FAIL);
     40  1.1  riastrad 	if (unlikely(!pd))
     41  1.1  riastrad 		return NULL;
     42  1.1  riastrad 
     43  1.1  riastrad 	spin_lock_init(&pd->lock);
     44  1.1  riastrad 	return pd;
     45  1.1  riastrad }
     46  1.1  riastrad 
     47  1.1  riastrad struct i915_page_directory *alloc_pd(struct i915_address_space *vm)
     48  1.1  riastrad {
     49  1.1  riastrad 	struct i915_page_directory *pd;
     50  1.1  riastrad 
     51  1.1  riastrad 	pd = __alloc_pd(sizeof(*pd));
     52  1.1  riastrad 	if (unlikely(!pd))
     53  1.1  riastrad 		return ERR_PTR(-ENOMEM);
     54  1.1  riastrad 
     55  1.1  riastrad 	if (unlikely(setup_page_dma(vm, px_base(pd)))) {
     56  1.4  riastrad 		spin_lock_destroy(&pd->lock);
     57  1.1  riastrad 		kfree(pd);
     58  1.1  riastrad 		return ERR_PTR(-ENOMEM);
     59  1.1  riastrad 	}
     60  1.1  riastrad 
     61  1.1  riastrad 	return pd;
     62  1.1  riastrad }
     63  1.1  riastrad 
     64  1.1  riastrad void free_pd(struct i915_address_space *vm, struct i915_page_dma *pd)
     65  1.1  riastrad {
     66  1.1  riastrad 	cleanup_page_dma(vm, pd);
     67  1.1  riastrad 	kfree(pd);
     68  1.1  riastrad }
     69  1.1  riastrad 
     70  1.1  riastrad static inline void
     71  1.1  riastrad write_dma_entry(struct i915_page_dma * const pdma,
     72  1.1  riastrad 		const unsigned short idx,
     73  1.1  riastrad 		const u64 encoded_entry)
     74  1.1  riastrad {
     75  1.1  riastrad 	u64 * const vaddr = kmap_atomic(pdma->page);
     76  1.1  riastrad 
     77  1.1  riastrad 	vaddr[idx] = encoded_entry;
     78  1.1  riastrad 	kunmap_atomic(vaddr);
     79  1.1  riastrad }
     80  1.1  riastrad 
     81  1.1  riastrad void
     82  1.1  riastrad __set_pd_entry(struct i915_page_directory * const pd,
     83  1.1  riastrad 	       const unsigned short idx,
     84  1.1  riastrad 	       struct i915_page_dma * const to,
     85  1.1  riastrad 	       u64 (*encode)(const dma_addr_t, const enum i915_cache_level))
     86  1.1  riastrad {
     87  1.1  riastrad 	/* Each thread pre-pins the pd, and we may have a thread per pde. */
     88  1.1  riastrad 	GEM_BUG_ON(atomic_read(px_used(pd)) > NALLOC * ARRAY_SIZE(pd->entry));
     89  1.1  riastrad 
     90  1.1  riastrad 	atomic_inc(px_used(pd));
     91  1.1  riastrad 	pd->entry[idx] = to;
     92  1.3  riastrad #ifdef __NetBSD__
     93  1.3  riastrad 	write_dma_entry(px_base(pd), idx, encode(to->map->dm_segs[0].ds_addr, I915_CACHE_LLC));
     94  1.3  riastrad #else
     95  1.1  riastrad 	write_dma_entry(px_base(pd), idx, encode(to->daddr, I915_CACHE_LLC));
     96  1.3  riastrad #endif
     97  1.1  riastrad }
     98  1.1  riastrad 
     99  1.1  riastrad void
    100  1.1  riastrad clear_pd_entry(struct i915_page_directory * const pd,
    101  1.1  riastrad 	       const unsigned short idx,
    102  1.1  riastrad 	       const struct i915_page_scratch * const scratch)
    103  1.1  riastrad {
    104  1.1  riastrad 	GEM_BUG_ON(atomic_read(px_used(pd)) == 0);
    105  1.1  riastrad 
    106  1.1  riastrad 	write_dma_entry(px_base(pd), idx, scratch->encode);
    107  1.1  riastrad 	pd->entry[idx] = NULL;
    108  1.1  riastrad 	atomic_dec(px_used(pd));
    109  1.1  riastrad }
    110  1.1  riastrad 
    111  1.1  riastrad bool
    112  1.1  riastrad release_pd_entry(struct i915_page_directory * const pd,
    113  1.1  riastrad 		 const unsigned short idx,
    114  1.1  riastrad 		 struct i915_page_table * const pt,
    115  1.1  riastrad 		 const struct i915_page_scratch * const scratch)
    116  1.1  riastrad {
    117  1.1  riastrad 	bool free = false;
    118  1.1  riastrad 
    119  1.1  riastrad 	if (atomic_add_unless(&pt->used, -1, 1))
    120  1.1  riastrad 		return false;
    121  1.1  riastrad 
    122  1.1  riastrad 	spin_lock(&pd->lock);
    123  1.1  riastrad 	if (atomic_dec_and_test(&pt->used)) {
    124  1.1  riastrad 		clear_pd_entry(pd, idx, scratch);
    125  1.1  riastrad 		free = true;
    126  1.1  riastrad 	}
    127  1.1  riastrad 	spin_unlock(&pd->lock);
    128  1.1  riastrad 
    129  1.1  riastrad 	return free;
    130  1.1  riastrad }
    131  1.1  riastrad 
    132  1.1  riastrad int i915_ppgtt_init_hw(struct intel_gt *gt)
    133  1.1  riastrad {
    134  1.1  riastrad 	struct drm_i915_private *i915 = gt->i915;
    135  1.1  riastrad 
    136  1.1  riastrad 	gtt_write_workarounds(gt);
    137  1.1  riastrad 
    138  1.1  riastrad 	if (IS_GEN(i915, 6))
    139  1.1  riastrad 		gen6_ppgtt_enable(gt);
    140  1.1  riastrad 	else if (IS_GEN(i915, 7))
    141  1.1  riastrad 		gen7_ppgtt_enable(gt);
    142  1.1  riastrad 
    143  1.1  riastrad 	return 0;
    144  1.1  riastrad }
    145  1.1  riastrad 
    146  1.1  riastrad static struct i915_ppgtt *
    147  1.1  riastrad __ppgtt_create(struct intel_gt *gt)
    148  1.1  riastrad {
    149  1.1  riastrad 	if (INTEL_GEN(gt->i915) < 8)
    150  1.1  riastrad 		return gen6_ppgtt_create(gt);
    151  1.1  riastrad 	else
    152  1.1  riastrad 		return gen8_ppgtt_create(gt);
    153  1.1  riastrad }
    154  1.1  riastrad 
    155  1.1  riastrad struct i915_ppgtt *i915_ppgtt_create(struct intel_gt *gt)
    156  1.1  riastrad {
    157  1.1  riastrad 	struct i915_ppgtt *ppgtt;
    158  1.1  riastrad 
    159  1.1  riastrad 	ppgtt = __ppgtt_create(gt);
    160  1.1  riastrad 	if (IS_ERR(ppgtt))
    161  1.1  riastrad 		return ppgtt;
    162  1.1  riastrad 
    163  1.1  riastrad 	trace_i915_ppgtt_create(&ppgtt->vm);
    164  1.1  riastrad 
    165  1.1  riastrad 	return ppgtt;
    166  1.1  riastrad }
    167  1.1  riastrad 
    168  1.1  riastrad static int ppgtt_bind_vma(struct i915_vma *vma,
    169  1.1  riastrad 			  enum i915_cache_level cache_level,
    170  1.1  riastrad 			  u32 flags)
    171  1.1  riastrad {
    172  1.1  riastrad 	u32 pte_flags;
    173  1.1  riastrad 	int err;
    174  1.1  riastrad 
    175  1.1  riastrad 	if (flags & I915_VMA_ALLOC) {
    176  1.1  riastrad 		err = vma->vm->allocate_va_range(vma->vm,
    177  1.1  riastrad 						 vma->node.start, vma->size);
    178  1.1  riastrad 		if (err)
    179  1.1  riastrad 			return err;
    180  1.1  riastrad 
    181  1.1  riastrad 		set_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma));
    182  1.1  riastrad 	}
    183  1.1  riastrad 
    184  1.1  riastrad 	/* Applicable to VLV, and gen8+ */
    185  1.1  riastrad 	pte_flags = 0;
    186  1.1  riastrad 	if (i915_gem_object_is_readonly(vma->obj))
    187  1.1  riastrad 		pte_flags |= PTE_READ_ONLY;
    188  1.1  riastrad 
    189  1.1  riastrad 	GEM_BUG_ON(!test_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma)));
    190  1.1  riastrad 	vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
    191  1.1  riastrad 	wmb();
    192  1.1  riastrad 
    193  1.1  riastrad 	return 0;
    194  1.1  riastrad }
    195  1.1  riastrad 
    196  1.1  riastrad static void ppgtt_unbind_vma(struct i915_vma *vma)
    197  1.1  riastrad {
    198  1.1  riastrad 	if (test_and_clear_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma)))
    199  1.1  riastrad 		vma->vm->clear_range(vma->vm, vma->node.start, vma->size);
    200  1.1  riastrad }
    201  1.1  riastrad 
    202  1.1  riastrad int ppgtt_set_pages(struct i915_vma *vma)
    203  1.1  riastrad {
    204  1.1  riastrad 	GEM_BUG_ON(vma->pages);
    205  1.1  riastrad 
    206  1.1  riastrad 	vma->pages = vma->obj->mm.pages;
    207  1.1  riastrad 
    208  1.1  riastrad 	vma->page_sizes = vma->obj->mm.page_sizes;
    209  1.1  riastrad 
    210  1.1  riastrad 	return 0;
    211  1.1  riastrad }
    212  1.1  riastrad 
    213  1.1  riastrad void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt)
    214  1.1  riastrad {
    215  1.1  riastrad 	struct drm_i915_private *i915 = gt->i915;
    216  1.1  riastrad 
    217  1.1  riastrad 	ppgtt->vm.gt = gt;
    218  1.1  riastrad 	ppgtt->vm.i915 = i915;
    219  1.3  riastrad #ifdef __NetBSD__
    220  1.3  riastrad 	ppgtt->vm.dmat = i915->drm.dmat;
    221  1.3  riastrad #else
    222  1.1  riastrad 	ppgtt->vm.dma = &i915->drm.pdev->dev;
    223  1.3  riastrad #endif
    224  1.1  riastrad 	ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size);
    225  1.1  riastrad 
    226  1.1  riastrad 	i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT);
    227  1.1  riastrad 
    228  1.1  riastrad 	ppgtt->vm.vma_ops.bind_vma    = ppgtt_bind_vma;
    229  1.1  riastrad 	ppgtt->vm.vma_ops.unbind_vma  = ppgtt_unbind_vma;
    230  1.1  riastrad 	ppgtt->vm.vma_ops.set_pages   = ppgtt_set_pages;
    231  1.1  riastrad 	ppgtt->vm.vma_ops.clear_pages = clear_pages;
    232  1.1  riastrad }
    233