added BCM57xx driver
This commit is contained in:
parent
ced69dcde4
commit
e0b36c7084
2 changed files with 670 additions and 0 deletions
669
sys/src/9/pc/etherbcm.c
Normal file
669
sys/src/9/pc/etherbcm.c
Normal file
|
@ -0,0 +1,669 @@
|
|||
/*
|
||||
* Broadcom BCM57xx
|
||||
* Not implemented:
|
||||
* proper fatal error handling
|
||||
* multiple rings
|
||||
* QoS
|
||||
* 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"
|
||||
|
||||
#define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)
|
||||
|
||||
typedef struct Ctlr Ctlr;
|
||||
struct Ctlr {
|
||||
Lock txlock;
|
||||
Ctlr *link;
|
||||
Pcidev *pdev;
|
||||
ulong *nic, *status;
|
||||
/* One Ring to find them, One Ring to bring them all and in the darkness bind them */
|
||||
ulong *recvret, *recvprod, *sendr;
|
||||
ulong port;
|
||||
ulong recvreti, recvprodi, sendri, sendcleani;
|
||||
Block **sends;
|
||||
int active, duplex;
|
||||
};
|
||||
|
||||
enum {
|
||||
RecvRetRingLen = 0x200,
|
||||
RecvProdRingLen = 0x200,
|
||||
SendRingLen = 0x200,
|
||||
};
|
||||
|
||||
enum {
|
||||
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,
|
||||
|
||||
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, *bcmtail;
|
||||
|
||||
static ulong
|
||||
dummyread(ulong x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Ctlr *ctlr;
|
||||
ulong i;
|
||||
|
||||
ctlr = edev->ctlr;
|
||||
miir(ctlr, PhyStatus); /* dummy read necessary */
|
||||
if(!(miir(ctlr, PhyStatus) & PhyLinkStatus)) {
|
||||
edev->link = 0;
|
||||
edev->mbps = 1000;
|
||||
ctlr->duplex = 1;
|
||||
print("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;
|
||||
print("bcm: link partner supports neither 10/100/1000 Mbps\n");
|
||||
goto out;
|
||||
}
|
||||
print("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)
|
||||
{
|
||||
csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti = (ctlr->recvreti + 1) & (RecvRetRingLen - 1);
|
||||
}
|
||||
|
||||
static int
|
||||
replenish(Ctlr *ctlr)
|
||||
{
|
||||
ulong *next;
|
||||
ulong incr;
|
||||
Block *bp;
|
||||
|
||||
incr = (ctlr->recvprodi + 1) & (RecvProdRingLen - 1);
|
||||
if(incr == (ctlr->status[2] >> 16)) 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;
|
||||
memset(next, 0, 32);
|
||||
next[1] = PADDR(bp->rp);
|
||||
next[2] = Rbsz;
|
||||
next[7] = (ulong) bp;
|
||||
csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bcmreceive(Ether *edev)
|
||||
{
|
||||
Ctlr *ctlr;
|
||||
Block *bp;
|
||||
ulong *pkt, len;
|
||||
|
||||
ctlr = edev->ctlr;
|
||||
for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {
|
||||
bp = (Block*) pkt[7];
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bcmtransclean(Ether *edev)
|
||||
{
|
||||
Ctlr *ctlr;
|
||||
ulong incr;
|
||||
|
||||
ctlr = edev->ctlr;
|
||||
ilock(&ctlr->txlock);
|
||||
while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {
|
||||
freeb(ctlr->sends[ctlr->sendri]);
|
||||
ctlr->sends[ctlr->sendri] = 0;
|
||||
ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1);
|
||||
}
|
||||
iunlock(&ctlr->txlock);
|
||||
}
|
||||
|
||||
static void
|
||||
bcmtransmit(Ether *edev)
|
||||
{
|
||||
Ctlr *ctlr;
|
||||
Block *bp;
|
||||
ulong *next;
|
||||
ulong incr;
|
||||
|
||||
ctlr = edev->ctlr;
|
||||
ilock(&ctlr->txlock);
|
||||
while(1) {
|
||||
incr = (ctlr->sendri + 1) & (SendRingLen - 1);
|
||||
if(incr == (ctlr->status[4] >> 16)) {
|
||||
print("bcm: send queue full\n");
|
||||
break;
|
||||
}
|
||||
bp = qget(edev->oq);
|
||||
if(bp == nil) break;
|
||||
next = ctlr->sendr + ctlr->sendri * 4;
|
||||
next[0] = 0;
|
||||
next[1] = PADDR(bp->rp);
|
||||
next[2] = (BLEN(bp) << 16) | PacketEnd;
|
||||
next[3] = 0;
|
||||
ctlr->sends[ctlr->sendri] = bp;
|
||||
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) & 0xF8FF8080UL) {
|
||||
panic("bcm: fatal error %#.8ux", csr32(ctlr, FlowAttention));
|
||||
}
|
||||
csr32(ctlr, FlowAttention) = 0;
|
||||
}
|
||||
csr32(ctlr, MACEventStatus) = 0; /* worth ignoring */
|
||||
if(csr32(ctlr, ReadDMAStatus) || csr32(ctlr, WriteDMAStatus)) {
|
||||
print("bcm: DMA error\n");
|
||||
csr32(ctlr, ReadDMAStatus) = 0;
|
||||
csr32(ctlr, WriteDMAStatus) = 0;
|
||||
}
|
||||
if(csr32(ctlr, RISCState)) {
|
||||
if(csr32(ctlr, RISCState) & 0x78000403) {
|
||||
panic("bcm: RISC halted %#.8ux", csr32(ctlr, RISCState));
|
||||
}
|
||||
csr32(ctlr, RISCState) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bcminterrupt(Ureg*, void *arg)
|
||||
{
|
||||
Ether *edev;
|
||||
Ctlr *ctlr;
|
||||
ulong status, tag;
|
||||
|
||||
edev = arg;
|
||||
ctlr = edev->ctlr;
|
||||
dummyread(csr32(ctlr, InterruptMailbox));
|
||||
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);
|
||||
// print("bcm: interrupt %8ulx %8ulx\n", ctlr->status[2], ctlr->status[4]);
|
||||
bcmreceive(edev);
|
||||
bcmtransclean(edev);
|
||||
bcmtransmit(edev);
|
||||
csr32(ctlr, InterruptMailbox) = tag << 24;
|
||||
}
|
||||
|
||||
static void
|
||||
bcminit(Ether *edev)
|
||||
{
|
||||
ulong i, j;
|
||||
Ctlr *ctlr;
|
||||
|
||||
ctlr = edev->ctlr;
|
||||
print("bcm: reset\n");
|
||||
/* initialization procedure according to the datasheet */
|
||||
csr32(ctlr, MiscHostCtl) |= MaskPCIInt | ClearIntA;
|
||||
csr32(ctlr, SwArbitration) |= SwArbitSet1;
|
||||
while((csr32(ctlr, SwArbitration) & SwArbitWon1) == 0);
|
||||
csr32(ctlr, MemArbiterMode) |= Enable;
|
||||
csr32(ctlr, MiscHostCtl) |= IndirectAccessEnable | EnablePCIStateRegister | EnableClockControlRegister;
|
||||
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;
|
||||
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;
|
||||
microdelay(40000);
|
||||
while(mem32(ctlr, 0xB50) != 0xB49A89AB);
|
||||
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) = 0;
|
||||
csr32(ctlr, ReceiveBDHostAddr + 4) = PADDR(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) = 0;
|
||||
mem32(ctlr, SendRCB + 4) = PADDR(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) = 0;
|
||||
mem32(ctlr, RecvRetRCB + 4) = PADDR(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; Broadcom is fucking with us */
|
||||
microdelay(1000);
|
||||
i = csr32(ctlr, 0x410);
|
||||
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) = 0;
|
||||
csr32(ctlr, StatusBlockHostAddr + 4) = PADDR(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));
|
||||
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;
|
||||
while(csr32(ctlr, MSIMode) & Enable);
|
||||
csr32(ctlr, MiscHostCtl) &= ~(MaskPCIInt | ClearIntA);
|
||||
}
|
||||
|
||||
static void
|
||||
bcmpci(void)
|
||||
{
|
||||
Pcidev *pdev;
|
||||
|
||||
pdev = nil;
|
||||
while(pdev = pcimatch(pdev, 0, 0)) {
|
||||
Ctlr *ctlr;
|
||||
void *mem;
|
||||
|
||||
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 0x14e4167A:
|
||||
case 0x14e4167b:
|
||||
case 0x14e41693:
|
||||
case 0x14e4169B:
|
||||
case 0x14e41712:
|
||||
case 0x14e41713:
|
||||
break;
|
||||
}
|
||||
pcisetbme(pdev);
|
||||
pcisetpms(pdev, 0);
|
||||
ctlr = malloc(sizeof(Ctlr));
|
||||
if(ctlr == nil) {
|
||||
print("bcm: unable to alloc Ctlr\n");
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
ctlr->pdev = pdev;
|
||||
ctlr->nic = mem;
|
||||
ctlr->port = pdev->mem[0].bar & ~0x0F;
|
||||
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(Block) * SendRingLen);
|
||||
if(bcmhead != nil)
|
||||
bcmtail->link = ctlr;
|
||||
else
|
||||
bcmhead = ctlr;
|
||||
bcmtail = ctlr;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if(bcmhead == nil)
|
||||
bcmpci();
|
||||
|
||||
for(ctlr = bcmhead; ctlr != nil; ctlr = ctlr->link) {
|
||||
if(ctlr->active)
|
||||
continue;
|
||||
|
||||
if(edev->port == 0 || edev->port == ctlr->port) {
|
||||
ctlr->active = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ctlr == nil)
|
||||
return -1;
|
||||
|
||||
edev->ctlr = ctlr;
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
etherbcmlink(void)
|
||||
{
|
||||
addethercard("BCM57xx", bcmpnp);
|
||||
}
|
|
@ -52,6 +52,7 @@ link
|
|||
ether82563 pci
|
||||
ether82557 pci
|
||||
ether83815 pci
|
||||
etherbcm pci
|
||||
etherdp83820 pci
|
||||
etherec2t ether8390
|
||||
etherelnk3 pci
|
||||
|
|
Loading…
Reference in a new issue