xref: /linux/drivers/gpu/drm/nouveau/nouveau_abi16.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
12a259a3dSBen Skeggs /*
22a259a3dSBen Skeggs  * Copyright 2012 Red Hat Inc.
32a259a3dSBen Skeggs  *
42a259a3dSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
52a259a3dSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
62a259a3dSBen Skeggs  * to deal in the Software without restriction, including without limitation
72a259a3dSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
82a259a3dSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
92a259a3dSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
102a259a3dSBen Skeggs  *
112a259a3dSBen Skeggs  * The above copyright notice and this permission notice shall be included in
122a259a3dSBen Skeggs  * all copies or substantial portions of the Software.
132a259a3dSBen Skeggs  *
142a259a3dSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
152a259a3dSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
162a259a3dSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
172a259a3dSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
182a259a3dSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
192a259a3dSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
202a259a3dSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
212a259a3dSBen Skeggs  *
222a259a3dSBen Skeggs  */
232a259a3dSBen Skeggs 
24a4e610b5SBen Skeggs #include <nvif/client.h>
25a4e610b5SBen Skeggs #include <nvif/driver.h>
26a7cf0180SBen Skeggs #include <nvif/fifo.h>
27a4e610b5SBen Skeggs #include <nvif/ioctl.h>
28fdb751efSBen Skeggs #include <nvif/class.h>
29845f2725SBen Skeggs #include <nvif/cl0002.h>
302621a416SBen Skeggs #include <nvif/unpack.h>
312a259a3dSBen Skeggs 
324dc28134SBen Skeggs #include "nouveau_drv.h"
332a259a3dSBen Skeggs #include "nouveau_dma.h"
34d59e75eeSDanilo Krummrich #include "nouveau_exec.h"
35ebb945a9SBen Skeggs #include "nouveau_gem.h"
36ebb945a9SBen Skeggs #include "nouveau_chan.h"
372a259a3dSBen Skeggs #include "nouveau_abi16.h"
3824e8375bSBen Skeggs #include "nouveau_vmm.h"
39b88baab8SDanilo Krummrich #include "nouveau_sched.h"
40ebb945a9SBen Skeggs 
41786a57efSBen Skeggs static struct nouveau_abi16 *
nouveau_abi16(struct drm_file * file_priv)42786a57efSBen Skeggs nouveau_abi16(struct drm_file *file_priv)
43ebb945a9SBen Skeggs {
44ebb945a9SBen Skeggs 	struct nouveau_cli *cli = nouveau_cli(file_priv);
45ebb945a9SBen Skeggs 	if (!cli->abi16) {
46ebb945a9SBen Skeggs 		struct nouveau_abi16 *abi16;
47ebb945a9SBen Skeggs 		cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
48ebb945a9SBen Skeggs 		if (cli->abi16) {
492e408ad7SBen Skeggs 			abi16->cli = cli;
50ebb945a9SBen Skeggs 			INIT_LIST_HEAD(&abi16->channels);
51ba6b8479SBen Skeggs 			INIT_LIST_HEAD(&abi16->objects);
52ebb945a9SBen Skeggs 		}
53ebb945a9SBen Skeggs 	}
54ebb945a9SBen Skeggs 	return cli->abi16;
55ebb945a9SBen Skeggs }
56ebb945a9SBen Skeggs 
57786a57efSBen Skeggs struct nouveau_abi16 *
nouveau_abi16_get(struct drm_file * file_priv)58786a57efSBen Skeggs nouveau_abi16_get(struct drm_file *file_priv)
59786a57efSBen Skeggs {
60786a57efSBen Skeggs 	struct nouveau_cli *cli = nouveau_cli(file_priv);
61786a57efSBen Skeggs 	mutex_lock(&cli->mutex);
62786a57efSBen Skeggs 	if (nouveau_abi16(file_priv))
63786a57efSBen Skeggs 		return cli->abi16;
64786a57efSBen Skeggs 	mutex_unlock(&cli->mutex);
65786a57efSBen Skeggs 	return NULL;
66786a57efSBen Skeggs }
67786a57efSBen Skeggs 
68ebb945a9SBen Skeggs int
nouveau_abi16_put(struct nouveau_abi16 * abi16,int ret)69ebb945a9SBen Skeggs nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret)
70ebb945a9SBen Skeggs {
712e408ad7SBen Skeggs 	struct nouveau_cli *cli = abi16->cli;
72ebb945a9SBen Skeggs 	mutex_unlock(&cli->mutex);
73ebb945a9SBen Skeggs 	return ret;
74ebb945a9SBen Skeggs }
75ebb945a9SBen Skeggs 
76ba6b8479SBen Skeggs /* Tracks objects created via the DRM_NOUVEAU_NVIF ioctl.
77ba6b8479SBen Skeggs  *
78ba6b8479SBen Skeggs  * The only two types of object that userspace ever allocated via this
79ba6b8479SBen Skeggs  * interface are 'device', in order to retrieve basic device info, and
80ba6b8479SBen Skeggs  * 'engine objects', which instantiate HW classes on a channel.
81ba6b8479SBen Skeggs  *
82ba6b8479SBen Skeggs  * The remainder of what used to be available via DRM_NOUVEAU_NVIF has
83ba6b8479SBen Skeggs  * been removed, but these object types need to be tracked to maintain
84ba6b8479SBen Skeggs  * compatibility with userspace.
85ba6b8479SBen Skeggs  */
86ba6b8479SBen Skeggs struct nouveau_abi16_obj {
87ba6b8479SBen Skeggs 	enum nouveau_abi16_obj_type {
88ba6b8479SBen Skeggs 		DEVICE,
89ba6b8479SBen Skeggs 		ENGOBJ,
90ba6b8479SBen Skeggs 	} type;
91ba6b8479SBen Skeggs 	u64 object;
92ba6b8479SBen Skeggs 
93ba6b8479SBen Skeggs 	struct nvif_object engobj;
94ba6b8479SBen Skeggs 
95ba6b8479SBen Skeggs 	struct list_head head; /* protected by nouveau_abi16.cli.mutex */
96ba6b8479SBen Skeggs };
97ba6b8479SBen Skeggs 
98ba6b8479SBen Skeggs static struct nouveau_abi16_obj *
nouveau_abi16_obj_find(struct nouveau_abi16 * abi16,u64 object)99ba6b8479SBen Skeggs nouveau_abi16_obj_find(struct nouveau_abi16 *abi16, u64 object)
100ba6b8479SBen Skeggs {
101ba6b8479SBen Skeggs 	struct nouveau_abi16_obj *obj;
102ba6b8479SBen Skeggs 
103ba6b8479SBen Skeggs 	list_for_each_entry(obj, &abi16->objects, head) {
104ba6b8479SBen Skeggs 		if (obj->object == object)
105ba6b8479SBen Skeggs 			return obj;
106ba6b8479SBen Skeggs 	}
107ba6b8479SBen Skeggs 
108ba6b8479SBen Skeggs 	return NULL;
109ba6b8479SBen Skeggs }
110ba6b8479SBen Skeggs 
111ba6b8479SBen Skeggs static void
nouveau_abi16_obj_del(struct nouveau_abi16_obj * obj)112ba6b8479SBen Skeggs nouveau_abi16_obj_del(struct nouveau_abi16_obj *obj)
113ba6b8479SBen Skeggs {
114ba6b8479SBen Skeggs 	list_del(&obj->head);
115ba6b8479SBen Skeggs 	kfree(obj);
116ba6b8479SBen Skeggs }
117ba6b8479SBen Skeggs 
118ba6b8479SBen Skeggs static struct nouveau_abi16_obj *
nouveau_abi16_obj_new(struct nouveau_abi16 * abi16,enum nouveau_abi16_obj_type type,u64 object)119ba6b8479SBen Skeggs nouveau_abi16_obj_new(struct nouveau_abi16 *abi16, enum nouveau_abi16_obj_type type, u64 object)
120ba6b8479SBen Skeggs {
121ba6b8479SBen Skeggs 	struct nouveau_abi16_obj *obj;
122ba6b8479SBen Skeggs 
123ba6b8479SBen Skeggs 	obj = nouveau_abi16_obj_find(abi16, object);
124ba6b8479SBen Skeggs 	if (obj)
125ba6b8479SBen Skeggs 		return ERR_PTR(-EEXIST);
126ba6b8479SBen Skeggs 
127ba6b8479SBen Skeggs 	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
128ba6b8479SBen Skeggs 	if (!obj)
129ba6b8479SBen Skeggs 		return ERR_PTR(-ENOMEM);
130ba6b8479SBen Skeggs 
131ba6b8479SBen Skeggs 	obj->type = type;
132ba6b8479SBen Skeggs 	obj->object = object;
133ba6b8479SBen Skeggs 	list_add_tail(&obj->head, &abi16->objects);
134ba6b8479SBen Skeggs 	return obj;
135ba6b8479SBen Skeggs }
136ba6b8479SBen Skeggs 
137f58ddf95SBen Skeggs s32
nouveau_abi16_swclass(struct nouveau_drm * drm)138ebb945a9SBen Skeggs nouveau_abi16_swclass(struct nouveau_drm *drm)
139ebb945a9SBen Skeggs {
1401167c6bcSBen Skeggs 	switch (drm->client.device.info.family) {
141967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_TNT:
14208f7633cSBen Skeggs 		return NVIF_CLASS_SW_NV04;
143967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_CELSIUS:
144967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_KELVIN:
145967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_RANKINE:
146967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_CURIE:
14708f7633cSBen Skeggs 		return NVIF_CLASS_SW_NV10;
148967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_TESLA:
14908f7633cSBen Skeggs 		return NVIF_CLASS_SW_NV50;
150967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_FERMI:
151967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_KEPLER:
152967e7bdeSBen Skeggs 	case NV_DEVICE_INFO_V0_MAXWELL:
1537f53abdbSBen Skeggs 	case NV_DEVICE_INFO_V0_PASCAL:
154c1f856bbSBen Skeggs 	case NV_DEVICE_INFO_V0_VOLTA:
15508f7633cSBen Skeggs 		return NVIF_CLASS_SW_GF100;
156ebb945a9SBen Skeggs 	}
157ebb945a9SBen Skeggs 
158ebb945a9SBen Skeggs 	return 0x0000;
159ebb945a9SBen Skeggs }
160ebb945a9SBen Skeggs 
161ebb945a9SBen Skeggs static void
nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan * chan,struct nouveau_abi16_ntfy * ntfy)162ebb945a9SBen Skeggs nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
163ebb945a9SBen Skeggs 			struct nouveau_abi16_ntfy *ntfy)
164ebb945a9SBen Skeggs {
1659ac596a4SBen Skeggs 	nvif_object_dtor(&ntfy->object);
166be83cd4eSBen Skeggs 	nvkm_mm_free(&chan->heap, &ntfy->node);
167ebb945a9SBen Skeggs 	list_del(&ntfy->head);
168ebb945a9SBen Skeggs 	kfree(ntfy);
169ebb945a9SBen Skeggs }
170ebb945a9SBen Skeggs 
171ebb945a9SBen Skeggs static void
nouveau_abi16_chan_fini(struct nouveau_abi16 * abi16,struct nouveau_abi16_chan * chan)172ebb945a9SBen Skeggs nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
173ebb945a9SBen Skeggs 			struct nouveau_abi16_chan *chan)
174ebb945a9SBen Skeggs {
175ebb945a9SBen Skeggs 	struct nouveau_abi16_ntfy *ntfy, *temp;
176ebb945a9SBen Skeggs 
1775f03a507SDanilo Krummrich 	/* Cancel all jobs from the entity's queue. */
1789a0c32d6SDanilo Krummrich 	if (chan->sched)
1799a0c32d6SDanilo Krummrich 		drm_sched_entity_fini(&chan->sched->entity);
180b88baab8SDanilo Krummrich 
1817ba01b50SBen Skeggs 	if (chan->chan)
1822b77c1c0SMarcin Slusarz 		nouveau_channel_idle(chan->chan);
1832b77c1c0SMarcin Slusarz 
1849a0c32d6SDanilo Krummrich 	if (chan->sched)
1859a0c32d6SDanilo Krummrich 		nouveau_sched_destroy(&chan->sched);
1865f03a507SDanilo Krummrich 
187ebb945a9SBen Skeggs 	/* cleanup notifier state */
188ebb945a9SBen Skeggs 	list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
189ebb945a9SBen Skeggs 		nouveau_abi16_ntfy_fini(chan, ntfy);
190ebb945a9SBen Skeggs 	}
191ebb945a9SBen Skeggs 
192ebb945a9SBen Skeggs 	if (chan->ntfy) {
19324e8375bSBen Skeggs 		nouveau_vma_del(&chan->ntfy_vma);
194198c14a0SMaarten Lankhorst 		nouveau_bo_unpin(chan->ntfy);
195cdc194ceSEmil Velikov 		drm_gem_object_put(&chan->ntfy->bo.base);
196ebb945a9SBen Skeggs 	}
197ebb945a9SBen Skeggs 
198ebb945a9SBen Skeggs 	if (chan->heap.block_size)
199be83cd4eSBen Skeggs 		nvkm_mm_fini(&chan->heap);
200ebb945a9SBen Skeggs 
201ebb945a9SBen Skeggs 	/* destroy channel object, all children will be killed too */
202ebb945a9SBen Skeggs 	if (chan->chan) {
20340184eceSBen Skeggs 		nvif_object_dtor(&chan->ce);
204ebb945a9SBen Skeggs 		nouveau_channel_del(&chan->chan);
205ebb945a9SBen Skeggs 	}
206ebb945a9SBen Skeggs 
207ebb945a9SBen Skeggs 	list_del(&chan->head);
208ebb945a9SBen Skeggs 	kfree(chan);
209ebb945a9SBen Skeggs }
210ebb945a9SBen Skeggs 
211ebb945a9SBen Skeggs void
nouveau_abi16_fini(struct nouveau_abi16 * abi16)212ebb945a9SBen Skeggs nouveau_abi16_fini(struct nouveau_abi16 *abi16)
213ebb945a9SBen Skeggs {
2142e408ad7SBen Skeggs 	struct nouveau_cli *cli = abi16->cli;
215ebb945a9SBen Skeggs 	struct nouveau_abi16_chan *chan, *temp;
216ba6b8479SBen Skeggs 	struct nouveau_abi16_obj *obj, *tmp;
217ba6b8479SBen Skeggs 
218ba6b8479SBen Skeggs 	/* cleanup objects */
219ba6b8479SBen Skeggs 	list_for_each_entry_safe(obj, tmp, &abi16->objects, head) {
220ba6b8479SBen Skeggs 		nouveau_abi16_obj_del(obj);
221ba6b8479SBen Skeggs 	}
222ebb945a9SBen Skeggs 
223ebb945a9SBen Skeggs 	/* cleanup channels */
224ebb945a9SBen Skeggs 	list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
225ebb945a9SBen Skeggs 		nouveau_abi16_chan_fini(abi16, chan);
226ebb945a9SBen Skeggs 	}
227ebb945a9SBen Skeggs 
228ebb945a9SBen Skeggs 	kfree(cli->abi16);
229ebb945a9SBen Skeggs 	cli->abi16 = NULL;
230ebb945a9SBen Skeggs }
2312a259a3dSBen Skeggs 
232d59e75eeSDanilo Krummrich static inline int
getparam_dma_ib_max(struct nvif_device * device)233d59e75eeSDanilo Krummrich getparam_dma_ib_max(struct nvif_device *device)
234d59e75eeSDanilo Krummrich {
235d59e75eeSDanilo Krummrich 	const struct nvif_mclass dmas[] = {
236d59e75eeSDanilo Krummrich 		{ NV03_CHANNEL_DMA, 0 },
237d59e75eeSDanilo Krummrich 		{ NV10_CHANNEL_DMA, 0 },
238d59e75eeSDanilo Krummrich 		{ NV17_CHANNEL_DMA, 0 },
239d59e75eeSDanilo Krummrich 		{ NV40_CHANNEL_DMA, 0 },
240d59e75eeSDanilo Krummrich 		{}
241d59e75eeSDanilo Krummrich 	};
242d59e75eeSDanilo Krummrich 
243d59e75eeSDanilo Krummrich 	return nvif_mclass(&device->object, dmas) < 0 ? NV50_DMA_IB_MAX : 0;
244d59e75eeSDanilo Krummrich }
245d59e75eeSDanilo Krummrich 
2462a259a3dSBen Skeggs int
nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)2472a259a3dSBen Skeggs nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
2482a259a3dSBen Skeggs {
249fa2bade9SBen Skeggs 	struct nouveau_cli *cli = nouveau_cli(file_priv);
250ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_drm(dev);
2511167c6bcSBen Skeggs 	struct nvif_device *device = &drm->client.device;
2526901f1d6SBen Skeggs 	struct nvkm_device *nvkm_device = nvxx_device(drm);
2536901f1d6SBen Skeggs 	struct nvkm_gr *gr = nvxx_gr(drm);
2542a259a3dSBen Skeggs 	struct drm_nouveau_getparam *getparam = data;
2554c0d42f7SThomas Zimmermann 	struct pci_dev *pdev = to_pci_dev(dev->dev);
2562a259a3dSBen Skeggs 
2572a259a3dSBen Skeggs 	switch (getparam->param) {
2582a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_CHIPSET_ID:
259967e7bdeSBen Skeggs 		getparam->value = device->info.chipset;
2602a259a3dSBen Skeggs 		break;
2612a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_PCI_VENDOR:
262359088d5SBen Skeggs 		if (device->info.platform != NV_DEVICE_INFO_V0_SOC)
2634c0d42f7SThomas Zimmermann 			getparam->value = pdev->vendor;
264420b9469SAlexandre Courbot 		else
265420b9469SAlexandre Courbot 			getparam->value = 0;
2662a259a3dSBen Skeggs 		break;
2672a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_PCI_DEVICE:
268359088d5SBen Skeggs 		if (device->info.platform != NV_DEVICE_INFO_V0_SOC)
2694c0d42f7SThomas Zimmermann 			getparam->value = pdev->device;
270420b9469SAlexandre Courbot 		else
271420b9469SAlexandre Courbot 			getparam->value = 0;
2722a259a3dSBen Skeggs 		break;
2732a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_BUS_TYPE:
274359088d5SBen Skeggs 		switch (device->info.platform) {
275359088d5SBen Skeggs 		case NV_DEVICE_INFO_V0_AGP : getparam->value = 0; break;
276359088d5SBen Skeggs 		case NV_DEVICE_INFO_V0_PCI : getparam->value = 1; break;
277359088d5SBen Skeggs 		case NV_DEVICE_INFO_V0_PCIE: getparam->value = 2; break;
278359088d5SBen Skeggs 		case NV_DEVICE_INFO_V0_SOC : getparam->value = 3; break;
279359088d5SBen Skeggs 		case NV_DEVICE_INFO_V0_IGP :
2804c0d42f7SThomas Zimmermann 			if (!pci_is_pcie(pdev))
2812a259a3dSBen Skeggs 				getparam->value = 1;
2822a259a3dSBen Skeggs 			else
2832a259a3dSBen Skeggs 				getparam->value = 2;
2842a259a3dSBen Skeggs 			break;
285359088d5SBen Skeggs 		default:
286359088d5SBen Skeggs 			WARN_ON(1);
287359088d5SBen Skeggs 			break;
288359088d5SBen Skeggs 		}
289785cf1eeSColin Ian King 		break;
2902a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_FB_SIZE:
291ebb945a9SBen Skeggs 		getparam->value = drm->gem.vram_available;
2922a259a3dSBen Skeggs 		break;
2932a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_AGP_SIZE:
294ebb945a9SBen Skeggs 		getparam->value = drm->gem.gart_available;
2952a259a3dSBen Skeggs 		break;
2962a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_VM_VRAM_BASE:
2972a259a3dSBen Skeggs 		getparam->value = 0; /* deprecated */
2982a259a3dSBen Skeggs 		break;
2992a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_PTIMER_TIME:
30056f67dc1SBen Skeggs 		getparam->value = nvif_device_time(device);
3012a259a3dSBen Skeggs 		break;
3022a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_HAS_BO_USAGE:
3032a259a3dSBen Skeggs 		getparam->value = 1;
3042a259a3dSBen Skeggs 		break;
3052a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
3062a259a3dSBen Skeggs 		getparam->value = 1;
3072a259a3dSBen Skeggs 		break;
3082a259a3dSBen Skeggs 	case NOUVEAU_GETPARAM_GRAPH_UNITS:
309c85ee6caSBen Skeggs 		getparam->value = nvkm_gr_units(gr);
3102a259a3dSBen Skeggs 		break;
311d59e75eeSDanilo Krummrich 	case NOUVEAU_GETPARAM_EXEC_PUSH_MAX: {
312d59e75eeSDanilo Krummrich 		int ib_max = getparam_dma_ib_max(device);
313d59e75eeSDanilo Krummrich 
314d59e75eeSDanilo Krummrich 		getparam->value = nouveau_exec_push_max_from_ib_max(ib_max);
315d59e75eeSDanilo Krummrich 		break;
316d59e75eeSDanilo Krummrich 	}
3173f4d8aacSDave Airlie 	case NOUVEAU_GETPARAM_VRAM_BAR_SIZE:
3183f4d8aacSDave Airlie 		getparam->value = nvkm_device->func->resource_size(nvkm_device, 1);
3193f4d8aacSDave Airlie 		break;
32072fa02fdSDave Airlie 	case NOUVEAU_GETPARAM_VRAM_USED: {
32172fa02fdSDave Airlie 		struct ttm_resource_manager *vram_mgr = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM);
322f7916c47SDave Airlie 		getparam->value = (u64)ttm_resource_manager_usage(vram_mgr);
32372fa02fdSDave Airlie 		break;
32472fa02fdSDave Airlie 	}
325959314c4SMohamed Ahmed 	case NOUVEAU_GETPARAM_HAS_VMA_TILEMODE:
326959314c4SMohamed Ahmed 		getparam->value = 1;
327959314c4SMohamed Ahmed 		break;
3282a259a3dSBen Skeggs 	default:
3299ad97edeSBen Skeggs 		NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
3302a259a3dSBen Skeggs 		return -EINVAL;
3312a259a3dSBen Skeggs 	}
3322a259a3dSBen Skeggs 
3332a259a3dSBen Skeggs 	return 0;
3342a259a3dSBen Skeggs }
3352a259a3dSBen Skeggs 
3362a259a3dSBen Skeggs int
nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)3372a259a3dSBen Skeggs nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
3382a259a3dSBen Skeggs {
3392a259a3dSBen Skeggs 	struct drm_nouveau_channel_alloc *init = data;
340ebb945a9SBen Skeggs 	struct nouveau_cli *cli = nouveau_cli(file_priv);
341ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_drm(dev);
34209433f24SBen Skeggs 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
343ebb945a9SBen Skeggs 	struct nouveau_abi16_chan *chan;
344d075d99eSBen Skeggs 	struct nvif_device *device = &cli->device;
3456de12538SBen Skeggs 	u64 engine, runm;
3462a259a3dSBen Skeggs 	int ret;
3472a259a3dSBen Skeggs 
348ebb945a9SBen Skeggs 	if (unlikely(!abi16))
349ebb945a9SBen Skeggs 		return -ENOMEM;
350bf7e438bSMarcin Slusarz 
351bf7e438bSMarcin Slusarz 	if (!drm->channel)
352bf7e438bSMarcin Slusarz 		return nouveau_abi16_put(abi16, -ENODEV);
353bf7e438bSMarcin Slusarz 
354b88baab8SDanilo Krummrich 	/* If uvmm wasn't initialized until now disable it completely to prevent
355b88baab8SDanilo Krummrich 	 * userspace from mixing up UAPIs.
356b88baab8SDanilo Krummrich 	 *
357b88baab8SDanilo Krummrich 	 * The client lock is already acquired by nouveau_abi16_get().
358b88baab8SDanilo Krummrich 	 */
359b88baab8SDanilo Krummrich 	__nouveau_cli_disable_uvmm_noinit(cli);
360b88baab8SDanilo Krummrich 
3616de12538SBen Skeggs 	engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR;
362ebb945a9SBen Skeggs 
36349469800SBen Skeggs 	/* hack to allow channel engine type specification on kepler */
364967e7bdeSBen Skeggs 	if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
365a7cf0180SBen Skeggs 		if (init->fb_ctxdma_handle == ~0) {
366a7cf0180SBen Skeggs 			switch (init->tt_ctxdma_handle) {
367460be1d5SKarol Herbst 			case NOUVEAU_FIFO_ENGINE_GR:
368460be1d5SKarol Herbst 				engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR;
369460be1d5SKarol Herbst 				break;
370460be1d5SKarol Herbst 			case NOUVEAU_FIFO_ENGINE_VP:
371460be1d5SKarol Herbst 				engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSPDEC;
372460be1d5SKarol Herbst 				break;
373460be1d5SKarol Herbst 			case NOUVEAU_FIFO_ENGINE_PPP:
374460be1d5SKarol Herbst 				engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSPPP;
375460be1d5SKarol Herbst 				break;
376460be1d5SKarol Herbst 			case NOUVEAU_FIFO_ENGINE_BSP:
377460be1d5SKarol Herbst 				engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSVLD;
378460be1d5SKarol Herbst 				break;
379460be1d5SKarol Herbst 			case NOUVEAU_FIFO_ENGINE_CE:
380460be1d5SKarol Herbst 				engine = NV_DEVICE_HOST_RUNLIST_ENGINES_CE;
381460be1d5SKarol Herbst 				break;
382a7cf0180SBen Skeggs 			default:
383a7cf0180SBen Skeggs 				return nouveau_abi16_put(abi16, -ENOSYS);
384a7cf0180SBen Skeggs 			}
3856de12538SBen Skeggs 
3866de12538SBen Skeggs 			init->fb_ctxdma_handle = 0;
3876de12538SBen Skeggs 			init->tt_ctxdma_handle = 0;
3886de12538SBen Skeggs 		}
3891f5ff7f5SBen Skeggs 	}
39049469800SBen Skeggs 
391f8fabd31SBen Skeggs 	if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_CE)
3926de12538SBen Skeggs 		runm = nvif_fifo_runlist(device, engine);
393a7cf0180SBen Skeggs 	else
3946de12538SBen Skeggs 		runm = nvif_fifo_runlist_ce(device);
39549469800SBen Skeggs 
3966de12538SBen Skeggs 	if (!runm || init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
39749469800SBen Skeggs 		return nouveau_abi16_put(abi16, -EINVAL);
39849469800SBen Skeggs 
399ebb945a9SBen Skeggs 	/* allocate "abi16 channel" data and make up a handle for it */
400ebb945a9SBen Skeggs 	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
401ebb945a9SBen Skeggs 	if (!chan)
402ebb945a9SBen Skeggs 		return nouveau_abi16_put(abi16, -ENOMEM);
403ebb945a9SBen Skeggs 
404ebb945a9SBen Skeggs 	INIT_LIST_HEAD(&chan->notifiers);
405ebb945a9SBen Skeggs 	list_add(&chan->head, &abi16->channels);
406ebb945a9SBen Skeggs 
407ebb945a9SBen Skeggs 	/* create channel object and initialise dma and fence management */
408*5cca41acSBen Skeggs 	ret = nouveau_channel_new(cli, false, runm, init->fb_ctxdma_handle,
4096de12538SBen Skeggs 				  init->tt_ctxdma_handle, &chan->chan);
4102a259a3dSBen Skeggs 	if (ret)
411ebb945a9SBen Skeggs 		goto done;
4122a259a3dSBen Skeggs 
413a1d8700dSDanilo Krummrich 	/* If we're not using the VM_BIND uAPI, we don't need a scheduler.
414a1d8700dSDanilo Krummrich 	 *
415a1d8700dSDanilo Krummrich 	 * The client lock is already acquired by nouveau_abi16_get().
416a1d8700dSDanilo Krummrich 	 */
417a1d8700dSDanilo Krummrich 	if (nouveau_cli_uvmm(cli)) {
4189a0c32d6SDanilo Krummrich 		ret = nouveau_sched_create(&chan->sched, drm, drm->sched_wq,
41946990918SDanilo Krummrich 					   chan->chan->dma.ib_max);
420b88baab8SDanilo Krummrich 		if (ret)
421b88baab8SDanilo Krummrich 			goto done;
422a1d8700dSDanilo Krummrich 	}
423b88baab8SDanilo Krummrich 
424fcf3f91cSBen Skeggs 	init->channel = chan->chan->chid;
425fcf3f91cSBen Skeggs 
426967e7bdeSBen Skeggs 	if (device->info.family >= NV_DEVICE_INFO_V0_TESLA)
4272a259a3dSBen Skeggs 		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
4282a259a3dSBen Skeggs 					NOUVEAU_GEM_DOMAIN_GART;
429ebb945a9SBen Skeggs 	else
430d3116756SChristian König 	if (chan->chan->push.buffer->bo.resource->mem_type == TTM_PL_VRAM)
4312a259a3dSBen Skeggs 		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
4322a259a3dSBen Skeggs 	else
4332a259a3dSBen Skeggs 		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
4342a259a3dSBen Skeggs 
435967e7bdeSBen Skeggs 	if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
4362a259a3dSBen Skeggs 		init->subchan[0].handle = 0x00000000;
4372a259a3dSBen Skeggs 		init->subchan[0].grclass = 0x0000;
438f45f55c4SBen Skeggs 		init->subchan[1].handle = chan->chan->nvsw.handle;
439ebb945a9SBen Skeggs 		init->subchan[1].grclass = 0x506e;
4402a259a3dSBen Skeggs 		init->nr_subchan = 2;
4412a259a3dSBen Skeggs 	}
4422a259a3dSBen Skeggs 
44340184eceSBen Skeggs 	/* Workaround "nvc0" gallium driver using classes it doesn't allocate on
44440184eceSBen Skeggs 	 * Kepler and above.  NVKM no longer always sets CE_CTX_VALID as part of
44540184eceSBen Skeggs 	 * channel init, now we know what that stuff actually is.
44640184eceSBen Skeggs 	 *
44740184eceSBen Skeggs 	 * Doesn't matter for Kepler/Pascal, CE context stored in NV_RAMIN.
44840184eceSBen Skeggs 	 *
44940184eceSBen Skeggs 	 * Userspace was fixed prior to adding Ampere support.
45040184eceSBen Skeggs 	 */
45140184eceSBen Skeggs 	switch (device->info.family) {
45240184eceSBen Skeggs 	case NV_DEVICE_INFO_V0_VOLTA:
45340184eceSBen Skeggs 		ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar", 0, VOLTA_DMA_COPY_A,
45440184eceSBen Skeggs 				       NULL, 0, &chan->ce);
45540184eceSBen Skeggs 		if (ret)
45640184eceSBen Skeggs 			goto done;
45740184eceSBen Skeggs 		break;
45840184eceSBen Skeggs 	case NV_DEVICE_INFO_V0_TURING:
45940184eceSBen Skeggs 		ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar", 0, TURING_DMA_COPY_A,
46040184eceSBen Skeggs 				       NULL, 0, &chan->ce);
46140184eceSBen Skeggs 		if (ret)
46240184eceSBen Skeggs 			goto done;
46340184eceSBen Skeggs 		break;
46440184eceSBen Skeggs 	default:
46540184eceSBen Skeggs 		break;
46640184eceSBen Skeggs 	}
46740184eceSBen Skeggs 
4682a259a3dSBen Skeggs 	/* Named memory object area */
469fc1b0a02SBen Skeggs 	ret = nouveau_gem_new(cli, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
470ebb945a9SBen Skeggs 			      0, 0, &chan->ntfy);
4712a259a3dSBen Skeggs 	if (ret == 0)
47281b61579SChristian König 		ret = nouveau_bo_pin(chan->ntfy, NOUVEAU_GEM_DOMAIN_GART,
47381b61579SChristian König 				     false);
474ebb945a9SBen Skeggs 	if (ret)
475ebb945a9SBen Skeggs 		goto done;
476ebb945a9SBen Skeggs 
477967e7bdeSBen Skeggs 	if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
478bfe91afaSBen Skeggs 		ret = nouveau_vma_new(chan->ntfy, chan->chan->vmm,
479bfe91afaSBen Skeggs 				      &chan->ntfy_vma);
480ebb945a9SBen Skeggs 		if (ret)
481ebb945a9SBen Skeggs 			goto done;
4822a259a3dSBen Skeggs 	}
4832a259a3dSBen Skeggs 
484f8659be8SGerd Hoffmann 	ret = drm_gem_handle_create(file_priv, &chan->ntfy->bo.base,
485ebb945a9SBen Skeggs 				    &init->notifier_handle);
486ebb945a9SBen Skeggs 	if (ret)
487ebb945a9SBen Skeggs 		goto done;
488ebb945a9SBen Skeggs 
4894d058fabSBen Skeggs 	ret = nvkm_mm_init(&chan->heap, 0, 0, PAGE_SIZE, 1);
490ebb945a9SBen Skeggs done:
491ebb945a9SBen Skeggs 	if (ret)
492ebb945a9SBen Skeggs 		nouveau_abi16_chan_fini(abi16, chan);
493ebb945a9SBen Skeggs 	return nouveau_abi16_put(abi16, ret);
494ebb945a9SBen Skeggs }
495ebb945a9SBen Skeggs 
496a4e610b5SBen Skeggs static struct nouveau_abi16_chan *
nouveau_abi16_chan(struct nouveau_abi16 * abi16,int channel)497a4e610b5SBen Skeggs nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel)
498a4e610b5SBen Skeggs {
499a4e610b5SBen Skeggs 	struct nouveau_abi16_chan *chan;
500a4e610b5SBen Skeggs 
501a4e610b5SBen Skeggs 	list_for_each_entry(chan, &abi16->channels, head) {
502fcf3f91cSBen Skeggs 		if (chan->chan->chid == channel)
503a4e610b5SBen Skeggs 			return chan;
504a4e610b5SBen Skeggs 	}
505a4e610b5SBen Skeggs 
506a4e610b5SBen Skeggs 	return NULL;
507a4e610b5SBen Skeggs }
508ebb945a9SBen Skeggs 
5092a259a3dSBen Skeggs int
nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)5102a259a3dSBen Skeggs nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
5112a259a3dSBen Skeggs {
5122a259a3dSBen Skeggs 	struct drm_nouveau_channel_free *req = data;
51309433f24SBen Skeggs 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
514ebb945a9SBen Skeggs 	struct nouveau_abi16_chan *chan;
5152a259a3dSBen Skeggs 
516ebb945a9SBen Skeggs 	if (unlikely(!abi16))
517ebb945a9SBen Skeggs 		return -ENOMEM;
5182a259a3dSBen Skeggs 
519a4e610b5SBen Skeggs 	chan = nouveau_abi16_chan(abi16, req->channel);
520a4e610b5SBen Skeggs 	if (!chan)
521a4e610b5SBen Skeggs 		return nouveau_abi16_put(abi16, -ENOENT);
522ebb945a9SBen Skeggs 	nouveau_abi16_chan_fini(abi16, chan);
523ebb945a9SBen Skeggs 	return nouveau_abi16_put(abi16, 0);
524ebb945a9SBen Skeggs }
5252a259a3dSBen Skeggs 
5262a259a3dSBen Skeggs int
nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)5272a259a3dSBen Skeggs nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
5282a259a3dSBen Skeggs {
5292a259a3dSBen Skeggs 	struct drm_nouveau_grobj_alloc *init = data;
53009433f24SBen Skeggs 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
531a01ca78cSBen Skeggs 	struct nouveau_abi16_chan *chan;
532a01ca78cSBen Skeggs 	struct nouveau_abi16_ntfy *ntfy;
53341a63406SBen Skeggs 	struct nvif_sclass *sclass;
534f58ddf95SBen Skeggs 	s32 oclass = 0;
535f58ddf95SBen Skeggs 	int ret, i;
5362a259a3dSBen Skeggs 
537ebb945a9SBen Skeggs 	if (unlikely(!abi16))
538ebb945a9SBen Skeggs 		return -ENOMEM;
539ebb945a9SBen Skeggs 
5402a259a3dSBen Skeggs 	if (init->handle == ~0)
541ebb945a9SBen Skeggs 		return nouveau_abi16_put(abi16, -EINVAL);
5422a259a3dSBen Skeggs 
543a01ca78cSBen Skeggs 	chan = nouveau_abi16_chan(abi16, init->channel);
544a01ca78cSBen Skeggs 	if (!chan)
545a01ca78cSBen Skeggs 		return nouveau_abi16_put(abi16, -ENOENT);
546a01ca78cSBen Skeggs 
54741a63406SBen Skeggs 	ret = nvif_object_sclass_get(&chan->chan->user, &sclass);
548f58ddf95SBen Skeggs 	if (ret < 0)
549f58ddf95SBen Skeggs 		return nouveau_abi16_put(abi16, ret);
550f58ddf95SBen Skeggs 
551f58ddf95SBen Skeggs 	if ((init->class & 0x00ff) == 0x006e) {
552f58ddf95SBen Skeggs 		/* nvsw: compatibility with older 0x*6e class identifier */
553f58ddf95SBen Skeggs 		for (i = 0; !oclass && i < ret; i++) {
55441a63406SBen Skeggs 			switch (sclass[i].oclass) {
55508f7633cSBen Skeggs 			case NVIF_CLASS_SW_NV04:
55608f7633cSBen Skeggs 			case NVIF_CLASS_SW_NV10:
55708f7633cSBen Skeggs 			case NVIF_CLASS_SW_NV50:
55808f7633cSBen Skeggs 			case NVIF_CLASS_SW_GF100:
55941a63406SBen Skeggs 				oclass = sclass[i].oclass;
560f58ddf95SBen Skeggs 				break;
561f58ddf95SBen Skeggs 			default:
562f58ddf95SBen Skeggs 				break;
563f58ddf95SBen Skeggs 			}
564f58ddf95SBen Skeggs 		}
565f58ddf95SBen Skeggs 	} else
566f58ddf95SBen Skeggs 	if ((init->class & 0x00ff) == 0x00b1) {
567f58ddf95SBen Skeggs 		/* msvld: compatibility with incorrect version exposure */
568f58ddf95SBen Skeggs 		for (i = 0; i < ret; i++) {
56941a63406SBen Skeggs 			if ((sclass[i].oclass & 0x00ff) == 0x00b1) {
57041a63406SBen Skeggs 				oclass = sclass[i].oclass;
571f58ddf95SBen Skeggs 				break;
572f58ddf95SBen Skeggs 			}
573f58ddf95SBen Skeggs 		}
574f58ddf95SBen Skeggs 	} else
575f58ddf95SBen Skeggs 	if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */
576f58ddf95SBen Skeggs 		/* mspdec: compatibility with incorrect version exposure */
577f58ddf95SBen Skeggs 		for (i = 0; i < ret; i++) {
57841a63406SBen Skeggs 			if ((sclass[i].oclass & 0x00ff) == 0x00b2) {
57941a63406SBen Skeggs 				oclass = sclass[i].oclass;
580f58ddf95SBen Skeggs 				break;
581f58ddf95SBen Skeggs 			}
582f58ddf95SBen Skeggs 		}
583f58ddf95SBen Skeggs 	} else
584f58ddf95SBen Skeggs 	if ((init->class & 0x00ff) == 0x00b3) { /* msppp */
585f58ddf95SBen Skeggs 		/* msppp: compatibility with incorrect version exposure */
586f58ddf95SBen Skeggs 		for (i = 0; i < ret; i++) {
58741a63406SBen Skeggs 			if ((sclass[i].oclass & 0x00ff) == 0x00b3) {
58841a63406SBen Skeggs 				oclass = sclass[i].oclass;
589f58ddf95SBen Skeggs 				break;
590f58ddf95SBen Skeggs 			}
591f58ddf95SBen Skeggs 		}
592f58ddf95SBen Skeggs 	} else {
593f58ddf95SBen Skeggs 		oclass = init->class;
594f58ddf95SBen Skeggs 	}
595f58ddf95SBen Skeggs 
59641a63406SBen Skeggs 	nvif_object_sclass_put(&sclass);
597f58ddf95SBen Skeggs 	if (!oclass)
598f58ddf95SBen Skeggs 		return nouveau_abi16_put(abi16, -EINVAL);
599f58ddf95SBen Skeggs 
600a01ca78cSBen Skeggs 	ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
601a01ca78cSBen Skeggs 	if (!ntfy)
602a01ca78cSBen Skeggs 		return nouveau_abi16_put(abi16, -ENOMEM);
603a01ca78cSBen Skeggs 
604a01ca78cSBen Skeggs 	list_add(&ntfy->head, &chan->notifiers);
605a01ca78cSBen Skeggs 
6069ac596a4SBen Skeggs 	ret = nvif_object_ctor(&chan->chan->user, "abi16EngObj", init->handle,
6079ac596a4SBen Skeggs 			       oclass, NULL, 0, &ntfy->object);
608a01ca78cSBen Skeggs 
609a01ca78cSBen Skeggs 	if (ret)
610a01ca78cSBen Skeggs 		nouveau_abi16_ntfy_fini(chan, ntfy);
611ebb945a9SBen Skeggs 	return nouveau_abi16_put(abi16, ret);
6122a259a3dSBen Skeggs }
6132a259a3dSBen Skeggs 
6142a259a3dSBen Skeggs int
nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)6152a259a3dSBen Skeggs nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
6162a259a3dSBen Skeggs {
617ebb945a9SBen Skeggs 	struct drm_nouveau_notifierobj_alloc *info = data;
618ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_drm(dev);
61909433f24SBen Skeggs 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
620a4e610b5SBen Skeggs 	struct nouveau_abi16_chan *chan;
621ebb945a9SBen Skeggs 	struct nouveau_abi16_ntfy *ntfy;
622d075d99eSBen Skeggs 	struct nvif_device *device;
623a01ca78cSBen Skeggs 	struct nv_dma_v0 args = {};
6242a259a3dSBen Skeggs 	int ret;
6252a259a3dSBen Skeggs 
626ebb945a9SBen Skeggs 	if (unlikely(!abi16))
627ebb945a9SBen Skeggs 		return -ENOMEM;
628d075d99eSBen Skeggs 	device = &abi16->cli->device;
629ebb945a9SBen Skeggs 
6302a259a3dSBen Skeggs 	/* completely unnecessary for these chipsets... */
631967e7bdeSBen Skeggs 	if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI))
632ebb945a9SBen Skeggs 		return nouveau_abi16_put(abi16, -EINVAL);
6332a259a3dSBen Skeggs 
634a4e610b5SBen Skeggs 	chan = nouveau_abi16_chan(abi16, info->channel);
635ebb945a9SBen Skeggs 	if (!chan)
636ebb945a9SBen Skeggs 		return nouveau_abi16_put(abi16, -ENOENT);
637ebb945a9SBen Skeggs 
638ebb945a9SBen Skeggs 	ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
639ebb945a9SBen Skeggs 	if (!ntfy)
640ebb945a9SBen Skeggs 		return nouveau_abi16_put(abi16, -ENOMEM);
641ebb945a9SBen Skeggs 
642ebb945a9SBen Skeggs 	list_add(&ntfy->head, &chan->notifiers);
643ebb945a9SBen Skeggs 
644be83cd4eSBen Skeggs 	ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
645ebb945a9SBen Skeggs 			   &ntfy->node);
646ebb945a9SBen Skeggs 	if (ret)
647ebb945a9SBen Skeggs 		goto done;
648ebb945a9SBen Skeggs 
649a01ca78cSBen Skeggs 	args.start = ntfy->node->offset;
650a01ca78cSBen Skeggs 	args.limit = ntfy->node->offset + ntfy->node->length - 1;
651967e7bdeSBen Skeggs 	if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
652a01ca78cSBen Skeggs 		args.target = NV_DMA_V0_TARGET_VM;
653a01ca78cSBen Skeggs 		args.access = NV_DMA_V0_ACCESS_VM;
65424e8375bSBen Skeggs 		args.start += chan->ntfy_vma->addr;
65524e8375bSBen Skeggs 		args.limit += chan->ntfy_vma->addr;
656ebb945a9SBen Skeggs 	} else
657340b0e7cSBen Skeggs 	if (drm->agp.bridge) {
658a01ca78cSBen Skeggs 		args.target = NV_DMA_V0_TARGET_AGP;
659a01ca78cSBen Skeggs 		args.access = NV_DMA_V0_ACCESS_RDWR;
6600dc9b286SNirmoy Das 		args.start += drm->agp.base + chan->ntfy->offset;
6610dc9b286SNirmoy Das 		args.limit += drm->agp.base + chan->ntfy->offset;
662ebb945a9SBen Skeggs 	} else {
663a01ca78cSBen Skeggs 		args.target = NV_DMA_V0_TARGET_VM;
664a01ca78cSBen Skeggs 		args.access = NV_DMA_V0_ACCESS_RDWR;
6650dc9b286SNirmoy Das 		args.start += chan->ntfy->offset;
6660dc9b286SNirmoy Das 		args.limit += chan->ntfy->offset;
667ebb945a9SBen Skeggs 	}
668ebb945a9SBen Skeggs 
6699ac596a4SBen Skeggs 	ret = nvif_object_ctor(&chan->chan->user, "abi16Ntfy", info->handle,
670a01ca78cSBen Skeggs 			       NV_DMA_IN_MEMORY, &args, sizeof(args),
671a01ca78cSBen Skeggs 			       &ntfy->object);
672ebb945a9SBen Skeggs 	if (ret)
673ebb945a9SBen Skeggs 		goto done;
674ebb945a9SBen Skeggs 
675c1ccaa64SBob Gleitsmann 	info->offset = ntfy->node->offset;
676ebb945a9SBen Skeggs done:
677ebb945a9SBen Skeggs 	if (ret)
678ebb945a9SBen Skeggs 		nouveau_abi16_ntfy_fini(chan, ntfy);
679ebb945a9SBen Skeggs 	return nouveau_abi16_put(abi16, ret);
6802a259a3dSBen Skeggs }
6812a259a3dSBen Skeggs 
6822a259a3dSBen Skeggs int
nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)6832a259a3dSBen Skeggs nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
6842a259a3dSBen Skeggs {
685ebb945a9SBen Skeggs 	struct drm_nouveau_gpuobj_free *fini = data;
68609433f24SBen Skeggs 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
687a4e610b5SBen Skeggs 	struct nouveau_abi16_chan *chan;
688ebb945a9SBen Skeggs 	struct nouveau_abi16_ntfy *ntfy;
689a01ca78cSBen Skeggs 	int ret = -ENOENT;
6902a259a3dSBen Skeggs 
691ebb945a9SBen Skeggs 	if (unlikely(!abi16))
692ebb945a9SBen Skeggs 		return -ENOMEM;
6932a259a3dSBen Skeggs 
694a4e610b5SBen Skeggs 	chan = nouveau_abi16_chan(abi16, fini->channel);
695ebb945a9SBen Skeggs 	if (!chan)
696a01ca78cSBen Skeggs 		return nouveau_abi16_put(abi16, -EINVAL);
697ebb945a9SBen Skeggs 
698ebb945a9SBen Skeggs 	/* synchronize with the user channel and destroy the gpu object */
699ebb945a9SBen Skeggs 	nouveau_channel_idle(chan->chan);
700ebb945a9SBen Skeggs 
701ebb945a9SBen Skeggs 	list_for_each_entry(ntfy, &chan->notifiers, head) {
702a01ca78cSBen Skeggs 		if (ntfy->object.handle == fini->handle) {
703a01ca78cSBen Skeggs 			nouveau_abi16_ntfy_fini(chan, ntfy);
704a01ca78cSBen Skeggs 			ret = 0;
705ebb945a9SBen Skeggs 			break;
706ebb945a9SBen Skeggs 		}
707ebb945a9SBen Skeggs 	}
708ebb945a9SBen Skeggs 
709a01ca78cSBen Skeggs 	return nouveau_abi16_put(abi16, ret);
7102a259a3dSBen Skeggs }
711ba6b8479SBen Skeggs 
712ba6b8479SBen Skeggs static int
nouveau_abi16_ioctl_mthd(struct nouveau_abi16 * abi16,struct nvif_ioctl_v0 * ioctl,u32 argc)713ba6b8479SBen Skeggs nouveau_abi16_ioctl_mthd(struct nouveau_abi16 *abi16, struct nvif_ioctl_v0 *ioctl, u32 argc)
714ba6b8479SBen Skeggs {
715ba6b8479SBen Skeggs 	struct nouveau_cli *cli = abi16->cli;
716ba6b8479SBen Skeggs 	struct nvif_ioctl_mthd_v0 *args;
717ba6b8479SBen Skeggs 	struct nouveau_abi16_obj *obj;
718ba6b8479SBen Skeggs 	struct nv_device_info_v0 *info;
719ba6b8479SBen Skeggs 
720ba6b8479SBen Skeggs 	if (ioctl->route || argc < sizeof(*args))
721ba6b8479SBen Skeggs 		return -EINVAL;
722ba6b8479SBen Skeggs 	args = (void *)ioctl->data;
723ba6b8479SBen Skeggs 	argc -= sizeof(*args);
724ba6b8479SBen Skeggs 
725ba6b8479SBen Skeggs 	obj = nouveau_abi16_obj_find(abi16, ioctl->object);
726ba6b8479SBen Skeggs 	if (!obj || obj->type != DEVICE)
727ba6b8479SBen Skeggs 		return -EINVAL;
728ba6b8479SBen Skeggs 
729ba6b8479SBen Skeggs 	if (args->method != NV_DEVICE_V0_INFO ||
730ba6b8479SBen Skeggs 	    argc != sizeof(*info))
731ba6b8479SBen Skeggs 		return -EINVAL;
732ba6b8479SBen Skeggs 
733ba6b8479SBen Skeggs 	info = (void *)args->data;
734ba6b8479SBen Skeggs 	if (info->version != 0x00)
735ba6b8479SBen Skeggs 		return -EINVAL;
736ba6b8479SBen Skeggs 
737ba6b8479SBen Skeggs 	info = &cli->device.info;
738ba6b8479SBen Skeggs 	memcpy(args->data, info, sizeof(*info));
739ba6b8479SBen Skeggs 	return 0;
740ba6b8479SBen Skeggs }
741ba6b8479SBen Skeggs 
742ba6b8479SBen Skeggs static int
nouveau_abi16_ioctl_del(struct nouveau_abi16 * abi16,struct nvif_ioctl_v0 * ioctl,u32 argc)743ba6b8479SBen Skeggs nouveau_abi16_ioctl_del(struct nouveau_abi16 *abi16, struct nvif_ioctl_v0 *ioctl, u32 argc)
744ba6b8479SBen Skeggs {
745ba6b8479SBen Skeggs 	struct nouveau_abi16_obj *obj;
746ba6b8479SBen Skeggs 
747ba6b8479SBen Skeggs 	if (ioctl->route || argc)
748ba6b8479SBen Skeggs 		return -EINVAL;
749ba6b8479SBen Skeggs 
750ba6b8479SBen Skeggs 	obj = nouveau_abi16_obj_find(abi16, ioctl->object);
751ba6b8479SBen Skeggs 	if (obj) {
752ba6b8479SBen Skeggs 		if (obj->type == ENGOBJ)
753ba6b8479SBen Skeggs 			nvif_object_dtor(&obj->engobj);
754ba6b8479SBen Skeggs 		nouveau_abi16_obj_del(obj);
755ba6b8479SBen Skeggs 	}
756ba6b8479SBen Skeggs 
757ba6b8479SBen Skeggs 	return 0;
758ba6b8479SBen Skeggs }
759ba6b8479SBen Skeggs 
760ba6b8479SBen Skeggs static int
nouveau_abi16_ioctl_new(struct nouveau_abi16 * abi16,struct nvif_ioctl_v0 * ioctl,u32 argc)761ba6b8479SBen Skeggs nouveau_abi16_ioctl_new(struct nouveau_abi16 *abi16, struct nvif_ioctl_v0 *ioctl, u32 argc)
762ba6b8479SBen Skeggs {
763ba6b8479SBen Skeggs 	struct nvif_ioctl_new_v0 *args;
764ba6b8479SBen Skeggs 	struct nouveau_abi16_chan *chan;
765ba6b8479SBen Skeggs 	struct nouveau_abi16_obj *obj;
766ba6b8479SBen Skeggs 	int ret;
767ba6b8479SBen Skeggs 
768ba6b8479SBen Skeggs 	if (argc < sizeof(*args))
769ba6b8479SBen Skeggs 		return -EINVAL;
770ba6b8479SBen Skeggs 	args = (void *)ioctl->data;
771ba6b8479SBen Skeggs 	argc -= sizeof(*args);
772ba6b8479SBen Skeggs 
773ba6b8479SBen Skeggs 	if (args->version != 0)
774ba6b8479SBen Skeggs 		return -EINVAL;
775ba6b8479SBen Skeggs 
776ba6b8479SBen Skeggs 	if (!ioctl->route) {
777ba6b8479SBen Skeggs 		if (ioctl->object || args->oclass != NV_DEVICE)
778ba6b8479SBen Skeggs 			return -EINVAL;
779ba6b8479SBen Skeggs 
780ba6b8479SBen Skeggs 		obj = nouveau_abi16_obj_new(abi16, DEVICE, args->object);
781ba6b8479SBen Skeggs 		if (IS_ERR(obj))
782ba6b8479SBen Skeggs 			return PTR_ERR(obj);
783ba6b8479SBen Skeggs 
784ba6b8479SBen Skeggs 		return 0;
785ba6b8479SBen Skeggs 	}
786ba6b8479SBen Skeggs 
787ba6b8479SBen Skeggs 	chan = nouveau_abi16_chan(abi16, ioctl->token);
788ba6b8479SBen Skeggs 	if (!chan)
789ba6b8479SBen Skeggs 		return -EINVAL;
790ba6b8479SBen Skeggs 
791ba6b8479SBen Skeggs 	obj = nouveau_abi16_obj_new(abi16, ENGOBJ, args->object);
792ba6b8479SBen Skeggs 	if (IS_ERR(obj))
793ba6b8479SBen Skeggs 		return PTR_ERR(obj);
794ba6b8479SBen Skeggs 
795ba6b8479SBen Skeggs 	ret = nvif_object_ctor(&chan->chan->user, "abi16EngObj", args->handle, args->oclass,
796ba6b8479SBen Skeggs 			       NULL, 0, &obj->engobj);
797ba6b8479SBen Skeggs 	if (ret)
798ba6b8479SBen Skeggs 		nouveau_abi16_obj_del(obj);
799ba6b8479SBen Skeggs 
800ba6b8479SBen Skeggs 	return ret;
801ba6b8479SBen Skeggs }
802ba6b8479SBen Skeggs 
803ba6b8479SBen Skeggs static int
nouveau_abi16_ioctl_sclass(struct nouveau_abi16 * abi16,struct nvif_ioctl_v0 * ioctl,u32 argc)804ba6b8479SBen Skeggs nouveau_abi16_ioctl_sclass(struct nouveau_abi16 *abi16, struct nvif_ioctl_v0 *ioctl, u32 argc)
805ba6b8479SBen Skeggs {
806ba6b8479SBen Skeggs 	struct nvif_ioctl_sclass_v0 *args;
807ba6b8479SBen Skeggs 	struct nouveau_abi16_chan *chan;
808ba6b8479SBen Skeggs 	struct nvif_sclass *sclass;
809ba6b8479SBen Skeggs 	int ret;
810ba6b8479SBen Skeggs 
811ba6b8479SBen Skeggs 	if (!ioctl->route || argc < sizeof(*args))
812ba6b8479SBen Skeggs 		return -EINVAL;
813ba6b8479SBen Skeggs 	args = (void *)ioctl->data;
814ba6b8479SBen Skeggs 	argc -= sizeof(*args);
815ba6b8479SBen Skeggs 
816ba6b8479SBen Skeggs 	if (argc != args->count * sizeof(args->oclass[0]))
817ba6b8479SBen Skeggs 		return -EINVAL;
818ba6b8479SBen Skeggs 
819ba6b8479SBen Skeggs 	chan = nouveau_abi16_chan(abi16, ioctl->token);
820ba6b8479SBen Skeggs 	if (!chan)
821ba6b8479SBen Skeggs 		return -EINVAL;
822ba6b8479SBen Skeggs 
823ba6b8479SBen Skeggs 	ret = nvif_object_sclass_get(&chan->chan->user, &sclass);
824ba6b8479SBen Skeggs 	if (ret < 0)
825ba6b8479SBen Skeggs 		return ret;
826ba6b8479SBen Skeggs 
827ba6b8479SBen Skeggs 	for (int i = 0; i < min_t(u8, args->count, ret); i++) {
828ba6b8479SBen Skeggs 		args->oclass[i].oclass = sclass[i].oclass;
829ba6b8479SBen Skeggs 		args->oclass[i].minver = sclass[i].minver;
830ba6b8479SBen Skeggs 		args->oclass[i].maxver = sclass[i].maxver;
831ba6b8479SBen Skeggs 	}
832ba6b8479SBen Skeggs 	args->count = ret;
833ba6b8479SBen Skeggs 
834ba6b8479SBen Skeggs 	nvif_object_sclass_put(&sclass);
835ba6b8479SBen Skeggs 	return 0;
836ba6b8479SBen Skeggs }
837ba6b8479SBen Skeggs 
838ba6b8479SBen Skeggs int
nouveau_abi16_ioctl(struct drm_file * filp,void __user * user,u32 size)839ba6b8479SBen Skeggs nouveau_abi16_ioctl(struct drm_file *filp, void __user *user, u32 size)
840ba6b8479SBen Skeggs {
841ba6b8479SBen Skeggs 	struct nvif_ioctl_v0 *ioctl;
842ba6b8479SBen Skeggs 	struct nouveau_abi16 *abi16;
843ba6b8479SBen Skeggs 	u32 argc = size;
844ba6b8479SBen Skeggs 	int ret;
845ba6b8479SBen Skeggs 
846ba6b8479SBen Skeggs 	if (argc < sizeof(*ioctl))
847ba6b8479SBen Skeggs 		return -EINVAL;
848ba6b8479SBen Skeggs 	argc -= sizeof(*ioctl);
849ba6b8479SBen Skeggs 
850ba6b8479SBen Skeggs 	ioctl = kmalloc(size, GFP_KERNEL);
851ba6b8479SBen Skeggs 	if (!ioctl)
852ba6b8479SBen Skeggs 		return -ENOMEM;
853ba6b8479SBen Skeggs 
854ba6b8479SBen Skeggs 	ret = -EFAULT;
855ba6b8479SBen Skeggs 	if (copy_from_user(ioctl, user, size))
856ba6b8479SBen Skeggs 		goto done_free;
857ba6b8479SBen Skeggs 
858ba6b8479SBen Skeggs 	if (ioctl->version != 0x00 ||
859ba6b8479SBen Skeggs 	    (ioctl->route && ioctl->route != 0xff)) {
860ba6b8479SBen Skeggs 		ret = -EINVAL;
861ba6b8479SBen Skeggs 		goto done_free;
862ba6b8479SBen Skeggs 	}
863ba6b8479SBen Skeggs 
864ba6b8479SBen Skeggs 	abi16 = nouveau_abi16_get(filp);
865ba6b8479SBen Skeggs 	if (unlikely(!abi16)) {
866ba6b8479SBen Skeggs 		ret = -ENOMEM;
867ba6b8479SBen Skeggs 		goto done_free;
868ba6b8479SBen Skeggs 	}
869ba6b8479SBen Skeggs 
870ba6b8479SBen Skeggs 	switch (ioctl->type) {
871ba6b8479SBen Skeggs 	case NVIF_IOCTL_V0_SCLASS: ret = nouveau_abi16_ioctl_sclass(abi16, ioctl, argc); break;
872ba6b8479SBen Skeggs 	case NVIF_IOCTL_V0_NEW   : ret = nouveau_abi16_ioctl_new   (abi16, ioctl, argc); break;
873ba6b8479SBen Skeggs 	case NVIF_IOCTL_V0_DEL   : ret = nouveau_abi16_ioctl_del   (abi16, ioctl, argc); break;
874ba6b8479SBen Skeggs 	case NVIF_IOCTL_V0_MTHD  : ret = nouveau_abi16_ioctl_mthd  (abi16, ioctl, argc); break;
875ba6b8479SBen Skeggs 	default:
876ba6b8479SBen Skeggs 		ret = -EINVAL;
877ba6b8479SBen Skeggs 		break;
878ba6b8479SBen Skeggs 	}
879ba6b8479SBen Skeggs 
880ba6b8479SBen Skeggs 	nouveau_abi16_put(abi16, 0);
881ba6b8479SBen Skeggs 
882ba6b8479SBen Skeggs 	if (ret == 0) {
883ba6b8479SBen Skeggs 		if (copy_to_user(user, ioctl, size))
884ba6b8479SBen Skeggs 			ret = -EFAULT;
885ba6b8479SBen Skeggs 	}
886ba6b8479SBen Skeggs 
887ba6b8479SBen Skeggs done_free:
888ba6b8479SBen Skeggs 	kfree(ioctl);
889ba6b8479SBen Skeggs 	return ret;
890ba6b8479SBen Skeggs }
891