1 /* $NetBSD: if_le.c,v 1.10 2007/03/04 05:59:50 christos Exp $ */
4 * Copyright (c) 1993 Adam Glass
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
34 #include <sys/param.h>
35 #include <sys/types.h>
37 #include <net/if_ether.h>
38 #include <netinet/in.h>
39 #include <netinet/in_systm.h>
41 #include <lib/libsa/stand.h>
42 #include <lib/libsa/net.h>
43 #include <lib/libsa/netif.h>
45 #include <lib/libkern/libkern.h>
47 #include <hp300/stand/common/device.h>
48 #include <hp300/stand/common/if_lereg.h>
49 #include <hp300/stand/common/samachdep.h>
56 struct lereg0
*sc_r0
; /* DIO registers */
57 struct lereg1
*sc_r1
; /* LANCE registers */
59 struct init_block
*sc_init
;
60 struct mds
*sc_rd
, *sc_td
;
61 u_char
*sc_rbuf
, *sc_tbuf
;
62 int sc_next_rd
, sc_next_td
;
63 u_char sc_addr
[ETHER_ADDR_LEN
];
75 int le_probe(struct netif
*, void *);
76 int le_match(struct netif
*, void *);
77 void le_init(struct iodesc
*, void *);
78 int le_get(struct iodesc
*, void *, size_t, saseconds_t
);
79 int le_put(struct iodesc
*, void *, size_t);
80 void le_end(struct netif
*);
82 static inline void lewrcsr(struct le_softc
*, uint16_t, uint16_t);
83 static inline uint16_t lerdcsr(struct le_softc
*, uint16_t);
85 static void leinit(void);
86 static void le_error(int, char *, uint16_t);
87 static void lememinit(struct le_softc
*);
88 static void le_reset(int, u_char
*);
89 static int le_poll(struct iodesc
*, void *, int);
95 struct le_sel le0conf
[] = {
96 /* offsets for: ID REGS MEM NVRAM le_heat le_bonus*/
97 { 0, 0x4000, 0x8000, 0xC008, 1, 10 }
99 #define NLE0CONF (sizeof(le0conf) / sizeof(le0conf[0]))
101 extern struct netif_stats le_stats
[];
103 struct netif_dif le_ifs
[] = {
104 /* dif_unit dif_nsel dif_stats dif_private */
105 { 0, NLE0CONF
, &le_stats
[0], le0conf
, },
107 #define NLE_IFS (sizeof(le_ifs) / sizeof(le_ifs[0]))
109 struct netif_stats le_stats
[NLE_IFS
];
111 struct netif_driver le_driver
= {
112 "le", /* netif_bname */
113 le_match
, /* netif_match */
114 le_probe
, /* netif_probe */
115 le_init
, /* netif_init */
116 le_get
, /* netif_get */
117 le_put
, /* netif_put */
118 le_end
, /* netif_end */
119 le_ifs
, /* netif_ifs */
120 NLE_IFS
/* netif_nifs */
123 struct le_softc le_softc
[NLE
];
126 lewrcsr(struct le_softc
*sc
, uint16_t port
, uint16_t val
)
128 struct lereg0
*ler0
= sc
->sc_r0
;
129 struct lereg1
*ler1
= sc
->sc_r1
;
132 ler1
->ler1_rap
= port
;
133 } while ((ler0
->ler0_status
& LE_ACK
) == 0);
135 ler1
->ler1_rdp
= val
;
136 } while ((ler0
->ler0_status
& LE_ACK
) == 0);
139 static inline uint16_t
140 lerdcsr(struct le_softc
*sc
, uint16_t port
)
142 struct lereg0
*ler0
= sc
->sc_r0
;
143 struct lereg1
*ler1
= sc
->sc_r1
;
147 ler1
->ler1_rap
= port
;
148 } while ((ler0
->ler0_status
& LE_ACK
) == 0);
150 val
= ler1
->ler1_rdp
;
151 } while ((ler0
->ler0_status
& LE_ACK
) == 0);
166 for (hw
= sc_table
; i
< NLE
&& hw
< &sc_table
[MAXCTLRS
]; hw
++) {
169 printf("found type %x\n", hw
->hw_type
);
173 if (!HW_ISDEV(hw
, D_LAN
))
177 sels
= (struct le_sel
*)le_ifs
[i
].dif_private
;
180 sc
->sc_r0
= (struct lereg0
*)(sels
->le_id
+ (int)hw
->hw_kva
);
182 if (sc
->sc_r0
->ler0_id
!= LEID
)
185 sc
->sc_r1
= (struct lereg1
*)(sels
->le_regs
+ (int)hw
->hw_kva
);
186 sc
->sc_mem
= (struct lereg2
*)(sels
->le_mem
+ (int)hw
->hw_kva
);
190 printf("le%d: DIO=%x regs=%x mem=%x\n",
191 i
, sc
->sc_r0
, sc
->sc_r1
, sc
->sc_mem
);
195 * Read the ethernet address off the board, one nibble at a time.
197 cp
= (char *)(sels
->le_nvram
+ (int)hw
->hw_kva
);
198 for (n
= 0; n
< sizeof(sc
->sc_addr
); n
++) {
199 sc
->sc_addr
[n
] = (*++cp
& 0xF) << 4;
201 sc
->sc_addr
[n
] |= *++cp
& 0xF;
206 printf("le%d at sc%d physical address %s\n",
207 i
, hw
->hw_sc
, ether_sprintf(sc
->sc_addr
));
209 hw
->hw_pa
= (void *) i
; /* XXX for autoconfig */
215 le_match(struct netif
*nif
, void *machdep_hint
)
218 char *name
= machdep_hint
;
221 if (nif
->nif_sel
< le_ifs
[nif
->nif_unit
].dif_nsel
) {
222 sels
= (struct le_sel
*)le_ifs
[nif
->nif_unit
].dif_private
;
223 rv
= sels
[nif
->nif_sel
].le_heat
;
224 if (name
&& !strncmp(le_driver
.netif_bname
, name
, 2))
225 rv
+= sels
[nif
->nif_sel
].le_bonus
;
229 printf("le%d: sel %d --> %d\n", nif
->nif_unit
, nif
->nif_sel
,
236 le_probe(struct netif
*nif
, void *machdep_hint
)
243 /* the set unit is the current unit */
246 printf("le%d.%d: le_probe called\n", nif
->nif_unit
, nif
->nif_sel
);
248 /* XXX reset controller */
254 le_mem_summary(int unit
)
256 struct lereg1
*ler1
= le_softc
.sc_r1
;
257 struct lereg2
*ler2
= le_softc
.sc_r2
;
260 printf("le%d: ler1 = %x\n", unit
, ler1
);
261 printf("le%d: ler2 = %x\n", unit
, ler2
);
264 ler1
->ler1_rap
= LE_CSR0
;
265 ler1
->ler1_rdp
= LE_STOP
;
266 printf("le%d: csr0 = %x\n", unit
, ler1
->ler1_rdp
);
267 ler1
->ler1_rap
= LE_CSR1
;
268 printf("le%d: csr1 = %x\n", unit
, ler1
->ler1_rdp
);
269 ler1
->ler1_rap
= LE_CSR2
;
270 printf("le%d: csr2 = %x\n", unit
, ler1
->ler1_rdp
);
271 ler1
->ler1_rap
= LE_CSR3
;
272 printf("le%d: csr3 = %x\n", unit
, ler1
->ler1_rdp
);
274 printf("le%d: ladrf[0] = %x\n", unit
, ler2
->ler2_ladrf
[0]);
275 printf("le%d: ladrf[1] = %x\n", unit
, ler2
->ler2_ladrf
[1]);
276 printf("le%d: ler2_rdra = %x\n", unit
, ler2
->ler2_rdra
);
277 printf("le%d: ler2_rlen = %x\n", unit
, ler2
->ler2_rlen
);
278 printf("le%d: ler2_tdra = %x\n", unit
, ler2
->ler2_tdra
);
279 printf("le%d: ler2_tlen = %x\n", unit
, ler2
->ler2_tlen
);
281 for (i
= 0; i
< LERBUF
; i
++) {
282 printf("le%d: ler2_rmd[%d].rmd0 (ladr) = %x\n", unit
, i
,
283 ler2
->ler2_rmd
[i
].rmd0
);
284 printf("le%d: ler2_rmd[%d].rmd1 = %x\n", unit
, i
,
285 ler2
->ler2_rmd
[i
].rmd1
);
286 printf("le%d: ler2_rmd[%d].rmd2 (-bcnt) = %x\n", unit
, i
,
287 ler2
->ler2_rmd
[i
].rmd2
);
288 printf("le%d: ler2_rmd[%d].rmd3 (mcnt) = %x\n", unit
, i
,
289 ler2
->ler2_rmd
[i
].rmd3
);
290 printf("le%d: ler2_rbuf[%d] addr = %x\n", unit
, i
,
291 &ler2
->ler2_rbuf
[i
]);
293 for (i
= 0; i
< LETBUF
; i
++) {
294 printf("le%d: ler2_tmd[%d].tmd0 = %x\n", unit
, i
,
295 ler2
->ler2_tmd
[i
].tmd0
);
296 printf("le%d: ler2_tmd[%d].tmd1 = %x\n", unit
, i
,
297 ler2
->ler2_tmd
[i
].tmd1
);
298 printf("le%d: ler2_tmd[%d].tmd2 (bcnt) = %x\n", unit
, i
,
299 ler2
->ler2_tmd
[i
].tmd2
);
300 printf("le%d: ler2_tmd[%d].tmd3 = %x\n", unit
, i
,
301 ler2
->ler2_tmd
[i
].tmd3
);
302 printf("le%d: ler2_tbuf[%d] addr = %x\n", unit
, i
,
303 &ler2
->ler2_tbuf
[i
]);
307 #define le_mem_summary(u)
311 le_error(int unit
, char *str
, uint16_t stat
)
315 panic("le%d: been babbling, found by '%s'", unit
, str
);
317 le_stats
[unit
].collision_error
++;
319 le_stats
[unit
].missed
++;
320 if (stat
& LE_MERR
) {
321 printf("le%d: memory error in '%s'\n", unit
, str
);
322 le_mem_summary(unit
);
327 #define LANCE_ADDR(sc, a) \
328 ((u_long)(a) - (u_long)sc->sc_mem)
330 /* LANCE initialization block set up. */
332 lememinit(struct le_softc
*sc
)
339 * At this point we assume that the memory allocated to the Lance is
340 * quadword aligned. If it isn't then the initialisation is going
345 sc
->sc_init
= (void *)mem
;
346 sc
->sc_init
->mode
= LE_NORMAL
;
347 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
348 sc
->sc_init
->padr
[i
] = sc
->sc_addr
[i
^1];
349 sc
->sc_init
->ladrf
[0] = sc
->sc_init
->ladrf
[1] = 0;
350 mem
+= sizeof(struct init_block
);
352 sc
->sc_rd
= (void *)mem
;
353 a
= LANCE_ADDR(sc
, mem
);
354 sc
->sc_init
->rdra
= a
;
355 sc
->sc_init
->rlen
= ((a
>> 16) & 0xff) | (RLEN
<< 13);
356 mem
+= NRBUF
* sizeof(struct mds
);
358 sc
->sc_td
= (void *)mem
;
359 a
= LANCE_ADDR(sc
, mem
);
360 sc
->sc_init
->tdra
= a
;
361 sc
->sc_init
->tlen
= ((a
>> 16) & 0xff) | (TLEN
<< 13);
362 mem
+= NTBUF
* sizeof(struct mds
);
365 * Set up receive ring descriptors.
368 for (i
= 0; i
< NRBUF
; i
++) {
369 a
= LANCE_ADDR(sc
, mem
);
370 sc
->sc_rd
[i
].addr
= a
;
371 sc
->sc_rd
[i
].flags
= ((a
>> 16) & 0xff) | LE_OWN
;
372 sc
->sc_rd
[i
].bcnt
= -BUFSIZE
;
373 sc
->sc_rd
[i
].mcnt
= 0;
378 * Set up transmit ring descriptors.
381 for (i
= 0; i
< NTBUF
; i
++) {
382 a
= LANCE_ADDR(sc
, mem
);
383 sc
->sc_td
[i
].addr
= a
;
384 sc
->sc_td
[i
].flags
= ((a
>> 16) & 0xff);
385 sc
->sc_td
[i
].bcnt
= 0xf000;
386 sc
->sc_td
[i
].mcnt
= 0;
392 le_reset(int unit
, u_char
*myea
)
394 struct le_softc
*sc
= &le_softc
[unit
];
400 printf("le%d: le_reset called\n", unit
);
401 printf(" r0=%x, r1=%x, mem=%x, addr=%x:%x:%x:%x:%x:%x\n",
402 sc
->sc_r0
, sc
->sc_r1
, sc
->sc_mem
,
403 sc
->sc_addr
[0], sc
->sc_addr
[1], sc
->sc_addr
[2],
404 sc
->sc_addr
[3], sc
->sc_addr
[4], sc
->sc_addr
[5]);
407 lewrcsr(sc
, 0, LE_STOP
);
408 for (timo
= 1000; timo
; timo
--);
410 sc
->sc_next_rd
= sc
->sc_next_td
= 0;
412 /* Set up LANCE init block. */
416 memcpy(myea
, sc
->sc_addr
, ETHER_ADDR_LEN
);
418 /* Turn on byte swapping. */
419 lewrcsr(sc
, 3, LE_BSWP
);
421 /* Give LANCE the physical address of its init block. */
422 a
= LANCE_ADDR(sc
, sc
->sc_init
);
424 lewrcsr(sc
, 2, (a
>> 16) & 0xff);
428 printf("le%d: before init\n", unit
);
431 /* Try to initialize the LANCE. */
432 lewrcsr(sc
, 0, LE_INIT
);
434 /* Wait for initialization to finish. */
435 for (timo
= 100000; timo
; timo
--)
436 if (lerdcsr(sc
, 0) & LE_IDON
)
439 if (lerdcsr(sc
, 0) & LE_IDON
) {
440 /* Start the LANCE. */
441 lewrcsr(sc
, 0, LE_INEA
| LE_STRT
| LE_IDON
);
443 printf("le%d: card failed to initialize\n", unit
);
447 printf("le%d: after init\n", unit
);
450 le_mem_summary(unit
);
454 le_poll(struct iodesc
*desc
, void *pkt
, int len
)
456 int unit
= /*nif->nif_unit*/0;
457 struct le_softc
*sc
= &le_softc
[unit
];
459 volatile struct mds
*cdm
;
464 printf("le%d: le_poll called. next_rd=%d\n", unit
, sc
->sc_next_rd
);
466 stat
= lerdcsr(sc
, 0);
467 lewrcsr(sc
, 0, stat
& (LE_BABL
| LE_MISS
| LE_MERR
| LE_RINT
));
468 cdm
= &sc
->sc_rd
[sc
->sc_next_rd
];
469 if (cdm
->flags
& LE_OWN
)
473 printf("next_rd %d\n", sc
->sc_next_rd
);
474 printf("cdm->flags %x\n", cdm
->flags
);
475 printf("cdm->bcnt %x, cdm->mcnt %x\n", cdm
->bcnt
, cdm
->mcnt
);
476 printf("cdm->rbuf msg %d buf %d\n", cdm
->mcnt
, -cdm
->bcnt
);
479 if (stat
& (LE_BABL
| LE_CERR
| LE_MISS
| LE_MERR
))
480 le_error(unit
, "le_poll", stat
);
481 if (cdm
->flags
& (LE_FRAM
| LE_OFLO
| LE_CRC
| LE_RBUFF
)) {
482 printf("le%d_poll: rmd status 0x%x\n", unit
, cdm
->flags
);
486 if ((cdm
->flags
& (LE_STP
|LE_ENP
)) != (LE_STP
|LE_ENP
))
487 panic("le_poll: chained packet");
492 printf("le_poll: length %d\n", length
);
494 if (length
>= BUFSIZE
) {
496 panic("csr0 when bad things happen: %x", stat
);
505 * If the length of the packet is greater than the size of the
506 * buffer, we have to truncate it, to avoid Bad Things.
507 * XXX Is this the right thing to do?
512 memcpy(pkt
, sc
->sc_rbuf
+ (BUFSIZE
* sc
->sc_next_rd
), length
);
517 cdm
->flags
|= LE_OWN
;
518 if (++sc
->sc_next_rd
>= NRBUF
)
522 printf("new next_rd %d\n", sc
->sc_next_rd
);
529 le_put(struct iodesc
*desc
, void *pkt
, size_t len
)
531 int unit
= /*nif->nif_unit*/0;
532 struct le_softc
*sc
= &le_softc
[unit
];
533 volatile struct mds
*cdm
;
541 printf("le%d: le_put called. next_td=%d\n", unit
, sc
->sc_next_td
);
543 stat
= lerdcsr(sc
, 0);
544 lewrcsr(sc
, 0, stat
& (LE_BABL
| LE_MISS
| LE_MERR
| LE_TINT
));
545 if (stat
& (LE_BABL
| LE_CERR
| LE_MISS
| LE_MERR
))
546 le_error(unit
, "le_put(way before xmit)", stat
);
547 cdm
= &sc
->sc_td
[sc
->sc_next_td
];
550 while (cdm
->flags
& LE_OWN
) {
552 printf("le%d: output buffer busy - flags=%x\n",
554 if (i
++ > 500) break;
556 if (cdm
->flags
& LE_OWN
)
559 while (cdm
->flags
& LE_OWN
);
561 memcpy(sc
->sc_tbuf
+ (BUFSIZE
* sc
->sc_next_td
), pkt
, len
);
562 if (len
< ETHER_MIN_LEN
)
563 cdm
->bcnt
= -ETHER_MIN_LEN
;
567 cdm
->flags
|= LE_OWN
| LE_STP
| LE_ENP
;
568 stat
= lerdcsr(sc
, 0);
569 if (stat
& (LE_BABL
| LE_CERR
| LE_MISS
| LE_MERR
))
570 le_error(unit
, "le_put(before xmit)", stat
);
571 lewrcsr(sc
, 0, LE_TDMD
);
572 stat
= lerdcsr(sc
, 0);
573 if (stat
& (LE_BABL
| LE_CERR
| LE_MISS
| LE_MERR
))
574 le_error(unit
, "le_put(after xmit)", stat
);
577 printf("le%d: transmit timeout, stat = 0x%x\n",
580 le_error(unit
, "le_put(timeout)", stat
);
581 if (stat
& LE_INIT
) {
582 printf("le%d: reset and retry packet\n", unit
);
583 lewrcsr(sc
, 0, LE_TINT
); /* sanity */
589 stat
= lerdcsr(sc
, 0);
590 } while ((stat
& LE_TINT
) == 0);
591 lewrcsr(sc
, 0, LE_TINT
);
592 if (stat
& (LE_BABL
|/* LE_CERR |*/ LE_MISS
| LE_MERR
)) {
593 printf("le_put: xmit error, buf %d\n", sc
->sc_next_td
);
594 le_error(unit
, "le_put(xmit error)", stat
);
596 if (++sc
->sc_next_td
>= NTBUF
)
598 if (cdm
->flags
& LE_DEF
)
599 le_stats
[unit
].deferred
++;
600 if (cdm
->flags
& LE_ONE
)
601 le_stats
[unit
].collisions
++;
602 if (cdm
->flags
& LE_MORE
)
603 le_stats
[unit
].collisions
+= 2;
604 if (cdm
->flags
& LE_ERR
) {
605 if (cdm
->mcnt
& LE_UFLO
)
606 printf("le%d: transmit underflow\n", unit
);
607 if (cdm
->mcnt
& LE_LCOL
)
608 le_stats
[unit
].collisions
++;
609 if (cdm
->mcnt
& LE_LCAR
)
610 printf("le%d: lost carrier\n", unit
);
611 if (cdm
->mcnt
& LE_RTRY
)
612 le_stats
[unit
].collisions
+= 16;
617 printf("le%d: le_put() successful: sent %d\n", unit
, len
);
618 printf("le%d: le_put(): flags: %x mcnt: %x\n", unit
,
619 (unsigned int) cdm
->flags
,
620 (unsigned int) cdm
->mcnt
);
628 le_get(struct iodesc
*desc
, void *pkt
, size_t len
, saseconds_t timeout
)
635 while (((getsecs() - t
) < timeout
) && !cc
) {
636 cc
= le_poll(desc
, pkt
, len
);
642 le_init(struct iodesc
*desc
, void *machdep_hint
)
644 struct netif
*nif
= desc
->io_netif
;
645 int unit
= nif
->nif_unit
;
647 /* Get machine's common ethernet interface. This is done in leinit() */
648 /* machdep_common_ether(myea); */
653 printf("le%d: le_init called\n", unit
);
656 le_reset(unit
, desc
->myea
);
660 le_end(struct netif
*nif
)
662 int unit
= nif
->nif_unit
;
666 printf("le%d: le_end called\n", unit
);
669 lewrcsr(&le_softc
[unit
], 0, LE_STOP
);