summaryrefslogtreecommitdiff
path: root/os/pc/etherga620.c
diff options
context:
space:
mode:
authorKonstantin Kirik (snegovick) <snegovick@uprojects.org>2025-12-28 12:27:31 +0300
committerKonstantin Kirik (snegovick) <snegovick@uprojects.org>2025-12-28 12:27:31 +0300
commit78ee7d5717807e6ac779293d0d3c78341de6130a (patch)
treea43e3b0f61318ac45e6d907c7cc5bad2c6d7f497 /os/pc/etherga620.c
parentbdaf46cf45bbb59261da245d548a179d95a42768 (diff)
Move existing boards into subdits split per arch
Diffstat (limited to 'os/pc/etherga620.c')
-rw-r--r--os/pc/etherga620.c1275
1 files changed, 0 insertions, 1275 deletions
diff --git a/os/pc/etherga620.c b/os/pc/etherga620.c
deleted file mode 100644
index 3d555be0..00000000
--- a/os/pc/etherga620.c
+++ /dev/null
@@ -1,1275 +0,0 @@
-/*
- * 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 "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"
-
-#define malign(n) xspanalloc((n), 32, 0)
-
-#include "etherif.h"
-#include "etherga620fw.h"
-
-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 */
-
- /*
- * legal values are 0x3800 iff Nsr is 128, 0x3000 iff Nsr is 256,
- * or 0x2000 iff Nsr is 512.
- */
- Sr = 0x2000, /* 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;
-
-/*
- * these sizes are all fixed in the card,
- * except for Nsr, which has only 3 valid sizes.
- */
-enum { /* Host/NIC Interface ring sizes */
- Ner = 256, /* event ring */
- Ncr = 64, /* command ring */
- Nsr = 512, /* send ring: 128, 256 or 512 */
- Nrsr = 512, /* receive standard ring */
- Nrjr = 256, /* receive jumbo ring */
- Nrmr = 1024, /* receive mini ring, optional */
- 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;
-struct Ctlr {
- int port;
- Pcidev* pcidev;
- Ctlr* next;
- int active;
- int id;
-
- uchar ea[Eaddrlen];
-
- int* nic;
- Gib* gib;
-
- Ere* er;
-
- Lock srlock;
- Sbd* sr;
- Block** 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) */
-
- int interrupts; /* statistics */
- int mi;
- uvlong ticks;
-
- int coalupdateonly; /* tuning */
- int hardwarecksum;
- int rct; /* Receive Coalesce Ticks */
- int sct; /* Send Coalesce Ticks */
- int st; /* Stat Ticks */
- int smcbd; /* Send Max. Coalesced BDs */
- int rmcbd; /* Receive Max. Coalesced BDs */
-};
-
-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 long
-ga620ifstat(Ether* edev, void* a, long n, ulong offset)
-{
- char *p;
- Ctlr *ctlr;
- int i, l, r;
-
- ctlr = edev->ctlr;
-
- if(n == 0)
- return 0;
- p = malloc(READSTR);
- l = 0;
- for(i = 0; i < 256; i++){
- if((r = ctlr->gib->statistics[i]) == 0)
- continue;
- l += snprint(p+l, READSTR-l, "%d: %ud\n", i, r);
- }
-
- l += snprint(p+l, READSTR-l, "interrupts: %ud\n", ctlr->interrupts);
- l += snprint(p+l, READSTR-l, "mi: %ud\n", ctlr->mi);
- l += snprint(p+l, READSTR-l, "ticks: %llud\n", ctlr->ticks);
- l += snprint(p+l, READSTR-l, "coalupdateonly: %d\n", ctlr->coalupdateonly);
- l += snprint(p+l, READSTR-l, "hardwarecksum: %d\n", ctlr->hardwarecksum);
- l += snprint(p+l, READSTR-l, "rct: %d\n", ctlr->rct);
- l += snprint(p+l, READSTR-l, "sct: %d\n", ctlr->sct);
- l += snprint(p+l, READSTR-l, "smcbd: %d\n", ctlr->smcbd);
- snprint(p+l, READSTR-l, "rmcbd: %d\n", ctlr->rmcbd);
-
- n = readstr(offset, a, n, p);
- free(p);
-
- return n;
-}
-
-static long
-ga620ctl(Ether* edev, void* buf, long n)
-{
- char *p;
- Cmdbuf *cb;
- Ctlr *ctlr;
- int control, i, r;
-
- ctlr = edev->ctlr;
- if(ctlr == nil)
- error(Enonexist);
- r = 0;
- cb = parsecmd(buf, n);
- if(cb->nf < 2)
- r = -1;
- else if(cistrcmp(cb->f[0], "coalupdateonly") == 0){
- if(cistrcmp(cb->f[1], "off") == 0){
- control = ctlr->gib->srcb.control;
- control &= ~CoalUpdateOnly;
- ctlr->gib->srcb.control = control;
- ctlr->coalupdateonly = 0;
- }
- else if(cistrcmp(cb->f[1], "on") == 0){
- control = ctlr->gib->srcb.control;
- control |= CoalUpdateOnly;
- ctlr->gib->srcb.control = control;
- ctlr->coalupdateonly = 1;
- }
- else
- r = -1;
- }
- else if(cistrcmp(cb->f[0], "hardwarecksum") == 0){
- if(cistrcmp(cb->f[1], "off") == 0){
- control = ctlr->gib->srcb.control;
- control &= ~(TcpUdpCksum|NoPseudoHdrCksum);
- ctlr->gib->srcb.control = control;
-
- control = ctlr->gib->rsrcb.control;
- control &= ~(TcpUdpCksum|NoPseudoHdrCksum);
- ctlr->gib->rsrcb.control = control;
-
- ctlr->hardwarecksum = 0;
- }
- else if(cistrcmp(cb->f[1], "on") == 0){
- control = ctlr->gib->srcb.control;
- control |= (TcpUdpCksum|NoPseudoHdrCksum);
- ctlr->gib->srcb.control = control;
-
- control = ctlr->gib->rsrcb.control;
- control |= (TcpUdpCksum|NoPseudoHdrCksum);
- ctlr->gib->rsrcb.control = control;
-
- ctlr->hardwarecksum = 1;
- }
- else
- r = -1;
- }
- else if(cistrcmp(cb->f[0], "rct") == 0){
- i = strtol(cb->f[1], &p, 0);
- if(i < 0 || p == cb->f[1])
- r = -1;
- else{
- ctlr->rct = i;
- csr32w(ctlr, Rct, ctlr->rct);
- }
- }
- else if(cistrcmp(cb->f[0], "sct") == 0){
- i = strtol(cb->f[1], &p, 0);
- if(i < 0 || p == cb->f[1])
- r = -1;
- else{
- ctlr->sct = i;
- csr32w(ctlr, Sct, ctlr->sct);
- }
- }
- else if(cistrcmp(cb->f[0], "st") == 0){
- i = strtol(cb->f[1], &p, 0);
- if(i < 0 || p == cb->f[1])
- r = -1;
- else{
- ctlr->st = i;
- csr32w(ctlr, St, ctlr->st);
- }
- }
- else if(cistrcmp(cb->f[0], "smcbd") == 0){
- i = strtol(cb->f[1], &p, 0);
- if(i < 0 || p == cb->f[1])
- r = -1;
- else{
- ctlr->smcbd = i;
- csr32w(ctlr, SmcBD, ctlr->smcbd);
- }
- }
- else if(cistrcmp(cb->f[0], "rmcbd") == 0){
- i = strtol(cb->f[1], &p, 0);
- if(i < 0 || p == cb->f[1])
- r = -1;
- else{
- ctlr->rmcbd = i;
- csr32w(ctlr, RmcBD, ctlr->rmcbd);
- }
- }
- else
- r = -1;
-
- free(cb);
- if(r == 0)
- return n;
- return r;
-}
-
-static int
-_ga620transmit(Ether* edev)
-{
- Sbd *sbd;
- Block *bp;
- Ctlr *ctlr;
- int sci, spi, work;
-
- /*
- * 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.
- */
- work = 0;
- for(sci = ctlr->sci[2]; sci != ctlr->sci[0]; sci = NEXT(sci, Nsr)){
- if(ctlr->srb[sci] == nil)
- continue;
- freeb(ctlr->srb[sci]);
- ctlr->srb[sci] = nil;
- work++;
- }
- ctlr->sci[2] = sci;
-
- sci = PREV(sci, Nsr);
- for(spi = csr32r(ctlr, Spi); spi != sci; spi = NEXT(spi, Nsr)){
- if((bp = qget(edev->oq)) == nil)
- break;
-
- sbd = &ctlr->sr[spi];
- sethost64(&sbd->addr, bp->rp);
- sbd->lenflags = BLEN(bp)<<16 | Fend;
-
- ctlr->srb[spi] = bp;
- work++;
- }
- csr32w(ctlr, Spi, spi);
-
- iunlock(&ctlr->srlock);
-
- return work;
-}
-
-static void
-ga620transmit(Ether* edev)
-{
- _ga620transmit(edev);
-}
-
-static void
-ga620replenish(Ctlr* ctlr)
-{
- Rbd *rbd;
- int rspi;
- Block *bp;
-
- rspi = csr32r(ctlr, Rspi);
- while(ctlr->nrsr < NrsrHI){
- if((bp = iallocb(ETHERMAXTU+4)) == nil)
- break;
- rbd = &ctlr->rsr[rspi];
- sethost64(&rbd->addr, bp->rp);
- 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(Ether *edev, int eci, int epi)
-{
- unsigned event, code;
- Ctlr *ctlr;
-
- ctlr = edev->ctlr;
- while(eci != epi){
- event = ctlr->er[eci].event;
- code = (event >> 12) & ((1<<12)-1);
- switch(event>>24){
- case 0x01: /* firmware operational */
- /* host stack (us) is up. 3rd arg of 2 means down. */
- ga620command(ctlr, 0x01, 0x01, 0x00);
- /*
- * link negotiation: any speed is okay.
- * 3rd arg of 1 selects gigabit only; 2 10/100 only.
- */
- ga620command(ctlr, 0x0B, 0x00, 0x00);
- print("#l%d: ga620: port %8.8uX: firmware is up\n",
- edev->ctlrno, ctlr->port);
- break;
- case 0x04: /* statistics updated */
- break;
- case 0x06: /* link state changed */
- switch (code) {
- case 1:
- edev->mbps = 1000;
- break;
- case 2:
- print("#l%d: link down\n", edev->ctlrno);
- break;
- case 3:
- edev->mbps = 100; /* it's 10 or 100 */
- break;
- }
- if (code != 2)
- print("#l%d: %dMbps link up\n",
- edev->ctlrno, edev->mbps);
- break;
- case 0x07: /* event error */
- default:
- print("#l%d: ga620: er[%d] = %8.8uX\n", edev->ctlrno,
- eci, event);
- break;
- }
- eci = NEXT(eci, Ner);
- }
- csr32w(ctlr, Eci, eci);
-}
-
-static void
-ga620receive(Ether* edev)
-{
- int len;
- Rbd *rbd;
- Block *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->wp = bp->rp+len;
- etheriq(edev, bp, 1);
- }
- else
- freeb(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, ie, work;
- Ctlr *ctlr;
- Ether *edev;
- uvlong tsc0, tsc1;
-
- edev = arg;
- ctlr = edev->ctlr;
-
- if(!(csr32r(ctlr, Mhc) & Is))
- return;
- cycles(&tsc0);
-
- ctlr->interrupts++;
- csr32w(ctlr, Hi, 1);
-
- ie = 0;
- work = 0;
- while(ie < 2){
- if(ctlr->rrrci != ctlr->rrrpi[0]){
- ga620receive(edev);
- work = 1;
- }
-
- if(_ga620transmit(edev) != 0)
- work = 1;
-
- csr = csr32r(ctlr, Eci);
- if(csr != ctlr->epi[0]){
- ga620event(edev, csr, ctlr->epi[0]);
- work = 1;
- }
-
- if(ctlr->nrsr <= NrsrLO)
- ga620replenish(ctlr);
- if(work == 0){
- if(ie == 0)
- csr32w(ctlr, Hi, 0);
- ie++;
- }
- work = 0;
- }
-
- cycles(&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 = malloc(sizeof(Gib));
- 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 = (uchar*)ctlr->nic+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(ctlr->hardwarecksum)
- flags = TcpUdpCksum|NoPseudoHdrCksum|HostRing;
- else
- flags = HostRing;
- if(ctlr->coalupdateonly)
- flags |= CoalUpdateOnly;
- ctlr->gib->srcb.control = Nsr<<16 | flags;
- sethost64(&ctlr->gib->scp, ctlr->sci);
- csr32w(ctlr, Spi, 0);
- ctlr->srb = malloc(sizeof(Block*)*Nsr);
-
- /*
- * Receive Standard Ring.
- */
- ctlr->rsr = malign(sizeof(Rbd)*Nrsr);
- sethost64(&ctlr->gib->rsrcb.addr, ctlr->rsr);
- if(ctlr->hardwarecksum)
- 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.
- */
- ctlr->rct = 1/*100*/;
- csr32w(ctlr, Rct, ctlr->rct);
- ctlr->sct = 0;
- csr32w(ctlr, Sct, ctlr->sct);
- ctlr->st = 1000000;
- csr32w(ctlr, St, ctlr->st);
- ctlr->smcbd = Nsr/4;
- csr32w(ctlr, SmcBD, ctlr->smcbd);
- ctlr->rmcbd = 4/*6*/;
- csr32w(ctlr, RmcBD, ctlr->rmcbd);
-
- /*
- * 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 void
-ga620shutdown(Ether* ether)
-{
-print("ga620shutdown\n");
- ga620detach(ether->ctlr);
-}
-
-static int
-ga620reset(Ctlr* ctlr)
-{
- int cls, csr, i, r;
-
- 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(ctlr->pcidev->pcr & 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 < Eaddrlen; i++){
- if((r = at24c32r(ctlr, 0x8E+i)) == -1)
- return -1;
- ctlr->ea[i] = r;
- }
-
- /*
- * 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)
-{
- void *mem;
- Pcidev *p;
- Ctlr *ctlr;
-
- p = nil;
- while(p = pcimatch(p, 0, 0)){
- if(p->ccrb != 0x02 || p->ccru != 0)
- continue;
-
- switch(p->did<<16 | p->vid){
- default:
- continue;
- case 0x620A<<16 | 0x1385: /* Netgear GA620 fiber */
- case 0x630A<<16 | 0x1385: /* Netgear GA620T copper */
- 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;
- }
-
- mem = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
- if(mem == 0){
- print("ga620: can't map %8.8luX\n", p->mem[0].bar);
- continue;
- }
-
- ctlr = malloc(sizeof(Ctlr));
- ctlr->port = p->mem[0].bar & ~0x0F;
- ctlr->pcidev = p;
- ctlr->id = p->did<<16 | p->vid;
-
- ctlr->nic = mem;
- if(ga620reset(ctlr)){
- free(ctlr);
- continue;
- }
-
- if(ctlrhead != nil)
- ctlrtail->next = ctlr;
- else
- ctlrhead = ctlr;
- ctlrtail = ctlr;
- }
-}
-
-static void
-ga620promiscuous(void *arg, int on)
-{
- Ether *ether = arg;
-
- /* 3rd arg: 1 enables, 2 disables */
- ga620command(ether->ctlr, 0xa, (on? 1: 2), 0);
-}
-
-static void
-ga620multicast(void *arg, uchar *addr, int on)
-{
- Ether *ether = arg;
-
- USED(addr);
- /* 3rd arg: 1 enables, 2 disables */
- ga620command(ether->ctlr, 0xe, (on? 1: 2), 0);
-}
-
-static int
-ga620pnp(Ether* edev)
-{
- Ctlr *ctlr;
- uchar ea[Eaddrlen];
-
- 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; /* placeholder */
-
- /*
- * 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, Eaddrlen);
- if(memcmp(ea, edev->ea, Eaddrlen) == 0)
- memmove(edev->ea, ctlr->ea, Eaddrlen);
-
- ga620init(edev);
-
- /*
- * Linkage to the generic ethernet driver.
- */
- edev->attach = ga620attach;
- edev->transmit = ga620transmit;
- edev->interrupt = ga620interrupt;
- edev->ifstat = ga620ifstat;
- edev->ctl = ga620ctl;
-
- edev->arg = edev;
- edev->promiscuous = ga620promiscuous;
- edev->multicast = ga620multicast;
- edev->shutdown = ga620shutdown;
-
- return 0;
-}
-
-void
-etherga620link(void)
-{
- addethercard("GA620", ga620pnp);
-}