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