概述:
无线驱动的收包过程是基于中断的处理方式。在准备接收数据之前,驱动需要先进行初始化接收数据使用到的相关结构(
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_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;
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 */
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);
}
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,
};定义
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;
{
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;
}
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
的对象。该结构为 <