1 /* $NetBSD: if_netdock_nubus.c,v 1.11 2005/12/24 23:24:01 perry Exp $ */ 2 3 /* 4 * Copyright (C) 2000,2002 Daishi Kato <daishi@axlight.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Daishi Kato 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Asante NetDock (for Duo series) driver 35 * the chip inside is not known 36 */ 37 38 /* 39 * The author would like to thank Takeo Kuwata <tkuwata@mac.com> for 40 * his help in stabilizing this driver. 41 */ 42 43 /***********************/ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: if_netdock_nubus.c,v 1.11 2005/12/24 23:24:01 perry Exp $"); 47 48 #include <sys/param.h> 49 #include <sys/device.h> 50 #include <sys/socket.h> 51 #include <sys/systm.h> 52 #include <sys/mbuf.h> 53 #include <sys/ioctl.h> 54 55 #include <net/if.h> 56 #include <net/if_dl.h> 57 #include <net/if_ether.h> 58 59 #include "opt_inet.h" 60 #ifdef INET 61 #include <netinet/in.h> 62 #include <netinet/if_inarp.h> 63 #endif 64 65 #include "bpfilter.h" 66 #if NBPFILTER > 0 67 #include <net/bpf.h> 68 #endif 69 70 #include <machine/bus.h> 71 #include <machine/viareg.h> 72 #include <mac68k/nubus/nubus.h> 73 74 /***********************/ 75 76 #define NETDOCK_DEBUG 77 78 #define NETDOCK_NUBUS_CATEGORY 0x0020 79 #define NETDOCK_NUBUS_TYPE 0x0003 80 #define NETDOCK_NUBUS_DRSW 0x0103 81 #define NETDOCK_NUBUS_DRHW 0x0100 82 83 #define ETHERMICRODOCK_NUBUS_CATEGORY 0x0020 84 #define ETHERMICRODOCK_NUBUS_TYPE 0x0003 85 #define ETHERMICRODOCK_NUBUS_DRSW 0x0102 86 #define ETHERMICRODOCK_NUBUS_DRHW 0x0100 87 88 #define REG_ISR 0x000c 89 #define REG_000E 0x000e 90 #define REG_0000 0x0000 91 #define REG_0002 0x0002 92 #define REG_0004 0x0004 93 #define REG_0006 0x0006 94 #define REG_DATA 0x0008 95 #define REG_EFD00 0xefd00 96 97 #define ISR_ALL 0x3300 98 #define ISR_TX 0x0200 99 #define ISR_RX 0x0100 100 #define ISR_READY 0x0800 101 #define ISR_BIT_0C 0x1000 102 #define ISR_BIT_0D 0x2000 103 #define ISR_MASK 0x0033 104 #define ISR_BIT_03 0x0008 105 106 #define REG_0002_BIT_04 0x0010 107 #define REG_0000_BIT_08 0x0100 108 #define REG_0004_BIT_0F 0x8000 109 #define REG_0004_BIT_07 0x0080 110 #define REG_DATA_BIT_02 0x0004 111 #define REG_DATA_BIT_03 0x0008 112 #define REG_DATA_BIT_04 0x0010 113 #define REG_DATA_BIT_05 0x0020 114 #define REG_DATA_BIT_08 0x0100 115 #define REG_DATA_BIT_07 0x0080 116 #define REG_DATA_BIT_0F 0x8000 117 118 /***********************/ 119 120 typedef struct netdock_softc { 121 struct device sc_dev; 122 struct ethercom sc_ethercom; 123 #define sc_if sc_ethercom.ec_if 124 125 bus_space_tag_t sc_regt; 126 bus_space_handle_t sc_regh; 127 128 u_int8_t sc_enaddr[ETHER_ADDR_LEN]; 129 130 } netdock_softc_t; 131 132 /***********************/ 133 134 static int netdock_nubus_match(struct device *, struct cfdata *, void *); 135 static void netdock_nubus_attach(struct device *, struct device *, void *); 136 static int netdock_nb_get_enaddr(bus_space_tag_t, bus_space_handle_t, 137 struct nubus_attach_args *, u_int8_t *); 138 #ifdef NETDOCK_DEBUG_DRIVER 139 static void netdock_print_driver(bus_space_tag_t, bus_space_handle_t, 140 struct nubus_attach_args *); 141 #endif 142 143 int netdock_setup(struct netdock_softc *, u_int8_t *); 144 void netdock_intr(void *); 145 146 static void netdock_watchdog(struct ifnet *); 147 static int netdock_init(struct netdock_softc *); 148 static int netdock_stop(struct netdock_softc *); 149 static int netdock_ioctl(struct ifnet *, u_long, caddr_t); 150 static void netdock_start(struct ifnet *); 151 static void netdock_reset(struct netdock_softc *); 152 static void netdock_txint(struct netdock_softc *); 153 static void netdock_rxint(struct netdock_softc *); 154 155 static u_int netdock_put(struct netdock_softc *, struct mbuf *); 156 static int netdock_read(struct netdock_softc *, int); 157 static struct mbuf *netdock_get(struct netdock_softc *, int); 158 159 /***********************/ 160 161 #define NIC_GET_1(sc, o) (bus_space_read_1((sc)->sc_regt, \ 162 (sc)->sc_regh, (o))) 163 #define NIC_PUT_1(sc, o, val) (bus_space_write_1((sc)->sc_regt, \ 164 (sc)->sc_regh, (o), (val))) 165 #define NIC_GET_2(sc, o) (bus_space_read_2((sc)->sc_regt, \ 166 (sc)->sc_regh, (o))) 167 #define NIC_PUT_2(sc, o, val) (bus_space_write_2((sc)->sc_regt, \ 168 (sc)->sc_regh, (o), (val))) 169 #define NIC_GET_4(sc, o) (bus_space_read_4((sc)->sc_regt, \ 170 (sc)->sc_regh, (o))) 171 #define NIC_PUT_4(sc, o, val) (bus_space_write_4((sc)->sc_regt, \ 172 (sc)->sc_regh, (o), (val))) 173 174 #define NIC_BSET(sc, o, b) \ 175 __asm volatile("bset %0,%1" : : "di" ((u_short)(b)), \ 176 "g" (*(u_int8_t *)((sc)->sc_regh.base + (o)))) 177 #define NIC_BCLR(sc, o, b) \ 178 __asm volatile("bclr %0,%1" : : "di" ((u_short)(b)), \ 179 "g" (*(u_int8_t *)((sc)->sc_regh.base + (o)))) 180 #define NIC_ANDW(sc, o, b) \ 181 __asm volatile("andw %0,%1" : : "di" ((u_short)(b)), \ 182 "g" (*(u_int8_t *)((sc)->sc_regh.base + (o)))) 183 #define NIC_ORW(sc, o, b) \ 184 __asm volatile("orw %0,%1" : : "di" ((u_short)(b)), \ 185 "g" (*(u_int8_t *)((sc)->sc_regh.base + (o)))) 186 187 188 /***********************/ 189 190 CFATTACH_DECL(netdock_nubus, sizeof(struct netdock_softc), 191 netdock_nubus_match, netdock_nubus_attach, NULL, NULL); 192 193 /***********************/ 194 195 static int 196 netdock_nubus_match(struct device *parent, struct cfdata *cf, void *aux) 197 { 198 struct nubus_attach_args *na = (struct nubus_attach_args *)aux; 199 bus_space_handle_t bsh; 200 int rv; 201 202 if (bus_space_map(na->na_tag, NUBUS_SLOT2PA(na->slot), 203 NBMEMSIZE, 0, &bsh)) 204 return (0); 205 206 rv = 0; 207 208 if (na->category == NETDOCK_NUBUS_CATEGORY && 209 na->type == NETDOCK_NUBUS_TYPE && 210 na->drsw == NETDOCK_NUBUS_DRSW) { 211 /* assuming this IS Asante NetDock */ 212 rv = 1; 213 } 214 215 if (na->category == ETHERMICRODOCK_NUBUS_CATEGORY && 216 na->type == ETHERMICRODOCK_NUBUS_TYPE && 217 na->drsw == ETHERMICRODOCK_NUBUS_DRSW) { 218 /* assuming this IS Newer EtherMicroDock */ 219 rv = 1; 220 } 221 222 bus_space_unmap(na->na_tag, bsh, NBMEMSIZE); 223 224 return rv; 225 } 226 227 static void 228 netdock_nubus_attach(struct device *parent, struct device *self, void *aux) 229 { 230 struct netdock_softc *sc = (struct netdock_softc *)self; 231 struct nubus_attach_args *na = (struct nubus_attach_args *)aux; 232 bus_space_tag_t bst; 233 bus_space_handle_t bsh; 234 u_int8_t enaddr[ETHER_ADDR_LEN]; 235 const char *cardtype; 236 237 bst = na->na_tag; 238 if (bus_space_map(bst, NUBUS_SLOT2PA(na->slot), NBMEMSIZE, 0, &bsh)) { 239 printf(": failed to map memory space.\n"); 240 return; 241 } 242 243 sc->sc_regt = bst; 244 cardtype = nubus_get_card_name(bst, bsh, na->fmt); 245 246 #ifdef NETDOCK_DEBUG_DRIVER 247 netdock_print_driver(bst, bsh, na); 248 #endif 249 250 if (netdock_nb_get_enaddr(bst, bsh, na, enaddr)) { 251 printf(": can't find MAC address.\n"); 252 bus_space_unmap(bst, bsh, NBMEMSIZE); 253 return; 254 } 255 256 if (bus_space_subregion(bst, bsh, 0xe00300, 0xf0000, &sc->sc_regh)) { 257 printf(": failed to map register space.\n"); 258 bus_space_unmap(bst, bsh, NBMEMSIZE); 259 return; 260 } 261 262 printf(": %s\n", cardtype); 263 264 if (netdock_setup(sc, enaddr)) { 265 bus_space_unmap(bst, bsh, NBMEMSIZE); 266 return; 267 } 268 269 add_nubus_intr(na->slot, netdock_intr, (void *)sc); 270 271 return; 272 } 273 274 static int 275 netdock_nb_get_enaddr(bus_space_tag_t bst, bus_space_handle_t bsh, 276 struct nubus_attach_args *na, u_int8_t *ep) 277 { 278 nubus_dir dir; 279 nubus_dirent dirent; 280 281 /* 282 * these hardwired resource IDs are only for NetDock 283 */ 284 nubus_get_main_dir(na->fmt, &dir); 285 if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x81, &dirent) <= 0) 286 return 1; 287 nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir); 288 if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x80, &dirent) <= 0) 289 return 1; 290 if (nubus_get_ind_data(bst, bsh, na->fmt, &dirent, 291 ep, ETHER_ADDR_LEN) <= 0) 292 return 1; 293 294 return 0; 295 } 296 297 #ifdef NETDOCK_DEBUG_DRIVER 298 static void 299 netdock_print_driver(bus_space_tag_t bst, bus_space_handle_t bsh, 300 struct nubus_attach_args *na) 301 { 302 #define HEADSIZE (8+4) 303 #define CODESIZE (6759-4) 304 unsigned char mydata[HEADSIZE + CODESIZE]; 305 nubus_dir dir; 306 nubus_dirent dirent; 307 int i, rv; 308 309 nubus_get_main_dir(na->fmt, &dir); 310 rv = nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x81, &dirent); 311 if (rv <= 0) { 312 printf(": can't find sResource.\n"); 313 return; 314 } 315 nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir); 316 if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, NUBUS_RSRC_DRVRDIR, 317 &dirent) <= 0) { 318 printf(": can't find sResource.\n"); 319 return; 320 } 321 if (nubus_get_ind_data(bst, bsh, na->fmt, 322 &dirent, mydata, HEADSIZE+CODESIZE) <= 0) { 323 printf(": can't find indirect data.\n"); 324 return; 325 } 326 printf("\n########## begin driver dir"); 327 for (i = 0; i < HEADSIZE; i++) { 328 if (i % 16 == 0) 329 printf("\n%02x:",i); 330 printf(" %02x", mydata[i]); 331 } 332 printf("\n########## begin driver code"); 333 for (i = 0; i < CODESIZE; i++) { 334 if (i % 16 == 0) 335 printf("\n%02x:",i); 336 printf(" %02x", mydata[i + HEADSIZE]); 337 } 338 #if 0 339 printf("\n########## begin driver code (partial)\n"); 340 #define PARTSIZE 256 341 #define OFFSET 0x1568 342 for (i = OFFSET; i < OFFSET + PARTSIZE; i++) { 343 if ((i - OFFSET) % 16 == 0) 344 printf("\n%02x:",i); 345 printf(" %02x", mydata[i + HEADSIZE]); 346 } 347 #endif 348 printf("\n########## end\n"); 349 } 350 #endif 351 352 353 int 354 netdock_setup(struct netdock_softc *sc, u_int8_t *lladdr) 355 { 356 struct ifnet *ifp = &sc->sc_if; 357 358 memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN); 359 printf("%s: Ethernet address %s\n", 360 sc->sc_dev.dv_xname, ether_sprintf(lladdr)); 361 362 memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 363 ifp->if_softc = sc; 364 ifp->if_ioctl = netdock_ioctl; 365 ifp->if_start = netdock_start; 366 ifp->if_flags = 367 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 368 ifp->if_watchdog = netdock_watchdog; 369 370 if_attach(ifp); 371 ether_ifattach(ifp, lladdr); 372 373 return (0); 374 } 375 376 static int 377 netdock_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 378 { 379 struct ifaddr *ifa; 380 struct ifreq *ifr; 381 struct netdock_softc *sc = ifp->if_softc; 382 int s = splnet(); 383 int err = 0; 384 int temp; 385 386 switch (cmd) { 387 case SIOCSIFADDR: 388 ifa = (struct ifaddr *)data; 389 ifp->if_flags |= IFF_UP; 390 switch (ifa->ifa_addr->sa_family) { 391 #ifdef INET 392 case AF_INET: 393 (void)netdock_init(sc); 394 arp_ifinit(ifp, ifa); 395 break; 396 #endif 397 default: 398 (void)netdock_init(sc); 399 break; 400 } 401 break; 402 403 case SIOCSIFFLAGS: 404 if ((ifp->if_flags & IFF_UP) == 0 && 405 (ifp->if_flags & IFF_RUNNING) != 0) { 406 netdock_stop(sc); 407 ifp->if_flags &= ~IFF_RUNNING; 408 } else if ((ifp->if_flags & IFF_UP) != 0 && 409 (ifp->if_flags & IFF_RUNNING) == 0) { 410 (void)netdock_init(sc); 411 } else { 412 temp = ifp->if_flags & IFF_UP; 413 netdock_reset(sc); 414 ifp->if_flags |= temp; 415 netdock_start(ifp); 416 } 417 break; 418 419 case SIOCADDMULTI: 420 case SIOCDELMULTI: 421 ifr = (struct ifreq *)data; 422 if (cmd == SIOCADDMULTI) 423 err = ether_addmulti(ifr, &sc->sc_ethercom); 424 else 425 err = ether_delmulti(ifr, &sc->sc_ethercom); 426 427 if (err == ENETRESET) { 428 if (ifp->if_flags & IFF_RUNNING) { 429 temp = ifp->if_flags & IFF_UP; 430 netdock_reset(sc); 431 ifp->if_flags |= temp; 432 } 433 err = 0; 434 } 435 break; 436 default: 437 err = EINVAL; 438 break; 439 } 440 splx(s); 441 return (err); 442 } 443 444 static void 445 netdock_start(struct ifnet *ifp) 446 { 447 struct netdock_softc *sc = ifp->if_softc; 448 struct mbuf *m; 449 450 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 451 return; 452 453 while (1) { 454 IF_DEQUEUE(&ifp->if_snd, m); 455 if (m == 0) 456 return; 457 458 if ((m->m_flags & M_PKTHDR) == 0) 459 panic("%s: netdock_start: no header mbuf", 460 sc->sc_dev.dv_xname); 461 462 #if NBPFILTER > 0 463 if (ifp->if_bpf) 464 bpf_mtap(ifp->if_bpf, m); 465 #endif 466 467 if ((netdock_put(sc, m)) == 0) { 468 IF_PREPEND(&ifp->if_snd, m); 469 return; 470 } 471 472 ifp->if_opackets++; 473 } 474 475 } 476 477 static void 478 netdock_reset(struct netdock_softc *sc) 479 { 480 481 netdock_stop(sc); 482 netdock_init(sc); 483 } 484 485 static int 486 netdock_init(struct netdock_softc *sc) 487 { 488 int s; 489 int saveisr; 490 int savetmp; 491 492 if (sc->sc_if.if_flags & IFF_RUNNING) 493 return (0); 494 495 s = splnet(); 496 497 /* 0606 */ 498 NIC_PUT_2(sc, REG_000E, 0x0200); 499 NIC_PUT_2(sc, REG_ISR , 0); 500 NIC_PUT_2(sc, REG_000E, 0); 501 502 NIC_PUT_2(sc, REG_0000, 0x8104); 503 NIC_PUT_2(sc, REG_0004, 0x0043); 504 NIC_PUT_2(sc, REG_000E, 0x0100); 505 NIC_PUT_2(sc, REG_0002, 0x6618); 506 NIC_PUT_2(sc, REG_0000, 0x8010); 507 508 NIC_PUT_1(sc, REG_0004 + 0, sc->sc_enaddr[0]); 509 NIC_PUT_1(sc, REG_0004 + 1, sc->sc_enaddr[1]); 510 NIC_PUT_1(sc, REG_0004 + 2, sc->sc_enaddr[2]); 511 NIC_PUT_1(sc, REG_0004 + 3, sc->sc_enaddr[3]); 512 NIC_PUT_1(sc, REG_0004 + 4, sc->sc_enaddr[4]); 513 NIC_PUT_1(sc, REG_0004 + 5, sc->sc_enaddr[5]); 514 515 NIC_PUT_2(sc, REG_ISR , 0x2008); 516 NIC_PUT_2(sc, REG_000E, 0x0200); 517 NIC_PUT_2(sc, REG_0000, 0x4000); 518 NIC_PUT_2(sc, REG_ISR, ISR_MASK); 519 520 521 /* 1320 */ 522 saveisr = NIC_GET_2(sc, REG_ISR); 523 NIC_PUT_2(sc, REG_ISR , 0); 524 savetmp = NIC_GET_2(sc, REG_000E); 525 NIC_PUT_2(sc, REG_000E, 0x0100); 526 NIC_ANDW(sc, REG_ISR, ~ISR_BIT_03); 527 NIC_PUT_2(sc, REG_000E, savetmp); 528 529 /* 1382 */ 530 savetmp = NIC_GET_2(sc, REG_000E); 531 NIC_PUT_2(sc, REG_000E, 0x0100); 532 NIC_ORW(sc, REG_ISR, ISR_BIT_03); 533 NIC_PUT_2(sc, REG_000E, savetmp); 534 NIC_PUT_2(sc, REG_ISR , saveisr); 535 536 537 sc->sc_if.if_flags |= IFF_RUNNING; 538 sc->sc_if.if_flags &= ~IFF_OACTIVE; 539 540 splx(s); 541 return (0); 542 } 543 544 static int 545 netdock_stop(struct netdock_softc *sc) 546 { 547 int s = splnet(); 548 549 sc->sc_if.if_timer = 0; 550 sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP); 551 552 splx(s); 553 return (0); 554 } 555 556 static void 557 netdock_watchdog(struct ifnet *ifp) 558 { 559 struct netdock_softc *sc = ifp->if_softc; 560 int tmp; 561 562 printf("netdock_watchdog: resetting chip\n"); 563 tmp = ifp->if_flags & IFF_UP; 564 netdock_reset(sc); 565 ifp->if_flags |= tmp; 566 } 567 568 static u_int 569 netdock_put(struct netdock_softc *sc, struct mbuf *m0) 570 { 571 struct mbuf *m; 572 u_int totlen = 0; 573 u_int tmplen; 574 int isr; 575 int timeout; 576 int tmp; 577 u_int i; 578 579 for (m = m0; m; m = m->m_next) 580 totlen += m->m_len; 581 582 if (totlen >= ETHER_MAX_LEN) 583 panic("%s: netdock_put: packet overflow", sc->sc_dev.dv_xname); 584 585 totlen += 6; 586 tmplen = totlen; 587 tmplen &= 0xff00; 588 tmplen |= 0x2000; 589 NIC_PUT_2(sc, REG_0000, tmplen); 590 591 timeout = 0x3000; 592 while ((((isr = NIC_GET_2(sc, REG_ISR)) & ISR_READY) == 0) && 593 timeout--) { 594 if (isr & ISR_TX) 595 netdock_txint(sc); 596 } 597 if (timeout == 0) 598 return (0); 599 600 tmp = NIC_GET_2(sc, REG_0002); 601 tmp <<= 8; 602 NIC_PUT_2(sc, REG_0002, tmp); 603 NIC_PUT_2(sc, REG_0006, 0x240); 604 NIC_GET_2(sc, REG_ISR); 605 tmplen = ((totlen << 8) & 0xfe00) | ((totlen >> 8) & 0x00ff); 606 NIC_PUT_2(sc, REG_DATA, tmplen); 607 608 for (m = m0; m; m = m->m_next) { 609 u_char *data = mtod(m, u_char *); 610 int len = m->m_len; 611 int len4 = len >> 2; 612 u_int32_t *data4 = (u_int32_t *)data; 613 for (i = 0; i < len4; i++) 614 NIC_PUT_4(sc, REG_DATA, data4[i]); 615 for (i = len4 << 2; i < len; i++) 616 NIC_PUT_1(sc, REG_DATA, data[i]); 617 } 618 619 if (totlen & 0x01) 620 NIC_PUT_2(sc, REG_DATA, 0x2020); 621 else 622 NIC_PUT_2(sc, REG_DATA, 0); 623 624 NIC_PUT_2(sc, REG_0000, 0xc000); 625 626 m_freem(m0); 627 /* sc->sc_if.if_timer = 5; */ 628 return (totlen); 629 } 630 631 void 632 netdock_intr(void *arg) 633 { 634 struct netdock_softc *sc = (struct netdock_softc *)arg; 635 int isr; 636 int tmp; 637 638 NIC_PUT_2(sc, REG_ISR, 0); 639 while ((isr = (NIC_GET_2(sc, REG_ISR) & ISR_ALL)) != 0) { 640 if (isr & ISR_TX) 641 netdock_txint(sc); 642 643 if (isr & ISR_RX) 644 netdock_rxint(sc); 645 646 if (isr & (ISR_BIT_0C | ISR_BIT_0D)) { 647 if (isr & ISR_BIT_0C) { 648 NIC_PUT_2(sc, REG_000E, 0); 649 NIC_BSET(sc, REG_0004, 0x08); 650 NIC_PUT_2(sc, REG_000E, 0x0200); 651 } 652 if (isr & ISR_BIT_0D) { 653 NIC_PUT_2(sc, REG_000E, 0); 654 tmp = NIC_GET_2(sc, REG_0002); 655 if (tmp & REG_0002_BIT_04) 656 NIC_GET_2(sc, REG_0006); 657 tmp = NIC_GET_2(sc, REG_0000); 658 if (tmp & REG_0000_BIT_08) 659 NIC_BSET(sc, REG_0000, 0x08); 660 NIC_PUT_2(sc, REG_000E, 0x0200); 661 } 662 NIC_PUT_2(sc, REG_ISR, isr); 663 } 664 } 665 NIC_PUT_2(sc, REG_ISR, ISR_MASK); 666 } 667 668 static void 669 netdock_txint(struct netdock_softc *sc) 670 { 671 struct ifnet *ifp = &sc->sc_if; 672 int savereg0002; 673 int reg0004; 674 int regdata; 675 676 ifp->if_flags &= ~IFF_OACTIVE; 677 ifp->if_timer = 0; 678 679 savereg0002 = NIC_GET_2(sc, REG_0002); 680 681 while (((reg0004 = NIC_GET_2(sc, REG_0004)) & REG_0004_BIT_0F) == 0) { 682 NIC_PUT_2(sc, REG_0002, reg0004); 683 NIC_PUT_2(sc, REG_0006, 0x0060); 684 NIC_GET_2(sc, REG_ISR); 685 regdata = NIC_GET_2(sc, REG_DATA); 686 if ((regdata & REG_DATA_BIT_08) == 0) { 687 /* ifp->if_collisions++; */ 688 if (regdata & REG_DATA_BIT_07) 689 /* ifp->if_oerrors++; */ 690 NIC_PUT_2(sc, REG_000E, 0); 691 NIC_ORW(sc, REG_0000, 0x0100); 692 NIC_PUT_2(sc, REG_000E, 0x0200); 693 } 694 NIC_GET_2(sc ,REG_DATA); 695 696 if (regdata & REG_DATA_BIT_0F) 697 NIC_GET_4(sc, REG_EFD00); 698 NIC_PUT_2(sc, REG_0000, 0xa000); 699 NIC_PUT_2(sc, REG_ISR, ISR_TX); 700 } 701 702 NIC_PUT_2(sc, REG_0002, savereg0002); 703 NIC_PUT_2(sc, REG_000E, 0); 704 NIC_GET_2(sc, REG_0006); 705 NIC_PUT_2(sc, REG_000E, 0x0200); 706 NIC_PUT_2(sc, REG_0006, 0); 707 } 708 709 static void 710 netdock_rxint(struct netdock_softc *sc) 711 { 712 struct ifnet *ifp = &sc->sc_if; 713 int regdata1; 714 int regdata2; 715 u_int len; 716 int timeout; 717 718 while ((NIC_GET_2(sc, REG_0004) & REG_0004_BIT_07) == 0) { 719 NIC_GET_2(sc, REG_ISR); 720 NIC_PUT_2(sc, REG_0006, 0x00e0); 721 NIC_GET_2(sc, REG_ISR); 722 regdata1 = NIC_GET_2(sc, REG_DATA); 723 regdata2 = NIC_GET_2(sc, REG_DATA); 724 len = ((regdata2 << 8) & 0x0700) | ((regdata2 >> 8) & 0x00ff); 725 726 #if 0 727 printf("netdock_rxint: r1=0x%04x, r2=0x%04x, len=%d\n", 728 regdata1, regdata2, len); 729 #endif 730 731 if ((regdata1 & REG_DATA_BIT_04) == 0) 732 len -= 2; 733 734 /* CRC is included with the packet; trim it off. */ 735 len -= ETHER_CRC_LEN; 736 737 if ((regdata1 & 0x00ac) == 0) { 738 if (netdock_read(sc, len)) 739 ifp->if_ipackets++; 740 else 741 ifp->if_ierrors++; 742 } else { 743 ifp->if_ierrors++; 744 745 if (regdata1 & REG_DATA_BIT_02) 746 NIC_GET_4(sc, REG_EFD00); 747 if (regdata1 & REG_DATA_BIT_03) 748 ; 749 if (regdata1 & REG_DATA_BIT_05) 750 NIC_GET_4(sc, REG_EFD00); 751 if (regdata1 & REG_DATA_BIT_07) 752 ; 753 } 754 755 timeout = 0x14; 756 while ((NIC_GET_2(sc, REG_0000) & REG_0000_BIT_08) && timeout--) 757 ; 758 if (timeout == 0) 759 ; 760 761 NIC_PUT_2(sc, REG_0000, 0x8000); 762 } 763 NIC_PUT_2(sc, REG_0006, 0); 764 } 765 766 static int 767 netdock_read(struct netdock_softc *sc, int len) 768 { 769 struct ifnet *ifp = &sc->sc_if; 770 struct mbuf *m; 771 772 m = netdock_get(sc, len); 773 if (m == 0) 774 return (0); 775 776 #if NBPFILTER > 0 777 if (ifp->if_bpf) 778 bpf_mtap(ifp->if_bpf, m); 779 #endif 780 781 (*ifp->if_input)(ifp, m); 782 783 return (1); 784 } 785 786 static struct mbuf * 787 netdock_get(struct netdock_softc *sc, int datalen) 788 { 789 struct mbuf *m, *top, **mp; 790 u_char *data; 791 int i; 792 int len; 793 int len4; 794 u_int32_t *data4; 795 796 MGETHDR(m, M_DONTWAIT, MT_DATA); 797 if (m == NULL) 798 return (NULL); 799 m->m_pkthdr.rcvif = &sc->sc_if; 800 m->m_pkthdr.len = datalen; 801 len = MHLEN; 802 top = NULL; 803 mp = ⊤ 804 805 while (datalen > 0) { 806 if (top) { 807 MGET(m, M_DONTWAIT, MT_DATA); 808 if (m == 0) { 809 m_freem(top); 810 return (NULL); 811 } 812 len = MLEN; 813 } 814 if (datalen >= MINCLSIZE) { 815 MCLGET(m, M_DONTWAIT); 816 if ((m->m_flags & M_EXT) == 0) { 817 if (top) 818 m_freem(top); 819 return (NULL); 820 } 821 len = MCLBYTES; 822 } 823 824 if (mp == &top) { 825 caddr_t newdata = (caddr_t) 826 ALIGN(m->m_data + sizeof(struct ether_header)) - 827 sizeof(struct ether_header); 828 len -= newdata - m->m_data; 829 m->m_data = newdata; 830 } 831 832 m->m_len = len = min(datalen, len); 833 834 data = mtod(m, u_char *); 835 len4 = len >> 2; 836 data4 = (u_int32_t *)data; 837 for (i = 0; i < len4; i++) 838 data4[i] = NIC_GET_4(sc, REG_DATA); 839 for (i = len4 << 2; i < len; i++) 840 data[i] = NIC_GET_1(sc, REG_DATA); 841 842 datalen -= len; 843 *mp = m; 844 mp = &m->m_next; 845 } 846 847 return (top); 848 } 849