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