12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082 |
- /**************************************************************************
- *
- * mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip.
- * Written 2004-2004 by Erdem Güven <zuencap@yahoo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Portions of this code based on:
- * fealnx.c: A Linux device driver for the mtd80x Ethernet chip
- * Written 1998-2000 by Donald Becker
- *
- ***************************************************************************/
-
- /* to get some global routines like printf */
- #include "etherboot.h"
- /* to get the interface to the body of the program */
- #include "nic.h"
- /* to get the PCI support functions, if this is a PCI NIC */
- #include <gpxe/pci.h>
- #include <gpxe/ethernet.h>
-
- /* Condensed operations for readability. */
- #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
- #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
- #define get_unaligned(ptr) (*(ptr))
-
-
- /* Operational parameters that are set at compile time. */
-
- /* Keep the ring sizes a power of two for compile efficiency. */
- /* The compiler will convert <unsigned>'%'<2^N> into a bit mask. */
- /* Making the Tx ring too large decreases the effectiveness of channel */
- /* bonding and packet priority. */
- /* There are no ill effects from too-large receive rings. */
- #define TX_RING_SIZE 2
- #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
- #define RX_RING_SIZE 4
-
- /* Operational parameters that usually are not changed. */
- /* Time in jiffies before concluding the transmitter is hung. */
- #define HZ 100
- #define TX_TIME_OUT (6*HZ)
-
- /* Allocation size of Rx buffers with normal sized Ethernet frames.
- Do not change this value without good reason. This is not a limit,
- but a way to keep a consistent allocation size among drivers.
- */
- #define PKT_BUF_SZ 1536
-
- /* Generic MII registers. */
-
- #define MII_BMCR 0x00 /* Basic mode control register */
- #define MII_BMSR 0x01 /* Basic mode status register */
- #define MII_PHYSID1 0x02 /* PHYS ID 1 */
- #define MII_PHYSID2 0x03 /* PHYS ID 2 */
- #define MII_ADVERTISE 0x04 /* Advertisement control reg */
- #define MII_LPA 0x05 /* Link partner ability reg */
- #define MII_EXPANSION 0x06 /* Expansion register */
- #define MII_DCOUNTER 0x12 /* Disconnect counter */
- #define MII_FCSCOUNTER 0x13 /* False carrier counter */
- #define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
- #define MII_RERRCOUNTER 0x15 /* Receive error counter */
- #define MII_SREVISION 0x16 /* Silicon revision */
- #define MII_RESV1 0x17 /* Reserved... */
- #define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
- #define MII_PHYADDR 0x19 /* PHY address */
- #define MII_RESV2 0x1a /* Reserved... */
- #define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
- #define MII_NCONFIG 0x1c /* Network interface config */
-
- /* Basic mode control register. */
- #define BMCR_RESV 0x007f /* Unused... */
- #define BMCR_CTST 0x0080 /* Collision test */
- #define BMCR_FULLDPLX 0x0100 /* Full duplex */
- #define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
- #define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
- #define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
- #define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
- #define BMCR_SPEED100 0x2000 /* Select 100Mbps */
- #define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
- #define BMCR_RESET 0x8000 /* Reset the DP83840 */
-
- /* Basic mode status register. */
- #define BMSR_ERCAP 0x0001 /* Ext-reg capability */
- #define BMSR_JCD 0x0002 /* Jabber detected */
- #define BMSR_LSTATUS 0x0004 /* Link status */
- #define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
- #define BMSR_RFAULT 0x0010 /* Remote fault detected */
- #define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
- #define BMSR_RESV 0x07c0 /* Unused... */
- #define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
- #define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
- #define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
- #define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
- #define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
-
- /* Advertisement control register. */
- #define ADVERTISE_SLCT 0x001f /* Selector bits */
- #define ADVERTISE_CSMA 0x0001 /* Only selector supported */
- #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
- #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
- #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
- #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
- #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
- #define ADVERTISE_RESV 0x1c00 /* Unused... */
- #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
- #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
- #define ADVERTISE_NPAGE 0x8000 /* Next page bit */
-
- #define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
- ADVERTISE_CSMA)
- #define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
- ADVERTISE_100HALF | ADVERTISE_100FULL)
-
- /* for different PHY */
- enum phy_type_flags {
- MysonPHY = 1,
- AhdocPHY = 2,
- SeeqPHY = 3,
- MarvellPHY = 4,
- Myson981 = 5,
- LevelOnePHY = 6,
- OtherPHY = 10,
- };
-
- /* A chip capabilities table*/
- enum chip_capability_flags {
- HAS_MII_XCVR,
- HAS_CHIP_XCVR,
- };
-
- #if 0 /* not used */
- static
- struct chip_info
- {
- u16 dev_id;
- int flag;
- }
- mtd80x_chips[] = {
- {0x0800, HAS_MII_XCVR},
- {0x0803, HAS_CHIP_XCVR},
- {0x0891, HAS_MII_XCVR}
- };
- static int chip_cnt = sizeof( mtd80x_chips ) / sizeof( struct chip_info );
- #endif
-
- /* Offsets to the Command and Status Registers. */
- enum mtd_offsets {
- PAR0 = 0x0, /* physical address 0-3 */
- PAR1 = 0x04, /* physical address 4-5 */
- MAR0 = 0x08, /* multicast address 0-3 */
- MAR1 = 0x0C, /* multicast address 4-7 */
- FAR0 = 0x10, /* flow-control address 0-3 */
- FAR1 = 0x14, /* flow-control address 4-5 */
- TCRRCR = 0x18, /* receive & transmit configuration */
- BCR = 0x1C, /* bus command */
- TXPDR = 0x20, /* transmit polling demand */
- RXPDR = 0x24, /* receive polling demand */
- RXCWP = 0x28, /* receive current word pointer */
- TXLBA = 0x2C, /* transmit list base address */
- RXLBA = 0x30, /* receive list base address */
- ISR = 0x34, /* interrupt status */
- IMR = 0x38, /* interrupt mask */
- FTH = 0x3C, /* flow control high/low threshold */
- MANAGEMENT = 0x40, /* bootrom/eeprom and mii management */
- TALLY = 0x44, /* tally counters for crc and mpa */
- TSR = 0x48, /* tally counter for transmit status */
- BMCRSR = 0x4c, /* basic mode control and status */
- PHYIDENTIFIER = 0x50, /* phy identifier */
- ANARANLPAR = 0x54, /* auto-negotiation advertisement and link
- partner ability */
- ANEROCR = 0x58, /* auto-negotiation expansion and pci conf. */
- BPREMRPSR = 0x5c, /* bypass & receive error mask and phy status */
- };
-
- /* Bits in the interrupt status/enable registers. */
- /* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
- enum intr_status_bits {
- RFCON = 0x00020000, /* receive flow control xon packet */
- RFCOFF = 0x00010000, /* receive flow control xoff packet */
- LSCStatus = 0x00008000, /* link status change */
- ANCStatus = 0x00004000, /* autonegotiation completed */
- FBE = 0x00002000, /* fatal bus error */
- FBEMask = 0x00001800, /* mask bit12-11 */
- ParityErr = 0x00000000, /* parity error */
- TargetErr = 0x00001000, /* target abort */
- MasterErr = 0x00000800, /* master error */
- TUNF = 0x00000400, /* transmit underflow */
- ROVF = 0x00000200, /* receive overflow */
- ETI = 0x00000100, /* transmit early int */
- ERI = 0x00000080, /* receive early int */
- CNTOVF = 0x00000040, /* counter overflow */
- RBU = 0x00000020, /* receive buffer unavailable */
- TBU = 0x00000010, /* transmit buffer unavilable */
- TI = 0x00000008, /* transmit interrupt */
- RI = 0x00000004, /* receive interrupt */
- RxErr = 0x00000002, /* receive error */
- };
-
- /* Bits in the NetworkConfig register. */
- enum rx_mode_bits {
- RxModeMask = 0xe0,
- AcceptAllPhys = 0x80, /* promiscuous mode */
- AcceptBroadcast = 0x40, /* accept broadcast */
- AcceptMulticast = 0x20, /* accept mutlicast */
- AcceptRunt = 0x08, /* receive runt pkt */
- ALP = 0x04, /* receive long pkt */
- AcceptErr = 0x02, /* receive error pkt */
-
- AcceptMyPhys = 0x00000000,
- RxEnable = 0x00000001,
- RxFlowCtrl = 0x00002000,
- TxEnable = 0x00040000,
- TxModeFDX = 0x00100000,
- TxThreshold = 0x00e00000,
-
- PS1000 = 0x00010000,
- PS10 = 0x00080000,
- FD = 0x00100000,
- };
-
- /* Bits in network_desc.status */
- enum rx_desc_status_bits {
- RXOWN = 0x80000000, /* own bit */
- FLNGMASK = 0x0fff0000, /* frame length */
- FLNGShift = 16,
- MARSTATUS = 0x00004000, /* multicast address received */
- BARSTATUS = 0x00002000, /* broadcast address received */
- PHYSTATUS = 0x00001000, /* physical address received */
- RXFSD = 0x00000800, /* first descriptor */
- RXLSD = 0x00000400, /* last descriptor */
- ErrorSummary = 0x80, /* error summary */
- RUNT = 0x40, /* runt packet received */
- LONG = 0x20, /* long packet received */
- FAE = 0x10, /* frame align error */
- CRC = 0x08, /* crc error */
- RXER = 0x04, /* receive error */
- };
-
- enum rx_desc_control_bits {
- RXIC = 0x00800000, /* interrupt control */
- RBSShift = 0,
- };
-
- enum tx_desc_status_bits {
- TXOWN = 0x80000000, /* own bit */
- JABTO = 0x00004000, /* jabber timeout */
- CSL = 0x00002000, /* carrier sense lost */
- LC = 0x00001000, /* late collision */
- EC = 0x00000800, /* excessive collision */
- UDF = 0x00000400, /* fifo underflow */
- DFR = 0x00000200, /* deferred */
- HF = 0x00000100, /* heartbeat fail */
- NCRMask = 0x000000ff, /* collision retry count */
- NCRShift = 0,
- };
-
- enum tx_desc_control_bits {
- TXIC = 0x80000000, /* interrupt control */
- ETIControl = 0x40000000, /* early transmit interrupt */
- TXLD = 0x20000000, /* last descriptor */
- TXFD = 0x10000000, /* first descriptor */
- CRCEnable = 0x08000000, /* crc control */
- PADEnable = 0x04000000, /* padding control */
- RetryTxLC = 0x02000000, /* retry late collision */
- PKTSMask = 0x3ff800, /* packet size bit21-11 */
- PKTSShift = 11,
- TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */
- TBSShift = 0,
- };
-
- /* BootROM/EEPROM/MII Management Register */
- #define MASK_MIIR_MII_READ 0x00000000
- #define MASK_MIIR_MII_WRITE 0x00000008
- #define MASK_MIIR_MII_MDO 0x00000004
- #define MASK_MIIR_MII_MDI 0x00000002
- #define MASK_MIIR_MII_MDC 0x00000001
-
- /* ST+OP+PHYAD+REGAD+TA */
- #define OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */
- #define OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */
-
- /* ------------------------------------------------------------------------- */
- /* Constants for Myson PHY */
- /* ------------------------------------------------------------------------- */
- #define MysonPHYID 0xd0000302
- /* 89-7-27 add, (begin) */
- #define MysonPHYID0 0x0302
- #define StatusRegister 18
- #define SPEED100 0x0400 // bit10
- #define FULLMODE 0x0800 // bit11
- /* 89-7-27 add, (end) */
-
- /* ------------------------------------------------------------------------- */
- /* Constants for Seeq 80225 PHY */
- /* ------------------------------------------------------------------------- */
- #define SeeqPHYID0 0x0016
-
- #define MIIRegister18 18
- #define SPD_DET_100 0x80
- #define DPLX_DET_FULL 0x40
-
- /* ------------------------------------------------------------------------- */
- /* Constants for Ahdoc 101 PHY */
- /* ------------------------------------------------------------------------- */
- #define AhdocPHYID0 0x0022
-
- #define DiagnosticReg 18
- #define DPLX_FULL 0x0800
- #define Speed_100 0x0400
-
- /* 89/6/13 add, */
- /* -------------------------------------------------------------------------- */
- /* Constants */
- /* -------------------------------------------------------------------------- */
- #define MarvellPHYID0 0x0141
- #define LevelOnePHYID0 0x0013
-
- #define MII1000BaseTControlReg 9
- #define MII1000BaseTStatusReg 10
- #define SpecificReg 17
-
- /* for 1000BaseT Control Register */
- #define PHYAbletoPerform1000FullDuplex 0x0200
- #define PHYAbletoPerform1000HalfDuplex 0x0100
- #define PHY1000AbilityMask 0x300
-
- // for phy specific status register, marvell phy.
- #define SpeedMask 0x0c000
- #define Speed_1000M 0x08000
- #define Speed_100M 0x4000
- #define Speed_10M 0
- #define Full_Duplex 0x2000
-
- // 89/12/29 add, for phy specific status register, levelone phy, (begin)
- #define LXT1000_100M 0x08000
- #define LXT1000_1000M 0x0c000
- #define LXT1000_Full 0x200
- // 89/12/29 add, for phy specific status register, levelone phy, (end)
-
- #if 0
- /* for 3-in-1 case */
- #define PS10 0x00080000
- #define FD 0x00100000
- #define PS1000 0x00010000
- #endif
-
- /* for PHY */
- #define LinkIsUp 0x0004
- #define LinkIsUp2 0x00040000
-
- /* Create a static buffer of size PKT_BUF_SZ for each
- RX and TX Descriptor. All descriptors point to a
- part of this buffer */
- struct {
- u8 txb[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned(8)));
- u8 rxb[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned(8)));
- } mtd80x_bufs __shared;
- #define txb mtd80x_bufs.txb
- #define rxb mtd80x_bufs.rxb
-
- /* The Tulip Rx and Tx buffer descriptors. */
- struct mtd_desc
- {
- s32 status;
- s32 control;
- u32 buffer;
- u32 next_desc;
- struct mtd_desc *next_desc_logical;
- u8* skbuff;
- u32 reserved1;
- u32 reserved2;
- };
-
- struct mtd_private
- {
- struct mtd_desc rx_ring[RX_RING_SIZE];
- struct mtd_desc tx_ring[TX_RING_SIZE];
-
- /* Frequently used values: keep some adjacent for cache effect. */
- int flags;
- struct pci_dev *pci_dev;
- unsigned long crvalue;
- unsigned long bcrvalue;
- /*unsigned long imrvalue;*/
- struct mtd_desc *cur_rx;
- struct mtd_desc *lack_rxbuf;
- int really_rx_count;
- struct mtd_desc *cur_tx;
- struct mtd_desc *cur_tx_copy;
- int really_tx_count;
- int free_tx_count;
- unsigned int rx_buf_sz; /* Based on MTU+slack. */
-
- /* These values are keep track of the transceiver/media in use. */
- unsigned int linkok;
- unsigned int line_speed;
- unsigned int duplexmode;
- unsigned int default_port:
- 4; /* Last dev->if_port value. */
- unsigned int PHYType;
-
- /* MII transceiver section. */
- int mii_cnt; /* MII device addresses. */
- unsigned char phys[1]; /* MII device addresses. */
-
- /*other*/
- const char *nic_name;
- int ioaddr;
- u16 dev_id;
- };
-
- static struct mtd_private mtdx;
-
- static int mdio_read(struct nic * , int phy_id, int location);
- static void getlinktype(struct nic * );
- static void getlinkstatus(struct nic * );
- static void set_rx_mode(struct nic *);
-
- /**************************************************************************
- * init_ring - setup the tx and rx descriptors
- *************************************************************************/
- static void init_ring(struct nic *nic __unused)
- {
- int i;
-
- mtdx.cur_rx = &mtdx.rx_ring[0];
-
- mtdx.rx_buf_sz = PKT_BUF_SZ;
- /*mtdx.rx_head_desc = &mtdx.rx_ring[0];*/
-
- /* Initialize all Rx descriptors. */
- /* Fill in the Rx buffers. Handle allocation failure gracefully. */
- for (i = 0; i < RX_RING_SIZE; i++)
- {
- mtdx.rx_ring[i].status = RXOWN;
- mtdx.rx_ring[i].control = mtdx.rx_buf_sz << RBSShift;
- mtdx.rx_ring[i].next_desc = virt_to_le32desc(&mtdx.rx_ring[i+1]);
- mtdx.rx_ring[i].next_desc_logical = &mtdx.rx_ring[i+1];
- mtdx.rx_ring[i].buffer = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
- mtdx.rx_ring[i].skbuff = &rxb[i * PKT_BUF_SZ];
- }
- /* Mark the last entry as wrapping the ring. */
- mtdx.rx_ring[i-1].next_desc = virt_to_le32desc(&mtdx.rx_ring[0]);
- mtdx.rx_ring[i-1].next_desc_logical = &mtdx.rx_ring[0];
-
- /* We only use one transmit buffer, but two
- * descriptors so transmit engines have somewhere
- * to point should they feel the need */
- mtdx.tx_ring[0].status = 0x00000000;
- mtdx.tx_ring[0].buffer = virt_to_bus(&txb[0]);
- mtdx.tx_ring[0].next_desc = virt_to_le32desc(&mtdx.tx_ring[1]);
-
- /* This descriptor is never used */
- mtdx.tx_ring[1].status = 0x00000000;
- mtdx.tx_ring[1].buffer = 0; /*virt_to_bus(&txb[1]); */
- mtdx.tx_ring[1].next_desc = virt_to_le32desc(&mtdx.tx_ring[0]);
-
- return;
- }
-
- /**************************************************************************
- RESET - Reset Adapter
- ***************************************************************************/
- static void mtd_reset( struct nic *nic )
- {
- /* Reset the chip to erase previous misconfiguration. */
- outl(0x00000001, mtdx.ioaddr + BCR);
-
- init_ring(nic);
-
- outl(virt_to_bus(mtdx.rx_ring), mtdx.ioaddr + RXLBA);
- outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
-
- /* Initialize other registers. */
- /* Configure the PCI bus bursts and FIFO thresholds. */
- mtdx.bcrvalue = 0x10; /* little-endian, 8 burst length */
- mtdx.crvalue = 0xa00; /* rx 128 burst length */
-
- if ( mtdx.dev_id == 0x891 ) {
- mtdx.bcrvalue |= 0x200; /* set PROG bit */
- mtdx.crvalue |= 0x02000000; /* set enhanced bit */
- }
-
- outl( mtdx.bcrvalue, mtdx.ioaddr + BCR);
-
- /* Restart Rx engine if stopped. */
- outl(0, mtdx.ioaddr + RXPDR);
-
- getlinkstatus(nic);
- if (mtdx.linkok)
- {
- static const char* texts[]={"half","full","10","100","1000"};
- getlinktype(nic);
- DBG ( "Link is OK : %s %s\n", texts[mtdx.duplexmode-1], texts[mtdx.line_speed+1] );
- } else
- {
- DBG ( "No link!!!\n" );
- }
-
- mtdx.crvalue |= /*TxEnable |*/ RxEnable | TxThreshold;
- set_rx_mode(nic);
-
- /* Clear interrupts by setting the interrupt mask. */
- outl(FBE | TUNF | CNTOVF | RBU | TI | RI, mtdx.ioaddr + ISR);
- outl( 0, mtdx.ioaddr + IMR);
- }
-
- /**************************************************************************
- POLL - Wait for a frame
- ***************************************************************************/
- static int mtd_poll(struct nic *nic, __unused int retrieve)
- {
- s32 rx_status = mtdx.cur_rx->status;
- int retval = 0;
-
- if( ( rx_status & RXOWN ) != 0 )
- {
- return 0;
- }
-
- if (rx_status & ErrorSummary)
- { /* there was a fatal error */
- printf( "%s: Receive error, Rx status %8.8x, Error(s) %s%s%s\n",
- mtdx.nic_name, rx_status ,
- (rx_status & (LONG | RUNT)) ? "length_error ":"",
- (rx_status & RXER) ? "frame_error ":"",
- (rx_status & CRC) ? "crc_error ":"" );
- retval = 0;
- } else if( !((rx_status & RXFSD) && (rx_status & RXLSD)) )
- {
- /* this pkt is too long, over one rx buffer */
- printf("Pkt is too long, over one rx buffer.\n");
- retval = 0;
- } else
- { /* this received pkt is ok */
- /* Omit the four octet CRC from the length. */
- short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4;
-
- DBG ( " netdev_rx() normal Rx pkt length %d"
- " status %x.\n", pkt_len, rx_status );
-
- nic->packetlen = pkt_len;
- memcpy(nic->packet, mtdx.cur_rx->skbuff, pkt_len);
-
- retval = 1;
- }
-
- while( ( mtdx.cur_rx->status & RXOWN ) == 0 )
- {
- mtdx.cur_rx->status = RXOWN;
- mtdx.cur_rx = mtdx.cur_rx->next_desc_logical;
- }
-
- /* Restart Rx engine if stopped. */
- outl(0, mtdx.ioaddr + RXPDR);
-
- return retval;
- }
-
- /**************************************************************************
- TRANSMIT - Transmit a frame
- ***************************************************************************/
- static void mtd_transmit(
- struct nic *nic,
- const char *dest, /* Destination */
- unsigned int type, /* Type */
- unsigned int size, /* size */
- const char *data) /* Packet */
- {
- u32 to;
- u32 tx_status;
- unsigned int nstype = htons ( type );
-
- memcpy( txb, dest, ETH_ALEN );
- memcpy( txb + ETH_ALEN, nic->node_addr, ETH_ALEN );
- memcpy( txb + 2 * ETH_ALEN, &nstype, 2 );
- memcpy( txb + ETH_HLEN, data, size );
-
- size += ETH_HLEN;
- size &= 0x0FFF;
- while( size < ETH_ZLEN )
- {
- txb[size++] = '\0';
- }
-
- mtdx.tx_ring[0].control = TXLD | TXFD | CRCEnable | PADEnable;
- mtdx.tx_ring[0].control |= (size << PKTSShift); /* pkt size */
- mtdx.tx_ring[0].control |= (size << TBSShift); /* buffer size */
- mtdx.tx_ring[0].status = TXOWN;
-
- /* Point to transmit descriptor */
- outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
- /* Enable Tx */
- outl( mtdx.crvalue | TxEnable, mtdx.ioaddr + TCRRCR);
- /* Wake the potentially-idle transmit channel. */
- outl(0, mtdx.ioaddr + TXPDR);
-
- to = currticks() + TX_TIME_OUT;
- while(( mtdx.tx_ring[0].status & TXOWN) && (currticks() < to));
-
- /* Disable Tx */
- outl( mtdx.crvalue & (~TxEnable), mtdx.ioaddr + TCRRCR);
-
- tx_status = mtdx.tx_ring[0].status;
- if (currticks() >= to){
- DBG ( "TX Time Out" );
- } else if( tx_status & (CSL | LC | EC | UDF | HF)){
- printf( "Transmit error: %8.8x %s %s %s %s %s\n",
- tx_status,
- tx_status & EC ? "abort" : "",
- tx_status & CSL ? "carrier" : "",
- tx_status & LC ? "late" : "",
- tx_status & UDF ? "fifo" : "",
- tx_status & HF ? "heartbeat" : "" );
- }
-
- /*hex_dump( txb, size );*/
- /*pause();*/
-
- DBG ( "TRANSMIT\n" );
- }
-
- /**************************************************************************
- DISABLE - Turn off ethernet interface
- ***************************************************************************/
- static void mtd_disable ( struct nic *nic ) {
-
- /* Disable Tx Rx*/
- outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR );
-
- /* Reset the chip to erase previous misconfiguration. */
- mtd_reset(nic);
-
- DBG ( "DISABLE\n" );
- }
-
- static struct nic_operations mtd_operations = {
- .connect = dummy_connect,
- .poll = mtd_poll,
- .transmit = mtd_transmit,
- .irq = dummy_irq,
-
- };
-
- static struct pci_device_id mtd80x_nics[] = {
- PCI_ROM(0x1516, 0x0800, "MTD800", "Myson MTD800"),
- PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X"),
- PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891"),
- };
-
- PCI_DRIVER ( mtd80x_driver, mtd80x_nics, PCI_NO_CLASS );
-
- /**************************************************************************
- PROBE - Look for an adapter, this routine's visible to the outside
- ***************************************************************************/
-
- static int mtd_probe ( struct nic *nic, struct pci_device *pci ) {
-
- int i;
-
- if (pci->ioaddr == 0)
- return 0;
-
- pci_fill_nic ( nic, pci );
- adjust_pci_device(pci);
-
- mtdx.nic_name = pci->name;
- mtdx.dev_id = pci->device;
- mtdx.ioaddr = nic->ioaddr;
-
- /* read ethernet id */
- for (i = 0; i < 6; ++i)
- {
- nic->node_addr[i] = inb(mtdx.ioaddr + PAR0 + i);
- }
-
- if (memcmp(nic->node_addr, "\0\0\0\0\0\0", 6) == 0)
- {
- return 0;
- }
-
- DBG ( "%s: ioaddr %4.4x MAC %s\n", mtdx.nic_name, mtdx.ioaddr, eth_ntoa ( nic->node_addr ) );
-
- /* Reset the chip to erase previous misconfiguration. */
- outl(0x00000001, mtdx.ioaddr + BCR);
-
- /* find the connected MII xcvrs */
-
- if( mtdx.dev_id != 0x803 )
- {
- int phy, phy_idx = 0;
-
- for (phy = 1; phy < 32 && phy_idx < 1; phy++) {
- int mii_status = mdio_read(nic, phy, 1);
-
- if (mii_status != 0xffff && mii_status != 0x0000) {
- mtdx.phys[phy_idx] = phy;
-
- DBG ( "%s: MII PHY found at address %d, status "
- "0x%4.4x.\n", mtdx.nic_name, phy, mii_status );
- /* get phy type */
- {
- unsigned int data;
-
- data = mdio_read(nic, mtdx.phys[phy_idx], 2);
- if (data == SeeqPHYID0)
- mtdx.PHYType = SeeqPHY;
- else if (data == AhdocPHYID0)
- mtdx.PHYType = AhdocPHY;
- else if (data == MarvellPHYID0)
- mtdx.PHYType = MarvellPHY;
- else if (data == MysonPHYID0)
- mtdx.PHYType = Myson981;
- else if (data == LevelOnePHYID0)
- mtdx.PHYType = LevelOnePHY;
- else
- mtdx.PHYType = OtherPHY;
- }
- phy_idx++;
- }
- }
-
- mtdx.mii_cnt = phy_idx;
- if (phy_idx == 0) {
- printf("%s: MII PHY not found -- this device may "
- "not operate correctly.\n", mtdx.nic_name);
- }
- } else {
- mtdx.phys[0] = 32;
- /* get phy type */
- if (inl(mtdx.ioaddr + PHYIDENTIFIER) == MysonPHYID ) {
- mtdx.PHYType = MysonPHY;
- DBG ( "MysonPHY\n" );
- } else {
- mtdx.PHYType = OtherPHY;
- DBG ( "OtherPHY\n" );
- }
- }
-
- getlinkstatus(nic);
- if( !mtdx.linkok )
- {
- printf("No link!!!\n");
- return 0;
- }
-
- mtd_reset( nic );
-
- /* point to NIC specific routines */
- nic->nic_op = &mtd_operations;
- return 1;
- }
-
-
- /**************************************************************************/
- static void set_rx_mode(struct nic *nic __unused)
- {
- u32 mc_filter[2]; /* Multicast hash filter */
- u32 rx_mode;
-
- /* Too many to match, or accept all multicasts. */
- mc_filter[1] = mc_filter[0] = ~0;
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-
- outl(mc_filter[0], mtdx.ioaddr + MAR0);
- outl(mc_filter[1], mtdx.ioaddr + MAR1);
-
- mtdx.crvalue = ( mtdx.crvalue & ~RxModeMask ) | rx_mode;
- outb( mtdx.crvalue, mtdx.ioaddr + TCRRCR);
- }
- /**************************************************************************/
- static unsigned int m80x_read_tick(void)
- /* function: Reads the Timer tick count register which decrements by 2 from */
- /* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the */
- /* count represents 838 nsec's. */
- /* input : none. */
- /* output : none. */
- {
- unsigned char tmp;
- int value;
-
- outb((char) 0x06, 0x43); // Command 8254 to latch T0's count
-
- // now read the count.
- tmp = (unsigned char) inb(0x40);
- value = ((int) tmp) << 8;
- tmp = (unsigned char) inb(0x40);
- value |= (((int) tmp) & 0xff);
- return (value);
- }
-
- static void m80x_delay(unsigned int interval)
- /* function: to wait for a specified time. */
- /* input : interval ... the specified time. */
- /* output : none. */
- {
- unsigned int interval1, interval2, i = 0;
-
- interval1 = m80x_read_tick(); // get initial value
- do
- {
- interval2 = m80x_read_tick();
- if (interval1 < interval2)
- interval1 += 65536;
- ++i;
- } while (((interval1 - interval2) < (u16) interval) && (i < 65535));
- }
-
-
- static u32 m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
- {
- u32 miir;
- int i;
- unsigned int mask, data;
-
- /* enable MII output */
- miir = (u32) inl(miiport);
- miir &= 0xfffffff0;
-
- miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO;
-
- /* send 32 1's preamble */
- for (i = 0; i < 32; i++) {
- /* low MDC; MDO is already high (miir) */
- miir &= ~MASK_MIIR_MII_MDC;
- outl(miir, miiport);
-
- /* high MDC */
- miir |= MASK_MIIR_MII_MDC;
- outl(miir, miiport);
- }
-
- /* calculate ST+OP+PHYAD+REGAD+TA */
- data = opcode | (phyad << 7) | (regad << 2);
-
- /* sent out */
- mask = 0x8000;
- while (mask) {
- /* low MDC, prepare MDO */
- miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
- if (mask & data)
- miir |= MASK_MIIR_MII_MDO;
-
- outl(miir, miiport);
- /* high MDC */
- miir |= MASK_MIIR_MII_MDC;
- outl(miir, miiport);
- m80x_delay(30);
-
- /* next */
- mask >>= 1;
- if (mask == 0x2 && opcode == OP_READ)
- miir &= ~MASK_MIIR_MII_WRITE;
- }
- return miir;
- }
-
- static int mdio_read(struct nic *nic __unused, int phyad, int regad)
- {
- long miiport = mtdx.ioaddr + MANAGEMENT;
- u32 miir;
- unsigned int mask, data;
-
- miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad);
-
- /* read data */
- mask = 0x8000;
- data = 0;
- while (mask)
- {
- /* low MDC */
- miir &= ~MASK_MIIR_MII_MDC;
- outl(miir, miiport);
-
- /* read MDI */
- miir = inl(miiport);
- if (miir & MASK_MIIR_MII_MDI)
- data |= mask;
-
- /* high MDC, and wait */
- miir |= MASK_MIIR_MII_MDC;
- outl(miir, miiport);
- m80x_delay((int) 30);
-
- /* next */
- mask >>= 1;
- }
-
- /* low MDC */
- miir &= ~MASK_MIIR_MII_MDC;
- outl(miir, miiport);
-
- return data & 0xffff;
- }
-
- #if 0 /* not used */
- static void mdio_write(struct nic *nic __unused, int phyad, int regad,
- int data)
- {
- long miiport = mtdx.ioaddr + MANAGEMENT;
- u32 miir;
- unsigned int mask;
-
- miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad);
-
- /* write data */
- mask = 0x8000;
- while (mask)
- {
- /* low MDC, prepare MDO */
- miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
- if (mask & data)
- miir |= MASK_MIIR_MII_MDO;
- outl(miir, miiport);
-
- /* high MDC */
- miir |= MASK_MIIR_MII_MDC;
- outl(miir, miiport);
-
- /* next */
- mask >>= 1;
- }
-
- /* low MDC */
- miir &= ~MASK_MIIR_MII_MDC;
- outl(miir, miiport);
-
- return;
- }
- #endif
-
- static void getlinkstatus(struct nic *nic)
- /* function: Routine will read MII Status Register to get link status. */
- /* input : dev... pointer to the adapter block. */
- /* output : none. */
- {
- unsigned int i, DelayTime = 0x1000;
-
- mtdx.linkok = 0;
-
- if (mtdx.PHYType == MysonPHY)
- {
- for (i = 0; i < DelayTime; ++i) {
- if (inl(mtdx.ioaddr + BMCRSR) & LinkIsUp2) {
- mtdx.linkok = 1;
- return;
- }
- // delay
- m80x_delay(100);
- }
- } else
- {
- for (i = 0; i < DelayTime; ++i) {
- if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) {
- mtdx.linkok = 1;
- return;
- }
- // delay
- m80x_delay(100);
- }
- }
- }
-
-
- static void getlinktype(struct nic *dev)
- {
- if (mtdx.PHYType == MysonPHY)
- { /* 3-in-1 case */
- if (inl(mtdx.ioaddr + TCRRCR) & FD)
- mtdx.duplexmode = 2; /* full duplex */
- else
- mtdx.duplexmode = 1; /* half duplex */
- if (inl(mtdx.ioaddr + TCRRCR) & PS10)
- mtdx.line_speed = 1; /* 10M */
- else
- mtdx.line_speed = 2; /* 100M */
- } else
- {
- if (mtdx.PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */
- unsigned int data;
-
- data = mdio_read(dev, mtdx.phys[0], MIIRegister18);
- if (data & SPD_DET_100)
- mtdx.line_speed = 2; /* 100M */
- else
- mtdx.line_speed = 1; /* 10M */
- if (data & DPLX_DET_FULL)
- mtdx.duplexmode = 2; /* full duplex mode */
- else
- mtdx.duplexmode = 1; /* half duplex mode */
- } else if (mtdx.PHYType == AhdocPHY) {
- unsigned int data;
-
- data = mdio_read(dev, mtdx.phys[0], DiagnosticReg);
- if (data & Speed_100)
- mtdx.line_speed = 2; /* 100M */
- else
- mtdx.line_speed = 1; /* 10M */
- if (data & DPLX_FULL)
- mtdx.duplexmode = 2; /* full duplex mode */
- else
- mtdx.duplexmode = 1; /* half duplex mode */
- }
- /* 89/6/13 add, (begin) */
- else if (mtdx.PHYType == MarvellPHY) {
- unsigned int data;
-
- data = mdio_read(dev, mtdx.phys[0], SpecificReg);
- if (data & Full_Duplex)
- mtdx.duplexmode = 2; /* full duplex mode */
- else
- mtdx.duplexmode = 1; /* half duplex mode */
- data &= SpeedMask;
- if (data == Speed_1000M)
- mtdx.line_speed = 3; /* 1000M */
- else if (data == Speed_100M)
- mtdx.line_speed = 2; /* 100M */
- else
- mtdx.line_speed = 1; /* 10M */
- }
- /* 89/6/13 add, (end) */
- /* 89/7/27 add, (begin) */
- else if (mtdx.PHYType == Myson981) {
- unsigned int data;
-
- data = mdio_read(dev, mtdx.phys[0], StatusRegister);
-
- if (data & SPEED100)
- mtdx.line_speed = 2;
- else
- mtdx.line_speed = 1;
-
- if (data & FULLMODE)
- mtdx.duplexmode = 2;
- else
- mtdx.duplexmode = 1;
- }
- /* 89/7/27 add, (end) */
- /* 89/12/29 add */
- else if (mtdx.PHYType == LevelOnePHY) {
- unsigned int data;
-
- data = mdio_read(dev, mtdx.phys[0], SpecificReg);
- if (data & LXT1000_Full)
- mtdx.duplexmode = 2; /* full duplex mode */
- else
- mtdx.duplexmode = 1; /* half duplex mode */
- data &= SpeedMask;
- if (data == LXT1000_1000M)
- mtdx.line_speed = 3; /* 1000M */
- else if (data == LXT1000_100M)
- mtdx.line_speed = 2; /* 100M */
- else
- mtdx.line_speed = 1; /* 10M */
- }
- // chage crvalue
- // mtdx.crvalue&=(~PS10)&(~FD);
- mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000);
- if (mtdx.line_speed == 1)
- mtdx.crvalue |= PS10;
- else if (mtdx.line_speed == 3)
- mtdx.crvalue |= PS1000;
- if (mtdx.duplexmode == 2)
- mtdx.crvalue |= FD;
- }
- }
-
- DRIVER ( "MTD80X", nic_driver, pci_driver, mtd80x_driver,
- mtd_probe, mtd_disable );
|