xref: /netbsd/sys/arch/mvme68k/stand/sboot/le_poll.c (revision bf9ec67e)
1 /*	$NetBSD: le_poll.c,v 1.4 2001/11/08 21:40:25 scw Exp $	*/
2 
3 /*
4  * Copyright (c) 1993 Adam Glass
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Adam Glass.
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 Adam Glass ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "sboot.h"
35 #include "if_lereg.h"
36 
37 struct {
38 	struct	lereg1 *sc_r1;	/* LANCE registers */
39 	struct	lereg2 *sc_r2;	/* RAM */
40 	int next_rmd;
41 	int next_tmd;
42 } le_softc;
43 
44 static void le_error(const char *, struct lereg1 *);
45 static void le_reset(u_char *);
46 static int le_poll(void *, int);
47 
48 static void
49 le_error(str, ler1)
50      const char *str;
51      struct lereg1 *ler1;
52 {
53     /* ler1->ler1_rap = LE_CSRO done in caller */
54     if (ler1->ler1_rdp & LE_C0_BABL) {
55 	printf("le0: been babbling, found by '%s'\n", str);
56 	callrom();
57     }
58     if (ler1->ler1_rdp & LE_C0_CERR) {
59 	ler1->ler1_rdp = LE_C0_CERR;
60     }
61     if (ler1->ler1_rdp & LE_C0_MISS) {
62 	ler1->ler1_rdp = LE_C0_MISS;
63     }
64     if (ler1->ler1_rdp & LE_C0_MERR) {
65 	printf("le0: memory error in '%s'\n", str);
66 	callrom();
67     }
68 
69 }
70 
71 static void
72 le_reset(myea)
73      u_char *myea;
74 {
75     struct lereg1 *ler1 = le_softc.sc_r1;
76     struct lereg2 *ler2 = le_softc.sc_r2;
77     unsigned int a;
78     int timo = 100000, stat = 0, i;
79 
80     ler1->ler1_rap = LE_CSR0;
81     ler1->ler1_rdp = LE_C0_STOP;	/* do nothing until we are finished */
82 
83     memset(ler2, 0, sizeof(*ler2));
84 
85     ler2->ler2_mode = LE_MODE_NORMAL;
86     ler2->ler2_padr[0] = myea[1];
87     ler2->ler2_padr[1] = myea[0];
88     ler2->ler2_padr[2] = myea[3];
89     ler2->ler2_padr[3] = myea[2];
90     ler2->ler2_padr[4] = myea[5];
91     ler2->ler2_padr[5] = myea[4];
92 
93 
94     ler2->ler2_ladrf0 = 0;
95     ler2->ler2_ladrf1 = 0;
96 
97     a = (u_int)ler2->ler2_rmd;
98     ler2->ler2_rlen =  LE_RLEN | (a >> 16);
99     ler2->ler2_rdra = a & LE_ADDR_LOW_MASK;
100 
101     a = (u_int)ler2->ler2_tmd;
102     ler2->ler2_tlen = LE_TLEN | (a >> 16);
103     ler2->ler2_tdra = a & LE_ADDR_LOW_MASK;
104 
105     ler1->ler1_rap = LE_CSR1;
106     a = (u_int)ler2;
107     ler1->ler1_rdp = a & LE_ADDR_LOW_MASK;
108     ler1->ler1_rap = LE_CSR2;
109     ler1->ler1_rdp = a >> 16;
110 
111     for (i = 0; i < LERBUF; i++) {
112 	a = (u_int)&ler2->ler2_rbuf[i];
113 	ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK;
114 	ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN;
115 	ler2->ler2_rmd[i].rmd1_hadr = a >> 16;
116 	ler2->ler2_rmd[i].rmd2 = -LEMTU;
117 	ler2->ler2_rmd[i].rmd3 = 0;
118     }
119     for (i = 0; i < LETBUF; i++) {
120 	a = (u_int)&ler2->ler2_tbuf[i];
121 	ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK;
122 	ler2->ler2_tmd[i].tmd1_bits = 0;
123 	ler2->ler2_tmd[i].tmd1_hadr = a >> 16;
124 	ler2->ler2_tmd[i].tmd2 = 0;
125 	ler2->ler2_tmd[i].tmd3 = 0;
126     }
127 
128     ler1->ler1_rap = LE_CSR3;
129     ler1->ler1_rdp = LE_C3_BSWP;
130 
131     ler1->ler1_rap = LE_CSR0;
132     ler1->ler1_rdp = LE_C0_INIT;
133     do {
134 	if (--timo == 0) {
135 	    printf("le0: init timeout, stat = 0x%x\n", stat);
136 	    break;
137 	}
138 	stat = ler1->ler1_rdp;
139     } while ((stat & LE_C0_IDON) == 0);
140 
141     ler1->ler1_rdp = LE_C0_IDON;
142     le_softc.next_rmd = 0;
143     le_softc.next_tmd = 0;
144     ler1->ler1_rap = LE_CSR0;
145     ler1->ler1_rdp = LE_C0_STRT;
146 }
147 
148 static int
149 le_poll(pkt, len)
150      void *pkt;
151      int len;
152 {
153     struct lereg1 *ler1 = le_softc.sc_r1;
154     struct lereg2 *ler2 = le_softc.sc_r2;
155     unsigned int a;
156     int length;
157     struct lermd *rmd;
158 
159     ler1->ler1_rap = LE_CSR0;
160     if ((ler1->ler1_rdp & LE_C0_RINT) != 0)
161       ler1->ler1_rdp = LE_C0_RINT;
162     rmd = &ler2->ler2_rmd[le_softc.next_rmd];
163     if (rmd->rmd1_bits & LE_R1_OWN) {
164 	return(0);
165     }
166     if (ler1->ler1_rdp & LE_C0_ERR)
167 	le_error("le_poll", ler1);
168     if (rmd->rmd1_bits & LE_R1_ERR) {
169 	printf("le0_poll: rmd status 0x%x\n", rmd->rmd1_bits);
170 	length = 0;
171 	goto cleanup;
172     }
173     if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) != (LE_R1_STP|LE_R1_ENP)) {
174 	printf("le_poll: chained packet\n");
175 	callrom();
176     }
177 
178     length = rmd->rmd3;
179     if (length >= LEMTU) {
180 	length = 0;
181 	printf("csr0 when bad things happen: %x\n", ler1->ler1_rdp);
182 	callrom();
183 	goto cleanup;
184     }
185     if (!length) goto cleanup;
186     length -= 4;
187     if (length > 0)
188 	memcpy(pkt, (char *)&ler2->ler2_rbuf[le_softc.next_rmd], length);
189 
190  cleanup:
191     a = (u_int)&ler2->ler2_rbuf[le_softc.next_rmd];
192     rmd->rmd0 = a & LE_ADDR_LOW_MASK;
193     rmd->rmd1_hadr = a >> 16;
194     rmd->rmd2 = -LEMTU;
195     le_softc.next_rmd =
196 	(le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1);
197     rmd->rmd1_bits = LE_R1_OWN;
198     return length;
199 }
200 
201 int le_put(pkt, len)
202      u_char *pkt;
203      size_t len;
204 {
205     struct lereg1 *ler1 = le_softc.sc_r1;
206     struct lereg2 *ler2 = le_softc.sc_r2;
207     struct letmd *tmd;
208     int timo = 100000, stat = 0;
209     unsigned int a;
210 
211     ler1->ler1_rap = LE_CSR0;
212     if (ler1->ler1_rdp & LE_C0_ERR)
213 	le_error("le_put(way before xmit)", ler1);
214     tmd = &ler2->ler2_tmd[le_softc.next_tmd];
215     while(tmd->tmd1_bits & LE_T1_OWN) {
216 	printf("le0: output buffer busy\n");
217     }
218     memcpy((char *)ler2->ler2_tbuf[le_softc.next_tmd], pkt, len);
219     if (len < 64)
220 	tmd->tmd2 = -64;
221     else
222 	tmd->tmd2 = -len;
223     tmd->tmd3 = 0;
224     if (ler1->ler1_rdp & LE_C0_ERR)
225 	le_error("le_put(before xmit)", ler1);
226     tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN;
227     a = (u_int)&ler2->ler2_tbuf[le_softc.next_tmd];
228     tmd->tmd0 = a & LE_ADDR_LOW_MASK;
229     tmd->tmd1_hadr = a >> 16;
230     ler1->ler1_rdp = LE_C0_TDMD;
231     if (ler1->ler1_rdp & LE_C0_ERR)
232 	le_error("le_put(after xmit)", ler1);
233     do {
234 	if (--timo == 0) {
235 	    printf("le0: transmit timeout, stat = 0x%x\n",
236 		   stat);
237 	    if (ler1->ler1_rdp & LE_C0_ERR)
238 		le_error("le_put(timeout)", ler1);
239 	    break;
240 	}
241 	stat = ler1->ler1_rdp;
242     } while ((stat & LE_C0_TINT) == 0);
243     ler1->ler1_rdp = LE_C0_TINT;
244     if (ler1->ler1_rdp & LE_C0_ERR) {
245 	if ((ler1->ler1_rdp & (LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR)) !=
246 		LE_C0_CERR)
247 	  printf("le_put: xmit error, buf %d\n", le_softc.next_tmd);
248 	le_error("le_put(xmit error)", ler1);
249     }
250     le_softc.next_tmd = 0;
251 /*	(le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/
252     if (tmd->tmd1_bits & LE_T1_ERR) {
253 	printf("le0: transmit error, error = 0x%x\n",
254 	       tmd->tmd3);
255 	return -1;
256     }
257     return len;
258 }
259 
260 int le_get(pkt, len, timeout)
261      u_char *pkt;
262      size_t len;
263      u_long timeout;
264 {
265     int cc;
266     int now, then;
267     int stopat = time() + timeout;
268     then = 0;
269 
270     cc = 0;
271     while ((now = time()) < stopat && !cc) {
272 	cc = le_poll(pkt, len);
273         if (then != now) {
274 #ifdef LE_DEBUG
275           printf("%d  \r", stopat - now);
276 #endif
277           then = now;
278         }
279         if (cc && (pkt[0] != myea[0] || pkt[1] != myea[1] ||
280                    pkt[2] != myea[2] || pkt[3] != myea[3] ||
281                    pkt[4] != myea[4] || pkt[5] != myea[5])) {
282           cc = 0; /* ignore broadcast / multicast */
283 #ifdef LE_DEBUG
284           printf("reject (%d sec left)\n", stopat - now);
285 #endif
286         }
287     }
288 #ifdef LE_DEBUG
289     printf("\n");
290 #endif
291     return cc;
292 }
293 
294 void le_init()
295 {
296     int *ea = (int *) LANCE_ADDR;
297     u_long *eram = (u_long *) ERAM_ADDR;
298     u_long e = *ea;
299     if (( e & 0x2fffff00 ) == 0x2fffff00) {
300       printf("ERROR: ethernet address not set!  Use LSAD.\n");
301       callrom();
302     }
303     myea[0] = 0x08;
304     myea[1] = 0x00;
305     myea[2] = 0x3e;
306     e = e >> 8;
307     myea[5] = e & 0xff;
308     e = e >> 8;
309     myea[4] = e & 0xff;
310     e = e >> 8;
311     myea[3] = e;
312     printf("le0: ethernet address: %x:%x:%x:%x:%x:%x\n",
313       myea[0], myea[1], myea[2], myea[3], myea[4], myea[5]);
314     memset(&le_softc, 0, sizeof(le_softc));
315     le_softc.sc_r1 = (struct lereg1 *) LANCE_REG_ADDR;
316     le_softc.sc_r2 = (struct lereg2 *)(*eram - (1024*1024));
317     le_reset(myea);
318 }
319 
320 void le_end()
321 {
322     struct lereg1 *ler1 = le_softc.sc_r1;
323 
324     ler1->ler1_rap = LE_CSR0;
325     ler1->ler1_rdp = LE_C0_STOP;
326 }
327