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

📄 fcc_enet.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net) * * This version of the driver is a combination of the 8xx fec and * 8260 SCC Ethernet drivers.  This version has some additional * configuration options, which should probably be moved out of * here.  This driver currently works for the EST SBC8260, * SBS Diablo/BCM, Embedded Planet RPX6, TQM8260, and others. * * Right now, I am very watseful with the buffers.  I allocate memory * pages and then divide them into 2K frame buffers.  This way I know I * have buffers large enough to hold one frame within one buffer descriptor. * Once I get this working, I will use 64 or 128 byte CPM buffers, which * will be much more memory efficient and will easily handle lots of * small packets.  Since this is a cache coherent processor and CPM, * I could also preallocate SKB's and use them directly on the interface. * * 2004-12	Leo Li (leoli@freescale.com) * - Rework the FCC clock configuration part, make it easier to configure. * */#include <linux/config.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/workqueue.h>#include <linux/bitops.h>#include <asm/immap_cpm2.h>#include <asm/pgtable.h>#include <asm/mpc8260.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/signal.h>/* We can't use the PHY interrupt if we aren't using MDIO. */#if !defined(CONFIG_USE_MDIO)#undef PHY_INTERRUPT#endif/* If we have a PHY interrupt, we will advertise both full-duplex and half- * duplex capabilities.  If we don't have a PHY interrupt, then we will only * advertise half-duplex capabilities. */#define MII_ADVERTISE_HALF	(ADVERTISE_100HALF | ADVERTISE_10HALF | \				 ADVERTISE_CSMA)#define MII_ADVERTISE_ALL	(ADVERTISE_100FULL | ADVERTISE_10FULL | \				 MII_ADVERTISE_HALF)#ifdef PHY_INTERRUPT#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_ALL#else#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_HALF#endif#include <asm/cpm2.h>/* The transmitter timeout */#define TX_TIMEOUT	(2*HZ)#ifdef	CONFIG_USE_MDIO/* Forward declarations of some structures to support different PHYs */typedef struct {	uint mii_data;	void (*funct)(uint mii_reg, struct net_device *dev);} phy_cmd_t;typedef struct {	uint id;	char *name;	const phy_cmd_t *config;	const phy_cmd_t *startup;	const phy_cmd_t *ack_int;	const phy_cmd_t *shutdown;} phy_info_t;/* values for phy_status */#define PHY_CONF_ANE	0x0001  /* 1 auto-negotiation enabled */#define PHY_CONF_LOOP	0x0002  /* 1 loopback mode enabled */#define PHY_CONF_SPMASK	0x00f0  /* mask for speed */#define PHY_CONF_10HDX	0x0010  /* 10 Mbit half duplex supported */#define PHY_CONF_10FDX	0x0020  /* 10 Mbit full duplex supported */#define PHY_CONF_100HDX	0x0040  /* 100 Mbit half duplex supported */#define PHY_CONF_100FDX	0x0080  /* 100 Mbit full duplex supported */#define PHY_STAT_LINK	0x0100  /* 1 up - 0 down */#define PHY_STAT_FAULT	0x0200  /* 1 remote fault */#define PHY_STAT_ANC	0x0400  /* 1 auto-negotiation complete	*/#define PHY_STAT_SPMASK	0xf000  /* mask for speed */#define PHY_STAT_10HDX	0x1000  /* 10 Mbit half duplex selected	*/#define PHY_STAT_10FDX	0x2000  /* 10 Mbit full duplex selected	*/#define PHY_STAT_100HDX	0x4000  /* 100 Mbit half duplex selected */#define PHY_STAT_100FDX	0x8000  /* 100 Mbit full duplex selected */#endif	/* CONFIG_USE_MDIO *//* The number of Tx and Rx buffers.  These are allocated from the page * pool.  The code may assume these are power of two, so it is best * to keep them that size. * We don't need to allocate pages for the transmitter.  We just use * the skbuffer directly. */#define FCC_ENET_RX_PAGES	16#define FCC_ENET_RX_FRSIZE	2048#define FCC_ENET_RX_FRPPG	(PAGE_SIZE / FCC_ENET_RX_FRSIZE)#define RX_RING_SIZE		(FCC_ENET_RX_FRPPG * FCC_ENET_RX_PAGES)#define TX_RING_SIZE		16	/* Must be power of two */#define TX_RING_MOD_MASK	15	/*   for this to work *//* The FCC stores dest/src/type, data, and checksum for receive packets. * size includes support for VLAN */#define PKT_MAXBUF_SIZE		1522#define PKT_MINBUF_SIZE		64/* Maximum input DMA size.  Must be a should(?) be a multiple of 4. * size includes support for VLAN */#define PKT_MAXDMA_SIZE		1524/* Maximum input buffer size.  Must be a multiple of 32.*/#define PKT_MAXBLR_SIZE		1536static int fcc_enet_open(struct net_device *dev);static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);static int fcc_enet_rx(struct net_device *dev);static irqreturn_t fcc_enet_interrupt(int irq, void *dev_id, struct pt_regs *);static int fcc_enet_close(struct net_device *dev);static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev);/* static void set_multicast_list(struct net_device *dev); */static void fcc_restart(struct net_device *dev, int duplex);static void fcc_stop(struct net_device *dev);static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);/* These will be configurable for the FCC choice. * Multiple ports can be configured.  There is little choice among the * I/O pins to the PHY, except the clocks.  We will need some board * dependent clock selection. * Why in the hell did I put these inside #ifdef's?  I dunno, maybe to * help show what pins are used for each device. *//* Since the CLK setting changes greatly from board to board, I changed * it to a easy way.  You just need to specify which CLK number to use. * Note that only limited choices can be make on each port. *//* FCC1 Clock Source Configuration.  There are board specific.   Can only choose from CLK9-12 */#ifdef CONFIG_SBC82xx#define F1_RXCLK	9#define F1_TXCLK	10#elif defined(CONFIG_ADS8272)#define F1_RXCLK	11#define F1_TXCLK	10#else#define F1_RXCLK	12#define F1_TXCLK	11#endif/* FCC2 Clock Source Configuration.  There are board specific.   Can only choose from CLK13-16 */#ifdef CONFIG_ADS8272#define F2_RXCLK	15#define F2_TXCLK	16#else#define F2_RXCLK	13#define F2_TXCLK	14#endif/* FCC3 Clock Source Configuration.  There are board specific.   Can only choose from CLK13-16 */#define F3_RXCLK	15#define F3_TXCLK	16/* Automatically generates register configurations */#define PC_CLK(x)	((uint)(1<<(x-1)))	/* FCC CLK I/O ports */#define CMXFCR_RF1CS(x)	((uint)((x-5)<<27))	/* FCC1 Receive Clock Source */#define CMXFCR_TF1CS(x)	((uint)((x-5)<<24))	/* FCC1 Transmit Clock Source */#define CMXFCR_RF2CS(x)	((uint)((x-9)<<19))	/* FCC2 Receive Clock Source */#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16))	/* FCC2 Transmit Clock Source */#define CMXFCR_RF3CS(x)	((uint)((x-9)<<11))	/* FCC3 Receive Clock Source */#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8))	/* FCC3 Transmit Clock Source */#define PC_F1RXCLK	PC_CLK(F1_RXCLK)#define PC_F1TXCLK	PC_CLK(F1_TXCLK)#define CMX1_CLK_ROUTE	(CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK))#define CMX1_CLK_MASK	((uint)0xff000000)#define PC_F2RXCLK	PC_CLK(F2_RXCLK)#define PC_F2TXCLK	PC_CLK(F2_TXCLK)#define CMX2_CLK_ROUTE	(CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK))#define CMX2_CLK_MASK	((uint)0x00ff0000)#define PC_F3RXCLK	PC_CLK(F3_RXCLK)#define PC_F3TXCLK	PC_CLK(F3_TXCLK)#define CMX3_CLK_ROUTE	(CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK))#define CMX3_CLK_MASK	((uint)0x0000ff00)/* I/O Pin assignment for FCC1.  I don't yet know the best way to do this, * but there is little variation among the choices. */#define PA1_COL		((uint)0x00000001)#define PA1_CRS		((uint)0x00000002)#define PA1_TXER	((uint)0x00000004)#define PA1_TXEN	((uint)0x00000008)#define PA1_RXDV	((uint)0x00000010)#define PA1_RXER	((uint)0x00000020)#define PA1_TXDAT	((uint)0x00003c00)#define PA1_RXDAT	((uint)0x0003c000)#define PA1_PSORA_BOUT	(PA1_RXDAT | PA1_TXDAT)#define PA1_PSORA_BIN	(PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \				PA1_RXDV | PA1_RXER)#define PA1_DIRA_BOUT	(PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)#define PA1_DIRA_BIN	(PA1_TXDAT | PA1_TXEN | PA1_TXER)/* I/O Pin assignment for FCC2.  I don't yet know the best way to do this, * but there is little variation among the choices. */#define PB2_TXER	((uint)0x00000001)#define PB2_RXDV	((uint)0x00000002)#define PB2_TXEN	((uint)0x00000004)#define PB2_RXER	((uint)0x00000008)#define PB2_COL		((uint)0x00000010)#define PB2_CRS		((uint)0x00000020)#define PB2_TXDAT	((uint)0x000003c0)#define PB2_RXDAT	((uint)0x00003c00)#define PB2_PSORB_BOUT	(PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \				PB2_RXER | PB2_RXDV | PB2_TXER)#define PB2_PSORB_BIN	(PB2_TXEN)#define PB2_DIRB_BOUT	(PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)#define PB2_DIRB_BIN	(PB2_TXDAT | PB2_TXEN | PB2_TXER)/* I/O Pin assignment for FCC3.  I don't yet know the best way to do this, * but there is little variation among the choices. */#define PB3_RXDV	((uint)0x00004000)#define PB3_RXER	((uint)0x00008000)#define PB3_TXER	((uint)0x00010000)#define PB3_TXEN	((uint)0x00020000)#define PB3_COL		((uint)0x00040000)#define PB3_CRS		((uint)0x00080000)#ifndef CONFIG_RPX8260#define PB3_TXDAT	((uint)0x0f000000)#define PC3_TXDAT	((uint)0x00000000)#else#define PB3_TXDAT	((uint)0x0f000000)#define PC3_TXDAT	0#endif#define PB3_RXDAT	((uint)0x00f00000)#define PB3_PSORB_BOUT	(PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \				PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN)#define PB3_PSORB_BIN	(0)#define PB3_DIRB_BOUT	(PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)#define PB3_DIRB_BIN	(PB3_TXDAT | PB3_TXEN | PB3_TXER)#define PC3_PSORC_BOUT	(PC3_TXDAT)#define PC3_PSORC_BIN	(0)#define PC3_DIRC_BOUT	(0)#define PC3_DIRC_BIN	(PC3_TXDAT)/* MII status/control serial interface.*/#if defined(CONFIG_RPX8260)/* The EP8260 doesn't use Port C for MDIO */#define PC_MDIO		((uint)0x00000000)#define PC_MDCK		((uint)0x00000000)#elif defined(CONFIG_TQM8260)/* TQM8260 has MDIO and MDCK on PC30 and PC31 respectively */#define PC_MDIO		((uint)0x00000002)#define PC_MDCK		((uint)0x00000001)#elif defined(CONFIG_ADS8272)#define PC_MDIO		((uint)0x00002000)#define PC_MDCK		((uint)0x00001000)#elif defined(CONFIG_EST8260) || defined(CONFIG_ADS8260) || defined(CONFIG_PQ2FADS)#define PC_MDIO		((uint)0x00400000)#define PC_MDCK		((uint)0x00200000)#else#define PC_MDIO		((uint)0x00000004)#define PC_MDCK		((uint)0x00000020)#endif#if defined(CONFIG_USE_MDIO) && (!defined(PC_MDIO) || !defined(PC_MDCK))#error "Must define PC_MDIO and PC_MDCK if using MDIO"#endif/* PHY addresses *//* default to dynamic config of phy addresses */#define FCC1_PHY_ADDR 0#ifdef CONFIG_PQ2FADS#define FCC2_PHY_ADDR 0#else#define FCC2_PHY_ADDR 2#endif#define FCC3_PHY_ADDR 3/* A table of information for supporting FCCs.  This does two things. * First, we know how many FCCs we have and they are always externally * numbered from zero.  Second, it holds control register and I/O * information that could be different among board designs. */typedef struct fcc_info {	uint	fc_fccnum;	uint	fc_phyaddr;	uint	fc_cpmblock;	uint	fc_cpmpage;	uint	fc_proff;	uint	fc_interrupt;	uint	fc_trxclocks;	uint	fc_clockroute;	uint	fc_clockmask;	uint	fc_mdio;	uint	fc_mdck;} fcc_info_t;static fcc_info_t fcc_ports[] = {#ifdef CONFIG_FCC1_ENET	{ 0, FCC1_PHY_ADDR, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1,		(PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK,		PC_MDIO, PC_MDCK },#endif#ifdef CONFIG_FCC2_ENET	{ 1, FCC2_PHY_ADDR, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2,		(PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK,		PC_MDIO, PC_MDCK },#endif#ifdef CONFIG_FCC3_ENET	{ 2, FCC3_PHY_ADDR, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3,		(PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK,		PC_MDIO, PC_MDCK },#endif};/* The FCC buffer descriptors track the ring buffers.  The rx_bd_base and * tx_bd_base always point to the base of the buffer descriptors.  The * cur_rx and cur_tx point to the currently available buffer. * The dirty_tx tracks the current buffer that is being sent by the * controller.  The cur_tx and dirty_tx are equal under both completely * empty and completely full conditions.  The empty/ready indicator in * the buffer descriptor determines the actual condition. */struct fcc_enet_private {	/* The saved address of a sent-in-place packet/buffer, for skfree(). */	struct	sk_buff* tx_skbuff[TX_RING_SIZE];	ushort	skb_cur;	ushort	skb_dirty;	/* CPM dual port RAM relative addresses.	*/	cbd_t	*rx_bd_base;		/* Address of Rx and Tx buffers. */	cbd_t	*tx_bd_base;	cbd_t	*cur_rx, *cur_tx;		/* The next free ring entry */	cbd_t	*dirty_tx;	/* The ring entries to be free()ed. */	volatile fcc_t	*fccp;	volatile fcc_enet_t	*ep;	struct	net_device_stats stats;	uint	tx_free;	spinlock_t lock;#ifdef	CONFIG_USE_MDIO	uint	phy_id;	uint	phy_id_done;	uint	phy_status;	phy_info_t	*phy;	struct work_struct phy_relink;	struct work_struct phy_display_config;	uint	sequence_done;	uint	phy_addr;#endif	/* CONFIG_USE_MDIO */	int	link;	int	old_link;	int	full_duplex;	fcc_info_t	*fip;};static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,	volatile cpm2_map_t *immap);static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev);static void init_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io,	volatile cpm2_map_t *immap);static void init_fcc_param(fcc_info_t *fip, struct net_device *dev,	volatile cpm2_map_t *immap);#ifdef	CONFIG_USE_MDIOstatic int	mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *));static uint	mii_send_receive(fcc_info_t *fip, uint cmd);static void	mii_do_cmd(struct net_device *dev, const phy_cmd_t *c);/* Make MII read/write commands for the FCC.*/#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#endif	/* CONFIG_USE_MDIO */static intfcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv;	volatile cbd_t	*bdp;	/* Fill in a Tx ring entry */	bdp = cep->cur_tx;#ifndef final_version	if (!cep->tx_free || (bdp->cbd_sc & BD_ENET_TX_READY)) {		/* Ooops.  All transmit buffers are full.  Bail out.		 * This should not happen, since the tx queue should be stopped.		 */		printk("%s: tx queue full!.\n", dev->name);		return 1;	}#endif	/* Clear all of the status flags. */	bdp->cbd_sc &= ~BD_ENET_TX_STATS;	/* If the frame is short, tell CPM to pad it. */	if (skb->len <= ETH_ZLEN)		bdp->cbd_sc |= BD_ENET_TX_PAD;	else		bdp->cbd_sc &= ~BD_ENET_TX_PAD;	/* Set buffer length and buffer pointer. */	bdp->cbd_datlen = skb->len;	bdp->cbd_bufaddr = __pa(skb->data);	spin_lock_irq(&cep->lock);	/* Save skb pointer. */	cep->tx_skbuff[cep->skb_cur] = skb;	cep->stats.tx_bytes += skb->len;	cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;	/* Send it on its way.  Tell CPM its ready, interrupt when done,	 * its the last BD of the frame, and to put the CRC on the end.	 */	bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC);#if 0	/* Errata says don't do this. */	cep->fccp->fcc_ftodr = 0x8000;#endif	dev->trans_start = jiffies;	/* If this was the last BD in the ring, start at the beginning again. */

⌨️ 快捷键说明

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