AR9344中ethernet处理方式分析

http://bbs.chinaunix.net/thread-1960516-1-1.html
9344 ethernet数据接收代码分析
在板的ethernet只有一个网卡,在系统处理话的时候有如下类似代码:
    for(i = 0; i < ATHR_GMAC_NMACS; i++)
    {

        dev = alloc_etherdev(ATHR_MAC_ETHERDEV_SZ);
        if (!dev)
        {
            printk(MODULE_NAME ": unable to allocate mac\n");
            return 1;
        }
        ATHR_MAC_NETPRIV(mac,dev);
        memset(mac, 0, sizeof(athr_gmac_t));

        mac->mac_dev       = dev;
        mac->mac_unit      = i;
        mac->mac_base      = athr_gmac_base(i);
        mac->mac_irq       = athr_gmac_irq(i);//以太网申请的中断号。
        mac->mac_noacs     = 1;
        mac->num_tx_desc   = athr_tx_desc_num[i];
        mac->num_rx_desc   = athr_rx_desc_num[i];
        mac->reap_thresh   = athr_tx_desc_num[i] / 2;
        mac->qstart_thresh = 4 * tx_max_desc_per_ds_pkt;
        mac->mac_speed     = ATHR_PHY_SPEED_UNKNOWN;
       ..............................................
       
     }
在之前的中断处理过程说明过,我们在申请中断之前,必须将中断注册到OS中。
/proc # cat interrupts
           CPU0      
  4:       3604            MIPS  eth0
  6:          0            MIPS  cascade
  7:     737861            MIPS  timer
 18:          0        ATH MISC  cascade
 19:        317        ATH MISC  serial
 48:          0        ATH GPIO  SW JUMPSTART/FACTORY RESET

有上面的可以知道,我们申请的中断号为4,其代码中也有定义#define ATH_CPU_IRQ_GE0 ATH_CPU_IRQ_BASE+4
当收到数据时,会触发中断:其执行如下代码:
asmlinkage void plat_irq_dispatch(void)
{
 int pending = read_c0_status() & read_c0_cause();
#if 0
 if (!(pending & CAUSEF_IP7))
  printk("%s: in irq dispatch \n", __func__);
#endif
 if (pending & CAUSEF_IP7) {
  do_IRQ(ATH_CPU_IRQ_TIMER);
  ath_aphang_timer_fn();
 }
 else if (pending & CAUSEF_IP2)
  ath_dispatch_wlan_intr();

 else if (pending & CAUSEF_IP4) //操作系统调度执行注册的中断处理函数。
  do_IRQ(ATH_CPU_IRQ_GE0);

 else if (pending & CAUSEF_IP5)
  do_IRQ(ATH_CPU_IRQ_GE1);

 else if (pending & CAUSEF_IP3)
  do_IRQ(ATH_CPU_IRQ_USB);

 else if (pending & CAUSEF_IP6)
  ath_dispatch_misc_intr();

 /*
  * Some PCI devices are write to clear. These writes are posted and might
  * require a flush (r8169.c e.g.). Its unclear what will have more
  * performance impact - flush after every interrupt or taking a few
  * "spurious" interrupts. For now, its the latter.
  */
 /*else
    printk("spurious IRQ pending: 0x%x\n", pending); */
}
注册的中断处理函数如下:
    st = request_irq(mac->mac_irq, athr_gmac_intr, ATHR_MAC_IRQF_DISABLED, dev->name, dev);
    if (st < 0)
    {
        printk(MODULE_NAME ": request irq %d failed %d\n", mac->mac_irq, st);
        return 1;
    }
