1 1.52 riastrad /* $NetBSD: am79c950.c,v 1.52 2024/06/29 12:11:10 riastradh Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /*- 4 1.1 tsubai * Copyright (c) 1997 David Huang <khym (at) bga.com> 5 1.1 tsubai * All rights reserved. 6 1.1 tsubai * 7 1.1 tsubai * Portions of this code are based on code by Denton Gentry <denny1 (at) home.com>, 8 1.1 tsubai * Charles M. Hannum, Yanagisawa Takeshi <yanagisw (at) aa.ap.titech.ac.jp>, and 9 1.1 tsubai * Jason R. Thorpe. 10 1.1 tsubai * 11 1.1 tsubai * Redistribution and use in source and binary forms, with or without 12 1.1 tsubai * modification, are permitted provided that the following conditions 13 1.1 tsubai * are met: 14 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 15 1.1 tsubai * notice, this list of conditions and the following disclaimer. 16 1.1 tsubai * 2. The name of the author may not be used to endorse or promote products 17 1.1 tsubai * derived from this software without specific prior written permission 18 1.1 tsubai * 19 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 1.1 tsubai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 1.1 tsubai * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 1.1 tsubai * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 1.1 tsubai * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 1.1 tsubai * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 1.1 tsubai * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 1.1 tsubai * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 1.1 tsubai * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 1.1 tsubai * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 1.1 tsubai * 30 1.1 tsubai */ 31 1.1 tsubai 32 1.1 tsubai /* 33 1.1 tsubai * Driver for the AMD Am79C940 (MACE) ethernet chip, used for onboard 34 1.1 tsubai * ethernet on the Centris/Quadra 660av and Quadra 840av. 35 1.1 tsubai */ 36 1.15 lukem 37 1.15 lukem #include <sys/cdefs.h> 38 1.52 riastrad __KERNEL_RCSID(0, "$NetBSD: am79c950.c,v 1.52 2024/06/29 12:11:10 riastradh Exp $"); 39 1.15 lukem 40 1.2 jonathan #include "opt_inet.h" 41 1.1 tsubai 42 1.1 tsubai #include <sys/param.h> 43 1.1 tsubai #include <sys/systm.h> 44 1.1 tsubai #include <sys/mbuf.h> 45 1.1 tsubai #include <sys/buf.h> 46 1.1 tsubai #include <sys/protosw.h> 47 1.1 tsubai #include <sys/socket.h> 48 1.1 tsubai #include <sys/syslog.h> 49 1.1 tsubai #include <sys/ioctl.h> 50 1.1 tsubai #include <sys/errno.h> 51 1.1 tsubai #include <sys/device.h> 52 1.43 msaitoh #include <sys/bus.h> 53 1.1 tsubai 54 1.1 tsubai #include <net/if.h> 55 1.1 tsubai #include <net/if_dl.h> 56 1.1 tsubai #include <net/if_ether.h> 57 1.1 tsubai #include <net/if_media.h> 58 1.39 msaitoh #include <net/bpf.h> 59 1.1 tsubai 60 1.1 tsubai #ifdef INET 61 1.1 tsubai #include <netinet/in.h> 62 1.1 tsubai #include <netinet/if_inarp.h> 63 1.1 tsubai #include <netinet/in_systm.h> 64 1.1 tsubai #include <netinet/in_var.h> 65 1.1 tsubai #include <netinet/ip.h> 66 1.1 tsubai #endif 67 1.1 tsubai 68 1.1 tsubai #include <macppc/dev/am79c950reg.h> 69 1.1 tsubai #include <macppc/dev/if_mcvar.h> 70 1.1 tsubai 71 1.25 dsl hide void mcwatchdog(struct ifnet *); 72 1.43 msaitoh hide int mcinit(struct mc_softc *); 73 1.43 msaitoh hide int mcstop(struct mc_softc *); 74 1.43 msaitoh hide int mcioctl(struct ifnet *, u_long, void *); 75 1.43 msaitoh hide void mcstart(struct ifnet *); 76 1.43 msaitoh hide void mcreset(struct mc_softc *); 77 1.25 dsl 78 1.43 msaitoh integrate u_int maceput(struct mc_softc *, struct mbuf *); 79 1.43 msaitoh integrate void mc_tint(struct mc_softc *); 80 1.25 dsl integrate void mace_read(struct mc_softc *, uint8_t *, int); 81 1.25 dsl integrate struct mbuf *mace_get(struct mc_softc *, uint8_t *, int); 82 1.43 msaitoh static void mace_calcladrf(struct ethercom *, uint8_t *); 83 1.43 msaitoh static inline uint16_t ether_cmp(void *, void *); 84 1.43 msaitoh static int mc_mediachange(struct ifnet *); 85 1.43 msaitoh static void mc_mediastatus(struct ifnet *, struct ifmediareq *); 86 1.1 tsubai 87 1.1 tsubai /* 88 1.1 tsubai * Compare two Ether/802 addresses for equality, inlined and 89 1.11 wiz * unrolled for speed. Use this like memcmp(). 90 1.1 tsubai * 91 1.1 tsubai * XXX: Add <machine/inlines.h> for stuff like this? 92 1.1 tsubai * XXX: or maybe add it to libkern.h instead? 93 1.1 tsubai * 94 1.1 tsubai * "I'd love to have an inline assembler version of this." 95 1.1 tsubai * XXX: Who wanted that? mycroft? I wrote one, but this 96 1.1 tsubai * version in C is as good as hand-coded assembly. -gwr 97 1.1 tsubai * 98 1.1 tsubai * Please do NOT tweak this without looking at the actual 99 1.1 tsubai * assembly code generated before and after your tweaks! 100 1.1 tsubai */ 101 1.43 msaitoh static inline uint16_t 102 1.27 dsl ether_cmp(void *one, void *two) 103 1.1 tsubai { 104 1.43 msaitoh register uint16_t *a = (u_short *) one; 105 1.43 msaitoh register uint16_t *b = (u_short *) two; 106 1.43 msaitoh register uint16_t diff; 107 1.1 tsubai 108 1.1 tsubai #ifdef m68k 109 1.1 tsubai /* 110 1.1 tsubai * The post-increment-pointer form produces the best 111 1.1 tsubai * machine code for m68k. This was carefully tuned 112 1.1 tsubai * so it compiles to just 8 short (2-byte) op-codes! 113 1.1 tsubai */ 114 1.1 tsubai diff = *a++ - *b++; 115 1.1 tsubai diff |= *a++ - *b++; 116 1.1 tsubai diff |= *a++ - *b++; 117 1.1 tsubai #else 118 1.1 tsubai /* 119 1.47 msaitoh * Most modern CPUs do better with a single expression. 120 1.1 tsubai * Note that short-cut evaluation is NOT helpful here, 121 1.1 tsubai * because it just makes the code longer, not faster! 122 1.1 tsubai */ 123 1.1 tsubai diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]); 124 1.1 tsubai #endif 125 1.1 tsubai 126 1.43 msaitoh return diff; 127 1.1 tsubai } 128 1.1 tsubai 129 1.1 tsubai #define ETHER_CMP ether_cmp 130 1.1 tsubai 131 1.1 tsubai /* 132 1.1 tsubai * Interface exists: make available by filling in network interface 133 1.1 tsubai * record. System will initialize the interface when it is ready 134 1.1 tsubai * to accept packets. 135 1.1 tsubai */ 136 1.1 tsubai int 137 1.43 msaitoh mcsetup(struct mc_softc *sc, uint8_t *lladdr) 138 1.1 tsubai { 139 1.1 tsubai struct ifnet *ifp = &sc->sc_if; 140 1.1 tsubai 141 1.43 msaitoh /* Reset the chip and disable all interrupts */ 142 1.1 tsubai NIC_PUT(sc, MACE_BIUCC, SWRST); 143 1.1 tsubai DELAY(100); 144 1.1 tsubai NIC_PUT(sc, MACE_IMR, ~0); 145 1.1 tsubai 146 1.11 wiz memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN); 147 1.1 tsubai printf(": address %s\n", ether_sprintf(lladdr)); 148 1.1 tsubai 149 1.32 macallan memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 150 1.1 tsubai ifp->if_softc = sc; 151 1.1 tsubai ifp->if_ioctl = mcioctl; 152 1.1 tsubai ifp->if_start = mcstart; 153 1.42 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 154 1.1 tsubai ifp->if_watchdog = mcwatchdog; 155 1.1 tsubai 156 1.43 msaitoh /* Initialize ifmedia structures */ 157 1.46 msaitoh sc->sc_ethercom.ec_ifmedia = &sc->sc_media; 158 1.1 tsubai ifmedia_init(&sc->sc_media, 0, mc_mediachange, mc_mediastatus); 159 1.44 msaitoh ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL); 160 1.44 msaitoh ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL); 161 1.1 tsubai 162 1.1 tsubai if_attach(ifp); 163 1.38 nonaka if_deferred_start_init(ifp, NULL); 164 1.1 tsubai ether_ifattach(ifp, lladdr); 165 1.1 tsubai 166 1.43 msaitoh return 0; 167 1.1 tsubai } 168 1.1 tsubai 169 1.1 tsubai hide int 170 1.26 dsl mcioctl(struct ifnet *ifp, u_long cmd, void *data) 171 1.1 tsubai { 172 1.1 tsubai struct mc_softc *sc = ifp->if_softc; 173 1.1 tsubai struct ifaddr *ifa; 174 1.1 tsubai 175 1.1 tsubai int s = splnet(), err = 0; 176 1.1 tsubai 177 1.1 tsubai switch (cmd) { 178 1.1 tsubai 179 1.24 dyoung case SIOCINITIFADDR: 180 1.1 tsubai ifa = (struct ifaddr *)data; 181 1.1 tsubai ifp->if_flags |= IFF_UP; 182 1.24 dyoung mcinit(sc); 183 1.1 tsubai switch (ifa->ifa_addr->sa_family) { 184 1.1 tsubai #ifdef INET 185 1.1 tsubai case AF_INET: 186 1.1 tsubai arp_ifinit(ifp, ifa); 187 1.1 tsubai break; 188 1.1 tsubai #endif 189 1.1 tsubai default: 190 1.1 tsubai break; 191 1.1 tsubai } 192 1.1 tsubai break; 193 1.1 tsubai 194 1.1 tsubai case SIOCSIFFLAGS: 195 1.24 dyoung if ((err = ifioctl_common(ifp, cmd, data)) != 0) 196 1.24 dyoung break; 197 1.24 dyoung /* XXX see the comment in ed_ioctl() about code re-use */ 198 1.1 tsubai if ((ifp->if_flags & IFF_UP) == 0 && 199 1.1 tsubai (ifp->if_flags & IFF_RUNNING) != 0) { 200 1.1 tsubai /* 201 1.1 tsubai * If interface is marked down and it is running, 202 1.1 tsubai * then stop it. 203 1.1 tsubai */ 204 1.1 tsubai mcstop(sc); 205 1.1 tsubai ifp->if_flags &= ~IFF_RUNNING; 206 1.1 tsubai } else if ((ifp->if_flags & IFF_UP) != 0 && 207 1.1 tsubai (ifp->if_flags & IFF_RUNNING) == 0) { 208 1.1 tsubai /* 209 1.1 tsubai * If interface is marked up and it is stopped, 210 1.1 tsubai * then start it. 211 1.1 tsubai */ 212 1.1 tsubai (void)mcinit(sc); 213 1.1 tsubai } else { 214 1.1 tsubai /* 215 1.43 msaitoh * Reset the interface to pick up any other changes 216 1.1 tsubai * in flags 217 1.1 tsubai */ 218 1.1 tsubai mcreset(sc); 219 1.1 tsubai mcstart(ifp); 220 1.1 tsubai } 221 1.1 tsubai break; 222 1.1 tsubai 223 1.1 tsubai case SIOCADDMULTI: 224 1.1 tsubai case SIOCDELMULTI: 225 1.22 dyoung if ((err = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 226 1.1 tsubai /* 227 1.1 tsubai * Multicast list has changed; set the hardware 228 1.1 tsubai * filter accordingly. But remember UP flag! 229 1.1 tsubai */ 230 1.16 thorpej if (ifp->if_flags & IFF_RUNNING) 231 1.16 thorpej mcreset(sc); 232 1.1 tsubai err = 0; 233 1.1 tsubai } 234 1.1 tsubai break; 235 1.1 tsubai 236 1.1 tsubai default: 237 1.24 dyoung err = ether_ioctl(ifp, cmd, data); 238 1.24 dyoung break; 239 1.1 tsubai } 240 1.1 tsubai splx(s); 241 1.43 msaitoh return err; 242 1.1 tsubai } 243 1.1 tsubai 244 1.1 tsubai /* 245 1.1 tsubai * Encapsulate a packet of type family for the local net. 246 1.1 tsubai */ 247 1.1 tsubai hide void 248 1.26 dsl mcstart(struct ifnet *ifp) 249 1.1 tsubai { 250 1.1 tsubai struct mc_softc *sc = ifp->if_softc; 251 1.1 tsubai struct mbuf *m; 252 1.1 tsubai 253 1.51 thorpej if ((ifp->if_flags & IFF_RUNNING) == 0) 254 1.1 tsubai return; 255 1.1 tsubai 256 1.51 thorpej while (!sc->sc_txbusy) { 257 1.1 tsubai IF_DEQUEUE(&ifp->if_snd, m); 258 1.1 tsubai if (m == 0) 259 1.1 tsubai return; 260 1.1 tsubai 261 1.1 tsubai /* 262 1.1 tsubai * If bpf is listening on this interface, let it 263 1.1 tsubai * see the packet before we commit it to the wire. 264 1.1 tsubai */ 265 1.40 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 266 1.1 tsubai 267 1.43 msaitoh /* Copy the mbuf chain into the transmit buffer. */ 268 1.51 thorpej sc->sc_txbusy = true; 269 1.1 tsubai maceput(sc, m); 270 1.1 tsubai 271 1.48 skrll if_statinc(ifp, if_opackets); /* # of pkts */ 272 1.1 tsubai } 273 1.1 tsubai } 274 1.1 tsubai 275 1.1 tsubai /* 276 1.43 msaitoh * Reset and restart the MACE. Called in case of fatal 277 1.1 tsubai * hardware/software errors. 278 1.1 tsubai */ 279 1.1 tsubai hide void 280 1.26 dsl mcreset(struct mc_softc *sc) 281 1.1 tsubai { 282 1.1 tsubai mcstop(sc); 283 1.1 tsubai mcinit(sc); 284 1.1 tsubai } 285 1.1 tsubai 286 1.1 tsubai hide int 287 1.26 dsl mcinit(struct mc_softc *sc) 288 1.1 tsubai { 289 1.1 tsubai int s; 290 1.43 msaitoh uint8_t maccc, ladrf[8]; 291 1.1 tsubai 292 1.1 tsubai if (sc->sc_if.if_flags & IFF_RUNNING) 293 1.1 tsubai /* already running */ 294 1.43 msaitoh return 0; 295 1.1 tsubai 296 1.1 tsubai s = splnet(); 297 1.1 tsubai 298 1.1 tsubai NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc); 299 1.1 tsubai NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc); 300 1.43 msaitoh NIC_PUT(sc, MACE_IMR, ~0); /* Disable all interrupts */ 301 1.1 tsubai NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc); 302 1.1 tsubai 303 1.43 msaitoh NIC_PUT(sc, MACE_UTR, RTRD); /* Disable reserved test registers */ 304 1.1 tsubai 305 1.43 msaitoh /* Set MAC address */ 306 1.1 tsubai NIC_PUT(sc, MACE_IAC, ADDRCHG); 307 1.1 tsubai while (NIC_GET(sc, MACE_IAC) & ADDRCHG) 308 1.1 tsubai ; 309 1.1 tsubai NIC_PUT(sc, MACE_IAC, PHYADDR); 310 1.1 tsubai bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_PADR), 311 1.1 tsubai sc->sc_enaddr, ETHER_ADDR_LEN); 312 1.1 tsubai 313 1.43 msaitoh /* Set logical address filter */ 314 1.1 tsubai mace_calcladrf(&sc->sc_ethercom, ladrf); 315 1.1 tsubai 316 1.1 tsubai NIC_PUT(sc, MACE_IAC, ADDRCHG); 317 1.1 tsubai while (NIC_GET(sc, MACE_IAC) & ADDRCHG) 318 1.1 tsubai ; 319 1.1 tsubai NIC_PUT(sc, MACE_IAC, LOGADDR); 320 1.1 tsubai bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_LADRF), 321 1.1 tsubai ladrf, 8); 322 1.1 tsubai 323 1.1 tsubai NIC_PUT(sc, MACE_XMTFC, APADXMT); 324 1.1 tsubai /* 325 1.1 tsubai * No need to autostrip padding on receive... Ethernet frames 326 1.1 tsubai * don't have a length field, unlike 802.3 frames, so the MACE 327 1.1 tsubai * can't figure out the length of the packet anyways. 328 1.1 tsubai */ 329 1.1 tsubai NIC_PUT(sc, MACE_RCVFC, 0); 330 1.1 tsubai 331 1.1 tsubai maccc = ENXMT | ENRCV; 332 1.1 tsubai if (sc->sc_if.if_flags & IFF_PROMISC) 333 1.1 tsubai maccc |= PROM; 334 1.1 tsubai 335 1.1 tsubai NIC_PUT(sc, MACE_MACCC, maccc); 336 1.1 tsubai 337 1.1 tsubai if (sc->sc_bus_init) 338 1.1 tsubai (*sc->sc_bus_init)(sc); 339 1.1 tsubai 340 1.1 tsubai /* 341 1.1 tsubai * Enable all interrupts except receive, since we use the DMA 342 1.1 tsubai * completion interrupt for that. 343 1.1 tsubai */ 344 1.1 tsubai NIC_PUT(sc, MACE_IMR, RCVINTM); 345 1.1 tsubai 346 1.43 msaitoh /* Flag interface as "running" */ 347 1.1 tsubai sc->sc_if.if_flags |= IFF_RUNNING; 348 1.51 thorpej sc->sc_txbusy = false; 349 1.1 tsubai 350 1.1 tsubai splx(s); 351 1.43 msaitoh return 0; 352 1.1 tsubai } 353 1.1 tsubai 354 1.1 tsubai /* 355 1.43 msaitoh * Close down an interface and free its buffers 356 1.43 msaitoh * Called on final close of device, or if mcinit() fails part way through. 357 1.1 tsubai */ 358 1.1 tsubai hide int 359 1.26 dsl mcstop(struct mc_softc *sc) 360 1.1 tsubai { 361 1.1 tsubai int s = splnet(); 362 1.1 tsubai 363 1.1 tsubai NIC_PUT(sc, MACE_BIUCC, SWRST); 364 1.1 tsubai DELAY(100); 365 1.1 tsubai 366 1.1 tsubai sc->sc_if.if_timer = 0; 367 1.14 bjh21 sc->sc_if.if_flags &= ~IFF_RUNNING; 368 1.1 tsubai 369 1.1 tsubai splx(s); 370 1.43 msaitoh return 0; 371 1.1 tsubai } 372 1.1 tsubai 373 1.1 tsubai /* 374 1.1 tsubai * Called if any Tx packets remain unsent after 5 seconds, 375 1.1 tsubai * In all cases we just reset the chip, and any retransmission 376 1.1 tsubai * will be handled by higher level protocol timeouts. 377 1.1 tsubai */ 378 1.1 tsubai hide void 379 1.26 dsl mcwatchdog(struct ifnet *ifp) 380 1.1 tsubai { 381 1.1 tsubai struct mc_softc *sc = ifp->if_softc; 382 1.1 tsubai 383 1.1 tsubai printf("mcwatchdog: resetting chip\n"); 384 1.1 tsubai mcreset(sc); 385 1.1 tsubai } 386 1.1 tsubai 387 1.1 tsubai /* 388 1.43 msaitoh * Stuff packet into MACE (at splnet) 389 1.1 tsubai */ 390 1.1 tsubai integrate u_int 391 1.26 dsl maceput(struct mc_softc *sc, struct mbuf *m) 392 1.1 tsubai { 393 1.1 tsubai struct mbuf *n; 394 1.1 tsubai u_int len, totlen = 0; 395 1.1 tsubai u_char *buff; 396 1.1 tsubai 397 1.1 tsubai buff = sc->sc_txbuf; 398 1.1 tsubai 399 1.1 tsubai for (; m; m = n) { 400 1.1 tsubai u_char *data = mtod(m, u_char *); 401 1.1 tsubai len = m->m_len; 402 1.1 tsubai totlen += len; 403 1.11 wiz memcpy(buff, data, len); 404 1.1 tsubai buff += len; 405 1.36 christos n = m_free(m); 406 1.1 tsubai } 407 1.1 tsubai 408 1.13 thorpej if (totlen > PAGE_SIZE) 409 1.32 macallan panic("%s: maceput: packet overflow", device_xname(sc->sc_dev)); 410 1.1 tsubai 411 1.1 tsubai #if 0 412 1.1 tsubai if (totlen < ETHERMIN + sizeof(struct ether_header)) { 413 1.1 tsubai int pad = ETHERMIN + sizeof(struct ether_header) - totlen; 414 1.11 wiz memset(sc->sc_txbuf + totlen, 0, pad); 415 1.1 tsubai totlen = ETHERMIN + sizeof(struct ether_header); 416 1.1 tsubai } 417 1.1 tsubai #endif 418 1.1 tsubai 419 1.1 tsubai (*sc->sc_putpacket)(sc, totlen); 420 1.1 tsubai 421 1.1 tsubai sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */ 422 1.43 msaitoh return totlen; 423 1.1 tsubai } 424 1.1 tsubai 425 1.6 tsubai int 426 1.26 dsl mcintr(void *arg) 427 1.1 tsubai { 428 1.1 tsubai struct mc_softc *sc = arg; 429 1.43 msaitoh uint8_t ir; 430 1.1 tsubai 431 1.1 tsubai ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR); 432 1.6 tsubai if (ir == 0) 433 1.6 tsubai return 0; 434 1.6 tsubai 435 1.1 tsubai if (ir & JAB) { 436 1.1 tsubai #ifdef MCDEBUG 437 1.32 macallan printf("%s: jabber error\n", device_xname(sc->sc_dev)); 438 1.1 tsubai #endif 439 1.49 martin if_statinc(&sc->sc_if, if_oerrors); 440 1.1 tsubai } 441 1.1 tsubai 442 1.1 tsubai if (ir & BABL) { 443 1.1 tsubai #ifdef MCDEBUG 444 1.32 macallan printf("%s: babble\n", device_xname(sc->sc_dev)); 445 1.1 tsubai #endif 446 1.49 martin if_statinc(&sc->sc_if, if_oerrors); 447 1.1 tsubai } 448 1.1 tsubai 449 1.1 tsubai if (ir & CERR) { 450 1.32 macallan printf("%s: collision error\n", device_xname(sc->sc_dev)); 451 1.49 martin if_statinc(&sc->sc_if, if_collisions); 452 1.1 tsubai } 453 1.1 tsubai 454 1.1 tsubai /* 455 1.1 tsubai * Pretend we have carrier; if we don't this will be cleared 456 1.1 tsubai * shortly. 457 1.1 tsubai */ 458 1.50 roy const int ocarrier = sc->sc_havecarrier; 459 1.1 tsubai sc->sc_havecarrier = 1; 460 1.1 tsubai 461 1.1 tsubai if (ir & XMTINT) 462 1.1 tsubai mc_tint(sc); 463 1.1 tsubai 464 1.1 tsubai if (ir & RCVINT) 465 1.1 tsubai mc_rint(sc); 466 1.6 tsubai 467 1.50 roy if (sc->sc_havecarrier != ocarrier) 468 1.50 roy if_link_state_change(&sc->sc_if, 469 1.50 roy sc->sc_havecarrier ? LINK_STATE_UP : LINK_STATE_DOWN); 470 1.50 roy 471 1.6 tsubai return 1; 472 1.1 tsubai } 473 1.1 tsubai 474 1.1 tsubai integrate void 475 1.26 dsl mc_tint(struct mc_softc *sc) 476 1.1 tsubai { 477 1.43 msaitoh uint8_t xmtfs; 478 1.1 tsubai 479 1.33 mrg (void)NIC_GET(sc, MACE_XMTRC); 480 1.1 tsubai xmtfs = NIC_GET(sc, MACE_XMTFS); 481 1.1 tsubai 482 1.1 tsubai if ((xmtfs & XMTSV) == 0) 483 1.1 tsubai return; 484 1.1 tsubai 485 1.1 tsubai if (xmtfs & UFLO) { 486 1.32 macallan printf("%s: underflow\n", device_xname(sc->sc_dev)); 487 1.1 tsubai mcreset(sc); 488 1.1 tsubai return; 489 1.1 tsubai } 490 1.1 tsubai 491 1.49 martin net_stat_ref_t nsr = IF_STAT_GETREF(&sc->sc_if); 492 1.1 tsubai if (xmtfs & LCOL) { 493 1.32 macallan printf("%s: late collision\n", device_xname(sc->sc_dev)); 494 1.52 riastrad if_statinc_ref(&sc->sc_if, nsr, if_oerrors); 495 1.52 riastrad if_statinc_ref(&sc->sc_if, nsr, if_collisions); 496 1.1 tsubai } 497 1.1 tsubai 498 1.1 tsubai if (xmtfs & MORE) 499 1.1 tsubai /* Real number is unknown. */ 500 1.52 riastrad if_statadd_ref(&sc->sc_if, nsr, if_collisions, 2); 501 1.1 tsubai else if (xmtfs & ONE) 502 1.52 riastrad if_statinc_ref(&sc->sc_if, nsr, if_collisions); 503 1.1 tsubai else if (xmtfs & RTRY) { 504 1.52 riastrad if_statadd_ref(&sc->sc_if, nsr, if_collisions, 16); 505 1.52 riastrad if_statinc_ref(&sc->sc_if, nsr, if_oerrors); 506 1.1 tsubai } 507 1.1 tsubai 508 1.1 tsubai if (xmtfs & LCAR) { 509 1.1 tsubai sc->sc_havecarrier = 0; 510 1.32 macallan printf("%s: lost carrier\n", device_xname(sc->sc_dev)); 511 1.52 riastrad if_statinc_ref(&sc->sc_if, nsr, if_oerrors); 512 1.1 tsubai } 513 1.49 martin IF_STAT_PUTREF(&sc->sc_if); 514 1.1 tsubai 515 1.51 thorpej sc->sc_txbusy = false; 516 1.1 tsubai sc->sc_if.if_timer = 0; 517 1.38 nonaka if_schedule_deferred_start(&sc->sc_if); 518 1.1 tsubai } 519 1.1 tsubai 520 1.1 tsubai void 521 1.26 dsl mc_rint(struct mc_softc *sc) 522 1.1 tsubai { 523 1.1 tsubai #define rxf sc->sc_rxframe 524 1.1 tsubai u_int len; 525 1.1 tsubai 526 1.1 tsubai len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4; 527 1.1 tsubai 528 1.1 tsubai #ifdef MCDEBUG 529 1.1 tsubai if (rxf.rx_rcvsts & 0xf0) 530 1.1 tsubai printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n", 531 1.32 macallan device_xname(sc->sc_dev), rxf.rx_rcvcnt, rxf.rx_rcvsts, 532 1.1 tsubai rxf.rx_rntpc, rxf.rx_rcvcc); 533 1.1 tsubai #endif 534 1.1 tsubai 535 1.1 tsubai if (rxf.rx_rcvsts & OFLO) { 536 1.32 macallan printf("%s: receive FIFO overflow\n", device_xname(sc->sc_dev)); 537 1.49 martin if_statinc(&sc->sc_if, if_ierrors); 538 1.1 tsubai return; 539 1.1 tsubai } 540 1.1 tsubai 541 1.1 tsubai if (rxf.rx_rcvsts & CLSN) 542 1.49 martin if_statinc(&sc->sc_if, if_collisions); 543 1.1 tsubai 544 1.1 tsubai if (rxf.rx_rcvsts & FRAM) { 545 1.1 tsubai #ifdef MCDEBUG 546 1.32 macallan printf("%s: framing error\n", device_xname(sc->sc_dev)); 547 1.1 tsubai #endif 548 1.49 martin if_statinc(&sc->sc_if, if_ierrors); 549 1.1 tsubai return; 550 1.1 tsubai } 551 1.1 tsubai 552 1.1 tsubai if (rxf.rx_rcvsts & FCS) { 553 1.1 tsubai #ifdef MCDEBUG 554 1.43 msaitoh printf("%s: frame control checksum error\n", 555 1.43 msaitoh device_xname(sc->sc_dev)); 556 1.1 tsubai #endif 557 1.49 martin if_statinc(&sc->sc_if, if_ierrors); 558 1.1 tsubai return; 559 1.1 tsubai } 560 1.1 tsubai 561 1.1 tsubai mace_read(sc, rxf.rx_frame, len); 562 1.1 tsubai #undef rxf 563 1.1 tsubai } 564 1.1 tsubai 565 1.1 tsubai integrate void 566 1.26 dsl mace_read(struct mc_softc *sc, uint8_t *pkt, int len) 567 1.1 tsubai { 568 1.1 tsubai struct ifnet *ifp = &sc->sc_if; 569 1.1 tsubai struct mbuf *m; 570 1.1 tsubai 571 1.1 tsubai if (len <= sizeof(struct ether_header) || 572 1.1 tsubai len > ETHERMTU + sizeof(struct ether_header)) { 573 1.1 tsubai #ifdef MCDEBUG 574 1.1 tsubai printf("%s: invalid packet size %d; dropping\n", 575 1.32 macallan device_xname(sc->sc_dev), len); 576 1.1 tsubai #endif 577 1.48 skrll if_statinc(ifp, if_ierrors); 578 1.1 tsubai return; 579 1.1 tsubai } 580 1.1 tsubai 581 1.1 tsubai m = mace_get(sc, pkt, len); 582 1.1 tsubai if (m == NULL) { 583 1.48 skrll if_statinc(ifp, if_ierrors); 584 1.1 tsubai return; 585 1.1 tsubai } 586 1.1 tsubai 587 1.7 thorpej /* Pass the packet up. */ 588 1.34 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 589 1.1 tsubai } 590 1.1 tsubai 591 1.1 tsubai /* 592 1.1 tsubai * Pull data off an interface. 593 1.1 tsubai * Len is length of data, with local net header stripped. 594 1.1 tsubai * We copy the data into mbufs. When full cluster sized units are present 595 1.1 tsubai * we copy into clusters. 596 1.1 tsubai */ 597 1.1 tsubai integrate struct mbuf * 598 1.26 dsl mace_get(struct mc_softc *sc, uint8_t *pkt, int totlen) 599 1.1 tsubai { 600 1.1 tsubai register struct mbuf *m; 601 1.1 tsubai struct mbuf *top, **mp; 602 1.1 tsubai int len; 603 1.1 tsubai 604 1.1 tsubai MGETHDR(m, M_DONTWAIT, MT_DATA); 605 1.1 tsubai if (m == 0) 606 1.43 msaitoh return 0; 607 1.35 ozaki m_set_rcvif(m, &sc->sc_if); 608 1.1 tsubai m->m_pkthdr.len = totlen; 609 1.1 tsubai len = MHLEN; 610 1.1 tsubai top = 0; 611 1.1 tsubai mp = ⊤ 612 1.1 tsubai 613 1.1 tsubai while (totlen > 0) { 614 1.1 tsubai if (top) { 615 1.1 tsubai MGET(m, M_DONTWAIT, MT_DATA); 616 1.1 tsubai if (m == 0) { 617 1.1 tsubai m_freem(top); 618 1.1 tsubai return 0; 619 1.1 tsubai } 620 1.1 tsubai len = MLEN; 621 1.1 tsubai } 622 1.1 tsubai if (totlen >= MINCLSIZE) { 623 1.1 tsubai MCLGET(m, M_DONTWAIT); 624 1.1 tsubai if ((m->m_flags & M_EXT) == 0) { 625 1.1 tsubai m_free(m); 626 1.1 tsubai m_freem(top); 627 1.1 tsubai return 0; 628 1.1 tsubai } 629 1.1 tsubai len = MCLBYTES; 630 1.1 tsubai } 631 1.41 riastrad m->m_len = len = uimin(totlen, len); 632 1.20 christos memcpy(mtod(m, void *), pkt, len); 633 1.1 tsubai pkt += len; 634 1.1 tsubai totlen -= len; 635 1.1 tsubai *mp = m; 636 1.1 tsubai mp = &m->m_next; 637 1.1 tsubai } 638 1.1 tsubai 639 1.43 msaitoh return top; 640 1.1 tsubai } 641 1.1 tsubai 642 1.1 tsubai /* 643 1.1 tsubai * Go through the list of multicast addresses and calculate the logical 644 1.1 tsubai * address filter. 645 1.1 tsubai */ 646 1.1 tsubai void 647 1.44 msaitoh mace_calcladrf(struct ethercom *ec, uint8_t *af) 648 1.1 tsubai { 649 1.44 msaitoh struct ifnet *ifp = &ec->ec_if; 650 1.1 tsubai struct ether_multi *enm; 651 1.1 tsubai register u_char *cp, c; 652 1.43 msaitoh register uint32_t crc; 653 1.1 tsubai register int i, len; 654 1.1 tsubai struct ether_multistep step; 655 1.1 tsubai 656 1.1 tsubai /* 657 1.1 tsubai * Set up multicast address filter by passing all multicast addresses 658 1.1 tsubai * through a crc generator, and then using the high order 6 bits as an 659 1.1 tsubai * index into the 64 bit logical address filter. The high order bit 660 1.1 tsubai * selects the word, while the rest of the bits select the bit within 661 1.1 tsubai * the word. 662 1.1 tsubai */ 663 1.1 tsubai 664 1.43 msaitoh *((uint32_t *)af) = *((uint32_t *)af + 1) = 0; 665 1.1 tsubai 666 1.45 msaitoh ETHER_LOCK(ec); 667 1.44 msaitoh ETHER_FIRST_MULTI(step, ec, enm); 668 1.1 tsubai while (enm != NULL) { 669 1.1 tsubai if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) { 670 1.1 tsubai /* 671 1.1 tsubai * We must listen to a range of multicast addresses. 672 1.1 tsubai * For now, just accept all multicasts, rather than 673 1.1 tsubai * trying to set only those filter bits needed to match 674 1.1 tsubai * the range. (At this time, the only use of address 675 1.1 tsubai * ranges is for IP multicast routing, for which the 676 1.1 tsubai * range is big enough to require all bits set.) 677 1.1 tsubai */ 678 1.45 msaitoh ETHER_UNLOCK(ec); 679 1.1 tsubai goto allmulti; 680 1.1 tsubai } 681 1.1 tsubai 682 1.1 tsubai cp = enm->enm_addrlo; 683 1.1 tsubai crc = 0xffffffff; 684 1.1 tsubai for (len = sizeof(enm->enm_addrlo); --len >= 0;) { 685 1.1 tsubai c = *cp++; 686 1.1 tsubai for (i = 8; --i >= 0;) { 687 1.1 tsubai if ((crc & 0x01) ^ (c & 0x01)) { 688 1.1 tsubai crc >>= 1; 689 1.1 tsubai crc ^= 0xedb88320; 690 1.1 tsubai } else 691 1.1 tsubai crc >>= 1; 692 1.1 tsubai c >>= 1; 693 1.1 tsubai } 694 1.1 tsubai } 695 1.1 tsubai /* Just want the 6 most significant bits. */ 696 1.1 tsubai crc >>= 26; 697 1.1 tsubai 698 1.1 tsubai /* Set the corresponding bit in the filter. */ 699 1.1 tsubai af[crc >> 3] |= 1 << (crc & 7); 700 1.1 tsubai 701 1.1 tsubai ETHER_NEXT_MULTI(step, enm); 702 1.1 tsubai } 703 1.45 msaitoh ETHER_UNLOCK(ec); 704 1.1 tsubai ifp->if_flags &= ~IFF_ALLMULTI; 705 1.1 tsubai return; 706 1.1 tsubai 707 1.1 tsubai allmulti: 708 1.1 tsubai ifp->if_flags |= IFF_ALLMULTI; 709 1.43 msaitoh *((uint32_t *)af) = *((uint32_t *)af + 1) = 0xffffffff; 710 1.1 tsubai } 711 1.1 tsubai 712 1.1 tsubai int 713 1.26 dsl mc_mediachange(struct ifnet *ifp) 714 1.1 tsubai { 715 1.1 tsubai return EINVAL; 716 1.1 tsubai } 717 1.1 tsubai 718 1.1 tsubai void 719 1.26 dsl mc_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 720 1.1 tsubai { 721 1.1 tsubai struct mc_softc *sc = ifp->if_softc; 722 1.1 tsubai 723 1.1 tsubai if ((ifp->if_flags & IFF_UP) == 0) 724 1.1 tsubai return; 725 1.1 tsubai 726 1.1 tsubai if (sc->sc_havecarrier) 727 1.1 tsubai ifmr->ifm_status |= IFM_ACTIVE; 728 1.1 tsubai } 729