diff options
Diffstat (limited to 'drivers/usb/host/uhci-debug.c')
-rw-r--r-- | drivers/usb/host/uhci-debug.c | 320 |
1 files changed, 92 insertions, 228 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 5832953086f8..3faccbd68547 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c | |||
@@ -90,13 +90,60 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) | |||
90 | return out - buf; | 90 | return out - buf; |
91 | } | 91 | } |
92 | 92 | ||
93 | static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) | 93 | static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) |
94 | { | 94 | { |
95 | char *out = buf; | 95 | char *out = buf; |
96 | struct urb_priv *urbp; | ||
97 | struct list_head *head, *tmp; | ||
98 | struct uhci_td *td; | 96 | struct uhci_td *td; |
99 | int i = 0, checked = 0, prevactive = 0; | 97 | int i, nactive, ninactive; |
98 | |||
99 | if (len < 200) | ||
100 | return 0; | ||
101 | |||
102 | out += sprintf(out, "urb_priv [%p] ", urbp); | ||
103 | out += sprintf(out, "urb [%p] ", urbp->urb); | ||
104 | out += sprintf(out, "qh [%p] ", urbp->qh); | ||
105 | out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe)); | ||
106 | out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), | ||
107 | (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); | ||
108 | |||
109 | switch (usb_pipetype(urbp->urb->pipe)) { | ||
110 | case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break; | ||
111 | case PIPE_INTERRUPT: out += sprintf(out, "INT"); break; | ||
112 | case PIPE_BULK: out += sprintf(out, "BLK"); break; | ||
113 | case PIPE_CONTROL: out += sprintf(out, "CTL"); break; | ||
114 | } | ||
115 | |||
116 | out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : "")); | ||
117 | out += sprintf(out, "%s", (urbp->fsbr_timeout ? " FSBR_TO" : "")); | ||
118 | |||
119 | if (urbp->urb->status != -EINPROGRESS) | ||
120 | out += sprintf(out, " Status=%d", urbp->urb->status); | ||
121 | out += sprintf(out, "\n"); | ||
122 | |||
123 | i = nactive = ninactive = 0; | ||
124 | list_for_each_entry(td, &urbp->td_list, list) { | ||
125 | if (++i <= 10 || debug > 2) { | ||
126 | out += sprintf(out, "%*s%d: ", space + 2, "", i); | ||
127 | out += uhci_show_td(td, out, len - (out - buf), 0); | ||
128 | } else { | ||
129 | if (td_status(td) & TD_CTRL_ACTIVE) | ||
130 | ++nactive; | ||
131 | else | ||
132 | ++ninactive; | ||
133 | } | ||
134 | } | ||
135 | if (nactive + ninactive > 0) | ||
136 | out += sprintf(out, "%*s[skipped %d inactive and %d active " | ||
137 | "TDs]\n", | ||
138 | space, "", ninactive, nactive); | ||
139 | |||
140 | return out - buf; | ||
141 | } | ||
142 | |||
143 | static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) | ||
144 | { | ||
145 | char *out = buf; | ||
146 | int i, nurbs; | ||
100 | __le32 element = qh_element(qh); | 147 | __le32 element = qh_element(qh); |
101 | 148 | ||
102 | /* Try to make sure there's enough memory */ | 149 | /* Try to make sure there's enough memory */ |
@@ -118,86 +165,36 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) | |||
118 | if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH))) | 165 | if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH))) |
119 | out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); | 166 | out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); |
120 | 167 | ||
121 | if (!qh->urbp) { | 168 | if (list_empty(&qh->queue)) { |
122 | out += sprintf(out, "%*s urbp == NULL\n", space, ""); | 169 | out += sprintf(out, "%*s queue is empty\n", space, ""); |
123 | goto out; | 170 | } else { |
124 | } | 171 | struct urb_priv *urbp = list_entry(qh->queue.next, |
125 | 172 | struct urb_priv, node); | |
126 | urbp = qh->urbp; | 173 | struct uhci_td *td = list_entry(urbp->td_list.next, |
127 | 174 | struct uhci_td, list); | |
128 | head = &urbp->td_list; | 175 | |
129 | tmp = head->next; | 176 | if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS)) |
130 | 177 | out += sprintf(out, "%*s Element != First TD\n", | |
131 | td = list_entry(tmp, struct uhci_td, list); | 178 | space, ""); |
132 | 179 | i = nurbs = 0; | |
133 | if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS)) | 180 | list_for_each_entry(urbp, &qh->queue, node) { |
134 | out += sprintf(out, "%*s Element != First TD\n", space, ""); | 181 | if (++i <= 10) |
135 | 182 | out += uhci_show_urbp(urbp, out, | |
136 | while (tmp != head) { | 183 | len - (out - buf), space + 2); |
137 | struct uhci_td *td = list_entry(tmp, struct uhci_td, list); | 184 | else |
138 | 185 | ++nurbs; | |
139 | tmp = tmp->next; | ||
140 | |||
141 | out += sprintf(out, "%*s%d: ", space + 2, "", i++); | ||
142 | out += uhci_show_td(td, out, len - (out - buf), 0); | ||
143 | |||
144 | if (i > 10 && !checked && prevactive && tmp != head && | ||
145 | debug <= 2) { | ||
146 | struct list_head *ntmp = tmp; | ||
147 | struct uhci_td *ntd = td; | ||
148 | int active = 1, ni = i; | ||
149 | |||
150 | checked = 1; | ||
151 | |||
152 | while (ntmp != head && ntmp->next != head && active) { | ||
153 | ntd = list_entry(ntmp, struct uhci_td, list); | ||
154 | |||
155 | ntmp = ntmp->next; | ||
156 | |||
157 | active = td_status(ntd) & TD_CTRL_ACTIVE; | ||
158 | |||
159 | ni++; | ||
160 | } | ||
161 | |||
162 | if (active && ni > i) { | ||
163 | out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i); | ||
164 | tmp = ntmp; | ||
165 | td = ntd; | ||
166 | i = ni; | ||
167 | } | ||
168 | } | 186 | } |
169 | 187 | if (nurbs > 0) | |
170 | prevactive = td_status(td) & TD_CTRL_ACTIVE; | 188 | out += sprintf(out, "%*s Skipped %d URBs\n", |
171 | } | 189 | space, "", nurbs); |
172 | |||
173 | if (list_empty(&urbp->queue_list) || urbp->queued) | ||
174 | goto out; | ||
175 | |||
176 | out += sprintf(out, "%*sQueued QHs:\n", -space, "--"); | ||
177 | |||
178 | head = &urbp->queue_list; | ||
179 | tmp = head->next; | ||
180 | |||
181 | while (tmp != head) { | ||
182 | struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, | ||
183 | queue_list); | ||
184 | tmp = tmp->next; | ||
185 | |||
186 | out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space); | ||
187 | } | 190 | } |
188 | 191 | ||
189 | out: | ||
190 | return out - buf; | 192 | return out - buf; |
191 | } | 193 | } |
192 | 194 | ||
193 | #define show_frame_num() \ | ||
194 | if (!shown) { \ | ||
195 | shown = 1; \ | ||
196 | out += sprintf(out, "- Frame %d\n", i); \ | ||
197 | } | ||
198 | |||
199 | #ifdef CONFIG_PROC_FS | 195 | #ifdef CONFIG_PROC_FS |
200 | static const char * const qh_names[] = { | 196 | static const char * const qh_names[] = { |
197 | "skel_unlink_qh", "skel_iso_qh", | ||
201 | "skel_int128_qh", "skel_int64_qh", | 198 | "skel_int128_qh", "skel_int64_qh", |
202 | "skel_int32_qh", "skel_int16_qh", | 199 | "skel_int32_qh", "skel_int16_qh", |
203 | "skel_int8_qh", "skel_int4_qh", | 200 | "skel_int8_qh", "skel_int4_qh", |
@@ -206,12 +203,6 @@ static const char * const qh_names[] = { | |||
206 | "skel_bulk_qh", "skel_term_qh" | 203 | "skel_bulk_qh", "skel_term_qh" |
207 | }; | 204 | }; |
208 | 205 | ||
209 | #define show_qh_name() \ | ||
210 | if (!shown) { \ | ||
211 | shown = 1; \ | ||
212 | out += sprintf(out, "- %s\n", qh_names[i]); \ | ||
213 | } | ||
214 | |||
215 | static int uhci_show_sc(int port, unsigned short status, char *buf, int len) | 206 | static int uhci_show_sc(int port, unsigned short status, char *buf, int len) |
216 | { | 207 | { |
217 | char *out = buf; | 208 | char *out = buf; |
@@ -321,139 +312,29 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) | |||
321 | return out - buf; | 312 | return out - buf; |
322 | } | 313 | } |
323 | 314 | ||
324 | static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len) | ||
325 | { | ||
326 | struct list_head *tmp; | ||
327 | char *out = buf; | ||
328 | int count = 0; | ||
329 | |||
330 | if (len < 200) | ||
331 | return 0; | ||
332 | |||
333 | out += sprintf(out, "urb_priv [%p] ", urbp); | ||
334 | out += sprintf(out, "urb [%p] ", urbp->urb); | ||
335 | out += sprintf(out, "qh [%p] ", urbp->qh); | ||
336 | out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe)); | ||
337 | out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); | ||
338 | |||
339 | switch (usb_pipetype(urbp->urb->pipe)) { | ||
340 | case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break; | ||
341 | case PIPE_INTERRUPT: out += sprintf(out, "INT "); break; | ||
342 | case PIPE_BULK: out += sprintf(out, "BLK "); break; | ||
343 | case PIPE_CONTROL: out += sprintf(out, "CTL "); break; | ||
344 | } | ||
345 | |||
346 | out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : "")); | ||
347 | out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : "")); | ||
348 | |||
349 | if (urbp->urb->status != -EINPROGRESS) | ||
350 | out += sprintf(out, "Status=%d ", urbp->urb->status); | ||
351 | //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); | ||
352 | |||
353 | count = 0; | ||
354 | list_for_each(tmp, &urbp->td_list) | ||
355 | count++; | ||
356 | out += sprintf(out, "TDs=%d ",count); | ||
357 | |||
358 | if (urbp->queued) | ||
359 | out += sprintf(out, "queued\n"); | ||
360 | else { | ||
361 | count = 0; | ||
362 | list_for_each(tmp, &urbp->queue_list) | ||
363 | count++; | ||
364 | out += sprintf(out, "queued URBs=%d\n", count); | ||
365 | } | ||
366 | |||
367 | return out - buf; | ||
368 | } | ||
369 | |||
370 | static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len) | ||
371 | { | ||
372 | char *out = buf; | ||
373 | struct list_head *head, *tmp; | ||
374 | int count; | ||
375 | |||
376 | out += sprintf(out, "Main list URBs:"); | ||
377 | if (list_empty(&uhci->urb_list)) | ||
378 | out += sprintf(out, " Empty\n"); | ||
379 | else { | ||
380 | out += sprintf(out, "\n"); | ||
381 | count = 0; | ||
382 | head = &uhci->urb_list; | ||
383 | tmp = head->next; | ||
384 | while (tmp != head) { | ||
385 | struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); | ||
386 | |||
387 | out += sprintf(out, " %d: ", ++count); | ||
388 | out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); | ||
389 | tmp = tmp->next; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | out += sprintf(out, "Remove list URBs:"); | ||
394 | if (list_empty(&uhci->urb_remove_list)) | ||
395 | out += sprintf(out, " Empty\n"); | ||
396 | else { | ||
397 | out += sprintf(out, "\n"); | ||
398 | count = 0; | ||
399 | head = &uhci->urb_remove_list; | ||
400 | tmp = head->next; | ||
401 | while (tmp != head) { | ||
402 | struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); | ||
403 | |||
404 | out += sprintf(out, " %d: ", ++count); | ||
405 | out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); | ||
406 | tmp = tmp->next; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | out += sprintf(out, "Complete list URBs:"); | ||
411 | if (list_empty(&uhci->complete_list)) | ||
412 | out += sprintf(out, " Empty\n"); | ||
413 | else { | ||
414 | out += sprintf(out, "\n"); | ||
415 | count = 0; | ||
416 | head = &uhci->complete_list; | ||
417 | tmp = head->next; | ||
418 | while (tmp != head) { | ||
419 | struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); | ||
420 | |||
421 | out += sprintf(out, " %d: ", ++count); | ||
422 | out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); | ||
423 | tmp = tmp->next; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | return out - buf; | ||
428 | } | ||
429 | |||
430 | static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | 315 | static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) |
431 | { | 316 | { |
432 | unsigned long flags; | ||
433 | char *out = buf; | 317 | char *out = buf; |
434 | int i, j; | 318 | int i, j; |
435 | struct uhci_qh *qh; | 319 | struct uhci_qh *qh; |
436 | struct uhci_td *td; | 320 | struct uhci_td *td; |
437 | struct list_head *tmp, *head; | 321 | struct list_head *tmp, *head; |
438 | 322 | ||
439 | spin_lock_irqsave(&uhci->lock, flags); | ||
440 | |||
441 | out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); | 323 | out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); |
442 | out += sprintf(out, "HC status\n"); | 324 | out += sprintf(out, "HC status\n"); |
443 | out += uhci_show_status(uhci, out, len - (out - buf)); | 325 | out += uhci_show_status(uhci, out, len - (out - buf)); |
326 | if (debug <= 1) | ||
327 | return out - buf; | ||
444 | 328 | ||
445 | out += sprintf(out, "Frame List\n"); | 329 | out += sprintf(out, "Frame List\n"); |
446 | for (i = 0; i < UHCI_NUMFRAMES; ++i) { | 330 | for (i = 0; i < UHCI_NUMFRAMES; ++i) { |
447 | int shown = 0; | ||
448 | td = uhci->frame_cpu[i]; | 331 | td = uhci->frame_cpu[i]; |
449 | if (!td) | 332 | if (!td) |
450 | continue; | 333 | continue; |
451 | 334 | ||
452 | if (td->dma_handle != (dma_addr_t)uhci->frame[i]) { | 335 | out += sprintf(out, "- Frame %d\n", i); \ |
453 | show_frame_num(); | 336 | if (td->dma_handle != (dma_addr_t)uhci->frame[i]) |
454 | out += sprintf(out, " frame list does not match td->dma_handle!\n"); | 337 | out += sprintf(out, " frame list does not match td->dma_handle!\n"); |
455 | } | ||
456 | show_frame_num(); | ||
457 | 338 | ||
458 | head = &td->fl_list; | 339 | head = &td->fl_list; |
459 | tmp = head; | 340 | tmp = head; |
@@ -467,14 +348,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
467 | out += sprintf(out, "Skeleton QHs\n"); | 348 | out += sprintf(out, "Skeleton QHs\n"); |
468 | 349 | ||
469 | for (i = 0; i < UHCI_NUM_SKELQH; ++i) { | 350 | for (i = 0; i < UHCI_NUM_SKELQH; ++i) { |
470 | int shown = 0; | 351 | int cnt = 0; |
471 | 352 | ||
472 | qh = uhci->skelqh[i]; | 353 | qh = uhci->skelqh[i]; |
473 | 354 | out += sprintf(out, "- %s\n", qh_names[i]); \ | |
474 | if (debug > 1) { | 355 | out += uhci_show_qh(qh, out, len - (out - buf), 4); |
475 | show_qh_name(); | ||
476 | out += uhci_show_qh(qh, out, len - (out - buf), 4); | ||
477 | } | ||
478 | 356 | ||
479 | /* Last QH is the Terminating QH, it's different */ | 357 | /* Last QH is the Terminating QH, it's different */ |
480 | if (i == UHCI_NUM_SKELQH - 1) { | 358 | if (i == UHCI_NUM_SKELQH - 1) { |
@@ -487,44 +365,27 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
487 | continue; | 365 | continue; |
488 | } | 366 | } |
489 | 367 | ||
490 | j = (i < 7) ? 7 : i+1; /* Next skeleton */ | 368 | j = (i < 9) ? 9 : i+1; /* Next skeleton */ |
491 | if (list_empty(&qh->list)) { | 369 | head = &qh->node; |
492 | if (i < UHCI_NUM_SKELQH - 1) { | ||
493 | if (qh->link != | ||
494 | (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) { | ||
495 | show_qh_name(); | ||
496 | out += sprintf(out, " skeleton QH not linked to next skeleton QH!\n"); | ||
497 | } | ||
498 | } | ||
499 | |||
500 | continue; | ||
501 | } | ||
502 | |||
503 | show_qh_name(); | ||
504 | |||
505 | head = &qh->list; | ||
506 | tmp = head->next; | 370 | tmp = head->next; |
507 | 371 | ||
508 | while (tmp != head) { | 372 | while (tmp != head) { |
509 | qh = list_entry(tmp, struct uhci_qh, list); | 373 | qh = list_entry(tmp, struct uhci_qh, node); |
510 | |||
511 | tmp = tmp->next; | 374 | tmp = tmp->next; |
512 | 375 | if (++cnt <= 10) | |
513 | out += uhci_show_qh(qh, out, len - (out - buf), 4); | 376 | out += uhci_show_qh(qh, out, |
377 | len - (out - buf), 4); | ||
514 | } | 378 | } |
379 | if ((cnt -= 10) > 0) | ||
380 | out += sprintf(out, " Skipped %d QHs\n", cnt); | ||
515 | 381 | ||
516 | if (i < UHCI_NUM_SKELQH - 1) { | 382 | if (i > 1 && i < UHCI_NUM_SKELQH - 1) { |
517 | if (qh->link != | 383 | if (qh->link != |
518 | (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) | 384 | (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) |
519 | out += sprintf(out, " last QH not linked to next skeleton!\n"); | 385 | out += sprintf(out, " last QH not linked to next skeleton!\n"); |
520 | } | 386 | } |
521 | } | 387 | } |
522 | 388 | ||
523 | if (debug > 2) | ||
524 | out += uhci_show_lists(uhci, out, len - (out - buf)); | ||
525 | |||
526 | spin_unlock_irqrestore(&uhci->lock, flags); | ||
527 | |||
528 | return out - buf; | 389 | return out - buf; |
529 | } | 390 | } |
530 | 391 | ||
@@ -541,6 +402,7 @@ static int uhci_debug_open(struct inode *inode, struct file *file) | |||
541 | struct uhci_hcd *uhci = inode->u.generic_ip; | 402 | struct uhci_hcd *uhci = inode->u.generic_ip; |
542 | struct uhci_debug *up; | 403 | struct uhci_debug *up; |
543 | int ret = -ENOMEM; | 404 | int ret = -ENOMEM; |
405 | unsigned long flags; | ||
544 | 406 | ||
545 | lock_kernel(); | 407 | lock_kernel(); |
546 | up = kmalloc(sizeof(*up), GFP_KERNEL); | 408 | up = kmalloc(sizeof(*up), GFP_KERNEL); |
@@ -553,7 +415,9 @@ static int uhci_debug_open(struct inode *inode, struct file *file) | |||
553 | goto out; | 415 | goto out; |
554 | } | 416 | } |
555 | 417 | ||
418 | spin_lock_irqsave(&uhci->lock, flags); | ||
556 | up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); | 419 | up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); |
420 | spin_unlock_irqrestore(&uhci->lock, flags); | ||
557 | 421 | ||
558 | file->private_data = up; | 422 | file->private_data = up; |
559 | 423 | ||