Subversion Repositories Kolibri OS

Rev

Rev 4569 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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.  */
  41. struct vmw_user_surface {
  42.         struct ttm_prime_object prime;
  43.         struct vmw_surface srf;
  44.         uint32_t size;
  45. };
  46.  
  47. /**
  48.  * struct vmw_surface_offset - Backing store mip level offset info
  49.  *
  50.  * @face:           Surface face.
  51.  * @mip:            Mip level.
  52.  * @bo_offset:      Offset into backing store of this mip level.
  53.  *
  54.  */
  55. struct vmw_surface_offset {
  56.         uint32_t face;
  57.         uint32_t mip;
  58.         uint32_t bo_offset;
  59. };
  60.  
  61. static void vmw_user_surface_free(struct vmw_resource *res);
  62. static struct vmw_resource *
  63. vmw_user_surface_base_to_res(struct ttm_base_object *base);
  64. static int vmw_legacy_srf_bind(struct vmw_resource *res,
  65.                                struct ttm_validate_buffer *val_buf);
  66. static int vmw_legacy_srf_unbind(struct vmw_resource *res,
  67.                                  bool readback,
  68.                                  struct ttm_validate_buffer *val_buf);
  69. static int vmw_legacy_srf_create(struct vmw_resource *res);
  70. static int vmw_legacy_srf_destroy(struct vmw_resource *res);
  71. static int vmw_gb_surface_create(struct vmw_resource *res);
  72. static int vmw_gb_surface_bind(struct vmw_resource *res,
  73.                                struct ttm_validate_buffer *val_buf);
  74. static int vmw_gb_surface_unbind(struct vmw_resource *res,
  75.                                  bool readback,
  76.                                  struct ttm_validate_buffer *val_buf);
  77. static int vmw_gb_surface_destroy(struct vmw_resource *res);
  78.  
  79.  
  80. static const struct vmw_user_resource_conv user_surface_conv = {
  81.         .object_type = VMW_RES_SURFACE,
  82.         .base_obj_to_res = vmw_user_surface_base_to_res,
  83.         .res_free = vmw_user_surface_free
  84. };
  85.  
  86. const struct vmw_user_resource_conv *user_surface_converter =
  87.         &user_surface_conv;
  88.  
  89.  
  90. static uint64_t vmw_user_surface_size;
  91.  
  92. static const struct vmw_res_func vmw_legacy_surface_func = {
  93.         .res_type = vmw_res_surface,
  94.         .needs_backup = false,
  95.         .may_evict = true,
  96.         .type_name = "legacy surfaces",
  97.         .backup_placement = &vmw_srf_placement,
  98.         .create = &vmw_legacy_srf_create,
  99.         .destroy = &vmw_legacy_srf_destroy,
  100.         .bind = &vmw_legacy_srf_bind,
  101.         .unbind = &vmw_legacy_srf_unbind
  102. };
  103.  
  104. static const struct vmw_res_func vmw_gb_surface_func = {
  105.         .res_type = vmw_res_surface,
  106.         .needs_backup = true,
  107.         .may_evict = true,
  108.         .type_name = "guest backed surfaces",
  109.         .backup_placement = &vmw_mob_placement,
  110.         .create = vmw_gb_surface_create,
  111.         .destroy = vmw_gb_surface_destroy,
  112.         .bind = vmw_gb_surface_bind,
  113.         .unbind = vmw_gb_surface_unbind
  114. };
  115.  
  116. /**
  117.  * struct vmw_surface_dma - SVGA3D DMA command
  118.  */
  119. struct vmw_surface_dma {
  120.         SVGA3dCmdHeader header;
  121.         SVGA3dCmdSurfaceDMA body;
  122.         SVGA3dCopyBox cb;
  123.         SVGA3dCmdSurfaceDMASuffix suffix;
  124. };
  125.  
  126. /**
  127.  * struct vmw_surface_define - SVGA3D Surface Define command
  128.  */
  129. struct vmw_surface_define {
  130.         SVGA3dCmdHeader header;
  131.         SVGA3dCmdDefineSurface body;
  132. };
  133.  
  134. /**
  135.  * struct vmw_surface_destroy - SVGA3D Surface Destroy command
  136.  */
  137. struct vmw_surface_destroy {
  138.         SVGA3dCmdHeader header;
  139.         SVGA3dCmdDestroySurface body;
  140. };
  141.  
  142.  
  143. /**
  144.  * vmw_surface_dma_size - Compute fifo size for a dma command.
  145.  *
  146.  * @srf: Pointer to a struct vmw_surface
  147.  *
  148.  * Computes the required size for a surface dma command for backup or
  149.  * restoration of the surface represented by @srf.
  150.  */
  151. static inline uint32_t vmw_surface_dma_size(const struct vmw_surface *srf)
  152. {
  153.         return srf->num_sizes * sizeof(struct vmw_surface_dma);
  154. }
  155.  
  156.  
  157. /**
  158.  * vmw_surface_define_size - Compute fifo size for a surface define command.
  159.  *
  160.  * @srf: Pointer to a struct vmw_surface
  161.  *
  162.  * Computes the required size for a surface define command for the definition
  163.  * of the surface represented by @srf.
  164.  */
  165. static inline uint32_t vmw_surface_define_size(const struct vmw_surface *srf)
  166. {
  167.         return sizeof(struct vmw_surface_define) + srf->num_sizes *
  168.                 sizeof(SVGA3dSize);
  169. }
  170.  
  171.  
  172. /**
  173.  * vmw_surface_destroy_size - Compute fifo size for a surface destroy command.
  174.  *
  175.  * Computes the required size for a surface destroy command for the destruction
  176.  * of a hw surface.
  177.  */
  178. static inline uint32_t vmw_surface_destroy_size(void)
  179. {
  180.         return sizeof(struct vmw_surface_destroy);
  181. }
  182.  
  183. /**
  184.  * vmw_surface_destroy_encode - Encode a surface_destroy command.
  185.  *
  186.  * @id: The surface id
  187.  * @cmd_space: Pointer to memory area in which the commands should be encoded.
  188.  */
  189. static void vmw_surface_destroy_encode(uint32_t id,
  190.                                        void *cmd_space)
  191. {
  192.         struct vmw_surface_destroy *cmd = (struct vmw_surface_destroy *)
  193.                 cmd_space;
  194.  
  195.         cmd->header.id = SVGA_3D_CMD_SURFACE_DESTROY;
  196.         cmd->header.size = sizeof(cmd->body);
  197.         cmd->body.sid = id;
  198. }
  199.  
  200. /**
  201.  * vmw_surface_define_encode - Encode a surface_define command.
  202.  *
  203.  * @srf: Pointer to a struct vmw_surface object.
  204.  * @cmd_space: Pointer to memory area in which the commands should be encoded.
  205.  */
  206. static void vmw_surface_define_encode(const struct vmw_surface *srf,
  207.                                       void *cmd_space)
  208. {
  209.         struct vmw_surface_define *cmd = (struct vmw_surface_define *)
  210.                 cmd_space;
  211.         struct drm_vmw_size *src_size;
  212.         SVGA3dSize *cmd_size;
  213.         uint32_t cmd_len;
  214.         int i;
  215.  
  216.         cmd_len = sizeof(cmd->body) + srf->num_sizes * sizeof(SVGA3dSize);
  217.  
  218.         cmd->header.id = SVGA_3D_CMD_SURFACE_DEFINE;
  219.         cmd->header.size = cmd_len;
  220.         cmd->body.sid = srf->res.id;
  221.         cmd->body.surfaceFlags = srf->flags;
  222.         cmd->body.format = cpu_to_le32(srf->format);
  223.         for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
  224.                 cmd->body.face[i].numMipLevels = srf->mip_levels[i];
  225.  
  226.         cmd += 1;
  227.         cmd_size = (SVGA3dSize *) cmd;
  228.         src_size = srf->sizes;
  229.  
  230.         for (i = 0; i < srf->num_sizes; ++i, cmd_size++, src_size++) {
  231.                 cmd_size->width = src_size->width;
  232.                 cmd_size->height = src_size->height;
  233.                 cmd_size->depth = src_size->depth;
  234.         }
  235. }
  236.  
  237. /**
  238.  * vmw_surface_dma_encode - Encode a surface_dma command.
  239.  *
  240.  * @srf: Pointer to a struct vmw_surface object.
  241.  * @cmd_space: Pointer to memory area in which the commands should be encoded.
  242.  * @ptr: Pointer to an SVGAGuestPtr indicating where the surface contents
  243.  * should be placed or read from.
  244.  * @to_surface: Boolean whether to DMA to the surface or from the surface.
  245.  */
  246. static void vmw_surface_dma_encode(struct vmw_surface *srf,
  247.                                    void *cmd_space,
  248.                                    const SVGAGuestPtr *ptr,
  249.                                    bool to_surface)
  250. {
  251.         uint32_t i;
  252.         struct vmw_surface_dma *cmd = (struct vmw_surface_dma *)cmd_space;
  253.         const struct svga3d_surface_desc *desc =
  254.                 svga3dsurface_get_desc(srf->format);
  255.  
  256.         for (i = 0; i < srf->num_sizes; ++i) {
  257.                 SVGA3dCmdHeader *header = &cmd->header;
  258.                 SVGA3dCmdSurfaceDMA *body = &cmd->body;
  259.                 SVGA3dCopyBox *cb = &cmd->cb;
  260.                 SVGA3dCmdSurfaceDMASuffix *suffix = &cmd->suffix;
  261.                 const struct vmw_surface_offset *cur_offset = &srf->offsets[i];
  262.                 const struct drm_vmw_size *cur_size = &srf->sizes[i];
  263.  
  264.                 header->id = SVGA_3D_CMD_SURFACE_DMA;
  265.                 header->size = sizeof(*body) + sizeof(*cb) + sizeof(*suffix);
  266.  
  267.                 body->guest.ptr = *ptr;
  268.                 body->guest.ptr.offset += cur_offset->bo_offset;
  269.                 body->guest.pitch = svga3dsurface_calculate_pitch(desc,
  270.                                                                   cur_size);
  271.                 body->host.sid = srf->res.id;
  272.                 body->host.face = cur_offset->face;
  273.                 body->host.mipmap = cur_offset->mip;
  274.                 body->transfer = ((to_surface) ?  SVGA3D_WRITE_HOST_VRAM :
  275.                                   SVGA3D_READ_HOST_VRAM);
  276.                 cb->x = 0;
  277.                 cb->y = 0;
  278.                 cb->z = 0;
  279.                 cb->srcx = 0;
  280.                 cb->srcy = 0;
  281.                 cb->srcz = 0;
  282.                 cb->w = cur_size->width;
  283.                 cb->h = cur_size->height;
  284.                 cb->d = cur_size->depth;
  285.  
  286.                 suffix->suffixSize = sizeof(*suffix);
  287.                 suffix->maximumOffset =
  288.                         svga3dsurface_get_image_buffer_size(desc, cur_size,
  289.                                                             body->guest.pitch);
  290.                 suffix->flags.discard = 0;
  291.                 suffix->flags.unsynchronized = 0;
  292.                 suffix->flags.reserved = 0;
  293.                 ++cmd;
  294.         }
  295. };
  296.  
  297.  
  298. /**
  299.  * vmw_hw_surface_destroy - destroy a Device surface
  300.  *
  301.  * @res:        Pointer to a struct vmw_resource embedded in a struct
  302.  *              vmw_surface.
  303.  *
  304.  * Destroys a the device surface associated with a struct vmw_surface if
  305.  * any, and adjusts accounting and resource count accordingly.
  306.  */
  307. static void vmw_hw_surface_destroy(struct vmw_resource *res)
  308. {
  309.  
  310.         struct vmw_private *dev_priv = res->dev_priv;
  311.         struct vmw_surface *srf;
  312.         void *cmd;
  313.  
  314.         if (res->func->destroy == vmw_gb_surface_destroy) {
  315.                 (void) vmw_gb_surface_destroy(res);
  316.                 return;
  317.         }
  318.  
  319.         if (res->id != -1) {
  320.  
  321.                 cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size());
  322.                 if (unlikely(cmd == NULL)) {
  323.                         DRM_ERROR("Failed reserving FIFO space for surface "
  324.                                   "destruction.\n");
  325.                         return;
  326.                 }
  327.  
  328.                 vmw_surface_destroy_encode(res->id, cmd);
  329.                 vmw_fifo_commit(dev_priv, vmw_surface_destroy_size());
  330.  
  331.                 /*
  332.                  * used_memory_size_atomic, or separate lock
  333.                  * to avoid taking dev_priv::cmdbuf_mutex in
  334.                  * the destroy path.
  335.                  */
  336.  
  337.                 mutex_lock(&dev_priv->cmdbuf_mutex);
  338.                 srf = vmw_res_to_srf(res);
  339.                 dev_priv->used_memory_size -= res->backup_size;
  340.                 mutex_unlock(&dev_priv->cmdbuf_mutex);
  341.         }
  342.         vmw_3d_resource_dec(dev_priv, false);
  343. }
  344.  
  345. /**
  346.  * vmw_legacy_srf_create - Create a device surface as part of the
  347.  * resource validation process.
  348.  *
  349.  * @res: Pointer to a struct vmw_surface.
  350.  *
  351.  * If the surface doesn't have a hw id.
  352.  *
  353.  * Returns -EBUSY if there wasn't sufficient device resources to
  354.  * complete the validation. Retry after freeing up resources.
  355.  *
  356.  * May return other errors if the kernel is out of guest resources.
  357.  */
  358. static int vmw_legacy_srf_create(struct vmw_resource *res)
  359. {
  360.         struct vmw_private *dev_priv = res->dev_priv;
  361.         struct vmw_surface *srf;
  362.         uint32_t submit_size;
  363.         uint8_t *cmd;
  364.         int ret;
  365.  
  366.         if (likely(res->id != -1))
  367.                 return 0;
  368.  
  369.         srf = vmw_res_to_srf(res);
  370.         if (unlikely(dev_priv->used_memory_size + res->backup_size >=
  371.                      dev_priv->memory_size))
  372.                 return -EBUSY;
  373.  
  374.         /*
  375.          * Alloc id for the resource.
  376.          */
  377.  
  378.         ret = vmw_resource_alloc_id(res);
  379.         if (unlikely(ret != 0)) {
  380.                 DRM_ERROR("Failed to allocate a surface id.\n");
  381.                 goto out_no_id;
  382.         }
  383.  
  384.         if (unlikely(res->id >= SVGA3D_MAX_SURFACE_IDS)) {
  385.                 ret = -EBUSY;
  386.                 goto out_no_fifo;
  387.         }
  388.  
  389.         /*
  390.          * Encode surface define- commands.
  391.          */
  392.  
  393.         submit_size = vmw_surface_define_size(srf);
  394.         cmd = vmw_fifo_reserve(dev_priv, submit_size);
  395.         if (unlikely(cmd == NULL)) {
  396.                 DRM_ERROR("Failed reserving FIFO space for surface "
  397.                           "creation.\n");
  398.                 ret = -ENOMEM;
  399.                 goto out_no_fifo;
  400.         }
  401.  
  402.         vmw_surface_define_encode(srf, cmd);
  403.         vmw_fifo_commit(dev_priv, submit_size);
  404.         /*
  405.          * Surface memory usage accounting.
  406.          */
  407.  
  408.         dev_priv->used_memory_size += res->backup_size;
  409.         return 0;
  410.  
  411. out_no_fifo:
  412.         vmw_resource_release_id(res);
  413. out_no_id:
  414.         return ret;
  415. }
  416.  
  417. /**
  418.  * vmw_legacy_srf_dma - Copy backup data to or from a legacy surface.
  419.  *
  420.  * @res:            Pointer to a struct vmw_res embedded in a struct
  421.  *                  vmw_surface.
  422.  * @val_buf:        Pointer to a struct ttm_validate_buffer containing
  423.  *                  information about the backup buffer.
  424.  * @bind:           Boolean wether to DMA to the surface.
  425.  *
  426.  * Transfer backup data to or from a legacy surface as part of the
  427.  * validation process.
  428.  * May return other errors if the kernel is out of guest resources.
  429.  * The backup buffer will be fenced or idle upon successful completion,
  430.  * and if the surface needs persistent backup storage, the backup buffer
  431.  * will also be returned reserved iff @bind is true.
  432.  */
  433. static int vmw_legacy_srf_dma(struct vmw_resource *res,
  434.                               struct ttm_validate_buffer *val_buf,
  435.                               bool bind)
  436. {
  437.         SVGAGuestPtr ptr;
  438.         struct vmw_fence_obj *fence;
  439.         uint32_t submit_size;
  440.         struct vmw_surface *srf = vmw_res_to_srf(res);
  441.         uint8_t *cmd;
  442.         struct vmw_private *dev_priv = res->dev_priv;
  443.  
  444.         BUG_ON(val_buf->bo == NULL);
  445.  
  446.         submit_size = vmw_surface_dma_size(srf);
  447.         cmd = vmw_fifo_reserve(dev_priv, submit_size);
  448.         if (unlikely(cmd == NULL)) {
  449.                 DRM_ERROR("Failed reserving FIFO space for surface "
  450.                           "DMA.\n");
  451.                 return -ENOMEM;
  452.         }
  453.         vmw_bo_get_guest_ptr(val_buf->bo, &ptr);
  454.         vmw_surface_dma_encode(srf, cmd, &ptr, bind);
  455.  
  456.         vmw_fifo_commit(dev_priv, submit_size);
  457.  
  458.         /*
  459.          * Create a fence object and fence the backup buffer.
  460.          */
  461.  
  462.         (void) vmw_execbuf_fence_commands(NULL, dev_priv,
  463.                                           &fence, NULL);
  464.  
  465.         vmw_fence_single_bo(val_buf->bo, fence);
  466.  
  467.         if (likely(fence != NULL))
  468.                 vmw_fence_obj_unreference(&fence);
  469.  
  470.         return 0;
  471. }
  472.  
  473. /**
  474.  * vmw_legacy_srf_bind - Perform a legacy surface bind as part of the
  475.  *                       surface validation process.
  476.  *
  477.  * @res:            Pointer to a struct vmw_res embedded in a struct
  478.  *                  vmw_surface.
  479.  * @val_buf:        Pointer to a struct ttm_validate_buffer containing
  480.  *                  information about the backup buffer.
  481.  *
  482.  * This function will copy backup data to the surface if the
  483.  * backup buffer is dirty.
  484.  */
  485. static int vmw_legacy_srf_bind(struct vmw_resource *res,
  486.                                struct ttm_validate_buffer *val_buf)
  487. {
  488.         if (!res->backup_dirty)
  489.                 return 0;
  490.  
  491.         return vmw_legacy_srf_dma(res, val_buf, true);
  492. }
  493.  
  494.  
  495. /**
  496.  * vmw_legacy_srf_unbind - Perform a legacy surface unbind as part of the
  497.  *                         surface eviction process.
  498.  *
  499.  * @res:            Pointer to a struct vmw_res embedded in a struct
  500.  *                  vmw_surface.
  501.  * @val_buf:        Pointer to a struct ttm_validate_buffer containing
  502.  *                  information about the backup buffer.
  503.  *
  504.  * This function will copy backup data from the surface.
  505.  */
  506. static int vmw_legacy_srf_unbind(struct vmw_resource *res,
  507.                                  bool readback,
  508.                                  struct ttm_validate_buffer *val_buf)
  509. {
  510.         if (unlikely(readback))
  511.                 return vmw_legacy_srf_dma(res, val_buf, false);
  512.         return 0;
  513. }
  514.  
  515. /**
  516.  * vmw_legacy_srf_destroy - Destroy a device surface as part of a
  517.  *                          resource eviction process.
  518.  *
  519.  * @res:            Pointer to a struct vmw_res embedded in a struct
  520.  *                  vmw_surface.
  521.  */
  522. static int vmw_legacy_srf_destroy(struct vmw_resource *res)
  523. {
  524.         struct vmw_private *dev_priv = res->dev_priv;
  525.         uint32_t submit_size;
  526.         uint8_t *cmd;
  527.  
  528.         BUG_ON(res->id == -1);
  529.  
  530.         /*
  531.          * Encode the dma- and surface destroy commands.
  532.          */
  533.  
  534.         submit_size = vmw_surface_destroy_size();
  535.         cmd = vmw_fifo_reserve(dev_priv, submit_size);
  536.         if (unlikely(cmd == NULL)) {
  537.                 DRM_ERROR("Failed reserving FIFO space for surface "
  538.                           "eviction.\n");
  539.                 return -ENOMEM;
  540.         }
  541.  
  542.         vmw_surface_destroy_encode(res->id, cmd);
  543.         vmw_fifo_commit(dev_priv, submit_size);
  544.  
  545.         /*
  546.          * Surface memory usage accounting.
  547.          */
  548.  
  549.         dev_priv->used_memory_size -= res->backup_size;
  550.  
  551.         /*
  552.          * Release the surface ID.
  553.          */
  554.  
  555.         vmw_resource_release_id(res);
  556.  
  557.         return 0;
  558. }
  559.  
  560.  
  561. /**
  562.  * vmw_surface_init - initialize a struct vmw_surface
  563.  *
  564.  * @dev_priv:       Pointer to a device private struct.
  565.  * @srf:            Pointer to the struct vmw_surface to initialize.
  566.  * @res_free:       Pointer to a resource destructor used to free
  567.  *                  the object.
  568.  */
  569. static int vmw_surface_init(struct vmw_private *dev_priv,
  570.                             struct vmw_surface *srf,
  571.                             void (*res_free) (struct vmw_resource *res))
  572. {
  573.         int ret;
  574.         struct vmw_resource *res = &srf->res;
  575.  
  576.         BUG_ON(res_free == NULL);
  577.         if (!dev_priv->has_mob)
  578.         (void) vmw_3d_resource_inc(dev_priv, false);
  579.         ret = vmw_resource_init(dev_priv, res, true, res_free,
  580.                                 (dev_priv->has_mob) ? &vmw_gb_surface_func :
  581.                                 &vmw_legacy_surface_func);
  582.  
  583.         if (unlikely(ret != 0)) {
  584.                 if (!dev_priv->has_mob)
  585.                 vmw_3d_resource_dec(dev_priv, false);
  586.                 res_free(res);
  587.                 return ret;
  588.         }
  589.  
  590.         /*
  591.          * The surface won't be visible to hardware until a
  592.          * surface validate.
  593.          */
  594.  
  595.         vmw_resource_activate(res, vmw_hw_surface_destroy);
  596.         return ret;
  597. }
  598.  
  599. /**
  600.  * vmw_user_surface_base_to_res - TTM base object to resource converter for
  601.  *                                user visible surfaces
  602.  *
  603.  * @base:           Pointer to a TTM base object
  604.  *
  605.  * Returns the struct vmw_resource embedded in a struct vmw_surface
  606.  * for the user-visible object identified by the TTM base object @base.
  607.  */
  608. static struct vmw_resource *
  609. vmw_user_surface_base_to_res(struct ttm_base_object *base)
  610. {
  611.         return &(container_of(base, struct vmw_user_surface,
  612.                               prime.base)->srf.res);
  613. }
  614.  
  615. /**
  616.  * vmw_user_surface_free - User visible surface resource destructor
  617.  *
  618.  * @res:            A struct vmw_resource embedded in a struct vmw_surface.
  619.  */
  620. static void vmw_user_surface_free(struct vmw_resource *res)
  621. {
  622.         struct vmw_surface *srf = vmw_res_to_srf(res);
  623.         struct vmw_user_surface *user_srf =
  624.             container_of(srf, struct vmw_user_surface, srf);
  625.         struct vmw_private *dev_priv = srf->res.dev_priv;
  626.         uint32_t size = user_srf->size;
  627.  
  628.         kfree(srf->offsets);
  629.         kfree(srf->sizes);
  630.         kfree(srf->snooper.image);
  631. //   ttm_base_object_kfree(user_srf, base);
  632.         ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
  633. }
  634.  
  635. /**
  636.  * vmw_user_surface_free - User visible surface TTM base object destructor
  637.  *
  638.  * @p_base:         Pointer to a pointer to a TTM base object
  639.  *                  embedded in a struct vmw_user_surface.
  640.  *
  641.  * Drops the base object's reference on its resource, and the
  642.  * pointer pointed to by *p_base is set to NULL.
  643.  */
  644. static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
  645. {
  646.         struct ttm_base_object *base = *p_base;
  647.         struct vmw_user_surface *user_srf =
  648.             container_of(base, struct vmw_user_surface, prime.base);
  649.         struct vmw_resource *res = &user_srf->srf.res;
  650.  
  651.         *p_base = NULL;
  652.         vmw_resource_unreference(&res);
  653. }
  654.  
  655. #if 0
  656. /**
  657.  * vmw_user_surface_define_ioctl - Ioctl function implementing
  658.  *                                  the user surface define functionality.
  659.  *
  660.  * @dev:            Pointer to a struct drm_device.
  661.  * @data:           Pointer to data copied from / to user-space.
  662.  * @file_priv:      Pointer to a drm file private structure.
  663.  */
  664. int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
  665.                              struct drm_file *file_priv)
  666. {
  667.         struct vmw_private *dev_priv = vmw_priv(dev);
  668.         struct vmw_user_surface *user_srf;
  669.         struct vmw_surface *srf;
  670.         struct vmw_resource *res;
  671.         struct vmw_resource *tmp;
  672.         union drm_vmw_surface_create_arg *arg =
  673.             (union drm_vmw_surface_create_arg *)data;
  674.         struct drm_vmw_surface_create_req *req = &arg->req;
  675.         struct drm_vmw_surface_arg *rep = &arg->rep;
  676.         struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
  677.         struct drm_vmw_size __user *user_sizes;
  678.         int ret;
  679.         int i, j;
  680.         uint32_t cur_bo_offset;
  681.         struct drm_vmw_size *cur_size;
  682.         struct vmw_surface_offset *cur_offset;
  683.         uint32_t num_sizes;
  684.         uint32_t size;
  685.         const struct svga3d_surface_desc *desc;
  686.  
  687.         if (unlikely(vmw_user_surface_size == 0))
  688.                 vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
  689.                         128;
  690.  
  691.         num_sizes = 0;
  692.         for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
  693.                 num_sizes += req->mip_levels[i];
  694.  
  695.         if (num_sizes > DRM_VMW_MAX_SURFACE_FACES *
  696.             DRM_VMW_MAX_MIP_LEVELS)
  697.                 return -EINVAL;
  698.  
  699.         size = vmw_user_surface_size + 128 +
  700.                 ttm_round_pot(num_sizes * sizeof(struct drm_vmw_size)) +
  701.                 ttm_round_pot(num_sizes * sizeof(struct vmw_surface_offset));
  702.  
  703.  
  704.         desc = svga3dsurface_get_desc(req->format);
  705.         if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) {
  706.                 DRM_ERROR("Invalid surface format for surface creation.\n");
  707.                 return -EINVAL;
  708.         }
  709.  
  710.         ret = ttm_read_lock(&dev_priv->reservation_sem, true);
  711.         if (unlikely(ret != 0))
  712.                 return ret;
  713.  
  714.         ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
  715.                                    size, false, true);
  716.         if (unlikely(ret != 0)) {
  717.                 if (ret != -ERESTARTSYS)
  718.                         DRM_ERROR("Out of graphics memory for surface"
  719.                                   " creation.\n");
  720.                 goto out_unlock;
  721.         }
  722.  
  723.         user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL);
  724.         if (unlikely(user_srf == NULL)) {
  725.                 ret = -ENOMEM;
  726.                 goto out_no_user_srf;
  727.         }
  728.  
  729.         srf = &user_srf->srf;
  730.         res = &srf->res;
  731.  
  732.         srf->flags = req->flags;
  733.         srf->format = req->format;
  734.         srf->scanout = req->scanout;
  735.  
  736.         memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels));
  737.         srf->num_sizes = num_sizes;
  738.         user_srf->size = size;
  739.  
  740.         srf->sizes = kmalloc(srf->num_sizes * sizeof(*srf->sizes), GFP_KERNEL);
  741.         if (unlikely(srf->sizes == NULL)) {
  742.                 ret = -ENOMEM;
  743.                 goto out_no_sizes;
  744.         }
  745.         srf->offsets = kmalloc(srf->num_sizes * sizeof(*srf->offsets),
  746.                                GFP_KERNEL);
  747.         if (unlikely(srf->sizes == NULL)) {
  748.                 ret = -ENOMEM;
  749.                 goto out_no_offsets;
  750.         }
  751.  
  752.         user_sizes = (struct drm_vmw_size __user *)(unsigned long)
  753.             req->size_addr;
  754.  
  755.         ret = copy_from_user(srf->sizes, user_sizes,
  756.                              srf->num_sizes * sizeof(*srf->sizes));
  757.         if (unlikely(ret != 0)) {
  758.                 ret = -EFAULT;
  759.                 goto out_no_copy;
  760.         }
  761.  
  762.         srf->base_size = *srf->sizes;
  763.         srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
  764.         srf->multisample_count = 0;
  765.  
  766.         cur_bo_offset = 0;
  767.         cur_offset = srf->offsets;
  768.         cur_size = srf->sizes;
  769.  
  770.         for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
  771.                 for (j = 0; j < srf->mip_levels[i]; ++j) {
  772.                         uint32_t stride = svga3dsurface_calculate_pitch
  773.                                 (desc, cur_size);
  774.  
  775.                         cur_offset->face = i;
  776.                         cur_offset->mip = j;
  777.                         cur_offset->bo_offset = cur_bo_offset;
  778.                         cur_bo_offset += svga3dsurface_get_image_buffer_size
  779.                                 (desc, cur_size, stride);
  780.                         ++cur_offset;
  781.                         ++cur_size;
  782.                 }
  783.         }
  784.         res->backup_size = cur_bo_offset;
  785.         if (srf->scanout &&
  786.             srf->num_sizes == 1 &&
  787.             srf->sizes[0].width == 64 &&
  788.             srf->sizes[0].height == 64 &&
  789.             srf->format == SVGA3D_A8R8G8B8) {
  790.  
  791.                 srf->snooper.image = kmalloc(64 * 64 * 4, GFP_KERNEL);
  792.                 /* clear the image */
  793.                 if (srf->snooper.image) {
  794.                         memset(srf->snooper.image, 0x00, 64 * 64 * 4);
  795.                 } else {
  796.                         DRM_ERROR("Failed to allocate cursor_image\n");
  797.                         ret = -ENOMEM;
  798.                         goto out_no_copy;
  799.                 }
  800.         } else {
  801.                 srf->snooper.image = NULL;
  802.         }
  803.         srf->snooper.crtc = NULL;
  804.  
  805.         user_srf->prime.base.shareable = false;
  806.         user_srf->prime.base.tfile = NULL;
  807.  
  808.         /**
  809.          * From this point, the generic resource management functions
  810.          * destroy the object on failure.
  811.          */
  812.  
  813.         ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);
  814.         if (unlikely(ret != 0))
  815.                 goto out_unlock;
  816.  
  817.         tmp = vmw_resource_reference(&srf->res);
  818.         ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
  819.                                    req->shareable, VMW_RES_SURFACE,
  820.                                    &vmw_user_surface_base_release, NULL);
  821.  
  822.         if (unlikely(ret != 0)) {
  823.                 vmw_resource_unreference(&tmp);
  824.                 vmw_resource_unreference(&res);
  825.                 goto out_unlock;
  826.         }
  827.  
  828.         rep->sid = user_srf->prime.base.hash.key;
  829.         vmw_resource_unreference(&res);
  830.  
  831.         ttm_read_unlock(&dev_priv->reservation_sem);
  832.         return 0;
  833. out_no_copy:
  834.         kfree(srf->offsets);
  835. out_no_offsets:
  836.         kfree(srf->sizes);
  837. out_no_sizes:
  838.         ttm_prime_object_kfree(user_srf, prime);
  839. out_no_user_srf:
  840.         ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
  841. out_unlock:
  842.         ttm_read_unlock(&dev_priv->reservation_sem);
  843.  
  844.         return ret;
  845. }
  846.  
  847. /**
  848.  * vmw_user_surface_define_ioctl - Ioctl function implementing
  849.  *                                  the user surface reference functionality.
  850.  *
  851.  * @dev:            Pointer to a struct drm_device.
  852.  * @data:           Pointer to data copied from / to user-space.
  853.  * @file_priv:      Pointer to a drm file private structure.
  854.  */
  855. int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
  856.                                 struct drm_file *file_priv)
  857. {
  858.         struct vmw_private *dev_priv = vmw_priv(dev);
  859.         union drm_vmw_surface_reference_arg *arg =
  860.             (union drm_vmw_surface_reference_arg *)data;
  861.         struct drm_vmw_surface_arg *req = &arg->req;
  862.         struct drm_vmw_surface_create_req *rep = &arg->rep;
  863.         struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
  864.         struct vmw_surface *srf;
  865.         struct vmw_user_surface *user_srf;
  866.         struct drm_vmw_size __user *user_sizes;
  867.         struct ttm_base_object *base;
  868.         int ret;
  869.  
  870.         ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid,
  871.                                            req->handle_type, &base);
  872.         if (unlikely(ret != 0))
  873.                 return ret;
  874.  
  875.         user_srf = container_of(base, struct vmw_user_surface, prime.base);
  876.         srf = &user_srf->srf;
  877.  
  878.         rep->flags = srf->flags;
  879.         rep->format = srf->format;
  880.         memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels));
  881.         user_sizes = (struct drm_vmw_size __user *)(unsigned long)
  882.             rep->size_addr;
  883.  
  884.         if (user_sizes)
  885.                 ret = copy_to_user(user_sizes, &srf->base_size,
  886.                                    sizeof(srf->base_size));
  887.         if (unlikely(ret != 0)) {
  888.                 DRM_ERROR("copy_to_user failed %p %u\n",
  889.                           user_sizes, srf->num_sizes);
  890.                 ttm_ref_object_base_unref(tfile, base->hash.key, TTM_REF_USAGE);
  891.                 ret = -EFAULT;
  892.         }
  893. out_bad_resource:
  894. out_no_reference:
  895.         ttm_base_object_unref(&base);
  896.  
  897.         return ret;
  898. }
  899.  
  900. #endif
  901.