root/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vmw_open_channel
  2. vmw_close_channel
  3. vmw_port_hb_out
  4. vmw_port_hb_in
  5. vmw_send_msg
  6. vmw_recv_msg
  7. vmw_host_get_guestinfo
  8. vmw_host_log

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

/* [<][>][^][v][top][bottom][index][help] */