| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899 | 
							- /**************************************************************************
 - *
 - *    sundance.c -- Etherboot device driver for the Sundance ST201 "Alta".
 - *    Written 2002-2002 by Timothy Legge <tlegge@rogers.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., 51 Franklin Street, Fifth Floor, Boston, MA
 - *    02110-1301, USA.
 - *
 - *    Portions of this code based on:
 - *               sundance.c: A Linux device driver for the Sundance ST201 "Alta"
 - *               Written 1999-2002 by Donald Becker
 - *
 - *               tulip.c: Tulip and Clone Etherboot Driver
 - *               By Marty Conner
 - *               Copyright (C) 2001 Entity Cyber, Inc.
 - *
 - *    Linux Driver Version LK1.09a, 10-Jul-2003 (2.4.25)
 - *
 - *    REVISION HISTORY:
 - *    ================
 - *    v1.1	01-01-2003	timlegge	Initial implementation
 - *    v1.7	04-10-2003	timlegge	Transfers Linux Kernel (30 sec)
 - *    v1.8	04-13-2003	timlegge	Fix multiple transmission bug
 - *    v1.9	08-19-2003	timlegge	Support Multicast
 - *    v1.10	01-17-2004	timlegge	Initial driver output cleanup
 - *    v1.11	03-21-2004	timlegge	Remove unused variables
 - *    v1.12	03-21-2004	timlegge	Remove excess MII defines
 - *    v1.13	03-24-2004	timlegge	Update to Linux 2.4.25 driver
 - *
 - ****************************************************************************/
 - 
 - 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 <ipxe/pci.h>
 - #include "mii.h"
 - 
 - #define drv_version "v1.12"
 - #define drv_date "2004-03-21"
 - 
 - #define HZ 100
 - 
 - /* 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))
 - 
 - /* Set the mtu */
 - static int mtu = 1514;
 - 
 - /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
 -    The sundance uses a 64 element hash table based on the Ethernet CRC.  */
 - // static int multicast_filter_limit = 32;
 - 
 - /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
 -    Setting to > 1518 effectively disables this feature.
 -    This chip can receive into any byte alignment buffers, so word-oriented
 -    archs do not need a copy-align of the IP header. */
 - static int rx_copybreak = 0;
 - static int flowctrl = 1;
 - 
 - /* Allow forcing the media type */
 - /* media[] specifies the media type the NIC operates at.
 - 		 autosense	Autosensing active media.
 - 		 10mbps_hd 	10Mbps half duplex.
 - 		 10mbps_fd 	10Mbps full duplex.
 - 		 100mbps_hd 	100Mbps half duplex.
 - 		 100mbps_fd 	100Mbps full duplex.
 - */
 - static char media[] = "autosense";
 - 
 - /* Operational parameters that are set at compile time. */
 - 
 - /* As Etherboot uses a Polling driver  we can keep the number of rings
 - to the minimum number required.  In general that is 1 transmit and 4 receive receive rings.  However some cards require that
 - there be a minimum of 2 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 TX_TIME_OUT	  (4*HZ)
 - #define PKT_BUF_SZ	1536
 - 
 - /* Offsets to the device registers.
 -    Unlike software-only systems, device drivers interact with complex hardware.
 -    It's not useful to define symbolic names for every register bit in the
 -    device.  The name can only partially document the semantics and make
 -    the driver longer and more difficult to read.
 -    In general, only the important configuration values or bits changed
 -    multiple times should be defined symbolically.
 - */
 - enum alta_offsets {
 - 	DMACtrl = 0x00,
 - 	TxListPtr = 0x04,
 - 	TxDMABurstThresh = 0x08,
 - 	TxDMAUrgentThresh = 0x09,
 - 	TxDMAPollPeriod = 0x0a,
 - 	RxDMAStatus = 0x0c,
 - 	RxListPtr = 0x10,
 - 	DebugCtrl0 = 0x1a,
 - 	DebugCtrl1 = 0x1c,
 - 	RxDMABurstThresh = 0x14,
 - 	RxDMAUrgentThresh = 0x15,
 - 	RxDMAPollPeriod = 0x16,
 - 	LEDCtrl = 0x1a,
 - 	ASICCtrl = 0x30,
 - 	EEData = 0x34,
 - 	EECtrl = 0x36,
 - 	TxStartThresh = 0x3c,
 - 	RxEarlyThresh = 0x3e,
 - 	FlashAddr = 0x40,
 - 	FlashData = 0x44,
 - 	TxStatus = 0x46,
 - 	TxFrameId = 0x47,
 - 	DownCounter = 0x18,
 - 	IntrClear = 0x4a,
 - 	IntrEnable = 0x4c,
 - 	IntrStatus = 0x4e,
 - 	MACCtrl0 = 0x50,
 - 	MACCtrl1 = 0x52,
 - 	StationAddr = 0x54,
 - 	MaxFrameSize = 0x5A,
 - 	RxMode = 0x5c,
 - 	MIICtrl = 0x5e,
 - 	MulticastFilter0 = 0x60,
 - 	MulticastFilter1 = 0x64,
 - 	RxOctetsLow = 0x68,
 - 	RxOctetsHigh = 0x6a,
 - 	TxOctetsLow = 0x6c,
 - 	TxOctetsHigh = 0x6e,
 - 	TxFramesOK = 0x70,
 - 	RxFramesOK = 0x72,
 - 	StatsCarrierError = 0x74,
 - 	StatsLateColl = 0x75,
 - 	StatsMultiColl = 0x76,
 - 	StatsOneColl = 0x77,
 - 	StatsTxDefer = 0x78,
 - 	RxMissed = 0x79,
 - 	StatsTxXSDefer = 0x7a,
 - 	StatsTxAbort = 0x7b,
 - 	StatsBcastTx = 0x7c,
 - 	StatsBcastRx = 0x7d,
 - 	StatsMcastTx = 0x7e,
 - 	StatsMcastRx = 0x7f,
 - 	/* Aliased and bogus values! */
 - 	RxStatus = 0x0c,
 - };
 - enum ASICCtrl_HiWord_bit {
 - 	GlobalReset = 0x0001,
 - 	RxReset = 0x0002,
 - 	TxReset = 0x0004,
 - 	DMAReset = 0x0008,
 - 	FIFOReset = 0x0010,
 - 	NetworkReset = 0x0020,
 - 	HostReset = 0x0040,
 - 	ResetBusy = 0x0400,
 - };
 - 
 - /* Bits in the interrupt status/mask registers. */
 - enum intr_status_bits {
 - 	IntrSummary = 0x0001, IntrPCIErr = 0x0002, IntrMACCtrl = 0x0008,
 - 	IntrTxDone = 0x0004, IntrRxDone = 0x0010, IntrRxStart = 0x0020,
 - 	IntrDrvRqst = 0x0040,
 - 	StatsMax = 0x0080, LinkChange = 0x0100,
 - 	IntrTxDMADone = 0x0200, IntrRxDMADone = 0x0400,
 - };
 - 
 - /* Bits in the RxMode register. */
 - enum rx_mode_bits {
 - 	AcceptAllIPMulti = 0x20, AcceptMultiHash = 0x10, AcceptAll = 0x08,
 - 	AcceptBroadcast = 0x04, AcceptMulticast = 0x02, AcceptMyPhys =
 - 	    0x01,
 - };
 - /* Bits in MACCtrl. */
 - enum mac_ctrl0_bits {
 - 	EnbFullDuplex = 0x20, EnbRcvLargeFrame = 0x40,
 - 	EnbFlowCtrl = 0x100, EnbPassRxCRC = 0x200,
 - };
 - enum mac_ctrl1_bits {
 - 	StatsEnable = 0x0020, StatsDisable = 0x0040, StatsEnabled = 0x0080,
 - 	TxEnable = 0x0100, TxDisable = 0x0200, TxEnabled = 0x0400,
 - 	RxEnable = 0x0800, RxDisable = 0x1000, RxEnabled = 0x2000,
 - };
 - 
 - /* The Rx and Tx buffer descriptors.
 -    Using only 32 bit fields simplifies software endian correction.
 -    This structure must be aligned, and should avoid spanning cache lines.
 - */
 - struct netdev_desc {
 - 	u32 next_desc;
 - 	u32 status;
 - 	u32 addr;
 - 	u32 length;
 - };
 - 
 - /* Bits in netdev_desc.status */
 - enum desc_status_bits {
 - 	DescOwn = 0x8000,
 - 	DescEndPacket = 0x4000,
 - 	DescEndRing = 0x2000,
 - 	LastFrag = 0x80000000,
 - 	DescIntrOnTx = 0x8000,
 - 	DescIntrOnDMADone = 0x80000000,
 - 	DisableAlign = 0x00000001,
 - };
 - 
 - /**********************************************
 - * Descriptor Ring and Buffer defination
 - ***********************************************/
 - /* Define the TX Descriptor */
 - static struct netdev_desc tx_ring[TX_RING_SIZE];
 - 
 - /* Define the RX Descriptor */
 - static struct netdev_desc rx_ring[RX_RING_SIZE];
 - 
 - /* 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 {
 - 	unsigned char txb[PKT_BUF_SZ * TX_RING_SIZE];
 - 	unsigned char rxb[RX_RING_SIZE * PKT_BUF_SZ];
 - } rx_tx_buf __shared;
 - #define rxb rx_tx_buf.rxb
 - #define txb rx_tx_buf.txb
 - 
 - /* FIXME: Move BASE to the private structure */
 - static u32 BASE;
 - #define EEPROM_SIZE	128
 - 
 - enum pci_id_flags_bits {
 - 	PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4,
 - 	PCI_ADDR0 = 0 << 4, PCI_ADDR1 = 1 << 4, PCI_ADDR2 =
 - 	    2 << 4, PCI_ADDR3 = 3 << 4,
 - };
 - 
 - enum chip_capability_flags { CanHaveMII = 1, KendinPktDropBug = 2, };
 - #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
 - 
 - #define MII_CNT		4
 - static struct sundance_private {
 - 	const char *nic_name;
 - 	/* Frequently used values */
 - 
 - 	unsigned int cur_rx;	/* Producer/consumer ring indices */
 - 	unsigned int mtu;
 - 
 - 	/* These values keep track of the tranceiver/media in use */
 - 	unsigned int flowctrl:1;
 - 	unsigned int an_enable:1;
 - 
 - 	unsigned int speed;
 - 
 - 	/* MII tranceiver section */
 - 	struct mii_if_info mii_if;
 - 	int mii_preamble_required;
 - 	unsigned char phys[MII_CNT];
 - 	unsigned char pci_rev_id;
 - } sdx;
 - 
 - static struct sundance_private *sdc;
 - 
 - /* Station Address location within the EEPROM */
 - #define EEPROM_SA_OFFSET	0x10
 - #define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
 -                         IntrDrvRqst | IntrTxDone | StatsMax | \
 -                         LinkChange)
 - 
 - static int eeprom_read(long ioaddr, int location);
 - static int mdio_read(struct nic *nic, int phy_id, unsigned int location);
 - static void mdio_write(struct nic *nic, int phy_id, unsigned int location,
 - 		       int value);
 - static void set_rx_mode(struct nic *nic);
 - 
 - static void check_duplex(struct nic *nic)
 - {
 - 	int mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA);
 - 	int negotiated = mii_lpa & sdc->mii_if.advertising;
 - 	int duplex;
 - 
 - 	/* Force media */
 - 	if (!sdc->an_enable || mii_lpa == 0xffff) {
 - 		if (sdc->mii_if.full_duplex)
 - 			outw(inw(BASE + MACCtrl0) | EnbFullDuplex,
 - 			     BASE + MACCtrl0);
 - 		return;
 - 	}
 - 
 - 	/* Autonegotiation */
 - 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 - 	if (sdc->mii_if.full_duplex != duplex) {
 - 		sdc->mii_if.full_duplex = duplex;
 - 		DBG ("%s: Setting %s-duplex based on MII #%d "
 - 			 "negotiated capability %4.4x.\n", sdc->nic_name,
 - 			 duplex ? "full" : "half", sdc->phys[0],
 - 			 negotiated );
 - 		outw(inw(BASE + MACCtrl0) | duplex ? 0x20 : 0,
 - 		     BASE + MACCtrl0);
 - 	}
 - }
 - 
 - 
 - /**************************************************************************
 -  *  init_ring - setup the tx and rx descriptors
 -  *************************************************************************/
 - static void init_ring(struct nic *nic __unused)
 - {
 - 	int i;
 - 
 - 	sdc->cur_rx = 0;
 - 
 - 	/* Initialize all the Rx descriptors */
 - 	for (i = 0; i < RX_RING_SIZE; i++) {
 - 		rx_ring[i].next_desc = virt_to_le32desc(&rx_ring[i + 1]);
 - 		rx_ring[i].status = 0;
 - 		rx_ring[i].length = 0;
 - 		rx_ring[i].addr = 0;
 - 	}
 - 
 - 	/* Mark the last entry as wrapping the ring */
 - 	rx_ring[i - 1].next_desc = virt_to_le32desc(&rx_ring[0]);
 - 
 - 	for (i = 0; i < RX_RING_SIZE; i++) {
 - 		rx_ring[i].addr = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
 - 		rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LastFrag);
 - 	}
 - 
 - 	/* We only use one transmit buffer, but two
 - 	 * descriptors so transmit engines have somewhere
 - 	 * to point should they feel the need */
 - 	tx_ring[0].status = 0x00000000;
 - 	tx_ring[0].addr = virt_to_bus(&txb[0]);
 - 	tx_ring[0].next_desc = 0;	/* virt_to_bus(&tx_ring[1]); */
 - 
 - 	/* This descriptor is never used */
 - 	tx_ring[1].status = 0x00000000;
 - 	tx_ring[1].addr = 0;	/*virt_to_bus(&txb[0]); */
 - 	tx_ring[1].next_desc = 0;
 - 
 - 	/* Mark the last entry as wrapping the ring,
 - 	 * though this should never happen */
 - 	tx_ring[1].length = cpu_to_le32(LastFrag | PKT_BUF_SZ);
 - }
 - 
 - /**************************************************************************
 -  *  RESET - Reset Adapter
 -  * ***********************************************************************/
 - static void sundance_reset(struct nic *nic)
 - {
 - 	int i;
 - 
 - 	init_ring(nic);
 - 
 - 	outl(virt_to_le32desc(&rx_ring[0]), BASE + RxListPtr);
 - 	/* The Tx List Pointer is written as packets are queued */
 - 
 - 	/* Initialize other registers. */
 - 	/* __set_mac_addr(dev); */
 - 	{
 - 		u16 addr16;
 - 
 - 		addr16 = (nic->node_addr[0] | (nic->node_addr[1] << 8));
 - 		outw(addr16, BASE + StationAddr);
 - 		addr16 = (nic->node_addr[2] | (nic->node_addr[3] << 8));
 - 		outw(addr16, BASE + StationAddr + 2);
 - 		addr16 = (nic->node_addr[4] | (nic->node_addr[5] << 8));
 - 		outw(addr16, BASE + StationAddr + 4);
 - 	}
 - 
 - 	outw(sdc->mtu + 14, BASE + MaxFrameSize);
 - 	if (sdc->mtu > 2047)	/* this will never happen with default options */
 - 		outl(inl(BASE + ASICCtrl) | 0x0c, BASE + ASICCtrl);
 - 
 - 	set_rx_mode(nic);
 - 
 - 	outw(0, BASE + DownCounter);
 - 	/* Set the chip to poll every N*30nsec */
 - 	outb(100, BASE + RxDMAPollPeriod);
 - 
 - 	/* Fix DFE-580TX packet drop issue */
 - 	if (sdc->pci_rev_id >= 0x14)
 - 		writeb(0x01, BASE + DebugCtrl1);
 - 
 - 	outw(RxEnable | TxEnable, BASE + MACCtrl1);
 - 
 - 	/* Construct a perfect filter frame with the mac address as first match
 - 	 * and broadcast for all others */
 - 	for (i = 0; i < 192; i++)
 - 		txb[i] = 0xFF;
 - 
 - 	txb[0] = nic->node_addr[0];
 - 	txb[1] = nic->node_addr[1];
 - 	txb[2] = nic->node_addr[2];
 - 	txb[3] = nic->node_addr[3];
 - 	txb[4] = nic->node_addr[4];
 - 	txb[5] = nic->node_addr[5];
 - 
 - 	DBG ( "%s: Done sundance_reset, status: Rx %hX Tx %hX "
 - 	      "MAC Control %hX, %hX %hX\n",
 - 	      sdc->nic_name, (int) inl(BASE + RxStatus),
 - 	      (int) inw(BASE + TxStatus), (int) inl(BASE + MACCtrl0),
 - 	      (int) inw(BASE + MACCtrl1), (int) inw(BASE + MACCtrl0) );
 - }
 - 
 - /**************************************************************************
 - IRQ - Wait for a frame
 - ***************************************************************************/
 - static void sundance_irq ( struct nic *nic, irq_action_t action ) {
 -         unsigned int intr_status;
 - 
 - 	switch ( action ) {
 - 	case DISABLE :
 - 	case ENABLE :
 - 		intr_status = inw(nic->ioaddr + IntrStatus);
 - 		intr_status = intr_status & ~DEFAULT_INTR;
 - 		if ( action == ENABLE ) 
 - 			intr_status = intr_status | DEFAULT_INTR;
 - 		outw(intr_status, nic->ioaddr + IntrEnable);
 - 		break;
 -         case FORCE :
 - 		outw(0x0200, BASE + ASICCtrl);
 - 		break;
 -         }
 - }
 - /**************************************************************************
 - POLL - Wait for a frame
 - ***************************************************************************/
 - static int sundance_poll(struct nic *nic, int retrieve)
 - {
 - 	/* return true if there's an ethernet packet ready to read */
 - 	/* nic->packet should contain data on return */
 - 	/* nic->packetlen should contain length of data */
 - 	int entry = sdc->cur_rx % RX_RING_SIZE;
 - 	u32 frame_status = le32_to_cpu(rx_ring[entry].status);
 - 	int intr_status;
 - 	int pkt_len = 0;
 - 
 - 	if (!(frame_status & DescOwn))
 - 		return 0;
 - 
 - 	/* There is a packet ready */
 - 	if(!retrieve)
 - 		return 1;
 - 
 - 	intr_status = inw(nic->ioaddr + IntrStatus);
 - 	outw(intr_status, nic->ioaddr + IntrStatus);
 - 
 - 	pkt_len = frame_status & 0x1fff;
 - 
 - 	if (frame_status & 0x001f4000) {
 - 		DBG ( "Polling frame_status error\n" );	/* Do we really care about this */
 - 	} else {
 - 		if (pkt_len < rx_copybreak) {
 - 			/* FIXME: What should happen Will this ever occur */
 - 			printf("Poll Error: pkt_len < rx_copybreak");
 - 		} else {
 - 			nic->packetlen = pkt_len;
 - 			memcpy(nic->packet, rxb +
 - 			       (sdc->cur_rx * PKT_BUF_SZ), nic->packetlen);
 - 
 - 		}
 - 	}
 - 	rx_ring[entry].length = cpu_to_le32(PKT_BUF_SZ | LastFrag);
 - 	rx_ring[entry].status = 0;
 - 	entry++;
 - 	sdc->cur_rx = entry % RX_RING_SIZE;
 - 	outw(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone), 
 - 		nic->ioaddr + IntrStatus);
 - 	return 1;
 - }
 - 
 - /**************************************************************************
 - TRANSMIT - Transmit a frame
 - ***************************************************************************/
 - static void sundance_transmit(struct nic *nic, const char *d,	/* Destination */
 - 			      unsigned int t,	/* Type */
 - 			      unsigned int s,	/* size */
 - 			      const char *p)
 - {				/* Packet */
 - 	u16 nstype;
 - 	u32 to;
 - 
 - 	/* Disable the Tx */
 - 	outw(TxDisable, BASE + MACCtrl1);
 - 
 - 	memcpy(txb, d, ETH_ALEN);
 - 	memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
 - 	nstype = htons((u16) t);
 - 	memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
 - 	memcpy(txb + ETH_HLEN, p, s);
 - 
 - 	s += ETH_HLEN;
 - 	s &= 0x0FFF;
 - 	while (s < ETH_ZLEN)
 - 		txb[s++] = '\0';
 - 
 - 	/* Setup the transmit descriptor */
 - 	tx_ring[0].length = cpu_to_le32(s | LastFrag);
 - 	tx_ring[0].status = cpu_to_le32(0x00000001);
 - 
 - 	/* Point to transmit descriptor */
 - 	outl(virt_to_le32desc(&tx_ring[0]), BASE + TxListPtr);
 - 
 - 	/* Enable Tx */
 - 	outw(TxEnable, BASE + MACCtrl1);
 - 	/* Trigger an immediate send */
 - 	outw(0, BASE + TxStatus);
 - 
 - 	to = currticks() + TX_TIME_OUT;
 - 	while (!(tx_ring[0].status & 0x00010000) && (currticks() < to));	/* wait */
 - 
 - 	if (currticks() >= to) {
 - 		printf("TX Time Out");
 - 	}
 - 	/* Disable Tx */
 - 	outw(TxDisable, BASE + MACCtrl1);
 - 
 - }
 - 
 - /**************************************************************************
 - DISABLE - Turn off ethernet interface
 - ***************************************************************************/
 - static void sundance_disable ( struct nic *nic __unused ) {
 - 	/* put the card in its initial state */
 - 	/* This function serves 3 purposes.
 - 	 * This disables DMA and interrupts so we don't receive
 - 	 *  unexpected packets or interrupts from the card after
 - 	 *  etherboot has finished.
 - 	 * This frees resources so etherboot may use
 - 	 *  this driver on another interface
 - 	 * This allows etherboot to reinitialize the interface
 - 	 *  if something is something goes wrong.
 - 	 */
 - 	outw(0x0000, BASE + IntrEnable);
 - 	/* Stop the Chipchips Tx and Rx Status */
 - 	outw(TxDisable | RxDisable | StatsDisable, BASE + MACCtrl1);
 - }
 - 
 - static struct nic_operations sundance_operations = {
 - 	.connect	= dummy_connect,
 - 	.poll		= sundance_poll,
 - 	.transmit	= sundance_transmit,
 - 	.irq		= sundance_irq,
 - 
 - };
 - 
 - /**************************************************************************
 - PROBE - Look for an adapter, this routine's visible to the outside
 - ***************************************************************************/
 - static int sundance_probe ( struct nic *nic, struct pci_device *pci ) {
 - 
 - 	u8 ee_data[EEPROM_SIZE];
 - 	u16 mii_ctl;
 - 	int i;
 - 	int speed;
 - 
 - 	if (pci->ioaddr == 0)
 - 		return 0;
 - 
 - 	/* BASE is used throughout to address the card */
 - 	BASE = pci->ioaddr;
 - 	printf(" sundance.c: Found %s Vendor=0x%hX Device=0x%hX\n",
 - 	       pci->id->name, pci->vendor, pci->device);
 - 
 - 	/* Get the MAC Address by reading the EEPROM */
 - 	for (i = 0; i < 3; i++) {
 - 		((u16 *) ee_data)[i] =
 - 		    le16_to_cpu(eeprom_read(BASE, i + EEPROM_SA_OFFSET));
 - 	}
 - 	/* Update the nic structure with the MAC Address */
 - 	for (i = 0; i < ETH_ALEN; i++) {
 - 		nic->node_addr[i] = ee_data[i];
 - 	}
 - 
 - 	/* Set the card as PCI Bus Master */
 - 	adjust_pci_device(pci);
 - 
 - //      sdc->mii_if.dev = pci;
 - //      sdc->mii_if.phy_id_mask = 0x1f;
 - //      sdc->mii_if.reg_num_mask = 0x1f;
 - 
 - 	/* point to private storage */
 - 	sdc = &sdx;
 - 
 - 	sdc->nic_name = pci->id->name;
 - 	sdc->mtu = mtu;
 - 
 - 	pci_read_config_byte(pci, PCI_REVISION, &sdc->pci_rev_id);
 - 
 - 	DBG ( "Device revision id: %hx\n", sdc->pci_rev_id );
 - 
 - 	/* Print out some hardware info */
 - 	DBG ( "%s: %s at ioaddr %hX, ",
 - 	      pci->id->name, nic->node_addr, (unsigned int) BASE);
 - 
 - 	sdc->mii_preamble_required = 0;
 - 	if (1) {
 - 		int phy, phy_idx = 0;
 - 		sdc->phys[0] = 1;	/* Default Setting */
 - 		sdc->mii_preamble_required++;
 - 		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
 - 			int mii_status = mdio_read(nic, phy, MII_BMSR);
 - 			if (mii_status != 0xffff && mii_status != 0x0000) {
 - 				sdc->phys[phy_idx++] = phy;
 - 				sdc->mii_if.advertising =
 - 				    mdio_read(nic, phy, MII_ADVERTISE);
 - 				if ((mii_status & 0x0040) == 0)
 - 					sdc->mii_preamble_required++;
 - 				DBG 
 - 				    ( "%s: MII PHY found at address %d, status " "%hX advertising %hX\n", sdc->nic_name, phy, mii_status, sdc->mii_if.advertising );
 - 			}
 - 		}
 - 		sdc->mii_preamble_required--;
 - 		if (phy_idx == 0)
 - 			printf("%s: No MII transceiver found!\n",
 - 			       sdc->nic_name);
 - 		sdc->mii_if.phy_id = sdc->phys[0];
 - 	}
 - 
 - 	/* Parse override configuration */
 - 	sdc->an_enable = 1;
 - 	if (strcasecmp(media, "autosense") != 0) {
 - 		sdc->an_enable = 0;
 - 		if (strcasecmp(media, "100mbps_fd") == 0 ||
 - 		    strcasecmp(media, "4") == 0) {
 - 			sdc->speed = 100;
 - 			sdc->mii_if.full_duplex = 1;
 - 		} else if (strcasecmp(media, "100mbps_hd") == 0
 - 			   || strcasecmp(media, "3") == 0) {
 - 			sdc->speed = 100;
 - 			sdc->mii_if.full_duplex = 0;
 - 		} else if (strcasecmp(media, "10mbps_fd") == 0 ||
 - 			   strcasecmp(media, "2") == 0) {
 - 			sdc->speed = 10;
 - 			sdc->mii_if.full_duplex = 1;
 - 		} else if (strcasecmp(media, "10mbps_hd") == 0 ||
 - 			   strcasecmp(media, "1") == 0) {
 - 			sdc->speed = 10;
 - 			sdc->mii_if.full_duplex = 0;
 - 		} else {
 - 			sdc->an_enable = 1;
 - 		}
 - 	}
 - 	if (flowctrl == 1)
 - 		sdc->flowctrl = 1;
 - 
 - 	/* Fibre PHY? */
 - 	if (inl(BASE + ASICCtrl) & 0x80) {
 - 		/* Default 100Mbps Full */
 - 		if (sdc->an_enable) {
 - 			sdc->speed = 100;
 - 			sdc->mii_if.full_duplex = 1;
 - 			sdc->an_enable = 0;
 - 		}
 - 	}
 - 
 - 	/* The Linux driver uses flow control and resets the link here.  This means the
 - 	   mii section from above would need to be re done I believe.  Since it serves
 - 	   no real purpose leave it out. */
 - 
 - 	/* Force media type */
 - 	if (!sdc->an_enable) {
 - 		mii_ctl = 0;
 - 		mii_ctl |= (sdc->speed == 100) ? BMCR_SPEED100 : 0;
 - 		mii_ctl |= (sdc->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
 - 		mdio_write(nic, sdc->phys[0], MII_BMCR, mii_ctl);
 - 		printf("Override speed=%d, %s duplex\n",
 - 		       sdc->speed,
 - 		       sdc->mii_if.full_duplex ? "Full" : "Half");
 - 	}
 - 
 - 	/* Reset the chip to erase previous misconfiguration */
 - 	DBG ( "ASIC Control is %#x\n", inl(BASE + ASICCtrl) );
 - 	outw(0x007f, BASE + ASICCtrl + 2);
 - 
 - 	/*
 - 	* wait for reset to complete
 - 	* this is heavily inspired by the linux sundance driver
 - 	* according to the linux driver it can take up to 1ms for the reset
 - 	* to complete
 - 	*/
 - 	i = 0;
 - 	while(inl(BASE + ASICCtrl) & (ResetBusy << 16)) {
 - 		if(i++ >= 10) {
 - 			DBG("sundance: NIC reset did not complete.\n");
 - 			break;
 - 		}
 - 		udelay(100);
 - 	}
 - 
 - 	DBG ( "ASIC Control is now %#x.\n", inl(BASE + ASICCtrl) );
 - 
 - 	sundance_reset(nic);
 - 	if (sdc->an_enable) {
 - 		u16 mii_advertise, mii_lpa;
 - 		mii_advertise =
 - 		    mdio_read(nic, sdc->phys[0], MII_ADVERTISE);
 - 		mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA);
 - 		mii_advertise &= mii_lpa;
 - 		if (mii_advertise & ADVERTISE_100FULL)
 - 			sdc->speed = 100;
 - 		else if (mii_advertise & ADVERTISE_100HALF)
 - 			sdc->speed = 100;
 - 		else if (mii_advertise & ADVERTISE_10FULL)
 - 			sdc->speed = 10;
 - 		else if (mii_advertise & ADVERTISE_10HALF)
 - 			sdc->speed = 10;
 - 	} else {
 - 		mii_ctl = mdio_read(nic, sdc->phys[0], MII_BMCR);
 - 		speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
 - 		sdc->speed = speed;
 - 		printf("%s: Link changed: %dMbps ,", sdc->nic_name, speed);
 - 		printf("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
 - 		       "full" : "half");
 - 	}
 - 	check_duplex(nic);
 - 	if (sdc->flowctrl && sdc->mii_if.full_duplex) {
 - 		outw(inw(BASE + MulticastFilter1 + 2) | 0x0200,
 - 		     BASE + MulticastFilter1 + 2);
 - 		outw(inw(BASE + MACCtrl0) | EnbFlowCtrl, BASE + MACCtrl0);
 - 	}
 - 	printf("%dMbps, %s-Duplex\n", sdc->speed,
 - 	       sdc->mii_if.full_duplex ? "Full" : "Half");
 - 
 - 	/* point to NIC specific routines */
 - 	nic->nic_op	= &sundance_operations;
 - 
 - 	nic->irqno  = pci->irq;
 - 	nic->ioaddr = BASE;
 - 
 - 	return 1;
 - }
 - 
 - 
 - /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
 - static int eeprom_read(long ioaddr, int location)
 - {
 - 	int boguscnt = 10000;	/* Typical 1900 ticks */
 - 	outw(0x0200 | (location & 0xff), ioaddr + EECtrl);
 - 	do {
 - 		if (!(inw(ioaddr + EECtrl) & 0x8000)) {
 - 			return inw(ioaddr + EEData);
 - 		}
 - 	}
 - 	while (--boguscnt > 0);
 - 	return 0;
 - }
 - 
 - /*  MII transceiver control section.
 - 	Read and write the MII registers using software-generated serial
 - 	MDIO protocol.  See the MII specifications or DP83840A data sheet
 - 	for details.
 - 
 - 	The maximum data clock rate is 2.5 Mhz.
 - 	The timing is decoupled from the processor clock by flushing the write
 - 	from the CPU write buffer with a following read, and using PCI
 - 	transaction time. */
 - 
 - #define mdio_in(mdio_addr) inb(mdio_addr)
 - #define mdio_out(value, mdio_addr) outb(value, mdio_addr)
 - #define mdio_delay(mdio_addr) inb(mdio_addr)
 - 
 - enum mii_reg_bits {
 - 	MDIO_ShiftClk = 0x0001, MDIO_Data = 0x0002, MDIO_EnbOutput =
 - 	    0x0004,
 - };
 - #define MDIO_EnbIn  (0)
 - #define MDIO_WRITE0 (MDIO_EnbOutput)
 - #define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
 - 
 - /* Generate the preamble required for initial synchronization and
 -    a few older transceivers. */
 - static void mdio_sync(long mdio_addr)
 - {
 - 	int bits = 32;
 - 
 - 	/* Establish sync by sending at least 32 logic ones. */
 - 	while (--bits >= 0) {
 - 		mdio_out(MDIO_WRITE1, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 		mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 	}
 - }
 - 
 - static int
 - mdio_read(struct nic *nic __unused, int phy_id, unsigned int location)
 - {
 - 	long mdio_addr = BASE + MIICtrl;
 - 	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 - 	int i, retval = 0;
 - 
 - 	if (sdc->mii_preamble_required)
 - 		mdio_sync(mdio_addr);
 - 
 - 	/* Shift the read command bits out. */
 - 	for (i = 15; i >= 0; i--) {
 - 		int dataval =
 - 		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
 - 
 - 		mdio_out(dataval, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 	}
 - 	/* Read the two transition, 16 data, and wire-idle bits. */
 - 	for (i = 19; i > 0; i--) {
 - 		mdio_out(MDIO_EnbIn, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 		retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data)
 - 					  ? 1 : 0);
 - 		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 	}
 - 	return (retval >> 1) & 0xffff;
 - }
 - 
 - static void
 - mdio_write(struct nic *nic __unused, int phy_id,
 - 	   unsigned int location, int value)
 - {
 - 	long mdio_addr = BASE + MIICtrl;
 - 	int mii_cmd =
 - 	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
 - 	int i;
 - 
 - 	if (sdc->mii_preamble_required)
 - 		mdio_sync(mdio_addr);
 - 
 - 	/* Shift the command bits out. */
 - 	for (i = 31; i >= 0; i--) {
 - 		int dataval =
 - 		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
 - 		mdio_out(dataval, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 	}
 - 	/* Clear out extra bits. */
 - 	for (i = 2; i > 0; i--) {
 - 		mdio_out(MDIO_EnbIn, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
 - 		mdio_delay(mdio_addr);
 - 	}
 - 	return;
 - }
 - 
 - static void set_rx_mode(struct nic *nic __unused)
 - {
 - 	int i;
 - 	u16 mc_filter[4];	/* Multicast hash filter */
 - 	u32 rx_mode;
 - 
 - 	memset(mc_filter, 0xff, sizeof(mc_filter));
 - 	rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
 - 
 - 	if (sdc->mii_if.full_duplex && sdc->flowctrl)
 - 		mc_filter[3] |= 0x0200;
 - 	for (i = 0; i < 4; i++)
 - 		outw(mc_filter[i], BASE + MulticastFilter0 + i * 2);
 - 	outb(rx_mode, BASE + RxMode);
 - 	return;
 - }
 - 
 - static struct pci_device_id sundance_nics[] = {
 - 	PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor", 0),
 - 	PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)", 0),
 - 	PCI_ROM(0x13f0, 0x0200, "ip100a", "IC+ IP100A", 0),
 - };
 - 
 - PCI_DRIVER ( sundance_driver, sundance_nics, PCI_NO_CLASS );
 - 
 - DRIVER ( "SUNDANCE/PCI", nic_driver, pci_driver, sundance_driver,
 - 	 sundance_probe, sundance_disable );
 - 
 - /*
 -  * Local variables:
 -  *  c-basic-offset: 8
 -  *  c-indent-level: 8
 -  *  tab-width: 8
 -  * End:
 -  */
 
 
  |