Browse Source

Plan 9 from Bell Labs 2009-11-15

David du Colombier 14 years ago
parent
commit
d758a03eb2
5 changed files with 90 additions and 84 deletions
  1. 47 30
      sys/src/9/kw/devusb.c
  2. 5 2
      sys/src/9/kw/usb.h
  3. 30 49
      sys/src/9/kw/usbehci.c
  4. 7 2
      sys/src/9/kw/usbehci.h
  5. 1 1
      sys/src/9/pc/usb.h

+ 47 - 30
sys/src/9/kw/devusb.c

@@ -71,7 +71,6 @@ enum
 	/* Usb ctls. */
 	CMdebug = 0,		/* debug on|off */
 	CMdump,			/* dump (data structures for debug) */
-	CMreset,		/* reset the bus; start over */
 
 	/* Ep. ctls */
 	CMnew = 0,		/* new nb ctl|bulk|intr|iso r|w|rw (endpoint) */
@@ -89,6 +88,8 @@ enum
 	CMaddress,		/* address (address is assigned) */
 	CMdebugep,		/* debug n (set/clear debug for this ep) */
 	CMname,			/* name str (show up as #u/name as well) */
+	CMtmout,		/* timeout n (activate timeouts for ep) */
+	CMpreset,		/* reset the port */
 
 	/* Hub feature selectors */
 	Rportenable	= 1,
@@ -112,7 +113,6 @@ static Cmdtab usbctls[] =
 {
 	{CMdebug,	"debug",	2},
 	{CMdump,	"dump",		1},
-	{CMreset,	"reset",	1},
 };
 
 static Cmdtab epctls[] =
@@ -132,6 +132,8 @@ static Cmdtab epctls[] =
 	{CMdebugep,	"debug",	2},
 	{CMclrhalt,	"clrhalt",	1},
 	{CMname,	"name",		2},
+	{CMtmout,	"timeout",	2},
+	{CMpreset,	"reset",	1},
 };
 
 static Dirtab usbdir[] =
@@ -267,7 +269,7 @@ addhcitype(char* t, int (*r)(Hci*))
 static char*
 seprintep(char *s, char *se, Ep *ep, int all)
 {
-	static char* dsnames[] = { "config", "enabled", "detached" };
+	static char* dsnames[] = { "config", "enabled", "detached", "reset" };
 	Udev *d;
 	int i;
 	int di;
@@ -303,6 +305,8 @@ seprintep(char *s, char *se, Ep *ep, int all)
 		s = seprint(s, se, " idx %d", ep->idx);
 		if(ep->name != nil)
 			s = seprint(s, se, " name '%s'", ep->name);
+		if(ep->tmout != 0)
+			s = seprint(s, se, " tmout");
 		if(ep == ep->ep0){
 			s = seprint(s, se, " ctlrno %#x", ep->hp->ctlrno);
 			s = seprint(s, se, " eps:");
@@ -312,7 +316,7 @@ seprintep(char *s, char *se, Ep *ep, int all)
 		}
 	}
 	if(ep->info != nil)
-		s = seprint(s, se, "\n%s\n", ep->info);
+		s = seprint(s, se, "\n%s %s\n", ep->info, ep->hp->type);
 	else
 		s = seprint(s, se, "\n");
 	qunlock(ep);
@@ -336,7 +340,7 @@ epalloc(Hci *hp)
 		qunlock(&epslck);
 		free(ep);
 		print("usb: bug: too few endpoints.\n");
-		return nil;	
+		return nil;
 	}
 	ep->idx = i;
 	if(epmax <= i)
@@ -467,6 +471,7 @@ newdev(Hci *hp, int ishub, int isroot)
 	ep->dev = d;
 	ep->ep0 = ep;			/* no ref counted here */
 	ep->ttype = Tctl;
+	ep->tmout = Xfertmout;
 	ep->mode = ORDWR;
 	dprint("newdev %#p ep%d.%d %#p\n", d, d->nb, ep->nb, ep);
 	return ep;
