xref: /linux/drivers/gpu/drm/nouveau/nvif/object.c (revision 06a130e42a5bfc84795464bff023bff4c16f58c5)
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 	} else
44 		return -ENOSYS;
45 
46 	return client->driver->ioctl(client->object.priv, data, size, hack);
47 }
48 
49 void
50 nvif_object_sclass_put(struct nvif_sclass **psclass)
51 {
52 	kfree(*psclass);
53 	*psclass = NULL;
54 }
55 
56 int
57 nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass)
58 {
59 	struct {
60 		struct nvif_ioctl_v0 ioctl;
61 		struct nvif_ioctl_sclass_v0 sclass;
62 	} *args = NULL;
63 	int ret, cnt = 0, i;
64 	u32 size;
65 
66 	while (1) {
67 		size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
68 		if (!(args = kmalloc(size, GFP_KERNEL)))
69 			return -ENOMEM;
70 		args->ioctl.version = 0;
71 		args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
72 		args->sclass.version = 0;
73 		args->sclass.count = cnt;
74 
75 		ret = nvif_object_ioctl(object, args, size, NULL);
76 		if (ret == 0 && args->sclass.count <= cnt)
77 			break;
78 		cnt = args->sclass.count;
79 		kfree(args);
80 		if (ret != 0)
81 			return ret;
82 	}
83 
84 	*psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL);
85 	if (*psclass) {
86 		for (i = 0; i < args->sclass.count; i++) {
87 			(*psclass)[i].oclass = args->sclass.oclass[i].oclass;
88 			(*psclass)[i].minver = args->sclass.oclass[i].minver;
89 			(*psclass)[i].maxver = args->sclass.oclass[i].maxver;
90 		}
91 		ret = args->sclass.count;
92 	} else {
93 		ret = -ENOMEM;
94 	}
95 
96 	kfree(args);
97 	return ret;
98 }
99 
100 int
101 nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
102 {
103 	struct {
104 		struct nvif_ioctl_v0 ioctl;
105 		struct nvif_ioctl_mthd_v0 mthd;
106 	} *args;
107 	u32 args_size;
108 	u8 stack[128];
109 	int ret;
110 
111 	if (check_add_overflow(sizeof(*args), size, &args_size))
112 		return -ENOMEM;
113 
114 	if (args_size > sizeof(stack)) {
115 		args = kmalloc(args_size, GFP_KERNEL);
116 		if (!args)
117 			return -ENOMEM;
118 	} else {
119 		args = (void *)stack;
120 	}
121 	args->ioctl.version = 0;
122 	args->ioctl.type = NVIF_IOCTL_V0_MTHD;
123 	args->mthd.version = 0;
124 	args->mthd.method = mthd;
125 
126 	memcpy(args->mthd.data, data, size);
127 	ret = nvif_object_ioctl(object, args, args_size, NULL);
128 	memcpy(data, args->mthd.data, size);
129 	if (args != (void *)stack)
130 		kfree(args);
131 	return ret;
132 }
133 
134 void
135 nvif_object_unmap_handle(struct nvif_object *object)
136 {
137 	struct {
138 		struct nvif_ioctl_v0 ioctl;
139 		struct nvif_ioctl_unmap unmap;
140 	} args = {
141 		.ioctl.type = NVIF_IOCTL_V0_UNMAP,
142 	};
143 
144 	nvif_object_ioctl(object, &args, sizeof(args), NULL);
145 }
146 
147 int
148 nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc,
149 		       u64 *handle, u64 *length)
150 {
151 	struct {
152 		struct nvif_ioctl_v0 ioctl;
153 		struct nvif_ioctl_map_v0 map;
154 	} *args;
155 	u32 argn = sizeof(*args) + argc;
156 	int ret, maptype;
157 
158 	if (!(args = kzalloc(argn, GFP_KERNEL)))
159 		return -ENOMEM;
160 	args->ioctl.type = NVIF_IOCTL_V0_MAP;
161 	memcpy(args->map.data, argv, argc);
162 
163 	ret = nvif_object_ioctl(object, args, argn, NULL);
164 	*handle = args->map.handle;
165 	*length = args->map.length;
166 	maptype = args->map.type;
167 	kfree(args);
168 	return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO);
169 }
170 
171 void
172 nvif_object_unmap(struct nvif_object *object)
173 {
174 	struct nvif_client *client = object->client;
175 	if (object->map.ptr) {
176 		if (object->map.size) {
177 			client->driver->unmap(client, object->map.ptr,
178 						      object->map.size);
179 			object->map.size = 0;
180 		}
181 		object->map.ptr = NULL;
182 		nvif_object_unmap_handle(object);
183 	}
184 }
185 
186 int
187 nvif_object_map(struct nvif_object *object, void *argv, u32 argc)
188 {
189 	struct nvif_client *client = object->client;
190 	u64 handle, length;
191 	int ret = nvif_object_map_handle(object, argv, argc, &handle, &length);
192 	if (ret >= 0) {
193 		if (ret) {
194 			object->map.ptr = client->driver->map(client,
195 							      handle,
196 							      length);
197 			if (ret = -ENOMEM, object->map.ptr) {
198 				object->map.size = length;
199 				return 0;
200 			}
201 		} else {
202 			object->map.ptr = (void *)(unsigned long)handle;
203 			return 0;
204 		}
205 		nvif_object_unmap_handle(object);
206 	}
207 	return ret;
208 }
209 
210 void
211 nvif_object_dtor(struct nvif_object *object)
212 {
213 	struct {
214 		struct nvif_ioctl_v0 ioctl;
215 		struct nvif_ioctl_del del;
216 	} args = {
217 		.ioctl.type = NVIF_IOCTL_V0_DEL,
218 	};
219 
220 	if (!nvif_object_constructed(object))
221 		return;
222 
223 	nvif_object_unmap(object);
224 	nvif_object_ioctl(object, &args, sizeof(args), NULL);
225 	object->client = NULL;
226 }
227 
228 int
229 nvif_object_ctor(struct nvif_object *parent, const char *name, u32 handle,
230 		 s32 oclass, void *data, u32 size, struct nvif_object *object)
231 {
232 	struct {
233 		struct nvif_ioctl_v0 ioctl;
234 		struct nvif_ioctl_new_v0 new;
235 	} *args;
236 	int ret = 0;
237 
238 	object->client = NULL;
239 	object->name = name ? name : "nvifObject";
240 	object->handle = handle;
241 	object->oclass = oclass;
242 	object->map.ptr = NULL;
243 	object->map.size = 0;
244 
245 	if (parent) {
246 		u32 args_size;
247 
248 		if (check_add_overflow(sizeof(*args), size, &args_size)) {
249 			nvif_object_dtor(object);
250 			return -ENOMEM;
251 		}
252 
253 		args = kmalloc(args_size, GFP_KERNEL);
254 		if (!args) {
255 			nvif_object_dtor(object);
256 			return -ENOMEM;
257 		}
258 
259 		object->parent = parent->parent;
260 
261 		args->ioctl.version = 0;
262 		args->ioctl.type = NVIF_IOCTL_V0_NEW;
263 		args->new.version = 0;
264 		args->new.object = nvif_handle(object);
265 		args->new.handle = handle;
266 		args->new.oclass = oclass;
267 
268 		memcpy(args->new.data, data, size);
269 		ret = nvif_object_ioctl(parent, args, args_size, &object->priv);
270 		memcpy(data, args->new.data, size);
271 		kfree(args);
272 		if (ret == 0)
273 			object->client = parent->client;
274 	}
275 
276 	if (ret)
277 		nvif_object_dtor(object);
278 	return ret;
279 }
280