ref: 6e65596827f7ee292221697ff5248c9bc9520851
parent: 215b67ff3d630c56418026dda7ae68f23111c4a5
author: cinap_lenrek <[email protected]>
date: Sun Jul 30 23:22:23 EDT 2017
xhci: experimental usb3 support
--- a/sys/src/9/pc/usbohci.c
+++ b/sys/src/9/pc/usbohci.c
@@ -949,7 +949,7 @@
case Tctl:
cio = ep->aux;
s = seprintio(s, e, cio, "c");
- s = seprint(s, e, "\trepl %d ndata %d\n", ep->rhrepl, cio->ndata);
+ s = seprint(s, e, "\trepl %llux ndata %d\n", ep->rhrepl, cio->ndata);
break;
case Tbulk:
case Tintr:
--- a/sys/src/9/pc/usbxhci.c
+++ b/sys/src/9/pc/usbxhci.c
@@ -387,8 +387,10 @@
ctlr->nscratch = (ctlr->mmio[HCSPARAMS2] >> 27) & 0x1F;
ctlr->nintrs = (ctlr->mmio[HCSPARAMS1] >> 8) & 0x7FF;
ctlr->nslots = (ctlr->mmio[HCSPARAMS1] >> 0) & 0xFF;
- hp->nports = (ctlr->mmio[HCSPARAMS1] >> 24) & 0xFF;
+ hp->highspeed = 1;
+ hp->superspeed = 0;
+ hp->nports = (ctlr->mmio[HCSPARAMS1] >> 24) & 0xFF;
ctlr->port = malloc(hp->nports * sizeof(Port));
for(i=0; i<hp->nports; i++)
ctlr->port[i].reg = &ctlr->opr[0x400/4 + i*4];
@@ -403,6 +405,8 @@
pp = &ctlr->port[i-1];
pp->proto = x[0]>>16;
memmove(pp->spec, &x[1], 4);
+ if(memcmp(pp->spec, "USB ", 4) == 0 && pp->proto >= 0x0300)
+ hp->superspeed |= 1<<(i-1);
i++;
}
}
@@ -1151,6 +1155,9 @@
char *err;
Wait ws[1];
+ if(ep->dev->isroot)
+ error(Egreg);
+
p = va;
if(ep->ttype == Tctl){
io = (Epio*)ep->aux + OREAD;
@@ -1212,6 +1219,9 @@
uchar *p;
char *err;
+ if(ep->dev->isroot)
+ error(Egreg);
+
p = va;
if(ep->ttype == Tctl){
int dir, len;
@@ -1335,41 +1345,46 @@
{
Ctlr *ctlr = hp->aux;
Port *pp = &ctlr->port[port-1];
- u32int psc = pp->reg[PORTSC];
- int ps = 0;
+ u32int psc, ps = 0;
- if(memcmp(pp->spec, "USB", 3) != 0 || pp->proto > 0x0200)
- return 0;
-
+ psc = pp->reg[PORTSC];
if(psc & CCS) ps |= HPpresent;
if(psc & PED) ps |= HPenable;
if(psc & OCA) ps |= HPovercurrent;
if(psc & PR) ps |= HPreset;
- else {
- switch((psc>>10)&0xF){
- case 1:
- /* full speed */
- break;
- case 2:
- ps |= HPslow;
- break;
- case 3:
- ps |= HPhigh;
- break;
- case 4: /* super speed */
- break;
+
+ if((hp->superspeed & (1<<(port-1))) != 0){
+ ps |= psc & (PLS|PP);
+ if(psc & CSC) ps |= 1<<0+16;
+ if(psc & OCC) ps |= 1<<3+16;
+ if(psc & PRC) ps |= 1<<4+16;
+ if(psc & WRC) ps |= 1<<5+16;
+ if(psc & PLC) ps |= 1<<6+16;
+ if(psc & CEC) ps |= 1<<7+16;
+ } else {
+ if((ps & HPreset) == 0){
+ switch((psc>>10)&15){
+ case 1:
+ /* full speed */
+ break;
+ case 2:
+ ps |= HPslow;
+ break;
+ case 3:
+ ps |= HPhigh;
+ break;
+ }
}
+ if(psc & PP) ps |= HPpower;
+ if(psc & CSC) ps |= HPstatuschg;
+ if(psc & PRC) ps |= HPchange;
}
- if(psc & PP) ps |= HPpower;
- if(psc & CSC) ps |= HPstatuschg;
- if(psc & PRC) ps |= HPchange;
-
return ps;
}
static int
-portenable(Hci *, int, int)
+portenable(Hci *, int port, int on)
{
return 0;
}
@@ -1379,9 +1394,6 @@
{
Ctlr *ctlr = hp->aux;
Port *pp = &ctlr->port[port-1];
-
- if(memcmp(pp->spec, "USB", 3) != 0 || pp->proto > 0x0200)
- return 0;
if(on){
pp->reg[PORTSC] |= PR;
--- a/sys/src/9/port/devusb.c
+++ b/sys/src/9/port/devusb.c
@@ -73,7 +73,7 @@
/* Ep. ctls */
CMnew = 0, /* new nb ctl|bulk|intr|iso r|w|rw (endpoint) */
- CMnewdev, /* newdev full|low|high portnb (allocate new devices) */
+ CMnewdev, /* newdev full|low|high|super portnb (allocate new devices) */
CMhub, /* hub (set the device as a hub) */
CMspeed, /* speed full|low|high|no */
CMmaxpkt, /* maxpkt size */
@@ -296,6 +296,7 @@
s = seprint(s, se, " hz %ld", ep->hz);
s = seprint(s, se, " hub %d", ep->dev->hub);
s = seprint(s, se, " port %d", ep->dev->port);
+ s = seprint(s, se, " rootport %d", ep->dev->rootport);
s = seprint(s, se, " addr %d", ep->dev->addr);
if(ep->inuse)
s = seprint(s, se, " busy");
@@ -474,11 +475,8 @@
d->isroot = isroot;
d->rootport = 0;
d->routestr = 0;
- d->depth = 0;
- if(hp->highspeed != 0)
- d->speed = Highspeed;
- else
- d->speed = Fullspeed;
+ d->depth = -1;
+ d->speed = Fullspeed;
d->state = Dconfig; /* address not yet set */
ep->dev = d;
ep->ep0 = ep; /* no ref counted here */
@@ -746,6 +744,17 @@
print("usbreset: bug: Nhcis (%d) too small\n", Nhcis);
}
+static int
+numbits(uint n)
+{
+ int c = 0;
+ while(n != 0){
+ c++;
+ n = (n-1) & n;
+ }
+ return c;
+}
+
static void
usbinit(void)
{
@@ -758,13 +767,31 @@
for(ctlrno = 0; ctlrno < Nhcis; ctlrno++){
hp = hcis[ctlrno];
if(hp != nil){
+ int n;
+
if(hp->init != nil)
hp->init(hp);
- d = newdev(hp, 1, 1); /* new root hub */
- d->dev->state = Denabled; /* although addr == 0 */
- d->maxpkt = 64;
- snprint(info, sizeof(info), "ports %d", hp->nports);
- kstrdup(&d->info, info);
+
+ hp->superspeed &= (1<<hp->nports)-1;
+ n = hp->nports - numbits(hp->superspeed);
+ if(n > 0){
+ d = newdev(hp, 1, 1); /* new LS/FS/HS root hub */
+ d->maxpkt = 64;
+ if(hp->highspeed != 0)
+ d->dev->speed = Highspeed;
+ d->dev->state = Denabled; /* although addr == 0 */
+ snprint(info, sizeof(info), "roothub ports %d", n);
+ kstrdup(&d->info, info);
+ }
+ n = numbits(hp->superspeed);
+ if(n > 0){
+ d = newdev(hp, 1, 1); /* new SS root hub */
+ d->maxpkt = 512;
+ d->dev->speed = Superspeed;
+ d->dev->state = Denabled; /* although addr == 0 */
+ snprint(info, sizeof(info), "roothub ports %d", n);
+ kstrdup(&d->info, info);
+ }
}
}
}
@@ -805,6 +832,7 @@
l = 0;
bs = 10UL * maxpkt;
switch(speed){
+ case Superspeed:
case Highspeed:
l = 55*8*2 + 2 * (3 + bs) + Hostns;
break;
@@ -985,20 +1013,57 @@
static long
rhubread(Ep *ep, void *a, long n)
{
- char *b;
+ uchar b[8];
- if(ep->dev->isroot == 0 || ep->nb != 0 || n < 2)
+ if(ep->dev->isroot == 0 || ep->nb != 0 || n < 2 || ep->rhrepl == -1)
return -1;
- if(ep->rhrepl < 0)
- return -1;
- b = a;
- memset(b, 0, n);
- PUT2(b, ep->rhrepl);
+ b[0] = ep->rhrepl;
+ b[1] = ep->rhrepl>>8;
+ b[2] = ep->rhrepl>>16;
+ b[3] = ep->rhrepl>>24;
+ b[4] = ep->rhrepl>>32;
+ b[5] = ep->rhrepl>>40;
+ b[6] = ep->rhrepl>>48;
+ b[7] = ep->rhrepl>>56;
+
ep->rhrepl = -1;
+
+ if(n > sizeof(b))
+ n = sizeof(b);
+ memmove(a, b, n);
+
return n;
}
+static int
+rootport(Ep *ep, int port)
+{
+ Hci *hp;
+ Udev *hub;
+ uint mask;
+ int rootport;
+
+ hp = ep->hp;
+ hub = ep->dev;
+ if(!hub->isroot)
+ return hub->rootport;
+
+ mask = hp->superspeed;
+ if(hub->speed != Superspeed)
+ mask = (1<<hp->nports)-1 & ~mask;
+
+ for(rootport = 1; mask != 0; rootport++){
+ if(mask & 1){
+ if(--port == 0)
+ return rootport;
+ }
+ mask >>= 1;
+ }
+
+ return 0;
+}
+
static long
rhubwrite(Ep *ep, void *a, long n)
{
@@ -1019,8 +1084,8 @@
hp = ep->hp;
cmd = s[Rreq];
feature = GET2(s+Rvalue);
- port = GET2(s+Rindex);
- if(port < 1 || port > hp->nports)
+ port = rootport(ep, GET2(s+Rindex));
+ if(port == 0)
error("bad hub port number");
switch(feature){
case Rportenable:
@@ -1089,16 +1154,15 @@
{
long spp, max; /* samples per packet */
- if(ep->dev->speed == Highspeed || ep->dev->speed == Superspeed)
- spp = (ep->hz * ep->pollival * ep->ntds + 7999) / 8000;
- else
+ if(ep->dev->speed == Fullspeed)
spp = (ep->hz * ep->pollival + 999) / 1000;
+ else
+ spp = (ep->hz * ep->pollival * ep->ntds + 7999) / 8000;
ep->maxpkt = spp * ep->samplesz;
deprint("usb: %s: setmaxpkt: hz %ld poll %ld"
" ntds %d %s speed -> spp %ld maxpkt %ld\n", s,
ep->hz, ep->pollival, ep->ntds, spname[ep->dev->speed],
spp, ep->maxpkt);
-
switch(ep->dev->speed){
case Fullspeed:
max = 1024;
@@ -1170,16 +1234,20 @@
error("not a hub setup endpoint");
l = name2speed(cb->f[1]);
if(l == Nospeed)
- error("speed must be full|low|high");
+ error("speed must be full|low|high|super");
+ if(l != d->speed && (l == Superspeed || d->speed == Superspeed))
+ error("wrong speed for superspeed hub/device");
nep = newdev(ep->hp, 0, 0);
nep->dev->speed = l;
- if(nep->dev->speed != Lowspeed)
+ if(l == Superspeed)
+ nep->maxpkt = 512;
+ else if(l != Lowspeed)
nep->maxpkt = 64; /* assume full speed */
nep->dev->hub = d->addr;
nep->dev->port = atoi(cb->f[2]);
nep->dev->depth = d->depth+1;
- nep->dev->rootport = d->depth == 0 ? nep->dev->port : d->rootport;
- nep->dev->routestr = d->routestr | ((nep->dev->port&15) << 4*d->depth) >> 4;
+ nep->dev->rootport = rootport(ep, nep->dev->port);
+ nep->dev->routestr = d->routestr | (((nep->dev->port&15) << 4*nep->dev->depth) >> 4);
/* next read request will read
* the name for the new endpoint
*/
@@ -1195,7 +1263,9 @@
l = name2speed(cb->f[1]);
deprint("usb epctl %s %d\n", cb->f[0], l);
if(l == Nospeed)
- error("speed must be full|low|high");
+ error("speed must be full|low|high|super");
+ if(l != d->speed && (l == Superspeed || d->speed == Superspeed))
+ error("cannot change speed on superspeed device");
qlock(ep->ep0);
d->speed = l;
qunlock(ep->ep0);
@@ -1223,13 +1293,13 @@
error("not an intr or iso endpoint");
l = strtoul(cb->f[1], nil, 0);
deprint("usb epctl %s %d\n", cb->f[0], l);
- if(ep->dev->speed == Highspeed || ep->dev->speed == Superspeed){
+ if(ep->dev->speed == Fullspeed || ep->dev->speed == Lowspeed){
+ if(l < 1 || l > 255)
+ error("pollival not in [1:255]");
+ } else {
if(l < 1 || l > 16)
error("pollival power not in [1:16]");
l = 1 << l-1;
- } else {
- if(l < 1 || l > 255)
- error("pollival not in [1:255]");
}
qlock(ep);
ep->pollival = l;
--- a/sys/src/9/port/usb.h
+++ b/sys/src/9/port/usb.h
@@ -128,7 +128,8 @@
int tbdf; /* type+busno+devno+funcno */
int ctlrno; /* controller number */
int nports; /* number of ports in hub */
- int highspeed;
+ int highspeed; /* supports highspeed devices */
+ uint superspeed; /* bitmap of superspeed ports */
Hciimpl; /* HCI driver */
};
@@ -164,7 +165,7 @@
int ttype; /* tranfer type */
ulong load; /* in µs, for a transfer of maxpkt bytes */
void* aux; /* for controller specific info */
- int rhrepl; /* fake root hub replies */
+ u64int rhrepl; /* fake root hub replies */
int toggle[2]; /* saved toggles (while ep is not in use) */
long pollival; /* poll interval ([µ]frames; intr/iso) */
long hz; /* poll frequency (iso) */
@@ -184,7 +185,7 @@
int state; /* state for the device */
int ishub; /* hubs can allocate devices */
int isroot; /* is a root hub */
- int speed; /* Full/Low/High/No -speed */
+ int speed; /* Full/Low/High/Super/No -speed */
int hub; /* device address for the parent hub */
int port; /* port number in the parent hub */
int addr; /* device address */
--- a/sys/src/9/port/usbehci.c
+++ b/sys/src/9/port/usbehci.c
@@ -1803,7 +1803,7 @@
case Tctl:
cio = ep->aux;
s = seprintio(s, e, cio, "c");
- s = seprint(s, e, "\trepl %d ndata %d\n", ep->rhrepl, cio->ndata);
+ s = seprint(s, e, "\trepl %llux ndata %d\n", ep->rhrepl, cio->ndata);
break;
case Tbulk:
case Tintr: