From ca67b09c015d4af3ae3cce12aa72e60941dbb8b5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:29:52 +0200 Subject: Adding debian version 2.06-13+deb12u1. Signed-off-by: Daniel Baumann --- .../disabled/gpxe/src/drivers/net/mtd80x.c | 1022 ++++++++++++++++++++ 1 file changed, 1022 insertions(+) create mode 100644 debian/grub-extras/disabled/gpxe/src/drivers/net/mtd80x.c (limited to 'debian/grub-extras/disabled/gpxe/src/drivers/net/mtd80x.c') diff --git a/debian/grub-extras/disabled/gpxe/src/drivers/net/mtd80x.c b/debian/grub-extras/disabled/gpxe/src/drivers/net/mtd80x.c new file mode 100644 index 0000000..7cf59b0 --- /dev/null +++ b/debian/grub-extras/disabled/gpxe/src/drivers/net/mtd80x.c @@ -0,0 +1,1022 @@ +/************************************************************************** +* +* mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip. +* Written 2004-2004 by Erdem Güven +* +* 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 +* +***************************************************************************/ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/* 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 +#include +#include + +/* 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 '%'<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 + +/* 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, (unsigned int) 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, (unsigned int) 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", + (unsigned int) 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", 0), + PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X", 0), + PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891", 0), +}; + +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; + + adjust_pci_device(pci); + + nic->ioaddr = pci->ioaddr; + nic->irqno = 0; + + mtdx.nic_name = pci->driver_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 ); -- cgit v1.2.3