1 /*
2  * UHCI-specific debugging code. Invaluable when something
3  * goes wrong, but don't get in my face.
4  *
5  * Kernel visible pointers are surrounded in []'s and bus
6  * visible pointers are surrounded in ()'s
7  *
8  * (C) Copyright 1999 Linus Torvalds
9  * (C) Copyright 1999-2001 Johannes Erdfelt
10  */
11 
12 #include <linux/config.h>
13 #include <linux/kernel.h>
14 #include <linux/proc_fs.h>
15 #include <asm/io.h>
16 
17 #include "uhci.h"
18 
19 /* Handle REALLY large printk's so we don't overflow buffers */
lprintk(char * buf)20 static void inline lprintk(char *buf)
21 {
22 	char *p;
23 
24 	/* Just write one line at a time */
25 	while (buf) {
26 		p = strchr(buf, '\n');
27 		if (p)
28 			*p = 0;
29 		printk("%s\n", buf);
30 		buf = p;
31 		if (buf)
32 			buf++;
33 	}
34 }
35 
uhci_is_skeleton_td(struct uhci * uhci,struct uhci_td * td)36 static int inline uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
37 {
38 	int i;
39 
40 	for (i = 0; i < UHCI_NUM_SKELTD; i++)
41 		if (td == uhci->skeltd[i])
42 			return 1;
43 
44 	return 0;
45 }
46 
uhci_is_skeleton_qh(struct uhci * uhci,struct uhci_qh * qh)47 static int inline uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
48 {
49 	int i;
50 
51 	for (i = 0; i < UHCI_NUM_SKELQH; i++)
52 		if (qh == uhci->skelqh[i])
53 			return 1;
54 
55 	return 0;
56 }
57 
uhci_show_td(struct uhci_td * td,char * buf,int len,int space)58 static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
59 {
60 	char *out = buf;
61 	char *spid;
62 
63 	/* Try to make sure there's enough memory */
64 	if (len < 160)
65 		return 0;
66 
67 	out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, td->link);
68 	out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
69 		((td->status >> 27) & 3),
70 		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
71 		(td->status & TD_CTRL_LS) ?       "LS " : "",
72 		(td->status & TD_CTRL_IOC) ?      "IOC " : "",
73 		(td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
74 		(td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
75 		(td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
76 		(td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
77 		(td->status & TD_CTRL_NAK) ?      "NAK " : "",
78 		(td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
79 		(td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
80 		td->status & 0x7ff);
81 
82 	switch (td->info & 0xff) {
83 		case USB_PID_SETUP:
84 			spid = "SETUP";
85 			break;
86 		case USB_PID_OUT:
87 			spid = "OUT";
88 			break;
89 		case USB_PID_IN:
90 			spid = "IN";
91 			break;
92 		default:
93 			spid = "?";
94 			break;
95 	}
96 
97 	out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
98 		td->info >> 21,
99 		((td->info >> 19) & 1),
100 		(td->info >> 15) & 15,
101 		(td->info >> 8) & 127,
102 		(td->info & 0xff),
103 		spid);
104 	out += sprintf(out, "(buf=%08x)\n", td->buffer);
105 
106 	return out - buf;
107 }
108 
uhci_show_sc(int port,unsigned short status,char * buf,int len)109 static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
110 {
111 	char *out = buf;
112 
113 	/* Try to make sure there's enough memory */
114 	if (len < 80)
115 		return 0;
116 
117 	out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
118 		port,
119 		status,
120 		(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
121 		(status & USBPORTSC_PR) ?   "PortReset " : "",
122 		(status & USBPORTSC_LSDA) ? "LowSpeed " : "",
123 		(status & USBPORTSC_RD) ?   "ResumeDetect " : "",
124 		(status & USBPORTSC_PEC) ?  "EnableChange " : "",
125 		(status & USBPORTSC_PE) ?   "PortEnabled " : "",
126 		(status & USBPORTSC_CSC) ?  "ConnectChange " : "",
127 		(status & USBPORTSC_CCS) ?  "PortConnected " : "");
128 
129 	return out - buf;
130 }
131 
uhci_show_status(struct uhci * uhci,char * buf,int len)132 static int uhci_show_status(struct uhci *uhci, char *buf, int len)
133 {
134 	char *out = buf;
135 	unsigned int io_addr = uhci->io_addr;
136 	unsigned short usbcmd, usbstat, usbint, usbfrnum;
137 	unsigned int flbaseadd;
138 	unsigned char sof;
139 	unsigned short portsc1, portsc2;
140 
141 	/* Try to make sure there's enough memory */
142 	if (len < 80 * 6)
143 		return 0;
144 
145 	usbcmd    = inw(io_addr + 0);
146 	usbstat   = inw(io_addr + 2);
147 	usbint    = inw(io_addr + 4);
148 	usbfrnum  = inw(io_addr + 6);
149 	flbaseadd = inl(io_addr + 8);
150 	sof       = inb(io_addr + 12);
151 	portsc1   = inw(io_addr + 16);
152 	portsc2   = inw(io_addr + 18);
153 
154 	out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
155 		usbcmd,
156 		(usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
157 		(usbcmd & USBCMD_CF) ?      "CF " : "",
158 		(usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
159 		(usbcmd & USBCMD_FGR) ?     "FGR " : "",
160 		(usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
161 		(usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
162 		(usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
163 		(usbcmd & USBCMD_RS) ?      "RS " : "");
164 
165 	out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
166 		usbstat,
167 		(usbstat & USBSTS_HCH) ?    "HCHalted " : "",
168 		(usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
169 		(usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
170 		(usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
171 		(usbstat & USBSTS_ERROR) ?  "USBError " : "",
172 		(usbstat & USBSTS_USBINT) ? "USBINT " : "");
173 
174 	out += sprintf(out, "  usbint    =     %04x\n", usbint);
175 	out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
176 		0xfff & (4*(unsigned int)usbfrnum));
177 	out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
178 	out += sprintf(out, "  sof       =       %02x\n", sof);
179 	out += uhci_show_sc(1, portsc1, out, len - (out - buf));
180 	out += uhci_show_sc(2, portsc2, out, len - (out - buf));
181 
182 	return out - buf;
183 }
184 
uhci_show_qh(struct uhci_qh * qh,char * buf,int len,int space)185 static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
186 {
187 	char *out = buf;
188 	struct urb_priv *urbp;
189 	struct list_head *head, *tmp;
190 	struct uhci_td *td;
191 	int i = 0, checked = 0, prevactive = 0;
192 
193 	/* Try to make sure there's enough memory */
194 	if (len < 80 * 6)
195 		return 0;
196 
197 	out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "",
198 			qh, qh->link, qh->element);
199 
200 	if (qh->element & UHCI_PTR_QH)
201 		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
202 
203 	if (qh->element & UHCI_PTR_DEPTH)
204 		out += sprintf(out, "%*s  Depth traverse\n", space, "");
205 
206 	if (qh->element & 8)
207 		out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
208 
209 	if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
210 		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
211 
212 	if (!qh->urbp) {
213 		out += sprintf(out, "%*s  urbp == NULL\n", space, "");
214 		goto out;
215 	}
216 
217 	urbp = qh->urbp;
218 
219 	head = &urbp->td_list;
220 	tmp = head->next;
221 
222 	td = list_entry(tmp, struct uhci_td, list);
223 
224 	if (td->dma_handle != (qh->element & ~UHCI_PTR_BITS))
225 		out += sprintf(out, "%*s Element != First TD\n", space, "");
226 
227 	while (tmp != head) {
228 		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
229 
230 		tmp = tmp->next;
231 
232 		out += sprintf(out, "%*s%d: ", space + 2, "", i++);
233 		out += uhci_show_td(td, out, len - (out - buf), 0);
234 
235 		if (i > 10 && !checked && prevactive && tmp != head &&
236 		    debug <= 2) {
237 			struct list_head *ntmp = tmp;
238 			struct uhci_td *ntd = td;
239 			int active = 1, ni = i;
240 
241 			checked = 1;
242 
243 			while (ntmp != head && ntmp->next != head && active) {
244 				ntd = list_entry(ntmp, struct uhci_td, list);
245 
246 				ntmp = ntmp->next;
247 
248 				active = ntd->status & TD_CTRL_ACTIVE;
249 
250 				ni++;
251 			}
252 
253 			if (active && ni > i) {
254 				out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
255 				tmp = ntmp;
256 				td = ntd;
257 				i = ni;
258 			}
259 		}
260 
261 		prevactive = td->status & TD_CTRL_ACTIVE;
262 	}
263 
264 	if (list_empty(&urbp->queue_list) || urbp->queued)
265 		goto out;
266 
267 	out += sprintf(out, "%*sQueued QH's:\n", -space, "--");
268 
269 	head = &urbp->queue_list;
270 	tmp = head->next;
271 
272 	while (tmp != head) {
273 		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
274 						queue_list);
275 		tmp = tmp->next;
276 
277 		out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
278 	}
279 
280 out:
281 	return out - buf;
282 }
283 
284 static const char *td_names[] = {"skel_int1_td", "skel_int2_td",
285 				 "skel_int4_td", "skel_int8_td",
286 				 "skel_int16_td", "skel_int32_td",
287 				 "skel_int64_td", "skel_int128_td",
288 				 "skel_int256_td", "skel_term_td" };
289 static const char *qh_names[] = { "skel_ls_control_qh", "skel_hs_control_qh",
290 				  "skel_bulk_qh", "skel_term_qh" };
291 
292 #define show_frame_num()	\
293 	if (!shown) {		\
294 	  shown = 1;		\
295 	  out += sprintf(out, "- Frame %d\n", i); \
296 	}
297 
298 #define show_td_name()		\
299 	if (!shown) {		\
300 	  shown = 1;		\
301 	  out += sprintf(out, "- %s\n", td_names[i]); \
302 	}
303 
304 #define show_qh_name()		\
305 	if (!shown) {		\
306 	  shown = 1;		\
307 	  out += sprintf(out, "- %s\n", qh_names[i]); \
308 	}
309 
uhci_sprint_schedule(struct uhci * uhci,char * buf,int len)310 static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len)
311 {
312 	char *out = buf;
313 	int i;
314 	struct uhci_qh *qh;
315 	struct uhci_td *td;
316 	struct list_head *tmp, *head;
317 
318 	out += sprintf(out, "HC status\n");
319 	out += uhci_show_status(uhci, out, len - (out - buf));
320 
321 	out += sprintf(out, "Frame List\n");
322 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
323 		int shown = 0;
324 		td = uhci->fl->frame_cpu[i];
325 		if (!td)
326 			continue;
327 
328 		if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
329 			show_frame_num();
330 			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
331 		}
332 		if (uhci_is_skeleton_td(uhci, td))
333 			continue;
334 		show_frame_num();
335 
336 		head = &td->fl_list;
337 		tmp = head;
338 		do {
339 			td = list_entry(tmp, struct uhci_td, fl_list);
340 			tmp = tmp->next;
341 			out += uhci_show_td(td, out, len - (out - buf), 4);
342 		} while (tmp != head);
343 	}
344 
345 	out += sprintf(out, "Skeleton TD's\n");
346 	for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) {
347 		int shown = 0;
348 
349 		td = uhci->skeltd[i];
350 
351 		if (debug > 1) {
352 			show_td_name();
353 			out += uhci_show_td(td, out, len - (out - buf), 4);
354 		}
355 
356 		if (list_empty(&td->fl_list)) {
357 			/* TD 0 is the int1 TD and links to control_ls_qh */
358 			if (!i) {
359 				if (td->link !=
360 				    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) {
361 					show_td_name();
362 					out += sprintf(out, "    skeleton TD not linked to ls_control QH!\n");
363 				}
364 			} else if (i < 9) {
365 				if (td->link != uhci->skeltd[i - 1]->dma_handle) {
366 					show_td_name();
367 					out += sprintf(out, "    skeleton TD not linked to next skeleton TD!\n");
368 				}
369 			} else {
370 				show_td_name();
371 
372 				if (td->link != td->dma_handle)
373 					out += sprintf(out, "    skel_term_td does not link to self\n");
374 
375 				/* Don't show it twice */
376 				if (debug <= 1)
377 					out += uhci_show_td(td, out, len - (out - buf), 4);
378 			}
379 
380 			continue;
381 		}
382 
383 		show_td_name();
384 
385 		head = &td->fl_list;
386 		tmp = head->next;
387 
388 		while (tmp != head) {
389 			td = list_entry(tmp, struct uhci_td, fl_list);
390 
391 			tmp = tmp->next;
392 
393 			out += uhci_show_td(td, out, len - (out - buf), 4);
394 		}
395 
396 		if (!i) {
397 			if (td->link !=
398 			    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH))
399 				out += sprintf(out, "    last TD not linked to ls_control QH!\n");
400 		} else if (i < 9) {
401 			if (td->link != uhci->skeltd[i - 1]->dma_handle)
402 				out += sprintf(out, "    last TD not linked to next skeleton!\n");
403 		}
404 	}
405 
406 	out += sprintf(out, "Skeleton QH's\n");
407 
408 	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
409 		int shown = 0;
410 
411 		qh = uhci->skelqh[i];
412 
413 		if (debug > 1) {
414 			show_qh_name();
415 			out += uhci_show_qh(qh, out, len - (out - buf), 4);
416 		}
417 
418 		/* QH 3 is the Terminating QH, it's different */
419 		if (i == 3) {
420 			if (qh->link != UHCI_PTR_TERM) {
421 				show_qh_name();
422 				out += sprintf(out, "    bandwidth reclamation on!\n");
423 			}
424 
425 			if (qh->element != uhci->skel_term_td->dma_handle) {
426 				show_qh_name();
427 				out += sprintf(out, "    skel_term_qh element is not set to skel_term_td\n");
428 			}
429 		}
430 
431 		if (list_empty(&qh->list)) {
432 			if (i < 3) {
433 				if (qh->link !=
434 				    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH)) {
435 					show_qh_name();
436 					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
437 				}
438 			}
439 
440 			continue;
441 		}
442 
443 		show_qh_name();
444 
445 		head = &qh->list;
446 		tmp = head->next;
447 
448 		while (tmp != head) {
449 			qh = list_entry(tmp, struct uhci_qh, list);
450 
451 			tmp = tmp->next;
452 
453 			out += uhci_show_qh(qh, out, len - (out - buf), 4);
454 		}
455 
456 		if (i < 3) {
457 			if (qh->link !=
458 			    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH))
459 				out += sprintf(out, "    last QH not linked to next skeleton!\n");
460 		}
461 	}
462 
463 	return out - buf;
464 }
465 
466 #ifdef CONFIG_PROC_FS
467 #define MAX_OUTPUT	(64 * 1024)
468 
469 static struct proc_dir_entry *uhci_proc_root = NULL;
470 
471 struct uhci_proc {
472 	int size;
473 	char *data;
474 	struct uhci *uhci;
475 };
476 
uhci_proc_open(struct inode * inode,struct file * file)477 static int uhci_proc_open(struct inode *inode, struct file *file)
478 {
479 	const struct proc_dir_entry *dp = inode->u.generic_ip;
480 	struct uhci *uhci = dp->data;
481 	struct uhci_proc *up;
482 	unsigned long flags;
483 	int ret = -ENOMEM;
484 
485 	lock_kernel();
486 	up = kmalloc(sizeof(*up), GFP_KERNEL);
487 	if (!up)
488 		goto out;
489 
490 	up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
491 	if (!up->data) {
492 		kfree(up);
493 		goto out;
494 	}
495 
496 	spin_lock_irqsave(&uhci->frame_list_lock, flags);
497 	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
498 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
499 
500 	file->private_data = up;
501 
502 	ret = 0;
503 out:
504 	unlock_kernel();
505 	return ret;
506 }
507 
uhci_proc_lseek(struct file * file,loff_t off,int whence)508 static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
509 {
510 	struct uhci_proc *up = file->private_data;
511 	loff_t new;
512 
513 	switch (whence) {
514 	case 0:
515 		new = off;
516 		break;
517 	case 1:
518 		new = file->f_pos + off;
519 		break;
520 	case 2:
521 	default:
522 		return -EINVAL;
523 	}
524 	if (new < 0 || new > up->size)
525 		return -EINVAL;
526 	return (file->f_pos = new);
527 }
528 
uhci_proc_read(struct file * file,char * buf,size_t nbytes,loff_t * ppos)529 static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
530 			loff_t *ppos)
531 {
532 	struct uhci_proc *up = file->private_data;
533 	loff_t n = *ppos;
534 	unsigned int pos = n;
535 	unsigned int size;
536 
537 	size = up->size;
538 	if (pos != n || pos >= size)
539 		return 0;
540 	if (nbytes > size - pos)
541 		nbytes = size - pos;
542 
543 	if (!access_ok(VERIFY_WRITE, buf, nbytes))
544 		return -EINVAL;
545 
546 	if (copy_to_user(buf, up->data + pos, nbytes))
547 		return -EFAULT;
548 
549 	*ppos = pos + nbytes;
550 
551 	return nbytes;
552 }
553 
uhci_proc_release(struct inode * inode,struct file * file)554 static int uhci_proc_release(struct inode *inode, struct file *file)
555 {
556 	struct uhci_proc *up = file->private_data;
557 
558 	kfree(up->data);
559 	kfree(up);
560 
561 	return 0;
562 }
563 
564 static struct file_operations uhci_proc_operations = {
565 	open:		uhci_proc_open,
566 	llseek:		uhci_proc_lseek,
567 	read:		uhci_proc_read,
568 //	write:		uhci_proc_write,
569 	release:	uhci_proc_release,
570 };
571 #endif
572 
573