xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/nouveau/nouveau_abi16.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2012 Red Hat Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun  * all copies or substantial portions of the Software.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*4882a593Smuzhiyun  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*4882a593Smuzhiyun  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*4882a593Smuzhiyun  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*4882a593Smuzhiyun  * OTHER DEALINGS IN THE SOFTWARE.
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include <nvif/client.h>
25*4882a593Smuzhiyun #include <nvif/driver.h>
26*4882a593Smuzhiyun #include <nvif/fifo.h>
27*4882a593Smuzhiyun #include <nvif/ioctl.h>
28*4882a593Smuzhiyun #include <nvif/class.h>
29*4882a593Smuzhiyun #include <nvif/cl0002.h>
30*4882a593Smuzhiyun #include <nvif/cla06f.h>
31*4882a593Smuzhiyun #include <nvif/unpack.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include "nouveau_drv.h"
34*4882a593Smuzhiyun #include "nouveau_dma.h"
35*4882a593Smuzhiyun #include "nouveau_gem.h"
36*4882a593Smuzhiyun #include "nouveau_chan.h"
37*4882a593Smuzhiyun #include "nouveau_abi16.h"
38*4882a593Smuzhiyun #include "nouveau_vmm.h"
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun static struct nouveau_abi16 *
nouveau_abi16(struct drm_file * file_priv)41*4882a593Smuzhiyun nouveau_abi16(struct drm_file *file_priv)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	struct nouveau_cli *cli = nouveau_cli(file_priv);
44*4882a593Smuzhiyun 	if (!cli->abi16) {
45*4882a593Smuzhiyun 		struct nouveau_abi16 *abi16;
46*4882a593Smuzhiyun 		cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
47*4882a593Smuzhiyun 		if (cli->abi16) {
48*4882a593Smuzhiyun 			struct nv_device_v0 args = {
49*4882a593Smuzhiyun 				.device = ~0ULL,
50*4882a593Smuzhiyun 			};
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 			INIT_LIST_HEAD(&abi16->channels);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 			/* allocate device object targeting client's default
55*4882a593Smuzhiyun 			 * device (ie. the one that belongs to the fd it
56*4882a593Smuzhiyun 			 * opened)
57*4882a593Smuzhiyun 			 */
58*4882a593Smuzhiyun 			if (nvif_device_ctor(&cli->base.object, "abi16Device",
59*4882a593Smuzhiyun 					     0, NV_DEVICE, &args, sizeof(args),
60*4882a593Smuzhiyun 					     &abi16->device) == 0)
61*4882a593Smuzhiyun 				return cli->abi16;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 			kfree(cli->abi16);
64*4882a593Smuzhiyun 			cli->abi16 = NULL;
65*4882a593Smuzhiyun 		}
66*4882a593Smuzhiyun 	}
67*4882a593Smuzhiyun 	return cli->abi16;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun struct nouveau_abi16 *
nouveau_abi16_get(struct drm_file * file_priv)71*4882a593Smuzhiyun nouveau_abi16_get(struct drm_file *file_priv)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct nouveau_cli *cli = nouveau_cli(file_priv);
74*4882a593Smuzhiyun 	mutex_lock(&cli->mutex);
75*4882a593Smuzhiyun 	if (nouveau_abi16(file_priv))
76*4882a593Smuzhiyun 		return cli->abi16;
77*4882a593Smuzhiyun 	mutex_unlock(&cli->mutex);
78*4882a593Smuzhiyun 	return NULL;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun int
nouveau_abi16_put(struct nouveau_abi16 * abi16,int ret)82*4882a593Smuzhiyun nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	struct nouveau_cli *cli = (void *)abi16->device.object.client;
85*4882a593Smuzhiyun 	mutex_unlock(&cli->mutex);
86*4882a593Smuzhiyun 	return ret;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun s32
nouveau_abi16_swclass(struct nouveau_drm * drm)90*4882a593Smuzhiyun nouveau_abi16_swclass(struct nouveau_drm *drm)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	switch (drm->client.device.info.family) {
93*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_TNT:
94*4882a593Smuzhiyun 		return NVIF_CLASS_SW_NV04;
95*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_CELSIUS:
96*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_KELVIN:
97*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_RANKINE:
98*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_CURIE:
99*4882a593Smuzhiyun 		return NVIF_CLASS_SW_NV10;
100*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_TESLA:
101*4882a593Smuzhiyun 		return NVIF_CLASS_SW_NV50;
102*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_FERMI:
103*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_KEPLER:
104*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_MAXWELL:
105*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_PASCAL:
106*4882a593Smuzhiyun 	case NV_DEVICE_INFO_V0_VOLTA:
107*4882a593Smuzhiyun 		return NVIF_CLASS_SW_GF100;
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	return 0x0000;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun static void
nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan * chan,struct nouveau_abi16_ntfy * ntfy)114*4882a593Smuzhiyun nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
115*4882a593Smuzhiyun 			struct nouveau_abi16_ntfy *ntfy)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	nvif_object_dtor(&ntfy->object);
118*4882a593Smuzhiyun 	nvkm_mm_free(&chan->heap, &ntfy->node);
119*4882a593Smuzhiyun 	list_del(&ntfy->head);
120*4882a593Smuzhiyun 	kfree(ntfy);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun static void
nouveau_abi16_chan_fini(struct nouveau_abi16 * abi16,struct nouveau_abi16_chan * chan)124*4882a593Smuzhiyun nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
125*4882a593Smuzhiyun 			struct nouveau_abi16_chan *chan)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct nouveau_abi16_ntfy *ntfy, *temp;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	/* wait for all activity to stop before releasing notify object, which
130*4882a593Smuzhiyun 	 * may be still in use */
131*4882a593Smuzhiyun 	if (chan->chan && chan->ntfy)
132*4882a593Smuzhiyun 		nouveau_channel_idle(chan->chan);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	/* cleanup notifier state */
135*4882a593Smuzhiyun 	list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
136*4882a593Smuzhiyun 		nouveau_abi16_ntfy_fini(chan, ntfy);
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (chan->ntfy) {
140*4882a593Smuzhiyun 		nouveau_vma_del(&chan->ntfy_vma);
141*4882a593Smuzhiyun 		nouveau_bo_unpin(chan->ntfy);
142*4882a593Smuzhiyun 		drm_gem_object_put(&chan->ntfy->bo.base);
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	if (chan->heap.block_size)
146*4882a593Smuzhiyun 		nvkm_mm_fini(&chan->heap);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	/* destroy channel object, all children will be killed too */
149*4882a593Smuzhiyun 	if (chan->chan) {
150*4882a593Smuzhiyun 		nouveau_channel_idle(chan->chan);
151*4882a593Smuzhiyun 		nouveau_channel_del(&chan->chan);
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	list_del(&chan->head);
155*4882a593Smuzhiyun 	kfree(chan);
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun void
nouveau_abi16_fini(struct nouveau_abi16 * abi16)159*4882a593Smuzhiyun nouveau_abi16_fini(struct nouveau_abi16 *abi16)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	struct nouveau_cli *cli = (void *)abi16->device.object.client;
162*4882a593Smuzhiyun 	struct nouveau_abi16_chan *chan, *temp;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* cleanup channels */
165*4882a593Smuzhiyun 	list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
166*4882a593Smuzhiyun 		nouveau_abi16_chan_fini(abi16, chan);
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	/* destroy the device object */
170*4882a593Smuzhiyun 	nvif_device_dtor(&abi16->device);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	kfree(cli->abi16);
173*4882a593Smuzhiyun 	cli->abi16 = NULL;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun int
nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)177*4882a593Smuzhiyun nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	struct nouveau_cli *cli = nouveau_cli(file_priv);
180*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_drm(dev);
181*4882a593Smuzhiyun 	struct nvif_device *device = &drm->client.device;
182*4882a593Smuzhiyun 	struct nvkm_gr *gr = nvxx_gr(device);
183*4882a593Smuzhiyun 	struct drm_nouveau_getparam *getparam = data;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	switch (getparam->param) {
186*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_CHIPSET_ID:
187*4882a593Smuzhiyun 		getparam->value = device->info.chipset;
188*4882a593Smuzhiyun 		break;
189*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_PCI_VENDOR:
190*4882a593Smuzhiyun 		if (device->info.platform != NV_DEVICE_INFO_V0_SOC)
191*4882a593Smuzhiyun 			getparam->value = dev->pdev->vendor;
192*4882a593Smuzhiyun 		else
193*4882a593Smuzhiyun 			getparam->value = 0;
194*4882a593Smuzhiyun 		break;
195*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_PCI_DEVICE:
196*4882a593Smuzhiyun 		if (device->info.platform != NV_DEVICE_INFO_V0_SOC)
197*4882a593Smuzhiyun 			getparam->value = dev->pdev->device;
198*4882a593Smuzhiyun 		else
199*4882a593Smuzhiyun 			getparam->value = 0;
200*4882a593Smuzhiyun 		break;
201*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_BUS_TYPE:
202*4882a593Smuzhiyun 		switch (device->info.platform) {
203*4882a593Smuzhiyun 		case NV_DEVICE_INFO_V0_AGP : getparam->value = 0; break;
204*4882a593Smuzhiyun 		case NV_DEVICE_INFO_V0_PCI : getparam->value = 1; break;
205*4882a593Smuzhiyun 		case NV_DEVICE_INFO_V0_PCIE: getparam->value = 2; break;
206*4882a593Smuzhiyun 		case NV_DEVICE_INFO_V0_SOC : getparam->value = 3; break;
207*4882a593Smuzhiyun 		case NV_DEVICE_INFO_V0_IGP :
208*4882a593Smuzhiyun 			if (!pci_is_pcie(dev->pdev))
209*4882a593Smuzhiyun 				getparam->value = 1;
210*4882a593Smuzhiyun 			else
211*4882a593Smuzhiyun 				getparam->value = 2;
212*4882a593Smuzhiyun 			break;
213*4882a593Smuzhiyun 		default:
214*4882a593Smuzhiyun 			WARN_ON(1);
215*4882a593Smuzhiyun 			break;
216*4882a593Smuzhiyun 		}
217*4882a593Smuzhiyun 		break;
218*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_FB_SIZE:
219*4882a593Smuzhiyun 		getparam->value = drm->gem.vram_available;
220*4882a593Smuzhiyun 		break;
221*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_AGP_SIZE:
222*4882a593Smuzhiyun 		getparam->value = drm->gem.gart_available;
223*4882a593Smuzhiyun 		break;
224*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_VM_VRAM_BASE:
225*4882a593Smuzhiyun 		getparam->value = 0; /* deprecated */
226*4882a593Smuzhiyun 		break;
227*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_PTIMER_TIME:
228*4882a593Smuzhiyun 		getparam->value = nvif_device_time(device);
229*4882a593Smuzhiyun 		break;
230*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_HAS_BO_USAGE:
231*4882a593Smuzhiyun 		getparam->value = 1;
232*4882a593Smuzhiyun 		break;
233*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
234*4882a593Smuzhiyun 		getparam->value = 1;
235*4882a593Smuzhiyun 		break;
236*4882a593Smuzhiyun 	case NOUVEAU_GETPARAM_GRAPH_UNITS:
237*4882a593Smuzhiyun 		getparam->value = nvkm_gr_units(gr);
238*4882a593Smuzhiyun 		break;
239*4882a593Smuzhiyun 	default:
240*4882a593Smuzhiyun 		NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
241*4882a593Smuzhiyun 		return -EINVAL;
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	return 0;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun int
nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)248*4882a593Smuzhiyun nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	struct drm_nouveau_channel_alloc *init = data;
251*4882a593Smuzhiyun 	struct nouveau_cli *cli = nouveau_cli(file_priv);
252*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_drm(dev);
253*4882a593Smuzhiyun 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
254*4882a593Smuzhiyun 	struct nouveau_abi16_chan *chan;
255*4882a593Smuzhiyun 	struct nvif_device *device;
256*4882a593Smuzhiyun 	u64 engine;
257*4882a593Smuzhiyun 	int ret;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	if (unlikely(!abi16))
260*4882a593Smuzhiyun 		return -ENOMEM;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	if (!drm->channel)
263*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -ENODEV);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	device = &abi16->device;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	/* hack to allow channel engine type specification on kepler */
268*4882a593Smuzhiyun 	if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
269*4882a593Smuzhiyun 		if (init->fb_ctxdma_handle == ~0) {
270*4882a593Smuzhiyun 			switch (init->tt_ctxdma_handle) {
271*4882a593Smuzhiyun 			case 0x01: engine = NV_DEVICE_INFO_ENGINE_GR    ; break;
272*4882a593Smuzhiyun 			case 0x02: engine = NV_DEVICE_INFO_ENGINE_MSPDEC; break;
273*4882a593Smuzhiyun 			case 0x04: engine = NV_DEVICE_INFO_ENGINE_MSPPP ; break;
274*4882a593Smuzhiyun 			case 0x08: engine = NV_DEVICE_INFO_ENGINE_MSVLD ; break;
275*4882a593Smuzhiyun 			case 0x30: engine = NV_DEVICE_INFO_ENGINE_CE    ; break;
276*4882a593Smuzhiyun 			default:
277*4882a593Smuzhiyun 				return nouveau_abi16_put(abi16, -ENOSYS);
278*4882a593Smuzhiyun 			}
279*4882a593Smuzhiyun 		} else {
280*4882a593Smuzhiyun 			engine = NV_DEVICE_INFO_ENGINE_GR;
281*4882a593Smuzhiyun 		}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		if (engine != NV_DEVICE_INFO_ENGINE_CE)
284*4882a593Smuzhiyun 			engine = nvif_fifo_runlist(device, engine);
285*4882a593Smuzhiyun 		else
286*4882a593Smuzhiyun 			engine = nvif_fifo_runlist_ce(device);
287*4882a593Smuzhiyun 		init->fb_ctxdma_handle = engine;
288*4882a593Smuzhiyun 		init->tt_ctxdma_handle = 0;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
292*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -EINVAL);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* allocate "abi16 channel" data and make up a handle for it */
295*4882a593Smuzhiyun 	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
296*4882a593Smuzhiyun 	if (!chan)
297*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -ENOMEM);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	INIT_LIST_HEAD(&chan->notifiers);
300*4882a593Smuzhiyun 	list_add(&chan->head, &abi16->channels);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	/* create channel object and initialise dma and fence management */
303*4882a593Smuzhiyun 	ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle,
304*4882a593Smuzhiyun 				  init->tt_ctxdma_handle, false, &chan->chan);
305*4882a593Smuzhiyun 	if (ret)
306*4882a593Smuzhiyun 		goto done;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	init->channel = chan->chan->chid;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	if (device->info.family >= NV_DEVICE_INFO_V0_TESLA)
311*4882a593Smuzhiyun 		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
312*4882a593Smuzhiyun 					NOUVEAU_GEM_DOMAIN_GART;
313*4882a593Smuzhiyun 	else
314*4882a593Smuzhiyun 	if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM)
315*4882a593Smuzhiyun 		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
316*4882a593Smuzhiyun 	else
317*4882a593Smuzhiyun 		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
320*4882a593Smuzhiyun 		init->subchan[0].handle = 0x00000000;
321*4882a593Smuzhiyun 		init->subchan[0].grclass = 0x0000;
322*4882a593Smuzhiyun 		init->subchan[1].handle = chan->chan->nvsw.handle;
323*4882a593Smuzhiyun 		init->subchan[1].grclass = 0x506e;
324*4882a593Smuzhiyun 		init->nr_subchan = 2;
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	/* Named memory object area */
328*4882a593Smuzhiyun 	ret = nouveau_gem_new(cli, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
329*4882a593Smuzhiyun 			      0, 0, &chan->ntfy);
330*4882a593Smuzhiyun 	if (ret == 0)
331*4882a593Smuzhiyun 		ret = nouveau_bo_pin(chan->ntfy, NOUVEAU_GEM_DOMAIN_GART,
332*4882a593Smuzhiyun 				     false);
333*4882a593Smuzhiyun 	if (ret)
334*4882a593Smuzhiyun 		goto done;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
337*4882a593Smuzhiyun 		ret = nouveau_vma_new(chan->ntfy, chan->chan->vmm,
338*4882a593Smuzhiyun 				      &chan->ntfy_vma);
339*4882a593Smuzhiyun 		if (ret)
340*4882a593Smuzhiyun 			goto done;
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	ret = drm_gem_handle_create(file_priv, &chan->ntfy->bo.base,
344*4882a593Smuzhiyun 				    &init->notifier_handle);
345*4882a593Smuzhiyun 	if (ret)
346*4882a593Smuzhiyun 		goto done;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	ret = nvkm_mm_init(&chan->heap, 0, 0, PAGE_SIZE, 1);
349*4882a593Smuzhiyun done:
350*4882a593Smuzhiyun 	if (ret)
351*4882a593Smuzhiyun 		nouveau_abi16_chan_fini(abi16, chan);
352*4882a593Smuzhiyun 	return nouveau_abi16_put(abi16, ret);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun static struct nouveau_abi16_chan *
nouveau_abi16_chan(struct nouveau_abi16 * abi16,int channel)356*4882a593Smuzhiyun nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	struct nouveau_abi16_chan *chan;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	list_for_each_entry(chan, &abi16->channels, head) {
361*4882a593Smuzhiyun 		if (chan->chan->chid == channel)
362*4882a593Smuzhiyun 			return chan;
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return NULL;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun int
nouveau_abi16_usif(struct drm_file * file_priv,void * data,u32 size)369*4882a593Smuzhiyun nouveau_abi16_usif(struct drm_file *file_priv, void *data, u32 size)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun 	union {
372*4882a593Smuzhiyun 		struct nvif_ioctl_v0 v0;
373*4882a593Smuzhiyun 	} *args = data;
374*4882a593Smuzhiyun 	struct nouveau_abi16_chan *chan;
375*4882a593Smuzhiyun 	struct nouveau_abi16 *abi16;
376*4882a593Smuzhiyun 	int ret = -ENOSYS;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
379*4882a593Smuzhiyun 		switch (args->v0.type) {
380*4882a593Smuzhiyun 		case NVIF_IOCTL_V0_NEW:
381*4882a593Smuzhiyun 		case NVIF_IOCTL_V0_MTHD:
382*4882a593Smuzhiyun 		case NVIF_IOCTL_V0_SCLASS:
383*4882a593Smuzhiyun 			break;
384*4882a593Smuzhiyun 		default:
385*4882a593Smuzhiyun 			return -EACCES;
386*4882a593Smuzhiyun 		}
387*4882a593Smuzhiyun 	} else
388*4882a593Smuzhiyun 		return ret;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	if (!(abi16 = nouveau_abi16(file_priv)))
391*4882a593Smuzhiyun 		return -ENOMEM;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	if (args->v0.token != ~0ULL) {
394*4882a593Smuzhiyun 		if (!(chan = nouveau_abi16_chan(abi16, args->v0.token)))
395*4882a593Smuzhiyun 			return -EINVAL;
396*4882a593Smuzhiyun 		args->v0.object = nvif_handle(&chan->chan->user);
397*4882a593Smuzhiyun 		args->v0.owner  = NVIF_IOCTL_V0_OWNER_ANY;
398*4882a593Smuzhiyun 		return 0;
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	args->v0.object = nvif_handle(&abi16->device.object);
402*4882a593Smuzhiyun 	args->v0.owner  = NVIF_IOCTL_V0_OWNER_ANY;
403*4882a593Smuzhiyun 	return 0;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun int
nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)407*4882a593Smuzhiyun nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	struct drm_nouveau_channel_free *req = data;
410*4882a593Smuzhiyun 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
411*4882a593Smuzhiyun 	struct nouveau_abi16_chan *chan;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	if (unlikely(!abi16))
414*4882a593Smuzhiyun 		return -ENOMEM;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	chan = nouveau_abi16_chan(abi16, req->channel);
417*4882a593Smuzhiyun 	if (!chan)
418*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -ENOENT);
419*4882a593Smuzhiyun 	nouveau_abi16_chan_fini(abi16, chan);
420*4882a593Smuzhiyun 	return nouveau_abi16_put(abi16, 0);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun int
nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)424*4882a593Smuzhiyun nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	struct drm_nouveau_grobj_alloc *init = data;
427*4882a593Smuzhiyun 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
428*4882a593Smuzhiyun 	struct nouveau_abi16_chan *chan;
429*4882a593Smuzhiyun 	struct nouveau_abi16_ntfy *ntfy;
430*4882a593Smuzhiyun 	struct nvif_client *client;
431*4882a593Smuzhiyun 	struct nvif_sclass *sclass;
432*4882a593Smuzhiyun 	s32 oclass = 0;
433*4882a593Smuzhiyun 	int ret, i;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	if (unlikely(!abi16))
436*4882a593Smuzhiyun 		return -ENOMEM;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	if (init->handle == ~0)
439*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -EINVAL);
440*4882a593Smuzhiyun 	client = abi16->device.object.client;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	chan = nouveau_abi16_chan(abi16, init->channel);
443*4882a593Smuzhiyun 	if (!chan)
444*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -ENOENT);
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	ret = nvif_object_sclass_get(&chan->chan->user, &sclass);
447*4882a593Smuzhiyun 	if (ret < 0)
448*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, ret);
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	if ((init->class & 0x00ff) == 0x006e) {
451*4882a593Smuzhiyun 		/* nvsw: compatibility with older 0x*6e class identifier */
452*4882a593Smuzhiyun 		for (i = 0; !oclass && i < ret; i++) {
453*4882a593Smuzhiyun 			switch (sclass[i].oclass) {
454*4882a593Smuzhiyun 			case NVIF_CLASS_SW_NV04:
455*4882a593Smuzhiyun 			case NVIF_CLASS_SW_NV10:
456*4882a593Smuzhiyun 			case NVIF_CLASS_SW_NV50:
457*4882a593Smuzhiyun 			case NVIF_CLASS_SW_GF100:
458*4882a593Smuzhiyun 				oclass = sclass[i].oclass;
459*4882a593Smuzhiyun 				break;
460*4882a593Smuzhiyun 			default:
461*4882a593Smuzhiyun 				break;
462*4882a593Smuzhiyun 			}
463*4882a593Smuzhiyun 		}
464*4882a593Smuzhiyun 	} else
465*4882a593Smuzhiyun 	if ((init->class & 0x00ff) == 0x00b1) {
466*4882a593Smuzhiyun 		/* msvld: compatibility with incorrect version exposure */
467*4882a593Smuzhiyun 		for (i = 0; i < ret; i++) {
468*4882a593Smuzhiyun 			if ((sclass[i].oclass & 0x00ff) == 0x00b1) {
469*4882a593Smuzhiyun 				oclass = sclass[i].oclass;
470*4882a593Smuzhiyun 				break;
471*4882a593Smuzhiyun 			}
472*4882a593Smuzhiyun 		}
473*4882a593Smuzhiyun 	} else
474*4882a593Smuzhiyun 	if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */
475*4882a593Smuzhiyun 		/* mspdec: compatibility with incorrect version exposure */
476*4882a593Smuzhiyun 		for (i = 0; i < ret; i++) {
477*4882a593Smuzhiyun 			if ((sclass[i].oclass & 0x00ff) == 0x00b2) {
478*4882a593Smuzhiyun 				oclass = sclass[i].oclass;
479*4882a593Smuzhiyun 				break;
480*4882a593Smuzhiyun 			}
481*4882a593Smuzhiyun 		}
482*4882a593Smuzhiyun 	} else
483*4882a593Smuzhiyun 	if ((init->class & 0x00ff) == 0x00b3) { /* msppp */
484*4882a593Smuzhiyun 		/* msppp: compatibility with incorrect version exposure */
485*4882a593Smuzhiyun 		for (i = 0; i < ret; i++) {
486*4882a593Smuzhiyun 			if ((sclass[i].oclass & 0x00ff) == 0x00b3) {
487*4882a593Smuzhiyun 				oclass = sclass[i].oclass;
488*4882a593Smuzhiyun 				break;
489*4882a593Smuzhiyun 			}
490*4882a593Smuzhiyun 		}
491*4882a593Smuzhiyun 	} else {
492*4882a593Smuzhiyun 		oclass = init->class;
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	nvif_object_sclass_put(&sclass);
496*4882a593Smuzhiyun 	if (!oclass)
497*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -EINVAL);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
500*4882a593Smuzhiyun 	if (!ntfy)
501*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -ENOMEM);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	list_add(&ntfy->head, &chan->notifiers);
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	client->route = NVDRM_OBJECT_ABI16;
506*4882a593Smuzhiyun 	ret = nvif_object_ctor(&chan->chan->user, "abi16EngObj", init->handle,
507*4882a593Smuzhiyun 			       oclass, NULL, 0, &ntfy->object);
508*4882a593Smuzhiyun 	client->route = NVDRM_OBJECT_NVIF;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	if (ret)
511*4882a593Smuzhiyun 		nouveau_abi16_ntfy_fini(chan, ntfy);
512*4882a593Smuzhiyun 	return nouveau_abi16_put(abi16, ret);
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun int
nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)516*4882a593Smuzhiyun nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	struct drm_nouveau_notifierobj_alloc *info = data;
519*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_drm(dev);
520*4882a593Smuzhiyun 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
521*4882a593Smuzhiyun 	struct nouveau_abi16_chan *chan;
522*4882a593Smuzhiyun 	struct nouveau_abi16_ntfy *ntfy;
523*4882a593Smuzhiyun 	struct nvif_device *device = &abi16->device;
524*4882a593Smuzhiyun 	struct nvif_client *client;
525*4882a593Smuzhiyun 	struct nv_dma_v0 args = {};
526*4882a593Smuzhiyun 	int ret;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	if (unlikely(!abi16))
529*4882a593Smuzhiyun 		return -ENOMEM;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	/* completely unnecessary for these chipsets... */
532*4882a593Smuzhiyun 	if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI))
533*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -EINVAL);
534*4882a593Smuzhiyun 	client = abi16->device.object.client;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	chan = nouveau_abi16_chan(abi16, info->channel);
537*4882a593Smuzhiyun 	if (!chan)
538*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -ENOENT);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
541*4882a593Smuzhiyun 	if (!ntfy)
542*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -ENOMEM);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	list_add(&ntfy->head, &chan->notifiers);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
547*4882a593Smuzhiyun 			   &ntfy->node);
548*4882a593Smuzhiyun 	if (ret)
549*4882a593Smuzhiyun 		goto done;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	args.start = ntfy->node->offset;
552*4882a593Smuzhiyun 	args.limit = ntfy->node->offset + ntfy->node->length - 1;
553*4882a593Smuzhiyun 	if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
554*4882a593Smuzhiyun 		args.target = NV_DMA_V0_TARGET_VM;
555*4882a593Smuzhiyun 		args.access = NV_DMA_V0_ACCESS_VM;
556*4882a593Smuzhiyun 		args.start += chan->ntfy_vma->addr;
557*4882a593Smuzhiyun 		args.limit += chan->ntfy_vma->addr;
558*4882a593Smuzhiyun 	} else
559*4882a593Smuzhiyun 	if (drm->agp.bridge) {
560*4882a593Smuzhiyun 		args.target = NV_DMA_V0_TARGET_AGP;
561*4882a593Smuzhiyun 		args.access = NV_DMA_V0_ACCESS_RDWR;
562*4882a593Smuzhiyun 		args.start += drm->agp.base + chan->ntfy->offset;
563*4882a593Smuzhiyun 		args.limit += drm->agp.base + chan->ntfy->offset;
564*4882a593Smuzhiyun 	} else {
565*4882a593Smuzhiyun 		args.target = NV_DMA_V0_TARGET_VM;
566*4882a593Smuzhiyun 		args.access = NV_DMA_V0_ACCESS_RDWR;
567*4882a593Smuzhiyun 		args.start += chan->ntfy->offset;
568*4882a593Smuzhiyun 		args.limit += chan->ntfy->offset;
569*4882a593Smuzhiyun 	}
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	client->route = NVDRM_OBJECT_ABI16;
572*4882a593Smuzhiyun 	client->super = true;
573*4882a593Smuzhiyun 	ret = nvif_object_ctor(&chan->chan->user, "abi16Ntfy", info->handle,
574*4882a593Smuzhiyun 			       NV_DMA_IN_MEMORY, &args, sizeof(args),
575*4882a593Smuzhiyun 			       &ntfy->object);
576*4882a593Smuzhiyun 	client->super = false;
577*4882a593Smuzhiyun 	client->route = NVDRM_OBJECT_NVIF;
578*4882a593Smuzhiyun 	if (ret)
579*4882a593Smuzhiyun 		goto done;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	info->offset = ntfy->node->offset;
582*4882a593Smuzhiyun done:
583*4882a593Smuzhiyun 	if (ret)
584*4882a593Smuzhiyun 		nouveau_abi16_ntfy_fini(chan, ntfy);
585*4882a593Smuzhiyun 	return nouveau_abi16_put(abi16, ret);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun int
nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)589*4882a593Smuzhiyun nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun 	struct drm_nouveau_gpuobj_free *fini = data;
592*4882a593Smuzhiyun 	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
593*4882a593Smuzhiyun 	struct nouveau_abi16_chan *chan;
594*4882a593Smuzhiyun 	struct nouveau_abi16_ntfy *ntfy;
595*4882a593Smuzhiyun 	int ret = -ENOENT;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	if (unlikely(!abi16))
598*4882a593Smuzhiyun 		return -ENOMEM;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	chan = nouveau_abi16_chan(abi16, fini->channel);
601*4882a593Smuzhiyun 	if (!chan)
602*4882a593Smuzhiyun 		return nouveau_abi16_put(abi16, -EINVAL);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	/* synchronize with the user channel and destroy the gpu object */
605*4882a593Smuzhiyun 	nouveau_channel_idle(chan->chan);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	list_for_each_entry(ntfy, &chan->notifiers, head) {
608*4882a593Smuzhiyun 		if (ntfy->object.handle == fini->handle) {
609*4882a593Smuzhiyun 			nouveau_abi16_ntfy_fini(chan, ntfy);
610*4882a593Smuzhiyun 			ret = 0;
611*4882a593Smuzhiyun 			break;
612*4882a593Smuzhiyun 		}
613*4882a593Smuzhiyun 	}
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	return nouveau_abi16_put(abi16, ret);
616*4882a593Smuzhiyun }
617