RK3288 GMAC整理
一、源文件
源碼路徑:\drivers\net\ethernet\rockchip\gmac
源碼閱讀順序:
? ? ?
二、重要探針函數(shù)stmmac_dvr_probe
1. alloc_etherdev
申請網(wǎng)卡設(shè)備和私有數(shù)據(jù)。
struct net_device *ndev = NULL;
struct stmmac_priv *priv;
ndev = alloc_etherdev(sizeof(struct stmmac_priv));
priv = netdev_priv(ndev);
網(wǎng)卡設(shè)備和私有數(shù)據(jù)緊緊的挨在一起:網(wǎng)卡設(shè)備+私用數(shù)據(jù)結(jié)構(gòu),通過netdev_priv獲取私有數(shù)據(jù)。網(wǎng)卡設(shè)備是通用數(shù)據(jù)結(jié)構(gòu),私有數(shù)據(jù)則為各個MAC控制器的數(shù)據(jù)結(jié)構(gòu)。
2. stmmac_hw_init
初始化MAC設(shè)備。檢測要添加的設(shè)備(GMAC/MAC10-100),檢查HW能力并設(shè)置驅(qū)動程序的特性。
3. netif_napi_add
初始化一個NAPI上下文,輪詢接收數(shù)據(jù)包接口。
netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);
stmmac_poll是輪詢接口
該接口完成兩個事情:
1)當(dāng)數(shù)據(jù)發(fā)送完成時產(chǎn)生中斷,進(jìn)入該函數(shù)進(jìn)行資源回收。
2)收到數(shù)據(jù)產(chǎn)生中斷,進(jìn)入該函數(shù)進(jìn)行數(shù)據(jù)接收和處理。
static int stmmac_poll(struct napi_struct *napi, int budget) { ...... stmmac_tx_clean(priv); //傳輸完成后回收資源work_done = stmmac_rx(priv, budget); //數(shù)據(jù)包接收處理stmmac_enable_dma_irq(priv); //使能dma終端 ...... }stmmac_rx函數(shù)解析
作用:再次填充并使用skb預(yù)先分配的緩存,由NAPI輪詢方法調(diào)用,可以獲得環(huán)內(nèi)所有幀。
函數(shù):static int stmmac_rx(struct stmmac_priv *priv, int limit)
函數(shù)內(nèi)定義:
1)priv->hw->desc->get_rx_owner(p)
判斷當(dāng)前描述子的歸屬:描述子數(shù)據(jù)結(jié)構(gòu)中OWN位,
0: 當(dāng)前描述子應(yīng)該由CPU操作,
1: 前描述子應(yīng)該由GMAC操作。
對于接收,初始化dma描述子隊列時設(shè)置為1。
GMAC根據(jù)寄存器配置,獲取可用接收描述子,然后從RxFIFO中讀取從PHY接收的Ethernet報文,如果報文符合接收條件,將該報文寫入接收描述子指向的數(shù)據(jù)緩沖區(qū),并回寫接收描述子。這個回寫就會將OWN位設(shè)置為0。
2)next_entry = (++priv->cur_rx) % rxsize;
獲取下一幀描述符,
p_next =priv->dma_rx + next_entry;
priv->cur_rx:已經(jīng)傳遞給協(xié)議層的index。
3)status =(priv->hw->desc->rx_status(&priv->dev->stats, &priv->xstats,p));
獲取收到幀狀態(tài),如果是丟棄幀,則什么都不處理;否則上傳到上層網(wǎng)絡(luò)。
4)frame_len = priv->hw->desc->get_rx_frame_len(p, coe); 獲取幀長度
5)skb = priv->rx_skbuff[entry];
priv->rx_skbuff[entry] = NULL;
注意:skb將有上層網(wǎng)絡(luò)處理完后進(jìn)行釋放。
6)skb_put(skb, frame_len);
dma_unmap_single(priv->device,priv->rx_skbuff_dma[entry],priv->dma_buf_sz, DMA_FROM_DEVICE); ?設(shè)置skb數(shù)據(jù)長度和解除流式DMA映射
7)獲取skb的協(xié)議類型
skb->protocol = eth_type_trans(skb,priv->dev);
skb->dev = priv->dev;
8)napi_gro_receive(&priv->napi,skb);
將skb通過NAPI接口上傳上層網(wǎng)絡(luò)協(xié)議處理。
9)stmmac_rx_refill(priv); 重新填充接收隊列
?
三、打開網(wǎng)卡設(shè)備接口stmmac_open
網(wǎng)卡剛起來時是關(guān)閉的,要用命令去打開,ifconfig eth0 up 時調(diào)用net_device_ops的.ndo_open,這里為stmmac_open。
mdiobus_register()
a.注冊總線設(shè)備device_register(&bus->dev);
b.復(fù)位總線bus->reset(bus);
c.掃描總線上的PHY設(shè)備,最大支持32個
4. stmmac_init_phy初始化PHY設(shè)備,并將PHY和MAC綁定
5. request_irq 申請中斷
ret = request_irq(dev->irq,?stmmac_interrupt,
??IRQF_SHARED, dev->name, dev);
注冊中斷請求線IRQ,中斷處理函數(shù)stmmac_interrupt用于接收DMA數(shù)據(jù),配合NAPI處理。
static irqreturn_t stmmac_interrupt(int irq, void *dev_id) {....../* To handle DMA interrupts */stmmac_dma_interrupt(priv); }static void stmmac_dma_interrupt(struct stmmac_priv *priv) {......status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);if (likely((status & handle_rx)) || (status & handle_tx)) {if (likely(napi_schedule_prep(&priv->napi))) {stmmac_disable_dma_irq(priv);__napi_schedule(&priv->napi); //加入poll流程}}...... }?
四、發(fā)送數(shù)據(jù)接口stmmac_xmit
該接口實(shí)現(xiàn)了Scatter/Gather I/O功能,通過skb_shinfo宏來判斷數(shù)據(jù)包是由一個數(shù)據(jù)片段組成,還是由大量數(shù)據(jù)片段組成。
1、entry= priv->cur_tx % txsize;
desc= priv->dma_tx + entry; 獲取可用發(fā)送描述子
first= desc; 保存第一個數(shù)據(jù)片段
2、priv->tx_skbuff[entry]= skb;
priv->tx_page[entry]= NULL; 將skb放到發(fā)送隊列
3、unsignedint nopaged_len = skb_headlen(skb);
desc->des2=dma_map_single(priv->device,skb->data,nopaged_len, DMA_TO_DEVICE);
priv->hw->desc->prepare_tx_desc(desc,1, nopaged_len, csum_insertion);
發(fā)送單個或第一個數(shù)據(jù)包,當(dāng)只有一個數(shù)據(jù)片段時,skb->data將發(fā)送所有數(shù)據(jù);當(dāng)有多個數(shù)據(jù)片段時,skb->data則指向第一個數(shù)據(jù)片段,數(shù)據(jù)長度skb->len –skb->data_len,其他數(shù)據(jù)存放在共享數(shù)據(jù)結(jié)構(gòu)frags數(shù)組中。(skb->len:數(shù)據(jù)包中全部數(shù)據(jù)的長度,skb->data_len分隔存儲數(shù)據(jù)片段長度)
4、
for (i = 0; i < nfrags; i++) {const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];int len = skb_frag_size(frag);entry = (++priv->cur_tx) % txsize;if (priv->extend_desc)desc = (struct dma_desc *)(priv->dma_etx + entry);elsedesc = priv->dma_tx + entry;TX_DBG("\t[entry %d] segment len: %d\n", entry, len);desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len, DMA_TO_DEVICE);priv->tx_skbuff_dma[entry] = desc->des2;priv->tx_skbuff[entry] = NULL;priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,priv->mode);wmb();priv->hw->desc->set_tx_owner(desc);wmb(); }發(fā)送剩余數(shù)據(jù)片段。
對于多個數(shù)據(jù)片段時,還要進(jìn)行數(shù)據(jù)片段的發(fā)送,采用頁處理。直接處理頁結(jié)構(gòu),而不是內(nèi)核虛擬地址。
5、priv->hw->desc->set_tx_owner(first);
priv->cur_tx ++;
將第一個數(shù)據(jù)片段描述子交給GMAC,記錄當(dāng)前發(fā)送index
6、priv->hw->dma->enable_dma_transmission(priv->dma_ioaddr,
??????????????????????????priv->dma_channel);
寫任何值喚醒處于掛起的RxDMA
轉(zhuǎn)載于:https://www.cnblogs.com/debruyne/p/9133439.html
總結(jié)
以上是生活随笔為你收集整理的RK3288 GMAC整理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DOM中Event 对象如何使用
- 下一篇: 【软件构造】第三章第三节 抽象数据型(A