au1000_eth.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,407 行 · 第 1/3 页

C
1,407
字号
/* * Alchemy Semi Au1000 ethernet driver * * Copyright 2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. *         	ppopov@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. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.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 <linux/crc32.h>#include <asm/mipsregs.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/au1000.h>#include "au1000_eth.h"#ifdef AU1000_ETH_DEBUGstatic int au1000_debug = 10;#elsestatic int au1000_debug = 3;#endif// prototypesstatic void *dma_alloc(size_t, dma_addr_t *);static void dma_free(void *, size_t);static void hard_stop(struct net_device *);static void enable_rx_tx(struct net_device *dev);static int __init au1000_probe1(long, int, int);static int au1000_init(struct net_device *);static int au1000_open(struct net_device *);static int au1000_close(struct net_device *);static int au1000_tx(struct sk_buff *, struct net_device *);static int au1000_rx(struct net_device *);static irqreturn_t au1000_interrupt(int, void *, struct pt_regs *);static void au1000_tx_timeout(struct net_device *);static int au1000_set_config(struct net_device *dev, struct ifmap *map);static void set_rx_mode(struct net_device *);static struct net_device_stats *au1000_get_stats(struct net_device *);static inline void update_tx_stats(struct net_device *, u32, u32);static inline void update_rx_stats(struct net_device *, u32);static void au1000_timer(unsigned long);static int au1000_ioctl(struct net_device *, struct ifreq *, int);static int mdio_read(struct net_device *, int, int);static void mdio_write(struct net_device *, int, int, u16);static void dump_mii(struct net_device *dev, int phy_id);// externsextern  void ack_rise_edge_irq(unsigned int);extern int get_ethernet_addr(char *ethernet_addr);extern inline void str2eaddr(unsigned char *ea, unsigned char *str);extern inline unsigned char str2hexnum(unsigned char c);extern char * __init prom_getcmdline(void);/* * Theory of operation * * The Au1000 MACs use a simple rx and tx descriptor ring scheme.  * There are four receive and four transmit descriptors.  These  * descriptors are not in memory; rather, they are just a set of  * hardware registers. * * Since the Au1000 has a coherent data cache, the receive and * transmit buffers are allocated from the KSEG0 segment. The  * hardware registers, however, are still mapped at KSEG1 to * make sure there's no out-of-order writes, and that all writes * complete immediately. *//* * Base address and interrupt of the Au1xxx ethernet macs */static struct {	unsigned int port;	int irq;} au1000_iflist[NUM_INTERFACES] = {		{AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, 		{AU1000_ETH1_BASE, AU1000_ETH1_IRQ}	},  au1500_iflist[NUM_INTERFACES] = {		{AU1500_ETH0_BASE, AU1000_ETH0_IRQ}, 		{AU1500_ETH1_BASE, AU1000_ETH1_IRQ}	},  au1100_iflist[NUM_INTERFACES] = {		{AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, 		{0, 0}	};static char version[] __devinitdata =    "au1000eth.c:1.0 ppopov@mvista.com\n";/* These addresses are only used if yamon doesn't tell us what * the mac address is, and the mac address is not passed on the * command line. */static unsigned char au1000_mac_addr[6] __devinitdata = { 	0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00};#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/* FIXME  * All of the PHY code really should be detached from the MAC  * code. */int bcm_5201_init(struct net_device *dev, int phy_addr){	s16 data;		/* Stop auto-negotiation */	//printk("bcm_5201_init\n");	data = mdio_read(dev, phy_addr, MII_CONTROL);	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);	/* Set advertisement to 10/100 and Half/Full duplex	 * (full capabilities) */	data = mdio_read(dev, phy_addr, MII_ANADV);	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;	mdio_write(dev, phy_addr, MII_ANADV, data);		/* Restart auto-negotiation */	data = mdio_read(dev, phy_addr, MII_CONTROL);	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;	mdio_write(dev, phy_addr, MII_CONTROL, data);	/* Enable TX LED instead of FDX */	data = mdio_read(dev, phy_addr, MII_INT);	data &= ~MII_FDX_LED;	mdio_write(dev, phy_addr, MII_INT, data);	/* Enable TX LED instead of FDX */	data = mdio_read(dev, phy_addr, MII_INT);	data &= ~MII_FDX_LED;	mdio_write(dev, phy_addr, MII_INT, data);	if (au1000_debug > 4) dump_mii(dev, phy_addr);	return 0;}int bcm_5201_reset(struct net_device *dev, int phy_addr){	s16 mii_control, timeout;		//printk("bcm_5201_reset\n");	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);	mdelay(1);	for (timeout = 100; timeout > 0; --timeout) {		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);		if ((mii_control & MII_CNTL_RESET) == 0)			break;		mdelay(1);	}	if (mii_control & MII_CNTL_RESET) {		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);		return -1;	}	return 0;}int bcm_5201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed){	u16 mii_data;	struct au1000_private *aup;	if (!dev) {		printk(KERN_ERR "bcm_5201_status error: NULL dev\n");		return -1;	}	aup = (struct au1000_private *) dev->priv;	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);	if (mii_data & MII_STAT_LINK) {		*link = 1;		mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL);		if (mii_data & MII_AUX_100) {			if (mii_data & MII_AUX_FDX) {				*speed = IF_PORT_100BASEFX;				dev->if_port = IF_PORT_100BASEFX;			}			else {				*speed = IF_PORT_100BASETX;				dev->if_port = IF_PORT_100BASETX;			}		}		else  {			*speed = IF_PORT_10BASET;			dev->if_port = IF_PORT_10BASET;		}	}	else {		*link = 0;		*speed = 0;		dev->if_port = IF_PORT_UNKNOWN;	}	return 0;}int lsi_80227_init(struct net_device *dev, int phy_addr){	if (au1000_debug > 4)		printk("lsi_80227_init\n");	/* restart auto-negotiation */	mdio_write(dev, phy_addr, 0, 0x3200);	mdelay(1);	/* set up LEDs to correct display */	mdio_write(dev, phy_addr, 17, 0xffc0);	if (au1000_debug > 4)		dump_mii(dev, phy_addr);	return 0;}int lsi_80227_reset(struct net_device *dev, int phy_addr){	s16 mii_control, timeout;		if (au1000_debug > 4) {		printk("lsi_80227_reset\n");		dump_mii(dev, phy_addr);	}	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);	mdelay(1);	for (timeout = 100; timeout > 0; --timeout) {		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);		if ((mii_control & MII_CNTL_RESET) == 0)			break;		mdelay(1);	}	if (mii_control & MII_CNTL_RESET) {		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);		return -1;	}	return 0;}intlsi_80227_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed){	u16 mii_data;	struct au1000_private *aup;	if (!dev) {		printk(KERN_ERR "lsi_80227_status error: NULL dev\n");		return -1;	}	aup = (struct au1000_private *) dev->priv;	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);	if (mii_data & MII_STAT_LINK) {		*link = 1;		mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_STAT);		if (mii_data & MII_LSI_STAT_SPD) {			if (mii_data & MII_LSI_STAT_FDX) {				*speed = IF_PORT_100BASEFX;				dev->if_port = IF_PORT_100BASEFX;			}			else {				*speed = IF_PORT_100BASETX;				dev->if_port = IF_PORT_100BASETX;			}		}		else  {			*speed = IF_PORT_10BASET;			dev->if_port = IF_PORT_10BASET;		}	}	else {		*link = 0;		*speed = 0;		dev->if_port = IF_PORT_UNKNOWN;	}	return 0;}int am79c901_init(struct net_device *dev, int phy_addr){	printk("am79c901_init\n");	return 0;}int am79c901_reset(struct net_device *dev, int phy_addr){	printk("am79c901_reset\n");	return 0;}int am79c901_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed){	return 0;}struct phy_ops bcm_5201_ops = {	bcm_5201_init,	bcm_5201_reset,	bcm_5201_status,};struct phy_ops am79c901_ops = {	am79c901_init,	am79c901_reset,	am79c901_status,};struct phy_ops lsi_80227_ops = { 	lsi_80227_init,	lsi_80227_reset,	lsi_80227_status,};static struct mii_chip_info {	const char * name;	u16 phy_id0;	u16 phy_id1;	struct phy_ops *phy_ops;	} mii_chip_table[] = {	{"Broadcom BCM5201 10/100 BaseT PHY",  0x0040, 0x6212, &bcm_5201_ops },	{"AMD 79C901 HomePNA PHY",  0x0000, 0x35c8, &am79c901_ops },	{"LSI 80227 10/100 BaseT PHY", 0x0016, 0xf840, &lsi_80227_ops },	{"Broadcom BCM5221 10/100 BaseT PHY",  0x0040, 0x61e4, &bcm_5201_ops },	{0,},};static int mdio_read(struct net_device *dev, int phy_id, int reg){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	u32 timedout = 20;	u32 mii_control;	while (aup->mac->mii_control & MAC_MII_BUSY) {		mdelay(1);		if (--timedout == 0) {			printk(KERN_ERR "%s: read_MII busy timeout!!\n", 					dev->name);			return -1;		}	}	mii_control = MAC_SET_MII_SELECT_REG(reg) | 		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_READ;	aup->mac->mii_control = mii_control;	timedout = 20;	while (aup->mac->mii_control & MAC_MII_BUSY) {		mdelay(1);		if (--timedout == 0) {			printk(KERN_ERR "%s: mdio_read busy timeout!!\n", 					dev->name);			return -1;		}	}	return (int)aup->mac->mii_data;}static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	u32 timedout = 20;	u32 mii_control;	while (aup->mac->mii_control & MAC_MII_BUSY) {		mdelay(1);		if (--timedout == 0) {			printk(KERN_ERR "%s: mdio_write busy timeout!!\n", 					dev->name);			return;		}	}	mii_control = MAC_SET_MII_SELECT_REG(reg) | 		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_WRITE;	aup->mac->mii_data = value;	aup->mac->mii_control = mii_control;}static void dump_mii(struct net_device *dev, int phy_id){	int i, val;	for (i = 0; i < 7; i++) {		if ((val = mdio_read(dev, phy_id, i)) >= 0)			printk("%s: MII Reg %d=%x\n", dev->name, i, val);	}	for (i = 16; i < 25; i++) {		if ((val = mdio_read(dev, phy_id, i)) >= 0)			printk("%s: MII Reg %d=%x\n", dev->name, i, val);	}}static int __init mii_probe (struct net_device * dev){	struct au1000_private *aup = (struct au1000_private *) dev->priv;	int phy_addr;	aup->mii = NULL;	/* search for total of 32 possible mii phy addresses */	for (phy_addr = 0; phy_addr < 32; phy_addr++) {		u16 mii_status;		u16 phy_id0, phy_id1;		int i;		mii_status = mdio_read(dev, phy_addr, MII_STATUS);		if (mii_status == 0xffff || mii_status == 0x0000)			/* the mii is not accessible, try next one */			continue;		phy_id0 = mdio_read(dev, phy_addr, MII_PHY_ID0);		phy_id1 = mdio_read(dev, phy_addr, MII_PHY_ID1);		/* search our mii table for the current mii */ 		for (i = 0; mii_chip_table[i].phy_id1; i++) {			if (phy_id0 == mii_chip_table[i].phy_id0 &&			    phy_id1 == mii_chip_table[i].phy_id1) {				struct mii_phy * mii_phy;				printk(KERN_INFO "%s: %s at phy address %d\n",				       dev->name, mii_chip_table[i].name, 				       phy_addr);

⌨️ 快捷键说明

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