aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-05-20 16:41:59 -0400
committerDave Airlie <airlied@redhat.com>2016-05-20 16:41:59 -0400
commitfc7fedc20b7c819b9ef003afa16a64dc9e5ac30e (patch)
tree060d0ad8c242388c88415ba5f24067f0c9822d18
parentd5fa33f28401414959b68591075c8053e8276547 (diff)
parentf921791314811afa00bb7fbbd40f51bd3b8eff01 (diff)
Merge tag 'vmwgfx-next-160520' of git://people.freedesktop.org/~thomash/linux into drm-next
Pull request of 2016-05-20 * tag 'vmwgfx-next-160520' of git://people.freedesktop.org/~thomash/linux: drm/vmwgfx: Report vmwgfx version to vmware.log drm/vmwgfx: Add VMWare host messaging capability drm/vmwgfx: Kill some lockdep warnings
-rw-r--r--drivers/gpu/drm/vmwgfx/Makefile2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c20
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h7
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c27
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_msg.c416
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_msg.h191
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c3
8 files changed, 653 insertions, 16 deletions
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile
index d281575bbe11..473d00451b0f 100644
--- a/drivers/gpu/drm/vmwgfx/Makefile
+++ b/drivers/gpu/drm/vmwgfx/Makefile
@@ -8,6 +8,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
8 vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \ 8 vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \
9 vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ 9 vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \
10 vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ 10 vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \
11 vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o 11 vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o
12 12
13obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o 13obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 9555e204814a..9fcd8200d485 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -1,6 +1,6 @@
1/************************************************************************** 1/**************************************************************************
2 * 2 *
3 * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA 3 * Copyright © 2009-2016 VMware, Inc., Palo Alto, CA., USA
4 * All Rights Reserved. 4 * All Rights Reserved.
5 * 5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a 6 * Permission is hereby granted, free of charge, to any person obtaining a
@@ -44,6 +44,12 @@
44#define VMW_MIN_INITIAL_WIDTH 800 44#define VMW_MIN_INITIAL_WIDTH 800
45#define VMW_MIN_INITIAL_HEIGHT 600 45#define VMW_MIN_INITIAL_HEIGHT 600
46 46
47#ifndef VMWGFX_GIT_VERSION
48#define VMWGFX_GIT_VERSION "Unknown"
49#endif
50
51#define VMWGFX_REPO "In Tree"
52
47 53
48/** 54/**
49 * Fully encoded drm commands. Might move to vmw_drm.h 55 * Fully encoded drm commands. Might move to vmw_drm.h
@@ -613,6 +619,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
613 uint32_t svga_id; 619 uint32_t svga_id;
614 enum vmw_res_type i; 620 enum vmw_res_type i;
615 bool refuse_dma = false; 621 bool refuse_dma = false;
622 char host_log[100] = {0};
616 623
617 dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); 624 dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
618 if (unlikely(dev_priv == NULL)) { 625 if (unlikely(dev_priv == NULL)) {
@@ -628,6 +635,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
628 mutex_init(&dev_priv->cmdbuf_mutex); 635 mutex_init(&dev_priv->cmdbuf_mutex);
629 mutex_init(&dev_priv->release_mutex); 636 mutex_init(&dev_priv->release_mutex);
630 mutex_init(&dev_priv->binding_mutex); 637 mutex_init(&dev_priv->binding_mutex);
638 mutex_init(&dev_priv->global_kms_state_mutex);
631 rwlock_init(&dev_priv->resource_lock); 639 rwlock_init(&dev_priv->resource_lock);
632 ttm_lock_init(&dev_priv->reservation_sem); 640 ttm_lock_init(&dev_priv->reservation_sem);
633 spin_lock_init(&dev_priv->hw_lock); 641 spin_lock_init(&dev_priv->hw_lock);
@@ -873,6 +881,16 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
873 881
874 DRM_INFO("DX: %s\n", dev_priv->has_dx ? "yes." : "no."); 882 DRM_INFO("DX: %s\n", dev_priv->has_dx ? "yes." : "no.");
875 883
884 snprintf(host_log, sizeof(host_log), "vmwgfx: %s-%s",
885 VMWGFX_REPO, VMWGFX_GIT_VERSION);
886 vmw_host_log(host_log);
887
888 memset(host_log, 0, sizeof(host_log));
889 snprintf(host_log, sizeof(host_log), "vmwgfx: Module Version: %d.%d.%d",
890 VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR,
891 VMWGFX_DRIVER_PATCHLEVEL);
892 vmw_host_log(host_log);
893
876 if (dev_priv->enable_fb) { 894 if (dev_priv->enable_fb) {
877 vmw_fifo_resource_inc(dev_priv); 895 vmw_fifo_resource_inc(dev_priv);
878 vmw_svga_enable(dev_priv); 896 vmw_svga_enable(dev_priv);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 019a6ca3e8e9..1980e2a28265 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -412,6 +412,7 @@ struct vmw_private {
412 struct drm_property *implicit_placement_property; 412 struct drm_property *implicit_placement_property;
413 unsigned num_implicit; 413 unsigned num_implicit;
414 struct vmw_framebuffer *implicit_fb; 414 struct vmw_framebuffer *implicit_fb;
415 struct mutex global_kms_state_mutex;
415 416
416 /* 417 /*
417 * Context and surface management. 418 * Context and surface management.
@@ -1234,4 +1235,10 @@ static inline void vmw_mmio_write(u32 value, u32 *addr)
1234{ 1235{
1235 WRITE_ONCE(*addr, value); 1236 WRITE_ONCE(*addr, value);
1236} 1237}
1238
1239/**
1240 * Add vmw_msg module function
1241 */
1242extern int vmw_host_log(const char *log);
1243
1237#endif 1244#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index fc20d45e3da9..55231cce73a0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -2143,13 +2143,13 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
2143void vmw_kms_del_active(struct vmw_private *dev_priv, 2143void vmw_kms_del_active(struct vmw_private *dev_priv,
2144 struct vmw_display_unit *du) 2144 struct vmw_display_unit *du)
2145{ 2145{
2146 lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); 2146 mutex_lock(&dev_priv->global_kms_state_mutex);
2147
2148 if (du->active_implicit) { 2147 if (du->active_implicit) {
2149 if (--(dev_priv->num_implicit) == 0) 2148 if (--(dev_priv->num_implicit) == 0)
2150 dev_priv->implicit_fb = NULL; 2149 dev_priv->implicit_fb = NULL;
2151 du->active_implicit = false; 2150 du->active_implicit = false;
2152 } 2151 }
2152 mutex_unlock(&dev_priv->global_kms_state_mutex);
2153} 2153}
2154 2154
2155/** 2155/**
@@ -2165,8 +2165,7 @@ void vmw_kms_add_active(struct vmw_private *dev_priv,
2165 struct vmw_display_unit *du, 2165 struct vmw_display_unit *du,
2166 struct vmw_framebuffer *vfb) 2166 struct vmw_framebuffer *vfb)
2167{ 2167{
2168 lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); 2168 mutex_lock(&dev_priv->global_kms_state_mutex);
2169
2170 WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb); 2169 WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb);
2171 2170
2172 if (!du->active_implicit && du->is_implicit) { 2171 if (!du->active_implicit && du->is_implicit) {
@@ -2174,6 +2173,7 @@ void vmw_kms_add_active(struct vmw_private *dev_priv,
2174 du->active_implicit = true; 2173 du->active_implicit = true;
2175 dev_priv->num_implicit++; 2174 dev_priv->num_implicit++;
2176 } 2175 }
2176 mutex_unlock(&dev_priv->global_kms_state_mutex);
2177} 2177}
2178 2178
2179/** 2179/**
@@ -2190,16 +2190,13 @@ bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv,
2190 struct drm_crtc *crtc) 2190 struct drm_crtc *crtc)
2191{ 2191{
2192 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 2192 struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
2193 bool ret;
2193 2194
2194 lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); 2195 mutex_lock(&dev_priv->global_kms_state_mutex);
2195 2196 ret = !du->is_implicit || dev_priv->num_implicit == 1;
2196 if (!du->is_implicit) 2197 mutex_unlock(&dev_priv->global_kms_state_mutex);
2197 return true;
2198
2199 if (dev_priv->num_implicit != 1)
2200 return false;
2201 2198
2202 return true; 2199 return ret;
2203} 2200}
2204 2201
2205/** 2202/**
@@ -2214,16 +2211,18 @@ void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv,
2214 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 2211 struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
2215 struct vmw_framebuffer *vfb; 2212 struct vmw_framebuffer *vfb;
2216 2213
2217 lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); 2214 mutex_lock(&dev_priv->global_kms_state_mutex);
2218 2215
2219 if (!du->is_implicit) 2216 if (!du->is_implicit)
2220 return; 2217 goto out_unlock;
2221 2218
2222 vfb = vmw_framebuffer_to_vfb(crtc->primary->fb); 2219 vfb = vmw_framebuffer_to_vfb(crtc->primary->fb);
2223 WARN_ON_ONCE(dev_priv->num_implicit != 1 && 2220 WARN_ON_ONCE(dev_priv->num_implicit != 1 &&
2224 dev_priv->implicit_fb != vfb); 2221 dev_priv->implicit_fb != vfb);
2225 2222
2226 dev_priv->implicit_fb = vfb; 2223 dev_priv->implicit_fb = vfb;
2224out_unlock:
2225 mutex_unlock(&dev_priv->global_kms_state_mutex);
2227} 2226}
2228 2227
2229/** 2228/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
new file mode 100644
index 000000000000..6de283c8fa3e
--- /dev/null
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
@@ -0,0 +1,416 @@
1/*
2 * Copyright © 2016 VMware, Inc., Palo Alto, CA., USA
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27
28#include <linux/slab.h>
29#include <linux/module.h>
30#include <linux/kernel.h>
31#include <asm/hypervisor.h>
32#include "drmP.h"
33#include "vmwgfx_msg.h"
34
35
36#define MESSAGE_STATUS_SUCCESS 0x0001
37#define MESSAGE_STATUS_DORECV 0x0002
38#define MESSAGE_STATUS_CPT 0x0010
39#define MESSAGE_STATUS_HB 0x0080
40
41#define RPCI_PROTOCOL_NUM 0x49435052
42#define GUESTMSG_FLAG_COOKIE 0x80000000
43
44#define RETRIES 3
45
46#define VMW_HYPERVISOR_MAGIC 0x564D5868
47#define VMW_HYPERVISOR_PORT 0x5658
48#define VMW_HYPERVISOR_HB_PORT 0x5659
49
50#define VMW_PORT_CMD_MSG 30
51#define VMW_PORT_CMD_HB_MSG 0
52#define VMW_PORT_CMD_OPEN_CHANNEL (MSG_TYPE_OPEN << 16 | VMW_PORT_CMD_MSG)
53#define VMW_PORT_CMD_CLOSE_CHANNEL (MSG_TYPE_CLOSE << 16 | VMW_PORT_CMD_MSG)
54#define VMW_PORT_CMD_SENDSIZE (MSG_TYPE_SENDSIZE << 16 | VMW_PORT_CMD_MSG)
55#define VMW_PORT_CMD_RECVSIZE (MSG_TYPE_RECVSIZE << 16 | VMW_PORT_CMD_MSG)
56#define VMW_PORT_CMD_RECVSTATUS (MSG_TYPE_RECVSTATUS << 16 | VMW_PORT_CMD_MSG)
57
58#define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16)
59
60static u32 vmw_msg_enabled = 1;
61
62enum rpc_msg_type {
63 MSG_TYPE_OPEN,
64 MSG_TYPE_SENDSIZE,
65 MSG_TYPE_SENDPAYLOAD,
66 MSG_TYPE_RECVSIZE,
67 MSG_TYPE_RECVPAYLOAD,
68 MSG_TYPE_RECVSTATUS,
69 MSG_TYPE_CLOSE,
70};
71
72struct rpc_channel {
73 u16 channel_id;
74 u32 cookie_high;
75 u32 cookie_low;
76};
77
78
79
80/**
81 * vmw_open_channel
82 *
83 * @channel: RPC channel
84 * @protocol:
85 *
86 * Returns: 0 on success
87 */
88static int vmw_open_channel(struct rpc_channel *channel, unsigned int protocol)
89{
90 unsigned long eax, ebx, ecx, edx, si = 0, di = 0;
91
92 VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL,
93 (protocol | GUESTMSG_FLAG_COOKIE), si, di,
94 VMW_HYPERVISOR_PORT,
95 VMW_HYPERVISOR_MAGIC,
96 eax, ebx, ecx, edx, si, di);
97
98 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
99 return -EINVAL;
100
101 channel->channel_id = HIGH_WORD(edx);
102 channel->cookie_high = si;
103 channel->cookie_low = di;
104
105 return 0;
106}
107
108
109
110/**
111 * vmw_close_channel
112 *
113 * @channel: RPC channel
114 *
115 * Returns: 0 on success
116 */
117static int vmw_close_channel(struct rpc_channel *channel)
118{
119 unsigned long eax, ebx, ecx, edx, si, di;
120
121 /* Set up additional parameters */
122 si = channel->cookie_high;
123 di = channel->cookie_low;
124
125 VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL,
126 0, si, di,
127 (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
128 VMW_HYPERVISOR_MAGIC,
129 eax, ebx, ecx, edx, si, di);
130
131 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
132 return -EINVAL;
133
134 return 0;
135}
136
137
138
139/**
140 * vmw_send_msg: Sends a message to the host
141 *
142 * @channel: RPC channel
143 * @logmsg: NULL terminated string
144 *
145 * Returns: 0 on success
146 */
147static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
148{
149 unsigned long eax, ebx, ecx, edx, si, di, bp;
150 size_t msg_len = strlen(msg);
151 int retries = 0;
152
153
154 while (retries < RETRIES) {
155 retries++;
156
157 /* Set up additional parameters */
158 si = channel->cookie_high;
159 di = channel->cookie_low;
160
161 VMW_PORT(VMW_PORT_CMD_SENDSIZE,
162 msg_len, si, di,
163 VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
164 VMW_HYPERVISOR_MAGIC,
165 eax, ebx, ecx, edx, si, di);
166
167 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
168 (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
169 /* Expected success + high-bandwidth. Give up. */
170 return -EINVAL;
171 }
172
173 /* Send msg */
174 si = (uintptr_t) msg;
175 di = channel->cookie_low;
176 bp = channel->cookie_high;
177
178 VMW_PORT_HB_OUT(
179 (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
180 msg_len, si, di,
181 VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
182 VMW_HYPERVISOR_MAGIC, bp,
183 eax, ebx, ecx, edx, si, di);
184
185 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) {
186 return 0;
187 } else if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) {
188 /* A checkpoint occurred. Retry. */
189 continue;
190 } else {
191 break;
192 }
193 }
194
195 return -EINVAL;
196}
197
198
199
200/**
201 * vmw_recv_msg: Receives a message from the host
202 *
203 * Note: It is the caller's responsibility to call kfree() on msg.
204 *
205 * @channel: channel opened by vmw_open_channel
206 * @msg: [OUT] message received from the host
207 * @msg_len: message length
208 */
209static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
210 size_t *msg_len)
211{
212 unsigned long eax, ebx, ecx, edx, si, di, bp;
213 char *reply;
214 size_t reply_len;
215 int retries = 0;
216
217
218 *msg_len = 0;
219 *msg = NULL;
220
221 while (retries < RETRIES) {
222 retries++;
223
224 /* Set up additional parameters */
225 si = channel->cookie_high;
226 di = channel->cookie_low;
227
228 VMW_PORT(VMW_PORT_CMD_RECVSIZE,
229 0, si, di,
230 (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
231 VMW_HYPERVISOR_MAGIC,
232 eax, ebx, ecx, edx, si, di);
233
234 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
235 (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
236 DRM_ERROR("Failed to get reply size\n");
237 return -EINVAL;
238 }
239
240 /* No reply available. This is okay. */
241 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_DORECV) == 0)
242 return 0;
243
244 reply_len = ebx;
245 reply = kzalloc(reply_len + 1, GFP_KERNEL);
246 if (reply == NULL) {
247 DRM_ERROR("Cannot allocate memory for reply\n");
248 return -ENOMEM;
249 }
250
251
252 /* Receive buffer */
253 si = channel->cookie_high;
254 di = (uintptr_t) reply;
255 bp = channel->cookie_low;
256
257 VMW_PORT_HB_IN(
258 (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
259 reply_len, si, di,
260 VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
261 VMW_HYPERVISOR_MAGIC, bp,
262 eax, ebx, ecx, edx, si, di);
263
264 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
265 kfree(reply);
266
267 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) {
268 /* A checkpoint occurred. Retry. */
269 continue;
270 }
271
272 return -EINVAL;
273 }
274
275 reply[reply_len] = '\0';
276
277
278 /* Ack buffer */
279 si = channel->cookie_high;
280 di = channel->cookie_low;
281
282 VMW_PORT(VMW_PORT_CMD_RECVSTATUS,
283 MESSAGE_STATUS_SUCCESS, si, di,
284 (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
285 VMW_HYPERVISOR_MAGIC,
286 eax, ebx, ecx, edx, si, di);
287
288 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
289 kfree(reply);
290
291 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_CPT) != 0) {
292 /* A checkpoint occurred. Retry. */
293 continue;
294 }
295
296 return -EINVAL;
297 }
298
299 break;
300 }
301
302 *msg_len = reply_len;
303 *msg = reply;
304
305 return 0;
306}
307
308
309/**
310 * vmw_host_get_guestinfo: Gets a GuestInfo parameter
311 *
312 * Gets the value of a GuestInfo.* parameter. The value returned will be in
313 * a string, and it is up to the caller to post-process.
314 *
315 * @guest_info_param: Parameter to get, e.g. GuestInfo.svga.gl3
316 * @buffer: if NULL, *reply_len will contain reply size.
317 * @length: size of the reply_buf. Set to size of reply upon return
318 *
319 * Returns: 0 on success
320 */
321int vmw_host_get_guestinfo(const char *guest_info_param,
322 char *buffer, size_t *length)
323{
324 struct rpc_channel channel;
325 char *msg, *reply = NULL;
326 size_t msg_len, reply_len = 0;
327 int ret = 0;
328
329
330 if (!vmw_msg_enabled)
331 return -ENODEV;
332
333 if (!guest_info_param || !length)
334 return -EINVAL;
335
336 msg_len = strlen(guest_info_param) + strlen("info-get ") + 1;
337 msg = kzalloc(msg_len, GFP_KERNEL);
338 if (msg == NULL) {
339 DRM_ERROR("Cannot allocate memory to get %s", guest_info_param);
340 return -ENOMEM;
341 }
342
343 sprintf(msg, "info-get %s", guest_info_param);
344
345 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) ||
346 vmw_send_msg(&channel, msg) ||
347 vmw_recv_msg(&channel, (void *) &reply, &reply_len) ||
348 vmw_close_channel(&channel)) {
349 DRM_ERROR("Failed to get %s", guest_info_param);
350
351 ret = -EINVAL;
352 }
353
354 if (buffer && reply && reply_len > 0) {
355 /* Remove reply code, which are the first 2 characters of
356 * the reply
357 */
358 reply_len = max(reply_len - 2, (size_t) 0);
359 reply_len = min(reply_len, *length);
360
361 if (reply_len > 0)
362 memcpy(buffer, reply + 2, reply_len);
363 }
364
365 *length = reply_len;
366
367 kfree(reply);
368 kfree(msg);
369
370 return ret;
371}
372
373
374
375/**
376 * vmw_host_log: Sends a log message to the host
377 *
378 * @log: NULL terminated string
379 *
380 * Returns: 0 on success
381 */
382int vmw_host_log(const char *log)
383{
384 struct rpc_channel channel;
385 char *msg;
386 int msg_len;
387 int ret = 0;
388
389
390 if (!vmw_msg_enabled)
391 return -ENODEV;
392
393 if (!log)
394 return ret;
395
396 msg_len = strlen(log) + strlen("log ") + 1;
397 msg = kzalloc(msg_len, GFP_KERNEL);
398 if (msg == NULL) {
399 DRM_ERROR("Cannot allocate memory for log message\n");
400 return -ENOMEM;
401 }
402
403 sprintf(msg, "log %s", log);
404
405 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) ||
406 vmw_send_msg(&channel, msg) ||
407 vmw_close_channel(&channel)) {
408 DRM_ERROR("Failed to send log\n");
409
410 ret = -EINVAL;
411 }
412
413 kfree(msg);
414
415 return ret;
416}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h
new file mode 100644
index 000000000000..557a033fb610
--- /dev/null
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h
@@ -0,0 +1,191 @@
1/*
2 * Copyright (C) 2016, VMware, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
12 * NON INFRINGEMENT. See the GNU General Public License for more
13 * details.
14 *
15 * Based on code from vmware.c and vmmouse.c.
16 * Author:
17 * Sinclair Yeh <syeh@vmware.com>
18 */
19#ifndef _VMWGFX_MSG_H
20#define _VMWGFX_MSG_H
21
22
23/**
24 * Hypervisor-specific bi-directional communication channel. Should never
25 * execute on bare metal hardware. The caller must make sure to check for
26 * supported hypervisor before using these macros.
27 *
28 * The last two parameters are both input and output and must be initialized.
29 *
30 * @cmd: [IN] Message Cmd
31 * @in_ebx: [IN] Message Len, through EBX
32 * @in_si: [IN] Input argument through SI, set to 0 if not used
33 * @in_di: [IN] Input argument through DI, set ot 0 if not used
34 * @port_num: [IN] port number + [channel id]
35 * @magic: [IN] hypervisor magic value
36 * @eax: [OUT] value of EAX register
37 * @ebx: [OUT] e.g. status from an HB message status command
38 * @ecx: [OUT] e.g. status from a non-HB message status command
39 * @edx: [OUT] e.g. channel id
40 * @si: [OUT]
41 * @di: [OUT]
42 */
43#define VMW_PORT(cmd, in_ebx, in_si, in_di, \
44 port_num, magic, \
45 eax, ebx, ecx, edx, si, di) \
46({ \
47 asm volatile ("inl %%dx, %%eax;" : \
48 "=a"(eax), \
49 "=b"(ebx), \
50 "=c"(ecx), \
51 "=d"(edx), \
52 "=S"(si), \
53 "=D"(di) : \
54 "a"(magic), \
55 "b"(in_ebx), \
56 "c"(cmd), \
57 "d"(port_num), \
58 "S"(in_si), \
59 "D"(in_di) : \
60 "memory"); \
61})
62
63
64/**
65 * Hypervisor-specific bi-directional communication channel. Should never
66 * execute on bare metal hardware. The caller must make sure to check for
67 * supported hypervisor before using these macros.
68 *
69 * The last 3 parameters are both input and output and must be initialized.
70 *
71 * @cmd: [IN] Message Cmd
72 * @in_ecx: [IN] Message Len, through ECX
73 * @in_si: [IN] Input argument through SI, set to 0 if not used
74 * @in_di: [IN] Input argument through DI, set to 0 if not used
75 * @port_num: [IN] port number + [channel id]
76 * @magic: [IN] hypervisor magic value
77 * @bp: [IN]
78 * @eax: [OUT] value of EAX register
79 * @ebx: [OUT] e.g. status from an HB message status command
80 * @ecx: [OUT] e.g. status from a non-HB message status command
81 * @edx: [OUT] e.g. channel id
82 * @si: [OUT]
83 * @di: [OUT]
84 */
85#ifdef __x86_64__
86
87#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \
88 port_num, magic, bp, \
89 eax, ebx, ecx, edx, si, di) \
90({ \
91 asm volatile ("push %%rbp;" \
92 "mov %12, %%rbp;" \
93 "rep outsb;" \
94 "pop %%rbp;" : \
95 "=a"(eax), \
96 "=b"(ebx), \
97 "=c"(ecx), \
98 "=d"(edx), \
99 "=S"(si), \
100 "=D"(di) : \
101 "a"(magic), \
102 "b"(cmd), \
103 "c"(in_ecx), \
104 "d"(port_num), \
105 "S"(in_si), \
106 "D"(in_di), \
107 "r"(bp) : \
108 "memory", "cc"); \
109})
110
111
112#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \
113 port_num, magic, bp, \
114 eax, ebx, ecx, edx, si, di) \
115({ \
116 asm volatile ("push %%rbp;" \
117 "mov %12, %%rbp;" \
118 "rep insb;" \
119 "pop %%rbp" : \
120 "=a"(eax), \
121 "=b"(ebx), \
122 "=c"(ecx), \
123 "=d"(edx), \
124 "=S"(si), \
125 "=D"(di) : \
126 "a"(magic), \
127 "b"(cmd), \
128 "c"(in_ecx), \
129 "d"(port_num), \
130 "S"(in_si), \
131 "D"(in_di), \
132 "r"(bp) : \
133 "memory", "cc"); \
134})
135
136#else
137
138/* In the 32-bit version of this macro, we use "m" because there is no
139 * more register left for bp
140 */
141#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \
142 port_num, magic, bp, \
143 eax, ebx, ecx, edx, si, di) \
144({ \
145 asm volatile ("push %%ebp;" \
146 "mov %12, %%ebp;" \
147 "rep outsb;" \
148 "pop %%ebp;" : \
149 "=a"(eax), \
150 "=b"(ebx), \
151 "=c"(ecx), \
152 "=d"(edx), \
153 "=S"(si), \
154 "=D"(di) : \
155 "a"(magic), \
156 "b"(cmd), \
157 "c"(in_ecx), \
158 "d"(port_num), \
159 "S"(in_si), \
160 "D"(in_di), \
161 "m"(bp) : \
162 "memory", "cc"); \
163})
164
165
166#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \
167 port_num, magic, bp, \
168 eax, ebx, ecx, edx, si, di) \
169({ \
170 asm volatile ("push %%ebp;" \
171 "mov %12, %%ebp;" \
172 "rep insb;" \
173 "pop %%ebp" : \
174 "=a"(eax), \
175 "=b"(ebx), \
176 "=c"(ecx), \
177 "=d"(edx), \
178 "=S"(si), \
179 "=D"(di) : \
180 "a"(magic), \
181 "b"(cmd), \
182 "c"(in_ecx), \
183 "d"(port_num), \
184 "S"(in_si), \
185 "D"(in_di), \
186 "m"(bp) : \
187 "memory", "cc"); \
188})
189#endif /* #if __x86_64__ */
190
191#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 0ea22fd112c9..b74eae2b8594 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -285,14 +285,17 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
285 } 285 }
286 286
287 /* Only one active implicit frame-buffer at a time. */ 287 /* Only one active implicit frame-buffer at a time. */
288 mutex_lock(&dev_priv->global_kms_state_mutex);
288 if (sou->base.is_implicit && 289 if (sou->base.is_implicit &&
289 dev_priv->implicit_fb && vfb && 290 dev_priv->implicit_fb && vfb &&
290 !(dev_priv->num_implicit == 1 && 291 !(dev_priv->num_implicit == 1 &&
291 sou->base.active_implicit) && 292 sou->base.active_implicit) &&
292 dev_priv->implicit_fb != vfb) { 293 dev_priv->implicit_fb != vfb) {
294 mutex_unlock(&dev_priv->global_kms_state_mutex);
293 DRM_ERROR("Multiple implicit framebuffers not supported.\n"); 295 DRM_ERROR("Multiple implicit framebuffers not supported.\n");
294 return -EINVAL; 296 return -EINVAL;
295 } 297 }
298 mutex_unlock(&dev_priv->global_kms_state_mutex);
296 299
297 /* since they always map one to one these are safe */ 300 /* since they always map one to one these are safe */
298 connector = &sou->base.connector; 301 connector = &sou->base.connector;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index b949102ad864..9ca818fb034c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -553,12 +553,15 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set)
553 } 553 }
554 554
555 /* Only one active implicit frame-buffer at a time. */ 555 /* Only one active implicit frame-buffer at a time. */
556 mutex_lock(&dev_priv->global_kms_state_mutex);
556 if (!turning_off && stdu->base.is_implicit && dev_priv->implicit_fb && 557 if (!turning_off && stdu->base.is_implicit && dev_priv->implicit_fb &&
557 !(dev_priv->num_implicit == 1 && stdu->base.active_implicit) 558 !(dev_priv->num_implicit == 1 && stdu->base.active_implicit)
558 && dev_priv->implicit_fb != vfb) { 559 && dev_priv->implicit_fb != vfb) {
560 mutex_unlock(&dev_priv->global_kms_state_mutex);
559 DRM_ERROR("Multiple implicit framebuffers not supported.\n"); 561 DRM_ERROR("Multiple implicit framebuffers not supported.\n");
560 return -EINVAL; 562 return -EINVAL;
561 } 563 }
564 mutex_unlock(&dev_priv->global_kms_state_mutex);
562 565
563 /* Since they always map one to one these are safe */ 566 /* Since they always map one to one these are safe */
564 connector = &stdu->base.connector; 567 connector = &stdu->base.connector;