xref: /plan9-contrib/sys/src/9/pc/etherm10g.c (revision 54d7663a1ce4eb4ba4bbd19f36ee38ce7905a669)
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