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

📄 sungem.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: sungem.c,v 1.44.2.5 2002/02/01 21:45:52 davem Exp $ * sungem.c: Sun GEM ethernet driver. * * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) *  * Support for Apple GMAC and assorted PHYs by * Benjamin Herrenscmidt (benh@kernel.crashing.org) *  * TODO:  *  - Get rid of all those nasty mdelay's and replace them * with schedule_timeout. *  - Implement WOL *  - Currently, forced Gb mode is only supported on bcm54xx *    PHY for which I use the SPD2 bit of the control register. *    On m1011 PHY, I can't force as I don't have the specs, but *    I can at least detect gigabit with autoneg. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#include <asm/irq.h>#ifdef __sparc__#include <asm/idprom.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/pbm.h>#endif#ifdef CONFIG_ALL_PPC#include <asm/pci-bridge.h>#include <asm/prom.h>#include <asm/machdep.h>#include <asm/pmac_feature.h>#endif#include "sungem.h"#define DEFAULT_MSG	(NETIF_MSG_DRV		| \			 NETIF_MSG_PROBE	| \			 NETIF_MSG_LINK)#define DRV_NAME	"sungem"#define DRV_VERSION	"0.96"#define DRV_RELDATE	"11/17/01"#define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"static char version[] __devinitdata =        DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";MODULE_AUTHOR(DRV_AUTHOR);MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");MODULE_LICENSE("GPL");MODULE_PARM(gem_debug, "i");MODULE_PARM_DESC(gem_debug, "bitmapped message enable number");MODULE_PARM(link_mode, "i");MODULE_PARM_DESC(link_mode, "default link mode");int gem_debug = -1;static int link_mode;static u16 link_modes[] __devinitdata = {	BMCR_ANENABLE,			/* 0 : autoneg */	0,				/* 1 : 10bt half duplex */	BMCR_SPEED100,			/* 2 : 100bt half duplex */	BMCR_SPD2, /* bcm54xx only */   /* 3 : 1000bt half duplex */	BMCR_FULLDPLX,			/* 4 : 10bt full duplex */	BMCR_SPEED100|BMCR_FULLDPLX,	/* 5 : 100bt full duplex */	BMCR_SPD2|BMCR_FULLDPLX		/* 6 : 1000bt full duplex */};#define GEM_MODULE_NAME	"gem"#define PFX GEM_MODULE_NAME ": "static struct pci_device_id gem_pci_tbl[] __devinitdata = {	{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	/* These models only differ from the original GEM in	 * that their tx/rx fifos are of a different size and	 * they only support 10/100 speeds. -DaveM	 * 	 * Apple's GMAC does support gigabit on machines with	 * the BCM54xx PHYs. -BenH	 */	{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMAC,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMACP,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{0, }};MODULE_DEVICE_TABLE(pci, gem_pci_tbl);static u16 __phy_read(struct gem *gp, int reg, int phy_addr){	u32 cmd;	int limit = 10000;	cmd  = (1 << 30);	cmd |= (2 << 28);	cmd |= (phy_addr << 23) & MIF_FRAME_PHYAD;	cmd |= (reg << 18) & MIF_FRAME_REGAD;	cmd |= (MIF_FRAME_TAMSB);	writel(cmd, gp->regs + MIF_FRAME);	while (limit--) {		cmd = readl(gp->regs + MIF_FRAME);		if (cmd & MIF_FRAME_TALSB)			break;		udelay(10);	}	if (!limit)		cmd = 0xffff;	return cmd & MIF_FRAME_DATA;}static inline u16 phy_read(struct gem *gp, int reg){	return __phy_read(gp, reg, gp->mii_phy_addr);}static void __phy_write(struct gem *gp, int reg, u16 val, int phy_addr){	u32 cmd;	int limit = 10000;	cmd  = (1 << 30);	cmd |= (1 << 28);	cmd |= (phy_addr << 23) & MIF_FRAME_PHYAD;	cmd |= (reg << 18) & MIF_FRAME_REGAD;	cmd |= (MIF_FRAME_TAMSB);	cmd |= (val & MIF_FRAME_DATA);	writel(cmd, gp->regs + MIF_FRAME);	while (limit--) {		cmd = readl(gp->regs + MIF_FRAME);		if (cmd & MIF_FRAME_TALSB)			break;		udelay(10);	}}static inline void phy_write(struct gem *gp, int reg, u16 val){	__phy_write(gp, reg, val, gp->mii_phy_addr);}static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits){	if (netif_msg_intr(gp))		printk(KERN_DEBUG "%s: mif interrupt\n", gp->dev->name);}static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status){	u32 pcs_istat = readl(gp->regs + PCS_ISTAT);	u32 pcs_miistat;	if (netif_msg_intr(gp))		printk(KERN_DEBUG "%s: pcs interrupt, pcs_istat: 0x%x\n",			gp->dev->name, pcs_istat);	if (!(pcs_istat & PCS_ISTAT_LSC)) {		printk(KERN_ERR "%s: PCS irq but no link status change???\n",		       dev->name);		return 0;	}	/* The link status bit latches on zero, so you must	 * read it twice in such a case to see a transition	 * to the link being up.	 */	pcs_miistat = readl(gp->regs + PCS_MIISTAT);	if (!(pcs_miistat & PCS_MIISTAT_LS))		pcs_miistat |=			(readl(gp->regs + PCS_MIISTAT) &			 PCS_MIISTAT_LS);	if (pcs_miistat & PCS_MIISTAT_ANC) {		/* The remote-fault indication is only valid		 * when autoneg has completed.		 */		if (pcs_miistat & PCS_MIISTAT_RF)			printk(KERN_INFO "%s: PCS AutoNEG complete, "			       "RemoteFault\n", dev->name);		else			printk(KERN_INFO "%s: PCS AutoNEG complete.\n",			       dev->name);	}	if (pcs_miistat & PCS_MIISTAT_LS) {		printk(KERN_INFO "%s: PCS link is now up.\n",		       dev->name);	} else {		printk(KERN_INFO "%s: PCS link is now down.\n",		       dev->name);		/* If this happens and the link timer is not running,		 * reset so we re-negotiate.		 */		if (!timer_pending(&gp->link_timer))			return 1;	}	return 0;}static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status){	u32 txmac_stat = readl(gp->regs + MAC_TXSTAT);	if (netif_msg_intr(gp))		printk(KERN_DEBUG "%s: txmac interrupt, txmac_stat: 0x%x\n",			gp->dev->name, txmac_stat);	/* Defer timer expiration is quite normal,	 * don't even log the event.	 */	if ((txmac_stat & MAC_TXSTAT_DTE) &&	    !(txmac_stat & ~MAC_TXSTAT_DTE))		return 0;	if (txmac_stat & MAC_TXSTAT_URUN) {		printk(KERN_ERR "%s: TX MAC xmit underrun.\n",		       dev->name);		gp->net_stats.tx_fifo_errors++;	}	if (txmac_stat & MAC_TXSTAT_MPE) {		printk(KERN_ERR "%s: TX MAC max packet size error.\n",		       dev->name);		gp->net_stats.tx_errors++;	}	/* The rest are all cases of one of the 16-bit TX	 * counters expiring.	 */	if (txmac_stat & MAC_TXSTAT_NCE)		gp->net_stats.collisions += 0x10000;	if (txmac_stat & MAC_TXSTAT_ECE) {		gp->net_stats.tx_aborted_errors += 0x10000;		gp->net_stats.collisions += 0x10000;	}	if (txmac_stat & MAC_TXSTAT_LCE) {		gp->net_stats.tx_aborted_errors += 0x10000;		gp->net_stats.collisions += 0x10000;	}	/* We do not keep track of MAC_TXSTAT_FCE and	 * MAC_TXSTAT_PCE events.	 */	return 0;}static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status){	u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT);	int ret = 0;	if (netif_msg_intr(gp))		printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n",			gp->dev->name, rxmac_stat);	if (rxmac_stat & MAC_RXSTAT_OFLW) {		u32 smac = readl(gp->regs + MAC_SMACHINE);		printk(KERN_ERR "%s: RX MAC fifo overflow smac[%08x].\n",		       dev->name, smac);		gp->net_stats.rx_over_errors++;		gp->net_stats.rx_fifo_errors++;		if (((smac >> 24) & 0x7) == 0x7) {			/* Due to a bug, the chip is hung in this case			 * and a full reset is necessary.			 */			ret = 1;		}	}	if (rxmac_stat & MAC_RXSTAT_ACE)		gp->net_stats.rx_frame_errors += 0x10000;	if (rxmac_stat & MAC_RXSTAT_CCE)		gp->net_stats.rx_crc_errors += 0x10000;	if (rxmac_stat & MAC_RXSTAT_LCE)		gp->net_stats.rx_length_errors += 0x10000;	/* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE	 * events.	 */	return ret;}static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status){	u32 mac_cstat = readl(gp->regs + MAC_CSTAT);	if (netif_msg_intr(gp))		printk(KERN_DEBUG "%s: mac interrupt, mac_cstat: 0x%x\n",			gp->dev->name, mac_cstat);	/* This interrupt is just for pause frame and pause	 * tracking.  It is useful for diagnostics and debug	 * but probably by default we will mask these events.	 */	if (mac_cstat & MAC_CSTAT_PS)		gp->pause_entered++;	if (mac_cstat & MAC_CSTAT_PRCV)		gp->pause_last_time_recvd = (mac_cstat >> 16);	return 0;}static int gem_mif_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status){	u32 mif_status = readl(gp->regs + MIF_STATUS);	u32 reg_val, changed_bits;	reg_val = (mif_status & MIF_STATUS_DATA) >> 16;	changed_bits = (mif_status & MIF_STATUS_STAT);	gem_handle_mif_event(gp, reg_val, changed_bits);	return 0;}static int gem_pci_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status){	u32 pci_estat = readl(gp->regs + GREG_PCIESTAT);	if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&	    gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) {		printk(KERN_ERR "%s: PCI error [%04x] ",		       dev->name, pci_estat);		if (pci_estat & GREG_PCIESTAT_BADACK)			printk("<No ACK64# during ABS64 cycle> ");		if (pci_estat & GREG_PCIESTAT_DTRTO)			printk("<Delayed transaction timeout> ");		if (pci_estat & GREG_PCIESTAT_OTHER)			printk("<other>");		printk("\n");	} else {		pci_estat |= GREG_PCIESTAT_OTHER;		printk(KERN_ERR "%s: PCI error\n", dev->name);	}	if (pci_estat & GREG_PCIESTAT_OTHER) {		u16 pci_cfg_stat;		/* Interrogate PCI config space for the		 * true cause.		 */		pci_read_config_word(gp->pdev, PCI_STATUS,				     &pci_cfg_stat);		printk(KERN_ERR "%s: Read PCI cfg space status [%04x]\n",		       dev->name, pci_cfg_stat);		if (pci_cfg_stat & PCI_STATUS_PARITY)			printk(KERN_ERR "%s: PCI parity error detected.\n",			       dev->name);		if (pci_cfg_stat & PCI_STATUS_SIG_TARGET_ABORT)			printk(KERN_ERR "%s: PCI target abort.\n",			       dev->name);		if (pci_cfg_stat & PCI_STATUS_REC_TARGET_ABORT)			printk(KERN_ERR "%s: PCI master acks target abort.\n",			       dev->name);		if (pci_cfg_stat & PCI_STATUS_REC_MASTER_ABORT)			printk(KERN_ERR "%s: PCI master abort.\n",			       dev->name);		if (pci_cfg_stat & PCI_STATUS_SIG_SYSTEM_ERROR)			printk(KERN_ERR "%s: PCI system error SERR#.\n",			       dev->name);		if (pci_cfg_stat & PCI_STATUS_DETECTED_PARITY)			printk(KERN_ERR "%s: PCI parity error.\n",			       dev->name);		/* Write the error bits back to clear them. */		pci_cfg_stat &= (PCI_STATUS_PARITY |				 PCI_STATUS_SIG_TARGET_ABORT |				 PCI_STATUS_REC_TARGET_ABORT |				 PCI_STATUS_REC_MASTER_ABORT |				 PCI_STATUS_SIG_SYSTEM_ERROR |				 PCI_STATUS_DETECTED_PARITY);		pci_write_config_word(gp->pdev,				      PCI_STATUS, pci_cfg_stat);	}	/* For all PCI errors, we should reset the chip. */	return 1;}/* All non-normal interrupt conditions get serviced here. * Returns non-zero if we should just exit the interrupt * handler right now (ie. if we reset the card which invalidates * all of the other original irq status bits). */static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_status){	if (gem_status & GREG_STAT_RXNOBUF) {		/* Frame arrived, no free RX buffers available. */		if (netif_msg_rx_err(gp))			printk(KERN_DEBUG "%s: no buffer for rx frame\n",				gp->dev->name);		gp->net_stats.rx_dropped++;	}	if (gem_status & GREG_STAT_RXTAGERR) {		/* corrupt RX tag framing */		if (netif_msg_rx_err(gp))			printk(KERN_DEBUG "%s: corrupt rx tag framing\n",				gp->dev->name);		gp->net_stats.rx_errors++;		goto do_reset;	}	if (gem_status & GREG_STAT_PCS) {		if (gem_pcs_interrupt(dev, gp, gem_status))			goto do_reset;	}	if (gem_status & GREG_STAT_TXMAC) {		if (gem_txmac_interrupt(dev, gp, gem_status))			goto do_reset;	}	if (gem_status & GREG_STAT_RXMAC) {		if (gem_rxmac_interrupt(dev, gp, gem_status))			goto do_reset;	}	if (gem_status & GREG_STAT_MAC) {		if (gem_mac_interrupt(dev, gp, gem_status))			goto do_reset;	}	if (gem_status & GREG_STAT_MIF) {		if (gem_mif_interrupt(dev, gp, gem_status))			goto do_reset;	}	if (gem_status & GREG_STAT_PCIERR) {		if (gem_pci_interrupt(dev, gp, gem_status))			goto do_reset;	}	return 0;do_reset:	gp->reset_task_pending = 2;	schedule_task(&gp->reset_task);	return 1;}static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_status){	int entry, limit;	if (netif_msg_intr(gp))		printk(KERN_DEBUG "%s: tx interrupt, gem_status: 0x%x\n",			gp->dev->name, gem_status);	entry = gp->tx_old;	limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT);	while (entry != limit) {		struct sk_buff *skb;		struct gem_txd *txd;		dma_addr_t dma_addr;		u32 dma_len;		int frag;		if (netif_msg_tx_done(gp))			printk(KERN_DEBUG "%s: tx done, slot %d\n",				gp->dev->name, entry);		skb = gp->tx_skbs[entry];		if (skb_shinfo(skb)->nr_frags) {			int last = entry + skb_shinfo(skb)->nr_frags;			int walk = entry;			int incomplete = 0;			last &= (TX_RING_SIZE - 1);			for (;;) {				walk = NEXT_TX(walk);				if (walk == limit)					incomplete = 1;				if (walk == last)					break;			}			if (incomplete)

⌨️ 快捷键说明

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