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