日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RK3288 GMAC整理

發(fā)布時間:2025/6/17 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RK3288 GMAC整理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、源文件

源碼路徑:\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)定義:

1priv->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ò)。

4frame_len = priv->hw->desc->get_rx_frame_len(p, coe); 獲取幀長度

5skb = priv->rx_skbuff[entry];

priv->rx_skbuff[entry] = NULL;

注意:skb將有上層網(wǎng)絡(luò)處理完后進(jìn)行釋放。

6skb_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

  • netdev_priv 獲得網(wǎng)絡(luò)設(shè)備私有數(shù)據(jù)
  • stmmac_check_ether_addr 檢測MAC地址是否有效,若無效,隨機(jī)產(chǎn)生一個
  • stmmac_mdio_register注冊MII總線
  • mdiobus_register()

    a.注冊總線設(shè)備device_register(&bus->dev);

    b.復(fù)位總線bus->reset(bus);

    c.掃描總線上的PHY設(shè)備,最大支持32

    4. stmmac_init_phy初始化PHY設(shè)備,并將PHYMAC綁定

    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ù)片段組成。

    1entry= priv->cur_tx % txsize;

    desc= priv->dma_tx + entry; 獲取可用發(fā)送描述子

    first= desc; 保存第一個數(shù)據(jù)片段

    2priv->tx_skbuff[entry]= skb;

    priv->tx_page[entry]= NULL; skb放到發(fā)送隊列

    3unsignedint 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)核虛擬地址。

    5priv->hw->desc->set_tx_owner(first);

    priv->cur_tx ++;

    將第一個數(shù)據(jù)片段描述子交給GMAC,記錄當(dāng)前發(fā)送index

    6priv->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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。