]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/sdiahci.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / pc / sdiahci.c
index 85ebc8d4b02e3ff281b4b23c66139a2a192b7a67..d474f6209a37b6e513f40b3ae6392ed2ce1a7886 100644 (file)
@@ -353,7 +353,7 @@ asleep(int ms)
                esleep(ms);
 }
 
-static int
+static void
 ahciportreset(Aportc *c, uint mode)
 {
        ulong *cmd, i;
@@ -372,7 +372,6 @@ ahciportreset(Aportc *c, uint mode)
        p->sctl = 3*Aipm | 0*Aspd | Adet;
        delay(1);
        p->sctl = 3*Aipm | mode*Aspd;
-       return 0;
 }
 
 static int
@@ -787,12 +786,6 @@ clearci(Aport *p)
        }
 }
 
-static int
-intel(Ctlr *c)
-{
-       return c->pci->vid == 0x8086;
-}
-
 static int
 ignoreahdrs(Drive *d)
 {
@@ -1011,9 +1004,9 @@ lose:
 
 enum {
        Nms             = 256,
+       Mcomrwait       =  1*1024/Nms - 1,
        Mphywait        =  2*1024/Nms - 1,
        Midwait         = 16*1024/Nms - 1,
-       Mcomrwait       = 64*1024/Nms - 1,
 };
 
 static void
@@ -1110,6 +1103,7 @@ reset:
                        else
                                d->mode--;
                        if(d->mode == DMautoneg){
+                               d->wait = 0;
                                d->state = Dportreset;
                                goto portreset;
                        }
@@ -1141,7 +1135,6 @@ reset:
        case Doffline:
                if(d->wait++ & Mcomrwait)
                        break;
-               /* fallthrough */
        case Derror:
        case Dreset:
                dprint("%s: reset [%s]: mode %d; status %.3ux\n",
@@ -1152,8 +1145,12 @@ reset:
                break;
        case Dportreset:
 portreset:
-               if(d->wait++ & 0xff && (s & Iactive) == 0)
+               if(d->wait++ & Mcomrwait)
+                       break;
+               if(d->wait > Mcomrwait && (s & Iactive) == 0){
+                       d->state = Dnull;       /* stuck in portreset */
                        break;
+               }
                dprint("%s: portreset [%s]: mode %d; status %.3ux\n",
                        dnam(d), diskstates[d->state], d->mode, s);
                d->portm.flag |= Ferror;
@@ -1218,14 +1215,19 @@ static int
 ahciencreset(Ctlr *c)
 {
        Ahba *h;
+       int i;
 
        if(c->enctype == Eesb)
                return 0;
        h = c->hba;
        h->emctl |= Emrst;
-       while(h->emctl & Emrst)
-               delay(1);
-       return 0;
+       for(i = 0; i < 1000; i++){
+               if((h->emctl & Emrst) == 0)
+                       return 0;
+               esleep(1);
+       }
+       print("%s: ahciencreset: hung ctlr\n", Tname(c));
+       return -1;
 }
 
 /*
@@ -1304,9 +1306,11 @@ blink(Drive *d, ulong t)
                return 0;
        c = d->ctlr;
        h = c->hba;
+
        /* ensure last message has been transmitted */
-       while(h->emctl & Tmsg)
-               microdelay(1);
+       if(h->emctl & Tmsg)
+               return -1;
+
        switch(c->enctype){
        default:
                panic("%s: bad led type %d", dnam(d), c->enctype);
@@ -1406,30 +1410,34 @@ ledkproc(void*)
        memset(map, 0, sizeof map);
        for(i = 0; i < niactlr; i++)
                if(iactlr[i].enctype != 0){
-                       ahciencreset(iactlr + i);
+                       if(ahciencreset(iactlr + i) == -1)
+                               continue;
                        map[i] = 1;
                        j++;
                }
        if(j == 0)
                pexit("no work", 1);
        for(i = 0; i < niadrive; i++){
-               iadrive[i]->nled = 3;           /* hardcoded */
-               if(iadrive[i]->ctlr->enctype == Eesb)
-                       iadrive[i]->nled = 3;
-               iadrive[i]->ledbits = -1;
+               d = iadrive[i];
+               d->nled = 3;            /* hardcoded */
+               if(d->ctlr->enctype == Eesb)
+                       d->nled = 3;
+               d->ledbits = -1;
        }
        for(i = 0; ; i++){
                t0 = Ticks;
                for(j = 0; j < niadrive; ){
-                       c = iadrive[j]->ctlr;
-                       if(map[j] == 0)
-                               j += c->enctype;
-                       else if(c->enctype == Eesb){
+                       d = iadrive[j];
+                       c = d->ctlr;
+                       if(map[c - iactlr] == 0)
+                               j++;
+                       else
+                       if(c->enctype == Eesb){
                                blinkesb(c, i);
                                j += c->ndrive;
                        }else{
-                               d = iadrive[j++];
                                blink(d, i);
+                               j++;
                        }
                }
                t1 = Ticks;
@@ -1538,21 +1546,25 @@ iaenable(SDev *s)
 
        c = s->ctlr;
        ilock(c);
-       if(!c->enabled){
-               if(once == 0)
-                       kproc("iasata", satakproc, 0);
-               if(c->ndrive == 0)
-                       panic("iaenable: zero s->ctlr->ndrive");
-               pcisetbme(c->pci);
-               snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
-               intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
-               /* supposed to squelch leftover interrupts here. */
-               ahcienable(c->hba);
-               c->enabled = 1;
-               if(++once == niactlr)
-                       kproc("ialed", ledkproc, 0);
+       if(c->enabled){
+               iunlock(c);
+               return 1;
        }
+       if(c->ndrive == 0)
+               panic("iaenable: zero s->ctlr->ndrive");
+       pcisetbme(c->pci);
+       snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
+       intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
+       /* supposed to squelch leftover interrupts here. */
+       ahcienable(c->hba);
+       c->enabled = 1;
        iunlock(c);
+
+       if(once == 0)
+               kproc("iasata", satakproc, 0);
+       if(++once == niactlr)
+               kproc("ialed", ledkproc, 0);
+
        return 1;
 }
 
@@ -1957,20 +1969,6 @@ iaataio(SDreq *r)
        return r->status = SDeio;
 }
 
-/*
- * configure drives 0-5 as ahci sata  (c.f. errata)
- */
-static int
-iaahcimode(Pcidev *p)
-{
-       uint u;
-
-       u = pcicfgr16(p, 0x92);
-       dprint("ahci: %T: iaahcimode %.2ux %.4ux\n", p->tbdf, pcicfgr8(p, 0x91), u);
-       pcicfgw16(p, 0x92, u | 0xf);    /* ports 0-15 */
-       return 0;
-}
-
 enum{
        Ghc     = 0x04/4,       /* global host control */
        Pi      = 0x0c/4,       /* ports implemented */
@@ -1983,14 +1981,20 @@ enum{
 static void
 iasetupahci(Ctlr *c)
 {
+       if(c->type != Tich)
+               return;
+
        pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~Cmddec);
        pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~Cmddec);
 
        c->lmmio[Ghc] |= Ahcien;
-       c->lmmio[Pi] = (1 << 6) - 1;    /* 5 ports (supposedly ro pi reg) */
+       c->lmmio[Pi] = (1 << 6) - 1;    /* 6 ports (supposedly ro pi reg) */
 
        /* enable ahci mode; from ich9 datasheet */
        pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
+
+       /* configure drives 0-5 as ahci sata  (c.f. errata) */
+       pcicfgw16(c->pci, 0x92, pcicfgr16(c->pci, 0x92) | 0xf);
 }
 
 static void
@@ -2113,8 +2117,10 @@ didtype(Pcidev *p)
                break;
        case 0x1022:
                /* Hudson SATA Controller [AHCI mode] */
-               if(p->did == 0x7801)
+               if((p->did & 0xfffe) == 0x7800){
+                       sbsetupahci(p);
                        return Tahci;
+               }
                break;
        case 0x10de:
        case 0x1039:
@@ -2159,8 +2165,10 @@ iapnp(void)
        while((p = pcimatch(p, 0, 0)) != nil){
                if((type = didtype(p)) == -1)
                        continue;
-               if(p->mem[Abar].bar == 0)
+               io = p->mem[Abar].bar;
+               if(io == 0 || (io & 1) != 0 || p->mem[Abar].size < 0x180)
                        continue;
+               io &= ~0xf;
                if(niactlr == NCtlr){
                        print("iapnp: %s: too many controllers\n", tname[type]);
                        break;
@@ -2169,7 +2177,6 @@ iapnp(void)
                s = sdevs + niactlr;
                memset(c, 0, sizeof *c);
                memset(s, 0, sizeof *s);
-               io = p->mem[Abar].bar & ~0xf;
                c->mmio = vmap(io, p->mem[Abar].size);
                if(c->mmio == 0){
                        print("%s: address %#p in use did %.4ux\n",
@@ -2185,13 +2192,14 @@ iapnp(void)
                s->ctlr = c;
                c->sdev = s;
 
+               pcienable(p);
                ahcihandoff((Ahba*)c->mmio);
-               if(intel(c) && p->did != 0x2681)
+               if(p->vid == 0x8086)
                        iasetupahci(c);
-//             ahcihbareset((Ahba*)c->mmio);
                nunit = ahciconf(c);
-               if(intel(c) && iaahcimode(p) == -1 || nunit < 1){
+               if(nunit < 1){
                        vunmap(c->mmio, p->mem[Abar].size);
+                       pcidisable(p);
                        continue;
                }
                c->ndrive = s->nunit = nunit;
@@ -2208,11 +2216,14 @@ iapnp(void)
                        d->ctlr = c;
                        if((c->hba->pi & 1<<i) == 0)
                                continue;
-                       snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
-                       d->port = (Aport*)(c->mmio + 0x80*i + 0x100);
+                       io = 0x100 + 0x80*i;
+                       if((io + 0x80) > p->mem[Abar].size)
+                               continue;
+                       d->port = (Aport*)(c->mmio + io);
                        d->portc.p = d->port;
                        d->portc.m = &d->portm;
                        d->driveno = n++;
+                       snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
                        c->drive[d->driveno] = d;
                        iadrive[niadrive + d->driveno] = d;
                }