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

📄 sunhme.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, *           auto carrier detecting ethernet driver.  Also known as the *           "Happy Meal Ethernet" found on SunSwift SBUS cards. * * Copyright (C) 1996, 1998, 1999, 2002, 2003,		 2006 David S. Miller (davem@davemloft.net) * * Changes : * 2000/11/11 Willy Tarreau <willy AT meta-x.org> *   - port to non-sparc architectures. Tested only on x86 and *     only currently works with QFE PCI cards. *   - ability to specify the MAC address at module load time by passing this *     argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50 */#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.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/ethtool.h>#include <linux/mii.h>#include <linux/crc32.h>#include <linux/random.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/mm.h>#include <linux/bitops.h>#include <asm/system.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#ifdef CONFIG_SPARC#include <asm/idprom.h>#include <asm/sbus.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/prom.h>#include <asm/auxio.h>#endif#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/irq.h>#ifdef CONFIG_PCI#include <linux/pci.h>#endif#include "sunhme.h"#define DRV_NAME	"sunhme"#define DRV_VERSION	"3.00"#define DRV_RELDATE	"June 23, 2006"#define DRV_AUTHOR	"David S. Miller (davem@davemloft.net)"static char version[] =	DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";MODULE_VERSION(DRV_VERSION);MODULE_AUTHOR(DRV_AUTHOR);MODULE_DESCRIPTION("Sun HappyMealEthernet(HME) 10/100baseT ethernet driver");MODULE_LICENSE("GPL");static int macaddr[6];/* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */module_param_array(macaddr, int, NULL, 0);MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");#ifdef CONFIG_SBUSstatic struct quattro *qfe_sbus_list;#endif#ifdef CONFIG_PCIstatic struct quattro *qfe_pci_list;#endif#undef HMEDEBUG#undef SXDEBUG#undef RXDEBUG#undef TXDEBUG#undef TXLOGGING#ifdef TXLOGGINGstruct hme_tx_logent {	unsigned int tstamp;	int tx_new, tx_old;	unsigned int action;#define TXLOG_ACTION_IRQ	0x01#define TXLOG_ACTION_TXMIT	0x02#define TXLOG_ACTION_TBUSY	0x04#define TXLOG_ACTION_NBUFS	0x08	unsigned int status;};#define TX_LOG_LEN	128static struct hme_tx_logent tx_log[TX_LOG_LEN];static int txlog_cur_entry;static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigned int s){	struct hme_tx_logent *tlp;	unsigned long flags;	save_and_cli(flags);	tlp = &tx_log[txlog_cur_entry];	tlp->tstamp = (unsigned int)jiffies;	tlp->tx_new = hp->tx_new;	tlp->tx_old = hp->tx_old;	tlp->action = a;	tlp->status = s;	txlog_cur_entry = (txlog_cur_entry + 1) & (TX_LOG_LEN - 1);	restore_flags(flags);}static __inline__ void tx_dump_log(void){	int i, this;	this = txlog_cur_entry;	for (i = 0; i < TX_LOG_LEN; i++) {		printk("TXLOG[%d]: j[%08x] tx[N(%d)O(%d)] action[%08x] stat[%08x]\n", i,		       tx_log[this].tstamp,		       tx_log[this].tx_new, tx_log[this].tx_old,		       tx_log[this].action, tx_log[this].status);		this = (this + 1) & (TX_LOG_LEN - 1);	}}static __inline__ void tx_dump_ring(struct happy_meal *hp){	struct hmeal_init_block *hb = hp->happy_block;	struct happy_meal_txd *tp = &hb->happy_meal_txd[0];	int i;	for (i = 0; i < TX_RING_SIZE; i+=4) {		printk("TXD[%d..%d]: [%08x:%08x] [%08x:%08x] [%08x:%08x] [%08x:%08x]\n",		       i, i + 4,		       le32_to_cpu(tp[i].tx_flags), le32_to_cpu(tp[i].tx_addr),		       le32_to_cpu(tp[i + 1].tx_flags), le32_to_cpu(tp[i + 1].tx_addr),		       le32_to_cpu(tp[i + 2].tx_flags), le32_to_cpu(tp[i + 2].tx_addr),		       le32_to_cpu(tp[i + 3].tx_flags), le32_to_cpu(tp[i + 3].tx_addr));	}}#else#define tx_add_log(hp, a, s)		do { } while(0)#define tx_dump_log()			do { } while(0)#define tx_dump_ring(hp)		do { } while(0)#endif#ifdef HMEDEBUG#define HMD(x)  printk x#else#define HMD(x)#endif/* #define AUTO_SWITCH_DEBUG */#ifdef AUTO_SWITCH_DEBUG#define ASD(x)  printk x#else#define ASD(x)#endif#define DEFAULT_IPG0      16 /* For lance-mode only */#define DEFAULT_IPG1       8 /* For all modes */#define DEFAULT_IPG2       4 /* For all modes */#define DEFAULT_JAMSIZE    4 /* Toe jam *//* NOTE: In the descriptor writes one _must_ write the address *	 member _first_.  The card must not be allowed to see *	 the updated descriptor flags until the address is *	 correct.  I've added a write memory barrier between *	 the two stores so that I can sleep well at night... -DaveM */#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)static void sbus_hme_write32(void __iomem *reg, u32 val){	sbus_writel(val, reg);}static u32 sbus_hme_read32(void __iomem *reg){	return sbus_readl(reg);}static void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr){	rxd->rx_addr = addr;	wmb();	rxd->rx_flags = flags;}static void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr){	txd->tx_addr = addr;	wmb();	txd->tx_flags = flags;}static u32 sbus_hme_read_desc32(u32 *p){	return *p;}static void pci_hme_write32(void __iomem *reg, u32 val){	writel(val, reg);}static u32 pci_hme_read32(void __iomem *reg){	return readl(reg);}static void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr){	rxd->rx_addr = cpu_to_le32(addr);	wmb();	rxd->rx_flags = cpu_to_le32(flags);}static void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr){	txd->tx_addr = cpu_to_le32(addr);	wmb();	txd->tx_flags = cpu_to_le32(flags);}static u32 pci_hme_read_desc32(u32 *p){	return cpu_to_le32p(p);}#define hme_write32(__hp, __reg, __val) \	((__hp)->write32((__reg), (__val)))#define hme_read32(__hp, __reg) \	((__hp)->read32(__reg))#define hme_write_rxd(__hp, __rxd, __flags, __addr) \	((__hp)->write_rxd((__rxd), (__flags), (__addr)))#define hme_write_txd(__hp, __txd, __flags, __addr) \	((__hp)->write_txd((__txd), (__flags), (__addr)))#define hme_read_desc32(__hp, __p) \	((__hp)->read_desc32(__p))#define hme_dma_map(__hp, __ptr, __size, __dir) \	((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))#define hme_dma_unmap(__hp, __addr, __size, __dir) \	((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \	((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)))#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \	((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)))#else#ifdef CONFIG_SBUS/* SBUS only compilation */#define hme_write32(__hp, __reg, __val) \	sbus_writel((__val), (__reg))#define hme_read32(__hp, __reg) \	sbus_readl(__reg)#define hme_write_rxd(__hp, __rxd, __flags, __addr) \do {	(__rxd)->rx_addr = (__addr); \	wmb(); \	(__rxd)->rx_flags = (__flags); \} while(0)#define hme_write_txd(__hp, __txd, __flags, __addr) \do {	(__txd)->tx_addr = (__addr); \	wmb(); \	(__txd)->tx_flags = (__flags); \} while(0)#define hme_read_desc32(__hp, __p)	(*(__p))#define hme_dma_map(__hp, __ptr, __size, __dir) \	sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))#define hme_dma_unmap(__hp, __addr, __size, __dir) \	sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \	sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \	sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))#else/* PCI only compilation */#define hme_write32(__hp, __reg, __val) \	writel((__val), (__reg))#define hme_read32(__hp, __reg) \	readl(__reg)#define hme_write_rxd(__hp, __rxd, __flags, __addr) \do {	(__rxd)->rx_addr = cpu_to_le32(__addr); \	wmb(); \	(__rxd)->rx_flags = cpu_to_le32(__flags); \} while(0)#define hme_write_txd(__hp, __txd, __flags, __addr) \do {	(__txd)->tx_addr = cpu_to_le32(__addr); \	wmb(); \	(__txd)->tx_flags = cpu_to_le32(__flags); \} while(0)#define hme_read_desc32(__hp, __p)	cpu_to_le32p(__p)#define hme_dma_map(__hp, __ptr, __size, __dir) \	pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))#define hme_dma_unmap(__hp, __addr, __size, __dir) \	pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \	pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \	pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))#endif#endif#ifdef SBUS_DMA_BIDIRECTIONAL#	define DMA_BIDIRECTIONAL	SBUS_DMA_BIDIRECTIONAL#else#	define DMA_BIDIRECTIONAL	0#endif#ifdef SBUS_DMA_FROMDEVICE#	define DMA_FROMDEVICE		SBUS_DMA_FROMDEVICE#else#	define DMA_TODEVICE		1#endif#ifdef SBUS_DMA_TODEVICE#	define DMA_TODEVICE		SBUS_DMA_TODEVICE#else#	define DMA_FROMDEVICE		2#endif/* Oh yes, the MIF BitBang is mighty fun to program.  BitBucket is more like it. */static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit){	hme_write32(hp, tregs + TCVR_BBDATA, bit);	hme_write32(hp, tregs + TCVR_BBCLOCK, 0);	hme_write32(hp, tregs + TCVR_BBCLOCK, 1);}#if 0static u32 BB_GET_BIT(struct happy_meal *hp, void __iomem *tregs, int internal){	u32 ret;	hme_write32(hp, tregs + TCVR_BBCLOCK, 0);	hme_write32(hp, tregs + TCVR_BBCLOCK, 1);	ret = hme_read32(hp, tregs + TCVR_CFG);	if (internal)		ret &= TCV_CFG_MDIO0;	else		ret &= TCV_CFG_MDIO1;	return ret;}#endifstatic u32 BB_GET_BIT2(struct happy_meal *hp, void __iomem *tregs, int internal){	u32 retval;	hme_write32(hp, tregs + TCVR_BBCLOCK, 0);	udelay(1);	retval = hme_read32(hp, tregs + TCVR_CFG);	if (internal)		retval &= TCV_CFG_MDIO0;	else		retval &= TCV_CFG_MDIO1;	hme_write32(hp, tregs + TCVR_BBCLOCK, 1);	return retval;}#define TCVR_FAILURE      0x80000000     /* Impossible MIF read value */static int happy_meal_bb_read(struct happy_meal *hp,			      void __iomem *tregs, int reg){	u32 tmp;	int retval = 0;	int i;	ASD(("happy_meal_bb_read: reg=%d ", reg));	/* Enable the MIF BitBang outputs. */	hme_write32(hp, tregs + TCVR_BBOENAB, 1);	/* Force BitBang into the idle state. */	for (i = 0; i < 32; i++)		BB_PUT_BIT(hp, tregs, 1);	/* Give it the read sequence. */	BB_PUT_BIT(hp, tregs, 0);	BB_PUT_BIT(hp, tregs, 1);	BB_PUT_BIT(hp, tregs, 1);	BB_PUT_BIT(hp, tregs, 0);	/* Give it the PHY address. */	tmp = hp->paddr & 0xff;	for (i = 4; i >= 0; i--)		BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1));	/* Tell it what register we want to read. */	tmp = (reg & 0xff);	for (i = 4; i >= 0; i--)		BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1));	/* Close down the MIF BitBang outputs. */	hme_write32(hp, tregs + TCVR_BBOENAB, 0);	/* Now read in the value. */	(void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));	for (i = 15; i >= 0; i--)		retval |= BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));	(void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));	(void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));	(void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal));	ASD(("value=%x\n", retval));	return retval;}static void happy_meal_bb_write(struct happy_meal *hp,				void __iomem *tregs, int reg,				unsigned short value){	u32 tmp;	int i;	ASD(("happy_meal_bb_write: reg=%d value=%x\n", reg, value));	/* Enable the MIF BitBang outputs. */	hme_write32(hp, tregs + TCVR_BBOENAB, 1);	/* Force BitBang into the idle state. */	for (i = 0; i < 32; i++)		BB_PUT_BIT(hp, tregs, 1);	/* Give it write sequence. */	BB_PUT_BIT(hp, tregs, 0);	BB_PUT_BIT(hp, tregs, 1);	BB_PUT_BIT(hp, tregs, 0);	BB_PUT_BIT(hp, tregs, 1);	/* Give it the PHY address. */	tmp = (hp->paddr & 0xff);

⌨️ 快捷键说明

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