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