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