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

📄 ag7100.c

📁 linux下atheros的ag7100驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
            ag7100_set_pll(mac, SW_PLL);        }#else        ag7100_set_pll(mac, 0x00991099);#endif        ag7100_reg_rmw_clear(mac, AG7100_MAC_FIFO_CFG_5, (1 << 19));        break;    default:        assert(0);    }#ifdef CONFIG_ATHRS26_PHY    if(change_flag)         athrs26_phy_on(mac);#endif    printk(MODULE_NAME ": cfg_1: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_1));    printk(MODULE_NAME ": cfg_2: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_2));    printk(MODULE_NAME ": cfg_3: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_3));    printk(MODULE_NAME ": cfg_4: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_4));    printk(MODULE_NAME ": cfg_5: %#x\n", ag7100_reg_rd(mac, AG7100_MAC_FIFO_CFG_5));}/* * phy link state management */static intag7100_check_link(ag7100_mac_t *mac){    struct net_device  *dev     = mac->mac_dev;    int                 carrier = netif_carrier_ok(dev), fdx, phy_up;    ag7100_phy_speed_t  speed;    int                 rc;    /* The vitesse switch uses an indirect method to communicate phy status    * so it is best to limit the number of calls to what is necessary.    * However a single call returns all three pieces of status information.    *     * This is a trivial change to the other PHYs ergo this change.    *    */    rc = ag7100_get_link_status(mac->mac_unit, &phy_up, &fdx, &speed);    if (rc < 0)        goto done;    if (!phy_up)    {        if (carrier)        {            printk(MODULE_NAME ": unit %d: phy not up carrier %d\n", mac->mac_unit, carrier);            netif_carrier_off(dev);            netif_stop_queue(dev);        }        goto done;    }    /*    * phy is up. Either nothing changed or phy setttings changed while we     * were sleeping.    */    if ((fdx < 0) || (speed < 0))    {        printk(MODULE_NAME ": phy not connected?\n");        return 0;    }    if (carrier && (speed == mac->mac_speed) && (fdx == mac->mac_fdx))         goto done;    printk(MODULE_NAME ": unit %d phy is up...", mac->mac_unit);    printk("%s %s %s\n", mii_str[mac->mac_unit][mii_if(mac)],         spd_str[speed], dup_str[fdx]);    ag7100_set_mac_from_link(mac, speed, fdx);    printk(MODULE_NAME ": done cfg2 %#x ifctl %#x miictrl %#x \n",         ag7100_reg_rd(mac, AG7100_MAC_CFG2),         ag7100_reg_rd(mac, AG7100_MAC_IFCTL),        ar7100_reg_rd(mii_reg(mac)));    /*    * in business    */    netif_carrier_on(dev);    netif_start_queue(dev);done:    mod_timer(&mac->mac_phy_timer, jiffies + AG7100_PHY_POLL_SECONDS*HZ);    return 0;}static voidag7100_choose_phy(uint32_t phy_addr){#ifdef CONFIG_AR7100_EMULATION    if (phy_addr == 0x10)    {        ar7100_reg_rmw_set(AR7100_MII0_CTRL, (1 << 6));    }    else    {        ar7100_reg_rmw_clear(AR7100_MII0_CTRL, (1 << 6));    }#endif}uint16_tag7100_mii_read(int unit, uint32_t phy_addr, uint8_t reg){    ag7100_mac_t *mac   = ag7100_unit2mac(0);    uint16_t      addr  = (phy_addr << AG7100_ADDR_SHIFT) | reg, val;    volatile int           rddata;    uint16_t      ii = 0x1000;    ag7100_choose_phy(phy_addr);    ag7100_reg_wr(mac, AG7100_MII_MGMT_CMD, 0x0);    ag7100_reg_wr(mac, AG7100_MII_MGMT_ADDRESS, addr);    ag7100_reg_wr(mac, AG7100_MII_MGMT_CMD, AG7100_MGMT_CMD_READ);    do    {        udelay(5);        rddata = ag7100_reg_rd(mac, AG7100_MII_MGMT_IND) & 0x1;    }while(rddata && --ii);    val = ag7100_reg_rd(mac, AG7100_MII_MGMT_STATUS);    ag7100_reg_wr(mac, AG7100_MII_MGMT_CMD, 0x0);    return val;}voidag7100_mii_write(int unit, uint32_t phy_addr, uint8_t reg, uint16_t data){    ag7100_mac_t *mac   = ag7100_unit2mac(0);    uint16_t      addr  = (phy_addr << AG7100_ADDR_SHIFT) | reg;    volatile int rddata;    uint16_t      ii = 0x1000;    ag7100_choose_phy(phy_addr);    ag7100_reg_wr(mac, AG7100_MII_MGMT_ADDRESS, addr);    ag7100_reg_wr(mac, AG7100_MII_MGMT_CTRL, data);    do    {        rddata = ag7100_reg_rd(mac, AG7100_MII_MGMT_IND) & 0x1;    }while(rddata && --ii);}/* * Tx operation: * We do lazy reaping - only when the ring is "thresh" full. If the ring is  * full and the hardware is not even done with the first pkt we q'd, we turn * on the tx interrupt, stop all q's and wait for h/w to * tell us when its done with a "few" pkts, and then turn the Qs on again. * * Locking: * The interrupt only touches the ring when Q's stopped  => Tx is lockless,  * except when handling ring full. * * Desc Flushing: Flushing needs to be handled at various levels, broadly: * - The DDr FIFOs for desc reads. * - WB's for desc writes. */static voidag7100_handle_tx_full(ag7100_mac_t *mac){    u32         flags;    assert(!netif_queue_stopped(mac->mac_dev));    mac->mac_net_stats.tx_fifo_errors ++;    netif_stop_queue(mac->mac_dev);    spin_lock_irqsave(&mac->mac_lock, flags);    ag7100_intr_enable_tx(mac);    spin_unlock_irqrestore(&mac->mac_lock, flags);}/* ****************************** *  * Code under test - do not use * * ****************************** */static ag7100_desc_t *ag7100_get_tx_ds(ag7100_mac_t *mac, int *len, unsigned char **start){    ag7100_desc_t      *ds;    int                len_this_ds;    ag7100_ring_t      *r   = &mac->mac_txring;    /* force extra pkt if remainder less than 4 bytes */    if (*len > tx_len_per_ds)        if (*len < (tx_len_per_ds + 4))            len_this_ds = tx_len_per_ds - 4;        else            len_this_ds = tx_len_per_ds;    else        len_this_ds    = *len;    ds = &r->ring_desc[r->ring_head];    ag7100_trc_new(ds,"ds addr");    ag7100_trc_new(ds,"ds len");#ifdef CONFIG_AR9100    if(ag7100_tx_owned_by_dma(ds))        ag7100_dma_reset(mac);#else    assert(!ag7100_tx_owned_by_dma(ds));#endif    ds->pkt_size       = len_this_ds;    ds->pkt_start_addr = virt_to_phys(*start);    ds->more           = 1;    *len   -= len_this_ds;    *start += len_this_ds;    ag7100_ring_incr(r->ring_head);    return ds;}#if defined(CONFIG_ATHRS26_PHY)int#elsestatic int#endifag7100_hard_start(struct sk_buff *skb, struct net_device *dev){    ag7100_mac_t       *mac = (ag7100_mac_t *)dev->priv;    ag7100_ring_t      *r   = &mac->mac_txring;    ag7100_buffer_t    *bp;    ag7100_desc_t      *ds, *fds;    unsigned char      *start;    int                len;    int                nds_this_pkt;#if defined(CONFIG_AR9100) && defined(CONFIG_VITESSE_8601_7395_PHY)    static int         vsc73xx_config;#endif#if defined(CONFIG_AR9100) && defined(CONFIG_VITESSE_8601_7395_PHY)    if (unlikely(vsc73xx_config == 0)) {        vsc73xx_wr(7,0,5,0x33);        vsc73xx_config = 1;    }#endif#ifdef VSC73XX_DEBUG    {        static int vsc73xx_dbg;        if (vsc73xx_dbg == 0) {            vsc73xx_get_link_status_dbg();            vsc73xx_dbg = 1;        }        vsc73xx_dbg = (vsc73xx_dbg + 1) % 10;    }#endif#if defined(CONFIG_ATHRS26_PHY) && defined(HEADER_EN)    /* add header to normal frames */    /* check if normal frames */    if ((mac->mac_unit == 0) && (!((skb->cb[0] == 0x7f) && (skb->cb[1] == 0x5d))))    {        skb_push(skb, HEADER_LEN);        skb->data[0] = 0x10; /* broadcast = 0; from_cpu = 0; reserved = 1; port_num = 0 */        skb->data[1] = 0x80; /* reserved = 0b10; priority = 0; type = 0 (normal) */    }#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)    if(unlikely((skb->len <= 0)         || (skb->len > (dev->mtu + ETH_HLEN + HEADER_LEN + 4))))    { /*vlan tag length = 4*/        printk(MODULE_NAME ": [%d] bad skb, dev->mtu=%d,ETH_HLEN=%d len %d\n", mac->mac_unit, dev->mtu, ETH_HLEN,  skb->len);        goto dropit;    }#else    if(unlikely((skb->len <= 0)         || (skb->len > (dev->mtu + ETH_HLEN + HEADER_LEN))))    {        printk(MODULE_NAME ": [%d] bad skb, dev->mtu=%d,ETH_HLEN=%d len %d\n", mac->mac_unit, dev->mtu, ETH_HLEN,  skb->len);        goto dropit;    }#endif  #else#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)    if(unlikely((skb->len <= 0) || (skb->len > (dev->mtu + ETH_HLEN + 4))))    {  /*vlan tag length = 4*/        printk(MODULE_NAME ": bad skb, len %d\n", skb->len);        goto dropit;    }#else    if(unlikely((skb->len <= 0) || (skb->len > (dev->mtu + ETH_HLEN))))    {        printk(MODULE_NAME ": bad skb, len %d\n", skb->len);        goto dropit;    }#endif    #endif    if (ag7100_tx_reap_thresh(mac))         ag7100_tx_reap(mac);    ag7100_trc_new(r->ring_head,"hard-stop hd");    ag7100_trc_new(r->ring_tail,"hard-stop tl");    ag7100_trc_new(skb->len,    "len this pkt");    ag7100_trc_new(skb->data,   "ptr 2 pkt");    dma_cache_wback((unsigned long)skb->data, skb->len);    bp          = &r->ring_buffer[r->ring_head];    bp->buf_pkt = skb;    len         = skb->len;    start       = skb->data;    assert(len>4);    nds_this_pkt = 1;    fds = ds = ag7100_get_tx_ds(mac, &len, &start);    while (len>0)    {        ds = ag7100_get_tx_ds(mac, &len, &start);        nds_this_pkt++;        ag7100_tx_give_to_dma(ds);    }    ds->more        = 0;    ag7100_tx_give_to_dma(fds);    bp->buf_lastds  = ds;    bp->buf_nds     = nds_this_pkt;    ag7100_trc_new(ds,"last ds");    ag7100_trc_new(nds_this_pkt,"nmbr ds for this pkt");    wmb();    mac->net_tx_packets ++;    mac->net_tx_bytes += skb->len;    ag7100_trc(ag7100_reg_rd(mac, AG7100_DMA_TX_CTRL),"dma idle");    ag7100_tx_start(mac);    if (unlikely(ag7100_tx_ring_full(mac)))        ag7100_handle_tx_full(mac);    dev->trans_start = jiffies;    return NETDEV_TX_OK;dropit:    printk(MODULE_NAME ": dropping skb %08x\n", skb);    kfree_skb(skb);    return NETDEV_TX_OK;}/* * Interrupt handling: * - Recv NAPI style (refer to Documentation/networking/NAPI) * *   2 Rx interrupts: RX and Overflow (OVF). *   - If we get RX and/or OVF, schedule a poll. Turn off _both_ interurpts.  * *   - When our poll's called, we *     a) Have one or more packets to process and replenish *     b) The hardware may have stopped because of an OVF. * *   - We process and replenish as much as we can. For every rcvd pkt  *     indicated up the stack, the head moves. For every such slot that we *     replenish with an skb, the tail moves. If head catches up with the tail *     we're OOM. When all's done, we consider where we're at: * *      if no OOM: *      - if we're out of quota, let the ints be disabled and poll scheduled. *      - If we've processed everything, enable ints and cancel poll. * *      If OOM: *      - Start a timer. Cancel poll. Ints still disabled.  *        If the hardware's stopped, no point in restarting yet.  * *      Note that in general, whether we're OOM or not, we still try to *      indicate everything recvd, up. * * Locking:  * The interrupt doesnt touch the ring => Rx is lockless * */static irqreturn_tag7100_intr(int cpl, void *dev_id, struct pt_regs *regs){    struct net_device *dev  = (struct net_device *)dev_id;    ag7100_mac_t      *mac  = (ag7100_mac_t *)dev->priv;    int   isr, imr, handled = 0;    isr   = ag7100_get_isr(mac);    imr   = ag7100_reg_rd(mac, AG7100_DMA_INTR_MASK);    ag7100_trc(isr,"isr");    ag7100_trc(imr,"imr");    assert(isr == (isr & imr));    if (likely(isr & (AG7100_INTR_RX | AG7100_INTR_RX_OVF)))    {        handled = 1;        if (likely(netif_rx_schedule_prep(dev)))        {            ag7100_intr_disable_recv(mac);            __netif_rx_schedule(dev);        }        else        {            printk(MODULE_NAME ": driver bug! interrupt while in poll\n");            assert(0);            ag7100_intr_disable_recv(mac);        }        /*ag7100_recv_packets(dev, mac, 200, &budget);*/    }    if (likely(isr & AG7100_INTR_TX))    {        handled = 1;        ag7100_intr_ack_tx(mac);        ag7100_tx_reap(mac);    }    if (unlikely(isr & AG7100_INTR_RX_BUS_ERROR))    {        assert(0);        handled = 1;        ag7100_intr_ack_rxbe(mac);    }    if (unlikely(isr & AG7100_INTR_TX_BUS_ERROR))    {        assert(0);        handled = 1;        ag7100_intr_ack_txbe(mac);    }

⌨️ 快捷键说明

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