]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/usbohci.c
kernel: cleanup makefile for $CONF.$O target
[plan9front.git] / sys / src / 9 / pc / usbohci.c
index 522a8df394dc49021789af65c363bd4f2feaa3d4..d24f2388e463ca2ffa944d066054035bc7f746be 100644 (file)
@@ -37,8 +37,8 @@ enum
 {
        Incr            = 64,           /* for Td and Ed pools */
 
-       Align           = 0x20,         /* OHCI only requires 0x10 */
-                                       /* use always a power of 2 */
+       Edalign         = 0x10,
+       Tdalign         = 0x20, 
 
        Abortdelay      = 1,            /* delay after cancelling Tds (ms) */
        Tdatomic                = 8,            /* max nb. of Tds per bulk I/O op. */
@@ -108,6 +108,7 @@ enum
        Cie             = 0x08,         /* iso. list enable */
        Ccle            = 0x10,         /* ctl list enable */
        Cble            = 0x20,         /* bulk list enable */
+       Cir             = 0x100,        /* interrupt routing (smm active) */
        Cfsmask         = 3 << 6,       /* functional state... */
        Cfsreset        = 0 << 6,
        Cfsresume       = 1 << 6,
@@ -115,6 +116,7 @@ enum
        Cfssuspend      = 3 << 6,
 
        /* command status */
+       Socr =  1 << 3,                 /* ownership change request */
        Sblf =  1 << 2,                 /* bulk list (load) flag */
        Sclf =  1 << 1,                 /* control list (load) flag */
        Shcr =  1 << 0,                 /* host controller reset */
@@ -348,6 +350,7 @@ struct Ctlr
        Qtree*  tree;           /* tree for t Ep i/o */
        int     ntree;          /* number of dummy Eds in tree */
        Pcidev* pcidev;
+       uintptr base;
 };
 
 #define dqprint                if(debug || io && io->debug)print
