⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 forcedeth.c

📁 linux下从网卡远程启动
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************    forcedeth.c -- Etherboot device driver for the NVIDIA nForce *			media access controllers.** Note: This driver is based on the Linux driver that was based on*      a cleanroom reimplementation which was based on reverse*      engineered documentation written by Carl-Daniel Hailfinger*      and Andrew de Quincey. It's neither supported nor endorsed*      by NVIDIA Corp. Use at your own risk.**    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:*		forcedeth: Ethernet driver for NVIDIA nForce media access controllers:**	(C) 2003 Manfred Spraul*		See Linux Driver for full information*	*	Linux Driver Version 0.22, 19 Jan 2004* * *    REVISION HISTORY:*    ================*    v1.0	01-31-2004	timlegge	Initial port of Linux driver*    v1.1	02-03-2004	timlegge	Large Clean up, first release *    *    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 support functions */#include "timer.h"#define drv_version "v1.1"#define drv_date "02-03-2004"//#define TFTM_DEBUG#ifdef TFTM_DEBUG#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;/* 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))unsigned long BASE;/* NIC specific static variables go here *//* * Hardware access: */#define DEV_NEED_LASTPACKET1	0x0001#define DEV_IRQMASK_1		0x0002#define DEV_IRQMASK_2		0x0004#define DEV_NEED_TIMERIRQ	0x0008enum {	NvRegIrqStatus = 0x000,#define NVREG_IRQSTAT_MIIEVENT	0040#define NVREG_IRQSTAT_MASK		0x1ff	NvRegIrqMask = 0x004,#define NVREG_IRQ_RX			0x0002#define NVREG_IRQ_RX_NOBUF		0x0004#define NVREG_IRQ_TX_ERR		0x0008#define NVREG_IRQ_TX2			0x0010#define NVREG_IRQ_TIMER			0x0020#define NVREG_IRQ_LINK			0x0040#define NVREG_IRQ_TX1			0x0100#define NVREG_IRQMASK_WANTED_1		0x005f#define NVREG_IRQMASK_WANTED_2		0x0147#define NVREG_IRQ_UNKNOWN		(~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))	NvRegUnknownSetupReg6 = 0x008,#define NVREG_UNKSETUP6_VAL		3/* * NVREG_POLL_DEFAULT is the interval length of the timer source on the nic * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms */	NvRegPollingInterval = 0x00c,#define NVREG_POLL_DEFAULT	970	NvRegMisc1 = 0x080,#define NVREG_MISC1_HD		0x02#define NVREG_MISC1_FORCE	0x3b0f3c	NvRegTransmitterControl = 0x084,#define NVREG_XMITCTL_START	0x01	NvRegTransmitterStatus = 0x088,#define NVREG_XMITSTAT_BUSY	0x01	NvRegPacketFilterFlags = 0x8c,#define NVREG_PFF_ALWAYS	0x7F0008#define NVREG_PFF_PROMISC	0x80#define NVREG_PFF_MYADDR	0x20	NvRegOffloadConfig = 0x90,#define NVREG_OFFLOAD_HOMEPHY	0x601#define NVREG_OFFLOAD_NORMAL	0x5ee	NvRegReceiverControl = 0x094,#define NVREG_RCVCTL_START	0x01	NvRegReceiverStatus = 0x98,#define NVREG_RCVSTAT_BUSY	0x01	NvRegRandomSeed = 0x9c,#define NVREG_RNDSEED_MASK	0x00ff#define NVREG_RNDSEED_FORCE	0x7f00	NvRegUnknownSetupReg1 = 0xA0,#define NVREG_UNKSETUP1_VAL	0x16070f	NvRegUnknownSetupReg2 = 0xA4,#define NVREG_UNKSETUP2_VAL	0x16	NvRegMacAddrA = 0xA8,	NvRegMacAddrB = 0xAC,	NvRegMulticastAddrA = 0xB0,#define NVREG_MCASTADDRA_FORCE	0x01	NvRegMulticastAddrB = 0xB4,	NvRegMulticastMaskA = 0xB8,	NvRegMulticastMaskB = 0xBC,	NvRegTxRingPhysAddr = 0x100,	NvRegRxRingPhysAddr = 0x104,	NvRegRingSizes = 0x108,#define NVREG_RINGSZ_TXSHIFT 0#define NVREG_RINGSZ_RXSHIFT 16	NvRegUnknownTransmitterReg = 0x10c,	NvRegLinkSpeed = 0x110,#define NVREG_LINKSPEED_FORCE 0x10000#define NVREG_LINKSPEED_10	10#define NVREG_LINKSPEED_100	100#define NVREG_LINKSPEED_1000	1000	NvRegUnknownSetupReg5 = 0x130,#define NVREG_UNKSETUP5_BIT31	(1<<31)	NvRegUnknownSetupReg3 = 0x134,#define NVREG_UNKSETUP3_VAL1	0x200010	NvRegTxRxControl = 0x144,#define NVREG_TXRXCTL_KICK	0x0001#define NVREG_TXRXCTL_BIT1	0x0002#define NVREG_TXRXCTL_BIT2	0x0004#define NVREG_TXRXCTL_IDLE	0x0008#define NVREG_TXRXCTL_RESET	0x0010	NvRegMIIStatus = 0x180,#define NVREG_MIISTAT_ERROR		0x0001#define NVREG_MIISTAT_LINKCHANGE	0x0008#define NVREG_MIISTAT_MASK		0x000f#define NVREG_MIISTAT_MASK2		0x000f	NvRegUnknownSetupReg4 = 0x184,#define NVREG_UNKSETUP4_VAL	8	NvRegAdapterControl = 0x188,#define NVREG_ADAPTCTL_START	0x02#define NVREG_ADAPTCTL_LINKUP	0x04#define NVREG_ADAPTCTL_PHYVALID	0x4000#define NVREG_ADAPTCTL_RUNNING	0x100000#define NVREG_ADAPTCTL_PHYSHIFT	24	NvRegMIISpeed = 0x18c,#define NVREG_MIISPEED_BIT8	(1<<8)#define NVREG_MIIDELAY	5	NvRegMIIControl = 0x190,#define NVREG_MIICTL_INUSE	0x10000#define NVREG_MIICTL_WRITE	0x08000#define NVREG_MIICTL_ADDRSHIFT	5	NvRegMIIData = 0x194,	NvRegWakeUpFlags = 0x200,#define NVREG_WAKEUPFLAGS_VAL		0x7770#define NVREG_WAKEUPFLAGS_BUSYSHIFT	24#define NVREG_WAKEUPFLAGS_ENABLESHIFT	16#define NVREG_WAKEUPFLAGS_D3SHIFT	12#define NVREG_WAKEUPFLAGS_D2SHIFT	8#define NVREG_WAKEUPFLAGS_D1SHIFT	4#define NVREG_WAKEUPFLAGS_D0SHIFT	0#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT		0x01#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT	0x02#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE	0x04	NvRegPatternCRC = 0x204,	NvRegPatternMask = 0x208,	NvRegPowerCap = 0x268,#define NVREG_POWERCAP_D3SUPP	(1<<30)#define NVREG_POWERCAP_D2SUPP	(1<<26)#define NVREG_POWERCAP_D1SUPP	(1<<25)	NvRegPowerState = 0x26c,#define NVREG_POWERSTATE_POWEREDUP	0x8000#define NVREG_POWERSTATE_VALID		0x0100#define NVREG_POWERSTATE_MASK		0x0003#define NVREG_POWERSTATE_D0		0x0000#define NVREG_POWERSTATE_D1		0x0001#define NVREG_POWERSTATE_D2		0x0002#define NVREG_POWERSTATE_D3		0x0003};#define NV_TX_LASTPACKET	(1<<0)#define NV_TX_RETRYERROR	(1<<3)#define NV_TX_LASTPACKET1	(1<<8)#define NV_TX_DEFERRED		(1<<10)#define NV_TX_CARRIERLOST	(1<<11)#define NV_TX_LATECOLLISION	(1<<12)#define NV_TX_UNDERFLOW		(1<<13)#define NV_TX_ERROR		(1<<14)#define NV_TX_VALID		(1<<15)#define NV_RX_DESCRIPTORVALID	(1<<0)#define NV_RX_MISSEDFRAME	(1<<1)#define NV_RX_SUBSTRACT1	(1<<3)#define NV_RX_ERROR1		(1<<7)#define NV_RX_ERROR2		(1<<8)#define NV_RX_ERROR3		(1<<9)#define NV_RX_ERROR4		(1<<10)#define NV_RX_CRCERR		(1<<11)#define NV_RX_OVERFLOW		(1<<12)#define NV_RX_FRAMINGERR	(1<<13)#define NV_RX_ERROR		(1<<14)#define NV_RX_AVAIL		(1<<15)/* Miscelaneous hardware related defines: */#define NV_PCI_REGSZ		0x270/* various timeout delays: all in usec */#define NV_TXRX_RESET_DELAY	4#define NV_TXSTOP_DELAY1	10#define NV_TXSTOP_DELAY1MAX	500000#define NV_TXSTOP_DELAY2	100#define NV_RXSTOP_DELAY1	10#define NV_RXSTOP_DELAY1MAX	500000#define NV_RXSTOP_DELAY2	100#define NV_SETUP5_DELAY		5#define NV_SETUP5_DELAYMAX	50000#define NV_POWERUP_DELAY	5#define NV_POWERUP_DELAYMAX	5000#define NV_MIIBUSY_DELAY	50#define NV_MIIPHY_DELAY	10#define NV_MIIPHY_DELAYMAX	10000#define NV_WAKEUPPATTERNS	5#define NV_WAKEUPMASKENTRIES	4/* General driver defaults */#define NV_WATCHDOG_TIMEO	(2*HZ)#define DEFAULT_MTU		1500	/* also maximum supported, at least for now */#define RX_RING		4#define TX_RING		2/* limited to 1 packet until we understand NV_TX_LASTPACKET */#define TX_LIMIT_STOP	10#define TX_LIMIT_START	5/* rx/tx mac addr + type + vlan + align + slack*/#define RX_NIC_BUFSIZE		(DEFAULT_MTU + 64)/* even more slack */#define RX_ALLOC_BUFSIZE	(DEFAULT_MTU + 128)#define OOM_REFILL	(1+HZ/20)#define POLL_WAIT	(1+HZ/100)struct ring_desc {	u32 PacketBuffer;	u16 Length;	u16 Flags;};/* Define the TX Descriptor */static struct ring_desc tx_ring[TX_RING];/* Create a static buffer of size RX_BUF_SZ for eachTX Descriptor.  All descriptors point to apart of this buffer */static unsigned char txb[TX_RING * RX_NIC_BUFSIZE];/* Define the TX Descriptor */static struct ring_desc rx_ring[RX_RING];/* Create a static buffer of size RX_BUF_SZ for eachRX Descriptor   All descriptors point to apart of this buffer */static unsigned char rxb[RX_RING * RX_NIC_BUFSIZE];/* Private Storage for the NIC */struct forcedeth_private {	/* General data:	 * Locking: spin_lock(&np->lock); */	int in_shutdown;	u32 linkspeed;	int duplex;	int phyaddr;	/* General data: RO fields */	u8 *ring_addr;	u32 orig_mac[2];	u32 irqmask;	/* rx specific fields.	 * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);	 */	struct ring_desc *rx_ring;	unsigned int cur_rx, refill_rx;	struct sk_buff *rx_skbuff[RX_RING];	u32 rx_dma[RX_RING];	unsigned int rx_buf_sz;	/*	 * tx specific fields.	 */	struct ring_desc *tx_ring;	unsigned int next_tx, nic_tx;	struct sk_buff *tx_skbuff[TX_RING];	u32 tx_dma[TX_RING];	u16 tx_flags;} npx;static struct forcedeth_private *np;static inline void pci_push(u8 * base){	/* force out pending posted writes */	readl(base);}static int reg_delay(int offset, u32 mask,		     u32 target, int delay, int delaymax, const char *msg){	u8 *base = (u8 *) BASE;	pci_push(base);	do {		udelay(delay);		delaymax -= delay;		if (delaymax < 0) {			if (msg)				printf(msg);			return 1;		}	} while ((readl(base + offset) & mask) != target);	return 0;}#define MII_READ	(-1)#define MII_PHYSID1         0x02	/* PHYS ID 1                   */#define MII_PHYSID2         0x03	/* PHYS ID 2                   */#define MII_BMCR            0x00	/* Basic mode control register */#define MII_BMSR            0x01	/* Basic mode status register  */#define MII_ADVERTISE       0x04	/* Advertisement control reg   */#define MII_LPA             0x05	/* Link partner ability reg    */#define BMSR_ANEGCOMPLETE       0x0020	/* Auto-negotiation complete   *//* Link partner ability register. */#define LPA_SLCT                0x001f	/* Same as advertise selector  */#define LPA_10HALF              0x0020	/* Can do 10mbps half-duplex   */#define LPA_10FULL              0x0040	/* Can do 10mbps full-duplex   */#define LPA_100HALF             0x0080	/* Can do 100mbps half-duplex  */#define LPA_100FULL             0x0100	/* Can do 100mbps full-duplex  */#define LPA_100BASE4            0x0200	/* Can do 100mbps 4k packets   */#define LPA_RESV                0x1c00	/* Unused...                   */#define LPA_RFAULT              0x2000	/* Link partner faulted        */#define LPA_LPACK               0x4000	/* Link partner acked us       */#define LPA_NPAGE               0x8000	/* Next page bit               *//* mii_rw: read/write a register on the PHY. * * Caller must guarantee serialization */static int mii_rw(struct nic *nic __unused, int addr, int miireg,		  int value){	u8 *base = (u8 *) BASE;	int was_running;	u32 reg;	int retval;	writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);	was_running = 0;	reg = readl(base + NvRegAdapterControl);	if (reg & NVREG_ADAPTCTL_RUNNING) {		was_running = 1;		writel(reg & ~NVREG_ADAPTCTL_RUNNING,		       base + NvRegAdapterControl);	}	reg = readl(base + NvRegMIIControl);	if (reg & NVREG_MIICTL_INUSE) {		writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl);		udelay(NV_MIIBUSY_DELAY);	}	reg =	    NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;	if (value != MII_READ) {		writel(value, base + NvRegMIIData);		reg |= NVREG_MIICTL_WRITE;	}	writel(reg, base + NvRegMIIControl);	if (reg_delay(NvRegMIIControl, NVREG_MIICTL_INUSE, 0,		      NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)) {		dprintf(("mii_rw of reg %d at PHY %d timed out.\n",			 miireg, addr));		retval = -1;	} else if (value != MII_READ) {		/* it was a write operation - fewer failures are detectable */		dprintf(("mii_rw wrote 0x%x to reg %d at PHY %d\n",			 value, miireg, addr));		retval = 0;	} else if (readl(base + NvRegMIIStatus) & NVREG_MIISTAT_ERROR) {		dprintf(("mii_rw of reg %d at PHY %d failed.\n",			 miireg, addr));		retval = -1;	} else {		/* FIXME: why is that required? */		udelay(50);		retval = readl(base + NvRegMIIData);		dprintf(("mii_rw read from reg %d at PHY %d: 0x%x.\n",			 miireg, addr, retval));	}	if (was_running) {		reg = readl(base + NvRegAdapterControl);		writel(reg | NVREG_ADAPTCTL_RUNNING,		       base + NvRegAdapterControl);	}	return retval;}static void start_rx(struct nic *nic __unused){	u8 *base = (u8 *) BASE;	dprintf(("start_rx\n"));	/* Already running? Stop it. */	if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {		writel(0, base + NvRegReceiverControl);		pci_push(base);	}	writel(np->linkspeed, base + NvRegLinkSpeed);	pci_push(base);	writel(NVREG_RCVCTL_START, base + NvRegReceiverControl);	pci_push(base);}static void stop_rx(void){	u8 *base = (u8 *) BASE;	dprintf(("stop_rx\n"));	writel(0, base + NvRegReceiverControl);	reg_delay(NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,		  NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,		  "stop_rx: ReceiverStatus remained busy");	udelay(NV_RXSTOP_DELAY2);	writel(0, base + NvRegLinkSpeed);}static void start_tx(struct nic *nic __unused){	u8 *base = (u8 *) BASE;	dprintf(("start_tx\n"));	writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl);	pci_push(base);}static void stop_tx(void){	u8 *base = (u8 *) BASE;	dprintf(("stop_tx\n"));	writel(0, base + NvRegTransmitterControl);	reg_delay(NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,		  NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,		  "stop_tx: TransmitterStatus remained busy");	udelay(NV_TXSTOP_DELAY2);	writel(0, base + NvRegUnknownTransmitterReg);}static void txrx_reset(struct nic *nic __unused){	u8 *base = (u8 *) BASE;	dprintf(("txrx_reset\n"));	writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET,	       base + NvRegTxRxControl);	pci_push(base);	udelay(NV_TXRX_RESET_DELAY);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -