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