您的位置:首页 > 其它

AR9344中ethernet处理方式分析

2012-08-23 22:16 253 查看
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中数据接收兼容了中断和查询这俩种方式来处理数据接收。在性能方面不知道那个要好一些。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: