Skip to content

Commit e6803ce

Browse files
thomashvmwgregkh
authored andcommitted
drm/vmwgfx: Use the backdoor port if the HB port is not available
commit cc0ba0d upstream. The HB port may not be available for various reasons. Either it has been disabled by a config option or by the hypervisor for other reasons. In that case, make sure we have a backup plan and use the backdoor port instead with a performance penalty. Cc: stable@vger.kernel.org Fixes: 89da76f ("drm/vmwgfx: Add VMWare host messaging capability") Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7499528 commit e6803ce

1 file changed

Lines changed: 117 additions & 29 deletions

File tree

drivers/gpu/drm/vmwgfx/vmwgfx_msg.c

Lines changed: 117 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,114 @@ static int vmw_close_channel(struct rpc_channel *channel)
136136
return 0;
137137
}
138138

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+
}
139247

140248

141249
/**
@@ -148,11 +256,10 @@ static int vmw_close_channel(struct rpc_channel *channel)
148256
*/
149257
static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
150258
{
151-
unsigned long eax, ebx, ecx, edx, si, di, bp;
259+
unsigned long eax, ebx, ecx, edx, si, di;
152260
size_t msg_len = strlen(msg);
153261
int retries = 0;
154262

155-
156263
while (retries < RETRIES) {
157264
retries++;
158265

@@ -166,23 +273,14 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
166273
VMW_HYPERVISOR_MAGIC,
167274
eax, ebx, ecx, edx, si, di);
168275

169-
if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
170-
(HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
171-
/* Expected success + high-bandwidth. Give up. */
276+
if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
277+
/* Expected success. Give up. */
172278
return -EINVAL;
173279
}
174280

175281
/* Send msg */
176-
si = (uintptr_t) msg;
177-
di = channel->cookie_low;
178-
bp = channel->cookie_high;
179-
180-
VMW_PORT_HB_OUT(
181-
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
182-
msg_len, si, di,
183-
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
184-
VMW_HYPERVISOR_MAGIC, bp,
185-
eax, ebx, ecx, edx, si, di);
282+
ebx = vmw_port_hb_out(channel, msg,
283+
!!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
186284

187285
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) {
188286
return 0;
@@ -211,7 +309,7 @@ STACK_FRAME_NON_STANDARD(vmw_send_msg);
211309
static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
212310
size_t *msg_len)
213311
{
214-
unsigned long eax, ebx, ecx, edx, si, di, bp;
312+
unsigned long eax, ebx, ecx, edx, si, di;
215313
char *reply;
216314
size_t reply_len;
217315
int retries = 0;
@@ -233,8 +331,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
233331
VMW_HYPERVISOR_MAGIC,
234332
eax, ebx, ecx, edx, si, di);
235333

236-
if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
237-
(HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
334+
if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
238335
DRM_ERROR("Failed to get reply size for host message.\n");
239336
return -EINVAL;
240337
}
@@ -252,17 +349,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
252349

253350

254351
/* Receive buffer */
255-
si = channel->cookie_high;
256-
di = (uintptr_t) reply;
257-
bp = channel->cookie_low;
258-
259-
VMW_PORT_HB_IN(
260-
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
261-
reply_len, si, di,
262-
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
263-
VMW_HYPERVISOR_MAGIC, bp,
264-
eax, ebx, ecx, edx, si, di);
265-
352+
ebx = vmw_port_hb_in(channel, reply, reply_len,
353+
!!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
266354
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
267355
kfree(reply);
268356

0 commit comments

Comments
 (0)