]> git.lizzy.rs Git - plan9front.git/commitdiff
devpccard, pci: fix pccard support and handle pci expansion roms
authorcinap_lenrek <cinap_lenrek@felloff.net>
Mon, 1 Mar 2021 16:24:54 +0000 (17:24 +0100)
committercinap_lenrek <cinap_lenrek@felloff.net>
Mon, 1 Mar 2021 16:24:54 +0000 (17:24 +0100)
let pci.c deal with the special cardbus controller bar0 and
expansion roms.

handle apic interrupt routing for devices behind a cardbus slot.

do not free the pcidev on card removal, as the drivers
most certanly are not prepared to handle this yet.
instead, we provide a pcidevfree() function that just unlinks
the device from pcilist and the parent bridge.

sys/src/9/bcm64/pcibcm.c
sys/src/9/mtx/pcimtx.c
sys/src/9/pc/devpccard.c
sys/src/9/pc/mp.c
sys/src/9/pc/pcipc.c
sys/src/9/port/pci.c
sys/src/9/port/pci.h
sys/src/9/teg2/pciteg.c

index 0ba9b51110a8384e6451e479f2219754f57b9c80..4e21d7e8616e239aee157b94dff6d1b1b89a6d6e 100644 (file)
@@ -210,7 +210,7 @@ pcicfginit(void)
 
        fmtinstall('T', tbdffmt);
 
-       pciscan(0, &pciroot);
+       pciscan(0, &pciroot, nil);
        if(pciroot == nil)
                return;
 
