📄 ns83820.c
字号:
/*************************************************************************** ns83820.c: Etherboot device driver for the National Semiconductor 83820* Written 2004 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:* ns83820.c by Benjamin LaHaise with contributions* for Linux kernel 2.4.x.* * Linux Driver Version 0.20, 20020610* * * * REVISION HISTORY:* ================** v1.0 02-16-2004 timlegge Initial port of Linux driver* v1.1 02-19-2004 timlegge More rohbust transmit and poll* * 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"#if ARCH == ia64 /* Support 64-bit addressing */#define USE_64BIT_ADDR#endif//#define DDEBUG#ifdef DDEBUG#define dprintf(x) printf x#else#define dprintf(x)#endiftypedef unsigned char u8;typedef signed char s8;typedef unsigned short u16;typedef signed short s16;typedef unsigned int u32;typedef signed int s32;#define HZ 100/* 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))/* NIC specific static variables go here *//* Global parameters. See MODULE_PARM near the bottom. */static int ihr = 2;static int reset_phy = 0;static int lnksts = 0; /* CFG_LNKSTS bit polarity */#if defined(CONFIG_HIGHMEM64G) || defined(__ia64__)#define USE_64BIT_ADDR "+"#endif#if defined(USE_64BIT_ADDR)#define TRY_DAC 1#else#define TRY_DAC 0#endif/* tunables */#define RX_BUF_SIZE 1500 /* 8192 *//* Must not exceed ~65000. */#define NR_RX_DESC 64#define NR_TX_DESC 1 /* not tunable *//* Extra 6 bytes for 64 bit alignment (divisable by 8) */#define REAL_RX_BUF_SIZE (RX_BUF_SIZE + 14 + 6) /* rx/tx mac addr + type */#define MIN_TX_DESC_FREE 8/* register defines */#define CFGCS 0x04#define CR_TXE 0x00000001#define CR_TXD 0x00000002/* Ramit : Here's a tip, don't do a RXD immediately followed by an RXE * The Receive engine skips one descriptor and moves * onto the next one!! */#define CR_RXE 0x00000004#define CR_RXD 0x00000008#define CR_TXR 0x00000010#define CR_RXR 0x00000020#define CR_SWI 0x00000080#define CR_RST 0x00000100#define PTSCR_EEBIST_FAIL 0x00000001#define PTSCR_EEBIST_EN 0x00000002#define PTSCR_EELOAD_EN 0x00000004#define PTSCR_RBIST_FAIL 0x000001b8#define PTSCR_RBIST_DONE 0x00000200#define PTSCR_RBIST_EN 0x00000400#define PTSCR_RBIST_RST 0x00002000#define MEAR_EEDI 0x00000001#define MEAR_EEDO 0x00000002#define MEAR_EECLK 0x00000004#define MEAR_EESEL 0x00000008#define MEAR_MDIO 0x00000010#define MEAR_MDDIR 0x00000020#define MEAR_MDC 0x00000040#define ISR_TXDESC3 0x40000000#define ISR_TXDESC2 0x20000000#define ISR_TXDESC1 0x10000000#define ISR_TXDESC0 0x08000000#define ISR_RXDESC3 0x04000000#define ISR_RXDESC2 0x02000000#define ISR_RXDESC1 0x01000000#define ISR_RXDESC0 0x00800000#define ISR_TXRCMP 0x00400000#define ISR_RXRCMP 0x00200000#define ISR_DPERR 0x00100000#define ISR_SSERR 0x00080000#define ISR_RMABT 0x00040000#define ISR_RTABT 0x00020000#define ISR_RXSOVR 0x00010000#define ISR_HIBINT 0x00008000#define ISR_PHY 0x00004000#define ISR_PME 0x00002000#define ISR_SWI 0x00001000#define ISR_MIB 0x00000800#define ISR_TXURN 0x00000400#define ISR_TXIDLE 0x00000200#define ISR_TXERR 0x00000100#define ISR_TXDESC 0x00000080#define ISR_TXOK 0x00000040#define ISR_RXORN 0x00000020#define ISR_RXIDLE 0x00000010#define ISR_RXEARLY 0x00000008#define ISR_RXERR 0x00000004#define ISR_RXDESC 0x00000002#define ISR_RXOK 0x00000001#define TXCFG_CSI 0x80000000#define TXCFG_HBI 0x40000000#define TXCFG_MLB 0x20000000#define TXCFG_ATP 0x10000000#define TXCFG_ECRETRY 0x00800000#define TXCFG_BRST_DIS 0x00080000#define TXCFG_MXDMA1024 0x00000000#define TXCFG_MXDMA512 0x00700000#define TXCFG_MXDMA256 0x00600000#define TXCFG_MXDMA128 0x00500000#define TXCFG_MXDMA64 0x00400000#define TXCFG_MXDMA32 0x00300000#define TXCFG_MXDMA16 0x00200000#define TXCFG_MXDMA8 0x00100000#define CFG_LNKSTS 0x80000000#define CFG_SPDSTS 0x60000000#define CFG_SPDSTS1 0x40000000#define CFG_SPDSTS0 0x20000000#define CFG_DUPSTS 0x10000000#define CFG_TBI_EN 0x01000000#define CFG_MODE_1000 0x00400000/* Ramit : Dont' ever use AUTO_1000, it never works and is buggy. * Read the Phy response and then configure the MAC accordingly */#define CFG_AUTO_1000 0x00200000#define CFG_PINT_CTL 0x001c0000#define CFG_PINT_DUPSTS 0x00100000#define CFG_PINT_LNKSTS 0x00080000#define CFG_PINT_SPDSTS 0x00040000#define CFG_TMRTEST 0x00020000#define CFG_MRM_DIS 0x00010000#define CFG_MWI_DIS 0x00008000#define CFG_T64ADDR 0x00004000#define CFG_PCI64_DET 0x00002000#define CFG_DATA64_EN 0x00001000#define CFG_M64ADDR 0x00000800#define CFG_PHY_RST 0x00000400#define CFG_PHY_DIS 0x00000200#define CFG_EXTSTS_EN 0x00000100#define CFG_REQALG 0x00000080#define CFG_SB 0x00000040#define CFG_POW 0x00000020#define CFG_EXD 0x00000010#define CFG_PESEL 0x00000008#define CFG_BROM_DIS 0x00000004#define CFG_EXT_125 0x00000002#define CFG_BEM 0x00000001#define EXTSTS_UDPPKT 0x00200000#define EXTSTS_TCPPKT 0x00080000#define EXTSTS_IPPKT 0x00020000#define SPDSTS_POLARITY (CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0))#define MIBC_MIBS 0x00000008#define MIBC_ACLR 0x00000004#define MIBC_FRZ 0x00000002#define MIBC_WRN 0x00000001#define PCR_PSEN (1 << 31)#define PCR_PS_MCAST (1 << 30)#define PCR_PS_DA (1 << 29)#define PCR_STHI_8 (3 << 23)#define PCR_STLO_4 (1 << 23)#define PCR_FFHI_8K (3 << 21)#define PCR_FFLO_4K (1 << 21)#define PCR_PAUSE_CNT 0xFFFE#define RXCFG_AEP 0x80000000#define RXCFG_ARP 0x40000000#define RXCFG_STRIPCRC 0x20000000#define RXCFG_RX_FD 0x10000000#define RXCFG_ALP 0x08000000#define RXCFG_AIRL 0x04000000#define RXCFG_MXDMA512 0x00700000#define RXCFG_DRTH 0x0000003e#define RXCFG_DRTH0 0x00000002#define RFCR_RFEN 0x80000000#define RFCR_AAB 0x40000000#define RFCR_AAM 0x20000000#define RFCR_AAU 0x10000000#define RFCR_APM 0x08000000#define RFCR_APAT 0x07800000#define RFCR_APAT3 0x04000000#define RFCR_APAT2 0x02000000#define RFCR_APAT1 0x01000000#define RFCR_APAT0 0x00800000#define RFCR_AARP 0x00400000#define RFCR_MHEN 0x00200000#define RFCR_UHEN 0x00100000#define RFCR_ULM 0x00080000#define VRCR_RUDPE 0x00000080#define VRCR_RTCPE 0x00000040#define VRCR_RIPE 0x00000020#define VRCR_IPEN 0x00000010#define VRCR_DUTF 0x00000008#define VRCR_DVTF 0x00000004#define VRCR_VTREN 0x00000002#define VRCR_VTDEN 0x00000001#define VTCR_PPCHK 0x00000008#define VTCR_GCHK 0x00000004#define VTCR_VPPTI 0x00000002#define VTCR_VGTI 0x00000001#define CR 0x00#define CFG 0x04#define MEAR 0x08#define PTSCR 0x0c#define ISR 0x10#define IMR 0x14#define IER 0x18#define IHR 0x1c#define TXDP 0x20#define TXDP_HI 0x24#define TXCFG 0x28#define GPIOR 0x2c#define RXDP 0x30#define RXDP_HI 0x34#define RXCFG 0x38#define PQCR 0x3c#define WCSR 0x40#define PCR 0x44#define RFCR 0x48#define RFDR 0x4c#define SRR 0x58#define VRCR 0xbc#define VTCR 0xc0#define VDR 0xc4#define CCSR 0xcc#define TBICR 0xe0#define TBISR 0xe4#define TANAR 0xe8#define TANLPAR 0xec#define TANER 0xf0#define TESR 0xf4#define TBICR_MR_AN_ENABLE 0x00001000#define TBICR_MR_RESTART_AN 0x00000200#define TBISR_MR_LINK_STATUS 0x00000020#define TBISR_MR_AN_COMPLETE 0x00000004#define TANAR_PS2 0x00000100#define TANAR_PS1 0x00000080#define TANAR_HALF_DUP 0x00000040#define TANAR_FULL_DUP 0x00000020#define GPIOR_GP5_OE 0x00000200#define GPIOR_GP4_OE 0x00000100#define GPIOR_GP3_OE 0x00000080#define GPIOR_GP2_OE 0x00000040#define GPIOR_GP1_OE 0x00000020#define GPIOR_GP3_OUT 0x00000004#define GPIOR_GP1_OUT 0x00000001#define LINK_AUTONEGOTIATE 0x01#define LINK_DOWN 0x02#define LINK_UP 0x04#define __kick_rx() writel(CR_RXE, ns->base + CR)#define kick_rx() do { \ dprintf(("kick_rx: maybe kicking\n")); \ writel(virt_to_le32desc(&rx_ring[ns->cur_rx]), ns->base + RXDP); \ if (ns->next_rx == ns->next_empty) \ dprintf(("uh-oh: next_rx == next_empty???\n"));\ __kick_rx(); \} while(0)#ifdef USE_64BIT_ADDR#define HW_ADDR_LEN 8#else#define HW_ADDR_LEN 4#endif#define CMDSTS_OWN 0x80000000#define CMDSTS_MORE 0x40000000#define CMDSTS_INTR 0x20000000#define CMDSTS_ERR 0x10000000#define CMDSTS_OK 0x08000000#define CMDSTS_LEN_MASK 0x0000ffff#define CMDSTS_DEST_MASK 0x01800000#define CMDSTS_DEST_SELF 0x00800000#define CMDSTS_DEST_MULTI 0x01000000#define DESC_SIZE 8 /* Should be cache line sized */#ifdef USE_64BIT_ADDRstruct ring_desc { uint64_t link; uint64_t bufptr; u32 cmdsts; u32 extsts; /* Extended status field */};#elsestruct ring_desc { u32 link; u32 bufptr; u32 cmdsts; u32 extsts; /* Extended status field */};#endif/* Define the TX Descriptor */static struct ring_desc tx_ring[NR_TX_DESC] __attribute__ ((aligned(8)));/* Create a static buffer of size REAL_RX_BUF_SIZE for eachTX Descriptor. All descriptors point to apart of this buffer */static unsigned char txb[NR_TX_DESC * REAL_RX_BUF_SIZE];/* Define the TX Descriptor */static struct ring_desc rx_ring[NR_RX_DESC] __attribute__ ((aligned(8)));/* Create a static buffer of size REAL_RX_BUF_SIZE for eachRX Descriptor All descriptors point to apart of this buffer */static unsigned char rxb[NR_RX_DESC * REAL_RX_BUF_SIZE] __attribute__ ((aligned(8)));/* Private Storage for the NIC */struct ns83820_private { u8 *base; int up; long idle; u32 *next_rx_desc; u16 next_rx, next_empty; u32 cur_rx; u32 *descs; unsigned ihr; u32 CFG_cache; u32 MEAR_cache; u32 IMR_cache; int linkstate; u16 tx_done_idx; u16 tx_idx; u16 tx_intr_idx; u32 phy_descs; u32 *tx_descs;} nsx;static struct ns83820_private *ns;static void phy_intr(struct nic *nic __unused){ static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; u32 cfg, new_cfg; u32 tbisr, tanar, tanlpar; int speed, fullduplex, newlinkstate; cfg = readl(ns->base + CFG) ^ SPDSTS_POLARITY; if (ns->CFG_cache & CFG_TBI_EN) { /* we have an optical transceiver */ tbisr = readl(ns->base + TBISR); tanar = readl(ns->base + TANAR); tanlpar = readl(ns->base + TANLPAR); dprintf(("phy_intr: tbisr=%hX, tanar=%hX, tanlpar=%hX\n", tbisr, tanar, tanlpar)); if ((fullduplex = (tanlpar & TANAR_FULL_DUP) && (tanar & TANAR_FULL_DUP))) { /* both of us are full duplex */ writel(readl(ns->base + TXCFG) | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP, ns->base + TXCFG); writel(readl(ns->base + RXCFG) | RXCFG_RX_FD, ns->base + RXCFG); /* Light up full duplex LED */ writel(readl(ns->base + GPIOR) | GPIOR_GP1_OUT, ns->base + GPIOR); } else if (((tanlpar & TANAR_HALF_DUP) && (tanar & TANAR_HALF_DUP)) || ((tanlpar & TANAR_FULL_DUP) && (tanar & TANAR_HALF_DUP)) || ((tanlpar & TANAR_HALF_DUP) && (tanar & TANAR_FULL_DUP))) { /* one or both of us are half duplex */ writel((readl(ns->base + TXCFG) & ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP, ns->base + TXCFG); writel(readl(ns->base + RXCFG) & ~RXCFG_RX_FD, ns->base + RXCFG); /* Turn off full duplex LED */ writel(readl(ns->base + GPIOR) & ~GPIOR_GP1_OUT, ns->base + GPIOR); } speed = 4; /* 1000F */ } else { /* we have a copper transceiver */ new_cfg = ns->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS); if (cfg & CFG_SPDSTS1) new_cfg |= CFG_MODE_1000; else new_cfg &= ~CFG_MODE_1000; speed = ((cfg / CFG_SPDSTS0) & 3); fullduplex = (cfg & CFG_DUPSTS); if (fullduplex) new_cfg |= CFG_SB; if ((cfg & CFG_LNKSTS) && ((new_cfg ^ ns->CFG_cache) & CFG_MODE_1000)) { writel(new_cfg, ns->base + CFG); ns->CFG_cache = new_cfg; } ns->CFG_cache &= ~CFG_SPDSTS; ns->CFG_cache |= cfg & CFG_SPDSTS; } newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN; if (newlinkstate & LINK_UP && ns->linkstate != newlinkstate) { printf("link now %s mbps, %s duplex and up.\n", speeds[speed], fullduplex ? "full" : "half"); } else if (newlinkstate & LINK_DOWN && ns->linkstate != newlinkstate) { printf("link now down.\n"); } ns->linkstate = newlinkstate;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -