Annotation of qemu/roms/ipxe/src/drivers/net/smc9000.c, revision 1.1

1.1     ! root        1: #ifdef ALLMULTI
        !             2: #error multicast support is not yet implemented
        !             3: #endif
        !             4:  /*------------------------------------------------------------------------
        !             5:  * smc9000.c
        !             6:  * This is a Etherboot driver for SMC's 9000 series of Ethernet cards.
        !             7:  *
        !             8:  * Copyright (C) 1998 Daniel Engstr�m <[email protected]>
        !             9:  * Based on the Linux SMC9000 driver, smc9194.c by Eric Stahlman
        !            10:  * Copyright (C) 1996 by Erik Stahlman <[email protected]>
        !            11:  *
        !            12:  * This software may be used and distributed according to the terms
        !            13:  * of the GNU Public License, incorporated herein by reference.
        !            14:  *
        !            15:  * "Features" of the SMC chip:
        !            16:  *   4608 byte packet memory. ( for the 91C92/4.  Others have more )
        !            17:  *   EEPROM for configuration
        !            18:  *   AUI/TP selection
        !            19:  *
        !            20:  * Authors
        !            21:  *     Erik Stahlman                           <[email protected]>
        !            22:  *      Daniel Engstr�m                         <[email protected]>
        !            23:  *
        !            24:  * History
        !            25:  * 98-09-25              Daniel Engstr�m Etherboot driver crated from Eric's
        !            26:  *                                       Linux driver.
        !            27:  *
        !            28:  *---------------------------------------------------------------------------*/
        !            29: 
        !            30: FILE_LICENCE ( GPL_ANY );
        !            31: 
        !            32: #define LINUX_OUT_MACROS 1
        !            33: #define SMC9000_DEBUG    0
        !            34: 
        !            35: #if SMC9000_DEBUG > 1
        !            36: #define PRINTK2 printf
        !            37: #else
        !            38: #define PRINTK2(args...)
        !            39: #endif
        !            40: 
        !            41: #include <ipxe/ethernet.h>
        !            42: #include <errno.h>
        !            43: #include "etherboot.h"
        !            44: #include "nic.h"
        !            45: #include <ipxe/isa.h>
        !            46: #include "smc9000.h"
        !            47: 
        !            48: # define _outb outb
        !            49: # define _outw outw
        !            50: 
        !            51: static const char       smc9000_version[] = "Version 0.99 98-09-30";
        !            52: static const char       *interfaces[ 2 ] = { "TP", "AUI" };
        !            53: static const char       *chip_ids[ 15 ] =  {
        !            54:    NULL, NULL, NULL,
        !            55:    /* 3 */ "SMC91C90/91C92",
        !            56:    /* 4 */ "SMC91C94",
        !            57:    /* 5 */ "SMC91C95",
        !            58:    NULL,
        !            59:    /* 7 */ "SMC91C100",
        !            60:    /* 8 */ "SMC91C100FD",
        !            61:    /* 9 */ "SMC91C11xFD",
        !            62:    NULL, NULL,
        !            63:    NULL, NULL, NULL
        !            64: };
        !            65: static const char      smc91c96_id[] = "SMC91C96";
        !            66: 
        !            67: /*------------------------------------------------------------
        !            68:  . Reads a register from the MII Management serial interface
        !            69:  .-------------------------------------------------------------*/
        !            70: static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg)
        !            71: {
        !            72:     int oldBank;
        !            73:     unsigned int i;
        !            74:     byte mask;
        !            75:     word mii_reg;
        !            76:     byte bits[64];
        !            77:     int clk_idx = 0;
        !            78:     int input_idx;
        !            79:     word phydata;
        !            80: 
        !            81:     // 32 consecutive ones on MDO to establish sync
        !            82:     for (i = 0; i < 32; ++i)
        !            83:         bits[clk_idx++] = MII_MDOE | MII_MDO;
        !            84: 
        !            85:     // Start code <01>
        !            86:     bits[clk_idx++] = MII_MDOE;
        !            87:     bits[clk_idx++] = MII_MDOE | MII_MDO;
        !            88: 
        !            89:     // Read command <10>
        !            90:     bits[clk_idx++] = MII_MDOE | MII_MDO;
        !            91:     bits[clk_idx++] = MII_MDOE;
        !            92: 
        !            93:     // Output the PHY address, msb first
        !            94:     mask = (byte)0x10;
        !            95:     for (i = 0; i < 5; ++i)
        !            96:     {
        !            97:         if (phyaddr & mask)
        !            98:             bits[clk_idx++] = MII_MDOE | MII_MDO;
        !            99:         else
        !           100:             bits[clk_idx++] = MII_MDOE;
        !           101: 
        !           102:         // Shift to next lowest bit
        !           103:         mask >>= 1;
        !           104:     }
        !           105: 
        !           106:     // Output the phy register number, msb first
        !           107:     mask = (byte)0x10;
        !           108:     for (i = 0; i < 5; ++i)
        !           109:     {
        !           110:         if (phyreg & mask)
        !           111:             bits[clk_idx++] = MII_MDOE | MII_MDO;
        !           112:         else
        !           113:             bits[clk_idx++] = MII_MDOE;
        !           114: 
        !           115:         // Shift to next lowest bit
        !           116:         mask >>= 1;
        !           117:     }
        !           118: 
        !           119:     // Tristate and turnaround (2 bit times)
        !           120:     bits[clk_idx++] = 0;
        !           121:     //bits[clk_idx++] = 0;
        !           122: 
        !           123:     // Input starts at this bit time
        !           124:     input_idx = clk_idx;
        !           125: 
        !           126:     // Will input 16 bits
        !           127:     for (i = 0; i < 16; ++i)
        !           128:         bits[clk_idx++] = 0;
        !           129: 
        !           130:     // Final clock bit
        !           131:     bits[clk_idx++] = 0;
        !           132: 
        !           133:     // Save the current bank
        !           134:     oldBank = inw( ioaddr+BANK_SELECT );
        !           135: 
        !           136:     // Select bank 3
        !           137:     SMC_SELECT_BANK(ioaddr, 3);
        !           138: 
        !           139:     // Get the current MII register value
        !           140:     mii_reg = inw( ioaddr+MII_REG );
        !           141: 
        !           142:     // Turn off all MII Interface bits
        !           143:     mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
        !           144: 
        !           145:     // Clock all 64 cycles
        !           146:     for (i = 0; i < sizeof(bits); ++i)
        !           147:     {
        !           148:         // Clock Low - output data
        !           149:         outw( mii_reg | bits[i], ioaddr+MII_REG );
        !           150:         udelay(50);
        !           151: 
        !           152: 
        !           153:         // Clock Hi - input data
        !           154:         outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
        !           155:         udelay(50);
        !           156:         bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
        !           157:     }
        !           158: 
        !           159:     // Return to idle state
        !           160:     // Set clock to low, data to low, and output tristated
        !           161:     outw( mii_reg, ioaddr+MII_REG );
        !           162:     udelay(50);
        !           163: 
        !           164:     // Restore original bank select
        !           165:     SMC_SELECT_BANK(ioaddr, oldBank);
        !           166: 
        !           167:     // Recover input data
        !           168:     phydata = 0;
        !           169:     for (i = 0; i < 16; ++i)
        !           170:     {
        !           171:         phydata <<= 1;
        !           172: 
        !           173:         if (bits[input_idx++] & MII_MDI)
        !           174:             phydata |= 0x0001;
        !           175:     }
        !           176: 
        !           177: #if (SMC_DEBUG > 2 )
        !           178:         printf("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
        !           179:                phyaddr, phyreg, phydata);
        !           180: #endif
        !           181: 
        !           182:         return(phydata);
        !           183: }
        !           184: 
        !           185: 
        !           186: /*------------------------------------------------------------
        !           187:  . Writes a register to the MII Management serial interface
        !           188:  .-------------------------------------------------------------*/
        !           189: static void smc_write_phy_register(int ioaddr,
        !           190:                                    byte phyaddr, byte phyreg, word phydata)
        !           191: {
        !           192:     int oldBank;
        !           193:     unsigned int i;
        !           194:     word mask;
        !           195:     word mii_reg;
        !           196:     byte bits[65];
        !           197:     int clk_idx = 0;
        !           198: 
        !           199:     // 32 consecutive ones on MDO to establish sync
        !           200:     for (i = 0; i < 32; ++i)
        !           201:         bits[clk_idx++] = MII_MDOE | MII_MDO;
        !           202: 
        !           203:     // Start code <01>
        !           204:     bits[clk_idx++] = MII_MDOE;
        !           205:     bits[clk_idx++] = MII_MDOE | MII_MDO;
        !           206: 
        !           207:     // Write command <01>
        !           208:     bits[clk_idx++] = MII_MDOE;
        !           209:     bits[clk_idx++] = MII_MDOE | MII_MDO;
        !           210: 
        !           211:     // Output the PHY address, msb first
        !           212:     mask = (byte)0x10;
        !           213:     for (i = 0; i < 5; ++i)
        !           214:     {
        !           215:         if (phyaddr & mask)
        !           216:             bits[clk_idx++] = MII_MDOE | MII_MDO;
        !           217:         else
        !           218:             bits[clk_idx++] = MII_MDOE;
        !           219: 
        !           220:                 // Shift to next lowest bit
        !           221:         mask >>= 1;
        !           222:     }
        !           223: 
        !           224:     // Output the phy register number, msb first
        !           225:     mask = (byte)0x10;
        !           226:     for (i = 0; i < 5; ++i)
        !           227:     {
        !           228:         if (phyreg & mask)
        !           229:             bits[clk_idx++] = MII_MDOE | MII_MDO;
        !           230:         else
        !           231:             bits[clk_idx++] = MII_MDOE;
        !           232: 
        !           233:         // Shift to next lowest bit
        !           234:         mask >>= 1;
        !           235:     }
        !           236: 
        !           237:     // Tristate and turnaround (2 bit times)
        !           238:     bits[clk_idx++] = 0;
        !           239:     bits[clk_idx++] = 0;
        !           240: 
        !           241:     // Write out 16 bits of data, msb first
        !           242:     mask = 0x8000;
        !           243:     for (i = 0; i < 16; ++i)
        !           244:     {
        !           245:         if (phydata & mask)
        !           246:             bits[clk_idx++] = MII_MDOE | MII_MDO;
        !           247:         else
        !           248:             bits[clk_idx++] = MII_MDOE;
        !           249: 
        !           250:         // Shift to next lowest bit
        !           251:         mask >>= 1;
        !           252:     }
        !           253: 
        !           254:     // Final clock bit (tristate)
        !           255:     bits[clk_idx++] = 0;
        !           256: 
        !           257:     // Save the current bank
        !           258:     oldBank = inw( ioaddr+BANK_SELECT );
        !           259: 
        !           260:     // Select bank 3
        !           261:     SMC_SELECT_BANK(ioaddr, 3);
        !           262: 
        !           263:     // Get the current MII register value
        !           264:     mii_reg = inw( ioaddr+MII_REG );
        !           265: 
        !           266:     // Turn off all MII Interface bits
        !           267:     mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
        !           268: 
        !           269:     // Clock all cycles
        !           270:     for (i = 0; i < sizeof(bits); ++i)
        !           271:     {
        !           272:         // Clock Low - output data
        !           273:         outw( mii_reg | bits[i], ioaddr+MII_REG );
        !           274:         udelay(50);
        !           275: 
        !           276: 
        !           277:         // Clock Hi - input data
        !           278:         outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
        !           279:         udelay(50);
        !           280:         bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
        !           281:     }
        !           282: 
        !           283:     // Return to idle state
        !           284:     // Set clock to low, data to low, and output tristated
        !           285:     outw( mii_reg, ioaddr+MII_REG );
        !           286:     udelay(50);
        !           287: 
        !           288:     // Restore original bank select
        !           289:     SMC_SELECT_BANK(ioaddr, oldBank);
        !           290: 
        !           291: #if (SMC_DEBUG > 2 )
        !           292:         printf("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
        !           293:                phyaddr, phyreg, phydata);
        !           294: #endif
        !           295: }
        !           296: 
        !           297: 
        !           298: /*------------------------------------------------------------
        !           299:  . Finds and reports the PHY address
        !           300:  .-------------------------------------------------------------*/
        !           301: static int smc_detect_phy(int ioaddr, byte *pphyaddr)
        !           302: {
        !           303:     word phy_id1;
        !           304:     word phy_id2;
        !           305:     int phyaddr;
        !           306:     int found = 0;
        !           307: 
        !           308:     // Scan all 32 PHY addresses if necessary
        !           309:     for (phyaddr = 0; phyaddr < 32; ++phyaddr)
        !           310:     {
        !           311:         // Read the PHY identifiers
        !           312:         phy_id1  = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG);
        !           313:         phy_id2  = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG);
        !           314: 
        !           315:         // Make sure it is a valid identifier
        !           316:         if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) &&
        !           317:              (phy_id1 > 0x0000) && (phy_id1 < 0xffff))
        !           318:         {
        !           319:             if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000))
        !           320:             {
        !           321:                 // Save the PHY's address
        !           322:                 *pphyaddr = phyaddr;
        !           323:                 found = 1;
        !           324:                 break;
        !           325:             }
        !           326:         }
        !           327:     }
        !           328: 
        !           329:     if (!found)
        !           330:     {
        !           331:         printf("No PHY found\n");
        !           332:         return(0);
        !           333:     }
        !           334: 
        !           335:     // Set the PHY type
        !           336:     if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) )
        !           337:     {
        !           338:         printf("PHY=LAN83C183 (LAN91C111 Internal)\n");
        !           339:     }
        !           340: 
        !           341:     if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) )
        !           342:     {
        !           343:         printf("PHY=LAN83C180\n");
        !           344:     }
        !           345: 
        !           346:     return(1);
        !           347: }
        !           348: 
        !           349: /*------------------------------------------------------------
        !           350:  . Configures the specified PHY using Autonegotiation. Calls
        !           351:  . smc_phy_fixed() if the user has requested a certain config.
        !           352:  .-------------------------------------------------------------*/
        !           353: static void smc_phy_configure(int ioaddr)
        !           354: {
        !           355:     int timeout;
        !           356:     byte phyaddr;
        !           357:     word my_phy_caps; // My PHY capabilities
        !           358:     word my_ad_caps; // My Advertised capabilities
        !           359:     word status;
        !           360:     int rpc_cur_mode = RPC_DEFAULT;
        !           361:     int lastPhy18;
        !           362: 
        !           363:     // Find the address and type of our phy
        !           364:     if (!smc_detect_phy(ioaddr, &phyaddr))
        !           365:     {
        !           366:         return;
        !           367:     }
        !           368: 
        !           369:     // Reset the PHY, setting all other bits to zero
        !           370:     smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST);
        !           371: 
        !           372:     // Wait for the reset to complete, or time out
        !           373:     timeout = 6; // Wait up to 3 seconds
        !           374:     while (timeout--)
        !           375:     {
        !           376:         if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG)
        !           377:               & PHY_CNTL_RST))
        !           378:         {
        !           379:             // reset complete
        !           380:             break;
        !           381:         }
        !           382: 
        !           383:         mdelay(500); // wait 500 millisecs
        !           384:     }
        !           385: 
        !           386:     if (timeout < 1)
        !           387:     {
        !           388:         PRINTK2("PHY reset timed out\n");
        !           389:         return;
        !           390:     }
        !           391: 
        !           392:     // Read PHY Register 18, Status Output
        !           393:     lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
        !           394: 
        !           395:     // Enable PHY Interrupts (for register 18)
        !           396:     // Interrupts listed here are disabled
        !           397:     smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG,
        !           398:                            PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
        !           399:                                    PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
        !           400:                                    PHY_INT_SPDDET | PHY_INT_DPLXDET);
        !           401: 
        !           402:     /* Configure the Receive/Phy Control register */
        !           403:     SMC_SELECT_BANK(ioaddr, 0);
        !           404:     outw( rpc_cur_mode, ioaddr + RPC_REG );
        !           405: 
        !           406:     // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG
        !           407:     my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
        !           408:     my_ad_caps  = PHY_AD_CSMA; // I am CSMA capable
        !           409: 
        !           410:     if (my_phy_caps & PHY_STAT_CAP_T4)
        !           411:         my_ad_caps |= PHY_AD_T4;
        !           412: 
        !           413:     if (my_phy_caps & PHY_STAT_CAP_TXF)
        !           414:         my_ad_caps |= PHY_AD_TX_FDX;
        !           415: 
        !           416:     if (my_phy_caps & PHY_STAT_CAP_TXH)
        !           417:         my_ad_caps |= PHY_AD_TX_HDX;
        !           418: 
        !           419:     if (my_phy_caps & PHY_STAT_CAP_TF)
        !           420:         my_ad_caps |= PHY_AD_10_FDX;
        !           421: 
        !           422:     if (my_phy_caps & PHY_STAT_CAP_TH)
        !           423:         my_ad_caps |= PHY_AD_10_HDX;
        !           424: 
        !           425:     // Update our Auto-Neg Advertisement Register
        !           426:     smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps);
        !           427: 
        !           428:     PRINTK2("phy caps=%x\n", my_phy_caps);
        !           429:     PRINTK2("phy advertised caps=%x\n", my_ad_caps);
        !           430: 
        !           431:     // Restart auto-negotiation process in order to advertise my caps
        !           432:     smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
        !           433:                             PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );
        !           434: 
        !           435:     // Wait for the auto-negotiation to complete.  This may take from
        !           436:     // 2 to 3 seconds.
        !           437:     // Wait for the reset to complete, or time out
        !           438:     timeout = 20; // Wait up to 10 seconds
        !           439:     while (timeout--)
        !           440:     {
        !           441:         status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
        !           442:         if (status & PHY_STAT_ANEG_ACK)
        !           443:         {
        !           444:             // auto-negotiate complete
        !           445:             break;
        !           446:         }
        !           447: 
        !           448:         mdelay(500); // wait 500 millisecs
        !           449: 
        !           450:         // Restart auto-negotiation if remote fault
        !           451:         if (status & PHY_STAT_REM_FLT)
        !           452:         {
        !           453:             PRINTK2("PHY remote fault detected\n");
        !           454: 
        !           455:             // Restart auto-negotiation
        !           456:             PRINTK2("PHY restarting auto-negotiation\n");
        !           457:             smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
        !           458:                                     PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST |
        !           459:                                     PHY_CNTL_SPEED | PHY_CNTL_DPLX);
        !           460:         }
        !           461:     }
        !           462: 
        !           463:     if (timeout < 1)
        !           464:     {
        !           465:         PRINTK2("PHY auto-negotiate timed out\n");
        !           466:     }
        !           467: 
        !           468:     // Fail if we detected an auto-negotiate remote fault
        !           469:     if (status & PHY_STAT_REM_FLT)
        !           470:     {
        !           471:         PRINTK2("PHY remote fault detected\n");
        !           472:     }
        !           473: 
        !           474:     // Set our sysctl parameters to match auto-negotiation results
        !           475:     if ( lastPhy18 & PHY_INT_SPDDET )
        !           476:     {
        !           477:         PRINTK2("PHY 100BaseT\n");
        !           478:         rpc_cur_mode |= RPC_SPEED;
        !           479:     }
        !           480:     else
        !           481:     {
        !           482:         PRINTK2("PHY 10BaseT\n");
        !           483:         rpc_cur_mode &= ~RPC_SPEED;
        !           484:     }
        !           485: 
        !           486:     if ( lastPhy18 & PHY_INT_DPLXDET )
        !           487:     {
        !           488:         PRINTK2("PHY Full Duplex\n");
        !           489:         rpc_cur_mode |= RPC_DPLX;
        !           490:     }
        !           491:     else
        !           492:     {
        !           493:         PRINTK2("PHY Half Duplex\n");
        !           494:         rpc_cur_mode &= ~RPC_DPLX;
        !           495:     }
        !           496: 
        !           497:     // Re-Configure the Receive/Phy Control register
        !           498:     outw( rpc_cur_mode, ioaddr + RPC_REG );
        !           499: }
        !           500: 
        !           501: /*
        !           502:  * Function: smc_reset( int ioaddr )
        !           503:  * Purpose:
        !           504:  *     This sets the SMC91xx chip to its normal state, hopefully from whatever
        !           505:  *     mess that any other DOS driver has put it in.
        !           506:  *
        !           507:  * Maybe I should reset more registers to defaults in here?  SOFTRESET  should
        !           508:  * do that for me.
        !           509:  *
        !           510:  * Method:
        !           511:  *     1.  send a SOFT RESET
        !           512:  *     2.  wait for it to finish
        !           513:  *     3.  reset the memory management unit
        !           514:  *      4.  clear all interrupts
        !           515:  *
        !           516: */
        !           517: static void smc_reset(int ioaddr)
        !           518: {
        !           519:    /* This resets the registers mostly to defaults, but doesn't
        !           520:     * affect EEPROM.  That seems unnecessary */
        !           521:    SMC_SELECT_BANK(ioaddr, 0);
        !           522:    _outw( RCR_SOFTRESET, ioaddr + RCR );
        !           523: 
        !           524:    /* this should pause enough for the chip to be happy */
        !           525:    SMC_DELAY(ioaddr);
        !           526: 
        !           527:    /* Set the transmit and receive configuration registers to
        !           528:     * default values */
        !           529:    _outw(RCR_CLEAR, ioaddr + RCR);
        !           530:    _outw(TCR_CLEAR, ioaddr + TCR);
        !           531: 
        !           532:    /* Reset the MMU */
        !           533:    SMC_SELECT_BANK(ioaddr, 2);
        !           534:    _outw( MC_RESET, ioaddr + MMU_CMD );
        !           535: 
        !           536:    /* Note:  It doesn't seem that waiting for the MMU busy is needed here,
        !           537:     * but this is a place where future chipsets _COULD_ break.  Be wary
        !           538:     * of issuing another MMU command right after this */
        !           539:    _outb(0, ioaddr + INT_MASK);
        !           540: }
        !           541: 
        !           542: 
        !           543: /*----------------------------------------------------------------------
        !           544:  * Function: smc9000_probe_addr( int ioaddr )
        !           545:  *
        !           546:  * Purpose:
        !           547:  *     Tests to see if a given ioaddr points to an SMC9xxx chip.
        !           548:  *     Returns a 1 on success
        !           549:  *
        !           550:  * Algorithm:
        !           551:  *     (1) see if the high byte of BANK_SELECT is 0x33
        !           552:  *     (2) compare the ioaddr with the base register's address
        !           553:  *     (3) see if I recognize the chip ID in the appropriate register
        !           554:  *
        !           555:  * ---------------------------------------------------------------------
        !           556:  */
        !           557: static int smc9000_probe_addr( isa_probe_addr_t ioaddr )
        !           558: {
        !           559:    word bank;
        !           560:    word        revision_register;
        !           561:    word base_address_register;
        !           562: 
        !           563:    /* First, see if the high byte is 0x33 */
        !           564:    bank = inw(ioaddr + BANK_SELECT);
        !           565:    if ((bank & 0xFF00) != 0x3300) {
        !           566:       return 0;
        !           567:    }
        !           568:    /* The above MIGHT indicate a device, but I need to write to further
        !           569:     *  test this.  */
        !           570:    _outw(0x0, ioaddr + BANK_SELECT);
        !           571:    bank = inw(ioaddr + BANK_SELECT);
        !           572:    if ((bank & 0xFF00) != 0x3300) {
        !           573:       return 0;
        !           574:    }
        !           575: 
        !           576:    /* well, we've already written once, so hopefully another time won't
        !           577:     *  hurt.  This time, I need to switch the bank register to bank 1,
        !           578:     *  so I can access the base address register */
        !           579:    SMC_SELECT_BANK(ioaddr, 1);
        !           580:    base_address_register = inw(ioaddr + BASE);
        !           581: 
        !           582:    if (ioaddr != (base_address_register >> 3 & 0x3E0))  {
        !           583:       DBG("SMC9000: IOADDR %hX doesn't match configuration (%hX)."
        !           584:          "Probably not a SMC chip\n",
        !           585:          ioaddr, base_address_register >> 3 & 0x3E0);
        !           586:       /* well, the base address register didn't match.  Must not have
        !           587:        * been a SMC chip after all. */
        !           588:       return 0;
        !           589:    }
        !           590: 
        !           591: 
        !           592:    /* check if the revision register is something that I recognize.
        !           593:     * These might need to be added to later, as future revisions
        !           594:     * could be added.  */
        !           595:    SMC_SELECT_BANK(ioaddr, 3);
        !           596:    revision_register  = inw(ioaddr + REVISION);
        !           597:    if (!chip_ids[(revision_register >> 4) & 0xF]) {
        !           598:       /* I don't recognize this chip, so... */
        !           599:       DBG( "SMC9000: IO %hX: Unrecognized revision register:"
        !           600:           " %hX, Contact author.\n", ioaddr, revision_register );
        !           601:       return 0;
        !           602:    }
        !           603: 
        !           604:    /* at this point I'll assume that the chip is an SMC9xxx.
        !           605:     * It might be prudent to check a listing of MAC addresses
        !           606:     * against the hardware address, or do some other tests. */
        !           607:    return 1;
        !           608: }
        !           609: 
        !           610: 
        !           611: /**************************************************************************
        !           612:  * ETH_TRANSMIT - Transmit a frame
        !           613:  ***************************************************************************/
        !           614: static void smc9000_transmit(
        !           615:        struct nic *nic,
        !           616:        const char *d,                  /* Destination */
        !           617:        unsigned int t,                 /* Type */
        !           618:        unsigned int s,                 /* size */
        !           619:        const char *p)                  /* Packet */
        !           620: {
        !           621:    word length; /* real, length incl. header */
        !           622:    word numPages;
        !           623:    unsigned long time_out;
        !           624:    byte        packet_no;
        !           625:    word status;
        !           626:    int i;
        !           627: 
        !           628:    /* We dont pad here since we can have the hardware doing it for us */
        !           629:    length = (s + ETH_HLEN + 1)&~1;
        !           630: 
        !           631:    /* convert to MMU pages */
        !           632:    numPages = length / 256;
        !           633: 
        !           634:    if (numPages > 7 ) {
        !           635:       DBG("SMC9000: Far too big packet error. \n");
        !           636:       return;
        !           637:    }
        !           638: 
        !           639:    /* dont try more than, say 30 times */
        !           640:    for (i=0;i<30;i++) {
        !           641:       /* now, try to allocate the memory */
        !           642:       SMC_SELECT_BANK(nic->ioaddr, 2);
        !           643:       _outw(MC_ALLOC | numPages, nic->ioaddr + MMU_CMD);
        !           644: 
        !           645:       status = 0;
        !           646:       /* wait for the memory allocation to finnish */
        !           647:       for (time_out = currticks() + 5*TICKS_PER_SEC; currticks() < time_out; ) {
        !           648:         status = inb(nic->ioaddr + INTERRUPT);
        !           649:         if ( status & IM_ALLOC_INT ) {
        !           650:            /* acknowledge the interrupt */
        !           651:            _outb(IM_ALLOC_INT, nic->ioaddr + INTERRUPT);
        !           652:            break;
        !           653:         }
        !           654:       }
        !           655: 
        !           656:       if ((status & IM_ALLOC_INT) != 0 ) {
        !           657:         /* We've got the memory */
        !           658:         break;
        !           659:       } else {
        !           660:         printf("SMC9000: Memory allocation timed out, resetting MMU.\n");
        !           661:         _outw(MC_RESET, nic->ioaddr + MMU_CMD);
        !           662:       }
        !           663:    }
        !           664: 
        !           665:    /* If I get here, I _know_ there is a packet slot waiting for me */
        !           666:    packet_no = inb(nic->ioaddr + PNR_ARR + 1);
        !           667:    if (packet_no & 0x80) {
        !           668:       /* or isn't there?  BAD CHIP! */
        !           669:       printf("SMC9000: Memory allocation failed. \n");
        !           670:       return;
        !           671:    }
        !           672: 
        !           673:    /* we have a packet address, so tell the card to use it */
        !           674:    _outb(packet_no, nic->ioaddr + PNR_ARR);
        !           675: 
        !           676:    /* point to the beginning of the packet */
        !           677:    _outw(PTR_AUTOINC, nic->ioaddr + POINTER);
        !           678: 
        !           679: #if    SMC9000_DEBUG > 2
        !           680:    printf("Trying to xmit packet of length %hX\n", length );
        !           681: #endif
        !           682: 
        !           683:    /* send the packet length ( +6 for status, length and ctl byte )
        !           684:     * and the status word ( set to zeros ) */
        !           685:    _outw(0, nic->ioaddr + DATA_1 );
        !           686: 
        !           687:    /* send the packet length ( +6 for status words, length, and ctl) */
        !           688:    _outb((length+6) & 0xFF,  nic->ioaddr + DATA_1);
        !           689:    _outb((length+6) >> 8 ,   nic->ioaddr + DATA_1);
        !           690: 
        !           691:    /* Write the contents of the packet */
        !           692: 
        !           693:    /* The ethernet header first... */
        !           694:    outsw(nic->ioaddr + DATA_1, d, ETH_ALEN >> 1);
        !           695:    outsw(nic->ioaddr + DATA_1, nic->node_addr, ETH_ALEN >> 1);
        !           696:    _outw(htons(t), nic->ioaddr + DATA_1);
        !           697: 
        !           698:    /* ... the data ... */
        !           699:    outsw(nic->ioaddr + DATA_1 , p, s >> 1);
        !           700: 
        !           701:    /* ... and the last byte, if there is one.   */
        !           702:    if ((s & 1) == 0) {
        !           703:       _outw(0, nic->ioaddr + DATA_1);
        !           704:    } else {
        !           705:       _outb(p[s-1], nic->ioaddr + DATA_1);
        !           706:       _outb(0x20, nic->ioaddr + DATA_1);
        !           707:    }
        !           708: 
        !           709:    /* and let the chipset deal with it */
        !           710:    _outw(MC_ENQUEUE , nic->ioaddr + MMU_CMD);
        !           711: 
        !           712:    status = 0; time_out = currticks() + 5*TICKS_PER_SEC;
        !           713:    do {
        !           714:       status = inb(nic->ioaddr + INTERRUPT);
        !           715: 
        !           716:       if ((status & IM_TX_INT ) != 0) {
        !           717:         word tx_status;
        !           718: 
        !           719:         /* ack interrupt */
        !           720:         _outb(IM_TX_INT, nic->ioaddr + INTERRUPT);
        !           721: 
        !           722:         packet_no = inw(nic->ioaddr + FIFO_PORTS);
        !           723:         packet_no &= 0x7F;
        !           724: 
        !           725:         /* select this as the packet to read from */
        !           726:         _outb( packet_no, nic->ioaddr + PNR_ARR );
        !           727: 
        !           728:         /* read the first word from this packet */
        !           729:         _outw( PTR_AUTOINC | PTR_READ, nic->ioaddr + POINTER );
        !           730: 
        !           731:         tx_status = inw( nic->ioaddr + DATA_1 );
        !           732: 
        !           733:         if (0 == (tx_status & TS_SUCCESS)) {
        !           734:            DBG("SMC9000: TX FAIL STATUS: %hX \n", tx_status);
        !           735:            /* re-enable transmit */
        !           736:            SMC_SELECT_BANK(nic->ioaddr, 0);
        !           737:            _outw(inw(nic->ioaddr + TCR ) | TCR_ENABLE, nic->ioaddr + TCR );
        !           738:         }
        !           739: 
        !           740:         /* kill the packet */
        !           741:         SMC_SELECT_BANK(nic->ioaddr, 2);
        !           742:         _outw(MC_FREEPKT, nic->ioaddr + MMU_CMD);
        !           743: 
        !           744:         return;
        !           745:       }
        !           746:    }while(currticks() < time_out);
        !           747: 
        !           748:    printf("SMC9000: TX timed out, resetting board\n");
        !           749:    smc_reset(nic->ioaddr);
        !           750:    return;
        !           751: }
        !           752: 
        !           753: /**************************************************************************
        !           754:  * ETH_POLL - Wait for a frame
        !           755:  ***************************************************************************/
        !           756: static int smc9000_poll(struct nic *nic, int retrieve)
        !           757: {
        !           758:    SMC_SELECT_BANK(nic->ioaddr, 2);
        !           759:    if (inw(nic->ioaddr + FIFO_PORTS) & FP_RXEMPTY)
        !           760:      return 0;
        !           761:    
        !           762:    if ( ! retrieve ) return 1;
        !           763: 
        !           764:    /*  start reading from the start of the packet */
        !           765:    _outw(PTR_READ | PTR_RCV | PTR_AUTOINC, nic->ioaddr + POINTER);
        !           766: 
        !           767:    /* First read the status and check that we're ok */
        !           768:    if (!(inw(nic->ioaddr + DATA_1) & RS_ERRORS)) {
        !           769:       /* Next: read the packet length and mask off the top bits */
        !           770:       nic->packetlen = (inw(nic->ioaddr + DATA_1) & 0x07ff);
        !           771: 
        !           772:       /* the packet length includes the 3 extra words */
        !           773:       nic->packetlen -= 6;
        !           774: #if    SMC9000_DEBUG > 2
        !           775:       printf(" Reading %d words (and %d byte(s))\n",
        !           776:               (nic->packetlen >> 1), nic->packetlen & 1);
        !           777: #endif
        !           778:       /* read the packet (and the last "extra" word) */
        !           779:       insw(nic->ioaddr + DATA_1, nic->packet, (nic->packetlen+2) >> 1);
        !           780:       /* is there an odd last byte ? */
        !           781:       if (nic->packet[nic->packetlen+1] & 0x20)
        !           782:         nic->packetlen++;
        !           783: 
        !           784:       /*  error or good, tell the card to get rid of this packet */
        !           785:       _outw(MC_RELEASE, nic->ioaddr + MMU_CMD);
        !           786:       return 1;
        !           787:    }
        !           788: 
        !           789:    printf("SMC9000: RX error\n");
        !           790:    /*  error or good, tell the card to get rid of this packet */
        !           791:    _outw(MC_RELEASE, nic->ioaddr + MMU_CMD);
        !           792:    return 0;
        !           793: }
        !           794: 
        !           795: static void smc9000_disable ( struct nic *nic, struct isa_device *isa __unused ) {
        !           796: 
        !           797:    smc_reset(nic->ioaddr);
        !           798: 
        !           799:    /* no more interrupts for me */
        !           800:    SMC_SELECT_BANK(nic->ioaddr, 2);
        !           801:    _outb( 0, nic->ioaddr + INT_MASK);
        !           802: 
        !           803:    /* and tell the card to stay away from that nasty outside world */
        !           804:    SMC_SELECT_BANK(nic->ioaddr, 0);
        !           805:    _outb( RCR_CLEAR, nic->ioaddr + RCR );
        !           806:    _outb( TCR_CLEAR, nic->ioaddr + TCR );
        !           807: }
        !           808: 
        !           809: static void smc9000_irq(struct nic *nic __unused, irq_action_t action __unused)
        !           810: {
        !           811:   switch ( action ) {
        !           812:   case DISABLE :
        !           813:     break;
        !           814:   case ENABLE :
        !           815:     break;
        !           816:   case FORCE :
        !           817:     break;
        !           818:   }
        !           819: }
        !           820: 
        !           821: static struct nic_operations smc9000_operations = {
        !           822:        .connect        = dummy_connect,
        !           823:        .poll           = smc9000_poll,
        !           824:        .transmit       = smc9000_transmit,
        !           825:        .irq            = smc9000_irq,
        !           826: 
        !           827: };
        !           828: 
        !           829: /**************************************************************************
        !           830:  * ETH_PROBE - Look for an adapter
        !           831:  ***************************************************************************/
        !           832: 
        !           833: static int smc9000_probe ( struct nic *nic, struct isa_device *isa ) {
        !           834: 
        !           835:    unsigned short   revision;
        !           836:    int             memory;
        !           837:    int              media;
        !           838:    const char *            version_string;
        !           839:    const char *            if_string;
        !           840:    int              i;
        !           841: 
        !           842:    nic->irqno  = 0;
        !           843:    nic->ioaddr = isa->ioaddr;
        !           844: 
        !           845:    /*
        !           846:     * Get the MAC address ( bank 1, regs 4 - 9 )
        !           847:     */
        !           848:    SMC_SELECT_BANK(nic->ioaddr, 1);
        !           849:    for ( i = 0; i < 6; i += 2 ) {
        !           850:       word address;
        !           851: 
        !           852:       address = inw(nic->ioaddr + ADDR0 + i);
        !           853:       nic->node_addr[i+1] = address >> 8;
        !           854:       nic->node_addr[i] = address & 0xFF;
        !           855:    }
        !           856: 
        !           857:    /* get the memory information */
        !           858:    SMC_SELECT_BANK(nic->ioaddr, 0);
        !           859:    memory = ( inw(nic->ioaddr + MCR) >> 9 )  & 0x7;  /* multiplier */
        !           860:    memory *= 256 * (inw(nic->ioaddr + MIR) & 0xFF);
        !           861: 
        !           862:    /*
        !           863:     * Now, I want to find out more about the chip.  This is sort of
        !           864:     * redundant, but it's cleaner to have it in both, rather than having
        !           865:     * one VERY long probe procedure.
        !           866:     */
        !           867:    SMC_SELECT_BANK(nic->ioaddr, 3);
        !           868:    revision  = inw(nic->ioaddr + REVISION);
        !           869:    version_string = chip_ids[(revision >> 4) & 0xF];
        !           870: 
        !           871:    if (((revision & 0xF0) >> 4 == CHIP_9196) &&
        !           872:        ((revision & 0x0F) >= REV_9196)) {
        !           873:       /* This is a 91c96. 'c96 has the same chip id as 'c94 (4) but
        !           874:        * a revision starting at 6 */
        !           875:       version_string = smc91c96_id;
        !           876:    }
        !           877: 
        !           878:    if ( !version_string ) {
        !           879:       /* I shouldn't get here because this call was done before.... */
        !           880:       return 0;
        !           881:    }
        !           882: 
        !           883:    /* is it using AUI or 10BaseT ? */
        !           884:    SMC_SELECT_BANK(nic->ioaddr, 1);
        !           885:    if (inw(nic->ioaddr + CONFIG) & CFG_AUI_SELECT)
        !           886:      media = 2;
        !           887:    else
        !           888:      media = 1;
        !           889: 
        !           890:    if_string = interfaces[media - 1];
        !           891: 
        !           892:    /* now, reset the chip, and put it into a known state */
        !           893:    smc_reset(nic->ioaddr);
        !           894: 
        !           895:    printf("SMC9000 %s\n", smc9000_version);
        !           896:    DBG("Copyright (C) 1998 Daniel Engstr\x94m\n");
        !           897:    DBG("Copyright (C) 1996 Eric Stahlman\n");
        !           898: 
        !           899:    printf("%s rev:%d I/O port:%hX Interface:%s RAM:%d bytes \n",
        !           900:          version_string, revision & 0xF,
        !           901:          nic->ioaddr, if_string, memory );
        !           902: 
        !           903:    DBG ( "Ethernet MAC address: %s\n", eth_ntoa ( nic->node_addr ) );
        !           904: 
        !           905:    SMC_SELECT_BANK(nic->ioaddr, 0);
        !           906: 
        !           907:    /* see the header file for options in TCR/RCR NORMAL*/
        !           908:    _outw(TCR_NORMAL, nic->ioaddr + TCR);
        !           909:    _outw(RCR_NORMAL, nic->ioaddr + RCR);
        !           910: 
        !           911:    /* Select which interface to use */
        !           912:    SMC_SELECT_BANK(nic->ioaddr, 1);
        !           913:    if ( media == 1 ) {
        !           914:       _outw( inw( nic->ioaddr + CONFIG ) & ~CFG_AUI_SELECT,
        !           915:           nic->ioaddr + CONFIG );
        !           916:    }
        !           917:    else if ( media == 2 ) {
        !           918:       _outw( inw( nic->ioaddr + CONFIG ) | CFG_AUI_SELECT,
        !           919:           nic->ioaddr + CONFIG );
        !           920:    }
        !           921: 
        !           922:    smc_phy_configure(nic->ioaddr);
        !           923:  
        !           924:    nic->nic_op = &smc9000_operations;
        !           925:    return 1;
        !           926: }
        !           927: 
        !           928: /*
        !           929:  * The SMC9000 can be at any of the following port addresses.  To
        !           930:  * change for a slightly different card, you can add it to the array.
        !           931:  *
        !           932:  */
        !           933: static isa_probe_addr_t smc9000_probe_addrs[] = {
        !           934:    0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
        !           935:    0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0,
        !           936: };
        !           937: 
        !           938: ISA_DRIVER ( smc9000_driver, smc9000_probe_addrs, smc9000_probe_addr,
        !           939:                     GENERIC_ISAPNP_VENDOR, 0x8228 );
        !           940: 
        !           941: DRIVER ( "SMC9000", nic_driver, isa_driver, smc9000_driver,
        !           942:         smc9000_probe, smc9000_disable );
        !           943: 
        !           944: ISA_ROM ( "smc9000", "SMC9000" );
        !           945: 
        !           946: /*
        !           947:  * Local variables:
        !           948:  *  c-basic-offset: 8
        !           949:  *  c-indent-level: 8
        !           950:  *  tab-width: 8
        !           951:  * End:
        !           952:  */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.