1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039 |
- /*
- * Netgear GA620 Gigabit Ethernet Card.
- * Specific for the Alteon Tigon 2 and Intel Pentium or later.
- * To Do:
- * cache alignment for PCI Write-and-Invalidate
- * mini ring (what size)?
- * tune coalescing values
- * statistics formatting
- * don't update Spi if nothing to send
- * receive ring alignment
- * watchdog for link management?
- */
- #include "all.h"
- #include "io.h"
- #include "mem.h"
- #include "../ip/ip.h"
- #define malign(n) ialloc((n), 32)
- #define KADDR(a) ((void*)((ulong)(a)|KZERO))
- #define PCIWINDOW 0
- #define PCIWADDR(va) (PADDR(va)+PCIWINDOW)
- #include "etherif.h"
- #include "etherga620fw.h"
- enum { /* Compile-time options */
- DoMhcCheck = 1,
- DoCoalUpdateOnly= 1,
- DoHardwareCksum = 0,
- DoCountTicks = 1,
- };
- enum {
- Mhc = 0x0040, /* Miscellaneous Host Control */
- Mlc = 0x0044, /* Miscellaneous Local Control */
- Mc = 0x0050, /* Miscellaneous Configuration */
- Ps = 0x005C, /* PCI State */
- Wba = 0x0068, /* Window Base Address */
- Wd = 0x006C, /* Window Data */
- DMAas = 0x011C, /* DMA Assist State */
- CPUAstate = 0x0140, /* CPU A State */
- CPUApc = 0x0144, /* CPU A Programme Counter */
- CPUBstate = 0x0240, /* CPU B State */
- Hi = 0x0504, /* Host In Interrupt Handler */
- Cpi = 0x050C, /* Command Producer Index */
- Spi = 0x0514, /* Send Producer Index */
- Rspi = 0x051C, /* Receive Standard Producer Index */
- Rjpi = 0x0524, /* Receive Jumbo Producer Index */
- Rmpi = 0x052C, /* Receive Mini Producer Index */
- Mac = 0x0600, /* MAC Address */
- Gip = 0x0608, /* General Information Pointer */
- Om = 0x0618, /* Operating Mode */
- DMArc = 0x061C, /* DMA Read Configuration */
- DMAwc = 0x0620, /* DMA Write Configuration */
- Tbr = 0x0624, /* Transmit Buffer Ratio */
- Eci = 0x0628, /* Event Consumer Index */
- Cci = 0x062C, /* Command Consumer Index */
- Rct = 0x0630, /* Receive Coalesced Ticks */
- Sct = 0x0634, /* Send Coalesced Ticks */
- St = 0x0638, /* Stat Ticks */
- SmcBD = 0x063C, /* Send Max. Coalesced BDs */
- RmcBD = 0x0640, /* Receive Max. Coalesced BDs */
- Nt = 0x0644, /* NIC Tracing */
- Gln = 0x0648, /* Gigabit Link Negotiation */
- Fln = 0x064C, /* 10/100 Link Negotiation */
- Ifx = 0x065C, /* Interface Index */
- IfMTU = 0x0660, /* Interface MTU */
- Mi = 0x0664, /* Mask Interrupts */
- Gls = 0x0668, /* Gigabit Link State */
- Fls = 0x066C, /* 10/100 Link State */
- Cr = 0x0700, /* Command Ring */
- Lmw = 0x0800, /* Local Memory Window */
- };
- enum { /* Mhc */
- Is = 0x00000001, /* Interrupt State */
- Ci = 0x00000002, /* Clear Interrupt */
- Hr = 0x00000008, /* Hard Reset */
- Eebs = 0x00000010, /* Enable Endian Byte Swap */
- Eews = 0x00000020, /* Enable Endian Word (64-bit) swap */
- Mpio = 0x00000040, /* Mask PCI Interrupt Output */
- };
- enum { /* Mlc */
- SRAM512 = 0x00000200, /* SRAM Bank Size of 512KB */
- SRAMmask = 0x00000300,
- EEclk = 0x00100000, /* Serial EEPROM Clock Output */
- EEdoe = 0x00200000, /* Serial EEPROM Data Out Enable */
- EEdo = 0x00400000, /* Serial EEPROM Data Out Value */
- EEdi = 0x00800000, /* Serial EEPROM Data Input */
- };
- enum { /* Mc */
- SyncSRAM = 0x00100000, /* Set Synchronous SRAM Timing */
- };
- enum { /* Ps */
- PCIwm32 = 0x000000C0, /* Write Max DMA 32 */
- PCImrm = 0x00020000, /* Use Memory Read Multiple Command */
- PCI66 = 0x00080000,
- PCI32 = 0x00100000,
- PCIrcmd = 0x06000000, /* PCI Read Command */
- PCIwcmd = 0x70000000, /* PCI Write Command */
- };
- enum { /* CPUAstate */
- CPUrf = 0x00000010, /* ROM Fail */
- CPUhalt = 0x00010000, /* Halt the internal CPU */
- CPUhie = 0x00040000, /* HALT instruction executed */
- };
- enum { /* Om */
- BswapBD = 0x00000002, /* Byte Swap Buffer Descriptors */
- WswapBD = 0x00000004, /* Word Swap Buffer Descriptors */
- Warn = 0x00000008,
- BswapDMA = 0x00000010, /* Byte Swap DMA Data */
- Only1DMA = 0x00000040, /* Only One DMA Active at a time */
- NoJFrag = 0x00000200, /* Don't Fragment Jumbo Frames */
- Fatal = 0x40000000,
- };
- enum { /* Lmw */
- Lmwsz = 2*1024, /* Local Memory Window Size */
- Sr = 0x3800, /* Send Ring (accessed via Lmw) */
- };
- enum { /* Link */
- Lpref = 0x00008000, /* Preferred Link */
- L10MB = 0x00010000,
- L100MB = 0x00020000,
- L1000MB = 0x00040000,
- Lfd = 0x00080000, /* Full Duplex */
- Lhd = 0x00100000, /* Half Duplex */
- Lefc = 0x00200000, /* Emit Flow Control Packets */
- Lofc = 0x00800000, /* Obey Flow Control Packets */
- Lean = 0x20000000, /* Enable Autonegotiation/Sensing */
- Le = 0x40000000, /* Link Enable */
- };
- typedef struct Host64 {
- uint hi;
- uint lo;
- } Host64;
- typedef struct Ere { /* Event Ring Element */
- int event; /* (event<<24)|(code<<12)|index */
- int unused;
- } Ere;
- typedef int Cmd; /* (cmd<<24)|(flags<<12)|index */
- typedef struct Rbd { /* Receive Buffer Descriptor */
- Host64 addr;
- int indexlen; /* (ring-index<<16)|buffer-length */
- int flags; /* only lower 16-bits */
- int checksum; /* (ip<<16)|tcp/udp */
- int error; /* only upper 16-bits */
- int reserved;
- void* opaque; /* passed to receive return ring */
- } Rbd;
- typedef struct Sbd { /* Send Buffer Descriptor */
- Host64 addr;
- int lenflags; /* (len<<16)|flags */
- int reserved;
- } Sbd;
- enum { /* Buffer Descriptor Flags */
- Fend = 0x00000004, /* Frame Ends in this Buffer */
- Frjr = 0x00000010, /* Receive Jumbo Ring Buffer */
- Funicast = 0x00000020, /* Unicast packet (2-bit field) */
- Fmulticast = 0x00000040, /* Multicast packet */
- Fbroadcast = 0x00000060, /* Broadcast packet */
- Ferror = 0x00000400, /* Frame Has Error */
- Frmr = 0x00001000, /* Receive Mini Ring Buffer */
- };
- enum { /* Buffer Error Flags */
- Ecrc = 0x00010000, /* bad CRC */
- Ecollision = 0x00020000, /* collision */
- Elink = 0x00040000, /* link lost */
- Ephy = 0x00080000, /* unspecified PHY frame decode error */
- Eodd = 0x00100000, /* odd number of nibbles */
- Emac = 0x00200000, /* unspecified MAC abort */
- Elen64 = 0x00400000, /* short packet */
- Eresources = 0x00800000, /* MAC out of internal resources */
- Egiant = 0x01000000, /* packet too big */
- };
- typedef struct Rcb { /* Ring Control Block */
- Host64 addr; /* points to the Rbd ring */
- int control; /* (max_len<<16)|flags */
- int unused;
- } Rcb;
- enum {
- TcpUdpCksum = 0x0001, /* Perform TCP or UDP checksum */
- IpCksum = 0x0002, /* Perform IP checksum */
- NoPseudoHdrCksum= 0x0008, /* Don't include the pseudo header */
- VlanAssist = 0x0010, /* Enable VLAN tagging */
- CoalUpdateOnly = 0x0020, /* Coalesce transmit interrupts */
- HostRing = 0x0040, /* Sr in host memory */
- SnapCksum = 0x0080, /* Parse + offload 802.3 SNAP frames */
- UseExtRxBd = 0x0100, /* Extended Rbd for Jumbo frames */
- RingDisabled = 0x0200, /* Jumbo or Mini RCB only */
- };
- typedef struct Gib { /* General Information Block */
- int statistics[256]; /* Statistics */
- Rcb ercb; /* Event Ring */
- Rcb crcb; /* Command Ring */
- Rcb srcb; /* Send Ring */
- Rcb rsrcb; /* Receive Standard Ring */
- Rcb rjrcb; /* Receive Jumbo Ring */
- Rcb rmrcb; /* Receive Mini Ring */
- Rcb rrrcb; /* Receive Return Ring */
- Host64 epp; /* Event Producer */
- Host64 rrrpp; /* Receive Return Ring Producer */
- Host64 scp; /* Send Consumer */
- Host64 rsp; /* Refresh Stats */
- } Gib;
- enum { /* Host/NIC Interface ring sizes */
- Ner = 256, /* event ring */
- Ncr = 64, /* command ring */
- Nsr = 512, /* send ring */
- Nrsr = 512, /* receive standard ring */
- Nrjr = 256, /* receive jumbo ring */
- Nrmr = 1024, /* receive mini ring */
- Nrrr = 2048, /* receive return ring */
- };
- enum {
- NrsrHI = 72, /* Fill-level of Rsr (m.b. < Nrsr) */
- NrsrLO = 54, /* Level at which to top-up ring */
- NrjrHI = 0, /* Fill-level of Rjr (m.b. < Nrjr) */
- NrjrLO = 0, /* Level at which to top-up ring */
- NrmrHI = 0, /* Fill-level of Rmr (m.b. < Nrmr) */
- NrmrLO = 0, /* Level at which to top-up ring */
- };
- typedef struct Ctlr Ctlr;
- typedef struct Ctlr {
- int port;
- Pcidev* pcidev;
- Ctlr* next;
- int active;
- int id;
- uchar ea[Easize];
- int interrupts;
- uvlong ticks;
- int* nic;
- Gib* gib;
- Ere* er;
- Lock srlock;
- Sbd* sr;
- Msgbuf** srb;
- int nsr; /* currently in send ring */
- Rbd* rsr;
- int nrsr; /* currently in Receive Standard Ring */
- Rbd* rjr;
- int nrjr; /* currently in Receive Jumbo Ring */
- Rbd* rmr;
- int nrmr; /* currently in Receive Mini Ring */
- Rbd* rrr;
- int rrrci; /* Receive Return Ring Consumer Index */
- int epi[2]; /* Event Producer Index */
- int rrrpi[2]; /* Receive Return Ring Producer Index */
- int sci[3]; /* Send Consumer Index ([2] is host) */
- } Ctlr;
- static Ctlr* ctlrhead;
- static Ctlr* ctlrtail;
- #define csr32r(c, r) (*((c)->nic+((r)/4)))
- #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
- static void
- sethost64(Host64* host64, void* addr)
- {
- uvlong uvl;
- uvl = PCIWADDR(addr);
- host64->hi = uvl>>32;
- host64->lo = uvl & 0xFFFFFFFFL;
- }
- static void
- ga620command(Ctlr* ctlr, int cmd, int flags, int index)
- {
- int cpi;
- cpi = csr32r(ctlr, Cpi);
- csr32w(ctlr, Cr+(cpi*4), (cmd<<24)|(flags<<12)|index);
- cpi = NEXT(cpi, Ncr);
- csr32w(ctlr, Cpi, cpi);
- }
- static void
- ga620attach(Ether* edev)
- {
- Ctlr *ctlr;
- ctlr = edev->ctlr;
- USED(ctlr);
- }
- static void
- ga620transmit(Ether* edev)
- {
- Sbd *sbd;
- Msgbuf *bp;
- Ctlr *ctlr;
- int sci, spi;
- /*
- * For now there are no smarts here, just empty the
- * ring and try to fill it back up. Tuning comes later.
- */
- ctlr = edev->ctlr;
- ilock(&ctlr->srlock);
- /*
- * Free any completed packets.
- * Ctlr->sci[0] is where the NIC has got to consuming the ring.
- * Ctlr->sci[2] is where the host has got to tidying up after the
- * NIC has done with the packets.
- */
- for(sci = ctlr->sci[2]; sci != ctlr->sci[0]; sci = NEXT(sci, Nsr)){
- if(ctlr->srb[sci] == nil)
- continue;
- mbfree(ctlr->srb[sci]);
- ctlr->srb[sci] = nil;
- }
- ctlr->sci[2] = sci;
- sci = PREV(sci, Nsr);
- for(spi = csr32r(ctlr, Spi); spi != sci; spi = NEXT(spi, Nsr)){
- if((bp = etheroq(edev)) == nil)
- break;
- sbd = &ctlr->sr[spi];
- sethost64(&sbd->addr, bp->data);
- sbd->lenflags = (bp->count<<16)|Fend;
- ctlr->srb[spi] = bp;
- }
- csr32w(ctlr, Spi, spi);
- iunlock(&ctlr->srlock);
- }
- static void
- ga620replenish(Ctlr* ctlr)
- {
- Rbd *rbd;
- int rspi;
- Msgbuf *bp;
- rspi = csr32r(ctlr, Rspi);
- while(ctlr->nrsr < NrsrHI){
- if((bp = mballoc(ETHERMAXTU+4, 0, Mbeth1)) == nil)
- break;
- rbd = &ctlr->rsr[rspi];
- sethost64(&rbd->addr, bp->data);
- rbd->indexlen = (rspi<<16)|(ETHERMAXTU+4);
- rbd->flags = 0;
- rbd->opaque = bp;
- rspi = NEXT(rspi, Nrsr);
- ctlr->nrsr++;
- }
- csr32w(ctlr, Rspi, rspi);
- }
- static void
- ga620event(Ctlr* ctlr, int eci, int epi)
- {
- int event;
- while(eci != epi){
- event = ctlr->er[eci].event;
- switch(event>>24){
- case 0x01: /* firmware operational */
- ga620command(ctlr, 0x01, 0x01, 0x00);
- ga620command(ctlr, 0x0B, 0x00, 0x00);
- print("%8.8uX: %8.8uX\n", ctlr->port, event);
- break;
- case 0x04: /* statistics updated */
- break;
- case 0x06: /* link state changed */
- print("%8.8uX: %8.8uX %8.8uX %8.8uX\n",
- ctlr->port, event, csr32r(ctlr, Gls), csr32r(ctlr, Fls));
- break;
- case 0x07: /* event error */
- default:
- print("er[%d] = %8.8uX\n", eci, event);
- break;
- }
- eci = NEXT(eci, Ner);
- }
- csr32w(ctlr, Eci, eci);
- }
- static void
- ga620receive(Ether* edev)
- {
- int len;
- Rbd *rbd;
- Msgbuf *bp;
- Ctlr* ctlr;
- ctlr = edev->ctlr;
- while(ctlr->rrrci != ctlr->rrrpi[0]){
- rbd = &ctlr->rrr[ctlr->rrrci];
- /*
- * Errors are collected in the statistics block so
- * no need to tally them here, let ifstat do the work.
- */
- len = rbd->indexlen & 0xFFFF;
- if(!(rbd->flags & Ferror) && len != 0){
- bp = rbd->opaque;
- bp->count = len;
- etheriq(edev, bp);
- }
- else
- mbfree(rbd->opaque);
- rbd->opaque = nil;
- if(rbd->flags & Frjr)
- ctlr->nrjr--;
- else if(rbd->flags & Frmr)
- ctlr->nrmr--;
- else
- ctlr->nrsr--;
- ctlr->rrrci = NEXT(ctlr->rrrci, Nrrr);
- }
- }
- static void
- ga620interrupt(Ureg*, void* arg)
- {
- int csr;
- Ctlr *ctlr;
- Ether *edev;
- uvlong tsc0, tsc1;
- edev = arg;
- ctlr = edev->ctlr;
- if(DoMhcCheck){
- if(!(csr32r(ctlr, Mhc) & Is))
- return;
- }
- if(DoCountTicks)
- rdtsc(&tsc0);
- ctlr->interrupts++;
- csr32w(ctlr, Hi, 1);
- if(ctlr->rrrci != ctlr->rrrpi[0])
- ga620receive(edev);
- ga620transmit(edev);
- csr = csr32r(ctlr, Eci);
- if(csr != ctlr->epi[0])
- ga620event(ctlr, csr, ctlr->epi[0]);
- if(ctlr->nrsr <= NrsrLO)
- ga620replenish(ctlr);
- csr32w(ctlr, Hi, 0);
- if(DoCountTicks){
- rdtsc(&tsc1);
- ctlr->ticks += tsc1-tsc0;
- }
- }
- static void
- ga620lmw(Ctlr* ctlr, int addr, int* data, int len)
- {
- int i, l, lmw, v;
- /*
- * Write to or clear ('data' == nil) 'len' bytes of the NIC
- * local memory at address 'addr'.
- * The destination address and count should be 32-bit aligned.
- */
- v = 0;
- while(len > 0){
- /*
- * 1) Set the window. The (Lmwsz-1) bits are ignored
- * in Wba when accessing through the local memory window;
- * 2) Find the minimum of how many bytes still to
- * transfer and how many left in this window;
- * 3) Create the offset into the local memory window in the
- * shared memory space then copy (or zero) the data;
- * 4) Bump the counts.
- */
- csr32w(ctlr, Wba, addr);
- l = ROUNDUP(addr+1, Lmwsz) - addr;
- if(l > len)
- l = len;
- lmw = Lmw + (addr & (Lmwsz-1));
- for(i = 0; i < l; i += 4){
- if(data != nil)
- v = *data++;
- csr32w(ctlr, lmw+i, v);
- }
- len -= l;
- addr += l;
- }
- }
- static int
- ga620init(Ether* edev)
- {
- Ctlr *ctlr;
- Host64 host64;
- int csr, ea, i, flags;
- ctlr = edev->ctlr;
- /*
- * Load the MAC address.
- */
- ea = (edev->ea[0]<<8)|edev->ea[1];
- csr32w(ctlr, Mac, ea);
- ea = (edev->ea[2]<<24)|(edev->ea[3]<<16)|(edev->ea[4]<<8)|edev->ea[5];
- csr32w(ctlr, Mac+4, ea);
- /*
- * General Information Block.
- */
- ctlr->gib = ialloc(sizeof(Gib), 0);
- sethost64(&host64, ctlr->gib);
- csr32w(ctlr, Gip, host64.hi);
- csr32w(ctlr, Gip+4, host64.lo);
- /*
- * Event Ring.
- * This is located in host memory. Allocate the ring,
- * tell the NIC where it is and initialise the indices.
- */
- ctlr->er = malign(sizeof(Ere)*Ner);
- sethost64(&ctlr->gib->ercb.addr, ctlr->er);
- sethost64(&ctlr->gib->epp, ctlr->epi);
- csr32w(ctlr, Eci, 0);
- /*
- * Command Ring.
- * This is located in the General Communications Region
- * and so the value placed in the Rcb is unused, the NIC
- * knows where it is. Stick in the value according to
- * the datasheet anyway.
- * Initialise the ring and indices.
- */
- ctlr->gib->crcb.addr.lo = Cr-0x400;
- for(i = 0; i < Ncr*4; i += 4)
- csr32w(ctlr, Cr+i, 0);
- csr32w(ctlr, Cpi, 0);
- csr32w(ctlr, Cci, 0);
- /*
- * Send Ring.
- * This ring is either in NIC memory at a fixed location depending
- * on how big the ring is or it is in host memory. If in NIC
- * memory it is accessed via the Local Memory Window; with a send
- * ring size of 128 the window covers the whole ring and then need
- * only be set once:
- * ctlr->sr = KADDR(ctlr->port+Lmw);
- * ga620lmw(ctlr, Sr, nil, sizeof(Sbd)*Nsr);
- * ctlr->gib->srcb.addr.lo = Sr;
- * There is nowhere in the Sbd to hold the Block* associated
- * with this entry so an external array must be kept.
- */
- ctlr->sr = malign(sizeof(Sbd)*Nsr);
- sethost64(&ctlr->gib->srcb.addr, ctlr->sr);
- if(DoHardwareCksum)
- flags = TcpUdpCksum|NoPseudoHdrCksum|HostRing;
- else
- flags = HostRing;
- if(DoCoalUpdateOnly)
- flags |= CoalUpdateOnly;
- ctlr->gib->srcb.control = (Nsr<<16)|flags;
- sethost64(&ctlr->gib->scp, ctlr->sci);
- csr32w(ctlr, Spi, 0);
- ctlr->srb = ialloc(sizeof(Msgbuf*)*Nsr, 0);
- /*
- * Receive Standard Ring.
- */
- ctlr->rsr = malign(sizeof(Rbd)*Nrsr);
- sethost64(&ctlr->gib->rsrcb.addr, ctlr->rsr);
- if(DoHardwareCksum)
- flags = TcpUdpCksum|NoPseudoHdrCksum;
- else
- flags = 0;
- ctlr->gib->rsrcb.control = ((ETHERMAXTU+4)<<16)|flags;
- csr32w(ctlr, Rspi, 0);
- /*
- * Jumbo and Mini Rings. Unused for now.
- */
- ctlr->gib->rjrcb.control = RingDisabled;
- ctlr->gib->rmrcb.control = RingDisabled;
- /*
- * Receive Return Ring.
- * This is located in host memory. Allocate the ring,
- * tell the NIC where it is and initialise the indices.
- */
- ctlr->rrr = malign(sizeof(Rbd)*Nrrr);
- sethost64(&ctlr->gib->rrrcb.addr, ctlr->rrr);
- ctlr->gib->rrrcb.control = (Nrrr<<16)|0;
- sethost64(&ctlr->gib->rrrpp, ctlr->rrrpi);
- ctlr->rrrci = 0;
- /*
- * Refresh Stats Pointer.
- * For now just point it at the existing statistics block.
- */
- sethost64(&ctlr->gib->rsp, ctlr->gib->statistics);
- /*
- * DMA configuration.
- * Use the recommended values.
- */
- csr32w(ctlr, DMArc, 0x80);
- csr32w(ctlr, DMAwc, 0x80);
- /*
- * Transmit Buffer Ratio.
- * Set to 1/3 of available buffer space (units are 1/64ths)
- * if using Jumbo packets, ~64KB otherwise (assume 1MB on NIC).
- */
- if(NrjrHI > 0 || Nsr > 128)
- csr32w(ctlr, Tbr, 64/3);
- else
- csr32w(ctlr, Tbr, 4);
- /*
- * Tuneable parameters.
- * These defaults are based on the tuning hints in the Alteon
- * Host/NIC Software Interface Definition and example software.
- */
- csr32w(ctlr, Rct, 120);
- csr32w(ctlr, Sct, 400);
- csr32w(ctlr, St, 1000000);
- csr32w(ctlr, SmcBD, 60);
- csr32w(ctlr, RmcBD, 25);
- /*
- * Enable DMA Assist Logic.
- */
- csr = csr32r(ctlr, DMAas) & ~0x03;
- csr32w(ctlr, DMAas, csr|0x01);
- /*
- * Link negotiation.
- * The bits are set here but the NIC must be given a command
- * once it is running to set negotiation in motion.
- */
- csr32w(ctlr, Gln, Le|Lean|Lofc|Lfd|L1000MB|Lpref);
- csr32w(ctlr, Fln, Le|Lean|Lhd|Lfd|L100MB|L10MB);
- /*
- * A unique index for this controller and the maximum packet
- * length expected.
- * For now only standard packets are expected.
- */
- csr32w(ctlr, Ifx, 1);
- csr32w(ctlr, IfMTU, ETHERMAXTU+4);
- /*
- * Enable Interrupts.
- * There are 3 ways to mask interrupts - a bit in the Mhc (which
- * is already cleared), the Mi register and the Hi mailbox.
- * Writing to the Hi mailbox has the side-effect of clearing the
- * PCI interrupt.
- */
- csr32w(ctlr, Mi, 0);
- csr32w(ctlr, Hi, 0);
- /*
- * Start the firmware.
- */
- csr32w(ctlr, CPUApc, tigon2FwStartAddr);
- csr = csr32r(ctlr, CPUAstate) & ~CPUhalt;
- csr32w(ctlr, CPUAstate, csr);
- return 0;
- }
- static int
- at24c32io(Ctlr* ctlr, char* op, int data)
- {
- char *lp, *p;
- int i, loop, mlc, r;
- mlc = csr32r(ctlr, Mlc);
- r = 0;
- loop = -1;
- lp = nil;
- for(p = op; *p != '\0'; p++){
- switch(*p){
- default:
- return -1;
- case ' ':
- continue;
- case ':': /* start of 8-bit loop */
- if(lp != nil)
- return -1;
- lp = p;
- loop = 7;
- continue;
- case ';': /* end of 8-bit loop */
- if(lp == nil)
- return -1;
- loop--;
- if(loop >= 0)
- p = lp;
- else
- lp = nil;
- continue;
- case 'C': /* assert clock */
- mlc |= EEclk;
- break;
- case 'c': /* deassert clock */
- mlc &= ~EEclk;
- break;
- case 'D': /* next bit in 'data' byte */
- if(loop < 0)
- return -1;
- if(data & (1<<loop))
- mlc |= EEdo;
- else
- mlc &= ~EEdo;
- break;
- case 'E': /* enable data output */
- mlc |= EEdoe;
- break;
- case 'e': /* disable data output */
- mlc &= ~EEdoe;
- break;
- case 'I': /* input bit */
- i = (csr32r(ctlr, Mlc) & EEdi) != 0;
- if(loop >= 0)
- r |= (i<<loop);
- else
- r = i;
- continue;
- case 'O': /* assert data output */
- mlc |= EEdo;
- break;
- case 'o': /* deassert data output */
- mlc &= ~EEdo;
- break;
- }
- csr32w(ctlr, Mlc, mlc);
- microdelay(1);
- }
- if(loop >= 0)
- return -1;
- return r;
- }
- static int
- at24c32r(Ctlr* ctlr, int addr)
- {
- int data;
- /*
- * Read a byte at address 'addr' from the Atmel AT24C32
- * Serial EEPROM. The 2-wire EEPROM access is controlled
- * by 4 bits in Mlc. See the AT24C32 datasheet for
- * protocol details.
- */
- /*
- * Start condition - a high to low transition of data
- * with the clock high must precede any other command.
- */
- at24c32io(ctlr, "OECoc", 0);
- /*
- * Perform a random read at 'addr'. A dummy byte
- * write sequence is performed to clock in the device
- * and data word addresses (0 and 'addr' respectively).
- */
- data = -1;
- if(at24c32io(ctlr, "oE :DCc; oeCIc", 0xA0) != 0)
- goto stop;
- if(at24c32io(ctlr, "oE :DCc; oeCIc", addr>>8) != 0)
- goto stop;
- if(at24c32io(ctlr, "oE :DCc; oeCIc", addr) != 0)
- goto stop;
- /*
- * Now send another start condition followed by a
- * request to read the device. The EEPROM responds
- * by clocking out the data.
- */
- at24c32io(ctlr, "OECoc", 0);
- if(at24c32io(ctlr, "oE :DCc; oeCIc", 0xA1) != 0)
- goto stop;
- data = at24c32io(ctlr, ":CIc;", 0xA1);
- stop:
- /*
- * Stop condition - a low to high transition of data
- * with the clock high is a stop condition. After a read
- * sequence, the stop command will place the EEPROM in
- * a standby power mode.
- */
- at24c32io(ctlr, "oECOc", 0);
- return data;
- }
- static int
- ga620detach(Ctlr* ctlr)
- {
- int timeo;
- /*
- * Hard reset (don't know which endian so catch both);
- * enable for little-endian mode;
- * wait for code to be loaded from serial EEPROM or flash;
- * make sure CPU A is halted.
- */
- csr32w(ctlr, Mhc, (Hr<<24)|Hr);
- csr32w(ctlr, Mhc, ((Eews|Ci)<<24)|(Eews|Ci));
- microdelay(1);
- for(timeo = 0; timeo < 500000; timeo++){
- if((csr32r(ctlr, CPUAstate) & (CPUhie|CPUrf)) == CPUhie)
- break;
- microdelay(1);
- }
- if((csr32r(ctlr, CPUAstate) & (CPUhie|CPUrf)) != CPUhie)
- return -1;
- csr32w(ctlr, CPUAstate, CPUhalt);
- /*
- * After reset, CPU B seems to be stuck in 'CPUrf'.
- * Worry about it later.
- */
- csr32w(ctlr, CPUBstate, CPUhalt);
- return 0;
- }
- static int
- ga620reset(Ctlr* ctlr)
- {
- int cls, csr, i;
- if(ga620detach(ctlr) < 0)
- return -1;
- /*
- * Tigon 2 PCI NICs have 512KB SRAM per bank.
- * Clear out any lingering serial EEPROM state
- * bits.
- */
- csr = csr32r(ctlr, Mlc) & ~(EEdi|EEdo|EEdoe|EEclk|SRAMmask);
- csr32w(ctlr, Mlc, SRAM512|csr);
- csr = csr32r(ctlr, Mc);
- csr32w(ctlr, Mc, SyncSRAM|csr);
- /*
- * Initialise PCI State register.
- * If PCI Write-and-Invalidate is enabled set the max write DMA
- * value to the host cache-line size (32 on Pentium or later).
- */
- csr = csr32r(ctlr, Ps) & (PCI32|PCI66);
- csr |= PCIwcmd|PCIrcmd|PCImrm;
- if(pcicfgr8(ctlr->pcidev, PciPCR) & 0x0010){
- cls = pcicfgr8(ctlr->pcidev, PciCLS) * 4;
- if(cls != 32)
- pcicfgw8(ctlr->pcidev, PciCLS, 32/4);
- csr |= PCIwm32;
- }
- csr32w(ctlr, Ps, csr);
- /*
- * Operating Mode.
- */
- csr32w(ctlr, Om, Fatal|NoJFrag|BswapDMA|WswapBD);
- /*
- * Snarf the MAC address from the serial EEPROM.
- */
- for(i = 0; i < Easize; i++){
- if((ctlr->ea[i] = at24c32r(ctlr, 0x8E+i)) == -1)
- return -1;
- }
- /*
- * Load the firmware.
- */
- ga620lmw(ctlr, tigon2FwTextAddr, tigon2FwText, tigon2FwTextLen);
- ga620lmw(ctlr, tigon2FwRodataAddr, tigon2FwRodata, tigon2FwRodataLen);
- ga620lmw(ctlr, tigon2FwDataAddr, tigon2FwData, tigon2FwDataLen);
- ga620lmw(ctlr, tigon2FwSbssAddr, nil, tigon2FwSbssLen);
- ga620lmw(ctlr, tigon2FwBssAddr, nil, tigon2FwBssLen);
- return 0;
- }
- static void
- ga620pci(void)
- {
- int port;
- Pcidev *p;
- Ctlr *ctlr;
- extern ulong upamalloc(ulong, int, int);
- p = nil;
- while(p = pcimatch(p, 0, 0)){
- if(p->ccru != ((0x02<<8)|0x00))
- continue;
- switch((p->did<<16)|p->vid){
- default:
- continue;
- case (0x620A<<16)|0x1385: /* Netgear GA620 */
- case (0x630A<<16)|0x1385: /* Netgear GA620T */
- case (0x0001<<16)|0x12AE: /* Alteon Acenic fiber
- * and DEC DEGPA-SA */
- case (0x0002<<16)|0x12AE: /* Alteon Acenic copper */
- case (0x0009<<16)|0x10A9: /* SGI Acenic */
- break;
- }
- port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0);
- if(port == 0){
- print("ga620: can't map %8.8luX\n", p->mem[0].bar);
- continue;
- }
- ctlr = ialloc(sizeof(Ctlr), 0);
- ctlr->port = port;
- ctlr->pcidev = p;
- ctlr->id = (p->did<<16)|p->vid;
- ctlr->nic = KADDR(ctlr->port);
- if(ga620reset(ctlr)){
- //free(ctlr);
- continue;
- }
- if(ctlrhead != nil)
- ctlrtail->next = ctlr;
- else
- ctlrhead = ctlr;
- ctlrtail = ctlr;
- }
- }
- int
- etherga620reset(Ether* edev)
- {
- Ctlr *ctlr;
- uchar ea[Easize];
- if(ctlrhead == nil)
- ga620pci();
- /*
- * Any adapter matches if no edev->port is supplied,
- * otherwise the ports must match.
- */
- for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
- 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->pcidev->intl;
- edev->tbdf = ctlr->pcidev->tbdf;
- edev->mbps = 1000;
- /*
- * Check if the adapter's station address is to be overridden.
- * If not, read it from the EEPROM and set in ether->ea prior to
- * loading the station address in the hardware.
- */
- memset(ea, 0, Easize);
- if(memcmp(ea, edev->ea, Easize) == 0)
- memmove(edev->ea, ctlr->ea, Easize);
- ga620init(edev);
- /*
- * Linkage to the generic ethernet driver.
- */
- edev->attach = ga620attach;
- edev->transmit = ga620transmit;
- edev->interrupt = ga620interrupt;
- return 0;
- }
|