xref: /plan9/sys/src/9/pc/etherm10g.c (revision 217e9e83c7f9cc6fb27d97dda90c8339b6f98728)
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.
8*217e9e83SDavid du Colombier  *
9*217e9e83SDavid 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 
31901484c1SDavid du Colombier #include "etherm10g2k.i"
32901484c1SDavid du Colombier #include "etherm10g4k.i"
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,
39*217e9e83SDavid du Colombier 	Maxslots= 1024,		/* rcv descriptors; wasteful: only 9 needed */
40901484c1SDavid du Colombier 	Align	= 4096,
41*217e9e83SDavid 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 	PciCapPMG	 = 0x01,	/* power management */
243901484c1SDavid du Colombier 	PciCapAGP	 = 0x02,
244901484c1SDavid du Colombier 	PciCapVPD	 = 0x03,	/* vital product data */
245901484c1SDavid du Colombier 	PciCapSID	 = 0x04,	/* slot id */
246901484c1SDavid du Colombier 	PciCapMSI	 = 0x05,
247901484c1SDavid du Colombier 	PciCapCHS	 = 0x06,	/* compact pci hot swap */
248901484c1SDavid du Colombier 	PciCapPCIX	 = 0x07,
249901484c1SDavid du Colombier 	PciCapHTC	 = 0x08,	/* hypertransport irq conf */
250901484c1SDavid du Colombier 	PciCapVND	 = 0x09,	/* vendor specific information */
251901484c1SDavid du Colombier 	PciCapHSW	 = 0x0C,	/* hot swap */
252901484c1SDavid du Colombier 	PciCapPCIe	 = 0x10,
253901484c1SDavid du Colombier 	PciCapMSIX	 = 0x11,
254901484c1SDavid du Colombier };
255901484c1SDavid du Colombier 
256901484c1SDavid du Colombier enum {
257901484c1SDavid du Colombier 	PcieAERC = 1,
258901484c1SDavid du Colombier 	PcieVC,
259901484c1SDavid du Colombier 	PcieSNC,
260901484c1SDavid du Colombier 	PciePBC,
261901484c1SDavid du Colombier };
262901484c1SDavid du Colombier 
263901484c1SDavid du Colombier enum {
264901484c1SDavid du Colombier 	AercCCR	= 0x18,		/* control register */
265901484c1SDavid du Colombier };
266901484c1SDavid du Colombier 
267901484c1SDavid du Colombier enum {
268901484c1SDavid du Colombier 	PcieCTL	= 8,
269901484c1SDavid du Colombier 	PcieLCR	= 12,
270901484c1SDavid du Colombier 	PcieMRD	= 0x7000,	/* maximum read size */
271901484c1SDavid du Colombier };
272901484c1SDavid du Colombier 
27341ac1ab6SDavid du Colombier static int
pcicap(Pcidev * p,int cap)274901484c1SDavid du Colombier pcicap(Pcidev *p, int cap)
275901484c1SDavid du Colombier {
276901484c1SDavid du Colombier 	int i, c, off;
277901484c1SDavid du Colombier 
278901484c1SDavid du Colombier 	pcicapdbg("pcicap: %x:%d\n", p->vid, p->did);
279901484c1SDavid du Colombier 	off = 0x34;			/* 0x14 for cardbus */
280901484c1SDavid du Colombier 	for(i = 48; i--; ){
281901484c1SDavid du Colombier 		pcicapdbg("\t" "loop %x\n", off);
282901484c1SDavid du Colombier 		off = pcicfgr8(p, off);
283901484c1SDavid du Colombier 		pcicapdbg("\t" "pcicfgr8 %x\n", off);
284901484c1SDavid du Colombier 		if(off < 0x40)
285901484c1SDavid du Colombier 			break;
286901484c1SDavid du Colombier 		off &= ~3;
287901484c1SDavid du Colombier 		c = pcicfgr8(p, off);
288901484c1SDavid du Colombier 		pcicapdbg("\t" "pcicfgr8 %x\n", c);
289901484c1SDavid du Colombier 		if(c == 0xff)
290901484c1SDavid du Colombier 			break;
291901484c1SDavid du Colombier 		if(c == cap)
292901484c1SDavid du Colombier 			return off;
293901484c1SDavid du Colombier 		off++;
294901484c1SDavid du Colombier 	}
295901484c1SDavid du Colombier 	return 0;
296901484c1SDavid du Colombier }
297901484c1SDavid du Colombier 
298901484c1SDavid du Colombier /*
299901484c1SDavid du Colombier  * this function doesn't work because pcicgr32 doesn't have access
300901484c1SDavid du Colombier  * to the pcie extended configuration space.
301901484c1SDavid du Colombier  */
30241ac1ab6SDavid du Colombier static int
pciecap(Pcidev * p,int cap)303901484c1SDavid du Colombier pciecap(Pcidev *p, int cap)
304901484c1SDavid du Colombier {
305901484c1SDavid du Colombier 	uint off, i;
306901484c1SDavid du Colombier 
307901484c1SDavid du Colombier 	off = 0x100;
308901484c1SDavid du Colombier 	while(((i = pcicfgr32(p, off)) & 0xffff) != cap){
309901484c1SDavid du Colombier 		off = i >> 20;
31080088de7SDavid du Colombier 		print("m10g: pciecap offset = %ud",  off);
31141ac1ab6SDavid du Colombier 		if(off < 0x100 || off >= 4*KiB - 1)
312901484c1SDavid du Colombier 			return 0;
313901484c1SDavid du Colombier 	}
31480088de7SDavid du Colombier 	print("m10g: pciecap found = %ud",  off);
315901484c1SDavid du Colombier 	return off;
316901484c1SDavid du Colombier }
317901484c1SDavid du Colombier 
318901484c1SDavid du Colombier static int
setpcie(Pcidev * p)319901484c1SDavid du Colombier setpcie(Pcidev *p)
320901484c1SDavid du Colombier {
321901484c1SDavid du Colombier 	int off;
322901484c1SDavid du Colombier 
323901484c1SDavid du Colombier 	/* set 4k writes */
324901484c1SDavid du Colombier 	off = pcicap(p, PciCapPCIe);
325901484c1SDavid du Colombier 	if(off < 64)
326901484c1SDavid du Colombier 		return -1;
327901484c1SDavid du Colombier 	off += PcieCTL;
328901484c1SDavid du Colombier 	pcicfgw16(p, off, (pcicfgr16(p, off) & ~PcieMRD) | 5<<12);
329901484c1SDavid du Colombier 	return 0;
330901484c1SDavid du Colombier }
331901484c1SDavid du Colombier 
332901484c1SDavid du Colombier static int
whichfw(Pcidev * p)333901484c1SDavid du Colombier whichfw(Pcidev *p)
334901484c1SDavid du Colombier {
335901484c1SDavid du Colombier 	char *s;
336901484c1SDavid du Colombier 	int i, off, lanes, ecrc;
33791b330d9SDavid du Colombier 	ulong cap;
338901484c1SDavid du Colombier 
339901484c1SDavid du Colombier 	/* check the number of configured lanes. */
340901484c1SDavid du Colombier 	off = pcicap(p, PciCapPCIe);
341901484c1SDavid du Colombier 	if(off < 64)
342901484c1SDavid du Colombier 		return -1;
343901484c1SDavid du Colombier 	off += PcieLCR;
344901484c1SDavid du Colombier 	cap = pcicfgr16(p, off);
345901484c1SDavid du Colombier 	lanes = (cap>>4) & 0x3f;
346901484c1SDavid du Colombier 
347901484c1SDavid du Colombier 	/* check AERC register.  we need it on.  */
348901484c1SDavid du Colombier 	off = pciecap(p, PcieAERC);
34980088de7SDavid du Colombier 	print("; offset %d returned\n", off);
350901484c1SDavid du Colombier 	cap = 0;
351901484c1SDavid du Colombier 	if(off != 0){
352901484c1SDavid du Colombier 		off += AercCCR;
353901484c1SDavid du Colombier 		cap = pcicfgr32(p, off);
35480088de7SDavid du Colombier 		print("m10g: %lud cap\n", cap);
355901484c1SDavid du Colombier 	}
356901484c1SDavid du Colombier 	ecrc = (cap>>4) & 0xf;
357901484c1SDavid du Colombier 	/* if we don't like the aerc, kick it here. */
358901484c1SDavid du Colombier 
35980088de7SDavid du Colombier 	print("m10g: %d lanes; ecrc=%d; ", lanes, ecrc);
360901484c1SDavid du Colombier 	if(s = getconf("myriforce")){
361901484c1SDavid du Colombier 		i = atoi(s);
36241ac1ab6SDavid du Colombier 		if(i != 4*KiB || i != 2*KiB)
36341ac1ab6SDavid du Colombier 			i = 2*KiB;
364901484c1SDavid du Colombier 		print("fw = %d [forced]\n", i);
365901484c1SDavid du Colombier 		return i;
366901484c1SDavid du Colombier 	}
367d5789509SDavid du Colombier 	if(lanes <= 4)
368901484c1SDavid du Colombier 		print("fw = 4096 [lanes]\n");
369d5789509SDavid du Colombier 	else if(ecrc & 10)
370901484c1SDavid du Colombier 		print("fw = 4096 [ecrc set]\n");
371d5789509SDavid du Colombier 	else
372901484c1SDavid du Colombier 		print("fw = 4096 [default]\n");
37341ac1ab6SDavid du Colombier 	return 4*KiB;
374901484c1SDavid du Colombier }
375901484c1SDavid du Colombier 
376901484c1SDavid du Colombier static int
parseeprom(Ctlr * c)377901484c1SDavid du Colombier parseeprom(Ctlr *c)
378901484c1SDavid du Colombier {
379901484c1SDavid du Colombier 	int i, j, k, l, bits;
380901484c1SDavid du Colombier 	char *s;
381901484c1SDavid du Colombier 
382901484c1SDavid du Colombier 	dprint("m10g eprom:\n");
383901484c1SDavid du Colombier 	s = c->eprom;
384901484c1SDavid du Colombier 	bits = 3;
385901484c1SDavid du Colombier 	for(i = 0; s[i] && i < Epromsz; i++){
386901484c1SDavid du Colombier 		l = strlen(s+i);
387901484c1SDavid du Colombier 		dprint("\t%s\n", s+i);
388901484c1SDavid du Colombier 		if(strncmp(s+i, "MAC=", 4) == 0 && l == 4+12+5){
389901484c1SDavid du Colombier 			bits ^= 1;
390901484c1SDavid du Colombier 			j = i + 4;
391901484c1SDavid du Colombier 			for(k = 0; k < 6; k++)
392901484c1SDavid du Colombier 				c->ra[k] = strtoul(s+j+3*k, 0, 16);
393901484c1SDavid du Colombier 		}else if(strncmp(s+i, "SN=", 3) == 0){
394901484c1SDavid du Colombier 			bits ^= 2;
395901484c1SDavid du Colombier 			c->serial = atoi(s+i+3);
396901484c1SDavid du Colombier 		}
397901484c1SDavid du Colombier 		i += l;
398901484c1SDavid du Colombier 	}
399901484c1SDavid du Colombier 	if(bits)
400901484c1SDavid du Colombier 		return -1;
401901484c1SDavid du Colombier 	return 0;
402901484c1SDavid du Colombier }
403901484c1SDavid du Colombier 
40491b330d9SDavid du Colombier static ushort
pbit16(ushort i)40591b330d9SDavid du Colombier pbit16(ushort i)
406901484c1SDavid du Colombier {
40791b330d9SDavid du Colombier 	ushort j;
408901484c1SDavid du Colombier 	uchar *p;
409901484c1SDavid du Colombier 
410901484c1SDavid du Colombier 	p = (uchar*)&j;
411901484c1SDavid du Colombier 	p[1] = i;
412901484c1SDavid du Colombier 	p[0] = i>>8;
413901484c1SDavid du Colombier 	return j;
414901484c1SDavid du Colombier }
415901484c1SDavid du Colombier 
41691b330d9SDavid du Colombier static ushort
gbit16(uchar i[2])417901484c1SDavid du Colombier gbit16(uchar i[2])
418901484c1SDavid du Colombier {
41991b330d9SDavid du Colombier 	ushort j;
420901484c1SDavid du Colombier 
421901484c1SDavid du Colombier 	j  = i[1];
422901484c1SDavid du Colombier 	j |= i[0]<<8;
423901484c1SDavid du Colombier 	return j;
424901484c1SDavid du Colombier }
425901484c1SDavid du Colombier 
42691b330d9SDavid du Colombier static ulong
pbit32(ulong i)42791b330d9SDavid du Colombier pbit32(ulong i)
428901484c1SDavid du Colombier {
42991b330d9SDavid du Colombier 	ulong j;
430901484c1SDavid du Colombier 	uchar *p;
431901484c1SDavid du Colombier 
432901484c1SDavid du Colombier 	p = (uchar*)&j;
433901484c1SDavid du Colombier 	p[3] = i;
434901484c1SDavid du Colombier 	p[2] = i>>8;
435901484c1SDavid du Colombier 	p[1] = i>>16;
436901484c1SDavid du Colombier 	p[0] = i>>24;
437901484c1SDavid du Colombier 	return j;
438901484c1SDavid du Colombier }
439901484c1SDavid du Colombier 
44091b330d9SDavid du Colombier static ulong
gbit32(uchar i[4])441901484c1SDavid du Colombier gbit32(uchar i[4])
442901484c1SDavid du Colombier {
44391b330d9SDavid du Colombier 	ulong j;
444901484c1SDavid du Colombier 
445901484c1SDavid du Colombier 	j  = i[3];
446901484c1SDavid du Colombier 	j |= i[2]<<8;
447901484c1SDavid du Colombier 	j |= i[1]<<16;
448901484c1SDavid du Colombier 	j |= i[0]<<24;
449901484c1SDavid du Colombier 	return j;
450901484c1SDavid du Colombier }
451901484c1SDavid du Colombier 
452901484c1SDavid du Colombier static void
prepcmd(ulong * cmd,int i)45391b330d9SDavid du Colombier prepcmd(ulong *cmd, int i)
454901484c1SDavid du Colombier {
455901484c1SDavid du Colombier 	while(i-- > 0)
456901484c1SDavid du Colombier 		cmd[i] = pbit32(cmd[i]);
457901484c1SDavid du Colombier }
458901484c1SDavid du Colombier 
459901484c1SDavid du Colombier /*
460901484c1SDavid du Colombier  * the command looks like this (int 32bit integers)
461901484c1SDavid du Colombier  * cmd type
462901484c1SDavid du Colombier  * addr (low)
463901484c1SDavid du Colombier  * addr (high)
464901484c1SDavid du Colombier  * pad (used for dma testing)
465901484c1SDavid du Colombier  * response (high)
466901484c1SDavid du Colombier  * response (low)
467901484c1SDavid du Colombier  * 40 byte = 5 int pad.
468901484c1SDavid du Colombier  */
469901484c1SDavid du Colombier 
47091b330d9SDavid du Colombier ulong
cmd(Ctlr * c,int type,uvlong data)47191b330d9SDavid du Colombier cmd(Ctlr *c, int type, uvlong data)
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] = data;
48241ac1ab6SDavid du Colombier 	buf[2] = data >> 32;
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: cmd 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 
51091b330d9SDavid du Colombier ulong
maccmd(Ctlr * c,int type,uchar * m)511901484c1SDavid du Colombier maccmd(Ctlr *c, int type, uchar *m)
512901484c1SDavid du Colombier {
51391b330d9SDavid du Colombier 	ulong buf[16], i;
514901484c1SDavid du Colombier 	Cmd *cmd;
515901484c1SDavid du Colombier 
516901484c1SDavid du Colombier 	qlock(&c->cmdl);
517901484c1SDavid du Colombier 	cmd = c->cmd;
518901484c1SDavid du Colombier 	cmd->i[1] = Noconf;
519901484c1SDavid du Colombier 	memset(buf, 0, sizeof buf);
520901484c1SDavid du Colombier 	buf[0] = type;
521901484c1SDavid du Colombier 	buf[1] = m[0]<<24 | m[1]<<16 | m[2]<<8 | m[3];
522901484c1SDavid du Colombier 	buf[2] = m[4]<< 8 | m[5];
52341ac1ab6SDavid du Colombier 	buf[4] = c->cprt >> 32;
524901484c1SDavid du Colombier 	buf[5] = c->cprt;
525901484c1SDavid du Colombier 	prepcmd(buf, 6);
526901484c1SDavid du Colombier 	coherence();
527901484c1SDavid du Colombier 	memmove(c->ram + Cmdoff, buf, sizeof buf);
528901484c1SDavid du Colombier 
5296083aa43SDavid du Colombier 	if(waserror()){
5306083aa43SDavid du Colombier 		qunlock(&c->cmdl);
531901484c1SDavid du Colombier 		nexterror();
5326083aa43SDavid du Colombier 	}
533901484c1SDavid du Colombier 	for(i = 0; i < 15; i++){
534901484c1SDavid du Colombier 		if(cmd->i[1] != Noconf){
535901484c1SDavid du Colombier 			poperror();
536901484c1SDavid du Colombier 			i = gbit32(cmd->c);
537901484c1SDavid du Colombier 			qunlock(&c->cmdl);
538901484c1SDavid du Colombier 			if(cmd->i[1] != 0)
53991b330d9SDavid du Colombier 				dprint("[%lux]", i);
5406083aa43SDavid du Colombier 			return i;	/* normal return */
541901484c1SDavid du Colombier 		}
542901484c1SDavid du Colombier 		tsleep(&up->sleep, return0, 0, 1);
543901484c1SDavid du Colombier 	}
544901484c1SDavid du Colombier 	iprint("m10g: maccmd timeout [%ux %ux] cmd=%d\n",
545901484c1SDavid du Colombier 		cmd->i[0], cmd->i[1], type);
546901484c1SDavid du Colombier 	error(Etimeout);
547901484c1SDavid du Colombier 	return ~0;			/* silence! */
548901484c1SDavid du Colombier }
549901484c1SDavid du Colombier 
550901484c1SDavid du Colombier /* remove this garbage after testing */
551901484c1SDavid du Colombier enum {
552901484c1SDavid du Colombier 	DMAread	= 0x10000,
553901484c1SDavid du Colombier 	DMAwrite= 0x1,
554901484c1SDavid du Colombier };
555901484c1SDavid du Colombier 
55691b330d9SDavid du Colombier ulong
dmatestcmd(Ctlr * c,int type,uvlong addr,int len)55791b330d9SDavid du Colombier dmatestcmd(Ctlr *c, int type, uvlong addr, int len)
558901484c1SDavid du Colombier {
55991b330d9SDavid du Colombier 	ulong buf[16], i;
560901484c1SDavid du Colombier 
561901484c1SDavid du Colombier 	memset(buf, 0, sizeof buf);
562901484c1SDavid du Colombier 	memset(c->cmd, Noconf, sizeof *c->cmd);
563901484c1SDavid du Colombier 	buf[0] = Cdmatest;
564901484c1SDavid du Colombier 	buf[1] = addr;
56541ac1ab6SDavid du Colombier 	buf[2] = addr >> 32;
566901484c1SDavid du Colombier 	buf[3] = len * type;
56741ac1ab6SDavid du Colombier 	buf[4] = c->cprt >> 32;
568901484c1SDavid du Colombier 	buf[5] = c->cprt;
569901484c1SDavid du Colombier 	prepcmd(buf, 6);
570901484c1SDavid du Colombier 	coherence();
571901484c1SDavid du Colombier 	memmove(c->ram + Cmdoff, buf, sizeof buf);
572901484c1SDavid du Colombier 
573901484c1SDavid du Colombier 	for(i = 0; i < 15; i++){
574901484c1SDavid du Colombier 		if(c->cmd->i[1] != Noconf){
575901484c1SDavid du Colombier 			i = gbit32(c->cmd->c);
576901484c1SDavid du Colombier 			if(i == 0)
577901484c1SDavid du Colombier 				error(Eio);
5786083aa43SDavid du Colombier 			return i;	/* normal return */
579901484c1SDavid du Colombier 		}
580901484c1SDavid du Colombier 		tsleep(&up->sleep, return0, 0, 5);
581901484c1SDavid du Colombier 	}
582901484c1SDavid du Colombier 	error(Etimeout);
583901484c1SDavid du Colombier 	return ~0;			/* silence! */
584901484c1SDavid du Colombier }
585901484c1SDavid du Colombier 
58691b330d9SDavid du Colombier ulong
rdmacmd(Ctlr * c,int on)587901484c1SDavid du Colombier rdmacmd(Ctlr *c, int on)
588901484c1SDavid du Colombier {
58991b330d9SDavid du Colombier 	ulong buf[16], i;
590901484c1SDavid du Colombier 
591901484c1SDavid du Colombier 	memset(buf, 0, sizeof buf);
592901484c1SDavid du Colombier 	c->cmd->i[0] = 0;
593901484c1SDavid du Colombier 	coherence();
59441ac1ab6SDavid du Colombier 	buf[0] = c->cprt >> 32;
595901484c1SDavid du Colombier 	buf[1] = c->cprt;
596901484c1SDavid du Colombier 	buf[2] = Noconf;
59741ac1ab6SDavid du Colombier 	buf[3] = c->cprt >> 32;
598901484c1SDavid du Colombier 	buf[4] = c->cprt;
599901484c1SDavid du Colombier 	buf[5] = on;
600901484c1SDavid du Colombier 	prepcmd(buf, 6);
601901484c1SDavid du Colombier 	memmove(c->ram + Rdmaoff, buf, sizeof buf);
602901484c1SDavid du Colombier 
603901484c1SDavid du Colombier 	for(i = 0; i < 20; i++){
6046083aa43SDavid du Colombier 		if(c->cmd->i[0] == Noconf)
6056083aa43SDavid du Colombier 			return gbit32(c->cmd->c);	/* normal return */
606901484c1SDavid du Colombier 		tsleep(&up->sleep, return0, 0, 1);
607901484c1SDavid du Colombier 	}
608901484c1SDavid du Colombier 	iprint("m10g: rdmacmd timeout\n");
6096083aa43SDavid du Colombier 	error(Etimeout);
610901484c1SDavid du Colombier 	return ~0;			/* silence! */
611901484c1SDavid du Colombier }
612901484c1SDavid du Colombier 
613901484c1SDavid du Colombier static int
loadfw(Ctlr * c,int * align)614901484c1SDavid du Colombier loadfw(Ctlr *c, int *align)
615901484c1SDavid du Colombier {
61691b330d9SDavid du Colombier 	ulong *f, *s, sz;
617901484c1SDavid du Colombier 	int i;
618901484c1SDavid du Colombier 
61941ac1ab6SDavid du Colombier 	if((*align = whichfw(c->pcidev)) == 4*KiB){
62091b330d9SDavid du Colombier 		f = (ulong*)fw4k;
621901484c1SDavid du Colombier 		sz = sizeof fw4k;
622901484c1SDavid du Colombier 	}else{
62391b330d9SDavid du Colombier 		f = (ulong*)fw2k;
624901484c1SDavid du Colombier 		sz = sizeof fw2k;
625901484c1SDavid du Colombier 	}
626901484c1SDavid du Colombier 
62791b330d9SDavid du Colombier 	s = (ulong*)(c->ram + Fwoffset);
628901484c1SDavid du Colombier 	for(i = 0; i < sz / 4; i++)
629901484c1SDavid du Colombier 		s[i] = f[i];
630901484c1SDavid du Colombier 	return sz & ~3;
631901484c1SDavid du Colombier }
632901484c1SDavid du Colombier 
633901484c1SDavid du Colombier static int
bootfw(Ctlr * c)634901484c1SDavid du Colombier bootfw(Ctlr *c)
635901484c1SDavid du Colombier {
636901484c1SDavid du Colombier 	int i, sz, align;
63791b330d9SDavid du Colombier 	ulong buf[16];
638901484c1SDavid du Colombier 	Cmd* cmd;
639901484c1SDavid du Colombier 
640901484c1SDavid du Colombier 	if((sz = loadfw(c, &align)) == 0)
641901484c1SDavid du Colombier 		return 0;
642901484c1SDavid du Colombier 	dprint("bootfw %d bytes ... ", sz);
643901484c1SDavid du Colombier 	cmd = c->cmd;
644901484c1SDavid du Colombier 
645901484c1SDavid du Colombier 	memset(buf, 0, sizeof buf);
646901484c1SDavid du Colombier 	c->cmd->i[0] = 0;
647901484c1SDavid du Colombier 	coherence();
64841ac1ab6SDavid du Colombier 	buf[0] = c->cprt >> 32;	/* upper dma target address */
649901484c1SDavid du Colombier 	buf[1] = c->cprt;	/* lower */
650901484c1SDavid du Colombier 	buf[2] = Noconf;	/* writeback */
651901484c1SDavid du Colombier 	buf[3] = Fwoffset + 8,
652901484c1SDavid du Colombier 	buf[4] = sz - 8;
653901484c1SDavid du Colombier 	buf[5] = 8;
654901484c1SDavid du Colombier 	buf[6] = 0;
655901484c1SDavid du Colombier 	prepcmd(buf, 7);
656901484c1SDavid du Colombier 	coherence();
657901484c1SDavid du Colombier 	memmove(c->ram + Fwsubmt, buf, sizeof buf);
658901484c1SDavid du Colombier 
659901484c1SDavid du Colombier 	for(i = 0; i < 20; i++){
660901484c1SDavid du Colombier 		if(cmd->i[0] == Noconf)
661901484c1SDavid du Colombier 			break;
662901484c1SDavid du Colombier 		delay(1);
663901484c1SDavid du Colombier 	}
66491b330d9SDavid du Colombier 	dprint("[%lux %lux]", gbit32(cmd->c), gbit32(cmd->c+4));
665901484c1SDavid du Colombier 	if(i == 20){
666901484c1SDavid du Colombier 		print("m10g: cannot load fw\n");
667901484c1SDavid du Colombier 		return -1;
668901484c1SDavid du Colombier 	}
669901484c1SDavid du Colombier 	dprint("\n");
670901484c1SDavid du Colombier 	c->tx.segsz = align;
671901484c1SDavid du Colombier 	return 0;
672901484c1SDavid du Colombier }
673901484c1SDavid du Colombier 
67441ac1ab6SDavid du Colombier static int
kickthebaby(Pcidev * p,Ctlr * c)675901484c1SDavid du Colombier kickthebaby(Pcidev *p, Ctlr *c)
676901484c1SDavid du Colombier {
677901484c1SDavid du Colombier 	/* don't kick the baby! */
67891b330d9SDavid du Colombier 	ulong code;
679901484c1SDavid du Colombier 
680901484c1SDavid du Colombier 	pcicfgw8(p,  0x10 + c->boot, 0x3);
681901484c1SDavid du Colombier 	pcicfgw32(p, 0x18 + c->boot, 0xfffffff0);
682901484c1SDavid du Colombier 	code = pcicfgr32(p, 0x14 + c->boot);
683901484c1SDavid du Colombier 
68491b330d9SDavid du Colombier 	dprint("reboot status = %lux\n", code);
685901484c1SDavid du Colombier 	if(code != 0xfffffff0)
686901484c1SDavid du Colombier 		return -1;
687901484c1SDavid du Colombier 	return 0;
688901484c1SDavid du Colombier }
689901484c1SDavid du Colombier 
690901484c1SDavid du Colombier typedef struct {
691901484c1SDavid du Colombier 	uchar	len[4];
692901484c1SDavid du Colombier 	uchar	type[4];
693901484c1SDavid du Colombier 	char	version[128];
694901484c1SDavid du Colombier 	uchar	globals[4];
695901484c1SDavid du Colombier 	uchar	ramsz[4];
696901484c1SDavid du Colombier 	uchar	specs[4];
697901484c1SDavid du Colombier 	uchar	specssz[4];
698901484c1SDavid du Colombier } Fwhdr;
699901484c1SDavid du Colombier 
700901484c1SDavid du Colombier enum {
701901484c1SDavid du Colombier 	Tmx	= 0x4d582020,
702901484c1SDavid du Colombier 	Tpcie	= 0x70636965,
703901484c1SDavid du Colombier 	Teth	= 0x45544820,
704901484c1SDavid du Colombier 	Tmcp0	= 0x4d435030,
705901484c1SDavid du Colombier };
706901484c1SDavid du Colombier 
70741ac1ab6SDavid du Colombier static char *
fwtype(ulong type)70891b330d9SDavid du Colombier fwtype(ulong type)
709901484c1SDavid du Colombier {
710901484c1SDavid du Colombier 	switch(type){
711901484c1SDavid du Colombier 	case Tmx:
712901484c1SDavid du Colombier 		return "mx";
713901484c1SDavid du Colombier 	case Tpcie:
714901484c1SDavid du Colombier 		return "PCIe";
715901484c1SDavid du Colombier 	case Teth:
716901484c1SDavid du Colombier 		return "eth";
717901484c1SDavid du Colombier 	case Tmcp0:
718901484c1SDavid du Colombier 		return "mcp0";
719901484c1SDavid du Colombier 	}
720901484c1SDavid du Colombier 	return "*GOK*";
721901484c1SDavid du Colombier }
722901484c1SDavid du Colombier 
72341ac1ab6SDavid du Colombier static int
chkfw(Ctlr * c)724901484c1SDavid du Colombier chkfw(Ctlr *c)
725901484c1SDavid du Colombier {
72664a26757SDavid du Colombier 	ulong off, type;
727901484c1SDavid du Colombier 	Fwhdr *h;
728901484c1SDavid du Colombier 
729901484c1SDavid du Colombier 	off = gbit32(c->ram+0x3c);
73064a26757SDavid du Colombier 	dprint("firmware %lux\n", off);
731901484c1SDavid du Colombier 	if((off&3) || off + sizeof *h > c->ramsz){
73264a26757SDavid du Colombier 		print("!m10g: bad firmware %lux\n", off);
733901484c1SDavid du Colombier 		return -1;
734901484c1SDavid du Colombier 	}
735901484c1SDavid du Colombier 	h = (Fwhdr*)(c->ram + off);
736901484c1SDavid du Colombier 	type = gbit32(h->type);
737901484c1SDavid du Colombier 	dprint("\t" "type	%s\n", fwtype(type));
738901484c1SDavid du Colombier 	dprint("\t" "vers	%s\n", h->version);
73991b330d9SDavid du Colombier 	dprint("\t" "ramsz	%lux\n", gbit32(h->ramsz));
740901484c1SDavid du Colombier 	if(type != Teth){
741901484c1SDavid du Colombier 		print("!m10g: bad card type %s\n", fwtype(type));
742901484c1SDavid du Colombier 		return -1;
743901484c1SDavid du Colombier 	}
744901484c1SDavid du Colombier 
745901484c1SDavid du Colombier 	return bootfw(c) || rdmacmd(c, 0);
746901484c1SDavid du Colombier }
747901484c1SDavid du Colombier 
748901484c1SDavid du Colombier static int
reset(Ether * e,Ctlr * c)749901484c1SDavid du Colombier reset(Ether *e, Ctlr *c)
750901484c1SDavid du Colombier {
75191b330d9SDavid du Colombier 	ulong i, sz;
752901484c1SDavid du Colombier 
753901484c1SDavid du Colombier 	if(waserror()){
754901484c1SDavid du Colombier 		print("m10g: reset error\n");
755901484c1SDavid du Colombier 		nexterror();
756901484c1SDavid du Colombier 		return -1;
757901484c1SDavid du Colombier 	}
758901484c1SDavid du Colombier 
759901484c1SDavid du Colombier 	chkfw(c);
760901484c1SDavid du Colombier 	cmd(c, Creset, 0);
761901484c1SDavid du Colombier 
762901484c1SDavid du Colombier 	cmd(c, CSintrqsz, c->done.n * sizeof *c->done.entry);
763901484c1SDavid du Colombier 	cmd(c, CSintrqdma, c->done.busaddr);
76491b330d9SDavid du Colombier 	c->irqack =   (ulong*)(c->ram + cmd(c, CGirqackoff, 0));
765901484c1SDavid du Colombier 	/* required only if we're not doing msi? */
76691b330d9SDavid du Colombier 	c->irqdeass = (ulong*)(c->ram + cmd(c, CGirqdeassoff, 0));
767901484c1SDavid du Colombier 	/* this is the driver default, why fiddle with this? */
76891b330d9SDavid du Colombier 	c->coal = (ulong*)(c->ram + cmd(c, CGcoaloff, 0));
769901484c1SDavid du Colombier 	*c->coal = pbit32(25);
770901484c1SDavid du Colombier 
771901484c1SDavid du Colombier 	dprint("dma stats:\n");
772901484c1SDavid du Colombier 	rdmacmd(c, 1);
773901484c1SDavid du Colombier 	sz = c->tx.segsz;
774901484c1SDavid du Colombier 	i = dmatestcmd(c, DMAread, c->done.busaddr, sz);
77580088de7SDavid du Colombier 	print("m10g: read %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff));
776901484c1SDavid du Colombier 	i = dmatestcmd(c, DMAwrite, c->done.busaddr, sz);
77780088de7SDavid du Colombier 	print(" write %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff));
778901484c1SDavid du Colombier 	i = dmatestcmd(c, DMAwrite|DMAread, c->done.busaddr, sz);
77980088de7SDavid du Colombier 	print(" r/w %lud MB/s\n", ((i>>16)*sz*2*2) / (i&0xffff));
780901484c1SDavid du Colombier 	memset(c->done.entry, 0, c->done.n * sizeof *c->done.entry);
781901484c1SDavid du Colombier 
782901484c1SDavid du Colombier 	maccmd(c, CSmac, c->ra);
783901484c1SDavid du Colombier //	cmd(c, Cnopromisc, 0);
784901484c1SDavid du Colombier 	cmd(c, Cenablefc, 0);
785901484c1SDavid du Colombier 	e->maxmtu = Maxmtu;
786901484c1SDavid du Colombier 	cmd(c, CSmtu, e->maxmtu);
787901484c1SDavid du Colombier 	dprint("CSmtu %d...\n", e->maxmtu);
788901484c1SDavid du Colombier 
789901484c1SDavid du Colombier 	poperror();
790901484c1SDavid du Colombier 	return 0;
791901484c1SDavid du Colombier }
792901484c1SDavid du Colombier 
793901484c1SDavid du Colombier static void
ctlrfree(Ctlr * c)794901484c1SDavid du Colombier ctlrfree(Ctlr *c)
795901484c1SDavid du Colombier {
796901484c1SDavid du Colombier 	/* free up all the Block*s, too */
797901484c1SDavid du Colombier 	free(c->tx.host);
798901484c1SDavid du Colombier 	free(c->sm.host);
799901484c1SDavid du Colombier 	free(c->bg.host);
800901484c1SDavid du Colombier 	free(c->cmd);
801901484c1SDavid du Colombier 	free(c->done.entry);
802901484c1SDavid du Colombier 	free(c->stats);
803901484c1SDavid du Colombier 	free(c);
804901484c1SDavid du Colombier }
805901484c1SDavid du Colombier 
806901484c1SDavid du Colombier static int
setmem(Pcidev * p,Ctlr * c)807901484c1SDavid du Colombier setmem(Pcidev *p, Ctlr *c)
808901484c1SDavid du Colombier {
80991b330d9SDavid du Colombier 	ulong i;
81091b330d9SDavid du Colombier 	uvlong raddr;
811901484c1SDavid du Colombier 	Done *d;
812901484c1SDavid du Colombier 	void *mem;
813901484c1SDavid du Colombier 
814901484c1SDavid du Colombier 	c->tx.segsz = 2048;
81541ac1ab6SDavid du Colombier 	c->ramsz = 2*MiB - (2*48*KiB + 32*KiB) - 0x100;
816901484c1SDavid du Colombier 	if(c->ramsz > p->mem[0].size)
817901484c1SDavid du Colombier 		return -1;
818901484c1SDavid du Colombier 
819901484c1SDavid du Colombier 	raddr = p->mem[0].bar & ~0x0F;
820901484c1SDavid du Colombier 	mem = vmap(raddr, p->mem[0].size);
821901484c1SDavid du Colombier 	if(mem == nil){
822901484c1SDavid du Colombier 		print("m10g: can't map %8.8lux\n", p->mem[0].bar);
823901484c1SDavid du Colombier 		return -1;
824901484c1SDavid du Colombier 	}
82541ac1ab6SDavid du Colombier 	dprint("%llux <- vmap(mem[0].size = %ux)\n", raddr, p->mem[0].size);
826901484c1SDavid du Colombier 	c->port = raddr;
827901484c1SDavid du Colombier 	c->ram = mem;
828901484c1SDavid du Colombier 	c->cmd = malign(sizeof *c->cmd);
829901484c1SDavid du Colombier 	c->cprt = PCIWADDR(c->cmd);
830901484c1SDavid du Colombier 
831901484c1SDavid du Colombier 	d = &c->done;
832901484c1SDavid du Colombier 	d->n = Maxslots;
833901484c1SDavid du Colombier 	d->m = d->n - 1;
834901484c1SDavid du Colombier 	i = d->n * sizeof *d->entry;
835901484c1SDavid du Colombier 	d->entry = malign(i);
836901484c1SDavid du Colombier 	memset(d->entry, 0, i);
837901484c1SDavid du Colombier 	d->busaddr = PCIWADDR(d->entry);
838901484c1SDavid du Colombier 
839901484c1SDavid du Colombier 	c->stats = malign(sizeof *c->stats);
840901484c1SDavid du Colombier 	memset(c->stats, 0, sizeof *c->stats);
841901484c1SDavid du Colombier 	c->statsprt = PCIWADDR(c->stats);
842901484c1SDavid du Colombier 
843901484c1SDavid du Colombier 	memmove(c->eprom, c->ram + c->ramsz - Epromsz, Epromsz-2);
844901484c1SDavid du Colombier 	return setpcie(p) || parseeprom(c);
845901484c1SDavid du Colombier }
846901484c1SDavid du Colombier 
847901484c1SDavid du Colombier static Rx*
whichrx(Ctlr * c,int sz)848901484c1SDavid du Colombier whichrx(Ctlr *c, int sz)
849901484c1SDavid du Colombier {
850901484c1SDavid du Colombier 	if(sz <= smpool.size)
851901484c1SDavid du Colombier 		return &c->sm;
852901484c1SDavid du Colombier 	return &c->bg;
853901484c1SDavid du Colombier }
854901484c1SDavid du Colombier 
855901484c1SDavid du Colombier static Block*
balloc(Rx * rx)856901484c1SDavid du Colombier balloc(Rx* rx)
857901484c1SDavid du Colombier {
8587fd2696aSDavid du Colombier 	Block *bp;
859901484c1SDavid du Colombier 
860901484c1SDavid du Colombier 	ilock(rx->pool);
8617fd2696aSDavid du Colombier 	if((bp = rx->pool->head) != nil){
8627fd2696aSDavid du Colombier 		rx->pool->head = bp->next;
8637fd2696aSDavid du Colombier 		bp->next = nil;
8647fd2696aSDavid du Colombier 		_xinc(&bp->ref);	/* prevent bp from being freed */
865901484c1SDavid du Colombier 		rx->pool->n--;
866901484c1SDavid du Colombier 	}
867901484c1SDavid du Colombier 	iunlock(rx->pool);
8687fd2696aSDavid du Colombier 	return bp;
869901484c1SDavid du Colombier }
870901484c1SDavid du Colombier 
871901484c1SDavid du Colombier static void
rbfree(Block * b,Bpool * p)872bfb6eab9SDavid du Colombier rbfree(Block *b, Bpool *p)
873901484c1SDavid du Colombier {
874901484c1SDavid du Colombier 	b->rp = b->wp = (uchar*)PGROUND((uintptr)b->base);
875bfb6eab9SDavid du Colombier  	b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
876bfb6eab9SDavid du Colombier 
877901484c1SDavid du Colombier 	ilock(p);
878901484c1SDavid du Colombier 	b->next = p->head;
879901484c1SDavid du Colombier 	p->head = b;
880901484c1SDavid du Colombier 	p->n++;
881901484c1SDavid du Colombier 	p->cnt++;
882901484c1SDavid du Colombier 	iunlock(p);
883901484c1SDavid du Colombier }
884901484c1SDavid du Colombier 
885901484c1SDavid du Colombier static void
smbfree(Block * b)886bfb6eab9SDavid du Colombier smbfree(Block *b)
887bfb6eab9SDavid du Colombier {
888bfb6eab9SDavid du Colombier 	rbfree(b, &smpool);
889bfb6eab9SDavid du Colombier }
890bfb6eab9SDavid du Colombier 
891bfb6eab9SDavid du Colombier static void
bgbfree(Block * b)892901484c1SDavid du Colombier bgbfree(Block *b)
893901484c1SDavid du Colombier {
894bfb6eab9SDavid du Colombier 	rbfree(b, &bgpool);
895901484c1SDavid du Colombier }
896901484c1SDavid du Colombier 
897901484c1SDavid du Colombier static void
replenish(Rx * rx)898901484c1SDavid du Colombier replenish(Rx *rx)
899901484c1SDavid du Colombier {
90091b330d9SDavid du Colombier 	ulong buf[16], i, idx, e;
901901484c1SDavid du Colombier 	Bpool *p;
902901484c1SDavid du Colombier 	Block *b;
903901484c1SDavid du Colombier 
904901484c1SDavid du Colombier 	p = rx->pool;
905901484c1SDavid du Colombier 	if(p->n < 8)
906901484c1SDavid du Colombier 		return;
907901484c1SDavid du Colombier 	memset(buf, 0, sizeof buf);
908901484c1SDavid du Colombier 	e = (rx->i - rx->cnt) & ~7;
909901484c1SDavid du Colombier 	e += rx->n;
910901484c1SDavid du Colombier 	while(p->n >= 8 && e){
911901484c1SDavid du Colombier 		idx = rx->cnt & rx->m;
912901484c1SDavid du Colombier 		for(i = 0; i < 8; i++){
913901484c1SDavid du Colombier 			b = balloc(rx);
91491b330d9SDavid du Colombier 			buf[i*2]   = pbit32((uvlong)PCIWADDR(b->wp) >> 32);
915901484c1SDavid du Colombier 			buf[i*2+1] = pbit32(PCIWADDR(b->wp));
916901484c1SDavid du Colombier 			rx->host[idx+i] = b;
917901484c1SDavid du Colombier 			assert(b);
918901484c1SDavid du Colombier 		}
919901484c1SDavid du Colombier 		memmove(rx->lanai + 2*idx, buf, sizeof buf);
920901484c1SDavid du Colombier 		coherence();
921901484c1SDavid du Colombier 		rx->cnt += 8;
922901484c1SDavid du Colombier 		e -= 8;
923901484c1SDavid du Colombier 	}
924901484c1SDavid du Colombier 	if(e && p->n > 7+1)
92580088de7SDavid du Colombier 		print("m10g: should panic? pool->n = %d\n", p->n);
926901484c1SDavid du Colombier }
927901484c1SDavid du Colombier 
928901484c1SDavid du Colombier /*
929901484c1SDavid du Colombier  * future:
930901484c1SDavid du Colombier  * if (c->mtrr >= 0) {
931901484c1SDavid du Colombier  *	c->tx.wcfifo = c->ram+0x200000;
932901484c1SDavid du Colombier  *	c->sm.wcfifo = c->ram+0x300000;
933901484c1SDavid du Colombier  *	c->bg.wcfifo = c->ram+0x340000;
934901484c1SDavid du Colombier  * }
935901484c1SDavid du Colombier  */
936901484c1SDavid du Colombier 
937901484c1SDavid du Colombier static int
nextpow(int j)938901484c1SDavid du Colombier nextpow(int j)
939901484c1SDavid du Colombier {
940901484c1SDavid du Colombier 	int i;
941901484c1SDavid du Colombier 
942901484c1SDavid du Colombier 	for(i = 0; j > (1 << i); i++)
943901484c1SDavid du Colombier 		;
944901484c1SDavid du Colombier 	return 1 << i;
945901484c1SDavid du Colombier }
946901484c1SDavid du Colombier 
947901484c1SDavid du Colombier static void*
emalign(int sz)948901484c1SDavid du Colombier emalign(int sz)
949901484c1SDavid du Colombier {
950901484c1SDavid du Colombier 	void *v;
951901484c1SDavid du Colombier 
952901484c1SDavid du Colombier 	v = malign(sz);
953901484c1SDavid du Colombier 	if(v == nil)
954901484c1SDavid du Colombier 		error(Enomem);
955901484c1SDavid du Colombier 	memset(v, 0, sz);
956901484c1SDavid du Colombier 	return v;
957901484c1SDavid du Colombier }
958901484c1SDavid du Colombier 
959901484c1SDavid du Colombier static void
open0(Ether * e,Ctlr * c)960901484c1SDavid du Colombier open0(Ether *e, Ctlr *c)
961901484c1SDavid du Colombier {
962901484c1SDavid du Colombier 	Block *b;
963901484c1SDavid du Colombier 	int i, sz, entries;
964901484c1SDavid du Colombier 
965901484c1SDavid du Colombier 	entries = cmd(c, CGsendrgsz, 0) / sizeof *c->tx.lanai;
966901484c1SDavid du Colombier 	c->tx.lanai = (Send*)(c->ram + cmd(c, CGsendoff, 0));
967901484c1SDavid du Colombier 	c->tx.host  = emalign(entries * sizeof *c->tx.host);
968901484c1SDavid du Colombier 	c->tx.bring = emalign(entries * sizeof *c->tx.bring);
969901484c1SDavid du Colombier 	c->tx.n = entries;
970901484c1SDavid du Colombier 	c->tx.m = entries-1;
971901484c1SDavid du Colombier 
972901484c1SDavid du Colombier 	entries = cmd(c, CGrxrgsz, 0)/8;
973901484c1SDavid du Colombier 	c->sm.pool = &smpool;
974901484c1SDavid du Colombier 	cmd(c, CSsmallsz, c->sm.pool->size);
97591b330d9SDavid du Colombier 	c->sm.lanai = (ulong*)(c->ram + cmd(c, CGsmallrxoff, 0));
976901484c1SDavid du Colombier 	c->sm.n = entries;
977901484c1SDavid du Colombier 	c->sm.m = entries-1;
978901484c1SDavid du Colombier 	c->sm.host = emalign(entries * sizeof *c->sm.host);
979901484c1SDavid du Colombier 
980901484c1SDavid du Colombier 	c->bg.pool = &bgpool;
981901484c1SDavid du Colombier 	c->bg.pool->size = nextpow(2 + e->maxmtu);  /* 2-byte alignment pad */
982901484c1SDavid du Colombier 	cmd(c, CSbigsz, c->bg.pool->size);
98391b330d9SDavid du Colombier 	c->bg.lanai = (ulong*)(c->ram + cmd(c, CGbigrxoff, 0));
984901484c1SDavid du Colombier 	c->bg.n = entries;
985901484c1SDavid du Colombier 	c->bg.m = entries-1;
986901484c1SDavid du Colombier 	c->bg.host = emalign(entries * sizeof *c->bg.host);
987901484c1SDavid du Colombier 
988901484c1SDavid du Colombier 	sz = c->sm.pool->size + BY2PG;
989901484c1SDavid du Colombier 	for(i = 0; i < c->sm.n; i++){
990901484c1SDavid du Colombier 		if((b = allocb(sz)) == 0)
991901484c1SDavid du Colombier 			break;
992901484c1SDavid du Colombier 		b->free = smbfree;
993901484c1SDavid du Colombier 		freeb(b);
994901484c1SDavid du Colombier 	}
995901484c1SDavid du Colombier 	sz = c->bg.pool->size + BY2PG;
996901484c1SDavid du Colombier 	for(i = 0; i < c->bg.n; i++){
997901484c1SDavid du Colombier 		if((b = allocb(sz)) == 0)
998901484c1SDavid du Colombier 			break;
999901484c1SDavid du Colombier 		b->free = bgbfree;
1000901484c1SDavid du Colombier 		freeb(b);
1001901484c1SDavid du Colombier 	}
1002901484c1SDavid du Colombier 
1003901484c1SDavid du Colombier 	cmd(c, CSstatsdma, c->statsprt);
1004901484c1SDavid du Colombier 	c->linkstat = ~0;
1005901484c1SDavid du Colombier 	c->nrdma = 15;
1006901484c1SDavid du Colombier 
1007901484c1SDavid du Colombier 	cmd(c, Cetherup, 0);
1008901484c1SDavid du Colombier }
1009901484c1SDavid du Colombier 
1010901484c1SDavid du Colombier static Block*
nextblock(Ctlr * c)1011901484c1SDavid du Colombier nextblock(Ctlr *c)
1012901484c1SDavid du Colombier {
1013901484c1SDavid du Colombier 	uint i;
101491b330d9SDavid du Colombier 	ushort l, k;
1015901484c1SDavid du Colombier 	Block *b;
1016901484c1SDavid du Colombier 	Done *d;
1017901484c1SDavid du Colombier 	Rx *rx;
1018901484c1SDavid du Colombier 	Slot *s;
101941ac1ab6SDavid du Colombier 	Slotparts *sp;
1020901484c1SDavid du Colombier 
1021901484c1SDavid du Colombier 	d = &c->done;
1022901484c1SDavid du Colombier 	s = d->entry;
1023901484c1SDavid du Colombier 	i = d->i & d->m;
102441ac1ab6SDavid du Colombier 	sp = (Slotparts *)(s + i);
102541ac1ab6SDavid du Colombier 	l = sp->len;
1026901484c1SDavid du Colombier 	if(l == 0)
1027901484c1SDavid du Colombier 		return 0;
102841ac1ab6SDavid du Colombier 	k = sp->cksum;
102941ac1ab6SDavid du Colombier 	s[i] = 0;
1030901484c1SDavid du Colombier 	d->i++;
1031901484c1SDavid du Colombier 	l = gbit16((uchar*)&l);
1032901484c1SDavid du Colombier //dprint("nextb: i=%d l=%d\n", d->i, l);
1033901484c1SDavid du Colombier 	rx = whichrx(c, l);
1034901484c1SDavid du Colombier 	if(rx->i >= rx->cnt){
1035901484c1SDavid du Colombier 		iprint("m10g: overrun\n");
1036901484c1SDavid du Colombier 		return 0;
1037901484c1SDavid du Colombier 	}
1038901484c1SDavid du Colombier 	i = rx->i & rx->m;
1039901484c1SDavid du Colombier 	b = rx->host[i];
1040901484c1SDavid du Colombier 	rx->host[i] = 0;
1041901484c1SDavid du Colombier 	if(b == 0){
1042901484c1SDavid du Colombier 		iprint("m10g: error rx to no block.  memory is hosed.\n");
1043901484c1SDavid du Colombier 		return 0;
1044901484c1SDavid du Colombier 	}
1045901484c1SDavid du Colombier 	rx->i++;
1046901484c1SDavid du Colombier 
1047901484c1SDavid du Colombier 	b->flag |= Bipck|Btcpck|Budpck;
1048901484c1SDavid du Colombier 	b->checksum = k;
1049901484c1SDavid du Colombier 	b->rp += 2;
1050901484c1SDavid du Colombier 	b->wp += 2+l;
1051901484c1SDavid du Colombier 	b->lim = b->wp;			/* lie like a dog. */
1052901484c1SDavid du Colombier 	return b;
1053901484c1SDavid du Colombier }
1054901484c1SDavid du Colombier 
1055901484c1SDavid du Colombier static int
rxcansleep(void * v)1056901484c1SDavid du Colombier rxcansleep(void *v)
1057901484c1SDavid du Colombier {
1058901484c1SDavid du Colombier 	Ctlr *c;
1059901484c1SDavid du Colombier 	Slot *s;
106041ac1ab6SDavid du Colombier 	Slotparts *sp;
1061901484c1SDavid du Colombier 	Done *d;
1062901484c1SDavid du Colombier 
1063901484c1SDavid du Colombier 	c = v;
1064901484c1SDavid du Colombier 	d = &c->done;
1065901484c1SDavid du Colombier 	s = c->done.entry;
106641ac1ab6SDavid du Colombier 	sp = (Slotparts *)(s + (d->i & d->m));
106741ac1ab6SDavid du Colombier 	if(sp->len != 0)
1068901484c1SDavid du Colombier 		return -1;
1069901484c1SDavid du Colombier 	c->irqack[0] = pbit32(3);
1070901484c1SDavid du Colombier 	return 0;
1071901484c1SDavid du Colombier }
1072901484c1SDavid du Colombier 
1073901484c1SDavid du Colombier static void
m10rx(void * v)1074901484c1SDavid du Colombier m10rx(void *v)
1075901484c1SDavid du Colombier {
1076901484c1SDavid du Colombier 	Ether *e;
1077901484c1SDavid du Colombier 	Ctlr *c;
1078901484c1SDavid du Colombier 	Block *b;
1079901484c1SDavid du Colombier 
1080901484c1SDavid du Colombier 	e = v;
1081901484c1SDavid du Colombier 	c = e->ctlr;
1082901484c1SDavid du Colombier 	for(;;){
1083901484c1SDavid du Colombier 		replenish(&c->sm);
1084901484c1SDavid du Colombier 		replenish(&c->bg);
1085901484c1SDavid du Colombier 		sleep(&c->rxrendez, rxcansleep, c);
1086901484c1SDavid du Colombier 		while(b = nextblock(c))
1087901484c1SDavid du Colombier 			etheriq(e, b, 1);
1088901484c1SDavid du Colombier 	}
1089901484c1SDavid du Colombier }
1090901484c1SDavid du Colombier 
109141ac1ab6SDavid du Colombier static void
txcleanup(Tx * tx,ulong n)109291b330d9SDavid du Colombier txcleanup(Tx *tx, ulong n)
1093901484c1SDavid du Colombier {
1094901484c1SDavid du Colombier 	Block *b;
1095901484c1SDavid du Colombier 	uint j, l, m;
1096901484c1SDavid du Colombier 
1097901484c1SDavid du Colombier 	if(tx->npkt == n)
1098901484c1SDavid du Colombier 		return;
1099901484c1SDavid du Colombier 	l = 0;
1100901484c1SDavid du Colombier 	m = tx->m;
110141ac1ab6SDavid du Colombier 	/*
110241ac1ab6SDavid du Colombier 	 * if tx->cnt == tx->i, yet tx->npkt == n-1, we just
110341ac1ab6SDavid du Colombier 	 * caught ourselves and myricom card updating.
110441ac1ab6SDavid du Colombier 	 */
1105901484c1SDavid du Colombier 	for(;; tx->cnt++){
1106901484c1SDavid du Colombier 		j = tx->cnt & tx->m;
1107901484c1SDavid du Colombier 		if(b = tx->bring[j]){
1108901484c1SDavid du Colombier 			tx->bring[j] = 0;
1109901484c1SDavid du Colombier 			tx->nbytes += BLEN(b);
1110901484c1SDavid du Colombier 			freeb(b);
1111901484c1SDavid du Colombier 			if(++tx->npkt == n)
1112901484c1SDavid du Colombier 				return;
1113901484c1SDavid du Colombier 		}
1114901484c1SDavid du Colombier 		if(tx->cnt == tx->i)
1115901484c1SDavid du Colombier 			return;
1116901484c1SDavid du Colombier 		if(l++ == m){
111780088de7SDavid du Colombier 			iprint("m10g: tx ovrun: %lud %lud\n", n, tx->npkt);
1118901484c1SDavid du Colombier 			return;
1119901484c1SDavid du Colombier 		}
1120901484c1SDavid du Colombier 	}
1121901484c1SDavid du Colombier }
1122901484c1SDavid du Colombier 
1123901484c1SDavid du Colombier static int
txcansleep(void * v)1124901484c1SDavid du Colombier txcansleep(void *v)
1125901484c1SDavid du Colombier {
1126901484c1SDavid du Colombier 	Ctlr *c;
1127901484c1SDavid du Colombier 
1128901484c1SDavid du Colombier 	c = v;
1129901484c1SDavid du Colombier 	if(c->tx.cnt != c->tx.i && c->tx.npkt != gbit32(c->stats->txcnt))
1130901484c1SDavid du Colombier 		return -1;
1131901484c1SDavid du Colombier 	return 0;
1132901484c1SDavid du Colombier }
1133901484c1SDavid du Colombier 
113441ac1ab6SDavid du Colombier static void
txproc(void * v)1135901484c1SDavid du Colombier txproc(void *v)
1136901484c1SDavid du Colombier {
1137901484c1SDavid du Colombier 	Ether *e;
1138901484c1SDavid du Colombier 	Ctlr *c;
1139901484c1SDavid du Colombier 	Tx *tx;
1140901484c1SDavid du Colombier 
1141901484c1SDavid du Colombier 	e = v;
1142901484c1SDavid du Colombier 	c = e->ctlr;
1143901484c1SDavid du Colombier 	tx = &c->tx;
1144901484c1SDavid du Colombier 	for(;;){
1145901484c1SDavid du Colombier  		sleep(&c->txrendez, txcansleep, c);
1146901484c1SDavid du Colombier 		txcleanup(tx, gbit32(c->stats->txcnt));
1147901484c1SDavid du Colombier 	}
1148901484c1SDavid du Colombier }
1149901484c1SDavid du Colombier 
115041ac1ab6SDavid du Colombier static void
submittx(Tx * tx,int n)1151901484c1SDavid du Colombier submittx(Tx *tx, int n)
1152901484c1SDavid du Colombier {
1153901484c1SDavid du Colombier 	Send *l, *h;
1154901484c1SDavid du Colombier 	int i0, i, m;
1155901484c1SDavid du Colombier 
1156901484c1SDavid du Colombier 	m = tx->m;
1157901484c1SDavid du Colombier 	i0 = tx->i & m;
1158901484c1SDavid du Colombier 	l = tx->lanai;
1159901484c1SDavid du Colombier 	h = tx->host;
1160901484c1SDavid du Colombier 	for(i = n-1; i >= 0; i--)
1161901484c1SDavid du Colombier 		memmove(l+(i + i0 & m), h+(i + i0 & m), sizeof *h);
1162901484c1SDavid du Colombier 	tx->i += n;
1163901484c1SDavid du Colombier //	coherence();
1164901484c1SDavid du Colombier }
1165901484c1SDavid du Colombier 
116641ac1ab6SDavid du Colombier static int
nsegments(Block * b,int segsz)1167901484c1SDavid du Colombier nsegments(Block *b, int segsz)
1168901484c1SDavid du Colombier {
1169901484c1SDavid du Colombier 	uintptr bus, end, slen, len;
1170901484c1SDavid du Colombier 	int i;
1171901484c1SDavid du Colombier 
1172901484c1SDavid du Colombier 	bus = PCIWADDR(b->rp);
1173901484c1SDavid du Colombier 	i = 0;
1174901484c1SDavid du Colombier 	for(len = BLEN(b); len; len -= slen){
1175901484c1SDavid du Colombier 		end = bus + segsz & ~(segsz-1);
1176901484c1SDavid du Colombier 		slen = end - bus;
1177901484c1SDavid du Colombier 		if(slen > len)
1178901484c1SDavid du Colombier 			slen = len;
1179901484c1SDavid du Colombier 		bus += slen;
1180901484c1SDavid du Colombier 		i++;
1181901484c1SDavid du Colombier 	}
1182901484c1SDavid du Colombier 	return i;
1183901484c1SDavid du Colombier }
1184901484c1SDavid du Colombier 
1185901484c1SDavid du Colombier static void
m10gtransmit(Ether * e)1186901484c1SDavid du Colombier m10gtransmit(Ether *e)
1187901484c1SDavid du Colombier {
118891b330d9SDavid du Colombier 	ushort slen;
118991b330d9SDavid du Colombier 	ulong i, cnt, rdma, nseg, count, end, bus, len, segsz;
1190901484c1SDavid du Colombier 	uchar flags;
1191901484c1SDavid du Colombier 	Block *b;
1192901484c1SDavid du Colombier 	Ctlr *c;
1193901484c1SDavid du Colombier 	Send *s, *s0, *s0m8;
1194901484c1SDavid du Colombier 	Tx *tx;
1195901484c1SDavid du Colombier 
1196901484c1SDavid du Colombier 	c = e->ctlr;
1197901484c1SDavid du Colombier 	tx = &c->tx;
1198901484c1SDavid du Colombier 	segsz = tx->segsz;
1199901484c1SDavid du Colombier 
1200901484c1SDavid du Colombier 	qlock(tx);
1201901484c1SDavid du Colombier 	count = 0;
1202901484c1SDavid du Colombier 	s = tx->host + (tx->i & tx->m);
1203901484c1SDavid du Colombier 	cnt = tx->cnt;
1204901484c1SDavid du Colombier 	s0 =   tx->host + (cnt & tx->m);
120541ac1ab6SDavid du Colombier 	s0m8 = tx->host + ((cnt - 8) & tx->m);
1206901484c1SDavid du Colombier 	i = tx->i;
1207901484c1SDavid du Colombier 	for(; s >= s0 || s < s0m8; i += nseg){
1208901484c1SDavid du Colombier 		if((b = qget(e->oq)) == nil)
1209901484c1SDavid du Colombier 			break;
1210901484c1SDavid du Colombier 		flags = SFfirst|SFnotso;
1211901484c1SDavid du Colombier 		if((len = BLEN(b)) < 1520)
1212901484c1SDavid du Colombier 			flags |= SFsmall;
1213901484c1SDavid du Colombier 		rdma = nseg = nsegments(b, segsz);
1214901484c1SDavid du Colombier 		bus = PCIWADDR(b->rp);
1215901484c1SDavid du Colombier 		for(; len; len -= slen){
121664a26757SDavid du Colombier 			end = (bus + segsz) & ~(segsz-1);
1217901484c1SDavid du Colombier 			slen = end - bus;
1218901484c1SDavid du Colombier 			if(slen > len)
1219901484c1SDavid du Colombier 				slen = len;
1220901484c1SDavid du Colombier 			s->low = pbit32(bus);
1221901484c1SDavid du Colombier 			s->len = pbit16(slen);
1222901484c1SDavid du Colombier 			s->nrdma = rdma;
1223901484c1SDavid du Colombier 			s->flags = flags;
1224901484c1SDavid du Colombier 
1225901484c1SDavid du Colombier 			bus += slen;
1226901484c1SDavid du Colombier 			if(++s ==  tx->host + tx->n)
1227901484c1SDavid du Colombier 				s = tx->host;
1228901484c1SDavid du Colombier 			count++;
1229901484c1SDavid du Colombier 			flags &= ~SFfirst;
1230901484c1SDavid du Colombier 			rdma = 1;
1231901484c1SDavid du Colombier 		}
123264a26757SDavid du Colombier 		tx->bring[(i + nseg - 1) & tx->m] = b;
1233901484c1SDavid du Colombier 		if(1 || count > 0){
1234901484c1SDavid du Colombier 			submittx(tx, count);
1235901484c1SDavid du Colombier 			count = 0;
1236901484c1SDavid du Colombier 			cnt = tx->cnt;
1237901484c1SDavid du Colombier 			s0 =   tx->host + (cnt & tx->m);
123841ac1ab6SDavid du Colombier 			s0m8 = tx->host + ((cnt - 8) & tx->m);
1239901484c1SDavid du Colombier 		}
1240901484c1SDavid du Colombier 	}
1241901484c1SDavid du Colombier 	qunlock(tx);
1242901484c1SDavid du Colombier }
1243901484c1SDavid du Colombier 
1244901484c1SDavid du Colombier static void
checkstats(Ether * e,Ctlr * c,Stats * s)1245901484c1SDavid du Colombier checkstats(Ether *e, Ctlr *c, Stats *s)
1246901484c1SDavid du Colombier {
124791b330d9SDavid du Colombier 	ulong i;
1248901484c1SDavid du Colombier 
1249901484c1SDavid du Colombier 	if(s->updated == 0)
1250901484c1SDavid du Colombier 		return;
1251901484c1SDavid du Colombier 
1252901484c1SDavid du Colombier 	i = gbit32(s->linkstat);
1253901484c1SDavid du Colombier 	if(c->linkstat != i){
1254901484c1SDavid du Colombier 		e->link = i;
1255901484c1SDavid du Colombier 		if(c->linkstat = i)
1256901484c1SDavid du Colombier 			dprint("m10g: link up\n");
1257901484c1SDavid du Colombier 		else
1258901484c1SDavid du Colombier 			dprint("m10g: link down\n");
1259901484c1SDavid du Colombier 	}
1260901484c1SDavid du Colombier 	i = gbit32(s->nrdma);
1261901484c1SDavid du Colombier 	if(i != c->nrdma){
126291b330d9SDavid du Colombier 		dprint("m10g: rdma timeout %ld\n", i);
1263901484c1SDavid du Colombier 		c->nrdma = i;
1264901484c1SDavid du Colombier 	}
1265901484c1SDavid du Colombier }
1266901484c1SDavid du Colombier 
1267901484c1SDavid du Colombier static void
waitintx(Ctlr * c)1268901484c1SDavid du Colombier waitintx(Ctlr *c)
1269901484c1SDavid du Colombier {
1270901484c1SDavid du Colombier 	int i;
1271901484c1SDavid du Colombier 
1272901484c1SDavid du Colombier 	for(i = 0; i < 1024*1024; i++){
1273901484c1SDavid du Colombier 		if(c->stats->valid == 0)
1274901484c1SDavid du Colombier 			break;
1275901484c1SDavid du Colombier 		coherence();
1276901484c1SDavid du Colombier 	}
1277901484c1SDavid du Colombier }
1278901484c1SDavid du Colombier 
1279901484c1SDavid du Colombier static void
m10ginterrupt(Ureg *,void * v)1280901484c1SDavid du Colombier m10ginterrupt(Ureg *, void *v)
1281901484c1SDavid du Colombier {
1282901484c1SDavid du Colombier 	Ether *e;
1283901484c1SDavid du Colombier 	Ctlr *c;
1284901484c1SDavid du Colombier 
1285901484c1SDavid du Colombier 	e = v;
1286901484c1SDavid du Colombier 	c = e->ctlr;
1287901484c1SDavid du Colombier 
1288901484c1SDavid du Colombier 	if(c->state != Runed || c->stats->valid == 0)	/* not ready for us? */
1289901484c1SDavid du Colombier 		return;
1290901484c1SDavid du Colombier 
1291901484c1SDavid du Colombier 	if(c->stats->valid & 1)
1292901484c1SDavid du Colombier 		wakeup(&c->rxrendez);
1293901484c1SDavid du Colombier 	if(gbit32(c->stats->txcnt) != c->tx.npkt)
1294901484c1SDavid du Colombier 		wakeup(&c->txrendez);
1295901484c1SDavid du Colombier 	if(c->msi == 0)
1296901484c1SDavid du Colombier 		*c->irqdeass = 0;
1297901484c1SDavid du Colombier 	else
1298901484c1SDavid du Colombier 		c->stats->valid = 0;
1299901484c1SDavid du Colombier 	waitintx(c);
1300901484c1SDavid du Colombier 	checkstats(e, c, c->stats);
1301901484c1SDavid du Colombier 	c->irqack[1] = pbit32(3);
1302901484c1SDavid du Colombier }
1303901484c1SDavid du Colombier 
1304901484c1SDavid du Colombier static void
m10gattach(Ether * e)1305901484c1SDavid du Colombier m10gattach(Ether *e)
1306901484c1SDavid du Colombier {
1307901484c1SDavid du Colombier 	Ctlr *c;
1308901484c1SDavid du Colombier 	char name[12];
1309901484c1SDavid du Colombier 
1310901484c1SDavid du Colombier 	dprint("m10gattach\n");
1311901484c1SDavid du Colombier 
1312901484c1SDavid du Colombier 	qlock(e->ctlr);
1313901484c1SDavid du Colombier 	c = e->ctlr;
1314901484c1SDavid du Colombier 	if(c->state != Detached){
1315901484c1SDavid du Colombier 		qunlock(c);
1316901484c1SDavid du Colombier 		return;
1317901484c1SDavid du Colombier 	}
1318901484c1SDavid du Colombier 	if(waserror()){
1319901484c1SDavid du Colombier 		c->state = Detached;
1320901484c1SDavid du Colombier 		qunlock(c);
1321901484c1SDavid du Colombier 		nexterror();
1322901484c1SDavid du Colombier 	}
1323901484c1SDavid du Colombier 	reset(e, c);
1324901484c1SDavid du Colombier 	c->state = Attached;
1325901484c1SDavid du Colombier 	open0(e, c);
1326901484c1SDavid du Colombier 	if(c->kprocs == 0){
1327901484c1SDavid du Colombier 		c->kprocs++;
1328901484c1SDavid du Colombier 		snprint(name, sizeof name, "#l%drxproc", e->ctlrno);
1329901484c1SDavid du Colombier 		kproc(name, m10rx, e);
1330901484c1SDavid du Colombier 		snprint(name, sizeof name, "#l%dtxproc", e->ctlrno);
1331901484c1SDavid du Colombier 		kproc(name, txproc, e);
1332901484c1SDavid du Colombier 	}
1333901484c1SDavid du Colombier 	c->state = Runed;
1334901484c1SDavid du Colombier 	qunlock(c);
1335901484c1SDavid du Colombier 	poperror();
1336901484c1SDavid du Colombier }
1337901484c1SDavid du Colombier 
1338901484c1SDavid du Colombier static int
m10gdetach(Ctlr * c)1339901484c1SDavid du Colombier m10gdetach(Ctlr *c)
1340901484c1SDavid du Colombier {
1341901484c1SDavid du Colombier 	dprint("m10gdetach\n");
1342901484c1SDavid du Colombier //	reset(e->ctlr);
1343901484c1SDavid du Colombier 	vunmap(c->ram, c->pcidev->mem[0].size);
13446083aa43SDavid du Colombier 	ctlrfree(c);		/* this is a bad idea: don't free c */
1345901484c1SDavid du Colombier 	return -1;
1346901484c1SDavid du Colombier }
1347901484c1SDavid du Colombier 
1348901484c1SDavid du Colombier static int
lstcount(Block * b)1349901484c1SDavid du Colombier lstcount(Block *b)
1350901484c1SDavid du Colombier {
1351901484c1SDavid du Colombier 	int i;
1352901484c1SDavid du Colombier 
1353901484c1SDavid du Colombier 	i = 0;
1354901484c1SDavid du Colombier 	for(; b; b = b->next)
1355901484c1SDavid du Colombier 		i++;
1356901484c1SDavid du Colombier 	return i;
1357901484c1SDavid du Colombier }
1358901484c1SDavid du Colombier 
1359901484c1SDavid du Colombier static long
m10gifstat(Ether * e,void * v,long n,ulong off)1360901484c1SDavid du Colombier m10gifstat(Ether *e, void *v, long n, ulong off)
1361901484c1SDavid du Colombier {
1362901484c1SDavid du Colombier 	char *p;
1363901484c1SDavid du Colombier 	Ctlr *c;
1364901484c1SDavid du Colombier 	Stats s;
1365901484c1SDavid du Colombier 
1366901484c1SDavid du Colombier 	c = e->ctlr;
136746136019SDavid du Colombier 	p = malloc(READSTR+1);
1368aa72973aSDavid du Colombier 	if(p == nil)
1369aa72973aSDavid du Colombier 		error(Enomem);
1370901484c1SDavid du Colombier 	/* no point in locking this because this is done via dma. */
1371901484c1SDavid du Colombier 	memmove(&s, c->stats, sizeof s);
1372901484c1SDavid du Colombier 
13736083aa43SDavid du Colombier 	snprint(p, READSTR,
137491b330d9SDavid du Colombier 		"txcnt = %lud\n"  "linkstat = %lud\n" 	"dlink = %lud\n"
137591b330d9SDavid du Colombier 		"derror = %lud\n" "drunt = %lud\n" 	"doverrun = %lud\n"
137691b330d9SDavid du Colombier 		"dnosm = %lud\n"  "dnobg = %lud\n"	"nrdma = %lud\n"
1377901484c1SDavid du Colombier 		"txstopped = %ud\n" "down = %ud\n" 	"updated = %ud\n"
1378901484c1SDavid du Colombier 		"valid = %ud\n\n"
137991b330d9SDavid du Colombier 		"tx pkt = %lud\n"  "tx bytes = %lld\n"
1380901484c1SDavid du Colombier 		"tx cnt = %ud\n"  "tx n = %ud\n"	"tx i = %ud\n"
138141ac1ab6SDavid du Colombier 		"sm cnt = %ud\n"  "sm i = %ud\n"	"sm n = %ud\n"
138241ac1ab6SDavid du Colombier 		"sm lst = %ud\n"
138341ac1ab6SDavid du Colombier 		"bg cnt = %ud\n"  "bg i = %ud\n"	"bg n = %ud\n"
138441ac1ab6SDavid du Colombier 		"bg lst = %ud\n"
138591b330d9SDavid du Colombier 		"segsz = %lud\n"   "coal = %lud\n",
1386901484c1SDavid du Colombier 		gbit32(s.txcnt),  gbit32(s.linkstat),	gbit32(s.dlink),
1387901484c1SDavid du Colombier 		gbit32(s.derror), gbit32(s.drunt),	gbit32(s.doverrun),
1388901484c1SDavid du Colombier 		gbit32(s.dnosm),  gbit32(s.dnobg),	gbit32(s.nrdma),
1389901484c1SDavid du Colombier 		s.txstopped,  s.down, s.updated, s.valid,
1390901484c1SDavid du Colombier 		c->tx.npkt, c->tx.nbytes,
1391901484c1SDavid du Colombier 		c->tx.cnt, c->tx.n, c->tx.i,
1392901484c1SDavid du Colombier 		c->sm.cnt, c->sm.i, c->sm.pool->n, lstcount(c->sm.pool->head),
1393901484c1SDavid du Colombier 		c->bg.cnt, c->bg.i, c->bg.pool->n, lstcount(c->bg.pool->head),
1394901484c1SDavid du Colombier 		c->tx.segsz, gbit32((uchar*)c->coal));
1395901484c1SDavid du Colombier 
1396901484c1SDavid du Colombier 	n = readstr(off, v, n, p);
1397901484c1SDavid du Colombier 	free(p);
1398901484c1SDavid du Colombier 	return n;
1399901484c1SDavid du Colombier }
1400901484c1SDavid du Colombier 
140141ac1ab6SDavid du Colombier //static void
1402901484c1SDavid du Colombier //summary(Ether *e)
1403901484c1SDavid du Colombier //{
1404901484c1SDavid du Colombier //	char *buf;
1405901484c1SDavid du Colombier //	int n, i, j;
1406901484c1SDavid du Colombier //
1407901484c1SDavid du Colombier //	if(e == 0)
1408901484c1SDavid du Colombier //		return;
1409901484c1SDavid du Colombier //	buf = malloc(n=250);
1410901484c1SDavid du Colombier //	if(buf == 0)
1411901484c1SDavid du Colombier //		return;
1412901484c1SDavid du Colombier //
1413901484c1SDavid du Colombier //	snprint(buf, n, "oq\n");
1414901484c1SDavid du Colombier //	qsummary(e->oq, buf+3, n-3-1);
1415901484c1SDavid du Colombier //	iprint("%s", buf);
1416901484c1SDavid du Colombier //
1417901484c1SDavid du Colombier //	if(e->f) for(i = 0; e->f[i]; i++){
1418901484c1SDavid du Colombier //		j = snprint(buf, n, "f%d %d\n", i, e->f[i]->type);
1419901484c1SDavid du Colombier //		qsummary(e->f[i]->in, buf+j, n-j-1);
1420901484c1SDavid du Colombier //		print("%s", buf);
1421901484c1SDavid du Colombier //	}
1422901484c1SDavid du Colombier //
1423901484c1SDavid du Colombier //	free(buf);
1424901484c1SDavid du Colombier //}
1425901484c1SDavid du Colombier 
142641ac1ab6SDavid du Colombier static void
rxring(Ctlr * c)1427901484c1SDavid du Colombier rxring(Ctlr *c)
1428901484c1SDavid du Colombier {
1429901484c1SDavid du Colombier 	Done *d;
1430901484c1SDavid du Colombier 	Slot *s;
143141ac1ab6SDavid du Colombier 	Slotparts *sp;
1432901484c1SDavid du Colombier 	int i;
1433901484c1SDavid du Colombier 
1434901484c1SDavid du Colombier 	d = &c->done;
1435901484c1SDavid du Colombier 	s = d->entry;
143641ac1ab6SDavid du Colombier 	for(i = 0; i < d->n; i++) {
143741ac1ab6SDavid du Colombier 		sp = (Slotparts *)(s + i);
143841ac1ab6SDavid du Colombier 		if(sp->len)
143941ac1ab6SDavid du Colombier 			iprint("s[%d] = %d\n", i, sp->len);
144041ac1ab6SDavid du Colombier 	}
1441901484c1SDavid du Colombier }
1442901484c1SDavid du Colombier 
1443901484c1SDavid du Colombier enum {
1444901484c1SDavid du Colombier 	CMdebug,
1445901484c1SDavid du Colombier 	CMcoal,
1446901484c1SDavid du Colombier 	CMwakeup,
1447901484c1SDavid du Colombier 	CMtxwakeup,
1448901484c1SDavid du Colombier 	CMqsummary,
1449901484c1SDavid du Colombier 	CMrxring,
1450901484c1SDavid du Colombier };
1451901484c1SDavid du Colombier 
1452901484c1SDavid du Colombier static Cmdtab ctab[] = {
1453901484c1SDavid du Colombier 	CMdebug,	"debug",	2,
1454901484c1SDavid du Colombier 	CMcoal,		"coal",		2,
1455901484c1SDavid du Colombier 	CMwakeup,	"wakeup",	1,
1456901484c1SDavid du Colombier 	CMtxwakeup,	"txwakeup",	1,
1457901484c1SDavid du Colombier //	CMqsummary,	"q",		1,
1458901484c1SDavid du Colombier 	CMrxring,	"rxring",	1,
1459901484c1SDavid du Colombier };
1460901484c1SDavid du Colombier 
1461901484c1SDavid du Colombier static long
m10gctl(Ether * e,void * v,long n)1462901484c1SDavid du Colombier m10gctl(Ether *e, void *v, long n)
1463901484c1SDavid du Colombier {
1464901484c1SDavid du Colombier 	int i;
1465901484c1SDavid du Colombier 	Cmdbuf *c;
1466901484c1SDavid du Colombier 	Cmdtab *t;
1467901484c1SDavid du Colombier 
1468901484c1SDavid du Colombier 	dprint("m10gctl\n");
1469901484c1SDavid du Colombier 	if(e->ctlr == nil)
1470901484c1SDavid du Colombier 		error(Enonexist);
1471901484c1SDavid du Colombier 
1472901484c1SDavid du Colombier 	c = parsecmd(v, n);
1473901484c1SDavid du Colombier 	if(waserror()){
1474901484c1SDavid du Colombier 		free(c);
1475901484c1SDavid du Colombier 		nexterror();
1476901484c1SDavid du Colombier 	}
1477901484c1SDavid du Colombier 	t = lookupcmd(c, ctab, nelem(ctab));
1478901484c1SDavid du Colombier 	switch(t->index){
1479901484c1SDavid du Colombier 	case CMdebug:
148041ac1ab6SDavid du Colombier 		debug = (strcmp(c->f[1], "on") == 0);
1481901484c1SDavid du Colombier 		break;
1482901484c1SDavid du Colombier 	case CMcoal:
1483901484c1SDavid du Colombier 		i = atoi(c->f[1]);
1484901484c1SDavid du Colombier 		if(i < 0 || i > 1000)
1485901484c1SDavid du Colombier 			error(Ebadarg);
1486901484c1SDavid du Colombier 		*((Ctlr*)e->ctlr)->coal = pbit32(i);
1487901484c1SDavid du Colombier 		break;
1488901484c1SDavid du Colombier 	case CMwakeup:
1489901484c1SDavid du Colombier 		wakeup(&((Ctlr*)e->ctlr)->rxrendez); /* you're kidding, right? */
1490901484c1SDavid du Colombier 		break;
1491901484c1SDavid du Colombier 	case CMtxwakeup:
1492901484c1SDavid du Colombier 		wakeup(&((Ctlr*)e->ctlr)->txrendez); /* you're kidding, right? */
1493901484c1SDavid du Colombier 		break;
1494901484c1SDavid du Colombier //	case CMqsummary:
1495901484c1SDavid du Colombier //		summary(e);
1496901484c1SDavid du Colombier //		break;
1497901484c1SDavid du Colombier 	case CMrxring:
1498901484c1SDavid du Colombier 		rxring(e->ctlr);
1499901484c1SDavid du Colombier 		break;
1500901484c1SDavid du Colombier 	default:
1501901484c1SDavid du Colombier 		error(Ebadarg);
1502901484c1SDavid du Colombier 	}
1503901484c1SDavid du Colombier 	free(c);
1504901484c1SDavid du Colombier 	poperror();
1505901484c1SDavid du Colombier 	return n;
1506901484c1SDavid du Colombier }
1507901484c1SDavid du Colombier 
1508901484c1SDavid du Colombier static void
m10gshutdown(Ether * e)1509901484c1SDavid du Colombier m10gshutdown(Ether *e)
1510901484c1SDavid du Colombier {
1511901484c1SDavid du Colombier 	dprint("m10gshutdown\n");
1512901484c1SDavid du Colombier 	m10gdetach(e->ctlr);
1513901484c1SDavid du Colombier }
1514901484c1SDavid du Colombier 
1515901484c1SDavid du Colombier static void
m10gpromiscuous(void * v,int on)1516901484c1SDavid du Colombier m10gpromiscuous(void *v, int on)
1517901484c1SDavid du Colombier {
1518901484c1SDavid du Colombier 	Ether *e;
1519901484c1SDavid du Colombier 	int i;
1520901484c1SDavid du Colombier 
1521901484c1SDavid du Colombier 	dprint("m10gpromiscuous\n");
1522901484c1SDavid du Colombier 	e = v;
1523901484c1SDavid du Colombier 	if(on)
1524901484c1SDavid du Colombier 		i = Cpromisc;
1525901484c1SDavid du Colombier 	else
1526901484c1SDavid du Colombier 		i = Cnopromisc;
1527901484c1SDavid du Colombier 	cmd(e->ctlr, i, 0);
1528901484c1SDavid du Colombier }
1529901484c1SDavid du Colombier 
1530901484c1SDavid du Colombier static int	mcctab[]  = { CSleavemc, CSjoinmc };
1531901484c1SDavid du Colombier static char	*mcntab[] = { "leave", "join" };
1532901484c1SDavid du Colombier 
1533901484c1SDavid du Colombier static void
m10gmulticast(void * v,uchar * ea,int on)1534901484c1SDavid du Colombier m10gmulticast(void *v, uchar *ea, int on)
1535901484c1SDavid du Colombier {
1536901484c1SDavid du Colombier 	Ether *e;
1537901484c1SDavid du Colombier 	int i;
1538901484c1SDavid du Colombier 
1539901484c1SDavid du Colombier 	dprint("m10gmulticast\n");
1540901484c1SDavid du Colombier 	e = v;
1541901484c1SDavid du Colombier 	if((i = maccmd(e->ctlr, mcctab[on], ea)) != 0)
1542901484c1SDavid du Colombier 		print("m10g: can't %s %E: %d\n", mcntab[on], ea, i);
1543901484c1SDavid du Colombier }
1544901484c1SDavid du Colombier 
1545901484c1SDavid du Colombier static void
m10gpci(void)1546901484c1SDavid du Colombier m10gpci(void)
1547901484c1SDavid du Colombier {
1548901484c1SDavid du Colombier 	Pcidev *p;
1549901484c1SDavid du Colombier 	Ctlr *t, *c;
1550901484c1SDavid du Colombier 
1551901484c1SDavid du Colombier 	t = 0;
1552d5789509SDavid du Colombier 	for(p = 0; p = pcimatch(p, Vmyricom, 0); ){
1553d5789509SDavid du Colombier 		switch(p->did){
1554d5789509SDavid du Colombier 		case 0x8:		/* 8a */
1555d5789509SDavid du Colombier 			break;
1556d5789509SDavid du Colombier 		case 0x9:		/* 8a with msi-x fw */
1557d5789509SDavid du Colombier 		case 0xa:		/* 8b */
1558d5789509SDavid du Colombier 		case 0xb:		/* 8b2 */
1559d5789509SDavid du Colombier 		case 0xc:		/* 2-8b2 */
1560d5789509SDavid du Colombier 			/* untested */
1561d5789509SDavid du Colombier 			break;
1562d5789509SDavid du Colombier 		default:
1563d5789509SDavid du Colombier 			print("etherm10g: unknown myricom did %#ux\n", p->did);
1564d5789509SDavid du Colombier 			continue;
1565d5789509SDavid du Colombier 		}
1566901484c1SDavid du Colombier 		c = malloc(sizeof *c);
1567901484c1SDavid du Colombier 		if(c == nil)
15686083aa43SDavid du Colombier 			break;
1569901484c1SDavid du Colombier 		c->pcidev = p;
1570901484c1SDavid du Colombier 		c->id = p->did<<16 | p->vid;
1571901484c1SDavid du Colombier 		c->boot = pcicap(p, PciCapVND);
1572901484c1SDavid du Colombier //		kickthebaby(p, c);
1573901484c1SDavid du Colombier 		pcisetbme(p);
1574901484c1SDavid du Colombier 		if(setmem(p, c) == -1){
157580088de7SDavid du Colombier 			print("m10g: setmem failed\n");
1576901484c1SDavid du Colombier 			free(c);
1577901484c1SDavid du Colombier 			/* cleanup */
1578901484c1SDavid du Colombier 			continue;
1579901484c1SDavid du Colombier 		}
1580901484c1SDavid du Colombier 		if(t)
1581901484c1SDavid du Colombier 			t->next = c;
1582901484c1SDavid du Colombier 		else
1583901484c1SDavid du Colombier 			ctlrs = c;
1584901484c1SDavid du Colombier 		t = c;
1585901484c1SDavid du Colombier 	}
1586901484c1SDavid du Colombier }
1587901484c1SDavid du Colombier 
1588901484c1SDavid du Colombier static int
m10gpnp(Ether * e)1589901484c1SDavid du Colombier m10gpnp(Ether *e)
1590901484c1SDavid du Colombier {
1591901484c1SDavid du Colombier 	Ctlr *c;
1592901484c1SDavid du Colombier 
1593901484c1SDavid du Colombier 	if(ctlrs == nil)
1594901484c1SDavid du Colombier 		m10gpci();
1595901484c1SDavid du Colombier 
1596901484c1SDavid du Colombier 	for(c = ctlrs; c != nil; c = c->next)
1597901484c1SDavid du Colombier 		if(c->active)
1598901484c1SDavid du Colombier 			continue;
1599901484c1SDavid du Colombier 		else if(e->port == 0 || e->port == c->port)
1600901484c1SDavid du Colombier 			break;
1601901484c1SDavid du Colombier 	if(c == nil)
1602901484c1SDavid du Colombier 		return -1;
1603901484c1SDavid du Colombier 	c->active = 1;
1604901484c1SDavid du Colombier 
1605901484c1SDavid du Colombier 	e->ctlr = c;
1606901484c1SDavid du Colombier 	e->port = c->port;
1607901484c1SDavid du Colombier 	e->irq = c->pcidev->intl;
1608901484c1SDavid du Colombier 	e->tbdf = c->pcidev->tbdf;
1609901484c1SDavid du Colombier 	e->mbps = 10000;
1610901484c1SDavid du Colombier 	memmove(e->ea, c->ra, Eaddrlen);
1611901484c1SDavid du Colombier 
1612901484c1SDavid du Colombier 	e->attach = m10gattach;
1613901484c1SDavid du Colombier 	e->detach = m10gshutdown;
1614901484c1SDavid du Colombier 	e->transmit = m10gtransmit;
1615901484c1SDavid du Colombier 	e->interrupt = m10ginterrupt;
1616901484c1SDavid du Colombier 	e->ifstat = m10gifstat;
1617901484c1SDavid du Colombier 	e->ctl = m10gctl;
1618901484c1SDavid du Colombier 	e->shutdown = m10gshutdown;
1619901484c1SDavid du Colombier 
1620901484c1SDavid du Colombier 	e->arg = e;
1621901484c1SDavid du Colombier 	e->promiscuous = m10gpromiscuous;
1622901484c1SDavid du Colombier 	e->multicast = m10gmulticast;
1623901484c1SDavid du Colombier 	return 0;
1624901484c1SDavid du Colombier }
1625901484c1SDavid du Colombier 
1626901484c1SDavid du Colombier void
etherm10glink(void)1627901484c1SDavid du Colombier etherm10glink(void)
1628901484c1SDavid du Colombier {
1629901484c1SDavid du Colombier 	addethercard("m10g", m10gpnp);
1630901484c1SDavid du Colombier }
1631