diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_abi16.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_abi16.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c new file mode 100644 index 000000000000..ff23d88880e5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c | |||
@@ -0,0 +1,245 @@ | |||
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 | } | ||