1 1.37 rin /* $NetBSD: if_ec.c,v 1.37 2024/07/05 04:31:50 rin Exp $ */ 2 1.1 fredette 3 1.1 fredette /* 4 1.1 fredette * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 1.1 fredette * All rights reserved. 6 1.1 fredette * 7 1.1 fredette * This code is derived from software contributed to The NetBSD Foundation 8 1.1 fredette * by Matthew Fredette. 9 1.1 fredette * 10 1.1 fredette * Redistribution and use in source and binary forms, with or without 11 1.1 fredette * modification, are permitted provided that the following conditions 12 1.1 fredette * are met: 13 1.1 fredette * 1. Redistributions of source code must retain the above copyright 14 1.1 fredette * notice, this list of conditions and the following disclaimer. 15 1.1 fredette * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 fredette * notice, this list of conditions and the following disclaimer in the 17 1.1 fredette * documentation and/or other materials provided with the distribution. 18 1.1 fredette * 19 1.1 fredette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 fredette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 fredette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 fredette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 fredette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 fredette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 fredette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 fredette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 fredette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 fredette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 fredette * POSSIBILITY OF SUCH DAMAGE. 30 1.1 fredette */ 31 1.1 fredette 32 1.1 fredette /* 33 1.1 fredette * 3Com 3C400 device driver 34 1.1 fredette */ 35 1.8 lukem 36 1.8 lukem #include <sys/cdefs.h> 37 1.37 rin __KERNEL_RCSID(0, "$NetBSD: if_ec.c,v 1.37 2024/07/05 04:31:50 rin Exp $"); 38 1.1 fredette 39 1.1 fredette #include "opt_inet.h" 40 1.1 fredette #include "opt_ns.h" 41 1.1 fredette 42 1.1 fredette #include <sys/param.h> 43 1.1 fredette #include <sys/systm.h> 44 1.1 fredette #include <sys/errno.h> 45 1.1 fredette #include <sys/ioctl.h> 46 1.1 fredette #include <sys/mbuf.h> 47 1.1 fredette #include <sys/socket.h> 48 1.1 fredette #include <sys/syslog.h> 49 1.1 fredette #include <sys/device.h> 50 1.1 fredette #include <sys/endian.h> 51 1.22 riastrad #include <sys/rndsource.h> 52 1.1 fredette 53 1.1 fredette #include <net/if.h> 54 1.1 fredette #include <net/if_dl.h> 55 1.1 fredette #include <net/if_types.h> 56 1.1 fredette #include <net/if_ether.h> 57 1.3 fredette #include <net/if_media.h> 58 1.28 msaitoh #include <net/bpf.h> 59 1.1 fredette 60 1.1 fredette #ifdef INET 61 1.1 fredette #include <netinet/in.h> 62 1.1 fredette #include <netinet/in_systm.h> 63 1.1 fredette #include <netinet/in_var.h> 64 1.1 fredette #include <netinet/ip.h> 65 1.1 fredette #include <netinet/if_inarp.h> 66 1.1 fredette #endif 67 1.1 fredette 68 1.1 fredette #include <machine/cpu.h> 69 1.1 fredette #include <machine/autoconf.h> 70 1.1 fredette #include <machine/idprom.h> 71 1.1 fredette #include <machine/bus.h> 72 1.1 fredette #include <machine/intr.h> 73 1.1 fredette 74 1.1 fredette #include <sun2/dev/if_ecreg.h> 75 1.1 fredette 76 1.1 fredette /* 77 1.1 fredette * Interface softc. 78 1.1 fredette */ 79 1.1 fredette struct ec_softc { 80 1.15 tsutsui device_t sc_dev; 81 1.1 fredette void *sc_ih; 82 1.1 fredette 83 1.1 fredette struct ethercom sc_ethercom; /* ethernet common */ 84 1.3 fredette struct ifmedia sc_media; /* our supported media */ 85 1.3 fredette 86 1.1 fredette bus_space_tag_t sc_iot; /* bus space tag */ 87 1.1 fredette bus_space_handle_t sc_ioh; /* bus space handle */ 88 1.1 fredette 89 1.36 thorpej bool sc_txbusy; 90 1.1 fredette u_char sc_jammed; /* nonzero if the net is jammed */ 91 1.1 fredette u_char sc_colliding; /* nonzero if the net is colliding */ 92 1.10 chs uint32_t sc_backoff_seed; /* seed for the backoff PRNG */ 93 1.1 fredette 94 1.19 tls krndsource_t rnd_source; 95 1.1 fredette }; 96 1.1 fredette 97 1.1 fredette /* Macros to read and write the CSR. */ 98 1.1 fredette #define ECREG_CSR_RD bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECREG_CSR) 99 1.1 fredette #define ECREG_CSR_WR(val) bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_CSR, val) 100 1.1 fredette 101 1.1 fredette /* After this many collisions, the packet is dropped. */ 102 1.1 fredette #define EC_COLLISIONS_JAMMED 16 103 1.1 fredette 104 1.1 fredette /* 105 1.1 fredette * Various constants used in the backoff pseudorandom 106 1.1 fredette * number generator. 107 1.1 fredette */ 108 1.1 fredette #define EC_BACKOFF_PRNG_COLL_MAX 10 109 1.1 fredette #define EC_BACKOFF_PRNG_MUL 1103515245 110 1.1 fredette #define EC_BACKOFF_PRNG_ADD 12345 111 1.1 fredette #define EC_BACKOFF_PRNG_MASK 0x7fffffff 112 1.1 fredette 113 1.1 fredette /* 114 1.1 fredette * Prototypes 115 1.1 fredette */ 116 1.10 chs int ec_intr(void *); 117 1.10 chs void ec_reset(struct ifnet *); 118 1.10 chs int ec_init(struct ifnet *); 119 1.12 christos int ec_ioctl(struct ifnet *, u_long, void *); 120 1.10 chs void ec_watchdog(struct ifnet *); 121 1.10 chs void ec_start(struct ifnet *); 122 1.10 chs 123 1.10 chs void ec_recv(struct ec_softc *, int); 124 1.10 chs void ec_coll(struct ec_softc *); 125 1.10 chs void ec_copyin(struct ec_softc *, void *, int, size_t); 126 1.10 chs void ec_copyout(struct ec_softc *, const void *, int, size_t); 127 1.1 fredette 128 1.10 chs int ec_mediachange(struct ifnet *); 129 1.10 chs void ec_mediastatus(struct ifnet *, struct ifmediareq *); 130 1.3 fredette 131 1.15 tsutsui int ec_match(device_t, cfdata_t, void *); 132 1.15 tsutsui void ec_attach(device_t, device_t, void *); 133 1.1 fredette 134 1.15 tsutsui CFATTACH_DECL_NEW(ec, sizeof(struct ec_softc), 135 1.6 thorpej ec_match, ec_attach, NULL, NULL); 136 1.1 fredette 137 1.1 fredette /* 138 1.1 fredette * Copy board memory to kernel. 139 1.1 fredette */ 140 1.32 msaitoh void 141 1.10 chs ec_copyin(struct ec_softc *sc, void *p, int offset, size_t size) 142 1.1 fredette { 143 1.15 tsutsui 144 1.1 fredette bus_space_copyin(sc->sc_iot, sc->sc_ioh, offset, p, size); 145 1.1 fredette } 146 1.1 fredette 147 1.1 fredette /* 148 1.1 fredette * Copy from kernel space to board memory. 149 1.1 fredette */ 150 1.32 msaitoh void 151 1.10 chs ec_copyout(struct ec_softc *sc, const void *p, int offset, size_t size) 152 1.1 fredette { 153 1.15 tsutsui 154 1.1 fredette bus_space_copyout(sc->sc_iot, sc->sc_ioh, offset, p, size); 155 1.1 fredette } 156 1.1 fredette 157 1.32 msaitoh int 158 1.15 tsutsui ec_match(device_t parent, cfdata_t cf, void *aux) 159 1.1 fredette { 160 1.1 fredette struct mbmem_attach_args *mbma = aux; 161 1.1 fredette bus_space_handle_t bh; 162 1.15 tsutsui bool matched; 163 1.1 fredette 164 1.1 fredette /* No default Multibus address. */ 165 1.1 fredette if (mbma->mbma_paddr == -1) 166 1.15 tsutsui return 0; 167 1.1 fredette 168 1.1 fredette /* Make sure there is something there... */ 169 1.32 msaitoh if (bus_space_map(mbma->mbma_bustag, mbma->mbma_paddr, ECREG_BANK_SZ, 170 1.15 tsutsui 0, &bh)) 171 1.15 tsutsui return 0; 172 1.1 fredette matched = (bus_space_peek_2(mbma->mbma_bustag, bh, 0, NULL) == 0); 173 1.1 fredette bus_space_unmap(mbma->mbma_bustag, bh, ECREG_BANK_SZ); 174 1.1 fredette if (!matched) 175 1.15 tsutsui return 0; 176 1.1 fredette 177 1.1 fredette /* Default interrupt priority. */ 178 1.1 fredette if (mbma->mbma_pri == -1) 179 1.1 fredette mbma->mbma_pri = 3; 180 1.1 fredette 181 1.15 tsutsui return 1; 182 1.1 fredette } 183 1.1 fredette 184 1.32 msaitoh void 185 1.15 tsutsui ec_attach(device_t parent, device_t self, void *aux) 186 1.1 fredette { 187 1.15 tsutsui struct ec_softc *sc = device_private(self); 188 1.1 fredette struct mbmem_attach_args *mbma = aux; 189 1.1 fredette struct ifnet *ifp = &sc->sc_ethercom.ec_if; 190 1.10 chs uint8_t myaddr[ETHER_ADDR_LEN]; 191 1.1 fredette 192 1.15 tsutsui sc->sc_dev = self; 193 1.15 tsutsui 194 1.15 tsutsui aprint_normal("\n"); 195 1.1 fredette 196 1.1 fredette /* Map in the board control regs. */ 197 1.1 fredette sc->sc_iot = mbma->mbma_bustag; 198 1.1 fredette if (bus_space_map(mbma->mbma_bustag, mbma->mbma_paddr, ECREG_BANK_SZ, 199 1.15 tsutsui 0, &sc->sc_ioh)) 200 1.15 tsutsui panic("%s: can't map regs", __func__); 201 1.1 fredette 202 1.1 fredette /* Reset the board. */ 203 1.1 fredette ECREG_CSR_WR(EC_CSR_RESET); 204 1.1 fredette delay(160); 205 1.1 fredette 206 1.1 fredette /* 207 1.1 fredette * Copy out the board ROM Ethernet address, 208 1.1 fredette * and use the non-vendor-ID part to seed 209 1.1 fredette * our backoff pseudorandom number generator. 210 1.1 fredette */ 211 1.15 tsutsui bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, 212 1.15 tsutsui ECREG_AROM, myaddr, ETHER_ADDR_LEN); 213 1.15 tsutsui sc->sc_backoff_seed = 214 1.15 tsutsui (myaddr[3] << 16) | (myaddr[4] << 8) | (myaddr[5]) | 1; 215 1.1 fredette 216 1.1 fredette /* Initialize ifnet structure. */ 217 1.15 tsutsui strcpy(ifp->if_xname, device_xname(self)); 218 1.1 fredette ifp->if_softc = sc; 219 1.1 fredette ifp->if_start = ec_start; 220 1.1 fredette ifp->if_ioctl = ec_ioctl; 221 1.1 fredette ifp->if_init = ec_init; 222 1.1 fredette ifp->if_watchdog = ec_watchdog; 223 1.31 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 224 1.1 fredette IFQ_SET_READY(&ifp->if_snd); 225 1.1 fredette 226 1.3 fredette /* Initialize ifmedia structures. */ 227 1.34 msaitoh sc->sc_ethercom.ec_ifmedia = &sc->sc_media; 228 1.3 fredette ifmedia_init(&sc->sc_media, 0, ec_mediachange, ec_mediastatus); 229 1.33 msaitoh ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL); 230 1.33 msaitoh ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL); 231 1.3 fredette 232 1.1 fredette /* Now we can attach the interface. */ 233 1.1 fredette if_attach(ifp); 234 1.26 ozaki if_deferred_start_init(ifp, NULL); 235 1.1 fredette idprom_etheraddr(myaddr); 236 1.1 fredette ether_ifattach(ifp, myaddr); 237 1.15 tsutsui aprint_normal_dev(self, "address %s\n", ether_sprintf(myaddr)); 238 1.1 fredette 239 1.1 fredette bus_intr_establish(mbma->mbma_bustag, mbma->mbma_pri, IPL_NET, 0, 240 1.1 fredette ec_intr, sc); 241 1.1 fredette 242 1.15 tsutsui rnd_attach_source(&sc->rnd_source, device_xname(self), 243 1.21 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 244 1.1 fredette } 245 1.1 fredette 246 1.1 fredette /* 247 1.1 fredette * Reset interface. 248 1.32 msaitoh */ 249 1.32 msaitoh void 250 1.10 chs ec_reset(struct ifnet *ifp) 251 1.1 fredette { 252 1.1 fredette int s; 253 1.1 fredette 254 1.1 fredette s = splnet(); 255 1.1 fredette ec_init(ifp); 256 1.1 fredette splx(s); 257 1.1 fredette } 258 1.1 fredette 259 1.1 fredette 260 1.1 fredette /* 261 1.1 fredette * Initialize interface. 262 1.1 fredette */ 263 1.32 msaitoh int 264 1.10 chs ec_init(struct ifnet *ifp) 265 1.1 fredette { 266 1.1 fredette struct ec_softc *sc = ifp->if_softc; 267 1.1 fredette 268 1.1 fredette /* Reset the board. */ 269 1.1 fredette ECREG_CSR_WR(EC_CSR_RESET); 270 1.1 fredette delay(160); 271 1.1 fredette 272 1.1 fredette /* Set the Ethernet address. */ 273 1.15 tsutsui bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, 274 1.15 tsutsui ECREG_ARAM, CLLADDR(sc->sc_ethercom.ec_if.if_sadl), ETHER_ADDR_LEN); 275 1.1 fredette ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_AMSW); 276 1.1 fredette ECREG_CSR_WR(ECREG_CSR_RD & 0); 277 1.1 fredette 278 1.1 fredette /* Enable interrupts. */ 279 1.15 tsutsui ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | 280 1.15 tsutsui EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_BINT | EC_CSR_AINT | 281 1.15 tsutsui (ifp->if_flags & IFF_PROMISC ? EC_CSR_PROMISC : EC_CSR_PA)); 282 1.1 fredette 283 1.1 fredette /* Set flags appropriately. */ 284 1.1 fredette ifp->if_flags |= IFF_RUNNING; 285 1.36 thorpej sc->sc_txbusy = false; 286 1.1 fredette 287 1.1 fredette /* Start output. */ 288 1.1 fredette ec_start(ifp); 289 1.1 fredette 290 1.15 tsutsui return 0; 291 1.1 fredette } 292 1.1 fredette 293 1.1 fredette /* 294 1.1 fredette * Start output on interface. 295 1.1 fredette */ 296 1.32 msaitoh void 297 1.10 chs ec_start(struct ifnet *ifp) 298 1.1 fredette { 299 1.1 fredette struct ec_softc *sc = ifp->if_softc; 300 1.1 fredette struct mbuf *m, *m0; 301 1.1 fredette int s; 302 1.7 bouyer u_int count, realcount; 303 1.1 fredette bus_size_t off; 304 1.10 chs static uint8_t padding[ETHER_MIN_LEN - ETHER_CRC_LEN] = {0}; 305 1.1 fredette 306 1.1 fredette s = splnet(); 307 1.1 fredette 308 1.1 fredette /* Don't do anything if output is active. */ 309 1.36 thorpej if (sc->sc_txbusy) { 310 1.1 fredette splx(s); 311 1.1 fredette return; 312 1.1 fredette } 313 1.1 fredette /* Don't do anything if the output queue is empty. */ 314 1.1 fredette IFQ_DEQUEUE(&ifp->if_snd, m0); 315 1.1 fredette if (m0 == NULL) { 316 1.1 fredette splx(s); 317 1.1 fredette return; 318 1.1 fredette } 319 1.1 fredette 320 1.1 fredette /* The BPF tap. */ 321 1.29 msaitoh bpf_mtap(ifp, m0, BPF_D_OUT); 322 1.1 fredette 323 1.1 fredette /* Size the packet. */ 324 1.9 mycroft count = EC_BUF_SZ - m0->m_pkthdr.len; 325 1.1 fredette 326 1.1 fredette /* Copy the packet into the xmit buffer. */ 327 1.7 bouyer realcount = MIN(count, EC_PKT_MAXTDOFF); 328 1.7 bouyer bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_TBUF, realcount); 329 1.7 bouyer for (off = realcount, m = m0; m != 0; off += m->m_len, m = m->m_next) 330 1.10 chs ec_copyout(sc, mtod(m, uint8_t *), ECREG_TBUF + off, m->m_len); 331 1.1 fredette m_freem(m0); 332 1.9 mycroft if (count - realcount) 333 1.9 mycroft ec_copyout(sc, padding, ECREG_TBUF + off, count - realcount); 334 1.1 fredette 335 1.1 fredette /* Enable the transmitter. */ 336 1.15 tsutsui ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_PA) | 337 1.15 tsutsui EC_CSR_TBSW | EC_CSR_TINT | EC_CSR_JINT); 338 1.36 thorpej sc->sc_txbusy = true; 339 1.1 fredette 340 1.1 fredette /* Done. */ 341 1.1 fredette splx(s); 342 1.1 fredette } 343 1.1 fredette 344 1.1 fredette /* 345 1.1 fredette * Controller interrupt. 346 1.1 fredette */ 347 1.32 msaitoh int 348 1.10 chs ec_intr(void *arg) 349 1.1 fredette { 350 1.1 fredette struct ec_softc *sc = arg; 351 1.1 fredette struct ifnet *ifp = &sc->sc_ethercom.ec_if; 352 1.1 fredette int recv_first; 353 1.1 fredette int recv_second; 354 1.1 fredette int retval; 355 1.1 fredette 356 1.1 fredette retval = 0; 357 1.1 fredette 358 1.1 fredette /* Check for received packet(s). */ 359 1.1 fredette recv_first = recv_second = 0; 360 1.1 fredette switch (ECREG_CSR_RD & (EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_RBBA)) { 361 1.1 fredette 362 1.1 fredette case (EC_CSR_BBSW | EC_CSR_ABSW): 363 1.1 fredette case (EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_RBBA): 364 1.1 fredette /* Neither buffer is full. Is this a transmit interrupt? 365 1.1 fredette * Acknowledge the interrupt ourselves. */ 366 1.15 tsutsui ECREG_CSR_WR(ECREG_CSR_RD & 367 1.15 tsutsui (EC_CSR_TINT | EC_CSR_JINT | EC_CSR_PAMASK)); 368 1.15 tsutsui ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | 369 1.15 tsutsui EC_CSR_BINT | EC_CSR_AINT); 370 1.1 fredette break; 371 1.1 fredette 372 1.1 fredette case EC_CSR_BBSW: 373 1.1 fredette case (EC_CSR_BBSW | EC_CSR_RBBA): 374 1.1 fredette /* Only the A buffer is full. */ 375 1.1 fredette recv_first = EC_CSR_AINT; 376 1.1 fredette break; 377 1.1 fredette 378 1.1 fredette case EC_CSR_ABSW: 379 1.1 fredette case (EC_CSR_ABSW | EC_CSR_RBBA): 380 1.1 fredette /* Only the B buffer is full. */ 381 1.1 fredette recv_first = EC_CSR_BINT; 382 1.1 fredette break; 383 1.1 fredette 384 1.1 fredette case 0: 385 1.1 fredette /* Both the A buffer and the B buffer are full, and the A 386 1.1 fredette * buffer is older than the B buffer. */ 387 1.1 fredette recv_first = EC_CSR_AINT; 388 1.1 fredette recv_second = EC_CSR_BINT; 389 1.1 fredette break; 390 1.1 fredette 391 1.1 fredette case EC_CSR_RBBA: 392 1.1 fredette /* Both the A buffer and the B buffer are full, and the B 393 1.1 fredette * buffer is older than the A buffer. */ 394 1.1 fredette recv_first = EC_CSR_BINT; 395 1.1 fredette recv_second = EC_CSR_AINT; 396 1.1 fredette break; 397 1.1 fredette } 398 1.1 fredette 399 1.1 fredette /* Receive packets. */ 400 1.1 fredette if (recv_first) { 401 1.1 fredette 402 1.1 fredette /* Acknowledge the interrupt. */ 403 1.15 tsutsui ECREG_CSR_WR(ECREG_CSR_RD & 404 1.15 tsutsui ((EC_CSR_BINT | EC_CSR_AINT | EC_CSR_TINT | EC_CSR_JINT | 405 1.15 tsutsui EC_CSR_PAMASK) ^ (recv_first | recv_second))); 406 1.1 fredette 407 1.1 fredette /* Receive a packet. */ 408 1.1 fredette ec_recv(sc, recv_first); 409 1.1 fredette 410 1.1 fredette /* Receive a packet. */ 411 1.1 fredette if (recv_second) 412 1.1 fredette ec_recv(sc, recv_second); 413 1.1 fredette 414 1.1 fredette retval++; 415 1.1 fredette } 416 1.1 fredette /* Check for a transmitted packet. */ 417 1.36 thorpej if (sc->sc_txbusy) { 418 1.1 fredette 419 1.1 fredette /* If we got a collision. */ 420 1.1 fredette if (ECREG_CSR_RD & EC_CSR_JAM) { 421 1.15 tsutsui ECREG_CSR_WR(ECREG_CSR_RD & 422 1.15 tsutsui (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK)); 423 1.35 thorpej if_statinc(ifp, if_collisions); 424 1.1 fredette retval++; 425 1.1 fredette ec_coll(sc); 426 1.1 fredette 427 1.1 fredette } 428 1.1 fredette /* If we transmitted a packet. */ 429 1.1 fredette else if ((ECREG_CSR_RD & EC_CSR_TBSW) == 0) { 430 1.15 tsutsui ECREG_CSR_WR(ECREG_CSR_RD & 431 1.15 tsutsui (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK)); 432 1.1 fredette retval++; 433 1.35 thorpej if_statinc(ifp, if_opackets); 434 1.1 fredette sc->sc_jammed = 0; 435 1.36 thorpej sc->sc_txbusy = false; 436 1.26 ozaki if_schedule_deferred_start(ifp); 437 1.1 fredette } 438 1.1 fredette } else { 439 1.1 fredette 440 1.1 fredette /* Make sure we disable transmitter interrupts. */ 441 1.15 tsutsui ECREG_CSR_WR(ECREG_CSR_RD & 442 1.15 tsutsui (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK)); 443 1.1 fredette } 444 1.1 fredette 445 1.1 fredette return retval; 446 1.1 fredette } 447 1.1 fredette 448 1.1 fredette /* 449 1.1 fredette * Read in a packet from the board. 450 1.1 fredette */ 451 1.32 msaitoh void 452 1.10 chs ec_recv(struct ec_softc *sc, int intbit) 453 1.1 fredette { 454 1.1 fredette struct ifnet *ifp = &sc->sc_ethercom.ec_if; 455 1.1 fredette struct mbuf *m0, *m, *newm; 456 1.1 fredette bus_size_t buf; 457 1.10 chs uint16_t status; 458 1.10 chs uint16_t doff; 459 1.1 fredette int length, total_length; 460 1.1 fredette 461 1.1 fredette buf = EC_CSR_INT_BUF(intbit); 462 1.1 fredette 463 1.1 fredette /* Read in the packet status. */ 464 1.1 fredette status = bus_space_read_2(sc->sc_iot, sc->sc_ioh, buf); 465 1.1 fredette doff = status & EC_PKT_DOFF; 466 1.1 fredette 467 1.15 tsutsui for (total_length = -1, m0 = NULL;;) { 468 1.1 fredette 469 1.1 fredette /* Check for an error. */ 470 1.1 fredette if (status & (EC_PKT_FCSERR | EC_PKT_RGERR | EC_PKT_FRERR) || 471 1.1 fredette doff < EC_PKT_MINRDOFF || 472 1.1 fredette doff > EC_PKT_MAXRDOFF) { 473 1.1 fredette printf("%s: garbled packet, status 0x%04x; dropping\n", 474 1.15 tsutsui device_xname(sc->sc_dev), (unsigned int)status); 475 1.1 fredette break; 476 1.1 fredette } 477 1.1 fredette 478 1.1 fredette /* Adjust for the header. */ 479 1.1 fredette total_length = doff - EC_PKT_RDOFF; 480 1.1 fredette buf += EC_PKT_RDOFF; 481 1.1 fredette 482 1.2 fredette /* XXX - sometimes the card reports a large data offset. */ 483 1.2 fredette if (total_length > (ETHER_MAX_LEN - ETHER_CRC_LEN)) { 484 1.2 fredette #ifdef DEBUG 485 1.2 fredette printf("%s: fixing too-large length of %d\n", 486 1.15 tsutsui device_xname(sc->sc_dev), total_length); 487 1.2 fredette #endif 488 1.2 fredette total_length = (ETHER_MAX_LEN - ETHER_CRC_LEN); 489 1.2 fredette } 490 1.2 fredette 491 1.1 fredette MGETHDR(m0, M_DONTWAIT, MT_DATA); 492 1.15 tsutsui if (m0 == NULL) 493 1.1 fredette break; 494 1.25 ozaki m_set_rcvif(m0, ifp); 495 1.1 fredette m0->m_pkthdr.len = total_length; 496 1.1 fredette length = MHLEN; 497 1.1 fredette m = m0; 498 1.1 fredette 499 1.1 fredette while (total_length > 0) { 500 1.1 fredette if (total_length >= MINCLSIZE) { 501 1.1 fredette MCLGET(m, M_DONTWAIT); 502 1.1 fredette if ((m->m_flags & M_EXT) == 0) 503 1.1 fredette break; 504 1.1 fredette length = MCLBYTES; 505 1.1 fredette } 506 1.30 riastrad m->m_len = length = uimin(total_length, length); 507 1.10 chs ec_copyin(sc, mtod(m, uint8_t *), buf, length); 508 1.1 fredette total_length -= length; 509 1.1 fredette buf += length; 510 1.1 fredette 511 1.1 fredette if (total_length > 0) { 512 1.1 fredette MGET(newm, M_DONTWAIT, MT_DATA); 513 1.15 tsutsui if (newm == NULL) 514 1.1 fredette break; 515 1.1 fredette length = MLEN; 516 1.1 fredette m = m->m_next = newm; 517 1.1 fredette } 518 1.1 fredette } 519 1.1 fredette break; 520 1.1 fredette } 521 1.1 fredette 522 1.1 fredette if (total_length == 0) { 523 1.1 fredette /* Pass the packet up. */ 524 1.24 ozaki if_percpuq_enqueue(ifp->if_percpuq, m0); 525 1.1 fredette 526 1.1 fredette } else { 527 1.1 fredette /* Something went wrong. */ 528 1.37 rin m_freem(m0); 529 1.35 thorpej if_statinc(ifp, if_ierrors); 530 1.1 fredette } 531 1.1 fredette 532 1.1 fredette /* Give the receive buffer back to the card. */ 533 1.2 fredette buf = EC_CSR_INT_BUF(intbit); 534 1.2 fredette bus_space_write_2(sc->sc_iot, sc->sc_ioh, buf, 0); 535 1.15 tsutsui ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | 536 1.15 tsutsui EC_CSR_INT_BSW(intbit) | intbit); 537 1.1 fredette } 538 1.1 fredette 539 1.32 msaitoh int 540 1.10 chs ec_mediachange(struct ifnet *ifp) 541 1.32 msaitoh { 542 1.15 tsutsui 543 1.15 tsutsui return 0; 544 1.3 fredette } 545 1.3 fredette 546 1.32 msaitoh void 547 1.10 chs ec_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 548 1.32 msaitoh { 549 1.15 tsutsui 550 1.3 fredette if ((ifp->if_flags & IFF_UP) == 0) 551 1.3 fredette return; 552 1.32 msaitoh 553 1.3 fredette ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 554 1.3 fredette } 555 1.3 fredette 556 1.1 fredette /* 557 1.1 fredette * Process an ioctl request. This code needs some work - it looks pretty ugly. 558 1.1 fredette */ 559 1.32 msaitoh int 560 1.12 christos ec_ioctl(struct ifnet *ifp, u_long cmd, void *data) 561 1.1 fredette { 562 1.15 tsutsui struct ifaddr *ifa = (struct ifaddr *)data; 563 1.1 fredette int s, error = 0; 564 1.1 fredette 565 1.1 fredette s = splnet(); 566 1.1 fredette 567 1.1 fredette switch (cmd) { 568 1.1 fredette 569 1.16 dyoung case SIOCINITIFADDR: 570 1.1 fredette ifp->if_flags |= IFF_UP; 571 1.1 fredette 572 1.1 fredette switch (ifa->ifa_addr->sa_family) { 573 1.1 fredette #ifdef INET 574 1.1 fredette case AF_INET: 575 1.1 fredette ec_init(ifp); 576 1.1 fredette arp_ifinit(ifp, ifa); 577 1.1 fredette break; 578 1.1 fredette #endif 579 1.1 fredette default: 580 1.1 fredette ec_init(ifp); 581 1.1 fredette break; 582 1.1 fredette } 583 1.1 fredette break; 584 1.1 fredette 585 1.1 fredette case SIOCSIFFLAGS: 586 1.16 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 587 1.16 dyoung break; 588 1.33 msaitoh switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { 589 1.16 dyoung case IFF_RUNNING: 590 1.1 fredette /* 591 1.1 fredette * If interface is marked down and it is running, then 592 1.1 fredette * stop it. 593 1.1 fredette */ 594 1.1 fredette ifp->if_flags &= ~IFF_RUNNING; 595 1.16 dyoung break; 596 1.16 dyoung case IFF_UP: 597 1.1 fredette /* 598 1.1 fredette * If interface is marked up and it is stopped, then 599 1.1 fredette * start it. 600 1.1 fredette */ 601 1.1 fredette ec_init(ifp); 602 1.16 dyoung break; 603 1.16 dyoung default: 604 1.1 fredette /* 605 1.1 fredette * Some other important flag might have changed, so 606 1.1 fredette * reset. 607 1.1 fredette */ 608 1.1 fredette ec_reset(ifp); 609 1.16 dyoung break; 610 1.1 fredette } 611 1.3 fredette break; 612 1.3 fredette 613 1.1 fredette default: 614 1.16 dyoung error = ether_ioctl(ifp, cmd, data); 615 1.1 fredette break; 616 1.1 fredette } 617 1.1 fredette 618 1.1 fredette splx(s); 619 1.1 fredette return error; 620 1.1 fredette } 621 1.1 fredette 622 1.1 fredette /* 623 1.1 fredette * Collision routine. 624 1.1 fredette */ 625 1.32 msaitoh void 626 1.10 chs ec_coll(struct ec_softc *sc) 627 1.1 fredette { 628 1.1 fredette struct ifnet *ifp = &sc->sc_ethercom.ec_if; 629 1.1 fredette u_short jams; 630 1.1 fredette 631 1.1 fredette if ((++sc->sc_colliding) >= EC_COLLISIONS_JAMMED) { 632 1.35 thorpej if_statinc(ifp, if_oerrors); 633 1.1 fredette if (!sc->sc_jammed) 634 1.1 fredette printf("%s: ethernet jammed\n", 635 1.15 tsutsui device_xname(sc->sc_dev)); 636 1.1 fredette sc->sc_jammed = 1; 637 1.1 fredette sc->sc_colliding = 0; 638 1.36 thorpej sc->sc_txbusy = false; 639 1.26 ozaki if_schedule_deferred_start(ifp); 640 1.1 fredette } else { 641 1.1 fredette jams = MAX(sc->sc_colliding, EC_BACKOFF_PRNG_COLL_MAX); 642 1.15 tsutsui sc->sc_backoff_seed = 643 1.15 tsutsui ((sc->sc_backoff_seed * EC_BACKOFF_PRNG_MUL) + 644 1.15 tsutsui EC_BACKOFF_PRNG_ADD) & EC_BACKOFF_PRNG_MASK; 645 1.15 tsutsui bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_BACKOFF, 646 1.15 tsutsui -(((sc->sc_backoff_seed >> 8) & ~(-1 << jams)) + 1)); 647 1.15 tsutsui ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | 648 1.15 tsutsui EC_CSR_JAM | EC_CSR_TINT | EC_CSR_JINT); 649 1.1 fredette } 650 1.1 fredette } 651 1.1 fredette 652 1.1 fredette /* 653 1.1 fredette * Device timeout routine. 654 1.1 fredette */ 655 1.32 msaitoh void 656 1.10 chs ec_watchdog(struct ifnet *ifp) 657 1.1 fredette { 658 1.1 fredette struct ec_softc *sc = ifp->if_softc; 659 1.1 fredette 660 1.15 tsutsui log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 661 1.35 thorpej if_statinc(ifp, if_oerrors); 662 1.1 fredette 663 1.1 fredette ec_reset(ifp); 664 1.1 fredette } 665