diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 293 |
1 files changed, 110 insertions, 183 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f6e66a7f4bf0..eb31b69a316a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -46,6 +46,7 @@ #include "gem/i915_gem_ioctls.h" #include "gem/i915_gem_pm.h" #include "gem/i915_gemfs.h" +#include "gt/intel_engine_user.h" #include "gt/intel_gt.h" #include "gt/intel_gt_pm.h" #include "gt/intel_mocs.h" @@ -58,7 +59,6 @@ #include "i915_trace.h" #include "i915_vgpu.h" -#include "intel_drv.h" #include "intel_pm.h" static int @@ -139,17 +139,19 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj, void *vaddr = obj->phys_handle->vaddr + args->offset; char __user *user_data = u64_to_user_ptr(args->data_ptr); - /* We manually control the domain here and pretend that it + /* + * We manually control the domain here and pretend that it * remains coherent i.e. in the GTT domain, like shmem_pwrite. */ - intel_fb_obj_invalidate(obj, ORIGIN_CPU); + intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU); + if (copy_from_user(vaddr, user_data, args->size)) return -EFAULT; drm_clflush_virt_range(vaddr, args->size); intel_gt_chipset_flush(&to_i915(obj->base.dev)->gt); - intel_fb_obj_flush(obj, ORIGIN_CPU); + intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU); return 0; } @@ -341,20 +343,16 @@ i915_gem_gtt_pread(struct drm_i915_gem_object *obj, return ret; wakeref = intel_runtime_pm_get(&i915->runtime_pm); - vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, - PIN_MAPPABLE | - PIN_NONFAULT | - PIN_NONBLOCK); + vma = ERR_PTR(-ENODEV); + if (!i915_gem_object_is_tiled(obj)) + vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, + PIN_MAPPABLE | + PIN_NONBLOCK /* NOWARN */ | + PIN_NOEVICT); if (!IS_ERR(vma)) { node.start = i915_ggtt_offset(vma); node.allocated = false; - ret = i915_vma_put_fence(vma); - if (ret) { - i915_vma_unpin(vma); - vma = ERR_PTR(ret); - } - } - if (IS_ERR(vma)) { + } else { ret = insert_mappable_node(ggtt, &node, PAGE_SIZE); if (ret) goto out_unlock; @@ -555,20 +553,16 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, wakeref = intel_runtime_pm_get(rpm); } - vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, - PIN_MAPPABLE | - PIN_NONFAULT | - PIN_NONBLOCK); + vma = ERR_PTR(-ENODEV); + if (!i915_gem_object_is_tiled(obj)) + vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, + PIN_MAPPABLE | + PIN_NONBLOCK /* NOWARN */ | + PIN_NOEVICT); if (!IS_ERR(vma)) { node.start = i915_ggtt_offset(vma); node.allocated = false; - ret = i915_vma_put_fence(vma); - if (ret) { - i915_vma_unpin(vma); - vma = ERR_PTR(ret); - } - } - if (IS_ERR(vma)) { + } else { ret = insert_mappable_node(ggtt, &node, PAGE_SIZE); if (ret) goto out_rpm; @@ -594,7 +588,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, goto out_unpin; } - intel_fb_obj_invalidate(obj, ORIGIN_CPU); + intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU); user_data = u64_to_user_ptr(args->data_ptr); offset = args->offset; @@ -636,7 +630,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, user_data += page_length; offset += page_length; } - intel_fb_obj_flush(obj, ORIGIN_CPU); + intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU); i915_gem_object_unlock_fence(obj, fence); out_unpin: @@ -729,7 +723,7 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, offset = 0; } - intel_fb_obj_flush(obj, ORIGIN_CPU); + intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU); i915_gem_object_unlock_fence(obj, fence); return ret; @@ -893,35 +887,22 @@ void i915_gem_runtime_suspend(struct drm_i915_private *i915) } } -static int wait_for_engines(struct intel_gt *gt) -{ - if (wait_for(intel_engines_are_idle(gt), I915_IDLE_ENGINES_TIMEOUT)) { - dev_err(gt->i915->drm.dev, - "Failed to idle engines, declaring wedged!\n"); - GEM_TRACE_DUMP(); - intel_gt_set_wedged(gt); - return -EIO; - } - - return 0; -} - static long wait_for_timelines(struct drm_i915_private *i915, unsigned int flags, long timeout) { - struct intel_gt_timelines *gt = &i915->gt.timelines; + struct intel_gt_timelines *timelines = &i915->gt.timelines; struct intel_timeline *tl; - mutex_lock(>->mutex); - list_for_each_entry(tl, >->active_list, link) { + spin_lock(&timelines->lock); + list_for_each_entry(tl, &timelines->active_list, link) { struct i915_request *rq; rq = i915_active_request_get_unlocked(&tl->last_request); if (!rq) continue; - mutex_unlock(>->mutex); + spin_unlock(&timelines->lock); /* * "Race-to-idle". @@ -941,10 +922,10 @@ wait_for_timelines(struct drm_i915_private *i915, return timeout; /* restart after reacquiring the lock */ - mutex_lock(>->mutex); - tl = list_entry(>->active_list, typeof(*tl), link); + spin_lock(&timelines->lock); + tl = list_entry(&timelines->active_list, typeof(*tl), link); } - mutex_unlock(>->mutex); + spin_unlock(&timelines->lock); return timeout; } @@ -953,27 +934,20 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags, long timeout) { /* If the device is asleep, we have no requests outstanding */ - if (!READ_ONCE(i915->gt.awake)) + if (!intel_gt_pm_is_awake(&i915->gt)) return 0; - GEM_TRACE("flags=%x (%s), timeout=%ld%s, awake?=%s\n", + GEM_TRACE("flags=%x (%s), timeout=%ld%s\n", flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked", - timeout, timeout == MAX_SCHEDULE_TIMEOUT ? " (forever)" : "", - yesno(i915->gt.awake)); + timeout, timeout == MAX_SCHEDULE_TIMEOUT ? " (forever)" : ""); timeout = wait_for_timelines(i915, flags, timeout); if (timeout < 0) return timeout; if (flags & I915_WAIT_LOCKED) { - int err; - lockdep_assert_held(&i915->drm.struct_mutex); - err = wait_for_engines(&i915->gt); - if (err) - return err; - i915_retire_requests(i915); } @@ -1240,22 +1214,14 @@ int i915_gem_init_hw(struct drm_i915_private *i915) goto out; } - ret = intel_wopcm_init_hw(&i915->wopcm, gt); - if (ret) { - DRM_ERROR("Enabling WOPCM failed (%d)\n", ret); - goto out; - } - /* We can't enable contexts until all firmware is loaded */ - ret = intel_uc_init_hw(&i915->gt.uc); + ret = intel_uc_init_hw(>->uc); if (ret) { - DRM_ERROR("Enabling uc failed (%d)\n", ret); + i915_probe_error(i915, "Enabling uc failed (%d)\n", ret); goto out; } - intel_mocs_init_l3cc_table(gt); - - intel_engines_set_scheduler_caps(i915); + intel_mocs_init(gt); out: intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL); @@ -1264,9 +1230,8 @@ out: static int __intel_engines_record_defaults(struct drm_i915_private *i915) { + struct i915_request *requests[I915_NUM_ENGINES] = {}; struct intel_engine_cs *engine; - struct i915_gem_context *ctx; - struct i915_gem_engines *e; enum intel_engine_id id; int err = 0; @@ -1279,20 +1244,25 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915) * from the same default HW values. */ - ctx = i915_gem_context_create_kernel(i915, 0); - if (IS_ERR(ctx)) - return PTR_ERR(ctx); - - e = i915_gem_context_lock_engines(ctx); - for_each_engine(engine, i915, id) { - struct intel_context *ce = e->engines[id]; + struct intel_context *ce; struct i915_request *rq; + /* We must be able to switch to something! */ + GEM_BUG_ON(!engine->kernel_context); + engine->serial++; /* force the kernel context switch */ + + ce = intel_context_create(i915->kernel_context, engine); + if (IS_ERR(ce)) { + err = PTR_ERR(ce); + goto out; + } + rq = intel_context_create_request(ce); if (IS_ERR(rq)) { err = PTR_ERR(rq); - goto err_active; + intel_context_put(ce); + goto out; } err = intel_engine_emit_ctx_wa(rq); @@ -1313,26 +1283,33 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915) goto err_rq; err_rq: + requests[id] = i915_request_get(rq); i915_request_add(rq); if (err) - goto err_active; + goto out; } /* Flush the default context image to memory, and enable powersaving. */ if (!i915_gem_load_power_context(i915)) { err = -EIO; - goto err_active; + goto out; } - for_each_engine(engine, i915, id) { - struct intel_context *ce = e->engines[id]; - struct i915_vma *state = ce->state; + for (id = 0; id < ARRAY_SIZE(requests); id++) { + struct i915_request *rq; + struct i915_vma *state; void *vaddr; - if (!state) + rq = requests[id]; + if (!rq) continue; - GEM_BUG_ON(intel_context_is_pinned(ce)); + /* We want to be able to unbind the state from the GGTT */ + GEM_BUG_ON(intel_context_is_pinned(rq->hw_context)); + + state = rq->hw_context->state; + if (!state) + continue; /* * As we will hold a reference to the logical state, it will @@ -1344,61 +1321,49 @@ err_rq: */ err = i915_vma_unbind(state); if (err) - goto err_active; + goto out; i915_gem_object_lock(state->obj); err = i915_gem_object_set_to_cpu_domain(state->obj, false); i915_gem_object_unlock(state->obj); if (err) - goto err_active; + goto out; - engine->default_state = i915_gem_object_get(state->obj); - i915_gem_object_set_cache_coherency(engine->default_state, - I915_CACHE_LLC); + i915_gem_object_set_cache_coherency(state->obj, I915_CACHE_LLC); /* Check we can acquire the image of the context state */ - vaddr = i915_gem_object_pin_map(engine->default_state, - I915_MAP_FORCE_WB); + vaddr = i915_gem_object_pin_map(state->obj, I915_MAP_FORCE_WB); if (IS_ERR(vaddr)) { err = PTR_ERR(vaddr); - goto err_active; + goto out; } - i915_gem_object_unpin_map(engine->default_state); - } - - if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) { - unsigned int found = intel_engines_has_context_isolation(i915); - - /* - * Make sure that classes with multiple engine instances all - * share the same basic configuration. - */ - for_each_engine(engine, i915, id) { - unsigned int bit = BIT(engine->uabi_class); - unsigned int expected = engine->default_state ? bit : 0; - - if ((found & bit) != expected) { - DRM_ERROR("mismatching default context state for class %d on engine %s\n", - engine->uabi_class, engine->name); - } - } + rq->engine->default_state = i915_gem_object_get(state->obj); + i915_gem_object_unpin_map(state->obj); } -out_ctx: - i915_gem_context_unlock_engines(ctx); - i915_gem_context_set_closed(ctx); - i915_gem_context_put(ctx); - return err; - -err_active: +out: /* * If we have to abandon now, we expect the engines to be idle * and ready to be torn-down. The quickest way we can accomplish * this is by declaring ourselves wedged. */ - intel_gt_set_wedged(&i915->gt); - goto out_ctx; + if (err) + intel_gt_set_wedged(&i915->gt); + + for (id = 0; id < ARRAY_SIZE(requests); id++) { + struct intel_context *ce; + struct i915_request *rq; + + rq = requests[id]; + if (!rq) + continue; + + ce = rq->hw_context; + i915_request_put(rq); + intel_context_put(ce); + } + return err; } static int @@ -1438,8 +1403,6 @@ int i915_gem_init(struct drm_i915_private *dev_priv) mkwrite_device_info(dev_priv)->page_sizes = I915_GTT_PAGE_SIZE_4K; - dev_priv->mm.unordered_timeline = dma_fence_context_alloc(1); - intel_timelines_init(dev_priv); ret = i915_gem_init_userptr(dev_priv); @@ -1447,10 +1410,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv) return ret; intel_uc_fetch_firmwares(&dev_priv->gt.uc); - - ret = intel_wopcm_init(&dev_priv->wopcm); - if (ret) - goto err_uc_fw; + intel_wopcm_init(&dev_priv->wopcm); /* This is just a security blanket to placate dragons. * On some systems, we very sporadically observe that the first TLBs @@ -1494,9 +1454,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv) intel_init_gt_powersave(dev_priv); - ret = intel_uc_init(&dev_priv->gt.uc); - if (ret) - goto err_pm; + intel_uc_init(&dev_priv->gt.uc); ret = i915_gem_init_hw(dev_priv); if (ret) @@ -1526,15 +1484,13 @@ int i915_gem_init(struct drm_i915_private *dev_priv) if (ret) goto err_gt; - if (i915_inject_probe_failure()) { - ret = -ENODEV; + ret = i915_inject_load_error(dev_priv, -ENODEV); + if (ret) goto err_gt; - } - if (i915_inject_probe_failure()) { - ret = -EIO; + ret = i915_inject_load_error(dev_priv, -EIO); + if (ret) goto err_gt; - } intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL); mutex_unlock(&dev_priv->drm.struct_mutex); @@ -1560,9 +1516,8 @@ err_gt: err_init_hw: intel_uc_fini_hw(&dev_priv->gt.uc); err_uc_init: - intel_uc_fini(&dev_priv->gt.uc); -err_pm: if (ret != -EIO) { + intel_uc_fini(&dev_priv->gt.uc); intel_cleanup_gt_powersave(dev_priv); intel_engines_cleanup(dev_priv); } @@ -1576,10 +1531,8 @@ err_unlock: intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL); mutex_unlock(&dev_priv->drm.struct_mutex); -err_uc_fw: - intel_uc_cleanup_firmwares(&dev_priv->gt.uc); - if (ret != -EIO) { + intel_uc_cleanup_firmwares(&dev_priv->gt.uc); i915_gem_cleanup_userptr(dev_priv); intel_timelines_fini(dev_priv); } @@ -1588,8 +1541,8 @@ err_uc_fw: mutex_lock(&dev_priv->drm.struct_mutex); /* - * Allow engine initialisation to fail by marking the GPU as - * wedged. But we only want to do this where the GPU is angry, + * Allow engines or uC initialisation to fail by marking the GPU + * as wedged. But we only want to do this when the GPU is angry, * for all other failure, such as an allocation failure, bail. */ if (!intel_gt_is_wedged(&dev_priv->gt)) { @@ -1611,6 +1564,18 @@ err_uc_fw: return ret; } +void i915_gem_driver_register(struct drm_i915_private *i915) +{ + i915_gem_driver_register__shrinker(i915); + + intel_engines_driver_register(i915); +} + +void i915_gem_driver_unregister(struct drm_i915_private *i915) +{ + i915_gem_driver_unregister__shrinker(i915); +} + void i915_gem_driver_remove(struct drm_i915_private *dev_priv) { GEM_BUG_ON(dev_priv->gt.awake); @@ -1660,7 +1625,6 @@ void i915_gem_init_mmio(struct drm_i915_private *i915) static void i915_gem_init__mm(struct drm_i915_private *i915) { spin_lock_init(&i915->mm.obj_lock); - spin_lock_init(&i915->mm.free_lock); init_llist_head(&i915->mm.free_list); @@ -1677,8 +1641,6 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv) i915_gem_init__mm(dev_priv); i915_gem_init__pm(dev_priv); - atomic_set(&dev_priv->mm.bsd_engine_dispatch_index, 0); - spin_lock_init(&dev_priv->fb_tracking.lock); err = i915_gemfs_init(dev_priv); @@ -1695,8 +1657,6 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv) GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count)); WARN_ON(dev_priv->mm.shrink_count); - intel_gt_cleanup_early(&dev_priv->gt); - i915_gemfs_fini(dev_priv); } @@ -1789,39 +1749,6 @@ int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file) return ret; } -/** - * i915_gem_track_fb - update frontbuffer tracking - * @old: current GEM buffer for the frontbuffer slots - * @new: new GEM buffer for the frontbuffer slots - * @frontbuffer_bits: bitmask of frontbuffer slots - * - * This updates the frontbuffer tracking bits @frontbuffer_bits by clearing them - * from @old and setting them in @new. Both @old and @new can be NULL. - */ -void i915_gem_track_fb(struct drm_i915_gem_object *old, - struct drm_i915_gem_object *new, - unsigned frontbuffer_bits) -{ - /* Control of individual bits within the mask are guarded by - * the owning plane->mutex, i.e. we can never see concurrent - * manipulation of individual bits. But since the bitfield as a whole - * is updated using RMW, we need to use atomics in order to update - * the bits. - */ - BUILD_BUG_ON(INTEL_FRONTBUFFER_BITS_PER_PIPE * I915_MAX_PIPES > - BITS_PER_TYPE(atomic_t)); - - if (old) { - WARN_ON(!(atomic_read(&old->frontbuffer_bits) & frontbuffer_bits)); - atomic_andnot(frontbuffer_bits, &old->frontbuffer_bits); - } - - if (new) { - WARN_ON(atomic_read(&new->frontbuffer_bits) & frontbuffer_bits); - atomic_or(frontbuffer_bits, &new->frontbuffer_bits); - } -} - #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftests/mock_gem_device.c" #include "selftests/i915_gem.c" |