index a2425d6094338a8f79856d4af3b887e32f3f22ed..c6704c0e13f030beeb7b5f407a89e168e27beaa7 100644 (file)
@@ -67,7 +67,7 @@ pcicfginit(void)
        list = &pciroot;
        for(bno = 0; bno <= pcimaxbno; bno++) {
                int sbno = bno;
-               bno = pciscan(bno, list);
+               bno = pciscan(bno, list, nil);
 
                while(*list)
                        list = &(*list)->link;
index fdfcdd9b7b9724c3a0f9cfd823dc1557e0582d6f..88d29fb31e46a3f7c15e9bbbe7098fa8316b8437 100644 (file)
@@ -101,7 +101,6 @@ enum {
 
        PciPMC = 0xa4,
 
-       Nbars = 6,
        Ncmd = 10,
        CBIRQ = 9,
 
@@ -346,7 +345,7 @@ engine(Cardbus *cb, int message)
                        break;
                default:
                        if(DEBUG)
-                               print("#Y%ld: Invalid message %s in SlotEmpty state\n",
+                               print("#Y%zd: Invalid message %s in SlotEmpty state\n",
                                        cb - cbslots, messages[message]);
                        break;
                }
@@ -365,7 +364,7 @@ engine(Cardbus *cb, int message)
                        break;
                default:
                        if(DEBUG)
-                               print("#Y%ld: Invalid message %s in SlotFull state\n",
+                               print("#Y%zd: Invalid message %s in SlotFull state\n",
                                        cb - cbslots, messages[message]);
                        break;
                }
@@ -383,7 +382,7 @@ engine(Cardbus *cb, int message)
                        powerdown(cb);
                        break;
                default:
-                       print("#Y%ld: Invalid message %s in SlotPowered state\n",
+                       print("#Y%zd: Invalid message %s in SlotPowered state\n",
                                cb - cbslots, messages[message]);
                        break;
                }
@@ -399,7 +398,7 @@ engine(Cardbus *cb, int message)
                        break;
                default:
                        if(DEBUG)
-                               print("#Y%ld: Invalid message %s in SlotConfigured state\n",
+                               print("#Y%zd: Invalid message %s in SlotConfigured state\n",
                                        cb - cbslots, messages[message]);
                        break;
                }
@@ -492,7 +491,7 @@ cbinterrupt(Ureg *, void *)
                rdreg(cb, Rcsc);        /* Ack the interrupt */
 
                if(DEBUG)
-                       print("#Y%ld: interrupt: event %.8lX, state %.8lX, (%s)\n",
+                       print("#Y%zd: interrupt: event %.8lX, state %.8lX, (%s)\n",
                                cb - cbslots, event, state, states[cb->state]);
 
                if (event & SE_CCD) {
@@ -520,7 +519,6 @@ devpccardlink(void)
        static int initialized;
        Pcidev *pci;
        int i;
-       uchar intl;
        char *p;
 
        if (initialized)
@@ -539,9 +537,7 @@ devpccardlink(void)
 
        /* Find all CardBus controllers */
        pci = nil;
-       intl = 0xff;
        while ((pci = pcimatch(pci, 0, 0)) != nil) {
-               uvlong baddr;
                Cardbus *cb;
                uchar pin;
 
@@ -559,20 +555,20 @@ devpccardlink(void)
                cb->pci = pci;
                cb->variant = &variant[i];
 
-               if (pci->vid != TI_vid) {
-                       /*
-                        * Gross hack, needs a fix.  Inherit the mappings from
-                        * 9load for the TIs (pb)
-                        */
-                       pcicfgw32(pci, PciCBMBR0, 0xffffffff);
-                       pcicfgw32(pci, PciCBMLR0, 0);
-                       pcicfgw32(pci, PciCBMBR1, 0xffffffff);
-                       pcicfgw32(pci, PciCBMLR1, 0);
-                       pcicfgw32(pci, PciCBIBR0, 0xffffffff);
-                       pcicfgw32(pci, PciCBILR0, 0);
-                       pcicfgw32(pci, PciCBIBR1, 0xffffffff);
-                       pcicfgw32(pci, PciCBILR1, 0);
-               }
+               if(pci->mem[0].size == 0 || (pci->mem[0].bar & 0xF) != 0)
+                       continue;
+               cb->regs = (ulong *)vmap(pci->mem[0].bar & ~0xFULL, pci->mem[0].size);
+               if(cb->regs == nil)
+                       continue;
+
+               pcicfgw32(pci, PciCBMBR0, 0xffffffff);
+               pcicfgw32(pci, PciCBMLR0, 0);
+               pcicfgw32(pci, PciCBMBR1, 0xffffffff);
+               pcicfgw32(pci, PciCBMLR1, 0);
+               pcicfgw32(pci, PciCBIBR0, 0xffffffff);
+               pcicfgw32(pci, PciCBILR0, 0);
+               pcicfgw32(pci, PciCBIBR1, 0xffffffff);
+               pcicfgw32(pci, PciCBILR1, 0);
 
                /* Set up PCI bus numbers if needed. */
                if (pcicfgr8(pci, PciSBN) == 0) {
@@ -590,7 +586,7 @@ devpccardlink(void)
                        pcicfgw8(pci, PciINTL, pci->intl);
 
                        if (pci->intl == 0xff || pci->intl == 0)
-                               print("#Y%ld: No interrupt?\n", cb - cbslots);
+                               print("#Y%zd: No interrupt?\n", cb - cbslots);
                }
 
                /* Don't you love standards! */
@@ -632,30 +628,15 @@ devpccardlink(void)
                        pcicfgw8(cb->pci, 0x94, 0xCA);
                        pcicfgw8(cb->pci, 0xD4, 0xCA);
                }
-
-               baddr = pcicfgr32(cb->pci, PciBAR0);
-               if (baddr == 0) {
-                       int size = (pci->did == Ricoh_478_did)? 0x10000: 0x1000;
-                       baddr = upaalloc(-1ULL, size, size);
-                       if(baddr == -1)
-                               continue;
-                       pcicfgw32(cb->pci, PciBAR0, (ulong)baddr);
-                       cb->regs = (ulong *)vmap(baddr, size);
-               }
-               else
-                       cb->regs = (ulong *)vmap(baddr, 4096);
-               if(cb->regs == nil)
-                       continue;
                cb->state = SlotEmpty;
 
-               if (intl != 0xff && intl != pci->intl)
-                       intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus");
+               intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus");
 
                /* Don't really know what to do with this... */
                i82365probe(cb, LegacyAddr, LegacyAddr + 1);
 
-               print("#Y%ld: %s, %.8lluX intl %d\n", cb - cbslots,
-                        variant[i].name, baddr, pci->intl);
+               print("#Y%zd: %s, %.8lluX intl %d\n", cb - cbslots,
+                        variant[i].name, pci->mem[0].bar, pci->intl);
 
                nslots++;
        }
@@ -699,7 +680,7 @@ powerup(Cardbus *cb)
        state = cb->regs[SocketState];
        if (state & SS_PC16) {
                if(DEBUG)
-                       print("#Y%ld: Probed a PC16 card, powering up card\n",
+                       print("#Y%zd: Probed a PC16 card, powering up card\n",
                                cb - cbslots);
                cb->type = PC16;
                memset(&cb->linfo, 0, sizeof(Pcminfo));
@@ -719,19 +700,19 @@ powerup(Cardbus *cb)
                return 0;
 
        if (state & SS_NOTCARD) {
-               print("#Y%ld: No card inserted\n", cb - cbslots);
+               print("#Y%zd: No card inserted\n", cb - cbslots);
                return 0;
        }
 
        if ((state & SS_3V) == 0 && (state & SS_5V) == 0) {
-               print("#Y%ld: Unsupported voltage, powering down card!\n",
+               print("#Y%zd: Unsupported voltage, powering down card!\n",
                        cb - cbslots);
                cb->regs[SocketControl] = 0;
                return 0;
        }
 
        if(DEBUG)
-               print("#Y%ld: card %spowered at %d volt\n", cb - cbslots,
+               print("#Y%zd: card %spowered at %d volt\n", cb - cbslots,
                        (state & SS_POWER)? "": "not ",
                        (state & SS_3V)? 3: (state & SS_5V)? 5: -1);
 
@@ -777,10 +758,9 @@ powerdown(Cardbus *cb)
 static void
 configure(Cardbus *cb)
 {
-       int i, r;
        Pcidev *pci;
-       uvlong romlen, memlen, membase, rombase, bar;
-       ulong iobase, iolen, size;
+       ulong iobase, iolen;
+       uvlong membase, memlen;
 
        if(DEBUG)
                print("configuring slot %ld (%s)\n", cb - cbslots, states[cb->state]);
@@ -796,102 +776,68 @@ configure(Cardbus *cb)
        }
 
        /* Scan the CardBus for new PCI devices */
-       pciscan(pcicfgr8(cb->pci, PciSBN), &cb->pci->bridge);
+       pciscan(pcicfgr8(cb->pci, PciSBN), &cb->pci->bridge, cb->pci);
 
-       /*
-        * size the devices on the bus, reserve a minimum for devices arriving later,
-        * allow for ROM space, allocate space, and set the cardbus mapping registers
-        */
-       pcibussize(cb->pci->bridge, &memlen, &iolen);   /* TO DO: need initial alignments */
-
-       romlen = 0;
-       for(pci = cb->pci->bridge; pci != nil; pci = pci->list){
-               size = pcibarsize(pci, PciEBAR0);
-               if(size > 0){
-                       pci->rom.bar = -1;
-                       pci->rom.size = size;
-                       romlen += size;
-               }
-       }
+       /* size the devices on the bus, reserve a minimum for devices arriving later */
+       pcibussize(cb->pci->bridge, &memlen, &iolen);
 
        if(iolen < 512)
                iolen = 512;
-       iobase = ioreserve(-1, iolen, 0, "cardbus");
-       if(iobase == -1)
-               return;
-
-       rombase = memlen;
-       memlen += romlen;
        if(memlen < 1*1024*1024)
                memlen = 1*1024*1024;
-       membase = upaalloc(-1ULL, memlen, 4*1024*1024); /* TO DO: better alignment */
-       if(membase == -1)
+
+       print("#Y%zd: iolen=%lud, memlen=%llud\n", cb - cbslots, iolen, memlen);
+
+       if(cb->pci->parent == nil){
+               iobase = ioreserve(-1,
+                       iolen, iolen, "cardbus");
+               if(iobase == -1){
+NoIO:
+                       print("#Y%zd: can't allocate io space\n", cb - cbslots);
+                       return;
+               }
+               membase = upaalloc(-1ULL,
+                       memlen, 4*1024*1024);
+       } else {
+               iobase = ioreservewin(cb->pci->parent->ioa.bar, cb->pci->parent->ioa.size,
+                       iolen, iolen, "cardbus");
+               if(iobase == -1)
+                       goto NoIO;
+               membase = upaallocwin(cb->pci->parent->mema.bar, cb->pci->parent->mema.size,
+                       memlen, 4*1024*1024);
+       }
+       if(membase == -1){
+               print("#Y%zd: can't allocate memory space\n", cb - cbslots);
                return;
+       }
+
+       print("#Y%zd: iobase=%lux, membase=%llux\n", cb - cbslots, iobase, membase);
 
        pcicfgw32(cb->pci, PciCBIBR0, iobase);
        pcicfgw32(cb->pci, PciCBILR0, iobase + iolen-1);
-       pcicfgw32(cb->pci, PciCBIBR1, 0);
+       pcicfgw32(cb->pci, PciCBIBR1, 0xffffffff);
        pcicfgw32(cb->pci, PciCBILR1, 0);
+       cb->pci->ioa.bar = iobase;
+       cb->pci->ioa.size = iolen;
 
        pcicfgw32(cb->pci, PciCBMBR0, (ulong)membase);
        pcicfgw32(cb->pci, PciCBMLR0, (ulong)membase + memlen-1);
-       pcicfgw32(cb->pci, PciCBMBR1, 0);
+       pcicfgw32(cb->pci, PciCBMBR1, 0xffffffff);
        pcicfgw32(cb->pci, PciCBMLR1, 0);
+       cb->pci->mema.bar = membase;
+       cb->pci->mema.size = memlen;
 
-//     pcibussize(cb->pci->bridge, &membase, &iobase); /* now assign them */
-       rombase += membase;
-
-       for(pci = cb->pci->bridge; pci != nil; pci = pci->list){
-               r = pcicfgr16(pci, PciPCR);
-               r &= ~(PciPCR_IO|PciPCR_MEM);
-               pcicfgw16(pci, PciPCR, r);
-
-               /*
-                * Treat the found device as an ordinary PCI card.
-                * It seems that the CIS is not always present in
-                * CardBus cards.
-                * XXX, need to support multifunction cards
-                */
-               for(i = 0; i < Nbars; i++) {
-                       if(pci->mem[i].size == 0)
-                               continue;
-                       bar = pci->mem[i].bar;
-                       if(bar & 1)
-                               bar += iobase;
-                       else
-                               bar += membase;
-                       pci->mem[i].bar = bar;
-                       pcicfgw32(pci, PciBAR0 + 4*i, bar);
-                       if((bar & 1) == 0){
-                               print("%T mem[%d] %8.8llux %d\n", pci->tbdf, i, bar, pci->mem[i].size);
-                               if(bar & 0x80){ /* TO DO: enable prefetch */
-                                       ;
-                               }
-                       }
-               }
-               if((size = pcibarsize(pci, PciEBAR0)) > 0) {    /* TO DO: can this be done by pci.c? */
-                       pci->rom.bar = rombase;
-                       pci->rom.size = size;
-                       rombase += size;
-                       pcicfgw32(pci, PciEBAR0, pci->rom.bar);
-               }
+       /* Route interrupts to INTA#/B#, Disable prefetch for MEM0/1 */
+       pcicfgw16(cb->pci, PciBCR, pcicfgr16(cb->pci, PciBCR) & ~(7 << 7));
 
-               /* Set the basic PCI registers for the device */
-               pci->pcr = pcicfgr16(pci, PciPCR);
-               pci->pcr |= PciPCR_IO|PciPCR_MEM|PciPCR_Master;
-               pci->cls = 8;
-               pci->ltr = 64;
-               pcicfgw16(pci, PciPCR, pci->pcr);
-               pcicfgw8(pci, PciCLS, pci->cls);
-               pcicfgw8(pci, PciLTR, pci->ltr);
-
-               if (pcicfgr8(pci, PciINTP)) {
-                       pci->intl = pcicfgr8(cb->pci, PciINTL);
-                       pcicfgw8(pci, PciINTL, pci->intl);
+       /* Assign resources */
+       pcibusmap(cb->pci->bridge, &membase, &iobase, 1);
 
-                       /* Route interrupts to INTA#/B# */
-                       pcicfgw16(cb->pci, PciBCR,
-                                         pcicfgr16(cb->pci, PciBCR) & ~(1 << 7));
+       /* Assign legacy IRQ's */
+       for(pci = cb->pci->bridge; pci != nil; pci = pci->link) {
+               if(pcicfgr8(pci, PciINTP) != 0) {
+                       pci->intl = cb->pci->intl;
+                       pcicfgw8(pci, PciINTL, pci->intl);
                }
        }
 }
@@ -899,58 +845,51 @@ configure(Cardbus *cb)
 static void
 unconfigure(Cardbus *cb)
 {
-       Pcidev *pci;
-       int i, ioindex, memindex, r;
-
        if (cb->type == PC16) {
-               print("#Y%d: Don't know how to unconfigure a PC16 card\n",
-                        (int)(cb - cbslots));
-
+               print("#Y%zd: Don't know how to unconfigure a PC16 card\n", cb - cbslots);
                memset(&cb->linfo, 0, sizeof(Pcminfo));
                return;
        }
 
-       pci = cb->pci->bridge;
-       if (pci == nil)
-               return;         /* Not configured */
-       cb->pci->bridge = nil;
+       pcicfgw32(cb->pci, PciCBIBR0, 0xffffffff);
+       pcicfgw32(cb->pci, PciCBILR0, 0);
+       pcicfgw32(cb->pci, PciCBIBR1, 0xffffffff);
+       pcicfgw32(cb->pci, PciCBILR1, 0);
 
-       memindex = ioindex = 0;
-       while (pci) {
-               Pcidev *_pci;
+       pcicfgw32(cb->pci, PciCBMBR0, 0xffffffff);
+       pcicfgw32(cb->pci, PciCBMLR0, 0);
+       pcicfgw32(cb->pci, PciCBMBR1, 0xffffffff);
+       pcicfgw32(cb->pci, PciCBMLR1, 0);
 
-               for (i = 0; i != Nbars; i++) {
-                       if (pci->mem[i].size == 0)
-                               continue;
-                       if (pci->mem[i].bar & 1) {
+       /* free i/o space */
+       if(cb->pci->ioa.size){
+               Pcidev *pci;
+               int i;
+
+               for(pci = cb->pci->bridge; pci != nil; pci = pci->link) {
+                       for(i = 0; i < nelem(pci->mem); i++) {
+                               if((pci->mem[i].size == 0)
+                               || (pci->mem[i].bar & 1) == 0
+                               || (pci->mem[i].bar & ~3) == 0)
+                                       continue;
                                iofree(pci->mem[i].bar & ~3);
-                               pcicfgw16(cb->pci, PciCBIBR0 + ioindex * 8,
-                                                (ushort)-1);
-                               pcicfgw16(cb->pci, PciCBILR0 + ioindex * 8, 0);
-                               ioindex++;
-                               continue;
                        }
-
-                       upafree(pci->mem[i].bar & ~0xF, pci->mem[i].size);
-                       pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1);
-                       pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0);
-                       r = pcicfgr16(cb->pci, PciBCR);
-                       r &= ~(1 << (8 + memindex));
-                       pcicfgw16(cb->pci, PciBCR, r);
-                       memindex++;
-               }
-
-               if (pci->rom.bar && memindex < 2) {
-                       upafree(pci->rom.bar & ~0xF, pci->rom.size);
-                       pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1);
-                       pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0);
-                       memindex++;
                }
+               iofree(cb->pci->ioa.bar);
+               cb->pci->ioa.bar = 0;
+               cb->pci->ioa.size = 0;
+       }
 
-               _pci = pci->list;
-               free(_pci);
-               pci = _pci;
+       /* free memory space */
+       if(cb->pci->mema.size){
+               upafree(cb->pci->mema.bar, cb->pci->mema.size);
+               cb->pci->mema.bar = 0;
+               cb->pci->mema.size = 0;
        }
+
+       /* remove the devices */
+       while(cb->pci->bridge != nil)
+               pcidevfree(cb->pci->bridge);
 }
 
 static void
@@ -1174,7 +1113,7 @@ pccard_pcmspecial(char *idstr, ISAConf *isa)
        pi->irq = isa->irq;
        unlock(cb);
 
-       print("#Y%ld: %s irq %d, port %lluX\n", cb - cbslots, pi->verstr, isa->irq, isa->port);
+       print("#Y%zd: %s irq %d, port %lluX\n", cb - cbslots, pi->verstr, isa->irq, isa->port);
        return (int)(cb - cbslots);
 }
 
@@ -1321,10 +1260,10 @@ pccardread(Chan *c, void *a, long n, vlong offset)
                                Pcidev *pci = cb->pci->bridge;
                                int i;
 
-                               while (pci) {
+                               while (pci != nil) {
                                        p = seprint(p, e, "%.4uX %.4uX; irq %d\n",
                                                          pci->vid, pci->did, pci->intl);
-                                       for (i = 0; i != Nbars; i++)
+                                       for (i = 0; i < nelem(pci->mem); i++)
                                                if (pci->mem[i].size)
                                                        p = seprint(p, e,
                                                                          "\tmem[%d] %.8ullX (%.8uX)\n",
@@ -1333,7 +1272,7 @@ pccardread(Chan *c, void *a, long n, vlong offset)
                                        if (pci->rom.size)
                                                p = seprint(p, e, "\tROM %.8ullX (%.8uX)\n",
                                                                  pci->rom.bar, pci->rom.size);
-                                       pci = pci->list;
+                                       pci = pci->link;
                                }
                        }
                        break;
index abb3e010ee4f38c57d596c9dda3682c276e78a41..ede29b323964c73ccb5c2a84e2e7301fb34314e0 100644 (file)
@@ -351,13 +351,19 @@ Findbus:
 
        if(bus == nil){
                /*
-                * if the PCI device is behind a PCI-PCI bridge thats not described
-                * by the MP or ACPI tables then walk up the bus translating interrupt
-                * pin to parent bus.
+                * if the PCI device is behind a bridge thats not described
+                * by the MP or ACPI tables then walk up the bus translating
+                * interrupt pin to parent bus.
                 */
                if(pci != nil && pci->parent != nil && pin > 0){
-                       pin = ((dno+(pin-1))%4)+1;
                        pci = pci->parent;
+                       if(pci->ccrb == 6 && pci->ccru == 7){
+                               /* Cardbus bridge, use controllers interrupt pin */
+                               pin = pcicfgr8(pci, PciINTP);
+                       } else {
+                               /* PCI-PCI bridge */
+                               pin = ((dno+(pin-1))%4)+1;
+                       }
                        bno = BUSBNO(pci->tbdf);
                        dno = BUSDNO(pci->tbdf);
                        goto Findbus;
index 3355e7b0ceaea56542efb2fb09c70c4b7098e84a..f5bb530bb614b77e2161a9e4863159c493a333ed 100644 (file)
@@ -557,6 +557,10 @@ pcireserve(void)
                                upaalloc(pa, p->mem[i].size, 0);
                        }
                }
+               if(p->rom.size && (p->rom.bar & 1) != 0){
+                       pa = p->rom.bar & ~0x7FFULL;
+                       upaalloc(pa, p->rom.size, 0);
+               }
        }
 
        /*
@@ -688,7 +692,7 @@ pcicfginit(void)
        list = &pciroot;
        for(bno = 0; bno <= pcimaxbno; bno++) {
                int sbno = bno;
-               bno = pciscan(bno, list);
+               bno = pciscan(bno, list, nil);
 
                while(*list)
                        list = &(*list)->link;
index 3efe83b003f3d61b61a99536c66863827d9c6cfa..bf5f43af02de8edd899d4cfa00c94391599c36c2 100644 (file)
@@ -18,8 +18,7 @@ struct Pcisiz
 int pcimaxdno;
 
 static Lock pcicfglock;
-static Pcidev* pcilist;
-static Pcidev* pcitail;
+static Pcidev *pcilist, **pcitail;
 
 static char* bustypes[] = {
        "CBUSI",
@@ -68,6 +67,46 @@ tbdffmt(Fmt* fmt)
        }
 }
 
+static Pcidev*
+pcidevalloc(void)
+{
+       Pcidev *p;
+
+       p = xalloc(sizeof(*p));
+       if(p == nil)
+               panic("pci: no memory for Pcidev");
+       return p;
+}
+
+void
+pcidevfree(Pcidev *p)
+{
+       Pcidev **l;
+
+       if(p == nil)
+               return;
+
+       while(p->bridge != nil)
+               pcidevfree(p->bridge);
+
+       if(p->parent != nil){
+               for(l = &p->parent->bridge; *l != nil; l = &(*l)->link) {
+                       if(*l == p) {
+                               *l = p->link;
+                               break;
+                       }
+               }
+       }
+       for(l = &pcilist; *l != nil; l = &(*l)->list) {
+               if(*l == p) {
+                       if((*l = p->list) == nil)
+                               pcitail = l;
+                       break;
+               }
+       }
+       /* leaked */
+}
+
 int
 pcicfgr8(Pcidev* p, int rno)
 {
@@ -135,12 +174,15 @@ pcibarsize(Pcidev *p, int rno)
        pcicfgrw32(p->tbdf, rno, v, 0);
        iunlock(&pcicfglock);
 
-       if(v & 1){
+       if(rno == PciEBAR0 || rno == PciEBAR1){
+               size &= ~0x7FF;
+       } else if(v & 1){
                size = (short)size;
                size &= ~3;
        } else {
                size &= ~0xF;
        }
+
        return -size;
 }
 
@@ -217,7 +259,7 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg)
                ntb++;
 
        ntb *= (PciCIS-PciBAR0)/4;
-       table = malloc(2*ntb*sizeof(Pcisiz));
+       table = malloc((2*ntb+1)*sizeof(Pcisiz));
        if(table == nil)
                panic("pcibusmap: can't allocate memory");
        itb = table;
@@ -228,6 +270,22 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg)
         */
        for(p = root; p != nil; p = p->link) {
                if(p->ccrb == 0x06) {
+                       /* carbus bridge? */
+                       if(p->ccru == 0x07){
+                               if(pcicfgr32(p, PciBAR0) & 1)
+                                       continue;
+                               size = pcibarsize(p, PciBAR0);
+                               if(size == 0)
+                                       continue;
+                               mtb->dev = p;
+                               mtb->bar = 0;
+                               mtb->siz = size;
+                               mtb->typ = 0;
+                               mtb++;
+                               continue;
+                       }
+
+                       /* pci bridge? */
                        if(p->ccru != 0x04 || p->bridge == nil)
                                continue;
 
@@ -252,9 +310,27 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg)
                        mtb->siz = hole;
                        mtb->typ = 0;
                        mtb++;
+
+                       size = pcibarsize(p, PciEBAR1);
+                       if(size != 0){
+                               mtb->dev = p;
+                               mtb->bar = -3;
+                               mtb->siz = size;
+                               mtb->typ = 0;
+                               mtb++;
+                       }
                        continue;
                }
 
+               size = pcibarsize(p, PciEBAR0);
+               if(size != 0){
+                       mtb->dev = p;
+                       mtb->bar = -2;
+                       mtb->siz = size;
+                       mtb->typ = 0;
+                       mtb++;
+               }
+
                for(i = 0; i < nelem(p->mem); i++) {
                        rno = PciBAR0 + i*4;
                        v = pcicfgr32(p, rno);
@@ -321,6 +397,14 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg)
                        if(tptr->bar == -1) {
                                p->mema.bar = mema;
                                p->mema.size = tptr->siz;
+                       } else if(tptr->bar == -2) {
+                               p->rom.bar = mema|1;
+                               p->rom.size = tptr->siz;
+                               pcisetbar(p, PciEBAR0, p->rom.bar);
+                       } else if(tptr->bar == -3) {
+                               p->rom.bar = mema|1;
+                               p->rom.size = tptr->siz;
+                               pcisetbar(p, PciEBAR1, p->rom.bar);
                        } else {
                                p->mem[tptr->bar].size = tptr->siz;
                                p->mem[tptr->bar].bar = mema|tptr->typ;
@@ -409,10 +493,10 @@ pcivalidbar(Pcidev *p, uvlong bar, int size)
        }
 }
 
-static int
-pcilscan(int bno, Pcidev** list, Pcidev *parent)
+int
+pciscan(int bno, Pcidev** list, Pcidev *parent)
 {
-       Pcidev *p, *head, *tail;
+       Pcidev *p, *head, **tail;
        int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
 
        maxubn = bno;
@@ -437,19 +521,11 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent)
 
                        if(l == 0xFFFFFFFF || l == 0)
                                continue;
-                       p = malloc(sizeof(*p));
-                       if(p == nil)
-                               panic("pcilscan: can't allocate memory");
+                       p = pcidevalloc();
                        p->tbdf = tbdf;
                        p->vid = l;
                        p->did = l>>16;
 
-                       if(pcilist != nil)
-                               pcitail->list = p;
-                       else
-                               pcilist = p;
-                       pcitail = p;
-
                        p->pcr = pcicfgr16(p, PciPCR);
                        p->rid = pcicfgr8(p, PciRID);
                        p->ccrp = pcicfgr8(p, PciCCRp);
@@ -502,20 +578,43 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent)
                                        }
                                        rno += 4;
                                }
