File Index
Files and directories
Sign in
FILE

ioctl.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c C
  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#include <core/ioctl.h>
 25#include <core/client.h>
 26#include <core/engine.h>
 27#include <core/event.h>
 28
 29#include <nvif/unpack.h>
 30#include <nvif/ioctl.h>
 31
 32static int
 33nvkm_ioctl_nop(struct nvkm_client *client,
 34	       struct nvkm_object *object, void *data, u32 size)
 35{
 36	return -ENOSYS;
 37}
 38
 39#include <nvif/class.h>
 40
 41static int
 42nvkm_ioctl_sclass_(struct nvkm_object *object, int index, struct nvkm_oclass *oclass)
 43{
 44	if ( object->func->uevent &&
 45	    !object->func->uevent(object, NULL, 0, NULL) && index-- == 0) {
 46		oclass->ctor = nvkm_uevent_new;
 47		oclass->base.minver = 0;
 48		oclass->base.maxver = 0;
 49		oclass->base.oclass = NVIF_CLASS_EVENT;
 50		return 0;
 51	}
 52
 53	if (object->func->sclass)
 54		return object->func->sclass(object, index, oclass);
 55
 56	return -ENOSYS;
 57}
 58
 59static int
 60nvkm_ioctl_sclass(struct nvkm_client *client,
 61		  struct nvkm_object *object, void *data, u32 size)
 62{
 63	union {
 64		struct nvif_ioctl_sclass_v0 v0;
 65	} *args = data;
 66	struct nvkm_oclass oclass = { .client = client };
 67	int ret = -ENOSYS, i = 0;
 68
 69	nvif_ioctl(object, "sclass size %d\n", size);
 70	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
 71		nvif_ioctl(object, "sclass vers %d count %d\n",
 72			   args->v0.version, args->v0.count);
 73		if (size != args->v0.count * sizeof(args->v0.oclass[0]))
 74			return -EINVAL;
 75
 76		while (nvkm_ioctl_sclass_(object, i, &oclass) >= 0) {
 77			if (i < args->v0.count) {
 78				args->v0.oclass[i].oclass = oclass.base.oclass;
 79				args->v0.oclass[i].minver = oclass.base.minver;
 80				args->v0.oclass[i].maxver = oclass.base.maxver;
 81			}
 82			i++;
 83		}
 84
 85		args->v0.count = i;
 86	}
 87
 88	return ret;
 89}
 90
 91static int
 92nvkm_ioctl_new(struct nvkm_client *client,
 93	       struct nvkm_object *parent, void *data, u32 size)
 94{
 95	union {
 96		struct nvif_ioctl_new_v0 v0;
 97	} *args = data;
 98	struct nvkm_object *object = NULL;
 99	struct nvkm_oclass oclass;
100	int ret = -ENOSYS, i = 0;
101
102	nvif_ioctl(parent, "new size %d\n", size);
103	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
104		nvif_ioctl(parent, "new vers %d handle %08x class %08x object %016llx\n",
105			   args->v0.version, args->v0.handle, args->v0.oclass,
106			   args->v0.object);
107	} else
108		return ret;
109
110	if (!parent->func->sclass && !parent->func->uevent) {
111		nvif_ioctl(parent, "cannot have children\n");
112		return -EINVAL;
113	}
114
115	do {
116		memset(&oclass, 0x00, sizeof(oclass));
117		oclass.handle = args->v0.handle;
118		oclass.object = args->v0.object;
119		oclass.client = client;
120		oclass.parent = parent;
121		ret = nvkm_ioctl_sclass_(parent, i++, &oclass);
122		if (ret)
123			return ret;
124	} while (oclass.base.oclass != args->v0.oclass);
125
126	if (oclass.engine) {
127		oclass.engine = nvkm_engine_ref(oclass.engine);
128		if (IS_ERR(oclass.engine))
129			return PTR_ERR(oclass.engine);
130	}
131
132	ret = oclass.ctor(&oclass, data, size, &object);
133	nvkm_engine_unref(&oclass.engine);
134	if (ret == 0) {
135		ret = nvkm_object_init(object);
136		if (ret == 0) {
137			list_add_tail(&object->head, &parent->tree);
138			if (nvkm_object_insert(object)) {
139				client->data = object;
140				return 0;
141			}
142			ret = -EEXIST;
143		}
144		nvkm_object_fini(object, NVKM_POWEROFF);
145	}
146
147	nvkm_object_del(&object);
148	return ret;
149}
150
151static int
152nvkm_ioctl_del(struct nvkm_client *client,
153	       struct nvkm_object *object, void *data, u32 size)
154{
155	union {
156		struct nvif_ioctl_del none;
157	} *args = data;
158	int ret = -ENOSYS;
159
160	nvif_ioctl(object, "delete size %d\n", size);
161	if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
162		nvif_ioctl(object, "delete\n");
163		nvkm_object_fini(object, NVKM_POWEROFF);
164		nvkm_object_del(&object);
165	}
166
167	return ret ? ret : 1;
168}
169
170static int
171nvkm_ioctl_mthd(struct nvkm_client *client,
172		struct nvkm_object *object, void *data, u32 size)
173{
174	union {
175		struct nvif_ioctl_mthd_v0 v0;
176	} *args = data;
177	int ret = -ENOSYS;
178
179	nvif_ioctl(object, "mthd size %d\n", size);
180	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
181		nvif_ioctl(object, "mthd vers %d mthd %02x\n",
182			   args->v0.version, args->v0.method);
183		ret = nvkm_object_mthd(object, args->v0.method, data, size);
184	}
185
186	return ret;
187}
188
189
190static int
191nvkm_ioctl_rd(struct nvkm_client *client,
192	      struct nvkm_object *object, void *data, u32 size)
193{
194	return -ENOSYS;
195}
196
197static int
198nvkm_ioctl_wr(struct nvkm_client *client,
199	      struct nvkm_object *object, void *data, u32 size)
200{
201	return -ENOSYS;
202}
203
204static int
205nvkm_ioctl_map(struct nvkm_client *client,
206	       struct nvkm_object *object, void *data, u32 size)
207{
208	union {
209		struct nvif_ioctl_map_v0 v0;
210	} *args = data;
211	enum nvkm_object_map type;
212	int ret = -ENOSYS;
213
214	nvif_ioctl(object, "map size %d\n", size);
215	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
216		nvif_ioctl(object, "map vers %d\n", args->v0.version);
217		ret = nvkm_object_map(object, data, size, &type,
218				      &args->v0.handle,
219				      &args->v0.length);
220		if (type == NVKM_OBJECT_MAP_IO)
221			args->v0.type = NVIF_IOCTL_MAP_V0_IO;
222		else
223			args->v0.type = NVIF_IOCTL_MAP_V0_VA;
224	}
225
226	return ret;
227}
228
229static int
230nvkm_ioctl_unmap(struct nvkm_client *client,
231		 struct nvkm_object *object, void *data, u32 size)
232{
233	union {
234		struct nvif_ioctl_unmap none;
235	} *args = data;
236	int ret = -ENOSYS;
237
238	nvif_ioctl(object, "unmap size %d\n", size);
239	if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
240		nvif_ioctl(object, "unmap\n");
241		ret = nvkm_object_unmap(object);
242	}
243
244	return ret;
245}
246
247static struct {
248	int version;
249	int (*func)(struct nvkm_client *, struct nvkm_object *, void *, u32);
250}
251nvkm_ioctl_v0[] = {
252	{ 0x00, nvkm_ioctl_nop },
253	{ 0x00, nvkm_ioctl_sclass },
254	{ 0x00, nvkm_ioctl_new },
255	{ 0x00, nvkm_ioctl_del },
256	{ 0x00, nvkm_ioctl_mthd },
257	{ 0x00, nvkm_ioctl_rd },
258	{ 0x00, nvkm_ioctl_wr },
259	{ 0x00, nvkm_ioctl_map },
260	{ 0x00, nvkm_ioctl_unmap },
261};
262
263static int
264nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type,
265		void *data, u32 size)
266{
267	struct nvkm_object *object;
268	int ret;
269
270	object = nvkm_object_search(client, handle, NULL);
271	if (IS_ERR(object)) {
272		nvif_ioctl(&client->object, "object not found\n");
273		return PTR_ERR(object);
274	}
275
276	if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
277		if (nvkm_ioctl_v0[type].version == 0)
278			ret = nvkm_ioctl_v0[type].func(client, object, data, size);
279	}
280
281	return ret;
282}
283
284int
285nvkm_ioctl(struct nvkm_client *client, void *data, u32 size, void **hack)
286{
287	struct nvkm_object *object = &client->object;
288	union {
289		struct nvif_ioctl_v0 v0;
290	} *args = data;
291	int ret = -ENOSYS;
292
293	nvif_ioctl(object, "size %d\n", size);
294
295	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
296		nvif_ioctl(object,
297			   "vers %d type %02x object %016llx owner %02x\n",
298			   args->v0.version, args->v0.type, args->v0.object,
299			   args->v0.owner);
300		ret = nvkm_ioctl_path(client, args->v0.object, args->v0.type,
301				      data, size);
302	}
303
304	if (ret != 1) {
305		nvif_ioctl(object, "return %d\n", ret);
306		if (hack) {
307			*hack = client->data;
308			client->data = NULL;
309		}
310	}
311
312	return ret;
313}
~/ Read-only file preview.