source: src/linux/universal/linux-4.9/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @ 31859

Last change on this file since 31859 was 31859, checked in by brainslayer, 2 months ago

kernel update

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