+
+                               p->rom.bar = (ulong)pcicfgr32(p, PciEBAR0);
+                               p->rom.size = pcibarsize(p, PciEBAR0);
                                break;
 
-                       case 0x05:              /* memory controller */
                        case 0x06:              /* bridge device */
+                               /* cardbus bridge? */
+                               if(p->ccru == 0x07){
+                                       p->mem[0].bar = (ulong)pcicfgr32(p, PciBAR0);
+                                       p->mem[0].size = pcibarsize(p, PciBAR0);
+                                       break;
+                               }
+
+                               /* pci bridge? */
+                               if(p->ccru != 0x04)
+                                       break;
+
+                               p->rom.bar = (ulong)pcicfgr32(p, PciEBAR1);
+                               p->rom.size = pcibarsize(p, PciEBAR1);
+                               break;
+                       case 0x05:              /* memory controller */
                        default:
                                break;
                        }
 
                        p->parent = parent;
                        if(head != nil)
-                               tail->link = p;
+                               *tail = p;
                        else
                                head = p;
-                       tail = p;
+                       tail = &p->link;
+
+                       if(pcilist != nil)
+                               *pcitail = p;
+                       else
+                               pcilist = p;
+                       pcitail = &p->list;
                }
        }
 
@@ -529,6 +628,7 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent)
                        if(p->ccru == 0x04)
                                break;
                default:
