ref: cf2f89c648d55fd28d29213763f276f523fb22c6
parent: 7eddb7fa7b965aeae238115e87d94db686d13614
author: cinap_lenrek <[email protected]>
date: Sat Dec 3 11:15:12 EST 2022
usbxhci: split usbxhci in portable and pci / soc specific drivers For the reform kernel, we used to have a slightly modified copy of port/usbxhci.c as the controller was implemented in soc specific registers and requires some rocket science initialization. Instead, we want to have a common generic xhci driver (usbxhci) and separate drivers that deal with the specific implementation such as usbxhcipci and usbxhciimx.
--- a/sys/src/9/bcm64/pi4
+++ b/sys/src/9/bcm64/pi4
@@ -29,7 +29,7 @@
gisb
pcibcm
archbcm4 pci
- usbxhci pci archbcm4
+ usbxhcipci pci usbxhci archbcm4
ethergenet ethermii
ethermedium
loopbackmedium
--- a/sys/src/9/imx8/mkfile
+++ b/sys/src/9/imx8/mkfile
@@ -90,6 +90,7 @@
main.$O: rebootcode.i
pciimx.$O: ../port/pci.h
+usbxhciimx.$O: ../port/usbxhci.h
initcode.out: init9.$O initcode.$O /$objtype/lib/libc.a
$LD -l -R1 -s -o $target $prereq
--- a/sys/src/9/imx8/reform
+++ b/sys/src/9/imx8/reform
@@ -26,7 +26,7 @@
audio
link
- usbxhciimx
+ usbxhciimx usbxhci
etherimx ethermii
ethermedium
loopbackmedium
--- a/sys/src/9/imx8/usbxhciimx.c
+++ b/sys/src/9/imx8/usbxhciimx.c
@@ -6,1769 +6,9 @@
#include "io.h"
#include "../port/error.h"
#include "../port/usb.h"
+#include "../port/usbxhci.h"
-enum {
- /* Capability Registers */
- CAPLENGTH = 0x00/4, // 1
- HCIVERSION = 0x02/4, // 2
- HCSPARAMS1 = 0x04/4,
- HCSPARAMS2 = 0x08/4,
- HCSPARAMS3 = 0x0C/4,
-
- HCCPARAMS = 0x10/4,
- AC64 = 1<<0,
- BNC = 1<<1,
- CSZ = 1<<2,
- PPC = 1<<3,
- PIND = 1<<4,
- LHRC = 1<<5,
- LTC = 1<<6,
- NSS = 1<<7,
-
- DBOFF = 0x14/4,
- RTSOFF = 0x18/4,
-
- HCCPARAMS2 = 0x1C/4,
-
- /* Operational Registers */
- USBCMD = 0x00/4, /* USB Command Register */
- RUNSTOP = 1<<0, /* Run/Stop - RW */
- HCRST = 1<<1, /* Host Controller Reset - RW */
- INTE = 1<<2, /* Interrupter Enable - RW */
- HSEE = 1<<3, /* Host System Error Enable - RW */
- LHCRST = 1<<7, /* Light Host Controller Reset - RO/RW */
- CSS = 1<<8, /* Controller Save State - RW */
- CRS = 1<<9, /* Controller Restore State - RW */
- EWE = 1<<10, /* Enable Wrap Event - RW */
- EU3S = 1<<11, /* Enable U3 MFINDEX Stop - RW */
-
- USBSTS = 0x04/4, /* USB Status Register */
- HCH = 1<<0, /* HCHalted - RO */
- HSE = 1<<2, /* Host System Error - RW1C */
- EINT = 1<<3, /* Event Interrupt - RW1C */
- PCD = 1<<4, /* Port Change Detect - RW1C */
- SSS = 1<<8, /* Save State Status - RO */
- RSS = 1<<9, /* Restore State Status - RO */
- SRE = 1<<10, /* Save/Restore Error - RW1C */
- CNR = 1<<11, /* Controller Not Ready - RO */
- HCE = 1<<12, /* Host Controller Error - RO */
-
- PAGESIZE = 0x08/4, /* Page Size - RO */
-
- DNCTRL = 0x14/4, /* Device Notification Control Register - RW */
-
- CRCR = 0x18/4, /* Command Ring Control Register - RW */
- RCS = 1<<0, /* Ring Cycle State - RW */
- CS = 1<<1, /* Command Stop - RW1S */
- CA = 1<<2, /* Command Abort - RW1S */
- CRR = 1<<3, /* Command Ring Running - RO */
-
- DCBAAP = 0x30/4, // 8
-
- CONFIG = 0x38/4, /* Configure Register (MaxSlotEn[7:0]) */
-
- /* Port Register Set */
- PORTSC = 0x00/4, /* Port status and Control Register */
- CCS = 1<<0, /* Current Connect Status - ROS */
- PED = 1<<1, /* Port Enable/Disabled - RW1CS */
- OCA = 1<<3, /* Over-current Active - RO */
- PR = 1<<4, /* Port Reset - RW1S */
- PLS = 15<<5, /* Port Link State - RWS */
- PP = 1<<9, /* Port Power - RWS */
- PS = 15<<10, /* Port Speed - ROS */
- PIC = 3<<14, /* Port Indicator Control - RWS */
- LWS = 1<<16, /* Port Link Write Strobe - RW */
- CSC = 1<<17, /* Connect Status Change - RW1CS */
- PEC = 1<<18, /* Port Enabled/Disabled Change - RW1CS */
- WRC = 1<<19, /* Warm Port Reset Change - RW1CS */
- OCC = 1<<20, /* Over-current Change - RW1CS */
- PRC = 1<<21, /* Port Reset Change - RW1CS */
- PLC = 1<<22, /* Port Link State Change - RW1CS */
- CEC = 1<<23, /* Port Config Error Change - RW1CS */
- CAS = 1<<24, /* Cold Attach Status - RO */
- WCE = 1<<25, /* Wake on Connect Enable - RWS */
- WDE = 1<<26, /* Wake on Disconnect Enable - RWS */
- WOE = 1<<27, /* Wake on Over-current Enable - RWS */
- DR = 1<<30, /* Device Removable - RO */
- WPR = 1<<31, /* Warm Port Reset - RW1S */
-
- PORTPMSC = 0x04/4,
- PORTLI = 0x08/4,
-
- /* Host Controller Runtime Register */
- MFINDEX = 0x0000/4, /* Microframe Index */
- IR0 = 0x0020/4, /* Interrupt Register Set 0 */
-
- /* Interrupter Registers */
- IMAN = 0x00/4, /* Interrupter Management */
- IMOD = 0x04/4, /* Interrupter Moderation */
- ERSTSZ = 0x08/4, /* Event Ring Segment Table Size */
- ERSTBA = 0x10/4, /* Event Ring Segment Table Base Address */
- ERDP = 0x18/4, /* Event Ring Dequeue Pointer */
-
- /* TRB flags */
- TR_ENT = 1<<1,
- TR_ISP = 1<<2,
- TR_NS = 1<<3,
- TR_CH = 1<<4,
- TR_IOC = 1<<5,
- TR_IDT = 1<<6,
- TR_BEI = 1<<9,
-
- /* TRB types */
- TR_RESERVED = 0<<10,
- TR_NORMAL = 1<<10,
- TR_SETUPSTAGE = 2<<10,
- TR_DATASTAGE = 3<<10,
- TR_STATUSSTAGE = 4<<10,
- TR_ISOCH = 5<<10,
- TR_LINK = 6<<10,
- TR_EVENTDATA = 7<<10,
- TR_NOOP = 8<<10,
-
- CR_ENABLESLOT = 9<<10,
- CR_DISABLESLOT = 10<<10,
- CR_ADDRESSDEV = 11<<10,
- CR_CONFIGEP = 12<<10,
- CR_EVALCTX = 13<<10,
- CR_RESETEP = 14<<10,
- CR_STOPEP = 15<<10,
- CR_SETTRDQP = 16<<10,
- CR_RESETDEV = 17<<10,
- CR_FORCECMD = 18<<10,
- CR_NEGBW = 19<<10,
- CR_SETLAT = 20<<10,
- CR_GETPORTBW = 21<<10,
- CR_FORCEHDR = 22<<10,
- CR_NOOP = 23<<10,
-
- ER_TRANSFER = 32<<10,
- ER_CMDCOMPL = 33<<10,
- ER_PORTSC = 34<<10,
- ER_BWREQ = 35<<10,
- ER_DOORBELL = 36<<10,
- ER_HCE = 37<<10,
- ER_DEVNOTE = 38<<10,
- ER_MFINDEXWRAP = 39<<10,
-};
-
-typedef struct Ctlr Ctlr;
-typedef struct Wait Wait;
-typedef struct Ring Ring;
-typedef struct Slot Slot;
-typedef struct Epio Epio;
-typedef struct Port Port;
-
-struct Wait
-{
- Wait *next;
- Ring *ring;
- u32int *td;
- u32int er[4];
- Rendez *z;
-};
-
-struct Ring
-{
- int id;
-
- Slot *slot;
-
- u32int *base;
-
- u32int mask;
- u32int shift;
-
- u32int rp;
- u32int wp;
-
- u32int *ctx;
- u32int *doorbell;
-
- int stopped;
-
- int *residue;
- Wait *pending;
- Lock;
-};
-
-struct Slot
-{
- int id;
-
- int confval; // bConfigurationValue of SET_CONFIGURATION
- int iface; // bInterfaceNumber of SET_INTERFACE
- int altc; // bAlternateSetting of SET_INTERFACE
-
- Ctlr *ctlr;
- Udev *dev;
-
- u32int *ibase;
- u32int *obase;
-
- /* endpoint rings */
- int nep;
- Ring epr[32];
-};
-
-struct Port
-{
- char spec[4];
- int proto;
-
- u32int *reg;
-};
-
-struct Ctlr
-{
- u32int *mmio;
-
- u32int *opr; /* operational registers */
- u32int *rts; /* runtime registers */
- u32int *dba; /* doorbell array */
-
- u64int *dcba; /* device context base array */
-
- u64int *sba; /* scratchpad buffer array */
- void *sbp; /* scratchpad buffer pages */
-
- u32int *erst[1]; /* event ring segment table */
- Ring er[1]; /* event ring segment */
- Ring cr[1]; /* command ring segment */
- QLock cmdlock;
-
- u32int µframe;
-
- QLock slotlock;
- Slot **slot; /* slots by slot id */
- Port *port;
-
- u32int hccparams;
-
- int csz;
- int pagesize;
- int nscratch;
- int nintrs;
- int nslots;
-
- Rendez recover;
- void *active;
-};
-
-struct Epio
-{
- QLock;
-
- Ring *ring;
- Block *b;
-
- /* iso */
- u32int frame;
- u32int period;
- u32int incr;
- u32int tdsz;
-
- /* isoread */
- u32int rp0;
- u32int frame0;
-
- int nleft;
-};
-
-static char Ebadlen[] = "bad usb request length";
-static char Enotconfig[] = "usb endpoint not configured";
-static char Erecover[] = "xhci controller needs reset";
-
-static char*
-ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er);
-
static void
-setrptr(u32int *reg, u64int pa)
-{
- coherence();
- reg[0] = pa;
- reg[1] = pa>>32;
-}
-
-static u32int
-µframe(Ctlr *ctlr)
-{
- u32int µ;
- do {
- µ = (ctlr->rts[MFINDEX] & (1<<14)-1) |
- (ctlr->µframe & ~((1<<14)-1));
- } while((int)(µ - ctlr->µframe) < 0);
- return µ;
-}
-
-static void
-freering(Ring *r)
-{
- if(r == nil)
- return;
- if(r->base != nil){
- dmaflush(0, r->base, 4*4<<r->shift);
- free(r->base);
- }
- if(r->residue != nil)
- free(r->residue);
- memset(r, 0, sizeof(*r));
-}
-
-static Ring*
-initring(Ring *r, int shift)
-{
- r->id = 0;
- r->ctx = nil;
- r->slot = nil;
- r->doorbell = nil;
- r->pending = nil;
- r->residue = nil;
- r->stopped = 0;
- r->shift = shift;
- r->mask = (1<<shift)-1;
- r->rp = r->wp = 0;
- r->base = mallocalign(4*4<<shift, 64, 0, 64*1024);
- if(r->base == nil){
- freering(r);
- error(Enomem);
- }
- dmaflush(1, r->base, 4*4<<shift);
- return r;
-}
-
-static void
-flushring(Ring *r)
-{
- Rendez *z;
- Wait *w;
-
- while((w = r->pending) != nil){
- r->pending = w->next;
- w->next = nil;
- if((z = w->z) != nil){
- w->z = nil;
- wakeup(z);
- }
- }
-}
-
-static u64int
-resetring(Ring *r)
-{
- u64int pa;
-
- ilock(r);
- flushring(r);
- r->rp = r->wp;
- pa = PADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1);
- iunlock(r);
-
- return pa;
-}
-
-static u32int*
-xecp(Ctlr *ctlr, uchar id, u32int *p)
-{
- u32int x;
-
- if(p == nil){
- p = ctlr->mmio;
- x = ctlr->hccparams>>16;
- } else {
- x = (*p>>8) & 255;
- }
- while(x != 0){
- p += x;
- x = *p;
- if((x & 255) == id)
- return p;
- x >>= 8;
- x &= 255;
- }
- return nil;
-}
-
-static void
-handoff(Ctlr *ctlr)
-{
- u32int *r;
- int i;
-
- if((r = xecp(ctlr, 1, nil)) == nil)
- return;
- if(getconf("*noxhcihandoff") == nil){
- r[0] |= 1<<24; /* request ownership */
- for(i = 0; (r[0] & (1<<16)) != 0 && i<100; i++)
- tsleep(&up->sleep, return0, nil, 10);
- }
- /* disable SMI interrupts */
- r[1] &= 7<<1 | 255<<5 | 7<<17 | 7<<29;
-
- /* clear BIOS ownership in case of timeout */
- r[0] &= ~(1<<16);
-}
-
-static void
-shutdown(Hci *hp)
-{
- Ctlr *ctlr = hp->aux;
- int i;
-
- ctlr->opr[USBCMD] = 0;
- for(i=0; (ctlr->opr[USBSTS] & HCH) == 0 && i < 10; i++)
- delay(10);
- intrdisable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
-}
-
-static void
-release(Ctlr *ctlr)
-{
- int i;
-
- freering(ctlr->cr);
- for(i=0; i<nelem(ctlr->er); i++){
- freering(&ctlr->er[i]);
- free(ctlr->erst[i]);
- ctlr->erst[i] = nil;
- }
- free(ctlr->port), ctlr->port = nil;
- free(ctlr->slot), ctlr->slot = nil;
- free(ctlr->dcba), ctlr->dcba = nil;
- free(ctlr->sba), ctlr->sba = 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
-init(Hci *hp)
-{
- Ctlr *ctlr;
- Port *pp;
- u32int *x;
- uchar *p;
- int i, j;
-
- ctlr = hp->aux;
- if(ctlr->mmio[CAPLENGTH] == -1){
- error("controller vanished");
- }
-
- ctlr->opr = &ctlr->mmio[(ctlr->mmio[CAPLENGTH]&0xFF)/4];
- ctlr->dba = &ctlr->mmio[ctlr->mmio[DBOFF]/4];
- ctlr->rts = &ctlr->mmio[ctlr->mmio[RTSOFF]/4];
-
- ctlr->hccparams = ctlr->mmio[HCCPARAMS];
- handoff(ctlr);
-
- for(i=0; (ctlr->opr[USBSTS] & CNR) != 0 && i<100; i++)
- tsleep(&up->sleep, return0, nil, 10);
-
- ctlr->opr[USBCMD] = HCRST;
- delay(1);
- for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != HCH && i<100; i++)
- tsleep(&up->sleep, return0, nil, 10);
-
- intrenable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
-
- if(waserror()){
- shutdown(hp);
- release(ctlr);
- nexterror();
- }
-
- ctlr->csz = (ctlr->hccparams & CSZ) != 0;
- ctlr->pagesize = (ctlr->opr[PAGESIZE] & 0xFFFF) << 12;
-
- ctlr->nscratch = (ctlr->mmio[HCSPARAMS2] >> 27) & 0x1F | (ctlr->mmio[HCSPARAMS2] >> 16) & 0x3E0;
- ctlr->nintrs = (ctlr->mmio[HCSPARAMS1] >> 8) & 0x7FF;
- ctlr->nslots = (ctlr->mmio[HCSPARAMS1] >> 0) & 0xFF;
-
- hp->highspeed = 1;
- hp->superspeed = 0;
- hp->nports = (ctlr->mmio[HCSPARAMS1] >> 24) & 0xFF;
- ctlr->port = malloc(hp->nports * sizeof(Port));
- if(ctlr->port == nil)
- error(Enomem);
- for(i=0; i<hp->nports; i++)
- ctlr->port[i].reg = &ctlr->opr[0x400/4 + i*4];
-
- x = nil;
- while((x = xecp(ctlr, 2, x)) != nil){
- i = x[2]&255;
- j = (x[2]>>8)&255;
- while(j--){
- if(i < 1 || i > hp->nports)
- break;
- 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++;
- }
- }
-
- ctlr->slot = malloc((1+ctlr->nslots)*sizeof(ctlr->slot[0]));
- ctlr->dcba = mallocalign((1+ctlr->nslots)*sizeof(ctlr->dcba[0]), 64, 0, ctlr->pagesize);
- if(ctlr->slot == nil || ctlr->dcba == nil)
- error(Enomem);
- if(ctlr->nscratch != 0){
- ctlr->sba = mallocalign(ctlr->nscratch*8, 64, 0, ctlr->pagesize);
- ctlr->sbp = mallocalign(ctlr->nscratch*ctlr->pagesize, ctlr->pagesize, 0, 0);
- if(ctlr->sba == nil || ctlr->sbp == nil)
- error(Enomem);
- for(i=0, p = ctlr->sbp; i<ctlr->nscratch; i++, p += ctlr->pagesize){
- memset(p, 0, ctlr->pagesize);
- ctlr->sba[i] = PADDR(p);
- }
- dmaflush(1, ctlr->sbp, ctlr->nscratch*ctlr->pagesize);
- dmaflush(1, ctlr->sba, ctlr->nscratch*8);
- ctlr->dcba[0] = PADDR(ctlr->sba);
- } else {
- ctlr->dcba[0] = 0;
- }
- for(i=1; i<=ctlr->nslots; i++)
- ctlr->dcba[i] = 0;
-
- ctlr->opr[CONFIG] = (ctlr->opr[CONFIG] & 0xFFFFFC00) | ctlr->nslots; /* MaxSlotsEn */
-
- dmaflush(1, ctlr->dcba, (1+ctlr->nslots)*sizeof(ctlr->dcba[0]));
- setrptr(&ctlr->opr[DCBAAP], PADDR(ctlr->dcba));
-
- initring(ctlr->cr, 8); /* 256 entries */
- ctlr->cr->id = 0;
- ctlr->cr->doorbell = &ctlr->dba[0];
- setrptr(&ctlr->opr[CRCR], resetring(ctlr->cr));
-
- for(i=0; i<ctlr->nintrs; i++){
- u32int *irs = &ctlr->rts[IR0 + i*8];
-
- if(i >= nelem(ctlr->er)){
- irs[ERSTSZ] = 0; /* disable ring */
- irs[IMAN] = 1;
- irs[IMOD] = 0;
- setrptr(&irs[ERSTBA], 0);
- setrptr(&irs[ERDP], 0);
- continue;
- }
-
- /* allocate and link into event ring segment table */
- initring(&ctlr->er[i], 8); /* 256 entries */
- ctlr->erst[i] = mallocalign(4*4, 64, 0, 0);
- if(ctlr->erst[i] == nil)
- error(Enomem);
- *((u64int*)ctlr->erst[i]) = PADDR(ctlr->er[i].base);
- ctlr->erst[i][2] = ctlr->er[i].mask+1;
- ctlr->erst[i][3] = 0;
- dmaflush(1, ctlr->erst[i], 4*4);
-
- irs[ERSTSZ] = 1; /* just one segment */
- irs[IMAN] = 3;
- irs[IMOD] = 0;
- setrptr(&irs[ERSTBA], PADDR(ctlr->erst[i]));
- setrptr(&irs[ERDP], PADDR(ctlr->er[i].base) | (1<<3));
- }
- poperror();
-
- ctlr->µframe = 0;
- ctlr->opr[USBSTS] = ctlr->opr[USBSTS] & (HSE|EINT|PCD|SRE);
- coherence();
-
- ctlr->opr[USBCMD] = RUNSTOP|INTE|HSEE|EWE;
- for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != 0 && i<100; i++)
- tsleep(&up->sleep, return0, nil, 10);
-
- kproc("xhcirecover", recover, hp);
-}
-
-static int
-needrecover(void *arg)
-{
- Ctlr *ctlr = arg;
- return ctlr->er->stopped ||
- (ctlr->opr[USBSTS] & (HCH|HCE|HSE)) != 0;
-}
-
-static void
-recover(void *arg)
-{
- Hci *hp = arg;
- Ctlr *ctlr = hp->aux;
-
- while(waserror())
- ;
- while(!needrecover(ctlr))
- tsleep(&ctlr->recover, needrecover, ctlr, 1000);
- shutdown(hp);
-
- /*
- * flush all transactions and wait until all devices have
- * been detached by usbd.
- */
- for(;;){
- int i, j, active;
-
- ilock(ctlr->cr);
- ctlr->cr->stopped = 1;
- flushring(ctlr->cr);
- iunlock(ctlr->cr);
-
- active = 0;
- qlock(&ctlr->slotlock);
- for(i=1; i<=ctlr->nslots; i++){
- Slot *slot = ctlr->slot[i];
- if(slot == nil)
- continue;
- active++;
- for(j=0; j < slot->nep; j++){
- Ring *ring = &slot->epr[j];
- if(ring->base == nil)
- continue;
- ilock(ring);
- ring->stopped = 1;
- flushring(ring);
- iunlock(ring);
- }
- }
- qunlock(&ctlr->slotlock);
- if(active == 0)
- break;
-
- tsleep(&up->sleep, return0, nil, 100);
- }
-
- qlock(&ctlr->slotlock);
- qlock(&ctlr->cmdlock);
-
- release(ctlr);
- if(waserror()) {
- print("xhci recovery failed: %s\n", up->errstr);
- } else {
- init(hp);
- poperror();
- }
-
- qunlock(&ctlr->cmdlock);
- qunlock(&ctlr->slotlock);
-
- pexit("", 1);
-}
-
-static void
-dump(Hci *)
-{
-}
-
-static void
-queuetd(Ring *r, u32int c, u32int s, u64int p, Wait *w)
-{
- u32int *td, x;
-
- x = r->wp++;
- if((x & r->mask) == r->mask){
- td = r->base + 4*(x & r->mask);
- *(u64int*)td = PADDR(r->base);
- td[2] = 0;
- td[3] = ((~x>>r->shift)&1) | (1<<1) | TR_LINK;
- dmaflush(1, td, 4*4);
- x = r->wp++;
- }
- td = r->base + 4*(x & r->mask);
- if(w != nil){
- w->er[0] = w->er[1] = w->er[2] = w->er[3] = 0;
- w->ring = r;
- w->td = td;
- w->z = &up->sleep;
-
- ilock(r);
- w->next = r->pending;
- r->pending = w;
- iunlock(r);
- }
- if(r->residue != nil)
- r->residue[x & r->mask] = s;
- coherence();
- *(u64int*)td = p;
- td[2] = s;
- td[3] = ((~x>>r->shift)&1) | c;
- dmaflush(1, td, 4*4);
-}
-
-static char *ccerrtab[] = {
-[2] "Data Buffer Error",
-[3] "Babble Detected Error",
-[4] "USB Transaction Error",
-[5] "TRB Error",
-[6] "Stall Error",
-[7] "Resume Error",
-[8] "Bandwidth Error",
-[9] "No Slots Available",
-[10] "Invalid Stream Type",
-[11] "Slot Not Enabled",
-[12] "Endpoint Not Enabled",
-[13] "Short Packet",
-[14] "Ring Underrun",
-[15] "Ring Overrun",
-[16] "VF Event Ring Full",
-[17] "Parameter Error",
-[18] "Bandwidth Overrun Error",
-[19] "Context State Error",
-[20] "No Ping Response",
-[21] "Event Ring Full",
-[22] "Incompatible Device",
-[23] "Missed Service Error",
-[24] "Command Ring Stopped",
-[25] "Command Aborted",
-[26] "Stopped",
-[27] "Stoppe - Length Invalid",
-[29] "Max Exit Latency Too Large",
-[31] "Isoch Buffer Overrun",
-[32] "Event Lost Error",
-[33] "Undefined Error",
-[34] "Invalid Stream ID",
-[35] "Secondary Bandwidth Error",
-[36] "Split Transaction Error",
-};
-
-static char*
-ccerrstr(u32int cc)
-{
- char *s;
-
- if(cc == 1 || cc == 13)
- return nil;
- if(cc < nelem(ccerrtab) && ccerrtab[cc] != nil)
- s = ccerrtab[cc];
- else
- s = "???";
- return s;
-}
-
-static int
-waitdone(void *a)
-{
- return ((Wait*)a)->z == nil;
-}
-
-static char*
-waittd(Ctlr *ctlr, Wait *w, int tmout)
-{
- Ring *r = w->ring;
-
- coherence();
- *r->doorbell = r->id;
-
- while(waserror()){
- if(r->stopped) {
- ctlr->er->stopped = 1;
- wakeup(&ctlr->recover);
-
- /* wait for rescue */
- tmout = 0;
- continue;
- }
-
- if(r == ctlr->cr)
- ctlr->opr[CRCR] |= CA;
- else
- ctlrcmd(ctlr, CR_STOPEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
- r->stopped = 1;
-
- /* time to abort the transaction */
- tmout = 5000;
- }
- if(tmout > 0){
- tsleep(&up->sleep, waitdone, w, tmout);
- if(!waitdone(w))
- error("timed out");
- } else {
- while(!waitdone(w))
- sleep(&up->sleep, waitdone, w);
- }
- poperror();
- return ccerrstr(w->er[2]>>24);
-}
-
-static char*
-ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er)
-{
- Wait w[1];
- char *err;
-
- qlock(&ctlr->cmdlock);
- if(needrecover(ctlr)){
- qunlock(&ctlr->cmdlock);
- return Erecover;
- }
- ctlr->cr->stopped = 0;
- queuetd(ctlr->cr, c, s, p, w);
- err = waittd(ctlr, w, 5000);
- qunlock(&ctlr->cmdlock);
-
- if(er != nil)
- memmove(er, w->er, 4*4);
-
- return err;
-}
-
-static void
-completering(Ring *r, u32int *er)
-{
- Wait *w, **wp;
- u32int *td, x;
- u64int pa;
-
- pa = (*(u64int*)er) & ~15ULL;
- ilock(r);
-
- for(x = r->rp; (int)(r->wp - x) > 0; x++){
- td = &r->base[4*(x & r->mask)];
- if((u64int)PADDR(td) == pa){
- if(r->residue != nil)
- r->residue[x & r->mask] = er[2] & 0xFFFFFF;
- r->rp = x+1;
- break;
- }
- }
-
- wp = &r->pending;
- while(w = *wp){
- if((u64int)PADDR(w->td) == pa){
- Rendez *z = w->z;
-
- memmove(w->er, er, 4*4);
- *wp = w->next;
- w->next = nil;
-
- if(z != nil){
- w->z = nil;
- wakeup(z);
- }
- break;
- } else {
- wp = &w->next;
- }
- }
-
- iunlock(r);
-}
-
-static void
-interrupt(Ureg*, void *arg)
-{
- Hci *hp = arg;
- Ctlr *ctlr = hp->aux;
- Ring *ring = ctlr->er;
- Slot *slot;
- u32int *irs, *td, x;
-
- if(ring->base == nil)
- return;
-
- irs = &ctlr->rts[IR0];
- x = irs[IMAN];
- if(x & 1) irs[IMAN] = x & 3;
-
- for(x = ring->rp;; x=++ring->rp){
- td = ring->base + 4*(x & ring->mask);
- dmaflush(0, td, 4*4);
-
- if((((x>>ring->shift)^td[3])&1) == 0)
- break;
-
- switch(td[3] & 0xFC00){
- case ER_CMDCOMPL:
- completering(ctlr->cr, td);
- break;
- case ER_TRANSFER:
- x = td[3]>>24;
- if(x == 0 || x > ctlr->nslots)
- break;
- slot = ctlr->slot[x];
- if(slot == nil)
- break;
- completering(&slot->epr[(td[3]>>16)-1&31], td);
- break;
- case ER_MFINDEXWRAP:
- ctlr->µframe = (ctlr->rts[MFINDEX] & (1<<14)-1) |
- (ctlr->µframe+(1<<14) & ~((1<<14)-1));
- break;
- case ER_HCE:
- iprint("xhci: host controller error: %ux %ux %ux %ux\n",
- td[0], td[1], td[2], td[3]);
- ctlr->er->stopped = 1;
- wakeup(&ctlr->recover);
- return;
- case ER_PORTSC:
- break;
- case ER_BWREQ:
- case ER_DOORBELL:
- case ER_DEVNOTE:
- default:
- iprint("xhci: event %ud: %ux %ux %ux %ux\n",
- x, td[0], td[1], td[2], td[3]);
- }
- }
-
- setrptr(&irs[ERDP], PADDR(td) | (1<<3));
-}
-
-static void
-freeslot(void *arg)
-{
- Slot *slot;
-
- if(arg == nil)
- return;
- slot = arg;
- if(slot->id != 0){
- Ctlr *ctlr = slot->ctlr;
- qlock(&ctlr->slotlock);
- if(ctlr->slot != nil && ctlr->slot[slot->id] == slot){
- ctlrcmd(ctlr, CR_DISABLESLOT | (slot->id<<24), 0, 0, nil);
- dmaflush(0, slot->obase, 32*32 << ctlr->csz);
- ctlr->dcba[slot->id] = 0;
- dmaflush(1, &ctlr->dcba[slot->id], sizeof(ctlr->dcba[0]));
- ctlr->slot[slot->id] = nil;
- }
- qunlock(&ctlr->slotlock);
- }
- freering(&slot->epr[0]);
- free(slot->ibase);
- free(slot->obase);
- free(slot);
-}
-
-static Slot*
-allocslot(Ctlr *ctlr, Udev *dev)
-{
- u32int r[4];
- Slot *slot;
- char *err;
-
- slot = malloc(sizeof(Slot));
- if(slot == nil)
- error(Enomem);
-
- slot->ctlr = ctlr;
- slot->dev = dev;
- slot->nep = 0;
- slot->id = 0;
-
- slot->confval = 0;
- slot->iface = 0;
- slot->altc = 0;
-
- qlock(&ctlr->slotlock);
- if(waserror()){
- qunlock(&ctlr->slotlock);
- freeslot(slot);
- nexterror();
- }
- if(ctlr->slot == nil)
- error(Erecover);
- slot->ibase = mallocalign(32*33 << ctlr->csz, 64, 0, ctlr->pagesize);
- slot->obase = mallocalign(32*32 << ctlr->csz, 64, 0, ctlr->pagesize);
- if(slot->ibase == nil || slot->obase == nil)
- error(Enomem);
-
- if((err = ctlrcmd(ctlr, CR_ENABLESLOT, 0, 0, r)) != nil)
- error(err);
- slot->id = r[3]>>24;
- if(slot->id <= 0 || slot->id > ctlr->nslots || ctlr->slot[slot->id] != nil){
- slot->id = 0;
- error("bad slot id from controller");
- }
- poperror();
-
- dmaflush(1, slot->obase, 32*32 << ctlr->csz);
- ctlr->dcba[slot->id] = PADDR(slot->obase);
- dmaflush(1, &ctlr->dcba[slot->id], sizeof(ctlr->dcba[0]));
-
- ctlr->slot[slot->id] = slot;
-
- qunlock(&ctlr->slotlock);
-
- return slot;
-}
-
-static void
-setdebug(Hci *, int)
-{
-}
-
-static void
-epclose(Ep *ep)
-{
- Ctlr *ctlr;
- Slot *slot;
- Ring *ring;
- Epio *io;
-
- if(ep->dev->isroot)
- return;
-
- io = ep->aux;
- if(io == nil)
- return;
- ep->aux = nil;
-
- ctlr = ep->hp->aux;
- slot = ep->dev->aux;
-
- if(ep->nb > 0 && (io[OREAD].ring != nil || io[OWRITE].ring != nil)){
- u32int *w;
-
- /* input control context */
- w = slot->ibase;
- memset(w, 0, 32<<ctlr->csz);
- w[1] = 1;
- if((ring = io[OREAD].ring) != nil){
- w[0] |= 1 << ring->id;
- if(ring->id == slot->nep)
- slot->nep--;
- ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
- }
- if((ring = io[OWRITE].ring) != nil){
- w[0] |= 1 << ring->id;
- if(ring->id == slot->nep)
- slot->nep--;
- ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
- }
-
- /* (input) slot context */
- w += 8<<ctlr->csz;
- w[0] = (w[0] & ~(0x1F<<27)) | slot->nep<<27;
-
- /* (input) ep context */
- w += (ep->nb&Epmax)*2*8<<ctlr->csz;
- memset(w, 0, 2*32<<ctlr->csz);
-
- dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
- ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PADDR(slot->ibase), nil);
- dmaflush(0, slot->obase, 32*32 << ctlr->csz);
-
- freering(io[OREAD].ring);
- freering(io[OWRITE].ring);
- }
- freeb(io[OREAD].b);
- freeb(io[OWRITE].b);
- free(io);
-}
-
-static void
-initepctx(u32int *w, Ring *r, Ep *ep)
-{
- int ival;
-
- if(ep->dev->speed == Lowspeed || ep->dev->speed == Fullspeed){
- for(ival=3; ival < 11 && (1<<ival) < ep->pollival; ival++)
- ;
- } else {
- for(ival=0; ival < 15 && (1<<ival) < ep->pollival; ival++)
- ;
- }
- w[0] = ival<<16;
- w[1] = ((ep->ttype-Tctl) | (r->id&1)<<2)<<3 | (ep->ntds-1)<<8 | ep->maxpkt<<16;
- if(ep->ttype != Tiso)
- w[1] |= 3<<1;
- *((u64int*)&w[2]) = PADDR(r->base) | 1;
- w[4] = 2*ep->maxpkt;
- if(ep->ttype == Tintr || ep->ttype == Tiso)
- w[4] |= (ep->maxpkt*ep->ntds)<<16;
-}
-
-static void
-initisoio(Epio *io, Ep *ep)
-{
- if(io->ring == nil)
- return;
- io->rp0 = io->ring->wp;
- io->frame0 = io->frame = 0;
- io->period = ep->pollival << 3*(ep->dev->speed == Fullspeed || ep->dev->speed == Lowspeed);
- if(io->ring->id & 1){
- io->ring->residue = smalloc((io->ring->mask+1)*sizeof(io->ring->residue[0]));
- io->incr = 0;
- io->tdsz = ep->maxpkt*ep->ntds;
- } else {
- io->incr = ((vlong)ep->hz*ep->pollival<<8)/1000;
- io->tdsz = (io->incr+255>>8)*ep->samplesz;
- }
- io->b = allocb((io->ring->mask+1)*io->tdsz);
-}
-
-static void
-initep(Ep *ep)
-{
- Epio *io;
- Ctlr *ctlr;
- Slot *slot;
- Ring *ring;
- u32int *w;
- char *err;
-
- io = ep->aux;
- ctlr = ep->hp->aux;
- slot = ep->dev->aux;
-
- io[OREAD].ring = io[OWRITE].ring = nil;
- if(ep->nb == 0){
- io[OWRITE].ring = &slot->epr[0];
- return;
- }
-
- /* (input) control context */
- w = slot->ibase;
- memset(w, 0, 32<<ctlr->csz);
- w[1] = 1;
- w[31] = slot->altc<<16 | slot->iface<<8 | slot->confval;
-
- if(waserror()){
- freering(io[OWRITE].ring), io[OWRITE].ring = nil;
- freering(io[OREAD].ring), io[OREAD].ring = nil;
- nexterror();
- }
- if(ep->mode != OREAD){
- ring = initring(io[OWRITE].ring = &slot->epr[(ep->nb&Epmax)*2-1], 8);
- ring->id = (ep->nb&Epmax)*2;
- if(ring->id > slot->nep)
- slot->nep = ring->id;
- ring->slot = slot;
- ring->doorbell = &ctlr->dba[slot->id];
- ring->ctx = &slot->obase[ring->id*8<<ctlr->csz];
- w[1] |= 1 << ring->id;
- }
- if(ep->mode != OWRITE){
- ring = initring(io[OREAD].ring = &slot->epr[(ep->nb&Epmax)*2], 8);
- ring->id = (ep->nb&Epmax)*2+1;
- if(ring->id > slot->nep)
- slot->nep = ring->id;
- ring->slot = slot;
- ring->doorbell = &ctlr->dba[slot->id];
- ring->ctx = &slot->obase[ring->id*8<<ctlr->csz];
- w[1] |= 1 << ring->id;
- }
-
- /* (input) slot context */
- w += 8<<ctlr->csz;
- w[0] = (w[0] & ~(0x1F<<27)) | slot->nep<<27;
- if(!ep->dev->ishub)
- w[0] &= ~(1<<25); // MTT
-
- /* (input) ep context */
- w += (ep->nb&Epmax)*2*8<<ctlr->csz;
- if(io[OWRITE].ring != nil){
- memset(w, 0, 5*4);
- initepctx(w, io[OWRITE].ring, ep);
- }
-
- w += 8<<ctlr->csz;
- if(io[OREAD].ring != nil){
- memset(w, 0, 5*4);
- initepctx(w, io[OREAD].ring, ep);
- }
-
- dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
- err = ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PADDR(slot->ibase), nil);
- dmaflush(0, slot->obase, 32*32 << ctlr->csz);
- if(err != nil)
- error(err);
-
- if(ep->ttype == Tiso){
- initisoio(io+OWRITE, ep);
- initisoio(io+OREAD, ep);
- }
- poperror();
-}
-
-static int
-speedid(int speed)
-{
- switch(speed){
- case Fullspeed: return 1;
- case Lowspeed: return 2;
- case Highspeed: return 3;
- case Superspeed: return 4;
- }
- return 0;
-}
-
-static void
-epopen(Ep *ep)
-{
- Ctlr *ctlr = ep->hp->aux;
- Slot *slot, *hub;
- Ring *ring;
- Epio *io;
- Udev *dev;
- char *err;
- u32int *w;
- int i;
-
- if(ep->dev->isroot)
- return;
- if(needrecover(ctlr))
- error(Erecover);
- io = malloc(sizeof(Epio)*2);
- if(io == nil)
- error(Enomem);
- ep->aux = io;
- if(waserror()){
- epclose(ep);
- nexterror();
- }
- dev = ep->dev;
- slot = dev->aux;
- if(slot != nil && slot->dev == dev){
- initep(ep);
- poperror();
- return;
- }
-
- /* first open has to be control endpoint */
- if(ep->nb != 0)
- error(Egreg);
-
- slot = allocslot(ctlr, dev);
- if(waserror()){
- freeslot(slot);
- nexterror();
- }
-
- /* allocate control ep 0 ring */
- ring = initring(io[OWRITE].ring = &slot->epr[0], 4);
- ring->id = 1;
- slot->nep = 1;
- ring->slot = slot;
- ring->doorbell = &ctlr->dba[slot->id];
- ring->ctx = &slot->obase[8<<ctlr->csz];
-
- /* (input) control context */
- w = slot->ibase;
- memset(w, 0, 3*32<<ctlr->csz);
- w[1] = 3; /* A0, A1 */
-
- /* (input) slot context */
- w += 8<<ctlr->csz;
- w[2] = w[3] = 0;
- w[0] = dev->routestr | speedid(dev->speed)<<20 |
- (dev->speed == Highspeed && dev->ishub != 0)<<25 | // MTT
- (dev->ishub != 0)<<26 | slot->nep<<27;
- w[1] = dev->rootport<<16;
-
- /* find the parent hub that this device is conected to */
- qlock(&ctlr->slotlock);
- for(i=1; i<=ctlr->nslots; i++){
- hub = ctlr->slot[i];
- if(hub == nil || hub->dev == nil || hub->dev->aux != hub)
- continue;
- if(hub == slot || hub->dev == dev)
- continue;
- if(!hub->dev->ishub)
- continue;
- if(hub->dev->addr != dev->hub)
- continue;
- if(hub->dev->rootport != dev->rootport)
- continue;
-
- if(dev->speed < Highspeed && hub->dev->speed == Highspeed){
- w[0] |= 1<<25; // MTT
- w[2] = hub->id | dev->port<<8;
- }
- break;
- }
- qunlock(&ctlr->slotlock);
-
- /* (input) ep context 0 */
- w += 8<<ctlr->csz;
- initepctx(w, io[OWRITE].ring, ep);
-
- dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
- err = ctlrcmd(ctlr, CR_ADDRESSDEV | (slot->id<<24), 0, PADDR(slot->ibase), nil);
- dmaflush(0, slot->obase, 32*32 << ctlr->csz);
- if(err != nil)
- error(err);
-
- /* (output) slot context */
- w = slot->obase;
-
- dev->addr = w[3] & 0xFF;
-
- dev->aux = slot;
- dev->free = freeslot;
-
- poperror();
- poperror();
-}
-
-static long
-isoread(Ep *ep, uchar *p, long n)
-{
- uchar *s, *d;
- Ctlr *ctlr;
- Epio *io;
- u32int i, µ;
- long m;
-
- s = p;
-
- io = (Epio*)ep->aux + OREAD;
- qlock(io);
- if(waserror()){
- qunlock(io);
- nexterror();
- }
- µ = io->period;
- ctlr = ep->hp->aux;
- if(needrecover(ctlr))
- error(Erecover);
-
- for(i = io->frame0; (int)(io->ring->rp - io->rp0) > 0 && n > 0; i++) {
- if((io->rp0 & io->ring->mask) == io->ring->mask)
- io->rp0++;
- m = io->tdsz - io->ring->residue[io->rp0 & io->ring->mask];
- if(m > 0){
- d = io->b->rp + (i&io->ring->mask)*io->tdsz;
- d += io->nleft, m -= io->nleft;
- if(n < m){
- dmaflush(0, d, n);
- memmove(p, d, n);
- io->nleft += n;
- p += n;
- break;
- }
- dmaflush(0, d, m);
- memmove(p, d, m);
- p += m, n -= m;
-
- if(ep->uframes == 1)
- n = 0;
- }
- io->nleft = 0;
- io->rp0++;
- }
- io->frame0 = i;
-
- for(i = io->frame;; i++){
- m = (int)(io->ring->wp - io->rp0);
- if(m <= 0) {
- i = (80 + µframe(ctlr))/µ;
- io->frame0 = i;
- io->rp0 = io->ring->wp;
- io->nleft = 0;
- } else if(m+1 >= io->ring->mask)
- break;
- m = io->tdsz;
- d = io->b->rp + (i&io->ring->mask)*io->tdsz;
- dmaflush(1, d, m);
- queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m, PADDR(d), nil);
- }
- io->frame = i;
-
- *io->ring->doorbell = io->ring->id;
- qunlock(io);
- poperror();
-
- return p - s;
-}
-
-static long
-isowrite(Ep *ep, uchar *p, long n)
-{
- uchar *s, *d;
- Ctlr *ctlr;
- Epio *io;
- u32int i, µ;
- long m;
-
- s = p;
- io = (Epio*)ep->aux + OWRITE;
- qlock(io);
- if(waserror()){
- qunlock(io);
- nexterror();
- }
- µ = io->period;
- ctlr = ep->hp->aux;
-
- for(i = io->frame;; i++){
- for(;;){
- if(needrecover(ctlr))
- error(Erecover);
- m = (int)(io->ring->wp - io->ring->rp);
- if(m <= 0)
- i = (80 + µframe(ctlr))/µ;
- if(m+1 < io->ring->mask)
- break;
-
- *io->ring->doorbell = io->ring->id;
- tsleep(&up->sleep, return0, nil, 5);
- }
- m = ((io->incr + (i*io->incr&255))>>8)*ep->samplesz;
- d = io->b->rp + (i&io->ring->mask)*io->tdsz;
- m -= io->nleft, d += io->nleft;
- if(n < m){
- memmove(d, p, n);
- p += n;
- io->nleft += n;
- break;
- }
- memmove(d, p, m);
- p += m, n -= m;
- m += io->nleft, d -= io->nleft;
- io->nleft = 0;
- dmaflush(1, d, m);
- queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m, PADDR(d), nil);
- }
- io->frame = i;
-
- while(io->ring->rp != io->ring->wp){
- int d = (int)(i*µ - µframe(ctlr))/8;
- d -= ep->sampledelay*1000 / ep->hz;
- if(d < 5)
- break;
-
- *io->ring->doorbell = io->ring->id;
- tsleep(&up->sleep, return0, nil, d);
- if(needrecover(ctlr))
- error(Erecover);
- }
-
- qunlock(io);
- poperror();
-
- return p - s;
-}
-
-static char*
-unstall(Ep *ep, Ring *r)
-{
- char *err;
-
- switch(r->ctx[0]&7){
- case 2: /* halted */
- case 4: /* error */
- ep->clrhalt = 1;
- }
- if(ep->clrhalt){
- ep->clrhalt = 0;
- err = ctlrcmd(r->slot->ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
- dmaflush(0, r->ctx, 8*4 << r->slot->ctlr->csz);
- if(err != nil)
- return err;
- r->stopped = 1;
- }
- if(r->stopped){
- err = ctlrcmd(r->slot->ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0, resetring(r), nil);
- dmaflush(0, r->ctx, 8*4 << r->slot->ctlr->csz);
- if(err != nil)
- return err;
- r->stopped = 0;
- }
- if(r->wp - r->rp >= r->mask)
- return "Ring Full";
- return nil;
-}
-
-static long
-epread(Ep *ep, void *va, long n)
-{
- Epio *io;
- Ctlr *ctlr;
- uchar *p;
- char *err;
- Wait w[1];
-
- if(ep->dev->isroot)
- error(Egreg);
-
- p = va;
- if(ep->ttype == Tctl){
- io = (Epio*)ep->aux + OREAD;
- qlock(io);
- if(io->b == nil || BLEN(io->b) == 0){
- qunlock(io);
- return 0;
- }
- if(n > BLEN(io->b))
- n = BLEN(io->b);
- memmove(p, io->b->rp, n);
- io->b->rp += n;
- qunlock(io);
- return n;
- } else if(ep->ttype == Tiso)
- return isoread(ep, p, n);
-
- if((uintptr)p <= KZERO){
- Block *b;
-
- b = allocb(n);
- if(waserror()){
- freeb(b);
- nexterror();
- }
- n = epread(ep, b->rp, n);
- memmove(p, b->rp, n);
- freeb(b);
- poperror();
- return n;
- }
-
- ctlr = (Ctlr*)ep->hp->aux;
- io = (Epio*)ep->aux + OREAD;
- qlock(io);
- if(waserror()){
- dmaflush(0, io->ring->ctx, 8*4 << ctlr->csz);
- qunlock(io);
- nexterror();
- }
-
- if((err = unstall(ep, io->ring)) != nil)
- error(err);
-
- dmaflush(1, p, n);
- queuetd(io->ring, TR_NORMAL | TR_IOC, n, PADDR(p), w);
- err = waittd(ctlr, w, ep->tmout);
- dmaflush(0, p, n);
- if(err != nil)
- error(err);
-
- qunlock(io);
- poperror();
-
- n -= (w->er[2] & 0xFFFFFF);
- if(n < 0)
- n = 0;
-
- return n;
-}
-
-static long
-epwrite(Ep *ep, void *va, long n)
-{
- Wait w[3];
- Ctlr *ctlr;
- Epio *io;
- uchar *p;
- char *err;
-
- if(ep->dev->isroot)
- error(Egreg);
-
- p = va;
- if(ep->ttype == Tctl){
- int dir, len;
- Ring *ring;
- Slot *slot;
-
- if(n < 8)
- error(Eshort);
-
- if(p[0] == 0x00 && p[1] == 0x05)
- return n;
-
- ctlr = (Ctlr*)ep->hp->aux;
- io = (Epio*)ep->aux + OREAD;
- ring = io[OWRITE-OREAD].ring;
- slot = ring->slot;
- qlock(io);
- if(waserror()){
- ilock(ring);
- ring->pending = nil;
- iunlock(ring);
- dmaflush(0, ring->ctx, 8*4 << ctlr->csz);
- qunlock(io);
- nexterror();
- }
- if(io->b != nil){
- freeb(io->b);
- io->b = nil;
- }
- len = GET2(&p[6]);
- dir = (p[0] & Rd2h) != 0;
- if(len > 0){
- io->b = allocb(len);
- if(dir == 0){ /* out */
- assert(len >= n-8);
- memmove(io->b->wp, p+8, n-8);
- } else {
- memset(io->b->wp, 0, len);
- io->b->wp += len;
- }
- }
- if((err = unstall(ep, ring)) != nil)
- error(err);
-
- if((ring->ctx[1]>>16) != ep->maxpkt){
- u32int *w = slot->ibase;
- w[0] = 0;
- w[1] = 1<<ring->id;
- w += (ring->id+1)*8<<ctlr->csz;
- initepctx(w, ring, ep);
- dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
- err = ctlrcmd(ctlr, CR_EVALCTX | (slot->id<<24), 0, PADDR(slot->ibase), nil);
- dmaflush(0, slot->obase, 32*32 << ctlr->csz);
- if(err != nil)
- error(err);
- }
-
- queuetd(ring, TR_SETUPSTAGE | (len > 0 ? 2+dir : 0)<<16 | TR_IDT | TR_IOC, 8,
- p[0] | p[1]<<8 | GET2(&p[2])<<16 |
- (u64int)(GET2(&p[4]) | len<<16)<<32, &w[0]);
- if(len > 0){
- dmaflush(1, io->b->rp, len);
- queuetd(ring, TR_DATASTAGE | dir<<16 | TR_IOC, len,
- PADDR(io->b->rp), &w[1]);
- }
- queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | TR_IOC, 0, 0, &w[2]);
-
- if((err = waittd(ctlr, &w[0], ep->tmout)) != nil)
- error(err);
- if(len > 0){
- if((err = waittd(ctlr, &w[1], ep->tmout)) != nil)
- error(err);
- if(dir != 0){
- dmaflush(0, io->b->rp, len);
- io->b->wp -= (w[1].er[2] & 0xFFFFFF);
- if(io->b->wp < io->b->rp)
- io->b->wp = io->b->rp;
- }
- }
- if((err = waittd(ctlr, &w[2], ep->tmout)) != nil)
- 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);
- poperror();
-
- return n;
- } else if(ep->ttype == Tiso)
- return isowrite(ep, p, n);
-
- if((uintptr)p <= KZERO){
- Block *b;
-
- b = allocb(n);
- if(waserror()){
- freeb(b);
- nexterror();
- }
- memmove(b->wp, p, n);
- n = epwrite(ep, b->wp, n);
- freeb(b);
- poperror();
- return n;
- }
-
- ctlr = (Ctlr*)ep->hp->aux;
- io = (Epio*)ep->aux + OWRITE;
- qlock(io);
- if(waserror()){
- dmaflush(0, io->ring->ctx, 8*4 << ctlr->csz);
- qunlock(io);
- nexterror();
- }
-
- if((err = unstall(ep, io->ring)) != nil)
- error(err);
-
- dmaflush(1, p, n);
- queuetd(io->ring, TR_NORMAL | TR_IOC, n, PADDR(p), w);
- if((err = waittd(ctlr, w, ep->tmout)) != nil)
- error(err);
-
- qunlock(io);
- poperror();
-
- return n;
-}
-
-static char*
-seprintep(char *s, char*, Ep*)
-{
- return s;
-}
-
-static int
-portstatus(Hci *hp, int port)
-{
- Ctlr *ctlr = hp->aux;
- u32int psc, ps;
-
- if(ctlr->port == nil || needrecover(ctlr))
- return 0;
-
- ps = 0;
- psc = ctlr->port[port-1].reg[PORTSC];
- if(psc & CCS) ps |= HPpresent;
- if(psc & PED) ps |= HPenable;
- if(psc & OCA) ps |= HPovercurrent;
- if(psc & PR) ps |= HPreset;
-
- 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;
- }
-
- return ps;
-}
-
-static int
-portenable(Hci*, int, int)
-{
- return 0;
-}
-
-static int
-portreset(Hci *hp, int port, int on)
-{
- Ctlr *ctlr = hp->aux;
-
- if(ctlr->port == nil || needrecover(ctlr))
- return 0;
-
- if(on){
- ctlr->port[port-1].reg[PORTSC] |= PR;
- tsleep(&up->sleep, return0, nil, 200);
- }
- return 0;
-}
-
-static void
clkenable(int i, int on)
{
char clk[32];
@@ -1826,19 +66,15 @@
reset(Hci *hp)
{
static char *powerdom[] = { "usb_otg1", "usb_otg2" };
- static Ctlr ctlrs[2];
- Ctlr *ctlr;
+ static Xhci *ctlrs[2];
+ Xhci *ctlr;
int i;
for(i=0; i<nelem(ctlrs); i++){
- ctlr = &ctlrs[i];
- if(ctlr->active == nil){
- ctlr->active = hp;
- ctlr->mmio = (u32int*)(VIRTIO + 0x8100000 + i*0x100000);
- hp->aux = ctlr;
- hp->port = (uintptr)ctlr->mmio - KZERO;
- hp->tbdf = BUSUNKNOWN;
- hp->irq = IRQusb1 + i;
+ if(ctlrs[i] == nil){
+ uintptr base = VIRTIO + 0x8100000 + i*0x100000;
+ ctlr = xhcialloc((u32int*)base, base - KZERO, 0x100000);
+ ctlrs[i] = ctlr;
goto Found;
}
}
@@ -1845,6 +81,10 @@
return -1;
Found:
+ xhcilinkage(hp, ctlr);
+ hp->tbdf = BUSUNKNOWN;
+ hp->irq = IRQusb1 + i;
+
if(i == 0){
iomuxpad("pad_gpio1_io13", "usb1_otg_oc", "~LVTTL ~HYS ~PUE ~ODE FAST 45_OHM");
iomuxpad("pad_gpio1_io14", "gpio1_io14", "~LVTTL HYS PUE ~ODE FAST 45_OHM");
@@ -1864,21 +104,6 @@
clkenable(i, 1);
phyinit(&ctlr->mmio[0xF0040/4]);
coreinit(ctlr->mmio);
-
- hp->init = init;
- hp->dump = dump;
- hp->interrupt = interrupt;
- hp->epopen = epopen;
- hp->epclose = epclose;
- hp->epread = epread;
- hp->epwrite = epwrite;
- hp->seprintep = seprintep;
- hp->portenable = portenable;
- hp->portreset = portreset;
- hp->portstatus = portstatus;
- hp->shutdown = shutdown;
- hp->debug = setdebug;
- hp->type = "xhci";
return 0;
}
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -86,8 +86,8 @@
pcmciamodem
usbuhci pci
usbohci pci
- usbehci usbehcipc
- usbxhci pci
+ usbehci pci usbehcipc
+ usbxhci pci usbxhcipci
audiosb16 dma
audioac97 pci audioac97mix
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -85,7 +85,7 @@
usbuhci pci
usbohci pci
usbehci pci usbehcipc
- usbxhci pci
+ usbxhcipci pci usbxhci
# audiosb16 dma
# audioac97 pci audioac97mix
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -109,8 +109,9 @@
sysproc.$O: /sys/include/a.out.h
syscallfmt.$O: /sys/src/libc/9syscall/sys.h
devusb.$O usbxhci.$O: ../port/usb.h
+usbxhci.$O usbxhcipci.$O: ../port/usbxhci.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: ../ip/ip.h ../ip/ipv6.h
ethermii.$O: ../port/ethermii.h
-pci.$O devpnp.$O devpci.$O usbxhci.$O: ../port/pci.h
+pci.$O devpnp.$O devpci.$O usbxhcipci.$O: ../port/pci.h
--- a/sys/src/9/port/usbxhci.c
+++ b/sys/src/9/port/usbxhci.c
@@ -4,10 +4,11 @@
#include "dat.h"
#include "fns.h"
#include "io.h"
-#include "../port/pci.h"
#include "../port/error.h"
#include "../port/usb.h"
+#include "usbxhci.h"
+
enum {
/* Capability Registers */
CAPLENGTH = 0x00/4, // 1
@@ -222,10 +223,8 @@
struct Ctlr
{
- Pcidev *pcidev;
+ Xhci;
- u32int *mmio;
-
u32int *opr; /* operational registers */
u32int *rts; /* runtime registers */
u32int *dba; /* doorbell array */
@@ -255,8 +254,6 @@
int nslots;
Rendez recover;
- void *active;
- uvlong base;
};
struct Epio
@@ -358,7 +355,7 @@
}
static u64int
-resetring(Ring *r)
+resetring(Ctlr *ctlr, Ring *r)
{
u64int pa;
@@ -365,7 +362,7 @@
ilock(r);
flushring(r);
r->rp = r->wp;
- pa = PCIWADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1);
+ pa = (*ctlr->dmaaddr)(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1);
iunlock(r);
return pa;
@@ -376,7 +373,7 @@
{
u32int x, *e;
- e = &ctlr->mmio[ctlr->pcidev->mem[0].size/4];
+ e = &ctlr->mmio[ctlr->size/4];
if(p == nil){
p = ctlr->mmio;
x = ctlr->hccparams>>16;
@@ -417,8 +414,8 @@
r[0] &= ~(1<<16);
}
-static void
-shutdown(Hci *hp)
+void
+xhcishutdown(Hci *hp)
{
Ctlr *ctlr = hp->aux;
int i;
@@ -426,8 +423,7 @@
ctlr->opr[USBCMD] = 0;
for(i=0; (ctlr->opr[USBSTS] & HCH) == 0 && i < 10; i++)
delay(10);
- intrdisable(ctlr->pcidev->intl, hp->interrupt, hp, ctlr->pcidev->tbdf, hp->type);
- pcidisable(ctlr->pcidev);
+ intrdisable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
}
static void
@@ -454,8 +450,8 @@
static void recover(void *arg);
-static void
-init(Hci *hp)
+void
+xhciinit(Hci *hp)
{
Ctlr *ctlr;
Port *pp;
@@ -464,12 +460,6 @@
int i, j;
ctlr = hp->aux;
- pcienable(ctlr->pcidev);
- if(ctlr->mmio[CAPLENGTH] == -1){
- pcidisable(ctlr->pcidev);
- error("controller vanished");
- }
-
ctlr->opr = &ctlr->mmio[(ctlr->mmio[CAPLENGTH]&0xFF)/4];
ctlr->dba = &ctlr->mmio[ctlr->mmio[DBOFF]/4];
ctlr->rts = &ctlr->mmio[ctlr->mmio[RTSOFF]/4];
@@ -481,18 +471,21 @@
tsleep(&up->sleep, return0, nil, 10);
ctlr->opr[USBCMD] = HCRST;
+
/* some intel controllers require 1ms delay after reset */
- delay(1);
+ tsleep(&up->sleep, return0, nil, 1);
+
for(i=0; (ctlr->opr[USBCMD] & HCRST) != 0 && i<100; i++)
tsleep(&up->sleep, return0, nil, 10);
for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != HCH && i<100; i++)
tsleep(&up->sleep, return0, nil, 10);
- pcisetbme(ctlr->pcidev);
- intrenable(ctlr->pcidev->intl, hp->interrupt, hp, ctlr->pcidev->tbdf, hp->type);
+ if(ctlr->dmaenable != nil)
+ (*ctlr->dmaenable)(ctlr);
+ intrenable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
if(waserror()){
- shutdown(hp);
+ (*hp->shutdown)(hp);
release(ctlr);
nexterror();
}
@@ -540,11 +533,11 @@
error(Enomem);
for(i=0, p = ctlr->sbp; i<ctlr->nscratch; i++, p += ctlr->pagesize){
memset(p, 0, ctlr->pagesize);
- ctlr->sba[i] = PCIWADDR(p);
+ ctlr->sba[i] = (*ctlr->dmaaddr)(p);
}
dmaflush(1, ctlr->sbp, ctlr->nscratch*ctlr->pagesize);
dmaflush(1, ctlr->sba, ctlr->nscratch*8);
- ctlr->dcba[0] = PCIWADDR(ctlr->sba);
+ ctlr->dcba[0] = (*ctlr->dmaaddr)(ctlr->sba);
} else {
ctlr->dcba[0] = 0;
}
@@ -554,12 +547,12 @@
ctlr->opr[CONFIG] = (ctlr->opr[CONFIG] & 0xFFFFFC00) | ctlr->nslots; /* MaxSlotsEn */
dmaflush(1, ctlr->dcba, (1+ctlr->nslots)*sizeof(ctlr->dcba[0]));
- setrptr(&ctlr->opr[DCBAAP], PCIWADDR(ctlr->dcba));
+ setrptr(&ctlr->opr[DCBAAP], (*ctlr->dmaaddr)(ctlr->dcba));
initring(ctlr->cr, 8); /* 256 entries */
ctlr->cr->id = 0;
ctlr->cr->doorbell = &ctlr->dba[0];
- setrptr(&ctlr->opr[CRCR], resetring(ctlr->cr));
+ setrptr(&ctlr->opr[CRCR], resetring(ctlr, ctlr->cr));
for(i=0; i<ctlr->nintrs; i++){
u32int *irs = &ctlr->rts[IR0 + i*8];
@@ -578,7 +571,7 @@
ctlr->erst[i] = mallocalign(4*4, 64, 0, 0);
if(ctlr->erst[i] == nil)
error(Enomem);
- *((u64int*)ctlr->erst[i]) = PCIWADDR(ctlr->er[i].base);
+ *((u64int*)ctlr->erst[i]) = (*ctlr->dmaaddr)(ctlr->er[i].base);
ctlr->erst[i][2] = ctlr->er[i].mask+1;
ctlr->erst[i][3] = 0;
dmaflush(1, ctlr->erst[i], 4*4);
@@ -586,8 +579,8 @@
irs[ERSTSZ] = 1; /* just one segment */
irs[IMAN] = 3;
irs[IMOD] = 0;
- setrptr(&irs[ERSTBA], PCIWADDR(ctlr->erst[i]));
- setrptr(&irs[ERDP], PCIWADDR(ctlr->er[i].base) | (1<<3));
+ setrptr(&irs[ERSTBA], (*ctlr->dmaaddr)(ctlr->erst[i]));
+ setrptr(&irs[ERDP], (*ctlr->dmaaddr)(ctlr->er[i].base) | (1<<3));
}
poperror();
@@ -620,7 +613,7 @@
;
while(!needrecover(ctlr))
tsleep(&ctlr->recover, needrecover, ctlr, 1000);
- shutdown(hp);
+ (*hp->shutdown)(hp);
/*
* flush all transactions and wait until all devices have
@@ -665,7 +658,7 @@
if(waserror()) {
print("xhci recovery failed: %s\n", up->errstr);
} else {
- init(hp);
+ (*hp->init)(hp);
poperror();
}
@@ -687,8 +680,9 @@
x = r->wp++;
if((x & r->mask) == r->mask){
+ Ctlr *ctlr = r->slot->ctlr;
td = r->base + 4*(x & r->mask);
- *(u64int*)td = PCIWADDR(r->base);
+ *(u64int*)td = (*ctlr->dmaaddr)(r->base);
td[2] = 0;
td[3] = ((~x>>r->shift)&1) | (1<<1) | TR_LINK;
dmaflush(1, td, 4*4);
@@ -833,7 +827,7 @@
}
static void
-completering(Ring *r, u32int *er)
+completering(Ctlr *ctlr, Ring *r, u32int *er)
{
Wait *w, **wp;
u32int *td, x;
@@ -841,10 +835,9 @@
pa = (*(u64int*)er) & ~15ULL;
ilock(r);
-
for(x = r->rp; (int)(r->wp - x) > 0; x++){
td = &r->base[4*(x & r->mask)];
- if((u64int)PCIWADDR(td) == pa){
+ if((*ctlr->dmaaddr)(td) == pa){
if(r->residue != nil)
r->residue[x & r->mask] = er[2] & 0xFFFFFF;
r->rp = x+1;
@@ -854,7 +847,7 @@
wp = &r->pending;
while(w = *wp){
- if((u64int)PCIWADDR(w->td) == pa){
+ if((*ctlr->dmaaddr)(w->td) == pa){
Rendez *z = w->z;
memmove(w->er, er, 4*4);
@@ -899,7 +892,7 @@
switch(td[3] & 0xFC00){
case ER_CMDCOMPL:
- completering(ctlr->cr, td);
+ completering(ctlr, ctlr->cr, td);
break;
case ER_TRANSFER:
x = td[3]>>24;
@@ -908,7 +901,7 @@
slot = ctlr->slot[x];
if(slot == nil)
break;
- completering(&slot->epr[(td[3]>>16)-1&31], td);
+ completering(ctlr, &slot->epr[(td[3]>>16)-1&31], td);
break;
case ER_MFINDEXWRAP:
ctlr->µframe = (ctlr->rts[MFINDEX] & (1<<14)-1) |
@@ -931,7 +924,7 @@
}
}
- setrptr(&irs[ERDP], PCIWADDR(td) | (1<<3));
+ setrptr(&irs[ERDP], (*ctlr->dmaaddr)(td) | (1<<3));
}
static void
@@ -1003,7 +996,7 @@
poperror();
dmaflush(1, slot->obase, 32*32 << ctlr->csz);
- ctlr->dcba[slot->id] = PCIWADDR(slot->obase);
+ ctlr->dcba[slot->id] = (*ctlr->dmaaddr)(slot->obase);
dmaflush(1, &ctlr->dcba[slot->id], sizeof(ctlr->dcba[0]));
ctlr->slot[slot->id] = slot;
@@ -1066,7 +1059,8 @@
memset(w, 0, 2*32<<ctlr->csz);
dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
- ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
+ ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0,
+ (*ctlr->dmaaddr)(slot->ibase), nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
freering(io[OREAD].ring);
@@ -1078,7 +1072,7 @@
}
static void
-initepctx(u32int *w, Ring *r, Ep *ep)
+initepctx(Ctlr *ctlr, u32int *w, Ring *r, Ep *ep)
{
int ival;
@@ -1093,7 +1087,7 @@
w[1] = ((ep->ttype-Tctl) | (r->id&1)<<2)<<3 | (ep->ntds-1)<<8 | ep->maxpkt<<16;
if(ep->ttype != Tiso)
w[1] |= 3<<1;
- *((u64int*)&w[2]) = PCIWADDR(r->base) | 1;
+ *((u64int*)&w[2]) = (*ctlr->dmaaddr)(r->base) | 1;
w[4] = 2*ep->maxpkt;
if(ep->ttype == Tintr || ep->ttype == Tiso)
w[4] |= (ep->maxpkt*ep->ntds)<<16;
@@ -1180,17 +1174,18 @@
w += (ep->nb&Epmax)*2*8<<ctlr->csz;
if(io[OWRITE].ring != nil){
memset(w, 0, 5*4);
- initepctx(w, io[OWRITE].ring, ep);
+ initepctx(ctlr, w, io[OWRITE].ring, ep);
}
w += 8<<ctlr->csz;
if(io[OREAD].ring != nil){
memset(w, 0, 5*4);
- initepctx(w, io[OREAD].ring, ep);
+ initepctx(ctlr, w, io[OREAD].ring, ep);
}
dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
- err = ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
+ err = ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0,
+ (*ctlr->dmaaddr)(slot->ibase), nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
if(err != nil)
error(err);
@@ -1302,10 +1297,11 @@
/* (input) ep context 0 */
w += 8<<ctlr->csz;
- initepctx(w, io[OWRITE].ring, ep);
+ initepctx(ctlr, w, io[OWRITE].ring, ep);
dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
- err = ctlrcmd(ctlr, CR_ADDRESSDEV | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
+ err = ctlrcmd(ctlr, CR_ADDRESSDEV | (slot->id<<24), 0,
+ (*ctlr->dmaaddr)(slot->ibase), nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
if(err != nil)
error(err);
@@ -1382,7 +1378,8 @@
m = io->tdsz;
d = io->b->rp + (i&io->ring->mask)*io->tdsz;
dmaflush(1, d, m);
- queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m, PCIWADDR(d), nil);
+ queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m,
+ (*ctlr->dmaaddr)(d), nil);
}
io->frame = i;
@@ -1439,7 +1436,8 @@
m += io->nleft, d -= io->nleft;
io->nleft = 0;
dmaflush(1, d, m);
- queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m, PCIWADDR(d), nil);
+ queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m,
+ (*ctlr->dmaaddr)(d), nil);
}
io->frame = i;
@@ -1464,6 +1462,7 @@
static char*
unstall(Ep *ep, Ring *r)
{
+ Ctlr *ctlr = r->slot->ctlr;
char *err;
switch(r->ctx[0]&7){
@@ -1473,15 +1472,16 @@
}
if(ep->clrhalt){
ep->clrhalt = 0;
- err = ctlrcmd(r->slot->ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
- dmaflush(0, r->ctx, 8*4 << r->slot->ctlr->csz);
+ err = ctlrcmd(ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
+ dmaflush(0, r->ctx, 8*4 << ctlr->csz);
if(err != nil)
return err;
r->stopped = 1;
}
if(r->stopped){
- err = ctlrcmd(r->slot->ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0, resetring(r), nil);
- dmaflush(0, r->ctx, 8*4 << r->slot->ctlr->csz);
+ err = ctlrcmd(ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0,
+ resetring(ctlr, r), nil);
+ dmaflush(0, r->ctx, 8*4 << ctlr->csz);
if(err != nil)
return err;
r->stopped = 0;
@@ -1548,7 +1548,7 @@
error(err);
dmaflush(1, p, n);
- queuetd(io->ring, TR_NORMAL | TR_IOC, n, PCIWADDR(p), w);
+ queuetd(io->ring, TR_NORMAL | TR_IOC, n, (*ctlr->dmaaddr)(p), w);
err = waittd(ctlr, w, ep->tmout);
dmaflush(0, p, n);
if(err != nil)
@@ -1625,9 +1625,10 @@
w[0] = 0;
w[1] = 1<<ring->id;
w += (ring->id+1)*8<<ctlr->csz;
- initepctx(w, ring, ep);
+ initepctx(ctlr, w, ring, ep);
dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
- err = ctlrcmd(ctlr, CR_EVALCTX | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
+ err = ctlrcmd(ctlr, CR_EVALCTX | (slot->id<<24), 0,
+ (*ctlr->dmaaddr)(slot->ibase), nil);
dmaflush(0, slot->obase, 32*32 << ctlr->csz);
if(err != nil)
error(err);
@@ -1634,12 +1635,11 @@
}
queuetd(ring, TR_SETUPSTAGE | (len > 0 ? 2+dir : 0)<<16 | TR_IDT | TR_IOC, 8,
- p[0] | p[1]<<8 | GET2(&p[2])<<16 |
- (u64int)(GET2(&p[4]) | len<<16)<<32, &w[0]);
+ p[0] | p[1]<<8 | GET2(&p[2])<<16 | (u64int)(GET2(&p[4]) | len<<16)<<32, &w[0]);
if(len > 0){
dmaflush(1, io->b->rp, len);
queuetd(ring, TR_DATASTAGE | dir<<16 | TR_IOC, len,
- PCIWADDR(io->b->rp), &w[1]);
+ (*ctlr->dmaaddr)(io->b->rp), &w[1]);
}
queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | TR_IOC, 0, 0, &w[2]);
@@ -1700,7 +1700,7 @@
error(err);
dmaflush(1, p, n);
- queuetd(io->ring, TR_NORMAL | TR_IOC, n, PCIWADDR(p), w);
+ queuetd(io->ring, TR_NORMAL | TR_IOC, n, (*ctlr->dmaaddr)(p), w);
if((err = waittd(ctlr, w, ep->tmout)) != nil)
error(err);
@@ -1783,93 +1783,40 @@
return 0;
}
-
-static Ctlr *ctlrs[Nhcis];
-
-static void
-scanpci(void)
+static u64int
+physaddr(void *va)
{
- static int already = 0;
- int i;
- uvlong io;
- Ctlr *ctlr;
- Pcidev *p;
- u32int *mmio;
-
- if(already)
- return;
- already = 1;
- p = nil;
- while ((p = pcimatch(p, 0, 0)) != nil) {
- /*
- * Find XHCI controllers (Programming Interface = 0x30).
- */
- if(p->ccrb != Pcibcserial || p->ccru != Pciscusb || p->ccrp != 0x30)
- continue;
- if(p->mem[0].bar & 1)
- continue;
- io = p->mem[0].bar & ~0x0f;
- if(io == 0)
- continue;
- print("usbxhci: %#x %#x: port %llux size %lld irq %d\n",
- p->vid, p->did, io, p->mem[0].size, p->intl);
- mmio = vmap(io, p->mem[0].size);
- if(mmio == nil){
- print("usbxhci: cannot map registers\n");
- continue;
- }
- ctlr = malloc(sizeof(Ctlr));
- if(ctlr == nil){
- print("usbxhci: no memory\n");
- vunmap(mmio, p->mem[0].size);
- continue;
- }
- ctlr->base = io;
- ctlr->active = nil;
- ctlr->pcidev = p;
- ctlr->mmio = mmio;
- for(i = 0; i < nelem(ctlrs); i++)
- if(ctlrs[i] == nil){
- ctlrs[i] = ctlr;
- break;
- }
- if(i >= nelem(ctlrs))
- print("xhci: bug: more than %d controllers\n", nelem(ctlrs));
- }
+ return PADDR(va);
}
-static int
-reset(Hci *hp)
+Xhci*
+xhcialloc(u32int *mmio, u64int base, u64int size)
{
Ctlr *ctlr;
- int i;
- if(getconf("*nousbxhci"))
- return -1;
+ ctlr = malloc(sizeof(Ctlr));
+ if(ctlr == nil){
+ print("usbxhci: no memory for controller\n");
+ return nil;
+ }
+ ctlr->base = base;
+ ctlr->size = size;
+ ctlr->mmio = mmio;
- scanpci();
+ ctlr->dmaaddr = physaddr;
- /*
- * Any adapter matches if no hp->port is supplied,
- * otherwise the ports must match.
- */
- for(i = 0; i < nelem(ctlrs) && ctlrs[i] != nil; i++){
- ctlr = ctlrs[i];
- if(ctlr->active == nil)
- if(hp->port == 0 || hp->port == ctlr->base){
- ctlr->active = hp;
- goto Found;
- }
- }
- return -1;
+ return ctlr;
+}
-Found:
- hp->aux = ctlr;
+void
+xhcilinkage(Hci *hp, Xhci *ctlr)
+{
hp->port = ctlr->base;
- hp->irq = ctlr->pcidev->intl;
- hp->tbdf = ctlr->pcidev->tbdf;
+ hp->aux = ctlr;
- hp->init = init;
+ hp->init = xhciinit;
+ hp->shutdown = xhcishutdown;
+
hp->dump = dump;
hp->interrupt = interrupt;
hp->epopen = epopen;
@@ -1880,15 +1827,14 @@
hp->portenable = portenable;
hp->portreset = portreset;
hp->portstatus = portstatus;
- hp->shutdown = shutdown;
+
hp->debug = setdebug;
hp->type = "xhci";
- return 0;
+ ctlr->active = hp;
}
void
usbxhcilink(void)
{
- addhcitype("xhci", reset);
}
--- /dev/null
+++ b/sys/src/9/port/usbxhci.h
@@ -1,0 +1,23 @@
+/*
+ * I/O interface for usb XHCI controller.
+ */
+
+typedef struct Xhci Xhci;
+struct Xhci
+{
+ u32int *mmio;
+ u64int base;
+ u64int size;
+
+ void *aux;
+ void (*dmaenable)(Xhci*);
+ u64int (*dmaaddr)(void*);
+
+ Hci *active;
+};
+
+Xhci* xhcialloc(u32int *mmio, u64int base, u64int size);
+void xhcilinkage(Hci *hp, Xhci *ctlr);
+
+void xhciinit(Hci *hp);
+void xhcishutdown(Hci *hp);
--- /dev/null
+++ b/sys/src/9/port/usbxhcipci.c
@@ -1,0 +1,146 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "../port/error.h"
+#include "../port/usb.h"
+
+#include "usbxhci.h"
+
+static Xhci *ctlrs[Nhcis];
+
+static void
+pcidmaenable(Xhci *ctlr)
+{
+ Pcidev *pcidev = ctlr->aux;
+ pcisetbme(pcidev);
+}
+
+static u64int
+pciwaddr(void *va)
+{
+ return PCIWADDR(va);
+}
+
+static void
+scanpci(void)
+{
+ static int already = 0;
+ int i;
+ u64int io, iosize;
+ Xhci *ctlr;
+ Pcidev *p;
+ u32int *mmio;
+
+ if(already)
+ return;
+ already = 1;
+ p = nil;
+ while ((p = pcimatch(p, 0, 0)) != nil) {
+ /*
+ * Find XHCI controllers (Programming Interface = 0x30).
+ */
+ if(p->ccrb != Pcibcserial || p->ccru != Pciscusb || p->ccrp != 0x30)
+ continue;
+ if(p->mem[0].bar & 1)
+ continue;
+ iosize = p->mem[0].size;
+ if(iosize == 0)
+ continue;
+ io = p->mem[0].bar & ~0x0f;
+ if(io == 0)
+ continue;
+ print("usbxhci: %#x %#x: port %llux size %lld irq %d\n",
+ p->vid, p->did, io, iosize, p->intl);
+ mmio = vmap(io, iosize);
+ if(mmio == nil){
+ print("usbxhci: cannot map registers\n");
+ continue;
+ }
+ ctlr = xhcialloc(mmio, io, iosize);
+ if(ctlr == nil){
+ print("usbxhci: no memory\n");
+ vunmap(mmio, iosize);
+ continue;
+ }
+ ctlr->aux = p;
+ ctlr->dmaenable = pcidmaenable;
+ ctlr->dmaaddr = pciwaddr;
+
+ for(i = 0; i < nelem(ctlrs); i++)
+ if(ctlrs[i] == nil){
+ ctlrs[i] = ctlr;
+ break;
+ }
+ if(i >= nelem(ctlrs))
+ print("xhci: bug: more than %d controllers\n", nelem(ctlrs));
+ }
+}
+
+static void
+init(Hci *hp)
+{
+ Xhci *xhci = hp->aux;
+ Pcidev *pcidev = xhci->aux;
+
+ pcienable(pcidev);
+ if(xhci->mmio[0] == -1){
+ pcidisable(pcidev);
+ error("controller vanished");
+ }
+ xhciinit(hp);
+}
+
+static void
+shutdown(Hci *hp)
+{
+ Xhci *xhci = hp->aux;
+ Pcidev *pcidev = xhci->aux;
+
+ xhcishutdown(hp);
+ pcidisable(pcidev);
+}
+
+static int
+reset(Hci *hp)
+{
+ Xhci *ctlr;
+ Pcidev *pcidev;
+ int i;
+
+ if(getconf("*nousbxhci"))
+ return -1;
+
+ scanpci();
+
+ /*
+ * Any adapter matches if no hp->port is supplied,
+ * otherwise the ports must match.
+ */
+ for(i = 0; i < nelem(ctlrs) && ctlrs[i] != nil; i++){
+ ctlr = ctlrs[i];
+ if(ctlr->active == nil)
+ if(hp->port == 0 || hp->port == ctlr->base)
+ goto Found;
+ }
+ return -1;
+
+Found:
+ pcidev = ctlr->aux;
+ xhcilinkage(hp, ctlr);
+ hp->init = init;
+ hp->shutdown = shutdown;
+ hp->irq = pcidev->intl;
+ hp->tbdf = pcidev->tbdf;
+
+ return 0;
+}
+
+void
+usbxhcipcilink(void)
+{
+ addhcitype("xhci", reset);
+}