1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include "vmwgfx_drv.h"
32#include <drm/ttm/ttm_bo_driver.h>
33#include <drm/ttm/ttm_placement.h>
34#include <linux/idr.h>
35#include <linux/spinlock.h>
36#include <linux/kernel.h>
37
38struct vmwgfx_gmrid_man {
39 struct ttm_resource_manager manager;
40 spinlock_t lock;
41 struct ida gmr_ida;
42 uint32_t max_gmr_ids;
43 uint32_t max_gmr_pages;
44 uint32_t used_gmr_pages;
45};
46
47static struct vmwgfx_gmrid_man *to_gmrid_manager(struct ttm_resource_manager *man)
48{
49 return container_of(man, struct vmwgfx_gmrid_man, manager);
50}
51
52static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man,
53 struct ttm_buffer_object *bo,
54 const struct ttm_place *place,
55 struct ttm_resource **res)
56{
57 struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
58 int id;
59
60 *res = kmalloc(sizeof(**res), GFP_KERNEL);
61 if (!*res)
62 return -ENOMEM;
63
64 ttm_resource_init(bo, place, *res);
65
66 id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL);
67 if (id < 0)
68 return id;
69
70 spin_lock(&gman->lock);
71
72 if (gman->max_gmr_pages > 0) {
73 gman->used_gmr_pages += (*res)->num_pages;
74
75
76
77
78
79
80
81 if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages)) {
82 const unsigned long max_graphics_pages = totalram_pages() / 2;
83 uint32_t new_max_pages = 0;
84
85 DRM_WARN("vmwgfx: mob memory overflow. Consider increasing guest RAM and graphicsMemory.\n");
86 vmw_host_printf("vmwgfx, warning: mob memory overflow. Consider increasing guest RAM and graphicsMemory.\n");
87
88 if (gman->max_gmr_pages > (max_graphics_pages / 2)) {
89 DRM_WARN("vmwgfx: guest requires more than half of RAM for graphics.\n");
90 new_max_pages = max_graphics_pages;
91 } else
92 new_max_pages = gman->max_gmr_pages * 2;
93 if (new_max_pages > gman->max_gmr_pages && new_max_pages >= gman->used_gmr_pages) {
94 DRM_WARN("vmwgfx: increasing guest mob limits to %u kB.\n",
95 ((new_max_pages) << (PAGE_SHIFT - 10)));
96
97 gman->max_gmr_pages = new_max_pages;
98 } else {
99 char buf[256];
100 snprintf(buf, sizeof(buf),
101 "vmwgfx, error: guest graphics is out of memory (mob limit at: %ukB).\n",
102 ((gman->max_gmr_pages) << (PAGE_SHIFT - 10)));
103 vmw_host_printf(buf);
104 DRM_WARN("%s", buf);
105 goto nospace;
106 }
107 }
108 }
109
110 (*res)->start = id;
111
112 spin_unlock(&gman->lock);
113 return 0;
114
115nospace:
116 gman->used_gmr_pages -= (*res)->num_pages;
117 spin_unlock(&gman->lock);
118 ida_free(&gman->gmr_ida, id);
119 kfree(*res);
120 return -ENOSPC;
121}
122
123static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man,
124 struct ttm_resource *res)
125{
126 struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
127
128 ida_free(&gman->gmr_ida, res->start);
129 spin_lock(&gman->lock);
130 gman->used_gmr_pages -= res->num_pages;
131 spin_unlock(&gman->lock);
132 kfree(res);
133}
134
135static const struct ttm_resource_manager_func vmw_gmrid_manager_func;
136
137int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type)
138{
139 struct ttm_resource_manager *man;
140 struct vmwgfx_gmrid_man *gman =
141 kzalloc(sizeof(*gman), GFP_KERNEL);
142
143 if (unlikely(!gman))
144 return -ENOMEM;
145
146 man = &gman->manager;
147
148 man->func = &vmw_gmrid_manager_func;
149
150 man->use_tt = true;
151 ttm_resource_manager_init(man, 0);
152 spin_lock_init(&gman->lock);
153 gman->used_gmr_pages = 0;
154 ida_init(&gman->gmr_ida);
155
156 switch (type) {
157 case VMW_PL_GMR:
158 gman->max_gmr_ids = dev_priv->max_gmr_ids;
159 gman->max_gmr_pages = dev_priv->max_gmr_pages;
160 break;
161 case VMW_PL_MOB:
162 gman->max_gmr_ids = VMWGFX_NUM_MOB;
163 gman->max_gmr_pages = dev_priv->max_mob_pages;
164 break;
165 default:
166 BUG();
167 }
168 ttm_set_driver_manager(&dev_priv->bdev, type, &gman->manager);
169 ttm_resource_manager_set_used(man, true);
170 return 0;
171}
172
173void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type)
174{
175 struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, type);
176 struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
177
178 ttm_resource_manager_set_used(man, false);
179
180 ttm_resource_manager_evict_all(&dev_priv->bdev, man);
181
182 ttm_resource_manager_cleanup(man);
183
184 ttm_set_driver_manager(&dev_priv->bdev, type, NULL);
185 ida_destroy(&gman->gmr_ida);
186 kfree(gman);
187
188}
189
190static const struct ttm_resource_manager_func vmw_gmrid_manager_func = {
191 .alloc = vmw_gmrid_man_get_node,
192 .free = vmw_gmrid_man_put_node,
193};
194