lemac.c revision 1.9 1 1.9 jonathan /* $NetBSD: lemac.c,v 1.9 1998/07/05 00:51:19 jonathan Exp $ */
2 1.1 matt
3 1.1 matt /*-
4 1.1 matt * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt (at) 3am-software.com>
5 1.1 matt * All rights reserved.
6 1.1 matt *
7 1.1 matt * Redistribution and use in source and binary forms, with or without
8 1.1 matt * modification, are permitted provided that the following conditions
9 1.1 matt * are met:
10 1.1 matt * 1. Redistributions of source code must retain the above copyright
11 1.1 matt * notice, this list of conditions and the following disclaimer.
12 1.1 matt * 2. The name of the author may not be used to endorse or promote products
13 1.1 matt * derived from this software withough specific prior written permission
14 1.1 matt *
15 1.1 matt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.1 matt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.1 matt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.1 matt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.1 matt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 1.1 matt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 1.1 matt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 1.1 matt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 1.1 matt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 1.1 matt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 1.1 matt */
26 1.1 matt
27 1.1 matt /*
28 1.1 matt * DEC EtherWORKS 3 Ethernet Controllers
29 1.1 matt *
30 1.1 matt * Written by Matt Thomas
31 1.1 matt * BPF support code stolen directly from if_ec.c
32 1.1 matt *
33 1.1 matt * This driver supports the LEMAC DE203/204/205 cards.
34 1.1 matt */
35 1.1 matt
36 1.9 jonathan #include "opt_inet.h"
37 1.2 explorer #include "rnd.h"
38 1.2 explorer
39 1.1 matt #include <sys/param.h>
40 1.1 matt #include <sys/systm.h>
41 1.1 matt #include <sys/mbuf.h>
42 1.1 matt #include <sys/protosw.h>
43 1.1 matt #include <sys/socket.h>
44 1.1 matt #include <sys/sockio.h>
45 1.1 matt #include <sys/errno.h>
46 1.1 matt #include <sys/malloc.h>
47 1.1 matt #include <sys/device.h>
48 1.2 explorer #if NRND > 0
49 1.2 explorer #include <sys/rnd.h>
50 1.2 explorer #endif
51 1.1 matt
52 1.1 matt #include <net/if.h>
53 1.1 matt #include <net/if_types.h>
54 1.1 matt #include <net/if_dl.h>
55 1.1 matt #include <net/route.h>
56 1.1 matt #include <net/if_ether.h>
57 1.1 matt #include <net/if_media.h>
58 1.1 matt
59 1.1 matt #ifdef INET
60 1.1 matt #include <netinet/in.h>
61 1.1 matt #include <netinet/in_systm.h>
62 1.1 matt #include <netinet/in_var.h>
63 1.1 matt #include <netinet/ip.h>
64 1.1 matt #include <netinet/if_inarp.h>
65 1.1 matt #endif
66 1.1 matt
67 1.1 matt #ifdef NS
68 1.1 matt #include <netns/ns.h>
69 1.1 matt #include <netns/ns_if.h>
70 1.1 matt #endif
71 1.1 matt
72 1.1 matt #include <machine/bus.h>
73 1.1 matt
74 1.1 matt #include <dev/ic/lemacreg.h>
75 1.1 matt #include <dev/ic/lemacvar.h>
76 1.1 matt #if 0
77 1.1 matt #include <i386/isa/decether.h>
78 1.1 matt #endif
79 1.1 matt
80 1.1 matt #include <vm/vm.h>
81 1.1 matt
82 1.1 matt #include "bpfilter.h"
83 1.1 matt #if NBPFILTER > 0
84 1.1 matt #include <net/bpf.h>
85 1.1 matt #endif
86 1.1 matt
87 1.1 matt static void lemac_init(lemac_softc_t *sc);
88 1.1 matt static void lemac_ifstart(struct ifnet *ifp);
89 1.1 matt static void lemac_reset(lemac_softc_t *sc);
90 1.1 matt static void lemac_rne_intr(lemac_softc_t *sc);
91 1.1 matt static void lemac_tne_intr(lemac_softc_t *sc);
92 1.1 matt static void lemac_txd_intr(lemac_softc_t *sc, unsigned cs_value);
93 1.1 matt static void lemac_rxd_intr(lemac_softc_t *sc, unsigned cs_value);
94 1.1 matt static int lemac_read_eeprom(lemac_softc_t *sc);
95 1.1 matt static void lemac_init_adapmem(lemac_softc_t *sc);
96 1.1 matt
97 1.1 matt static const u_int16_t lemac_allmulti_mctbl[16] = {
98 1.1 matt 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
99 1.1 matt 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
100 1.1 matt 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
101 1.1 matt 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
102 1.1 matt };
103 1.1 matt
104 1.1 matt /*
105 1.1 matt * Some tuning/monitoring variables.
106 1.1 matt */
107 1.1 matt unsigned lemac_txmax = 16;
108 1.1 matt
109 1.1 matt static void
111 1.1 matt lemac_rxd_intr(
112 1.1 matt lemac_softc_t *sc,
113 1.1 matt unsigned cs_value)
114 1.1 matt {
115 1.1 matt /*
116 1.1 matt * Handle CS_RXD (Receiver disabled) here.
117 1.1 matt *
118 1.1 matt * Check Free Memory Queue Count. If not equal to zero
119 1.1 matt * then just turn Receiver back on. If it is equal to
120 1.1 matt * zero then check to see if transmitter is disabled.
121 1.1 matt * Process transmit TXD loop once more. If all else
122 1.1 matt * fails then do software init (0xC0 to EEPROM Init)
123 1.1 matt * and rebuild Free Memory Queue.
124 1.1 matt */
125 1.1 matt
126 1.1 matt sc->sc_cntrs.cntr_rxd_intrs++;
127 1.1 matt
128 1.1 matt /*
129 1.1 matt * Re-enable Receiver.
130 1.1 matt */
131 1.1 matt
132 1.1 matt cs_value &= ~LEMAC_CS_RXD;
133 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value);
134 1.1 matt
135 1.1 matt if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0)
136 1.1 matt return;
137 1.1 matt
138 1.1 matt if (cs_value & LEMAC_CS_TXD)
139 1.1 matt lemac_txd_intr(sc, cs_value);
140 1.1 matt
141 1.1 matt if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0)
142 1.1 matt return;
143 1.1 matt
144 1.1 matt printf("%s: fatal RXD error, attempting recovery\n", sc->sc_if.if_xname);
145 1.1 matt
146 1.1 matt lemac_reset(sc);
147 1.1 matt if (sc->sc_if.if_flags & IFF_UP) {
148 1.1 matt lemac_init(sc);
149 1.1 matt return;
150 1.1 matt }
151 1.1 matt
152 1.1 matt /*
153 1.1 matt * Error during initializion. Mark card as disabled.
154 1.1 matt */
155 1.1 matt printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
156 1.1 matt }
157 1.1 matt
158 1.1 matt static void
160 1.1 matt lemac_tne_intr(
161 1.1 matt lemac_softc_t *sc)
162 1.1 matt {
163 1.1 matt unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC);
164 1.1 matt
165 1.1 matt sc->sc_cntrs.cntr_tne_intrs++;
166 1.1 matt while (txcount-- > 0) {
167 1.1 matt unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
168 1.1 matt sc->sc_if.if_opackets++; /* another one done */
169 1.1 matt if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL))
170 1.1 matt || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) {
171 1.1 matt if (txsts & LEMAC_TDQ_NCL)
172 1.1 matt sc->sc_flags &= ~LEMAC_LINKUP;
173 1.1 matt sc->sc_if.if_oerrors++;
174 1.1 matt } else {
175 1.1 matt sc->sc_flags |= LEMAC_LINKUP;
176 1.1 matt if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
177 1.1 matt sc->sc_if.if_collisions++;
178 1.1 matt }
179 1.1 matt }
180 1.1 matt sc->sc_if.if_flags &= ~IFF_OACTIVE;
181 1.1 matt lemac_ifstart(&sc->sc_if);
182 1.1 matt }
183 1.1 matt
184 1.1 matt static void
185 1.1 matt lemac_txd_intr(
186 1.1 matt lemac_softc_t *sc,
187 1.1 matt unsigned cs_value)
188 1.1 matt {
189 1.1 matt /*
190 1.1 matt * Read transmit status, remove transmit buffer from
191 1.1 matt * transmit queue and place on free memory queue,
192 1.1 matt * then reset transmitter.
193 1.1 matt * Increment appropriate counters.
194 1.1 matt */
195 1.1 matt
196 1.1 matt sc->sc_cntrs.cntr_txd_intrs++;
197 1.1 matt if (sc->sc_txctl & LEMAC_TX_STP) {
198 1.1 matt sc->sc_if.if_oerrors++;
199 1.1 matt /* return page to free queue */
200 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
201 1.1 matt }
202 1.1 matt
203 1.1 matt /* Turn back on transmitter if disabled */
204 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
205 1.1 matt sc->sc_if.if_flags &= ~IFF_OACTIVE;
206 1.1 matt }
207 1.1 matt
208 1.1 matt static int
210 1.1 matt lemac_read_eeprom(
211 1.1 matt lemac_softc_t *sc)
212 1.1 matt {
213 1.1 matt int word_off, cksum;
214 1.1 matt
215 1.1 matt u_char *ep;
216 1.1 matt
217 1.1 matt cksum = 0;
218 1.1 matt ep = sc->sc_eeprom;
219 1.1 matt for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
220 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
221 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
222 1.1 matt
223 1.1 matt DELAY(LEMAC_EEP_DELAY);
224 1.1 matt
225 1.1 matt *ep = LEMAC_INB(sc, LEMAC_REG_EE1); cksum += *ep++;
226 1.1 matt *ep = LEMAC_INB(sc, LEMAC_REG_EE2); cksum += *ep++;
227 1.1 matt }
228 1.1 matt
229 1.1 matt /*
230 1.1 matt * Set up Transmit Control Byte for use later during transmit.
231 1.1 matt */
232 1.1 matt
233 1.1 matt sc->sc_txctl |= LEMAC_TX_FLAGS;
234 1.1 matt
235 1.1 matt if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
236 1.1 matt sc->sc_txctl &= ~LEMAC_TX_SQE;
237 1.1 matt
238 1.1 matt if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
239 1.1 matt sc->sc_txctl |= LEMAC_TX_LAB;
240 1.1 matt
241 1.1 matt bcopy(&sc->sc_eeprom[LEMAC_EEP_PRDNM], sc->sc_prodname, LEMAC_EEP_PRDNMSZ);
242 1.1 matt sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
243 1.1 matt
244 1.1 matt return cksum % 256;
245 1.1 matt }
246 1.1 matt
247 1.1 matt static void
249 1.1 matt lemac_init_adapmem(
250 1.1 matt lemac_softc_t *sc)
251 1.1 matt {
252 1.1 matt int pg, conf;
253 1.1 matt
254 1.1 matt conf = LEMAC_INB(sc, LEMAC_REG_CNF);
255 1.1 matt
256 1.1 matt if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
257 1.1 matt sc->sc_lastpage = 63;
258 1.1 matt conf &= ~LEMAC_CNF_DRAM;
259 1.1 matt } else {
260 1.1 matt sc->sc_lastpage = 127;
261 1.1 matt conf |= LEMAC_CNF_DRAM;
262 1.1 matt }
263 1.1 matt
264 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
265 1.1 matt
266 1.1 matt for (pg = 1; pg <= sc->sc_lastpage; pg++)
267 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
268 1.1 matt }
269 1.1 matt
270 1.1 matt static void
272 1.1 matt lemac_input(
273 1.1 matt lemac_softc_t *sc,
274 1.1 matt bus_addr_t offset,
275 1.1 matt size_t length)
276 1.1 matt {
277 1.1 matt struct ether_header eh;
278 1.1 matt struct mbuf *m;
279 1.1 matt
280 1.1 matt if (length - sizeof(eh) > ETHERMTU
281 1.1 matt || length - sizeof(eh) < ETHERMIN) {
282 1.1 matt sc->sc_if.if_ierrors++;
283 1.1 matt return;
284 1.1 matt }
285 1.1 matt if (LEMAC_USE_PIO_MODE(sc)) {
286 1.1 matt LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *) &eh);
287 1.1 matt } else {
288 1.1 matt LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *) &eh);
289 1.1 matt }
290 1.1 matt
291 1.1 matt /*
292 1.1 matt * If this is single cast but not to us
293 1.1 matt * drop it!
294 1.8 matt */
295 1.1 matt if ((eh.ether_dhost[0] & 1) == 0
296 1.1 matt #if NBPFILTER > 0
297 1.1 matt && (sc->sc_if.if_flags & IFF_PROMISC) == 0
298 1.1 matt #endif
299 1.1 matt && !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_enaddr))
300 1.1 matt return;
301 1.1 matt
302 1.1 matt MGETHDR(m, M_DONTWAIT, MT_DATA);
303 1.1 matt if (m == NULL) {
304 1.1 matt sc->sc_if.if_ierrors++;
305 1.1 matt return;
306 1.1 matt }
307 1.1 matt if (length + 2 > MHLEN) {
308 1.1 matt MCLGET(m, M_DONTWAIT);
309 1.1 matt if ((m->m_flags & M_EXT) == 0) {
310 1.1 matt m_free(m);
311 1.1 matt sc->sc_if.if_ierrors++;
312 1.1 matt return;
313 1.1 matt }
314 1.1 matt }
315 1.1 matt m->m_data += 2;
316 1.1 matt bcopy((caddr_t)&eh, m->m_data, sizeof(eh));
317 1.1 matt if (LEMAC_USE_PIO_MODE(sc)) {
318 1.1 matt LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
319 1.1 matt mtod(m, caddr_t) + sizeof(eh));
320 1.1 matt } else {
321 1.1 matt LEMAC_GETBUF16(sc, offset + sizeof(eh), (length - sizeof(eh)) / 2,
322 1.1 matt (void *) (mtod(m, caddr_t) + sizeof(eh)));
323 1.1 matt if (length & 1)
324 1.1 matt m->m_data[length - 1] = LEMAC_GET8(sc, offset + length - 1);
325 1.1 matt }
326 1.1 matt #if NBPFILTER > 0
327 1.1 matt if (sc->sc_if.if_bpf != NULL) {
328 1.1 matt m->m_pkthdr.len = m->m_len = length;
329 1.1 matt bpf_mtap(sc->sc_if.if_bpf, m);
330 1.1 matt }
331 1.8 matt /*
332 1.1 matt * If this is single cast but not to us
333 1.1 matt * drop it!
334 1.1 matt */
335 1.1 matt if ((eh.ether_dhost[0] & 1) == 0
336 1.1 matt && !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_enaddr)) {
337 1.1 matt m_freem(m);
338 1.1 matt return;
339 1.1 matt }
340 1.1 matt #endif
341 1.1 matt m->m_pkthdr.len = m->m_len = length - sizeof(eh);
342 1.1 matt m->m_data += sizeof(eh);
343 1.1 matt m->m_pkthdr.rcvif = &sc->sc_if;
344 1.1 matt ether_input(&sc->sc_if, &eh, m);
345 1.1 matt }
346 1.1 matt
347 1.1 matt static void
349 1.1 matt lemac_rne_intr(
350 1.1 matt lemac_softc_t *sc)
351 1.1 matt {
352 1.1 matt int rxcount;
353 1.1 matt
354 1.1 matt sc->sc_cntrs.cntr_rne_intrs++;
355 1.1 matt rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
356 1.1 matt while (rxcount--) {
357 1.1 matt unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
358 1.1 matt u_int32_t rxlen;
359 1.1 matt
360 1.1 matt sc->sc_if.if_ipackets++;
361 1.1 matt if (LEMAC_USE_PIO_MODE(sc)) {
362 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
363 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
364 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
365 1.1 matt LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen), (void *) &rxlen);
366 1.1 matt } else {
367 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
368 1.1 matt rxlen = LEMAC_GET32(sc, 0);
369 1.1 matt }
370 1.1 matt if (rxlen & LEMAC_RX_OK) {
371 1.1 matt sc->sc_flags |= LEMAC_LINKUP;
372 1.1 matt /*
373 1.1 matt * Get receive length - subtract out checksum.
374 1.1 matt */
375 1.1 matt rxlen = ((rxlen >> 8) & 0x7FF) - 4;
376 1.1 matt lemac_input(sc, sizeof(rxlen), rxlen);
377 1.1 matt } else {
378 1.1 matt sc->sc_if.if_ierrors++;
379 1.1 matt }
380 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg); /* Return this page to Free Memory Queue */
381 1.1 matt } /* end while (recv_count--) */
382 1.1 matt
383 1.1 matt return;
384 1.1 matt }
385 1.1 matt
386 1.1 matt /*
388 1.1 matt * This is the standard method of reading the DEC Address ROMS.
389 1.1 matt * I don't understand it but it does work.
390 1.1 matt */
391 1.1 matt static int
392 1.1 matt lemac_read_macaddr(
393 1.1 matt unsigned char *hwaddr,
394 1.1 matt const bus_space_tag_t iot,
395 1.1 matt const bus_space_handle_t ioh,
396 1.1 matt const bus_addr_t ioreg,
397 1.1 matt int skippat)
398 1.1 matt {
399 1.1 matt int cksum, rom_cksum;
400 1.1 matt unsigned char addrbuf[6];
401 1.1 matt
402 1.1 matt if (!skippat) {
403 1.1 matt int idx, idx2, found, octet;
404 1.1 matt static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
405 1.1 matt idx2 = found = 0;
406 1.1 matt
407 1.1 matt for (idx = 0; idx < 32; idx++) {
408 1.1 matt octet = bus_space_read_1(iot, ioh, ioreg);
409 1.1 matt
410 1.1 matt if (octet == testpat[idx2]) {
411 1.1 matt if (++idx2 == sizeof(testpat)) {
412 1.1 matt ++found;
413 1.1 matt break;
414 1.1 matt }
415 1.1 matt } else {
416 1.1 matt idx2 = 0;
417 1.1 matt }
418 1.1 matt }
419 1.1 matt
420 1.1 matt if (!found)
421 1.1 matt return -1;
422 1.1 matt }
423 1.1 matt
424 1.1 matt if (hwaddr == NULL)
425 1.1 matt hwaddr = addrbuf;
426 1.1 matt
427 1.1 matt cksum = 0;
428 1.1 matt hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
429 1.1 matt hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
430 1.1 matt
431 1.1 matt /* hardware adddress can't be multicast */
432 1.1 matt if (hwaddr[0] & 1)
433 1.1 matt return -1;
434 1.1 matt
435 1.1 matt cksum = *(u_short *) &hwaddr[0];
436 1.1 matt
437 1.1 matt hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
438 1.1 matt hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
439 1.1 matt cksum *= 2;
440 1.1 matt if (cksum > 65535) cksum -= 65535;
441 1.1 matt cksum += *(u_short *) &hwaddr[2];
442 1.1 matt if (cksum > 65535) cksum -= 65535;
443 1.1 matt
444 1.1 matt hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
445 1.1 matt hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
446 1.1 matt cksum *= 2;
447 1.1 matt if (cksum > 65535) cksum -= 65535;
448 1.1 matt cksum += *(u_short *) &hwaddr[4];
449 1.1 matt if (cksum >= 65535) cksum -= 65535;
450 1.1 matt
451 1.1 matt /* 00-00-00 is an illegal OUI */
452 1.1 matt if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
453 1.1 matt return -1;
454 1.1 matt
455 1.1 matt rom_cksum = bus_space_read_1(iot, ioh, ioreg);
456 1.1 matt rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
457 1.1 matt
458 1.1 matt if (cksum != rom_cksum)
459 1.1 matt return -1;
460 1.1 matt return 0;
461 1.1 matt }
462 1.7 hannken
463 1.6 mycroft static void
465 1.5 mycroft lemac_multicast_op(
466 1.5 mycroft u_int16_t *mctbl,
467 1.5 mycroft const u_char *mca,
468 1.5 mycroft int enable)
469 1.1 matt {
470 1.4 mycroft u_int idx, bit, crc = 0xFFFFFFFFUL;
471 1.5 mycroft static const u_int crctab[] = {
472 1.5 mycroft 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
473 1.5 mycroft 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
474 1.4 mycroft 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
475 1.1 matt 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
476 1.1 matt };
477 1.1 matt
478 1.1 matt for (idx = 0; idx < 6; idx++) {
479 1.1 matt crc ^= *mca++;
480 1.1 matt crc = (crc >> 4) ^ crctab[crc & 0xf];
481 1.1 matt crc = (crc >> 4) ^ crctab[crc & 0xf];
482 1.1 matt }
483 1.1 matt /*
484 1.1 matt * The following two lines convert the N bit index into a longword index
485 1.1 matt * and a longword mask.
486 1.1 matt */
487 1.1 matt #if LEMAC_MCTBL_BITS < 0
488 1.1 matt crc >>= (32 + LEMAC_MCTBL_BITS);
489 1.1 matt crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
490 1.1 matt #else
491 1.1 matt crc &= (1 << LEMAC_MCTBL_BITS) - 1;
492 1.1 matt #endif
493 1.1 matt bit = 1 << (crc & 0x0F);
494 1.1 matt idx = crc >> 4;
495 1.1 matt
496 1.1 matt /*
497 1.1 matt * Set or clear hash filter bit in our table.
498 1.1 matt */
499 1.1 matt if (enable) {
500 1.1 matt mctbl[idx] |= bit; /* Set Bit */
501 1.1 matt } else {
502 1.1 matt mctbl[idx] &= ~bit; /* Clear Bit */
503 1.1 matt }
504 1.1 matt }
505 1.1 matt
506 1.1 matt static void
508 1.1 matt lemac_multicast_filter(
509 1.1 matt lemac_softc_t *sc)
510 1.1 matt {
511 1.1 matt struct ether_multistep step;
512 1.1 matt struct ether_multi *enm;
513 1.1 matt
514 1.1 matt bzero(sc->sc_mctbl, LEMAC_MCTBL_BITS / 8);
515 1.1 matt
516 1.1 matt lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE);
517 1.1 matt
518 1.1 matt ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
519 1.1 matt while (enm != NULL) {
520 1.1 matt if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
521 1.1 matt sc->sc_flags |= LEMAC_ALLMULTI;
522 1.1 matt sc->sc_if.if_flags |= IFF_ALLMULTI;
523 1.1 matt return;
524 1.1 matt }
525 1.1 matt lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
526 1.1 matt ETHER_NEXT_MULTI(step, enm);
527 1.1 matt }
528 1.1 matt sc->sc_flags &= ~LEMAC_ALLMULTI;
529 1.1 matt sc->sc_if.if_flags &= ~IFF_ALLMULTI;
530 1.1 matt }
531 1.1 matt
532 1.1 matt /*
534 1.1 matt * Do a hard reset of the board;
535 1.1 matt */
536 1.1 matt static void
537 1.1 matt lemac_reset(
538 1.1 matt lemac_softc_t * const sc)
539 1.1 matt {
540 1.1 matt unsigned data;
541 1.1 matt
542 1.1 matt /*
543 1.1 matt * Initialize board..
544 1.1 matt */
545 1.1 matt sc->sc_flags &= ~LEMAC_LINKUP;
546 1.1 matt sc->sc_if.if_flags &= ~IFF_OACTIVE;
547 1.1 matt LEMAC_INTR_DISABLE(sc);
548 1.1 matt
549 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
550 1.1 matt DELAY(LEMAC_EEP_DELAY);
551 1.1 matt
552 1.1 matt /*
553 1.1 matt * Read EEPROM information. NOTE - the placement of this function
554 1.1 matt * is important because functions hereafter may rely on information
555 1.1 matt * read from the EEPROM.
556 1.1 matt */
557 1.1 matt if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
558 1.1 matt printf("%s: reset: EEPROM checksum failed (0x%x)\n",
559 1.1 matt sc->sc_if.if_xname, data);
560 1.1 matt return;
561 1.1 matt }
562 1.1 matt
563 1.1 matt /*
564 1.1 matt * Update the control register to reflect the media choice
565 1.1 matt */
566 1.1 matt data = LEMAC_INB(sc, LEMAC_REG_CTL);
567 1.1 matt if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
568 1.1 matt data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
569 1.1 matt data |= sc->sc_ctlmode;
570 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
571 1.1 matt }
572 1.1 matt
573 1.1 matt /*
574 1.1 matt * Force to 2K mode if not already configured.
575 1.1 matt */
576 1.1 matt
577 1.1 matt data = LEMAC_INB(sc, LEMAC_REG_MBR);
578 1.1 matt if (LEMAC_IS_2K_MODE(data)) {
579 1.1 matt sc->sc_flags |= LEMAC_2K_MODE;
580 1.1 matt } else if (LEMAC_IS_64K_MODE(data)) {
581 1.1 matt data = (((data * 2) & 0xF) << 4);
582 1.1 matt sc->sc_flags |= LEMAC_WAS_64K_MODE;
583 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
584 1.1 matt } else if (LEMAC_IS_32K_MODE(data)) {
585 1.1 matt data = ((data & 0xF) << 4);
586 1.1 matt sc->sc_flags |= LEMAC_WAS_32K_MODE;
587 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
588 1.1 matt } else {
589 1.1 matt sc->sc_flags |= LEMAC_PIO_MODE;
590 1.1 matt /* PIO mode */
591 1.1 matt }
592 1.1 matt
593 1.1 matt /*
594 1.1 matt * Initialize Free Memory Queue, Init mcast table with broadcast.
595 1.1 matt */
596 1.1 matt
597 1.1 matt lemac_init_adapmem(sc);
598 1.1 matt sc->sc_flags |= LEMAC_ALIVE;
599 1.1 matt }
600 1.1 matt
601 1.1 matt static void
603 1.1 matt lemac_init(
604 1.8 matt lemac_softc_t * const sc)
605 1.8 matt {
606 1.8 matt if ((sc->sc_flags & LEMAC_ALIVE) == 0)
607 1.8 matt return;
608 1.8 matt
609 1.8 matt /*
610 1.1 matt * If the interface has the up flag
611 1.1 matt */
612 1.1 matt if (sc->sc_if.if_flags & IFF_UP) {
613 1.1 matt int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
614 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
615 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_enaddr[0]);
616 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_enaddr[1]);
617 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_enaddr[2]);
618 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_enaddr[3]);
619 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_enaddr[4]);
620 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_enaddr[5]);
621 1.1 matt
622 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IC, LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
623 1.1 matt
624 1.1 matt if (sc->sc_if.if_flags & IFF_PROMISC) {
625 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE | LEMAC_CS_PME);
626 1.1 matt } else {
627 1.1 matt LEMAC_INTR_DISABLE(sc);
628 1.1 matt lemac_multicast_filter(sc);
629 1.1 matt if (sc->sc_flags & LEMAC_ALLMULTI)
630 1.1 matt bcopy(lemac_allmulti_mctbl, sc->sc_mctbl, sizeof(sc->sc_mctbl));
631 1.1 matt if (LEMAC_USE_PIO_MODE(sc)) {
632 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
633 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI1, LEMAC_MCTBL_OFF & 0xFF);
634 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI2, LEMAC_MCTBL_OFF >> 8);
635 1.1 matt LEMAC_OUTSB(sc, LEMAC_REG_DAT, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
636 1.1 matt } else {
637 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
638 1.1 matt LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
639 1.1 matt }
640 1.1 matt
641 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
642 1.1 matt }
643 1.1 matt
644 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
645 1.1 matt
646 1.1 matt LEMAC_INTR_ENABLE(sc);
647 1.1 matt sc->sc_if.if_flags |= IFF_RUNNING;
648 1.1 matt lemac_ifstart(&sc->sc_if);
649 1.1 matt } else {
650 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
651 1.1 matt
652 1.1 matt LEMAC_INTR_DISABLE(sc);
653 1.1 matt sc->sc_if.if_flags &= ~IFF_RUNNING;
654 1.1 matt }
655 1.1 matt }
656 1.1 matt
657 1.1 matt static void
659 1.1 matt lemac_ifstart(
660 1.1 matt struct ifnet *ifp)
661 1.1 matt {
662 1.1 matt lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
663 1.1 matt struct ifqueue * const ifq = &ifp->if_snd;
664 1.1 matt
665 1.1 matt if ((ifp->if_flags & IFF_RUNNING) == 0)
666 1.1 matt return;
667 1.1 matt
668 1.1 matt LEMAC_INTR_DISABLE(sc);
669 1.1 matt
670 1.1 matt while (ifq->ifq_head != NULL) {
671 1.1 matt struct mbuf *m;
672 1.1 matt struct mbuf *m0;
673 1.1 matt int tx_pg;
674 1.1 matt
675 1.1 matt if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >= lemac_txmax) {
676 1.1 matt sc->sc_cntrs.cntr_txfull++;
677 1.1 matt ifp->if_flags |= IFF_OACTIVE;
678 1.1 matt break;
679 1.1 matt }
680 1.1 matt
681 1.1 matt /*
682 1.1 matt * get free memory page
683 1.1 matt */
684 1.1 matt tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
685 1.1 matt /*
686 1.1 matt * Check for good transmit page.
687 1.1 matt */
688 1.1 matt if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
689 1.1 matt sc->sc_cntrs.cntr_txnospc++;
690 1.1 matt ifp->if_flags |= IFF_OACTIVE;
691 1.1 matt break;
692 1.1 matt }
693 1.1 matt
694 1.1 matt IF_DEQUEUE(ifq, m);
695 1.1 matt
696 1.1 matt /*
697 1.1 matt * The first four bytes of each transmit buffer are for
698 1.1 matt * control information. The first byte is the control
699 1.1 matt * byte, then the length (why not word aligned??), then
700 1.1 matt * the offset to the buffer.
701 1.1 matt */
702 1.1 matt
703 1.1 matt if (LEMAC_USE_PIO_MODE(sc)) {
704 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg); /* Shift 2K window. */
705 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
706 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
707 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
708 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 0) & 0xFF);
709 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 8) & 0xFF);
710 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
711 1.1 matt for (m0 = m; m0 != NULL; m0 = m0->m_next)
712 1.1 matt LEMAC_OUTSB(sc, LEMAC_REG_DAT, m0->m_len, m0->m_data);
713 1.1 matt } else {
714 1.1 matt bus_size_t txoff = /* (mtod(m, u_int32_t) & (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
715 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg); /* Shift 2K window. */
716 1.1 matt LEMAC_PUT8(sc, 0, sc->sc_txctl);
717 1.1 matt LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
718 1.1 matt LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
719 1.1 matt LEMAC_PUT8(sc, 3, txoff);
720 1.1 matt
721 1.1 matt /*
722 1.1 matt * Copy the packet to the board
723 1.1 matt */
724 1.1 matt for (m0 = m; m0 != NULL; m0 = m0->m_next) {
725 1.1 matt #if 0
726 1.1 matt LEMAC_PUTBUF8(sc, txoff, m0->m_len, m0->m_data);
727 1.1 matt txoff += m0->m_len;
728 1.1 matt #else
729 1.1 matt const u_int8_t *cp = m0->m_data;
730 1.1 matt int len = m0->m_len;
731 1.1 matt #if 0
732 1.1 matt if ((txoff & 3) == (((long)cp) & 3) && len >= 4) {
733 1.1 matt if (txoff & 3) {
734 1.1 matt int alen = (~txoff & 3);
735 1.1 matt LEMAC_PUTBUF8(sc, txoff, alen, cp);
736 1.1 matt cp += alen; txoff += alen; len -= alen;
737 1.1 matt }
738 1.1 matt if (len >= 4) {
739 1.1 matt LEMAC_PUTBUF32(sc, txoff, len / 4, cp);
740 1.1 matt cp += len & ~3; txoff += len & ~3; len &= 3;
741 1.1 matt }
742 1.1 matt }
743 1.1 matt #endif
744 1.1 matt if ((txoff & 1) == (((long)cp) & 1) && len >= 2) {
745 1.1 matt if (txoff & 1) {
746 1.1 matt int alen = (~txoff & 1);
747 1.1 matt LEMAC_PUTBUF8(sc, txoff, alen, cp);
748 1.1 matt cp += alen; txoff += alen; len -= alen;
749 1.1 matt }
750 1.1 matt if (len >= 2) {
751 1.1 matt LEMAC_PUTBUF16(sc, txoff, len / 2, (void *) cp);
752 1.1 matt cp += len & ~1; txoff += len & ~1; len &= 1;
753 1.1 matt }
754 1.1 matt }
755 1.1 matt if (len > 0) {
756 1.1 matt LEMAC_PUTBUF8(sc, txoff, len, cp);
757 1.1 matt txoff += len;
758 1.1 matt }
759 1.1 matt #endif
760 1.1 matt }
761 1.1 matt }
762 1.1 matt
763 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg); /* tell chip to transmit this packet */
764 1.1 matt #if NBPFILTER > 0
765 1.1 matt if (sc->sc_if.if_bpf != NULL)
766 1.1 matt bpf_mtap(sc->sc_if.if_bpf, m);
767 1.1 matt #endif
768 1.1 matt m_freem(m); /* free the mbuf */
769 1.1 matt }
770 1.1 matt LEMAC_INTR_ENABLE(sc);
771 1.1 matt }
772 1.1 matt
773 1.1 matt static int
775 1.1 matt lemac_ifioctl(
776 1.1 matt struct ifnet *ifp,
777 1.1 matt u_long cmd,
778 1.1 matt caddr_t data)
779 1.1 matt {
780 1.1 matt lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
781 1.1 matt int s;
782 1.1 matt int error = 0;
783 1.1 matt
784 1.1 matt s = splnet();
785 1.1 matt
786 1.1 matt switch (cmd) {
787 1.1 matt case SIOCSIFADDR: {
788 1.1 matt struct ifaddr *ifa = (struct ifaddr *)data;
789 1.1 matt
790 1.1 matt ifp->if_flags |= IFF_UP;
791 1.1 matt lemac_init(sc);
792 1.1 matt switch (ifa->ifa_addr->sa_family) {
793 1.1 matt #ifdef INET
794 1.1 matt case AF_INET: {
795 1.8 matt arp_ifinit(&sc->sc_if, ifa);
796 1.1 matt break;
797 1.8 matt }
798 1.8 matt #endif /* INET */
799 1.1 matt
800 1.1 matt #ifdef NS
801 1.1 matt /* This magic copied from if_is.c; I don't use XNS,
802 1.1 matt * so I have no way of telling if this actually
803 1.1 matt * works or not.
804 1.1 matt */
805 1.1 matt case AF_NS: {
806 1.1 matt struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
807 1.1 matt if (ns_nullhost(*ina)) {
808 1.1 matt ina->x_host = *(union ns_host *)sc->sc_enaddr;
809 1.1 matt } else {
810 1.1 matt bcopy((caddr_t)ina->x_host.c_host, sc->sc_enaddr,
811 1.1 matt ifp->if_addrlen);
812 1.1 matt }
813 1.1 matt break;
814 1.1 matt }
815 1.1 matt #endif /* NS */
816 1.1 matt
817 1.1 matt default: {
818 1.1 matt break;
819 1.1 matt }
820 1.1 matt }
821 1.1 matt break;
822 1.1 matt }
823 1.1 matt
824 1.1 matt case SIOCSIFFLAGS: {
825 1.1 matt lemac_init(sc);
826 1.1 matt break;
827 1.1 matt }
828 1.1 matt
829 1.1 matt case SIOCADDMULTI:
830 1.1 matt case SIOCDELMULTI: {
831 1.1 matt /*
832 1.1 matt * Update multicast listeners
833 1.1 matt */
834 1.1 matt if (cmd == SIOCADDMULTI)
835 1.1 matt error = ether_addmulti((struct ifreq *)data, &sc->sc_ec);
836 1.1 matt else
837 1.1 matt error = ether_delmulti((struct ifreq *)data, &sc->sc_ec);
838 1.1 matt
839 1.1 matt if (error == ENETRESET) {
840 1.1 matt
841 1.1 matt /* reset multicast filtering */
842 1.1 matt lemac_init(sc);
843 1.1 matt error = 0;
844 1.1 matt }
845 1.1 matt break;
846 1.1 matt }
847 1.1 matt
848 1.1 matt case SIOCSIFMEDIA:
849 1.1 matt case SIOCGIFMEDIA: {
850 1.1 matt error = ifmedia_ioctl(ifp, (struct ifreq *)data,
851 1.1 matt &sc->sc_ifmedia, cmd);
852 1.1 matt break;
853 1.1 matt }
854 1.1 matt
855 1.1 matt default: {
856 1.1 matt error = EINVAL;
857 1.1 matt break;
858 1.1 matt }
859 1.1 matt }
860 1.1 matt
861 1.1 matt splx(s);
862 1.1 matt return error;
863 1.1 matt }
864 1.1 matt
865 1.1 matt static int
867 1.1 matt lemac_ifmedia_change(
868 1.1 matt struct ifnet * const ifp)
869 1.1 matt {
870 1.1 matt lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
871 1.1 matt unsigned new_ctl;
872 1.1 matt
873 1.1 matt switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
874 1.1 matt case IFM_10_T: new_ctl = LEMAC_CTL_APD; break;
875 1.1 matt case IFM_10_2:
876 1.1 matt case IFM_10_5: new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL; break;
877 1.1 matt case IFM_AUTO: new_ctl = 0; break;
878 1.1 matt default: return EINVAL;
879 1.1 matt }
880 1.1 matt if (sc->sc_ctlmode != new_ctl) {
881 1.1 matt sc->sc_ctlmode = new_ctl;
882 1.1 matt lemac_reset(sc);
883 1.1 matt if (sc->sc_if.if_flags & IFF_UP)
884 1.1 matt lemac_init(sc);
885 1.1 matt }
886 1.1 matt return 0;
887 1.1 matt }
888 1.1 matt
889 1.1 matt /*
890 1.1 matt * Media status callback
891 1.1 matt */
892 1.1 matt static void
893 1.1 matt lemac_ifmedia_status(
894 1.1 matt struct ifnet * const ifp,
895 1.1 matt struct ifmediareq *req)
896 1.1 matt {
897 1.1 matt lemac_softc_t *sc = LEMAC_IFP_TO_SOFTC(ifp);
898 1.1 matt unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
899 1.1 matt
900 1.1 matt req->ifm_status = IFM_AVALID;
901 1.1 matt if (sc->sc_flags & LEMAC_LINKUP)
902 1.1 matt req->ifm_status |= IFM_ACTIVE;
903 1.1 matt
904 1.1 matt if (sc->sc_ctlmode & LEMAC_CTL_APD) {
905 1.1 matt if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
906 1.1 matt req->ifm_active = IFM_10_5;
907 1.1 matt } else {
908 1.1 matt req->ifm_active = IFM_10_T;
909 1.1 matt }
910 1.1 matt } else {
911 1.1 matt /*
912 1.1 matt * The link bit of the configuration register reflects the
913 1.1 matt * current media choice when auto-port is enabled.
914 1.1 matt */
915 1.1 matt if (data & LEMAC_CNF_NOLINK) {
916 1.1 matt req->ifm_active = IFM_10_5;
917 1.1 matt } else {
918 1.1 matt req->ifm_active = IFM_10_T;
919 1.1 matt }
920 1.1 matt }
921 1.1 matt
922 1.1 matt req->ifm_active |= IFM_ETHER;
923 1.1 matt }
924 1.1 matt
925 1.1 matt int
927 1.1 matt lemac_port_check(
928 1.1 matt const bus_space_tag_t iot,
929 1.1 matt const bus_space_handle_t ioh)
930 1.1 matt {
931 1.1 matt unsigned char hwaddr[6];
932 1.1 matt
933 1.1 matt if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
934 1.1 matt return 1;
935 1.1 matt if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
936 1.1 matt return 1;
937 1.1 matt return 0;
938 1.1 matt }
939 1.1 matt
940 1.1 matt void
942 1.1 matt lemac_info_get(
943 1.1 matt const bus_space_tag_t iot,
944 1.1 matt const bus_space_handle_t ioh,
945 1.1 matt bus_addr_t *maddr_p,
946 1.1 matt bus_size_t *msize_p,
947 1.1 matt int *irq_p)
948 1.1 matt {
949 1.1 matt unsigned data;
950 1.1 matt
951 1.1 matt *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) & LEMAC_IC_IRQMSK);
952 1.1 matt
953 1.1 matt data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
954 1.1 matt if (LEMAC_IS_2K_MODE(data)) {
955 1.1 matt *maddr_p = data * (2 * 1024) + (512 * 1024);
956 1.1 matt *msize_p = 2 * 1024;
957 1.1 matt } else if (LEMAC_IS_64K_MODE(data)) {
958 1.1 matt *maddr_p = data * 64 * 1024;
959 1.1 matt *msize_p = 64 * 1024;
960 1.1 matt } else if (LEMAC_IS_32K_MODE(data)) {
961 1.1 matt *maddr_p = data * 32 * 1024;
962 1.1 matt *msize_p = 32* 1024;
963 1.1 matt } else {
964 1.1 matt *maddr_p = 0;
965 1.1 matt *msize_p = 0;
966 1.1 matt }
967 1.1 matt }
968 1.1 matt
969 1.1 matt /*
971 1.1 matt * What to do upon receipt of an interrupt.
972 1.1 matt */
973 1.1 matt int
974 1.1 matt lemac_intr(
975 1.1 matt void *arg)
976 1.1 matt {
977 1.1 matt lemac_softc_t * const sc = arg;
978 1.1 matt int cs_value;
979 1.1 matt
980 1.1 matt LEMAC_INTR_DISABLE(sc); /* Mask interrupts */
981 1.1 matt
982 1.1 matt /*
983 1.1 matt * Determine cause of interrupt. Receive events take
984 1.1 matt * priority over Transmit.
985 1.1 matt */
986 1.1 matt
987 1.1 matt cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
988 1.1 matt
989 1.1 matt /*
990 1.1 matt * Check for Receive Queue not being empty.
991 1.1 matt * Check for Transmit Done Queue not being empty.
992 1.1 matt */
993 1.1 matt
994 1.1 matt if (cs_value & LEMAC_CS_RNE)
995 1.1 matt lemac_rne_intr(sc);
996 1.1 matt if (cs_value & LEMAC_CS_TNE)
997 1.1 matt lemac_tne_intr(sc);
998 1.1 matt
999 1.1 matt /*
1000 1.2 explorer * Check for Transmitter Disabled.
1001 1.2 explorer * Check for Receiver Disabled.
1002 1.2 explorer */
1003 1.2 explorer
1004 1.2 explorer if (cs_value & LEMAC_CS_TXD)
1005 1.2 explorer lemac_txd_intr(sc, cs_value);
1006 1.1 matt if (cs_value & LEMAC_CS_RXD)
1007 1.1 matt lemac_rxd_intr(sc, cs_value);
1008 1.1 matt
1009 1.1 matt /*
1010 1.1 matt * Toggle LED and unmask interrupts.
1011 1.1 matt */
1012 1.1 matt
1013 1.1 matt sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
1014 1.1 matt
1015 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
1016 1.1 matt LEMAC_INTR_ENABLE(sc); /* Unmask interrupts */
1017 1.1 matt
1018 1.1 matt #if NRND > 0
1019 1.1 matt if (cs_value)
1020 1.1 matt rnd_add_uint32(&sc->rnd_source, cs_value);
1021 1.1 matt #endif
1022 1.1 matt
1023 1.1 matt return 1;
1024 1.1 matt }
1025 1.1 matt
1026 1.1 matt void
1027 1.1 matt lemac_shutdown(
1028 1.1 matt void *arg)
1029 1.1 matt {
1030 1.1 matt lemac_reset((lemac_softc_t *) arg);
1031 1.1 matt }
1032 1.1 matt
1033 1.1 matt static const char * const lemac_modes[4] = {
1035 1.1 matt "PIO mode (internal 2KB window)",
1036 1.1 matt "2KB window",
1037 1.1 matt "changed 32KB window to 2KB",
1038 1.1 matt "changed 64KB window to 2KB",
1039 1.1 matt };
1040 1.1 matt
1041 1.1 matt void
1042 1.1 matt lemac_ifattach(
1043 1.1 matt lemac_softc_t *sc)
1044 1.1 matt {
1045 1.1 matt struct ifnet * const ifp = &sc->sc_if;
1046 1.1 matt
1047 1.1 matt bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
1048 1.1 matt
1049 1.1 matt lemac_reset(sc);
1050 1.1 matt
1051 1.1 matt (void) lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh,
1052 1.1 matt LEMAC_REG_APD, 0);
1053 1.1 matt
1054 1.1 matt printf(": %s\n", sc->sc_prodname);
1055 1.1 matt
1056 1.1 matt printf("%s: address %s, %dKB RAM, %s\n",
1057 1.1 matt ifp->if_xname,
1058 1.1 matt ether_sprintf(sc->sc_enaddr),
1059 1.1 matt sc->sc_lastpage * 2 + 2,
1060 1.1 matt lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
1061 1.1 matt
1062 1.1 matt ifp->if_baudrate = 10000000;
1063 1.1 matt ifp->if_softc = (void *) sc;
1064 1.1 matt ifp->if_start = lemac_ifstart;
1065 1.2 explorer ifp->if_output = ether_output;
1066 1.2 explorer ifp->if_ioctl = lemac_ifioctl;
1067 1.2 explorer
1068 1.2 explorer ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
1069 1.2 explorer #ifdef IFF_NOTRAILERS
1070 1.1 matt | IFF_NOTRAILERS
1071 1.1 matt #endif
1072 1.1 matt | IFF_MULTICAST;
1073 1.1 matt
1074 1.1 matt if (sc->sc_flags & LEMAC_ALIVE) {
1075 1.1 matt int media;
1076 1.1 matt
1077 1.1 matt if_attach(ifp);
1078 1.1 matt ether_ifattach(ifp, sc->sc_enaddr);
1079 1.1 matt
1080 1.1 matt #if NBPFILTER > 0
1081 1.1 matt bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
1082 1.1 matt #endif
1083 1.1 matt
1084 1.1 matt #if NRND > 0
1085 1.1 matt rnd_attach_source(&sc->rnd_source, sc->sc_dv.dv_xname, RND_TYPE_NET);
1086 1.1 matt #endif
1087 1.1 matt
1088 1.1 matt ifmedia_init(&sc->sc_ifmedia, 0,
1089 lemac_ifmedia_change,
1090 lemac_ifmedia_status);
1091 if (sc->sc_prodname[4] == '5') /* DE205 is UTP/AUI */
1092 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
1093 if (sc->sc_prodname[4] != '3') /* DE204 & 205 have UTP */
1094 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
1095 if (sc->sc_prodname[4] != '4') /* DE203 & 205 have BNC */
1096 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
1097 switch (sc->sc_prodname[4]) {
1098 case '3': media = IFM_10_5; break;
1099 case '4': media = IFM_10_T; break;
1100 default: media = IFM_AUTO; break;
1101 }
1102 ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
1103 } else {
1104 printf("%s: disabled due to error\n", ifp->if_xname);
1105 }
1106 }
1107