]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/etherbcm.c
devether: mux bridges, portable netconsole
[plan9front.git] / sys / src / 9 / pc / etherbcm.c
index a82e748d8ab074a90dd35dbd5b9667ae217ea51d..ab030f7dcd8ef7d73640c43b420e2c7b38e75c59 100644 (file)
@@ -15,8 +15,7 @@
 #include "io.h"
 #include "../port/error.h"
 #include "../port/netif.h"
-
-#include "etherif.h"
+#include "../port/etherif.h"
 
 #define Rbsz           ROUNDUP(sizeof(Etherpkt)+4, 4)
 
@@ -30,7 +29,7 @@ struct Ctlr {
        ulong *recvret, *recvprod, *sendr;
        ulong port;
        ulong recvreti, recvprodi, sendri, sendcleani;
-       Block **sends;
+       Block **sends, **recvs;
        int active, duplex;
 };
 
@@ -50,9 +49,11 @@ enum {
        MiscHostCtl = 0x68,
        ClearIntA = 1<<0,
        MaskPCIInt = 1<<1,
-       IndirectAccessEnable = 1<<7,
+       ByteSwap = 1<<2,
+       WordSwap = 1<<3,
        EnablePCIStateRegister = 1<<4,
        EnableClockControlRegister = 1<<5,
+       IndirectAccessEnable = 1<<7,
        TaggedStatus = 1<<9,
        
        DMARWControl = 0x6C,
@@ -193,6 +194,89 @@ enum {
        FrameError = 1<<10,
 };
 
+enum {
+       BCM5752 = 0x1600, 
+       BCM5752M = 0x1601, 
+       BCM5709 = 0x1639, 
+       BCM5709S = 0x163a, 
+       BCM5716 = 0x163b, 
+       BCM5716S = 0x163c, 
+       BCM5700 = 0x1644, 
+       BCM5701 = 0x1645, 
+       BCM5702 = 0x1646, 
+       BCM5703 = 0x1647, 
+       BCM5704 = 0x1648, 
+       BCM5704S_2 = 0x1649, 
+       BCM5706 = 0x164a, 
+       BCM5708 = 0x164c, 
+       BCM5702FE = 0x164d, 
+       BCM57710 = 0x164e, 
+       BCM57711 = 0x164f, 
+       BCM57711E = 0x1650, 
+       BCM5705 = 0x1653, 
+       BCM5705_2 = 0x1654, 
+       BCM5717 = 0x1655, 
+       BCM5718 = 0x1656, 
+       BCM5720 = 0x1658, 
+       BCM5721 = 0x1659, 
+       BCM5722 = 0x165a, 
+       BCM5723 = 0x165b, 
+       BCM5724 = 0x165c, 
+       BCM5705M = 0x165d, 
+       BCM5705M_2 = 0x165e, 
+       BCM5714 = 0x1668, 
+       BCM5780 = 0x166a, 
+       BCM5780S = 0x166b, 
+       BCM5754M = 0x1672, 
+       BCM5755M = 0x1673, 
+       BCM5756ME = 0x1674, 
+       BCM5750 = 0x1676, 
+       BCM5751 = 0x1677, 
+       BCM5715 = 0x1678, 
+       BCM5715S = 0x1679, 
+       BCM5754 = 0x167a, 
+       BCM5755 = 0x167b, 
+       BCM5750M = 0x167c, 
+       BCM5751M = 0x167d, 
+       BCM5751F = 0x167e, 
+       BCM5787F = 0x167f, 
+       BCM5761e = 0x1680, 
+       BCM5761 = 0x1681, 
+       BCM5764M = 0x1684, 
+       BCM57760 = 0x1690, 
+       BCM57788 = 0x1691, 
+       BCM57780 = 0x1692, 
+       BCM5787M = 0x1693, 
+       BCM57790 = 0x1694, 
+       BCM5782 = 0x1696, 
+       BCM5784M = 0x1698, 
+       BCM5785 = 0x1699, 
+       BCM5786 = 0x169a, 
+       BCM5787 = 0x169b, 
+       BCM5788 = 0x169c, 
+       BCM5789 = 0x169d, 
+       BCM5785_2 = 0x16a0, 
+       BCM5702X = 0x16a6, 
+       BCM5703X = 0x16a7, 
+       BCM5704S = 0x16a8, 
+       BCM5706S = 0x16aa, 
+       BCM5708S = 0x16ac, 
+       BCM57761 = 0x16b0, 
+       BCM57781 = 0x16b1, 
+       BCM57791 = 0x16b2, 
+       BCM57765 = 0x16b4, 
+       BCM57785 = 0x16b5, 
+       BCM57795 = 0x16b6, 
+       BCM5702A3 = 0x16c6, 
+       BCM5703_2 = 0x16c7, 
+       BCM5781 = 0x16dd, 
+       BCM5753 = 0x16f7, 
+       BCM5753M = 0x16fd, 
+       BCM5753F = 0x16fe, 
+       BCM5906 = 0x1712,
+       BCM5906M = 0x1713,
+};
+
 #define csr32(c, r)    ((c)->nic[(r)/4])
 #define mem32(c, r) csr32(c, (r)+0x8000)
 
@@ -285,21 +369,25 @@ static int
 replenish(Ctlr *ctlr)
 {
        ulong *next;
-       ulong incr;
+       ulong incr, idx;
        Block *bp;
-       
-       incr = (ctlr->recvprodi + 1) & (RecvProdRingLen - 1);
+
+       idx = ctlr->recvprodi;
+       incr = (idx + 1) & (RecvProdRingLen - 1);
        if(incr == (ctlr->status[2] >> 16)) return -1;
+       if(ctlr->recvs[idx] != 0) return -1;
        bp = iallocb(Rbsz);
        if(bp == nil) {
                print("bcm: out of memory for receive buffers\n");
                return -1;
        }
-       next = ctlr->recvprod + ctlr->recvprodi * 8;
+       ctlr->recvs[idx] = bp;
+       next = ctlr->recvprod + idx * 8;
        memset(next, 0, 32);
        next[1] = PADDR(bp->rp);
        next[2] = Rbsz;
-       next[7] = (ulong) bp;
+       next[7] = idx;
+       coherence();
        csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;
        return 0;
 }
@@ -309,18 +397,24 @@ bcmreceive(Ether *edev)
 {
        Ctlr *ctlr;
        Block *bp;
-       ulong *pkt, len;
+       ulong *pkt, len, idx;
        
        ctlr = edev->ctlr;
        for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
-               bp = (Block*) pkt[7];
+               idx = pkt[7] & (RecvProdRingLen - 1);
+               bp = ctlr->recvs[idx];
+               if(bp == 0) {
+                       print("bcm: nil block at %lux -- shouldn't happen\n", idx);
+                       break;
+               }
+               ctlr->recvs[idx] = 0;
                len = pkt[2] & 0xFFFF;
                bp->wp = bp->rp + len;
                if((pkt[3] & PacketEnd) == 0) print("bcm: partial frame received -- shouldn't happen\n");
                if(pkt[3] & FrameError) {
                        freeb(bp); /* dump erroneous packets */ 
                } else {
-                       etheriq(edev, bp, 1);
+                       etheriq(edev, bp);
                }
        }
 }