+                       /* check and clear invalid membars for non bridges */
                        for(i = 0; i < nelem(p->mem); i++) {
                                if(p->mem[i].size == 0)
                                        continue;
@@ -540,9 +640,24 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent)
                                        pcisetbar(p, PciBAR0 + i*4, p->mem[i].bar);
                                }
                        }
+                       if(p->rom.size) {
+                               if((p->rom.bar & 1) == 0
+                               || !pcivalidbar(p, p->rom.bar & ~0x7FFUL, p->rom.size)){
+                                       p->rom.bar = 0;
+                                       pcisetbar(p, PciEBAR0, p->rom.bar);
+                               }
+                       }
                        continue;
                }
 
+               if(p->rom.size) {
+                       if((p->rom.bar & 1) == 0
+                       || !pcivalidbar(p, p->rom.bar & ~0x7FFULL, p->rom.size)){
+                               p->rom.bar = 0;
+                               pcisetbar(p, PciEBAR1, p->rom.bar);
+                       }
+               }
+
                /*
                 * If the secondary or subordinate bus number is not
                 * initialised try to do what the PCI BIOS should have
@@ -581,7 +696,7 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent)
                        pcisetwin(p, 0xFFF00000|0, 0);
                        pcisetwin(p, 0xFFF00000|8, 0);
 
-                       maxubn = pcilscan(sbn, &p->bridge, p);
+                       maxubn = pciscan(sbn, &p->bridge, p);
                        l = (maxubn<<16)|(sbn<<8)|bno;
 
                        pcicfgw32(p, PciPBN, l);
@@ -635,19 +750,13 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent)
 
                        if(ubn > maxubn)
                                maxubn = ubn;
-                       pcilscan(sbn, &p->bridge, p);
+                       pciscan(sbn, &p->bridge, p);
                }
        }
 
        return maxubn;
 }
 
-int
-pciscan(int bno, Pcidev **list)
-{
-       return pcilscan(bno, list, nil);
-}
-
 void
 pcibussize(Pcidev *root, uvlong *msize, ulong *iosize)
 {
@@ -720,6 +829,8 @@ pcilhinv(Pcidev* p)
                                continue;
                        print("%d:%.8llux %d ", i, t->mem[i].bar, t->mem[i].size);
                }
+               if(t->rom.bar || t->rom.size)
+                       print("rom:%.8llux %d ", t->rom.bar, t->rom.size);
                if(t->ioa.bar || t->ioa.size)
                        print("ioa:%.8llux-%.8llux %d ", t->ioa.bar, t->ioa.bar+t->ioa.size, t->ioa.size);
                if(t->mema.bar || t->mema.size)
index fc84d1e2b22285f1a6e9d8f49d38953c2ad56496..7d4acb2f852d22535d036bb37be52d1635a22225 100644 (file)
@@ -96,7 +96,7 @@ enum {                                        /* type 1 pre-defined header */
        PciPULR         = 0x2C,         /* prefetchable limit upper 32 bits */
        PciIUBR         = 0x30,         /* I/O base upper 16 bits */
        PciIULR         = 0x32,         /* I/O limit upper 16 bits */
