diff options
Diffstat (limited to 'sound/soc/intel/sst-haswell-ipc.c')
-rw-r--r-- | sound/soc/intel/sst-haswell-ipc.c | 53 |
1 files changed, 42 insertions, 11 deletions
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index f46bb4ddde6f..434236343ddf 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/list.h> | ||
29 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
30 | #include <linux/kthread.h> | 29 | #include <linux/kthread.h> |
31 | #include <linux/firmware.h> | 30 | #include <linux/firmware.h> |
@@ -617,7 +616,7 @@ static void hsw_notification_work(struct work_struct *work) | |||
617 | case IPC_POSITION_CHANGED: | 616 | case IPC_POSITION_CHANGED: |
618 | trace_ipc_notification("DSP stream position changed for", | 617 | trace_ipc_notification("DSP stream position changed for", |
619 | stream->reply.stream_hw_id); | 618 | stream->reply.stream_hw_id); |
620 | sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos)); | 619 | sst_dsp_inbox_read(hsw->dsp, pos, sizeof(*pos)); |
621 | 620 | ||
622 | if (stream->notify_position) | 621 | if (stream->notify_position) |
623 | stream->notify_position(stream, stream->pdata); | 622 | stream->notify_position(stream, stream->pdata); |
@@ -991,7 +990,8 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream | |||
991 | return -EINVAL; | 990 | return -EINVAL; |
992 | 991 | ||
993 | sst_dsp_read(hsw->dsp, volume, | 992 | sst_dsp_read(hsw->dsp, volume, |
994 | stream->reply.volume_register_address[channel], sizeof(volume)); | 993 | stream->reply.volume_register_address[channel], |
994 | sizeof(*volume)); | ||
995 | 995 | ||
996 | return 0; | 996 | return 0; |
997 | } | 997 | } |
@@ -1158,11 +1158,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | |||
1158 | void *data) | 1158 | void *data) |
1159 | { | 1159 | { |
1160 | struct sst_hsw_stream *stream; | 1160 | struct sst_hsw_stream *stream; |
1161 | struct sst_dsp *sst = hsw->dsp; | ||
1162 | unsigned long flags; | ||
1161 | 1163 | ||
1162 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 1164 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
1163 | if (stream == NULL) | 1165 | if (stream == NULL) |
1164 | return NULL; | 1166 | return NULL; |
1165 | 1167 | ||
1168 | spin_lock_irqsave(&sst->spinlock, flags); | ||
1166 | list_add(&stream->node, &hsw->stream_list); | 1169 | list_add(&stream->node, &hsw->stream_list); |
1167 | stream->notify_position = notify_position; | 1170 | stream->notify_position = notify_position; |
1168 | stream->pdata = data; | 1171 | stream->pdata = data; |
@@ -1171,6 +1174,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | |||
1171 | 1174 | ||
1172 | /* work to process notification messages */ | 1175 | /* work to process notification messages */ |
1173 | INIT_WORK(&stream->notify_work, hsw_notification_work); | 1176 | INIT_WORK(&stream->notify_work, hsw_notification_work); |
1177 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
1174 | 1178 | ||
1175 | return stream; | 1179 | return stream; |
1176 | } | 1180 | } |
@@ -1179,6 +1183,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1179 | { | 1183 | { |
1180 | u32 header; | 1184 | u32 header; |
1181 | int ret = 0; | 1185 | int ret = 0; |
1186 | struct sst_dsp *sst = hsw->dsp; | ||
1187 | unsigned long flags; | ||
1182 | 1188 | ||
1183 | /* dont free DSP streams that are not commited */ | 1189 | /* dont free DSP streams that are not commited */ |
1184 | if (!stream->commited) | 1190 | if (!stream->commited) |
@@ -1200,8 +1206,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1200 | trace_hsw_stream_free_req(stream, &stream->free_req); | 1206 | trace_hsw_stream_free_req(stream, &stream->free_req); |
1201 | 1207 | ||
1202 | out: | 1208 | out: |
1209 | cancel_work_sync(&stream->notify_work); | ||
1210 | spin_lock_irqsave(&sst->spinlock, flags); | ||
1203 | list_del(&stream->node); | 1211 | list_del(&stream->node); |
1204 | kfree(stream); | 1212 | kfree(stream); |
1213 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
1205 | 1214 | ||
1206 | return ret; | 1215 | return ret; |
1207 | } | 1216 | } |
@@ -1537,10 +1546,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1537 | } | 1546 | } |
1538 | 1547 | ||
1539 | /* Stream pointer positions */ | 1548 | /* Stream pointer positions */ |
1540 | int sst_hsw_get_dsp_position(struct sst_hsw *hsw, | 1549 | u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, |
1541 | struct sst_hsw_stream *stream) | 1550 | struct sst_hsw_stream *stream) |
1542 | { | 1551 | { |
1543 | return stream->rpos.position; | 1552 | u32 rpos; |
1553 | |||
1554 | sst_dsp_read(hsw->dsp, &rpos, | ||
1555 | stream->reply.read_position_register_address, sizeof(rpos)); | ||
1556 | |||
1557 | return rpos; | ||
1558 | } | ||
1559 | |||
1560 | /* Stream presentation (monotonic) positions */ | ||
1561 | u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, | ||
1562 | struct sst_hsw_stream *stream) | ||
1563 | { | ||
1564 | u64 ppos; | ||
1565 | |||
1566 | sst_dsp_read(hsw->dsp, &ppos, | ||
1567 | stream->reply.presentation_position_register_address, | ||
1568 | sizeof(ppos)); | ||
1569 | |||
1570 | return ppos; | ||
1544 | } | 1571 | } |
1545 | 1572 | ||
1546 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | 1573 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, |
@@ -1609,7 +1636,7 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
1609 | trace_ipc_request("PM enter Dx state", state); | 1636 | trace_ipc_request("PM enter Dx state", state); |
1610 | 1637 | ||
1611 | ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), | 1638 | ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), |
1612 | dx, sizeof(dx)); | 1639 | dx, sizeof(*dx)); |
1613 | if (ret < 0) { | 1640 | if (ret < 0) { |
1614 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); | 1641 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); |
1615 | return ret; | 1642 | return ret; |
@@ -1702,17 +1729,17 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1702 | 1729 | ||
1703 | ret = msg_empty_list_init(hsw); | 1730 | ret = msg_empty_list_init(hsw); |
1704 | if (ret < 0) | 1731 | if (ret < 0) |
1705 | goto list_err; | 1732 | return -ENOMEM; |
1706 | 1733 | ||
1707 | /* start the IPC message thread */ | 1734 | /* start the IPC message thread */ |
1708 | init_kthread_worker(&hsw->kworker); | 1735 | init_kthread_worker(&hsw->kworker); |
1709 | hsw->tx_thread = kthread_run(kthread_worker_fn, | 1736 | hsw->tx_thread = kthread_run(kthread_worker_fn, |
1710 | &hsw->kworker, | 1737 | &hsw->kworker, "%s", |
1711 | dev_name(hsw->dev)); | 1738 | dev_name(hsw->dev)); |
1712 | if (IS_ERR(hsw->tx_thread)) { | 1739 | if (IS_ERR(hsw->tx_thread)) { |
1713 | ret = PTR_ERR(hsw->tx_thread); | 1740 | ret = PTR_ERR(hsw->tx_thread); |
1714 | dev_err(hsw->dev, "error: failed to create message TX task\n"); | 1741 | dev_err(hsw->dev, "error: failed to create message TX task\n"); |
1715 | goto list_err; | 1742 | goto err_free_msg; |
1716 | } | 1743 | } |
1717 | init_kthread_work(&hsw->kwork, ipc_tx_msgs); | 1744 | init_kthread_work(&hsw->kwork, ipc_tx_msgs); |
1718 | 1745 | ||
@@ -1722,7 +1749,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1722 | hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); | 1749 | hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); |
1723 | if (hsw->dsp == NULL) { | 1750 | if (hsw->dsp == NULL) { |
1724 | ret = -ENODEV; | 1751 | ret = -ENODEV; |
1725 | goto list_err; | 1752 | goto dsp_err; |
1726 | } | 1753 | } |
1727 | 1754 | ||
1728 | /* keep the DSP in reset state for base FW loading */ | 1755 | /* keep the DSP in reset state for base FW loading */ |
@@ -1766,8 +1793,11 @@ boot_err: | |||
1766 | sst_fw_free(hsw_sst_fw); | 1793 | sst_fw_free(hsw_sst_fw); |
1767 | fw_err: | 1794 | fw_err: |
1768 | sst_dsp_free(hsw->dsp); | 1795 | sst_dsp_free(hsw->dsp); |
1796 | dsp_err: | ||
1797 | kthread_stop(hsw->tx_thread); | ||
1798 | err_free_msg: | ||
1769 | kfree(hsw->msg); | 1799 | kfree(hsw->msg); |
1770 | list_err: | 1800 | |
1771 | return ret; | 1801 | return ret; |
1772 | } | 1802 | } |
1773 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); | 1803 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); |
@@ -1780,6 +1810,7 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) | |||
1780 | sst_fw_free_all(hsw->dsp); | 1810 | sst_fw_free_all(hsw->dsp); |
1781 | sst_dsp_free(hsw->dsp); | 1811 | sst_dsp_free(hsw->dsp); |
1782 | kfree(hsw->scratch); | 1812 | kfree(hsw->scratch); |
1813 | kthread_stop(hsw->tx_thread); | ||
1783 | kfree(hsw->msg); | 1814 | kfree(hsw->msg); |
1784 | } | 1815 | } |
1785 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); | 1816 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); |