diff options
| -rw-r--r-- | sound/soc/intel/baytrail/sst-baytrail-ipc.c | 360 |
1 files changed, 77 insertions, 283 deletions
diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index aabb9b0f48b8..1efb33b36303 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include "sst-baytrail-ipc.h" | 31 | #include "sst-baytrail-ipc.h" |
| 32 | #include "../common/sst-dsp.h" | 32 | #include "../common/sst-dsp.h" |
| 33 | #include "../common/sst-dsp-priv.h" | 33 | #include "../common/sst-dsp-priv.h" |
| 34 | #include "../common/sst-ipc.h" | ||
| 34 | 35 | ||
| 35 | /* IPC message timeout */ | 36 | /* IPC message timeout */ |
| 36 | #define IPC_TIMEOUT_MSECS 300 | 37 | #define IPC_TIMEOUT_MSECS 300 |
| @@ -142,23 +143,6 @@ struct sst_byt_fw_init { | |||
| 142 | u8 debug_info; | 143 | u8 debug_info; |
| 143 | } __packed; | 144 | } __packed; |
| 144 | 145 | ||
| 145 | /* driver internal IPC message structure */ | ||
| 146 | struct ipc_message { | ||
| 147 | struct list_head list; | ||
| 148 | u64 header; | ||
| 149 | |||
| 150 | /* direction wrt host CPU */ | ||
| 151 | char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; | ||
| 152 | size_t tx_size; | ||
| 153 | char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; | ||
| 154 | size_t rx_size; | ||
| 155 | |||
| 156 | wait_queue_head_t waitq; | ||
| 157 | bool complete; | ||
| 158 | bool wait; | ||
| 159 | int errno; | ||
| 160 | }; | ||
| 161 | |||
| 162 | struct sst_byt_stream; | 146 | struct sst_byt_stream; |
| 163 | struct sst_byt; | 147 | struct sst_byt; |
| 164 | 148 | ||
| @@ -195,14 +179,7 @@ struct sst_byt { | |||
| 195 | struct sst_fw *fw; | 179 | struct sst_fw *fw; |
| 196 | 180 | ||
| 197 | /* IPC messaging */ | 181 | /* IPC messaging */ |
| 198 | struct list_head tx_list; | 182 | struct sst_generic_ipc ipc; |
| 199 | struct list_head rx_list; | ||
| 200 | struct list_head empty_list; | ||
| 201 | wait_queue_head_t wait_txq; | ||
| 202 | struct task_struct *tx_thread; | ||
| 203 | struct kthread_worker kworker; | ||
| 204 | struct kthread_work kwork; | ||
| 205 | struct ipc_message *msg; | ||
| 206 | }; | 183 | }; |
| 207 | 184 | ||
| 208 | static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id) | 185 | static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id) |
| @@ -246,209 +223,6 @@ static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt, | |||
| 246 | return NULL; | 223 | return NULL; |
| 247 | } | 224 | } |
| 248 | 225 | ||
| 249 | static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text) | ||
| 250 | { | ||
| 251 | struct sst_dsp *sst = byt->dsp; | ||
| 252 | u64 isr, ipcd, imrx, ipcx; | ||
| 253 | |||
| 254 | ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX); | ||
| 255 | isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); | ||
| 256 | ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
| 257 | imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX); | ||
| 258 | |||
| 259 | dev_err(byt->dev, | ||
| 260 | "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n", | ||
| 261 | text, ipcx, isr, ipcd, imrx); | ||
| 262 | } | ||
| 263 | |||
| 264 | /* locks held by caller */ | ||
| 265 | static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt) | ||
| 266 | { | ||
| 267 | struct ipc_message *msg = NULL; | ||
| 268 | |||
| 269 | if (!list_empty(&byt->empty_list)) { | ||
| 270 | msg = list_first_entry(&byt->empty_list, | ||
| 271 | struct ipc_message, list); | ||
| 272 | list_del(&msg->list); | ||
| 273 | } | ||
| 274 | |||
| 275 | return msg; | ||
| 276 | } | ||
| 277 | |||
| 278 | static void sst_byt_ipc_tx_msgs(struct kthread_work *work) | ||
| 279 | { | ||
| 280 | struct sst_byt *byt = | ||
| 281 | container_of(work, struct sst_byt, kwork); | ||
| 282 | struct ipc_message *msg; | ||
| 283 | u64 ipcx; | ||
| 284 | unsigned long flags; | ||
| 285 | |||
| 286 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
| 287 | if (list_empty(&byt->tx_list)) { | ||
| 288 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 289 | return; | ||
| 290 | } | ||
| 291 | |||
| 292 | /* if the DSP is busy we will TX messages after IRQ */ | ||
| 293 | ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX); | ||
| 294 | if (ipcx & SST_BYT_IPCX_BUSY) { | ||
| 295 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 296 | return; | ||
| 297 | } | ||
| 298 | |||
| 299 | msg = list_first_entry(&byt->tx_list, struct ipc_message, list); | ||
| 300 | |||
| 301 | list_move(&msg->list, &byt->rx_list); | ||
| 302 | |||
| 303 | /* send the message */ | ||
| 304 | if (msg->header & IPC_HEADER_LARGE(true)) | ||
| 305 | sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size); | ||
| 306 | sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header); | ||
| 307 | |||
| 308 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 309 | } | ||
| 310 | |||
| 311 | static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt, | ||
| 312 | struct ipc_message *msg) | ||
| 313 | { | ||
| 314 | msg->complete = true; | ||
| 315 | |||
| 316 | if (!msg->wait) | ||
| 317 | list_add_tail(&msg->list, &byt->empty_list); | ||
| 318 | else | ||
| 319 | wake_up(&msg->waitq); | ||
| 320 | } | ||
| 321 | |||
| 322 | static void sst_byt_drop_all(struct sst_byt *byt) | ||
| 323 | { | ||
| 324 | struct ipc_message *msg, *tmp; | ||
| 325 | unsigned long flags; | ||
| 326 | |||
| 327 | /* drop all TX and Rx messages before we stall + reset DSP */ | ||
| 328 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
| 329 | list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) { | ||
| 330 | list_move(&msg->list, &byt->empty_list); | ||
| 331 | } | ||
| 332 | |||
| 333 | list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) { | ||
| 334 | list_move(&msg->list, &byt->empty_list); | ||
| 335 | } | ||
| 336 | |||
| 337 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 338 | } | ||
| 339 | |||
| 340 | static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg, | ||
| 341 | void *rx_data) | ||
| 342 | { | ||
| 343 | unsigned long flags; | ||
| 344 | int ret; | ||
| 345 | |||
| 346 | /* wait for DSP completion */ | ||
| 347 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
| 348 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
| 349 | |||
| 350 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
| 351 | if (ret == 0) { | ||
| 352 | list_del(&msg->list); | ||
| 353 | sst_byt_ipc_shim_dbg(byt, "message timeout"); | ||
| 354 | |||
| 355 | ret = -ETIMEDOUT; | ||
| 356 | } else { | ||
| 357 | |||
| 358 | /* copy the data returned from DSP */ | ||
| 359 | if (msg->rx_size) | ||
| 360 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
| 361 | ret = msg->errno; | ||
| 362 | } | ||
| 363 | |||
| 364 | list_add_tail(&msg->list, &byt->empty_list); | ||
| 365 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 366 | return ret; | ||
| 367 | } | ||
| 368 | |||
| 369 | static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header, | ||
| 370 | void *tx_data, size_t tx_bytes, | ||
| 371 | void *rx_data, size_t rx_bytes, int wait) | ||
| 372 | { | ||
| 373 | unsigned long flags; | ||
| 374 | struct ipc_message *msg; | ||
| 375 | |||
| 376 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
| 377 | |||
| 378 | msg = sst_byt_msg_get_empty(byt); | ||
| 379 | if (msg == NULL) { | ||
| 380 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 381 | return -EBUSY; | ||
| 382 | } | ||
| 383 | |||
| 384 | msg->header = header; | ||
| 385 | msg->tx_size = tx_bytes; | ||
| 386 | msg->rx_size = rx_bytes; | ||
| 387 | msg->wait = wait; | ||
| 388 | msg->errno = 0; | ||
| 389 | msg->complete = false; | ||
| 390 | |||
| 391 | if (tx_bytes) { | ||
| 392 | /* msg content = lower 32-bit of the header + data */ | ||
| 393 | *(u32 *)msg->tx_data = (u32)(header & (u32)-1); | ||
| 394 | memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes); | ||
| 395 | msg->tx_size += sizeof(u32); | ||
| 396 | } | ||
| 397 | |||
| 398 | list_add_tail(&msg->list, &byt->tx_list); | ||
| 399 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 400 | |||
| 401 | queue_kthread_work(&byt->kworker, &byt->kwork); | ||
| 402 | |||
| 403 | if (wait) | ||
| 404 | return sst_byt_tx_wait_done(byt, msg, rx_data); | ||
| 405 | else | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header, | ||
| 410 | void *tx_data, size_t tx_bytes, | ||
| 411 | void *rx_data, size_t rx_bytes) | ||
| 412 | { | ||
| 413 | return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, | ||
| 414 | rx_data, rx_bytes, 1); | ||
| 415 | } | ||
| 416 | |||
| 417 | static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header, | ||
| 418 | void *tx_data, size_t tx_bytes) | ||
| 419 | { | ||
| 420 | return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, | ||
| 421 | NULL, 0, 0); | ||
| 422 | } | ||
| 423 | |||
| 424 | static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt, | ||
| 425 | u64 header) | ||
| 426 | { | ||
| 427 | struct ipc_message *msg = NULL, *_msg; | ||
| 428 | u64 mask; | ||
| 429 | |||
| 430 | /* match reply to message sent based on msg and stream IDs */ | ||
| 431 | mask = IPC_HEADER_MSG_ID_MASK | | ||
| 432 | IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT; | ||
| 433 | header &= mask; | ||
| 434 | |||
| 435 | if (list_empty(&byt->rx_list)) { | ||
| 436 | dev_err(byt->dev, | ||
| 437 | "ipc: rx list is empty but received 0x%llx\n", header); | ||
| 438 | goto out; | ||
| 439 | } | ||
| 440 | |||
| 441 | list_for_each_entry(_msg, &byt->rx_list, list) { | ||
| 442 | if ((_msg->header & mask) == header) { | ||
| 443 | msg = _msg; | ||
| 444 | break; | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | out: | ||
| 449 | return msg; | ||
| 450 | } | ||
| 451 | |||
| 452 | static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) | 226 | static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) |
| 453 | { | 227 | { |
| 454 | struct sst_byt_stream *stream; | 228 | struct sst_byt_stream *stream; |
| @@ -477,7 +251,7 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header) | |||
| 477 | { | 251 | { |
| 478 | struct ipc_message *msg; | 252 | struct ipc_message *msg; |
| 479 | 253 | ||
| 480 | msg = sst_byt_reply_find_msg(byt, header); | 254 | msg = sst_ipc_reply_find_msg(&byt->ipc, header); |
| 481 | if (msg == NULL) | 255 | if (msg == NULL) |
| 482 | return 1; | 256 | return 1; |
| 483 | 257 | ||
| @@ -491,7 +265,7 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header) | |||
| 491 | 265 | ||
| 492 | list_del(&msg->list); | 266 | list_del(&msg->list); |
| 493 | /* wake up */ | 267 | /* wake up */ |
| 494 | sst_byt_tx_msg_reply_complete(byt, msg); | 268 | sst_ipc_tx_msg_reply_complete(&byt->ipc, msg); |
| 495 | 269 | ||
| 496 | return 1; | 270 | return 1; |
| 497 | } | 271 | } |
| @@ -538,6 +312,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) | |||
| 538 | { | 312 | { |
| 539 | struct sst_dsp *sst = (struct sst_dsp *) context; | 313 | struct sst_dsp *sst = (struct sst_dsp *) context; |
| 540 | struct sst_byt *byt = sst_dsp_get_thread_context(sst); | 314 | struct sst_byt *byt = sst_dsp_get_thread_context(sst); |
| 315 | struct sst_generic_ipc *ipc = &byt->ipc; | ||
| 541 | u64 header; | 316 | u64 header; |
| 542 | unsigned long flags; | 317 | unsigned long flags; |
| 543 | 318 | ||
| @@ -569,7 +344,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) | |||
| 569 | spin_unlock_irqrestore(&sst->spinlock, flags); | 344 | spin_unlock_irqrestore(&sst->spinlock, flags); |
| 570 | 345 | ||
| 571 | /* continue to send any remaining messages... */ | 346 | /* continue to send any remaining messages... */ |
| 572 | queue_kthread_work(&byt->kworker, &byt->kwork); | 347 | queue_kthread_work(&ipc->kworker, &ipc->kwork); |
| 573 | 348 | ||
| 574 | return IRQ_HANDLED; | 349 | return IRQ_HANDLED; |
| 575 | } | 350 | } |
| @@ -656,7 +431,8 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
| 656 | header = sst_byt_header(IPC_IA_ALLOC_STREAM, | 431 | header = sst_byt_header(IPC_IA_ALLOC_STREAM, |
| 657 | sizeof(*str_req) + sizeof(u32), | 432 | sizeof(*str_req) + sizeof(u32), |
| 658 | true, stream->str_id); | 433 | true, stream->str_id); |
| 659 | ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req), | 434 | ret = sst_ipc_tx_message_wait(&byt->ipc, header, str_req, |
| 435 | sizeof(*str_req), | ||
| 660 | reply, sizeof(*reply)); | 436 | reply, sizeof(*reply)); |
| 661 | if (ret < 0) { | 437 | if (ret < 0) { |
| 662 | dev_err(byt->dev, "ipc: error stream commit failed\n"); | 438 | dev_err(byt->dev, "ipc: error stream commit failed\n"); |
| @@ -679,7 +455,7 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | |||
| 679 | goto out; | 455 | goto out; |
| 680 | 456 | ||
| 681 | header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); | 457 | header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); |
| 682 | ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); | 458 | ret = sst_ipc_tx_message_wait(&byt->ipc, header, NULL, 0, NULL, 0); |
| 683 | if (ret < 0) { | 459 | if (ret < 0) { |
| 684 | dev_err(byt->dev, "ipc: free stream %d failed\n", | 460 | dev_err(byt->dev, "ipc: free stream %d failed\n", |
| 685 | stream->str_id); | 461 | stream->str_id); |
| @@ -703,9 +479,11 @@ static int sst_byt_stream_operations(struct sst_byt *byt, int type, | |||
| 703 | 479 | ||
| 704 | header = sst_byt_header(type, 0, false, stream_id); | 480 | header = sst_byt_header(type, 0, false, stream_id); |
| 705 | if (wait) | 481 | if (wait) |
| 706 | return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); | 482 | return sst_ipc_tx_message_wait(&byt->ipc, header, NULL, |
| 483 | 0, NULL, 0); | ||
| 707 | else | 484 | else |
| 708 | return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0); | 485 | return sst_ipc_tx_message_nowait(&byt->ipc, header, |
| 486 | NULL, 0); | ||
| 709 | } | 487 | } |
| 710 | 488 | ||
| 711 | /* stream ALSA trigger operations */ | 489 | /* stream ALSA trigger operations */ |
| @@ -725,7 +503,7 @@ int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream, | |||
| 725 | tx_msg = &start_stream; | 503 | tx_msg = &start_stream; |
| 726 | size = sizeof(start_stream); | 504 | size = sizeof(start_stream); |
| 727 | 505 | ||
| 728 | ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); | 506 | ret = sst_ipc_tx_message_nowait(&byt->ipc, header, tx_msg, size); |
| 729 | if (ret < 0) | 507 | if (ret < 0) |
| 730 | dev_err(byt->dev, "ipc: error failed to start stream %d\n", | 508 | dev_err(byt->dev, "ipc: error failed to start stream %d\n", |
| 731 | stream->str_id); | 509 | stream->str_id); |
| @@ -790,23 +568,6 @@ int sst_byt_get_dsp_position(struct sst_byt *byt, | |||
| 790 | return do_div(fw_tstamp.ring_buffer_counter, buffer_size); | 568 | return do_div(fw_tstamp.ring_buffer_counter, buffer_size); |
| 791 | } | 569 | } |
| 792 | 570 | ||
| 793 | static int msg_empty_list_init(struct sst_byt *byt) | ||
| 794 | { | ||
| 795 | struct ipc_message *msg; | ||
| 796 | int i; | ||
| 797 | |||
| 798 | byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | ||
| 799 | if (byt->msg == NULL) | ||
| 800 | return -ENOMEM; | ||
| 801 | |||
| 802 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
| 803 | init_waitqueue_head(&byt->msg[i].waitq); | ||
| 804 | list_add(&byt->msg[i].list, &byt->empty_list); | ||
| 805 | } | ||
| 806 | |||
| 807 | return 0; | ||
| 808 | } | ||
| 809 | |||
| 810 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt) | 571 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt) |
| 811 | { | 572 | { |
| 812 | return byt->dsp; | 573 | return byt->dsp; |
| @@ -823,7 +584,7 @@ int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) | |||
| 823 | 584 | ||
| 824 | dev_dbg(byt->dev, "dsp reset\n"); | 585 | dev_dbg(byt->dev, "dsp reset\n"); |
| 825 | sst_dsp_reset(byt->dsp); | 586 | sst_dsp_reset(byt->dsp); |
| 826 | sst_byt_drop_all(byt); | 587 | sst_ipc_drop_all(&byt->ipc); |
| 827 | dev_dbg(byt->dev, "dsp in reset\n"); | 588 | dev_dbg(byt->dev, "dsp in reset\n"); |
| 828 | 589 | ||
| 829 | dev_dbg(byt->dev, "free all blocks and unload fw\n"); | 590 | dev_dbg(byt->dev, "free all blocks and unload fw\n"); |
| @@ -876,9 +637,52 @@ int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata) | |||
| 876 | } | 637 | } |
| 877 | EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); | 638 | EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); |
| 878 | 639 | ||
| 640 | static void byt_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) | ||
| 641 | { | ||
| 642 | if (msg->header & IPC_HEADER_LARGE(true)) | ||
| 643 | sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); | ||
| 644 | |||
| 645 | sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->header); | ||
| 646 | } | ||
| 647 | |||
| 648 | static void byt_shim_dbg(struct sst_generic_ipc *ipc, const char *text) | ||
| 649 | { | ||
| 650 | struct sst_dsp *sst = ipc->dsp; | ||
| 651 | u64 isr, ipcd, imrx, ipcx; | ||
| 652 | |||
| 653 | ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX); | ||
| 654 | isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); | ||
| 655 | ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
| 656 | imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX); | ||
| 657 | |||
| 658 | dev_err(ipc->dev, | ||
| 659 | "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n", | ||
| 660 | text, ipcx, isr, ipcd, imrx); | ||
| 661 | } | ||
| 662 | |||
| 663 | static void byt_tx_data_copy(struct ipc_message *msg, char *tx_data, | ||
| 664 | size_t tx_size) | ||
| 665 | { | ||
| 666 | /* msg content = lower 32-bit of the header + data */ | ||
| 667 | *(u32 *)msg->tx_data = (u32)(msg->header & (u32)-1); | ||
| 668 | memcpy(msg->tx_data + sizeof(u32), tx_data, tx_size); | ||
| 669 | msg->tx_size += sizeof(u32); | ||
| 670 | } | ||
| 671 | |||
| 672 | static u64 byt_reply_msg_match(u64 header, u64 *mask) | ||
| 673 | { | ||
| 674 | /* match reply to message sent based on msg and stream IDs */ | ||
| 675 | *mask = IPC_HEADER_MSG_ID_MASK | | ||
| 676 | IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT; | ||
| 677 | header &= *mask; | ||
| 678 | |||
| 679 | return header; | ||
| 680 | } | ||
| 681 | |||
| 879 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | 682 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) |
| 880 | { | 683 | { |
| 881 | struct sst_byt *byt; | 684 | struct sst_byt *byt; |
| 685 | struct sst_generic_ipc *ipc; | ||
| 882 | struct sst_fw *byt_sst_fw; | 686 | struct sst_fw *byt_sst_fw; |
| 883 | struct sst_byt_fw_init init; | 687 | struct sst_byt_fw_init init; |
| 884 | int err; | 688 | int err; |
| @@ -889,39 +693,30 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
| 889 | if (byt == NULL) | 693 | if (byt == NULL) |
| 890 | return -ENOMEM; | 694 | return -ENOMEM; |
| 891 | 695 | ||
| 892 | byt->dev = dev; | 696 | ipc = &byt->ipc; |
| 893 | INIT_LIST_HEAD(&byt->stream_list); | 697 | ipc->dev = dev; |
| 894 | INIT_LIST_HEAD(&byt->tx_list); | 698 | ipc->ops.tx_msg = byt_tx_msg; |
| 895 | INIT_LIST_HEAD(&byt->rx_list); | 699 | ipc->ops.shim_dbg = byt_shim_dbg; |
| 896 | INIT_LIST_HEAD(&byt->empty_list); | 700 | ipc->ops.tx_data_copy = byt_tx_data_copy; |
| 897 | init_waitqueue_head(&byt->boot_wait); | 701 | ipc->ops.reply_msg_match = byt_reply_msg_match; |
| 898 | init_waitqueue_head(&byt->wait_txq); | ||
| 899 | 702 | ||
| 900 | err = msg_empty_list_init(byt); | 703 | err = sst_ipc_init(ipc); |
| 901 | if (err < 0) | 704 | if (err != 0) |
| 902 | return -ENOMEM; | 705 | goto ipc_init_err; |
| 903 | |||
| 904 | /* start the IPC message thread */ | ||
| 905 | init_kthread_worker(&byt->kworker); | ||
| 906 | byt->tx_thread = kthread_run(kthread_worker_fn, | ||
| 907 | &byt->kworker, "%s", | ||
| 908 | dev_name(byt->dev)); | ||
| 909 | if (IS_ERR(byt->tx_thread)) { | ||
| 910 | err = PTR_ERR(byt->tx_thread); | ||
| 911 | dev_err(byt->dev, "error failed to create message TX task\n"); | ||
| 912 | goto err_free_msg; | ||
| 913 | } | ||
| 914 | init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs); | ||
| 915 | 706 | ||
| 707 | INIT_LIST_HEAD(&byt->stream_list); | ||
| 708 | init_waitqueue_head(&byt->boot_wait); | ||
| 916 | byt_dev.thread_context = byt; | 709 | byt_dev.thread_context = byt; |
| 917 | 710 | ||
| 918 | /* init SST shim */ | 711 | /* init SST shim */ |
| 919 | byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); | 712 | byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); |
| 920 | if (byt->dsp == NULL) { | 713 | if (byt->dsp == NULL) { |
| 921 | err = -ENODEV; | 714 | err = -ENODEV; |
| 922 | goto dsp_err; | 715 | goto dsp_new_err; |
| 923 | } | 716 | } |
| 924 | 717 | ||
| 718 | ipc->dsp = byt->dsp; | ||
| 719 | |||
| 925 | /* keep the DSP in reset state for base FW loading */ | 720 | /* keep the DSP in reset state for base FW loading */ |
| 926 | sst_dsp_reset(byt->dsp); | 721 | sst_dsp_reset(byt->dsp); |
| 927 | 722 | ||
| @@ -961,10 +756,10 @@ boot_err: | |||
| 961 | sst_fw_free(byt_sst_fw); | 756 | sst_fw_free(byt_sst_fw); |
| 962 | fw_err: | 757 | fw_err: |
| 963 | sst_dsp_free(byt->dsp); | 758 | sst_dsp_free(byt->dsp); |
| 964 | dsp_err: | 759 | dsp_new_err: |
| 965 | kthread_stop(byt->tx_thread); | 760 | sst_ipc_fini(ipc); |
| 966 | err_free_msg: | 761 | ipc_init_err: |
| 967 | kfree(byt->msg); | 762 | kfree(byt); |
| 968 | 763 | ||
| 969 | return err; | 764 | return err; |
| 970 | } | 765 | } |
| @@ -977,7 +772,6 @@ void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata) | |||
| 977 | sst_dsp_reset(byt->dsp); | 772 | sst_dsp_reset(byt->dsp); |
| 978 | sst_fw_free_all(byt->dsp); | 773 | sst_fw_free_all(byt->dsp); |
| 979 | sst_dsp_free(byt->dsp); | 774 | sst_dsp_free(byt->dsp); |
| 980 | kthread_stop(byt->tx_thread); | 775 | sst_ipc_fini(&byt->ipc); |
| 981 | kfree(byt->msg); | ||
| 982 | } | 776 | } |
| 983 | EXPORT_SYMBOL_GPL(sst_byt_dsp_free); | 777 | EXPORT_SYMBOL_GPL(sst_byt_dsp_free); |
