blob: f98f800cc0112709635c3b4be3a2839d2fc70de9 [file] [log] [blame]
Ben Skeggs2a259a32012-05-08 10:24:27 +10001/*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23
Ben Skeggsa4e610b2014-08-10 04:10:23 +100024#include <nvif/client.h>
25#include <nvif/driver.h>
26#include <nvif/ioctl.h>
Ben Skeggsfdb751e2014-08-10 04:10:23 +100027#include <nvif/class.h>
Ben Skeggs845f2722015-11-08 12:16:40 +100028#include <nvif/cl0002.h>
Ben Skeggs8ed17302015-11-08 11:28:26 +100029#include <nvif/cla06f.h>
Ben Skeggs2621a412015-11-03 11:21:43 +100030#include <nvif/unpack.h>
Ben Skeggs2a259a32012-05-08 10:24:27 +100031
Ben Skeggs4dc28132016-05-20 09:22:55 +100032#include "nouveau_drv.h"
Ben Skeggs2a259a32012-05-08 10:24:27 +100033#include "nouveau_dma.h"
Ben Skeggsebb945a2012-07-20 08:17:34 +100034#include "nouveau_gem.h"
35#include "nouveau_chan.h"
Ben Skeggs2a259a32012-05-08 10:24:27 +100036#include "nouveau_abi16.h"
Ben Skeggsebb945a2012-07-20 08:17:34 +100037
Ben Skeggs786a57e2015-11-03 10:55:45 +100038static struct nouveau_abi16 *
39nouveau_abi16(struct drm_file *file_priv)
Ben Skeggsebb945a2012-07-20 08:17:34 +100040{
41 struct nouveau_cli *cli = nouveau_cli(file_priv);
Ben Skeggsebb945a2012-07-20 08:17:34 +100042 if (!cli->abi16) {
43 struct nouveau_abi16 *abi16;
44 cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
45 if (cli->abi16) {
Ben Skeggs586491e2014-08-10 04:10:24 +100046 struct nv_device_v0 args = {
47 .device = ~0ULL,
48 };
49
Ben Skeggsebb945a2012-07-20 08:17:34 +100050 INIT_LIST_HEAD(&abi16->channels);
Ben Skeggsebb945a2012-07-20 08:17:34 +100051
52 /* allocate device object targeting client's default
53 * device (ie. the one that belongs to the fd it
54 * opened)
55 */
Ben Skeggsfcf3f912015-09-04 14:40:32 +100056 if (nvif_device_init(&cli->base.object, 0, NV_DEVICE,
Ben Skeggs586491e2014-08-10 04:10:24 +100057 &args, sizeof(args),
Ben Skeggs0ad72862014-08-10 04:10:22 +100058 &abi16->device) == 0)
Ben Skeggsebb945a2012-07-20 08:17:34 +100059 return cli->abi16;
60
61 kfree(cli->abi16);
62 cli->abi16 = NULL;
63 }
Ben Skeggsebb945a2012-07-20 08:17:34 +100064 }
65 return cli->abi16;
66}
67
Ben Skeggs786a57e2015-11-03 10:55:45 +100068struct nouveau_abi16 *
69nouveau_abi16_get(struct drm_file *file_priv)
70{
71 struct nouveau_cli *cli = nouveau_cli(file_priv);
72 mutex_lock(&cli->mutex);
73 if (nouveau_abi16(file_priv))
74 return cli->abi16;
75 mutex_unlock(&cli->mutex);
76 return NULL;
77}
78
Ben Skeggsebb945a2012-07-20 08:17:34 +100079int
80nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret)
81{
Ben Skeggsa01ca782015-08-20 14:54:15 +100082 struct nouveau_cli *cli = (void *)abi16->device.object.client;
Ben Skeggsebb945a2012-07-20 08:17:34 +100083 mutex_unlock(&cli->mutex);
84 return ret;
85}
86
Ben Skeggsf58ddf92015-08-20 14:54:16 +100087s32
Ben Skeggsebb945a2012-07-20 08:17:34 +100088nouveau_abi16_swclass(struct nouveau_drm *drm)
89{
Ben Skeggs1167c6b2016-05-18 13:57:42 +100090 switch (drm->client.device.info.family) {
Ben Skeggs967e7bd2014-08-10 04:10:22 +100091 case NV_DEVICE_INFO_V0_TNT:
Ben Skeggs08f76332015-11-08 10:18:19 +100092 return NVIF_CLASS_SW_NV04;
Ben Skeggs967e7bd2014-08-10 04:10:22 +100093 case NV_DEVICE_INFO_V0_CELSIUS:
94 case NV_DEVICE_INFO_V0_KELVIN:
95 case NV_DEVICE_INFO_V0_RANKINE:
96 case NV_DEVICE_INFO_V0_CURIE:
Ben Skeggs08f76332015-11-08 10:18:19 +100097 return NVIF_CLASS_SW_NV10;
Ben Skeggs967e7bd2014-08-10 04:10:22 +100098 case NV_DEVICE_INFO_V0_TESLA:
Ben Skeggs08f76332015-11-08 10:18:19 +100099 return NVIF_CLASS_SW_NV50;
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000100 case NV_DEVICE_INFO_V0_FERMI:
101 case NV_DEVICE_INFO_V0_KEPLER:
102 case NV_DEVICE_INFO_V0_MAXWELL:
Ben Skeggs7f53abd2016-07-09 10:41:01 +1000103 case NV_DEVICE_INFO_V0_PASCAL:
Ben Skeggs08f76332015-11-08 10:18:19 +1000104 return NVIF_CLASS_SW_GF100;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000105 }
106
107 return 0x0000;
108}
109
110static void
111nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
112 struct nouveau_abi16_ntfy *ntfy)
113{
Ben Skeggsa01ca782015-08-20 14:54:15 +1000114 nvif_object_fini(&ntfy->object);
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000115 nvkm_mm_free(&chan->heap, &ntfy->node);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000116 list_del(&ntfy->head);
117 kfree(ntfy);
118}
119
120static void
121nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
122 struct nouveau_abi16_chan *chan)
123{
124 struct nouveau_abi16_ntfy *ntfy, *temp;
125
Marcin Slusarz2b77c1c2013-03-03 18:58:45 +0100126 /* wait for all activity to stop before releasing notify object, which
127 * may be still in use */
128 if (chan->chan && chan->ntfy)
129 nouveau_channel_idle(chan->chan);
130
Ben Skeggsebb945a2012-07-20 08:17:34 +1000131 /* cleanup notifier state */
132 list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
133 nouveau_abi16_ntfy_fini(chan, ntfy);
134 }
135
136 if (chan->ntfy) {
137 nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma);
Maarten Lankhorst198c14a2013-06-27 13:38:20 +0200138 nouveau_bo_unpin(chan->ntfy);
David Herrmann55fb74a2013-10-02 10:15:17 +0200139 drm_gem_object_unreference_unlocked(&chan->ntfy->gem);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000140 }
141
142 if (chan->heap.block_size)
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000143 nvkm_mm_fini(&chan->heap);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000144
145 /* destroy channel object, all children will be killed too */
146 if (chan->chan) {
Ben Skeggsfbd58eb2015-08-20 14:54:22 +1000147 nouveau_channel_idle(chan->chan);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000148 nouveau_channel_del(&chan->chan);
149 }
150
151 list_del(&chan->head);
152 kfree(chan);
153}
154
155void
156nouveau_abi16_fini(struct nouveau_abi16 *abi16)
157{
Ben Skeggsa01ca782015-08-20 14:54:15 +1000158 struct nouveau_cli *cli = (void *)abi16->device.object.client;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000159 struct nouveau_abi16_chan *chan, *temp;
160
161 /* cleanup channels */
162 list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
163 nouveau_abi16_chan_fini(abi16, chan);
164 }
165
166 /* destroy the device object */
Ben Skeggs0ad72862014-08-10 04:10:22 +1000167 nvif_device_fini(&abi16->device);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000168
169 kfree(cli->abi16);
170 cli->abi16 = NULL;
171}
Ben Skeggs2a259a32012-05-08 10:24:27 +1000172
173int
174nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
175{
Ben Skeggsfa2bade2014-08-10 04:10:22 +1000176 struct nouveau_cli *cli = nouveau_cli(file_priv);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000177 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs1167c6b2016-05-18 13:57:42 +1000178 struct nvif_device *device = &drm->client.device;
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000179 struct nvkm_gr *gr = nvxx_gr(device);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000180 struct drm_nouveau_getparam *getparam = data;
181
182 switch (getparam->param) {
183 case NOUVEAU_GETPARAM_CHIPSET_ID:
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000184 getparam->value = device->info.chipset;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000185 break;
186 case NOUVEAU_GETPARAM_PCI_VENDOR:
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000187 if (nvxx_device(device)->func->pci)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900188 getparam->value = dev->pdev->vendor;
189 else
190 getparam->value = 0;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000191 break;
192 case NOUVEAU_GETPARAM_PCI_DEVICE:
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000193 if (nvxx_device(device)->func->pci)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900194 getparam->value = dev->pdev->device;
195 else
196 getparam->value = 0;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000197 break;
198 case NOUVEAU_GETPARAM_BUS_TYPE:
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000199 if (!nvxx_device(device)->func->pci)
Alexandre Courbot420b9462014-02-17 15:17:26 +0900200 getparam->value = 3;
201 else
Daniel Vetter2ce02642017-01-25 07:26:52 +0100202 if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP))
Ben Skeggs2a259a32012-05-08 10:24:27 +1000203 getparam->value = 0;
204 else
205 if (!pci_is_pcie(dev->pdev))
206 getparam->value = 1;
207 else
208 getparam->value = 2;
209 break;
210 case NOUVEAU_GETPARAM_FB_SIZE:
Ben Skeggsebb945a2012-07-20 08:17:34 +1000211 getparam->value = drm->gem.vram_available;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000212 break;
213 case NOUVEAU_GETPARAM_AGP_SIZE:
Ben Skeggsebb945a2012-07-20 08:17:34 +1000214 getparam->value = drm->gem.gart_available;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000215 break;
216 case NOUVEAU_GETPARAM_VM_VRAM_BASE:
217 getparam->value = 0; /* deprecated */
218 break;
219 case NOUVEAU_GETPARAM_PTIMER_TIME:
Ben Skeggs56f67dc2015-08-20 14:54:10 +1000220 getparam->value = nvif_device_time(device);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000221 break;
222 case NOUVEAU_GETPARAM_HAS_BO_USAGE:
223 getparam->value = 1;
224 break;
225 case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
226 getparam->value = 1;
227 break;
228 case NOUVEAU_GETPARAM_GRAPH_UNITS:
Ben Skeggsc85ee6c2015-08-20 14:54:22 +1000229 getparam->value = nvkm_gr_units(gr);
Christoph Bumiller7e22e712013-03-27 22:16:54 +0100230 break;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000231 default:
Ben Skeggs9ad97ed2015-08-20 14:54:13 +1000232 NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000233 return -EINVAL;
234 }
235
236 return 0;
237}
238
239int
240nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS)
241{
242 return -EINVAL;
243}
244
245int
246nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
247{
Ben Skeggs2a259a32012-05-08 10:24:27 +1000248 struct drm_nouveau_channel_alloc *init = data;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000249 struct nouveau_cli *cli = nouveau_cli(file_priv);
250 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs09433f22015-11-03 10:17:49 +1000251 struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000252 struct nouveau_abi16_chan *chan;
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000253 struct nvif_device *device;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000254 int ret;
255
Ben Skeggsebb945a2012-07-20 08:17:34 +1000256 if (unlikely(!abi16))
257 return -ENOMEM;
Marcin Slusarzbf7e4382012-11-11 20:00:09 +0100258
259 if (!drm->channel)
260 return nouveau_abi16_put(abi16, -ENODEV);
261
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000262 device = &abi16->device;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000263
Ben Skeggs49469802012-11-22 13:43:55 +1000264 /* hack to allow channel engine type specification on kepler */
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000265 if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
Ben Skeggs49469802012-11-22 13:43:55 +1000266 if (init->fb_ctxdma_handle != ~0)
Ben Skeggs1f5ff7f2016-03-11 13:09:28 +1000267 init->fb_ctxdma_handle = NVA06F_V0_ENGINE_GR;
268 else {
269 init->fb_ctxdma_handle = 0;
270#define _(A,B) if (init->tt_ctxdma_handle & (A)) init->fb_ctxdma_handle |= (B)
271 _(0x01, NVA06F_V0_ENGINE_GR);
272 _(0x02, NVA06F_V0_ENGINE_MSPDEC);
273 _(0x04, NVA06F_V0_ENGINE_MSPPP);
274 _(0x08, NVA06F_V0_ENGINE_MSVLD);
275 _(0x10, NVA06F_V0_ENGINE_CE0);
276 _(0x20, NVA06F_V0_ENGINE_CE1);
277 _(0x40, NVA06F_V0_ENGINE_MSENC);
278#undef _
279 }
Ben Skeggs49469802012-11-22 13:43:55 +1000280
281 /* allow flips to be executed if this is a graphics channel */
282 init->tt_ctxdma_handle = 0;
Ben Skeggs1f5ff7f2016-03-11 13:09:28 +1000283 if (init->fb_ctxdma_handle == NVA06F_V0_ENGINE_GR)
Ben Skeggs49469802012-11-22 13:43:55 +1000284 init->tt_ctxdma_handle = 1;
285 }
286
287 if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
288 return nouveau_abi16_put(abi16, -EINVAL);
289
Ben Skeggsebb945a2012-07-20 08:17:34 +1000290 /* allocate "abi16 channel" data and make up a handle for it */
Ben Skeggsebb945a2012-07-20 08:17:34 +1000291 chan = kzalloc(sizeof(*chan), GFP_KERNEL);
292 if (!chan)
293 return nouveau_abi16_put(abi16, -ENOMEM);
294
295 INIT_LIST_HEAD(&chan->notifiers);
296 list_add(&chan->head, &abi16->channels);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000297
298 /* create channel object and initialise dma and fence management */
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000299 ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle,
Ben Skeggsebb945a2012-07-20 08:17:34 +1000300 init->tt_ctxdma_handle, &chan->chan);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000301 if (ret)
Ben Skeggsebb945a2012-07-20 08:17:34 +1000302 goto done;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000303
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000304 init->channel = chan->chan->chid;
305
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000306 if (device->info.family >= NV_DEVICE_INFO_V0_TESLA)
Ben Skeggsebb945a2012-07-20 08:17:34 +1000307 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
308 NOUVEAU_GEM_DOMAIN_GART;
309 else
310 if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM)
Ben Skeggs2a259a32012-05-08 10:24:27 +1000311 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000312 else
313 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000314
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000315 if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
Ben Skeggs2a259a32012-05-08 10:24:27 +1000316 init->subchan[0].handle = 0x00000000;
317 init->subchan[0].grclass = 0x0000;
Ben Skeggsf45f55c42014-08-10 04:10:23 +1000318 init->subchan[1].handle = chan->chan->nvsw.handle;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000319 init->subchan[1].grclass = 0x506e;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000320 init->nr_subchan = 2;
321 }
322
323 /* Named memory object area */
Ben Skeggsfc1b0a02016-05-24 17:29:55 +1000324 ret = nouveau_gem_new(cli, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
Ben Skeggsebb945a2012-07-20 08:17:34 +1000325 0, 0, &chan->ntfy);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000326 if (ret == 0)
Ben Skeggsad76b3f2014-11-10 11:24:27 +1000327 ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT, false);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000328 if (ret)
329 goto done;
330
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000331 if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000332 ret = nouveau_bo_vma_add(chan->ntfy, cli->vm,
Ben Skeggsebb945a2012-07-20 08:17:34 +1000333 &chan->ntfy_vma);
334 if (ret)
335 goto done;
336 }
337
David Herrmann55fb74a2013-10-02 10:15:17 +0200338 ret = drm_gem_handle_create(file_priv, &chan->ntfy->gem,
Ben Skeggsebb945a2012-07-20 08:17:34 +1000339 &init->notifier_handle);
340 if (ret)
341 goto done;
342
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000343 ret = nvkm_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000344done:
345 if (ret)
346 nouveau_abi16_chan_fini(abi16, chan);
347 return nouveau_abi16_put(abi16, ret);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000348}
349
Ben Skeggsa4e610b2014-08-10 04:10:23 +1000350static struct nouveau_abi16_chan *
351nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel)
352{
353 struct nouveau_abi16_chan *chan;
354
355 list_for_each_entry(chan, &abi16->channels, head) {
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000356 if (chan->chan->chid == channel)
Ben Skeggsa4e610b2014-08-10 04:10:23 +1000357 return chan;
358 }
359
360 return NULL;
361}
Ben Skeggsebb945a2012-07-20 08:17:34 +1000362
Ben Skeggs2a259a32012-05-08 10:24:27 +1000363int
Ben Skeggs2621a412015-11-03 11:21:43 +1000364nouveau_abi16_usif(struct drm_file *file_priv, void *data, u32 size)
365{
366 union {
367 struct nvif_ioctl_v0 v0;
368 } *args = data;
369 struct nouveau_abi16_chan *chan;
370 struct nouveau_abi16 *abi16;
Ben Skeggsf01c4e62015-11-09 09:21:27 +1000371 int ret = -ENOSYS;
Ben Skeggs2621a412015-11-03 11:21:43 +1000372
Ben Skeggsf01c4e62015-11-09 09:21:27 +1000373 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
Ben Skeggs2621a412015-11-03 11:21:43 +1000374 switch (args->v0.type) {
375 case NVIF_IOCTL_V0_NEW:
376 case NVIF_IOCTL_V0_MTHD:
377 case NVIF_IOCTL_V0_SCLASS:
378 break;
379 default:
380 return -EACCES;
381 }
382 } else
383 return ret;
384
385 if (!(abi16 = nouveau_abi16(file_priv)))
386 return -ENOMEM;
387
388 if (args->v0.token != ~0ULL) {
389 if (!(chan = nouveau_abi16_chan(abi16, args->v0.token)))
390 return -EINVAL;
391 args->v0.object = nvif_handle(&chan->chan->user);
392 args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
393 return 0;
394 }
395
396 args->v0.object = nvif_handle(&abi16->device.object);
397 args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
398 return 0;
399}
400
401int
Ben Skeggs2a259a32012-05-08 10:24:27 +1000402nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
403{
404 struct drm_nouveau_channel_free *req = data;
Ben Skeggs09433f22015-11-03 10:17:49 +1000405 struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000406 struct nouveau_abi16_chan *chan;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000407
Ben Skeggsebb945a2012-07-20 08:17:34 +1000408 if (unlikely(!abi16))
409 return -ENOMEM;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000410
Ben Skeggsa4e610b2014-08-10 04:10:23 +1000411 chan = nouveau_abi16_chan(abi16, req->channel);
412 if (!chan)
413 return nouveau_abi16_put(abi16, -ENOENT);
414 nouveau_abi16_chan_fini(abi16, chan);
415 return nouveau_abi16_put(abi16, 0);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000416}
417
418int
419nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
420{
421 struct drm_nouveau_grobj_alloc *init = data;
Ben Skeggs09433f22015-11-03 10:17:49 +1000422 struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
Ben Skeggsa01ca782015-08-20 14:54:15 +1000423 struct nouveau_abi16_chan *chan;
424 struct nouveau_abi16_ntfy *ntfy;
Ben Skeggsa4e610b2014-08-10 04:10:23 +1000425 struct nvif_client *client;
Ben Skeggs41a63402015-08-20 14:54:16 +1000426 struct nvif_sclass *sclass;
Ben Skeggsf58ddf92015-08-20 14:54:16 +1000427 s32 oclass = 0;
428 int ret, i;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000429
Ben Skeggsebb945a2012-07-20 08:17:34 +1000430 if (unlikely(!abi16))
431 return -ENOMEM;
432
Ben Skeggs2a259a32012-05-08 10:24:27 +1000433 if (init->handle == ~0)
Ben Skeggsebb945a2012-07-20 08:17:34 +1000434 return nouveau_abi16_put(abi16, -EINVAL);
Ben Skeggsa01ca782015-08-20 14:54:15 +1000435 client = abi16->device.object.client;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000436
Ben Skeggsa01ca782015-08-20 14:54:15 +1000437 chan = nouveau_abi16_chan(abi16, init->channel);
438 if (!chan)
439 return nouveau_abi16_put(abi16, -ENOENT);
440
Ben Skeggs41a63402015-08-20 14:54:16 +1000441 ret = nvif_object_sclass_get(&chan->chan->user, &sclass);
Ben Skeggsf58ddf92015-08-20 14:54:16 +1000442 if (ret < 0)
443 return nouveau_abi16_put(abi16, ret);
444
445 if ((init->class & 0x00ff) == 0x006e) {
446 /* nvsw: compatibility with older 0x*6e class identifier */
447 for (i = 0; !oclass && i < ret; i++) {
Ben Skeggs41a63402015-08-20 14:54:16 +1000448 switch (sclass[i].oclass) {
Ben Skeggs08f76332015-11-08 10:18:19 +1000449 case NVIF_CLASS_SW_NV04:
450 case NVIF_CLASS_SW_NV10:
451 case NVIF_CLASS_SW_NV50:
452 case NVIF_CLASS_SW_GF100:
Ben Skeggs41a63402015-08-20 14:54:16 +1000453 oclass = sclass[i].oclass;
Ben Skeggsf58ddf92015-08-20 14:54:16 +1000454 break;
455 default:
456 break;
457 }
458 }
459 } else
460 if ((init->class & 0x00ff) == 0x00b1) {
461 /* msvld: compatibility with incorrect version exposure */
462 for (i = 0; i < ret; i++) {
Ben Skeggs41a63402015-08-20 14:54:16 +1000463 if ((sclass[i].oclass & 0x00ff) == 0x00b1) {
464 oclass = sclass[i].oclass;
Ben Skeggsf58ddf92015-08-20 14:54:16 +1000465 break;
466 }
467 }
468 } else
469 if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */
470 /* mspdec: compatibility with incorrect version exposure */
471 for (i = 0; i < ret; i++) {
Ben Skeggs41a63402015-08-20 14:54:16 +1000472 if ((sclass[i].oclass & 0x00ff) == 0x00b2) {
473 oclass = sclass[i].oclass;
Ben Skeggsf58ddf92015-08-20 14:54:16 +1000474 break;
475 }
476 }
477 } else
478 if ((init->class & 0x00ff) == 0x00b3) { /* msppp */
479 /* msppp: compatibility with incorrect version exposure */
480 for (i = 0; i < ret; i++) {
Ben Skeggs41a63402015-08-20 14:54:16 +1000481 if ((sclass[i].oclass & 0x00ff) == 0x00b3) {
482 oclass = sclass[i].oclass;
Ben Skeggsf58ddf92015-08-20 14:54:16 +1000483 break;
484 }
485 }
486 } else {
487 oclass = init->class;
488 }
489
Ben Skeggs41a63402015-08-20 14:54:16 +1000490 nvif_object_sclass_put(&sclass);
Ben Skeggsf58ddf92015-08-20 14:54:16 +1000491 if (!oclass)
492 return nouveau_abi16_put(abi16, -EINVAL);
493
Ben Skeggsa01ca782015-08-20 14:54:15 +1000494 ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
495 if (!ntfy)
496 return nouveau_abi16_put(abi16, -ENOMEM);
497
498 list_add(&ntfy->head, &chan->notifiers);
499
500 client->route = NVDRM_OBJECT_ABI16;
Ben Skeggsf58ddf92015-08-20 14:54:16 +1000501 ret = nvif_object_init(&chan->chan->user, init->handle, oclass,
Ben Skeggsa01ca782015-08-20 14:54:15 +1000502 NULL, 0, &ntfy->object);
503 client->route = NVDRM_OBJECT_NVIF;
504
505 if (ret)
506 nouveau_abi16_ntfy_fini(chan, ntfy);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000507 return nouveau_abi16_put(abi16, ret);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000508}
509
510int
511nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
512{
Ben Skeggsebb945a2012-07-20 08:17:34 +1000513 struct drm_nouveau_notifierobj_alloc *info = data;
514 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs09433f22015-11-03 10:17:49 +1000515 struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
Ben Skeggsa4e610b2014-08-10 04:10:23 +1000516 struct nouveau_abi16_chan *chan;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000517 struct nouveau_abi16_ntfy *ntfy;
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000518 struct nvif_device *device = &abi16->device;
Ben Skeggs3bdda042014-08-10 04:10:23 +1000519 struct nvif_client *client;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000520 struct nv_dma_v0 args = {};
Ben Skeggs2a259a32012-05-08 10:24:27 +1000521 int ret;
522
Ben Skeggsebb945a2012-07-20 08:17:34 +1000523 if (unlikely(!abi16))
524 return -ENOMEM;
525
Ben Skeggs2a259a32012-05-08 10:24:27 +1000526 /* completely unnecessary for these chipsets... */
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000527 if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI))
Ben Skeggsebb945a2012-07-20 08:17:34 +1000528 return nouveau_abi16_put(abi16, -EINVAL);
Ben Skeggsa01ca782015-08-20 14:54:15 +1000529 client = abi16->device.object.client;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000530
Ben Skeggsa4e610b2014-08-10 04:10:23 +1000531 chan = nouveau_abi16_chan(abi16, info->channel);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000532 if (!chan)
533 return nouveau_abi16_put(abi16, -ENOENT);
534
535 ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
536 if (!ntfy)
537 return nouveau_abi16_put(abi16, -ENOMEM);
538
539 list_add(&ntfy->head, &chan->notifiers);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000540
Ben Skeggsbe83cd42015-01-14 15:36:34 +1000541 ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
542 &ntfy->node);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000543 if (ret)
544 goto done;
545
Ben Skeggsa01ca782015-08-20 14:54:15 +1000546 args.start = ntfy->node->offset;
547 args.limit = ntfy->node->offset + ntfy->node->length - 1;
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000548 if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
Ben Skeggsa01ca782015-08-20 14:54:15 +1000549 args.target = NV_DMA_V0_TARGET_VM;
550 args.access = NV_DMA_V0_ACCESS_VM;
551 args.start += chan->ntfy_vma.offset;
552 args.limit += chan->ntfy_vma.offset;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000553 } else
Ben Skeggs340b0e72015-08-20 14:54:23 +1000554 if (drm->agp.bridge) {
Ben Skeggsa01ca782015-08-20 14:54:15 +1000555 args.target = NV_DMA_V0_TARGET_AGP;
556 args.access = NV_DMA_V0_ACCESS_RDWR;
557 args.start += drm->agp.base + chan->ntfy->bo.offset;
558 args.limit += drm->agp.base + chan->ntfy->bo.offset;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000559 } else {
Ben Skeggsa01ca782015-08-20 14:54:15 +1000560 args.target = NV_DMA_V0_TARGET_VM;
561 args.access = NV_DMA_V0_ACCESS_RDWR;
562 args.start += chan->ntfy->bo.offset;
563 args.limit += chan->ntfy->bo.offset;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000564 }
565
Ben Skeggsa01ca782015-08-20 14:54:15 +1000566 client->route = NVDRM_OBJECT_ABI16;
567 client->super = true;
568 ret = nvif_object_init(&chan->chan->user, info->handle,
569 NV_DMA_IN_MEMORY, &args, sizeof(args),
570 &ntfy->object);
Ben Skeggs3bdda042014-08-10 04:10:23 +1000571 client->super = false;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000572 client->route = NVDRM_OBJECT_NVIF;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000573 if (ret)
574 goto done;
575
Bob Gleitsmannc1ccaa62014-01-06 08:59:07 +1000576 info->offset = ntfy->node->offset;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000577done:
578 if (ret)
579 nouveau_abi16_ntfy_fini(chan, ntfy);
580 return nouveau_abi16_put(abi16, ret);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000581}
582
583int
584nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
585{
Ben Skeggsebb945a2012-07-20 08:17:34 +1000586 struct drm_nouveau_gpuobj_free *fini = data;
Ben Skeggs09433f22015-11-03 10:17:49 +1000587 struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
Ben Skeggsa4e610b2014-08-10 04:10:23 +1000588 struct nouveau_abi16_chan *chan;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000589 struct nouveau_abi16_ntfy *ntfy;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000590 int ret = -ENOENT;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000591
Ben Skeggsebb945a2012-07-20 08:17:34 +1000592 if (unlikely(!abi16))
593 return -ENOMEM;
Ben Skeggs2a259a32012-05-08 10:24:27 +1000594
Ben Skeggsa4e610b2014-08-10 04:10:23 +1000595 chan = nouveau_abi16_chan(abi16, fini->channel);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000596 if (!chan)
Ben Skeggsa01ca782015-08-20 14:54:15 +1000597 return nouveau_abi16_put(abi16, -EINVAL);
Ben Skeggsebb945a2012-07-20 08:17:34 +1000598
599 /* synchronize with the user channel and destroy the gpu object */
600 nouveau_channel_idle(chan->chan);
601
Ben Skeggsebb945a2012-07-20 08:17:34 +1000602 list_for_each_entry(ntfy, &chan->notifiers, head) {
Ben Skeggsa01ca782015-08-20 14:54:15 +1000603 if (ntfy->object.handle == fini->handle) {
604 nouveau_abi16_ntfy_fini(chan, ntfy);
605 ret = 0;
Ben Skeggsebb945a2012-07-20 08:17:34 +1000606 break;
607 }
608 }
609
Ben Skeggsa01ca782015-08-20 14:54:15 +1000610 return nouveau_abi16_put(abi16, ret);
Ben Skeggs2a259a32012-05-08 10:24:27 +1000611}