📄 au1000_eth.c
字号:
/* * * 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. * * ######################################################################## * * */#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 <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 int __init au1000_probe1(struct net_device *, 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 void 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 void cleanup_buffers(struct net_device *);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 inline void sync(void);extern void ack_rise_edge_irq(unsigned int);static int next_dev;/* * 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 interupt of the Au1000 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}};static char version[] __devinitdata = "au1000eth.c:0.1 ppopov@mvista.com\n";// FIX! Need real Ethernet addressesstatic unsigned char au1000_mac_addr[2][6] __devinitdata = { {0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00}, {0x00, 0x50, 0xc2, 0x0c, 0x40, 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/* CPU pipeline flush */static inline void sync(void){ asm volatile ("sync");}/* FIXME * All of the PHY code really should be detached from the MAC * code. */static char *phy_link[] = {"unknown", "10Base2", "10BaseT", "AUI", "100BaseT", "100BaseTX", "100BaseFX"};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); //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; } 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,};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 }, {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 accessable, 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 found at phy address %d\n", dev->name, mii_chip_table[i].name, phy_addr); if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { mii_phy->chip_info = mii_chip_table+i; mii_phy->phy_addr = phy_addr; //mii_phy->status = mdio_read(dev, phy_addr, MII_STATUS); mii_phy->next = aup->mii; aup->phy_ops = mii_chip_table[i].phy_ops; aup->mii = mii_phy; } /* the current mii is on our mii_info_table, try next address */ break; } } if (aup->mii == NULL) { printk(KERN_ERR "%s: No MII transceivers found!\n", dev->name); return -1; } /* use last PHY */ aup->phy_addr = aup->mii->phy_addr; printk(KERN_INFO "%s: Using %s as default\n", dev->name, aup->mii->chip_info->name); return 0;}/* * Buffer allocation/deallocation routines. The buffer descriptor returned * has the virtual and dma address of a buffer suitable for * both, receive and transmit operations. */static db_dest_t *GetFreeDB(struct au1000_private *aup){ db_dest_t *pDB; pDB = aup->pDBfree; if (pDB) { aup->pDBfree = pDB->pnext; } //printk("GetFreeDB: %x\n", pDB); return pDB;}void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB){ db_dest_t *pDBfree = aup->pDBfree; if (pDBfree) pDBfree->pnext = pDB; aup->pDBfree = pDB;}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -