Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
0002 //
0003 // This file is provided under a dual BSD/GPLv2 license.  When using or
0004 // redistributing this file, you may do so under either license.
0005 //
0006 // Copyright(c) 2018 Intel Corporation. All rights reserved.
0007 //
0008 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
0009 //
0010 
0011 #include <linux/pci.h>
0012 #include "ops.h"
0013 
0014 static
0015 bool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset,
0016                       u32 mask, u32 value)
0017 {
0018     struct pci_dev *pci = to_pci_dev(sdev->dev);
0019     unsigned int old, new;
0020     u32 ret = 0;
0021 
0022     pci_read_config_dword(pci, offset, &ret);
0023     old = ret;
0024     dev_dbg(sdev->dev, "Debug PCIR: %8.8x at  %8.8x\n", old & mask, offset);
0025 
0026     new = (old & ~mask) | (value & mask);
0027 
0028     if (old == new)
0029         return false;
0030 
0031     pci_write_config_dword(pci, offset, new);
0032     dev_dbg(sdev->dev, "Debug PCIW: %8.8x at  %8.8x\n", value,
0033         offset);
0034 
0035     return true;
0036 }
0037 
0038 bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
0039                  u32 mask, u32 value)
0040 {
0041     unsigned long flags;
0042     bool change;
0043 
0044     spin_lock_irqsave(&sdev->hw_lock, flags);
0045     change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value);
0046     spin_unlock_irqrestore(&sdev->hw_lock, flags);
0047     return change;
0048 }
0049 EXPORT_SYMBOL(snd_sof_pci_update_bits);
0050 
0051 bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
0052                       u32 offset, u32 mask, u32 value)
0053 {
0054     unsigned int old, new;
0055     u32 ret;
0056 
0057     ret = snd_sof_dsp_read(sdev, bar, offset);
0058 
0059     old = ret;
0060     new = (old & ~mask) | (value & mask);
0061 
0062     if (old == new)
0063         return false;
0064 
0065     snd_sof_dsp_write(sdev, bar, offset, new);
0066 
0067     return true;
0068 }
0069 EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked);
0070 
0071 bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,
0072                     u32 offset, u64 mask, u64 value)
0073 {
0074     u64 old, new;
0075 
0076     old = snd_sof_dsp_read64(sdev, bar, offset);
0077 
0078     new = (old & ~mask) | (value & mask);
0079 
0080     if (old == new)
0081         return false;
0082 
0083     snd_sof_dsp_write64(sdev, bar, offset, new);
0084 
0085     return true;
0086 }
0087 EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked);
0088 
0089 /* This is for registers bits with attribute RWC */
0090 bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,
0091                  u32 mask, u32 value)
0092 {
0093     unsigned long flags;
0094     bool change;
0095 
0096     spin_lock_irqsave(&sdev->hw_lock, flags);
0097     change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask,
0098                           value);
0099     spin_unlock_irqrestore(&sdev->hw_lock, flags);
0100     return change;
0101 }
0102 EXPORT_SYMBOL(snd_sof_dsp_update_bits);
0103 
0104 bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset,
0105                    u64 mask, u64 value)
0106 {
0107     unsigned long flags;
0108     bool change;
0109 
0110     spin_lock_irqsave(&sdev->hw_lock, flags);
0111     change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask,
0112                             value);
0113     spin_unlock_irqrestore(&sdev->hw_lock, flags);
0114     return change;
0115 }
0116 EXPORT_SYMBOL(snd_sof_dsp_update_bits64);
0117 
0118 static
0119 void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar,
0120                          u32 offset, u32 mask, u32 value)
0121 {
0122     unsigned int old, new;
0123     u32 ret;
0124 
0125     ret = snd_sof_dsp_read(sdev, bar, offset);
0126 
0127     old = ret;
0128     new = (old & ~mask) | (value & mask);
0129 
0130     snd_sof_dsp_write(sdev, bar, offset, new);
0131 }
0132 
0133 /* This is for registers bits with attribute RWC */
0134 void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
0135                     u32 offset, u32 mask, u32 value)
0136 {
0137     unsigned long flags;
0138 
0139     spin_lock_irqsave(&sdev->hw_lock, flags);
0140     snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value);
0141     spin_unlock_irqrestore(&sdev->hw_lock, flags);
0142 }
0143 EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced);
0144 
0145 /**
0146  * snd_sof_dsp_panic - handle a received DSP panic message
0147  * @sdev: Pointer to the device's sdev
0148  * @offset: offset of panic information
0149  * @non_recoverable: the panic is fatal, no recovery will be done by the caller
0150  */
0151 void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverable)
0152 {
0153     /*
0154      * if DSP is not ready and the dsp_oops_offset is not yet set, use the
0155      * offset from the panic message.
0156      */
0157     if (!sdev->dsp_oops_offset)
0158         sdev->dsp_oops_offset = offset;
0159 
0160     /*
0161      * Print warning if the offset from the panic message differs from
0162      * dsp_oops_offset
0163      */
0164     if (sdev->dsp_oops_offset != offset)
0165         dev_warn(sdev->dev,
0166              "%s: dsp_oops_offset %zu differs from panic offset %u\n",
0167              __func__, sdev->dsp_oops_offset, offset);
0168 
0169     /*
0170      * Set the fw_state to crashed only in case of non recoverable DSP panic
0171      * event.
0172      * Use different message within the snd_sof_dsp_dbg_dump() depending on
0173      * the non_recoverable flag.
0174      */
0175     sdev->dbg_dump_printed = false;
0176     if (non_recoverable) {
0177         snd_sof_dsp_dbg_dump(sdev, "DSP panic!",
0178                      SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
0179         sof_set_fw_state(sdev, SOF_FW_CRASHED);
0180         sof_fw_trace_fw_crashed(sdev);
0181     } else {
0182         snd_sof_dsp_dbg_dump(sdev,
0183                      "DSP panic (recovery will be attempted)",
0184                      SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
0185     }
0186 }
0187 EXPORT_SYMBOL(snd_sof_dsp_panic);