1857 lines · 34.9 KB · C
RawDownload
#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 "wifi.h" enum {	Nrxlog = 6,	Nrx    = 1<<Nrxlog,	Ntx    = 256, 	Rbufsize = 3*1024,	Rdscsize = 8, 	Tdscsize = 64,	Tcmdsize = 128,}; /* registers */enum {	Cfg		= 0x000,		AlmMb		= 1<<8,		AlmMm		= 1<<9,		SkuMrc		= 1<<10,		RevD		= 1<<11,		TypeB		= 1<<12,	Isr		= 0x008,	Imr		= 0x00c,		Ialive	= 1<<0,		Iwakeup		= 1<<1,		Iswrx		= 1<<3,		Irftoggled	= 1<<7,		Iswerr		= 1<<25,		Ifhtx		= 1<<27,		Ihwerr		= 1<<29,		Ifhrx		= 1<<31,		Ierr		= Iswerr | Ihwerr,		Idefmask	= Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx | Irftoggled,	FhIsr		= 0x010,	GpioIn		= 0x018,	Reset		= 0x020,		Nevo	= 1<<0,		SW	= 1<<7,		MasterDisabled	= 1<<8,		StopMaster	= 1<<9, 	Gpc		= 0x024,		MacAccessEna	= 1<<0,		MacClockReady	= 1<<0,		InitDone	= 1<<2,		MacAccessReq	= 1<<3,		NicSleep	= 1<<4,		RfKill		= 1<<27,	Eeprom		= 0x02c,	EepromGp	= 0x030, 	UcodeGp1Clr	= 0x05c,		UcodeGp1RfKill		= 1<<1,		UcodeGp1CmdBlocked	= 1<<2,	UcodeGp2	= 0x060, 	GioChicken	= 0x100,		L1AnoL0Srx	= 1<<23,	AnaPll		= 0x20c,		Init		= 1<<24, 	PrphWaddr	= 0x444,	PrphRaddr	= 0x448,	PrphWdata	= 0x44c,	PrphRdata	= 0x450,	HbusTargWptr	= 0x460,}; /* * Flow-Handler registers. */enum {	FhCbbcCtrl	= 0x940,	FhCbbcBase	= 0x944,	FhRxConfig	= 0xc00,		FhRxConfigDmaEna	= 1<<31,		FhRxConfigRdrbdEna	= 1<<29,		FhRxConfigWrstatusEna	= 1<<27,		FhRxConfigMaxfrag	= 1<<24,		FhRxConfigIrqDstHost	= 1<<12, 		FhRxConfigNrdbShift	= 20,		FhRxConfigIrqRbthShift	= 4,	FhRxBase	= 0xc04,	FhRxWptr	= 0xc20,	FhRxRptrAddr	= 0xc24,	FhRssrTbl	= 0xcc0,	FhRxStatus	= 0xcc4,	FhTxConfig	= 0xd00,	// +q*32	FhTxBase	= 0xe80,	FhMsgConfig	= 0xe88,	FhTxStatus	= 0xe90,}; /* * NIC internal memory offsets. */enum {	AlmSchedMode	= 0x2e00,	AlmSchedArastat	= 0x2e04,	AlmSchedTxfact	= 0x2e10,	AlmSchedTxf4mf	= 0x2e14,	AlmSchedTxf5mf	= 0x2e20,	AlmSchedBP1	= 0x2e2c,	AlmSchedBP2	= 0x2e30,	ApmgClkEna	= 0x3004,	ApmgClkDis	= 0x3008,		DmaClkRqt	= 1<<9,		BsmClkRqt	= 1<<11,	ApmgPs		= 0x300c,		PwrSrcVMain	= 0<<24,		PwrSrcMask	= 3<<24, 	ApmgPciStt	= 0x3010, 	BsmWrCtrl	= 0x3400,	BsmWrMemSrc	= 0x3404,	BsmWrMemDst	= 0x3408,	BsmWrDwCount	= 0x340c,	BsmDramTextAddr	= 0x3490,	BsmDramTextSize	= 0x3494,	BsmDramDataAddr	= 0x3498,	BsmDramDataSize	= 0x349c,	BsmSramBase	= 0x3800,}; enum {	FilterPromisc		= 1<<0,	FilterCtl		= 1<<1,	FilterMulticast		= 1<<2,	FilterNoDecrypt		= 1<<3,	FilterBSS		= 1<<5,}; enum {	RFlag24Ghz		= 1<<0,	RFlagCCK		= 1<<1,	RFlagAuto		= 1<<2,	RFlagShSlot		= 1<<4,	RFlagShPreamble		= 1<<5,	RFlagNoDiversity	= 1<<7,	RFlagAntennaA		= 1<<8,	RFlagAntennaB		= 1<<9,	RFlagTSF		= 1<<15,}; typedef struct FWSect FWSect;typedef struct FWImage FWImage; typedef struct TXQ TXQ;typedef struct RXQ RXQ; typedef struct Shared Shared;typedef struct Sample Sample;typedef struct Powergrp Powergrp; typedef struct Ctlr Ctlr; struct FWSect{	uchar *data;	uint  size;}; struct FWImage{	struct {		FWSect text;		FWSect data;	} init, main, boot; 	uint  version;	uchar data[];}; struct TXQ{	uint n;	uint i;	Block **b;	uchar *d;	uchar *c; 	uint lastcmd; 	Rendez;	QLock;}; struct RXQ{	uint   i;	Block  **b;	u32int *p;}; struct Shared{	u32int txbase[8];	u32int next;	u32int reserved[2];}; struct Sample{	uchar index;	char power;}; struct Powergrp{	uchar chan;	char maxpwr;	short temp;	Sample samples[5];}; struct Ctlr {	Lock;	QLock; 	Ctlr *link;	Pcidev *pdev;	Wifi *wifi; 	int port;	int power;	int active;	int broken;	int attached; 	int temp;	u32int ie;	u32int *nic; 	/* assigned node ids in hardware node table or -1 if unassigned */	int bcastnodeid;	int bssnodeid; 	/* current receiver settings */	uchar bssid[Eaddrlen];	int channel;	int prom;	int aid; 	RXQ rx;	TXQ tx[8]; 	struct {		Rendez;		u32int	m;		u32int	w;	} wait; 	struct {		uchar cap;		u16int rev;		uchar type; 		char regdom[4+1]; 		Powergrp pwrgrps[5];	} eeprom; 	char maxpwr[256]; 	Shared *shared; 	FWImage *fw;}; static void setled(Ctlr *ctlr, int which, int on, int off); #define csr32r(c, r)	(*((c)->nic+((r)/4)))#define csr32w(c, r, v)	(*((c)->nic+((r)/4)) = (v)) static uintget32(uchar *p){	return *((u32int*)p);}static uintget16(uchar *p){	return *((u16int*)p);}static voidput32(uchar *p, uint v){	*((u32int*)p) = v;}static voidput16(uchar *p, uint v){	*((u16int*)p) = v;}; 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";} static voidnicunlock(Ctlr *ctlr){	csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq);} static u32intprphread(Ctlr *ctlr, uint off){	csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off);	coherence();	return csr32r(ctlr, PrphRdata);}static voidprphwrite(Ctlr *ctlr, uint off, u32int data){	csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off);	coherence();	csr32w(ctlr, PrphWdata, data);} 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;} 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";} 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;} static voidpoweroff(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;} static struct {	u32int	addr;	/* offset in EEPROM */	u8int	nchan;	u8int	chan[14];} bands[5] = {	{ 0x63, 14,	    { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 } },	{ 0x72, 13,	    { 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 } },	{ 0x80, 12,	    { 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 } },	{ 0x8d, 11,	    { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 } },	{ 0x99, 6,	    { 145, 149, 153, 157, 161, 165 } }}; static intwpiinit(Ether *edev)

Lines 1–500 of 1857.