diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index 9096f6c3d598..263ceb39d25d 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,10 @@ struct avs_dsp_ops { int (* const load_basefw)(struct avs_dev *, struct firmware *); int (* const load_lib)(struct avs_dev *, struct firmware *, u32); int (* const transfer_mods)(struct avs_dev *, bool, struct avs_module_entry *, u32); + int (* const enable_logs)(struct avs_dev *, enum avs_log_enable, u32, u32, unsigned long, + u32 *); + int (* const log_buffer_offset)(struct avs_dev *, u32); + int (* const log_buffer_status)(struct avs_dev *, union avs_notify_msg *); int (* const coredump)(struct avs_dev *, union avs_notify_msg *); }; @@ -75,6 +80,16 @@ struct avs_fw_entry { struct list_head node; }; +struct avs_debug { + struct kfifo trace_fifo; + spinlock_t fifo_lock; /* serialize I/O for trace_fifo */ + spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */ + wait_queue_head_t trace_waitq; + u32 aging_timer_period; + u32 fifo_full_timer_period; + u32 logged_resources; /* context dependent: core or library */ +}; + /* * struct avs_dev - Intel HD-Audio driver data * @@ -115,6 +130,8 @@ struct avs_dev { struct list_head path_list; spinlock_t path_list_lock; struct mutex path_mutex; + + struct avs_debug dbg; }; /* from hda_bus to avs_dev */ @@ -279,4 +296,19 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l unsigned long *tdms); int avs_hda_platform_register(struct avs_dev *adev, const char *name); +/* Firmware tracing helpers */ + +unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len, + spinlock_t *lock); + +#define avs_log_buffer_size(adev) \ + ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores) + +#define avs_log_buffer_addr(adev, core) \ +({ \ + s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \ + (__offset < 0) ? NULL : \ + (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \ +}) + #endif /* __SOUND_SOC_INTEL_AVS_H */ diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index 98cdc05071fb..feb900ba1db9 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -140,6 +140,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header) data_size = sizeof(struct avs_notify_res_data); break; + case AVS_NOTIFY_LOG_BUFFER_STATUS: case AVS_NOTIFY_EXCEPTION_CAUGHT: break; @@ -170,6 +171,10 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header) complete(&adev->fw_ready); break; + case AVS_NOTIFY_LOG_BUFFER_STATUS: + avs_dsp_op(adev, log_buffer_status, &msg); + break; + case AVS_NOTIFY_EXCEPTION_CAUGHT: avs_dsp_exception_caught(adev, &msg); break; diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c index 004da166a943..3da33150aabf 100644 --- a/sound/soc/intel/avs/messages.c +++ b/sound/soc/intel/avs/messages.c @@ -677,6 +677,37 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info) return 0; } +int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size) +{ + int ret; + + ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, + AVS_BASEFW_ENABLE_LOGS, log_info, size); + if (ret) + dev_err(adev->dev, "enable logs failed: %d\n", ret); + + return ret; +} + +int avs_ipc_set_system_time(struct avs_dev *adev) +{ + struct avs_sys_time sys_time; + int ret; + u64 us; + + /* firmware expects UTC time in micro seconds */ + us = ktime_to_us(ktime_get()); + sys_time.val_l = us & UINT_MAX; + sys_time.val_u = us >> 32; + + ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, + AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time)); + if (ret) + dev_err(adev->dev, "set system time failed: %d\n", ret); + + return ret; +} + int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, u8 instance_id, u32 sink_id, const struct avs_audio_format *src_fmt, diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h index 94875a153124..257482e160bc 100644 --- a/sound/soc/intel/avs/messages.h +++ b/sound/soc/intel/avs/messages.h @@ -186,6 +186,7 @@ union avs_reply_msg { enum avs_notify_msg_type { AVS_NOTIFY_PHRASE_DETECTED = 4, AVS_NOTIFY_RESOURCE_EVENT = 5, + AVS_NOTIFY_LOG_BUFFER_STATUS = 6, AVS_NOTIFY_FW_READY = 8, AVS_NOTIFY_EXCEPTION_CAUGHT = 10, AVS_NOTIFY_MODULE_EVENT = 12, @@ -203,6 +204,10 @@ union avs_notify_msg { u32 msg_direction:1; u32 msg_target:1; }; + struct { + u16 rsvd:12; + u16 core:4; + } log; }; union { u32 val; @@ -329,12 +334,21 @@ int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming); #define AVS_BASEFW_INST_ID 0 enum avs_basefw_runtime_param { + AVS_BASEFW_ENABLE_LOGS = 6, AVS_BASEFW_FIRMWARE_CONFIG = 7, AVS_BASEFW_HARDWARE_CONFIG = 8, AVS_BASEFW_MODULES_INFO = 9, AVS_BASEFW_LIBRARIES_INFO = 16, + AVS_BASEFW_SYSTEM_TIME = 20, }; +enum avs_log_enable { + AVS_LOG_DISABLE = 0, + AVS_LOG_ENABLE = 1 +}; + +int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size); + struct avs_fw_version { u16 major; u16 minor; @@ -502,6 +516,13 @@ static inline bool avs_module_entry_is_loaded(struct avs_module_entry *mentry) int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info); +struct avs_sys_time { + u32 val_l; + u32 val_u; +} __packed; + +int avs_ipc_set_system_time(struct avs_dev *adev); + /* Module configuration */ #define AVS_MIXIN_MOD_UUID \ diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h index 3fd02389ed2b..f951d3441cdf 100644 --- a/sound/soc/intel/avs/registers.h +++ b/sound/soc/intel/avs/registers.h @@ -58,6 +58,7 @@ #define AVS_UPLINK_WINDOW AVS_FW_REGS_WINDOW /* HOST -> DSP communication window */ #define AVS_DOWNLINK_WINDOW 1 +#define AVS_DEBUG_WINDOW 2 /* registry I/O helpers */ #define avs_sram_offset(adev, window_idx) \ diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c index 6473e3ae4c6e..13611dee9787 100644 --- a/sound/soc/intel/avs/utils.c +++ b/sound/soc/intel/avs/utils.c @@ -7,6 +7,7 @@ // #include +#include #include #include "avs.h" #include "messages.h" @@ -299,3 +300,25 @@ void avs_release_firmwares(struct avs_dev *adev) kfree(entry); } } + +unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len, + spinlock_t *lock) +{ + struct __kfifo *__fifo = &fifo->kfifo; + unsigned long flags; + unsigned int l, off; + + spin_lock_irqsave(lock, flags); + len = min(len, kfifo_avail(fifo)); + off = __fifo->in & __fifo->mask; + l = min(len, kfifo_size(fifo) - off); + + memcpy_fromio(__fifo->data + off, src, l); + memcpy_fromio(__fifo->data, src + l, len - l); + /* Make sure data copied from SRAM is visible to all CPUs. */ + smp_mb(); + __fifo->in += len; + spin_unlock_irqrestore(lock, flags); + + return len; +}