The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/etherelnk3.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Etherlink III, Fast EtherLink and Fast EtherLink XL adapters.
    3  * To do:
    4  *      check robustness in the face of errors (e.g. busmaster & rxUnderrun);
    5  *      RxEarly and busmaster;
    6  *      autoSelect;
    7  *      PCI latency timer and master enable;
    8  *      errata list;
    9  *      rewrite all initialisation.
   10  */
   11 #include "u.h"
   12 #include "../port/lib.h"
   13 #include "mem.h"
   14 #include "dat.h"
   15 #include "fns.h"
   16 #include "io.h"
   17 #include "../port/error.h"
   18 #include "../port/netif.h"
   19 
   20 #include "etherif.h"
   21 
   22 #define XCVRDEBUG               if(0)print
   23 
   24 enum {
   25         IDport                  = 0x0110,       /* anywhere between 0x0100 and 0x01F0 */
   26 };
   27 
   28 enum {                                          /* all windows */
   29         CommandR                = 0x000E,
   30         IntStatusR              = 0x000E,
   31 };
   32 
   33 enum {                                          /* Commands */
   34         GlobalReset             = 0x0000,
   35         SelectRegisterWindow    = 0x0001,
   36         EnableDcConverter       = 0x0002,
   37         RxDisable               = 0x0003,
   38         RxEnable                = 0x0004,
   39         RxReset                 = 0x0005,
   40         Stall                   = 0x0006,       /* 3C90x */
   41         TxDone                  = 0x0007,
   42         RxDiscard               = 0x0008,
   43         TxEnable                = 0x0009,
   44         TxDisable               = 0x000A,
   45         TxReset                 = 0x000B,
   46         RequestInterrupt        = 0x000C,
   47         AcknowledgeInterrupt    = 0x000D,
   48         SetInterruptEnable      = 0x000E,
   49         SetIndicationEnable     = 0x000F,       /* SetReadZeroMask */
   50         SetRxFilter             = 0x0010,
   51         SetRxEarlyThresh        = 0x0011,
   52         SetTxAvailableThresh    = 0x0012,
   53         SetTxStartThresh        = 0x0013,
   54         StartDma                = 0x0014,       /* initiate busmaster operation */
   55         StatisticsEnable        = 0x0015,
   56         StatisticsDisable       = 0x0016,
   57         DisableDcConverter      = 0x0017,
   58         SetTxReclaimThresh      = 0x0018,       /* PIO-only adapters */
   59         PowerUp                 = 0x001B,       /* not all adapters */
   60         PowerDownFull           = 0x001C,       /* not all adapters */
   61         PowerAuto               = 0x001D,       /* not all adapters */
   62 };
   63 
   64 enum {                                          /* (Global|Rx|Tx)Reset command bits */
   65         tpAuiReset              = 0x0001,       /* 10BaseT and AUI transceivers */
   66         endecReset              = 0x0002,       /* internal Ethernet encoder/decoder */
   67         networkReset            = 0x0004,       /* network interface logic */
   68         fifoReset               = 0x0008,       /* FIFO control logic */
   69         aismReset               = 0x0010,       /* autoinitialise state-machine logic */
   70         hostReset               = 0x0020,       /* bus interface logic */
   71         dmaReset                = 0x0040,       /* bus master logic */
   72         vcoReset                = 0x0080,       /* on-board 10Mbps VCO */
   73         updnReset               = 0x0100,       /* upload/download (Rx/TX) logic */
   74 
   75         resetMask               = 0x01FF,
   76 };
   77 
   78 enum {                                          /* Stall command bits */
   79         upStall                 = 0x0000,
   80         upUnStall               = 0x0001,
   81         dnStall                 = 0x0002,
   82         dnUnStall               = 0x0003,
   83 };
   84 
   85 enum {                                          /* SetRxFilter command bits */
   86         receiveIndividual       = 0x0001,       /* match station address */
   87         receiveMulticast        = 0x0002,
   88         receiveBroadcast        = 0x0004,
   89         receiveAllFrames        = 0x0008,       /* promiscuous */
   90 };
   91 
   92 enum {                                          /* StartDma command bits */
   93         Upload                  = 0x0000,       /* transfer data from adapter to memory */
   94         Download                = 0x0001,       /* transfer data from memory to adapter */
   95 };
   96 
   97 enum {                                          /* IntStatus bits */
   98         interruptLatch          = 0x0001,
   99         hostError               = 0x0002,       /* Adapter Failure */
  100         txComplete              = 0x0004,
  101         txAvailable             = 0x0008,
  102         rxComplete              = 0x0010,
  103         rxEarly                 = 0x0020,
  104         intRequested            = 0x0040,
  105         updateStats             = 0x0080,
  106         transferInt             = 0x0100,       /* Bus Master Transfer Complete */
  107         dnComplete              = 0x0200,
  108         upComplete              = 0x0400,
  109         busMasterInProgress     = 0x0800,
  110         commandInProgress       = 0x1000,
  111 
  112         interruptMask           = 0x07FE,
  113 };
  114 
  115 #define COMMAND(port, cmd, a)   outs((port)+CommandR, ((cmd)<<11)|(a))
  116 #define STATUS(port)            ins((port)+IntStatusR)
  117 
  118 enum {                                          /* Window 0 - setup */
  119         Wsetup                  = 0x0000,
  120                                                 /* registers */
  121         ManufacturerID          = 0x0000,       /* 3C5[08]*, 3C59[27] */
  122         ProductID               = 0x0002,       /* 3C5[08]*, 3C59[27] */
  123         ConfigControl           = 0x0004,       /* 3C5[08]*, 3C59[27] */
  124         AddressConfig           = 0x0006,       /* 3C5[08]*, 3C59[27] */
  125         ResourceConfig          = 0x0008,       /* 3C5[08]*, 3C59[27] */
  126         EepromCommand           = 0x000A,
  127         EepromData              = 0x000C,
  128                                                 /* AddressConfig Bits */
  129         autoSelect9             = 0x0080,
  130         xcvrMask9               = 0xC000,
  131                                                 /* ConfigControl bits */
  132         Ena                     = 0x0001,
  133         base10TAvailable9       = 0x0200,
  134         coaxAvailable9          = 0x1000,
  135         auiAvailable9           = 0x2000,
  136                                                 /* EepromCommand bits */
  137         EepromReadRegister      = 0x0080,
  138         EepromReadOffRegister   = 0x00B0,
  139         EepromRead8bRegister    = 0x0230,
  140         EepromBusy              = 0x8000,
  141 };
  142 
  143 #define EEPROMCMD(port, cmd, a) outs((port)+EepromCommand, (cmd)|(a))
  144 #define EEPROMBUSY(port)        (ins((port)+EepromCommand) & EepromBusy)
  145 #define EEPROMDATA(port)        ins((port)+EepromData)
  146 
  147 enum {                                          /* Window 1 - operating set */
  148         Wop                     = 0x0001,
  149                                                 /* registers */
  150         Fifo                    = 0x0000,
  151         RxError                 = 0x0004,       /* 3C59[0257] only */
  152         RxStatus                = 0x0008,
  153         TIMER                   = 0x000A,
  154         TxStatus                = 0x000B,
  155         TxFree                  = 0x000C,
  156                                                 /* RxError bits */
  157         rxOverrun               = 0x0001,
  158         runtFrame               = 0x0002,
  159         alignmentError          = 0x0004,       /* Framing */
  160         crcError                = 0x0008,
  161         oversizedFrame          = 0x0010,
  162         dribbleBits             = 0x0080,
  163                                                 /* RxStatus bits */
  164         rxBytes                 = 0x1FFF,       /* 3C59[0257] mask */
  165         rxBytes9                = 0x07FF,       /* 3C5[078]9 mask */
  166         rxError9                = 0x3800,       /* 3C5[078]9 error mask */
  167         rxOverrun9              = 0x0000,
  168         oversizedFrame9         = 0x0800,
  169         dribbleBits9            = 0x1000,
  170         runtFrame9              = 0x1800,
  171         alignmentError9         = 0x2000,       /* Framing */
  172         crcError9               = 0x2800,
  173         rxError                 = 0x4000,
  174         rxIncomplete            = 0x8000,
  175                                                 /* TxStatus Bits */
  176         txStatusOverflow        = 0x0004,
  177         maxCollisions           = 0x0008,
  178         txUnderrun              = 0x0010,
  179         txJabber                = 0x0020,
  180         interruptRequested      = 0x0040,
  181         txStatusComplete        = 0x0080,
  182 };
  183 
  184 enum {                                          /* Window 2 - station address */
  185         Wstation                = 0x0002,
  186 
  187         ResetOp905B             = 0x000C,
  188 };
  189 
  190 enum {                                          /* Window 3 - FIFO management */
  191         Wfifo                   = 0x0003,
  192                                                 /* registers */
  193         InternalConfig          = 0x0000,       /* 3C509B, 3C589, 3C59[0257] */
  194         OtherInt                = 0x0004,       /* 3C59[0257] */
  195         RomControl              = 0x0006,       /* 3C509B, 3C59[27] */
  196         MacControl              = 0x0006,       /* 3C59[0257] */
  197         ResetOptions            = 0x0008,       /* 3C59[0257] */
  198         MediaOptions            = 0x0008,       /* 3C905B */
  199         RxFree                  = 0x000A,
  200                                                 /* InternalConfig bits */
  201         disableBadSsdDetect     = 0x00000100,
  202         ramLocation             = 0x00000200,   /* 0 external, 1 internal */
  203         ramPartition5to3        = 0x00000000,
  204         ramPartition3to1        = 0x00010000,
  205         ramPartition1to1        = 0x00020000,
  206         ramPartition3to5        = 0x00030000,
  207         ramPartitionMask        = 0x00030000,
  208         xcvr10BaseT             = 0x00000000,
  209         xcvrAui                 = 0x00100000,   /* 10BASE5 */
  210         xcvr10Base2             = 0x00300000,
  211         xcvr100BaseTX           = 0x00400000,
  212         xcvr100BaseFX           = 0x00500000,
  213         xcvrMii                 = 0x00600000,
  214         xcvrMask                = 0x00700000,
  215         autoSelect              = 0x01000000,
  216                                                 /* MacControl bits */
  217         deferExtendEnable       = 0x0001,
  218         deferTIMERSelect        = 0x001E,       /* mask */
  219         fullDuplexEnable        = 0x0020,
  220         allowLargePackets       = 0x0040,
  221         extendAfterCollision    = 0x0080,       /* 3C90xB */
  222         flowControlEnable       = 0x0100,       /* 3C90xB */
  223         vltEnable               = 0x0200,       /* 3C90xB */
  224                                                 /* ResetOptions bits */
  225         baseT4Available         = 0x0001,
  226         baseTXAvailable         = 0x0002,
  227         baseFXAvailable         = 0x0004,
  228         base10TAvailable        = 0x0008,
  229         coaxAvailable           = 0x0010,
  230         auiAvailable            = 0x0020,
  231         miiConnector            = 0x0040,
  232 };
  233 
  234 enum {                                          /* Window 4 - diagnostic */
  235         Wdiagnostic             = 0x0004,
  236                                                 /* registers */
  237         VcoDiagnostic           = 0x0002,
  238         FifoDiagnostic          = 0x0004,
  239         NetworkDiagnostic       = 0x0006,
  240         PhysicalMgmt            = 0x0008,
  241         MediaStatus             = 0x000A,
  242         BadSSD                  = 0x000C,
  243         UpperBytesOk            = 0x000D,
  244                                                 /* FifoDiagnostic bits */
  245         txOverrun               = 0x0400,
  246         rxUnderrun              = 0x2000,
  247         receiving               = 0x8000,
  248                                                 /* PhysicalMgmt bits */
  249         mgmtClk                 = 0x0001,
  250         mgmtData                = 0x0002,
  251         mgmtDir                 = 0x0004,
  252         cat5LinkTestDefeat      = 0x8000,
  253                                                 /* MediaStatus bits */
  254         dataRate100             = 0x0002,
  255         crcStripDisable         = 0x0004,
  256         enableSqeStats          = 0x0008,
  257         collisionDetect         = 0x0010,
  258         carrierSense            = 0x0020,
  259         jabberGuardEnable       = 0x0040,
  260         linkBeatEnable          = 0x0080,
  261         jabberDetect            = 0x0200,
  262         polarityReversed        = 0x0400,
  263         linkBeatDetect          = 0x0800,
  264         txInProg                = 0x1000,
  265         dcConverterEnabled      = 0x4000,
  266         auiDisable              = 0x8000,       /* 10BaseT transceiver selected */
  267 };
  268 
  269 enum {                                          /* Window 5 - internal state */
  270         Wstate                  = 0x0005,
  271                                                 /* registers */
  272         TxStartThresh           = 0x0000,
  273         TxAvailableThresh       = 0x0002,
  274         RxEarlyThresh           = 0x0006,
  275         RxFilter                = 0x0008,
  276         InterruptEnable         = 0x000A,
  277         IndicationEnable        = 0x000C,
  278 };
  279 
  280 enum {                                          /* Window 6 - statistics */
  281         Wstatistics             = 0x0006,
  282                                                 /* registers */
  283         CarrierLost             = 0x0000,
  284         SqeErrors               = 0x0001,
  285         MultipleColls           = 0x0002,
  286         SingleCollFrames        = 0x0003,
  287         LateCollisions          = 0x0004,
  288         RxOverruns              = 0x0005,
  289         FramesXmittedOk         = 0x0006,
  290         FramesRcvdOk            = 0x0007,
  291         FramesDeferred          = 0x0008,
  292         UpperFramesOk           = 0x0009,
  293         BytesRcvdOk             = 0x000A,
  294         BytesXmittedOk          = 0x000C,
  295 };
  296 
  297 enum {                                          /* Window 7 - bus master operations */
  298         Wmaster                 = 0x0007,
  299                                                 /* registers */
  300         MasterAddress           = 0x0000,
  301         MasterLen               = 0x0006,
  302         MasterStatus            = 0x000C,
  303                                                 /* MasterStatus bits */
  304         masterAbort             = 0x0001,
  305         targetAbort             = 0x0002,
  306         targetRetry             = 0x0004,
  307         targetDisc              = 0x0008,
  308         masterDownload          = 0x1000,
  309         masterUpload            = 0x4000,
  310         masterInProgress        = 0x8000,
  311 
  312         masterMask              = 0xD00F,
  313 };
  314 
  315 enum {                                          /* 3C90x extended register set */
  316         TIMER905                = 0x001A,       /* 8-bits */
  317         TxStatus905             = 0x001B,       /* 8-bits */
  318         PktStatus               = 0x0020,       /* 32-bits */
  319         DnListPtr               = 0x0024,       /* 32-bits, 8-byte aligned */
  320         FragAddr                = 0x0028,       /* 32-bits */
  321         FragLen                 = 0x002C,       /* 16-bits */
  322         ListOffset              = 0x002E,       /* 8-bits */
  323         TxFreeThresh            = 0x002F,       /* 8-bits */
  324         UpPktStatus             = 0x0030,       /* 32-bits */
  325         FreeTIMER               = 0x0034,       /* 16-bits */
  326         UpListPtr               = 0x0038,       /* 32-bits, 8-byte aligned */
  327 
  328                                                 /* PktStatus bits */
  329         fragLast                = 0x00000001,
  330         dnCmplReq               = 0x00000002,
  331         dnStalled               = 0x00000004,
  332         upCompleteX             = 0x00000008,
  333         dnCompleteX             = 0x00000010,
  334         upRxEarlyEnable         = 0x00000020,
  335         armCountdown            = 0x00000040,
  336         dnInProg                = 0x00000080,
  337         counterSpeed            = 0x00000010,   /* 0 3.2uS, 1 320nS */
  338         countdownMode           = 0x00000020,
  339                                                 /* UpPktStatus bits (dpd->control) */
  340         upPktLenMask            = 0x00001FFF,
  341         upStalled               = 0x00002000,
  342         upError                 = 0x00004000,
  343         upPktComplete           = 0x00008000,
  344         upOverrun               = 0x00010000,   /* RxError<<16 */
  345         upRuntFrame             = 0x00020000,
  346         upAlignmentError        = 0x00040000,
  347         upCRCError              = 0x00080000,
  348         upOversizedFrame        = 0x00100000,
  349         upDribbleBits           = 0x00800000,
  350         upOverflow              = 0x01000000,
  351 
  352         dnIndicate              = 0x80000000,   /* FrameStartHeader (dpd->control) */
  353 
  354         updnLastFrag            = 0x80000000,   /* (dpd->len) */
  355 
  356         Nup                     = 32,
  357         Ndn                     = 64,
  358 };
  359 
  360 /*
  361  * Up/Dn Packet Descriptors.
  362  * The hardware info (np, control, addr, len) must be 8-byte aligned
  363  * and this structure size must be a multiple of 8.
  364  */
  365 typedef struct Pd Pd;
  366 typedef struct Pd {
  367         ulong   np;                     /* next pointer */
  368         ulong   control;                /* FSH or UpPktStatus */
  369         ulong   addr;
  370         ulong   len;
  371 
  372         Pd*     next;
  373         Block*  bp;
  374 } Pd;
  375 
  376 typedef struct Ctlr Ctlr;
  377 typedef struct Ctlr {
  378         int     port;
  379         Pcidev* pcidev;
  380         int     irq;
  381         Ctlr*   next;
  382         int     active;
  383         int     did;
  384 
  385         Lock    wlock;                  /* window access */
  386 
  387         int     attached;
  388         int     busmaster;
  389         Block*  rbp;                    /* receive buffer */
  390 
  391         Block*  txbp;                   /* FIFO -based transmission */
  392         int     txthreshold;
  393         int     txbusy;
  394 
  395         int     nup;                    /* full-busmaster -based reception */
  396         void*   upbase;
  397         Pd*     upr;
  398         Pd*     uphead;
  399 
  400         int     ndn;                    /* full-busmaster -based transmission */
  401         void*   dnbase;
  402         Pd*     dnr;
  403         Pd*     dnhead;
  404         Pd*     dntail;
  405         int     dnq;
  406 
  407         long    interrupts;             /* statistics */
  408         long    bogusinterrupts;
  409         long    timer[2];
  410         long    stats[BytesRcvdOk+3];
  411 
  412         int     upqmax;
  413         int     upqmaxhw;
  414         ulong   upinterrupts;
  415         ulong   upqueued;
  416         ulong   upstalls;
  417         int     dnqmax;
  418         int     dnqmaxhw;
  419         ulong   dninterrupts;
  420         ulong   dnqueued;
  421 
  422         int     xcvr;                   /* transceiver type */
  423         int     eepromcmd;              /* EEPROM read command */
  424         int     rxstatus9;              /* old-style RxStatus register */
  425         int     rxearly;                /* RxEarlyThreshold */
  426         int     ts;                     /* threshold shift */
  427         int     upenabled;
  428         int     dnenabled;
  429         ulong   cbfnpa;                 /* CardBus functions */
  430         ulong*  cbfn;
  431 } Ctlr;
  432 
  433 static Ctlr* ctlrhead;
  434 static Ctlr* ctlrtail;
  435 
  436 static void
  437 init905(Ctlr* ctlr)
  438 {
  439         Block *bp;
  440         Pd *pd, *prev;
  441 
  442         /*
  443          * Create rings for the receive and transmit sides.
  444          * Take care with alignment:
  445          *      make sure ring base is 8-byte aligned;
  446          *      make sure each entry is 8-byte aligned.
  447          */
  448         ctlr->upbase = malloc((ctlr->nup+1)*sizeof(Pd));
  449         ctlr->upr = (Pd*)ROUNDUP((ulong)ctlr->upbase, 8);
  450 
  451         prev = ctlr->upr;
  452         for(pd = &ctlr->upr[ctlr->nup-1]; pd >= ctlr->upr; pd--){
  453                 pd->np = PADDR(&prev->np);
  454                 pd->control = 0;
  455                 bp = iallocb(sizeof(Etherpkt));
  456                 if(bp == nil)
  457                         panic("can't allocate ethernet receive ring");
  458                 pd->addr = PADDR(bp->rp);
  459                 pd->len = updnLastFrag|sizeof(Etherpkt);
  460 
  461                 pd->next = prev;
  462                 prev = pd;
  463                 pd->bp = bp;
  464         }
  465         ctlr->uphead = ctlr->upr;
  466 
  467         ctlr->dnbase = malloc((ctlr->ndn+1)*sizeof(Pd));
  468         ctlr->dnr = (Pd*)ROUNDUP((ulong)ctlr->dnbase, 8);
  469 
  470         prev = ctlr->dnr;
  471         for(pd = &ctlr->dnr[ctlr->ndn-1]; pd >= ctlr->dnr; pd--){
  472                 pd->next = prev;
  473                 prev = pd;
  474         }
  475         ctlr->dnhead = ctlr->dnr;
  476         ctlr->dntail = ctlr->dnr;
  477         ctlr->dnq = 0;
  478 }
  479 
  480 static Block*
  481 rbpalloc(Block* (*f)(int))
  482 {
  483         Block *bp;
  484         ulong addr;
  485 
  486         /*
  487          * The receive buffers must be on a 32-byte
  488          * boundary for EISA busmastering.
  489          */
  490         if(bp = f(ROUNDUP(sizeof(Etherpkt), 4) + 31)){
  491                 addr = (ulong)bp->base;
  492                 addr = ROUNDUP(addr, 32);
  493                 bp->rp = (uchar*)addr;
  494         }
  495 
  496         return bp;
  497 }
  498 
  499 static uchar*
  500 startdma(Ether* ether, ulong address)
  501 {
  502         int port, status, w;
  503         uchar *wp;
  504 
  505         port = ether->port;
  506 
  507         w = (STATUS(port)>>13) & 0x07;
  508         COMMAND(port, SelectRegisterWindow, Wmaster);
  509 
  510         wp = KADDR(inl(port+MasterAddress));
  511         status = ins(port+MasterStatus);
  512         if(status & (masterInProgress|targetAbort|masterAbort))
  513                 print("#l%d: BM status 0x%uX\n", ether->ctlrno, status);
  514         outs(port+MasterStatus, masterMask);
  515         outl(port+MasterAddress, address);
  516         outs(port+MasterLen, sizeof(Etherpkt));
  517         COMMAND(port, StartDma, Upload);
  518 
  519         COMMAND(port, SelectRegisterWindow, w);
  520         return wp;
  521 }
  522 
  523 static void
  524 promiscuous(void* arg, int on)
  525 {
  526         int filter, port;
  527         Ether *ether;
  528 
  529         ether = (Ether*)arg;
  530         port = ether->port;
  531 
  532         filter = receiveBroadcast|receiveIndividual;
  533         if(ether->nmaddr)
  534                 filter |= receiveMulticast;
  535         if(on)
  536                 filter |= receiveAllFrames;
  537         COMMAND(port, SetRxFilter, filter);
  538 }
  539 
  540 static void
  541 multicast(void* arg, uchar *addr, int on)
  542 {
  543         int filter, port;
  544         Ether *ether;
  545 
  546         USED(addr, on);
  547 
  548         ether = (Ether*)arg;
  549         port = ether->port;
  550 
  551         filter = receiveBroadcast|receiveIndividual;
  552         if(ether->nmaddr)
  553                 filter |= receiveMulticast;
  554         if(ether->prom)
  555                 filter |= receiveAllFrames;
  556         COMMAND(port, SetRxFilter, filter);
  557 }
  558 
  559 /* On the 575B and C, interrupts need to be acknowledged in CardBus memory space */
  560 static void
  561 intrackcb(ulong *cbfn)
  562 {
  563         cbfn[1] = 0x8000;
  564 }
  565 
  566 static void
  567 attach(Ether* ether)
  568 {
  569         int port, x;
  570         Ctlr *ctlr;
  571 
  572         ctlr = ether->ctlr;
  573         ilock(&ctlr->wlock);
  574         if(ctlr->attached){
  575                 iunlock(&ctlr->wlock);
  576                 return;
  577         }
  578 
  579         port = ether->port;
  580 
  581         /*
  582          * Set the receiver packet filter for this and broadcast addresses,
  583          * set the interrupt masks for all interrupts, enable the receiver
  584          * and transmitter.
  585          */
  586         promiscuous(ether, ether->prom);
  587 
  588         x = interruptMask;
  589         if(ctlr->busmaster == 1)
  590                 x &= ~(rxEarly|rxComplete);
  591         else{
  592                 if(ctlr->dnenabled)
  593                         x &= ~transferInt;
  594                 if(ctlr->upenabled)
  595                         x &= ~(rxEarly|rxComplete);
  596         }
  597         COMMAND(port, SetIndicationEnable, x);
  598         COMMAND(port, SetInterruptEnable, x);
  599         COMMAND(port, RxEnable, 0);
  600         COMMAND(port, TxEnable, 0);
  601 
  602         /*
  603          * If this is a CardBus card, acknowledge any interrupts.
  604          */
  605         if(ctlr->cbfn != nil)
  606                 intrackcb(ctlr->cbfn);
  607                 
  608         /*
  609          * Prime the busmaster channel for receiving directly into a
  610          * receive packet buffer if necessary.
  611          */
  612         if(ctlr->busmaster == 1)
  613                 startdma(ether, PADDR(ctlr->rbp->rp));
  614         else{
  615                 if(ctlr->upenabled)
  616                         outl(port+UpListPtr, PADDR(&ctlr->uphead->np));
  617         }
  618 
  619         ctlr->attached = 1;
  620         iunlock(&ctlr->wlock);
  621 }
  622 
  623 static void
  624 statistics(Ether* ether)
  625 {
  626         int port, i, u, w;
  627         Ctlr *ctlr;
  628 
  629         port = ether->port;
  630         ctlr = ether->ctlr;
  631 
  632         /*
  633          * 3C59[27] require a read between a PIO write and
  634          * reading a statistics register.
  635          */
  636         w = (STATUS(port)>>13) & 0x07;
  637         COMMAND(port, SelectRegisterWindow, Wstatistics);
  638         STATUS(port);
  639 
  640         for(i = 0; i < UpperFramesOk; i++)
  641                 ctlr->stats[i] += inb(port+i) & 0xFF;
  642         u = inb(port+UpperFramesOk) & 0xFF;
  643         ctlr->stats[FramesXmittedOk] += (u & 0x30)<<4;
  644         ctlr->stats[FramesRcvdOk] += (u & 0x03)<<8;
  645         ctlr->stats[BytesRcvdOk] += ins(port+BytesRcvdOk) & 0xFFFF;
  646         ctlr->stats[BytesRcvdOk+1] += ins(port+BytesXmittedOk) & 0xFFFF;
  647 
  648         switch(ctlr->xcvr){
  649 
  650         case xcvrMii:
  651         case xcvr100BaseTX:
  652         case xcvr100BaseFX:
  653                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  654                 STATUS(port);
  655                 ctlr->stats[BytesRcvdOk+2] += inb(port+BadSSD);
  656                 break;
  657         }
  658 
  659         COMMAND(port, SelectRegisterWindow, w);
  660 }
  661 
  662 static void
  663 txstart(Ether* ether)
  664 {
  665         int port, len;
  666         Ctlr *ctlr;
  667         Block *bp;
  668 
  669         port = ether->port;
  670         ctlr = ether->ctlr;
  671 
  672         /*
  673          * Attempt to top-up the transmit FIFO. If there's room simply
  674          * stuff in the packet length (unpadded to a dword boundary), the
  675          * packet data (padded) and remove the packet from the queue.
  676          * If there's no room post an interrupt for when there is.
  677          * This routine is called both from the top level and from interrupt
  678          * level and expects to be called with ctlr->wlock already locked
  679          * and the correct register window (Wop) in place.
  680          */
  681         for(;;){
  682                 if(ctlr->txbp){
  683                         bp = ctlr->txbp;
  684                         ctlr->txbp = 0;
  685                 }
  686                 else{
  687                         bp = qget(ether->oq);
  688                         if(bp == nil)
  689                                 break;
  690                 }
  691 
  692                 len = ROUNDUP(BLEN(bp), 4);
  693                 if(len+4 <= ins(port+TxFree)){
  694                         outl(port+Fifo, BLEN(bp));
  695                         outsl(port+Fifo, bp->rp, len/4);
  696 
  697                         freeb(bp);
  698 
  699                         ether->outpackets++;
  700                 }
  701                 else{
  702                         ctlr->txbp = bp;
  703                         if(ctlr->txbusy == 0){
  704                                 ctlr->txbusy = 1;
  705                                 COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts);
  706                         }
  707                         break;
  708                 }
  709         }
  710 }
  711 
  712 static void
  713 txstart905(Ether* ether)
  714 {
  715         Ctlr *ctlr;
  716         int port, stalled, timeo;
  717         Block *bp;
  718         Pd *pd;
  719 
  720         ctlr = ether->ctlr;
  721         port = ether->port;
  722 
  723         /*
  724          * Free any completed packets.
  725          */
  726         pd = ctlr->dntail;
  727         while(ctlr->dnq){
  728                 if(PADDR(&pd->np) == inl(port+DnListPtr))
  729                         break;
  730                 if(pd->bp){
  731                         freeb(pd->bp);
  732                         pd->bp = nil;
  733                 }
  734                 ctlr->dnq--;
  735                 pd = pd->next;
  736         }
  737         ctlr->dntail = pd;
  738 
  739         stalled = 0;
  740         while(ctlr->dnq < (ctlr->ndn-1)){
  741                 bp = qget(ether->oq);
  742                 if(bp == nil)
  743                         break;
  744 
  745                 pd = ctlr->dnhead->next;
  746                 pd->np = 0;
  747                 pd->control = dnIndicate|BLEN(bp);
  748                 pd->addr = PADDR(bp->rp);
  749                 pd->len = updnLastFrag|BLEN(bp);
  750                 pd->bp = bp;
  751 
  752                 if(stalled == 0 && ctlr->dnq && inl(port+DnListPtr)){
  753                         COMMAND(port, Stall, dnStall);
  754                         for(timeo = 100; (STATUS(port) & commandInProgress) && timeo; timeo--)
  755                                 ;
  756                         if(timeo == 0)
  757                                 print("#l%d: dnstall %d\n", ether->ctlrno, timeo);
  758                         stalled = 1;
  759                 }
  760 
  761                 coherence();
  762                 ctlr->dnhead->np = PADDR(&pd->np);
  763                 ctlr->dnhead->control &= ~dnIndicate;
  764                 ctlr->dnhead = pd;
  765                 if(ctlr->dnq == 0)
  766                         ctlr->dntail = pd;
  767                 ctlr->dnq++;
  768 
  769                 ctlr->dnqueued++;
  770         }
  771 
  772         if(ctlr->dnq > ctlr->dnqmax)
  773                 ctlr->dnqmax = ctlr->dnq;
  774 
  775         /*
  776          * If the adapter is not currently processing anything
  777          * and there is something on the queue, start it processing.
  778          */
  779         if(inl(port+DnListPtr) == 0 && ctlr->dnq)
  780                 outl(port+DnListPtr, PADDR(&ctlr->dnhead->np));
  781         if(stalled)
  782                 COMMAND(port, Stall, dnUnStall);
  783 }
  784 
  785 static void
  786 transmit(Ether* ether)
  787 {
  788         Ctlr *ctlr;
  789         int port, w;
  790 
  791         port = ether->port;
  792         ctlr = ether->ctlr;
  793 
  794         ilock(&ctlr->wlock);
  795         if(ctlr->dnenabled)
  796                 txstart905(ether);
  797         else{
  798                 w = (STATUS(port)>>13) & 0x07;
  799                 COMMAND(port, SelectRegisterWindow, Wop);
  800                 txstart(ether);
  801                 COMMAND(port, SelectRegisterWindow, w);
  802         }
  803         iunlock(&ctlr->wlock);
  804 }
  805 
  806 static void
  807 receive905(Ether* ether)
  808 {
  809         Ctlr *ctlr;
  810         int len, port, q;
  811         Pd *pd;
  812         Block *bp;
  813 
  814         ctlr = ether->ctlr;
  815         port = ether->port;
  816 
  817         if(inl(port+UpPktStatus) & upStalled)
  818                 ctlr->upstalls++;
  819         q = 0;
  820         for(pd = ctlr->uphead; pd->control & upPktComplete; pd = pd->next){
  821                 if(pd->control & upError){
  822                         if(pd->control & upOverrun)
  823                                 ether->overflows++;
  824                         if(pd->control & (upOversizedFrame|upRuntFrame))
  825                                 ether->buffs++;
  826                         if(pd->control & upAlignmentError)
  827                                 ether->frames++;
  828                         if(pd->control & upCRCError)
  829                                 ether->crcs++;
  830                 }
  831                 else if(bp = iallocb(sizeof(Etherpkt)+4)){
  832                         len = pd->control & rxBytes;
  833                         pd->bp->wp = pd->bp->rp+len;
  834                         etheriq(ether, pd->bp, 1);
  835                         pd->bp = bp;
  836                         pd->addr = PADDR(bp->rp);
  837                         coherence();
  838                 }
  839 
  840                 pd->control = 0;
  841                 COMMAND(port, Stall, upUnStall);
  842 
  843                 q++;
  844         }
  845         ctlr->uphead = pd;
  846 
  847         ctlr->upqueued += q;
  848         if(q > ctlr->upqmax)
  849                 ctlr->upqmax = q;
  850 }
  851 
  852 static void
  853 receive(Ether* ether)
  854 {
  855         int len, port, rxerror, rxstatus;
  856         Ctlr *ctlr;
  857         Block *bp;
  858 
  859         port = ether->port;
  860         ctlr = ether->ctlr;
  861 
  862         while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){
  863                 if(ctlr->busmaster == 1 && (STATUS(port) & busMasterInProgress))
  864                         break;
  865 
  866                 /*
  867                  * If there was an error, log it and continue.
  868                  * Unfortunately the 3C5[078]9 has the error info in the status register
  869                  * and the 3C59[0257] implement a separate RxError register.
  870                  */
  871                 if(rxstatus & rxError){
  872                         if(ctlr->rxstatus9){
  873                                 switch(rxstatus & rxError9){
  874 
  875                                 case rxOverrun9:
  876                                         ether->overflows++;
  877                                         break;
  878 
  879                                 case oversizedFrame9:
  880                                 case runtFrame9:
  881                                         ether->buffs++;
  882                                         break;
  883 
  884                                 case alignmentError9:
  885                                         ether->frames++;
  886                                         break;
  887 
  888                                 case crcError9:
  889                                         ether->crcs++;
  890                                         break;
  891 
  892                                 }
  893                         }
  894                         else{
  895                                 rxerror = inb(port+RxError);
  896                                 if(rxerror & rxOverrun)
  897                                         ether->overflows++;
  898                                 if(rxerror & (oversizedFrame|runtFrame))
  899                                         ether->buffs++;
  900                                 if(rxerror & alignmentError)
  901                                         ether->frames++;
  902                                 if(rxerror & crcError)
  903                                         ether->crcs++;
  904                         }
  905                 }
  906 
  907                 /*
  908                  * If there was an error or a new receive buffer can't be
  909                  * allocated, discard the packet and go on to the next.
  910                  */
  911                 if((rxstatus & rxError) || (bp = rbpalloc(iallocb)) == 0){
  912                         COMMAND(port, RxDiscard, 0);
  913                         while(STATUS(port) & commandInProgress)
  914                                 ;
  915 
  916                         if(ctlr->busmaster == 1)
  917                                 startdma(ether, PADDR(ctlr->rbp->rp));
  918 
  919                         continue;
  920                 }
  921 
  922                 /*
  923                  * A valid receive packet awaits:
  924                  *      if using PIO, read it into the buffer;
  925                  *      discard the packet from the FIFO;
  926                  *      if using busmastering, start a new transfer for
  927                  *        the next packet and as a side-effect get the
  928                  *        end-pointer of the one just received;
  929                  *      pass the packet on to whoever wants it.
  930                  */
  931                 if(ctlr->busmaster == 0 || ctlr->busmaster == 2){
  932                         len = (rxstatus & rxBytes9);
  933                         ctlr->rbp->wp = ctlr->rbp->rp + len;
  934                         insl(port+Fifo, ctlr->rbp->rp, HOWMANY(len, 4));
  935                 }
  936 
  937                 COMMAND(port, RxDiscard, 0);
  938                 while(STATUS(port) & commandInProgress)
  939                         ;
  940 
  941                 if(ctlr->busmaster == 1)
  942                         ctlr->rbp->wp = startdma(ether, PADDR(bp->rp));
  943 
  944                 etheriq(ether, ctlr->rbp, 1);
  945                 ctlr->rbp = bp;
  946         }
  947 }
  948 
  949 static int
  950 ejectable(int did)
  951 {
  952         switch (did) {
  953         case 0x5157:
  954                 return 1;
  955 
  956         default:
  957                 return 0;
  958         }
  959 }
  960 
  961 static void
  962 interrupt(Ureg*, void* arg)
  963 {
  964         Ether *ether;
  965         int port, status, s, txstatus, w, x;
  966         Ctlr *ctlr;
  967 
  968         ether = arg;
  969         port = ether->port;
  970         ctlr = ether->ctlr;
  971 
  972         ilock(&ctlr->wlock);
  973         status = STATUS(port);
  974         if(!(status & (interruptMask|interruptLatch))){
  975                 ctlr->bogusinterrupts++;
  976                 iunlock(&ctlr->wlock);
  977                 return;
  978         }
  979         w = (status>>13) & 0x07;
  980         COMMAND(port, SelectRegisterWindow, Wop);
  981 
  982         ctlr->interrupts++;
  983         if(ctlr->busmaster == 2)
  984                 ctlr->timer[0] += inb(port+TIMER905) & 0xFF;
  985         else
  986                 ctlr->timer[0] += inb(port+TIMER) & 0xFF;
  987 
  988         do{
  989                 if(status & hostError){
  990                         /*
  991                          * Adapter failure, try to find out why, reset if
  992                          * necessary. What happens if Tx is active and a reset
  993                          * occurs, need to retransmit? This probably isn't right.
  994                          */
  995                         COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  996                         x = ins(port+FifoDiagnostic);
  997                         COMMAND(port, SelectRegisterWindow, Wop);
  998         
  999                         if (status == 0xFFFF && x == 0xFFFF && ejectable(ctlr->did)) {
 1000                                 print("#l%d: Card ejected?\n", ether->ctlrno);
 1001                                 iunlock(&ctlr->wlock);
 1002                                 return;
 1003                         }
 1004 
 1005                         print("#l%d: status 0x%uX, diag 0x%uX\n",
 1006                             ether->ctlrno, status, x);
 1007 
 1008                         if(x & txOverrun){
 1009                                 if(ctlr->busmaster == 0)
 1010                                         COMMAND(port, TxReset, 0);
 1011                                 else
 1012                                         COMMAND(port, TxReset, (updnReset|dmaReset));
 1013                                 COMMAND(port, TxEnable, 0);
 1014                         }
 1015 
 1016                         if(x & rxUnderrun){
 1017                                 /*
 1018                                  * This shouldn't happen...
 1019                                  * Reset the receiver and restore the filter and RxEarly
 1020                                  * threshold before re-enabling.
 1021                                  * Need to restart any busmastering?
 1022                                  */
 1023                                 COMMAND(port, SelectRegisterWindow, Wstate);
 1024                                 s = (port+RxFilter) & 0x000F;
 1025                                 COMMAND(port, SelectRegisterWindow, Wop);
 1026                                 COMMAND(port, RxReset, 0);
 1027                                 while(STATUS(port) & commandInProgress)
 1028                                         ;
 1029                                 COMMAND(port, SetRxFilter, s);
 1030                                 COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts);
 1031                                 COMMAND(port, RxEnable, 0);
 1032                         }
 1033 
 1034                         status &= ~hostError;
 1035                 }
 1036 
 1037                 if(status & (transferInt|rxComplete)){
 1038                         receive(ether);
 1039                         status &= ~(transferInt|rxComplete);
 1040                 }
 1041 
 1042                 if(status & (upComplete)){
 1043                         COMMAND(port, AcknowledgeInterrupt, upComplete);
 1044                         receive905(ether);
 1045                         status &= ~upComplete;
 1046                         ctlr->upinterrupts++;
 1047                 }
 1048 
 1049                 if(status & txComplete){
 1050                         /*
 1051                          * Pop the TxStatus stack, accumulating errors.
 1052                          * Adjust the TX start threshold if there was an underrun.
 1053                          * If there was a Jabber or Underrun error, reset
 1054                          * the transmitter, taking care not to reset the dma logic
 1055                          * as a busmaster receive may be in progress.
 1056                          * For all conditions enable the transmitter.
 1057                          */
 1058                         if(ctlr->busmaster == 2)
 1059                                 txstatus = port+TxStatus905;
 1060                         else
 1061                                 txstatus = port+TxStatus;
 1062                         s = 0;
 1063                         do{
 1064                                 if(x = inb(txstatus))
 1065                                         outb(txstatus, 0);
 1066                                 s |= x;
 1067                         }while(STATUS(port) & txComplete);
 1068 
 1069                         if(s & txUnderrun){
 1070                                 if(ctlr->dnenabled){
 1071                                         while(inl(port+PktStatus) & dnInProg)
 1072                                                 ;
 1073                                 }
 1074                                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
 1075                                 while(ins(port+MediaStatus) & txInProg)
 1076                                         ;
 1077                                 COMMAND(port, SelectRegisterWindow, Wop);
 1078                                 if(ctlr->txthreshold < ETHERMAXTU)
 1079                                         ctlr->txthreshold += ETHERMINTU;
 1080                         }
 1081 
 1082                         /*
 1083                          * According to the manual, maxCollisions does not require
 1084                          * a TxReset, merely a TxEnable. However, evidence points to
 1085                          * it being necessary on the 3C905. The jury is still out.
 1086                          * On busy or badly configured networks maxCollisions can
 1087                          * happen frequently enough for messages to be annoying so
 1088                          * keep quiet about them by popular request.
 1089                          */
 1090                         if(s & (txJabber|txUnderrun|maxCollisions)){
 1091                                 if(ctlr->busmaster == 0)
 1092                                         COMMAND(port, TxReset, 0);
 1093                                 else
 1094                                         COMMAND(port, TxReset, (updnReset|dmaReset));
 1095                                 while(STATUS(port) & commandInProgress)
 1096                                         ;
 1097                                 COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts);
 1098                                 if(ctlr->busmaster == 2)
 1099                                         outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));
 1100                                 if(ctlr->dnenabled)
 1101                                         status |= dnComplete;
 1102                         }
 1103 
 1104                         if(s & ~(txStatusComplete|maxCollisions))
 1105                                 print("#l%d: txstatus 0x%uX, threshold %d\n",
 1106                                         ether->ctlrno, s, ctlr->txthreshold);
 1107                         COMMAND(port, TxEnable, 0);
 1108                         ether->oerrs++;
 1109                         status &= ~txComplete;
 1110                         status |= txAvailable;
 1111                 }
 1112 
 1113                 if(status & txAvailable){
 1114                         COMMAND(port, AcknowledgeInterrupt, txAvailable);
 1115                         ctlr->txbusy = 0;
 1116                         txstart(ether);
 1117                         status &= ~txAvailable;
 1118                 }
 1119 
 1120                 if(status & dnComplete){
 1121                         COMMAND(port, AcknowledgeInterrupt, dnComplete);
 1122                         txstart905(ether);
 1123                         status &= ~dnComplete;
 1124                         ctlr->dninterrupts++;
 1125                 }
 1126 
 1127                 if(status & updateStats){
 1128                         statistics(ether);
 1129                         status &= ~updateStats;
 1130                 }
 1131 
 1132                 /*
 1133                  * Currently, this shouldn't happen.
 1134                  */
 1135                 if(status & rxEarly){
 1136                         COMMAND(port, AcknowledgeInterrupt, rxEarly);
 1137                         status &= ~rxEarly;
 1138                 }
 1139 
 1140                 /*
 1141                  * Panic if there are any interrupts not dealt with.
 1142                  */
 1143                 if(status & interruptMask)
 1144                         panic("#l%d: interrupt mask 0x%uX\n", ether->ctlrno, status);
 1145 
 1146                 COMMAND(port, AcknowledgeInterrupt, interruptLatch);
 1147                 if(ctlr->cbfn != nil)
 1148                         intrackcb(ctlr->cbfn);
 1149 
 1150         }while((status = STATUS(port)) & (interruptMask|interruptLatch));
 1151 
 1152         if(ctlr->busmaster == 2)
 1153                 ctlr->timer[1] += inb(port+TIMER905) & 0xFF;
 1154         else
 1155                 ctlr->timer[1] += inb(port+TIMER) & 0xFF;
 1156 
 1157         COMMAND(port, SelectRegisterWindow, w);
 1158         iunlock(&ctlr->wlock);
 1159 }
 1160 
 1161 static long
 1162 ifstat(Ether* ether, void* a, long n, ulong offset)
 1163 {
 1164         char *p;
 1165         int len;
 1166         Ctlr *ctlr;
 1167 
 1168         if(n == 0)
 1169                 return 0;
 1170 
 1171         ctlr = ether->ctlr;
 1172 
 1173         ilock(&ctlr->wlock);
 1174         statistics(ether);
 1175         iunlock(&ctlr->wlock);
 1176 
 1177         p = malloc(READSTR);
 1178         len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
 1179         len += snprint(p+len, READSTR-len, "bogusinterrupts: %lud\n", ctlr->bogusinterrupts);
 1180         len += snprint(p+len, READSTR-len, "timer: %lud %lud\n",
 1181                 ctlr->timer[0], ctlr->timer[1]);
 1182         len += snprint(p+len, READSTR-len, "carrierlost: %lud\n",
 1183                 ctlr->stats[CarrierLost]);
 1184         len += snprint(p+len, READSTR-len, "sqeerrors: %lud\n",
 1185                 ctlr->stats[SqeErrors]);
 1186         len += snprint(p+len, READSTR-len, "multiplecolls: %lud\n",
 1187                 ctlr->stats[MultipleColls]);
 1188         len += snprint(p+len, READSTR-len, "singlecollframes: %lud\n",
 1189                 ctlr->stats[SingleCollFrames]);
 1190         len += snprint(p+len, READSTR-len, "latecollisions: %lud\n",
 1191                 ctlr->stats[LateCollisions]);
 1192         len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n",
 1193                 ctlr->stats[RxOverruns]);
 1194         len += snprint(p+len, READSTR-len, "framesxmittedok: %lud\n",
 1195                 ctlr->stats[FramesXmittedOk]);
 1196         len += snprint(p+len, READSTR-len, "framesrcvdok: %lud\n",
 1197                 ctlr->stats[FramesRcvdOk]);
 1198         len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n",
 1199                 ctlr->stats[FramesDeferred]);
 1200         len += snprint(p+len, READSTR-len, "bytesrcvdok: %lud\n",
 1201                 ctlr->stats[BytesRcvdOk]);
 1202         len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n",
 1203                 ctlr->stats[BytesRcvdOk+1]);
 1204 
 1205         if(ctlr->upenabled){
 1206                 if(ctlr->upqmax > ctlr->upqmaxhw)
 1207                         ctlr->upqmaxhw = ctlr->upqmax;
 1208                 len += snprint(p+len, READSTR-len, "up: q %lud i %lud m %d h %d s %lud\n",
 1209                         ctlr->upqueued, ctlr->upinterrupts,
 1210                         ctlr->upqmax, ctlr->upqmaxhw, ctlr->upstalls);
 1211                 ctlr->upqmax = 0;
 1212         }
 1213         if(ctlr->dnenabled){
 1214                 if(ctlr->dnqmax > ctlr->dnqmaxhw)
 1215                         ctlr->dnqmaxhw = ctlr->dnqmax;
 1216                 len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d h %d\n",
 1217                         ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax, ctlr->dnqmaxhw);
 1218                 ctlr->dnqmax = 0;
 1219         }
 1220 
 1221         snprint(p+len, READSTR-len, "badssd: %lud\n", ctlr->stats[BytesRcvdOk+2]);
 1222 
 1223         n = readstr(offset, a, n, p);
 1224         free(p);
 1225 
 1226         return n;
 1227 }
 1228 
 1229 static void
 1230 txrxreset(int port)
 1231 {
 1232         COMMAND(port, TxReset, 0);
 1233         while(STATUS(port) & commandInProgress)
 1234                 ;
 1235         COMMAND(port, RxReset, 0);
 1236         while(STATUS(port) & commandInProgress)
 1237                 ;
 1238 }
 1239 
 1240 static Ctlr*
 1241 tcmadapter(int port, int irq, Pcidev* pcidev)
 1242 {
 1243         Ctlr *ctlr;
 1244 
 1245         ctlr = malloc(sizeof(Ctlr));
 1246         ctlr->port = port;
 1247         ctlr->irq = irq;
 1248         ctlr->pcidev = pcidev;
 1249         ctlr->eepromcmd = EepromReadRegister;
 1250 
 1251         if(ctlrhead != nil)
 1252                 ctlrtail->next = ctlr;
 1253         else
 1254                 ctlrhead = ctlr;
 1255         ctlrtail = ctlr;
 1256 
 1257         return ctlr;
 1258 }
 1259 
 1260 /*
 1261  * Write two 0 bytes to identify the IDport and then reset the
 1262  * ID sequence. Then send the ID sequence to the card to get
 1263  * the card into command state.
 1264  */
 1265 static void
 1266 idseq(void)
 1267 {
 1268         int i;
 1269         uchar al;
 1270         static int reset, untag;
 1271 
 1272         /*
 1273          * One time only:
 1274          *      reset any adapters listening
 1275          */
 1276         if(reset == 0){
 1277                 outb(IDport, 0);
 1278                 outb(IDport, 0);
 1279                 outb(IDport, 0xC0);
 1280                 delay(20);
 1281                 reset = 1;
 1282         }
 1283 
 1284         outb(IDport, 0);
 1285         outb(IDport, 0);
 1286         for(al = 0xFF, i = 0; i < 255; i++){
 1287                 outb(IDport, al);
 1288                 if(al & 0x80){
 1289                         al <<= 1;
 1290                         al ^= 0xCF;
 1291                 }
 1292                 else
 1293                         al <<= 1;
 1294         }
 1295 
 1296         /*
 1297          * One time only:
 1298          *      write ID sequence to get the attention of all adapters;
 1299          *      untag all adapters.
 1300          * If a global reset is done here on all adapters it will confuse
 1301          * any ISA cards configured for EISA mode.
 1302          */
 1303         if(untag == 0){
 1304                 outb(IDport, 0xD0);
 1305                 untag = 1;
 1306         }
 1307 }
 1308 
 1309 static ulong
 1310 activate(void)
 1311 {
 1312         int i;
 1313         ushort x, acr;
 1314 
 1315         /*
 1316          * Do the little configuration dance:
 1317          *
 1318          * 2. write the ID sequence to get to command state.
 1319          */
 1320         idseq();
 1321 
 1322         /*
 1323          * 3. Read the Manufacturer ID from the EEPROM.
 1324          *    This is done by writing the IDPort with 0x87 (0x80
 1325          *    is the 'read EEPROM' command, 0x07 is the offset of
 1326          *    the Manufacturer ID field in the EEPROM).
 1327          *    The data comes back 1 bit at a time.
 1328          *    A delay seems necessary between reading the bits.
 1329          *
 1330          * If the ID doesn't match, there are no more adapters.
 1331          */
 1332         outb(IDport, 0x87);
 1333         delay(20);
 1334         for(x = 0, i = 0; i < 16; i++){
 1335                 delay(20);
 1336                 x <<= 1;
 1337                 x |= inb(IDport) & 0x01;
 1338         }
 1339         if(x != 0x6D50)
 1340                 return 0;
 1341 
 1342         /*
 1343          * 3. Read the Address Configuration from the EEPROM.
 1344          *    The Address Configuration field is at offset 0x08 in the EEPROM).
 1345          */
 1346         outb(IDport, 0x88);
 1347         for(acr = 0, i = 0; i < 16; i++){
 1348                 delay(20);
 1349                 acr <<= 1;
 1350                 acr |= inb(IDport) & 0x01;
 1351         }
 1352 
 1353         return (acr & 0x1F)*0x10 + 0x200;
 1354 }
 1355 
 1356 static void
 1357 tcm509isa(void)
 1358 {
 1359         int irq, port;
 1360 
 1361         /*
 1362          * Attempt to activate all adapters. If adapter is set for
 1363          * EISA mode (0x3F0), tag it and ignore. Otherwise, activate
 1364          * it fully.
 1365          */
 1366         while(port = activate()){
 1367                 if(ioalloc(port, 0x10, 0, "tcm509isa") < 0){
 1368                         print("tcm509isa: port 0x%uX in use\n", port);
 1369                         continue;
 1370                 }
 1371 
 1372                 /*
 1373                  * 6. Tag the adapter so it won't respond in future.
 1374                  */
 1375                 outb(IDport, 0xD1);
 1376                 if(port == 0x3F0){
 1377                         iofree(port);
 1378                         continue;
 1379                 }
 1380 
 1381                 /*
 1382                  * 6. Activate the adapter by writing the Activate command
 1383                  *    (0xFF).
 1384                  */
 1385                 outb(IDport, 0xFF);
 1386                 delay(20);
 1387 
 1388                 /*
 1389                  * 8. Can now talk to the adapter's I/O base addresses.
 1390                  *    Use the I/O base address from the acr just read.
 1391                  *
 1392                  *    Enable the adapter and clear out any lingering status
 1393                  *    and interrupts.
 1394                  */
 1395                 while(STATUS(port) & commandInProgress)
 1396                         ;
 1397                 COMMAND(port, SelectRegisterWindow, Wsetup);
 1398                 outs(port+ConfigControl, Ena);
 1399 
 1400                 txrxreset(port);
 1401                 COMMAND(port, AcknowledgeInterrupt, 0xFF);
 1402 
 1403                 irq = (ins(port+ResourceConfig)>>12) & 0x0F;
 1404                 tcmadapter(port, irq, nil);
 1405         }
 1406 }
 1407 
 1408 static void
 1409 tcm5XXeisa(void)
 1410 {
 1411         ushort x;
 1412         int irq, port, slot;
 1413 
 1414         /*
 1415          * Check if this is an EISA machine.
 1416          * If not, nothing to do.
 1417          */
 1418         if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4))
 1419                 return;
 1420 
 1421         /*
 1422          * Continue through the EISA slots looking for a match on both
 1423          * 3COM as the manufacturer and 3C579-* or 3C59[27]-* as the product.
 1424          * If an adapter is found, select window 0, enable it and clear
 1425          * out any lingering status and interrupts.
 1426          */
 1427         for(slot = 1; slot < MaxEISA; slot++){
 1428                 port = slot*0x1000;
 1429                 if(ioalloc(port, 0x1000, 0, "tcm5XXeisa") < 0){
 1430                         print("tcm5XXeisa: port 0x%uX in use\n", port);
 1431                         continue;
 1432                 }
 1433                 if(ins(port+0xC80+ManufacturerID) != 0x6D50){
 1434                         iofree(port);
 1435                         continue;
 1436                 }
 1437                 x = ins(port+0xC80+ProductID);
 1438                 if((x & 0xF0FF) != 0x9050 && (x & 0xFF00) != 0x5900){
 1439                         iofree(port);
 1440                         continue;
 1441                 }
 1442 
 1443                 COMMAND(port, SelectRegisterWindow, Wsetup);
 1444                 outs(port+ConfigControl, Ena);
 1445 
 1446                 txrxreset(port);
 1447                 COMMAND(port, AcknowledgeInterrupt, 0xFF);
 1448 
 1449                 irq = (ins(port+ResourceConfig)>>12) & 0x0F;
 1450                 tcmadapter(port, irq, nil);
 1451         }
 1452 }
 1453 
 1454 static void
 1455 tcm59Xpci(void)
 1456 {
 1457         Pcidev *p;
 1458         Ctlr *ctlr;
 1459         int irq, port;
 1460 
 1461         p = nil;
 1462         while(p = pcimatch(p, 0x10B7, 0)){
 1463                 if(p->ccrb != 0x02 || p->ccru != 0)
 1464                         continue;
 1465                 /*
 1466                  * Not prepared to deal with memory-mapped
 1467                  * devices yet.
 1468                  */
 1469                 if(!(p->mem[0].bar & 0x01))
 1470                         continue;
 1471                 port = p->mem[0].bar & ~0x01;
 1472                 if((port = ioalloc((port == 0)? -1: port,  p->mem[0].size, 
 1473                                           0, "tcm59Xpci")) < 0){
 1474                         print("tcm59Xpci: port 0x%uX in use\n", port);
 1475                         continue;
 1476                 }
 1477                 irq = p->intl;
 1478 
 1479                 txrxreset(port);
 1480                 COMMAND(port, AcknowledgeInterrupt, 0xFF);
 1481 
 1482                 ctlr = tcmadapter(port, irq, p);
 1483                 switch(p->did){
 1484                 default:
 1485                         break;
 1486                 case 0x5157:
 1487                         ctlr->eepromcmd = EepromRead8bRegister;
 1488                         ctlr->cbfnpa = p->mem[2].bar&~0x0F;
 1489                         ctlr->cbfn = vmap(p->mem[2].bar&~0x0F, p->mem[2].size);
 1490                         break;
 1491                 case 0x6056:
 1492                         ctlr->eepromcmd = EepromReadOffRegister;
 1493                         ctlr->cbfnpa = p->mem[2].bar&~0x0F;
 1494                         ctlr->cbfn = vmap(p->mem[2].bar&~0x0F, p->mem[2].size);
 1495                         break;
 1496                 }
 1497                 pcisetbme(p);
 1498         }
 1499 }
 1500 
 1501 static char* tcmpcmcia[] = {
 1502         "3C589",                        /* 3COM 589[ABCD] */
 1503         "3C562",                        /* 3COM 562 */
 1504         "589E",                         /* 3COM Megahertz 589E */
 1505         nil,
 1506 };
 1507 
 1508 static Ctlr*
 1509 tcm5XXpcmcia(Ether* ether)
 1510 {
 1511         int i;
 1512         Ctlr *ctlr;
 1513 
 1514         if(ether->type == nil)
 1515                 return nil;
 1516 
 1517         for(i = 0; tcmpcmcia[i] != nil; i++){
 1518                 if(cistrcmp(ether->type, tcmpcmcia[i]))
 1519                         continue;
 1520                 ctlr = tcmadapter(ether->port, ether->irq, nil);
 1521                 ctlr->active = 1;
 1522                 return ctlr;
 1523         }
 1524 
 1525         return nil;
 1526 }
 1527 
 1528 static void
 1529 setxcvr(Ctlr* ctlr, int xcvr)
 1530 {
 1531         int port, x;
 1532 
 1533         port = ctlr->port;
 1534         if(ctlr->rxstatus9){
 1535                 COMMAND(port, SelectRegisterWindow, Wsetup);
 1536                 x = ins(port+AddressConfig) & ~xcvrMask9;
 1537                 x |= (xcvr>>20)<<14;
 1538                 outs(port+AddressConfig, x);
 1539         }
 1540         else{
 1541                 COMMAND(port, SelectRegisterWindow, Wfifo);
 1542                 x = inl(port+InternalConfig) & ~xcvrMask;
 1543                 x |= xcvr;
 1544                 outl(port+InternalConfig, x);
 1545         }
 1546 
 1547         txrxreset(port);
 1548 }
 1549 
 1550 static void
 1551 setfullduplex(int port)
 1552 {
 1553         int x;
 1554 
 1555         COMMAND(port, SelectRegisterWindow, Wfifo);
 1556         x = ins(port+MacControl);
 1557         outs(port+MacControl, fullDuplexEnable|x);
 1558 
 1559         txrxreset(port);
 1560 }
 1561 
 1562 static int
 1563 miimdi(int port, int n)
 1564 {
 1565         int data, i;
 1566 
 1567         /*
 1568          * Read n bits from the MII Management Register.
 1569          */
 1570         data = 0;
 1571         for(i = n-1; i >= 0; i--){
 1572                 if(ins(port) & mgmtData)
 1573                         data |= (1<<i);
 1574                 microdelay(1);
 1575                 outs(port, mgmtClk);
 1576                 microdelay(1);
 1577                 outs(port, 0);
 1578                 microdelay(1);
 1579         }
 1580 
 1581         return data;
 1582 }
 1583 
 1584 static void
 1585 miimdo(int port, int bits, int n)
 1586 {
 1587         int i, mdo;
 1588 
 1589         /*
 1590          * Write n bits to the MII Management Register.
 1591          */
 1592         for(i = n-1; i >= 0; i--){
 1593                 if(bits & (1<<i))
 1594                         mdo = mgmtDir|mgmtData;
 1595                 else
 1596                         mdo = mgmtDir;
 1597                 outs(port, mdo);
 1598                 microdelay(1);
 1599                 outs(port, mdo|mgmtClk);
 1600                 microdelay(1);
 1601                 outs(port, mdo);
 1602                 microdelay(1);
 1603         }
 1604 }
 1605 
 1606 static int
 1607 miir(int port, int phyad, int regad)
 1608 {
 1609         int data, w;
 1610 
 1611         w = (STATUS(port)>>13) & 0x07;
 1612         COMMAND(port, SelectRegisterWindow, Wdiagnostic);
 1613         port += PhysicalMgmt;
 1614 
 1615         /*
 1616          * Preamble;
 1617          * ST+OP+PHYAD+REGAD;
 1618          * TA + 16 data bits.
 1619          */
 1620         miimdo(port, 0xFFFFFFFF, 32);
 1621         miimdo(port, 0x1800|(phyad<<5)|regad, 14);
 1622         data = miimdi(port, 18);
 1623 
 1624         port -= PhysicalMgmt;
 1625         COMMAND(port, SelectRegisterWindow, w);
 1626 
 1627         if(data & 0x10000)
 1628                 return -1;
 1629 
 1630         return data & 0xFFFF;
 1631 }
 1632 
 1633 static int
 1634 scanphy(int port)
 1635 {
 1636         int i, x;
 1637 
 1638         for(i = 0; i < 32; i++){
 1639                 if((x = miir(port, i, 2)) == -1 || x == 0)
 1640                         continue;
 1641                 x <<= 6;
 1642                 x |= miir(port, i, 3)>>10;
 1643                 XCVRDEBUG("phy%d: oui %uX reg1 %uX\n", i, x, miir(port, i, 1));
 1644                 USED(x);
 1645 
 1646                 return i;
 1647         }
 1648         return 24;
 1649 }
 1650 
 1651 static struct {
 1652         char *name;
 1653         int avail;
 1654         int xcvr;
 1655 } media[] = {
 1656         "10BaseT",      base10TAvailable,       xcvr10BaseT,
 1657         "10Base2",      coaxAvailable,          xcvr10Base2,
 1658         "100BaseTX",    baseTXAvailable,        xcvr100BaseTX,
 1659         "100BaseFX",    baseFXAvailable,        xcvr100BaseFX,
 1660         "aui",          auiAvailable,           xcvrAui,
 1661         "mii",          miiConnector,           xcvrMii
 1662 };
 1663 
 1664 static int
 1665 autoselect(Ctlr* ctlr)
 1666 {
 1667         int media, port, x;
 1668 
 1669         /*
 1670          * Pathetic attempt at automatic media selection.
 1671          * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX
 1672          * cards operational.
 1673          * It's a bonus if it works for anything else.
 1674          */
 1675         port = ctlr->port;
 1676         if(ctlr->rxstatus9){
 1677                 COMMAND(port, SelectRegisterWindow, Wsetup);
 1678                 x = ins(port+ConfigControl);
 1679                 media = 0;
 1680                 if(x & base10TAvailable9)
 1681                         media |= base10TAvailable;
 1682                 if(x & coaxAvailable9)
 1683                         media |= coaxAvailable;
 1684                 if(x & auiAvailable9)
 1685                         media |= auiAvailable;
 1686         }
 1687         else{
 1688                 COMMAND(port, SelectRegisterWindow, Wfifo);
 1689                 media = ins(port+ResetOptions);
 1690         }
 1691         XCVRDEBUG("autoselect: media %uX\n", media);
 1692 
 1693         if(media & miiConnector)
 1694                 return xcvrMii;
 1695 
 1696         COMMAND(port, SelectRegisterWindow, Wdiagnostic);
 1697         XCVRDEBUG("autoselect: media status %uX\n", ins(port+MediaStatus));
 1698 
 1699         if(media & baseTXAvailable){
 1700                 /*
 1701                  * Must have InternalConfig register.
 1702                  */
 1703                 setxcvr(ctlr, xcvr100BaseTX);
 1704 
 1705                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
 1706                 x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
 1707                 outs(port+MediaStatus, linkBeatEnable|x);
 1708                 delay(10);
 1709 
 1710                 if(ins(port+MediaStatus) & linkBeatDetect)
 1711                         return xcvr100BaseTX;
 1712                 outs(port+MediaStatus, x);
 1713         }
 1714 
 1715         if(media & base10TAvailable){
 1716                 setxcvr(ctlr, xcvr10BaseT);
 1717 
 1718                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
 1719                 x = ins(port+MediaStatus) & ~dcConverterEnabled;
 1720                 outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x);
 1721                 delay(100);
 1722 
 1723                 XCVRDEBUG("autoselect: 10BaseT media status %uX\n", ins(port+MediaStatus));
 1724                 if(ins(port+MediaStatus) & linkBeatDetect)
 1725                         return xcvr10BaseT;
 1726                 outs(port+MediaStatus, x);
 1727         }
 1728 
 1729         /*
 1730          * Botch.
 1731          */
 1732         return autoSelect;
 1733 }
 1734 
 1735 static int
 1736 eepromdata(Ctlr* ctlr, int offset)
 1737 {
 1738         int port;
 1739 
 1740         port = ctlr->port;
 1741 
 1742         COMMAND(port, SelectRegisterWindow, Wsetup);
 1743         while(EEPROMBUSY(port))
 1744                 ;
 1745         EEPROMCMD(port, ctlr->eepromcmd, offset);
 1746         while(EEPROMBUSY(port))
 1747                 ;
 1748         return EEPROMDATA(port);
 1749 }
 1750 
 1751 static void
 1752 resetctlr(Ctlr *ctlr)
 1753 {
 1754         int x, port = ctlr->port;
 1755 
 1756         txrxreset(port);
 1757         x = ins(port+ResetOp905B);
 1758         XCVRDEBUG("905[BC] reset ops 0x%uX\n", x);
 1759         x &= ~0x4010;
 1760         if(ctlr->did == 0x5157){
 1761                 x |= 0x0010;                    /* Invert LED */
 1762                 outs(port+ResetOp905B, x);
 1763         }
 1764         if(ctlr->did == 0x6056){
 1765                 x |= 0x4000;
 1766                 outs(port+ResetOp905B, x);
 1767 
 1768                 COMMAND(port, SelectRegisterWindow, Wsetup);
 1769                 outs(port, 0x0800);
 1770         }
 1771 }
 1772 
 1773 static void
 1774 shutdown(Ether *ether)
 1775 {
 1776 print("etherelnk3 shutting down\n");
 1777         resetctlr(ether->ctlr);
 1778 }
 1779 
 1780 int
 1781 etherelnk3reset(Ether* ether)
 1782 {
 1783         char *p;
 1784         Ctlr *ctlr;
 1785         uchar ea[Eaddrlen];
 1786         static int scandone;
 1787         int anar, anlpar, i, j, phyaddr, phystat, port, timeo, x;
 1788 
 1789         /*
 1790          * Scan for adapter on PCI, EISA and finally
 1791          * using the little ISA configuration dance.
 1792          */
 1793         if(scandone == 0){
 1794                 tcm59Xpci();
 1795                 tcm5XXeisa();
 1796                 tcm509isa();
 1797                 scandone = 1;
 1798         }
 1799 
 1800         /*
 1801          * Any adapter matches if no ether->port is supplied,
 1802          * otherwise the ports must match.
 1803          */
 1804         for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
 1805                 if(ctlr->active)
 1806                         continue;
 1807                 if(ether->port == 0 || ether->port == ctlr->port){
 1808                         ctlr->active = 1;
 1809                         break;
 1810                 }
 1811         }
 1812         if(ctlr == nil && (ctlr = tcm5XXpcmcia(ether)) == 0)
 1813                 return -1;
 1814 
 1815         ether->ctlr = ctlr;
 1816         port = ctlr->port;
 1817         ether->port = port;
 1818         ether->irq = ctlr->irq;
 1819         if(ctlr->pcidev != nil)
 1820                 ether->tbdf = ctlr->pcidev->tbdf;
 1821         else
 1822                 ether->tbdf = BUSUNKNOWN;
 1823 
 1824         /*
 1825          * Read the DeviceID from the EEPROM, it's at offset 0x03,
 1826          * and do something depending on capabilities.
 1827          */
 1828         switch(ctlr->did = eepromdata(ctlr, 0x03)){
 1829         case 0x5157:            /* 3C575 Cyclone */
 1830         case 0x6056:
 1831                 /*FALLTHROUGH*/
 1832         case 0x4500:            /* 3C450 HomePNA Tornado */
 1833         case 0x7646:            /* 3CSOHO100-TX */
 1834         case 0x9055:            /* 3C905B-TX */
 1835         case 0x9200:            /* 3C905C-TX */
 1836         case 0x9201:            /* 3C920 */
 1837         case 0x9805:            /* 3C9805: 3C980-TX Python-T 10/100baseTX */
 1838                 /*FALLTHROUGH*/
 1839         case 0x9000:            /* 3C900-TPO */
 1840         case 0x9001:            /* 3C900-COMBO */
 1841         case 0x9005:            /* 3C900B-COMBO */
 1842         case 0x9050:            /* 3C905-TX */
 1843         case 0x9051:            /* 3C905-T4 */
 1844                 if(BUSTYPE(ether->tbdf) != BusPCI)
 1845                         goto buggery;
 1846                 ctlr->busmaster = 2;
 1847                 goto vortex;
 1848         case 0x5900:            /* 3C590-[TP|COMBO|TPO] */
 1849         case 0x5920:            /* 3C592-[TP|COMBO|TPO] */
 1850         case 0x5950:            /* 3C595-TX */
 1851         case 0x5951:            /* 3C595-T4 */
 1852         case 0x5952:            /* 3C595-MII */
 1853         case 0x5970:            /* 3C597-TX */
 1854         case 0x5971:            /* 3C597-T4 */
 1855         case 0x5972:            /* 3C597-MII */
 1856                 ctlr->busmaster = 1;
 1857         vortex:
 1858                 COMMAND(port, SelectRegisterWindow, Wfifo);
 1859                 ctlr->xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask);
 1860                 ctlr->rxearly = 8188;
 1861                 ctlr->rxstatus9 = 0;
 1862                 break;
 1863         buggery:
 1864         default:
 1865                 ctlr->busmaster = 0;
 1866                 COMMAND(port, SelectRegisterWindow, Wsetup);
 1867                 x = ins(port+AddressConfig);
 1868                 ctlr->xcvr = ((x & xcvrMask9)>>14)<<20;
 1869                 if(x & autoSelect9)
 1870                         ctlr->xcvr |= autoSelect;
 1871                 ctlr->rxearly = 2044;
 1872                 ctlr->rxstatus9 = 1;
 1873                 break;
 1874         }
 1875         if(ctlr->rxearly >= 2048)
 1876                 ctlr->ts = 2;
 1877 
 1878         /*
 1879          * Check if the adapter's station address is to be overridden.
 1880          * If not, read it from the EEPROM and set in ether->ea prior to
 1881          * loading the station address in Wstation.
 1882          * The EEPROM returns 16-bits at a time.
 1883          */
 1884         memset(ea, 0, Eaddrlen);
 1885         if(memcmp(ea, ether->ea, Eaddrlen) == 0){
 1886                 for(i = 0; i < Eaddrlen/2; i++){
 1887                         x = eepromdata(ctlr, i);
 1888                         ether->ea[2*i] = x>>8;
 1889                         ether->ea[2*i+1] = x;
 1890                 }
 1891         }
 1892 
 1893         COMMAND(port, SelectRegisterWindow, Wstation);
 1894         for(i = 0; i < Eaddrlen; i++)
 1895                 outb(port+i, ether->ea[i]);
 1896 
 1897         /*
 1898          * Enable the transceiver if necessary and determine whether
 1899          * busmastering can be used. Due to bugs in the first revision
 1900          * of the 3C59[05], don't use busmastering at 10Mbps.
 1901          */
 1902         XCVRDEBUG("reset: xcvr %uX\n", ctlr->xcvr);
 1903 
 1904         /*
 1905          * Allow user to specify desired media in plan9.ini
 1906          */
 1907         for(i = 0; i < ether->nopt; i++){
 1908                 if(cistrncmp(ether->opt[i], "media=", 6) != 0)
 1909                         continue;
 1910                 p = ether->opt[i]+6;
 1911                 for(j = 0; j < nelem(media); j++)
 1912                         if(cistrcmp(p, media[j].name) == 0)
 1913                                 ctlr->xcvr = media[j].xcvr;
 1914         }
 1915         
 1916         /*
 1917          * forgive me, but i am weak
 1918          */
 1919         switch(ctlr->did){
 1920         default:
 1921                 if(ctlr->xcvr & autoSelect)
 1922                         ctlr->xcvr = autoselect(ctlr);
 1923                 break;
 1924         case 0x5157:
 1925         case 0x6056:
 1926         case 0x4500:
 1927         case 0x7646:
 1928         case 0x9055:
 1929         case 0x9200:
 1930         case 0x9201:
 1931         case 0x9805:
 1932                 ctlr->xcvr = xcvrMii;
 1933                 resetctlr(ctlr);
 1934                 break;
 1935         }
 1936         XCVRDEBUG("xcvr selected: %uX, did 0x%uX\n", ctlr->xcvr, ctlr->did);
 1937 
 1938         switch(ctlr->xcvr){
 1939         case xcvrMii:
 1940                 /*
 1941                  * Quick hack.
 1942                  */
 1943                 if(ctlr->did == 0x5157)
 1944                         phyaddr = 0;
 1945                 else if(ctlr->did == 0x6056)
 1946                         phyaddr = scanphy(port);
 1947                 else
 1948                         phyaddr = 24;
 1949                 for(i = 0; i < 7; i++)
 1950                         XCVRDEBUG(" %2.2uX", miir(port, phyaddr, i));
 1951                         XCVRDEBUG("\n");
 1952 
 1953                 for(timeo = 0; timeo < 30; timeo++){
 1954                         phystat = miir(port, phyaddr, 0x01);
 1955                         if(phystat & 0x20)
 1956                                 break;
 1957                         XCVRDEBUG(" %2.2uX", phystat);
 1958                         delay(100);
 1959                 }
 1960                 XCVRDEBUG(" %2.2uX", miir(port, phyaddr, 0x01));
 1961                 XCVRDEBUG("\n");
 1962 
 1963                 anar = miir(port, phyaddr, 0x04);
 1964                 anlpar = miir(port, phyaddr, 0x05) & 0x03E0;
 1965                 anar &= anlpar;
 1966                 miir(port, phyaddr, 0x00);
 1967                 XCVRDEBUG("mii an: %uX anlp: %uX r0:%uX r1:%uX\n",
 1968                         anar, anlpar, miir(port, phyaddr, 0x00),
 1969                         miir(port, phyaddr, 0x01));
 1970                 for(i = 0; i < ether->nopt; i++){
 1971                         if(cistrcmp(ether->opt[i], "fullduplex") == 0)
 1972                                 anar |= 0x0100;
 1973                         else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
 1974                                 anar |= 0x0100;
 1975                         else if(cistrcmp(ether->opt[i], "force100") == 0)
 1976                                 anar |= 0x0080;
 1977                 }
 1978                 XCVRDEBUG("mii anar: %uX\n", anar);
 1979                 if(anar & 0x0100){              /* 100BASE-TXFD */
 1980                         ether->mbps = 100;
 1981                         setfullduplex(port);
 1982                 }
 1983                 else if(anar & 0x0200){         /* 100BASE-T4 */
 1984                         /* nothing to do */
 1985                 }
 1986                 else if(anar & 0x0080)          /* 100BASE-TX */
 1987                         ether->mbps = 100;
 1988                 else if(anar & 0x0040)          /* 10BASE-TFD */
 1989                         setfullduplex(port);
 1990                 else{                           /* 10BASE-T */
 1991                         /* nothing to do */
 1992                 }
 1993                 break;
 1994         case xcvr100BaseTX:
 1995         case xcvr100BaseFX:
 1996                 COMMAND(port, SelectRegisterWindow, Wfifo);
 1997                 x = inl(port+InternalConfig) & ~ramPartitionMask;
 1998                 outl(port+InternalConfig, x|ramPartition1to1);
 1999 
 2000                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
 2001                 x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
 2002                 x |= linkBeatEnable;
 2003                 outs(port+MediaStatus, x);
 2004 
 2005                 if(x & dataRate100)
 2006                         ether->mbps = 100;
 2007                 break;
 2008         case xcvr10BaseT:
 2009                 /*
 2010                  * Enable Link Beat and Jabber to start the
 2011                  * transceiver.
 2012                  */
 2013                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
 2014                 x = ins(port+MediaStatus) & ~dcConverterEnabled;
 2015                 x |= linkBeatEnable|jabberGuardEnable;
 2016                 outs(port+MediaStatus, x);
 2017 
 2018                 if((ctlr->did & 0xFF00) == 0x5900)
 2019                         ctlr->busmaster = 0;
 2020                 break;
 2021         case xcvr10Base2:
 2022                 COMMAND(port, SelectRegisterWindow, Wdiagnostic);
 2023                 x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable);
 2024                 outs(port+MediaStatus, x);
 2025 
 2026                 /*
 2027                  * Start the DC-DC converter.
 2028                  * Wait > 800 microseconds.
 2029                  */
 2030                 COMMAND(port, EnableDcConverter, 0);
 2031                 delay(1);
 2032                 break;
 2033         }
 2034 
 2035         /*
 2036          * Wop is the normal operating register set.
 2037          * The 3C59[0257] adapters allow access to more than one register window
 2038          * at a time, but there are situations where switching still needs to be
 2039          * done, so just do it.
 2040          * Clear out any lingering Tx status.
 2041          */
 2042         COMMAND(port, SelectRegisterWindow, Wop);
 2043         if(ctlr->busmaster == 2)
 2044                 x = port+TxStatus905;
 2045         else
 2046                 x = port+TxStatus;
 2047         while(inb(x))
 2048                 outb(x, 0);
 2049 
 2050         /*
 2051          * Clear out the
 2052          * adapter statistics, clear the statistics logged into ctlr
 2053          * and enable statistics collection.
 2054          */
 2055         ilock(&ctlr->wlock);
 2056         statistics(ether);
 2057         memset(ctlr->stats, 0, sizeof(ctlr->stats));
 2058 
 2059         COMMAND(port, StatisticsEnable, 0);
 2060 
 2061         /*
 2062          * Allocate any receive buffers.
 2063          */
 2064         switch(ctlr->busmaster){
 2065         case 2:
 2066                 ctlr->dnenabled = 1;
 2067 
 2068                 /*
 2069                  * 10MUpldBug.
 2070                  * Disabling is too severe, can use receive busmastering at
 2071                  * 100Mbps OK, but how to tell which rate is actually being used -
 2072                  * the 3c905 always seems to have dataRate100 set?
 2073                  * Believe the bug doesn't apply if upRxEarlyEnable is set
 2074                  * and the threshold is set such that uploads won't start
 2075                  * until the whole packet has been received.
 2076                  */
 2077                 ctlr->upenabled = 1;
 2078                 x = eepromdata(ctlr, 0x0F);
 2079                 if(!(x & 0x01))
 2080                         outl(port+PktStatus, upRxEarlyEnable);
 2081 
 2082                 if(ctlr->upenabled || ctlr->dnenabled){
 2083                         ctlr->nup = Nup;
 2084                         ctlr->ndn = Ndn;
 2085                         init905(ctlr);
 2086                 }
 2087                 else {
 2088                         ctlr->rbp = rbpalloc(iallocb);
 2089                         if(ctlr->rbp == nil)
 2090                                 panic("can't reset ethernet: out of memory");
 2091                 }
 2092                 outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));
 2093                 break;
 2094         default:
 2095                 ctlr->rbp = rbpalloc(iallocb);
 2096                 if(ctlr->rbp == nil)
 2097                         panic("can't reset ethernet: out of memory");
 2098                 break;
 2099         }
 2100 
 2101         /*
 2102          * Set a base TxStartThresh which will be incremented
 2103          * if any txUnderrun errors occur and ensure no RxEarly
 2104          * interrupts happen.
 2105          */
 2106         ctlr->txthreshold = ETHERMAXTU/2;
 2107         COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts);
 2108         COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts);
 2109 
 2110         iunlock(&ctlr->wlock);
 2111 
 2112         /*
 2113          * Linkage to the generic ethernet driver.
 2114          */
 2115         ether->attach = attach;
 2116         ether->transmit = transmit;
 2117         ether->interrupt = interrupt;
 2118         ether->ifstat = ifstat;
 2119 
 2120         ether->promiscuous = promiscuous;
 2121         ether->multicast = multicast;
 2122         ether->shutdown = shutdown;
 2123         ether->arg = ether;
 2124 
 2125         return 0;
 2126 }
 2127 
 2128 void
 2129 etherelnk3link(void)
 2130 {
 2131         addethercard("elnk3", etherelnk3reset);
 2132         addethercard("3C509", etherelnk3reset);
 2133         addethercard("3C575", etherelnk3reset);
 2134 }

Cache object: d66da89fc987fc760b24f7bf337956ee


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.