📄 fcc_enet.c
字号:
/* * BK Id: SCCS/s.fcc_enet.c 1.7 05/17/01 18:14:20 cort *//* * 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. People seem to be choosing common I/O * configurations, so this driver will work on the EST8260 boards and * others yet to be announced. * * 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. * */#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 <asm/immap_8260.h>#include <asm/pgtable.h>#include <asm/mpc8260.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <asm/cpm_8260.h>/* The transmitter timeout */#define TX_TIMEOUT (2*HZ)/* 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. */#define PKT_MAXBUF_SIZE 1518#define PKT_MINBUF_SIZE 64/* Maximum input DMA size. Must be a should(?) be a multiple of 4.*/#define PKT_MAXDMA_SIZE 1520/* 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 void fcc_enet_mii(struct net_device *dev);static void fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * 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 restart_fcc(struct net_device *dev);/* 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. *//* 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_PSORA0 (PA1_RXDAT | PA1_TXDAT)#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ PA1_RXDV | PA1_RXER)#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER)/* CLK12 is receive, CLK11 is transmit. These are board specific.*/#define PC_F1RXCLK ((uint)0x00000800)#define PC_F1TXCLK ((uint)0x00000400)#define CMX1_CLK_ROUTE ((uint)0x3e000000)#define CMX1_CLK_MASK ((uint)0xff000000)/* 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_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ PB2_RXER | PB2_RXDV | PB2_TXER)#define PB2_PSORB1 (PB2_TXEN)#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER)/* CLK13 is receive, CLK14 is transmit. These are board dependent.*/#define PC_F2RXCLK ((uint)0x00001000)#define PC_F2TXCLK ((uint)0x00002000)#define CMX2_CLK_ROUTE ((uint)0x00250000)#define CMX2_CLK_MASK ((uint)0x00ff0000)/* 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)#define PB3_TXDAT ((uint)0x0f000000)#define PB3_RXDAT ((uint)0x00f00000)#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN)#define PB3_PSORB1 (0)#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER)/* CLK15 is receive, CLK16 is transmit. These are board dependent.*/#define PC_F3RXCLK ((uint)0x00004000)#define PC_F3TXCLK ((uint)0x00008000)#define CMX3_CLK_ROUTE ((uint)0x00003700)#define CMX3_CLK_MASK ((uint)0x0000ff00)/* MII status/control serial interface.*/#define PC_MDIO ((uint)0x00400000)#define PC_MDCK ((uint)0x00200000)/* 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_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, 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, 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, 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_full; spinlock_t lock; uint phy_address; uint phy_type; uint phy_duplex; fcc_info_t *fip;};static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, volatile immap_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 iop8260_t *io, volatile immap_t *immap);static void init_fcc_param(fcc_info_t *fip, struct net_device *dev, volatile immap_t *immap);/* 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); struct mii_list *mii_next;} 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;static int phyaddr;static uint phytype;static int mii_queue(int request, void (*func)(uint, struct net_device *));static void mii_startup_cmds(void);static uint mii_send_receive(fcc_info_t *fip, uint cmd);/* Make MII read/write commands for the FCC.*/#define mk_mii_phyaddr(ADDR) (0x60020000 | ((ADDR) << 23) | (2 << 18))#define mk_mii_read(REG) (0x60020000 | ((phyaddr << 23) | \ (REG & 0x1f) << 18))#define mk_mii_write(REG, VAL) (0x50020000 | ((phyaddr << 23) | \ (REG & 0x1f) << 18) | \ (VAL & 0xffff))static intfcc_enet_open(struct net_device *dev){ netif_start_queue(dev); return 0; /* Always succeed */}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 (bdp->cbd_sc & BD_ENET_TX_READY) { /* Ooops. All transmit buffers are full. Bail out. * This should not happen, since cep->tx_full should be set. */ 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); /* 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; spin_lock_irq(&cep->lock); /* 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. */ if (bdp->cbd_sc & BD_ENET_TX_WRAP) bdp = cep->tx_bd_base; else bdp++; if (bdp->cbd_sc & BD_ENET_TX_READY) { netif_stop_queue(dev); cep->tx_full = 1; } cep->cur_tx = (cbd_t *)bdp; spin_unlock_irq(&cep->lock); return 0;}static voidfcc_enet_timeout(struct net_device *dev){ struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; printk("%s: transmit timed out.\n", dev->name); cep->stats.tx_errors++;#ifndef final_version { int i; cbd_t *bdp; printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", cep->cur_tx, cep->tx_full ? " (full)" : "", cep->cur_rx); bdp = cep->tx_bd_base; printk(" Tx @base %p :\n", bdp); for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) printk("%04x %04x %08x\n", bdp->cbd_sc, bdp->cbd_datlen, bdp->cbd_bufaddr); bdp = cep->rx_bd_base; printk(" Rx @base %p :\n", bdp); for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) printk("%04x %04x %08x\n", bdp->cbd_sc, bdp->cbd_datlen, bdp->cbd_bufaddr); }#endif if (!cep->tx_full) netif_wake_queue(dev);}/* The interrupt handler. */static voidfcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs){ struct net_device *dev = dev_id; volatile struct fcc_enet_private *cep; volatile cbd_t *bdp; ushort int_events; int must_restart; cep = (struct fcc_enet_private *)dev->priv; /* Get the interrupt events that caused us to be here. */ int_events = cep->fccp->fcc_fcce; cep->fccp->fcc_fcce = int_events; must_restart = 0; /* Handle receive event in its own function. */ if (int_events & FCC_ENET_RXF) fcc_enet_rx(dev_id); /* Check for a transmit error. The manual is a little unclear * about this, so the debug code until I get it figured out. It * appears that if TXE is set, then TXB is not set. However, * if carrier sense is lost during frame transmission, the TXE * bit is set, "and continues the buffer transmission normally." * I don't know if "normally" implies TXB is set when the buffer * descriptor is closed.....trial and error :-). */ /* Transmit OK, or non-fatal error. Update the buffer descriptors. */ if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) { spin_lock(&cep->lock); bdp = cep->dirty_tx; while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) break; if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ cep->stats.tx_heartbeat_errors++; if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ cep->stats.tx_window_errors++; if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ cep->stats.tx_aborted_errors++; if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ cep->stats.tx_fifo_errors++; if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ cep->stats.tx_carrier_errors++; /* No heartbeat or Lost carrier are not really bad errors. * The others require a restart transmit command. */ if (bdp->cbd_sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { must_restart = 1; cep->stats.tx_errors++; } cep->stats.tx_packets++; /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ if (bdp->cbd_sc & BD_ENET_TX_DEF) cep->stats.collisions++; /* Free the sk buffer associated with this last transmit. */ dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; /* Update pointer to next buffer descriptor to be transmitted. */ if (bdp->cbd_sc & BD_ENET_TX_WRAP) bdp = cep->tx_bd_base; else bdp++; /* I don't know if we can be held off from processing these * interrupts for more than one frame time. I really hope * not. In such a case, we would now want to check the * currently available BD (cur_tx) and determine if any * buffers between the dirty_tx and cur_tx have also been * sent. We would want to process anything in between that * does not have BD_ENET_TX_READY set. */ /* Since we have freed up a buffer, the ring is no longer * full. */ if (cep->tx_full) { cep->tx_full = 0; if (netif_queue_stopped(dev)) { netif_wake_queue(dev); } } cep->dirty_tx = (cbd_t *)bdp; } if (must_restart) { volatile cpm8260_t *cp; /* Some transmit errors cause the transmitter to shut * down. We now issue a restart transmit. Since the * errors close the BD and update the pointers, the restart * _should_ pick up without having to reset any of our * pointers either. */ cp = cpmp; cp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock, 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); } spin_unlock(&cep->lock); } /* Check for receive busy, i.e. packets coming but no place to * put them. */ if (int_events & FCC_ENET_BSY) { cep->stats.rx_dropped++; } return;}/* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -