1 1.102 thorpej /* $NetBSD: if_el.c,v 1.102 2022/09/17 17:15:02 thorpej Exp $ */ 2 1.14 cgd 3 1.2 cgd /* 4 1.2 cgd * Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted 5 1.1 hpeyerl * to use, copy, modify and distribute this software provided that both 6 1.1 hpeyerl * the copyright notice and this permission notice appear in all copies 7 1.1 hpeyerl * of the software, derivative works or modified versions, and any 8 1.1 hpeyerl * portions thereof. 9 1.1 hpeyerl */ 10 1.2 cgd 11 1.2 cgd /* 12 1.2 cgd * 3COM Etherlink 3C501 device driver 13 1.1 hpeyerl */ 14 1.2 cgd 15 1.2 cgd /* 16 1.2 cgd * Bugs/possible improvements: 17 1.1 hpeyerl * - Does not currently support DMA 18 1.1 hpeyerl * - Does not currently support multicasts 19 1.1 hpeyerl */ 20 1.65 lukem 21 1.65 lukem #include <sys/cdefs.h> 22 1.102 thorpej __KERNEL_RCSID(0, "$NetBSD: if_el.c,v 1.102 2022/09/17 17:15:02 thorpej Exp $"); 23 1.2 cgd 24 1.53 jonathan #include "opt_inet.h" 25 1.1 hpeyerl 26 1.1 hpeyerl #include <sys/param.h> 27 1.37 christos #include <sys/systm.h> 28 1.1 hpeyerl #include <sys/errno.h> 29 1.1 hpeyerl #include <sys/ioctl.h> 30 1.1 hpeyerl #include <sys/mbuf.h> 31 1.1 hpeyerl #include <sys/socket.h> 32 1.1 hpeyerl #include <sys/syslog.h> 33 1.3 mycroft #include <sys/device.h> 34 1.91 riastrad #include <sys/rndsource.h> 35 1.1 hpeyerl 36 1.1 hpeyerl #include <net/if.h> 37 1.1 hpeyerl #include <net/if_dl.h> 38 1.1 hpeyerl #include <net/if_types.h> 39 1.95 msaitoh #include <net/bpf.h> 40 1.1 hpeyerl 41 1.44 is #include <net/if_ether.h> 42 1.44 is 43 1.1 hpeyerl #ifdef INET 44 1.1 hpeyerl #include <netinet/in.h> 45 1.1 hpeyerl #include <netinet/in_systm.h> 46 1.1 hpeyerl #include <netinet/in_var.h> 47 1.1 hpeyerl #include <netinet/ip.h> 48 1.44 is #include <netinet/if_inarp.h> 49 1.1 hpeyerl #endif 50 1.1 hpeyerl 51 1.79 ad #include <sys/cpu.h> 52 1.79 ad #include <sys/intr.h> 53 1.79 ad #include <sys/bus.h> 54 1.1 hpeyerl 55 1.23 cgd #include <dev/isa/isavar.h> 56 1.21 cgd #include <dev/isa/if_elreg.h> 57 1.1 hpeyerl 58 1.3 mycroft /* for debugging convenience */ 59 1.1 hpeyerl #ifdef EL_DEBUG 60 1.42 christos #define DPRINTF(x) printf x 61 1.1 hpeyerl #else 62 1.41 christos #define DPRINTF(x) 63 1.1 hpeyerl #endif 64 1.1 hpeyerl 65 1.2 cgd /* 66 1.3 mycroft * per-line info and status 67 1.2 cgd */ 68 1.1 hpeyerl struct el_softc { 69 1.89 chs device_t sc_dev; 70 1.23 cgd void *sc_ih; 71 1.3 mycroft 72 1.44 is struct ethercom sc_ethercom; /* ethernet common */ 73 1.43 thorpej bus_space_tag_t sc_iot; /* bus space identifier */ 74 1.43 thorpej bus_space_handle_t sc_ioh; /* i/o handle */ 75 1.102 thorpej bool sc_txbusy; /* transmitter is busy */ 76 1.49 explorer 77 1.87 tls krndsource_t rnd_source; 78 1.8 mycroft }; 79 1.1 hpeyerl 80 1.2 cgd /* 81 1.3 mycroft * prototypes 82 1.2 cgd */ 83 1.100 thorpej static int elintr(void *); 84 1.100 thorpej static void elinit(struct el_softc *); 85 1.100 thorpej static int elioctl(struct ifnet *, u_long, void *); 86 1.100 thorpej static void elstart(struct ifnet *); 87 1.100 thorpej static void elwatchdog(struct ifnet *); 88 1.100 thorpej static void elreset(struct el_softc *); 89 1.100 thorpej static void elstop(struct el_softc *); 90 1.100 thorpej static int el_xmit(struct el_softc *); 91 1.100 thorpej static void elread(struct el_softc *, int); 92 1.100 thorpej static struct mbuf *elget(struct el_softc *sc, int); 93 1.72 perry static inline void el_hardreset(struct el_softc *); 94 1.1 hpeyerl 95 1.100 thorpej static int elprobe(device_t, cfdata_t, void *); 96 1.100 thorpej static void elattach(device_t, device_t, void *); 97 1.8 mycroft 98 1.89 chs CFATTACH_DECL_NEW(el, sizeof(struct el_softc), 99 1.69 thorpej elprobe, elattach, NULL, NULL); 100 1.1 hpeyerl 101 1.2 cgd /* 102 1.2 cgd * Probe routine. 103 1.2 cgd * 104 1.2 cgd * See if the card is there and at the right place. 105 1.2 cgd * (XXX - cgd -- needs help) 106 1.2 cgd */ 107 1.100 thorpej static int 108 1.84 cegger elprobe(device_t parent, cfdata_t match, void *aux) 109 1.8 mycroft { 110 1.8 mycroft struct isa_attach_args *ia = aux; 111 1.43 thorpej bus_space_tag_t iot = ia->ia_iot; 112 1.43 thorpej bus_space_handle_t ioh; 113 1.66 thorpej int iobase; 114 1.101 thorpej uint8_t station_addr[ETHER_ADDR_LEN]; 115 1.101 thorpej uint8_t i; 116 1.40 thorpej int rval; 117 1.40 thorpej 118 1.40 thorpej rval = 0; 119 1.1 hpeyerl 120 1.66 thorpej if (ia->ia_nio < 1) 121 1.66 thorpej return (0); 122 1.66 thorpej if (ia->ia_nirq < 1) 123 1.66 thorpej return (0); 124 1.66 thorpej 125 1.66 thorpej if (ISA_DIRECT_CONFIG(ia)) 126 1.66 thorpej return (0); 127 1.66 thorpej 128 1.66 thorpej iobase = ia->ia_io[0].ir_addr; 129 1.66 thorpej 130 1.71 drochner if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 131 1.66 thorpej return (0); 132 1.71 drochner if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ) 133 1.66 thorpej return (0); 134 1.66 thorpej 135 1.3 mycroft /* First check the base. */ 136 1.48 mycroft if (iobase < 0x200 || iobase > 0x3f0) 137 1.3 mycroft return 0; 138 1.3 mycroft 139 1.40 thorpej /* Map i/o space. */ 140 1.48 mycroft if (bus_space_map(iot, iobase, 16, 0, &ioh)) 141 1.40 thorpej return 0; 142 1.3 mycroft 143 1.2 cgd /* 144 1.3 mycroft * Now attempt to grab the station address from the PROM and see if it 145 1.3 mycroft * contains the 3com vendor code. 146 1.1 hpeyerl */ 147 1.41 christos DPRINTF(("Probing 3c501 at 0x%x...\n", iobase)); 148 1.3 mycroft 149 1.3 mycroft /* Reset the board. */ 150 1.41 christos DPRINTF(("Resetting board...\n")); 151 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET); 152 1.6 mycroft delay(5); 153 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, 0); 154 1.3 mycroft 155 1.3 mycroft /* Now read the address. */ 156 1.41 christos DPRINTF(("Reading station address...\n")); 157 1.3 mycroft for (i = 0; i < ETHER_ADDR_LEN; i++) { 158 1.43 thorpej bus_space_write_1(iot, ioh, EL_GPBL, i); 159 1.43 thorpej station_addr[i] = bus_space_read_1(iot, ioh, EL_EAW); 160 1.1 hpeyerl } 161 1.41 christos DPRINTF(("Address is %s\n", ether_sprintf(station_addr))); 162 1.1 hpeyerl 163 1.2 cgd /* 164 1.3 mycroft * If the vendor code is ok, return a 1. We'll assume that whoever 165 1.3 mycroft * configured this system is right about the IRQ. 166 1.1 hpeyerl */ 167 1.3 mycroft if (station_addr[0] != 0x02 || station_addr[1] != 0x60 || 168 1.3 mycroft station_addr[2] != 0x8c) { 169 1.41 christos DPRINTF(("Bad vendor code.\n")); 170 1.40 thorpej goto out; 171 1.1 hpeyerl } 172 1.41 christos DPRINTF(("Vendor code ok.\n")); 173 1.8 mycroft 174 1.66 thorpej ia->ia_nio = 1; 175 1.66 thorpej ia->ia_io[0].ir_size = 16; 176 1.66 thorpej 177 1.66 thorpej ia->ia_nirq = 1; 178 1.66 thorpej 179 1.66 thorpej ia->ia_niomem = 0; 180 1.66 thorpej ia->ia_ndrq = 0; 181 1.66 thorpej 182 1.40 thorpej rval = 1; 183 1.40 thorpej 184 1.40 thorpej out: 185 1.48 mycroft bus_space_unmap(iot, ioh, 16); 186 1.40 thorpej return rval; 187 1.1 hpeyerl } 188 1.1 hpeyerl 189 1.2 cgd /* 190 1.3 mycroft * Attach the interface to the kernel data structures. By the time this is 191 1.3 mycroft * called, we know that the card exists at the given I/O address. We still 192 1.3 mycroft * assume that the IRQ given is correct. 193 1.1 hpeyerl */ 194 1.100 thorpej static void 195 1.84 cegger elattach(device_t parent, device_t self, void *aux) 196 1.1 hpeyerl { 197 1.89 chs struct el_softc *sc = device_private(self); 198 1.9 mycroft struct isa_attach_args *ia = aux; 199 1.43 thorpej bus_space_tag_t iot = ia->ia_iot; 200 1.43 thorpej bus_space_handle_t ioh; 201 1.44 is struct ifnet *ifp = &sc->sc_ethercom.ec_if; 202 1.101 thorpej uint8_t myaddr[ETHER_ADDR_LEN]; 203 1.101 thorpej uint8_t i; 204 1.40 thorpej 205 1.89 chs sc->sc_dev = self; 206 1.89 chs 207 1.42 christos printf("\n"); 208 1.1 hpeyerl 209 1.89 chs DPRINTF(("Attaching %s...\n", device_xname(sc->sc_dev))); 210 1.1 hpeyerl 211 1.40 thorpej /* Map i/o space. */ 212 1.66 thorpej if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh)) { 213 1.80 cegger aprint_error_dev(self, "can't map i/o space\n"); 214 1.40 thorpej return; 215 1.40 thorpej } 216 1.40 thorpej 217 1.43 thorpej sc->sc_iot = iot; 218 1.40 thorpej sc->sc_ioh = ioh; 219 1.40 thorpej 220 1.40 thorpej /* Reset the board. */ 221 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET); 222 1.40 thorpej delay(5); 223 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, 0); 224 1.40 thorpej 225 1.40 thorpej /* Now read the address. */ 226 1.40 thorpej for (i = 0; i < ETHER_ADDR_LEN; i++) { 227 1.43 thorpej bus_space_write_1(iot, ioh, EL_GPBL, i); 228 1.44 is myaddr[i] = bus_space_read_1(iot, ioh, EL_EAW); 229 1.40 thorpej } 230 1.40 thorpej 231 1.3 mycroft /* Stop the board. */ 232 1.30 mycroft elstop(sc); 233 1.1 hpeyerl 234 1.3 mycroft /* Initialize ifnet structure. */ 235 1.89 chs strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 236 1.38 thorpej ifp->if_softc = sc; 237 1.30 mycroft ifp->if_start = elstart; 238 1.30 mycroft ifp->if_ioctl = elioctl; 239 1.30 mycroft ifp->if_watchdog = elwatchdog; 240 1.98 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 241 1.63 thorpej IFQ_SET_READY(&ifp->if_snd); 242 1.1 hpeyerl 243 1.3 mycroft /* Now we can attach the interface. */ 244 1.41 christos DPRINTF(("Attaching interface...\n")); 245 1.1 hpeyerl if_attach(ifp); 246 1.44 is ether_ifattach(ifp, myaddr); 247 1.1 hpeyerl 248 1.3 mycroft /* Print out some information for the user. */ 249 1.80 cegger printf("%s: address %s\n", device_xname(self), ether_sprintf(myaddr)); 250 1.1 hpeyerl 251 1.66 thorpej sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, 252 1.66 thorpej IST_EDGE, IPL_NET, elintr, sc); 253 1.9 mycroft 254 1.49 explorer DPRINTF(("Attaching to random...\n")); 255 1.89 chs rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 256 1.90 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 257 1.49 explorer 258 1.41 christos DPRINTF(("elattach() finished.\n")); 259 1.1 hpeyerl } 260 1.1 hpeyerl 261 1.2 cgd /* 262 1.2 cgd * Reset interface. 263 1.2 cgd */ 264 1.100 thorpej static void 265 1.82 dsl elreset(struct el_softc *sc) 266 1.1 hpeyerl { 267 1.1 hpeyerl int s; 268 1.1 hpeyerl 269 1.41 christos DPRINTF(("elreset()\n")); 270 1.34 mycroft s = splnet(); 271 1.30 mycroft elstop(sc); 272 1.30 mycroft elinit(sc); 273 1.1 hpeyerl splx(s); 274 1.1 hpeyerl } 275 1.1 hpeyerl 276 1.2 cgd /* 277 1.2 cgd * Stop interface. 278 1.2 cgd */ 279 1.100 thorpej static void 280 1.82 dsl elstop(struct el_softc *sc) 281 1.1 hpeyerl { 282 1.1 hpeyerl 283 1.43 thorpej bus_space_write_1(sc->sc_iot, sc->sc_ioh, EL_AC, 0); 284 1.1 hpeyerl } 285 1.1 hpeyerl 286 1.2 cgd /* 287 1.5 mycroft * Do a hardware reset of the board, and upload the ethernet address again in 288 1.5 mycroft * case the board forgets. 289 1.5 mycroft */ 290 1.5 mycroft static inline void 291 1.82 dsl el_hardreset(struct el_softc *sc) 292 1.5 mycroft { 293 1.43 thorpej bus_space_tag_t iot = sc->sc_iot; 294 1.43 thorpej bus_space_handle_t ioh = sc->sc_ioh; 295 1.5 mycroft int i; 296 1.5 mycroft 297 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET); 298 1.6 mycroft delay(5); 299 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, 0); 300 1.5 mycroft 301 1.5 mycroft for (i = 0; i < ETHER_ADDR_LEN; i++) 302 1.44 is bus_space_write_1(iot, ioh, i, 303 1.78 dyoung CLLADDR(sc->sc_ethercom.ec_if.if_sadl)[i]); 304 1.5 mycroft } 305 1.5 mycroft 306 1.5 mycroft /* 307 1.2 cgd * Initialize interface. 308 1.2 cgd */ 309 1.100 thorpej static void 310 1.82 dsl elinit(struct el_softc *sc) 311 1.1 hpeyerl { 312 1.44 is struct ifnet *ifp = &sc->sc_ethercom.ec_if; 313 1.43 thorpej bus_space_tag_t iot = sc->sc_iot; 314 1.43 thorpej bus_space_handle_t ioh = sc->sc_ioh; 315 1.1 hpeyerl 316 1.1 hpeyerl /* First, reset the board. */ 317 1.5 mycroft el_hardreset(sc); 318 1.1 hpeyerl 319 1.3 mycroft /* Configure rx. */ 320 1.41 christos DPRINTF(("Configuring rx...\n")); 321 1.2 cgd if (ifp->if_flags & IFF_PROMISC) 322 1.43 thorpej bus_space_write_1(iot, ioh, EL_RXC, 323 1.40 thorpej EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | 324 1.40 thorpej EL_RXC_DOFLOW | EL_RXC_PROMISC); 325 1.1 hpeyerl else 326 1.43 thorpej bus_space_write_1(iot, ioh, EL_RXC, 327 1.40 thorpej EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | 328 1.40 thorpej EL_RXC_DOFLOW | EL_RXC_ABROAD); 329 1.43 thorpej bus_space_write_1(iot, ioh, EL_RBC, 0); 330 1.1 hpeyerl 331 1.3 mycroft /* Configure TX. */ 332 1.41 christos DPRINTF(("Configuring tx...\n")); 333 1.43 thorpej bus_space_write_1(iot, ioh, EL_TXC, 0); 334 1.1 hpeyerl 335 1.3 mycroft /* Start reception. */ 336 1.41 christos DPRINTF(("Starting reception...\n")); 337 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX); 338 1.1 hpeyerl 339 1.3 mycroft /* Set flags appropriately. */ 340 1.1 hpeyerl ifp->if_flags |= IFF_RUNNING; 341 1.102 thorpej sc->sc_txbusy = false; 342 1.1 hpeyerl 343 1.1 hpeyerl /* And start output. */ 344 1.30 mycroft elstart(ifp); 345 1.1 hpeyerl } 346 1.1 hpeyerl 347 1.2 cgd /* 348 1.3 mycroft * Start output on interface. Get datagrams from the queue and output them, 349 1.34 mycroft * giving the receiver a chance between datagrams. Call only from splnet or 350 1.3 mycroft * interrupt level! 351 1.1 hpeyerl */ 352 1.100 thorpej static void 353 1.82 dsl elstart(struct ifnet *ifp) 354 1.1 hpeyerl { 355 1.38 thorpej struct el_softc *sc = ifp->if_softc; 356 1.43 thorpej bus_space_tag_t iot = sc->sc_iot; 357 1.43 thorpej bus_space_handle_t ioh = sc->sc_ioh; 358 1.1 hpeyerl struct mbuf *m, *m0; 359 1.27 mycroft int s, i, off, retries; 360 1.1 hpeyerl 361 1.41 christos DPRINTF(("elstart()...\n")); 362 1.34 mycroft s = splnet(); 363 1.1 hpeyerl 364 1.3 mycroft /* Don't do anything if output is active. */ 365 1.102 thorpej if (sc->sc_txbusy) { 366 1.27 mycroft splx(s); 367 1.1 hpeyerl return; 368 1.27 mycroft } 369 1.27 mycroft 370 1.102 thorpej sc->sc_txbusy = true; 371 1.1 hpeyerl 372 1.3 mycroft /* 373 1.3 mycroft * The main loop. They warned me against endless loops, but would I 374 1.3 mycroft * listen? NOOO.... 375 1.1 hpeyerl */ 376 1.3 mycroft for (;;) { 377 1.3 mycroft /* Dequeue the next datagram. */ 378 1.63 thorpej IFQ_DEQUEUE(&ifp->if_snd, m0); 379 1.1 hpeyerl 380 1.1 hpeyerl /* If there's nothing to send, return. */ 381 1.27 mycroft if (m0 == 0) 382 1.27 mycroft break; 383 1.27 mycroft 384 1.27 mycroft /* Give the packet to the bpf, if any. */ 385 1.96 msaitoh bpf_mtap(ifp, m0, BPF_D_OUT); 386 1.1 hpeyerl 387 1.3 mycroft /* Disable the receiver. */ 388 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST); 389 1.43 thorpej bus_space_write_1(iot, ioh, EL_RBC, 0); 390 1.1 hpeyerl 391 1.27 mycroft /* Transfer datagram to board. */ 392 1.41 christos DPRINTF(("el: xfr pkt length=%d...\n", m0->m_pkthdr.len)); 393 1.97 riastrad off = EL_BUFSIZ - uimax(m0->m_pkthdr.len, 394 1.59 thorpej ETHER_MIN_LEN - ETHER_CRC_LEN); 395 1.40 thorpej #ifdef DIAGNOSTIC 396 1.40 thorpej if ((off & 0xffff) != off) 397 1.42 christos printf("%s: bogus off 0x%x\n", 398 1.89 chs device_xname(sc->sc_dev), off); 399 1.40 thorpej #endif 400 1.43 thorpej bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff); 401 1.43 thorpej bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff); 402 1.27 mycroft 403 1.1 hpeyerl /* Copy the datagram to the buffer. */ 404 1.27 mycroft for (m = m0; m != 0; m = m->m_next) 405 1.43 thorpej bus_space_write_multi_1(iot, ioh, EL_BUF, 406 1.101 thorpej mtod(m, uint8_t *), m->m_len); 407 1.70 bouyer for (i = 0; 408 1.70 bouyer i < ETHER_MIN_LEN - ETHER_CRC_LEN - m0->m_pkthdr.len; i++) 409 1.70 bouyer bus_space_write_1(iot, ioh, EL_BUF, 0); 410 1.27 mycroft 411 1.1 hpeyerl m_freem(m0); 412 1.1 hpeyerl 413 1.3 mycroft /* Now transmit the datagram. */ 414 1.3 mycroft retries = 0; 415 1.27 mycroft for (;;) { 416 1.43 thorpej bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff); 417 1.43 thorpej bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff); 418 1.33 mycroft if (el_xmit(sc)) { 419 1.99 thorpej if_statinc(ifp, if_oerrors); 420 1.1 hpeyerl break; 421 1.33 mycroft } 422 1.3 mycroft /* Check out status. */ 423 1.43 thorpej i = bus_space_read_1(iot, ioh, EL_TXS); 424 1.41 christos DPRINTF(("tx status=0x%x\n", i)); 425 1.3 mycroft if ((i & EL_TXS_READY) == 0) { 426 1.41 christos DPRINTF(("el: err txs=%x\n", i)); 427 1.3 mycroft if (i & (EL_TXS_COLL | EL_TXS_COLL16)) { 428 1.99 thorpej if_statinc(ifp, if_collisions); 429 1.3 mycroft if ((i & EL_TXC_DCOLL16) == 0 && 430 1.2 cgd retries < 15) { 431 1.1 hpeyerl retries++; 432 1.43 thorpej bus_space_write_1(iot, ioh, 433 1.40 thorpej EL_AC, EL_AC_HOST); 434 1.1 hpeyerl } 435 1.33 mycroft } else { 436 1.99 thorpej if_statinc(ifp, if_oerrors); 437 1.27 mycroft break; 438 1.33 mycroft } 439 1.4 mycroft } else { 440 1.99 thorpej if_statinc(ifp, if_opackets); 441 1.27 mycroft break; 442 1.4 mycroft } 443 1.1 hpeyerl } 444 1.1 hpeyerl 445 1.2 cgd /* 446 1.2 cgd * Now give the card a chance to receive. 447 1.1 hpeyerl * Gotta love 3c501s... 448 1.1 hpeyerl */ 449 1.43 thorpej (void)bus_space_read_1(iot, ioh, EL_AS); 450 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX); 451 1.1 hpeyerl splx(s); 452 1.102 thorpej /* (Maybe) interrupt here. */ 453 1.34 mycroft s = splnet(); 454 1.1 hpeyerl } 455 1.27 mycroft 456 1.43 thorpej (void)bus_space_read_1(iot, ioh, EL_AS); 457 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX); 458 1.102 thorpej sc->sc_txbusy = false; 459 1.27 mycroft splx(s); 460 1.1 hpeyerl } 461 1.1 hpeyerl 462 1.2 cgd /* 463 1.3 mycroft * This function actually attempts to transmit a datagram downloaded to the 464 1.34 mycroft * board. Call at splnet or interrupt, after downloading data! Returns 0 on 465 1.3 mycroft * success, non-0 on failure. 466 1.1 hpeyerl */ 467 1.1 hpeyerl static int 468 1.82 dsl el_xmit(struct el_softc *sc) 469 1.1 hpeyerl { 470 1.43 thorpej bus_space_tag_t iot = sc->sc_iot; 471 1.43 thorpej bus_space_handle_t ioh = sc->sc_ioh; 472 1.1 hpeyerl int i; 473 1.1 hpeyerl 474 1.33 mycroft /* 475 1.33 mycroft * XXX 476 1.33 mycroft * This busy-waits for the tx completion. Can we get an interrupt 477 1.33 mycroft * instead? 478 1.33 mycroft */ 479 1.33 mycroft 480 1.41 christos DPRINTF(("el: xmit...")); 481 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_TXFRX); 482 1.1 hpeyerl i = 20000; 483 1.43 thorpej while ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_TXBUSY) && (i > 0)) 484 1.1 hpeyerl i--; 485 1.2 cgd if (i == 0) { 486 1.41 christos DPRINTF(("tx not ready\n")); 487 1.3 mycroft return -1; 488 1.1 hpeyerl } 489 1.41 christos DPRINTF(("%d cycles.\n", 20000 - i)); 490 1.3 mycroft return 0; 491 1.1 hpeyerl } 492 1.1 hpeyerl 493 1.3 mycroft /* 494 1.3 mycroft * Controller interrupt. 495 1.3 mycroft */ 496 1.100 thorpej static int 497 1.82 dsl elintr(void *arg) 498 1.1 hpeyerl { 499 1.60 augustss struct el_softc *sc = arg; 500 1.43 thorpej bus_space_tag_t iot = sc->sc_iot; 501 1.43 thorpej bus_space_handle_t ioh = sc->sc_ioh; 502 1.101 thorpej uint8_t rxstat; 503 1.40 thorpej int len; 504 1.1 hpeyerl 505 1.41 christos DPRINTF(("elintr: ")); 506 1.1 hpeyerl 507 1.3 mycroft /* Check board status. */ 508 1.43 thorpej if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0) { 509 1.43 thorpej (void)bus_space_read_1(iot, ioh, EL_RXC); 510 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX); 511 1.10 mycroft return 0; 512 1.1 hpeyerl } 513 1.1 hpeyerl 514 1.27 mycroft for (;;) { 515 1.43 thorpej rxstat = bus_space_read_1(iot, ioh, EL_RXS); 516 1.27 mycroft if (rxstat & EL_RXS_STALE) 517 1.27 mycroft break; 518 1.1 hpeyerl 519 1.1 hpeyerl /* If there's an overflow, reinit the board. */ 520 1.3 mycroft if ((rxstat & EL_RXS_NOFLOW) == 0) { 521 1.41 christos DPRINTF(("overflow.\n")); 522 1.5 mycroft el_hardreset(sc); 523 1.3 mycroft /* Put board back into receive mode. */ 524 1.44 is if (sc->sc_ethercom.ec_if.if_flags & IFF_PROMISC) 525 1.43 thorpej bus_space_write_1(iot, ioh, EL_RXC, 526 1.40 thorpej EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | 527 1.40 thorpej EL_RXC_DOFLOW | EL_RXC_PROMISC); 528 1.1 hpeyerl else 529 1.43 thorpej bus_space_write_1(iot, ioh, EL_RXC, 530 1.40 thorpej EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | 531 1.40 thorpej EL_RXC_DOFLOW | EL_RXC_ABROAD); 532 1.43 thorpej (void)bus_space_read_1(iot, ioh, EL_AS); 533 1.43 thorpej bus_space_write_1(iot, ioh, EL_RBC, 0); 534 1.27 mycroft break; 535 1.1 hpeyerl } 536 1.1 hpeyerl 537 1.3 mycroft /* Incoming packet. */ 538 1.43 thorpej len = bus_space_read_1(iot, ioh, EL_RBL); 539 1.43 thorpej len |= bus_space_read_1(iot, ioh, EL_RBH) << 8; 540 1.41 christos DPRINTF(("receive len=%d rxstat=%x ", len, rxstat)); 541 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST); 542 1.1 hpeyerl 543 1.3 mycroft /* Pass data up to upper levels. */ 544 1.27 mycroft elread(sc, len); 545 1.1 hpeyerl 546 1.1 hpeyerl /* Is there another packet? */ 547 1.43 thorpej if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0) 548 1.27 mycroft break; 549 1.49 explorer 550 1.49 explorer rnd_add_uint32(&sc->rnd_source, rxstat); 551 1.27 mycroft 552 1.41 christos DPRINTF(("<rescan> ")); 553 1.1 hpeyerl } 554 1.1 hpeyerl 555 1.43 thorpej (void)bus_space_read_1(iot, ioh, EL_RXC); 556 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX); 557 1.10 mycroft return 1; 558 1.1 hpeyerl } 559 1.1 hpeyerl 560 1.2 cgd /* 561 1.30 mycroft * Pass a packet to the higher levels. 562 1.2 cgd */ 563 1.100 thorpej static void 564 1.82 dsl elread(struct el_softc *sc, int len) 565 1.1 hpeyerl { 566 1.44 is struct ifnet *ifp = &sc->sc_ethercom.ec_if; 567 1.1 hpeyerl struct mbuf *m; 568 1.1 hpeyerl 569 1.30 mycroft if (len <= sizeof(struct ether_header) || 570 1.30 mycroft len > ETHER_MAX_LEN) { 571 1.42 christos printf("%s: invalid packet size %d; dropping\n", 572 1.89 chs device_xname(sc->sc_dev), len); 573 1.99 thorpej if_statinc(ifp, if_ierrors); 574 1.30 mycroft return; 575 1.30 mycroft } 576 1.30 mycroft 577 1.13 mycroft /* Pull packet off interface. */ 578 1.30 mycroft m = elget(sc, len); 579 1.30 mycroft if (m == 0) { 580 1.99 thorpej if_statinc(ifp, if_ierrors); 581 1.1 hpeyerl return; 582 1.30 mycroft } 583 1.30 mycroft 584 1.92 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 585 1.1 hpeyerl } 586 1.1 hpeyerl 587 1.1 hpeyerl /* 588 1.3 mycroft * Pull read data off a interface. Len is length of data, with local net 589 1.13 mycroft * header stripped. We copy the data into mbufs. When full cluster sized 590 1.13 mycroft * units are present we copy into clusters. 591 1.1 hpeyerl */ 592 1.100 thorpej static struct mbuf * 593 1.82 dsl elget(struct el_softc *sc, int totlen) 594 1.26 mycroft { 595 1.44 is struct ifnet *ifp = &sc->sc_ethercom.ec_if; 596 1.43 thorpej bus_space_tag_t iot = sc->sc_iot; 597 1.43 thorpej bus_space_handle_t ioh = sc->sc_ioh; 598 1.55 mycroft struct mbuf *m, *m0, *newm; 599 1.26 mycroft int len; 600 1.26 mycroft 601 1.55 mycroft MGETHDR(m0, M_DONTWAIT, MT_DATA); 602 1.55 mycroft if (m0 == 0) 603 1.55 mycroft return (0); 604 1.93 ozaki m_set_rcvif(m0, ifp); 605 1.55 mycroft m0->m_pkthdr.len = totlen; 606 1.26 mycroft len = MHLEN; 607 1.55 mycroft m = m0; 608 1.26 mycroft 609 1.43 thorpej bus_space_write_1(iot, ioh, EL_GPBL, 0); 610 1.43 thorpej bus_space_write_1(iot, ioh, EL_GPBH, 0); 611 1.27 mycroft 612 1.26 mycroft while (totlen > 0) { 613 1.26 mycroft if (totlen >= MINCLSIZE) { 614 1.26 mycroft MCLGET(m, M_DONTWAIT); 615 1.55 mycroft if ((m->m_flags & M_EXT) == 0) 616 1.55 mycroft goto bad; 617 1.45 mycroft len = MCLBYTES; 618 1.26 mycroft } 619 1.55 mycroft 620 1.97 riastrad m->m_len = len = uimin(totlen, len); 621 1.101 thorpej bus_space_read_multi_1(iot, ioh, EL_BUF, mtod(m, uint8_t *), len); 622 1.55 mycroft 623 1.26 mycroft totlen -= len; 624 1.55 mycroft if (totlen > 0) { 625 1.55 mycroft MGET(newm, M_DONTWAIT, MT_DATA); 626 1.55 mycroft if (newm == 0) 627 1.55 mycroft goto bad; 628 1.55 mycroft len = MLEN; 629 1.55 mycroft m = m->m_next = newm; 630 1.55 mycroft } 631 1.26 mycroft } 632 1.27 mycroft 633 1.43 thorpej bus_space_write_1(iot, ioh, EL_RBC, 0); 634 1.43 thorpej bus_space_write_1(iot, ioh, EL_AC, EL_AC_RX); 635 1.13 mycroft 636 1.55 mycroft return (m0); 637 1.55 mycroft 638 1.55 mycroft bad: 639 1.55 mycroft m_freem(m0); 640 1.55 mycroft return (0); 641 1.1 hpeyerl } 642 1.1 hpeyerl 643 1.1 hpeyerl /* 644 1.3 mycroft * Process an ioctl request. This code needs some work - it looks pretty ugly. 645 1.1 hpeyerl */ 646 1.100 thorpej static int 647 1.81 dyoung elioctl(struct ifnet *ifp, u_long cmd, void *data) 648 1.1 hpeyerl { 649 1.38 thorpej struct el_softc *sc = ifp->if_softc; 650 1.13 mycroft struct ifaddr *ifa = (struct ifaddr *)data; 651 1.1 hpeyerl int s, error = 0; 652 1.1 hpeyerl 653 1.34 mycroft s = splnet(); 654 1.1 hpeyerl 655 1.13 mycroft switch (cmd) { 656 1.1 hpeyerl 657 1.81 dyoung case SIOCINITIFADDR: 658 1.1 hpeyerl ifp->if_flags |= IFF_UP; 659 1.1 hpeyerl 660 1.81 dyoung elinit(sc); 661 1.1 hpeyerl switch (ifa->ifa_addr->sa_family) { 662 1.1 hpeyerl #ifdef INET 663 1.1 hpeyerl case AF_INET: 664 1.44 is arp_ifinit(ifp, ifa); 665 1.1 hpeyerl break; 666 1.1 hpeyerl #endif 667 1.1 hpeyerl default: 668 1.1 hpeyerl break; 669 1.1 hpeyerl } 670 1.1 hpeyerl break; 671 1.1 hpeyerl 672 1.1 hpeyerl case SIOCSIFFLAGS: 673 1.81 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 674 1.81 dyoung break; 675 1.81 dyoung /* XXX re-use ether_ioctl() */ 676 1.81 dyoung switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { 677 1.81 dyoung case IFF_RUNNING: 678 1.3 mycroft /* 679 1.3 mycroft * If interface is marked down and it is running, then 680 1.3 mycroft * stop it. 681 1.3 mycroft */ 682 1.30 mycroft elstop(sc); 683 1.1 hpeyerl ifp->if_flags &= ~IFF_RUNNING; 684 1.81 dyoung break; 685 1.81 dyoung case IFF_UP: 686 1.3 mycroft /* 687 1.3 mycroft * If interface is marked up and it is stopped, then 688 1.3 mycroft * start it. 689 1.3 mycroft */ 690 1.30 mycroft elinit(sc); 691 1.81 dyoung break; 692 1.81 dyoung default: 693 1.3 mycroft /* 694 1.3 mycroft * Some other important flag might have changed, so 695 1.3 mycroft * reset. 696 1.3 mycroft */ 697 1.30 mycroft elreset(sc); 698 1.81 dyoung break; 699 1.1 hpeyerl } 700 1.24 mycroft break; 701 1.1 hpeyerl 702 1.1 hpeyerl default: 703 1.81 dyoung error = ether_ioctl(ifp, cmd, data); 704 1.24 mycroft break; 705 1.1 hpeyerl } 706 1.24 mycroft 707 1.22 mycroft splx(s); 708 1.3 mycroft return error; 709 1.1 hpeyerl } 710 1.1 hpeyerl 711 1.3 mycroft /* 712 1.3 mycroft * Device timeout routine. 713 1.3 mycroft */ 714 1.100 thorpej static void 715 1.82 dsl elwatchdog(struct ifnet *ifp) 716 1.1 hpeyerl { 717 1.38 thorpej struct el_softc *sc = ifp->if_softc; 718 1.1 hpeyerl 719 1.89 chs log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 720 1.99 thorpej if_statinc(ifp, if_oerrors); 721 1.1 hpeyerl 722 1.30 mycroft elreset(sc); 723 1.1 hpeyerl } 724