1/*	$NetBSD: if_ie.c,v 1.12 2008/01/12 09:54:32 tsutsui Exp $	*/
2
3/*
4 * Copyright (c) 1995 Theo de Raadt
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
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/param.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31
32#include <netinet/in.h>
33#include <netinet/in_systm.h>
34
35#include <net/if.h>
36#include <net/if_ether.h>
37
38#include <lib/libkern/libkern.h>
39#include <lib/libsa/stand.h>
40#include <lib/libsa/net.h>
41
42#define NTXBUF	1
43#define NRXBUF	16
44#define IE_RBUF_SIZE	ETHER_MAX_LEN
45
46#include <machine/prom.h>
47
48#include "libsa.h"
49#include "netif.h"
50#include "config.h"
51#include "dev_net.h"
52
53#include "i82586.h"
54#include "if_iereg.h"
55
56int     ie_debug = 0;
57
58void ie_stop(struct netif *);
59void ie_end(struct netif *);
60void ie_error(struct netif *, char *, volatile struct iereg *);
61int ie_get(struct iodesc *, void *, size_t, saseconds_t);
62void ie_init(struct iodesc *, void *);
63int ie_match(struct netif *, void *);
64int ie_poll(struct iodesc *, void *, int);
65int ie_probe(struct netif *, void *);
66int ie_put(struct iodesc *, void *, size_t);
67void ie_reset(struct netif *, u_char *);
68void ieack(volatile struct iereg *, struct iemem *);
69
70struct netif_stats ie_stats;
71
72struct netif_dif ie0_dif = {
73	0,			/* unit */
74	1,			/* nsel */
75	&ie_stats,
76	0,
77	0,
78};
79
80struct netif_driver ie_driver = {
81	"ie",			/* netif_bname */
82	ie_match,		/* match */
83	ie_probe,		/* probe */
84	ie_init,		/* init */
85	ie_get,			/* get */
86	ie_put,			/* put */
87	ie_end,			/* end */
88	&ie0_dif,		/* netif_ifs */
89	1,			/* netif_nifs */
90};
91
92struct ie_configuration {
93	u_int   phys_addr;
94	int     used;
95} ie_config[] = {
96	{ INTEL_REG_ADDR, 0 }
97};
98
99int     nie_config = __arraycount(ie_config);
100
101struct {
102	struct iereg *sc_reg;	/* IE registers */
103	struct iemem *sc_mem;	/* RAM */
104}       ie_softc;
105
106int
107ie_match(struct netif *nif, void *machdep_hint)
108{
109	char   *name;
110	int     i, val = 0;
111
112	if (bugargs.cputyp == CPU_147)
113		return 0;
114	name = machdep_hint;
115	if (name && !memcmp(ie_driver.netif_bname, name, 2))
116		val += 10;
117	for (i = 0; i < nie_config; i++) {
118		if (ie_config[i].used)
119			continue;
120		if (ie_debug)
121			printf("ie%d: ie_match --> %d\n", i, val + 1);
122		ie_config[i].used++;
123		return (val + 1);
124	}
125	if (ie_debug)
126		printf("ie%d: ie_match --> 0\n", i);
127	return 0;
128}
129
130int
131ie_probe(struct netif *nif, void *machdep_hint)
132{
133
134	/* the set unit is the current unit */
135	if (ie_debug)
136		printf("ie%d: ie_probe called\n", nif->nif_unit);
137
138	if (bugargs.cputyp != CPU_147)
139		return 0;
140	return 1;
141}
142
143void
144ie_error(struct netif *nif, char *str, volatile struct iereg *ier)
145{
146
147	panic("ie%d: unknown error", nif->nif_unit);
148}
149
150void
151ieack(volatile struct iereg *ier, struct iemem *iem)
152{
153
154	/* ack the `interrupt' */
155	iem->im_scb.ie_command = iem->im_scb.ie_status & IE_ST_WHENCE;
156	ier->ie_attention = 1;	/* chan attention! */
157	while (iem->im_scb.ie_command)
158		;
159}
160
161void
162ie_reset(struct netif *nif, u_char *myea)
163{
164	volatile struct iereg *ier = ie_softc.sc_reg;
165	struct iemem *iem = ie_softc.sc_mem;
166	int     timo = 10000, i;
167	volatile int t;
168	u_int   a;
169
170	if (ie_debug)
171		printf("ie%d: ie_reset called\n", nif->nif_unit);
172
173	/*printf("ier %x iem %x\n", ier, iem);*/
174
175	*(u_char *)0xfff4202a = 0x40;
176
177	memset(iem, 0, sizeof(*iem));
178	iem->im_scp.scp_sysbus = 0;
179	iem->im_scp.scp_iscp_low = (int)&iem->im_iscp & 0xffff;
180	iem->im_scp.scp_iscp_high = (int)&iem->im_iscp >> 16;
181
182	iem->im_iscp.iscp_scboffset = (int)&iem->im_scb - (int) iem;
183	iem->im_iscp.iscp_busy = 1;
184	iem->im_iscp.iscp_base_low = (int)iem & 0xffff;
185	iem->im_iscp.iscp_base_high = (int)iem >> 16;
186
187	/*
188	 * completely and utterly unlike what i expected, the
189	 * "write" order is:
190	 * 1st:	d15-d0 -> high address
191	 * 2nd:	d31-d16 -> low address
192	 */
193
194	/* reset chip */
195	a = IE_PORT_RESET;
196	ier->ie_porthigh = a & 0xffff;
197	t = 0;
198	t = 1;
199	ier->ie_portlow = a >> 16;
200	for (t = timo; t--;)
201		;
202
203	/* set new SCP pointer */
204	a = (int) &iem->im_scp | IE_PORT_NEWSCP;
205	ier->ie_porthigh = a & 0xffff;
206	t = 0;
207	t = 1;
208	ier->ie_portlow = a >> 16;
209	for (t = timo; t--;)
210		;
211
212	ier->ie_attention = 1;	/* chan attention! */
213	for (t = timo * 10; t--;)
214		;
215
216	/* send CONFIGURE command */
217	iem->im_scb.ie_command = IE_CU_START;
218	iem->im_scb.ie_command_list = (int) &iem->im_cc - (int) iem;
219	iem->im_cc.com.ie_cmd_status = 0;
220	iem->im_cc.com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
221	iem->im_cc.com.ie_cmd_link = 0xffff;
222	iem->im_cc.ie_config_count = 0x0c;
223	iem->im_cc.ie_fifo = 8;
224	iem->im_cc.ie_save_bad = 0x40;
225	iem->im_cc.ie_addr_len = 0x2e;
226	iem->im_cc.ie_priority = 0;
227	iem->im_cc.ie_ifs = 0x60;
228	iem->im_cc.ie_slot_low = 0;
229	iem->im_cc.ie_slot_high = 0xf2;
230	iem->im_cc.ie_promisc = 0;
231	iem->im_cc.ie_crs_cdt = 0;
232	iem->im_cc.ie_min_len = 64;
233	iem->im_cc.ie_junk = 0xff;
234
235	ier->ie_attention = 1;	/* chan attention! */
236	for (t = timo * 10; t--;)
237		;
238
239	ieack(ier, iem);
240
241	/*printf("ic %x\n", &iem->im_ic);*/
242	/* send IASETUP command */
243	iem->im_scb.ie_command = IE_CU_START;
244	iem->im_scb.ie_command_list = (int)&iem->im_ic - (int)iem;
245	iem->im_ic.com.ie_cmd_status = 0;
246	iem->im_ic.com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
247	iem->im_ic.com.ie_cmd_link = 0xffff;
248	memcpy((void *)&iem->im_ic.ie_address, myea,
249	    sizeof(iem->im_ic.ie_address));
250
251	ier->ie_attention = 1;	/* chan attention! */
252	for (t = timo * 10; t--;)
253		;
254
255	ieack(ier, iem);
256
257	/* setup buffers */
258
259	for (i = 0; i < NRXBUF; i++) {
260		iem->im_rfd[i].ie_fd_next = (int)&iem->im_rfd[(i+1) % NRXBUF] -
261		    (int)iem;
262		iem->im_rbd[i].ie_rbd_next = (int)&iem->im_rbd[(i+1) % NRXBUF] -
263		    (int)iem;
264		a = (int)&iem->im_rxbuf[i * IE_RBUF_SIZE];
265		iem->im_rbd[i].ie_rbd_buffer_low = a & 0xffff;
266		iem->im_rbd[i].ie_rbd_buffer_high = a >> 16;
267		iem->im_rbd[i].ie_rbd_length = IE_RBUF_SIZE;
268	}
269	iem->im_rfd[NRXBUF - 1].ie_fd_last |= IE_FD_LAST;
270	iem->im_rbd[NRXBUF - 1].ie_rbd_length |= IE_RBD_LAST;
271	iem->im_rfd[0].ie_fd_buf_desc = (int)&iem->im_rbd[0] - (int)iem;
272
273#if 0
274	printf("rfd[0] %x rbd[0] %x buf[0] %x\n", &iem->im_rfd, &iem->im_rbd,
275	    &iem->im_rxbuf);
276#endif
277
278	/* send receiver start command */
279	iem->im_scb.ie_command = IE_RU_START;
280	iem->im_scb.ie_command_list = 0;
281	iem->im_scb.ie_recv_list = (int) &iem->im_rfd[0] - (int) iem;
282	ier->ie_attention = 1;	/* chan attention! */
283	while (iem->im_scb.ie_command)
284		;
285
286	ieack(ier, iem);
287}
288
289int
290ie_poll(struct iodesc *desc, void *pkt, int len)
291{
292	volatile struct iereg *ier = ie_softc.sc_reg;
293	struct iemem *iem = ie_softc.sc_mem;
294	static int slot;
295	int length = 0;
296	u_short status;
297
298	__asm(".word	0xf518\n");
299	status = iem->im_rfd[slot].ie_fd_status;
300	if (status & IE_FD_BUSY)
301		return 0;
302
303	/* printf("slot %d: %x\n", slot, status); */
304	if ((status & (IE_FD_COMPLETE | IE_FD_OK)) ==
305	    (IE_FD_COMPLETE | IE_FD_OK)) {
306		if (status & IE_FD_OK) {
307			length = iem->im_rbd[slot].ie_rbd_actual & 0x3fff;
308			if (length > len)
309				length = len;
310			memcpy(pkt, (void *)&iem->im_rxbuf[slot * IE_RBUF_SIZE],
311			    length);
312
313			iem->im_rfd[slot].ie_fd_status = 0;
314			iem->im_rfd[slot].ie_fd_last |= IE_FD_LAST;
315			iem->im_rfd[(slot+NRXBUF-1)%NRXBUF].ie_fd_last &=
316			    ~IE_FD_LAST;
317			iem->im_rbd[slot].ie_rbd_actual = 0;
318			iem->im_rbd[slot].ie_rbd_length |= IE_RBD_LAST;
319			iem->im_rbd[(slot+NRXBUF-1)%NRXBUF].ie_rbd_length &=
320			    ~IE_RBD_LAST;
321#if 0
322			printf("S%d\n", slot);
323#endif
324		} else {
325			printf("shit\n");
326		}
327		slot++;
328		/* should move descriptor onto end of queue... */
329	}
330	if ((iem->im_scb.ie_status & IE_RU_READY) == 0) {
331		printf("RR\n");
332
333		for (slot = 0; slot < NRXBUF; slot++) {
334			iem->im_rbd[slot].ie_rbd_length &= ~IE_RBD_LAST;
335			iem->im_rfd[slot].ie_fd_last &= ~IE_FD_LAST;
336		}
337		iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST;
338		iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST;
339
340		iem->im_rfd[0].ie_fd_buf_desc = (int)&iem->im_rbd[0] - (int)iem;
341
342		iem->im_scb.ie_command = IE_RU_START;
343		iem->im_scb.ie_command_list = 0;
344		iem->im_scb.ie_recv_list = (int)&iem->im_rfd[0] - (int)iem;
345		ier->ie_attention = 1;	/* chan attention! */
346		while (iem->im_scb.ie_command)
347			;
348		slot = 0;
349	}
350	slot = slot % NRXBUF;
351	return length;
352}
353
354int
355ie_put(struct iodesc *desc, void *pkt, size_t len)
356{
357	volatile struct iereg *ier = ie_softc.sc_reg;
358	struct iemem *iem = ie_softc.sc_mem;
359	u_char *p = pkt;
360	u_int a;
361	int xx = 0;
362
363	/* send transmit command */
364
365	while (iem->im_scb.ie_command)
366		;
367
368	/* copy data */
369	memcpy((void *)&iem->im_txbuf[xx], p, len);
370
371	len = MAX(len, ETHER_MIN_LEN);
372
373	/* build transmit descriptor */
374	iem->im_xd[xx].ie_xmit_flags = len | IE_XMIT_LAST;
375	iem->im_xd[xx].ie_xmit_next = 0xffff;
376	a = (int) &iem->im_txbuf[xx];
377	iem->im_xd[xx].ie_xmit_buf_low = a & 0xffff;
378	iem->im_xd[xx].ie_xmit_buf_high = a >> 16;
379
380	/* transmit command */
381	iem->im_xc[xx].com.ie_cmd_status = 0;
382	iem->im_xc[xx].com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_LAST;
383	iem->im_xc[xx].com.ie_cmd_link = 0xffff;
384	iem->im_xc[xx].ie_xmit_desc = (int)&iem->im_xd[xx] - (int)iem;
385	iem->im_xc[xx].ie_xmit_length = len;
386	memcpy((void *)&iem->im_xc[xx].ie_xmit_addr, p,
387	    sizeof iem->im_xc[xx].ie_xmit_addr);
388
389	iem->im_scb.ie_command = IE_CU_START;
390	iem->im_scb.ie_command_list = (int)&iem->im_xc[xx] - (int)iem;
391
392	ier->ie_attention = 1;	/* chan attention! */
393
394	if (ie_debug) {
395		printf("ie%d: send %d to %x:%x:%x:%x:%x:%x\n",
396		    ((struct netif *)desc->io_netif)->nif_unit, len,
397		    p[0], p[1], p[2], p[3], p[4], p[5]);
398	}
399	return len;
400}
401
402int
403ie_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
404{
405	satime_t  t;
406	int     cc;
407
408	t = getsecs();
409	cc = 0;
410	while (((getsecs() - t) < timeout) && !cc) {
411		cc = ie_poll(desc, pkt, len);
412	}
413	return cc;
414}
415/*
416 * init ie device.   return 0 on failure, 1 if ok.
417 */
418void
419ie_init(struct iodesc *desc, void *machdep_hint)
420{
421	struct netif *nif = desc->io_netif;
422
423	if (ie_debug)
424		printf("ie%d: ie_init called\n", nif->nif_unit);
425	machdep_common_ether(desc->myea);
426	memset(&ie_softc, 0, sizeof(ie_softc));
427	ie_softc.sc_reg =
428	    (struct iereg *)ie_config[nif->nif_unit].phys_addr;
429	ie_softc.sc_mem = (struct iemem *)0x3e0000;
430	ie_reset(desc->io_netif, desc->myea);
431	printf("device: %s%d attached to %s\n", nif->nif_driver->netif_bname,
432	    nif->nif_unit, ether_sprintf(desc->myea));
433}
434
435void
436ie_stop(struct netif *nif)
437{
438	volatile struct iereg *ier = ie_softc.sc_reg;
439	struct iemem *iem = ie_softc.sc_mem;
440	int timo = 10000;
441	volatile int t;
442	u_int a;
443
444	iem->im_iscp.iscp_busy = 1;
445	/* reset chip */
446	a = IE_PORT_RESET;
447	ier->ie_porthigh = a & 0xffff;
448	t = 0;
449	t = 1;
450	ier->ie_portlow = a >> 16;
451	for (t = timo; t--;)
452		;
453
454	/* reset chip again */
455	a = IE_PORT_RESET;
456	ier->ie_porthigh = a & 0xffff;
457	t = 0;
458	t = 1;
459	ier->ie_portlow = a >> 16;
460	for (t = timo; t--;)
461		;
462
463#if 0
464	printf("status %x busy %x\n", iem->im_scb.ie_status,
465	    iem->im_iscp.iscp_busy);
466#endif
467}
468
469void
470ie_end(struct netif *nif)
471{
472
473	if (ie_debug)
474		printf("ie%d: ie_end called\n", nif->nif_unit);
475
476	ie_stop(nif);
477
478#if 0
479	*(u_char *)0xfff42002 = 0;
480#endif
481}
482