1 /* $NetBSD: vmwgfx_gmrid_manager.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $ */ 2 3 // SPDX-License-Identifier: GPL-2.0 OR MIT 4 /************************************************************************** 5 * 6 * Copyright 2007-2010 VMware, Inc., Palo Alto, CA., USA 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sub license, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial portions 18 * of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 24 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 26 * USE OR OTHER DEALINGS IN THE SOFTWARE. 27 * 28 **************************************************************************/ 29 /* 30 * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: vmwgfx_gmrid_manager.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $"); 35 36 #include "vmwgfx_drv.h" 37 #include <drm/ttm/ttm_module.h> 38 #include <drm/ttm/ttm_bo_driver.h> 39 #include <drm/ttm/ttm_placement.h> 40 #include <linux/idr.h> 41 #include <linux/spinlock.h> 42 #include <linux/kernel.h> 43 44 struct vmwgfx_gmrid_man { 45 spinlock_t lock; 46 struct ida gmr_ida; 47 uint32_t max_gmr_ids; 48 uint32_t max_gmr_pages; 49 uint32_t used_gmr_pages; 50 }; 51 52 static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man, 53 struct ttm_buffer_object *bo, 54 const struct ttm_place *place, 55 struct ttm_mem_reg *mem) 56 { 57 struct vmwgfx_gmrid_man *gman = 58 (struct vmwgfx_gmrid_man *)man->priv; 59 int id; 60 61 mem->mm_node = NULL; 62 63 id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); 64 if (id < 0) 65 return (id != -ENOMEM ? 0 : id); 66 67 spin_lock(&gman->lock); 68 69 if (gman->max_gmr_pages > 0) { 70 gman->used_gmr_pages += bo->num_pages; 71 if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages)) 72 goto nospace; 73 } 74 75 mem->mm_node = gman; 76 mem->start = id; 77 mem->num_pages = bo->num_pages; 78 79 spin_unlock(&gman->lock); 80 return 0; 81 82 nospace: 83 gman->used_gmr_pages -= bo->num_pages; 84 spin_unlock(&gman->lock); 85 ida_free(&gman->gmr_ida, id); 86 return 0; 87 } 88 89 static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, 90 struct ttm_mem_reg *mem) 91 { 92 struct vmwgfx_gmrid_man *gman = 93 (struct vmwgfx_gmrid_man *)man->priv; 94 95 if (mem->mm_node) { 96 ida_free(&gman->gmr_ida, mem->start); 97 spin_lock(&gman->lock); 98 gman->used_gmr_pages -= mem->num_pages; 99 spin_unlock(&gman->lock); 100 mem->mm_node = NULL; 101 } 102 } 103 104 static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man, 105 unsigned long p_size) 106 { 107 struct vmw_private *dev_priv = 108 container_of(man->bdev, struct vmw_private, bdev); 109 struct vmwgfx_gmrid_man *gman = 110 kzalloc(sizeof(*gman), GFP_KERNEL); 111 112 if (unlikely(!gman)) 113 return -ENOMEM; 114 115 spin_lock_init(&gman->lock); 116 gman->used_gmr_pages = 0; 117 ida_init(&gman->gmr_ida); 118 119 switch (p_size) { 120 case VMW_PL_GMR: 121 gman->max_gmr_ids = dev_priv->max_gmr_ids; 122 gman->max_gmr_pages = dev_priv->max_gmr_pages; 123 break; 124 case VMW_PL_MOB: 125 gman->max_gmr_ids = VMWGFX_NUM_MOB; 126 gman->max_gmr_pages = dev_priv->max_mob_pages; 127 break; 128 default: 129 BUG(); 130 } 131 man->priv = (void *) gman; 132 return 0; 133 } 134 135 static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man) 136 { 137 struct vmwgfx_gmrid_man *gman = 138 (struct vmwgfx_gmrid_man *)man->priv; 139 140 if (gman) { 141 ida_destroy(&gman->gmr_ida); 142 kfree(gman); 143 } 144 return 0; 145 } 146 147 static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man, 148 struct drm_printer *printer) 149 { 150 drm_printf(printer, "No debug info available for the GMR id manager\n"); 151 } 152 153 const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = { 154 .init = vmw_gmrid_man_init, 155 .takedown = vmw_gmrid_man_takedown, 156 .get_node = vmw_gmrid_man_get_node, 157 .put_node = vmw_gmrid_man_put_node, 158 .debug = vmw_gmrid_man_debug 159 }; 160