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

📄 ag7100.c

📁 linux下atheros的ag7100驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
#include <linux/stddef.h>#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <asm/byteorder.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/dma-mapping.h>#include <linux/bitops.h>#include <asm/irq.h>#include <asm/io.h>#include <net/sch_generic.h>#include "ag7100.h"#include "ag7100_phy.h"#include "ag7100_trc.h"static ag7100_mac_t *ag7100_macs[2];static void ag7100_hw_setup(ag7100_mac_t *mac);static void ag7100_hw_stop(ag7100_mac_t *mac);static void ag7100_oom_timer(unsigned long data);static int  ag7100_check_link(ag7100_mac_t *mac);static int  ag7100_tx_alloc(ag7100_mac_t *mac);static int  ag7100_rx_alloc(ag7100_mac_t *mac);static void ag7100_rx_free(ag7100_mac_t *mac);static void ag7100_tx_free(ag7100_mac_t *mac);static int  ag7100_ring_alloc(ag7100_ring_t *r, int count);static int  ag7100_rx_replenish(ag7100_mac_t *mac);static int  ag7100_tx_reap(ag7100_mac_t *mac);static void ag7100_ring_release(ag7100_mac_t *mac, ag7100_ring_t  *r);static void ag7100_ring_free(ag7100_ring_t *r);static void ag7100_tx_timeout_task(ag7100_mac_t *mac);static int  ag7100_poll(struct net_device *dev, int *budget);#ifdef CONFIG_AR9100void ag7100_dma_reset(ag7100_mac_t *mac);#endifstatic int  ag7100_recv_packets(struct net_device *dev, ag7100_mac_t *mac,    int max_work, int *work_done);static irqreturn_t ag7100_intr(int cpl, void *dev_id, struct pt_regs *regs);static struct sk_buff * ag7100_buffer_alloc(void);char *mii_str[2][4] = {    {"GMii", "Mii", "RGMii", "RMii"},    {"RGMii", "RMii"}};char *spd_str[] = {"10Mbps", "100Mbps", "1000Mbps"};char *dup_str[] = {"half duplex", "full duplex"};#define MODULE_NAME "AG7100"/* if 0 compute in init */int tx_len_per_ds = 0;module_param(tx_len_per_ds, int, 0);MODULE_PARM_DESC(tx_len_per_ds, "Size of DMA chunk");/* if 0 compute in init */int tx_max_desc_per_ds_pkt=0;/* if 0 compute in init */#ifdef CONFIG_AR9100int fifo_3 = 0x780008;#elseint fifo_3 = 0;#endifmodule_param(fifo_3, int, 0);MODULE_PARM_DESC(fifo_3, "fifo cfg 3 settings");int mii0_if = AG7100_MII0_INTERFACE;module_param(mii0_if, int, 0);MODULE_PARM_DESC(mii0_if, "mii0 connect");int mii1_if = AG7100_MII1_INTERFACE;module_param(mii1_if, int, 0);MODULE_PARM_DESC(mii1_if, "mii1 connect");#ifndef CONFIG_AR9100int gige_pll = 0x0110000;#else#define SW_PLL 0x1f000000ulint gige_pll = 0x1a000000;#endifmodule_param(gige_pll, int, 0);MODULE_PARM_DESC(gige_pll, "Pll for (R)GMII if");/* * Cfg 5 settings* Weed out junk frames (CRC errored, short collision'ed frames etc.)*/int fifo_5 = 0x7ffef;module_param(fifo_5, int, 0);MODULE_PARM_DESC(fifo_5, "fifo cfg 5 settings");#define addr_to_words(addr, w1, w2)  {                                 \    w1 = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; \    w2 = (addr[4] << 24) | (addr[5] << 16) | 0;                        \}/* * Defines specific to this implemention */#ifndef CONFIG_AG7100_LEN_PER_TX_DS#error Please run menuconfig and define CONFIG_AG7100_LEN_PER_TX_DS#endif#ifndef CONFIG_AG7100_NUMBER_TX_PKTS#error Please run menuconfig and define CONFIG_AG7100_NUMBER_TX_PKTS#endif#ifndef CONFIG_AG7100_NUMBER_RX_PKTS#error Please run menuconfig and define CONFIG_AG7100_NUMBER_RX_PKTS#endif#define AG7100_TX_FIFO_LEN          2048#define AG7100_TX_MIN_DS_LEN        128#define AG7100_TX_MAX_DS_LEN        AG7100_TX_FIFO_LEN#define AG7100_TX_MTU_LEN           1536#define AG7100_TX_DESC_CNT           CONFIG_AG7100_NUMBER_TX_PKTS*tx_max_desc_per_ds_pkt#define AG7100_TX_REAP_THRESH        AG7100_TX_DESC_CNT/2#define AG7100_TX_QSTART_THRESH      4*tx_max_desc_per_ds_pkt#define AG7100_RX_DESC_CNT           CONFIG_AG7100_NUMBER_RX_PKTS#define AG7100_NAPI_WEIGHT           64#define AG7100_PHY_POLL_SECONDS      2int dma_flag = 0;static inline int ag7100_tx_reap_thresh(ag7100_mac_t *mac){    ag7100_ring_t *r = &mac->mac_txring;    return (ag7100_ndesc_unused(mac, r) < AG7100_TX_REAP_THRESH);}static inline int ag7100_tx_ring_full(ag7100_mac_t *mac){    ag7100_ring_t *r = &mac->mac_txring;    ag7100_trc_new(ag7100_ndesc_unused(mac, r),"tx ring full");    return (ag7100_ndesc_unused(mac, r) < tx_max_desc_per_ds_pkt + 2);}static intag7100_open(struct net_device *dev){    unsigned int w1 = 0, w2 = 0;    ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv;    int st;#if defined(CONFIG_AR9100) && defined(SWITCH_AHB_FREQ)    u32 tmp_pll, pll;#endif    assert(mac);    st = request_irq(mac->mac_irq, ag7100_intr, 0, dev->name, dev);    if (st < 0)    {        printk(MODULE_NAME ": request irq %d failed %d\n", mac->mac_irq, st);        return 1;    }    if (ag7100_tx_alloc(mac)) goto tx_failed;    if (ag7100_rx_alloc(mac)) goto rx_failed;    ag7100_hw_setup(mac);#if defined(CONFIG_AR9100) && defined(SWITCH_AHB_FREQ)    /*     * Reduce the AHB frequency to 100MHz while setting up the     * S26 phy.     */    pll= ar7100_reg_rd(AR7100_PLL_CONFIG);    tmp_pll = pll& ~((PLL_DIV_MASK << PLL_DIV_SHIFT) | (PLL_REF_DIV_MASK << PLL_REF_DIV_SHIFT));    tmp_pll = tmp_pll | (0x64 << PLL_DIV_SHIFT) |        (0x5 << PLL_REF_DIV_SHIFT) | (1 << AHB_DIV_SHIFT);    ar7100_reg_wr_nf(AR7100_PLL_CONFIG, tmp_pll);    udelay(100*1000);#endif#if defined(CONFIG_ATHRS26_PHY)    /* if using header for register configuration, we have to     */    /* configure s26 register after frame transmission is enabled */    if (mac->mac_unit == 1) /* wan phy */        athrs26_reg_init();#endif    ag7100_phy_setup(mac->mac_unit);#if defined(CONFIG_AR9100) && defined(SWITCH_AHB_FREQ)    ar7100_reg_wr_nf(AR7100_PLL_CONFIG, pll);    udelay(100*1000);#endif    /*    * set the mac addr    */    addr_to_words(dev->dev_addr, w1, w2);    ag7100_reg_wr(mac, AG7100_GE_MAC_ADDR1, w1);    ag7100_reg_wr(mac, AG7100_GE_MAC_ADDR2, w2);    /*    * phy link mgmt    */    init_timer(&mac->mac_phy_timer);    mac->mac_phy_timer.data     = (unsigned long)mac;    mac->mac_phy_timer.function = ag7100_check_link;    ag7100_check_link(mac);    dev->trans_start = jiffies;    ag7100_int_enable(mac);    ag7100_rx_start(mac);    ag7100_start_rx_count(mac);    return 0;rx_failed:    ag7100_tx_free(mac);tx_failed:    free_irq(mac->mac_irq, dev);    return 1;}static intag7100_stop(struct net_device *dev){    ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv;    int flags;    spin_lock_irqsave(&mac->mac_lock, flags);    netif_stop_queue(dev);    netif_carrier_off(dev);    ag7100_hw_stop(mac);    free_irq(mac->mac_irq, dev);    ag7100_tx_free(mac);    ag7100_rx_free(mac);    del_timer(&mac->mac_phy_timer);    spin_unlock_irqrestore(&mac->mac_lock, flags);    /*ag7100_trc_dump();*/    return 0;}static voidag7100_hw_setup(ag7100_mac_t *mac){    ag7100_ring_t *tx = &mac->mac_txring, *rx = &mac->mac_rxring;    ag7100_desc_t *r0, *t0;    ag7100_reg_wr(mac, AG7100_MAC_CFG1, (AG7100_MAC_CFG1_RX_EN |        AG7100_MAC_CFG1_TX_EN));    ag7100_reg_rmw_set(mac, AG7100_MAC_CFG2, (AG7100_MAC_CFG2_PAD_CRC_EN |        AG7100_MAC_CFG2_LEN_CHECK));    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_0, 0x1f00);    /*    * set the mii if type - NB reg not in the gigE space    */    ar7100_reg_wr(mii_reg(mac), mii_if(mac));    ag7100_reg_wr(mac, AG7100_MAC_MII_MGMT_CFG, AG7100_MGMT_CFG_CLK_DIV_20);#ifdef CONFIG_AR7100_EMULATION    ag7100_reg_rmw_set(mac, AG7100_MAC_FIFO_CFG_4, 0x3ffff);    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_1, 0xfff0000);    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_2, 0x1fff);#else    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_1, 0xfff0000);    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_2, 0x1fff);    /*    * Weed out junk frames (CRC errored, short collision'ed frames etc.)    */    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_4, 0xffff);    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_5, 0x7ffef);#endif    t0  =  &tx->ring_desc[0];    r0  =  &rx->ring_desc[0];    ag7100_reg_wr(mac, AG7100_DMA_TX_DESC, ag7100_desc_dma_addr(tx, t0));    ag7100_reg_wr(mac, AG7100_DMA_RX_DESC, ag7100_desc_dma_addr(rx, r0));    printk(MODULE_NAME ": cfg1 %#x cfg2 %#x\n", ag7100_reg_rd(mac, AG7100_MAC_CFG1),        ag7100_reg_rd(mac, AG7100_MAC_CFG2));}static voidag7100_hw_stop(ag7100_mac_t *mac){    ag7100_rx_stop(mac);    ag7100_tx_stop(mac);    ag7100_int_disable(mac);    /*    * put everything into reset.    */    ag7100_reg_rmw_set(mac, AG7100_MAC_CFG1, AG7100_MAC_CFG1_SOFT_RST);}/* * program the usb pll (misnomer) to genrate appropriate clock * Write 2 into control field * Write pll value  * Write 3 into control field  * Write 0 into control field  */#ifdef CONFIG_AR9100#define ag7100_pll_shift(_mac)      (((_mac)->mac_unit) ? 22: 20)#define ag7100_pll_offset(_mac)     \    (((_mac)->mac_unit) ? AR9100_ETH_INT1_CLK : \                          AR9100_ETH_INT0_CLK)#else#define ag7100_pll_shift(_mac)      (((_mac)->mac_unit) ? 19: 17)#define ag7100_pll_offset(_mac)     \    (((_mac)->mac_unit) ? AR7100_USB_PLL_GE1_OFFSET : \                          AR7100_USB_PLL_GE0_OFFSET)#endifstatic voidag7100_set_pll(ag7100_mac_t *mac, unsigned int pll){#ifdef CONFIG_AR9100#define ETH_PLL_CONFIG AR9100_ETH_PLL_CONFIG#else#define ETH_PLL_CONFIG AR7100_USB_PLL_CONFIG#endif     uint32_t shift, reg, val;    shift = ag7100_pll_shift(mac);    reg   = ag7100_pll_offset(mac);    val  = ar7100_reg_rd(ETH_PLL_CONFIG);    val &= ~(3 << shift);    val |=  (2 << shift);    ar7100_reg_wr(ETH_PLL_CONFIG, val);    udelay(100);    ar7100_reg_wr(reg, pll);    val |=  (3 << shift);    ar7100_reg_wr(ETH_PLL_CONFIG, val);    udelay(100);    val &= ~(3 << shift);    ar7100_reg_wr(ETH_PLL_CONFIG, val);    udelay(100);    printk(MODULE_NAME ": pll reg %#x: %#x  ", reg, ar7100_reg_rd(reg));}/* * Several fields need to be programmed based on what the PHY negotiated * Ideally we should quiesce everything before touching the pll, but: * 1. If its a linkup/linkdown, we dont care about quiescing the traffic. * 2. If its a single gigE PHY, this can only happen on lup/ldown. * 3. If its a 100Mpbs switch, the link will always remain at 100 (or nothing) * 4. If its a gigE switch then the speed should always be set at 1000Mpbs,  *    and the switch should provide buffering for slower devices. * * XXX Only gigE PLL can be changed as a parameter for now. 100/10 is hardcoded. * XXX Need defines for them - * XXX FIFO settings based on the mode */static voidag7100_set_mac_from_link(ag7100_mac_t *mac, ag7100_phy_speed_t speed, int fdx){#ifdef CONFIG_ATHRS26_PHY    int change_flag = 0;    if(mac->mac_speed !=  speed)        change_flag = 1;    if(change_flag)    {        athrs26_phy_off(mac);        athrs26_mac_speed_set(mac, speed);    }#endif    mac->mac_speed =  speed;    mac->mac_fdx   =  fdx;    ag7100_set_mii_ctrl_speed(mac, speed);    ag7100_set_mac_duplex(mac, fdx);    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_3, fifo_3);#ifndef CONFIG_AR9100    ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_5, fifo_5);#endif    switch (speed)    {    case AG7100_PHY_SPEED_1000T:#ifdef CONFIG_AR9100        ag7100_reg_wr(mac, AG7100_MAC_FIFO_CFG_3, 0x780fff);#endif        ag7100_set_mac_if(mac, 1);#ifdef CONFIG_AR9100        if (mac->mac_unit == 0)        { /* eth0 */            ag7100_set_pll(mac, gige_pll);        }        else        {            ag7100_set_pll(mac, SW_PLL);        }#else        ag7100_set_pll(mac, gige_pll);#endif        ag7100_reg_rmw_set(mac, AG7100_MAC_FIFO_CFG_5, (1 << 19));        break;    case AG7100_PHY_SPEED_100TX:        ag7100_set_mac_if(mac, 0);        ag7100_set_mac_speed(mac, 1);#ifndef CONFIG_AR7100_EMULATION#ifdef CONFIG_AR9100        if (mac->mac_unit == 0)        { /* eth0 */            ag7100_set_pll(mac, 0x13000a44);        }        else        {            ag7100_set_pll(mac, SW_PLL);        }#else        ag7100_set_pll(mac, 0x0001099);#endif#endif        ag7100_reg_rmw_clear(mac, AG7100_MAC_FIFO_CFG_5, (1 << 19));        break;    case AG7100_PHY_SPEED_10T:        ag7100_set_mac_if(mac, 0);        ag7100_set_mac_speed(mac, 0);#ifdef CONFIG_AR9100        if (mac->mac_unit == 0)        { /* eth0 */            ag7100_set_pll(mac, 0x00441099);        }        else        {

⌨️ 快捷键说明

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