-       PciEBAR1        = 0x28,         /* expansion ROM base address */
+       PciEBAR1        = 0x38,         /* expansion ROM base address */
        PciBCR          = 0x3E,         /* bridge control register */
 };
 
@@ -173,31 +173,34 @@ struct Pcidev
        uchar   cls;
        uchar   ltr;
 
+       uchar   intl;                   /* interrupt line */
+
        struct {
                uvlong  bar;            /* base address */
                int     size;
        } mem[6];
 
-       struct {
+       struct {                        /* expansion rom bar */
                uvlong  bar;    
                int     size;
        } rom;
-       uchar   intl;                   /* interrupt line */
-
-       Pcidev* list;
-       Pcidev* link;                   /* next device on this bno */
 
-       Pcidev* parent;                 /* up a bus */
-       Pcidev* bridge;                 /* down a bus */
-       struct {
+       struct {                        /* 32-bit io and memory windows */
                uvlong  bar;
                int     size;
        } ioa, mema;
-       struct {
+
+       struct {                        /* 64-bit prefechable memory window */
                uvlong  bar;
                uvlong  size;
        } prefa;
 
+       Pcidev* list;
+       Pcidev* link;                   /* next device on this bno */
+
+       Pcidev* parent;                 /* up a bus */
+       Pcidev* bridge;                 /* down a bus */
+
        int     pmrb;                   /* power management register block */
        int     msi;                    /* MSI capability register block */
 };
@@ -221,6 +224,8 @@ enum
 
 extern int pcimaxdno;
 
+extern void pcidevfree(Pcidev* pcidev);
+
 extern int pcicfgr32(Pcidev* pcidev, int rno);
 extern void pcicfgw32(Pcidev* pcidev, int rno, int data);
 extern int pcicfgr16(Pcidev* pcidev, int rno);
@@ -228,7 +233,7 @@ extern void pcicfgw16(Pcidev* pcidev, int rno, int data);
 extern int pcicfgr8(Pcidev* pcidev, int rno);
 extern void pcicfgw8(Pcidev* pcidev, int rno, int data);
 
-extern int pciscan(int bno, Pcidev **list);
+extern int pciscan(int bno, Pcidev **list, Pcidev *parent);
 extern void pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg);
 extern void pcibussize(Pcidev *root, uvlong *msize, ulong *iosize);
 
index d6cc8a2917bfdf32c36bb6b7123140aae5752d5e..96430ee36fce3979d8cc22047cbf7768b73dfb8a 100644 (file)
@@ -181,7 +181,7 @@ pcicfginit(void)
        list = &pciroot;
        /* was bno = 0; trimslice needs to start at 1 */
        for(bno = 1; bno <= pcimaxbno; bno++) {
-               bno = pciscan(bno, list);
+               bno = pciscan(bno, list, nil);
                while(*list)
                        list = &(*list)->link;
        }