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 + -
显示快捷键?