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