@@ -360,7 +454,6 @@ bcmtransmit(Ether *edev)
                }
                bp = qget(edev->oq);
                if(bp == nil) break;
-               setmalloctag(bp, (ulong)(void*)bcmtransmit);
                next = ctlr->sendr + ctlr->sendri * 4;
                next[0] = 0;
                next[1] = PADDR(bp->rp);
@@ -369,6 +462,7 @@ bcmtransmit(Ether *edev)
                if(ctlr->sends[ctlr->sendri] != 0)
                        freeb(ctlr->sends[ctlr->sendri]);
                ctlr->sends[ctlr->sendri] = bp;
+               coherence();
                csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr;
        }
        iunlock(&ctlr->txlock);
@@ -425,7 +519,7 @@ bcminterrupt(Ureg*, void *arg)
        iunlock(&ctlr->imlock);
 }
 
-static void
+static int
 bcminit(Ether *edev)
 {
        ulong i, j;
@@ -436,24 +530,43 @@ bcminit(Ether *edev)
        /* initialization procedure according to the datasheet */
        csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA;
        csr32(ctlr, SwArbitration) |= SwArbitSet1;
-       while((csr32(ctlr, SwArbitration) & SwArbitWon1) == 0);
+       for(i = 0; i < 10000 && (csr32(ctlr, SwArbitration) & SwArbitWon1) == 0; i++)
+               microdelay(100);
+       if(i == 10000){
+               iprint("bcm: arbiter failed to respond\n");
+               return -1;
+       }
        csr32(ctlr, MemArbiterMode) |= Enable;
        csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister;
+       csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
+       csr32(ctlr, ModeControl) |= ByteWordSwap;
        csr32(ctlr, MemoryWindow) = 0;
        mem32(ctlr, 0xB50) = 0x4B657654; /* magic number bullshit */
        csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE;
        csr32(ctlr, MiscConfiguration) |= CoreClockBlocksReset;
        microdelay(100000);
-       ctlr->pdev->pcr |= 1<<1;
+       ctlr->pdev->pcr |= 1<<1; /* pci memory access enable */
        pcisetbme(ctlr->pdev);
        csr32(ctlr, MiscHostCtl) |= MaskPCIInt;
        csr32(ctlr, MemArbiterMode) |= Enable;
+       csr32(ctlr, MiscHostCtl) = (csr32(ctlr, MiscHostCtl) & ~(ByteSwap|WordSwap)) | WordSwap;
        csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister | TaggedStatus;
        csr32(ctlr, ModeControl) |= ByteWordSwap;
        csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
        microdelay(40000);
-       while(mem32(ctlr, 0xB50) != 0xB49A89AB);
-       csr32(ctlr, TLPControl) |= (1<<25) | (1<<29);
+       for(i = 0; i < 100000 && mem32(ctlr, 0xB50) != 0xB49A89AB; i++)
+               microdelay(100);
+       if(i == 100000){
+               iprint("bcm: chip failed to reset\n");
+               return -1;
+       }
+       switch(ctlr->pdev->did){
+       case BCM5721:
+       case BCM5751:
+       case BCM5752:
+               csr32(ctlr, TLPControl) |= (1<<25) | (1<<29);
+               break;
+       }
        memset(ctlr->status, 0, 20);
        csr32(ctlr, DMARWControl) = (csr32(ctlr, DMARWControl) & DMAWatermarkMask) | DMAWatermarkValue;
        csr32(ctlr, ModeControl) |= HostSendBDs | HostStackUp | InterruptOnMAC;
@@ -462,10 +575,20 @@ bcminit(Ether *edev)
        csr32(ctlr, MBUFHighWatermark) = 0x60;
        csr32(ctlr, LowWatermarkMaximum) = (csr32(ctlr, LowWatermarkMaximum) & LowWatermarkMaxMask) | LowWatermarkMaxValue;
        csr32(ctlr, BufferManMode) |= Enable | Attn;
-       while((csr32(ctlr, BufferManMode) & Enable) == 0);
+       for(i = 0; i < 100 && (csr32(ctlr, BufferManMode) & Enable) == 0; i++)
+               microdelay(100);
+       if(i == 100){
+               iprint("bcm: buffer manager failed to start\n");
+               return -1;
+       }
        csr32(ctlr, FTQReset) = -1;
        csr32(ctlr, FTQReset) = 0;
-       while(csr32(ctlr, FTQReset));
+       for(i = 0; i < 1000 && csr32(ctlr, FTQReset) != 0; i++)
+               microdelay(100);
+       if(i == 1000){
+               iprint("bcm: ftq failed to reset\n");
+               return -1;
+       }
        csr32(ctlr, ReceiveBDHostAddr) = 0;
        csr32(ctlr, ReceiveBDHostAddr + 4) = PADDR(ctlr->recvprod);
        csr32(ctlr, ReceiveBDFlags) = RecvProdRingLen << 16;
@@ -503,7 +626,12 @@ bcminit(Ether *edev)
        csr32(ctlr, SendInitiatorMask) = 0xFFFFFF;
        csr32(ctlr, SendInitiatorConfiguration) |= SendStats;
        csr32(ctlr, HostCoalescingMode) = 0;
-       while(csr32(ctlr, HostCoalescingMode) != 0);
+       for(i = 0; i < 200 && csr32(ctlr, HostCoalescingMode) != 0; i++)
+               microdelay(100);
+       if(i == 200){
+               iprint("bcm: host coalescing engine failed to stop\n");
+               return -1;
+       }
        csr32(ctlr, HostCoalescingRecvTicks) = 150;
        csr32(ctlr, HostCoalescingSendTicks) = 150;
        csr32(ctlr, RecvMaxCoalescedFrames) = 10;
@@ -539,7 +667,12 @@ bcminit(Ether *edev)
        csr32(ctlr, MIMode) = 0xC0000;
        microdelay(40);
        miiw(ctlr, PhyControl, 1<<15);
-       while(miir(ctlr, PhyControl) & (1<<15));
+       for(i = 0; i < 1000 && miir(ctlr, PhyControl) & (1<<15); i++)
+               microdelay(100);
+       if(i == 1000){
+               iprint("bcm: PHY failed to reset\n");
+               return -1;
+       }
        miiw(ctlr, PhyAuxControl, 2);
        miir(ctlr, PhyIntStatus);
        miir(ctlr, PhyIntStatus);
@@ -554,6 +687,7 @@ bcminit(Ether *edev)
        csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3;
        csr32(ctlr, MSIMode) |= Enable;
        csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
+       return 0;
 }
 
 static void
