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