lemac.c revision 1.51 1 1.51 msaitoh /* $NetBSD: lemac.c,v 1.51 2019/04/24 08:03:07 msaitoh 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.51 msaitoh __KERNEL_RCSID(0, "$NetBSD: lemac.c,v 1.51 2019/04/24 08:03:07 msaitoh 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.24 itojun static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_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.51 msaitoh while (txcount-- > 0) {
155 1.51 msaitoh unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
156 1.51 msaitoh 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.51 msaitoh if (txsts & LEMAC_TDQ_NCL)
160 1.51 msaitoh sc->sc_flags &= ~LEMAC_LINKUP;
161 1.51 msaitoh sc->sc_if.if_oerrors++;
162 1.51 msaitoh } else {
163 1.51 msaitoh sc->sc_flags |= LEMAC_LINKUP;
164 1.51 msaitoh if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
165 1.51 msaitoh 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.51 msaitoh sc->sc_cntrs.cntr_txd_intrs++;
183 1.51 msaitoh if (sc->sc_txctl & LEMAC_TX_STP) {
184 1.51 msaitoh 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.51 msaitoh {
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 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.51 msaitoh 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 sc->sc_if.if_ierrors++;
271 1.51 msaitoh return;
272 1.51 msaitoh }
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 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.51 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 u_int32_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.51 msaitoh 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 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.51 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 u_int16_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.51 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.51 msaitoh {
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.51 msaitoh
452 1.51 msaitoh lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE);
453 1.51 msaitoh
454 1.51 msaitoh ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
455 1.51 msaitoh while (enm != NULL) {
456 1.51 msaitoh if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
457 1.1 matt sc->sc_flags |= LEMAC_ALLMULTI;
458 1.1 matt sc->sc_if.if_flags |= IFF_ALLMULTI;
459 1.27 perry return;
460 1.1 matt }
461 1.1 matt lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
462 1.1 matt ETHER_NEXT_MULTI(step, enm);
463 1.51 msaitoh }
464 1.1 matt sc->sc_flags &= ~LEMAC_ALLMULTI;
465 1.51 msaitoh sc->sc_if.if_flags &= ~IFF_ALLMULTI;
466 1.51 msaitoh }
467 1.51 msaitoh
468 1.51 msaitoh /*
470 1.51 msaitoh * Do a hard reset of the board;
471 1.51 msaitoh */
472 1.51 msaitoh static void
473 1.1 matt lemac_reset(lemac_softc_t * const sc)
474 1.51 msaitoh {
475 1.51 msaitoh unsigned data;
476 1.51 msaitoh
477 1.51 msaitoh /*
478 1.51 msaitoh * Initialize board..
479 1.51 msaitoh */
480 1.51 msaitoh sc->sc_flags &= ~LEMAC_LINKUP;
481 1.51 msaitoh sc->sc_if.if_flags &= ~IFF_OACTIVE;
482 1.51 msaitoh LEMAC_INTR_DISABLE(sc);
483 1.51 msaitoh
484 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
485 1.51 msaitoh DELAY(LEMAC_EEP_DELAY);
486 1.51 msaitoh
487 1.51 msaitoh /*
488 1.51 msaitoh * Read EEPROM information. NOTE - the placement of this function
489 1.51 msaitoh * is important because functions hereafter may rely on information
490 1.51 msaitoh * read from the EEPROM.
491 1.51 msaitoh */
492 1.51 msaitoh if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
493 1.51 msaitoh printf("%s: reset: EEPROM checksum failed (0x%x)\n",
494 1.51 msaitoh sc->sc_if.if_xname, data);
495 1.51 msaitoh return;
496 1.51 msaitoh }
497 1.51 msaitoh
498 1.51 msaitoh /* Update the control register to reflect the media choice */
499 1.51 msaitoh data = LEMAC_INB(sc, LEMAC_REG_CTL);
500 1.51 msaitoh if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
501 1.51 msaitoh data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
502 1.51 msaitoh data |= sc->sc_ctlmode;
503 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
504 1.51 msaitoh }
505 1.51 msaitoh
506 1.51 msaitoh /* Force to 2K mode if not already configured. */
507 1.51 msaitoh
508 1.51 msaitoh data = LEMAC_INB(sc, LEMAC_REG_MBR);
509 1.51 msaitoh if (LEMAC_IS_2K_MODE(data)) {
510 1.51 msaitoh sc->sc_flags |= LEMAC_2K_MODE;
511 1.51 msaitoh } else if (LEMAC_IS_64K_MODE(data)) {
512 1.51 msaitoh data = (((data * 2) & 0xF) << 4);
513 1.51 msaitoh sc->sc_flags |= LEMAC_WAS_64K_MODE;
514 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
515 1.1 matt } else if (LEMAC_IS_32K_MODE(data)) {
516 1.51 msaitoh data = ((data & 0xF) << 4);
517 1.51 msaitoh sc->sc_flags |= LEMAC_WAS_32K_MODE;
518 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
519 1.1 matt } else {
520 1.1 matt sc->sc_flags |= LEMAC_PIO_MODE;
521 1.51 msaitoh /* PIO mode */
522 1.1 matt }
523 1.51 msaitoh
524 1.51 msaitoh /* Initialize Free Memory Queue, Init mcast table with broadcast. */
525 1.51 msaitoh
526 1.51 msaitoh lemac_init_adapmem(sc);
527 1.51 msaitoh sc->sc_flags |= LEMAC_ALIVE;
528 1.51 msaitoh }
529 1.51 msaitoh
530 1.51 msaitoh static void
532 1.51 msaitoh lemac_init(lemac_softc_t * const sc)
533 1.51 msaitoh {
534 1.51 msaitoh if ((sc->sc_flags & LEMAC_ALIVE) == 0)
535 1.51 msaitoh return;
536 1.51 msaitoh
537 1.51 msaitoh /*
538 1.51 msaitoh * If the interface has the up flag
539 1.51 msaitoh */
540 1.51 msaitoh if (sc->sc_if.if_flags & IFF_UP) {
541 1.51 msaitoh int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
542 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_CS,
543 1.51 msaitoh saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
544 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_enaddr[0]);
545 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_enaddr[1]);
546 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_enaddr[2]);
547 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_enaddr[3]);
548 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_enaddr[4]);
549 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_enaddr[5]);
550 1.51 msaitoh
551 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_IC,
552 1.51 msaitoh LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
553 1.51 msaitoh
554 1.51 msaitoh if (sc->sc_if.if_flags & IFF_PROMISC) {
555 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_CS,
556 1.51 msaitoh LEMAC_CS_MCE | LEMAC_CS_PME);
557 1.51 msaitoh } else {
558 1.51 msaitoh LEMAC_INTR_DISABLE(sc);
559 1.51 msaitoh lemac_multicast_filter(sc);
560 1.51 msaitoh if (sc->sc_flags & LEMAC_ALLMULTI)
561 1.51 msaitoh memcpy(sc->sc_mctbl, lemac_allmulti_mctbl,
562 1.51 msaitoh sizeof(sc->sc_mctbl));
563 1.51 msaitoh if (LEMAC_USE_PIO_MODE(sc)) {
564 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
565 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PI1,
566 1.51 msaitoh LEMAC_MCTBL_OFF & 0xFF);
567 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_PI2,
568 1.51 msaitoh LEMAC_MCTBL_OFF >> 8);
569 1.51 msaitoh LEMAC_OUTSB(sc, LEMAC_REG_DAT,
570 1.1 matt sizeof(sc->sc_mctbl),
571 1.51 msaitoh (void *)sc->sc_mctbl);
572 1.51 msaitoh } else {
573 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
574 1.51 msaitoh LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF,
575 1.51 msaitoh sizeof(sc->sc_mctbl),
576 1.51 msaitoh (void *)sc->sc_mctbl);
577 1.1 matt }
578 1.51 msaitoh
579 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
580 1.51 msaitoh }
581 1.51 msaitoh
582 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CTL,
583 1.1 matt LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
584 1.1 matt
585 1.27 perry LEMAC_INTR_ENABLE(sc);
586 1.1 matt sc->sc_if.if_flags |= IFF_RUNNING;
587 1.51 msaitoh lemac_ifstart(&sc->sc_if);
588 1.1 matt } else {
589 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
590 1.1 matt
591 1.51 msaitoh LEMAC_INTR_DISABLE(sc);
592 1.51 msaitoh sc->sc_if.if_flags &= ~IFF_RUNNING;
593 1.1 matt }
594 1.51 msaitoh }
595 1.1 matt
596 1.51 msaitoh static void
598 1.51 msaitoh lemac_ifstart(
599 1.51 msaitoh struct ifnet *ifp)
600 1.51 msaitoh {
601 1.51 msaitoh lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
602 1.51 msaitoh
603 1.51 msaitoh if ((ifp->if_flags & IFF_RUNNING) == 0)
604 1.51 msaitoh return;
605 1.51 msaitoh
606 1.51 msaitoh LEMAC_INTR_DISABLE(sc);
607 1.51 msaitoh
608 1.51 msaitoh for (;;) {
609 1.51 msaitoh struct mbuf *m;
610 1.51 msaitoh struct mbuf *m0;
611 1.1 matt int tx_pg;
612 1.51 msaitoh
613 1.51 msaitoh IFQ_POLL(&ifp->if_snd, m);
614 1.1 matt if (m == NULL)
615 1.51 msaitoh break;
616 1.51 msaitoh
617 1.51 msaitoh if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC))
618 1.51 msaitoh >= lemac_txmax) {
619 1.51 msaitoh sc->sc_cntrs.cntr_txfull++;
620 1.51 msaitoh ifp->if_flags |= IFF_OACTIVE;
621 1.1 matt break;
622 1.51 msaitoh }
623 1.1 matt
624 1.51 msaitoh /* Get free memory page */
625 1.51 msaitoh tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
626 1.51 msaitoh
627 1.51 msaitoh /* Check for good transmit page. */
628 1.51 msaitoh if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
629 1.51 msaitoh sc->sc_cntrs.cntr_txnospc++;
630 1.51 msaitoh ifp->if_flags |= IFF_OACTIVE;
631 1.51 msaitoh break;
632 1.51 msaitoh }
633 1.51 msaitoh
634 1.51 msaitoh IFQ_DEQUEUE(&ifp->if_snd, m);
635 1.51 msaitoh
636 1.51 msaitoh /*
637 1.51 msaitoh * The first four bytes of each transmit buffer are for
638 1.51 msaitoh * control information. The first byte is the control
639 1.51 msaitoh * byte, then the length (why not word aligned?), then
640 1.51 msaitoh * the offset to the buffer.
641 1.51 msaitoh */
642 1.51 msaitoh
643 1.51 msaitoh if (LEMAC_USE_PIO_MODE(sc)) {
644 1.51 msaitoh /* Shift 2K window. */
645 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg);
646 1.51 msaitoh
647 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
648 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
649 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
650 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_DAT,
651 1.51 msaitoh (m->m_pkthdr.len >> 0) & 0xFF);
652 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_DAT,
653 1.51 msaitoh (m->m_pkthdr.len >> 8) & 0xFF);
654 1.51 msaitoh LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
655 1.51 msaitoh for (m0 = m; m0 != NULL; m0 = m0->m_next)
656 1.1 matt LEMAC_OUTSB(sc, LEMAC_REG_DAT,
657 1.51 msaitoh m0->m_len, m0->m_data);
658 1.51 msaitoh } else {
659 1.1 matt bus_size_t txoff = /* (mtod(m, u_int32_t) & (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
660 1.51 msaitoh
661 1.51 msaitoh /* Shift 2K window. */
662 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg);
663 1.51 msaitoh
664 1.51 msaitoh LEMAC_PUT8(sc, 0, sc->sc_txctl);
665 1.1 matt LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
666 1.51 msaitoh LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
667 1.51 msaitoh LEMAC_PUT8(sc, 3, txoff);
668 1.51 msaitoh
669 1.51 msaitoh /* Copy the packet to the board */
670 1.51 msaitoh for (m0 = m; m0 != NULL; m0 = m0->m_next) {
671 1.51 msaitoh #if 0
672 1.51 msaitoh LEMAC_PUTBUF8(sc, txoff, m0->m_len, m0->m_data);
673 1.51 msaitoh txoff += m0->m_len;
674 1.51 msaitoh #else
675 1.51 msaitoh const u_int8_t *cp = m0->m_data;
676 1.51 msaitoh int len = m0->m_len;
677 1.51 msaitoh #if 0
678 1.51 msaitoh if ((txoff & 3) == (((long)cp) & 3)
679 1.51 msaitoh && len >= 4) {
680 1.51 msaitoh if (txoff & 3) {
681 1.51 msaitoh int alen = (~txoff & 3);
682 1.51 msaitoh LEMAC_PUTBUF8(sc, txoff, alen,
683 1.51 msaitoh cp);
684 1.51 msaitoh cp += alen;
685 1.51 msaitoh txoff += alen;
686 1.51 msaitoh len -= alen;
687 1.51 msaitoh }
688 1.51 msaitoh if (len >= 4) {
689 1.51 msaitoh LEMAC_PUTBUF32(sc, txoff,
690 1.51 msaitoh len / 4, cp);
691 1.51 msaitoh cp += len & ~3;
692 1.51 msaitoh txoff += len & ~3;
693 1.51 msaitoh len &= 3;
694 1.51 msaitoh }
695 1.51 msaitoh }
696 1.51 msaitoh #endif
697 1.51 msaitoh if ((txoff & 1) == (((long)cp) & 1)
698 1.51 msaitoh && len >= 2) {
699 1.51 msaitoh if (txoff & 1) {
700 1.51 msaitoh int alen = (~txoff & 1);
701 1.51 msaitoh LEMAC_PUTBUF8(sc, txoff, alen,
702 1.51 msaitoh cp);
703 1.51 msaitoh cp += alen;
704 1.51 msaitoh txoff += alen;
705 1.51 msaitoh len -= alen;
706 1.51 msaitoh }
707 1.1 matt if (len >= 2) {
708 1.51 msaitoh LEMAC_PUTBUF16(sc, txoff,
709 1.1 matt len / 2, (const void *)cp);
710 1.51 msaitoh cp += len & ~1;
711 1.51 msaitoh txoff += len & ~1;
712 1.51 msaitoh len &= 1;
713 1.51 msaitoh }
714 1.51 msaitoh }
715 1.1 matt if (len > 0) {
716 1.51 msaitoh LEMAC_PUTBUF8(sc, txoff, len, cp);
717 1.1 matt txoff += len;
718 1.1 matt }
719 1.1 matt #endif
720 1.1 matt }
721 1.51 msaitoh }
722 1.51 msaitoh
723 1.51 msaitoh /* Tell chip to transmit this packet */
724 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg);
725 1.51 msaitoh bpf_mtap(&sc->sc_if, m, BPF_D_OUT);
726 1.51 msaitoh m_freem(m); /* Free the mbuf */
727 1.51 msaitoh }
728 1.1 matt LEMAC_INTR_ENABLE(sc);
729 1.51 msaitoh }
730 1.1 matt
731 1.51 msaitoh static int
733 1.51 msaitoh lemac_ifioctl(
734 1.1 matt struct ifnet *ifp,
735 1.51 msaitoh u_long cmd,
736 1.51 msaitoh void *data)
737 1.51 msaitoh {
738 1.1 matt lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
739 1.51 msaitoh int s;
740 1.51 msaitoh int error = 0;
741 1.51 msaitoh
742 1.1 matt s = splnet();
743 1.1 matt
744 1.1 matt switch (cmd) {
745 1.51 msaitoh case SIOCINITIFADDR: {
746 1.51 msaitoh struct ifaddr *ifa = (struct ifaddr *)data;
747 1.1 matt
748 1.51 msaitoh ifp->if_flags |= IFF_UP;
749 1.1 matt lemac_init(sc);
750 1.1 matt switch (ifa->ifa_addr->sa_family) {
751 1.51 msaitoh #ifdef INET
752 1.51 msaitoh case AF_INET:
753 1.51 msaitoh arp_ifinit(&sc->sc_if, ifa);
754 1.51 msaitoh break;
755 1.36 dyoung #endif /* INET */
756 1.1 matt
757 1.1 matt
758 1.51 msaitoh default:
759 1.51 msaitoh break;
760 1.51 msaitoh }
761 1.51 msaitoh break;
762 1.51 msaitoh }
763 1.51 msaitoh
764 1.51 msaitoh case SIOCSIFFLAGS:
765 1.51 msaitoh if ((error = ifioctl_common(ifp, cmd, data)) != 0)
766 1.51 msaitoh break;
767 1.51 msaitoh lemac_init(sc);
768 1.51 msaitoh break;
769 1.1 matt
770 1.1 matt case SIOCADDMULTI:
771 1.51 msaitoh case SIOCDELMULTI:
772 1.51 msaitoh /*
773 1.51 msaitoh * Update multicast listeners
774 1.51 msaitoh */
775 1.1 matt if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
776 1.51 msaitoh /* reset multicast filtering */
777 1.51 msaitoh if (ifp->if_flags & IFF_RUNNING)
778 1.51 msaitoh lemac_init(sc);
779 1.1 matt error = 0;
780 1.1 matt }
781 1.51 msaitoh break;
782 1.51 msaitoh
783 1.1 matt case SIOCSIFMEDIA:
784 1.1 matt case SIOCGIFMEDIA:
785 1.1 matt error = ifmedia_ioctl(ifp, (struct ifreq *)data,
786 1.51 msaitoh &sc->sc_ifmedia, cmd);
787 1.1 matt break;
788 1.51 msaitoh
789 1.51 msaitoh default:
790 1.1 matt error = ether_ioctl(ifp, cmd, data);
791 1.51 msaitoh break;
792 1.1 matt }
793 1.1 matt
794 1.1 matt splx(s);
795 1.1 matt return error;
796 1.1 matt }
797 1.51 msaitoh
798 1.51 msaitoh static int
800 1.51 msaitoh lemac_ifmedia_change(struct ifnet * const ifp)
801 1.51 msaitoh {
802 1.51 msaitoh lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
803 1.51 msaitoh unsigned new_ctl;
804 1.51 msaitoh
805 1.1 matt switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
806 1.1 matt case IFM_10_T: new_ctl = LEMAC_CTL_APD; break;
807 1.1 matt case IFM_10_2:
808 1.1 matt case IFM_10_5: new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL; break;
809 1.1 matt case IFM_AUTO: new_ctl = 0; break;
810 1.1 matt default: return EINVAL;
811 1.51 msaitoh }
812 1.51 msaitoh if (sc->sc_ctlmode != new_ctl) {
813 1.51 msaitoh sc->sc_ctlmode = new_ctl;
814 1.51 msaitoh lemac_reset(sc);
815 1.51 msaitoh if (sc->sc_if.if_flags & IFF_UP)
816 1.51 msaitoh lemac_init(sc);
817 1.51 msaitoh }
818 1.51 msaitoh return 0;
819 1.51 msaitoh }
820 1.51 msaitoh
821 1.51 msaitoh /*
822 1.51 msaitoh * Media status callback
823 1.51 msaitoh */
824 1.51 msaitoh static void
825 1.1 matt lemac_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req)
826 1.51 msaitoh {
827 1.51 msaitoh lemac_softc_t *sc = LEMAC_IFP_TO_SOFTC(ifp);
828 1.51 msaitoh unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
829 1.51 msaitoh
830 1.51 msaitoh req->ifm_status = IFM_AVALID;
831 1.51 msaitoh if (sc->sc_flags & LEMAC_LINKUP)
832 1.51 msaitoh req->ifm_status |= IFM_ACTIVE;
833 1.51 msaitoh
834 1.1 matt if (sc->sc_ctlmode & LEMAC_CTL_APD) {
835 1.1 matt if (sc->sc_ctlmode & LEMAC_CTL_PSL)
836 1.51 msaitoh req->ifm_active = IFM_10_5;
837 1.1 matt else
838 1.1 matt req->ifm_active = IFM_10_T;
839 1.1 matt } else {
840 1.51 msaitoh /*
841 1.1 matt * The link bit of the configuration register reflects the
842 1.51 msaitoh * current media choice when auto-port is enabled.
843 1.1 matt */
844 1.51 msaitoh if (data & LEMAC_CNF_NOLINK)
845 1.51 msaitoh req->ifm_active = IFM_10_5;
846 1.51 msaitoh else
847 1.51 msaitoh req->ifm_active = IFM_10_T;
848 1.51 msaitoh }
849 1.1 matt
850 1.1 matt req->ifm_active |= IFM_ETHER;
851 1.1 matt }
852 1.51 msaitoh
853 1.51 msaitoh int
855 1.51 msaitoh lemac_port_check(const bus_space_tag_t iot, const bus_space_handle_t ioh)
856 1.51 msaitoh {
857 1.51 msaitoh unsigned char hwaddr[6];
858 1.51 msaitoh
859 1.51 msaitoh if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
860 1.51 msaitoh return 1;
861 1.51 msaitoh if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
862 1.51 msaitoh return 1;
863 1.51 msaitoh return 0;
864 1.51 msaitoh }
865 1.51 msaitoh
866 1.51 msaitoh void
868 1.51 msaitoh lemac_info_get(const bus_space_tag_t iot, const bus_space_handle_t ioh,
869 1.51 msaitoh bus_addr_t *maddr_p, bus_size_t *msize_p, int *irq_p)
870 1.51 msaitoh {
871 1.51 msaitoh unsigned data;
872 1.51 msaitoh
873 1.51 msaitoh *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC)
874 1.1 matt & LEMAC_IC_IRQMSK);
875 1.1 matt
876 1.1 matt data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
877 1.1 matt if (LEMAC_IS_2K_MODE(data)) {
878 1.1 matt *maddr_p = data * (2 * 1024) + (512 * 1024);
879 1.1 matt *msize_p = 2 * 1024;
880 1.51 msaitoh } else if (LEMAC_IS_64K_MODE(data)) {
881 1.1 matt *maddr_p = data * 64 * 1024;
882 1.51 msaitoh *msize_p = 64 * 1024;
883 1.51 msaitoh } else if (LEMAC_IS_32K_MODE(data)) {
884 1.1 matt *maddr_p = data * 32 * 1024;
885 1.51 msaitoh *msize_p = 32* 1024;
886 1.1 matt } else {
887 1.51 msaitoh *maddr_p = 0;
888 1.51 msaitoh *msize_p = 0;
889 1.51 msaitoh }
890 1.51 msaitoh }
891 1.1 matt
892 1.51 msaitoh /*
894 1.51 msaitoh * What to do upon receipt of an interrupt.
895 1.51 msaitoh */
896 1.51 msaitoh int
897 1.51 msaitoh lemac_intr(void *arg)
898 1.1 matt {
899 1.51 msaitoh lemac_softc_t * const sc = arg;
900 1.51 msaitoh int cs_value;
901 1.51 msaitoh
902 1.51 msaitoh LEMAC_INTR_DISABLE(sc); /* Mask interrupts */
903 1.1 matt
904 1.51 msaitoh /*
905 1.51 msaitoh * Determine cause of interrupt. Receive events take
906 1.51 msaitoh * priority over Transmit.
907 1.51 msaitoh */
908 1.1 matt
909 1.51 msaitoh cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
910 1.51 msaitoh
911 1.51 msaitoh /*
912 1.51 msaitoh * Check for Receive Queue not being empty.
913 1.1 matt * Check for Transmit Done Queue not being empty.
914 1.51 msaitoh */
915 1.1 matt
916 1.51 msaitoh if (cs_value & LEMAC_CS_RNE)
917 1.1 matt lemac_rne_intr(sc);
918 1.51 msaitoh if (cs_value & LEMAC_CS_TNE)
919 1.51 msaitoh lemac_tne_intr(sc);
920 1.51 msaitoh
921 1.2 explorer /*
922 1.51 msaitoh * Check for Transmitter Disabled.
923 1.51 msaitoh * Check for Receiver Disabled.
924 1.2 explorer */
925 1.51 msaitoh
926 1.1 matt if (cs_value & LEMAC_CS_TXD)
927 1.1 matt lemac_txd_intr(sc, cs_value);
928 1.1 matt if (cs_value & LEMAC_CS_RXD)
929 1.51 msaitoh lemac_rxd_intr(sc, cs_value);
930 1.1 matt
931 1.51 msaitoh /* Toggle LED and unmask interrupts. */
932 1.51 msaitoh
933 1.1 matt sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
934 1.1 matt
935 1.1 matt LEMAC_OUTB(sc, LEMAC_REG_CTL,
936 1.51 msaitoh LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
937 1.51 msaitoh LEMAC_INTR_ENABLE(sc); /* Unmask interrupts */
938 1.51 msaitoh
939 1.51 msaitoh if (cs_value)
940 1.1 matt rnd_add_uint32(&sc->rnd_source, cs_value);
941 1.1 matt
942 1.1 matt return 1;
943 1.51 msaitoh }
944 1.1 matt
945 1.51 msaitoh void
946 1.1 matt lemac_shutdown(void *arg)
947 1.51 msaitoh {
948 1.1 matt
949 1.51 msaitoh lemac_reset((lemac_softc_t *) arg);
950 1.51 msaitoh }
951 1.51 msaitoh
952 1.51 msaitoh static const char * const lemac_modes[4] = {
954 1.51 msaitoh "PIO mode (internal 2KB window)",
955 1.51 msaitoh "2KB window",
956 1.51 msaitoh "changed 32KB window to 2KB",
957 1.51 msaitoh "changed 64KB window to 2KB",
958 1.51 msaitoh };
959 1.51 msaitoh
960 1.51 msaitoh void
961 1.51 msaitoh lemac_ifattach(lemac_softc_t *sc)
962 1.51 msaitoh {
963 1.51 msaitoh struct ifnet * const ifp = &sc->sc_if;
964 1.51 msaitoh
965 1.51 msaitoh strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
966 1.51 msaitoh
967 1.51 msaitoh lemac_reset(sc);
968 1.51 msaitoh
969 1.51 msaitoh (void)lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh,
970 1.51 msaitoh LEMAC_REG_APD, 0);
971 1.51 msaitoh
972 1.51 msaitoh printf(": %s\n", sc->sc_prodname);
973 1.51 msaitoh
974 1.51 msaitoh printf("%s: address %s, %dKB RAM, %s\n",
975 1.51 msaitoh ifp->if_xname,
976 1.51 msaitoh ether_sprintf(sc->sc_enaddr),
977 1.51 msaitoh sc->sc_lastpage * 2 + 2,
978 1.51 msaitoh lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
979 1.51 msaitoh
980 1.51 msaitoh ifp->if_softc = (void *)sc;
981 1.51 msaitoh ifp->if_start = lemac_ifstart;
982 1.51 msaitoh ifp->if_ioctl = lemac_ifioctl;
983 1.51 msaitoh
984 1.51 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
985 1.51 msaitoh
986 1.51 msaitoh if (sc->sc_flags & LEMAC_ALIVE) {
987 1.51 msaitoh int media;
988 1.51 msaitoh
989 1.51 msaitoh IFQ_SET_READY(&ifp->if_snd);
990 1.51 msaitoh
991 1.51 msaitoh if_attach(ifp);
992 1.51 msaitoh if_deferred_start_init(ifp, NULL);
993 1.51 msaitoh ether_ifattach(ifp, sc->sc_enaddr);
994 1.51 msaitoh
995 1.51 msaitoh rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
996 1.51 msaitoh RND_TYPE_NET, RND_FLAG_DEFAULT);
997 1.51 msaitoh
998 1.51 msaitoh ifmedia_init(&sc->sc_ifmedia, 0,
999 1.51 msaitoh lemac_ifmedia_change,
1000 1.1 matt lemac_ifmedia_status);
1001 if (sc->sc_prodname[4] == '5') /* DE205 is UTP/AUI */
1002 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO,
1003 0, 0);
1004 if (sc->sc_prodname[4] != '3') /* DE204 & 205 have UTP */
1005 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T,
1006 0, 0);
1007 if (sc->sc_prodname[4] != '4') /* DE203 & 205 have BNC */
1008 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5,
1009 0, 0);
1010 switch (sc->sc_prodname[4]) {
1011 case '3': media = IFM_10_5; break;
1012 case '4': media = IFM_10_T; break;
1013 default: media = IFM_AUTO; break;
1014 }
1015 ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
1016 } else
1017 printf("%s: disabled due to error\n", ifp->if_xname);
1018 }
1019