mtd80x.c

Go to the documentation of this file.
00001 /**************************************************************************
00002 *
00003 *    mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip.
00004 *    Written 2004-2004 by Erdem Güven <zuencap@yahoo.com>
00005 *
00006 *    This program is free software; you can redistribute it and/or modify
00007 *    it under the terms of the GNU General Public License as published by
00008 *    the Free Software Foundation; either version 2 of the License, or
00009 *    (at your option) any later version.
00010 *
00011 *    This program is distributed in the hope that it will be useful,
00012 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 *    GNU General Public License for more details.
00015 *
00016 *    You should have received a copy of the GNU General Public License
00017 *    along with this program; if not, write to the Free Software
00018 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 *
00020 *    Portions of this code based on:
00021 *               fealnx.c: A Linux device driver for the mtd80x Ethernet chip
00022 *               Written 1998-2000 by Donald Becker
00023 *
00024 ***************************************************************************/
00025 
00026 FILE_LICENCE ( GPL2_OR_LATER );
00027 
00028 /* to get some global routines like printf */
00029 #include "etherboot.h"
00030 /* to get the interface to the body of the program */
00031 #include "nic.h"
00032 /* to get the PCI support functions, if this is a PCI NIC */
00033 #include <gpxe/pci.h>
00034 #include <gpxe/ethernet.h>
00035 #include <mii.h>
00036 
00037 /* Condensed operations for readability. */
00038 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
00039 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
00040 #define get_unaligned(ptr) (*(ptr))
00041 
00042 
00043 /* Operational parameters that are set at compile time. */
00044 
00045 /* Keep the ring sizes a power of two for compile efficiency.           */
00046 /* The compiler will convert <unsigned>'%'<2^N> into a bit mask.        */
00047 /* Making the Tx ring too large decreases the effectiveness of channel  */
00048 /* bonding and packet priority.                                         */
00049 /* There are no ill effects from too-large receive rings.               */
00050 #define TX_RING_SIZE 2
00051 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used.  */
00052 #define RX_RING_SIZE 4
00053 
00054 /* Operational parameters that usually are not changed. */
00055 /* Time in jiffies before concluding the transmitter is hung. */
00056 #define HZ 100
00057 #define TX_TIME_OUT   (6*HZ)
00058 
00059 /* Allocation size of Rx buffers with normal sized Ethernet frames.
00060    Do not change this value without good reason.  This is not a limit,
00061    but a way to keep a consistent allocation size among drivers.
00062  */
00063 #define PKT_BUF_SZ 1536
00064 
00065 /* for different PHY */
00066 enum phy_type_flags {
00067     MysonPHY = 1,
00068     AhdocPHY = 2,
00069     SeeqPHY = 3,
00070     MarvellPHY = 4,
00071     Myson981 = 5,
00072     LevelOnePHY = 6,
00073     OtherPHY = 10,
00074 };
00075 
00076 /* A chip capabilities table*/
00077 enum chip_capability_flags {
00078     HAS_MII_XCVR,
00079     HAS_CHIP_XCVR,
00080 };
00081 
00082 #if 0 /* not used */
00083 static
00084 struct chip_info
00085 {
00086     u16 dev_id;
00087     int flag;
00088 }
00089 mtd80x_chips[] = {
00090                      {0x0800, HAS_MII_XCVR},
00091                      {0x0803, HAS_CHIP_XCVR},
00092                      {0x0891, HAS_MII_XCVR}
00093                  };
00094 static int chip_cnt = sizeof( mtd80x_chips ) / sizeof( struct chip_info );
00095 #endif
00096 
00097 /* Offsets to the Command and Status Registers. */
00098 enum mtd_offsets {
00099     PAR0 = 0x0,        /* physical address 0-3 */
00100     PAR1 = 0x04,        /* physical address 4-5 */
00101     MAR0 = 0x08,        /* multicast address 0-3 */
00102     MAR1 = 0x0C,        /* multicast address 4-7 */
00103     FAR0 = 0x10,        /* flow-control address 0-3 */
00104     FAR1 = 0x14,        /* flow-control address 4-5 */
00105     TCRRCR = 0x18,        /* receive & transmit configuration */
00106     BCR = 0x1C,        /* bus command */
00107     TXPDR = 0x20,        /* transmit polling demand */
00108     RXPDR = 0x24,        /* receive polling demand */
00109     RXCWP = 0x28,        /* receive current word pointer */
00110     TXLBA = 0x2C,        /* transmit list base address */
00111     RXLBA = 0x30,        /* receive list base address */
00112     ISR = 0x34,        /* interrupt status */
00113     IMR = 0x38,        /* interrupt mask */
00114     FTH = 0x3C,        /* flow control high/low threshold */
00115     MANAGEMENT = 0x40,    /* bootrom/eeprom and mii management */
00116     TALLY = 0x44,        /* tally counters for crc and mpa */
00117     TSR = 0x48,        /* tally counter for transmit status */
00118     BMCRSR = 0x4c,        /* basic mode control and status */
00119     PHYIDENTIFIER = 0x50,    /* phy identifier */
00120     ANARANLPAR = 0x54,    /* auto-negotiation advertisement and link
00121                                                        partner ability */
00122     ANEROCR = 0x58,        /* auto-negotiation expansion and pci conf. */
00123     BPREMRPSR = 0x5c,    /* bypass & receive error mask and phy status */
00124 };
00125 
00126 /* Bits in the interrupt status/enable registers. */
00127 /* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
00128 enum intr_status_bits {
00129     RFCON = 0x00020000, /* receive flow control xon packet */
00130     RFCOFF = 0x00010000, /* receive flow control xoff packet */
00131     LSCStatus = 0x00008000, /* link status change */
00132     ANCStatus = 0x00004000, /* autonegotiation completed */
00133     FBE = 0x00002000, /* fatal bus error */
00134     FBEMask = 0x00001800, /* mask bit12-11 */
00135     ParityErr = 0x00000000, /* parity error */
00136     TargetErr = 0x00001000, /* target abort */
00137     MasterErr = 0x00000800, /* master error */
00138     TUNF = 0x00000400, /* transmit underflow */
00139     ROVF = 0x00000200, /* receive overflow */
00140     ETI = 0x00000100, /* transmit early int */
00141     ERI = 0x00000080, /* receive early int */
00142     CNTOVF = 0x00000040, /* counter overflow */
00143     RBU = 0x00000020, /* receive buffer unavailable */
00144     TBU = 0x00000010, /* transmit buffer unavilable */
00145     TI = 0x00000008, /* transmit interrupt */
00146     RI = 0x00000004, /* receive interrupt */
00147     RxErr = 0x00000002, /* receive error */
00148 };
00149 
00150 /* Bits in the NetworkConfig register. */
00151 enum rx_mode_bits {
00152     RxModeMask   = 0xe0,
00153     AcceptAllPhys = 0x80,        /* promiscuous mode */
00154     AcceptBroadcast = 0x40,        /* accept broadcast */
00155     AcceptMulticast = 0x20,        /* accept mutlicast */
00156     AcceptRunt   = 0x08,        /* receive runt pkt */
00157     ALP          = 0x04,        /* receive long pkt */
00158     AcceptErr    = 0x02,        /* receive error pkt */
00159 
00160     AcceptMyPhys = 0x00000000,
00161     RxEnable     = 0x00000001,
00162     RxFlowCtrl   = 0x00002000,
00163     TxEnable     = 0x00040000,
00164     TxModeFDX    = 0x00100000,
00165     TxThreshold  = 0x00e00000,
00166 
00167     PS1000       = 0x00010000,
00168     PS10         = 0x00080000,
00169     FD           = 0x00100000,
00170 };
00171 
00172 /* Bits in network_desc.status */
00173 enum rx_desc_status_bits {
00174     RXOWN = 0x80000000, /* own bit */
00175     FLNGMASK = 0x0fff0000, /* frame length */
00176     FLNGShift = 16,
00177     MARSTATUS = 0x00004000, /* multicast address received */
00178     BARSTATUS = 0x00002000, /* broadcast address received */
00179     PHYSTATUS = 0x00001000, /* physical address received */
00180     RXFSD = 0x00000800, /* first descriptor */
00181     RXLSD = 0x00000400, /* last descriptor */
00182     ErrorSummary = 0x80, /* error summary */
00183     RUNT = 0x40,  /* runt packet received */
00184     LONG = 0x20,  /* long packet received */
00185     FAE = 0x10,  /* frame align error */
00186     CRC = 0x08,  /* crc error */
00187     RXER = 0x04,  /* receive error */
00188 };
00189 
00190 enum rx_desc_control_bits {
00191     RXIC = 0x00800000, /* interrupt control */
00192     RBSShift = 0,
00193 };
00194 
00195 enum tx_desc_status_bits {
00196     TXOWN = 0x80000000, /* own bit */
00197     JABTO = 0x00004000, /* jabber timeout */
00198     CSL = 0x00002000, /* carrier sense lost */
00199     LC = 0x00001000, /* late collision */
00200     EC = 0x00000800, /* excessive collision */
00201     UDF = 0x00000400, /* fifo underflow */
00202     DFR = 0x00000200, /* deferred */
00203     HF = 0x00000100, /* heartbeat fail */
00204     NCRMask = 0x000000ff, /* collision retry count */
00205     NCRShift = 0,
00206 };
00207 
00208 enum tx_desc_control_bits {
00209     TXIC = 0x80000000, /* interrupt control */
00210     ETIControl = 0x40000000, /* early transmit interrupt */
00211     TXLD = 0x20000000, /* last descriptor */
00212     TXFD = 0x10000000, /* first descriptor */
00213     CRCEnable = 0x08000000, /* crc control */
00214     PADEnable = 0x04000000, /* padding control */
00215     RetryTxLC = 0x02000000, /* retry late collision */
00216     PKTSMask = 0x3ff800, /* packet size bit21-11 */
00217     PKTSShift = 11,
00218     TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */
00219     TBSShift = 0,
00220 };
00221 
00222 /* BootROM/EEPROM/MII Management Register */
00223 #define MASK_MIIR_MII_READ       0x00000000
00224 #define MASK_MIIR_MII_WRITE      0x00000008
00225 #define MASK_MIIR_MII_MDO        0x00000004
00226 #define MASK_MIIR_MII_MDI        0x00000002
00227 #define MASK_MIIR_MII_MDC        0x00000001
00228 
00229 /* ST+OP+PHYAD+REGAD+TA */
00230 #define OP_READ             0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */
00231 #define OP_WRITE            0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */
00232 
00233 /* ------------------------------------------------------------------------- */
00234 /*      Constants for Myson PHY                                              */
00235 /* ------------------------------------------------------------------------- */
00236 #define MysonPHYID      0xd0000302
00237 /* 89-7-27 add, (begin) */
00238 #define MysonPHYID0     0x0302
00239 #define StatusRegister  18
00240 #define SPEED100        0x0400 // bit10
00241 #define FULLMODE        0x0800 // bit11
00242 /* 89-7-27 add, (end) */
00243 
00244 /* ------------------------------------------------------------------------- */
00245 /*      Constants for Seeq 80225 PHY                                         */
00246 /* ------------------------------------------------------------------------- */
00247 #define SeeqPHYID0      0x0016
00248 
00249 #define MIIRegister18   18
00250 #define SPD_DET_100     0x80
00251 #define DPLX_DET_FULL   0x40
00252 
00253 /* ------------------------------------------------------------------------- */
00254 /*      Constants for Ahdoc 101 PHY                                          */
00255 /* ------------------------------------------------------------------------- */
00256 #define AhdocPHYID0     0x0022
00257 
00258 #define DiagnosticReg   18
00259 #define DPLX_FULL       0x0800
00260 #define Speed_100       0x0400
00261 
00262 /* 89/6/13 add, */
00263 /* -------------------------------------------------------------------------- */
00264 /*      Constants                                                             */
00265 /* -------------------------------------------------------------------------- */
00266 #define MarvellPHYID0           0x0141
00267 #define LevelOnePHYID0  0x0013
00268 
00269 #define MII1000BaseTControlReg  9
00270 #define MII1000BaseTStatusReg   10
00271 #define SpecificReg  17
00272 
00273 /* for 1000BaseT Control Register */
00274 #define PHYAbletoPerform1000FullDuplex  0x0200
00275 #define PHYAbletoPerform1000HalfDuplex  0x0100
00276 #define PHY1000AbilityMask              0x300
00277 
00278 // for phy specific status register, marvell phy.
00279 #define SpeedMask       0x0c000
00280 #define Speed_1000M     0x08000
00281 #define Speed_100M      0x4000
00282 #define Speed_10M       0
00283 #define Full_Duplex     0x2000
00284 
00285 // 89/12/29 add, for phy specific status register, levelone phy, (begin)
00286 #define LXT1000_100M    0x08000
00287 #define LXT1000_1000M   0x0c000
00288 #define LXT1000_Full    0x200
00289 // 89/12/29 add, for phy specific status register, levelone phy, (end)
00290 
00291 #if 0
00292 /* for 3-in-1 case */
00293 #define PS10            0x00080000
00294 #define FD              0x00100000
00295 #define PS1000          0x00010000
00296 #endif
00297 
00298 /* for PHY */
00299 #define LinkIsUp        0x0004
00300 #define LinkIsUp2 0x00040000
00301 
00302 /* Create a static buffer of size PKT_BUF_SZ for each
00303 RX and TX Descriptor.  All descriptors point to a
00304 part of this buffer */
00305 struct {
00306         u8 txb[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned(8)));
00307         u8 rxb[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned(8)));
00308 } mtd80x_bufs __shared;
00309 #define txb mtd80x_bufs.txb
00310 #define rxb mtd80x_bufs.rxb
00311 
00312 /* The Tulip Rx and Tx buffer descriptors. */
00313 struct mtd_desc
00314 {
00315     s32 status;
00316     s32 control;
00317     u32 buffer;
00318     u32 next_desc;
00319     struct mtd_desc *next_desc_logical;
00320     u8* skbuff;
00321     u32 reserved1;
00322     u32 reserved2;
00323 };
00324 
00325 struct mtd_private
00326 {
00327     struct mtd_desc rx_ring[RX_RING_SIZE];
00328     struct mtd_desc tx_ring[TX_RING_SIZE];
00329 
00330     /* Frequently used values: keep some adjacent for cache effect. */
00331     int flags;
00332     struct pci_dev *pci_dev;
00333     unsigned long crvalue;
00334     unsigned long bcrvalue;
00335     /*unsigned long imrvalue;*/
00336     struct mtd_desc *cur_rx;
00337     struct mtd_desc *lack_rxbuf;
00338     int really_rx_count;
00339     struct mtd_desc *cur_tx;
00340     struct mtd_desc *cur_tx_copy;
00341     int really_tx_count;
00342     int free_tx_count;
00343     unsigned int rx_buf_sz; /* Based on MTU+slack. */
00344 
00345     /* These values are keep track of the transceiver/media in use. */
00346     unsigned int linkok;
00347     unsigned int line_speed;
00348     unsigned int duplexmode;
00349     unsigned int default_port:
00350     4; /* Last dev->if_port value. */
00351     unsigned int PHYType;
00352 
00353     /* MII transceiver section. */
00354     int mii_cnt;  /* MII device addresses. */
00355     unsigned char phys[1]; /* MII device addresses. */
00356 
00357     /*other*/
00358     const char *nic_name;
00359     int ioaddr;
00360     u16 dev_id;
00361 };
00362 
00363 static struct mtd_private mtdx;
00364 
00365 static int mdio_read(struct nic * , int phy_id, int location);
00366 static void getlinktype(struct nic * );
00367 static void getlinkstatus(struct nic * );
00368 static void set_rx_mode(struct nic *);
00369 
00370 /**************************************************************************
00371  *  init_ring - setup the tx and rx descriptors
00372  *************************************************************************/
00373 static void init_ring(struct nic *nic __unused)
00374 {
00375     int i;
00376 
00377     mtdx.cur_rx = &mtdx.rx_ring[0];
00378 
00379     mtdx.rx_buf_sz = PKT_BUF_SZ;
00380     /*mtdx.rx_head_desc = &mtdx.rx_ring[0];*/
00381 
00382     /* Initialize all Rx descriptors. */
00383     /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
00384     for (i = 0; i < RX_RING_SIZE; i++)
00385     {
00386         mtdx.rx_ring[i].status = RXOWN;
00387         mtdx.rx_ring[i].control = mtdx.rx_buf_sz << RBSShift;
00388         mtdx.rx_ring[i].next_desc = virt_to_le32desc(&mtdx.rx_ring[i+1]);
00389         mtdx.rx_ring[i].next_desc_logical = &mtdx.rx_ring[i+1];
00390         mtdx.rx_ring[i].buffer = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
00391         mtdx.rx_ring[i].skbuff = &rxb[i * PKT_BUF_SZ];
00392     }
00393     /* Mark the last entry as wrapping the ring. */
00394     mtdx.rx_ring[i-1].next_desc = virt_to_le32desc(&mtdx.rx_ring[0]);
00395     mtdx.rx_ring[i-1].next_desc_logical = &mtdx.rx_ring[0];
00396 
00397     /* We only use one transmit buffer, but two
00398      * descriptors so transmit engines have somewhere
00399      * to point should they feel the need */
00400     mtdx.tx_ring[0].status = 0x00000000;
00401     mtdx.tx_ring[0].buffer = virt_to_bus(&txb[0]);
00402     mtdx.tx_ring[0].next_desc = virt_to_le32desc(&mtdx.tx_ring[1]);
00403 
00404     /* This descriptor is never used */
00405     mtdx.tx_ring[1].status = 0x00000000;
00406     mtdx.tx_ring[1].buffer = 0; /*virt_to_bus(&txb[1]); */
00407     mtdx.tx_ring[1].next_desc = virt_to_le32desc(&mtdx.tx_ring[0]);
00408 
00409     return;
00410 }
00411 
00412 /**************************************************************************
00413 RESET - Reset Adapter
00414 ***************************************************************************/
00415 static void mtd_reset( struct nic *nic )
00416 {
00417     /* Reset the chip to erase previous misconfiguration. */
00418     outl(0x00000001, mtdx.ioaddr + BCR);
00419 
00420     init_ring(nic);
00421 
00422     outl(virt_to_bus(mtdx.rx_ring), mtdx.ioaddr + RXLBA);
00423     outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
00424 
00425     /* Initialize other registers. */
00426     /* Configure the PCI bus bursts and FIFO thresholds. */
00427     mtdx.bcrvalue = 0x10; /* little-endian, 8 burst length */
00428     mtdx.crvalue = 0xa00; /* rx 128 burst length */
00429 
00430         if ( mtdx.dev_id == 0x891 ) {
00431                 mtdx.bcrvalue |= 0x200; /* set PROG bit */
00432                 mtdx.crvalue |= 0x02000000;     /* set enhanced bit */
00433         }
00434 
00435     outl( mtdx.bcrvalue, mtdx.ioaddr + BCR);
00436 
00437     /* Restart Rx engine if stopped. */
00438     outl(0, mtdx.ioaddr + RXPDR);
00439 
00440     getlinkstatus(nic);
00441     if (mtdx.linkok)
00442     {
00443         static const char* texts[]={"half","full","10","100","1000"};
00444         getlinktype(nic);
00445         DBG ( "Link is OK : %s %s\n", texts[mtdx.duplexmode-1], texts[mtdx.line_speed+1] );
00446     } else
00447     {
00448         DBG ( "No link!!!\n" );
00449     }
00450 
00451     mtdx.crvalue |= /*TxEnable |*/ RxEnable | TxThreshold;
00452     set_rx_mode(nic);
00453 
00454     /* Clear interrupts by setting the interrupt mask. */
00455     outl(FBE | TUNF | CNTOVF | RBU | TI | RI, mtdx.ioaddr + ISR);
00456     outl( 0, mtdx.ioaddr + IMR);
00457 }
00458 
00459 /**************************************************************************
00460 POLL - Wait for a frame
00461 ***************************************************************************/
00462 static int mtd_poll(struct nic *nic, __unused int retrieve)
00463 {
00464     s32 rx_status = mtdx.cur_rx->status;
00465     int retval = 0;
00466 
00467     if( ( rx_status & RXOWN ) != 0 )
00468     {
00469         return 0;
00470     }
00471 
00472     if (rx_status & ErrorSummary)
00473     { /* there was a fatal error */
00474         printf( "%s: Receive error, Rx status %8.8x, Error(s) %s%s%s\n",
00475                 mtdx.nic_name, (unsigned int) rx_status,
00476                 (rx_status & (LONG | RUNT)) ? "length_error ":"",
00477                 (rx_status & RXER) ? "frame_error ":"",
00478                 (rx_status & CRC) ? "crc_error ":"" );
00479         retval = 0;
00480     } else if( !((rx_status & RXFSD) && (rx_status & RXLSD)) )
00481     {
00482         /* this pkt is too long, over one rx buffer */
00483         printf("Pkt is too long, over one rx buffer.\n");
00484         retval = 0;
00485     } else
00486     { /* this received pkt is ok */
00487         /* Omit the four octet CRC from the length. */
00488         short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4;
00489 
00490         DBG ( " netdev_rx() normal Rx pkt length %d"
00491               " status %x.\n", pkt_len, (unsigned int) rx_status );
00492 
00493         nic->packetlen = pkt_len;
00494         memcpy(nic->packet, mtdx.cur_rx->skbuff, pkt_len);
00495 
00496         retval = 1;
00497     }
00498 
00499     while( ( mtdx.cur_rx->status & RXOWN ) == 0 )
00500     {
00501         mtdx.cur_rx->status = RXOWN;
00502         mtdx.cur_rx = mtdx.cur_rx->next_desc_logical;
00503     }
00504 
00505     /* Restart Rx engine if stopped. */
00506     outl(0, mtdx.ioaddr + RXPDR);
00507 
00508     return retval;
00509 }
00510 
00511 /**************************************************************************
00512 TRANSMIT - Transmit a frame
00513 ***************************************************************************/
00514 static void mtd_transmit(
00515     struct nic *nic,
00516     const char *dest,            /* Destination */
00517     unsigned int type,            /* Type */
00518     unsigned int size,            /* size */
00519     const char *data)            /* Packet */
00520 {
00521     u32 to;
00522     u32 tx_status;
00523     unsigned int nstype = htons ( type );
00524 
00525     memcpy( txb, dest, ETH_ALEN );
00526     memcpy( txb + ETH_ALEN, nic->node_addr, ETH_ALEN );
00527     memcpy( txb + 2 * ETH_ALEN, &nstype, 2 );
00528     memcpy( txb + ETH_HLEN, data, size );
00529 
00530     size += ETH_HLEN;
00531     size &= 0x0FFF;
00532     while( size < ETH_ZLEN )
00533     {
00534         txb[size++] = '\0';
00535     }
00536 
00537     mtdx.tx_ring[0].control = TXLD | TXFD | CRCEnable | PADEnable;
00538     mtdx.tx_ring[0].control |= (size << PKTSShift); /* pkt size */
00539     mtdx.tx_ring[0].control |= (size << TBSShift); /* buffer size */
00540     mtdx.tx_ring[0].status = TXOWN;
00541 
00542     /* Point to transmit descriptor */
00543     outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
00544     /* Enable Tx */
00545     outl( mtdx.crvalue | TxEnable, mtdx.ioaddr + TCRRCR);
00546     /* Wake the potentially-idle transmit channel. */
00547     outl(0, mtdx.ioaddr + TXPDR);
00548 
00549     to = currticks() + TX_TIME_OUT;
00550     while(( mtdx.tx_ring[0].status & TXOWN) && (currticks() < to));
00551 
00552     /* Disable Tx */
00553     outl( mtdx.crvalue & (~TxEnable), mtdx.ioaddr + TCRRCR);
00554 
00555     tx_status = mtdx.tx_ring[0].status;
00556     if (currticks() >= to){
00557         DBG ( "TX Time Out" );
00558     } else if( tx_status & (CSL | LC | EC | UDF | HF)){
00559         printf( "Transmit error: %8.8x %s %s %s %s %s\n",
00560                 (unsigned int) tx_status,
00561                 tx_status & EC ? "abort" : "",
00562                 tx_status & CSL ? "carrier" : "",
00563                 tx_status & LC ? "late" : "",
00564                 tx_status & UDF ? "fifo" : "",
00565                 tx_status & HF ? "heartbeat" : "" );
00566     }
00567 
00568     /*hex_dump( txb, size );*/
00569     /*pause();*/
00570 
00571     DBG ( "TRANSMIT\n" );
00572 }
00573 
00574 /**************************************************************************
00575 DISABLE - Turn off ethernet interface
00576 ***************************************************************************/
00577 static void mtd_disable ( struct nic *nic ) {
00578 
00579     /* Disable Tx Rx*/
00580     outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR );
00581 
00582     /* Reset the chip to erase previous misconfiguration. */
00583     mtd_reset(nic);
00584 
00585     DBG ( "DISABLE\n" );
00586 }
00587 
00588 static struct nic_operations mtd_operations = {
00589         .connect        = dummy_connect,
00590         .poll           = mtd_poll,
00591         .transmit       = mtd_transmit,
00592         .irq            = dummy_irq,
00593 
00594 };
00595 
00596 static struct pci_device_id mtd80x_nics[] = {
00597         PCI_ROM(0x1516, 0x0800, "MTD800", "Myson MTD800", 0),
00598         PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X", 0),
00599         PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891", 0),
00600 };
00601 
00602 PCI_DRIVER ( mtd80x_driver, mtd80x_nics, PCI_NO_CLASS );
00603 
00604 /**************************************************************************
00605 PROBE - Look for an adapter, this routine's visible to the outside
00606 ***************************************************************************/
00607 
00608 static int mtd_probe ( struct nic *nic, struct pci_device *pci ) {
00609 
00610     int i;
00611 
00612     if (pci->ioaddr == 0)
00613             return 0;
00614 
00615     adjust_pci_device(pci);
00616 
00617     nic->ioaddr = pci->ioaddr;
00618     nic->irqno = 0;
00619 
00620     mtdx.nic_name = pci->driver_name;
00621     mtdx.dev_id = pci->device;
00622     mtdx.ioaddr = nic->ioaddr;
00623 
00624     /* read ethernet id */
00625     for (i = 0; i < 6; ++i)
00626     {
00627         nic->node_addr[i] = inb(mtdx.ioaddr + PAR0 + i);
00628     }
00629 
00630     if (memcmp(nic->node_addr, "\0\0\0\0\0\0", 6) == 0)
00631     {
00632         return 0;
00633     }
00634 
00635     DBG ( "%s: ioaddr %4.4x MAC %s\n", mtdx.nic_name, mtdx.ioaddr, eth_ntoa ( nic->node_addr ) );
00636 
00637     /* Reset the chip to erase previous misconfiguration. */
00638     outl(0x00000001, mtdx.ioaddr + BCR);
00639 
00640     /* find the connected MII xcvrs */
00641 
00642     if( mtdx.dev_id != 0x803 )
00643     {
00644         int phy, phy_idx = 0;
00645 
00646         for (phy = 1; phy < 32 && phy_idx < 1; phy++) {
00647             int mii_status = mdio_read(nic, phy, 1);
00648 
00649             if (mii_status != 0xffff && mii_status != 0x0000) {
00650                 mtdx.phys[phy_idx] = phy;
00651 
00652                 DBG ( "%s: MII PHY found at address %d, status "
00653                       "0x%4.4x.\n", mtdx.nic_name, phy, mii_status );
00654                 /* get phy type */
00655                 {
00656                     unsigned int data;
00657 
00658                     data = mdio_read(nic, mtdx.phys[phy_idx], 2);
00659                     if (data == SeeqPHYID0)
00660                         mtdx.PHYType = SeeqPHY;
00661                     else if (data == AhdocPHYID0)
00662                         mtdx.PHYType = AhdocPHY;
00663                     else if (data == MarvellPHYID0)
00664                         mtdx.PHYType = MarvellPHY;
00665                     else if (data == MysonPHYID0)
00666                         mtdx.PHYType = Myson981;
00667                     else if (data == LevelOnePHYID0)
00668                         mtdx.PHYType = LevelOnePHY;
00669                     else
00670                         mtdx.PHYType = OtherPHY;
00671                 }
00672                 phy_idx++;
00673             }
00674         }
00675 
00676         mtdx.mii_cnt = phy_idx;
00677         if (phy_idx == 0) {
00678             printf("%s: MII PHY not found -- this device may "
00679                    "not operate correctly.\n", mtdx.nic_name);
00680         }
00681     } else {
00682         mtdx.phys[0] = 32;
00683         /* get phy type */
00684         if (inl(mtdx.ioaddr + PHYIDENTIFIER) == MysonPHYID ) {
00685             mtdx.PHYType = MysonPHY;
00686             DBG ( "MysonPHY\n" );
00687         } else {
00688             mtdx.PHYType = OtherPHY;
00689             DBG ( "OtherPHY\n" );
00690         }
00691     }
00692 
00693     getlinkstatus(nic);
00694     if( !mtdx.linkok )
00695     {
00696         printf("No link!!!\n");
00697         return 0;
00698     }
00699 
00700     mtd_reset( nic );
00701 
00702     /* point to NIC specific routines */
00703     nic->nic_op = &mtd_operations;
00704     return 1;
00705 }
00706 
00707 
00708 /**************************************************************************/
00709 static void set_rx_mode(struct nic *nic __unused)
00710 {
00711     u32 mc_filter[2];                       /* Multicast hash filter */
00712     u32 rx_mode;
00713 
00714     /* Too many to match, or accept all multicasts. */
00715     mc_filter[1] = mc_filter[0] = ~0;
00716     rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
00717 
00718     outl(mc_filter[0], mtdx.ioaddr + MAR0);
00719     outl(mc_filter[1], mtdx.ioaddr + MAR1);
00720 
00721     mtdx.crvalue = ( mtdx.crvalue & ~RxModeMask ) | rx_mode;
00722     outb( mtdx.crvalue, mtdx.ioaddr + TCRRCR);
00723 }
00724 /**************************************************************************/
00725 static unsigned int m80x_read_tick(void)
00726 /* function: Reads the Timer tick count register which decrements by 2 from  */
00727 /*           65536 to 0 every 1/36.414 of a second. Each 2 decrements of the */
00728 /*           count represents 838 nsec's.                                    */
00729 /* input   : none.                                                           */
00730 /* output  : none.                                                           */
00731 {
00732     unsigned char tmp;
00733     int value;
00734 
00735     outb((char) 0x06, 0x43); // Command 8254 to latch T0's count
00736 
00737     // now read the count.
00738     tmp = (unsigned char) inb(0x40);
00739     value = ((int) tmp) << 8;
00740     tmp = (unsigned char) inb(0x40);
00741     value |= (((int) tmp) & 0xff);
00742     return (value);
00743 }
00744 
00745 static void m80x_delay(unsigned int interval)
00746 /* function: to wait for a specified time.                                   */
00747 /* input   : interval ... the specified time.                                */
00748 /* output  : none.                                                           */
00749 {
00750     unsigned int interval1, interval2, i = 0;
00751 
00752     interval1 = m80x_read_tick(); // get initial value
00753     do
00754     {
00755         interval2 = m80x_read_tick();
00756         if (interval1 < interval2)
00757             interval1 += 65536;
00758         ++i;
00759     } while (((interval1 - interval2) < (u16) interval) && (i < 65535));
00760 }
00761 
00762 
00763 static u32 m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
00764 {
00765     u32 miir;
00766     int i;
00767     unsigned int mask, data;
00768 
00769     /* enable MII output */
00770     miir = (u32) inl(miiport);
00771     miir &= 0xfffffff0;
00772 
00773     miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO;
00774 
00775     /* send 32 1's preamble */
00776     for (i = 0; i < 32; i++) {
00777         /* low MDC; MDO is already high (miir) */
00778         miir &= ~MASK_MIIR_MII_MDC;
00779         outl(miir, miiport);
00780 
00781         /* high MDC */
00782         miir |= MASK_MIIR_MII_MDC;
00783         outl(miir, miiport);
00784     }
00785 
00786     /* calculate ST+OP+PHYAD+REGAD+TA */
00787     data = opcode | (phyad << 7) | (regad << 2);
00788 
00789     /* sent out */
00790     mask = 0x8000;
00791     while (mask) {
00792         /* low MDC, prepare MDO */
00793         miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
00794         if (mask & data)
00795             miir |= MASK_MIIR_MII_MDO;
00796 
00797         outl(miir, miiport);
00798         /* high MDC */
00799         miir |= MASK_MIIR_MII_MDC;
00800         outl(miir, miiport);
00801         m80x_delay(30);
00802 
00803         /* next */
00804         mask >>= 1;
00805         if (mask == 0x2 && opcode == OP_READ)
00806             miir &= ~MASK_MIIR_MII_WRITE;
00807     }
00808     return miir;
00809 }
00810 
00811 static int mdio_read(struct nic *nic __unused, int phyad, int regad)
00812 {
00813     long miiport = mtdx.ioaddr + MANAGEMENT;
00814     u32 miir;
00815     unsigned int mask, data;
00816 
00817     miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad);
00818 
00819     /* read data */
00820     mask = 0x8000;
00821     data = 0;
00822     while (mask)
00823     {
00824         /* low MDC */
00825         miir &= ~MASK_MIIR_MII_MDC;
00826         outl(miir, miiport);
00827 
00828         /* read MDI */
00829         miir = inl(miiport);
00830         if (miir & MASK_MIIR_MII_MDI)
00831             data |= mask;
00832 
00833         /* high MDC, and wait */
00834         miir |= MASK_MIIR_MII_MDC;
00835         outl(miir, miiport);
00836         m80x_delay((int) 30);
00837 
00838         /* next */
00839         mask >>= 1;
00840     }
00841 
00842     /* low MDC */
00843     miir &= ~MASK_MIIR_MII_MDC;
00844     outl(miir, miiport);
00845 
00846     return data & 0xffff;
00847 }
00848 
00849 #if 0 /* not used */
00850 static void mdio_write(struct nic *nic __unused, int phyad, int regad,
00851                        int data)
00852 {
00853     long miiport = mtdx.ioaddr + MANAGEMENT;
00854     u32 miir;
00855     unsigned int mask;
00856 
00857     miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad);
00858 
00859     /* write data */
00860     mask = 0x8000;
00861     while (mask)
00862     {
00863         /* low MDC, prepare MDO */
00864         miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
00865         if (mask & data)
00866             miir |= MASK_MIIR_MII_MDO;
00867         outl(miir, miiport);
00868 
00869         /* high MDC */
00870         miir |= MASK_MIIR_MII_MDC;
00871         outl(miir, miiport);
00872 
00873         /* next */
00874         mask >>= 1;
00875     }
00876 
00877     /* low MDC */
00878     miir &= ~MASK_MIIR_MII_MDC;
00879     outl(miir, miiport);
00880 
00881     return;
00882 }
00883 #endif
00884 
00885 static void getlinkstatus(struct nic *nic)
00886 /* function: Routine will read MII Status Register to get link status.       */
00887 /* input   : dev... pointer to the adapter block.                            */
00888 /* output  : none.                                                           */
00889 {
00890     unsigned int i, DelayTime = 0x1000;
00891 
00892     mtdx.linkok = 0;
00893 
00894     if (mtdx.PHYType == MysonPHY)
00895     {
00896         for (i = 0; i < DelayTime; ++i) {
00897             if (inl(mtdx.ioaddr + BMCRSR) & LinkIsUp2) {
00898                 mtdx.linkok = 1;
00899                 return;
00900             }
00901             // delay
00902             m80x_delay(100);
00903         }
00904     } else
00905     {
00906         for (i = 0; i < DelayTime; ++i) {
00907             if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) {
00908                 mtdx.linkok = 1;
00909                 return;
00910             }
00911             // delay
00912             m80x_delay(100);
00913         }
00914     }
00915 }
00916 
00917 
00918 static void getlinktype(struct nic *dev)
00919 {
00920     if (mtdx.PHYType == MysonPHY)
00921     { /* 3-in-1 case */
00922         if (inl(mtdx.ioaddr + TCRRCR) & FD)
00923             mtdx.duplexmode = 2; /* full duplex */
00924         else
00925             mtdx.duplexmode = 1; /* half duplex */
00926         if (inl(mtdx.ioaddr + TCRRCR) & PS10)
00927             mtdx.line_speed = 1; /* 10M */
00928         else
00929             mtdx.line_speed = 2; /* 100M */
00930     } else
00931     {
00932         if (mtdx.PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */
00933             unsigned int data;
00934 
00935             data = mdio_read(dev, mtdx.phys[0], MIIRegister18);
00936             if (data & SPD_DET_100)
00937                 mtdx.line_speed = 2; /* 100M */
00938             else
00939                 mtdx.line_speed = 1; /* 10M */
00940             if (data & DPLX_DET_FULL)
00941                 mtdx.duplexmode = 2; /* full duplex mode */
00942             else
00943                 mtdx.duplexmode = 1; /* half duplex mode */
00944         } else if (mtdx.PHYType == AhdocPHY) {
00945             unsigned int data;
00946 
00947             data = mdio_read(dev, mtdx.phys[0], DiagnosticReg);
00948             if (data & Speed_100)
00949                 mtdx.line_speed = 2; /* 100M */
00950             else
00951                 mtdx.line_speed = 1; /* 10M */
00952             if (data & DPLX_FULL)
00953                 mtdx.duplexmode = 2; /* full duplex mode */
00954             else
00955                 mtdx.duplexmode = 1; /* half duplex mode */
00956         }
00957         /* 89/6/13 add, (begin) */
00958         else if (mtdx.PHYType == MarvellPHY) {
00959             unsigned int data;
00960 
00961             data = mdio_read(dev, mtdx.phys[0], SpecificReg);
00962             if (data & Full_Duplex)
00963                 mtdx.duplexmode = 2; /* full duplex mode */
00964             else
00965                 mtdx.duplexmode = 1; /* half duplex mode */
00966             data &= SpeedMask;
00967             if (data == Speed_1000M)
00968                 mtdx.line_speed = 3; /* 1000M */
00969             else if (data == Speed_100M)
00970                 mtdx.line_speed = 2; /* 100M */
00971             else
00972                 mtdx.line_speed = 1; /* 10M */
00973         }
00974         /* 89/6/13 add, (end) */
00975         /* 89/7/27 add, (begin) */
00976         else if (mtdx.PHYType == Myson981) {
00977             unsigned int data;
00978 
00979             data = mdio_read(dev, mtdx.phys[0], StatusRegister);
00980 
00981             if (data & SPEED100)
00982                 mtdx.line_speed = 2;
00983             else
00984                 mtdx.line_speed = 1;
00985 
00986             if (data & FULLMODE)
00987                 mtdx.duplexmode = 2;
00988             else
00989                 mtdx.duplexmode = 1;
00990         }
00991         /* 89/7/27 add, (end) */
00992         /* 89/12/29 add */
00993         else if (mtdx.PHYType == LevelOnePHY) {
00994             unsigned int data;
00995 
00996             data = mdio_read(dev, mtdx.phys[0], SpecificReg);
00997             if (data & LXT1000_Full)
00998                 mtdx.duplexmode = 2; /* full duplex mode */
00999             else
01000                 mtdx.duplexmode = 1; /* half duplex mode */
01001             data &= SpeedMask;
01002             if (data == LXT1000_1000M)
01003                 mtdx.line_speed = 3; /* 1000M */
01004             else if (data == LXT1000_100M)
01005                 mtdx.line_speed = 2; /* 100M */
01006             else
01007                 mtdx.line_speed = 1; /* 10M */
01008         }
01009         // chage crvalue
01010         // mtdx.crvalue&=(~PS10)&(~FD);
01011         mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000);
01012         if (mtdx.line_speed == 1)
01013             mtdx.crvalue |= PS10;
01014         else if (mtdx.line_speed == 3)
01015             mtdx.crvalue |= PS1000;
01016         if (mtdx.duplexmode == 2)
01017             mtdx.crvalue |= FD;
01018     }
01019 }
01020 
01021 DRIVER ( "MTD80X", nic_driver, pci_driver, mtd80x_driver,
01022          mtd_probe, mtd_disable );

Generated on Tue Apr 6 20:01:01 2010 for gPXE by  doxygen 1.5.7.1