1 /* $NetBSD: nouveau_nvif_object.c,v 1.8 2021/12/19 11:07:35 riastradh Exp $ */
2
3 /*
4 * Copyright 2014 Red Hat Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: Ben Skeggs <bskeggs@redhat.com>
25 */
26
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvif_object.c,v 1.8 2021/12/19 11:07:35 riastradh Exp $");
29
30 #include <nvif/object.h>
31 #include <nvif/client.h>
32 #include <nvif/driver.h>
33 #include <nvif/ioctl.h>
34
35 int
nvif_object_ioctl(struct nvif_object * object,void * data,u32 size,void ** hack)36 nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
37 {
38 struct nvif_client *client = object->client;
39 union {
40 struct nvif_ioctl_v0 v0;
41 } *args = data;
42
43 if (size >= sizeof(*args) && args->v0.version == 0) {
44 if (object != &client->object)
45 args->v0.object = nvif_handle(object);
46 else
47 args->v0.object = 0;
48 args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
49 } else
50 return -ENOSYS;
51
52 return client->driver->ioctl(client->object.priv, client->super,
53 data, size, hack);
54 }
55
56 void
nvif_object_sclass_put(struct nvif_sclass ** psclass)57 nvif_object_sclass_put(struct nvif_sclass **psclass)
58 {
59 kfree(*psclass);
60 *psclass = NULL;
61 }
62
63 int
nvif_object_sclass_get(struct nvif_object * object,struct nvif_sclass ** psclass)64 nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass)
65 {
66 struct {
67 struct nvif_ioctl_v0 ioctl;
68 struct nvif_ioctl_sclass_v0 sclass;
69 } *args = NULL;
70 int ret, cnt = 0, i;
71 u32 size;
72
73 while (1) {
74 size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
75 if (!(args = kmalloc(size, GFP_KERNEL)))
76 return -ENOMEM;
77 args->ioctl.version = 0;
78 args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
79 args->sclass.version = 0;
80 args->sclass.count = cnt;
81
82 ret = nvif_object_ioctl(object, args, size, NULL);
83 if (ret == 0 && args->sclass.count <= cnt)
84 break;
85 cnt = args->sclass.count;
86 kfree(args);
87 if (ret != 0)
88 return ret;
89 }
90
91 *psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL);
92 if (*psclass) {
93 for (i = 0; i < args->sclass.count; i++) {
94 (*psclass)[i].oclass = args->sclass.oclass[i].oclass;
95 (*psclass)[i].minver = args->sclass.oclass[i].minver;
96 (*psclass)[i].maxver = args->sclass.oclass[i].maxver;
97 }
98 ret = args->sclass.count;
99 } else {
100 ret = -ENOMEM;
101 }
102
103 kfree(args);
104 return ret;
105 }
106
107 u32
nvif_object_rd(struct nvif_object * object,int size,u64 addr)108 nvif_object_rd(struct nvif_object *object, int size, u64 addr)
109 {
110 struct {
111 struct nvif_ioctl_v0 ioctl;
112 struct nvif_ioctl_rd_v0 rd;
113 } args = {
114 .ioctl.type = NVIF_IOCTL_V0_RD,
115 .rd.size = size,
116 .rd.addr = addr,
117 };
118 int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
119 if (ret) {
120 /*XXX: warn? */
121 return 0;
122 }
123 return args.rd.data;
124 }
125
126 void
nvif_object_wr(struct nvif_object * object,int size,u64 addr,u32 data)127 nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data)
128 {
129 struct {
130 struct nvif_ioctl_v0 ioctl;
131 struct nvif_ioctl_wr_v0 wr;
132 } args = {
133 .ioctl.type = NVIF_IOCTL_V0_WR,
134 .wr.size = size,
135 .wr.addr = addr,
136 .wr.data = data,
137 };
138 int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
139 if (ret) {
140 /*XXX: warn? */
141 }
142 }
143
144 int
nvif_object_mthd(struct nvif_object * object,u32 mthd,void * data,u32 size)145 nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
146 {
147 struct {
148 struct nvif_ioctl_v0 ioctl;
149 struct nvif_ioctl_mthd_v0 mthd;
150 } *args;
151 u8 stack[128];
152 int ret;
153
154 if (sizeof(*args) + size > sizeof(stack)) {
155 if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
156 return -ENOMEM;
157 } else {
158 args = (void *)stack;
159 }
160 args->ioctl.version = 0;
161 args->ioctl.type = NVIF_IOCTL_V0_MTHD;
162 args->mthd.version = 0;
163 args->mthd.method = mthd;
164
165 memcpy(args->mthd.data, data, size);
166 ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
167 memcpy(data, args->mthd.data, size);
168 if (args != (void *)stack)
169 kfree(args);
170 return ret;
171 }
172
173 void
nvif_object_unmap_handle(struct nvif_object * object)174 nvif_object_unmap_handle(struct nvif_object *object)
175 {
176 struct {
177 struct nvif_ioctl_v0 ioctl;
178 struct nvif_ioctl_unmap unmap;
179 } args = {
180 .ioctl.type = NVIF_IOCTL_V0_UNMAP,
181 };
182
183 nvif_object_ioctl(object, &args, sizeof(args), NULL);
184 }
185
186 int
nvif_object_map_handle(struct nvif_object * object,void * argv,u32 argc,bus_space_tag_t * tag,u64 * handle,u64 * length)187 nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc,
188 #ifdef __NetBSD__
189 bus_space_tag_t *tag,
190 #endif
191 u64 *handle, u64 *length)
192 {
193 struct {
194 struct nvif_ioctl_v0 ioctl;
195 #ifdef __NetBSD__
196 struct nvif_ioctl_map_netbsd_v0 map;
197 #else
198 struct nvif_ioctl_map_v0 map;
199 #endif
200 } *args;
201 u32 argn = sizeof(*args) + argc;
202 int ret, maptype;
203
204 if (!(args = kzalloc(argn, GFP_KERNEL)))
205 return -ENOMEM;
206 #ifdef __NetBSD__
207 args->ioctl.type = NVIF_IOCTL_V0_MAP_NETBSD;
208 #else
209 args->ioctl.type = NVIF_IOCTL_V0_MAP;
210 #endif
211 memcpy(args->map.data, argv, argc);
212
213 ret = nvif_object_ioctl(object, args, argn, NULL);
214 #ifdef __NetBSD__
215 if (tag)
216 *tag = args->map.tag;
217 #endif
218 *handle = args->map.handle;
219 *length = args->map.length;
220 maptype = args->map.type;
221 kfree(args);
222 return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO);
223 }
224
225 void
nvif_object_unmap(struct nvif_object * object)226 nvif_object_unmap(struct nvif_object *object)
227 {
228 struct nvif_client *client = object->client;
229 if (object->map.ptr) {
230 if (object->map.size) {
231 #ifdef __NetBSD__
232 client->driver->unmap(client, object->map.tag,
233 object->map.handle,
234 object->map.addr,
235 object->map.ptr,
236 object->map.size);
237 #else
238 client->driver->unmap(client, object->map.ptr,
239 object->map.size);
240 #endif
241 object->map.size = 0;
242 }
243 object->map.ptr = NULL;
244 nvif_object_unmap_handle(object);
245 }
246 }
247
248 int
nvif_object_map(struct nvif_object * object,void * argv,u32 argc)249 nvif_object_map(struct nvif_object *object, void *argv, u32 argc)
250 {
251 struct nvif_client *client = object->client;
252 u64 handle, length;
253 #ifdef __NetBSD__
254 bus_space_tag_t tag;
255 int ret = nvif_object_map_handle(object, argv, argc, &tag, &handle, &length);
256 #else
257 int ret = nvif_object_map_handle(object, argv, argc, &handle, &length);
258 #endif
259 if (ret >= 0) {
260 if (ret) {
261 #ifdef __NetBSD__
262 /*
263 * Note: handle is the bus address;
264 * object->map.handle is the
265 * bus_space_handle_t, which is typically a
266 * virtual address mapped in kva.
267 */
268 object->map.tag = tag;
269 object->map.addr = handle;
270 ret = client->driver->map(client, tag, handle, length,
271 &object->map.handle, &object->map.ptr);
272 if (ret == 0) {
273 object->map.size = length;
274 return 0;
275 }
276 #else
277 object->map.ptr = client->driver->map(client,
278 handle,
279 length);
280 if (ret = -ENOMEM, object->map.ptr) {
281 object->map.size = length;
282 return 0;
283 }
284 #endif
285 } else {
286 object->map.ptr = (void *)(unsigned long)handle;
287 return 0;
288 }
289 nvif_object_unmap_handle(object);
290 }
291 return ret;
292 }
293
294 void
nvif_object_fini(struct nvif_object * object)295 nvif_object_fini(struct nvif_object *object)
296 {
297 struct {
298 struct nvif_ioctl_v0 ioctl;
299 struct nvif_ioctl_del del;
300 } args = {
301 .ioctl.type = NVIF_IOCTL_V0_DEL,
302 };
303
304 if (!object->client)
305 return;
306
307 nvif_object_unmap(object);
308 nvif_object_ioctl(object, &args, sizeof(args), NULL);
309 object->client = NULL;
310 }
311
312 int
nvif_object_init(struct nvif_object * parent,u32 handle,s32 oclass,void * data,u32 size,struct nvif_object * object)313 nvif_object_init(struct nvif_object *parent, u32 handle, s32 oclass,
314 void *data, u32 size, struct nvif_object *object)
315 {
316 struct {
317 struct nvif_ioctl_v0 ioctl;
318 struct nvif_ioctl_new_v0 new;
319 } *args;
320 int ret = 0;
321
322 object->client = NULL;
323 object->handle = handle;
324 object->oclass = oclass;
325 object->map.ptr = NULL;
326 object->map.size = 0;
327
328 if (parent) {
329 if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) {
330 nvif_object_fini(object);
331 return -ENOMEM;
332 }
333
334 args->ioctl.version = 0;
335 args->ioctl.type = NVIF_IOCTL_V0_NEW;
336 args->new.version = 0;
337 args->new.route = parent->client->route;
338 args->new.token = nvif_handle(object);
339 args->new.object = nvif_handle(object);
340 args->new.handle = handle;
341 args->new.oclass = oclass;
342
343 memcpy(args->new.data, data, size);
344 ret = nvif_object_ioctl(parent, args, sizeof(*args) + size,
345 &object->priv);
346 memcpy(data, args->new.data, size);
347 kfree(args);
348 if (ret == 0)
349 object->client = parent->client;
350 }
351
352 if (ret)
353 nvif_object_fini(object);
354 return ret;
355 }
356