1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219 |
- /*
- * VIA VT6105M Fast Ethernet Controller (Rhine III).
- * To do:
- * cache-line size alignments - done
- * reduce tx interrupts - done
- * reorganise initialisation/shutdown/reset
- * adjust Tx FIFO threshold on underflow - untested
- * why does the link status never cause an interrupt?
- * use the lproc as a periodic timer for stalls, etc.
- * checksum offload - done
- * take non-HW stuff out of descriptor for 64-bit
- * cleanliness
- * why does the receive buffer alloc have a +3?
- */
- #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 "ethermii.h"
- enum {
- Par0 = 0x00, /* Ethernet Address */
- Rcr = 0x06, /* Receive Configuration */
- Tcr = 0x07, /* Transmit Configuration */
- Cr = 0x08, /* Control */
- Tqw = 0x0A, /* Transmit Queue Wake */
- Isr = 0x0C, /* Interrupt Status */
- Imr = 0x0E, /* Interrupt Mask */
- Mcfilt0 = 0x10, /* Multicast Filter 0 */
- Mcfilt1 = 0x14, /* Multicast Filter 1 */
- Rxdaddr = 0x18, /* Current Rd Address */
- Txdaddr = 0x1C, /* Current Td Address */
- Phyadr = 0x6C, /* Phy Address */
- Miisr = 0x6D, /* MII Status */
- Bcr0 = 0x6E, /* Bus Control */
- Bcr1 = 0x6F,
- Miicr = 0x70, /* MII Control */
- Miiadr = 0x71, /* MII Address */
- Miidata = 0x72, /* MII Data */
- Eecsr = 0x74, /* EEPROM Control and Status */
- CfgA = 0x78, /* Chip Configuration A */
- CfgB = 0x79,
- CfgC = 0x7A,
- CfgD = 0x7B,
- Cr0 = 0x80, /* Miscellaneous Control */
- Cr1 = 0x81,
- Pmcc = 0x82, /* Power Mgmt Capability Control */
- Stickhw = 0x83, /* Sticky Hardware Control */
- Misr = 0x84, /* MII Interrupt Control */
- Mimr = 0x85, /* MII Interrupt Mask */
- Wolcrclr = 0xA4,
- Wolcgclr = 0xA7,
- Pwrcsrclr = 0xAC,
- };
- enum { /* Rcr */
- Sep = 0x01, /* Accept Error Packets */
- Ar = 0x02, /* Accept Small Packets */
- Am = 0x04, /* Accept Multicast */
- Ab = 0x08, /* Accept Broadcast */
- Prom = 0x10, /* Accept Physical Address Packets */
- RrftMASK = 0xE0, /* Receive FIFO Threshold */
- RrftSHIFT = 5,
- Rrft64 = 0<<RrftSHIFT,
- Rrft32 = 1<<RrftSHIFT,
- Rrft128 = 2<<RrftSHIFT,
- Rrft256 = 3<<RrftSHIFT,
- Rrft512 = 4<<RrftSHIFT,
- Rrft768 = 5<<RrftSHIFT,
- Rrft1024 = 6<<RrftSHIFT,
- RrftSAF = 7<<RrftSHIFT,
- };
- enum { /* Tcr */
- Lb0 = 0x02, /* Loopback Mode */
- Lb1 = 0x04,
- Ofset = 0x08, /* Select Back-off Priority */
- RtsfMASK = 0xE0, /* Transmit FIFO Threshold */
- RtsfSHIFT = 5,
- Rtsf128 = 0<<RtsfSHIFT,
- Rtsf256 = 1<<RtsfSHIFT,
- Rtsf512 = 2<<RtsfSHIFT,
- Rtsf1024 = 3<<RtsfSHIFT,
- RtsfSAF = 7<<RtsfSHIFT,
- };
- enum { /* Cr */
- Init = 0x0001, /* INIT Process Begin */
- Strt = 0x0002, /* Start NIC */
- Stop = 0x0004, /* Stop NIC */
- Rxon = 0x0008, /* Turn on Receive Process */
- Txon = 0x0010, /* Turn on Transmit Process */
- Tdmd = 0x0020, /* Transmit Poll Demand */
- Rdmd = 0x0040, /* Receive Poll Demand */
- Eren = 0x0100, /* Early Receive Enable */
- Fdx = 0x0400, /* Set MAC to Full Duplex */
- Dpoll = 0x0800, /* Disable Td/Rd Auto Polling */
- Tdmd1 = 0x2000, /* Transmit Poll Demand 1 */
- Rdmd1 = 0x4000, /* Receive Poll Demand 1 */
- Sfrst = 0x8000, /* Software Reset */
- };
- enum { /* Isr/Imr */
- Prx = 0x0001, /* Packet Received OK */
- Ptx = 0x0002, /* Packet Transmitted OK */
- Rxe = 0x0004, /* Receive Error */
- Txe = 0x0008, /* Transmit Error */
- Tu = 0x0010, /* Transmit Buffer Underflow */
- Ru = 0x0020, /* Receive Buffer Link Error */
- Be = 0x0040, /* PCI Bus Error */
- Cnt = 0x0080, /* Counter Overflow */
- Eri = 0x0100, /* Early Receive Interrupt */
- Udfi = 0x0200, /* Tx FIFO Underflow */
- Ovfi = 0x0400, /* Receive FIFO Overflow */
- Pktrace = 0x0800, /* Hmmm... */
- Norbf = 0x1000, /* No Receive Buffers */
- Abti = 0x2000, /* Transmission Abort */
- Srci = 0x4000, /* Port State Change */
- Geni = 0x8000, /* General Purpose Interrupt */
- };
- enum { /* Phyadr */
- PhyadMASK = 0x1F, /* PHY Address */
- PhyadSHIFT = 0,
- Mfdc = 0x20, /* Accelerate MDC Speed */
- Mpo0 = 0x40, /* MII Polling Timer Interval */
- Mpo1 = 0x80,
- };
- enum { /* Bcr0 */
- DmaMASK = 0x07, /* DMA Length */
- DmaSHIFT = 0,
- Dma32 = 0<<DmaSHIFT,
- Dma64 = 1<<DmaSHIFT,
- Dma128 = 2<<DmaSHIFT,
- Dma256 = 3<<DmaSHIFT,
- Dma512 = 4<<DmaSHIFT,
- Dma1024 = 5<<DmaSHIFT,
- DmaSAF = 7<<DmaSHIFT,
- CrftMASK = 0x38, /* Rx FIFO Threshold */
- CrftSHIFT = 3,
- Crft64 = 1<<CrftSHIFT,
- Crft128 = 2<<CrftSHIFT,
- Crft256 = 3<<CrftSHIFT,
- Crft512 = 4<<CrftSHIFT,
- Crft1024 = 5<<CrftSHIFT,
- CrftSAF = 7<<CrftSHIFT,
- Extled = 0x40, /* Extra LED Support Control */
- Med2 = 0x80, /* Medium Select Control */
- };
- enum { /* Bcr1 */
- PotMASK = 0x07, /* Polling Timer Interval */
- PotSHIFT = 0,
- CtftMASK = 0x38, /* Tx FIFO Threshold */
- CtftSHIFT = 3,
- Ctft64 = 1<<CtftSHIFT,
- Ctft128 = 2<<CtftSHIFT,
- Ctft256 = 3<<CtftSHIFT,
- Ctft512 = 4<<CtftSHIFT,
- Ctft1024 = 5<<CtftSHIFT,
- CtftSAF = 7<<CtftSHIFT,
- };
- enum { /* Miicr */
- Mdc = 0x01, /* Clock */
- Mdi = 0x02, /* Data In */
- Mdo = 0x04, /* Data Out */
- Mout = 0x08, /* Output Enable */
- Mdpm = 0x10, /* Direct Program Mode Enable */
- Wcmd = 0x20, /* Write Enable */
- Rcmd = 0x40, /* Read Enable */
- Mauto = 0x80, /* Auto Polling Enable */
- };
- enum { /* Miiadr */
- MadMASK = 0x1F, /* MII Port Address */
- MadSHIFT = 0,
- Mdone = 0x20, /* Accelerate MDC Speed */
- Msrcen = 0x40, /* MII Polling Timer Interval */
- Midle = 0x80,
- };
- enum { /* Eecsr */
- Edo = 0x01, /* Data Out */
- Edi = 0x02, /* Data In */
- Eck = 0x04, /* Clock */
- Ecs = 0x08, /* Chip Select */
- Dpm = 0x10, /* Direct Program Mode Enable */
- Autold = 0x20, /* Dynamic Reload */
- Embp = 0x40, /* Embedded Program Enable */
- Eepr = 0x80, /* Programmed */
- };
- /*
- * Ring descriptor. The space allocated for each
- * of these will be rounded up to a cache-line boundary.
- * The first 4 elements are known to the hardware.
- */
- typedef struct Ds Ds;
- typedef struct Ds {
- u32int status;
- u32int control;
- u32int addr;
- u32int branch;
- Block* bp;
- Ds* next;
- Ds* prev;
- } Ds;
- enum { /* Rx Ds status */
- Rerr = 0x00000001, /* Buff|Rxserr|Fov|Fae|Crc */
- Crc = 0x00000002, /* CRC Error */
- Fae = 0x00000004, /* Frame Alignment Error */
- Fov = 0x00000008, /* FIFO Overflow */
- Long = 0x00000010, /* A Long Packet */
- Runt = 0x00000020, /* A Runt Packet */
- Rxserr = 0x00000040, /* System Error */
- Buff = 0x00000080, /* Buffer Underflow Error */
- Rxedp = 0x00000100, /* End of Packet Buffer */
- Rxstp = 0x00000200, /* Packet Start */
- Chn = 0x00000400, /* Chain Buffer */
- Phy = 0x00000800, /* Physical Address Packet */
- Bar = 0x00001000, /* Broadcast Packet */
- Mar = 0x00002000, /* Multicast Packet */
- Rxok = 0x00008000, /* Packet Received OK */
- LengthMASK = 0x07FF0000, /* Received Packet Length */
- LengthSHIFT = 16,
- Own = 0x80000000, /* Descriptor Owned by NIC */
- };
- enum { /* Rx Ds control */
- RbsizeMASK = 0x000007FF, /* Receive Buffer Size */
- RbsizeSHIFT = 0,
- Tag = 0x00010000, /* Receive a Tagged Packet */
- Udpkt = 0x00020000, /* Receive a UDP Packet */
- Tcpkt = 0x00040000, /* Receive a TCP Packet */
- Ipkt = 0x00080000, /* Receive an IP Packet */
- Tuok = 0x00100000, /* TCP/UDP Checksum OK */
- Ipok = 0x00200000, /* IP Checksum OK */
- Snaptag = 0x00400000, /* Snap Packet + 802.1q Tag */
- Rxlerr = 0x00800000, /* Receive Length Check Error */
- IpktMASK = 0xff000000, /* Interesting Packet */
- IpktSHIFT = 24,
- };
- enum { /* Tx Ds status */
- NcrMASK = 0x0000000F, /* Collision Retry Count */
- NcrSHIFT = 0,
- Cols = 0x00000010, /* Experienced Collisions */
- Cdh = 0x00000080, /* CD Heartbeat */
- Abt = 0x00000100, /* Aborted after Excessive Collisions */
- Owc = 0x00000200, /* Out of Window Collision */
- Crs = 0x00000400, /* Carrier Sense Lost */
- Udf = 0x00000800, /* FIFO Underflow */
- Tbuff = 0x00001000, /* Invalid Td */
- Txserr = 0x00002000, /* System Error */
- Terr = 0x00008000, /* Excessive Collisions */
- };
- enum { /* Tx Ds control */
- TbsMASK = 0x000007FF, /* Tx Buffer Size */
- TbsSHIFT = 0,
- Chain = 0x00008000, /* Chain Buffer */
- Crcdisable = 0x00010000, /* Disable CRC generation */
- Stp = 0x00200000, /* Start of Packet */
- Edp = 0x00400000, /* End of Packet */
- Ic = 0x00800000, /* Interrupt Control */
- };
- enum { /* Tx Ds branch */
- Tdctl = 0x00000001, /* No Interrupt Generated */
- };
- enum {
- Nrd = 196,
- Ntd = 128,
- Crcsz = 4,
- Bslop = 48,
- Rdbsz = ETHERMAXTU+Crcsz+Bslop,
- Nrxstats = 8,
- Ntxstats = 9,
- Txcopy = 128,
- };
- typedef struct Ctlr Ctlr;
- typedef struct Ctlr {
- int port;
- Pcidev* pcidev;
- Ctlr* next;
- int active;
- int id;
- uchar par[Eaddrlen];
- QLock alock; /* attach */
- void* alloc; /* descriptors, etc. */
- int cls; /* alignment */
- int nrd;
- int ntd;
- Ds* rd;
- Ds* rdh;
- Lock tlock;
- Ds* td;
- Ds* tdh;
- Ds* tdt;
- int tdused;
- Lock clock; /* */
- int cr;
- int imr;
- int tft; /* Tx threshold */
- Mii* mii;
- Rendez lrendez;
- int lwakeup;
- uint rxstats[Nrxstats]; /* statistics */
- uint txstats[Ntxstats];
- ulong totalt;
- uint intr;
- uint lintr;
- uint lsleep;
- uint rintr;
- uint tintr;
- uint txdw;
- int tdumax;
- uint abt;
- uint tbuff;
- uint udf;
- uint abti;
- uint udfi;
- uint tu;
- uint tuok;
- uint ipok;
- } Ctlr;
- static Ctlr* vt6105Mctlrhead;
- static Ctlr* vt6105Mctlrtail;
- #define csr8r(c, r) (inb((c)->port+(r)))
- #define csr16r(c, r) (ins((c)->port+(r)))
- #define csr32r(c, r) (inl((c)->port+(r)))
- #define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
- #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
- #define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
- static Lock vt6105Mrblock; /* receive Block freelist */
- static Block* vt6105Mrbpool;
- static uint vt6105Mrbpoolsz;
- typedef struct Regs Regs;
- typedef struct Regs {
- char* name;
- int offset;
- int size;
- } Regs;
- static Regs regs[] = {
- // "Par0", Par0, 1,
- // "Par1", Par0+1, 1,
- // "Par2", Par0+2, 1,
- // "Par3", Par0+3, 1,
- // "Par4", Par0+4, 1,
- // "Par5", Par0+5, 1,
- "Rcr", Rcr, 1,
- "Tcr", Tcr, 1,
- "Cr0", Cr, 1,
- "Cr1", Cr+1, 1,
- "Isr0", Isr, 1,
- "Isr1", Isr+1, 1,
- "Imr0", Imr, 1,
- "Imr1", Imr+1, 1,
- // "Mcfilt0", Mcfilt0,4,
- // "Mcfilt1", Mcfilt1,4,
- // "Rxdaddr", Rxdaddr,4,
- // "Txdaddr", Txdaddr,4,
- "Phyadr", Phyadr, 1,
- "Miisr", Miisr, 1,
- "Bcr0", Bcr0, 1,
- "Bcr1", Bcr1, 1,
- "Miicr", Miicr, 1,
- "Miiadr", Miiadr, 1,
- // "Miidata", Miidata,2,
- "Eecsr", Eecsr, 1,
- "CfgA", CfgA, 1,
- "CfgB", CfgB, 1,
- "CfgC", CfgC, 1,
- "CfgD", CfgD, 1,
- "Cr0", Cr0, 1,
- "Cr1", Cr1, 1,
- "Pmcc", Pmcc, 1,
- "Stickhw", Stickhw,1,
- "Misr", Misr, 1,
- "Mimr", Mimr, 1,
- nil,
- };
- static char* rxstats[Nrxstats] = {
- "Receiver Error",
- "CRC Error",
- "Frame Alignment Error",
- "FIFO Overflow",
- "Long Packet",
- "Runt Packet",
- "System Error",
- "Buffer Underflow Error",
- };
- static char* txstats[Ntxstats] = {
- "Aborted after Excessive Collisions",
- "Out of Window Collision Seen",
- "Carrier Sense Lost",
- "FIFO Underflow",
- "Invalid Td",
- "System Error",
- nil,
- "Excessive Collisions",
- };
- static long
- vt6105Mifstat(Ether* edev, void* a, long n, ulong offset)
- {
- int i, r;
- Ctlr *ctlr;
- char *alloc, *e, *p;
- ctlr = edev->ctlr;
- alloc = malloc(READSTR);
- p = alloc;
- e = p + READSTR;
- for(i = 0; i < Nrxstats; i++){
- p = seprint(p, e, "%s: %ud\n", rxstats[i], ctlr->rxstats[i]);
- }
- for(i = 0; i < Ntxstats; i++){
- if(txstats[i] == nil)
- continue;
- p = seprint(p, e, "%s: %ud\n", txstats[i], ctlr->txstats[i]);
- }
- p = seprint(p, e, "cls: %ud\n", ctlr->cls);
- p = seprint(p, e, "intr: %ud\n", ctlr->intr);
- p = seprint(p, e, "lintr: %ud\n", ctlr->lintr);
- p = seprint(p, e, "lsleep: %ud\n", ctlr->lsleep);
- p = seprint(p, e, "rintr: %ud\n", ctlr->rintr);
- p = seprint(p, e, "tintr: %ud\n", ctlr->tintr);
- p = seprint(p, e, "txdw: %ud\n", ctlr->txdw);
- p = seprint(p, e, "tdumax: %ud\n", ctlr->tdumax);
- p = seprint(p, e, "tft: %ud\n", ctlr->tft);
- p = seprint(p, e, "abt: %ud\n", ctlr->abt);
- p = seprint(p, e, "tbuff: %ud\n", ctlr->tbuff);
- p = seprint(p, e, "udf: %ud\n", ctlr->udf);
- p = seprint(p, e, "abti: %ud\n", ctlr->abti);
- p = seprint(p, e, "udfi: %ud\n", ctlr->udfi);
- p = seprint(p, e, "tu: %ud\n", ctlr->tu);
- p = seprint(p, e, "tuok: %ud\n", ctlr->tuok);
- p = seprint(p, e, "ipok: %ud\n", ctlr->ipok);
- p = seprint(p, e, "rbpoolsz: %ud\n", vt6105Mrbpoolsz);
- p = seprint(p, e, "totalt: %uld\n", ctlr->totalt);
- for(i = 0; regs[i].name != nil; i++){
- p = seprint(p, e, "%s: %2.2x\n",
- regs[i].name, csr8r(ctlr, regs[i].offset));
- }
- if(ctlr->mii != nil && ctlr->mii->curphy != nil){
- p = seprint(p, e, "phy: ");
- for(i = 0; i < NMiiPhyr; i++){
- if(i && ((i & 0x07) == 0))
- p = seprint(p, e, "\n ");
- r = miimir(ctlr->mii, i);
- p = seprint(p, e, " %4.4uX", r);
- }
- seprint(p, e, "\n");
- }
- n = readstr(offset, a, n, alloc);
- free(alloc);
- return n;
- }
- static void
- vt6105Mpromiscuous(void* arg, int on)
- {
- int rcr;
- Ctlr *ctlr;
- Ether *edev;
- edev = arg;
- ctlr = edev->ctlr;
- rcr = csr8r(ctlr, Rcr);
- if(on)
- rcr |= Prom;
- else
- rcr &= ~Prom;
- csr8w(ctlr, Rcr, rcr);
- }
- static void
- vt6105Mmulticast(void* arg, uchar* addr, int on)
- {
- /*
- * For now Am is set in Rcr.
- * Will need to interlock with promiscuous
- * when this gets filled in.
- */
- USED(arg, addr, on);
- }
- static int
- vt6105Mwakeup(void* v)
- {
- return *((int*)v) != 0;
- }
- static void
- vt6105Mimr(Ctlr* ctlr, int imr)
- {
- ilock(&ctlr->clock);
- ctlr->imr |= imr;
- csr16w(ctlr, Imr, ctlr->imr);
- iunlock(&ctlr->clock);
- }
- static void
- vt6105Mlproc(void* arg)
- {
- Ctlr *ctlr;
- Ether *edev;
- MiiPhy *phy;
- edev = arg;
- ctlr = edev->ctlr;
- for(;;){
- if(ctlr->mii == nil || ctlr->mii->curphy == nil)
- break;
- if(miistatus(ctlr->mii) < 0)
- goto enable;
- phy = ctlr->mii->curphy;
- ilock(&ctlr->clock);
- csr16w(ctlr, Cr, ctlr->cr & ~(Txon|Rxon));
- if(phy->fd)
- ctlr->cr |= Fdx;
- else
- ctlr->cr &= ~Fdx;
- csr16w(ctlr, Cr, ctlr->cr);
- iunlock(&ctlr->clock);
- enable:
- ctlr->lwakeup = 0;
- vt6105Mimr(ctlr, Srci);
- ctlr->lsleep++;
- sleep(&ctlr->lrendez, vt6105Mwakeup, &ctlr->lwakeup);
- }
- pexit("vt6105Mlproc: done", 1);
- }
- static void
- vt6105Mrbfree(Block* bp)
- {
- bp->rp = bp->lim - (Rdbsz+3);
- bp->wp = bp->rp;
- ilock(&vt6105Mrblock);
- bp->next = vt6105Mrbpool;
- vt6105Mrbpool = bp;
- iunlock(&vt6105Mrblock);
- }
- static Block*
- vt6105Mrballoc(void)
- {
- Block *bp;
- ilock(&vt6105Mrblock);
- if((bp = vt6105Mrbpool) != nil){
- vt6105Mrbpool = bp->next;
- bp->next = nil;
- _xinc(&bp->ref); /* prevent bp from being freed */
- }
- iunlock(&vt6105Mrblock);
- if(bp == nil && (bp = iallocb(Rdbsz+3)) != nil){
- bp->free = vt6105Mrbfree;
- vt6105Mrbpoolsz++;
- }
- return bp;
- }
- static void
- vt6105Mattach(Ether* edev)
- {
- Ctlr *ctlr;
- // MiiPhy *phy;
- uchar *alloc;
- Ds *ds, *prev;
- int dsz, i, timeo;
- char name[KNAMELEN];
- ctlr = edev->ctlr;
- qlock(&ctlr->alock);
- if(ctlr->alloc != nil){
- qunlock(&ctlr->alock);
- return;
- }
- /*
- * Descriptor space.
- * Receive descriptors should all be aligned on a 4-byte boundary,
- * but try to do cache-line alignment.
- */
- ctlr->nrd = Nrd;
- ctlr->ntd = Ntd;
- dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
- alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz, dsz, 0, 0);
- if(alloc == nil){
- qunlock(&ctlr->alock);
- return;
- }
- ctlr->alloc = alloc;
- ctlr->rd = (Ds*)alloc;
- if(waserror()){
- ds = ctlr->rd;
- for(i = 0; i < ctlr->nrd; i++){
- if(ds->bp != nil){
- freeb(ds->bp);
- ds->bp = nil;
- }
- if((ds = ds->next) == nil)
- break;
- }
- free(ctlr->alloc);
- ctlr->alloc = nil;
- qunlock(&ctlr->alock);
- nexterror();
- }
- prev = (Ds*)(alloc + (ctlr->nrd-1)*dsz);
- for(i = 0; i < ctlr->nrd; i++){
- ds = (Ds*)alloc;
- alloc += dsz;
- ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
- ds->branch = PCIWADDR(alloc);
- ds->bp = vt6105Mrballoc();
- if(ds->bp == nil)
- error("vt6105M: can't allocate receive ring\n");
- ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
- ds->addr = PCIWADDR(ds->bp->rp);
- ds->next = (Ds*)alloc;
- ds->prev = prev;
- prev = ds;
- ds->status = Own;
- }
- prev->branch = 0;
- prev->next = ctlr->rd;
- prev->status = 0;
- ctlr->rdh = ctlr->rd;
- ctlr->td = (Ds*)alloc;
- prev = (Ds*)(alloc + (ctlr->ntd-1)*dsz);
- for(i = 0; i < ctlr->ntd; i++){
- ds = (Ds*)alloc;
- alloc += dsz;
- ds->next = (Ds*)alloc;
- ds->prev = prev;
- prev = ds;
- }
- prev->next = ctlr->td;
- ctlr->tdh = ctlr->tdt = ctlr->td;
- ctlr->tdused = 0;
- ctlr->cr = Dpoll|Rdmd/*|Txon|Rxon*/|Strt;
- /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
- ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
- ilock(&ctlr->clock);
- csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
- csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
- csr16w(ctlr, Isr, ~0);
- csr16w(ctlr, Imr, ctlr->imr);
- csr16w(ctlr, Cr, ctlr->cr);
- iunlock(&ctlr->clock);
- /*
- * Wait for link to be ready.
- */
- for(timeo = 0; timeo < 350; timeo++){
- if(miistatus(ctlr->mii) == 0)
- break;
- tsleep(&up->sleep, return0, 0, 10);
- }
- // phy = ctlr->mii->curphy;
- // print("%s: speed %d fd %d link %d rfc %d tfc %d\n",
- // edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc);
- ilock(&ctlr->clock);
- ctlr->cr |= Txon|Rxon;
- csr16w(ctlr, Cr, ctlr->cr);
- iunlock(&ctlr->clock);
- snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
- kproc(name, vt6105Mlproc, edev);
- qunlock(&ctlr->alock);
- poperror();
- }
- static void
- vt6105Mtransmit(Ether* edev)
- {
- Block *bp;
- Ctlr *ctlr;
- Ds *ds, *next;
- int control, i, size, tdused, timeo;
- long t;
- ctlr = edev->ctlr;
- ilock(&ctlr->tlock);
- t = lcycles();
- /*
- * Free any completed packets
- */
- ds = ctlr->tdh;
- for(tdused = ctlr->tdused; tdused > 0; tdused--){
- /*
- * For some errors the chip will turn the Tx engine
- * off. Wait for that to happen.
- * Could reset and re-init the chip here if it doesn't
- * play fair.
- * To do: adjust Tx FIFO threshold on underflow.
- */
- if(ds->status & (Abt|Tbuff|Udf)){
- if(ds->status & Abt)
- ctlr->abt++;
- if(ds->status & Tbuff)
- ctlr->tbuff++;
- if(ds->status & Udf)
- ctlr->udf++;
- for(timeo = 0; timeo < 1000; timeo++){
- if(!(csr16r(ctlr, Cr) & Txon))
- break;
- microdelay(1);
- }
- ds->status = Own;
- csr32w(ctlr, Txdaddr, PCIWADDR(ds));
- }
- if(ds->status & Own)
- break;
- ds->addr = 0;
- ds->branch = 0;
- if(ds->bp != nil){
- freeb(ds->bp);
- ds->bp = nil;
- }
- for(i = 0; i < Ntxstats-1; i++){
- if(ds->status & (1<<i))
- ctlr->txstats[i]++;
- }
- ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
- ds = ds->next;
- }
- ctlr->tdh = ds;
- /*
- * Try to fill the ring back up.
- */
- ds = ctlr->tdt;
- while(tdused < ctlr->ntd-2){
- if((bp = qget(edev->oq)) == nil)
- break;
- tdused++;
- size = BLEN(bp);
- next = ds->next;
- ds->branch = PCIWADDR(ds->next)|Tdctl;
- ds->bp = bp;
- ds->addr = PCIWADDR(bp->rp);
- control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
- ds->control = control;
- if(tdused >= ctlr->ntd-2){
- ctlr->txdw++;
- ds->branch &= ~Tdctl;
- }
- coherence();
- ds->status = Own;
- ds = next;
- }
- ctlr->tdt = ds;
- ctlr->tdused = tdused;
- if(ctlr->tdused){
- csr16w(ctlr, Cr, Tdmd|ctlr->cr);
- if(tdused > ctlr->tdumax)
- ctlr->tdumax = tdused;
- }
- ctlr->totalt += lcycles() - t;
- iunlock(&ctlr->tlock);
- }
- static void
- vt6105Mreceive(Ether* edev)
- {
- Ds *ds;
- Block *bp;
- Ctlr *ctlr;
- int i, len;
- ctlr = edev->ctlr;
- ds = ctlr->rdh;
- while(!(ds->status & Own) && ds->status != 0){
- /*
- * Can Long packets be received OK?
- * What happens to the Rxok bit?
- */
- if(ds->status & Rerr){
- for(i = 0; i < Nrxstats; i++){
- if(ds->status & (1<<i))
- ctlr->rxstats[i]++;
- }
- }
- else if(bp = vt6105Mrballoc()){
- if(ds->control & Tuok){
- ds->bp->flag |= Btcpck|Budpck;
- ctlr->tuok++;
- }
- if(ds->control & Ipok){
- ds->bp->flag |= Bipck;
- ctlr->ipok++;
- }
- len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
- ds->bp->wp = ds->bp->rp+len;
- etheriq(edev, ds->bp, 1);
- bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
- ds->addr = PCIWADDR(bp->rp);
- ds->bp = bp;
- }
- ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
- ds->branch = 0;
- ds->status = 0;
- ds->prev->branch = PCIWADDR(ds);
- coherence();
- ds->prev->status = Own;
- ds = ds->next;
- }
- ctlr->rdh = ds;
- csr16w(ctlr, Cr, ctlr->cr);
- }
- static void
- vt6105Minterrupt(Ureg*, void* arg)
- {
- Ctlr *ctlr;
- Ether *edev;
- int imr, isr, r, timeo;
- long t;
- edev = arg;
- ctlr = edev->ctlr;
- ilock(&ctlr->clock);
- t = lcycles();
- csr16w(ctlr, Imr, 0);
- imr = ctlr->imr;
- ctlr->intr++;
- for(;;){
- if((isr = csr16r(ctlr, Isr)) != 0)
- csr16w(ctlr, Isr, isr);
- if((isr & ctlr->imr) == 0)
- break;
-
- if(isr & Srci){
- imr &= ~Srci;
- ctlr->lwakeup = isr & Srci;
- wakeup(&ctlr->lrendez);
- isr &= ~Srci;
- ctlr->lintr++;
- }
- if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
- vt6105Mreceive(edev);
- isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
- ctlr->rintr++;
- }
- if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
- if(isr & (Abti|Udfi|Tu)){
- if(isr & Abti)
- ctlr->abti++;
- if(isr & Udfi)
- ctlr->udfi++;
- if(isr & Tu)
- ctlr->tu++;
- for(timeo = 0; timeo < 1000; timeo++){
- if(!(csr16r(ctlr, Cr) & Txon))
- break;
- microdelay(1);
- }
- if((isr & Udfi) && ctlr->tft < CtftSAF){
- ctlr->tft += 1<<CtftSHIFT;
- r = csr8r(ctlr, Bcr1) & ~CtftMASK;
- csr8w(ctlr, Bcr1, r|ctlr->tft);
- }
- }
-
-
- ctlr->totalt += lcycles() - t;
- vt6105Mtransmit(edev);
- t = lcycles();
- isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
- ctlr->tintr++;
- }
- if(isr)
- panic("vt6105M: isr %4.4uX\n", isr);
- }
- ctlr->imr = imr;
- csr16w(ctlr, Imr, ctlr->imr);
-
- ctlr->totalt += lcycles() - t;
- iunlock(&ctlr->clock);
- }
- static int
- vt6105Mmiimicmd(Mii* mii, int pa, int ra, int cmd, int data)
- {
- Ctlr *ctlr;
- int r, timeo;
- ctlr = mii->ctlr;
- csr8w(ctlr, Miicr, 0);
- r = csr8r(ctlr, Phyadr);
- csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
- csr8w(ctlr, Phyadr, pa);
- csr8w(ctlr, Miiadr, ra);
- if(cmd == Wcmd)
- csr16w(ctlr, Miidata, data);
- csr8w(ctlr, Miicr, cmd);
- for(timeo = 0; timeo < 10000; timeo++){
- if(!(csr8r(ctlr, Miicr) & cmd))
- break;
- microdelay(1);
- }
- if(timeo >= 10000)
- return -1;
- if(cmd == Wcmd)
- return 0;
- return csr16r(ctlr, Miidata);
- }
- static int
- vt6105Mmiimir(Mii* mii, int pa, int ra)
- {
- return vt6105Mmiimicmd(mii, pa, ra, Rcmd, 0);
- }
- static int
- vt6105Mmiimiw(Mii* mii, int pa, int ra, int data)
- {
- return vt6105Mmiimicmd(mii, pa, ra, Wcmd, data);
- }
- static int
- vt6105Mdetach(Ctlr* ctlr)
- {
- int revid, timeo;
- /*
- * Reset power management registers.
- */
- revid = pcicfgr8(ctlr->pcidev, PciRID);
- if(revid >= 0x40){
- /* Set power state D0. */
- csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
- /* Disable force PME-enable. */
- csr8w(ctlr, Wolcgclr, 0x80);
- /* Clear WOL config and status bits. */
- csr8w(ctlr, Wolcrclr, 0xFF);
- csr8w(ctlr, Pwrcsrclr, 0xFF);
- }
- /*
- * Soft reset the controller.
- */
- csr16w(ctlr, Cr, Stop);
- csr16w(ctlr, Cr, Stop|Sfrst);
- for(timeo = 0; timeo < 10000; timeo++){
- if(!(csr16r(ctlr, Cr) & Sfrst))
- break;
- microdelay(1);
- }
- if(timeo >= 1000)
- return -1;
- return 0;
- }
- static int
- vt6105Mreset(Ctlr* ctlr)
- {
- MiiPhy *phy;
- int i, r, timeo;
- if(vt6105Mdetach(ctlr) < 0)
- return -1;
- /*
- * Load the MAC address into the PAR[01]
- * registers.
- */
- r = csr8r(ctlr, Eecsr);
- csr8w(ctlr, Eecsr, Autold|r);
- for(timeo = 0; timeo < 100; timeo++){
- if(!(csr8r(ctlr, Cr) & Autold))
- break;
- microdelay(1);
- }
- if(timeo >= 100)
- return -1;
- for(i = 0; i < Eaddrlen; i++)
- ctlr->par[i] = csr8r(ctlr, Par0+i);
- /*
- * Configure DMA and Rx/Tx thresholds.
- * If the Rx/Tx threshold bits in Bcr[01] are 0 then
- * the thresholds are determined by Rcr/Tcr.
- */
- r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
- csr8w(ctlr, Bcr0, r|Crft128|DmaSAF);
- r = csr8r(ctlr, Bcr1) & ~CtftMASK;
- csr8w(ctlr, Bcr1, r|ctlr->tft);
- r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
- csr8w(ctlr, Rcr, r|Ab|Am);
- csr32w(ctlr, Mcfilt0, ~0UL); /* accept all multicast */
- csr32w(ctlr, Mcfilt1, ~0UL);
- r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
- csr8w(ctlr, Tcr, r);
- /*
- * Link management.
- */
- if((ctlr->mii = malloc(sizeof(Mii))) == nil)
- return -1;
- ctlr->mii->mir = vt6105Mmiimir;
- ctlr->mii->miw = vt6105Mmiimiw;
- ctlr->mii->ctlr = ctlr;
- if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
- free(ctlr->mii);
- ctlr->mii = nil;
- return -1;
- }
- // print("oui %X phyno %d\n", phy->oui, phy->phyno);
- USED(phy);
- if(miistatus(ctlr->mii) < 0){
- // miireset(ctlr->mii);
- miiane(ctlr->mii, ~0, ~0, ~0);
- }
- return 0;
- }
- static void
- vt6105Mpci(void)
- {
- Pcidev *p;
- Ctlr *ctlr;
- int cls, port;
- p = nil;
- while(p = pcimatch(p, 0, 0)){
- if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
- continue;
- switch((p->did<<16)|p->vid){
- default:
- continue;
- case (0x3053<<16)|0x1106: /* Rhine III-M vt6105M */
- break;
- }
- port = p->mem[0].bar & ~0x01;
- if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
- print("vt6105M: port 0x%uX in use\n", port);
- continue;
- }
- ctlr = malloc(sizeof(Ctlr));
- ctlr->port = port;
- ctlr->pcidev = p;
- ctlr->id = (p->did<<16)|p->vid;
- if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
- cls = 0x10;
- ctlr->cls = cls*4;
- if(ctlr->cls < sizeof(Ds)){
- print("vt6105M: cls %d < sizeof(Ds)\n", ctlr->cls);
- iofree(port);
- free(ctlr);
- continue;
- }
- ctlr->tft = CtftSAF;
- if(vt6105Mreset(ctlr)){
- iofree(port);
- free(ctlr);
- continue;
- }
- pcisetbme(p);
- if(vt6105Mctlrhead != nil)
- vt6105Mctlrtail->next = ctlr;
- else
- vt6105Mctlrhead = ctlr;
- vt6105Mctlrtail = ctlr;
- }
- }
- static int
- vt6105Mpnp(Ether* edev)
- {
- Ctlr *ctlr;
- if(vt6105Mctlrhead == nil)
- vt6105Mpci();
- /*
- * Any adapter matches if no edev->port is supplied,
- * otherwise the ports must match.
- */
- for(ctlr = vt6105Mctlrhead; 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;
- /*
- * Set to 1000Mb/s to fool the bsz calculation. We need
- * something better, though.
- */
- edev->mbps = 1000;
- memmove(edev->ea, ctlr->par, Eaddrlen);
- /*
- * Linkage to the generic ethernet driver.
- */
- edev->attach = vt6105Mattach;
- edev->transmit = vt6105Mtransmit;
- edev->interrupt = vt6105Minterrupt;
- edev->ifstat = vt6105Mifstat;
- edev->ctl = nil;
- edev->arg = edev;
- edev->promiscuous = vt6105Mpromiscuous;
- edev->multicast = vt6105Mmulticast;
- edev->maxmtu = ETHERMAXTU+Bslop;
- return 0;
- }
- void
- ethervt6105mlink(void)
- {
- addethercard("vt6105M", vt6105Mpnp);
- }
|