1 1.1 riastrad /* $NetBSD: vmwgfx_cmdbuf_res.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $ */ 2 1.1 riastrad 3 1.3 riastrad // SPDX-License-Identifier: GPL-2.0 OR MIT 4 1.1 riastrad /************************************************************************** 5 1.1 riastrad * 6 1.3 riastrad * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA 7 1.1 riastrad * 8 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 9 1.1 riastrad * copy of this software and associated documentation files (the 10 1.1 riastrad * "Software"), to deal in the Software without restriction, including 11 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 12 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 13 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 14 1.1 riastrad * the following conditions: 15 1.1 riastrad * 16 1.1 riastrad * The above copyright notice and this permission notice (including the 17 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 18 1.1 riastrad * of the Software. 19 1.1 riastrad * 20 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 24 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 26 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 27 1.1 riastrad * 28 1.1 riastrad **************************************************************************/ 29 1.1 riastrad 30 1.1 riastrad #include <sys/cdefs.h> 31 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: vmwgfx_cmdbuf_res.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $"); 32 1.1 riastrad 33 1.1 riastrad #include "vmwgfx_drv.h" 34 1.1 riastrad #include "vmwgfx_resource_priv.h" 35 1.1 riastrad 36 1.1 riastrad #define VMW_CMDBUF_RES_MAN_HT_ORDER 12 37 1.1 riastrad 38 1.1 riastrad /** 39 1.1 riastrad * struct vmw_cmdbuf_res - Command buffer managed resource entry. 40 1.1 riastrad * 41 1.1 riastrad * @res: Refcounted pointer to a struct vmw_resource. 42 1.1 riastrad * @hash: Hash entry for the manager hash table. 43 1.1 riastrad * @head: List head used either by the staging list or the manager list 44 1.1 riastrad * of commited resources. 45 1.1 riastrad * @state: Staging state of this resource entry. 46 1.1 riastrad * @man: Pointer to a resource manager for this entry. 47 1.1 riastrad */ 48 1.1 riastrad struct vmw_cmdbuf_res { 49 1.1 riastrad struct vmw_resource *res; 50 1.1 riastrad struct drm_hash_item hash; 51 1.1 riastrad struct list_head head; 52 1.1 riastrad enum vmw_cmdbuf_res_state state; 53 1.1 riastrad struct vmw_cmdbuf_res_manager *man; 54 1.1 riastrad }; 55 1.1 riastrad 56 1.1 riastrad /** 57 1.1 riastrad * struct vmw_cmdbuf_res_manager - Command buffer resource manager. 58 1.1 riastrad * 59 1.1 riastrad * @resources: Hash table containing staged and commited command buffer 60 1.1 riastrad * resources 61 1.1 riastrad * @list: List of commited command buffer resources. 62 1.1 riastrad * @dev_priv: Pointer to a device private structure. 63 1.1 riastrad * 64 1.1 riastrad * @resources and @list are protected by the cmdbuf mutex for now. 65 1.1 riastrad */ 66 1.1 riastrad struct vmw_cmdbuf_res_manager { 67 1.1 riastrad struct drm_open_hash resources; 68 1.1 riastrad struct list_head list; 69 1.1 riastrad struct vmw_private *dev_priv; 70 1.1 riastrad }; 71 1.1 riastrad 72 1.1 riastrad 73 1.1 riastrad /** 74 1.1 riastrad * vmw_cmdbuf_res_lookup - Look up a command buffer resource 75 1.1 riastrad * 76 1.1 riastrad * @man: Pointer to the command buffer resource manager 77 1.1 riastrad * @resource_type: The resource type, that combined with the user key 78 1.1 riastrad * identifies the resource. 79 1.1 riastrad * @user_key: The user key. 80 1.1 riastrad * 81 1.1 riastrad * Returns a valid refcounted struct vmw_resource pointer on success, 82 1.1 riastrad * an error pointer on failure. 83 1.1 riastrad */ 84 1.1 riastrad struct vmw_resource * 85 1.1 riastrad vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man, 86 1.1 riastrad enum vmw_cmdbuf_res_type res_type, 87 1.1 riastrad u32 user_key) 88 1.1 riastrad { 89 1.1 riastrad struct drm_hash_item *hash; 90 1.1 riastrad int ret; 91 1.1 riastrad unsigned long key = user_key | (res_type << 24); 92 1.1 riastrad 93 1.1 riastrad ret = drm_ht_find_item(&man->resources, key, &hash); 94 1.1 riastrad if (unlikely(ret != 0)) 95 1.1 riastrad return ERR_PTR(ret); 96 1.1 riastrad 97 1.3 riastrad return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res; 98 1.1 riastrad } 99 1.1 riastrad 100 1.1 riastrad /** 101 1.1 riastrad * vmw_cmdbuf_res_free - Free a command buffer resource. 102 1.1 riastrad * 103 1.1 riastrad * @man: Pointer to the command buffer resource manager 104 1.1 riastrad * @entry: Pointer to a struct vmw_cmdbuf_res. 105 1.1 riastrad * 106 1.1 riastrad * Frees a struct vmw_cmdbuf_res entry and drops its reference to the 107 1.1 riastrad * struct vmw_resource. 108 1.1 riastrad */ 109 1.1 riastrad static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man, 110 1.1 riastrad struct vmw_cmdbuf_res *entry) 111 1.1 riastrad { 112 1.1 riastrad list_del(&entry->head); 113 1.1 riastrad WARN_ON(drm_ht_remove_item(&man->resources, &entry->hash)); 114 1.1 riastrad vmw_resource_unreference(&entry->res); 115 1.1 riastrad kfree(entry); 116 1.1 riastrad } 117 1.1 riastrad 118 1.1 riastrad /** 119 1.1 riastrad * vmw_cmdbuf_res_commit - Commit a list of command buffer resource actions 120 1.1 riastrad * 121 1.1 riastrad * @list: Caller's list of command buffer resource actions. 122 1.1 riastrad * 123 1.1 riastrad * This function commits a list of command buffer resource 124 1.1 riastrad * additions or removals. 125 1.1 riastrad * It is typically called when the execbuf ioctl call triggering these 126 1.1 riastrad * actions has commited the fifo contents to the device. 127 1.1 riastrad */ 128 1.1 riastrad void vmw_cmdbuf_res_commit(struct list_head *list) 129 1.1 riastrad { 130 1.1 riastrad struct vmw_cmdbuf_res *entry, *next; 131 1.1 riastrad 132 1.1 riastrad list_for_each_entry_safe(entry, next, list, head) { 133 1.1 riastrad list_del(&entry->head); 134 1.1 riastrad if (entry->res->func->commit_notify) 135 1.1 riastrad entry->res->func->commit_notify(entry->res, 136 1.1 riastrad entry->state); 137 1.1 riastrad switch (entry->state) { 138 1.1 riastrad case VMW_CMDBUF_RES_ADD: 139 1.1 riastrad entry->state = VMW_CMDBUF_RES_COMMITTED; 140 1.1 riastrad list_add_tail(&entry->head, &entry->man->list); 141 1.1 riastrad break; 142 1.1 riastrad case VMW_CMDBUF_RES_DEL: 143 1.1 riastrad vmw_resource_unreference(&entry->res); 144 1.1 riastrad kfree(entry); 145 1.1 riastrad break; 146 1.1 riastrad default: 147 1.1 riastrad BUG(); 148 1.1 riastrad break; 149 1.1 riastrad } 150 1.1 riastrad } 151 1.1 riastrad } 152 1.1 riastrad 153 1.1 riastrad /** 154 1.1 riastrad * vmw_cmdbuf_res_revert - Revert a list of command buffer resource actions 155 1.1 riastrad * 156 1.1 riastrad * @man: Pointer to the command buffer resource manager 157 1.1 riastrad * @list: Caller's list of command buffer resource action 158 1.1 riastrad * 159 1.1 riastrad * This function reverts a list of command buffer resource 160 1.1 riastrad * additions or removals. 161 1.1 riastrad * It is typically called when the execbuf ioctl call triggering these 162 1.1 riastrad * actions failed for some reason, and the command stream was never 163 1.1 riastrad * submitted. 164 1.1 riastrad */ 165 1.1 riastrad void vmw_cmdbuf_res_revert(struct list_head *list) 166 1.1 riastrad { 167 1.1 riastrad struct vmw_cmdbuf_res *entry, *next; 168 1.1 riastrad int ret; 169 1.1 riastrad 170 1.1 riastrad list_for_each_entry_safe(entry, next, list, head) { 171 1.1 riastrad switch (entry->state) { 172 1.1 riastrad case VMW_CMDBUF_RES_ADD: 173 1.1 riastrad vmw_cmdbuf_res_free(entry->man, entry); 174 1.1 riastrad break; 175 1.1 riastrad case VMW_CMDBUF_RES_DEL: 176 1.1 riastrad ret = drm_ht_insert_item(&entry->man->resources, 177 1.1 riastrad &entry->hash); 178 1.1 riastrad list_del(&entry->head); 179 1.1 riastrad list_add_tail(&entry->head, &entry->man->list); 180 1.1 riastrad entry->state = VMW_CMDBUF_RES_COMMITTED; 181 1.1 riastrad break; 182 1.1 riastrad default: 183 1.1 riastrad BUG(); 184 1.1 riastrad break; 185 1.1 riastrad } 186 1.1 riastrad } 187 1.1 riastrad } 188 1.1 riastrad 189 1.1 riastrad /** 190 1.1 riastrad * vmw_cmdbuf_res_add - Stage a command buffer managed resource for addition. 191 1.1 riastrad * 192 1.1 riastrad * @man: Pointer to the command buffer resource manager. 193 1.1 riastrad * @res_type: The resource type. 194 1.1 riastrad * @user_key: The user-space id of the resource. 195 1.1 riastrad * @res: Valid (refcount != 0) pointer to a struct vmw_resource. 196 1.1 riastrad * @list: The staging list. 197 1.1 riastrad * 198 1.1 riastrad * This function allocates a struct vmw_cmdbuf_res entry and adds the 199 1.1 riastrad * resource to the hash table of the manager identified by @man. The 200 1.1 riastrad * entry is then put on the staging list identified by @list. 201 1.1 riastrad */ 202 1.1 riastrad int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man, 203 1.1 riastrad enum vmw_cmdbuf_res_type res_type, 204 1.1 riastrad u32 user_key, 205 1.1 riastrad struct vmw_resource *res, 206 1.1 riastrad struct list_head *list) 207 1.1 riastrad { 208 1.1 riastrad struct vmw_cmdbuf_res *cres; 209 1.1 riastrad int ret; 210 1.1 riastrad 211 1.1 riastrad cres = kzalloc(sizeof(*cres), GFP_KERNEL); 212 1.3 riastrad if (unlikely(!cres)) 213 1.1 riastrad return -ENOMEM; 214 1.1 riastrad 215 1.1 riastrad cres->hash.key = user_key | (res_type << 24); 216 1.1 riastrad ret = drm_ht_insert_item(&man->resources, &cres->hash); 217 1.3 riastrad if (unlikely(ret != 0)) { 218 1.3 riastrad kfree(cres); 219 1.1 riastrad goto out_invalid_key; 220 1.3 riastrad } 221 1.1 riastrad 222 1.1 riastrad cres->state = VMW_CMDBUF_RES_ADD; 223 1.1 riastrad cres->res = vmw_resource_reference(res); 224 1.1 riastrad cres->man = man; 225 1.1 riastrad list_add_tail(&cres->head, list); 226 1.1 riastrad 227 1.1 riastrad out_invalid_key: 228 1.1 riastrad return ret; 229 1.1 riastrad } 230 1.1 riastrad 231 1.1 riastrad /** 232 1.1 riastrad * vmw_cmdbuf_res_remove - Stage a command buffer managed resource for removal. 233 1.1 riastrad * 234 1.1 riastrad * @man: Pointer to the command buffer resource manager. 235 1.1 riastrad * @res_type: The resource type. 236 1.1 riastrad * @user_key: The user-space id of the resource. 237 1.1 riastrad * @list: The staging list. 238 1.1 riastrad * @res_p: If the resource is in an already committed state, points to the 239 1.1 riastrad * struct vmw_resource on successful return. The pointer will be 240 1.1 riastrad * non ref-counted. 241 1.1 riastrad * 242 1.1 riastrad * This function looks up the struct vmw_cmdbuf_res entry from the manager 243 1.1 riastrad * hash table and, if it exists, removes it. Depending on its current staging 244 1.1 riastrad * state it then either removes the entry from the staging list or adds it 245 1.1 riastrad * to it with a staging state of removal. 246 1.1 riastrad */ 247 1.1 riastrad int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man, 248 1.1 riastrad enum vmw_cmdbuf_res_type res_type, 249 1.1 riastrad u32 user_key, 250 1.1 riastrad struct list_head *list, 251 1.1 riastrad struct vmw_resource **res_p) 252 1.1 riastrad { 253 1.1 riastrad struct vmw_cmdbuf_res *entry; 254 1.1 riastrad struct drm_hash_item *hash; 255 1.1 riastrad int ret; 256 1.1 riastrad 257 1.1 riastrad ret = drm_ht_find_item(&man->resources, user_key | (res_type << 24), 258 1.1 riastrad &hash); 259 1.1 riastrad if (likely(ret != 0)) 260 1.1 riastrad return -EINVAL; 261 1.1 riastrad 262 1.1 riastrad entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash); 263 1.1 riastrad 264 1.1 riastrad switch (entry->state) { 265 1.1 riastrad case VMW_CMDBUF_RES_ADD: 266 1.1 riastrad vmw_cmdbuf_res_free(man, entry); 267 1.1 riastrad *res_p = NULL; 268 1.1 riastrad break; 269 1.1 riastrad case VMW_CMDBUF_RES_COMMITTED: 270 1.1 riastrad (void) drm_ht_remove_item(&man->resources, &entry->hash); 271 1.1 riastrad list_del(&entry->head); 272 1.1 riastrad entry->state = VMW_CMDBUF_RES_DEL; 273 1.1 riastrad list_add_tail(&entry->head, list); 274 1.1 riastrad *res_p = entry->res; 275 1.1 riastrad break; 276 1.1 riastrad default: 277 1.1 riastrad BUG(); 278 1.1 riastrad break; 279 1.1 riastrad } 280 1.1 riastrad 281 1.1 riastrad return 0; 282 1.1 riastrad } 283 1.1 riastrad 284 1.1 riastrad /** 285 1.1 riastrad * vmw_cmdbuf_res_man_create - Allocate a command buffer managed resource 286 1.1 riastrad * manager. 287 1.1 riastrad * 288 1.1 riastrad * @dev_priv: Pointer to a struct vmw_private 289 1.1 riastrad * 290 1.1 riastrad * Allocates and initializes a command buffer managed resource manager. Returns 291 1.1 riastrad * an error pointer on failure. 292 1.1 riastrad */ 293 1.1 riastrad struct vmw_cmdbuf_res_manager * 294 1.1 riastrad vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv) 295 1.1 riastrad { 296 1.1 riastrad struct vmw_cmdbuf_res_manager *man; 297 1.1 riastrad int ret; 298 1.1 riastrad 299 1.1 riastrad man = kzalloc(sizeof(*man), GFP_KERNEL); 300 1.3 riastrad if (!man) 301 1.1 riastrad return ERR_PTR(-ENOMEM); 302 1.1 riastrad 303 1.1 riastrad man->dev_priv = dev_priv; 304 1.1 riastrad INIT_LIST_HEAD(&man->list); 305 1.1 riastrad ret = drm_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER); 306 1.1 riastrad if (ret == 0) 307 1.1 riastrad return man; 308 1.1 riastrad 309 1.1 riastrad kfree(man); 310 1.1 riastrad return ERR_PTR(ret); 311 1.1 riastrad } 312 1.1 riastrad 313 1.1 riastrad /** 314 1.1 riastrad * vmw_cmdbuf_res_man_destroy - Destroy a command buffer managed resource 315 1.1 riastrad * manager. 316 1.1 riastrad * 317 1.1 riastrad * @man: Pointer to the manager to destroy. 318 1.1 riastrad * 319 1.1 riastrad * This function destroys a command buffer managed resource manager and 320 1.1 riastrad * unreferences / frees all command buffer managed resources and -entries 321 1.1 riastrad * associated with it. 322 1.1 riastrad */ 323 1.1 riastrad void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man) 324 1.1 riastrad { 325 1.1 riastrad struct vmw_cmdbuf_res *entry, *next; 326 1.1 riastrad 327 1.1 riastrad list_for_each_entry_safe(entry, next, &man->list, head) 328 1.1 riastrad vmw_cmdbuf_res_free(man, entry); 329 1.1 riastrad 330 1.1 riastrad drm_ht_remove(&man->resources); 331 1.1 riastrad kfree(man); 332 1.1 riastrad } 333 1.1 riastrad 334 1.1 riastrad /** 335 1.1 riastrad * 336 1.1 riastrad * vmw_cmdbuf_res_man_size - Return the size of a command buffer managed 337 1.1 riastrad * resource manager 338 1.1 riastrad * 339 1.1 riastrad * Returns the approximate allocation size of a command buffer managed 340 1.1 riastrad * resource manager. 341 1.1 riastrad */ 342 1.1 riastrad size_t vmw_cmdbuf_res_man_size(void) 343 1.1 riastrad { 344 1.1 riastrad static size_t res_man_size; 345 1.1 riastrad 346 1.1 riastrad if (unlikely(res_man_size == 0)) 347 1.1 riastrad res_man_size = 348 1.1 riastrad ttm_round_pot(sizeof(struct vmw_cmdbuf_res_manager)) + 349 1.1 riastrad ttm_round_pot(sizeof(struct hlist_head) << 350 1.1 riastrad VMW_CMDBUF_RES_MAN_HT_ORDER); 351 1.1 riastrad 352 1.1 riastrad return res_man_size; 353 1.1 riastrad } 354