1*1b8adde7SWilliam Kucharski /************************************************************************** 2*1b8adde7SWilliam Kucharski * 3*1b8adde7SWilliam Kucharski * sundance.c -- Etherboot device driver for the Sundance ST201 "Alta". 4*1b8adde7SWilliam Kucharski * Written 2002-2002 by Timothy Legge <tlegge@rogers.com> 5*1b8adde7SWilliam Kucharski * 6*1b8adde7SWilliam Kucharski * This program is free software; you can redistribute it and/or modify 7*1b8adde7SWilliam Kucharski * it under the terms of the GNU General Public License as published by 8*1b8adde7SWilliam Kucharski * the Free Software Foundation; either version 2 of the License, or 9*1b8adde7SWilliam Kucharski * (at your option) any later version. 10*1b8adde7SWilliam Kucharski * 11*1b8adde7SWilliam Kucharski * This program is distributed in the hope that it will be useful, 12*1b8adde7SWilliam Kucharski * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*1b8adde7SWilliam Kucharski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*1b8adde7SWilliam Kucharski * GNU General Public License for more details. 15*1b8adde7SWilliam Kucharski * 16*1b8adde7SWilliam Kucharski * You should have received a copy of the GNU General Public License 17*1b8adde7SWilliam Kucharski * along with this program; if not, write to the Free Software 18*1b8adde7SWilliam Kucharski * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*1b8adde7SWilliam Kucharski * 20*1b8adde7SWilliam Kucharski * Portions of this code based on: 21*1b8adde7SWilliam Kucharski * sundance.c: A Linux device driver for the Sundance ST201 "Alta" 22*1b8adde7SWilliam Kucharski * Written 1999-2002 by Donald Becker 23*1b8adde7SWilliam Kucharski * 24*1b8adde7SWilliam Kucharski * tulip.c: Tulip and Clone Etherboot Driver 25*1b8adde7SWilliam Kucharski * By Marty Conner 26*1b8adde7SWilliam Kucharski * Copyright (C) 2001 Entity Cyber, Inc. 27*1b8adde7SWilliam Kucharski * 28*1b8adde7SWilliam Kucharski * Linux Driver Version LK1.09a, 10-Jul-2003 (2.4.25) 29*1b8adde7SWilliam Kucharski * 30*1b8adde7SWilliam Kucharski * REVISION HISTORY: 31*1b8adde7SWilliam Kucharski * ================ 32*1b8adde7SWilliam Kucharski * v1.1 01-01-2003 timlegge Initial implementation 33*1b8adde7SWilliam Kucharski * v1.7 04-10-2003 timlegge Transfers Linux Kernel (30 sec) 34*1b8adde7SWilliam Kucharski * v1.8 04-13-2003 timlegge Fix multiple transmission bug 35*1b8adde7SWilliam Kucharski * v1.9 08-19-2003 timlegge Support Multicast 36*1b8adde7SWilliam Kucharski * v1.10 01-17-2004 timlegge Initial driver output cleanup 37*1b8adde7SWilliam Kucharski * v1.11 03-21-2004 timlegge Remove unused variables 38*1b8adde7SWilliam Kucharski * v1.12 03-21-2004 timlegge Remove excess MII defines 39*1b8adde7SWilliam Kucharski * v1.13 03-24-2004 timlegge Update to Linux 2.4.25 driver 40*1b8adde7SWilliam Kucharski * 41*1b8adde7SWilliam Kucharski ****************************************************************************/ 42*1b8adde7SWilliam Kucharski 43*1b8adde7SWilliam Kucharski /* to get some global routines like printf */ 44*1b8adde7SWilliam Kucharski #include "etherboot.h" 45*1b8adde7SWilliam Kucharski /* to get the interface to the body of the program */ 46*1b8adde7SWilliam Kucharski #include "nic.h" 47*1b8adde7SWilliam Kucharski /* to get the PCI support functions, if this is a PCI NIC */ 48*1b8adde7SWilliam Kucharski #include "pci.h" 49*1b8adde7SWilliam Kucharski #include "timer.h" 50*1b8adde7SWilliam Kucharski #include "mii.h" 51*1b8adde7SWilliam Kucharski 52*1b8adde7SWilliam Kucharski #define drv_version "v1.12" 53*1b8adde7SWilliam Kucharski #define drv_date "2004-03-21" 54*1b8adde7SWilliam Kucharski 55*1b8adde7SWilliam Kucharski typedef unsigned char u8; 56*1b8adde7SWilliam Kucharski typedef signed char s8; 57*1b8adde7SWilliam Kucharski typedef unsigned short u16; 58*1b8adde7SWilliam Kucharski typedef signed short s16; 59*1b8adde7SWilliam Kucharski typedef unsigned int u32; 60*1b8adde7SWilliam Kucharski typedef signed int s32; 61*1b8adde7SWilliam Kucharski 62*1b8adde7SWilliam Kucharski #define HZ 100 63*1b8adde7SWilliam Kucharski 64*1b8adde7SWilliam Kucharski /* Condensed operations for readability. */ 65*1b8adde7SWilliam Kucharski #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) 66*1b8adde7SWilliam Kucharski #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) 67*1b8adde7SWilliam Kucharski 68*1b8adde7SWilliam Kucharski /* May need to be moved to mii.h */ 69*1b8adde7SWilliam Kucharski struct mii_if_info { 70*1b8adde7SWilliam Kucharski int phy_id; 71*1b8adde7SWilliam Kucharski int advertising; 72*1b8adde7SWilliam Kucharski unsigned int full_duplex:1; /* is full duplex? */ 73*1b8adde7SWilliam Kucharski }; 74*1b8adde7SWilliam Kucharski 75*1b8adde7SWilliam Kucharski //#define EDEBUG 76*1b8adde7SWilliam Kucharski #ifdef EDEBUG 77*1b8adde7SWilliam Kucharski #define dprintf(x) printf x 78*1b8adde7SWilliam Kucharski #else 79*1b8adde7SWilliam Kucharski #define dprintf(x) 80*1b8adde7SWilliam Kucharski #endif 81*1b8adde7SWilliam Kucharski 82*1b8adde7SWilliam Kucharski #if defined(__sun) 83*1b8adde7SWilliam Kucharski /* Hack: use grub_strcmp since strcasecmp is undefined */ 84*1b8adde7SWilliam Kucharski #define strcasecmp grub_strcmp 85*1b8adde7SWilliam Kucharski #endif 86*1b8adde7SWilliam Kucharski 87*1b8adde7SWilliam Kucharski 88*1b8adde7SWilliam Kucharski /* Set the mtu */ 89*1b8adde7SWilliam Kucharski static int mtu = 1514; 90*1b8adde7SWilliam Kucharski 91*1b8adde7SWilliam Kucharski /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). 92*1b8adde7SWilliam Kucharski The sundance uses a 64 element hash table based on the Ethernet CRC. */ 93*1b8adde7SWilliam Kucharski // static int multicast_filter_limit = 32; 94*1b8adde7SWilliam Kucharski 95*1b8adde7SWilliam Kucharski /* Set the copy breakpoint for the copy-only-tiny-frames scheme. 96*1b8adde7SWilliam Kucharski Setting to > 1518 effectively disables this feature. 97*1b8adde7SWilliam Kucharski This chip can receive into any byte alignment buffers, so word-oriented 98*1b8adde7SWilliam Kucharski archs do not need a copy-align of the IP header. */ 99*1b8adde7SWilliam Kucharski static int rx_copybreak = 0; 100*1b8adde7SWilliam Kucharski static int flowctrl = 1; 101*1b8adde7SWilliam Kucharski 102*1b8adde7SWilliam Kucharski /* Allow forcing the media type */ 103*1b8adde7SWilliam Kucharski /* media[] specifies the media type the NIC operates at. 104*1b8adde7SWilliam Kucharski autosense Autosensing active media. 105*1b8adde7SWilliam Kucharski 10mbps_hd 10Mbps half duplex. 106*1b8adde7SWilliam Kucharski 10mbps_fd 10Mbps full duplex. 107*1b8adde7SWilliam Kucharski 100mbps_hd 100Mbps half duplex. 108*1b8adde7SWilliam Kucharski 100mbps_fd 100Mbps full duplex. 109*1b8adde7SWilliam Kucharski */ 110*1b8adde7SWilliam Kucharski static char media[] = "autosense"; 111*1b8adde7SWilliam Kucharski 112*1b8adde7SWilliam Kucharski /* Operational parameters that are set at compile time. */ 113*1b8adde7SWilliam Kucharski 114*1b8adde7SWilliam Kucharski /* As Etherboot uses a Polling driver we can keep the number of rings 115*1b8adde7SWilliam Kucharski to the minimum number required. In general that is 1 transmit and 4 receive receive rings. However some cards require that 116*1b8adde7SWilliam Kucharski there be a minimum of 2 rings */ 117*1b8adde7SWilliam Kucharski #define TX_RING_SIZE 2 118*1b8adde7SWilliam Kucharski #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ 119*1b8adde7SWilliam Kucharski #define RX_RING_SIZE 4 120*1b8adde7SWilliam Kucharski 121*1b8adde7SWilliam Kucharski 122*1b8adde7SWilliam Kucharski /* Operational parameters that usually are not changed. */ 123*1b8adde7SWilliam Kucharski /* Time in jiffies before concluding the transmitter is hung. */ 124*1b8adde7SWilliam Kucharski #define TX_TIME_OUT (4*HZ) 125*1b8adde7SWilliam Kucharski #define PKT_BUF_SZ 1536 126*1b8adde7SWilliam Kucharski 127*1b8adde7SWilliam Kucharski /* Offsets to the device registers. 128*1b8adde7SWilliam Kucharski Unlike software-only systems, device drivers interact with complex hardware. 129*1b8adde7SWilliam Kucharski It's not useful to define symbolic names for every register bit in the 130*1b8adde7SWilliam Kucharski device. The name can only partially document the semantics and make 131*1b8adde7SWilliam Kucharski the driver longer and more difficult to read. 132*1b8adde7SWilliam Kucharski In general, only the important configuration values or bits changed 133*1b8adde7SWilliam Kucharski multiple times should be defined symbolically. 134*1b8adde7SWilliam Kucharski */ 135*1b8adde7SWilliam Kucharski enum alta_offsets { 136*1b8adde7SWilliam Kucharski DMACtrl = 0x00, 137*1b8adde7SWilliam Kucharski TxListPtr = 0x04, 138*1b8adde7SWilliam Kucharski TxDMABurstThresh = 0x08, 139*1b8adde7SWilliam Kucharski TxDMAUrgentThresh = 0x09, 140*1b8adde7SWilliam Kucharski TxDMAPollPeriod = 0x0a, 141*1b8adde7SWilliam Kucharski RxDMAStatus = 0x0c, 142*1b8adde7SWilliam Kucharski RxListPtr = 0x10, 143*1b8adde7SWilliam Kucharski DebugCtrl0 = 0x1a, 144*1b8adde7SWilliam Kucharski DebugCtrl1 = 0x1c, 145*1b8adde7SWilliam Kucharski RxDMABurstThresh = 0x14, 146*1b8adde7SWilliam Kucharski RxDMAUrgentThresh = 0x15, 147*1b8adde7SWilliam Kucharski RxDMAPollPeriod = 0x16, 148*1b8adde7SWilliam Kucharski LEDCtrl = 0x1a, 149*1b8adde7SWilliam Kucharski ASICCtrl = 0x30, 150*1b8adde7SWilliam Kucharski EEData = 0x34, 151*1b8adde7SWilliam Kucharski EECtrl = 0x36, 152*1b8adde7SWilliam Kucharski TxStartThresh = 0x3c, 153*1b8adde7SWilliam Kucharski RxEarlyThresh = 0x3e, 154*1b8adde7SWilliam Kucharski FlashAddr = 0x40, 155*1b8adde7SWilliam Kucharski FlashData = 0x44, 156*1b8adde7SWilliam Kucharski TxStatus = 0x46, 157*1b8adde7SWilliam Kucharski TxFrameId = 0x47, 158*1b8adde7SWilliam Kucharski DownCounter = 0x18, 159*1b8adde7SWilliam Kucharski IntrClear = 0x4a, 160*1b8adde7SWilliam Kucharski IntrEnable = 0x4c, 161*1b8adde7SWilliam Kucharski IntrStatus = 0x4e, 162*1b8adde7SWilliam Kucharski MACCtrl0 = 0x50, 163*1b8adde7SWilliam Kucharski MACCtrl1 = 0x52, 164*1b8adde7SWilliam Kucharski StationAddr = 0x54, 165*1b8adde7SWilliam Kucharski MaxFrameSize = 0x5A, 166*1b8adde7SWilliam Kucharski RxMode = 0x5c, 167*1b8adde7SWilliam Kucharski MIICtrl = 0x5e, 168*1b8adde7SWilliam Kucharski MulticastFilter0 = 0x60, 169*1b8adde7SWilliam Kucharski MulticastFilter1 = 0x64, 170*1b8adde7SWilliam Kucharski RxOctetsLow = 0x68, 171*1b8adde7SWilliam Kucharski RxOctetsHigh = 0x6a, 172*1b8adde7SWilliam Kucharski TxOctetsLow = 0x6c, 173*1b8adde7SWilliam Kucharski TxOctetsHigh = 0x6e, 174*1b8adde7SWilliam Kucharski TxFramesOK = 0x70, 175*1b8adde7SWilliam Kucharski RxFramesOK = 0x72, 176*1b8adde7SWilliam Kucharski StatsCarrierError = 0x74, 177*1b8adde7SWilliam Kucharski StatsLateColl = 0x75, 178*1b8adde7SWilliam Kucharski StatsMultiColl = 0x76, 179*1b8adde7SWilliam Kucharski StatsOneColl = 0x77, 180*1b8adde7SWilliam Kucharski StatsTxDefer = 0x78, 181*1b8adde7SWilliam Kucharski RxMissed = 0x79, 182*1b8adde7SWilliam Kucharski StatsTxXSDefer = 0x7a, 183*1b8adde7SWilliam Kucharski StatsTxAbort = 0x7b, 184*1b8adde7SWilliam Kucharski StatsBcastTx = 0x7c, 185*1b8adde7SWilliam Kucharski StatsBcastRx = 0x7d, 186*1b8adde7SWilliam Kucharski StatsMcastTx = 0x7e, 187*1b8adde7SWilliam Kucharski StatsMcastRx = 0x7f, 188*1b8adde7SWilliam Kucharski /* Aliased and bogus values! */ 189*1b8adde7SWilliam Kucharski RxStatus = 0x0c, 190*1b8adde7SWilliam Kucharski }; 191*1b8adde7SWilliam Kucharski enum ASICCtrl_HiWord_bit { 192*1b8adde7SWilliam Kucharski GlobalReset = 0x0001, 193*1b8adde7SWilliam Kucharski RxReset = 0x0002, 194*1b8adde7SWilliam Kucharski TxReset = 0x0004, 195*1b8adde7SWilliam Kucharski DMAReset = 0x0008, 196*1b8adde7SWilliam Kucharski FIFOReset = 0x0010, 197*1b8adde7SWilliam Kucharski NetworkReset = 0x0020, 198*1b8adde7SWilliam Kucharski HostReset = 0x0040, 199*1b8adde7SWilliam Kucharski ResetBusy = 0x0400, 200*1b8adde7SWilliam Kucharski }; 201*1b8adde7SWilliam Kucharski 202*1b8adde7SWilliam Kucharski /* Bits in the interrupt status/mask registers. */ 203*1b8adde7SWilliam Kucharski enum intr_status_bits { 204*1b8adde7SWilliam Kucharski IntrSummary = 0x0001, IntrPCIErr = 0x0002, IntrMACCtrl = 0x0008, 205*1b8adde7SWilliam Kucharski IntrTxDone = 0x0004, IntrRxDone = 0x0010, IntrRxStart = 0x0020, 206*1b8adde7SWilliam Kucharski IntrDrvRqst = 0x0040, 207*1b8adde7SWilliam Kucharski StatsMax = 0x0080, LinkChange = 0x0100, 208*1b8adde7SWilliam Kucharski IntrTxDMADone = 0x0200, IntrRxDMADone = 0x0400, 209*1b8adde7SWilliam Kucharski }; 210*1b8adde7SWilliam Kucharski 211*1b8adde7SWilliam Kucharski /* Bits in the RxMode register. */ 212*1b8adde7SWilliam Kucharski enum rx_mode_bits { 213*1b8adde7SWilliam Kucharski AcceptAllIPMulti = 0x20, AcceptMultiHash = 0x10, AcceptAll = 0x08, 214*1b8adde7SWilliam Kucharski AcceptBroadcast = 0x04, AcceptMulticast = 0x02, AcceptMyPhys = 215*1b8adde7SWilliam Kucharski 0x01, 216*1b8adde7SWilliam Kucharski }; 217*1b8adde7SWilliam Kucharski /* Bits in MACCtrl. */ 218*1b8adde7SWilliam Kucharski enum mac_ctrl0_bits { 219*1b8adde7SWilliam Kucharski EnbFullDuplex = 0x20, EnbRcvLargeFrame = 0x40, 220*1b8adde7SWilliam Kucharski EnbFlowCtrl = 0x100, EnbPassRxCRC = 0x200, 221*1b8adde7SWilliam Kucharski }; 222*1b8adde7SWilliam Kucharski enum mac_ctrl1_bits { 223*1b8adde7SWilliam Kucharski StatsEnable = 0x0020, StatsDisable = 0x0040, StatsEnabled = 0x0080, 224*1b8adde7SWilliam Kucharski TxEnable = 0x0100, TxDisable = 0x0200, TxEnabled = 0x0400, 225*1b8adde7SWilliam Kucharski RxEnable = 0x0800, RxDisable = 0x1000, RxEnabled = 0x2000, 226*1b8adde7SWilliam Kucharski }; 227*1b8adde7SWilliam Kucharski 228*1b8adde7SWilliam Kucharski /* The Rx and Tx buffer descriptors. 229*1b8adde7SWilliam Kucharski Using only 32 bit fields simplifies software endian correction. 230*1b8adde7SWilliam Kucharski This structure must be aligned, and should avoid spanning cache lines. 231*1b8adde7SWilliam Kucharski */ 232*1b8adde7SWilliam Kucharski struct netdev_desc { 233*1b8adde7SWilliam Kucharski u32 next_desc; 234*1b8adde7SWilliam Kucharski u32 status; 235*1b8adde7SWilliam Kucharski u32 addr; 236*1b8adde7SWilliam Kucharski u32 length; 237*1b8adde7SWilliam Kucharski }; 238*1b8adde7SWilliam Kucharski 239*1b8adde7SWilliam Kucharski /* Bits in netdev_desc.status */ 240*1b8adde7SWilliam Kucharski enum desc_status_bits { 241*1b8adde7SWilliam Kucharski DescOwn = 0x8000, 242*1b8adde7SWilliam Kucharski DescEndPacket = 0x4000, 243*1b8adde7SWilliam Kucharski DescEndRing = 0x2000, 244*1b8adde7SWilliam Kucharski LastFrag = 0x80000000, 245*1b8adde7SWilliam Kucharski DescIntrOnTx = 0x8000, 246*1b8adde7SWilliam Kucharski DescIntrOnDMADone = 0x80000000, 247*1b8adde7SWilliam Kucharski DisableAlign = 0x00000001, 248*1b8adde7SWilliam Kucharski }; 249*1b8adde7SWilliam Kucharski 250*1b8adde7SWilliam Kucharski /********************************************** 251*1b8adde7SWilliam Kucharski * Descriptor Ring and Buffer defination 252*1b8adde7SWilliam Kucharski ***********************************************/ 253*1b8adde7SWilliam Kucharski /* Define the TX Descriptor */ 254*1b8adde7SWilliam Kucharski static struct netdev_desc tx_ring[TX_RING_SIZE]; 255*1b8adde7SWilliam Kucharski 256*1b8adde7SWilliam Kucharski /* Create a static buffer of size PKT_BUF_SZ for each TX Descriptor. 257*1b8adde7SWilliam Kucharski All descriptors point to a part of this buffer */ 258*1b8adde7SWilliam Kucharski static unsigned char txb[PKT_BUF_SZ * TX_RING_SIZE]; 259*1b8adde7SWilliam Kucharski 260*1b8adde7SWilliam Kucharski /* Define the RX Descriptor */ 261*1b8adde7SWilliam Kucharski static struct netdev_desc rx_ring[RX_RING_SIZE]; 262*1b8adde7SWilliam Kucharski 263*1b8adde7SWilliam Kucharski /* Create a static buffer of size PKT_BUF_SZ for each RX Descriptor. 264*1b8adde7SWilliam Kucharski All descriptors point to a part of this buffer */ 265*1b8adde7SWilliam Kucharski static unsigned char rxb[RX_RING_SIZE * PKT_BUF_SZ]; 266*1b8adde7SWilliam Kucharski 267*1b8adde7SWilliam Kucharski /* FIXME: Move BASE to the private structure */ 268*1b8adde7SWilliam Kucharski static u32 BASE; 269*1b8adde7SWilliam Kucharski #define EEPROM_SIZE 128 270*1b8adde7SWilliam Kucharski 271*1b8adde7SWilliam Kucharski enum pci_id_flags_bits { 272*1b8adde7SWilliam Kucharski PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4, 273*1b8adde7SWilliam Kucharski PCI_ADDR0 = 0 << 4, PCI_ADDR1 = 1 << 4, PCI_ADDR2 = 274*1b8adde7SWilliam Kucharski 2 << 4, PCI_ADDR3 = 3 << 4, 275*1b8adde7SWilliam Kucharski }; 276*1b8adde7SWilliam Kucharski 277*1b8adde7SWilliam Kucharski enum chip_capability_flags { CanHaveMII = 1, KendinPktDropBug = 2, }; 278*1b8adde7SWilliam Kucharski #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) 279*1b8adde7SWilliam Kucharski 280*1b8adde7SWilliam Kucharski #define MII_CNT 4 281*1b8adde7SWilliam Kucharski struct sundance_private { 282*1b8adde7SWilliam Kucharski const char *nic_name; 283*1b8adde7SWilliam Kucharski /* Frequently used values */ 284*1b8adde7SWilliam Kucharski 285*1b8adde7SWilliam Kucharski unsigned int cur_rx; /* Producer/consumer ring indicies */ 286*1b8adde7SWilliam Kucharski unsigned int mtu; 287*1b8adde7SWilliam Kucharski 288*1b8adde7SWilliam Kucharski /* These values keep track of the tranceiver/media in use */ 289*1b8adde7SWilliam Kucharski unsigned int flowctrl:1; 290*1b8adde7SWilliam Kucharski unsigned int an_enable:1; 291*1b8adde7SWilliam Kucharski 292*1b8adde7SWilliam Kucharski unsigned int speed; 293*1b8adde7SWilliam Kucharski 294*1b8adde7SWilliam Kucharski /* MII tranceiver section */ 295*1b8adde7SWilliam Kucharski struct mii_if_info mii_if; 296*1b8adde7SWilliam Kucharski int mii_preamble_required; 297*1b8adde7SWilliam Kucharski unsigned char phys[MII_CNT]; 298*1b8adde7SWilliam Kucharski unsigned char pci_rev_id; 299*1b8adde7SWilliam Kucharski } sdx; 300*1b8adde7SWilliam Kucharski 301*1b8adde7SWilliam Kucharski static struct sundance_private *sdc; 302*1b8adde7SWilliam Kucharski 303*1b8adde7SWilliam Kucharski /* Station Address location within the EEPROM */ 304*1b8adde7SWilliam Kucharski #define EEPROM_SA_OFFSET 0x10 305*1b8adde7SWilliam Kucharski #define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \ 306*1b8adde7SWilliam Kucharski IntrDrvRqst | IntrTxDone | StatsMax | \ 307*1b8adde7SWilliam Kucharski LinkChange) 308*1b8adde7SWilliam Kucharski 309*1b8adde7SWilliam Kucharski static int eeprom_read(long ioaddr, int location); 310*1b8adde7SWilliam Kucharski static int mdio_read(struct nic *nic, int phy_id, unsigned int location); 311*1b8adde7SWilliam Kucharski static void mdio_write(struct nic *nic, int phy_id, unsigned int location, 312*1b8adde7SWilliam Kucharski int value); 313*1b8adde7SWilliam Kucharski static void set_rx_mode(struct nic *nic); 314*1b8adde7SWilliam Kucharski 315*1b8adde7SWilliam Kucharski static void check_duplex(struct nic *nic) 316*1b8adde7SWilliam Kucharski { 317*1b8adde7SWilliam Kucharski int mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA); 318*1b8adde7SWilliam Kucharski int negotiated = mii_lpa & sdc->mii_if.advertising; 319*1b8adde7SWilliam Kucharski int duplex; 320*1b8adde7SWilliam Kucharski 321*1b8adde7SWilliam Kucharski /* Force media */ 322*1b8adde7SWilliam Kucharski if (!sdc->an_enable || mii_lpa == 0xffff) { 323*1b8adde7SWilliam Kucharski if (sdc->mii_if.full_duplex) 324*1b8adde7SWilliam Kucharski outw(inw(BASE + MACCtrl0) | EnbFullDuplex, 325*1b8adde7SWilliam Kucharski BASE + MACCtrl0); 326*1b8adde7SWilliam Kucharski return; 327*1b8adde7SWilliam Kucharski } 328*1b8adde7SWilliam Kucharski 329*1b8adde7SWilliam Kucharski /* Autonegotiation */ 330*1b8adde7SWilliam Kucharski duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; 331*1b8adde7SWilliam Kucharski if (sdc->mii_if.full_duplex != duplex) { 332*1b8adde7SWilliam Kucharski sdc->mii_if.full_duplex = duplex; 333*1b8adde7SWilliam Kucharski dprintf(("%s: Setting %s-duplex based on MII #%d " 334*1b8adde7SWilliam Kucharski "negotiated capability %4.4x.\n", sdc->nic_name, 335*1b8adde7SWilliam Kucharski duplex ? "full" : "half", sdc->phys[0], 336*1b8adde7SWilliam Kucharski negotiated)); 337*1b8adde7SWilliam Kucharski outw(inw(BASE + MACCtrl0) | duplex ? 0x20 : 0, 338*1b8adde7SWilliam Kucharski BASE + MACCtrl0); 339*1b8adde7SWilliam Kucharski } 340*1b8adde7SWilliam Kucharski } 341*1b8adde7SWilliam Kucharski 342*1b8adde7SWilliam Kucharski 343*1b8adde7SWilliam Kucharski /************************************************************************** 344*1b8adde7SWilliam Kucharski * init_ring - setup the tx and rx descriptors 345*1b8adde7SWilliam Kucharski *************************************************************************/ 346*1b8adde7SWilliam Kucharski static void init_ring(struct nic *nic __unused) 347*1b8adde7SWilliam Kucharski { 348*1b8adde7SWilliam Kucharski int i; 349*1b8adde7SWilliam Kucharski 350*1b8adde7SWilliam Kucharski sdc->cur_rx = 0; 351*1b8adde7SWilliam Kucharski 352*1b8adde7SWilliam Kucharski /* Initialize all the Rx descriptors */ 353*1b8adde7SWilliam Kucharski for (i = 0; i < RX_RING_SIZE; i++) { 354*1b8adde7SWilliam Kucharski rx_ring[i].next_desc = virt_to_le32desc(&rx_ring[i + 1]); 355*1b8adde7SWilliam Kucharski rx_ring[i].status = 0; 356*1b8adde7SWilliam Kucharski rx_ring[i].length = 0; 357*1b8adde7SWilliam Kucharski rx_ring[i].addr = 0; 358*1b8adde7SWilliam Kucharski } 359*1b8adde7SWilliam Kucharski 360*1b8adde7SWilliam Kucharski /* Mark the last entry as wrapping the ring */ 361*1b8adde7SWilliam Kucharski rx_ring[i - 1].next_desc = virt_to_le32desc(&rx_ring[0]); 362*1b8adde7SWilliam Kucharski 363*1b8adde7SWilliam Kucharski for (i = 0; i < RX_RING_SIZE; i++) { 364*1b8adde7SWilliam Kucharski rx_ring[i].addr = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]); 365*1b8adde7SWilliam Kucharski rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LastFrag); 366*1b8adde7SWilliam Kucharski } 367*1b8adde7SWilliam Kucharski 368*1b8adde7SWilliam Kucharski /* We only use one transmit buffer, but two 369*1b8adde7SWilliam Kucharski * descriptors so transmit engines have somewhere 370*1b8adde7SWilliam Kucharski * to point should they feel the need */ 371*1b8adde7SWilliam Kucharski tx_ring[0].status = 0x00000000; 372*1b8adde7SWilliam Kucharski tx_ring[0].addr = virt_to_bus(&txb[0]); 373*1b8adde7SWilliam Kucharski tx_ring[0].next_desc = 0; /* virt_to_bus(&tx_ring[1]); */ 374*1b8adde7SWilliam Kucharski 375*1b8adde7SWilliam Kucharski /* This descriptor is never used */ 376*1b8adde7SWilliam Kucharski tx_ring[1].status = 0x00000000; 377*1b8adde7SWilliam Kucharski tx_ring[1].addr = 0; /*virt_to_bus(&txb[0]); */ 378*1b8adde7SWilliam Kucharski tx_ring[1].next_desc = 0; 379*1b8adde7SWilliam Kucharski 380*1b8adde7SWilliam Kucharski /* Mark the last entry as wrapping the ring, 381*1b8adde7SWilliam Kucharski * though this should never happen */ 382*1b8adde7SWilliam Kucharski tx_ring[1].length = cpu_to_le32(LastFrag | PKT_BUF_SZ); 383*1b8adde7SWilliam Kucharski } 384*1b8adde7SWilliam Kucharski 385*1b8adde7SWilliam Kucharski /************************************************************************** 386*1b8adde7SWilliam Kucharski * RESET - Reset Adapter 387*1b8adde7SWilliam Kucharski * ***********************************************************************/ 388*1b8adde7SWilliam Kucharski static void sundance_reset(struct nic *nic) 389*1b8adde7SWilliam Kucharski { 390*1b8adde7SWilliam Kucharski int i; 391*1b8adde7SWilliam Kucharski 392*1b8adde7SWilliam Kucharski init_ring(nic); 393*1b8adde7SWilliam Kucharski 394*1b8adde7SWilliam Kucharski outl(virt_to_le32desc(&rx_ring[0]), BASE + RxListPtr); 395*1b8adde7SWilliam Kucharski /* The Tx List Pointer is written as packets are queued */ 396*1b8adde7SWilliam Kucharski 397*1b8adde7SWilliam Kucharski /* Initialize other registers. */ 398*1b8adde7SWilliam Kucharski /* __set_mac_addr(dev); */ 399*1b8adde7SWilliam Kucharski { 400*1b8adde7SWilliam Kucharski u16 addr16; 401*1b8adde7SWilliam Kucharski 402*1b8adde7SWilliam Kucharski addr16 = (nic->node_addr[0] | (nic->node_addr[1] << 8)); 403*1b8adde7SWilliam Kucharski outw(addr16, BASE + StationAddr); 404*1b8adde7SWilliam Kucharski addr16 = (nic->node_addr[2] | (nic->node_addr[3] << 8)); 405*1b8adde7SWilliam Kucharski outw(addr16, BASE + StationAddr + 2); 406*1b8adde7SWilliam Kucharski addr16 = (nic->node_addr[4] | (nic->node_addr[5] << 8)); 407*1b8adde7SWilliam Kucharski outw(addr16, BASE + StationAddr + 4); 408*1b8adde7SWilliam Kucharski } 409*1b8adde7SWilliam Kucharski 410*1b8adde7SWilliam Kucharski outw(sdc->mtu + 14, BASE + MaxFrameSize); 411*1b8adde7SWilliam Kucharski if (sdc->mtu > 2047) /* this will never happen with default options */ 412*1b8adde7SWilliam Kucharski outl(inl(BASE + ASICCtrl) | 0x0c, BASE + ASICCtrl); 413*1b8adde7SWilliam Kucharski 414*1b8adde7SWilliam Kucharski set_rx_mode(nic); 415*1b8adde7SWilliam Kucharski 416*1b8adde7SWilliam Kucharski outw(0, BASE + DownCounter); 417*1b8adde7SWilliam Kucharski /* Set the chip to poll every N*30nsec */ 418*1b8adde7SWilliam Kucharski outb(100, BASE + RxDMAPollPeriod); 419*1b8adde7SWilliam Kucharski 420*1b8adde7SWilliam Kucharski /* Fix DFE-580TX packet drop issue */ 421*1b8adde7SWilliam Kucharski if (sdc->pci_rev_id >= 0x14) 422*1b8adde7SWilliam Kucharski writeb(0x01, BASE + DebugCtrl1); 423*1b8adde7SWilliam Kucharski 424*1b8adde7SWilliam Kucharski outw(RxEnable | TxEnable, BASE + MACCtrl1); 425*1b8adde7SWilliam Kucharski 426*1b8adde7SWilliam Kucharski /* Construct a perfect filter frame with the mac address as first match 427*1b8adde7SWilliam Kucharski * and broadcast for all others */ 428*1b8adde7SWilliam Kucharski for (i = 0; i < 192; i++) 429*1b8adde7SWilliam Kucharski txb[i] = 0xFF; 430*1b8adde7SWilliam Kucharski 431*1b8adde7SWilliam Kucharski txb[0] = nic->node_addr[0]; 432*1b8adde7SWilliam Kucharski txb[1] = nic->node_addr[1]; 433*1b8adde7SWilliam Kucharski txb[2] = nic->node_addr[2]; 434*1b8adde7SWilliam Kucharski txb[3] = nic->node_addr[3]; 435*1b8adde7SWilliam Kucharski txb[4] = nic->node_addr[4]; 436*1b8adde7SWilliam Kucharski txb[5] = nic->node_addr[5]; 437*1b8adde7SWilliam Kucharski 438*1b8adde7SWilliam Kucharski dprintf(("%s: Done sundance_reset, status: Rx %hX Tx %hX " 439*1b8adde7SWilliam Kucharski "MAC Control %hX, %hX %hX\n", 440*1b8adde7SWilliam Kucharski sdc->nic_name, (int) inl(BASE + RxStatus), 441*1b8adde7SWilliam Kucharski (int) inw(BASE + TxStatus), (int) inl(BASE + MACCtrl0), 442*1b8adde7SWilliam Kucharski (int) inw(BASE + MACCtrl1), (int) inw(BASE + MACCtrl0))); 443*1b8adde7SWilliam Kucharski } 444*1b8adde7SWilliam Kucharski 445*1b8adde7SWilliam Kucharski /************************************************************************** 446*1b8adde7SWilliam Kucharski IRQ - Wait for a frame 447*1b8adde7SWilliam Kucharski ***************************************************************************/ 448*1b8adde7SWilliam Kucharski void sundance_irq ( struct nic *nic, irq_action_t action ) { 449*1b8adde7SWilliam Kucharski unsigned int intr_status; 450*1b8adde7SWilliam Kucharski 451*1b8adde7SWilliam Kucharski switch ( action ) { 452*1b8adde7SWilliam Kucharski case DISABLE : 453*1b8adde7SWilliam Kucharski case ENABLE : 454*1b8adde7SWilliam Kucharski intr_status = inw(nic->ioaddr + IntrStatus); 455*1b8adde7SWilliam Kucharski intr_status = intr_status & ~DEFAULT_INTR; 456*1b8adde7SWilliam Kucharski if ( action == ENABLE ) 457*1b8adde7SWilliam Kucharski intr_status = intr_status | DEFAULT_INTR; 458*1b8adde7SWilliam Kucharski outw(intr_status, nic->ioaddr + IntrEnable); 459*1b8adde7SWilliam Kucharski break; 460*1b8adde7SWilliam Kucharski case FORCE : 461*1b8adde7SWilliam Kucharski outw(0x0200, BASE + ASICCtrl); 462*1b8adde7SWilliam Kucharski break; 463*1b8adde7SWilliam Kucharski } 464*1b8adde7SWilliam Kucharski } 465*1b8adde7SWilliam Kucharski /************************************************************************** 466*1b8adde7SWilliam Kucharski POLL - Wait for a frame 467*1b8adde7SWilliam Kucharski ***************************************************************************/ 468*1b8adde7SWilliam Kucharski static int sundance_poll(struct nic *nic, int retreive) 469*1b8adde7SWilliam Kucharski { 470*1b8adde7SWilliam Kucharski /* return true if there's an ethernet packet ready to read */ 471*1b8adde7SWilliam Kucharski /* nic->packet should contain data on return */ 472*1b8adde7SWilliam Kucharski /* nic->packetlen should contain length of data */ 473*1b8adde7SWilliam Kucharski int entry = sdc->cur_rx % RX_RING_SIZE; 474*1b8adde7SWilliam Kucharski u32 frame_status = le32_to_cpu(rx_ring[entry].status); 475*1b8adde7SWilliam Kucharski int intr_status; 476*1b8adde7SWilliam Kucharski int pkt_len = 0; 477*1b8adde7SWilliam Kucharski 478*1b8adde7SWilliam Kucharski if (!(frame_status & DescOwn)) 479*1b8adde7SWilliam Kucharski return 0; 480*1b8adde7SWilliam Kucharski 481*1b8adde7SWilliam Kucharski /* There is a packet ready */ 482*1b8adde7SWilliam Kucharski if(!retreive) 483*1b8adde7SWilliam Kucharski return 1; 484*1b8adde7SWilliam Kucharski 485*1b8adde7SWilliam Kucharski intr_status = inw(nic->ioaddr + IntrStatus); 486*1b8adde7SWilliam Kucharski outw(intr_status, nic->ioaddr + IntrStatus); 487*1b8adde7SWilliam Kucharski 488*1b8adde7SWilliam Kucharski pkt_len = frame_status & 0x1fff; 489*1b8adde7SWilliam Kucharski 490*1b8adde7SWilliam Kucharski if (frame_status & 0x001f4000) { 491*1b8adde7SWilliam Kucharski dprintf(("Polling frame_status error\n")); /* Do we really care about this */ 492*1b8adde7SWilliam Kucharski } else { 493*1b8adde7SWilliam Kucharski if (pkt_len < rx_copybreak) { 494*1b8adde7SWilliam Kucharski /* FIXME: What should happen Will this ever occur */ 495*1b8adde7SWilliam Kucharski printf("Poll Error: pkt_len < rx_copybreak"); 496*1b8adde7SWilliam Kucharski } else { 497*1b8adde7SWilliam Kucharski nic->packetlen = pkt_len; 498*1b8adde7SWilliam Kucharski memcpy(nic->packet, rxb + 499*1b8adde7SWilliam Kucharski (sdc->cur_rx * PKT_BUF_SZ), nic->packetlen); 500*1b8adde7SWilliam Kucharski 501*1b8adde7SWilliam Kucharski } 502*1b8adde7SWilliam Kucharski } 503*1b8adde7SWilliam Kucharski rx_ring[entry].length = cpu_to_le32(PKT_BUF_SZ | LastFrag); 504*1b8adde7SWilliam Kucharski rx_ring[entry].status = 0; 505*1b8adde7SWilliam Kucharski entry++; 506*1b8adde7SWilliam Kucharski sdc->cur_rx = entry % RX_RING_SIZE; 507*1b8adde7SWilliam Kucharski outw(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone), 508*1b8adde7SWilliam Kucharski nic->ioaddr + IntrStatus); 509*1b8adde7SWilliam Kucharski return 1; 510*1b8adde7SWilliam Kucharski } 511*1b8adde7SWilliam Kucharski 512*1b8adde7SWilliam Kucharski /************************************************************************** 513*1b8adde7SWilliam Kucharski TRANSMIT - Transmit a frame 514*1b8adde7SWilliam Kucharski ***************************************************************************/ 515*1b8adde7SWilliam Kucharski static void sundance_transmit(struct nic *nic, const char *d, /* Destination */ 516*1b8adde7SWilliam Kucharski unsigned int t, /* Type */ 517*1b8adde7SWilliam Kucharski unsigned int s, /* size */ 518*1b8adde7SWilliam Kucharski const char *p) 519*1b8adde7SWilliam Kucharski { /* Packet */ 520*1b8adde7SWilliam Kucharski u16 nstype; 521*1b8adde7SWilliam Kucharski u32 to; 522*1b8adde7SWilliam Kucharski 523*1b8adde7SWilliam Kucharski /* Disable the Tx */ 524*1b8adde7SWilliam Kucharski outw(TxDisable, BASE + MACCtrl1); 525*1b8adde7SWilliam Kucharski 526*1b8adde7SWilliam Kucharski memcpy(txb, d, ETH_ALEN); 527*1b8adde7SWilliam Kucharski memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); 528*1b8adde7SWilliam Kucharski nstype = htons((u16) t); 529*1b8adde7SWilliam Kucharski memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2); 530*1b8adde7SWilliam Kucharski memcpy(txb + ETH_HLEN, p, s); 531*1b8adde7SWilliam Kucharski 532*1b8adde7SWilliam Kucharski s += ETH_HLEN; 533*1b8adde7SWilliam Kucharski s &= 0x0FFF; 534*1b8adde7SWilliam Kucharski while (s < ETH_ZLEN) 535*1b8adde7SWilliam Kucharski txb[s++] = '\0'; 536*1b8adde7SWilliam Kucharski 537*1b8adde7SWilliam Kucharski /* Setup the transmit descriptor */ 538*1b8adde7SWilliam Kucharski tx_ring[0].length = cpu_to_le32(s | LastFrag); 539*1b8adde7SWilliam Kucharski tx_ring[0].status = cpu_to_le32(0x00000001); 540*1b8adde7SWilliam Kucharski 541*1b8adde7SWilliam Kucharski /* Point to transmit descriptor */ 542*1b8adde7SWilliam Kucharski outl(virt_to_le32desc(&tx_ring[0]), BASE + TxListPtr); 543*1b8adde7SWilliam Kucharski 544*1b8adde7SWilliam Kucharski /* Enable Tx */ 545*1b8adde7SWilliam Kucharski outw(TxEnable, BASE + MACCtrl1); 546*1b8adde7SWilliam Kucharski /* Trigger an immediate send */ 547*1b8adde7SWilliam Kucharski outw(0, BASE + TxStatus); 548*1b8adde7SWilliam Kucharski 549*1b8adde7SWilliam Kucharski to = currticks() + TX_TIME_OUT; 550*1b8adde7SWilliam Kucharski while (!(tx_ring[0].status & 0x00010000) && (currticks() < to)); /* wait */ 551*1b8adde7SWilliam Kucharski 552*1b8adde7SWilliam Kucharski if (currticks() >= to) { 553*1b8adde7SWilliam Kucharski printf("TX Time Out"); 554*1b8adde7SWilliam Kucharski } 555*1b8adde7SWilliam Kucharski /* Disable Tx */ 556*1b8adde7SWilliam Kucharski outw(TxDisable, BASE + MACCtrl1); 557*1b8adde7SWilliam Kucharski 558*1b8adde7SWilliam Kucharski } 559*1b8adde7SWilliam Kucharski 560*1b8adde7SWilliam Kucharski /************************************************************************** 561*1b8adde7SWilliam Kucharski DISABLE - Turn off ethernet interface 562*1b8adde7SWilliam Kucharski ***************************************************************************/ 563*1b8adde7SWilliam Kucharski static void sundance_disable(struct dev *dev __unused) 564*1b8adde7SWilliam Kucharski { 565*1b8adde7SWilliam Kucharski /* put the card in its initial state */ 566*1b8adde7SWilliam Kucharski /* This function serves 3 purposes. 567*1b8adde7SWilliam Kucharski * This disables DMA and interrupts so we don't receive 568*1b8adde7SWilliam Kucharski * unexpected packets or interrupts from the card after 569*1b8adde7SWilliam Kucharski * etherboot has finished. 570*1b8adde7SWilliam Kucharski * This frees resources so etherboot may use 571*1b8adde7SWilliam Kucharski * this driver on another interface 572*1b8adde7SWilliam Kucharski * This allows etherboot to reinitialize the interface 573*1b8adde7SWilliam Kucharski * if something is something goes wrong. 574*1b8adde7SWilliam Kucharski */ 575*1b8adde7SWilliam Kucharski outw(0x0000, BASE + IntrEnable); 576*1b8adde7SWilliam Kucharski /* Stop the Chipchips Tx and Rx Status */ 577*1b8adde7SWilliam Kucharski outw(TxDisable | RxDisable | StatsDisable, BASE + MACCtrl1); 578*1b8adde7SWilliam Kucharski } 579*1b8adde7SWilliam Kucharski 580*1b8adde7SWilliam Kucharski 581*1b8adde7SWilliam Kucharski 582*1b8adde7SWilliam Kucharski /************************************************************************** 583*1b8adde7SWilliam Kucharski PROBE - Look for an adapter, this routine's visible to the outside 584*1b8adde7SWilliam Kucharski ***************************************************************************/ 585*1b8adde7SWilliam Kucharski static int sundance_probe(struct dev *dev, struct pci_device *pci) 586*1b8adde7SWilliam Kucharski { 587*1b8adde7SWilliam Kucharski struct nic *nic = (struct nic *) dev; 588*1b8adde7SWilliam Kucharski u8 ee_data[EEPROM_SIZE]; 589*1b8adde7SWilliam Kucharski u16 mii_ctl; 590*1b8adde7SWilliam Kucharski int i; 591*1b8adde7SWilliam Kucharski int speed; 592*1b8adde7SWilliam Kucharski 593*1b8adde7SWilliam Kucharski if (pci->ioaddr == 0) 594*1b8adde7SWilliam Kucharski return 0; 595*1b8adde7SWilliam Kucharski 596*1b8adde7SWilliam Kucharski /* BASE is used throughout to address the card */ 597*1b8adde7SWilliam Kucharski BASE = pci->ioaddr; 598*1b8adde7SWilliam Kucharski printf(" sundance.c: Found %s Vendor=0x%hX Device=0x%hX\n", 599*1b8adde7SWilliam Kucharski pci->name, pci->vendor, pci->dev_id); 600*1b8adde7SWilliam Kucharski 601*1b8adde7SWilliam Kucharski /* Get the MAC Address by reading the EEPROM */ 602*1b8adde7SWilliam Kucharski for (i = 0; i < 3; i++) { 603*1b8adde7SWilliam Kucharski ((u16 *) ee_data)[i] = 604*1b8adde7SWilliam Kucharski le16_to_cpu(eeprom_read(BASE, i + EEPROM_SA_OFFSET)); 605*1b8adde7SWilliam Kucharski } 606*1b8adde7SWilliam Kucharski /* Update the nic structure with the MAC Address */ 607*1b8adde7SWilliam Kucharski for (i = 0; i < ETH_ALEN; i++) { 608*1b8adde7SWilliam Kucharski nic->node_addr[i] = ee_data[i]; 609*1b8adde7SWilliam Kucharski } 610*1b8adde7SWilliam Kucharski 611*1b8adde7SWilliam Kucharski /* Set the card as PCI Bus Master */ 612*1b8adde7SWilliam Kucharski adjust_pci_device(pci); 613*1b8adde7SWilliam Kucharski 614*1b8adde7SWilliam Kucharski // sdc->mii_if.dev = pci; 615*1b8adde7SWilliam Kucharski // sdc->mii_if.phy_id_mask = 0x1f; 616*1b8adde7SWilliam Kucharski // sdc->mii_if.reg_num_mask = 0x1f; 617*1b8adde7SWilliam Kucharski 618*1b8adde7SWilliam Kucharski /* point to private storage */ 619*1b8adde7SWilliam Kucharski sdc = &sdx; 620*1b8adde7SWilliam Kucharski 621*1b8adde7SWilliam Kucharski sdc->nic_name = pci->name; 622*1b8adde7SWilliam Kucharski sdc->mtu = mtu; 623*1b8adde7SWilliam Kucharski 624*1b8adde7SWilliam Kucharski pci_read_config_byte(pci, PCI_REVISION_ID, &sdc->pci_rev_id); 625*1b8adde7SWilliam Kucharski dprintf(("Device revision id: %hx\n", sdc->pci_rev_id)); 626*1b8adde7SWilliam Kucharski /* Print out some hardware info */ 627*1b8adde7SWilliam Kucharski printf("%s: %! at ioaddr %hX, ", pci->name, nic->node_addr, BASE); 628*1b8adde7SWilliam Kucharski sdc->mii_preamble_required = 0; 629*1b8adde7SWilliam Kucharski if (1) { 630*1b8adde7SWilliam Kucharski int phy, phy_idx = 0; 631*1b8adde7SWilliam Kucharski sdc->phys[0] = 1; /* Default Setting */ 632*1b8adde7SWilliam Kucharski sdc->mii_preamble_required++; 633*1b8adde7SWilliam Kucharski for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { 634*1b8adde7SWilliam Kucharski int mii_status = mdio_read(nic, phy, MII_BMSR); 635*1b8adde7SWilliam Kucharski if (mii_status != 0xffff && mii_status != 0x0000) { 636*1b8adde7SWilliam Kucharski sdc->phys[phy_idx++] = phy; 637*1b8adde7SWilliam Kucharski sdc->mii_if.advertising = 638*1b8adde7SWilliam Kucharski mdio_read(nic, phy, MII_ADVERTISE); 639*1b8adde7SWilliam Kucharski if ((mii_status & 0x0040) == 0) 640*1b8adde7SWilliam Kucharski sdc->mii_preamble_required++; 641*1b8adde7SWilliam Kucharski dprintf 642*1b8adde7SWilliam Kucharski (("%s: MII PHY found at address %d, status " "%hX advertising %hX\n", sdc->nic_name, phy, mii_status, sdc->mii_if.advertising)); 643*1b8adde7SWilliam Kucharski } 644*1b8adde7SWilliam Kucharski } 645*1b8adde7SWilliam Kucharski sdc->mii_preamble_required--; 646*1b8adde7SWilliam Kucharski if (phy_idx == 0) 647*1b8adde7SWilliam Kucharski printf("%s: No MII transceiver found!\n", 648*1b8adde7SWilliam Kucharski sdc->nic_name); 649*1b8adde7SWilliam Kucharski sdc->mii_if.phy_id = sdc->phys[0]; 650*1b8adde7SWilliam Kucharski } 651*1b8adde7SWilliam Kucharski 652*1b8adde7SWilliam Kucharski /* Parse override configuration */ 653*1b8adde7SWilliam Kucharski sdc->an_enable = 1; 654*1b8adde7SWilliam Kucharski if (strcasecmp(media, "autosense") != 0) { 655*1b8adde7SWilliam Kucharski sdc->an_enable = 0; 656*1b8adde7SWilliam Kucharski if (strcasecmp(media, "100mbps_fd") == 0 || 657*1b8adde7SWilliam Kucharski strcasecmp(media, "4") == 0) { 658*1b8adde7SWilliam Kucharski sdc->speed = 100; 659*1b8adde7SWilliam Kucharski sdc->mii_if.full_duplex = 1; 660*1b8adde7SWilliam Kucharski } else if (strcasecmp(media, "100mbps_hd") == 0 661*1b8adde7SWilliam Kucharski || strcasecmp(media, "3") == 0) { 662*1b8adde7SWilliam Kucharski sdc->speed = 100; 663*1b8adde7SWilliam Kucharski sdc->mii_if.full_duplex = 0; 664*1b8adde7SWilliam Kucharski } else if (strcasecmp(media, "10mbps_fd") == 0 || 665*1b8adde7SWilliam Kucharski strcasecmp(media, "2") == 0) { 666*1b8adde7SWilliam Kucharski sdc->speed = 10; 667*1b8adde7SWilliam Kucharski sdc->mii_if.full_duplex = 1; 668*1b8adde7SWilliam Kucharski } else if (strcasecmp(media, "10mbps_hd") == 0 || 669*1b8adde7SWilliam Kucharski strcasecmp(media, "1") == 0) { 670*1b8adde7SWilliam Kucharski sdc->speed = 10; 671*1b8adde7SWilliam Kucharski sdc->mii_if.full_duplex = 0; 672*1b8adde7SWilliam Kucharski } else { 673*1b8adde7SWilliam Kucharski sdc->an_enable = 1; 674*1b8adde7SWilliam Kucharski } 675*1b8adde7SWilliam Kucharski } 676*1b8adde7SWilliam Kucharski if (flowctrl == 1) 677*1b8adde7SWilliam Kucharski sdc->flowctrl = 1; 678*1b8adde7SWilliam Kucharski 679*1b8adde7SWilliam Kucharski /* Fibre PHY? */ 680*1b8adde7SWilliam Kucharski if (inl(BASE + ASICCtrl) & 0x80) { 681*1b8adde7SWilliam Kucharski /* Default 100Mbps Full */ 682*1b8adde7SWilliam Kucharski if (sdc->an_enable) { 683*1b8adde7SWilliam Kucharski sdc->speed = 100; 684*1b8adde7SWilliam Kucharski sdc->mii_if.full_duplex = 1; 685*1b8adde7SWilliam Kucharski sdc->an_enable = 0; 686*1b8adde7SWilliam Kucharski } 687*1b8adde7SWilliam Kucharski } 688*1b8adde7SWilliam Kucharski 689*1b8adde7SWilliam Kucharski /* The Linux driver uses flow control and resets the link here. This means the 690*1b8adde7SWilliam Kucharski mii section from above would need to be re done I believe. Since it serves 691*1b8adde7SWilliam Kucharski no real purpose leave it out. */ 692*1b8adde7SWilliam Kucharski 693*1b8adde7SWilliam Kucharski /* Force media type */ 694*1b8adde7SWilliam Kucharski if (!sdc->an_enable) { 695*1b8adde7SWilliam Kucharski mii_ctl = 0; 696*1b8adde7SWilliam Kucharski mii_ctl |= (sdc->speed == 100) ? BMCR_SPEED100 : 0; 697*1b8adde7SWilliam Kucharski mii_ctl |= (sdc->mii_if.full_duplex) ? BMCR_FULLDPLX : 0; 698*1b8adde7SWilliam Kucharski mdio_write(nic, sdc->phys[0], MII_BMCR, mii_ctl); 699*1b8adde7SWilliam Kucharski printf("Override speed=%d, %s duplex\n", 700*1b8adde7SWilliam Kucharski sdc->speed, 701*1b8adde7SWilliam Kucharski sdc->mii_if.full_duplex ? "Full" : "Half"); 702*1b8adde7SWilliam Kucharski } 703*1b8adde7SWilliam Kucharski 704*1b8adde7SWilliam Kucharski /* Reset the chip to erase previous misconfiguration */ 705*1b8adde7SWilliam Kucharski dprintf(("ASIC Control is %x.\n", inl(BASE + ASICCtrl))); 706*1b8adde7SWilliam Kucharski outw(0x007f, BASE + ASICCtrl + 2); 707*1b8adde7SWilliam Kucharski dprintf(("ASIC Control is now %x.\n", inl(BASE + ASICCtrl))); 708*1b8adde7SWilliam Kucharski 709*1b8adde7SWilliam Kucharski sundance_reset(nic); 710*1b8adde7SWilliam Kucharski if (sdc->an_enable) { 711*1b8adde7SWilliam Kucharski u16 mii_advertise, mii_lpa; 712*1b8adde7SWilliam Kucharski mii_advertise = 713*1b8adde7SWilliam Kucharski mdio_read(nic, sdc->phys[0], MII_ADVERTISE); 714*1b8adde7SWilliam Kucharski mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA); 715*1b8adde7SWilliam Kucharski mii_advertise &= mii_lpa; 716*1b8adde7SWilliam Kucharski if (mii_advertise & ADVERTISE_100FULL) 717*1b8adde7SWilliam Kucharski sdc->speed = 100; 718*1b8adde7SWilliam Kucharski else if (mii_advertise & ADVERTISE_100HALF) 719*1b8adde7SWilliam Kucharski sdc->speed = 100; 720*1b8adde7SWilliam Kucharski else if (mii_advertise & ADVERTISE_10FULL) 721*1b8adde7SWilliam Kucharski sdc->speed = 10; 722*1b8adde7SWilliam Kucharski else if (mii_advertise & ADVERTISE_10HALF) 723*1b8adde7SWilliam Kucharski sdc->speed = 10; 724*1b8adde7SWilliam Kucharski } else { 725*1b8adde7SWilliam Kucharski mii_ctl = mdio_read(nic, sdc->phys[0], MII_BMCR); 726*1b8adde7SWilliam Kucharski speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; 727*1b8adde7SWilliam Kucharski sdc->speed = speed; 728*1b8adde7SWilliam Kucharski printf("%s: Link changed: %dMbps ,", sdc->nic_name, speed); 729*1b8adde7SWilliam Kucharski printf("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ? 730*1b8adde7SWilliam Kucharski "full" : "half"); 731*1b8adde7SWilliam Kucharski } 732*1b8adde7SWilliam Kucharski check_duplex(nic); 733*1b8adde7SWilliam Kucharski if (sdc->flowctrl && sdc->mii_if.full_duplex) { 734*1b8adde7SWilliam Kucharski outw(inw(BASE + MulticastFilter1 + 2) | 0x0200, 735*1b8adde7SWilliam Kucharski BASE + MulticastFilter1 + 2); 736*1b8adde7SWilliam Kucharski outw(inw(BASE + MACCtrl0) | EnbFlowCtrl, BASE + MACCtrl0); 737*1b8adde7SWilliam Kucharski } 738*1b8adde7SWilliam Kucharski printf("%dMbps, %s-Duplex\n", sdc->speed, 739*1b8adde7SWilliam Kucharski sdc->mii_if.full_duplex ? "Full" : "Half"); 740*1b8adde7SWilliam Kucharski 741*1b8adde7SWilliam Kucharski /* point to NIC specific routines */ 742*1b8adde7SWilliam Kucharski dev->disable = sundance_disable; 743*1b8adde7SWilliam Kucharski nic->poll = sundance_poll; 744*1b8adde7SWilliam Kucharski nic->transmit = sundance_transmit; 745*1b8adde7SWilliam Kucharski nic->irqno = pci->irq; 746*1b8adde7SWilliam Kucharski nic->irq = sundance_irq; 747*1b8adde7SWilliam Kucharski nic->ioaddr = BASE; 748*1b8adde7SWilliam Kucharski 749*1b8adde7SWilliam Kucharski return 1; 750*1b8adde7SWilliam Kucharski } 751*1b8adde7SWilliam Kucharski 752*1b8adde7SWilliam Kucharski 753*1b8adde7SWilliam Kucharski /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ 754*1b8adde7SWilliam Kucharski static int eeprom_read(long ioaddr, int location) 755*1b8adde7SWilliam Kucharski { 756*1b8adde7SWilliam Kucharski int boguscnt = 10000; /* Typical 1900 ticks */ 757*1b8adde7SWilliam Kucharski outw(0x0200 | (location & 0xff), ioaddr + EECtrl); 758*1b8adde7SWilliam Kucharski do { 759*1b8adde7SWilliam Kucharski if (!(inw(ioaddr + EECtrl) & 0x8000)) { 760*1b8adde7SWilliam Kucharski return inw(ioaddr + EEData); 761*1b8adde7SWilliam Kucharski } 762*1b8adde7SWilliam Kucharski } 763*1b8adde7SWilliam Kucharski while (--boguscnt > 0); 764*1b8adde7SWilliam Kucharski return 0; 765*1b8adde7SWilliam Kucharski } 766*1b8adde7SWilliam Kucharski 767*1b8adde7SWilliam Kucharski /* MII transceiver control section. 768*1b8adde7SWilliam Kucharski Read and write the MII registers using software-generated serial 769*1b8adde7SWilliam Kucharski MDIO protocol. See the MII specifications or DP83840A data sheet 770*1b8adde7SWilliam Kucharski for details. 771*1b8adde7SWilliam Kucharski 772*1b8adde7SWilliam Kucharski The maximum data clock rate is 2.5 Mhz. 773*1b8adde7SWilliam Kucharski The timing is decoupled from the processor clock by flushing the write 774*1b8adde7SWilliam Kucharski from the CPU write buffer with a following read, and using PCI 775*1b8adde7SWilliam Kucharski transaction time. */ 776*1b8adde7SWilliam Kucharski 777*1b8adde7SWilliam Kucharski #define mdio_in(mdio_addr) inb(mdio_addr) 778*1b8adde7SWilliam Kucharski #define mdio_out(value, mdio_addr) outb(value, mdio_addr) 779*1b8adde7SWilliam Kucharski #define mdio_delay(mdio_addr) inb(mdio_addr) 780*1b8adde7SWilliam Kucharski 781*1b8adde7SWilliam Kucharski enum mii_reg_bits { 782*1b8adde7SWilliam Kucharski MDIO_ShiftClk = 0x0001, MDIO_Data = 0x0002, MDIO_EnbOutput = 783*1b8adde7SWilliam Kucharski 0x0004, 784*1b8adde7SWilliam Kucharski }; 785*1b8adde7SWilliam Kucharski #define MDIO_EnbIn (0) 786*1b8adde7SWilliam Kucharski #define MDIO_WRITE0 (MDIO_EnbOutput) 787*1b8adde7SWilliam Kucharski #define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput) 788*1b8adde7SWilliam Kucharski 789*1b8adde7SWilliam Kucharski /* Generate the preamble required for initial synchronization and 790*1b8adde7SWilliam Kucharski a few older transceivers. */ 791*1b8adde7SWilliam Kucharski static void mdio_sync(long mdio_addr) 792*1b8adde7SWilliam Kucharski { 793*1b8adde7SWilliam Kucharski int bits = 32; 794*1b8adde7SWilliam Kucharski 795*1b8adde7SWilliam Kucharski /* Establish sync by sending at least 32 logic ones. */ 796*1b8adde7SWilliam Kucharski while (--bits >= 0) { 797*1b8adde7SWilliam Kucharski mdio_out(MDIO_WRITE1, mdio_addr); 798*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 799*1b8adde7SWilliam Kucharski mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); 800*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 801*1b8adde7SWilliam Kucharski } 802*1b8adde7SWilliam Kucharski } 803*1b8adde7SWilliam Kucharski 804*1b8adde7SWilliam Kucharski static int 805*1b8adde7SWilliam Kucharski mdio_read(struct nic *nic __unused, int phy_id, unsigned int location) 806*1b8adde7SWilliam Kucharski { 807*1b8adde7SWilliam Kucharski long mdio_addr = BASE + MIICtrl; 808*1b8adde7SWilliam Kucharski int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; 809*1b8adde7SWilliam Kucharski int i, retval = 0; 810*1b8adde7SWilliam Kucharski 811*1b8adde7SWilliam Kucharski if (sdc->mii_preamble_required) 812*1b8adde7SWilliam Kucharski mdio_sync(mdio_addr); 813*1b8adde7SWilliam Kucharski 814*1b8adde7SWilliam Kucharski /* Shift the read command bits out. */ 815*1b8adde7SWilliam Kucharski for (i = 15; i >= 0; i--) { 816*1b8adde7SWilliam Kucharski int dataval = 817*1b8adde7SWilliam Kucharski (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; 818*1b8adde7SWilliam Kucharski 819*1b8adde7SWilliam Kucharski mdio_out(dataval, mdio_addr); 820*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 821*1b8adde7SWilliam Kucharski mdio_out(dataval | MDIO_ShiftClk, mdio_addr); 822*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 823*1b8adde7SWilliam Kucharski } 824*1b8adde7SWilliam Kucharski /* Read the two transition, 16 data, and wire-idle bits. */ 825*1b8adde7SWilliam Kucharski for (i = 19; i > 0; i--) { 826*1b8adde7SWilliam Kucharski mdio_out(MDIO_EnbIn, mdio_addr); 827*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 828*1b8adde7SWilliam Kucharski retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data) 829*1b8adde7SWilliam Kucharski ? 1 : 0); 830*1b8adde7SWilliam Kucharski mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); 831*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 832*1b8adde7SWilliam Kucharski } 833*1b8adde7SWilliam Kucharski return (retval >> 1) & 0xffff; 834*1b8adde7SWilliam Kucharski } 835*1b8adde7SWilliam Kucharski 836*1b8adde7SWilliam Kucharski static void 837*1b8adde7SWilliam Kucharski mdio_write(struct nic *nic __unused, int phy_id, 838*1b8adde7SWilliam Kucharski unsigned int location, int value) 839*1b8adde7SWilliam Kucharski { 840*1b8adde7SWilliam Kucharski long mdio_addr = BASE + MIICtrl; 841*1b8adde7SWilliam Kucharski int mii_cmd = 842*1b8adde7SWilliam Kucharski (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; 843*1b8adde7SWilliam Kucharski int i; 844*1b8adde7SWilliam Kucharski 845*1b8adde7SWilliam Kucharski if (sdc->mii_preamble_required) 846*1b8adde7SWilliam Kucharski mdio_sync(mdio_addr); 847*1b8adde7SWilliam Kucharski 848*1b8adde7SWilliam Kucharski /* Shift the command bits out. */ 849*1b8adde7SWilliam Kucharski for (i = 31; i >= 0; i--) { 850*1b8adde7SWilliam Kucharski int dataval = 851*1b8adde7SWilliam Kucharski (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; 852*1b8adde7SWilliam Kucharski mdio_out(dataval, mdio_addr); 853*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 854*1b8adde7SWilliam Kucharski mdio_out(dataval | MDIO_ShiftClk, mdio_addr); 855*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 856*1b8adde7SWilliam Kucharski } 857*1b8adde7SWilliam Kucharski /* Clear out extra bits. */ 858*1b8adde7SWilliam Kucharski for (i = 2; i > 0; i--) { 859*1b8adde7SWilliam Kucharski mdio_out(MDIO_EnbIn, mdio_addr); 860*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 861*1b8adde7SWilliam Kucharski mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); 862*1b8adde7SWilliam Kucharski mdio_delay(mdio_addr); 863*1b8adde7SWilliam Kucharski } 864*1b8adde7SWilliam Kucharski return; 865*1b8adde7SWilliam Kucharski } 866*1b8adde7SWilliam Kucharski 867*1b8adde7SWilliam Kucharski static void set_rx_mode(struct nic *nic __unused) 868*1b8adde7SWilliam Kucharski { 869*1b8adde7SWilliam Kucharski int i; 870*1b8adde7SWilliam Kucharski u16 mc_filter[4]; /* Multicast hash filter */ 871*1b8adde7SWilliam Kucharski u32 rx_mode; 872*1b8adde7SWilliam Kucharski 873*1b8adde7SWilliam Kucharski memset(mc_filter, 0xff, sizeof(mc_filter)); 874*1b8adde7SWilliam Kucharski rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; 875*1b8adde7SWilliam Kucharski 876*1b8adde7SWilliam Kucharski if (sdc->mii_if.full_duplex && sdc->flowctrl) 877*1b8adde7SWilliam Kucharski mc_filter[3] |= 0x0200; 878*1b8adde7SWilliam Kucharski for (i = 0; i < 4; i++) 879*1b8adde7SWilliam Kucharski outw(mc_filter[i], BASE + MulticastFilter0 + i * 2); 880*1b8adde7SWilliam Kucharski outb(rx_mode, BASE + RxMode); 881*1b8adde7SWilliam Kucharski return; 882*1b8adde7SWilliam Kucharski } 883*1b8adde7SWilliam Kucharski 884*1b8adde7SWilliam Kucharski static struct pci_id sundance_nics[] = { 885*1b8adde7SWilliam Kucharski PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor"), 886*1b8adde7SWilliam Kucharski PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)"), 887*1b8adde7SWilliam Kucharski }; 888*1b8adde7SWilliam Kucharski 889*1b8adde7SWilliam Kucharski struct pci_driver sundance_driver = { 890*1b8adde7SWilliam Kucharski .type = NIC_DRIVER, 891*1b8adde7SWilliam Kucharski .name = "SUNDANCE/PCI", 892*1b8adde7SWilliam Kucharski .probe = sundance_probe, 893*1b8adde7SWilliam Kucharski .ids = sundance_nics, 894*1b8adde7SWilliam Kucharski .id_count = sizeof(sundance_nics) / sizeof(sundance_nics[0]), 895*1b8adde7SWilliam Kucharski .class = 0, 896*1b8adde7SWilliam Kucharski }; 897