Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2024 Intel Corporation
  4 */
  5
  6#include <linux/bitmap.h>
  7#include <linux/mutex.h>
  8
  9#include <drm/drm_managed.h>
 10
 11#include "xe_assert.h"
 12#include "xe_gt_printk.h"
 13#include "xe_guc.h"
 14#include "xe_guc_id_mgr.h"
 15#include "xe_guc_types.h"
 16
 17static struct xe_guc *idm_to_guc(struct xe_guc_id_mgr *idm)
 18{
 19	return container_of(idm, struct xe_guc, submission_state.idm);
 20}
 21
 22static struct xe_gt *idm_to_gt(struct xe_guc_id_mgr *idm)
 23{
 24	return guc_to_gt(idm_to_guc(idm));
 25}
 26
 27static struct xe_device *idm_to_xe(struct xe_guc_id_mgr *idm)
 28{
 29	return gt_to_xe(idm_to_gt(idm));
 30}
 31
 32#define idm_assert(idm, cond)		xe_gt_assert(idm_to_gt(idm), cond)
 33#define idm_mutex(idm)			(&idm_to_guc(idm)->submission_state.lock)
 34
 35static void idm_print_locked(struct xe_guc_id_mgr *idm, struct drm_printer *p, int indent);
 36
 37static void __fini_idm(struct drm_device *drm, void *arg)
 38{
 39	struct xe_guc_id_mgr *idm = arg;
 40
 41	mutex_lock(idm_mutex(idm));
 42
 43	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) {
 44		unsigned int weight = bitmap_weight(idm->bitmap, idm->total);
 45
 46		if (weight) {
 47			struct drm_printer p = xe_gt_info_printer(idm_to_gt(idm));
 48
 49			xe_gt_err(idm_to_gt(idm), "GUC ID manager unclean (%u/%u)\n",
 50				  weight, idm->total);
 51			idm_print_locked(idm, &p, 1);
 52		}
 53	}
 54
 55	bitmap_free(idm->bitmap);
 56	idm->bitmap = NULL;
 57	idm->total = 0;
 58	idm->used = 0;
 59
 60	mutex_unlock(idm_mutex(idm));
 61}
 62
 63/**
 64 * xe_guc_id_mgr_init() - Initialize GuC context ID Manager.
 65 * @idm: the &xe_guc_id_mgr to initialize
 66 * @limit: number of IDs to manage
 67 *
 68 * The bare-metal or PF driver can pass ~0 as &limit to indicate that all
 69 * context IDs supported by the GuC firmware are available for use.
 70 *
 71 * Only VF drivers will have to provide explicit number of context IDs
 72 * that they can use.
 73 *
 74 * Return: 0 on success or a negative error code on failure.
 75 */
 76int xe_guc_id_mgr_init(struct xe_guc_id_mgr *idm, unsigned int limit)
 77{
 78	int ret;
 79
 80	idm_assert(idm, !idm->bitmap);
 81	idm_assert(idm, !idm->total);
 82	idm_assert(idm, !idm->used);
 83
 84	if (limit == ~0)
 85		limit = GUC_ID_MAX;
 86	else if (limit > GUC_ID_MAX)
 87		return -ERANGE;
 88	else if (!limit)
 89		return -EINVAL;
 90
 91	idm->bitmap = bitmap_zalloc(limit, GFP_KERNEL);
 92	if (!idm->bitmap)
 93		return -ENOMEM;
 94	idm->total = limit;
 95
 96	ret = drmm_add_action_or_reset(&idm_to_xe(idm)->drm, __fini_idm, idm);
 97	if (ret)
 98		return ret;
 99
100	xe_gt_dbg(idm_to_gt(idm), "using %u GuC ID%s\n",
101		  idm->total, str_plural(idm->total));
102	return 0;
103}
104
105static unsigned int find_last_zero_area(unsigned long *bitmap,
106					unsigned int total,
107					unsigned int count)
108{
109	unsigned int found = total;
110	unsigned int rs, re, range;
111
112	for_each_clear_bitrange(rs, re, bitmap, total) {
113		range = re - rs;
114		if (range < count)
115			continue;
116		found = rs + (range - count);
117	}
118	return found;
119}
120
121static int idm_reserve_chunk_locked(struct xe_guc_id_mgr *idm,
122				    unsigned int count, unsigned int retain)
123{
124	int id;
125
126	idm_assert(idm, count);
127	lockdep_assert_held(idm_mutex(idm));
128
129	if (!idm->total)
130		return -ENODATA;
131
132	if (retain) {
133		/*
134		 * For IDs reservations (used on PF for VFs) we want to make
135		 * sure there will be at least 'retain' available for the PF
136		 */
137		if (idm->used + count + retain > idm->total)
138			return -EDQUOT;
139		/*
140		 * ... and we want to reserve highest IDs close to the end.
141		 */
142		id = find_last_zero_area(idm->bitmap, idm->total, count);
143	} else {
144		/*
145		 * For regular IDs reservations (used by submission code)
146		 * we start searching from the lower range of IDs.
147		 */
148		id = bitmap_find_next_zero_area(idm->bitmap, idm->total, 0, count, 0);
149	}
150	if (id >= idm->total)
151		return -ENOSPC;
152
153	bitmap_set(idm->bitmap, id, count);
154	idm->used += count;
155
156	return id;
157}
158
159static void idm_release_chunk_locked(struct xe_guc_id_mgr *idm,
160				     unsigned int start, unsigned int count)
161{
162	idm_assert(idm, count);
163	idm_assert(idm, count <= idm->used);
164	idm_assert(idm, start < idm->total);
165	idm_assert(idm, start + count - 1 < idm->total);
166	lockdep_assert_held(idm_mutex(idm));
167
168	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) {
169		unsigned int n;
170
171		for (n = 0; n < count; n++)
172			idm_assert(idm, test_bit(start + n, idm->bitmap));
173	}
174	bitmap_clear(idm->bitmap, start, count);
175	idm->used -= count;
176}
177
178/**
179 * xe_guc_id_mgr_reserve_locked() - Reserve one or more GuC context IDs.
180 * @idm: the &xe_guc_id_mgr
181 * @count: number of IDs to allocate (can't be 0)
182 *
183 * This function is dedicated for the use by the GuC submission code,
184 * where submission lock is already taken.
185 *
186 * Return: ID of allocated GuC context or a negative error code on failure.
187 */
188int xe_guc_id_mgr_reserve_locked(struct xe_guc_id_mgr *idm, unsigned int count)
189{
190	return idm_reserve_chunk_locked(idm, count, 0);
191}
192
193/**
194 * xe_guc_id_mgr_release_locked() - Release one or more GuC context IDs.
195 * @idm: the &xe_guc_id_mgr
196 * @id: the GuC context ID to release
197 * @count: number of IDs to release (can't be 0)
198 *
199 * This function is dedicated for the use by the GuC submission code,
200 * where submission lock is already taken.
201 */
202void xe_guc_id_mgr_release_locked(struct xe_guc_id_mgr *idm, unsigned int id,
203				  unsigned int count)
204{
205	return idm_release_chunk_locked(idm, id, count);
206}
207
208/**
209 * xe_guc_id_mgr_reserve() - Reserve a range of GuC context IDs.
210 * @idm: the &xe_guc_id_mgr
211 * @count: number of GuC context IDs to reserve (can't be 0)
212 * @retain: number of GuC context IDs to keep available (can't be 0)
213 *
214 * This function is dedicated for the use by the PF driver which expects that
215 * reserved range of IDs will be contiguous and that there will be at least
216 * &retain IDs still available for the PF after this reservation.
217 *
218 * Return: starting ID of the allocated GuC context ID range or
219 *         a negative error code on failure.
220 */
221int xe_guc_id_mgr_reserve(struct xe_guc_id_mgr *idm,
222			  unsigned int count, unsigned int retain)
223{
224	int ret;
225
226	idm_assert(idm, count);
227	idm_assert(idm, retain);
228
229	mutex_lock(idm_mutex(idm));
230	ret = idm_reserve_chunk_locked(idm, count, retain);
231	mutex_unlock(idm_mutex(idm));
232
233	return ret;
234}
235
236/**
237 * xe_guc_id_mgr_release() - Release a range of GuC context IDs.
238 * @idm: the &xe_guc_id_mgr
239 * @start: the starting ID of GuC context range to release
240 * @count: number of GuC context IDs to release
241 */
242void xe_guc_id_mgr_release(struct xe_guc_id_mgr *idm,
243			   unsigned int start, unsigned int count)
244{
245	mutex_lock(idm_mutex(idm));
246	idm_release_chunk_locked(idm, start, count);
247	mutex_unlock(idm_mutex(idm));
248}
249
250static void idm_print_locked(struct xe_guc_id_mgr *idm, struct drm_printer *p, int indent)
251{
252	unsigned int rs, re;
253
254	lockdep_assert_held(idm_mutex(idm));
255
256	drm_printf_indent(p, indent, "total %u\n", idm->total);
257	if (!idm->bitmap)
258		return;
259
260	drm_printf_indent(p, indent, "used %u\n", idm->used);
261	for_each_set_bitrange(rs, re, idm->bitmap, idm->total)
262		drm_printf_indent(p, indent, "range %u..%u (%u)\n", rs, re - 1, re - rs);
263}
264
265/**
266 * xe_guc_id_mgr_print() - Print status of GuC ID Manager.
267 * @idm: the &xe_guc_id_mgr to print
268 * @p: the &drm_printer to print to
269 * @indent: tab indentation level
270 */
271void xe_guc_id_mgr_print(struct xe_guc_id_mgr *idm, struct drm_printer *p, int indent)
272{
273	mutex_lock(idm_mutex(idm));
274	idm_print_locked(idm, p, indent);
275	mutex_unlock(idm_mutex(idm));
276}
277
278#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
279#include "tests/xe_guc_id_mgr_test.c"
280#endif