Subversion Repositories Kolibri OS

Rev

Rev 4569 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4075 Serge 1
/**************************************************************************
2
 *
6296 serge 3
 * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA
4075 Serge 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
 
4080 Serge 28
#include "vmwgfx_drv.h"
4075 Serge 29
#include 
30
#include 
31
 
4111 Serge 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)
4569 Serge 35
#define DMA_ADDR_INVALID ((dma_addr_t) 0)
36
#define DMA_PAGE_INVALID 0UL
4075 Serge 37
 
38
static int vmw_gmr2_bind(struct vmw_private *dev_priv,
4569 Serge 39
			 struct vmw_piter *iter,
4075 Serge 40
			 unsigned long num_pages,
41
			 int gmr_id)
42
{
43
	SVGAFifoCmdDefineGMR2 define_cmd;
44
	SVGAFifoCmdRemapGMR2 remap_cmd;
45
	uint32_t *cmd;
46
	uint32_t *cmd_orig;
4111 Serge 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;
4075 Serge 52
	uint32_t i;
53
 
4111 Serge 54
	cmd_orig = cmd = vmw_fifo_reserve(dev_priv, cmd_size);
4075 Serge 55
	if (unlikely(cmd == NULL))
56
		return -ENOMEM;
57
 
58
	define_cmd.gmrId = gmr_id;
59
	define_cmd.numPages = num_pages;
60
 
4111 Serge 61
	*cmd++ = SVGA_CMD_DEFINE_GMR2;
62
	memcpy(cmd, &define_cmd, sizeof(define_cmd));
63
	cmd += sizeof(define_cmd) / sizeof(*cmd);
64
 
65
	/*
66
	 * Need to split the command if there are too many
67
	 * pages that goes into the gmr.
68
	 */
69
 
4075 Serge 70
	remap_cmd.gmrId = gmr_id;
71
	remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ?
72
		SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32;
73
 
4111 Serge 74
	while (num_pages > 0) {
75
		unsigned long nr = min(num_pages, (unsigned long)VMW_PPN_PER_REMAP);
4075 Serge 76
 
4111 Serge 77
		remap_cmd.offsetPages = remap_pos;
78
		remap_cmd.numPages = nr;
79
 
6296 serge 80
		*cmd++ = SVGA_CMD_REMAP_GMR2;
81
		memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
4111 Serge 82
		cmd += sizeof(remap_cmd) / sizeof(*cmd);
4075 Serge 83
 
4111 Serge 84
		for (i = 0; i < nr; ++i) {
4569 Serge 85
			if (VMW_PPN_SIZE <= 4)
86
				*cmd = vmw_piter_dma_addr(iter) >> PAGE_SHIFT;
87
			else
88
				*((uint64_t *)cmd) = vmw_piter_dma_addr(iter) >>
89
					PAGE_SHIFT;
4075 Serge 90
 
4569 Serge 91
			cmd += VMW_PPN_SIZE / sizeof(*cmd);
92
			vmw_piter_next(iter);
93
		}
4075 Serge 94
 
4111 Serge 95
		num_pages -= nr;
96
		remap_pos += nr;
97
	}
4075 Serge 98
 
4111 Serge 99
	BUG_ON(cmd != cmd_orig + cmd_size / sizeof(*cmd));
100
 
101
	vmw_fifo_commit(dev_priv, cmd_size);
102
 
4075 Serge 103
	return 0;
104
}
105
 
106
static void vmw_gmr2_unbind(struct vmw_private *dev_priv,
107
			    int gmr_id)
108
{
109
	SVGAFifoCmdDefineGMR2 define_cmd;
110
	uint32_t define_size = sizeof(define_cmd) + 4;
111
	uint32_t *cmd;
112
 
113
	cmd = vmw_fifo_reserve(dev_priv, define_size);
114
	if (unlikely(cmd == NULL)) {
115
		DRM_ERROR("GMR2 unbind failed.\n");
116
		return;
117
	}
118
	define_cmd.gmrId = gmr_id;
119
	define_cmd.numPages = 0;
120
 
121
	*cmd++ = SVGA_CMD_DEFINE_GMR2;
122
	memcpy(cmd, &define_cmd, sizeof(define_cmd));
123
 
124
	vmw_fifo_commit(dev_priv, define_size);
125
}
126
 
127
 
128
int vmw_gmr_bind(struct vmw_private *dev_priv,
4569 Serge 129
		 const struct vmw_sg_table *vsgt,
4075 Serge 130
		 unsigned long num_pages,
131
		 int gmr_id)
132
{
4569 Serge 133
	struct vmw_piter data_iter;
4075 Serge 134
 
4569 Serge 135
	vmw_piter_start(&data_iter, vsgt, 0);
4075 Serge 136
 
4569 Serge 137
	if (unlikely(!vmw_piter_next(&data_iter)))
138
		return 0;
139
 
140
	if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR2)))
6296 serge 141
		return -EINVAL;
4569 Serge 142
 
143
	return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id);
4075 Serge 144
}
145
 
146
 
147
void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id)
148
{
4569 Serge 149
	if (likely(dev_priv->capabilities & SVGA_CAP_GMR2))
4075 Serge 150
		vmw_gmr2_unbind(dev_priv, gmr_id);
151
}