Commit | Line | Data |
---|---|---|
e149ca29 | 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) |
d1d95fcb LG |
2 | // |
3 | // This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | // redistributing this file, you may do so under either license. | |
5 | // | |
293ad281 | 6 | // Copyright(c) 2018 Intel Corporation |
d1d95fcb LG |
7 | // |
8 | // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> | |
9 | // | |
10 | ||
11 | #include <linux/pci.h> | |
12 | #include "ops.h" | |
13 | ||
14 | static | |
15 | bool 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; | |
c41d384c | 20 | u32 ret = 0; |
d1d95fcb LG |
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 | ||
38 | bool 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 | } | |
49 | EXPORT_SYMBOL(snd_sof_pci_update_bits); | |
50 | ||
51 | bool 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 | } | |
69 | EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked); | |
70 | ||
71 | bool 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 | } | |
87 | EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked); | |
88 | ||
89 | /* This is for registers bits with attribute RWC */ | |
90 | bool 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 | } | |
102 | EXPORT_SYMBOL(snd_sof_dsp_update_bits); | |
103 | ||
104 | bool 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 | } | |
116 | EXPORT_SYMBOL(snd_sof_dsp_update_bits64); | |
117 | ||
118 | static | |
119 | void 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 */ | |
134 | void 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 | } | |
143 | EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); | |
144 | ||
b2b10aa7 PU |
145 | /** |
146 | * snd_sof_dsp_panic - handle a received DSP panic message | |
147 | * @sdev: Pointer to the device's sdev | |
148 | * @offset: offset of panic information | |
149 | * @non_recoverable: the panic is fatal, no recovery will be done by the caller | |
150 | */ | |
151 | void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverable) | |
d1d95fcb | 152 | { |
d1d95fcb | 153 | /* |
72b8ed83 PU |
154 | * if DSP is not ready and the dsp_oops_offset is not yet set, use the |
155 | * offset from the panic message. | |
d1d95fcb LG |
156 | */ |
157 | if (!sdev->dsp_oops_offset) | |
158 | sdev->dsp_oops_offset = offset; | |
72b8ed83 PU |
159 | |
160 | /* | |
161 | * Print warning if the offset from the panic message differs from | |
162 | * dsp_oops_offset | |
163 | */ | |
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 | ||
b2b10aa7 | 169 | /* |
fdc573b1 PU |
170 | * Set the fw_state to crashed only in case of non recoverable DSP panic |
171 | * event. | |
172 | * Use different message within the snd_sof_dsp_dbg_dump() depending on | |
173 | * the non_recoverable flag. | |
b2b10aa7 | 174 | */ |
fdc573b1 PU |
175 | sdev->dbg_dump_printed = false; |
176 | if (non_recoverable) { | |
2f148430 PU |
177 | snd_sof_dsp_dbg_dump(sdev, "DSP panic!", |
178 | SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); | |
fdc573b1 | 179 | sof_set_fw_state(sdev, SOF_FW_CRASHED); |
1dedbe4f | 180 | sof_fw_trace_fw_crashed(sdev); |
fdc573b1 PU |
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); | |
b2b10aa7 | 185 | } |
d1d95fcb LG |
186 | } |
187 | EXPORT_SYMBOL(snd_sof_dsp_panic); |