linux/drivers/gpu/drm/i915/gt/intel_renderstate.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2/*
   3 * Copyright © 2014 Intel Corporation
   4 */
   5
   6#include "i915_drv.h"
   7#include "intel_renderstate.h"
   8#include "intel_context.h"
   9#include "intel_gpu_commands.h"
  10#include "intel_ring.h"
  11
  12static const struct intel_renderstate_rodata *
  13render_state_get_rodata(const struct intel_engine_cs *engine)
  14{
  15        if (engine->class != RENDER_CLASS)
  16                return NULL;
  17
  18        switch (GRAPHICS_VER(engine->i915)) {
  19        case 6:
  20                return &gen6_null_state;
  21        case 7:
  22                return &gen7_null_state;
  23        case 8:
  24                return &gen8_null_state;
  25        case 9:
  26                return &gen9_null_state;
  27        }
  28
  29        return NULL;
  30}
  31
  32/*
  33 * Macro to add commands to auxiliary batch.
  34 * This macro only checks for page overflow before inserting the commands,
  35 * this is sufficient as the null state generator makes the final batch
  36 * with two passes to build command and state separately. At this point
  37 * the size of both are known and it compacts them by relocating the state
  38 * right after the commands taking care of alignment so we should sufficient
  39 * space below them for adding new commands.
  40 */
  41#define OUT_BATCH(batch, i, val)                                \
  42        do {                                                    \
  43                if ((i) >= PAGE_SIZE / sizeof(u32))             \
  44                        goto out;                               \
  45                (batch)[(i)++] = (val);                         \
  46        } while (0)
  47
  48static int render_state_setup(struct intel_renderstate *so,
  49                              struct drm_i915_private *i915)
  50{
  51        const struct intel_renderstate_rodata *rodata = so->rodata;
  52        unsigned int i = 0, reloc_index = 0;
  53        int ret = -EINVAL;
  54        u32 *d;
  55
  56        d = i915_gem_object_pin_map(so->vma->obj, I915_MAP_WB);
  57        if (IS_ERR(d))
  58                return PTR_ERR(d);
  59
  60        while (i < rodata->batch_items) {
  61                u32 s = rodata->batch[i];
  62
  63                if (i * 4  == rodata->reloc[reloc_index]) {
  64                        u64 r = s + so->vma->node.start;
  65
  66                        s = lower_32_bits(r);
  67                        if (HAS_64BIT_RELOC(i915)) {
  68                                if (i + 1 >= rodata->batch_items ||
  69                                    rodata->batch[i + 1] != 0)
  70                                        goto out;
  71
  72                                d[i++] = s;
  73                                s = upper_32_bits(r);
  74                        }
  75
  76                        reloc_index++;
  77                }
  78
  79                d[i++] = s;
  80        }
  81
  82        if (rodata->reloc[reloc_index] != -1) {
  83                drm_err(&i915->drm, "only %d relocs resolved\n", reloc_index);
  84                goto out;
  85        }
  86
  87        so->batch_offset = i915_ggtt_offset(so->vma);
  88        so->batch_size = rodata->batch_items * sizeof(u32);
  89
  90        while (i % CACHELINE_DWORDS)
  91                OUT_BATCH(d, i, MI_NOOP);
  92
  93        so->aux_offset = i * sizeof(u32);
  94
  95        if (HAS_POOLED_EU(i915)) {
  96                /*
  97                 * We always program 3x6 pool config but depending upon which
  98                 * subslice is disabled HW drops down to appropriate config
  99                 * shown below.
 100                 *
 101                 * In the below table 2x6 config always refers to
 102                 * fused-down version, native 2x6 is not available and can
 103                 * be ignored
 104                 *
 105                 * SNo  subslices config                eu pool configuration
 106                 * -----------------------------------------------------------
 107                 * 1    3 subslices enabled (3x6)  -    0x00777000  (9+9)
 108                 * 2    ss0 disabled (2x6)         -    0x00777000  (3+9)
 109                 * 3    ss1 disabled (2x6)         -    0x00770000  (6+6)
 110                 * 4    ss2 disabled (2x6)         -    0x00007000  (9+3)
 111                 */
 112                u32 eu_pool_config = 0x00777000;
 113
 114                OUT_BATCH(d, i, GEN9_MEDIA_POOL_STATE);
 115                OUT_BATCH(d, i, GEN9_MEDIA_POOL_ENABLE);
 116                OUT_BATCH(d, i, eu_pool_config);
 117                OUT_BATCH(d, i, 0);
 118                OUT_BATCH(d, i, 0);
 119                OUT_BATCH(d, i, 0);
 120        }
 121
 122        OUT_BATCH(d, i, MI_BATCH_BUFFER_END);
 123        so->aux_size = i * sizeof(u32) - so->aux_offset;
 124        so->aux_offset += so->batch_offset;
 125        /*
 126         * Since we are sending length, we need to strictly conform to
 127         * all requirements. For Gen2 this must be a multiple of 8.
 128         */
 129        so->aux_size = ALIGN(so->aux_size, 8);
 130
 131        ret = 0;
 132out:
 133        __i915_gem_object_flush_map(so->vma->obj, 0, i * sizeof(u32));
 134        __i915_gem_object_release_map(so->vma->obj);
 135        return ret;
 136}
 137
 138#undef OUT_BATCH
 139
 140int intel_renderstate_init(struct intel_renderstate *so,
 141                           struct intel_context *ce)
 142{
 143        struct intel_engine_cs *engine = ce->engine;
 144        struct drm_i915_gem_object *obj = NULL;
 145        int err;
 146
 147        memset(so, 0, sizeof(*so));
 148
 149        so->rodata = render_state_get_rodata(engine);
 150        if (so->rodata) {
 151                if (so->rodata->batch_items * 4 > PAGE_SIZE)
 152                        return -EINVAL;
 153
 154                obj = i915_gem_object_create_internal(engine->i915, PAGE_SIZE);
 155                if (IS_ERR(obj))
 156                        return PTR_ERR(obj);
 157
 158                so->vma = i915_vma_instance(obj, &engine->gt->ggtt->vm, NULL);
 159                if (IS_ERR(so->vma)) {
 160                        err = PTR_ERR(so->vma);
 161                        goto err_obj;
 162                }
 163        }
 164
 165        i915_gem_ww_ctx_init(&so->ww, true);
 166retry:
 167        err = intel_context_pin_ww(ce, &so->ww);
 168        if (err)
 169                goto err_fini;
 170
 171        /* return early if there's nothing to setup */
 172        if (!err && !so->rodata)
 173                return 0;
 174
 175        err = i915_gem_object_lock(so->vma->obj, &so->ww);
 176        if (err)
 177                goto err_context;
 178
 179        err = i915_vma_pin_ww(so->vma, &so->ww, 0, 0, PIN_GLOBAL | PIN_HIGH);
 180        if (err)
 181                goto err_context;
 182
 183        err = render_state_setup(so, engine->i915);
 184        if (err)
 185                goto err_unpin;
 186
 187        return 0;
 188
 189err_unpin:
 190        i915_vma_unpin(so->vma);
 191err_context:
 192        intel_context_unpin(ce);
 193err_fini:
 194        if (err == -EDEADLK) {
 195                err = i915_gem_ww_ctx_backoff(&so->ww);
 196                if (!err)
 197                        goto retry;
 198        }
 199        i915_gem_ww_ctx_fini(&so->ww);
 200err_obj:
 201        if (obj)
 202                i915_gem_object_put(obj);
 203        so->vma = NULL;
 204        return err;
 205}
 206
 207int intel_renderstate_emit(struct intel_renderstate *so,
 208                           struct i915_request *rq)
 209{
 210        struct intel_engine_cs *engine = rq->engine;
 211        int err;
 212
 213        if (!so->vma)
 214                return 0;
 215
 216        err = i915_request_await_object(rq, so->vma->obj, false);
 217        if (err == 0)
 218                err = i915_vma_move_to_active(so->vma, rq, 0);
 219        if (err)
 220                return err;
 221
 222        err = engine->emit_bb_start(rq,
 223                                    so->batch_offset, so->batch_size,
 224                                    I915_DISPATCH_SECURE);
 225        if (err)
 226                return err;
 227
 228        if (so->aux_size > 8) {
 229                err = engine->emit_bb_start(rq,
 230                                            so->aux_offset, so->aux_size,
 231                                            I915_DISPATCH_SECURE);
 232                if (err)
 233                        return err;
 234        }
 235
 236        return 0;
 237}
 238
 239void intel_renderstate_fini(struct intel_renderstate *so,
 240                            struct intel_context *ce)
 241{
 242        if (so->vma) {
 243                i915_vma_unpin(so->vma);
 244                i915_vma_close(so->vma);
 245        }
 246
 247        intel_context_unpin(ce);
 248        i915_gem_ww_ctx_fini(&so->ww);
 249
 250        if (so->vma)
 251                i915_gem_object_put(so->vma->obj);
 252}
 253