2 * Copyright (c) 2009 by Martin Fuzzey
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* this file is part of imx21-hcd.c */
21 #ifdef CONFIG_DYNAMIC_DEBUG
27 static inline void create_debug_files(struct imx21
*imx21
) { }
28 static inline void remove_debug_files(struct imx21
*imx21
) { }
29 static inline void debug_urb_submitted(struct imx21
*imx21
, struct urb
*urb
) {}
30 static inline void debug_urb_completed(struct imx21
*imx21
, struct urb
*urb
,
32 static inline void debug_urb_unlinked(struct imx21
*imx21
, struct urb
*urb
) {}
33 static inline void debug_urb_queued_for_etd(struct imx21
*imx21
,
35 static inline void debug_urb_queued_for_dmem(struct imx21
*imx21
,
37 static inline void debug_etd_allocated(struct imx21
*imx21
) {}
38 static inline void debug_etd_freed(struct imx21
*imx21
) {}
39 static inline void debug_dmem_allocated(struct imx21
*imx21
, int size
) {}
40 static inline void debug_dmem_freed(struct imx21
*imx21
, int size
) {}
41 static inline void debug_isoc_submitted(struct imx21
*imx21
,
42 int frame
, struct td
*td
) {}
43 static inline void debug_isoc_completed(struct imx21
*imx21
,
44 int frame
, struct td
*td
, int cc
, int len
) {}
48 #include <linux/debugfs.h>
49 #include <linux/seq_file.h>
51 static const char *dir_labels
[] = {
58 static const char *speed_labels
[] = {
63 static const char *format_labels
[] = {
70 static inline struct debug_stats
*stats_for_urb(struct imx21
*imx21
,
73 return usb_pipeisoc(urb
->pipe
) ?
74 &imx21
->isoc_stats
: &imx21
->nonisoc_stats
;
77 static void debug_urb_submitted(struct imx21
*imx21
, struct urb
*urb
)
79 stats_for_urb(imx21
, urb
)->submitted
++;
82 static void debug_urb_completed(struct imx21
*imx21
, struct urb
*urb
, int st
)
85 stats_for_urb(imx21
, urb
)->completed_failed
++;
87 stats_for_urb(imx21
, urb
)->completed_ok
++;
90 static void debug_urb_unlinked(struct imx21
*imx21
, struct urb
*urb
)
92 stats_for_urb(imx21
, urb
)->unlinked
++;
95 static void debug_urb_queued_for_etd(struct imx21
*imx21
, struct urb
*urb
)
97 stats_for_urb(imx21
, urb
)->queue_etd
++;
100 static void debug_urb_queued_for_dmem(struct imx21
*imx21
, struct urb
*urb
)
102 stats_for_urb(imx21
, urb
)->queue_dmem
++;
105 static inline void debug_etd_allocated(struct imx21
*imx21
)
107 imx21
->etd_usage
.maximum
= max(
108 ++(imx21
->etd_usage
.value
),
109 imx21
->etd_usage
.maximum
);
112 static inline void debug_etd_freed(struct imx21
*imx21
)
114 imx21
->etd_usage
.value
--;
117 static inline void debug_dmem_allocated(struct imx21
*imx21
, int size
)
119 imx21
->dmem_usage
.value
+= size
;
120 imx21
->dmem_usage
.maximum
= max(
121 imx21
->dmem_usage
.value
,
122 imx21
->dmem_usage
.maximum
);
125 static inline void debug_dmem_freed(struct imx21
*imx21
, int size
)
127 imx21
->dmem_usage
.value
-= size
;
131 static void debug_isoc_submitted(struct imx21
*imx21
,
132 int frame
, struct td
*td
)
134 struct debug_isoc_trace
*trace
= &imx21
->isoc_trace
[
135 imx21
->isoc_trace_index
++];
137 imx21
->isoc_trace_index
%= ARRAY_SIZE(imx21
->isoc_trace
);
138 trace
->schedule_frame
= td
->frame
;
139 trace
->submit_frame
= frame
;
140 trace
->request_len
= td
->len
;
144 static inline void debug_isoc_completed(struct imx21
*imx21
,
145 int frame
, struct td
*td
, int cc
, int len
)
147 struct debug_isoc_trace
*trace
, *trace_failed
;
151 trace
= imx21
->isoc_trace
;
152 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace
); i
++, trace
++) {
153 if (trace
->td
== td
) {
154 trace
->done_frame
= frame
;
155 trace
->done_len
= len
;
164 trace_failed
= &imx21
->isoc_trace_failed
[
165 imx21
->isoc_trace_index_failed
++];
167 imx21
->isoc_trace_index_failed
%= ARRAY_SIZE(
168 imx21
->isoc_trace_failed
);
169 *trace_failed
= *trace
;
174 static char *format_ep(struct usb_host_endpoint
*ep
, char *buf
, int bufsize
)
177 snprintf(buf
, bufsize
, "ep_%02x (type:%02X kaddr:%p)",
178 ep
->desc
.bEndpointAddress
,
179 usb_endpoint_type(&ep
->desc
),
182 snprintf(buf
, bufsize
, "none");
186 static char *format_etd_dword0(u32 value
, char *buf
, int bufsize
)
188 snprintf(buf
, bufsize
,
189 "addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
191 (value
>> DW0_ENDPNT
) & 0x0F,
192 dir_labels
[(value
>> DW0_DIRECT
) & 0x03],
193 speed_labels
[(value
>> DW0_SPEED
) & 0x01],
194 format_labels
[(value
>> DW0_FORMAT
) & 0x03],
195 (value
>> DW0_HALTED
) & 0x01);
199 static int debug_status_show(struct seq_file
*s
, void *v
)
201 struct imx21
*imx21
= s
->private;
202 int etds_allocated
= 0;
203 int etds_sw_busy
= 0;
204 int etds_hw_busy
= 0;
206 int queued_for_etd
= 0;
207 int queued_for_dmem
= 0;
208 unsigned int dmem_bytes
= 0;
210 struct etd_priv
*etd
;
213 struct imx21_dmem_area
*dmem
;
214 struct ep_priv
*ep_priv
;
216 spin_lock_irqsave(&imx21
->lock
, flags
);
218 etd_enable_mask
= readl(imx21
->regs
+ USBH_ETDENSET
);
219 for (i
= 0, etd
= imx21
->etd
; i
< USB_NUM_ETD
; i
++, etd
++) {
224 if (etd_enable_mask
& (1<<i
))
228 list_for_each_entry(dmem
, &imx21
->dmem_list
, list
) {
229 dmem_bytes
+= dmem
->size
;
233 list_for_each_entry(ep_priv
, &imx21
->queue_for_etd
, queue
)
236 list_for_each_entry(etd
, &imx21
->queue_for_dmem
, queue
)
239 spin_unlock_irqrestore(&imx21
->lock
, flags
);
243 "ETDs allocated: %d/%d (max=%d)\n"
244 "ETDs in use sw: %d\n"
245 "ETDs in use hw: %d\n"
246 "DMEM allocated: %d/%d (max=%d)\n"
248 "Queued waiting for ETD: %d\n"
249 "Queued waiting for DMEM: %d\n",
250 readl(imx21
->regs
+ USBH_FRMNUB
) & 0xFFFF,
251 etds_allocated
, USB_NUM_ETD
, imx21
->etd_usage
.maximum
,
254 dmem_bytes
, DMEM_SIZE
, imx21
->dmem_usage
.maximum
,
262 static int debug_dmem_show(struct seq_file
*s
, void *v
)
264 struct imx21
*imx21
= s
->private;
265 struct imx21_dmem_area
*dmem
;
269 spin_lock_irqsave(&imx21
->lock
, flags
);
271 list_for_each_entry(dmem
, &imx21
->dmem_list
, list
)
275 dmem
->offset
, dmem
->size
,
276 format_ep(dmem
->ep
, ep_text
, sizeof(ep_text
)));
278 spin_unlock_irqrestore(&imx21
->lock
, flags
);
283 static int debug_etd_show(struct seq_file
*s
, void *v
)
285 struct imx21
*imx21
= s
->private;
286 struct etd_priv
*etd
;
292 spin_lock_irqsave(&imx21
->lock
, flags
);
294 for (i
= 0, etd
= imx21
->etd
; i
< USB_NUM_ETD
; i
++, etd
++) {
296 struct urb_priv
*urb_priv
;
298 urb_priv
= etd
->urb
->hcpriv
;
300 state
= urb_priv
->state
;
314 format_ep(etd
->ep
, buf
, sizeof(buf
)),
318 (readl(imx21
->regs
+ USBH_ETDENSET
) & (1 << i
)) > 0,
322 for (j
= 0; j
< 4; j
++) {
323 dword
= etd_readl(imx21
, i
, j
);
326 format_etd_dword0(dword
, buf
, sizeof(buf
));
329 snprintf(buf
, sizeof(buf
),
330 "cc=0X%02X", dword
>> DW2_COMPCODE
);
337 "dword %d: submitted=%08X cur=%08X [%s]\n",
339 etd
->submitted_dwords
[j
],
346 spin_unlock_irqrestore(&imx21
->lock
, flags
);
351 static void debug_statistics_show_one(struct seq_file
*s
,
352 const char *name
, struct debug_stats
*stats
)
354 seq_printf(s
, "%s:\n"
355 "submitted URBs: %lu\n"
356 "completed OK: %lu\n"
357 "completed failed: %lu\n"
359 "queued for ETD: %lu\n"
360 "queued for DMEM: %lu\n\n",
364 stats
->completed_failed
,
370 static int debug_statistics_show(struct seq_file
*s
, void *v
)
372 struct imx21
*imx21
= s
->private;
375 spin_lock_irqsave(&imx21
->lock
, flags
);
377 debug_statistics_show_one(s
, "nonisoc", &imx21
->nonisoc_stats
);
378 debug_statistics_show_one(s
, "isoc", &imx21
->isoc_stats
);
379 seq_printf(s
, "unblock kludge triggers: %lu\n", imx21
->debug_unblocks
);
380 spin_unlock_irqrestore(&imx21
->lock
, flags
);
385 static void debug_isoc_show_one(struct seq_file
*s
,
386 const char *name
, int index
, struct debug_isoc_trace
*trace
)
388 seq_printf(s
, "%s %d:\n"
390 "scheduled frame %d (%d)\n"
391 "submitted frame %d (%d)\n"
392 "completed frame %d (%d)\n"
393 "requested length=%d\n"
394 "completed length=%d\n\n",
397 trace
->schedule_frame
, trace
->schedule_frame
& 0xFFFF,
398 trace
->submit_frame
, trace
->submit_frame
& 0xFFFF,
399 trace
->done_frame
, trace
->done_frame
& 0xFFFF,
404 static int debug_isoc_show(struct seq_file
*s
, void *v
)
406 struct imx21
*imx21
= s
->private;
407 struct debug_isoc_trace
*trace
;
411 spin_lock_irqsave(&imx21
->lock
, flags
);
413 trace
= imx21
->isoc_trace_failed
;
414 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace_failed
); i
++, trace
++)
415 debug_isoc_show_one(s
, "isoc failed", i
, trace
);
417 trace
= imx21
->isoc_trace
;
418 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace
); i
++, trace
++)
419 debug_isoc_show_one(s
, "isoc", i
, trace
);
421 spin_unlock_irqrestore(&imx21
->lock
, flags
);
426 static int debug_status_open(struct inode
*inode
, struct file
*file
)
428 return single_open(file
, debug_status_show
, inode
->i_private
);
431 static int debug_dmem_open(struct inode
*inode
, struct file
*file
)
433 return single_open(file
, debug_dmem_show
, inode
->i_private
);
436 static int debug_etd_open(struct inode
*inode
, struct file
*file
)
438 return single_open(file
, debug_etd_show
, inode
->i_private
);
441 static int debug_statistics_open(struct inode
*inode
, struct file
*file
)
443 return single_open(file
, debug_statistics_show
, inode
->i_private
);
446 static int debug_isoc_open(struct inode
*inode
, struct file
*file
)
448 return single_open(file
, debug_isoc_show
, inode
->i_private
);
451 static const struct file_operations debug_status_fops
= {
452 .open
= debug_status_open
,
455 .release
= single_release
,
458 static const struct file_operations debug_dmem_fops
= {
459 .open
= debug_dmem_open
,
462 .release
= single_release
,
465 static const struct file_operations debug_etd_fops
= {
466 .open
= debug_etd_open
,
469 .release
= single_release
,
472 static const struct file_operations debug_statistics_fops
= {
473 .open
= debug_statistics_open
,
476 .release
= single_release
,
479 static const struct file_operations debug_isoc_fops
= {
480 .open
= debug_isoc_open
,
483 .release
= single_release
,
486 static void create_debug_files(struct imx21
*imx21
)
488 imx21
->debug_root
= debugfs_create_dir(dev_name(imx21
->dev
), NULL
);
489 if (!imx21
->debug_root
)
490 goto failed_create_rootdir
;
492 if (!debugfs_create_file("status", S_IRUGO
,
493 imx21
->debug_root
, imx21
, &debug_status_fops
))
496 if (!debugfs_create_file("dmem", S_IRUGO
,
497 imx21
->debug_root
, imx21
, &debug_dmem_fops
))
500 if (!debugfs_create_file("etd", S_IRUGO
,
501 imx21
->debug_root
, imx21
, &debug_etd_fops
))
504 if (!debugfs_create_file("statistics", S_IRUGO
,
505 imx21
->debug_root
, imx21
, &debug_statistics_fops
))
508 if (!debugfs_create_file("isoc", S_IRUGO
,
509 imx21
->debug_root
, imx21
, &debug_isoc_fops
))
515 debugfs_remove_recursive(imx21
->debug_root
);
517 failed_create_rootdir
:
518 imx21
->debug_root
= NULL
;
522 static void remove_debug_files(struct imx21
*imx21
)
524 if (imx21
->debug_root
) {
525 debugfs_remove_recursive(imx21
->debug_root
);
526 imx21
->debug_root
= NULL
;