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
check_duplex(struct nic * nic)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 *************************************************************************/
init_ring(struct nic * nic __unused)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 * ***********************************************************************/
sundance_reset(struct nic * nic)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 ***************************************************************************/
sundance_irq(struct nic * nic,irq_action_t action)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 ***************************************************************************/
sundance_poll(struct nic * nic,int retreive)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 ***************************************************************************/
sundance_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)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 ***************************************************************************/
sundance_disable(struct dev * dev __unused)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 ***************************************************************************/
sundance_probe(struct dev * dev,struct pci_device * pci)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. */
eeprom_read(long ioaddr,int location)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. */
mdio_sync(long mdio_addr)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
mdio_read(struct nic * nic __unused,int phy_id,unsigned int location)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
mdio_write(struct nic * nic __unused,int phy_id,unsigned int location,int value)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
set_rx_mode(struct nic * nic __unused)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