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