Exemplo n.º 1
0
static void
wpiinterrupt(Ureg*, void *arg)
{
	u32int isr, fhisr;
	Ether *edev;
	Ctlr *ctlr;

	edev = arg;
	ctlr = edev->ctlr;
	ilock(ctlr);
	csr32w(ctlr, Imr, 0);
	isr = csr32r(ctlr, Isr);
	fhisr = csr32r(ctlr, FhIsr);
	if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
		iunlock(ctlr);
		return;
	}
	if(isr == 0 && fhisr == 0)
		goto done;
	csr32w(ctlr, Isr, isr);
	csr32w(ctlr, FhIsr, fhisr);
	if((isr & (Iswrx | Ifhrx)) || (fhisr & Ifhrx))
		receive(ctlr);
	if(isr & Ierr){
		ctlr->broken = 1;
		iprint("#l%d: fatal firmware error, lastcmd %ud\n", edev->ctlrno, ctlr->tx[4].lastcmd);
	}
	ctlr->wait.m |= isr;
	if(ctlr->wait.m & ctlr->wait.w)
		wakeup(&ctlr->wait);
done:
	csr32w(ctlr, Imr, ctlr->ie);
	iunlock(ctlr);
}
Exemplo n.º 2
0
static char*
eepromread(Ctlr *ctlr, void *data, int count, uint off)
{
	uchar *out = data;
	char *err;
	u32int w = 0;
	int i;

	if((err = niclock(ctlr)) != nil)
		return err;

	for(; count > 0; count -= 2, off++){
		csr32w(ctlr, Eeprom, off << 2);
		csr32w(ctlr, Eeprom, csr32r(ctlr, Eeprom) & ~(1<<1));

		for(i = 0; i < 10; i++){
			w = csr32r(ctlr, Eeprom);
			if(w & 1)
				break;
			delay(5);
		}
		if(i == 10)
			break;
		*out++ = w >> 16;
		if(count > 1)
			*out++ = w >> 24;
	}
	nicunlock(ctlr);

	if(count > 0)
		return "eeprompread: timeout";
	return nil;
}
Exemplo n.º 3
0
static char*
poweron(Ctlr *ctlr)
{
	char *err;

	if(ctlr->power)
		return nil;

	csr32w(ctlr, AnaPll, csr32r(ctlr, AnaPll) | Init);
	/* Disable L0s. */
	csr32w(ctlr, GioChicken, csr32r(ctlr, GioChicken) | L1AnoL0Srx);

	if((err = clockwait(ctlr)) != nil)
		return err;

	if((err = niclock(ctlr)) != nil)
		return err;

	prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt);
	delay(20);

	/* Disable L1. */
	prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));

	nicunlock(ctlr);

	ctlr->power = 1;

	return nil;
}
Exemplo n.º 4
0
static void
i82563interrupt(Ureg*, void* arg)
{
	int icr, im, rdh, txdw = 0;
	Block *bp;
	Ctlr *ctlr;
	Ether *edev;
	Rdesc *rdesc;

	edev = arg;
	ctlr = edev->ctlr;

	ilock(&ctlr->imlock);
	csr32w(ctlr, Imc, ~0);
	im = ctlr->im;

	for(icr = csr32r(ctlr, Icr); icr & ctlr->im; icr = csr32r(ctlr, Icr)){
		if(icr & (Rxseq|Lsc)){
			/* should be more here */
		}

		rdh = ctlr->rdh;
		for (;;) {
			rdesc = &ctlr->rdba[rdh];
			if(!(rdesc->status & Rdd))
				break;
			if ((rdesc->status & Reop) && rdesc->errors == 0) {
				bp = ctlr->rb[rdh];
				if(0 && memcmp(bp->rp, broadcast, 6) != 0)
					print("#l%d: rx %d %E %E %d\n",
						edev->ctlrno, rdh, bp->rp,
						bp->rp+6, rdesc->length);
				ctlr->rb[rdh] = nil;
				bp->wp += rdesc->length;
				if (interesting(bp))
					toringbuf(edev, bp);
				freeb(bp);
			} else if (rdesc->status & Reop && rdesc->errors)
				print("%s: input packet error %#ux\n",
					tname[ctlr->type], rdesc->errors);
			rdesc->status = 0;
			rdh = NEXT(rdh, Nrdesc);
		}
		ctlr->rdh = rdh;
		if(icr & Rxdmt0)
			i82563replenish(ctlr);
		if(icr & Txdw){
			im &= ~Txdw;
			txdw++;
		}
	}
	ctlr->im = im;
	csr32w(ctlr, Ims, im);
	iunlock(&ctlr->imlock);
	if(txdw)
		i82563transmit(edev);
}
Exemplo n.º 5
0
static char*
niclock(Ctlr *ctlr)
{
	int i;

	csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq);
	for(i=0; i<1000; i++){
		if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna)
			return 0;
		delay(10);
	}
	return "niclock: timeout";
}
Exemplo n.º 6
0
static void
i82563attach(Ether* edev)
{
	int ctl;
	Ctlr *ctlr;

	ctlr = edev->ctlr;
	i82563im(ctlr, 0);
	ctl = csr32r(ctlr, Rctl)|Ren;
	csr32w(ctlr, Rctl, ctl);
	ctl = csr32r(ctlr, Tctl)|Ten;
	csr32w(ctlr, Tctl, ctl);
}
Exemplo n.º 7
0
static char*
clockwait(Ctlr *ctlr)
{
	int i;

	/* Set "initialization complete" bit. */
	csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | InitDone);
	for(i=0; i<2500; i++){
		if(csr32r(ctlr, Gpc) & MacClockReady)
			return nil;
		delay(10);
	}
	return "clockwait: timeout";
}
Exemplo n.º 8
0
static void
detach(Ctlr *ctlr)
{
	int r;

	/*
	 * Perform a device reset to get the chip back to the
	 * power-on state, followed by an EEPROM reset to read
	 * the defaults for some internal registers.
	 */
	csr32w(ctlr, Imc, ~0);
	csr32w(ctlr, Rctl, 0);
	csr32w(ctlr, Tctl, 0);

	delay(20);

	csr32w(ctlr, Ctrl, Devrst);
	/* apparently needed on multi-GHz processors to avoid infinite loops */
	delay(1);
	while(csr32r(ctlr, Ctrl) & Devrst)
		;

	csr32w(ctlr, Ctrlext, Eerst | csr32r(ctlr, Ctrlext));
	delay(1);
	while(csr32r(ctlr, Ctrlext) & Eerst)
		;

	switch(ctlr->id){
	default:
		break;
	case i82540em:
	case i82540eplp:
	case i82541gi:
	case i82541pi:
	case i82547gi:
	case i82546gb:
	case i82546eb:
		r = csr32r(ctlr, Manc);
		r &= ~Arpen;
		csr32w(ctlr, Manc, r);
		break;
	}

	csr32w(ctlr, Imc, ~0);
	delay(1);
	while(csr32r(ctlr, Icr))
		;
}
Exemplo n.º 9
0
static u32int
prphread(Ctlr *ctlr, uint off)
{
	csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off);
	coherence();
	return csr32r(ctlr, PrphRdata);
}
Exemplo n.º 10
0
static ushort
eeread(Ctlr* ctlr, int adr)
{
	csr32w(ctlr, Eerd, ee_start | adr << 2);
	while ((csr32r(ctlr, Eerd) & ee_done) == 0)
		;
	return csr32r(ctlr, Eerd) >> 16;
}
Exemplo n.º 11
0
static void
wpiattach(Ether *edev)
{
	FWImage *fw;
	Ctlr *ctlr;
	char *err;

	ctlr = edev->ctlr;
	eqlock(ctlr);
	if(waserror()){
		print("#l%d: %s\n", edev->ctlrno, up->errstr);
		if(ctlr->power)
			poweroff(ctlr);
		qunlock(ctlr);
		nexterror();
	}
	if(ctlr->attached == 0){
		if((csr32r(ctlr, Gpc) & RfKill) == 0)
			error("wifi disabled by switch");

		if(ctlr->wifi == nil){
			ctlr->wifi = wifiattach(edev, transmit);
			ctlr->wifi->rates = wpirates;
		}

		if(ctlr->fw == nil){
			fw = readfirmware();
			print("#l%d: firmware: %ux, size: %ux+%ux+%ux+%ux+%ux\n",
				edev->ctlrno, fw->version,
				fw->main.text.size, fw->main.data.size,
				fw->init.text.size, fw->init.data.size,
				fw->boot.text.size);
			ctlr->fw = fw;
		}

		if((err = reset(ctlr)) != nil)
			error(err);
		if((err = boot(ctlr)) != nil)
			error(err);

		ctlr->bcastnodeid = -1;
		ctlr->bssnodeid = -1;
		ctlr->channel = 1;
		ctlr->aid = 0;

		setoptions(edev);

		ctlr->attached = 1;

		kproc("wpirecover", wpirecover, edev);
	}
	qunlock(ctlr);
	poperror();
}
Exemplo n.º 12
0
static int
i82543mdior(Ctlr* ctlr, int n)
{
	int ctrl, data, i, r;

	/*
	 * Read n bits from the Management Data I/O Interface.
	 */
	ctrl = csr32r(ctlr, Ctrl);
	r = (ctrl & ~Mddo)|Mdco;
	data = 0;
	for(i = n-1; i >= 0; i--){
		if(csr32r(ctlr, Ctrl) & Mdd)
			data |= (1<<i);
		csr32w(ctlr, Ctrl, Mdc|r);
		csr32w(ctlr, Ctrl, r);
	}
	csr32w(ctlr, Ctrl, ctrl);

	return data;
}
Exemplo n.º 13
0
static void
igbeattach(Ether* edev)
{
	int ctl;
	Ctlr *ctlr;

	/*
	 * To do here:
	 *	one-time stuff;
	 *	start off a kproc for link status change:
	 *		adjust queue length depending on speed;
	 *		flow control.
	 *	more needed here...
	 */
	ctlr = edev->ctlr;
	igbeim(ctlr, 0);
	ctl = csr32r(ctlr, Rctl)|Ren;
	csr32w(ctlr, Rctl, ctl);
	ctl = csr32r(ctlr, Tctl)|Ten;
	csr32w(ctlr, Tctl, ctl);
}
Exemplo n.º 14
0
static void
detach(Ctlr *ctlr)
{
	int r;

	csr32w(ctlr, Imc, ~0);
	csr32w(ctlr, Rctl, 0);
	csr32w(ctlr, Tctl, 0);

	delay(10);

	r = csr32r(ctlr, Ctrl);
	if(ctlr->type == i82566 || ctlr->type == i82567)
		r |= Phy_rst;
	csr32w(ctlr, Ctrl, Devrst | r);
	/* apparently needed on multi-GHz processors to avoid infinite loops */
	delay(1);
	while(csr32r(ctlr, Ctrl) & Devrst)
		;

	if(1 || ctlr->type != i82563){
		r = csr32r(ctlr, Ctrl);
		csr32w(ctlr, Ctrl, Slu | r);
	}

	csr32w(ctlr, Ctrlext, Eerst | csr32r(ctlr, Ctrlext));
	delay(1);
	while(csr32r(ctlr, Ctrlext) & Eerst)
		;

	csr32w(ctlr, Imc, ~0);
	delay(1);
	while(csr32r(ctlr, Icr))
		;
}
Exemplo n.º 15
0
static void
poweroff(Ctlr *ctlr)
{
	int i, j;

	csr32w(ctlr, Reset, Nevo);

	/* Disable interrupts. */
	csr32w(ctlr, Imr, 0);
	csr32w(ctlr, Isr, ~0);
	csr32w(ctlr, FhIsr, ~0);

	if(niclock(ctlr) == nil){
		/* Stop TX scheduler. */
		prphwrite(ctlr, AlmSchedMode, 0);
		prphwrite(ctlr, AlmSchedTxfact, 0);

		/* Stop all DMA channels */
		for(i = 0; i < 6; i++){
			csr32w(ctlr, FhTxConfig + i*32, 0);
			for(j = 0; j < 100; j++){
				if((csr32r(ctlr, FhTxStatus) & (0x1010000<<i)) == (0x1010000<<i))
					break;
				delay(10);
			}
		}
		nicunlock(ctlr);
	}

	/* Stop RX ring. */
	if(niclock(ctlr) == nil){
		csr32w(ctlr, FhRxConfig, 0);
		for(j = 0; j < 100; j++){
			if(csr32r(ctlr, FhRxStatus) & (1<<24))
				break;
			delay(10);
		}
		nicunlock(ctlr);
	}

	if(niclock(ctlr) == nil){
		prphwrite(ctlr, ApmgClkDis, DmaClkRqt);
		nicunlock(ctlr);
	}
	delay(5);

	csr32w(ctlr, Reset, csr32r(ctlr, Reset) | StopMaster);

	if((csr32r(ctlr, Gpc) & (7<<24)) != (4<<24)){
		for(j = 0; j < 100; j++){
			if(csr32r(ctlr, Reset) & MasterDisabled)
				break;
			delay(10);
		}
	}

	csr32w(ctlr, Reset, csr32r(ctlr, Reset) | SW);

	ctlr->power = 0;
}
Exemplo n.º 16
0
static int
i82563reset(Ctlr* ctlr)
{
	int i, r;

	detach(ctlr);

	if(ctlr->type == i82566 || ctlr->type == i82567)
		r = fload(ctlr);
	else
		r = eeload(ctlr);
	if (r != 0 && r != 0xBABA){
		print("%s: bad EEPROM checksum - 0x%4.4ux\n",
			tname[ctlr->type], r);
		return -1;
	}

	for(i = Ea; i < Eaddrlen/2; i++){
		ctlr->ra[2*i]   = ctlr->eeprom[i];
		ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8;
	}
	r = (csr32r(ctlr, Status) & Lanid) >> 2;
	ctlr->ra[5] += r;		/* ea ctlr[1] = ea ctlr[0]+1 */

	r = ctlr->ra[3]<<24 | ctlr->ra[2]<<16 | ctlr->ra[1]<<8 | ctlr->ra[0];
	csr32w(ctlr, Ral, r);
	r = 0x80000000 | ctlr->ra[5]<<8 | ctlr->ra[4];
	csr32w(ctlr, Rah, r);
	for(i = 1; i < 16; i++){
		csr32w(ctlr, Ral+i*8, 0);
		csr32w(ctlr, Rah+i*8, 0);
	}

	for(i = 0; i < 128; i++)
		csr32w(ctlr, Mta+i*4, 0);

	csr32w(ctlr, Fcal, 0x00C28001);
	csr32w(ctlr, Fcah, 0x00000100);
	csr32w(ctlr, Fct,  0x00008808);
	csr32w(ctlr, Fcttv, 0x00000100);

	csr32w(ctlr, Fcrtl, ctlr->fcrtl);
	csr32w(ctlr, Fcrth, ctlr->fcrth);

	ilock(&ctlr->imlock);
	csr32w(ctlr, Imc, ~0);
	ctlr->im = 0;		/* was = Lsc, which hangs some controllers */
	csr32w(ctlr, Ims, ctlr->im);
	iunlock(&ctlr->imlock);

	return 0;
}
Exemplo n.º 17
0
static char*
postboot(Ctlr *ctlr)
{
	while((ctlr->temp = (int)csr32r(ctlr, UcodeGp2)) == 0)
		delay(10);

if(0){
	char *err;

	if((err = btcoex(ctlr)) != nil)
		print("btcoex: %s\n", err);
	if((err = powermode(ctlr)) != nil)
		print("powermode: %s\n", err);
}

	return nil;
}
Exemplo n.º 18
0
static int
igbemiimiw(Mii* mii, int pa, int ra, int data)
{
	Ctlr *ctlr;
	int mdic, timo;

	ctlr = mii->ctlr;

	data &= MDIdMASK;
	csr32w(ctlr, Mdic, MDIwop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)|data);
	mdic = 0;
	for(timo = 64; timo; timo--){
		mdic = csr32r(ctlr, Mdic);
		if(mdic & (MDIe|MDIready))
			break;
		microdelay(1);
	}
	if((mdic & (MDIe|MDIready)) == MDIready)
		return 0;
	return -1;
}
Exemplo n.º 19
0
static int
igbemiimir(Mii* mii, int pa, int ra)
{
	Ctlr *ctlr;
	int mdic, timo;

	ctlr = mii->ctlr;

	csr32w(ctlr, Mdic, MDIrop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT));
	mdic = 0;
	for(timo = 64; timo; timo--){
		mdic = csr32r(ctlr, Mdic);
		if(mdic & (MDIe|MDIready))
			break;
		microdelay(1);
	}

	if((mdic & (MDIe|MDIready)) == MDIready)
		return mdic & 0xFFFF;
	return -1;
}
Exemplo n.º 20
0
static int
i82543mdiow(Ctlr* ctlr, int bits, int n)
{
	int ctrl, i, r;

	/*
	 * Write n bits to the Management Data I/O Interface.
	 */
	ctrl = csr32r(ctlr, Ctrl);
	r = Mdco|Mddo|ctrl;
	for(i = n-1; i >= 0; i--){
		if(bits & (1<<i))
			r |= Mdd;
		else
			r &= ~Mdd;
		csr32w(ctlr, Ctrl, Mdc|r);
		csr32w(ctlr, Ctrl, r);
	}
	csr32w(ctlr, Ctrl, ctrl);

	return 0;
}
Exemplo n.º 21
0
static int
fload(Ctlr *c)
{
	ulong data, io, r, adr;
	ushort sum;
	Flash f;
	Pcidev *p;

//	io = c->pcidev->mem[1].bar & ~0x0f;
//	f.reg = vmap(io, c->pcidev->mem[1].size);
//	if(f.reg == nil)
//		return -1;

	p = c->pcidev;
	io = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0);
	if(io == 0){
		print("igbepcie: can't map flash @ 0x%8.8lux\n", p->mem[1].bar);
		return -1;
	}
	f.reg = KADDR(io);

	f.reg32 = (ulong*)f.reg;
	f.sz = f.reg32[Bfpr];
	r = f.sz & 0x1fff;
	if(csr32r(c, Eec) & (1<<22))
		++r;
	r <<= 12;

	sum = 0;
	for (adr = 0; adr < 0x40; adr++) {
		data = fread(c, &f, r + adr*2);
		if(data == -1)
			break;
		c->eeprom[adr] = data;
		sum += data;
	}
//	vunmap(f.reg, c->pcidev->mem[1].size);
	return sum;
}
Exemplo n.º 22
0
static void
wpirecover(void *arg)
{
	Ether *edev;
	Ctlr *ctlr;

	edev = arg;
	ctlr = edev->ctlr;
	while(waserror())
		;
	for(;;){
		tsleep(&up->sleep, return0, 0, 4000);

		qlock(ctlr);
		for(;;){
			if(ctlr->broken == 0)
				break;

			if(ctlr->power)
				poweroff(ctlr);

			if((csr32r(ctlr, Gpc) & RfKill) == 0)
				break;

			if(reset(ctlr) != nil)
				break;
			if(boot(ctlr) != nil)
				break;

			ctlr->bcastnodeid = -1;
			ctlr->bssnodeid = -1;
			ctlr->aid = 0;
			rxon(edev, ctlr->wifi->bss);
			break;
		}
		qunlock(ctlr);
	}
}
Exemplo n.º 23
0
static int
igbemii(Ctlr* ctlr)
{
	MiiPhy *phy = (MiiPhy *)1;
	int ctrl, p, r;

	USED(phy);
	r = csr32r(ctlr, Status);
	if(r & Tbimode)
		return -1;
	if((ctlr->mii = malloc(sizeof(Mii))) == nil)
		return -1;
	ctlr->mii->ctlr = ctlr;

	ctrl = csr32r(ctlr, Ctrl);
	ctrl |= Slu;

	switch(ctlr->id){
	case i82543gc:
		ctrl |= Frcdplx|Frcspd;
		csr32w(ctlr, Ctrl, ctrl);

		/*
		 * The reset pin direction (Mdro) should already
		 * be set from the EEPROM load.
		 * If it's not set this configuration is unexpected
		 * so bail.
		 */
		r = csr32r(ctlr, Ctrlext);
		if(!(r & Mdro))
			return -1;
		csr32w(ctlr, Ctrlext, r);
		delay(20);
		r = csr32r(ctlr, Ctrlext);
		r &= ~Mdr;
		csr32w(ctlr, Ctrlext, r);
		delay(20);
		r = csr32r(ctlr, Ctrlext);
		r |= Mdr;
		csr32w(ctlr, Ctrlext, r);
		delay(20);

		ctlr->mii->mir = i82543miimir;
		ctlr->mii->miw = i82543miimiw;
		break;
	case i82544ei:
	case i82547ei:
	case i82540em:
	case i82540eplp:
	case i82547gi:
	case i82541gi:
	case i82541pi:
	case i82546gb:
	case i82546eb:
		ctrl &= ~(Frcdplx|Frcspd);
		csr32w(ctlr, Ctrl, ctrl);
		ctlr->mii->mir = igbemiimir;
		ctlr->mii->miw = igbemiimiw;
		break;
	default:
		free(ctlr->mii);
		ctlr->mii = nil;
		return -1;
	}

	if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
		if (0)
			print("phy trouble: phy = 0x%lux\n", (uint32_t)phy);
		free(ctlr->mii);
		ctlr->mii = nil;
		return -1;
	}
	//print("oui %X phyno %d\n", phy->oui, phy->phyno);
	USED(phy);

	/*
	 * 8254X-specific PHY registers not in 802.3:
	 *	0x10	PHY specific control
	 *	0x14	extended PHY specific control
	 * Set appropriate values then reset the PHY to have
	 * changes noted.
	 */
	switch(ctlr->id){
	case i82547gi:
	case i82541gi:
	case i82541pi:
	case i82546gb:
	case i82546eb:
		break;
	default:
		r = miimir(ctlr->mii, 16);
		r |= 0x0800;			/* assert CRS on Tx */
		r |= 0x0060;			/* auto-crossover all speeds */
		r |= 0x0002;			/* polarity reversal enabled */
		miimiw(ctlr->mii, 16, r);

		r = miimir(ctlr->mii, 20);
		r |= 0x0070;			/* +25MHz clock */
		r &= ~0x0F00;
		r |= 0x0100;			/* 1x downshift */
		miimiw(ctlr->mii, 20, r);

		miireset(ctlr->mii);
		break;
	}
	p = 0;
	if(ctlr->txcw & TxcwPs)
		p |= AnaP;
	if(ctlr->txcw & TxcwAs)
		p |= AnaAP;
	miiane(ctlr->mii, ~0, p, ~0);

	return 0;
}
Exemplo n.º 24
0
static void
igbeinterrupt(Ureg*, void* arg)
{
	Block *bp;
	Ctlr *ctlr;
	Ether *edev;
	Rdesc *rdesc;
	int icr, im, rdh, txdw = 0;

	edev = arg;
	ctlr = edev->ctlr;

	ilock(&ctlr->imlock);
	csr32w(ctlr, Imc, ~0);
	im = ctlr->im;

	if((icr = csr32r(ctlr, Icr)) & ctlr->im){
		/*
		 * Link status changed.
		 */
		if(icr & (Rxseq|Lsc)){
			/*
			 * More here...
			 */
		}

		/*
		 * Process any received packets.
		 */
		rdh = ctlr->rdh;
		for(;;){
			rdesc = &ctlr->rdba[rdh];
			if(!(rdesc->status & Rdd))
				break;
			if ((rdesc->status & Reop) && rdesc->errors == 0) {
				bp = ctlr->rb[rdh];
				ctlr->rb[rdh] = nil;
				/*
				 * it appears that the original 82543 needed
				 * to have the Ethernet CRC excluded, but that
				 * the newer chips do not?
				 */
				bp->wp += rdesc->length /* -4 */;
				toringbuf(edev, bp);
				freeb(bp);
			} else if ((rdesc->status & Reop) && rdesc->errors)
				print("igbe: input packet error 0x%ux\n",
					rdesc->errors);
			rdesc->status = 0;
			rdh = NEXT(rdh, Nrdesc);
		}
		ctlr->rdh = rdh;

		if(icr & Rxdmt0)
			igbereplenish(ctlr);
		if(icr & Txdw){
			im &= ~Txdw;
			txdw++;
		}
	}

	ctlr->im = im;
	csr32w(ctlr, Ims, im);
	iunlock(&ctlr->imlock);

	if(txdw)
		igbetransmit(edev);
}
Exemplo n.º 25
0
static int
igbeinit(Ether* edev)
{
	int csr, i, r, ctrl, timeo;
	MiiPhy *phy;
	Ctlr *ctlr;

	ctlr = edev->ctlr;

	/*
	 * Set up the receive addresses.
	 * There are 16 addresses. The first should be the MAC address.
	 * The others are cleared and not marked valid (MS bit of Rah).
	 */
	csr = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0];
	csr32w(ctlr, Ral, csr);
	csr = 0x80000000|(edev->ea[5]<<8)|edev->ea[4];
	csr32w(ctlr, Rah, csr);
	for(i = 1; i < 16; i++){
		csr32w(ctlr, Ral+i*8, 0);
		csr32w(ctlr, Rah+i*8, 0);
	}

	/*
	 * Clear the Multicast Table Array.
	 * It's a 4096 bit vector accessed as 128 32-bit registers.
	 */
	for(i = 0; i < 128; i++)
		csr32w(ctlr, Mta+i*4, 0);

	/*
	 * Receive initialisation.
	 * Mostly defaults from the datasheet, will
	 * need some tuning for performance:
	 *	Rctl	descriptor mimimum threshold size
	 *		discard pause frames
	 *		strip CRC
	 * 	Rdtr	interrupt delay
	 * 	Rxdctl	all the thresholds
	 */
	csr32w(ctlr, Rctl, 0);

	/*
	 * Allocate the descriptor ring and load its
	 * address and length into the NIC.
	 */
	ctlr->rdba = xspanalloc(Nrdesc*sizeof(Rdesc), 128 /* was 16 */, 0);
	csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba));
	csr32w(ctlr, Rdbah, 0);
	csr32w(ctlr, Rdlen, Nrdesc*sizeof(Rdesc));

	/*
	 * Initialise the ring head and tail pointers and
	 * populate the ring with Blocks.
	 * The datasheet says the tail pointer is set to beyond the last
	 * descriptor hardware can process, which implies the initial
	 * condition is Rdh == Rdt. However, experience shows Rdt must
	 * always be 'behind' Rdh; the replenish routine ensures this.
	 */
	ctlr->rdh = 0;
	csr32w(ctlr, Rdh, ctlr->rdh);
	ctlr->rdt = 0;
	csr32w(ctlr, Rdt, ctlr->rdt);
	ctlr->rb = malloc(sizeof(Block*)*Nrdesc);
	igbereplenish(ctlr);

	/*
	 * Set up Rctl but don't enable receiver (yet).
	 */
	csr32w(ctlr, Rdtr, 0);
	switch(ctlr->id){
	case i82540em:
	case i82540eplp:
	case i82541gi:
	case i82541pi:
	case i82546gb:
	case i82546eb:
	case i82547gi:
		csr32w(ctlr, Radv, 64);
		break;
	}
	csr32w(ctlr, Rxdctl, (8<<WthreshSHIFT)|(8<<HthreshSHIFT)|4);
	/*
	 * Enable checksum offload.
	 */
	csr32w(ctlr, Rxcsum, Tuofl|Ipofl|(ETHERHDRSIZE<<PcssSHIFT));

	csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF);
 	/*
	 * VirtualBox does not like Rxt0,
	 * it continually interrupts.
	 */
	ctlr->im |= /*Rxt0|*/Rxo|Rxdmt0|Rxseq;

	/*
	 * Transmit initialisation.
	 * Mostly defaults from the datasheet, will
	 * need some tuning for performance. The normal mode will
	 * be full-duplex and things to tune for half-duplex are
	 *	Tctl	re-transmit on late collision
	 *	Tipg	all IPG times
	 *	Tbt	burst timer
	 *	Ait	adaptive IFS throttle
	 * and in general
	 *	Txdmac	packet prefetching
	 *	Ett	transmit early threshold
	 *	Tidv	interrupt delay value
	 *	Txdctl	all the thresholds
	 */
	csr32w(ctlr, Tctl, (0x0F<<CtSHIFT)|Psp|(66<<ColdSHIFT));	/* Fd */
	switch(ctlr->id){
	default:
		r = 6;
		break;
	case i82543gc:
	case i82544ei:
	case i82547ei:
	case i82540em:
	case i82540eplp:
	case i82541gi:
	case i82541pi:
	case i82546gb:
	case i82546eb:
	case i82547gi:
		r = 8;
		break;
	}
	csr32w(ctlr, Tipg, (6<<20)|(8<<10)|r);
	csr32w(ctlr, Ait, 0);
	csr32w(ctlr, Txdmac, 0);
	csr32w(ctlr, Tidv, 128);

	/*
	 * Allocate the descriptor ring and load its
	 * address and length into the NIC.
	 */
	ctlr->tdba = xspanalloc(Ntdesc*sizeof(Tdesc), 128 /* was 16 */, 0);
	csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));
	csr32w(ctlr, Tdbah, 0);
	csr32w(ctlr, Tdlen, Ntdesc*sizeof(Tdesc));

	/*
	 * Initialise the ring head and tail pointers.
	 */
	ctlr->tdh = 0;
	csr32w(ctlr, Tdh, ctlr->tdh);
	ctlr->tdt = 0;
	csr32w(ctlr, Tdt, ctlr->tdt);
	ctlr->tb = malloc(sizeof(Block*)*Ntdesc);
