17c478bd9Sstevel@tonic-gate /**************************************************************************
27c478bd9Sstevel@tonic-gate *
37c478bd9Sstevel@tonic-gate *    sundance.c -- Etherboot device driver for the Sundance ST201 "Alta".
47c478bd9Sstevel@tonic-gate *    Written 2002-2002 by Timothy Legge <tlegge@rogers.com>
57c478bd9Sstevel@tonic-gate *
67c478bd9Sstevel@tonic-gate *    This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate *    it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate *    the Free Software Foundation; either version 2 of the License, or
97c478bd9Sstevel@tonic-gate *    (at your option) any later version.
107c478bd9Sstevel@tonic-gate *
117c478bd9Sstevel@tonic-gate *    This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate *    but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate *    GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate *
167c478bd9Sstevel@tonic-gate *    You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate *    along with this program; if not, write to the Free Software
187c478bd9Sstevel@tonic-gate *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate *    Portions of this code based on:
217c478bd9Sstevel@tonic-gate *               sundance.c: A Linux device driver for the Sundance ST201 "Alta"
227c478bd9Sstevel@tonic-gate *               Written 1999-2002 by Donald Becker
237c478bd9Sstevel@tonic-gate *
247c478bd9Sstevel@tonic-gate *               tulip.c: Tulip and Clone Etherboot Driver
257c478bd9Sstevel@tonic-gate *               By Marty Conner
267c478bd9Sstevel@tonic-gate *               Copyright (C) 2001 Entity Cyber, Inc.
277c478bd9Sstevel@tonic-gate *
287c478bd9Sstevel@tonic-gate *    Linux Driver Version LK1.09a, 10-Jul-2003 (2.4.25)
297c478bd9Sstevel@tonic-gate *
307c478bd9Sstevel@tonic-gate *    REVISION HISTORY:
317c478bd9Sstevel@tonic-gate *    ================
327c478bd9Sstevel@tonic-gate *    v1.1	01-01-2003	timlegge	Initial implementation
337c478bd9Sstevel@tonic-gate *    v1.7	04-10-2003	timlegge	Transfers Linux Kernel (30 sec)
347c478bd9Sstevel@tonic-gate *    v1.8	04-13-2003	timlegge	Fix multiple transmission bug
357c478bd9Sstevel@tonic-gate *    v1.9	08-19-2003	timlegge	Support Multicast
367c478bd9Sstevel@tonic-gate *    v1.10	01-17-2004	timlegge	Initial driver output cleanup
377c478bd9Sstevel@tonic-gate *    v1.11	03-21-2004	timlegge	Remove unused variables
387c478bd9Sstevel@tonic-gate *    v1.12	03-21-2004	timlegge	Remove excess MII defines
397c478bd9Sstevel@tonic-gate *    v1.13	03-24-2004	timlegge	Update to Linux 2.4.25 driver
407c478bd9Sstevel@tonic-gate *
417c478bd9Sstevel@tonic-gate ****************************************************************************/
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* to get some global routines like printf */
447c478bd9Sstevel@tonic-gate #include "etherboot.h"
457c478bd9Sstevel@tonic-gate /* to get the interface to the body of the program */
467c478bd9Sstevel@tonic-gate #include "nic.h"
477c478bd9Sstevel@tonic-gate /* to get the PCI support functions, if this is a PCI NIC */
487c478bd9Sstevel@tonic-gate #include "pci.h"
497c478bd9Sstevel@tonic-gate #include "timer.h"
507c478bd9Sstevel@tonic-gate #include "mii.h"
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define drv_version "v1.12"
537c478bd9Sstevel@tonic-gate #define drv_date "2004-03-21"
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate typedef unsigned char u8;
567c478bd9Sstevel@tonic-gate typedef signed char s8;
577c478bd9Sstevel@tonic-gate typedef unsigned short u16;
587c478bd9Sstevel@tonic-gate typedef signed short s16;
597c478bd9Sstevel@tonic-gate typedef unsigned int u32;
607c478bd9Sstevel@tonic-gate typedef signed int s32;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #define HZ 100
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /* Condensed operations for readability. */
657c478bd9Sstevel@tonic-gate #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
667c478bd9Sstevel@tonic-gate #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /* May need to be moved to mii.h */
697c478bd9Sstevel@tonic-gate struct mii_if_info {
707c478bd9Sstevel@tonic-gate 	int phy_id;
717c478bd9Sstevel@tonic-gate 	int advertising;
727c478bd9Sstevel@tonic-gate 	unsigned int full_duplex:1;	/* is full duplex? */
737c478bd9Sstevel@tonic-gate };
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate //#define EDEBUG
767c478bd9Sstevel@tonic-gate #ifdef EDEBUG
777c478bd9Sstevel@tonic-gate #define dprintf(x) printf x
787c478bd9Sstevel@tonic-gate #else
797c478bd9Sstevel@tonic-gate #define dprintf(x)
807c478bd9Sstevel@tonic-gate #endif
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate #if defined(__sun)
837c478bd9Sstevel@tonic-gate /* Hack: use grub_strcmp since strcasecmp is undefined */
847c478bd9Sstevel@tonic-gate #define strcasecmp grub_strcmp
857c478bd9Sstevel@tonic-gate #endif
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /* Set the mtu */
897c478bd9Sstevel@tonic-gate static int mtu = 1514;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
927c478bd9Sstevel@tonic-gate    The sundance uses a 64 element hash table based on the Ethernet CRC.  */
937c478bd9Sstevel@tonic-gate // static int multicast_filter_limit = 32;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
967c478bd9Sstevel@tonic-gate    Setting to > 1518 effectively disables this feature.
977c478bd9Sstevel@tonic-gate    This chip can receive into any byte alignment buffers, so word-oriented
987c478bd9Sstevel@tonic-gate    archs do not need a copy-align of the IP header. */
997c478bd9Sstevel@tonic-gate static int rx_copybreak = 0;
1007c478bd9Sstevel@tonic-gate static int flowctrl = 1;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /* Allow forcing the media type */
1037c478bd9Sstevel@tonic-gate /* media[] specifies the media type the NIC operates at.
1047c478bd9Sstevel@tonic-gate 		 autosense	Autosensing active media.
1057c478bd9Sstevel@tonic-gate 		 10mbps_hd 	10Mbps half duplex.
1067c478bd9Sstevel@tonic-gate 		 10mbps_fd 	10Mbps full duplex.
1077c478bd9Sstevel@tonic-gate 		 100mbps_hd 	100Mbps half duplex.
1087c478bd9Sstevel@tonic-gate 		 100mbps_fd 	100Mbps full duplex.
1097c478bd9Sstevel@tonic-gate */
1107c478bd9Sstevel@tonic-gate static char media[] = "autosense";
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /* Operational parameters that are set at compile time. */
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* As Etherboot uses a Polling driver  we can keep the number of rings
1157c478bd9Sstevel@tonic-gate to the minimum number required.  In general that is 1 transmit and 4 receive receive rings.  However some cards require that
1167c478bd9Sstevel@tonic-gate there be a minimum of 2 rings  */
1177c478bd9Sstevel@tonic-gate #define TX_RING_SIZE	2
1187c478bd9Sstevel@tonic-gate #define TX_QUEUE_LEN	10	/* Limit ring entries actually used.  */
1197c478bd9Sstevel@tonic-gate #define RX_RING_SIZE	4
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /* Operational parameters that usually are not changed. */
1237c478bd9Sstevel@tonic-gate /* Time in jiffies before concluding the transmitter is hung. */
1247c478bd9Sstevel@tonic-gate #define TX_TIME_OUT	  (4*HZ)
1257c478bd9Sstevel@tonic-gate #define PKT_BUF_SZ	1536
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /* Offsets to the device registers.
1287c478bd9Sstevel@tonic-gate    Unlike software-only systems, device drivers interact with complex hardware.
1297c478bd9Sstevel@tonic-gate    It's not useful to define symbolic names for every register bit in the
1307c478bd9Sstevel@tonic-gate    device.  The name can only partially document the semantics and make
1317c478bd9Sstevel@tonic-gate    the driver longer and more difficult to read.
1327c478bd9Sstevel@tonic-gate    In general, only the important configuration values or bits changed
1337c478bd9Sstevel@tonic-gate    multiple times should be defined symbolically.
1347c478bd9Sstevel@tonic-gate */
1357c478bd9Sstevel@tonic-gate enum alta_offsets {
1367c478bd9Sstevel@tonic-gate 	DMACtrl = 0x00,
1377c478bd9Sstevel@tonic-gate 	TxListPtr = 0x04,
1387c478bd9Sstevel@tonic-gate 	TxDMABurstThresh = 0x08,
1397c478bd9Sstevel@tonic-gate 	TxDMAUrgentThresh = 0x09,
1407c478bd9Sstevel@tonic-gate 	TxDMAPollPeriod = 0x0a,
1417c478bd9Sstevel@tonic-gate 	RxDMAStatus = 0x0c,
1427c478bd9Sstevel@tonic-gate 	RxListPtr = 0x10,
1437c478bd9Sstevel@tonic-gate 	DebugCtrl0 = 0x1a,
1447c478bd9Sstevel@tonic-gate 	DebugCtrl1 = 0x1c,
1457c478bd9Sstevel@tonic-gate 	RxDMABurstThresh = 0x14,
1467c478bd9Sstevel@tonic-gate 	RxDMAUrgentThresh = 0x15,
1477c478bd9Sstevel@tonic-gate 	RxDMAPollPeriod = 0x16,
1487c478bd9Sstevel@tonic-gate 	LEDCtrl = 0x1a,
1497c478bd9Sstevel@tonic-gate 	ASICCtrl = 0x30,
1507c478bd9Sstevel@tonic-gate 	EEData = 0x34,
1517c478bd9Sstevel@tonic-gate 	EECtrl = 0x36,
1527c478bd9Sstevel@tonic-gate 	TxStartThresh = 0x3c,
1537c478bd9Sstevel@tonic-gate 	RxEarlyThresh = 0x3e,
1547c478bd9Sstevel@tonic-gate 	FlashAddr = 0x40,
1557c478bd9Sstevel@tonic-gate 	FlashData = 0x44,
1567c478bd9Sstevel@tonic-gate 	TxStatus = 0x46,
1577c478bd9Sstevel@tonic-gate 	TxFrameId = 0x47,
1587c478bd9Sstevel@tonic-gate 	DownCounter = 0x18,
1597c478bd9Sstevel@tonic-gate 	IntrClear = 0x4a,
1607c478bd9Sstevel@tonic-gate 	IntrEnable = 0x4c,
1617c478bd9Sstevel@tonic-gate 	IntrStatus = 0x4e,
1627c478bd9Sstevel@tonic-gate 	MACCtrl0 = 0x50,
1637c478bd9Sstevel@tonic-gate 	MACCtrl1 = 0x52,
1647c478bd9Sstevel@tonic-gate 	StationAddr = 0x54,
1657c478bd9Sstevel@tonic-gate 	MaxFrameSize = 0x5A,
1667c478bd9Sstevel@tonic-gate 	RxMode = 0x5c,
1677c478bd9Sstevel@tonic-gate 	MIICtrl = 0x5e,
1687c478bd9Sstevel@tonic-gate 	MulticastFilter0 = 0x60,
1697c478bd9Sstevel@tonic-gate 	MulticastFilter1 = 0x64,
1707c478bd9Sstevel@tonic-gate 	RxOctetsLow = 0x68,
1717c478bd9Sstevel@tonic-gate 	RxOctetsHigh = 0x6a,
1727c478bd9Sstevel@tonic-gate 	TxOctetsLow = 0x6c,
1737c478bd9Sstevel@tonic-gate 	TxOctetsHigh = 0x6e,
1747c478bd9Sstevel@tonic-gate 	TxFramesOK = 0x70,
1757c478bd9Sstevel@tonic-gate 	RxFramesOK = 0x72,
1767c478bd9Sstevel@tonic-gate 	StatsCarrierError = 0x74,
1777c478bd9Sstevel@tonic-gate 	StatsLateColl = 0x75,
1787c478bd9Sstevel@tonic-gate 	StatsMultiColl = 0x76,
1797c478bd9Sstevel@tonic-gate 	StatsOneColl = 0x77,
1807c478bd9Sstevel@tonic-gate 	StatsTxDefer = 0x78,
1817c478bd9Sstevel@tonic-gate 	RxMissed = 0x79,
1827c478bd9Sstevel@tonic-gate 	StatsTxXSDefer = 0x7a,
1837c478bd9Sstevel@tonic-gate 	StatsTxAbort = 0x7b,
1847c478bd9Sstevel@tonic-gate 	StatsBcastTx = 0x7c,
1857c478bd9Sstevel@tonic-gate 	StatsBcastRx = 0x7d,
1867c478bd9Sstevel@tonic-gate 	StatsMcastTx = 0x7e,
1877c478bd9Sstevel@tonic-gate 	StatsMcastRx = 0x7f,
1887c478bd9Sstevel@tonic-gate 	/* Aliased and bogus values! */
1897c478bd9Sstevel@tonic-gate 	RxStatus = 0x0c,
1907c478bd9Sstevel@tonic-gate };
1917c478bd9Sstevel@tonic-gate enum ASICCtrl_HiWord_bit {
1927c478bd9Sstevel@tonic-gate 	GlobalReset = 0x0001,
1937c478bd9Sstevel@tonic-gate 	RxReset = 0x0002,
1947c478bd9Sstevel@tonic-gate 	TxReset = 0x0004,
1957c478bd9Sstevel@tonic-gate 	DMAReset = 0x0008,
1967c478bd9Sstevel@tonic-gate 	FIFOReset = 0x0010,
1977c478bd9Sstevel@tonic-gate 	NetworkReset = 0x0020,
1987c478bd9Sstevel@tonic-gate 	HostReset = 0x0040,
1997c478bd9Sstevel@tonic-gate 	ResetBusy = 0x0400,
2007c478bd9Sstevel@tonic-gate };
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /* Bits in the interrupt status/mask registers. */
2037c478bd9Sstevel@tonic-gate enum intr_status_bits {
2047c478bd9Sstevel@tonic-gate 	IntrSummary = 0x0001, IntrPCIErr = 0x0002, IntrMACCtrl = 0x0008,
2057c478bd9Sstevel@tonic-gate 	IntrTxDone = 0x0004, IntrRxDone = 0x0010, IntrRxStart = 0x0020,
2067c478bd9Sstevel@tonic-gate 	IntrDrvRqst = 0x0040,
2077c478bd9Sstevel@tonic-gate 	StatsMax = 0x0080, LinkChange = 0x0100,
2087c478bd9Sstevel@tonic-gate 	IntrTxDMADone = 0x0200, IntrRxDMADone = 0x0400,
2097c478bd9Sstevel@tonic-gate };
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /* Bits in the RxMode register. */
2127c478bd9Sstevel@tonic-gate enum rx_mode_bits {
2137c478bd9Sstevel@tonic-gate 	AcceptAllIPMulti = 0x20, AcceptMultiHash = 0x10, AcceptAll = 0x08,
2147c478bd9Sstevel@tonic-gate 	AcceptBroadcast = 0x04, AcceptMulticast = 0x02, AcceptMyPhys =
2157c478bd9Sstevel@tonic-gate 	    0x01,
2167c478bd9Sstevel@tonic-gate };
2177c478bd9Sstevel@tonic-gate /* Bits in MACCtrl. */
2187c478bd9Sstevel@tonic-gate enum mac_ctrl0_bits {
2197c478bd9Sstevel@tonic-gate 	EnbFullDuplex = 0x20, EnbRcvLargeFrame = 0x40,
2207c478bd9Sstevel@tonic-gate 	EnbFlowCtrl = 0x100, EnbPassRxCRC = 0x200,
2217c478bd9Sstevel@tonic-gate };
2227c478bd9Sstevel@tonic-gate enum mac_ctrl1_bits {
2237c478bd9Sstevel@tonic-gate 	StatsEnable = 0x0020, StatsDisable = 0x0040, StatsEnabled = 0x0080,
2247c478bd9Sstevel@tonic-gate 	TxEnable = 0x0100, TxDisable = 0x0200, TxEnabled = 0x0400,
2257c478bd9Sstevel@tonic-gate 	RxEnable = 0x0800, RxDisable = 0x1000, RxEnabled = 0x2000,
2267c478bd9Sstevel@tonic-gate };
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate /* The Rx and Tx buffer descriptors.
2297c478bd9Sstevel@tonic-gate    Using only 32 bit fields simplifies software endian correction.
2307c478bd9Sstevel@tonic-gate    This structure must be aligned, and should avoid spanning cache lines.
2317c478bd9Sstevel@tonic-gate */
2327c478bd9Sstevel@tonic-gate struct netdev_desc {
2337c478bd9Sstevel@tonic-gate 	u32 next_desc;
2347c478bd9Sstevel@tonic-gate 	u32 status;
2357c478bd9Sstevel@tonic-gate 	u32 addr;
2367c478bd9Sstevel@tonic-gate 	u32 length;
2377c478bd9Sstevel@tonic-gate };
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate /* Bits in netdev_desc.status */
2407c478bd9Sstevel@tonic-gate enum desc_status_bits {
2417c478bd9Sstevel@tonic-gate 	DescOwn = 0x8000,
2427c478bd9Sstevel@tonic-gate 	DescEndPacket = 0x4000,
2437c478bd9Sstevel@tonic-gate 	DescEndRing = 0x2000,
2447c478bd9Sstevel@tonic-gate 	LastFrag = 0x80000000,
2457c478bd9Sstevel@tonic-gate 	DescIntrOnTx = 0x8000,
2467c478bd9Sstevel@tonic-gate 	DescIntrOnDMADone = 0x80000000,
2477c478bd9Sstevel@tonic-gate 	DisableAlign = 0x00000001,
2487c478bd9Sstevel@tonic-gate };
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate /**********************************************
2517c478bd9Sstevel@tonic-gate * Descriptor Ring and Buffer defination
2527c478bd9Sstevel@tonic-gate ***********************************************/
2537c478bd9Sstevel@tonic-gate /* Define the TX Descriptor */
2547c478bd9Sstevel@tonic-gate static struct netdev_desc tx_ring[TX_RING_SIZE];
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /* Create a static buffer of size PKT_BUF_SZ for each TX Descriptor.
2577c478bd9Sstevel@tonic-gate   All descriptors point to a part of this buffer */
2587c478bd9Sstevel@tonic-gate static unsigned char txb[PKT_BUF_SZ * TX_RING_SIZE];
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate /* Define the RX Descriptor */
2617c478bd9Sstevel@tonic-gate static struct netdev_desc rx_ring[RX_RING_SIZE];
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate /* Create a static buffer of size PKT_BUF_SZ for each RX Descriptor.
2647c478bd9Sstevel@tonic-gate    All descriptors point to a part of this buffer */
2657c478bd9Sstevel@tonic-gate static unsigned char rxb[RX_RING_SIZE * PKT_BUF_SZ];
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate /* FIXME: Move BASE to the private structure */
2687c478bd9Sstevel@tonic-gate static u32 BASE;
2697c478bd9Sstevel@tonic-gate #define EEPROM_SIZE	128
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate enum pci_id_flags_bits {
2727c478bd9Sstevel@tonic-gate 	PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4,
2737c478bd9Sstevel@tonic-gate 	PCI_ADDR0 = 0 << 4, PCI_ADDR1 = 1 << 4, PCI_ADDR2 =
2747c478bd9Sstevel@tonic-gate 	    2 << 4, PCI_ADDR3 = 3 << 4,
2757c478bd9Sstevel@tonic-gate };
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate enum chip_capability_flags { CanHaveMII = 1, KendinPktDropBug = 2, };
2787c478bd9Sstevel@tonic-gate #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate #define MII_CNT		4
2817c478bd9Sstevel@tonic-gate struct sundance_private {
2827c478bd9Sstevel@tonic-gate 	const char *nic_name;
2837c478bd9Sstevel@tonic-gate 	/* Frequently used values */
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	unsigned int cur_rx;	/* Producer/consumer ring indicies */
2867c478bd9Sstevel@tonic-gate 	unsigned int mtu;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	/* These values keep track of the tranceiver/media in use */
2897c478bd9Sstevel@tonic-gate 	unsigned int flowctrl:1;
2907c478bd9Sstevel@tonic-gate 	unsigned int an_enable:1;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	unsigned int speed;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* MII tranceiver section */
2957c478bd9Sstevel@tonic-gate 	struct mii_if_info mii_if;
2967c478bd9Sstevel@tonic-gate 	int mii_preamble_required;
2977c478bd9Sstevel@tonic-gate 	unsigned char phys[MII_CNT];
2987c478bd9Sstevel@tonic-gate 	unsigned char pci_rev_id;
2997c478bd9Sstevel@tonic-gate } sdx;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate static struct sundance_private *sdc;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /* Station Address location within the EEPROM */
3047c478bd9Sstevel@tonic-gate #define EEPROM_SA_OFFSET	0x10
3057c478bd9Sstevel@tonic-gate #define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
3067c478bd9Sstevel@tonic-gate                         IntrDrvRqst | IntrTxDone | StatsMax | \
3077c478bd9Sstevel@tonic-gate                         LinkChange)
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate static int eeprom_read(long ioaddr, int location);
3107c478bd9Sstevel@tonic-gate static int mdio_read(struct nic *nic, int phy_id, unsigned int location);
3117c478bd9Sstevel@tonic-gate static void mdio_write(struct nic *nic, int phy_id, unsigned int location,
3127c478bd9Sstevel@tonic-gate 		       int value);
3137c478bd9Sstevel@tonic-gate static void set_rx_mode(struct nic *nic);
3147c478bd9Sstevel@tonic-gate 
check_duplex(struct nic * nic)3157c478bd9Sstevel@tonic-gate static void check_duplex(struct nic *nic)
3167c478bd9Sstevel@tonic-gate {
3177c478bd9Sstevel@tonic-gate 	int mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA);
3187c478bd9Sstevel@tonic-gate 	int negotiated = mii_lpa & sdc->mii_if.advertising;
3197c478bd9Sstevel@tonic-gate 	int duplex;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* Force media */
3227c478bd9Sstevel@tonic-gate 	if (!sdc->an_enable || mii_lpa == 0xffff) {
3237c478bd9Sstevel@tonic-gate 		if (sdc->mii_if.full_duplex)
3247c478bd9Sstevel@tonic-gate 			outw(inw(BASE + MACCtrl0) | EnbFullDuplex,
3257c478bd9Sstevel@tonic-gate 			     BASE + MACCtrl0);
3267c478bd9Sstevel@tonic-gate 		return;
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	/* Autonegotiation */
3307c478bd9Sstevel@tonic-gate 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
3317c478bd9Sstevel@tonic-gate 	if (sdc->mii_if.full_duplex != duplex) {
3327c478bd9Sstevel@tonic-gate 		sdc->mii_if.full_duplex = duplex;
3337c478bd9Sstevel@tonic-gate 		dprintf(("%s: Setting %s-duplex based on MII #%d "
3347c478bd9Sstevel@tonic-gate 			 "negotiated capability %4.4x.\n", sdc->nic_name,
3357c478bd9Sstevel@tonic-gate 			 duplex ? "full" : "half", sdc->phys[0],
3367c478bd9Sstevel@tonic-gate 			 negotiated));
3377c478bd9Sstevel@tonic-gate 		outw(inw(BASE + MACCtrl0) | duplex ? 0x20 : 0,
3387c478bd9Sstevel@tonic-gate 		     BASE + MACCtrl0);
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate /**************************************************************************
3447c478bd9Sstevel@tonic-gate  *  init_ring - setup the tx and rx descriptors
3457c478bd9Sstevel@tonic-gate  *************************************************************************/
init_ring(struct nic * nic __unused)3467c478bd9Sstevel@tonic-gate static void init_ring(struct nic *nic __unused)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 	int i;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	sdc->cur_rx = 0;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/* Initialize all the Rx descriptors */
3537c478bd9Sstevel@tonic-gate 	for (i = 0; i < RX_RING_SIZE; i++) {
3547c478bd9Sstevel@tonic-gate 		rx_ring[i].next_desc = virt_to_le32desc(&rx_ring[i + 1]);
3557c478bd9Sstevel@tonic-gate 		rx_ring[i].status = 0;
3567c478bd9Sstevel@tonic-gate 		rx_ring[i].length = 0;
3577c478bd9Sstevel@tonic-gate 		rx_ring[i].addr = 0;
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* Mark the last entry as wrapping the ring */
3617c478bd9Sstevel@tonic-gate 	rx_ring[i - 1].next_desc = virt_to_le32desc(&rx_ring[0]);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	for (i = 0; i < RX_RING_SIZE; i++) {
3647c478bd9Sstevel@tonic-gate 		rx_ring[i].addr = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
3657c478bd9Sstevel@tonic-gate 		rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LastFrag);
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	/* We only use one transmit buffer, but two
3697c478bd9Sstevel@tonic-gate 	 * descriptors so transmit engines have somewhere
3707c478bd9Sstevel@tonic-gate 	 * to point should they feel the need */
3717c478bd9Sstevel@tonic-gate 	tx_ring[0].status = 0x00000000;
3727c478bd9Sstevel@tonic-gate 	tx_ring[0].addr = virt_to_bus(&txb[0]);
3737c478bd9Sstevel@tonic-gate 	tx_ring[0].next_desc = 0;	/* virt_to_bus(&tx_ring[1]); */
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	/* This descriptor is never used */
3767c478bd9Sstevel@tonic-gate 	tx_ring[1].status = 0x00000000;
3777c478bd9Sstevel@tonic-gate 	tx_ring[1].addr = 0;	/*virt_to_bus(&txb[0]); */
3787c478bd9Sstevel@tonic-gate 	tx_ring[1].next_desc = 0;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	/* Mark the last entry as wrapping the ring,
3817c478bd9Sstevel@tonic-gate 	 * though this should never happen */
3827c478bd9Sstevel@tonic-gate 	tx_ring[1].length = cpu_to_le32(LastFrag | PKT_BUF_SZ);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /**************************************************************************
3867c478bd9Sstevel@tonic-gate  *  RESET - Reset Adapter
3877c478bd9Sstevel@tonic-gate  * ***********************************************************************/
sundance_reset(struct nic * nic)3887c478bd9Sstevel@tonic-gate static void sundance_reset(struct nic *nic)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	int i;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	init_ring(nic);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	outl(virt_to_le32desc(&rx_ring[0]), BASE + RxListPtr);
3957c478bd9Sstevel@tonic-gate 	/* The Tx List Pointer is written as packets are queued */
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/* Initialize other registers. */
3987c478bd9Sstevel@tonic-gate 	/* __set_mac_addr(dev); */
3997c478bd9Sstevel@tonic-gate 	{
4007c478bd9Sstevel@tonic-gate 		u16 addr16;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		addr16 = (nic->node_addr[0] | (nic->node_addr[1] << 8));
4037c478bd9Sstevel@tonic-gate 		outw(addr16, BASE + StationAddr);
4047c478bd9Sstevel@tonic-gate 		addr16 = (nic->node_addr[2] | (nic->node_addr[3] << 8));
4057c478bd9Sstevel@tonic-gate 		outw(addr16, BASE + StationAddr + 2);
4067c478bd9Sstevel@tonic-gate 		addr16 = (nic->node_addr[4] | (nic->node_addr[5] << 8));
4077c478bd9Sstevel@tonic-gate 		outw(addr16, BASE + StationAddr + 4);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	outw(sdc->mtu + 14, BASE + MaxFrameSize);
4117c478bd9Sstevel@tonic-gate 	if (sdc->mtu > 2047)	/* this will never happen with default options */
4127c478bd9Sstevel@tonic-gate 		outl(inl(BASE + ASICCtrl) | 0x0c, BASE + ASICCtrl);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	set_rx_mode(nic);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	outw(0, BASE + DownCounter);
4177c478bd9Sstevel@tonic-gate 	/* Set the chip to poll every N*30nsec */
4187c478bd9Sstevel@tonic-gate 	outb(100, BASE + RxDMAPollPeriod);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	/* Fix DFE-580TX packet drop issue */
4217c478bd9Sstevel@tonic-gate 	if (sdc->pci_rev_id >= 0x14)
4227c478bd9Sstevel@tonic-gate 		writeb(0x01, BASE + DebugCtrl1);
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	outw(RxEnable | TxEnable, BASE + MACCtrl1);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	/* Construct a perfect filter frame with the mac address as first match
4277c478bd9Sstevel@tonic-gate 	 * and broadcast for all others */
4287c478bd9Sstevel@tonic-gate 	for (i = 0; i < 192; i++)
4297c478bd9Sstevel@tonic-gate 		txb[i] = 0xFF;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	txb[0] = nic->node_addr[0];
4327c478bd9Sstevel@tonic-gate 	txb[1] = nic->node_addr[1];
4337c478bd9Sstevel@tonic-gate 	txb[2] = nic->node_addr[2];
4347c478bd9Sstevel@tonic-gate 	txb[3] = nic->node_addr[3];
4357c478bd9Sstevel@tonic-gate 	txb[4] = nic->node_addr[4];
4367c478bd9Sstevel@tonic-gate 	txb[5] = nic->node_addr[5];
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	dprintf(("%s: Done sundance_reset, status: Rx %hX Tx %hX "
4397c478bd9Sstevel@tonic-gate 		 "MAC Control %hX, %hX %hX\n",
4407c478bd9Sstevel@tonic-gate 		 sdc->nic_name, (int) inl(BASE + RxStatus),
4417c478bd9Sstevel@tonic-gate 		 (int) inw(BASE + TxStatus), (int) inl(BASE + MACCtrl0),
4427c478bd9Sstevel@tonic-gate 		 (int) inw(BASE + MACCtrl1), (int) inw(BASE + MACCtrl0)));
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate /**************************************************************************
4467c478bd9Sstevel@tonic-gate IRQ - Wait for a frame
4477c478bd9Sstevel@tonic-gate ***************************************************************************/
sundance_irq(struct nic * nic,irq_action_t action)4487c478bd9Sstevel@tonic-gate void sundance_irq ( struct nic *nic, irq_action_t action ) {
4497c478bd9Sstevel@tonic-gate         unsigned int intr_status;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	switch ( action ) {
4527c478bd9Sstevel@tonic-gate 	case DISABLE :
4537c478bd9Sstevel@tonic-gate 	case ENABLE :
4547c478bd9Sstevel@tonic-gate 		intr_status = inw(nic->ioaddr + IntrStatus);
4557c478bd9Sstevel@tonic-gate 		intr_status = intr_status & ~DEFAULT_INTR;
4567c478bd9Sstevel@tonic-gate 		if ( action == ENABLE )
4577c478bd9Sstevel@tonic-gate 			intr_status = intr_status | DEFAULT_INTR;
4587c478bd9Sstevel@tonic-gate 		outw(intr_status, nic->ioaddr + IntrEnable);
4597c478bd9Sstevel@tonic-gate 		break;
4607c478bd9Sstevel@tonic-gate         case FORCE :
4617c478bd9Sstevel@tonic-gate 		outw(0x0200, BASE + ASICCtrl);
4627c478bd9Sstevel@tonic-gate 		break;
4637c478bd9Sstevel@tonic-gate         }
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate /**************************************************************************
4667c478bd9Sstevel@tonic-gate POLL - Wait for a frame
4677c478bd9Sstevel@tonic-gate ***************************************************************************/
sundance_poll(struct nic * nic,int retreive)4687c478bd9Sstevel@tonic-gate static int sundance_poll(struct nic *nic, int retreive)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate 	/* return true if there's an ethernet packet ready to read */
4717c478bd9Sstevel@tonic-gate 	/* nic->packet should contain data on return */
4727c478bd9Sstevel@tonic-gate 	/* nic->packetlen should contain length of data */
4737c478bd9Sstevel@tonic-gate 	int entry = sdc->cur_rx % RX_RING_SIZE;
4747c478bd9Sstevel@tonic-gate 	u32 frame_status = le32_to_cpu(rx_ring[entry].status);
4757c478bd9Sstevel@tonic-gate 	int intr_status;
4767c478bd9Sstevel@tonic-gate 	int pkt_len = 0;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	if (!(frame_status & DescOwn))
4797c478bd9Sstevel@tonic-gate 		return 0;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	/* There is a packet ready */
4827c478bd9Sstevel@tonic-gate 	if(!retreive)
4837c478bd9Sstevel@tonic-gate 		return 1;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	intr_status = inw(nic->ioaddr + IntrStatus);
4867c478bd9Sstevel@tonic-gate 	outw(intr_status, nic->ioaddr + IntrStatus);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	pkt_len = frame_status & 0x1fff;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (frame_status & 0x001f4000) {
4917c478bd9Sstevel@tonic-gate 		dprintf(("Polling frame_status error\n"));	/* Do we really care about this */
4927c478bd9Sstevel@tonic-gate 	} else {
4937c478bd9Sstevel@tonic-gate 		if (pkt_len < rx_copybreak) {
4947c478bd9Sstevel@tonic-gate 			/* FIXME: What should happen Will this ever occur */
4957c478bd9Sstevel@tonic-gate 			printf("Poll Error: pkt_len < rx_copybreak");
4967c478bd9Sstevel@tonic-gate 		} else {
4977c478bd9Sstevel@tonic-gate 			nic->packetlen = pkt_len;
4987c478bd9Sstevel@tonic-gate 			memcpy(nic->packet, rxb +
4997c478bd9Sstevel@tonic-gate 			       (sdc->cur_rx * PKT_BUF_SZ), nic->packetlen);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		}
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate 	rx_ring[entry].length = cpu_to_le32(PKT_BUF_SZ | LastFrag);
5047c478bd9Sstevel@tonic-gate 	rx_ring[entry].status = 0;
5057c478bd9Sstevel@tonic-gate 	entry++;
5067c478bd9Sstevel@tonic-gate 	sdc->cur_rx = entry % RX_RING_SIZE;
5077c478bd9Sstevel@tonic-gate 	outw(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
5087c478bd9Sstevel@tonic-gate 		nic->ioaddr + IntrStatus);
5097c478bd9Sstevel@tonic-gate 	return 1;
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate /**************************************************************************
5137c478bd9Sstevel@tonic-gate TRANSMIT - Transmit a frame
5147c478bd9Sstevel@tonic-gate ***************************************************************************/
sundance_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)5157c478bd9Sstevel@tonic-gate static void sundance_transmit(struct nic *nic, const char *d,	/* Destination */
5167c478bd9Sstevel@tonic-gate 			      unsigned int t,	/* Type */
5177c478bd9Sstevel@tonic-gate 			      unsigned int s,	/* size */
5187c478bd9Sstevel@tonic-gate 			      const char *p)
5197c478bd9Sstevel@tonic-gate {				/* Packet */
5207c478bd9Sstevel@tonic-gate 	u16 nstype;
5217c478bd9Sstevel@tonic-gate 	u32 to;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	/* Disable the Tx */
5247c478bd9Sstevel@tonic-gate 	outw(TxDisable, BASE + MACCtrl1);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	memcpy(txb, d, ETH_ALEN);
5277c478bd9Sstevel@tonic-gate 	memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
5287c478bd9Sstevel@tonic-gate 	nstype = htons((u16) t);
5297c478bd9Sstevel@tonic-gate 	memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
5307c478bd9Sstevel@tonic-gate 	memcpy(txb + ETH_HLEN, p, s);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	s += ETH_HLEN;
5337c478bd9Sstevel@tonic-gate 	s &= 0x0FFF;
5347c478bd9Sstevel@tonic-gate 	while (s < ETH_ZLEN)
5357c478bd9Sstevel@tonic-gate 		txb[s++] = '\0';
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	/* Setup the transmit descriptor */
5387c478bd9Sstevel@tonic-gate 	tx_ring[0].length = cpu_to_le32(s | LastFrag);
5397c478bd9Sstevel@tonic-gate 	tx_ring[0].status = cpu_to_le32(0x00000001);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	/* Point to transmit descriptor */
5427c478bd9Sstevel@tonic-gate 	outl(virt_to_le32desc(&tx_ring[0]), BASE + TxListPtr);
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	/* Enable Tx */
5457c478bd9Sstevel@tonic-gate 	outw(TxEnable, BASE + MACCtrl1);
5467c478bd9Sstevel@tonic-gate 	/* Trigger an immediate send */
5477c478bd9Sstevel@tonic-gate 	outw(0, BASE + TxStatus);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	to = currticks() + TX_TIME_OUT;
5507c478bd9Sstevel@tonic-gate 	while (!(tx_ring[0].status & 0x00010000) && (currticks() < to));	/* wait */
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	if (currticks() >= to) {
5537c478bd9Sstevel@tonic-gate 		printf("TX Time Out");
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 	/* Disable Tx */
5567c478bd9Sstevel@tonic-gate 	outw(TxDisable, BASE + MACCtrl1);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate /**************************************************************************
5617c478bd9Sstevel@tonic-gate DISABLE - Turn off ethernet interface
5627c478bd9Sstevel@tonic-gate ***************************************************************************/
sundance_disable(struct dev * dev __unused)5637c478bd9Sstevel@tonic-gate static void sundance_disable(struct dev *dev __unused)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	/* put the card in its initial state */
5667c478bd9Sstevel@tonic-gate 	/* This function serves 3 purposes.
5677c478bd9Sstevel@tonic-gate 	 * This disables DMA and interrupts so we don't receive
5687c478bd9Sstevel@tonic-gate 	 *  unexpected packets or interrupts from the card after
5697c478bd9Sstevel@tonic-gate 	 *  etherboot has finished.
5707c478bd9Sstevel@tonic-gate 	 * This frees resources so etherboot may use
5717c478bd9Sstevel@tonic-gate 	 *  this driver on another interface
5727c478bd9Sstevel@tonic-gate 	 * This allows etherboot to reinitialize the interface
5737c478bd9Sstevel@tonic-gate 	 *  if something is something goes wrong.
5747c478bd9Sstevel@tonic-gate 	 */
5757c478bd9Sstevel@tonic-gate 	outw(0x0000, BASE + IntrEnable);
5767c478bd9Sstevel@tonic-gate 	/* Stop the Chipchips Tx and Rx Status */
5777c478bd9Sstevel@tonic-gate 	outw(TxDisable | RxDisable | StatsDisable, BASE + MACCtrl1);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate /**************************************************************************
5837c478bd9Sstevel@tonic-gate PROBE - Look for an adapter, this routine's visible to the outside
5847c478bd9Sstevel@tonic-gate ***************************************************************************/
sundance_probe(struct dev * dev,struct pci_device * pci)5857c478bd9Sstevel@tonic-gate static int sundance_probe(struct dev *dev, struct pci_device *pci)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate 	struct nic *nic = (struct nic *) dev;
5887c478bd9Sstevel@tonic-gate 	u8 ee_data[EEPROM_SIZE];
5897c478bd9Sstevel@tonic-gate 	u16 mii_ctl;
5907c478bd9Sstevel@tonic-gate 	int i;
5917c478bd9Sstevel@tonic-gate 	int speed;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	if (pci->ioaddr == 0)
5947c478bd9Sstevel@tonic-gate 		return 0;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	/* BASE is used throughout to address the card */
5977c478bd9Sstevel@tonic-gate 	BASE = pci->ioaddr;
5987c478bd9Sstevel@tonic-gate 	printf(" sundance.c: Found %s Vendor=0x%hX Device=0x%hX\n",
5997c478bd9Sstevel@tonic-gate 	       pci->name, pci->vendor, pci->dev_id);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	/* Get the MAC Address by reading the EEPROM */
6027c478bd9Sstevel@tonic-gate 	for (i = 0; i < 3; i++) {
6037c478bd9Sstevel@tonic-gate 		((u16 *) ee_data)[i] =
6047c478bd9Sstevel@tonic-gate 		    le16_to_cpu(eeprom_read(BASE, i + EEPROM_SA_OFFSET));
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 	/* Update the nic structure with the MAC Address */
6077c478bd9Sstevel@tonic-gate 	for (i = 0; i < ETH_ALEN; i++) {
6087c478bd9Sstevel@tonic-gate 		nic->node_addr[i] = ee_data[i];
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/* Set the card as PCI Bus Master */
6127c478bd9Sstevel@tonic-gate 	adjust_pci_device(pci);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate //      sdc->mii_if.dev = pci;
6157c478bd9Sstevel@tonic-gate //      sdc->mii_if.phy_id_mask = 0x1f;
6167c478bd9Sstevel@tonic-gate //      sdc->mii_if.reg_num_mask = 0x1f;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	/* point to private storage */
6197c478bd9Sstevel@tonic-gate 	sdc = &sdx;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	sdc->nic_name = pci->name;
6227c478bd9Sstevel@tonic-gate 	sdc->mtu = mtu;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	pci_read_config_byte(pci, PCI_REVISION_ID, &sdc->pci_rev_id);
6257c478bd9Sstevel@tonic-gate 	dprintf(("Device revision id: %hx\n", sdc->pci_rev_id));
6267c478bd9Sstevel@tonic-gate 	/* Print out some hardware info */
6277c478bd9Sstevel@tonic-gate 	printf("%s: %! at ioaddr %hX, ", pci->name, nic->node_addr, BASE);
6287c478bd9Sstevel@tonic-gate 	sdc->mii_preamble_required = 0;
6297c478bd9Sstevel@tonic-gate 	if (1) {
6307c478bd9Sstevel@tonic-gate 		int phy, phy_idx = 0;
6317c478bd9Sstevel@tonic-gate 		sdc->phys[0] = 1;	/* Default Setting */
6327c478bd9Sstevel@tonic-gate 		sdc->mii_preamble_required++;
6337c478bd9Sstevel@tonic-gate 		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
6347c478bd9Sstevel@tonic-gate 			int mii_status = mdio_read(nic, phy, MII_BMSR);
6357c478bd9Sstevel@tonic-gate 			if (mii_status != 0xffff && mii_status != 0x0000) {
6367c478bd9Sstevel@tonic-gate 				sdc->phys[phy_idx++] = phy;
6377c478bd9Sstevel@tonic-gate 				sdc->mii_if.advertising =
6387c478bd9Sstevel@tonic-gate 				    mdio_read(nic, phy, MII_ADVERTISE);
6397c478bd9Sstevel@tonic-gate 				if ((mii_status & 0x0040) == 0)
6407c478bd9Sstevel@tonic-gate 					sdc->mii_preamble_required++;
6417c478bd9Sstevel@tonic-gate 				dprintf
6427c478bd9Sstevel@tonic-gate 				    (("%s: MII PHY found at address %d, status " "%hX advertising %hX\n", sdc->nic_name, phy, mii_status, sdc->mii_if.advertising));
6437c478bd9Sstevel@tonic-gate 			}
6447c478bd9Sstevel@tonic-gate 		}
6457c478bd9Sstevel@tonic-gate 		sdc->mii_preamble_required--;
6467c478bd9Sstevel@tonic-gate 		if (phy_idx == 0)
6477c478bd9Sstevel@tonic-gate 			printf("%s: No MII transceiver found!\n",
6487c478bd9Sstevel@tonic-gate 			       sdc->nic_name);
6497c478bd9Sstevel@tonic-gate 		sdc->mii_if.phy_id = sdc->phys[0];
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/* Parse override configuration */
6537c478bd9Sstevel@tonic-gate 	sdc->an_enable = 1;
6547c478bd9Sstevel@tonic-gate 	if (strcasecmp(media, "autosense") != 0) {
6557c478bd9Sstevel@tonic-gate 		sdc->an_enable = 0;
6567c478bd9Sstevel@tonic-gate 		if (strcasecmp(media, "100mbps_fd") == 0 ||
6577c478bd9Sstevel@tonic-gate 		    strcasecmp(media, "4") == 0) {
6587c478bd9Sstevel@tonic-gate 			sdc->speed = 100;
6597c478bd9Sstevel@tonic-gate 			sdc->mii_if.full_duplex = 1;
6607c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(media, "100mbps_hd") == 0
6617c478bd9Sstevel@tonic-gate 			   || strcasecmp(media, "3") == 0) {
6627c478bd9Sstevel@tonic-gate 			sdc->speed = 100;
6637c478bd9Sstevel@tonic-gate 			sdc->mii_if.full_duplex = 0;
6647c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(media, "10mbps_fd") == 0 ||
6657c478bd9Sstevel@tonic-gate 			   strcasecmp(media, "2") == 0) {
6667c478bd9Sstevel@tonic-gate 			sdc->speed = 10;
6677c478bd9Sstevel@tonic-gate 			sdc->mii_if.full_duplex = 1;
6687c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(media, "10mbps_hd") == 0 ||
6697c478bd9Sstevel@tonic-gate 			   strcasecmp(media, "1") == 0) {
6707c478bd9Sstevel@tonic-gate 			sdc->speed = 10;
6717c478bd9Sstevel@tonic-gate 			sdc->mii_if.full_duplex = 0;
6727c478bd9Sstevel@tonic-gate 		} else {
6737c478bd9Sstevel@tonic-gate 			sdc->an_enable = 1;
6747c478bd9Sstevel@tonic-gate 		}
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 	if (flowctrl == 1)
6777c478bd9Sstevel@tonic-gate 		sdc->flowctrl = 1;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	/* Fibre PHY? */
6807c478bd9Sstevel@tonic-gate 	if (inl(BASE + ASICCtrl) & 0x80) {
6817c478bd9Sstevel@tonic-gate 		/* Default 100Mbps Full */
6827c478bd9Sstevel@tonic-gate 		if (sdc->an_enable) {
6837c478bd9Sstevel@tonic-gate 			sdc->speed = 100;
6847c478bd9Sstevel@tonic-gate 			sdc->mii_if.full_duplex = 1;
6857c478bd9Sstevel@tonic-gate 			sdc->an_enable = 0;
6867c478bd9Sstevel@tonic-gate 		}
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	/* The Linux driver uses flow control and resets the link here.  This means the
6907c478bd9Sstevel@tonic-gate 	   mii section from above would need to be re done I believe.  Since it serves
6917c478bd9Sstevel@tonic-gate 	   no real purpose leave it out. */
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	/* Force media type */
6947c478bd9Sstevel@tonic-gate 	if (!sdc->an_enable) {
6957c478bd9Sstevel@tonic-gate 		mii_ctl = 0;
6967c478bd9Sstevel@tonic-gate 		mii_ctl |= (sdc->speed == 100) ? BMCR_SPEED100 : 0;
6977c478bd9Sstevel@tonic-gate 		mii_ctl |= (sdc->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
6987c478bd9Sstevel@tonic-gate 		mdio_write(nic, sdc->phys[0], MII_BMCR, mii_ctl);
6997c478bd9Sstevel@tonic-gate 		printf("Override speed=%d, %s duplex\n",
7007c478bd9Sstevel@tonic-gate 		       sdc->speed,
7017c478bd9Sstevel@tonic-gate 		       sdc->mii_if.full_duplex ? "Full" : "Half");
7027c478bd9Sstevel@tonic-gate 	}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	/* Reset the chip to erase previous misconfiguration */
7057c478bd9Sstevel@tonic-gate 	dprintf(("ASIC Control is %x.\n", inl(BASE + ASICCtrl)));
7067c478bd9Sstevel@tonic-gate 	outw(0x007f, BASE + ASICCtrl + 2);
7077c478bd9Sstevel@tonic-gate 	dprintf(("ASIC Control is now %x.\n", inl(BASE + ASICCtrl)));
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	sundance_reset(nic);
7107c478bd9Sstevel@tonic-gate 	if (sdc->an_enable) {
7117c478bd9Sstevel@tonic-gate 		u16 mii_advertise, mii_lpa;
7127c478bd9Sstevel@tonic-gate 		mii_advertise =
7137c478bd9Sstevel@tonic-gate 		    mdio_read(nic, sdc->phys[0], MII_ADVERTISE);
7147c478bd9Sstevel@tonic-gate 		mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA);
7157c478bd9Sstevel@tonic-gate 		mii_advertise &= mii_lpa;
7167c478bd9Sstevel@tonic-gate 		if (mii_advertise & ADVERTISE_100FULL)
7177c478bd9Sstevel@tonic-gate 			sdc->speed = 100;
7187c478bd9Sstevel@tonic-gate 		else if (mii_advertise & ADVERTISE_100HALF)
7197c478bd9Sstevel@tonic-gate 			sdc->speed = 100;
7207c478bd9Sstevel@tonic-gate 		else if (mii_advertise & ADVERTISE_10FULL)
7217c478bd9Sstevel@tonic-gate 			sdc->speed = 10;
7227c478bd9Sstevel@tonic-gate 		else if (mii_advertise & ADVERTISE_10HALF)
7237c478bd9Sstevel@tonic-gate 			sdc->speed = 10;
7247c478bd9Sstevel@tonic-gate 	} else {
7257c478bd9Sstevel@tonic-gate 		mii_ctl = mdio_read(nic, sdc->phys[0], MII_BMCR);
7267c478bd9Sstevel@tonic-gate 		speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
7277c478bd9Sstevel@tonic-gate 		sdc->speed = speed;
7287c478bd9Sstevel@tonic-gate 		printf("%s: Link changed: %dMbps ,", sdc->nic_name, speed);
7297c478bd9Sstevel@tonic-gate 		printf("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
7307c478bd9Sstevel@tonic-gate 		       "full" : "half");
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 	check_duplex(nic);
7337c478bd9Sstevel@tonic-gate 	if (sdc->flowctrl && sdc->mii_if.full_duplex) {
7347c478bd9Sstevel@tonic-gate 		outw(inw(BASE + MulticastFilter1 + 2) | 0x0200,
7357c478bd9Sstevel@tonic-gate 		     BASE + MulticastFilter1 + 2);
7367c478bd9Sstevel@tonic-gate 		outw(inw(BASE + MACCtrl0) | EnbFlowCtrl, BASE + MACCtrl0);
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 	printf("%dMbps, %s-Duplex\n", sdc->speed,
7397c478bd9Sstevel@tonic-gate 	       sdc->mii_if.full_duplex ? "Full" : "Half");
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	/* point to NIC specific routines */
7427c478bd9Sstevel@tonic-gate 	dev->disable = sundance_disable;
7437c478bd9Sstevel@tonic-gate 	nic->poll = sundance_poll;
7447c478bd9Sstevel@tonic-gate 	nic->transmit = sundance_transmit;
7457c478bd9Sstevel@tonic-gate 	nic->irqno = pci->irq;
7467c478bd9Sstevel@tonic-gate 	nic->irq = sundance_irq;
7477c478bd9Sstevel@tonic-gate 	nic->ioaddr = BASE;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	return 1;
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
eeprom_read(long ioaddr,int location)7547c478bd9Sstevel@tonic-gate static int eeprom_read(long ioaddr, int location)
7557c478bd9Sstevel@tonic-gate {
7567c478bd9Sstevel@tonic-gate 	int boguscnt = 10000;	/* Typical 1900 ticks */
7577c478bd9Sstevel@tonic-gate 	outw(0x0200 | (location & 0xff), ioaddr + EECtrl);
7587c478bd9Sstevel@tonic-gate 	do {
7597c478bd9Sstevel@tonic-gate 		if (!(inw(ioaddr + EECtrl) & 0x8000)) {
7607c478bd9Sstevel@tonic-gate 			return inw(ioaddr + EEData);
7617c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 	while (--boguscnt > 0);
7647c478bd9Sstevel@tonic-gate 	return 0;
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate /*  MII transceiver control section.
7687c478bd9Sstevel@tonic-gate 	Read and write the MII registers using software-generated serial
7697c478bd9Sstevel@tonic-gate 	MDIO protocol.  See the MII specifications or DP83840A data sheet
7707c478bd9Sstevel@tonic-gate 	for details.
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	The maximum data clock rate is 2.5 Mhz.
7737c478bd9Sstevel@tonic-gate 	The timing is decoupled from the processor clock by flushing the write
7747c478bd9Sstevel@tonic-gate 	from the CPU write buffer with a following read, and using PCI
7757c478bd9Sstevel@tonic-gate 	transaction time. */
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate #define mdio_in(mdio_addr) inb(mdio_addr)
7787c478bd9Sstevel@tonic-gate #define mdio_out(value, mdio_addr) outb(value, mdio_addr)
7797c478bd9Sstevel@tonic-gate #define mdio_delay(mdio_addr) inb(mdio_addr)
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate enum mii_reg_bits {
7827c478bd9Sstevel@tonic-gate 	MDIO_ShiftClk = 0x0001, MDIO_Data = 0x0002, MDIO_EnbOutput =
7837c478bd9Sstevel@tonic-gate 	    0x0004,
7847c478bd9Sstevel@tonic-gate };
7857c478bd9Sstevel@tonic-gate #define MDIO_EnbIn  (0)
7867c478bd9Sstevel@tonic-gate #define MDIO_WRITE0 (MDIO_EnbOutput)
7877c478bd9Sstevel@tonic-gate #define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate /* Generate the preamble required for initial synchronization and
7907c478bd9Sstevel@tonic-gate    a few older transceivers. */
mdio_sync(long mdio_addr)7917c478bd9Sstevel@tonic-gate static void mdio_sync(long mdio_addr)
7927c478bd9Sstevel@tonic-gate {
7937c478bd9Sstevel@tonic-gate 	int bits = 32;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	/* Establish sync by sending at least 32 logic ones. */
7967c478bd9Sstevel@tonic-gate 	while (--bits >= 0) {
7977c478bd9Sstevel@tonic-gate 		mdio_out(MDIO_WRITE1, mdio_addr);
7987c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
7997c478bd9Sstevel@tonic-gate 		mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
8007c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate static int
mdio_read(struct nic * nic __unused,int phy_id,unsigned int location)8057c478bd9Sstevel@tonic-gate mdio_read(struct nic *nic __unused, int phy_id, unsigned int location)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate 	long mdio_addr = BASE + MIICtrl;
8087c478bd9Sstevel@tonic-gate 	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
8097c478bd9Sstevel@tonic-gate 	int i, retval = 0;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	if (sdc->mii_preamble_required)
8127c478bd9Sstevel@tonic-gate 		mdio_sync(mdio_addr);
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	/* Shift the read command bits out. */
8157c478bd9Sstevel@tonic-gate 	for (i = 15; i >= 0; i--) {
8167c478bd9Sstevel@tonic-gate 		int dataval =
8177c478bd9Sstevel@tonic-gate 		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 		mdio_out(dataval, mdio_addr);
8207c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8217c478bd9Sstevel@tonic-gate 		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
8227c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 	/* Read the two transition, 16 data, and wire-idle bits. */
8257c478bd9Sstevel@tonic-gate 	for (i = 19; i > 0; i--) {
8267c478bd9Sstevel@tonic-gate 		mdio_out(MDIO_EnbIn, mdio_addr);
8277c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8287c478bd9Sstevel@tonic-gate 		retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data)
8297c478bd9Sstevel@tonic-gate 					  ? 1 : 0);
8307c478bd9Sstevel@tonic-gate 		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
8317c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate 	return (retval >> 1) & 0xffff;
8347c478bd9Sstevel@tonic-gate }
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate static void
mdio_write(struct nic * nic __unused,int phy_id,unsigned int location,int value)8377c478bd9Sstevel@tonic-gate mdio_write(struct nic *nic __unused, int phy_id,
8387c478bd9Sstevel@tonic-gate 	   unsigned int location, int value)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate 	long mdio_addr = BASE + MIICtrl;
8417c478bd9Sstevel@tonic-gate 	int mii_cmd =
8427c478bd9Sstevel@tonic-gate 	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
8437c478bd9Sstevel@tonic-gate 	int i;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if (sdc->mii_preamble_required)
8467c478bd9Sstevel@tonic-gate 		mdio_sync(mdio_addr);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/* Shift the command bits out. */
8497c478bd9Sstevel@tonic-gate 	for (i = 31; i >= 0; i--) {
8507c478bd9Sstevel@tonic-gate 		int dataval =
8517c478bd9Sstevel@tonic-gate 		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
8527c478bd9Sstevel@tonic-gate 		mdio_out(dataval, mdio_addr);
8537c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8547c478bd9Sstevel@tonic-gate 		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
8557c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8567c478bd9Sstevel@tonic-gate 	}
8577c478bd9Sstevel@tonic-gate 	/* Clear out extra bits. */
8587c478bd9Sstevel@tonic-gate 	for (i = 2; i > 0; i--) {
8597c478bd9Sstevel@tonic-gate 		mdio_out(MDIO_EnbIn, mdio_addr);
8607c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8617c478bd9Sstevel@tonic-gate 		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
8627c478bd9Sstevel@tonic-gate 		mdio_delay(mdio_addr);
8637c478bd9Sstevel@tonic-gate 	}
8647c478bd9Sstevel@tonic-gate 	return;
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate 
set_rx_mode(struct nic * nic __unused)8677c478bd9Sstevel@tonic-gate static void set_rx_mode(struct nic *nic __unused)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	int i;
8707c478bd9Sstevel@tonic-gate 	u16 mc_filter[4];	/* Multicast hash filter */
8717c478bd9Sstevel@tonic-gate 	u32 rx_mode;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	memset(mc_filter, 0xff, sizeof(mc_filter));
8747c478bd9Sstevel@tonic-gate 	rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	if (sdc->mii_if.full_duplex && sdc->flowctrl)
8777c478bd9Sstevel@tonic-gate 		mc_filter[3] |= 0x0200;
8787c478bd9Sstevel@tonic-gate 	for (i = 0; i < 4; i++)
8797c478bd9Sstevel@tonic-gate 		outw(mc_filter[i], BASE + MulticastFilter0 + i * 2);
8807c478bd9Sstevel@tonic-gate 	outb(rx_mode, BASE + RxMode);
8817c478bd9Sstevel@tonic-gate 	return;
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate static struct pci_id sundance_nics[] = {
8857c478bd9Sstevel@tonic-gate 	PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor"),
8867c478bd9Sstevel@tonic-gate 	PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)"),
8877c478bd9Sstevel@tonic-gate };
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate struct pci_driver sundance_driver = {
8907c478bd9Sstevel@tonic-gate 	.type = NIC_DRIVER,
8917c478bd9Sstevel@tonic-gate 	.name = "SUNDANCE/PCI",
8927c478bd9Sstevel@tonic-gate 	.probe = sundance_probe,
8937c478bd9Sstevel@tonic-gate 	.ids = sundance_nics,
8947c478bd9Sstevel@tonic-gate 	.id_count = sizeof(sundance_nics) / sizeof(sundance_nics[0]),
8957c478bd9Sstevel@tonic-gate 	.class = 0,
8967c478bd9Sstevel@tonic-gate };
897