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

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

update

File size: 39.3 KB
Line 
1/**************************************************************************
2 *
3 * Copyright © 2009-2012 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 "vmwgfx_resource_priv.h"
30#include <ttm/ttm_placement.h>
31#include "svga3d_surfacedefs.h"
32
33/**
34 * struct vmw_user_surface - User-space visible surface resource
35 *
36 * @base:           The TTM base object handling user-space visibility.
37 * @srf:            The surface metadata.
38 * @size:           TTM accounting size for the surface.
39 * @master:         master of the creating client. Used for security check.
40 */
41struct vmw_user_surface {
42        struct ttm_prime_object prime;
43        struct vmw_surface srf;
44        uint32_t size;
45        struct drm_master *master;
46};
47
48/**
49 * struct vmw_surface_offset - Backing store mip level offset info
50 *
51 * @face:           Surface face.
52 * @mip:            Mip level.
53 * @bo_offset:      Offset into backing store of this mip level.
54 *
55 */
56struct vmw_surface_offset {
57        uint32_t face;
58        uint32_t mip;
59        uint32_t bo_offset;
60};
61
62static void vmw_user_surface_free(struct vmw_resource *res);
63static struct vmw_resource *
64vmw_user_surface_base_to_res(struct ttm_base_object *base);
65static int vmw_legacy_srf_bind(struct vmw_resource *res,
66                               struct ttm_validate_buffer *val_buf);
67static int vmw_legacy_srf_unbind(struct vmw_resource *res,
68                                 bool readback,
69                                 struct ttm_validate_buffer *val_buf);
70static int vmw_legacy_srf_create(struct vmw_resource *res);
71static int vmw_legacy_srf_destroy(struct vmw_resource *res);
72static int vmw_gb_surface_create(struct vmw_resource *res);
73static int vmw_gb_surface_bind(struct vmw_resource *res,
74                               struct ttm_validate_buffer *val_buf);
75static int vmw_gb_surface_unbind(struct vmw_resource *res,
76                                 bool readback,
77                                 struct ttm_validate_buffer *val_buf);
78static int vmw_gb_surface_destroy(struct vmw_resource *res);
79
80
81static const struct vmw_user_resource_conv user_surface_conv = {
82        .object_type = VMW_RES_SURFACE,
83        .base_obj_to_res = vmw_user_surface_base_to_res,
84        .res_free = vmw_user_surface_free
85};
86
87const struct vmw_user_resource_conv *user_surface_converter =
88        &user_surface_conv;
89
90
91static uint64_t vmw_user_surface_size;
92
93static const struct vmw_res_func vmw_legacy_surface_func = {
94        .res_type = vmw_res_surface,
95        .needs_backup = false,
96        .may_evict = true,
97        .type_name = "legacy surfaces",
98        .backup_placement = &vmw_srf_placement,
99        .create = &vmw_legacy_srf_create,
100        .destroy = &vmw_legacy_srf_destroy,
101        .bind = &vmw_legacy_srf_bind,
102        .unbind = &vmw_legacy_srf_unbind
103};
104
105static const struct vmw_res_func vmw_gb_surface_func = {
106        .res_type = vmw_res_surface,
107        .needs_backup = true,
108        .may_evict = true,
109        .type_name = "guest backed surfaces",
110        .backup_placement = &vmw_mob_placement,
111        .create = vmw_gb_surface_create,
112        .destroy = vmw_gb_surface_destroy,
113        .bind = vmw_gb_surface_bind,
114        .unbind = vmw_gb_surface_unbind
115};
116
117/**
118 * struct vmw_surface_dma - SVGA3D DMA command
119 */
120struct vmw_surface_dma {
121        SVGA3dCmdHeader header;
122        SVGA3dCmdSurfaceDMA body;
123        SVGA3dCopyBox cb;
124        SVGA3dCmdSurfaceDMASuffix suffix;
125};
126
127/**
128 * struct vmw_surface_define - SVGA3D Surface Define command
129 */
130struct vmw_surface_define {
131        SVGA3dCmdHeader header;
132        SVGA3dCmdDefineSurface body;
133};
134
135/**
136 * struct vmw_surface_destroy - SVGA3D Surface Destroy command
137 */
138struct vmw_surface_destroy {
139        SVGA3dCmdHeader header;
140        SVGA3dCmdDestroySurface body;
141};
142
143
144/**
145 * vmw_surface_dma_size - Compute fifo size for a dma command.
146 *
147 * @srf: Pointer to a struct vmw_surface
148 *
149 * Computes the required size for a surface dma command for backup or
150 * restoration of the surface represented by @srf.
151 */
152static inline uint32_t vmw_surface_dma_size(const struct vmw_surface *srf)
153{
154        return srf->num_sizes * sizeof(struct vmw_surface_dma);
155}
156
157
158/**
159 * vmw_surface_define_size - Compute fifo size for a surface define command.
160 *
161 * @srf: Pointer to a struct vmw_surface
162 *
163 * Computes the required size for a surface define command for the definition
164 * of the surface represented by @srf.
165 */
166static inline uint32_t vmw_surface_define_size(const struct vmw_surface *srf)
167{
168        return sizeof(struct vmw_surface_define) + srf->num_sizes *
169                sizeof(SVGA3dSize);
170}
171
172
173/**
174 * vmw_surface_destroy_size - Compute fifo size for a surface destroy command.
175 *
176 * Computes the required size for a surface destroy command for the destruction
177 * of a hw surface.
178 */
179static inline uint32_t vmw_surface_destroy_size(void)
180{
181        return sizeof(struct vmw_surface_destroy);
182}
183
184/**
185 * vmw_surface_destroy_encode - Encode a surface_destroy command.
186 *
187 * @id: The surface id
188 * @cmd_space: Pointer to memory area in which the commands should be encoded.
189 */
190static void vmw_surface_destroy_encode(uint32_t id,
191                                       void *cmd_space)
192{
193        struct vmw_surface_destroy *cmd = (struct vmw_surface_destroy *)
194                cmd_space;
195
196        cmd->header.id = SVGA_3D_CMD_SURFACE_DESTROY;
197        cmd->header.size = sizeof(cmd->body);
198        cmd->body.sid = id;
199}
200
201/**
202 * vmw_surface_define_encode - Encode a surface_define command.
203 *
204 * @srf: Pointer to a struct vmw_surface object.
205 * @cmd_space: Pointer to memory area in which the commands should be encoded.
206 */
207static void vmw_surface_define_encode(const struct vmw_surface *srf,
208                                      void *cmd_space)
209{
210        struct vmw_surface_define *cmd = (struct vmw_surface_define *)
211                cmd_space;
212        struct drm_vmw_size *src_size;
213        SVGA3dSize *cmd_size;
214        uint32_t cmd_len;
215        int i;
216
217        cmd_len = sizeof(cmd->body) + srf->num_sizes * sizeof(SVGA3dSize);
218
219        cmd->header.id = SVGA_3D_CMD_SURFACE_DEFINE;
220        cmd->header.size = cmd_len;
221        cmd->body.sid = srf->res.id;
222        cmd->body.surfaceFlags = srf->flags;
223        cmd->body.format = cpu_to_le32(srf->format);
224        for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
225                cmd->body.face[i].numMipLevels = srf->mip_levels[i];
226
227        cmd += 1;
228        cmd_size = (SVGA3dSize *) cmd;
229        src_size = srf->sizes;
230
231        for (i = 0; i < srf->num_sizes; ++i, cmd_size++, src_size++) {
232                cmd_size->width = src_size->width;
233                cmd_size->height = src_size->height;
234                cmd_size->depth = src_size->depth;
235        }
236}
237
238/**
239 * vmw_surface_dma_encode - Encode a surface_dma command.
240 *
241 * @srf: Pointer to a struct vmw_surface object.
242 * @cmd_space: Pointer to memory area in which the commands should be encoded.
243 * @ptr: Pointer to an SVGAGuestPtr indicating where the surface contents
244 * should be placed or read from.
245 * @to_surface: Boolean whether to DMA to the surface or from the surface.
246 */
247static void vmw_surface_dma_encode(struct vmw_surface *srf,
248                                   void *cmd_space,
249                                   const SVGAGuestPtr *ptr,
250                                   bool to_surface)
251{
252        uint32_t i;
253        struct vmw_surface_dma *cmd = (struct vmw_surface_dma *)cmd_space;
254        const struct svga3d_surface_desc *desc =
255                svga3dsurface_get_desc(srf->format);
256
257        for (i = 0; i < srf->num_sizes; ++i) {
258                SVGA3dCmdHeader *header = &cmd->header;
259                SVGA3dCmdSurfaceDMA *body = &cmd->body;
260                SVGA3dCopyBox *cb = &cmd->cb;
261                SVGA3dCmdSurfaceDMASuffix *suffix = &cmd->suffix;
262                const struct vmw_surface_offset *cur_offset = &srf->offsets[i];
263                const struct drm_vmw_size *cur_size = &srf->sizes[i];
264
265                header->id = SVGA_3D_CMD_SURFACE_DMA;
266                header->size = sizeof(*body) + sizeof(*cb) + sizeof(*suffix);
267
268                body->guest.ptr = *ptr;
269                body->guest.ptr.offset += cur_offset->bo_offset;
270                body->guest.pitch = svga3dsurface_calculate_pitch(desc,
271                                                                  cur_size);
272                body->host.sid = srf->res.id;
273                body->host.face = cur_offset->face;
274                body->host.mipmap = cur_offset->mip;
275                body->transfer = ((to_surface) ?  SVGA3D_WRITE_HOST_VRAM :
276                                  SVGA3D_READ_HOST_VRAM);
277                cb->x = 0;
278                cb->y = 0;
279                cb->z = 0;
280                cb->srcx = 0;
281                cb->srcy = 0;
282                cb->srcz = 0;
283                cb->w = cur_size->width;
284                cb->h = cur_size->height;
285                cb->d = cur_size->depth;
286
287                suffix->suffixSize = sizeof(*suffix);
288                suffix->maximumOffset =
289                        svga3dsurface_get_image_buffer_size(desc, cur_size,
290                                                            body->guest.pitch);
291                suffix->flags.discard = 0;
292                suffix->flags.unsynchronized = 0;
293                suffix->flags.reserved = 0;
294                ++cmd;
295        }
296};
297
298
299/**
300 * vmw_hw_surface_destroy - destroy a Device surface
301 *
302 * @res:        Pointer to a struct vmw_resource embedded in a struct
303 *              vmw_surface.
304 *
305 * Destroys a the device surface associated with a struct vmw_surface if
306 * any, and adjusts accounting and resource count accordingly.
307 */
308static void vmw_hw_surface_destroy(struct vmw_resource *res)
309{
310
311        struct vmw_private *dev_priv = res->dev_priv;
312        struct vmw_surface *srf;
313        void *cmd;
314
315        if (res->func->destroy == vmw_gb_surface_destroy) {
316                (void) vmw_gb_surface_destroy(res);
317                return;
318        }
319
320        if (res->id != -1) {
321
322                cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size());
323                if (unlikely(cmd == NULL)) {
324                        DRM_ERROR("Failed reserving FIFO space for surface "
325                                  "destruction.\n");
326                        return;
327                }
328
329                vmw_surface_destroy_encode(res->id, cmd);
330                vmw_fifo_commit(dev_priv, vmw_surface_destroy_size());
331
332                /*
333                 * used_memory_size_atomic, or separate lock
334                 * to avoid taking dev_priv::cmdbuf_mutex in
335                 * the destroy path.
336                 */
337
338                mutex_lock(&dev_priv->cmdbuf_mutex);
339                srf = vmw_res_to_srf(res);
340                dev_priv->used_memory_size -= res->backup_size;
341                mutex_unlock(&dev_priv->cmdbuf_mutex);
342        }
343        vmw_3d_resource_dec(dev_priv, false);
344}
345
346/**
347 * vmw_legacy_srf_create - Create a device surface as part of the
348 * resource validation process.
349 *
350 * @res: Pointer to a struct vmw_surface.
351 *
352 * If the surface doesn't have a hw id.
353 *
354 * Returns -EBUSY if there wasn't sufficient device resources to
355 * complete the validation. Retry after freeing up resources.
356 *
357 * May return other errors if the kernel is out of guest resources.
358 */
359static int vmw_legacy_srf_create(struct vmw_resource *res)
360{
361        struct vmw_private *dev_priv = res->dev_priv;
362        struct vmw_surface *srf;
363        uint32_t submit_size;
364        uint8_t *cmd;
365        int ret;
366
367        if (likely(res->id != -1))
368                return 0;
369
370        srf = vmw_res_to_srf(res);
371        if (unlikely(dev_priv->used_memory_size + res->backup_size >=
372                     dev_priv->memory_size))
373                return -EBUSY;
374
375        /*
376         * Alloc id for the resource.
377         */
378
379        ret = vmw_resource_alloc_id(res);
380        if (unlikely(ret != 0)) {
381                DRM_ERROR("Failed to allocate a surface id.\n");
382                goto out_no_id;
383        }
384
385        if (unlikely(res->id >= SVGA3D_MAX_SURFACE_IDS)) {
386                ret = -EBUSY;
387                goto out_no_fifo;
388        }
389
390        /*
391         * Encode surface define- commands.
392         */
393
394        submit_size = vmw_surface_define_size(srf);
395        cmd = vmw_fifo_reserve(dev_priv, submit_size);
396        if (unlikely(cmd == NULL)) {
397                DRM_ERROR("Failed reserving FIFO space for surface "
398                          "creation.\n");
399                ret = -ENOMEM;
400                goto out_no_fifo;
401        }
402
403        vmw_surface_define_encode(srf, cmd);
404        vmw_fifo_commit(dev_priv, submit_size);
405        /*
406         * Surface memory usage accounting.
407         */
408
409        dev_priv->used_memory_size += res->backup_size;
410        return 0;
411
412out_no_fifo:
413        vmw_resource_release_id(res);
414out_no_id:
415        return ret;
416}
417
418/**
419 * vmw_legacy_srf_dma - Copy backup data to or from a legacy surface.
420 *
421 * @res:            Pointer to a struct vmw_res embedded in a struct
422 *                  vmw_surface.
423 * @val_buf:        Pointer to a struct ttm_validate_buffer containing
424 *                  information about the backup buffer.
425 * @bind:           Boolean wether to DMA to the surface.
426 *
427 * Transfer backup data to or from a legacy surface as part of the
428 * validation process.
429 * May return other errors if the kernel is out of guest resources.
430 * The backup buffer will be fenced or idle upon successful completion,
431 * and if the surface needs persistent backup storage, the backup buffer
432 * will also be returned reserved iff @bind is true.
433 */
434static int vmw_legacy_srf_dma(struct vmw_resource *res,
435                              struct ttm_validate_buffer *val_buf,
436                              bool bind)
437{
438        SVGAGuestPtr ptr;
439        struct vmw_fence_obj *fence;
440        uint32_t submit_size;
441        struct vmw_surface *srf = vmw_res_to_srf(res);
442        uint8_t *cmd;
443        struct vmw_private *dev_priv = res->dev_priv;
444
445        BUG_ON(val_buf->bo == NULL);
446
447        submit_size = vmw_surface_dma_size(srf);
448        cmd = vmw_fifo_reserve(dev_priv, submit_size);
449        if (unlikely(cmd == NULL)) {
450                DRM_ERROR("Failed reserving FIFO space for surface "
451                          "DMA.\n");
452                return -ENOMEM;
453        }
454        vmw_bo_get_guest_ptr(val_buf->bo, &ptr);
455        vmw_surface_dma_encode(srf, cmd, &ptr, bind);
456
457        vmw_fifo_commit(dev_priv, submit_size);
458
459        /*
460         * Create a fence object and fence the backup buffer.
461         */
462
463        (void) vmw_execbuf_fence_commands(NULL, dev_priv,
464                                          &fence, NULL);
465
466        vmw_fence_single_bo(val_buf->bo, fence);
467
468        if (likely(fence != NULL))
469                vmw_fence_obj_unreference(&fence);
470
471        return 0;
472}
473
474/**
475 * vmw_legacy_srf_bind - Perform a legacy surface bind as part of the
476 *                       surface validation process.
477 *
478 * @res:            Pointer to a struct vmw_res embedded in a struct
479 *                  vmw_surface.
480 * @val_buf:        Pointer to a struct ttm_validate_buffer containing
481 *                  information about the backup buffer.
482 *
483 * This function will copy backup data to the surface if the
484 * backup buffer is dirty.
485 */
486static int vmw_legacy_srf_bind(struct vmw_resource *res,
487                               struct ttm_validate_buffer *val_buf)
488{
489        if (!res->backup_dirty)
490                return 0;
491
492        return vmw_legacy_srf_dma(res, val_buf, true);
493}
494
495
496/**
497 * vmw_legacy_srf_unbind - Perform a legacy surface unbind as part of the
498 *                         surface eviction process.
499 *
500 * @res:            Pointer to a struct vmw_res embedded in a struct
501 *                  vmw_surface.
502 * @val_buf:        Pointer to a struct ttm_validate_buffer containing
503 *                  information about the backup buffer.
504 *
505 * This function will copy backup data from the surface.
506 */
507static int vmw_legacy_srf_unbind(struct vmw_resource *res,
508                                 bool readback,
509                                 struct ttm_validate_buffer *val_buf)
510{
511        if (unlikely(readback))
512                return vmw_legacy_srf_dma(res, val_buf, false);
513        return 0;
514}
515
516/**
517 * vmw_legacy_srf_destroy - Destroy a device surface as part of a
518 *                          resource eviction process.
519 *
520 * @res:            Pointer to a struct vmw_res embedded in a struct
521 *                  vmw_surface.
522 */
523static int vmw_legacy_srf_destroy(struct vmw_resource *res)
524{
525        struct vmw_private *dev_priv = res->dev_priv;
526        uint32_t submit_size;
527        uint8_t *cmd;
528
529        BUG_ON(res->id == -1);
530
531        /*
532         * Encode the dma- and surface destroy commands.
533         */
534
535        submit_size = vmw_surface_destroy_size();
536        cmd = vmw_fifo_reserve(dev_priv, submit_size);
537        if (unlikely(cmd == NULL)) {
538                DRM_ERROR("Failed reserving FIFO space for surface "
539                          "eviction.\n");
540                return -ENOMEM;
541        }
542
543        vmw_surface_destroy_encode(res->id, cmd);
544        vmw_fifo_commit(dev_priv, submit_size);
545
546        /*
547         * Surface memory usage accounting.
548         */
549
550        dev_priv->used_memory_size -= res->backup_size;
551
552        /*
553         * Release the surface ID.
554         */
555
556        vmw_resource_release_id(res);
557
558        return 0;
559}
560
561
562/**
563 * vmw_surface_init - initialize a struct vmw_surface
564 *
565 * @dev_priv:       Pointer to a device private struct.
566 * @srf:            Pointer to the struct vmw_surface to initialize.
567 * @res_free:       Pointer to a resource destructor used to free
568 *                  the object.
569 */
570static int vmw_surface_init(struct vmw_private *dev_priv,
571                            struct vmw_surface *srf,
572                            void (*res_free) (struct vmw_resource *res))
573{
574        int ret;
575        struct vmw_resource *res = &srf->res;
576
577        BUG_ON(res_free == NULL);
578        if (!dev_priv->has_mob)
579                (void) vmw_3d_resource_inc(dev_priv, false);
580        ret = vmw_resource_init(dev_priv, res, true, res_free,
581                                (dev_priv->has_mob) ? &vmw_gb_surface_func :
582                                &vmw_legacy_surface_func);
583
584        if (unlikely(ret != 0)) {
585                if (!dev_priv->has_mob)
586                        vmw_3d_resource_dec(dev_priv, false);
587                res_free(res);
588                return ret;
589        }
590
591        /*
592         * The surface won't be visible to hardware until a
593         * surface validate.
594         */
595
596        vmw_resource_activate(res, vmw_hw_surface_destroy);
597        return ret;
598}
599
600/**
601 * vmw_user_surface_base_to_res - TTM base object to resource converter for
602 *                                user visible surfaces
603 *
604 * @base:           Pointer to a TTM base object
605 *
606 * Returns the struct vmw_resource embedded in a struct vmw_surface
607 * for the user-visible object identified by the TTM base object @base.
608 */
609static struct vmw_resource *
610vmw_user_surface_base_to_res(struct ttm_base_object *base)
611{
612        return &(container_of(base, struct vmw_user_surface,
613                              prime.base)->srf.res);
614}
615
616/**
617 * vmw_user_surface_free - User visible surface resource destructor
618 *
619 * @res:            A struct vmw_resource embedded in a struct vmw_surface.
620 */
621static void vmw_user_surface_free(struct vmw_resource *res)
622{
623        struct vmw_surface *srf = vmw_res_to_srf(res);
624        struct vmw_user_surface *user_srf =
625            container_of(srf, struct vmw_user_surface, srf);
626        struct vmw_private *dev_priv = srf->res.dev_priv;
627        uint32_t size = user_srf->size;
628
629        if (user_srf->master)
630                drm_master_put(&user_srf->master);
631        kfree(srf->offsets);
632        kfree(srf->sizes);
633        kfree(srf->snooper.image);
634        ttm_prime_object_kfree(user_srf, prime);
635        ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
636}
637
638/**
639 * vmw_user_surface_free - User visible surface TTM base object destructor
640 *
641 * @p_base:         Pointer to a pointer to a TTM base object
642 *                  embedded in a struct vmw_user_surface.
643 *
644 * Drops the base object's reference on its resource, and the
645 * pointer pointed to by *p_base is set to NULL.
646 */
647static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
648{
649        struct ttm_base_object *base = *p_base;
650        struct vmw_user_surface *user_srf =
651            container_of(base, struct vmw_user_surface, prime.base);
652        struct vmw_resource *res = &user_srf->srf.res;
653
654        *p_base = NULL;
655        vmw_resource_unreference(&res);
656}
657
658/**
659 * vmw_user_surface_destroy_ioctl - Ioctl function implementing
660 *                                  the user surface destroy functionality.
661 *
662 * @dev:            Pointer to a struct drm_device.
663 * @data:           Pointer to data copied from / to user-space.
664 * @file_priv:      Pointer to a drm file private structure.
665 */
666int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
667                              struct drm_file *file_priv)
668{
669        struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data;
670        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
671
672        return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE);
673}
674
675/**
676 * vmw_user_surface_define_ioctl - Ioctl function implementing
677 *                                  the user surface define functionality.
678 *
679 * @dev:            Pointer to a struct drm_device.
680 * @data:           Pointer to data copied from / to user-space.
681 * @file_priv:      Pointer to a drm file private structure.
682 */
683int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
684                             struct drm_file *file_priv)
685{
686        struct vmw_private *dev_priv = vmw_priv(dev);
687        struct vmw_user_surface *user_srf;
688        struct vmw_surface *srf;
689        struct vmw_resource *res;
690        struct vmw_resource *tmp;
691        union drm_vmw_surface_create_arg *arg =
692            (union drm_vmw_surface_create_arg *)data;
693        struct drm_vmw_surface_create_req *req = &arg->req;
694        struct drm_vmw_surface_arg *rep = &arg->rep;
695        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
696        struct drm_vmw_size __user *user_sizes;
697        int ret;
698        int i, j;
699        uint32_t cur_bo_offset;
700        struct drm_vmw_size *cur_size;
701        struct vmw_surface_offset *cur_offset;
702        uint32_t num_sizes;
703        uint32_t size;
704        const struct svga3d_surface_desc *desc;
705
706        if (unlikely(vmw_user_surface_size == 0))
707                vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
708                        128;
709
710        num_sizes = 0;
711        for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
712                if (req->mip_levels[i] > DRM_VMW_MAX_MIP_LEVELS)
713                        return -EINVAL;
714                num_sizes += req->mip_levels[i];
715        }
716
717        if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS ||
718            num_sizes == 0)
719                return -EINVAL;
720
721        size = vmw_user_surface_size + 128 +
722                ttm_round_pot(num_sizes * sizeof(struct drm_vmw_size)) +
723                ttm_round_pot(num_sizes * sizeof(struct vmw_surface_offset));
724
725
726        desc = svga3dsurface_get_desc(req->format);
727        if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) {
728                DRM_ERROR("Invalid surface format for surface creation.\n");
729                return -EINVAL;
730        }
731
732        ret = ttm_read_lock(&dev_priv->reservation_sem, true);
733        if (unlikely(ret != 0))
734                return ret;
735
736        ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
737                                   size, false, true);
738        if (unlikely(ret != 0)) {
739                if (ret != -ERESTARTSYS)
740                        DRM_ERROR("Out of graphics memory for surface"
741                                  " creation.\n");
742                goto out_unlock;
743        }
744
745        user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL);
746        if (unlikely(user_srf == NULL)) {
747                ret = -ENOMEM;
748                goto out_no_user_srf;
749        }
750
751        srf = &user_srf->srf;
752        res = &srf->res;
753
754        srf->flags = req->flags;
755        srf->format = req->format;
756        srf->scanout = req->scanout;
757
758        memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels));
759        srf->num_sizes = num_sizes;
760        user_srf->size = size;
761
762        srf->sizes = kmalloc(srf->num_sizes * sizeof(*srf->sizes), GFP_KERNEL);
763        if (unlikely(srf->sizes == NULL)) {
764                ret = -ENOMEM;
765                goto out_no_sizes;
766        }
767        srf->offsets = kmalloc(srf->num_sizes * sizeof(*srf->offsets),
768                               GFP_KERNEL);
769        if (unlikely(srf->sizes == NULL)) {
770                ret = -ENOMEM;
771                goto out_no_offsets;
772        }
773
774        user_sizes = (struct drm_vmw_size __user *)(unsigned long)
775            req->size_addr;
776
777        ret = copy_from_user(srf->sizes, user_sizes,
778                             srf->num_sizes * sizeof(*srf->sizes));
779        if (unlikely(ret != 0)) {
780                ret = -EFAULT;
781                goto out_no_copy;
782        }
783
784        srf->base_size = *srf->sizes;
785        srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
786        srf->multisample_count = 0;
787
788        cur_bo_offset = 0;
789        cur_offset = srf->offsets;
790        cur_size = srf->sizes;
791
792        for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
793                for (j = 0; j < srf->mip_levels[i]; ++j) {
794                        uint32_t stride = svga3dsurface_calculate_pitch
795                                (desc, cur_size);
796
797                        cur_offset->face = i;
798                        cur_offset->mip = j;
799                        cur_offset->bo_offset = cur_bo_offset;
800                        cur_bo_offset += svga3dsurface_get_image_buffer_size
801                                (desc, cur_size, stride);
802                        ++cur_offset;
803                        ++cur_size;
804                }
805        }
806        res->backup_size = cur_bo_offset;
807        if (srf->scanout &&
808            srf->num_sizes == 1 &&
809            srf->sizes[0].width == 64 &&
810            srf->sizes[0].height == 64 &&
811            srf->format == SVGA3D_A8R8G8B8) {
812
813                srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL);
814                /* clear the image */
815                if (srf->snooper.image) {
816                        memset(srf->snooper.image, 0x00, 64 * 64 * 4);
817                } else {
818                        DRM_ERROR("Failed to allocate cursor_image\n");
819                        ret = -ENOMEM;
820                        goto out_no_copy;
821                }
822        } else {
823                srf->snooper.image = NULL;
824        }
825        srf->snooper.crtc = NULL;
826
827        user_srf->prime.base.shareable = false;
828        user_srf->prime.base.tfile = NULL;
829        if (drm_is_primary_client(file_priv))
830                user_srf->master = drm_master_get(file_priv->master);
831
832        /**
833         * From this point, the generic resource management functions
834         * destroy the object on failure.
835         */
836
837        ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);
838        if (unlikely(ret != 0))
839                goto out_unlock;
840
841        /*
842         * A gb-aware client referencing a shared surface will
843         * expect a backup buffer to be present.
844         */
845        if (dev_priv->has_mob && req->shareable) {
846                uint32_t backup_handle;
847
848                ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
849                                            res->backup_size,
850                                            true,
851                                            &backup_handle,
852                                            &res->backup);
853                if (unlikely(ret != 0)) {
854                        vmw_resource_unreference(&res);
855                        goto out_unlock;
856                }
857        }
858
859        tmp = vmw_resource_reference(&srf->res);
860        ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
861                                    req->shareable, VMW_RES_SURFACE,
862                                    &vmw_user_surface_base_release, NULL);
863
864        if (unlikely(ret != 0)) {
865                vmw_resource_unreference(&tmp);
866                vmw_resource_unreference(&res);
867                goto out_unlock;
868        }
869
870        rep->sid = user_srf->prime.base.hash.key;
871        vmw_resource_unreference(&res);
872
873        ttm_read_unlock(&dev_priv->reservation_sem);
874        return 0;
875out_no_copy:
876        kfree(srf->offsets);
877out_no_offsets:
878        kfree(srf->sizes);
879out_no_sizes:
880        ttm_prime_object_kfree(user_srf, prime);
881out_no_user_srf:
882        ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
883out_unlock:
884        ttm_read_unlock(&dev_priv->reservation_sem);
885        return ret;
886}
887
888
889static int
890vmw_surface_handle_reference(struct vmw_private *dev_priv,
891                             struct drm_file *file_priv,
892                             uint32_t u_handle,
893                             enum drm_vmw_handle_type handle_type,
894                             struct ttm_base_object **base_p)
895{
896        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
897        struct vmw_user_surface *user_srf;
898        uint32_t handle;
899        struct ttm_base_object *base;
900        int ret;
901        bool require_exist = false;
902
903        if (handle_type == DRM_VMW_HANDLE_PRIME) {
904                ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle);
905                if (unlikely(ret != 0))
906                        return ret;
907        } else {
908                if (unlikely(drm_is_render_client(file_priv)))
909                        require_exist = true;
910
911                handle = u_handle;
912        }
913
914        ret = -EINVAL;
915        base = ttm_base_object_lookup_for_ref(dev_priv->tdev, handle);
916        if (unlikely(base == NULL)) {
917                DRM_ERROR("Could not find surface to reference.\n");
918                goto out_no_lookup;
919        }
920
921        if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) {
922                DRM_ERROR("Referenced object is not a surface.\n");
923                goto out_bad_resource;
924        }
925
926        if (handle_type != DRM_VMW_HANDLE_PRIME) {
927                user_srf = container_of(base, struct vmw_user_surface,
928                                        prime.base);
929
930                /*
931                 * Make sure the surface creator has the same
932                 * authenticating master, or is already registered with us.
933                 */
934                if (drm_is_primary_client(file_priv) &&
935                    user_srf->master != file_priv->master)
936                        require_exist = true;
937
938                ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL,
939                                         require_exist);
940                if (unlikely(ret != 0)) {
941                        DRM_ERROR("Could not add a reference to a surface.\n");
942                        goto out_bad_resource;
943                }
944        }
945
946        *base_p = base;
947        return 0;
948
949out_bad_resource:
950        ttm_base_object_unref(&base);
951out_no_lookup:
952        if (handle_type == DRM_VMW_HANDLE_PRIME)
953                (void) ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE);
954
955        return ret;
956}
957
958/**
959 * vmw_user_surface_define_ioctl - Ioctl function implementing
960 *                                  the user surface reference functionality.
961 *
962 * @dev:            Pointer to a struct drm_device.
963 * @data:           Pointer to data copied from / to user-space.
964 * @file_priv:      Pointer to a drm file private structure.
965 */
966int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
967                                struct drm_file *file_priv)
968{
969        struct vmw_private *dev_priv = vmw_priv(dev);
970        union drm_vmw_surface_reference_arg *arg =
971            (union drm_vmw_surface_reference_arg *)data;
972        struct drm_vmw_surface_arg *req = &arg->req;
973        struct drm_vmw_surface_create_req *rep = &arg->rep;
974        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
975        struct vmw_surface *srf;
976        struct vmw_user_surface *user_srf;
977        struct drm_vmw_size __user *user_sizes;
978        struct ttm_base_object *base;
979        int ret;
980
981        ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid,
982                                           req->handle_type, &base);
983        if (unlikely(ret != 0))
984                return ret;
985
986        user_srf = container_of(base, struct vmw_user_surface, prime.base);
987        srf = &user_srf->srf;
988
989        rep->flags = srf->flags;
990        rep->format = srf->format;
991        memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels));
992        user_sizes = (struct drm_vmw_size __user *)(unsigned long)
993            rep->size_addr;
994
995        if (user_sizes)
996                ret = copy_to_user(user_sizes, &srf->base_size,
997                                   sizeof(srf->base_size));
998        if (unlikely(ret != 0)) {
999                DRM_ERROR("copy_to_user failed %p %u\n",
1000                          user_sizes, srf->num_sizes);
1001                ttm_ref_object_base_unref(tfile, base->hash.key, TTM_REF_USAGE);
1002                ret = -EFAULT;
1003        }
1004
1005        ttm_base_object_unref(&base);
1006
1007        return ret;
1008}
1009
1010/**
1011 * vmw_surface_define_encode - Encode a surface_define command.
1012 *
1013 * @srf: Pointer to a struct vmw_surface object.
1014 * @cmd_space: Pointer to memory area in which the commands should be encoded.
1015 */
1016static int vmw_gb_surface_create(struct vmw_resource *res)
1017{
1018        struct vmw_private *dev_priv = res->dev_priv;
1019        struct vmw_surface *srf = vmw_res_to_srf(res);
1020        uint32_t cmd_len, submit_len;
1021        int ret;
1022        struct {
1023                SVGA3dCmdHeader header;
1024                SVGA3dCmdDefineGBSurface body;
1025        } *cmd;
1026
1027        if (likely(res->id != -1))
1028                return 0;
1029
1030        (void) vmw_3d_resource_inc(dev_priv, false);
1031        ret = vmw_resource_alloc_id(res);
1032        if (unlikely(ret != 0)) {
1033                DRM_ERROR("Failed to allocate a surface id.\n");
1034                goto out_no_id;
1035        }
1036
1037        if (unlikely(res->id >= VMWGFX_NUM_GB_SURFACE)) {
1038                ret = -EBUSY;
1039                goto out_no_fifo;
1040        }
1041
1042        cmd_len = sizeof(cmd->body);
1043        submit_len = sizeof(*cmd);
1044        cmd = vmw_fifo_reserve(dev_priv, submit_len);
1045        if (unlikely(cmd == NULL)) {
1046                DRM_ERROR("Failed reserving FIFO space for surface "
1047                          "creation.\n");
1048                ret = -ENOMEM;
1049                goto out_no_fifo;
1050        }
1051
1052        cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SURFACE;
1053        cmd->header.size = cmd_len;
1054        cmd->body.sid = srf->res.id;
1055        cmd->body.surfaceFlags = srf->flags;
1056        cmd->body.format = cpu_to_le32(srf->format);
1057        cmd->body.numMipLevels = srf->mip_levels[0];
1058        cmd->body.multisampleCount = srf->multisample_count;
1059        cmd->body.autogenFilter = srf->autogen_filter;
1060        cmd->body.size.width = srf->base_size.width;
1061        cmd->body.size.height = srf->base_size.height;
1062        cmd->body.size.depth = srf->base_size.depth;
1063        vmw_fifo_commit(dev_priv, submit_len);
1064
1065        return 0;
1066
1067out_no_fifo:
1068        vmw_resource_release_id(res);
1069out_no_id:
1070        vmw_3d_resource_dec(dev_priv, false);
1071        return ret;
1072}
1073
1074
1075static int vmw_gb_surface_bind(struct vmw_resource *res,
1076                               struct ttm_validate_buffer *val_buf)
1077{
1078        struct vmw_private *dev_priv = res->dev_priv;
1079        struct {
1080                SVGA3dCmdHeader header;
1081                SVGA3dCmdBindGBSurface body;
1082        } *cmd1;
1083        struct {
1084                SVGA3dCmdHeader header;
1085                SVGA3dCmdUpdateGBSurface body;
1086        } *cmd2;
1087        uint32_t submit_size;
1088        struct ttm_buffer_object *bo = val_buf->bo;
1089
1090        BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
1091
1092        submit_size = sizeof(*cmd1) + (res->backup_dirty ? sizeof(*cmd2) : 0);
1093
1094        cmd1 = vmw_fifo_reserve(dev_priv, submit_size);
1095        if (unlikely(cmd1 == NULL)) {
1096                DRM_ERROR("Failed reserving FIFO space for surface "
1097                          "binding.\n");
1098                return -ENOMEM;
1099        }
1100
1101        cmd1->header.id = SVGA_3D_CMD_BIND_GB_SURFACE;
1102        cmd1->header.size = sizeof(cmd1->body);
1103        cmd1->body.sid = res->id;
1104        cmd1->body.mobid = bo->mem.start;
1105        if (res->backup_dirty) {
1106                cmd2 = (void *) &cmd1[1];
1107                cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE;
1108                cmd2->header.size = sizeof(cmd2->body);
1109                cmd2->body.sid = res->id;
1110                res->backup_dirty = false;
1111        }
1112        vmw_fifo_commit(dev_priv, submit_size);
1113
1114        return 0;
1115}
1116
1117static int vmw_gb_surface_unbind(struct vmw_resource *res,
1118                                 bool readback,
1119                                 struct ttm_validate_buffer *val_buf)
1120{
1121        struct vmw_private *dev_priv = res->dev_priv;
1122        struct ttm_buffer_object *bo = val_buf->bo;
1123        struct vmw_fence_obj *fence;
1124
1125        struct {
1126                SVGA3dCmdHeader header;
1127                SVGA3dCmdReadbackGBSurface body;
1128        } *cmd1;
1129        struct {
1130                SVGA3dCmdHeader header;
1131                SVGA3dCmdInvalidateGBSurface body;
1132        } *cmd2;
1133        struct {
1134                SVGA3dCmdHeader header;
1135                SVGA3dCmdBindGBSurface body;
1136        } *cmd3;
1137        uint32_t submit_size;
1138        uint8_t *cmd;
1139
1140
1141        BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
1142
1143        submit_size = sizeof(*cmd3) + (readback ? sizeof(*cmd1) : sizeof(*cmd2));
1144        cmd = vmw_fifo_reserve(dev_priv, submit_size);
1145        if (unlikely(cmd == NULL)) {
1146                DRM_ERROR("Failed reserving FIFO space for surface "
1147                          "unbinding.\n");
1148                return -ENOMEM;
1149        }
1150
1151        if (readback) {
1152                cmd1 = (void *) cmd;
1153                cmd1->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE;
1154                cmd1->header.size = sizeof(cmd1->body);
1155                cmd1->body.sid = res->id;
1156                cmd3 = (void *) &cmd1[1];
1157        } else {
1158                cmd2 = (void *) cmd;
1159                cmd2->header.id = SVGA_3D_CMD_INVALIDATE_GB_SURFACE;
1160                cmd2->header.size = sizeof(cmd2->body);
1161                cmd2->body.sid = res->id;
1162                cmd3 = (void *) &cmd2[1];
1163        }
1164
1165        cmd3->header.id = SVGA_3D_CMD_BIND_GB_SURFACE;
1166        cmd3->header.size = sizeof(cmd3->body);
1167        cmd3->body.sid = res->id;
1168        cmd3->body.mobid = SVGA3D_INVALID_ID;
1169
1170        vmw_fifo_commit(dev_priv, submit_size);
1171
1172        /*
1173         * Create a fence object and fence the backup buffer.
1174         */
1175
1176        (void) vmw_execbuf_fence_commands(NULL, dev_priv,
1177                                          &fence, NULL);
1178
1179        vmw_fence_single_bo(val_buf->bo, fence);
1180
1181        if (likely(fence != NULL))
1182                vmw_fence_obj_unreference(&fence);
1183
1184        return 0;
1185}
1186
1187static int vmw_gb_surface_destroy(struct vmw_resource *res)
1188{
1189        struct vmw_private *dev_priv = res->dev_priv;
1190        struct {
1191                SVGA3dCmdHeader header;
1192                SVGA3dCmdDestroyGBSurface body;
1193        } *cmd;
1194
1195        if (likely(res->id == -1))
1196                return 0;
1197
1198        mutex_lock(&dev_priv->binding_mutex);
1199        vmw_context_binding_res_list_scrub(&res->binding_head);
1200
1201        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
1202        if (unlikely(cmd == NULL)) {
1203                DRM_ERROR("Failed reserving FIFO space for surface "
1204                          "destruction.\n");
1205                mutex_unlock(&dev_priv->binding_mutex);
1206                return -ENOMEM;
1207        }
1208
1209        cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SURFACE;
1210        cmd->header.size = sizeof(cmd->body);
1211        cmd->body.sid = res->id;
1212        vmw_fifo_commit(dev_priv, sizeof(*cmd));
1213        mutex_unlock(&dev_priv->binding_mutex);
1214        vmw_resource_release_id(res);
1215        vmw_3d_resource_dec(dev_priv, false);
1216
1217        return 0;
1218}
1219
1220/**
1221 * vmw_gb_surface_define_ioctl - Ioctl function implementing
1222 *                               the user surface define functionality.
1223 *
1224 * @dev:            Pointer to a struct drm_device.
1225 * @data:           Pointer to data copied from / to user-space.
1226 * @file_priv:      Pointer to a drm file private structure.
1227 */
1228int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
1229                                struct drm_file *file_priv)
1230{
1231        struct vmw_private *dev_priv = vmw_priv(dev);
1232        struct vmw_user_surface *user_srf;
1233        struct vmw_surface *srf;
1234        struct vmw_resource *res;
1235        struct vmw_resource *tmp;
1236        union drm_vmw_gb_surface_create_arg *arg =
1237            (union drm_vmw_gb_surface_create_arg *)data;
1238        struct drm_vmw_gb_surface_create_req *req = &arg->req;
1239        struct drm_vmw_gb_surface_create_rep *rep = &arg->rep;
1240        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1241        int ret;
1242        uint32_t size;
1243        const struct svga3d_surface_desc *desc;
1244        uint32_t backup_handle;
1245
1246        if (unlikely(vmw_user_surface_size == 0))
1247                vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
1248                        128;
1249
1250        size = vmw_user_surface_size + 128;
1251
1252        desc = svga3dsurface_get_desc(req->format);
1253        if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) {
1254                DRM_ERROR("Invalid surface format for surface creation.\n");
1255                return -EINVAL;
1256        }
1257
1258        ret = ttm_read_lock(&dev_priv->reservation_sem, true);
1259        if (unlikely(ret != 0))
1260                return ret;
1261
1262        ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
1263                                   size, false, true);
1264        if (unlikely(ret != 0)) {
1265                if (ret != -ERESTARTSYS)
1266                        DRM_ERROR("Out of graphics memory for surface"
1267                                  " creation.\n");
1268                goto out_unlock;
1269        }
1270
1271        user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL);
1272        if (unlikely(user_srf == NULL)) {
1273                ret = -ENOMEM;
1274                goto out_no_user_srf;
1275        }
1276
1277        srf = &user_srf->srf;
1278        res = &srf->res;
1279
1280        srf->flags = req->svga3d_flags;
1281        srf->format = req->format;
1282        srf->scanout = req->drm_surface_flags & drm_vmw_surface_flag_scanout;
1283        srf->mip_levels[0] = req->mip_levels;
1284        srf->num_sizes = 1;
1285        srf->sizes = NULL;
1286        srf->offsets = NULL;
1287        user_srf->size = size;
1288        srf->base_size = req->base_size;
1289        srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
1290        srf->multisample_count = req->multisample_count;
1291        res->backup_size = svga3dsurface_get_serialized_size
1292          (srf->format, srf->base_size, srf->mip_levels[0],
1293           srf->flags & SVGA3D_SURFACE_CUBEMAP);
1294
1295        user_srf->prime.base.shareable = false;
1296        user_srf->prime.base.tfile = NULL;
1297        if (drm_is_primary_client(file_priv))
1298                user_srf->master = drm_master_get(file_priv->master);
1299
1300        /**
1301         * From this point, the generic resource management functions
1302         * destroy the object on failure.
1303         */
1304
1305        ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);
1306        if (unlikely(ret != 0))
1307                goto out_unlock;
1308
1309        if (req->buffer_handle != SVGA3D_INVALID_ID) {
1310                ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
1311                                             &res->backup);
1312        } else if (req->drm_surface_flags &
1313                   drm_vmw_surface_flag_create_buffer)
1314                ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
1315                                            res->backup_size,
1316                                            req->drm_surface_flags &
1317                                            drm_vmw_surface_flag_shareable,
1318                                            &backup_handle,
1319                                            &res->backup);
1320
1321        if (unlikely(ret != 0)) {
1322                vmw_resource_unreference(&res);
1323                goto out_unlock;
1324        }
1325
1326        tmp = vmw_resource_reference(&srf->res);
1327        ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
1328                                    req->drm_surface_flags &
1329                                    drm_vmw_surface_flag_shareable,
1330                                    VMW_RES_SURFACE,
1331                                    &vmw_user_surface_base_release, NULL);
1332
1333        if (unlikely(ret != 0)) {
1334                vmw_resource_unreference(&tmp);
1335                vmw_resource_unreference(&res);
1336                goto out_unlock;
1337        }
1338
1339        rep->handle = user_srf->prime.base.hash.key;
1340        rep->backup_size = res->backup_size;
1341        if (res->backup) {
1342                rep->buffer_map_handle =
1343                        drm_vma_node_offset_addr(&res->backup->base.vma_node);
1344                rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE;
1345                rep->buffer_handle = backup_handle;
1346        } else {
1347                rep->buffer_map_handle = 0;
1348                rep->buffer_size = 0;
1349                rep->buffer_handle = SVGA3D_INVALID_ID;
1350        }
1351
1352        vmw_resource_unreference(&res);
1353
1354        ttm_read_unlock(&dev_priv->reservation_sem);
1355        return 0;
1356out_no_user_srf:
1357        ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
1358out_unlock:
1359        ttm_read_unlock(&dev_priv->reservation_sem);
1360        return ret;
1361}
1362
1363/**
1364 * vmw_gb_surface_reference_ioctl - Ioctl function implementing
1365 *                                  the user surface reference functionality.
1366 *
1367 * @dev:            Pointer to a struct drm_device.
1368 * @data:           Pointer to data copied from / to user-space.
1369 * @file_priv:      Pointer to a drm file private structure.
1370 */
1371int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
1372                                   struct drm_file *file_priv)
1373{
1374        struct vmw_private *dev_priv = vmw_priv(dev);
1375        union drm_vmw_gb_surface_reference_arg *arg =
1376            (union drm_vmw_gb_surface_reference_arg *)data;
1377        struct drm_vmw_surface_arg *req = &arg->req;
1378        struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep;
1379        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1380        struct vmw_surface *srf;
1381        struct vmw_user_surface *user_srf;
1382        struct ttm_base_object *base;
1383        uint32_t backup_handle;
1384        int ret = -EINVAL;
1385
1386        ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid,
1387                                           req->handle_type, &base);
1388        if (unlikely(ret != 0))
1389                return ret;
1390
1391        user_srf = container_of(base, struct vmw_user_surface, prime.base);
1392        srf = &user_srf->srf;
1393        if (srf->res.backup == NULL) {
1394                DRM_ERROR("Shared GB surface is missing a backup buffer.\n");
1395                goto out_bad_resource;
1396        }
1397
1398        mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */
1399        ret = vmw_user_dmabuf_reference(tfile, srf->res.backup,
1400                                        &backup_handle);
1401        mutex_unlock(&dev_priv->cmdbuf_mutex);
1402
1403        if (unlikely(ret != 0)) {
1404                DRM_ERROR("Could not add a reference to a GB surface "
1405                          "backup buffer.\n");
1406                (void) ttm_ref_object_base_unref(tfile, base->hash.key,
1407                                                 TTM_REF_USAGE);
1408                goto out_bad_resource;
1409        }
1410
1411        rep->creq.svga3d_flags = srf->flags;
1412        rep->creq.format = srf->format;
1413        rep->creq.mip_levels = srf->mip_levels[0];
1414        rep->creq.drm_surface_flags = 0;
1415        rep->creq.multisample_count = srf->multisample_count;
1416        rep->creq.autogen_filter = srf->autogen_filter;
1417        rep->creq.buffer_handle = backup_handle;
1418        rep->creq.base_size = srf->base_size;
1419        rep->crep.handle = user_srf->prime.base.hash.key;
1420        rep->crep.backup_size = srf->res.backup_size;
1421        rep->crep.buffer_handle = backup_handle;
1422        rep->crep.buffer_map_handle =
1423                drm_vma_node_offset_addr(&srf->res.backup->base.vma_node);
1424        rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE;
1425
1426out_bad_resource:
1427        ttm_base_object_unref(&base);
1428
1429        return ret;
1430}
Note: See TracBrowser for help on using the repository browser.