17c478bd9Sstevel@tonic-gate #define EB51
27c478bd9Sstevel@tonic-gate
37c478bd9Sstevel@tonic-gate #ifdef EB50
47c478bd9Sstevel@tonic-gate #define __unused __attribute__((unused))
57c478bd9Sstevel@tonic-gate #endif
67c478bd9Sstevel@tonic-gate
77c478bd9Sstevel@tonic-gate /**************************************************************************
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * tlan.c -- Etherboot device driver for the Texas Instruments ThunderLAN
107c478bd9Sstevel@tonic-gate * Written 2003-2003 by Timothy Legge <tlegge@rogers.com>
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate * This program is free software; you can redistribute it and/or modify
137c478bd9Sstevel@tonic-gate * it under the terms of the GNU General Public License as published by
147c478bd9Sstevel@tonic-gate * the Free Software Foundation; either version 2 of the License, or
157c478bd9Sstevel@tonic-gate * (at your option) any later version.
167c478bd9Sstevel@tonic-gate *
177c478bd9Sstevel@tonic-gate * This program is distributed in the hope that it will be useful,
187c478bd9Sstevel@tonic-gate * but WITHOUT ANY WARRANTY; without even the implied warranty of
197c478bd9Sstevel@tonic-gate * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
207c478bd9Sstevel@tonic-gate * GNU General Public License for more details.
217c478bd9Sstevel@tonic-gate *
227c478bd9Sstevel@tonic-gate * You should have received a copy of the GNU General Public License
237c478bd9Sstevel@tonic-gate * along with this program; if not, write to the Free Software
247c478bd9Sstevel@tonic-gate * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
257c478bd9Sstevel@tonic-gate *
267c478bd9Sstevel@tonic-gate * Portions of this code based on:
277c478bd9Sstevel@tonic-gate * lan.c: Linux ThunderLan Driver:
287c478bd9Sstevel@tonic-gate *
297c478bd9Sstevel@tonic-gate * by James Banks
307c478bd9Sstevel@tonic-gate *
317c478bd9Sstevel@tonic-gate * (C) 1997-1998 Caldera, Inc.
327c478bd9Sstevel@tonic-gate * (C) 1998 James Banks
337c478bd9Sstevel@tonic-gate * (C) 1999-2001 Torben Mathiasen
347c478bd9Sstevel@tonic-gate * (C) 2002 Samuel Chessman
357c478bd9Sstevel@tonic-gate *
367c478bd9Sstevel@tonic-gate * REVISION HISTORY:
377c478bd9Sstevel@tonic-gate * ================
387c478bd9Sstevel@tonic-gate * v1.0 07-08-2003 timlegge Initial not quite working version
397c478bd9Sstevel@tonic-gate * v1.1 07-27-2003 timlegge Sync 5.0 and 5.1 versions
407c478bd9Sstevel@tonic-gate * v1.2 08-19-2003 timlegge Implement Multicast Support
417c478bd9Sstevel@tonic-gate * v1.3 08-23-2003 timlegge Fix the transmit Function
427c478bd9Sstevel@tonic-gate * v1.4 01-17-2004 timlegge Initial driver output cleanup
437c478bd9Sstevel@tonic-gate *
447c478bd9Sstevel@tonic-gate * Indent Options: indent -kr -i8
457c478bd9Sstevel@tonic-gate ***************************************************************************/
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate /* to get some global routines like printf */
487c478bd9Sstevel@tonic-gate #include "etherboot.h"
497c478bd9Sstevel@tonic-gate /* to get the interface to the body of the program */
507c478bd9Sstevel@tonic-gate #include "nic.h"
517c478bd9Sstevel@tonic-gate /* to get the PCI support functions, if this is a PCI NIC */
527c478bd9Sstevel@tonic-gate #include "pci.h"
537c478bd9Sstevel@tonic-gate #include "timer.h"
547c478bd9Sstevel@tonic-gate #include "tlan.h"
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate #define drv_version "v1.4"
577c478bd9Sstevel@tonic-gate #define drv_date "01-17-2004"
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate /* NIC specific static variables go here */
607c478bd9Sstevel@tonic-gate #define HZ 100
617c478bd9Sstevel@tonic-gate #define TX_TIME_OUT (6*HZ)
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate #ifdef EB50
647c478bd9Sstevel@tonic-gate #define cpu_to_le32(val) (val)
657c478bd9Sstevel@tonic-gate #define le32_to_cpu(val) (val)
667c478bd9Sstevel@tonic-gate #define virt_to_bus(x) ((unsigned long) x)
677c478bd9Sstevel@tonic-gate #define bus_to_virt(x) ((unsigned long) x)
687c478bd9Sstevel@tonic-gate #endif
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate /* Condensed operations for readability. */
717c478bd9Sstevel@tonic-gate #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
727c478bd9Sstevel@tonic-gate #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate static void TLan_ResetLists(struct nic *nic __unused);
767c478bd9Sstevel@tonic-gate static void TLan_ResetAdapter(struct nic *nic __unused);
777c478bd9Sstevel@tonic-gate static void TLan_FinishReset(struct nic *nic __unused);
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate static void TLan_EeSendStart(u16);
807c478bd9Sstevel@tonic-gate static int TLan_EeSendByte(u16, u8, int);
817c478bd9Sstevel@tonic-gate static void TLan_EeReceiveByte(u16, u8 *, int);
827c478bd9Sstevel@tonic-gate static int TLan_EeReadByte(u16 io_base, u8, u8 *);
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate static void TLan_PhyDetect(struct nic *nic);
857c478bd9Sstevel@tonic-gate static void TLan_PhyPowerDown(struct nic *nic);
867c478bd9Sstevel@tonic-gate static void TLan_PhyPowerUp(struct nic *nic);
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate static void TLan_SetMac(struct nic *nic __unused, int areg, char *mac);
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate static void TLan_PhyReset(struct nic *nic);
927c478bd9Sstevel@tonic-gate static void TLan_PhyStartLink(struct nic *nic);
937c478bd9Sstevel@tonic-gate static void TLan_PhyFinishAutoNeg(struct nic *nic);
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate #ifdef MONITOR
967c478bd9Sstevel@tonic-gate static void TLan_PhyMonitor(struct nic *nic);
977c478bd9Sstevel@tonic-gate #endif
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate static void refill_rx(struct nic *nic __unused);
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate static int TLan_MiiReadReg(struct nic *nic __unused, u16, u16, u16 *);
1037c478bd9Sstevel@tonic-gate static void TLan_MiiSendData(u16, u32, unsigned);
1047c478bd9Sstevel@tonic-gate static void TLan_MiiSync(u16);
1057c478bd9Sstevel@tonic-gate static void TLan_MiiWriteReg(struct nic *nic __unused, u16, u16, u16);
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate const char *media[] = {
1097c478bd9Sstevel@tonic-gate "10BaseT-HD ", "10BaseT-FD ", "100baseTx-HD ",
1107c478bd9Sstevel@tonic-gate "100baseTx-FD", "100baseT4", 0
1117c478bd9Sstevel@tonic-gate };
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate /* This much match tlan_pci_tbl[]! */
1147c478bd9Sstevel@tonic-gate enum tlan_nics {
1157c478bd9Sstevel@tonic-gate NETEL10 = 0, NETEL100 = 1, NETFLEX3I = 2, THUNDER = 3, NETFLEX3B =
1167c478bd9Sstevel@tonic-gate 4, NETEL100PI = 5,
1177c478bd9Sstevel@tonic-gate NETEL100D = 6, NETEL100I = 7, OC2183 = 8, OC2325 = 9, OC2326 =
1187c478bd9Sstevel@tonic-gate 10, NETELLIGENT_10_100_WS_5100 = 11,
1197c478bd9Sstevel@tonic-gate NETELLIGENT_10_T2 = 12
1207c478bd9Sstevel@tonic-gate };
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate struct pci_id_info {
1237c478bd9Sstevel@tonic-gate const char *name;
1247c478bd9Sstevel@tonic-gate int nic_id;
1257c478bd9Sstevel@tonic-gate struct match_info {
1267c478bd9Sstevel@tonic-gate u32 pci, pci_mask, subsystem, subsystem_mask;
1277c478bd9Sstevel@tonic-gate u32 revision, revision_mask; /* Only 8 bits. */
1287c478bd9Sstevel@tonic-gate } id;
1297c478bd9Sstevel@tonic-gate u32 flags;
1307c478bd9Sstevel@tonic-gate u16 addrOfs; /* Address Offset */
1317c478bd9Sstevel@tonic-gate };
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate static struct pci_id_info tlan_pci_tbl[] = {
1347c478bd9Sstevel@tonic-gate {"Compaq Netelligent 10 T PCI UTP", NETEL10,
1357c478bd9Sstevel@tonic-gate {0xae340e11, 0xffffffff, 0, 0, 0, 0},
1367c478bd9Sstevel@tonic-gate TLAN_ADAPTER_ACTIVITY_LED, 0x83},
1377c478bd9Sstevel@tonic-gate {"Compaq Netelligent 10/100 TX PCI UTP", NETEL100,
1387c478bd9Sstevel@tonic-gate {0xae320e11, 0xffffffff, 0, 0, 0, 0},
1397c478bd9Sstevel@tonic-gate TLAN_ADAPTER_ACTIVITY_LED, 0x83},
1407c478bd9Sstevel@tonic-gate {"Compaq Integrated NetFlex-3/P", NETFLEX3I,
1417c478bd9Sstevel@tonic-gate {0xae350e11, 0xffffffff, 0, 0, 0, 0},
1427c478bd9Sstevel@tonic-gate TLAN_ADAPTER_NONE, 0x83},
1437c478bd9Sstevel@tonic-gate {"Compaq NetFlex-3/P", THUNDER,
1447c478bd9Sstevel@tonic-gate {0xf1300e11, 0xffffffff, 0, 0, 0, 0},
1457c478bd9Sstevel@tonic-gate TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83},
1467c478bd9Sstevel@tonic-gate {"Compaq NetFlex-3/P", NETFLEX3B,
1477c478bd9Sstevel@tonic-gate {0xf1500e11, 0xffffffff, 0, 0, 0, 0},
1487c478bd9Sstevel@tonic-gate TLAN_ADAPTER_NONE, 0x83},
1497c478bd9Sstevel@tonic-gate {"Compaq Netelligent Integrated 10/100 TX UTP", NETEL100PI,
1507c478bd9Sstevel@tonic-gate {0xae430e11, 0xffffffff, 0, 0, 0, 0},
1517c478bd9Sstevel@tonic-gate TLAN_ADAPTER_ACTIVITY_LED, 0x83},
1527c478bd9Sstevel@tonic-gate {"Compaq Netelligent Dual 10/100 TX PCI UTP", NETEL100D,
1537c478bd9Sstevel@tonic-gate {0xae400e11, 0xffffffff, 0, 0, 0, 0},
1547c478bd9Sstevel@tonic-gate TLAN_ADAPTER_NONE, 0x83},
1557c478bd9Sstevel@tonic-gate {"Compaq Netelligent 10/100 TX Embedded UTP", NETEL100I,
1567c478bd9Sstevel@tonic-gate {0xb0110e11, 0xffffffff, 0, 0, 0, 0},
1577c478bd9Sstevel@tonic-gate TLAN_ADAPTER_NONE, 0x83},
1587c478bd9Sstevel@tonic-gate {"Olicom OC-2183/2185", OC2183,
1597c478bd9Sstevel@tonic-gate {0x0013108d, 0xffffffff, 0, 0, 0, 0},
1607c478bd9Sstevel@tonic-gate TLAN_ADAPTER_USE_INTERN_10, 0x83},
1617c478bd9Sstevel@tonic-gate {"Olicom OC-2325", OC2325,
1627c478bd9Sstevel@tonic-gate {0x0012108d, 0xffffffff, 0, 0, 0, 0},
1637c478bd9Sstevel@tonic-gate TLAN_ADAPTER_UNMANAGED_PHY, 0xF8},
1647c478bd9Sstevel@tonic-gate {"Olicom OC-2326", OC2326,
1657c478bd9Sstevel@tonic-gate {0x0014108d, 0xffffffff, 0, 0, 0, 0},
1667c478bd9Sstevel@tonic-gate TLAN_ADAPTER_USE_INTERN_10, 0xF8},
1677c478bd9Sstevel@tonic-gate {"Compaq Netelligent 10/100 TX UTP", NETELLIGENT_10_100_WS_5100,
1687c478bd9Sstevel@tonic-gate {0xb0300e11, 0xffffffff, 0, 0, 0, 0},
1697c478bd9Sstevel@tonic-gate TLAN_ADAPTER_ACTIVITY_LED, 0x83},
1707c478bd9Sstevel@tonic-gate {"Compaq Netelligent 10 T/2 PCI UTP/Coax", NETELLIGENT_10_T2,
1717c478bd9Sstevel@tonic-gate {0xb0120e11, 0xffffffff, 0, 0, 0, 0},
1727c478bd9Sstevel@tonic-gate TLAN_ADAPTER_NONE, 0x83},
1737c478bd9Sstevel@tonic-gate {"Compaq NetFlex-3/E", 0, /* EISA card */
1747c478bd9Sstevel@tonic-gate {0, 0, 0, 0, 0, 0},
1757c478bd9Sstevel@tonic-gate TLAN_ADAPTER_ACTIVITY_LED | TLAN_ADAPTER_UNMANAGED_PHY |
1767c478bd9Sstevel@tonic-gate TLAN_ADAPTER_BIT_RATE_PHY, 0x83},
1777c478bd9Sstevel@tonic-gate {"Compaq NetFlex-3/E", 0, /* EISA card */
1787c478bd9Sstevel@tonic-gate {0, 0, 0, 0, 0, 0},
1797c478bd9Sstevel@tonic-gate TLAN_ADAPTER_ACTIVITY_LED, 0x83},
1807c478bd9Sstevel@tonic-gate {0, 0,
1817c478bd9Sstevel@tonic-gate {0, 0, 0, 0, 0, 0},
1827c478bd9Sstevel@tonic-gate 0, 0},
1837c478bd9Sstevel@tonic-gate };
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate struct TLanList {
1877c478bd9Sstevel@tonic-gate u32 forward;
1887c478bd9Sstevel@tonic-gate u16 cStat;
1897c478bd9Sstevel@tonic-gate u16 frameSize;
1907c478bd9Sstevel@tonic-gate struct {
1917c478bd9Sstevel@tonic-gate u32 count;
1927c478bd9Sstevel@tonic-gate u32 address;
1937c478bd9Sstevel@tonic-gate } buffer[TLAN_BUFFERS_PER_LIST];
1947c478bd9Sstevel@tonic-gate };
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate struct TLanList tx_ring[TLAN_NUM_TX_LISTS];
1997c478bd9Sstevel@tonic-gate static unsigned char txb[TLAN_MAX_FRAME_SIZE * TLAN_NUM_TX_LISTS];
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate struct TLanList rx_ring[TLAN_NUM_RX_LISTS];
2027c478bd9Sstevel@tonic-gate static unsigned char rxb[TLAN_MAX_FRAME_SIZE * TLAN_NUM_RX_LISTS];
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE];
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate int chip_idx;
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate /*****************************************************************
2117c478bd9Sstevel@tonic-gate * TLAN Private Information Structure
2127c478bd9Sstevel@tonic-gate *
2137c478bd9Sstevel@tonic-gate ****************************************************************/
2147c478bd9Sstevel@tonic-gate struct tlan_private {
2157c478bd9Sstevel@tonic-gate unsigned short vendor_id; /* PCI Vendor code */
2167c478bd9Sstevel@tonic-gate unsigned short dev_id; /* PCI Device code */
2177c478bd9Sstevel@tonic-gate const char *nic_name;
2187c478bd9Sstevel@tonic-gate u8 *padBuffer;
2197c478bd9Sstevel@tonic-gate u8 *rxBuffer;
2207c478bd9Sstevel@tonic-gate struct TLanList *rx_head_desc;
2217c478bd9Sstevel@tonic-gate u32 rxHead;
2227c478bd9Sstevel@tonic-gate u32 rxTail;
2237c478bd9Sstevel@tonic-gate u32 rxEocCount;
2247c478bd9Sstevel@tonic-gate unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indicies */
2257c478bd9Sstevel@tonic-gate unsigned int cur_tx, dirty_tx;
2267c478bd9Sstevel@tonic-gate unsigned rx_buf_sz; /* Based on mtu + Slack */
2277c478bd9Sstevel@tonic-gate struct TLanList *txList;
2287c478bd9Sstevel@tonic-gate struct TLanList *rxList;
2297c478bd9Sstevel@tonic-gate u8 *txBuffer;
2307c478bd9Sstevel@tonic-gate u32 txHead;
2317c478bd9Sstevel@tonic-gate u32 txInProgress;
2327c478bd9Sstevel@tonic-gate u32 txTail;
2337c478bd9Sstevel@tonic-gate int eoc;
2347c478bd9Sstevel@tonic-gate u32 txBusyCount;
2357c478bd9Sstevel@tonic-gate u32 phyOnline;
2367c478bd9Sstevel@tonic-gate u32 timerSetAt;
2377c478bd9Sstevel@tonic-gate u32 timerType;
2387c478bd9Sstevel@tonic-gate u32 adapterRev;
2397c478bd9Sstevel@tonic-gate u32 aui;
2407c478bd9Sstevel@tonic-gate u32 debug;
2417c478bd9Sstevel@tonic-gate u32 duplex;
2427c478bd9Sstevel@tonic-gate u32 phy[2];
2437c478bd9Sstevel@tonic-gate u32 phyNum;
2447c478bd9Sstevel@tonic-gate u32 speed;
2457c478bd9Sstevel@tonic-gate u8 tlanRev;
2467c478bd9Sstevel@tonic-gate u8 tlanFullDuplex;
2477c478bd9Sstevel@tonic-gate char devName[8];
2487c478bd9Sstevel@tonic-gate u8 link;
2497c478bd9Sstevel@tonic-gate u8 is_eisa;
2507c478bd9Sstevel@tonic-gate u8 neg_be_verbose;
2517c478bd9Sstevel@tonic-gate } TLanPrivateInfo;
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate static struct tlan_private *priv;
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate u32 BASE;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate /***************************************************************
2607c478bd9Sstevel@tonic-gate * TLan_ResetLists
2617c478bd9Sstevel@tonic-gate *
2627c478bd9Sstevel@tonic-gate * Returns:
2637c478bd9Sstevel@tonic-gate * Nothing
2647c478bd9Sstevel@tonic-gate * Parms:
2657c478bd9Sstevel@tonic-gate * dev The device structure with the list
2667c478bd9Sstevel@tonic-gate * stuctures to be reset.
2677c478bd9Sstevel@tonic-gate *
2687c478bd9Sstevel@tonic-gate * This routine sets the variables associated with managing
2697c478bd9Sstevel@tonic-gate * the TLAN lists to their initial values.
2707c478bd9Sstevel@tonic-gate *
2717c478bd9Sstevel@tonic-gate **************************************************************/
2727c478bd9Sstevel@tonic-gate
TLan_ResetLists(struct nic * nic __unused)2737c478bd9Sstevel@tonic-gate void TLan_ResetLists(struct nic *nic __unused)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate int i;
2777c478bd9Sstevel@tonic-gate struct TLanList *list;
2787c478bd9Sstevel@tonic-gate priv->txHead = 0;
2797c478bd9Sstevel@tonic-gate priv->txTail = 0;
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate for (i = 0; i < TLAN_NUM_TX_LISTS; i++) {
2827c478bd9Sstevel@tonic-gate list = &tx_ring[i];
2837c478bd9Sstevel@tonic-gate list->cStat = TLAN_CSTAT_UNUSED;
2847c478bd9Sstevel@tonic-gate /* list->buffer[0].address = 0; */
2857c478bd9Sstevel@tonic-gate list->buffer[0].address = virt_to_bus(txb +
2867c478bd9Sstevel@tonic-gate (i * TLAN_MAX_FRAME_SIZE));
2877c478bd9Sstevel@tonic-gate list->buffer[2].count = 0;
2887c478bd9Sstevel@tonic-gate list->buffer[2].address = 0;
2897c478bd9Sstevel@tonic-gate list->buffer[9].address = 0;
2907c478bd9Sstevel@tonic-gate /* list->forward = 0; */
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate priv->cur_rx = 0;
2947c478bd9Sstevel@tonic-gate priv->rx_buf_sz = (TLAN_MAX_FRAME_SIZE);
2957c478bd9Sstevel@tonic-gate priv->rx_head_desc = &rx_ring[0];
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate /* Initialize all the Rx descriptors */
2987c478bd9Sstevel@tonic-gate for (i = 0; i < TLAN_NUM_RX_LISTS; i++) {
2997c478bd9Sstevel@tonic-gate rx_ring[i].forward = virt_to_le32desc(&rx_ring[i + 1]);
3007c478bd9Sstevel@tonic-gate rx_ring[i].cStat = TLAN_CSTAT_READY;
3017c478bd9Sstevel@tonic-gate rx_ring[i].frameSize = TLAN_MAX_FRAME_SIZE;
3027c478bd9Sstevel@tonic-gate rx_ring[i].buffer[0].count =
3037c478bd9Sstevel@tonic-gate TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
3047c478bd9Sstevel@tonic-gate rx_ring[i].buffer[0].address =
3057c478bd9Sstevel@tonic-gate virt_to_le32desc(&rxb[i * TLAN_MAX_FRAME_SIZE]);
3067c478bd9Sstevel@tonic-gate rx_ring[i].buffer[1].count = 0;
3077c478bd9Sstevel@tonic-gate rx_ring[i].buffer[1].address = 0;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate
3107c478bd9Sstevel@tonic-gate /* Mark the last entry as wrapping the ring */
3117c478bd9Sstevel@tonic-gate rx_ring[i - 1].forward = virt_to_le32desc(&rx_ring[0]);
3127c478bd9Sstevel@tonic-gate priv->dirty_rx = (unsigned int) (i - TLAN_NUM_RX_LISTS);
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate } /* TLan_ResetLists */
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate /***************************************************************
3177c478bd9Sstevel@tonic-gate * TLan_Reset
3187c478bd9Sstevel@tonic-gate *
3197c478bd9Sstevel@tonic-gate * Returns:
3207c478bd9Sstevel@tonic-gate * 0
3217c478bd9Sstevel@tonic-gate * Parms:
3227c478bd9Sstevel@tonic-gate * dev Pointer to device structure of adapter
3237c478bd9Sstevel@tonic-gate * to be reset.
3247c478bd9Sstevel@tonic-gate *
3257c478bd9Sstevel@tonic-gate * This function resets the adapter and it's physical
3267c478bd9Sstevel@tonic-gate * device. See Chap. 3, pp. 9-10 of the "ThunderLAN
3277c478bd9Sstevel@tonic-gate * Programmer's Guide" for details. The routine tries to
3287c478bd9Sstevel@tonic-gate * implement what is detailed there, though adjustments
3297c478bd9Sstevel@tonic-gate * have been made.
3307c478bd9Sstevel@tonic-gate *
3317c478bd9Sstevel@tonic-gate **************************************************************/
3327c478bd9Sstevel@tonic-gate
TLan_ResetAdapter(struct nic * nic __unused)3337c478bd9Sstevel@tonic-gate void TLan_ResetAdapter(struct nic *nic __unused)
3347c478bd9Sstevel@tonic-gate {
3357c478bd9Sstevel@tonic-gate int i;
3367c478bd9Sstevel@tonic-gate u32 addr;
3377c478bd9Sstevel@tonic-gate u32 data;
3387c478bd9Sstevel@tonic-gate u8 data8;
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate priv->tlanFullDuplex = FALSE;
3417c478bd9Sstevel@tonic-gate priv->phyOnline = 0;
3427c478bd9Sstevel@tonic-gate /* 1. Assert reset bit. */
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate data = inl(BASE + TLAN_HOST_CMD);
3457c478bd9Sstevel@tonic-gate data |= TLAN_HC_AD_RST;
3467c478bd9Sstevel@tonic-gate outl(data, BASE + TLAN_HOST_CMD);
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate udelay(1000);
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate /* 2. Turn off interrupts. ( Probably isn't necessary ) */
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate data = inl(BASE + TLAN_HOST_CMD);
3537c478bd9Sstevel@tonic-gate data |= TLAN_HC_INT_OFF;
3547c478bd9Sstevel@tonic-gate outl(data, BASE + TLAN_HOST_CMD);
3557c478bd9Sstevel@tonic-gate /* 3. Clear AREGs and HASHs. */
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate for (i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4) {
3587c478bd9Sstevel@tonic-gate TLan_DioWrite32(BASE, (u16) i, 0);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate /* 4. Setup NetConfig register. */
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate data =
3647c478bd9Sstevel@tonic-gate TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
3657c478bd9Sstevel@tonic-gate TLan_DioWrite16(BASE, TLAN_NET_CONFIG, (u16) data);
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate /* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate outl(TLAN_HC_LD_TMR | 0x3f, BASE + TLAN_HOST_CMD);
3707c478bd9Sstevel@tonic-gate outl(TLAN_HC_LD_THR | 0x0, BASE + TLAN_HOST_CMD);
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate /* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
3757c478bd9Sstevel@tonic-gate addr = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
3767c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_NMRST, addr);
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate /* 7. Setup the remaining registers. */
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate if (priv->tlanRev >= 0x30) {
3817c478bd9Sstevel@tonic-gate data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC;
3827c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_INT_DIS, data8);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate TLan_PhyDetect(nic);
3857c478bd9Sstevel@tonic-gate data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_BIT_RATE_PHY) {
3887c478bd9Sstevel@tonic-gate data |= TLAN_NET_CFG_BIT;
3897c478bd9Sstevel@tonic-gate if (priv->aui == 1) {
3907c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x0a);
3917c478bd9Sstevel@tonic-gate } else if (priv->duplex == TLAN_DUPLEX_FULL) {
3927c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x00);
3937c478bd9Sstevel@tonic-gate priv->tlanFullDuplex = TRUE;
3947c478bd9Sstevel@tonic-gate } else {
3957c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x08);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate if (priv->phyNum == 0) {
4007c478bd9Sstevel@tonic-gate data |= TLAN_NET_CFG_PHY_EN;
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate TLan_DioWrite16(BASE, TLAN_NET_CONFIG, (u16) data);
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY) {
4057c478bd9Sstevel@tonic-gate TLan_FinishReset(nic);
4067c478bd9Sstevel@tonic-gate } else {
4077c478bd9Sstevel@tonic-gate TLan_PhyPowerDown(nic);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate } /* TLan_ResetAdapter */
4117c478bd9Sstevel@tonic-gate
TLan_FinishReset(struct nic * nic)4127c478bd9Sstevel@tonic-gate void TLan_FinishReset(struct nic *nic)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate u8 data;
4167c478bd9Sstevel@tonic-gate u32 phy;
4177c478bd9Sstevel@tonic-gate u8 sio;
4187c478bd9Sstevel@tonic-gate u16 status;
4197c478bd9Sstevel@tonic-gate u16 partner;
4207c478bd9Sstevel@tonic-gate u16 tlphy_ctl;
4217c478bd9Sstevel@tonic-gate u16 tlphy_par;
4227c478bd9Sstevel@tonic-gate u16 tlphy_id1, tlphy_id2;
4237c478bd9Sstevel@tonic-gate int i;
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate phy = priv->phy[priv->phyNum];
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
4287c478bd9Sstevel@tonic-gate if (priv->tlanFullDuplex) {
4297c478bd9Sstevel@tonic-gate data |= TLAN_NET_CMD_DUPLEX;
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_NET_CMD, data);
4327c478bd9Sstevel@tonic-gate data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
4337c478bd9Sstevel@tonic-gate if (priv->phyNum == 0) {
4347c478bd9Sstevel@tonic-gate data |= TLAN_NET_MASK_MASK7;
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_NET_MASK, data);
4377c478bd9Sstevel@tonic-gate TLan_DioWrite16(BASE, TLAN_MAX_RX, ((1536) + 7) & ~7);
4387c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_ID_HI, &tlphy_id1);
4397c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_ID_LO, &tlphy_id2);
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate if ((tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY)
4427c478bd9Sstevel@tonic-gate || (priv->aui)) {
4437c478bd9Sstevel@tonic-gate status = MII_GS_LINK;
4447c478bd9Sstevel@tonic-gate printf("TLAN: %s: Link forced.\n", priv->nic_name);
4457c478bd9Sstevel@tonic-gate } else {
4467c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
4477c478bd9Sstevel@tonic-gate udelay(1000);
4487c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
4497c478bd9Sstevel@tonic-gate if ((status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */
4507c478bd9Sstevel@tonic-gate (tlphy_id1 == NAT_SEM_ID1)
4517c478bd9Sstevel@tonic-gate && (tlphy_id2 == NAT_SEM_ID2)) {
4527c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_AN_LPA, &partner);
4537c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, TLAN_TLPHY_PAR,
4547c478bd9Sstevel@tonic-gate &tlphy_par);
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate printf("TLAN: %s: Link active with ",
4577c478bd9Sstevel@tonic-gate priv->nic_name);
4587c478bd9Sstevel@tonic-gate if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) {
4597c478bd9Sstevel@tonic-gate printf("forced 10%sMbps %s-Duplex\n",
4607c478bd9Sstevel@tonic-gate tlphy_par & TLAN_PHY_SPEED_100 ? ""
4617c478bd9Sstevel@tonic-gate : "0",
4627c478bd9Sstevel@tonic-gate tlphy_par & TLAN_PHY_DUPLEX_FULL ?
4637c478bd9Sstevel@tonic-gate "Full" : "Half");
4647c478bd9Sstevel@tonic-gate } else {
4657c478bd9Sstevel@tonic-gate printf
4667c478bd9Sstevel@tonic-gate ("AutoNegotiation enabled, at 10%sMbps %s-Duplex\n",
4677c478bd9Sstevel@tonic-gate tlphy_par & TLAN_PHY_SPEED_100 ? "" :
4687c478bd9Sstevel@tonic-gate "0",
4697c478bd9Sstevel@tonic-gate tlphy_par & TLAN_PHY_DUPLEX_FULL ?
4707c478bd9Sstevel@tonic-gate "Full" : "Half");
4717c478bd9Sstevel@tonic-gate printf("TLAN: Partner capability: ");
4727c478bd9Sstevel@tonic-gate for (i = 5; i <= 10; i++)
4737c478bd9Sstevel@tonic-gate if (partner & (1 << i))
4747c478bd9Sstevel@tonic-gate printf("%s", media[i - 5]);
4757c478bd9Sstevel@tonic-gate printf("\n");
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_LED_REG, TLAN_LED_LINK);
4797c478bd9Sstevel@tonic-gate #ifdef MONITOR
4807c478bd9Sstevel@tonic-gate /* We have link beat..for now anyway */
4817c478bd9Sstevel@tonic-gate priv->link = 1;
4827c478bd9Sstevel@tonic-gate /*Enabling link beat monitoring */
4837c478bd9Sstevel@tonic-gate /* TLan_SetTimer( nic, (10*HZ), TLAN_TIMER_LINK_BEAT ); */
4847c478bd9Sstevel@tonic-gate mdelay(10000);
4857c478bd9Sstevel@tonic-gate TLan_PhyMonitor(nic);
4867c478bd9Sstevel@tonic-gate #endif
4877c478bd9Sstevel@tonic-gate } else if (status & MII_GS_LINK) {
4887c478bd9Sstevel@tonic-gate printf("TLAN: %s: Link active\n", priv->nic_name);
4897c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_LED_REG, TLAN_LED_LINK);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate if (priv->phyNum == 0) {
4947c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, TLAN_TLPHY_CTL, &tlphy_ctl);
4957c478bd9Sstevel@tonic-gate tlphy_ctl |= TLAN_TC_INTEN;
4967c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, TLAN_TLPHY_CTL, tlphy_ctl);
4977c478bd9Sstevel@tonic-gate sio = TLan_DioRead8(BASE, TLAN_NET_SIO);
4987c478bd9Sstevel@tonic-gate sio |= TLAN_NET_SIO_MINTEN;
4997c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_NET_SIO, sio);
5007c478bd9Sstevel@tonic-gate }
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate if (status & MII_GS_LINK) {
5037c478bd9Sstevel@tonic-gate TLan_SetMac(nic, 0, nic->node_addr);
5047c478bd9Sstevel@tonic-gate priv->phyOnline = 1;
5057c478bd9Sstevel@tonic-gate outb((TLAN_HC_INT_ON >> 8), BASE + TLAN_HOST_CMD + 1);
5067c478bd9Sstevel@tonic-gate /* if ( debug >= 1 && debug != TLAN_DEBUG_PROBE ) {
5077c478bd9Sstevel@tonic-gate outb( ( TLAN_HC_REQ_INT >> 8 ), BASE + TLAN_HOST_CMD + 1 );
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate */
5117c478bd9Sstevel@tonic-gate outl(virt_to_bus(&rx_ring), BASE + TLAN_CH_PARM);
5127c478bd9Sstevel@tonic-gate outl(TLAN_HC_GO | TLAN_HC_RT, BASE + TLAN_HOST_CMD);
5137c478bd9Sstevel@tonic-gate } else {
5147c478bd9Sstevel@tonic-gate printf
5157c478bd9Sstevel@tonic-gate ("TLAN: %s: Link inactive, will retry in 10 secs...\n",
5167c478bd9Sstevel@tonic-gate priv->nic_name);
5177c478bd9Sstevel@tonic-gate /* TLan_SetTimer( nic, (10*HZ), TLAN_TIMER_FINISH_RESET ); */
5187c478bd9Sstevel@tonic-gate mdelay(10000);
5197c478bd9Sstevel@tonic-gate TLan_FinishReset(nic);
5207c478bd9Sstevel@tonic-gate return;
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate } /* TLan_FinishReset */
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate /**************************************************************************
5277c478bd9Sstevel@tonic-gate POLL - Wait for a frame
5287c478bd9Sstevel@tonic-gate ***************************************************************************/
tlan_poll(struct nic * nic,int retrieve)5297c478bd9Sstevel@tonic-gate static int tlan_poll(struct nic *nic, int retrieve)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate /* return true if there's an ethernet packet ready to read */
5327c478bd9Sstevel@tonic-gate /* nic->packet should contain data on return */
5337c478bd9Sstevel@tonic-gate /* nic->packetlen should contain length of data */
5347c478bd9Sstevel@tonic-gate u32 framesize;
5357c478bd9Sstevel@tonic-gate u32 host_cmd = 0;
5367c478bd9Sstevel@tonic-gate u32 ack = 1;
5377c478bd9Sstevel@tonic-gate int eoc = 0;
5387c478bd9Sstevel@tonic-gate int entry = priv->cur_rx % TLAN_NUM_RX_LISTS;
5397c478bd9Sstevel@tonic-gate u16 tmpCStat = le32_to_cpu(rx_ring[entry].cStat);
5407c478bd9Sstevel@tonic-gate u16 host_int = inw(BASE + TLAN_HOST_INT);
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate if ((tmpCStat & TLAN_CSTAT_FRM_CMP) && !retrieve)
5437c478bd9Sstevel@tonic-gate return 1;
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate outw(host_int, BASE + TLAN_HOST_INT);
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate if (!(tmpCStat & TLAN_CSTAT_FRM_CMP))
5487c478bd9Sstevel@tonic-gate return 0;
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /* printf("PI-1: 0x%hX\n", host_int); */
5517c478bd9Sstevel@tonic-gate if (tmpCStat & TLAN_CSTAT_EOC)
5527c478bd9Sstevel@tonic-gate eoc = 1;
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate framesize = rx_ring[entry].frameSize;
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate nic->packetlen = framesize;
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
5597c478bd9Sstevel@tonic-gate printf(".%d.", framesize);
5607c478bd9Sstevel@tonic-gate #endif
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate memcpy(nic->packet, rxb +
5637c478bd9Sstevel@tonic-gate (priv->cur_rx * TLAN_MAX_FRAME_SIZE), nic->packetlen);
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate rx_ring[entry].cStat = 0;
5667c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
5677c478bd9Sstevel@tonic-gate hex_dump(nic->packet, nic->packetlen);
5687c478bd9Sstevel@tonic-gate printf("%d", entry);
5697c478bd9Sstevel@tonic-gate #endif
5707c478bd9Sstevel@tonic-gate entry = (entry + 1) % TLAN_NUM_RX_LISTS;
5717c478bd9Sstevel@tonic-gate priv->cur_rx = entry;
5727c478bd9Sstevel@tonic-gate if (eoc) {
5737c478bd9Sstevel@tonic-gate if ((rx_ring[entry].cStat & TLAN_CSTAT_READY) ==
5747c478bd9Sstevel@tonic-gate TLAN_CSTAT_READY) {
5757c478bd9Sstevel@tonic-gate ack |= TLAN_HC_GO | TLAN_HC_RT;
5767c478bd9Sstevel@tonic-gate host_cmd = TLAN_HC_ACK | ack | 0x001C0000;
5777c478bd9Sstevel@tonic-gate outl(host_cmd, BASE + TLAN_HOST_CMD);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate } else {
5807c478bd9Sstevel@tonic-gate host_cmd = TLAN_HC_ACK | ack | (0x000C0000);
5817c478bd9Sstevel@tonic-gate outl(host_cmd, BASE + TLAN_HOST_CMD);
5827c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
5837c478bd9Sstevel@tonic-gate printf("AC: 0x%hX\n", inw(BASE + TLAN_CH_PARM));
5847c478bd9Sstevel@tonic-gate host_int = inw(BASE + TLAN_HOST_INT);
5857c478bd9Sstevel@tonic-gate printf("PI-2: 0x%hX\n", host_int);
5867c478bd9Sstevel@tonic-gate #endif
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate refill_rx(nic);
5897c478bd9Sstevel@tonic-gate return (1); /* initially as this is called to flush the input */
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate
refill_rx(struct nic * nic __unused)5927c478bd9Sstevel@tonic-gate static void refill_rx(struct nic *nic __unused)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate int entry = 0;
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate for (;
5977c478bd9Sstevel@tonic-gate (priv->cur_rx - priv->dirty_rx +
5987c478bd9Sstevel@tonic-gate TLAN_NUM_RX_LISTS) % TLAN_NUM_RX_LISTS > 0;
5997c478bd9Sstevel@tonic-gate priv->dirty_rx = (priv->dirty_rx + 1) % TLAN_NUM_RX_LISTS) {
6007c478bd9Sstevel@tonic-gate entry = priv->dirty_rx % TLAN_NUM_TX_LISTS;
6017c478bd9Sstevel@tonic-gate rx_ring[entry].frameSize = TLAN_MAX_FRAME_SIZE;
6027c478bd9Sstevel@tonic-gate rx_ring[entry].cStat = TLAN_CSTAT_READY;
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate /* #define EBDEBUG */
6087c478bd9Sstevel@tonic-gate /**************************************************************************
6097c478bd9Sstevel@tonic-gate TRANSMIT - Transmit a frame
6107c478bd9Sstevel@tonic-gate ***************************************************************************/
tlan_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)6117c478bd9Sstevel@tonic-gate static void tlan_transmit(struct nic *nic, const char *d, /* Destination */
6127c478bd9Sstevel@tonic-gate unsigned int t, /* Type */
6137c478bd9Sstevel@tonic-gate unsigned int s, /* size */
6147c478bd9Sstevel@tonic-gate const char *p)
6157c478bd9Sstevel@tonic-gate { /* Packet */
6167c478bd9Sstevel@tonic-gate u16 nstype;
6177c478bd9Sstevel@tonic-gate u32 to;
6187c478bd9Sstevel@tonic-gate struct TLanList *tail_list;
6197c478bd9Sstevel@tonic-gate struct TLanList *head_list;
6207c478bd9Sstevel@tonic-gate u8 *tail_buffer;
6217c478bd9Sstevel@tonic-gate u32 ack = 0;
6227c478bd9Sstevel@tonic-gate u32 host_cmd;
6237c478bd9Sstevel@tonic-gate int eoc = 0;
6247c478bd9Sstevel@tonic-gate u16 tmpCStat;
6257c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
6267c478bd9Sstevel@tonic-gate u16 host_int = inw(BASE + TLAN_HOST_INT);
6277c478bd9Sstevel@tonic-gate #endif
6287c478bd9Sstevel@tonic-gate int entry = 0;
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
6317c478bd9Sstevel@tonic-gate printf("INT0-0x%hX\n", host_int);
6327c478bd9Sstevel@tonic-gate #endif
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate if (!priv->phyOnline) {
6357c478bd9Sstevel@tonic-gate printf("TRANSMIT: %s PHY is not ready\n", priv->nic_name);
6367c478bd9Sstevel@tonic-gate return;
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate
6397c478bd9Sstevel@tonic-gate tail_list = priv->txList + priv->txTail;
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate if (tail_list->cStat != TLAN_CSTAT_UNUSED) {
6427c478bd9Sstevel@tonic-gate printf("TRANSMIT: %s is busy (Head=%d Tail=%d)\n",
6437c478bd9Sstevel@tonic-gate priv->nic_name, priv->txList, priv->txTail);
6447c478bd9Sstevel@tonic-gate tx_ring[entry].cStat = TLAN_CSTAT_UNUSED;
6457c478bd9Sstevel@tonic-gate priv->txBusyCount++;
6467c478bd9Sstevel@tonic-gate return;
6477c478bd9Sstevel@tonic-gate }
6487c478bd9Sstevel@tonic-gate
6497c478bd9Sstevel@tonic-gate tail_list->forward = 0;
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate tail_buffer = txb + (priv->txTail * TLAN_MAX_FRAME_SIZE);
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate /* send the packet to destination */
6547c478bd9Sstevel@tonic-gate memcpy(tail_buffer, d, ETH_ALEN);
6557c478bd9Sstevel@tonic-gate memcpy(tail_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN);
6567c478bd9Sstevel@tonic-gate nstype = htons((u16) t);
6577c478bd9Sstevel@tonic-gate memcpy(tail_buffer + 2 * ETH_ALEN, (u8 *) & nstype, 2);
6587c478bd9Sstevel@tonic-gate memcpy(tail_buffer + ETH_HLEN, p, s);
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate s += ETH_HLEN;
6617c478bd9Sstevel@tonic-gate s &= 0x0FFF;
6627c478bd9Sstevel@tonic-gate while (s < ETH_ZLEN)
6637c478bd9Sstevel@tonic-gate tail_buffer[s++] = '\0';
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate /*=====================================================*/
6667c478bd9Sstevel@tonic-gate /* Receive
6677c478bd9Sstevel@tonic-gate * 0000 0000 0001 1100
6687c478bd9Sstevel@tonic-gate * 0000 0000 0000 1100
6697c478bd9Sstevel@tonic-gate * 0000 0000 0000 0011 = 0x0003
6707c478bd9Sstevel@tonic-gate *
6717c478bd9Sstevel@tonic-gate * 0000 0000 0000 0000 0000 0000 0000 0011
6727c478bd9Sstevel@tonic-gate * 0000 0000 0000 1100 0000 0000 0000 0000 = 0x000C0000
6737c478bd9Sstevel@tonic-gate *
6747c478bd9Sstevel@tonic-gate * Transmit
6757c478bd9Sstevel@tonic-gate * 0000 0000 0001 1100
6767c478bd9Sstevel@tonic-gate * 0000 0000 0000 0100
6777c478bd9Sstevel@tonic-gate * 0000 0000 0000 0001 = 0x0001
6787c478bd9Sstevel@tonic-gate *
6797c478bd9Sstevel@tonic-gate * 0000 0000 0000 0000 0000 0000 0000 0001
6807c478bd9Sstevel@tonic-gate * 0000 0000 0000 0100 0000 0000 0000 0000 = 0x00040000
6817c478bd9Sstevel@tonic-gate * */
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate /* Setup the transmit descriptor */
6847c478bd9Sstevel@tonic-gate tail_list->frameSize = (u16) s;
6857c478bd9Sstevel@tonic-gate tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) s;
6867c478bd9Sstevel@tonic-gate tail_list->buffer[1].count = 0;
6877c478bd9Sstevel@tonic-gate tail_list->buffer[1].address = 0;
6887c478bd9Sstevel@tonic-gate
6897c478bd9Sstevel@tonic-gate tail_list->cStat = TLAN_CSTAT_READY;
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
6927c478bd9Sstevel@tonic-gate host_int = inw(BASE + TLAN_HOST_INT);
6937c478bd9Sstevel@tonic-gate printf("INT1-0x%hX\n", host_int);
6947c478bd9Sstevel@tonic-gate #endif
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate if (!priv->txInProgress) {
6977c478bd9Sstevel@tonic-gate priv->txInProgress = 1;
6987c478bd9Sstevel@tonic-gate outl(virt_to_le32desc(tail_list), BASE + TLAN_CH_PARM);
6997c478bd9Sstevel@tonic-gate outl(TLAN_HC_GO, BASE + TLAN_HOST_CMD);
7007c478bd9Sstevel@tonic-gate } else {
7017c478bd9Sstevel@tonic-gate if (priv->txTail == 0) {
7027c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
7037c478bd9Sstevel@tonic-gate printf("Out buffer\n");
7047c478bd9Sstevel@tonic-gate #endif
7057c478bd9Sstevel@tonic-gate (priv->txList + (TLAN_NUM_TX_LISTS - 1))->forward =
7067c478bd9Sstevel@tonic-gate virt_to_le32desc(tail_list);
7077c478bd9Sstevel@tonic-gate } else {
7087c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
7097c478bd9Sstevel@tonic-gate printf("Fix this \n");
7107c478bd9Sstevel@tonic-gate #endif
7117c478bd9Sstevel@tonic-gate (priv->txList + (priv->txTail - 1))->forward =
7127c478bd9Sstevel@tonic-gate virt_to_le32desc(tail_list);
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate CIRC_INC(priv->txTail, TLAN_NUM_TX_LISTS);
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate #ifdef EBDEBUG
7197c478bd9Sstevel@tonic-gate host_int = inw(BASE + TLAN_HOST_INT);
7207c478bd9Sstevel@tonic-gate printf("INT2-0x%hX\n", host_int);
7217c478bd9Sstevel@tonic-gate #endif
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate to = currticks() + TX_TIME_OUT;
7247c478bd9Sstevel@tonic-gate while ((tail_list->cStat == TLAN_CSTAT_READY) && currticks() < to);
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate head_list = priv->txList + priv->txHead;
7277c478bd9Sstevel@tonic-gate while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP)
7287c478bd9Sstevel@tonic-gate && (ack < 255)) {
7297c478bd9Sstevel@tonic-gate ack++;
7307c478bd9Sstevel@tonic-gate if(tmpCStat & TLAN_CSTAT_EOC)
7317c478bd9Sstevel@tonic-gate eoc =1;
7327c478bd9Sstevel@tonic-gate head_list->cStat = TLAN_CSTAT_UNUSED;
7337c478bd9Sstevel@tonic-gate CIRC_INC(priv->txHead, TLAN_NUM_TX_LISTS);
7347c478bd9Sstevel@tonic-gate head_list = priv->txList + priv->txHead;
7357c478bd9Sstevel@tonic-gate
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate if(!ack)
7387c478bd9Sstevel@tonic-gate printf("Incomplete TX Frame\n");
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate if(eoc) {
7417c478bd9Sstevel@tonic-gate head_list = priv->txList + priv->txHead;
7427c478bd9Sstevel@tonic-gate if ((head_list->cStat & TLAN_CSTAT_READY) == TLAN_CSTAT_READY) {
7437c478bd9Sstevel@tonic-gate outl(virt_to_le32desc(head_list), BASE + TLAN_CH_PARM);
7447c478bd9Sstevel@tonic-gate ack |= TLAN_HC_GO;
7457c478bd9Sstevel@tonic-gate } else {
7467c478bd9Sstevel@tonic-gate priv->txInProgress = 0;
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate if(ack) {
7507c478bd9Sstevel@tonic-gate host_cmd = TLAN_HC_ACK | ack;
7517c478bd9Sstevel@tonic-gate outl(host_cmd, BASE + TLAN_HOST_CMD);
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate if(priv->tlanRev < 0x30 ) {
7557c478bd9Sstevel@tonic-gate ack = 1;
7567c478bd9Sstevel@tonic-gate head_list = priv->txList + priv->txHead;
7577c478bd9Sstevel@tonic-gate if ((head_list->cStat & TLAN_CSTAT_READY) == TLAN_CSTAT_READY) {
7587c478bd9Sstevel@tonic-gate outl(virt_to_le32desc(head_list), BASE + TLAN_CH_PARM);
7597c478bd9Sstevel@tonic-gate ack |= TLAN_HC_GO;
7607c478bd9Sstevel@tonic-gate } else {
7617c478bd9Sstevel@tonic-gate priv->txInProgress = 0;
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate host_cmd = TLAN_HC_ACK | ack | 0x00140000;
7647c478bd9Sstevel@tonic-gate outl(host_cmd, BASE + TLAN_HOST_CMD);
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate }
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate if (currticks() >= to) {
7697c478bd9Sstevel@tonic-gate printf("TX Time Out");
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate /**************************************************************************
7747c478bd9Sstevel@tonic-gate DISABLE - Turn off ethernet interface
7757c478bd9Sstevel@tonic-gate ***************************************************************************/
7767c478bd9Sstevel@tonic-gate #ifdef EB51
tlan_disable(struct dev * dev __unused)7777c478bd9Sstevel@tonic-gate static void tlan_disable(struct dev *dev __unused)
7787c478bd9Sstevel@tonic-gate #else
7797c478bd9Sstevel@tonic-gate static void tlan_disable(struct nic *nic __unused)
7807c478bd9Sstevel@tonic-gate #endif
7817c478bd9Sstevel@tonic-gate {
7827c478bd9Sstevel@tonic-gate /* put the card in its initial state */
7837c478bd9Sstevel@tonic-gate /* This function serves 3 purposes.
7847c478bd9Sstevel@tonic-gate * This disables DMA and interrupts so we don't receive
7857c478bd9Sstevel@tonic-gate * unexpected packets or interrupts from the card after
7867c478bd9Sstevel@tonic-gate * etherboot has finished.
7877c478bd9Sstevel@tonic-gate * This frees resources so etherboot may use
7887c478bd9Sstevel@tonic-gate * this driver on another interface
7897c478bd9Sstevel@tonic-gate * This allows etherboot to reinitialize the interface
7907c478bd9Sstevel@tonic-gate * if something is something goes wrong.
7917c478bd9Sstevel@tonic-gate *
7927c478bd9Sstevel@tonic-gate */
7937c478bd9Sstevel@tonic-gate outl(TLAN_HC_AD_RST, BASE + TLAN_HOST_CMD);
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate /**************************************************************************
7977c478bd9Sstevel@tonic-gate IRQ - Enable, Disable, or Force interrupts
7987c478bd9Sstevel@tonic-gate ***************************************************************************/
tlan_irq(struct nic * nic __unused,irq_action_t action __unused)7997c478bd9Sstevel@tonic-gate static void tlan_irq(struct nic *nic __unused, irq_action_t action __unused)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate switch ( action ) {
8027c478bd9Sstevel@tonic-gate case DISABLE :
8037c478bd9Sstevel@tonic-gate break;
8047c478bd9Sstevel@tonic-gate case ENABLE :
8057c478bd9Sstevel@tonic-gate break;
8067c478bd9Sstevel@tonic-gate case FORCE :
8077c478bd9Sstevel@tonic-gate break;
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate
TLan_SetMulticastList(struct nic * nic)8117c478bd9Sstevel@tonic-gate static void TLan_SetMulticastList(struct nic *nic) {
8127c478bd9Sstevel@tonic-gate int i;
8137c478bd9Sstevel@tonic-gate u8 tmp;
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate /* !IFF_PROMISC */
8167c478bd9Sstevel@tonic-gate tmp = TLan_DioRead8(BASE, TLAN_NET_CMD);
8177c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF);
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate /* IFF_ALLMULTI */
8207c478bd9Sstevel@tonic-gate for(i = 0; i< 3; i++)
8217c478bd9Sstevel@tonic-gate TLan_SetMac(nic, i + 1, NULL);
8227c478bd9Sstevel@tonic-gate TLan_DioWrite32(BASE, TLAN_HASH_1, 0xFFFFFFFF);
8237c478bd9Sstevel@tonic-gate TLan_DioWrite32(BASE, TLAN_HASH_2, 0xFFFFFFFF);
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate }
8277c478bd9Sstevel@tonic-gate /**************************************************************************
8287c478bd9Sstevel@tonic-gate PROBE - Look for an adapter, this routine's visible to the outside
8297c478bd9Sstevel@tonic-gate ***************************************************************************/
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate #define board_found 1
8327c478bd9Sstevel@tonic-gate #define valid_link 0
8337c478bd9Sstevel@tonic-gate #ifdef EB51
tlan_probe(struct dev * dev,struct pci_device * pci)8347c478bd9Sstevel@tonic-gate static int tlan_probe(struct dev *dev, struct pci_device *pci)
8357c478bd9Sstevel@tonic-gate {
8367c478bd9Sstevel@tonic-gate struct nic *nic = (struct nic *) dev;
8377c478bd9Sstevel@tonic-gate #else
8387c478bd9Sstevel@tonic-gate struct nic *tlan_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate #endif
8417c478bd9Sstevel@tonic-gate u16 data = 0;
8427c478bd9Sstevel@tonic-gate int err;
8437c478bd9Sstevel@tonic-gate int i;
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate if (pci->ioaddr == 0)
8467c478bd9Sstevel@tonic-gate return 0;
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate nic->irqno = 0;
8497c478bd9Sstevel@tonic-gate nic->ioaddr = pci->ioaddr & ~3;
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate BASE = pci->ioaddr;
8527c478bd9Sstevel@tonic-gate printf("\n");
8537c478bd9Sstevel@tonic-gate printf("tlan.c: %s, %s\n", drv_version, drv_date);
8547c478bd9Sstevel@tonic-gate printf("%s: Probing for Vendor 0x%hX, Device 0x%hX",
8557c478bd9Sstevel@tonic-gate pci->name, pci->vendor, pci->dev_id);
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate /* I really must find out what this does */
8597c478bd9Sstevel@tonic-gate adjust_pci_device(pci);
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate /* Point to private storage */
8627c478bd9Sstevel@tonic-gate priv = &TLanPrivateInfo;
8637c478bd9Sstevel@tonic-gate /* Figure out which chip we're dealing with */
8647c478bd9Sstevel@tonic-gate i = 0;
8657c478bd9Sstevel@tonic-gate chip_idx = -1;
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate while (tlan_pci_tbl[i].name) {
8687c478bd9Sstevel@tonic-gate if ((((u32) pci->dev_id << 16) | pci->vendor) ==
8697c478bd9Sstevel@tonic-gate (tlan_pci_tbl[i].id.pci & 0xffffffff)) {
8707c478bd9Sstevel@tonic-gate chip_idx = i;
8717c478bd9Sstevel@tonic-gate break;
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate i++;
8747c478bd9Sstevel@tonic-gate }
8757c478bd9Sstevel@tonic-gate
8767c478bd9Sstevel@tonic-gate priv->vendor_id = pci->vendor;
8777c478bd9Sstevel@tonic-gate priv->dev_id = pci->dev_id;
8787c478bd9Sstevel@tonic-gate priv->nic_name = pci->name;
8797c478bd9Sstevel@tonic-gate priv->eoc = 0;
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate err = 0;
8827c478bd9Sstevel@tonic-gate for (i = 0; i < 6; i++)
8837c478bd9Sstevel@tonic-gate err |= TLan_EeReadByte(BASE,
8847c478bd9Sstevel@tonic-gate (u8) tlan_pci_tbl[chip_idx].
8857c478bd9Sstevel@tonic-gate addrOfs + i,
8867c478bd9Sstevel@tonic-gate (u8 *) & nic->node_addr[i]);
8877c478bd9Sstevel@tonic-gate if (err) {
8887c478bd9Sstevel@tonic-gate printf("TLAN: %s: Error reading MAC from eeprom: %d\n",
8897c478bd9Sstevel@tonic-gate pci->name, err);
8907c478bd9Sstevel@tonic-gate } else
8917c478bd9Sstevel@tonic-gate printf("\nAddress: %!\n", nic->node_addr);
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate priv->tlanRev = TLan_DioRead8(BASE, TLAN_DEF_REVISION);
8947c478bd9Sstevel@tonic-gate printf("\nRevision = 0x%hX\n", priv->tlanRev);
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate TLan_ResetLists(nic);
8977c478bd9Sstevel@tonic-gate TLan_ResetAdapter(nic);
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate data = inl(BASE + TLAN_HOST_CMD);
9007c478bd9Sstevel@tonic-gate data |= TLAN_HC_EOC;
9017c478bd9Sstevel@tonic-gate outw(data, BASE + TLAN_HOST_CMD);
9027c478bd9Sstevel@tonic-gate */
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate data = inl(BASE + TLAN_HOST_CMD);
9057c478bd9Sstevel@tonic-gate data |= TLAN_HC_INT_OFF;
9067c478bd9Sstevel@tonic-gate outw(data, BASE + TLAN_HOST_CMD);
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate TLan_SetMulticastList(nic);
9097c478bd9Sstevel@tonic-gate udelay(100);
9107c478bd9Sstevel@tonic-gate priv->txList = tx_ring;
9117c478bd9Sstevel@tonic-gate priv->rxList = rx_ring;
9127c478bd9Sstevel@tonic-gate /* if (board_found && valid_link)
9137c478bd9Sstevel@tonic-gate {*/
9147c478bd9Sstevel@tonic-gate /* point to NIC specific routines */
9157c478bd9Sstevel@tonic-gate #ifdef EB51
9167c478bd9Sstevel@tonic-gate dev->disable = tlan_disable;
9177c478bd9Sstevel@tonic-gate nic->poll = tlan_poll;
9187c478bd9Sstevel@tonic-gate nic->transmit = tlan_transmit;
9197c478bd9Sstevel@tonic-gate nic->irq = tlan_irq;
9207c478bd9Sstevel@tonic-gate return 1;
9217c478bd9Sstevel@tonic-gate #else
9227c478bd9Sstevel@tonic-gate nic->disable = tlan_disable;
9237c478bd9Sstevel@tonic-gate nic->poll = tlan_poll;
9247c478bd9Sstevel@tonic-gate nic->transmit = tlan_transmit;
9257c478bd9Sstevel@tonic-gate nic->irq = tlan_irq;
9267c478bd9Sstevel@tonic-gate return nic;
9277c478bd9Sstevel@tonic-gate #endif
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate /*****************************************************************************
9327c478bd9Sstevel@tonic-gate ******************************************************************************
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate ThunderLAN Driver Eeprom routines
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A
9377c478bd9Sstevel@tonic-gate EEPROM. These functions are based on information in Microchip's
9387c478bd9Sstevel@tonic-gate data sheet. I don't know how well this functions will work with
9397c478bd9Sstevel@tonic-gate other EEPROMs.
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate ******************************************************************************
9427c478bd9Sstevel@tonic-gate *****************************************************************************/
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate /***************************************************************
9467c478bd9Sstevel@tonic-gate * TLan_EeSendStart
9477c478bd9Sstevel@tonic-gate *
9487c478bd9Sstevel@tonic-gate * Returns:
9497c478bd9Sstevel@tonic-gate * Nothing
9507c478bd9Sstevel@tonic-gate * Parms:
9517c478bd9Sstevel@tonic-gate * io_base The IO port base address for the
9527c478bd9Sstevel@tonic-gate * TLAN device with the EEPROM to
9537c478bd9Sstevel@tonic-gate * use.
9547c478bd9Sstevel@tonic-gate *
9557c478bd9Sstevel@tonic-gate * This function sends a start cycle to an EEPROM attached
9567c478bd9Sstevel@tonic-gate * to a TLAN chip.
9577c478bd9Sstevel@tonic-gate *
9587c478bd9Sstevel@tonic-gate **************************************************************/
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate void TLan_EeSendStart(u16 io_base)
9617c478bd9Sstevel@tonic-gate {
9627c478bd9Sstevel@tonic-gate u16 sio;
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
9657c478bd9Sstevel@tonic-gate sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
9687c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
9697c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
9707c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);
9717c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
9727c478bd9Sstevel@tonic-gate
9737c478bd9Sstevel@tonic-gate } /* TLan_EeSendStart */
9747c478bd9Sstevel@tonic-gate
9757c478bd9Sstevel@tonic-gate
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate /***************************************************************
9797c478bd9Sstevel@tonic-gate * TLan_EeSendByte
9807c478bd9Sstevel@tonic-gate *
9817c478bd9Sstevel@tonic-gate * Returns:
9827c478bd9Sstevel@tonic-gate * If the correct ack was received, 0, otherwise 1
9837c478bd9Sstevel@tonic-gate * Parms: io_base The IO port base address for the
9847c478bd9Sstevel@tonic-gate * TLAN device with the EEPROM to
9857c478bd9Sstevel@tonic-gate * use.
9867c478bd9Sstevel@tonic-gate * data The 8 bits of information to
9877c478bd9Sstevel@tonic-gate * send to the EEPROM.
9887c478bd9Sstevel@tonic-gate * stop If TLAN_EEPROM_STOP is passed, a
9897c478bd9Sstevel@tonic-gate * stop cycle is sent after the
9907c478bd9Sstevel@tonic-gate * byte is sent after the ack is
9917c478bd9Sstevel@tonic-gate * read.
9927c478bd9Sstevel@tonic-gate *
9937c478bd9Sstevel@tonic-gate * This function sends a byte on the serial EEPROM line,
9947c478bd9Sstevel@tonic-gate * driving the clock to send each bit. The function then
9957c478bd9Sstevel@tonic-gate * reverses transmission direction and reads an acknowledge
9967c478bd9Sstevel@tonic-gate * bit.
9977c478bd9Sstevel@tonic-gate *
9987c478bd9Sstevel@tonic-gate **************************************************************/
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate int TLan_EeSendByte(u16 io_base, u8 data, int stop)
10017c478bd9Sstevel@tonic-gate {
10027c478bd9Sstevel@tonic-gate int err;
10037c478bd9Sstevel@tonic-gate u8 place;
10047c478bd9Sstevel@tonic-gate u16 sio;
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
10077c478bd9Sstevel@tonic-gate sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
10087c478bd9Sstevel@tonic-gate
10097c478bd9Sstevel@tonic-gate /* Assume clock is low, tx is enabled; */
10107c478bd9Sstevel@tonic-gate for (place = 0x80; place != 0; place >>= 1) {
10117c478bd9Sstevel@tonic-gate if (place & data)
10127c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
10137c478bd9Sstevel@tonic-gate else
10147c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);
10157c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
10167c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_ETXEN, sio);
10197c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
10207c478bd9Sstevel@tonic-gate err = TLan_GetBit(TLAN_NET_SIO_EDATA, sio);
10217c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
10227c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate if ((!err) && stop) {
10257c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_EDATA, sio); /* STOP, raise data while clock is high */
10267c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
10277c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate
10307c478bd9Sstevel@tonic-gate return (err);
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate } /* TLan_EeSendByte */
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate
10377c478bd9Sstevel@tonic-gate /***************************************************************
10387c478bd9Sstevel@tonic-gate * TLan_EeReceiveByte
10397c478bd9Sstevel@tonic-gate *
10407c478bd9Sstevel@tonic-gate * Returns:
10417c478bd9Sstevel@tonic-gate * Nothing
10427c478bd9Sstevel@tonic-gate * Parms:
10437c478bd9Sstevel@tonic-gate * io_base The IO port base address for the
10447c478bd9Sstevel@tonic-gate * TLAN device with the EEPROM to
10457c478bd9Sstevel@tonic-gate * use.
10467c478bd9Sstevel@tonic-gate * data An address to a char to hold the
10477c478bd9Sstevel@tonic-gate * data sent from the EEPROM.
10487c478bd9Sstevel@tonic-gate * stop If TLAN_EEPROM_STOP is passed, a
10497c478bd9Sstevel@tonic-gate * stop cycle is sent after the
10507c478bd9Sstevel@tonic-gate * byte is received, and no ack is
10517c478bd9Sstevel@tonic-gate * sent.
10527c478bd9Sstevel@tonic-gate *
10537c478bd9Sstevel@tonic-gate * This function receives 8 bits of data from the EEPROM
10547c478bd9Sstevel@tonic-gate * over the serial link. It then sends and ack bit, or no
10557c478bd9Sstevel@tonic-gate * ack and a stop bit. This function is used to retrieve
10567c478bd9Sstevel@tonic-gate * data after the address of a byte in the EEPROM has been
10577c478bd9Sstevel@tonic-gate * sent.
10587c478bd9Sstevel@tonic-gate *
10597c478bd9Sstevel@tonic-gate **************************************************************/
10607c478bd9Sstevel@tonic-gate
10617c478bd9Sstevel@tonic-gate void TLan_EeReceiveByte(u16 io_base, u8 * data, int stop)
10627c478bd9Sstevel@tonic-gate {
10637c478bd9Sstevel@tonic-gate u8 place;
10647c478bd9Sstevel@tonic-gate u16 sio;
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
10677c478bd9Sstevel@tonic-gate sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
10687c478bd9Sstevel@tonic-gate *data = 0;
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate /* Assume clock is low, tx is enabled; */
10717c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_ETXEN, sio);
10727c478bd9Sstevel@tonic-gate for (place = 0x80; place; place >>= 1) {
10737c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
10747c478bd9Sstevel@tonic-gate if (TLan_GetBit(TLAN_NET_SIO_EDATA, sio))
10757c478bd9Sstevel@tonic-gate *data |= place;
10767c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
10807c478bd9Sstevel@tonic-gate if (!stop) {
10817c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_EDATA, sio); /* Ack = 0 */
10827c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
10837c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
10847c478bd9Sstevel@tonic-gate } else {
10857c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_EDATA, sio); /* No ack = 1 (?) */
10867c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
10877c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
10887c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_EDATA, sio); /* STOP, raise data while clock is high */
10897c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
10907c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
10917c478bd9Sstevel@tonic-gate }
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate } /* TLan_EeReceiveByte */
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate
10967c478bd9Sstevel@tonic-gate
10977c478bd9Sstevel@tonic-gate /***************************************************************
10987c478bd9Sstevel@tonic-gate * TLan_EeReadByte
10997c478bd9Sstevel@tonic-gate *
11007c478bd9Sstevel@tonic-gate * Returns:
11017c478bd9Sstevel@tonic-gate * No error = 0, else, the stage at which the error
11027c478bd9Sstevel@tonic-gate * occurred.
11037c478bd9Sstevel@tonic-gate * Parms:
11047c478bd9Sstevel@tonic-gate * io_base The IO port base address for the
11057c478bd9Sstevel@tonic-gate * TLAN device with the EEPROM to
11067c478bd9Sstevel@tonic-gate * use.
11077c478bd9Sstevel@tonic-gate * ee_addr The address of the byte in the
11087c478bd9Sstevel@tonic-gate * EEPROM whose contents are to be
11097c478bd9Sstevel@tonic-gate * retrieved.
11107c478bd9Sstevel@tonic-gate * data An address to a char to hold the
11117c478bd9Sstevel@tonic-gate * data obtained from the EEPROM.
11127c478bd9Sstevel@tonic-gate *
11137c478bd9Sstevel@tonic-gate * This function reads a byte of information from an byte
11147c478bd9Sstevel@tonic-gate * cell in the EEPROM.
11157c478bd9Sstevel@tonic-gate *
11167c478bd9Sstevel@tonic-gate **************************************************************/
11177c478bd9Sstevel@tonic-gate
11187c478bd9Sstevel@tonic-gate int TLan_EeReadByte(u16 io_base, u8 ee_addr, u8 * data)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate int err;
11217c478bd9Sstevel@tonic-gate int ret = 0;
11227c478bd9Sstevel@tonic-gate
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate TLan_EeSendStart(io_base);
11257c478bd9Sstevel@tonic-gate err = TLan_EeSendByte(io_base, 0xA0, TLAN_EEPROM_ACK);
11267c478bd9Sstevel@tonic-gate if (err) {
11277c478bd9Sstevel@tonic-gate ret = 1;
11287c478bd9Sstevel@tonic-gate goto fail;
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate err = TLan_EeSendByte(io_base, ee_addr, TLAN_EEPROM_ACK);
11317c478bd9Sstevel@tonic-gate if (err) {
11327c478bd9Sstevel@tonic-gate ret = 2;
11337c478bd9Sstevel@tonic-gate goto fail;
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate TLan_EeSendStart(io_base);
11367c478bd9Sstevel@tonic-gate err = TLan_EeSendByte(io_base, 0xA1, TLAN_EEPROM_ACK);
11377c478bd9Sstevel@tonic-gate if (err) {
11387c478bd9Sstevel@tonic-gate ret = 3;
11397c478bd9Sstevel@tonic-gate goto fail;
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate TLan_EeReceiveByte(io_base, data, TLAN_EEPROM_STOP);
11427c478bd9Sstevel@tonic-gate fail:
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate return ret;
11457c478bd9Sstevel@tonic-gate
11467c478bd9Sstevel@tonic-gate } /* TLan_EeReadByte */
11477c478bd9Sstevel@tonic-gate
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate /*****************************************************************************
11507c478bd9Sstevel@tonic-gate ******************************************************************************
11517c478bd9Sstevel@tonic-gate
11527c478bd9Sstevel@tonic-gate ThunderLAN Driver MII Routines
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate These routines are based on the information in Chap. 2 of the
11557c478bd9Sstevel@tonic-gate "ThunderLAN Programmer's Guide", pp. 15-24.
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate ******************************************************************************
11587c478bd9Sstevel@tonic-gate *****************************************************************************/
11597c478bd9Sstevel@tonic-gate
11607c478bd9Sstevel@tonic-gate
11617c478bd9Sstevel@tonic-gate /***************************************************************
11627c478bd9Sstevel@tonic-gate * TLan_MiiReadReg
11637c478bd9Sstevel@tonic-gate *
11647c478bd9Sstevel@tonic-gate * Returns:
11657c478bd9Sstevel@tonic-gate * 0 if ack received ok
11667c478bd9Sstevel@tonic-gate * 1 otherwise.
11677c478bd9Sstevel@tonic-gate *
11687c478bd9Sstevel@tonic-gate * Parms:
11697c478bd9Sstevel@tonic-gate * dev The device structure containing
11707c478bd9Sstevel@tonic-gate * The io address and interrupt count
11717c478bd9Sstevel@tonic-gate * for this device.
11727c478bd9Sstevel@tonic-gate * phy The address of the PHY to be queried.
11737c478bd9Sstevel@tonic-gate * reg The register whose contents are to be
11747c478bd9Sstevel@tonic-gate * retreived.
11757c478bd9Sstevel@tonic-gate * val A pointer to a variable to store the
11767c478bd9Sstevel@tonic-gate * retrieved value.
11777c478bd9Sstevel@tonic-gate *
11787c478bd9Sstevel@tonic-gate * This function uses the TLAN's MII bus to retreive the contents
11797c478bd9Sstevel@tonic-gate * of a given register on a PHY. It sends the appropriate info
11807c478bd9Sstevel@tonic-gate * and then reads the 16-bit register value from the MII bus via
11817c478bd9Sstevel@tonic-gate * the TLAN SIO register.
11827c478bd9Sstevel@tonic-gate *
11837c478bd9Sstevel@tonic-gate **************************************************************/
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate int TLan_MiiReadReg(struct nic *nic __unused, u16 phy, u16 reg, u16 * val)
11867c478bd9Sstevel@tonic-gate {
11877c478bd9Sstevel@tonic-gate u8 nack;
11887c478bd9Sstevel@tonic-gate u16 sio, tmp;
11897c478bd9Sstevel@tonic-gate u32 i;
11907c478bd9Sstevel@tonic-gate int err;
11917c478bd9Sstevel@tonic-gate int minten;
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate err = FALSE;
11947c478bd9Sstevel@tonic-gate outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
11957c478bd9Sstevel@tonic-gate sio = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
11967c478bd9Sstevel@tonic-gate
11977c478bd9Sstevel@tonic-gate TLan_MiiSync(BASE);
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate minten = TLan_GetBit(TLAN_NET_SIO_MINTEN, sio);
12007c478bd9Sstevel@tonic-gate if (minten)
12017c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
12027c478bd9Sstevel@tonic-gate
12037c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, 0x1, 2); /* Start ( 01b ) */
12047c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, 0x2, 2); /* Read ( 10b ) */
12057c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, phy, 5); /* Device # */
12067c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, reg, 5); /* Register # */
12077c478bd9Sstevel@tonic-gate
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio); /* Change direction */
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Clock Idle bit */
12127c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
12137c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Wait 300ns */
12147c478bd9Sstevel@tonic-gate
12157c478bd9Sstevel@tonic-gate nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio); /* Check for ACK */
12167c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MCLK, sio); /* Finish ACK */
12177c478bd9Sstevel@tonic-gate if (nack) { /* No ACK, so fake it */
12187c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) {
12197c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
12207c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate tmp = 0xffff;
12237c478bd9Sstevel@tonic-gate err = TRUE;
12247c478bd9Sstevel@tonic-gate } else { /* ACK, so read data */
12257c478bd9Sstevel@tonic-gate for (tmp = 0, i = 0x8000; i; i >>= 1) {
12267c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
12277c478bd9Sstevel@tonic-gate if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio))
12287c478bd9Sstevel@tonic-gate tmp |= i;
12297c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
12307c478bd9Sstevel@tonic-gate }
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate
12337c478bd9Sstevel@tonic-gate
12347c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Idle cycle */
12357c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate if (minten)
12387c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate *val = tmp;
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gate return err;
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate } /* TLan_MiiReadReg */
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate /***************************************************************
12477c478bd9Sstevel@tonic-gate * TLan_MiiSendData
12487c478bd9Sstevel@tonic-gate *
12497c478bd9Sstevel@tonic-gate * Returns:
12507c478bd9Sstevel@tonic-gate * Nothing
12517c478bd9Sstevel@tonic-gate * Parms:
12527c478bd9Sstevel@tonic-gate * base_port The base IO port of the adapter in
12537c478bd9Sstevel@tonic-gate * question.
12547c478bd9Sstevel@tonic-gate * dev The address of the PHY to be queried.
12557c478bd9Sstevel@tonic-gate * data The value to be placed on the MII bus.
12567c478bd9Sstevel@tonic-gate * num_bits The number of bits in data that are to
12577c478bd9Sstevel@tonic-gate * be placed on the MII bus.
12587c478bd9Sstevel@tonic-gate *
12597c478bd9Sstevel@tonic-gate * This function sends on sequence of bits on the MII
12607c478bd9Sstevel@tonic-gate * configuration bus.
12617c478bd9Sstevel@tonic-gate *
12627c478bd9Sstevel@tonic-gate **************************************************************/
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate void TLan_MiiSendData(u16 base_port, u32 data, unsigned num_bits)
12657c478bd9Sstevel@tonic-gate {
12667c478bd9Sstevel@tonic-gate u16 sio;
12677c478bd9Sstevel@tonic-gate u32 i;
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate if (num_bits == 0)
12707c478bd9Sstevel@tonic-gate return;
12717c478bd9Sstevel@tonic-gate
12727c478bd9Sstevel@tonic-gate outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
12737c478bd9Sstevel@tonic-gate sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
12747c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MTXEN, sio);
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate for (i = (0x1 << (num_bits - 1)); i; i >>= 1) {
12777c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
12787c478bd9Sstevel@tonic-gate (void) TLan_GetBit(TLAN_NET_SIO_MCLK, sio);
12797c478bd9Sstevel@tonic-gate if (data & i)
12807c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MDATA, sio);
12817c478bd9Sstevel@tonic-gate else
12827c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MDATA, sio);
12837c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
12847c478bd9Sstevel@tonic-gate (void) TLan_GetBit(TLAN_NET_SIO_MCLK, sio);
12857c478bd9Sstevel@tonic-gate }
12867c478bd9Sstevel@tonic-gate
12877c478bd9Sstevel@tonic-gate } /* TLan_MiiSendData */
12887c478bd9Sstevel@tonic-gate
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate
12927c478bd9Sstevel@tonic-gate /***************************************************************
12937c478bd9Sstevel@tonic-gate * TLan_MiiSync
12947c478bd9Sstevel@tonic-gate *
12957c478bd9Sstevel@tonic-gate * Returns:
12967c478bd9Sstevel@tonic-gate * Nothing
12977c478bd9Sstevel@tonic-gate * Parms:
12987c478bd9Sstevel@tonic-gate * base_port The base IO port of the adapter in
12997c478bd9Sstevel@tonic-gate * question.
13007c478bd9Sstevel@tonic-gate *
13017c478bd9Sstevel@tonic-gate * This functions syncs all PHYs in terms of the MII configuration
13027c478bd9Sstevel@tonic-gate * bus.
13037c478bd9Sstevel@tonic-gate *
13047c478bd9Sstevel@tonic-gate **************************************************************/
13057c478bd9Sstevel@tonic-gate
13067c478bd9Sstevel@tonic-gate void TLan_MiiSync(u16 base_port)
13077c478bd9Sstevel@tonic-gate {
13087c478bd9Sstevel@tonic-gate int i;
13097c478bd9Sstevel@tonic-gate u16 sio;
13107c478bd9Sstevel@tonic-gate
13117c478bd9Sstevel@tonic-gate outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
13127c478bd9Sstevel@tonic-gate sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
13137c478bd9Sstevel@tonic-gate
13147c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);
13157c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) {
13167c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
13177c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate
13207c478bd9Sstevel@tonic-gate } /* TLan_MiiSync */
13217c478bd9Sstevel@tonic-gate
13227c478bd9Sstevel@tonic-gate
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate
13257c478bd9Sstevel@tonic-gate /***************************************************************
13267c478bd9Sstevel@tonic-gate * TLan_MiiWriteReg
13277c478bd9Sstevel@tonic-gate *
13287c478bd9Sstevel@tonic-gate * Returns:
13297c478bd9Sstevel@tonic-gate * Nothing
13307c478bd9Sstevel@tonic-gate * Parms:
13317c478bd9Sstevel@tonic-gate * dev The device structure for the device
13327c478bd9Sstevel@tonic-gate * to write to.
13337c478bd9Sstevel@tonic-gate * phy The address of the PHY to be written to.
13347c478bd9Sstevel@tonic-gate * reg The register whose contents are to be
13357c478bd9Sstevel@tonic-gate * written.
13367c478bd9Sstevel@tonic-gate * val The value to be written to the register.
13377c478bd9Sstevel@tonic-gate *
13387c478bd9Sstevel@tonic-gate * This function uses the TLAN's MII bus to write the contents of a
13397c478bd9Sstevel@tonic-gate * given register on a PHY. It sends the appropriate info and then
13407c478bd9Sstevel@tonic-gate * writes the 16-bit register value from the MII configuration bus
13417c478bd9Sstevel@tonic-gate * via the TLAN SIO register.
13427c478bd9Sstevel@tonic-gate *
13437c478bd9Sstevel@tonic-gate **************************************************************/
13447c478bd9Sstevel@tonic-gate
13457c478bd9Sstevel@tonic-gate void TLan_MiiWriteReg(struct nic *nic __unused, u16 phy, u16 reg, u16 val)
13467c478bd9Sstevel@tonic-gate {
13477c478bd9Sstevel@tonic-gate u16 sio;
13487c478bd9Sstevel@tonic-gate int minten;
13497c478bd9Sstevel@tonic-gate
13507c478bd9Sstevel@tonic-gate outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
13517c478bd9Sstevel@tonic-gate sio = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
13527c478bd9Sstevel@tonic-gate
13537c478bd9Sstevel@tonic-gate TLan_MiiSync(BASE);
13547c478bd9Sstevel@tonic-gate
13557c478bd9Sstevel@tonic-gate minten = TLan_GetBit(TLAN_NET_SIO_MINTEN, sio);
13567c478bd9Sstevel@tonic-gate if (minten)
13577c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, 0x1, 2); /* Start ( 01b ) */
13607c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, 0x1, 2); /* Write ( 01b ) */
13617c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, phy, 5); /* Device # */
13627c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, reg, 5); /* Register # */
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, 0x2, 2); /* Send ACK */
13657c478bd9Sstevel@tonic-gate TLan_MiiSendData(BASE, val, 16); /* Send Data */
13667c478bd9Sstevel@tonic-gate
13677c478bd9Sstevel@tonic-gate TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Idle cycle */
13687c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate if (minten)
13717c478bd9Sstevel@tonic-gate TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate } /* TLan_MiiWriteReg */
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate /***************************************************************
13777c478bd9Sstevel@tonic-gate * TLan_SetMac
13787c478bd9Sstevel@tonic-gate *
13797c478bd9Sstevel@tonic-gate * Returns:
13807c478bd9Sstevel@tonic-gate * Nothing
13817c478bd9Sstevel@tonic-gate * Parms:
13827c478bd9Sstevel@tonic-gate * dev Pointer to device structure of adapter
13837c478bd9Sstevel@tonic-gate * on which to change the AREG.
13847c478bd9Sstevel@tonic-gate * areg The AREG to set the address in (0 - 3).
13857c478bd9Sstevel@tonic-gate * mac A pointer to an array of chars. Each
13867c478bd9Sstevel@tonic-gate * element stores one byte of the address.
13877c478bd9Sstevel@tonic-gate * IE, it isn't in ascii.
13887c478bd9Sstevel@tonic-gate *
13897c478bd9Sstevel@tonic-gate * This function transfers a MAC address to one of the
13907c478bd9Sstevel@tonic-gate * TLAN AREGs (address registers). The TLAN chip locks
13917c478bd9Sstevel@tonic-gate * the register on writing to offset 0 and unlocks the
13927c478bd9Sstevel@tonic-gate * register after writing to offset 5. If NULL is passed
13937c478bd9Sstevel@tonic-gate * in mac, then the AREG is filled with 0's.
13947c478bd9Sstevel@tonic-gate *
13957c478bd9Sstevel@tonic-gate **************************************************************/
13967c478bd9Sstevel@tonic-gate
13977c478bd9Sstevel@tonic-gate void TLan_SetMac(struct nic *nic __unused, int areg, char *mac)
13987c478bd9Sstevel@tonic-gate {
13997c478bd9Sstevel@tonic-gate int i;
14007c478bd9Sstevel@tonic-gate
14017c478bd9Sstevel@tonic-gate areg *= 6;
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate if (mac != NULL) {
14047c478bd9Sstevel@tonic-gate for (i = 0; i < 6; i++)
14057c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_AREG_0 + areg + i,
14067c478bd9Sstevel@tonic-gate mac[i]);
14077c478bd9Sstevel@tonic-gate } else {
14087c478bd9Sstevel@tonic-gate for (i = 0; i < 6; i++)
14097c478bd9Sstevel@tonic-gate TLan_DioWrite8(BASE, TLAN_AREG_0 + areg + i, 0);
14107c478bd9Sstevel@tonic-gate }
14117c478bd9Sstevel@tonic-gate
14127c478bd9Sstevel@tonic-gate } /* TLan_SetMac */
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate /*********************************************************************
14157c478bd9Sstevel@tonic-gate * TLan_PhyDetect
14167c478bd9Sstevel@tonic-gate *
14177c478bd9Sstevel@tonic-gate * Returns:
14187c478bd9Sstevel@tonic-gate * Nothing
14197c478bd9Sstevel@tonic-gate * Parms:
14207c478bd9Sstevel@tonic-gate * dev A pointer to the device structure of the adapter
14217c478bd9Sstevel@tonic-gate * for which the PHY needs determined.
14227c478bd9Sstevel@tonic-gate *
14237c478bd9Sstevel@tonic-gate * So far I've found that adapters which have external PHYs
14247c478bd9Sstevel@tonic-gate * may also use the internal PHY for part of the functionality.
14257c478bd9Sstevel@tonic-gate * (eg, AUI/Thinnet). This function finds out if this TLAN
14267c478bd9Sstevel@tonic-gate * chip has an internal PHY, and then finds the first external
14277c478bd9Sstevel@tonic-gate * PHY (starting from address 0) if it exists).
14287c478bd9Sstevel@tonic-gate *
14297c478bd9Sstevel@tonic-gate ********************************************************************/
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate void TLan_PhyDetect(struct nic *nic)
14327c478bd9Sstevel@tonic-gate {
14337c478bd9Sstevel@tonic-gate u16 control;
14347c478bd9Sstevel@tonic-gate u16 hi;
14357c478bd9Sstevel@tonic-gate u16 lo;
14367c478bd9Sstevel@tonic-gate u32 phy;
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY) {
14397c478bd9Sstevel@tonic-gate priv->phyNum = 0xFFFF;
14407c478bd9Sstevel@tonic-gate return;
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi);
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate if (hi != 0xFFFF) {
14467c478bd9Sstevel@tonic-gate priv->phy[0] = TLAN_PHY_MAX_ADDR;
14477c478bd9Sstevel@tonic-gate } else {
14487c478bd9Sstevel@tonic-gate priv->phy[0] = TLAN_PHY_NONE;
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate
14517c478bd9Sstevel@tonic-gate priv->phy[1] = TLAN_PHY_NONE;
14527c478bd9Sstevel@tonic-gate for (phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++) {
14537c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_CTL, &control);
14547c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_ID_HI, &hi);
14557c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_ID_LO, &lo);
14567c478bd9Sstevel@tonic-gate if ((control != 0xFFFF) || (hi != 0xFFFF)
14577c478bd9Sstevel@tonic-gate || (lo != 0xFFFF)) {
14587c478bd9Sstevel@tonic-gate printf("PHY found at %hX %hX %hX %hX\n", phy,
14597c478bd9Sstevel@tonic-gate control, hi, lo);
14607c478bd9Sstevel@tonic-gate if ((priv->phy[1] == TLAN_PHY_NONE)
14617c478bd9Sstevel@tonic-gate && (phy != TLAN_PHY_MAX_ADDR)) {
14627c478bd9Sstevel@tonic-gate priv->phy[1] = phy;
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate }
14657c478bd9Sstevel@tonic-gate }
14667c478bd9Sstevel@tonic-gate
14677c478bd9Sstevel@tonic-gate if (priv->phy[1] != TLAN_PHY_NONE) {
14687c478bd9Sstevel@tonic-gate priv->phyNum = 1;
14697c478bd9Sstevel@tonic-gate } else if (priv->phy[0] != TLAN_PHY_NONE) {
14707c478bd9Sstevel@tonic-gate priv->phyNum = 0;
14717c478bd9Sstevel@tonic-gate } else {
14727c478bd9Sstevel@tonic-gate printf
14737c478bd9Sstevel@tonic-gate ("TLAN: Cannot initialize device, no PHY was found!\n");
14747c478bd9Sstevel@tonic-gate }
14757c478bd9Sstevel@tonic-gate
14767c478bd9Sstevel@tonic-gate } /* TLan_PhyDetect */
14777c478bd9Sstevel@tonic-gate
14787c478bd9Sstevel@tonic-gate void TLan_PhyPowerDown(struct nic *nic)
14797c478bd9Sstevel@tonic-gate {
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate u16 value;
14827c478bd9Sstevel@tonic-gate printf("%s: Powering down PHY(s).\n", priv->nic_name);
14837c478bd9Sstevel@tonic-gate value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE;
14847c478bd9Sstevel@tonic-gate TLan_MiiSync(BASE);
14857c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, priv->phy[priv->phyNum], MII_GEN_CTL, value);
14867c478bd9Sstevel@tonic-gate if ((priv->phyNum == 0) && (priv->phy[1] != TLAN_PHY_NONE)
14877c478bd9Sstevel@tonic-gate &&
14887c478bd9Sstevel@tonic-gate (!(tlan_pci_tbl[chip_idx].
14897c478bd9Sstevel@tonic-gate flags & TLAN_ADAPTER_USE_INTERN_10))) {
14907c478bd9Sstevel@tonic-gate TLan_MiiSync(BASE);
14917c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, priv->phy[1], MII_GEN_CTL, value);
14927c478bd9Sstevel@tonic-gate }
14937c478bd9Sstevel@tonic-gate
14947c478bd9Sstevel@tonic-gate /* Wait for 50 ms and powerup
14957c478bd9Sstevel@tonic-gate * This is abitrary. It is intended to make sure the
14967c478bd9Sstevel@tonic-gate * tranceiver settles.
14977c478bd9Sstevel@tonic-gate */
14987c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_PUP ); */
14997c478bd9Sstevel@tonic-gate mdelay(50);
15007c478bd9Sstevel@tonic-gate TLan_PhyPowerUp(nic);
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate } /* TLan_PhyPowerDown */
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate void TLan_PhyPowerUp(struct nic *nic)
15067c478bd9Sstevel@tonic-gate {
15077c478bd9Sstevel@tonic-gate u16 value;
15087c478bd9Sstevel@tonic-gate
15097c478bd9Sstevel@tonic-gate printf("%s: Powering up PHY.\n", priv->nic_name);
15107c478bd9Sstevel@tonic-gate TLan_MiiSync(BASE);
15117c478bd9Sstevel@tonic-gate value = MII_GC_LOOPBK;
15127c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, priv->phy[priv->phyNum], MII_GEN_CTL, value);
15137c478bd9Sstevel@tonic-gate TLan_MiiSync(BASE);
15147c478bd9Sstevel@tonic-gate /* Wait for 500 ms and reset the
15157c478bd9Sstevel@tonic-gate * tranceiver. The TLAN docs say both 50 ms and
15167c478bd9Sstevel@tonic-gate * 500 ms, so do the longer, just in case.
15177c478bd9Sstevel@tonic-gate */
15187c478bd9Sstevel@tonic-gate mdelay(500);
15197c478bd9Sstevel@tonic-gate TLan_PhyReset(nic);
15207c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_RESET ); */
15217c478bd9Sstevel@tonic-gate
15227c478bd9Sstevel@tonic-gate } /* TLan_PhyPowerUp */
15237c478bd9Sstevel@tonic-gate
15247c478bd9Sstevel@tonic-gate void TLan_PhyReset(struct nic *nic)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate u16 phy;
15277c478bd9Sstevel@tonic-gate u16 value;
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate phy = priv->phy[priv->phyNum];
15307c478bd9Sstevel@tonic-gate
15317c478bd9Sstevel@tonic-gate printf("%s: Reseting PHY.\n", priv->nic_name);
15327c478bd9Sstevel@tonic-gate TLan_MiiSync(BASE);
15337c478bd9Sstevel@tonic-gate value = MII_GC_LOOPBK | MII_GC_RESET;
15347c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, value);
15357c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_CTL, &value);
15367c478bd9Sstevel@tonic-gate while (value & MII_GC_RESET) {
15377c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_CTL, &value);
15387c478bd9Sstevel@tonic-gate }
15397c478bd9Sstevel@tonic-gate
15407c478bd9Sstevel@tonic-gate /* Wait for 500 ms and initialize.
15417c478bd9Sstevel@tonic-gate * I don't remember why I wait this long.
15427c478bd9Sstevel@tonic-gate * I've changed this to 50ms, as it seems long enough.
15437c478bd9Sstevel@tonic-gate */
15447c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_START_LINK ); */
15457c478bd9Sstevel@tonic-gate mdelay(50);
15467c478bd9Sstevel@tonic-gate TLan_PhyStartLink(nic);
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate } /* TLan_PhyReset */
15497c478bd9Sstevel@tonic-gate
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate void TLan_PhyStartLink(struct nic *nic)
15527c478bd9Sstevel@tonic-gate {
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate u16 ability;
15557c478bd9Sstevel@tonic-gate u16 control;
15567c478bd9Sstevel@tonic-gate u16 data;
15577c478bd9Sstevel@tonic-gate u16 phy;
15587c478bd9Sstevel@tonic-gate u16 status;
15597c478bd9Sstevel@tonic-gate u16 tctl;
15607c478bd9Sstevel@tonic-gate
15617c478bd9Sstevel@tonic-gate phy = priv->phy[priv->phyNum];
15627c478bd9Sstevel@tonic-gate printf("%s: Trying to activate link.\n", priv->nic_name);
15637c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
15647c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_STS, &ability);
15657c478bd9Sstevel@tonic-gate
15667c478bd9Sstevel@tonic-gate if ((status & MII_GS_AUTONEG) && (!priv->aui)) {
15677c478bd9Sstevel@tonic-gate ability = status >> 11;
15687c478bd9Sstevel@tonic-gate if (priv->speed == TLAN_SPEED_10 &&
15697c478bd9Sstevel@tonic-gate priv->duplex == TLAN_DUPLEX_HALF) {
15707c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x0000);
15717c478bd9Sstevel@tonic-gate } else if (priv->speed == TLAN_SPEED_10 &&
15727c478bd9Sstevel@tonic-gate priv->duplex == TLAN_DUPLEX_FULL) {
15737c478bd9Sstevel@tonic-gate priv->tlanFullDuplex = TRUE;
15747c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x0100);
15757c478bd9Sstevel@tonic-gate } else if (priv->speed == TLAN_SPEED_100 &&
15767c478bd9Sstevel@tonic-gate priv->duplex == TLAN_DUPLEX_HALF) {
15777c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x2000);
15787c478bd9Sstevel@tonic-gate } else if (priv->speed == TLAN_SPEED_100 &&
15797c478bd9Sstevel@tonic-gate priv->duplex == TLAN_DUPLEX_FULL) {
15807c478bd9Sstevel@tonic-gate priv->tlanFullDuplex = TRUE;
15817c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x2100);
15827c478bd9Sstevel@tonic-gate } else {
15837c478bd9Sstevel@tonic-gate
15847c478bd9Sstevel@tonic-gate /* Set Auto-Neg advertisement */
15857c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_AN_ADV,
15867c478bd9Sstevel@tonic-gate (ability << 5) | 1);
15877c478bd9Sstevel@tonic-gate /* Enablee Auto-Neg */
15887c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x1000);
15897c478bd9Sstevel@tonic-gate /* Restart Auto-Neg */
15907c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x1200);
15917c478bd9Sstevel@tonic-gate /* Wait for 4 sec for autonegotiation
15927c478bd9Sstevel@tonic-gate * to complete. The max spec time is less than this
15937c478bd9Sstevel@tonic-gate * but the card need additional time to start AN.
15947c478bd9Sstevel@tonic-gate * .5 sec should be plenty extra.
15957c478bd9Sstevel@tonic-gate */
15967c478bd9Sstevel@tonic-gate printf("TLAN: %s: Starting autonegotiation.\n",
15977c478bd9Sstevel@tonic-gate priv->nic_name);
15987c478bd9Sstevel@tonic-gate mdelay(4000);
15997c478bd9Sstevel@tonic-gate TLan_PhyFinishAutoNeg(nic);
16007c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN ); */
16017c478bd9Sstevel@tonic-gate return;
16027c478bd9Sstevel@tonic-gate }
16037c478bd9Sstevel@tonic-gate
16047c478bd9Sstevel@tonic-gate }
16057c478bd9Sstevel@tonic-gate
16067c478bd9Sstevel@tonic-gate if ((priv->aui) && (priv->phyNum != 0)) {
16077c478bd9Sstevel@tonic-gate priv->phyNum = 0;
16087c478bd9Sstevel@tonic-gate data =
16097c478bd9Sstevel@tonic-gate TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN |
16107c478bd9Sstevel@tonic-gate TLAN_NET_CFG_PHY_EN;
16117c478bd9Sstevel@tonic-gate TLan_DioWrite16(BASE, TLAN_NET_CONFIG, data);
16127c478bd9Sstevel@tonic-gate mdelay(50);
16137c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN ); */
16147c478bd9Sstevel@tonic-gate TLan_PhyPowerDown(nic);
16157c478bd9Sstevel@tonic-gate return;
16167c478bd9Sstevel@tonic-gate } else if (priv->phyNum == 0) {
16177c478bd9Sstevel@tonic-gate control = 0;
16187c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, TLAN_TLPHY_CTL, &tctl);
16197c478bd9Sstevel@tonic-gate if (priv->aui) {
16207c478bd9Sstevel@tonic-gate tctl |= TLAN_TC_AUISEL;
16217c478bd9Sstevel@tonic-gate } else {
16227c478bd9Sstevel@tonic-gate tctl &= ~TLAN_TC_AUISEL;
16237c478bd9Sstevel@tonic-gate if (priv->duplex == TLAN_DUPLEX_FULL) {
16247c478bd9Sstevel@tonic-gate control |= MII_GC_DUPLEX;
16257c478bd9Sstevel@tonic-gate priv->tlanFullDuplex = TRUE;
16267c478bd9Sstevel@tonic-gate }
16277c478bd9Sstevel@tonic-gate if (priv->speed == TLAN_SPEED_100) {
16287c478bd9Sstevel@tonic-gate control |= MII_GC_SPEEDSEL;
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, control);
16327c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, TLAN_TLPHY_CTL, tctl);
16337c478bd9Sstevel@tonic-gate }
16347c478bd9Sstevel@tonic-gate
16357c478bd9Sstevel@tonic-gate /* Wait for 2 sec to give the tranceiver time
16367c478bd9Sstevel@tonic-gate * to establish link.
16377c478bd9Sstevel@tonic-gate */
16387c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_FINISH_RESET ); */
16397c478bd9Sstevel@tonic-gate mdelay(2000);
16407c478bd9Sstevel@tonic-gate TLan_FinishReset(nic);
16417c478bd9Sstevel@tonic-gate
16427c478bd9Sstevel@tonic-gate } /* TLan_PhyStartLink */
16437c478bd9Sstevel@tonic-gate
16447c478bd9Sstevel@tonic-gate void TLan_PhyFinishAutoNeg(struct nic *nic)
16457c478bd9Sstevel@tonic-gate {
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate u16 an_adv;
16487c478bd9Sstevel@tonic-gate u16 an_lpa;
16497c478bd9Sstevel@tonic-gate u16 data;
16507c478bd9Sstevel@tonic-gate u16 mode;
16517c478bd9Sstevel@tonic-gate u16 phy;
16527c478bd9Sstevel@tonic-gate u16 status;
16537c478bd9Sstevel@tonic-gate
16547c478bd9Sstevel@tonic-gate phy = priv->phy[priv->phyNum];
16557c478bd9Sstevel@tonic-gate
16567c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
16577c478bd9Sstevel@tonic-gate udelay(1000);
16587c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
16597c478bd9Sstevel@tonic-gate
16607c478bd9Sstevel@tonic-gate if (!(status & MII_GS_AUTOCMPLT)) {
16617c478bd9Sstevel@tonic-gate /* Wait for 8 sec to give the process
16627c478bd9Sstevel@tonic-gate * more time. Perhaps we should fail after a while.
16637c478bd9Sstevel@tonic-gate */
16647c478bd9Sstevel@tonic-gate if (!priv->neg_be_verbose++) {
16657c478bd9Sstevel@tonic-gate printf
16667c478bd9Sstevel@tonic-gate ("TLAN: Giving autonegotiation more time.\n");
16677c478bd9Sstevel@tonic-gate printf
16687c478bd9Sstevel@tonic-gate ("TLAN: Please check that your adapter has\n");
16697c478bd9Sstevel@tonic-gate printf
16707c478bd9Sstevel@tonic-gate ("TLAN: been properly connected to a HUB or Switch.\n");
16717c478bd9Sstevel@tonic-gate printf
16727c478bd9Sstevel@tonic-gate ("TLAN: Trying to establish link in the background...\n");
16737c478bd9Sstevel@tonic-gate }
16747c478bd9Sstevel@tonic-gate mdelay(8000);
16757c478bd9Sstevel@tonic-gate TLan_PhyFinishAutoNeg(nic);
16767c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); */
16777c478bd9Sstevel@tonic-gate return;
16787c478bd9Sstevel@tonic-gate }
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate printf("TLAN: %s: Autonegotiation complete.\n", priv->nic_name);
16817c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_AN_ADV, &an_adv);
16827c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_AN_LPA, &an_lpa);
16837c478bd9Sstevel@tonic-gate mode = an_adv & an_lpa & 0x03E0;
16847c478bd9Sstevel@tonic-gate if (mode & 0x0100) {
16857c478bd9Sstevel@tonic-gate printf("Full Duplex\n");
16867c478bd9Sstevel@tonic-gate priv->tlanFullDuplex = TRUE;
16877c478bd9Sstevel@tonic-gate } else if (!(mode & 0x0080) && (mode & 0x0040)) {
16887c478bd9Sstevel@tonic-gate priv->tlanFullDuplex = TRUE;
16897c478bd9Sstevel@tonic-gate printf("Full Duplex\n");
16907c478bd9Sstevel@tonic-gate }
16917c478bd9Sstevel@tonic-gate
16927c478bd9Sstevel@tonic-gate if ((!(mode & 0x0180))
16937c478bd9Sstevel@tonic-gate && (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_USE_INTERN_10)
16947c478bd9Sstevel@tonic-gate && (priv->phyNum != 0)) {
16957c478bd9Sstevel@tonic-gate priv->phyNum = 0;
16967c478bd9Sstevel@tonic-gate data =
16977c478bd9Sstevel@tonic-gate TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN |
16987c478bd9Sstevel@tonic-gate TLAN_NET_CFG_PHY_EN;
16997c478bd9Sstevel@tonic-gate TLan_DioWrite16(BASE, TLAN_NET_CONFIG, data);
17007c478bd9Sstevel@tonic-gate /* TLan_SetTimer( nic, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN ); */
17017c478bd9Sstevel@tonic-gate mdelay(400);
17027c478bd9Sstevel@tonic-gate TLan_PhyPowerDown(nic);
17037c478bd9Sstevel@tonic-gate return;
17047c478bd9Sstevel@tonic-gate }
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate if (priv->phyNum == 0) {
17077c478bd9Sstevel@tonic-gate if ((priv->duplex == TLAN_DUPLEX_FULL)
17087c478bd9Sstevel@tonic-gate || (an_adv & an_lpa & 0x0040)) {
17097c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL,
17107c478bd9Sstevel@tonic-gate MII_GC_AUTOENB | MII_GC_DUPLEX);
17117c478bd9Sstevel@tonic-gate printf
17127c478bd9Sstevel@tonic-gate ("TLAN: Starting internal PHY with FULL-DUPLEX\n");
17137c478bd9Sstevel@tonic-gate } else {
17147c478bd9Sstevel@tonic-gate TLan_MiiWriteReg(nic, phy, MII_GEN_CTL,
17157c478bd9Sstevel@tonic-gate MII_GC_AUTOENB);
17167c478bd9Sstevel@tonic-gate printf
17177c478bd9Sstevel@tonic-gate ("TLAN: Starting internal PHY with HALF-DUPLEX\n");
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate }
17207c478bd9Sstevel@tonic-gate
17217c478bd9Sstevel@tonic-gate /* Wait for 100 ms. No reason in partiticular.
17227c478bd9Sstevel@tonic-gate */
17237c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET ); */
17247c478bd9Sstevel@tonic-gate mdelay(100);
17257c478bd9Sstevel@tonic-gate TLan_FinishReset(nic);
17267c478bd9Sstevel@tonic-gate
17277c478bd9Sstevel@tonic-gate } /* TLan_PhyFinishAutoNeg */
17287c478bd9Sstevel@tonic-gate
17297c478bd9Sstevel@tonic-gate #ifdef MONITOR
17307c478bd9Sstevel@tonic-gate
17317c478bd9Sstevel@tonic-gate /*********************************************************************
17327c478bd9Sstevel@tonic-gate *
17337c478bd9Sstevel@tonic-gate * TLan_phyMonitor
17347c478bd9Sstevel@tonic-gate *
17357c478bd9Sstevel@tonic-gate * Returns:
17367c478bd9Sstevel@tonic-gate * None
17377c478bd9Sstevel@tonic-gate *
17387c478bd9Sstevel@tonic-gate * Params:
17397c478bd9Sstevel@tonic-gate * dev The device structure of this device.
17407c478bd9Sstevel@tonic-gate *
17417c478bd9Sstevel@tonic-gate *
17427c478bd9Sstevel@tonic-gate * This function monitors PHY condition by reading the status
17437c478bd9Sstevel@tonic-gate * register via the MII bus. This can be used to give info
17447c478bd9Sstevel@tonic-gate * about link changes (up/down), and possible switch to alternate
17457c478bd9Sstevel@tonic-gate * media.
17467c478bd9Sstevel@tonic-gate *
17477c478bd9Sstevel@tonic-gate * ******************************************************************/
17487c478bd9Sstevel@tonic-gate
17497c478bd9Sstevel@tonic-gate void TLan_PhyMonitor(struct net_device *dev)
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate TLanPrivateInfo *priv = dev->priv;
17527c478bd9Sstevel@tonic-gate u16 phy;
17537c478bd9Sstevel@tonic-gate u16 phy_status;
17547c478bd9Sstevel@tonic-gate
17557c478bd9Sstevel@tonic-gate phy = priv->phy[priv->phyNum];
17567c478bd9Sstevel@tonic-gate
17577c478bd9Sstevel@tonic-gate /* Get PHY status register */
17587c478bd9Sstevel@tonic-gate TLan_MiiReadReg(nic, phy, MII_GEN_STS, &phy_status);
17597c478bd9Sstevel@tonic-gate
17607c478bd9Sstevel@tonic-gate /* Check if link has been lost */
17617c478bd9Sstevel@tonic-gate if (!(phy_status & MII_GS_LINK)) {
17627c478bd9Sstevel@tonic-gate if (priv->link) {
17637c478bd9Sstevel@tonic-gate priv->link = 0;
17647c478bd9Sstevel@tonic-gate printf("TLAN: %s has lost link\n", priv->nic_name);
17657c478bd9Sstevel@tonic-gate priv->flags &= ~IFF_RUNNING;
17667c478bd9Sstevel@tonic-gate mdelay(2000);
17677c478bd9Sstevel@tonic-gate TLan_PhyMonitor(nic);
17687c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); */
17697c478bd9Sstevel@tonic-gate return;
17707c478bd9Sstevel@tonic-gate }
17717c478bd9Sstevel@tonic-gate }
17727c478bd9Sstevel@tonic-gate
17737c478bd9Sstevel@tonic-gate /* Link restablished? */
17747c478bd9Sstevel@tonic-gate if ((phy_status & MII_GS_LINK) && !priv->link) {
17757c478bd9Sstevel@tonic-gate priv->link = 1;
17767c478bd9Sstevel@tonic-gate printf("TLAN: %s has reestablished link\n",
17777c478bd9Sstevel@tonic-gate priv->nic_name);
17787c478bd9Sstevel@tonic-gate priv->flags |= IFF_RUNNING;
17797c478bd9Sstevel@tonic-gate }
17807c478bd9Sstevel@tonic-gate
17817c478bd9Sstevel@tonic-gate /* Setup a new monitor */
17827c478bd9Sstevel@tonic-gate /* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); */
17837c478bd9Sstevel@tonic-gate mdelay(2000);
17847c478bd9Sstevel@tonic-gate TLan_PhyMonitor(nic);
17857c478bd9Sstevel@tonic-gate }
17867c478bd9Sstevel@tonic-gate
17877c478bd9Sstevel@tonic-gate #endif /* MONITOR */
17887c478bd9Sstevel@tonic-gate
17897c478bd9Sstevel@tonic-gate #ifdef EB51
17907c478bd9Sstevel@tonic-gate static struct pci_id tlan_nics[] = {
17917c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xae34, "netel10", "Compaq Netelligent 10 T PCI UTP"),
17927c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xae32, "netel100","Compaq Netelligent 10/100 TX PCI UTP"),
17937c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xae35, "netflex3i", "Compaq Integrated NetFlex-3/P"),
17947c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xf130, "thunder", "Compaq NetFlex-3/P"),
17957c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xf150, "netflex3b", "Compaq NetFlex-3/P"),
17967c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xae43, "netel100pi", "Compaq Netelligent Integrated 10/100 TX UTP"),
17977c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xae40, "netel100d", "Compaq Netelligent Dual 10/100 TX PCI UTP"),
17987c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xb011, "netel100i", "Compaq Netelligent 10/100 TX Embedded UTP"),
17997c478bd9Sstevel@tonic-gate PCI_ROM(0x108d, 0x0013, "oc2183", "Olicom OC-2183/2185"),
18007c478bd9Sstevel@tonic-gate PCI_ROM(0x108d, 0x0012, "oc2325", "Olicom OC-2325"),
18017c478bd9Sstevel@tonic-gate PCI_ROM(0x108d, 0x0014, "oc2326", "Olicom OC-2326"),
18027c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xb030, "netelligent_10_100_ws_5100", "Compaq Netelligent 10/100 TX UTP"),
18037c478bd9Sstevel@tonic-gate PCI_ROM(0x0e11, 0xb012, "netelligent_10_t2", "Compaq Netelligent 10 T/2 PCI UTP/Coax"),
18047c478bd9Sstevel@tonic-gate };
18057c478bd9Sstevel@tonic-gate
18067c478bd9Sstevel@tonic-gate struct pci_driver tlan_driver = {
18077c478bd9Sstevel@tonic-gate .type = NIC_DRIVER,
18087c478bd9Sstevel@tonic-gate .name = "TLAN/PCI",
18097c478bd9Sstevel@tonic-gate .probe = tlan_probe,
18107c478bd9Sstevel@tonic-gate .ids = tlan_nics,
18117c478bd9Sstevel@tonic-gate .id_count = sizeof(tlan_nics) / sizeof(tlan_nics[0]),
18127c478bd9Sstevel@tonic-gate .class = 0,
18137c478bd9Sstevel@tonic-gate };
18147c478bd9Sstevel@tonic-gate #endif
1815