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