【无线】【流程】QCA无线驱动收包流程分析

本文深入探讨了QCA无线驱动的收包流程,分析了无线通信中高优先级和低优先级队列的工作机制,其中High-Priority队列容量为16,Low-Priority队列可达128。
摘要由CSDN通过智能技术生成
概述:
无线驱动的收包过程是基于中断的处理方式。在准备接收数据之前,驱动需要先进行初始化接收数据使用到的相关结构(  sc_rxbuf rxfifo  )。当数据包到达时,硬件会首先进行  DMA ,完成以后产生 Rx 中断。中断处理过程又分为两个部分,首先是立即执行的上半段处理,负责将数据包从软件接收缓冲队列中取出,并补全接收缓冲区,以便继续接收数据;然后就是一个  tasklet 机制的调度,进行数据包的分析处理,在  LMAC 层中进行接收状态的分析和填充,在  UMAC 层中对数据包本身进行分析,包括重组和包头转换等,最后将其转换为以太网帧的形式提交到  bridge 上去。

中断开始
内核活动中有硬件中断和软件中断,对于无线网卡收包的第一步,是硬件中断,对于中断,内核中执行专门的例程,又叫中断处理程序,执行中断发生时的动作。中断处理可通过request_irq进行注册。
跟踪无线收包流程,就从中断处理开始:
error = request_irq(dev->irq, ath_isr, IRQF_DISABLED, dev->name, dev);
然后主要的目光集中在中断处理函数ath_isr中:
ath_rx_buf_link_aponly<--ath_rx_addbuffer_aponly<--ath_rx_intr_aponly<--ath_rx_edma_intr_aponly<--ath_common_intr_aponly<--ath_intr_aponly<--ath_isr_aponly<--do_ath_isr<--ath_isr

可以按照这个函数调用轨迹去看处理的过程,不详细说,重点集中在函数ath_rx_intr_aponly中
void ath_rx_intr_aponly(ath_dev_t dev, HAL_RX_QUEUE qtype)
       {
    struct ath_softc *sc = ATH_DEV_TO_SC(dev);
    struct ath_rx_edma *rxedma;
    wbuf_t wbuf;
    struct ath_buf *bf;
 struct ath_rx_status *rxs;
    HAL_STATUS retval;
    struct ath_hal *ah = sc->sc_ah;
    int    frames;

    rxedma = &sc->sc_rxedma[qtype];

    do {
          printk("%s %d receive packet %d \r\n", __func__, __LINE__, rxedma->rxfifoheadindex);
        wbuf = rxedma->rxfifo[rxedma->rxfifoheadindex];
        if (unlikely(wbuf == NULL))
            break;
        bf = ATH_GET_RX_CONTEXT_BUF(wbuf);

        /*清理一下cache,则个是cache一致性问题后续说 */
        OS_SYNC_SINGLE(sc->sc_osdev,
                       bf->bf_buf_addr[0], sc->sc_rxstatuslen, BUS_DMA_FROMDEVICE,
                       OS_GET_DMA_MEM_CONTEXT(bf, bf_dmacontext));
        bf->bf_status |= ATH_BUFSTATUS_SYNCED;

        rxs = bf->bf_desc;
#ifdef CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT
        if (wbuf->mspd_data) {
            __memcpy(wbuf->data, wbuf->mspd_data, sc->sc_rxstatuslen + sizeof(struct ieee80211_qosframe) + ATH_COMCERTO_CUSTOM_SKB_OFFSET);
            wbuf->mspd_ofst = sc->sc_rxstatuslen + sizeof(struct ieee80211_qosframe) + ATH_COMCERTO_CUSTOM_SKB_OFFSET;
        }
#endif       
        retval = ath_hal_rxprocdescfast(ah, NULL, 0, NULL, rxs, wbuf_raw_data(wbuf));
          /*ath_hal_rxprocdescfast = ar9300_proc_rx_desc_fast*/
#ifdef ATH_RX_DESC_WAR
        if (unlikely(HAL_EINVAL == retval)) 
{
               struct ath_buf *next_bf;
               wbuf_t next_wbuf;
               u_int32_t next_idx = rxedma->rxfifoheadindex;

               bf->bf_status |= ATH_BUFSTATUS_WAR;

               INCR(next_idx, rxedma->rxfifohwsize);
               next_wbuf = rxedma->rxfifo[next_idx];

               if (next_wbuf == NULL)
                    break;

               next_bf = ATH_GET_RX_CONTEXT_BUF(next_wbuf);
               next_bf->bf_status |= ATH_BUFSTATUS_WAR;
               DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: Marking first DP 0x%x for drop\n",
                        __func__, (unsigned) bf->bf_buf_addr[0]);
               DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: Marking second DP 0x%x for drop\n",
                       __func__, (unsigned) next_bf->bf_buf_addr[0]);
          }
