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> 26a4e610b5SBen Skeggs #include <nvif/ioctl.h> 27fdb751efSBen Skeggs #include <nvif/class.h> 282a259a3dSBen Skeggs 29ebb945a9SBen Skeggs #include "nouveau_drm.h" 302a259a3dSBen Skeggs #include "nouveau_dma.h" 31ebb945a9SBen Skeggs #include "nouveau_gem.h" 32ebb945a9SBen Skeggs #include "nouveau_chan.h" 332a259a3dSBen Skeggs #include "nouveau_abi16.h" 34ebb945a9SBen Skeggs 35ebb945a9SBen Skeggs struct nouveau_abi16 * 36ebb945a9SBen Skeggs nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev) 37ebb945a9SBen Skeggs { 38ebb945a9SBen Skeggs struct nouveau_cli *cli = nouveau_cli(file_priv); 39ebb945a9SBen Skeggs mutex_lock(&cli->mutex); 40ebb945a9SBen Skeggs if (!cli->abi16) { 41ebb945a9SBen Skeggs struct nouveau_abi16 *abi16; 42ebb945a9SBen Skeggs cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL); 43ebb945a9SBen Skeggs if (cli->abi16) { 44586491e6SBen Skeggs struct nv_device_v0 args = { 45586491e6SBen Skeggs .device = ~0ULL, 46586491e6SBen Skeggs }; 47586491e6SBen Skeggs 48ebb945a9SBen Skeggs INIT_LIST_HEAD(&abi16->channels); 49ebb945a9SBen Skeggs 50ebb945a9SBen Skeggs /* allocate device object targeting client's default 51ebb945a9SBen Skeggs * device (ie. the one that belongs to the fd it 52ebb945a9SBen Skeggs * opened) 53ebb945a9SBen Skeggs */ 54*fcf3f91cSBen Skeggs if (nvif_device_init(&cli->base.object, 0, NV_DEVICE, 55586491e6SBen Skeggs &args, sizeof(args), 560ad72863SBen Skeggs &abi16->device) == 0) 57ebb945a9SBen Skeggs return cli->abi16; 58ebb945a9SBen Skeggs 59ebb945a9SBen Skeggs kfree(cli->abi16); 60ebb945a9SBen Skeggs cli->abi16 = NULL; 61ebb945a9SBen Skeggs } 62ebb945a9SBen Skeggs 63ebb945a9SBen Skeggs mutex_unlock(&cli->mutex); 64ebb945a9SBen Skeggs } 65ebb945a9SBen Skeggs return cli->abi16; 66ebb945a9SBen Skeggs } 67ebb945a9SBen Skeggs 68ebb945a9SBen Skeggs int 69ebb945a9SBen Skeggs nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret) 70ebb945a9SBen Skeggs { 71a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)abi16->device.object.client; 72ebb945a9SBen Skeggs mutex_unlock(&cli->mutex); 73ebb945a9SBen Skeggs return ret; 74ebb945a9SBen Skeggs } 75ebb945a9SBen Skeggs 76f58ddf95SBen Skeggs s32 77ebb945a9SBen Skeggs nouveau_abi16_swclass(struct nouveau_drm *drm) 78ebb945a9SBen Skeggs { 79967e7bdeSBen Skeggs switch (drm->device.info.family) { 80967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_TNT: 81f58ddf95SBen Skeggs return NVIF_IOCTL_NEW_V0_SW_NV04; 82967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_CELSIUS: 83967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_KELVIN: 84967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_RANKINE: 85967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_CURIE: 86f58ddf95SBen Skeggs return NVIF_IOCTL_NEW_V0_SW_NV10; 87967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_TESLA: 88f58ddf95SBen Skeggs return NVIF_IOCTL_NEW_V0_SW_NV50; 89967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_FERMI: 90967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_KEPLER: 91967e7bdeSBen Skeggs case NV_DEVICE_INFO_V0_MAXWELL: 92f58ddf95SBen Skeggs return NVIF_IOCTL_NEW_V0_SW_GF100; 93ebb945a9SBen Skeggs } 94ebb945a9SBen Skeggs 95ebb945a9SBen Skeggs return 0x0000; 96ebb945a9SBen Skeggs } 97ebb945a9SBen Skeggs 98ebb945a9SBen Skeggs static void 99ebb945a9SBen Skeggs nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan, 100ebb945a9SBen Skeggs struct nouveau_abi16_ntfy *ntfy) 101ebb945a9SBen Skeggs { 102a01ca78cSBen Skeggs nvif_object_fini(&ntfy->object); 103be83cd4eSBen Skeggs nvkm_mm_free(&chan->heap, &ntfy->node); 104ebb945a9SBen Skeggs list_del(&ntfy->head); 105ebb945a9SBen Skeggs kfree(ntfy); 106ebb945a9SBen Skeggs } 107ebb945a9SBen Skeggs 108ebb945a9SBen Skeggs static void 109ebb945a9SBen Skeggs nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, 110ebb945a9SBen Skeggs struct nouveau_abi16_chan *chan) 111ebb945a9SBen Skeggs { 112ebb945a9SBen Skeggs struct nouveau_abi16_ntfy *ntfy, *temp; 113ebb945a9SBen Skeggs 1142b77c1c0SMarcin Slusarz /* wait for all activity to stop before releasing notify object, which 1152b77c1c0SMarcin Slusarz * may be still in use */ 1162b77c1c0SMarcin Slusarz if (chan->chan && chan->ntfy) 1172b77c1c0SMarcin Slusarz nouveau_channel_idle(chan->chan); 1182b77c1c0SMarcin Slusarz 119ebb945a9SBen Skeggs /* cleanup notifier state */ 120ebb945a9SBen Skeggs list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) { 121ebb945a9SBen Skeggs nouveau_abi16_ntfy_fini(chan, ntfy); 122ebb945a9SBen Skeggs } 123ebb945a9SBen Skeggs 124ebb945a9SBen Skeggs if (chan->ntfy) { 125ebb945a9SBen Skeggs nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma); 126198c14a0SMaarten Lankhorst nouveau_bo_unpin(chan->ntfy); 12755fb74adSDavid Herrmann drm_gem_object_unreference_unlocked(&chan->ntfy->gem); 128ebb945a9SBen Skeggs } 129ebb945a9SBen Skeggs 130ebb945a9SBen Skeggs if (chan->heap.block_size) 131be83cd4eSBen Skeggs nvkm_mm_fini(&chan->heap); 132ebb945a9SBen Skeggs 133ebb945a9SBen Skeggs /* destroy channel object, all children will be killed too */ 134ebb945a9SBen Skeggs if (chan->chan) { 135fbd58ebdSBen Skeggs nouveau_channel_idle(chan->chan); 136ebb945a9SBen Skeggs nouveau_channel_del(&chan->chan); 137ebb945a9SBen Skeggs } 138ebb945a9SBen Skeggs 139ebb945a9SBen Skeggs list_del(&chan->head); 140ebb945a9SBen Skeggs kfree(chan); 141ebb945a9SBen Skeggs } 142ebb945a9SBen Skeggs 143ebb945a9SBen Skeggs void 144ebb945a9SBen Skeggs nouveau_abi16_fini(struct nouveau_abi16 *abi16) 145ebb945a9SBen Skeggs { 146a01ca78cSBen Skeggs struct nouveau_cli *cli = (void *)abi16->device.object.client; 147ebb945a9SBen Skeggs struct nouveau_abi16_chan *chan, *temp; 148ebb945a9SBen Skeggs 149ebb945a9SBen Skeggs /* cleanup channels */ 150ebb945a9SBen Skeggs list_for_each_entry_safe(chan, temp, &abi16->channels, head) { 151ebb945a9SBen Skeggs nouveau_abi16_chan_fini(abi16, chan); 152ebb945a9SBen Skeggs } 153ebb945a9SBen Skeggs 154ebb945a9SBen Skeggs /* destroy the device object */ 1550ad72863SBen Skeggs nvif_device_fini(&abi16->device); 156ebb945a9SBen Skeggs 157ebb945a9SBen Skeggs kfree(cli->abi16); 158ebb945a9SBen Skeggs cli->abi16 = NULL; 159ebb945a9SBen Skeggs } 1602a259a3dSBen Skeggs 1612a259a3dSBen Skeggs int 1622a259a3dSBen Skeggs nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) 1632a259a3dSBen Skeggs { 164fa2bade9SBen Skeggs struct nouveau_cli *cli = nouveau_cli(file_priv); 165ebb945a9SBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev); 166967e7bdeSBen Skeggs struct nvif_device *device = &drm->device; 167be83cd4eSBen Skeggs struct nvkm_gr *gr = nvxx_gr(device); 1682a259a3dSBen Skeggs struct drm_nouveau_getparam *getparam = data; 1692a259a3dSBen Skeggs 1702a259a3dSBen Skeggs switch (getparam->param) { 1712a259a3dSBen Skeggs case NOUVEAU_GETPARAM_CHIPSET_ID: 172967e7bdeSBen Skeggs getparam->value = device->info.chipset; 1732a259a3dSBen Skeggs break; 1742a259a3dSBen Skeggs case NOUVEAU_GETPARAM_PCI_VENDOR: 17526c9e8efSBen Skeggs if (nvxx_device(device)->func->pci) 176ffbab09bSVille Syrjälä getparam->value = dev->pdev->vendor; 177420b9469SAlexandre Courbot else 178420b9469SAlexandre Courbot getparam->value = 0; 1792a259a3dSBen Skeggs break; 1802a259a3dSBen Skeggs case NOUVEAU_GETPARAM_PCI_DEVICE: 18126c9e8efSBen Skeggs if (nvxx_device(device)->func->pci) 182ffbab09bSVille Syrjälä getparam->value = dev->pdev->device; 183420b9469SAlexandre Courbot else 184420b9469SAlexandre Courbot getparam->value = 0; 1852a259a3dSBen Skeggs break; 1862a259a3dSBen Skeggs case NOUVEAU_GETPARAM_BUS_TYPE: 18726c9e8efSBen Skeggs if (!nvxx_device(device)->func->pci) 188420b9469SAlexandre Courbot getparam->value = 3; 189420b9469SAlexandre Courbot else 1902a259a3dSBen Skeggs if (drm_pci_device_is_agp(dev)) 1912a259a3dSBen Skeggs getparam->value = 0; 1922a259a3dSBen Skeggs else 1932a259a3dSBen Skeggs if (!pci_is_pcie(dev->pdev)) 1942a259a3dSBen Skeggs getparam->value = 1; 1952a259a3dSBen Skeggs else 1962a259a3dSBen Skeggs getparam->value = 2; 1972a259a3dSBen Skeggs break; 1982a259a3dSBen Skeggs case NOUVEAU_GETPARAM_FB_SIZE: 199ebb945a9SBen Skeggs getparam->value = drm->gem.vram_available; 2002a259a3dSBen Skeggs break; 2012a259a3dSBen Skeggs case NOUVEAU_GETPARAM_AGP_SIZE: 202ebb945a9SBen Skeggs getparam->value = drm->gem.gart_available; 2032a259a3dSBen Skeggs break; 2042a259a3dSBen Skeggs case NOUVEAU_GETPARAM_VM_VRAM_BASE: 2052a259a3dSBen Skeggs getparam->value = 0; /* deprecated */ 2062a259a3dSBen Skeggs break; 2072a259a3dSBen Skeggs case NOUVEAU_GETPARAM_PTIMER_TIME: 20856f67dc1SBen Skeggs getparam->value = nvif_device_time(device); 2092a259a3dSBen Skeggs break; 2102a259a3dSBen Skeggs case NOUVEAU_GETPARAM_HAS_BO_USAGE: 2112a259a3dSBen Skeggs getparam->value = 1; 2122a259a3dSBen Skeggs break; 2132a259a3dSBen Skeggs case NOUVEAU_GETPARAM_HAS_PAGEFLIP: 2142a259a3dSBen Skeggs getparam->value = 1; 2152a259a3dSBen Skeggs break; 2162a259a3dSBen Skeggs case NOUVEAU_GETPARAM_GRAPH_UNITS: 217c85ee6caSBen Skeggs getparam->value = nvkm_gr_units(gr); 2182a259a3dSBen Skeggs break; 2192a259a3dSBen Skeggs default: 2209ad97edeSBen Skeggs NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param); 2212a259a3dSBen Skeggs return -EINVAL; 2222a259a3dSBen Skeggs } 2232a259a3dSBen Skeggs 2242a259a3dSBen Skeggs return 0; 2252a259a3dSBen Skeggs } 2262a259a3dSBen Skeggs 2272a259a3dSBen Skeggs int 2282a259a3dSBen Skeggs nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS) 2292a259a3dSBen Skeggs { 2302a259a3dSBen Skeggs return -EINVAL; 2312a259a3dSBen Skeggs } 2322a259a3dSBen Skeggs 2332a259a3dSBen Skeggs int 2342a259a3dSBen Skeggs nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) 2352a259a3dSBen Skeggs { 2362a259a3dSBen Skeggs struct drm_nouveau_channel_alloc *init = data; 237ebb945a9SBen Skeggs struct nouveau_cli *cli = nouveau_cli(file_priv); 238ebb945a9SBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev); 239ebb945a9SBen Skeggs struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); 240ebb945a9SBen Skeggs struct nouveau_abi16_chan *chan; 241967e7bdeSBen Skeggs struct nvif_device *device; 2422a259a3dSBen Skeggs int ret; 2432a259a3dSBen Skeggs 244ebb945a9SBen Skeggs if (unlikely(!abi16)) 245ebb945a9SBen Skeggs return -ENOMEM; 246bf7e438bSMarcin Slusarz 247bf7e438bSMarcin Slusarz if (!drm->channel) 248bf7e438bSMarcin Slusarz return nouveau_abi16_put(abi16, -ENODEV); 249bf7e438bSMarcin Slusarz 250967e7bdeSBen Skeggs device = &abi16->device; 251ebb945a9SBen Skeggs 25249469800SBen Skeggs /* hack to allow channel engine type specification on kepler */ 253967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { 25449469800SBen Skeggs if (init->fb_ctxdma_handle != ~0) 255bbf8906bSBen Skeggs init->fb_ctxdma_handle = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR; 25649469800SBen Skeggs else 25749469800SBen Skeggs init->fb_ctxdma_handle = init->tt_ctxdma_handle; 25849469800SBen Skeggs 25949469800SBen Skeggs /* allow flips to be executed if this is a graphics channel */ 26049469800SBen Skeggs init->tt_ctxdma_handle = 0; 261bbf8906bSBen Skeggs if (init->fb_ctxdma_handle == KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR) 26249469800SBen Skeggs init->tt_ctxdma_handle = 1; 26349469800SBen Skeggs } 26449469800SBen Skeggs 26549469800SBen Skeggs if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) 26649469800SBen Skeggs return nouveau_abi16_put(abi16, -EINVAL); 26749469800SBen Skeggs 268ebb945a9SBen Skeggs /* allocate "abi16 channel" data and make up a handle for it */ 269ebb945a9SBen Skeggs chan = kzalloc(sizeof(*chan), GFP_KERNEL); 270ebb945a9SBen Skeggs if (!chan) 271ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, -ENOMEM); 272ebb945a9SBen Skeggs 273ebb945a9SBen Skeggs INIT_LIST_HEAD(&chan->notifiers); 274ebb945a9SBen Skeggs list_add(&chan->head, &abi16->channels); 275ebb945a9SBen Skeggs 276ebb945a9SBen Skeggs /* create channel object and initialise dma and fence management */ 277*fcf3f91cSBen Skeggs ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle, 278ebb945a9SBen Skeggs init->tt_ctxdma_handle, &chan->chan); 2792a259a3dSBen Skeggs if (ret) 280ebb945a9SBen Skeggs goto done; 2812a259a3dSBen Skeggs 282*fcf3f91cSBen Skeggs init->channel = chan->chan->chid; 283*fcf3f91cSBen Skeggs 284967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) 2852a259a3dSBen Skeggs init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | 2862a259a3dSBen Skeggs NOUVEAU_GEM_DOMAIN_GART; 287ebb945a9SBen Skeggs else 288ebb945a9SBen Skeggs if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) 2892a259a3dSBen Skeggs init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; 2902a259a3dSBen Skeggs else 2912a259a3dSBen Skeggs init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; 2922a259a3dSBen Skeggs 293967e7bdeSBen Skeggs if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { 2942a259a3dSBen Skeggs init->subchan[0].handle = 0x00000000; 2952a259a3dSBen Skeggs init->subchan[0].grclass = 0x0000; 296f45f55c4SBen Skeggs init->subchan[1].handle = chan->chan->nvsw.handle; 297ebb945a9SBen Skeggs init->subchan[1].grclass = 0x506e; 2982a259a3dSBen Skeggs init->nr_subchan = 2; 2992a259a3dSBen Skeggs } 3002a259a3dSBen Skeggs 3012a259a3dSBen Skeggs /* Named memory object area */ 302ebb945a9SBen Skeggs ret = nouveau_gem_new(dev, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART, 303ebb945a9SBen Skeggs 0, 0, &chan->ntfy); 3042a259a3dSBen Skeggs if (ret == 0) 305ad76b3f7SBen Skeggs ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT, false); 306ebb945a9SBen Skeggs if (ret) 307ebb945a9SBen Skeggs goto done; 308ebb945a9SBen Skeggs 309967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 3100ad72863SBen Skeggs ret = nouveau_bo_vma_add(chan->ntfy, cli->vm, 311ebb945a9SBen Skeggs &chan->ntfy_vma); 312ebb945a9SBen Skeggs if (ret) 313ebb945a9SBen Skeggs goto done; 3142a259a3dSBen Skeggs } 3152a259a3dSBen Skeggs 31655fb74adSDavid Herrmann ret = drm_gem_handle_create(file_priv, &chan->ntfy->gem, 317ebb945a9SBen Skeggs &init->notifier_handle); 318ebb945a9SBen Skeggs if (ret) 319ebb945a9SBen Skeggs goto done; 320ebb945a9SBen Skeggs 321be83cd4eSBen Skeggs ret = nvkm_mm_init(&chan->heap, 0, PAGE_SIZE, 1); 322ebb945a9SBen Skeggs done: 323ebb945a9SBen Skeggs if (ret) 324ebb945a9SBen Skeggs nouveau_abi16_chan_fini(abi16, chan); 325ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, ret); 326ebb945a9SBen Skeggs } 327ebb945a9SBen Skeggs 328a4e610b5SBen Skeggs static struct nouveau_abi16_chan * 329a4e610b5SBen Skeggs nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel) 330a4e610b5SBen Skeggs { 331a4e610b5SBen Skeggs struct nouveau_abi16_chan *chan; 332a4e610b5SBen Skeggs 333a4e610b5SBen Skeggs list_for_each_entry(chan, &abi16->channels, head) { 334*fcf3f91cSBen Skeggs if (chan->chan->chid == channel) 335a4e610b5SBen Skeggs return chan; 336a4e610b5SBen Skeggs } 337a4e610b5SBen Skeggs 338a4e610b5SBen Skeggs return NULL; 339a4e610b5SBen Skeggs } 340ebb945a9SBen Skeggs 3412a259a3dSBen Skeggs int 3422a259a3dSBen Skeggs nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS) 3432a259a3dSBen Skeggs { 3442a259a3dSBen Skeggs struct drm_nouveau_channel_free *req = data; 345ebb945a9SBen Skeggs struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); 346ebb945a9SBen Skeggs struct nouveau_abi16_chan *chan; 3472a259a3dSBen Skeggs 348ebb945a9SBen Skeggs if (unlikely(!abi16)) 349ebb945a9SBen Skeggs return -ENOMEM; 3502a259a3dSBen Skeggs 351a4e610b5SBen Skeggs chan = nouveau_abi16_chan(abi16, req->channel); 352a4e610b5SBen Skeggs if (!chan) 353a4e610b5SBen Skeggs return nouveau_abi16_put(abi16, -ENOENT); 354ebb945a9SBen Skeggs nouveau_abi16_chan_fini(abi16, chan); 355ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, 0); 356ebb945a9SBen Skeggs } 3572a259a3dSBen Skeggs 3582a259a3dSBen Skeggs int 3592a259a3dSBen Skeggs nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) 3602a259a3dSBen Skeggs { 3612a259a3dSBen Skeggs struct drm_nouveau_grobj_alloc *init = data; 362ebb945a9SBen Skeggs struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); 363a01ca78cSBen Skeggs struct nouveau_abi16_chan *chan; 364a01ca78cSBen Skeggs struct nouveau_abi16_ntfy *ntfy; 365a4e610b5SBen Skeggs struct nvif_client *client; 36641a63406SBen Skeggs struct nvif_sclass *sclass; 367f58ddf95SBen Skeggs s32 oclass = 0; 368f58ddf95SBen Skeggs int ret, i; 3692a259a3dSBen Skeggs 370ebb945a9SBen Skeggs if (unlikely(!abi16)) 371ebb945a9SBen Skeggs return -ENOMEM; 372ebb945a9SBen Skeggs 3732a259a3dSBen Skeggs if (init->handle == ~0) 374ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, -EINVAL); 375a01ca78cSBen Skeggs client = abi16->device.object.client; 3762a259a3dSBen Skeggs 377a01ca78cSBen Skeggs chan = nouveau_abi16_chan(abi16, init->channel); 378a01ca78cSBen Skeggs if (!chan) 379a01ca78cSBen Skeggs return nouveau_abi16_put(abi16, -ENOENT); 380a01ca78cSBen Skeggs 38141a63406SBen Skeggs ret = nvif_object_sclass_get(&chan->chan->user, &sclass); 382f58ddf95SBen Skeggs if (ret < 0) 383f58ddf95SBen Skeggs return nouveau_abi16_put(abi16, ret); 384f58ddf95SBen Skeggs 385f58ddf95SBen Skeggs if ((init->class & 0x00ff) == 0x006e) { 386f58ddf95SBen Skeggs /* nvsw: compatibility with older 0x*6e class identifier */ 387f58ddf95SBen Skeggs for (i = 0; !oclass && i < ret; i++) { 38841a63406SBen Skeggs switch (sclass[i].oclass) { 389f58ddf95SBen Skeggs case NVIF_IOCTL_NEW_V0_SW_NV04: 390f58ddf95SBen Skeggs case NVIF_IOCTL_NEW_V0_SW_NV10: 391f58ddf95SBen Skeggs case NVIF_IOCTL_NEW_V0_SW_NV50: 392f58ddf95SBen Skeggs case NVIF_IOCTL_NEW_V0_SW_GF100: 39341a63406SBen Skeggs oclass = sclass[i].oclass; 394f58ddf95SBen Skeggs break; 395f58ddf95SBen Skeggs default: 396f58ddf95SBen Skeggs break; 397f58ddf95SBen Skeggs } 398f58ddf95SBen Skeggs } 399f58ddf95SBen Skeggs } else 400f58ddf95SBen Skeggs if ((init->class & 0x00ff) == 0x00b1) { 401f58ddf95SBen Skeggs /* msvld: compatibility with incorrect version exposure */ 402f58ddf95SBen Skeggs for (i = 0; i < ret; i++) { 40341a63406SBen Skeggs if ((sclass[i].oclass & 0x00ff) == 0x00b1) { 40441a63406SBen Skeggs oclass = sclass[i].oclass; 405f58ddf95SBen Skeggs break; 406f58ddf95SBen Skeggs } 407f58ddf95SBen Skeggs } 408f58ddf95SBen Skeggs } else 409f58ddf95SBen Skeggs if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */ 410f58ddf95SBen Skeggs /* mspdec: compatibility with incorrect version exposure */ 411f58ddf95SBen Skeggs for (i = 0; i < ret; i++) { 41241a63406SBen Skeggs if ((sclass[i].oclass & 0x00ff) == 0x00b2) { 41341a63406SBen Skeggs oclass = sclass[i].oclass; 414f58ddf95SBen Skeggs break; 415f58ddf95SBen Skeggs } 416f58ddf95SBen Skeggs } 417f58ddf95SBen Skeggs } else 418f58ddf95SBen Skeggs if ((init->class & 0x00ff) == 0x00b3) { /* msppp */ 419f58ddf95SBen Skeggs /* msppp: compatibility with incorrect version exposure */ 420f58ddf95SBen Skeggs for (i = 0; i < ret; i++) { 42141a63406SBen Skeggs if ((sclass[i].oclass & 0x00ff) == 0x00b3) { 42241a63406SBen Skeggs oclass = sclass[i].oclass; 423f58ddf95SBen Skeggs break; 424f58ddf95SBen Skeggs } 425f58ddf95SBen Skeggs } 426f58ddf95SBen Skeggs } else { 427f58ddf95SBen Skeggs oclass = init->class; 428f58ddf95SBen Skeggs } 429f58ddf95SBen Skeggs 43041a63406SBen Skeggs nvif_object_sclass_put(&sclass); 431f58ddf95SBen Skeggs if (!oclass) 432f58ddf95SBen Skeggs return nouveau_abi16_put(abi16, -EINVAL); 433f58ddf95SBen Skeggs 434a01ca78cSBen Skeggs ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL); 435a01ca78cSBen Skeggs if (!ntfy) 436a01ca78cSBen Skeggs return nouveau_abi16_put(abi16, -ENOMEM); 437a01ca78cSBen Skeggs 438a01ca78cSBen Skeggs list_add(&ntfy->head, &chan->notifiers); 439a01ca78cSBen Skeggs 440a01ca78cSBen Skeggs client->route = NVDRM_OBJECT_ABI16; 441f58ddf95SBen Skeggs ret = nvif_object_init(&chan->chan->user, init->handle, oclass, 442a01ca78cSBen Skeggs NULL, 0, &ntfy->object); 443a01ca78cSBen Skeggs client->route = NVDRM_OBJECT_NVIF; 444a01ca78cSBen Skeggs 445a01ca78cSBen Skeggs if (ret) 446a01ca78cSBen Skeggs nouveau_abi16_ntfy_fini(chan, ntfy); 447ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, ret); 4482a259a3dSBen Skeggs } 4492a259a3dSBen Skeggs 4502a259a3dSBen Skeggs int 4512a259a3dSBen Skeggs nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) 4522a259a3dSBen Skeggs { 453ebb945a9SBen Skeggs struct drm_nouveau_notifierobj_alloc *info = data; 454ebb945a9SBen Skeggs struct nouveau_drm *drm = nouveau_drm(dev); 455ebb945a9SBen Skeggs struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); 456a4e610b5SBen Skeggs struct nouveau_abi16_chan *chan; 457ebb945a9SBen Skeggs struct nouveau_abi16_ntfy *ntfy; 458967e7bdeSBen Skeggs struct nvif_device *device = &abi16->device; 4593bdda04fSBen Skeggs struct nvif_client *client; 460a01ca78cSBen Skeggs struct nv_dma_v0 args = {}; 4612a259a3dSBen Skeggs int ret; 4622a259a3dSBen Skeggs 463ebb945a9SBen Skeggs if (unlikely(!abi16)) 464ebb945a9SBen Skeggs return -ENOMEM; 465ebb945a9SBen Skeggs 4662a259a3dSBen Skeggs /* completely unnecessary for these chipsets... */ 467967e7bdeSBen Skeggs if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI)) 468ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, -EINVAL); 469a01ca78cSBen Skeggs client = abi16->device.object.client; 4702a259a3dSBen Skeggs 471a4e610b5SBen Skeggs chan = nouveau_abi16_chan(abi16, info->channel); 472ebb945a9SBen Skeggs if (!chan) 473ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, -ENOENT); 474ebb945a9SBen Skeggs 475ebb945a9SBen Skeggs ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL); 476ebb945a9SBen Skeggs if (!ntfy) 477ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, -ENOMEM); 478ebb945a9SBen Skeggs 479ebb945a9SBen Skeggs list_add(&ntfy->head, &chan->notifiers); 480ebb945a9SBen Skeggs 481be83cd4eSBen Skeggs ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1, 482ebb945a9SBen Skeggs &ntfy->node); 483ebb945a9SBen Skeggs if (ret) 484ebb945a9SBen Skeggs goto done; 485ebb945a9SBen Skeggs 486a01ca78cSBen Skeggs args.start = ntfy->node->offset; 487a01ca78cSBen Skeggs args.limit = ntfy->node->offset + ntfy->node->length - 1; 488967e7bdeSBen Skeggs if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { 489a01ca78cSBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 490a01ca78cSBen Skeggs args.access = NV_DMA_V0_ACCESS_VM; 491a01ca78cSBen Skeggs args.start += chan->ntfy_vma.offset; 492a01ca78cSBen Skeggs args.limit += chan->ntfy_vma.offset; 493ebb945a9SBen Skeggs } else 494340b0e7cSBen Skeggs if (drm->agp.bridge) { 495a01ca78cSBen Skeggs args.target = NV_DMA_V0_TARGET_AGP; 496a01ca78cSBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 497a01ca78cSBen Skeggs args.start += drm->agp.base + chan->ntfy->bo.offset; 498a01ca78cSBen Skeggs args.limit += drm->agp.base + chan->ntfy->bo.offset; 499ebb945a9SBen Skeggs } else { 500a01ca78cSBen Skeggs args.target = NV_DMA_V0_TARGET_VM; 501a01ca78cSBen Skeggs args.access = NV_DMA_V0_ACCESS_RDWR; 502a01ca78cSBen Skeggs args.start += chan->ntfy->bo.offset; 503a01ca78cSBen Skeggs args.limit += chan->ntfy->bo.offset; 504ebb945a9SBen Skeggs } 505ebb945a9SBen Skeggs 506a01ca78cSBen Skeggs client->route = NVDRM_OBJECT_ABI16; 507a01ca78cSBen Skeggs client->super = true; 508a01ca78cSBen Skeggs ret = nvif_object_init(&chan->chan->user, info->handle, 509a01ca78cSBen Skeggs NV_DMA_IN_MEMORY, &args, sizeof(args), 510a01ca78cSBen Skeggs &ntfy->object); 5113bdda04fSBen Skeggs client->super = false; 512a01ca78cSBen Skeggs client->route = NVDRM_OBJECT_NVIF; 513ebb945a9SBen Skeggs if (ret) 514ebb945a9SBen Skeggs goto done; 515ebb945a9SBen Skeggs 516c1ccaa64SBob Gleitsmann info->offset = ntfy->node->offset; 517ebb945a9SBen Skeggs done: 518ebb945a9SBen Skeggs if (ret) 519ebb945a9SBen Skeggs nouveau_abi16_ntfy_fini(chan, ntfy); 520ebb945a9SBen Skeggs return nouveau_abi16_put(abi16, ret); 5212a259a3dSBen Skeggs } 5222a259a3dSBen Skeggs 5232a259a3dSBen Skeggs int 5242a259a3dSBen Skeggs nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS) 5252a259a3dSBen Skeggs { 526ebb945a9SBen Skeggs struct drm_nouveau_gpuobj_free *fini = data; 527ebb945a9SBen Skeggs struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); 528a4e610b5SBen Skeggs struct nouveau_abi16_chan *chan; 529ebb945a9SBen Skeggs struct nouveau_abi16_ntfy *ntfy; 530a01ca78cSBen Skeggs int ret = -ENOENT; 5312a259a3dSBen Skeggs 532ebb945a9SBen Skeggs if (unlikely(!abi16)) 533ebb945a9SBen Skeggs return -ENOMEM; 5342a259a3dSBen Skeggs 535a4e610b5SBen Skeggs chan = nouveau_abi16_chan(abi16, fini->channel); 536ebb945a9SBen Skeggs if (!chan) 537a01ca78cSBen Skeggs return nouveau_abi16_put(abi16, -EINVAL); 538ebb945a9SBen Skeggs 539ebb945a9SBen Skeggs /* synchronize with the user channel and destroy the gpu object */ 540ebb945a9SBen Skeggs nouveau_channel_idle(chan->chan); 541ebb945a9SBen Skeggs 542ebb945a9SBen Skeggs list_for_each_entry(ntfy, &chan->notifiers, head) { 543a01ca78cSBen Skeggs if (ntfy->object.handle == fini->handle) { 544a01ca78cSBen Skeggs nouveau_abi16_ntfy_fini(chan, ntfy); 545a01ca78cSBen Skeggs ret = 0; 546ebb945a9SBen Skeggs break; 547ebb945a9SBen Skeggs } 548ebb945a9SBen Skeggs } 549ebb945a9SBen Skeggs 550a01ca78cSBen Skeggs return nouveau_abi16_put(abi16, ret); 5512a259a3dSBen Skeggs } 552