/* * Broadcom BCM57xx * Not implemented: * proper fatal error handling * multiple rings * checksum offloading */ #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"#include "ethermii.h" #define dprint(...) do{ if(debug)print(__VA_ARGS__); }while(0)#define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4) typedef struct Ctlr Ctlr;struct Ctlr { Lock txlock, imlock; Ether *ether; Ctlr *next; Pcidev *pdev; u32int *nic, *status; u32int *recvret, *recvprod, *sendr; ulong port; uint recvreti, recvprodi, sendri, sendcleani; Block **sends; Block **rxs; int active, duplex; int type; uint nobuf; uint partial; uint rxerr; uint qfull; uint dmaerr;}; enum { /* configurable constants */ RxRetRingLen = 0x200, RxProdRingLen = 0x200, TxRingLen = 0x200, Reset = 1<<0, Enable = 1<<1, Attn = 1<<2, Pwrctlstat = 0x4C, MiscHostCtl = 0x68, TaggedStatus = 1<<9, IndirAccessEn = 1<<7, EnableClockCtl = 1<<5, PCIStateRegEn = 1<<4, WordSwap = 1<<3, ByteSwap = 1<<2, MaskPCIInt = 1<<1, ClearIntA = 1<<0, Fwmbox = 0x0b50, /* magic value exchange */ Fwmagic = 0x4b657654, Dmarwctl = 0x6C, DMAWaterMask = ~(7<<19), DMAWaterValue = 3<<19, Memwind = 0x7C, MemwindData = 0x84, TxRCB = 0x100, RxRetRCB = 0x200, InterruptMailbox = 0x204, RxProdBDRingIdx = 0x26c, RxBDRetRingIdx = 0x284, TxBDRingHostIdx = 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, RandomBackoff = 0x438, RxMTU = 0x43C, MIComm = 0x44C, MIStatus = 0x450, MIMode = 0x454, RxMACMode = 0x468, TxMACMode = 0x45C, TxMACLengths = 0x464, MACHash = 0x470, RxRules = 0x480, RxRulesConf = 0x500, LowWaterMax = 0x504, LowWaterMaxMask = ~0xFFFF, LowWaterMaxValue = 2, TxDataInitiatorMode = 0xC00, TxInitiatorConf = 0x0C08, TxStats = 1<<0, TxInitiatorMask = 0x0C0C, TxDataCompletionMode = 0x1000, TxBDSelectorMode = 0x1400, TxBDInitiatorMode = 0x1800, TxBDCompletionMode = 0x1C00, RxListPlacementMode = 0x2000, RxListPlacement = 0x2010, RxListPlacementConf = 0x2014, RxStats = 1<<0, RxListPlacementMask = 0x2018, RxDataBDInitiatorMode = 0x2400, RxBDHostAddr = 0x2450, RxBDFlags = 0x2458, RxBDNIC = 0x245C, RxDataCompletionMode = 0x2800, RxBDInitiatorMode = 0x2C00, RxBDRepl = 0x2C18, RxBDCompletionMode = 0x3000, HostCoalMode = 0x3C00, HostCoalRxTicks = 0x3C08, HostCoalTxTicks = 0x3C0C, RxMaxCoalFrames = 0x3C10, TxMaxCoalFrames = 0x3C14, RxMaxCoalFramesInt = 0x3C20, TxMaxCoalFramesInt = 0x3C24, StatusBlockHostAddr = 0x3C38, FlowAttention = 0x3C48, MemArbiterMode = 0x4000, BufferManMode = 0x4400, MBUFLowWater = 0x4414, MBUFHighWater = 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, HostTxBDs = 1<<17, InterruptOnMAC = 1<<26, MiscConf = 0x6804, CoreClockBlocksReset = 1<<0, GPHYPwrdnOverride = 1<<26, DisableGRCRstOnPpcie = 1<<29, TimerMask = ~0xFF, TimerValue = 65<<1, MiscLocalControl = 0x6808, InterruptOnAttn = 1<<3, AutoSEEPROM = 1<<24, SwArbit = 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,}; enum { b5709, b5722, b5751, b5754, b5755, b5756, b5782, b5787, b5906, Nctlrtype,}; typedef struct Ctlrtype Ctlrtype;struct Ctlrtype { int mtu; int flag; char *name;}; static Ctlrtype cttab[Nctlrtype] = {[b5709] 1514, 0, "b5709",[b5722] 1514, 0, "b5722",[b5751] 1514, 0, "b5751",[b5754] 1514, 0, "b5754",[b5755] 1514, 0, "b5755",[b5756] 1514, 0, "b5756",[b5782] 1514, 0, "b5782",[b5787] 1514, 0, "b5787",[b5906] 1514, 0, "b5906",}; #define csr32(c, r) ((c)->nic[(r)/4]) static Ctlr *bcmhead;static int debug; static char*cname(Ctlr *c){ return cttab[c->type].name;} static longbcmifstat(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); p = seprint(p, e, "type: %s\n", cname(c)); USED(p); n = readstr(offset, a, n, s); free(s); return n;} 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 voidchecklink(Ether *edev){ uint i; Ctlr *ctlr; ctlr = edev->ctlr; miir(ctlr, Bmsr); /* read twice for current status as per 802.3 */ if(!(miir(ctlr, Bmsr) & BmsrLs)) { edev->link = 0; edev->mbps = 1000; ctlr->duplex = 1; dprint("bcm: no link\n"); goto out; } edev->link = 1; while((miir(ctlr, Bmsr) & BmsrAnc) == 0) ; i = miir(ctlr, Mssr); if(i & (Mssr1000THD | Mssr1000TFD)) { edev->mbps = 1000; ctlr->duplex = (i & Mssr1000TFD) != 0; } else if(i = miir(ctlr, Anlpar), i & (AnaTXHD | AnaTXFD)) { edev->mbps = 100; ctlr->duplex = (i & AnaTXFD) != 0; } else if(i & (Ana10HD | Ana10FD)) { edev->mbps = 10; ctlr->duplex = (i & Ana10FD) != 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 uint*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 & RxRetRingLen-1; csr32(ctlr, RxBDRetRingIdx) = ctlr->recvreti;} static intreplenish(Ctlr *ctlr){ uint incr; u32int *next; Block *bp; incr = (ctlr->recvprodi + 1) & (RxProdRingLen - 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, RxProdBDRingIdx) = ctlr->recvprodi = incr; return 0;} static voidbcmreceive(Ether *edev){ uint len; u32int *pkt; 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) & (TxRingLen - 1); } iunlock(&ctlr->txlock);} static voidbcmtransmit(Ether *edev){ uint incr; u32int *next; Ctlr *ctlr; Block *bp; ctlr = edev->ctlr; ilock(&ctlr->txlock); for(;;){ incr = (ctlr->sendri + 1) & (TxRingLen - 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, TxBDRingHostIdx) = 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 %#.8ux", csr32(ctlr, FlowAttention));Lines 1–500 of 896. Load more
/* * Broadcom BCM57xx * Not implemented: * proper fatal error handling * multiple rings * checksum offloading */ #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" #include "ethermii.h" #define dprint(...) do{ if(debug)print(__VA_ARGS__); }while(0) #define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4) typedef struct Ctlr Ctlr; struct Ctlr { Lock txlock, imlock; Ether *ether; Ctlr *next; Pcidev *pdev; u32int *nic, *status; u32int *recvret, *recvprod, *sendr; ulong port; uint recvreti, recvprodi, sendri, sendcleani; Block **sends; Block **rxs; int active, duplex; int type; uint nobuf; uint partial; uint rxerr; uint qfull; uint dmaerr; }; enum { /* configurable constants */ RxRetRingLen = 0x200, RxProdRingLen = 0x200, TxRingLen = 0x200, Reset = 1<<0, Enable = 1<<1, Attn = 1<<2, Pwrctlstat = 0x4C, MiscHostCtl = 0x68, TaggedStatus = 1<<9, IndirAccessEn = 1<<7, EnableClockCtl = 1<<5, PCIStateRegEn = 1<<4, WordSwap = 1<<3, ByteSwap = 1<<2, MaskPCIInt = 1<<1, ClearIntA = 1<<0, Fwmbox = 0x0b50, /* magic value exchange */ Fwmagic = 0x4b657654, Dmarwctl = 0x6C, DMAWaterMask = ~(7<<19), DMAWaterValue = 3<<19, Memwind = 0x7C, MemwindData = 0x84, TxRCB = 0x100, RxRetRCB = 0x200, InterruptMailbox = 0x204, RxProdBDRingIdx = 0x26c, RxBDRetRingIdx = 0x284, TxBDRingHostIdx = 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, RandomBackoff = 0x438, RxMTU = 0x43C, MIComm = 0x44C, MIStatus = 0x450, MIMode = 0x454, RxMACMode = 0x468, TxMACMode = 0x45C, TxMACLengths = 0x464, MACHash = 0x470, RxRules = 0x480, RxRulesConf = 0x500, LowWaterMax = 0x504, LowWaterMaxMask = ~0xFFFF, LowWaterMaxValue = 2, TxDataInitiatorMode = 0xC00, TxInitiatorConf = 0x0C08, TxStats = 1<<0, TxInitiatorMask = 0x0C0C, TxDataCompletionMode = 0x1000, TxBDSelectorMode = 0x1400, TxBDInitiatorMode = 0x1800, TxBDCompletionMode = 0x1C00, RxListPlacementMode = 0x2000, RxListPlacement = 0x2010, RxListPlacementConf = 0x2014, RxStats = 1<<0, RxListPlacementMask = 0x2018, RxDataBDInitiatorMode = 0x2400, RxBDHostAddr = 0x2450, RxBDFlags = 0x2458, RxBDNIC = 0x245C, RxDataCompletionMode = 0x2800, RxBDInitiatorMode = 0x2C00, RxBDRepl = 0x2C18, RxBDCompletionMode = 0x3000, HostCoalMode = 0x3C00, HostCoalRxTicks = 0x3C08, HostCoalTxTicks = 0x3C0C, RxMaxCoalFrames = 0x3C10, TxMaxCoalFrames = 0x3C14, RxMaxCoalFramesInt = 0x3C20, TxMaxCoalFramesInt = 0x3C24, StatusBlockHostAddr = 0x3C38, FlowAttention = 0x3C48, MemArbiterMode = 0x4000, BufferManMode = 0x4400, MBUFLowWater = 0x4414, MBUFHighWater = 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, HostTxBDs = 1<<17, InterruptOnMAC = 1<<26, MiscConf = 0x6804, CoreClockBlocksReset = 1<<0, GPHYPwrdnOverride = 1<<26, DisableGRCRstOnPpcie = 1<<29, TimerMask = ~0xFF, TimerValue = 65<<1, MiscLocalControl = 0x6808, InterruptOnAttn = 1<<3, AutoSEEPROM = 1<<24, SwArbit = 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, }; enum { b5709, b5722, b5751, b5754, b5755, b5756, b5782, b5787, b5906, Nctlrtype, }; typedef struct Ctlrtype Ctlrtype; struct Ctlrtype { int mtu; int flag; char *name; }; static Ctlrtype cttab[Nctlrtype] = { [b5709] 1514, 0, "b5709", [b5722] 1514, 0, "b5722", [b5751] 1514, 0, "b5751", [b5754] 1514, 0, "b5754", [b5755] 1514, 0, "b5755", [b5756] 1514, 0, "b5756", [b5782] 1514, 0, "b5782", [b5787] 1514, 0, "b5787", [b5906] 1514, 0, "b5906", }; #define csr32(c, r) ((c)->nic[(r)/4]) static Ctlr *bcmhead; static int debug; static char* cname(Ctlr *c) { return cttab[c->type].name; } 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); p = seprint(p, e, "type: %s\n", cname(c)); USED(p); n = readstr(offset, a, n, s); free(s); return n; } 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 void checklink(Ether *edev) { uint i; Ctlr *ctlr; ctlr = edev->ctlr; miir(ctlr, Bmsr); /* read twice for current status as per 802.3 */ if(!(miir(ctlr, Bmsr) & BmsrLs)) { edev->link = 0; edev->mbps = 1000; ctlr->duplex = 1; dprint("bcm: no link\n"); goto out; } edev->link = 1; while((miir(ctlr, Bmsr) & BmsrAnc) == 0) ; i = miir(ctlr, Mssr); if(i & (Mssr1000THD | Mssr1000TFD)) { edev->mbps = 1000; ctlr->duplex = (i & Mssr1000TFD) != 0; } else if(i = miir(ctlr, Anlpar), i & (AnaTXHD | AnaTXFD)) { edev->mbps = 100; ctlr->duplex = (i & AnaTXFD) != 0; } else if(i & (Ana10HD | Ana10FD)) { edev->mbps = 10; ctlr->duplex = (i & Ana10FD) != 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 uint* 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 & RxRetRingLen-1; csr32(ctlr, RxBDRetRingIdx) = ctlr->recvreti; } static int replenish(Ctlr *ctlr) { uint incr; u32int *next; Block *bp; incr = (ctlr->recvprodi + 1) & (RxProdRingLen - 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, RxProdBDRingIdx) = ctlr->recvprodi = incr; return 0; } static void bcmreceive(Ether *edev) { uint len; u32int *pkt; 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) & (TxRingLen - 1); } iunlock(&ctlr->txlock); } static void bcmtransmit(Ether *edev) { uint incr; u32int *next; Ctlr *ctlr; Block *bp; ctlr = edev->ctlr; ilock(&ctlr->txlock); for(;;){ incr = (ctlr->sendri + 1) & (TxRingLen - 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, TxBDRingHostIdx) = 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 %#.8ux", csr32(ctlr, FlowAttention));