1901484c1SDavid du Colombier /*
2d5789509SDavid du Colombier * myricom 10g-pcie-8a 10 Gb ethernet driver
3901484c1SDavid du Colombier * © 2007 erik quanstrom, coraid
441ac1ab6SDavid du Colombier *
541ac1ab6SDavid du Colombier * the card is big endian.
691b330d9SDavid du Colombier * we use uvlong rather than uintptr to hold addresses so that
741ac1ab6SDavid du Colombier * we don't get "warning: stupid shift" on 32-bit architectures.
8217e9e83SDavid du Colombier *
9217e9e83SDavid du Colombier * appears to have massively-bloated buffers.
10901484c1SDavid du Colombier */
11901484c1SDavid du Colombier #include "u.h"
12901484c1SDavid du Colombier #include "../port/lib.h"
13901484c1SDavid du Colombier #include "mem.h"
14901484c1SDavid du Colombier #include "dat.h"
15901484c1SDavid du Colombier #include "fns.h"
16901484c1SDavid du Colombier #include "io.h"
17901484c1SDavid du Colombier #include "../port/error.h"
18901484c1SDavid du Colombier #include "../port/netif.h"
19901484c1SDavid du Colombier
2041ac1ab6SDavid du Colombier #include "../pc/etherif.h"
21901484c1SDavid du Colombier
2241ac1ab6SDavid du Colombier #ifndef KiB
2341ac1ab6SDavid du Colombier #define KiB 1024u /* Kibi 0x0000000000000400 */
2441ac1ab6SDavid du Colombier #define MiB 1048576u /* Mebi 0x0000000000100000 */
2541ac1ab6SDavid du Colombier #endif /* KiB */
26901484c1SDavid du Colombier
27901484c1SDavid du Colombier #define dprint(...) if(debug) print(__VA_ARGS__)
28901484c1SDavid du Colombier #define pcicapdbg(...)
2941ac1ab6SDavid du Colombier #define malign(n) mallocalign((n), 4*KiB, 0, 0)
30901484c1SDavid du Colombier
31*54d7663aSDavid du Colombier #include "etherm10g2k.h"
32*54d7663aSDavid du Colombier #include "etherm10g4k.h"
33901484c1SDavid du Colombier
34901484c1SDavid du Colombier static int debug = 0;
35901484c1SDavid du Colombier static char Etimeout[] = "timeout";
36901484c1SDavid du Colombier
37901484c1SDavid du Colombier enum {
38901484c1SDavid du Colombier Epromsz = 256,
39217e9e83SDavid du Colombier Maxslots= 1024, /* rcv descriptors; wasteful: only 9 needed */
40901484c1SDavid du Colombier Align = 4096,
41217e9e83SDavid du Colombier Maxmtu = 9000, /* jumbos; bad idea */
42901484c1SDavid du Colombier Noconf = 0xffffffff,
43901484c1SDavid du Colombier
4441ac1ab6SDavid du Colombier Fwoffset= 1*MiB,
45901484c1SDavid du Colombier Cmdoff = 0xf80000, /* command port offset */
46901484c1SDavid du Colombier Fwsubmt = 0xfc0000, /* firmware submission command port offset */
47901484c1SDavid du Colombier Rdmaoff = 0xfc01c0, /* rdma command port offset */
48901484c1SDavid du Colombier };
49901484c1SDavid du Colombier
50901484c1SDavid du Colombier enum {
51901484c1SDavid du Colombier CZero,
52901484c1SDavid du Colombier Creset,
53901484c1SDavid du Colombier Cversion,
54901484c1SDavid du Colombier
55901484c1SDavid du Colombier CSintrqdma, /* issue these before Cetherup */
56901484c1SDavid du Colombier CSbigsz, /* in bytes bigsize = 2^n */
57901484c1SDavid du Colombier CSsmallsz,
58901484c1SDavid du Colombier
59901484c1SDavid du Colombier CGsendoff,
60901484c1SDavid du Colombier CGsmallrxoff,
61901484c1SDavid du Colombier CGbigrxoff,
62901484c1SDavid du Colombier CGirqackoff,
63901484c1SDavid du Colombier CGirqdeassoff,
64901484c1SDavid du Colombier CGsendrgsz,
65901484c1SDavid du Colombier CGrxrgsz,
66901484c1SDavid du Colombier
67901484c1SDavid du Colombier CSintrqsz, /* 2^n */
68901484c1SDavid du Colombier Cetherup, /* above parameters + mtu/mac addr must be set first. */
69901484c1SDavid du Colombier Cetherdn,
70901484c1SDavid du Colombier
71901484c1SDavid du Colombier CSmtu, /* below may be issued live */
72901484c1SDavid du Colombier CGcoaloff, /* in µs */
73901484c1SDavid du Colombier CSstatsrate, /* in µs */
74901484c1SDavid du Colombier CSstatsdma,
75901484c1SDavid du Colombier
76901484c1SDavid du Colombier Cpromisc,
77901484c1SDavid du Colombier Cnopromisc,
78901484c1SDavid du Colombier CSmac,
79901484c1SDavid du Colombier
80901484c1SDavid du Colombier Cenablefc,
81901484c1SDavid du Colombier Cdisablefc,
82901484c1SDavid du Colombier
83901484c1SDavid du Colombier Cdmatest, /* address in d[0-1], d[2]=length */
84901484c1SDavid du Colombier
85901484c1SDavid du Colombier Cenableallmc,
86901484c1SDavid du Colombier Cdisableallmc,
87901484c1SDavid du Colombier
88901484c1SDavid du Colombier CSjoinmc,
89901484c1SDavid du Colombier CSleavemc,
90901484c1SDavid du Colombier Cleaveallmc,
91901484c1SDavid du Colombier
92901484c1SDavid du Colombier CSstatsdma2, /* adds (unused) multicast stats */
93901484c1SDavid du Colombier };
94901484c1SDavid du Colombier
95901484c1SDavid du Colombier typedef union {
96901484c1SDavid du Colombier uint i[2];
97901484c1SDavid du Colombier uchar c[8];
98901484c1SDavid du Colombier } Cmd;
99901484c1SDavid du Colombier
10041ac1ab6SDavid du Colombier typedef ulong Slot;
101901484c1SDavid du Colombier typedef struct {
10291b330d9SDavid du Colombier ushort cksum;
10391b330d9SDavid du Colombier ushort len;
10441ac1ab6SDavid du Colombier } Slotparts;
105901484c1SDavid du Colombier
106901484c1SDavid du Colombier enum {
107901484c1SDavid du Colombier SFsmall = 1,
108901484c1SDavid du Colombier SFfirst = 2,
109901484c1SDavid du Colombier SFalign = 4,
110901484c1SDavid du Colombier SFnotso = 16,
111901484c1SDavid du Colombier };
112901484c1SDavid du Colombier
113901484c1SDavid du Colombier typedef struct {
11491b330d9SDavid du Colombier ulong high;
11591b330d9SDavid du Colombier ulong low;
11691b330d9SDavid du Colombier ushort hdroff;
11791b330d9SDavid du Colombier ushort len;
118901484c1SDavid du Colombier uchar pad;
119901484c1SDavid du Colombier uchar nrdma;
120901484c1SDavid du Colombier uchar chkoff;
121901484c1SDavid du Colombier uchar flags;
122901484c1SDavid du Colombier } Send;
123901484c1SDavid du Colombier
124901484c1SDavid du Colombier typedef struct {
125901484c1SDavid du Colombier QLock;
126901484c1SDavid du Colombier Send *lanai; /* tx ring (cksum+len in lanai memory) */
127901484c1SDavid du Colombier Send *host; /* tx ring (data in our memory) */
128901484c1SDavid du Colombier Block **bring;
129901484c1SDavid du Colombier // uchar *wcfifo; /* what the heck is a w/c fifo? */
130901484c1SDavid du Colombier int size; /* of buffers in the z8's memory */
13191b330d9SDavid du Colombier ulong segsz;
132901484c1SDavid du Colombier uint n; /* rxslots */
133901484c1SDavid du Colombier uint m; /* mask; rxslots must be a power of two */
134901484c1SDavid du Colombier uint i; /* number of segments (not frames) queued */
135901484c1SDavid du Colombier uint cnt; /* number of segments sent by the card */
136901484c1SDavid du Colombier
137901484c1SDavid du Colombier ulong npkt;
138901484c1SDavid du Colombier vlong nbytes;
139901484c1SDavid du Colombier } Tx;
140901484c1SDavid du Colombier
141901484c1SDavid du Colombier typedef struct {
142901484c1SDavid du Colombier Lock;
143901484c1SDavid du Colombier Block *head;
144901484c1SDavid du Colombier uint size; /* buffer size of each block */
145901484c1SDavid du Colombier uint n; /* n free buffers */
146901484c1SDavid du Colombier uint cnt;
147901484c1SDavid du Colombier } Bpool;
148901484c1SDavid du Colombier
14941ac1ab6SDavid du Colombier static Bpool smpool = { .size = 128, };
15041ac1ab6SDavid du Colombier static Bpool bgpool = { .size = Maxmtu, };
151901484c1SDavid du Colombier
152901484c1SDavid du Colombier typedef struct {
153901484c1SDavid du Colombier Bpool *pool; /* free buffers */
15491b330d9SDavid du Colombier ulong *lanai; /* rx ring; we have no permanent host shadow */
155901484c1SDavid du Colombier Block **host; /* called "info" in myricom driver */
156901484c1SDavid du Colombier // uchar *wcfifo; /* cmd submission fifo */
157901484c1SDavid du Colombier uint m;
158901484c1SDavid du Colombier uint n; /* rxslots */
159901484c1SDavid du Colombier uint i;
160901484c1SDavid du Colombier uint cnt; /* number of buffers allocated (lifetime) */
161901484c1SDavid du Colombier uint allocfail;
162901484c1SDavid du Colombier } Rx;
163901484c1SDavid du Colombier
164901484c1SDavid du Colombier /* dma mapped. unix network byte order. */
165901484c1SDavid du Colombier typedef struct {
166901484c1SDavid du Colombier uchar txcnt[4];
167901484c1SDavid du Colombier uchar linkstat[4];
168901484c1SDavid du Colombier uchar dlink[4];
169901484c1SDavid du Colombier uchar derror[4];
170901484c1SDavid du Colombier uchar drunt[4];
171901484c1SDavid du Colombier uchar doverrun[4];
172901484c1SDavid du Colombier uchar dnosm[4];
173901484c1SDavid du Colombier uchar dnobg[4];
174901484c1SDavid du Colombier uchar nrdma[4];
175901484c1SDavid du Colombier uchar txstopped;
176901484c1SDavid du Colombier uchar down;
177901484c1SDavid du Colombier uchar updated;
178901484c1SDavid du Colombier uchar valid;
179901484c1SDavid du Colombier } Stats;
180901484c1SDavid du Colombier
181901484c1SDavid du Colombier enum {
182901484c1SDavid du Colombier Detached,
183901484c1SDavid du Colombier Attached,
184901484c1SDavid du Colombier Runed,
185901484c1SDavid du Colombier };
186901484c1SDavid du Colombier
187901484c1SDavid du Colombier typedef struct {
188901484c1SDavid du Colombier Slot *entry;
18991b330d9SDavid du Colombier uvlong busaddr;
190901484c1SDavid du Colombier uint m;
191901484c1SDavid du Colombier uint n;
192901484c1SDavid du Colombier uint i;
193901484c1SDavid du Colombier } Done;
194901484c1SDavid du Colombier
195901484c1SDavid du Colombier typedef struct Ctlr Ctlr;
196901484c1SDavid du Colombier typedef struct Ctlr {
197901484c1SDavid du Colombier QLock;
198901484c1SDavid du Colombier int state;
199901484c1SDavid du Colombier int kprocs;
20091b330d9SDavid du Colombier uvlong port;
201901484c1SDavid du Colombier Pcidev* pcidev;
202901484c1SDavid du Colombier Ctlr* next;
203901484c1SDavid du Colombier int active;
204901484c1SDavid du Colombier int id; /* do we need this? */
205901484c1SDavid du Colombier
206901484c1SDavid du Colombier uchar ra[Eaddrlen];
207901484c1SDavid du Colombier
208901484c1SDavid du Colombier int ramsz;
209901484c1SDavid du Colombier uchar *ram;
210901484c1SDavid du Colombier
21191b330d9SDavid du Colombier ulong *irqack;
21291b330d9SDavid du Colombier ulong *irqdeass;
21391b330d9SDavid du Colombier ulong *coal;
214901484c1SDavid du Colombier
215901484c1SDavid du Colombier char eprom[Epromsz];
216901484c1SDavid du Colombier ulong serial; /* unit serial number */
217901484c1SDavid du Colombier
218901484c1SDavid du Colombier QLock cmdl;
219901484c1SDavid du Colombier Cmd *cmd; /* address of command return */
22091b330d9SDavid du Colombier uvlong cprt; /* bus address of command */
221901484c1SDavid du Colombier
22291b330d9SDavid du Colombier uvlong boot; /* boot address */
223901484c1SDavid du Colombier
224901484c1SDavid du Colombier Done done;
225901484c1SDavid du Colombier Tx tx;
226901484c1SDavid du Colombier Rx sm;
227901484c1SDavid du Colombier Rx bg;
228901484c1SDavid du Colombier Stats *stats;
22991b330d9SDavid du Colombier uvlong statsprt;
230901484c1SDavid du Colombier
231901484c1SDavid du Colombier Rendez rxrendez;
232901484c1SDavid du Colombier Rendez txrendez;
233901484c1SDavid du Colombier
234901484c1SDavid du Colombier int msi;
23591b330d9SDavid du Colombier ulong linkstat;
23691b330d9SDavid du Colombier ulong nrdma;
237901484c1SDavid du Colombier } Ctlr;
238901484c1SDavid du Colombier
239901484c1SDavid du Colombier static Ctlr *ctlrs;
240901484c1SDavid du Colombier
241901484c1SDavid du Colombier enum {
242901484c1SDavid du Colombier PcieAERC = 1,
243901484c1SDavid du Colombier PcieVC,
244901484c1SDavid du Colombier PcieSNC,
245901484c1SDavid du Colombier PciePBC,
246901484c1SDavid du Colombier };
247901484c1SDavid du Colombier
248901484c1SDavid du Colombier enum {
249901484c1SDavid du Colombier AercCCR = 0x18, /* control register */
250901484c1SDavid du Colombier };
251901484c1SDavid du Colombier
252901484c1SDavid du Colombier enum {
253901484c1SDavid du Colombier PcieCTL = 8,
254901484c1SDavid du Colombier PcieLCR = 12,
255901484c1SDavid du Colombier PcieMRD = 0x7000, /* maximum read size */
256901484c1SDavid du Colombier };
257901484c1SDavid du Colombier
258901484c1SDavid du Colombier /*
259901484c1SDavid du Colombier * this function doesn't work because pcicgr32 doesn't have access
260901484c1SDavid du Colombier * to the pcie extended configuration space.
261901484c1SDavid du Colombier */
26241ac1ab6SDavid du Colombier static int
pciecap(Pcidev * p,int cap)263901484c1SDavid du Colombier pciecap(Pcidev *p, int cap)
264901484c1SDavid du Colombier {
265901484c1SDavid du Colombier uint off, i;
266901484c1SDavid du Colombier
267901484c1SDavid du Colombier off = 0x100;
268901484c1SDavid du Colombier while(((i = pcicfgr32(p, off)) & 0xffff) != cap){
269901484c1SDavid du Colombier off = i >> 20;
27080088de7SDavid du Colombier print("m10g: pciecap offset = %ud", off);
27141ac1ab6SDavid du Colombier if(off < 0x100 || off >= 4*KiB - 1)
272901484c1SDavid du Colombier return 0;
273901484c1SDavid du Colombier }
27480088de7SDavid du Colombier print("m10g: pciecap found = %ud", off);
275901484c1SDavid du Colombier return off;
276901484c1SDavid du Colombier }
277901484c1SDavid du Colombier
278901484c1SDavid du Colombier static int
setpcie(Pcidev * p)279901484c1SDavid du Colombier setpcie(Pcidev *p)
280901484c1SDavid du Colombier {
281901484c1SDavid du Colombier int off;
282901484c1SDavid du Colombier
283901484c1SDavid du Colombier /* set 4k writes */
284901484c1SDavid du Colombier off = pcicap(p, PciCapPCIe);
285901484c1SDavid du Colombier if(off < 64)
286901484c1SDavid du Colombier return -1;
287901484c1SDavid du Colombier off += PcieCTL;
288901484c1SDavid du Colombier pcicfgw16(p, off, (pcicfgr16(p, off) & ~PcieMRD) | 5<<12);
289901484c1SDavid du Colombier return 0;
290901484c1SDavid du Colombier }
291901484c1SDavid du Colombier
292901484c1SDavid du Colombier static int
whichfw(Pcidev * p)293901484c1SDavid du Colombier whichfw(Pcidev *p)
294901484c1SDavid du Colombier {
295901484c1SDavid du Colombier char *s;
296901484c1SDavid du Colombier int i, off, lanes, ecrc;
29791b330d9SDavid du Colombier ulong cap;
298901484c1SDavid du Colombier
299901484c1SDavid du Colombier /* check the number of configured lanes. */
300901484c1SDavid du Colombier off = pcicap(p, PciCapPCIe);
301901484c1SDavid du Colombier if(off < 64)
302901484c1SDavid du Colombier return -1;
303901484c1SDavid du Colombier off += PcieLCR;
304901484c1SDavid du Colombier cap = pcicfgr16(p, off);
305901484c1SDavid du Colombier lanes = (cap>>4) & 0x3f;
306901484c1SDavid du Colombier
307901484c1SDavid du Colombier /* check AERC register. we need it on. */
308901484c1SDavid du Colombier off = pciecap(p, PcieAERC);
30980088de7SDavid du Colombier print("; offset %d returned\n", off);
310901484c1SDavid du Colombier cap = 0;
311901484c1SDavid du Colombier if(off != 0){
312901484c1SDavid du Colombier off += AercCCR;
313901484c1SDavid du Colombier cap = pcicfgr32(p, off);
31480088de7SDavid du Colombier print("m10g: %lud cap\n", cap);
315901484c1SDavid du Colombier }
316901484c1SDavid du Colombier ecrc = (cap>>4) & 0xf;
317901484c1SDavid du Colombier /* if we don't like the aerc, kick it here. */
318901484c1SDavid du Colombier
31980088de7SDavid du Colombier print("m10g: %d lanes; ecrc=%d; ", lanes, ecrc);
320901484c1SDavid du Colombier if(s = getconf("myriforce")){
321901484c1SDavid du Colombier i = atoi(s);
32241ac1ab6SDavid du Colombier if(i != 4*KiB || i != 2*KiB)
32341ac1ab6SDavid du Colombier i = 2*KiB;
324901484c1SDavid du Colombier print("fw = %d [forced]\n", i);
325901484c1SDavid du Colombier return i;
326901484c1SDavid du Colombier }
327d5789509SDavid du Colombier if(lanes <= 4)
328901484c1SDavid du Colombier print("fw = 4096 [lanes]\n");
329d5789509SDavid du Colombier else if(ecrc & 10)
330901484c1SDavid du Colombier print("fw = 4096 [ecrc set]\n");
331d5789509SDavid du Colombier else
332901484c1SDavid du Colombier print("fw = 4096 [default]\n");
33341ac1ab6SDavid du Colombier return 4*KiB;
334901484c1SDavid du Colombier }
335901484c1SDavid du Colombier
336901484c1SDavid du Colombier static int
parseeprom(Ctlr * c)337901484c1SDavid du Colombier parseeprom(Ctlr *c)
338901484c1SDavid du Colombier {
339901484c1SDavid du Colombier int i, j, k, l, bits;
340901484c1SDavid du Colombier char *s;
341901484c1SDavid du Colombier
342901484c1SDavid du Colombier dprint("m10g eprom:\n");
343901484c1SDavid du Colombier s = c->eprom;
344901484c1SDavid du Colombier bits = 3;
345901484c1SDavid du Colombier for(i = 0; s[i] && i < Epromsz; i++){
346901484c1SDavid du Colombier l = strlen(s+i);
347901484c1SDavid du Colombier dprint("\t%s\n", s+i);
348901484c1SDavid du Colombier if(strncmp(s+i, "MAC=", 4) == 0 && l == 4+12+5){
349901484c1SDavid du Colombier bits ^= 1;
350901484c1SDavid du Colombier j = i + 4;
351901484c1SDavid du Colombier for(k = 0; k < 6; k++)
352901484c1SDavid du Colombier c->ra[k] = strtoul(s+j+3*k, 0, 16);
353901484c1SDavid du Colombier }else if(strncmp(s+i, "SN=", 3) == 0){
354901484c1SDavid du Colombier bits ^= 2;
355901484c1SDavid du Colombier c->serial = atoi(s+i+3);
356901484c1SDavid du Colombier }
357901484c1SDavid du Colombier i += l;
358901484c1SDavid du Colombier }
359901484c1SDavid du Colombier if(bits)
360901484c1SDavid du Colombier return -1;
361901484c1SDavid du Colombier return 0;
362901484c1SDavid du Colombier }
363901484c1SDavid du Colombier
36491b330d9SDavid du Colombier static ushort
pbit16(ushort i)36591b330d9SDavid du Colombier pbit16(ushort i)
366901484c1SDavid du Colombier {
36791b330d9SDavid du Colombier ushort j;
368901484c1SDavid du Colombier uchar *p;
369901484c1SDavid du Colombier
370901484c1SDavid du Colombier p = (uchar*)&j;
371901484c1SDavid du Colombier p[1] = i;
372901484c1SDavid du Colombier p[0] = i>>8;
373901484c1SDavid du Colombier return j;
374901484c1SDavid du Colombier }
375901484c1SDavid du Colombier
37691b330d9SDavid du Colombier static ushort
gbit16(uchar i[2])377901484c1SDavid du Colombier gbit16(uchar i[2])
378901484c1SDavid du Colombier {
37991b330d9SDavid du Colombier ushort j;
380901484c1SDavid du Colombier
381901484c1SDavid du Colombier j = i[1];
382901484c1SDavid du Colombier j |= i[0]<<8;
383901484c1SDavid du Colombier return j;
384901484c1SDavid du Colombier }
385901484c1SDavid du Colombier
38691b330d9SDavid du Colombier static ulong
pbit32(ulong i)38791b330d9SDavid du Colombier pbit32(ulong i)
388901484c1SDavid du Colombier {
38991b330d9SDavid du Colombier ulong j;
390901484c1SDavid du Colombier uchar *p;
391901484c1SDavid du Colombier
392901484c1SDavid du Colombier p = (uchar*)&j;
393901484c1SDavid du Colombier p[3] = i;
394901484c1SDavid du Colombier p[2] = i>>8;
395901484c1SDavid du Colombier p[1] = i>>16;
396901484c1SDavid du Colombier p[0] = i>>24;
397901484c1SDavid du Colombier return j;
398901484c1SDavid du Colombier }
399901484c1SDavid du Colombier
40091b330d9SDavid du Colombier static ulong
gbit32(uchar i[4])401901484c1SDavid du Colombier gbit32(uchar i[4])
402901484c1SDavid du Colombier {
40391b330d9SDavid du Colombier ulong j;
404901484c1SDavid du Colombier
405901484c1SDavid du Colombier j = i[3];
406901484c1SDavid du Colombier j |= i[2]<<8;
407901484c1SDavid du Colombier j |= i[1]<<16;
408901484c1SDavid du Colombier j |= i[0]<<24;
409901484c1SDavid du Colombier return j;
410901484c1SDavid du Colombier }
411901484c1SDavid du Colombier
412901484c1SDavid du Colombier static void
prepcmd(ulong * cmd,int i)41391b330d9SDavid du Colombier prepcmd(ulong *cmd, int i)
414901484c1SDavid du Colombier {
415901484c1SDavid du Colombier while(i-- > 0)
416901484c1SDavid du Colombier cmd[i] = pbit32(cmd[i]);
417901484c1SDavid du Colombier }
418901484c1SDavid du Colombier
419901484c1SDavid du Colombier /*
420901484c1SDavid du Colombier * the command looks like this (int 32bit integers)
421901484c1SDavid du Colombier * cmd type
422901484c1SDavid du Colombier * addr (low)
423901484c1SDavid du Colombier * addr (high)
424901484c1SDavid du Colombier * pad (used for dma testing)
425901484c1SDavid du Colombier * response (high)
426901484c1SDavid du Colombier * response (low)
427901484c1SDavid du Colombier * 40 byte = 5 int pad.
428901484c1SDavid du Colombier */
429901484c1SDavid du Colombier
43091b330d9SDavid du Colombier ulong
cmd(Ctlr * c,int type,uvlong data)43191b330d9SDavid du Colombier cmd(Ctlr *c, int type, uvlong data)
432901484c1SDavid du Colombier {
43391b330d9SDavid du Colombier ulong buf[16], i;
434901484c1SDavid du Colombier Cmd *cmd;
435901484c1SDavid du Colombier
436901484c1SDavid du Colombier qlock(&c->cmdl);
437901484c1SDavid du Colombier cmd = c->cmd;
438901484c1SDavid du Colombier cmd->i[1] = Noconf;
439901484c1SDavid du Colombier memset(buf, 0, sizeof buf);
440901484c1SDavid du Colombier buf[0] = type;
441901484c1SDavid du Colombier buf[1] = data;
44241ac1ab6SDavid du Colombier buf[2] = data >> 32;
44341ac1ab6SDavid du Colombier buf[4] = c->cprt >> 32;
444901484c1SDavid du Colombier buf[5] = c->cprt;
445901484c1SDavid du Colombier prepcmd(buf, 6);
446901484c1SDavid du Colombier coherence();
447901484c1SDavid du Colombier memmove(c->ram + Cmdoff, buf, sizeof buf);
448901484c1SDavid du Colombier
4496083aa43SDavid du Colombier if(waserror()){
4506083aa43SDavid du Colombier qunlock(&c->cmdl);
451901484c1SDavid du Colombier nexterror();
4526083aa43SDavid du Colombier }
453901484c1SDavid du Colombier for(i = 0; i < 15; i++){
454901484c1SDavid du Colombier if(cmd->i[1] != Noconf){
455901484c1SDavid du Colombier poperror();
456901484c1SDavid du Colombier i = gbit32(cmd->c);
457901484c1SDavid du Colombier qunlock(&c->cmdl);
458901484c1SDavid du Colombier if(cmd->i[1] != 0)
45991b330d9SDavid du Colombier dprint("[%lux]", i);
4606083aa43SDavid du Colombier return i; /* normal return */
461901484c1SDavid du Colombier }
462901484c1SDavid du Colombier tsleep(&up->sleep, return0, 0, 1);
463901484c1SDavid du Colombier }
464901484c1SDavid du Colombier iprint("m10g: cmd timeout [%ux %ux] cmd=%d\n",
465901484c1SDavid du Colombier cmd->i[0], cmd->i[1], type);
466901484c1SDavid du Colombier error(Etimeout);
467901484c1SDavid du Colombier return ~0; /* silence! */
468901484c1SDavid du Colombier }
469901484c1SDavid du Colombier
47091b330d9SDavid du Colombier ulong
maccmd(Ctlr * c,int type,uchar * m)471901484c1SDavid du Colombier maccmd(Ctlr *c, int type, uchar *m)
472901484c1SDavid du Colombier {
47391b330d9SDavid du Colombier ulong buf[16], i;
474901484c1SDavid du Colombier Cmd *cmd;
475901484c1SDavid du Colombier
476901484c1SDavid du Colombier qlock(&c->cmdl);
477901484c1SDavid du Colombier cmd = c->cmd;
478901484c1SDavid du Colombier cmd->i[1] = Noconf;
479901484c1SDavid du Colombier memset(buf, 0, sizeof buf);
480901484c1SDavid du Colombier buf[0] = type;
481901484c1SDavid du Colombier buf[1] = m[0]<<24 | m[1]<<16 | m[2]<<8 | m[3];
482901484c1SDavid du Colombier buf[2] = m[4]<< 8 | m[5];
48341ac1ab6SDavid du Colombier buf[4] = c->cprt >> 32;
484901484c1SDavid du Colombier buf[5] = c->cprt;
485901484c1SDavid du Colombier prepcmd(buf, 6);
486901484c1SDavid du Colombier coherence();
487901484c1SDavid du Colombier memmove(c->ram + Cmdoff, buf, sizeof buf);
488901484c1SDavid du Colombier
4896083aa43SDavid du Colombier if(waserror()){
4906083aa43SDavid du Colombier qunlock(&c->cmdl);
491901484c1SDavid du Colombier nexterror();
4926083aa43SDavid du Colombier }
493901484c1SDavid du Colombier for(i = 0; i < 15; i++){
494901484c1SDavid du Colombier if(cmd->i[1] != Noconf){
495901484c1SDavid du Colombier poperror();
496901484c1SDavid du Colombier i = gbit32(cmd->c);
497901484c1SDavid du Colombier qunlock(&c->cmdl);
498901484c1SDavid du Colombier if(cmd->i[1] != 0)
49991b330d9SDavid du Colombier dprint("[%lux]", i);
5006083aa43SDavid du Colombier return i; /* normal return */
501901484c1SDavid du Colombier }
502901484c1SDavid du Colombier tsleep(&up->sleep, return0, 0, 1);
503901484c1SDavid du Colombier }
504901484c1SDavid du Colombier iprint("m10g: maccmd timeout [%ux %ux] cmd=%d\n",
505901484c1SDavid du Colombier cmd->i[0], cmd->i[1], type);
506901484c1SDavid du Colombier error(Etimeout);
507901484c1SDavid du Colombier return ~0; /* silence! */
508901484c1SDavid du Colombier }
509901484c1SDavid du Colombier
510901484c1SDavid du Colombier /* remove this garbage after testing */
511901484c1SDavid du Colombier enum {
512901484c1SDavid du Colombier DMAread = 0x10000,
513901484c1SDavid du Colombier DMAwrite= 0x1,
514901484c1SDavid du Colombier };
515901484c1SDavid du Colombier
51691b330d9SDavid du Colombier ulong
dmatestcmd(Ctlr * c,int type,uvlong addr,int len)51791b330d9SDavid du Colombier dmatestcmd(Ctlr *c, int type, uvlong addr, int len)
518901484c1SDavid du Colombier {
51991b330d9SDavid du Colombier ulong buf[16], i;
520901484c1SDavid du Colombier
521901484c1SDavid du Colombier memset(buf, 0, sizeof buf);
522901484c1SDavid du Colombier memset(c->cmd, Noconf, sizeof *c->cmd);
523901484c1SDavid du Colombier buf[0] = Cdmatest;
524901484c1SDavid du Colombier buf[1] = addr;
52541ac1ab6SDavid du Colombier buf[2] = addr >> 32;
526901484c1SDavid du Colombier buf[3] = len * type;
52741ac1ab6SDavid du Colombier buf[4] = c->cprt >> 32;
528901484c1SDavid du Colombier buf[5] = c->cprt;
529901484c1SDavid du Colombier prepcmd(buf, 6);
530901484c1SDavid du Colombier coherence();
531901484c1SDavid du Colombier memmove(c->ram + Cmdoff, buf, sizeof buf);
532901484c1SDavid du Colombier
533901484c1SDavid du Colombier for(i = 0; i < 15; i++){
534901484c1SDavid du Colombier if(c->cmd->i[1] != Noconf){
535901484c1SDavid du Colombier i = gbit32(c->cmd->c);
536901484c1SDavid du Colombier if(i == 0)
537901484c1SDavid du Colombier error(Eio);
5386083aa43SDavid du Colombier return i; /* normal return */
539901484c1SDavid du Colombier }
540901484c1SDavid du Colombier tsleep(&up->sleep, return0, 0, 5);
541901484c1SDavid du Colombier }
542901484c1SDavid du Colombier error(Etimeout);
543901484c1SDavid du Colombier return ~0; /* silence! */
544901484c1SDavid du Colombier }
545901484c1SDavid du Colombier
54691b330d9SDavid du Colombier ulong
rdmacmd(Ctlr * c,int on)547901484c1SDavid du Colombier rdmacmd(Ctlr *c, int on)
548901484c1SDavid du Colombier {
54991b330d9SDavid du Colombier ulong buf[16], i;
550901484c1SDavid du Colombier
551901484c1SDavid du Colombier memset(buf, 0, sizeof buf);
552901484c1SDavid du Colombier c->cmd->i[0] = 0;
553901484c1SDavid du Colombier coherence();
55441ac1ab6SDavid du Colombier buf[0] = c->cprt >> 32;
555901484c1SDavid du Colombier buf[1] = c->cprt;
556901484c1SDavid du Colombier buf[2] = Noconf;
55741ac1ab6SDavid du Colombier buf[3] = c->cprt >> 32;
558901484c1SDavid du Colombier buf[4] = c->cprt;
559901484c1SDavid du Colombier buf[5] = on;
560901484c1SDavid du Colombier prepcmd(buf, 6);
561901484c1SDavid du Colombier memmove(c->ram + Rdmaoff, buf, sizeof buf);
562901484c1SDavid du Colombier
563901484c1SDavid du Colombier for(i = 0; i < 20; i++){
5646083aa43SDavid du Colombier if(c->cmd->i[0] == Noconf)
5656083aa43SDavid du Colombier return gbit32(c->cmd->c); /* normal return */
566901484c1SDavid du Colombier tsleep(&up->sleep, return0, 0, 1);
567901484c1SDavid du Colombier }
568901484c1SDavid du Colombier iprint("m10g: rdmacmd timeout\n");
5696083aa43SDavid du Colombier error(Etimeout);
570901484c1SDavid du Colombier return ~0; /* silence! */
571901484c1SDavid du Colombier }
572901484c1SDavid du Colombier
573901484c1SDavid du Colombier static int
loadfw(Ctlr * c,int * align)574901484c1SDavid du Colombier loadfw(Ctlr *c, int *align)
575901484c1SDavid du Colombier {
57691b330d9SDavid du Colombier ulong *f, *s, sz;
577901484c1SDavid du Colombier int i;
578901484c1SDavid du Colombier
57941ac1ab6SDavid du Colombier if((*align = whichfw(c->pcidev)) == 4*KiB){
58091b330d9SDavid du Colombier f = (ulong*)fw4k;
581901484c1SDavid du Colombier sz = sizeof fw4k;
582901484c1SDavid du Colombier }else{
58391b330d9SDavid du Colombier f = (ulong*)fw2k;
584901484c1SDavid du Colombier sz = sizeof fw2k;
585901484c1SDavid du Colombier }
586901484c1SDavid du Colombier
58791b330d9SDavid du Colombier s = (ulong*)(c->ram + Fwoffset);
588901484c1SDavid du Colombier for(i = 0; i < sz / 4; i++)
589901484c1SDavid du Colombier s[i] = f[i];
590901484c1SDavid du Colombier return sz & ~3;
591901484c1SDavid du Colombier }
592901484c1SDavid du Colombier
593901484c1SDavid du Colombier static int
bootfw(Ctlr * c)594901484c1SDavid du Colombier bootfw(Ctlr *c)
595901484c1SDavid du Colombier {
596901484c1SDavid du Colombier int i, sz, align;
59791b330d9SDavid du Colombier ulong buf[16];
598901484c1SDavid du Colombier Cmd* cmd;
599901484c1SDavid du Colombier
600901484c1SDavid du Colombier if((sz = loadfw(c, &align)) == 0)
601901484c1SDavid du Colombier return 0;
602901484c1SDavid du Colombier dprint("bootfw %d bytes ... ", sz);
603901484c1SDavid du Colombier cmd = c->cmd;
604901484c1SDavid du Colombier
605901484c1SDavid du Colombier memset(buf, 0, sizeof buf);
606901484c1SDavid du Colombier c->cmd->i[0] = 0;
607901484c1SDavid du Colombier coherence();
60841ac1ab6SDavid du Colombier buf[0] = c->cprt >> 32; /* upper dma target address */
609901484c1SDavid du Colombier buf[1] = c->cprt; /* lower */
610901484c1SDavid du Colombier buf[2] = Noconf; /* writeback */
611901484c1SDavid du Colombier buf[3] = Fwoffset + 8,
612901484c1SDavid du Colombier buf[4] = sz - 8;
613901484c1SDavid du Colombier buf[5] = 8;
614901484c1SDavid du Colombier buf[6] = 0;
615901484c1SDavid du Colombier prepcmd(buf, 7);
616901484c1SDavid du Colombier coherence();
617901484c1SDavid du Colombier memmove(c->ram + Fwsubmt, buf, sizeof buf);
618901484c1SDavid du Colombier
619901484c1SDavid du Colombier for(i = 0; i < 20; i++){
620901484c1SDavid du Colombier if(cmd->i[0] == Noconf)
621901484c1SDavid du Colombier break;
622901484c1SDavid du Colombier delay(1);
623901484c1SDavid du Colombier }
62491b330d9SDavid du Colombier dprint("[%lux %lux]", gbit32(cmd->c), gbit32(cmd->c+4));
625901484c1SDavid du Colombier if(i == 20){
626901484c1SDavid du Colombier print("m10g: cannot load fw\n");
627901484c1SDavid du Colombier return -1;
628901484c1SDavid du Colombier }
629901484c1SDavid du Colombier dprint("\n");
630901484c1SDavid du Colombier c->tx.segsz = align;
631901484c1SDavid du Colombier return 0;
632901484c1SDavid du Colombier }
633901484c1SDavid du Colombier
63441ac1ab6SDavid du Colombier static int
kickthebaby(Pcidev * p,Ctlr * c)635901484c1SDavid du Colombier kickthebaby(Pcidev *p, Ctlr *c)
636901484c1SDavid du Colombier {
637901484c1SDavid du Colombier /* don't kick the baby! */
63891b330d9SDavid du Colombier ulong code;
639901484c1SDavid du Colombier
640901484c1SDavid du Colombier pcicfgw8(p, 0x10 + c->boot, 0x3);
641901484c1SDavid du Colombier pcicfgw32(p, 0x18 + c->boot, 0xfffffff0);
642901484c1SDavid du Colombier code = pcicfgr32(p, 0x14 + c->boot);
643901484c1SDavid du Colombier
64491b330d9SDavid du Colombier dprint("reboot status = %lux\n", code);
645901484c1SDavid du Colombier if(code != 0xfffffff0)
646901484c1SDavid du Colombier return -1;
647901484c1SDavid du Colombier return 0;
648901484c1SDavid du Colombier }
649901484c1SDavid du Colombier
650901484c1SDavid du Colombier typedef struct {
651901484c1SDavid du Colombier uchar len[4];
652901484c1SDavid du Colombier uchar type[4];
653901484c1SDavid du Colombier char version[128];
654901484c1SDavid du Colombier uchar globals[4];
655901484c1SDavid du Colombier uchar ramsz[4];
656901484c1SDavid du Colombier uchar specs[4];
657901484c1SDavid du Colombier uchar specssz[4];
658901484c1SDavid du Colombier } Fwhdr;
659901484c1SDavid du Colombier
660901484c1SDavid du Colombier enum {
661901484c1SDavid du Colombier Tmx = 0x4d582020,
662901484c1SDavid du Colombier Tpcie = 0x70636965,
663901484c1SDavid du Colombier Teth = 0x45544820,
664901484c1SDavid du Colombier Tmcp0 = 0x4d435030,
665901484c1SDavid du Colombier };
666901484c1SDavid du Colombier
66741ac1ab6SDavid du Colombier static char *
fwtype(ulong type)66891b330d9SDavid du Colombier fwtype(ulong type)
669901484c1SDavid du Colombier {
670901484c1SDavid du Colombier switch(type){
671901484c1SDavid du Colombier case Tmx:
672901484c1SDavid du Colombier return "mx";
673901484c1SDavid du Colombier case Tpcie:
674901484c1SDavid du Colombier return "PCIe";
675901484c1SDavid du Colombier case Teth:
676901484c1SDavid du Colombier return "eth";
677901484c1SDavid du Colombier case Tmcp0:
678901484c1SDavid du Colombier return "mcp0";
679901484c1SDavid du Colombier }
680901484c1SDavid du Colombier return "*GOK*";
681901484c1SDavid du Colombier }
682901484c1SDavid du Colombier
68341ac1ab6SDavid du Colombier static int
chkfw(Ctlr * c)684901484c1SDavid du Colombier chkfw(Ctlr *c)
685901484c1SDavid du Colombier {
68664a26757SDavid du Colombier ulong off, type;
687901484c1SDavid du Colombier Fwhdr *h;
688901484c1SDavid du Colombier
689901484c1SDavid du Colombier off = gbit32(c->ram+0x3c);
69064a26757SDavid du Colombier dprint("firmware %lux\n", off);
691901484c1SDavid du Colombier if((off&3) || off + sizeof *h > c->ramsz){
69264a26757SDavid du Colombier print("!m10g: bad firmware %lux\n", off);
693901484c1SDavid du Colombier return -1;
694901484c1SDavid du Colombier }
695901484c1SDavid du Colombier h = (Fwhdr*)(c->ram + off);
696901484c1SDavid du Colombier type = gbit32(h->type);
697901484c1SDavid du Colombier dprint("\t" "type %s\n", fwtype(type));
698901484c1SDavid du Colombier dprint("\t" "vers %s\n", h->version);
69991b330d9SDavid du Colombier dprint("\t" "ramsz %lux\n", gbit32(h->ramsz));
700901484c1SDavid du Colombier if(type != Teth){
701901484c1SDavid du Colombier print("!m10g: bad card type %s\n", fwtype(type));
702901484c1SDavid du Colombier return -1;
703901484c1SDavid du Colombier }
704901484c1SDavid du Colombier
705901484c1SDavid du Colombier return bootfw(c) || rdmacmd(c, 0);
706901484c1SDavid du Colombier }
707901484c1SDavid du Colombier
708901484c1SDavid du Colombier static int
reset(Ether * e,Ctlr * c)709901484c1SDavid du Colombier reset(Ether *e, Ctlr *c)
710901484c1SDavid du Colombier {
71191b330d9SDavid du Colombier ulong i, sz;
712901484c1SDavid du Colombier
713901484c1SDavid du Colombier if(waserror()){
714901484c1SDavid du Colombier print("m10g: reset error\n");
715901484c1SDavid du Colombier nexterror();
716901484c1SDavid du Colombier return -1;
717901484c1SDavid du Colombier }
718901484c1SDavid du Colombier
719901484c1SDavid du Colombier chkfw(c);
720901484c1SDavid du Colombier cmd(c, Creset, 0);
721901484c1SDavid du Colombier
722901484c1SDavid du Colombier cmd(c, CSintrqsz, c->done.n * sizeof *c->done.entry);
723901484c1SDavid du Colombier cmd(c, CSintrqdma, c->done.busaddr);
72491b330d9SDavid du Colombier c->irqack = (ulong*)(c->ram + cmd(c, CGirqackoff, 0));
725901484c1SDavid du Colombier /* required only if we're not doing msi? */
72691b330d9SDavid du Colombier c->irqdeass = (ulong*)(c->ram + cmd(c, CGirqdeassoff, 0));
727901484c1SDavid du Colombier /* this is the driver default, why fiddle with this? */
72891b330d9SDavid du Colombier c->coal = (ulong*)(c->ram + cmd(c, CGcoaloff, 0));
729901484c1SDavid du Colombier *c->coal = pbit32(25);
730901484c1SDavid du Colombier
731901484c1SDavid du Colombier dprint("dma stats:\n");
732901484c1SDavid du Colombier rdmacmd(c, 1);
733901484c1SDavid du Colombier sz = c->tx.segsz;
734901484c1SDavid du Colombier i = dmatestcmd(c, DMAread, c->done.busaddr, sz);
73580088de7SDavid du Colombier print("m10g: read %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff));
736901484c1SDavid du Colombier i = dmatestcmd(c, DMAwrite, c->done.busaddr, sz);
73780088de7SDavid du Colombier print(" write %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff));
738901484c1SDavid du Colombier i = dmatestcmd(c, DMAwrite|DMAread, c->done.busaddr, sz);
73980088de7SDavid du Colombier print(" r/w %lud MB/s\n", ((i>>16)*sz*2*2) / (i&0xffff));
740901484c1SDavid du Colombier memset(c->done.entry, 0, c->done.n * sizeof *c->done.entry);
741901484c1SDavid du Colombier
742901484c1SDavid du Colombier maccmd(c, CSmac, c->ra);
743901484c1SDavid du Colombier // cmd(c, Cnopromisc, 0);
744901484c1SDavid du Colombier cmd(c, Cenablefc, 0);
745901484c1SDavid du Colombier e->maxmtu = Maxmtu;
746901484c1SDavid du Colombier cmd(c, CSmtu, e->maxmtu);
747901484c1SDavid du Colombier dprint("CSmtu %d...\n", e->maxmtu);
748901484c1SDavid du Colombier
749901484c1SDavid du Colombier poperror();
750901484c1SDavid du Colombier return 0;
751901484c1SDavid du Colombier }
752901484c1SDavid du Colombier
753901484c1SDavid du Colombier static void
ctlrfree(Ctlr * c)754901484c1SDavid du Colombier ctlrfree(Ctlr *c)
755901484c1SDavid du Colombier {
756901484c1SDavid du Colombier /* free up all the Block*s, too */
757901484c1SDavid du Colombier free(c->tx.host);
758901484c1SDavid du Colombier free(c->sm.host);
759901484c1SDavid du Colombier free(c->bg.host);
760901484c1SDavid du Colombier free(c->cmd);
761901484c1SDavid du Colombier free(c->done.entry);
762901484c1SDavid du Colombier free(c->stats);
763901484c1SDavid du Colombier free(c);
764901484c1SDavid du Colombier }
765901484c1SDavid du Colombier
766901484c1SDavid du Colombier static int
setmem(Pcidev * p,Ctlr * c)767901484c1SDavid du Colombier setmem(Pcidev *p, Ctlr *c)
768901484c1SDavid du Colombier {
76991b330d9SDavid du Colombier ulong i;
77091b330d9SDavid du Colombier uvlong raddr;
771901484c1SDavid du Colombier Done *d;
772901484c1SDavid du Colombier void *mem;
773901484c1SDavid du Colombier
774901484c1SDavid du Colombier c->tx.segsz = 2048;
77541ac1ab6SDavid du Colombier c->ramsz = 2*MiB - (2*48*KiB + 32*KiB) - 0x100;
776901484c1SDavid du Colombier if(c->ramsz > p->mem[0].size)
777901484c1SDavid du Colombier return -1;
778901484c1SDavid du Colombier
779901484c1SDavid du Colombier raddr = p->mem[0].bar & ~0x0F;
780901484c1SDavid du Colombier mem = vmap(raddr, p->mem[0].size);
781901484c1SDavid du Colombier if(mem == nil){
782901484c1SDavid du Colombier print("m10g: can't map %8.8lux\n", p->mem[0].bar);
783901484c1SDavid du Colombier return -1;
784901484c1SDavid du Colombier }
78541ac1ab6SDavid du Colombier dprint("%llux <- vmap(mem[0].size = %ux)\n", raddr, p->mem[0].size);
786901484c1SDavid du Colombier c->port = raddr;
787901484c1SDavid du Colombier c->ram = mem;
788901484c1SDavid du Colombier c->cmd = malign(sizeof *c->cmd);
789901484c1SDavid du Colombier c->cprt = PCIWADDR(c->cmd);
790901484c1SDavid du Colombier
791901484c1SDavid du Colombier d = &c->done;
792901484c1SDavid du Colombier d->n = Maxslots;
793901484c1SDavid du Colombier d->m = d->n - 1;
794901484c1SDavid du Colombier i = d->n * sizeof *d->entry;
795901484c1SDavid du Colombier d->entry = malign(i);
796901484c1SDavid du Colombier memset(d->entry, 0, i);
797901484c1SDavid du Colombier d->busaddr = PCIWADDR(d->entry);
798901484c1SDavid du Colombier
799901484c1SDavid du Colombier c->stats = malign(sizeof *c->stats);
800901484c1SDavid du Colombier memset(c->stats, 0, sizeof *c->stats);
801901484c1SDavid du Colombier c->statsprt = PCIWADDR(c->stats);
802901484c1SDavid du Colombier
803901484c1SDavid du Colombier memmove(c->eprom, c->ram + c->ramsz - Epromsz, Epromsz-2);
804901484c1SDavid du Colombier return setpcie(p) || parseeprom(c);
805901484c1SDavid du Colombier }
806901484c1SDavid du Colombier
807901484c1SDavid du Colombier static Rx*
whichrx(Ctlr * c,int sz)808901484c1SDavid du Colombier whichrx(Ctlr *c, int sz)
809901484c1SDavid du Colombier {
810901484c1SDavid du Colombier if(sz <= smpool.size)
811901484c1SDavid du Colombier return &c->sm;
812901484c1SDavid du Colombier return &c->bg;
813901484c1SDavid du Colombier }
814901484c1SDavid du Colombier
815901484c1SDavid du Colombier static Block*
balloc(Rx * rx)816901484c1SDavid du Colombier balloc(Rx* rx)
817901484c1SDavid du Colombier {
8187fd2696aSDavid du Colombier Block *bp;
819901484c1SDavid du Colombier
820901484c1SDavid du Colombier ilock(rx->pool);
8217fd2696aSDavid du Colombier if((bp = rx->pool->head) != nil){
8227fd2696aSDavid du Colombier rx->pool->head = bp->next;
8237fd2696aSDavid du Colombier bp->next = nil;
82461d44851SDavid du Colombier ainc(&bp->ref); /* prevent bp from being freed */
825901484c1SDavid du Colombier rx->pool->n--;
826901484c1SDavid du Colombier }
827901484c1SDavid du Colombier iunlock(rx->pool);
8287fd2696aSDavid du Colombier return bp;
829901484c1SDavid du Colombier }
830901484c1SDavid du Colombier
831901484c1SDavid du Colombier static void
rbfree(Block * b,Bpool * p)832bfb6eab9SDavid du Colombier rbfree(Block *b, Bpool *p)
833901484c1SDavid du Colombier {
834901484c1SDavid du Colombier b->rp = b->wp = (uchar*)PGROUND((uintptr)b->base);
835bfb6eab9SDavid du Colombier b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
836bfb6eab9SDavid du Colombier
837901484c1SDavid du Colombier ilock(p);
838901484c1SDavid du Colombier b->next = p->head;
839901484c1SDavid du Colombier p->head = b;
840901484c1SDavid du Colombier p->n++;
841901484c1SDavid du Colombier p->cnt++;
842901484c1SDavid du Colombier iunlock(p);
843901484c1SDavid du Colombier }
844901484c1SDavid du Colombier
845901484c1SDavid du Colombier static void
smbfree(Block * b)846bfb6eab9SDavid du Colombier smbfree(Block *b)
847bfb6eab9SDavid du Colombier {
848bfb6eab9SDavid du Colombier rbfree(b, &smpool);
849bfb6eab9SDavid du Colombier }
850bfb6eab9SDavid du Colombier
851bfb6eab9SDavid du Colombier static void
bgbfree(Block * b)852901484c1SDavid du Colombier bgbfree(Block *b)
853901484c1SDavid du Colombier {
854bfb6eab9SDavid du Colombier rbfree(b, &bgpool);
855901484c1SDavid du Colombier }
856901484c1SDavid du Colombier
857901484c1SDavid du Colombier static void
replenish(Rx * rx)858901484c1SDavid du Colombier replenish(Rx *rx)
859901484c1SDavid du Colombier {
86091b330d9SDavid du Colombier ulong buf[16], i, idx, e;
861901484c1SDavid du Colombier Bpool *p;
862901484c1SDavid du Colombier Block *b;
863901484c1SDavid du Colombier
864901484c1SDavid du Colombier p = rx->pool;
865901484c1SDavid du Colombier if(p->n < 8)
866901484c1SDavid du Colombier return;
867901484c1SDavid du Colombier memset(buf, 0, sizeof buf);
868901484c1SDavid du Colombier e = (rx->i - rx->cnt) & ~7;
869901484c1SDavid du Colombier e += rx->n;
870901484c1SDavid du Colombier while(p->n >= 8 && e){
871901484c1SDavid du Colombier idx = rx->cnt & rx->m;
872901484c1SDavid du Colombier for(i = 0; i < 8; i++){
873901484c1SDavid du Colombier b = balloc(rx);
87491b330d9SDavid du Colombier buf[i*2] = pbit32((uvlong)PCIWADDR(b->wp) >> 32);
875901484c1SDavid du Colombier buf[i*2+1] = pbit32(PCIWADDR(b->wp));
876901484c1SDavid du Colombier rx->host[idx+i] = b;
877901484c1SDavid du Colombier assert(b);
878901484c1SDavid du Colombier }
879901484c1SDavid du Colombier memmove(rx->lanai + 2*idx, buf, sizeof buf);
880901484c1SDavid du Colombier coherence();
881901484c1SDavid du Colombier rx->cnt += 8;
882901484c1SDavid du Colombier e -= 8;
883901484c1SDavid du Colombier }
884901484c1SDavid du Colombier if(e && p->n > 7+1)
88580088de7SDavid du Colombier print("m10g: should panic? pool->n = %d\n", p->n);
886901484c1SDavid du Colombier }
887901484c1SDavid du Colombier
888901484c1SDavid du Colombier /*
889901484c1SDavid du Colombier * future:
890901484c1SDavid du Colombier * if (c->mtrr >= 0) {
891901484c1SDavid du Colombier * c->tx.wcfifo = c->ram+0x200000;
892901484c1SDavid du Colombier * c->sm.wcfifo = c->ram+0x300000;
893901484c1SDavid du Colombier * c->bg.wcfifo = c->ram+0x340000;
894901484c1SDavid du Colombier * }
895901484c1SDavid du Colombier */
896901484c1SDavid du Colombier
897901484c1SDavid du Colombier static int
nextpow(int j)898901484c1SDavid du Colombier nextpow(int j)
899901484c1SDavid du Colombier {
900901484c1SDavid du Colombier int i;
901901484c1SDavid du Colombier
902901484c1SDavid du Colombier for(i = 0; j > (1 << i); i++)
903901484c1SDavid du Colombier ;
904901484c1SDavid du Colombier return 1 << i;
905901484c1SDavid du Colombier }
906901484c1SDavid du Colombier
907901484c1SDavid du Colombier static void*
emalign(int sz)908901484c1SDavid du Colombier emalign(int sz)
909901484c1SDavid du Colombier {
910901484c1SDavid du Colombier void *v;
911901484c1SDavid du Colombier
912901484c1SDavid du Colombier v = malign(sz);
913901484c1SDavid du Colombier if(v == nil)
914901484c1SDavid du Colombier error(Enomem);
915901484c1SDavid du Colombier memset(v, 0, sz);
916901484c1SDavid du Colombier return v;
917901484c1SDavid du Colombier }
918901484c1SDavid du Colombier
919901484c1SDavid du Colombier static void
open0(Ether * e,Ctlr * c)920901484c1SDavid du Colombier open0(Ether *e, Ctlr *c)
921901484c1SDavid du Colombier {
922901484c1SDavid du Colombier Block *b;
923901484c1SDavid du Colombier int i, sz, entries;
924901484c1SDavid du Colombier
925901484c1SDavid du Colombier entries = cmd(c, CGsendrgsz, 0) / sizeof *c->tx.lanai;
926901484c1SDavid du Colombier c->tx.lanai = (Send*)(c->ram + cmd(c, CGsendoff, 0));
927901484c1SDavid du Colombier c->tx.host = emalign(entries * sizeof *c->tx.host);
928901484c1SDavid du Colombier c->tx.bring = emalign(entries * sizeof *c->tx.bring);
929901484c1SDavid du Colombier c->tx.n = entries;
930901484c1SDavid du Colombier c->tx.m = entries-1;
931901484c1SDavid du Colombier
932901484c1SDavid du Colombier entries = cmd(c, CGrxrgsz, 0)/8;
933901484c1SDavid du Colombier c->sm.pool = &smpool;
934901484c1SDavid du Colombier cmd(c, CSsmallsz, c->sm.pool->size);
93591b330d9SDavid du Colombier c->sm.lanai = (ulong*)(c->ram + cmd(c, CGsmallrxoff, 0));
936901484c1SDavid du Colombier c->sm.n = entries;
937901484c1SDavid du Colombier c->sm.m = entries-1;
938901484c1SDavid du Colombier c->sm.host = emalign(entries * sizeof *c->sm.host);
939901484c1SDavid du Colombier
940901484c1SDavid du Colombier c->bg.pool = &bgpool;
941901484c1SDavid du Colombier c->bg.pool->size = nextpow(2 + e->maxmtu); /* 2-byte alignment pad */
942901484c1SDavid du Colombier cmd(c, CSbigsz, c->bg.pool->size);
94391b330d9SDavid du Colombier c->bg.lanai = (ulong*)(c->ram + cmd(c, CGbigrxoff, 0));
944901484c1SDavid du Colombier c->bg.n = entries;
945901484c1SDavid du Colombier c->bg.m = entries-1;
946901484c1SDavid du Colombier c->bg.host = emalign(entries * sizeof *c->bg.host);
947901484c1SDavid du Colombier
948901484c1SDavid du Colombier sz = c->sm.pool->size + BY2PG;
949901484c1SDavid du Colombier for(i = 0; i < c->sm.n; i++){
950901484c1SDavid du Colombier if((b = allocb(sz)) == 0)
951901484c1SDavid du Colombier break;
952901484c1SDavid du Colombier b->free = smbfree;
953901484c1SDavid du Colombier freeb(b);
954901484c1SDavid du Colombier }
955901484c1SDavid du Colombier sz = c->bg.pool->size + BY2PG;
956901484c1SDavid du Colombier for(i = 0; i < c->bg.n; i++){
957901484c1SDavid du Colombier if((b = allocb(sz)) == 0)
958901484c1SDavid du Colombier break;
959901484c1SDavid du Colombier b->free = bgbfree;
960901484c1SDavid du Colombier freeb(b);
961901484c1SDavid du Colombier }
962901484c1SDavid du Colombier
963901484c1SDavid du Colombier cmd(c, CSstatsdma, c->statsprt);
964901484c1SDavid du Colombier c->linkstat = ~0;
965901484c1SDavid du Colombier c->nrdma = 15;
966901484c1SDavid du Colombier
967901484c1SDavid du Colombier cmd(c, Cetherup, 0);
968901484c1SDavid du Colombier }
969901484c1SDavid du Colombier
970901484c1SDavid du Colombier static Block*
nextblock(Ctlr * c)971901484c1SDavid du Colombier nextblock(Ctlr *c)
972901484c1SDavid du Colombier {
973901484c1SDavid du Colombier uint i;
97491b330d9SDavid du Colombier ushort l, k;
975901484c1SDavid du Colombier Block *b;
976901484c1SDavid du Colombier Done *d;
977901484c1SDavid du Colombier Rx *rx;
978901484c1SDavid du Colombier Slot *s;
97941ac1ab6SDavid du Colombier Slotparts *sp;
980901484c1SDavid du Colombier
981901484c1SDavid du Colombier d = &c->done;
982901484c1SDavid du Colombier s = d->entry;
983901484c1SDavid du Colombier i = d->i & d->m;
98441ac1ab6SDavid du Colombier sp = (Slotparts *)(s + i);
98541ac1ab6SDavid du Colombier l = sp->len;
986901484c1SDavid du Colombier if(l == 0)
987901484c1SDavid du Colombier return 0;
98841ac1ab6SDavid du Colombier k = sp->cksum;
98941ac1ab6SDavid du Colombier s[i] = 0;
990901484c1SDavid du Colombier d->i++;
991901484c1SDavid du Colombier l = gbit16((uchar*)&l);
992901484c1SDavid du Colombier //dprint("nextb: i=%d l=%d\n", d->i, l);
993901484c1SDavid du Colombier rx = whichrx(c, l);
994901484c1SDavid du Colombier if(rx->i >= rx->cnt){
995901484c1SDavid du Colombier iprint("m10g: overrun\n");
996901484c1SDavid du Colombier return 0;
997901484c1SDavid du Colombier }
998901484c1SDavid du Colombier i = rx->i & rx->m;
999901484c1SDavid du Colombier b = rx->host[i];
1000901484c1SDavid du Colombier rx->host[i] = 0;
1001901484c1SDavid du Colombier if(b == 0){
1002901484c1SDavid du Colombier iprint("m10g: error rx to no block. memory is hosed.\n");
1003901484c1SDavid du Colombier return 0;
1004901484c1SDavid du Colombier }
1005901484c1SDavid du Colombier rx->i++;
1006901484c1SDavid du Colombier
1007901484c1SDavid du Colombier b->flag |= Bipck|Btcpck|Budpck;
1008901484c1SDavid du Colombier b->checksum = k;
1009901484c1SDavid du Colombier b->rp += 2;
1010901484c1SDavid du Colombier b->wp += 2+l;
1011901484c1SDavid du Colombier b->lim = b->wp; /* lie like a dog. */
1012901484c1SDavid du Colombier return b;
1013901484c1SDavid du Colombier }
1014901484c1SDavid du Colombier
1015901484c1SDavid du Colombier static int
rxcansleep(void * v)1016901484c1SDavid du Colombier rxcansleep(void *v)
1017901484c1SDavid du Colombier {
1018901484c1SDavid du Colombier Ctlr *c;
1019901484c1SDavid du Colombier Slot *s;
102041ac1ab6SDavid du Colombier Slotparts *sp;
1021901484c1SDavid du Colombier Done *d;
1022901484c1SDavid du Colombier
1023901484c1SDavid du Colombier c = v;
1024901484c1SDavid du Colombier d = &c->done;
1025901484c1SDavid du Colombier s = c->done.entry;
102641ac1ab6SDavid du Colombier sp = (Slotparts *)(s + (d->i & d->m));
102741ac1ab6SDavid du Colombier if(sp->len != 0)
1028901484c1SDavid du Colombier return -1;
1029901484c1SDavid du Colombier c->irqack[0] = pbit32(3);
1030901484c1SDavid du Colombier return 0;
1031901484c1SDavid du Colombier }
1032901484c1SDavid du Colombier
1033901484c1SDavid du Colombier static void
m10rx(void * v)1034901484c1SDavid du Colombier m10rx(void *v)
1035901484c1SDavid du Colombier {
1036901484c1SDavid du Colombier Ether *e;
1037901484c1SDavid du Colombier Ctlr *c;
1038901484c1SDavid du Colombier Block *b;
1039901484c1SDavid du Colombier
1040901484c1SDavid du Colombier e = v;
1041901484c1SDavid du Colombier c = e->ctlr;
1042901484c1SDavid du Colombier for(;;){
1043901484c1SDavid du Colombier replenish(&c->sm);
1044901484c1SDavid du Colombier replenish(&c->bg);
1045901484c1SDavid du Colombier sleep(&c->rxrendez, rxcansleep, c);
1046901484c1SDavid du Colombier while(b = nextblock(c))
1047901484c1SDavid du Colombier etheriq(e, b, 1);
1048901484c1SDavid du Colombier }
1049901484c1SDavid du Colombier }
1050901484c1SDavid du Colombier
105141ac1ab6SDavid du Colombier static void
txcleanup(Tx * tx,ulong n)105291b330d9SDavid du Colombier txcleanup(Tx *tx, ulong n)
1053901484c1SDavid du Colombier {
1054901484c1SDavid du Colombier Block *b;
1055901484c1SDavid du Colombier uint j, l, m;
1056901484c1SDavid du Colombier
1057901484c1SDavid du Colombier if(tx->npkt == n)
1058901484c1SDavid du Colombier return;
1059901484c1SDavid du Colombier l = 0;
1060901484c1SDavid du Colombier m = tx->m;
106141ac1ab6SDavid du Colombier /*
106241ac1ab6SDavid du Colombier * if tx->cnt == tx->i, yet tx->npkt == n-1, we just
106341ac1ab6SDavid du Colombier * caught ourselves and myricom card updating.
106441ac1ab6SDavid du Colombier */
1065901484c1SDavid du Colombier for(;; tx->cnt++){
1066901484c1SDavid du Colombier j = tx->cnt & tx->m;
1067901484c1SDavid du Colombier if(b = tx->bring[j]){
1068901484c1SDavid du Colombier tx->bring[j] = 0;
1069901484c1SDavid du Colombier tx->nbytes += BLEN(b);
1070901484c1SDavid du Colombier freeb(b);
1071901484c1SDavid du Colombier if(++tx->npkt == n)
1072901484c1SDavid du Colombier return;
1073901484c1SDavid du Colombier }
1074901484c1SDavid du Colombier if(tx->cnt == tx->i)
1075901484c1SDavid du Colombier return;
1076901484c1SDavid du Colombier if(l++ == m){
107780088de7SDavid du Colombier iprint("m10g: tx ovrun: %lud %lud\n", n, tx->npkt);
1078901484c1SDavid du Colombier return;
1079901484c1SDavid du Colombier }
1080901484c1SDavid du Colombier }
1081901484c1SDavid du Colombier }
1082901484c1SDavid du Colombier
1083901484c1SDavid du Colombier static int
txcansleep(void * v)1084901484c1SDavid du Colombier txcansleep(void *v)
1085901484c1SDavid du Colombier {
1086901484c1SDavid du Colombier Ctlr *c;
1087901484c1SDavid du Colombier
1088901484c1SDavid du Colombier c = v;
1089901484c1SDavid du Colombier if(c->tx.cnt != c->tx.i && c->tx.npkt != gbit32(c->stats->txcnt))
1090901484c1SDavid du Colombier return -1;
1091901484c1SDavid du Colombier return 0;
1092901484c1SDavid du Colombier }
1093901484c1SDavid du Colombier
109441ac1ab6SDavid du Colombier static void
txproc(void * v)1095901484c1SDavid du Colombier txproc(void *v)
1096901484c1SDavid du Colombier {
1097901484c1SDavid du Colombier Ether *e;
1098901484c1SDavid du Colombier Ctlr *c;
1099901484c1SDavid du Colombier Tx *tx;
1100901484c1SDavid du Colombier
1101901484c1SDavid du Colombier e = v;
1102901484c1SDavid du Colombier c = e->ctlr;
1103901484c1SDavid du Colombier tx = &c->tx;
1104901484c1SDavid du Colombier for(;;){
1105901484c1SDavid du Colombier sleep(&c->txrendez, txcansleep, c);
1106901484c1SDavid du Colombier txcleanup(tx, gbit32(c->stats->txcnt));
1107901484c1SDavid du Colombier }
1108901484c1SDavid du Colombier }
1109901484c1SDavid du Colombier
111041ac1ab6SDavid du Colombier static void
submittx(Tx * tx,int n)1111901484c1SDavid du Colombier submittx(Tx *tx, int n)
1112901484c1SDavid du Colombier {
1113901484c1SDavid du Colombier Send *l, *h;
1114901484c1SDavid du Colombier int i0, i, m;
1115901484c1SDavid du Colombier
1116901484c1SDavid du Colombier m = tx->m;
1117901484c1SDavid du Colombier i0 = tx->i & m;
1118901484c1SDavid du Colombier l = tx->lanai;
1119901484c1SDavid du Colombier h = tx->host;
1120901484c1SDavid du Colombier for(i = n-1; i >= 0; i--)
1121901484c1SDavid du Colombier memmove(l+(i + i0 & m), h+(i + i0 & m), sizeof *h);
1122901484c1SDavid du Colombier tx->i += n;
1123901484c1SDavid du Colombier // coherence();
1124901484c1SDavid du Colombier }
1125901484c1SDavid du Colombier
112641ac1ab6SDavid du Colombier static int
nsegments(Block * b,int segsz)1127901484c1SDavid du Colombier nsegments(Block *b, int segsz)
1128901484c1SDavid du Colombier {
1129901484c1SDavid du Colombier uintptr bus, end, slen, len;
1130901484c1SDavid du Colombier int i;
1131901484c1SDavid du Colombier
1132901484c1SDavid du Colombier bus = PCIWADDR(b->rp);
1133901484c1SDavid du Colombier i = 0;
1134901484c1SDavid du Colombier for(len = BLEN(b); len; len -= slen){
1135901484c1SDavid du Colombier end = bus + segsz & ~(segsz-1);
1136901484c1SDavid du Colombier slen = end - bus;
1137901484c1SDavid du Colombier if(slen > len)
1138901484c1SDavid du Colombier slen = len;
1139901484c1SDavid du Colombier bus += slen;
1140901484c1SDavid du Colombier i++;
1141901484c1SDavid du Colombier }
1142901484c1SDavid du Colombier return i;
1143901484c1SDavid du Colombier }
1144901484c1SDavid du Colombier
1145901484c1SDavid du Colombier static void
m10gtransmit(Ether * e)1146901484c1SDavid du Colombier m10gtransmit(Ether *e)
1147901484c1SDavid du Colombier {
114891b330d9SDavid du Colombier ushort slen;
114991b330d9SDavid du Colombier ulong i, cnt, rdma, nseg, count, end, bus, len, segsz;
1150901484c1SDavid du Colombier uchar flags;
1151901484c1SDavid du Colombier Block *b;
1152901484c1SDavid du Colombier Ctlr *c;
1153901484c1SDavid du Colombier Send *s, *s0, *s0m8;
1154901484c1SDavid du Colombier Tx *tx;
1155901484c1SDavid du Colombier
1156901484c1SDavid du Colombier c = e->ctlr;
1157901484c1SDavid du Colombier tx = &c->tx;
1158901484c1SDavid du Colombier segsz = tx->segsz;
1159901484c1SDavid du Colombier
1160901484c1SDavid du Colombier qlock(tx);
1161901484c1SDavid du Colombier count = 0;
1162901484c1SDavid du Colombier s = tx->host + (tx->i & tx->m);
1163901484c1SDavid du Colombier cnt = tx->cnt;
1164901484c1SDavid du Colombier s0 = tx->host + (cnt & tx->m);
116541ac1ab6SDavid du Colombier s0m8 = tx->host + ((cnt - 8) & tx->m);
1166901484c1SDavid du Colombier i = tx->i;
1167901484c1SDavid du Colombier for(; s >= s0 || s < s0m8; i += nseg){
1168901484c1SDavid du Colombier if((b = qget(e->oq)) == nil)
1169901484c1SDavid du Colombier break;
1170901484c1SDavid du Colombier flags = SFfirst|SFnotso;
1171901484c1SDavid du Colombier if((len = BLEN(b)) < 1520)
1172901484c1SDavid du Colombier flags |= SFsmall;
1173901484c1SDavid du Colombier rdma = nseg = nsegments(b, segsz);
1174901484c1SDavid du Colombier bus = PCIWADDR(b->rp);
1175901484c1SDavid du Colombier for(; len; len -= slen){
117664a26757SDavid du Colombier end = (bus + segsz) & ~(segsz-1);
1177901484c1SDavid du Colombier slen = end - bus;
1178901484c1SDavid du Colombier if(slen > len)
1179901484c1SDavid du Colombier slen = len;
1180901484c1SDavid du Colombier s->low = pbit32(bus);
1181901484c1SDavid du Colombier s->len = pbit16(slen);
1182901484c1SDavid du Colombier s->nrdma = rdma;
1183901484c1SDavid du Colombier s->flags = flags;
1184901484c1SDavid du Colombier
1185901484c1SDavid du Colombier bus += slen;
1186901484c1SDavid du Colombier if(++s == tx->host + tx->n)
1187901484c1SDavid du Colombier s = tx->host;
1188901484c1SDavid du Colombier count++;
1189901484c1SDavid du Colombier flags &= ~SFfirst;
1190901484c1SDavid du Colombier rdma = 1;
1191901484c1SDavid du Colombier }
119264a26757SDavid du Colombier tx->bring[(i + nseg - 1) & tx->m] = b;
1193901484c1SDavid du Colombier if(1 || count > 0){
1194901484c1SDavid du Colombier submittx(tx, count);
1195901484c1SDavid du Colombier count = 0;
1196901484c1SDavid du Colombier cnt = tx->cnt;
1197901484c1SDavid du Colombier s0 = tx->host + (cnt & tx->m);
119841ac1ab6SDavid du Colombier s0m8 = tx->host + ((cnt - 8) & tx->m);
1199901484c1SDavid du Colombier }
1200901484c1SDavid du Colombier }
1201901484c1SDavid du Colombier qunlock(tx);
1202901484c1SDavid du Colombier }
1203901484c1SDavid du Colombier
1204901484c1SDavid du Colombier static void
checkstats(Ether * e,Ctlr * c,Stats * s)1205901484c1SDavid du Colombier checkstats(Ether *e, Ctlr *c, Stats *s)
1206901484c1SDavid du Colombier {
120791b330d9SDavid du Colombier ulong i;
1208901484c1SDavid du Colombier
1209901484c1SDavid du Colombier if(s->updated == 0)
1210901484c1SDavid du Colombier return;
1211901484c1SDavid du Colombier
1212901484c1SDavid du Colombier i = gbit32(s->linkstat);
1213901484c1SDavid du Colombier if(c->linkstat != i){
1214901484c1SDavid du Colombier e->link = i;
1215901484c1SDavid du Colombier if(c->linkstat = i)
1216901484c1SDavid du Colombier dprint("m10g: link up\n");
1217901484c1SDavid du Colombier else
1218901484c1SDavid du Colombier dprint("m10g: link down\n");
1219901484c1SDavid du Colombier }
1220901484c1SDavid du Colombier i = gbit32(s->nrdma);
1221901484c1SDavid du Colombier if(i != c->nrdma){
122291b330d9SDavid du Colombier dprint("m10g: rdma timeout %ld\n", i);
1223901484c1SDavid du Colombier c->nrdma = i;
1224901484c1SDavid du Colombier }
1225901484c1SDavid du Colombier }
1226901484c1SDavid du Colombier
1227901484c1SDavid du Colombier static void
waitintx(Ctlr * c)1228901484c1SDavid du Colombier waitintx(Ctlr *c)
1229901484c1SDavid du Colombier {
1230901484c1SDavid du Colombier int i;
1231901484c1SDavid du Colombier
1232901484c1SDavid du Colombier for(i = 0; i < 1024*1024; i++){
1233901484c1SDavid du Colombier if(c->stats->valid == 0)
1234901484c1SDavid du Colombier break;
1235901484c1SDavid du Colombier coherence();
1236901484c1SDavid du Colombier }
1237901484c1SDavid du Colombier }
1238901484c1SDavid du Colombier
1239901484c1SDavid du Colombier static void
m10ginterrupt(Ureg *,void * v)1240901484c1SDavid du Colombier m10ginterrupt(Ureg *, void *v)
1241901484c1SDavid du Colombier {
1242901484c1SDavid du Colombier Ether *e;
1243901484c1SDavid du Colombier Ctlr *c;
1244901484c1SDavid du Colombier
1245901484c1SDavid du Colombier e = v;
1246901484c1SDavid du Colombier c = e->ctlr;
1247901484c1SDavid du Colombier
1248901484c1SDavid du Colombier if(c->state != Runed || c->stats->valid == 0) /* not ready for us? */
1249901484c1SDavid du Colombier return;
1250901484c1SDavid du Colombier
1251901484c1SDavid du Colombier if(c->stats->valid & 1)
1252901484c1SDavid du Colombier wakeup(&c->rxrendez);
1253901484c1SDavid du Colombier if(gbit32(c->stats->txcnt) != c->tx.npkt)
1254901484c1SDavid du Colombier wakeup(&c->txrendez);
1255901484c1SDavid du Colombier if(c->msi == 0)
1256901484c1SDavid du Colombier *c->irqdeass = 0;
1257901484c1SDavid du Colombier else
1258901484c1SDavid du Colombier c->stats->valid = 0;
1259901484c1SDavid du Colombier waitintx(c);
1260901484c1SDavid du Colombier checkstats(e, c, c->stats);
1261901484c1SDavid du Colombier c->irqack[1] = pbit32(3);
1262901484c1SDavid du Colombier }
1263901484c1SDavid du Colombier
1264901484c1SDavid du Colombier static void
m10gattach(Ether * e)1265901484c1SDavid du Colombier m10gattach(Ether *e)
1266901484c1SDavid du Colombier {
1267901484c1SDavid du Colombier Ctlr *c;
1268901484c1SDavid du Colombier char name[12];
1269901484c1SDavid du Colombier
1270901484c1SDavid du Colombier dprint("m10gattach\n");
1271901484c1SDavid du Colombier
1272901484c1SDavid du Colombier qlock(e->ctlr);
1273901484c1SDavid du Colombier c = e->ctlr;
1274901484c1SDavid du Colombier if(c->state != Detached){
1275901484c1SDavid du Colombier qunlock(c);
1276901484c1SDavid du Colombier return;
1277901484c1SDavid du Colombier }
1278901484c1SDavid du Colombier if(waserror()){
1279901484c1SDavid du Colombier c->state = Detached;
1280901484c1SDavid du Colombier qunlock(c);
1281901484c1SDavid du Colombier nexterror();
1282901484c1SDavid du Colombier }
1283901484c1SDavid du Colombier reset(e, c);
1284901484c1SDavid du Colombier c->state = Attached;
1285901484c1SDavid du Colombier open0(e, c);
1286901484c1SDavid du Colombier if(c->kprocs == 0){
1287901484c1SDavid du Colombier c->kprocs++;
1288901484c1SDavid du Colombier snprint(name, sizeof name, "#l%drxproc", e->ctlrno);
1289901484c1SDavid du Colombier kproc(name, m10rx, e);
1290901484c1SDavid du Colombier snprint(name, sizeof name, "#l%dtxproc", e->ctlrno);
1291901484c1SDavid du Colombier kproc(name, txproc, e);
1292901484c1SDavid du Colombier }
1293901484c1SDavid du Colombier c->state = Runed;
1294901484c1SDavid du Colombier qunlock(c);
1295901484c1SDavid du Colombier poperror();
1296901484c1SDavid du Colombier }
1297901484c1SDavid du Colombier
1298901484c1SDavid du Colombier static int
m10gdetach(Ctlr * c)1299901484c1SDavid du Colombier m10gdetach(Ctlr *c)
1300901484c1SDavid du Colombier {
1301901484c1SDavid du Colombier dprint("m10gdetach\n");
1302901484c1SDavid du Colombier // reset(e->ctlr);
1303901484c1SDavid du Colombier vunmap(c->ram, c->pcidev->mem[0].size);
13046083aa43SDavid du Colombier ctlrfree(c); /* this is a bad idea: don't free c */
1305901484c1SDavid du Colombier return -1;
1306901484c1SDavid du Colombier }
1307901484c1SDavid du Colombier
1308901484c1SDavid du Colombier static int
lstcount(Block * b)1309901484c1SDavid du Colombier lstcount(Block *b)
1310901484c1SDavid du Colombier {
1311901484c1SDavid du Colombier int i;
1312901484c1SDavid du Colombier
1313901484c1SDavid du Colombier i = 0;
1314901484c1SDavid du Colombier for(; b; b = b->next)
1315901484c1SDavid du Colombier i++;
1316901484c1SDavid du Colombier return i;
1317901484c1SDavid du Colombier }
1318901484c1SDavid du Colombier
1319901484c1SDavid du Colombier static long
m10gifstat(Ether * e,void * v,long n,ulong off)1320901484c1SDavid du Colombier m10gifstat(Ether *e, void *v, long n, ulong off)
1321901484c1SDavid du Colombier {
1322901484c1SDavid du Colombier char *p;
1323901484c1SDavid du Colombier Ctlr *c;
1324901484c1SDavid du Colombier Stats s;
1325901484c1SDavid du Colombier
1326901484c1SDavid du Colombier c = e->ctlr;
132746136019SDavid du Colombier p = malloc(READSTR+1);
1328aa72973aSDavid du Colombier if(p == nil)
1329aa72973aSDavid du Colombier error(Enomem);
1330901484c1SDavid du Colombier /* no point in locking this because this is done via dma. */
1331901484c1SDavid du Colombier memmove(&s, c->stats, sizeof s);
1332901484c1SDavid du Colombier
13336083aa43SDavid du Colombier snprint(p, READSTR,
133491b330d9SDavid du Colombier "txcnt = %lud\n" "linkstat = %lud\n" "dlink = %lud\n"
133591b330d9SDavid du Colombier "derror = %lud\n" "drunt = %lud\n" "doverrun = %lud\n"
133691b330d9SDavid du Colombier "dnosm = %lud\n" "dnobg = %lud\n" "nrdma = %lud\n"
1337901484c1SDavid du Colombier "txstopped = %ud\n" "down = %ud\n" "updated = %ud\n"
1338901484c1SDavid du Colombier "valid = %ud\n\n"
133991b330d9SDavid du Colombier "tx pkt = %lud\n" "tx bytes = %lld\n"
1340901484c1SDavid du Colombier "tx cnt = %ud\n" "tx n = %ud\n" "tx i = %ud\n"
134141ac1ab6SDavid du Colombier "sm cnt = %ud\n" "sm i = %ud\n" "sm n = %ud\n"
134241ac1ab6SDavid du Colombier "sm lst = %ud\n"
134341ac1ab6SDavid du Colombier "bg cnt = %ud\n" "bg i = %ud\n" "bg n = %ud\n"
134441ac1ab6SDavid du Colombier "bg lst = %ud\n"
134591b330d9SDavid du Colombier "segsz = %lud\n" "coal = %lud\n",
1346901484c1SDavid du Colombier gbit32(s.txcnt), gbit32(s.linkstat), gbit32(s.dlink),
1347901484c1SDavid du Colombier gbit32(s.derror), gbit32(s.drunt), gbit32(s.doverrun),
1348901484c1SDavid du Colombier gbit32(s.dnosm), gbit32(s.dnobg), gbit32(s.nrdma),
1349901484c1SDavid du Colombier s.txstopped, s.down, s.updated, s.valid,
1350901484c1SDavid du Colombier c->tx.npkt, c->tx.nbytes,
1351901484c1SDavid du Colombier c->tx.cnt, c->tx.n, c->tx.i,
1352901484c1SDavid du Colombier c->sm.cnt, c->sm.i, c->sm.pool->n, lstcount(c->sm.pool->head),
1353901484c1SDavid du Colombier c->bg.cnt, c->bg.i, c->bg.pool->n, lstcount(c->bg.pool->head),
1354901484c1SDavid du Colombier c->tx.segsz, gbit32((uchar*)c->coal));
1355901484c1SDavid du Colombier
1356901484c1SDavid du Colombier n = readstr(off, v, n, p);
1357901484c1SDavid du Colombier free(p);
1358901484c1SDavid du Colombier return n;
1359901484c1SDavid du Colombier }
1360901484c1SDavid du Colombier
136141ac1ab6SDavid du Colombier //static void
1362901484c1SDavid du Colombier //summary(Ether *e)
1363901484c1SDavid du Colombier //{
1364901484c1SDavid du Colombier // char *buf;
1365901484c1SDavid du Colombier // int n, i, j;
1366901484c1SDavid du Colombier //
1367901484c1SDavid du Colombier // if(e == 0)
1368901484c1SDavid du Colombier // return;
1369901484c1SDavid du Colombier // buf = malloc(n=250);
1370901484c1SDavid du Colombier // if(buf == 0)
1371901484c1SDavid du Colombier // return;
1372901484c1SDavid du Colombier //
1373901484c1SDavid du Colombier // snprint(buf, n, "oq\n");
1374901484c1SDavid du Colombier // qsummary(e->oq, buf+3, n-3-1);
1375901484c1SDavid du Colombier // iprint("%s", buf);
1376901484c1SDavid du Colombier //
1377901484c1SDavid du Colombier // if(e->f) for(i = 0; e->f[i]; i++){
1378901484c1SDavid du Colombier // j = snprint(buf, n, "f%d %d\n", i, e->f[i]->type);
1379901484c1SDavid du Colombier // qsummary(e->f[i]->in, buf+j, n-j-1);
1380901484c1SDavid du Colombier // print("%s", buf);
1381901484c1SDavid du Colombier // }
1382901484c1SDavid du Colombier //
1383901484c1SDavid du Colombier // free(buf);
1384901484c1SDavid du Colombier //}
1385901484c1SDavid du Colombier
138641ac1ab6SDavid du Colombier static void
rxring(Ctlr * c)1387901484c1SDavid du Colombier rxring(Ctlr *c)
1388901484c1SDavid du Colombier {
1389901484c1SDavid du Colombier Done *d;
1390901484c1SDavid du Colombier Slot *s;
139141ac1ab6SDavid du Colombier Slotparts *sp;
1392901484c1SDavid du Colombier int i;
1393901484c1SDavid du Colombier
1394901484c1SDavid du Colombier d = &c->done;
1395901484c1SDavid du Colombier s = d->entry;
139641ac1ab6SDavid du Colombier for(i = 0; i < d->n; i++) {
139741ac1ab6SDavid du Colombier sp = (Slotparts *)(s + i);
139841ac1ab6SDavid du Colombier if(sp->len)
139941ac1ab6SDavid du Colombier iprint("s[%d] = %d\n", i, sp->len);
140041ac1ab6SDavid du Colombier }
1401901484c1SDavid du Colombier }
1402901484c1SDavid du Colombier
1403901484c1SDavid du Colombier enum {
1404901484c1SDavid du Colombier CMdebug,
1405901484c1SDavid du Colombier CMcoal,
1406901484c1SDavid du Colombier CMwakeup,
1407901484c1SDavid du Colombier CMtxwakeup,
1408901484c1SDavid du Colombier CMqsummary,
1409901484c1SDavid du Colombier CMrxring,
1410901484c1SDavid du Colombier };
1411901484c1SDavid du Colombier
1412901484c1SDavid du Colombier static Cmdtab ctab[] = {
1413901484c1SDavid du Colombier CMdebug, "debug", 2,
1414901484c1SDavid du Colombier CMcoal, "coal", 2,
1415901484c1SDavid du Colombier CMwakeup, "wakeup", 1,
1416901484c1SDavid du Colombier CMtxwakeup, "txwakeup", 1,
1417901484c1SDavid du Colombier // CMqsummary, "q", 1,
1418901484c1SDavid du Colombier CMrxring, "rxring", 1,
1419901484c1SDavid du Colombier };
1420901484c1SDavid du Colombier
1421901484c1SDavid du Colombier static long
m10gctl(Ether * e,void * v,long n)1422901484c1SDavid du Colombier m10gctl(Ether *e, void *v, long n)
1423901484c1SDavid du Colombier {
1424901484c1SDavid du Colombier int i;
1425901484c1SDavid du Colombier Cmdbuf *c;
1426901484c1SDavid du Colombier Cmdtab *t;
1427901484c1SDavid du Colombier
1428901484c1SDavid du Colombier dprint("m10gctl\n");
1429901484c1SDavid du Colombier if(e->ctlr == nil)
1430901484c1SDavid du Colombier error(Enonexist);
1431901484c1SDavid du Colombier
1432901484c1SDavid du Colombier c = parsecmd(v, n);
1433901484c1SDavid du Colombier if(waserror()){
1434901484c1SDavid du Colombier free(c);
1435901484c1SDavid du Colombier nexterror();
1436901484c1SDavid du Colombier }
1437901484c1SDavid du Colombier t = lookupcmd(c, ctab, nelem(ctab));
1438901484c1SDavid du Colombier switch(t->index){
1439901484c1SDavid du Colombier case CMdebug:
144041ac1ab6SDavid du Colombier debug = (strcmp(c->f[1], "on") == 0);
1441901484c1SDavid du Colombier break;
1442901484c1SDavid du Colombier case CMcoal:
1443901484c1SDavid du Colombier i = atoi(c->f[1]);
1444901484c1SDavid du Colombier if(i < 0 || i > 1000)
1445901484c1SDavid du Colombier error(Ebadarg);
1446901484c1SDavid du Colombier *((Ctlr*)e->ctlr)->coal = pbit32(i);
1447901484c1SDavid du Colombier break;
1448901484c1SDavid du Colombier case CMwakeup:
1449901484c1SDavid du Colombier wakeup(&((Ctlr*)e->ctlr)->rxrendez); /* you're kidding, right? */
1450901484c1SDavid du Colombier break;
1451901484c1SDavid du Colombier case CMtxwakeup:
1452901484c1SDavid du Colombier wakeup(&((Ctlr*)e->ctlr)->txrendez); /* you're kidding, right? */
1453901484c1SDavid du Colombier break;
1454901484c1SDavid du Colombier // case CMqsummary:
1455901484c1SDavid du Colombier // summary(e);
1456901484c1SDavid du Colombier // break;
1457901484c1SDavid du Colombier case CMrxring:
1458901484c1SDavid du Colombier rxring(e->ctlr);
1459901484c1SDavid du Colombier break;
1460901484c1SDavid du Colombier default:
1461901484c1SDavid du Colombier error(Ebadarg);
1462901484c1SDavid du Colombier }
1463901484c1SDavid du Colombier free(c);
1464901484c1SDavid du Colombier poperror();
1465901484c1SDavid du Colombier return n;
1466901484c1SDavid du Colombier }
1467901484c1SDavid du Colombier
1468901484c1SDavid du Colombier static void
m10gshutdown(Ether * e)1469901484c1SDavid du Colombier m10gshutdown(Ether *e)
1470901484c1SDavid du Colombier {
1471901484c1SDavid du Colombier dprint("m10gshutdown\n");
1472901484c1SDavid du Colombier m10gdetach(e->ctlr);
1473901484c1SDavid du Colombier }
1474901484c1SDavid du Colombier
1475901484c1SDavid du Colombier static void
m10gpromiscuous(void * v,int on)1476901484c1SDavid du Colombier m10gpromiscuous(void *v, int on)
1477901484c1SDavid du Colombier {
1478901484c1SDavid du Colombier Ether *e;
1479901484c1SDavid du Colombier int i;
1480901484c1SDavid du Colombier
1481901484c1SDavid du Colombier dprint("m10gpromiscuous\n");
1482901484c1SDavid du Colombier e = v;
1483901484c1SDavid du Colombier if(on)
1484901484c1SDavid du Colombier i = Cpromisc;
1485901484c1SDavid du Colombier else
1486901484c1SDavid du Colombier i = Cnopromisc;
1487901484c1SDavid du Colombier cmd(e->ctlr, i, 0);
1488901484c1SDavid du Colombier }
1489901484c1SDavid du Colombier
1490901484c1SDavid du Colombier static int mcctab[] = { CSleavemc, CSjoinmc };
1491901484c1SDavid du Colombier static char *mcntab[] = { "leave", "join" };
1492901484c1SDavid du Colombier
1493901484c1SDavid du Colombier static void
m10gmulticast(void * v,uchar * ea,int on)1494901484c1SDavid du Colombier m10gmulticast(void *v, uchar *ea, int on)
1495901484c1SDavid du Colombier {
1496901484c1SDavid du Colombier Ether *e;
1497901484c1SDavid du Colombier int i;
1498901484c1SDavid du Colombier
1499901484c1SDavid du Colombier dprint("m10gmulticast\n");
1500901484c1SDavid du Colombier e = v;
1501901484c1SDavid du Colombier if((i = maccmd(e->ctlr, mcctab[on], ea)) != 0)
1502901484c1SDavid du Colombier print("m10g: can't %s %E: %d\n", mcntab[on], ea, i);
1503901484c1SDavid du Colombier }
1504901484c1SDavid du Colombier
1505901484c1SDavid du Colombier static void
m10gpci(void)1506901484c1SDavid du Colombier m10gpci(void)
1507901484c1SDavid du Colombier {
1508901484c1SDavid du Colombier Pcidev *p;
1509901484c1SDavid du Colombier Ctlr *t, *c;
1510901484c1SDavid du Colombier
1511901484c1SDavid du Colombier t = 0;
1512d5789509SDavid du Colombier for(p = 0; p = pcimatch(p, Vmyricom, 0); ){
1513d5789509SDavid du Colombier switch(p->did){
1514d5789509SDavid du Colombier case 0x8: /* 8a */
1515d5789509SDavid du Colombier break;
1516d5789509SDavid du Colombier case 0x9: /* 8a with msi-x fw */
1517d5789509SDavid du Colombier case 0xa: /* 8b */
1518d5789509SDavid du Colombier case 0xb: /* 8b2 */
1519d5789509SDavid du Colombier case 0xc: /* 2-8b2 */
1520d5789509SDavid du Colombier /* untested */
1521d5789509SDavid du Colombier break;
1522d5789509SDavid du Colombier default:
1523d5789509SDavid du Colombier print("etherm10g: unknown myricom did %#ux\n", p->did);
1524d5789509SDavid du Colombier continue;
1525d5789509SDavid du Colombier }
1526901484c1SDavid du Colombier c = malloc(sizeof *c);
1527901484c1SDavid du Colombier if(c == nil)
15286083aa43SDavid du Colombier break;
1529901484c1SDavid du Colombier c->pcidev = p;
1530901484c1SDavid du Colombier c->id = p->did<<16 | p->vid;
1531901484c1SDavid du Colombier c->boot = pcicap(p, PciCapVND);
1532901484c1SDavid du Colombier // kickthebaby(p, c);
1533901484c1SDavid du Colombier pcisetbme(p);
1534901484c1SDavid du Colombier if(setmem(p, c) == -1){
153580088de7SDavid du Colombier print("m10g: setmem failed\n");
1536901484c1SDavid du Colombier free(c);
1537901484c1SDavid du Colombier /* cleanup */
1538901484c1SDavid du Colombier continue;
1539901484c1SDavid du Colombier }
1540901484c1SDavid du Colombier if(t)
1541901484c1SDavid du Colombier t->next = c;
1542901484c1SDavid du Colombier else
1543901484c1SDavid du Colombier ctlrs = c;
1544901484c1SDavid du Colombier t = c;
1545901484c1SDavid du Colombier }
1546901484c1SDavid du Colombier }
1547901484c1SDavid du Colombier
1548901484c1SDavid du Colombier static int
m10gpnp(Ether * e)1549901484c1SDavid du Colombier m10gpnp(Ether *e)
1550901484c1SDavid du Colombier {
1551901484c1SDavid du Colombier Ctlr *c;
1552901484c1SDavid du Colombier
1553901484c1SDavid du Colombier if(ctlrs == nil)
1554901484c1SDavid du Colombier m10gpci();
1555901484c1SDavid du Colombier
1556901484c1SDavid du Colombier for(c = ctlrs; c != nil; c = c->next)
1557901484c1SDavid du Colombier if(c->active)
1558901484c1SDavid du Colombier continue;
1559901484c1SDavid du Colombier else if(e->port == 0 || e->port == c->port)
1560901484c1SDavid du Colombier break;
1561901484c1SDavid du Colombier if(c == nil)
1562901484c1SDavid du Colombier return -1;
1563901484c1SDavid du Colombier c->active = 1;
1564901484c1SDavid du Colombier
1565901484c1SDavid du Colombier e->ctlr = c;
1566901484c1SDavid du Colombier e->port = c->port;
1567901484c1SDavid du Colombier e->irq = c->pcidev->intl;
1568901484c1SDavid du Colombier e->tbdf = c->pcidev->tbdf;
1569901484c1SDavid du Colombier e->mbps = 10000;
1570901484c1SDavid du Colombier memmove(e->ea, c->ra, Eaddrlen);
1571901484c1SDavid du Colombier
1572901484c1SDavid du Colombier e->attach = m10gattach;
1573901484c1SDavid du Colombier e->detach = m10gshutdown;
1574901484c1SDavid du Colombier e->transmit = m10gtransmit;
1575901484c1SDavid du Colombier e->interrupt = m10ginterrupt;
1576901484c1SDavid du Colombier e->ifstat = m10gifstat;
1577901484c1SDavid du Colombier e->ctl = m10gctl;
1578901484c1SDavid du Colombier e->shutdown = m10gshutdown;
1579901484c1SDavid du Colombier
1580901484c1SDavid du Colombier e->arg = e;
1581901484c1SDavid du Colombier e->promiscuous = m10gpromiscuous;
1582901484c1SDavid du Colombier e->multicast = m10gmulticast;
1583901484c1SDavid du Colombier return 0;
1584901484c1SDavid du Colombier }
1585901484c1SDavid du Colombier
1586901484c1SDavid du Colombier void
etherm10glink(void)1587901484c1SDavid du Colombier etherm10glink(void)
1588901484c1SDavid du Colombier {
1589901484c1SDavid du Colombier addethercard("m10g", m10gpnp);
1590901484c1SDavid du Colombier }
1591