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
,
248 DEFINE_SHOW_ATTRIBUTE(debug_status
);
250 static int debug_dmem_show(struct seq_file
*s
, void *v
)
252 struct imx21
*imx21
= s
->private;
253 struct imx21_dmem_area
*dmem
;
257 spin_lock_irqsave(&imx21
->lock
, flags
);
259 list_for_each_entry(dmem
, &imx21
->dmem_list
, list
)
263 dmem
->offset
, dmem
->size
,
264 format_ep(dmem
->ep
, ep_text
, sizeof(ep_text
)));
266 spin_unlock_irqrestore(&imx21
->lock
, flags
);
270 DEFINE_SHOW_ATTRIBUTE(debug_dmem
);
272 static int debug_etd_show(struct seq_file
*s
, void *v
)
274 struct imx21
*imx21
= s
->private;
275 struct etd_priv
*etd
;
281 spin_lock_irqsave(&imx21
->lock
, flags
);
283 for (i
= 0, etd
= imx21
->etd
; i
< USB_NUM_ETD
; i
++, etd
++) {
285 struct urb_priv
*urb_priv
;
287 urb_priv
= etd
->urb
->hcpriv
;
289 state
= urb_priv
->state
;
303 format_ep(etd
->ep
, buf
, sizeof(buf
)),
307 (readl(imx21
->regs
+ USBH_ETDENSET
) & (1 << i
)) > 0,
311 for (j
= 0; j
< 4; j
++) {
312 dword
= etd_readl(imx21
, i
, j
);
315 format_etd_dword0(dword
, buf
, sizeof(buf
));
318 snprintf(buf
, sizeof(buf
),
319 "cc=0X%02X", dword
>> DW2_COMPCODE
);
326 "dword %d: submitted=%08X cur=%08X [%s]\n",
328 etd
->submitted_dwords
[j
],
335 spin_unlock_irqrestore(&imx21
->lock
, flags
);
339 DEFINE_SHOW_ATTRIBUTE(debug_etd
);
341 static void debug_statistics_show_one(struct seq_file
*s
,
342 const char *name
, struct debug_stats
*stats
)
344 seq_printf(s
, "%s:\n"
345 "submitted URBs: %lu\n"
346 "completed OK: %lu\n"
347 "completed failed: %lu\n"
349 "queued for ETD: %lu\n"
350 "queued for DMEM: %lu\n\n",
354 stats
->completed_failed
,
360 static int debug_statistics_show(struct seq_file
*s
, void *v
)
362 struct imx21
*imx21
= s
->private;
365 spin_lock_irqsave(&imx21
->lock
, flags
);
367 debug_statistics_show_one(s
, "nonisoc", &imx21
->nonisoc_stats
);
368 debug_statistics_show_one(s
, "isoc", &imx21
->isoc_stats
);
369 seq_printf(s
, "unblock kludge triggers: %lu\n", imx21
->debug_unblocks
);
370 spin_unlock_irqrestore(&imx21
->lock
, flags
);
374 DEFINE_SHOW_ATTRIBUTE(debug_statistics
);
376 static void debug_isoc_show_one(struct seq_file
*s
,
377 const char *name
, int index
, struct debug_isoc_trace
*trace
)
379 seq_printf(s
, "%s %d:\n"
381 "scheduled frame %d (%d)\n"
382 "submitted frame %d (%d)\n"
383 "completed frame %d (%d)\n"
384 "requested length=%d\n"
385 "completed length=%d\n\n",
388 trace
->schedule_frame
, trace
->schedule_frame
& 0xFFFF,
389 trace
->submit_frame
, trace
->submit_frame
& 0xFFFF,
390 trace
->done_frame
, trace
->done_frame
& 0xFFFF,
395 static int debug_isoc_show(struct seq_file
*s
, void *v
)
397 struct imx21
*imx21
= s
->private;
398 struct debug_isoc_trace
*trace
;
402 spin_lock_irqsave(&imx21
->lock
, flags
);
404 trace
= imx21
->isoc_trace_failed
;
405 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace_failed
); i
++, trace
++)
406 debug_isoc_show_one(s
, "isoc failed", i
, trace
);
408 trace
= imx21
->isoc_trace
;
409 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace
); i
++, trace
++)
410 debug_isoc_show_one(s
, "isoc", i
, trace
);
412 spin_unlock_irqrestore(&imx21
->lock
, flags
);
416 DEFINE_SHOW_ATTRIBUTE(debug_isoc
);
418 static void create_debug_files(struct imx21
*imx21
)
422 root
= debugfs_create_dir(dev_name(imx21
->dev
), NULL
);
423 imx21
->debug_root
= root
;
425 debugfs_create_file("status", S_IRUGO
, root
, imx21
, &debug_status_fops
);
426 debugfs_create_file("dmem", S_IRUGO
, root
, imx21
, &debug_dmem_fops
);
427 debugfs_create_file("etd", S_IRUGO
, root
, imx21
, &debug_etd_fops
);
428 debugfs_create_file("statistics", S_IRUGO
, root
, imx21
,
429 &debug_statistics_fops
);
430 debugfs_create_file("isoc", S_IRUGO
, root
, imx21
, &debug_isoc_fops
);
433 static void remove_debug_files(struct imx21
*imx21
)
435 debugfs_remove_recursive(imx21
->debug_root
);