1 /* $NetBSD: if_iy.c,v 1.12 1997/04/24 08:05:23 mycroft Exp $ */ 2 /* #define IYDEBUG */ 3 /* #define IYMEMDEBUG */ 4 /*- 5 * Copyright (c) 1996 Ignatios Souvatzis. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product contains software developed by Ignatios Souvatzis for 19 * the NetBSD project. 20 * 4. The names of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "bpfilter.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/mbuf.h> 41 #include <sys/buf.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 #include <sys/ioctl.h> 45 #include <sys/errno.h> 46 #include <sys/syslog.h> 47 #include <sys/device.h> 48 49 #include <net/if.h> 50 #include <net/if_types.h> 51 #include <net/if_dl.h> 52 53 #include <net/if_ether.h> 54 55 #if NBPFILTER > 0 56 #include <net/bpf.h> 57 #include <net/bpfdesc.h> 58 #endif 59 60 #ifdef INET 61 #include <netinet/in.h> 62 #include <netinet/in_systm.h> 63 #include <netinet/in_var.h> 64 #include <netinet/ip.h> 65 #include <netinet/if_inarp.h> 66 #endif 67 68 #ifdef NS 69 #include <netns/ns.h> 70 #include <netns/ns_if.h> 71 #endif 72 73 #include <vm/vm.h> 74 75 #include <machine/cpu.h> 76 #include <machine/bus.h> 77 #include <machine/intr.h> 78 79 #include <dev/isa/isareg.h> 80 #include <dev/isa/isavar.h> 81 #include <dev/ic/i82595reg.h> 82 83 #define ETHER_MIN_LEN (ETHERMIN + sizeof(struct ether_header) + 4) 84 #define ETHER_MAX_LEN (ETHERMTU + sizeof(struct ether_header) + 4) 85 86 /* 87 * Ethernet status, per interface. 88 */ 89 struct iy_softc { 90 struct device sc_dev; 91 void *sc_ih; 92 93 bus_space_tag_t sc_iot; 94 bus_space_handle_t sc_ioh; 95 96 struct ethercom sc_ethercom; 97 98 #define MAX_MBS 8 99 struct mbuf *mb[MAX_MBS]; 100 int next_mb, last_mb; 101 102 int mappedirq; 103 104 int hard_vers; 105 106 int promisc; 107 108 int sram, tx_size, rx_size; 109 110 int tx_start, tx_end, tx_last; 111 int rx_start; 112 113 #ifdef IYDEBUG 114 int sc_debug; 115 #endif 116 }; 117 118 void iywatchdog __P((struct ifnet *)); 119 int iyioctl __P((struct ifnet *, u_long, caddr_t)); 120 int iyintr __P((void *)); 121 void iyinit __P((struct iy_softc *)); 122 void iystop __P((struct iy_softc *)); 123 void iystart __P((struct ifnet *)); 124 125 void iy_intr_rx __P((struct iy_softc *)); 126 void iy_intr_tx __P((struct iy_softc *)); 127 128 void iyreset __P((struct iy_softc *)); 129 void iy_readframe __P((struct iy_softc *, int)); 130 void iy_drop_packet_buffer __P((struct iy_softc *)); 131 void iy_find_mem_size __P((struct iy_softc *)); 132 void iyrint __P((struct iy_softc *)); 133 void iytint __P((struct iy_softc *)); 134 void iyxmit __P((struct iy_softc *)); 135 void iyget __P((struct iy_softc *, bus_space_tag_t, bus_space_handle_t, int)); 136 void iymbuffill __P((void *)); 137 void iymbufempty __P((void *)); 138 void iyprobemem __P((struct iy_softc *)); 139 static __inline void eepromwritebit __P((bus_space_tag_t, bus_space_handle_t, 140 int)); 141 static __inline int eepromreadbit __P((bus_space_tag_t, bus_space_handle_t)); 142 /* 143 * void iymeminit __P((void *, struct iy_softc *)); 144 * static int iy_mc_setup __P((struct iy_softc *, void *)); 145 * static void iy_mc_reset __P((struct iy_softc *)); 146 */ 147 #ifdef IYDEBUGX 148 void print_rbd __P((volatile struct iy_recv_buf_desc *)); 149 150 int in_ifrint = 0; 151 int in_iftint = 0; 152 #endif 153 154 int iyprobe __P((struct device *, void *, void *)); 155 void iyattach __P((struct device *, struct device *, void *)); 156 157 static u_int16_t eepromread __P((bus_space_tag_t, bus_space_handle_t, int)); 158 159 static int eepromreadall __P((bus_space_tag_t, bus_space_handle_t, u_int16_t *, 160 int)); 161 162 struct cfattach iy_ca = { 163 sizeof(struct iy_softc), iyprobe, iyattach 164 }; 165 166 struct cfdriver iy_cd = { 167 NULL, "iy", DV_IFNET 168 }; 169 170 static u_int8_t eepro_irqmap[] = EEPP_INTMAP; 171 static u_int8_t eepro_revirqmap[] = EEPP_RINTMAP; 172 173 int 174 iyprobe(parent, match, aux) 175 struct device *parent; 176 void *match, *aux; 177 { 178 struct isa_attach_args *ia = aux; 179 u_int16_t eaddr[8]; 180 181 bus_space_tag_t iot; 182 bus_space_handle_t ioh; 183 184 u_int8_t c, d; 185 186 iot = ia->ia_iot; 187 188 if (bus_space_map(iot, ia->ia_iobase, 16, 0, &ioh)) 189 return 0; 190 191 /* try to find the round robin sig: */ 192 193 c = bus_space_read_1(iot, ioh, ID_REG); 194 if ((c & ID_REG_MASK) != ID_REG_SIG) 195 goto out; 196 197 d = bus_space_read_1(iot, ioh, ID_REG); 198 if ((d & ID_REG_MASK) != ID_REG_SIG) 199 goto out; 200 201 if (((d-c) & R_ROBIN_BITS) != 0x40) 202 goto out; 203 204 d = bus_space_read_1(iot, ioh, ID_REG); 205 if ((d & ID_REG_MASK) != ID_REG_SIG) 206 goto out; 207 208 if (((d-c) & R_ROBIN_BITS) != 0x80) 209 goto out; 210 211 d = bus_space_read_1(iot, ioh, ID_REG); 212 if ((d & ID_REG_MASK) != ID_REG_SIG) 213 goto out; 214 215 if (((d-c) & R_ROBIN_BITS) != 0xC0) 216 goto out; 217 218 d = bus_space_read_1(iot, ioh, ID_REG); 219 if ((d & ID_REG_MASK) != ID_REG_SIG) 220 goto out; 221 222 if (((d-c) & R_ROBIN_BITS) != 0x00) 223 goto out; 224 225 #ifdef IYDEBUG 226 printf("iyprobe verified working ID reg.\n"); 227 #endif 228 229 if (eepromreadall(iot, ioh, eaddr, 8)) 230 goto out; 231 232 if (ia->ia_irq == IRQUNK) 233 ia->ia_irq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int]; 234 235 if (ia->ia_irq >= sizeof(eepro_revirqmap)) 236 goto out; 237 238 if (eepro_revirqmap[ia->ia_irq] == 0xff) 239 goto out; 240 241 /* now lets reset the chip */ 242 243 bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD); 244 delay(200); 245 246 ia->ia_iosize = 16; 247 248 bus_space_unmap(iot, ioh, 16); 249 return 1; /* found */ 250 out: 251 bus_space_unmap(iot, ioh, 16); 252 return 0; 253 } 254 255 void 256 iyattach(parent, self, aux) 257 struct device *parent, *self; 258 void *aux; 259 { 260 struct iy_softc *sc = (void *)self; 261 struct isa_attach_args *ia = aux; 262 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 263 bus_space_tag_t iot; 264 bus_space_handle_t ioh; 265 unsigned temp; 266 u_int16_t eaddr[8]; 267 u_int8_t myaddr[ETHER_ADDR_LEN]; 268 int eirq; 269 270 iot = ia->ia_iot; 271 272 if (bus_space_map(iot, ia->ia_iobase, 16, 0, &ioh)) 273 panic("Can't bus_space_map in iyattach"); 274 275 sc->sc_iot = iot; 276 sc->sc_ioh = ioh; 277 278 sc->mappedirq = eepro_revirqmap[ia->ia_irq]; 279 280 /* now let's reset the chip */ 281 282 bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD); 283 delay(200); 284 285 iyprobemem(sc); 286 287 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 288 ifp->if_softc = sc; 289 ifp->if_start = iystart; 290 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; 291 /* XXX todo: | IFF_MULTICAST */ 292 293 ifp->if_ioctl = iyioctl; 294 ifp->if_watchdog = iywatchdog; 295 296 (void)eepromreadall(iot, ioh, eaddr, 8); 297 sc->hard_vers = eaddr[EEPW6] & EEPP_BoardRev; 298 299 #ifdef DIAGNOSTICS 300 if ((eaddr[EEPPEther0] != 301 eepromread(iot, ioh, EEPPEther0a)) && 302 (eaddr[EEPPEther1] != 303 eepromread(iot, ioh, EEPPEther1a)) && 304 (eaddr[EEPPEther2] != 305 eepromread(iot, ioh, EEPPEther2a))) 306 307 printf("EEPROM Ethernet address differs from copy\n"); 308 #endif 309 310 myaddr[1] = eaddr[EEPPEther0] & 0xFF; 311 myaddr[0] = eaddr[EEPPEther0] >> 8; 312 myaddr[3] = eaddr[EEPPEther1] & 0xFF; 313 myaddr[2] = eaddr[EEPPEther1] >> 8; 314 myaddr[5] = eaddr[EEPPEther2] & 0xFF; 315 myaddr[4] = eaddr[EEPPEther2] >> 8; 316 317 /* Attach the interface. */ 318 if_attach(ifp); 319 ether_ifattach(ifp, myaddr); 320 printf(": address %s, rev. %d, %d kB\n", 321 ether_sprintf(myaddr), 322 sc->hard_vers, sc->sram/1024); 323 324 eirq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int]; 325 if (eirq != ia->ia_irq) 326 printf("%s: EEPROM irq setting %d ignored\n", 327 sc->sc_dev.dv_xname, eirq); 328 329 #if NBPFILTER > 0 330 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 331 #endif 332 333 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 334 IPL_NET, iyintr, sc); 335 336 temp = bus_space_read_1(iot, ioh, INT_NO_REG); 337 bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq); 338 } 339 340 void 341 iystop(sc) 342 struct iy_softc *sc; 343 { 344 bus_space_tag_t iot; 345 bus_space_handle_t ioh; 346 #ifdef IYDEBUG 347 u_int p, v; 348 #endif 349 350 iot = sc->sc_iot; 351 ioh = sc->sc_ioh; 352 353 bus_space_write_1(iot, ioh, COMMAND_REG, RCV_DISABLE_CMD); 354 355 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS); 356 bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS); 357 358 bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD); 359 delay(200); 360 #ifdef IYDEBUG 361 printf("%s: dumping tx chain (st 0x%x end 0x%x last 0x%x)\n", 362 sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last); 363 p = sc->tx_last; 364 if (!p) 365 p = sc->tx_start; 366 do { 367 bus_space_write_2(iot, ioh, HOST_ADDR_REG, p); 368 v = bus_space_read_2(iot, ioh, MEM_PORT_REG); 369 printf("0x%04x: %b ", p, v, "\020\006Ab\010Dn"); 370 v = bus_space_read_2(iot, ioh, MEM_PORT_REG); 371 printf("0x%b", v, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL"); 372 p = bus_space_read_2(iot, ioh, MEM_PORT_REG); 373 printf(" 0x%04x", p); 374 v = bus_space_read_2(iot, ioh, MEM_PORT_REG); 375 printf(" 0x%b\n", v, "\020\020Ch"); 376 377 } while (v & 0x8000); 378 #endif 379 sc->tx_start = sc->tx_end = sc->rx_size; 380 sc->tx_last = 0; 381 sc->sc_ethercom.ec_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 382 383 iymbufempty((void *)sc); 384 } 385 386 void 387 iyreset(sc) 388 struct iy_softc *sc; 389 { 390 int s; 391 s = splimp(); 392 iystop(sc); 393 iyinit(sc); 394 splx(s); 395 } 396 397 void 398 iyinit(sc) 399 struct iy_softc *sc; 400 { 401 int i; 402 unsigned temp; 403 struct ifnet *ifp; 404 bus_space_tag_t iot; 405 bus_space_handle_t ioh; 406 407 iot = sc->sc_iot; 408 ioh = sc->sc_ioh; 409 410 ifp = &sc->sc_ethercom.ec_if; 411 #ifdef IYDEBUG 412 printf("ifp is %p\n", ifp); 413 #endif 414 415 bus_space_write_1(iot, ioh, 0, BANK_SEL(2)); 416 417 temp = bus_space_read_1(iot, ioh, EEPROM_REG); 418 if (temp & 0x10) 419 bus_space_write_1(iot, ioh, EEPROM_REG, temp & ~0x10); 420 421 for (i=0; i<6; ++i) { 422 bus_space_write_1(iot, ioh, I_ADD(i), LLADDR(ifp->if_sadl)[i]); 423 } 424 425 temp = bus_space_read_1(iot, ioh, REG1); 426 bus_space_write_1(iot, ioh, REG1, 427 temp | XMT_CHAIN_INT | XMT_CHAIN_ERRSTOP | RCV_DISCARD_BAD); 428 429 temp = bus_space_read_1(iot, ioh, RECV_MODES_REG); 430 bus_space_write_1(iot, ioh, RECV_MODES_REG, temp | MATCH_BRDCST); 431 #ifdef IYDEBUG 432 printf("%s: RECV_MODES were %b set to %b\n", 433 sc->sc_dev.dv_xname, 434 temp, "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA", 435 temp|MATCH_BRDCST, 436 "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA"); 437 #endif 438 439 440 delay(500000); /* for the hardware to test for the connector */ 441 442 temp = bus_space_read_1(iot, ioh, MEDIA_SELECT); 443 #ifdef IYDEBUG 444 printf("%s: media select was 0x%b ", sc->sc_dev.dv_xname, 445 temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC"); 446 #endif 447 temp = (temp & TEST_MODE_MASK); 448 449 switch(ifp->if_flags & (IFF_LINK0 | IFF_LINK1)) { 450 case IFF_LINK0: 451 temp &= ~ (BNC_BIT | TPE_BIT); 452 break; 453 454 case IFF_LINK1: 455 temp = (temp & ~TPE_BIT) | BNC_BIT; 456 break; 457 458 case IFF_LINK0|IFF_LINK1: 459 temp = (temp & ~BNC_BIT) | TPE_BIT; 460 break; 461 default: 462 /* nothing; leave as it is */ 463 } 464 465 466 bus_space_write_1(iot, ioh, MEDIA_SELECT, temp); 467 #ifdef IYDEBUG 468 printf("changed to 0x%b\n", 469 temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC"); 470 #endif 471 472 bus_space_write_1(iot, ioh, 0, BANK_SEL(0)); 473 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS); 474 bus_space_write_1(iot, ioh, 0, BANK_SEL(1)); 475 476 temp = bus_space_read_1(iot, ioh, INT_NO_REG); 477 bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq); 478 479 #ifdef IYDEBUG 480 printf("%s: int no was %b\n", sc->sc_dev.dv_xname, 481 temp, "\020\4bad_irq\010flash/boot present"); 482 temp = bus_space_read_1(iot, ioh, INT_NO_REG); 483 printf("%s: int no now 0x%02x\n", sc->sc_dev.dv_xname, 484 temp, "\020\4BAD IRQ\010flash/boot present"); 485 #endif 486 487 488 bus_space_write_1(iot, ioh, RCV_LOWER_LIMIT_REG, 0); 489 bus_space_write_1(iot, ioh, RCV_UPPER_LIMIT_REG, (sc->rx_size - 2) >> 8); 490 bus_space_write_1(iot, ioh, XMT_LOWER_LIMIT_REG, sc->rx_size >> 8); 491 bus_space_write_1(iot, ioh, XMT_UPPER_LIMIT_REG, sc->sram >> 8); 492 493 temp = bus_space_read_1(iot, ioh, REG1); 494 #ifdef IYDEBUG 495 printf("%s: HW access is %b\n", sc->sc_dev.dv_xname, 496 temp, "\020\2WORD_WIDTH\010INT_ENABLE"); 497 #endif 498 bus_space_write_1(iot, ioh, REG1, temp | INT_ENABLE); /* XXX what about WORD_WIDTH? */ 499 500 #ifdef IYDEBUG 501 temp = bus_space_read_1(iot, ioh, REG1); 502 printf("%s: HW access is %b\n", sc->sc_dev.dv_xname, 503 temp, "\020\2WORD_WIDTH\010INT_ENABLE"); 504 #endif 505 506 bus_space_write_1(iot, ioh, 0, BANK_SEL(0)); 507 508 bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS & ~(RX_BIT|TX_BIT)); 509 bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS); /* clear ints */ 510 511 bus_space_write_2(iot, ioh, RCV_START_LOW, 0); 512 bus_space_write_2(iot, ioh, RCV_STOP_LOW, sc->rx_size - 2); 513 sc->rx_start = 0; 514 515 bus_space_write_1(iot, ioh, 0, SEL_RESET_CMD); 516 delay(200); 517 518 bus_space_write_2(iot, ioh, XMT_ADDR_REG, sc->rx_size); 519 520 sc->tx_start = sc->tx_end = sc->rx_size; 521 sc->tx_last = 0; 522 523 bus_space_write_1(iot, ioh, 0, RCV_ENABLE_CMD); 524 525 ifp->if_flags |= IFF_RUNNING; 526 ifp->if_flags &= ~IFF_OACTIVE; 527 } 528 529 void 530 iystart(ifp) 531 struct ifnet *ifp; 532 { 533 struct iy_softc *sc; 534 535 536 struct mbuf *m0, *m; 537 u_int len, pad, last, end; 538 u_int llen, residual; 539 int avail; 540 caddr_t data; 541 u_int16_t resval, stat; 542 bus_space_tag_t iot; 543 bus_space_handle_t ioh; 544 545 #ifdef IYDEBUG 546 printf("iystart called\n"); 547 #endif 548 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 549 return; 550 551 sc = ifp->if_softc; 552 iot = sc->sc_iot; 553 ioh = sc->sc_ioh; 554 555 while ((m0 = ifp->if_snd.ifq_head) != NULL) { 556 #ifdef IYDEBUG 557 printf("%s: trying to write another packet to the hardware\n", 558 sc->sc_dev.dv_xname); 559 #endif 560 561 /* We need to use m->m_pkthdr.len, so require the header */ 562 if ((m0->m_flags & M_PKTHDR) == 0) 563 panic("iystart: no header mbuf"); 564 565 len = m0->m_pkthdr.len; 566 pad = len & 1; 567 568 #ifdef IYDEBUG 569 printf("%s: length is %d.\n", sc->sc_dev.dv_xname, len); 570 #endif 571 if (len < ETHER_MIN_LEN) { 572 pad = ETHER_MIN_LEN - len; 573 } 574 575 if (len + pad > ETHER_MAX_LEN) { 576 /* packet is obviously too large: toss it */ 577 ++ifp->if_oerrors; 578 IF_DEQUEUE(&ifp->if_snd, m0); 579 m_freem(m0); 580 continue; 581 } 582 583 #if NBPFILTER > 0 584 if (ifp->if_bpf) 585 bpf_mtap(ifp->if_bpf, m0); 586 #endif 587 588 avail = sc->tx_start - sc->tx_end; 589 if (avail <= 0) 590 avail += sc->tx_size; 591 592 #ifdef IYDEBUG 593 printf("%s: avail is %d.\n", sc->sc_dev.dv_xname, avail); 594 #endif 595 /* 596 * we MUST RUN at splnet here --- 597 * XXX todo: or even turn off the boards ints ??? hm... 598 */ 599 600 /* See if there is room to put another packet in the buffer. */ 601 602 if ((len+pad+2*I595_XMT_HDRLEN) > avail) { 603 printf("%s: len = %d, avail = %d, setting OACTIVE\n", 604 sc->sc_dev.dv_xname, len, avail); 605 ifp->if_flags |= IFF_OACTIVE; 606 return; 607 } 608 609 /* we know it fits in the hardware now, so dequeue it */ 610 IF_DEQUEUE(&ifp->if_snd, m0); 611 612 last = sc->tx_end; 613 end = last + pad + len + I595_XMT_HDRLEN; 614 615 if (end >= sc->sram) { 616 if ((sc->sram - last) <= I595_XMT_HDRLEN) { 617 /* keep header in one piece */ 618 last = sc->rx_size; 619 end = last + pad + len + I595_XMT_HDRLEN; 620 } else 621 end -= sc->tx_size; 622 } 623 624 bus_space_write_2(iot, ioh, HOST_ADDR_REG, last); 625 bus_space_write_2(iot, ioh, MEM_PORT_REG, XMT_CMD); 626 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0); 627 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0); 628 bus_space_write_2(iot, ioh, MEM_PORT_REG, len + pad); 629 630 residual = resval = 0; 631 632 while ((m = m0)!=0) { 633 data = mtod(m, caddr_t); 634 llen = m->m_len; 635 if (residual) { 636 #ifdef IYDEBUG 637 printf("%s: merging residual with next mbuf.\n", 638 sc->sc_dev.dv_xname); 639 #endif 640 resval |= *data << 8; 641 bus_space_write_2(iot, ioh, MEM_PORT_REG, resval); 642 --llen; 643 ++data; 644 } 645 if (llen > 1) 646 bus_space_write_multi_2(iot, ioh, MEM_PORT_REG, 647 data, llen>>1); 648 residual = llen & 1; 649 if (residual) { 650 resval = *(data + llen - 1); 651 #ifdef IYDEBUG 652 printf("%s: got odd mbuf to send.\n", 653 sc->sc_dev.dv_xname); 654 #endif 655 } 656 657 MFREE(m, m0); 658 } 659 660 if (residual) 661 bus_space_write_2(iot, ioh, MEM_PORT_REG, resval); 662 663 pad >>= 1; 664 while (pad-- > 0) 665 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0); 666 667 #ifdef IYDEBUG 668 printf("%s: new last = 0x%x, end = 0x%x.\n", 669 sc->sc_dev.dv_xname, last, end); 670 printf("%s: old start = 0x%x, end = 0x%x, last = 0x%x\n", 671 sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last); 672 #endif 673 674 if (sc->tx_start != sc->tx_end) { 675 bus_space_write_2(iot, ioh, HOST_ADDR_REG, sc->tx_last + XMT_COUNT); 676 stat = bus_space_read_2(iot, ioh, MEM_PORT_REG); 677 678 bus_space_write_2(iot, ioh, HOST_ADDR_REG, sc->tx_last + XMT_CHAIN); 679 bus_space_write_2(iot, ioh, MEM_PORT_REG, last); 680 bus_space_write_2(iot, ioh, MEM_PORT_REG, stat | CHAIN); 681 #ifdef IYDEBUG 682 printf("%s: setting 0x%x to 0x%x\n", 683 sc->sc_dev.dv_xname, sc->tx_last + XMT_COUNT, 684 stat | CHAIN); 685 #endif 686 } 687 stat = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */ 688 689 /* XXX todo: enable ints here if disabled */ 690 691 ++ifp->if_opackets; 692 693 if (sc->tx_start == sc->tx_end) { 694 bus_space_write_2(iot, ioh, XMT_ADDR_REG, last); 695 bus_space_write_1(iot, ioh, 0, XMT_CMD); 696 sc->tx_start = last; 697 #ifdef IYDEBUG 698 printf("%s: writing 0x%x to XAR and giving XCMD\n", 699 sc->sc_dev.dv_xname, last); 700 #endif 701 } else { 702 bus_space_write_1(iot, ioh, 0, RESUME_XMT_CMD); 703 #ifdef IYDEBUG 704 printf("%s: giving RESUME_XCMD\n", 705 sc->sc_dev.dv_xname); 706 #endif 707 } 708 sc->tx_last = last; 709 sc->tx_end = end; 710 } 711 } 712 713 714 static __inline void 715 eepromwritebit(iot, ioh, what) 716 bus_space_tag_t iot; 717 bus_space_handle_t ioh; 718 int what; 719 { 720 bus_space_write_1(iot, ioh, EEPROM_REG, what); 721 delay(1); 722 bus_space_write_1(iot, ioh, EEPROM_REG, what|EESK); 723 delay(1); 724 bus_space_write_1(iot, ioh, EEPROM_REG, what); 725 delay(1); 726 } 727 728 static __inline int 729 eepromreadbit(iot, ioh) 730 bus_space_tag_t iot; 731 bus_space_handle_t ioh; 732 { 733 int b; 734 735 bus_space_write_1(iot, ioh, EEPROM_REG, EECS|EESK); 736 delay(1); 737 b = bus_space_read_1(iot, ioh, EEPROM_REG); 738 bus_space_write_1(iot, ioh, EEPROM_REG, EECS); 739 delay(1); 740 741 return ((b & EEDO) != 0); 742 } 743 744 static u_int16_t 745 eepromread(iot, ioh, offset) 746 bus_space_tag_t iot; 747 bus_space_handle_t ioh; 748 int offset; 749 { 750 volatile int i; 751 volatile int j; 752 volatile u_int16_t readval; 753 754 bus_space_write_1(iot, ioh, 0, BANK_SEL(2)); 755 delay(1); 756 bus_space_write_1(iot, ioh, EEPROM_REG, EECS); /* XXXX??? */ 757 delay(1); 758 759 eepromwritebit(iot, ioh, EECS|EEDI); 760 eepromwritebit(iot, ioh, EECS|EEDI); 761 eepromwritebit(iot, ioh, EECS); 762 763 for (j=5; j>=0; --j) { 764 if ((offset>>j) & 1) 765 eepromwritebit(iot, ioh, EECS|EEDI); 766 else 767 eepromwritebit(iot, ioh, EECS); 768 } 769 770 for (readval=0, i=0; i<16; ++i) { 771 readval<<=1; 772 readval |= eepromreadbit(iot, ioh); 773 } 774 775 bus_space_write_1(iot, ioh, EEPROM_REG, 0|EESK); 776 delay(1); 777 bus_space_write_1(iot, ioh, EEPROM_REG, 0); 778 779 bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0)); 780 781 return readval; 782 } 783 784 /* 785 * Device timeout/watchdog routine. Entered if the device neglects to generate 786 * an interrupt after a transmit has been started on it. 787 */ 788 void 789 iywatchdog(ifp) 790 struct ifnet *ifp; 791 { 792 struct iy_softc *sc = ifp->if_softc; 793 794 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); 795 ++sc->sc_ethercom.ec_if.if_oerrors; 796 iyreset(sc); 797 } 798 799 /* 800 * What to do upon receipt of an interrupt. 801 */ 802 int 803 iyintr(arg) 804 void *arg; 805 { 806 struct iy_softc *sc = arg; 807 bus_space_tag_t iot; 808 bus_space_handle_t ioh; 809 810 register u_short status; 811 812 iot = sc->sc_iot; 813 ioh = sc->sc_ioh; 814 815 status = bus_space_read_1(iot, ioh, STATUS_REG); 816 #ifdef IYDEBUG 817 if (status & ALL_INTS) { 818 printf("%s: got interupt %b", sc->sc_dev.dv_xname, status, 819 "\020\1RX_STP\2RX\3TX\4EXEC"); 820 if (status & EXEC_INT) 821 printf(" event %b\n", bus_space_read_1(iot, ioh, 0), 822 "\020\6ABORT"); 823 else 824 printf("\n"); 825 } 826 #endif 827 if (((status & (RX_INT | TX_INT)) == 0)) 828 return 0; 829 830 if (status & RX_INT) { 831 iy_intr_rx(sc); 832 bus_space_write_1(iot, ioh, STATUS_REG, RX_INT); 833 } else if (status & TX_INT) { 834 iy_intr_tx(sc); 835 bus_space_write_1(iot, ioh, STATUS_REG, TX_INT); 836 } 837 return 1; 838 } 839 840 void 841 iyget(sc, iot, ioh, rxlen) 842 struct iy_softc *sc; 843 bus_space_tag_t iot; 844 bus_space_handle_t ioh; 845 int rxlen; 846 { 847 struct mbuf *m, *top, **mp; 848 struct ether_header *eh; 849 struct ifnet *ifp; 850 int len; 851 852 ifp = &sc->sc_ethercom.ec_if; 853 854 m = sc->mb[sc->next_mb]; 855 sc->mb[sc->next_mb] = 0; 856 if (m == 0) { 857 MGETHDR(m, M_DONTWAIT, MT_DATA); 858 if (m == 0) 859 goto dropped; 860 } else { 861 if (sc->last_mb == sc->next_mb) 862 timeout(iymbuffill, sc, 1); 863 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 864 m->m_data = m->m_pktdat; 865 m->m_flags = M_PKTHDR; 866 } 867 m->m_pkthdr.rcvif = ifp; 868 m->m_pkthdr.len = rxlen; 869 len = MHLEN; 870 top = 0; 871 mp = ⊤ 872 873 while (rxlen > 0) { 874 if (top) { 875 m = sc->mb[sc->next_mb]; 876 sc->mb[sc->next_mb] = 0; 877 if (m == 0) { 878 MGET(m, M_DONTWAIT, MT_DATA); 879 if (m == 0) { 880 m_freem(top); 881 goto dropped; 882 } 883 } else { 884 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 885 } 886 len = MLEN; 887 } 888 if (rxlen >= MINCLSIZE) { 889 MCLGET(m, M_DONTWAIT); 890 if ((m->m_flags & M_EXT) == 0) { 891 m_freem(top); 892 goto dropped; 893 } 894 len = MCLBYTES; 895 } 896 len = min(rxlen, len); 897 if (len > 1) { 898 len &= ~1; 899 900 bus_space_read_multi_2(iot, ioh, MEM_PORT_REG, 901 mtod(m, caddr_t), len/2); 902 } else { 903 #ifdef IYDEBUG 904 printf("%s: received odd mbuf\n", sc->sc_dev.dv_xname); 905 #endif 906 *(mtod(m, caddr_t)) = bus_space_read_2(iot, ioh, 907 MEM_PORT_REG); 908 } 909 m->m_len = len; 910 rxlen -= len; 911 *mp = m; 912 mp = &m->m_next; 913 } 914 /* XXX receive the top here */ 915 ++ifp->if_ipackets; 916 917 eh = mtod(top, struct ether_header *); 918 919 #if NBPFILTER > 0 920 if (ifp->if_bpf) { 921 bpf_mtap(ifp->if_bpf, top); 922 if ((ifp->if_flags & IFF_PROMISC) && 923 (eh->ether_dhost[0] & 1) == 0 && 924 bcmp(eh->ether_dhost, 925 LLADDR(sc->sc_ethercom.ec_if.if_sadl), 926 sizeof(eh->ether_dhost)) != 0) { 927 928 m_freem(top); 929 return; 930 } 931 } 932 #endif 933 m_adj(top, sizeof(struct ether_header)); 934 ether_input(ifp, eh, top); 935 return; 936 937 dropped: 938 ++ifp->if_ierrors; 939 return; 940 } 941 void 942 iy_intr_rx(sc) 943 struct iy_softc *sc; 944 { 945 struct ifnet *ifp; 946 bus_space_tag_t iot; 947 bus_space_handle_t ioh; 948 949 u_int rxadrs, rxevnt, rxstatus, rxnext, rxlen; 950 951 iot = sc->sc_iot; 952 ioh = sc->sc_ioh; 953 ifp = &sc->sc_ethercom.ec_if; 954 955 rxadrs = sc->rx_start; 956 bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxadrs); 957 rxevnt = bus_space_read_2(iot, ioh, MEM_PORT_REG); 958 rxnext = 0; 959 960 while (rxevnt == RCV_DONE) { 961 rxstatus = bus_space_read_2(iot, ioh, MEM_PORT_REG); 962 rxnext = bus_space_read_2(iot, ioh, MEM_PORT_REG); 963 rxlen = bus_space_read_2(iot, ioh, MEM_PORT_REG); 964 #ifdef IYDEBUG 965 printf("%s: pck at 0x%04x stat %b next 0x%x len 0x%x\n", 966 sc->sc_dev.dv_xname, rxadrs, rxstatus, 967 "\020\1RCLD\2IA_MCH\010SHORT\011OVRN\013ALGERR" 968 "\014CRCERR\015LENERR\016RCVOK\020TYP", 969 rxnext, rxlen); 970 #endif 971 iyget(sc, iot, ioh, rxlen); 972 973 /* move stop address */ 974 bus_space_write_2(iot, ioh, RCV_STOP_LOW, 975 rxnext == 0 ? sc->rx_size - 2 : rxnext - 2); 976 977 bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxnext); 978 rxadrs = rxnext; 979 rxevnt = bus_space_read_2(iot, ioh, MEM_PORT_REG); 980 } 981 sc->rx_start = rxnext; 982 } 983 984 void 985 iy_intr_tx(sc) 986 struct iy_softc *sc; 987 { 988 bus_space_tag_t iot; 989 bus_space_handle_t ioh; 990 struct ifnet *ifp; 991 u_int txstatus, txstat2, txlen, txnext; 992 993 ifp = &sc->sc_ethercom.ec_if; 994 iot = sc->sc_iot; 995 ioh = sc->sc_ioh; 996 997 while (sc->tx_start != sc->tx_end) { 998 bus_space_write_2(iot, ioh, HOST_ADDR_REG, sc->tx_start); 999 txstatus = bus_space_read_2(iot, ioh, MEM_PORT_REG); 1000 if ((txstatus & (TX_DONE|CMD_MASK)) != (TX_DONE|XMT_CMD)) 1001 break; 1002 1003 txstat2 = bus_space_read_2(iot, ioh, MEM_PORT_REG); 1004 txnext = bus_space_read_2(iot, ioh, MEM_PORT_REG); 1005 txlen = bus_space_read_2(iot, ioh, MEM_PORT_REG); 1006 #ifdef IYDEBUG 1007 printf("txstat 0x%x stat2 0x%b next 0x%x len 0x%x\n", 1008 txstatus, txstat2, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF" 1009 "\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL", 1010 txnext, txlen); 1011 #endif 1012 if (txlen & CHAIN) 1013 sc->tx_start = txnext; 1014 else 1015 sc->tx_start = sc->tx_end; 1016 ifp->if_flags &= ~IFF_OACTIVE; 1017 1018 if ((txstat2 & 0x2000) == 0) 1019 ++ifp->if_oerrors; 1020 if (txstat2 & 0x000f) 1021 ifp->if_oerrors += txstat2 & 0x000f; 1022 } 1023 ifp->if_flags &= ~IFF_OACTIVE; 1024 } 1025 1026 #if 0 1027 /* 1028 * Compare two Ether/802 addresses for equality, inlined and unrolled for 1029 * speed. I'd love to have an inline assembler version of this... 1030 */ 1031 static inline int 1032 ether_equal(one, two) 1033 u_char *one, *two; 1034 { 1035 1036 if (one[0] != two[0] || one[1] != two[1] || one[2] != two[2] || 1037 one[3] != two[3] || one[4] != two[4] || one[5] != two[5]) 1038 return 0; 1039 return 1; 1040 } 1041 1042 /* 1043 * Check for a valid address. to_bpf is filled in with one of the following: 1044 * 0 -> BPF doesn't get this packet 1045 * 1 -> BPF does get this packet 1046 * 2 -> BPF does get this packet, but we don't 1047 * Return value is true if the packet is for us, and false otherwise. 1048 * 1049 * This routine is a mess, but it's also critical that it be as fast 1050 * as possible. It could be made cleaner if we can assume that the 1051 * only client which will fiddle with IFF_PROMISC is BPF. This is 1052 * probably a good assumption, but we do not make it here. (Yet.) 1053 */ 1054 static inline int 1055 check_eh(sc, eh, to_bpf) 1056 struct iy_softc *sc; 1057 struct ether_header *eh; 1058 int *to_bpf; 1059 { 1060 int i; 1061 1062 switch (sc->promisc) { 1063 case IFF_ALLMULTI: 1064 /* 1065 * Receiving all multicasts, but no unicasts except those 1066 * destined for us. 1067 */ 1068 #if NBPFILTER > 0 1069 *to_bpf = (sc->sc_ethercom.ec_if.iy_bpf != 0); /* BPF gets this packet if anybody cares */ 1070 #endif 1071 if (eh->ether_dhost[0] & 1) 1072 return 1; 1073 if (ether_equal(eh->ether_dhost, 1074 LLADDR(sc->sc_ethercom.ec_if.if_sadl))) 1075 return 1; 1076 return 0; 1077 1078 case IFF_PROMISC: 1079 /* 1080 * Receiving all packets. These need to be passed on to BPF. 1081 */ 1082 #if NBPFILTER > 0 1083 *to_bpf = (sc->sc_ethercom.ec_if.iy_bpf != 0); 1084 #endif 1085 /* If for us, accept and hand up to BPF */ 1086 if (ether_equal(eh->ether_dhost, LLADDR(sc->sc_ethercom.ec_if.if_sadl))) 1087 return 1; 1088 1089 #if NBPFILTER > 0 1090 if (*to_bpf) 1091 *to_bpf = 2; /* we don't need to see it */ 1092 #endif 1093 1094 /* 1095 * Not a multicast, so BPF wants to see it but we don't. 1096 */ 1097 if (!(eh->ether_dhost[0] & 1)) 1098 return 1; 1099 1100 /* 1101 * If it's one of our multicast groups, accept it and pass it 1102 * up. 1103 */ 1104 for (i = 0; i < sc->mcast_count; i++) { 1105 if (ether_equal(eh->ether_dhost, (u_char *)&sc->mcast_addrs[i])) { 1106 #if NBPFILTER > 0 1107 if (*to_bpf) 1108 *to_bpf = 1; 1109 #endif 1110 return 1; 1111 } 1112 } 1113 return 1; 1114 1115 case IFF_ALLMULTI | IFF_PROMISC: 1116 /* 1117 * Acting as a multicast router, and BPF running at the same 1118 * time. Whew! (Hope this is a fast machine...) 1119 */ 1120 #if NBPFILTER > 0 1121 *to_bpf = (sc->sc_ethercom.ec_if.iy_bpf != 0); 1122 #endif 1123 /* We want to see multicasts. */ 1124 if (eh->ether_dhost[0] & 1) 1125 return 1; 1126 1127 /* We want to see our own packets */ 1128 if (ether_equal(eh->ether_dhost, LLADDR(sc->sc_ethercom.ec_if.if_sadl))) 1129 return 1; 1130 1131 /* Anything else goes to BPF but nothing else. */ 1132 #if NBPFILTER > 0 1133 if (*to_bpf) 1134 *to_bpf = 2; 1135 #endif 1136 return 1; 1137 1138 case 0: 1139 /* 1140 * Only accept unicast packets destined for us, or multicasts 1141 * for groups that we belong to. For now, we assume that the 1142 * '586 will only return packets that we asked it for. This 1143 * isn't strictly true (it uses hashing for the multicast 1144 * filter), but it will do in this case, and we want to get out 1145 * of here as quickly as possible. 1146 */ 1147 #if NBPFILTER > 0 1148 *to_bpf = (sc->sc_ethercom.ec_if.iy_bpf != 0); 1149 #endif 1150 return 1; 1151 } 1152 1153 #ifdef DIAGNOSTIC 1154 panic("check_eh: impossible"); 1155 #endif 1156 } 1157 #endif 1158 1159 int 1160 iyioctl(ifp, cmd, data) 1161 register struct ifnet *ifp; 1162 u_long cmd; 1163 caddr_t data; 1164 { 1165 struct iy_softc *sc; 1166 struct ifaddr *ifa; 1167 struct ifreq *ifr; 1168 int s, error = 0; 1169 1170 sc = ifp->if_softc; 1171 ifa = (struct ifaddr *)data; 1172 ifr = (struct ifreq *)data; 1173 1174 #ifdef IYDEBUG 1175 printf("iyioctl called with ifp 0x%p (%s) cmd 0x%x data 0x%p\n", 1176 ifp, ifp->if_xname, cmd, data); 1177 #endif 1178 1179 s = splimp(); 1180 1181 switch (cmd) { 1182 1183 case SIOCSIFADDR: 1184 ifp->if_flags |= IFF_UP; 1185 1186 switch (ifa->ifa_addr->sa_family) { 1187 #ifdef INET 1188 case AF_INET: 1189 iyinit(sc); 1190 arp_ifinit(ifp, ifa); 1191 break; 1192 #endif 1193 #ifdef NS 1194 /* XXX - This code is probably wrong. */ 1195 case AF_NS: 1196 { 1197 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 1198 1199 if (ns_nullhost(*ina)) 1200 ina->x_host = *(union ns_host *) 1201 LLADDR(sc->sc_ethercom.ec_if.if_sadl); 1202 else 1203 bcopy(ina->x_host.c_host, 1204 LLADDR(sc->sc_ethercom.ec_if.if_sadl), 1205 ETHER_ADDR_LEN); 1206 /* Set new address. */ 1207 iyinit(sc); 1208 break; 1209 } 1210 #endif /* NS */ 1211 default: 1212 iyinit(sc); 1213 break; 1214 } 1215 break; 1216 1217 case SIOCSIFFLAGS: 1218 sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI); 1219 if ((ifp->if_flags & IFF_UP) == 0 && 1220 (ifp->if_flags & IFF_RUNNING) != 0) { 1221 /* 1222 * If interface is marked down and it is running, then 1223 * stop it. 1224 */ 1225 iystop(sc); 1226 ifp->if_flags &= ~IFF_RUNNING; 1227 } else if ((ifp->if_flags & IFF_UP) != 0 && 1228 (ifp->if_flags & IFF_RUNNING) == 0) { 1229 /* 1230 * If interface is marked up and it is stopped, then 1231 * start it. 1232 */ 1233 iyinit(sc); 1234 } else { 1235 /* 1236 * Reset the interface to pick up changes in any other 1237 * flags that affect hardware registers. 1238 */ 1239 iystop(sc); 1240 iyinit(sc); 1241 } 1242 #ifdef IYDEBUGX 1243 if (ifp->if_flags & IFF_DEBUG) 1244 sc->sc_debug = IFY_ALL; 1245 else 1246 sc->sc_debug = 0; 1247 #endif 1248 break; 1249 1250 #if 0 /* XXX */ 1251 case SIOCADDMULTI: 1252 case SIOCDELMULTI: 1253 error = (cmd == SIOCADDMULTI) ? 1254 ether_addmulti(ifr, &sc->sc_ethercom): 1255 ether_delmulti(ifr, &sc->sc_ethercom); 1256 1257 if (error == ENETRESET) { 1258 /* 1259 * Multicast list has changed; set the hardware filter 1260 * accordingly. 1261 */ 1262 iy_mc_reset(sc); /* XXX */ 1263 error = 0; 1264 } 1265 break; 1266 #endif 1267 default: 1268 error = EINVAL; 1269 } 1270 splx(s); 1271 return error; 1272 } 1273 1274 #if 0 1275 static void 1276 iy_mc_reset(sc) 1277 struct iy_softc *sc; 1278 { 1279 struct ether_multi *enm; 1280 struct ether_multistep step; 1281 1282 /* 1283 * Step through the list of addresses. 1284 */ 1285 sc->mcast_count = 0; 1286 ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm); 1287 while (enm) { 1288 if (sc->mcast_count >= MAXMCAST || 1289 bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) { 1290 sc->sc_ethercom.ec_if.if_flags |= IFF_ALLMULTI; 1291 iyioctl(&sc->sc_ethercom.ec_if, SIOCSIFFLAGS, 1292 (void *)0); 1293 goto setflag; 1294 } 1295 1296 bcopy(enm->enm_addrlo, &sc->mcast_addrs[sc->mcast_count], 6); 1297 sc->mcast_count++; 1298 ETHER_NEXT_MULTI(step, enm); 1299 } 1300 setflag: 1301 sc->want_mcsetup = 1; 1302 } 1303 1304 #ifdef IYDEBUG 1305 void 1306 print_rbd(rbd) 1307 volatile struct ie_recv_buf_desc *rbd; 1308 { 1309 1310 printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n" 1311 "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual, 1312 rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length, 1313 rbd->mbz); 1314 } 1315 #endif 1316 #endif 1317 1318 void 1319 iymbuffill(arg) 1320 void *arg; 1321 { 1322 struct iy_softc *sc = (struct iy_softc *)arg; 1323 int s, i; 1324 1325 s = splimp(); 1326 i = sc->last_mb; 1327 do { 1328 if (sc->mb[i] == NULL) 1329 MGET(sc->mb[i], M_DONTWAIT, MT_DATA); 1330 if (sc->mb[i] == NULL) 1331 break; 1332 i = (i + 1) % MAX_MBS; 1333 } while (i != sc->next_mb); 1334 sc->last_mb = i; 1335 /* If the queue was not filled, try again. */ 1336 if (sc->last_mb != sc->next_mb) 1337 timeout(iymbuffill, sc, 1); 1338 splx(s); 1339 } 1340 1341 1342 void 1343 iymbufempty(arg) 1344 void *arg; 1345 { 1346 struct iy_softc *sc = (struct iy_softc *)arg; 1347 int s, i; 1348 1349 s = splimp(); 1350 for (i = 0; i<MAX_MBS; i++) { 1351 if (sc->mb[i]) { 1352 m_freem(sc->mb[i]); 1353 sc->mb[i] = NULL; 1354 } 1355 } 1356 sc->last_mb = sc->next_mb = 0; 1357 untimeout(iymbuffill, sc); 1358 splx(s); 1359 } 1360 1361 void 1362 iyprobemem(sc) 1363 struct iy_softc *sc; 1364 { 1365 bus_space_tag_t iot; 1366 bus_space_handle_t ioh; 1367 int testing; 1368 1369 iot = sc->sc_iot; 1370 ioh = sc->sc_ioh; 1371 1372 bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0)); 1373 delay(1); 1374 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 4096-2); 1375 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0); 1376 1377 for (testing=65536; testing >= 4096; testing >>= 1) { 1378 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2); 1379 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xdead); 1380 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2); 1381 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xdead) { 1382 #ifdef IYMEMDEBUG 1383 printf("%s: Didn't keep 0xdead at 0x%x\n", 1384 sc->sc_dev.dv_xname, testing-2); 1385 #endif 1386 continue; 1387 } 1388 1389 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2); 1390 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xbeef); 1391 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2); 1392 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xbeef) { 1393 #ifdef IYMEMDEBUG 1394 printf("%s: Didn't keep 0xbeef at 0x%x\n", 1395 sc->sc_dev.dv_xname, testing-2); 1396 #endif 1397 continue; 1398 } 1399 1400 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0); 1401 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0); 1402 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing >> 1); 1403 bus_space_write_2(iot, ioh, MEM_PORT_REG, testing >> 1); 1404 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0); 1405 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) == (testing >> 1)) { 1406 #ifdef IYMEMDEBUG 1407 printf("%s: 0x%x alias of 0x0\n", 1408 sc->sc_dev.dv_xname, testing >> 1); 1409 #endif 1410 continue; 1411 } 1412 1413 break; 1414 } 1415 1416 sc->sram = testing; 1417 1418 switch(testing) { 1419 case 65536: 1420 /* 4 NFS packets + overhead RX, 2 NFS + overhead TX */ 1421 sc->rx_size = 44*1024; 1422 break; 1423 1424 case 32768: 1425 /* 2 NFS packets + overhead RX, 1 NFS + overhead TX */ 1426 sc->rx_size = 22*1024; 1427 break; 1428 1429 case 16384: 1430 /* 1 NFS packet + overhead RX, 4 big packets TX */ 1431 sc->rx_size = 10*1024; 1432 break; 1433 default: 1434 sc->rx_size = testing/2; 1435 break; 1436 } 1437 sc->tx_size = testing - sc->rx_size; 1438 } 1439 1440 static int 1441 eepromreadall(iot, ioh, wordp, maxi) 1442 bus_space_tag_t iot; 1443 bus_space_handle_t ioh; 1444 u_int16_t *wordp; 1445 int maxi; 1446 { 1447 int i; 1448 u_int16_t checksum, tmp; 1449 1450 checksum = 0; 1451 1452 for (i=0; i<EEPP_LENGTH; ++i) { 1453 tmp = eepromread(iot, ioh, i); 1454 checksum += tmp; 1455 if (i<maxi) 1456 wordp[i] = tmp; 1457 } 1458 1459 if (checksum != EEPP_CHKSUM) { 1460 #ifdef IYDEBUG 1461 printf("wrong EEPROM checksum 0x%x should be 0x%x\n", 1462 checksum, EEPP_CHKSUM); 1463 #endif 1464 return 1; 1465 } 1466 return 0; 1467 } 1468