linux/drivers/gpu/drm/i915/selftests/mock_engine.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2016 Intel Corporation
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the next
  12 * paragraph) shall be included in all copies or substantial portions of the
  13 * Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21 * IN THE SOFTWARE.
  22 *
  23 */
  24
  25#include "mock_engine.h"
  26#include "mock_request.h"
  27
  28static struct mock_request *first_request(struct mock_engine *engine)
  29{
  30        return list_first_entry_or_null(&engine->hw_queue,
  31                                        struct mock_request,
  32                                        link);
  33}
  34
  35static void hw_delay_complete(unsigned long data)
  36{
  37        struct mock_engine *engine = (typeof(engine))data;
  38        struct mock_request *request;
  39
  40        spin_lock(&engine->hw_lock);
  41
  42        request = first_request(engine);
  43        if (request) {
  44                list_del_init(&request->link);
  45                mock_seqno_advance(&engine->base, request->base.global_seqno);
  46        }
  47
  48        request = first_request(engine);
  49        if (request)
  50                mod_timer(&engine->hw_delay, jiffies + request->delay);
  51
  52        spin_unlock(&engine->hw_lock);
  53}
  54
  55static struct intel_ring *
  56mock_context_pin(struct intel_engine_cs *engine,
  57                 struct i915_gem_context *ctx)
  58{
  59        i915_gem_context_get(ctx);
  60        return engine->buffer;
  61}
  62
  63static void mock_context_unpin(struct intel_engine_cs *engine,
  64                               struct i915_gem_context *ctx)
  65{
  66        i915_gem_context_put(ctx);
  67}
  68
  69static int mock_request_alloc(struct drm_i915_gem_request *request)
  70{
  71        struct mock_request *mock = container_of(request, typeof(*mock), base);
  72
  73        INIT_LIST_HEAD(&mock->link);
  74        mock->delay = 0;
  75
  76        return 0;
  77}
  78
  79static int mock_emit_flush(struct drm_i915_gem_request *request,
  80                           unsigned int flags)
  81{
  82        return 0;
  83}
  84
  85static void mock_emit_breadcrumb(struct drm_i915_gem_request *request,
  86                                 u32 *flags)
  87{
  88}
  89
  90static void mock_submit_request(struct drm_i915_gem_request *request)
  91{
  92        struct mock_request *mock = container_of(request, typeof(*mock), base);
  93        struct mock_engine *engine =
  94                container_of(request->engine, typeof(*engine), base);
  95
  96        i915_gem_request_submit(request);
  97        GEM_BUG_ON(!request->global_seqno);
  98
  99        spin_lock_irq(&engine->hw_lock);
 100        list_add_tail(&mock->link, &engine->hw_queue);
 101        if (mock->link.prev == &engine->hw_queue)
 102                mod_timer(&engine->hw_delay, jiffies + mock->delay);
 103        spin_unlock_irq(&engine->hw_lock);
 104}
 105
 106static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
 107{
 108        const unsigned long sz = roundup_pow_of_two(sizeof(struct intel_ring));
 109        struct intel_ring *ring;
 110
 111        ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL);
 112        if (!ring)
 113                return NULL;
 114
 115        ring->size = sz;
 116        ring->effective_size = sz;
 117        ring->vaddr = (void *)(ring + 1);
 118
 119        INIT_LIST_HEAD(&ring->request_list);
 120        intel_ring_update_space(ring);
 121
 122        return ring;
 123}
 124
 125struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 126                                    const char *name)
 127{
 128        struct mock_engine *engine;
 129        static int id;
 130
 131        engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_KERNEL);
 132        if (!engine)
 133                return NULL;
 134
 135        engine->base.buffer = mock_ring(&engine->base);
 136        if (!engine->base.buffer) {
 137                kfree(engine);
 138                return NULL;
 139        }
 140
 141        /* minimal engine setup for requests */
 142        engine->base.i915 = i915;
 143        snprintf(engine->base.name, sizeof(engine->base.name), "%s", name);
 144        engine->base.id = id++;
 145        engine->base.status_page.page_addr = (void *)(engine + 1);
 146
 147        engine->base.context_pin = mock_context_pin;
 148        engine->base.context_unpin = mock_context_unpin;
 149        engine->base.request_alloc = mock_request_alloc;
 150        engine->base.emit_flush = mock_emit_flush;
 151        engine->base.emit_breadcrumb = mock_emit_breadcrumb;
 152        engine->base.submit_request = mock_submit_request;
 153
 154        engine->base.timeline =
 155                &i915->gt.global_timeline.engine[engine->base.id];
 156
 157        intel_engine_init_breadcrumbs(&engine->base);
 158        engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
 159
 160        /* fake hw queue */
 161        spin_lock_init(&engine->hw_lock);
 162        setup_timer(&engine->hw_delay,
 163                    hw_delay_complete,
 164                    (unsigned long)engine);
 165        INIT_LIST_HEAD(&engine->hw_queue);
 166
 167        return &engine->base;
 168}
 169
 170void mock_engine_flush(struct intel_engine_cs *engine)
 171{
 172        struct mock_engine *mock =
 173                container_of(engine, typeof(*mock), base);
 174        struct mock_request *request, *rn;
 175
 176        del_timer_sync(&mock->hw_delay);
 177
 178        spin_lock_irq(&mock->hw_lock);
 179        list_for_each_entry_safe(request, rn, &mock->hw_queue, link) {
 180                list_del_init(&request->link);
 181                mock_seqno_advance(&mock->base, request->base.global_seqno);
 182        }
 183        spin_unlock_irq(&mock->hw_lock);
 184}
 185
 186void mock_engine_reset(struct intel_engine_cs *engine)
 187{
 188        intel_write_status_page(engine, I915_GEM_HWS_INDEX, 0);
 189}
 190
 191void mock_engine_free(struct intel_engine_cs *engine)
 192{
 193        struct mock_engine *mock =
 194                container_of(engine, typeof(*mock), base);
 195
 196        GEM_BUG_ON(timer_pending(&mock->hw_delay));
 197
 198        if (engine->last_retired_context)
 199                engine->context_unpin(engine, engine->last_retired_context);
 200
 201        intel_engine_fini_breadcrumbs(engine);
 202
 203        kfree(engine->buffer);
 204        kfree(engine);
 205}
 206