1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
3 // This file is provided under a dual BSD/GPLv2 license. When using or
4 // redistributing this file, you may do so under either license.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
11 #include <linux/firmware.h>
12 #include <linux/module.h>
13 #include <sound/soc.h>
14 #include <sound/sof.h>
18 #define CREATE_TRACE_POINTS
19 #include <trace/events/sof.h>
21 /* see SOF_DBG_ flags */
22 static int sof_core_debug
= IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE
);
23 module_param_named(sof_debug
, sof_core_debug
, int, 0444);
24 MODULE_PARM_DESC(sof_debug
, "SOF core debug options (0x0 all off)");
26 /* SOF defaults if not provided by the platform in ms */
27 #define TIMEOUT_DEFAULT_IPC_MS 500
28 #define TIMEOUT_DEFAULT_BOOT_MS 2000
31 * sof_debug_check_flag - check if a given flag(s) is set in sof_core_debug
32 * @mask: Flag or combination of flags to check
34 * Returns true if all bits set in mask is also set in sof_core_debug, otherwise
37 bool sof_debug_check_flag(int mask
)
39 if ((sof_core_debug
& mask
) == mask
)
44 EXPORT_SYMBOL(sof_debug_check_flag
);
47 * FW Panic/fault handling.
50 struct sof_panic_msg
{
55 /* standard FW panic types */
56 static const struct sof_panic_msg panic_msg
[] = {
57 {SOF_IPC_PANIC_MEM
, "out of memory"},
58 {SOF_IPC_PANIC_WORK
, "work subsystem init failed"},
59 {SOF_IPC_PANIC_IPC
, "IPC subsystem init failed"},
60 {SOF_IPC_PANIC_ARCH
, "arch init failed"},
61 {SOF_IPC_PANIC_PLATFORM
, "platform init failed"},
62 {SOF_IPC_PANIC_TASK
, "scheduler init failed"},
63 {SOF_IPC_PANIC_EXCEPTION
, "runtime exception"},
64 {SOF_IPC_PANIC_DEADLOCK
, "deadlock"},
65 {SOF_IPC_PANIC_STACK
, "stack overflow"},
66 {SOF_IPC_PANIC_IDLE
, "can't enter idle"},
67 {SOF_IPC_PANIC_WFI
, "invalid wait state"},
68 {SOF_IPC_PANIC_ASSERT
, "assertion failed"},
72 * sof_print_oops_and_stack - Handle the printing of DSP oops and stack trace
73 * @sdev: Pointer to the device's sdev
74 * @level: prink log level to use for the printing
75 * @panic_code: the panic code
76 * @tracep_code: tracepoint code
77 * @oops: Pointer to DSP specific oops data
78 * @panic_info: Pointer to the received panic information message
79 * @stack: Pointer to the call stack data
80 * @stack_words: Number of words in the stack data
82 * helper to be called from .dbg_dump callbacks. No error code is
83 * provided, it's left as an exercise for the caller of .dbg_dump
84 * (typically IPC or loader)
86 void sof_print_oops_and_stack(struct snd_sof_dev
*sdev
, const char *level
,
87 u32 panic_code
, u32 tracep_code
, void *oops
,
88 struct sof_ipc_panic_info
*panic_info
,
89 void *stack
, size_t stack_words
)
94 /* is firmware dead ? */
95 if ((panic_code
& SOF_IPC_PANIC_MAGIC_MASK
) != SOF_IPC_PANIC_MAGIC
) {
96 dev_printk(level
, sdev
->dev
, "unexpected fault %#010x trace %#010x\n",
97 panic_code
, tracep_code
);
98 return; /* no fault ? */
101 code
= panic_code
& (SOF_IPC_PANIC_MAGIC_MASK
| SOF_IPC_PANIC_CODE_MASK
);
103 for (i
= 0; i
< ARRAY_SIZE(panic_msg
); i
++) {
104 if (panic_msg
[i
].id
== code
) {
105 dev_printk(level
, sdev
->dev
, "reason: %s (%#x)\n",
106 panic_msg
[i
].msg
, code
& SOF_IPC_PANIC_CODE_MASK
);
107 dev_printk(level
, sdev
->dev
, "trace point: %#010x\n", tracep_code
);
113 dev_printk(level
, sdev
->dev
, "unknown panic code: %#x\n",
114 code
& SOF_IPC_PANIC_CODE_MASK
);
115 dev_printk(level
, sdev
->dev
, "trace point: %#010x\n", tracep_code
);
118 dev_printk(level
, sdev
->dev
, "panic at %s:%d\n", panic_info
->filename
,
119 panic_info
->linenum
);
120 sof_oops(sdev
, level
, oops
);
121 sof_stack(sdev
, level
, oops
, stack
, stack_words
);
123 EXPORT_SYMBOL(sof_print_oops_and_stack
);
125 /* Helper to manage DSP state */
126 void sof_set_fw_state(struct snd_sof_dev
*sdev
, enum sof_fw_state new_state
)
128 if (sdev
->fw_state
== new_state
)
131 dev_dbg(sdev
->dev
, "fw_state change: %d -> %d\n", sdev
->fw_state
, new_state
);
132 sdev
->fw_state
= new_state
;
135 case SOF_FW_BOOT_NOT_STARTED
:
136 case SOF_FW_BOOT_COMPLETE
:
138 sof_client_fw_state_dispatcher(sdev
);
144 EXPORT_SYMBOL(sof_set_fw_state
);
147 * FW Boot State Transition Diagram
149 * +----------------------------------------------------------------------+
151 * ------------------ ------------------ |
153 * | BOOT_FAILED |<-------| READY_FAILED | |
154 * | |<--+ | | ------------------ |
155 * ------------------ | ------------------ | | |
156 * ^ | ^ | CRASHED |---+ |
158 * (FW Boot Timeout) | (FW_READY FAIL) ------------------ | |
160 * | | | |(DSP Panic) | |
161 * ------------------ | | ------------------ | |
163 * | IN_PROGRESS |---------------+------------->| COMPLETE | | |
164 * | | (FW Boot OK) (FW_READY OK) | | | |
165 * ------------------ | ------------------ | |
168 * (FW Loading OK) | (System Suspend/Runtime Suspend)
170 * | (FW Loading Fail) | | |
171 * ------------------ | ------------------ | | |
172 * | | | | |<-----+ | |
173 * | PREPARE |---+ | NOT_STARTED |<---------------------+ |
174 * | | | |<--------------------------+
175 * ------------------ ------------------
178 * | +-----------------------+ |
182 * +------------------------------------+
183 * (System Suspend/Runtime Suspend)
186 static int sof_probe_continue(struct snd_sof_dev
*sdev
)
188 struct snd_sof_pdata
*plat_data
= sdev
->pdata
;
191 /* probe the DSP hardware */
192 ret
= snd_sof_probe(sdev
);
194 dev_err(sdev
->dev
, "error: failed to probe DSP %d\n", ret
);
198 sof_set_fw_state(sdev
, SOF_FW_BOOT_PREPARE
);
200 /* check machine info */
201 ret
= sof_machine_check(sdev
);
203 dev_err(sdev
->dev
, "error: failed to get machine info %d\n",
208 /* set up platform component driver */
209 snd_sof_new_platform_drv(sdev
);
211 if (sdev
->dspless_mode_selected
) {
212 sof_set_fw_state(sdev
, SOF_DSPLESS_MODE
);
216 /* register any debug/trace capabilities */
217 ret
= snd_sof_dbg_init(sdev
);
220 * debugfs issues are suppressed in snd_sof_dbg_init() since
221 * we cannot rely on debugfs
222 * here we trap errors due to memory allocation only.
224 dev_err(sdev
->dev
, "error: failed to init DSP trace/debug %d\n",
230 sdev
->ipc
= snd_sof_ipc_init(sdev
);
233 dev_err(sdev
->dev
, "error: failed to init DSP IPC %d\n", ret
);
237 /* load the firmware */
238 ret
= snd_sof_load_firmware(sdev
);
240 dev_err(sdev
->dev
, "error: failed to load DSP firmware %d\n",
242 sof_set_fw_state(sdev
, SOF_FW_BOOT_FAILED
);
246 sof_set_fw_state(sdev
, SOF_FW_BOOT_IN_PROGRESS
);
249 * Boot the firmware. The FW boot status will be modified
250 * in snd_sof_run_firmware() depending on the outcome.
252 ret
= snd_sof_run_firmware(sdev
);
254 dev_err(sdev
->dev
, "error: failed to boot DSP firmware %d\n",
256 sof_set_fw_state(sdev
, SOF_FW_BOOT_FAILED
);
260 if (sof_debug_check_flag(SOF_DBG_ENABLE_TRACE
)) {
261 sdev
->fw_trace_is_supported
= true;
263 /* init firmware tracing */
264 ret
= sof_fw_trace_init(sdev
);
267 dev_warn(sdev
->dev
, "failed to initialize firmware tracing %d\n",
271 dev_dbg(sdev
->dev
, "SOF firmware trace disabled\n");
275 /* hereafter all FW boot flows are for PM reasons */
276 sdev
->first_boot
= false;
278 /* now register audio DSP platform driver and dai */
279 ret
= devm_snd_soc_register_component(sdev
->dev
, &sdev
->plat_drv
,
281 sof_ops(sdev
)->num_drv
);
284 "error: failed to register DSP DAI driver %d\n", ret
);
288 ret
= snd_sof_machine_register(sdev
, plat_data
);
291 "error: failed to register machine driver %d\n", ret
);
295 ret
= sof_register_clients(sdev
);
297 dev_err(sdev
->dev
, "failed to register clients %d\n", ret
);
298 goto sof_machine_err
;
302 * Some platforms in SOF, ex: BYT, may not have their platform PM
303 * callbacks set. Increment the usage count so as to
304 * prevent the device from entering runtime suspend.
306 if (!sof_ops(sdev
)->runtime_suspend
|| !sof_ops(sdev
)->runtime_resume
)
307 pm_runtime_get_noresume(sdev
->dev
);
309 if (plat_data
->sof_probe_complete
)
310 plat_data
->sof_probe_complete(sdev
->dev
);
312 sdev
->probe_completed
= true;
317 snd_sof_machine_unregister(sdev
, plat_data
);
319 sof_fw_trace_free(sdev
);
321 snd_sof_fw_unload(sdev
);
323 snd_sof_ipc_free(sdev
);
326 snd_sof_free_debug(sdev
);
328 snd_sof_remove(sdev
);
332 /* all resources freed, update state to match */
333 sof_set_fw_state(sdev
, SOF_FW_BOOT_NOT_STARTED
);
334 sdev
->first_boot
= true;
339 static void sof_probe_work(struct work_struct
*work
)
341 struct snd_sof_dev
*sdev
=
342 container_of(work
, struct snd_sof_dev
, probe_work
);
345 ret
= sof_probe_continue(sdev
);
347 /* errors cannot be propagated, log */
348 dev_err(sdev
->dev
, "error: %s failed err: %d\n", __func__
, ret
);
352 int snd_sof_device_probe(struct device
*dev
, struct snd_sof_pdata
*plat_data
)
354 struct snd_sof_dev
*sdev
;
357 sdev
= devm_kzalloc(dev
, sizeof(*sdev
), GFP_KERNEL
);
361 /* initialize sof device */
364 /* initialize default DSP power state */
365 sdev
->dsp_power_state
.state
= SOF_DSP_PM_D0
;
367 sdev
->pdata
= plat_data
;
368 sdev
->first_boot
= true;
369 dev_set_drvdata(dev
, sdev
);
372 dev_info(dev
, "sof_debug value: %#x\n", sof_core_debug
);
374 if (sof_debug_check_flag(SOF_DBG_DSPLESS_MODE
)) {
375 if (plat_data
->desc
->dspless_mode_supported
) {
376 dev_info(dev
, "Switching to DSPless mode\n");
377 sdev
->dspless_mode_selected
= true;
379 dev_info(dev
, "DSPless mode is not supported by the platform\n");
383 /* check IPC support */
384 if (!(BIT(plat_data
->ipc_type
) & plat_data
->desc
->ipc_supported_mask
)) {
385 dev_err(dev
, "ipc_type %d is not supported on this platform, mask is %#x\n",
386 plat_data
->ipc_type
, plat_data
->desc
->ipc_supported_mask
);
390 /* init ops, if necessary */
391 ret
= sof_ops_init(sdev
);
395 /* check all mandatory ops */
396 if (!sof_ops(sdev
) || !sof_ops(sdev
)->probe
) {
398 dev_err(dev
, "missing mandatory ops\n");
402 if (!sdev
->dspless_mode_selected
&&
403 (!sof_ops(sdev
)->run
|| !sof_ops(sdev
)->block_read
||
404 !sof_ops(sdev
)->block_write
|| !sof_ops(sdev
)->send_msg
||
405 !sof_ops(sdev
)->load_firmware
|| !sof_ops(sdev
)->ipc_msg_data
)) {
407 dev_err(dev
, "missing mandatory DSP ops\n");
411 INIT_LIST_HEAD(&sdev
->pcm_list
);
412 INIT_LIST_HEAD(&sdev
->kcontrol_list
);
413 INIT_LIST_HEAD(&sdev
->widget_list
);
414 INIT_LIST_HEAD(&sdev
->pipeline_list
);
415 INIT_LIST_HEAD(&sdev
->dai_list
);
416 INIT_LIST_HEAD(&sdev
->dai_link_list
);
417 INIT_LIST_HEAD(&sdev
->route_list
);
418 INIT_LIST_HEAD(&sdev
->ipc_client_list
);
419 INIT_LIST_HEAD(&sdev
->ipc_rx_handler_list
);
420 INIT_LIST_HEAD(&sdev
->fw_state_handler_list
);
421 spin_lock_init(&sdev
->ipc_lock
);
422 spin_lock_init(&sdev
->hw_lock
);
423 mutex_init(&sdev
->power_state_access
);
424 mutex_init(&sdev
->ipc_client_mutex
);
425 mutex_init(&sdev
->client_event_handler_mutex
);
427 /* set default timeouts if none provided */
428 if (plat_data
->desc
->ipc_timeout
== 0)
429 sdev
->ipc_timeout
= TIMEOUT_DEFAULT_IPC_MS
;
431 sdev
->ipc_timeout
= plat_data
->desc
->ipc_timeout
;
432 if (plat_data
->desc
->boot_timeout
== 0)
433 sdev
->boot_timeout
= TIMEOUT_DEFAULT_BOOT_MS
;
435 sdev
->boot_timeout
= plat_data
->desc
->boot_timeout
;
437 sof_set_fw_state(sdev
, SOF_FW_BOOT_NOT_STARTED
);
439 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE
)) {
440 INIT_WORK(&sdev
->probe_work
, sof_probe_work
);
441 schedule_work(&sdev
->probe_work
);
445 return sof_probe_continue(sdev
);
447 EXPORT_SYMBOL(snd_sof_device_probe
);
449 bool snd_sof_device_probe_completed(struct device
*dev
)
451 struct snd_sof_dev
*sdev
= dev_get_drvdata(dev
);
453 return sdev
->probe_completed
;
455 EXPORT_SYMBOL(snd_sof_device_probe_completed
);
457 int snd_sof_device_remove(struct device
*dev
)
459 struct snd_sof_dev
*sdev
= dev_get_drvdata(dev
);
460 struct snd_sof_pdata
*pdata
= sdev
->pdata
;
463 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE
))
464 cancel_work_sync(&sdev
->probe_work
);
467 * Unregister any registered client device first before IPC and debugfs
468 * to allow client drivers to be removed cleanly
470 sof_unregister_clients(sdev
);
473 * Unregister machine driver. This will unbind the snd_card which
474 * will remove the component driver and unload the topology
475 * before freeing the snd_card.
477 snd_sof_machine_unregister(sdev
, pdata
);
479 if (sdev
->fw_state
> SOF_FW_BOOT_NOT_STARTED
) {
480 sof_fw_trace_free(sdev
);
481 ret
= snd_sof_dsp_power_down_notify(sdev
);
483 dev_warn(dev
, "error: %d failed to prepare DSP for device removal",
486 snd_sof_ipc_free(sdev
);
487 snd_sof_free_debug(sdev
);
488 snd_sof_remove(sdev
);
493 /* release firmware */
494 snd_sof_fw_unload(sdev
);
498 EXPORT_SYMBOL(snd_sof_device_remove
);
500 int snd_sof_device_shutdown(struct device
*dev
)
502 struct snd_sof_dev
*sdev
= dev_get_drvdata(dev
);
504 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE
))
505 cancel_work_sync(&sdev
->probe_work
);
507 if (sdev
->fw_state
== SOF_FW_BOOT_COMPLETE
) {
508 sof_fw_trace_free(sdev
);
509 return snd_sof_shutdown(sdev
);
514 EXPORT_SYMBOL(snd_sof_device_shutdown
);
516 MODULE_AUTHOR("Liam Girdwood");
517 MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
518 MODULE_LICENSE("Dual BSD/GPL");
519 MODULE_ALIAS("platform:sof-audio");
520 MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT
);