/* * this driver is too bloated with firmware to include in 9pxeload, * which must fit in 512K. it's also for a very old card. * * bootstrap driver for * 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 "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.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 = 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; /* * 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 = 128, /* 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 voidsethost64(Host64* host64, void* addr){ uvlong uvl; uvl = PCIWADDR(addr); host64->hi = uvl>>32; host64->lo = uvl & 0xFFFFFFFFL;} static voidga620command(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 voidga620attach(Ether* ){} static voidwaitforlink(Ether *edev){ int i; if (edev->mbps == 0) { print("#l%d: ga620: waiting for link", edev->ctlrno); /* usually takes about 10 seconds */ for (i = 0; i < 20 && edev->mbps == 0; i++) { print("."); delay(1000); } print("\n"); if (i == 20 && edev->mbps == 0) edev->mbps = 1; /* buggered */ }} static voidtoringbuf(Ether *ether, Block *bp){ RingBuf *rb = ðer->rb[ether->ri]; if (rb->owner == Interface) { rb->len = BLEN(bp); memmove(rb->pkt, bp->rp, rb->len); rb->owner = Host; ether->ri = NEXT(ether->ri, ether->nrb); } /* else no one is expecting packets from the network */} static Block *fromringbuf(Ether *ether){ RingBuf *tb = ðer->tb[ether->ti]; Block *bp = allocb(tb->len); if (bp == nil) panic("fromringbuf: nil allocb return"); if (bp->wp == nil) panic("fromringbuf: nil bp->wb"); memmove(bp->wp, tb->pkt, tb->len); memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); bp->wp += tb->len; return bp;} static int_ga620transmit(Ether* edev){ Sbd *sbd; Block *bp; Ctlr *ctlr; RingBuf *tb; 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; waitforlink(edev); 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); tb = &edev->tb[edev->ti]; for(spi = csr32r(ctlr, Spi); spi != sci && tb->owner == Interface; spi = NEXT(spi, Nsr)){ bp = fromringbuf(edev); sbd = &ctlr->sr[spi]; sethost64(&sbd->addr, bp->rp); sbd->lenflags = BLEN(bp)<<16 |Fend; ctlr->srb[spi] = bp; work++; tb->owner = Host; edev->ti = NEXT(edev->ti, edev->ntb); tb = &edev->tb[edev->ti]; } csr32w(ctlr, Spi, spi); iunlock(&ctlr->srlock); return work;} static voidga620transmit(Ether* edev){ _ga620transmit(edev);} static voidga620replenish(Ctlr* ctlr){ Rbd *rbd; int rspi; Block *bp; rspi = csr32r(ctlr, Rspi); while(ctlr->nrsr < NrsrHI){ if((bp = allocb(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 voidga620event(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:Lines 1–500 of 1150. Load more
/* * this driver is too bloated with firmware to include in 9pxeload, * which must fit in 512K. it's also for a very old card. * * bootstrap driver for * 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 "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.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 = 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; /* * 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 = 128, /* 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* ) { } static void waitforlink(Ether *edev) { int i; if (edev->mbps == 0) { print("#l%d: ga620: waiting for link", edev->ctlrno); /* usually takes about 10 seconds */ for (i = 0; i < 20 && edev->mbps == 0; i++) { print("."); delay(1000); } print("\n"); if (i == 20 && edev->mbps == 0) edev->mbps = 1; /* buggered */ } } static void toringbuf(Ether *ether, Block *bp) { RingBuf *rb = ðer->rb[ether->ri]; if (rb->owner == Interface) { rb->len = BLEN(bp); memmove(rb->pkt, bp->rp, rb->len); rb->owner = Host; ether->ri = NEXT(ether->ri, ether->nrb); } /* else no one is expecting packets from the network */ } static Block * fromringbuf(Ether *ether) { RingBuf *tb = ðer->tb[ether->ti]; Block *bp = allocb(tb->len); if (bp == nil) panic("fromringbuf: nil allocb return"); if (bp->wp == nil) panic("fromringbuf: nil bp->wb"); memmove(bp->wp, tb->pkt, tb->len); memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); bp->wp += tb->len; return bp; } static int _ga620transmit(Ether* edev) { Sbd *sbd; Block *bp; Ctlr *ctlr; RingBuf *tb; 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; waitforlink(edev); 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); tb = &edev->tb[edev->ti]; for(spi = csr32r(ctlr, Spi); spi != sci && tb->owner == Interface; spi = NEXT(spi, Nsr)){ bp = fromringbuf(edev); sbd = &ctlr->sr[spi]; sethost64(&sbd->addr, bp->rp); sbd->lenflags = BLEN(bp)<<16 |Fend; ctlr->srb[spi] = bp; work++; tb->owner = Host; edev->ti = NEXT(edev->ti, edev->ntb); tb = &edev->tb[edev->ti]; } 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 = allocb(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: