From mboxrd@z Thu Jan 1 00:00:00 1970 From: quanstro@quanstro.net (erik quanstrom) Date: Fri, 25 Nov 2011 17:42:22 -0500 Subject: [9fans] Forks of Plan 9 (Was: 9vx instability) In-Reply-To: References: Message-ID: <22cc46aeabe9242035819a85e84179a6@chula.quanstro.net> Topicbox-Message-UUID: 47863cc0-ead7-11e9-9d60-3106f5b1d025 still not working; doesn't even reset. i've taken a pass at cleaning up the code. the biggest change is using style(6) formatting. also, coherence() is missing when entering ring entries, since the posted write of the ring ptr can pass the memory writes of the ring entry, from the perspective of the pci root complex. and transmit wasn't careful enough not to run into its head. (checking the chip isn't good enough. you have to not run over your own unfreed bps.) - erik -------------- next part -------------- /* * Broadcom BCM57xx * Not implemented: * proper fatal error handling * multiple rings * QoS * checksum offloading */ /* this driver needs some work, and probablly doesn't conform to style(6) */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "../port/netif.h" #include "etherif.h" #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; 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, ClearIntA = 1<<0, MaskPCIInt = 1<<1, IndirectAccessEnable = 1<<7, EnablePCIStateRegister = 1<<4, EnableClockControlRegister = 1<<5, TaggedStatus = 1<<9, 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, TLPControl = 0x7C00, PhyControl = 0x00, PhyStatus = 0x01, PhyLinkStatus = 1<<2, PhyAutoNegComplete = 1<<5, PhyPartnerStatus = 0x05, Phy100FD = 1<<8, Phy100HD = 1<<7, Phy10FD = 1<<6, Phy10HD = 1<<5, PhyGbitStatus = 0x0A, Phy1000FD = 1<<12, Phy1000HD = 1<<11, 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]) #define mem32(c, r) csr32(c, (r)+0x8000) static Ctlr *bcmhead; static int debug=1; static long bcmifstat(Ether *edev, void *a, long n, ulong offset) { char *s, *p, *e; Ctlr *c; c = edev->ctlr; p = s = malloc(READSTR); e = p + READSTR; p = seprint(p, e, "nobuf %ud\n", c->nobuf); p = seprint(p, e, "partial %ud\n", c->partial); p = seprint(p, e, "rxerr %ud\n", c->rxerr); p = seprint(p, e, "qfull %ud\n", c->qfull); p = seprint(p, e, "dmaerr %ud\n", c->dmaerr); USED(p); n = readstr(offset, a, n, s); free(s); return n; } static int miir(Ctlr *ctlr, int ra) { while(csr32(ctlr, MIComm) & (1<<29)) ; csr32(ctlr, MIComm) = (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29); while(csr32(ctlr, MIComm) & (1<<29)) ; if(csr32(ctlr, MIComm) & (1<<28)) return -1; return csr32(ctlr, MIComm) & 0xFFFF; } static int miiw(Ctlr *ctlr, int ra, int value) { while(csr32(ctlr, MIComm) & (1<<29)) ; csr32(ctlr, MIComm) = (value & 0xFFFF) | (ra << 16) | (1 << 21) | (1 << 27) | (1 << 29); while(csr32(ctlr, MIComm) & (1<<29)) ; return 0; } static void checklink(Ether *edev) { ulong i; Ctlr *ctlr; ctlr = edev->ctlr; miir(ctlr, PhyStatus); /* dummy read necessary */ if(!(miir(ctlr, PhyStatus) & PhyLinkStatus)) { edev->link = 0; edev->mbps = 1000; ctlr->duplex = 1; dprint("bcm: no link\n"); goto out; } edev->link = 1; while((miir(ctlr, PhyStatus) & PhyAutoNegComplete) == 0) ; i = miir(ctlr, PhyGbitStatus); if(i & (Phy1000FD | Phy1000HD)) { edev->mbps = 1000; ctlr->duplex = (i & Phy1000FD) != 0; } else if(i = miir(ctlr, PhyPartnerStatus), i & (Phy100FD | Phy100HD)) { edev->mbps = 100; ctlr->duplex = (i & Phy100FD) != 0; } else if(i & (Phy10FD | Phy10HD)) { edev->mbps = 10; ctlr->duplex = (i & Phy10FD) != 0; } else { edev->link = 0; edev->mbps = 1000; ctlr->duplex = 1; dprint("bcm: link partner supports neither 10/100/1000 Mbps\n"); goto out; } dprint("bcm: %d Mbps link, %s duplex\n", edev->mbps, ctlr->duplex ? "full" : "half"); out: if(ctlr->duplex) csr32(ctlr, MACMode) &= ~MACHalfDuplex; else csr32(ctlr, MACMode) |= MACHalfDuplex; if(edev->mbps >= 1000) csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII; else csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortMII; csr32(ctlr, MACEventStatus) |= (1<<4) | (1<<3); /* undocumented bits (sync and config changed) */ } 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\n"); 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); iprint("bcm: interrupt %8lux %8lux\n", ctlr->status[2], ctlr->status[4]); bcmreceive(edev); bcmtransclean(edev); bcmtransmit(edev); csr32(ctlr, InterruptMailbox) = tag << 24; iunlock(&ctlr->imlock); } 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; for(i = 0;; i += 100){ if((csr32(ctlr, SwArbitration) & SwArbitWon1)) break; if(i == 2000 /* ?s */){ print("bcm: arbiter failed to respond\n"); return -1; } microdelay(100); } csr32(ctlr, MemArbiterMode) |= Enable; csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister; csr32(ctlr, MemoryWindow) = 0; mem32(ctlr, Fwmbox) = Fwmagic; csr32(ctlr, MiscConfiguration) |= GPHYPowerDownOverride | DisableGRCResetOnPCIE; csr32(ctlr, MiscConfiguration) |= CoreClockBlocksReset; delay(100); ctlr->pdev->pcr |= 1<<1; pcisetbme(ctlr->pdev); csr32(ctlr, MiscHostCtl) |= MaskPCIInt; csr32(ctlr, MemArbiterMode) |= Enable; csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister | TaggedStatus; csr32(ctlr, ModeControl) |= ByteWordSwap; csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII; delay(40); for(i = 0;; i += 100){ if(mem32(ctlr, Fwmbox) == ~Fwmagic) break; if(i == 20*10000 /* ?s */){ print("bcm: fw failed to respond %#.8lux\n", mem32(ctlr, Fwmbox)); break; //return -1; } microdelay(100); } csr32(ctlr, TLPControl) |= (1<<25) | (1<<29); memset(ctlr->status, 0, 20); csr32(ctlr, DMARWControl) = (csr32(ctlr, DMARWControl) & DMAWatermarkMask) | DMAWatermarkValue; csr32(ctlr, ModeControl) |= HostSendBDs | HostStackUp | InterruptOnMAC; csr32(ctlr, MiscConfiguration) = (csr32(ctlr, MiscConfiguration) & TimerMask) | TimerValue; csr32(ctlr, MBUFLowWatermark) = 0x20; csr32(ctlr, MBUFHighWatermark) = 0x60; csr32(ctlr, LowWatermarkMaximum) = (csr32(ctlr, LowWatermarkMaximum) & LowWatermarkMaxMask) | LowWatermarkMaxValue; csr32(ctlr, BufferManMode) |= Enable | Attn; while((csr32(ctlr, BufferManMode) & Enable) == 0) ; csr32(ctlr, FTQReset) = -1; csr32(ctlr, FTQReset) = 0; while(csr32(ctlr, FTQReset)) ; csr32(ctlr, ReceiveBDHostAddr) = Pciwaddrh(ctlr->recvprod); csr32(ctlr, ReceiveBDHostAddr + 4) = Pciwaddrl(ctlr->recvprod); csr32(ctlr, ReceiveBDFlags) = RecvProdRingLen << 16; csr32(ctlr, ReceiveBDNIC) = 0x6000; csr32(ctlr, ReceiveBDRepl) = 25; csr32(ctlr, SendBDRingHostIndex) = 0; csr32(ctlr, SendBDRingHostIndex+4) = 0; mem32(ctlr, SendRCB) = Pciwaddrh(ctlr->sendr); mem32(ctlr, SendRCB + 4) = Pciwaddrl(ctlr->sendr); mem32(ctlr, SendRCB + 8) = SendRingLen << 16; mem32(ctlr, SendRCB + 12) = 0x4000; for(i=1;i<4;i++) mem32(ctlr, RecvRetRCB + i * 0x10 + 8) = 2; mem32(ctlr, RecvRetRCB) = Pciwaddrh(ctlr->recvret); mem32(ctlr, RecvRetRCB + 4) = Pciwaddrl(ctlr->recvret); mem32(ctlr, RecvRetRCB + 8) = RecvRetRingLen << 16; csr32(ctlr, RecvProdBDRingIndex) = 0; csr32(ctlr, RecvProdBDRingIndex+4) = 0; /* this delay is not in the datasheet, but necessary */ delay(1); i = csr32(ctlr, MACAddress); j = edev->ea[0] = i >> 8; j += edev->ea[1] = i; i = csr32(ctlr, MACAddress + 4); j += edev->ea[2] = i >> 24; j += edev->ea[3] = i >> 16; j += edev->ea[4] = i >> 8; j += edev->ea[5] = i; csr32(ctlr, EthernetRandomBackoff) = j & 0x3FF; csr32(ctlr, ReceiveMTU) = Rbsz; csr32(ctlr, TransmitMACLengths) = 0x2620; csr32(ctlr, ReceiveListPlacement) = 1<<3; /* one list */ csr32(ctlr, ReceiveListPlacementMask) = 0xFFFFFF; csr32(ctlr, ReceiveListPlacementConfiguration) |= ReceiveStats; csr32(ctlr, SendInitiatorMask) = 0xFFFFFF; csr32(ctlr, SendInitiatorConfiguration) |= SendStats; csr32(ctlr, HostCoalescingMode) = 0; while(csr32(ctlr, HostCoalescingMode) != 0) ; csr32(ctlr, HostCoalescingRecvTicks) = 150; csr32(ctlr, HostCoalescingSendTicks) = 150; csr32(ctlr, RecvMaxCoalescedFrames) = 10; csr32(ctlr, SendMaxCoalescedFrames) = 10; csr32(ctlr, RecvMaxCoalescedFramesInt) = 0; csr32(ctlr, SendMaxCoalescedFramesInt) = 0; csr32(ctlr, StatusBlockHostAddr) = Pciwaddrh(ctlr->status); csr32(ctlr, StatusBlockHostAddr + 4) = Pciwaddrl(ctlr->status); csr32(ctlr, HostCoalescingMode) |= Enable; csr32(ctlr, ReceiveBDCompletionMode) |= Enable | Attn; csr32(ctlr, ReceiveListPlacementMode) |= Enable; csr32(ctlr, MACMode) |= MACEnable; csr32(ctlr, MiscLocalControl) |= InterruptOnAttn | AutoSEEPROM; csr32(ctlr, InterruptMailbox) = 0; csr32(ctlr, WriteDMAMode) |= 0x200003fe; /* pulled out of my nose */ csr32(ctlr, ReadDMAMode) |= 0x3fe; csr32(ctlr, ReceiveDataCompletionMode) |= Enable | Attn; csr32(ctlr, SendDataCompletionMode) |= Enable; csr32(ctlr, SendBDCompletionMode) |= Enable | Attn; csr32(ctlr, ReceiveBDInitiatorMode) |= Enable | Attn; csr32(ctlr, ReceiveDataBDInitiatorMode) |= Enable | (1<<4); csr32(ctlr, SendDataInitiatorMode) |= Enable; csr32(ctlr, SendBDInitiatorMode) |= Enable | Attn; csr32(ctlr, SendBDSelectorMode) |= Enable | Attn; ctlr->recvprodi = 0; while(replenish(ctlr) >= 0) ; csr32(ctlr, TransmitMACMode) |= Enable; csr32(ctlr, ReceiveMACMode) |= Enable; csr32(ctlr, PowerControlStatus) &= ~3; csr32(ctlr, MIStatus) |= 1<<0; csr32(ctlr, MACEventEnable) = 0; csr32(ctlr, MACEventStatus) |= (1<<12); csr32(ctlr, MIMode) = 0xC0000; microdelay(40); miiw(ctlr, PhyControl, 1<<15); while(miir(ctlr, PhyControl) & (1<<15)) ; for(i = 0;; i += 100){ if((miir(ctlr, PhyControl) & (1<<15)) == 0) break; if(i == 10000 /* ?s */){ print("bcm: phy reset failure\n"); return -1; } microdelay(100); } miiw(ctlr, PhyAuxControl, 2); miir(ctlr, PhyIntStatus); miir(ctlr, PhyIntStatus); miiw(ctlr, PhyIntMask, ~(1<<1)); checklink(edev); csr32(ctlr, MACEventEnable) |= 1<<12; csr32(ctlr, MACHash) = -1; csr32(ctlr, MACHash+4) = -1; csr32(ctlr, MACHash+8) = -1; csr32(ctlr, MACHash+12) = -1; for(i = 0; i < 8; i++) csr32(ctlr, ReceiveRules + 8 * i) = 0; csr32(ctlr, ReceiveRulesConfiguration) = 1 << 3; csr32(ctlr, MSIMode) |= Enable; csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA); return 0; } static void bcmpci(void) { void *mem; Ctlr *ctlr, **xx; Pcidev *p; xx = &bcmhead; for(p = nil; p = pcimatch(p, 0, 0); ) { if(p->ccrb != 2 || p->ccru != 0) continue; switch(p->vid<<16 | p->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: break; } pcisetbme(p); pcisetpms(p, 0); ctlr = malloc(sizeof(Ctlr)); if(ctlr == nil) continue; ctlr->port = p->mem[0].bar & ~0x0F; mem = vmap(ctlr->port, p->mem[0].size); if(mem == nil) { print("bcm: can't map %#p\n", ctlr->port); free(ctlr); continue; } ctlr->pdev = p; ctlr->nic = mem; ctlr->status = xspanalloc(20, 16, 0); 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 *ctlr->sends * SendRingLen); ctlr->rxs = malloc(sizeof *ctlr->sends * SendRingLen); *xx = ctlr; xx = &ctlr->next; } } static void bcmpromiscuous(void* arg, int on) { Ctlr *ctlr; ctlr = ((Ether*)arg)->ctlr; if(on) csr32(ctlr, ReceiveMACMode) |= 1<<8; else csr32(ctlr, ReceiveMACMode) &= ~(1<<8); } static void bcmmulticast(void*, uchar*, int) { } static int bcmpnp(Ether* edev) { Ctlr *ctlr; static int done; if(done == 0){ bcmpci(); done = 1; } redux: for(ctlr = bcmhead; ; ctlr = ctlr->next) { if(ctlr == nil) return -1; if(ctlr->active) continue; if(edev->port == 0 || edev->port == ctlr->port) { ctlr->active = 1; break; } } edev->ctlr = ctlr; edev->port = ctlr->port; edev->irq = ctlr->pdev->intl; edev->tbdf = ctlr->pdev->tbdf; edev->interrupt = bcminterrupt; edev->ifstat = bcmifstat; edev->transmit = bcmtransmit; edev->multicast = bcmmulticast; edev->promiscuous = bcmpromiscuous; edev->arg = edev; edev->mbps = 1000; if(bcminit(edev) == -1) goto redux; return 0; } void etherbcmlink(void) { addethercard("bcm57xx", bcmpnp); }