0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <drm/ttm/ttm_bo_driver.h>
0029
0030 #include "vmwgfx_drv.h"
0031
0032 #define VMW_PPN_SIZE (sizeof(unsigned long))
0033
0034 #define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE)
0035 #define DMA_ADDR_INVALID ((dma_addr_t) 0)
0036 #define DMA_PAGE_INVALID 0UL
0037
0038 static int vmw_gmr2_bind(struct vmw_private *dev_priv,
0039 struct vmw_piter *iter,
0040 unsigned long num_pages,
0041 int gmr_id)
0042 {
0043 SVGAFifoCmdDefineGMR2 define_cmd;
0044 SVGAFifoCmdRemapGMR2 remap_cmd;
0045 uint32_t *cmd;
0046 uint32_t *cmd_orig;
0047 uint32_t define_size = sizeof(define_cmd) + sizeof(*cmd);
0048 uint32_t remap_num = num_pages / VMW_PPN_PER_REMAP + ((num_pages % VMW_PPN_PER_REMAP) > 0);
0049 uint32_t remap_size = VMW_PPN_SIZE * num_pages + (sizeof(remap_cmd) + sizeof(*cmd)) * remap_num;
0050 uint32_t remap_pos = 0;
0051 uint32_t cmd_size = define_size + remap_size;
0052 uint32_t i;
0053
0054 cmd_orig = cmd = VMW_CMD_RESERVE(dev_priv, cmd_size);
0055 if (unlikely(cmd == NULL))
0056 return -ENOMEM;
0057
0058 define_cmd.gmrId = gmr_id;
0059 define_cmd.numPages = num_pages;
0060
0061 *cmd++ = SVGA_CMD_DEFINE_GMR2;
0062 memcpy(cmd, &define_cmd, sizeof(define_cmd));
0063 cmd += sizeof(define_cmd) / sizeof(*cmd);
0064
0065
0066
0067
0068
0069
0070 remap_cmd.gmrId = gmr_id;
0071 remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ?
0072 SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32;
0073
0074 while (num_pages > 0) {
0075 unsigned long nr = min_t(unsigned long, num_pages, VMW_PPN_PER_REMAP);
0076
0077 remap_cmd.offsetPages = remap_pos;
0078 remap_cmd.numPages = nr;
0079
0080 *cmd++ = SVGA_CMD_REMAP_GMR2;
0081 memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
0082 cmd += sizeof(remap_cmd) / sizeof(*cmd);
0083
0084 for (i = 0; i < nr; ++i) {
0085 if (VMW_PPN_SIZE <= 4)
0086 *cmd = vmw_piter_dma_addr(iter) >> PAGE_SHIFT;
0087 else
0088 *((uint64_t *)cmd) = vmw_piter_dma_addr(iter) >>
0089 PAGE_SHIFT;
0090
0091 cmd += VMW_PPN_SIZE / sizeof(*cmd);
0092 vmw_piter_next(iter);
0093 }
0094
0095 num_pages -= nr;
0096 remap_pos += nr;
0097 }
0098
0099 BUG_ON(cmd != cmd_orig + cmd_size / sizeof(*cmd));
0100
0101 vmw_cmd_commit(dev_priv, cmd_size);
0102
0103 return 0;
0104 }
0105
0106 static void vmw_gmr2_unbind(struct vmw_private *dev_priv,
0107 int gmr_id)
0108 {
0109 SVGAFifoCmdDefineGMR2 define_cmd;
0110 uint32_t define_size = sizeof(define_cmd) + 4;
0111 uint32_t *cmd;
0112
0113 cmd = VMW_CMD_RESERVE(dev_priv, define_size);
0114 if (unlikely(cmd == NULL))
0115 return;
0116
0117 define_cmd.gmrId = gmr_id;
0118 define_cmd.numPages = 0;
0119
0120 *cmd++ = SVGA_CMD_DEFINE_GMR2;
0121 memcpy(cmd, &define_cmd, sizeof(define_cmd));
0122
0123 vmw_cmd_commit(dev_priv, define_size);
0124 }
0125
0126
0127 int vmw_gmr_bind(struct vmw_private *dev_priv,
0128 const struct vmw_sg_table *vsgt,
0129 unsigned long num_pages,
0130 int gmr_id)
0131 {
0132 struct vmw_piter data_iter;
0133
0134 vmw_piter_start(&data_iter, vsgt, 0);
0135
0136 if (unlikely(!vmw_piter_next(&data_iter)))
0137 return 0;
0138
0139 if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR2)))
0140 return -EINVAL;
0141
0142 return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id);
0143 }
0144
0145
0146 void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id)
0147 {
0148 if (likely(dev_priv->capabilities & SVGA_CAP_GMR2))
0149 vmw_gmr2_unbind(dev_priv, gmr_id);
0150 }