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

📄 lp486e.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Intel Professional Workstation/panther ethernet driver *//* lp486e.c: A panther 82596 ethernet driver for linux. *//*    History and copyrights:    Driver skeleton        Written 1993 by Donald Becker.        Copyright 1993 United States Government as represented by the Director,        National Security Agency.  This software may only be used and	distributed according to the terms of the GNU General Public License	as modified by SRC, incorporated herein by reference.        The author may be reached as becker@scyld.com, or C/O	Scyld Computing Corporation	410 Severn Ave., Suite 210	Annapolis MD 21403    Apricot        Written 1994 by Mark Evans.        This driver is for the Apricot 82596 bus-master interface        Modularised 12/94 Mark Evans    Professional Workstation	Derived from apricot.c by Ard van Breemen	<ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>	Credits:	Thanks to Murphy Software BV for letting me write this in their time.	Well, actually, I get payed doing this...	(Also: see http://www.murphy.nl for murphy, and my homepage ~ard for	more information on the Professional Workstation)    Present version	aeb@cwi.nl*//*    There are currently two motherboards that I know of in the    professional workstation. The only one that I know is the    intel panther motherboard. -- ard*//*The pws is equipped with an intel 82596. This is a very intelligent controllerwhich runs its own micro-code. Communication with the hostprocessor is donethrough linked lists of commands and buffers in the hostprocessors memory.A complete description of the 82596 is available from intel. Search fora file called "29021806.pdf". It is a complete description of the chip itself.To use it for the pws some additions are needed regarding generation ofthe PORT and CA signal, and the interrupt glue needed for a pc.I/O map:PORT  SIZE ACTION MEANING0xCB0    2 WRITE  Lower 16 bits for PORT command0xCB2    2 WRITE  Upper 16 bits for PORT command, and issue of PORT command0xCB4    1 WRITE  Generation of CA signal0xCB8    1 WRITE  Clear interrupt glueAll other communication is through memory!*/#define SLOW_DOWN_IO udelay(5);#include <linux/module.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>/* debug print flags */#define LOG_SRCDST    0x80000000#define LOG_STATINT   0x40000000#define LOG_STARTINT  0x20000000#define i596_debug debugstatic int i596_debug = 0;static const char * const medianame[] = {	"10baseT", "AUI",	"10baseT-FD", "AUI-FD",};#define LP486E_TOTAL_SIZE 16#define I596_NULL (0xffffffff)#define CMD_EOL		0x8000	/* The last command of the list, stop. */#define CMD_SUSP	0x4000	/* Suspend after doing cmd. */#define CMD_INTR	0x2000	/* Interrupt after doing cmd. */#define CMD_FLEX	0x0008	/* Enable flexible memory model */enum commands {	CmdNOP = 0,	CmdIASetup = 1,	CmdConfigure = 2,	CmdMulticastList = 3,	CmdTx = 4,	CmdTDR = 5,	CmdDump = 6,	CmdDiagnose = 7};char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",			"Tx", "TDR", "Dump", "Diagnose" };/* Status word bits */#define	STAT_CX		0x8000	/* The CU finished executing a command				   with the Interrupt bit set */#define	STAT_FR		0x4000	/* The RU finished receiving a frame */#define	STAT_CNA	0x2000	/* The CU left the active state */#define	STAT_RNR	0x1000	/* The RU left the active state */#define STAT_ACK	(STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)#define	STAT_CUS	0x0700	/* Status of CU: 0: idle, 1: suspended,				   2: active, 3-7: unused */#define STAT_RUS	0x00f0	/* Status of RU: 0: idle, 1: suspended,				   2: no resources, 4: ready,				   10: no resources due to no more RBDs,				   12: no more RBDs, other: unused */#define	STAT_T		0x0008	/* Bus throttle timers loaded */#define	STAT_ZERO	0x0807	/* Always zero */#if 0static char *CUstates[8] = {	"idle", "suspended", "active", 0, 0, 0, 0, 0};static char *RUstates[16] = {	"idle", "suspended", "no resources", 0, "ready", 0, 0, 0,	0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0};static voidi596_out_status(int status) {	int bad = 0;	char *s;	printk("status %4.4x:", status);	if (status == 0xffff)		printk(" strange..\n");	else {		if (status & STAT_CX)			printk("  CU done");		if (status & STAT_CNA)			printk("  CU stopped");		if (status & STAT_FR)			printk("  got a frame");		if (status & STAT_RNR)			printk("  RU stopped");		if (status & STAT_T)			printk("  throttled");		if (status & STAT_ZERO)			bad = 1;		s = CUstates[(status & STAT_CUS) >> 8];		if (!s)			bad = 1;		else			printk("  CU(%s)", s);		s = RUstates[(status & STAT_RUS) >> 4];		if (!s)			bad = 1;		else			printk("  RU(%s)", s);		if (bad)			printk("  bad status");		printk("\n");	}}#endif/* Command word bits */#define ACK_CX		0x8000#define ACK_FR		0x4000#define ACK_CNA		0x2000#define ACK_RNR		0x1000#define CUC_START	0x0100#define CUC_RESUME	0x0200#define CUC_SUSPEND	0x0300#define CUC_ABORT	0x0400#define RX_START	0x0010#define RX_RESUME	0x0020#define RX_SUSPEND	0x0030#define RX_ABORT	0x0040typedef u32 phys_addr;static inline phys_addrva_to_pa(volatile void *x) {	return x ? virt_to_bus(x) : I596_NULL;}static inline void *pa_to_va(phys_addr x) {	return (x == I596_NULL) ? NULL : bus_to_virt(x);}/* status bits for cmd */#define CMD_STAT_C	0x8000	/* CU command complete */#define CMD_STAT_B	0x4000	/* CU command in progress */#define CMD_STAT_OK	0x2000	/* CU command completed without errors */#define CMD_STAT_A	0x1000	/* CU command abnormally terminated */struct i596_cmd {		/* 8 bytes */	unsigned short status;	unsigned short command;	phys_addr pa_next;	/* va_to_pa(struct i596_cmd *next) */};#define EOF		0x8000#define SIZE_MASK	0x3fffstruct i596_tbd {	unsigned short size;	unsigned short pad;	phys_addr pa_next;	/* va_to_pa(struct i596_tbd *next) */	phys_addr pa_data;	/* va_to_pa(char *data) */	struct sk_buff *skb;};struct tx_cmd {	struct i596_cmd cmd;	phys_addr pa_tbd;	/* va_to_pa(struct i596_tbd *tbd) */	unsigned short size;	unsigned short pad;};/* status bits for rfd */#define RFD_STAT_C	0x8000	/* Frame reception complete */#define RFD_STAT_B	0x4000	/* Frame reception in progress */#define RFD_STAT_OK	0x2000	/* Frame received without errors */#define RFD_STATUS	0x1fff#define RFD_LENGTH_ERR	0x1000#define RFD_CRC_ERR	0x0800#define RFD_ALIGN_ERR	0x0400#define RFD_NOBUFS_ERR	0x0200#define RFD_DMA_ERR	0x0100	/* DMA overrun failure to acquire system bus */#define RFD_SHORT_FRAME_ERR	0x0080#define RFD_NOEOP_ERR	0x0040#define RFD_TRUNC_ERR	0x0020#define RFD_MULTICAST  0x0002	/* 0: destination had our address				   1: destination was broadcast/multicast */#define RFD_COLLISION  0x0001/* receive frame descriptor */struct i596_rfd {	unsigned short stat;	unsigned short cmd;	phys_addr pa_next;	/* va_to_pa(struct i596_rfd *next) */	phys_addr pa_rbd;	/* va_to_pa(struct i596_rbd *rbd) */	unsigned short count;	unsigned short size;	char data[1532];};#define RBD_EL		0x8000#define RBD_P		0x4000#define RBD_SIZEMASK	0x3fff#define RBD_EOF		0x8000#define RBD_F		0x4000/* receive buffer descriptor */struct i596_rbd {	unsigned short size;	unsigned short pad;	phys_addr pa_next;	/* va_to_pa(struct i596_tbd *next) */	phys_addr pa_data;	/* va_to_pa(char *data) */	phys_addr pa_prev;	/* va_to_pa(struct i596_tbd *prev) */		/* Driver private part */	struct sk_buff *skb;};#define RX_RING_SIZE 64#define RX_SKBSIZE (ETH_FRAME_LEN+10)#define RX_RBD_SIZE 32/* System Control Block - 40 bytes */struct i596_scb {	u16 status;		/* 0 */	u16 command;		/* 2 */	phys_addr pa_cmd;	/* 4 - va_to_pa(struct i596_cmd *cmd) */	phys_addr pa_rfd;	/* 8 - va_to_pa(struct i596_rfd *rfd) */	u32 crc_err;		/* 12 */	u32 align_err;		/* 16 */	u32 resource_err;	/* 20 */	u32 over_err;		/* 24 */	u32 rcvdt_err;		/* 28 */	u32 short_err;		/* 32 */	u16 t_on;		/* 36 */	u16 t_off;		/* 38 */};/* Intermediate System Configuration Pointer - 8 bytes */struct i596_iscp {	u32 busy;		/* 0 */	phys_addr pa_scb;	/* 4 - va_to_pa(struct i596_scb *scb) */};/* System Configuration Pointer - 12 bytes */struct i596_scp {	u32 sysbus;		/* 0 */	u32 pad;		/* 4 */	phys_addr pa_iscp;	/* 8 - va_to_pa(struct i596_iscp *iscp) */};/* Selftest and dump results - needs 16-byte alignment *//* * The size of the dump area is 304 bytes. When the dump is executed * by the Port command an extra word will be appended to the dump area. * The extra word is a copy of the Dump status word (containing the * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump] */struct i596_dump {	u16 dump[153];		/* (304 = 130h) + 2 bytes */};struct i596_private {		/* aligned to a 16-byte boundary */	struct i596_scp scp;	/* 0 - needs 16-byte alignment */	struct i596_iscp iscp;	/* 12 */	struct i596_scb scb;	/* 20 */	u32 dummy;		/* 60 */	struct i596_dump dump;	/* 64 - needs 16-byte alignment */	struct i596_cmd set_add;	char eth_addr[8];	/* directly follows set_add */	struct i596_cmd set_conf;	char i596_config[16];	/* directly follows set_conf */	struct i596_cmd tdr;	unsigned long tdr_stat;	/* directly follows tdr */	int last_restart;	volatile struct i596_rbd *rbd_list;	volatile struct i596_rbd *rbd_tail;	volatile struct i596_rfd *rx_tail;	volatile struct i596_cmd *cmd_tail;	volatile struct i596_cmd *cmd_head;	int cmd_backlog;	unsigned long last_cmd;	struct net_device_stats stats;};static char init_setup[14] = {	0x8E,	/* length 14 bytes, prefetch on */	0xC8,	/* default: fifo to 8, monitor off */	0x40,	/* default: don't save bad frames (apricot.c had 0x80) */	0x2E,	/* (default is 0x26)		   No source address insertion, 8 byte preamble */	0x00,	/* default priority and backoff */	0x60,	/* default interframe spacing */	0x00,	/* default slot time LSB */	0xf2,	/* default slot time and nr of retries */	0x00,	/* default various bits		   (0: promiscuous mode, 1: broadcast disable,		    2: encoding mode, 3: transmit on no CRS,		    4: no CRC insertion, 5: CRC type,		    6: bit stuffing, 7: padding) */	0x00,	/* default carrier sense and collision detect */	0x40,	/* default minimum frame length */	0xff,	/* (default is 0xff, and that is what apricot.c has;		   elp486.c has 0xfb: Enable crc append in memory.) */	0x00,	/* default: not full duplex */	0x7f	/* (default is 0x3f) multi IA */};static int i596_open(struct net_device *dev);static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int i596_close(struct net_device *dev);static struct net_device_stats *i596_get_stats(struct net_device *dev);static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);static void print_eth(char *);static void set_multicast_list(struct net_device *dev);static void i596_tx_timeout(struct net_device *dev);static inti596_timeout(struct net_device *dev, char *msg, int ct) {	volatile struct i596_private *lp;	int boguscnt = ct;	lp = (struct i596_private *) dev->priv;	while (lp->scb.command) {		if (--boguscnt == 0) {			printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",			       dev->name, msg,			       lp->scb.status, lp->scb.command);			return 1;		}		udelay(5);	}	return 0;}static inline intinit_rx_bufs(struct net_device *dev, int num) {	volatile struct i596_private *lp;	struct i596_rfd *rfd;	int i;	// struct i596_rbd *rbd;	lp = (struct i596_private *) dev->priv;	lp->scb.pa_rfd = I596_NULL;	for (i = 0; i < num; i++) {		rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);		if (rfd == NULL)			break;		rfd->stat = 0;		rfd->pa_rbd = I596_NULL;		rfd->count = 0;		rfd->size = 1532;		if (i == 0) {			rfd->cmd = CMD_EOL;			lp->rx_tail = rfd;		} else {			rfd->cmd = 0;		}		rfd->pa_next = lp->scb.pa_rfd;		lp->scb.pa_rfd = va_to_pa(rfd);		lp->rx_tail->pa_next = lp->scb.pa_rfd;	}#if 0	for (i = 0; i<RX_RBD_SIZE; i++) {		rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);		if (rbd) {			rbd->pad = 0;			rbd->count = 0;			rbd->skb = dev_alloc_skb(RX_SKB_SIZE);			if (!rbd->skb) {				printk("dev_alloc_skb failed");			}			rbd->next = rfd->rbd;			if (i) {				rfd->rbd->prev = rbd;				rbd->size = RX_SKB_SIZE;			} else {				rbd->size = (RX_SKB_SIZE | RBD_EL);				lp->rbd_tail = rbd;			}

⌨️ 快捷键说明

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