0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/devcoredump.h>
0010 #include <linux/slab.h>
0011 #include "avs.h"
0012 #include "messages.h"
0013 #include "path.h"
0014 #include "topology.h"
0015
0016 static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
0017 u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
0018 {
0019 struct apl_log_state_info *info;
0020 u32 size, num_cores = adev->hw_cfg.dsp_cores;
0021 int ret, i;
0022
0023 if (fls_long(resource_mask) > num_cores)
0024 return -EINVAL;
0025 size = struct_size(info, logs_core, num_cores);
0026 info = kzalloc(size, GFP_KERNEL);
0027 if (!info)
0028 return -ENOMEM;
0029
0030 info->aging_timer_period = aging_period;
0031 info->fifo_full_timer_period = fifo_full_period;
0032 info->core_mask = resource_mask;
0033 if (enable)
0034 for_each_set_bit(i, &resource_mask, num_cores) {
0035 info->logs_core[i].enable = enable;
0036 info->logs_core[i].min_priority = *priorities++;
0037 }
0038 else
0039 for_each_set_bit(i, &resource_mask, num_cores)
0040 info->logs_core[i].enable = enable;
0041
0042 ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
0043 kfree(info);
0044 if (ret)
0045 return AVS_IPC_RET(ret);
0046
0047 return 0;
0048 }
0049
0050 static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
0051 {
0052 struct apl_log_buffer_layout layout;
0053 unsigned long flags;
0054 void __iomem *addr, *buf;
0055
0056 addr = avs_log_buffer_addr(adev, msg->log.core);
0057 if (!addr)
0058 return -ENXIO;
0059
0060 memcpy_fromio(&layout, addr, sizeof(layout));
0061
0062 spin_lock_irqsave(&adev->dbg.trace_lock, flags);
0063 if (!kfifo_initialized(&adev->dbg.trace_fifo))
0064
0065 goto update_read_ptr;
0066
0067 buf = apl_log_payload_addr(addr);
0068
0069 if (layout.read_ptr > layout.write_ptr) {
0070 __kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
0071 apl_log_payload_size(adev) - layout.read_ptr,
0072 &adev->dbg.fifo_lock);
0073 layout.read_ptr = 0;
0074 }
0075 __kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
0076 layout.write_ptr - layout.read_ptr, &adev->dbg.fifo_lock);
0077
0078 wake_up(&adev->dbg.trace_waitq);
0079
0080 update_read_ptr:
0081 spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
0082 writel(layout.write_ptr, addr);
0083 return 0;
0084 }
0085
0086 static int apl_wait_log_entry(struct avs_dev *adev, u32 core, struct apl_log_buffer_layout *layout)
0087 {
0088 unsigned long timeout;
0089 void __iomem *addr;
0090
0091 addr = avs_log_buffer_addr(adev, core);
0092 if (!addr)
0093 return -ENXIO;
0094
0095 timeout = jiffies + msecs_to_jiffies(10);
0096
0097 do {
0098 memcpy_fromio(layout, addr, sizeof(*layout));
0099 if (layout->read_ptr != layout->write_ptr)
0100 return 0;
0101 usleep_range(500, 1000);
0102 } while (!time_after(jiffies, timeout));
0103
0104 return -ETIMEDOUT;
0105 }
0106
0107
0108 #define apl_is_entry_stackdump(addr) ((readl(addr) >> 30) & 0x1)
0109
0110 static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
0111 {
0112 struct apl_log_buffer_layout layout;
0113 void __iomem *addr, *buf;
0114 size_t dump_size;
0115 u16 offset = 0;
0116 u8 *dump, *pos;
0117
0118 dump_size = AVS_FW_REGS_SIZE + msg->ext.coredump.stack_dump_size;
0119 dump = vzalloc(dump_size);
0120 if (!dump)
0121 return -ENOMEM;
0122
0123 memcpy_fromio(dump, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE);
0124
0125 if (!msg->ext.coredump.stack_dump_size)
0126 goto exit;
0127
0128
0129 addr = avs_log_buffer_addr(adev, msg->ext.coredump.core_id);
0130 if (!addr)
0131 goto exit;
0132
0133 buf = apl_log_payload_addr(addr);
0134 memcpy_fromio(&layout, addr, sizeof(layout));
0135 if (!apl_is_entry_stackdump(buf + layout.read_ptr)) {
0136
0137
0138
0139
0140 msg->log.core = msg->ext.coredump.core_id;
0141 avs_dsp_op(adev, log_buffer_status, msg);
0142 }
0143
0144 pos = dump + AVS_FW_REGS_SIZE;
0145
0146 do {
0147 u32 count;
0148
0149 if (apl_wait_log_entry(adev, msg->ext.coredump.core_id, &layout))
0150 break;
0151
0152 if (layout.read_ptr > layout.write_ptr) {
0153 count = apl_log_payload_size(adev) - layout.read_ptr;
0154 memcpy_fromio(pos + offset, buf + layout.read_ptr, count);
0155 layout.read_ptr = 0;
0156 offset += count;
0157 }
0158 count = layout.write_ptr - layout.read_ptr;
0159 memcpy_fromio(pos + offset, buf + layout.read_ptr, count);
0160 offset += count;
0161
0162
0163 writel(layout.write_ptr, addr);
0164 } while (offset < msg->ext.coredump.stack_dump_size);
0165
0166 exit:
0167 dev_coredumpv(adev->dev, dump, dump_size, GFP_KERNEL);
0168
0169 return 0;
0170 }
0171
0172 static bool apl_lp_streaming(struct avs_dev *adev)
0173 {
0174 struct avs_path *path;
0175
0176
0177 list_for_each_entry(path, &adev->path_list, node) {
0178 struct avs_path_pipeline *ppl;
0179
0180 list_for_each_entry(ppl, &path->ppl_list, node) {
0181 struct avs_path_module *mod;
0182
0183 list_for_each_entry(mod, &ppl->mod_list, node) {
0184 struct avs_tplg_modcfg_ext *cfg;
0185
0186 cfg = mod->template->cfg_ext;
0187
0188
0189 if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
0190 continue;
0191
0192 if (cfg->copier.dma_type == INVALID_OBJECT_ID)
0193 continue;
0194
0195 if (!mod->gtw_attrs.lp_buffer_alloc)
0196 return false;
0197 }
0198 }
0199 }
0200
0201 return true;
0202 }
0203
0204 static bool apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
0205 {
0206
0207 if (wake)
0208 return true;
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 return apl_lp_streaming(adev);
0219 }
0220
0221 static int apl_set_d0ix(struct avs_dev *adev, bool enable)
0222 {
0223 bool streaming = false;
0224 int ret;
0225
0226 if (enable)
0227
0228 streaming = !list_empty(&adev->path_list);
0229
0230 ret = avs_ipc_set_d0ix(adev, enable, streaming);
0231 return AVS_IPC_RET(ret);
0232 }
0233
0234 const struct avs_dsp_ops apl_dsp_ops = {
0235 .power = avs_dsp_core_power,
0236 .reset = avs_dsp_core_reset,
0237 .stall = avs_dsp_core_stall,
0238 .irq_handler = avs_dsp_irq_handler,
0239 .irq_thread = avs_dsp_irq_thread,
0240 .int_control = avs_dsp_interrupt_control,
0241 .load_basefw = avs_hda_load_basefw,
0242 .load_lib = avs_hda_load_library,
0243 .transfer_mods = avs_hda_transfer_modules,
0244 .enable_logs = apl_enable_logs,
0245 .log_buffer_offset = skl_log_buffer_offset,
0246 .log_buffer_status = apl_log_buffer_status,
0247 .coredump = apl_coredump,
0248 .d0ix_toggle = apl_d0ix_toggle,
0249 .set_d0ix = apl_set_d0ix,
0250 };