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

📄 adapter.c

📁 xilinx trimode mac driver for linux
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Xilinx Ethernet Adapter component to interface XTemac component to Linux * * Author: MontaVista Software, Inc. *         source@mvista.com * * 2002-2004 (c) MontaVista, Software, Inc.  This file is licensed under the terms * of the GNU General Public License version 2.1.  This program is licensed * "as is" without any warranty of any kind, whether express or implied. * * <pre> * MODIFICATION HISTORY: * * Ver   Who  Date     Changes * ----- ---- -------- ------------------------------------------------------- * 1.00a xd   12/12/05 First release * 2.00a jvb  12/21/05 Added support for checksum offload, and receive side DRE * 2.00b wgr  08/17/06 Port to kernel 2.6.10_mvl401. * </pre> * *//* * This driver is a bit unusual in that it is composed of two logical * parts where one part is the OS independent code and the other part is * the OS dependent code.  Xilinx provides their drivers split in this * fashion.  This file represents the Linux OS dependent part known as * the Linux adapter.  The other files in this directory are the OS * independent files as provided by Xilinx with no changes made to them. * The names exported by those files begin with XTemac_.  All functions * in this file that are called by Linux have names that begin with * xenet_.  The functions in this file that have Handler in their name * are registered as callbacks with the underlying Xilinx OS independent * layer.  Any other functions are static helper functions. *//* * With the way the hardened PLB Temac works, the driver needs to communicate * with the PHY controller. Since each board will have a different * type of PHY, the code that communicates with the MII type controller * is inside #ifdef XILINX_PLB_TEMAC_3_00A_ML403_PHY_SUPPORT conditional * compilation. For your specific board, you will want to replace this code with * code of your own for your specific board. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/mii.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/xilinx_devices.h>#include <asm/io.h>#include <linux/ethtool.h>#include <linux/vmalloc.h>#include "xbasic_types.h"#include "xtemac.h"#include "xipif_v1_23_b.h"#include "xpacket_fifo_v2_00_a.h"#include "xdmav3.h"#include "xdmabdv3.h"#define LOCAL_FEATURE_RX_CSUM   0x01#define LOCAL_FEATURE_RX_DRE    0x02/* * Default SEND and RECV buffer descriptors (BD) numbers. * BD Space needed is (XTE_SEND_BD_CNT+XTE_RECV_BD_CNT)*Sizeof(XDmaBdV3). * Each XDmaBdV3 instance currently takes 40 bytes. */#define XTE_SEND_BD_CNT 256#define XTE_RECV_BD_CNT 256/* Must be shorter than length of ethtool_drvinfo.driver field to fit */#define DRIVER_NAME         "xilinx_temac"#define DRIVER_DESCRIPTION  "Xilinx Tri-Mode Ethernet MAC driver"#define DRIVER_VERSION      "2.00b"#define TX_TIMEOUT   (3*HZ)    /* Transmission timeout is 3 seconds. *//* * When Xilinx TEMAC is configured to use the TX Data Realignment Engine (DRE), * alignment restrictions are as follows: *   - SGDMA transmit buffers can be aligned on any boundary, but receive buffers *     must be aligned on a 8-byte boundary. * * Without TX DRE, buffer alignment restrictions are as follows: *   - SGDMA transmit and receive buffers must be aligned on a 8-byte boundary * * There are no alignment restrictions when using XTemac_FifoRead() and * XTemac_FifoWrite(). * *//* * ALIGNMENT_RECV = the alignement required to receive (8 required by plb bus w/no DRE) * ALIGNMENT_SEND = the alignement required to send (8 required by plb bus w/no DRE) * ALIGNMENT_SEND_PERF = tx alignment for better performance * * ALIGNMENT_SEND is used to see if we *need* to copy the data to re-align. * ALIGNMENT_SEND_PERF is used if we've decided we need to copy anyway, we just * copy to this alignment for better performance. */#define ALIGNMENT_RECV          32#define ALIGNMENT_SEND          8#define ALIGNMENT_SEND_PERF     32/* SGDMA buffer descriptors must be aligned on a 8-byte boundary. */#define ALIGNMENT_BD            4/* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */#define BUFFER_ALIGNSEND(adr) ((ALIGNMENT_SEND - ((u32) adr)) % ALIGNMENT_SEND)#define BUFFER_ALIGNSEND_PERF(adr) ((ALIGNMENT_SEND_PERF - ((u32) adr)) % ALIGNMENT_SEND_PERF)#define BUFFER_ALIGNRECV(adr) ((ALIGNMENT_RECV - ((u32) adr)) % ALIGNMENT_RECV)/* Default TX/RX Threshold and waitbound values for SGDMA mode */#define DFT_TX_THRESHOLD  16#define DFT_TX_WAITBOUND  1#define DFT_RX_THRESHOLD  2#define DFT_RX_WAITBOUND  1#define XTE_AUTOSTRIPPING 1/* Put Buffer Descriptors in BRAM? * NOTE: *   Putting BDs in BRAM only works if there is only ONE instance of the TEMAC *   in hardware.  The code does not handle multiple instances, e.g. it does *   not manage the memory in BRAM. */#define BD_IN_BRAM        0#define BRAM_BASEADDR     0xffff8000/* * Our private per device data.  When a net_device is allocated we will * ask for enough extra space for this. */struct net_local {    struct list_head rcv;    struct list_head xmit;    struct net_device       *ndev;      /* this device */    struct net_device       *next_dev;  /* The next device in dev_list */    struct net_device_stats stats;      /* Statistics for this device */    struct timer_list       phy_timer;  /* PHY monitoring timer */    u32 index;                          /* Which interface is this */    XInterruptHandler   Isr;            /* Pointer to the XTemac ISR routine */    u8 gmii_addr;                       /* The GMII address of the PHY */    /* The underlying OS independent code needs space as well.  A     * pointer to the following XTemac structure will be passed to     * any XTemac_ function that requires it.  However, we treat the     * data as an opaque object in this file (meaning that we never     * reference any of the fields inside of the structure). */    XTemac Emac;    unsigned int max_frame_size;    int cur_speed;    /* Buffer Descriptor space for both TX and RX BD ring */    void        *desc_space;            /* virtual address of BD space */    dma_addr_t  desc_space_handle;      /* physical address of BD space */    int         desc_space_size;        /* size of BD space */    /* buffer for one skb in case no room is available for transmission */    struct sk_buff* deferred_skb;    /* send buffers for non tx-dre hw */    void        **tx_orig_buffers;      /* Buffer addresses as returned by                                           dma_alloc_coherent() */    void        **tx_buffers;           /* Buffers addresses aligned for DMA */    dma_addr_t  *tx_phys_buffers;       /* Buffer addresses in physical memory */    size_t      tx_buffers_cur;         /* Index of current buffer used */    /* stats */    int             max_frags_in_a_packet;    unsigned long   realignments;    unsigned long   tx_hw_csums;    unsigned long   rx_hw_csums;    unsigned long   local_features;#if ! XTE_AUTOSTRIPPING    unsigned long   stripping;#endif};/* for exclusion of all program flows (processes, ISRs and BHs) */spinlock_t XTE_spinlock;spinlock_t XTE_tx_spinlock;spinlock_t XTE_rx_spinlock;/* * ethtool has a status reporting feature where we can report any sort of * status information we'd like. This is the list of strings used for that * status reporting. ETH_GSTRING_LEN is defined in ethtool.h */static char xenet_ethtool_gstrings_stats[][ETH_GSTRING_LEN] = {    "txdmaerr", "txpfifoerr", "txstatuserr", "rxrejerr", "rxdmaerr",    "rxpfifoerror", "fifoerr", "ipiferr", "intr",    "max_frags", "tx_hw_csums", "rx_hw_csums",};#define XENET_STATS_LEN sizeof(xenet_ethtool_gstrings_stats) / ETH_GSTRING_LEN/* Helper function to determine if a given XTemac error warrants a reset. */extern inline intstatus_requires_reset(XStatus s){    return (s == XST_FIFO_ERROR ||            s == XST_PFIFO_DEADLOCK ||            s == XST_DMA_ERROR ||            s == XST_IPIF_ERROR);}/* BH statics */LIST_HEAD(receivedQueue);static spinlock_t receivedQueueSpin = SPIN_LOCK_UNLOCKED;LIST_HEAD(sentQueue);static spinlock_t sentQueueSpin = SPIN_LOCK_UNLOCKED;/* from mii.h * * Items in mii.h but not in gmii.h */#define ADVERTISE_100FULL       0x0100#define ADVERTISE_100HALF       0x0080#define ADVERTISE_10FULL        0x0040#define ADVERTISE_10HALF        0x0020#define ADVERTISE_CSMA          0x0001#define EX_ADVERTISE_1000FULL   0x0200#define EX_ADVERTISE_1000HALF   0x0100/* * items not in mii.h nor gmii.h but should be */#define MII_EXADVERTISE 0x09typedef enum DUPLEX { UNKNOWN_DUPLEX, HALF_DUPLEX, FULL_DUPLEX } DUPLEX;int renegotiate_speed(struct net_device *dev, int speed, DUPLEX duplex){    struct net_local *lp = (struct net_local *) dev->priv;    XStatus status;    int retries = 2;    int wait_count;    u16 phy_reg0 = BMCR_ANENABLE | BMCR_ANRESTART;    u16 phy_reg1;    u16 phy_reg4;    u16 phy_reg9 = 0;    /*     * It appears that the 10baset full and half duplex settings     * are overloaded for gigabit ethernet     */    if ((duplex == FULL_DUPLEX) && (speed == 10)) {        phy_reg4 = ADVERTISE_10FULL | ADVERTISE_CSMA;    } else if ((duplex == FULL_DUPLEX) && (speed == 100)) {        phy_reg4 = ADVERTISE_100FULL | ADVERTISE_CSMA;    } else if ((duplex == FULL_DUPLEX) && (speed == 1000)) {        phy_reg4 = ADVERTISE_CSMA;        phy_reg9 = EX_ADVERTISE_1000FULL;    } else if (speed == 10) {        phy_reg4 = ADVERTISE_10HALF | ADVERTISE_CSMA;    } else if (speed == 100) {        phy_reg4 = ADVERTISE_100HALF | ADVERTISE_CSMA;    } else if (speed == 1000) {        phy_reg4 = ADVERTISE_CSMA;        phy_reg9 = EX_ADVERTISE_1000HALF;    } else {        printk(KERN_ERR            "%s: XTemac: unsupported speed requested: %d\n", dev->name, speed);        return -1;    }    /*     * link status in register 1:     * first read / second read:     * 0               0           link is down     * 0               1           link is up (but it was down earlier)     * 1               0           link is down (but it was just up)     * 1               1           link is up     *     */    status = XTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, &phy_reg1);    status |= XTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, &phy_reg1);    status |= XTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MII_ADVERTISE, phy_reg4);    status |= XTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MII_EXADVERTISE, phy_reg9);    if (status != XST_SUCCESS) {        printk(KERN_ERR            "%s: XTemac: error accessing PHY: %d\n", dev->name, status);        return -1;    }    while (retries--) {        /* initiate an autonegotiation of the speed */        status = XTemac_PhyWrite(&lp->Emac, lp->gmii_addr, MII_BMCR, phy_reg0);        if (status != XST_SUCCESS) {            printk(KERN_ERR                "%s: XTemac: error starting autonegotiateion: %d\n", dev->name, status);            return -1;        }        wait_count = 20;  /* so we don't loop forever */        while (wait_count--) {            /* wait a bit for the negotiation to complete */            mdelay(500);            status = XTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, &phy_reg1);            status |= XTemac_PhyRead(&lp->Emac, lp->gmii_addr, MII_BMSR, &phy_reg1);            if (status != XST_SUCCESS) {                printk(KERN_ERR                    "%s: XTemac: error reading MII status %d\n", dev->name, status);                return -1;            }            if ((phy_reg1 & BMSR_LSTATUS) && (phy_reg1 & BMSR_ANEGCAPABLE)) break;        }        if (phy_reg1 & BMSR_LSTATUS) {            printk(KERN_INFO "%s: XTemac: We renegotiated the speed to: %d\n",                    dev->name, speed);            return 0;        } else {            printk(KERN_ERR                "%s: XTemac: Not able to set the speed to %d (status: 0x%0x)\n",                dev->name, speed, phy_reg1);            return -1;        }    }    printk(KERN_ERR        "%s: XTemac: Not able to set the speed to %d\n", dev->name, speed);    return -1;}// #define XILINX_PLB_TEMAC_3_00A_ML403_PHY_SUPPORT/* * This function sets up MAC's speed according to link speed of PHY * This function is specific to MARVELL 88E1111 PHY chip on Xilinx ML403 * board and assumes GMII interface is being used by the TEMAC */void set_mac_speed(struct net_local *lp){    u16 phylinkspeed;    struct net_device *dev = lp->ndev;    XStatus ret;#ifndef XILINX_PLB_TEMAC_3_00A_ML403_PHY_SUPPORT    int retry_count = 1;#endif    /*     * See comments at top for an explanation of     * XILINX_PLB_TEMAC_3_00A_ML403_PHY_SUPPORT     */#ifdef XILINX_PLB_TEMAC_3_00A_ML403_PHY_SUPPORT#define MARVELL_88E1111_PHY_SPECIFIC_STATUS_REG_OFFSET  17#define MARVELL_88E1111_LINKSPEED_MARK                  0xC000#define MARVELL_88E1111_LINKSPEED_SHIFT                 14#define MARVELL_88E1111_LINKSPEED_1000M                 0x0002#define MARVELL_88E1111_LINKSPEED_100M                  0x0001#define MARVELL_88E1111_LINKSPEED_10M                   0x0000    u16 RegValue;    /* Loop until read of PHY specific status register is successful. */    do {        ret = XTemac_PhyRead(&lp->Emac, lp->gmii_addr,                             MARVELL_88E1111_PHY_SPECIFIC_STATUS_REG_OFFSET,                             &RegValue);    } while (ret != XST_SUCCESS);    /* Get current link speed */    phylinkspeed = (RegValue & MARVELL_88E1111_LINKSPEED_MARK)                    >> MARVELL_88E1111_LINKSPEED_SHIFT;    /* Update TEMAC speed accordingly */    switch (phylinkspeed) {

⌨️ 快捷键说明

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