Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  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 advance(struct mock_engine *engine,
 36		    struct mock_request *request)
 37{
 38	list_del_init(&request->link);
 39	mock_seqno_advance(&engine->base, request->base.global_seqno);
 40}
 41
 42static void hw_delay_complete(struct timer_list *t)
 43{
 44	struct mock_engine *engine = from_timer(engine, t, hw_delay);
 45	struct mock_request *request;
 46
 47	spin_lock(&engine->hw_lock);
 48
 49	/* Timer fired, first request is complete */
 50	request = first_request(engine);
 51	if (request)
 52		advance(engine, request);
 53
 54	/*
 55	 * Also immediately signal any subsequent 0-delay requests, but
 56	 * requeue the timer for the next delayed request.
 57	 */
 58	while ((request = first_request(engine))) {
 59		if (request->delay) {
 60			mod_timer(&engine->hw_delay, jiffies + request->delay);
 61			break;
 62		}
 63
 64		advance(engine, request);
 65	}
 66
 67	spin_unlock(&engine->hw_lock);
 68}
 69
 70static struct intel_ring *
 71mock_context_pin(struct intel_engine_cs *engine,
 72		 struct i915_gem_context *ctx)
 73{
 74	i915_gem_context_get(ctx);
 75	return engine->buffer;
 76}
 77
 78static void mock_context_unpin(struct intel_engine_cs *engine,
 79			       struct i915_gem_context *ctx)
 80{
 81	i915_gem_context_put(ctx);
 82}
 83
 84static int mock_request_alloc(struct i915_request *request)
 85{
 86	struct mock_request *mock = container_of(request, typeof(*mock), base);
 87
 88	INIT_LIST_HEAD(&mock->link);
 89	mock->delay = 0;
 90
 91	return 0;
 92}
 93
 94static int mock_emit_flush(struct i915_request *request,
 95			   unsigned int flags)
 96{
 97	return 0;
 98}
 99
100static void mock_emit_breadcrumb(struct i915_request *request,
101				 u32 *flags)
102{
103}
104
105static void mock_submit_request(struct i915_request *request)
106{
107	struct mock_request *mock = container_of(request, typeof(*mock), base);
108	struct mock_engine *engine =
109		container_of(request->engine, typeof(*engine), base);
110
111	i915_request_submit(request);
112	GEM_BUG_ON(!request->global_seqno);
113
114	spin_lock_irq(&engine->hw_lock);
115	list_add_tail(&mock->link, &engine->hw_queue);
116	if (mock->link.prev == &engine->hw_queue) {
117		if (mock->delay)
118			mod_timer(&engine->hw_delay, jiffies + mock->delay);
119		else
120			advance(engine, mock);
121	}
122	spin_unlock_irq(&engine->hw_lock);
123}
124
125static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
126{
127	const unsigned long sz = PAGE_SIZE / 2;
128	struct intel_ring *ring;
129
130	BUILD_BUG_ON(MIN_SPACE_FOR_ADD_REQUEST > sz);
131
132	ring = kzalloc(sizeof(*ring) + sz, GFP_KERNEL);
133	if (!ring)
134		return NULL;
135
136	ring->size = sz;
137	ring->effective_size = sz;
138	ring->vaddr = (void *)(ring + 1);
139
140	INIT_LIST_HEAD(&ring->request_list);
141	intel_ring_update_space(ring);
142
143	return ring;
144}
145
146struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
147				    const char *name,
148				    int id)
149{
150	struct mock_engine *engine;
151
152	GEM_BUG_ON(id >= I915_NUM_ENGINES);
153
154	engine = kzalloc(sizeof(*engine) + PAGE_SIZE, GFP_KERNEL);
155	if (!engine)
156		return NULL;
157
158	engine->base.buffer = mock_ring(&engine->base);
159	if (!engine->base.buffer) {
160		kfree(engine);
161		return NULL;
162	}
163
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);
169
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;
176
177	engine->base.timeline =
178		&i915->gt.global_timeline.engine[engine->base.id];
179
180	intel_engine_init_breadcrumbs(&engine->base);
181	engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
182
183	/* fake hw queue */
184	spin_lock_init(&engine->hw_lock);
185	timer_setup(&engine->hw_delay, hw_delay_complete, 0);
186	INIT_LIST_HEAD(&engine->hw_queue);
187
188	return &engine->base;
189}
190
191void mock_engine_flush(struct intel_engine_cs *engine)
192{
193	struct mock_engine *mock =
194		container_of(engine, typeof(*mock), base);
195	struct mock_request *request, *rn;
196
197	del_timer_sync(&mock->hw_delay);
198
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);
203	}
204	spin_unlock_irq(&mock->hw_lock);
205}
206
207void mock_engine_reset(struct intel_engine_cs *engine)
208{
209	intel_write_status_page(engine, I915_GEM_HWS_INDEX, 0);
210}
211
212void mock_engine_free(struct intel_engine_cs *engine)
213{
214	struct mock_engine *mock =
215		container_of(engine, typeof(*mock), base);
216
217	GEM_BUG_ON(timer_pending(&mock->hw_delay));
218
219	if (engine->last_retired_context)
220		engine->context_unpin(engine, engine->last_retired_context);
221
222	intel_engine_fini_breadcrumbs(engine);
223
224	kfree(engine->buffer);
225	kfree(engine);
226}