894 lines · 21.3 KB · C
RawDownload
/* * 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, imlock;	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, **recvs;	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,	ByteSwap = 1<<2,	WordSwap = 1<<3,	EnablePCIStateRegister = 1<<4,	EnableClockControlRegister = 1<<5,	IndirectAccessEnable = 1<<7,	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,}; enum {	BCM5752 = 0x1600, 	BCM5752M = 0x1601, 	BCM5709 = 0x1639, 	BCM5709S = 0x163a, 	BCM5716 = 0x163b, 	BCM5716S = 0x163c, 	BCM5700 = 0x1644, 	BCM5701 = 0x1645, 	BCM5702 = 0x1646, 	BCM5703 = 0x1647, 	BCM5704 = 0x1648, 	BCM5704S_2 = 0x1649, 	BCM5706 = 0x164a, 	BCM5708 = 0x164c, 	BCM5702FE = 0x164d, 	BCM57710 = 0x164e, 	BCM57711 = 0x164f, 	BCM57711E = 0x1650, 	BCM5705 = 0x1653, 	BCM5705_2 = 0x1654, 	BCM5717 = 0x1655, 	BCM5718 = 0x1656, 	BCM5720 = 0x1658, 	BCM5721 = 0x1659, 	BCM5722 = 0x165a, 	BCM5723 = 0x165b, 	BCM5724 = 0x165c, 	BCM5705M = 0x165d, 	BCM5705M_2 = 0x165e, 	BCM5714 = 0x1668, 	BCM5780 = 0x166a, 	BCM5780S = 0x166b, 	BCM5754M = 0x1672, 	BCM5755M = 0x1673, 	BCM5756ME = 0x1674, 	BCM5750 = 0x1676, 	BCM5751 = 0x1677, 	BCM5715 = 0x1678, 	BCM5715S = 0x1679, 	BCM5754 = 0x167a, 	BCM5755 = 0x167b, 	BCM5750M = 0x167c, 	BCM5751M = 0x167d, 	BCM5751F = 0x167e, 	BCM5787F = 0x167f, 	BCM5761e = 0x1680, 	BCM5761 = 0x1681, 	BCM5764M = 0x1684, 	BCM57760 = 0x1690, 	BCM57788 = 0x1691, 	BCM57780 = 0x1692, 	BCM5787M = 0x1693, 	BCM57790 = 0x1694, 	BCM5782 = 0x1696, 	BCM5784M = 0x1698, 	BCM5785 = 0x1699, 	BCM5786 = 0x169a, 	BCM5787 = 0x169b, 	BCM5788 = 0x169c, 	BCM5789 = 0x169d, 	BCM5785_2 = 0x16a0, 	BCM5702X = 0x16a6, 	BCM5703X = 0x16a7, 	BCM5704S = 0x16a8, 	BCM5706S = 0x16aa, 	BCM5708S = 0x16ac, 	BCM57761 = 0x16b0, 	BCM57781 = 0x16b1, 	BCM57791 = 0x16b2, 	BCM57765 = 0x16b4, 	BCM57785 = 0x16b5, 	BCM57795 = 0x16b6, 	BCM5702A3 = 0x16c6, 	BCM5703_2 = 0x16c7, 	BCM5781 = 0x16dd, 	BCM5753 = 0x16f7, 	BCM5753M = 0x16fd, 	BCM5753F = 0x16fe, 	BCM5906 = 0x1712,	BCM5906M = 0x1713,}; #define csr32(c, r)	((c)->nic[(r)/4])#define mem32(c, r) csr32(c, (r)+0x8000) static Ctlr *bcmhead, *bcmtail; static ulongdummyread(ulong x){	return x;} static intmiir(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 intmiiw(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 voidchecklink(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 voidconsumerecvret(Ctlr *ctlr){	csr32(ctlr, RecvBDRetRingIndex) = ctlr->recvreti = (ctlr->recvreti + 1) & (RecvRetRingLen - 1);} static intreplenish(Ctlr *ctlr){	ulong *next;	ulong incr, idx;	Block *bp; 	idx = ctlr->recvprodi;	incr = (idx + 1) & (RecvProdRingLen - 1);	if(incr == (ctlr->status[2] >> 16)) return -1;	if(ctlr->recvs[idx] != 0) return -1;	bp = iallocb(Rbsz);	if(bp == nil) {		print("bcm: out of memory for receive buffers\n");		return -1;	}	ctlr->recvs[idx] = bp;	next = ctlr->recvprod + idx * 8;	memset(next, 0, 32);	next[1] = PADDR(bp->rp);	next[2] = Rbsz;	next[7] = idx;	coherence();	csr32(ctlr, RecvProdBDRingIndex) = ctlr->recvprodi = incr;	return 0;} static voidbcmreceive(Ether *edev){	Ctlr *ctlr;	Block *bp;	ulong *pkt, len, idx;		ctlr = edev->ctlr;	for(; pkt = currentrecvret(ctlr); replenish(ctlr), consumerecvret(ctlr)) {		idx = pkt[7] & (RecvProdRingLen - 1);		bp = ctlr->recvs[idx];		if(bp == 0) {			print("bcm: nil block at %lux -- shouldn't happen\n", idx);			break;		}		ctlr->recvs[idx] = 0;		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 voidbcmtransclean(Ether *edev, int dolock){	Ctlr *ctlr;		ctlr = edev->ctlr;	if(dolock)		ilock(&ctlr->txlock);	while(ctlr->sendcleani != (ctlr->status[4] >> 16)) {		freeb(ctlr->sends[ctlr->sendcleani]);		ctlr->sends[ctlr->sendcleani] = 0;		ctlr->sendcleani = (ctlr->sendcleani + 1) & (SendRingLen - 1);	}	if(dolock)		iunlock(&ctlr->txlock);} static voidbcmtransmit(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;		if(ctlr->sends[ctlr->sendri] != 0)			freeb(ctlr->sends[ctlr->sendri]);		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) & 0xF8FF8080UL) {			panic("bcm: fatal error %#.8ulx", 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 %#.8ulx", csr32(ctlr, RISCState));		}		csr32(ctlr, RISCState) = 0;	}} static voidbcminterrupt(Ureg*, void *arg){

Lines 1–500 of 894.