static irqreturn_t athr_gmac_intr(ATHR_MAC_ISR_ARGS)
{
    struct net_device *dev  = (struct net_device *)dev_id;
    athr_gmac_t      *mac  = (athr_gmac_t *)ATHR_MAC_PRIV(dev);
    int   isr, imr, handled = 0;

    isr   = athr_gmac_get_isr(mac); //取得中断状态寄存器的值
    imr   = athr_gmac_reg_rd(mac, ATHR_GMAC_DMA_INTR_MASK);

    athr_gmac_trc(isr,"isr");
    athr_gmac_trc(imr,"imr");

    assert(mac->mac_ifup);
    assert(isr == (isr & imr));

    if (isr & (ATHR_GMAC_INTR_RX_OVF))
    {
     handled = 1;
 
     if (is_ar7240() || is_ar933x())
   {
       athr_gmac_reg_wr(mac,ATHR_GMAC_CFG1,(athr_gmac_reg_rd(mac,ATHR_GMAC_CFG1)&0xfffffff3));
   }
      athr_gmac_intr_ack_rxovf(mac);
    }
    if (likely(isr & ATHR_GMAC_INTR_RX)) //接收中断触发,是分析的重点。
    {
      handled = 1;
      if (mac_has_flag(mac,ATHR_RX_POLL))
    {
              if (likely(athr_mac_rx_sched_prep(mac,dev)))
              {
                  int status = athr_gmac_reg_rd(mac, ATHR_GMAC_DMA_RX_STATUS);
                  athr_gmac_intr_disable_recv(mac);
                  assert((status & ATHR_GMAC_RX_STATUS_PKT_RCVD));
                  assert((status >> 16));
                  __athr_mac_rx_sched(mac,dev);
              }
              else
              {
                  //printk(MODULE_NAME ": driver bug! interrupt while in poll\n");
                  //assert(0);
                  athr_gmac_intr_disable_recv(mac);
              }
       }
       else
    {
           athr_gmac_intr_disable_recv(mac);
        ATH_SCHEDULE_TQUEUE(&mac->rxtq,mac);
       }
    }
    if (likely(isr & ATHR_GMAC_INTR_TX))
    {
        handled = 1;
        athr_gmac_intr_ack_tx(mac);
        athr_gmac_intr_disable_tx(mac);
     ATH_SCHEDULE_TQUEUE(&mac->txreaptq,mac);
    }
    if (unlikely(isr & ATHR_GMAC_INTR_RX_BUS_ERROR))
    {
        assert(0);
        handled = 1;
        athr_gmac_intr_ack_rxbe(mac);
    }
    if (unlikely(isr & ATHR_GMAC_INTR_TX_BUS_ERROR))
    {
        assert(0);
        handled = 1;
        athr_gmac_intr_ack_txbe(mac);
    }
    if (!handled)
    {
 /*
  * Mac fast reset will clear the status register
  * if we get a previously queued interrupt after reset
  * ignore it.
   */
        if (mac->dma_check)
  {
            mac->dma_check = 0;
            return IRQ_HANDLED;
        }
        printk(MODULE_NAME ": unhandled intr isr %#x\n", isr);
        assert(0);
    }

    return IRQ_HANDLED;
}

由于在SDK中,我们定义了,#define CONFIG_ATHR_RX_TASK 1故在中断处理函数中时候,中断上下半部分。
使用的是tasklet
    if (likely(isr & ATHR_GMAC_INTR_RX)) //没有使用查询模式,此模式时将会涉及到NAPI机制来接收数据包。
    {
      handled = 1;
      if (mac_has_flag(mac,ATHR_RX_POLL))
    {
              if (likely(athr_mac_rx_sched_prep(mac,dev)))
              {
                  int status = athr_gmac_reg_rd(mac, ATHR_GMAC_DMA_RX_STATUS);
                  athr_gmac_intr_disable_recv(mac);
                  assert((status & ATHR_GMAC_RX_STATUS_PKT_RCVD));
                  assert((status >> 16));
                  __athr_mac_rx_sched(mac,dev);
              }
              else
              {
                  //printk(MODULE_NAME ": driver bug! interrupt while in poll\n");
                  //assert(0);
                  athr_gmac_intr_disable_recv(mac);
              }
       }
       else
    {
          athr_gmac_intr_disable_recv(mac);//禁止中断
        ATH_SCHEDULE_TQUEUE(&mac->rxtq,mac); //调度tasklet。
      }
    }
中断处理的下半部定义如下:
#define ATH_INIT_RX_TASK() ATH_INIT_TQUEUE(&mac->rxtq,athr_gmac_recv_packets,mac);
athr_gmac_recv_packets()函数定义如下:

athr_receive_pkt() //这个函数兼顾中断俩种处理方式NAPI和完全中断的方式。
{
    ATHR_TASK_DEFS()
    athr_gmac_ring_t       *r     = &mac->mac_rxring;     
    athr_gmac_desc_t       *ds;
    athr_gmac_buffer_t     *bp;
    struct sk_buff      *skb;
    athr_gmac_rx_status_t   ret   = ATHR_GMAC_RX_STATUS_DONE;
    int head = r->ring_head, len, status, iquota = quota, more_pkts, rep;
#ifdef MEMLAT_OPT
    athr_gmac_desc_t       ds_pre[2];
    int head_pre;
#endif

    athr_gmac_trc(iquota,"iquota");
    status = athr_gmac_reg_rd(mac, ATHR_GMAC_DMA_RX_STATUS);

process_pkts:
    athr_gmac_trc(status,"status");

    assert(mac->mac_ifup);

    /*
     * Flush the DDR FIFOs for our gmac
     */
    athrs_flush_ge(mac->mac_unit);

    assert(quota > 0); /* WCL */

    if (mac->dma_check) {
        mac->dma_check = 0;
    }
    else {
        ATHR_NAPI_CHECK_STATUS();
    }

#ifdef MEMLAT_OPT
    head_pre = head;
    ds_pre[quota & 1] = r->ring_desc[head_pre];
#endif
    while(quota)
    {
#ifndef MEMLAT_OPT
        ds    = &r->ring_desc[head];
#else
        ds = ds_pre + (quota & 1);
        if (quota - 1) {
            athr_gmac_ring_incr(head_pre);
            ds_pre[(quota & 1) ^ 1] = r->ring_desc[head_pre];
        }
#endif

        athr_gmac_trc(head,"hd");
        athr_gmac_trc(ds,  "ds");

        if (athr_gmac_rx_owned_by_dma(ds))
        {
            assert(quota != iquota); /* WCL */
            break;
        }
        athr_gmac_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);

        /*
         *Data corruption sometimes with large buffer size of 4k.Cached region
         *is not synced with non cached region putting temporary fix for
         *invalidating cache contents Need to find the root cause.
         */
       
    athr_mac_cache_inv((unsigned long)(skb->data), skb->len);

        athr_ssdk_process_arp_header(mac, skb);

        athr_gmac_rx_qos(mac,skb);

        athr_gmac_vlan_igmp(mac,skb);

        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--;

        athr_nat_process_ingress_pkts(mac->mac_unit, skb, ds);

        netif_receive_skb(skb); //将接受的数据送往协议栈

        if (mac->rx_dma_check) {
            mac->rx_dma_check = 0;
        }

        athr_gmac_ring_incr(head);
    }

    assert(iquota != quota);
    r->ring_head   =  head;

    rep = athr_gmac_rx_replenish(mac);

    /*
    * 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       =  athr_gmac_reg_rd(mac, ATHR_GMAC_DMA_RX_STATUS);
    more_pkts    =  (status & ATHR_GMAC_RX_STATUS_PKT_RCVD);

    athr_gmac_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 = ATHR_GMAC_RX_STATUS_NOT_DONE;

done:

    if (mac_has_flag(mac,ATHR_RX_POLL))
        *work_done   = (iquota - quota);

    if (mac_has_flag(mac,ATHR_RX_POLL) &&
           unlikely(athr_gmac_rx_ring_full(mac)))
        return GMAC_RX_STATUS_OOM;
    /*
    * !oom; if stopped, restart h/w
    */

    if (unlikely(status & ATHR_GMAC_RX_STATUS_OVF))
    {
        mac->net_rx_over_errors ++;
        athr_gmac_intr_ack_rxovf(mac);
        athr_gmac_rx_start(mac);
    }

    if (mac_has_flag(mac,ATHR_RX_TASK))
        athr_gmac_intr_enable_recv(mac);

    RX_RETURN();
}
上面的接收处理函数中,重要的结构参数ring_buffer[]不好理解,还需要更升入的研究。
需要注意的是:每中断一次,都会禁止中断,之后在tasklet中来接收数据,数据接收完成之后有开启中断。
我们对capwap协议的处理放在了驱动中进行处理,故接收和发送函数都需要对capwap协议进行处理。
注意:不能在中断和查询中占用太多的时间。
9344中数据接收兼容了中断和查询这俩种方式来处理数据接收。在性能方面不知道那个要好一些。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
AR9344芯片是一款由高通公司设计和生产的网络芯片,主要用于无线路由器和无线通信设备。该芯片采用了32位MIPS架构,内置有高性能的处理器和丰富的外设接口,能够提供强大的计算能力和高速的数据处理速度。 AR9344芯片手册是一本详细介绍该芯片的使用方法和技术规格的文档。手册包含了该芯片的物理架构、功能配置、编程接口和寄存器描述等内容,可以帮助开发人员理解和使用该芯片。 手册的第一部分主要介绍了AR9344芯片的概述,包括芯片的主要特性和在无线通信领域的应用场景。接着是芯片的物理结构和引脚布局,这些信息对于设计电路板和进行硬件连接非常重要。 手册的第二部分详细介绍了AR9344芯片的功能配置和性能参数。其包括处理器核心的频率、缓存配置、外设接口的类型和数量等信息,开发人员可以根据这些参数设计和优化软件算法。 手册的第三部分主要介绍了AR9344芯片的软件开发接口和编程指南。开发人员可以根据手册提供的API文档和示例代码,将芯片与操作系统和应用软件进行集成开发,实现各种无线通信功能。 手册的最后部分是AR9344芯片的寄存器描述和编程手册。这些信息对于底层驱动程序的开发非常重要,开发人员可以根据手册提供的寄存器描述,编写底层驱动程序,实现对芯片各个功能模块的控制和配置。 总之,AR9344芯片手册是一本重要的参考资料,能够帮助开发人员深入了解和使用该芯片,实现各种无线通信领域的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

家有工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值