brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · e845425 Raw
281 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2024 Intel Corporation4 */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 initialize66 * @limit: number of IDs to manage67 *68 * The bare-metal or PF driver can pass ~0 as &limit to indicate that all69 * context IDs supported by the GuC firmware are available for use.70 *71 * Only VF drivers will have to provide explicit number of context IDs72 * 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 make135		 * sure there will be at least 'retain' available for the PF136		 */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_mgr181 * @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_mgr196 * @id: the GuC context ID to release197 * @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_mgr211 * @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 that215 * reserved range of IDs will be contiguous and that there will be at least216 * &retain IDs still available for the PF after this reservation.217 *218 * Return: starting ID of the allocated GuC context ID range or219 *         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_mgr239 * @start: the starting ID of GuC context range to release240 * @count: number of GuC context IDs to release241 */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 print268 * @p: the &drm_printer to print to269 * @indent: tab indentation level270 */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#endif281