aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2019-05-29 02:15:19 -0400
committerThomas Hellstrom <thellstrom@vmware.com>2019-06-11 10:59:54 -0400
commitcc0ba0d8624f210995924bb57a8b181ce8976606 (patch)
treed9f31efec66c045ee2bb70dc00b75b4784be9984
parent5ed7f4b5eca11c3c69e7c8b53e4321812bc1ee1e (diff)
drm/vmwgfx: Use the backdoor port if the HB port is not available
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: 89da76fde68d ("drm/vmwgfx: Add VMWare host messaging capability") Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com>
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_msg.c146
1 files changed, 117 insertions, 29 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
index 8b9270f31409..e4e09d47c5c0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
@@ -136,6 +136,114 @@ static int vmw_close_channel(struct rpc_channel *channel)
136 return 0; 136 return 0;
137} 137}
138 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 */
148static 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 */
202static 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}
139 247
140 248
141/** 249/**
@@ -148,11 +256,10 @@ static int vmw_close_channel(struct rpc_channel *channel)
148 */ 256 */
149static int vmw_send_msg(struct rpc_channel *channel, const char *msg) 257static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
150{ 258{
151 unsigned long eax, ebx, ecx, edx, si, di, bp; 259 unsigned long eax, ebx, ecx, edx, si, di;
152 size_t msg_len = strlen(msg); 260 size_t msg_len = strlen(msg);
153 int retries = 0; 261 int retries = 0;
154 262
155
156 while (retries < RETRIES) { 263 while (retries < RETRIES) {
157 retries++; 264 retries++;
158 265
@@ -166,23 +273,14 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
166 VMW_HYPERVISOR_MAGIC, 273 VMW_HYPERVISOR_MAGIC,
167 eax, ebx, ecx, edx, si, di); 274 eax, ebx, ecx, edx, si, di);
168 275
169 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 || 276 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
170 (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) { 277 /* Expected success. Give up. */
171 /* Expected success + high-bandwidth. Give up. */
172 return -EINVAL; 278 return -EINVAL;
173 } 279 }
174 280
175 /* Send msg */ 281 /* Send msg */
176 si = (uintptr_t) msg; 282 ebx = vmw_port_hb_out(channel, msg,
177 di = channel->cookie_low; 283 !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
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);
186 284
187 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) { 285 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) {
188 return 0; 286 return 0;
@@ -211,7 +309,7 @@ STACK_FRAME_NON_STANDARD(vmw_send_msg);
211static int vmw_recv_msg(struct rpc_channel *channel, void **msg, 309static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
212 size_t *msg_len) 310 size_t *msg_len)
213{ 311{
214 unsigned long eax, ebx, ecx, edx, si, di, bp; 312 unsigned long eax, ebx, ecx, edx, si, di;
215 char *reply; 313 char *reply;
216 size_t reply_len; 314 size_t reply_len;
217 int retries = 0; 315 int retries = 0;
@@ -233,8 +331,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
233 VMW_HYPERVISOR_MAGIC, 331 VMW_HYPERVISOR_MAGIC,
234 eax, ebx, ecx, edx, si, di); 332 eax, ebx, ecx, edx, si, di);
235 333
236 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 || 334 if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
237 (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
238 DRM_ERROR("Failed to get reply size for host message.\n"); 335 DRM_ERROR("Failed to get reply size for host message.\n");
239 return -EINVAL; 336 return -EINVAL;
240 } 337 }
@@ -252,17 +349,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
252 349
253 350
254 /* Receive buffer */ 351 /* Receive buffer */
255 si = channel->cookie_high; 352 ebx = vmw_port_hb_in(channel, reply, reply_len,
256 di = (uintptr_t) reply; 353 !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
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
266 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) { 354 if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
267 kfree(reply); 355 kfree(reply);
268 356