#endif
        /* XXX Check for done bit in RxS */
        if (HAL_EINPROGRESS == retval) {
            break;
        }

        /* add this ath_buf for deferred processing, 将包放入到rxqueue,下半段部再处理*/
        TAILQ_INSERT_TAIL(&rxedma->rxqueue, bf, bf_list);

        /* clear this element before advancing */
        rxedma->rxfifo[rxedma->rxfifoheadindex] = NULL;

        /* advance the head pointer */
        INCR(rxedma->rxfifoheadindex, rxedma->rxfifohwsize); /*处理下一个包*/

        if (unlikely(rxedma->rxfifodepth == 0))
            printk("ath_rx_intr: depth 0 PANIC\n");

        rxedma->rxfifodepth--;
    } while (TRUE);

    /* 将ath_bufs 从空闲的链表移到rxedma的rxfifo  */
frames = rxedma->rxfifohwsize - rxedma->rxfifodepth;
    if (frames > 0)
        ath_rx_addbuffer_aponly(sc, qtype, frames);
}
这个函数主要做的就是将数据包从rxfifo中收上来,然后放入rxqueue,然后在空闲队列中找一个ath_bufs放回到rxfifo。

rxfifo

sc 中对应的rxfifo 有两个,分别对应于硬件的两个不同优先级的队列( High-Priority Low-Priority ,HP长队16,LP长度128)

这两个参数在函数 ar9300_fill_capability_info中的:
   p_cap->hal_rx_hp_depth = HAL_HP_RXFIFO_DEPTH;
   p_cap->hal_rx_lp_depth = HAL_LP_RXFIFO_DEPTH;
赋值;
通过枚举变量:
enum RX_FIFO_DEPTH {
    HAL_HP_RXFIFO_DEPTH             = 16,
    HAL_LP_RXFIFO_DEPTH             = 128,
};定义

rxfifo是指针的数组,在函数中申请了空间。
static int ath_rxfifo_alloc(struct ath_softc *sc, HAL_RX_QUEUE qtype)
{
    struct ath_rx_edma *rxedma;
    int bsize, error;

    rxedma = &sc->sc_rxedma[qtype];

    error = ath_hal_getrxfifodepth(sc->sc_ah, qtype, &rxedma->rxfifohwsize);
    if (error)
        return error;

    bsize = sizeof(wbuf_t) * rxedma->rxfifohwsize;

     printk("%s %d rxedma->rxfifohwsize = %d, bsize = %d\r\n", __func__, __LINE__, rxedma->rxfifohwsize, bsize);
/*
     上面在串口中打印结果是:
      [2016:11:10:14:55:09][   10.804000] ath_rxfifo_alloc 128 rxedma->rxfifohwsize = 16, bsize = 64
   [2016:11:10:14:55:09][   10.812000] ath_rxfifo_alloc 128 rxedma->rxfifohwsize = 128, bsize = 512
*/
    rxedma->rxfifo = (wbuf_t *)OS_MALLOC(sc->sc_osdev, bsize, GFP_KERNEL); /*所以这里申请的是存放指针的数组空间,这些指针就用来指向可用的ath_buf*/
    if (rxedma->rxfifo == NULL)
        return -ENOMEM;

    rxedma->rxfifoheadindex = 0;
    rxedma->rxfifotailindex = 0;
    rxedma->rxfifodepth = 0;

    OS_MEMZERO(rxedma->rxfifo, bsize);
    TAILQ_INIT(&rxedma->rxqueue);
    ATH_RXQ_LOCK_INIT(rxedma);

    return 0;
}
sc->sc_rxbuf
sc_rxbuf  是整个驱动中,收包所使用的缓冲池,其中初始化了  512   ath_buf  的对象。该结构为  <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值