1 /* $NetBSD: if_le.c,v 1.9 2008/01/12 09:54:32 tsutsui Exp $ */
4 * Copyright (c) 1995 Theo de Raadt
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * Copyright (c) 1993 Adam Glass
28 * All rights reserved.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by Adam Glass.
41 * 4. The name of the Author may not be used to endorse or promote products
42 * derived from this software without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 #include <sys/param.h>
58 #include <sys/types.h>
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
63 #include <machine/prom.h>
65 #include <lib/libkern/libkern.h>
66 #include <lib/libsa/stand.h>
67 #include <lib/libsa/net.h>
78 void le_end(struct netif
*);
79 void le_error(struct netif
*, char *, volatile struct lereg1
*);
80 int le_get(struct iodesc
*, void *, size_t, saseconds_t
);
81 void le_init(struct iodesc
*, void *);
82 int le_match(struct netif
*, void *);
83 int le_poll(struct iodesc
*, void *, int);
84 int le_probe(struct netif
*, void *);
85 int le_put(struct iodesc
*, void *, size_t);
86 void le_reset(struct netif
*, u_char
*);
88 struct netif_stats le_stats
;
90 struct netif_dif le0_dif
= {
98 struct netif_driver le_driver
= {
99 "le", /* netif_bname */
100 le_match
, /* match */
101 le_probe
, /* probe */
106 &le0_dif
, /* netif_ifs */
110 struct le_configuration
{
111 unsigned int phys_addr
;
114 { LANCE_REG_ADDR
, 0 }
117 int nle_config
= __arraycount(le_config
);
120 struct lereg1
*sc_r1
; /* LANCE registers */
121 struct lereg2
*sc_r2
; /* RAM */
127 le_match(struct netif
*nif
, void *machdep_hint
)
132 if (bugargs
.cputyp
!= CPU_147
)
135 if (name
&& !memcmp(le_driver
.netif_bname
, name
, 2))
137 for (i
= 0; i
< nle_config
; i
++) {
138 if (le_config
[i
].used
)
141 printf("le%d: le_match --> %d\n", i
, val
+ 1);
146 printf("le%d: le_match --> 0\n", i
);
151 le_probe(struct netif
*nif
, void *machdep_hint
)
154 /* the set unit is the current unit */
156 printf("le%d: le_probe called\n", nif
->nif_unit
);
158 if (bugargs
.cputyp
== CPU_147
)
164 le_error(struct netif
*nif
, char *str
, volatile struct lereg1
*ler1
)
167 /* ler1->ler1_rap = LE_CSRO done in caller */
168 if (ler1
->ler1_rdp
& LE_C0_BABL
)
169 panic("le%d: been babbling, found by '%s'", nif
->nif_unit
, str
);
170 if (ler1
->ler1_rdp
& LE_C0_CERR
) {
171 le_stats
.collision_error
++;
172 ler1
->ler1_rdp
= LE_C0_CERR
;
174 if (ler1
->ler1_rdp
& LE_C0_MISS
) {
176 ler1
->ler1_rdp
= LE_C0_MISS
;
178 if (ler1
->ler1_rdp
& LE_C0_MERR
) {
179 printf("le%d: memory error in '%s'\n", nif
->nif_unit
, str
);
180 panic("memory error");
185 le_reset(struct netif
*nif
, u_char
*myea
)
187 struct lereg1
*ler1
= le_softc
.sc_r1
;
188 struct lereg2
*ler2
= le_softc
.sc_r2
;
190 int timo
= 100000, stat
= 0, i
;
193 printf("le%d: le_reset called\n", nif
->nif_unit
);
194 ler1
->ler1_rap
= LE_CSR0
;
195 ler1
->ler1_rdp
= LE_C0_STOP
; /* do nothing until we are finished */
197 memset(ler2
, 0, sizeof(*ler2
));
199 ler2
->ler2_mode
= LE_MODE_NORMAL
;
200 ler2
->ler2_padr
[0] = myea
[1];
201 ler2
->ler2_padr
[1] = myea
[0];
202 ler2
->ler2_padr
[2] = myea
[3];
203 ler2
->ler2_padr
[3] = myea
[2];
204 ler2
->ler2_padr
[4] = myea
[5];
205 ler2
->ler2_padr
[5] = myea
[4];
208 ler2
->ler2_ladrf0
= 0;
209 ler2
->ler2_ladrf1
= 0;
211 a
= (u_int
)ler2
->ler2_rmd
;
212 ler2
->ler2_rlen
= LE_RLEN
| (a
>> 16);
213 ler2
->ler2_rdra
= a
& LE_ADDR_LOW_MASK
;
215 a
= (u_int
)ler2
->ler2_tmd
;
216 ler2
->ler2_tlen
= LE_TLEN
| (a
>> 16);
217 ler2
->ler2_tdra
= a
& LE_ADDR_LOW_MASK
;
219 ler1
->ler1_rap
= LE_CSR1
;
221 ler1
->ler1_rdp
= a
& LE_ADDR_LOW_MASK
;
222 ler1
->ler1_rap
= LE_CSR2
;
223 ler1
->ler1_rdp
= a
>> 16;
225 for (i
= 0; i
< LERBUF
; i
++) {
226 a
= (u_int
)&ler2
->ler2_rbuf
[i
];
227 ler2
->ler2_rmd
[i
].rmd0
= a
& LE_ADDR_LOW_MASK
;
228 ler2
->ler2_rmd
[i
].rmd1_bits
= LE_R1_OWN
;
229 ler2
->ler2_rmd
[i
].rmd1_hadr
= a
>> 16;
230 ler2
->ler2_rmd
[i
].rmd2
= -LEMTU
;
231 ler2
->ler2_rmd
[i
].rmd3
= 0;
233 for (i
= 0; i
< LETBUF
; i
++) {
234 a
= (u_int
)&ler2
->ler2_tbuf
[i
];
235 ler2
->ler2_tmd
[i
].tmd0
= a
& LE_ADDR_LOW_MASK
;
236 ler2
->ler2_tmd
[i
].tmd1_bits
= 0;
237 ler2
->ler2_tmd
[i
].tmd1_hadr
= a
>> 16;
238 ler2
->ler2_tmd
[i
].tmd2
= 0;
239 ler2
->ler2_tmd
[i
].tmd3
= 0;
242 ler1
->ler1_rap
= LE_CSR3
;
243 ler1
->ler1_rdp
= LE_C3_BSWP
;
245 ler1
->ler1_rap
= LE_CSR0
;
246 ler1
->ler1_rdp
= LE_C0_INIT
;
249 printf("le%d: init timeout, stat = 0x%x\n",
250 nif
->nif_unit
, stat
);
253 stat
= ler1
->ler1_rdp
;
254 } while ((stat
& LE_C0_IDON
) == 0);
256 ler1
->ler1_rdp
= LE_C0_IDON
;
257 le_softc
.next_rmd
= 0;
258 le_softc
.next_tmd
= 0;
259 ler1
->ler1_rap
= LE_CSR0
;
260 ler1
->ler1_rdp
= LE_C0_STRT
;
264 le_poll(struct iodesc
*desc
, void *pkt
, int len
)
266 struct lereg1
*ler1
= le_softc
.sc_r1
;
267 struct lereg2
*ler2
= le_softc
.sc_r2
;
273 ler1
->ler1_rap
= LE_CSR0
;
274 if ((ler1
->ler1_rdp
& LE_C0_RINT
) != 0)
275 ler1
->ler1_rdp
= LE_C0_RINT
;
276 rmd
= &ler2
->ler2_rmd
[le_softc
.next_rmd
];
277 if (rmd
->rmd1_bits
& LE_R1_OWN
) {
280 if (ler1
->ler1_rdp
& LE_C0_ERR
)
281 le_error(desc
->io_netif
, "le_poll", ler1
);
282 if (rmd
->rmd1_bits
& LE_R1_ERR
) {
283 printf("le%d_poll: rmd status 0x%x\n",
284 ((struct netif
*)desc
->io_netif
)->nif_unit
,
289 if ((rmd
->rmd1_bits
& (LE_R1_STP
| LE_R1_ENP
)) !=
290 (LE_R1_STP
| LE_R1_ENP
))
291 panic("le_poll: chained packet");
294 if (length
>= LEMTU
) {
296 panic("csr0 when bad things happen: %x", ler1
->ler1_rdp
);
305 * if buffer is smaller than the packet truncate it.
311 memcpy(pkt
, (void *)&ler2
->ler2_rbuf
[le_softc
.next_rmd
],
315 a
= (u_int
)&ler2
->ler2_rbuf
[le_softc
.next_rmd
];
316 rmd
->rmd0
= a
& LE_ADDR_LOW_MASK
;
317 rmd
->rmd1_hadr
= a
>> 16;
320 (le_softc
.next_rmd
== (LERBUF
- 1)) ? 0 : (le_softc
.next_rmd
+ 1);
321 rmd
->rmd1_bits
= LE_R1_OWN
;
326 le_put(struct iodesc
*desc
, void *pkt
, size_t len
)
328 volatile struct lereg1
*ler1
= le_softc
.sc_r1
;
329 volatile struct lereg2
*ler2
= le_softc
.sc_r2
;
330 volatile struct letmd
*tmd
;
331 int timo
= 100000, stat
= 0;
333 int nifunit
= ((struct netif
*)desc
->io_netif
)->nif_unit
;
335 ler1
->ler1_rap
= LE_CSR0
;
336 if (ler1
->ler1_rdp
& LE_C0_ERR
)
337 le_error(desc
->io_netif
, "le_put(way before xmit)", ler1
);
338 tmd
= &ler2
->ler2_tmd
[le_softc
.next_tmd
];
339 while (tmd
->tmd1_bits
& LE_T1_OWN
) {
340 printf("le%d: output buffer busy\n", nifunit
);
342 memcpy((void *)ler2
->ler2_tbuf
[le_softc
.next_tmd
], pkt
, len
);
348 if (ler1
->ler1_rdp
& LE_C0_ERR
)
349 le_error(desc
->io_netif
, "le_put(before xmit)", ler1
);
350 tmd
->tmd1_bits
= LE_T1_STP
| LE_T1_ENP
| LE_T1_OWN
;
351 a
= (u_int
)&ler2
->ler2_tbuf
[le_softc
.next_tmd
];
352 tmd
->tmd0
= a
& LE_ADDR_LOW_MASK
;
353 tmd
->tmd1_hadr
= a
>> 16;
354 ler1
->ler1_rdp
= LE_C0_TDMD
;
355 if (ler1
->ler1_rdp
& LE_C0_ERR
)
356 le_error(desc
->io_netif
, "le_put(after xmit)", ler1
);
359 printf("le%d: transmit timeout, stat = 0x%x\n",
361 if (ler1
->ler1_rdp
& LE_C0_ERR
)
362 le_error(desc
->io_netif
, "le_put(timeout)",
366 stat
= ler1
->ler1_rdp
;
367 } while ((stat
& LE_C0_TINT
) == 0);
368 ler1
->ler1_rdp
= LE_C0_TINT
;
369 if (ler1
->ler1_rdp
& LE_C0_ERR
) {
370 if ((ler1
->ler1_rdp
& (LE_C0_BABL
| LE_C0_CERR
| LE_C0_MISS
|
373 printf("le_put: xmit error, buf %d\n",
375 le_error(desc
->io_netif
, "le_put(xmit error)", ler1
);
377 le_softc
.next_tmd
= 0;
378 /* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/
379 if (tmd
->tmd1_bits
& LE_T1_DEF
)
381 if (tmd
->tmd1_bits
& LE_T1_ONE
)
382 le_stats
.collisions
++;
383 if (tmd
->tmd1_bits
& LE_T1_MORE
)
384 le_stats
.collisions
+= 2;
385 if (tmd
->tmd1_bits
& LE_T1_ERR
) {
386 printf("le%d: transmit error, error = 0x%x\n", nifunit
,
391 printf("le%d: le_put() successful: sent %d\n",
393 printf("le%d: le_put(): tmd1_bits: %x tmd3: %x\n",
395 (unsigned int)tmd
->tmd1_bits
,
396 (unsigned int)tmd
->tmd3
);
402 le_get(struct iodesc
*desc
, void *pkt
, size_t len
, saseconds_t timeout
)
409 while (((getsecs() - t
) < timeout
) && !cc
) {
410 cc
= le_poll(desc
, pkt
, len
);
415 * init le device. return 0 on failure, 1 if ok.
418 le_init(struct iodesc
*desc
, void *machdep_hint
)
420 u_long eram
= 4 * 1024 * 1024;
421 struct netif
*nif
= desc
->io_netif
;
424 printf("le%d: le_init called\n", nif
->nif_unit
);
425 machdep_common_ether(desc
->myea
);
426 memset(&le_softc
, 0, sizeof(le_softc
));
428 (struct lereg1
*)le_config
[nif
->nif_unit
].phys_addr
;
429 le_softc
.sc_r2
= (struct lereg2
*)(eram
- (1024 * 1024));
430 le_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
));
436 le_end(struct netif
*nif
)
438 struct lereg1
*ler1
= le_softc
.sc_r1
;
441 printf("le%d: le_end called\n", nif
->nif_unit
);
442 ler1
->ler1_rap
= LE_CSR0
;
443 ler1
->ler1_rdp
= LE_C0_STOP
;