xref: /netbsd/sys/arch/vax/boot/boot/if_le.c (revision bf9ec67e)
1 /*	$NetBSD: if_le.c,v 1.6 2000/05/20 13:30:03 ragge Exp $ */
2 /*
3  * Copyright (c) 1997, 1999 Ludd, University of Lule}, Sweden.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed at Ludd, University of
17  *      Lule}, Sweden and its contributors.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Standalone routine for MicroVAX LANCE chip.
35  */
36 
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
41 
42 #include <net/if.h>
43 #include <net/if_ether.h>
44 
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47 
48 #include <../include/sid.h>
49 #include <../include/rpb.h>
50 
51 #include <lib/libsa/netif.h>
52 #include <lib/libsa/stand.h>
53 
54 #include <dev/ic/lancereg.h>
55 #include <dev/ic/am7990reg.h>
56 
57 #include "vaxstand.h"
58 
59 /*
60  * Buffer sizes.
61  */
62 #define TLEN    1
63 #define NTBUF   (1 << TLEN)
64 #define RLEN    3
65 #define NRBUF   (1 << RLEN)
66 #define BUFSIZE 1518
67 
68 #define	QW_ALLOC(x)	(((int)alloc((x) + 7) + 7) & ~7)
69 
70 static int le_get(struct iodesc *, void *, size_t, time_t);
71 static int le_put(struct iodesc *, void *, size_t);
72 static void copyout(void *from, int dest, int len);
73 static void copyin(int src, void *to, int len);
74 
75 struct netif_driver le_driver = {
76 	0, 0, 0, 0, le_get, le_put,
77 };
78 
79 /*
80  * Init block & buffer descriptors according to DEC system
81  * specification documentation.
82  */
83 struct initblock {
84 	short	ib_mode;
85 	char	ib_padr[6]; /* Ethernet address */
86 	int	ib_ladrf1;
87 	int	ib_ladrf2;
88 	int	ib_rdr; /* Receive address */
89 	int	ib_tdr; /* Transmit address */
90 } *initblock = NULL;
91 
92 struct nireg {
93 	volatile u_short ni_rdp;       /* data port */
94 	volatile short ni_pad0;
95 	volatile short ni_rap;       /* register select port */
96 } *nireg;
97 
98 
99 volatile struct	buffdesc {
100 	int	bd_adrflg;
101 	short	bd_bcnt;
102 	short	bd_mcnt;
103 } *rdesc, *tdesc;
104 
105 static	int addoff, kopiera = 0;
106 
107 /* Flags in the address field */
108 #define	BR_OWN	0x80000000
109 #define	BR_ERR	0x40000000
110 #define	BR_FRAM	0x20000000
111 #define	BR_OFLO	0x10000000
112 #define	BR_CRC	0x08000000
113 #define	BR_BUFF	0x04000000
114 #define	BR_STP	0x02000000
115 #define	BR_ENP	0x01000000
116 
117 #define	BT_OWN	0x80000000
118 #define	BT_ERR	0x40000000
119 #define	BT_MORE	0x10000000
120 #define	BT_ONE	0x08000000
121 #define	BT_DEF	0x04000000
122 #define	BT_STP	0x02000000
123 #define	BT_ENP	0x01000000
124 
125 int	next_rdesc, next_tdesc;
126 
127 #define	LEWRCSR(port, val) { \
128 	nireg->ni_rap = (port); \
129 	nireg->ni_rdp = (val); \
130 }
131 
132 #define	LERDCSR(port) \
133 	(nireg->ni_rap = port, nireg->ni_rdp)
134 
135 int
136 leopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
137 {
138 	int i, *ea;
139 	volatile int to = 100000;
140 	u_char eaddr[6];
141 
142 	next_rdesc = next_tdesc = 0;
143 
144 	if (vax_boardtype == VAX_BTYP_650 &&
145 	    ((vax_siedata >> 8) & 0xff) == VAX_SIE_KA640) {
146 		kopiera = 1;
147 		ea = (void *)0x20084200;
148 		nireg = (void *)0x20084400;
149 	} else {
150 		*(int *)0x20080014 = 0; /* Be sure we do DMA in low 16MB */
151 		ea = (void *)0x20090000; /* XXX ethernetadressen */
152 		nireg = (void *)0x200e0000;
153 	}
154 	if (askname == 0) /* Override if autoboot */
155 		nireg = (void *)bootrpb.csrphy;
156 	else /* Tell kernel from where we booted */
157 		bootrpb.csrphy = (int)nireg;
158 
159 	if (vax_boardtype == VAX_BTYP_43)
160 		addoff = 0x28000000;
161 	else
162 		addoff = 0;
163 igen:
164 	LEWRCSR(LE_CSR0, LE_C0_STOP);
165 	while (to--)
166 		;
167 
168 	for (i = 0; i < 6; i++)
169 		eaddr[i] = ea[i] & 0377;
170 
171 	if (initblock == NULL) {
172 		(void *)initblock =
173 		    (char *)QW_ALLOC(sizeof(struct initblock)) + addoff;
174 		initblock->ib_mode = LE_MODE_NORMAL;
175 		bcopy(eaddr, initblock->ib_padr, 6);
176 		initblock->ib_ladrf1 = 0;
177 		initblock->ib_ladrf2 = 0;
178 
179 		(int)rdesc = QW_ALLOC(sizeof(struct buffdesc) * NRBUF) + addoff;
180 		initblock->ib_rdr = (RLEN << 29) | (int)rdesc;
181 		if (kopiera)
182 			initblock->ib_rdr -= (int)initblock;
183 		(int)tdesc = QW_ALLOC(sizeof(struct buffdesc) * NTBUF) + addoff;
184 		initblock->ib_tdr = (TLEN << 29) | (int)tdesc;
185 		if (kopiera)
186 			initblock->ib_tdr -= (int)initblock;
187 		if (kopiera)
188 			copyout(initblock, 0, sizeof(struct initblock));
189 
190 		for (i = 0; i < NRBUF; i++) {
191 			rdesc[i].bd_adrflg = QW_ALLOC(BUFSIZE) | BR_OWN;
192 			if (kopiera)
193 				rdesc[i].bd_adrflg -= (int)initblock;
194 			rdesc[i].bd_bcnt = -BUFSIZE;
195 			rdesc[i].bd_mcnt = 0;
196 		}
197 		if (kopiera)
198 			copyout((void *)rdesc, (int)rdesc - (int)initblock,
199 			    sizeof(struct buffdesc) * NRBUF);
200 
201 		for (i = 0; i < NTBUF; i++) {
202 			tdesc[i].bd_adrflg = QW_ALLOC(BUFSIZE);
203 			if (kopiera)
204 				tdesc[i].bd_adrflg -= (int)initblock;
205 			tdesc[i].bd_bcnt = 0xf000;
206 			tdesc[i].bd_mcnt = 0;
207 		}
208 		if (kopiera)
209 			copyout((void *)tdesc, (int)tdesc - (int)initblock,
210 			    sizeof(struct buffdesc) * NTBUF);
211 	}
212 
213 	if (kopiera) {
214 		LEWRCSR(LE_CSR1, 0);
215 		LEWRCSR(LE_CSR2, 0);
216 	} else {
217 		LEWRCSR(LE_CSR1, (int)initblock & 0xffff);
218 		LEWRCSR(LE_CSR2, ((int)initblock >> 16) & 0xff);
219 	}
220 
221 	LEWRCSR(LE_CSR0, LE_C0_INIT);
222 
223 	to = 100000;
224 	while (to--) {
225 		if (LERDCSR(LE_CSR0) & LE_C0_IDON)
226 			break;
227 		if (LERDCSR(LE_CSR0) & LE_C0_ERR) {
228 			printf("lance init error: csr0 %x\n", LERDCSR(LE_CSR0));
229 			goto igen;
230 		}
231 	}
232 
233 	LEWRCSR(LE_CSR0, LE_C0_INEA | LE_C0_STRT | LE_C0_IDON);
234 
235 	net_devinit(f, &le_driver, eaddr);
236 	return 0;
237 }
238 
239 int
240 le_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout)
241 {
242 	int csr, len;
243 	volatile int to = 100000 * timeout;
244 
245 retry:
246 	if (to-- == 0)
247 		return 0;
248 
249 	csr = LERDCSR(LE_CSR0);
250 	LEWRCSR(LE_CSR0, csr & (LE_C0_BABL|LE_C0_MISS|LE_C0_MERR|LE_C0_RINT));
251 
252 	if (kopiera)
253 		copyin((int)&rdesc[next_rdesc] - (int)initblock,
254 		    (void *)&rdesc[next_rdesc], sizeof(struct buffdesc));
255 	if (rdesc[next_rdesc].bd_adrflg & BR_OWN)
256 		goto retry;
257 
258         if (rdesc[next_rdesc].bd_adrflg & BR_ERR)
259                 len = 0;
260         else {
261 		if ((len = rdesc[next_rdesc].bd_mcnt - 4) > maxlen)
262 			len = maxlen;
263 
264 		if (kopiera)
265 			copyin((rdesc[next_rdesc].bd_adrflg&0xffffff),
266 			    pkt, len);
267 		else
268 			bcopy((char *)(rdesc[next_rdesc].bd_adrflg&0xffffff) +
269 			    addoff, pkt, len);
270 	}
271 
272 	rdesc[next_rdesc].bd_mcnt = 0;
273 	rdesc[next_rdesc].bd_adrflg |= BR_OWN;
274 	if (kopiera)
275 		copyout((void *)&rdesc[next_rdesc], (int)&rdesc[next_rdesc] -
276 		    (int)initblock, sizeof(struct buffdesc));
277 	if (++next_rdesc >= NRBUF)
278 		next_rdesc = 0;
279 
280 
281 	if (len == 0)
282 		goto retry;
283 	return len;
284 }
285 
286 int
287 le_put(struct iodesc *desc, void *pkt, size_t len)
288 {
289 	volatile int to = 100000;
290 	int csr;
291 
292 retry:
293 	if (--to == 0)
294 		return -1;
295 
296 	csr = LERDCSR(LE_CSR0);
297 	LEWRCSR(LE_CSR0, csr & (LE_C0_MISS|LE_C0_CERR|LE_C0_TINT));
298 
299 	if (kopiera)
300 		copyin((int)&tdesc[next_tdesc] - (int)initblock,
301 		    (void *)&tdesc[next_tdesc], sizeof(struct buffdesc));
302 	if (tdesc[next_tdesc].bd_adrflg & BT_OWN)
303 		goto retry;
304 
305 	if (kopiera)
306 		copyout(pkt, (tdesc[next_tdesc].bd_adrflg & 0xffffff), len);
307 	else
308 		bcopy(pkt, (char *)(tdesc[next_tdesc].bd_adrflg & 0xffffff) +
309 		    addoff, len);
310 	tdesc[next_tdesc].bd_bcnt =
311 	    (len < ETHER_MIN_LEN ? -ETHER_MIN_LEN : -len);
312 	tdesc[next_tdesc].bd_mcnt = 0;
313 	tdesc[next_tdesc].bd_adrflg |= BT_OWN | BT_STP | BT_ENP;
314 	if (kopiera)
315 		copyout((void *)&tdesc[next_tdesc], (int)&tdesc[next_tdesc] -
316 		    (int)initblock, sizeof(struct buffdesc));
317 
318 	LEWRCSR(LE_CSR0, LE_C0_TDMD);
319 
320 	to = 100000;
321 	while (((LERDCSR(LE_CSR0) & LE_C0_TINT) == 0) && --to)
322 		;
323 
324 	LEWRCSR(LE_CSR0, LE_C0_TINT);
325 	if (++next_tdesc >= NTBUF)
326 		next_tdesc = 0;
327 
328 	if (to)
329 		return len;
330 
331 	return -1;
332 }
333 
334 int
335 leclose(struct open_file *f)
336 {
337 	LEWRCSR(LE_CSR0, LE_C0_STOP);
338 
339 	return 0;
340 }
341 
342 void
343 copyout(void *f, int dest, int len)
344 {
345 	short *from = f;
346 	short *toaddr;
347 
348 	toaddr = (short *)0x20120000 + dest;
349 
350 	while (len > 0) {
351 		*toaddr = *from++;
352 		toaddr += 2;
353 		len -= 2;
354 	}
355 }
356 
357 void
358 copyin(int src, void *f, int len)
359 {
360 	short *to = f;
361 	short *fromaddr;
362 
363 	fromaddr = (short *)0x20120000 + src;
364 
365 	while (len > 0) {
366 		*to++ = *fromaddr;
367 		fromaddr += 2;
368 		len -= 2;
369 	}
370 }
371