gianfar.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,865 行 · 第 1/4 页

C
1,865
字号
/*  * drivers/net/gianfar.c * * Gianfar Ethernet Driver * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 * Based on 8260_io/fcc_enet.c * * Author: Andy Fleming * Maintainer: Kumar Gala (kumar.gala@freescale.com) * * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute  it and/or modify it * under  the terms of  the GNU General  Public License as published by the * Free Software Foundation;  either version 2 of the  License, or (at your * option) any later version. * *  Gianfar:  AKA Lambda Draconis, "Dragon" *  RA 11 31 24.2 *  Dec +69 19 52 *  V 3.84 *  B-V +1.62 * *  Theory of operation *  This driver is designed for the Triple-speed Ethernet *  controllers on the Freescale 8540/8560 integrated processors, *  as well as the Fast Ethernet Controller on the 8540.   *   *  The driver is initialized through OCP.  Structures which *  define the configuration needed by the board are defined in a *  board structure in arch/ppc/platforms (though I do not *  discount the possibility that other architectures could one *  day be supported.  One assumption the driver currently makes *  is that the PHY is configured in such a way to advertise all *  capabilities.  This is a sensible default, and on certain *  PHYs, changing this default encounters substantial errata *  issues.  Future versions may remove this requirement, but for *  now, it is best for the firmware to ensure this is the case. * *  The Gianfar Ethernet Controller uses a ring of buffer *  descriptors.  The beginning is indicated by a register *  pointing to the physical address of the start of the ring.  *  The end is determined by a "wrap" bit being set in the  *  last descriptor of the ring. * *  When a packet is received, the RXF bit in the *  IEVENT register is set, triggering an interrupt when the  *  corresponding bit in the IMASK register is also set (if *  interrupt coalescing is active, then the interrupt may not *  happen immediately, but will wait until either a set number *  of frames or amount of time have passed.).  In NAPI, the *  interrupt handler will signal there is work to be done, and *  exit.  Without NAPI, the packet(s) will be handled *  immediately.  Both methods will start at the last known empty *  descriptor, and process every subsequent descriptor until there  *  are none left with data (NAPI will stop after a set number of *  packets to give time to other tasks, but will eventually *  process all the packets).  The data arrives inside a *  pre-allocated skb, and so after the skb is passed up to the *  stack, a new skb must be allocated, and the address field in *  the buffer descriptor must be updated to indicate this new *  skb. * *  When the kernel requests that a packet be transmitted, the *  driver starts where it left off last time, and points the *  descriptor at the buffer which was passed in.  The driver *  then informs the DMA engine that there are packets ready to *  be transmitted.  Once the controller is finished transmitting *  the packet, an interrupt may be triggered (under the same *  conditions as for reception, but depending on the TXF bit). *  The driver then cleans up the buffer. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/interrupt.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/mm.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <linux/module.h>#include <linux/version.h>#include <linux/dma-mapping.h>#include <linux/crc32.h>#include "gianfar.h"#include "gianfar_phy.h"#define TX_TIMEOUT      (1*HZ)#define SKB_ALLOC_TIMEOUT 1000000#undef BRIEF_GFAR_ERRORS#undef VERBOSE_GFAR_ERRORS#ifdef CONFIG_GFAR_NAPI#define RECEIVE(x) netif_receive_skb(x)#else#define RECEIVE(x) netif_rx(x)#endifconst char gfar_driver_name[] = "Gianfar Ethernet";const char gfar_driver_version[] = "1.1";int startup_gfar(struct net_device *dev);static int gfar_enet_open(struct net_device *dev);static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);static void gfar_timeout(struct net_device *dev);static int gfar_close(struct net_device *dev);struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp);static struct net_device_stats *gfar_get_stats(struct net_device *dev);static int gfar_set_mac_address(struct net_device *dev);static int gfar_change_mtu(struct net_device *dev, int new_mtu);static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void gfar_phy_change(void *data);static void gfar_phy_timer(unsigned long data);static void adjust_link(struct net_device *dev);static void init_registers(struct net_device *dev);static int init_phy(struct net_device *dev);static int gfar_probe(struct ocp_device *ocpdev);static void gfar_remove(struct ocp_device *ocpdev);void free_skb_resources(struct gfar_private *priv);static void gfar_set_multi(struct net_device *dev);static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);#ifdef CONFIG_GFAR_NAPIstatic int gfar_poll(struct net_device *dev, int *budget);#endifstatic int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);static void gfar_phy_startup_timer(unsigned long data);extern struct ethtool_ops gfar_ethtool_ops;MODULE_AUTHOR("Freescale Semiconductor, Inc");MODULE_DESCRIPTION("Gianfar Ethernet Driver");MODULE_LICENSE("GPL");/* Called by the ocp code to initialize device data structures * required for bringing up the device * returns 0 on success */static int gfar_probe(struct ocp_device *ocpdev){	u32 tempval;	struct ocp_device *mdiodev;	struct net_device *dev = NULL;	struct gfar_private *priv = NULL;	struct ocp_gfar_data *einfo;	int idx;	int err = 0;	int dev_ethtool_ops = 0;	einfo = (struct ocp_gfar_data *) ocpdev->def->additions;	if (einfo == NULL) {		printk(KERN_ERR "gfar %d: Missing additional data!\n",		       ocpdev->def->index);		return -ENODEV;	}	/* get a pointer to the register memory which can	 * configure the PHYs.  If it's different from this set,	 * get the device which has those regs */	if ((einfo->phyregidx >= 0) && 			(einfo->phyregidx != ocpdev->def->index)) {		mdiodev = ocp_find_device(OCP_ANY_ID,					  OCP_FUNC_GFAR, einfo->phyregidx);		/* If the device which holds the MDIO regs isn't		 * up, wait for it to come up */		if (mdiodev == NULL)			return -EAGAIN;	} else {		mdiodev = ocpdev;	}	/* Create an ethernet device instance */	dev = alloc_etherdev(sizeof (*priv));	if (dev == NULL)		return -ENOMEM;	priv = netdev_priv(dev);	/* Set the info in the priv to the current info */	priv->einfo = einfo;	/* get a pointer to the register memory */	priv->regs = (struct gfar *)		ioremap(ocpdev->def->paddr, sizeof (struct gfar));	if (priv->regs == NULL) {		err = -ENOMEM;		goto regs_fail;	}	/* Set the PHY base address */	priv->phyregs = (struct gfar *)	    ioremap(mdiodev->def->paddr, sizeof (struct gfar));	if (priv->phyregs == NULL) {		err = -ENOMEM;		goto phy_regs_fail;	}	spin_lock_init(&priv->lock);	ocp_set_drvdata(ocpdev, dev);	/* Stop the DMA engine now, in case it was running before */	/* (The firmware could have used it, and left it running). */	/* To do this, we write Graceful Receive Stop and Graceful */	/* Transmit Stop, and then wait until the corresponding bits */	/* in IEVENT indicate the stops have completed. */	tempval = gfar_read(&priv->regs->dmactrl);	tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);	gfar_write(&priv->regs->dmactrl, tempval);	tempval = gfar_read(&priv->regs->dmactrl);	tempval |= (DMACTRL_GRS | DMACTRL_GTS);	gfar_write(&priv->regs->dmactrl, tempval);	while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))		cpu_relax();	/* Reset MAC layer */	gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);	tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);	gfar_write(&priv->regs->maccfg1, tempval);	/* Initialize MACCFG2. */	gfar_write(&priv->regs->maccfg2, MACCFG2_INIT_SETTINGS);	/* Initialize ECNTRL */	gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS);	/* Copy the station address into the dev structure, */	memcpy(dev->dev_addr, einfo->mac_addr, MAC_ADDR_LEN);	/* Set the dev->base_addr to the gfar reg region */	dev->base_addr = (unsigned long) (priv->regs);	SET_MODULE_OWNER(dev);	SET_NETDEV_DEV(dev, &ocpdev->dev);	/* Fill in the dev structure */	dev->open = gfar_enet_open;	dev->hard_start_xmit = gfar_start_xmit;	dev->tx_timeout = gfar_timeout;	dev->watchdog_timeo = TX_TIMEOUT;#ifdef CONFIG_GFAR_NAPI	dev->poll = gfar_poll;	dev->weight = GFAR_DEV_WEIGHT;#endif	dev->stop = gfar_close;	dev->get_stats = gfar_get_stats;	dev->change_mtu = gfar_change_mtu;	dev->mtu = 1500;	dev->set_multicast_list = gfar_set_multi;	/* Index into the array of possible ethtool	 * ops to catch all 4 possibilities */	if((priv->einfo->flags & GFAR_HAS_RMON) == 0)		dev_ethtool_ops += 1;	if((priv->einfo->flags & GFAR_HAS_COALESCE) == 0)		dev_ethtool_ops += 2;	dev->ethtool_ops = gfar_op_array[dev_ethtool_ops];	priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;#ifdef CONFIG_GFAR_BUFSTASH	priv->rx_stash_size = STASH_LENGTH;#endif	priv->tx_ring_size = DEFAULT_TX_RING_SIZE;	priv->rx_ring_size = DEFAULT_RX_RING_SIZE;	priv->txcoalescing = DEFAULT_TX_COALESCE;	priv->txcount = DEFAULT_TXCOUNT;	priv->txtime = DEFAULT_TXTIME;	priv->rxcoalescing = DEFAULT_RX_COALESCE;	priv->rxcount = DEFAULT_RXCOUNT;	priv->rxtime = DEFAULT_RXTIME;	err = register_netdev(dev);	if (err) {		printk(KERN_ERR "%s: Cannot register net device, aborting.\n",				dev->name);		goto register_fail;	}	/* Print out the device info */	printk(KERN_INFO DEVICE_NAME, dev->name);	for (idx = 0; idx < 6; idx++)		printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':');	printk("\n");	/* Even more device info helps when determining which kernel */	/* provided which set of benchmarks.  Since this is global for all */	/* devices, we only print it once */#ifdef CONFIG_GFAR_NAPI	printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name);#else	printk(KERN_INFO "%s: Running with NAPI disabled\n", dev->name);#endif	printk(KERN_INFO "%s: %d/%d RX/TX BD ring size\n",	       dev->name, priv->rx_ring_size, priv->tx_ring_size);	return 0;register_fail:	iounmap((void *) priv->phyregs);phy_regs_fail:	iounmap((void *) priv->regs);regs_fail:	free_netdev(dev);	return -ENOMEM;}static void gfar_remove(struct ocp_device *ocpdev){	struct net_device *dev = ocp_get_drvdata(ocpdev);	struct gfar_private *priv = netdev_priv(dev);	ocp_set_drvdata(ocpdev, NULL);	iounmap((void *) priv->regs);	iounmap((void *) priv->phyregs);	free_netdev(dev);}/* Configure the PHY for dev. * returns 0 if success.  -1 if failure */static int init_phy(struct net_device *dev){	struct gfar_private *priv = netdev_priv(dev);	struct phy_info *curphy;	unsigned int timeout = PHY_INIT_TIMEOUT;	struct gfar *phyregs = priv->phyregs;	struct gfar_mii_info *mii_info;	int err;	priv->oldlink = 0;	priv->oldspeed = 0;	priv->oldduplex = -1;	mii_info = kmalloc(sizeof(struct gfar_mii_info),			GFP_KERNEL);	if(NULL == mii_info) {		printk(KERN_ERR "%s: Could not allocate mii_info\n", 				dev->name);		return -ENOMEM;	}	mii_info->speed = SPEED_1000;	mii_info->duplex = DUPLEX_FULL;	mii_info->pause = 0;	mii_info->link = 1;	mii_info->advertising = (ADVERTISED_10baseT_Half |			ADVERTISED_10baseT_Full |			ADVERTISED_100baseT_Half |			ADVERTISED_100baseT_Full |			ADVERTISED_1000baseT_Full);	mii_info->autoneg = 1;	mii_info->mii_id = priv->einfo->phyid;	mii_info->dev = dev;	mii_info->mdio_read = &read_phy_reg;	mii_info->mdio_write = &write_phy_reg;	priv->mii_info = mii_info;	/* Reset the management interface */	gfar_write(&phyregs->miimcfg, MIIMCFG_RESET);	/* Setup the MII Mgmt clock speed */	gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE);	/* Wait until the bus is free */	while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) &&			timeout--)		cpu_relax();	if(timeout <= 0) {		printk(KERN_ERR "%s: The MII Bus is stuck!\n",				dev->name);		err = -1;		goto bus_fail;	}	/* get info for this PHY */	curphy = get_phy_info(priv->mii_info);	if (curphy == NULL) {		printk(KERN_ERR "%s: No PHY found\n", dev->name);		err = -1;		goto no_phy;	}	mii_info->phyinfo = curphy;	/* Run the commands which initialize the PHY */	if(curphy->init) {		err = curphy->init(priv->mii_info);		if (err) 			goto phy_init_fail;	}	return 0;phy_init_fail:no_phy:bus_fail:	kfree(mii_info);	return err;}static void init_registers(struct net_device *dev){	struct gfar_private *priv = netdev_priv(dev);	/* Clear IEVENT */	gfar_write(&priv->regs->ievent, IEVENT_INIT_CLEAR);	/* Initialize IMASK */	gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR);	/* Init hash registers to zero */	gfar_write(&priv->regs->iaddr0, 0);	gfar_write(&priv->regs->iaddr1, 0);	gfar_write(&priv->regs->iaddr2, 0);	gfar_write(&priv->regs->iaddr3, 0);	gfar_write(&priv->regs->iaddr4, 0);	gfar_write(&priv->regs->iaddr5, 0);	gfar_write(&priv->regs->iaddr6, 0);	gfar_write(&priv->regs->iaddr7, 0);	gfar_write(&priv->regs->gaddr0, 0);	gfar_write(&priv->regs->gaddr1, 0);	gfar_write(&priv->regs->gaddr2, 0);	gfar_write(&priv->regs->gaddr3, 0);	gfar_write(&priv->regs->gaddr4, 0);	gfar_write(&priv->regs->gaddr5, 0);	gfar_write(&priv->regs->gaddr6, 0);	gfar_write(&priv->regs->gaddr7, 0);

⌨️ 快捷键说明

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