175 176/* 177 * autoconfig attachments 178 */ 179 180struct cfdriver en_cd = { 181 0, "en", DV_IFNET, 182}; 183 184/* 185 * local structures 186 */ 187 188/* 189 * params to en_txlaunch() function 190 */ 191 192struct en_launch { 193 u_int32_t tbd1; /* TBD 1 */ 194 u_int32_t tbd2; /* TBD 2 */ 195 u_int32_t pdu1; /* PDU 1 (aal5) */ 196 int nodma; /* don't use DMA */ 197 int need; /* total space we need (pad out if less data) */ 198 int mlen; /* length of mbuf (for dtq) */ 199 struct mbuf *t; /* data */ 200 u_int32_t aal; /* aal code */ 201 u_int32_t atm_vci; /* vci */ 202 u_int8_t atm_flags; /* flags */ 203}; 204 205 206/* 207 * dma table (index by # of words) 208 * 209 * plan A: use WMAYBE 210 * plan B: avoid WMAYBE 211 */ 212 213struct en_dmatab { 214 u_int8_t bcode; /* code */ 215 u_int8_t divshift; /* byte divisor */ 216}; 217 218static struct en_dmatab en_dma_planA[] = { 219 { 0, 0 }, /* 0 */ { MIDDMA_WORD, 2 }, /* 1 */ 220 { MIDDMA_2WORD, 3}, /* 2 */ { MIDDMA_4WMAYBE, 2}, /* 3 */ 221 { MIDDMA_4WORD, 4}, /* 4 */ { MIDDMA_8WMAYBE, 2}, /* 5 */ 222 { MIDDMA_8WMAYBE, 2}, /* 6 */ { MIDDMA_8WMAYBE, 2}, /* 7 */ 223 { MIDDMA_8WORD, 5}, /* 8 */ { MIDDMA_16WMAYBE, 2}, /* 9 */ 224 { MIDDMA_16WMAYBE,2}, /* 10 */ { MIDDMA_16WMAYBE, 2}, /* 11 */ 225 { MIDDMA_16WMAYBE,2}, /* 12 */ { MIDDMA_16WMAYBE, 2}, /* 13 */ 226 { MIDDMA_16WMAYBE,2}, /* 14 */ { MIDDMA_16WMAYBE, 2}, /* 15 */ 227 { MIDDMA_16WORD, 6}, /* 16 */ 228}; 229 230static struct en_dmatab en_dma_planB[] = { 231 { 0, 0 }, /* 0 */ { MIDDMA_WORD, 2}, /* 1 */ 232 { MIDDMA_2WORD, 3}, /* 2 */ { MIDDMA_WORD, 2}, /* 3 */ 233 { MIDDMA_4WORD, 4}, /* 4 */ { MIDDMA_WORD, 2}, /* 5 */ 234 { MIDDMA_2WORD, 3}, /* 6 */ { MIDDMA_WORD, 2}, /* 7 */ 235 { MIDDMA_8WORD, 5}, /* 8 */ { MIDDMA_WORD, 2}, /* 9 */ 236 { MIDDMA_2WORD, 3}, /* 10 */ { MIDDMA_WORD, 2}, /* 11 */ 237 { MIDDMA_4WORD, 4}, /* 12 */ { MIDDMA_WORD, 2}, /* 13 */ 238 { MIDDMA_2WORD, 3}, /* 14 */ { MIDDMA_WORD, 2}, /* 15 */ 239 { MIDDMA_16WORD, 6}, /* 16 */ 240}; 241 242static struct en_dmatab *en_dmaplan = en_dma_planA; 243 244/* 245 * prototypes 246 */ 247 248STATIC int en_b2sz __P((int)); 249#ifdef EN_DDBHOOK 250int en_dump __P((int,int)); 251int en_dumpmem __P((int,int,int)); 252#endif 253STATIC void en_dmaprobe __P((struct en_softc *)); 254STATIC int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *, 255 u_int8_t *, int)); 256STATIC int en_dqneed __P((struct en_softc *, caddr_t, u_int, u_int)); 257STATIC void en_init __P((struct en_softc *)); 258STATIC int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t)); 259STATIC int en_k2sz __P((int)); 260STATIC void en_loadvc __P((struct en_softc *, int)); 261STATIC int en_mfix __P((struct en_softc *, struct mbuf **, struct mbuf *)); 262STATIC struct mbuf *en_mget __P((struct en_softc *, u_int, u_int *)); 263STATIC u_int32_t en_read __P((struct en_softc *, u_int32_t)); 264STATIC int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *, int)); 265STATIC void en_txdma __P((struct en_softc *, int)); 266STATIC void en_txlaunch __P((struct en_softc *, int, struct en_launch *)); 267STATIC void en_service __P((struct en_softc *)); 268STATIC void en_start __P((struct ifnet *)); 269STATIC int en_sz2b __P((int)); 270STATIC void en_write __P((struct en_softc *, u_int32_t, u_int32_t)); 271 272/* 273 * macros/inline 274 */ 275 276/* 277 * raw read/write macros 278 */ 279 280#define EN_READDAT(SC,R) en_read(SC,R) 281#define EN_WRITEDAT(SC,R,V) en_write(SC,R,V) 282 283/* 284 * cooked read/write macros 285 */ 286 287#define EN_READ(SC,R) ntohl(en_read(SC,R)) 288#define EN_WRITE(SC,R,V) en_write(SC,R, htonl(V)) 289 290#define EN_WRAPADD(START,STOP,CUR,VAL) { \ 291 (CUR) = (CUR) + (VAL); \ 292 if ((CUR) >= (STOP)) \ 293 (CUR) = (START) + ((CUR) - (STOP)); \ 294 } 295 296#define WORD_IDX(START, X) (((X) - (START)) / sizeof(u_int32_t)) 297 298/* we store sc->dtq and sc->drq data in the following format... */ 299#define EN_DQ_MK(SLOT,LEN) (((SLOT) << 20)|(LEN)|(0x80000)) 300 /* the 0x80000 ensures we != 0 */ 301#define EN_DQ_SLOT(X) ((X) >> 20) 302#define EN_DQ_LEN(X) ((X) & 0x3ffff) 303 304/* format of DTQ/DRQ word 1 differs between ENI and ADP */ 305#if defined(MIDWAY_ENIONLY) 306 307#define MID_MK_TXQ(SC,CNT,CHAN,END,BCODE) \ 308 EN_WRITE((SC), (SC)->dtq_us, \ 309 MID_MK_TXQ_ENI((CNT), (CHAN), (END), (BCODE))); 310 311#define MID_MK_RXQ(SC,CNT,VCI,END,BCODE) \ 312 EN_WRITE((SC), (SC)->drq_us, \ 313 MID_MK_RXQ_ENI((CNT), (VCI), (END), (BCODE))); 314 315#elif defined(MIDWAY_ADPONLY) 316 317#define MID_MK_TXQ(SC,CNT,CHAN,END,JK) \ 318 EN_WRITE((SC), (SC)->dtq_us, \ 319 MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK))); 320 321#define MID_MK_RXQ(SC,CNT,VCI,END,JK) \ 322 EN_WRITE((SC), (SC)->drq_us, \ 323 MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK))); 324 325#else 326 327#define MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE) { \ 328 if ((SC)->is_adaptec) \ 329 EN_WRITE((SC), (SC)->dtq_us, \ 330 MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK_OR_BCODE))); \ 331 else \ 332 EN_WRITE((SC), (SC)->dtq_us, \ 333 MID_MK_TXQ_ENI((CNT), (CHAN), (END), (JK_OR_BCODE))); \ 334 } 335 336#define MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE) { \ 337 if ((SC)->is_adaptec) \ 338 EN_WRITE((SC), (SC)->drq_us, \ 339 MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK_OR_BCODE))); \ 340 else \ 341 EN_WRITE((SC), (SC)->drq_us, \ 342 MID_MK_RXQ_ENI((CNT), (VCI), (END), (JK_OR_BCODE))); \ 343 } 344 345#endif 346 347/* add an item to the DTQ */ 348#define EN_DTQADD(SC,CNT,CHAN,JK_OR_BCODE,ADDR,LEN,END) { \ 349 if (END) \ 350 (SC)->dtq[MID_DTQ_A2REG((SC)->dtq_us)] = EN_DQ_MK(CHAN,LEN); \ 351 MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE); \ 352 (SC)->dtq_us += 4; \ 353 EN_WRITE((SC), (SC)->dtq_us, (ADDR)); \ 354 EN_WRAPADD(MID_DTQOFF, MID_DTQEND, (SC)->dtq_us, 4); \ 355 (SC)->dtq_free--; \ 356 if (END) \ 357 EN_WRITE((SC), MID_DMA_WRTX, MID_DTQ_A2REG((SC)->dtq_us)); \ 358} 359 360/* DRQ add macro */ 361#define EN_DRQADD(SC,CNT,VCI,JK_OR_BCODE,ADDR,LEN,SLOT,END) { \ 362 if (END) \ 363 (SC)->drq[MID_DRQ_A2REG((SC)->drq_us)] = EN_DQ_MK(SLOT,LEN); \ 364 MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE); \ 365 (SC)->drq_us += 4; \ 366 EN_WRITE((SC), (SC)->drq_us, (ADDR)); \ 367 EN_WRAPADD(MID_DRQOFF, MID_DRQEND, (SC)->drq_us, 4); \ 368 (SC)->drq_free--; \ 369 if (END) \ 370 EN_WRITE((SC), MID_DMA_WRRX, MID_DRQ_A2REG((SC)->drq_us)); \ 371} 372 373/* 374 * the driver code 375 * 376 * the code is arranged in a specific way: 377 * [1] short/inline functions 378 * [2] autoconfig stuff 379 * [3] ioctl stuff 380 * [4] reset -> init -> trasmit -> intr -> receive functions 381 * 382 */ 383 384/***********************************************************************/ 385 386/* 387 * en_read: read a word from the card. this is the only function 388 * that reads from the card. 389 */ 390 391STATIC INLINE u_int32_t en_read(sc, r) 392 393struct en_softc *sc; 394u_int32_t r; 395 396{ 397 398#ifdef EN_DEBUG_RANGE 399 if (r > MID_MAXOFF || (r % 4)) { 400 printf("en_read out of range, r=0x%x\n", r); 401 panic("en_read"); 402 } 403#endif 404 405 return(bus_space_read_4(sc->en_memt, sc->en_base, r)); 406} 407 408/* 409 * en_write: write a word to the card. this is the only function that 410 * writes to the card. 411 */ 412 413STATIC INLINE void en_write(sc, r, v) 414 415struct en_softc *sc; 416u_int32_t r, v; 417 418{ 419#ifdef EN_DEBUG_RANGE 420 if (r > MID_MAXOFF || (r % 4)) { 421 printf("en_write out of range, r=0x%x\n", r); 422 panic("en_write"); 423 } 424#endif 425 426 bus_space_write_4(sc->en_memt, sc->en_base, r, v); 427} 428 429/* 430 * en_k2sz: convert KBytes to a size parameter (a log2) 431 */ 432 433STATIC INLINE int en_k2sz(k) 434 435int k; 436 437{ 438 switch(k) { 439 case 1: return(0); 440 case 2: return(1); 441 case 4: return(2); 442 case 8: return(3); 443 case 16: return(4); 444 case 32: return(5); 445 case 64: return(6); 446 case 128: return(7); 447 default: panic("en_k2sz"); 448 } 449 return(0); 450} 451#define en_log2(X) en_k2sz(X) 452 453 454/* 455 * en_b2sz: convert a DMA burst code to its byte size 456 */ 457 458STATIC INLINE int en_b2sz(b) 459 460int b; 461 462{ 463 switch (b) { 464 case MIDDMA_WORD: return(1*4); 465 case MIDDMA_2WMAYBE: 466 case MIDDMA_2WORD: return(2*4); 467 case MIDDMA_4WMAYBE: 468 case MIDDMA_4WORD: return(4*4); 469 case MIDDMA_8WMAYBE: 470 case MIDDMA_8WORD: return(8*4); 471 case MIDDMA_16WMAYBE: 472 case MIDDMA_16WORD: return(16*4); 473 default: panic("en_b2sz"); 474 } 475 return(0); 476} 477 478 479/* 480 * en_sz2b: convert a burst size (bytes) to DMA burst code 481 */ 482 483STATIC INLINE int en_sz2b(sz) 484 485int sz; 486 487{ 488 switch (sz) { 489 case 1*4: return(MIDDMA_WORD); 490 case 2*4: return(MIDDMA_2WORD); 491 case 4*4: return(MIDDMA_4WORD); 492 case 8*4: return(MIDDMA_8WORD); 493 case 16*4: return(MIDDMA_16WORD); 494 default: panic("en_sz2b"); 495 } 496 return(0); 497} 498 499 500/* 501 * en_dqneed: calculate number of DTQ/DRQ's needed for a buffer 502 */ 503 504STATIC INLINE int en_dqneed(sc, data, len, tx) 505 506struct en_softc *sc; 507caddr_t data; 508u_int len, tx; 509 510{ 511 int result, needalign, sz; 512 513#if !defined(MIDWAY_ENIONLY) 514#if !defined(MIDWAY_ADPONLY) 515 if (sc->is_adaptec) 516#endif /* !MIDWAY_ADPONLY */ 517 return(1); /* adaptec can DMA anything in one go */ 518#endif 519 520#if !defined(MIDWAY_ADPONLY) 521 result = 0; 522 if (len < EN_MINDMA) { 523 if (!tx) /* XXX: conservative */ 524 return(1); /* will copy/DMA_JK */ 525 } 526 527 if (tx) { /* byte burst? */ 528 needalign = (((unsigned long) data) % sizeof(u_int32_t)); 529 if (needalign) { 530 result++; 531 sz = min(len, sizeof(u_int32_t) - needalign); 532 len -= sz; 533 data += sz; 534 } 535 } 536 537 if (sc->alburst && len) { 538 needalign = (((unsigned long) data) & sc->bestburstmask); 539 if (needalign) { 540 result++; /* alburst */ 541 sz = min(len, sc->bestburstlen - needalign); 542 len -= sz; 543 } 544 } 545 546 if (len >= sc->bestburstlen) { 547 sz = len / sc->bestburstlen; 548 sz = sz * sc->bestburstlen; 549 len -= sz; 550 result++; /* best shot */ 551 } 552 553 if (len) { 554 result++; /* clean up */ 555 if (tx && (len % sizeof(u_int32_t)) != 0) 556 result++; /* byte cleanup */ 557 } 558 559 return(result); 560#endif /* !MIDWAY_ADPONLY */ 561} 562 563 564/* 565 * en_mget: get an mbuf chain that can hold totlen bytes and return it 566 * (for recv) [based on am7990_get from if_le and ieget from if_ie] 567 * after this call the sum of all the m_len's in the chain will be totlen. 568 */ 569 570STATIC INLINE struct mbuf *en_mget(sc, totlen, drqneed) 571 572struct en_softc *sc; 573u_int totlen, *drqneed; 574 575{ 576 struct mbuf *m; 577 struct mbuf *top, **mp; 578 *drqneed = 0; 579 580 MGETHDR(m, M_DONTWAIT, MT_DATA); 581 if (m == NULL) 582 return(NULL); 583 m->m_pkthdr.rcvif = &sc->enif; 584 m->m_pkthdr.len = totlen; 585 m->m_len = MHLEN; 586 top = NULL; 587 mp = ⊤ 588 589 /* if (top != NULL) then we've already got 1 mbuf on the chain */ 590 while (totlen > 0) { 591 if (top) { 592 MGET(m, M_DONTWAIT, MT_DATA); 593 if (!m) { 594 m_freem(top); 595 return(NULL); /* out of mbufs */ 596 } 597 m->m_len = MLEN; 598 } 599 if (top && totlen >= MINCLSIZE) { 600 MCLGET(m, M_DONTWAIT); 601 if (m->m_flags & M_EXT) 602 m->m_len = MCLBYTES; 603 } 604 m->m_len = min(totlen, m->m_len); 605 totlen -= m->m_len; 606 *mp = m; 607 mp = &m->m_next; 608 609 *drqneed += en_dqneed(sc, m->m_data, m->m_len, 0); 610 611 } 612 return(top); 613} 614 615/***********************************************************************/ 616 617/* 618 * autoconfig stuff 619 */ 620 621void en_attach(sc) 622 623struct en_softc *sc; 624 625{ 626 struct ifnet *ifp = &sc->enif; 627 int sz; 628 u_int32_t reg, lcv, check, ptr, sav, midvloc; 629 630 /* 631 * probe card to determine memory size. the stupid ENI card always 632 * reports to PCI that it needs 4MB of space (2MB regs and 2MB RAM). 633 * if it has less than 2MB RAM the addresses wrap in the RAM address space. 634 * (i.e. on a 512KB card addresses 0x3ffffc, 0x37fffc, and 0x2ffffc 635 * are aliases for 0x27fffc [note that RAM starts at offset 0x200000]). 636 */ 637 638 if (sc->en_busreset) 639 sc->en_busreset(sc); 640 EN_WRITE(sc, MID_RESID, 0x0); /* reset card before touching RAM */ 641 for (lcv = MID_PROBEOFF; lcv <= MID_MAXOFF ; lcv += MID_PROBSIZE) { 642 EN_WRITE(sc, lcv, lcv); /* data[address] = address */ 643 for (check = MID_PROBEOFF ; check < lcv ; check += MID_PROBSIZE) { 644 reg = EN_READ(sc, check); 645 if (reg != check) { /* found an alias! */ 646 goto done_probe; /* and quit */ 647 } 648 } 649 } 650done_probe: 651 lcv -= MID_PROBSIZE; /* take one step back */ 652 sc->en_obmemsz = (lcv + 4) - MID_RAMOFF; 653 654 /* 655 * determine the largest DMA burst supported 656 */ 657 658 en_dmaprobe(sc); 659 660 /* 661 * "hello world" 662 */ 663 664 if (sc->en_busreset) 665 sc->en_busreset(sc); 666 EN_WRITE(sc, MID_RESID, 0x0); /* reset */ 667 for (lcv = MID_RAMOFF ; lcv < MID_RAMOFF + sc->en_obmemsz ; lcv += 4) 668 EN_WRITE(sc, lcv, 0); /* zero memory */ 669 670 reg = EN_READ(sc, MID_RESID); 671 672 printf("%s: ATM midway v%d, board IDs %d.%d, %s%s%s, %ldKB on-board RAM\n", 673 sc->sc_dev.dv_xname, MID_VER(reg), MID_MID(reg), MID_DID(reg), 674 (MID_IS_SABRE(reg)) ? "sabre controller, " : "", 675 (MID_IS_SUNI(reg)) ? "SUNI" : "Utopia", 676 (!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "", 677 sc->en_obmemsz / 1024); 678 679 if (sc->is_adaptec) { 680 if (sc->bestburstlen == 64 && sc->alburst == 0) 681 printf("%s: passed 64 byte DMA test\n", sc->sc_dev.dv_xname); 682 else 683 printf("%s: FAILED DMA TEST: burst=%d, alburst=%d\n", 684 sc->sc_dev.dv_xname, sc->bestburstlen, sc->alburst); 685 } else { 686 printf("%s: maximum DMA burst length = %d bytes%s\n", sc->sc_dev.dv_xname, 687 sc->bestburstlen, (sc->alburst) ? " (must align)" : ""); 688 } 689 690#if 0 /* WMAYBE doesn't work, don't complain about it */ 691 /* check if en_dmaprobe disabled wmaybe */ 692 if (en_dmaplan == en_dma_planB) 693 printf("%s: note: WMAYBE DMA has been disabled\n", sc->sc_dev.dv_xname); 694#endif 695 696 /* 697 * link into network subsystem and prepare card 698 */ 699 700#if defined(__NetBSD__) || defined(__OpenBSD__) 701 bcopy(sc->sc_dev.dv_xname, sc->enif.if_xname, IFNAMSIZ); 702#endif 703#if !defined(MISSING_IF_SOFTC) 704 sc->enif.if_softc = sc; 705#endif 706 ifp->if_flags = IFF_SIMPLEX|IFF_NOTRAILERS; 707 ifp->if_ioctl = en_ioctl; 708 ifp->if_output = atm_output; 709 ifp->if_start = en_start; 710 711 /* 712 * init softc 713 */ 714 715 for (lcv = 0 ; lcv < MID_N_VC ; lcv++) { 716 sc->rxvc2slot[lcv] = RX_NONE; 717 sc->txspeed[lcv] = 0; /* full */ 718 sc->txvc2slot[lcv] = 0; /* full speed == slot 0 */ 719 } 720 721 sz = sc->en_obmemsz - (MID_BUFOFF - MID_RAMOFF); 722 ptr = sav = MID_BUFOFF; 723 ptr = roundup(ptr, EN_TXSZ * 1024); /* align */ 724 sz = sz - (ptr - sav); 725 if (EN_TXSZ*1024 * EN_NTX > sz) { 726 printf("%s: EN_NTX/EN_TXSZ too big\n", sc->sc_dev.dv_xname); 727 return; 728 } 729 for (lcv = 0 ; lcv < EN_NTX ; lcv++) { 730 sc->txslot[lcv].mbsize = 0; 731 sc->txslot[lcv].start = ptr; 732 ptr += (EN_TXSZ * 1024); 733 sz -= (EN_TXSZ * 1024); 734 sc->txslot[lcv].stop = ptr; 735 sc->txslot[lcv].nref = 0; 736 bzero(&sc->txslot[lcv].indma, sizeof(sc->txslot[lcv].indma)); 737 bzero(&sc->txslot[lcv].q, sizeof(sc->txslot[lcv].q)); 738#ifdef EN_DEBUG 739 printf("%s: tx%d: start 0x%x, stop 0x%x\n", sc->sc_dev.dv_xname, lcv, 740 sc->txslot[lcv].start, sc->txslot[lcv].stop); 741#endif 742 } 743 744 sav = ptr; 745 ptr = roundup(ptr, EN_RXSZ * 1024); /* align */ 746 sz = sz - (ptr - sav); 747 sc->en_nrx = sz / (EN_RXSZ * 1024); 748 if (sc->en_nrx <= 0) { 749 printf("%s: EN_NTX/EN_TXSZ/EN_RXSZ too big\n", sc->sc_dev.dv_xname); 750 return; 751 } 752#if 1 753 /* leave one entry in the ringbuf unused to avoid wraparound */ 754 if (sc->en_nrx >= MID_N_VC) 755 sc->en_nrx = MID_N_VC - 1; 756#endif 757 for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) { 758 sc->rxslot[lcv].rxhand = NULL; 759 sc->rxslot[lcv].oth_flags = ENOTHER_FREE; 760 bzero(&sc->rxslot[lcv].indma, sizeof(sc->rxslot[lcv].indma)); 761 bzero(&sc->rxslot[lcv].q, sizeof(sc->rxslot[lcv].q)); 762 midvloc = sc->rxslot[lcv].start = ptr; 763 ptr += (EN_RXSZ * 1024); 764 sz -= (EN_RXSZ * 1024); 765 sc->rxslot[lcv].stop = ptr; 766 midvloc = midvloc - MID_RAMOFF; 767 midvloc = (midvloc & ~((EN_RXSZ*1024) - 1)) >> 2; /* mask, cvt to words */ 768 midvloc = midvloc >> MIDV_LOCTOPSHFT; /* we only want the top 11 bits */ 769 midvloc = (midvloc & MIDV_LOCMASK) << MIDV_LOCSHIFT; 770 sc->rxslot[lcv].mode = midvloc | 771 (en_k2sz(EN_RXSZ) << MIDV_SZSHIFT) | MIDV_TRASH; 772 773#ifdef EN_DEBUG 774 printf("%s: rx%d: start 0x%x, stop 0x%x, mode 0x%x\n", sc->sc_dev.dv_xname, 775 lcv, sc->rxslot[lcv].start, sc->rxslot[lcv].stop, sc->rxslot[lcv].mode); 776#endif 777 } 778 779#ifdef EN_STAT 780 sc->vtrash = sc->otrash = sc->mfix = sc->txmbovr = sc->dmaovr = 0; 781 sc->txoutspace = sc->txdtqout = sc->launch = sc->lheader = sc->ltail = 0; 782 sc->hwpull = sc->swadd = sc->rxqnotus = sc->rxqus = sc->rxoutboth = 0; 783 sc->rxdrqout = sc->ttrash = sc->rxmbufout = sc->mfixfail = 0; 784 sc->headbyte = sc->tailbyte = sc->tailflush = 0; 785#endif 786 sc->need_drqs = sc->need_dtqs = 0; 787 788 printf("%s: %d %dKB receive buffers, %d %dKB transmit buffers allocated\n", 789 sc->sc_dev.dv_xname, sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ); 790 791 /* 792 * final commit 793 */ 794 795 if_attach(ifp); 796 atm_ifattach(ifp); 797 798} 799 800 801/* 802 * en_dmaprobe: helper function for en_attach. 803 * 804 * see how the card handles DMA by running a few DMA tests. we need 805 * to figure out the largest number of bytes we can DMA in one burst 806 * ("bestburstlen"), and if the starting address for a burst needs to 807 * be aligned on any sort of boundary or not ("alburst"). 808 * 809 * typical findings: 810 * sparc1: bestburstlen=4, alburst=0 (ick, broken DMA!) 811 * sparc2: bestburstlen=64, alburst=1 812 * p166: bestburstlen=64, alburst=0 813 */ 814 815STATIC void en_dmaprobe(sc) 816 817struct en_softc *sc; 818 819{ 820 u_int32_t srcbuf[64], dstbuf[64]; 821 u_int8_t *sp, *dp; 822 int bestalgn, bestnotalgn, lcv, try, fail; 823 824 sc->alburst = 0; 825 826 sp = (u_int8_t *) srcbuf; 827 while ((((unsigned long) sp) % MIDDMA_MAXBURST) != 0) 828 sp += 4; 829 dp = (u_int8_t *) dstbuf; 830 while ((((unsigned long) dp) % MIDDMA_MAXBURST) != 0) 831 dp += 4; 832 833 bestalgn = bestnotalgn = en_dmaprobe_doit(sc, sp, dp, 0); 834 835 for (lcv = 4 ; lcv < MIDDMA_MAXBURST ; lcv += 4) { 836 try = en_dmaprobe_doit(sc, sp+lcv, dp+lcv, 0); 837 if (try < bestnotalgn) 838 bestnotalgn = try; 839 } 840 841 if (bestalgn != bestnotalgn) /* need bursts aligned */ 842 sc->alburst = 1; 843 844 sc->bestburstlen = bestalgn; 845 sc->bestburstshift = en_log2(bestalgn); 846 sc->bestburstmask = sc->bestburstlen - 1; /* must be power of 2 */ 847 sc->bestburstcode = en_sz2b(bestalgn); 848 849 if (sc->bestburstlen <= 2*sizeof(u_int32_t)) 850 return; /* won't be using WMAYBE */ 851 852 /* 853 * adaptec does not have (or need) wmaybe. do not bother testing 854 * for it. 855 */ 856 if (sc->is_adaptec) { 857 /* XXX, actually don't need a DMA plan: adaptec is smarter than that */ 858 en_dmaplan = en_dma_planB; 859 return; 860 } 861 862 /* 863 * test that WMAYBE dma works like we think it should 864 * (i.e. no alignment restrictions on host address other than alburst) 865 */ 866 867 try = sc->bestburstlen - 4; 868 fail = 0; 869 fail += en_dmaprobe_doit(sc, sp, dp, try); 870 for (lcv = 4 ; lcv < sc->bestburstlen ; lcv += 4) { 871 fail += en_dmaprobe_doit(sc, sp+lcv, dp+lcv, try); 872 if (sc->alburst) 873 try -= 4; 874 } 875 if (EN_NOWMAYBE || fail) { 876 if (fail) 877 printf("%s: WARNING: WMAYBE DMA test failed %d time(s)\n", 878 sc->sc_dev.dv_xname, fail); 879 en_dmaplan = en_dma_planB; /* fall back to plan B */ 880 } 881 882} 883 884 885/* 886 * en_dmaprobe_doit: do actual testing 887 */ 888 889int 890en_dmaprobe_doit(sc, sp, dp, wmtry) 891 892struct en_softc *sc; 893u_int8_t *sp, *dp; 894int wmtry; 895 896{ 897 int lcv, retval = 4, cnt, count; 898 u_int32_t reg, bcode, midvloc; 899 900 /* 901 * set up a 1k buffer at MID_BUFOFF 902 */ 903 904 if (sc->en_busreset) 905 sc->en_busreset(sc); 906 EN_WRITE(sc, MID_RESID, 0x0); /* reset card before touching RAM */ 907 908 midvloc = ((MID_BUFOFF - MID_RAMOFF) / sizeof(u_int32_t)) >> MIDV_LOCTOPSHFT; 909 EN_WRITE(sc, MIDX_PLACE(0), MIDX_MKPLACE(en_k2sz(1), midvloc)); 910 EN_WRITE(sc, MID_VC(0), (midvloc << MIDV_LOCSHIFT) 911 | (en_k2sz(1) << MIDV_SZSHIFT) | MIDV_TRASH); 912 EN_WRITE(sc, MID_DST_RP(0), 0); 913 EN_WRITE(sc, MID_WP_ST_CNT(0), 0); 914 915 for (lcv = 0 ; lcv < 68 ; lcv++) /* set up sample data */ 916 sp[lcv] = lcv+1; 917 EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* enable DMA (only) */ 918 919 sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX)); 920 sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX)); 921 922 /* 923 * try it now . . . DMA it out, then DMA it back in and compare 924 * 925 * note: in order to get the dma stuff to reverse directions it wants 926 * the "end" flag set! since we are not dma'ing valid data we may 927 * get an ident mismatch interrupt (which we will ignore). 928 * 929 * note: we've got two different tests rolled up in the same loop 930 * if (wmtry) 931 * then we are doing a wmaybe test and wmtry is a byte count 932 * else we are doing a burst test 933 */ 934 935 for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) { 936 937 /* zero SRAM and dest buffer */ 938 for (cnt = 0 ; cnt < 1024; cnt += 4) 939 EN_WRITE(sc, MID_BUFOFF+cnt, 0); /* zero memory */ 940 for (cnt = 0 ; cnt < 68 ; cnt++) 941 dp[cnt] = 0; 942 943 if (wmtry) { 944 count = (sc->bestburstlen - sizeof(u_int32_t)) / sizeof(u_int32_t); 945 bcode = en_dmaplan[count].bcode; 946 count = wmtry >> en_dmaplan[count].divshift; 947 } else { 948 bcode = en_sz2b(lcv); 949 count = 1; 950 } 951 if (sc->is_adaptec) 952 EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ADP(lcv, 0, MID_DMA_END, 0)); 953 else 954 EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ENI(count, 0, MID_DMA_END, bcode)); 955 EN_WRITE(sc, sc->dtq_chip+4, vtophys(sp)); 956 EN_WRITE(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_chip+8)); 957 cnt = 1000; 958 while (EN_READ(sc, MID_DMA_RDTX) == MID_DTQ_A2REG(sc->dtq_chip)) { 959 DELAY(1); 960 cnt--; 961 if (cnt == 0) { 962 printf("%s: unexpected timeout in tx DMA test\n", sc->sc_dev.dv_xname); 963 return(retval); /* timeout, give up */ 964 } 965 } 966 EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8); 967 reg = EN_READ(sc, MID_INTACK); 968 if ((reg & MID_INT_DMA_TX) != MID_INT_DMA_TX) { 969 printf("%s: unexpected status in tx DMA test: 0x%x\n", 970 sc->sc_dev.dv_xname, reg); 971 return(retval); 972 } 973 EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* re-enable DMA (only) */ 974 975 /* "return to sender..." address is known ... */ 976 977 if (sc->is_adaptec) 978 EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ADP(lcv, 0, MID_DMA_END, 0)); 979 else 980 EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ENI(count, 0, MID_DMA_END, bcode)); 981 EN_WRITE(sc, sc->drq_chip+4, vtophys(dp)); 982 EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip+8)); 983 cnt = 1000; 984 while (EN_READ(sc, MID_DMA_RDRX) == MID_DRQ_A2REG(sc->drq_chip)) { 985 DELAY(1); 986 cnt--; 987 if (cnt == 0) { 988 printf("%s: unexpected timeout in rx DMA test\n", sc->sc_dev.dv_xname); 989 return(retval); /* timeout, give up */ 990 } 991 } 992 EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8); 993 reg = EN_READ(sc, MID_INTACK); 994 if ((reg & MID_INT_DMA_RX) != MID_INT_DMA_RX) { 995 printf("%s: unexpected status in rx DMA test: 0x%x\n", 996 sc->sc_dev.dv_xname, reg); 997 return(retval); 998 } 999 EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* re-enable DMA (only) */ 1000 1001 if (wmtry) { 1002 return(bcmp(sp, dp, wmtry)); /* wmtry always exits here, no looping */ 1003 } 1004 1005 if (bcmp(sp, dp, lcv)) 1006 return(retval); /* failed, use last value */ 1007 1008 retval = lcv; 1009 1010 } 1011 return(retval); /* studly 64 byte DMA present! oh baby!! */ 1012} 1013 1014/***********************************************************************/ 1015 1016/* 1017 * en_ioctl: handle ioctl requests 1018 * 1019 * NOTE: if you add an ioctl to set txspeed, you should choose a new 1020 * TX channel/slot. Choose the one with the lowest sc->txslot[slot].nref 1021 * value, subtract one from sc->txslot[0].nref, add one to the 1022 * sc->txslot[slot].nref, set sc->txvc2slot[vci] = slot, and then set 1023 * txspeed[vci]. 1024 */ 1025 1026STATIC int en_ioctl(ifp, cmd, data) 1027 1028struct ifnet *ifp; 1029EN_IOCTL_CMDT cmd; 1030caddr_t data; 1031 1032{ 1033#ifdef MISSING_IF_SOFTC 1034 struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit]; 1035#else 1036 struct en_softc *sc = (struct en_softc *) ifp->if_softc; 1037#endif 1038 struct ifaddr *ifa = (struct ifaddr *) data; 1039 struct ifreq *ifr = (struct ifreq *) data; 1040 struct atm_pseudoioctl *api = (struct atm_pseudoioctl *)data; 1041#ifdef NATM 1042 struct atm_rawioctl *ario = (struct atm_rawioctl *)data; 1043 int slot; 1044#endif 1045 int s, error = 0; 1046 1047 s = splnet(); 1048 1049 switch (cmd) { 1050 case SIOCATMENA: /* enable circuit for recv */ 1051 error = en_rxctl(sc, api, 1); 1052 break; 1053 1054 case SIOCATMDIS: /* disable circuit for recv */ 1055 error = en_rxctl(sc, api, 0); 1056 break; 1057 1058#ifdef NATM 1059 case SIOCXRAWATM: 1060 if ((slot = sc->rxvc2slot[ario->npcb->npcb_vci]) == RX_NONE) { 1061 error = EINVAL; 1062 break; 1063 } 1064 if (ario->rawvalue > EN_RXSZ*1024) 1065 ario->rawvalue = EN_RXSZ*1024; 1066 if (ario->rawvalue) { 1067 sc->rxslot[slot].oth_flags |= ENOTHER_RAW; 1068 sc->rxslot[slot].raw_threshold = ario->rawvalue; 1069 } else { 1070 sc->rxslot[slot].oth_flags &= (~ENOTHER_RAW); 1071 sc->rxslot[slot].raw_threshold = 0; 1072 } 1073#ifdef EN_DEBUG 1074 printf("%s: rxvci%d: turn %s raw (boodi) mode\n", 1075 sc->sc_dev.dv_xname, ario->npcb->npcb_vci, 1076 (ario->rawvalue) ? "on" : "off"); 1077#endif 1078 break; 1079#endif 1080 case SIOCSIFADDR: 1081 ifp->if_flags |= IFF_UP; 1082#ifdef INET 1083 if (ifa->ifa_addr->sa_family == AF_INET) { 1084 en_reset(sc); 1085 en_init(sc); 1086 ifa->ifa_rtrequest = atm_rtrequest; /* ??? */ 1087 break; 1088 } 1089#endif /* INET */ 1090 /* what to do if not INET? */ 1091 en_reset(sc); 1092 en_init(sc); 1093 break; 1094 1095 case SIOCGIFADDR: 1096 error = EINVAL; 1097 break; 1098 1099 case SIOCSIFFLAGS: 1100 error = EINVAL; 1101 break; 1102 1103#if defined(SIOCSIFMTU) /* ??? copied from if_de */ 1104#if !defined(ifr_mtu) 1105#define ifr_mtu ifr_metric 1106#endif 1107 case SIOCSIFMTU: 1108 /* 1109 * Set the interface MTU. 1110 */ 1111#ifdef notsure 1112 if (ifr->ifr_mtu > ATMMTU) { 1113 error = EINVAL; 1114 break; 1115 } 1116#endif 1117 ifp->if_mtu = ifr->ifr_mtu; 1118 /* XXXCDC: do we really need to reset on MTU size change? */ 1119 en_reset(sc); 1120 en_init(sc); 1121 break; 1122#endif /* SIOCSIFMTU */ 1123 1124 default: 1125 error = EINVAL; 1126 break; 1127 } 1128 splx(s); 1129 return error; 1130} 1131 1132 1133/* 1134 * en_rxctl: turn on and off VCs for recv. 1135 */ 1136 1137STATIC int en_rxctl(sc, pi, on) 1138 1139struct en_softc *sc; 1140struct atm_pseudoioctl *pi; 1141int on; 1142 1143{ 1144 u_int s, vci, flags, slot; 1145 u_int32_t oldmode, newmode; 1146 1147 vci = ATM_PH_VCI(&pi->aph); 1148 flags = ATM_PH_FLAGS(&pi->aph); 1149 1150#ifdef EN_DEBUG 1151 printf("%s: %s vpi=%d, vci=%d, flags=%d\n", sc->sc_dev.dv_xname, 1152 (on) ? "enable" : "disable", ATM_PH_VPI(&pi->aph), vci, flags); 1153#endif 1154 1155 if (ATM_PH_VPI(&pi->aph) || vci >= MID_N_VC) 1156 return(EINVAL); 1157 1158 /* 1159 * turn on VCI! 1160 */ 1161 1162 if (on) { 1163 if (sc->rxvc2slot[vci] != RX_NONE) 1164 return(EINVAL); 1165 for (slot = 0 ; slot < sc->en_nrx ; slot++) 1166 if (sc->rxslot[slot].oth_flags & ENOTHER_FREE) 1167 break; 1168 if (slot == sc->en_nrx) 1169 return(ENOSPC); 1170 sc->rxvc2slot[vci] = slot; 1171 sc->rxslot[slot].rxhand = NULL; 1172 oldmode = sc->rxslot[slot].mode; 1173 newmode = (flags & ATM_PH_AAL5) ? MIDV_AAL5 : MIDV_NOAAL; 1174 sc->rxslot[slot].mode = MIDV_SETMODE(oldmode, newmode); 1175 sc->rxslot[slot].atm_vci = vci; 1176 sc->rxslot[slot].atm_flags = flags; 1177 sc->rxslot[slot].oth_flags = 0; 1178 sc->rxslot[slot].rxhand = pi->rxhand; 1179 if (sc->rxslot[slot].indma.ifq_head || sc->rxslot[slot].q.ifq_head) 1180 panic("en_rxctl: left over mbufs on enable"); 1181 sc->txspeed[vci] = 0; /* full speed to start */ 1182 sc->txvc2slot[vci] = 0; /* init value */ 1183 sc->txslot[0].nref++; /* bump reference count */ 1184 en_loadvc(sc, vci); /* does debug printf for us */ 1185 return(0); 1186 } 1187 1188 /* 1189 * turn off VCI 1190 */ 1191 1192 if (sc->rxvc2slot[vci] == RX_NONE) 1193 return(EINVAL); 1194 slot = sc->rxvc2slot[vci]; 1195 if ((sc->rxslot[slot].oth_flags & (ENOTHER_FREE|ENOTHER_DRAIN)) != 0) 1196 return(EINVAL); 1197 s = splimp(); /* block out enintr() */ 1198 oldmode = EN_READ(sc, MID_VC(vci)); 1199 newmode = MIDV_SETMODE(oldmode, MIDV_TRASH) & ~MIDV_INSERVICE; 1200 EN_WRITE(sc, MID_VC(vci), (newmode | (oldmode & MIDV_INSERVICE))); 1201 /* halt in tracks, be careful to preserve inserivce bit */ 1202 DELAY(27); 1203 sc->rxslot[slot].rxhand = NULL; 1204 sc->rxslot[slot].mode = newmode; 1205 1206 sc->txslot[sc->txvc2slot[vci]].nref--; 1207 sc->txspeed[vci] = 0; 1208 sc->txvc2slot[vci] = 0; 1209 1210 /* if stuff is still going on we are going to have to drain it out */ 1211 if (sc->rxslot[slot].indma.ifq_head || 1212 sc->rxslot[slot].q.ifq_head || 1213 (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) != 0) { 1214 sc->rxslot[slot].oth_flags |= ENOTHER_DRAIN; 1215 } else { 1216 sc->rxslot[slot].oth_flags = ENOTHER_FREE; 1217 sc->rxslot[slot].atm_vci = RX_NONE; 1218 sc->rxvc2slot[vci] = RX_NONE; 1219 } 1220 splx(s); /* enable enintr() */ 1221#ifdef EN_DEBUG 1222 printf("%s: rx%d: VCI %d is now %s\n", sc->sc_dev.dv_xname, slot, vci, 1223 (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) ? "draining" : "free"); 1224#endif 1225 return(0); 1226} 1227 1228/***********************************************************************/ 1229 1230/* 1231 * en_reset: reset the board, throw away work in progress. 1232 * must en_init to recover. 1233 */ 1234 1235void en_reset(sc) 1236 1237struct en_softc *sc; 1238 1239{ 1240 struct mbuf *m; 1241 int lcv, slot; 1242 1243#ifdef EN_DEBUG 1244 printf("%s: reset\n", sc->sc_dev.dv_xname); 1245#endif 1246 1247 if (sc->en_busreset) 1248 sc->en_busreset(sc); 1249 EN_WRITE(sc, MID_RESID, 0x0); /* reset hardware */ 1250 1251 /* 1252 * recv: dump any mbufs we are dma'ing into, if DRAINing, then a reset 1253 * will free us! 1254 */ 1255 1256 for (lcv = 0 ; lcv < MID_N_VC ; lcv++) { 1257 if (sc->rxvc2slot[lcv] == RX_NONE) 1258 continue; 1259 slot = sc->rxvc2slot[lcv]; 1260 while (1) { 1261 IF_DEQUEUE(&sc->rxslot[slot].indma, m); 1262 if (m == NULL) 1263 break; /* >>> exit 'while(1)' here <<< */ 1264 m_freem(m); 1265 } 1266 while (1) { 1267 IF_DEQUEUE(&sc->rxslot[slot].q, m); 1268 if (m == NULL) 1269 break; /* >>> exit 'while(1)' here <<< */ 1270 m_freem(m); 1271 } 1272 sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL; 1273 if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) { 1274 sc->rxslot[slot].oth_flags = ENOTHER_FREE; 1275 sc->rxvc2slot[lcv] = RX_NONE; 1276#ifdef EN_DEBUG 1277 printf("%s: rx%d: VCI %d is now free\n", sc->sc_dev.dv_xname, slot, lcv); 1278#endif 1279 } 1280 } 1281 1282 /* 1283 * xmit: dump everything 1284 */ 1285 1286 for (lcv = 0 ; lcv < EN_NTX ; lcv++) { 1287 while (1) { 1288 IF_DEQUEUE(&sc->txslot[lcv].indma, m); 1289 if (m == NULL) 1290 break; /* >>> exit 'while(1)' here <<< */ 1291 m_freem(m); 1292 } 1293 while (1) { 1294 IF_DEQUEUE(&sc->txslot[lcv].q, m); 1295 if (m == NULL) 1296 break; /* >>> exit 'while(1)' here <<< */ 1297 m_freem(m); 1298 } 1299 sc->txslot[lcv].mbsize = 0; 1300 } 1301 1302 return; 1303} 1304 1305 1306/* 1307 * en_init: init board and sync the card with the data in the softc. 1308 */ 1309 1310STATIC void en_init(sc) 1311 1312struct en_softc *sc; 1313 1314{ 1315 int vc, slot; 1316 u_int32_t loc; 1317 1318 if ((sc->enif.if_flags & IFF_UP) == 0) { 1319#ifdef EN_DEBUG 1320 printf("%s: going down\n", sc->sc_dev.dv_xname); 1321#endif 1322 en_reset(sc); /* to be safe */ 1323 sc->enif.if_flags &= ~IFF_RUNNING; /* disable */ 1324 return; 1325 } 1326 1327#ifdef EN_DEBUG 1328 printf("%s: going up\n", sc->sc_dev.dv_xname); 1329#endif 1330 sc->enif.if_flags |= IFF_RUNNING; /* enable */ 1331 1332 if (sc->en_busreset) 1333 sc->en_busreset(sc); 1334 EN_WRITE(sc, MID_RESID, 0x0); /* reset */ 1335 1336 /* 1337 * init obmem data structures: vc tab, dma q's, slist. 1338 */ 1339 1340 for (vc = 0 ; vc < MID_N_VC ; vc++) 1341 en_loadvc(sc, vc); 1342 1343 bzero(&sc->drq, sizeof(sc->drq)); 1344#if 1 1345 /* leave one entry in the ringbuf unused to avoid wraparound */ 1346 sc->drq_free = MID_DRQ_N - 1; 1347#else 1348 sc->drq_free = MID_DRQ_N; 1349#endif 1350 sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX)); 1351 EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip)); 1352 /* ensure zero queue */ 1353 sc->drq_us = sc->drq_chip; 1354 1355 bzero(&sc->dtq, sizeof(sc->dtq)); 1356#if 1 1357 /* leave one entry in the ringbuf unused to avoid wraparound */ 1358 sc->dtq_free = MID_DTQ_N - 1; 1359#else 1360 sc->dtq_free = MID_DTQ_N; 1361#endif 1362 sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX)); 1363 EN_WRITE(sc, MID_DMA_WRTX, MID_DRQ_A2REG(sc->dtq_chip)); 1364 /* ensure zero queue */ 1365 sc->dtq_us = sc->dtq_chip; 1366 1367 sc->hwslistp = MID_SL_REG2A(EN_READ(sc, MID_SERV_WRITE)); 1368 sc->swsl_size = sc->swsl_head = sc->swsl_tail = 0; 1369 1370#ifdef EN_DEBUG 1371 printf("%s: drq free/chip: %d/0x%x, dtq free/chip: %d/0x%x, hwslist: 0x%x\n", 1372 sc->sc_dev.dv_xname, sc->drq_free, sc->drq_chip, 1373 sc->dtq_free, sc->dtq_chip, sc->hwslistp); 1374#endif 1375 1376 for (slot = 0 ; slot < EN_NTX ; slot++) { 1377 sc->txslot[slot].bfree = EN_TXSZ * 1024; 1378 EN_WRITE(sc, MIDX_READPTR(slot), 0); 1379 EN_WRITE(sc, MIDX_DESCSTART(slot), 0); 1380 loc = sc->txslot[slot].cur = sc->txslot[slot].start; 1381 loc = loc - MID_RAMOFF; 1382 loc = (loc & ~((EN_TXSZ*1024) - 1)) >> 2; /* mask, cvt to words */ 1383 loc = loc >> MIDV_LOCTOPSHFT; /* top 11 bits */ 1384 EN_WRITE(sc, MIDX_PLACE(slot), MIDX_MKPLACE(en_k2sz(EN_TXSZ), loc)); 1385#ifdef EN_DEBUG 1386 printf("%s: tx%d: place 0x%x\n", sc->sc_dev.dv_xname, slot, 1387 EN_READ(sc, MIDX_PLACE(slot))); 1388#endif 1389 } 1390 1391 /* 1392 * enable! 1393 */ 1394 1395 EN_WRITE(sc, MID_INTENA, MID_INT_TX|MID_INT_DMA_OVR|MID_INT_IDENT| 1396 MID_INT_LERR|MID_INT_DMA_ERR|MID_INT_DMA_RX|MID_INT_DMA_TX| 1397 MID_INT_SERVICE| /* >>> MID_INT_SUNI| XXXCDC<<< */ MID_INT_STATS); 1398 EN_WRITE(sc, MID_MAST_CSR, MID_SETIPL(sc->ipl)|MID_MCSR_ENDMA| 1399 MID_MCSR_ENTX|MID_MCSR_ENRX); 1400 1401} 1402 1403 1404/* 1405 * en_loadvc: load a vc tab entry from a slot 1406 */ 1407 1408STATIC void en_loadvc(sc, vc) 1409 1410struct en_softc *sc; 1411int vc; 1412 1413{ 1414 int slot; 1415 u_int32_t reg = EN_READ(sc, MID_VC(vc)); 1416 1417 reg = MIDV_SETMODE(reg, MIDV_TRASH); 1418 EN_WRITE(sc, MID_VC(vc), reg); 1419 DELAY(27); 1420 1421 if ((slot = sc->rxvc2slot[vc]) == RX_NONE) 1422 return; 1423 1424 /* no need to set CRC */ 1425 EN_WRITE(sc, MID_DST_RP(vc), 0); /* read pointer = 0, desc. start = 0 */ 1426 EN_WRITE(sc, MID_WP_ST_CNT(vc), 0); /* write pointer = 0 */ 1427 EN_WRITE(sc, MID_VC(vc), sc->rxslot[slot].mode); /* set mode, size, loc */ 1428 sc->rxslot[slot].cur = sc->rxslot[slot].start; 1429 1430#ifdef EN_DEBUG 1431 printf("%s: rx%d: assigned to VCI %d\n", sc->sc_dev.dv_xname, slot, vc); 1432#endif 1433} 1434 1435 1436/* 1437 * en_start: start transmitting the next packet that needs to go out 1438 * if there is one. note that atm_output() has already splimp()'d us. 1439 */ 1440 1441STATIC void en_start(ifp) 1442 1443struct ifnet *ifp; 1444 1445{ 1446#ifdef MISSING_IF_SOFTC 1447 struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit]; 1448#else 1449 struct en_softc *sc = (struct en_softc *) ifp->if_softc; 1450#endif 1451 struct ifqueue *ifq = &ifp->if_snd; /* if INPUT QUEUE */ 1452 struct mbuf *m, *lastm, *prev; 1453 struct atm_pseudohdr *ap, *new_ap; 1454 int txchan, mlen, got, need, toadd, cellcnt, first; 1455 u_int32_t atm_vpi, atm_vci, atm_flags, *dat, aal; 1456 u_int8_t *cp; 1457 1458 if ((ifp->if_flags & IFF_RUNNING) == 0) 1459 return; 1460 1461 /* 1462 * remove everything from interface queue since we handle all queueing 1463 * locally ... 1464 */ 1465 1466 while (1) { 1467 1468 IF_DEQUEUE(ifq, m); 1469 if (m == NULL) 1470 return; /* EMPTY: >>> exit here <<< */ 1471 1472 /* 1473 * calculate size of packet (in bytes) 1474 * also, if we are not doing transmit DMA we eliminate all stupid 1475 * (non-word) alignments here using en_mfix(). calls to en_mfix() 1476 * seem to be due to tcp retransmits for the most part. 1477 * 1478 * after this loop mlen total length of mbuf chain (including atm_ph), 1479 * and lastm is a pointer to the last mbuf on the chain. 1480 */ 1481 1482 lastm = m; 1483 mlen = 0; 1484 prev = NULL; 1485 while (1) { 1486#ifdef EN_FIXMBUF 1487 /* if eni, always fix misaligned mbuf */ 1488 if (!sc->is_adaptec || EN_NOTXDMA || !en_dma) { 1489#else 1490 if (EN_NOTXDMA || !en_dma) { /* no DMA? */ 1491#endif 1492 if ( (mtod(lastm, unsigned long) % sizeof(u_int32_t)) != 0 || 1493 ((lastm->m_len % sizeof(u_int32_t)) != 0 && lastm->m_next)) { 1494 first = (lastm == m); 1495 if (en_mfix(sc, &lastm, prev) == 0) { /* failed? */ 1496 m_freem(m); 1497 m = NULL; 1498 break; 1499 } 1500 if (first) 1501 m = lastm; /* update */ 1502 } 1503 prev = lastm; 1504 } 1505 mlen += lastm->m_len; 1506 if (lastm->m_next == NULL) 1507 break; 1508 lastm = lastm->m_next; 1509 } 1510 1511 if (m == NULL) /* happens only if mfix fails */ 1512 continue; 1513 1514 ap = mtod(m, struct atm_pseudohdr *); 1515 1516 atm_vpi = ATM_PH_VPI(ap); 1517 atm_vci = ATM_PH_VCI(ap); 1518 atm_flags = ATM_PH_FLAGS(ap) & ~(EN_OBHDR|EN_OBTRL); 1519 aal = ((atm_flags & ATM_PH_AAL5) != 0) 1520 ? MID_TBD_AAL5 : MID_TBD_NOAAL5; 1521 1522 /* 1523 * check that vpi/vci is one we can use 1524 */ 1525 1526 if (atm_vpi || atm_vci > MID_N_VC) { 1527 printf("%s: output vpi=%d, vci=%d out of card range, dropping...\n", 1528 sc->sc_dev.dv_xname, atm_vpi, atm_vci); 1529 m_freem(m); 1530 continue; 1531 } 1532 1533 /* 1534 * computing how much padding we need on the end of the mbuf, then 1535 * see if we can put the TBD at the front of the mbuf where the 1536 * link header goes (well behaved protocols will reserve room for us). 1537 * last, check if room for PDU tail. 1538 * 1539 * got = number of bytes of data we have 1540 * cellcnt = number of cells in this mbuf 1541 * need = number of bytes of data + padding we need (excludes TBD) 1542 * toadd = number of bytes of data we need to add to end of mbuf, 1543 * [including AAL5 PDU, if AAL5] 1544 */ 1545 1546 got = mlen - sizeof(struct atm_pseudohdr *); 1547 toadd = (aal == MID_TBD_AAL5) ? MID_PDU_SIZE : 0; /* PDU */ 1548 cellcnt = (got + toadd + (MID_ATMDATASZ - 1)) / MID_ATMDATASZ; 1549 need = cellcnt * MID_ATMDATASZ; 1550 toadd = need - got; /* recompute, including zero padding */ 1551 1552#ifdef EN_DEBUG 1553 printf("%s: txvci%d: mlen=%d, got=%d, need=%d, toadd=%d, cell#=%d\n", 1554 sc->sc_dev.dv_xname, atm_vci, mlen, got, need, toadd, cellcnt); 1555 printf(" leading_space=%d, trailing_space=%d\n", 1556 M_LEADINGSPACE(m), M_TRAILINGSPACE(lastm)); 1557#endif 1558 1559#ifdef EN_MBUF_OPT 1560 1561 /* 1562 * note: external storage (M_EXT) can be shared between mbufs 1563 * to avoid copying (see m_copym()). this means that the same 1564 * data buffer could be shared by several mbufs, and thus it isn't 1565 * a good idea to try and write TBDs or PDUs to M_EXT data areas. 1566 */ 1567 1568 if (M_LEADINGSPACE(m) >= MID_TBD_SIZE && (m->m_flags & M_EXT) == 0) { 1569 m->m_data -= MID_TBD_SIZE; 1570 m->m_len += MID_TBD_SIZE; 1571 mlen += MID_TBD_SIZE; 1572 new_ap = mtod(m, struct atm_pseudohdr *); 1573 *new_ap = *ap; /* move it back */ 1574 ap = new_ap; 1575 dat = ((u_int32_t *) ap) + 1; 1576 /* make sure the TBD is in proper byte order */ 1577 *dat++ = htonl(MID_TBD_MK1(aal, sc->txspeed[atm_vci], cellcnt)); 1578 *dat = htonl(MID_TBD_MK2(atm_vci, 0, 0)); 1579 atm_flags |= EN_OBHDR; 1580 } 1581 1582 if (toadd && (lastm->m_flags & M_EXT) == 0 && 1583 M_TRAILINGSPACE(lastm) >= toadd) { 1584 cp = mtod(lastm, u_int8_t *) + lastm->m_len; 1585 lastm->m_len += toadd; 1586 mlen += toadd; 1587 if (aal == MID_TBD_AAL5) { 1588 bzero(cp, toadd - MID_PDU_SIZE); 1589 dat = (u_int32_t *)(cp + toadd - MID_PDU_SIZE); 1590 /* make sure the PDU is in proper byte order */ 1591 *dat = htonl(MID_PDU_MK1(0, 0, got)); 1592 } else { 1593 bzero(cp, toadd); 1594 } 1595 atm_flags |= EN_OBTRL; 1596 } 1597 ATM_PH_FLAGS(ap) = atm_flags; /* update EN_OBHDR/EN_OBTRL bits */ 1598#endif /* EN_MBUF_OPT */ 1599 1600 /* 1601 * get assigned channel (will be zero unless txspeed[atm_vci] is set) 1602 */ 1603 1604 txchan = sc->txvc2slot[atm_vci]; 1605 1606 if (sc->txslot[txchan].mbsize > EN_TXHIWAT) { 1607 EN_COUNT(sc->txmbovr); 1608 m_freem(m); 1609#ifdef EN_DEBUG 1610 printf("%s: tx%d: buffer space shortage\n", sc->sc_dev.dv_xname, 1611 txchan); 1612#endif 1613 continue; 1614 } 1615 1616 sc->txslot[txchan].mbsize += mlen; 1617 1618#ifdef EN_DEBUG 1619 printf("%s: tx%d: VPI=%d, VCI=%d, FLAGS=0x%x, speed=0x%x\n", 1620 sc->sc_dev.dv_xname, txchan, atm_vpi, atm_vci, atm_flags, 1621 sc->txspeed[atm_vci]); 1622 printf(" adjusted mlen=%d, mbsize=%d\n", mlen, 1623 sc->txslot[txchan].mbsize); 1624#endif 1625 1626 IF_ENQUEUE(&sc->txslot[txchan].q, m); 1627 en_txdma(sc, txchan); 1628 1629 } 1630 /*NOTREACHED*/ 1631} 1632 1633 1634/* 1635 * en_mfix: fix a stupid mbuf 1636 */ 1637STATIC int en_makeexclusive(struct en_softc *, struct mbuf **, struct mbuf *); 1638 1639STATIC int en_makeexclusive(sc, mm, prev) 1640 struct en_softc *sc; 1641 struct mbuf **mm, *prev; 1642{ 1643 struct mbuf *m, *new; 1644 1645 m = *mm; 1646 1647 if (m->m_flags & M_EXT) { 1648 if (m->m_ext.ext_free) { 1649 /* external buffer isn't an ordinary mbuf cluster! */ 1650 printf("%s: mfix: special buffer! can't make a copy!\n", 1651 sc->sc_dev.dv_xname); 1652 return (0); 1653 } 1654 1655 if (mclrefcnt[mtocl(m->m_ext.ext_buf)] > 1) { 1656 /* make a real copy of the M_EXT mbuf since it is shared */ 1657 MGET(new, M_DONTWAIT, MT_DATA); 1658 if (!new) { 1659 EN_COUNT(sc->mfixfail); 1660 return(0); 1661 } 1662 if (m->m_flags & M_PKTHDR) 1663 M_COPY_PKTHDR(new, m); 1664 MCLGET(new, M_DONTWAIT); 1665 if ((new->m_flags & M_EXT) == 0) { 1666 m_free(new); 1667 EN_COUNT(sc->mfixfail); 1668 return(0); 1669 } 1670 bcopy(m->m_data, new->m_data, m->m_len); 1671 new->m_len = m->m_len; 1672 new->m_next = m->m_next; 1673 if (prev) 1674 prev->m_next = new; 1675 m_free(m); 1676 *mm = new; 1677 } 1678 else { 1679 /* the buffer is not shared, align the data offset using 1680 this buffer. */ 1681 u_char *d = mtod(m, u_char *); 1682 int off = ((u_long)d) % sizeof(u_int32_t); 1683 1684 if (off > 0) { 1685 bcopy(d, d - off, m->m_len); 1686 m->m_data = (caddr_t)d - off; 1687 } 1688 } 1689 } 1690 return (1); 1691} 1692 1693STATIC int en_mfix(sc, mm, prev) 1694 1695struct en_softc *sc; 1696struct mbuf **mm, *prev; 1697 1698{ 1699 struct mbuf *m; 1700 u_char *d, *cp; 1701 int off; 1702 struct mbuf *nxt; 1703 1704 m = *mm; 1705 1706 EN_COUNT(sc->mfix); /* count # of calls */ 1707#ifdef EN_DEBUG 1708 printf("%s: mfix mbuf m_data=0x%x, m_len=%d\n", sc->sc_dev.dv_xname, 1709 m->m_data, m->m_len); 1710#endif 1711 1712 d = mtod(m, u_char *); 1713 off = ((unsigned long) d) % sizeof(u_int32_t); 1714 1715 if (off) { 1716 if ((m->m_flags & M_EXT) == 0) { 1717 bcopy(d, d - off, m->m_len); /* ALIGN! (with costly data copy...) */ 1718 d -= off; 1719 m->m_data = (caddr_t)d; 1720 } else { 1721 /* can't write to an M_EXT mbuf since it may be shared */ 1722 if (en_makeexclusive(sc, &m, prev) == 0) 1723 return (0); 1724 *mm = m; /* note: 'd' now invalid */ 1725 } 1726 } 1727 1728 off = m->m_len % sizeof(u_int32_t); 1729 if (off == 0) 1730 return(1); 1731 1732 if (m->m_flags & M_EXT) { 1733 /* can't write to an M_EXT mbuf since it may be shared */ 1734 if (en_makeexclusive(sc, &m, prev) == 0) 1735 return (0); 1736 *mm = m; /* note: 'd' now invalid */ 1737 } 1738 1739 d = mtod(m, u_char *) + m->m_len; 1740 off = sizeof(u_int32_t) - off; 1741 1742 nxt = m->m_next; 1743 while (off--) { 1744 if (nxt != NULL && nxt->m_len == 0) { 1745 /* remove an empty mbuf. this avoids odd byte padding to an empty 1746 last mbuf. */ 1747 m->m_next = nxt = m_free(nxt); 1748 } 1749 if (nxt == NULL) { /* out of data, zero fill */ 1750 *d++ = 0; 1751 continue; /* next "off" */ 1752 } 1753 cp = mtod(nxt, u_char *); 1754 *d++ = *cp++; 1755 m->m_len++; 1756 nxt->m_len--; 1757 nxt->m_data = (caddr_t)cp; 1758 } 1759 if (nxt != NULL && nxt->m_len == 0) 1760 m->m_next = m_free(nxt); 1761 return(1); 1762} 1763 1764 1765/* 1766 * en_txdma: start trasmit DMA, if possible 1767 */ 1768 1769STATIC void en_txdma(sc, chan) 1770 1771struct en_softc *sc; 1772int chan; 1773 1774{ 1775 struct mbuf *tmp; 1776 struct atm_pseudohdr *ap; 1777 struct en_launch launch; 1778 int datalen = 0, dtqneed, len, ncells; 1779 u_int8_t *cp; 1780 1781#ifdef EN_DEBUG 1782 printf("%s: tx%d: starting...\n", sc->sc_dev.dv_xname, chan); 1783#endif 1784 1785 /* 1786 * note: now that txlaunch handles non-word aligned/sized requests 1787 * the only time you can safely set launch.nodma is if you've en_mfix()'d 1788 * the mbuf chain. this happens only if EN_NOTXDMA || !en_dma. 1789 */ 1790 1791 launch.nodma = (EN_NOTXDMA || !en_dma); 1792 1793again: 1794 1795 /* 1796 * get an mbuf waiting for DMA 1797 */ 1798 1799 launch.t = sc->txslot[chan].q.ifq_head; /* peek at head of queue */ 1800 1801 if (launch.t == NULL) { 1802#ifdef EN_DEBUG 1803 printf("%s: tx%d: ...done!\n", sc->sc_dev.dv_xname, chan); 1804#endif 1805 return; /* >>> exit here if no data waiting for DMA <<< */ 1806 } 1807 1808 /* 1809 * get flags, vci 1810 * 1811 * note: launch.need = # bytes we need to get on the card 1812 * dtqneed = # of DTQs we need for this packet 1813 * launch.mlen = # of bytes in in mbuf chain (<= launch.need) 1814 */ 1815 1816 ap = mtod(launch.t, struct atm_pseudohdr *); 1817 launch.atm_vci = ATM_PH_VCI(ap); 1818 launch.atm_flags = ATM_PH_FLAGS(ap); 1819 launch.aal = ((launch.atm_flags & ATM_PH_AAL5) != 0) ? 1820 MID_TBD_AAL5 : MID_TBD_NOAAL5; 1821 1822 /* 1823 * XXX: have to recompute the length again, even though we already did 1824 * it in en_start(). might as well compute dtqneed here as well, so 1825 * this isn't that bad. 1826 */ 1827 1828 if ((launch.atm_flags & EN_OBHDR) == 0) { 1829 dtqneed = 1; /* header still needs to be added */ 1830 launch.need = MID_TBD_SIZE; /* not includeded with mbuf */ 1831 } else { 1832 dtqneed = 0; /* header on-board, dma with mbuf */ 1833 launch.need = 0; 1834 } 1835 1836 launch.mlen = 0; 1837 for (tmp = launch.t ; tmp != NULL ; tmp = tmp->m_next) { 1838 len = tmp->m_len; 1839 launch.mlen += len; 1840 cp = mtod(tmp, u_int8_t *); 1841 if (tmp == launch.t) { 1842 len -= sizeof(struct atm_pseudohdr); /* don't count this! */ 1843 cp += sizeof(struct atm_pseudohdr); 1844 } 1845 launch.need += len; 1846 if (len == 0) 1847 continue; /* atm_pseudohdr alone in first mbuf */ 1848 1849 dtqneed += en_dqneed(sc, (caddr_t) cp, len, 1); 1850 } 1851 1852 if ((launch.need % sizeof(u_int32_t)) != 0) 1853 dtqneed++; /* need DTQ to FLUSH internal buffer */ 1854 1855 if ((launch.atm_flags & EN_OBTRL) == 0) { 1856 if (launch.aal == MID_TBD_AAL5) { 1857 datalen = launch.need - MID_TBD_SIZE; 1858 launch.need += MID_PDU_SIZE; /* AAL5: need PDU tail */ 1859 } 1860 dtqneed++; /* need to work on the end a bit */ 1861 } 1862 1863 /* 1864 * finish calculation of launch.need (need to figure out how much padding 1865 * we will need). launch.need includes MID_TBD_SIZE, but we need to 1866 * remove that to so we can round off properly. we have to add 1867 * MID_TBD_SIZE back in after calculating ncells. 1868 */ 1869 1870 launch.need = roundup(launch.need - MID_TBD_SIZE, MID_ATMDATASZ); 1871 ncells = launch.need / MID_ATMDATASZ; 1872 launch.need += MID_TBD_SIZE; 1873 1874 if (launch.need > EN_TXSZ * 1024) { 1875 printf("%s: tx%d: packet larger than xmit buffer (%d > %d)\n", 1876 sc->sc_dev.dv_xname, chan, launch.need, EN_TXSZ * 1024); 1877 goto dequeue_drop; 1878 } 1879 1880 if (launch.need > sc->txslot[chan].bfree) { 1881 EN_COUNT(sc->txoutspace); 1882#ifdef EN_DEBUG 1883 printf("%s: tx%d: out of transmit space\n", sc->sc_dev.dv_xname, chan); 1884#endif 1885 return; /* >>> exit here if out of obmem buffer space <<< */ 1886 } 1887 1888 /* 1889 * ensure we have enough dtqs to go, if not, wait for more. 1890 */ 1891 1892 if (launch.nodma) { 1893 dtqneed = 1; 1894 } 1895 if (dtqneed > sc->dtq_free) { 1896 sc->need_dtqs = 1; 1897 EN_COUNT(sc->txdtqout); 1898#ifdef EN_DEBUG 1899 printf("%s: tx%d: out of transmit DTQs\n", sc->sc_dev.dv_xname, chan); 1900#endif 1901 return; /* >>> exit here if out of dtqs <<< */ 1902 } 1903 1904 /* 1905 * it is a go, commit! dequeue mbuf start working on the xfer. 1906 */ 1907 1908 IF_DEQUEUE(&sc->txslot[chan].q, tmp); 1909#ifdef EN_DIAG 1910 if (launch.t != tmp) 1911 panic("en dequeue"); 1912#endif /* EN_DIAG */ 1913 1914 /* 1915 * launch! 1916 */ 1917 1918 EN_COUNT(sc->launch); 1919 sc->enif.if_opackets++; 1920 if ((launch.atm_flags & EN_OBHDR) == 0) { 1921 EN_COUNT(sc->lheader); 1922 /* store tbd1/tbd2 in host byte order */ 1923 launch.tbd1 = MID_TBD_MK1(launch.aal, sc->txspeed[launch.atm_vci], ncells); 1924 launch.tbd2 = MID_TBD_MK2(launch.atm_vci, 0, 0); 1925 } 1926 if ((launch.atm_flags & EN_OBTRL) == 0 && launch.aal == MID_TBD_AAL5) { 1927 EN_COUNT(sc->ltail); 1928 launch.pdu1 = MID_PDU_MK1(0, 0, datalen); /* host byte order */ 1929 } 1930 1931 en_txlaunch(sc, chan, &launch); 1932 1933 /* 1934 * do some housekeeping and get the next packet 1935 */ 1936 1937 sc->txslot[chan].bfree -= launch.need; 1938 IF_ENQUEUE(&sc->txslot[chan].indma, launch.t); 1939 goto again; 1940 1941 /* 1942 * END of txdma loop! 1943 */ 1944 1945 /* 1946 * error handles 1947 */ 1948 1949dequeue_drop: 1950 IF_DEQUEUE(&sc->txslot[chan].q, tmp); 1951 if (launch.t != tmp) 1952 panic("en dequeue drop"); 1953 m_freem(launch.t); 1954 sc->txslot[chan].mbsize -= launch.mlen; 1955 goto again; 1956} 1957 1958 1959/* 1960 * en_txlaunch: launch an mbuf into the dma pool! 1961 */ 1962 1963STATIC void en_txlaunch(sc, chan, l) 1964 1965struct en_softc *sc; 1966int chan; 1967struct en_launch *l; 1968 1969{ 1970 struct mbuf *tmp; 1971 u_int32_t cur = sc->txslot[chan].cur, 1972 start = sc->txslot[chan].start, 1973 stop = sc->txslot[chan].stop, 1974 dma, *data, *datastop, count, bcode; 1975 int pad, addtail, need, len, needalign, cnt, end, mx; 1976 1977 1978 /* 1979 * vars: 1980 * need = # bytes card still needs (decr. to zero) 1981 * len = # of bytes left in current mbuf 1982 * cur = our current pointer 1983 * dma = last place we programmed into the DMA 1984 * data = pointer into data area of mbuf that needs to go next 1985 * cnt = # of bytes to transfer in this DTQ 1986 * bcode/count = DMA burst code, and chip's version of cnt 1987 * 1988 * a single buffer can require up to 5 DTQs depending on its size 1989 * and alignment requirements. the 5 possible requests are: 1990 * [1] 1, 2, or 3 byte DMA to align src data pointer to word boundary 1991 * [2] alburst DMA to align src data pointer to bestburstlen 1992 * [3] 1 or more bestburstlen DMAs 1993 * [4] clean up burst (to last word boundary) 1994 * [5] 1, 2, or 3 byte final clean up DMA 1995 */ 1996 1997 need = l->need; 1998 dma = cur; 1999 addtail = (l->atm_flags & EN_OBTRL) == 0; /* add a tail? */ 2000 2001#ifdef EN_DIAG 2002 if ((need - MID_TBD_SIZE) % MID_ATMDATASZ) 2003 printf("%s: tx%d: bogus trasmit needs (%d)\n", sc->sc_dev.dv_xname, chan, 2004 need); 2005#endif 2006#ifdef EN_DEBUG 2007 printf("%s: tx%d: launch mbuf %p! cur=0x%x[%d], need=%d, addtail=%d\n", 2008 sc->sc_dev.dv_xname, chan, l->t, cur, (cur-start)/4, need, addtail); 2009 count = EN_READ(sc, MIDX_PLACE(chan)); 2010 printf(" HW: base_address=0x%x, size=%d, read=%d, descstart=%d\n", 2011 MIDX_BASE(count), MIDX_SZ(count), EN_READ(sc, MIDX_READPTR(chan)), 2012 EN_READ(sc, MIDX_DESCSTART(chan))); 2013#endif 2014 2015 /* 2016 * do we need to insert the TBD by hand? 2017 * note that tbd1/tbd2/pdu1 are in host byte order. 2018 */ 2019 2020 if ((l->atm_flags & EN_OBHDR) == 0) { 2021#ifdef EN_DEBUG 2022 printf("%s: tx%d: insert header 0x%x 0x%x\n", sc->sc_dev.dv_xname, 2023 chan, l->tbd1, l->tbd2); 2024#endif 2025 EN_WRITE(sc, cur, l->tbd1); 2026 EN_WRAPADD(start, stop, cur, 4); 2027 EN_WRITE(sc, cur, l->tbd2); 2028 EN_WRAPADD(start, stop, cur, 4); 2029 need -= 8; 2030 } 2031 2032 /* 2033 * now do the mbufs... 2034 */ 2035 2036 for (tmp = l->t ; tmp != NULL ; tmp = tmp->m_next) { 2037 2038 /* get pointer to data and length */ 2039 data = mtod(tmp, u_int32_t *); 2040 len = tmp->m_len; 2041 if (tmp == l->t) { 2042 data += sizeof(struct atm_pseudohdr)/sizeof(u_int32_t); 2043 len -= sizeof(struct atm_pseudohdr); 2044 } 2045 2046 /* now, determine if we should copy it */ 2047 if (l->nodma || (len < EN_MINDMA && 2048 (len % 4) == 0 && ((unsigned long) data % 4) == 0 && (cur % 4) == 0)) { 2049 2050 /* 2051 * roundup len: the only time this will change the value of len 2052 * is when l->nodma is true, tmp is the last mbuf, and there is 2053 * a non-word number of bytes to transmit. in this case it is 2054 * safe to round up because we've en_mfix'd the mbuf (so the first 2055 * byte is word aligned there must be enough free bytes at the end 2056 * to round off to the next word boundary)... 2057 */ 2058 len = roundup(len, sizeof(u_int32_t)); 2059 datastop = data + (len / sizeof(u_int32_t)); 2060 /* copy loop: preserve byte order!!! use WRITEDAT */ 2061 while (data != datastop) { 2062 EN_WRITEDAT(sc, cur, *data); 2063 data++; 2064 EN_WRAPADD(start, stop, cur, 4); 2065 } 2066 need -= len; 2067#ifdef EN_DEBUG 2068 printf("%s: tx%d: copied %d bytes (%d left, cur now 0x%x)\n", 2069 sc->sc_dev.dv_xname, chan, len, need, cur); 2070#endif 2071 continue; /* continue on to next mbuf */ 2072 } 2073 2074 /* going to do DMA, first make sure the dtq is in sync. */ 2075 if (dma != cur) { 2076 EN_DTQADD(sc, WORD_IDX(start,cur), chan, MIDDMA_JK, 0, 0, 0); 2077#ifdef EN_DEBUG 2078 printf("%s: tx%d: dtq_sync: advance pointer to %d\n", 2079 sc->sc_dev.dv_xname, chan, cur); 2080#endif 2081 } 2082 2083 /* 2084 * if this is the last buffer, and it looks like we are going to need to 2085 * flush the internal buffer, can we extend the length of this mbuf to 2086 * avoid the FLUSH? 2087 */ 2088 2089 if (tmp->m_next == NULL) { 2090 cnt = (need - len) % sizeof(u_int32_t); 2091 if (cnt && M_TRAILINGSPACE(tmp) >= cnt) 2092 len += cnt; /* pad for FLUSH */ 2093 } 2094 2095#if !defined(MIDWAY_ENIONLY) 2096 2097 /* 2098 * the adaptec DMA engine is smart and handles everything for us. 2099 */ 2100 2101 if (sc->is_adaptec) { 2102 /* need to DMA "len" bytes out to card */ 2103 need -= len; 2104 EN_WRAPADD(start, stop, cur, len); 2105#ifdef EN_DEBUG 2106 printf("%s: tx%d: adp_dma %d bytes (%d left, cur now 0x%x)\n", 2107 sc->sc_dev.dv_xname, chan, len, need, cur); 2108#endif 2109 end = (need == 0) ? MID_DMA_END : 0; 2110 EN_DTQADD(sc, len, chan, 0, vtophys(data), l->mlen, end); 2111 if (end) 2112 goto done; 2113 dma = cur; /* update dma pointer */ 2114 continue; 2115 } 2116#endif /* !MIDWAY_ENIONLY */ 2117 2118#if !defined(MIDWAY_ADPONLY) 2119 2120 /* 2121 * the ENI DMA engine is not so smart and need more help from us 2122 */ 2123 2124 /* do we need to do a DMA op to align to word boundary? */ 2125 needalign = (unsigned long) data % sizeof(u_int32_t); 2126 if (needalign) { 2127 EN_COUNT(sc->headbyte); 2128 cnt = sizeof(u_int32_t) - needalign; 2129 if (cnt == 2 && len >= cnt) { 2130 count = 1; 2131 bcode = MIDDMA_2BYTE; 2132 } else { 2133 cnt = min(cnt, len); /* prevent overflow */ 2134 count = cnt; 2135 bcode = MIDDMA_BYTE; 2136 } 2137 need -= cnt; 2138 EN_WRAPADD(start, stop, cur, cnt); 2139#ifdef EN_DEBUG 2140 printf("%s: tx%d: small al_dma %d bytes (%d left, cur now 0x%x)\n", 2141 sc->sc_dev.dv_xname, chan, cnt, need, cur); 2142#endif 2143 len -= cnt; 2144 end = (need == 0) ? MID_DMA_END : 0; 2145 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2146 if (end) 2147 goto done; 2148 data = (u_int32_t *) ((u_char *)data + cnt); 2149 } 2150 2151 /* do we need to do a DMA op to align? */ 2152 if (sc->alburst && 2153 (needalign = (((unsigned long) data) & sc->bestburstmask)) != 0 2154 && len >= sizeof(u_int32_t)) { 2155 cnt = sc->bestburstlen - needalign; 2156 mx = len & ~(sizeof(u_int32_t)-1); /* don't go past end */ 2157 if (cnt > mx) { 2158 cnt = mx; 2159 count = cnt / sizeof(u_int32_t); 2160 bcode = MIDDMA_WORD; 2161 } else { 2162 count = cnt / sizeof(u_int32_t); 2163 bcode = en_dmaplan[count].bcode; 2164 count = cnt >> en_dmaplan[count].divshift; 2165 } 2166 need -= cnt; 2167 EN_WRAPADD(start, stop, cur, cnt); 2168#ifdef EN_DEBUG 2169 printf("%s: tx%d: al_dma %d bytes (%d left, cur now 0x%x)\n", 2170 sc->sc_dev.dv_xname, chan, cnt, need, cur); 2171#endif 2172 len -= cnt; 2173 end = (need == 0) ? MID_DMA_END : 0; 2174 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2175 if (end) 2176 goto done; 2177 data = (u_int32_t *) ((u_char *)data + cnt); 2178 } 2179 2180 /* do we need to do a max-sized burst? */ 2181 if (len >= sc->bestburstlen) { 2182 count = len >> sc->bestburstshift; 2183 cnt = count << sc->bestburstshift; 2184 bcode = sc->bestburstcode; 2185 need -= cnt; 2186 EN_WRAPADD(start, stop, cur, cnt); 2187#ifdef EN_DEBUG 2188 printf("%s: tx%d: best_dma %d bytes (%d left, cur now 0x%x)\n", 2189 sc->sc_dev.dv_xname, chan, cnt, need, cur); 2190#endif 2191 len -= cnt; 2192 end = (need == 0) ? MID_DMA_END : 0; 2193 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2194 if (end) 2195 goto done; 2196 data = (u_int32_t *) ((u_char *)data + cnt); 2197 } 2198 2199 /* do we need to do a cleanup burst? */ 2200 cnt = len & ~(sizeof(u_int32_t)-1); 2201 if (cnt) { 2202 count = cnt / sizeof(u_int32_t); 2203 bcode = en_dmaplan[count].bcode; 2204 count = cnt >> en_dmaplan[count].divshift; 2205 need -= cnt; 2206 EN_WRAPADD(start, stop, cur, cnt); 2207#ifdef EN_DEBUG 2208 printf("%s: tx%d: cleanup_dma %d bytes (%d left, cur now 0x%x)\n", 2209 sc->sc_dev.dv_xname, chan, cnt, need, cur); 2210#endif 2211 len -= cnt; 2212 end = (need == 0) ? MID_DMA_END : 0; 2213 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2214 if (end) 2215 goto done; 2216 data = (u_int32_t *) ((u_char *)data + cnt); 2217 } 2218 2219 /* any word fragments left? */ 2220 if (len) { 2221 EN_COUNT(sc->tailbyte); 2222 if (len == 2) { 2223 count = 1; 2224 bcode = MIDDMA_2BYTE; /* use 2byte mode */ 2225 } else { 2226 count = len; 2227 bcode = MIDDMA_BYTE; /* use 1 byte mode */ 2228 } 2229 need -= len; 2230 EN_WRAPADD(start, stop, cur, len); 2231#ifdef EN_DEBUG 2232 printf("%s: tx%d: byte cleanup_dma %d bytes (%d left, cur now 0x%x)\n", 2233 sc->sc_dev.dv_xname, chan, len, need, cur); 2234#endif 2235 end = (need == 0) ? MID_DMA_END : 0; 2236 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2237 if (end) 2238 goto done; 2239 } 2240 2241 dma = cur; /* update dma pointer */ 2242#endif /* !MIDWAY_ADPONLY */ 2243 2244 } /* next mbuf, please */ 2245 2246 /* 2247 * all mbuf data has been copied out to the obmem (or set up to be DMAd). 2248 * if the trailer or padding needs to be put in, do it now. 2249 * 2250 * NOTE: experimental results reveal the following fact: 2251 * if you DMA "X" bytes to the card, where X is not a multiple of 4, 2252 * then the card will internally buffer the last (X % 4) bytes (in 2253 * hopes of getting (4 - (X % 4)) more bytes to make a complete word). 2254 * it is imporant to make sure we don't leave any important data in 2255 * this internal buffer because it is discarded on the last (end) DTQ. 2256 * one way to do this is to DMA in (4 - (X % 4)) more bytes to flush 2257 * the darn thing out. 2258 */ 2259 2260 if (addtail) { 2261 2262 pad = need % sizeof(u_int32_t); 2263 if (pad) { 2264 /* 2265 * FLUSH internal data buffer. pad out with random data from the front 2266 * of the mbuf chain... 2267 */ 2268 bcode = (sc->is_adaptec) ? 0 : MIDDMA_BYTE; 2269 EN_COUNT(sc->tailflush); 2270 EN_WRAPADD(start, stop, cur, pad); 2271 EN_DTQADD(sc, pad, chan, bcode, vtophys(l->t->m_data), 0, 0); 2272 need -= pad; 2273#ifdef EN_DEBUG 2274 printf("%s: tx%d: pad/FLUSH dma %d bytes (%d left, cur now 0x%x)\n", 2275 sc->sc_dev.dv_xname, chan, pad, need, cur); 2276#endif 2277 } 2278 2279 /* copy data */ 2280 pad = need / sizeof(u_int32_t); /* round *down* */ 2281 if (l->aal == MID_TBD_AAL5) 2282 pad -= 2; 2283#ifdef EN_DEBUG 2284 printf("%s: tx%d: padding %d bytes (cur now 0x%x)\n", 2285 sc->sc_dev.dv_xname, chan, pad * sizeof(u_int32_t), cur); 2286#endif 2287 while (pad--) { 2288 EN_WRITEDAT(sc, cur, 0); /* no byte order issues with zero */ 2289 EN_WRAPADD(start, stop, cur, 4); 2290 } 2291 if (l->aal == MID_TBD_AAL5) { 2292 EN_WRITE(sc, cur, l->pdu1); /* in host byte order */ 2293 EN_WRAPADD(start, stop, cur, 8); 2294 } 2295 } 2296 2297 if (addtail || dma != cur) { 2298 /* write final descritor */ 2299 EN_DTQADD(sc, WORD_IDX(start,cur), chan, MIDDMA_JK, 0, 2300 l->mlen, MID_DMA_END); 2301 /* dma = cur; */ /* not necessary since we are done */ 2302 } 2303 2304done: 2305 /* update current pointer */ 2306 sc->txslot[chan].cur = cur; 2307#ifdef EN_DEBUG 2308 printf("%s: tx%d: DONE! cur now = 0x%x\n", 2309 sc->sc_dev.dv_xname, chan, cur); 2310#endif 2311 2312 return; 2313} 2314 2315 2316/* 2317 * interrupt handler 2318 */ 2319 2320EN_INTR_TYPE en_intr(arg) 2321 2322void *arg; 2323 2324{ 2325 struct en_softc *sc = (struct en_softc *) arg; 2326 struct mbuf *m; 2327 struct atm_pseudohdr ah; 2328 u_int32_t reg, kick, val, mask, chip, vci, slot, dtq, drq; 2329 int lcv, idx, need_softserv = 0; 2330 2331 reg = EN_READ(sc, MID_INTACK); 2332 2333 if ((reg & MID_INT_ANY) == 0) 2334 EN_INTR_RET(0); /* not us */ 2335 2336#ifdef EN_DEBUG 2337 printf("%s: interrupt=0x%b\n", sc->sc_dev.dv_xname, reg, MID_INTBITS); 2338#endif 2339 2340 /* 2341 * unexpected errors that need a reset 2342 */ 2343 2344 if ((reg & (MID_INT_IDENT|MID_INT_LERR|MID_INT_DMA_ERR|MID_INT_SUNI)) != 0) { 2345 printf("%s: unexpected interrupt=0x%b, resetting card\n", 2346 sc->sc_dev.dv_xname, reg, MID_INTBITS); 2347#ifdef EN_DEBUG 2348#ifdef DDB 2349 Debugger(); 2350#endif /* DDB */ 2351 sc->enif.if_flags &= ~IFF_RUNNING; /* FREEZE! */ 2352#else 2353 en_reset(sc); 2354 en_init(sc); 2355#endif 2356 EN_INTR_RET(1); /* for us */ 2357 } 2358 2359 /******************* 2360 * xmit interrupts * 2361 ******************/ 2362 2363 kick = 0; /* bitmask of channels to kick */ 2364 if (reg & MID_INT_TX) { /* TX done! */ 2365 2366 /* 2367 * check for tx complete, if detected then this means that some space 2368 * has come free on the card. we must account for it and arrange to 2369 * kick the channel to life (in case it is stalled waiting on the card). 2370 */ 2371 for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) { 2372 if (reg & MID_TXCHAN(lcv)) { 2373 kick = kick | mask; /* want to kick later */ 2374 val = EN_READ(sc, MIDX_READPTR(lcv)); /* current read pointer */ 2375 val = (val * sizeof(u_int32_t)) + sc->txslot[lcv].start; 2376 /* convert to offset */ 2377 if (val > sc->txslot[lcv].cur) 2378 sc->txslot[lcv].bfree = val - sc->txslot[lcv].cur; 2379 else 2380 sc->txslot[lcv].bfree = (val + (EN_TXSZ*1024)) - sc->txslot[lcv].cur; 2381#ifdef EN_DEBUG 2382 printf("%s: tx%d: trasmit done. %d bytes now free in buffer\n", 2383 sc->sc_dev.dv_xname, lcv, sc->txslot[lcv].bfree); 2384#endif 2385 } 2386 } 2387 } 2388 2389 if (reg & MID_INT_DMA_TX) { /* TX DMA done! */ 2390 2391 /* 2392 * check for TX DMA complete, if detected then this means that some DTQs 2393 * are now free. it also means some indma mbufs can be freed. 2394 * if we needed DTQs, kick all channels. 2395 */ 2396 val = EN_READ(sc, MID_DMA_RDTX); /* chip's current location */ 2397 idx = MID_DTQ_A2REG(sc->dtq_chip);/* where we last saw chip */ 2398 if (sc->need_dtqs) { 2399 kick = MID_NTX_CH - 1; /* assume power of 2, kick all! */ 2400 sc->need_dtqs = 0; /* recalculated in "kick" loop below */ 2401#ifdef EN_DEBUG 2402 printf("%s: cleared need DTQ condition\n", sc->sc_dev.dv_xname); 2403#endif 2404 } 2405 while (idx != val) { 2406 sc->dtq_free++; 2407 if ((dtq = sc->dtq[idx]) != 0) { 2408 sc->dtq[idx] = 0; /* don't forget to zero it out when done */ 2409 slot = EN_DQ_SLOT(dtq); 2410 IF_DEQUEUE(&sc->txslot[slot].indma, m); 2411 if (!m) panic("enintr: dtqsync"); 2412 sc->txslot[slot].mbsize -= EN_DQ_LEN(dtq); 2413#ifdef EN_DEBUG 2414 printf("%s: tx%d: free %d dma bytes, mbsize now %d\n", 2415 sc->sc_dev.dv_xname, slot, EN_DQ_LEN(dtq), 2416 sc->txslot[slot].mbsize); 2417#endif 2418 m_freem(m); 2419 } 2420 EN_WRAPADD(0, MID_DTQ_N, idx, 1); 2421 } 2422 sc->dtq_chip = MID_DTQ_REG2A(val); /* sync softc */ 2423 } 2424 2425 2426 /* 2427 * kick xmit channels as needed 2428 */ 2429 2430 if (kick) { 2431#ifdef EN_DEBUG 2432 printf("%s: tx kick mask = 0x%x\n", sc->sc_dev.dv_xname, kick); 2433#endif 2434 for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) { 2435 if ((kick & mask) && sc->txslot[lcv].q.ifq_head) { 2436 en_txdma(sc, lcv); /* kick it! */ 2437 } 2438 } /* for each slot */ 2439 } /* if kick */ 2440 2441 2442 /******************* 2443 * recv interrupts * 2444 ******************/ 2445 2446 /* 2447 * check for RX DMA complete, and pass the data "upstairs" 2448 */ 2449 2450 if (reg & MID_INT_DMA_RX) { 2451 val = EN_READ(sc, MID_DMA_RDRX); /* chip's current location */ 2452 idx = MID_DRQ_A2REG(sc->drq_chip);/* where we last saw chip */ 2453 while (idx != val) { 2454 sc->drq_free++; 2455 if ((drq = sc->drq[idx]) != 0) { 2456 sc->drq[idx] = 0; /* don't forget to zero it out when done */ 2457 slot = EN_DQ_SLOT(drq); 2458 if (EN_DQ_LEN(drq) == 0) { /* "JK" trash DMA? */ 2459 m = NULL; 2460 } else { 2461 IF_DEQUEUE(&sc->rxslot[slot].indma, m); 2462 if (!m) { 2463 printf("%s: lost mbuf in slot %d!\n", sc->sc_dev.dv_xname, slot); 2464 panic("enintr: drqsync"); 2465 } 2466 } 2467 /* do something with this mbuf */ 2468 if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) { /* drain? */ 2469 if (m) 2470 m_freem(m); 2471 vci = sc->rxslot[slot].atm_vci; 2472 if (sc->rxslot[slot].indma.ifq_head == NULL && 2473 sc->rxslot[slot].q.ifq_head == NULL && 2474 (EN_READ(sc, MID_VC(vci)) & MIDV_INSERVICE) == 0 && 2475 (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) { 2476 sc->rxslot[slot].oth_flags = ENOTHER_FREE; /* done drain */ 2477 sc->rxslot[slot].atm_vci = RX_NONE; 2478 sc->rxvc2slot[vci] = RX_NONE; 2479#ifdef EN_DEBUG 2480 printf("%s: rx%d: VCI %d now free\n", sc->sc_dev.dv_xname, 2481 slot, vci); 2482#endif 2483 } 2484 } else if (m != NULL) { 2485 ATM_PH_FLAGS(&ah) = sc->rxslot[slot].atm_flags; 2486 ATM_PH_VPI(&ah) = 0; 2487 ATM_PH_SETVCI(&ah, sc->rxslot[slot].atm_vci); 2488#ifdef EN_DEBUG 2489 printf("%s: rx%d: rxvci%d: atm_input, mbuf %p, len %d, hand %p\n", 2490 sc->sc_dev.dv_xname, slot, sc->rxslot[slot].atm_vci, m, 2491 EN_DQ_LEN(drq), sc->rxslot[slot].rxhand); 2492#endif 2493 sc->enif.if_ipackets++; 2494 2495 atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand); 2496 } 2497 2498 } 2499 EN_WRAPADD(0, MID_DRQ_N, idx, 1); 2500 } 2501 sc->drq_chip = MID_DRQ_REG2A(val); /* sync softc */ 2502 2503 if (sc->need_drqs) { /* true if we had a DRQ shortage */ 2504 need_softserv = 1; 2505 sc->need_drqs = 0; 2506#ifdef EN_DEBUG 2507 printf("%s: cleared need DRQ condition\n", sc->sc_dev.dv_xname); 2508#endif 2509 } 2510 } 2511 2512 /* 2513 * handle service interrupts 2514 */ 2515 2516 if (reg & MID_INT_SERVICE) { 2517 chip = MID_SL_REG2A(EN_READ(sc, MID_SERV_WRITE)); 2518 2519 while (sc->hwslistp != chip) { 2520 2521 /* fetch and remove it from hardware service list */ 2522 vci = EN_READ(sc, sc->hwslistp); 2523 EN_WRAPADD(MID_SLOFF, MID_SLEND, sc->hwslistp, 4);/* advance hw ptr */ 2524 slot = sc->rxvc2slot[vci]; 2525 if (slot == RX_NONE) { 2526#ifdef EN_DEBUG 2527 printf("%s: unexpected rx interrupt on VCI %d\n", 2528 sc->sc_dev.dv_xname, vci); 2529#endif 2530 EN_WRITE(sc, MID_VC(vci), MIDV_TRASH); /* rx off, damn it! */ 2531 continue; /* next */ 2532 } 2533 EN_WRITE(sc, MID_VC(vci), sc->rxslot[slot].mode); /* remove from hwsl */ 2534 EN_COUNT(sc->hwpull); 2535 2536#ifdef EN_DEBUG 2537 printf("%s: pulled VCI %d off hwslist\n", sc->sc_dev.dv_xname, vci); 2538#endif 2539 2540 /* add it to the software service list (if needed) */ 2541 if ((sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) { 2542 EN_COUNT(sc->swadd); 2543 need_softserv = 1; 2544 sc->rxslot[slot].oth_flags |= ENOTHER_SWSL; 2545 sc->swslist[sc->swsl_tail] = slot; 2546 EN_WRAPADD(0, MID_SL_N, sc->swsl_tail, 1); 2547 sc->swsl_size++; 2548#ifdef EN_DEBUG 2549 printf("%s: added VCI %d to swslist\n", sc->sc_dev.dv_xname, vci); 2550#endif 2551 } 2552 } 2553 } 2554 2555 /* 2556 * now service (function too big to include here) 2557 */ 2558 2559 if (need_softserv) 2560 en_service(sc); 2561 2562 /* 2563 * keep our stats 2564 */ 2565 2566 if (reg & MID_INT_DMA_OVR) { 2567 EN_COUNT(sc->dmaovr); 2568#ifdef EN_DEBUG 2569 printf("%s: MID_INT_DMA_OVR\n", sc->sc_dev.dv_xname); 2570#endif 2571 } 2572 reg = EN_READ(sc, MID_STAT); 2573#ifdef EN_STAT 2574 sc->otrash += MID_OTRASH(reg); 2575 sc->vtrash += MID_VTRASH(reg); 2576#endif 2577 2578 EN_INTR_RET(1); /* for us */ 2579} 2580 2581 2582/* 2583 * en_service: handle a service interrupt 2584 * 2585 * Q: why do we need a software service list? 2586 * 2587 * A: if we remove a VCI from the hardware list and we find that we are 2588 * out of DRQs we must defer processing until some DRQs become free. 2589 * so we must remember to look at this RX VCI/slot later, but we can't 2590 * put it back on the hardware service list (since that isn't allowed). 2591 * so we instead save it on the software service list. it would be nice 2592 * if we could peek at the VCI on top of the hwservice list without removing 2593 * it, however this leads to a race condition: if we peek at it and 2594 * decide we are done with it new data could come in before we have a 2595 * chance to remove it from the hwslist. by the time we get it out of 2596 * the list the interrupt for the new data will be lost. oops! 2597 * 2598 */ 2599 2600STATIC void en_service(sc) 2601 2602struct en_softc *sc; 2603 2604{ 2605 struct mbuf *m, *tmp; 2606 u_int32_t cur, dstart, rbd, pdu, *sav, dma, bcode, count, *data, *datastop; 2607 u_int32_t start, stop, cnt, needalign; 2608 int slot, raw, aal5, llc, vci, fill, mlen, tlen, drqneed, need, needfill, end; 2609 2610 aal5 = 0; /* Silence gcc */ 2611next_vci: 2612 if (sc->swsl_size == 0) { 2613#ifdef EN_DEBUG 2614 printf("%s: en_service done\n", sc->sc_dev.dv_xname); 2615#endif 2616 return; /* >>> exit here if swsl now empty <<< */ 2617 } 2618 2619 /* 2620 * get slot/vci to service 2621 */ 2622 2623 slot = sc->swslist[sc->swsl_head]; 2624 vci = sc->rxslot[slot].atm_vci; 2625#ifdef EN_DIAG 2626 if (sc->rxvc2slot[vci] != slot) panic("en_service rx slot/vci sync"); 2627#endif 2628 2629 /* 2630 * determine our mode and if we've got any work to do 2631 */ 2632 2633 raw = sc->rxslot[slot].oth_flags & ENOTHER_RAW; 2634 start= sc->rxslot[slot].start; 2635 stop= sc->rxslot[slot].stop; 2636 cur = sc->rxslot[slot].cur; 2637 2638#ifdef EN_DEBUG 2639 printf("%s: rx%d: service vci=%d raw=%d start/stop/cur=0x%x 0x%x 0x%x\n", 2640 sc->sc_dev.dv_xname, slot, vci, raw, start, stop, cur); 2641#endif 2642 2643same_vci: 2644 dstart = MIDV_DSTART(EN_READ(sc, MID_DST_RP(vci))); 2645 dstart = (dstart * sizeof(u_int32_t)) + start; 2646 2647 /* check to see if there is any data at all */ 2648 if (dstart == cur) { 2649defer: /* defer processing */ 2650 EN_WRAPADD(0, MID_SL_N, sc->swsl_head, 1); 2651 sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL; 2652 sc->swsl_size--; 2653 /* >>> remove from swslist <<< */ 2654#ifdef EN_DEBUG 2655 printf("%s: rx%d: remove vci %d from swslist\n", 2656 sc->sc_dev.dv_xname, slot, vci); 2657#endif 2658 goto next_vci; 2659 } 2660 2661 /* 2662 * figure out how many bytes we need 2663 * [mlen = # bytes to go in mbufs, fill = # bytes to dump (MIDDMA_JK)] 2664 */ 2665 2666 if (raw) { 2667 2668 /* raw mode (aka boodi mode) */ 2669 fill = 0; 2670 if (dstart > cur) 2671 mlen = dstart - cur; 2672 else 2673 mlen = (dstart + (EN_RXSZ*1024)) - cur; 2674 2675 if (mlen < sc->rxslot[slot].raw_threshold) 2676 goto defer; /* too little data to deal with */ 2677 2678 } else { 2679 2680 /* normal mode */ 2681 aal5 = (sc->rxslot[slot].atm_flags & ATM_PH_AAL5); 2682 llc = (aal5 && (sc->rxslot[slot].atm_flags & ATM_PH_LLCSNAP)) ? 1 : 0; 2683 rbd = EN_READ(sc, cur); 2684 if (MID_RBD_ID(rbd) != MID_RBD_STDID) 2685 panic("en_service: id mismatch\n"); 2686 2687 if (rbd & MID_RBD_T) { 2688 mlen = 0; /* we've got trash */ 2689 fill = MID_RBD_SIZE; 2690 EN_COUNT(sc->ttrash); 2691 } else if (!aal5) { 2692 mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */ 2693 fill = 0; 2694 } else { 2695 tlen = (MID_RBD_CNT(rbd) * MID_ATMDATASZ) + MID_RBD_SIZE; 2696 pdu = cur + tlen - MID_PDU_SIZE; 2697 if (pdu >= stop) 2698 pdu -= (EN_RXSZ*1024); 2699 pdu = EN_READ(sc, pdu); /* get PDU in correct byte order */ 2700 fill = tlen - MID_RBD_SIZE - MID_PDU_LEN(pdu); 2701 if (fill < 0 || (rbd & MID_RBD_CRCERR) != 0) { 2702 printf("%s: invalid AAL5 PDU length or CRC detected, dropping frame\n", 2703 sc->sc_dev.dv_xname); 2704 printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x) CRCERR=%d\n", 2705 sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE, 2706 MID_PDU_LEN(pdu), pdu, (rbd & MID_RBD_CRCERR)?1:0); 2707 fill = tlen; 2708 } 2709 mlen = tlen - fill; 2710 } 2711 2712 } 2713 2714 /* 2715 * now allocate mbufs for mlen bytes of data, if out of mbufs, trash all 2716 * 2717 * notes: 2718 * 1. it is possible that we've already allocated an mbuf for this pkt 2719 * but ran out of DRQs, in which case we saved the allocated mbuf on 2720 * "q". 2721 * 2. if we save an mbuf in "q" we store the "cur" (pointer) in the front 2722 * of the mbuf as an identity (that we can check later), and we also 2723 * store drqneed (so we don't have to recompute it). 2724 * 3. after this block of code, if m is still NULL then we ran out of mbufs 2725 */ 2726 2727 m = sc->rxslot[slot].q.ifq_head; 2728 drqneed = 1; 2729 if (m) { 2730 sav = mtod(m, u_int32_t *); 2731 if (sav[0] != cur) { 2732#ifdef EN_DEBUG 2733 printf("%s: rx%d: q'ed mbuf %p not ours\n", 2734 sc->sc_dev.dv_xname, slot, m); 2735#endif 2736 m = NULL; /* wasn't ours */ 2737 EN_COUNT(sc->rxqnotus); 2738 } else { 2739 EN_COUNT(sc->rxqus); 2740 IF_DEQUEUE(&sc->rxslot[slot].q, m); 2741 drqneed = sav[1]; 2742#ifdef EN_DEBUG 2743 printf("%s: rx%d: recovered q'ed mbuf %p (drqneed=%d)\n", 2744 sc->sc_dev.dv_xname, slot, m, drqneed); 2745#endif 2746 } 2747 } 2748 2749 if (mlen != 0 && m == NULL) { 2750 m = en_mget(sc, mlen, &drqneed); /* allocate! */ 2751 if (m == NULL) { 2752 fill += mlen; 2753 mlen = 0; 2754 EN_COUNT(sc->rxmbufout); 2755#ifdef EN_DEBUG 2756 printf("%s: rx%d: out of mbufs\n", sc->sc_dev.dv_xname, slot); 2757#endif 2758 } 2759#ifdef EN_DEBUG 2760 printf("%s: rx%d: allocate mbuf %p, mlen=%d, drqneed=%d\n", 2761 sc->sc_dev.dv_xname, slot, m, mlen, drqneed); 2762#endif 2763 } 2764 2765#ifdef EN_DEBUG 2766 printf("%s: rx%d: VCI %d, mbuf_chain %p, mlen %d, fill %d\n", 2767 sc->sc_dev.dv_xname, slot, vci, m, mlen, fill); 2768#endif 2769 2770 /* 2771 * now check to see if we've got the DRQs needed. if we are out of 2772 * DRQs we must quit (saving our mbuf, if we've got one). 2773 */ 2774 2775 needfill = (fill) ? 1 : 0; 2776 if (drqneed + needfill > sc->drq_free) { 2777 sc->need_drqs = 1; /* flag condition */ 2778 if (m == NULL) { 2779 EN_COUNT(sc->rxoutboth); 2780#ifdef EN_DEBUG 2781 printf("%s: rx%d: out of DRQs *and* mbufs!\n", sc->sc_dev.dv_xname, slot); 2782#endif 2783 return; /* >>> exit here if out of both mbufs and DRQs <<< */ 2784 } 2785 sav = mtod(m, u_int32_t *); 2786 sav[0] = cur; 2787 sav[1] = drqneed; 2788 IF_ENQUEUE(&sc->rxslot[slot].q, m); 2789 EN_COUNT(sc->rxdrqout); 2790#ifdef EN_DEBUG 2791 printf("%s: rx%d: out of DRQs\n", sc->sc_dev.dv_xname, slot); 2792#endif 2793 return; /* >>> exit here if out of DRQs <<< */ 2794 } 2795 2796 /* 2797 * at this point all resources have been allocated and we are commited 2798 * to servicing this slot. 2799 * 2800 * dma = last location we told chip about 2801 * cur = current location 2802 * mlen = space in the mbuf we want 2803 * need = bytes to xfer in (decrs to zero) 2804 * fill = how much fill we need 2805 * tlen = how much data to transfer to this mbuf 2806 * cnt/bcode/count = <same as xmit> 2807 * 2808 * 'needfill' not used after this point 2809 */ 2810 2811 dma = cur; /* dma = last location we told chip about */ 2812 need = roundup(mlen, sizeof(u_int32_t)); 2813 fill = fill - (need - mlen); /* note: may invalidate 'needfill' */ 2814 2815 for (tmp = m ; tmp != NULL && need > 0 ; tmp = tmp->m_next) { 2816 tlen = roundup(tmp->m_len, sizeof(u_int32_t)); /* m_len set by en_mget */ 2817 data = mtod(tmp, u_int32_t *); 2818 2819#ifdef EN_DEBUG 2820 printf("%s: rx%d: load mbuf %p, m_len=%d, m_data=%p, tlen=%d\n", 2821 sc->sc_dev.dv_xname, slot, tmp, tmp->m_len, tmp->m_data, tlen); 2822#endif 2823 2824 /* copy data */ 2825 if (EN_NORXDMA || !en_dma || tlen < EN_MINDMA) { 2826 datastop = (u_int32_t *)((u_char *) data + tlen); 2827 /* copy loop: preserve byte order!!! use READDAT */ 2828 while (data != datastop) { 2829 *data = EN_READDAT(sc, cur); 2830 data++; 2831 EN_WRAPADD(start, stop, cur, 4); 2832 } 2833 need -= tlen; 2834#ifdef EN_DEBUG 2835 printf("%s: rx%d: vci%d: copied %d bytes (%d left)\n", 2836 sc->sc_dev.dv_xname, slot, vci, tlen, need); 2837#endif 2838 continue; 2839 } 2840 2841 /* DMA data (check to see if we need to sync DRQ first) */ 2842 if (dma != cur) { 2843 EN_DRQADD(sc, WORD_IDX(start,cur), vci, MIDDMA_JK, 0, 0, 0, 0); 2844#ifdef EN_DEBUG 2845 printf("%s: rx%d: vci%d: drq_sync: advance pointer to %d\n", 2846 sc->sc_dev.dv_xname, slot, vci, cur); 2847#endif 2848 } 2849 2850#if !defined(MIDWAY_ENIONLY) 2851 2852 /* 2853 * the adaptec DMA engine is smart and handles everything for us. 2854 */ 2855 2856 if (sc->is_adaptec) { 2857 need -= tlen; 2858 EN_WRAPADD(start, stop, cur, tlen); 2859#ifdef EN_DEBUG 2860 printf("%s: rx%d: vci%d: adp_dma %d bytes (%d left)\n", 2861 sc->sc_dev.dv_xname, slot, vci, tlen, need); 2862#endif 2863 end = (need == 0 && !fill) ? MID_DMA_END : 0; 2864 EN_DRQADD(sc, tlen, vci, 0, vtophys(data), mlen, slot, end); 2865 if (end) 2866 goto done; 2867 dma = cur; /* update dma pointer */ 2868 continue; 2869 } 2870#endif /* !MIDWAY_ENIONLY */ 2871 2872 2873#if !defined(MIDWAY_ADPONLY) 2874 2875 /* 2876 * the ENI DMA engine is not so smart and need more help from us 2877 */ 2878 2879 /* do we need to do a DMA op to align? */ 2880 if (sc->alburst && 2881 (needalign = (((unsigned long) data) & sc->bestburstmask)) != 0) { 2882 cnt = sc->bestburstlen - needalign; 2883 if (cnt > tlen) { 2884 cnt = tlen; 2885 count = cnt / sizeof(u_int32_t); 2886 bcode = MIDDMA_WORD; 2887 } else { 2888 count = cnt / sizeof(u_int32_t); 2889 bcode = en_dmaplan[count].bcode; 2890 count = cnt >> en_dmaplan[count].divshift; 2891 } 2892 need -= cnt; 2893 EN_WRAPADD(start, stop, cur, cnt); 2894#ifdef EN_DEBUG 2895 printf("%s: rx%d: vci%d: al_dma %d bytes (%d left)\n", 2896 sc->sc_dev.dv_xname, slot, vci, cnt, need); 2897#endif 2898 tlen -= cnt; 2899 end = (need == 0 && !fill) ? MID_DMA_END : 0; 2900 EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end); 2901 if (end) 2902 goto done; 2903 data = (u_int32_t *)((u_char *) data + cnt); 2904 } 2905 2906 /* do we need a max-sized burst? */ 2907 if (tlen >= sc->bestburstlen) { 2908 count = tlen >> sc->bestburstshift; 2909 cnt = count << sc->bestburstshift; 2910 bcode = sc->bestburstcode; 2911 need -= cnt; 2912 EN_WRAPADD(start, stop, cur, cnt); 2913#ifdef EN_DEBUG 2914 printf("%s: rx%d: vci%d: best_dma %d bytes (%d left)\n", 2915 sc->sc_dev.dv_xname, slot, vci, cnt, need); 2916#endif 2917 tlen -= cnt; 2918 end = (need == 0 && !fill) ? MID_DMA_END : 0; 2919 EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end); 2920 if (end) 2921 goto done; 2922 data = (u_int32_t *)((u_char *) data + cnt); 2923 } 2924 2925 /* do we need to do a cleanup burst? */ 2926 if (tlen) { 2927 count = tlen / sizeof(u_int32_t); 2928 bcode = en_dmaplan[count].bcode; 2929 count = tlen >> en_dmaplan[count].divshift; 2930 need -= tlen; 2931 EN_WRAPADD(start, stop, cur, tlen); 2932#ifdef EN_DEBUG 2933 printf("%s: rx%d: vci%d: cleanup_dma %d bytes (%d left)\n", 2934 sc->sc_dev.dv_xname, slot, vci, tlen, need); 2935#endif 2936 end = (need == 0 && !fill) ? MID_DMA_END : 0; 2937 EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end); 2938 if (end) 2939 goto done; 2940 } 2941 2942 dma = cur; /* update dma pointer */ 2943 2944#endif /* !MIDWAY_ADPONLY */ 2945 2946 } 2947 2948 /* skip the end */ 2949 if (fill || dma != cur) { 2950#ifdef EN_DEBUG 2951 if (fill) 2952 printf("%s: rx%d: vci%d: skipping %d bytes of fill\n", 2953 sc->sc_dev.dv_xname, slot, vci, fill); 2954 else 2955 printf("%s: rx%d: vci%d: syncing chip from 0x%x to 0x%x [cur]\n", 2956 sc->sc_dev.dv_xname, slot, vci, dma, cur); 2957#endif 2958 EN_WRAPADD(start, stop, cur, fill); 2959 EN_DRQADD(sc, WORD_IDX(start,cur), vci, MIDDMA_JK, 0, mlen, 2960 slot, MID_DMA_END); 2961 /* dma = cur; */ /* not necessary since we are done */ 2962 } 2963 2964 /* 2965 * done, remove stuff we don't want to pass up: 2966 * raw mode (boodi mode): pass everything up for later processing 2967 * aal5: remove RBD 2968 * aal0: remove RBD + cell header 2969 */ 2970 2971done: 2972 if (m) { 2973 if (!raw) { 2974 cnt = MID_RBD_SIZE; 2975 if (!aal5) cnt += MID_CHDR_SIZE; 2976 m->m_len -= cnt; /* chop! */ 2977 m->m_pkthdr.len -= cnt; 2978 m->m_data += cnt; 2979 } 2980 IF_ENQUEUE(&sc->rxslot[slot].indma, m); 2981 } 2982 sc->rxslot[slot].cur = cur; /* update master copy of 'cur' */ 2983 2984#ifdef EN_DEBUG 2985 printf("%s: rx%d: vci%d: DONE! cur now =0x%x\n", 2986 sc->sc_dev.dv_xname, slot, vci, cur); 2987#endif 2988 2989 goto same_vci; /* get next packet in this slot */ 2990} 2991 2992 2993#ifdef EN_DDBHOOK 2994/* 2995 * functions we can call from ddb 2996 */ 2997 2998/* 2999 * en_dump: dump the state 3000 */ 3001 3002#define END_SWSL 0x00000040 /* swsl state */ 3003#define END_DRQ 0x00000020 /* drq state */ 3004#define END_DTQ 0x00000010 /* dtq state */ 3005#define END_RX 0x00000008 /* rx state */ 3006#define END_TX 0x00000004 /* tx state */ 3007#define END_MREGS 0x00000002 /* registers */ 3008#define END_STATS 0x00000001 /* dump stats */ 3009 3010#define END_BITS "\20\7SWSL\6DRQ\5DTQ\4RX\3TX\2MREGS\1STATS" 3011 3012int en_dump(unit, level) 3013 3014int unit, level; 3015 3016{ 3017 struct en_softc *sc; 3018 int lcv, cnt, slot; 3019 u_int32_t ptr, reg; 3020 3021 for (lcv = 0 ; lcv < en_cd.cd_ndevs ; lcv++) { 3022 sc = (struct en_softc *) en_cd.cd_devs[lcv]; 3023 if (sc == NULL) continue; 3024 if (unit != -1 && unit != lcv) 3025 continue; 3026 3027 printf("dumping device %s at level 0x%b\n", sc->sc_dev.dv_xname, level, 3028 END_BITS); 3029 3030 if (sc->dtq_us == 0) { 3031 printf("<hasn't been en_init'd yet>\n"); 3032 continue; 3033 } 3034 3035 if (level & END_STATS) { 3036 printf(" en_stats:\n"); 3037 printf(" %d mfix (%d failed); %d/%d head/tail byte DMAs, %d flushes\n", 3038 sc->mfix, sc->mfixfail, sc->headbyte, sc->tailbyte, sc->tailflush); 3039 printf(" %d rx dma overflow interrupts\n", sc->dmaovr); 3040 printf(" %d times we ran out of TX space and stalled\n", 3041 sc->txoutspace); 3042 printf(" %d times we ran out of DTQs\n", sc->txdtqout); 3043 printf(" %d times we launched a packet\n", sc->launch); 3044 printf(" %d times we launched without on-board header\n", sc->lheader); 3045 printf(" %d times we launched without on-board tail\n", sc->ltail); 3046 printf(" %d times we pulled the hw service list\n", sc->hwpull); 3047 printf(" %d times we pushed a vci on the sw service list\n", 3048 sc->swadd); 3049 printf(" %d times RX pulled an mbuf from Q that wasn't ours\n", 3050 sc->rxqnotus); 3051 printf(" %d times RX pulled a good mbuf from Q\n", sc->rxqus); 3052 printf(" %d times we ran out of mbufs *and* DRQs\n", sc->rxoutboth); 3053 printf(" %d times we ran out of DRQs\n", sc->rxdrqout); 3054 3055 printf(" %d trasmit packets dropped due to mbsize\n", sc->txmbovr); 3056 printf(" %d cells trashed due to turned off rxvc\n", sc->vtrash); 3057 printf(" %d cells trashed due to totally full buffer\n", sc->otrash); 3058 printf(" %d cells trashed due almost full buffer\n", sc->ttrash); 3059 printf(" %d rx mbuf allocation failures\n", sc->rxmbufout); 3060#ifdef NATM 3061 printf(" %d drops at natmintrq\n", natmintrq.ifq_drops); 3062#ifdef NATM_STAT 3063 printf(" natmintr so_rcv: ok/drop cnt: %d/%d, ok/drop bytes: %d/%d\n", 3064 natm_sookcnt, natm_sodropcnt, natm_sookbytes, natm_sodropbytes); 3065#endif 3066#endif 3067 } 3068 3069 if (level & END_MREGS) { 3070 printf("mregs:\n"); 3071 printf("resid = 0x%x\n", EN_READ(sc, MID_RESID)); 3072 printf("interrupt status = 0x%b\n", 3073 EN_READ(sc, MID_INTSTAT), MID_INTBITS); 3074 printf("interrupt enable = 0x%b\n", 3075 EN_READ(sc, MID_INTENA), MID_INTBITS); 3076 printf("mcsr = 0x%b\n", EN_READ(sc, MID_MAST_CSR), MID_MCSRBITS); 3077 printf("serv_write = [chip=%d] [us=%d]\n", EN_READ(sc, MID_SERV_WRITE), 3078 MID_SL_A2REG(sc->hwslistp)); 3079 printf("dma addr = 0x%x\n", EN_READ(sc, MID_DMA_ADDR)); 3080 printf("DRQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n", 3081 MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX)), 3082 MID_DRQ_REG2A(EN_READ(sc, MID_DMA_WRRX)), sc->drq_chip, sc->drq_us); 3083 printf("DTQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n", 3084 MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX)), 3085 MID_DTQ_REG2A(EN_READ(sc, MID_DMA_WRTX)), sc->dtq_chip, sc->dtq_us); 3086 3087 printf(" unusal txspeeds: "); 3088 for (cnt = 0 ; cnt < MID_N_VC ; cnt++) 3089 if (sc->txspeed[cnt]) 3090 printf(" vci%d=0x%x", cnt, sc->txspeed[cnt]); 3091 printf("\n"); 3092 3093 printf(" rxvc slot mappings: "); 3094 for (cnt = 0 ; cnt < MID_N_VC ; cnt++) 3095 if (sc->rxvc2slot[cnt] != RX_NONE) 3096 printf(" %d->%d", cnt, sc->rxvc2slot[cnt]); 3097 printf("\n"); 3098 3099 } 3100 3101 if (level & END_TX) { 3102 printf("tx:\n"); 3103 for (slot = 0 ; slot < EN_NTX; slot++) { 3104 printf("tx%d: start/stop/cur=0x%x/0x%x/0x%x [%d] ", slot, 3105 sc->txslot[slot].start, sc->txslot[slot].stop, sc->txslot[slot].cur, 3106 (sc->txslot[slot].cur - sc->txslot[slot].start)/4); 3107 printf("mbsize=%d, bfree=%d\n", sc->txslot[slot].mbsize, 3108 sc->txslot[slot].bfree); 3109 printf("txhw: base_address=0x%x, size=%d, read=%d, descstart=%d\n", 3110 MIDX_BASE(EN_READ(sc, MIDX_PLACE(slot))), 3111 MIDX_SZ(EN_READ(sc, MIDX_PLACE(slot))), 3112 EN_READ(sc, MIDX_READPTR(slot)), EN_READ(sc, MIDX_DESCSTART(slot))); 3113 } 3114 } 3115 3116 if (level & END_RX) { 3117 printf(" recv slots:\n"); 3118 for (slot = 0 ; slot < sc->en_nrx; slot++) { 3119 printf("rx%d: vci=%d: start/stop/cur=0x%x/0x%x/0x%x ", slot, 3120 sc->rxslot[slot].atm_vci, sc->rxslot[slot].start, 3121 sc->rxslot[slot].stop, sc->rxslot[slot].cur); 3122 printf("mode=0x%x, atm_flags=0x%x, oth_flags=0x%x\n", 3123 sc->rxslot[slot].mode, sc->rxslot[slot].atm_flags, 3124 sc->rxslot[slot].oth_flags); 3125 printf("RXHW: mode=0x%x, DST_RP=0x%x, WP_ST_CNT=0x%x\n", 3126 EN_READ(sc, MID_VC(sc->rxslot[slot].atm_vci)), 3127 EN_READ(sc, MID_DST_RP(sc->rxslot[slot].atm_vci)), 3128 EN_READ(sc, MID_WP_ST_CNT(sc->rxslot[slot].atm_vci))); 3129 } 3130 } 3131 3132 if (level & END_DTQ) { 3133 printf(" dtq [need_dtqs=%d,dtq_free=%d]:\n", 3134 sc->need_dtqs, sc->dtq_free); 3135 ptr = sc->dtq_chip; 3136 while (ptr != sc->dtq_us) { 3137 reg = EN_READ(sc, ptr); 3138 printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n", 3139 sc->dtq[MID_DTQ_A2REG(ptr)], MID_DMA_CNT(reg), MID_DMA_TXCHAN(reg), 3140 (reg & MID_DMA_END) != 0, MID_DMA_TYPE(reg), EN_READ(sc, ptr+4)); 3141 EN_WRAPADD(MID_DTQOFF, MID_DTQEND, ptr, 8); 3142 } 3143 } 3144 3145 if (level & END_DRQ) { 3146 printf(" drq [need_drqs=%d,drq_free=%d]:\n", 3147 sc->need_drqs, sc->drq_free); 3148 ptr = sc->drq_chip; 3149 while (ptr != sc->drq_us) { 3150 reg = EN_READ(sc, ptr); 3151 printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n", 3152 sc->drq[MID_DRQ_A2REG(ptr)], MID_DMA_CNT(reg), MID_DMA_RXVCI(reg), 3153 (reg & MID_DMA_END) != 0, MID_DMA_TYPE(reg), EN_READ(sc, ptr+4)); 3154 EN_WRAPADD(MID_DRQOFF, MID_DRQEND, ptr, 8); 3155 } 3156 } 3157 3158 if (level & END_SWSL) { 3159 printf(" swslist [size=%d]: ", sc->swsl_size); 3160 for (cnt = sc->swsl_head ; cnt != sc->swsl_tail ; 3161 cnt = (cnt + 1) % MID_SL_N) 3162 printf("0x%x ", sc->swslist[cnt]); 3163 printf("\n"); 3164 } 3165 3166 } 3167 return(0); 3168} 3169 3170/* 3171 * en_dumpmem: dump the memory 3172 */ 3173 3174int en_dumpmem(unit, addr, len) 3175 3176int unit, addr, len; 3177 3178{ 3179 struct en_softc *sc; 3180 u_int32_t reg; 3181 3182 if (unit < 0 || unit > en_cd.cd_ndevs || 3183 (sc = (struct en_softc *) en_cd.cd_devs[unit]) == NULL) { 3184 printf("invalid unit number: %d\n", unit); 3185 return(0); 3186 } 3187 addr = addr & ~3; 3188 if (addr < MID_RAMOFF || addr + len*4 > MID_MAXOFF || len <= 0) { 3189 printf("invalid addr/len number: %d, %d\n", addr, len); 3190 return(0); 3191 } 3192 printf("dumping %d words starting at offset 0x%x\n", len, addr); 3193 while (len--) { 3194 reg = EN_READ(sc, addr); 3195 printf("mem[0x%x] = 0x%x\n", addr, reg); 3196 addr += 4; 3197 } 3198 return(0); 3199} 3200#endif 3201 3202 3203#endif /* NEN > 0 || !defined(__FreeBSD__) */
| 175 176/* 177 * autoconfig attachments 178 */ 179 180struct cfdriver en_cd = { 181 0, "en", DV_IFNET, 182}; 183 184/* 185 * local structures 186 */ 187 188/* 189 * params to en_txlaunch() function 190 */ 191 192struct en_launch { 193 u_int32_t tbd1; /* TBD 1 */ 194 u_int32_t tbd2; /* TBD 2 */ 195 u_int32_t pdu1; /* PDU 1 (aal5) */ 196 int nodma; /* don't use DMA */ 197 int need; /* total space we need (pad out if less data) */ 198 int mlen; /* length of mbuf (for dtq) */ 199 struct mbuf *t; /* data */ 200 u_int32_t aal; /* aal code */ 201 u_int32_t atm_vci; /* vci */ 202 u_int8_t atm_flags; /* flags */ 203}; 204 205 206/* 207 * dma table (index by # of words) 208 * 209 * plan A: use WMAYBE 210 * plan B: avoid WMAYBE 211 */ 212 213struct en_dmatab { 214 u_int8_t bcode; /* code */ 215 u_int8_t divshift; /* byte divisor */ 216}; 217 218static struct en_dmatab en_dma_planA[] = { 219 { 0, 0 }, /* 0 */ { MIDDMA_WORD, 2 }, /* 1 */ 220 { MIDDMA_2WORD, 3}, /* 2 */ { MIDDMA_4WMAYBE, 2}, /* 3 */ 221 { MIDDMA_4WORD, 4}, /* 4 */ { MIDDMA_8WMAYBE, 2}, /* 5 */ 222 { MIDDMA_8WMAYBE, 2}, /* 6 */ { MIDDMA_8WMAYBE, 2}, /* 7 */ 223 { MIDDMA_8WORD, 5}, /* 8 */ { MIDDMA_16WMAYBE, 2}, /* 9 */ 224 { MIDDMA_16WMAYBE,2}, /* 10 */ { MIDDMA_16WMAYBE, 2}, /* 11 */ 225 { MIDDMA_16WMAYBE,2}, /* 12 */ { MIDDMA_16WMAYBE, 2}, /* 13 */ 226 { MIDDMA_16WMAYBE,2}, /* 14 */ { MIDDMA_16WMAYBE, 2}, /* 15 */ 227 { MIDDMA_16WORD, 6}, /* 16 */ 228}; 229 230static struct en_dmatab en_dma_planB[] = { 231 { 0, 0 }, /* 0 */ { MIDDMA_WORD, 2}, /* 1 */ 232 { MIDDMA_2WORD, 3}, /* 2 */ { MIDDMA_WORD, 2}, /* 3 */ 233 { MIDDMA_4WORD, 4}, /* 4 */ { MIDDMA_WORD, 2}, /* 5 */ 234 { MIDDMA_2WORD, 3}, /* 6 */ { MIDDMA_WORD, 2}, /* 7 */ 235 { MIDDMA_8WORD, 5}, /* 8 */ { MIDDMA_WORD, 2}, /* 9 */ 236 { MIDDMA_2WORD, 3}, /* 10 */ { MIDDMA_WORD, 2}, /* 11 */ 237 { MIDDMA_4WORD, 4}, /* 12 */ { MIDDMA_WORD, 2}, /* 13 */ 238 { MIDDMA_2WORD, 3}, /* 14 */ { MIDDMA_WORD, 2}, /* 15 */ 239 { MIDDMA_16WORD, 6}, /* 16 */ 240}; 241 242static struct en_dmatab *en_dmaplan = en_dma_planA; 243 244/* 245 * prototypes 246 */ 247 248STATIC int en_b2sz __P((int)); 249#ifdef EN_DDBHOOK 250int en_dump __P((int,int)); 251int en_dumpmem __P((int,int,int)); 252#endif 253STATIC void en_dmaprobe __P((struct en_softc *)); 254STATIC int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *, 255 u_int8_t *, int)); 256STATIC int en_dqneed __P((struct en_softc *, caddr_t, u_int, u_int)); 257STATIC void en_init __P((struct en_softc *)); 258STATIC int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t)); 259STATIC int en_k2sz __P((int)); 260STATIC void en_loadvc __P((struct en_softc *, int)); 261STATIC int en_mfix __P((struct en_softc *, struct mbuf **, struct mbuf *)); 262STATIC struct mbuf *en_mget __P((struct en_softc *, u_int, u_int *)); 263STATIC u_int32_t en_read __P((struct en_softc *, u_int32_t)); 264STATIC int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *, int)); 265STATIC void en_txdma __P((struct en_softc *, int)); 266STATIC void en_txlaunch __P((struct en_softc *, int, struct en_launch *)); 267STATIC void en_service __P((struct en_softc *)); 268STATIC void en_start __P((struct ifnet *)); 269STATIC int en_sz2b __P((int)); 270STATIC void en_write __P((struct en_softc *, u_int32_t, u_int32_t)); 271 272/* 273 * macros/inline 274 */ 275 276/* 277 * raw read/write macros 278 */ 279 280#define EN_READDAT(SC,R) en_read(SC,R) 281#define EN_WRITEDAT(SC,R,V) en_write(SC,R,V) 282 283/* 284 * cooked read/write macros 285 */ 286 287#define EN_READ(SC,R) ntohl(en_read(SC,R)) 288#define EN_WRITE(SC,R,V) en_write(SC,R, htonl(V)) 289 290#define EN_WRAPADD(START,STOP,CUR,VAL) { \ 291 (CUR) = (CUR) + (VAL); \ 292 if ((CUR) >= (STOP)) \ 293 (CUR) = (START) + ((CUR) - (STOP)); \ 294 } 295 296#define WORD_IDX(START, X) (((X) - (START)) / sizeof(u_int32_t)) 297 298/* we store sc->dtq and sc->drq data in the following format... */ 299#define EN_DQ_MK(SLOT,LEN) (((SLOT) << 20)|(LEN)|(0x80000)) 300 /* the 0x80000 ensures we != 0 */ 301#define EN_DQ_SLOT(X) ((X) >> 20) 302#define EN_DQ_LEN(X) ((X) & 0x3ffff) 303 304/* format of DTQ/DRQ word 1 differs between ENI and ADP */ 305#if defined(MIDWAY_ENIONLY) 306 307#define MID_MK_TXQ(SC,CNT,CHAN,END,BCODE) \ 308 EN_WRITE((SC), (SC)->dtq_us, \ 309 MID_MK_TXQ_ENI((CNT), (CHAN), (END), (BCODE))); 310 311#define MID_MK_RXQ(SC,CNT,VCI,END,BCODE) \ 312 EN_WRITE((SC), (SC)->drq_us, \ 313 MID_MK_RXQ_ENI((CNT), (VCI), (END), (BCODE))); 314 315#elif defined(MIDWAY_ADPONLY) 316 317#define MID_MK_TXQ(SC,CNT,CHAN,END,JK) \ 318 EN_WRITE((SC), (SC)->dtq_us, \ 319 MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK))); 320 321#define MID_MK_RXQ(SC,CNT,VCI,END,JK) \ 322 EN_WRITE((SC), (SC)->drq_us, \ 323 MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK))); 324 325#else 326 327#define MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE) { \ 328 if ((SC)->is_adaptec) \ 329 EN_WRITE((SC), (SC)->dtq_us, \ 330 MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK_OR_BCODE))); \ 331 else \ 332 EN_WRITE((SC), (SC)->dtq_us, \ 333 MID_MK_TXQ_ENI((CNT), (CHAN), (END), (JK_OR_BCODE))); \ 334 } 335 336#define MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE) { \ 337 if ((SC)->is_adaptec) \ 338 EN_WRITE((SC), (SC)->drq_us, \ 339 MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK_OR_BCODE))); \ 340 else \ 341 EN_WRITE((SC), (SC)->drq_us, \ 342 MID_MK_RXQ_ENI((CNT), (VCI), (END), (JK_OR_BCODE))); \ 343 } 344 345#endif 346 347/* add an item to the DTQ */ 348#define EN_DTQADD(SC,CNT,CHAN,JK_OR_BCODE,ADDR,LEN,END) { \ 349 if (END) \ 350 (SC)->dtq[MID_DTQ_A2REG((SC)->dtq_us)] = EN_DQ_MK(CHAN,LEN); \ 351 MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE); \ 352 (SC)->dtq_us += 4; \ 353 EN_WRITE((SC), (SC)->dtq_us, (ADDR)); \ 354 EN_WRAPADD(MID_DTQOFF, MID_DTQEND, (SC)->dtq_us, 4); \ 355 (SC)->dtq_free--; \ 356 if (END) \ 357 EN_WRITE((SC), MID_DMA_WRTX, MID_DTQ_A2REG((SC)->dtq_us)); \ 358} 359 360/* DRQ add macro */ 361#define EN_DRQADD(SC,CNT,VCI,JK_OR_BCODE,ADDR,LEN,SLOT,END) { \ 362 if (END) \ 363 (SC)->drq[MID_DRQ_A2REG((SC)->drq_us)] = EN_DQ_MK(SLOT,LEN); \ 364 MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE); \ 365 (SC)->drq_us += 4; \ 366 EN_WRITE((SC), (SC)->drq_us, (ADDR)); \ 367 EN_WRAPADD(MID_DRQOFF, MID_DRQEND, (SC)->drq_us, 4); \ 368 (SC)->drq_free--; \ 369 if (END) \ 370 EN_WRITE((SC), MID_DMA_WRRX, MID_DRQ_A2REG((SC)->drq_us)); \ 371} 372 373/* 374 * the driver code 375 * 376 * the code is arranged in a specific way: 377 * [1] short/inline functions 378 * [2] autoconfig stuff 379 * [3] ioctl stuff 380 * [4] reset -> init -> trasmit -> intr -> receive functions 381 * 382 */ 383 384/***********************************************************************/ 385 386/* 387 * en_read: read a word from the card. this is the only function 388 * that reads from the card. 389 */ 390 391STATIC INLINE u_int32_t en_read(sc, r) 392 393struct en_softc *sc; 394u_int32_t r; 395 396{ 397 398#ifdef EN_DEBUG_RANGE 399 if (r > MID_MAXOFF || (r % 4)) { 400 printf("en_read out of range, r=0x%x\n", r); 401 panic("en_read"); 402 } 403#endif 404 405 return(bus_space_read_4(sc->en_memt, sc->en_base, r)); 406} 407 408/* 409 * en_write: write a word to the card. this is the only function that 410 * writes to the card. 411 */ 412 413STATIC INLINE void en_write(sc, r, v) 414 415struct en_softc *sc; 416u_int32_t r, v; 417 418{ 419#ifdef EN_DEBUG_RANGE 420 if (r > MID_MAXOFF || (r % 4)) { 421 printf("en_write out of range, r=0x%x\n", r); 422 panic("en_write"); 423 } 424#endif 425 426 bus_space_write_4(sc->en_memt, sc->en_base, r, v); 427} 428 429/* 430 * en_k2sz: convert KBytes to a size parameter (a log2) 431 */ 432 433STATIC INLINE int en_k2sz(k) 434 435int k; 436 437{ 438 switch(k) { 439 case 1: return(0); 440 case 2: return(1); 441 case 4: return(2); 442 case 8: return(3); 443 case 16: return(4); 444 case 32: return(5); 445 case 64: return(6); 446 case 128: return(7); 447 default: panic("en_k2sz"); 448 } 449 return(0); 450} 451#define en_log2(X) en_k2sz(X) 452 453 454/* 455 * en_b2sz: convert a DMA burst code to its byte size 456 */ 457 458STATIC INLINE int en_b2sz(b) 459 460int b; 461 462{ 463 switch (b) { 464 case MIDDMA_WORD: return(1*4); 465 case MIDDMA_2WMAYBE: 466 case MIDDMA_2WORD: return(2*4); 467 case MIDDMA_4WMAYBE: 468 case MIDDMA_4WORD: return(4*4); 469 case MIDDMA_8WMAYBE: 470 case MIDDMA_8WORD: return(8*4); 471 case MIDDMA_16WMAYBE: 472 case MIDDMA_16WORD: return(16*4); 473 default: panic("en_b2sz"); 474 } 475 return(0); 476} 477 478 479/* 480 * en_sz2b: convert a burst size (bytes) to DMA burst code 481 */ 482 483STATIC INLINE int en_sz2b(sz) 484 485int sz; 486 487{ 488 switch (sz) { 489 case 1*4: return(MIDDMA_WORD); 490 case 2*4: return(MIDDMA_2WORD); 491 case 4*4: return(MIDDMA_4WORD); 492 case 8*4: return(MIDDMA_8WORD); 493 case 16*4: return(MIDDMA_16WORD); 494 default: panic("en_sz2b"); 495 } 496 return(0); 497} 498 499 500/* 501 * en_dqneed: calculate number of DTQ/DRQ's needed for a buffer 502 */ 503 504STATIC INLINE int en_dqneed(sc, data, len, tx) 505 506struct en_softc *sc; 507caddr_t data; 508u_int len, tx; 509 510{ 511 int result, needalign, sz; 512 513#if !defined(MIDWAY_ENIONLY) 514#if !defined(MIDWAY_ADPONLY) 515 if (sc->is_adaptec) 516#endif /* !MIDWAY_ADPONLY */ 517 return(1); /* adaptec can DMA anything in one go */ 518#endif 519 520#if !defined(MIDWAY_ADPONLY) 521 result = 0; 522 if (len < EN_MINDMA) { 523 if (!tx) /* XXX: conservative */ 524 return(1); /* will copy/DMA_JK */ 525 } 526 527 if (tx) { /* byte burst? */ 528 needalign = (((unsigned long) data) % sizeof(u_int32_t)); 529 if (needalign) { 530 result++; 531 sz = min(len, sizeof(u_int32_t) - needalign); 532 len -= sz; 533 data += sz; 534 } 535 } 536 537 if (sc->alburst && len) { 538 needalign = (((unsigned long) data) & sc->bestburstmask); 539 if (needalign) { 540 result++; /* alburst */ 541 sz = min(len, sc->bestburstlen - needalign); 542 len -= sz; 543 } 544 } 545 546 if (len >= sc->bestburstlen) { 547 sz = len / sc->bestburstlen; 548 sz = sz * sc->bestburstlen; 549 len -= sz; 550 result++; /* best shot */ 551 } 552 553 if (len) { 554 result++; /* clean up */ 555 if (tx && (len % sizeof(u_int32_t)) != 0) 556 result++; /* byte cleanup */ 557 } 558 559 return(result); 560#endif /* !MIDWAY_ADPONLY */ 561} 562 563 564/* 565 * en_mget: get an mbuf chain that can hold totlen bytes and return it 566 * (for recv) [based on am7990_get from if_le and ieget from if_ie] 567 * after this call the sum of all the m_len's in the chain will be totlen. 568 */ 569 570STATIC INLINE struct mbuf *en_mget(sc, totlen, drqneed) 571 572struct en_softc *sc; 573u_int totlen, *drqneed; 574 575{ 576 struct mbuf *m; 577 struct mbuf *top, **mp; 578 *drqneed = 0; 579 580 MGETHDR(m, M_DONTWAIT, MT_DATA); 581 if (m == NULL) 582 return(NULL); 583 m->m_pkthdr.rcvif = &sc->enif; 584 m->m_pkthdr.len = totlen; 585 m->m_len = MHLEN; 586 top = NULL; 587 mp = ⊤ 588 589 /* if (top != NULL) then we've already got 1 mbuf on the chain */ 590 while (totlen > 0) { 591 if (top) { 592 MGET(m, M_DONTWAIT, MT_DATA); 593 if (!m) { 594 m_freem(top); 595 return(NULL); /* out of mbufs */ 596 } 597 m->m_len = MLEN; 598 } 599 if (top && totlen >= MINCLSIZE) { 600 MCLGET(m, M_DONTWAIT); 601 if (m->m_flags & M_EXT) 602 m->m_len = MCLBYTES; 603 } 604 m->m_len = min(totlen, m->m_len); 605 totlen -= m->m_len; 606 *mp = m; 607 mp = &m->m_next; 608 609 *drqneed += en_dqneed(sc, m->m_data, m->m_len, 0); 610 611 } 612 return(top); 613} 614 615/***********************************************************************/ 616 617/* 618 * autoconfig stuff 619 */ 620 621void en_attach(sc) 622 623struct en_softc *sc; 624 625{ 626 struct ifnet *ifp = &sc->enif; 627 int sz; 628 u_int32_t reg, lcv, check, ptr, sav, midvloc; 629 630 /* 631 * probe card to determine memory size. the stupid ENI card always 632 * reports to PCI that it needs 4MB of space (2MB regs and 2MB RAM). 633 * if it has less than 2MB RAM the addresses wrap in the RAM address space. 634 * (i.e. on a 512KB card addresses 0x3ffffc, 0x37fffc, and 0x2ffffc 635 * are aliases for 0x27fffc [note that RAM starts at offset 0x200000]). 636 */ 637 638 if (sc->en_busreset) 639 sc->en_busreset(sc); 640 EN_WRITE(sc, MID_RESID, 0x0); /* reset card before touching RAM */ 641 for (lcv = MID_PROBEOFF; lcv <= MID_MAXOFF ; lcv += MID_PROBSIZE) { 642 EN_WRITE(sc, lcv, lcv); /* data[address] = address */ 643 for (check = MID_PROBEOFF ; check < lcv ; check += MID_PROBSIZE) { 644 reg = EN_READ(sc, check); 645 if (reg != check) { /* found an alias! */ 646 goto done_probe; /* and quit */ 647 } 648 } 649 } 650done_probe: 651 lcv -= MID_PROBSIZE; /* take one step back */ 652 sc->en_obmemsz = (lcv + 4) - MID_RAMOFF; 653 654 /* 655 * determine the largest DMA burst supported 656 */ 657 658 en_dmaprobe(sc); 659 660 /* 661 * "hello world" 662 */ 663 664 if (sc->en_busreset) 665 sc->en_busreset(sc); 666 EN_WRITE(sc, MID_RESID, 0x0); /* reset */ 667 for (lcv = MID_RAMOFF ; lcv < MID_RAMOFF + sc->en_obmemsz ; lcv += 4) 668 EN_WRITE(sc, lcv, 0); /* zero memory */ 669 670 reg = EN_READ(sc, MID_RESID); 671 672 printf("%s: ATM midway v%d, board IDs %d.%d, %s%s%s, %ldKB on-board RAM\n", 673 sc->sc_dev.dv_xname, MID_VER(reg), MID_MID(reg), MID_DID(reg), 674 (MID_IS_SABRE(reg)) ? "sabre controller, " : "", 675 (MID_IS_SUNI(reg)) ? "SUNI" : "Utopia", 676 (!MID_IS_SUNI(reg) && MID_IS_UPIPE(reg)) ? " (pipelined)" : "", 677 sc->en_obmemsz / 1024); 678 679 if (sc->is_adaptec) { 680 if (sc->bestburstlen == 64 && sc->alburst == 0) 681 printf("%s: passed 64 byte DMA test\n", sc->sc_dev.dv_xname); 682 else 683 printf("%s: FAILED DMA TEST: burst=%d, alburst=%d\n", 684 sc->sc_dev.dv_xname, sc->bestburstlen, sc->alburst); 685 } else { 686 printf("%s: maximum DMA burst length = %d bytes%s\n", sc->sc_dev.dv_xname, 687 sc->bestburstlen, (sc->alburst) ? " (must align)" : ""); 688 } 689 690#if 0 /* WMAYBE doesn't work, don't complain about it */ 691 /* check if en_dmaprobe disabled wmaybe */ 692 if (en_dmaplan == en_dma_planB) 693 printf("%s: note: WMAYBE DMA has been disabled\n", sc->sc_dev.dv_xname); 694#endif 695 696 /* 697 * link into network subsystem and prepare card 698 */ 699 700#if defined(__NetBSD__) || defined(__OpenBSD__) 701 bcopy(sc->sc_dev.dv_xname, sc->enif.if_xname, IFNAMSIZ); 702#endif 703#if !defined(MISSING_IF_SOFTC) 704 sc->enif.if_softc = sc; 705#endif 706 ifp->if_flags = IFF_SIMPLEX|IFF_NOTRAILERS; 707 ifp->if_ioctl = en_ioctl; 708 ifp->if_output = atm_output; 709 ifp->if_start = en_start; 710 711 /* 712 * init softc 713 */ 714 715 for (lcv = 0 ; lcv < MID_N_VC ; lcv++) { 716 sc->rxvc2slot[lcv] = RX_NONE; 717 sc->txspeed[lcv] = 0; /* full */ 718 sc->txvc2slot[lcv] = 0; /* full speed == slot 0 */ 719 } 720 721 sz = sc->en_obmemsz - (MID_BUFOFF - MID_RAMOFF); 722 ptr = sav = MID_BUFOFF; 723 ptr = roundup(ptr, EN_TXSZ * 1024); /* align */ 724 sz = sz - (ptr - sav); 725 if (EN_TXSZ*1024 * EN_NTX > sz) { 726 printf("%s: EN_NTX/EN_TXSZ too big\n", sc->sc_dev.dv_xname); 727 return; 728 } 729 for (lcv = 0 ; lcv < EN_NTX ; lcv++) { 730 sc->txslot[lcv].mbsize = 0; 731 sc->txslot[lcv].start = ptr; 732 ptr += (EN_TXSZ * 1024); 733 sz -= (EN_TXSZ * 1024); 734 sc->txslot[lcv].stop = ptr; 735 sc->txslot[lcv].nref = 0; 736 bzero(&sc->txslot[lcv].indma, sizeof(sc->txslot[lcv].indma)); 737 bzero(&sc->txslot[lcv].q, sizeof(sc->txslot[lcv].q)); 738#ifdef EN_DEBUG 739 printf("%s: tx%d: start 0x%x, stop 0x%x\n", sc->sc_dev.dv_xname, lcv, 740 sc->txslot[lcv].start, sc->txslot[lcv].stop); 741#endif 742 } 743 744 sav = ptr; 745 ptr = roundup(ptr, EN_RXSZ * 1024); /* align */ 746 sz = sz - (ptr - sav); 747 sc->en_nrx = sz / (EN_RXSZ * 1024); 748 if (sc->en_nrx <= 0) { 749 printf("%s: EN_NTX/EN_TXSZ/EN_RXSZ too big\n", sc->sc_dev.dv_xname); 750 return; 751 } 752#if 1 753 /* leave one entry in the ringbuf unused to avoid wraparound */ 754 if (sc->en_nrx >= MID_N_VC) 755 sc->en_nrx = MID_N_VC - 1; 756#endif 757 for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) { 758 sc->rxslot[lcv].rxhand = NULL; 759 sc->rxslot[lcv].oth_flags = ENOTHER_FREE; 760 bzero(&sc->rxslot[lcv].indma, sizeof(sc->rxslot[lcv].indma)); 761 bzero(&sc->rxslot[lcv].q, sizeof(sc->rxslot[lcv].q)); 762 midvloc = sc->rxslot[lcv].start = ptr; 763 ptr += (EN_RXSZ * 1024); 764 sz -= (EN_RXSZ * 1024); 765 sc->rxslot[lcv].stop = ptr; 766 midvloc = midvloc - MID_RAMOFF; 767 midvloc = (midvloc & ~((EN_RXSZ*1024) - 1)) >> 2; /* mask, cvt to words */ 768 midvloc = midvloc >> MIDV_LOCTOPSHFT; /* we only want the top 11 bits */ 769 midvloc = (midvloc & MIDV_LOCMASK) << MIDV_LOCSHIFT; 770 sc->rxslot[lcv].mode = midvloc | 771 (en_k2sz(EN_RXSZ) << MIDV_SZSHIFT) | MIDV_TRASH; 772 773#ifdef EN_DEBUG 774 printf("%s: rx%d: start 0x%x, stop 0x%x, mode 0x%x\n", sc->sc_dev.dv_xname, 775 lcv, sc->rxslot[lcv].start, sc->rxslot[lcv].stop, sc->rxslot[lcv].mode); 776#endif 777 } 778 779#ifdef EN_STAT 780 sc->vtrash = sc->otrash = sc->mfix = sc->txmbovr = sc->dmaovr = 0; 781 sc->txoutspace = sc->txdtqout = sc->launch = sc->lheader = sc->ltail = 0; 782 sc->hwpull = sc->swadd = sc->rxqnotus = sc->rxqus = sc->rxoutboth = 0; 783 sc->rxdrqout = sc->ttrash = sc->rxmbufout = sc->mfixfail = 0; 784 sc->headbyte = sc->tailbyte = sc->tailflush = 0; 785#endif 786 sc->need_drqs = sc->need_dtqs = 0; 787 788 printf("%s: %d %dKB receive buffers, %d %dKB transmit buffers allocated\n", 789 sc->sc_dev.dv_xname, sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ); 790 791 /* 792 * final commit 793 */ 794 795 if_attach(ifp); 796 atm_ifattach(ifp); 797 798} 799 800 801/* 802 * en_dmaprobe: helper function for en_attach. 803 * 804 * see how the card handles DMA by running a few DMA tests. we need 805 * to figure out the largest number of bytes we can DMA in one burst 806 * ("bestburstlen"), and if the starting address for a burst needs to 807 * be aligned on any sort of boundary or not ("alburst"). 808 * 809 * typical findings: 810 * sparc1: bestburstlen=4, alburst=0 (ick, broken DMA!) 811 * sparc2: bestburstlen=64, alburst=1 812 * p166: bestburstlen=64, alburst=0 813 */ 814 815STATIC void en_dmaprobe(sc) 816 817struct en_softc *sc; 818 819{ 820 u_int32_t srcbuf[64], dstbuf[64]; 821 u_int8_t *sp, *dp; 822 int bestalgn, bestnotalgn, lcv, try, fail; 823 824 sc->alburst = 0; 825 826 sp = (u_int8_t *) srcbuf; 827 while ((((unsigned long) sp) % MIDDMA_MAXBURST) != 0) 828 sp += 4; 829 dp = (u_int8_t *) dstbuf; 830 while ((((unsigned long) dp) % MIDDMA_MAXBURST) != 0) 831 dp += 4; 832 833 bestalgn = bestnotalgn = en_dmaprobe_doit(sc, sp, dp, 0); 834 835 for (lcv = 4 ; lcv < MIDDMA_MAXBURST ; lcv += 4) { 836 try = en_dmaprobe_doit(sc, sp+lcv, dp+lcv, 0); 837 if (try < bestnotalgn) 838 bestnotalgn = try; 839 } 840 841 if (bestalgn != bestnotalgn) /* need bursts aligned */ 842 sc->alburst = 1; 843 844 sc->bestburstlen = bestalgn; 845 sc->bestburstshift = en_log2(bestalgn); 846 sc->bestburstmask = sc->bestburstlen - 1; /* must be power of 2 */ 847 sc->bestburstcode = en_sz2b(bestalgn); 848 849 if (sc->bestburstlen <= 2*sizeof(u_int32_t)) 850 return; /* won't be using WMAYBE */ 851 852 /* 853 * adaptec does not have (or need) wmaybe. do not bother testing 854 * for it. 855 */ 856 if (sc->is_adaptec) { 857 /* XXX, actually don't need a DMA plan: adaptec is smarter than that */ 858 en_dmaplan = en_dma_planB; 859 return; 860 } 861 862 /* 863 * test that WMAYBE dma works like we think it should 864 * (i.e. no alignment restrictions on host address other than alburst) 865 */ 866 867 try = sc->bestburstlen - 4; 868 fail = 0; 869 fail += en_dmaprobe_doit(sc, sp, dp, try); 870 for (lcv = 4 ; lcv < sc->bestburstlen ; lcv += 4) { 871 fail += en_dmaprobe_doit(sc, sp+lcv, dp+lcv, try); 872 if (sc->alburst) 873 try -= 4; 874 } 875 if (EN_NOWMAYBE || fail) { 876 if (fail) 877 printf("%s: WARNING: WMAYBE DMA test failed %d time(s)\n", 878 sc->sc_dev.dv_xname, fail); 879 en_dmaplan = en_dma_planB; /* fall back to plan B */ 880 } 881 882} 883 884 885/* 886 * en_dmaprobe_doit: do actual testing 887 */ 888 889int 890en_dmaprobe_doit(sc, sp, dp, wmtry) 891 892struct en_softc *sc; 893u_int8_t *sp, *dp; 894int wmtry; 895 896{ 897 int lcv, retval = 4, cnt, count; 898 u_int32_t reg, bcode, midvloc; 899 900 /* 901 * set up a 1k buffer at MID_BUFOFF 902 */ 903 904 if (sc->en_busreset) 905 sc->en_busreset(sc); 906 EN_WRITE(sc, MID_RESID, 0x0); /* reset card before touching RAM */ 907 908 midvloc = ((MID_BUFOFF - MID_RAMOFF) / sizeof(u_int32_t)) >> MIDV_LOCTOPSHFT; 909 EN_WRITE(sc, MIDX_PLACE(0), MIDX_MKPLACE(en_k2sz(1), midvloc)); 910 EN_WRITE(sc, MID_VC(0), (midvloc << MIDV_LOCSHIFT) 911 | (en_k2sz(1) << MIDV_SZSHIFT) | MIDV_TRASH); 912 EN_WRITE(sc, MID_DST_RP(0), 0); 913 EN_WRITE(sc, MID_WP_ST_CNT(0), 0); 914 915 for (lcv = 0 ; lcv < 68 ; lcv++) /* set up sample data */ 916 sp[lcv] = lcv+1; 917 EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* enable DMA (only) */ 918 919 sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX)); 920 sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX)); 921 922 /* 923 * try it now . . . DMA it out, then DMA it back in and compare 924 * 925 * note: in order to get the dma stuff to reverse directions it wants 926 * the "end" flag set! since we are not dma'ing valid data we may 927 * get an ident mismatch interrupt (which we will ignore). 928 * 929 * note: we've got two different tests rolled up in the same loop 930 * if (wmtry) 931 * then we are doing a wmaybe test and wmtry is a byte count 932 * else we are doing a burst test 933 */ 934 935 for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) { 936 937 /* zero SRAM and dest buffer */ 938 for (cnt = 0 ; cnt < 1024; cnt += 4) 939 EN_WRITE(sc, MID_BUFOFF+cnt, 0); /* zero memory */ 940 for (cnt = 0 ; cnt < 68 ; cnt++) 941 dp[cnt] = 0; 942 943 if (wmtry) { 944 count = (sc->bestburstlen - sizeof(u_int32_t)) / sizeof(u_int32_t); 945 bcode = en_dmaplan[count].bcode; 946 count = wmtry >> en_dmaplan[count].divshift; 947 } else { 948 bcode = en_sz2b(lcv); 949 count = 1; 950 } 951 if (sc->is_adaptec) 952 EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ADP(lcv, 0, MID_DMA_END, 0)); 953 else 954 EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ENI(count, 0, MID_DMA_END, bcode)); 955 EN_WRITE(sc, sc->dtq_chip+4, vtophys(sp)); 956 EN_WRITE(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_chip+8)); 957 cnt = 1000; 958 while (EN_READ(sc, MID_DMA_RDTX) == MID_DTQ_A2REG(sc->dtq_chip)) { 959 DELAY(1); 960 cnt--; 961 if (cnt == 0) { 962 printf("%s: unexpected timeout in tx DMA test\n", sc->sc_dev.dv_xname); 963 return(retval); /* timeout, give up */ 964 } 965 } 966 EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8); 967 reg = EN_READ(sc, MID_INTACK); 968 if ((reg & MID_INT_DMA_TX) != MID_INT_DMA_TX) { 969 printf("%s: unexpected status in tx DMA test: 0x%x\n", 970 sc->sc_dev.dv_xname, reg); 971 return(retval); 972 } 973 EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* re-enable DMA (only) */ 974 975 /* "return to sender..." address is known ... */ 976 977 if (sc->is_adaptec) 978 EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ADP(lcv, 0, MID_DMA_END, 0)); 979 else 980 EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ENI(count, 0, MID_DMA_END, bcode)); 981 EN_WRITE(sc, sc->drq_chip+4, vtophys(dp)); 982 EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip+8)); 983 cnt = 1000; 984 while (EN_READ(sc, MID_DMA_RDRX) == MID_DRQ_A2REG(sc->drq_chip)) { 985 DELAY(1); 986 cnt--; 987 if (cnt == 0) { 988 printf("%s: unexpected timeout in rx DMA test\n", sc->sc_dev.dv_xname); 989 return(retval); /* timeout, give up */ 990 } 991 } 992 EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8); 993 reg = EN_READ(sc, MID_INTACK); 994 if ((reg & MID_INT_DMA_RX) != MID_INT_DMA_RX) { 995 printf("%s: unexpected status in rx DMA test: 0x%x\n", 996 sc->sc_dev.dv_xname, reg); 997 return(retval); 998 } 999 EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* re-enable DMA (only) */ 1000 1001 if (wmtry) { 1002 return(bcmp(sp, dp, wmtry)); /* wmtry always exits here, no looping */ 1003 } 1004 1005 if (bcmp(sp, dp, lcv)) 1006 return(retval); /* failed, use last value */ 1007 1008 retval = lcv; 1009 1010 } 1011 return(retval); /* studly 64 byte DMA present! oh baby!! */ 1012} 1013 1014/***********************************************************************/ 1015 1016/* 1017 * en_ioctl: handle ioctl requests 1018 * 1019 * NOTE: if you add an ioctl to set txspeed, you should choose a new 1020 * TX channel/slot. Choose the one with the lowest sc->txslot[slot].nref 1021 * value, subtract one from sc->txslot[0].nref, add one to the 1022 * sc->txslot[slot].nref, set sc->txvc2slot[vci] = slot, and then set 1023 * txspeed[vci]. 1024 */ 1025 1026STATIC int en_ioctl(ifp, cmd, data) 1027 1028struct ifnet *ifp; 1029EN_IOCTL_CMDT cmd; 1030caddr_t data; 1031 1032{ 1033#ifdef MISSING_IF_SOFTC 1034 struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit]; 1035#else 1036 struct en_softc *sc = (struct en_softc *) ifp->if_softc; 1037#endif 1038 struct ifaddr *ifa = (struct ifaddr *) data; 1039 struct ifreq *ifr = (struct ifreq *) data; 1040 struct atm_pseudoioctl *api = (struct atm_pseudoioctl *)data; 1041#ifdef NATM 1042 struct atm_rawioctl *ario = (struct atm_rawioctl *)data; 1043 int slot; 1044#endif 1045 int s, error = 0; 1046 1047 s = splnet(); 1048 1049 switch (cmd) { 1050 case SIOCATMENA: /* enable circuit for recv */ 1051 error = en_rxctl(sc, api, 1); 1052 break; 1053 1054 case SIOCATMDIS: /* disable circuit for recv */ 1055 error = en_rxctl(sc, api, 0); 1056 break; 1057 1058#ifdef NATM 1059 case SIOCXRAWATM: 1060 if ((slot = sc->rxvc2slot[ario->npcb->npcb_vci]) == RX_NONE) { 1061 error = EINVAL; 1062 break; 1063 } 1064 if (ario->rawvalue > EN_RXSZ*1024) 1065 ario->rawvalue = EN_RXSZ*1024; 1066 if (ario->rawvalue) { 1067 sc->rxslot[slot].oth_flags |= ENOTHER_RAW; 1068 sc->rxslot[slot].raw_threshold = ario->rawvalue; 1069 } else { 1070 sc->rxslot[slot].oth_flags &= (~ENOTHER_RAW); 1071 sc->rxslot[slot].raw_threshold = 0; 1072 } 1073#ifdef EN_DEBUG 1074 printf("%s: rxvci%d: turn %s raw (boodi) mode\n", 1075 sc->sc_dev.dv_xname, ario->npcb->npcb_vci, 1076 (ario->rawvalue) ? "on" : "off"); 1077#endif 1078 break; 1079#endif 1080 case SIOCSIFADDR: 1081 ifp->if_flags |= IFF_UP; 1082#ifdef INET 1083 if (ifa->ifa_addr->sa_family == AF_INET) { 1084 en_reset(sc); 1085 en_init(sc); 1086 ifa->ifa_rtrequest = atm_rtrequest; /* ??? */ 1087 break; 1088 } 1089#endif /* INET */ 1090 /* what to do if not INET? */ 1091 en_reset(sc); 1092 en_init(sc); 1093 break; 1094 1095 case SIOCGIFADDR: 1096 error = EINVAL; 1097 break; 1098 1099 case SIOCSIFFLAGS: 1100 error = EINVAL; 1101 break; 1102 1103#if defined(SIOCSIFMTU) /* ??? copied from if_de */ 1104#if !defined(ifr_mtu) 1105#define ifr_mtu ifr_metric 1106#endif 1107 case SIOCSIFMTU: 1108 /* 1109 * Set the interface MTU. 1110 */ 1111#ifdef notsure 1112 if (ifr->ifr_mtu > ATMMTU) { 1113 error = EINVAL; 1114 break; 1115 } 1116#endif 1117 ifp->if_mtu = ifr->ifr_mtu; 1118 /* XXXCDC: do we really need to reset on MTU size change? */ 1119 en_reset(sc); 1120 en_init(sc); 1121 break; 1122#endif /* SIOCSIFMTU */ 1123 1124 default: 1125 error = EINVAL; 1126 break; 1127 } 1128 splx(s); 1129 return error; 1130} 1131 1132 1133/* 1134 * en_rxctl: turn on and off VCs for recv. 1135 */ 1136 1137STATIC int en_rxctl(sc, pi, on) 1138 1139struct en_softc *sc; 1140struct atm_pseudoioctl *pi; 1141int on; 1142 1143{ 1144 u_int s, vci, flags, slot; 1145 u_int32_t oldmode, newmode; 1146 1147 vci = ATM_PH_VCI(&pi->aph); 1148 flags = ATM_PH_FLAGS(&pi->aph); 1149 1150#ifdef EN_DEBUG 1151 printf("%s: %s vpi=%d, vci=%d, flags=%d\n", sc->sc_dev.dv_xname, 1152 (on) ? "enable" : "disable", ATM_PH_VPI(&pi->aph), vci, flags); 1153#endif 1154 1155 if (ATM_PH_VPI(&pi->aph) || vci >= MID_N_VC) 1156 return(EINVAL); 1157 1158 /* 1159 * turn on VCI! 1160 */ 1161 1162 if (on) { 1163 if (sc->rxvc2slot[vci] != RX_NONE) 1164 return(EINVAL); 1165 for (slot = 0 ; slot < sc->en_nrx ; slot++) 1166 if (sc->rxslot[slot].oth_flags & ENOTHER_FREE) 1167 break; 1168 if (slot == sc->en_nrx) 1169 return(ENOSPC); 1170 sc->rxvc2slot[vci] = slot; 1171 sc->rxslot[slot].rxhand = NULL; 1172 oldmode = sc->rxslot[slot].mode; 1173 newmode = (flags & ATM_PH_AAL5) ? MIDV_AAL5 : MIDV_NOAAL; 1174 sc->rxslot[slot].mode = MIDV_SETMODE(oldmode, newmode); 1175 sc->rxslot[slot].atm_vci = vci; 1176 sc->rxslot[slot].atm_flags = flags; 1177 sc->rxslot[slot].oth_flags = 0; 1178 sc->rxslot[slot].rxhand = pi->rxhand; 1179 if (sc->rxslot[slot].indma.ifq_head || sc->rxslot[slot].q.ifq_head) 1180 panic("en_rxctl: left over mbufs on enable"); 1181 sc->txspeed[vci] = 0; /* full speed to start */ 1182 sc->txvc2slot[vci] = 0; /* init value */ 1183 sc->txslot[0].nref++; /* bump reference count */ 1184 en_loadvc(sc, vci); /* does debug printf for us */ 1185 return(0); 1186 } 1187 1188 /* 1189 * turn off VCI 1190 */ 1191 1192 if (sc->rxvc2slot[vci] == RX_NONE) 1193 return(EINVAL); 1194 slot = sc->rxvc2slot[vci]; 1195 if ((sc->rxslot[slot].oth_flags & (ENOTHER_FREE|ENOTHER_DRAIN)) != 0) 1196 return(EINVAL); 1197 s = splimp(); /* block out enintr() */ 1198 oldmode = EN_READ(sc, MID_VC(vci)); 1199 newmode = MIDV_SETMODE(oldmode, MIDV_TRASH) & ~MIDV_INSERVICE; 1200 EN_WRITE(sc, MID_VC(vci), (newmode | (oldmode & MIDV_INSERVICE))); 1201 /* halt in tracks, be careful to preserve inserivce bit */ 1202 DELAY(27); 1203 sc->rxslot[slot].rxhand = NULL; 1204 sc->rxslot[slot].mode = newmode; 1205 1206 sc->txslot[sc->txvc2slot[vci]].nref--; 1207 sc->txspeed[vci] = 0; 1208 sc->txvc2slot[vci] = 0; 1209 1210 /* if stuff is still going on we are going to have to drain it out */ 1211 if (sc->rxslot[slot].indma.ifq_head || 1212 sc->rxslot[slot].q.ifq_head || 1213 (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) != 0) { 1214 sc->rxslot[slot].oth_flags |= ENOTHER_DRAIN; 1215 } else { 1216 sc->rxslot[slot].oth_flags = ENOTHER_FREE; 1217 sc->rxslot[slot].atm_vci = RX_NONE; 1218 sc->rxvc2slot[vci] = RX_NONE; 1219 } 1220 splx(s); /* enable enintr() */ 1221#ifdef EN_DEBUG 1222 printf("%s: rx%d: VCI %d is now %s\n", sc->sc_dev.dv_xname, slot, vci, 1223 (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) ? "draining" : "free"); 1224#endif 1225 return(0); 1226} 1227 1228/***********************************************************************/ 1229 1230/* 1231 * en_reset: reset the board, throw away work in progress. 1232 * must en_init to recover. 1233 */ 1234 1235void en_reset(sc) 1236 1237struct en_softc *sc; 1238 1239{ 1240 struct mbuf *m; 1241 int lcv, slot; 1242 1243#ifdef EN_DEBUG 1244 printf("%s: reset\n", sc->sc_dev.dv_xname); 1245#endif 1246 1247 if (sc->en_busreset) 1248 sc->en_busreset(sc); 1249 EN_WRITE(sc, MID_RESID, 0x0); /* reset hardware */ 1250 1251 /* 1252 * recv: dump any mbufs we are dma'ing into, if DRAINing, then a reset 1253 * will free us! 1254 */ 1255 1256 for (lcv = 0 ; lcv < MID_N_VC ; lcv++) { 1257 if (sc->rxvc2slot[lcv] == RX_NONE) 1258 continue; 1259 slot = sc->rxvc2slot[lcv]; 1260 while (1) { 1261 IF_DEQUEUE(&sc->rxslot[slot].indma, m); 1262 if (m == NULL) 1263 break; /* >>> exit 'while(1)' here <<< */ 1264 m_freem(m); 1265 } 1266 while (1) { 1267 IF_DEQUEUE(&sc->rxslot[slot].q, m); 1268 if (m == NULL) 1269 break; /* >>> exit 'while(1)' here <<< */ 1270 m_freem(m); 1271 } 1272 sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL; 1273 if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) { 1274 sc->rxslot[slot].oth_flags = ENOTHER_FREE; 1275 sc->rxvc2slot[lcv] = RX_NONE; 1276#ifdef EN_DEBUG 1277 printf("%s: rx%d: VCI %d is now free\n", sc->sc_dev.dv_xname, slot, lcv); 1278#endif 1279 } 1280 } 1281 1282 /* 1283 * xmit: dump everything 1284 */ 1285 1286 for (lcv = 0 ; lcv < EN_NTX ; lcv++) { 1287 while (1) { 1288 IF_DEQUEUE(&sc->txslot[lcv].indma, m); 1289 if (m == NULL) 1290 break; /* >>> exit 'while(1)' here <<< */ 1291 m_freem(m); 1292 } 1293 while (1) { 1294 IF_DEQUEUE(&sc->txslot[lcv].q, m); 1295 if (m == NULL) 1296 break; /* >>> exit 'while(1)' here <<< */ 1297 m_freem(m); 1298 } 1299 sc->txslot[lcv].mbsize = 0; 1300 } 1301 1302 return; 1303} 1304 1305 1306/* 1307 * en_init: init board and sync the card with the data in the softc. 1308 */ 1309 1310STATIC void en_init(sc) 1311 1312struct en_softc *sc; 1313 1314{ 1315 int vc, slot; 1316 u_int32_t loc; 1317 1318 if ((sc->enif.if_flags & IFF_UP) == 0) { 1319#ifdef EN_DEBUG 1320 printf("%s: going down\n", sc->sc_dev.dv_xname); 1321#endif 1322 en_reset(sc); /* to be safe */ 1323 sc->enif.if_flags &= ~IFF_RUNNING; /* disable */ 1324 return; 1325 } 1326 1327#ifdef EN_DEBUG 1328 printf("%s: going up\n", sc->sc_dev.dv_xname); 1329#endif 1330 sc->enif.if_flags |= IFF_RUNNING; /* enable */ 1331 1332 if (sc->en_busreset) 1333 sc->en_busreset(sc); 1334 EN_WRITE(sc, MID_RESID, 0x0); /* reset */ 1335 1336 /* 1337 * init obmem data structures: vc tab, dma q's, slist. 1338 */ 1339 1340 for (vc = 0 ; vc < MID_N_VC ; vc++) 1341 en_loadvc(sc, vc); 1342 1343 bzero(&sc->drq, sizeof(sc->drq)); 1344#if 1 1345 /* leave one entry in the ringbuf unused to avoid wraparound */ 1346 sc->drq_free = MID_DRQ_N - 1; 1347#else 1348 sc->drq_free = MID_DRQ_N; 1349#endif 1350 sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX)); 1351 EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip)); 1352 /* ensure zero queue */ 1353 sc->drq_us = sc->drq_chip; 1354 1355 bzero(&sc->dtq, sizeof(sc->dtq)); 1356#if 1 1357 /* leave one entry in the ringbuf unused to avoid wraparound */ 1358 sc->dtq_free = MID_DTQ_N - 1; 1359#else 1360 sc->dtq_free = MID_DTQ_N; 1361#endif 1362 sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX)); 1363 EN_WRITE(sc, MID_DMA_WRTX, MID_DRQ_A2REG(sc->dtq_chip)); 1364 /* ensure zero queue */ 1365 sc->dtq_us = sc->dtq_chip; 1366 1367 sc->hwslistp = MID_SL_REG2A(EN_READ(sc, MID_SERV_WRITE)); 1368 sc->swsl_size = sc->swsl_head = sc->swsl_tail = 0; 1369 1370#ifdef EN_DEBUG 1371 printf("%s: drq free/chip: %d/0x%x, dtq free/chip: %d/0x%x, hwslist: 0x%x\n", 1372 sc->sc_dev.dv_xname, sc->drq_free, sc->drq_chip, 1373 sc->dtq_free, sc->dtq_chip, sc->hwslistp); 1374#endif 1375 1376 for (slot = 0 ; slot < EN_NTX ; slot++) { 1377 sc->txslot[slot].bfree = EN_TXSZ * 1024; 1378 EN_WRITE(sc, MIDX_READPTR(slot), 0); 1379 EN_WRITE(sc, MIDX_DESCSTART(slot), 0); 1380 loc = sc->txslot[slot].cur = sc->txslot[slot].start; 1381 loc = loc - MID_RAMOFF; 1382 loc = (loc & ~((EN_TXSZ*1024) - 1)) >> 2; /* mask, cvt to words */ 1383 loc = loc >> MIDV_LOCTOPSHFT; /* top 11 bits */ 1384 EN_WRITE(sc, MIDX_PLACE(slot), MIDX_MKPLACE(en_k2sz(EN_TXSZ), loc)); 1385#ifdef EN_DEBUG 1386 printf("%s: tx%d: place 0x%x\n", sc->sc_dev.dv_xname, slot, 1387 EN_READ(sc, MIDX_PLACE(slot))); 1388#endif 1389 } 1390 1391 /* 1392 * enable! 1393 */ 1394 1395 EN_WRITE(sc, MID_INTENA, MID_INT_TX|MID_INT_DMA_OVR|MID_INT_IDENT| 1396 MID_INT_LERR|MID_INT_DMA_ERR|MID_INT_DMA_RX|MID_INT_DMA_TX| 1397 MID_INT_SERVICE| /* >>> MID_INT_SUNI| XXXCDC<<< */ MID_INT_STATS); 1398 EN_WRITE(sc, MID_MAST_CSR, MID_SETIPL(sc->ipl)|MID_MCSR_ENDMA| 1399 MID_MCSR_ENTX|MID_MCSR_ENRX); 1400 1401} 1402 1403 1404/* 1405 * en_loadvc: load a vc tab entry from a slot 1406 */ 1407 1408STATIC void en_loadvc(sc, vc) 1409 1410struct en_softc *sc; 1411int vc; 1412 1413{ 1414 int slot; 1415 u_int32_t reg = EN_READ(sc, MID_VC(vc)); 1416 1417 reg = MIDV_SETMODE(reg, MIDV_TRASH); 1418 EN_WRITE(sc, MID_VC(vc), reg); 1419 DELAY(27); 1420 1421 if ((slot = sc->rxvc2slot[vc]) == RX_NONE) 1422 return; 1423 1424 /* no need to set CRC */ 1425 EN_WRITE(sc, MID_DST_RP(vc), 0); /* read pointer = 0, desc. start = 0 */ 1426 EN_WRITE(sc, MID_WP_ST_CNT(vc), 0); /* write pointer = 0 */ 1427 EN_WRITE(sc, MID_VC(vc), sc->rxslot[slot].mode); /* set mode, size, loc */ 1428 sc->rxslot[slot].cur = sc->rxslot[slot].start; 1429 1430#ifdef EN_DEBUG 1431 printf("%s: rx%d: assigned to VCI %d\n", sc->sc_dev.dv_xname, slot, vc); 1432#endif 1433} 1434 1435 1436/* 1437 * en_start: start transmitting the next packet that needs to go out 1438 * if there is one. note that atm_output() has already splimp()'d us. 1439 */ 1440 1441STATIC void en_start(ifp) 1442 1443struct ifnet *ifp; 1444 1445{ 1446#ifdef MISSING_IF_SOFTC 1447 struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit]; 1448#else 1449 struct en_softc *sc = (struct en_softc *) ifp->if_softc; 1450#endif 1451 struct ifqueue *ifq = &ifp->if_snd; /* if INPUT QUEUE */ 1452 struct mbuf *m, *lastm, *prev; 1453 struct atm_pseudohdr *ap, *new_ap; 1454 int txchan, mlen, got, need, toadd, cellcnt, first; 1455 u_int32_t atm_vpi, atm_vci, atm_flags, *dat, aal; 1456 u_int8_t *cp; 1457 1458 if ((ifp->if_flags & IFF_RUNNING) == 0) 1459 return; 1460 1461 /* 1462 * remove everything from interface queue since we handle all queueing 1463 * locally ... 1464 */ 1465 1466 while (1) { 1467 1468 IF_DEQUEUE(ifq, m); 1469 if (m == NULL) 1470 return; /* EMPTY: >>> exit here <<< */ 1471 1472 /* 1473 * calculate size of packet (in bytes) 1474 * also, if we are not doing transmit DMA we eliminate all stupid 1475 * (non-word) alignments here using en_mfix(). calls to en_mfix() 1476 * seem to be due to tcp retransmits for the most part. 1477 * 1478 * after this loop mlen total length of mbuf chain (including atm_ph), 1479 * and lastm is a pointer to the last mbuf on the chain. 1480 */ 1481 1482 lastm = m; 1483 mlen = 0; 1484 prev = NULL; 1485 while (1) { 1486#ifdef EN_FIXMBUF 1487 /* if eni, always fix misaligned mbuf */ 1488 if (!sc->is_adaptec || EN_NOTXDMA || !en_dma) { 1489#else 1490 if (EN_NOTXDMA || !en_dma) { /* no DMA? */ 1491#endif 1492 if ( (mtod(lastm, unsigned long) % sizeof(u_int32_t)) != 0 || 1493 ((lastm->m_len % sizeof(u_int32_t)) != 0 && lastm->m_next)) { 1494 first = (lastm == m); 1495 if (en_mfix(sc, &lastm, prev) == 0) { /* failed? */ 1496 m_freem(m); 1497 m = NULL; 1498 break; 1499 } 1500 if (first) 1501 m = lastm; /* update */ 1502 } 1503 prev = lastm; 1504 } 1505 mlen += lastm->m_len; 1506 if (lastm->m_next == NULL) 1507 break; 1508 lastm = lastm->m_next; 1509 } 1510 1511 if (m == NULL) /* happens only if mfix fails */ 1512 continue; 1513 1514 ap = mtod(m, struct atm_pseudohdr *); 1515 1516 atm_vpi = ATM_PH_VPI(ap); 1517 atm_vci = ATM_PH_VCI(ap); 1518 atm_flags = ATM_PH_FLAGS(ap) & ~(EN_OBHDR|EN_OBTRL); 1519 aal = ((atm_flags & ATM_PH_AAL5) != 0) 1520 ? MID_TBD_AAL5 : MID_TBD_NOAAL5; 1521 1522 /* 1523 * check that vpi/vci is one we can use 1524 */ 1525 1526 if (atm_vpi || atm_vci > MID_N_VC) { 1527 printf("%s: output vpi=%d, vci=%d out of card range, dropping...\n", 1528 sc->sc_dev.dv_xname, atm_vpi, atm_vci); 1529 m_freem(m); 1530 continue; 1531 } 1532 1533 /* 1534 * computing how much padding we need on the end of the mbuf, then 1535 * see if we can put the TBD at the front of the mbuf where the 1536 * link header goes (well behaved protocols will reserve room for us). 1537 * last, check if room for PDU tail. 1538 * 1539 * got = number of bytes of data we have 1540 * cellcnt = number of cells in this mbuf 1541 * need = number of bytes of data + padding we need (excludes TBD) 1542 * toadd = number of bytes of data we need to add to end of mbuf, 1543 * [including AAL5 PDU, if AAL5] 1544 */ 1545 1546 got = mlen - sizeof(struct atm_pseudohdr *); 1547 toadd = (aal == MID_TBD_AAL5) ? MID_PDU_SIZE : 0; /* PDU */ 1548 cellcnt = (got + toadd + (MID_ATMDATASZ - 1)) / MID_ATMDATASZ; 1549 need = cellcnt * MID_ATMDATASZ; 1550 toadd = need - got; /* recompute, including zero padding */ 1551 1552#ifdef EN_DEBUG 1553 printf("%s: txvci%d: mlen=%d, got=%d, need=%d, toadd=%d, cell#=%d\n", 1554 sc->sc_dev.dv_xname, atm_vci, mlen, got, need, toadd, cellcnt); 1555 printf(" leading_space=%d, trailing_space=%d\n", 1556 M_LEADINGSPACE(m), M_TRAILINGSPACE(lastm)); 1557#endif 1558 1559#ifdef EN_MBUF_OPT 1560 1561 /* 1562 * note: external storage (M_EXT) can be shared between mbufs 1563 * to avoid copying (see m_copym()). this means that the same 1564 * data buffer could be shared by several mbufs, and thus it isn't 1565 * a good idea to try and write TBDs or PDUs to M_EXT data areas. 1566 */ 1567 1568 if (M_LEADINGSPACE(m) >= MID_TBD_SIZE && (m->m_flags & M_EXT) == 0) { 1569 m->m_data -= MID_TBD_SIZE; 1570 m->m_len += MID_TBD_SIZE; 1571 mlen += MID_TBD_SIZE; 1572 new_ap = mtod(m, struct atm_pseudohdr *); 1573 *new_ap = *ap; /* move it back */ 1574 ap = new_ap; 1575 dat = ((u_int32_t *) ap) + 1; 1576 /* make sure the TBD is in proper byte order */ 1577 *dat++ = htonl(MID_TBD_MK1(aal, sc->txspeed[atm_vci], cellcnt)); 1578 *dat = htonl(MID_TBD_MK2(atm_vci, 0, 0)); 1579 atm_flags |= EN_OBHDR; 1580 } 1581 1582 if (toadd && (lastm->m_flags & M_EXT) == 0 && 1583 M_TRAILINGSPACE(lastm) >= toadd) { 1584 cp = mtod(lastm, u_int8_t *) + lastm->m_len; 1585 lastm->m_len += toadd; 1586 mlen += toadd; 1587 if (aal == MID_TBD_AAL5) { 1588 bzero(cp, toadd - MID_PDU_SIZE); 1589 dat = (u_int32_t *)(cp + toadd - MID_PDU_SIZE); 1590 /* make sure the PDU is in proper byte order */ 1591 *dat = htonl(MID_PDU_MK1(0, 0, got)); 1592 } else { 1593 bzero(cp, toadd); 1594 } 1595 atm_flags |= EN_OBTRL; 1596 } 1597 ATM_PH_FLAGS(ap) = atm_flags; /* update EN_OBHDR/EN_OBTRL bits */ 1598#endif /* EN_MBUF_OPT */ 1599 1600 /* 1601 * get assigned channel (will be zero unless txspeed[atm_vci] is set) 1602 */ 1603 1604 txchan = sc->txvc2slot[atm_vci]; 1605 1606 if (sc->txslot[txchan].mbsize > EN_TXHIWAT) { 1607 EN_COUNT(sc->txmbovr); 1608 m_freem(m); 1609#ifdef EN_DEBUG 1610 printf("%s: tx%d: buffer space shortage\n", sc->sc_dev.dv_xname, 1611 txchan); 1612#endif 1613 continue; 1614 } 1615 1616 sc->txslot[txchan].mbsize += mlen; 1617 1618#ifdef EN_DEBUG 1619 printf("%s: tx%d: VPI=%d, VCI=%d, FLAGS=0x%x, speed=0x%x\n", 1620 sc->sc_dev.dv_xname, txchan, atm_vpi, atm_vci, atm_flags, 1621 sc->txspeed[atm_vci]); 1622 printf(" adjusted mlen=%d, mbsize=%d\n", mlen, 1623 sc->txslot[txchan].mbsize); 1624#endif 1625 1626 IF_ENQUEUE(&sc->txslot[txchan].q, m); 1627 en_txdma(sc, txchan); 1628 1629 } 1630 /*NOTREACHED*/ 1631} 1632 1633 1634/* 1635 * en_mfix: fix a stupid mbuf 1636 */ 1637STATIC int en_makeexclusive(struct en_softc *, struct mbuf **, struct mbuf *); 1638 1639STATIC int en_makeexclusive(sc, mm, prev) 1640 struct en_softc *sc; 1641 struct mbuf **mm, *prev; 1642{ 1643 struct mbuf *m, *new; 1644 1645 m = *mm; 1646 1647 if (m->m_flags & M_EXT) { 1648 if (m->m_ext.ext_free) { 1649 /* external buffer isn't an ordinary mbuf cluster! */ 1650 printf("%s: mfix: special buffer! can't make a copy!\n", 1651 sc->sc_dev.dv_xname); 1652 return (0); 1653 } 1654 1655 if (mclrefcnt[mtocl(m->m_ext.ext_buf)] > 1) { 1656 /* make a real copy of the M_EXT mbuf since it is shared */ 1657 MGET(new, M_DONTWAIT, MT_DATA); 1658 if (!new) { 1659 EN_COUNT(sc->mfixfail); 1660 return(0); 1661 } 1662 if (m->m_flags & M_PKTHDR) 1663 M_COPY_PKTHDR(new, m); 1664 MCLGET(new, M_DONTWAIT); 1665 if ((new->m_flags & M_EXT) == 0) { 1666 m_free(new); 1667 EN_COUNT(sc->mfixfail); 1668 return(0); 1669 } 1670 bcopy(m->m_data, new->m_data, m->m_len); 1671 new->m_len = m->m_len; 1672 new->m_next = m->m_next; 1673 if (prev) 1674 prev->m_next = new; 1675 m_free(m); 1676 *mm = new; 1677 } 1678 else { 1679 /* the buffer is not shared, align the data offset using 1680 this buffer. */ 1681 u_char *d = mtod(m, u_char *); 1682 int off = ((u_long)d) % sizeof(u_int32_t); 1683 1684 if (off > 0) { 1685 bcopy(d, d - off, m->m_len); 1686 m->m_data = (caddr_t)d - off; 1687 } 1688 } 1689 } 1690 return (1); 1691} 1692 1693STATIC int en_mfix(sc, mm, prev) 1694 1695struct en_softc *sc; 1696struct mbuf **mm, *prev; 1697 1698{ 1699 struct mbuf *m; 1700 u_char *d, *cp; 1701 int off; 1702 struct mbuf *nxt; 1703 1704 m = *mm; 1705 1706 EN_COUNT(sc->mfix); /* count # of calls */ 1707#ifdef EN_DEBUG 1708 printf("%s: mfix mbuf m_data=0x%x, m_len=%d\n", sc->sc_dev.dv_xname, 1709 m->m_data, m->m_len); 1710#endif 1711 1712 d = mtod(m, u_char *); 1713 off = ((unsigned long) d) % sizeof(u_int32_t); 1714 1715 if (off) { 1716 if ((m->m_flags & M_EXT) == 0) { 1717 bcopy(d, d - off, m->m_len); /* ALIGN! (with costly data copy...) */ 1718 d -= off; 1719 m->m_data = (caddr_t)d; 1720 } else { 1721 /* can't write to an M_EXT mbuf since it may be shared */ 1722 if (en_makeexclusive(sc, &m, prev) == 0) 1723 return (0); 1724 *mm = m; /* note: 'd' now invalid */ 1725 } 1726 } 1727 1728 off = m->m_len % sizeof(u_int32_t); 1729 if (off == 0) 1730 return(1); 1731 1732 if (m->m_flags & M_EXT) { 1733 /* can't write to an M_EXT mbuf since it may be shared */ 1734 if (en_makeexclusive(sc, &m, prev) == 0) 1735 return (0); 1736 *mm = m; /* note: 'd' now invalid */ 1737 } 1738 1739 d = mtod(m, u_char *) + m->m_len; 1740 off = sizeof(u_int32_t) - off; 1741 1742 nxt = m->m_next; 1743 while (off--) { 1744 if (nxt != NULL && nxt->m_len == 0) { 1745 /* remove an empty mbuf. this avoids odd byte padding to an empty 1746 last mbuf. */ 1747 m->m_next = nxt = m_free(nxt); 1748 } 1749 if (nxt == NULL) { /* out of data, zero fill */ 1750 *d++ = 0; 1751 continue; /* next "off" */ 1752 } 1753 cp = mtod(nxt, u_char *); 1754 *d++ = *cp++; 1755 m->m_len++; 1756 nxt->m_len--; 1757 nxt->m_data = (caddr_t)cp; 1758 } 1759 if (nxt != NULL && nxt->m_len == 0) 1760 m->m_next = m_free(nxt); 1761 return(1); 1762} 1763 1764 1765/* 1766 * en_txdma: start trasmit DMA, if possible 1767 */ 1768 1769STATIC void en_txdma(sc, chan) 1770 1771struct en_softc *sc; 1772int chan; 1773 1774{ 1775 struct mbuf *tmp; 1776 struct atm_pseudohdr *ap; 1777 struct en_launch launch; 1778 int datalen = 0, dtqneed, len, ncells; 1779 u_int8_t *cp; 1780 1781#ifdef EN_DEBUG 1782 printf("%s: tx%d: starting...\n", sc->sc_dev.dv_xname, chan); 1783#endif 1784 1785 /* 1786 * note: now that txlaunch handles non-word aligned/sized requests 1787 * the only time you can safely set launch.nodma is if you've en_mfix()'d 1788 * the mbuf chain. this happens only if EN_NOTXDMA || !en_dma. 1789 */ 1790 1791 launch.nodma = (EN_NOTXDMA || !en_dma); 1792 1793again: 1794 1795 /* 1796 * get an mbuf waiting for DMA 1797 */ 1798 1799 launch.t = sc->txslot[chan].q.ifq_head; /* peek at head of queue */ 1800 1801 if (launch.t == NULL) { 1802#ifdef EN_DEBUG 1803 printf("%s: tx%d: ...done!\n", sc->sc_dev.dv_xname, chan); 1804#endif 1805 return; /* >>> exit here if no data waiting for DMA <<< */ 1806 } 1807 1808 /* 1809 * get flags, vci 1810 * 1811 * note: launch.need = # bytes we need to get on the card 1812 * dtqneed = # of DTQs we need for this packet 1813 * launch.mlen = # of bytes in in mbuf chain (<= launch.need) 1814 */ 1815 1816 ap = mtod(launch.t, struct atm_pseudohdr *); 1817 launch.atm_vci = ATM_PH_VCI(ap); 1818 launch.atm_flags = ATM_PH_FLAGS(ap); 1819 launch.aal = ((launch.atm_flags & ATM_PH_AAL5) != 0) ? 1820 MID_TBD_AAL5 : MID_TBD_NOAAL5; 1821 1822 /* 1823 * XXX: have to recompute the length again, even though we already did 1824 * it in en_start(). might as well compute dtqneed here as well, so 1825 * this isn't that bad. 1826 */ 1827 1828 if ((launch.atm_flags & EN_OBHDR) == 0) { 1829 dtqneed = 1; /* header still needs to be added */ 1830 launch.need = MID_TBD_SIZE; /* not includeded with mbuf */ 1831 } else { 1832 dtqneed = 0; /* header on-board, dma with mbuf */ 1833 launch.need = 0; 1834 } 1835 1836 launch.mlen = 0; 1837 for (tmp = launch.t ; tmp != NULL ; tmp = tmp->m_next) { 1838 len = tmp->m_len; 1839 launch.mlen += len; 1840 cp = mtod(tmp, u_int8_t *); 1841 if (tmp == launch.t) { 1842 len -= sizeof(struct atm_pseudohdr); /* don't count this! */ 1843 cp += sizeof(struct atm_pseudohdr); 1844 } 1845 launch.need += len; 1846 if (len == 0) 1847 continue; /* atm_pseudohdr alone in first mbuf */ 1848 1849 dtqneed += en_dqneed(sc, (caddr_t) cp, len, 1); 1850 } 1851 1852 if ((launch.need % sizeof(u_int32_t)) != 0) 1853 dtqneed++; /* need DTQ to FLUSH internal buffer */ 1854 1855 if ((launch.atm_flags & EN_OBTRL) == 0) { 1856 if (launch.aal == MID_TBD_AAL5) { 1857 datalen = launch.need - MID_TBD_SIZE; 1858 launch.need += MID_PDU_SIZE; /* AAL5: need PDU tail */ 1859 } 1860 dtqneed++; /* need to work on the end a bit */ 1861 } 1862 1863 /* 1864 * finish calculation of launch.need (need to figure out how much padding 1865 * we will need). launch.need includes MID_TBD_SIZE, but we need to 1866 * remove that to so we can round off properly. we have to add 1867 * MID_TBD_SIZE back in after calculating ncells. 1868 */ 1869 1870 launch.need = roundup(launch.need - MID_TBD_SIZE, MID_ATMDATASZ); 1871 ncells = launch.need / MID_ATMDATASZ; 1872 launch.need += MID_TBD_SIZE; 1873 1874 if (launch.need > EN_TXSZ * 1024) { 1875 printf("%s: tx%d: packet larger than xmit buffer (%d > %d)\n", 1876 sc->sc_dev.dv_xname, chan, launch.need, EN_TXSZ * 1024); 1877 goto dequeue_drop; 1878 } 1879 1880 if (launch.need > sc->txslot[chan].bfree) { 1881 EN_COUNT(sc->txoutspace); 1882#ifdef EN_DEBUG 1883 printf("%s: tx%d: out of transmit space\n", sc->sc_dev.dv_xname, chan); 1884#endif 1885 return; /* >>> exit here if out of obmem buffer space <<< */ 1886 } 1887 1888 /* 1889 * ensure we have enough dtqs to go, if not, wait for more. 1890 */ 1891 1892 if (launch.nodma) { 1893 dtqneed = 1; 1894 } 1895 if (dtqneed > sc->dtq_free) { 1896 sc->need_dtqs = 1; 1897 EN_COUNT(sc->txdtqout); 1898#ifdef EN_DEBUG 1899 printf("%s: tx%d: out of transmit DTQs\n", sc->sc_dev.dv_xname, chan); 1900#endif 1901 return; /* >>> exit here if out of dtqs <<< */ 1902 } 1903 1904 /* 1905 * it is a go, commit! dequeue mbuf start working on the xfer. 1906 */ 1907 1908 IF_DEQUEUE(&sc->txslot[chan].q, tmp); 1909#ifdef EN_DIAG 1910 if (launch.t != tmp) 1911 panic("en dequeue"); 1912#endif /* EN_DIAG */ 1913 1914 /* 1915 * launch! 1916 */ 1917 1918 EN_COUNT(sc->launch); 1919 sc->enif.if_opackets++; 1920 if ((launch.atm_flags & EN_OBHDR) == 0) { 1921 EN_COUNT(sc->lheader); 1922 /* store tbd1/tbd2 in host byte order */ 1923 launch.tbd1 = MID_TBD_MK1(launch.aal, sc->txspeed[launch.atm_vci], ncells); 1924 launch.tbd2 = MID_TBD_MK2(launch.atm_vci, 0, 0); 1925 } 1926 if ((launch.atm_flags & EN_OBTRL) == 0 && launch.aal == MID_TBD_AAL5) { 1927 EN_COUNT(sc->ltail); 1928 launch.pdu1 = MID_PDU_MK1(0, 0, datalen); /* host byte order */ 1929 } 1930 1931 en_txlaunch(sc, chan, &launch); 1932 1933 /* 1934 * do some housekeeping and get the next packet 1935 */ 1936 1937 sc->txslot[chan].bfree -= launch.need; 1938 IF_ENQUEUE(&sc->txslot[chan].indma, launch.t); 1939 goto again; 1940 1941 /* 1942 * END of txdma loop! 1943 */ 1944 1945 /* 1946 * error handles 1947 */ 1948 1949dequeue_drop: 1950 IF_DEQUEUE(&sc->txslot[chan].q, tmp); 1951 if (launch.t != tmp) 1952 panic("en dequeue drop"); 1953 m_freem(launch.t); 1954 sc->txslot[chan].mbsize -= launch.mlen; 1955 goto again; 1956} 1957 1958 1959/* 1960 * en_txlaunch: launch an mbuf into the dma pool! 1961 */ 1962 1963STATIC void en_txlaunch(sc, chan, l) 1964 1965struct en_softc *sc; 1966int chan; 1967struct en_launch *l; 1968 1969{ 1970 struct mbuf *tmp; 1971 u_int32_t cur = sc->txslot[chan].cur, 1972 start = sc->txslot[chan].start, 1973 stop = sc->txslot[chan].stop, 1974 dma, *data, *datastop, count, bcode; 1975 int pad, addtail, need, len, needalign, cnt, end, mx; 1976 1977 1978 /* 1979 * vars: 1980 * need = # bytes card still needs (decr. to zero) 1981 * len = # of bytes left in current mbuf 1982 * cur = our current pointer 1983 * dma = last place we programmed into the DMA 1984 * data = pointer into data area of mbuf that needs to go next 1985 * cnt = # of bytes to transfer in this DTQ 1986 * bcode/count = DMA burst code, and chip's version of cnt 1987 * 1988 * a single buffer can require up to 5 DTQs depending on its size 1989 * and alignment requirements. the 5 possible requests are: 1990 * [1] 1, 2, or 3 byte DMA to align src data pointer to word boundary 1991 * [2] alburst DMA to align src data pointer to bestburstlen 1992 * [3] 1 or more bestburstlen DMAs 1993 * [4] clean up burst (to last word boundary) 1994 * [5] 1, 2, or 3 byte final clean up DMA 1995 */ 1996 1997 need = l->need; 1998 dma = cur; 1999 addtail = (l->atm_flags & EN_OBTRL) == 0; /* add a tail? */ 2000 2001#ifdef EN_DIAG 2002 if ((need - MID_TBD_SIZE) % MID_ATMDATASZ) 2003 printf("%s: tx%d: bogus trasmit needs (%d)\n", sc->sc_dev.dv_xname, chan, 2004 need); 2005#endif 2006#ifdef EN_DEBUG 2007 printf("%s: tx%d: launch mbuf %p! cur=0x%x[%d], need=%d, addtail=%d\n", 2008 sc->sc_dev.dv_xname, chan, l->t, cur, (cur-start)/4, need, addtail); 2009 count = EN_READ(sc, MIDX_PLACE(chan)); 2010 printf(" HW: base_address=0x%x, size=%d, read=%d, descstart=%d\n", 2011 MIDX_BASE(count), MIDX_SZ(count), EN_READ(sc, MIDX_READPTR(chan)), 2012 EN_READ(sc, MIDX_DESCSTART(chan))); 2013#endif 2014 2015 /* 2016 * do we need to insert the TBD by hand? 2017 * note that tbd1/tbd2/pdu1 are in host byte order. 2018 */ 2019 2020 if ((l->atm_flags & EN_OBHDR) == 0) { 2021#ifdef EN_DEBUG 2022 printf("%s: tx%d: insert header 0x%x 0x%x\n", sc->sc_dev.dv_xname, 2023 chan, l->tbd1, l->tbd2); 2024#endif 2025 EN_WRITE(sc, cur, l->tbd1); 2026 EN_WRAPADD(start, stop, cur, 4); 2027 EN_WRITE(sc, cur, l->tbd2); 2028 EN_WRAPADD(start, stop, cur, 4); 2029 need -= 8; 2030 } 2031 2032 /* 2033 * now do the mbufs... 2034 */ 2035 2036 for (tmp = l->t ; tmp != NULL ; tmp = tmp->m_next) { 2037 2038 /* get pointer to data and length */ 2039 data = mtod(tmp, u_int32_t *); 2040 len = tmp->m_len; 2041 if (tmp == l->t) { 2042 data += sizeof(struct atm_pseudohdr)/sizeof(u_int32_t); 2043 len -= sizeof(struct atm_pseudohdr); 2044 } 2045 2046 /* now, determine if we should copy it */ 2047 if (l->nodma || (len < EN_MINDMA && 2048 (len % 4) == 0 && ((unsigned long) data % 4) == 0 && (cur % 4) == 0)) { 2049 2050 /* 2051 * roundup len: the only time this will change the value of len 2052 * is when l->nodma is true, tmp is the last mbuf, and there is 2053 * a non-word number of bytes to transmit. in this case it is 2054 * safe to round up because we've en_mfix'd the mbuf (so the first 2055 * byte is word aligned there must be enough free bytes at the end 2056 * to round off to the next word boundary)... 2057 */ 2058 len = roundup(len, sizeof(u_int32_t)); 2059 datastop = data + (len / sizeof(u_int32_t)); 2060 /* copy loop: preserve byte order!!! use WRITEDAT */ 2061 while (data != datastop) { 2062 EN_WRITEDAT(sc, cur, *data); 2063 data++; 2064 EN_WRAPADD(start, stop, cur, 4); 2065 } 2066 need -= len; 2067#ifdef EN_DEBUG 2068 printf("%s: tx%d: copied %d bytes (%d left, cur now 0x%x)\n", 2069 sc->sc_dev.dv_xname, chan, len, need, cur); 2070#endif 2071 continue; /* continue on to next mbuf */ 2072 } 2073 2074 /* going to do DMA, first make sure the dtq is in sync. */ 2075 if (dma != cur) { 2076 EN_DTQADD(sc, WORD_IDX(start,cur), chan, MIDDMA_JK, 0, 0, 0); 2077#ifdef EN_DEBUG 2078 printf("%s: tx%d: dtq_sync: advance pointer to %d\n", 2079 sc->sc_dev.dv_xname, chan, cur); 2080#endif 2081 } 2082 2083 /* 2084 * if this is the last buffer, and it looks like we are going to need to 2085 * flush the internal buffer, can we extend the length of this mbuf to 2086 * avoid the FLUSH? 2087 */ 2088 2089 if (tmp->m_next == NULL) { 2090 cnt = (need - len) % sizeof(u_int32_t); 2091 if (cnt && M_TRAILINGSPACE(tmp) >= cnt) 2092 len += cnt; /* pad for FLUSH */ 2093 } 2094 2095#if !defined(MIDWAY_ENIONLY) 2096 2097 /* 2098 * the adaptec DMA engine is smart and handles everything for us. 2099 */ 2100 2101 if (sc->is_adaptec) { 2102 /* need to DMA "len" bytes out to card */ 2103 need -= len; 2104 EN_WRAPADD(start, stop, cur, len); 2105#ifdef EN_DEBUG 2106 printf("%s: tx%d: adp_dma %d bytes (%d left, cur now 0x%x)\n", 2107 sc->sc_dev.dv_xname, chan, len, need, cur); 2108#endif 2109 end = (need == 0) ? MID_DMA_END : 0; 2110 EN_DTQADD(sc, len, chan, 0, vtophys(data), l->mlen, end); 2111 if (end) 2112 goto done; 2113 dma = cur; /* update dma pointer */ 2114 continue; 2115 } 2116#endif /* !MIDWAY_ENIONLY */ 2117 2118#if !defined(MIDWAY_ADPONLY) 2119 2120 /* 2121 * the ENI DMA engine is not so smart and need more help from us 2122 */ 2123 2124 /* do we need to do a DMA op to align to word boundary? */ 2125 needalign = (unsigned long) data % sizeof(u_int32_t); 2126 if (needalign) { 2127 EN_COUNT(sc->headbyte); 2128 cnt = sizeof(u_int32_t) - needalign; 2129 if (cnt == 2 && len >= cnt) { 2130 count = 1; 2131 bcode = MIDDMA_2BYTE; 2132 } else { 2133 cnt = min(cnt, len); /* prevent overflow */ 2134 count = cnt; 2135 bcode = MIDDMA_BYTE; 2136 } 2137 need -= cnt; 2138 EN_WRAPADD(start, stop, cur, cnt); 2139#ifdef EN_DEBUG 2140 printf("%s: tx%d: small al_dma %d bytes (%d left, cur now 0x%x)\n", 2141 sc->sc_dev.dv_xname, chan, cnt, need, cur); 2142#endif 2143 len -= cnt; 2144 end = (need == 0) ? MID_DMA_END : 0; 2145 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2146 if (end) 2147 goto done; 2148 data = (u_int32_t *) ((u_char *)data + cnt); 2149 } 2150 2151 /* do we need to do a DMA op to align? */ 2152 if (sc->alburst && 2153 (needalign = (((unsigned long) data) & sc->bestburstmask)) != 0 2154 && len >= sizeof(u_int32_t)) { 2155 cnt = sc->bestburstlen - needalign; 2156 mx = len & ~(sizeof(u_int32_t)-1); /* don't go past end */ 2157 if (cnt > mx) { 2158 cnt = mx; 2159 count = cnt / sizeof(u_int32_t); 2160 bcode = MIDDMA_WORD; 2161 } else { 2162 count = cnt / sizeof(u_int32_t); 2163 bcode = en_dmaplan[count].bcode; 2164 count = cnt >> en_dmaplan[count].divshift; 2165 } 2166 need -= cnt; 2167 EN_WRAPADD(start, stop, cur, cnt); 2168#ifdef EN_DEBUG 2169 printf("%s: tx%d: al_dma %d bytes (%d left, cur now 0x%x)\n", 2170 sc->sc_dev.dv_xname, chan, cnt, need, cur); 2171#endif 2172 len -= cnt; 2173 end = (need == 0) ? MID_DMA_END : 0; 2174 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2175 if (end) 2176 goto done; 2177 data = (u_int32_t *) ((u_char *)data + cnt); 2178 } 2179 2180 /* do we need to do a max-sized burst? */ 2181 if (len >= sc->bestburstlen) { 2182 count = len >> sc->bestburstshift; 2183 cnt = count << sc->bestburstshift; 2184 bcode = sc->bestburstcode; 2185 need -= cnt; 2186 EN_WRAPADD(start, stop, cur, cnt); 2187#ifdef EN_DEBUG 2188 printf("%s: tx%d: best_dma %d bytes (%d left, cur now 0x%x)\n", 2189 sc->sc_dev.dv_xname, chan, cnt, need, cur); 2190#endif 2191 len -= cnt; 2192 end = (need == 0) ? MID_DMA_END : 0; 2193 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2194 if (end) 2195 goto done; 2196 data = (u_int32_t *) ((u_char *)data + cnt); 2197 } 2198 2199 /* do we need to do a cleanup burst? */ 2200 cnt = len & ~(sizeof(u_int32_t)-1); 2201 if (cnt) { 2202 count = cnt / sizeof(u_int32_t); 2203 bcode = en_dmaplan[count].bcode; 2204 count = cnt >> en_dmaplan[count].divshift; 2205 need -= cnt; 2206 EN_WRAPADD(start, stop, cur, cnt); 2207#ifdef EN_DEBUG 2208 printf("%s: tx%d: cleanup_dma %d bytes (%d left, cur now 0x%x)\n", 2209 sc->sc_dev.dv_xname, chan, cnt, need, cur); 2210#endif 2211 len -= cnt; 2212 end = (need == 0) ? MID_DMA_END : 0; 2213 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2214 if (end) 2215 goto done; 2216 data = (u_int32_t *) ((u_char *)data + cnt); 2217 } 2218 2219 /* any word fragments left? */ 2220 if (len) { 2221 EN_COUNT(sc->tailbyte); 2222 if (len == 2) { 2223 count = 1; 2224 bcode = MIDDMA_2BYTE; /* use 2byte mode */ 2225 } else { 2226 count = len; 2227 bcode = MIDDMA_BYTE; /* use 1 byte mode */ 2228 } 2229 need -= len; 2230 EN_WRAPADD(start, stop, cur, len); 2231#ifdef EN_DEBUG 2232 printf("%s: tx%d: byte cleanup_dma %d bytes (%d left, cur now 0x%x)\n", 2233 sc->sc_dev.dv_xname, chan, len, need, cur); 2234#endif 2235 end = (need == 0) ? MID_DMA_END : 0; 2236 EN_DTQADD(sc, count, chan, bcode, vtophys(data), l->mlen, end); 2237 if (end) 2238 goto done; 2239 } 2240 2241 dma = cur; /* update dma pointer */ 2242#endif /* !MIDWAY_ADPONLY */ 2243 2244 } /* next mbuf, please */ 2245 2246 /* 2247 * all mbuf data has been copied out to the obmem (or set up to be DMAd). 2248 * if the trailer or padding needs to be put in, do it now. 2249 * 2250 * NOTE: experimental results reveal the following fact: 2251 * if you DMA "X" bytes to the card, where X is not a multiple of 4, 2252 * then the card will internally buffer the last (X % 4) bytes (in 2253 * hopes of getting (4 - (X % 4)) more bytes to make a complete word). 2254 * it is imporant to make sure we don't leave any important data in 2255 * this internal buffer because it is discarded on the last (end) DTQ. 2256 * one way to do this is to DMA in (4 - (X % 4)) more bytes to flush 2257 * the darn thing out. 2258 */ 2259 2260 if (addtail) { 2261 2262 pad = need % sizeof(u_int32_t); 2263 if (pad) { 2264 /* 2265 * FLUSH internal data buffer. pad out with random data from the front 2266 * of the mbuf chain... 2267 */ 2268 bcode = (sc->is_adaptec) ? 0 : MIDDMA_BYTE; 2269 EN_COUNT(sc->tailflush); 2270 EN_WRAPADD(start, stop, cur, pad); 2271 EN_DTQADD(sc, pad, chan, bcode, vtophys(l->t->m_data), 0, 0); 2272 need -= pad; 2273#ifdef EN_DEBUG 2274 printf("%s: tx%d: pad/FLUSH dma %d bytes (%d left, cur now 0x%x)\n", 2275 sc->sc_dev.dv_xname, chan, pad, need, cur); 2276#endif 2277 } 2278 2279 /* copy data */ 2280 pad = need / sizeof(u_int32_t); /* round *down* */ 2281 if (l->aal == MID_TBD_AAL5) 2282 pad -= 2; 2283#ifdef EN_DEBUG 2284 printf("%s: tx%d: padding %d bytes (cur now 0x%x)\n", 2285 sc->sc_dev.dv_xname, chan, pad * sizeof(u_int32_t), cur); 2286#endif 2287 while (pad--) { 2288 EN_WRITEDAT(sc, cur, 0); /* no byte order issues with zero */ 2289 EN_WRAPADD(start, stop, cur, 4); 2290 } 2291 if (l->aal == MID_TBD_AAL5) { 2292 EN_WRITE(sc, cur, l->pdu1); /* in host byte order */ 2293 EN_WRAPADD(start, stop, cur, 8); 2294 } 2295 } 2296 2297 if (addtail || dma != cur) { 2298 /* write final descritor */ 2299 EN_DTQADD(sc, WORD_IDX(start,cur), chan, MIDDMA_JK, 0, 2300 l->mlen, MID_DMA_END); 2301 /* dma = cur; */ /* not necessary since we are done */ 2302 } 2303 2304done: 2305 /* update current pointer */ 2306 sc->txslot[chan].cur = cur; 2307#ifdef EN_DEBUG 2308 printf("%s: tx%d: DONE! cur now = 0x%x\n", 2309 sc->sc_dev.dv_xname, chan, cur); 2310#endif 2311 2312 return; 2313} 2314 2315 2316/* 2317 * interrupt handler 2318 */ 2319 2320EN_INTR_TYPE en_intr(arg) 2321 2322void *arg; 2323 2324{ 2325 struct en_softc *sc = (struct en_softc *) arg; 2326 struct mbuf *m; 2327 struct atm_pseudohdr ah; 2328 u_int32_t reg, kick, val, mask, chip, vci, slot, dtq, drq; 2329 int lcv, idx, need_softserv = 0; 2330 2331 reg = EN_READ(sc, MID_INTACK); 2332 2333 if ((reg & MID_INT_ANY) == 0) 2334 EN_INTR_RET(0); /* not us */ 2335 2336#ifdef EN_DEBUG 2337 printf("%s: interrupt=0x%b\n", sc->sc_dev.dv_xname, reg, MID_INTBITS); 2338#endif 2339 2340 /* 2341 * unexpected errors that need a reset 2342 */ 2343 2344 if ((reg & (MID_INT_IDENT|MID_INT_LERR|MID_INT_DMA_ERR|MID_INT_SUNI)) != 0) { 2345 printf("%s: unexpected interrupt=0x%b, resetting card\n", 2346 sc->sc_dev.dv_xname, reg, MID_INTBITS); 2347#ifdef EN_DEBUG 2348#ifdef DDB 2349 Debugger(); 2350#endif /* DDB */ 2351 sc->enif.if_flags &= ~IFF_RUNNING; /* FREEZE! */ 2352#else 2353 en_reset(sc); 2354 en_init(sc); 2355#endif 2356 EN_INTR_RET(1); /* for us */ 2357 } 2358 2359 /******************* 2360 * xmit interrupts * 2361 ******************/ 2362 2363 kick = 0; /* bitmask of channels to kick */ 2364 if (reg & MID_INT_TX) { /* TX done! */ 2365 2366 /* 2367 * check for tx complete, if detected then this means that some space 2368 * has come free on the card. we must account for it and arrange to 2369 * kick the channel to life (in case it is stalled waiting on the card). 2370 */ 2371 for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) { 2372 if (reg & MID_TXCHAN(lcv)) { 2373 kick = kick | mask; /* want to kick later */ 2374 val = EN_READ(sc, MIDX_READPTR(lcv)); /* current read pointer */ 2375 val = (val * sizeof(u_int32_t)) + sc->txslot[lcv].start; 2376 /* convert to offset */ 2377 if (val > sc->txslot[lcv].cur) 2378 sc->txslot[lcv].bfree = val - sc->txslot[lcv].cur; 2379 else 2380 sc->txslot[lcv].bfree = (val + (EN_TXSZ*1024)) - sc->txslot[lcv].cur; 2381#ifdef EN_DEBUG 2382 printf("%s: tx%d: trasmit done. %d bytes now free in buffer\n", 2383 sc->sc_dev.dv_xname, lcv, sc->txslot[lcv].bfree); 2384#endif 2385 } 2386 } 2387 } 2388 2389 if (reg & MID_INT_DMA_TX) { /* TX DMA done! */ 2390 2391 /* 2392 * check for TX DMA complete, if detected then this means that some DTQs 2393 * are now free. it also means some indma mbufs can be freed. 2394 * if we needed DTQs, kick all channels. 2395 */ 2396 val = EN_READ(sc, MID_DMA_RDTX); /* chip's current location */ 2397 idx = MID_DTQ_A2REG(sc->dtq_chip);/* where we last saw chip */ 2398 if (sc->need_dtqs) { 2399 kick = MID_NTX_CH - 1; /* assume power of 2, kick all! */ 2400 sc->need_dtqs = 0; /* recalculated in "kick" loop below */ 2401#ifdef EN_DEBUG 2402 printf("%s: cleared need DTQ condition\n", sc->sc_dev.dv_xname); 2403#endif 2404 } 2405 while (idx != val) { 2406 sc->dtq_free++; 2407 if ((dtq = sc->dtq[idx]) != 0) { 2408 sc->dtq[idx] = 0; /* don't forget to zero it out when done */ 2409 slot = EN_DQ_SLOT(dtq); 2410 IF_DEQUEUE(&sc->txslot[slot].indma, m); 2411 if (!m) panic("enintr: dtqsync"); 2412 sc->txslot[slot].mbsize -= EN_DQ_LEN(dtq); 2413#ifdef EN_DEBUG 2414 printf("%s: tx%d: free %d dma bytes, mbsize now %d\n", 2415 sc->sc_dev.dv_xname, slot, EN_DQ_LEN(dtq), 2416 sc->txslot[slot].mbsize); 2417#endif 2418 m_freem(m); 2419 } 2420 EN_WRAPADD(0, MID_DTQ_N, idx, 1); 2421 } 2422 sc->dtq_chip = MID_DTQ_REG2A(val); /* sync softc */ 2423 } 2424 2425 2426 /* 2427 * kick xmit channels as needed 2428 */ 2429 2430 if (kick) { 2431#ifdef EN_DEBUG 2432 printf("%s: tx kick mask = 0x%x\n", sc->sc_dev.dv_xname, kick); 2433#endif 2434 for (mask = 1, lcv = 0 ; lcv < EN_NTX ; lcv++, mask = mask * 2) { 2435 if ((kick & mask) && sc->txslot[lcv].q.ifq_head) { 2436 en_txdma(sc, lcv); /* kick it! */ 2437 } 2438 } /* for each slot */ 2439 } /* if kick */ 2440 2441 2442 /******************* 2443 * recv interrupts * 2444 ******************/ 2445 2446 /* 2447 * check for RX DMA complete, and pass the data "upstairs" 2448 */ 2449 2450 if (reg & MID_INT_DMA_RX) { 2451 val = EN_READ(sc, MID_DMA_RDRX); /* chip's current location */ 2452 idx = MID_DRQ_A2REG(sc->drq_chip);/* where we last saw chip */ 2453 while (idx != val) { 2454 sc->drq_free++; 2455 if ((drq = sc->drq[idx]) != 0) { 2456 sc->drq[idx] = 0; /* don't forget to zero it out when done */ 2457 slot = EN_DQ_SLOT(drq); 2458 if (EN_DQ_LEN(drq) == 0) { /* "JK" trash DMA? */ 2459 m = NULL; 2460 } else { 2461 IF_DEQUEUE(&sc->rxslot[slot].indma, m); 2462 if (!m) { 2463 printf("%s: lost mbuf in slot %d!\n", sc->sc_dev.dv_xname, slot); 2464 panic("enintr: drqsync"); 2465 } 2466 } 2467 /* do something with this mbuf */ 2468 if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) { /* drain? */ 2469 if (m) 2470 m_freem(m); 2471 vci = sc->rxslot[slot].atm_vci; 2472 if (sc->rxslot[slot].indma.ifq_head == NULL && 2473 sc->rxslot[slot].q.ifq_head == NULL && 2474 (EN_READ(sc, MID_VC(vci)) & MIDV_INSERVICE) == 0 && 2475 (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) { 2476 sc->rxslot[slot].oth_flags = ENOTHER_FREE; /* done drain */ 2477 sc->rxslot[slot].atm_vci = RX_NONE; 2478 sc->rxvc2slot[vci] = RX_NONE; 2479#ifdef EN_DEBUG 2480 printf("%s: rx%d: VCI %d now free\n", sc->sc_dev.dv_xname, 2481 slot, vci); 2482#endif 2483 } 2484 } else if (m != NULL) { 2485 ATM_PH_FLAGS(&ah) = sc->rxslot[slot].atm_flags; 2486 ATM_PH_VPI(&ah) = 0; 2487 ATM_PH_SETVCI(&ah, sc->rxslot[slot].atm_vci); 2488#ifdef EN_DEBUG 2489 printf("%s: rx%d: rxvci%d: atm_input, mbuf %p, len %d, hand %p\n", 2490 sc->sc_dev.dv_xname, slot, sc->rxslot[slot].atm_vci, m, 2491 EN_DQ_LEN(drq), sc->rxslot[slot].rxhand); 2492#endif 2493 sc->enif.if_ipackets++; 2494 2495 atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand); 2496 } 2497 2498 } 2499 EN_WRAPADD(0, MID_DRQ_N, idx, 1); 2500 } 2501 sc->drq_chip = MID_DRQ_REG2A(val); /* sync softc */ 2502 2503 if (sc->need_drqs) { /* true if we had a DRQ shortage */ 2504 need_softserv = 1; 2505 sc->need_drqs = 0; 2506#ifdef EN_DEBUG 2507 printf("%s: cleared need DRQ condition\n", sc->sc_dev.dv_xname); 2508#endif 2509 } 2510 } 2511 2512 /* 2513 * handle service interrupts 2514 */ 2515 2516 if (reg & MID_INT_SERVICE) { 2517 chip = MID_SL_REG2A(EN_READ(sc, MID_SERV_WRITE)); 2518 2519 while (sc->hwslistp != chip) { 2520 2521 /* fetch and remove it from hardware service list */ 2522 vci = EN_READ(sc, sc->hwslistp); 2523 EN_WRAPADD(MID_SLOFF, MID_SLEND, sc->hwslistp, 4);/* advance hw ptr */ 2524 slot = sc->rxvc2slot[vci]; 2525 if (slot == RX_NONE) { 2526#ifdef EN_DEBUG 2527 printf("%s: unexpected rx interrupt on VCI %d\n", 2528 sc->sc_dev.dv_xname, vci); 2529#endif 2530 EN_WRITE(sc, MID_VC(vci), MIDV_TRASH); /* rx off, damn it! */ 2531 continue; /* next */ 2532 } 2533 EN_WRITE(sc, MID_VC(vci), sc->rxslot[slot].mode); /* remove from hwsl */ 2534 EN_COUNT(sc->hwpull); 2535 2536#ifdef EN_DEBUG 2537 printf("%s: pulled VCI %d off hwslist\n", sc->sc_dev.dv_xname, vci); 2538#endif 2539 2540 /* add it to the software service list (if needed) */ 2541 if ((sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) { 2542 EN_COUNT(sc->swadd); 2543 need_softserv = 1; 2544 sc->rxslot[slot].oth_flags |= ENOTHER_SWSL; 2545 sc->swslist[sc->swsl_tail] = slot; 2546 EN_WRAPADD(0, MID_SL_N, sc->swsl_tail, 1); 2547 sc->swsl_size++; 2548#ifdef EN_DEBUG 2549 printf("%s: added VCI %d to swslist\n", sc->sc_dev.dv_xname, vci); 2550#endif 2551 } 2552 } 2553 } 2554 2555 /* 2556 * now service (function too big to include here) 2557 */ 2558 2559 if (need_softserv) 2560 en_service(sc); 2561 2562 /* 2563 * keep our stats 2564 */ 2565 2566 if (reg & MID_INT_DMA_OVR) { 2567 EN_COUNT(sc->dmaovr); 2568#ifdef EN_DEBUG 2569 printf("%s: MID_INT_DMA_OVR\n", sc->sc_dev.dv_xname); 2570#endif 2571 } 2572 reg = EN_READ(sc, MID_STAT); 2573#ifdef EN_STAT 2574 sc->otrash += MID_OTRASH(reg); 2575 sc->vtrash += MID_VTRASH(reg); 2576#endif 2577 2578 EN_INTR_RET(1); /* for us */ 2579} 2580 2581 2582/* 2583 * en_service: handle a service interrupt 2584 * 2585 * Q: why do we need a software service list? 2586 * 2587 * A: if we remove a VCI from the hardware list and we find that we are 2588 * out of DRQs we must defer processing until some DRQs become free. 2589 * so we must remember to look at this RX VCI/slot later, but we can't 2590 * put it back on the hardware service list (since that isn't allowed). 2591 * so we instead save it on the software service list. it would be nice 2592 * if we could peek at the VCI on top of the hwservice list without removing 2593 * it, however this leads to a race condition: if we peek at it and 2594 * decide we are done with it new data could come in before we have a 2595 * chance to remove it from the hwslist. by the time we get it out of 2596 * the list the interrupt for the new data will be lost. oops! 2597 * 2598 */ 2599 2600STATIC void en_service(sc) 2601 2602struct en_softc *sc; 2603 2604{ 2605 struct mbuf *m, *tmp; 2606 u_int32_t cur, dstart, rbd, pdu, *sav, dma, bcode, count, *data, *datastop; 2607 u_int32_t start, stop, cnt, needalign; 2608 int slot, raw, aal5, llc, vci, fill, mlen, tlen, drqneed, need, needfill, end; 2609 2610 aal5 = 0; /* Silence gcc */ 2611next_vci: 2612 if (sc->swsl_size == 0) { 2613#ifdef EN_DEBUG 2614 printf("%s: en_service done\n", sc->sc_dev.dv_xname); 2615#endif 2616 return; /* >>> exit here if swsl now empty <<< */ 2617 } 2618 2619 /* 2620 * get slot/vci to service 2621 */ 2622 2623 slot = sc->swslist[sc->swsl_head]; 2624 vci = sc->rxslot[slot].atm_vci; 2625#ifdef EN_DIAG 2626 if (sc->rxvc2slot[vci] != slot) panic("en_service rx slot/vci sync"); 2627#endif 2628 2629 /* 2630 * determine our mode and if we've got any work to do 2631 */ 2632 2633 raw = sc->rxslot[slot].oth_flags & ENOTHER_RAW; 2634 start= sc->rxslot[slot].start; 2635 stop= sc->rxslot[slot].stop; 2636 cur = sc->rxslot[slot].cur; 2637 2638#ifdef EN_DEBUG 2639 printf("%s: rx%d: service vci=%d raw=%d start/stop/cur=0x%x 0x%x 0x%x\n", 2640 sc->sc_dev.dv_xname, slot, vci, raw, start, stop, cur); 2641#endif 2642 2643same_vci: 2644 dstart = MIDV_DSTART(EN_READ(sc, MID_DST_RP(vci))); 2645 dstart = (dstart * sizeof(u_int32_t)) + start; 2646 2647 /* check to see if there is any data at all */ 2648 if (dstart == cur) { 2649defer: /* defer processing */ 2650 EN_WRAPADD(0, MID_SL_N, sc->swsl_head, 1); 2651 sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL; 2652 sc->swsl_size--; 2653 /* >>> remove from swslist <<< */ 2654#ifdef EN_DEBUG 2655 printf("%s: rx%d: remove vci %d from swslist\n", 2656 sc->sc_dev.dv_xname, slot, vci); 2657#endif 2658 goto next_vci; 2659 } 2660 2661 /* 2662 * figure out how many bytes we need 2663 * [mlen = # bytes to go in mbufs, fill = # bytes to dump (MIDDMA_JK)] 2664 */ 2665 2666 if (raw) { 2667 2668 /* raw mode (aka boodi mode) */ 2669 fill = 0; 2670 if (dstart > cur) 2671 mlen = dstart - cur; 2672 else 2673 mlen = (dstart + (EN_RXSZ*1024)) - cur; 2674 2675 if (mlen < sc->rxslot[slot].raw_threshold) 2676 goto defer; /* too little data to deal with */ 2677 2678 } else { 2679 2680 /* normal mode */ 2681 aal5 = (sc->rxslot[slot].atm_flags & ATM_PH_AAL5); 2682 llc = (aal5 && (sc->rxslot[slot].atm_flags & ATM_PH_LLCSNAP)) ? 1 : 0; 2683 rbd = EN_READ(sc, cur); 2684 if (MID_RBD_ID(rbd) != MID_RBD_STDID) 2685 panic("en_service: id mismatch\n"); 2686 2687 if (rbd & MID_RBD_T) { 2688 mlen = 0; /* we've got trash */ 2689 fill = MID_RBD_SIZE; 2690 EN_COUNT(sc->ttrash); 2691 } else if (!aal5) { 2692 mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */ 2693 fill = 0; 2694 } else { 2695 tlen = (MID_RBD_CNT(rbd) * MID_ATMDATASZ) + MID_RBD_SIZE; 2696 pdu = cur + tlen - MID_PDU_SIZE; 2697 if (pdu >= stop) 2698 pdu -= (EN_RXSZ*1024); 2699 pdu = EN_READ(sc, pdu); /* get PDU in correct byte order */ 2700 fill = tlen - MID_RBD_SIZE - MID_PDU_LEN(pdu); 2701 if (fill < 0 || (rbd & MID_RBD_CRCERR) != 0) { 2702 printf("%s: invalid AAL5 PDU length or CRC detected, dropping frame\n", 2703 sc->sc_dev.dv_xname); 2704 printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x) CRCERR=%d\n", 2705 sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE, 2706 MID_PDU_LEN(pdu), pdu, (rbd & MID_RBD_CRCERR)?1:0); 2707 fill = tlen; 2708 } 2709 mlen = tlen - fill; 2710 } 2711 2712 } 2713 2714 /* 2715 * now allocate mbufs for mlen bytes of data, if out of mbufs, trash all 2716 * 2717 * notes: 2718 * 1. it is possible that we've already allocated an mbuf for this pkt 2719 * but ran out of DRQs, in which case we saved the allocated mbuf on 2720 * "q". 2721 * 2. if we save an mbuf in "q" we store the "cur" (pointer) in the front 2722 * of the mbuf as an identity (that we can check later), and we also 2723 * store drqneed (so we don't have to recompute it). 2724 * 3. after this block of code, if m is still NULL then we ran out of mbufs 2725 */ 2726 2727 m = sc->rxslot[slot].q.ifq_head; 2728 drqneed = 1; 2729 if (m) { 2730 sav = mtod(m, u_int32_t *); 2731 if (sav[0] != cur) { 2732#ifdef EN_DEBUG 2733 printf("%s: rx%d: q'ed mbuf %p not ours\n", 2734 sc->sc_dev.dv_xname, slot, m); 2735#endif 2736 m = NULL; /* wasn't ours */ 2737 EN_COUNT(sc->rxqnotus); 2738 } else { 2739 EN_COUNT(sc->rxqus); 2740 IF_DEQUEUE(&sc->rxslot[slot].q, m); 2741 drqneed = sav[1]; 2742#ifdef EN_DEBUG 2743 printf("%s: rx%d: recovered q'ed mbuf %p (drqneed=%d)\n", 2744 sc->sc_dev.dv_xname, slot, m, drqneed); 2745#endif 2746 } 2747 } 2748 2749 if (mlen != 0 && m == NULL) { 2750 m = en_mget(sc, mlen, &drqneed); /* allocate! */ 2751 if (m == NULL) { 2752 fill += mlen; 2753 mlen = 0; 2754 EN_COUNT(sc->rxmbufout); 2755#ifdef EN_DEBUG 2756 printf("%s: rx%d: out of mbufs\n", sc->sc_dev.dv_xname, slot); 2757#endif 2758 } 2759#ifdef EN_DEBUG 2760 printf("%s: rx%d: allocate mbuf %p, mlen=%d, drqneed=%d\n", 2761 sc->sc_dev.dv_xname, slot, m, mlen, drqneed); 2762#endif 2763 } 2764 2765#ifdef EN_DEBUG 2766 printf("%s: rx%d: VCI %d, mbuf_chain %p, mlen %d, fill %d\n", 2767 sc->sc_dev.dv_xname, slot, vci, m, mlen, fill); 2768#endif 2769 2770 /* 2771 * now check to see if we've got the DRQs needed. if we are out of 2772 * DRQs we must quit (saving our mbuf, if we've got one). 2773 */ 2774 2775 needfill = (fill) ? 1 : 0; 2776 if (drqneed + needfill > sc->drq_free) { 2777 sc->need_drqs = 1; /* flag condition */ 2778 if (m == NULL) { 2779 EN_COUNT(sc->rxoutboth); 2780#ifdef EN_DEBUG 2781 printf("%s: rx%d: out of DRQs *and* mbufs!\n", sc->sc_dev.dv_xname, slot); 2782#endif 2783 return; /* >>> exit here if out of both mbufs and DRQs <<< */ 2784 } 2785 sav = mtod(m, u_int32_t *); 2786 sav[0] = cur; 2787 sav[1] = drqneed; 2788 IF_ENQUEUE(&sc->rxslot[slot].q, m); 2789 EN_COUNT(sc->rxdrqout); 2790#ifdef EN_DEBUG 2791 printf("%s: rx%d: out of DRQs\n", sc->sc_dev.dv_xname, slot); 2792#endif 2793 return; /* >>> exit here if out of DRQs <<< */ 2794 } 2795 2796 /* 2797 * at this point all resources have been allocated and we are commited 2798 * to servicing this slot. 2799 * 2800 * dma = last location we told chip about 2801 * cur = current location 2802 * mlen = space in the mbuf we want 2803 * need = bytes to xfer in (decrs to zero) 2804 * fill = how much fill we need 2805 * tlen = how much data to transfer to this mbuf 2806 * cnt/bcode/count = <same as xmit> 2807 * 2808 * 'needfill' not used after this point 2809 */ 2810 2811 dma = cur; /* dma = last location we told chip about */ 2812 need = roundup(mlen, sizeof(u_int32_t)); 2813 fill = fill - (need - mlen); /* note: may invalidate 'needfill' */ 2814 2815 for (tmp = m ; tmp != NULL && need > 0 ; tmp = tmp->m_next) { 2816 tlen = roundup(tmp->m_len, sizeof(u_int32_t)); /* m_len set by en_mget */ 2817 data = mtod(tmp, u_int32_t *); 2818 2819#ifdef EN_DEBUG 2820 printf("%s: rx%d: load mbuf %p, m_len=%d, m_data=%p, tlen=%d\n", 2821 sc->sc_dev.dv_xname, slot, tmp, tmp->m_len, tmp->m_data, tlen); 2822#endif 2823 2824 /* copy data */ 2825 if (EN_NORXDMA || !en_dma || tlen < EN_MINDMA) { 2826 datastop = (u_int32_t *)((u_char *) data + tlen); 2827 /* copy loop: preserve byte order!!! use READDAT */ 2828 while (data != datastop) { 2829 *data = EN_READDAT(sc, cur); 2830 data++; 2831 EN_WRAPADD(start, stop, cur, 4); 2832 } 2833 need -= tlen; 2834#ifdef EN_DEBUG 2835 printf("%s: rx%d: vci%d: copied %d bytes (%d left)\n", 2836 sc->sc_dev.dv_xname, slot, vci, tlen, need); 2837#endif 2838 continue; 2839 } 2840 2841 /* DMA data (check to see if we need to sync DRQ first) */ 2842 if (dma != cur) { 2843 EN_DRQADD(sc, WORD_IDX(start,cur), vci, MIDDMA_JK, 0, 0, 0, 0); 2844#ifdef EN_DEBUG 2845 printf("%s: rx%d: vci%d: drq_sync: advance pointer to %d\n", 2846 sc->sc_dev.dv_xname, slot, vci, cur); 2847#endif 2848 } 2849 2850#if !defined(MIDWAY_ENIONLY) 2851 2852 /* 2853 * the adaptec DMA engine is smart and handles everything for us. 2854 */ 2855 2856 if (sc->is_adaptec) { 2857 need -= tlen; 2858 EN_WRAPADD(start, stop, cur, tlen); 2859#ifdef EN_DEBUG 2860 printf("%s: rx%d: vci%d: adp_dma %d bytes (%d left)\n", 2861 sc->sc_dev.dv_xname, slot, vci, tlen, need); 2862#endif 2863 end = (need == 0 && !fill) ? MID_DMA_END : 0; 2864 EN_DRQADD(sc, tlen, vci, 0, vtophys(data), mlen, slot, end); 2865 if (end) 2866 goto done; 2867 dma = cur; /* update dma pointer */ 2868 continue; 2869 } 2870#endif /* !MIDWAY_ENIONLY */ 2871 2872 2873#if !defined(MIDWAY_ADPONLY) 2874 2875 /* 2876 * the ENI DMA engine is not so smart and need more help from us 2877 */ 2878 2879 /* do we need to do a DMA op to align? */ 2880 if (sc->alburst && 2881 (needalign = (((unsigned long) data) & sc->bestburstmask)) != 0) { 2882 cnt = sc->bestburstlen - needalign; 2883 if (cnt > tlen) { 2884 cnt = tlen; 2885 count = cnt / sizeof(u_int32_t); 2886 bcode = MIDDMA_WORD; 2887 } else { 2888 count = cnt / sizeof(u_int32_t); 2889 bcode = en_dmaplan[count].bcode; 2890 count = cnt >> en_dmaplan[count].divshift; 2891 } 2892 need -= cnt; 2893 EN_WRAPADD(start, stop, cur, cnt); 2894#ifdef EN_DEBUG 2895 printf("%s: rx%d: vci%d: al_dma %d bytes (%d left)\n", 2896 sc->sc_dev.dv_xname, slot, vci, cnt, need); 2897#endif 2898 tlen -= cnt; 2899 end = (need == 0 && !fill) ? MID_DMA_END : 0; 2900 EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end); 2901 if (end) 2902 goto done; 2903 data = (u_int32_t *)((u_char *) data + cnt); 2904 } 2905 2906 /* do we need a max-sized burst? */ 2907 if (tlen >= sc->bestburstlen) { 2908 count = tlen >> sc->bestburstshift; 2909 cnt = count << sc->bestburstshift; 2910 bcode = sc->bestburstcode; 2911 need -= cnt; 2912 EN_WRAPADD(start, stop, cur, cnt); 2913#ifdef EN_DEBUG 2914 printf("%s: rx%d: vci%d: best_dma %d bytes (%d left)\n", 2915 sc->sc_dev.dv_xname, slot, vci, cnt, need); 2916#endif 2917 tlen -= cnt; 2918 end = (need == 0 && !fill) ? MID_DMA_END : 0; 2919 EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end); 2920 if (end) 2921 goto done; 2922 data = (u_int32_t *)((u_char *) data + cnt); 2923 } 2924 2925 /* do we need to do a cleanup burst? */ 2926 if (tlen) { 2927 count = tlen / sizeof(u_int32_t); 2928 bcode = en_dmaplan[count].bcode; 2929 count = tlen >> en_dmaplan[count].divshift; 2930 need -= tlen; 2931 EN_WRAPADD(start, stop, cur, tlen); 2932#ifdef EN_DEBUG 2933 printf("%s: rx%d: vci%d: cleanup_dma %d bytes (%d left)\n", 2934 sc->sc_dev.dv_xname, slot, vci, tlen, need); 2935#endif 2936 end = (need == 0 && !fill) ? MID_DMA_END : 0; 2937 EN_DRQADD(sc, count, vci, bcode, vtophys(data), mlen, slot, end); 2938 if (end) 2939 goto done; 2940 } 2941 2942 dma = cur; /* update dma pointer */ 2943 2944#endif /* !MIDWAY_ADPONLY */ 2945 2946 } 2947 2948 /* skip the end */ 2949 if (fill || dma != cur) { 2950#ifdef EN_DEBUG 2951 if (fill) 2952 printf("%s: rx%d: vci%d: skipping %d bytes of fill\n", 2953 sc->sc_dev.dv_xname, slot, vci, fill); 2954 else 2955 printf("%s: rx%d: vci%d: syncing chip from 0x%x to 0x%x [cur]\n", 2956 sc->sc_dev.dv_xname, slot, vci, dma, cur); 2957#endif 2958 EN_WRAPADD(start, stop, cur, fill); 2959 EN_DRQADD(sc, WORD_IDX(start,cur), vci, MIDDMA_JK, 0, mlen, 2960 slot, MID_DMA_END); 2961 /* dma = cur; */ /* not necessary since we are done */ 2962 } 2963 2964 /* 2965 * done, remove stuff we don't want to pass up: 2966 * raw mode (boodi mode): pass everything up for later processing 2967 * aal5: remove RBD 2968 * aal0: remove RBD + cell header 2969 */ 2970 2971done: 2972 if (m) { 2973 if (!raw) { 2974 cnt = MID_RBD_SIZE; 2975 if (!aal5) cnt += MID_CHDR_SIZE; 2976 m->m_len -= cnt; /* chop! */ 2977 m->m_pkthdr.len -= cnt; 2978 m->m_data += cnt; 2979 } 2980 IF_ENQUEUE(&sc->rxslot[slot].indma, m); 2981 } 2982 sc->rxslot[slot].cur = cur; /* update master copy of 'cur' */ 2983 2984#ifdef EN_DEBUG 2985 printf("%s: rx%d: vci%d: DONE! cur now =0x%x\n", 2986 sc->sc_dev.dv_xname, slot, vci, cur); 2987#endif 2988 2989 goto same_vci; /* get next packet in this slot */ 2990} 2991 2992 2993#ifdef EN_DDBHOOK 2994/* 2995 * functions we can call from ddb 2996 */ 2997 2998/* 2999 * en_dump: dump the state 3000 */ 3001 3002#define END_SWSL 0x00000040 /* swsl state */ 3003#define END_DRQ 0x00000020 /* drq state */ 3004#define END_DTQ 0x00000010 /* dtq state */ 3005#define END_RX 0x00000008 /* rx state */ 3006#define END_TX 0x00000004 /* tx state */ 3007#define END_MREGS 0x00000002 /* registers */ 3008#define END_STATS 0x00000001 /* dump stats */ 3009 3010#define END_BITS "\20\7SWSL\6DRQ\5DTQ\4RX\3TX\2MREGS\1STATS" 3011 3012int en_dump(unit, level) 3013 3014int unit, level; 3015 3016{ 3017 struct en_softc *sc; 3018 int lcv, cnt, slot; 3019 u_int32_t ptr, reg; 3020 3021 for (lcv = 0 ; lcv < en_cd.cd_ndevs ; lcv++) { 3022 sc = (struct en_softc *) en_cd.cd_devs[lcv]; 3023 if (sc == NULL) continue; 3024 if (unit != -1 && unit != lcv) 3025 continue; 3026 3027 printf("dumping device %s at level 0x%b\n", sc->sc_dev.dv_xname, level, 3028 END_BITS); 3029 3030 if (sc->dtq_us == 0) { 3031 printf("<hasn't been en_init'd yet>\n"); 3032 continue; 3033 } 3034 3035 if (level & END_STATS) { 3036 printf(" en_stats:\n"); 3037 printf(" %d mfix (%d failed); %d/%d head/tail byte DMAs, %d flushes\n", 3038 sc->mfix, sc->mfixfail, sc->headbyte, sc->tailbyte, sc->tailflush); 3039 printf(" %d rx dma overflow interrupts\n", sc->dmaovr); 3040 printf(" %d times we ran out of TX space and stalled\n", 3041 sc->txoutspace); 3042 printf(" %d times we ran out of DTQs\n", sc->txdtqout); 3043 printf(" %d times we launched a packet\n", sc->launch); 3044 printf(" %d times we launched without on-board header\n", sc->lheader); 3045 printf(" %d times we launched without on-board tail\n", sc->ltail); 3046 printf(" %d times we pulled the hw service list\n", sc->hwpull); 3047 printf(" %d times we pushed a vci on the sw service list\n", 3048 sc->swadd); 3049 printf(" %d times RX pulled an mbuf from Q that wasn't ours\n", 3050 sc->rxqnotus); 3051 printf(" %d times RX pulled a good mbuf from Q\n", sc->rxqus); 3052 printf(" %d times we ran out of mbufs *and* DRQs\n", sc->rxoutboth); 3053 printf(" %d times we ran out of DRQs\n", sc->rxdrqout); 3054 3055 printf(" %d trasmit packets dropped due to mbsize\n", sc->txmbovr); 3056 printf(" %d cells trashed due to turned off rxvc\n", sc->vtrash); 3057 printf(" %d cells trashed due to totally full buffer\n", sc->otrash); 3058 printf(" %d cells trashed due almost full buffer\n", sc->ttrash); 3059 printf(" %d rx mbuf allocation failures\n", sc->rxmbufout); 3060#ifdef NATM 3061 printf(" %d drops at natmintrq\n", natmintrq.ifq_drops); 3062#ifdef NATM_STAT 3063 printf(" natmintr so_rcv: ok/drop cnt: %d/%d, ok/drop bytes: %d/%d\n", 3064 natm_sookcnt, natm_sodropcnt, natm_sookbytes, natm_sodropbytes); 3065#endif 3066#endif 3067 } 3068 3069 if (level & END_MREGS) { 3070 printf("mregs:\n"); 3071 printf("resid = 0x%x\n", EN_READ(sc, MID_RESID)); 3072 printf("interrupt status = 0x%b\n", 3073 EN_READ(sc, MID_INTSTAT), MID_INTBITS); 3074 printf("interrupt enable = 0x%b\n", 3075 EN_READ(sc, MID_INTENA), MID_INTBITS); 3076 printf("mcsr = 0x%b\n", EN_READ(sc, MID_MAST_CSR), MID_MCSRBITS); 3077 printf("serv_write = [chip=%d] [us=%d]\n", EN_READ(sc, MID_SERV_WRITE), 3078 MID_SL_A2REG(sc->hwslistp)); 3079 printf("dma addr = 0x%x\n", EN_READ(sc, MID_DMA_ADDR)); 3080 printf("DRQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n", 3081 MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX)), 3082 MID_DRQ_REG2A(EN_READ(sc, MID_DMA_WRRX)), sc->drq_chip, sc->drq_us); 3083 printf("DTQ: chip[rd=0x%x,wr=0x%x], sc[chip=0x%x,us=0x%x]\n", 3084 MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX)), 3085 MID_DTQ_REG2A(EN_READ(sc, MID_DMA_WRTX)), sc->dtq_chip, sc->dtq_us); 3086 3087 printf(" unusal txspeeds: "); 3088 for (cnt = 0 ; cnt < MID_N_VC ; cnt++) 3089 if (sc->txspeed[cnt]) 3090 printf(" vci%d=0x%x", cnt, sc->txspeed[cnt]); 3091 printf("\n"); 3092 3093 printf(" rxvc slot mappings: "); 3094 for (cnt = 0 ; cnt < MID_N_VC ; cnt++) 3095 if (sc->rxvc2slot[cnt] != RX_NONE) 3096 printf(" %d->%d", cnt, sc->rxvc2slot[cnt]); 3097 printf("\n"); 3098 3099 } 3100 3101 if (level & END_TX) { 3102 printf("tx:\n"); 3103 for (slot = 0 ; slot < EN_NTX; slot++) { 3104 printf("tx%d: start/stop/cur=0x%x/0x%x/0x%x [%d] ", slot, 3105 sc->txslot[slot].start, sc->txslot[slot].stop, sc->txslot[slot].cur, 3106 (sc->txslot[slot].cur - sc->txslot[slot].start)/4); 3107 printf("mbsize=%d, bfree=%d\n", sc->txslot[slot].mbsize, 3108 sc->txslot[slot].bfree); 3109 printf("txhw: base_address=0x%x, size=%d, read=%d, descstart=%d\n", 3110 MIDX_BASE(EN_READ(sc, MIDX_PLACE(slot))), 3111 MIDX_SZ(EN_READ(sc, MIDX_PLACE(slot))), 3112 EN_READ(sc, MIDX_READPTR(slot)), EN_READ(sc, MIDX_DESCSTART(slot))); 3113 } 3114 } 3115 3116 if (level & END_RX) { 3117 printf(" recv slots:\n"); 3118 for (slot = 0 ; slot < sc->en_nrx; slot++) { 3119 printf("rx%d: vci=%d: start/stop/cur=0x%x/0x%x/0x%x ", slot, 3120 sc->rxslot[slot].atm_vci, sc->rxslot[slot].start, 3121 sc->rxslot[slot].stop, sc->rxslot[slot].cur); 3122 printf("mode=0x%x, atm_flags=0x%x, oth_flags=0x%x\n", 3123 sc->rxslot[slot].mode, sc->rxslot[slot].atm_flags, 3124 sc->rxslot[slot].oth_flags); 3125 printf("RXHW: mode=0x%x, DST_RP=0x%x, WP_ST_CNT=0x%x\n", 3126 EN_READ(sc, MID_VC(sc->rxslot[slot].atm_vci)), 3127 EN_READ(sc, MID_DST_RP(sc->rxslot[slot].atm_vci)), 3128 EN_READ(sc, MID_WP_ST_CNT(sc->rxslot[slot].atm_vci))); 3129 } 3130 } 3131 3132 if (level & END_DTQ) { 3133 printf(" dtq [need_dtqs=%d,dtq_free=%d]:\n", 3134 sc->need_dtqs, sc->dtq_free); 3135 ptr = sc->dtq_chip; 3136 while (ptr != sc->dtq_us) { 3137 reg = EN_READ(sc, ptr); 3138 printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n", 3139 sc->dtq[MID_DTQ_A2REG(ptr)], MID_DMA_CNT(reg), MID_DMA_TXCHAN(reg), 3140 (reg & MID_DMA_END) != 0, MID_DMA_TYPE(reg), EN_READ(sc, ptr+4)); 3141 EN_WRAPADD(MID_DTQOFF, MID_DTQEND, ptr, 8); 3142 } 3143 } 3144 3145 if (level & END_DRQ) { 3146 printf(" drq [need_drqs=%d,drq_free=%d]:\n", 3147 sc->need_drqs, sc->drq_free); 3148 ptr = sc->drq_chip; 3149 while (ptr != sc->drq_us) { 3150 reg = EN_READ(sc, ptr); 3151 printf("\t0x%x=[cnt=%d, chan=%d, end=%d, type=%d @ 0x%x]\n", 3152 sc->drq[MID_DRQ_A2REG(ptr)], MID_DMA_CNT(reg), MID_DMA_RXVCI(reg), 3153 (reg & MID_DMA_END) != 0, MID_DMA_TYPE(reg), EN_READ(sc, ptr+4)); 3154 EN_WRAPADD(MID_DRQOFF, MID_DRQEND, ptr, 8); 3155 } 3156 } 3157 3158 if (level & END_SWSL) { 3159 printf(" swslist [size=%d]: ", sc->swsl_size); 3160 for (cnt = sc->swsl_head ; cnt != sc->swsl_tail ; 3161 cnt = (cnt + 1) % MID_SL_N) 3162 printf("0x%x ", sc->swslist[cnt]); 3163 printf("\n"); 3164 } 3165 3166 } 3167 return(0); 3168} 3169 3170/* 3171 * en_dumpmem: dump the memory 3172 */ 3173 3174int en_dumpmem(unit, addr, len) 3175 3176int unit, addr, len; 3177 3178{ 3179 struct en_softc *sc; 3180 u_int32_t reg; 3181 3182 if (unit < 0 || unit > en_cd.cd_ndevs || 3183 (sc = (struct en_softc *) en_cd.cd_devs[unit]) == NULL) { 3184 printf("invalid unit number: %d\n", unit); 3185 return(0); 3186 } 3187 addr = addr & ~3; 3188 if (addr < MID_RAMOFF || addr + len*4 > MID_MAXOFF || len <= 0) { 3189 printf("invalid addr/len number: %d, %d\n", addr, len); 3190 return(0); 3191 } 3192 printf("dumping %d words starting at offset 0x%x\n", len, addr); 3193 while (len--) { 3194 reg = EN_READ(sc, addr); 3195 printf("mem[0x%x] = 0x%x\n", addr, reg); 3196 addr += 4; 3197 } 3198 return(0); 3199} 3200#endif 3201 3202 3203#endif /* NEN > 0 || !defined(__FreeBSD__) */
|