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