From mboxrd@z Thu Jan 1 00:00:00 1970 From: quanstro@quanstro.net (erik quanstrom) Date: Fri, 25 Nov 2011 21:09:55 -0500 Subject: [9fans] Forks of Plan 9 (Was: 9vx instability) In-Reply-To: References: Message-ID: <8d9e9da12e38e79907635542853c8cd2@brasstown.quanstro.net> Topicbox-Message-UUID: 4798a9b4-ead7-11e9-9d60-3106f5b1d025 fixed for my hw. the really key bit was setting the endianness properly. this may have been set up by your pxe hardware or bios, if your bcm chip was built-in. i've updated 9atom with this driver. - 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, 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, 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]) 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); /* read twice for current status as per 802.3 */ 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); } void mem32w(Ctlr *c, uint r, uint v) { pcicfgw32(c->pdev, MemoryWindow, r); pcicfgw32(c->pdev, MemoryWindowData, v); } 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 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) = 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); } 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; mem32w(ctlr, SendRCB, Pciwaddrh(ctlr->sendr)); mem32w(ctlr, SendRCB + 4, Pciwaddrl(ctlr->sendr)); mem32w(ctlr, SendRCB + 8, SendRingLen << 16); mem32w(ctlr, SendRCB + 12, 0x4000); for(i=1;i<4;i++) mem32w(ctlr, RecvRetRCB + i * 0x10 + 8, 2); mem32w(ctlr, RecvRetRCB, Pciwaddrh(ctlr->recvret)); mem32w(ctlr, RecvRetRCB + 4, Pciwaddrl(ctlr->recvret)); mem32w(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); }