Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.15 267 lines 7.1 kB view raw
1// SPDX-License-Identifier: MIT 2/* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6#include <linux/bitmap.h> 7#include <linux/mutex.h> 8 9#include <drm/drm_managed.h> 10 11#include "regs/xe_guc_regs.h" 12 13#include "xe_assert.h" 14#include "xe_gt_printk.h" 15#include "xe_guc.h" 16#include "xe_guc_db_mgr.h" 17#include "xe_guc_types.h" 18 19/** 20 * DOC: GuC Doorbells 21 * 22 * The GFX doorbell solution provides a mechanism for submission of workload 23 * to the graphics hardware by a ring3 application without the penalty of 24 * ring transition for each workload submission. 25 * 26 * In SR-IOV mode, the doorbells are treated as shared resource and PF must 27 * be able to provision exclusive range of IDs across VFs, which may want to 28 * use this feature. 29 */ 30 31static struct xe_guc *dbm_to_guc(struct xe_guc_db_mgr *dbm) 32{ 33 return container_of(dbm, struct xe_guc, dbm); 34} 35 36static struct xe_gt *dbm_to_gt(struct xe_guc_db_mgr *dbm) 37{ 38 return guc_to_gt(dbm_to_guc(dbm)); 39} 40 41static struct xe_device *dbm_to_xe(struct xe_guc_db_mgr *dbm) 42{ 43 return gt_to_xe(dbm_to_gt(dbm)); 44} 45 46#define dbm_assert(_dbm, _cond) xe_gt_assert(dbm_to_gt(_dbm), _cond) 47#define dbm_mutex(_dbm) (&dbm_to_guc(_dbm)->submission_state.lock) 48 49static void dbm_print_locked(struct xe_guc_db_mgr *dbm, struct drm_printer *p, int indent); 50 51static void __fini_dbm(struct drm_device *drm, void *arg) 52{ 53 struct xe_guc_db_mgr *dbm = arg; 54 unsigned int weight; 55 56 mutex_lock(dbm_mutex(dbm)); 57 58 weight = bitmap_weight(dbm->bitmap, dbm->count); 59 if (weight) { 60 struct drm_printer p = xe_gt_info_printer(dbm_to_gt(dbm)); 61 62 xe_gt_err(dbm_to_gt(dbm), "GuC doorbells manager unclean (%u/%u)\n", 63 weight, dbm->count); 64 dbm_print_locked(dbm, &p, 1); 65 } 66 67 bitmap_free(dbm->bitmap); 68 dbm->bitmap = NULL; 69 dbm->count = 0; 70 71 mutex_unlock(dbm_mutex(dbm)); 72} 73 74/** 75 * xe_guc_db_mgr_init() - Initialize GuC Doorbells Manager. 76 * @dbm: the &xe_guc_db_mgr to initialize 77 * @count: number of doorbells to manage 78 * 79 * The bare-metal or PF driver can pass ~0 as &count to indicate that all 80 * doorbells supported by the hardware are available for use. 81 * 82 * Only VF's drivers will have to provide explicit number of doorbells IDs 83 * that they can use. 84 * 85 * Return: 0 on success or a negative error code on failure. 86 */ 87int xe_guc_db_mgr_init(struct xe_guc_db_mgr *dbm, unsigned int count) 88{ 89 int ret; 90 91 if (count == ~0) 92 count = GUC_NUM_DOORBELLS; 93 94 dbm_assert(dbm, !dbm->bitmap); 95 dbm_assert(dbm, count <= GUC_NUM_DOORBELLS); 96 97 if (!count) 98 goto done; 99 100 dbm->bitmap = bitmap_zalloc(count, GFP_KERNEL); 101 if (!dbm->bitmap) 102 return -ENOMEM; 103 dbm->count = count; 104 105 ret = drmm_add_action_or_reset(&dbm_to_xe(dbm)->drm, __fini_dbm, dbm); 106 if (ret) 107 return ret; 108done: 109 xe_gt_dbg(dbm_to_gt(dbm), "using %u doorbell%s\n", 110 dbm->count, str_plural(dbm->count)); 111 return 0; 112} 113 114static int dbm_reserve_chunk_locked(struct xe_guc_db_mgr *dbm, 115 unsigned int count, unsigned int spare) 116{ 117 unsigned int used; 118 int index; 119 120 dbm_assert(dbm, count); 121 dbm_assert(dbm, count <= GUC_NUM_DOORBELLS); 122 dbm_assert(dbm, dbm->count <= GUC_NUM_DOORBELLS); 123 lockdep_assert_held(dbm_mutex(dbm)); 124 125 if (!dbm->count) 126 return -ENODATA; 127 128 if (spare) { 129 used = bitmap_weight(dbm->bitmap, dbm->count); 130 if (used + count + spare > dbm->count) 131 return -EDQUOT; 132 } 133 134 index = bitmap_find_next_zero_area(dbm->bitmap, dbm->count, 0, count, 0); 135 if (index >= dbm->count) 136 return -ENOSPC; 137 138 bitmap_set(dbm->bitmap, index, count); 139 140 return index; 141} 142 143static void dbm_release_chunk_locked(struct xe_guc_db_mgr *dbm, 144 unsigned int start, unsigned int count) 145{ 146 dbm_assert(dbm, count); 147 dbm_assert(dbm, count <= GUC_NUM_DOORBELLS); 148 dbm_assert(dbm, dbm->count); 149 dbm_assert(dbm, dbm->count <= GUC_NUM_DOORBELLS); 150 lockdep_assert_held(dbm_mutex(dbm)); 151 152 if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) { 153 unsigned int n; 154 155 for (n = 0; n < count; n++) 156 dbm_assert(dbm, test_bit(start + n, dbm->bitmap)); 157 } 158 bitmap_clear(dbm->bitmap, start, count); 159} 160 161/** 162 * xe_guc_db_mgr_reserve_id_locked() - Reserve a single GuC Doorbell ID. 163 * @dbm: the &xe_guc_db_mgr 164 * 165 * This function expects that submission lock is already taken. 166 * 167 * Return: ID of the allocated GuC doorbell or a negative error code on failure. 168 */ 169int xe_guc_db_mgr_reserve_id_locked(struct xe_guc_db_mgr *dbm) 170{ 171 return dbm_reserve_chunk_locked(dbm, 1, 0); 172} 173 174/** 175 * xe_guc_db_mgr_release_id_locked() - Release a single GuC Doorbell ID. 176 * @dbm: the &xe_guc_db_mgr 177 * @id: the GuC Doorbell ID to release 178 * 179 * This function expects that submission lock is already taken. 180 */ 181void xe_guc_db_mgr_release_id_locked(struct xe_guc_db_mgr *dbm, unsigned int id) 182{ 183 return dbm_release_chunk_locked(dbm, id, 1); 184} 185 186/** 187 * xe_guc_db_mgr_reserve_range() - Reserve a range of GuC Doorbell IDs. 188 * @dbm: the &xe_guc_db_mgr 189 * @count: number of GuC doorbell IDs to reserve 190 * @spare: number of GuC doorbell IDs to keep available 191 * 192 * This function is dedicated for the for use by the PF which expects that 193 * allocated range for the VF will be contiguous and that there will be at 194 * least &spare IDs still available for the PF use after this reservation. 195 * 196 * Return: starting ID of the allocated GuC doorbell ID range or 197 * a negative error code on failure. 198 */ 199int xe_guc_db_mgr_reserve_range(struct xe_guc_db_mgr *dbm, 200 unsigned int count, unsigned int spare) 201{ 202 int ret; 203 204 mutex_lock(dbm_mutex(dbm)); 205 ret = dbm_reserve_chunk_locked(dbm, count, spare); 206 mutex_unlock(dbm_mutex(dbm)); 207 208 return ret; 209} 210 211/** 212 * xe_guc_db_mgr_release_range() - Release a range of Doorbell IDs. 213 * @dbm: the &xe_guc_db_mgr 214 * @start: the starting ID of GuC doorbell ID range to release 215 * @count: number of GuC doorbell IDs to release 216 */ 217void xe_guc_db_mgr_release_range(struct xe_guc_db_mgr *dbm, 218 unsigned int start, unsigned int count) 219{ 220 mutex_lock(dbm_mutex(dbm)); 221 dbm_release_chunk_locked(dbm, start, count); 222 mutex_unlock(dbm_mutex(dbm)); 223} 224 225static void dbm_print_locked(struct xe_guc_db_mgr *dbm, struct drm_printer *p, int indent) 226{ 227 unsigned int rs, re; 228 unsigned int total; 229 230 drm_printf_indent(p, indent, "count: %u\n", dbm->count); 231 if (!dbm->bitmap) 232 return; 233 234 total = 0; 235 for_each_clear_bitrange(rs, re, dbm->bitmap, dbm->count) { 236 drm_printf_indent(p, indent, "available range: %u..%u (%u)\n", 237 rs, re - 1, re - rs); 238 total += re - rs; 239 } 240 drm_printf_indent(p, indent, "available total: %u\n", total); 241 242 total = 0; 243 for_each_set_bitrange(rs, re, dbm->bitmap, dbm->count) { 244 drm_printf_indent(p, indent, "reserved range: %u..%u (%u)\n", 245 rs, re - 1, re - rs); 246 total += re - rs; 247 } 248 drm_printf_indent(p, indent, "reserved total: %u\n", total); 249} 250 251/** 252 * xe_guc_db_mgr_print() - Print status of GuC Doorbells Manager. 253 * @dbm: the &xe_guc_db_mgr to print 254 * @p: the &drm_printer to print to 255 * @indent: tab indentation level 256 */ 257void xe_guc_db_mgr_print(struct xe_guc_db_mgr *dbm, 258 struct drm_printer *p, int indent) 259{ 260 mutex_lock(dbm_mutex(dbm)); 261 dbm_print_locked(dbm, p, indent); 262 mutex_unlock(dbm_mutex(dbm)); 263} 264 265#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST) 266#include "tests/xe_guc_db_mgr_test.c" 267#endif