| // SPDX-License-Identifier: MIT |
| /* |
| * Copyright © 2019 Intel Corporation |
| */ |
| |
| #include <uapi/drm/i915_drm.h> |
| |
| #include "intel_memory_region.h" |
| #include "gem/i915_gem_region.h" |
| #include "gem/i915_gem_lmem.h" |
| #include "i915_drv.h" |
| |
| void __iomem * |
| i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj, |
| unsigned long n, |
| unsigned long size) |
| { |
| resource_size_t offset; |
| |
| GEM_BUG_ON(!i915_gem_object_is_contiguous(obj)); |
| |
| offset = i915_gem_object_get_dma_address(obj, n); |
| offset -= obj->mm.region->region.start; |
| |
| return io_mapping_map_wc(&obj->mm.region->iomap, offset, size); |
| } |
| |
| /** |
| * i915_gem_object_is_lmem - Whether the object is resident in |
| * lmem |
| * @obj: The object to check. |
| * |
| * Even if an object is allowed to migrate and change memory region, |
| * this function checks whether it will always be present in lmem when |
| * valid *or* if that's not the case, whether it's currently resident in lmem. |
| * For migratable and evictable objects, the latter only makes sense when |
| * the object is locked. |
| * |
| * Return: Whether the object migratable but resident in lmem, or not |
| * migratable and will be present in lmem when valid. |
| */ |
| bool i915_gem_object_is_lmem(struct drm_i915_gem_object *obj) |
| { |
| struct intel_memory_region *mr = READ_ONCE(obj->mm.region); |
| |
| #ifdef CONFIG_LOCKDEP |
| if (i915_gem_object_migratable(obj) && |
| i915_gem_object_evictable(obj)) |
| assert_object_held(obj); |
| #endif |
| return mr && (mr->type == INTEL_MEMORY_LOCAL || |
| mr->type == INTEL_MEMORY_STOLEN_LOCAL); |
| } |
| |
| /** |
| * __i915_gem_object_is_lmem - Whether the object is resident in |
| * lmem while in the fence signaling critical path. |
| * @obj: The object to check. |
| * |
| * This function is intended to be called from within the fence signaling |
| * path where the fence, or a pin, keeps the object from being migrated. For |
| * example during gpu reset or similar. |
| * |
| * Return: Whether the object is resident in lmem. |
| */ |
| bool __i915_gem_object_is_lmem(struct drm_i915_gem_object *obj) |
| { |
| struct intel_memory_region *mr = READ_ONCE(obj->mm.region); |
| |
| #ifdef CONFIG_LOCKDEP |
| GEM_WARN_ON(dma_resv_test_signaled(obj->base.resv, DMA_RESV_USAGE_BOOKKEEP) && |
| i915_gem_object_evictable(obj)); |
| #endif |
| return mr && (mr->type == INTEL_MEMORY_LOCAL || |
| mr->type == INTEL_MEMORY_STOLEN_LOCAL); |
| } |
| |
| /** |
| * __i915_gem_object_create_lmem_with_ps - Create lmem object and force the |
| * minimum page size for the backing pages. |
| * @i915: The i915 instance. |
| * @size: The size in bytes for the object. Note that we need to round the size |
| * up depending on the @page_size. The final object size can be fished out from |
| * the drm GEM object. |
| * @page_size: The requested minimum page size in bytes for this object. This is |
| * useful if we need something bigger than the regions min_page_size due to some |
| * hw restriction, or in some very specialised cases where it needs to be |
| * smaller, where the internal fragmentation cost is too great when rounding up |
| * the object size. |
| * @flags: The optional BO allocation flags. |
| * |
| * Note that this interface assumes you know what you are doing when forcing the |
| * @page_size. If this is smaller than the regions min_page_size then it can |
| * never be inserted into any GTT, otherwise it might lead to undefined |
| * behaviour. |
| * |
| * Return: The object pointer, which might be an ERR_PTR in the case of failure. |
| */ |
| struct drm_i915_gem_object * |
| __i915_gem_object_create_lmem_with_ps(struct drm_i915_private *i915, |
| resource_size_t size, |
| resource_size_t page_size, |
| unsigned int flags) |
| { |
| return i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_LMEM_0], |
| size, page_size, flags); |
| } |
| |
| struct drm_i915_gem_object * |
| i915_gem_object_create_lmem_from_data(struct drm_i915_private *i915, |
| const void *data, size_t size) |
| { |
| struct drm_i915_gem_object *obj; |
| void *map; |
| |
| obj = i915_gem_object_create_lmem(i915, |
| round_up(size, PAGE_SIZE), |
| I915_BO_ALLOC_CONTIGUOUS); |
| if (IS_ERR(obj)) |
| return obj; |
| |
| map = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); |
| if (IS_ERR(map)) { |
| i915_gem_object_put(obj); |
| return map; |
| } |
| |
| memcpy(map, data, size); |
| |
| i915_gem_object_flush_map(obj); |
| __i915_gem_object_release_map(obj); |
| |
| return obj; |
| } |
| |
| struct drm_i915_gem_object * |
| i915_gem_object_create_lmem(struct drm_i915_private *i915, |
| resource_size_t size, |
| unsigned int flags) |
| { |
| return i915_gem_object_create_region(i915->mm.regions[INTEL_REGION_LMEM_0], |
| size, 0, flags); |
| } |