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