usbxhci: implement portable dma flush operations and move to port/

This commit is contained in:
cinap_lenrek 2019-07-17 10:30:06 +02:00
parent 19a883ce7a
commit a6a1806c17
2 changed files with 134 additions and 73 deletions

View file

@ -101,7 +101,7 @@ random.$O: /sys/include/libsec.h
devaoe.$O sdaoe.$O: /sys/include/fis.h devaoe.$O sdaoe.$O: /sys/include/fis.h
sysproc.$O: /sys/include/a.out.h sysproc.$O: /sys/include/a.out.h
syscallfmt.$O: /sys/src/libc/9syscall/sys.h syscallfmt.$O: /sys/src/libc/9syscall/sys.h
devusb.$O: ../port/usb.h devusb.$O usbxhci.$O: ../port/usb.h
devether.$O ethersink.$O: ../port/etherif.h ../port/netif.h devether.$O ethersink.$O: ../port/etherif.h ../port/netif.h
wifi.$O: ../port/etherif.h ../port/netif.h ../port/wifi.h /sys/include/libsec.h wifi.$O: ../port/etherif.h ../port/netif.h ../port/wifi.h /sys/include/libsec.h
wifi.$O: ../ip/ip.h ../ip/ipv6.h wifi.$O: ../ip/ip.h ../ip/ipv6.h

View file