@@ -495,11 +500,20 @@ newdevep(Ep *ep, int i, int tt, int mode)
 	nep->mode = mode;
 	nep->ttype = tt;
 	nep->debug = ep->debug;
-	if(tt == Tintr || tt == Tiso)	/* assign defaults */
+	/* set defaults */
+	switch(tt){
+	case Tctl:
+		nep->tmout = Xfertmout;
+		break;
+	case Tintr:
+		nep->pollival = 10;
+		break;
+	case Tiso:
+		nep->tmout = Xfertmout;
 		nep->pollival = 10;
-	if(tt == Tiso){
 		nep->samplesz = 4;
 		nep->hz = 44100;
+		break;
 	}
 	deprint("newdevep ep%d.%d %#p\n", d->nb, nep->nb, nep);
 	return ep;
@@ -643,7 +657,6 @@ usbgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
 Fail:
 	if(0)ddprint("fail\n");
 	return -1;
-	
 }
 
 static Hci*
@@ -683,7 +696,8 @@ hciprobe(int cardno, int ctlrno)
 	snprint(name, sizeof(name), "usb%s", hcitypes[cardno].type);
 	intrenable(Irqlo, hp->irq, hp->interrupt, hp, name);
 	print("#u/usb/ep%d.0: %s: port 0x%luX irq %d\n",
-		epnb++, hcitypes[cardno].type, hp->port, hp->irq);
+		epnb, hcitypes[cardno].type, hp->port, hp->irq);
+	epnb++;
 	return hp;
 }
 
@@ -1112,7 +1126,7 @@ epctl(Ep *ep, Chan *c, void *a, long n)
 	if(ct == nil)
 		error(Ebadctl);
 	i = ct->index;
-	if(i == CMnew || i == CMspeed || i == CMhub)
+	if(i == CMnew || i == CMspeed || i == CMhub || i == CMpreset)
 		if(ep != ep->ep0)
 			error("allowed only on a setup endpoint");
 	if(i != CMclrhalt && i != CMdetach && i != CMdebugep && i != CMname)
@@ -1279,6 +1293,22 @@ epctl(Ep *ep, Chan *c, void *a, long n)
 		validname(cb->f[1], 0);
 		kstrdup(&ep->name, cb->f[1]);
 		break;
+	case CMtmout:
+		deprint("usb epctl %s\n", cb->f[0]);
+		if(ep->ttype == Tiso || ep->ttype == Tctl)
+			error("ctl ignored for this endpoint type");
+		ep->tmout = strtoul(cb->f[1], nil, 0);
+		if(ep->tmout != 0 && ep->tmout < Xfertmout)
+			ep->tmout = Xfertmout;
+		break;
+	case CMpreset:
+		deprint("usb epctl %s\n", cb->f[0]);
+		if(ep->ttype != Tctl)
+			error("not a control endpoint");
+		if(ep->dev->state != Denabled)
+			error("forbidden on devices not enabled");
+		ep->dev->state = Dreset;
+		break;
 	default:
 		panic("usb: unknown epctl %d", ct->index);
 	}
@@ -1317,18 +1347,6 @@ usbctl(void *a, long n)
 				putep(ep);
 			}
 		break;
-	case CMreset:
-		print("devusb: CMreset not implemented\n");
-		error("not implemented");
-		/*
-		 * XXX: I'm not sure this is a good idea.
-		 * Usbd should not be restarted at all.
-		 * for(all eps)
-		 *	closeep(ep);
-		 * do a global reset once more
-		 * recreate root hub devices in place.
-		 */
-		break;
 	case CMdump:
 		dumpeps();
 		break;
@@ -1418,18 +1436,17 @@ usbwrite(Chan *c, void *a, long n, vlong off)
 void
 usbshutdown(void)
 {
-	Hci *hci;
+	Hci *hp;
 	int i;
 
 	for(i = 0; i < Nhcis; i++){
-		hci = hcis[i];
-		if(hci == nil)
-			continue;
-		if(hci->shutdown == nil) {
-			print("#l%d: no shutdown function\n", i);
+		hp = hcis[i];
+		if(hp == nil)
 			continue;
-		}
-		(*hci->shutdown)(hci);
+		if(hp->shutdown == nil)
+			print("#u: no shutdown function for %s\n", hp->type);
+		else
+			hp->shutdown(hp);
 	}
 }
 

+ 5 - 2
sys/src/9/kw/usb.h

@@ -14,7 +14,8 @@ enum
 	/* tunable parameters */
 	Nhcis	= 16,		/* max nb. of HCIs */
 	Neps	= 64,		/* max nb. of endpoints */
-	Maxctllen = 8*1024,	/* max allowed sized for ctl. xfers */
+	Maxctllen = 16*1024,	/* max allowed sized for ctl. xfers */
+	Xfertmout = 2000,	/* default request time out (ms) */
 
 	/* transfer types. keep this order */
 	Tnone = 0,		/* no tranfer type configured */
@@ -61,6 +62,7 @@ enum
 	Dconfig	 = 0,		/* configuration in progress */
 	Denabled,		/* address assigned */
 	Ddetach,		/* device is detached */
+	Dreset,			/* its port is being reset */
 
 	/* (root) Hub reply to port status (reported to usbd) */
 	HPpresent	= 0x1,
@@ -118,7 +120,7 @@ struct Hci
 	int	ctlrno;				/* controller number */
 	int	nports;				/* number of ports in hub */
 	int	highspeed;
-	Hciimpl;				/* HCI driver  */
+	Hciimpl;					/* HCI driver  */
 };
 
 /*
@@ -159,6 +161,7 @@ struct Ep
 	long	hz;		/* poll frequency (iso) */
 	long	samplesz;	/* sample size (iso) */
 	int	ntds;		/* nb. of Tds per µframe */
+	int	tmout;		/* 0 or timeout for transfers (ms) */
 };
 
 /*

+ 30 - 49
sys/src/9/kw/usbehci.c

@@ -49,9 +49,6 @@ enum
 
 	Enabledelay	= 100,		/* waiting for a port to enable */
 	Abortdelay	= 5,		/* delay after cancelling Tds (ms) */
-	Ctltmout	= 2000,		/* timeout for a ctl. request (ms) */
-	Bulktmout	= 2000,		/* timeout for a bulk xfer. (ms) */
-	Isotmout	= 2000,		/* timeout for an iso. request (ms) */
 
 	Incr		= 64,		/* for pools of Tds, Qhs, etc. */
 	Align		= 128,		/* in bytes for all those descriptors */
@@ -412,14 +409,14 @@ ehcirun(Ctlr *ctlr, int on)
 		opio->cmd |= Crun;
 	else
 		opio->cmd = Cstop;
-	for(i = 0; i < 1000; i++)			/* was 100 */
+	for(i = 0; i < 100; i++)
 		if(on == 0 && (opio->sts & Shalted) != 0)
 			break;
 		else if(on != 0 && (opio->sts & Shalted) == 0)
 			break;
 		else
 			delay(1);
-	if(i >= 1000)
+	if(i == 100)
 		print("ehci %#p %s cmd timed out\n",
 			ctlr->capio, on ? "run" : "halt");
 	ddprint("ehci %#p cmd %#ulx sts %#ulx\n", ctlr->capio, opio->cmd, opio->sts);
