source: src/linux/universal/linux-3.18/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @ 31885

Last change on this file since 31885 was 31885, checked in by brainslayer, 5 weeks ago

update

File size: 11.4 KB
Line 
1/**************************************************************************
2 *
3 * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include "vmwgfx_drv.h"
29#include <drm/vmwgfx_drm.h>
30#include "vmwgfx_kms.h"
31
32struct svga_3d_compat_cap {
33        SVGA3dCapsRecordHeader header;
34        SVGA3dCapPair pairs[SVGA3D_DEVCAP_MAX];
35};
36
37int vmw_getparam_ioctl(struct drm_device *dev, void *data,
38                       struct drm_file *file_priv)
39{
40        struct vmw_private *dev_priv = vmw_priv(dev);
41        struct drm_vmw_getparam_arg *param =
42            (struct drm_vmw_getparam_arg *)data;
43        struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
44
45        switch (param->param) {
46        case DRM_VMW_PARAM_NUM_STREAMS:
47                param->value = vmw_overlay_num_overlays(dev_priv);
48                break;
49        case DRM_VMW_PARAM_NUM_FREE_STREAMS:
50                param->value = vmw_overlay_num_free_overlays(dev_priv);
51                break;
52        case DRM_VMW_PARAM_3D:
53                param->value = vmw_fifo_have_3d(dev_priv) ? 1 : 0;
54                break;
55        case DRM_VMW_PARAM_HW_CAPS:
56                param->value = dev_priv->capabilities;
57                break;
58        case DRM_VMW_PARAM_FIFO_CAPS:
59                param->value = dev_priv->fifo.capabilities;
60                break;
61        case DRM_VMW_PARAM_MAX_FB_SIZE:
62                param->value = dev_priv->prim_bb_mem;
63                break;
64        case DRM_VMW_PARAM_FIFO_HW_VERSION:
65        {
66                __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
67                const struct vmw_fifo_state *fifo = &dev_priv->fifo;
68
69                if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) {
70                        param->value = SVGA3D_HWVERSION_WS8_B1;
71                        break;
72                }
73
74                param->value =
75                        ioread32(fifo_mem +
76                                 ((fifo->capabilities &
77                                   SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
78                                  SVGA_FIFO_3D_HWVERSION_REVISED :
79                                  SVGA_FIFO_3D_HWVERSION));
80                break;
81        }
82        case DRM_VMW_PARAM_MAX_SURF_MEMORY:
83                if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) &&
84                    !vmw_fp->gb_aware)
85                        param->value = dev_priv->max_mob_pages * PAGE_SIZE / 2;
86                else
87                        param->value = dev_priv->memory_size;
88                break;
89        case DRM_VMW_PARAM_3D_CAPS_SIZE:
90                if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) &&
91                    vmw_fp->gb_aware)
92                        param->value = SVGA3D_DEVCAP_MAX * sizeof(uint32_t);
93                else if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS)
94                        param->value = sizeof(struct svga_3d_compat_cap) +
95                                sizeof(uint32_t);
96                else
97                        param->value = (SVGA_FIFO_3D_CAPS_LAST -
98                                        SVGA_FIFO_3D_CAPS + 1) *
99                                sizeof(uint32_t);
100                break;
101        case DRM_VMW_PARAM_MAX_MOB_MEMORY:
102                vmw_fp->gb_aware = true;
103                param->value = dev_priv->max_mob_pages * PAGE_SIZE;
104                break;
105        case DRM_VMW_PARAM_MAX_MOB_SIZE:
106                param->value = dev_priv->max_mob_size;
107                break;
108        default:
109                return -EINVAL;
110        }
111
112        return 0;
113}
114
115static int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce,
116                               size_t size)
117{
118        struct svga_3d_compat_cap *compat_cap =
119                (struct svga_3d_compat_cap *) bounce;
120        unsigned int i;
121        size_t pair_offset = offsetof(struct svga_3d_compat_cap, pairs);
122        unsigned int max_size;
123
124        if (size < pair_offset)
125                return -EINVAL;
126
127        max_size = (size - pair_offset) / sizeof(SVGA3dCapPair);
128
129        if (max_size > SVGA3D_DEVCAP_MAX)
130                max_size = SVGA3D_DEVCAP_MAX;
131
132        compat_cap->header.length =
133                (pair_offset + max_size * sizeof(SVGA3dCapPair)) / sizeof(u32);
134        compat_cap->header.type = SVGA3DCAPS_RECORD_DEVCAPS;
135
136        spin_lock(&dev_priv->cap_lock);
137        for (i = 0; i < max_size; ++i) {
138                vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
139                compat_cap->pairs[i][0] = i;
140                compat_cap->pairs[i][1] = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
141        }
142        spin_unlock(&dev_priv->cap_lock);
143
144        return 0;
145}
146
147
148int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
149                         struct drm_file *file_priv)
150{
151        struct drm_vmw_get_3d_cap_arg *arg =
152                (struct drm_vmw_get_3d_cap_arg *) data;
153        struct vmw_private *dev_priv = vmw_priv(dev);
154        uint32_t size;
155        __le32 __iomem *fifo_mem;
156        void __user *buffer = (void __user *)((unsigned long)(arg->buffer));
157        void *bounce;
158        int ret;
159        bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS);
160        struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
161
162        if (unlikely(arg->pad64 != 0 || arg->max_size == 0)) {
163                DRM_ERROR("Illegal GET_3D_CAP argument.\n");
164                return -EINVAL;
165        }
166
167        if (gb_objects && vmw_fp->gb_aware)
168                size = SVGA3D_DEVCAP_MAX * sizeof(uint32_t);
169        else if (gb_objects)
170                size = sizeof(struct svga_3d_compat_cap) + sizeof(uint32_t);
171        else
172                size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) *
173                        sizeof(uint32_t);
174
175        if (arg->max_size < size)
176                size = arg->max_size;
177
178        bounce = vzalloc(size);
179        if (unlikely(bounce == NULL)) {
180                DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n");
181                return -ENOMEM;
182        }
183
184        if (gb_objects && vmw_fp->gb_aware) {
185                int i, num;
186                uint32_t *bounce32 = (uint32_t *) bounce;
187
188                num = size / sizeof(uint32_t);
189                if (num > SVGA3D_DEVCAP_MAX)
190                        num = SVGA3D_DEVCAP_MAX;
191
192                spin_lock(&dev_priv->cap_lock);
193                for (i = 0; i < num; ++i) {
194                        vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
195                        *bounce32++ = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
196                }
197                spin_unlock(&dev_priv->cap_lock);
198        } else if (gb_objects) {
199                ret = vmw_fill_compat_cap(dev_priv, bounce, size);
200                if (unlikely(ret != 0))
201                        goto out_err;
202        } else {
203                fifo_mem = dev_priv->mmio_virt;
204                memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
205        }
206
207        ret = copy_to_user(buffer, bounce, size);
208        if (ret)
209                ret = -EFAULT;
210out_err:
211        vfree(bounce);
212
213        if (unlikely(ret != 0))
214                DRM_ERROR("Failed to report 3D caps info.\n");
215
216        return ret;
217}
218
219int vmw_present_ioctl(struct drm_device *dev, void *data,
220                      struct drm_file *file_priv)
221{
222        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
223        struct vmw_private *dev_priv = vmw_priv(dev);
224        struct drm_vmw_present_arg *arg =
225                (struct drm_vmw_present_arg *)data;
226        struct vmw_surface *surface;
227        struct drm_vmw_rect __user *clips_ptr;
228        struct drm_vmw_rect *clips = NULL;
229        struct drm_framebuffer *fb;
230        struct vmw_framebuffer *vfb;
231        struct vmw_resource *res;
232        uint32_t num_clips;
233        int ret;
234
235        num_clips = arg->num_clips;
236        clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
237
238        if (unlikely(num_clips == 0))
239                return 0;
240
241        if (clips_ptr == NULL) {
242                DRM_ERROR("Variable clips_ptr must be specified.\n");
243                ret = -EINVAL;
244                goto out_clips;
245        }
246
247        clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
248        if (clips == NULL) {
249                DRM_ERROR("Failed to allocate clip rect list.\n");
250                ret = -ENOMEM;
251                goto out_clips;
252        }
253
254        ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
255        if (ret) {
256                DRM_ERROR("Failed to copy clip rects from userspace.\n");
257                ret = -EFAULT;
258                goto out_no_copy;
259        }
260
261        drm_modeset_lock_all(dev);
262
263        fb = drm_framebuffer_lookup(dev, arg->fb_id);
264        if (!fb) {
265                DRM_ERROR("Invalid framebuffer id.\n");
266                ret = -ENOENT;
267                goto out_no_fb;
268        }
269        vfb = vmw_framebuffer_to_vfb(fb);
270
271        ret = ttm_read_lock(&dev_priv->reservation_sem, true);
272        if (unlikely(ret != 0))
273                goto out_no_ttm_lock;
274
275        ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg->sid,
276                                              user_surface_converter,
277                                              &res);
278        if (ret)
279                goto out_no_surface;
280
281        surface = vmw_res_to_srf(res);
282        ret = vmw_kms_present(dev_priv, file_priv,
283                              vfb, surface, arg->sid,
284                              arg->dest_x, arg->dest_y,
285                              clips, num_clips);
286
287        /* vmw_user_surface_lookup takes one ref so does new_fb */
288        vmw_surface_unreference(&surface);
289
290out_no_surface:
291        ttm_read_unlock(&dev_priv->reservation_sem);
292out_no_ttm_lock:
293        drm_framebuffer_unreference(fb);
294out_no_fb:
295        drm_modeset_unlock_all(dev);
296out_no_copy:
297        kfree(clips);
298out_clips:
299        return ret;
300}
301
302int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
303                               struct drm_file *file_priv)
304{
305        struct vmw_private *dev_priv = vmw_priv(dev);
306        struct drm_vmw_present_readback_arg *arg =
307                (struct drm_vmw_present_readback_arg *)data;
308        struct drm_vmw_fence_rep __user *user_fence_rep =
309                (struct drm_vmw_fence_rep __user *)
310                (unsigned long)arg->fence_rep;
311        struct drm_vmw_rect __user *clips_ptr;
312        struct drm_vmw_rect *clips = NULL;
313        struct drm_framebuffer *fb;
314        struct vmw_framebuffer *vfb;
315        uint32_t num_clips;
316        int ret;
317
318        num_clips = arg->num_clips;
319        clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
320
321        if (unlikely(num_clips == 0))
322                return 0;
323
324        if (clips_ptr == NULL) {
325                DRM_ERROR("Argument clips_ptr must be specified.\n");
326                ret = -EINVAL;
327                goto out_clips;
328        }
329
330        clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
331        if (clips == NULL) {
332                DRM_ERROR("Failed to allocate clip rect list.\n");
333                ret = -ENOMEM;
334                goto out_clips;
335        }
336
337        ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
338        if (ret) {
339                DRM_ERROR("Failed to copy clip rects from userspace.\n");
340                ret = -EFAULT;
341                goto out_no_copy;
342        }
343
344        drm_modeset_lock_all(dev);
345
346        fb = drm_framebuffer_lookup(dev, arg->fb_id);
347        if (!fb) {
348                DRM_ERROR("Invalid framebuffer id.\n");
349                ret = -ENOENT;
350                goto out_no_fb;
351        }
352
353        vfb = vmw_framebuffer_to_vfb(fb);
354        if (!vfb->dmabuf) {
355                DRM_ERROR("Framebuffer not dmabuf backed.\n");
356                ret = -EINVAL;
357                goto out_no_ttm_lock;
358        }
359
360        ret = ttm_read_lock(&dev_priv->reservation_sem, true);
361        if (unlikely(ret != 0))
362                goto out_no_ttm_lock;
363
364        ret = vmw_kms_readback(dev_priv, file_priv,
365                               vfb, user_fence_rep,
366                               clips, num_clips);
367
368        ttm_read_unlock(&dev_priv->reservation_sem);
369out_no_ttm_lock:
370        drm_framebuffer_unreference(fb);
371out_no_fb:
372        drm_modeset_unlock_all(dev);
373out_no_copy:
374        kfree(clips);
375out_clips:
376        return ret;
377}
378
379
380/**
381 * vmw_fops_poll - wrapper around the drm_poll function
382 *
383 * @filp: See the linux fops poll documentation.
384 * @wait: See the linux fops poll documentation.
385 *
386 * Wrapper around the drm_poll function that makes sure the device is
387 * processing the fifo if drm_poll decides to wait.
388 */
389unsigned int vmw_fops_poll(struct file *filp, struct poll_table_struct *wait)
390{
391        struct drm_file *file_priv = filp->private_data;
392        struct vmw_private *dev_priv =
393                vmw_priv(file_priv->minor->dev);
394
395        vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
396        return drm_poll(filp, wait);
397}
398
399
400/**
401 * vmw_fops_read - wrapper around the drm_read function
402 *
403 * @filp: See the linux fops read documentation.
404 * @buffer: See the linux fops read documentation.
405 * @count: See the linux fops read documentation.
406 * offset: See the linux fops read documentation.
407 *
408 * Wrapper around the drm_read function that makes sure the device is
409 * processing the fifo if drm_read decides to wait.
410 */
411ssize_t vmw_fops_read(struct file *filp, char __user *buffer,
412                      size_t count, loff_t *offset)
413{
414        struct drm_file *file_priv = filp->private_data;
415        struct vmw_private *dev_priv =
416                vmw_priv(file_priv->minor->dev);
417
418        vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
419        return drm_read(filp, buffer, count, offset);
420}
Note: See TracBrowser for help on using the repository browser.