diff options
-rw-r--r-- | sound/soc/intel/haswell/sst-haswell-ipc.c | 382 |
1 files changed, 87 insertions, 295 deletions
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index 28667d8e2005..d75f09eb30b7 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "sst-haswell-ipc.h" | 36 | #include "sst-haswell-ipc.h" |
37 | #include "../common/sst-dsp.h" | 37 | #include "../common/sst-dsp.h" |
38 | #include "../common/sst-dsp-priv.h" | 38 | #include "../common/sst-dsp-priv.h" |
39 | #include "../common/sst-ipc.h" | ||
39 | 40 | ||
40 | /* Global Message - Generic */ | 41 | /* Global Message - Generic */ |
41 | #define IPC_GLB_TYPE_SHIFT 24 | 42 | #define IPC_GLB_TYPE_SHIFT 24 |
@@ -210,23 +211,6 @@ struct sst_hsw_ipc_fw_ready { | |||
210 | u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; | 211 | u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; |
211 | } __attribute__((packed)); | 212 | } __attribute__((packed)); |
212 | 213 | ||
213 | struct ipc_message { | ||
214 | struct list_head list; | ||
215 | u32 header; | ||
216 | |||
217 | /* direction wrt host CPU */ | ||
218 | char tx_data[IPC_MAX_MAILBOX_BYTES]; | ||
219 | size_t tx_size; | ||
220 | char rx_data[IPC_MAX_MAILBOX_BYTES]; | ||
221 | size_t rx_size; | ||
222 | |||
223 | wait_queue_head_t waitq; | ||
224 | bool pending; | ||
225 | bool complete; | ||
226 | bool wait; | ||
227 | int errno; | ||
228 | }; | ||
229 | |||
230 | struct sst_hsw_stream; | 214 | struct sst_hsw_stream; |
231 | struct sst_hsw; | 215 | struct sst_hsw; |
232 | 216 | ||
@@ -325,15 +309,7 @@ struct sst_hsw { | |||
325 | bool shutdown; | 309 | bool shutdown; |
326 | 310 | ||
327 | /* IPC messaging */ | 311 | /* IPC messaging */ |
328 | struct list_head tx_list; | 312 | struct sst_generic_ipc ipc; |
329 | struct list_head rx_list; | ||
330 | struct list_head empty_list; | ||
331 | wait_queue_head_t wait_txq; | ||
332 | struct task_struct *tx_thread; | ||
333 | struct kthread_worker kworker; | ||
334 | struct kthread_work kwork; | ||
335 | bool pending; | ||
336 | struct ipc_message *msg; | ||
337 | 313 | ||
338 | /* FW log stream */ | 314 | /* FW log stream */ |
339 | struct sst_hsw_log_stream log_stream; | 315 | struct sst_hsw_log_stream log_stream; |
@@ -456,159 +432,6 @@ static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw, | |||
456 | return NULL; | 432 | return NULL; |
457 | } | 433 | } |
458 | 434 | ||
459 | static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text) | ||
460 | { | ||
461 | struct sst_dsp *sst = hsw->dsp; | ||
462 | u32 isr, ipcd, imrx, ipcx; | ||
463 | |||
464 | ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX); | ||
465 | isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); | ||
466 | ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
467 | imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX); | ||
468 | |||
469 | dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n", | ||
470 | text, ipcx, isr, ipcd, imrx); | ||
471 | } | ||
472 | |||
473 | /* locks held by caller */ | ||
474 | static struct ipc_message *msg_get_empty(struct sst_hsw *hsw) | ||
475 | { | ||
476 | struct ipc_message *msg = NULL; | ||
477 | |||
478 | if (!list_empty(&hsw->empty_list)) { | ||
479 | msg = list_first_entry(&hsw->empty_list, struct ipc_message, | ||
480 | list); | ||
481 | list_del(&msg->list); | ||
482 | } | ||
483 | |||
484 | return msg; | ||
485 | } | ||
486 | |||
487 | static void ipc_tx_msgs(struct kthread_work *work) | ||
488 | { | ||
489 | struct sst_hsw *hsw = | ||
490 | container_of(work, struct sst_hsw, kwork); | ||
491 | struct ipc_message *msg; | ||
492 | unsigned long flags; | ||
493 | u32 ipcx; | ||
494 | |||
495 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
496 | |||
497 | if (list_empty(&hsw->tx_list) || hsw->pending) { | ||
498 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
499 | return; | ||
500 | } | ||
501 | |||
502 | /* if the DSP is busy, we will TX messages after IRQ. | ||
503 | * also postpone if we are in the middle of procesing completion irq*/ | ||
504 | ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); | ||
505 | if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) { | ||
506 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | msg = list_first_entry(&hsw->tx_list, struct ipc_message, list); | ||
511 | |||
512 | list_move(&msg->list, &hsw->rx_list); | ||
513 | |||
514 | /* send the message */ | ||
515 | sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size); | ||
516 | sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY); | ||
517 | |||
518 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
519 | } | ||
520 | |||
521 | /* locks held by caller */ | ||
522 | static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg) | ||
523 | { | ||
524 | msg->complete = true; | ||
525 | trace_ipc_reply("completed", msg->header); | ||
526 | |||
527 | if (!msg->wait) | ||
528 | list_add_tail(&msg->list, &hsw->empty_list); | ||
529 | else | ||
530 | wake_up(&msg->waitq); | ||
531 | } | ||
532 | |||
533 | static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg, | ||
534 | void *rx_data) | ||
535 | { | ||
536 | unsigned long flags; | ||
537 | int ret; | ||
538 | |||
539 | /* wait for DSP completion (in all cases atm inc pending) */ | ||
540 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
541 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
542 | |||
543 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
544 | if (ret == 0) { | ||
545 | ipc_shim_dbg(hsw, "message timeout"); | ||
546 | |||
547 | trace_ipc_error("error message timeout for", msg->header); | ||
548 | list_del(&msg->list); | ||
549 | ret = -ETIMEDOUT; | ||
550 | } else { | ||
551 | |||
552 | /* copy the data returned from DSP */ | ||
553 | if (msg->rx_size) | ||
554 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
555 | ret = msg->errno; | ||
556 | } | ||
557 | |||
558 | list_add_tail(&msg->list, &hsw->empty_list); | ||
559 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
560 | return ret; | ||
561 | } | ||
562 | |||
563 | static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data, | ||
564 | size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait) | ||
565 | { | ||
566 | struct ipc_message *msg; | ||
567 | unsigned long flags; | ||
568 | |||
569 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
570 | |||
571 | msg = msg_get_empty(hsw); | ||
572 | if (msg == NULL) { | ||
573 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
574 | return -EBUSY; | ||
575 | } | ||
576 | |||
577 | if (tx_bytes) | ||
578 | memcpy(msg->tx_data, tx_data, tx_bytes); | ||
579 | |||
580 | msg->header = header; | ||
581 | msg->tx_size = tx_bytes; | ||
582 | msg->rx_size = rx_bytes; | ||
583 | msg->wait = wait; | ||
584 | msg->errno = 0; | ||
585 | msg->pending = false; | ||
586 | msg->complete = false; | ||
587 | |||
588 | list_add_tail(&msg->list, &hsw->tx_list); | ||
589 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
590 | |||
591 | queue_kthread_work(&hsw->kworker, &hsw->kwork); | ||
592 | |||
593 | if (wait) | ||
594 | return tx_wait_done(hsw, msg, rx_data); | ||
595 | else | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header, | ||
600 | void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) | ||
601 | { | ||
602 | return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data, | ||
603 | rx_bytes, 1); | ||
604 | } | ||
605 | |||
606 | static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header, | ||
607 | void *tx_data, size_t tx_bytes) | ||
608 | { | ||
609 | return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0); | ||
610 | } | ||
611 | |||
612 | static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | 435 | static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) |
613 | { | 436 | { |
614 | struct sst_hsw_ipc_fw_ready fw_ready; | 437 | struct sst_hsw_ipc_fw_ready fw_ready; |
@@ -696,27 +519,6 @@ static void hsw_notification_work(struct work_struct *work) | |||
696 | sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0); | 519 | sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0); |
697 | } | 520 | } |
698 | 521 | ||
699 | static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header) | ||
700 | { | ||
701 | struct ipc_message *msg; | ||
702 | |||
703 | /* clear reply bits & status bits */ | ||
704 | header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); | ||
705 | |||
706 | if (list_empty(&hsw->rx_list)) { | ||
707 | dev_err(hsw->dev, "error: rx list empty but received 0x%x\n", | ||
708 | header); | ||
709 | return NULL; | ||
710 | } | ||
711 | |||
712 | list_for_each_entry(msg, &hsw->rx_list, list) { | ||
713 | if (msg->header == header) | ||
714 | return msg; | ||
715 | } | ||
716 | |||
717 | return NULL; | ||
718 | } | ||
719 | |||
720 | static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) | 522 | static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) |
721 | { | 523 | { |
722 | struct sst_hsw_stream *stream; | 524 | struct sst_hsw_stream *stream; |
@@ -755,7 +557,7 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
755 | 557 | ||
756 | trace_ipc_reply("processing -->", header); | 558 | trace_ipc_reply("processing -->", header); |
757 | 559 | ||
758 | msg = reply_find_msg(hsw, header); | 560 | msg = sst_ipc_reply_find_msg(&hsw->ipc, header); |
759 | if (msg == NULL) { | 561 | if (msg == NULL) { |
760 | trace_ipc_error("error: can't find message header", header); | 562 | trace_ipc_error("error: can't find message header", header); |
761 | return -EIO; | 563 | return -EIO; |
@@ -766,14 +568,14 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
766 | case IPC_GLB_REPLY_PENDING: | 568 | case IPC_GLB_REPLY_PENDING: |
767 | trace_ipc_pending_reply("received", header); | 569 | trace_ipc_pending_reply("received", header); |
768 | msg->pending = true; | 570 | msg->pending = true; |
769 | hsw->pending = true; | 571 | hsw->ipc.pending = true; |
770 | return 1; | 572 | return 1; |
771 | case IPC_GLB_REPLY_SUCCESS: | 573 | case IPC_GLB_REPLY_SUCCESS: |
772 | if (msg->pending) { | 574 | if (msg->pending) { |
773 | trace_ipc_pending_reply("completed", header); | 575 | trace_ipc_pending_reply("completed", header); |
774 | sst_dsp_inbox_read(hsw->dsp, msg->rx_data, | 576 | sst_dsp_inbox_read(hsw->dsp, msg->rx_data, |
775 | msg->rx_size); | 577 | msg->rx_size); |
776 | hsw->pending = false; | 578 | hsw->ipc.pending = false; |
777 | } else { | 579 | } else { |
778 | /* copy data from the DSP */ | 580 | /* copy data from the DSP */ |
779 | sst_dsp_outbox_read(hsw->dsp, msg->rx_data, | 581 | sst_dsp_outbox_read(hsw->dsp, msg->rx_data, |
@@ -829,7 +631,7 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
829 | 631 | ||
830 | /* wake up and return the error if we have waiters on this message ? */ | 632 | /* wake up and return the error if we have waiters on this message ? */ |
831 | list_del(&msg->list); | 633 | list_del(&msg->list); |
832 | tx_msg_reply_complete(hsw, msg); | 634 | sst_ipc_tx_msg_reply_complete(&hsw->ipc, msg); |
833 | 635 | ||
834 | return 1; | 636 | return 1; |
835 | } | 637 | } |
@@ -970,6 +772,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) | |||
970 | { | 772 | { |
971 | struct sst_dsp *sst = (struct sst_dsp *) context; | 773 | struct sst_dsp *sst = (struct sst_dsp *) context; |
972 | struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); | 774 | struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); |
775 | struct sst_generic_ipc *ipc = &hsw->ipc; | ||
973 | u32 ipcx, ipcd; | 776 | u32 ipcx, ipcd; |
974 | int handled; | 777 | int handled; |
975 | unsigned long flags; | 778 | unsigned long flags; |
@@ -1016,7 +819,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) | |||
1016 | spin_unlock_irqrestore(&sst->spinlock, flags); | 819 | spin_unlock_irqrestore(&sst->spinlock, flags); |
1017 | 820 | ||
1018 | /* continue to send any remaining messages... */ | 821 | /* continue to send any remaining messages... */ |
1019 | queue_kthread_work(&hsw->kworker, &hsw->kwork); | 822 | queue_kthread_work(&ipc->kworker, &ipc->kwork); |
1020 | 823 | ||
1021 | return IRQ_HANDLED; | 824 | return IRQ_HANDLED; |
1022 | } | 825 | } |
@@ -1026,7 +829,8 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, | |||
1026 | { | 829 | { |
1027 | int ret; | 830 | int ret; |
1028 | 831 | ||
1029 | ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), | 832 | ret = sst_ipc_tx_message_wait(&hsw->ipc, |
833 | IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), | ||
1030 | NULL, 0, version, sizeof(*version)); | 834 | NULL, 0, version, sizeof(*version)); |
1031 | if (ret < 0) | 835 | if (ret < 0) |
1032 | dev_err(hsw->dev, "error: get version failed\n"); | 836 | dev_err(hsw->dev, "error: get version failed\n"); |
@@ -1090,7 +894,8 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | |||
1090 | req->channel = channel; | 894 | req->channel = channel; |
1091 | } | 895 | } |
1092 | 896 | ||
1093 | ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); | 897 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, req, |
898 | sizeof(*req), NULL, 0); | ||
1094 | if (ret < 0) { | 899 | if (ret < 0) { |
1095 | dev_err(hsw->dev, "error: set stream volume failed\n"); | 900 | dev_err(hsw->dev, "error: set stream volume failed\n"); |
1096 | return ret; | 901 | return ret; |
@@ -1155,7 +960,8 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | |||
1155 | req.curve_type = hsw->curve_type; | 960 | req.curve_type = hsw->curve_type; |
1156 | req.target_volume = volume; | 961 | req.target_volume = volume; |
1157 | 962 | ||
1158 | ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0); | 963 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &req, |
964 | sizeof(req), NULL, 0); | ||
1159 | if (ret < 0) { | 965 | if (ret < 0) { |
1160 | dev_err(hsw->dev, "error: set mixer volume failed\n"); | 966 | dev_err(hsw->dev, "error: set mixer volume failed\n"); |
1161 | return ret; | 967 | return ret; |
@@ -1213,7 +1019,7 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1213 | stream->free_req.stream_id = stream->reply.stream_hw_id; | 1019 | stream->free_req.stream_id = stream->reply.stream_hw_id; |
1214 | header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); | 1020 | header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); |
1215 | 1021 | ||
1216 | ret = ipc_tx_message_wait(hsw, header, &stream->free_req, | 1022 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &stream->free_req, |
1217 | sizeof(stream->free_req), NULL, 0); | 1023 | sizeof(stream->free_req), NULL, 0); |
1218 | if (ret < 0) { | 1024 | if (ret < 0) { |
1219 | dev_err(hsw->dev, "error: free stream %d failed\n", | 1025 | dev_err(hsw->dev, "error: free stream %d failed\n", |
@@ -1405,8 +1211,8 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1405 | 1211 | ||
1406 | header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); | 1212 | header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); |
1407 | 1213 | ||
1408 | ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req), | 1214 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, str_req, |
1409 | reply, sizeof(*reply)); | 1215 | sizeof(*str_req), reply, sizeof(*reply)); |
1410 | if (ret < 0) { | 1216 | if (ret < 0) { |
1411 | dev_err(hsw->dev, "error: stream commit failed\n"); | 1217 | dev_err(hsw->dev, "error: stream commit failed\n"); |
1412 | return ret; | 1218 | return ret; |
@@ -1455,7 +1261,8 @@ int sst_hsw_mixer_get_info(struct sst_hsw *hsw) | |||
1455 | 1261 | ||
1456 | trace_ipc_request("get global mixer info", 0); | 1262 | trace_ipc_request("get global mixer info", 0); |
1457 | 1263 | ||
1458 | ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply)); | 1264 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, |
1265 | reply, sizeof(*reply)); | ||
1459 | if (ret < 0) { | 1266 | if (ret < 0) { |
1460 | dev_err(hsw->dev, "error: get stream info failed\n"); | 1267 | dev_err(hsw->dev, "error: get stream info failed\n"); |
1461 | return ret; | 1268 | return ret; |
@@ -1476,9 +1283,10 @@ static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type, | |||
1476 | header |= (stream_id << IPC_STR_ID_SHIFT); | 1283 | header |= (stream_id << IPC_STR_ID_SHIFT); |
1477 | 1284 | ||
1478 | if (wait) | 1285 | if (wait) |
1479 | return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); | 1286 | return sst_ipc_tx_message_wait(&hsw->ipc, header, |
1287 | NULL, 0, NULL, 0); | ||
1480 | else | 1288 | else |
1481 | return ipc_tx_message_nowait(hsw, header, NULL, 0); | 1289 | return sst_ipc_tx_message_nowait(&hsw->ipc, header, NULL, 0); |
1482 | } | 1290 | } |
1483 | 1291 | ||
1484 | /* Stream ALSA trigger operations */ | 1292 | /* Stream ALSA trigger operations */ |
@@ -1605,8 +1413,8 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, | |||
1605 | 1413 | ||
1606 | header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); | 1414 | header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); |
1607 | 1415 | ||
1608 | ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config), | 1416 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &config, |
1609 | NULL, 0); | 1417 | sizeof(config), NULL, 0); |
1610 | if (ret < 0) | 1418 | if (ret < 0) |
1611 | dev_err(hsw->dev, "error: set device formats failed\n"); | 1419 | dev_err(hsw->dev, "error: set device formats failed\n"); |
1612 | 1420 | ||
@@ -1626,8 +1434,8 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
1626 | 1434 | ||
1627 | trace_ipc_request("PM enter Dx state", state); | 1435 | trace_ipc_request("PM enter Dx state", state); |
1628 | 1436 | ||
1629 | ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), | 1437 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &state_, |
1630 | dx, sizeof(*dx)); | 1438 | sizeof(state_), dx, sizeof(*dx)); |
1631 | if (ret < 0) { | 1439 | if (ret < 0) { |
1632 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); | 1440 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); |
1633 | return ret; | 1441 | return ret; |
@@ -1770,32 +1578,6 @@ static int sst_hsw_dx_state_restore(struct sst_hsw *hsw) | |||
1770 | return 0; | 1578 | return 0; |
1771 | } | 1579 | } |
1772 | 1580 | ||
1773 | static void sst_hsw_drop_all(struct sst_hsw *hsw) | ||
1774 | { | ||
1775 | struct ipc_message *msg, *tmp; | ||
1776 | unsigned long flags; | ||
1777 | int tx_drop_cnt = 0, rx_drop_cnt = 0; | ||
1778 | |||
1779 | /* drop all TX and Rx messages before we stall + reset DSP */ | ||
1780 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
1781 | |||
1782 | list_for_each_entry_safe(msg, tmp, &hsw->tx_list, list) { | ||
1783 | list_move(&msg->list, &hsw->empty_list); | ||
1784 | tx_drop_cnt++; | ||
1785 | } | ||
1786 | |||
1787 | list_for_each_entry_safe(msg, tmp, &hsw->rx_list, list) { | ||
1788 | list_move(&msg->list, &hsw->empty_list); | ||
1789 | rx_drop_cnt++; | ||
1790 | } | ||
1791 | |||
1792 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
1793 | |||
1794 | if (tx_drop_cnt || rx_drop_cnt) | ||
1795 | dev_err(hsw->dev, "dropped IPC msg RX=%d, TX=%d\n", | ||
1796 | tx_drop_cnt, rx_drop_cnt); | ||
1797 | } | ||
1798 | |||
1799 | int sst_hsw_dsp_load(struct sst_hsw *hsw) | 1581 | int sst_hsw_dsp_load(struct sst_hsw *hsw) |
1800 | { | 1582 | { |
1801 | struct sst_dsp *dsp = hsw->dsp; | 1583 | struct sst_dsp *dsp = hsw->dsp; |
@@ -1875,7 +1657,7 @@ int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw) | |||
1875 | if (ret < 0) | 1657 | if (ret < 0) |
1876 | return ret; | 1658 | return ret; |
1877 | 1659 | ||
1878 | sst_hsw_drop_all(hsw); | 1660 | sst_ipc_drop_all(&hsw->ipc); |
1879 | 1661 | ||
1880 | return 0; | 1662 | return 0; |
1881 | } | 1663 | } |
@@ -1933,23 +1715,6 @@ int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) | |||
1933 | } | 1715 | } |
1934 | #endif | 1716 | #endif |
1935 | 1717 | ||
1936 | static int msg_empty_list_init(struct sst_hsw *hsw) | ||
1937 | { | ||
1938 | int i; | ||
1939 | |||
1940 | hsw->msg = kzalloc(sizeof(struct ipc_message) * | ||
1941 | IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | ||
1942 | if (hsw->msg == NULL) | ||
1943 | return -ENOMEM; | ||
1944 | |||
1945 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
1946 | init_waitqueue_head(&hsw->msg[i].waitq); | ||
1947 | list_add(&hsw->msg[i].list, &hsw->empty_list); | ||
1948 | } | ||
1949 | |||
1950 | return 0; | ||
1951 | } | ||
1952 | |||
1953 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) | 1718 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) |
1954 | { | 1719 | { |
1955 | return hsw->dsp; | 1720 | return hsw->dsp; |
@@ -2184,7 +1949,7 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, | |||
2184 | config.scratch_mem.size, config.scratch_mem.offset, | 1949 | config.scratch_mem.size, config.scratch_mem.offset, |
2185 | config.map.module_entries[0].entry_point); | 1950 | config.map.module_entries[0].entry_point); |
2186 | 1951 | ||
2187 | ret = ipc_tx_message_wait(hsw, header, | 1952 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, |
2188 | &config, sizeof(config), NULL, 0); | 1953 | &config, sizeof(config), NULL, 0); |
2189 | if (ret < 0) | 1954 | if (ret < 0) |
2190 | dev_err(dev, "ipc: module enable failed - %d\n", ret); | 1955 | dev_err(dev, "ipc: module enable failed - %d\n", ret); |
@@ -2223,7 +1988,7 @@ int sst_hsw_module_disable(struct sst_hsw *hsw, | |||
2223 | IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | | 1988 | IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | |
2224 | IPC_MODULE_ID(module_id); | 1989 | IPC_MODULE_ID(module_id); |
2225 | 1990 | ||
2226 | ret = ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); | 1991 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, NULL, 0); |
2227 | if (ret < 0) | 1992 | if (ret < 0) |
2228 | dev_err(dev, "module disable failed - %d\n", ret); | 1993 | dev_err(dev, "module disable failed - %d\n", ret); |
2229 | else | 1994 | else |
@@ -2277,7 +2042,7 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, | |||
2277 | parameter->parameter_id = parameter_id; | 2042 | parameter->parameter_id = parameter_id; |
2278 | parameter->data_size = param_size; | 2043 | parameter->data_size = param_size; |
2279 | 2044 | ||
2280 | ret = ipc_tx_message_wait(hsw, header, | 2045 | ret = sst_ipc_tx_message_wait(&hsw->ipc, header, |
2281 | parameter, transfer_parameter_size , NULL, 0); | 2046 | parameter, transfer_parameter_size , NULL, 0); |
2282 | if (ret < 0) | 2047 | if (ret < 0) |
2283 | dev_err(dev, "ipc: module set parameter failed - %d\n", ret); | 2048 | dev_err(dev, "ipc: module set parameter failed - %d\n", ret); |
@@ -2296,10 +2061,48 @@ static struct sst_dsp_device hsw_dev = { | |||
2296 | .ops = &haswell_ops, | 2061 | .ops = &haswell_ops, |
2297 | }; | 2062 | }; |
2298 | 2063 | ||
2064 | static void hsw_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) | ||
2065 | { | ||
2066 | /* send the message */ | ||
2067 | sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); | ||
2068 | sst_dsp_ipc_msg_tx(ipc->dsp, msg->header); | ||
2069 | } | ||
2070 | |||
2071 | static void hsw_shim_dbg(struct sst_generic_ipc *ipc, const char *text) | ||
2072 | { | ||
2073 | struct sst_dsp *sst = ipc->dsp; | ||
2074 | u32 isr, ipcd, imrx, ipcx; | ||
2075 | |||
2076 | ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX); | ||
2077 | isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); | ||
2078 | ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
2079 | imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX); | ||
2080 | |||
2081 | dev_err(ipc->dev, | ||
2082 | "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n", | ||
2083 | text, ipcx, isr, ipcd, imrx); | ||
2084 | } | ||
2085 | |||
2086 | static void hsw_tx_data_copy(struct ipc_message *msg, char *tx_data, | ||
2087 | size_t tx_size) | ||
2088 | { | ||
2089 | memcpy(msg->tx_data, tx_data, tx_size); | ||
2090 | } | ||
2091 | |||
2092 | static u64 hsw_reply_msg_match(u64 header, u64 *mask) | ||
2093 | { | ||
2094 | /* clear reply bits & status bits */ | ||
2095 | header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); | ||
2096 | *mask = (u64)-1; | ||
2097 | |||
2098 | return header; | ||
2099 | } | ||
2100 | |||
2299 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | 2101 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) |
2300 | { | 2102 | { |
2301 | struct sst_hsw_ipc_fw_version version; | 2103 | struct sst_hsw_ipc_fw_version version; |
2302 | struct sst_hsw *hsw; | 2104 | struct sst_hsw *hsw; |
2105 | struct sst_generic_ipc *ipc; | ||
2303 | int ret; | 2106 | int ret; |
2304 | 2107 | ||
2305 | dev_dbg(dev, "initialising Audio DSP IPC\n"); | 2108 | dev_dbg(dev, "initialising Audio DSP IPC\n"); |
@@ -2308,39 +2111,30 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
2308 | if (hsw == NULL) | 2111 | if (hsw == NULL) |
2309 | return -ENOMEM; | 2112 | return -ENOMEM; |
2310 | 2113 | ||
2311 | hsw->dev = dev; | 2114 | ipc = &hsw->ipc; |
2312 | INIT_LIST_HEAD(&hsw->stream_list); | 2115 | ipc->dev = dev; |
2313 | INIT_LIST_HEAD(&hsw->tx_list); | 2116 | ipc->ops.tx_msg = hsw_tx_msg; |
2314 | INIT_LIST_HEAD(&hsw->rx_list); | 2117 | ipc->ops.shim_dbg = hsw_shim_dbg; |
2315 | INIT_LIST_HEAD(&hsw->empty_list); | 2118 | ipc->ops.tx_data_copy = hsw_tx_data_copy; |
2316 | init_waitqueue_head(&hsw->boot_wait); | 2119 | ipc->ops.reply_msg_match = hsw_reply_msg_match; |
2317 | init_waitqueue_head(&hsw->wait_txq); | ||
2318 | 2120 | ||
2319 | ret = msg_empty_list_init(hsw); | 2121 | ret = sst_ipc_init(ipc); |
2320 | if (ret < 0) | 2122 | if (ret != 0) |
2321 | return -ENOMEM; | 2123 | goto ipc_init_err; |
2322 | |||
2323 | /* start the IPC message thread */ | ||
2324 | init_kthread_worker(&hsw->kworker); | ||
2325 | hsw->tx_thread = kthread_run(kthread_worker_fn, | ||
2326 | &hsw->kworker, "%s", | ||
2327 | dev_name(hsw->dev)); | ||
2328 | if (IS_ERR(hsw->tx_thread)) { | ||
2329 | ret = PTR_ERR(hsw->tx_thread); | ||
2330 | dev_err(hsw->dev, "error: failed to create message TX task\n"); | ||
2331 | goto err_free_msg; | ||
2332 | } | ||
2333 | init_kthread_work(&hsw->kwork, ipc_tx_msgs); | ||
2334 | 2124 | ||
2125 | INIT_LIST_HEAD(&hsw->stream_list); | ||
2126 | init_waitqueue_head(&hsw->boot_wait); | ||
2335 | hsw_dev.thread_context = hsw; | 2127 | hsw_dev.thread_context = hsw; |
2336 | 2128 | ||
2337 | /* init SST shim */ | 2129 | /* init SST shim */ |
2338 | hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); | 2130 | hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); |
2339 | if (hsw->dsp == NULL) { | 2131 | if (hsw->dsp == NULL) { |
2340 | ret = -ENODEV; | 2132 | ret = -ENODEV; |
2341 | goto dsp_err; | 2133 | goto dsp_new_err; |
2342 | } | 2134 | } |
2343 | 2135 | ||
2136 | ipc->dsp = hsw->dsp; | ||
2137 | |||
2344 | /* allocate DMA buffer for context storage */ | 2138 | /* allocate DMA buffer for context storage */ |
2345 | hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev, | 2139 | hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev, |
2346 | SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL); | 2140 | SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL); |
@@ -2404,11 +2198,10 @@ fw_err: | |||
2404 | hsw->dx_context, hsw->dx_context_paddr); | 2198 | hsw->dx_context, hsw->dx_context_paddr); |
2405 | dma_err: | 2199 | dma_err: |
2406 | sst_dsp_free(hsw->dsp); | 2200 | sst_dsp_free(hsw->dsp); |
2407 | dsp_err: | 2201 | dsp_new_err: |
2408 | kthread_stop(hsw->tx_thread); | 2202 | sst_ipc_fini(ipc); |
2409 | err_free_msg: | 2203 | ipc_init_err: |
2410 | kfree(hsw->msg); | 2204 | kfree(hsw); |
2411 | |||
2412 | return ret; | 2205 | return ret; |
2413 | } | 2206 | } |
2414 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); | 2207 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); |
@@ -2422,7 +2215,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) | |||
2422 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | 2215 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, |
2423 | hsw->dx_context, hsw->dx_context_paddr); | 2216 | hsw->dx_context, hsw->dx_context_paddr); |
2424 | sst_dsp_free(hsw->dsp); | 2217 | sst_dsp_free(hsw->dsp); |
2425 | kthread_stop(hsw->tx_thread); | 2218 | sst_ipc_fini(&hsw->ipc); |
2426 | kfree(hsw->msg); | ||
2427 | } | 2219 | } |
2428 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); | 2220 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); |