|
|
@@ -136,6 +136,114 @@ static int vmw_close_channel(struct rpc_channel *channel)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * vmw_port_hb_out - Send the message payload either through the
|
|
|
+ * high-bandwidth port if available, or through the backdoor otherwise.
|
|
|
+ * @channel: The rpc channel.
|
|
|
+ * @msg: NULL-terminated message.
|
|
|
+ * @hb: Whether the high-bandwidth port is available.
|
|
|
+ *
|
|
|
+ * Return: The port status.
|
|
|
+ */
|
|
|
+static unsigned long vmw_port_hb_out(struct rpc_channel *channel,
|
|
|
+ const char *msg, bool hb)
|
|
|
+{
|
|
|
+ unsigned long si, di, eax, ebx, ecx, edx;
|
|
|
+ unsigned long msg_len = strlen(msg);
|
|
|
+
|
|
|
+ if (hb) {
|
|
|
+ unsigned long bp = channel->cookie_high;
|
|
|
+
|
|
|
+ si = (uintptr_t) msg;
|
|
|
+ di = channel->cookie_low;
|
|
|
+
|
|
|
+ VMW_PORT_HB_OUT(
|
|
|
+ (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
|
|
|
+ msg_len, si, di,
|
|
|
+ VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
|
|
|
+ VMW_HYPERVISOR_MAGIC, bp,
|
|
|
+ eax, ebx, ecx, edx, si, di);
|
|
|
+
|
|
|
+ return ebx;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* HB port not available. Send the message 4 bytes at a time. */
|
|
|
+ ecx = MESSAGE_STATUS_SUCCESS << 16;
|
|
|
+ while (msg_len && (HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS)) {
|
|
|
+ unsigned int bytes = min_t(size_t, msg_len, 4);
|
|
|
+ unsigned long word = 0;
|
|
|
+
|
|
|
+ memcpy(&word, msg, bytes);
|
|
|
+ msg_len -= bytes;
|
|
|
+ msg += bytes;
|
|
|
+ si = channel->cookie_high;
|
|
|
+ di = channel->cookie_low;
|
|
|
+
|
|
|
+ VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16),
|
|
|
+ word, si, di,
|
|
|
+ VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
|
|
|
+ VMW_HYPERVISOR_MAGIC,
|
|
|
+ eax, ebx, ecx, edx, si, di);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ecx;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * vmw_port_hb_in - Receive the message payload either through the
|
|
|
+ * high-bandwidth port if available, or through the backdoor otherwise.
|
|
|
+ * @channel: The rpc channel.
|
|
|
+ * @reply: Pointer to buffer holding reply.
|
|
|
+ * @reply_len: Length of the reply.
|
|
|
+ * @hb: Whether the high-bandwidth port is available.
|
|
|
+ *
|
|
|
+ * Return: The port status.
|
|
|
+ */
|
|
|
+static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply,
|
|
|
+ unsigned long reply_len, bool hb)
|
|
|
+{
|
|
|
+ unsigned long si, di, eax, ebx, ecx, edx;
|
|
|
+
|
|
|
+ if (hb) {
|
|
|
+ unsigned long bp = channel->cookie_low;
|
|
|
+
|
|
|
+ si = channel->cookie_high;
|
|
|
+ di = (uintptr_t) reply;
|
|
|
+
|
|
|
+ VMW_PORT_HB_IN(
|
|
|
+ (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
|
|
|
+ reply_len, si, di,
|
|
|
+ VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
|
|
|
+ VMW_HYPERVISOR_MAGIC, bp,
|
|
|
+ eax, ebx, ecx, edx, si, di);
|
|
|
+
|
|
|
+ return ebx;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* HB port not available. Retrieve the message 4 bytes at a time. */
|
|
|
+ ecx = MESSAGE_STATUS_SUCCESS << 16;
|
|
|
+ while (reply_len) {
|
|
|
+ unsigned int bytes = min_t(unsigned long, reply_len, 4);
|
|
|
+
|
|
|
+ si = channel->cookie_high;
|
|
|
+ di = channel->cookie_low;
|
|
|
+
|
|
|
+ VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16),
|
|
|
+ MESSAGE_STATUS_SUCCESS, si, di,
|
|
|
+ VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
|
|
|
+ VMW_HYPERVISOR_MAGIC,
|
|
|
+ eax, ebx, ecx, edx, si, di);
|
|
|
+
|
|
|
+ if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ memcpy(reply, &ebx, bytes);
|
|
|
+ reply_len -= bytes;
|
|
|
+ reply += bytes;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ecx;
|
|
|
+}
|
|
|
|
|
|
|
|
|
/**
|
|
|
@@ -148,11 +256,10 @@ static int vmw_close_channel(struct rpc_channel *channel)
|
|
|
*/
|
|
|
static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
|
|
|
{
|
|
|
- unsigned long eax, ebx, ecx, edx, si, di, bp;
|
|
|
+ unsigned long eax, ebx, ecx, edx, si, di;
|
|
|
size_t msg_len = strlen(msg);
|
|
|
int retries = 0;
|
|
|
|
|
|
-
|
|
|
while (retries < RETRIES) {
|
|
|
retries++;
|
|
|
|
|
|
@@ -166,23 +273,14 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
|
|
|
VMW_HYPERVISOR_MAGIC,
|
|
|
eax, ebx, ecx, edx, si, di);
|
|
|
|
|
|
- if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
|
|
|
- (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
|
|
|
- /* Expected success + high-bandwidth. Give up. */
|
|
|
+ if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
|
|
|
+ /* Expected success. Give up. */
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
/* Send msg */
|
|
|
- si = (uintptr_t) msg;
|
|
|
- di = channel->cookie_low;
|
|
|
- bp = channel->cookie_high;
|
|
|
-
|
|
|
- VMW_PORT_HB_OUT(
|
|
|
- (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
|
|
|
- msg_len, si, di,
|
|
|
- VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
|
|
|
- VMW_HYPERVISOR_MAGIC, bp,
|
|
|
- eax, ebx, ecx, edx, si, di);
|
|
|
+ ebx = vmw_port_hb_out(channel, msg,
|
|
|
+ !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
|
|
|
|
|
|
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) {
|
|
|
return 0;
|
|
|
@@ -211,7 +309,7 @@ STACK_FRAME_NON_STANDARD(vmw_send_msg);
|
|
|
static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
|
|
|
size_t *msg_len)
|
|
|
{
|
|
|
- unsigned long eax, ebx, ecx, edx, si, di, bp;
|
|
|
+ unsigned long eax, ebx, ecx, edx, si, di;
|
|
|
char *reply;
|
|
|
size_t reply_len;
|
|
|
int retries = 0;
|
|
|
@@ -233,8 +331,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
|
|
|
VMW_HYPERVISOR_MAGIC,
|
|
|
eax, ebx, ecx, edx, si, di);
|
|
|
|
|
|
- if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
|
|
|
- (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
|
|
|
+ if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
|
|
|
DRM_ERROR("Failed to get reply size for host message.\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
@@ -252,17 +349,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
|
|
|
|
|
|
|
|
|
/* Receive buffer */
|
|
|
- si = channel->cookie_high;
|
|
|
- di = (uintptr_t) reply;
|
|
|
- bp = channel->cookie_low;
|
|
|
-
|
|
|
- VMW_PORT_HB_IN(
|
|
|
- (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
|
|
|
- reply_len, si, di,
|
|
|
- VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
|
|
|
- VMW_HYPERVISOR_MAGIC, bp,
|
|
|
- eax, ebx, ecx, edx, si, di);
|
|
|
-
|
|
|
+ ebx = vmw_port_hb_in(channel, reply, reply_len,
|
|
|
+ !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
|
|
|
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
|
|
|
kfree(reply);
|
|
|
|