|
|
1.1 ! root 1: /************************************************************************** ! 2: * ! 3: * mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip. ! 4: * Written 2004-2004 by Erdem Güven <[email protected]> ! 5: * ! 6: * This program is free software; you can redistribute it and/or modify ! 7: * it under the terms of the GNU General Public License as published by ! 8: * the Free Software Foundation; either version 2 of the License, or ! 9: * (at your option) any later version. ! 10: * ! 11: * This program is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: * GNU General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU General Public License ! 17: * along with this program; if not, write to the Free Software ! 18: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 19: * ! 20: * Portions of this code based on: ! 21: * fealnx.c: A Linux device driver for the mtd80x Ethernet chip ! 22: * Written 1998-2000 by Donald Becker ! 23: * ! 24: ***************************************************************************/ ! 25: ! 26: FILE_LICENCE ( GPL2_OR_LATER ); ! 27: ! 28: /* to get some global routines like printf */ ! 29: #include "etherboot.h" ! 30: /* to get the interface to the body of the program */ ! 31: #include "nic.h" ! 32: /* to get the PCI support functions, if this is a PCI NIC */ ! 33: #include <ipxe/pci.h> ! 34: #include <ipxe/ethernet.h> ! 35: #include <mii.h> ! 36: ! 37: /* Condensed operations for readability. */ ! 38: #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) ! 39: #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) ! 40: #define get_unaligned(ptr) (*(ptr)) ! 41: ! 42: ! 43: /* Operational parameters that are set at compile time. */ ! 44: ! 45: /* Keep the ring sizes a power of two for compile efficiency. */ ! 46: /* The compiler will convert <unsigned>'%'<2^N> into a bit mask. */ ! 47: /* Making the Tx ring too large decreases the effectiveness of channel */ ! 48: /* bonding and packet priority. */ ! 49: /* There are no ill effects from too-large receive rings. */ ! 50: #define TX_RING_SIZE 2 ! 51: #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ ! 52: #define RX_RING_SIZE 4 ! 53: ! 54: /* Operational parameters that usually are not changed. */ ! 55: /* Time in jiffies before concluding the transmitter is hung. */ ! 56: #define HZ 100 ! 57: #define TX_TIME_OUT (6*HZ) ! 58: ! 59: /* Allocation size of Rx buffers with normal sized Ethernet frames. ! 60: Do not change this value without good reason. This is not a limit, ! 61: but a way to keep a consistent allocation size among drivers. ! 62: */ ! 63: #define PKT_BUF_SZ 1536 ! 64: ! 65: /* for different PHY */ ! 66: enum phy_type_flags { ! 67: MysonPHY = 1, ! 68: AhdocPHY = 2, ! 69: SeeqPHY = 3, ! 70: MarvellPHY = 4, ! 71: Myson981 = 5, ! 72: LevelOnePHY = 6, ! 73: OtherPHY = 10, ! 74: }; ! 75: ! 76: /* A chip capabilities table*/ ! 77: enum chip_capability_flags { ! 78: HAS_MII_XCVR, ! 79: HAS_CHIP_XCVR, ! 80: }; ! 81: ! 82: #if 0 /* not used */ ! 83: static ! 84: struct chip_info ! 85: { ! 86: u16 dev_id; ! 87: int flag; ! 88: } ! 89: mtd80x_chips[] = { ! 90: {0x0800, HAS_MII_XCVR}, ! 91: {0x0803, HAS_CHIP_XCVR}, ! 92: {0x0891, HAS_MII_XCVR} ! 93: }; ! 94: static int chip_cnt = sizeof( mtd80x_chips ) / sizeof( struct chip_info ); ! 95: #endif ! 96: ! 97: /* Offsets to the Command and Status Registers. */ ! 98: enum mtd_offsets { ! 99: PAR0 = 0x0, /* physical address 0-3 */ ! 100: PAR1 = 0x04, /* physical address 4-5 */ ! 101: MAR0 = 0x08, /* multicast address 0-3 */ ! 102: MAR1 = 0x0C, /* multicast address 4-7 */ ! 103: FAR0 = 0x10, /* flow-control address 0-3 */ ! 104: FAR1 = 0x14, /* flow-control address 4-5 */ ! 105: TCRRCR = 0x18, /* receive & transmit configuration */ ! 106: BCR = 0x1C, /* bus command */ ! 107: TXPDR = 0x20, /* transmit polling demand */ ! 108: RXPDR = 0x24, /* receive polling demand */ ! 109: RXCWP = 0x28, /* receive current word pointer */ ! 110: TXLBA = 0x2C, /* transmit list base address */ ! 111: RXLBA = 0x30, /* receive list base address */ ! 112: ISR = 0x34, /* interrupt status */ ! 113: IMR = 0x38, /* interrupt mask */ ! 114: FTH = 0x3C, /* flow control high/low threshold */ ! 115: MANAGEMENT = 0x40, /* bootrom/eeprom and mii management */ ! 116: TALLY = 0x44, /* tally counters for crc and mpa */ ! 117: TSR = 0x48, /* tally counter for transmit status */ ! 118: BMCRSR = 0x4c, /* basic mode control and status */ ! 119: PHYIDENTIFIER = 0x50, /* phy identifier */ ! 120: ANARANLPAR = 0x54, /* auto-negotiation advertisement and link ! 121: partner ability */ ! 122: ANEROCR = 0x58, /* auto-negotiation expansion and pci conf. */ ! 123: BPREMRPSR = 0x5c, /* bypass & receive error mask and phy status */ ! 124: }; ! 125: ! 126: /* Bits in the interrupt status/enable registers. */ ! 127: /* The bits in the Intr Status/Enable registers, mostly interrupt sources. */ ! 128: enum intr_status_bits { ! 129: RFCON = 0x00020000, /* receive flow control xon packet */ ! 130: RFCOFF = 0x00010000, /* receive flow control xoff packet */ ! 131: LSCStatus = 0x00008000, /* link status change */ ! 132: ANCStatus = 0x00004000, /* autonegotiation completed */ ! 133: FBE = 0x00002000, /* fatal bus error */ ! 134: FBEMask = 0x00001800, /* mask bit12-11 */ ! 135: ParityErr = 0x00000000, /* parity error */ ! 136: TargetErr = 0x00001000, /* target abort */ ! 137: MasterErr = 0x00000800, /* master error */ ! 138: TUNF = 0x00000400, /* transmit underflow */ ! 139: ROVF = 0x00000200, /* receive overflow */ ! 140: ETI = 0x00000100, /* transmit early int */ ! 141: ERI = 0x00000080, /* receive early int */ ! 142: CNTOVF = 0x00000040, /* counter overflow */ ! 143: RBU = 0x00000020, /* receive buffer unavailable */ ! 144: TBU = 0x00000010, /* transmit buffer unavilable */ ! 145: TI = 0x00000008, /* transmit interrupt */ ! 146: RI = 0x00000004, /* receive interrupt */ ! 147: RxErr = 0x00000002, /* receive error */ ! 148: }; ! 149: ! 150: /* Bits in the NetworkConfig register. */ ! 151: enum rx_mode_bits { ! 152: RxModeMask = 0xe0, ! 153: AcceptAllPhys = 0x80, /* promiscuous mode */ ! 154: AcceptBroadcast = 0x40, /* accept broadcast */ ! 155: AcceptMulticast = 0x20, /* accept mutlicast */ ! 156: AcceptRunt = 0x08, /* receive runt pkt */ ! 157: ALP = 0x04, /* receive long pkt */ ! 158: AcceptErr = 0x02, /* receive error pkt */ ! 159: ! 160: AcceptMyPhys = 0x00000000, ! 161: RxEnable = 0x00000001, ! 162: RxFlowCtrl = 0x00002000, ! 163: TxEnable = 0x00040000, ! 164: TxModeFDX = 0x00100000, ! 165: TxThreshold = 0x00e00000, ! 166: ! 167: PS1000 = 0x00010000, ! 168: PS10 = 0x00080000, ! 169: FD = 0x00100000, ! 170: }; ! 171: ! 172: /* Bits in network_desc.status */ ! 173: enum rx_desc_status_bits { ! 174: RXOWN = 0x80000000, /* own bit */ ! 175: FLNGMASK = 0x0fff0000, /* frame length */ ! 176: FLNGShift = 16, ! 177: MARSTATUS = 0x00004000, /* multicast address received */ ! 178: BARSTATUS = 0x00002000, /* broadcast address received */ ! 179: PHYSTATUS = 0x00001000, /* physical address received */ ! 180: RXFSD = 0x00000800, /* first descriptor */ ! 181: RXLSD = 0x00000400, /* last descriptor */ ! 182: ErrorSummary = 0x80, /* error summary */ ! 183: RUNT = 0x40, /* runt packet received */ ! 184: LONG = 0x20, /* long packet received */ ! 185: FAE = 0x10, /* frame align error */ ! 186: CRC = 0x08, /* crc error */ ! 187: RXER = 0x04, /* receive error */ ! 188: }; ! 189: ! 190: enum rx_desc_control_bits { ! 191: RXIC = 0x00800000, /* interrupt control */ ! 192: RBSShift = 0, ! 193: }; ! 194: ! 195: enum tx_desc_status_bits { ! 196: TXOWN = 0x80000000, /* own bit */ ! 197: JABTO = 0x00004000, /* jabber timeout */ ! 198: CSL = 0x00002000, /* carrier sense lost */ ! 199: LC = 0x00001000, /* late collision */ ! 200: EC = 0x00000800, /* excessive collision */ ! 201: UDF = 0x00000400, /* fifo underflow */ ! 202: DFR = 0x00000200, /* deferred */ ! 203: HF = 0x00000100, /* heartbeat fail */ ! 204: NCRMask = 0x000000ff, /* collision retry count */ ! 205: NCRShift = 0, ! 206: }; ! 207: ! 208: enum tx_desc_control_bits { ! 209: TXIC = 0x80000000, /* interrupt control */ ! 210: ETIControl = 0x40000000, /* early transmit interrupt */ ! 211: TXLD = 0x20000000, /* last descriptor */ ! 212: TXFD = 0x10000000, /* first descriptor */ ! 213: CRCEnable = 0x08000000, /* crc control */ ! 214: PADEnable = 0x04000000, /* padding control */ ! 215: RetryTxLC = 0x02000000, /* retry late collision */ ! 216: PKTSMask = 0x3ff800, /* packet size bit21-11 */ ! 217: PKTSShift = 11, ! 218: TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */ ! 219: TBSShift = 0, ! 220: }; ! 221: ! 222: /* BootROM/EEPROM/MII Management Register */ ! 223: #define MASK_MIIR_MII_READ 0x00000000 ! 224: #define MASK_MIIR_MII_WRITE 0x00000008 ! 225: #define MASK_MIIR_MII_MDO 0x00000004 ! 226: #define MASK_MIIR_MII_MDI 0x00000002 ! 227: #define MASK_MIIR_MII_MDC 0x00000001 ! 228: ! 229: /* ST+OP+PHYAD+REGAD+TA */ ! 230: #define OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */ ! 231: #define OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */ ! 232: ! 233: /* ------------------------------------------------------------------------- */ ! 234: /* Constants for Myson PHY */ ! 235: /* ------------------------------------------------------------------------- */ ! 236: #define MysonPHYID 0xd0000302 ! 237: /* 89-7-27 add, (begin) */ ! 238: #define MysonPHYID0 0x0302 ! 239: #define StatusRegister 18 ! 240: #define SPEED100 0x0400 // bit10 ! 241: #define FULLMODE 0x0800 // bit11 ! 242: /* 89-7-27 add, (end) */ ! 243: ! 244: /* ------------------------------------------------------------------------- */ ! 245: /* Constants for Seeq 80225 PHY */ ! 246: /* ------------------------------------------------------------------------- */ ! 247: #define SeeqPHYID0 0x0016 ! 248: ! 249: #define MIIRegister18 18 ! 250: #define SPD_DET_100 0x80 ! 251: #define DPLX_DET_FULL 0x40 ! 252: ! 253: /* ------------------------------------------------------------------------- */ ! 254: /* Constants for Ahdoc 101 PHY */ ! 255: /* ------------------------------------------------------------------------- */ ! 256: #define AhdocPHYID0 0x0022 ! 257: ! 258: #define DiagnosticReg 18 ! 259: #define DPLX_FULL 0x0800 ! 260: #define Speed_100 0x0400 ! 261: ! 262: /* 89/6/13 add, */ ! 263: /* -------------------------------------------------------------------------- */ ! 264: /* Constants */ ! 265: /* -------------------------------------------------------------------------- */ ! 266: #define MarvellPHYID0 0x0141 ! 267: #define LevelOnePHYID0 0x0013 ! 268: ! 269: #define MII1000BaseTControlReg 9 ! 270: #define MII1000BaseTStatusReg 10 ! 271: #define SpecificReg 17 ! 272: ! 273: /* for 1000BaseT Control Register */ ! 274: #define PHYAbletoPerform1000FullDuplex 0x0200 ! 275: #define PHYAbletoPerform1000HalfDuplex 0x0100 ! 276: #define PHY1000AbilityMask 0x300 ! 277: ! 278: // for phy specific status register, marvell phy. ! 279: #define SpeedMask 0x0c000 ! 280: #define Speed_1000M 0x08000 ! 281: #define Speed_100M 0x4000 ! 282: #define Speed_10M 0 ! 283: #define Full_Duplex 0x2000 ! 284: ! 285: // 89/12/29 add, for phy specific status register, levelone phy, (begin) ! 286: #define LXT1000_100M 0x08000 ! 287: #define LXT1000_1000M 0x0c000 ! 288: #define LXT1000_Full 0x200 ! 289: // 89/12/29 add, for phy specific status register, levelone phy, (end) ! 290: ! 291: #if 0 ! 292: /* for 3-in-1 case */ ! 293: #define PS10 0x00080000 ! 294: #define FD 0x00100000 ! 295: #define PS1000 0x00010000 ! 296: #endif ! 297: ! 298: /* for PHY */ ! 299: #define LinkIsUp 0x0004 ! 300: #define LinkIsUp2 0x00040000 ! 301: ! 302: /* Create a static buffer of size PKT_BUF_SZ for each ! 303: RX and TX Descriptor. All descriptors point to a ! 304: part of this buffer */ ! 305: struct { ! 306: u8 txb[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned(8))); ! 307: u8 rxb[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned(8))); ! 308: } mtd80x_bufs __shared; ! 309: #define txb mtd80x_bufs.txb ! 310: #define rxb mtd80x_bufs.rxb ! 311: ! 312: /* The Tulip Rx and Tx buffer descriptors. */ ! 313: struct mtd_desc ! 314: { ! 315: s32 status; ! 316: s32 control; ! 317: u32 buffer; ! 318: u32 next_desc; ! 319: struct mtd_desc *next_desc_logical; ! 320: u8* skbuff; ! 321: u32 reserved1; ! 322: u32 reserved2; ! 323: }; ! 324: ! 325: struct mtd_private ! 326: { ! 327: struct mtd_desc rx_ring[RX_RING_SIZE]; ! 328: struct mtd_desc tx_ring[TX_RING_SIZE]; ! 329: ! 330: /* Frequently used values: keep some adjacent for cache effect. */ ! 331: int flags; ! 332: struct pci_dev *pci_dev; ! 333: unsigned long crvalue; ! 334: unsigned long bcrvalue; ! 335: /*unsigned long imrvalue;*/ ! 336: struct mtd_desc *cur_rx; ! 337: struct mtd_desc *lack_rxbuf; ! 338: int really_rx_count; ! 339: struct mtd_desc *cur_tx; ! 340: struct mtd_desc *cur_tx_copy; ! 341: int really_tx_count; ! 342: int free_tx_count; ! 343: unsigned int rx_buf_sz; /* Based on MTU+slack. */ ! 344: ! 345: /* These values are keep track of the transceiver/media in use. */ ! 346: unsigned int linkok; ! 347: unsigned int line_speed; ! 348: unsigned int duplexmode; ! 349: unsigned int default_port: ! 350: 4; /* Last dev->if_port value. */ ! 351: unsigned int PHYType; ! 352: ! 353: /* MII transceiver section. */ ! 354: int mii_cnt; /* MII device addresses. */ ! 355: unsigned char phys[1]; /* MII device addresses. */ ! 356: ! 357: /*other*/ ! 358: const char *nic_name; ! 359: int ioaddr; ! 360: u16 dev_id; ! 361: }; ! 362: ! 363: static struct mtd_private mtdx; ! 364: ! 365: static int mdio_read(struct nic * , int phy_id, int location); ! 366: static void getlinktype(struct nic * ); ! 367: static void getlinkstatus(struct nic * ); ! 368: static void set_rx_mode(struct nic *); ! 369: ! 370: /************************************************************************** ! 371: * init_ring - setup the tx and rx descriptors ! 372: *************************************************************************/ ! 373: static void init_ring(struct nic *nic __unused) ! 374: { ! 375: int i; ! 376: ! 377: mtdx.cur_rx = &mtdx.rx_ring[0]; ! 378: ! 379: mtdx.rx_buf_sz = PKT_BUF_SZ; ! 380: /*mtdx.rx_head_desc = &mtdx.rx_ring[0];*/ ! 381: ! 382: /* Initialize all Rx descriptors. */ ! 383: /* Fill in the Rx buffers. Handle allocation failure gracefully. */ ! 384: for (i = 0; i < RX_RING_SIZE; i++) ! 385: { ! 386: mtdx.rx_ring[i].status = RXOWN; ! 387: mtdx.rx_ring[i].control = mtdx.rx_buf_sz << RBSShift; ! 388: mtdx.rx_ring[i].next_desc = virt_to_le32desc(&mtdx.rx_ring[i+1]); ! 389: mtdx.rx_ring[i].next_desc_logical = &mtdx.rx_ring[i+1]; ! 390: mtdx.rx_ring[i].buffer = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]); ! 391: mtdx.rx_ring[i].skbuff = &rxb[i * PKT_BUF_SZ]; ! 392: } ! 393: /* Mark the last entry as wrapping the ring. */ ! 394: mtdx.rx_ring[i-1].next_desc = virt_to_le32desc(&mtdx.rx_ring[0]); ! 395: mtdx.rx_ring[i-1].next_desc_logical = &mtdx.rx_ring[0]; ! 396: ! 397: /* We only use one transmit buffer, but two ! 398: * descriptors so transmit engines have somewhere ! 399: * to point should they feel the need */ ! 400: mtdx.tx_ring[0].status = 0x00000000; ! 401: mtdx.tx_ring[0].buffer = virt_to_bus(&txb[0]); ! 402: mtdx.tx_ring[0].next_desc = virt_to_le32desc(&mtdx.tx_ring[1]); ! 403: ! 404: /* This descriptor is never used */ ! 405: mtdx.tx_ring[1].status = 0x00000000; ! 406: mtdx.tx_ring[1].buffer = 0; /*virt_to_bus(&txb[1]); */ ! 407: mtdx.tx_ring[1].next_desc = virt_to_le32desc(&mtdx.tx_ring[0]); ! 408: ! 409: return; ! 410: } ! 411: ! 412: /************************************************************************** ! 413: RESET - Reset Adapter ! 414: ***************************************************************************/ ! 415: static void mtd_reset( struct nic *nic ) ! 416: { ! 417: /* Reset the chip to erase previous misconfiguration. */ ! 418: outl(0x00000001, mtdx.ioaddr + BCR); ! 419: ! 420: init_ring(nic); ! 421: ! 422: outl(virt_to_bus(mtdx.rx_ring), mtdx.ioaddr + RXLBA); ! 423: outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA); ! 424: ! 425: /* Initialize other registers. */ ! 426: /* Configure the PCI bus bursts and FIFO thresholds. */ ! 427: mtdx.bcrvalue = 0x10; /* little-endian, 8 burst length */ ! 428: mtdx.crvalue = 0xa00; /* rx 128 burst length */ ! 429: ! 430: if ( mtdx.dev_id == 0x891 ) { ! 431: mtdx.bcrvalue |= 0x200; /* set PROG bit */ ! 432: mtdx.crvalue |= 0x02000000; /* set enhanced bit */ ! 433: } ! 434: ! 435: outl( mtdx.bcrvalue, mtdx.ioaddr + BCR); ! 436: ! 437: /* Restart Rx engine if stopped. */ ! 438: outl(0, mtdx.ioaddr + RXPDR); ! 439: ! 440: getlinkstatus(nic); ! 441: if (mtdx.linkok) ! 442: { ! 443: static const char* texts[]={"half","full","10","100","1000"}; ! 444: getlinktype(nic); ! 445: DBG ( "Link is OK : %s %s\n", texts[mtdx.duplexmode-1], texts[mtdx.line_speed+1] ); ! 446: } else ! 447: { ! 448: DBG ( "No link!!!\n" ); ! 449: } ! 450: ! 451: mtdx.crvalue |= /*TxEnable |*/ RxEnable | TxThreshold; ! 452: set_rx_mode(nic); ! 453: ! 454: /* Clear interrupts by setting the interrupt mask. */ ! 455: outl(FBE | TUNF | CNTOVF | RBU | TI | RI, mtdx.ioaddr + ISR); ! 456: outl( 0, mtdx.ioaddr + IMR); ! 457: } ! 458: ! 459: /************************************************************************** ! 460: POLL - Wait for a frame ! 461: ***************************************************************************/ ! 462: static int mtd_poll(struct nic *nic, __unused int retrieve) ! 463: { ! 464: s32 rx_status = mtdx.cur_rx->status; ! 465: int retval = 0; ! 466: ! 467: if( ( rx_status & RXOWN ) != 0 ) ! 468: { ! 469: return 0; ! 470: } ! 471: ! 472: if (rx_status & ErrorSummary) ! 473: { /* there was a fatal error */ ! 474: printf( "%s: Receive error, Rx status %8.8x, Error(s) %s%s%s\n", ! 475: mtdx.nic_name, (unsigned int) rx_status, ! 476: (rx_status & (LONG | RUNT)) ? "length_error ":"", ! 477: (rx_status & RXER) ? "frame_error ":"", ! 478: (rx_status & CRC) ? "crc_error ":"" ); ! 479: retval = 0; ! 480: } else if( !((rx_status & RXFSD) && (rx_status & RXLSD)) ) ! 481: { ! 482: /* this pkt is too long, over one rx buffer */ ! 483: printf("Pkt is too long, over one rx buffer.\n"); ! 484: retval = 0; ! 485: } else ! 486: { /* this received pkt is ok */ ! 487: /* Omit the four octet CRC from the length. */ ! 488: short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4; ! 489: ! 490: DBG ( " netdev_rx() normal Rx pkt length %d" ! 491: " status %x.\n", pkt_len, (unsigned int) rx_status ); ! 492: ! 493: nic->packetlen = pkt_len; ! 494: memcpy(nic->packet, mtdx.cur_rx->skbuff, pkt_len); ! 495: ! 496: retval = 1; ! 497: } ! 498: ! 499: while( ( mtdx.cur_rx->status & RXOWN ) == 0 ) ! 500: { ! 501: mtdx.cur_rx->status = RXOWN; ! 502: mtdx.cur_rx = mtdx.cur_rx->next_desc_logical; ! 503: } ! 504: ! 505: /* Restart Rx engine if stopped. */ ! 506: outl(0, mtdx.ioaddr + RXPDR); ! 507: ! 508: return retval; ! 509: } ! 510: ! 511: /************************************************************************** ! 512: TRANSMIT - Transmit a frame ! 513: ***************************************************************************/ ! 514: static void mtd_transmit( ! 515: struct nic *nic, ! 516: const char *dest, /* Destination */ ! 517: unsigned int type, /* Type */ ! 518: unsigned int size, /* size */ ! 519: const char *data) /* Packet */ ! 520: { ! 521: u32 to; ! 522: u32 tx_status; ! 523: unsigned int nstype = htons ( type ); ! 524: ! 525: memcpy( txb, dest, ETH_ALEN ); ! 526: memcpy( txb + ETH_ALEN, nic->node_addr, ETH_ALEN ); ! 527: memcpy( txb + 2 * ETH_ALEN, &nstype, 2 ); ! 528: memcpy( txb + ETH_HLEN, data, size ); ! 529: ! 530: size += ETH_HLEN; ! 531: size &= 0x0FFF; ! 532: while( size < ETH_ZLEN ) ! 533: { ! 534: txb[size++] = '\0'; ! 535: } ! 536: ! 537: mtdx.tx_ring[0].control = TXLD | TXFD | CRCEnable | PADEnable; ! 538: mtdx.tx_ring[0].control |= (size << PKTSShift); /* pkt size */ ! 539: mtdx.tx_ring[0].control |= (size << TBSShift); /* buffer size */ ! 540: mtdx.tx_ring[0].status = TXOWN; ! 541: ! 542: /* Point to transmit descriptor */ ! 543: outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA); ! 544: /* Enable Tx */ ! 545: outl( mtdx.crvalue | TxEnable, mtdx.ioaddr + TCRRCR); ! 546: /* Wake the potentially-idle transmit channel. */ ! 547: outl(0, mtdx.ioaddr + TXPDR); ! 548: ! 549: to = currticks() + TX_TIME_OUT; ! 550: while(( mtdx.tx_ring[0].status & TXOWN) && (currticks() < to)); ! 551: ! 552: /* Disable Tx */ ! 553: outl( mtdx.crvalue & (~TxEnable), mtdx.ioaddr + TCRRCR); ! 554: ! 555: tx_status = mtdx.tx_ring[0].status; ! 556: if (currticks() >= to){ ! 557: DBG ( "TX Time Out" ); ! 558: } else if( tx_status & (CSL | LC | EC | UDF | HF)){ ! 559: printf( "Transmit error: %8.8x %s %s %s %s %s\n", ! 560: (unsigned int) tx_status, ! 561: tx_status & EC ? "abort" : "", ! 562: tx_status & CSL ? "carrier" : "", ! 563: tx_status & LC ? "late" : "", ! 564: tx_status & UDF ? "fifo" : "", ! 565: tx_status & HF ? "heartbeat" : "" ); ! 566: } ! 567: ! 568: /*hex_dump( txb, size );*/ ! 569: /*pause();*/ ! 570: ! 571: DBG ( "TRANSMIT\n" ); ! 572: } ! 573: ! 574: /************************************************************************** ! 575: DISABLE - Turn off ethernet interface ! 576: ***************************************************************************/ ! 577: static void mtd_disable ( struct nic *nic ) { ! 578: ! 579: /* Disable Tx Rx*/ ! 580: outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR ); ! 581: ! 582: /* Reset the chip to erase previous misconfiguration. */ ! 583: mtd_reset(nic); ! 584: ! 585: DBG ( "DISABLE\n" ); ! 586: } ! 587: ! 588: static struct nic_operations mtd_operations = { ! 589: .connect = dummy_connect, ! 590: .poll = mtd_poll, ! 591: .transmit = mtd_transmit, ! 592: .irq = dummy_irq, ! 593: ! 594: }; ! 595: ! 596: static struct pci_device_id mtd80x_nics[] = { ! 597: PCI_ROM(0x1516, 0x0800, "MTD800", "Myson MTD800", 0), ! 598: PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X", 0), ! 599: PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891", 0), ! 600: }; ! 601: ! 602: PCI_DRIVER ( mtd80x_driver, mtd80x_nics, PCI_NO_CLASS ); ! 603: ! 604: /************************************************************************** ! 605: PROBE - Look for an adapter, this routine's visible to the outside ! 606: ***************************************************************************/ ! 607: ! 608: static int mtd_probe ( struct nic *nic, struct pci_device *pci ) { ! 609: ! 610: int i; ! 611: ! 612: if (pci->ioaddr == 0) ! 613: return 0; ! 614: ! 615: adjust_pci_device(pci); ! 616: ! 617: nic->ioaddr = pci->ioaddr; ! 618: nic->irqno = 0; ! 619: ! 620: mtdx.nic_name = pci->id->name; ! 621: mtdx.dev_id = pci->device; ! 622: mtdx.ioaddr = nic->ioaddr; ! 623: ! 624: /* read ethernet id */ ! 625: for (i = 0; i < 6; ++i) ! 626: { ! 627: nic->node_addr[i] = inb(mtdx.ioaddr + PAR0 + i); ! 628: } ! 629: ! 630: if (memcmp(nic->node_addr, "\0\0\0\0\0\0", 6) == 0) ! 631: { ! 632: return 0; ! 633: } ! 634: ! 635: DBG ( "%s: ioaddr %4.4x MAC %s\n", mtdx.nic_name, mtdx.ioaddr, eth_ntoa ( nic->node_addr ) ); ! 636: ! 637: /* Reset the chip to erase previous misconfiguration. */ ! 638: outl(0x00000001, mtdx.ioaddr + BCR); ! 639: ! 640: /* find the connected MII xcvrs */ ! 641: ! 642: if( mtdx.dev_id != 0x803 ) ! 643: { ! 644: int phy, phy_idx = 0; ! 645: ! 646: for (phy = 1; phy < 32 && phy_idx < 1; phy++) { ! 647: int mii_status = mdio_read(nic, phy, 1); ! 648: ! 649: if (mii_status != 0xffff && mii_status != 0x0000) { ! 650: mtdx.phys[phy_idx] = phy; ! 651: ! 652: DBG ( "%s: MII PHY found at address %d, status " ! 653: "0x%4.4x.\n", mtdx.nic_name, phy, mii_status ); ! 654: /* get phy type */ ! 655: { ! 656: unsigned int data; ! 657: ! 658: data = mdio_read(nic, mtdx.phys[phy_idx], 2); ! 659: if (data == SeeqPHYID0) ! 660: mtdx.PHYType = SeeqPHY; ! 661: else if (data == AhdocPHYID0) ! 662: mtdx.PHYType = AhdocPHY; ! 663: else if (data == MarvellPHYID0) ! 664: mtdx.PHYType = MarvellPHY; ! 665: else if (data == MysonPHYID0) ! 666: mtdx.PHYType = Myson981; ! 667: else if (data == LevelOnePHYID0) ! 668: mtdx.PHYType = LevelOnePHY; ! 669: else ! 670: mtdx.PHYType = OtherPHY; ! 671: } ! 672: phy_idx++; ! 673: } ! 674: } ! 675: ! 676: mtdx.mii_cnt = phy_idx; ! 677: if (phy_idx == 0) { ! 678: printf("%s: MII PHY not found -- this device may " ! 679: "not operate correctly.\n", mtdx.nic_name); ! 680: } ! 681: } else { ! 682: mtdx.phys[0] = 32; ! 683: /* get phy type */ ! 684: if (inl(mtdx.ioaddr + PHYIDENTIFIER) == MysonPHYID ) { ! 685: mtdx.PHYType = MysonPHY; ! 686: DBG ( "MysonPHY\n" ); ! 687: } else { ! 688: mtdx.PHYType = OtherPHY; ! 689: DBG ( "OtherPHY\n" ); ! 690: } ! 691: } ! 692: ! 693: getlinkstatus(nic); ! 694: if( !mtdx.linkok ) ! 695: { ! 696: printf("No link!!!\n"); ! 697: return 0; ! 698: } ! 699: ! 700: mtd_reset( nic ); ! 701: ! 702: /* point to NIC specific routines */ ! 703: nic->nic_op = &mtd_operations; ! 704: return 1; ! 705: } ! 706: ! 707: ! 708: /**************************************************************************/ ! 709: static void set_rx_mode(struct nic *nic __unused) ! 710: { ! 711: u32 mc_filter[2]; /* Multicast hash filter */ ! 712: u32 rx_mode; ! 713: ! 714: /* Too many to match, or accept all multicasts. */ ! 715: mc_filter[1] = mc_filter[0] = ~0; ! 716: rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; ! 717: ! 718: outl(mc_filter[0], mtdx.ioaddr + MAR0); ! 719: outl(mc_filter[1], mtdx.ioaddr + MAR1); ! 720: ! 721: mtdx.crvalue = ( mtdx.crvalue & ~RxModeMask ) | rx_mode; ! 722: outb( mtdx.crvalue, mtdx.ioaddr + TCRRCR); ! 723: } ! 724: /**************************************************************************/ ! 725: static unsigned int m80x_read_tick(void) ! 726: /* function: Reads the Timer tick count register which decrements by 2 from */ ! 727: /* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the */ ! 728: /* count represents 838 nsec's. */ ! 729: /* input : none. */ ! 730: /* output : none. */ ! 731: { ! 732: unsigned char tmp; ! 733: int value; ! 734: ! 735: outb((char) 0x06, 0x43); // Command 8254 to latch T0's count ! 736: ! 737: // now read the count. ! 738: tmp = (unsigned char) inb(0x40); ! 739: value = ((int) tmp) << 8; ! 740: tmp = (unsigned char) inb(0x40); ! 741: value |= (((int) tmp) & 0xff); ! 742: return (value); ! 743: } ! 744: ! 745: static void m80x_delay(unsigned int interval) ! 746: /* function: to wait for a specified time. */ ! 747: /* input : interval ... the specified time. */ ! 748: /* output : none. */ ! 749: { ! 750: unsigned int interval1, interval2, i = 0; ! 751: ! 752: interval1 = m80x_read_tick(); // get initial value ! 753: do ! 754: { ! 755: interval2 = m80x_read_tick(); ! 756: if (interval1 < interval2) ! 757: interval1 += 65536; ! 758: ++i; ! 759: } while (((interval1 - interval2) < (u16) interval) && (i < 65535)); ! 760: } ! 761: ! 762: ! 763: static u32 m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad) ! 764: { ! 765: u32 miir; ! 766: int i; ! 767: unsigned int mask, data; ! 768: ! 769: /* enable MII output */ ! 770: miir = (u32) inl(miiport); ! 771: miir &= 0xfffffff0; ! 772: ! 773: miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO; ! 774: ! 775: /* send 32 1's preamble */ ! 776: for (i = 0; i < 32; i++) { ! 777: /* low MDC; MDO is already high (miir) */ ! 778: miir &= ~MASK_MIIR_MII_MDC; ! 779: outl(miir, miiport); ! 780: ! 781: /* high MDC */ ! 782: miir |= MASK_MIIR_MII_MDC; ! 783: outl(miir, miiport); ! 784: } ! 785: ! 786: /* calculate ST+OP+PHYAD+REGAD+TA */ ! 787: data = opcode | (phyad << 7) | (regad << 2); ! 788: ! 789: /* sent out */ ! 790: mask = 0x8000; ! 791: while (mask) { ! 792: /* low MDC, prepare MDO */ ! 793: miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); ! 794: if (mask & data) ! 795: miir |= MASK_MIIR_MII_MDO; ! 796: ! 797: outl(miir, miiport); ! 798: /* high MDC */ ! 799: miir |= MASK_MIIR_MII_MDC; ! 800: outl(miir, miiport); ! 801: m80x_delay(30); ! 802: ! 803: /* next */ ! 804: mask >>= 1; ! 805: if (mask == 0x2 && opcode == OP_READ) ! 806: miir &= ~MASK_MIIR_MII_WRITE; ! 807: } ! 808: return miir; ! 809: } ! 810: ! 811: static int mdio_read(struct nic *nic __unused, int phyad, int regad) ! 812: { ! 813: long miiport = mtdx.ioaddr + MANAGEMENT; ! 814: u32 miir; ! 815: unsigned int mask, data; ! 816: ! 817: miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad); ! 818: ! 819: /* read data */ ! 820: mask = 0x8000; ! 821: data = 0; ! 822: while (mask) ! 823: { ! 824: /* low MDC */ ! 825: miir &= ~MASK_MIIR_MII_MDC; ! 826: outl(miir, miiport); ! 827: ! 828: /* read MDI */ ! 829: miir = inl(miiport); ! 830: if (miir & MASK_MIIR_MII_MDI) ! 831: data |= mask; ! 832: ! 833: /* high MDC, and wait */ ! 834: miir |= MASK_MIIR_MII_MDC; ! 835: outl(miir, miiport); ! 836: m80x_delay((int) 30); ! 837: ! 838: /* next */ ! 839: mask >>= 1; ! 840: } ! 841: ! 842: /* low MDC */ ! 843: miir &= ~MASK_MIIR_MII_MDC; ! 844: outl(miir, miiport); ! 845: ! 846: return data & 0xffff; ! 847: } ! 848: ! 849: #if 0 /* not used */ ! 850: static void mdio_write(struct nic *nic __unused, int phyad, int regad, ! 851: int data) ! 852: { ! 853: long miiport = mtdx.ioaddr + MANAGEMENT; ! 854: u32 miir; ! 855: unsigned int mask; ! 856: ! 857: miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad); ! 858: ! 859: /* write data */ ! 860: mask = 0x8000; ! 861: while (mask) ! 862: { ! 863: /* low MDC, prepare MDO */ ! 864: miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); ! 865: if (mask & data) ! 866: miir |= MASK_MIIR_MII_MDO; ! 867: outl(miir, miiport); ! 868: ! 869: /* high MDC */ ! 870: miir |= MASK_MIIR_MII_MDC; ! 871: outl(miir, miiport); ! 872: ! 873: /* next */ ! 874: mask >>= 1; ! 875: } ! 876: ! 877: /* low MDC */ ! 878: miir &= ~MASK_MIIR_MII_MDC; ! 879: outl(miir, miiport); ! 880: ! 881: return; ! 882: } ! 883: #endif ! 884: ! 885: static void getlinkstatus(struct nic *nic) ! 886: /* function: Routine will read MII Status Register to get link status. */ ! 887: /* input : dev... pointer to the adapter block. */ ! 888: /* output : none. */ ! 889: { ! 890: unsigned int i, DelayTime = 0x1000; ! 891: ! 892: mtdx.linkok = 0; ! 893: ! 894: if (mtdx.PHYType == MysonPHY) ! 895: { ! 896: for (i = 0; i < DelayTime; ++i) { ! 897: if (inl(mtdx.ioaddr + BMCRSR) & LinkIsUp2) { ! 898: mtdx.linkok = 1; ! 899: return; ! 900: } ! 901: // delay ! 902: m80x_delay(100); ! 903: } ! 904: } else ! 905: { ! 906: for (i = 0; i < DelayTime; ++i) { ! 907: if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) { ! 908: mtdx.linkok = 1; ! 909: return; ! 910: } ! 911: // delay ! 912: m80x_delay(100); ! 913: } ! 914: } ! 915: } ! 916: ! 917: ! 918: static void getlinktype(struct nic *dev) ! 919: { ! 920: if (mtdx.PHYType == MysonPHY) ! 921: { /* 3-in-1 case */ ! 922: if (inl(mtdx.ioaddr + TCRRCR) & FD) ! 923: mtdx.duplexmode = 2; /* full duplex */ ! 924: else ! 925: mtdx.duplexmode = 1; /* half duplex */ ! 926: if (inl(mtdx.ioaddr + TCRRCR) & PS10) ! 927: mtdx.line_speed = 1; /* 10M */ ! 928: else ! 929: mtdx.line_speed = 2; /* 100M */ ! 930: } else ! 931: { ! 932: if (mtdx.PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */ ! 933: unsigned int data; ! 934: ! 935: data = mdio_read(dev, mtdx.phys[0], MIIRegister18); ! 936: if (data & SPD_DET_100) ! 937: mtdx.line_speed = 2; /* 100M */ ! 938: else ! 939: mtdx.line_speed = 1; /* 10M */ ! 940: if (data & DPLX_DET_FULL) ! 941: mtdx.duplexmode = 2; /* full duplex mode */ ! 942: else ! 943: mtdx.duplexmode = 1; /* half duplex mode */ ! 944: } else if (mtdx.PHYType == AhdocPHY) { ! 945: unsigned int data; ! 946: ! 947: data = mdio_read(dev, mtdx.phys[0], DiagnosticReg); ! 948: if (data & Speed_100) ! 949: mtdx.line_speed = 2; /* 100M */ ! 950: else ! 951: mtdx.line_speed = 1; /* 10M */ ! 952: if (data & DPLX_FULL) ! 953: mtdx.duplexmode = 2; /* full duplex mode */ ! 954: else ! 955: mtdx.duplexmode = 1; /* half duplex mode */ ! 956: } ! 957: /* 89/6/13 add, (begin) */ ! 958: else if (mtdx.PHYType == MarvellPHY) { ! 959: unsigned int data; ! 960: ! 961: data = mdio_read(dev, mtdx.phys[0], SpecificReg); ! 962: if (data & Full_Duplex) ! 963: mtdx.duplexmode = 2; /* full duplex mode */ ! 964: else ! 965: mtdx.duplexmode = 1; /* half duplex mode */ ! 966: data &= SpeedMask; ! 967: if (data == Speed_1000M) ! 968: mtdx.line_speed = 3; /* 1000M */ ! 969: else if (data == Speed_100M) ! 970: mtdx.line_speed = 2; /* 100M */ ! 971: else ! 972: mtdx.line_speed = 1; /* 10M */ ! 973: } ! 974: /* 89/6/13 add, (end) */ ! 975: /* 89/7/27 add, (begin) */ ! 976: else if (mtdx.PHYType == Myson981) { ! 977: unsigned int data; ! 978: ! 979: data = mdio_read(dev, mtdx.phys[0], StatusRegister); ! 980: ! 981: if (data & SPEED100) ! 982: mtdx.line_speed = 2; ! 983: else ! 984: mtdx.line_speed = 1; ! 985: ! 986: if (data & FULLMODE) ! 987: mtdx.duplexmode = 2; ! 988: else ! 989: mtdx.duplexmode = 1; ! 990: } ! 991: /* 89/7/27 add, (end) */ ! 992: /* 89/12/29 add */ ! 993: else if (mtdx.PHYType == LevelOnePHY) { ! 994: unsigned int data; ! 995: ! 996: data = mdio_read(dev, mtdx.phys[0], SpecificReg); ! 997: if (data & LXT1000_Full) ! 998: mtdx.duplexmode = 2; /* full duplex mode */ ! 999: else ! 1000: mtdx.duplexmode = 1; /* half duplex mode */ ! 1001: data &= SpeedMask; ! 1002: if (data == LXT1000_1000M) ! 1003: mtdx.line_speed = 3; /* 1000M */ ! 1004: else if (data == LXT1000_100M) ! 1005: mtdx.line_speed = 2; /* 100M */ ! 1006: else ! 1007: mtdx.line_speed = 1; /* 10M */ ! 1008: } ! 1009: // chage crvalue ! 1010: // mtdx.crvalue&=(~PS10)&(~FD); ! 1011: mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000); ! 1012: if (mtdx.line_speed == 1) ! 1013: mtdx.crvalue |= PS10; ! 1014: else if (mtdx.line_speed == 3) ! 1015: mtdx.crvalue |= PS1000; ! 1016: if (mtdx.duplexmode == 2) ! 1017: mtdx.crvalue |= FD; ! 1018: } ! 1019: } ! 1020: ! 1021: DRIVER ( "MTD80X", nic_driver, pci_driver, mtd80x_driver, ! 1022: mtd_probe, mtd_disable );
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.