@@ -428,8 +425,7 @@ ehcirun(Ctlr *ctlr, int on)
 static void*
 edalloc(void)
 {
-	Ed *ed;
-	Ed *pool;
+	Ed *ed, *pool;
 	int i;
 
 	lock(&edpool);
@@ -1457,7 +1453,6 @@ qhinterrupt(Ctlr *ctlr, Qh *qh)
 {
 	Td *td;
 	int err;
-	char buf[256];
 
 	if(qh->state != Qrun)
 		panic("qhinterrupt: qh state");
@@ -1470,10 +1465,6 @@ qhinterrupt(Ctlr *ctlr, Qh *qh)
 			return 0;
 		if((td->csw & Tderrors) != 0){
 			err = td->csw & Tderrors;
-if(debug || qh->io->debug){
-seprinttd(buf, buf+sizeof(buf), td, "intr-fail-td");
-print("qh %#p io %#p\n\t%s\n", qh, qh->io, buf);
-}
 			if(qh->io->err == nil){
 				qh->io->err = errmsg(td->csw & Tderrors);
 				dqprint("qhintr: td %#p csw %#ulx error %#ux %s\n",
@@ -1930,7 +1921,7 @@ episoread(Ep *ep, Isoio *iso, void *a, long count)
 			ilock(ctlr);
 			break;
 		}
-		tsleep(iso, isocanread, iso, Isotmout);
+		tsleep(iso, isocanread, iso, ep->tmout);
 		poperror();
 		ilock(ctlr);
 	}
@@ -2030,7 +2021,7 @@ episowrite(Ep *ep, Isoio *iso, void *a, long count)
 				ilock(ctlr);
 				break;
 			}
-			tsleep(iso, isocanwrite, iso, Isotmout);
+			tsleep(iso, isocanwrite, iso, ep->tmout);
 			poperror();
 			ilock(ctlr);
 		}
@@ -2262,30 +2253,24 @@ epiowait(Hci *hp, Qio *io, int tmout, ulong load)
  * Non iso I/O.
  * To make it work for control transfers, the caller may
  * lock the Qio for the entire control transfer.
- * If tmout is not 0 it is a timeout value in ms.
- *
  */
 static long
-epio(Ep *ep, Qio *io, void *a, long count, int tmout, int mustlock)
+epio(Ep *ep, Qio *io, void *a, long count, int mustlock)
 {
-	Td *td;
-	Td *ltd;
-	Td *td0;
-	Td *ntd;
+	Td *td, *ltd, *td0, *ntd;
 	Ctlr *ctlr;
 	Qh* qh;
-	long n;
-	long tot;
+	long n, tot;
 	char buf[128];
 	uchar *c;
-	int saved;
-	int ntds;
+	int saved, ntds, tmout;
 	ulong load;
 	char *err;
 
 	qh = io->qh;
 	ctlr = ep->hp->aux;
 	io->debug = ep->debug;
+	tmout = ep->tmout;
 	ddeprint("epio: %s ep%d.%d io %#p count %ld load %uld\n",
 		io->tok == Tdtokin ? "in" : "out",
 		ep->dev->nb, ep->nb, io, count, ctlr->load);
@@ -2448,7 +2433,7 @@ epread(Ep *ep, void *a, long count)
 		io = ep->aux;
 		if(ep->clrhalt)
 			clrhalt(ep);
-		return epio(ep, &io[OREAD], a, count, Bulktmout, 1);
+		return epio(ep, &io[OREAD], a, count, 1);
 	case Tintr:
 		io = ep->aux;
 		delta = TK2MS(MACHP(0)->ticks) - io[OREAD].iotime + 1;
@@ -2456,7 +2441,7 @@ epread(Ep *ep, void *a, long count)
 			tsleep(&up->sleep, return0, 0, ep->pollival/2 - delta);
 		if(ep->clrhalt)
 			clrhalt(ep);
-		return epio(ep, &io[OREAD], a, count, 0, 1);
+		return epio(ep, &io[OREAD], a, count, 1);
 	case Tiso:
 		iso = ep->aux;
 		return episoread(ep, iso, a, count);
@@ -2500,17 +2485,18 @@ epctlio(Ep *ep, Ctlio *cio, void *a, long count)
 	}
 
 	/* set the address if unset and out of configuration state */
-	if(ep->dev->state != Dconfig && cio->usbid == 0){
-		cio->usbid = ((ep->nb&Epmax)<<7)|(ep->dev->nb&Devmax);
-		qhsetaddr(cio->qh, cio->usbid);
-	}
+	if(ep->dev->state != Dconfig && ep->dev->state != Dreset)
+		if(cio->usbid == 0){
+			cio->usbid = ((ep->nb&Epmax)<<7)|(ep->dev->nb&Devmax);
+			qhsetaddr(cio->qh, cio->usbid);
+		}
 	/* adjust maxpkt if the user has learned a different one */
 	if(qhmaxpkt(cio->qh) != ep->maxpkt)
 		qhsetmaxpkt(cio->qh, ep->maxpkt);
 	c = a;
 	cio->tok = Tdtoksetup;
 	cio->toggle = Tddata0;
-	if(epio(ep, cio, a, Rsetuplen, Ctltmout, 0) < Rsetuplen)
+	if(epio(ep, cio, a, Rsetuplen, 0) < Rsetuplen)
 		error(Eio);
 	a = c + Rsetuplen;
 	count -= Rsetuplen;
@@ -2532,7 +2518,7 @@ epctlio(Ep *ep, Ctlio *cio, void *a, long count)
 		if(waserror())
 			len = -1;
 		else{
-			len = epio(ep, cio, a, len, Ctltmout, 0);
+			len = epio(ep, cio, a, len, 0);
 			poperror();
 		}
 	if(c[Rtype] & Rd2h){
@@ -2547,7 +2533,7 @@ epctlio(Ep *ep, Ctlio *cio, void *a, long count)
 		cio->tok = Tdtokin;
 	}
 	cio->toggle = Tddata1;
-	epio(ep, cio, nil, 0, Ctltmout, 0);
+	epio(ep, cio, nil, 0, 0);
 	qunlock(cio);
 	poperror();
 	ddeprint("epctlio cio %#p return %ld\n", cio, count);
@@ -2575,7 +2561,7 @@ epwrite(Ep *ep, void *a, long count)
 		io = ep->aux;
 		if(ep->clrhalt)
 			clrhalt(ep);
-		return epio(ep, &io[OWRITE], a, count, Bulktmout, 1);
+		return epio(ep, &io[OWRITE], a, count, 1);
 	case Tintr:
 		io = ep->aux;
 		delta = TK2MS(MACHP(0)->ticks) - io[OWRITE].iotime + 1;
@@ -2583,7 +2569,7 @@ epwrite(Ep *ep, void *a, long count)
 			tsleep(&up->sleep, return0, 0, ep->pollival - delta);
 		if(ep->clrhalt)
 			clrhalt(ep);
-		return epio(ep, &io[OWRITE], a, count, 0, 1);
+		return epio(ep, &io[OWRITE], a, count, 1);
 	case Tiso:
 		iso = ep->aux;
 		return episowrite(ep, iso, a, count);
@@ -2725,11 +2711,9 @@ isoopen(Ctlr *ctlr, Ep *ep)
 	if(iso->nframes < 3)
 		error("uhci isoopen bug");	/* we need at least 3 tds */
 	iso->maxsize = ep->ntds * ep->maxpkt;
+	if(ctlr->load + ep->load > 800)
+		print("usb: ehci: bandwidth may be exceeded\n");
 	ilock(ctlr);
-	if(ctlr->load + ep->load > 800){
-		iunlock(ctlr);
-		error("bandwidth exceeded");
-	}
 	ctlr->load += ep->load;
 	ctlr->isoload += ep->load;
 	ctlr->nreqs++;
@@ -3044,7 +3028,6 @@ epclose(Ep *ep)
 static void
 scanpci(void)		/* actually just use fixed addresses on sheeva */
 {
-	int i = 0;
 	Ctlr *ctlr;
 	static int already = 0;
 
@@ -3058,9 +3041,7 @@ scanpci(void)		/* actually just use fixed addresses on sheeva */
 	ctlr->opio  = (Eopio *) (Addrusb + 0x140);
 	dprint("usbehci: port %#p\n", ctlr->capio);
 
-	if(i == Nhcis)
-		print("ehci: bug: no more controllers\n");
-	ctlrs[i] = ctlr;
+	ctlrs[0] = ctlr;
 }
 
 /*
@@ -3142,7 +3123,7 @@ ehcimeminit(Ctlr *ctlr)
 	int i;
 
 	opio = ctlr->opio;
-	frsize = ctlr->nframes * sizeof(ulong);
+	frsize = ctlr->nframes*sizeof(ulong);
 	assert((frsize & 0xFFF) == 0);		/* must be 4k aligned */
 	ctlr->frames = xspanalloc(frsize, frsize, 0);
 	if(ctlr->frames == nil)
@@ -3179,10 +3160,10 @@ init(Hci *hp)
 	 * some machines won't post other interrupts.
 	 */
 	opio->intr = Iusb|Ierr|Iportchg|Ihcerr|Iasync;
-	opio->config = Callmine;	/* reclaim all ports */
 	opio->cmd |= Cpse;
 	opio->cmd |= Case;
 	ehcirun(ctlr, 1);
+	opio->config = Callmine;	/* reclaim all ports */
 
 	for (i = 0; i < hp->nports; i++)
 		opio->portsc[i] = Pspower;
@@ -3201,6 +3182,7 @@ ehcireset(Ctlr *ctlr)
 
 	ilock(ctlr);
 	dprint("ehci %#p reset\n", ctlr->capio);
+	opio = ctlr->opio;
 
 	/*
 	 * Turn off legacy mode. Some controllers won't
@@ -3213,10 +3195,9 @@ ehcireset(Ctlr *ctlr)
 	 */
 	if((ctlr->capio->capparms & C64) != 0){
 		dprint("ehci: 64 bits\n");
-		ctlr->opio->seg = 0;
+		opio->seg = 0;
 	}
 
-	opio = ctlr->opio;
 	opio->cmd |= Chcreset;	/* controller reset */
 	for(i = 0; i < 100; i++){
 		if((opio->cmd & Chcreset) == 0)
@@ -3239,7 +3220,7 @@ ehcireset(Ctlr *ctlr)
 		ctlr->nframes = 256;
 		break;
 	default:
-		panic("ehci: unknown fls %#lux", opio->cmd & Cflsmask);
+		panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
 	}
 	dprint("ehci: %d frames\n", ctlr->nframes);
 	iunlock(ctlr);

+ 7 - 2
sys/src/9/kw/usbehci.h

@@ -11,6 +11,11 @@ enum
 	Cdbgportshift	= 20,,		/* debug port in Ecapio parms. */
 	Cdbgportmask	= 0xF,
 	C64		= 1,		/* 64-bits, in Ecapio capparms. */
+	Ceecpshift	= 8,		/* extended capabilities ptr. in */
+	Ceecpmask	= 8,		/* the Ecapio capparms reg. */
+	Clegacy		= 1,		/* legacy support cap. id */
+	CLbiossem	= 2,		/* legacy cap. bios sem. */
+	CLossem		= 3,		/* legacy cap. os sem */
 
 	/* typed links  */
 	Lterm		= 1,
@@ -75,7 +80,7 @@ enum
 
 	/* Debug port csw reg. */
 	Cowner	= 0x40000000,		/* port owned by ehci */
-	Cenable	= 0x20000000,		/* debug port enabled */
+	Cenable	= 0x10000000,		/* debug port enabled */
 	Cdone	= 0x00010000,		/* request is done */
 	Cbusy	= 0x00000400,		/* port in use by a driver */
 	Cerrmask= 0x00000380,		/* error code bits */
@@ -95,7 +100,7 @@ enum
 	Ptokmask	= 0xFF,
 
 	Ptoggle		= 0x00008800,	/* to update toggles */
-	Ptogglemask	= 0x00FFFF00,
+	Ptogglemask	= 0x0000FF00,
 
 	/* Debug port addr reg. */
 	Adevshift	= 8,		/* device address */

+ 1 - 1
sys/src/9/pc/usb.h

@@ -109,6 +109,7 @@ struct Hciimpl
 	int	(*portenable)(Hci*, int, int);	/* enable/disable port */
 	int	(*portreset)(Hci*, int, int);	/* set/clear port reset */
 	int	(*portstatus)(Hci*, int);	/* get port status */
+	void	(*shutdown)(Hci*);		/* shutdown for reboot */
 	void	(*debug)(Hci*, int);		/* set/clear debug flag */
 };
 
@@ -120,7 +121,6 @@ struct Hci
 	int	nports;				/* number of ports in hub */
 	int	highspeed;
 	Hciimpl;					/* HCI driver  */
-
 };
 
 /*