18cde348aSDavid du Colombier /*
29a3e0102SDavid du Colombier * intel pci-express 10Gb ethernet driver for 8259[89]
38cde348aSDavid du Colombier * copyright © 2007, coraid, inc.
49a3e0102SDavid du Colombier * depessimised and made to work on the 82599 at bell labs, 2013.
59a3e0102SDavid du Colombier *
69a3e0102SDavid du Colombier * 82599 requests should ideally not cross a 4KB (page) boundary.
78cde348aSDavid du Colombier */
88cde348aSDavid du Colombier #include "u.h"
98cde348aSDavid du Colombier #include "../port/lib.h"
108cde348aSDavid du Colombier #include "mem.h"
118cde348aSDavid du Colombier #include "dat.h"
128cde348aSDavid du Colombier #include "fns.h"
138cde348aSDavid du Colombier #include "io.h"
148cde348aSDavid du Colombier #include "../port/error.h"
158cde348aSDavid du Colombier #include "../port/netif.h"
168cde348aSDavid du Colombier #include "etherif.h"
178cde348aSDavid du Colombier
189a3e0102SDavid du Colombier #define NEXTPOW2(x, m) (((x)+1) & (m))
199a3e0102SDavid du Colombier
20e845aa5bSDavid du Colombier enum {
219a3e0102SDavid du Colombier Rbsz = ETHERMAXTU+32, /* +slop is for vlan headers, crcs, etc. */
229a3e0102SDavid du Colombier Descalign= 128, /* 599 manual needs 128-byte alignment */
23830f0b04SDavid du Colombier
24830f0b04SDavid du Colombier /* tunable parameters */
259a3e0102SDavid du Colombier Goslow = 0, /* flag: go slow by throttling intrs, etc. */
26*588d0145SDavid du Colombier /* were 256, 1024 & 64, but 30, 47 and 1 are ample. */
27*588d0145SDavid du Colombier Nrd = 64, /* multiple of 8, power of 2 for NEXTPOW2 */
28*588d0145SDavid du Colombier Nrb = 128,
29*588d0145SDavid du Colombier Ntd = 32, /* multiple of 8, power of 2 for NEXTPOW2 */
30e845aa5bSDavid du Colombier };
31e845aa5bSDavid du Colombier
328cde348aSDavid du Colombier enum {
338cde348aSDavid du Colombier /* general */
348cde348aSDavid du Colombier Ctrl = 0x00000/4, /* Device Control */
358cde348aSDavid du Colombier Status = 0x00008/4, /* Device Status */
368cde348aSDavid du Colombier Ctrlext = 0x00018/4, /* Extended Device Control */
378cde348aSDavid du Colombier Esdp = 0x00020/4, /* extended sdp control */
389a3e0102SDavid du Colombier Esodp = 0x00028/4, /* extended od sdp control (i2cctl on 599) */
398cde348aSDavid du Colombier Ledctl = 0x00200/4, /* led control */
408cde348aSDavid du Colombier Tcptimer = 0x0004c/4, /* tcp timer */
419a3e0102SDavid du Colombier Ecc = 0x110b0/4, /* errata ecc control magic (pcie intr cause on 599) */
428cde348aSDavid du Colombier
438cde348aSDavid du Colombier /* nvm */
448cde348aSDavid du Colombier Eec = 0x10010/4, /* eeprom/flash control */
458cde348aSDavid du Colombier Eerd = 0x10014/4, /* eeprom read */
468cde348aSDavid du Colombier Fla = 0x1001c/4, /* flash access */
478cde348aSDavid du Colombier Flop = 0x1013c/4, /* flash opcode */
488cde348aSDavid du Colombier Grc = 0x10200/4, /* general rx control */
498cde348aSDavid du Colombier
508cde348aSDavid du Colombier /* interrupt */
518cde348aSDavid du Colombier Icr = 0x00800/4, /* interrupt cause read */
528cde348aSDavid du Colombier Ics = 0x00808/4, /* " set */
539a3e0102SDavid du Colombier Ims = 0x00880/4, /* " mask read/set (actually enable) */
548cde348aSDavid du Colombier Imc = 0x00888/4, /* " mask clear */
559a3e0102SDavid du Colombier Iac = 0x00810/4, /* " auto clear */
568cde348aSDavid du Colombier Iam = 0x00890/4, /* " auto mask enable */
579a3e0102SDavid du Colombier Itr = 0x00820/4, /* " throttling rate regs (0-19) */
588cde348aSDavid du Colombier Ivar = 0x00900/4, /* " vector allocation regs. */
598cde348aSDavid du Colombier /* msi interrupt */
608cde348aSDavid du Colombier Msixt = 0x0000/4, /* msix table (bar3) */
618cde348aSDavid du Colombier Msipba = 0x2000/4, /* msix pending bit array (bar3) */
628cde348aSDavid du Colombier Pbacl = 0x11068/4, /* pba clear */
638cde348aSDavid du Colombier Gpie = 0x00898/4, /* general purpose int enable */
648cde348aSDavid du Colombier
658cde348aSDavid du Colombier /* flow control */
668cde348aSDavid du Colombier Pfctop = 0x03008/4, /* priority flow ctl type opcode */
678cde348aSDavid du Colombier Fcttv = 0x03200/4, /* " transmit timer value (0-3) */
688cde348aSDavid du Colombier Fcrtl = 0x03220/4, /* " rx threshold low (0-7) +8n */
698cde348aSDavid du Colombier Fcrth = 0x03260/4, /* " rx threshold high (0-7) +8n */
708cde348aSDavid du Colombier Rcrtv = 0x032a0/4, /* " refresh value threshold */
718cde348aSDavid du Colombier Tfcs = 0x0ce00/4, /* " tx status */
728cde348aSDavid du Colombier
738cde348aSDavid du Colombier /* rx dma */
748cde348aSDavid du Colombier Rbal = 0x01000/4, /* rx desc base low (0-63) +0x40n */
758cde348aSDavid du Colombier Rbah = 0x01004/4, /* " high */
768cde348aSDavid du Colombier Rdlen = 0x01008/4, /* " length */
778cde348aSDavid du Colombier Rdh = 0x01010/4, /* " head */
788cde348aSDavid du Colombier Rdt = 0x01018/4, /* " tail */
798cde348aSDavid du Colombier Rxdctl = 0x01028/4, /* " control */
808cde348aSDavid du Colombier
819a3e0102SDavid du Colombier Srrctl = 0x02100/4, /* split & replication rx ctl. array */
828cde348aSDavid du Colombier Dcarxctl = 0x02200/4, /* rx dca control */
838cde348aSDavid du Colombier Rdrxctl = 0x02f00/4, /* rx dma control */
848cde348aSDavid du Colombier Rxpbsize = 0x03c00/4, /* rx packet buffer size */
858cde348aSDavid du Colombier Rxctl = 0x03000/4, /* rx control */
869a3e0102SDavid du Colombier Dropen = 0x03d04/4, /* drop enable control (598 only) */
878cde348aSDavid du Colombier
888cde348aSDavid du Colombier /* rx */
898cde348aSDavid du Colombier Rxcsum = 0x05000/4, /* rx checksum control */
909a3e0102SDavid du Colombier Rfctl = 0x05008/4, /* rx filter control */
918cde348aSDavid du Colombier Mta = 0x05200/4, /* multicast table array (0-127) */
929a3e0102SDavid du Colombier Ral98 = 0x05400/4, /* rx address low (598) */
939a3e0102SDavid du Colombier Rah98 = 0x05404/4,
949a3e0102SDavid du Colombier Ral99 = 0x0a200/4, /* rx address low array (599) */
959a3e0102SDavid du Colombier Rah99 = 0x0a204/4,
968cde348aSDavid du Colombier Psrtype = 0x05480/4, /* packet split rx type. */
978cde348aSDavid du Colombier Vfta = 0x0a000/4, /* vlan filter table array. */
988cde348aSDavid du Colombier Fctrl = 0x05080/4, /* filter control */
998cde348aSDavid du Colombier Vlnctrl = 0x05088/4, /* vlan control */
1008cde348aSDavid du Colombier Msctctrl = 0x05090/4, /* multicast control */
1018cde348aSDavid du Colombier Mrqc = 0x05818/4, /* multiple rx queues cmd */
1029a3e0102SDavid du Colombier Vmdctl = 0x0581c/4, /* vmdq control (598 only) */
1039a3e0102SDavid du Colombier Imir = 0x05a80/4, /* immediate irq rx (0-7) (598 only) */
1049a3e0102SDavid du Colombier Imirext = 0x05aa0/4, /* immediate irq rx ext (598 only) */
1059a3e0102SDavid du Colombier Imirvp = 0x05ac0/4, /* immediate irq vlan priority (598 only) */
1068cde348aSDavid du Colombier Reta = 0x05c00/4, /* redirection table */
1078cde348aSDavid du Colombier Rssrk = 0x05c80/4, /* rss random key */
1088cde348aSDavid du Colombier
1098cde348aSDavid du Colombier /* tx */
1109a3e0102SDavid du Colombier Tdbal = 0x06000/4, /* tx desc base low +0x40n array */
1118cde348aSDavid du Colombier Tdbah = 0x06004/4, /* " high */
1128cde348aSDavid du Colombier Tdlen = 0x06008/4, /* " len */
1138cde348aSDavid du Colombier Tdh = 0x06010/4, /* " head */
1148cde348aSDavid du Colombier Tdt = 0x06018/4, /* " tail */
1158cde348aSDavid du Colombier Txdctl = 0x06028/4, /* " control */
1168cde348aSDavid du Colombier Tdwbal = 0x06038/4, /* " write-back address low */
1178cde348aSDavid du Colombier Tdwbah = 0x0603c/4,
1188cde348aSDavid du Colombier
1199a3e0102SDavid du Colombier Dtxctl98 = 0x07e00/4, /* tx dma control (598 only) */
1209a3e0102SDavid du Colombier Dtxctl99 = 0x04a80/4, /* tx dma control (599 only) */
1219a3e0102SDavid du Colombier Tdcatxctrl98 = 0x07200/4, /* tx dca register (0-15) (598 only) */
1229a3e0102SDavid du Colombier Tdcatxctrl99 = 0x0600c/4, /* tx dca register (0-127) (599 only) */
1239a3e0102SDavid du Colombier Tipg = 0x0cb00/4, /* tx inter-packet gap (598 only) */
1248cde348aSDavid du Colombier Txpbsize = 0x0cc00/4, /* tx packet-buffer size (0-15) */
1258cde348aSDavid du Colombier
1268cde348aSDavid du Colombier /* mac */
1278cde348aSDavid du Colombier Hlreg0 = 0x04240/4, /* highlander control reg 0 */
1288cde348aSDavid du Colombier Hlreg1 = 0x04244/4, /* highlander control reg 1 (ro) */
1298cde348aSDavid du Colombier Msca = 0x0425c/4, /* mdi signal cmd & addr */
1308cde348aSDavid du Colombier Msrwd = 0x04260/4, /* mdi single rw data */
1318cde348aSDavid du Colombier Mhadd = 0x04268/4, /* mac addr high & max frame */
1328cde348aSDavid du Colombier Pcss1 = 0x04288/4, /* xgxs status 1 */
1338cde348aSDavid du Colombier Pcss2 = 0x0428c/4,
1348cde348aSDavid du Colombier Xpcss = 0x04290/4, /* 10gb-x pcs status */
1358cde348aSDavid du Colombier Serdesc = 0x04298/4, /* serdes control */
1368cde348aSDavid du Colombier Macs = 0x0429c/4, /* fifo control & report */
1378cde348aSDavid du Colombier Autoc = 0x042a0/4, /* autodetect control & status */
1388cde348aSDavid du Colombier Links = 0x042a4/4, /* link status */
1399a3e0102SDavid du Colombier Links2 = 0x04324/4, /* 599 only */
1408cde348aSDavid du Colombier Autoc2 = 0x042a8/4,
1418cde348aSDavid du Colombier };
1428cde348aSDavid du Colombier
1438cde348aSDavid du Colombier enum {
1449a3e0102SDavid du Colombier Factive = 1<<0,
1459a3e0102SDavid du Colombier Enable = 1<<31,
1469a3e0102SDavid du Colombier
1478cde348aSDavid du Colombier /* Ctrl */
1488cde348aSDavid du Colombier Rst = 1<<26, /* full nic reset */
1498cde348aSDavid du Colombier
1508cde348aSDavid du Colombier /* Txdctl */
1518cde348aSDavid du Colombier Ten = 1<<25,
1528cde348aSDavid du Colombier
1539a3e0102SDavid du Colombier /* Dtxctl99 */
1549a3e0102SDavid du Colombier Te = 1<<0, /* dma tx enable */
1559a3e0102SDavid du Colombier
1568cde348aSDavid du Colombier /* Fctrl */
1578cde348aSDavid du Colombier Bam = 1<<10, /* broadcast accept mode */
1588cde348aSDavid du Colombier Upe = 1<<9, /* unicast promiscuous */
1598cde348aSDavid du Colombier Mpe = 1<<8, /* multicast promiscuous */
1608cde348aSDavid du Colombier
1618cde348aSDavid du Colombier /* Rxdctl */
1628cde348aSDavid du Colombier Pthresh = 0, /* prefresh threshold shift in bits */
1638cde348aSDavid du Colombier Hthresh = 8, /* host buffer minimum threshold " */
1648cde348aSDavid du Colombier Wthresh = 16, /* writeback threshold */
1658cde348aSDavid du Colombier Renable = 1<<25,
1668cde348aSDavid du Colombier
1678cde348aSDavid du Colombier /* Rxctl */
1688cde348aSDavid du Colombier Rxen = 1<<0,
1699a3e0102SDavid du Colombier Dmbyps = 1<<1, /* descr. monitor bypass (598 only) */
1708cde348aSDavid du Colombier
1718cde348aSDavid du Colombier /* Rdrxctl */
1729a3e0102SDavid du Colombier Rdmt½ = 0, /* 598 */
1739a3e0102SDavid du Colombier Rdmt¼ = 1, /* 598 */
1749a3e0102SDavid du Colombier Rdmt⅛ = 2, /* 598 */
1759a3e0102SDavid du Colombier Crcstrip = 1<<1, /* 599 */
1769a3e0102SDavid du Colombier Rscfrstsize = 037<<17, /* 599; should be zero */
1778cde348aSDavid du Colombier
1788cde348aSDavid du Colombier /* Rxcsum */
1798cde348aSDavid du Colombier Ippcse = 1<<12, /* ip payload checksum enable */
1808cde348aSDavid du Colombier
1818cde348aSDavid du Colombier /* Eerd */
1828cde348aSDavid du Colombier EEstart = 1<<0, /* Start Read */
1838cde348aSDavid du Colombier EEdone = 1<<1, /* Read done */
1848cde348aSDavid du Colombier
1858cde348aSDavid du Colombier /* interrupts */
1868cde348aSDavid du Colombier Irx0 = 1<<0, /* driver defined */
1878cde348aSDavid du Colombier Itx0 = 1<<1, /* driver defined */
1888cde348aSDavid du Colombier Lsc = 1<<20, /* link status change */
1898cde348aSDavid du Colombier
1908cde348aSDavid du Colombier /* Links */
1918cde348aSDavid du Colombier Lnkup = 1<<30,
1928cde348aSDavid du Colombier Lnkspd = 1<<29,
1938cde348aSDavid du Colombier
1948cde348aSDavid du Colombier /* Hlreg0 */
1959a3e0102SDavid du Colombier Txcrcen = 1<<0, /* add crc during xmit */
1969a3e0102SDavid du Colombier Rxcrcstrip = 1<<1, /* strip crc during recv */
1978cde348aSDavid du Colombier Jumboen = 1<<2,
1989a3e0102SDavid du Colombier Txpaden = 1<<10, /* pad short frames during xmit */
1999a3e0102SDavid du Colombier
2009a3e0102SDavid du Colombier /* Autoc */
2019a3e0102SDavid du Colombier Flu = 1<<0, /* force link up */
2029a3e0102SDavid du Colombier Lmsshift = 13, /* link mode select shift */
2039a3e0102SDavid du Colombier Lmsmask = 7,
2048cde348aSDavid du Colombier };
2058cde348aSDavid du Colombier
206c02f0a41SDavid du Colombier typedef struct Ctlr Ctlr;
207c02f0a41SDavid du Colombier typedef struct Rd Rd;
208c02f0a41SDavid du Colombier typedef struct Td Td;
209c02f0a41SDavid du Colombier
2108cde348aSDavid du Colombier typedef struct {
2118cde348aSDavid du Colombier uint reg;
2128cde348aSDavid du Colombier char *name;
2138cde348aSDavid du Colombier } Stat;
2148cde348aSDavid du Colombier
2158cde348aSDavid du Colombier Stat stattab[] = {
2168cde348aSDavid du Colombier 0x4000, "crc error",
2178cde348aSDavid du Colombier 0x4004, "illegal byte",
2188cde348aSDavid du Colombier 0x4008, "short packet",
2198cde348aSDavid du Colombier 0x3fa0, "missed pkt0",
2208cde348aSDavid du Colombier 0x4034, "mac local flt",
2218cde348aSDavid du Colombier 0x4038, "mac rmt flt",
2228cde348aSDavid du Colombier 0x4040, "rx length err",
2238cde348aSDavid du Colombier 0x3f60, "xon tx",
2248cde348aSDavid du Colombier 0xcf60, "xon rx",
2258cde348aSDavid du Colombier 0x3f68, "xoff tx",
2268cde348aSDavid du Colombier 0xcf68, "xoff rx",
2278cde348aSDavid du Colombier 0x405c, "rx 040",
2288cde348aSDavid du Colombier 0x4060, "rx 07f",
2298cde348aSDavid du Colombier 0x4064, "rx 100",
2308cde348aSDavid du Colombier 0x4068, "rx 200",
2318cde348aSDavid du Colombier 0x406c, "rx 3ff",
2328cde348aSDavid du Colombier 0x4070, "rx big",
2338cde348aSDavid du Colombier 0x4074, "rx ok",
2348cde348aSDavid du Colombier 0x4078, "rx bcast",
2358cde348aSDavid du Colombier 0x3fc0, "rx no buf0",
2368cde348aSDavid du Colombier 0x40a4, "rx runt",
2378cde348aSDavid du Colombier 0x40a8, "rx frag",
2388cde348aSDavid du Colombier 0x40ac, "rx ovrsz",
2398cde348aSDavid du Colombier 0x40b0, "rx jab",
2408cde348aSDavid du Colombier 0x40d0, "rx pkt",
2418cde348aSDavid du Colombier
2428cde348aSDavid du Colombier 0x40d4, "tx pkt",
2438cde348aSDavid du Colombier 0x40d8, "tx 040",
2448cde348aSDavid du Colombier 0x40dc, "tx 07f",
2458cde348aSDavid du Colombier 0x40e0, "tx 100",
2468cde348aSDavid du Colombier 0x40e4, "tx 200",
2478cde348aSDavid du Colombier 0x40e8, "tx 3ff",
2488cde348aSDavid du Colombier 0x40ec, "tx big",
2498cde348aSDavid du Colombier 0x40f4, "tx bcast",
2508cde348aSDavid du Colombier 0x4120, "xsum err",
2518cde348aSDavid du Colombier };
2528cde348aSDavid du Colombier
2538cde348aSDavid du Colombier /* status */
2548cde348aSDavid du Colombier enum {
2558cde348aSDavid du Colombier Pif = 1<<7, /* past exact filter (sic) */
2569a3e0102SDavid du Colombier Ipcs = 1<<6, /* ip checksum calculated */
2578cde348aSDavid du Colombier L4cs = 1<<5, /* layer 2 */
2589a3e0102SDavid du Colombier Tcpcs = 1<<4, /* tcp checksum calculated */
2598cde348aSDavid du Colombier Vp = 1<<3, /* 802.1q packet matched vet */
2608cde348aSDavid du Colombier Ixsm = 1<<2, /* ignore checksum */
2618cde348aSDavid du Colombier Reop = 1<<1, /* end of packet */
2628cde348aSDavid du Colombier Rdd = 1<<0, /* descriptor done */
2638cde348aSDavid du Colombier };
2648cde348aSDavid du Colombier
265c02f0a41SDavid du Colombier struct Rd { /* Receive Descriptor */
2668cde348aSDavid du Colombier u32int addr[2];
2678cde348aSDavid du Colombier ushort length;
2688cde348aSDavid du Colombier ushort cksum;
2698cde348aSDavid du Colombier uchar status;
2708cde348aSDavid du Colombier uchar errors;
2718cde348aSDavid du Colombier ushort vlan;
272c02f0a41SDavid du Colombier };
2738cde348aSDavid du Colombier
2748cde348aSDavid du Colombier enum {
2758cde348aSDavid du Colombier /* Td cmd */
2769a3e0102SDavid du Colombier Rs = 1<<3, /* report status */
2779a3e0102SDavid du Colombier Ic = 1<<2, /* insert checksum */
2789a3e0102SDavid du Colombier Ifcs = 1<<1, /* insert FCS (ethernet crc) */
2799a3e0102SDavid du Colombier Teop = 1<<0, /* end of packet */
2808cde348aSDavid du Colombier
2818cde348aSDavid du Colombier /* Td status */
2829a3e0102SDavid du Colombier Tdd = 1<<0, /* descriptor done */
2838cde348aSDavid du Colombier };
2848cde348aSDavid du Colombier
285c02f0a41SDavid du Colombier struct Td { /* Transmit Descriptor */
2868cde348aSDavid du Colombier u32int addr[2];
2878cde348aSDavid du Colombier ushort length;
2888cde348aSDavid du Colombier uchar cso;
2898cde348aSDavid du Colombier uchar cmd;
2908cde348aSDavid du Colombier uchar status;
2918cde348aSDavid du Colombier uchar css;
2928cde348aSDavid du Colombier ushort vlan;
293c02f0a41SDavid du Colombier };
2948cde348aSDavid du Colombier
295c02f0a41SDavid du Colombier struct Ctlr {
2968cde348aSDavid du Colombier Pcidev *p;
2973b86f2f8SDavid du Colombier Ether *edev;
2989a3e0102SDavid du Colombier int type;
299830f0b04SDavid du Colombier
300830f0b04SDavid du Colombier /* virtual */
3018cde348aSDavid du Colombier u32int *reg;
302830f0b04SDavid du Colombier u32int *msix; /* unused */
303830f0b04SDavid du Colombier
304830f0b04SDavid du Colombier /* physical */
305830f0b04SDavid du Colombier u32int *physreg;
306830f0b04SDavid du Colombier u32int *physmsix; /* unused */
307830f0b04SDavid du Colombier
3088cde348aSDavid du Colombier uchar flag;
3098cde348aSDavid du Colombier int nrd;
3108cde348aSDavid du Colombier int ntd;
311c02f0a41SDavid du Colombier int nrb; /* # bufs this Ctlr has in the pool */
3129a3e0102SDavid du Colombier uint rbsz;
3139a3e0102SDavid du Colombier int procsrunning;
3149a3e0102SDavid du Colombier int attached;
3159a3e0102SDavid du Colombier
316217e9e83SDavid du Colombier Watermark wmrb;
317217e9e83SDavid du Colombier Watermark wmrd;
318217e9e83SDavid du Colombier Watermark wmtd;
319217e9e83SDavid du Colombier
320217e9e83SDavid du Colombier QLock slock;
321217e9e83SDavid du Colombier QLock alock; /* attach lock */
3228cde348aSDavid du Colombier QLock tlock;
3238cde348aSDavid du Colombier Rendez lrendez;
3248cde348aSDavid du Colombier Rendez trendez;
3258cde348aSDavid du Colombier Rendez rrendez;
3269a3e0102SDavid du Colombier
327c02f0a41SDavid du Colombier uint im; /* interrupt mask */
3288cde348aSDavid du Colombier uint lim;
3298cde348aSDavid du Colombier uint rim;
3308cde348aSDavid du Colombier uint tim;
3318cde348aSDavid du Colombier Lock imlock;
3328cde348aSDavid du Colombier
333c02f0a41SDavid du Colombier Rd* rdba; /* receive descriptor base address */
334c02f0a41SDavid du Colombier Block** rb; /* receive buffers */
335c02f0a41SDavid du Colombier int rdt; /* receive descriptor tail */
336c02f0a41SDavid du Colombier int rdfree; /* rx descriptors awaiting packets */
3378cde348aSDavid du Colombier
338c02f0a41SDavid du Colombier Td* tdba; /* transmit descriptor base address */
339c02f0a41SDavid du Colombier int tdh; /* transmit descriptor head */
340c02f0a41SDavid du Colombier int tdt; /* transmit descriptor tail */
341c02f0a41SDavid du Colombier Block** tb; /* transmit buffers */
3428cde348aSDavid du Colombier
343c02f0a41SDavid du Colombier uchar ra[Eaddrlen]; /* receive address */
344c02f0a41SDavid du Colombier uchar mta[128]; /* multicast table array */
3458cde348aSDavid du Colombier ulong stats[nelem(stattab)];
3468cde348aSDavid du Colombier uint speeds[3];
347c02f0a41SDavid du Colombier };
3488cde348aSDavid du Colombier
3499a3e0102SDavid du Colombier enum {
3509a3e0102SDavid du Colombier I82598 = 1,
3519a3e0102SDavid du Colombier I82599,
3529a3e0102SDavid du Colombier };
3539a3e0102SDavid du Colombier
3548cde348aSDavid du Colombier static Ctlr *ctlrtab[4];
3558cde348aSDavid du Colombier static int nctlr;
3568cde348aSDavid du Colombier static Lock rblock;
3578cde348aSDavid du Colombier static Block *rbpool;
358217e9e83SDavid du Colombier static int nrbfull; /* # of rcv Blocks with data awaiting processing */
3598cde348aSDavid du Colombier
3608cde348aSDavid du Colombier static void
readstats(Ctlr * ctlr)361217e9e83SDavid du Colombier readstats(Ctlr *ctlr)
3628cde348aSDavid du Colombier {
3638cde348aSDavid du Colombier int i;
3648cde348aSDavid du Colombier
365217e9e83SDavid du Colombier qlock(&ctlr->slock);
366217e9e83SDavid du Colombier for(i = 0; i < nelem(ctlr->stats); i++)
367217e9e83SDavid du Colombier ctlr->stats[i] += ctlr->reg[stattab[i].reg >> 2];
368217e9e83SDavid du Colombier qunlock(&ctlr->slock);
3698cde348aSDavid du Colombier }
3708cde348aSDavid du Colombier
3718cde348aSDavid du Colombier static int speedtab[] = {
3728cde348aSDavid du Colombier 0,
3738cde348aSDavid du Colombier 1000,
3748cde348aSDavid du Colombier 10000,
3758cde348aSDavid du Colombier };
3768cde348aSDavid du Colombier
3778cde348aSDavid du Colombier static long
ifstat(Ether * edev,void * a,long n,ulong offset)378217e9e83SDavid du Colombier ifstat(Ether *edev, void *a, long n, ulong offset)
3798cde348aSDavid du Colombier {
3808cde348aSDavid du Colombier uint i, *t;
381217e9e83SDavid du Colombier char *s, *p, *e;
382217e9e83SDavid du Colombier Ctlr *ctlr;
3838cde348aSDavid du Colombier
384217e9e83SDavid du Colombier ctlr = edev->ctlr;
38546136019SDavid du Colombier p = s = malloc(READSTR);
386aa72973aSDavid du Colombier if(p == nil)
387aa72973aSDavid du Colombier error(Enomem);
388217e9e83SDavid du Colombier e = p + READSTR;
3898cde348aSDavid du Colombier
390217e9e83SDavid du Colombier readstats(ctlr);
3918cde348aSDavid du Colombier for(i = 0; i < nelem(stattab); i++)
392217e9e83SDavid du Colombier if(ctlr->stats[i] > 0)
393217e9e83SDavid du Colombier p = seprint(p, e, "%.10s %uld\n", stattab[i].name,
394217e9e83SDavid du Colombier ctlr->stats[i]);
395217e9e83SDavid du Colombier t = ctlr->speeds;
396217e9e83SDavid du Colombier p = seprint(p, e, "speeds: 0:%d 1000:%d 10000:%d\n", t[0], t[1], t[2]);
397217e9e83SDavid du Colombier p = seprint(p, e, "mtu: min:%d max:%d\n", edev->minmtu, edev->maxmtu);
398217e9e83SDavid du Colombier p = seprint(p, e, "rdfree %d rdh %d rdt %d\n", ctlr->rdfree, ctlr->reg[Rdt],
399217e9e83SDavid du Colombier ctlr->reg[Rdh]);
400217e9e83SDavid du Colombier p = seprintmark(p, e, &ctlr->wmrb);
401217e9e83SDavid du Colombier p = seprintmark(p, e, &ctlr->wmrd);
402217e9e83SDavid du Colombier p = seprintmark(p, e, &ctlr->wmtd);
403217e9e83SDavid du Colombier USED(p);
4048cde348aSDavid du Colombier n = readstr(offset, a, n, s);
4058cde348aSDavid du Colombier free(s);
4068cde348aSDavid du Colombier
4078cde348aSDavid du Colombier return n;
4088cde348aSDavid du Colombier }
4098cde348aSDavid du Colombier
4108cde348aSDavid du Colombier static void
ienable(Ctlr * ctlr,int i)411217e9e83SDavid du Colombier ienable(Ctlr *ctlr, int i)
4128cde348aSDavid du Colombier {
413217e9e83SDavid du Colombier ilock(&ctlr->imlock);
414217e9e83SDavid du Colombier ctlr->im |= i;
415217e9e83SDavid du Colombier ctlr->reg[Ims] = ctlr->im;
416217e9e83SDavid du Colombier iunlock(&ctlr->imlock);
4178cde348aSDavid du Colombier }
4188cde348aSDavid du Colombier
4198cde348aSDavid du Colombier static int
lim(void * v)4208cde348aSDavid du Colombier lim(void *v)
4218cde348aSDavid du Colombier {
4228cde348aSDavid du Colombier return ((Ctlr*)v)->lim != 0;
4238cde348aSDavid du Colombier }
4248cde348aSDavid du Colombier
4258cde348aSDavid du Colombier static void
lproc(void * v)4268cde348aSDavid du Colombier lproc(void *v)
4278cde348aSDavid du Colombier {
4288cde348aSDavid du Colombier int r, i;
429217e9e83SDavid du Colombier Ctlr *ctlr;
4308cde348aSDavid du Colombier Ether *e;
4318cde348aSDavid du Colombier
4328cde348aSDavid du Colombier e = v;
433217e9e83SDavid du Colombier ctlr = e->ctlr;
4348cde348aSDavid du Colombier for (;;) {
435217e9e83SDavid du Colombier r = ctlr->reg[Links];
4368cde348aSDavid du Colombier e->link = (r & Lnkup) != 0;
4378cde348aSDavid du Colombier i = 0;
4388cde348aSDavid du Colombier if(e->link)
4398cde348aSDavid du Colombier i = 1 + ((r & Lnkspd) != 0);
440217e9e83SDavid du Colombier ctlr->speeds[i]++;
4418cde348aSDavid du Colombier e->mbps = speedtab[i];
442217e9e83SDavid du Colombier ctlr->lim = 0;
443217e9e83SDavid du Colombier ienable(ctlr, Lsc);
444217e9e83SDavid du Colombier sleep(&ctlr->lrendez, lim, ctlr);
445217e9e83SDavid du Colombier ctlr->lim = 0;
4468cde348aSDavid du Colombier }
4478cde348aSDavid du Colombier }
4488cde348aSDavid du Colombier
4498cde348aSDavid du Colombier static long
ctl(Ether *,void *,long)4508cde348aSDavid du Colombier ctl(Ether *, void *, long)
4518cde348aSDavid du Colombier {
4528cde348aSDavid du Colombier error(Ebadarg);
4538cde348aSDavid du Colombier return -1;
4548cde348aSDavid du Colombier }
4558cde348aSDavid du Colombier
4568cde348aSDavid du Colombier static Block*
rballoc(void)4578cde348aSDavid du Colombier rballoc(void)
4588cde348aSDavid du Colombier {
459b08d585eSDavid du Colombier Block *bp;
4608cde348aSDavid du Colombier
4618cde348aSDavid du Colombier ilock(&rblock);
462b08d585eSDavid du Colombier if((bp = rbpool) != nil){
463b08d585eSDavid du Colombier rbpool = bp->next;
464b08d585eSDavid du Colombier bp->next = 0;
465b08d585eSDavid du Colombier _xinc(&bp->ref); /* prevent bp from being freed */
4668cde348aSDavid du Colombier }
4678cde348aSDavid du Colombier iunlock(&rblock);
468b08d585eSDavid du Colombier return bp;
4698cde348aSDavid du Colombier }
4708cde348aSDavid du Colombier
4718cde348aSDavid du Colombier void
rbfree(Block * b)4728cde348aSDavid du Colombier rbfree(Block *b)
4738cde348aSDavid du Colombier {
4748cde348aSDavid du Colombier b->rp = b->wp = (uchar*)PGROUND((uintptr)b->base);
475bfb6eab9SDavid du Colombier b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
4768cde348aSDavid du Colombier ilock(&rblock);
4778cde348aSDavid du Colombier b->next = rbpool;
4788cde348aSDavid du Colombier rbpool = b;
479217e9e83SDavid du Colombier nrbfull--;
4808cde348aSDavid du Colombier iunlock(&rblock);
4818cde348aSDavid du Colombier }
4828cde348aSDavid du Colombier
4838cde348aSDavid du Colombier static int
cleanup(Ctlr * ctlr,int tdh)484217e9e83SDavid du Colombier cleanup(Ctlr *ctlr, int tdh)
4858cde348aSDavid du Colombier {
4868cde348aSDavid du Colombier Block *b;
4878cde348aSDavid du Colombier uint m, n;
4888cde348aSDavid du Colombier
489217e9e83SDavid du Colombier m = ctlr->ntd - 1;
490217e9e83SDavid du Colombier while(ctlr->tdba[n = NEXTPOW2(tdh, m)].status & Tdd){
4918cde348aSDavid du Colombier tdh = n;
492217e9e83SDavid du Colombier b = ctlr->tb[tdh];
493217e9e83SDavid du Colombier ctlr->tb[tdh] = 0;
4949a3e0102SDavid du Colombier if (b)
4958cde348aSDavid du Colombier freeb(b);
496217e9e83SDavid du Colombier ctlr->tdba[tdh].status = 0;
4978cde348aSDavid du Colombier }
4988cde348aSDavid du Colombier return tdh;
4998cde348aSDavid du Colombier }
5008cde348aSDavid du Colombier
5018cde348aSDavid du Colombier void
transmit(Ether * e)5028cde348aSDavid du Colombier transmit(Ether *e)
5038cde348aSDavid du Colombier {
5048cde348aSDavid du Colombier uint i, m, tdt, tdh;
505217e9e83SDavid du Colombier Ctlr *ctlr;
5068cde348aSDavid du Colombier Block *b;
5078cde348aSDavid du Colombier Td *t;
5088cde348aSDavid du Colombier
509217e9e83SDavid du Colombier ctlr = e->ctlr;
510217e9e83SDavid du Colombier if(!canqlock(&ctlr->tlock)){
511217e9e83SDavid du Colombier ienable(ctlr, Itx0);
5128cde348aSDavid du Colombier return;
5138cde348aSDavid du Colombier }
514217e9e83SDavid du Colombier tdh = ctlr->tdh = cleanup(ctlr, ctlr->tdh);
515217e9e83SDavid du Colombier tdt = ctlr->tdt;
516217e9e83SDavid du Colombier m = ctlr->ntd - 1;
5179a3e0102SDavid du Colombier for(i = 0; ; i++){
5189a3e0102SDavid du Colombier if(NEXTPOW2(tdt, m) == tdh){ /* ring full? */
519217e9e83SDavid du Colombier ienable(ctlr, Itx0);
5208cde348aSDavid du Colombier break;
5218cde348aSDavid du Colombier }
5229a3e0102SDavid du Colombier if((b = qget(e->oq)) == nil)
5238cde348aSDavid du Colombier break;
524217e9e83SDavid du Colombier assert(ctlr->tdba != nil);
525217e9e83SDavid du Colombier t = ctlr->tdba + tdt;
5268cde348aSDavid du Colombier t->addr[0] = PCIWADDR(b->rp);
5278cde348aSDavid du Colombier t->length = BLEN(b);
5289a3e0102SDavid du Colombier t->cmd = Ifcs | Teop;
5299a3e0102SDavid du Colombier if (!Goslow)
5309a3e0102SDavid du Colombier t->cmd |= Rs;
531217e9e83SDavid du Colombier ctlr->tb[tdt] = b;
532217e9e83SDavid du Colombier /* note size of queue of tds awaiting transmission */
533217e9e83SDavid du Colombier notemark(&ctlr->wmtd, (tdt + Ntd - tdh) % Ntd);
5349a3e0102SDavid du Colombier tdt = NEXTPOW2(tdt, m);
5358cde348aSDavid du Colombier }
5368cde348aSDavid du Colombier if(i) {
5379a3e0102SDavid du Colombier coherence();
538217e9e83SDavid du Colombier ctlr->reg[Tdt] = ctlr->tdt = tdt; /* make new Tds active */
5399a3e0102SDavid du Colombier coherence();
540217e9e83SDavid du Colombier ienable(ctlr, Itx0);
5418cde348aSDavid du Colombier }
542217e9e83SDavid du Colombier qunlock(&ctlr->tlock);
5438cde348aSDavid du Colombier }
5448cde348aSDavid du Colombier
5458cde348aSDavid du Colombier static int
tim(void * c)5468cde348aSDavid du Colombier tim(void *c)
5478cde348aSDavid du Colombier {
5488cde348aSDavid du Colombier return ((Ctlr*)c)->tim != 0;
5498cde348aSDavid du Colombier }
5508cde348aSDavid du Colombier
5518cde348aSDavid du Colombier static void
tproc(void * v)5528cde348aSDavid du Colombier tproc(void *v)
5538cde348aSDavid du Colombier {
554217e9e83SDavid du Colombier Ctlr *ctlr;
5558cde348aSDavid du Colombier Ether *e;
5568cde348aSDavid du Colombier
5578cde348aSDavid du Colombier e = v;
558217e9e83SDavid du Colombier ctlr = e->ctlr;
5598cde348aSDavid du Colombier for (;;) {
560217e9e83SDavid du Colombier sleep(&ctlr->trendez, tim, ctlr); /* xmit interrupt kicks us */
561217e9e83SDavid du Colombier ctlr->tim = 0;
5628cde348aSDavid du Colombier transmit(e);
5638cde348aSDavid du Colombier }
5648cde348aSDavid du Colombier }
5658cde348aSDavid du Colombier
5668cde348aSDavid du Colombier static void
rxinit(Ctlr * ctlr)567217e9e83SDavid du Colombier rxinit(Ctlr *ctlr)
5688cde348aSDavid du Colombier {
569217e9e83SDavid du Colombier int i, is598, autoc;
570217e9e83SDavid du Colombier ulong until;
5718cde348aSDavid du Colombier Block *b;
5728cde348aSDavid du Colombier
573217e9e83SDavid du Colombier ctlr->reg[Rxctl] &= ~Rxen;
574217e9e83SDavid du Colombier ctlr->reg[Rxdctl] = 0;
575217e9e83SDavid du Colombier for(i = 0; i < ctlr->nrd; i++){
576217e9e83SDavid du Colombier b = ctlr->rb[i];
577217e9e83SDavid du Colombier ctlr->rb[i] = 0;
5788cde348aSDavid du Colombier if(b)
5798cde348aSDavid du Colombier freeb(b);
5808cde348aSDavid du Colombier }
581217e9e83SDavid du Colombier ctlr->rdfree = 0;
5828cde348aSDavid du Colombier
5839a3e0102SDavid du Colombier coherence();
584217e9e83SDavid du Colombier ctlr->reg[Fctrl] |= Bam;
585217e9e83SDavid du Colombier ctlr->reg[Fctrl] &= ~(Upe | Mpe);
5869a3e0102SDavid du Colombier
5879a3e0102SDavid du Colombier /* intel gets some csums wrong (e.g., errata 44) */
588217e9e83SDavid du Colombier ctlr->reg[Rxcsum] &= ~Ippcse;
589217e9e83SDavid du Colombier ctlr->reg[Hlreg0] &= ~Jumboen; /* jumbos are a bad idea */
590217e9e83SDavid du Colombier ctlr->reg[Hlreg0] |= Txcrcen | Rxcrcstrip | Txpaden;
591217e9e83SDavid du Colombier ctlr->reg[Srrctl] = (ctlr->rbsz + 1024 - 1) / 1024;
592217e9e83SDavid du Colombier ctlr->reg[Mhadd] = ctlr->rbsz << 16;
5938cde348aSDavid du Colombier
594217e9e83SDavid du Colombier ctlr->reg[Rbal] = PCIWADDR(ctlr->rdba);
595217e9e83SDavid du Colombier ctlr->reg[Rbah] = 0;
596217e9e83SDavid du Colombier ctlr->reg[Rdlen] = ctlr->nrd*sizeof(Rd); /* must be multiple of 128 */
597217e9e83SDavid du Colombier ctlr->reg[Rdh] = 0;
598217e9e83SDavid du Colombier ctlr->reg[Rdt] = ctlr->rdt = 0;
5999a3e0102SDavid du Colombier coherence();
6008cde348aSDavid du Colombier
601217e9e83SDavid du Colombier is598 = (ctlr->type == I82598);
6029a3e0102SDavid du Colombier if (is598)
603217e9e83SDavid du Colombier ctlr->reg[Rdrxctl] = Rdmt¼;
6049a3e0102SDavid du Colombier else {
605217e9e83SDavid du Colombier ctlr->reg[Rdrxctl] |= Crcstrip;
606217e9e83SDavid du Colombier ctlr->reg[Rdrxctl] &= ~Rscfrstsize;
6079a3e0102SDavid du Colombier }
6089a3e0102SDavid du Colombier if (Goslow && is598)
609217e9e83SDavid du Colombier ctlr->reg[Rxdctl] = 8<<Wthresh | 8<<Pthresh | 4<<Hthresh | Renable;
6109a3e0102SDavid du Colombier else
611217e9e83SDavid du Colombier ctlr->reg[Rxdctl] = Renable;
6129a3e0102SDavid du Colombier coherence();
613217e9e83SDavid du Colombier
614217e9e83SDavid du Colombier /*
615217e9e83SDavid du Colombier * don't wait forever like an idiot (and hang the system),
616217e9e83SDavid du Colombier * maybe it's disconnected.
617217e9e83SDavid du Colombier */
618217e9e83SDavid du Colombier until = TK2MS(MACHP(0)->ticks) + 250;
619217e9e83SDavid du Colombier while (!(ctlr->reg[Rxdctl] & Renable) && TK2MS(MACHP(0)->ticks) < until)
6209a3e0102SDavid du Colombier ;
621217e9e83SDavid du Colombier if(!(ctlr->reg[Rxdctl] & Renable))
622217e9e83SDavid du Colombier print("#l%d: Renable didn't come on, might be disconnected\n",
623217e9e83SDavid du Colombier ctlr->edev->ctlrno);
624217e9e83SDavid du Colombier
625217e9e83SDavid du Colombier ctlr->reg[Rxctl] |= Rxen | (is598? Dmbyps: 0);
6266083aa43SDavid du Colombier
6276083aa43SDavid du Colombier if (is598){
628217e9e83SDavid du Colombier autoc = ctlr->reg[Autoc];
629217e9e83SDavid du Colombier /* what is this rubbish and why do we care? */
630217e9e83SDavid du Colombier print("#l%d: autoc %#ux; lms %d (3 is 10g sfp)\n",
631217e9e83SDavid du Colombier ctlr->edev->ctlrno, autoc, (autoc>>Lmsshift) & Lmsmask);
632217e9e83SDavid du Colombier ctlr->reg[Autoc] |= Flu;
6336083aa43SDavid du Colombier coherence();
6346083aa43SDavid du Colombier delay(50);
6356083aa43SDavid du Colombier }
6368cde348aSDavid du Colombier }
6378cde348aSDavid du Colombier
6388cde348aSDavid du Colombier static void
replenish(Ctlr * ctlr,uint rdh)639217e9e83SDavid du Colombier replenish(Ctlr *ctlr, uint rdh)
6408cde348aSDavid du Colombier {
6418cde348aSDavid du Colombier int rdt, m, i;
6428cde348aSDavid du Colombier Block *b;
6438cde348aSDavid du Colombier Rd *r;
6448cde348aSDavid du Colombier
645217e9e83SDavid du Colombier m = ctlr->nrd - 1;
6468cde348aSDavid du Colombier i = 0;
647217e9e83SDavid du Colombier for(rdt = ctlr->rdt; NEXTPOW2(rdt, m) != rdh; rdt = NEXTPOW2(rdt, m)){
648217e9e83SDavid du Colombier r = ctlr->rdba + rdt;
6499a3e0102SDavid du Colombier if((b = rballoc()) == nil){
650217e9e83SDavid du Colombier print("#l%d: no buffers\n", ctlr->edev->ctlrno);
6518cde348aSDavid du Colombier break;
6528cde348aSDavid du Colombier }
653217e9e83SDavid du Colombier ctlr->rb[rdt] = b;
6548cde348aSDavid du Colombier r->addr[0] = PCIWADDR(b->rp);
6558cde348aSDavid du Colombier r->status = 0;
656217e9e83SDavid du Colombier ctlr->rdfree++;
6578cde348aSDavid du Colombier i++;
6588cde348aSDavid du Colombier }
6599a3e0102SDavid du Colombier if(i) {
6609a3e0102SDavid du Colombier coherence();
661217e9e83SDavid du Colombier ctlr->reg[Rdt] = ctlr->rdt = rdt; /* hand back recycled rdescs */
6629a3e0102SDavid du Colombier coherence();
6639a3e0102SDavid du Colombier }
6648cde348aSDavid du Colombier }
6658cde348aSDavid du Colombier
6668cde348aSDavid du Colombier static int
rim(void * v)6678cde348aSDavid du Colombier rim(void *v)
6688cde348aSDavid du Colombier {
6698cde348aSDavid du Colombier return ((Ctlr*)v)->rim != 0;
6708cde348aSDavid du Colombier }
6718cde348aSDavid du Colombier
6728cde348aSDavid du Colombier void
rproc(void * v)6738cde348aSDavid du Colombier rproc(void *v)
6748cde348aSDavid du Colombier {
675217e9e83SDavid du Colombier int passed;
6768cde348aSDavid du Colombier uint m, rdh;
677217e9e83SDavid du Colombier Block *bp;
678217e9e83SDavid du Colombier Ctlr *ctlr;
6798cde348aSDavid du Colombier Ether *e;
6808cde348aSDavid du Colombier Rd *r;
6818cde348aSDavid du Colombier
6828cde348aSDavid du Colombier e = v;
683217e9e83SDavid du Colombier ctlr = e->ctlr;
684217e9e83SDavid du Colombier m = ctlr->nrd - 1;
6859a3e0102SDavid du Colombier for (rdh = 0; ; ) {
686217e9e83SDavid du Colombier replenish(ctlr, rdh);
687217e9e83SDavid du Colombier ienable(ctlr, Irx0);
688217e9e83SDavid du Colombier sleep(&ctlr->rrendez, rim, ctlr);
689217e9e83SDavid du Colombier passed = 0;
6909a3e0102SDavid du Colombier for (;;) {
691217e9e83SDavid du Colombier ctlr->rim = 0;
692217e9e83SDavid du Colombier r = ctlr->rdba + rdh;
6939a3e0102SDavid du Colombier if(!(r->status & Rdd))
6949a3e0102SDavid du Colombier break; /* wait for pkts to arrive */
695217e9e83SDavid du Colombier bp = ctlr->rb[rdh];
696217e9e83SDavid du Colombier ctlr->rb[rdh] = 0;
6979a3e0102SDavid du Colombier if (r->length > ETHERMAXTU)
698217e9e83SDavid du Colombier print("#l%d: got jumbo of %d bytes\n",
699217e9e83SDavid du Colombier e->ctlrno, r->length);
700217e9e83SDavid du Colombier bp->wp += r->length;
701217e9e83SDavid du Colombier bp->lim = bp->wp; /* lie like a dog */
7028cde348aSDavid du Colombier // r->status = 0;
703217e9e83SDavid du Colombier
704217e9e83SDavid du Colombier ilock(&rblock);
705217e9e83SDavid du Colombier nrbfull++;
706217e9e83SDavid du Colombier iunlock(&rblock);
707217e9e83SDavid du Colombier notemark(&ctlr->wmrb, nrbfull);
708217e9e83SDavid du Colombier etheriq(e, bp, 1);
709217e9e83SDavid du Colombier
710217e9e83SDavid du Colombier passed++;
711217e9e83SDavid du Colombier ctlr->rdfree--;
7129a3e0102SDavid du Colombier rdh = NEXTPOW2(rdh, m);
713217e9e83SDavid du Colombier if (ctlr->rdfree <= ctlr->nrd - 16)
714217e9e83SDavid du Colombier replenish(ctlr, rdh);
7159a3e0102SDavid du Colombier }
716217e9e83SDavid du Colombier /* note how many rds had full buffers */
717217e9e83SDavid du Colombier notemark(&ctlr->wmrd, passed);
718bf3a53f8SDavid du Colombier }
7198cde348aSDavid du Colombier }
7208cde348aSDavid du Colombier
7218cde348aSDavid du Colombier static void
promiscuous(void * a,int on)7228cde348aSDavid du Colombier promiscuous(void *a, int on)
7238cde348aSDavid du Colombier {
724217e9e83SDavid du Colombier Ctlr *ctlr;
7258cde348aSDavid du Colombier Ether *e;
7268cde348aSDavid du Colombier
7278cde348aSDavid du Colombier e = a;
728217e9e83SDavid du Colombier ctlr = e->ctlr;
7298cde348aSDavid du Colombier if(on)
730217e9e83SDavid du Colombier ctlr->reg[Fctrl] |= Upe | Mpe;
7318cde348aSDavid du Colombier else
732217e9e83SDavid du Colombier ctlr->reg[Fctrl] &= ~(Upe | Mpe);
7338cde348aSDavid du Colombier }
7348cde348aSDavid du Colombier
7358cde348aSDavid du Colombier static void
multicast(void * a,uchar * ea,int on)7368cde348aSDavid du Colombier multicast(void *a, uchar *ea, int on)
7378cde348aSDavid du Colombier {
7388cde348aSDavid du Colombier int b, i;
739217e9e83SDavid du Colombier Ctlr *ctlr;
7408cde348aSDavid du Colombier Ether *e;
7418cde348aSDavid du Colombier
7428cde348aSDavid du Colombier e = a;
743217e9e83SDavid du Colombier ctlr = e->ctlr;
7448cde348aSDavid du Colombier
7458cde348aSDavid du Colombier /*
7468cde348aSDavid du Colombier * multiple ether addresses can hash to the same filter bit,
7478cde348aSDavid du Colombier * so it's never safe to clear a filter bit.
7488cde348aSDavid du Colombier * if we want to clear filter bits, we need to keep track of
7498cde348aSDavid du Colombier * all the multicast addresses in use, clear all the filter bits,
7508cde348aSDavid du Colombier * then set the ones corresponding to in-use addresses.
7518cde348aSDavid du Colombier */
7528cde348aSDavid du Colombier i = ea[5] >> 1;
7538cde348aSDavid du Colombier b = (ea[5]&1)<<4 | ea[4]>>4;
7548cde348aSDavid du Colombier b = 1 << b;
7558cde348aSDavid du Colombier if(on)
756217e9e83SDavid du Colombier ctlr->mta[i] |= b;
7578cde348aSDavid du Colombier // else
758217e9e83SDavid du Colombier // ctlr->mta[i] &= ~b;
759217e9e83SDavid du Colombier ctlr->reg[Mta+i] = ctlr->mta[i];
7608cde348aSDavid du Colombier }
7618cde348aSDavid du Colombier
7629a3e0102SDavid du Colombier static void
freemem(Ctlr * ctlr)763217e9e83SDavid du Colombier freemem(Ctlr *ctlr)
7649a3e0102SDavid du Colombier {
7659a3e0102SDavid du Colombier Block *b;
7669a3e0102SDavid du Colombier
7679a3e0102SDavid du Colombier while(b = rballoc()){
7689a3e0102SDavid du Colombier b->free = 0;
7699a3e0102SDavid du Colombier freeb(b);
7709a3e0102SDavid du Colombier }
771217e9e83SDavid du Colombier free(ctlr->rdba);
772217e9e83SDavid du Colombier ctlr->rdba = nil;
773217e9e83SDavid du Colombier free(ctlr->tdba);
774217e9e83SDavid du Colombier ctlr->tdba = nil;
775217e9e83SDavid du Colombier free(ctlr->rb);
776217e9e83SDavid du Colombier ctlr->rb = nil;
777217e9e83SDavid du Colombier free(ctlr->tb);
778217e9e83SDavid du Colombier ctlr->tb = nil;
7799a3e0102SDavid du Colombier }
7809a3e0102SDavid du Colombier
7818cde348aSDavid du Colombier static int
detach(Ctlr * ctlr)782217e9e83SDavid du Colombier detach(Ctlr *ctlr)
7838cde348aSDavid du Colombier {
7849a3e0102SDavid du Colombier int i, is598;
7858cde348aSDavid du Colombier
786217e9e83SDavid du Colombier ctlr->reg[Imc] = ~0;
787217e9e83SDavid du Colombier ctlr->reg[Ctrl] |= Rst;
7888cde348aSDavid du Colombier for(i = 0; i < 100; i++){
7898cde348aSDavid du Colombier delay(1);
790217e9e83SDavid du Colombier if((ctlr->reg[Ctrl] & Rst) == 0)
7918cde348aSDavid du Colombier break;
7928cde348aSDavid du Colombier }
7938cde348aSDavid du Colombier if (i >= 100)
7948cde348aSDavid du Colombier return -1;
795217e9e83SDavid du Colombier is598 = (ctlr->type == I82598);
7969a3e0102SDavid du Colombier if (is598) { /* errata */
7978cde348aSDavid du Colombier delay(50);
798217e9e83SDavid du Colombier ctlr->reg[Ecc] &= ~(1<<21 | 1<<18 | 1<<9 | 1<<6);
7999a3e0102SDavid du Colombier }
8008cde348aSDavid du Colombier
8018cde348aSDavid du Colombier /* not cleared by reset; kill it manually. */
8028cde348aSDavid du Colombier for(i = 1; i < 16; i++)
803217e9e83SDavid du Colombier ctlr->reg[is598? Rah98: Rah99] &= ~Enable;
8048cde348aSDavid du Colombier for(i = 0; i < 128; i++)
805217e9e83SDavid du Colombier ctlr->reg[Mta + i] = 0;
8069a3e0102SDavid du Colombier for(i = 1; i < (is598? 640: 128); i++)
807217e9e83SDavid du Colombier ctlr->reg[Vfta + i] = 0;
8089a3e0102SDavid du Colombier
809217e9e83SDavid du Colombier // freemem(ctlr); // TODO
810217e9e83SDavid du Colombier ctlr->attached = 0;
8118cde348aSDavid du Colombier return 0;
8128cde348aSDavid du Colombier }
8138cde348aSDavid du Colombier
8148cde348aSDavid du Colombier static void
shutdown(Ether * e)8158cde348aSDavid du Colombier shutdown(Ether *e)
8168cde348aSDavid du Colombier {
8178cde348aSDavid du Colombier detach(e->ctlr);
8189a3e0102SDavid du Colombier // freemem(e->ctlr);
8198cde348aSDavid du Colombier }
8208cde348aSDavid du Colombier
8218cde348aSDavid du Colombier /* ≤ 20ms */
8228cde348aSDavid du Colombier static ushort
eeread(Ctlr * ctlr,int i)823217e9e83SDavid du Colombier eeread(Ctlr *ctlr, int i)
8248cde348aSDavid du Colombier {
825217e9e83SDavid du Colombier ctlr->reg[Eerd] = EEstart | i<<2;
826217e9e83SDavid du Colombier while((ctlr->reg[Eerd] & EEdone) == 0)
8278cde348aSDavid du Colombier ;
828217e9e83SDavid du Colombier return ctlr->reg[Eerd] >> 16;
8298cde348aSDavid du Colombier }
8308cde348aSDavid du Colombier
8318cde348aSDavid du Colombier static int
eeload(Ctlr * ctlr)832217e9e83SDavid du Colombier eeload(Ctlr *ctlr)
8338cde348aSDavid du Colombier {
8348cde348aSDavid du Colombier ushort u, v, p, l, i, j;
8358cde348aSDavid du Colombier
836217e9e83SDavid du Colombier if((eeread(ctlr, 0) & 0xc0) != 0x40)
8378cde348aSDavid du Colombier return -1;
8388cde348aSDavid du Colombier u = 0;
8398cde348aSDavid du Colombier for(i = 0; i < 0x40; i++)
840217e9e83SDavid du Colombier u += eeread(ctlr, i);
8418cde348aSDavid du Colombier for(i = 3; i < 0xf; i++){
842217e9e83SDavid du Colombier p = eeread(ctlr, i);
843217e9e83SDavid du Colombier l = eeread(ctlr, p++);
8448cde348aSDavid du Colombier if((int)p + l + 1 > 0xffff)
8458cde348aSDavid du Colombier continue;
8468cde348aSDavid du Colombier for(j = p; j < p + l; j++)
847217e9e83SDavid du Colombier u += eeread(ctlr, j);
8488cde348aSDavid du Colombier }
8498cde348aSDavid du Colombier if(u != 0xbaba)
8508cde348aSDavid du Colombier return -1;
851217e9e83SDavid du Colombier if(ctlr->reg[Status] & (1<<3))
852217e9e83SDavid du Colombier u = eeread(ctlr, 10);
8538cde348aSDavid du Colombier else
854217e9e83SDavid du Colombier u = eeread(ctlr, 9);
8558cde348aSDavid du Colombier u++;
8568cde348aSDavid du Colombier for(i = 0; i < Eaddrlen;){
857217e9e83SDavid du Colombier v = eeread(ctlr, u + i/2);
858217e9e83SDavid du Colombier ctlr->ra[i++] = v;
859217e9e83SDavid du Colombier ctlr->ra[i++] = v>>8;
8608cde348aSDavid du Colombier }
861217e9e83SDavid du Colombier ctlr->ra[5] += (ctlr->reg[Status] & 0xc) >> 2;
8628cde348aSDavid du Colombier return 0;
8638cde348aSDavid du Colombier }
8648cde348aSDavid du Colombier
8658cde348aSDavid du Colombier static int
reset(Ctlr * ctlr)866217e9e83SDavid du Colombier reset(Ctlr *ctlr)
8678cde348aSDavid du Colombier {
8689a3e0102SDavid du Colombier int i, is598;
8698cde348aSDavid du Colombier uchar *p;
8708cde348aSDavid du Colombier
871217e9e83SDavid du Colombier if(detach(ctlr)){
8728cde348aSDavid du Colombier print("82598: reset timeout\n");
8738cde348aSDavid du Colombier return -1;
8748cde348aSDavid du Colombier }
875217e9e83SDavid du Colombier if(eeload(ctlr)){
8768cde348aSDavid du Colombier print("82598: eeprom failure\n");
8778cde348aSDavid du Colombier return -1;
8788cde348aSDavid du Colombier }
879217e9e83SDavid du Colombier p = ctlr->ra;
880217e9e83SDavid du Colombier is598 = (ctlr->type == I82598);
881217e9e83SDavid du Colombier ctlr->reg[is598? Ral98: Ral99] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
882217e9e83SDavid du Colombier ctlr->reg[is598? Rah98: Rah99] = p[5]<<8 | p[4] | Enable;
8838cde348aSDavid du Colombier
884217e9e83SDavid du Colombier readstats(ctlr);
885217e9e83SDavid du Colombier for(i = 0; i<nelem(ctlr->stats); i++)
886217e9e83SDavid du Colombier ctlr->stats[i] = 0;
8878cde348aSDavid du Colombier
888217e9e83SDavid du Colombier ctlr->reg[Ctrlext] |= 1 << 16; /* required by errata (spec change 4) */
8899a3e0102SDavid du Colombier if (Goslow) {
8908cde348aSDavid du Colombier /* make some guesses for flow control */
891217e9e83SDavid du Colombier ctlr->reg[Fcrtl] = 0x10000 | Enable;
892217e9e83SDavid du Colombier ctlr->reg[Fcrth] = 0x40000 | Enable;
893217e9e83SDavid du Colombier ctlr->reg[Rcrtv] = 0x6000;
8949a3e0102SDavid du Colombier } else
895217e9e83SDavid du Colombier ctlr->reg[Fcrtl] = ctlr->reg[Fcrth] = ctlr->reg[Rcrtv] = 0;
8968cde348aSDavid du Colombier
8978cde348aSDavid du Colombier /* configure interrupt mapping (don't ask) */
898217e9e83SDavid du Colombier ctlr->reg[Ivar+0] = 0 | 1<<7;
899217e9e83SDavid du Colombier ctlr->reg[Ivar+64/4] = 1 | 1<<7;
900217e9e83SDavid du Colombier // ctlr->reg[Ivar+97/4] = (2 | 1<<7) << (8*(97%4));
9018cde348aSDavid du Colombier
9029a3e0102SDavid du Colombier if (Goslow) {
9038cde348aSDavid du Colombier /* interrupt throttling goes here. */
9048cde348aSDavid du Colombier for(i = Itr; i < Itr + 20; i++)
905217e9e83SDavid du Colombier ctlr->reg[i] = 128; /* ¼µs intervals */
906217e9e83SDavid du Colombier ctlr->reg[Itr + Itx0] = 256;
9079a3e0102SDavid du Colombier } else { /* don't throttle */
9089a3e0102SDavid du Colombier for(i = Itr; i < Itr + 20; i++)
909217e9e83SDavid du Colombier ctlr->reg[i] = 0; /* ¼µs intervals */
910217e9e83SDavid du Colombier ctlr->reg[Itr + Itx0] = 0;
9119a3e0102SDavid du Colombier }
9128cde348aSDavid du Colombier return 0;
9138cde348aSDavid du Colombier }
9148cde348aSDavid du Colombier
9158cde348aSDavid du Colombier static void
txinit(Ctlr * ctlr)916217e9e83SDavid du Colombier txinit(Ctlr *ctlr)
9178cde348aSDavid du Colombier {
9188cde348aSDavid du Colombier Block *b;
9198cde348aSDavid du Colombier int i;
9208cde348aSDavid du Colombier
9219a3e0102SDavid du Colombier if (Goslow)
922217e9e83SDavid du Colombier ctlr->reg[Txdctl] = 16<<Wthresh | 16<<Pthresh;
9239a3e0102SDavid du Colombier else
924217e9e83SDavid du Colombier ctlr->reg[Txdctl] = 0;
925217e9e83SDavid du Colombier if (ctlr->type == I82599)
926217e9e83SDavid du Colombier ctlr->reg[Dtxctl99] = 0;
9279a3e0102SDavid du Colombier coherence();
928217e9e83SDavid du Colombier for(i = 0; i < ctlr->ntd; i++){
929217e9e83SDavid du Colombier b = ctlr->tb[i];
930217e9e83SDavid du Colombier ctlr->tb[i] = 0;
9318cde348aSDavid du Colombier if(b)
9328cde348aSDavid du Colombier freeb(b);
9338cde348aSDavid du Colombier }
9349a3e0102SDavid du Colombier
935217e9e83SDavid du Colombier assert(ctlr->tdba != nil);
936217e9e83SDavid du Colombier memset(ctlr->tdba, 0, ctlr->ntd * sizeof(Td));
937217e9e83SDavid du Colombier ctlr->reg[Tdbal] = PCIWADDR(ctlr->tdba);
938217e9e83SDavid du Colombier ctlr->reg[Tdbah] = 0;
939217e9e83SDavid du Colombier ctlr->reg[Tdlen] = ctlr->ntd*sizeof(Td); /* must be multiple of 128 */
940217e9e83SDavid du Colombier ctlr->reg[Tdh] = 0;
941217e9e83SDavid du Colombier ctlr->tdh = ctlr->ntd - 1;
942217e9e83SDavid du Colombier ctlr->reg[Tdt] = ctlr->tdt = 0;
9439a3e0102SDavid du Colombier coherence();
944217e9e83SDavid du Colombier if (ctlr->type == I82599)
945217e9e83SDavid du Colombier ctlr->reg[Dtxctl99] |= Te;
9469a3e0102SDavid du Colombier coherence();
947217e9e83SDavid du Colombier ctlr->reg[Txdctl] |= Ten;
9489a3e0102SDavid du Colombier coherence();
949217e9e83SDavid du Colombier while (!(ctlr->reg[Txdctl] & Ten))
9509a3e0102SDavid du Colombier ;
9518cde348aSDavid du Colombier }
9528cde348aSDavid du Colombier
9538cde348aSDavid du Colombier static void
attach(Ether * e)9548cde348aSDavid du Colombier attach(Ether *e)
9558cde348aSDavid du Colombier {
9568cde348aSDavid du Colombier Block *b;
957217e9e83SDavid du Colombier Ctlr *ctlr;
9588cde348aSDavid du Colombier char buf[KNAMELEN];
9598cde348aSDavid du Colombier
960217e9e83SDavid du Colombier ctlr = e->ctlr;
961217e9e83SDavid du Colombier ctlr->edev = e; /* point back to Ether* */
962217e9e83SDavid du Colombier qlock(&ctlr->alock);
9638cde348aSDavid du Colombier if(waserror()){
964217e9e83SDavid du Colombier reset(ctlr);
965217e9e83SDavid du Colombier freemem(ctlr);
966217e9e83SDavid du Colombier qunlock(&ctlr->alock);
9678cde348aSDavid du Colombier nexterror();
9688cde348aSDavid du Colombier }
969217e9e83SDavid du Colombier if(ctlr->rdba == nil) {
970217e9e83SDavid du Colombier ctlr->nrd = Nrd;
971217e9e83SDavid du Colombier ctlr->ntd = Ntd;
972217e9e83SDavid du Colombier ctlr->rdba = mallocalign(ctlr->nrd * sizeof *ctlr->rdba,
973217e9e83SDavid du Colombier Descalign, 0, 0);
974217e9e83SDavid du Colombier ctlr->tdba = mallocalign(ctlr->ntd * sizeof *ctlr->tdba,
975217e9e83SDavid du Colombier Descalign, 0, 0);
976217e9e83SDavid du Colombier ctlr->rb = malloc(ctlr->nrd * sizeof(Block *));
977217e9e83SDavid du Colombier ctlr->tb = malloc(ctlr->ntd * sizeof(Block *));
978217e9e83SDavid du Colombier if (ctlr->rdba == nil || ctlr->tdba == nil ||
979217e9e83SDavid du Colombier ctlr->rb == nil || ctlr->tb == nil)
9809a3e0102SDavid du Colombier error(Enomem);
9819a3e0102SDavid du Colombier
982217e9e83SDavid du Colombier for(ctlr->nrb = 0; ctlr->nrb < 2*Nrb; ctlr->nrb++){
983217e9e83SDavid du Colombier b = allocb(ctlr->rbsz + BY2PG); /* see rbfree() */
984830f0b04SDavid du Colombier if(b == nil)
9858cde348aSDavid du Colombier error(Enomem);
9868cde348aSDavid du Colombier b->free = rbfree;
9878cde348aSDavid du Colombier freeb(b);
9888cde348aSDavid du Colombier }
9899a3e0102SDavid du Colombier }
990217e9e83SDavid du Colombier if (!ctlr->attached) {
991217e9e83SDavid du Colombier rxinit(ctlr);
992217e9e83SDavid du Colombier txinit(ctlr);
993217e9e83SDavid du Colombier nrbfull = 0;
994217e9e83SDavid du Colombier if (!ctlr->procsrunning) {
99580dab12eSDavid du Colombier snprint(buf, sizeof buf, "#l%dl", e->ctlrno);
9968cde348aSDavid du Colombier kproc(buf, lproc, e);
99780dab12eSDavid du Colombier snprint(buf, sizeof buf, "#l%dr", e->ctlrno);
9988cde348aSDavid du Colombier kproc(buf, rproc, e);
99980dab12eSDavid du Colombier snprint(buf, sizeof buf, "#l%dt", e->ctlrno);
10008cde348aSDavid du Colombier kproc(buf, tproc, e);
1001217e9e83SDavid du Colombier ctlr->procsrunning = 1;
10029a3e0102SDavid du Colombier }
1003217e9e83SDavid du Colombier initmark(&ctlr->wmrb, Nrb, "rcv bufs unprocessed");
1004217e9e83SDavid du Colombier initmark(&ctlr->wmrd, Nrd-1, "rcv descrs processed at once");
1005217e9e83SDavid du Colombier initmark(&ctlr->wmtd, Ntd-1, "xmit descr queue len");
1006217e9e83SDavid du Colombier ctlr->attached = 1;
10079a3e0102SDavid du Colombier }
1008217e9e83SDavid du Colombier qunlock(&ctlr->alock);
10099a3e0102SDavid du Colombier poperror();
10108cde348aSDavid du Colombier }
10118cde348aSDavid du Colombier
10128cde348aSDavid du Colombier static void
interrupt(Ureg *,void * v)10138cde348aSDavid du Colombier interrupt(Ureg*, void *v)
10148cde348aSDavid du Colombier {
10158cde348aSDavid du Colombier int icr, im;
1016217e9e83SDavid du Colombier Ctlr *ctlr;
10178cde348aSDavid du Colombier Ether *e;
10188cde348aSDavid du Colombier
10198cde348aSDavid du Colombier e = v;
1020217e9e83SDavid du Colombier ctlr = e->ctlr;
1021217e9e83SDavid du Colombier ilock(&ctlr->imlock);
1022217e9e83SDavid du Colombier ctlr->reg[Imc] = ~0; /* disable all intrs */
1023217e9e83SDavid du Colombier im = ctlr->im;
1024217e9e83SDavid du Colombier while((icr = ctlr->reg[Icr] & ctlr->im) != 0){
10258cde348aSDavid du Colombier if(icr & Irx0){
10268cde348aSDavid du Colombier im &= ~Irx0;
1027217e9e83SDavid du Colombier ctlr->rim = Irx0;
1028217e9e83SDavid du Colombier wakeup(&ctlr->rrendez);
10298cde348aSDavid du Colombier }
10308cde348aSDavid du Colombier if(icr & Itx0){
10318cde348aSDavid du Colombier im &= ~Itx0;
1032217e9e83SDavid du Colombier ctlr->tim = Itx0;
1033217e9e83SDavid du Colombier wakeup(&ctlr->trendez);
10348cde348aSDavid du Colombier }
10359a3e0102SDavid du Colombier if(icr & Lsc){
10369a3e0102SDavid du Colombier im &= ~Lsc;
1037217e9e83SDavid du Colombier ctlr->lim = Lsc;
1038217e9e83SDavid du Colombier wakeup(&ctlr->lrendez);
10398cde348aSDavid du Colombier }
10409a3e0102SDavid du Colombier }
1041217e9e83SDavid du Colombier ctlr->reg[Ims] = ctlr->im = im; /* enable only intrs we didn't service */
1042217e9e83SDavid du Colombier iunlock(&ctlr->imlock);
10438cde348aSDavid du Colombier }
10448cde348aSDavid du Colombier
10458cde348aSDavid du Colombier static void
scan(void)10468cde348aSDavid du Colombier scan(void)
10478cde348aSDavid du Colombier {
10489a3e0102SDavid du Colombier int pciregs, pcimsix, type;
1049830f0b04SDavid du Colombier ulong io, iomsi;
1050830f0b04SDavid du Colombier void *mem, *memmsi;
1051217e9e83SDavid du Colombier Ctlr *ctlr;
10528cde348aSDavid du Colombier Pcidev *p;
10538cde348aSDavid du Colombier
10548cde348aSDavid du Colombier p = 0;
1055830f0b04SDavid du Colombier while(p = pcimatch(p, Vintel, 0)){
10568cde348aSDavid du Colombier switch(p->did){
10579a3e0102SDavid du Colombier case 0x10b6: /* 82598 backplane */
10588cde348aSDavid du Colombier case 0x10c6: /* 82598 af dual port */
10598cde348aSDavid du Colombier case 0x10c7: /* 82598 af single port */
10608cde348aSDavid du Colombier case 0x10dd: /* 82598 at cx4 */
1061e464c1a8SDavid du Colombier case 0x10ec: /* 82598 at cx4 dual port */
1062830f0b04SDavid du Colombier pcimsix = 3;
10639a3e0102SDavid du Colombier type = I82598;
1064830f0b04SDavid du Colombier break;
10659a3e0102SDavid du Colombier case 0x10f7: /* 82599 kx/kx4 */
10669a3e0102SDavid du Colombier case 0x10f8: /* 82599 kx/kx4/kx */
10679a3e0102SDavid du Colombier case 0x10f9: /* 82599 cx4 */
10689a3e0102SDavid du Colombier case 0x10fb: /* 82599 sfi/sfp+ */
10699a3e0102SDavid du Colombier case 0x10fc: /* 82599 xaui/bx4 */
10709a3e0102SDavid du Colombier case 0x1557: /* 82599 single-port sfi */
1071830f0b04SDavid du Colombier pcimsix = 4;
10729a3e0102SDavid du Colombier type = I82599;
10738cde348aSDavid du Colombier break;
10748cde348aSDavid du Colombier default:
10758cde348aSDavid du Colombier continue;
10768cde348aSDavid du Colombier }
1077830f0b04SDavid du Colombier pciregs = 0;
1078217e9e83SDavid du Colombier if(nctlr >= nelem(ctlrtab)){
10798cde348aSDavid du Colombier print("i82598: too many controllers\n");
10808cde348aSDavid du Colombier return;
10818cde348aSDavid du Colombier }
1082830f0b04SDavid du Colombier
1083830f0b04SDavid du Colombier io = p->mem[pciregs].bar & ~0xf;
1084830f0b04SDavid du Colombier mem = vmap(io, p->mem[pciregs].size);
10858cde348aSDavid du Colombier if(mem == nil){
1086830f0b04SDavid du Colombier print("i82598: can't map regs %#p\n",
1087830f0b04SDavid du Colombier p->mem[pciregs].bar);
10888cde348aSDavid du Colombier continue;
10898cde348aSDavid du Colombier }
1090830f0b04SDavid du Colombier
1091830f0b04SDavid du Colombier iomsi = p->mem[pcimsix].bar & ~0xf;
1092830f0b04SDavid du Colombier memmsi = vmap(iomsi, p->mem[pcimsix].size);
1093830f0b04SDavid du Colombier if(memmsi == nil){
1094830f0b04SDavid du Colombier print("i82598: can't map msi-x regs %#p\n",
1095830f0b04SDavid du Colombier p->mem[pcimsix].bar);
1096830f0b04SDavid du Colombier vunmap(mem, p->mem[pciregs].size);
10978cde348aSDavid du Colombier continue;
10988cde348aSDavid du Colombier }
1099830f0b04SDavid du Colombier
1100217e9e83SDavid du Colombier ctlr = malloc(sizeof *ctlr);
1101217e9e83SDavid du Colombier if(ctlr == nil) {
1102830f0b04SDavid du Colombier vunmap(mem, p->mem[pciregs].size);
1103830f0b04SDavid du Colombier vunmap(memmsi, p->mem[pcimsix].size);
1104aa72973aSDavid du Colombier error(Enomem);
1105aa72973aSDavid du Colombier }
1106217e9e83SDavid du Colombier ctlr->p = p;
1107217e9e83SDavid du Colombier ctlr->type = type;
1108217e9e83SDavid du Colombier ctlr->physreg = (u32int*)io;
1109217e9e83SDavid du Colombier ctlr->physmsix = (u32int*)iomsi;
1110217e9e83SDavid du Colombier ctlr->reg = (u32int*)mem;
1111217e9e83SDavid du Colombier ctlr->msix = (u32int*)memmsi; /* unused */
1112217e9e83SDavid du Colombier ctlr->rbsz = Rbsz;
1113217e9e83SDavid du Colombier if(reset(ctlr)){
11148cde348aSDavid du Colombier print("i82598: can't reset\n");
1115217e9e83SDavid du Colombier free(ctlr);
1116830f0b04SDavid du Colombier vunmap(mem, p->mem[pciregs].size);
1117830f0b04SDavid du Colombier vunmap(memmsi, p->mem[pcimsix].size);
11188cde348aSDavid du Colombier continue;
11198cde348aSDavid du Colombier }
11208cde348aSDavid du Colombier pcisetbme(p);
1121217e9e83SDavid du Colombier ctlrtab[nctlr++] = ctlr;
11228cde348aSDavid du Colombier }
11238cde348aSDavid du Colombier }
11248cde348aSDavid du Colombier
11258cde348aSDavid du Colombier static int
pnp(Ether * e)11268cde348aSDavid du Colombier pnp(Ether *e)
11278cde348aSDavid du Colombier {
11288cde348aSDavid du Colombier int i;
1129217e9e83SDavid du Colombier Ctlr *ctlr;
11308cde348aSDavid du Colombier
11318cde348aSDavid du Colombier if(nctlr == 0)
11328cde348aSDavid du Colombier scan();
1133217e9e83SDavid du Colombier ctlr = nil;
11348cde348aSDavid du Colombier for(i = 0; i < nctlr; i++){
1135217e9e83SDavid du Colombier ctlr = ctlrtab[i];
1136217e9e83SDavid du Colombier if(ctlr == nil || ctlr->flag & Factive)
11378cde348aSDavid du Colombier continue;
1138217e9e83SDavid du Colombier if(e->port == 0 || e->port == (ulong)ctlr->reg)
11398cde348aSDavid du Colombier break;
11408cde348aSDavid du Colombier }
11418cde348aSDavid du Colombier if (i >= nctlr)
11428cde348aSDavid du Colombier return -1;
1143217e9e83SDavid du Colombier ctlr->flag |= Factive;
1144217e9e83SDavid du Colombier e->ctlr = ctlr;
1145217e9e83SDavid du Colombier e->port = (uintptr)ctlr->physreg;
1146217e9e83SDavid du Colombier e->irq = ctlr->p->intl;
1147217e9e83SDavid du Colombier e->tbdf = ctlr->p->tbdf;
11488cde348aSDavid du Colombier e->mbps = 10000;
11499a3e0102SDavid du Colombier e->maxmtu = ETHERMAXTU;
1150217e9e83SDavid du Colombier memmove(e->ea, ctlr->ra, Eaddrlen);
11516083aa43SDavid du Colombier
11528cde348aSDavid du Colombier e->arg = e;
11538cde348aSDavid du Colombier e->attach = attach;
11546083aa43SDavid du Colombier e->detach = shutdown;
11556083aa43SDavid du Colombier e->transmit = transmit;
11568cde348aSDavid du Colombier e->interrupt = interrupt;
11576083aa43SDavid du Colombier e->ifstat = ifstat;
11586083aa43SDavid du Colombier e->shutdown = shutdown;
11596083aa43SDavid du Colombier e->ctl = ctl;
11608cde348aSDavid du Colombier e->multicast = multicast;
11618cde348aSDavid du Colombier e->promiscuous = promiscuous;
11628cde348aSDavid du Colombier
11638cde348aSDavid du Colombier return 0;
11648cde348aSDavid du Colombier }
11658cde348aSDavid du Colombier
11668cde348aSDavid du Colombier void
ether82598link(void)11678cde348aSDavid du Colombier ether82598link(void)
11688cde348aSDavid du Colombier {
11698cde348aSDavid du Colombier addethercard("i82598", pnp);
1170217e9e83SDavid du Colombier addethercard("i10gbe", pnp);
11718cde348aSDavid du Colombier }
1172