linux/drivers/gpu/drm/i915/display/intel_fb_pin.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2/*
   3 * Copyright © 2021 Intel Corporation
   4 */
   5
   6/**
   7 * DOC: display pinning helpers
   8 */
   9
  10#include "gem/i915_gem_object.h"
  11
  12#include "i915_drv.h"
  13#include "intel_display_types.h"
  14#include "intel_dpt.h"
  15#include "intel_fb.h"
  16#include "intel_fb_pin.h"
  17
  18static struct i915_vma *
  19intel_pin_fb_obj_dpt(struct drm_framebuffer *fb,
  20                     const struct i915_ggtt_view *view,
  21                     bool uses_fence,
  22                     unsigned long *out_flags,
  23                     struct i915_address_space *vm)
  24{
  25        struct drm_device *dev = fb->dev;
  26        struct drm_i915_private *dev_priv = to_i915(dev);
  27        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
  28        struct i915_vma *vma;
  29        u32 alignment;
  30        int ret;
  31
  32        if (WARN_ON(!i915_gem_object_is_framebuffer(obj)))
  33                return ERR_PTR(-EINVAL);
  34
  35        alignment = 4096 * 512;
  36
  37        atomic_inc(&dev_priv->gpu_error.pending_fb_pin);
  38
  39        ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE);
  40        if (ret) {
  41                vma = ERR_PTR(ret);
  42                goto err;
  43        }
  44
  45        vma = i915_vma_instance(obj, vm, view);
  46        if (IS_ERR(vma))
  47                goto err;
  48
  49        if (i915_vma_misplaced(vma, 0, alignment, 0)) {
  50                ret = i915_vma_unbind(vma);
  51                if (ret) {
  52                        vma = ERR_PTR(ret);
  53                        goto err;
  54                }
  55        }
  56
  57        ret = i915_vma_pin(vma, 0, alignment, PIN_GLOBAL);
  58        if (ret) {
  59                vma = ERR_PTR(ret);
  60                goto err;
  61        }
  62
  63        vma->display_alignment = max_t(u64, vma->display_alignment, alignment);
  64
  65        i915_gem_object_flush_if_display(obj);
  66
  67        i915_vma_get(vma);
  68err:
  69        atomic_dec(&dev_priv->gpu_error.pending_fb_pin);
  70
  71        return vma;
  72}
  73
  74struct i915_vma *
  75intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
  76                           bool phys_cursor,
  77                           const struct i915_ggtt_view *view,
  78                           bool uses_fence,
  79                           unsigned long *out_flags)
  80{
  81        struct drm_device *dev = fb->dev;
  82        struct drm_i915_private *dev_priv = to_i915(dev);
  83        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
  84        intel_wakeref_t wakeref;
  85        struct i915_gem_ww_ctx ww;
  86        struct i915_vma *vma;
  87        unsigned int pinctl;
  88        u32 alignment;
  89        int ret;
  90
  91        if (drm_WARN_ON(dev, !i915_gem_object_is_framebuffer(obj)))
  92                return ERR_PTR(-EINVAL);
  93
  94        if (phys_cursor)
  95                alignment = intel_cursor_alignment(dev_priv);
  96        else
  97                alignment = intel_surf_alignment(fb, 0);
  98        if (drm_WARN_ON(dev, alignment && !is_power_of_2(alignment)))
  99                return ERR_PTR(-EINVAL);
 100
 101        /* Note that the w/a also requires 64 PTE of padding following the
 102         * bo. We currently fill all unused PTE with the shadow page and so
 103         * we should always have valid PTE following the scanout preventing
 104         * the VT-d warning.
 105         */
 106        if (intel_scanout_needs_vtd_wa(dev_priv) && alignment < 256 * 1024)
 107                alignment = 256 * 1024;
 108
 109        /*
 110         * Global gtt pte registers are special registers which actually forward
 111         * writes to a chunk of system memory. Which means that there is no risk
 112         * that the register values disappear as soon as we call
 113         * intel_runtime_pm_put(), so it is correct to wrap only the
 114         * pin/unpin/fence and not more.
 115         */
 116        wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
 117
 118        atomic_inc(&dev_priv->gpu_error.pending_fb_pin);
 119
 120        /*
 121         * Valleyview is definitely limited to scanning out the first
 122         * 512MiB. Lets presume this behaviour was inherited from the
 123         * g4x display engine and that all earlier gen are similarly
 124         * limited. Testing suggests that it is a little more
 125         * complicated than this. For example, Cherryview appears quite
 126         * happy to scanout from anywhere within its global aperture.
 127         */
 128        pinctl = 0;
 129        if (HAS_GMCH(dev_priv))
 130                pinctl |= PIN_MAPPABLE;
 131
 132        i915_gem_ww_ctx_init(&ww, true);
 133retry:
 134        ret = i915_gem_object_lock(obj, &ww);
 135        if (!ret && phys_cursor)
 136                ret = i915_gem_object_attach_phys(obj, alignment);
 137        else if (!ret && HAS_LMEM(dev_priv))
 138                ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM);
 139        /* TODO: Do we need to sync when migration becomes async? */
 140        if (!ret)
 141                ret = i915_gem_object_pin_pages(obj);
 142        if (ret)
 143                goto err;
 144
 145        vma = i915_gem_object_pin_to_display_plane(obj, &ww, alignment,
 146                                                   view, pinctl);
 147        if (IS_ERR(vma)) {
 148                ret = PTR_ERR(vma);
 149                goto err_unpin;
 150        }
 151
 152        if (uses_fence && i915_vma_is_map_and_fenceable(vma)) {
 153                /*
 154                 * Install a fence for tiled scan-out. Pre-i965 always needs a
 155                 * fence, whereas 965+ only requires a fence if using
 156                 * framebuffer compression.  For simplicity, we always, when
 157                 * possible, install a fence as the cost is not that onerous.
 158                 *
 159                 * If we fail to fence the tiled scanout, then either the
 160                 * modeset will reject the change (which is highly unlikely as
 161                 * the affected systems, all but one, do not have unmappable
 162                 * space) or we will not be able to enable full powersaving
 163                 * techniques (also likely not to apply due to various limits
 164                 * FBC and the like impose on the size of the buffer, which
 165                 * presumably we violated anyway with this unmappable buffer).
 166                 * Anyway, it is presumably better to stumble onwards with
 167                 * something and try to run the system in a "less than optimal"
 168                 * mode that matches the user configuration.
 169                 */
 170                ret = i915_vma_pin_fence(vma);
 171                if (ret != 0 && DISPLAY_VER(dev_priv) < 4) {
 172                        i915_vma_unpin(vma);
 173                        goto err_unpin;
 174                }
 175                ret = 0;
 176
 177                if (vma->fence)
 178                        *out_flags |= PLANE_HAS_FENCE;
 179        }
 180
 181        i915_vma_get(vma);
 182
 183err_unpin:
 184        i915_gem_object_unpin_pages(obj);
 185err:
 186        if (ret == -EDEADLK) {
 187                ret = i915_gem_ww_ctx_backoff(&ww);
 188                if (!ret)
 189                        goto retry;
 190        }
 191        i915_gem_ww_ctx_fini(&ww);
 192        if (ret)
 193                vma = ERR_PTR(ret);
 194
 195        atomic_dec(&dev_priv->gpu_error.pending_fb_pin);
 196        intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
 197        return vma;
 198}
 199
 200void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags)
 201{
 202        if (flags & PLANE_HAS_FENCE)
 203                i915_vma_unpin_fence(vma);
 204        i915_vma_unpin(vma);
 205        i915_vma_put(vma);
 206}
 207
 208int intel_plane_pin_fb(struct intel_plane_state *plane_state)
 209{
 210        struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
 211        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 212        struct drm_framebuffer *fb = plane_state->hw.fb;
 213        struct i915_vma *vma;
 214        bool phys_cursor =
 215                plane->id == PLANE_CURSOR &&
 216                INTEL_INFO(dev_priv)->display.cursor_needs_physical;
 217
 218        if (!intel_fb_uses_dpt(fb)) {
 219                vma = intel_pin_and_fence_fb_obj(fb, phys_cursor,
 220                                                 &plane_state->view.gtt,
 221                                                 intel_plane_uses_fence(plane_state),
 222                                                 &plane_state->flags);
 223                if (IS_ERR(vma))
 224                        return PTR_ERR(vma);
 225
 226                plane_state->ggtt_vma = vma;
 227        } else {
 228                struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 229
 230                vma = intel_dpt_pin(intel_fb->dpt_vm);
 231                if (IS_ERR(vma))
 232                        return PTR_ERR(vma);
 233
 234                plane_state->ggtt_vma = vma;
 235
 236                vma = intel_pin_fb_obj_dpt(fb, &plane_state->view.gtt, false,
 237                                           &plane_state->flags, intel_fb->dpt_vm);
 238                if (IS_ERR(vma)) {
 239                        intel_dpt_unpin(intel_fb->dpt_vm);
 240                        plane_state->ggtt_vma = NULL;
 241                        return PTR_ERR(vma);
 242                }
 243
 244                plane_state->dpt_vma = vma;
 245
 246                WARN_ON(plane_state->ggtt_vma == plane_state->dpt_vma);
 247        }
 248
 249        return 0;
 250}
 251
 252void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
 253{
 254        struct drm_framebuffer *fb = old_plane_state->hw.fb;
 255        struct i915_vma *vma;
 256
 257        if (!intel_fb_uses_dpt(fb)) {
 258                vma = fetch_and_zero(&old_plane_state->ggtt_vma);
 259                if (vma)
 260                        intel_unpin_fb_vma(vma, old_plane_state->flags);
 261        } else {
 262                struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 263
 264                vma = fetch_and_zero(&old_plane_state->dpt_vma);
 265                if (vma)
 266                        intel_unpin_fb_vma(vma, old_plane_state->flags);
 267
 268                vma = fetch_and_zero(&old_plane_state->ggtt_vma);
 269                if (vma)
 270                        intel_dpt_unpin(intel_fb->dpt_vm);
 271        }
 272}
 273