📄 tlan.c
字号:
#define EB51#ifdef EB50#define __unused __attribute__((unused))#endif/**************************************************************************** tlan.c -- Etherboot device driver for the Texas Instruments ThunderLAN* Written 2003-2003 by Timothy Legge <tlegge@rogers.com>** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.** Portions of this code based on:* lan.c: Linux ThunderLan Driver:** by James Banks** (C) 1997-1998 Caldera, Inc.* (C) 1998 James Banks* (C) 1999-2001 Torben Mathiasen* (C) 2002 Samuel Chessman** REVISION HISTORY:* ================* v1.0 07-08-2003 timlegge Initial not quite working version* v1.1 07-27-2003 timlegge Sync 5.0 and 5.1 versions* v1.2 08-19-2003 timlegge Implement Multicast Support* v1.3 08-23-2003 timlegge Fix the transmit Function* v1.4 01-17-2004 timlegge Initial driver output cleanup * * Indent Options: indent -kr -i8***************************************************************************//* to get some global routines like printf */#include "etherboot.h"/* to get the interface to the body of the program */#include "nic.h"/* to get the PCI support functions, if this is a PCI NIC */#include "pci.h"#include "timer.h"#include "tlan.h"#define drv_version "v1.4"#define drv_date "01-17-2004"/* NIC specific static variables go here */#define HZ 100#define TX_TIME_OUT (6*HZ)#ifdef EB50#define cpu_to_le32(val) (val)#define le32_to_cpu(val) (val)#define virt_to_bus(x) ((unsigned long) x)#define bus_to_virt(x) ((unsigned long) x)#endif/* Condensed operations for readability. */#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))static void TLan_ResetLists(struct nic *nic __unused);static void TLan_ResetAdapter(struct nic *nic __unused);static void TLan_FinishReset(struct nic *nic __unused);static void TLan_EeSendStart(u16);static int TLan_EeSendByte(u16, u8, int);static void TLan_EeReceiveByte(u16, u8 *, int);static int TLan_EeReadByte(u16 io_base, u8, u8 *);static void TLan_PhyDetect(struct nic *nic);static void TLan_PhyPowerDown(struct nic *nic);static void TLan_PhyPowerUp(struct nic *nic);static void TLan_SetMac(struct nic *nic __unused, int areg, char *mac);static void TLan_PhyReset(struct nic *nic);static void TLan_PhyStartLink(struct nic *nic);static void TLan_PhyFinishAutoNeg(struct nic *nic);#ifdef MONITORstatic void TLan_PhyMonitor(struct nic *nic);#endifstatic void refill_rx(struct nic *nic __unused);static int TLan_MiiReadReg(struct nic *nic __unused, u16, u16, u16 *);static void TLan_MiiSendData(u16, u32, unsigned);static void TLan_MiiSync(u16);static void TLan_MiiWriteReg(struct nic *nic __unused, u16, u16, u16);const char *media[] = { "10BaseT-HD ", "10BaseT-FD ", "100baseTx-HD ", "100baseTx-FD", "100baseT4", 0};/* This much match tlan_pci_tbl[]! */enum tlan_nics { NETEL10 = 0, NETEL100 = 1, NETFLEX3I = 2, THUNDER = 3, NETFLEX3B = 4, NETEL100PI = 5, NETEL100D = 6, NETEL100I = 7, OC2183 = 8, OC2325 = 9, OC2326 = 10, NETELLIGENT_10_100_WS_5100 = 11, NETELLIGENT_10_T2 = 12};struct pci_id_info { const char *name; int nic_id; struct match_info { u32 pci, pci_mask, subsystem, subsystem_mask; u32 revision, revision_mask; /* Only 8 bits. */ } id; u32 flags; u16 addrOfs; /* Address Offset */};static struct pci_id_info tlan_pci_tbl[] = { {"Compaq Netelligent 10 T PCI UTP", NETEL10, {0xae340e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_ACTIVITY_LED, 0x83}, {"Compaq Netelligent 10/100 TX PCI UTP", NETEL100, {0xae320e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_ACTIVITY_LED, 0x83}, {"Compaq Integrated NetFlex-3/P", NETFLEX3I, {0xae350e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_NONE, 0x83}, {"Compaq NetFlex-3/P", THUNDER, {0xf1300e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83}, {"Compaq NetFlex-3/P", NETFLEX3B, {0xf1500e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_NONE, 0x83}, {"Compaq Netelligent Integrated 10/100 TX UTP", NETEL100PI, {0xae430e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_ACTIVITY_LED, 0x83}, {"Compaq Netelligent Dual 10/100 TX PCI UTP", NETEL100D, {0xae400e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_NONE, 0x83}, {"Compaq Netelligent 10/100 TX Embedded UTP", NETEL100I, {0xb0110e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_NONE, 0x83}, {"Olicom OC-2183/2185", OC2183, {0x0013108d, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_USE_INTERN_10, 0x83}, {"Olicom OC-2325", OC2325, {0x0012108d, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_UNMANAGED_PHY, 0xF8}, {"Olicom OC-2326", OC2326, {0x0014108d, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_USE_INTERN_10, 0xF8}, {"Compaq Netelligent 10/100 TX UTP", NETELLIGENT_10_100_WS_5100, {0xb0300e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_ACTIVITY_LED, 0x83}, {"Compaq Netelligent 10 T/2 PCI UTP/Coax", NETELLIGENT_10_T2, {0xb0120e11, 0xffffffff, 0, 0, 0, 0}, TLAN_ADAPTER_NONE, 0x83}, {"Compaq NetFlex-3/E", 0, /* EISA card */ {0, 0, 0, 0, 0, 0}, TLAN_ADAPTER_ACTIVITY_LED | TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83}, {"Compaq NetFlex-3/E", 0, /* EISA card */ {0, 0, 0, 0, 0, 0}, TLAN_ADAPTER_ACTIVITY_LED, 0x83}, {0, 0, {0, 0, 0, 0, 0, 0}, 0, 0},};struct TLanList { u32 forward; u16 cStat; u16 frameSize; struct { u32 count; u32 address; } buffer[TLAN_BUFFERS_PER_LIST];};struct TLanList tx_ring[TLAN_NUM_TX_LISTS];static unsigned char txb[TLAN_MAX_FRAME_SIZE * TLAN_NUM_TX_LISTS];struct TLanList rx_ring[TLAN_NUM_RX_LISTS];static unsigned char rxb[TLAN_MAX_FRAME_SIZE * TLAN_NUM_RX_LISTS];typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE];int chip_idx;/****************************************************************** TLAN Private Information Structure*****************************************************************/struct tlan_private { unsigned short vendor_id; /* PCI Vendor code */ unsigned short dev_id; /* PCI Device code */ const char *nic_name; u8 *padBuffer; u8 *rxBuffer; struct TLanList *rx_head_desc; u32 rxHead; u32 rxTail; u32 rxEocCount; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indicies */ unsigned int cur_tx, dirty_tx; unsigned rx_buf_sz; /* Based on mtu + Slack */ struct TLanList *txList; struct TLanList *rxList; u8 *txBuffer; u32 txHead; u32 txInProgress; u32 txTail; int eoc; u32 txBusyCount; u32 phyOnline; u32 timerSetAt; u32 timerType; u32 adapterRev; u32 aui; u32 debug; u32 duplex; u32 phy[2]; u32 phyNum; u32 speed; u8 tlanRev; u8 tlanFullDuplex; char devName[8]; u8 link; u8 is_eisa; u8 neg_be_verbose;} TLanPrivateInfo;static struct tlan_private *priv;u32 BASE;/**************************************************************** TLan_ResetLists** Returns:* Nothing* Parms:* dev The device structure with the list* stuctures to be reset.** This routine sets the variables associated with managing* the TLAN lists to their initial values.***************************************************************/void TLan_ResetLists(struct nic *nic __unused){ int i; struct TLanList *list; priv->txHead = 0; priv->txTail = 0; for (i = 0; i < TLAN_NUM_TX_LISTS; i++) { list = &tx_ring[i]; list->cStat = TLAN_CSTAT_UNUSED;/* list->buffer[0].address = 0; */ list->buffer[0].address = virt_to_bus(txb + (i * TLAN_MAX_FRAME_SIZE)); list->buffer[2].count = 0; list->buffer[2].address = 0; list->buffer[9].address = 0;/* list->forward = 0; */ } priv->cur_rx = 0; priv->rx_buf_sz = (TLAN_MAX_FRAME_SIZE); priv->rx_head_desc = &rx_ring[0]; /* Initialize all the Rx descriptors */ for (i = 0; i < TLAN_NUM_RX_LISTS; i++) { rx_ring[i].forward = virt_to_le32desc(&rx_ring[i + 1]); rx_ring[i].cStat = TLAN_CSTAT_READY; rx_ring[i].frameSize = TLAN_MAX_FRAME_SIZE; rx_ring[i].buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; rx_ring[i].buffer[0].address = virt_to_le32desc(&rxb[i * TLAN_MAX_FRAME_SIZE]); rx_ring[i].buffer[1].count = 0; rx_ring[i].buffer[1].address = 0; } /* Mark the last entry as wrapping the ring */ rx_ring[i - 1].forward = virt_to_le32desc(&rx_ring[0]); priv->dirty_rx = (unsigned int) (i - TLAN_NUM_RX_LISTS);} /* TLan_ResetLists *//**************************************************************** TLan_Reset** Returns:* 0* Parms:* dev Pointer to device structure of adapter* to be reset.** This function resets the adapter and it's physical* device. See Chap. 3, pp. 9-10 of the "ThunderLAN* Programmer's Guide" for details. The routine tries to* implement what is detailed there, though adjustments* have been made.***************************************************************/void TLan_ResetAdapter(struct nic *nic __unused){ int i; u32 addr; u32 data; u8 data8; priv->tlanFullDuplex = FALSE; priv->phyOnline = 0;/* 1. Assert reset bit. */ data = inl(BASE + TLAN_HOST_CMD); data |= TLAN_HC_AD_RST; outl(data, BASE + TLAN_HOST_CMD); udelay(1000);/* 2. Turn off interrupts. ( Probably isn't necessary ) */ data = inl(BASE + TLAN_HOST_CMD); data |= TLAN_HC_INT_OFF; outl(data, BASE + TLAN_HOST_CMD);/* 3. Clear AREGs and HASHs. */ for (i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4) { TLan_DioWrite32(BASE, (u16) i, 0); }/* 4. Setup NetConfig register. */ data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16(BASE, TLAN_NET_CONFIG, (u16) data);/* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */ outl(TLAN_HC_LD_TMR | 0x3f, BASE + TLAN_HOST_CMD); outl(TLAN_HC_LD_THR | 0x0, BASE + TLAN_HOST_CMD);/* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */ outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR); addr = BASE + TLAN_DIO_DATA + TLAN_NET_SIO; TLan_SetBit(TLAN_NET_SIO_NMRST, addr);/* 7. Setup the remaining registers. */ if (priv->tlanRev >= 0x30) { data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC; TLan_DioWrite8(BASE, TLAN_INT_DIS, data8); } TLan_PhyDetect(nic); data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN; if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_BIT_RATE_PHY) { data |= TLAN_NET_CFG_BIT; if (priv->aui == 1) { TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x0a); } else if (priv->duplex == TLAN_DUPLEX_FULL) { TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x00); priv->tlanFullDuplex = TRUE; } else { TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x08); } } if (priv->phyNum == 0) { data |= TLAN_NET_CFG_PHY_EN; } TLan_DioWrite16(BASE, TLAN_NET_CONFIG, (u16) data); if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY) { TLan_FinishReset(nic); } else { TLan_PhyPowerDown(nic); }} /* TLan_ResetAdapter */void TLan_FinishReset(struct nic *nic){ u8 data; u32 phy; u8 sio; u16 status; u16 partner; u16 tlphy_ctl; u16 tlphy_par; u16 tlphy_id1, tlphy_id2; int i; phy = priv->phy[priv->phyNum]; data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP; if (priv->tlanFullDuplex) { data |= TLAN_NET_CMD_DUPLEX; } TLan_DioWrite8(BASE, TLAN_NET_CMD, data); data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; if (priv->phyNum == 0) { data |= TLAN_NET_MASK_MASK7; } TLan_DioWrite8(BASE, TLAN_NET_MASK, data); TLan_DioWrite16(BASE, TLAN_MAX_RX, ((1536) + 7) & ~7); TLan_MiiReadReg(nic, phy, MII_GEN_ID_HI, &tlphy_id1); TLan_MiiReadReg(nic, phy, MII_GEN_ID_LO, &tlphy_id2); if ((tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY) || (priv->aui)) { status = MII_GS_LINK; printf("TLAN: %s: Link forced.\n", priv->nic_name); } else { TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status); udelay(1000); TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -