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

📄 ag7100.c

📁 linux下atheros的ag7100驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
    if (!handled)    {        assert(0);        printk(MODULE_NAME ": unhandled intr isr %#x\n", isr);    }    return IRQ_HANDLED;} /*  * Rx and Tx DMA hangs and goes to an invalid state in HOWL boards   * when the link partner is forced to 10/100 Mode.By resetting the MAC  * we are able to recover from this state.This is a software  WAR and  * will be removed once we have a hardware fix.   */#ifdef CONFIG_AR9100void ag7100_dma_reset(ag7100_mac_t *mac){    uint32_t mask;    if(mac->mac_unit)        mask = AR7100_RESET_GE1_MAC;    else        mask = AR7100_RESET_GE0_MAC;    ar7100_reg_rmw_set(AR7100_RESET, mask);    mdelay(100);    ar7100_reg_rmw_clear(AR7100_RESET, mask);    mdelay(100);    ag7100_intr_disable_recv(mac);    schedule_work(&mac->mac_tx_timeout);}#endifstatic intag7100_poll(struct net_device *dev, int *budget){    ag7100_mac_t       *mac       = (ag7100_mac_t *)dev->priv;    int work_done,      max_work  = min(*budget, dev->quota), status = 0;    ag7100_rx_status_t  ret;    u32                 flags;    ret = ag7100_recv_packets(dev, mac, max_work, &work_done);    dev->quota  -= work_done;    *budget     -= work_done;#ifdef CONFIG_AR9100    if(ret == AG7100_RX_DMA_HANG)    {        status = 0;        netif_rx_complete(dev);        ag7100_dma_reset(mac);        return status;    }#endif    if (likely(ret == AG7100_RX_STATUS_DONE))    {        netif_rx_complete(dev);        spin_lock_irqsave(&mac->mac_lock, flags);        ag7100_intr_enable_recv(mac);        spin_unlock_irqrestore(&mac->mac_lock, flags);    }    else if (likely(ret == AG7100_RX_STATUS_NOT_DONE))    {        /*        * We have work left        */        status = 1;    }    else if (ret == AG7100_RX_STATUS_OOM)    {        printk(MODULE_NAME ": oom..?\n");        /*         * Start timer, stop polling, but do not enable rx interrupts.        */        mod_timer(&mac->mac_oom_timer, jiffies+1);        netif_rx_complete(dev);    }    return status;}static intag7100_recv_packets(struct net_device *dev, ag7100_mac_t *mac,     int quota, int *work_done){    ag7100_ring_t       *r     = &mac->mac_rxring;    ag7100_desc_t       *ds;    ag7100_buffer_t     *bp;    struct sk_buff      *skb;    ag7100_rx_status_t   ret   = AG7100_RX_STATUS_DONE;    int head = r->ring_head, len, status, iquota = quota, more_pkts, rep;    ag7100_trc(iquota,"iquota");#if !defined(CONFIG_AR9100)    status = ag7100_reg_rd(mac, AG7100_DMA_RX_STATUS);#endifprocess_pkts:    ag7100_trc(status,"status");#if !defined(CONFIG_AR9100)    /*    * Under stress, the following assertion fails.    *    * On investigation, the following `appears' to happen.    *   - pkts received    *   - rx intr    *   - poll invoked    *   - process received pkts    *   - replenish buffers    *   - pkts received    *    *   - NO RX INTR & STATUS REG NOT UPDATED <---    *    *   - s/w doesn't process pkts since no intr    *   - eventually, no more buffers for h/w to put    *     future rx pkts    *   - RX overflow intr    *   - poll invoked    *   - since status reg is not getting updated    *     following assertion fails..    *    * Ignore the status register.  Regardless of this    * being a rx or rx overflow, we have packets to process.    * So, we go ahead and receive the packets..    */    assert((status & AG7100_RX_STATUS_PKT_RCVD));    assert((status >> 16));#endif    /*    * Flush the DDR FIFOs for our gmac    */    ar7100_flush_ge(mac->mac_unit);    assert(quota > 0); /* WCL */    while(quota)    {        ds    = &r->ring_desc[head];        ag7100_trc(head,"hd");        ag7100_trc(ds,  "ds");        if (ag7100_rx_owned_by_dma(ds))        {#ifdef CONFIG_AR9100            if(quota == iquota)            {                *work_done = quota = 0;                return AG7100_RX_DMA_HANG;            }#else            assert(quota != iquota); /* WCL */#endif            break;        }        ag7100_intr_ack_rx(mac);        bp                  = &r->ring_buffer[head];        len                 = ds->pkt_size;        skb                 = bp->buf_pkt;        assert(skb);        skb_put(skb, len - ETHERNET_FCS_SIZE);#if defined(CONFIG_ATHRS26_PHY) && defined(HEADER_EN)        uint8_t type;        uint16_t def_vid;        if(mac->mac_unit == 0)        {            type = (skb->data[1]) & 0xf;            if (type == NORMAL_PACKET)            {#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)            	                /*cpu egress tagged*/                if (is_cpu_egress_tagged())                {                    if ((skb->data[12 + HEADER_LEN] != 0x81) || (skb->data[13 + HEADER_LEN] != 0x00))                    {                        def_vid = athrs26_defvid_get(skb->data[0] & 0xf);                        skb_push(skb, 2); /* vid lenghth - header length */                        memmove(&skb->data[0], &skb->data[4], 12); /*remove header and add vlan tag*/                        skb->data[12] = 0x81;                        skb->data[13] = 0x00;                        skb->data[14] = (def_vid >> 8) & 0xf;                        skb->data[15] = def_vid & 0xff;                    }                }                else#endif                                    skb_pull(skb, 2); /* remove attansic header */                mac->net_rx_packets ++;                mac->net_rx_bytes += skb->len;                /*                * also pulls the ether header                */                skb->protocol       = eth_type_trans(skb, dev);                skb->dev            = dev;                bp->buf_pkt         = NULL;                dev->last_rx        = jiffies;                quota--;                netif_receive_skb(skb);            }            else            {                mac->net_rx_packets ++;                mac->net_rx_bytes += skb->len;                bp->buf_pkt         = NULL;                dev->last_rx        = jiffies;                quota--;                if (type == READ_WRITE_REG_ACK)                {                    header_receive_skb(skb);                }                else                {                    kfree_skb(skb);                }            }        }else        {            mac->net_rx_packets ++;            mac->net_rx_bytes += skb->len;            /*            * also pulls the ether header            */            skb->protocol       = eth_type_trans(skb, dev);            skb->dev            = dev;            bp->buf_pkt         = NULL;            dev->last_rx        = jiffies;            quota--;            netif_receive_skb(skb);        }#else        mac->net_rx_packets ++;        mac->net_rx_bytes += skb->len;        /*        * also pulls the ether header        */        skb->protocol       = eth_type_trans(skb, dev);        skb->dev            = dev;        bp->buf_pkt         = NULL;        dev->last_rx        = jiffies;        quota--;        netif_receive_skb(skb);#endif        ag7100_ring_incr(head);    }    assert(iquota != quota);    r->ring_head   =  head;    rep = ag7100_rx_replenish(mac);#ifdef CONFIG_AR9100    if(rep < 0)    {        *work_done =0 ;        return AG7100_RX_DMA_HANG;    }#endif    /*    * let's see what changed while we were slogging.    * ack Rx in the loop above is no flush version. It will get flushed now.    */    status       =  ag7100_reg_rd(mac, AG7100_DMA_RX_STATUS);    more_pkts    =  (status & AG7100_RX_STATUS_PKT_RCVD);    ag7100_trc(more_pkts,"more_pkts");    if (!more_pkts) goto done;    /*    * more pkts arrived; if we have quota left, get rolling again    */    if (quota)      goto process_pkts;    /*    * out of quota    */    ret = AG7100_RX_STATUS_NOT_DONE;done:    *work_done   = (iquota - quota);    if (unlikely(ag7100_rx_ring_full(mac)))         return AG7100_RX_STATUS_OOM;    /*    * !oom; if stopped, restart h/w    */    if (unlikely(status & AG7100_RX_STATUS_OVF))    {        mac->net_rx_over_errors ++;        ag7100_intr_ack_rxovf(mac);        ag7100_rx_start(mac);    }    return ret;}static struct sk_buff *    ag7100_buffer_alloc(void){    struct sk_buff *skb;    skb = dev_alloc_skb(AG7100_RX_BUF_SIZE);    if (unlikely(!skb))        return NULL;    skb_reserve(skb, AG7100_RX_RESERVE);    return skb;}static voidag7100_buffer_free(struct sk_buff *skb){    if (in_irq())        dev_kfree_skb_irq(skb);    else        dev_kfree_skb(skb);}/* * Head is the first slot with a valid buffer. Tail is the last slot  * replenished. Tries to refill buffers from tail to head. */static intag7100_rx_replenish(ag7100_mac_t *mac){    ag7100_ring_t   *r     = &mac->mac_rxring;    int              head  = r->ring_head, tail = r->ring_tail, refilled = 0;    ag7100_desc_t   *ds;    ag7100_buffer_t *bf;    ag7100_trc(head,"hd");    ag7100_trc(tail,"tl");    do    {        bf                  = &r->ring_buffer[tail];        ds                  = &r->ring_desc[tail];        ag7100_trc(ds,"ds");#ifdef CONFIG_AR9100        if(ag7100_rx_owned_by_dma(ds))        {            return -1;        }#else		        assert(!ag7100_rx_owned_by_dma(ds));#endif        assert(!bf->buf_pkt);        bf->buf_pkt         = ag7100_buffer_alloc();        if (!bf->buf_pkt)        {            printk(MODULE_NAME ": outta skbs!\n");            break;        }        dma_cache_inv((unsigned long)bf->buf_pkt->data, AG7100_RX_BUF_SIZE);        ds->pkt_start_addr  = virt_to_phys(bf->buf_pkt->data);        ag7100_rx_give_to_dma(ds);        refilled ++;        ag7100_ring_incr(tail);    } while(tail != head);    /*    * Flush descriptors    */    wmb();    r->ring_tail = tail;    ag7100_trc(refilled,"refilled");    return refilled;}/*  * Reap from tail till the head or whenever we encounter an unxmited packet. */static intag7100_tx_reap(ag7100_mac_t *mac){    ag7100_ring_t   *r     = &mac->mac_txring;    int              head  = r->ring_head, tail = r->ring_tail, reaped = 0, i;    ag7100_desc_t   *ds;    ag7100_buffer_t *bf;    uint32_t    flags;    ag7100_trc_new(head,"hd");    ag7100_trc_new(tail,"tl");    ar7100_flush_ge(mac->mac_unit);    while(tail != head)    {        ds   = &r->ring_desc[tail];        ag7100_trc_new(ds,"ds");        if(ag7100_tx_owned_by_dma(ds))            break;        bf      = &r->ring_buffer[tail];        assert(bf->buf_pkt);        ag7100_trc_new(bf->buf_lastds,"lastds");        if(ag7100_tx_owned_by_dma(bf->buf_lastds))            break;        for(i = 0; i < bf->buf_nds; i++)        {            ag7100_intr_ack_tx(mac);            ag7100_ring_incr(tail);        }        ag7100_buffer_free(bf->buf_pkt);        bf->buf_pkt = NULL;        reaped ++;    }    r->ring_tail = tail;    if (netif_queue_stopped(mac->mac_dev) &&        (ag7100_ndesc_unused(mac, r) >= AG7100_TX_QSTART_THRESH) &&        netif_carrier_ok(mac->mac_dev))    {        if (ag7100_reg_rd(mac, AG7100_DMA_INTR_MASK) & AG7100_INTR_TX)        {            spin_lock_irqsave(&mac->mac_lock, flags);            ag7100_intr_disable_tx(mac);

⌨️ 快捷键说明

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