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