1 1.77 rillig /* $NetBSD: smc90cx6.c,v 1.77 2024/09/08 09:36:50 rillig Exp $ */ 2 1.2 chopps 3 1.28 is /*- 4 1.29 is * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc. 5 1.1 chopps * All rights reserved. 6 1.1 chopps * 7 1.28 is * This code is derived from software contributed to The NetBSD Foundation 8 1.28 is * by Ignatios Souvatzis. 9 1.28 is * 10 1.1 chopps * Redistribution and use in source and binary forms, with or without 11 1.1 chopps * modification, are permitted provided that the following conditions 12 1.1 chopps * are met: 13 1.1 chopps * 1. Redistributions of source code must retain the above copyright 14 1.1 chopps * notice, this list of conditions and the following disclaimer. 15 1.1 chopps * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 chopps * notice, this list of conditions and the following disclaimer in the 17 1.1 chopps * documentation and/or other materials provided with the distribution. 18 1.1 chopps * 19 1.28 is * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.28 is * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.28 is * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.28 is * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.28 is * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.28 is * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.28 is * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.28 is * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.28 is * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.28 is * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.28 is * POSSIBILITY OF SUCH DAMAGE. 30 1.1 chopps */ 31 1.1 chopps 32 1.1 chopps /* 33 1.25 is * Chip core driver for the SMC90c26 / SMC90c56 (and SMC90c66 in '56 34 1.25 is * compatibility mode) boards 35 1.1 chopps */ 36 1.39 lukem 37 1.39 lukem #include <sys/cdefs.h> 38 1.77 rillig __KERNEL_RCSID(0, "$NetBSD: smc90cx6.c,v 1.77 2024/09/08 09:36:50 rillig Exp $"); 39 1.1 chopps 40 1.33 is /* #define BAHSOFTCOPY */ 41 1.14 chopps #define BAHRETRANSMIT /**/ 42 1.16 is 43 1.24 jonathan #include "opt_inet.h" 44 1.1 chopps 45 1.1 chopps #include <sys/param.h> 46 1.1 chopps #include <sys/systm.h> 47 1.1 chopps #include <sys/mbuf.h> 48 1.1 chopps #include <sys/buf.h> 49 1.1 chopps #include <sys/device.h> 50 1.1 chopps #include <sys/protosw.h> 51 1.1 chopps #include <sys/socket.h> 52 1.1 chopps #include <sys/syslog.h> 53 1.1 chopps #include <sys/ioctl.h> 54 1.1 chopps #include <sys/errno.h> 55 1.51 ad #include <sys/kernel.h> 56 1.51 ad #include <sys/intr.h> 57 1.1 chopps 58 1.1 chopps #include <net/if.h> 59 1.1 chopps #include <net/if_dl.h> 60 1.58 phx #include <net/if_ether.h> 61 1.1 chopps #include <net/if_types.h> 62 1.25 is #include <net/if_arc.h> 63 1.72 msaitoh #include <net/bpf.h> 64 1.1 chopps 65 1.1 chopps #ifdef INET 66 1.1 chopps #include <netinet/in.h> 67 1.1 chopps #include <netinet/in_systm.h> 68 1.1 chopps #include <netinet/in_var.h> 69 1.1 chopps #include <netinet/ip.h> 70 1.25 is #include <netinet/if_inarp.h> 71 1.1 chopps #endif 72 1.1 chopps 73 1.52 ad #include <sys/bus.h> 74 1.52 ad #include <sys/cpu.h> 75 1.1 chopps 76 1.25 is #include <dev/ic/smc90cx6reg.h> 77 1.25 is #include <dev/ic/smc90cx6var.h> 78 1.1 chopps 79 1.1 chopps /* these should be elsewhere */ 80 1.1 chopps 81 1.1 chopps #define ARC_MIN_LEN 1 82 1.1 chopps #define ARC_MIN_FORBID_LEN 254 83 1.1 chopps #define ARC_MAX_FORBID_LEN 256 84 1.1 chopps #define ARC_MAX_LEN 508 85 1.1 chopps #define ARC_ADDR_LEN 1 86 1.1 chopps 87 1.6 chopps /* for watchdog timer. This should be more than enough. */ 88 1.6 chopps #define ARCTIMEOUT (5*IFNET_SLOWHZ) 89 1.6 chopps 90 1.1 chopps /* 91 1.1 chopps * This currently uses 2 bufs for tx, 2 for rx 92 1.1 chopps * 93 1.1 chopps * New rx protocol: 94 1.1 chopps * 95 1.43 perry * rx has a fillcount variable. If fillcount > (NRXBUF-1), 96 1.43 perry * rx can be switched off from rx hard int. 97 1.1 chopps * Else rx is restarted on the other receiver. 98 1.1 chopps * rx soft int counts down. if it is == (NRXBUF-1), it restarts 99 1.1 chopps * the receiver. 100 1.1 chopps * To ensure packet ordering (we need that for 1201 later), we have a counter 101 1.1 chopps * which is incremented modulo 256 on each receive and a per buffer 102 1.1 chopps * variable, which is set to the counter on filling. The soft int can 103 1.1 chopps * compare both values to determine the older packet. 104 1.1 chopps * 105 1.1 chopps * Transmit direction: 106 1.43 perry * 107 1.1 chopps * bah_start checks tx_fillcount 108 1.1 chopps * case 2: return 109 1.1 chopps * 110 1.1 chopps * else fill tx_act ^ 1 && inc tx_fillcount 111 1.1 chopps * 112 1.1 chopps * check tx_fillcount again. 113 1.1 chopps * case 2: set IFF_OACTIVE to stop arc_output from filling us. 114 1.1 chopps * case 1: start tx 115 1.1 chopps * 116 1.1 chopps * tint clears IFF_OCATIVE, decrements and checks tx_fillcount 117 1.1 chopps * case 1: start tx on tx_act ^ 1, softcall bah_start 118 1.1 chopps * case 0: softcall bah_start 119 1.1 chopps * 120 1.1 chopps * #define fill(i) get mbuf && copy mbuf to chip(i) 121 1.1 chopps */ 122 1.1 chopps 123 1.42 perry void bah_init(struct bah_softc *); 124 1.42 perry void bah_reset(struct bah_softc *); 125 1.42 perry void bah_stop(struct bah_softc *); 126 1.42 perry void bah_start(struct ifnet *); 127 1.42 perry int bahintr(void *); 128 1.47 christos int bah_ioctl(struct ifnet *, unsigned long, void *); 129 1.42 perry void bah_watchdog(struct ifnet *); 130 1.42 perry void bah_srint(void *vsc); 131 1.42 perry static void bah_tint(struct bah_softc *, int); 132 1.25 is void bah_reconwatch(void *); 133 1.25 is 134 1.25 is /* short notation */ 135 1.25 is 136 1.25 is #define GETREG(off) bus_space_read_1(bst_r, regs, (off)) 137 1.25 is #define PUTREG(off, v) bus_space_write_1(bst_r, regs, (off), (v)) 138 1.25 is #define GETMEM(off) bus_space_read_1(bst_m, mem, (off)) 139 1.25 is #define PUTMEM(off, v) bus_space_write_1(bst_m, mem, (off), (v)) 140 1.1 chopps 141 1.71 msaitoh int 142 1.59 dsl bah_attach_subr(struct bah_softc *sc) 143 1.1 chopps { 144 1.4 mycroft struct ifnet *ifp = &sc->sc_arccom.ac_if; 145 1.71 msaitoh int s, rv; 146 1.25 is u_int8_t linkaddress; 147 1.25 is 148 1.25 is bus_space_tag_t bst_r = sc->sc_bst_r; 149 1.25 is bus_space_tag_t bst_m = sc->sc_bst_m; 150 1.25 is bus_space_handle_t regs = sc->sc_regs; 151 1.25 is bus_space_handle_t mem = sc->sc_mem; 152 1.1 chopps 153 1.1 chopps s = splhigh(); 154 1.1 chopps 155 1.1 chopps /* 156 1.1 chopps * read the arcnet address from the board 157 1.1 chopps */ 158 1.1 chopps 159 1.25 is (*sc->sc_reset)(sc, 1); 160 1.1 chopps 161 1.1 chopps do { 162 1.25 is delay(200); 163 1.43 perry } while (!(GETREG(BAHSTAT) & BAH_POR)); 164 1.1 chopps 165 1.25 is linkaddress = GETMEM(BAHMACOFF); 166 1.1 chopps 167 1.25 is printf(": link addr 0x%02x(%d)\n", linkaddress, linkaddress); 168 1.1 chopps 169 1.1 chopps /* clear the int mask... */ 170 1.1 chopps 171 1.25 is sc->sc_intmask = 0; 172 1.25 is PUTREG(BAHSTAT, 0); 173 1.1 chopps 174 1.25 is PUTREG(BAHCMD, BAH_CONF(CONF_LONG)); 175 1.25 is PUTREG(BAHCMD, BAH_CLR(CLR_POR|CLR_RECONFIG)); 176 1.3 chopps sc->sc_recontime = sc->sc_reconcount = 0; 177 1.1 chopps 178 1.1 chopps /* and reenable kernel int level */ 179 1.1 chopps splx(s); 180 1.1 chopps 181 1.1 chopps /* 182 1.1 chopps * set interface to stopped condition (reset) 183 1.1 chopps */ 184 1.43 perry bah_stop(sc); 185 1.1 chopps 186 1.64 chs strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 187 1.17 thorpej ifp->if_softc = sc; 188 1.1 chopps ifp->if_start = bah_start; 189 1.1 chopps ifp->if_ioctl = bah_ioctl; 190 1.6 chopps ifp->if_timer = 0; 191 1.6 chopps ifp->if_watchdog = bah_watchdog; 192 1.37 thorpej IFQ_SET_READY(&ifp->if_snd); 193 1.6 chopps 194 1.74 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 195 1.6 chopps 196 1.6 chopps ifp->if_mtu = ARCMTU; 197 1.1 chopps 198 1.71 msaitoh rv = arc_ifattach(ifp, linkaddress); 199 1.71 msaitoh if (rv != 0) 200 1.71 msaitoh return rv; 201 1.69 ozaki if_deferred_start_init(ifp, NULL); 202 1.1 chopps 203 1.25 is #ifdef BAHSOFTCOPY 204 1.51 ad sc->sc_rxcookie = softint_establish(SOFTINT_NET, bah_srint, sc); 205 1.51 ad sc->sc_txcookie = softint_establish(SOFTINT_NET, 206 1.42 perry (void (*)(void *))bah_start, ifp); 207 1.25 is #endif 208 1.25 is 209 1.48 he callout_init(&sc->sc_recon_ch, 0); 210 1.71 msaitoh return 0; 211 1.1 chopps } 212 1.1 chopps 213 1.1 chopps /* 214 1.1 chopps * Initialize device 215 1.1 chopps * 216 1.1 chopps */ 217 1.1 chopps void 218 1.59 dsl bah_init(struct bah_softc *sc) 219 1.1 chopps { 220 1.3 chopps struct ifnet *ifp; 221 1.1 chopps int s; 222 1.3 chopps 223 1.3 chopps ifp = &sc->sc_arccom.ac_if; 224 1.1 chopps 225 1.1 chopps if ((ifp->if_flags & IFF_RUNNING) == 0) { 226 1.13 mycroft s = splnet(); 227 1.1 chopps ifp->if_flags |= IFF_RUNNING; 228 1.1 chopps bah_reset(sc); 229 1.4 mycroft bah_start(ifp); 230 1.1 chopps splx(s); 231 1.1 chopps } 232 1.1 chopps } 233 1.1 chopps 234 1.1 chopps /* 235 1.1 chopps * Reset the interface... 236 1.1 chopps * 237 1.1 chopps * this assumes that it is called inside a critical section... 238 1.1 chopps * 239 1.1 chopps */ 240 1.1 chopps void 241 1.59 dsl bah_reset(struct bah_softc *sc) 242 1.1 chopps { 243 1.3 chopps struct ifnet *ifp; 244 1.53 he uint8_t linkaddress; 245 1.1 chopps 246 1.25 is bus_space_tag_t bst_r = sc->sc_bst_r; 247 1.25 is bus_space_tag_t bst_m = sc->sc_bst_m; 248 1.25 is bus_space_handle_t regs = sc->sc_regs; 249 1.25 is bus_space_handle_t mem = sc->sc_mem; 250 1.25 is 251 1.1 chopps ifp = &sc->sc_arccom.ac_if; 252 1.1 chopps 253 1.1 chopps #ifdef BAH_DEBUG 254 1.64 chs printf("%s: reset\n", device_xname(sc->sc_dev)); 255 1.1 chopps #endif 256 1.25 is /* stop and restart hardware */ 257 1.1 chopps 258 1.25 is (*sc->sc_reset)(sc, 1); 259 1.1 chopps do { 260 1.14 chopps DELAY(200); 261 1.43 perry } while (!(GETREG(BAHSTAT) & BAH_POR)); 262 1.1 chopps 263 1.25 is linkaddress = GETMEM(BAHMACOFF); 264 1.6 chopps 265 1.1 chopps #if defined(BAH_DEBUG) && (BAH_DEBUG > 2) 266 1.65 phx printf("%s: reset: card reset, link addr = 0x%02x (%u)\n", 267 1.64 chs device_xname(sc->sc_dev), linkaddress, linkaddress); 268 1.1 chopps #endif 269 1.6 chopps 270 1.6 chopps /* tell the routing level about the (possibly changed) link address */ 271 1.57 dyoung if_set_sadl(ifp, &linkaddress, sizeof(linkaddress), false); 272 1.6 chopps 273 1.1 chopps /* POR is NMI, but we need it below: */ 274 1.25 is sc->sc_intmask = BAH_RECON|BAH_POR; 275 1.25 is PUTREG(BAHSTAT, sc->sc_intmask); 276 1.25 is PUTREG(BAHCMD, BAH_CONF(CONF_LONG)); 277 1.43 perry 278 1.1 chopps #ifdef BAH_DEBUG 279 1.19 christos printf("%s: reset: chip configured, status=0x%02x\n", 280 1.64 chs device_xname(sc->sc_dev), GETREG(BAHSTAT)); 281 1.1 chopps #endif 282 1.25 is PUTREG(BAHCMD, BAH_CLR(CLR_POR|CLR_RECONFIG)); 283 1.1 chopps 284 1.1 chopps #ifdef BAH_DEBUG 285 1.19 christos printf("%s: reset: bits cleared, status=0x%02x\n", 286 1.64 chs device_xname(sc->sc_dev), GETREG(BAHSTAT)); 287 1.1 chopps #endif 288 1.1 chopps 289 1.1 chopps sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS; 290 1.1 chopps 291 1.1 chopps /* start receiver */ 292 1.1 chopps 293 1.25 is sc->sc_intmask |= BAH_RI; 294 1.14 chopps sc->sc_rx_fillcount = 0; 295 1.1 chopps sc->sc_rx_act = 2; 296 1.1 chopps 297 1.25 is PUTREG(BAHCMD, BAH_RXBC(2)); 298 1.25 is PUTREG(BAHSTAT, sc->sc_intmask); 299 1.1 chopps 300 1.1 chopps #ifdef BAH_DEBUG 301 1.19 christos printf("%s: reset: started receiver, status=0x%02x\n", 302 1.64 chs device_xname(sc->sc_dev), GETREG(BAHSTAT)); 303 1.1 chopps #endif 304 1.1 chopps 305 1.1 chopps /* and init transmitter status */ 306 1.1 chopps sc->sc_tx_act = 0; 307 1.1 chopps sc->sc_tx_fillcount = 0; 308 1.1 chopps 309 1.1 chopps ifp->if_flags |= IFF_RUNNING; 310 1.1 chopps ifp->if_flags &= ~IFF_OACTIVE; 311 1.1 chopps 312 1.1 chopps bah_start(ifp); 313 1.1 chopps } 314 1.1 chopps 315 1.1 chopps /* 316 1.1 chopps * Take interface offline 317 1.1 chopps */ 318 1.1 chopps void 319 1.59 dsl bah_stop(struct bah_softc *sc) 320 1.1 chopps { 321 1.25 is bus_space_tag_t bst_r = sc->sc_bst_r; 322 1.25 is bus_space_handle_t regs = sc->sc_regs; 323 1.25 is 324 1.1 chopps /* Stop the interrupts */ 325 1.25 is PUTREG(BAHSTAT, 0); 326 1.1 chopps 327 1.1 chopps /* Stop the interface */ 328 1.25 is (*sc->sc_reset)(sc, 0); 329 1.1 chopps 330 1.6 chopps /* Stop watchdog timer */ 331 1.6 chopps sc->sc_arccom.ac_if.if_timer = 0; 332 1.1 chopps } 333 1.1 chopps 334 1.1 chopps /* 335 1.1 chopps * Start output on interface. Get another datagram to send 336 1.1 chopps * off the interface queue, and copy it to the 337 1.41 wiz * interface before starting the output 338 1.1 chopps * 339 1.1 chopps * this assumes that it is called inside a critical section... 340 1.1 chopps * XXX hm... does it still? 341 1.1 chopps * 342 1.1 chopps */ 343 1.4 mycroft void 344 1.59 dsl bah_start(struct ifnet *ifp) 345 1.1 chopps { 346 1.25 is struct bah_softc *sc = ifp->if_softc; 347 1.1 chopps struct mbuf *m,*mp; 348 1.25 is 349 1.25 is bus_space_tag_t bst_r = sc->sc_bst_r; 350 1.25 is bus_space_handle_t regs = sc->sc_regs; 351 1.25 is bus_space_tag_t bst_m = sc->sc_bst_m; 352 1.25 is bus_space_handle_t mem = sc->sc_mem; 353 1.25 is 354 1.25 is int bah_ram_ptr; 355 1.14 chopps int len, tlen, offset, s, buffer; 356 1.1 chopps #ifdef BAHTIMINGS 357 1.7 cgd u_long copystart, lencopy, perbyte; 358 1.1 chopps #endif 359 1.1 chopps 360 1.1 chopps #if defined(BAH_DEBUG) && (BAH_DEBUG > 3) 361 1.64 chs printf("%s: start(0x%x)\n", device_xname(sc->sc_dev), ifp); 362 1.1 chopps #endif 363 1.1 chopps 364 1.4 mycroft if ((ifp->if_flags & IFF_RUNNING) == 0) 365 1.5 chopps return; 366 1.1 chopps 367 1.13 mycroft s = splnet(); 368 1.1 chopps 369 1.1 chopps if (sc->sc_tx_fillcount >= 2) { 370 1.1 chopps splx(s); 371 1.5 chopps return; 372 1.1 chopps } 373 1.1 chopps 374 1.37 thorpej IFQ_DEQUEUE(&ifp->if_snd, m); 375 1.1 chopps buffer = sc->sc_tx_act ^ 1; 376 1.1 chopps 377 1.1 chopps splx(s); 378 1.1 chopps 379 1.1 chopps if (m == 0) 380 1.5 chopps return; 381 1.1 chopps 382 1.1 chopps /* 383 1.1 chopps * If bpf is listening on this interface, let it 384 1.1 chopps * see the packet before we commit it to the wire 385 1.1 chopps * 386 1.1 chopps * (can't give the copy in A2060 card RAM to bpf, because 387 1.1 chopps * that RAM is just accessed as on every other byte) 388 1.1 chopps */ 389 1.73 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 390 1.1 chopps 391 1.1 chopps #ifdef BAH_DEBUG 392 1.33 is if (m->m_len < ARC_HDRLEN) 393 1.33 is m = m_pullup(m, ARC_HDRLEN);/* gcc does structure padding */ 394 1.65 phx printf("%s: start: filling %d from %u to %u type %u\n", 395 1.64 chs device_xname(sc->sc_dev), buffer, mtod(m, u_char *)[0], 396 1.7 cgd mtod(m, u_char *)[1], mtod(m, u_char *)[2]); 397 1.1 chopps #else 398 1.33 is if (m->m_len < 2) 399 1.33 is m = m_pullup(m, 2); 400 1.1 chopps #endif 401 1.25 is bah_ram_ptr = buffer*512; 402 1.1 chopps 403 1.33 is if (m == 0) 404 1.33 is return; 405 1.33 is 406 1.1 chopps /* write the addresses to RAM and throw them away */ 407 1.1 chopps 408 1.1 chopps /* 409 1.1 chopps * Hardware does this: Yet Another Microsecond Saved. 410 1.1 chopps * (btw, timing code says usually 2 microseconds) 411 1.25 is * PUTMEM(bah_ram_ptr + 0, mtod(m, u_char *)[0]); 412 1.1 chopps */ 413 1.25 is 414 1.25 is PUTMEM(bah_ram_ptr + 1, mtod(m, u_char *)[1]); 415 1.4 mycroft m_adj(m, 2); 416 1.43 perry 417 1.14 chopps /* get total length left at this point */ 418 1.14 chopps tlen = m->m_pkthdr.len; 419 1.3 chopps if (tlen < ARC_MIN_FORBID_LEN) { 420 1.7 cgd offset = 256 - tlen; 421 1.25 is PUTMEM(bah_ram_ptr + 2, offset); 422 1.3 chopps } else { 423 1.25 is PUTMEM(bah_ram_ptr + 2, 0); 424 1.14 chopps if (tlen <= ARC_MAX_FORBID_LEN) 425 1.14 chopps offset = 255; /* !!! */ 426 1.1 chopps else { 427 1.1 chopps if (tlen > ARC_MAX_LEN) 428 1.1 chopps tlen = ARC_MAX_LEN; 429 1.7 cgd offset = 512 - tlen; 430 1.1 chopps } 431 1.25 is PUTMEM(bah_ram_ptr + 3, offset); 432 1.1 chopps 433 1.1 chopps } 434 1.25 is bah_ram_ptr += offset; 435 1.1 chopps 436 1.14 chopps /* lets loop through the mbuf chain */ 437 1.1 chopps 438 1.7 cgd for (mp = m; mp; mp = mp->m_next) { 439 1.14 chopps if ((len = mp->m_len)) { /* YAMS */ 440 1.25 is bus_space_write_region_1(bst_m, mem, bah_ram_ptr, 441 1.47 christos mtod(mp, void *), len); 442 1.1 chopps 443 1.25 is bah_ram_ptr += len; 444 1.1 chopps } 445 1.1 chopps } 446 1.1 chopps 447 1.1 chopps sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0; 448 1.4 mycroft sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5; 449 1.1 chopps 450 1.1 chopps /* actually transmit the packet */ 451 1.13 mycroft s = splnet(); 452 1.1 chopps 453 1.43 perry if (++sc->sc_tx_fillcount > 1) { 454 1.3 chopps /* 455 1.3 chopps * We are filled up to the rim. No more bufs for the moment, 456 1.3 chopps * please. 457 1.3 chopps */ 458 1.3 chopps ifp->if_flags |= IFF_OACTIVE; 459 1.3 chopps } else { 460 1.1 chopps #ifdef BAH_DEBUG 461 1.43 perry printf("%s: start: starting transmitter on buffer %d\n", 462 1.64 chs device_xname(sc->sc_dev), buffer); 463 1.1 chopps #endif 464 1.1 chopps /* Transmitter was off, start it */ 465 1.1 chopps sc->sc_tx_act = buffer; 466 1.1 chopps 467 1.1 chopps /* 468 1.1 chopps * We still can accept another buf, so don't: 469 1.1 chopps * ifp->if_flags |= IFF_OACTIVE; 470 1.1 chopps */ 471 1.25 is sc->sc_intmask |= BAH_TA; 472 1.25 is PUTREG(BAHCMD, BAH_TX(buffer)); 473 1.25 is PUTREG(BAHSTAT, sc->sc_intmask); 474 1.1 chopps 475 1.6 chopps sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT; 476 1.1 chopps } 477 1.1 chopps splx(s); 478 1.1 chopps m_freem(m); 479 1.1 chopps 480 1.1 chopps /* 481 1.6 chopps * After 10 times reading the docs, I realized 482 1.6 chopps * that in the case the receiver NAKs the buffer request, 483 1.1 chopps * the hardware retries till shutdown. 484 1.6 chopps * This is integrated now in the code above. 485 1.1 chopps */ 486 1.6 chopps 487 1.6 chopps return; 488 1.1 chopps } 489 1.1 chopps 490 1.1 chopps /* 491 1.1 chopps * Arcnet interface receiver soft interrupt: 492 1.1 chopps * get the stuff out of any filled buffer we find. 493 1.1 chopps */ 494 1.1 chopps void 495 1.59 dsl bah_srint(void *vsc) 496 1.14 chopps { 497 1.25 is struct bah_softc *sc = (struct bah_softc *)vsc; 498 1.25 is int buffer, len, len1, amount, offset, s, type; 499 1.25 is int bah_ram_ptr; 500 1.3 chopps struct mbuf *m, *dst, *head; 501 1.3 chopps struct arc_header *ah; 502 1.5 chopps struct ifnet *ifp; 503 1.25 is 504 1.25 is bus_space_tag_t bst_r = sc->sc_bst_r; 505 1.25 is bus_space_tag_t bst_m = sc->sc_bst_m; 506 1.25 is bus_space_handle_t regs = sc->sc_regs; 507 1.25 is bus_space_handle_t mem = sc->sc_mem; 508 1.25 is 509 1.14 chopps ifp = &sc->sc_arccom.ac_if; 510 1.3 chopps head = 0; 511 1.1 chopps 512 1.13 mycroft s = splnet(); 513 1.14 chopps buffer = sc->sc_rx_act ^ 1; 514 1.1 chopps splx(s); 515 1.1 chopps 516 1.1 chopps /* Allocate header mbuf */ 517 1.1 chopps MGETHDR(m, M_DONTWAIT, MT_DATA); 518 1.1 chopps 519 1.1 chopps if (m == 0) { 520 1.43 perry /* 521 1.1 chopps * in case s.th. goes wrong with mem, drop it 522 1.1 chopps * to make sure the receiver can be started again 523 1.1 chopps * count it as input error (we dont have any other 524 1.1 chopps * detectable) 525 1.1 chopps */ 526 1.75 thorpej if_statinc(ifp, if_ierrors); 527 1.1 chopps goto cleanup; 528 1.1 chopps } 529 1.43 perry 530 1.67 ozaki m_set_rcvif(m, ifp); 531 1.1 chopps 532 1.1 chopps /* 533 1.1 chopps * Align so that IP packet will be longword aligned. Here we 534 1.1 chopps * assume that m_data of new packet is longword aligned. 535 1.8 cgd * When implementing PHDS, we might have to change it to 2, 536 1.8 cgd * (2*sizeof(ulong) - ARC_HDRNEWLEN)), packet type dependent. 537 1.1 chopps */ 538 1.1 chopps 539 1.25 is bah_ram_ptr = buffer*512; 540 1.25 is offset = GETMEM(bah_ram_ptr + 2); 541 1.3 chopps if (offset) 542 1.1 chopps len = 256 - offset; 543 1.3 chopps else { 544 1.25 is offset = GETMEM(bah_ram_ptr + 3); 545 1.1 chopps len = 512 - offset; 546 1.1 chopps } 547 1.33 is if (len+2 >= MINCLSIZE) 548 1.33 is MCLGET(m, M_DONTWAIT); 549 1.43 perry 550 1.33 is if (m == 0) { 551 1.75 thorpej if_statinc(ifp, if_ierrors); 552 1.33 is goto cleanup; 553 1.33 is } 554 1.33 is 555 1.25 is type = GETMEM(bah_ram_ptr + offset); 556 1.8 cgd m->m_data += 1 + arc_isphds(type); 557 1.8 cgd 558 1.8 cgd head = m; 559 1.8 cgd ah = mtod(head, struct arc_header *); 560 1.43 perry 561 1.25 is ah->arc_shost = GETMEM(bah_ram_ptr + 0); 562 1.25 is ah->arc_dhost = GETMEM(bah_ram_ptr + 1); 563 1.8 cgd 564 1.8 cgd m->m_pkthdr.len = len+2; /* whole packet length */ 565 1.8 cgd m->m_len = 2; /* mbuf filled with ARCnet addresses */ 566 1.25 is bah_ram_ptr += offset; /* ram buffer continues there */ 567 1.1 chopps 568 1.1 chopps while (len > 0) { 569 1.43 perry 570 1.1 chopps len1 = len; 571 1.1 chopps amount = M_TRAILINGSPACE(m); 572 1.1 chopps 573 1.1 chopps if (amount == 0) { 574 1.1 chopps dst = m; 575 1.1 chopps MGET(m, M_DONTWAIT, MT_DATA); 576 1.43 perry 577 1.1 chopps if (m == 0) { 578 1.75 thorpej if_statinc(ifp, if_ierrors); 579 1.1 chopps goto cleanup; 580 1.1 chopps } 581 1.43 perry 582 1.25 is if (len1 >= MINCLSIZE) 583 1.1 chopps MCLGET(m, M_DONTWAIT); 584 1.43 perry 585 1.1 chopps m->m_len = 0; 586 1.1 chopps dst->m_next = m; 587 1.1 chopps amount = M_TRAILINGSPACE(m); 588 1.1 chopps } 589 1.1 chopps 590 1.1 chopps if (amount < len1) 591 1.1 chopps len1 = amount; 592 1.1 chopps 593 1.43 perry bus_space_read_region_1(bst_m, mem, bah_ram_ptr, 594 1.25 is mtod(m, u_char *) + m->m_len, len1); 595 1.1 chopps 596 1.1 chopps m->m_len += len1; 597 1.25 is bah_ram_ptr += len1; 598 1.1 chopps len -= len1; 599 1.1 chopps } 600 1.1 chopps 601 1.66 ozaki if_percpuq_enqueue((&sc->sc_arccom.ac_if)->if_percpuq, head); 602 1.1 chopps 603 1.1 chopps head = NULL; 604 1.43 perry 605 1.1 chopps cleanup: 606 1.1 chopps 607 1.76 rin m_freem(head); 608 1.1 chopps 609 1.16 is /* mark buffer as invalid by source id 0 */ 610 1.25 is bus_space_write_1(bst_m, mem, buffer*512, 0); 611 1.13 mycroft s = splnet(); 612 1.1 chopps 613 1.14 chopps if (--sc->sc_rx_fillcount == 2 - 1) { 614 1.1 chopps 615 1.1 chopps /* was off, restart it on buffer just emptied */ 616 1.1 chopps sc->sc_rx_act = buffer; 617 1.25 is sc->sc_intmask |= BAH_RI; 618 1.1 chopps 619 1.40 wiz /* this also clears the RI flag interrupt: */ 620 1.25 is PUTREG(BAHCMD, BAH_RXBC(buffer)); 621 1.25 is PUTREG(BAHSTAT, sc->sc_intmask); 622 1.1 chopps 623 1.1 chopps #ifdef BAH_DEBUG 624 1.65 phx printf("%s: srint: restarted rx on buf %d\n", 625 1.64 chs device_xname(sc->sc_dev), buffer); 626 1.1 chopps #endif 627 1.1 chopps } 628 1.1 chopps splx(s); 629 1.1 chopps } 630 1.1 chopps 631 1.45 perry inline static void 632 1.59 dsl bah_tint(struct bah_softc *sc, int isr) 633 1.1 chopps { 634 1.14 chopps struct ifnet *ifp; 635 1.14 chopps 636 1.25 is bus_space_tag_t bst_r = sc->sc_bst_r; 637 1.25 is bus_space_handle_t regs = sc->sc_regs; 638 1.25 is 639 1.25 is 640 1.1 chopps int buffer; 641 1.14 chopps #ifdef BAHTIMINGS 642 1.1 chopps int clknow; 643 1.14 chopps #endif 644 1.1 chopps 645 1.14 chopps ifp = &(sc->sc_arccom.ac_if); 646 1.1 chopps buffer = sc->sc_tx_act; 647 1.1 chopps 648 1.6 chopps /* 649 1.43 perry * retransmit code: 650 1.41 wiz * Normal situations first for fast path: 651 1.14 chopps * If acknowledgement received ok or broadcast, we're ok. 652 1.43 perry * else if 653 1.43 perry */ 654 1.1 chopps 655 1.25 is if (isr & BAH_TMA || sc->sc_broadcast[buffer]) 656 1.75 thorpej if_statinc(ifp, if_opackets); 657 1.14 chopps #ifdef BAHRETRANSMIT 658 1.43 perry else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0 659 1.14 chopps && --sc->sc_retransmits[buffer] > 0) { 660 1.14 chopps /* retransmit same buffer */ 661 1.25 is PUTREG(BAHCMD, BAH_TX(buffer)); 662 1.14 chopps return; 663 1.14 chopps } 664 1.14 chopps #endif 665 1.3 chopps else 666 1.75 thorpej if_statinc(ifp, if_oerrors); 667 1.43 perry 668 1.43 perry 669 1.1 chopps /* We know we can accept another buffer at this point. */ 670 1.14 chopps ifp->if_flags &= ~IFF_OACTIVE; 671 1.1 chopps 672 1.1 chopps if (--sc->sc_tx_fillcount > 0) { 673 1.1 chopps 674 1.43 perry /* 675 1.1 chopps * start tx on other buffer. 676 1.1 chopps * This also clears the int flag 677 1.1 chopps */ 678 1.1 chopps buffer ^= 1; 679 1.1 chopps sc->sc_tx_act = buffer; 680 1.1 chopps 681 1.1 chopps /* 682 1.1 chopps * already given: 683 1.43 perry * sc->sc_intmask |= BAH_TA; 684 1.25 is * PUTREG(BAHSTAT, sc->sc_intmask); 685 1.1 chopps */ 686 1.25 is PUTREG(BAHCMD, BAH_TX(buffer)); 687 1.6 chopps /* init watchdog timer */ 688 1.14 chopps ifp->if_timer = ARCTIMEOUT; 689 1.1 chopps 690 1.1 chopps #if defined(BAH_DEBUG) && (BAH_DEBUG > 1) 691 1.43 perry printf("%s: tint: starting tx on buffer %d, status 0x%02x\n", 692 1.64 chs device_xname(sc->sc_dev), buffer, GETREG(BAHSTAT)); 693 1.1 chopps #endif 694 1.1 chopps } else { 695 1.1 chopps /* have to disable TX interrupt */ 696 1.25 is sc->sc_intmask &= ~BAH_TA; 697 1.25 is PUTREG(BAHSTAT, sc->sc_intmask); 698 1.6 chopps /* ... and watchdog timer */ 699 1.14 chopps ifp->if_timer = 0; 700 1.1 chopps 701 1.1 chopps #ifdef BAH_DEBUG 702 1.19 christos printf("%s: tint: no more buffers to send, status 0x%02x\n", 703 1.64 chs device_xname(sc->sc_dev), GETREG(BAHSTAT)); 704 1.1 chopps #endif 705 1.1 chopps } 706 1.1 chopps 707 1.25 is /* XXXX TODO */ 708 1.1 chopps #ifdef BAHSOFTCOPY 709 1.1 chopps /* schedule soft int to fill a new buffer for us */ 710 1.51 ad softint_schedule(sc->sc_txcookie); 711 1.1 chopps #else 712 1.69 ozaki if_schedule_deferred_start(ifp); 713 1.1 chopps #endif 714 1.1 chopps } 715 1.1 chopps 716 1.1 chopps /* 717 1.1 chopps * Our interrupt routine 718 1.1 chopps */ 719 1.1 chopps int 720 1.59 dsl bahintr(void *arg) 721 1.1 chopps { 722 1.25 is struct bah_softc *sc = arg; 723 1.25 is 724 1.25 is bus_space_tag_t bst_r = sc->sc_bst_r; 725 1.25 is bus_space_tag_t bst_m = sc->sc_bst_m; 726 1.25 is bus_space_handle_t regs = sc->sc_regs; 727 1.25 is bus_space_handle_t mem = sc->sc_mem; 728 1.25 is 729 1.11 chopps u_char isr, maskedisr; 730 1.1 chopps int buffer; 731 1.1 chopps u_long newsec; 732 1.1 chopps 733 1.25 is isr = GETREG(BAHSTAT); 734 1.11 chopps maskedisr = isr & sc->sc_intmask; 735 1.43 perry if (!maskedisr) 736 1.3 chopps return (0); 737 1.25 is do { 738 1.1 chopps 739 1.1 chopps #if defined(BAH_DEBUG) && (BAH_DEBUG>1) 740 1.25 is printf("%s: intr: status 0x%02x, intmask 0x%02x\n", 741 1.64 chs device_xname(sc->sc_dev), isr, sc->sc_intmask); 742 1.1 chopps #endif 743 1.1 chopps 744 1.25 is if (maskedisr & BAH_POR) { 745 1.43 perry /* 746 1.25 is * XXX We should never see this. Don't bother to store 747 1.25 is * the address. 748 1.25 is * sc->sc_arccom.ac_anaddr = GETMEM(BAHMACOFF); 749 1.25 is */ 750 1.25 is PUTREG(BAHCMD, BAH_CLR(CLR_POR)); 751 1.3 chopps log(LOG_WARNING, 752 1.25 is "%s: intr: got spurious power on reset int\n", 753 1.64 chs device_xname(sc->sc_dev)); 754 1.1 chopps } 755 1.43 perry 756 1.25 is if (maskedisr & BAH_RECON) { 757 1.16 is /* 758 1.25 is * we dont need to: 759 1.25 is * PUTREG(BAHCMD, BAH_CONF(CONF_LONG)); 760 1.16 is */ 761 1.25 is PUTREG(BAHCMD, BAH_CLR(CLR_RECONFIG)); 762 1.75 thorpej if_statinc(&sc->sc_arccom.ac_if, if_collisions); 763 1.43 perry 764 1.1 chopps /* 765 1.25 is * If less than 2 seconds per reconfig: 766 1.25 is * If ARC_EXCESSIVE_RECONFIGS 767 1.46 wiz * since last burst, complain and set threshold for 768 1.25 is * warnings to ARC_EXCESSIVE_RECONS_REWARN. 769 1.25 is * 770 1.25 is * This allows for, e.g., new stations on the cable, or 771 1.25 is * cable switching as long as it is over after 772 1.25 is * (normally) 16 seconds. 773 1.25 is * 774 1.25 is * XXX TODO: check timeout bits in status word and 775 1.25 is * double time if necessary. 776 1.1 chopps */ 777 1.43 perry 778 1.34 thorpej callout_stop(&sc->sc_recon_ch); 779 1.54 joerg newsec = time_second; 780 1.43 perry if ((newsec - sc->sc_recontime <= 2) && 781 1.25 is (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) { 782 1.25 is log(LOG_WARNING, 783 1.25 is "%s: excessive token losses, " 784 1.64 chs "cable problem?\n", device_xname(sc->sc_dev)); 785 1.25 is } 786 1.25 is sc->sc_recontime = newsec; 787 1.34 thorpej callout_reset(&sc->sc_recon_ch, 15 * hz, 788 1.34 thorpej bah_reconwatch, (void *)sc); 789 1.25 is } 790 1.25 is 791 1.25 is if (maskedisr & BAH_RI) { 792 1.25 is #if defined(BAH_DEBUG) && (BAH_DEBUG > 1) 793 1.65 phx printf("%s: intr: hard rint, act %d\n", 794 1.64 chs device_xname(sc->sc_dev), sc->sc_rx_act); 795 1.25 is #endif 796 1.1 chopps 797 1.25 is buffer = sc->sc_rx_act; 798 1.25 is /* look if buffer is marked invalid: */ 799 1.25 is if (GETMEM(buffer*512) == 0) { 800 1.25 is /* 801 1.25 is * invalid marked buffer (or illegally 802 1.25 is * configured sender) 803 1.25 is */ 804 1.43 perry log(LOG_WARNING, 805 1.40 wiz "%s: spurious RX interrupt or sender 0 " 806 1.64 chs " (ignored)\n", device_xname(sc->sc_dev)); 807 1.25 is /* 808 1.25 is * restart receiver on same buffer. 809 1.25 is * XXX maybe better reset interface? 810 1.25 is */ 811 1.25 is PUTREG(BAHCMD, BAH_RXBC(buffer)); 812 1.25 is } else { 813 1.25 is if (++sc->sc_rx_fillcount > 1) { 814 1.25 is sc->sc_intmask &= ~BAH_RI; 815 1.25 is PUTREG(BAHSTAT, sc->sc_intmask); 816 1.25 is } else { 817 1.25 is buffer ^= 1; 818 1.25 is sc->sc_rx_act = buffer; 819 1.43 perry 820 1.25 is /* 821 1.25 is * Start receiver on other receive 822 1.25 is * buffer. This also clears the RI 823 1.40 wiz * interrupt flag. 824 1.25 is */ 825 1.25 is PUTREG(BAHCMD, BAH_RXBC(buffer)); 826 1.25 is /* in RX intr, so mask is ok for RX */ 827 1.43 perry 828 1.1 chopps #ifdef BAH_DEBUG 829 1.65 phx printf("%s: strt rx for buf %u, " 830 1.25 is "stat 0x%02x\n", 831 1.64 chs device_xname(sc->sc_dev), sc->sc_rx_act, 832 1.61 snj GETREG(BAHSTAT)); 833 1.1 chopps #endif 834 1.25 is } 835 1.43 perry 836 1.1 chopps #ifdef BAHSOFTCOPY 837 1.25 is /* 838 1.25 is * this one starts a soft int to copy out 839 1.25 is * of the hw 840 1.25 is */ 841 1.51 ad softint_schedule(sc->sc_rxcookie); 842 1.1 chopps #else 843 1.25 is /* this one does the copy here */ 844 1.25 is bah_srint(sc); 845 1.1 chopps #endif 846 1.25 is } 847 1.25 is } 848 1.25 is if (maskedisr & BAH_TA) { 849 1.25 is bah_tint(sc, isr); 850 1.25 is } 851 1.25 is isr = GETREG(BAHSTAT); 852 1.25 is maskedisr = isr & sc->sc_intmask; 853 1.25 is } while (maskedisr); 854 1.25 is 855 1.25 is return (1); 856 1.25 is } 857 1.1 chopps 858 1.25 is void 859 1.59 dsl bah_reconwatch(void *arg) 860 1.25 is { 861 1.25 is struct bah_softc *sc = arg; 862 1.1 chopps 863 1.25 is if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) { 864 1.25 is sc->sc_reconcount = 0; 865 1.25 is log(LOG_WARNING, "%s: token valid again.\n", 866 1.64 chs device_xname(sc->sc_dev)); 867 1.25 is } 868 1.25 is sc->sc_reconcount = 0; 869 1.1 chopps } 870 1.1 chopps 871 1.25 is 872 1.1 chopps /* 873 1.43 perry * Process an ioctl request. 874 1.1 chopps * This code needs some work - it looks pretty ugly. 875 1.1 chopps */ 876 1.1 chopps int 877 1.59 dsl bah_ioctl(struct ifnet *ifp, u_long cmd, void *data) 878 1.1 chopps { 879 1.1 chopps struct bah_softc *sc; 880 1.35 augustss struct ifaddr *ifa; 881 1.25 is struct ifreq *ifr; 882 1.3 chopps int s, error; 883 1.1 chopps 884 1.3 chopps error = 0; 885 1.17 thorpej sc = ifp->if_softc; 886 1.1 chopps ifa = (struct ifaddr *)data; 887 1.25 is ifr = (struct ifreq *)data; 888 1.13 mycroft s = splnet(); 889 1.1 chopps 890 1.43 perry #if defined(BAH_DEBUG) && (BAH_DEBUG > 2) 891 1.65 phx printf("%s: ioctl() called, cmd = 0x%lx\n", 892 1.64 chs device_xname(sc->sc_dev), cmd); 893 1.1 chopps #endif 894 1.1 chopps 895 1.50 he switch (cmd) { 896 1.57 dyoung case SIOCINITIFADDR: 897 1.1 chopps ifp->if_flags |= IFF_UP; 898 1.57 dyoung bah_init(sc); 899 1.4 mycroft switch (ifa->ifa_addr->sa_family) { 900 1.1 chopps #ifdef INET 901 1.1 chopps case AF_INET: 902 1.25 is arp_ifinit(ifp, ifa); 903 1.1 chopps break; 904 1.1 chopps #endif 905 1.1 chopps default: 906 1.1 chopps break; 907 1.1 chopps } 908 1.1 chopps 909 1.1 chopps case SIOCSIFFLAGS: 910 1.57 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 911 1.57 dyoung break; 912 1.57 dyoung /* XXX re-use ether_ioctl() */ 913 1.57 dyoung switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { 914 1.57 dyoung case IFF_RUNNING: 915 1.1 chopps /* 916 1.43 perry * If interface is marked down and it is running, 917 1.1 chopps * then stop it. 918 1.1 chopps */ 919 1.1 chopps bah_stop(sc); 920 1.1 chopps ifp->if_flags &= ~IFF_RUNNING; 921 1.57 dyoung break; 922 1.57 dyoung case IFF_UP: 923 1.1 chopps /* 924 1.1 chopps * If interface is marked up and it is stopped, then 925 1.1 chopps * start it. 926 1.1 chopps */ 927 1.1 chopps bah_init(sc); 928 1.57 dyoung break; 929 1.43 perry } 930 1.1 chopps break; 931 1.1 chopps 932 1.25 is case SIOCADDMULTI: 933 1.25 is case SIOCDELMULTI: 934 1.49 dyoung switch (ifreq_getaddr(cmd, ifr)->sa_family) { 935 1.33 is case AF_INET: 936 1.33 is case AF_INET6: 937 1.25 is error = 0; 938 1.33 is break; 939 1.33 is default: 940 1.25 is error = EAFNOSUPPORT; 941 1.33 is break; 942 1.33 is } 943 1.25 is break; 944 1.4 mycroft 945 1.1 chopps default: 946 1.57 dyoung error = ether_ioctl(ifp, cmd, data); 947 1.1 chopps } 948 1.1 chopps 949 1.4 mycroft splx(s); 950 1.3 chopps return (error); 951 1.6 chopps } 952 1.6 chopps 953 1.6 chopps /* 954 1.6 chopps * watchdog routine for transmitter. 955 1.6 chopps * 956 1.6 chopps * We need this, because else a receiver whose hardware is alive, but whose 957 1.6 chopps * software has not enabled the Receiver, would make our hardware wait forever 958 1.6 chopps * Discovered this after 20 times reading the docs. 959 1.6 chopps * 960 1.77 rillig * Only thing we do is disable transmitter. We'll get a transmit timeout, 961 1.6 chopps * and the int handler will have to decide not to retransmit (in case 962 1.6 chopps * retransmission is implemented). 963 1.6 chopps * 964 1.25 is * This one assumes being called inside splnet() 965 1.6 chopps */ 966 1.6 chopps 967 1.6 chopps void 968 1.59 dsl bah_watchdog(struct ifnet *ifp) 969 1.6 chopps { 970 1.17 thorpej struct bah_softc *sc = ifp->if_softc; 971 1.6 chopps 972 1.25 is bus_space_tag_t bst_r = sc->sc_bst_r; 973 1.25 is bus_space_handle_t regs = sc->sc_regs; 974 1.25 is 975 1.25 is PUTREG(BAHCMD, BAH_TXDIS); 976 1.6 chopps return; 977 1.1 chopps } 978 1.25 is 979