xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/vmwgfx/vmwgfx_gmrid_manager.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
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 
vmw_gmrid_man_get_node(struct ttm_mem_type_manager * man,struct ttm_buffer_object * bo,const struct ttm_place * place,struct ttm_mem_reg * mem)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 
vmw_gmrid_man_put_node(struct ttm_mem_type_manager * man,struct ttm_mem_reg * mem)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 
vmw_gmrid_man_init(struct ttm_mem_type_manager * man,unsigned long p_size)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 
vmw_gmrid_man_takedown(struct ttm_mem_type_manager * man)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 
vmw_gmrid_man_debug(struct ttm_mem_type_manager * man,struct drm_printer * printer)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