1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2009 by Martin Fuzzey
6 /* this file is part of imx21-hcd.c */
8 #ifdef CONFIG_DYNAMIC_DEBUG
14 static inline void create_debug_files(struct imx21
*imx21
) { }
15 static inline void remove_debug_files(struct imx21
*imx21
) { }
16 static inline void debug_urb_submitted(struct imx21
*imx21
, struct urb
*urb
) {}
17 static inline void debug_urb_completed(struct imx21
*imx21
, struct urb
*urb
,
19 static inline void debug_urb_unlinked(struct imx21
*imx21
, struct urb
*urb
) {}
20 static inline void debug_urb_queued_for_etd(struct imx21
*imx21
,
22 static inline void debug_urb_queued_for_dmem(struct imx21
*imx21
,
24 static inline void debug_etd_allocated(struct imx21
*imx21
) {}
25 static inline void debug_etd_freed(struct imx21
*imx21
) {}
26 static inline void debug_dmem_allocated(struct imx21
*imx21
, int size
) {}
27 static inline void debug_dmem_freed(struct imx21
*imx21
, int size
) {}
28 static inline void debug_isoc_submitted(struct imx21
*imx21
,
29 int frame
, struct td
*td
) {}
30 static inline void debug_isoc_completed(struct imx21
*imx21
,
31 int frame
, struct td
*td
, int cc
, int len
) {}
35 #include <linux/debugfs.h>
36 #include <linux/seq_file.h>
38 static const char *dir_labels
[] = {
45 static const char *speed_labels
[] = {
50 static const char *format_labels
[] = {
57 static inline struct debug_stats
*stats_for_urb(struct imx21
*imx21
,
60 return usb_pipeisoc(urb
->pipe
) ?
61 &imx21
->isoc_stats
: &imx21
->nonisoc_stats
;
64 static void debug_urb_submitted(struct imx21
*imx21
, struct urb
*urb
)
66 stats_for_urb(imx21
, urb
)->submitted
++;
69 static void debug_urb_completed(struct imx21
*imx21
, struct urb
*urb
, int st
)
72 stats_for_urb(imx21
, urb
)->completed_failed
++;
74 stats_for_urb(imx21
, urb
)->completed_ok
++;
77 static void debug_urb_unlinked(struct imx21
*imx21
, struct urb
*urb
)
79 stats_for_urb(imx21
, urb
)->unlinked
++;
82 static void debug_urb_queued_for_etd(struct imx21
*imx21
, struct urb
*urb
)
84 stats_for_urb(imx21
, urb
)->queue_etd
++;
87 static void debug_urb_queued_for_dmem(struct imx21
*imx21
, struct urb
*urb
)
89 stats_for_urb(imx21
, urb
)->queue_dmem
++;
92 static inline void debug_etd_allocated(struct imx21
*imx21
)
94 imx21
->etd_usage
.maximum
= max(
95 ++(imx21
->etd_usage
.value
),
96 imx21
->etd_usage
.maximum
);
99 static inline void debug_etd_freed(struct imx21
*imx21
)
101 imx21
->etd_usage
.value
--;
104 static inline void debug_dmem_allocated(struct imx21
*imx21
, int size
)
106 imx21
->dmem_usage
.value
+= size
;
107 imx21
->dmem_usage
.maximum
= max(
108 imx21
->dmem_usage
.value
,
109 imx21
->dmem_usage
.maximum
);
112 static inline void debug_dmem_freed(struct imx21
*imx21
, int size
)
114 imx21
->dmem_usage
.value
-= size
;
118 static void debug_isoc_submitted(struct imx21
*imx21
,
119 int frame
, struct td
*td
)
121 struct debug_isoc_trace
*trace
= &imx21
->isoc_trace
[
122 imx21
->isoc_trace_index
++];
124 imx21
->isoc_trace_index
%= ARRAY_SIZE(imx21
->isoc_trace
);
125 trace
->schedule_frame
= td
->frame
;
126 trace
->submit_frame
= frame
;
127 trace
->request_len
= td
->len
;
131 static inline void debug_isoc_completed(struct imx21
*imx21
,
132 int frame
, struct td
*td
, int cc
, int len
)
134 struct debug_isoc_trace
*trace
, *trace_failed
;
138 trace
= imx21
->isoc_trace
;
139 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace
); i
++, trace
++) {
140 if (trace
->td
== td
) {
141 trace
->done_frame
= frame
;
142 trace
->done_len
= len
;
151 trace_failed
= &imx21
->isoc_trace_failed
[
152 imx21
->isoc_trace_index_failed
++];
154 imx21
->isoc_trace_index_failed
%= ARRAY_SIZE(
155 imx21
->isoc_trace_failed
);
156 *trace_failed
= *trace
;
161 static char *format_ep(struct usb_host_endpoint
*ep
, char *buf
, int bufsize
)
164 snprintf(buf
, bufsize
, "ep_%02x (type:%02X kaddr:%p)",
165 ep
->desc
.bEndpointAddress
,
166 usb_endpoint_type(&ep
->desc
),
169 snprintf(buf
, bufsize
, "none");
173 static char *format_etd_dword0(u32 value
, char *buf
, int bufsize
)
175 snprintf(buf
, bufsize
,
176 "addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
178 (value
>> DW0_ENDPNT
) & 0x0F,
179 dir_labels
[(value
>> DW0_DIRECT
) & 0x03],
180 speed_labels
[(value
>> DW0_SPEED
) & 0x01],
181 format_labels
[(value
>> DW0_FORMAT
) & 0x03],
182 (value
>> DW0_HALTED
) & 0x01);
186 static int debug_status_show(struct seq_file
*s
, void *v
)
188 struct imx21
*imx21
= s
->private;
189 int etds_allocated
= 0;
190 int etds_sw_busy
= 0;
191 int etds_hw_busy
= 0;
193 int queued_for_etd
= 0;
194 int queued_for_dmem
= 0;
195 unsigned int dmem_bytes
= 0;
197 struct etd_priv
*etd
;
200 struct imx21_dmem_area
*dmem
;
201 struct ep_priv
*ep_priv
;
203 spin_lock_irqsave(&imx21
->lock
, flags
);
205 etd_enable_mask
= readl(imx21
->regs
+ USBH_ETDENSET
);
206 for (i
= 0, etd
= imx21
->etd
; i
< USB_NUM_ETD
; i
++, etd
++) {
211 if (etd_enable_mask
& (1<<i
))
215 list_for_each_entry(dmem
, &imx21
->dmem_list
, list
) {
216 dmem_bytes
+= dmem
->size
;
220 list_for_each_entry(ep_priv
, &imx21
->queue_for_etd
, queue
)
223 list_for_each_entry(etd
, &imx21
->queue_for_dmem
, queue
)
226 spin_unlock_irqrestore(&imx21
->lock
, flags
);
230 "ETDs allocated: %d/%d (max=%d)\n"
231 "ETDs in use sw: %d\n"
232 "ETDs in use hw: %d\n"
233 "DMEM allocated: %d/%d (max=%d)\n"
235 "Queued waiting for ETD: %d\n"
236 "Queued waiting for DMEM: %d\n",
237 readl(imx21
->regs
+ USBH_FRMNUB
) & 0xFFFF,
238 etds_allocated
, USB_NUM_ETD
, imx21
->etd_usage
.maximum
,
241 dmem_bytes
, DMEM_SIZE
, imx21
->dmem_usage
.maximum
,
249 static int debug_dmem_show(struct seq_file
*s
, void *v
)
251 struct imx21
*imx21
= s
->private;
252 struct imx21_dmem_area
*dmem
;
256 spin_lock_irqsave(&imx21
->lock
, flags
);
258 list_for_each_entry(dmem
, &imx21
->dmem_list
, list
)
262 dmem
->offset
, dmem
->size
,
263 format_ep(dmem
->ep
, ep_text
, sizeof(ep_text
)));
265 spin_unlock_irqrestore(&imx21
->lock
, flags
);
270 static int debug_etd_show(struct seq_file
*s
, void *v
)
272 struct imx21
*imx21
= s
->private;
273 struct etd_priv
*etd
;
279 spin_lock_irqsave(&imx21
->lock
, flags
);
281 for (i
= 0, etd
= imx21
->etd
; i
< USB_NUM_ETD
; i
++, etd
++) {
283 struct urb_priv
*urb_priv
;
285 urb_priv
= etd
->urb
->hcpriv
;
287 state
= urb_priv
->state
;
301 format_ep(etd
->ep
, buf
, sizeof(buf
)),
305 (readl(imx21
->regs
+ USBH_ETDENSET
) & (1 << i
)) > 0,
309 for (j
= 0; j
< 4; j
++) {
310 dword
= etd_readl(imx21
, i
, j
);
313 format_etd_dword0(dword
, buf
, sizeof(buf
));
316 snprintf(buf
, sizeof(buf
),
317 "cc=0X%02X", dword
>> DW2_COMPCODE
);
324 "dword %d: submitted=%08X cur=%08X [%s]\n",
326 etd
->submitted_dwords
[j
],
333 spin_unlock_irqrestore(&imx21
->lock
, flags
);
338 static void debug_statistics_show_one(struct seq_file
*s
,
339 const char *name
, struct debug_stats
*stats
)
341 seq_printf(s
, "%s:\n"
342 "submitted URBs: %lu\n"
343 "completed OK: %lu\n"
344 "completed failed: %lu\n"
346 "queued for ETD: %lu\n"
347 "queued for DMEM: %lu\n\n",
351 stats
->completed_failed
,
357 static int debug_statistics_show(struct seq_file
*s
, void *v
)
359 struct imx21
*imx21
= s
->private;
362 spin_lock_irqsave(&imx21
->lock
, flags
);
364 debug_statistics_show_one(s
, "nonisoc", &imx21
->nonisoc_stats
);
365 debug_statistics_show_one(s
, "isoc", &imx21
->isoc_stats
);
366 seq_printf(s
, "unblock kludge triggers: %lu\n", imx21
->debug_unblocks
);
367 spin_unlock_irqrestore(&imx21
->lock
, flags
);
372 static void debug_isoc_show_one(struct seq_file
*s
,
373 const char *name
, int index
, struct debug_isoc_trace
*trace
)
375 seq_printf(s
, "%s %d:\n"
377 "scheduled frame %d (%d)\n"
378 "submitted frame %d (%d)\n"
379 "completed frame %d (%d)\n"
380 "requested length=%d\n"
381 "completed length=%d\n\n",
384 trace
->schedule_frame
, trace
->schedule_frame
& 0xFFFF,
385 trace
->submit_frame
, trace
->submit_frame
& 0xFFFF,
386 trace
->done_frame
, trace
->done_frame
& 0xFFFF,
391 static int debug_isoc_show(struct seq_file
*s
, void *v
)
393 struct imx21
*imx21
= s
->private;
394 struct debug_isoc_trace
*trace
;
398 spin_lock_irqsave(&imx21
->lock
, flags
);
400 trace
= imx21
->isoc_trace_failed
;
401 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace_failed
); i
++, trace
++)
402 debug_isoc_show_one(s
, "isoc failed", i
, trace
);
404 trace
= imx21
->isoc_trace
;
405 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace
); i
++, trace
++)
406 debug_isoc_show_one(s
, "isoc", i
, trace
);
408 spin_unlock_irqrestore(&imx21
->lock
, flags
);
413 static int debug_status_open(struct inode
*inode
, struct file
*file
)
415 return single_open(file
, debug_status_show
, inode
->i_private
);
418 static int debug_dmem_open(struct inode
*inode
, struct file
*file
)
420 return single_open(file
, debug_dmem_show
, inode
->i_private
);
423 static int debug_etd_open(struct inode
*inode
, struct file
*file
)
425 return single_open(file
, debug_etd_show
, inode
->i_private
);
428 static int debug_statistics_open(struct inode
*inode
, struct file
*file
)
430 return single_open(file
, debug_statistics_show
, inode
->i_private
);
433 static int debug_isoc_open(struct inode
*inode
, struct file
*file
)
435 return single_open(file
, debug_isoc_show
, inode
->i_private
);
438 static const struct file_operations debug_status_fops
= {
439 .open
= debug_status_open
,
442 .release
= single_release
,
445 static const struct file_operations debug_dmem_fops
= {
446 .open
= debug_dmem_open
,
449 .release
= single_release
,
452 static const struct file_operations debug_etd_fops
= {
453 .open
= debug_etd_open
,
456 .release
= single_release
,
459 static const struct file_operations debug_statistics_fops
= {
460 .open
= debug_statistics_open
,
463 .release
= single_release
,
466 static const struct file_operations debug_isoc_fops
= {
467 .open
= debug_isoc_open
,
470 .release
= single_release
,
473 static void create_debug_files(struct imx21
*imx21
)
475 imx21
->debug_root
= debugfs_create_dir(dev_name(imx21
->dev
), NULL
);
476 if (!imx21
->debug_root
)
477 goto failed_create_rootdir
;
479 if (!debugfs_create_file("status", S_IRUGO
,
480 imx21
->debug_root
, imx21
, &debug_status_fops
))
483 if (!debugfs_create_file("dmem", S_IRUGO
,
484 imx21
->debug_root
, imx21
, &debug_dmem_fops
))
487 if (!debugfs_create_file("etd", S_IRUGO
,
488 imx21
->debug_root
, imx21
, &debug_etd_fops
))
491 if (!debugfs_create_file("statistics", S_IRUGO
,
492 imx21
->debug_root
, imx21
, &debug_statistics_fops
))
495 if (!debugfs_create_file("isoc", S_IRUGO
,
496 imx21
->debug_root
, imx21
, &debug_isoc_fops
))
502 debugfs_remove_recursive(imx21
->debug_root
);
504 failed_create_rootdir
:
505 imx21
->debug_root
= NULL
;
509 static void remove_debug_files(struct imx21
*imx21
)
511 if (imx21
->debug_root
) {
512 debugfs_remove_recursive(imx21
->debug_root
);
513 imx21
->debug_root
= NULL
;