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