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