9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: quanstro@quanstro.net (erik quanstrom)
Subject: [9fans] Forks of Plan 9 (Was: 9vx instability)
Date: Fri, 25 Nov 2011 17:42:22 -0500	[thread overview]
Message-ID: <22cc46aeabe9242035819a85e84179a6@chula.quanstro.net> (raw)
In-Reply-To: <CAHfqX-ot8PRUNW5aH+5zKFQXvd_O+otfE4pBS0HfjfD6-6HQSA@mail.gmail.c>

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);
}


  parent reply	other threads:[~2011-11-25 22:42 UTC|newest]

Thread overview: 92+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-21  8:31 [9fans] 9vx instability Anton
2011-11-21  8:39 ` Alexander Kapshuk
2011-11-21  9:08 ` Akshat Kumar
2011-11-21  9:23 ` Anthony Martin
2011-11-21 21:13   ` yy
2011-11-21 11:01 ` yy
2011-11-21 11:17   ` Jens Staal
2011-11-21 11:56     ` yy
2011-11-21 12:14     ` Anton
2011-11-21 19:58       ` Federico G. Benavento
2011-11-21 14:46     ` Sergey Kish
2011-11-21 14:51       ` Sergey Kish
2011-11-21 15:04       ` Jens Staal
2011-11-21 15:49         ` ron minnich
2011-11-21 16:51           ` Charles Forsyth
2011-11-21 17:09             ` Anton
2011-11-21 17:26               ` Jens Staal
2011-11-21 18:24                 ` ron minnich
2011-11-21 18:35                   ` Charles Forsyth
2011-11-21 18:39                     ` ron minnich
2011-11-21 18:49                       ` Francisco J Ballesteros
2011-11-21 19:02                         ` Charles Forsyth
2011-11-21 19:18                           ` andrey mirtchovski
2011-11-21 20:20                 ` Skip Tavakkolian
     [not found]                 ` <CAJSxfmLDrF5b_MxK7GW0jMRuywo88iDGdsH2ZBPbzzcsTQ1i9Q@mail.gmail.c>
2011-11-21 20:32                   ` erik quanstrom
2011-11-21 21:59                     ` Skip Tavakkolian
2011-11-21 22:44                       ` Anton
2011-11-21 23:02                         ` Skip Tavakkolian
2011-11-24 16:40                           ` Yaroslav
2011-11-24 16:56                             ` Francisco J Ballesteros
2011-11-24 17:56                           ` Rudolf Sykora
2011-11-24 18:51                             ` Skip Tavakkolian
2011-11-25  3:30                               ` Lucio De Re
2011-11-25  4:12                                 ` Stanley Lieber
2011-11-25  6:18                                   ` Lucio De Re
     [not found]                 ` <CAJSxfmLDrF5b_MxK7GW0jMRuywo88iDGdsH2ZBPbzzcsTQ1i9Q@>
     [not found]                   ` <CAJSxfm+TZvGdfMGR1smusVAqJK9w=qtUHkXr8OGc5cuZ9VtrdQ@mail.gmail.c>
2011-11-21 23:07                     ` erik quanstrom
2011-11-22 13:56                       ` Charles Forsyth
     [not found]                   ` <CAOEdRO10gkM7SwLRLyscLYENH=BfS8++mFNiRR6VnuAiRpZcag@mail.gmail.c>
2011-11-24 18:25                     ` erik quanstrom
2011-11-24 18:52                       ` Francisco J Ballesteros
2011-11-24 19:01                         ` Stanley Lieber
2011-11-25  3:37                           ` Lucio De Re
2011-11-25  4:21                             ` Stanley Lieber
2011-11-25 19:20                           ` Skip Tavakkolian
2011-11-24 20:39                         ` cinap_lenrek
2011-11-24 20:45                           ` ron minnich
2011-11-24 21:21                             ` Francisco J Ballesteros
2011-11-25  2:02                           ` erik quanstrom
2011-11-26 23:30                             ` Uriel
     [not found]                             ` <CAK=G1Tj4o_ysw_-dh8EQwWHkSSc6v=ga8E4Z331DasO13WNr_A@mail.gmail.c>
2011-11-26 23:40                               ` erik quanstrom
2011-11-26 23:57                                 ` Jacob Todd
2011-11-27  3:27                                   ` Lucio De Re
2011-11-27  4:26                                     ` cinap_lenrek at gmx.de
2011-11-27  4:32                                     ` cinap_lenrek at gmx.de
2011-11-27 14:23                                       ` Dan Cross
2011-11-27 19:09                                         ` Lyndon Nerenberg
2011-11-27 20:44                                           ` Dan Cross
2011-11-27 23:35                                             ` hiro
2011-11-28 12:02                                               ` Dennis den Brok
2011-11-28  1:45                                       ` Anthony Martin
2011-11-27 18:34                                   ` Skip Tavakkolian
2011-11-27 19:01                                     ` Stanley Lieber
2011-11-27 19:39                                     ` Iruatã Souza
2011-11-27  2:40                                 ` Skip Tavakkolian
2011-11-28  1:14                                 ` Andrés Domínguez
2011-11-25  3:46                           ` Lucio De Re
2011-11-25  4:35                             ` Stanley Lieber
2011-11-25  3:33                         ` [9fans] Forks of Plan 9 (Was: 9vx instability) Lucio De Re
2011-11-25  3:54                           ` Stanley Lieber
2011-11-25  4:14                             ` Lucio De Re
2011-11-25  6:05                             ` cinap_lenrek at gmx.de
2011-11-25  6:22                               ` Lucio De Re
2011-11-25  6:45                                 ` cinap_lenrek at gmx.de
2011-11-25  7:52                                   ` Francisco J Ballesteros
2011-11-25  8:06                                     ` Lucio De Re
2011-11-25 10:15                                       ` Francisco J Ballesteros
2011-11-25 13:25                                         ` Lucio De Re
2011-11-25 13:28                                       ` Charles Forsyth
2011-11-25 13:34                                         ` Charles Forsyth
2011-11-25 14:22                                           ` Lucio De Re
2011-11-25 14:26                                         ` Lucio De Re
2011-11-25 14:38                                   ` erik quanstrom
     [not found]                           ` <CAHfqX-pxHzzHQdf2Rg=Fo+yKOSxYVX7UdU7j4hQJKYS2c7e4tQ@mail.gmail.c>
2011-11-25 13:55                             ` erik quanstrom
2011-11-25 16:56                               ` Stanley Lieber
     [not found]                               ` <CAHfqX-ot8PRUNW5aH+5zKFQXvd_O+otfE4pBS0HfjfD6-6HQSA@mail.gmail.c>
2011-11-25 22:42                                 ` erik quanstrom [this message]
2011-11-25 23:21                                   ` Steve Simon
2011-11-25 23:39                                     ` erik quanstrom
2011-11-27 14:52                                       ` Charles Forsyth
2011-11-26  2:09                                 ` erik quanstrom
2011-11-24 20:35                       ` [9fans] 9vx instability ron minnich
     [not found]           ` <CAOw7k5ijEpAGbQgbG94K3bCfOjTLGCKACRZBj60=-ra57FiXAg@mail.gmail.c>
2011-11-21 16:53             ` erik quanstrom
2011-11-27 13:39     ` yy
2011-11-27 13:43       ` Jens Staal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=22cc46aeabe9242035819a85e84179a6@chula.quanstro.net \
    --to=quanstro@quanstro.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).