1 /* $NetBSD: if_ie.c,v 1.11 2003/01/20 14:59:27 bouyer Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Melvin Tang-Richardson. 5 * All rights reserved. 6 * 7 * This driver is a major hash up of src/sys/dev/isa/if_ie.c and 8 * src/sys/arch/acorn32/podulebus/kgdb_ie.c Please refer to copyright 9 * notices from them too. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by RiscBSD. 22 * 4. The name of the company nor the name of the author may be used to 23 * endorse or promote products derived from this software without specific 24 * prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY RISCBSD ``AS IS'' AND ANY EXPRESS OR IMPLIED 27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL RISCBSD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * RiscBSD kernel project 39 * 40 * if_ie.c 41 * 42 * Ether 1 podule driver 43 * 44 * Created : 26/06/95 45 */ 46 47 /* 48 * This driver is at it's last beta release. It should not cause 49 * any problems (Touch wood) 50 * 51 * If it passes field tests again. This will constitute the realse 52 * version. 53 */ 54 55 #define IGNORE_ETHER1_IDROM_CHECKSUM 56 57 /* Standard podule includes */ 58 59 #include "opt_inet.h" 60 #include "opt_ns.h" 61 62 #include <sys/param.h> 63 64 __RCSID("$NetBSD: if_ie.c,v 1.11 2003/01/20 14:59:27 bouyer Exp $"); 65 66 #include <sys/systm.h> 67 #include <sys/kernel.h> 68 #include <sys/conf.h> 69 #include <sys/malloc.h> 70 #include <sys/device.h> 71 #include <machine/io.h> 72 #include <machine/intr.h> 73 #include <arm/arm32/katelib.h> 74 #include <acorn32/podulebus/podulebus.h> 75 #include <dev/podulebus/podules.h> 76 77 /* Include for interface to the net and ethernet subsystems */ 78 79 #include <sys/socket.h> 80 #include <sys/syslog.h> 81 #include <sys/ioctl.h> 82 #include <sys/mbuf.h> 83 84 #include <net/if.h> 85 #include <net/if_types.h> 86 #include <net/if_dl.h> 87 #include <net/if_ether.h> 88 89 #ifdef INET 90 #include <netinet/in.h> 91 #include <netinet/in_systm.h> 92 #include <netinet/in_var.h> 93 #include <netinet/ip.h> 94 #include <netinet/if_inarp.h> 95 #endif 96 97 #ifdef NS 98 #include <netns/ns.h> 99 #include <netns/ns_if.h> 100 #endif 101 102 /* Import our data structres */ 103 104 #include "if_iereg.h" 105 106 /* BPF support */ 107 108 #include "bpfilter.h" 109 #if NBPFILTER > 0 110 #include <net/bpf.h> 111 #include <net/bpfdesc.h> 112 #endif 113 114 /* Some useful defines and macros */ 115 116 #define PODULE_IRQ_PENDING (1) 117 #define NFRAMES (16) /* number of frame to allow for receive */ 118 #define NRXBUF (48) /* number of receive buffers to allocate */ 119 #define IE_RXBUF_SIZE (256) /* receive buf size */ 120 #define NTXBUF (2) /* number of transmit buffers to allocate */ 121 #define IE_TXBUF_SIZE (1522) /* size of tx buffer */ 122 123 #define PWriteShort(a,b) WriteWord(a,(b)<<16|(b)) 124 125 #define xoffsetof(type, member) (offsetof(type, member) << 1) 126 127 /* Some data structres local to this file */ 128 129 struct ie_softc { 130 struct device sc_dev; 131 int sc_podule_number; 132 podule_t *sc_podule; 133 irqhandler_t sc_ih; 134 int sc_flags; 135 #define IE_BROKEN 1 136 int sc_iobase; 137 int sc_fastbase; 138 int sc_rom; 139 int sc_ram; 140 int sc_control; 141 struct ethercom sc_ethercom; 142 int promisc; 143 int sc_irqmode; 144 145 u_long rframes[NFRAMES]; 146 u_long rbuffs[NRXBUF]; 147 u_long cbuffs[NRXBUF]; 148 int rfhead, rftail, rbhead, rbtail; 149 150 u_long xmit_cmds[NTXBUF]; 151 u_long xmit_buffs[NTXBUF]; 152 u_long xmit_cbuffs[NTXBUF]; 153 int xmit_count; 154 int xmit_free; 155 int xchead; 156 int xctail; 157 }; 158 159 /* Function and data prototypes */ 160 161 static void host2ie __P(( struct ie_softc *sc, void *src, u_long dest, int size )); 162 static void ie2host __P(( struct ie_softc *sc, u_long src, void *dest, int size )); 163 static void iezero __P(( struct ie_softc *sc, u_long p, int size )); 164 void iereset __P(( struct ie_softc *sc )); 165 void iewatchdog __P(( struct ifnet *ifp )); 166 int ieioctl __P(( struct ifnet *ifp, u_long cmd, caddr_t data )); 167 void iestart __P(( struct ifnet *ifp )); 168 int iestop __P(( struct ie_softc *sc )); 169 int ieinit __P(( struct ie_softc *sc )); 170 int ieintr __P(( void *arg )); 171 void ietint __P(( struct ie_softc *sc )); 172 173 /* A whopper of a function */ 174 static int command_and_wait __P(( struct ie_softc *sc, u_short cmd, 175 struct ie_sys_ctl_block *pscb, 176 void *pcmd, int ocmd, int scmd, int mask )); 177 178 int ieprobe __P((struct device *, struct cfdata *, void *)); 179 void ieattach __P((struct device *, struct device *, void *)); 180 181 static __inline void ie_cli(struct ie_softc *); 182 static __inline void ieattn(struct ie_softc *); 183 static __inline void setpage(struct ie_softc *, u_long); 184 static void ie_ack(struct ie_softc *, u_short); 185 void PWriteShorts(char *, char *, int); 186 void ReadShorts(char *, char *, int); 187 static void run_tdr(struct ie_softc *); 188 u_long setup_rfa(struct ie_softc *, u_long); 189 static __inline int ie_buflen(struct ie_softc *, int); 190 static __inline int ie_packet_len(struct ie_softc *); 191 struct mbuf *ieget(struct ie_softc *, int *); 192 void ie_drop_packet_buffer(struct ie_softc *); 193 void ie_read_frame(struct ie_softc *, int num); 194 void ierint(struct ie_softc *); 195 void iexmit(struct ie_softc *); 196 static void start_receiver(struct ie_softc *); 197 198 199 /* 200 * Our cfattach structure for the autoconfig system to chew on 201 */ 202 203 CFATTACH_DECL(ie, sizeof(struct ie_softc), 204 ieprobe, ieattach, NULL, NULL); 205 206 /* Let's go! */ 207 208 /* 209 * Clear all pending interrupts from the i82586 chip 210 */ 211 212 static __inline void 213 ie_cli(sc) 214 struct ie_softc *sc; 215 { 216 WriteByte(sc->sc_fastbase + (IE_CONTROL<<2), IE_CONT_CLI); 217 } 218 219 /* 220 * Wake the i82586 chip up and get it to do something 221 */ 222 223 static __inline void 224 ieattn(sc) 225 struct ie_softc *sc; 226 { 227 WriteByte ( sc->sc_control + (IE_CONTROL<<2), IE_CONT_ATTN ); 228 } 229 230 /* 231 * Set the podule page register to bring a given address into view 232 */ 233 234 static __inline void 235 setpage(sc, off) 236 struct ie_softc *sc; 237 u_long off; 238 { 239 WriteByte ( sc->sc_control + (IE_PAGE<<2), IE_COFF2PAGE(off) ); 240 } 241 242 /* 243 * Ack the i82586 244 */ 245 246 static void 247 ie_ack(sc, mask) 248 struct ie_softc *sc; 249 u_short mask; 250 { 251 u_short stat; 252 int i; 253 setpage(sc, IE_IBASE + IE_SCB_OFF ); 254 255 stat = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) + 256 (xoffsetof(struct ie_sys_ctl_block, ie_status)) ); 257 258 PWriteShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) + 259 (xoffsetof(struct ie_sys_ctl_block, ie_command)), 260 stat & mask ); 261 262 ieattn(sc); 263 264 for ( i=4000; --i>=0; ) { 265 if ( !ReadShort(sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) + 266 (xoffsetof(struct ie_sys_ctl_block, ie_command))) ) 267 break; 268 delay(100); 269 } 270 271 if ( i<=0 ) 272 printf ( "ie: command timed out\n" ); 273 ie_cli(sc); 274 } 275 276 /* 277 * This routine does the checksumming for the idrom 278 */ 279 280 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM 281 static u_long 282 crc32(p, l) 283 u_char *p; 284 int l; 285 { 286 u_long crc=-1; 287 int i, b; 288 while ( --l >= 0 ) { 289 b = *p++; 290 for ( i=8; --i >= 0; b>>=1 ) 291 if ((b&1)^(crc>>31)) 292 crc=(crc<<1)^0x4c11db7; 293 else 294 crc<<=1; 295 } 296 return crc; 297 } 298 #endif 299 300 /* 301 * Probe for the ether1 card. return 1 on success 0 on failure 302 */ 303 304 int 305 ieprobe(struct device *parent, struct cfdata *cf, void *aux) 306 { 307 struct podule_attach_args *pa = (void *)aux; 308 309 /* Look for a network slot interface */ 310 311 return (pa->pa_product == PODULE_ETHER1); 312 } 313 314 /* 315 * Attach our driver to the interfaces it uses 316 */ 317 318 void ieattach ( struct device *parent, struct device *self, void *aux ) 319 { 320 struct ie_softc *sc = (void *)self; 321 struct podule_attach_args *pa = (void *)aux; 322 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 323 int i; 324 char idrom[32]; 325 u_int8_t hwaddr[ETHER_ADDR_LEN]; 326 327 /* Check a few things about the attach args */ 328 329 if (pa->pa_podule_number == -1) 330 panic("Podule has disappeared !"); 331 332 sc->sc_podule_number = pa->pa_podule_number; 333 sc->sc_podule = pa->pa_podule; 334 podules[sc->sc_podule_number].attached = 1; 335 336 /* 337 * MESS MESS MESS 338 * 339 * This needs a serious clean up. Alot of this code was in the probe function 340 * but required the softc structure. As a temporary measure until I rewrite it 341 * I have just bolted in the probe code here. 342 */ 343 344 /* Index some podule areas */ 345 sc->sc_iobase = sc->sc_podule->sync_base; /* OBSOLETE */ 346 sc->sc_fastbase = sc->sc_podule->fast_base; /* OBSOLETE */ 347 sc->sc_rom = sc->sc_podule->sync_base; 348 sc->sc_control = sc->sc_podule->fast_base; 349 sc->sc_ram = sc->sc_podule->fast_base + IE_MEMOFF; 350 351 /* Set the page mask to something know and neutral */ 352 setpage(sc, IE_SCB_OFF); 353 354 /* Fetch the first part of the idrom */ 355 for ( i=0; i<16; i++ ) 356 idrom[i] = ReadByte ( sc->sc_rom + (i<<2) ); 357 358 /* Verify the podulebus probe incase RiscOS lied */ 359 if ( ReadByte ( sc->sc_rom + (3<<2) ) != 0x03 ) { 360 printf(": Ether1 ROM probablly broken. ECID corrupt\n"); 361 sc->sc_flags |= IE_BROKEN; 362 return; 363 } 364 365 /* Reset the 82586 */ 366 WriteByte ( sc->sc_fastbase + (IE_CONTROL<<2), IE_CONT_RESET ); 367 delay(1000); 368 WriteByte ( sc->sc_fastbase + (IE_CONTROL<<2), 0 ); 369 delay(10000); 370 371 /* Clear pending interrupts */ 372 ie_cli (sc); 373 374 /* Setup SCP */ 375 { 376 struct ie_sys_conf_ptr scp; 377 bzero (&scp, sizeof(scp) ); 378 scp.ie_iscp_ptr = (caddr_t)IE_ISCP_ADDR; 379 host2ie(sc, &scp, IE_SCP_ADDR, sizeof (scp) ); 380 } 381 382 /* Setup ISCP */ 383 { 384 struct ie_int_sys_conf_ptr iscp; 385 bzero ( &iscp, sizeof(iscp) ); 386 iscp.ie_busy = 1; 387 iscp.ie_base = (caddr_t)IE_IBASE; 388 iscp.ie_scb_offset = IE_SCB_OFF; 389 host2ie(sc, &iscp, IE_ISCP_ADDR, sizeof(iscp) ); 390 } 391 392 /* Initialise the control block */ 393 iezero ( sc, IE_IBASE + IE_SCB_OFF, sizeof(struct ie_sys_ctl_block) ); 394 ieattn(sc); 395 396 /* Wait for not busy */ 397 setpage ( sc, IE_ISCP_ADDR ); 398 for ( i=10000; --i>=0; ) { 399 if ( !ReadShort( sc->sc_ram + IE_COFF2POFF(IE_ISCP_ADDR) + 400 ( xoffsetof(struct ie_int_sys_conf_ptr, ie_busy)) ) ) 401 break; 402 delay (10); 403 } 404 405 /* If the busy didn't go low, the i82586 is broken or too slow */ 406 if ( i<=0 ) { 407 printf ( ": ether1 chipset didn't respond\n" ); 408 sc->sc_flags |= IE_BROKEN; 409 return; 410 } 411 412 /* Ensure that the podule sends interrupts */ 413 for ( i=1000; --i>=0 ; ) { 414 if ( ReadByte(sc->sc_rom + 0) & PODULE_IRQ_PENDING ) 415 break; 416 delay (10); 417 } 418 419 /* If we didn't see the interrupt then the IRQ line is broken */ 420 if ( i<=0 ) { 421 printf ( ": interrupt from chipset didn't reach host\n" ); 422 sc->sc_flags |= IE_BROKEN; 423 return; 424 } 425 426 /* Ack our little test operation */ 427 ie_ack(sc,IE_ST_WHENCE); 428 ie_cli (sc); 429 430 /* Get second part of idrom */ 431 for ( i=16; i<32; i++ ) 432 idrom[i] = ReadByte ( sc->sc_rom + (i<<2) ); 433 434 /* This checksum always fails. For some reason the first 16 */ 435 /* bytes are duplicated in the second 16 bytes, the checksum */ 436 /* should be at location 28 it is clearly not */ 437 438 /* It is possible that this ether1 card is buggered */ 439 440 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM 441 if ( crc32(idrom,28) != *(u_long *)(idrom+28) ) 442 { 443 printf ( "ie: ether1 idrom failed checksum %08x!=%08x\n", 444 crc32(idrom,28), *(u_long *)(idrom+28)); 445 for ( i=0; i<32; i+=8 ) { 446 printf ( "IDROM: %02x %02x %02x %02x %02x %02x %02x %02x\n", 447 idrom[0+i], idrom[1+i], idrom[2+i], idrom[3+i], 448 idrom[4+i], idrom[5+i], idrom[6+i], idrom[7+i] ); 449 } 450 printf ( "ie: I'll ignore this fact for now!\n" ); 451 } 452 #endif 453 454 /* Get our ethernet address. Do explicit copy */ 455 for ( i=0; i<ETHER_ADDR_LEN; i++ ) 456 hwaddr[i] = idrom[9+i]; 457 458 /* Fill in my application form to attach to the inet system */ 459 460 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 461 ifp->if_softc = sc; 462 ifp->if_start = iestart; 463 ifp->if_ioctl = ieioctl; 464 ifp->if_watchdog = iewatchdog; 465 ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS; 466 467 /* Signed, dated then sent */ 468 if_attach (ifp); 469 ether_ifattach(ifp, hwaddr); 470 471 /* "Hmm," said nuts, "what if the attach fails" */ 472 473 /* Write some pretty things on the annoucement line */ 474 printf ( ": %s using %dk card ram", 475 ether_sprintf(hwaddr), 476 ((NRXBUF*IE_RXBUF_SIZE)+(NTXBUF*IE_TXBUF_SIZE))/1024 ); 477 478 sc->sc_ih.ih_func = ieintr; 479 sc->sc_ih.ih_arg = sc; 480 sc->sc_ih.ih_level = IPL_NET; 481 sc->sc_ih.ih_name = "net: ie"; 482 sc->sc_ih.ih_maskaddr = sc->sc_podule->irq_addr; 483 sc->sc_ih.ih_maskbits = sc->sc_podule->irq_mask; 484 485 if (irq_claim(sc->sc_podule->interrupt, &sc->sc_ih)) { 486 sc->sc_irqmode = 0; 487 printf(" POLLED"); 488 panic("%s: Cannot install IRQ handler", sc->sc_dev.dv_xname); 489 } else { 490 sc->sc_irqmode = 1; 491 printf(" IRQ"); 492 } 493 494 printf("\n"); 495 } 496 497 498 /* 499 * Oh no!! Where's my shorts!!! I'm sure I put them on this morning 500 */ 501 502 void 503 PWriteShorts(src, dest, cnt) 504 char *src; 505 char *dest; 506 int cnt; 507 { 508 for (cnt /= 2; --cnt >= 0; ) { 509 PWriteShort(dest, *(u_short *)src); 510 src+=2; 511 dest+=4; 512 } 513 } 514 515 void 516 ReadShorts(src, dest, cnt) 517 char *src; 518 char *dest; 519 int cnt; 520 { 521 for (cnt /= 2; --cnt >= 0; ) { 522 *(u_short *)dest = ReadShort(src); 523 src+=4; 524 dest+=2; 525 } 526 } 527 528 /* 529 * A bcopy or memcpy to adapter ram. It handles the page register for you 530 * so you dont have to worry about the ram windowing 531 */ 532 533 static void 534 host2ie(sc, src, dest, size) 535 struct ie_softc *sc; 536 void *src; 537 u_long dest; 538 int size; 539 { 540 int cnt; 541 char *sptr = src; 542 543 #ifdef DIAGNOSTIC 544 if (size & 1) 545 panic("host2ie"); 546 #endif 547 548 while (size > 0) { 549 cnt = IE_PAGESIZE - dest % IE_PAGESIZE; 550 if (cnt > size) 551 cnt = size; 552 setpage(sc, dest); 553 PWriteShorts(sptr, (char *)sc->sc_ram + IE_COFF2POFF(dest), cnt); 554 sptr+=cnt; 555 dest+=cnt; 556 size-=cnt; 557 } 558 } 559 560 static void 561 ie2host(sc, src, dest, size) 562 struct ie_softc *sc; 563 u_long src; 564 void *dest; 565 int size; 566 { 567 int cnt; 568 char *dptr = dest; 569 570 #ifdef DIAGNOSTIC 571 if (size & 1) 572 panic ( "ie2host" ); 573 #endif 574 575 while (size > 0) { 576 cnt = IE_PAGESIZE - src % IE_PAGESIZE; 577 if (cnt > size) 578 cnt = size; 579 setpage(sc, src); 580 ReadShorts((char *)sc->sc_ram + IE_COFF2POFF(src), dptr, cnt); 581 src+=cnt; 582 dptr+=cnt; 583 size-=cnt; 584 } 585 } 586 587 /* 588 * Like a bzero or memset 0 for adapter memory. It handles the page 589 * register so you dont have to worry about it 590 */ 591 592 static void 593 iezero(sc, p, size) 594 struct ie_softc *sc; 595 u_long p; 596 int size; 597 { 598 int cnt; 599 600 while (size > 0) { 601 cnt = IE_PAGESIZE - p % IE_PAGESIZE; 602 if (cnt > size) 603 cnt=size; 604 setpage(sc, p); 605 bzero((char *)sc->sc_ram + IE_COFF2POFF(p), 2*cnt); 606 p += cnt; 607 size -= cnt; 608 } 609 } 610 611 /* 612 * I/O Control interface to the kernel, entry point here 613 */ 614 615 int 616 ieioctl(ifp, cmd, data) 617 struct ifnet *ifp; 618 u_long cmd; 619 caddr_t data; 620 { 621 struct ie_softc *sc = ifp->if_softc; 622 struct ifaddr *ifa = (struct ifaddr *)data; 623 /* struct ifreq *ifr = (struct ifreq *)data;*/ 624 int s; 625 int error=0; 626 627 s=splnet(); 628 629 switch ( cmd ) 630 { 631 case SIOCSIFADDR: 632 ifp->if_flags |= IFF_UP; 633 switch ( ifa->ifa_addr->sa_family ) { 634 #ifdef INET 635 case AF_INET: 636 ieinit(sc); 637 arp_ifinit(ifp, ifa ); 638 break; 639 #endif 640 default: 641 ieinit(sc); 642 break; 643 } 644 break; 645 646 #define IZSET(a,b) ((a->if_flags&b)!=0) 647 #define IZCLR(a,b) ((a->if_flags&b)==0) 648 #define DOSET(a,b) (a->if_flags|=b) 649 #define DOCLR(a,b) (a->if_flags&=~b) 650 651 case SIOCSIFFLAGS: 652 sc->promisc = ifp->if_flags & ( IFF_PROMISC | IFF_ALLMULTI ); 653 654 if ( IZCLR(ifp,IFF_UP) && IZSET(ifp,IFF_RUNNING) ) 655 { 656 /* Interface was marked down and its running so stop it */ 657 iestop(sc); 658 DOCLR(ifp,IFF_RUNNING); 659 } 660 else if ( IZSET(ifp,IFF_UP) && IZCLR(ifp,IFF_RUNNING) ) 661 { 662 /* Just marked up and we're not running so start it */ 663 ieinit(sc); 664 } 665 else 666 { 667 /* else reset to invoke changes in other registers */ 668 iestop(sc); 669 ieinit(sc); 670 } 671 672 default: 673 error = EINVAL; 674 } 675 (void)splx(s); 676 return error; 677 } 678 679 /* 680 * Reset the card. Completely. 681 */ 682 683 void 684 iereset(sc) 685 struct ie_softc *sc; 686 { 687 struct ie_sys_ctl_block scb; 688 int s = splnet(); 689 690 iestop(sc); 691 692 ie2host(sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb); 693 694 if (command_and_wait(sc, IE_RU_ABORT|IE_CU_ABORT, 0, 0, 0, 0, 0)) 695 printf("ie0: abort commands timed out\n"); 696 697 if (command_and_wait(sc, IE_RU_DISABLE|IE_CU_STOP, 0, 0, 0, 0, 0)) 698 printf("ie0: abort commands timed out\n"); 699 700 ieinit(sc); 701 702 (void)splx(s); 703 } 704 705 /* 706 * Watchdog entry point. This is the entry for the kernel to call us 707 */ 708 709 void 710 iewatchdog(ifp) 711 struct ifnet *ifp; 712 { 713 struct ie_softc *sc = ifp->if_softc; 714 715 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); 716 ++ifp->if_oerrors; 717 iereset(sc); 718 } 719 720 /* 721 * Start the time-domain-refloctometer running 722 */ 723 724 static void 725 run_tdr(sc) 726 struct ie_softc *sc; 727 { 728 struct ie_sys_ctl_block scb; 729 u_long ptr = IE_IBASE + IE_SCB_OFF + sizeof scb; 730 struct ie_tdr_cmd cmd; 731 int result; 732 733 bzero ( &scb, sizeof(scb) ); 734 bzero ( &cmd, sizeof(cmd) ); 735 736 cmd.com.ie_cmd_status = 0; 737 cmd.com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST; 738 cmd.com.ie_cmd_link = 0xffff; 739 cmd.ie_tdr_time = 0; 740 741 scb.ie_command_list = (u_short)ptr; 742 743 result=0; 744 if ( command_and_wait(sc, IE_CU_START, &scb, &cmd, ptr, sizeof cmd, 745 IE_STAT_COMPL) ) 746 { 747 result = 0x10000; 748 } 749 else if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) ) 750 { 751 result = 0x10000; 752 } 753 754 if ( result==0 ) 755 result = cmd.ie_tdr_time; 756 757 ie_ack ( sc, IE_ST_WHENCE ); 758 759 if (result & IE_TDR_SUCCESS ) 760 return; 761 762 /* Very messy. I'll tidy it later */ 763 764 if ( result & 0x10000 ) 765 { 766 printf ( "ie: TDR command failed\n" ); 767 } 768 else if ( result & IE_TDR_XCVR ) 769 { 770 printf ( "ie: tranceiver problem. Is it plugged in?\n" ); 771 } 772 else if ( result & IE_TDR_OPEN ) 773 { 774 if ((result & IE_TDR_TIME)>0) 775 printf ( "ie: TDR detected an open %d clocks away.\n", 776 result & IE_TDR_TIME ); 777 } 778 else if ( result & IE_TDR_SHORT ) 779 { 780 if ((result & IE_TDR_TIME)>0) 781 printf ( "ie: TDR detected a short %d clock away.\n", 782 result & IE_TDR_TIME ); 783 } 784 else 785 { 786 printf ( "ie: TDR returned unknown status %x\n", result ); 787 } 788 } 789 790 u_long 791 setup_rfa(sc, ptr) 792 struct ie_softc *sc; 793 u_long ptr; 794 { 795 int i; 796 { 797 /* Receive frame descriptors */ 798 struct ie_recv_frame_desc rfd; 799 bzero( &rfd, sizeof rfd ); 800 for ( i=0; i<NFRAMES; i++ ) 801 { 802 sc->rframes[i] = ptr; 803 rfd.ie_fd_next = ptr + sizeof rfd; 804 host2ie(sc, (char *)&rfd, ptr, sizeof rfd); 805 ptr += sizeof rfd; 806 } 807 rfd.ie_fd_next = sc->rframes[0]; 808 rfd.ie_fd_last |= IE_FD_LAST; 809 host2ie(sc, (char *)&rfd, sc->rframes[NFRAMES-1], sizeof rfd ); 810 811 ie2host(sc, sc->rframes[0], (char *)&rfd, sizeof rfd ); 812 rfd.ie_fd_buf_desc = (u_short) ptr; 813 host2ie(sc, (char *)&rfd, sc->rframes[0], sizeof rfd ); 814 } 815 816 { 817 /* Receive frame descriptors */ 818 struct ie_recv_buf_desc rbd; 819 bzero(&rbd, sizeof rbd); 820 for ( i=0; i<NRXBUF; i++ ) 821 { 822 sc->rbuffs[i] = ptr; 823 rbd.ie_rbd_length = IE_RXBUF_SIZE; 824 rbd.ie_rbd_buffer = (caddr_t)(ptr + sizeof rbd); 825 rbd.ie_rbd_next = (u_short)(ptr + sizeof rbd + IE_RXBUF_SIZE); 826 host2ie(sc, &rbd, ptr, sizeof rbd); 827 ptr+=sizeof rbd; 828 829 sc->cbuffs[i] = ptr; 830 ptr+=IE_RXBUF_SIZE; 831 } 832 rbd.ie_rbd_next = sc->rbuffs[0]; 833 rbd.ie_rbd_length |= IE_RBD_LAST; 834 host2ie(sc, &rbd, sc->rbuffs[NRXBUF-1], sizeof rbd); 835 } 836 837 sc->rfhead = 0; 838 sc->rftail = NFRAMES-1; 839 sc->rbhead = 0; 840 sc->rbtail = NRXBUF-1; 841 842 { 843 struct ie_sys_ctl_block scb; 844 bzero ( &scb, sizeof scb ); 845 scb.ie_recv_list = (u_short)sc->rframes[0]; 846 host2ie(sc, (char *)&scb, (IE_IBASE + IE_SCB_OFF), sizeof scb ); 847 } 848 return ptr; 849 } 850 851 static void 852 start_receiver(sc) 853 struct ie_softc *sc; 854 { 855 struct ie_sys_ctl_block scb; 856 ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb ); 857 scb.ie_recv_list = (u_short)sc->rframes[0]; 858 command_and_wait(sc, IE_RU_START, &scb, 0, 0, 0, 0); 859 ie_ack(sc, IE_ST_WHENCE ); 860 } 861 862 /* 863 * Take our configuration and update all the other data structures that 864 * require information from the driver. 865 * 866 * CALL AT SPLIMP OR HIGHER 867 */ 868 869 int 870 ieinit(sc) 871 struct ie_softc *sc; 872 { 873 struct ifnet *ifp; 874 struct ie_sys_ctl_block scb; 875 struct ie_config_cmd cmd; 876 struct ie_iasetup_cmd iasetup_cmd; 877 u_long ptr = IE_IBASE + IE_SCB_OFF + sizeof scb; 878 int n; 879 880 ifp = &sc->sc_ethercom.ec_if; 881 882 bzero ( &scb, sizeof(scb) ); 883 884 /* Send the configure command */ 885 886 cmd.com.ie_cmd_status = 0; 887 cmd.com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST; 888 cmd.com.ie_cmd_link = 0xffff; 889 890 cmd.ie_config_count = 0x0c; 891 cmd.ie_fifo = 8; 892 cmd.ie_save_bad = 0x40; 893 cmd.ie_addr_len = 0x2e; 894 cmd.ie_priority = 0; 895 cmd.ie_ifs = 0x60; 896 cmd.ie_slot_low = 0; 897 cmd.ie_slot_high = 0xf2; 898 cmd.ie_promisc = 0; /* Hey nuts, look at this! */ 899 cmd.ie_crs_cdt = 0; 900 cmd.ie_min_len = 64; 901 cmd.ie_junk = 0xff; 902 903 scb.ie_command_list = (u_short)ptr; 904 905 if ( command_and_wait(sc, IE_CU_START, &scb, &cmd, ptr, sizeof cmd, 906 IE_STAT_COMPL) ) 907 { 908 printf ( "%s: command failed: timeout\n", sc->sc_dev.dv_xname ); 909 return 0; 910 } 911 912 if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) ) 913 { 914 printf ( "%s: command failed: !IE_STAT_OK\n", sc->sc_dev.dv_xname ); 915 return 0; 916 } 917 918 /* Individual address setup command */ 919 920 iasetup_cmd.com.ie_cmd_status = 0; 921 iasetup_cmd.com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST; 922 iasetup_cmd.com.ie_cmd_link = 0xffff; 923 924 bcopy ( LLADDR(ifp->if_sadl), (caddr_t) &iasetup_cmd.ie_address, 925 sizeof (iasetup_cmd.ie_address) ); 926 927 if ( command_and_wait(sc, IE_CU_START, &scb, &iasetup_cmd, ptr, sizeof cmd, 928 IE_STAT_COMPL) ) 929 { 930 printf ( "%s: iasetup failed : timeout\n", sc->sc_dev.dv_xname ); 931 return 0; 932 } 933 934 if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) ) 935 { 936 printf ( "%s: iasetup failed : !IE_STAT_OK\n", sc->sc_dev.dv_xname ); 937 return 0; 938 } 939 940 ie_ack ( sc, IE_ST_WHENCE ); 941 942 /* Run the time-domain refloctometer */ 943 run_tdr ( sc ); 944 945 ie_ack ( sc, IE_ST_WHENCE ); 946 947 /* meminit */ 948 ptr = setup_rfa(sc, ptr); 949 950 ifp->if_flags |= IFF_RUNNING; 951 ifp->if_flags &= ~IFF_OACTIVE; 952 953 /* Setup transmit buffers */ 954 955 for ( n=0; n<NTXBUF; n++ ) { 956 sc->xmit_cmds[n] = ptr; 957 iezero(sc, ptr, sizeof(struct ie_xmit_cmd) ); 958 ptr += sizeof(struct ie_xmit_cmd); 959 960 sc->xmit_buffs[n] = ptr; 961 iezero(sc, ptr, sizeof(struct ie_xmit_buf)); 962 ptr += sizeof(struct ie_xmit_buf); 963 } 964 965 for ( n=0; n<NTXBUF; n++ ) { 966 sc->xmit_cbuffs[n] = ptr; 967 ptr += IE_TXBUF_SIZE; 968 } 969 970 sc->xmit_free = NTXBUF; 971 sc->xchead = sc->xctail = 0; 972 973 { 974 struct ie_xmit_cmd xmcmd; 975 bzero ( &xmcmd, sizeof xmcmd ); 976 xmcmd.ie_xmit_status = IE_STAT_COMPL; 977 host2ie(sc, &xmcmd, sc->xmit_cmds[0], sizeof xmcmd); 978 } 979 980 start_receiver (sc); 981 982 return 0; 983 } 984 985 int 986 iestop(sc) 987 struct ie_softc *sc; 988 { 989 struct ie_sys_ctl_block scb; 990 int s = splnet(); 991 992 ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb ); 993 994 if ( command_and_wait(sc, IE_RU_DISABLE, &scb, 0, 0, 0, 0) ) 995 printf ( "ie0: abort commands timed out\n" ); 996 997 (void)splx(s); 998 return(0); 999 } 1000 1001 /* 1002 * Send a command to the card and awaits it's completion. 1003 * Timeout if it's taking too long 1004 */ 1005 1006 /*CAW*/ 1007 1008 static int 1009 command_and_wait(sc, cmd, pscb, pcmd, ocmd, scmd, mask) 1010 struct ie_softc *sc; 1011 u_short cmd; 1012 struct ie_sys_ctl_block *pscb; 1013 void *pcmd; 1014 int ocmd, scmd, mask; 1015 { 1016 int i=0; 1017 1018 /* Copy the command to the card */ 1019 1020 if ( pcmd ) 1021 host2ie(sc, pcmd, ocmd, scmd); /* transfer the command to the card */ 1022 1023 /* Copy the scb to the card */ 1024 1025 if ( pscb ) { 1026 pscb->ie_command = cmd; 1027 host2ie(sc, pscb, IE_IBASE + IE_SCB_OFF, sizeof *pscb); 1028 } 1029 else 1030 { 1031 setpage ( sc, IE_IBASE + IE_SCB_OFF ); 1032 PWriteShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) + 1033 (xoffsetof(struct ie_sys_ctl_block, ie_command)), cmd ); 1034 } 1035 1036 /* Prod the card to act on the newly loaded command */ 1037 ieattn(sc); 1038 1039 /* Wait for the command to complete */ 1040 if ( IE_ACTION_COMMAND(cmd) && pcmd ) 1041 { 1042 setpage(sc,ocmd); 1043 for ( i=4000; --i>=0; ) { 1044 if ( ReadShort(sc->sc_ram + IE_COFF2POFF(ocmd) + 1045 (xoffsetof(struct ie_config_cmd, ie_config_status))) & mask) 1046 break; 1047 delay(100); 1048 } 1049 } 1050 else 1051 { 1052 for ( i=4000; --i>=0; ) { 1053 if ( !ReadShort(sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) + 1054 (xoffsetof(struct ie_sys_ctl_block, ie_command))) ) 1055 break; 1056 delay(100); 1057 } 1058 } 1059 1060 /* Update the host structures to reflect the state on the card */ 1061 if ( pscb ) 1062 ie2host(sc, IE_IBASE + IE_SCB_OFF, pscb, sizeof *pscb ); 1063 if ( pcmd ) 1064 ie2host(sc, ocmd, pcmd, scmd); 1065 1066 return i < 0; 1067 } 1068 1069 #define READ_MEMBER(sc,type,member,ptr,dest) \ 1070 setpage(sc, ptr); \ 1071 dest = ReadShort(sc->sc_ram + IE_COFF2POFF(ptr) + \ 1072 (xoffsetof(type, member)) ); 1073 1074 #define WRITE_MEMBER(sc,type,member,ptr,dest) \ 1075 setpage(sc, ptr); \ 1076 PWriteShort(sc->sc_ram + IE_COFF2POFF(ptr) + \ 1077 (xoffsetof(type, member)), dest ); 1078 1079 static __inline int 1080 ie_buflen(sc, head) 1081 struct ie_softc *sc; 1082 int head; 1083 { 1084 int actual; 1085 1086 READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual, 1087 sc->rbuffs[head], actual ); 1088 1089 return(actual & (IE_RXBUF_SIZE | (IE_RXBUF_SIZE-1))) ; 1090 } 1091 1092 static __inline int 1093 ie_packet_len(sc) 1094 struct ie_softc *sc; 1095 { 1096 int i; 1097 int actual; 1098 int head = sc->rbhead; 1099 int acc=0; 1100 1101 do { 1102 READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual, 1103 sc->rbuffs[sc->rbhead], actual ); 1104 if (!(actual&IE_RBD_USED)) 1105 { 1106 return (-1); 1107 } 1108 1109 READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual, 1110 sc->rbuffs[head], i ); 1111 i = i & IE_RBD_LAST; 1112 1113 acc += ie_buflen(sc, head); 1114 head = (head+1) % NRXBUF; 1115 } while (!i); 1116 1117 return acc; 1118 } 1119 1120 struct mbuf * 1121 ieget(struct ie_softc *sc, int *to_bpf ) 1122 { 1123 struct mbuf *top, **mp, *m; 1124 int head; 1125 int resid, totlen, thisrboff, thismboff; 1126 int len; 1127 struct ether_header eh; 1128 1129 totlen = ie_packet_len(sc); 1130 1131 if ( totlen > ETHER_MAX_LEN ) 1132 { 1133 printf ( "ie: Gosh that packet was s-o-o-o big.\n" ); 1134 return 0; 1135 } 1136 1137 if ( totlen<=0 ) 1138 return 0; 1139 1140 head = sc->rbhead; 1141 1142 /* Read the ethernet header */ 1143 ie2host ( sc, sc->cbuffs[head], (caddr_t)&eh, sizeof eh ); 1144 1145 /* Check if the packet is for us */ 1146 1147 resid = totlen; 1148 1149 MGETHDR ( m, M_DONTWAIT, MT_DATA ); 1150 if ( m==0 ) 1151 return 0; 1152 1153 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if; 1154 m->m_pkthdr.len = totlen; 1155 len = MHLEN; 1156 top = 0; 1157 mp = ⊤ 1158 1159 /* 1160 * This loop goes through and allocates mbufs for all the data we will 1161 * be copying in. It does not actually do the copying yet. 1162 */ 1163 while (totlen > 0) { 1164 if (top) { 1165 MGET(m, M_DONTWAIT, MT_DATA); 1166 if (m == 0) { 1167 m_freem(top); 1168 return 0; 1169 } 1170 len = MLEN; 1171 } 1172 if (totlen >= MINCLSIZE) { 1173 MCLGET(m, M_DONTWAIT); 1174 if (m->m_flags & M_EXT) 1175 len = MCLBYTES; 1176 } 1177 1178 if (mp == &top) { 1179 caddr_t newdata = (caddr_t) 1180 ALIGN(m->m_data + sizeof(struct ether_header)) - 1181 sizeof(struct ether_header); 1182 len -= newdata - m->m_data; 1183 m->m_data = newdata; 1184 } 1185 1186 m->m_len = len = min(totlen, len); 1187 1188 totlen -= len; 1189 *mp = m; 1190 mp = &m->m_next; 1191 } 1192 1193 m = top; 1194 thismboff = 0; 1195 1196 /* 1197 * Copy the Ethernet header into the mbuf chain. 1198 */ 1199 memcpy(mtod(m, caddr_t), &eh, sizeof(struct ether_header)); 1200 thismboff = sizeof(struct ether_header); 1201 thisrboff = sizeof(struct ether_header); 1202 resid -= sizeof(struct ether_header); 1203 1204 /* 1205 * Now we take the mbuf chain (hopefully only one mbuf most of the 1206 * time) and stuff the data into it. There are no possible failures at 1207 * or after this point. 1208 */ 1209 while (resid > 0) { 1210 int thisrblen = ie_buflen(sc, head) - thisrboff, 1211 thismblen = m->m_len - thismboff; 1212 len = min(thisrblen, thismblen); 1213 1214 /* bcopy((caddr_t)(sc->cbuffs[head] + thisrboff), 1215 mtod(m, caddr_t) + thismboff, (u_int)len); */ 1216 1217 1218 if ( len&1 ) 1219 { 1220 ie2host(sc, sc->cbuffs[head]+thisrboff, 1221 mtod(m, caddr_t) + thismboff, (u_int)len+1); 1222 } 1223 else 1224 { 1225 ie2host(sc, sc->cbuffs[head]+thisrboff, 1226 mtod(m, caddr_t) + thismboff, (u_int)len); 1227 } 1228 1229 resid -= len; 1230 1231 if (len == thismblen) { 1232 m = m->m_next; 1233 thismboff = 0; 1234 } else 1235 thismboff += len; 1236 1237 if (len == thisrblen) { 1238 head = (head + 1) % NRXBUF; 1239 thisrboff = 0; 1240 } else 1241 thisrboff += len; 1242 } 1243 1244 1245 return top; 1246 } 1247 1248 void 1249 ie_drop_packet_buffer(sc) 1250 struct ie_softc *sc; 1251 { 1252 int i, actual, last; 1253 1254 do { 1255 READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual, 1256 sc->rbuffs[sc->rbhead], actual ); 1257 if (!(actual&IE_RBD_USED)) 1258 { 1259 iereset(sc); 1260 return; 1261 } 1262 1263 i = actual & IE_RBD_LAST; 1264 1265 READ_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length, 1266 sc->rbuffs[sc->rbhead], last ); 1267 last |= IE_RBD_LAST; 1268 WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length, 1269 sc->rbuffs[sc->rbhead], last ); 1270 1271 WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_actual, 1272 sc->rbuffs[sc->rbhead], 0 ); 1273 1274 sc->rbhead = ( sc->rbhead + 1 ) % NRXBUF; 1275 1276 READ_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length, 1277 sc->rbuffs[sc->rbtail], last ); 1278 last &= ~IE_RBD_LAST; 1279 WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length, 1280 sc->rbuffs[sc->rbtail], last ); 1281 1282 sc->rbtail = ( sc->rbtail + 1 ) % NRXBUF; 1283 } while (!i); 1284 } 1285 1286 void 1287 ie_read_frame(sc, num) 1288 struct ie_softc *sc; 1289 int num; 1290 { 1291 int status; 1292 struct ie_recv_frame_desc rfd; 1293 struct mbuf *m=0; 1294 struct ifnet *ifp; 1295 int last; 1296 1297 ifp = &sc->sc_ethercom.ec_if; 1298 1299 ie2host(sc, sc->rframes[num], &rfd, sizeof rfd ); 1300 status = rfd.ie_fd_status; 1301 1302 /* Advance the RFD list, since we're done with this descriptor */ 1303 1304 WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_status, 1305 sc->rframes[num], 0 ); 1306 1307 READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last, 1308 sc->rframes[num], last ); 1309 last |= IE_FD_LAST; 1310 WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last, 1311 sc->rframes[num], last ); 1312 1313 READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last, 1314 sc->rframes[sc->rftail], last ); 1315 last &= ~IE_FD_LAST; 1316 WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last, 1317 sc->rframes[sc->rftail], last ); 1318 1319 sc->rftail = ( sc->rftail + 1 ) % NFRAMES; 1320 sc->rfhead = ( sc->rfhead + 1 ) % NFRAMES; 1321 1322 if ( status & IE_FD_OK ) { 1323 m = ieget(sc, 0); 1324 ie_drop_packet_buffer(sc); 1325 } 1326 1327 if ( m==0 ) { 1328 ifp->if_ierrors++; 1329 return; 1330 } 1331 1332 ifp->if_ipackets++; 1333 1334 #if NBPFILTER > 0 1335 if ( ifp->if_bpf ) { 1336 bpf_mtap(ifp->if_bpf, m ); 1337 }; 1338 #endif 1339 1340 (*ifp->if_input)(ifp, m); 1341 } 1342 1343 void 1344 ierint(sc) 1345 struct ie_softc *sc; 1346 { 1347 int i; 1348 int times_thru = 1024; 1349 struct ie_sys_ctl_block scb; 1350 int status; 1351 int safety_catch = 0; 1352 1353 i = sc->rfhead; 1354 for (;;) { 1355 1356 if ( (safety_catch++)>100 ) 1357 { 1358 printf ( "ie: ierint safety catch tripped\n" ); 1359 iereset(sc); 1360 return; 1361 } 1362 1363 READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_status, 1364 sc->rframes[i],status); 1365 1366 if ((status&IE_FD_COMPLETE)&&(status&IE_FD_OK)) { 1367 if ( !--times_thru ) { 1368 printf ( "IERINT: Uh oh. Nuts, look at this bit!!!\n" ); 1369 ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb ); 1370 sc->sc_ethercom.ec_if.if_ierrors += scb.ie_err_crc + 1371 scb.ie_err_align + 1372 scb.ie_err_resource + 1373 scb.ie_err_overrun; 1374 scb.ie_err_crc = scb.ie_err_align = 0; 1375 scb.ie_err_resource = scb.ie_err_overrun = 0; 1376 host2ie(sc, &scb, IE_SCP_ADDR, sizeof (scb) ); 1377 } 1378 ie_read_frame(sc, i); 1379 } else { 1380 ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb ); 1381 1382 if ( ((status&IE_FD_RNR)!=0) && ((scb.ie_status&IE_RU_READY)==0) ) 1383 { 1384 WRITE_MEMBER(sc,struct ie_recv_frame_desc, ie_fd_buf_desc, 1385 sc->rframes[0], sc->rbuffs[0] ); 1386 1387 scb.ie_recv_list = sc->rframes[0]; 1388 host2ie(sc, (char *)&scb, IE_IBASE + IE_SCB_OFF, sizeof (scb) ); 1389 command_and_wait(sc, IE_RU_START, &scb, 0, 0, 0, 0); 1390 } 1391 break; 1392 } 1393 i = (i + 1) % NFRAMES; 1394 } 1395 } 1396 1397 static int in_intr = 0; 1398 1399 int 1400 ieintr(arg) 1401 void *arg; 1402 { 1403 struct ie_softc *sc = arg; 1404 u_short status; 1405 int safety_catch = 0; 1406 static int safety_net = 0; 1407 1408 if (in_intr == 1) 1409 panic ( "ie: INTERRUPT REENTERED\n" ); 1410 1411 /* Clear the interrrupt */ 1412 ie_cli (sc); 1413 1414 setpage(sc, IE_IBASE + IE_SCB_OFF ); 1415 status = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) + 1416 (xoffsetof(struct ie_sys_ctl_block, ie_status)) ); 1417 1418 status = status & IE_ST_WHENCE; 1419 1420 if (status == 0) { 1421 in_intr = 0; 1422 return(0); 1423 } 1424 1425 loop: 1426 1427 ie_ack(sc, status); 1428 1429 if (status & (IE_ST_FR | IE_ST_RNR)) 1430 ierint(sc); 1431 1432 if (status & IE_ST_CX) 1433 ietint(sc); 1434 1435 if (status & IE_ST_RNR) { 1436 printf ( "ie: receiver not ready\n" ); 1437 sc->sc_ethercom.ec_if.if_ierrors++; 1438 iereset(sc); 1439 } 1440 1441 setpage(sc, IE_IBASE + IE_SCB_OFF ); 1442 status = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) + 1443 (xoffsetof(struct ie_sys_ctl_block, ie_status)) ); 1444 status = status & IE_ST_WHENCE; 1445 1446 ie_cli(sc); 1447 1448 if (status == 0) { 1449 in_intr = 0; 1450 return(0); 1451 } 1452 1453 /* This is prehaps a little over cautious */ 1454 if ( safety_catch++ > 10 ) 1455 { 1456 printf ( "ie: Interrupt couldn't be cleared\n" ); 1457 delay ( 1000 ); 1458 ie_cli(sc); 1459 if ( safety_net++ > 50 ) 1460 { 1461 /* printf ( "ie: safety net catches driver, shutting down\n" ); 1462 disable_irq ( IRQ_PODULE );*/ 1463 } 1464 in_intr = 0; 1465 return(0); 1466 } 1467 1468 goto loop; 1469 } 1470 1471 void 1472 iexmit(sc) 1473 struct ie_softc *sc; 1474 { 1475 /* int actual;*/ 1476 struct ie_sys_ctl_block scb; 1477 1478 struct ie_xmit_cmd xc; 1479 struct ie_xmit_buf xb; 1480 1481 ie2host(sc, sc->xmit_buffs[sc->xctail], (char *)&xb, sizeof xb ); 1482 xb.ie_xmit_flags |= IE_XMIT_LAST; 1483 xb.ie_xmit_next = 0xffff; 1484 xb.ie_xmit_buf = (caddr_t)sc->xmit_cbuffs[sc->xctail]; 1485 host2ie(sc, &xb, sc->xmit_buffs[sc->xctail], sizeof xb ); 1486 1487 bzero ( &xc, sizeof xc ); 1488 xc.com.ie_cmd_link = 0xffff; 1489 xc.com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST; 1490 xc.ie_xmit_status = 0x0000; 1491 xc.ie_xmit_desc = sc->xmit_buffs[sc->xctail]; 1492 host2ie(sc, (char *)&xc, sc->xmit_cmds[sc->xctail], sizeof xc ); 1493 1494 ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb ); 1495 scb.ie_command_list = sc->xmit_cmds[sc->xctail]; 1496 host2ie(sc, (char *)&scb, (IE_IBASE + IE_SCB_OFF), sizeof scb ); 1497 1498 command_and_wait(sc, IE_CU_START, &scb, &xc, sc->xmit_cmds[sc->xctail] 1499 , sizeof xc, IE_STAT_COMPL); 1500 1501 sc->sc_ethercom.ec_if.if_timer = 5; 1502 } 1503 /* 1504 * Start sending all the queued buffers. 1505 */ 1506 1507 void 1508 iestart(ifp) 1509 struct ifnet *ifp; 1510 { 1511 struct ie_softc *sc = ifp->if_softc; 1512 struct mbuf *m0, *m; 1513 u_char *buffer; 1514 u_short len; 1515 char txbuf[IE_TXBUF_SIZE]; 1516 int safety_catch = 0; 1517 1518 if ((ifp->if_flags & IFF_OACTIVE) != 0) 1519 return; 1520 1521 for (;;) { 1522 if ( (safety_catch++)>100 ) 1523 { 1524 printf ( "ie: iestart safety catch tripped\n" ); 1525 iereset(sc); 1526 return; 1527 } 1528 if (sc->xmit_free == 0) { 1529 ifp->if_flags |= IFF_OACTIVE; 1530 break; 1531 } 1532 1533 IF_DEQUEUE(&ifp->if_snd, m); 1534 if (!m) 1535 break; 1536 1537 /* TODO: Write directly to the card */ 1538 len = 0; 1539 /* buffer = sc->xmit_cbuffs[sc->xchead]; */ 1540 buffer = txbuf; 1541 1542 for (m0 = m; m && (len + m->m_len) < IE_TXBUF_SIZE; 1543 m = m->m_next) { 1544 bcopy(mtod(m, caddr_t), buffer, m->m_len); 1545 buffer += m->m_len; 1546 len += m->m_len; 1547 } 1548 1549 #if NBPFILTER > 0 1550 if ( ifp->if_bpf ) 1551 bpf_mtap(ifp->if_bpf, m0); 1552 #endif 1553 1554 m_freem(m0); 1555 if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) { 1556 memset(buffer, 0, ETHER_MIN_LEN - ETHER_CRC_LEN - len); 1557 len = ETHER_MIN_LEN - ETHER_CRC_LEN; 1558 buffer += ETHER_MIN_LEN - ETHER_CRC_LEN; 1559 } 1560 1561 /* When we write directly to the card we dont need this */ 1562 if (len&1) 1563 host2ie(sc, txbuf, sc->xmit_cbuffs[sc->xchead], len+1 ); 1564 else 1565 host2ie(sc, txbuf, sc->xmit_cbuffs[sc->xchead], len ); 1566 1567 /* sc->xmit_buffs[sc->xchead]->ie_xmit_flags = len; */ 1568 1569 WRITE_MEMBER(sc,struct ie_xmit_buf, ie_xmit_flags, 1570 sc->xmit_buffs[sc->xchead], len) 1571 1572 /* Start the first packet transmitting. */ 1573 if (sc->xmit_free == NTXBUF) 1574 iexmit(sc); 1575 1576 sc->xchead = (sc->xchead + 1) % NTXBUF; 1577 sc->xmit_free--; 1578 } 1579 } 1580 1581 void 1582 ietint(sc) 1583 struct ie_softc *sc; 1584 { 1585 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 1586 1587 int status; 1588 1589 ifp->if_timer=0; 1590 ifp->if_flags &= ~IFF_OACTIVE; 1591 1592 READ_MEMBER(sc,struct ie_xmit_cmd, ie_xmit_status, 1593 sc->xmit_cmds[sc->xctail], status ); 1594 1595 if (!(status&IE_STAT_COMPL) || (status & IE_STAT_BUSY) ) 1596 printf ( "ietint: command still busy!\n" ); 1597 1598 if ( status & IE_STAT_OK ) { 1599 ifp->if_opackets++; 1600 ifp->if_collisions += status & IE_XS_MAXCOLL; 1601 } else { 1602 ifp->if_oerrors++; 1603 if ( status & IE_STAT_ABORT ) 1604 printf ( "ie: send aborted\n" ); 1605 if ( status & IE_XS_LATECOLL ) 1606 printf ( "ie: late collision\n" ); 1607 if ( status & IE_XS_NOCARRIER ) 1608 printf ( "ie: no carrier\n" ); 1609 if ( status & IE_XS_LOSTCTS ) 1610 printf ( "ie: lost CTS\n" ); 1611 if ( status & IE_XS_UNDERRUN ) 1612 printf ( "ie: DMA underrun\n" ); 1613 if ( status & IE_XS_EXCMAX ) 1614 printf ( "ie: too many collisions\n" ); 1615 ifp->if_collisions+=16; 1616 } 1617 /* Done with the buffer */ 1618 sc->xmit_free++; 1619 sc->xctail = (sc->xctail + 1 ) % NTXBUF; 1620 1621 /* Start the next packet transmitting, if any */ 1622 if ( sc->xmit_free<NTXBUF ) 1623 iexmit(sc); 1624 1625 iestart(ifp); 1626 } 1627 1628 /* End of if_ie.c */ 1629