@@ -568,24 +702,95 @@ bcmpci(void)
                
                if(pdev->ccrb != 2 || pdev->ccru != 0)
                        continue;
-               
-               switch((pdev->vid<<16) | pdev->did){
-               default: continue;
-               case 0x14e4165a:
-               case 0x14e4167d:
-               case 0x14e41670:
-               case 0x14e41672:
-               case 0x14e41673:
-               case 0x14e41674:
-               case 0x14e41677:
-               case 0x14e4167A:
-               case 0x14e4167b:
-               case 0x14e41693:
-               case 0x14e4169B:
-               case 0x14e41712:
-               case 0x14e41713:
+               if(pdev->vid != 0x14e4)
+                       continue;
+               switch(pdev->did){
+               default:
+                       continue;
+               case BCM5752:
+               case BCM5752M:
+               case BCM5709:
+               case BCM5709S:
+               case BCM5716:
+               case BCM5716S:
+               case BCM5700:
+               case BCM5701:
+               case BCM5702:
+               case BCM5703:
+               case BCM5704:
+               case BCM5704S_2:
+               case BCM5706:
+               case BCM5708:
+               case BCM5702FE:
+               case BCM57710:
+               case BCM57711:
+               case BCM57711E:
+               case BCM5705:
+               case BCM5705_2:
+               case BCM5717:
+               case BCM5718:
+               case BCM5720:
+               case BCM5721:
+               case BCM5722:
+               case BCM5723:
+               case BCM5724:
+               case BCM5705M:
+               case BCM5705M_2:
+               case BCM5714:
+               case BCM5780:
+               case BCM5780S:
+               case BCM5754M:
+               case BCM5755M:
+               case BCM5756ME:
+               case BCM5750:
+               case BCM5751:
+               case BCM5715:
+               case BCM5715S:
+               case BCM5754:
+               case BCM5755:
+               case BCM5750M:
+               case BCM5751M:
+               case BCM5751F:
+               case BCM5787F:
+               case BCM5761e:
+               case BCM5761:
+               case BCM5764M:
+               case BCM57760:
+               case BCM57788:
+               case BCM57780:
+               case BCM5787M:
+               case BCM57790:
+               case BCM5782:
+               case BCM5784M:
+               case BCM5785:
+               case BCM5786:
+               case BCM5787:
+               case BCM5788:
+               case BCM5789:
+               case BCM5785_2:
+               case BCM5702X:
+               case BCM5703X:
+               case BCM5704S:
+               case BCM5706S:
+               case BCM5708S:
+               case BCM57761:
+               case BCM57781:
+               case BCM57791:
+               case BCM57765:
+               case BCM57785:
+               case BCM57795:
+               case BCM5702A3:
+               case BCM5703_2:
+               case BCM5781:
+               case BCM5753:
+               case BCM5753M:
+               case BCM5753F:
+               case BCM5906:   /* ??? */
+               case BCM5906M:  /* ??? */
+               case 0x1670:    /* ??? */
                        break;
                }
+
                pcisetbme(pdev);
                pcisetpms(pdev, 0);
                ctlr = malloc(sizeof(Ctlr));
@@ -593,9 +798,19 @@ bcmpci(void)
                        print("bcm: unable to alloc Ctlr\n");
                        continue;
                }
