📄 ax88180.c
字号:
/* ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet Linux driver *//* * Copyright (c) 2005 ASIX Electronics Corporation * Written by Allan Chou <allan@asix.com.tw> * * 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. * *//* * ======================================================================== * ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver * * The AX88180 Ethernet controller is high performance and highly * integrated local CPU bus Ethernet controllers with embedded 40K bytes * SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces * for any embedded systems. * The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet controller * that supports both MII and RGMII interfaces and is compliant to * IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards. * * Please visit ASIX's web site (http://www.asix.com.tw) for more details. * * Module Name : ax88180.c * Purpose : This file is the main file. * Author : Allan Chou <allan@asix.com.tw> * Date : 2005-12-07 * Notes : * History : * $Log:$ * 1.0.0 2005-12-07 * New release for AX88180 US1 chip. * * 1.0.1 2006-06-14 * 1.Modify to support AX88180 US2 chip. * 2.Modify to support AX88180 US2 burst data access function. * * * * * * * * * * ======================================================================== */#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/string.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/spinlock.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/crc32.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)#include <linux/ethtool.h>#endif#include <linux/mii.h>#include <linux/if_ether.h>#include <asm/io.h>#include <asm/uaccess.h> /* User space memory access functions */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)# ifdef CONFIG_BOARD_S3C2440_SMDK# include <asm/irq.h># include <asm/arch/S3C2440.h># endif#else# ifdef CONFIG_ARCH_S3C2410# include <asm/arch/regs-mem.h># include <asm/arch/regs-irq.h># endif#endif#include "ax88180.h"/* * =========================================================================== * <<<<<< Declare Global Variables >>>>>> * =========================================================================== */#define DRV_NAME "ax88180"#define DRV_VERSION "v1.1.0"static char version[] __initdata = KERN_INFO "ax88180: ASIX AX88180 Non-PCI 32-bit Gigabit Ethernet Driver " DRV_VERSION "\n" KERN_INFO "ax88180: Please visit http://www.asix.com.tw for the latest driver.\n";/* * =========================================================================== * <<<<<< Declare Macro/Structure Definition >>>>>> * =========================================================================== *///allan1/* Information that need to be kept for each board. */struct _AX88180_PRIVATE { struct net_device_stats stats; unsigned long Phy_MemBase; unsigned long PhyAddr; unsigned long PhyID0; unsigned int MediaMode; unsigned int RealMediaMode; unsigned int ForceMedia; unsigned int LineSpeed; unsigned int DuplexMode; unsigned int JumboFlag; unsigned long RxFilterMode; unsigned long FirstTxDesc; unsigned long NextTxDesc; unsigned long rxbuf_overflow_count; unsigned char *rx_buf; spinlock_t lock; struct mii_if_info mii_if;} AX88180_PRIVATE, *PAX88180_PRIVATE;static unsigned long Log_MemBase = 0;unsigned long mem = PLATFORM_MEMBASE; unsigned long irq = PLATFORM_IRQ;unsigned int jumbo = DISABLE_JUMBO; unsigned int media = 0;#define PRINTK(flag, args...) if (flag & DEBUG_FLAGS) printk(args) //Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer#define READ_RXBUF(data) data = *(const volatile unsigned long * const)(Log_MemBase + RXBUFFER_START)#define WRITE_TXBUF(data) *(volatile unsigned long *)(Log_MemBase + TXBUFFER_START) = data#define READ_MACREG(regaddr, regdata) regdata = *(volatile unsigned long *)(Log_MemBase + regaddr)#define WRITE_MACREG(regaddr, regdata) { \ *(volatile unsigned long *)(Log_MemBase + regaddr) = regdata; \ }#define READ_PHYREG(phyaddr, regaddr, regdata) { \ unsigned long tmpval1, k1; \ WRITE_MACREG(MDIOCTRL, READ_PHY | (regaddr << 8) | phyaddr); \ for (k1 = 0; k1 < 10000; k1++) { \ READ_MACREG(MDIOCTRL, tmpval1); \ if ((tmpval1 & READ_PHY) == 0) { \ break; \ } \ udelay(1); \ } \ READ_MACREG(MDIODP, regdata); \}#define WRITE_PHYREG(phyaddr, regaddr, regdata) { \ unsigned long tmpval2, k2; \ WRITE_MACREG(MDIODP, regdata); \ WRITE_MACREG(MDIOCTRL, WRITE_PHY | (regaddr << 8) | phyaddr); \ for (k2 = 0; k2 < 10000; k2++) { \ READ_MACREG(MDIOCTRL, tmpval2); \ if ((tmpval2 & WRITE_PHY) == 0) { \ break; \ } \ udelay(1); \ } \}#define RESET_MAC { \ unsigned long tmpval3; \ WRITE_MACREG(MISC, MISC_RESET_MAC); \ READ_MACREG(MISC, tmpval3); \ WRITE_MACREG(MISC, MISC_NORMAL); \ WRITE_MACREG(RXINDICATOR, DEFAULT_RXINDICATOR); \ WRITE_MACREG(TXCMD, DEFAULT_TXCMD); \ WRITE_MACREG(TXBS, DEFAULT_TXBS); \ WRITE_MACREG(TXDES0, DEFAULT_TXDES0); \ WRITE_MACREG(TXDES1, DEFAULT_TXDES1); \ WRITE_MACREG(TXDES2, DEFAULT_TXDES2); \ WRITE_MACREG(TXDES3, DEFAULT_TXDES3); \ WRITE_MACREG(TXCFG, DEFAULT_TXCFG); \ WRITE_MACREG(MACCFG2, DEFAULT_MACCFG2); \ WRITE_MACREG(MACCFG3, DEFAULT_MACCFG3); \ WRITE_MACREG(TXLEN, DEFAULT_TXLEN); \ WRITE_MACREG(TXPAUT, DEFAULT_TXPAUT); \ WRITE_MACREG(RXBTHD0, DEFAULT_RXBTHD0); \ WRITE_MACREG(RXBTHD1, DEFAULT_RXBTHD1); \ WRITE_MACREG(RXFULTHD, DEFAULT_RXFULTHD); \ WRITE_MACREG(DOGTHD0, DEFAULT_DOGTHD0); \ WRITE_MACREG(DOGTHD1, DEFAULT_DOGTHD1); \}#define RESET_PHY { \ unsigned long tmpval3a, k3a; \ WRITE_PHYREG(pax88180_local->PhyAddr, BMCR, PHY_RESET); \ for (k3a = 0; k3a < 500; k3a++) { \ READ_PHYREG(pax88180_local->PhyAddr, BMCR, tmpval3a); \ if (!(tmpval3a & PHY_RESET)) \ break; \ mdelay(1); \ } \}#define INIT_TXRX_VARIABLES { \ pax88180_local->FirstTxDesc = TXDP0; \ pax88180_local->NextTxDesc = TXDP0; \ pax88180_local->rxbuf_overflow_count = 0; \}#define ENABLE_INTERRUPT WRITE_MACREG(IMR, DEFAULT_IMR)#define DISABLE_INTERRUPT WRITE_MACREG(IMR, CLEAR_IMR)#define START_READ_RXBUFF WRITE_MACREG(RXINDICATOR, RX_START_READ)#define STOP_READ_RXBUFF WRITE_MACREG(RXINDICATOR, RX_STOP_READ)/* Display all AX88180 MAC registers onto console screen */#define DISPLAY_ALLMACREG { \ unsigned long tmpval4; \ int k4; \ PRINTK(DEBUG_MSG, "ax88180: AX88180 MAC Registers:\n"); \ for (k4 = 0xFC00; k4 <= 0xFCFF; k4+=4) { \ READ_MACREG(k4, tmpval4); \ PRINTK(DEBUG_MSG, "0x%04x=0x%08lx ", k4, tmpval4); \ if ((k4 & 0xF) == 0xC) \ PRINTK(DEBUG_MSG, "\n"); \ } \ PRINTK(DEBUG_MSG, "\n"); \}//allan3/* Display all AX88180 PHY registers onto console screen */#define DISPLAY_ALLPHYREG { \ unsigned long tmpval5; \ PRINTK(DEBUG_MSG, "ax88180: AX88180 PHY Registers: (media=%d)\n", media); \ READ_PHYREG(pax88180_local->PhyAddr, BMCR, tmpval5); \ PRINTK(DEBUG_MSG, "BMCR=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, BMSR, tmpval5); \ PRINTK(DEBUG_MSG, "BMSR=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, PHYIDR0, tmpval5); \ PRINTK(DEBUG_MSG, "PHYIDR0=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, PHYIDR1, tmpval5); \ PRINTK(DEBUG_MSG, "PHYIDR1=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, ANAR, tmpval5); \ PRINTK(DEBUG_MSG, "ANAR=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, ANLPAR, tmpval5); \ PRINTK(DEBUG_MSG, "ANLPAR=0x%04x \n", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, ANER, tmpval5); \ PRINTK(DEBUG_MSG, "ANER=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, AUX_1000_CTRL, tmpval5); \ PRINTK(DEBUG_MSG, "1G_CTRL=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, AUX_1000_STATUS, tmpval5); \ PRINTK(DEBUG_MSG, "1G_STATUS=0x%04x \n", (unsigned int)tmpval5); \ if (pax88180_local->PhyID0 == MARVELL_88E1111_PHYIDR0) { \ READ_PHYREG(pax88180_local->PhyAddr, M88_SSR, tmpval5); \ PRINTK(DEBUG_MSG, "M88_SSR=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, M88_IER, tmpval5); \ PRINTK(DEBUG_MSG, "M88_IER=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, M88_ISR, tmpval5); \ PRINTK(DEBUG_MSG, "M88_ISR=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, M88_EXT_SCR, tmpval5); \ PRINTK(DEBUG_MSG, "M88_EXT_SCR=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, M88_EXT_SSR, tmpval5); \ PRINTK(DEBUG_MSG, "M88_EXT_SSR=0x%04x \n", (unsigned int)tmpval5); \ } else if (pax88180_local->PhyID0 == CICADA_CIS8201_PHYIDR0) { \ READ_PHYREG(pax88180_local->PhyAddr, CIS_IMR, tmpval5); \ PRINTK(DEBUG_MSG, "CIS_IMR=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, CIS_ISR, tmpval5); \ PRINTK(DEBUG_MSG, "CIS_ISR=0x%04x ", (unsigned int)tmpval5); \ READ_PHYREG(pax88180_local->PhyAddr, CIS_AUX_CTRL_STATUS, tmpval5); \ PRINTK(DEBUG_MSG, "CIS_AUX=0x%04x \n", (unsigned int)tmpval5); \ } \ READ_MACREG(RXCFG, tmpval5); \ PRINTK(DEBUG_MSG, "RXCFG=0x%08lx ", tmpval5); \ READ_MACREG(MACCFG0, tmpval5); \ PRINTK(DEBUG_MSG, "MACCFG0=0x%08lx ", tmpval5); \ READ_MACREG(MACCFG1, tmpval5); \ PRINTK(DEBUG_MSG, "MACCFG1=0x%08lx ", tmpval5); \ READ_MACREG(MACCFG2, tmpval5); \ PRINTK(DEBUG_MSG, "MACCFG2=0x%08lx \n\n", tmpval5); \} /* Index to functions, as function prototypes. */extern int __init ax88180_probe(struct net_device *global_dev);static int ax88180_open(struct net_device *global_dev);static int ax88180_stop(struct net_device *global_dev);static int ax88180_start_xmit(struct sk_buff *skb, struct net_device *global_dev);static void ax88180_tx_timeout(struct net_device *global_dev);static struct net_device_stats * ax88180_get_stats(struct net_device *global_dev);static void ax88180_set_multicast_list(struct net_device *global_dev);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)#ifdef CONFIG_BOARD_S3C2440_SMDKint set_external_irq(int irq, int edge, int pullup);#endifstatic void ax88180_interrupt(int irq, void *global_dev_id, struct pt_regs * regs);#elsestatic irqreturn_t ax88180_interrupt(int irq, void *global_dev_id, struct pt_regs * regs);#endifstatic int ax88180_initialization(struct net_device *global_dev);static void ax88180_PHY_initial(struct net_device *global_dev);static void ax88180_meida_config(struct net_device *global_dev);static void get_MarvellPHY_meida_mode(struct net_device *global_dev);static void get_CicadaPHY_meida_mode(struct net_device *global_dev);static void ax88180_rx_handler(struct net_device *global_dev);static void ax88180_tx_handler(struct net_device *global_dev);#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)static int ax88180_ioctl(struct net_device *global_dev, struct ifreq *rq, int cmd);static int ax88180_ethtool_ioctl(struct net_device *global_dev, void *useraddr);static int mdio_read(struct net_device *global_dev, int phy_id, int regaddr);static void mdio_write(struct net_device *global_dev, int phy_id, int regaddr, int regval);#endifint set_external_irq(int irq, int edge, int pullup);/* * =========================================================================== * <<<<<< MODULE-ROUTINES >>>>>> * =========================================================================== */#ifdef MODULEMODULE_AUTHOR("Allan Chou <allan@asix.com.tw>");MODULE_DESCRIPTION("ASIX AX88180 Non-PCI 32-bit Gigabit Ethernet Driver");MODULE_LICENSE("GPL");/* ***************************************************************************** * AX88180 module mode driver optional parameters: * Syntax: insmod ax88180.o mem=0xXXXXXXXX irq=0xXX media=<media_type> jumbo=x * mem Set memory base address (default is 0x08000000) * irq Set IRQ number (default is 0x27) * media Set media mode (0:auto, 1:100full, 2:100half, 3:10full 4:10half) * jumbo Enable/disable Jumbo frame (1=enable, 0=disable)(default is 0) * * example: insmod ax88180.o mem=0x08000000 irq=0x27 media=auto jumbo=0 * ***************************************************************************** */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)MODULE_PARM(media, "i");MODULE_PARM(mem, "i");MODULE_PARM(irq, "i");MODULE_PARM(jumbo, "i");#elsemodule_param(media, int, 0);module_param(jumbo, int, 0);module_param(mem, long, 0);module_param(irq, long, 0);#endifMODULE_PARM_DESC(media, "Media Mode(auto, 100full, 100half, 10full or 10half)");MODULE_PARM_DESC(mem, "Memory Base Address");MODULE_PARM_DESC(irq, "Interrupt Number");MODULE_PARM_DESC(jumbo, "Jumbo Frame(1=enable, 0=disable");static struct net_device dev_ax;static int __init ax88180_init_module(void);static void __exit ax88180_cleanup_module(void);module_init(ax88180_init_module);module_exit(ax88180_cleanup_module);/* ***************************************************************************** * ax88180_init_module() * * Check for a network adaptor of this type, and return '0' if one exists. * * Return 0 on success. ***************************************************************************** */static int __init ax88180_init_module(void){ static struct net_device *global_dev; PRINTK(INIT_MSG, "ax88180: ax88180_init_module beginning ..........\n"); global_dev = &dev_ax; global_dev->irq = irq; global_dev->base_addr = mem; global_dev->init = ax88180_probe; if(register_netdev(global_dev) == 0) { PRINTK(INIT_MSG, "ax88180: ax88180_init_module end ..........\n"); return 0; } if (mem != 0) { PRINTK(WARNING_MSG, "AX88180: No AX88180 card found at memory = %#lx\n", mem); } else { PRINTK(WARNING_MSG, "AX88180: You must supply \"mem=0xNNNNNNN\" value(s) for AX88180.\n"); } return -ENXIO;}/* ***************************************************************************** * ax88180_cleanup_module() ***************************************************************************** */static void __exit ax88180_cleanup_module(void){ struct _AX88180_PRIVATE *pax88180_local; static struct net_device *global_dev = &dev_ax; PRINTK(INIT_MSG, "ax88180: ax88180_cleanup_module beginning ..........\n"); pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; if (global_dev != NULL) { unregister_netdev(global_dev); free_irq(global_dev->irq, global_dev); } if (Log_MemBase != 0) { iounmap((void *)Log_MemBase); } if (pax88180_local != NULL) { if (pax88180_local->Phy_MemBase != 0) { release_mem_region(pax88180_local->Phy_MemBase, AX88180_MEMORY_SIZE); } kfree(global_dev->priv); global_dev->priv = NULL; } PRINTK(INIT_MSG, "ax88180: ax88180_cleanup_module end ..........\n"); return;}#endif/* * =========================================================================== * <<<<<< MAIN-ROUTINES >>>>>> * =========================================================================== *//* ***************************************************************************** * ax88180_probe() * * This is the entry routine for kernel mode driver. This routine will probe * the AX88180 device and allocate a (64K bytes + private data structure size) * memory space for AX88180 operation. * * AX88180 32-bit memory mapping: * ============================== * 0x0000~0x3FFF RX buffer area * 0x4000~0xFBFF TX buffer area
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -