lemac.c revision 1.38 1 1.38 joerg /* $NetBSD: lemac.c,v 1.38 2010/04/05 07:19:35 joerg 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.38 joerg __KERNEL_RCSID(0, "$NetBSD: lemac.c,v 1.38 2010/04/05 07:19:35 joerg Exp $");
38 1.1 matt
39 1.9 jonathan #include "opt_inet.h"
40 1.2 explorer #include "rnd.h"
41 1.2 explorer
42 1.1 matt #include <sys/param.h>
43 1.1 matt #include <sys/systm.h>
44 1.1 matt #include <sys/mbuf.h>
45 1.1 matt #include <sys/protosw.h>
46 1.1 matt #include <sys/socket.h>
47 1.1 matt #include <sys/sockio.h>
48 1.1 matt #include <sys/errno.h>
49 1.1 matt #include <sys/malloc.h>
50 1.1 matt #include <sys/device.h>
51 1.2 explorer #if NRND > 0
52 1.2 explorer #include <sys/rnd.h>
53 1.2 explorer #endif
54 1.1 matt
55 1.1 matt #include <net/if.h>
56 1.1 matt #include <net/if_types.h>
57 1.1 matt #include <net/if_dl.h>
58 1.1 matt #include <net/route.h>
59 1.1 matt #include <net/if_ether.h>
60 1.1 matt #include <net/if_media.h>
61 1.1 matt
62 1.1 matt #ifdef INET
63 1.1 matt #include <netinet/in.h>
64 1.1 matt #include <netinet/in_systm.h>
65 1.1 matt #include <netinet/in_var.h>
66 1.1 matt #include <netinet/ip.h>
67 1.1 matt #include <netinet/if_inarp.h>
68 1.1 matt #endif
69 1.1 matt
70 1.1 matt
71 1.34 ad #include <sys/bus.h>
72 1.1 matt
73 1.1 matt #include <dev/ic/lemacreg.h>
74 1.1 matt #include <dev/ic/lemacvar.h>
75 1.1 matt #if 0
76 1.1 matt #include <i386/isa/decether.h>
77 1.1 matt #endif
78 1.1 matt
79 1.15 mrg #include <uvm/uvm_extern.h>
80 1.1 matt
81 1.1 matt #include <net/bpf.h>
82 1.1 matt
83 1.1 matt static void lemac_init(lemac_softc_t *sc);
84 1.1 matt static void lemac_ifstart(struct ifnet *ifp);
85 1.1 matt static void lemac_reset(lemac_softc_t *sc);
86 1.1 matt static void lemac_rne_intr(lemac_softc_t *sc);
87 1.1 matt static void lemac_tne_intr(lemac_softc_t *sc);
88 1.1 matt static void lemac_txd_intr(lemac_softc_t *sc, unsigned cs_value);
89 1.1 matt static void lemac_rxd_intr(lemac_softc_t *sc, unsigned cs_value);
90 1.1 matt static int lemac_read_eeprom(lemac_softc_t *sc);
91 1.1 matt static void lemac_init_adapmem(lemac_softc_t *sc);
92 1.1 matt
93 1.24 itojun static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_t)] = {
94 1.24 itojun 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
95 1.24 itojun 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
96 1.24 itojun 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
97 1.24 itojun 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
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.25 wiz /*
153 1.1 matt * Error during initialization. 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.21 thorpej 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 memcpy(sc->sc_prodname, &sc->sc_eeprom[LEMAC_EEP_PRDNM], 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 MGETHDR(m, M_DONTWAIT, MT_DATA);
292 1.1 matt if (m == NULL) {
293 1.1 matt sc->sc_if.if_ierrors++;
294 1.1 matt return;
295 1.1 matt }
296 1.1 matt if (length + 2 > MHLEN) {
297 1.1 matt MCLGET(m, M_DONTWAIT);
298 1.1 matt if ((m->m_flags & M_EXT) == 0) {
299 1.1 matt m_free(m);
300 1.31 christos sc->sc_if.if_ierrors++;
301 1.1 matt return;
302 1.1 matt }
303 1.31 christos }
304 1.1 matt m->m_data += 2;
305 1.1 matt memcpy(m->m_data, (void *)&eh, sizeof(eh));
306 1.32 yamt if (LEMAC_USE_PIO_MODE(sc)) {
307 1.1 matt LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
308 1.1 matt mtod(m, char *) + sizeof(eh));
309 1.1 matt } else {
310 1.1 matt LEMAC_GETBUF16(sc, offset + sizeof(eh), (length - sizeof(eh)) / 2,
311 1.1 matt (void *)(mtod(m, char *) + sizeof(eh)));
312 1.38 joerg if (length & 1)
313 1.1 matt m->m_data[length - 1] = LEMAC_GET8(sc, offset + length - 1);
314 1.1 matt }
315 1.1 matt if (sc->sc_if.if_bpf != NULL) {
316 1.1 matt m->m_pkthdr.len = m->m_len = length;
317 1.1 matt bpf_mtap(&sc->sc_if, m);
318 1.1 matt }
319 1.8 matt /*
320 1.1 matt * If this is single cast but not to us
321 1.1 matt * drop it!
322 1.1 matt */
323 1.12 thorpej if ((eh.ether_dhost[0] & 1) == 0
324 1.1 matt && !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_enaddr)) {
325 1.12 thorpej m_freem(m);
326 1.1 matt return;
327 1.1 matt }
328 1.1 matt m->m_pkthdr.len = m->m_len = length;
329 1.1 matt m->m_pkthdr.rcvif = &sc->sc_if;
330 1.1 matt (*sc->sc_if.if_input)(&sc->sc_if, m);
331 1.1 matt }
332 1.1 matt
333 1.1 matt static void
335 1.1 matt lemac_rne_intr(
336 1.1 matt lemac_softc_t *sc)
337 1.1 matt {
338 1.1 matt int rxcount;
339 1.27 perry
340 1.1 matt sc->sc_cntrs.cntr_rne_intrs++;
341 1.1 matt rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
342 1.1 matt while (rxcount--) {
343 1.1 matt unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
344 1.1 matt u_int32_t rxlen;
345 1.1 matt
346 1.1 matt sc->sc_if.if_ipackets++;
347 1.1 matt if (LEMAC_USE_PIO_MODE(sc)) {
348 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
349 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
350 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
351 1.1 matt LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen), (void *) &rxlen);
352 1.1 matt } else {
353 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
354 1.1 matt rxlen = LEMAC_GET32(sc, 0);
355 1.1 matt }
356 1.1 matt if (rxlen & LEMAC_RX_OK) {
357 1.1 matt sc->sc_flags |= LEMAC_LINKUP;
358 1.1 matt /*
359 1.1 matt * Get receive length - subtract out checksum.
360 1.1 matt */
361 1.1 matt rxlen = ((rxlen >> 8) & 0x7FF) - 4;
362 1.27 perry lemac_input(sc, sizeof(rxlen), rxlen);
363 1.1 matt } else {
364 1.1 matt sc->sc_if.if_ierrors++;
365 1.1 matt }
366 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg); /* Return this page to Free Memory Queue */
367 1.1 matt } /* end while (recv_count--) */
368 1.1 matt
369 1.1 matt return;
370 1.1 matt }
371 1.1 matt
372 1.1 matt /*
374 1.1 matt * This is the standard method of reading the DEC Address ROMS.
375 1.1 matt * I don't understand it but it does work.
376 1.1 matt */
377 1.1 matt static int
378 1.1 matt lemac_read_macaddr(
379 1.1 matt unsigned char *hwaddr,
380 1.27 perry const bus_space_tag_t iot,
381 1.1 matt const bus_space_handle_t ioh,
382 1.1 matt const bus_addr_t ioreg,
383 1.1 matt int skippat)
384 1.1 matt {
385 1.27 perry int cksum, rom_cksum;
386 1.1 matt unsigned char addrbuf[6];
387 1.1 matt
388 1.27 perry if (!skippat) {
389 1.1 matt int idx, idx2, found, octet;
390 1.1 matt static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
391 1.1 matt idx2 = found = 0;
392 1.1 matt
393 1.1 matt for (idx = 0; idx < 32; idx++) {
394 1.1 matt octet = bus_space_read_1(iot, ioh, ioreg);
395 1.1 matt
396 1.1 matt if (octet == testpat[idx2]) {
397 1.1 matt if (++idx2 == sizeof(testpat)) {
398 1.27 perry ++found;
399 1.1 matt break;
400 1.1 matt }
401 1.1 matt } else {
402 1.1 matt idx2 = 0;
403 1.1 matt }
404 1.1 matt }
405 1.1 matt
406 1.1 matt if (!found)
407 1.1 matt return -1;
408 1.1 matt }
409 1.1 matt
410 1.25 wiz if (hwaddr == NULL)
411 1.1 matt hwaddr = addrbuf;
412 1.1 matt
413 1.1 matt cksum = 0;
414 1.1 matt hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
415 1.1 matt hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
416 1.1 matt
417 1.1 matt /* hardware address can't be multicast */
418 1.1 matt if (hwaddr[0] & 1)
419 1.1 matt return -1;
420 1.1 matt
421 1.1 matt cksum = *(u_short *) &hwaddr[0];
422 1.1 matt
423 1.1 matt hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
424 1.1 matt hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
425 1.1 matt cksum *= 2;
426 1.1 matt if (cksum > 65535) cksum -= 65535;
427 1.1 matt cksum += *(u_short *) &hwaddr[2];
428 1.1 matt if (cksum > 65535) cksum -= 65535;
429 1.1 matt
430 1.1 matt hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
431 1.1 matt hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
432 1.1 matt cksum *= 2;
433 1.1 matt if (cksum > 65535) cksum -= 65535;
434 1.1 matt cksum += *(u_short *) &hwaddr[4];
435 1.1 matt if (cksum >= 65535) cksum -= 65535;
436 1.27 perry
437 1.1 matt /* 00-00-00 is an illegal OUI */
438 1.1 matt if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
439 1.1 matt return -1;
440 1.1 matt
441 1.1 matt rom_cksum = bus_space_read_1(iot, ioh, ioreg);
442 1.1 matt rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
443 1.1 matt
444 1.1 matt if (cksum != rom_cksum)
445 1.1 matt return -1;
446 1.1 matt return 0;
447 1.1 matt }
448 1.14 thorpej
449 1.14 thorpej static void
451 1.14 thorpej lemac_multicast_op(
452 1.1 matt u_int16_t *mctbl,
453 1.1 matt const u_char *mca,
454 1.27 perry int enable)
455 1.1 matt {
456 1.1 matt u_int idx, bit, crc;
457 1.1 matt
458 1.1 matt crc = ether_crc32_le(mca, ETHER_ADDR_LEN);
459 1.1 matt
460 1.1 matt /*
461 1.1 matt * The following two lines convert the N bit index into a longword index
462 1.1 matt * and a longword mask.
463 1.1 matt */
464 1.1 matt #if LEMAC_MCTBL_BITS < 0
465 1.1 matt crc >>= (32 + LEMAC_MCTBL_BITS);
466 1.1 matt crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
467 1.1 matt #else
468 1.1 matt crc &= (1 << LEMAC_MCTBL_BITS) - 1;
469 1.1 matt #endif
470 1.1 matt bit = 1 << (crc & 0x0F);
471 1.1 matt idx = crc >> 4;
472 1.1 matt
473 1.1 matt /*
474 1.1 matt * Set or clear hash filter bit in our table.
475 1.1 matt */
476 1.1 matt if (enable) {
477 1.1 matt mctbl[idx] |= bit; /* Set Bit */
478 1.1 matt } else {
479 1.1 matt mctbl[idx] &= ~bit; /* Clear Bit */
480 1.1 matt }
481 1.1 matt }
482 1.22 thorpej
483 1.1 matt static void
485 1.1 matt lemac_multicast_filter(
486 1.1 matt lemac_softc_t *sc)
487 1.1 matt {
488 1.1 matt struct ether_multistep step;
489 1.1 matt struct ether_multi *enm;
490 1.1 matt
491 1.1 matt memset(sc->sc_mctbl, 0, LEMAC_MCTBL_BITS / 8);
492 1.1 matt
493 1.1 matt lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE);
494 1.1 matt
495 1.1 matt ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
496 1.1 matt while (enm != NULL) {
497 1.1 matt if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
498 1.1 matt sc->sc_flags |= LEMAC_ALLMULTI;
499 1.1 matt sc->sc_if.if_flags |= IFF_ALLMULTI;
500 1.27 perry return;
501 1.1 matt }
502 1.1 matt lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
503 1.1 matt ETHER_NEXT_MULTI(step, enm);
504 1.1 matt }
505 1.1 matt sc->sc_flags &= ~LEMAC_ALLMULTI;
506 1.1 matt sc->sc_if.if_flags &= ~IFF_ALLMULTI;
507 1.1 matt }
508 1.1 matt
509 1.1 matt /*
511 1.1 matt * Do a hard reset of the board;
512 1.1 matt */
513 1.1 matt static void
514 1.1 matt lemac_reset(
515 1.1 matt lemac_softc_t * const sc)
516 1.1 matt {
517 1.1 matt unsigned data;
518 1.1 matt
519 1.1 matt /*
520 1.1 matt * Initialize board..
521 1.1 matt */
522 1.1 matt sc->sc_flags &= ~LEMAC_LINKUP;
523 1.1 matt sc->sc_if.if_flags &= ~IFF_OACTIVE;
524 1.27 perry LEMAC_INTR_DISABLE(sc);
525 1.1 matt
526 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
527 1.1 matt DELAY(LEMAC_EEP_DELAY);
528 1.1 matt
529 1.1 matt /*
530 1.1 matt * Read EEPROM information. NOTE - the placement of this function
531 1.1 matt * is important because functions hereafter may rely on information
532 1.1 matt * read from the EEPROM.
533 1.1 matt */
534 1.1 matt if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
535 1.1 matt printf("%s: reset: EEPROM checksum failed (0x%x)\n",
536 1.1 matt sc->sc_if.if_xname, data);
537 1.1 matt return;
538 1.1 matt }
539 1.1 matt
540 1.1 matt /*
541 1.1 matt * Update the control register to reflect the media choice
542 1.1 matt */
543 1.1 matt data = LEMAC_INB(sc, LEMAC_REG_CTL);
544 1.1 matt if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
545 1.1 matt data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
546 1.1 matt data |= sc->sc_ctlmode;
547 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
548 1.1 matt }
549 1.1 matt
550 1.1 matt /*
551 1.1 matt * Force to 2K mode if not already configured.
552 1.1 matt */
553 1.1 matt
554 1.1 matt data = LEMAC_INB(sc, LEMAC_REG_MBR);
555 1.1 matt if (LEMAC_IS_2K_MODE(data)) {
556 1.1 matt sc->sc_flags |= LEMAC_2K_MODE;
557 1.1 matt } else if (LEMAC_IS_64K_MODE(data)) {
558 1.1 matt data = (((data * 2) & 0xF) << 4);
559 1.1 matt sc->sc_flags |= LEMAC_WAS_64K_MODE;
560 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
561 1.1 matt } else if (LEMAC_IS_32K_MODE(data)) {
562 1.1 matt data = ((data & 0xF) << 4);
563 1.1 matt sc->sc_flags |= LEMAC_WAS_32K_MODE;
564 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
565 1.1 matt } else {
566 1.1 matt sc->sc_flags |= LEMAC_PIO_MODE;
567 1.1 matt /* PIO mode */
568 1.1 matt }
569 1.1 matt
570 1.1 matt /*
571 1.1 matt * Initialize Free Memory Queue, Init mcast table with broadcast.
572 1.1 matt */
573 1.1 matt
574 1.1 matt lemac_init_adapmem(sc);
575 1.1 matt sc->sc_flags |= LEMAC_ALIVE;
576 1.1 matt }
577 1.1 matt
578 1.1 matt static void
580 1.1 matt lemac_init(
581 1.8 matt lemac_softc_t * const sc)
582 1.8 matt {
583 1.8 matt if ((sc->sc_flags & LEMAC_ALIVE) == 0)
584 1.8 matt return;
585 1.8 matt
586 1.8 matt /*
587 1.1 matt * If the interface has the up flag
588 1.1 matt */
589 1.1 matt if (sc->sc_if.if_flags & IFF_UP) {
590 1.1 matt int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
591 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
592 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_enaddr[0]);
593 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_enaddr[1]);
594 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_enaddr[2]);
595 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_enaddr[3]);
596 1.21 thorpej LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_enaddr[4]);
597 1.21 thorpej LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_enaddr[5]);
598 1.1 matt
599 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IC, LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
600 1.1 matt
601 1.1 matt if (sc->sc_if.if_flags & IFF_PROMISC) {
602 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE | LEMAC_CS_PME);
603 1.1 matt } else {
604 1.1 matt LEMAC_INTR_DISABLE(sc);
605 1.1 matt lemac_multicast_filter(sc);
606 1.1 matt if (sc->sc_flags & LEMAC_ALLMULTI)
607 1.1 matt memcpy(sc->sc_mctbl, lemac_allmulti_mctbl,
608 1.1 matt sizeof(sc->sc_mctbl));
609 1.1 matt if (LEMAC_USE_PIO_MODE(sc)) {
610 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
611 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI1, LEMAC_MCTBL_OFF & 0xFF);
612 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI2, LEMAC_MCTBL_OFF >> 8);
613 1.1 matt LEMAC_OUTSB(sc, LEMAC_REG_DAT, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
614 1.1 matt } else {
615 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
616 1.1 matt LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
617 1.1 matt }
618 1.1 matt
619 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
620 1.1 matt }
621 1.1 matt
622 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
623 1.1 matt
624 1.27 perry LEMAC_INTR_ENABLE(sc);
625 1.1 matt sc->sc_if.if_flags |= IFF_RUNNING;
626 1.1 matt lemac_ifstart(&sc->sc_if);
627 1.1 matt } else {
628 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
629 1.1 matt
630 1.1 matt LEMAC_INTR_DISABLE(sc);
631 1.1 matt sc->sc_if.if_flags &= ~IFF_RUNNING;
632 1.1 matt }
633 1.1 matt }
634 1.1 matt
635 1.18 thorpej static void
637 1.1 matt lemac_ifstart(
638 1.1 matt struct ifnet *ifp)
639 1.1 matt {
640 1.18 thorpej lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
641 1.18 thorpej
642 1.18 thorpej if ((ifp->if_flags & IFF_RUNNING) == 0)
643 1.18 thorpej return;
644 1.1 matt
645 1.1 matt LEMAC_INTR_DISABLE(sc);
646 1.1 matt
647 1.1 matt for (;;) {
648 1.1 matt struct mbuf *m;
649 1.1 matt struct mbuf *m0;
650 1.1 matt int tx_pg;
651 1.1 matt
652 1.1 matt IFQ_POLL(&ifp->if_snd, m);
653 1.1 matt if (m == NULL)
654 1.1 matt break;
655 1.1 matt
656 1.1 matt if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >= lemac_txmax) {
657 1.1 matt sc->sc_cntrs.cntr_txfull++;
658 1.1 matt ifp->if_flags |= IFF_OACTIVE;
659 1.1 matt break;
660 1.1 matt }
661 1.1 matt
662 1.1 matt /*
663 1.18 thorpej * get free memory page
664 1.1 matt */
665 1.1 matt tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
666 1.1 matt /*
667 1.1 matt * Check for good transmit page.
668 1.19 lukem */
669 1.1 matt if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
670 1.1 matt sc->sc_cntrs.cntr_txnospc++;
671 1.1 matt ifp->if_flags |= IFF_OACTIVE;
672 1.1 matt break;
673 1.1 matt }
674 1.1 matt
675 1.1 matt IFQ_DEQUEUE(&ifp->if_snd, m);
676 1.1 matt
677 1.1 matt /*
678 1.1 matt * The first four bytes of each transmit buffer are for
679 1.1 matt * control information. The first byte is the control
680 1.1 matt * byte, then the length (why not word aligned?), then
681 1.1 matt * the offset to the buffer.
682 1.1 matt */
683 1.1 matt
684 1.1 matt if (LEMAC_USE_PIO_MODE(sc)) {
685 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg); /* Shift 2K window. */
686 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
687 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
688 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
689 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 0) & 0xFF);
690 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 8) & 0xFF);
691 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
692 1.1 matt for (m0 = m; m0 != NULL; m0 = m0->m_next)
693 1.1 matt LEMAC_OUTSB(sc, LEMAC_REG_DAT, m0->m_len, m0->m_data);
694 1.1 matt } else {
695 1.1 matt bus_size_t txoff = /* (mtod(m, u_int32_t) & (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
696 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg); /* Shift 2K window. */
697 1.1 matt LEMAC_PUT8(sc, 0, sc->sc_txctl);
698 1.1 matt LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
699 1.1 matt LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
700 1.1 matt LEMAC_PUT8(sc, 3, txoff);
701 1.1 matt
702 1.1 matt /*
703 1.1 matt * Copy the packet to the board
704 1.1 matt */
705 1.1 matt for (m0 = m; m0 != NULL; m0 = m0->m_next) {
706 1.1 matt #if 0
707 1.1 matt LEMAC_PUTBUF8(sc, txoff, m0->m_len, m0->m_data);
708 1.1 matt txoff += m0->m_len;
709 1.1 matt #else
710 1.1 matt const u_int8_t *cp = m0->m_data;
711 1.1 matt int len = m0->m_len;
712 1.1 matt #if 0
713 1.1 matt if ((txoff & 3) == (((long)cp) & 3) && len >= 4) {
714 1.1 matt if (txoff & 3) {
715 1.1 matt int alen = (~txoff & 3);
716 1.1 matt LEMAC_PUTBUF8(sc, txoff, alen, cp);
717 1.1 matt cp += alen; txoff += alen; len -= alen;
718 1.1 matt }
719 1.1 matt if (len >= 4) {
720 1.28 christos LEMAC_PUTBUF32(sc, txoff, len / 4, cp);
721 1.1 matt cp += len & ~3; txoff += len & ~3; len &= 3;
722 1.1 matt }
723 1.1 matt }
724 1.1 matt #endif
725 1.1 matt if ((txoff & 1) == (((long)cp) & 1) && len >= 2) {
726 1.1 matt if (txoff & 1) {
727 1.1 matt int alen = (~txoff & 1);
728 1.1 matt LEMAC_PUTBUF8(sc, txoff, alen, cp);
729 1.1 matt cp += alen; txoff += alen; len -= alen;
730 1.1 matt }
731 1.1 matt if (len >= 2) {
732 1.1 matt LEMAC_PUTBUF16(sc, txoff, len / 2, (const void *) cp);
733 1.38 joerg cp += len & ~1; txoff += len & ~1; len &= 1;
734 1.1 matt }
735 1.1 matt }
736 1.1 matt if (len > 0) {
737 1.1 matt LEMAC_PUTBUF8(sc, txoff, len, cp);
738 1.1 matt txoff += len;
739 1.1 matt }
740 1.1 matt #endif
741 1.1 matt }
742 1.1 matt }
743 1.31 christos
744 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg); /* tell chip to transmit this packet */
745 1.1 matt bpf_mtap(&sc->sc_if, m);
746 1.1 matt m_freem(m); /* free the mbuf */
747 1.1 matt }
748 1.1 matt LEMAC_INTR_ENABLE(sc);
749 1.1 matt }
750 1.1 matt
751 1.1 matt static int
753 1.1 matt lemac_ifioctl(
754 1.1 matt struct ifnet *ifp,
755 1.1 matt u_long cmd,
756 1.1 matt void *data)
757 1.1 matt {
758 1.1 matt lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
759 1.1 matt int s;
760 1.1 matt int error = 0;
761 1.1 matt
762 1.1 matt s = splnet();
763 1.1 matt
764 1.1 matt switch (cmd) {
765 1.1 matt case SIOCINITIFADDR: {
766 1.1 matt struct ifaddr *ifa = (struct ifaddr *)data;
767 1.1 matt
768 1.1 matt ifp->if_flags |= IFF_UP;
769 1.1 matt lemac_init(sc);
770 1.1 matt switch (ifa->ifa_addr->sa_family) {
771 1.1 matt #ifdef INET
772 1.1 matt case AF_INET: {
773 1.1 matt arp_ifinit(&sc->sc_if, ifa);
774 1.36 dyoung break;
775 1.36 dyoung }
776 1.1 matt #endif /* INET */
777 1.1 matt
778 1.1 matt
779 1.1 matt default: {
780 1.1 matt break;
781 1.1 matt }
782 1.1 matt }
783 1.1 matt break;
784 1.1 matt }
785 1.33 dyoung
786 1.1 matt case SIOCSIFFLAGS: {
787 1.26 thorpej if ((error = ifioctl_common(ifp, cmd, data)) != 0)
788 1.26 thorpej break;
789 1.1 matt lemac_init(sc);
790 1.1 matt break;
791 1.1 matt }
792 1.1 matt
793 1.1 matt case SIOCADDMULTI:
794 1.1 matt case SIOCDELMULTI: {
795 1.1 matt /*
796 1.1 matt * Update multicast listeners
797 1.1 matt */
798 1.1 matt if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
799 1.1 matt /* reset multicast filtering */
800 1.1 matt if (ifp->if_flags & IFF_RUNNING)
801 1.1 matt lemac_init(sc);
802 1.36 dyoung error = 0;
803 1.1 matt }
804 1.1 matt break;
805 1.1 matt }
806 1.1 matt
807 1.1 matt case SIOCSIFMEDIA:
808 1.1 matt case SIOCGIFMEDIA: {
809 1.1 matt error = ifmedia_ioctl(ifp, (struct ifreq *)data,
810 1.1 matt &sc->sc_ifmedia, cmd);
811 1.1 matt break;
812 1.1 matt }
813 1.1 matt
814 1.1 matt default: {
815 1.1 matt error = ether_ioctl(ifp, cmd, data);
816 1.1 matt break;
817 1.1 matt }
818 1.1 matt }
819 1.1 matt
820 1.1 matt splx(s);
821 1.1 matt return error;
822 1.1 matt }
823 1.1 matt
824 1.1 matt static int
826 1.1 matt lemac_ifmedia_change(
827 1.1 matt struct ifnet * const ifp)
828 1.1 matt {
829 1.1 matt lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
830 1.1 matt unsigned new_ctl;
831 1.1 matt
832 1.1 matt switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
833 1.1 matt case IFM_10_T: new_ctl = LEMAC_CTL_APD; break;
834 1.1 matt case IFM_10_2:
835 1.1 matt case IFM_10_5: new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL; break;
836 1.1 matt case IFM_AUTO: new_ctl = 0; break;
837 1.1 matt default: return EINVAL;
838 1.1 matt }
839 1.1 matt if (sc->sc_ctlmode != new_ctl) {
840 1.1 matt sc->sc_ctlmode = new_ctl;
841 1.1 matt lemac_reset(sc);
842 1.1 matt if (sc->sc_if.if_flags & IFF_UP)
843 1.1 matt lemac_init(sc);
844 1.1 matt }
845 1.1 matt return 0;
846 1.1 matt }
847 1.1 matt
848 1.1 matt /*
849 1.1 matt * Media status callback
850 1.1 matt */
851 1.1 matt static void
852 1.1 matt lemac_ifmedia_status(
853 1.1 matt struct ifnet * const ifp,
854 1.1 matt struct ifmediareq *req)
855 1.1 matt {
856 1.1 matt lemac_softc_t *sc = LEMAC_IFP_TO_SOFTC(ifp);
857 1.1 matt unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
858 1.1 matt
859 1.1 matt req->ifm_status = IFM_AVALID;
860 1.1 matt if (sc->sc_flags & LEMAC_LINKUP)
861 1.1 matt req->ifm_status |= IFM_ACTIVE;
862 1.1 matt
863 1.1 matt if (sc->sc_ctlmode & LEMAC_CTL_APD) {
864 1.1 matt if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
865 1.1 matt req->ifm_active = IFM_10_5;
866 1.1 matt } else {
867 1.1 matt req->ifm_active = IFM_10_T;
868 1.1 matt }
869 1.1 matt } else {
870 1.1 matt /*
871 1.1 matt * The link bit of the configuration register reflects the
872 1.1 matt * current media choice when auto-port is enabled.
873 1.1 matt */
874 1.1 matt if (data & LEMAC_CNF_NOLINK) {
875 1.1 matt req->ifm_active = IFM_10_5;
876 1.1 matt } else {
877 1.1 matt req->ifm_active = IFM_10_T;
878 1.1 matt }
879 1.1 matt }
880 1.1 matt
881 1.1 matt req->ifm_active |= IFM_ETHER;
882 1.1 matt }
883 1.1 matt
884 1.1 matt int
886 1.1 matt lemac_port_check(
887 1.1 matt const bus_space_tag_t iot,
888 1.1 matt const bus_space_handle_t ioh)
889 1.1 matt {
890 1.1 matt unsigned char hwaddr[6];
891 1.1 matt
892 1.1 matt if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
893 1.1 matt return 1;
894 1.1 matt if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
895 1.1 matt return 1;
896 1.1 matt return 0;
897 1.1 matt }
898 1.1 matt
899 1.1 matt void
901 1.1 matt lemac_info_get(
902 1.1 matt const bus_space_tag_t iot,
903 1.1 matt const bus_space_handle_t ioh,
904 1.1 matt bus_addr_t *maddr_p,
905 1.1 matt bus_size_t *msize_p,
906 1.1 matt int *irq_p)
907 1.1 matt {
908 1.1 matt unsigned data;
909 1.1 matt
910 1.1 matt *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) & LEMAC_IC_IRQMSK);
911 1.1 matt
912 1.1 matt data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
913 1.1 matt if (LEMAC_IS_2K_MODE(data)) {
914 1.1 matt *maddr_p = data * (2 * 1024) + (512 * 1024);
915 1.1 matt *msize_p = 2 * 1024;
916 1.1 matt } else if (LEMAC_IS_64K_MODE(data)) {
917 1.1 matt *maddr_p = data * 64 * 1024;
918 1.1 matt *msize_p = 64 * 1024;
919 1.1 matt } else if (LEMAC_IS_32K_MODE(data)) {
920 1.1 matt *maddr_p = data * 32 * 1024;
921 1.1 matt *msize_p = 32* 1024;
922 1.1 matt } else {
923 1.1 matt *maddr_p = 0;
924 1.1 matt *msize_p = 0;
925 1.1 matt }
926 1.1 matt }
927 1.1 matt
928 1.1 matt /*
930 1.1 matt * What to do upon receipt of an interrupt.
931 1.1 matt */
932 1.1 matt int
933 1.1 matt lemac_intr(
934 1.1 matt void *arg)
935 1.1 matt {
936 1.1 matt lemac_softc_t * const sc = arg;
937 1.1 matt int cs_value;
938 1.1 matt
939 1.1 matt LEMAC_INTR_DISABLE(sc); /* Mask interrupts */
940 1.1 matt
941 1.1 matt /*
942 1.1 matt * Determine cause of interrupt. Receive events take
943 1.1 matt * priority over Transmit.
944 1.1 matt */
945 1.1 matt
946 1.1 matt cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
947 1.1 matt
948 1.1 matt /*
949 1.1 matt * Check for Receive Queue not being empty.
950 1.1 matt * Check for Transmit Done Queue not being empty.
951 1.1 matt */
952 1.1 matt
953 1.1 matt if (cs_value & LEMAC_CS_RNE)
954 1.1 matt lemac_rne_intr(sc);
955 1.1 matt if (cs_value & LEMAC_CS_TNE)
956 1.1 matt lemac_tne_intr(sc);
957 1.1 matt
958 1.1 matt /*
959 1.2 explorer * Check for Transmitter Disabled.
960 1.2 explorer * Check for Receiver Disabled.
961 1.2 explorer */
962 1.2 explorer
963 1.2 explorer if (cs_value & LEMAC_CS_TXD)
964 1.2 explorer lemac_txd_intr(sc, cs_value);
965 1.1 matt if (cs_value & LEMAC_CS_RXD)
966 1.1 matt lemac_rxd_intr(sc, cs_value);
967 1.1 matt
968 1.1 matt /*
969 1.1 matt * Toggle LED and unmask interrupts.
970 1.1 matt */
971 1.1 matt
972 1.1 matt sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
973 1.1 matt
974 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
975 1.1 matt LEMAC_INTR_ENABLE(sc); /* Unmask interrupts */
976 1.1 matt
977 1.1 matt #if NRND > 0
978 1.1 matt if (cs_value)
979 1.1 matt rnd_add_uint32(&sc->rnd_source, cs_value);
980 1.1 matt #endif
981 1.1 matt
982 1.1 matt return 1;
983 1.1 matt }
984 1.1 matt
985 1.1 matt void
986 1.1 matt lemac_shutdown(
987 1.1 matt void *arg)
988 1.35 cegger {
989 1.1 matt lemac_reset((lemac_softc_t *) arg);
990 1.1 matt }
991 1.1 matt
992 1.1 matt static const char * const lemac_modes[4] = {
994 1.27 perry "PIO mode (internal 2KB window)",
995 1.1 matt "2KB window",
996 1.1 matt "changed 32KB window to 2KB",
997 1.1 matt "changed 64KB window to 2KB",
998 1.1 matt };
999 1.1 matt
1000 1.1 matt void
1001 1.1 matt lemac_ifattach(
1002 1.1 matt lemac_softc_t *sc)
1003 1.1 matt {
1004 1.1 matt struct ifnet * const ifp = &sc->sc_if;
1005 1.1 matt
1006 1.1 matt strlcpy(ifp->if_xname, device_xname(&sc->sc_dv), IFNAMSIZ);
1007 1.1 matt
1008 1.1 matt lemac_reset(sc);
1009 1.1 matt
1010 1.1 matt (void) lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh,
1011 1.1 matt LEMAC_REG_APD, 0);
1012 1.1 matt
1013 1.1 matt printf(": %s\n", sc->sc_prodname);
1014 1.1 matt
1015 1.18 thorpej printf("%s: address %s, %dKB RAM, %s\n",
1016 1.18 thorpej ifp->if_xname,
1017 1.1 matt ether_sprintf(sc->sc_enaddr),
1018 1.1 matt sc->sc_lastpage * 2 + 2,
1019 1.1 matt lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
1020 1.2 explorer
1021 1.2 explorer ifp->if_softc = (void *) sc;
1022 1.35 cegger ifp->if_start = lemac_ifstart;
1023 1.11 explorer ifp->if_ioctl = lemac_ifioctl;
1024 1.2 explorer
1025 1.2 explorer ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
1026 1.1 matt #ifdef IFF_NOTRAILERS
1027 1.1 matt | IFF_NOTRAILERS
1028 1.1 matt #endif
1029 1.1 matt | IFF_MULTICAST;
1030 1.1 matt
1031 1.1 matt if (sc->sc_flags & LEMAC_ALIVE) {
1032 1.1 matt int media;
1033 1.1 matt
1034 1.1 matt IFQ_SET_READY(&ifp->if_snd);
1035 1.1 matt
1036 1.1 matt if_attach(ifp);
1037 1.1 matt ether_ifattach(ifp, sc->sc_enaddr);
1038 1.1 matt
1039 1.1 matt #if NRND > 0
1040 1.1 matt rnd_attach_source(&sc->rnd_source, device_xname(&sc->sc_dv),
1041 1.1 matt RND_TYPE_NET, 0);
1042 1.1 matt #endif
1043 1.1 matt
1044 1.1 matt ifmedia_init(&sc->sc_ifmedia, 0,
1045 lemac_ifmedia_change,
1046 lemac_ifmedia_status);
1047 if (sc->sc_prodname[4] == '5') /* DE205 is UTP/AUI */
1048 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
1049 if (sc->sc_prodname[4] != '3') /* DE204 & 205 have UTP */
1050 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
1051 if (sc->sc_prodname[4] != '4') /* DE203 & 205 have BNC */
1052 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
1053 switch (sc->sc_prodname[4]) {
1054 case '3': media = IFM_10_5; break;
1055 case '4': media = IFM_10_T; break;
1056 default: media = IFM_AUTO; break;
1057 }
1058 ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
1059 } else {
1060 printf("%s: disabled due to error\n", ifp->if_xname);
1061 }
1062 }
1063