/* * broadcom bcm57xx bootstrap driver */ #include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "etherif.h"#include "ethermii.h" #define debug bcmdebug#define iallocb(x) allocb(x)#define etheriq(e, b, frn) toringbuf(e, (b)->rp, BLEN(b))#define qget(blah) fromringbuf(edev) #define dprint(...) do{ if(debug)print(__VA_ARGS__); }while(0)#define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)#define Pciwaddrl(x) PCIWADDR(x)#define Pciwaddrh(x) (sizeof(uintptr)>4? (uvlong)PCIWADDR(x)>>32: 0) typedef struct Ctlr Ctlr;struct Ctlr { Lock txlock, imlock; Ether *ether; Ctlr *next; Pcidev *pdev; ulong *nic, *status; ulong *recvret, *recvprod, *sendr; ulong port; ulong recvreti, recvprodi, sendri, sendcleani; Block **sends; Block **rxs; int active, duplex; uint nobuf; uint partial; uint rxerr; uint qfull; uint dmaerr;}; enum { RecvRetRingLen = 0x200, RecvProdRingLen = 0x200, SendRingLen = 0x200, Reset = 1<<0, Enable = 1<<1, Attn = 1<<2, PowerControlStatus = 0x4C, MiscHostCtl = 0x68, TaggedStatus = 1<<9, IndirectAccessEnable = 1<<7, EnableClockControl = 1<<5, EnablePCIStateRegister = 1<<4, WordSwap = 1<<3, ByteSwap = 1<<2, MaskPCIInt = 1<<1, ClearIntA = 1<<0, Fwmbox = 0x0b50, /* magic value exchange */ Fwmagic = 0x4b657654, DMARWControl = 0x6C, DMAWatermarkMask = ~(7<<19), DMAWatermarkValue = 3<<19, MemoryWindow = 0x7C, MemoryWindowData = 0x84, SendRCB = 0x100, RecvRetRCB = 0x200, InterruptMailbox = 0x204, RecvProdBDRingIndex = 0x26c, RecvBDRetRingIndex = 0x284, SendBDRingHostIndex = 0x304, MACMode = 0x400, MACPortMask = ~((1<<3)|(1<<2)), MACPortGMII = 1<<3, MACPortMII = 1<<2, MACEnable = (1<<23) | (1<<22) | (1<<21) | (1 << 15) | (1 << 14) | (1<<12) | (1<<11), MACHalfDuplex = 1<<1, MACEventStatus = 0x404, MACEventEnable = 0x408, MACAddress = 0x410, EthernetRandomBackoff = 0x438, ReceiveMTU = 0x43C, MIComm = 0x44C, MIStatus = 0x450, MIMode = 0x454, ReceiveMACMode = 0x468, TransmitMACMode = 0x45C, TransmitMACLengths = 0x464, MACHash = 0x470, ReceiveRules = 0x480, ReceiveRulesConfiguration = 0x500, LowWatermarkMaximum = 0x504, LowWatermarkMaxMask = ~0xFFFF, LowWatermarkMaxValue = 2, SendDataInitiatorMode = 0xC00, SendInitiatorConfiguration = 0x0C08, SendStats = 1<<0, SendInitiatorMask = 0x0C0C, SendDataCompletionMode = 0x1000, SendBDSelectorMode = 0x1400, SendBDInitiatorMode = 0x1800, SendBDCompletionMode = 0x1C00, ReceiveListPlacementMode = 0x2000, ReceiveListPlacement = 0x2010, ReceiveListPlacementConfiguration = 0x2014, ReceiveStats = 1<<0, ReceiveListPlacementMask = 0x2018, ReceiveDataBDInitiatorMode = 0x2400, ReceiveBDHostAddr = 0x2450, ReceiveBDFlags = 0x2458, ReceiveBDNIC = 0x245C, ReceiveDataCompletionMode = 0x2800, ReceiveBDInitiatorMode = 0x2C00, ReceiveBDRepl = 0x2C18, ReceiveBDCompletionMode = 0x3000, HostCoalescingMode = 0x3C00, HostCoalescingRecvTicks = 0x3C08, HostCoalescingSendTicks = 0x3C0C, RecvMaxCoalescedFrames = 0x3C10, SendMaxCoalescedFrames = 0x3C14, RecvMaxCoalescedFramesInt = 0x3C20, SendMaxCoalescedFramesInt = 0x3C24, StatusBlockHostAddr = 0x3C38, FlowAttention = 0x3C48, MemArbiterMode = 0x4000, BufferManMode = 0x4400, MBUFLowWatermark = 0x4414, MBUFHighWatermark = 0x4418, ReadDMAMode = 0x4800, ReadDMAStatus = 0x4804, WriteDMAMode = 0x4C00, WriteDMAStatus = 0x4C04, RISCState = 0x5004, FTQReset = 0x5C00, MSIMode = 0x6000, ModeControl = 0x6800, ByteWordSwap = (1<<4)|(1<<5)|(1<<2),//|(1<<1), HostStackUp = 1<<16, HostSendBDs = 1<<17, InterruptOnMAC = 1<<26, MiscConfiguration = 0x6804, CoreClockBlocksReset = 1<<0, GPHYPowerDownOverride = 1<<26, DisableGRCResetOnPCIE = 1<<29, TimerMask = ~0xFF, TimerValue = 65<<1, MiscLocalControl = 0x6808, InterruptOnAttn = 1<<3, AutoSEEPROM = 1<<24, SwArbitration = 0x7020, SwArbitSet1 = 1<<1, SwArbitWon1 = 1<<9, Pcitlplpl = 0x7C00, /* "lower 1k of the pcie pl regs" ?? */ PhyAuxControl = 0x18, PhyIntStatus = 0x1A, PhyIntMask = 0x1B, Updated = 1<<0, LinkStateChange = 1<<1, Error = 1<<2, PacketEnd = 1<<2, FrameError = 1<<10,}; #define csr32(c, r) ((c)->nic[(r)/4]) static Ctlr *bcmhead;static int debug=1; enum { Phybusy = 1<<29, Phyrdfail = 1<<28, Phyrd = 1<<27, Phywr = 1<<26,};Lock miilock; static uintmiiwait(Ctlr *ctlr){ uint i, v; for(i = 0; i < 100; i += 5){ microdelay(10); v = csr32(ctlr, MIComm); if((v & Phybusy) == 0){ microdelay(5); return csr32(ctlr, MIComm); } microdelay(5); } print("#l%d: bcm: miiwait: timeout\n", ctlr->ether->ctlrno); return ~0;} static intmiir(Ctlr *ctlr, int r){ uint v, phyno; phyno = 1; lock(&miilock); csr32(ctlr, MIComm) = r<<16 | phyno<<21 | Phyrd | Phybusy; v = miiwait(ctlr); unlock(&miilock); if(v == ~0) return -1; if(v & Phyrdfail){ print("#l%d: bcm: miir: fail\n", ctlr->ether->ctlrno); return -1; } return v & 0xffff;} static intmiiw(Ctlr *ctlr, int r, int v){ uint phyno, w; phyno = 1; lock(&miilock); csr32(ctlr, MIComm) = r<<16 | v&0xffff | phyno<<21 | Phywr | Phybusy; w = miiwait(ctlr); unlock(&miilock); if(w == ~0) return -1; return 0;} static ulong*currentrecvret(Ctlr *ctlr){ if(ctlr->recvreti == (ctlr->status[4] & 0xFFFF)) return 0; return ctlr->recvret + ctlr->recvreti * 8;} static voidconsumerecvret(Ctlr *ctlr){ ctlr->recvreti = ctlr->recvreti+1 & RecvRetRingLen-1; csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti;} static intreplenish(Ctlr *ctlr){ ulong *next, incr; Block *bp; incr = (ctlr->recvprodi + 1) & (RecvProdRingLen - 1); if(incr == (ctlr->status[2] >> 16)) return -1; bp = iallocb(Rbsz); if(bp == nil) { /* iallocb never fails. this code is unnecessary */ dprint("bcm: out of memory for receive buffers\n"); ctlr->nobuf++; return -1; } next = ctlr->recvprod + ctlr->recvprodi * 8; memset(next, 0, 32); next[0] = Pciwaddrh(bp->rp); next[1] = Pciwaddrl(bp->rp); next[2] = Rbsz; next[7] = ctlr->recvprodi; ctlr->rxs[ctlr->recvprodi] = bp; coherence(); csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr; return 0;} static voidbcmreceive(Ether *edev){ ulong *pkt, len; Ctlr *ctlr; Block *bp; ctlr = edev->ctlr; for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) { bp = ctlr->rxs[pkt[7]]; len = pkt[2] & 0xFFFF; bp->wp = bp->rp + len; if((pkt[3] & PacketEnd) == 0){ dprint("bcm: partial frame received -- shouldn't happen\n"); ctlr->partial++; freeb(bp); continue; } if(pkt[3] & FrameError){ ctlr->rxerr++; freeb(bp); continue; } etheriq(edev, bp, 1); }} static voidbcmtransclean(Ether *edev){ Ctlr *ctlr; ctlr = edev->ctlr; ilock(&ctlr->txlock); while(ctlr->sendcleani != (ctlr->status[4] >> 16)) { freeb(ctlr->sends[ctlr->sendcleani]); ctlr->sends[ctlr->sendcleani] = nil; ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1); } iunlock(&ctlr->txlock);} static voidbcmtransmit(Ether *edev){ ulong *next, incr; Ctlr *ctlr; Block *bp; ctlr = edev->ctlr; ilock(&ctlr->txlock); for(;;){ incr = (ctlr->sendri + 1) & (SendRingLen - 1); if(incr == ctlr->sendcleani) { dprint("bcm: send queue full %ld %ld\n", incr, ctlr->sendcleani); ctlr->qfull++; break; } bp = qget(edev->oq); if(bp == nil) break; next = ctlr->sendr + ctlr->sendri * 4; next[0] = Pciwaddrh(bp->rp); next[1] = Pciwaddrl(bp->rp); next[2] = (BLEN(bp) << 16) | PacketEnd; next[3] = 0; ctlr->sends[ctlr->sendri] = bp; coherence(); csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr; } iunlock(&ctlr->txlock);} static voidbcmerror(Ether *edev){ Ctlr *ctlr; ctlr = edev->ctlr; if(csr32(ctlr, FlowAttention)) { if(csr32(ctlr, FlowAttention) & 0xf8ff8080) print("bcm: fatal error %#.8lux", csr32(ctlr, FlowAttention)); csr32(ctlr, FlowAttention) = 0; } csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */ if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) { dprint("bcm: DMA error\n"); ctlr->dmaerr++; csr32(ctlr, ReadDMAStatus) = 0; csr32(ctlr, WriteDMAStatus) = 0; } if(csr32(ctlr, RISCState)) { if(csr32(ctlr, RISCState) & 0x78000403) print("bcm: RISC halted %#.8lux", csr32(ctlr, RISCState)); csr32(ctlr, RISCState) = 0; }} static voidbcminterrupt(Ureg*, void *arg){ ulong status, tag, dummy; Ether *edev; Ctlr *ctlr; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->imlock); dummy = csr32(ctlr, InterruptMailbox); USED(dummy); csr32(ctlr, InterruptMailbox) = 1; status = ctlr->status[0]; tag = ctlr->status[1]; ctlr->status[0] = 0; if(status & Error) bcmerror(edev); if(status & LinkStateChange) {}//checklink(edev); bcmreceive(edev); bcmtransclean(edev); bcmtransmit(edev); csr32(ctlr, InterruptMailbox) = tag << 24; iunlock(&ctlr->imlock);} static voidmem32w(Ctlr *c, uint r, uint v){ pcicfgw32(c->pdev, MemoryWindow, r); pcicfgw32(c->pdev, MemoryWindowData, v);} static ulongmem32r(Ctlr *c, uint r){ ulong v; pcicfgw32(c->pdev, MemoryWindow, r); v = pcicfgr32(c->pdev, MemoryWindowData); pcicfgw32(c->pdev, MemoryWindow, 0); return v;} static intbcmµwait(Ctlr *ctlr, uint to, uint r, uint m, uint v){ int i; for(i = 0;; i += 100){ if((csr32(ctlr, r) & m) == v) return 0; if(i == to /* µs */) return -1; microdelay(100); }} static intbcminit(Ether *edev){ ulong i, j; Ctlr *ctlr; ctlr = edev->ctlr; dprint("bcm: reset\n"); /* initialization procedure according to the datasheet */ csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA; csr32(ctlr, SwArbitration) |= SwArbitSet1; if(bcmµwait(ctlr, 2000, SwArbitration, SwArbitWon1, SwArbitWon1) == -1){ print("bcm: arbiter failed to respond\n"); return -1; } csr32(ctlr, MemArbiterMode) |= Enable; csr32(ctlr, MiscHostCtl) = WordSwap | IndirectAccessEnable | EnablePCIStateRegister | EnableClockControl | MaskPCIInt | ClearIntA; csr32(ctlr, MemoryWindow) = 0; mem32w(ctlr, Fwmbox, Fwmagic); csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE | CoreClockBlocksReset; delay(100); pcicfgw32(ctlr->pdev, PciPCR, ctlr->pdev->pcr); /* restore pci bits lost */ csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA; csr32(ctlr, MemArbiterMode) |= Enable; csr32(ctlr, MiscHostCtl) |= WordSwap | IndirectAccessEnable | EnablePCIStateRegister | EnableClockControl | TaggedStatus; csr32(ctlr, ModeControl) |= ByteWordSwap; csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII; delay(40); for(i = 0;; i += 100){ if(mem32r(ctlr, Fwmbox) == ~Fwmagic) break; if(i == 20*10000 /* µs */){ print("bcm: fw failed to respond %#.8lux\n", mem32r(ctlr, Fwmbox)); break; //return -1; } microdelay(100); } /* * there appears to be no justification for setting these bits in any driverLines 1–500 of 723. Load more
/* * broadcom bcm57xx bootstrap driver */ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "etherif.h" #include "ethermii.h" #define debug bcmdebug #define iallocb(x) allocb(x) #define etheriq(e, b, frn) toringbuf(e, (b)->rp, BLEN(b)) #define qget(blah) fromringbuf(edev) #define dprint(...) do{ if(debug)print(__VA_ARGS__); }while(0) #define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4) #define Pciwaddrl(x) PCIWADDR(x) #define Pciwaddrh(x) (sizeof(uintptr)>4? (uvlong)PCIWADDR(x)>>32: 0) typedef struct Ctlr Ctlr; struct Ctlr { Lock txlock, imlock; Ether *ether; Ctlr *next; Pcidev *pdev; ulong *nic, *status; ulong *recvret, *recvprod, *sendr; ulong port; ulong recvreti, recvprodi, sendri, sendcleani; Block **sends; Block **rxs; int active, duplex; uint nobuf; uint partial; uint rxerr; uint qfull; uint dmaerr; }; enum { RecvRetRingLen = 0x200, RecvProdRingLen = 0x200, SendRingLen = 0x200, Reset = 1<<0, Enable = 1<<1, Attn = 1<<2, PowerControlStatus = 0x4C, MiscHostCtl = 0x68, TaggedStatus = 1<<9, IndirectAccessEnable = 1<<7, EnableClockControl = 1<<5, EnablePCIStateRegister = 1<<4, WordSwap = 1<<3, ByteSwap = 1<<2, MaskPCIInt = 1<<1, ClearIntA = 1<<0, Fwmbox = 0x0b50, /* magic value exchange */ Fwmagic = 0x4b657654, DMARWControl = 0x6C, DMAWatermarkMask = ~(7<<19), DMAWatermarkValue = 3<<19, MemoryWindow = 0x7C, MemoryWindowData = 0x84, SendRCB = 0x100, RecvRetRCB = 0x200, InterruptMailbox = 0x204, RecvProdBDRingIndex = 0x26c, RecvBDRetRingIndex = 0x284, SendBDRingHostIndex = 0x304, MACMode = 0x400, MACPortMask = ~((1<<3)|(1<<2)), MACPortGMII = 1<<3, MACPortMII = 1<<2, MACEnable = (1<<23) | (1<<22) | (1<<21) | (1 << 15) | (1 << 14) | (1<<12) | (1<<11), MACHalfDuplex = 1<<1, MACEventStatus = 0x404, MACEventEnable = 0x408, MACAddress = 0x410, EthernetRandomBackoff = 0x438, ReceiveMTU = 0x43C, MIComm = 0x44C, MIStatus = 0x450, MIMode = 0x454, ReceiveMACMode = 0x468, TransmitMACMode = 0x45C, TransmitMACLengths = 0x464, MACHash = 0x470, ReceiveRules = 0x480, ReceiveRulesConfiguration = 0x500, LowWatermarkMaximum = 0x504, LowWatermarkMaxMask = ~0xFFFF, LowWatermarkMaxValue = 2, SendDataInitiatorMode = 0xC00, SendInitiatorConfiguration = 0x0C08, SendStats = 1<<0, SendInitiatorMask = 0x0C0C, SendDataCompletionMode = 0x1000, SendBDSelectorMode = 0x1400, SendBDInitiatorMode = 0x1800, SendBDCompletionMode = 0x1C00, ReceiveListPlacementMode = 0x2000, ReceiveListPlacement = 0x2010, ReceiveListPlacementConfiguration = 0x2014, ReceiveStats = 1<<0, ReceiveListPlacementMask = 0x2018, ReceiveDataBDInitiatorMode = 0x2400, ReceiveBDHostAddr = 0x2450, ReceiveBDFlags = 0x2458, ReceiveBDNIC = 0x245C, ReceiveDataCompletionMode = 0x2800, ReceiveBDInitiatorMode = 0x2C00, ReceiveBDRepl = 0x2C18, ReceiveBDCompletionMode = 0x3000, HostCoalescingMode = 0x3C00, HostCoalescingRecvTicks = 0x3C08, HostCoalescingSendTicks = 0x3C0C, RecvMaxCoalescedFrames = 0x3C10, SendMaxCoalescedFrames = 0x3C14, RecvMaxCoalescedFramesInt = 0x3C20, SendMaxCoalescedFramesInt = 0x3C24, StatusBlockHostAddr = 0x3C38, FlowAttention = 0x3C48, MemArbiterMode = 0x4000, BufferManMode = 0x4400, MBUFLowWatermark = 0x4414, MBUFHighWatermark = 0x4418, ReadDMAMode = 0x4800, ReadDMAStatus = 0x4804, WriteDMAMode = 0x4C00, WriteDMAStatus = 0x4C04, RISCState = 0x5004, FTQReset = 0x5C00, MSIMode = 0x6000, ModeControl = 0x6800, ByteWordSwap = (1<<4)|(1<<5)|(1<<2),//|(1<<1), HostStackUp = 1<<16, HostSendBDs = 1<<17, InterruptOnMAC = 1<<26, MiscConfiguration = 0x6804, CoreClockBlocksReset = 1<<0, GPHYPowerDownOverride = 1<<26, DisableGRCResetOnPCIE = 1<<29, TimerMask = ~0xFF, TimerValue = 65<<1, MiscLocalControl = 0x6808, InterruptOnAttn = 1<<3, AutoSEEPROM = 1<<24, SwArbitration = 0x7020, SwArbitSet1 = 1<<1, SwArbitWon1 = 1<<9, Pcitlplpl = 0x7C00, /* "lower 1k of the pcie pl regs" ?? */ PhyAuxControl = 0x18, PhyIntStatus = 0x1A, PhyIntMask = 0x1B, Updated = 1<<0, LinkStateChange = 1<<1, Error = 1<<2, PacketEnd = 1<<2, FrameError = 1<<10, }; #define csr32(c, r) ((c)->nic[(r)/4]) static Ctlr *bcmhead; static int debug=1; enum { Phybusy = 1<<29, Phyrdfail = 1<<28, Phyrd = 1<<27, Phywr = 1<<26, }; Lock miilock; static uint miiwait(Ctlr *ctlr) { uint i, v; for(i = 0; i < 100; i += 5){ microdelay(10); v = csr32(ctlr, MIComm); if((v & Phybusy) == 0){ microdelay(5); return csr32(ctlr, MIComm); } microdelay(5); } print("#l%d: bcm: miiwait: timeout\n", ctlr->ether->ctlrno); return ~0; } static int miir(Ctlr *ctlr, int r) { uint v, phyno; phyno = 1; lock(&miilock); csr32(ctlr, MIComm) = r<<16 | phyno<<21 | Phyrd | Phybusy; v = miiwait(ctlr); unlock(&miilock); if(v == ~0) return -1; if(v & Phyrdfail){ print("#l%d: bcm: miir: fail\n", ctlr->ether->ctlrno); return -1; } return v & 0xffff; } static int miiw(Ctlr *ctlr, int r, int v) { uint phyno, w; phyno = 1; lock(&miilock); csr32(ctlr, MIComm) = r<<16 | v&0xffff | phyno<<21 | Phywr | Phybusy; w = miiwait(ctlr); unlock(&miilock); if(w == ~0) return -1; return 0; } static ulong* currentrecvret(Ctlr *ctlr) { if(ctlr->recvreti == (ctlr->status[4] & 0xFFFF)) return 0; return ctlr->recvret + ctlr->recvreti * 8; } static void consumerecvret(Ctlr *ctlr) { ctlr->recvreti = ctlr->recvreti+1 & RecvRetRingLen-1; csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti; } static int replenish(Ctlr *ctlr) { ulong *next, incr; Block *bp; incr = (ctlr->recvprodi + 1) & (RecvProdRingLen - 1); if(incr == (ctlr->status[2] >> 16)) return -1; bp = iallocb(Rbsz); if(bp == nil) { /* iallocb never fails. this code is unnecessary */ dprint("bcm: out of memory for receive buffers\n"); ctlr->nobuf++; return -1; } next = ctlr->recvprod + ctlr->recvprodi * 8; memset(next, 0, 32); next[0] = Pciwaddrh(bp->rp); next[1] = Pciwaddrl(bp->rp); next[2] = Rbsz; next[7] = ctlr->recvprodi; ctlr->rxs[ctlr->recvprodi] = bp; coherence(); csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr; return 0; } static void bcmreceive(Ether *edev) { ulong *pkt, len; Ctlr *ctlr; Block *bp; ctlr = edev->ctlr; for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) { bp = ctlr->rxs[pkt[7]]; len = pkt[2] & 0xFFFF; bp->wp = bp->rp + len; if((pkt[3] & PacketEnd) == 0){ dprint("bcm: partial frame received -- shouldn't happen\n"); ctlr->partial++; freeb(bp); continue; } if(pkt[3] & FrameError){ ctlr->rxerr++; freeb(bp); continue; } etheriq(edev, bp, 1); } } static void bcmtransclean(Ether *edev) { Ctlr *ctlr; ctlr = edev->ctlr; ilock(&ctlr->txlock); while(ctlr->sendcleani != (ctlr->status[4] >> 16)) { freeb(ctlr->sends[ctlr->sendcleani]); ctlr->sends[ctlr->sendcleani] = nil; ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1); } iunlock(&ctlr->txlock); } static void bcmtransmit(Ether *edev) { ulong *next, incr; Ctlr *ctlr; Block *bp; ctlr = edev->ctlr; ilock(&ctlr->txlock); for(;;){ incr = (ctlr->sendri + 1) & (SendRingLen - 1); if(incr == ctlr->sendcleani) { dprint("bcm: send queue full %ld %ld\n", incr, ctlr->sendcleani); ctlr->qfull++; break; } bp = qget(edev->oq); if(bp == nil) break; next = ctlr->sendr + ctlr->sendri * 4; next[0] = Pciwaddrh(bp->rp); next[1] = Pciwaddrl(bp->rp); next[2] = (BLEN(bp) << 16) | PacketEnd; next[3] = 0; ctlr->sends[ctlr->sendri] = bp; coherence(); csr32(ctlr, SendBDRingHostIndex) = ctlr->sendri = incr; } iunlock(&ctlr->txlock); } static void bcmerror(Ether *edev) { Ctlr *ctlr; ctlr = edev->ctlr; if(csr32(ctlr, FlowAttention)) { if(csr32(ctlr, FlowAttention) & 0xf8ff8080) print("bcm: fatal error %#.8lux", csr32(ctlr, FlowAttention)); csr32(ctlr, FlowAttention) = 0; } csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */ if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) { dprint("bcm: DMA error\n"); ctlr->dmaerr++; csr32(ctlr, ReadDMAStatus) = 0; csr32(ctlr, WriteDMAStatus) = 0; } if(csr32(ctlr, RISCState)) { if(csr32(ctlr, RISCState) & 0x78000403) print("bcm: RISC halted %#.8lux", csr32(ctlr, RISCState)); csr32(ctlr, RISCState) = 0; } } static void bcminterrupt(Ureg*, void *arg) { ulong status, tag, dummy; Ether *edev; Ctlr *ctlr; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->imlock); dummy = csr32(ctlr, InterruptMailbox); USED(dummy); csr32(ctlr, InterruptMailbox) = 1; status = ctlr->status[0]; tag = ctlr->status[1]; ctlr->status[0] = 0; if(status & Error) bcmerror(edev); if(status & LinkStateChange) {}//checklink(edev); bcmreceive(edev); bcmtransclean(edev); bcmtransmit(edev); csr32(ctlr, InterruptMailbox) = tag << 24; iunlock(&ctlr->imlock); } static void mem32w(Ctlr *c, uint r, uint v) { pcicfgw32(c->pdev, MemoryWindow, r); pcicfgw32(c->pdev, MemoryWindowData, v); } static ulong mem32r(Ctlr *c, uint r) { ulong v; pcicfgw32(c->pdev, MemoryWindow, r); v = pcicfgr32(c->pdev, MemoryWindowData); pcicfgw32(c->pdev, MemoryWindow, 0); return v; } static int bcmµwait(Ctlr *ctlr, uint to, uint r, uint m, uint v) { int i; for(i = 0;; i += 100){ if((csr32(ctlr, r) & m) == v) return 0; if(i == to /* µs */) return -1; microdelay(100); } } static int bcminit(Ether *edev) { ulong i, j; Ctlr *ctlr; ctlr = edev->ctlr; dprint("bcm: reset\n"); /* initialization procedure according to the datasheet */ csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA; csr32(ctlr, SwArbitration) |= SwArbitSet1; if(bcmµwait(ctlr, 2000, SwArbitration, SwArbitWon1, SwArbitWon1) == -1){ print("bcm: arbiter failed to respond\n"); return -1; } csr32(ctlr, MemArbiterMode) |= Enable; csr32(ctlr, MiscHostCtl) = WordSwap | IndirectAccessEnable | EnablePCIStateRegister | EnableClockControl | MaskPCIInt | ClearIntA; csr32(ctlr, MemoryWindow) = 0; mem32w(ctlr, Fwmbox, Fwmagic); csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE | CoreClockBlocksReset; delay(100); pcicfgw32(ctlr->pdev, PciPCR, ctlr->pdev->pcr); /* restore pci bits lost */ csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA; csr32(ctlr, MemArbiterMode) |= Enable; csr32(ctlr, MiscHostCtl) |= WordSwap | IndirectAccessEnable | EnablePCIStateRegister | EnableClockControl | TaggedStatus; csr32(ctlr, ModeControl) |= ByteWordSwap; csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII; delay(40); for(i = 0;; i += 100){ if(mem32r(ctlr, Fwmbox) == ~Fwmagic) break; if(i == 20*10000 /* µs */){ print("bcm: fw failed to respond %#.8lux\n", mem32r(ctlr, Fwmbox)); break; //return -1; } microdelay(100); } /* * there appears to be no justification for setting these bits in any driver