1 /* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 24 #include "drmP.h" 25 26 #include "nouveau_drv.h" 27 #include "nouveau_dma.h" 28 #include "nouveau_abi16.h" 29 #include "nouveau_ramht.h" 30 #include "nouveau_software.h" 31 32 int 33 nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) 34 { 35 struct drm_nouveau_private *dev_priv = dev->dev_private; 36 struct drm_nouveau_getparam *getparam = data; 37 38 switch (getparam->param) { 39 case NOUVEAU_GETPARAM_CHIPSET_ID: 40 getparam->value = dev_priv->chipset; 41 break; 42 case NOUVEAU_GETPARAM_PCI_VENDOR: 43 getparam->value = dev->pci_vendor; 44 break; 45 case NOUVEAU_GETPARAM_PCI_DEVICE: 46 getparam->value = dev->pci_device; 47 break; 48 case NOUVEAU_GETPARAM_BUS_TYPE: 49 if (drm_pci_device_is_agp(dev)) 50 getparam->value = 0; 51 else 52 if (!pci_is_pcie(dev->pdev)) 53 getparam->value = 1; 54 else 55 getparam->value = 2; 56 break; 57 case NOUVEAU_GETPARAM_FB_SIZE: 58 getparam->value = dev_priv->fb_available_size; 59 break; 60 case NOUVEAU_GETPARAM_AGP_SIZE: 61 getparam->value = dev_priv->gart_info.aper_size; 62 break; 63 case NOUVEAU_GETPARAM_VM_VRAM_BASE: 64 getparam->value = 0; /* deprecated */ 65 break; 66 case NOUVEAU_GETPARAM_PTIMER_TIME: 67 getparam->value = dev_priv->engine.timer.read(dev); 68 break; 69 case NOUVEAU_GETPARAM_HAS_BO_USAGE: 70 getparam->value = 1; 71 break; 72 case NOUVEAU_GETPARAM_HAS_PAGEFLIP: 73 getparam->value = 1; 74 break; 75 case NOUVEAU_GETPARAM_GRAPH_UNITS: 76 /* NV40 and NV50 versions are quite different, but register 77 * address is the same. User is supposed to know the card 78 * family anyway... */ 79 if (dev_priv->chipset >= 0x40) { 80 getparam->value = nv_rd32(dev, NV40_PMC_GRAPH_UNITS); 81 break; 82 } 83 /* FALLTHRU */ 84 default: 85 NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param); 86 return -EINVAL; 87 } 88 89 return 0; 90 } 91 92 int 93 nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS) 94 { 95 return -EINVAL; 96 } 97 98 int 99 nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) 100 { 101 struct drm_nouveau_private *dev_priv = dev->dev_private; 102 struct drm_nouveau_channel_alloc *init = data; 103 struct nouveau_channel *chan; 104 int ret; 105 106 if (!dev_priv->eng[NVOBJ_ENGINE_GR]) 107 return -ENODEV; 108 109 if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) 110 return -EINVAL; 111 112 ret = nouveau_channel_alloc(dev, &chan, file_priv, 113 init->fb_ctxdma_handle, 114 init->tt_ctxdma_handle); 115 if (ret) 116 return ret; 117 init->channel = chan->id; 118 119 if (nouveau_vram_pushbuf == 0) { 120 if (chan->dma.ib_max) 121 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | 122 NOUVEAU_GEM_DOMAIN_GART; 123 else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) 124 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; 125 else 126 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; 127 } else { 128 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; 129 } 130 131 if (dev_priv->card_type < NV_C0) { 132 init->subchan[0].handle = 0x00000000; 133 init->subchan[0].grclass = 0x0000; 134 init->subchan[1].handle = NvSw; 135 init->subchan[1].grclass = NV_SW; 136 init->nr_subchan = 2; 137 } 138 139 /* Named memory object area */ 140 ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem, 141 &init->notifier_handle); 142 143 if (ret == 0) 144 atomic_inc(&chan->users); /* userspace reference */ 145 nouveau_channel_put(&chan); 146 return ret; 147 } 148 149 int 150 nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS) 151 { 152 struct drm_nouveau_channel_free *req = data; 153 struct nouveau_channel *chan; 154 155 chan = nouveau_channel_get(file_priv, req->channel); 156 if (IS_ERR(chan)) 157 return PTR_ERR(chan); 158 159 list_del(&chan->list); 160 atomic_dec(&chan->users); 161 nouveau_channel_put(&chan); 162 return 0; 163 } 164 165 int 166 nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) 167 { 168 struct drm_nouveau_grobj_alloc *init = data; 169 struct nouveau_channel *chan; 170 int ret; 171 172 if (init->handle == ~0) 173 return -EINVAL; 174 175 /* compatibility with userspace that assumes 506e for all chipsets */ 176 if (init->class == 0x506e) { 177 init->class = nouveau_software_class(dev); 178 if (init->class == 0x906e) 179 return 0; 180 } else 181 if (init->class == 0x906e) { 182 NV_ERROR(dev, "906e not supported yet\n"); 183 return -EINVAL; 184 } 185 186 chan = nouveau_channel_get(file_priv, init->channel); 187 if (IS_ERR(chan)) 188 return PTR_ERR(chan); 189 190 if (nouveau_ramht_find(chan, init->handle)) { 191 ret = -EEXIST; 192 goto out; 193 } 194 195 ret = nouveau_gpuobj_gr_new(chan, init->handle, init->class); 196 if (ret) { 197 NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n", 198 ret, init->channel, init->handle); 199 } 200 201 out: 202 nouveau_channel_put(&chan); 203 return ret; 204 } 205 206 int 207 nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) 208 { 209 struct drm_nouveau_private *dev_priv = dev->dev_private; 210 struct drm_nouveau_notifierobj_alloc *na = data; 211 struct nouveau_channel *chan; 212 int ret; 213 214 /* completely unnecessary for these chipsets... */ 215 if (unlikely(dev_priv->card_type >= NV_C0)) 216 return -EINVAL; 217 218 chan = nouveau_channel_get(file_priv, na->channel); 219 if (IS_ERR(chan)) 220 return PTR_ERR(chan); 221 222 ret = nouveau_notifier_alloc(chan, na->handle, na->size, 0, 0x1000, 223 &na->offset); 224 nouveau_channel_put(&chan); 225 return ret; 226 } 227 228 int 229 nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS) 230 { 231 struct drm_nouveau_gpuobj_free *objfree = data; 232 struct nouveau_channel *chan; 233 int ret; 234 235 chan = nouveau_channel_get(file_priv, objfree->channel); 236 if (IS_ERR(chan)) 237 return PTR_ERR(chan); 238 239 /* Synchronize with the user channel */ 240 nouveau_channel_idle(chan); 241 242 ret = nouveau_ramht_remove(chan, objfree->handle); 243 nouveau_channel_put(&chan); 244 return ret; 245 } 246