Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  */
0023 
0024 #include <nvif/client.h>
0025 #include <nvif/driver.h>
0026 #include <nvif/fifo.h>
0027 #include <nvif/ioctl.h>
0028 #include <nvif/class.h>
0029 #include <nvif/cl0002.h>
0030 #include <nvif/cla06f.h>
0031 #include <nvif/unpack.h>
0032 
0033 #include "nouveau_drv.h"
0034 #include "nouveau_dma.h"
0035 #include "nouveau_gem.h"
0036 #include "nouveau_chan.h"
0037 #include "nouveau_abi16.h"
0038 #include "nouveau_vmm.h"
0039 
0040 static struct nouveau_abi16 *
0041 nouveau_abi16(struct drm_file *file_priv)
0042 {
0043     struct nouveau_cli *cli = nouveau_cli(file_priv);
0044     if (!cli->abi16) {
0045         struct nouveau_abi16 *abi16;
0046         cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
0047         if (cli->abi16) {
0048             struct nv_device_v0 args = {
0049                 .device = ~0ULL,
0050             };
0051 
0052             INIT_LIST_HEAD(&abi16->channels);
0053 
0054             /* allocate device object targeting client's default
0055              * device (ie. the one that belongs to the fd it
0056              * opened)
0057              */
0058             if (nvif_device_ctor(&cli->base.object, "abi16Device",
0059                          0, NV_DEVICE, &args, sizeof(args),
0060                          &abi16->device) == 0)
0061                 return cli->abi16;
0062 
0063             kfree(cli->abi16);
0064             cli->abi16 = NULL;
0065         }
0066     }
0067     return cli->abi16;
0068 }
0069 
0070 struct nouveau_abi16 *
0071 nouveau_abi16_get(struct drm_file *file_priv)
0072 {
0073     struct nouveau_cli *cli = nouveau_cli(file_priv);
0074     mutex_lock(&cli->mutex);
0075     if (nouveau_abi16(file_priv))
0076         return cli->abi16;
0077     mutex_unlock(&cli->mutex);
0078     return NULL;
0079 }
0080 
0081 int
0082 nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret)
0083 {
0084     struct nouveau_cli *cli = (void *)abi16->device.object.client;
0085     mutex_unlock(&cli->mutex);
0086     return ret;
0087 }
0088 
0089 s32
0090 nouveau_abi16_swclass(struct nouveau_drm *drm)
0091 {
0092     switch (drm->client.device.info.family) {
0093     case NV_DEVICE_INFO_V0_TNT:
0094         return NVIF_CLASS_SW_NV04;
0095     case NV_DEVICE_INFO_V0_CELSIUS:
0096     case NV_DEVICE_INFO_V0_KELVIN:
0097     case NV_DEVICE_INFO_V0_RANKINE:
0098     case NV_DEVICE_INFO_V0_CURIE:
0099         return NVIF_CLASS_SW_NV10;
0100     case NV_DEVICE_INFO_V0_TESLA:
0101         return NVIF_CLASS_SW_NV50;
0102     case NV_DEVICE_INFO_V0_FERMI:
0103     case NV_DEVICE_INFO_V0_KEPLER:
0104     case NV_DEVICE_INFO_V0_MAXWELL:
0105     case NV_DEVICE_INFO_V0_PASCAL:
0106     case NV_DEVICE_INFO_V0_VOLTA:
0107         return NVIF_CLASS_SW_GF100;
0108     }
0109 
0110     return 0x0000;
0111 }
0112 
0113 static void
0114 nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
0115             struct nouveau_abi16_ntfy *ntfy)
0116 {
0117     nvif_object_dtor(&ntfy->object);
0118     nvkm_mm_free(&chan->heap, &ntfy->node);
0119     list_del(&ntfy->head);
0120     kfree(ntfy);
0121 }
0122 
0123 static void
0124 nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
0125             struct nouveau_abi16_chan *chan)
0126 {
0127     struct nouveau_abi16_ntfy *ntfy, *temp;
0128 
0129     /* wait for all activity to stop before cleaning up */
0130     if (chan->chan)
0131         nouveau_channel_idle(chan->chan);
0132 
0133     /* cleanup notifier state */
0134     list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
0135         nouveau_abi16_ntfy_fini(chan, ntfy);
0136     }
0137 
0138     if (chan->ntfy) {
0139         nouveau_vma_del(&chan->ntfy_vma);
0140         nouveau_bo_unpin(chan->ntfy);
0141         drm_gem_object_put(&chan->ntfy->bo.base);
0142     }
0143 
0144     if (chan->heap.block_size)
0145         nvkm_mm_fini(&chan->heap);
0146 
0147     /* destroy channel object, all children will be killed too */
0148     if (chan->chan) {
0149         nvif_object_dtor(&chan->ce);
0150         nouveau_channel_del(&chan->chan);
0151     }
0152 
0153     list_del(&chan->head);
0154     kfree(chan);
0155 }
0156 
0157 void
0158 nouveau_abi16_fini(struct nouveau_abi16 *abi16)
0159 {
0160     struct nouveau_cli *cli = (void *)abi16->device.object.client;
0161     struct nouveau_abi16_chan *chan, *temp;
0162 
0163     /* cleanup channels */
0164     list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
0165         nouveau_abi16_chan_fini(abi16, chan);
0166     }
0167 
0168     /* destroy the device object */
0169     nvif_device_dtor(&abi16->device);
0170 
0171     kfree(cli->abi16);
0172     cli->abi16 = NULL;
0173 }
0174 
0175 int
0176 nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
0177 {
0178     struct nouveau_cli *cli = nouveau_cli(file_priv);
0179     struct nouveau_drm *drm = nouveau_drm(dev);
0180     struct nvif_device *device = &drm->client.device;
0181     struct nvkm_gr *gr = nvxx_gr(device);
0182     struct drm_nouveau_getparam *getparam = data;
0183     struct pci_dev *pdev = to_pci_dev(dev->dev);
0184 
0185     switch (getparam->param) {
0186     case NOUVEAU_GETPARAM_CHIPSET_ID:
0187         getparam->value = device->info.chipset;
0188         break;
0189     case NOUVEAU_GETPARAM_PCI_VENDOR:
0190         if (device->info.platform != NV_DEVICE_INFO_V0_SOC)
0191             getparam->value = pdev->vendor;
0192         else
0193             getparam->value = 0;
0194         break;
0195     case NOUVEAU_GETPARAM_PCI_DEVICE:
0196         if (device->info.platform != NV_DEVICE_INFO_V0_SOC)
0197             getparam->value = pdev->device;
0198         else
0199             getparam->value = 0;
0200         break;
0201     case NOUVEAU_GETPARAM_BUS_TYPE:
0202         switch (device->info.platform) {
0203         case NV_DEVICE_INFO_V0_AGP : getparam->value = 0; break;
0204         case NV_DEVICE_INFO_V0_PCI : getparam->value = 1; break;
0205         case NV_DEVICE_INFO_V0_PCIE: getparam->value = 2; break;
0206         case NV_DEVICE_INFO_V0_SOC : getparam->value = 3; break;
0207         case NV_DEVICE_INFO_V0_IGP :
0208             if (!pci_is_pcie(pdev))
0209                 getparam->value = 1;
0210             else
0211                 getparam->value = 2;
0212             break;
0213         default:
0214             WARN_ON(1);
0215             break;
0216         }
0217         break;
0218     case NOUVEAU_GETPARAM_FB_SIZE:
0219         getparam->value = drm->gem.vram_available;
0220         break;
0221     case NOUVEAU_GETPARAM_AGP_SIZE:
0222         getparam->value = drm->gem.gart_available;
0223         break;
0224     case NOUVEAU_GETPARAM_VM_VRAM_BASE:
0225         getparam->value = 0; /* deprecated */
0226         break;
0227     case NOUVEAU_GETPARAM_PTIMER_TIME:
0228         getparam->value = nvif_device_time(device);
0229         break;
0230     case NOUVEAU_GETPARAM_HAS_BO_USAGE:
0231         getparam->value = 1;
0232         break;
0233     case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
0234         getparam->value = 1;
0235         break;
0236     case NOUVEAU_GETPARAM_GRAPH_UNITS:
0237         getparam->value = nvkm_gr_units(gr);
0238         break;
0239     default:
0240         NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
0241         return -EINVAL;
0242     }
0243 
0244     return 0;
0245 }
0246 
0247 int
0248 nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
0249 {
0250     struct drm_nouveau_channel_alloc *init = data;
0251     struct nouveau_cli *cli = nouveau_cli(file_priv);
0252     struct nouveau_drm *drm = nouveau_drm(dev);
0253     struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
0254     struct nouveau_abi16_chan *chan;
0255     struct nvif_device *device;
0256     u64 engine;
0257     int ret;
0258 
0259     if (unlikely(!abi16))
0260         return -ENOMEM;
0261 
0262     if (!drm->channel)
0263         return nouveau_abi16_put(abi16, -ENODEV);
0264 
0265     device = &abi16->device;
0266 
0267     /* hack to allow channel engine type specification on kepler */
0268     if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
0269         if (init->fb_ctxdma_handle == ~0) {
0270             switch (init->tt_ctxdma_handle) {
0271             case 0x01: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR    ; break;
0272             case 0x02: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSPDEC; break;
0273             case 0x04: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSPPP ; break;
0274             case 0x08: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSVLD ; break;
0275             case 0x30: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_CE    ; break;
0276             default:
0277                 return nouveau_abi16_put(abi16, -ENOSYS);
0278             }
0279         } else {
0280             engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR;
0281         }
0282 
0283         if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_CE)
0284             engine = nvif_fifo_runlist(device, engine);
0285         else
0286             engine = nvif_fifo_runlist_ce(device);
0287         init->fb_ctxdma_handle = engine;
0288         init->tt_ctxdma_handle = 0;
0289     }
0290 
0291     if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
0292         return nouveau_abi16_put(abi16, -EINVAL);
0293 
0294     /* allocate "abi16 channel" data and make up a handle for it */
0295     chan = kzalloc(sizeof(*chan), GFP_KERNEL);
0296     if (!chan)
0297         return nouveau_abi16_put(abi16, -ENOMEM);
0298 
0299     INIT_LIST_HEAD(&chan->notifiers);
0300     list_add(&chan->head, &abi16->channels);
0301 
0302     /* create channel object and initialise dma and fence management */
0303     ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle,
0304                   init->tt_ctxdma_handle, false, &chan->chan);
0305     if (ret)
0306         goto done;
0307 
0308     init->channel = chan->chan->chid;
0309 
0310     if (device->info.family >= NV_DEVICE_INFO_V0_TESLA)
0311         init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
0312                     NOUVEAU_GEM_DOMAIN_GART;
0313     else
0314     if (chan->chan->push.buffer->bo.resource->mem_type == TTM_PL_VRAM)
0315         init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
0316     else
0317         init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
0318 
0319     if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
0320         init->subchan[0].handle = 0x00000000;
0321         init->subchan[0].grclass = 0x0000;
0322         init->subchan[1].handle = chan->chan->nvsw.handle;
0323         init->subchan[1].grclass = 0x506e;
0324         init->nr_subchan = 2;
0325     }
0326 
0327     /* Workaround "nvc0" gallium driver using classes it doesn't allocate on
0328      * Kepler and above.  NVKM no longer always sets CE_CTX_VALID as part of
0329      * channel init, now we know what that stuff actually is.
0330      *
0331      * Doesn't matter for Kepler/Pascal, CE context stored in NV_RAMIN.
0332      *
0333      * Userspace was fixed prior to adding Ampere support.
0334      */
0335     switch (device->info.family) {
0336     case NV_DEVICE_INFO_V0_VOLTA:
0337         ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar", 0, VOLTA_DMA_COPY_A,
0338                        NULL, 0, &chan->ce);
0339         if (ret)
0340             goto done;
0341         break;
0342     case NV_DEVICE_INFO_V0_TURING:
0343         ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar", 0, TURING_DMA_COPY_A,
0344                        NULL, 0, &chan->ce);
0345         if (ret)
0346             goto done;
0347         break;
0348     default:
0349         break;
0350     }
0351 
0352     /* Named memory object area */
0353     ret = nouveau_gem_new(cli, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
0354                   0, 0, &chan->ntfy);
0355     if (ret == 0)
0356         ret = nouveau_bo_pin(chan->ntfy, NOUVEAU_GEM_DOMAIN_GART,
0357                      false);
0358     if (ret)
0359         goto done;
0360 
0361     if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
0362         ret = nouveau_vma_new(chan->ntfy, chan->chan->vmm,
0363                       &chan->ntfy_vma);
0364         if (ret)
0365             goto done;
0366     }
0367 
0368     ret = drm_gem_handle_create(file_priv, &chan->ntfy->bo.base,
0369                     &init->notifier_handle);
0370     if (ret)
0371         goto done;
0372 
0373     ret = nvkm_mm_init(&chan->heap, 0, 0, PAGE_SIZE, 1);
0374 done:
0375     if (ret)
0376         nouveau_abi16_chan_fini(abi16, chan);
0377     return nouveau_abi16_put(abi16, ret);
0378 }
0379 
0380 static struct nouveau_abi16_chan *
0381 nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel)
0382 {
0383     struct nouveau_abi16_chan *chan;
0384 
0385     list_for_each_entry(chan, &abi16->channels, head) {
0386         if (chan->chan->chid == channel)
0387             return chan;
0388     }
0389 
0390     return NULL;
0391 }
0392 
0393 int
0394 nouveau_abi16_usif(struct drm_file *file_priv, void *data, u32 size)
0395 {
0396     union {
0397         struct nvif_ioctl_v0 v0;
0398     } *args = data;
0399     struct nouveau_abi16_chan *chan;
0400     struct nouveau_abi16 *abi16;
0401     int ret = -ENOSYS;
0402 
0403     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0404         switch (args->v0.type) {
0405         case NVIF_IOCTL_V0_NEW:
0406         case NVIF_IOCTL_V0_MTHD:
0407         case NVIF_IOCTL_V0_SCLASS:
0408             break;
0409         default:
0410             return -EACCES;
0411         }
0412     } else
0413         return ret;
0414 
0415     if (!(abi16 = nouveau_abi16(file_priv)))
0416         return -ENOMEM;
0417 
0418     if (args->v0.token != ~0ULL) {
0419         if (!(chan = nouveau_abi16_chan(abi16, args->v0.token)))
0420             return -EINVAL;
0421         args->v0.object = nvif_handle(&chan->chan->user);
0422         args->v0.owner  = NVIF_IOCTL_V0_OWNER_ANY;
0423         return 0;
0424     }
0425 
0426     args->v0.object = nvif_handle(&abi16->device.object);
0427     args->v0.owner  = NVIF_IOCTL_V0_OWNER_ANY;
0428     return 0;
0429 }
0430 
0431 int
0432 nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
0433 {
0434     struct drm_nouveau_channel_free *req = data;
0435     struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
0436     struct nouveau_abi16_chan *chan;
0437 
0438     if (unlikely(!abi16))
0439         return -ENOMEM;
0440 
0441     chan = nouveau_abi16_chan(abi16, req->channel);
0442     if (!chan)
0443         return nouveau_abi16_put(abi16, -ENOENT);
0444     nouveau_abi16_chan_fini(abi16, chan);
0445     return nouveau_abi16_put(abi16, 0);
0446 }
0447 
0448 int
0449 nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
0450 {
0451     struct drm_nouveau_grobj_alloc *init = data;
0452     struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
0453     struct nouveau_abi16_chan *chan;
0454     struct nouveau_abi16_ntfy *ntfy;
0455     struct nvif_client *client;
0456     struct nvif_sclass *sclass;
0457     s32 oclass = 0;
0458     int ret, i;
0459 
0460     if (unlikely(!abi16))
0461         return -ENOMEM;
0462 
0463     if (init->handle == ~0)
0464         return nouveau_abi16_put(abi16, -EINVAL);
0465     client = abi16->device.object.client;
0466 
0467     chan = nouveau_abi16_chan(abi16, init->channel);
0468     if (!chan)
0469         return nouveau_abi16_put(abi16, -ENOENT);
0470 
0471     ret = nvif_object_sclass_get(&chan->chan->user, &sclass);
0472     if (ret < 0)
0473         return nouveau_abi16_put(abi16, ret);
0474 
0475     if ((init->class & 0x00ff) == 0x006e) {
0476         /* nvsw: compatibility with older 0x*6e class identifier */
0477         for (i = 0; !oclass && i < ret; i++) {
0478             switch (sclass[i].oclass) {
0479             case NVIF_CLASS_SW_NV04:
0480             case NVIF_CLASS_SW_NV10:
0481             case NVIF_CLASS_SW_NV50:
0482             case NVIF_CLASS_SW_GF100:
0483                 oclass = sclass[i].oclass;
0484                 break;
0485             default:
0486                 break;
0487             }
0488         }
0489     } else
0490     if ((init->class & 0x00ff) == 0x00b1) {
0491         /* msvld: compatibility with incorrect version exposure */
0492         for (i = 0; i < ret; i++) {
0493             if ((sclass[i].oclass & 0x00ff) == 0x00b1) {
0494                 oclass = sclass[i].oclass;
0495                 break;
0496             }
0497         }
0498     } else
0499     if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */
0500         /* mspdec: compatibility with incorrect version exposure */
0501         for (i = 0; i < ret; i++) {
0502             if ((sclass[i].oclass & 0x00ff) == 0x00b2) {
0503                 oclass = sclass[i].oclass;
0504                 break;
0505             }
0506         }
0507     } else
0508     if ((init->class & 0x00ff) == 0x00b3) { /* msppp */
0509         /* msppp: compatibility with incorrect version exposure */
0510         for (i = 0; i < ret; i++) {
0511             if ((sclass[i].oclass & 0x00ff) == 0x00b3) {
0512                 oclass = sclass[i].oclass;
0513                 break;
0514             }
0515         }
0516     } else {
0517         oclass = init->class;
0518     }
0519 
0520     nvif_object_sclass_put(&sclass);
0521     if (!oclass)
0522         return nouveau_abi16_put(abi16, -EINVAL);
0523 
0524     ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
0525     if (!ntfy)
0526         return nouveau_abi16_put(abi16, -ENOMEM);
0527 
0528     list_add(&ntfy->head, &chan->notifiers);
0529 
0530     client->route = NVDRM_OBJECT_ABI16;
0531     ret = nvif_object_ctor(&chan->chan->user, "abi16EngObj", init->handle,
0532                    oclass, NULL, 0, &ntfy->object);
0533     client->route = NVDRM_OBJECT_NVIF;
0534 
0535     if (ret)
0536         nouveau_abi16_ntfy_fini(chan, ntfy);
0537     return nouveau_abi16_put(abi16, ret);
0538 }
0539 
0540 int
0541 nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
0542 {
0543     struct drm_nouveau_notifierobj_alloc *info = data;
0544     struct nouveau_drm *drm = nouveau_drm(dev);
0545     struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
0546     struct nouveau_abi16_chan *chan;
0547     struct nouveau_abi16_ntfy *ntfy;
0548     struct nvif_device *device = &abi16->device;
0549     struct nvif_client *client;
0550     struct nv_dma_v0 args = {};
0551     int ret;
0552 
0553     if (unlikely(!abi16))
0554         return -ENOMEM;
0555 
0556     /* completely unnecessary for these chipsets... */
0557     if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI))
0558         return nouveau_abi16_put(abi16, -EINVAL);
0559     client = abi16->device.object.client;
0560 
0561     chan = nouveau_abi16_chan(abi16, info->channel);
0562     if (!chan)
0563         return nouveau_abi16_put(abi16, -ENOENT);
0564 
0565     ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
0566     if (!ntfy)
0567         return nouveau_abi16_put(abi16, -ENOMEM);
0568 
0569     list_add(&ntfy->head, &chan->notifiers);
0570 
0571     ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
0572                &ntfy->node);
0573     if (ret)
0574         goto done;
0575 
0576     args.start = ntfy->node->offset;
0577     args.limit = ntfy->node->offset + ntfy->node->length - 1;
0578     if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
0579         args.target = NV_DMA_V0_TARGET_VM;
0580         args.access = NV_DMA_V0_ACCESS_VM;
0581         args.start += chan->ntfy_vma->addr;
0582         args.limit += chan->ntfy_vma->addr;
0583     } else
0584     if (drm->agp.bridge) {
0585         args.target = NV_DMA_V0_TARGET_AGP;
0586         args.access = NV_DMA_V0_ACCESS_RDWR;
0587         args.start += drm->agp.base + chan->ntfy->offset;
0588         args.limit += drm->agp.base + chan->ntfy->offset;
0589     } else {
0590         args.target = NV_DMA_V0_TARGET_VM;
0591         args.access = NV_DMA_V0_ACCESS_RDWR;
0592         args.start += chan->ntfy->offset;
0593         args.limit += chan->ntfy->offset;
0594     }
0595 
0596     client->route = NVDRM_OBJECT_ABI16;
0597     ret = nvif_object_ctor(&chan->chan->user, "abi16Ntfy", info->handle,
0598                    NV_DMA_IN_MEMORY, &args, sizeof(args),
0599                    &ntfy->object);
0600     client->route = NVDRM_OBJECT_NVIF;
0601     if (ret)
0602         goto done;
0603 
0604     info->offset = ntfy->node->offset;
0605 done:
0606     if (ret)
0607         nouveau_abi16_ntfy_fini(chan, ntfy);
0608     return nouveau_abi16_put(abi16, ret);
0609 }
0610 
0611 int
0612 nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
0613 {
0614     struct drm_nouveau_gpuobj_free *fini = data;
0615     struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
0616     struct nouveau_abi16_chan *chan;
0617     struct nouveau_abi16_ntfy *ntfy;
0618     int ret = -ENOENT;
0619 
0620     if (unlikely(!abi16))
0621         return -ENOMEM;
0622 
0623     chan = nouveau_abi16_chan(abi16, fini->channel);
0624     if (!chan)
0625         return nouveau_abi16_put(abi16, -EINVAL);
0626 
0627     /* synchronize with the user channel and destroy the gpu object */
0628     nouveau_channel_idle(chan->chan);
0629 
0630     list_for_each_entry(ntfy, &chan->notifiers, head) {
0631         if (ntfy->object.handle == fini->handle) {
0632             nouveau_abi16_ntfy_fini(chan, ntfy);
0633             ret = 0;
0634             break;
0635         }
0636     }
0637 
0638     return nouveau_abi16_put(abi16, ret);
0639 }