2 * Copyright © 2016 Intel Corporation
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:
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
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
25 #include "mock_engine.h"
26 #include "mock_request.h"
28 static struct mock_request
*first_request(struct mock_engine
*engine
)
30 return list_first_entry_or_null(&engine
->hw_queue
,
35 static void advance(struct mock_engine
*engine
,
36 struct mock_request
*request
)
38 list_del_init(&request
->link
);
39 mock_seqno_advance(&engine
->base
, request
->base
.global_seqno
);
42 static void hw_delay_complete(struct timer_list
*t
)
44 struct mock_engine
*engine
= from_timer(engine
, t
, hw_delay
);
45 struct mock_request
*request
;
47 spin_lock(&engine
->hw_lock
);
49 /* Timer fired, first request is complete */
50 request
= first_request(engine
);
52 advance(engine
, request
);
55 * Also immediately signal any subsequent 0-delay requests, but
56 * requeue the timer for the next delayed request.
58 while ((request
= first_request(engine
))) {
60 mod_timer(&engine
->hw_delay
, jiffies
+ request
->delay
);
64 advance(engine
, request
);
67 spin_unlock(&engine
->hw_lock
);
70 static struct intel_ring
*
71 mock_context_pin(struct intel_engine_cs
*engine
,
72 struct i915_gem_context
*ctx
)
74 i915_gem_context_get(ctx
);
75 return engine
->buffer
;
78 static void mock_context_unpin(struct intel_engine_cs
*engine
,
79 struct i915_gem_context
*ctx
)
81 i915_gem_context_put(ctx
);
84 static int mock_request_alloc(struct drm_i915_gem_request
*request
)
86 struct mock_request
*mock
= container_of(request
, typeof(*mock
), base
);
88 INIT_LIST_HEAD(&mock
->link
);
94 static int mock_emit_flush(struct drm_i915_gem_request
*request
,
100 static void mock_emit_breadcrumb(struct drm_i915_gem_request
*request
,
105 static void mock_submit_request(struct drm_i915_gem_request
*request
)
107 struct mock_request
*mock
= container_of(request
, typeof(*mock
), base
);
108 struct mock_engine
*engine
=
109 container_of(request
->engine
, typeof(*engine
), base
);
111 i915_gem_request_submit(request
);
112 GEM_BUG_ON(!request
->global_seqno
);
114 spin_lock_irq(&engine
->hw_lock
);
115 list_add_tail(&mock
->link
, &engine
->hw_queue
);
116 if (mock
->link
.prev
== &engine
->hw_queue
) {
118 mod_timer(&engine
->hw_delay
, jiffies
+ mock
->delay
);
120 advance(engine
, mock
);
122 spin_unlock_irq(&engine
->hw_lock
);
125 static struct intel_ring
*mock_ring(struct intel_engine_cs
*engine
)
127 const unsigned long sz
= PAGE_SIZE
/ 2;
128 struct intel_ring
*ring
;
130 BUILD_BUG_ON(MIN_SPACE_FOR_ADD_REQUEST
> sz
);
132 ring
= kzalloc(sizeof(*ring
) + sz
, GFP_KERNEL
);
137 ring
->effective_size
= sz
;
138 ring
->vaddr
= (void *)(ring
+ 1);
140 INIT_LIST_HEAD(&ring
->request_list
);
141 intel_ring_update_space(ring
);
146 struct intel_engine_cs
*mock_engine(struct drm_i915_private
*i915
,
150 struct mock_engine
*engine
;
152 GEM_BUG_ON(id
>= I915_NUM_ENGINES
);
154 engine
= kzalloc(sizeof(*engine
) + PAGE_SIZE
, GFP_KERNEL
);
158 engine
->base
.buffer
= mock_ring(&engine
->base
);
159 if (!engine
->base
.buffer
) {
164 /* minimal engine setup for requests */
165 engine
->base
.i915
= i915
;
166 snprintf(engine
->base
.name
, sizeof(engine
->base
.name
), "%s", name
);
167 engine
->base
.id
= id
;
168 engine
->base
.status_page
.page_addr
= (void *)(engine
+ 1);
170 engine
->base
.context_pin
= mock_context_pin
;
171 engine
->base
.context_unpin
= mock_context_unpin
;
172 engine
->base
.request_alloc
= mock_request_alloc
;
173 engine
->base
.emit_flush
= mock_emit_flush
;
174 engine
->base
.emit_breadcrumb
= mock_emit_breadcrumb
;
175 engine
->base
.submit_request
= mock_submit_request
;
177 engine
->base
.timeline
=
178 &i915
->gt
.global_timeline
.engine
[engine
->base
.id
];
180 intel_engine_init_breadcrumbs(&engine
->base
);
181 engine
->base
.breadcrumbs
.mock
= true; /* prevent touching HW for irqs */
184 spin_lock_init(&engine
->hw_lock
);
185 timer_setup(&engine
->hw_delay
, hw_delay_complete
, 0);
186 INIT_LIST_HEAD(&engine
->hw_queue
);
188 return &engine
->base
;
191 void mock_engine_flush(struct intel_engine_cs
*engine
)
193 struct mock_engine
*mock
=
194 container_of(engine
, typeof(*mock
), base
);
195 struct mock_request
*request
, *rn
;
197 del_timer_sync(&mock
->hw_delay
);
199 spin_lock_irq(&mock
->hw_lock
);
200 list_for_each_entry_safe(request
, rn
, &mock
->hw_queue
, link
) {
201 list_del_init(&request
->link
);
202 mock_seqno_advance(&mock
->base
, request
->base
.global_seqno
);
204 spin_unlock_irq(&mock
->hw_lock
);
207 void mock_engine_reset(struct intel_engine_cs
*engine
)
209 intel_write_status_page(engine
, I915_GEM_HWS_INDEX
, 0);
212 void mock_engine_free(struct intel_engine_cs
*engine
)
214 struct mock_engine
*mock
=
215 container_of(engine
, typeof(*mock
), base
);
217 GEM_BUG_ON(timer_pending(&mock
->hw_delay
));
219 if (engine
->last_retired_context
)
220 engine
->context_unpin(engine
, engine
->last_retired_context
);
222 intel_engine_fini_breadcrumbs(engine
);
224 kfree(engine
->buffer
);