Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 //
0003 // Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
0004 //
0005 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
0006 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
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         /* consume the logs regardless of consumer presence */
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 /* reads log header and tests its type */
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     /* Dump the registers even if an external error prevents gathering the stack. */
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          * DSP awaits the remaining logs to be
0138          * gathered before dumping stack
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     /* gather the stack */
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         /* update read pointer */
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     /* Any gateway without buffer allocated in LP area disqualifies D0IX. */
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                 /* only copiers have gateway attributes */
0189                 if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
0190                     continue;
0191                 /* non-gateway copiers do not prevent PG */
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     /* wake in all cases */
0207     if (wake)
0208         return true;
0209 
0210     /*
0211      * If no pipelines are running, allow for d0ix schedule.
0212      * If all gateways have lp=1, allow for d0ix schedule.
0213      * If any gateway with lp=0 is allocated, abort scheduling d0ix.
0214      *
0215      * Note: for cAVS 1.5+ and 1.8, D0IX is LP-firmware transition,
0216      * not the power-gating mechanism known from cAVS 2.0.
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         /* Either idle or all gateways with lp=1. */
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 };