1:     2:     3:     4:     5:     6:     7:     8:     9:    10:    11:    12:    13: 
   14:    15:    16:    17:    18:    19:    20:    21:    22:    23:    24:    25:    26:    27:    28:    29:    30:    31:    32:    33:    34:    35:    36:    37:    38:    39:    40:    41:    42:    43:    44: 
   45: 
   46:    47:    48:    49: 
   50: 
   51: #include "netdrv.h"
   52: 
   53: 
   54: #define SMSC9118_IOSZ           0x100
   55: 
   56: 
   57: #define RX_DATA                 0x00
   58: #define TX_DATA                 0x20
   59: #define RX_STS                  0x40
   60: #define TX_STS                  0x48
   61: #define ID_REV                  0x50
   62: #define IRQ_CFG                 0x54
   63: #define INT_STS                 0x58
   64: #define INT_EN                  0x5c
   65: #define BYTE_TEST               0x64
   66: #define FIFO_INT                0x68
   67: #define RX_CFG                  0x6c
   68: #define TX_CFG                  0x70
   69: #define HW_CFG                  0x74
   70: #define RX_DP_CTL               0x78
   71: #define RX_FIFO_INF             0x7c
   72: #define TX_FIFO_INF             0x80
   73: #define PMT_CTRL                0x84
   74: #define GPIO_CFG                0x88
   75: #define ENDIAN                  0x98
   76: #define RX_DROP                 0xa0
   77: #define MAC_CSR_CMD             0xa4
   78: #define MAC_CSR_DATA            0xa8
   79: #define AFC_CFG                 0xac
   80: #define E2P_CMD                 0xb0
   81: #define E2P_DATA                0xb4
   82: 
   83: 
   84: #define IRQ_CFG_INT_DEAS(x)     ((x) << 24)
   85: #define IRQ_CFG_IRQ_EN          (1 << 8)
   86: #define IRQ_CFG_IRQ_POL         (1 << 4)
   87: #define IRQ_CFG_IRQ_TYPE        (1 << 0)
   88: 
   89: 
   90: #define INT_TXSTOP              (1 << 25)
   91: #define INT_RXSTOP              (1 << 24)
   92: #define INT_TSFF                (1 << 8)
   93: #define INT_TSFL                (1 << 7)
   94: #define INT_RSFF                (1 << 4)
   95: #define INT_RSFL                (1 << 3)
   96: 
   97: 
   98: #define BYTE_TEST_MAGIC         0x87654321
   99: 
  100: 
  101: #define FIFO_INT_TSFL(x)        ((x) << 16)
  102: #define FIFO_INT_RSFL(x)        ((x) << 0)
  103: 
  104: 
  105: #define RX_CFG_ALIGN_4          (0 << 30)
  106: #define RX_CFG_DUMP             (1 << 15)
  107: #define RX_CFG_DOFF(x)          ((x) << 8)
  108: 
  109: 
  110: #define TX_CFG_SDUMP            (1 << 15)
  111: #define TX_CFG_DDUMP            (1 << 14)
  112: #define TX_CFG_ON               (1 << 1)
  113: #define TX_CFG_STOP             (1 << 0)
  114: 
  115: 
  116: #define HW_CFG_SF               (1 << 20)
  117: #define HW_CFG_TX_FIF_SZ(x)     ((x) << 16)
  118: #define HW_CFG_PHY_CLK_INT      (0 << 5)
  119: #define HW_CFG_SRST_TO          (1 << 1)
  120: #define HW_CFG_SRST             (1 << 0)
  121: 
  122: 
  123: #define RX_DP_CTL_FFWD          (1 << 31)
  124: 
  125: 
  126: #define PMT_CTRL_PM_MODE(x)     ((x) << 12)
  127: #define PMT_CTRL_PHY_RST        (1 << 10)
  128: #define PMT_CTRL_READY          (1 << 0)
  129: 
  130: 
  131: #define MAC_CSR_CMD_BUSY        (1 << 31)
  132: #define MAC_CSR_CMD_READ        (1 << 30)
  133: #define MAC_CSR_CMD_ADDR(x)     ((x) << 0)
  134: 
  135: 
  136: #define E2P_CMD_BUSY            (1 << 31)
  137: #define E2P_CMD_READ            (0 << 28)
  138: #define E2P_CMD_TMO             (1 << 9)
  139: #define E2P_CMD_ADDR(x)         ((x) << 0)
  140: 
  141: 
  142: #define MAC_CR                  0x01
  143: #define ADDRH                   0x02
  144: #define ADDRL                   0x03
  145: #define HASHH                   0x04
  146: #define HASHL                   0x05
  147: #define MII_ACC                 0x06
  148: #define MII_DATA                0x07
  149: #define FLOW                    0x08
  150: #define VLAN1                   0x09
  151: #define VLAN2                   0x0a
  152: #define WUFF                    0x0b
  153: #define WUCSR                   0x0c
  154: 
  155: 
  156: #define MAC_CR_FDPX             (1 << 20)
  157: #define MAC_CR_TXEN             (1 << 3)
  158: #define MAC_CR_RXEN             (1 << 2)
  159: 
  160: 
  161: #define MII_ACC_PHYADR(x)       ((x) << 11)
  162: #define MII_ACC_MIIRINDA(x)     ((x) << 6)
  163: #define MII_ACC_MIIWnR          (1 << 1)
  164: #define MII_ACC_MIIBZY          (1 << 0)
  165: 
  166: 
  167: #define BadState                wrk.uw[0]
  168: #define ChipID                  wrk.uw[3]
  169: #define IntMask                 wrk.uw[6]
  170: 
  171: 
  172: #define RX_STS_ES               (1 << 15)
  173: 
  174: 
  175: #define TX_CMDA_ALIGN_4         (0 << 24)
  176: #define TX_CMDA_OFFSET(x)       ((x) << 16)
  177: #define TX_CMDA_FS              (1 << 13)
  178: #define TX_CMDA_LS              (1 << 12)
  179: #define TX_CMDA_BUFSZ(x)        ((x) << 0)
  180: 
  181: 
  182: #define TX_CMDB_PADDIS          (1 << 12)
  183: #define TX_CMDB_PKTSZ(x)        ((x) << 0)
  184: 
  185: 
  186: #define TX_STS_ES               (1 << 15)
  187: 
  188: 
  189: #define IOBase                  di.iobase
  190: 
  191: #define POLL_LIMIT              100000              
  192: #define DLY_LIMIT               100          
  193: 
  194: #define TX_FIFO_SIZE            5         
  195: 
  196: 
  197: LOCAL   const UB  *SMSC9118_PNAME1[] = {
  198:         "SMSC ",
  199: };
  200: 
  201: LOCAL   const UB  *SMSC9118_PNAME2[] = {
  202:         "LAN9118 family",
  203: };
  204: 
  205: 
  206:   207:   208: 
  209: LOCAL   void      wait_reg(NetInf *inf, W reg, W mask, W val)
  210: {
  211:         UW     IOB = inf->IOBase;
  212:         W      i;
  213: 
  214:         for (i = POLL_LIMIT; i > 0; i--) {
  215:                 InW(BYTE_TEST);               
  216:                 if ((InW(reg) & mask) == val) goto fin0;
  217:         }
  218:         for (i = DLY_LIMIT; i > 0; i--) {
  219:                 if (tk_dly_tsk(10) < E_OK) InW(BYTE_TEST);
  220:                 if ((InW(reg) & mask) == val) goto fin0;
  221:         }
  222: 
  223:         inf->BadState = 1;
  224:         DP(("wait_reg: reg %#x mask %#x timeout\n", reg, mask));
  225:  fin0:
  226:         return;
  227: }
  228: 
  229:   230:   231: 
  232: #define wait_mac(inf)   wait_reg((inf), MAC_CSR_CMD, MAC_CSR_CMD_BUSY, 0)
  233: 
  234:   235:   236: 
  237: LOCAL   void      poke_mac(NetInf *inf, W reg, W dat)
  238: {
  239:         UW     IOB = inf->IOBase;
  240: 
  241:         wait_mac(inf);
  242:         OutW(MAC_CSR_DATA, dat);
  243:         OutW(MAC_CSR_CMD, reg | MAC_CSR_CMD_BUSY);
  244:         wait_mac(inf);
  245: 
  246:         return;
  247: }
  248: 
  249:   250:   251: 
  252: LOCAL   W peek_mac(NetInf *inf, W reg)
  253: {
  254:         UW     IOB = inf->IOBase;
  255: 
  256:         wait_mac(inf);
  257:         OutW(MAC_CSR_CMD, reg | MAC_CSR_CMD_BUSY | MAC_CSR_CMD_READ);
  258:         wait_mac(inf);
  259: 
  260:         return InW(MAC_CSR_DATA);
  261: }
  262: 
  263:   264:   265: 
  266: LOCAL   void      wait_mii(NetInf *inf)
  267: {
  268:         W      i;
  269: 
  270:         for (i = POLL_LIMIT; i > 0; i--) {
  271:                 if (!(peek_mac(inf, MII_ACC) & MII_ACC_MIIBZY)) break;
  272:         }
  273: 
  274:         if (!i) {
  275:                 inf->BadState = 1;
  276:                 DP(("wait_mii: timeout\n"));
  277:         }
  278: 
  279:         return;
  280: }
  281: 
  282:   283:   284: 
  285: LOCAL   void      poke_mii(NetInf *inf, W adr, W reg, W dat)
  286: {
  287:         wait_mii(inf);
  288:         poke_mac(inf, MII_DATA, dat);
  289:         poke_mac(inf, MII_ACC, (MII_ACC_PHYADR(adr) | MII_ACC_MIIRINDA(reg) |
  290:                                 MII_ACC_MIIBZY | MII_ACC_MIIWnR));
  291:         wait_mii(inf);
  292: 
  293:         return;
  294: }
  295: 
  296:   297:   298: 
  299: LOCAL   UH        peek_mii(NetInf *inf, W adr, W reg)
  300: {
  301:         wait_mii(inf);
  302:         poke_mac(inf, MII_ACC, (MII_ACC_PHYADR(adr) | MII_ACC_MIIRINDA(reg) |
  303:                                 MII_ACC_MIIBZY));
  304:         wait_mii(inf);
  305: 
  306:         return peek_mac(inf, MII_DATA);
  307: }
  308: 
  309:   310:   311: 
  312: #define wait_srom(inf)  wait_reg((inf), E2P_CMD, E2P_CMD_BUSY, 0)
  313: 
  314:   315:   316: 
  317: LOCAL   W peek_srom(NetInf *inf, W adr)
  318: {
  319:         UW     IOB = inf->IOBase;
  320: 
  321:         wait_srom(inf);
  322:         OutW(E2P_CMD, (E2P_CMD_BUSY | E2P_CMD_READ |
  323:                        E2P_CMD_TMO | E2P_CMD_ADDR(adr)));
  324:         wait_srom(inf);
  325: 
  326:         return (InW(E2P_CMD) & E2P_CMD_TMO) ? -1 : InW(E2P_DATA);
  327: }
  328: 
  329:   330:   331: 
  332: LOCAL   void      smsc9118_wakeup(NetInf *inf)
  333: {
  334:         UW     IOB = inf->IOBase;
  335: 
  336:         
  337:         if (InW(PMT_CTRL) & PMT_CTRL_PM_MODE(3)) {
  338:                 OutW(BYTE_TEST, BYTE_TEST_MAGIC);     
  339:                 wait_reg(inf, PMT_CTRL, PMT_CTRL_READY, PMT_CTRL_READY);
  340:         }
  341: 
  342:         
  343:         OutW(PMT_CTRL, PMT_CTRL_PHY_RST);
  344:         WaitUsec(100);
  345:         wait_reg(inf, PMT_CTRL, PMT_CTRL_PHY_RST, 0);
  346: 
  347:         return;
  348: }
  349: 
  350:   351:   352: 
  353: LOCAL   void      smsc9118_phyen(NetInf *inf, BOOL power_on)
  354: {
  355: #define BMCR_PDN        (1 << 11)
  356: 
  357:         W      adr;
  358: 
  359:         adr = MIIfind(inf, 1);
  360:         if (adr >= 0) {
  361:                 if (power_on) {
  362:                         poke_mii(inf, adr, 0,
  363:                                  peek_mii(inf, adr, 0) & ~BMCR_PDN);
  364:                 } else {
  365:                         poke_mii(inf, adr, 0,
  366:                                  peek_mii(inf, adr, 0) | BMCR_PDN);
  367:                 }
  368:         }
  369: 
  370:         return;
  371: }
  372: 
  373:   374:   375: 
  376: LOCAL   void      smsc9118_reset(NetInf *inf, BOOL start)
  377: {
  378:         UW     IOB = inf->IOBase;
  379:         UW     cr;
  380: 
  381:         
  382:         smsc9118_wakeup(inf);
  383: 
  384:         
  385:         OutW(INT_EN, 0);
  386:         inf->IntMask = 0;
  387:         inf->BadState = 0;
  388:         inf->txbusy = FALSE;
  389: 
  390:         
  391:         smsc9118_phyen(inf, TRUE);
  392: 
  393:         
  394:         OutW(HW_CFG, HW_CFG_SRST);
  395:         wait_reg(inf, HW_CFG, HW_CFG_SRST, 0);
  396:         wait_reg(inf, PMT_CTRL, PMT_CTRL_READY, PMT_CTRL_READY);
  397:         if (InW(HW_CFG) & HW_CFG_SRST_TO) inf->BadState = 1;
  398:         wait_srom(inf);                        
  399:         if (start && inf->BadState) goto fin0;
  400: 
  401:         OutW(HW_CFG, HW_CFG_SF | HW_CFG_TX_FIF_SZ(TX_FIFO_SIZE) |
  402:              HW_CFG_PHY_CLK_INT);
  403:         OutW(AFC_CFG, 0x006e3740);
  404:         OutW(FIFO_INT, FIFO_INT_TSFL(0) | FIFO_INT_RSFL(0));
  405:         OutW(RX_CFG, RX_CFG_ALIGN_4 | RX_CFG_DUMP | RX_CFG_DOFF(0));
  406:         wait_reg(inf, RX_CFG, RX_CFG_DUMP, 0);
  407:         OutW(TX_CFG, TX_CFG_SDUMP | TX_CFG_DDUMP);
  408:         wait_reg(inf, TX_CFG, TX_CFG_SDUMP | TX_CFG_DDUMP, 0);
  409: #ifdef  GPIO_CFG_VAL
  410:         OutW(GPIO_CFG, GPIO_CFG_VAL);
  411: #else
  412:         OutW(GPIO_CFG, 0x70000000);    
  413: #endif
  414:         InW(RX_DROP);  
  415: 
  416:         
  417:         poke_mac(inf, ADDRH, *((UH *)&inf->eaddr.c[4]));
  418:         poke_mac(inf, ADDRL, *((UW *)&inf->eaddr.c[0]));
  419: 
  420:         
  421:         poke_mac(inf, HASHH, 0);
  422:         poke_mac(inf, HASHL, 0);
  423: 
  424:         
  425:         MIIinit(inf, 1);
  426: 
  427:         
  428:         if (!start) {
  429:                 smsc9118_phyen(inf, FALSE);
  430:                 goto fin0;
  431:         }
  432: 
  433:         
  434:         tk_dly_tsk(1500);
  435: 
  436:         
  437:         peek_mii(inf, 1, 1);
  438: 
  439:         
  440:         OutW(TX_CFG, TX_CFG_ON);
  441:         cr = MAC_CR_TXEN | MAC_CR_RXEN;
  442:         if (isFDX(inf)) cr |= MAC_CR_FDPX;
  443:         poke_mac(inf, MAC_CR, cr);
  444: 
  445:         
  446: #ifdef  IRQ_CFG_VAL
  447:         OutW(IRQ_CFG, IRQ_CFG_IRQ_EN | IRQ_CFG_VAL);
  448: #else
  449:         OutW(IRQ_CFG, (IRQ_CFG_INT_DEAS(22) |
  450:                        IRQ_CFG_IRQ_EN | IRQ_CFG_IRQ_TYPE)); 
  451: #endif
  452:         inf->IntMask = (INT_TXSTOP | INT_RXSTOP |
  453:                         INT_TSFF | INT_TSFL | INT_RSFF | INT_RSFL);
  454:         OutW(INT_EN, inf->IntMask);
  455:  fin0:
  456:         return;
  457: }
  458: 
  459:   460:   461: 
  462: Inline  void     smsc9118_poprx(NetInf *inf, UB *bp, W len)
  463: {
  464:         UW     IOB = inf->IOBase;
  465:         UW     d;
  466: 
  467:         
  468:         switch ((W)bp & 3) {
  469:         case   0:        
  470:                 for (; len > 7; len -= 4) {
  471:                         *(UW *)bp = InW(RX_DATA);
  472:                         bp += 4;
  473:                 }
  474:                 break;
  475:         case   2:        
  476:                 for (; len > 7; len -= 4) {
  477:                         d = InW(RX_DATA);
  478:                         *(UH *)bp = d;
  479:                         bp += 2;
  480:                         *(UH *)bp = d >> 16;
  481:                         bp += 2;
  482:                 }
  483:                 break;
  484:         default:       
  485:                 for (; len > 7; len -= 4) {
  486:                         d = InW(RX_DATA);
  487:                         *bp++ = d;
  488:                         *bp++ = d >> 8;
  489:                         *bp++ = d >> 16;
  490:                         *bp++ = d >> 24;
  491:                 }
  492:                 break;
  493:         }
  494: 
  495:         
  496:         if (len >= 4) {
  497:                 d = InW(RX_DATA);
  498:                 switch (len) {
  499:                 case  7:       bp[2] = d >> 16;      
  500:                 case  6:       bp[1] = d >> 8;               
  501:                 case  5:       bp[0] = d;            
  502:                 default:      break;
  503:                 }
  504:                 len -= 4;
  505:         }
  506: 
  507:         
  508:         if (len) InW(RX_DATA);
  509: 
  510:         return;
  511: }
  512: 
  513:   514:   515: 
  516: Inline  void     smsc9118_receive(NetInf *inf)
  517: {
  518:         UW     IOB = inf->IOBase;
  519:         UW     i, rxsused, sts, len, pktlen;
  520:         UB     *bp;
  521: 
  522:         
  523:         rxsused = (InW(RX_FIFO_INF) >> 16) & 0xff;
  524: 
  525:         
  526:         for (i = 0; i < rxsused; i++) {
  527:                 sts = InW(RX_STS);
  528:                 len = (sts >> 16) & 0x3fff;   
  529:                 pktlen = len - 4;             
  530: 
  531:                 if (sts & RX_STS_ES) {
  532:                         inf->stinf.rxerr++;
  533:                         inf->stinf.other[2] |= sts;
  534: 
  535:                 } else if ((pktlen < inf->bufsz.minsz) ||
  536:                            (pktlen > inf->bufsz.maxsz)) {
  537:                         inf->stinf.invpkt++;
  538: 
  539:                 } else if (inf->mbfid > 0) {
  540:                         bp = GetRxBuf(inf);
  541: 
  542:                         if (bp == NULL) {
  543:                                 inf->stinf.misspkt++;
  544:                         } else {
  545:                                 
  546:                                 smsc9118_poprx(inf, bp, len);
  547:                                 SendMsg(inf, bp, pktlen);
  548:                                 continue;
  549:                         }
  550:                 }
  551: 
  552:                   553: 
  554:                 len = (len + 3) / 4;
  555:                 if (len >= 4) {
  556:                         OutW(RX_DP_CTL, RX_DP_CTL_FFWD);
  557:                         wait_reg(inf, RX_DP_CTL, RX_DP_CTL_FFWD, 0);
  558:                 } else {
  559:                         for (; len > 0; len--) InW(RX_DATA);
  560:                 }
  561:         }
  562: 
  563:         return;
  564: }
  565: 
  566:   567:   568: 
  569: #define TXFIFOisReady   ((InW(TX_FIFO_INF) & 0xffff) >= MAXPKTLEN + 8)
  570: 
  571:   572:   573: 
  574: Inline  void     smsc9118_sendcomplete(NetInf *inf)
  575: {
  576:         UW     IOB = inf->IOBase;
  577:         UW     i, txsused, sts;
  578: 
  579:         
  580:         txsused = (InW(TX_FIFO_INF) >> 16) & 0xff;
  581: 
  582:         
  583:         for (i = 0; i < txsused; i++) {
  584:                 sts = InW(TX_STS);
  585:                 if (sts & TX_STS_ES) {
  586:                         inf->stinf.txerr++;
  587:                         inf->stinf.other[1] |= sts;
  588:                 }
  589:                 inf->stinf.collision += (sts >> 3) & 0x0f;
  590:         }
  591: 
  592:           593: 
  594:         if (inf->txbusy && TXFIFOisReady) {
  595:                 inf->txbusy = FALSE;
  596:                 SendMsg(inf, NULL, 0);
  597:         }
  598: 
  599:         return;
  600: }
  601: 
  602:   603:   604: 
  605: LOCAL   void      smsc9118_inthdr(NetInf *inf)
  606: {
  607:         UW     IOB = inf->IOBase;
  608:         UW     sts, limit;
  609: 
  610:         inf->stinf.nint++;
  611:         limit = 1000000;       
  612: 
  613:         while (1) {
  614:                 
  615:                 sts = InW(INT_STS);
  616:                 OutW(INT_STS, sts & ~inf->IntMask);
  617: 
  618:                 
  619:                 if (!(sts & inf->IntMask)) break;
  620: 
  621:                 
  622:                 if (--limit < 0) {
  623:                         inf->stinf.hwerr++;
  624:                         smsc9118_reset(inf, FALSE);
  625:                         break;
  626:                 }
  627: 
  628:                 
  629:                 if (sts & (INT_RSFF | INT_RSFL)) {
  630:                         inf->stinf.rxint++;
  631:                         smsc9118_receive(inf);
  632:                         OutW(INT_STS, sts & (INT_RSFF | INT_RSFL));
  633:                 }
  634: 
  635:                 
  636:                 if (sts & (INT_TSFF | INT_TSFL)) {
  637:                         inf->stinf.txint++;
  638:                         smsc9118_sendcomplete(inf);
  639:                         OutW(INT_STS, sts & (INT_TSFF | INT_TSFL));
  640:                 }
  641: 
  642:                 
  643:                 if (sts & (INT_TXSTOP | INT_RXSTOP)) {
  644:                         inf->stinf.hwerr++;
  645:                         smsc9118_reset(inf, TRUE);
  646:                         break;
  647:                 }
  648: 
  649:                 
  650:                 InW(BYTE_TEST);
  651:         }
  652: 
  653:         return;
  654: }
  655: 
  656:   657:   658: 
  659: LOCAL   INT       smsc9118_send(NetInf *inf, UB *buf, W len)
  660: {
  661:         UW     IOB = inf->IOBase;
  662:         UW     i, d, ofs;
  663: 
  664:           665: 
  666:         if (!inf->IntMask || inf->txbusy) {
  667:                 inf->stinf.txbusy++;
  668:                 return E_BUSY;
  669:         }
  670: 
  671:         
  672:         OutW(INT_EN, 0);
  673: 
  674:         
  675:         len = (len < MAXPKTLEN) ? len : MAXPKTLEN;
  676: 
  677:         
  678:         ofs = (W)buf & 3;
  679: 
  680:         
  681:         OutW(TX_DATA, (TX_CMDA_ALIGN_4 | TX_CMDA_OFFSET(ofs) |
  682:                        TX_CMDA_FS | TX_CMDA_LS | TX_CMDA_BUFSZ(len)));
  683:         OutW(TX_DATA, TX_CMDB_PADDIS | TX_CMDB_PKTSZ(len));
  684: 
  685:         
  686:         if (ofs) {
  687:                 for (d = i = 0; i < 4 - ofs && len > 0; i++, len--, buf++) {
  688:                         d |= *buf << (((W)buf & 3) * 8);
  689:                 }
  690:                 OutW(TX_DATA, d);
  691:         }
  692: 
  693:         
  694:         for (; len > 3; len -= 4, buf += 4) OutW(TX_DATA, *(UW *)buf);
  695: 
  696:         
  697:         if (len) {
  698:                 d = 0;
  699:                 switch (len) {
  700:                 case  3:       d |= (buf[2] << 16);  
  701:                 case  2:       d |= (buf[1] << 8);   
  702:                 case  1:       d |=  buf[0];         
  703:                 default:      break;
  704:                 }
  705:                 OutW(TX_DATA, d);
  706:         }
  707: 
  708:           709: 
  710:         if (TXFIFOisReady) {
  711:                 SendMsg(inf, NULL, 0);
  712:         } else {
  713:                 inf->txbusy = TRUE;
  714:         }
  715: 
  716:         
  717:         OutW(INT_EN, inf->IntMask);
  718:         inf->stinf.txpkt++;
  719: 
  720:         return len;
  721: }
  722: 
  723:   724:   725: 
  726: LOCAL   void      smsc9118_getstatus(NetInf *inf)
  727: {
  728:         UW     IOB = inf->IOBase;
  729: 
  730:         
  731:         if (!inf->opencnt) goto fin0;
  732: 
  733:         inf->stinf.overrun += InW(RX_DROP);
  734: 
  735:           736:   737:   738:   739:   740:   741: 
  742:         if (!(InW(PMT_CTRL) & PMT_CTRL_READY) ||
  743:             InW(BYTE_TEST) != BYTE_TEST_MAGIC ||
  744:             inf->txbusy || ((InW(TX_FIFO_INF) >> 16) & 0xff) ||
  745:             (InW(TX_FIFO_INF) & 0xffff) < (TX_FIFO_SIZE * 1024 - 512) ||
  746:             (peek_mii(inf, 1, 2) != 0x0007)) {
  747:                 inf->BadState = 1;
  748:         }
  749: 
  750:         
  751:         if (inf->BadState) {
  752:                 inf->stinf.other[0]++;
  753:                 DP(("smsc9118_getstatus: Bad state, try restart\n"));
  754: 
  755:                 smsc9118_reset(inf, TRUE);
  756:         }
  757: 
  758:  fin0:
  759:         return;
  760: }
  761: 
  762:   763:   764: 
  765: LOCAL   W smsc9118_probe(NetInf *inf)
  766: {
  767:         UW     IOB = inf->IOBase;
  768:         W      i, err;
  769: 
  770:         
  771:         inf->IntMask = 0;
  772: 
  773:         
  774:         smsc9118_wakeup(inf);
  775: 
  776:         
  777:         if (InW(BYTE_TEST) != BYTE_TEST_MAGIC) {
  778:                 DP(("smsc9118_probe: LAN911x not found\n"));
  779:                 err = E_NOMDA;
  780:                 goto fin0;
  781:         }
  782: 
  783:         
  784:         if (inf->di.stat < E_OK) {
  785:                 err = E_OK;
  786:                 goto fin0;
  787:         }
  788: 
  789:         
  790:         OutW(INT_EN, 0);                               
  791:         OutW(TX_CFG, TX_CFG_STOP);                     
  792:         wait_reg(inf, TX_CFG, TX_CFG_STOP, 0);
  793:         poke_mac(inf, MAC_CR,
  794:                  peek_mac(inf, MAC_CR) & ~(MAC_CR_TXEN | MAC_CR_RXEN));
  795: 
  796:         
  797:         smsc9118_phyen(inf, FALSE);
  798: 
  799:         
  800:         inf->ChipID = InW(ID_REV);
  801:         DP(("smsc9118_probe: ID_REV %#x\n", inf->ChipID));
  802: 
  803:         
  804:         for (i = 0; i < L_EADDR; i++) {
  805:                 inf->eaddr.c[i] = peek_srom(inf, i + 1);
  806:                 DP(("%02x ", inf->eaddr.c[i]));
  807:         }
  808:         DP(("\n"));
  809: 
  810:         
  811:         err = E_OK;
  812:  fin0:
  813:         return err;
  814: }
  815: 
  816:   817:   818:   819:   820:   821:   822:   823:   824:   825:   826:   827:   828:   829:   830:   831:   832:   833:   834:   835:   836:   837:   838:   839:   840:   841:   842:   843:   844:   845:   846:   847:   848:   849:   850:   851:   852:   853:   854:   855:   856:   857:   858:   859:   860:   861:   862:   863:   864:   865:   866: 
  867: EXPORT  ER       InitSMSC9118(NetInf *inf, W init)
  868: {
  869:         ER     err;
  870: 
  871:         
  872:         if (init < 0) goto fin1;
  873: 
  874:         inf->di.iosize = SMSC9118_IOSZ;
  875: 
  876:         DP(("Net%c: InitSMSC9118 kind:%#x\n", NetUnit(inf), inf->di.kind));
  877: 
  878:         
  879:         inf->mii_read  = peek_mii;
  880:         inf->mii_write = poke_mii;
  881: 
  882:         
  883:         err = smsc9118_probe(inf);
  884:         if (err < E_OK) goto fin0;
  885: 
  886:         
  887:         SetProdName(inf, (UB **)SMSC9118_PNAME1, (UB **)SMSC9118_PNAME2);
  888: 
  889:         
  890:         inf->inthdr  = smsc9118_inthdr;
  891:         inf->sendfn  = smsc9118_send;
  892:         inf->reset   = smsc9118_reset;
  893:         inf->cardchk = NULL;
  894:         inf->misc    = NULL;
  895:         inf->mcast   = NULL;
  896:         inf->tmout   = 10000;
  897:         inf->tmofn   = smsc9118_getstatus;
  898: 
  899:  fin1:
  900:         err = E_OK;
  901:  fin0:
  902:         return err;
  903: }
  904: