Merge tag 'samsung-defconfig-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / vmwgfx / vmwgfx_msg.c
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /*
3  * Copyright 2016 VMware, Inc., Palo Alto, CA., USA
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 <linux/frame.h>
32 #include <asm/hypervisor.h>
33 #include <drm/drmP.h>
34 #include "vmwgfx_drv.h"
35 #include "vmwgfx_msg.h"
36
37
38 #define MESSAGE_STATUS_SUCCESS  0x0001
39 #define MESSAGE_STATUS_DORECV   0x0002
40 #define MESSAGE_STATUS_CPT      0x0010
41 #define MESSAGE_STATUS_HB       0x0080
42
43 #define RPCI_PROTOCOL_NUM       0x49435052
44 #define GUESTMSG_FLAG_COOKIE    0x80000000
45
46 #define RETRIES                 3
47
48 #define VMW_HYPERVISOR_MAGIC    0x564D5868
49 #define VMW_HYPERVISOR_PORT     0x5658
50 #define VMW_HYPERVISOR_HB_PORT  0x5659
51
52 #define VMW_PORT_CMD_MSG        30
53 #define VMW_PORT_CMD_HB_MSG     0
54 #define VMW_PORT_CMD_OPEN_CHANNEL  (MSG_TYPE_OPEN << 16 | VMW_PORT_CMD_MSG)
55 #define VMW_PORT_CMD_CLOSE_CHANNEL (MSG_TYPE_CLOSE << 16 | VMW_PORT_CMD_MSG)
56 #define VMW_PORT_CMD_SENDSIZE   (MSG_TYPE_SENDSIZE << 16 | VMW_PORT_CMD_MSG)
57 #define VMW_PORT_CMD_RECVSIZE   (MSG_TYPE_RECVSIZE << 16 | VMW_PORT_CMD_MSG)
58 #define VMW_PORT_CMD_RECVSTATUS (MSG_TYPE_RECVSTATUS << 16 | VMW_PORT_CMD_MSG)
59
60 #define HIGH_WORD(X) ((X & 0xFFFF0000) >> 16)
61
62 static u32 vmw_msg_enabled = 1;
63
64 enum rpc_msg_type {
65         MSG_TYPE_OPEN,
66         MSG_TYPE_SENDSIZE,
67         MSG_TYPE_SENDPAYLOAD,
68         MSG_TYPE_RECVSIZE,
69         MSG_TYPE_RECVPAYLOAD,
70         MSG_TYPE_RECVSTATUS,
71         MSG_TYPE_CLOSE,
72 };
73
74 struct rpc_channel {
75         u16 channel_id;
76         u32 cookie_high;
77         u32 cookie_low;
78 };
79
80
81
82 /**
83  * vmw_open_channel
84  *
85  * @channel: RPC channel
86  * @protocol:
87  *
88  * Returns: 0 on success
89  */
90 static int vmw_open_channel(struct rpc_channel *channel, unsigned int protocol)
91 {
92         unsigned long eax, ebx, ecx, edx, si = 0, di = 0;
93
94         VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL,
95                 (protocol | GUESTMSG_FLAG_COOKIE), si, di,
96                 VMW_HYPERVISOR_PORT,
97                 VMW_HYPERVISOR_MAGIC,
98                 eax, ebx, ecx, edx, si, di);
99
100         if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
101                 return -EINVAL;
102
103         channel->channel_id  = HIGH_WORD(edx);
104         channel->cookie_high = si;
105         channel->cookie_low  = di;
106
107         return 0;
108 }
109
110
111
112 /**
113  * vmw_close_channel
114  *
115  * @channel: RPC channel
116  *
117  * Returns: 0 on success
118  */
119 static int vmw_close_channel(struct rpc_channel *channel)
120 {
121         unsigned long eax, ebx, ecx, edx, si, di;
122
123         /* Set up additional parameters */
124         si  = channel->cookie_high;
125         di  = channel->cookie_low;
126
127         VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL,
128                 0, si, di,
129                 (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
130                 VMW_HYPERVISOR_MAGIC,
131                 eax, ebx, ecx, edx, si, di);
132
133         if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
134                 return -EINVAL;
135
136         return 0;
137 }
138
139 /**
140  * vmw_port_hb_out - Send the message payload either through the
141  * high-bandwidth port if available, or through the backdoor otherwise.
142  * @channel: The rpc channel.
143  * @msg: NULL-terminated message.
144  * @hb: Whether the high-bandwidth port is available.
145  *
146  * Return: The port status.
147  */
148 static unsigned long vmw_port_hb_out(struct rpc_channel *channel,
149                                      const char *msg, bool hb)
150 {
151         unsigned long si, di, eax, ebx, ecx, edx;
152         unsigned long msg_len = strlen(msg);
153
154         if (hb) {
155                 unsigned long bp = channel->cookie_high;
156
157                 si = (uintptr_t) msg;
158                 di = channel->cookie_low;
159
160                 VMW_PORT_HB_OUT(
161                         (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
162                         msg_len, si, di,
163                         VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
164                         VMW_HYPERVISOR_MAGIC, bp,
165                         eax, ebx, ecx, edx, si, di);
166
167                 return ebx;
168         }
169
170         /* HB port not available. Send the message 4 bytes at a time. */
171         ecx = MESSAGE_STATUS_SUCCESS << 16;
172         while (msg_len && (HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS)) {
173                 unsigned int bytes = min_t(size_t, msg_len, 4);
174                 unsigned long word = 0;
175
176                 memcpy(&word, msg, bytes);
177                 msg_len -= bytes;
178                 msg += bytes;
179                 si = channel->cookie_high;
180                 di = channel->cookie_low;
181
182                 VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16),
183                          word, si, di,
184                          VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
185                          VMW_HYPERVISOR_MAGIC,
186                          eax, ebx, ecx, edx, si, di);
187         }
188
189         return ecx;
190 }
191
192 /**
193  * vmw_port_hb_in - Receive the message payload either through the
194  * high-bandwidth port if available, or through the backdoor otherwise.
195  * @channel: The rpc channel.
196  * @reply: Pointer to buffer holding reply.
197  * @reply_len: Length of the reply.
198  * @hb: Whether the high-bandwidth port is available.
199  *
200  * Return: The port status.
201  */
202 static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply,
203                                     unsigned long reply_len, bool hb)
204 {
205         unsigned long si, di, eax, ebx, ecx, edx;
206
207         if (hb) {
208                 unsigned long bp = channel->cookie_low;
209
210                 si = channel->cookie_high;
211                 di = (uintptr_t) reply;
212
213                 VMW_PORT_HB_IN(
214                         (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
215                         reply_len, si, di,
216                         VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
217                         VMW_HYPERVISOR_MAGIC, bp,
218                         eax, ebx, ecx, edx, si, di);
219
220                 return ebx;
221         }
222
223         /* HB port not available. Retrieve the message 4 bytes at a time. */
224         ecx = MESSAGE_STATUS_SUCCESS << 16;
225         while (reply_len) {
226                 unsigned int bytes = min_t(unsigned long, reply_len, 4);
227
228                 si = channel->cookie_high;
229                 di = channel->cookie_low;
230
231                 VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16),
232                          MESSAGE_STATUS_SUCCESS, si, di,
233                          VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
234                          VMW_HYPERVISOR_MAGIC,
235                          eax, ebx, ecx, edx, si, di);
236
237                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
238                         break;
239
240                 memcpy(reply, &ebx, bytes);
241                 reply_len -= bytes;
242                 reply += bytes;
243         }
244
245         return ecx;
246 }
247
248
249 /**
250  * vmw_send_msg: Sends a message to the host
251  *
252  * @channel: RPC channel
253  * @logmsg: NULL terminated string
254  *
255  * Returns: 0 on success
256  */
257 static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
258 {
259         unsigned long eax, ebx, ecx, edx, si, di;
260         size_t msg_len = strlen(msg);
261         int retries = 0;
262
263         while (retries < RETRIES) {
264                 retries++;
265
266                 /* Set up additional parameters */
267                 si  = channel->cookie_high;
268                 di  = channel->cookie_low;
269
270                 VMW_PORT(VMW_PORT_CMD_SENDSIZE,
271                         msg_len, si, di,
272                         VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
273                         VMW_HYPERVISOR_MAGIC,
274                         eax, ebx, ecx, edx, si, di);
275
276                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
277                         /* Expected success. Give up. */
278                         return -EINVAL;
279                 }
280
281                 /* Send msg */
282                 ebx = vmw_port_hb_out(channel, msg,
283                                       !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
284
285                 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) {
286                         return 0;
287                 } else if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) {
288                         /* A checkpoint occurred. Retry. */
289                         continue;
290                 } else {
291                         break;
292                 }
293         }
294
295         return -EINVAL;
296 }
297 STACK_FRAME_NON_STANDARD(vmw_send_msg);
298
299
300 /**
301  * vmw_recv_msg: Receives a message from the host
302  *
303  * Note:  It is the caller's responsibility to call kfree() on msg.
304  *
305  * @channel:  channel opened by vmw_open_channel
306  * @msg:  [OUT] message received from the host
307  * @msg_len: message length
308  */
309 static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
310                         size_t *msg_len)
311 {
312         unsigned long eax, ebx, ecx, edx, si, di;
313         char *reply;
314         size_t reply_len;
315         int retries = 0;
316
317
318         *msg_len = 0;
319         *msg = NULL;
320
321         while (retries < RETRIES) {
322                 retries++;
323
324                 /* Set up additional parameters */
325                 si  = channel->cookie_high;
326                 di  = channel->cookie_low;
327
328                 VMW_PORT(VMW_PORT_CMD_RECVSIZE,
329                         0, si, di,
330                         (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
331                         VMW_HYPERVISOR_MAGIC,
332                         eax, ebx, ecx, edx, si, di);
333
334                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
335                         DRM_ERROR("Failed to get reply size for host message.\n");
336                         return -EINVAL;
337                 }
338
339                 /* No reply available.  This is okay. */
340                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_DORECV) == 0)
341                         return 0;
342
343                 reply_len = ebx;
344                 reply     = kzalloc(reply_len + 1, GFP_KERNEL);
345                 if (!reply) {
346                         DRM_ERROR("Cannot allocate memory for host message reply.\n");
347                         return -ENOMEM;
348                 }
349
350
351                 /* Receive buffer */
352                 ebx = vmw_port_hb_in(channel, reply, reply_len,
353                                      !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
354                 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
355                         kfree(reply);
356
357                         if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) {
358                                 /* A checkpoint occurred. Retry. */
359                                 continue;
360                         }
361
362                         return -EINVAL;
363                 }
364
365                 reply[reply_len] = '\0';
366
367
368                 /* Ack buffer */
369                 si  = channel->cookie_high;
370                 di  = channel->cookie_low;
371
372                 VMW_PORT(VMW_PORT_CMD_RECVSTATUS,
373                         MESSAGE_STATUS_SUCCESS, si, di,
374                         (VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
375                         VMW_HYPERVISOR_MAGIC,
376                         eax, ebx, ecx, edx, si, di);
377
378                 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
379                         kfree(reply);
380
381                         if ((HIGH_WORD(ecx) & MESSAGE_STATUS_CPT) != 0) {
382                                 /* A checkpoint occurred. Retry. */
383                                 continue;
384                         }
385
386                         return -EINVAL;
387                 }
388
389                 break;
390         }
391
392         if (retries == RETRIES) {
393                 kfree(reply);
394                 return -EINVAL;
395         }
396
397         *msg_len = reply_len;
398         *msg     = reply;
399
400         return 0;
401 }
402 STACK_FRAME_NON_STANDARD(vmw_recv_msg);
403
404
405 /**
406  * vmw_host_get_guestinfo: Gets a GuestInfo parameter
407  *
408  * Gets the value of a  GuestInfo.* parameter.  The value returned will be in
409  * a string, and it is up to the caller to post-process.
410  *
411  * @guest_info_param:  Parameter to get, e.g. GuestInfo.svga.gl3
412  * @buffer: if NULL, *reply_len will contain reply size.
413  * @length: size of the reply_buf.  Set to size of reply upon return
414  *
415  * Returns: 0 on success
416  */
417 int vmw_host_get_guestinfo(const char *guest_info_param,
418                            char *buffer, size_t *length)
419 {
420         struct rpc_channel channel;
421         char *msg, *reply = NULL;
422         size_t reply_len = 0;
423
424         if (!vmw_msg_enabled)
425                 return -ENODEV;
426
427         if (!guest_info_param || !length)
428                 return -EINVAL;
429
430         msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param);
431         if (!msg) {
432                 DRM_ERROR("Cannot allocate memory to get guest info \"%s\".",
433                           guest_info_param);
434                 return -ENOMEM;
435         }
436
437         if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM))
438                 goto out_open;
439
440         if (vmw_send_msg(&channel, msg) ||
441             vmw_recv_msg(&channel, (void *) &reply, &reply_len))
442                 goto out_msg;
443
444         vmw_close_channel(&channel);
445         if (buffer && reply && reply_len > 0) {
446                 /* Remove reply code, which are the first 2 characters of
447                  * the reply
448                  */
449                 reply_len = max(reply_len - 2, (size_t) 0);
450                 reply_len = min(reply_len, *length);
451
452                 if (reply_len > 0)
453                         memcpy(buffer, reply + 2, reply_len);
454         }
455
456         *length = reply_len;
457
458         kfree(reply);
459         kfree(msg);
460
461         return 0;
462
463 out_msg:
464         vmw_close_channel(&channel);
465         kfree(reply);
466 out_open:
467         *length = 0;
468         kfree(msg);
469         DRM_ERROR("Failed to get guest info \"%s\".", guest_info_param);
470
471         return -EINVAL;
472 }
473
474
475
476 /**
477  * vmw_host_log: Sends a log message to the host
478  *
479  * @log: NULL terminated string
480  *
481  * Returns: 0 on success
482  */
483 int vmw_host_log(const char *log)
484 {
485         struct rpc_channel channel;
486         char *msg;
487         int ret = 0;
488
489
490         if (!vmw_msg_enabled)
491                 return -ENODEV;
492
493         if (!log)
494                 return ret;
495
496         msg = kasprintf(GFP_KERNEL, "log %s", log);
497         if (!msg) {
498                 DRM_ERROR("Cannot allocate memory for host log message.\n");
499                 return -ENOMEM;
500         }
501
502         if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM))
503                 goto out_open;
504
505         if (vmw_send_msg(&channel, msg))
506                 goto out_msg;
507
508         vmw_close_channel(&channel);
509         kfree(msg);
510
511         return 0;
512
513 out_msg:
514         vmw_close_channel(&channel);
515 out_open:
516         kfree(msg);
517         DRM_ERROR("Failed to send host log message.\n");
518
519         return -EINVAL;
520 }