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

📄 gianfar.c

📁 Powerpc网络处理器MPC85xx增强型三速以太控制器驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * drivers/net/gianfar.c * * Gianfar Ethernet Driver * This driver is designed for the non-CPM ethernet controllers * on the 85xx and 83xx family of integrated processors * Based on 8260_io/fcc_enet.c * * Author: Andy Fleming * Maintainer: Kumar Gala * * Copyright (C) 2002-2008 Freescale Semiconductor, Inc. All rights reserved. * Copyright (c) 2007 MontaVista Software, Inc. *  * ChangeLog: *  2007 Scott Wood <scottwood@freescale.com> *       Add power manangement support *  2008 Tanya Jiang <tanya.jiang@freescale.com> *       Enhanced pm support for waking up from phy interrupt * * 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 * *  The driver is initialized through platform_device.  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. * *  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/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/unistd.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/if_vlan.h>#include <linux/spinlock.h>#include <linux/mm.h>#include <linux/platform_device.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/udp.h>#include <linux/in.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <linux/module.h>#include <linux/dma-mapping.h>#include <linux/crc32.h>#include <linux/mii.h>#include <linux/phy.h>#include "gianfar.h"#include "gianfar_mii.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.3-skbr";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);static irqreturn_t gfar_transmit(int irq, void *dev_id);static irqreturn_t gfar_interrupt(int irq, void *dev_id);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 platform_device *pdev);static int gfar_remove(struct platform_device *pdev);static 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);static void gfar_configure_serdes(struct net_device *dev);extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);#ifdef CONFIG_GFAR_NAPIstatic int gfar_poll(struct net_device *dev, int *budget);#endif#ifdef CONFIG_NET_POLL_CONTROLLERstatic void gfar_netpoll(struct net_device *dev);#endifint 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_vlan_rx_register(struct net_device *netdev,		                struct vlan_group *grp);static void gfar_halt_nodisable(struct net_device *dev);void gfar_halt(struct net_device *dev);void gfar_start(struct net_device *dev);static void gfar_clear_exact_match(struct net_device *dev);static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);extern const struct ethtool_ops gfar_ethtool_ops;#ifdef CONFIG_GFAR_SKBUFF_RECYCLINGstatic unsigned int skbuff_truesize(unsigned int buffer_size);static void gfar_skbr_register_truesize(struct gfar_private *priv);static int gfar_kfree_skb(struct sk_buff *skb);static void gfar_reset_skb_handler(struct gfar_skb_handler *sh);#endifMODULE_AUTHOR("Freescale Semiconductor, Inc");MODULE_DESCRIPTION("Gianfar Ethernet Driver");MODULE_LICENSE("GPL");/* Returns 1 if incoming frames use an FCB */static inline int gfar_uses_fcb(struct gfar_private *priv){	return (priv->vlan_enable || priv->rx_csum_enable);}/* Set up the ethernet device structure, private data, * and anything else we need before we start */static int gfar_probe(struct platform_device *pdev){	u32 tempval;	struct net_device *dev = NULL;	struct gfar_private *priv = NULL;	struct gianfar_platform_data *einfo;	struct resource *r;	int idx;	int err = 0;	einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;	if (NULL == einfo) {		printk(KERN_ERR "gfar %d: Missing additional data!\n",		       pdev->id);		return -ENODEV;	}	/* Create an ethernet device instance */	dev = alloc_etherdev(sizeof (*priv));	if (NULL == dev)		return -ENOMEM;	priv = netdev_priv(dev);	/* Set the info in the priv to the current info */	priv->einfo = einfo;	/* fill out IRQ fields */	if (einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {		priv->interruptTransmit = platform_get_irq_byname(pdev, "tx");		priv->interruptReceive = platform_get_irq_byname(pdev, "rx");		priv->interruptError = platform_get_irq_byname(pdev, "error");		if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0)			goto regs_fail;	} else {		priv->interruptTransmit = platform_get_irq(pdev, 0);		if (priv->interruptTransmit < 0)			goto regs_fail;	}	/* get a pointer to the register memory */	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);	priv->regs = ioremap(r->start, sizeof (struct gfar));	if (NULL == priv->regs) {		err = -ENOMEM;		goto regs_fail;	}	spin_lock_init(&priv->txlock);	spin_lock_init(&priv->rxlock);	spin_lock_init(&priv->bflock);	platform_set_drvdata(pdev, 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, &pdev->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#ifdef CONFIG_NET_POLL_CONTROLLER	dev->poll_controller = gfar_netpoll;#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;	dev->ethtool_ops = &gfar_ethtool_ops;	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {		priv->rx_csum_enable = 1;		dev->features |= NETIF_F_IP_CSUM;	} else		priv->rx_csum_enable = 0;	priv->vlgrp = NULL;	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {		dev->vlan_rx_register = gfar_vlan_rx_register;		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;		priv->vlan_enable = 1;	}	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {		priv->extended_hash = 1;		priv->hash_width = 9;		priv->hash_regs[0] = &priv->regs->igaddr0;		priv->hash_regs[1] = &priv->regs->igaddr1;		priv->hash_regs[2] = &priv->regs->igaddr2;		priv->hash_regs[3] = &priv->regs->igaddr3;		priv->hash_regs[4] = &priv->regs->igaddr4;		priv->hash_regs[5] = &priv->regs->igaddr5;		priv->hash_regs[6] = &priv->regs->igaddr6;		priv->hash_regs[7] = &priv->regs->igaddr7;		priv->hash_regs[8] = &priv->regs->gaddr0;		priv->hash_regs[9] = &priv->regs->gaddr1;		priv->hash_regs[10] = &priv->regs->gaddr2;		priv->hash_regs[11] = &priv->regs->gaddr3;		priv->hash_regs[12] = &priv->regs->gaddr4;		priv->hash_regs[13] = &priv->regs->gaddr5;		priv->hash_regs[14] = &priv->regs->gaddr6;		priv->hash_regs[15] = &priv->regs->gaddr7;	} else {		priv->extended_hash = 0;		priv->hash_width = 8;		priv->hash_regs[0] = &priv->regs->gaddr0;                priv->hash_regs[1] = &priv->regs->gaddr1;		priv->hash_regs[2] = &priv->regs->gaddr2;		priv->hash_regs[3] = &priv->regs->gaddr3;		priv->hash_regs[4] = &priv->regs->gaddr4;		priv->hash_regs[5] = &priv->regs->gaddr5;		priv->hash_regs[6] = &priv->regs->gaddr6;		priv->hash_regs[7] = &priv->regs->gaddr7;	}	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)		priv->padding = DEFAULT_PADDING;	else		priv->padding = 0;	if (dev->features & NETIF_F_IP_CSUM)		dev->hard_header_len += GMAC_FCB_LEN;	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;	/* Enable most messages by default */	priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;	err = register_netdev(dev);	if (err) {		printk(KERN_ERR "%s: Cannot register net device, aborting.\n",				dev->name);		goto register_fail;	}	/* Create all the sysfs files */	gfar_init_sysfs(dev);	/* 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");#ifdef CONFIG_GFAR_SKBUFF_RECYCLING	priv->rx_skbuff_truesize = GFAR_DEFAULT_RECYCLE_TRUESIZE;	gfar_reset_skb_handler(&priv->skb_handler);#endif	/* Setup MTU, receive buffer size */	gfar_change_mtu(dev, 1500);	/* Even more device info helps when determining which kernel */	/* provided which set of benchmarks. */#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(priv->regs);regs_fail:	free_netdev(dev);	return err;}static int gfar_remove(struct platform_device *pdev){	struct net_device *dev = platform_get_drvdata(pdev);	struct gfar_private *priv = netdev_priv(dev);	platform_set_drvdata(pdev, NULL);	iounmap(priv->regs);	free_netdev(dev);	return 0;}#ifdef CONFIG_PMstatic int gfar_suspend(struct platform_device *pdev, pm_message_t state){	struct net_device *dev = platform_get_drvdata(pdev);	struct gfar_private *priv = netdev_priv(dev);	unsigned long flags;	u32 tempval;	int magic_packet = priv->wol_magic_packet &&		(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);	int wake_phy = priv->wol_wake_phy &&		(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_WAKE_PHY);	netif_device_detach(dev);	if (netif_running(dev)) {		spin_lock_irqsave(&priv->txlock, flags);		spin_lock(&priv->rxlock);		gfar_halt_nodisable(dev);		/* Disable Tx, and Rx if wake-on-LAN is disabled. */		tempval = gfar_read(&priv->regs->maccfg1);		tempval &= ~MACCFG1_TX_EN;		if (!magic_packet)			tempval &= ~MACCFG1_RX_EN;		gfar_write(&priv->regs->maccfg1, tempval);		spin_unlock(&priv->rxlock);		spin_unlock_irqrestore(&priv->txlock, flags);#ifdef CONFIG_GFAR_NAPI		netif_poll_disable(dev);#endif		if (magic_packet) {			/* Enable interrupt on Magic Packet */			gfar_write(&priv->regs->imask, IMASK_MAG);			/* Enable Magic Packet mode */			tempval = gfar_read(&priv->regs->maccfg2);			tempval |= MACCFG2_MPEN;			gfar_write(&priv->regs->maccfg2, tempval);		}		if (!wake_phy)			phy_stop(priv->phydev);	}	return 0;}static int gfar_resume(struct platform_device *pdev)

⌨️ 快捷键说明

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