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

📄 gt96100eth.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2000 MontaVista Software Inc. * Author: MontaVista Software, Inc. *         	stevel@mvista.com or source@mvista.com * * ######################################################################## * *  This program is free software; you can distribute it and/or modify it *  under the terms of the GNU General Public License (Version 2) as *  published by the Free Software Foundation. * *  This program is distributed in the hope 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., *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * * ######################################################################## * * Ethernet driver for the MIPS GT96100 Advanced Communication Controller. *  */#ifndef __mips__#error This driver only works with MIPS architectures!#endif#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/in.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/io.h>#include "gt96100eth.h"#ifdef GT96100_DEBUGstatic int gt96100_debug = GT96100_DEBUG;#elsestatic int gt96100_debug = 3;#endif// prototypesstatic void *dmaalloc(size_t size, dma_addr_t * dma_handle);static void dmafree(size_t size, void *vaddr);static int gt96100_add_hash_entry(struct net_device *dev,				  unsigned char *addr);static void read_mib_counters(struct gt96100_private *gp);static int read_MII(struct net_device *dev, u32 reg);static int write_MII(struct net_device *dev, u32 reg, u16 data);static void dump_MII(struct net_device *dev);static void update_stats(struct gt96100_private *gp);static void abort(struct net_device *dev, u32 abort_bits);static void hard_stop(struct net_device *dev);static void enable_ether_irq(struct net_device *dev);static void disable_ether_irq(struct net_device *dev);static int __init gt96100_probe1(struct net_device *dev, long ioaddr,				 int irq, int port_num);static int gt96100_init(struct net_device *dev);static int gt96100_open(struct net_device *dev);static int gt96100_close(struct net_device *dev);static int gt96100_tx(struct sk_buff *skb, struct net_device *dev);static int gt96100_rx(struct net_device *dev, u32 status);static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void gt96100_tx_timeout(struct net_device *dev);static void gt96100_set_rx_mode(struct net_device *dev);static struct net_device_stats *gt96100_get_stats(struct net_device *dev);static char version[] __devinitdata =    "gt96100eth.c:0.1 stevel@mvista.com\n";// FIX! Need real Ethernet addressesstatic unsigned char gt96100_station_addr[2][6] __devinitdata =    { {0x01, 0x02, 0x03, 0x04, 0x05, 0x06},{0x01, 0x02, 0x03, 0x04, 0x05, 0x07}};#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0))#define RUN_AT(x) (jiffies + (x))// For reading/writing 32-bit words from/to DMA memory#define cpu_to_dma32 cpu_to_be32#define dma32_to_cpu be32_to_cpu/* * Base address and interupt of the GT96100 ethernet controllers */static struct {	unsigned int port;	int irq;} gt96100_iflist[NUM_INTERFACES] = {	{	GT96100_ETH0_BASE, GT96100_ETHER0_IRQ}, {	GT96100_ETH1_BASE, GT96100_ETHER1_IRQ}};/*  DMA memory allocation, derived from pci_alloc_consistent.*/static void *dmaalloc(size_t size, dma_addr_t * dma_handle){	void *ret;	ret =	    (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA,				      get_order(size));	if (ret != NULL) {		dma_cache_inv((unsigned long) ret, size);		if (dma_handle != NULL)			*dma_handle = virt_to_phys(ret);		/* bump virtual address up to non-cached area */		ret = KSEG1ADDR(ret);	}	return ret;}static void dmafree(size_t size, void *vaddr){	vaddr = KSEG0ADDR(vaddr);	free_pages((unsigned long) vaddr, get_order(size));}static int read_MII(struct net_device *dev, u32 reg){	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;	int timedout = 20;	u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) |	    (reg << smirRegAdBit);	// wait for last operation to complete	while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {		// snooze for 1 msec and check again#if 0		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(10 * HZ / 10000);#else		mdelay(1);#endif		if (--timedout == 0) {			printk(KERN_ERR "%s: read_MII busy timeout!!\n",			       dev->name);			return -1;		}	}	GT96100_WRITE(GT96100_ETH_SMI_REG, smir);	timedout = 20;	// wait for read to complete	while (!(smir = GT96100_READ(GT96100_ETH_SMI_REG) & smirReadValid)) {		// snooze for 1 msec and check again#if 0		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(10 * HZ / 10000);#else		mdelay(1);#endif		if (--timedout == 0) {			printk(KERN_ERR "%s: read_MII timeout!!\n",			       dev->name);			return -1;		}	}	return (int) (smir & smirDataMask);}static int write_MII(struct net_device *dev, u32 reg, u16 data){	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;	int timedout = 20;	u32 smir =	    (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data;	// wait for last operation to complete	while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {		// snooze for 1 msec and check again#if 0		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(10 * HZ / 10000);#else		mdelay(1);#endif		if (--timedout == 0) {			printk(KERN_ERR "%s: write_MII busy timeout!!\n",			       dev->name);			return -1;		}	}	GT96100_WRITE(GT96100_ETH_SMI_REG, smir);	return 0;}static void dump_MII(struct net_device *dev){	int i, val;	for (i = 0; i < 7; i++) {		if ((val = read_MII(dev, i)) >= 0)			printk("%s: MII Reg %d=%x\n", dev->name, i, val);	}	for (i = 16; i < 21; i++) {		if ((val = read_MII(dev, i)) >= 0)			printk("%s: MII Reg %d=%x\n", dev->name, i, val);	}}static intgt96100_add_hash_entry(struct net_device *dev, unsigned char *addr){	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;	u16 hashResult, stmp;	unsigned char ctmp, hash_ea[6];	u32 tblEntry, *tblEntryAddr;	int i;	for (i = 0; i < 6; i++) {		// nibble swap		ctmp = nibswap(addr[i]);		// invert every nibble		hash_ea[i] = ((ctmp & 1) << 3) | ((ctmp & 8) >> 3) |		    ((ctmp & 2) << 1) | ((ctmp & 4) >> 1);		hash_ea[i] |= ((ctmp & 0x10) << 3) | ((ctmp & 0x80) >> 3) |		    ((ctmp & 0x20) << 1) | ((ctmp & 0x40) >> 1);	}	if (gp->hash_mode == 0) {		hashResult = ((u16) hash_ea[0] & 0xfc) << 7;		stmp =		    ((u16) hash_ea[0] & 0x03) | (((u16) hash_ea[1] & 0x7f)						 << 2);		stmp ^=		    (((u16) hash_ea[1] >> 7) & 0x01) | ((u16) hash_ea[2] <<							1);		stmp ^= (u16) hash_ea[3] | (((u16) hash_ea[4] & 1) << 8);		hashResult |= stmp;	} else {		return -1;	// don't support hash mode 1	}	tblEntryAddr =	    (u32 *) (&gp->hash_table[((u32) hashResult & 0x7ff) << 3]);	for (i = 0; i < HASH_HOP_NUMBER; i++) {		if ((*tblEntryAddr & hteValid)		    && !(*tblEntryAddr & hteSkip)) {			// This entry is already occupied, go to next entry			tblEntryAddr += 2;		} else {			memset(tblEntryAddr, 0, 8);			tblEntry = hteValid | hteRD;			tblEntry |= (u32) addr[5] << 3;			tblEntry |= (u32) addr[4] << 11;			tblEntry |= (u32) addr[3] << 19;			tblEntry |= ((u32) addr[2] & 0x1f) << 27;			*(tblEntryAddr + 1) = cpu_to_dma32(tblEntry);			tblEntry = ((u32) addr[2] >> 5) & 0x07;			tblEntry |= (u32) addr[1] << 3;			tblEntry |= (u32) addr[0] << 11;			*tblEntryAddr = cpu_to_dma32(tblEntry);			break;		}	}	if (i >= HASH_HOP_NUMBER) {		printk(KERN_ERR "%s: gt96100_add_hash_entry expired!\n",		       dev->name);		return -1;	// Couldn't find an unused entry	}	return 0;}static void read_mib_counters(struct gt96100_private *gp){	u32 *mib_regs = (u32 *) & gp->mib;	int i;	for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++)		mib_regs[i] =		    GT96100ETH_READ(gp,				    GT96100_ETH_MIB_COUNT_BASE +				    i * sizeof(u32));}static void update_stats(struct gt96100_private *gp){	mib_counters_t *mib = &gp->mib;	struct net_device_stats *stats = &gp->stats;	read_mib_counters(gp);	stats->rx_packets = mib->totalFramesReceived;	stats->tx_packets = mib->framesSent;	stats->rx_bytes = mib->totalByteReceived;	stats->tx_bytes = mib->byteSent;	stats->rx_errors = mib->totalFramesReceived - mib->framesReceived;	//the tx error counters are incremented by the ISR	//rx_dropped incremented by gt96100_rx	//tx_dropped incremented by gt96100_tx	stats->multicast = mib->multicastFramesReceived;	// Tx collisions incremented by ISR, so add in MIB Rx collisions	stats->collisions += mib->collision + mib->lateCollision;	stats->rx_length_errors = mib->oversizeFrames + mib->fragments;	// The RxError condition means the Rx DMA encountered a	// CPU owned descriptor, which, if things are working as	// they should, means the Rx ring has overflowed.	stats->rx_over_errors = mib->macRxError;	stats->rx_crc_errors = mib->cRCError;}static void abort(struct net_device *dev, u32 abort_bits){	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;	int timedout = 100;	// wait up to 100 msec for hard stop to complete	if (gt96100_debug > 2)		printk(KERN_INFO "%s: abort\n", dev->name);	// Return if neither Rx or Tx abort bits are set	if (!(abort_bits & (sdcmrAR | sdcmrAT)))		return;	// make sure only the Rx/Tx abort bits are set	abort_bits &= (sdcmrAR | sdcmrAT);	spin_lock(&gp->lock);	// abort any Rx/Tx DMA immediately	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits);	if (gt96100_debug > 2)		printk(KERN_INFO "%s: abort: SDMA comm = %x\n",		       dev->name, GT96100ETH_READ(gp,						  GT96100_ETH_SDMA_COMM));	// wait for abort to complete	while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) {		// snooze for 20 msec and check again#if 0		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(10 * HZ / 10000);#else		mdelay(1);#endif		if (--timedout == 0) {			printk(KERN_ERR "%s: abort timeout!!\n",			       dev->name);			break;		}	}	if (gt96100_debug > 2)		printk(KERN_INFO "%s: abort: timedout=%d\n", dev->name,		       timedout);	spin_unlock(&gp->lock);}static void hard_stop(struct net_device *dev){	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;	if (gt96100_debug > 2)		printk(KERN_INFO "%s: hard stop\n", dev->name);	disable_ether_irq(dev);	abort(dev, sdcmrAR | sdcmrAT);	// disable port	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, 0);}static void enable_ether_irq(struct net_device *dev){	struct gt96100_private *gp = (struct gt96100_private *) dev->priv;	u32 intMask;	// unmask interrupts	GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK,			 icrRxBuffer | icrTxBufferLow | icrTxEndLow |			 icrRxError | icrTxErrorLow | icrRxOVR |			 icrTxUdr | icrRxBufferQ0 | icrRxErrorQ0 |			 icrMIIPhySTC);

⌨️ 快捷键说明

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