@@ -579,19 +582,20 @@ tdtok(Td *td)
 static Td*
 tdalloc(void)
 {
+       uchar *pool;
        Td *td;
-       Td *pool;
        int i;
 
        lock(&tdpool);
        if(tdpool.free == nil){
                ddprint("ohci: tdalloc %d Tds\n", Incr);
-               pool = xspanalloc(Incr*sizeof(Td), Align, 0);
+               pool = xspanalloc(Incr*ROUND(sizeof(Td), Tdalign), Tdalign, 0);
                if(pool == nil)
-                       panic("tdalloc");
+                       panic("ohci: tdalloc");
                for(i=Incr; --i>=0;){
-                       pool[i].next = tdpool.free;
-                       tdpool.free = &pool[i];
+                       td = (Td*)(pool + i*ROUND(sizeof(Td), Tdalign));
+                       td->next = tdpool.free;
+                       tdpool.free = td;
                }
                tdpool.nalloc += Incr;
                tdpool.nfree += Incr;
@@ -600,10 +604,9 @@ tdalloc(void)
        tdpool.nfree--;
        td = tdpool.free;
        tdpool.free = td->next;
-       memset(td, 0, sizeof(Td));
        unlock(&tdpool);
-
-       assert(((uintptr)td & 0xF) == 0);
+       assert(((uintptr)td & 0x1F) == 0);
+       memset(td, 0, sizeof(Td));
        return td;
 }
 
@@ -628,18 +631,20 @@ tdfree(Td *td)
 static Ed*
 edalloc(void)
 {
-       Ed *ed, *pool;
+       uchar *pool;
+       Ed *ed;
        int i;
 
        lock(&edpool);
        if(edpool.free == nil){
                ddprint("ohci: edalloc %d Eds\n", Incr);
-               pool = xspanalloc(Incr*sizeof(Ed), Align, 0);
+               pool = xspanalloc(Incr*ROUND(sizeof(Ed), Edalign), Edalign, 0);
                if(pool == nil)
-                       panic("edalloc");
+                       panic("ohci: edalloc");
                for(i=Incr; --i>=0;){
-                       pool[i].next = edpool.free;
-                       edpool.free = &pool[i];
+                       ed = (Ed*)(pool + i*ROUND(sizeof(Ed), Edalign));
+                       ed->next = edpool.free;
+                       edpool.free = ed;
                }
                edpool.nalloc += Incr;
                edpool.nfree += Incr;
@@ -648,9 +653,9 @@ edalloc(void)
        edpool.nfree--;
        ed = edpool.free;
        edpool.free = ed->next;
-       memset(ed, 0, sizeof(Ed));
        unlock(&edpool);
-
+       assert(((uintptr)ed & 0xF) == 0);
+       memset(ed, 0, sizeof(Ed));
        return ed;
 }
 
@@ -819,7 +824,7 @@ seprinttd(char *s, char *e, Td *td, int iso)
 
        if(td == nil)
                return seprint(s, e, "<nil td>\n");
-       s = seprint(s, e, "%#p ep %#p ctrl %#p", td, td->ep, td->ctrl);
+       s = seprint(s, e, "%#p ep %#p ctrl %#lux", td, td->ep, td->ctrl);
        s = seprint(s, e, " cc=%#ulx", (td->ctrl >> Tdccshift) & Tdccmask);
        if(iso == 0){
                if((td->ctrl & Tdround) != 0)
@@ -834,7 +839,7 @@ seprinttd(char *s, char *e, Td *td, int iso)
                s = seprint(s, e, " fc=%uld", (td->ctrl >> Tdfcshift) & Tdfcmask);
                s = seprint(s, e, " sf=%uld", td->ctrl & Tdsfmask);
        }
-       s = seprint(s, e, " cbp0 %#p cbp %#p next %#p be %#p %s",
+       s = seprint(s, e, " cbp0 %#lux cbp %#lux next %#lux be %#lux %s",
                td->cbp0, td->cbp, td->nexttd, td->be, td->last ? "last" : "");
        s = seprint(s, e, "\n\t\t%ld bytes", td->nbytes);
        if((bp = td->bp) != nil){
@@ -896,7 +901,7 @@ dumped(Ed *ed)
        if(buf == nil)
                return;
        e = buf+512;
-       s = seprint(buf, e, "\ted %#p: ctrl %#p", ed, ed->ctrl);
+       s = seprint(buf, e, "\ted %#p: ctrl %#lux", ed, ed->ctrl);
        if((ed->ctrl & Edskip) != 0)
                s = seprint(s, e, " skip");
        if((ed->ctrl & Ediso) != 0)
@@ -912,7 +917,7 @@ dumped(Ed *ed)
                s = seprint(s, e, " hlt");
        s = seprint(s, e, " ep%uld.%uld", (ed->ctrl>>7)&Epmax, ed->ctrl&0x7f);
        s = seprint(s, e, " maxpkt %uld", (ed->ctrl>>Edmpsshift)&Edmpsmask);
-       seprint(s, e, " tail %#p head %#p next %#p\n",ed->tail,ed->head,ed->nexted);
+       seprint(s, e, " tail %#lux head %#lux next %#lux\n",ed->tail,ed->head,ed->nexted);
        print("%s", buf);
        free(buf);
        if(ed->tds != nil && (ed->ctrl & Ediso) == 0)
@@ -945,7 +950,7 @@ seprintep(char* s, char* e, Ep *ep)
        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:
@@ -1263,57 +1268,66 @@ isointerrupt(Ctlr *ctlr, Ep *ep, Qio *io, Td *td, int)
 static void
 interrupt(Ureg *, void *arg)
 {
-       Td *td, *ntd, *td0;
+       Td *td, *ntd;
        Hci *hp;
        Ctlr *ctlr;
-       ulong status, curred;
+       ulong status, curred, done;
        int i, frno;
 
        hp = arg;
        ctlr = hp->aux;
        ilock(ctlr);
+       done = ctlr->hcca->donehead;
        status = ctlr->ohci->intrsts;
+       if(status == ~0){
+               iunlock(ctlr);
+               return;
+       }
+       if(done & ~0xF){
+               ctlr->hcca->donehead = 0;
+               status |= Wdh;
+       }
+       else if(status & Wdh){
+               done = ctlr->hcca->donehead;
+               ctlr->hcca->donehead = 0;
+       }
+       status &= ~Mie;
+       if(status == 0){
+               iunlock(ctlr);
+               return;
+       }
+       ctlr->ohci->intrsts = status;
        status &= ctlr->ohci->intrenable;
        status &= Oc|Rhsc|Fno|Ue|Rd|Sf|Wdh|So;
-       frno = TRUNC(ctlr->ohci->fmnumber, Ntdframes);
-       if((status & Wdh) != 0){
-               /* lsb of donehead has bit to flag other intrs.  */
-               td = pa2ptr(ctlr->hcca->donehead & ~0xF);
-       }else
-               td = nil;
-       td0 = td;
-
-       for(i = 0; td != nil && i < 1024; i++){
-               if(0)ddprint("ohci tdinterrupt: td %#p\n", td);
-               ntd = pa2ptr(td->nexttd & ~0xF);
-               td->nexttd = 0;
-               if(td->ep == nil || td->io == nil)
-                       panic("ohci: interrupt: ep %#p io %#p", td->ep, td->io);
-               ohciinterrupts[td->ep->ttype]++;
-               if(td->ep->ttype == Tiso)
-                       isointerrupt(ctlr, td->ep, td->io, td, frno);
-               else
-                       qhinterrupt(ctlr, td->ep, td->io, td, frno);
-               td = ntd;
+       if(status & Wdh){
+               frno = TRUNC(ctlr->ohci->fmnumber, Ntdframes);
+               td = pa2ptr(done & ~0xF);
+               for(i = 0; td != nil && i < 1024; i++){
+                       if(0)ddprint("ohci tdinterrupt: td %#p\n", td);
+                       ntd = pa2ptr(td->nexttd & ~0xF);
+                       td->nexttd = 0;
+                       if(td->ep == nil || td->io == nil)
+                               panic("ohci: interrupt: ep %#p io %#p", td->ep, td->io);
+                       ohciinterrupts[td->ep->ttype]++;
+                       if(td->ep->ttype == Tiso)
+                               isointerrupt(ctlr, td->ep, td->io, td, frno);
+                       else
+                               qhinterrupt(ctlr, td->ep, td->io, td, frno);
+                       td = ntd;
+               }
+               if(i == 1024)
+                       iprint("ohci: bug: more than 1024 done Tds?\n");
+               status &= ~Wdh;
        }
-       if(i == 1024)
-               print("ohci: bug: more than 1024 done Tds?\n");
-
-       if(pa2ptr(ctlr->hcca->donehead & ~0xF) != td0)
-               print("ohci: bug: donehead changed before ack\n");
-       ctlr->hcca->donehead = 0;
-
-       ctlr->ohci->intrsts = status;
-       status &= ~Wdh;
        status &= ~Sf;
        if(status & So){
-               print("ohci: sched overrun: too much load\n");
+               iprint("ohci: sched overrun: too much load\n");
                ctlr->overrun++;
                status &= ~So;
        }
-       if((status & Ue) != 0){
+       if(status & Ue){
                curred = ctlr->ohci->periodcurred;
-               print("ohci: unrecoverable error frame 0x%.8lux ed 0x%.8lux, "
+               iprint("ohci: unrecoverable error frame 0x%.8lux ed 0x%.8lux, "
                        "ints %d %d %d %d\n",
                        ctlr->ohci->fmnumber, curred,
                        ohciinterrupts[Tctl], ohciinterrupts[Tintr],
@@ -1322,8 +1336,10 @@ interrupt(Ureg *, void *arg)
                        dumped(pa2ptr(curred));
                status &= ~Ue;
        }
-       if(status != 0)
-               print("ohci interrupt: unhandled sts 0x%.8lux\n", status);
+       if(status != 0){
+               iprint("ohci interrupt: unhandled sts 0x%.8lux\n", status);
+               ctlr->ohci->intrdisable = status;
+       }
        iunlock(ctlr);
 }
 
@@ -1706,7 +1722,7 @@ epctlio(Ep *ep, Ctlio *cio, void *a, long count)
        /* set the address if unset and out of configuration state */
        if(ep->dev->state != Dconfig && ep->dev->state != Dreset)
                if(cio->usbid == 0){
-                       cio->usbid = (ep->nb<<7)|(ep->dev->nb & Devmax);
+                       cio->usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax);
                        edsetaddr(cio->ed, cio->usbid);
                }
        /* adjust maxpkt if the user has learned a different one */
@@ -1973,7 +1989,7 @@ isoopen(Ctlr *ctlr, Ep *ep)
        int i;
 
        iso = ep->aux;
-       iso->usbid = (ep->nb<<7)|(ep->dev->nb & Devmax);
+       iso->usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax);
        iso->bw = ep->hz * ep->samplesz;        /* bytes/sec */
        if(ep->mode != OWRITE){
                print("ohci: bug: iso input streams not implemented\n");
@@ -2054,7 +2070,7 @@ epopen(Ep *ep)
        case Tintr:
                io = ep->aux = smalloc(sizeof(Qio)*2);
                io[OREAD].debug = io[OWRITE].debug = ep->debug;
-               usbid = (ep->nb<<7)|(ep->dev->nb & Devmax);
+               usbid = (ep->nb&Epmax)<<7 | (ep->dev->nb&Devmax);
                if(ep->mode != OREAD){
                        if(ep->toggle[OWRITE] != 0)
                                io[OWRITE].toggle = Tddata1;
@@ -2301,11 +2317,16 @@ init(Hci *hp)
        dprint("ohci %#p init\n", ctlr->ohci);
        ohci = ctlr->ohci;
 
-       fmi =  ctlr->ohci->fminterval;
-       ctlr->ohci->cmdsts = Shcr;         /* reset the block */
-       while(ctlr->ohci->cmdsts & Shcr)
-               delay(1);  /* wait till reset complete, Ohci says 10us max. */
-       ctlr->ohci->fminterval = fmi;
+       fmi = ohci->fminterval;
+       ohci->cmdsts = Shcr;    /* reset the block */
+       for(i = 0; i<100; i++){
+               if((ohci->cmdsts & Shcr) == 0)
+                       break;
+               delay(1);       /* wait till reset complete, Ohci says 10us max. */
+       }
+       if(i == 100)
+               print("ohci: reset timed out\n");
+       ohci->fminterval = fmi;
 
        /*
         * now that soft reset is done we are in suspend state.
@@ -2358,7 +2379,7 @@ init(Hci *hp)
 static void
 scanpci(void)
 {
-       ulong mem;
+       uintptr io;
        Ctlr *ctlr;
        Pcidev *p;
        int i;
@@ -2372,34 +2393,33 @@ scanpci(void)
                /*
                 * Find Ohci controllers (Programming Interface = 0x10).
                 */
-               if(p->ccrb != Pcibcserial || p->ccru != Pciscusb ||
-                   p->ccrp != 0x10)
+               if(p->ccrb != Pcibcserial || p->ccru != Pciscusb || p->ccrp != 0x10)
                        continue;
-               mem = p->mem[0].bar & ~0x0F;
-               dprint("ohci: %x/%x port 0x%lux size 0x%x irq %d\n",
-                       p->vid, p->did, mem, p->mem[0].size, p->intl);
-               if(mem == 0){
-                       print("usbohci: failed to map registers\n");
+               io = p->mem[0].bar & ~0x0F;
+               if(io == 0)
                        continue;
-               }
-
+               print("usbohci: %#x %#x: port %#p size %#x irq %d\n",
+                       p->vid, p->did, io, p->mem[0].size, p->intl);
                ctlr = malloc(sizeof(Ctlr));
                if(ctlr == nil){
-                       print("usbohci: no memory\n");
+                       print("ohci: no memory\n");
+                       continue;
+               }
+               if((ctlr->ohci = vmap(io, p->mem[0].size)) == nil){
+                       print("ohci: can't map ohci\n");
+                       free(ctlr);
                        continue;
                }
                ctlr->pcidev = p;
-               ctlr->ohci = vmap(mem, p->mem[0].size);
+               ctlr->base = io;
                dprint("scanpci: ctlr %#p, ohci %#p\n", ctlr, ctlr->ohci);
-               pcisetbme(p);
-               pcisetpms(p, 0);
                for(i = 0; i < Nhcis; i++)
                        if(ctlrs[i] == nil){
                                ctlrs[i] = ctlr;
                                break;
                        }
                if(i == Nhcis)
-                       print("usbohci: bug: no more controllers\n");
+                       print("ohci: bug: no more controllers\n");
        }
 }
 
@@ -2424,16 +2444,16 @@ mkqhtree(Ctlr *ctlr)
        n = (1 << (depth+1)) - 1;
        qt = mallocz(sizeof(*qt), 1);
        if(qt == nil)
-               panic("usb: can't allocate scheduling tree");
+               panic("ohci: can't allocate scheduling tree");
        qt->nel = n;
        qt->depth = depth;
        qt->bw = mallocz(n * sizeof(qt->bw), 1);
        qt->root = tree = mallocz(n * sizeof(Ed *), 1);
        if(qt->bw == nil || qt->root == nil)
-               panic("usb: can't allocate scheduling tree");
+               panic("ohci: can't allocate scheduling tree");
        for(i = 0; i < n; i++){
                if((tree[i] = edalloc()) == nil)
-                       panic("mkqhtree");
+                       panic("ohci: mkqhtree");
                tree[i]->ctrl = (8 << Edmpsshift);      /* not needed */
                tree[i]->ctrl |= Edskip;
 
@@ -2473,7 +2493,7 @@ ohcimeminit(Ctlr *ctlr)
 
        hcca = xspanalloc(sizeof(Hcca), 256, 0);
        if(hcca == nil)
-               panic("usbhreset: no memory for Hcca");
+               panic("ohci: no memory for Hcca");
        memset(hcca, 0, sizeof(*hcca));
        ctlr->hcca = hcca;
 
@@ -2483,9 +2503,23 @@ ohcimeminit(Ctlr *ctlr)
 static void
 ohcireset(Ctlr *ctlr)
 {
+       int i;
+
        ilock(ctlr);
        dprint("ohci %#p reset\n", ctlr->ohci);
 
+       if(ctlr->ohci->control & Cir){
+               dprint("ohci: smm active, taking over\n");
+               ctlr->ohci->cmdsts |= Socr;         /* take ownership */
+               for(i = 0; i<100; i++){
+                       if((ctlr->ohci->control & Cir) == 0)
+                               break;
+                       delay(1);
+               }
+               if(i == 100)
+                       print("ohci: smm takeover timed out\n");
+       }
+
        /*
         * usually enter here in reset, wait till its through,
         * then do our own so we are on known timing conditions.
@@ -2509,6 +2543,7 @@ shutdown(Hci *hp)
        ctlr = hp->aux;
 
        ilock(ctlr);
+       ctlr->ohci->intrdisable = Mie;
        ctlr->ohci->intrenable = 0;
        ctlr->ohci->control = 0;
        delay(100);
@@ -2536,7 +2571,7 @@ reset(Hci *hp)
        for(i = 0; i < Nhcis && ctlrs[i] != nil; i++){
                ctlr = ctlrs[i];
                if(ctlr->active == 0)
-               if(hp->port == 0 || hp->port == (uintptr)ctlr->ohci){
+               if(hp->port == 0 || hp->port == ctlr->base){
                        ctlr->active = 1;
                        break;
                }
@@ -2544,13 +2579,17 @@ reset(Hci *hp)
        iunlock(&resetlck);
        if(ctlrs[i] == nil || i == Nhcis)
                return -1;
-       if(ctlr->ohci->control == ~0)
-               return -1;
-
 
        p = ctlr->pcidev;
+       pcienable(p);
+
+       if(ctlr->ohci->control == ~0){
+               pcidisable(p);
+               return -1;
+       }
+
        hp->aux = ctlr;
-       hp->port = (uintptr)ctlr->ohci;
+       hp->port = ctlr->base;
        hp->irq = p->intl;
        hp->tbdf = p->tbdf;
        ctlr->nports = hp->nports = ctlr->ohci->rhdesca & 0xff;
@@ -2558,6 +2597,8 @@ reset(Hci *hp)
        ohcireset(ctlr);
        ohcimeminit(ctlr);
 
+       pcisetbme(p);
+
        /*
         * Linkage to the generic HCI driver.
         */
@@ -2575,6 +2616,8 @@ reset(Hci *hp)
        hp->shutdown = shutdown;
        hp->debug = usbdebug;
        hp->type = "ohci";
+       intrenable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
+
        return 0;
 }