@ -5,7 +5,6 @@
#include "fns.h" #include "fns.h"
#include "io.h" #include "io.h"
#include "../port/error.h" #include "../port/error.h"
#include "../port/usb.h" #include "../port/usb.h"
enum { enum {
@ -29,6 +28,8 @@ enum {
DBOFF = 0x14/4, DBOFF = 0x14/4,
RTSOFF = 0x18/4, RTSOFF = 0x18/4,
HCCPARAMS2 = 0x1C/4,
/* Operational Registers */ /* Operational Registers */
USBCMD = 0x00/4, /* USB Command Register */ USBCMD = 0x00/4, /* USB Command Register */
RUNSTOP = 1<<0, /* Run/Stop - RW */ RUNSTOP = 1<<0, /* Run/Stop - RW */
@ -67,7 +68,7 @@ enum {
CONFIG = 0x38/4, /* Configure Register (MaxSlotEn[7:0]) */ CONFIG = 0x38/4, /* Configure Register (MaxSlotEn[7:0]) */
/* Port Register Set */ /* Port Register Set */
PORTSC = 0x00/4, /* Port tatus and Control Register */ PORTSC = 0x00/4, /* Port status and Control Register */
CCS = 1<<0, /* Current Connect Status - ROS */ CCS = 1<<0, /* Current Connect Status - ROS */
PED = 1<<1, /* Port Enable/Disabled - RW1CS */ PED = 1<<1, /* Port Enable/Disabled - RW1CS */
OCA = 1<<3, /* Over-current Active - RO */ OCA = 1<<3, /* Over-current Active - RO */
@ -194,6 +195,10 @@ struct Slot
{ {
int id; int id;
int confval; // bConfigurationValue of SET_CONFIGURATION
int iface; // bInterfaceNumber of SET_INTERFACE
int altc; // bAlternateSetting of SET_INTERFACE
Ctlr *ctlr; Ctlr *ctlr;
Udev *dev; Udev *dev;
@ -247,8 +252,6 @@ struct Ctlr
int nintrs; int nintrs;
int nslots; int nslots;
void (*setrptr)(u32int*, u64int);
Rendez recover; Rendez recover;
void *active; void *active;
uintptr base; uintptr base;
@ -274,21 +277,17 @@ static char Ebadlen[] = "bad usb request length";
static char Enotconfig[] = "usb endpoint not configured"; static char Enotconfig[] = "usb endpoint not configured";
static char Erecover[] = "xhci controller needs reset"; static char Erecover[] = "xhci controller needs reset";
static char*
ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er);
static void static void
setrptr32(u32int *reg, u64int pa) setrptr(u32int *reg, u64int pa)
{ {
coherence(); coherence();
reg[0] = pa; reg[0] = pa;
reg[1] = pa>>32; reg[1] = pa>>32;
} }
static void
setrptr64(u32int *reg, u64int pa)
{
coherence();
*((u64int*)reg) = pa;
}
static u32int static u32int
µframe(Ctlr *ctlr) µframe(Ctlr *ctlr)
{ {
@ -305,7 +304,10 @@ freering(Ring *r)
{ {
if(r == nil) if(r == nil)
return; return;
free(r->base); if(r->base != nil){
dmaflush(0, r->base, 4*4<<r->shift);
free(r->base);
}
memset(r, 0, sizeof(*r)); memset(r, 0, sizeof(*r));
} }
@ -326,6 +328,7 @@ initring(Ring *r, int shift)
freering(r); freering(r);
error(Enomem); error(Enomem);
} }
dmaflush(1, r->base, 4*4<<shift);
return r; return r;
} }
@ -353,7 +356,7 @@ resetring(Ring *r)
ilock(r); ilock(r);
flushring(r); flushring(r);
r->rp = r->wp; r->rp = r->wp;
pa = PADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1); pa = PCIWADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1);
iunlock(r); iunlock(r);
return pa; return pa;
@ -433,7 +436,11 @@ release(Ctlr *ctlr)
free(ctlr->slot), ctlr->slot = nil; free(ctlr->slot), ctlr->slot = nil;
free(ctlr->dcba), ctlr->dcba = nil; free(ctlr->dcba), ctlr->dcba = nil;
free(ctlr->sba), ctlr->sba = nil; free(ctlr->sba), ctlr->sba = nil;
free(ctlr->sbp), ctlr->sbp = nil; if(ctlr->sbp != nil){
dmaflush(0, ctlr->sbp, ctlr->nscratch*ctlr->pagesize);
free(ctlr->sbp);
ctlr->sbp = nil;
}
} }
static void recover(void *arg); static void recover(void *arg);
@ -479,10 +486,6 @@ init(Hci *hp)
} }
ctlr->csz = (ctlr->hccparams & CSZ) != 0; ctlr->csz = (ctlr->hccparams & CSZ) != 0;
if(ctlr->hccparams & AC64)
ctlr->setrptr = setrptr64;
else
ctlr->setrptr = setrptr32;
ctlr->pagesize = (ctlr->opr[PAGESIZE] & 0xFFFF) << 12; ctlr->pagesize = (ctlr->opr[PAGESIZE] & 0xFFFF) << 12;
ctlr->nscratch = (ctlr->mmio[HCSPARAMS2] >> 27) & 0x1F | (ctlr->mmio[HCSPARAMS2] >> 16) & 0x3E0; ctlr->nscratch = (ctlr->mmio[HCSPARAMS2] >> 27) & 0x1F | (ctlr->mmio[HCSPARAMS2] >> 16) & 0x3E0;
@ -515,7 +518,7 @@ init(Hci *hp)
} }
ctlr->slot = malloc((1+ctlr->nslots)*sizeof(ctlr->slot[0])); ctlr->slot = malloc((1+ctlr->nslots)*sizeof(ctlr->slot[0]));
ctlr->dcba = mallocalign((1+ctlr->nslots)*8, 64, 0, ctlr->pagesize); ctlr->dcba = mallocalign((1+ctlr->nslots)*sizeof(ctlr->dcba[0]), 64, 0, ctlr->pagesize);
if(ctlr->slot == nil || ctlr->dcba == nil) if(ctlr->slot == nil || ctlr->dcba == nil)
error(Enomem); error(Enomem);
if(ctlr->nscratch != 0){ if(ctlr->nscratch != 0){
@ -525,49 +528,61 @@ init(Hci *hp)
error(Enomem); error(Enomem);
for(i=0, p = ctlr->sbp; i<ctlr->nscratch; i++, p += ctlr->pagesize){ for(i=0, p = ctlr->sbp; i<ctlr->nscratch; i++, p += ctlr->pagesize){
memset(p, 0, ctlr->pagesize); memset(p, 0, ctlr->pagesize);
ctlr->sba[i] = PADDR(p); ctlr->sba[i] = PCIWADDR(p);
} }
ctlr->dcba[0] = PADDR(ctlr->sba); dmaflush(1, ctlr->sbp, ctlr->nscratch*ctlr->pagesize);
dmaflush(1, ctlr->sba, ctlr->nscratch*8);
ctlr->dcba[0] = PCIWADDR(ctlr->sba);
} else { } else {
ctlr->dcba[0] = 0; ctlr->dcba[0] = 0;
} }
for(i=1; i<=ctlr->nslots; i++) for(i=1; i<=ctlr->nslots; i++)
ctlr->dcba[i] = 0; ctlr->dcba[i] = 0;
ctlr->opr[CONFIG] = (ctlr->opr[CONFIG] & 0xFFFFFC00) | ctlr->nslots; /* MaxSlotsEn */ ctlr->opr[CONFIG] = (ctlr->opr[CONFIG] & 0xFFFFFC00) | ctlr->nslots; /* MaxSlotsEn */
ctlr->setrptr(&ctlr->opr[DCBAAP], PADDR(ctlr->dcba));
dmaflush(1, ctlr->dcba, (1+ctlr->nslots)*sizeof(ctlr->dcba[0]));
setrptr(&ctlr->opr[DCBAAP], PCIWADDR(ctlr->dcba));
initring(ctlr->cr, 8); /* 256 entries */ initring(ctlr->cr, 8); /* 256 entries */
ctlr->cr->id = 0; ctlr->cr->id = 0;
ctlr->cr->doorbell = &ctlr->dba[0]; ctlr->cr->doorbell = &ctlr->dba[0];
ctlr->setrptr(&ctlr->opr[CRCR], resetring(ctlr->cr)); setrptr(&ctlr->opr[CRCR], resetring(ctlr->cr));
for(i=0; i<ctlr->nintrs; i++){ for(i=0; i<ctlr->nintrs; i++){
u32int *irs = &ctlr->rts[IR0 + i*8]; u32int *irs = &ctlr->rts[IR0 + i*8];
if(i >= nelem(ctlr->er)){ if(i >= nelem(ctlr->er)){
irs[ERSTSZ] = 0; /* disable ring */ irs[ERSTSZ] = 0; /* disable ring */
irs[IMAN] = 1;
irs[IMOD] = 0;
setrptr(&irs[ERSTBA], 0);
setrptr(&irs[ERDP], 0);
continue; continue;
} }
/* allocate and link into event ring segment table */ /* allocate and link into event ring segment table */
initring(&ctlr->er[i], 8); /* 256 entries */ initring(&ctlr->er[i], 8); /* 256 entries */
ctlr->erst[i] = mallocalign(16, 64, 0, 0); ctlr->erst[i] = mallocalign(4*4, 64, 0, 0);
if(ctlr->erst[i] == nil) if(ctlr->erst[i] == nil)
error(Enomem); error(Enomem);
*((u64int*)ctlr->erst[i]) = PADDR(ctlr->er[i].base); *((u64int*)ctlr->erst[i]) = PCIWADDR(ctlr->er[i].base);
ctlr->erst[i][2] = ctlr->er[i].mask+1; ctlr->erst[i][2] = ctlr->er[i].mask+1;
ctlr->erst[i][3] = 0; ctlr->erst[i][3] = 0;
dmaflush(1, ctlr->erst[i], 4*4);
irs[ERSTSZ] = 1; /* just one segment */ irs[ERSTSZ] = 1; /* just one segment */
ctlr->setrptr(&irs[ERDP], PADDR(ctlr->er[i].base));
ctlr->setrptr(&irs[ERSTBA], PADDR(ctlr->erst[i]));
irs[IMAN] = 3; irs[IMAN] = 3;
irs[IMOD] = 0; irs[IMOD] = 0;
setrptr(&irs[ERSTBA], PCIWADDR(ctlr->erst[i]));
setrptr(&irs[ERDP], PCIWADDR(ctlr->er[i].base) | (1<<3));
} }
poperror(); poperror();
ctlr->µframe = 0; ctlr->µframe = 0;
ctlr->opr[USBSTS] = ctlr->opr[USBSTS] & (HSE|EINT|PCD|SRE);
coherence();
ctlr->opr[USBCMD] = RUNSTOP|INTE|HSEE|EWE; ctlr->opr[USBCMD] = RUNSTOP|INTE|HSEE|EWE;
for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != 0 && i<100; i++) for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != 0 && i<100; i++)
tsleep(&up->sleep, return0, nil, 10); tsleep(&up->sleep, return0, nil, 10);
@ -592,8 +607,7 @@ recover(void *arg)
while(waserror()) while(waserror())
; ;
while(!needrecover(ctlr)) while(!needrecover(ctlr))
tsleep(&ctlr->recover, needrecover, ctlr, 1000); tsleep(&ctlr->recover, needrecover, ctlr, 10);
shutdown(hp); shutdown(hp);
/* /*
@ -662,9 +676,10 @@ queuetd(Ring *r, u32int c, u32int s, u64int p, Wait *w)
x = r->wp++; x = r->wp++;
if((x & r->mask) == r->mask){ if((x & r->mask) == r->mask){
td = r->base + 4*(x & r->mask); td = r->base + 4*(x & r->mask);
*(u64int*)td = PADDR(r->base); *(u64int*)td = PCIWADDR(r->base);
td[2] = 0; td[2] = 0;
td[3] = ((~x>>r->shift)&1) | (1<<1) | TR_LINK; td[3] = ((~x>>r->shift)&1) | (1<<1) | TR_LINK;
dmaflush(1, td, 4*4);
x = r->wp++; x = r->wp++;
} }
td = r->base + 4*(x & r->mask); td = r->base + 4*(x & r->mask);
@ -683,6 +698,7 @@ queuetd(Ring *r, u32int c, u32int s, u64int p, Wait *w)
*(u64int*)td = p; *(u64int*)td = p;
td[2] = s; td[2] = s;
td[3] = ((~x>>r->shift)&1) | c; td[3] = ((~x>>r->shift)&1) | c;
dmaflush(1, td, 4*4);
} }
static char *ccerrtab[] = { static char *ccerrtab[] = {
@ -741,9 +757,6 @@ waitdone(void *a)
return ((Wait*)a)->z == nil; return ((Wait*)a)->z == nil;
} }
static char*
ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er);
static char* static char*
waittd(Ctlr *ctlr, Wait *w, int tmout) waittd(Ctlr *ctlr, Wait *w, int tmout)
{ {
@ -780,7 +793,6 @@ waittd(Ctlr *ctlr, Wait *w, int tmout)
sleep(&up->sleep, waitdone, w); sleep(&up->sleep, waitdone, w);
} }
poperror(); poperror();
return ccerrstr(w->er[2]>>24); return ccerrstr(w->er[2]>>24);
} }
@ -798,7 +810,6 @@ ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er)
ctlr->cr->stopped = 0; ctlr->cr->stopped = 0;
queuetd(ctlr->cr, c, s, p, w); queuetd(ctlr->cr, c, s, p, w);
err = waittd(ctlr, w, 5000); err = waittd(ctlr, w, 5000);
qunlock(&ctlr->cmdlock); qunlock(&ctlr->cmdlock);
if(er != nil) if(er != nil)
@ -819,7 +830,7 @@ completering(Ring *r, u32int *er)
for(x = r->rp; (int)(r->wp - x) > 0;){ for(x = r->rp; (int)(r->wp - x) > 0;){
td = &r->base[4*(x++ & r->mask)]; td = &r->base[4*(x++ & r->mask)];
if((u64int)PADDR(td) == pa){ if((u64int)PCIWADDR(td) == pa){
r->rp = x; r->rp = x;
break; break;
} }
@ -827,7 +838,7 @@ completering(Ring *r, u32int *er)
wp = &r->pending; wp = &r->pending;
while(w = *wp){ while(w = *wp){
if((u64int)PADDR(w->td) == pa){ if((u64int)PCIWADDR(w->td) == pa){
Rendez *z = w->z; Rendez *z = w->z;
memmove(w->er, er, 4*4); memmove(w->er, er, 4*4);
@ -865,6 +876,8 @@ interrupt(Ureg*, void *arg)
for(x = ring->rp;; x=++ring->rp){ for(x = ring->rp;; x=++ring->rp){
td = ring->base + 4*(x & ring->mask); td = ring->base + 4*(x & ring->mask);
dmaflush(0, td, 4*4);
if((((x>>ring->shift)^td[3])&1) == 0) if((((x>>ring->shift)^td[3])&1) == 0)
break; break;
@ -902,7 +915,7 @@ interrupt(Ureg*, void *arg)
} }
} }
ctlr->setrptr(&irs[ERDP], PADDR(td) | (1<<3)); setrptr(&irs[ERDP], PCIWADDR(td) | (1<<3));
} }
static void static void
@ -918,7 +931,9 @@ freeslot(void *arg)
qlock(&ctlr->slotlock); qlock(&ctlr->slotlock);
if(ctlr->slot != nil && ctlr->slot[slot->id] == slot){ if(ctlr->slot != nil && ctlr->slot[slot->id] == slot){
ctlrcmd(ctlr, CR_DISABLESLOT | (slot->id<<24), 0, 0, nil); ctlrcmd(ctlr, CR_DISABLESLOT | (slot->id<<24), 0, 0, nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
ctlr->dcba[slot->id] = 0; ctlr->dcba[slot->id] = 0;
dmaflush(1, &ctlr->dcba[slot->id], sizeof(ctlr->dcba[0]));
ctlr->slot[slot->id] = nil; ctlr->slot[slot->id] = nil;
} }
qunlock(&ctlr->slotlock); qunlock(&ctlr->slotlock);
@ -945,6 +960,10 @@ allocslot(Ctlr *ctlr, Udev *dev)
slot->nep = 0; slot->nep = 0;
slot->id = 0; slot->id = 0;
slot->confval = 0;
slot->iface = 0;
slot->altc = 0;
qlock(&ctlr->slotlock); qlock(&ctlr->slotlock);
if(waserror()){ if(waserror()){
qunlock(&ctlr->slotlock); qunlock(&ctlr->slotlock);
@ -957,6 +976,7 @@ allocslot(Ctlr *ctlr, Udev *dev)
slot->obase = mallocalign(32*32 << ctlr->csz, 64, 0, ctlr->pagesize); slot->obase = mallocalign(32*32 << ctlr->csz, 64, 0, ctlr->pagesize);
if(slot->ibase == nil || slot->obase == nil) if(slot->ibase == nil || slot->obase == nil)
error(Enomem); error(Enomem);
if((err = ctlrcmd(ctlr, CR_ENABLESLOT, 0, 0, r)) != nil) if((err = ctlrcmd(ctlr, CR_ENABLESLOT, 0, 0, r)) != nil)
error(err); error(err);
slot->id = r[3]>>24; slot->id = r[3]>>24;
@ -966,8 +986,12 @@ allocslot(Ctlr *ctlr, Udev *dev)
} }
poperror(); poperror();
ctlr->dcba[slot->id] = PADDR(slot->obase); dmaflush(1, slot->obase, 32*32 << ctlr->csz);
ctlr->dcba[slot->id] = PCIWADDR(slot->obase);
dmaflush(1, &ctlr->dcba[slot->id], sizeof(ctlr->dcba[0]));
ctlr->slot[slot->id] = slot; ctlr->slot[slot->id] = slot;
qunlock(&ctlr->slotlock); qunlock(&ctlr->slotlock);
return slot; return slot;
@ -1025,7 +1049,9 @@ epclose(Ep *ep)
w += ep->nb*2*8<<ctlr->csz; w += ep->nb*2*8<<ctlr->csz;
memset(w, 0, 2*32<<ctlr->csz); memset(w, 0, 2*32<<ctlr->csz);
ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PADDR(slot->ibase), nil); dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
freering(io[OREAD].ring); freering(io[OREAD].ring);
freering(io[OWRITE].ring); freering(io[OWRITE].ring);
@ -1048,12 +1074,11 @@ initepctx(u32int *w, Ring *r, Ep *ep)
; ;
} }
w[0] = ival<<16; w[0] = ival<<16;
w[1] = ((ep->ttype-Tctl)|(r->id&1)<<2)<<3 | (ep->ntds-1)<<8 | ep->maxpkt<<16; w[1] = ((ep->ttype-Tctl) | (r->id&1)<<2)<<3 | (ep->ntds-1)<<8 | ep->maxpkt<<16;
if(ep->ttype != Tiso) if(ep->ttype != Tiso)
w[1] |= 3<<1; w[1] |= 3<<1;
*((u64int*)&w[2]) = PADDR(r->base) | 1; *((u64int*)&w[2]) = PCIWADDR(r->base) | 1;
w[4] = 2*ep->maxpkt;
w[4] = ep->maxpkt;
if(ep->ttype == Tintr || ep->ttype == Tiso) if(ep->ttype == Tintr || ep->ttype == Tiso)
w[4] |= (ep->maxpkt*ep->ntds)<<16; w[4] |= (ep->maxpkt*ep->ntds)<<16;
} }
@ -1094,6 +1119,7 @@ initep(Ep *ep)
w = slot->ibase; w = slot->ibase;
memset(w, 0, 32<<ctlr->csz); memset(w, 0, 32<<ctlr->csz);
w[1] = 1; w[1] = 1;
w[31] = slot->altc<<16 | slot->iface<<8 | slot->confval;
if(waserror()){ if(waserror()){
freering(io[OWRITE].ring), io[OWRITE].ring = nil; freering(io[OWRITE].ring), io[OWRITE].ring = nil;
@ -1124,21 +1150,28 @@ initep(Ep *ep)
/* (input) slot context */ /* (input) slot context */
w += 8<<ctlr->csz; w += 8<<ctlr->csz;
w[0] = (w[0] & ~(0x1F<<27)) | slot->nep<<27; w[0] = (w[0] & ~(0x1F<<27)) | slot->nep<<27;
if(!ep->dev->ishub)
w[0] &= ~(1<<25); // MTT
/* (input) ep context */ /* (input) ep context */
w += ep->nb*2*8<<ctlr->csz; w += ep->nb*2*8<<ctlr->csz;
memset(w, 0, 2*32<<ctlr->csz); if(io[OWRITE].ring != nil){
if(io[OWRITE].ring != nil) memset(w, 0, 5*4);
initepctx(w, io[OWRITE].ring, ep); initepctx(w, io[OWRITE].ring, ep);
}
w += 8<<ctlr->csz; w += 8<<ctlr->csz;
if(io[OREAD].ring != nil) if(io[OREAD].ring != nil){
memset(w, 0, 5*4);
initepctx(w, io[OREAD].ring, ep); initepctx(w, io[OREAD].ring, ep);
if((err = ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0,
PADDR(slot->ibase), nil)) != nil){
error(err);
} }
dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
err = ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
if(err != nil)
error(err);
if(ep->ttype == Tiso){ if(ep->ttype == Tiso){
initisoio(io+OWRITE, ep); initisoio(io+OWRITE, ep);
initisoio(io+OREAD, ep); initisoio(io+OREAD, ep);
@ -1217,8 +1250,7 @@ epopen(Ep *ep)
w += 8<<ctlr->csz; w += 8<<ctlr->csz;
w[2] = w[3] = 0; w[2] = w[3] = 0;
w[0] = dev->routestr | speedid(dev->speed)<<20 | w[0] = dev->routestr | speedid(dev->speed)<<20 |
(dev->speed == Highspeed && dev->ishub != 0 (dev->speed == Highspeed && dev->ishub != 0)<<25 | // MTT
||dev->speed < Highspeed && dev->ishub == 0)<<25 |
(dev->ishub != 0)<<26 | slot->nep<<27; (dev->ishub != 0)<<26 | slot->nep<<27;
w[1] = dev->rootport<<16; w[1] = dev->rootport<<16;
@ -1237,8 +1269,10 @@ epopen(Ep *ep)
if(hub->dev->rootport != dev->rootport) if(hub->dev->rootport != dev->rootport)
continue; continue;
if(dev->speed < Highspeed && hub->dev->speed == Highspeed) if(dev->speed < Highspeed && hub->dev->speed == Highspeed){
w[0] |= 1<<25; // MTT
w[2] = hub->id | dev->port<<8; w[2] = hub->id | dev->port<<8;
}
break; break;
} }
qunlock(&ctlr->slotlock); qunlock(&ctlr->slotlock);
@ -1247,10 +1281,11 @@ epopen(Ep *ep)
w += 8<<ctlr->csz; w += 8<<ctlr->csz;
initepctx(w, io[OWRITE].ring, ep); initepctx(w, io[OWRITE].ring, ep);
if((err = ctlrcmd(ctlr, CR_ADDRESSDEV | (slot->id<<24), 0, dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
PADDR(slot->ibase), nil)) != nil){ err = ctlrcmd(ctlr, CR_ADDRESSDEV | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
if(err != nil)
error(err); error(err);
}
/* (output) slot context */ /* (output) slot context */
w = slot->obase; w = slot->obase;
@ -1314,7 +1349,8 @@ isowrite(Ep *ep, uchar *p, long n)
p += m, n -= m; p += m, n -= m;
m += io->nleft, d -= io->nleft; m += io->nleft, d -= io->nleft;
io->nleft = 0; io->nleft = 0;
queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m, PADDR(d), nil); dmaflush(1, d, m);
queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m, PCIWADDR(d), nil);
} }
io->frame = i; io->frame = i;
while(io->ring->rp != io->ring->wp){ while(io->ring->rp != io->ring->wp){
@ -1359,6 +1395,7 @@ static long
epread(Ep *ep, void *va, long n) epread(Ep *ep, void *va, long n)
{ {
Epio *io; Epio *io;
Ctlr *ctlr;
uchar *p; uchar *p;
char *err; char *err;
Wait w[1]; Wait w[1];
@ -1398,9 +1435,11 @@ epread(Ep *ep, void *va, long n)
return n; return n;
} }
ctlr = (Ctlr*)ep->hp->aux;
io = (Epio*)ep->aux + OREAD; io = (Epio*)ep->aux + OREAD;
qlock(io); qlock(io);
if(waserror()){ if(waserror()){
dmaflush(0, io->ring->ctx, 8*4 << ctlr->csz);
qunlock(io); qunlock(io);
nexterror(); nexterror();
} }
@ -1408,8 +1447,11 @@ epread(Ep *ep, void *va, long n)
if((err = unstall(io->ring)) != nil) if((err = unstall(io->ring)) != nil)
error(err); error(err);
queuetd(io->ring, TR_NORMAL | TR_IOC, n, PADDR(p), w); dmaflush(1, p, n);
if((err = waittd((Ctlr*)ep->hp->aux, w, ep->tmout)) != nil) queuetd(io->ring, TR_NORMAL | TR_IOC, n, PCIWADDR(p), w);
err = waittd(ctlr, w, ep->tmout);
dmaflush(0, p, n);
if(err != nil)
error(err); error(err);
qunlock(io); qunlock(io);
@ -1426,6 +1468,7 @@ static long
epwrite(Ep *ep, void *va, long n) epwrite(Ep *ep, void *va, long n)
{ {
Wait w[3]; Wait w[3];
Ctlr *ctlr;
Epio *io; Epio *io;
uchar *p; uchar *p;
char *err; char *err;
@ -1437,6 +1480,7 @@ epwrite(Ep *ep, void *va, long n)
if(ep->ttype == Tctl){ if(ep->ttype == Tctl){
int dir, len; int dir, len;
Ring *ring; Ring *ring;
Slot *slot;
if(n < 8) if(n < 8)
error(Eshort); error(Eshort);
@ -1444,13 +1488,16 @@ epwrite(Ep *ep, void *va, long n)
if(p[0] == 0x00 && p[1] == 0x05) if(p[0] == 0x00 && p[1] == 0x05)
return n; return n;
ctlr = (Ctlr*)ep->hp->aux;
io = (Epio*)ep->aux + OREAD; io = (Epio*)ep->aux + OREAD;
ring = io[OWRITE-OREAD].ring; ring = io[OWRITE-OREAD].ring;
slot = ring->slot;
qlock(io); qlock(io);
if(waserror()){ if(waserror()){
ilock(ring); ilock(ring);
ring->pending = nil; ring->pending = nil;
iunlock(ring); iunlock(ring);
dmaflush(0, ring->ctx, 8*4 << ctlr->csz);
qunlock(io); qunlock(io);
nexterror(); nexterror();
} }
@ -1474,39 +1521,50 @@ epwrite(Ep *ep, void *va, long n)
error(err); error(err);
if((ring->ctx[1]>>16) != ep->maxpkt){ if((ring->ctx[1]>>16) != ep->maxpkt){
Slot *slot = ring->slot;
Ctlr *ctlr = slot->ctlr;
u32int *w = slot->ibase; u32int *w = slot->ibase;
w[0] = 0; w[0] = 0;
w[1] = 1<<ring->id; w[1] = 1<<ring->id;
w += (ring->id+1)*8<<ctlr->csz; w += (ring->id+1)*8<<ctlr->csz;
initepctx(w, ring, ep); initepctx(w, ring, ep);
if((err = ctlrcmd(ctlr, CR_EVALCTX | (slot->id<<24), 0, PADDR(slot->ibase), nil)) != nil) dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
err = ctlrcmd(ctlr, CR_EVALCTX | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
if(err != nil)
error(err); error(err);
} }
queuetd(ring, TR_SETUPSTAGE | (len > 0 ? 2+dir : 0)<<16 | TR_IDT | TR_IOC, 8, queuetd(ring, TR_SETUPSTAGE | (len > 0 ? 2+dir : 0)<<16 | TR_IDT | TR_IOC, 8,
p[0] | p[1]<<8 | GET2(&p[2])<<16 | p[0] | p[1]<<8 | GET2(&p[2])<<16 |
(u64int)(GET2(&p[4]) | len<<16)<<32, &w[0]); (u64int)(GET2(&p[4]) | len<<16)<<32, &w[0]);
if(len > 0) if(len > 0){
dmaflush(1, io->b->rp, len);
queuetd(ring, TR_DATASTAGE | dir<<16 | TR_IOC, len, queuetd(ring, TR_DATASTAGE | dir<<16 | TR_IOC, len,
PADDR(io->b->rp), &w[1]); PCIWADDR(io->b->rp), &w[1]);
}
queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | TR_IOC, 0, 0, &w[2]); queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | TR_IOC, 0, 0, &w[2]);
if((err = waittd((Ctlr*)ep->hp->aux, &w[0], ep->tmout)) != nil) if((err = waittd(ctlr, &w[0], ep->tmout)) != nil)
error(err); error(err);
if(len > 0){ if(len > 0){
if((err = waittd((Ctlr*)ep->hp->aux, &w[1], ep->tmout)) != nil) if((err = waittd(ctlr, &w[1], ep->tmout)) != nil)
error(err); error(err);
if(dir != 0){ if(dir != 0){
dmaflush(0, io->b->rp, len);
io->b->wp -= (w[1].er[2] & 0xFFFFFF); io->b->wp -= (w[1].er[2] & 0xFFFFFF);
if(io->b->wp < io->b->rp) if(io->b->wp < io->b->rp)
io->b->wp = io->b->rp; io->b->wp = io->b->rp;
} }
} }
if((err = waittd((Ctlr*)ep->hp->aux, &w[2], ep->tmout)) != nil) if((err = waittd(ctlr, &w[2], ep->tmout)) != nil)
error(err); error(err);
if(p[0] == 0x00 && p[1] == 0x09){
slot->confval = GET2(&p[2]);
} else if(p[0] == 0x01 && p[1] == 0x0d){
slot->altc = GET2(&p[2]);
slot->iface = GET2(&p[4]);
}
qunlock(io); qunlock(io);
poperror(); poperror();
@ -1529,9 +1587,11 @@ epwrite(Ep *ep, void *va, long n)
return n; return n;
} }
ctlr = (Ctlr*)ep->hp->aux;
io = (Epio*)ep->aux + OWRITE; io = (Epio*)ep->aux + OWRITE;
qlock(io); qlock(io);
if(waserror()){ if(waserror()){
dmaflush(0, io->ring->ctx, 8*4 << ctlr->csz);
qunlock(io); qunlock(io);
nexterror(); nexterror();
} }
@ -1539,8 +1599,9 @@ epwrite(Ep *ep, void *va, long n)
if((err = unstall(io->ring)) != nil) if((err = unstall(io->ring)) != nil)
error(err); error(err);
queuetd(io->ring, TR_NORMAL | TR_IOC, n, PADDR(p), w); dmaflush(1, p, n);
if((err = waittd((Ctlr*)ep->hp->aux, w, ep->tmout)) != nil) queuetd(io->ring, TR_NORMAL | TR_IOC, n, PCIWADDR(p), w);
if((err = waittd(ctlr, w, ep->tmout)) != nil)
error(err); error(err);
qunlock(io); qunlock(io);