diff options
-rw-r--r-- | drivers/misc/mei/bus.c | 103 | ||||
-rw-r--r-- | drivers/misc/mei/client.c | 105 | ||||
-rw-r--r-- | drivers/misc/mei/client.h | 7 | ||||
-rw-r--r-- | drivers/misc/mei/main.c | 83 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 6 |
5 files changed, 146 insertions, 158 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 8dbcb1516dc6..6badfa1110e9 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
@@ -226,112 +226,47 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, | |||
226 | bool blocking) | 226 | bool blocking) |
227 | { | 227 | { |
228 | struct mei_device *dev; | 228 | struct mei_device *dev; |
229 | struct mei_msg_hdr mei_hdr; | ||
230 | struct mei_cl_cb *cb; | 229 | struct mei_cl_cb *cb; |
231 | int me_cl_id, err; | 230 | int id; |
231 | int rets; | ||
232 | 232 | ||
233 | if (WARN_ON(!cl || !cl->dev)) | 233 | if (WARN_ON(!cl || !cl->dev)) |
234 | return -ENODEV; | 234 | return -ENODEV; |
235 | 235 | ||
236 | dev = cl->dev; | ||
237 | |||
236 | if (cl->state != MEI_FILE_CONNECTED) | 238 | if (cl->state != MEI_FILE_CONNECTED) |
237 | return -ENODEV; | 239 | return -ENODEV; |
238 | 240 | ||
241 | /* Check if we have an ME client device */ | ||
242 | id = mei_me_cl_by_id(dev, cl->me_client_id); | ||
243 | if (id < 0) | ||
244 | return -ENODEV; | ||
245 | |||
246 | if (length > dev->me_clients[id].props.max_msg_length) | ||
247 | return -EINVAL; | ||
248 | |||
239 | cb = mei_io_cb_init(cl, NULL); | 249 | cb = mei_io_cb_init(cl, NULL); |
240 | if (!cb) | 250 | if (!cb) |
241 | return -ENOMEM; | 251 | return -ENOMEM; |
242 | 252 | ||
243 | err = mei_io_cb_alloc_req_buf(cb, length); | 253 | rets = mei_io_cb_alloc_req_buf(cb, length); |
244 | if (err < 0) { | 254 | if (rets < 0) { |
245 | mei_io_cb_free(cb); | 255 | mei_io_cb_free(cb); |
246 | return err; | 256 | return rets; |
247 | } | 257 | } |
248 | 258 | ||
249 | memcpy(cb->request_buffer.data, buf, length); | 259 | memcpy(cb->request_buffer.data, buf, length); |
250 | cb->fop_type = MEI_FOP_WRITE; | ||
251 | |||
252 | dev = cl->dev; | ||
253 | 260 | ||
254 | mutex_lock(&dev->device_lock); | 261 | mutex_lock(&dev->device_lock); |
255 | 262 | ||
256 | /* Check if we have an ME client device */ | 263 | rets = mei_cl_write(cl, cb, blocking); |
257 | me_cl_id = mei_me_cl_by_id(dev, cl->me_client_id); | ||
258 | if (me_cl_id == dev->me_clients_num) { | ||
259 | err = -ENODEV; | ||
260 | goto out_err; | ||
261 | } | ||
262 | |||
263 | if (length > dev->me_clients[me_cl_id].props.max_msg_length) { | ||
264 | err = -EINVAL; | ||
265 | goto out_err; | ||
266 | } | ||
267 | |||
268 | err = mei_cl_flow_ctrl_creds(cl); | ||
269 | if (err < 0) | ||
270 | goto out_err; | ||
271 | |||
272 | /* Host buffer is not ready, we queue the request */ | ||
273 | if (err == 0 || !dev->hbuf_is_ready) { | ||
274 | cb->buf_idx = 0; | ||
275 | mei_hdr.msg_complete = 0; | ||
276 | cl->writing_state = MEI_WRITING; | ||
277 | |||
278 | goto out; | ||
279 | } | ||
280 | |||
281 | dev->hbuf_is_ready = false; | ||
282 | |||
283 | /* Check for a maximum length */ | ||
284 | if (length > mei_hbuf_max_len(dev)) { | ||
285 | mei_hdr.length = mei_hbuf_max_len(dev); | ||
286 | mei_hdr.msg_complete = 0; | ||
287 | } else { | ||
288 | mei_hdr.length = length; | ||
289 | mei_hdr.msg_complete = 1; | ||
290 | } | ||
291 | |||
292 | mei_hdr.host_addr = cl->host_client_id; | ||
293 | mei_hdr.me_addr = cl->me_client_id; | ||
294 | mei_hdr.reserved = 0; | ||
295 | |||
296 | if (mei_write_message(dev, &mei_hdr, buf)) { | ||
297 | err = -EIO; | ||
298 | goto out_err; | ||
299 | } | ||
300 | |||
301 | cl->writing_state = MEI_WRITING; | ||
302 | cb->buf_idx = mei_hdr.length; | ||
303 | |||
304 | out: | ||
305 | if (mei_hdr.msg_complete) { | ||
306 | if (mei_cl_flow_ctrl_reduce(cl)) { | ||
307 | err = -ENODEV; | ||
308 | goto out_err; | ||
309 | } | ||
310 | list_add_tail(&cb->list, &dev->write_waiting_list.list); | ||
311 | } else { | ||
312 | list_add_tail(&cb->list, &dev->write_list.list); | ||
313 | } | ||
314 | 264 | ||
315 | mutex_unlock(&dev->device_lock); | 265 | mutex_unlock(&dev->device_lock); |
266 | if (rets < 0) | ||
267 | mei_io_cb_free(cb); | ||
316 | 268 | ||
317 | if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { | 269 | return rets; |
318 | if (wait_event_interruptible(cl->tx_wait, | ||
319 | cl->writing_state == MEI_WRITE_COMPLETE)) { | ||
320 | if (signal_pending(current)) | ||
321 | err = -EINTR; | ||
322 | err = -ERESTARTSYS; | ||
323 | mutex_lock(&dev->device_lock); | ||
324 | goto out_err; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | return mei_hdr.length; | ||
329 | |||
330 | out_err: | ||
331 | mutex_unlock(&dev->device_lock); | ||
332 | mei_io_cb_free(cb); | ||
333 | |||
334 | return err; | ||
335 | } | 270 | } |
336 | 271 | ||
337 | int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | 272 | int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) |
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e14397b09187..ecadd0053ba9 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -678,6 +678,111 @@ err: | |||
678 | } | 678 | } |
679 | 679 | ||
680 | /** | 680 | /** |
681 | * mei_cl_write - submit a write cb to mei device | ||
682 | assumes device_lock is locked | ||
683 | * | ||
684 | * @cl: host client | ||
685 | * @cl: write callback with filled data | ||
686 | * | ||
687 | * returns numbe of bytes sent on success, <0 on failure. | ||
688 | */ | ||
689 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | ||
690 | { | ||
691 | struct mei_device *dev; | ||
692 | struct mei_msg_data *buf; | ||
693 | struct mei_msg_hdr mei_hdr; | ||
694 | int rets; | ||
695 | |||
696 | |||
697 | if (WARN_ON(!cl || !cl->dev)) | ||
698 | return -ENODEV; | ||
699 | |||
700 | if (WARN_ON(!cb)) | ||
701 | return -EINVAL; | ||
702 | |||
703 | dev = cl->dev; | ||
704 | |||
705 | |||
706 | buf = &cb->request_buffer; | ||
707 | |||
708 | dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size); | ||
709 | |||
710 | |||
711 | cb->fop_type = MEI_FOP_WRITE; | ||
712 | |||
713 | rets = mei_cl_flow_ctrl_creds(cl); | ||
714 | if (rets < 0) | ||
715 | goto err; | ||
716 | |||
717 | /* Host buffer is not ready, we queue the request */ | ||
718 | if (rets == 0 || !dev->hbuf_is_ready) { | ||
719 | cb->buf_idx = 0; | ||
720 | /* unseting complete will enqueue the cb for write */ | ||
721 | mei_hdr.msg_complete = 0; | ||
722 | cl->writing_state = MEI_WRITING; | ||
723 | rets = buf->size; | ||
724 | goto out; | ||
725 | } | ||
726 | |||
727 | dev->hbuf_is_ready = false; | ||
728 | |||
729 | /* Check for a maximum length */ | ||
730 | if (buf->size > mei_hbuf_max_len(dev)) { | ||
731 | mei_hdr.length = mei_hbuf_max_len(dev); | ||
732 | mei_hdr.msg_complete = 0; | ||
733 | } else { | ||
734 | mei_hdr.length = buf->size; | ||
735 | mei_hdr.msg_complete = 1; | ||
736 | } | ||
737 | |||
738 | mei_hdr.host_addr = cl->host_client_id; | ||
739 | mei_hdr.me_addr = cl->me_client_id; | ||
740 | mei_hdr.reserved = 0; | ||
741 | |||
742 | dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n", | ||
743 | MEI_HDR_PRM(&mei_hdr)); | ||
744 | |||
745 | |||
746 | if (mei_write_message(dev, &mei_hdr, buf->data)) { | ||
747 | rets = -EIO; | ||
748 | goto err; | ||
749 | } | ||
750 | |||
751 | cl->writing_state = MEI_WRITING; | ||
752 | cb->buf_idx = mei_hdr.length; | ||
753 | |||
754 | rets = buf->size; | ||
755 | out: | ||
756 | if (mei_hdr.msg_complete) { | ||
757 | if (mei_cl_flow_ctrl_reduce(cl)) { | ||
758 | rets = -ENODEV; | ||
759 | goto err; | ||
760 | } | ||
761 | list_add_tail(&cb->list, &dev->write_waiting_list.list); | ||
762 | } else { | ||
763 | list_add_tail(&cb->list, &dev->write_list.list); | ||
764 | } | ||
765 | |||
766 | |||
767 | if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { | ||
768 | |||
769 | mutex_unlock(&dev->device_lock); | ||
770 | if (wait_event_interruptible(cl->tx_wait, | ||
771 | cl->writing_state == MEI_WRITE_COMPLETE)) { | ||
772 | if (signal_pending(current)) | ||
773 | rets = -EINTR; | ||
774 | else | ||
775 | rets = -ERESTARTSYS; | ||
776 | } | ||
777 | mutex_lock(&dev->device_lock); | ||
778 | } | ||
779 | err: | ||
780 | return rets; | ||
781 | } | ||
782 | |||
783 | |||
784 | |||
785 | /** | ||
681 | * mei_cl_all_disconnect - disconnect forcefully all connected clients | 786 | * mei_cl_all_disconnect - disconnect forcefully all connected clients |
682 | * | 787 | * |
683 | * @dev - mei device | 788 | * @dev - mei device |
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 214b2397ec3e..e890c8bf89d0 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h | |||
@@ -86,17 +86,16 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl); | |||
86 | */ | 86 | */ |
87 | bool mei_cl_is_other_connecting(struct mei_cl *cl); | 87 | bool mei_cl_is_other_connecting(struct mei_cl *cl); |
88 | int mei_cl_disconnect(struct mei_cl *cl); | 88 | int mei_cl_disconnect(struct mei_cl *cl); |
89 | |||
90 | int mei_cl_read_start(struct mei_cl *cl); | ||
91 | |||
92 | int mei_cl_connect(struct mei_cl *cl, struct file *file); | 89 | int mei_cl_connect(struct mei_cl *cl, struct file *file); |
90 | int mei_cl_read_start(struct mei_cl *cl); | ||
91 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking); | ||
93 | 92 | ||
94 | void mei_host_client_init(struct work_struct *work); | 93 | void mei_host_client_init(struct work_struct *work); |
95 | 94 | ||
96 | 95 | ||
96 | |||
97 | void mei_cl_all_disconnect(struct mei_device *dev); | 97 | void mei_cl_all_disconnect(struct mei_device *dev); |
98 | void mei_cl_all_read_wakeup(struct mei_device *dev); | 98 | void mei_cl_all_read_wakeup(struct mei_device *dev); |
99 | void mei_cl_all_write_clear(struct mei_device *dev); | 99 | void mei_cl_all_write_clear(struct mei_device *dev); |
100 | 100 | ||
101 | |||
102 | #endif /* _MEI_CLIENT_H_ */ | 101 | #endif /* _MEI_CLIENT_H_ */ |
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 329fb865cfd0..cb11b36512b5 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -342,11 +342,10 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
342 | { | 342 | { |
343 | struct mei_cl *cl = file->private_data; | 343 | struct mei_cl *cl = file->private_data; |
344 | struct mei_cl_cb *write_cb = NULL; | 344 | struct mei_cl_cb *write_cb = NULL; |
345 | struct mei_msg_hdr mei_hdr; | ||
346 | struct mei_device *dev; | 345 | struct mei_device *dev; |
347 | unsigned long timeout = 0; | 346 | unsigned long timeout = 0; |
348 | int rets; | 347 | int rets; |
349 | int i; | 348 | int id; |
350 | 349 | ||
351 | if (WARN_ON(!cl || !cl->dev)) | 350 | if (WARN_ON(!cl || !cl->dev)) |
352 | return -ENODEV; | 351 | return -ENODEV; |
@@ -357,24 +356,24 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
357 | 356 | ||
358 | if (dev->dev_state != MEI_DEV_ENABLED) { | 357 | if (dev->dev_state != MEI_DEV_ENABLED) { |
359 | rets = -ENODEV; | 358 | rets = -ENODEV; |
360 | goto err; | 359 | goto out; |
361 | } | 360 | } |
362 | 361 | ||
363 | i = mei_me_cl_by_id(dev, cl->me_client_id); | 362 | id = mei_me_cl_by_id(dev, cl->me_client_id); |
364 | if (i < 0) { | 363 | if (id < 0) { |
365 | rets = -ENODEV; | 364 | rets = -ENODEV; |
366 | goto err; | 365 | goto out; |
367 | } | 366 | } |
368 | if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { | 367 | if (length > dev->me_clients[id].props.max_msg_length || length <= 0) { |
369 | rets = -EMSGSIZE; | 368 | rets = -EMSGSIZE; |
370 | goto err; | 369 | goto out; |
371 | } | 370 | } |
372 | 371 | ||
373 | if (cl->state != MEI_FILE_CONNECTED) { | 372 | if (cl->state != MEI_FILE_CONNECTED) { |
374 | rets = -ENODEV; | ||
375 | dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", | 373 | dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", |
376 | cl->host_client_id, cl->me_client_id); | 374 | cl->host_client_id, cl->me_client_id); |
377 | goto err; | 375 | rets = -ENODEV; |
376 | goto out; | ||
378 | } | 377 | } |
379 | if (cl == &dev->iamthif_cl) { | 378 | if (cl == &dev->iamthif_cl) { |
380 | write_cb = mei_amthif_find_read_list_entry(dev, file); | 379 | write_cb = mei_amthif_find_read_list_entry(dev, file); |
@@ -412,17 +411,15 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
412 | if (!write_cb) { | 411 | if (!write_cb) { |
413 | dev_err(&dev->pdev->dev, "write cb allocation failed\n"); | 412 | dev_err(&dev->pdev->dev, "write cb allocation failed\n"); |
414 | rets = -ENOMEM; | 413 | rets = -ENOMEM; |
415 | goto err; | 414 | goto out; |
416 | } | 415 | } |
417 | rets = mei_io_cb_alloc_req_buf(write_cb, length); | 416 | rets = mei_io_cb_alloc_req_buf(write_cb, length); |
418 | if (rets) | 417 | if (rets) |
419 | goto err; | 418 | goto out; |
420 | |||
421 | dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length); | ||
422 | 419 | ||
423 | rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); | 420 | rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); |
424 | if (rets) | 421 | if (rets) |
425 | goto err; | 422 | goto out; |
426 | 423 | ||
427 | cl->sm_state = 0; | 424 | cl->sm_state = 0; |
428 | if (length == 4 && | 425 | if (length == 4 && |
@@ -440,65 +437,17 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
440 | if (rets) { | 437 | if (rets) { |
441 | dev_err(&dev->pdev->dev, | 438 | dev_err(&dev->pdev->dev, |
442 | "amthif write failed with status = %d\n", rets); | 439 | "amthif write failed with status = %d\n", rets); |
443 | goto err; | 440 | goto out; |
444 | } | 441 | } |
445 | mutex_unlock(&dev->device_lock); | 442 | mutex_unlock(&dev->device_lock); |
446 | return length; | 443 | return length; |
447 | } | 444 | } |
448 | 445 | ||
449 | write_cb->fop_type = MEI_FOP_WRITE; | 446 | rets = mei_cl_write(cl, write_cb, false); |
450 | |||
451 | dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", | ||
452 | cl->host_client_id, cl->me_client_id); | ||
453 | rets = mei_cl_flow_ctrl_creds(cl); | ||
454 | if (rets < 0) | ||
455 | goto err; | ||
456 | |||
457 | if (rets == 0 || !dev->hbuf_is_ready) { | ||
458 | write_cb->buf_idx = 0; | ||
459 | mei_hdr.msg_complete = 0; | ||
460 | cl->writing_state = MEI_WRITING; | ||
461 | goto out; | ||
462 | } | ||
463 | |||
464 | dev->hbuf_is_ready = false; | ||
465 | if (length > mei_hbuf_max_len(dev)) { | ||
466 | mei_hdr.length = mei_hbuf_max_len(dev); | ||
467 | mei_hdr.msg_complete = 0; | ||
468 | } else { | ||
469 | mei_hdr.length = length; | ||
470 | mei_hdr.msg_complete = 1; | ||
471 | } | ||
472 | mei_hdr.host_addr = cl->host_client_id; | ||
473 | mei_hdr.me_addr = cl->me_client_id; | ||
474 | mei_hdr.reserved = 0; | ||
475 | |||
476 | dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n", | ||
477 | MEI_HDR_PRM(&mei_hdr)); | ||
478 | if (mei_write_message(dev, &mei_hdr, write_cb->request_buffer.data)) { | ||
479 | rets = -ENODEV; | ||
480 | goto err; | ||
481 | } | ||
482 | cl->writing_state = MEI_WRITING; | ||
483 | write_cb->buf_idx = mei_hdr.length; | ||
484 | |||
485 | out: | 447 | out: |
486 | if (mei_hdr.msg_complete) { | ||
487 | if (mei_cl_flow_ctrl_reduce(cl)) { | ||
488 | rets = -ENODEV; | ||
489 | goto err; | ||
490 | } | ||
491 | list_add_tail(&write_cb->list, &dev->write_waiting_list.list); | ||
492 | } else { | ||
493 | list_add_tail(&write_cb->list, &dev->write_list.list); | ||
494 | } | ||
495 | |||
496 | mutex_unlock(&dev->device_lock); | ||
497 | return length; | ||
498 | |||
499 | err: | ||
500 | mutex_unlock(&dev->device_lock); | 448 | mutex_unlock(&dev->device_lock); |
501 | mei_io_cb_free(write_cb); | 449 | if (rets < 0) |
450 | mei_io_cb_free(write_cb); | ||
502 | return rets; | 451 | return rets; |
503 | } | 452 | } |
504 | 453 | ||
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 8806be420f6b..d786da6aa25b 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -153,7 +153,7 @@ enum mei_cb_file_ops { | |||
153 | /* | 153 | /* |
154 | * Intel MEI message data struct | 154 | * Intel MEI message data struct |
155 | */ | 155 | */ |
156 | struct mei_message_data { | 156 | struct mei_msg_data { |
157 | u32 size; | 157 | u32 size; |
158 | unsigned char *data; | 158 | unsigned char *data; |
159 | }; | 159 | }; |
@@ -184,8 +184,8 @@ struct mei_cl_cb { | |||
184 | struct list_head list; | 184 | struct list_head list; |
185 | struct mei_cl *cl; | 185 | struct mei_cl *cl; |
186 | enum mei_cb_file_ops fop_type; | 186 | enum mei_cb_file_ops fop_type; |
187 | struct mei_message_data request_buffer; | 187 | struct mei_msg_data request_buffer; |
188 | struct mei_message_data response_buffer; | 188 | struct mei_msg_data response_buffer; |
189 | unsigned long buf_idx; | 189 | unsigned long buf_idx; |
190 | unsigned long read_time; | 190 | unsigned long read_time; |
191 | struct file *file_object; | 191 | struct file *file_object; |