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