//	ctlr->im |= Txqe|Txdw;

	r = (4<<WthreshSHIFT)|(4<<HthreshSHIFT)|(8<<PthreshSHIFT);
	switch(ctlr->id){
	default:
		break;
	case i82540em:
	case i82540eplp:
	case i82547gi:
	case i82541pi:
	case i82546gb:
	case i82546eb:
	case i82541gi:
		r = csr32r(ctlr, Txdctl);
		r &= ~WthreshMASK;
		r |= Gran|(4<<WthreshSHIFT);

		csr32w(ctlr, Tadv, 64);
		break;
	}
	csr32w(ctlr, Txdctl, r);

	r = csr32r(ctlr, Tctl);
	r |= Ten;
	csr32w(ctlr, Tctl, r);

	igbeim(ctlr, ctlr->im);

	if(ctlr->mii == nil || ctlr->mii->curphy == nil) {
		print("igbe: no mii (yet)\n");
		return 0;
	}
	/* wait for the link to come up */
	for(timeo = 0; timeo < 3500; timeo++){
		if(miistatus(ctlr->mii) == 0)
			break;
		delay(10);
	}
	print("igbe: phy: ");
	phy = ctlr->mii->curphy;
	if (phy->fd)
		print("full duplex");
	else
		print("half duplex");
	print(", %d Mb/s\n", phy->speed);

	/*
	 * Flow control.
	 */
	ctrl = csr32r(ctlr, Ctrl);
	if(phy->rfc)
		ctrl |= Rfce;
	if(phy->tfc)
		ctrl |= Tfce;
	csr32w(ctlr, Ctrl, ctrl);

	return 0;
}
Exemplo n.º 26
0
static long
ifstat(Ether* ether, void* a, long n, ulong offset)
{
	Ctlr *ctlr;
	char *buf, *p;
	int i, l, len;

	ctlr = ether->ctlr;

	ether->crcs = ctlr->ce;
	ether->frames = ctlr->rf+ctlr->cs;
	ether->buffs = ctlr->de+ctlr->tl;
	ether->overflows = ctlr->of;

	if(n == 0)
		return 0;

	p = malloc(READSTR);
	l = snprint(p, READSTR, "Overflow: %lud\n", ctlr->of);
	l += snprint(p+l, READSTR-l, "Ru: %lud\n", ctlr->ru);
	l += snprint(p+l, READSTR-l, "Rps: %lud\n", ctlr->rps);
	l += snprint(p+l, READSTR-l, "Rwt: %lud\n", ctlr->rwt);
	l += snprint(p+l, READSTR-l, "Tps: %lud\n", ctlr->tps);
	l += snprint(p+l, READSTR-l, "Tu: %lud\n", ctlr->tu);
	l += snprint(p+l, READSTR-l, "Tjt: %lud\n", ctlr->tjt);
	l += snprint(p+l, READSTR-l, "Unf: %lud\n", ctlr->unf);
	l += snprint(p+l, READSTR-l, "CRC Error: %lud\n", ctlr->ce);
	l += snprint(p+l, READSTR-l, "Collision Seen: %lud\n", ctlr->cs);
	l += snprint(p+l, READSTR-l, "Frame Too Long: %lud\n", ctlr->tl);
	l += snprint(p+l, READSTR-l, "Runt Frame: %lud\n", ctlr->rf);
	l += snprint(p+l, READSTR-l, "Descriptor Error: %lud\n", ctlr->de);
	l += snprint(p+l, READSTR-l, "Underflow Error: %lud\n", ctlr->uf);
	l += snprint(p+l, READSTR-l, "Excessive Collisions: %lud\n", ctlr->ec);
	l += snprint(p+l, READSTR-l, "Late Collision: %lud\n", ctlr->lc);
	l += snprint(p+l, READSTR-l, "No Carrier: %lud\n", ctlr->nc);
	l += snprint(p+l, READSTR-l, "Loss of Carrier: %lud\n", ctlr->lo);
	l += snprint(p+l, READSTR-l, "Transmit Jabber Timeout: %lud\n",
		ctlr->to);
	l += snprint(p+l, READSTR-l, "csr6: %luX %uX\n", csr32r(ctlr, 6),
		ctlr->csr6);
	snprint(p+l, READSTR-l, "ntqmax: %d\n", ctlr->ntqmax);
	ctlr->ntqmax = 0;
	buf = a;
	len = readstr(offset, buf, n, p);
	if(offset > l)
		offset -= l;
	else
		offset = 0;
	buf += len;
	n -= len;

	l = snprint(p, READSTR, "srom:");
	for(i = 0; i < (1<<(ctlr->sromsz)*sizeof(ushort)); i++){
		if(i && ((i & 0x0F) == 0))
			l += snprint(p+l, READSTR-l, "\n     ");
		l += snprint(p+l, READSTR-l, " %2.2uX", ctlr->srom[i]);
	}

	snprint(p+l, READSTR-l, "\n");
	len += readstr(offset, buf, n, p);
	free(p);

	return len;
}
Exemplo n.º 27
0
static int
igbereset(Ctlr* ctlr)
{
	int ctrl, i, pause, r, swdpio, txcw;

	detach(ctlr);

	/*
	 * Read the EEPROM, validate the checksum
	 * then get the device back to a power-on state.
	 */
	r = at93c46r(ctlr);
	/* zero return means no SPI EEPROM access */
	if (r != 0 && r != 0xBABA){
		print("igbe: bad EEPROM checksum - 0x%4.4uX\n", r);
		return -1;
	}

	/*
	 * Snarf and set up the receive addresses.
	 * There are 16 addresses. The first should be the MAC address.
	 * The others are cleared and not marked valid (MS bit of Rah).
	 */
	if ((ctlr->id == i82546gb || ctlr->id == i82546eb) && BUSFNO(ctlr->pcidev->tbdf) == 1)
		ctlr->eeprom[Ea+2] += 0x100;	// second interface
	for(i = Ea; i < Eaddrlen/2; i++){
		ctlr->ra[2*i] = ctlr->eeprom[i];
		ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8;
	}
	r = (ctlr->ra[3]<<24)|(ctlr->ra[2]<<16)|(ctlr->ra[1]<<8)|ctlr->ra[0];
	csr32w(ctlr, Ral, r);
	r = 0x80000000|(ctlr->ra[5]<<8)|ctlr->ra[4];
	csr32w(ctlr, Rah, r);
	for(i = 1; i < 16; i++){
		csr32w(ctlr, Ral+i*8, 0);
		csr32w(ctlr, Rah+i*8, 0);
	}

	/*
	 * Clear the Multicast Table Array.
	 * It's a 4096 bit vector accessed as 128 32-bit registers.
	 */
	memset(ctlr->mta, 0, sizeof(ctlr->mta));
	for(i = 0; i < 128; i++)
		csr32w(ctlr, Mta+i*4, 0);

	/*
	 * Just in case the Eerst didn't load the defaults
	 * (doesn't appear to fully on the 8243GC), do it manually.
	 */
	if (ctlr->id == i82543gc) {
		txcw = csr32r(ctlr, Txcw);
		txcw &= ~(TxcwAne|TxcwPauseMASK|TxcwFd);
		ctrl = csr32r(ctlr, Ctrl);
		ctrl &= ~(SwdpioloMASK|Frcspd|Ilos|Lrst|Fd);

		if(ctlr->eeprom[Icw1] & 0x0400){
			ctrl |= Fd;
			txcw |= TxcwFd;
		}
		if(ctlr->eeprom[Icw1] & 0x0200)
			ctrl |= Lrst;
		if(ctlr->eeprom[Icw1] & 0x0010)
			ctrl |= Ilos;
		if(ctlr->eeprom[Icw1] & 0x0800)
			ctrl |= Frcspd;
		swdpio = (ctlr->eeprom[Icw1] & 0x01E0)>>5;
		ctrl |= swdpio<<SwdpioloSHIFT;
		csr32w(ctlr, Ctrl, ctrl);

		ctrl = csr32r(ctlr, Ctrlext);
		ctrl &= ~(Ips|SwdpiohiMASK);
		swdpio = (ctlr->eeprom[Icw2] & 0x00F0)>>4;
		if(ctlr->eeprom[Icw1] & 0x1000)
			ctrl |= Ips;
		ctrl |= swdpio<<SwdpiohiSHIFT;
		csr32w(ctlr, Ctrlext, ctrl);

		if(ctlr->eeprom[Icw2] & 0x0800)
			txcw |= TxcwAne;
		pause = (ctlr->eeprom[Icw2] & 0x3000)>>12;
		txcw |= pause<<TxcwPauseSHIFT;
		switch(pause){
		default:
			ctlr->fcrtl = 0x00002000;
			ctlr->fcrth = 0x00004000;
			txcw |= TxcwAs|TxcwPs;
			break;
		case 0:
			ctlr->fcrtl = 0x00002000;
			ctlr->fcrth = 0x00004000;
			break;
		case 2:
			ctlr->fcrtl = 0;
			ctlr->fcrth = 0;
			txcw |= TxcwAs;
			break;
		}
		ctlr->txcw = txcw;
		csr32w(ctlr, Txcw, txcw);
	}
Exemplo n.º 28
0
static void
interrupt(Ureg*, void* arg)
{
	Ctlr *ctlr;
	Ether *ether;
	int len, status;
	Des *des;
	Block *bp;

	ether = arg;
	ctlr = ether->ctlr;

	while((status = csr32r(ctlr, 5)) & (Nis|Ais)){
		/*
		 * Acknowledge the interrupts and mask-out
		 * the ones that are implicitly handled.
		 */
		csr32w(ctlr, 5, status);
		status &= (ctlr->mask & ~(Nis|Ti));

		if(status & Ais){
			if(status & Tps)
				ctlr->tps++;
			if(status & Tu)
				ctlr->tu++;
			if(status & Tjt)
				ctlr->tjt++;
			if(status & Ru)
				ctlr->ru++;
			if(status & Rps)
				ctlr->rps++;
			if(status & Rwt)
				ctlr->rwt++;
			status &= ~(Ais|Rwt|Rps|Ru|Tjt|Tu|Tps);
		}

		/*
		 * Received packets.
		 */
		if(status & Ri){
			des = &ctlr->rdr[ctlr->rdrx];
			while(!(des->status & Own)){
				if(des->status & Es){
					if(des->status & Of)
						ctlr->of++;
					if(des->status & Ce)
						ctlr->ce++;
					if(des->status & Cs)
						ctlr->cs++;
					if(des->status & Tl)
						ctlr->tl++;
					if(des->status & Rf)
						ctlr->rf++;
					if(des->status & De)
						ctlr->de++;
				}
				else if(bp = iallocb(Rbsz)){
					len = ((des->status & Fl)>>16)-4;
					des->bp->wp = des->bp->rp+len;
					etheriq(ether, des->bp, 1);
					des->bp = bp;
					des->addr = PCIWADDR(bp->rp);
				}

				des->control &= Er;
				des->control |= Rbsz;
				coherence();
				des->status = Own;

				ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr);
				des = &ctlr->rdr[ctlr->rdrx];
			}
			status &= ~Ri;
		}
Exemplo n.º 29
0
static int
at93c46r(Ctlr* ctlr)
{
	uint16_t sum;
	char rop[20];
	int addr, areq, bits, data, eecd, i;

	eecd = csr32r(ctlr, Eecd);
	if(eecd & Spi){
		print("igbe: SPI EEPROM access not implemented\n");
		return 0;
	}
	if(eecd & (Eeszaddr|Eesz256))
		bits = 8;
	else
		bits = 6;
	sum = 0;

	switch(ctlr->id){
	default:
		areq = 0;
		break;
	case i82540em:
	case i82540eplp:
	case i82541gi:
	case i82541pi:
	case i82547gi:
	case i82546gb:
	case i82546eb:
		areq = 1;
		csr32w(ctlr, Eecd, eecd|Areq);
		for(i = 0; i < 1000; i++){
			if((eecd = csr32r(ctlr, Eecd)) & Agnt)
				break;
			microdelay(5);
		}
		if(!(eecd & Agnt)){
			print("igbe: not granted EEPROM access\n");
			goto release;
		}
		break;
	}
	snprint(rop, sizeof(rop), "S :%dDCc;", bits+3);

	for(addr = 0; addr < 0x40; addr++){
		/*
		 * Read a word at address 'addr' from the Atmel AT93C46
		 * 3-Wire Serial EEPROM or compatible. The EEPROM access is
		 * controlled by 4 bits in Eecd. See the AT93C46 datasheet
		 * for protocol details.
		 */
		if(at93c46io(ctlr, rop, (0x06<<bits)|addr) != 0){
			print("igbe: can't set EEPROM address 0x%2.2X\n", addr);
			goto release;
		}
		data = at93c46io(ctlr, ":16COc;", 0);
		at93c46io(ctlr, "sic", 0);
		ctlr->eeprom[addr] = data;
		sum += data;

		//if(addr && ((addr & 0x07) == 0))
		//	print("\n");
		//print(" %4.4ux", data);
	}
	//print("\n");

release:
	if(areq)
		csr32w(ctlr, Eecd, eecd & ~Areq);
	return sum;
}
Exemplo n.º 30
0
static int
at93c46io(Ctlr* ctlr, char* op, int data)
{
	char *lp, *p;
	int i, loop, eecd, r;

	eecd = csr32r(ctlr, Eecd);

	r = 0;
	loop = -1;
	lp = nil;
	for(p = op; *p != '\0'; p++){
		switch(*p){
		default:
			return -1;
		case ' ':
			continue;
		case ':':			/* start of loop */
			loop = strtol(p+1, &lp, 0)-1;
			lp--;
			if(p == lp)
				loop = 7;
			p = lp;
			continue;
		case ';':			/* end of loop */
			if(lp == nil)
				return -1;
			loop--;
			if(loop >= 0)
				p = lp;
			else
				lp = nil;
			continue;
		case 'C':			/* assert clock */
			eecd |= Sk;
			break;
		case 'c':			/* deassert clock */
			eecd &= ~Sk;
			break;
		case 'D':			/* next bit in 'data' byte */
			if(loop < 0)
				return -1;
			if(data & (1<<loop))
				eecd |= Di;
			else
				eecd &= ~Di;
			break;
		case 'O':			/* collect data output */
			i = (csr32r(ctlr, Eecd) & Do) != 0;
			if(loop >= 0)
				r |= (i<<loop);
			else
				r = i;
			continue;
		case 'I':			/* assert data input */
			eecd |= Di;
			break;
		case 'i':			/* deassert data input */
			eecd &= ~Di;
			break;
		case 'S':			/* enable chip select */
			eecd |= Cs;
			break;
		case 's':			/* disable chip select */
			eecd &= ~Cs;
			break;
		}
		csr32w(ctlr, Eecd, eecd);
		microdelay(50);
	}
	if(loop >= 0)
		return -1;
	return r;
}