?? fec.c
字號:
/* * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * * This version of the driver is specific to the FADS implementation, * since the board contains control registers external to the processor * for the control of the LevelOne LXT970 transceiver. The MPC860T manual * describes connections using the internal parallel port I/O, which * is basically all of Port D. * * Includes support for the following PHYs: QS6612, LXT970, LXT971/2. * * Right now, I am very wasteful 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. * * Much better multiple PHY support by Magnus Damm. * Copyright (c) 2000 Ericsson Radio Systems AB. * * Make use of MII for PHY control configurable. * Some fixes. * Copyright (c) 2000, 2001, 2002 Wolfgang Denk, DENX Software Engineering. * * Fixes for tx_full condition and relink when using MII. * Support for AMD AM79C874 added. * Thomas Lange, thomas@corelatus.com * * Added code for Multicast support, Frederic Goddeeris, Paul Geerinckx * Copyright (c) 2002 Siemens Atea */#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/ethtool.h>#ifdef CONFIG_FEC_PACKETHOOK#include <linux/pkthook.h>#endif#include <asm/8xx_immap.h>#include <asm/pgtable.h>#include <asm/mpc8xx.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include "commproc.h"/* multicast support*//* #define DEBUG_MULTICAST *//* CRC polynomium used by the FEC for the multicast group filtering*/#define FEC_CRC_POLY 0x04c11db7#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, uint data);} 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;#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. */#ifdef CONFIG_ENET_BIG_BUFFERS#define FEC_ENET_RX_PAGES 16#define FEC_ENET_RX_FRSIZE 2048#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE)#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)#define TX_RING_SIZE 16 /* Must be power of two */#define TX_RING_MOD_MASK 15 /* for this to work */#else#define FEC_ENET_RX_PAGES 4#define FEC_ENET_RX_FRSIZE 2048#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE)#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)#define TX_RING_SIZE 8 /* Must be power of two */#define TX_RING_MOD_MASK 7 /* for this to work */#endif/* Interrupt events/masks.*/#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error *//**/#define FEC_ECNTRL_PINMUX 0x00000004#define FEC_ECNTRL_ETHER_EN 0x00000002#define FEC_ECNTRL_RESET 0x00000001#define FEC_RCNTRL_BC_REJ 0x00000010#define FEC_RCNTRL_PROM 0x00000008#define FEC_RCNTRL_MII_MODE 0x00000004#define FEC_RCNTRL_DRT 0x00000002#define FEC_RCNTRL_LOOP 0x00000001#define FEC_TCNTRL_FDEN 0x00000004#define FEC_TCNTRL_HBC 0x00000002#define FEC_TCNTRL_GTS 0x00000001/* Delay to wait for FEC reset command to complete (in us)*/#define FEC_RESET_DELAY 50/* The FEC stores dest/src/type, data, and checksum for receive packets. */#define PKT_MAXBUF_SIZE 1518#define PKT_MINBUF_SIZE 64#define PKT_MAXBLR_SIZE 1520/* The FEC 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 fec_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. */ scc_t *sccp; struct net_device_stats stats; uint tx_full;; spinlock_t lock;#ifdef CONFIG_USE_MDIO uint phy_id; uint phy_id_done; uint phy_status; uint phy_speed; phy_info_t *phy; struct tq_struct phy_task; uint sequence_done; uint phy_addr; struct timer_list phy_timer_list; u16 old_status;#endif /* CONFIG_USE_MDIO */ int link; int old_link; int full_duplex;#ifdef CONFIG_FEC_PACKETHOOK unsigned long ph_lock; fec_ph_func *ph_rxhandler; fec_ph_func *ph_txhandler; __u16 ph_proto; volatile __u32 *ph_regaddr; void *ph_priv;#endif};static int fec_enet_open(struct net_device *dev);static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);#ifdef CONFIG_USE_MDIOstatic void fec_enet_mii(struct net_device *dev);#endif /* CONFIG_USE_MDIO */static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);#ifdef CONFIG_FEC_PACKETHOOKstatic void fec_enet_tx(struct net_device *dev, __u32 regval);static void fec_enet_rx(struct net_device *dev, __u32 regval);#elsestatic void fec_enet_tx(struct net_device *dev);static void fec_enet_rx(struct net_device *dev);#endifstatic int fec_enet_close(struct net_device *dev);static struct net_device_stats *fec_enet_get_stats(struct net_device *dev);static void set_multicast_list(struct net_device *dev);static void fec_restart(struct net_device *dev, int duplex);static void fec_stop(struct net_device *dev);static ushort my_enet_addr[3];#ifdef CONFIG_USE_MDIOstatic int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr);static void mdio_callback(uint regval, struct net_device *dev, uint data);static int mdio_read(struct net_device *dev, int phy_id, int location);#if defined(CONFIG_FEC_DP83846A)static void mdio_timer_callback(unsigned long data);#endif /* CONFIG_FEC_DP83846A *//* MII processing. We keep this as simple as possible. Requests are * placed on the list (if there is room). When the request is finished * by the MII, an optional function may be called. */typedef struct mii_list { uint mii_regval; void (*mii_func)(uint val, struct net_device *dev, uint data); struct mii_list *mii_next; uint mii_data;} mii_list_t;#define NMII 20mii_list_t mii_cmds[NMII];mii_list_t *mii_free;mii_list_t *mii_head;mii_list_t *mii_tail;typedef struct mdio_read_data { u16 regval; struct task_struct *sleeping_task;} mdio_read_data_t;static int mii_queue ( struct net_device *dev, int request, void (*func)(uint, struct net_device *, uint), uint data );/* 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#endif /* CONFIG_USE_MDIO *//* Transmitter timeout.*/#define TX_TIMEOUT (2*HZ)#ifdef CONFIG_USE_MDIO/* Register definitions for the PHY.*/#define MII_REG_CR 0 /* Control Register */#define MII_REG_SR 1 /* Status Register */#define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */#define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */#define MII_REG_ANAR 4 /* A-N Advertisement Register */#define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */#define MII_REG_ANER 6 /* A-N Expansion Register */#define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */#define MII_REG_ANLPRNPR 8 /* A-N Link Partner Received Next Page Reg. *//* 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 */#ifdef CONFIG_FEC_PACKETHOOKintfec_register_ph(struct net_device *dev, fec_ph_func *rxfun, fec_ph_func *txfun, __u16 proto, volatile __u32 *regaddr, void *priv){ struct fec_enet_private *fep; int retval = 0; fep = dev->priv; if (test_and_set_bit(0, (void*)&fep->ph_lock) != 0) { /* Someone is messing with the packet hook */ return -EAGAIN; } if (fep->ph_rxhandler != NULL || fep->ph_txhandler != NULL) { retval = -EBUSY; goto out; } fep->ph_rxhandler = rxfun; fep->ph_txhandler = txfun; fep->ph_proto = proto; fep->ph_regaddr = regaddr; fep->ph_priv = priv; out: fep->ph_lock = 0; return retval;}intfec_unregister_ph(struct net_device *dev){ struct fec_enet_private *fep; int retval = 0; fep = dev->priv; if (test_and_set_bit(0, (void*)&fep->ph_lock) != 0) { /* Someone is messing with the packet hook */ return -EAGAIN; } fep->ph_rxhandler = fep->ph_txhandler = NULL; fep->ph_proto = 0; fep->ph_regaddr = NULL; fep->ph_priv = NULL; fep->ph_lock = 0; return retval;}EXPORT_SYMBOL(fec_register_ph);EXPORT_SYMBOL(fec_unregister_ph);#endif /* CONFIG_FEC_PACKETHOOK */static intfec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct fec_enet_private *fep; volatile fec_t *fecp; volatile cbd_t *bdp; fep = dev->priv; fecp = (volatile fec_t*)dev->base_addr; if (!fep->link) { /* Link is down or autonegotiation is in progress. */ return 1; } /* Fill in a Tx ring entry */ bdp = fep->cur_tx; /* Clear all of the status flags. */ bdp->cbd_sc &= ~BD_ENET_TX_STATS; /* Set buffer length and buffer pointer. */ bdp->cbd_bufaddr = __pa(skb->data); bdp->cbd_datlen = skb->len; /* Save skb pointer. */ fep->tx_skbuff[fep->skb_cur] = skb; fep->stats.tx_bytes += skb->len; fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; /* Push the data cache so the CPM does not get stale memory * data. */ flush_dcache_range((unsigned long)skb->data, (unsigned long)skb->data + skb->len); spin_lock_irq(&fep->lock); /* Send it on its way. Tell FEC 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); dev->trans_start = jiffies; /* Trigger transmission start */ fecp->fec_x_des_active = 0x01000000; /* If this was the last BD in the ring, start at the beginning again. */ if (bdp->cbd_sc & BD_ENET_TX_WRAP) { bdp = fep->tx_bd_base; } else { bdp++; } if (bdp->cbd_sc & BD_ENET_TX_READY) { netif_stop_queue(dev); fep->tx_full = 1; } fep->cur_tx = (cbd_t *)bdp;/* AJZ Mar06 2002 * As of v1.2 of the ICU this problem has gone away. * This is probably the result of improved PCB layout. */#if 0 && defined(CONFIG_ICU862) /* workaround for hardware problem */ udelay(1000);#endif spin_unlock_irq(&fep->lock); return 0;}static voidfec_timeout(struct net_device *dev){ struct fec_enet_private *fep = dev->priv; if (fep->link || fep->old_link) { /* Link status changed - print timeout message */ printk("%s: transmit timed out.\n", dev->name); } fep->stats.tx_errors++;#ifndef final_version if (fep->link) { int i; cbd_t *bdp; printk ("Ring data dump: " "cur_tx %p%s dirty_tx %p cur_rx %p\n", fep->cur_tx, fep->tx_full ? " (full)" : "", fep->dirty_tx, fep->cur_rx); bdp = fep->tx_bd_base; printk(" tx: %u buffers\n", TX_RING_SIZE); for (i = 0 ; i < TX_RING_SIZE; i++) { printk(" %08x: %04x %04x %08x\n", (uint) bdp, bdp->cbd_sc, bdp->cbd_datlen, bdp->cbd_bufaddr); bdp++; } bdp = fep->rx_bd_base; printk(" rx: %lu buffers\n", RX_RING_SIZE); for (i = 0 ; i < RX_RING_SIZE; i++) { printk(" %08x: %04x %04x %08x\n", (uint) bdp, bdp->cbd_sc, bdp->cbd_datlen, bdp->cbd_bufaddr);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -