blob: 898a08b481ed5e0c85908659c96c949a7d094df5 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * Copyright (C) 2016 Red Hat
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors:
23 * Rob Clark <robdclark@gmail.com>
24 */
25
26#define DEBUG /* for pr_debug() */
27
28#include <stdarg.h>
29
30#include <linux/io.h>
31#include <linux/seq_file.h>
32#include <linux/slab.h>
33
34#include <drm/drm.h>
35#include <drm/drm_drv.h>
36#include <drm/drm_print.h>
37
38void __drm_puts_coredump(struct drm_printer *p, const char *str)
39{
40 struct drm_print_iterator *iterator = p->arg;
41 ssize_t len;
42
43 if (!iterator->remain)
44 return;
45
46 if (iterator->offset < iterator->start) {
47 ssize_t copy;
48
49 len = strlen(str);
50
51 if (iterator->offset + len <= iterator->start) {
52 iterator->offset += len;
53 return;
54 }
55
56 copy = len - (iterator->start - iterator->offset);
57
58 if (copy > iterator->remain)
59 copy = iterator->remain;
60
61 /* Copy out the bit of the string that we need */
62 if (iterator->data)
63 memcpy(iterator->data,
64 str + (iterator->start - iterator->offset), copy);
65
66 iterator->offset = iterator->start + copy;
67 iterator->remain -= copy;
68 } else {
69 ssize_t pos = iterator->offset - iterator->start;
70
71 len = min_t(ssize_t, strlen(str), iterator->remain);
72
73 if (iterator->data)
74 memcpy(iterator->data + pos, str, len);
75
76 iterator->offset += len;
77 iterator->remain -= len;
78 }
79}
80EXPORT_SYMBOL(__drm_puts_coredump);
81
82void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf)
83{
84 struct drm_print_iterator *iterator = p->arg;
85 size_t len;
86 char *buf;
87
88 if (!iterator->remain)
89 return;
90
91 /* Figure out how big the string will be */
92 len = snprintf(NULL, 0, "%pV", vaf);
93
94 /* This is the easiest path, we've already advanced beyond the offset */
95 if (iterator->offset + len <= iterator->start) {
96 iterator->offset += len;
97 return;
98 }
99
100 /* Then check if we can directly copy into the target buffer */
101 if ((iterator->offset >= iterator->start) && (len < iterator->remain)) {
102 ssize_t pos = iterator->offset - iterator->start;
103
104 if (iterator->data)
105 snprintf(((char *) iterator->data) + pos,
106 iterator->remain, "%pV", vaf);
107
108 iterator->offset += len;
109 iterator->remain -= len;
110
111 return;
112 }
113
114 /*
115 * Finally, hit the slow path and make a temporary string to copy over
116 * using _drm_puts_coredump
117 */
118 buf = kmalloc(len + 1, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
119 if (!buf)
120 return;
121
122 snprintf(buf, len + 1, "%pV", vaf);
123 __drm_puts_coredump(p, (const char *) buf);
124
125 kfree(buf);
126}
127EXPORT_SYMBOL(__drm_printfn_coredump);
128
129void __drm_puts_seq_file(struct drm_printer *p, const char *str)
130{
131 seq_puts(p->arg, str);
132}
133EXPORT_SYMBOL(__drm_puts_seq_file);
134
135void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf)
136{
137 seq_printf(p->arg, "%pV", vaf);
138}
139EXPORT_SYMBOL(__drm_printfn_seq_file);
140
141void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf)
142{
143 dev_info(p->arg, "[" DRM_NAME "] %pV", vaf);
144}
145EXPORT_SYMBOL(__drm_printfn_info);
146
147void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf)
148{
149 pr_debug("%s %pV", p->prefix, vaf);
150}
151EXPORT_SYMBOL(__drm_printfn_debug);
152
153/**
154 * drm_puts - print a const string to a &drm_printer stream
155 * @p: the &drm printer
156 * @str: const string
157 *
158 * Allow &drm_printer types that have a constant string
159 * option to use it.
160 */
161void drm_puts(struct drm_printer *p, const char *str)
162{
163 if (p->puts)
164 p->puts(p, str);
165 else
166 drm_printf(p, "%s", str);
167}
168EXPORT_SYMBOL(drm_puts);
169
170/**
171 * drm_printf - print to a &drm_printer stream
172 * @p: the &drm_printer
173 * @f: format string
174 */
175void drm_printf(struct drm_printer *p, const char *f, ...)
176{
177 va_list args;
178
179 va_start(args, f);
180 drm_vprintf(p, f, &args);
181 va_end(args);
182}
183EXPORT_SYMBOL(drm_printf);
184
185void drm_dev_printk(const struct device *dev, const char *level,
186 const char *format, ...)
187{
188 struct va_format vaf;
189 va_list args;
190
191 va_start(args, format);
192 vaf.fmt = format;
193 vaf.va = &args;
194
195 if (dev)
196 dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV",
197 __builtin_return_address(0), &vaf);
198 else
199 printk("%s" "[" DRM_NAME ":%ps] %pV",
200 level, __builtin_return_address(0), &vaf);
201
202 va_end(args);
203}
204EXPORT_SYMBOL(drm_dev_printk);
205
206void drm_dev_dbg(const struct device *dev, unsigned int category,
207 const char *format, ...)
208{
209 struct va_format vaf;
210 va_list args;
211
212 if (!(drm_debug & category))
213 return;
214
215 va_start(args, format);
216 vaf.fmt = format;
217 vaf.va = &args;
218
219 if (dev)
220 dev_printk(KERN_DEBUG, dev, "[" DRM_NAME ":%ps] %pV",
221 __builtin_return_address(0), &vaf);
222 else
223 printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
224 __builtin_return_address(0), &vaf);
225
226 va_end(args);
227}
228EXPORT_SYMBOL(drm_dev_dbg);
229
230void drm_dbg(unsigned int category, const char *format, ...)
231{
232 struct va_format vaf;
233 va_list args;
234
235 if (!(drm_debug & category))
236 return;
237
238 va_start(args, format);
239 vaf.fmt = format;
240 vaf.va = &args;
241
242 printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
243 __builtin_return_address(0), &vaf);
244
245 va_end(args);
246}
247EXPORT_SYMBOL(drm_dbg);
248
249void drm_err(const char *format, ...)
250{
251 struct va_format vaf;
252 va_list args;
253
254 va_start(args, format);
255 vaf.fmt = format;
256 vaf.va = &args;
257
258 printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
259 __builtin_return_address(0), &vaf);
260
261 va_end(args);
262}
263EXPORT_SYMBOL(drm_err);
264
265/**
266 * drm_print_regset32 - print the contents of registers to a
267 * &drm_printer stream.
268 *
269 * @p: the &drm printer
270 * @regset: the list of registers to print.
271 *
272 * Often in driver debug, it's useful to be able to either capture the
273 * contents of registers in the steady state using debugfs or at
274 * specific points during operation. This lets the driver have a
275 * single list of registers for both.
276 */
277void drm_print_regset32(struct drm_printer *p, struct debugfs_regset32 *regset)
278{
279 int namelen = 0;
280 int i;
281
282 for (i = 0; i < regset->nregs; i++)
283 namelen = max(namelen, (int)strlen(regset->regs[i].name));
284
285 for (i = 0; i < regset->nregs; i++) {
286 drm_printf(p, "%*s = 0x%08x\n",
287 namelen, regset->regs[i].name,
288 readl(regset->base + regset->regs[i].offset));
289 }
290}
291EXPORT_SYMBOL(drm_print_regset32);