1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /**************************************************************************
4 * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
28 #include <drm/ttm/ttm_bo_driver.h>
30 #include "vmwgfx_drv.h"
32 #define VMW_PPN_SIZE (sizeof(unsigned long))
33 /* A future safe maximum remap size. */
34 #define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE)
35 #define DMA_ADDR_INVALID ((dma_addr_t) 0)
36 #define DMA_PAGE_INVALID 0UL
38 static int vmw_gmr2_bind(struct vmw_private
*dev_priv
,
39 struct vmw_piter
*iter
,
40 unsigned long num_pages
,
43 SVGAFifoCmdDefineGMR2 define_cmd
;
44 SVGAFifoCmdRemapGMR2 remap_cmd
;
47 uint32_t define_size
= sizeof(define_cmd
) + sizeof(*cmd
);
48 uint32_t remap_num
= num_pages
/ VMW_PPN_PER_REMAP
+ ((num_pages
% VMW_PPN_PER_REMAP
) > 0);
49 uint32_t remap_size
= VMW_PPN_SIZE
* num_pages
+ (sizeof(remap_cmd
) + sizeof(*cmd
)) * remap_num
;
50 uint32_t remap_pos
= 0;
51 uint32_t cmd_size
= define_size
+ remap_size
;
54 cmd_orig
= cmd
= VMW_FIFO_RESERVE(dev_priv
, cmd_size
);
55 if (unlikely(cmd
== NULL
))
58 define_cmd
.gmrId
= gmr_id
;
59 define_cmd
.numPages
= num_pages
;
61 *cmd
++ = SVGA_CMD_DEFINE_GMR2
;
62 memcpy(cmd
, &define_cmd
, sizeof(define_cmd
));
63 cmd
+= sizeof(define_cmd
) / sizeof(*cmd
);
66 * Need to split the command if there are too many
67 * pages that goes into the gmr.
70 remap_cmd
.gmrId
= gmr_id
;
71 remap_cmd
.flags
= (VMW_PPN_SIZE
> sizeof(*cmd
)) ?
72 SVGA_REMAP_GMR2_PPN64
: SVGA_REMAP_GMR2_PPN32
;
74 while (num_pages
> 0) {
75 unsigned long nr
= min(num_pages
, (unsigned long)VMW_PPN_PER_REMAP
);
77 remap_cmd
.offsetPages
= remap_pos
;
78 remap_cmd
.numPages
= nr
;
80 *cmd
++ = SVGA_CMD_REMAP_GMR2
;
81 memcpy(cmd
, &remap_cmd
, sizeof(remap_cmd
));
82 cmd
+= sizeof(remap_cmd
) / sizeof(*cmd
);
84 for (i
= 0; i
< nr
; ++i
) {
85 if (VMW_PPN_SIZE
<= 4)
86 *cmd
= vmw_piter_dma_addr(iter
) >> PAGE_SHIFT
;
88 *((uint64_t *)cmd
) = vmw_piter_dma_addr(iter
) >>
91 cmd
+= VMW_PPN_SIZE
/ sizeof(*cmd
);
99 BUG_ON(cmd
!= cmd_orig
+ cmd_size
/ sizeof(*cmd
));
101 vmw_fifo_commit(dev_priv
, cmd_size
);
106 static void vmw_gmr2_unbind(struct vmw_private
*dev_priv
,
109 SVGAFifoCmdDefineGMR2 define_cmd
;
110 uint32_t define_size
= sizeof(define_cmd
) + 4;
113 cmd
= VMW_FIFO_RESERVE(dev_priv
, define_size
);
114 if (unlikely(cmd
== NULL
))
117 define_cmd
.gmrId
= gmr_id
;
118 define_cmd
.numPages
= 0;
120 *cmd
++ = SVGA_CMD_DEFINE_GMR2
;
121 memcpy(cmd
, &define_cmd
, sizeof(define_cmd
));
123 vmw_fifo_commit(dev_priv
, define_size
);
127 int vmw_gmr_bind(struct vmw_private
*dev_priv
,
128 const struct vmw_sg_table
*vsgt
,
129 unsigned long num_pages
,
132 struct vmw_piter data_iter
;
134 vmw_piter_start(&data_iter
, vsgt
, 0);
136 if (unlikely(!vmw_piter_next(&data_iter
)))
139 if (unlikely(!(dev_priv
->capabilities
& SVGA_CAP_GMR2
)))
142 return vmw_gmr2_bind(dev_priv
, &data_iter
, num_pages
, gmr_id
);
146 void vmw_gmr_unbind(struct vmw_private
*dev_priv
, int gmr_id
)
148 if (likely(dev_priv
->capabilities
& SVGA_CAP_GMR2
))
149 vmw_gmr2_unbind(dev_priv
, gmr_id
);