188 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)2//3// This file is provided under a dual BSD/GPLv2 license. When using or4// redistributing this file, you may do so under either license.5//6// Copyright(c) 2018 Intel Corporation7//8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>9//10 11#include <linux/pci.h>12#include "ops.h"13 14static15bool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset,16 u32 mask, u32 value)17{18 struct pci_dev *pci = to_pci_dev(sdev->dev);19 unsigned int old, new;20 u32 ret = 0;21 22 pci_read_config_dword(pci, offset, &ret);23 old = ret;24 dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", old & mask, offset);25 26 new = (old & ~mask) | (value & mask);27 28 if (old == new)29 return false;30 31 pci_write_config_dword(pci, offset, new);32 dev_dbg(sdev->dev, "Debug PCIW: %8.8x at %8.8x\n", value,33 offset);34 35 return true;36}37 38bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,39 u32 mask, u32 value)40{41 unsigned long flags;42 bool change;43 44 spin_lock_irqsave(&sdev->hw_lock, flags);45 change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value);46 spin_unlock_irqrestore(&sdev->hw_lock, flags);47 return change;48}49EXPORT_SYMBOL(snd_sof_pci_update_bits);50 51bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,52 u32 offset, u32 mask, u32 value)53{54 unsigned int old, new;55 u32 ret;56 57 ret = snd_sof_dsp_read(sdev, bar, offset);58 59 old = ret;60 new = (old & ~mask) | (value & mask);61 62 if (old == new)63 return false;64 65 snd_sof_dsp_write(sdev, bar, offset, new);66 67 return true;68}69EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked);70 71bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,72 u32 offset, u64 mask, u64 value)73{74 u64 old, new;75 76 old = snd_sof_dsp_read64(sdev, bar, offset);77 78 new = (old & ~mask) | (value & mask);79 80 if (old == new)81 return false;82 83 snd_sof_dsp_write64(sdev, bar, offset, new);84 85 return true;86}87EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked);88 89/* This is for registers bits with attribute RWC */90bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,91 u32 mask, u32 value)92{93 unsigned long flags;94 bool change;95 96 spin_lock_irqsave(&sdev->hw_lock, flags);97 change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask,98 value);99 spin_unlock_irqrestore(&sdev->hw_lock, flags);100 return change;101}102EXPORT_SYMBOL(snd_sof_dsp_update_bits);103 104bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset,105 u64 mask, u64 value)106{107 unsigned long flags;108 bool change;109 110 spin_lock_irqsave(&sdev->hw_lock, flags);111 change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask,112 value);113 spin_unlock_irqrestore(&sdev->hw_lock, flags);114 return change;115}116EXPORT_SYMBOL(snd_sof_dsp_update_bits64);117 118static119void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar,120 u32 offset, u32 mask, u32 value)121{122 unsigned int old, new;123 u32 ret;124 125 ret = snd_sof_dsp_read(sdev, bar, offset);126 127 old = ret;128 new = (old & ~mask) | (value & mask);129 130 snd_sof_dsp_write(sdev, bar, offset, new);131}132 133/* This is for registers bits with attribute RWC */134void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,135 u32 offset, u32 mask, u32 value)136{137 unsigned long flags;138 139 spin_lock_irqsave(&sdev->hw_lock, flags);140 snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value);141 spin_unlock_irqrestore(&sdev->hw_lock, flags);142}143EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced);144 145/**146 * snd_sof_dsp_panic - handle a received DSP panic message147 * @sdev: Pointer to the device's sdev148 * @offset: offset of panic information149 * @non_recoverable: the panic is fatal, no recovery will be done by the caller150 */151void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverable)152{153 /*154 * if DSP is not ready and the dsp_oops_offset is not yet set, use the155 * offset from the panic message.156 */157 if (!sdev->dsp_oops_offset)158 sdev->dsp_oops_offset = offset;159 160 /*161 * Print warning if the offset from the panic message differs from162 * dsp_oops_offset163 */164 if (sdev->dsp_oops_offset != offset)165 dev_warn(sdev->dev,166 "%s: dsp_oops_offset %zu differs from panic offset %u\n",167 __func__, sdev->dsp_oops_offset, offset);168 169 /*170 * Set the fw_state to crashed only in case of non recoverable DSP panic171 * event.172 * Use different message within the snd_sof_dsp_dbg_dump() depending on173 * the non_recoverable flag.174 */175 sdev->dbg_dump_printed = false;176 if (non_recoverable) {177 snd_sof_dsp_dbg_dump(sdev, "DSP panic!",178 SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);179 sof_set_fw_state(sdev, SOF_FW_CRASHED);180 sof_fw_trace_fw_crashed(sdev);181 } else {182 snd_sof_dsp_dbg_dump(sdev,183 "DSP panic (recovery will be attempted)",184 SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);185 }186}187EXPORT_SYMBOL(snd_sof_dsp_panic);188