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