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 */
23 static inline void create_debug_files(struct imx21
*imx21
) { }
24 static inline void remove_debug_files(struct imx21
*imx21
) { }
25 static inline void debug_urb_submitted(struct imx21
*imx21
, struct urb
*urb
) {}
26 static inline void debug_urb_completed(struct imx21
*imx21
, struct urb
*urb
,
28 static inline void debug_urb_unlinked(struct imx21
*imx21
, struct urb
*urb
) {}
29 static inline void debug_urb_queued_for_etd(struct imx21
*imx21
,
31 static inline void debug_urb_queued_for_dmem(struct imx21
*imx21
,
33 static inline void debug_etd_allocated(struct imx21
*imx21
) {}
34 static inline void debug_etd_freed(struct imx21
*imx21
) {}
35 static inline void debug_dmem_allocated(struct imx21
*imx21
, int size
) {}
36 static inline void debug_dmem_freed(struct imx21
*imx21
, int size
) {}
37 static inline void debug_isoc_submitted(struct imx21
*imx21
,
38 int frame
, struct td
*td
) {}
39 static inline void debug_isoc_completed(struct imx21
*imx21
,
40 int frame
, struct td
*td
, int cc
, int len
) {}
44 #include <linux/debugfs.h>
45 #include <linux/seq_file.h>
47 static const char *dir_labels
[] = {
54 static const char *speed_labels
[] = {
59 static const char *format_labels
[] = {
66 static inline struct debug_stats
*stats_for_urb(struct imx21
*imx21
,
69 return usb_pipeisoc(urb
->pipe
) ?
70 &imx21
->isoc_stats
: &imx21
->nonisoc_stats
;
73 static void debug_urb_submitted(struct imx21
*imx21
, struct urb
*urb
)
75 stats_for_urb(imx21
, urb
)->submitted
++;
78 static void debug_urb_completed(struct imx21
*imx21
, struct urb
*urb
, int st
)
81 stats_for_urb(imx21
, urb
)->completed_failed
++;
83 stats_for_urb(imx21
, urb
)->completed_ok
++;
86 static void debug_urb_unlinked(struct imx21
*imx21
, struct urb
*urb
)
88 stats_for_urb(imx21
, urb
)->unlinked
++;
91 static void debug_urb_queued_for_etd(struct imx21
*imx21
, struct urb
*urb
)
93 stats_for_urb(imx21
, urb
)->queue_etd
++;
96 static void debug_urb_queued_for_dmem(struct imx21
*imx21
, struct urb
*urb
)
98 stats_for_urb(imx21
, urb
)->queue_dmem
++;
101 static inline void debug_etd_allocated(struct imx21
*imx21
)
103 imx21
->etd_usage
.maximum
= max(
104 ++(imx21
->etd_usage
.value
),
105 imx21
->etd_usage
.maximum
);
108 static inline void debug_etd_freed(struct imx21
*imx21
)
110 imx21
->etd_usage
.value
--;
113 static inline void debug_dmem_allocated(struct imx21
*imx21
, int size
)
115 imx21
->dmem_usage
.value
+= size
;
116 imx21
->dmem_usage
.maximum
= max(
117 imx21
->dmem_usage
.value
,
118 imx21
->dmem_usage
.maximum
);
121 static inline void debug_dmem_freed(struct imx21
*imx21
, int size
)
123 imx21
->dmem_usage
.value
-= size
;
127 static void debug_isoc_submitted(struct imx21
*imx21
,
128 int frame
, struct td
*td
)
130 struct debug_isoc_trace
*trace
= &imx21
->isoc_trace
[
131 imx21
->isoc_trace_index
++];
133 imx21
->isoc_trace_index
%= ARRAY_SIZE(imx21
->isoc_trace
);
134 trace
->schedule_frame
= td
->frame
;
135 trace
->submit_frame
= frame
;
136 trace
->request_len
= td
->len
;
140 static inline void debug_isoc_completed(struct imx21
*imx21
,
141 int frame
, struct td
*td
, int cc
, int len
)
143 struct debug_isoc_trace
*trace
, *trace_failed
;
147 trace
= imx21
->isoc_trace
;
148 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace
); i
++, trace
++) {
149 if (trace
->td
== td
) {
150 trace
->done_frame
= frame
;
151 trace
->done_len
= len
;
160 trace_failed
= &imx21
->isoc_trace_failed
[
161 imx21
->isoc_trace_index_failed
++];
163 imx21
->isoc_trace_index_failed
%= ARRAY_SIZE(
164 imx21
->isoc_trace_failed
);
165 *trace_failed
= *trace
;
170 static char *format_ep(struct usb_host_endpoint
*ep
, char *buf
, int bufsize
)
173 snprintf(buf
, bufsize
, "ep_%02x (type:%02X kaddr:%p)",
174 ep
->desc
.bEndpointAddress
,
175 usb_endpoint_type(&ep
->desc
),
178 snprintf(buf
, bufsize
, "none");
182 static char *format_etd_dword0(u32 value
, char *buf
, int bufsize
)
184 snprintf(buf
, bufsize
,
185 "addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
187 (value
>> DW0_ENDPNT
) & 0x0F,
188 dir_labels
[(value
>> DW0_DIRECT
) & 0x03],
189 speed_labels
[(value
>> DW0_SPEED
) & 0x01],
190 format_labels
[(value
>> DW0_FORMAT
) & 0x03],
191 (value
>> DW0_HALTED
) & 0x01);
195 static int debug_status_show(struct seq_file
*s
, void *v
)
197 struct imx21
*imx21
= s
->private;
198 int etds_allocated
= 0;
199 int etds_sw_busy
= 0;
200 int etds_hw_busy
= 0;
202 int queued_for_etd
= 0;
203 int queued_for_dmem
= 0;
204 unsigned int dmem_bytes
= 0;
206 struct etd_priv
*etd
;
209 struct imx21_dmem_area
*dmem
;
210 struct ep_priv
*ep_priv
;
212 spin_lock_irqsave(&imx21
->lock
, flags
);
214 etd_enable_mask
= readl(imx21
->regs
+ USBH_ETDENSET
);
215 for (i
= 0, etd
= imx21
->etd
; i
< USB_NUM_ETD
; i
++, etd
++) {
220 if (etd_enable_mask
& (1<<i
))
224 list_for_each_entry(dmem
, &imx21
->dmem_list
, list
) {
225 dmem_bytes
+= dmem
->size
;
229 list_for_each_entry(ep_priv
, &imx21
->queue_for_etd
, queue
)
232 list_for_each_entry(etd
, &imx21
->queue_for_dmem
, queue
)
235 spin_unlock_irqrestore(&imx21
->lock
, flags
);
239 "ETDs allocated: %d/%d (max=%d)\n"
240 "ETDs in use sw: %d\n"
241 "ETDs in use hw: %d\n"
242 "DMEM alocated: %d/%d (max=%d)\n"
244 "Queued waiting for ETD: %d\n"
245 "Queued waiting for DMEM: %d\n",
246 readl(imx21
->regs
+ USBH_FRMNUB
) & 0xFFFF,
247 etds_allocated
, USB_NUM_ETD
, imx21
->etd_usage
.maximum
,
250 dmem_bytes
, DMEM_SIZE
, imx21
->dmem_usage
.maximum
,
258 static int debug_dmem_show(struct seq_file
*s
, void *v
)
260 struct imx21
*imx21
= s
->private;
261 struct imx21_dmem_area
*dmem
;
265 spin_lock_irqsave(&imx21
->lock
, flags
);
267 list_for_each_entry(dmem
, &imx21
->dmem_list
, list
)
271 dmem
->offset
, dmem
->size
,
272 format_ep(dmem
->ep
, ep_text
, sizeof(ep_text
)));
274 spin_unlock_irqrestore(&imx21
->lock
, flags
);
279 static int debug_etd_show(struct seq_file
*s
, void *v
)
281 struct imx21
*imx21
= s
->private;
282 struct etd_priv
*etd
;
288 spin_lock_irqsave(&imx21
->lock
, flags
);
290 for (i
= 0, etd
= imx21
->etd
; i
< USB_NUM_ETD
; i
++, etd
++) {
292 struct urb_priv
*urb_priv
;
294 urb_priv
= etd
->urb
->hcpriv
;
296 state
= urb_priv
->state
;
310 format_ep(etd
->ep
, buf
, sizeof(buf
)),
314 (readl(imx21
->regs
+ USBH_ETDENSET
) & (1 << i
)) > 0,
318 for (j
= 0; j
< 4; j
++) {
319 dword
= etd_readl(imx21
, i
, j
);
322 format_etd_dword0(dword
, buf
, sizeof(buf
));
325 snprintf(buf
, sizeof(buf
),
326 "cc=0X%02X", dword
>> DW2_COMPCODE
);
333 "dword %d: submitted=%08X cur=%08X [%s]\n",
335 etd
->submitted_dwords
[j
],
342 spin_unlock_irqrestore(&imx21
->lock
, flags
);
347 static void debug_statistics_show_one(struct seq_file
*s
,
348 const char *name
, struct debug_stats
*stats
)
350 seq_printf(s
, "%s:\n"
351 "submitted URBs: %lu\n"
352 "completed OK: %lu\n"
353 "completed failed: %lu\n"
355 "queued for ETD: %lu\n"
356 "queued for DMEM: %lu\n\n",
360 stats
->completed_failed
,
366 static int debug_statistics_show(struct seq_file
*s
, void *v
)
368 struct imx21
*imx21
= s
->private;
371 spin_lock_irqsave(&imx21
->lock
, flags
);
373 debug_statistics_show_one(s
, "nonisoc", &imx21
->nonisoc_stats
);
374 debug_statistics_show_one(s
, "isoc", &imx21
->isoc_stats
);
375 seq_printf(s
, "unblock kludge triggers: %lu\n", imx21
->debug_unblocks
);
376 spin_unlock_irqrestore(&imx21
->lock
, flags
);
381 static void debug_isoc_show_one(struct seq_file
*s
,
382 const char *name
, int index
, struct debug_isoc_trace
*trace
)
384 seq_printf(s
, "%s %d:\n"
386 "scheduled frame %d (%d)\n"
387 "submittted frame %d (%d)\n"
388 "completed frame %d (%d)\n"
389 "requested length=%d\n"
390 "completed length=%d\n\n",
393 trace
->schedule_frame
, trace
->schedule_frame
& 0xFFFF,
394 trace
->submit_frame
, trace
->submit_frame
& 0xFFFF,
395 trace
->done_frame
, trace
->done_frame
& 0xFFFF,
400 static int debug_isoc_show(struct seq_file
*s
, void *v
)
402 struct imx21
*imx21
= s
->private;
403 struct debug_isoc_trace
*trace
;
407 spin_lock_irqsave(&imx21
->lock
, flags
);
409 trace
= imx21
->isoc_trace_failed
;
410 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace_failed
); i
++, trace
++)
411 debug_isoc_show_one(s
, "isoc failed", i
, trace
);
413 trace
= imx21
->isoc_trace
;
414 for (i
= 0; i
< ARRAY_SIZE(imx21
->isoc_trace
); i
++, trace
++)
415 debug_isoc_show_one(s
, "isoc", i
, trace
);
417 spin_unlock_irqrestore(&imx21
->lock
, flags
);
422 static int debug_status_open(struct inode
*inode
, struct file
*file
)
424 return single_open(file
, debug_status_show
, inode
->i_private
);
427 static int debug_dmem_open(struct inode
*inode
, struct file
*file
)
429 return single_open(file
, debug_dmem_show
, inode
->i_private
);
432 static int debug_etd_open(struct inode
*inode
, struct file
*file
)
434 return single_open(file
, debug_etd_show
, inode
->i_private
);
437 static int debug_statistics_open(struct inode
*inode
, struct file
*file
)
439 return single_open(file
, debug_statistics_show
, inode
->i_private
);
442 static int debug_isoc_open(struct inode
*inode
, struct file
*file
)
444 return single_open(file
, debug_isoc_show
, inode
->i_private
);
447 static const struct file_operations debug_status_fops
= {
448 .open
= debug_status_open
,
451 .release
= single_release
,
454 static const struct file_operations debug_dmem_fops
= {
455 .open
= debug_dmem_open
,
458 .release
= single_release
,
461 static const struct file_operations debug_etd_fops
= {
462 .open
= debug_etd_open
,
465 .release
= single_release
,
468 static const struct file_operations debug_statistics_fops
= {
469 .open
= debug_statistics_open
,
472 .release
= single_release
,
475 static const struct file_operations debug_isoc_fops
= {
476 .open
= debug_isoc_open
,
479 .release
= single_release
,
482 static void create_debug_files(struct imx21
*imx21
)
484 imx21
->debug_root
= debugfs_create_dir(dev_name(imx21
->dev
), NULL
);
485 if (!imx21
->debug_root
)
486 goto failed_create_rootdir
;
488 if (!debugfs_create_file("status", S_IRUGO
,
489 imx21
->debug_root
, imx21
, &debug_status_fops
))
492 if (!debugfs_create_file("dmem", S_IRUGO
,
493 imx21
->debug_root
, imx21
, &debug_dmem_fops
))
496 if (!debugfs_create_file("etd", S_IRUGO
,
497 imx21
->debug_root
, imx21
, &debug_etd_fops
))
500 if (!debugfs_create_file("statistics", S_IRUGO
,
501 imx21
->debug_root
, imx21
, &debug_statistics_fops
))
504 if (!debugfs_create_file("isoc", S_IRUGO
,
505 imx21
->debug_root
, imx21
, &debug_isoc_fops
))
511 debugfs_remove_recursive(imx21
->debug_root
);
513 failed_create_rootdir
:
514 imx21
->debug_root
= NULL
;
518 static void remove_debug_files(struct imx21
*imx21
)
520 if (imx21
->debug_root
) {
521 debugfs_remove_recursive(imx21
->debug_root
);
522 imx21
->debug_root
= NULL
;