+               ctlr->sends = malloc(sizeof(ctlr->sends[0]) * SendRingLen);
+               ctlr->recvs = malloc(sizeof(ctlr->recvs[0]) * RecvProdRingLen);
+               if(ctlr->sends == nil || ctlr->recvs == nil){
+                       print("bcm: unable to alloc ctlr->sends and ctlr->recvs\n");
+                       free(ctlr->sends);
+                       free(ctlr->recvs);
+                       free(ctlr);
+                       continue;
+               }
                mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
                if(mem == nil) {
                        print("bcm: can't map %8.8luX\n", pdev->mem[0].bar);
+                       free(ctlr->sends);
                        free(ctlr);
                        continue;
                }
@@ -606,7 +821,6 @@ bcmpci(void)
                ctlr->recvprod = xspanalloc(32 * RecvProdRingLen, 16, 0);
                ctlr->recvret = xspanalloc(32 * RecvRetRingLen, 16, 0);
                ctlr->sendr = xspanalloc(16 * SendRingLen, 16, 0);
-               ctlr->sends = malloc(sizeof(Block) * SendRingLen);
                if(bcmhead != nil)
                        bcmtail->link = ctlr;
                else
@@ -637,6 +851,7 @@ bcmpnp(Ether* edev)
 {
        Ctlr *ctlr;
        
+again:
        if(bcmhead == nil)
                bcmpci();
        
@@ -657,19 +872,24 @@ bcmpnp(Ether* edev)
        edev->port = ctlr->port;
        edev->irq = ctlr->pdev->intl;
        edev->tbdf = ctlr->pdev->tbdf;
-       edev->interrupt = bcminterrupt;
        edev->transmit = bcmtransmit;
        edev->multicast = bcmmulticast;
        edev->promiscuous = bcmpromiscuous;
        edev->arg = edev;
        edev->mbps = 1000;
        
-       bcminit(edev);
+       if(bcminit(edev) < 0){
+               edev->ctlr = nil;
+               goto again;
+       }
+
+       intrenable(edev->irq, bcminterrupt, edev, edev->tbdf, edev->name);
+
        return 0;
 }
 
 void
 etherbcmlink(void)
 {
-       addethercard("BCM5755", bcmpnp);
+       addethercard("bcm", bcmpnp);
 }