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

📄 fec_mii.c

📁 linux-2.6.15.6
💻 C
字号:
/* * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. * * Copyright (c) 2003 Intracom S.A.  *  by Pantelis Antoniou <panto@intracom.gr> * * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com> * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se> * * Released under the GPL */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/spinlock.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/bitops.h>#include <asm/8xx_immap.h>#include <asm/pgtable.h>#include <asm/mpc8xx.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/commproc.h>/*************************************************/#include "fec_8xx.h"/*************************************************//* Make MII read/write commands for the FEC.*/#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))#define mk_mii_end		0/*************************************************//* XXX both FECs use the MII interface of FEC1 */static DEFINE_SPINLOCK(fec_mii_lock);#define FEC_MII_LOOPS	10000int fec_mii_read(struct net_device *dev, int phy_id, int location){	struct fec_enet_private *fep = netdev_priv(dev);	fec_t *fecp;	int i, ret = -1;	unsigned long flags;	/* XXX MII interface is only connected to FEC1 */	fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;	spin_lock_irqsave(&fec_mii_lock, flags);	if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {		FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */		FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);		FW(fecp, ievent, FEC_ENET_MII);	}	/* Add PHY address to register command.  */	FW(fecp, mii_speed, fep->fec_phy_speed);	FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));	for (i = 0; i < FEC_MII_LOOPS; i++)		if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)			break;	if (i < FEC_MII_LOOPS) {		FW(fecp, ievent, FEC_ENET_MII);		ret = FR(fecp, mii_data) & 0xffff;	}	spin_unlock_irqrestore(&fec_mii_lock, flags);	return ret;}void fec_mii_write(struct net_device *dev, int phy_id, int location, int value){	struct fec_enet_private *fep = netdev_priv(dev);	fec_t *fecp;	unsigned long flags;	int i;	/* XXX MII interface is only connected to FEC1 */	fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;	spin_lock_irqsave(&fec_mii_lock, flags);	if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {		FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */		FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);		FW(fecp, ievent, FEC_ENET_MII);	}	/* Add PHY address to register command.  */	FW(fecp, mii_speed, fep->fec_phy_speed);	/* always adapt mii speed */	FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));	for (i = 0; i < FEC_MII_LOOPS; i++)		if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)			break;	if (i < FEC_MII_LOOPS)		FW(fecp, ievent, FEC_ENET_MII);	spin_unlock_irqrestore(&fec_mii_lock, flags);}/*************************************************/#ifdef CONFIG_FEC_8XX_GENERIC_PHY/* * Generic PHY support. * Should work for all PHYs, but link change is detected by polling */static void generic_timer_callback(unsigned long data){	struct net_device *dev = (struct net_device *)data;	struct fec_enet_private *fep = netdev_priv(dev);	fep->phy_timer_list.expires = jiffies + HZ / 2;	add_timer(&fep->phy_timer_list);	fec_mii_link_status_change_check(dev, 0);}static void generic_startup(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fep->phy_timer_list.expires = jiffies + HZ / 2;	/* every 500ms */	fep->phy_timer_list.data = (unsigned long)dev;	fep->phy_timer_list.function = generic_timer_callback;	add_timer(&fep->phy_timer_list);}static void generic_shutdown(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	del_timer_sync(&fep->phy_timer_list);}#endif#ifdef CONFIG_FEC_8XX_DM9161_PHY/* ------------------------------------------------------------------------- *//* The Davicom DM9161 is used on the NETTA board			     *//* register definitions */#define MII_DM9161_ACR		16	/* Aux. Config Register         */#define MII_DM9161_ACSR		17	/* Aux. Config/Status Register  */#define MII_DM9161_10TCSR	18	/* 10BaseT Config/Status Reg.   */#define MII_DM9161_INTR		21	/* Interrupt Register           */#define MII_DM9161_RECR		22	/* Receive Error Counter Reg.   */#define MII_DM9161_DISCR	23	/* Disconnect Counter Register  */static void dm9161_startup(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);}static void dm9161_ack_int(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fec_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);}static void dm9161_shutdown(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);}#endif#ifdef CONFIG_FEC_8XX_LXT971_PHY/* Support for LXT971/972 PHY */#define MII_LXT971_PCR		16 /* Port Control Register */#define MII_LXT971_SR2		17 /* Status Register 2 */#define MII_LXT971_IER		18 /* Interrupt Enable Register */#define MII_LXT971_ISR		19 /* Interrupt Status Register */#define MII_LXT971_LCR		20 /* LED Control Register */#define MII_LXT971_TCR		30 /* Transmit Control Register */static void lxt971_startup(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x00F2);}static void lxt971_ack_int(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fec_mii_read(dev, fep->mii_if.phy_id, MII_LXT971_ISR);}static void lxt971_shutdown(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x0000);}#endif/**********************************************************************************/static const struct phy_info phy_info[] = {#ifdef CONFIG_FEC_8XX_DM9161_PHY	{	 .id = 0x00181b88,	 .name = "DM9161",	 .startup = dm9161_startup,	 .ack_int = dm9161_ack_int,	 .shutdown = dm9161_shutdown,	 },#endif#ifdef CONFIG_FEC_8XX_LXT971_PHY	{	 .id = 0x0001378e,	 .name = "LXT971/972",	 .startup = lxt971_startup,	 .ack_int = lxt971_ack_int,	 .shutdown = lxt971_shutdown,	},#endif#ifdef CONFIG_FEC_8XX_GENERIC_PHY	{	 .id = 0,	 .name = "GENERIC",	 .startup = generic_startup,	 .shutdown = generic_shutdown,	 },#endif};/**********************************************************************************/int fec_mii_phy_id_detect(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	const struct fec_platform_info *fpi = fep->fpi;	int i, r, start, end, phytype, physubtype;	const struct phy_info *phy;	int phy_hwid, phy_id;	/* if no MDIO */	if (fpi->use_mdio == 0)		return -1;	phy_hwid = -1;	fep->phy = NULL;	/* auto-detect? */	if (fpi->phy_addr == -1) {		start = 0;		end = 32;	} else {		/* direct */		start = fpi->phy_addr;		end = start + 1;	}	for (phy_id = start; phy_id < end; phy_id++) {		r = fec_mii_read(dev, phy_id, MII_PHYSID1);		if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)			continue;		r = fec_mii_read(dev, phy_id, MII_PHYSID2);		if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)			continue;		phy_hwid = (phytype << 16) | physubtype;		if (phy_hwid != -1)			break;	}	if (phy_hwid == -1) {		printk(KERN_ERR DRV_MODULE_NAME		       ": %s No PHY detected!\n", dev->name);		return -1;	}	for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]);	     i++, phy++)		if (phy->id == (phy_hwid >> 4) || phy->id == 0)			break;	if (i >= sizeof(phy_info) / sizeof(phy_info[0])) {		printk(KERN_ERR DRV_MODULE_NAME		       ": %s PHY id 0x%08x is not supported!\n",		       dev->name, phy_hwid);		return -1;	}	fep->phy = phy;	printk(KERN_INFO DRV_MODULE_NAME	       ": %s Phy @ 0x%x, type %s (0x%08x)\n",	       dev->name, phy_id, fep->phy->name, phy_hwid);	return phy_id;}void fec_mii_startup(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	const struct fec_platform_info *fpi = fep->fpi;	if (!fpi->use_mdio || fep->phy == NULL)		return;	if (fep->phy->startup == NULL)		return;	(*fep->phy->startup) (dev);}void fec_mii_shutdown(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	const struct fec_platform_info *fpi = fep->fpi;	if (!fpi->use_mdio || fep->phy == NULL)		return;	if (fep->phy->shutdown == NULL)		return;	(*fep->phy->shutdown) (dev);}void fec_mii_ack_int(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	const struct fec_platform_info *fpi = fep->fpi;	if (!fpi->use_mdio || fep->phy == NULL)		return;	if (fep->phy->ack_int == NULL)		return;	(*fep->phy->ack_int) (dev);}/* helper function */static int mii_negotiated(struct mii_if_info *mii){	int advert, lpa, val;	if (!mii_link_ok(mii))		return 0;	val = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_BMSR);	if ((val & BMSR_ANEGCOMPLETE) == 0)		return 0;	advert = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_ADVERTISE);	lpa = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_LPA);	return mii_nway_result(advert & lpa);}void fec_mii_link_status_change_check(struct net_device *dev, int init_media){	struct fec_enet_private *fep = netdev_priv(dev);	unsigned int media;	unsigned long flags;	if (mii_check_media(&fep->mii_if, netif_msg_link(fep), init_media) == 0)		return;	media = mii_negotiated(&fep->mii_if);	if (netif_carrier_ok(dev)) {		spin_lock_irqsave(&fep->lock, flags);		fec_restart(dev, !!(media & ADVERTISE_FULL),			    (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) ?			    100 : 10);		spin_unlock_irqrestore(&fep->lock, flags);		netif_start_queue(dev);	} else {		netif_stop_queue(dev);		spin_lock_irqsave(&fep->lock, flags);		fec_stop(dev);		spin_unlock_irqrestore(&fep->lock, flags);	}}

⌨️ 快捷键说明

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