以太網驅動的流程淺析(一)-Ifconfig主要流程【原創】

以太網驅動的流程淺析(一)-Ifconfig主要流程

Author:張昺華
Email:920052390@qq.com
Time:2019年3月23日星期六

此文也在我的個人公眾號以及《Linux內核之旅》上有發表:

很喜歡一群人在研究技術,一起做有意思的東西,一起分享技術帶給我們的快樂,也希望中國有更多的人熱愛技術,喜歡一起研究、分享技術,然後可以一起用我們的技術來做一些好玩的東西,可以為這個社會創造一些東西來改善人們的生活。
如下是本人調試過程中的一點經驗分享,以太網驅動架構畢竟涉及的東西太多,如下僅僅是針對加載流程和圍繞這個問題產生的分析過程和驅動加載流程部分,並不涉及以太網協議層的數據流程分析。

【硬件環境】 Imx6ul

【Linux kernel版本】 Linux4.1.15

【以太網phy】 Realtek8201f

一個以太網的案例來講述Ifconfig

1. 問題描述

【問題】

機器通過usb方式下載了mac地址后,發現以太網無法正常使用,敲命令 ifconfig eth0 up出現:ifconfig: SIOCSIFFLAGS: No such device,而對於沒有下載以太網mac address的機器表現均正常。調試過程中發現在以太網控制器代碼中加入一些printk,不正常的機器又正常了,打印的位置不同,機器的以太網有時會正常,有時會異常,十分詭異。

2. 原因分析

【根本原因】

reset時序問題導致,phy reset的時間不滿足時序要求。如下圖,如果硬件接了reset引腳,應滿足時序要求在reset保持10ms有效電平后,還必須維持至少150ms才可以訪問phy register,也就是reset要在B點之後才可以正常通過MDC/MDIO來訪問phy register。如果是不使用硬件reset,使用軟件reset方式,那也要至少在A點,也就是在reset維持10ms有效電平后,再維持3.5個clk才能正常訪問phy register。

那為什麼下載了mac地址后才異常呢?不下載的又正常呢?

【原因分析】

freescale控制器獲取mac address流程如下:
1)模塊化參數設置,如果沒有跳到步驟2;
2)device tree中設置,如果沒有跳到步驟3;
3)from flash / fuse / via platform data,如果沒有跳到步驟4;
4)FEC mac registers set by bootloader===》即靠usb方式下載mac address ,如果沒有跳到步驟5;
5)靠kernel算一個隨機數mac address出來,然後寫入mac

那為什麼下載了mac地址后才異常呢?
下了mac后,會執行步驟4,不會執行步驟5,此時目前的代碼不滿足150ms的時序要求,無法訪問phy register,
導致phy_id獲取不到,因此phy_device也不會創建

那為什麼不下載的又正常呢?
不下載mac address,會執行步驟5 ,步驟5中調用了函數eth_hw_addr_random
剛好滿足了150ms的時序要求,所以才可以正常

跟入代碼eth_hw_addr_random看下

繼續看:

最終調用了kernel提供的獲取隨機數的一個函數,這塊代碼比較多就不繼續追下去了。

所以這塊步驟五的代碼剛剛好好在這個硬件條件下,恰巧滿足了150ms的reset時序要求,所以以太網才可以正常。

3. 以太網流程分析跟蹤

3.1 Ifconfig主要流程

回歸主題,根據這個ifconfig失敗的現象,我們追蹤一下code:
ifconfig: SIOCSIFFLAGS: No such device,既然出現了這個問題log,我們就從應用層的log入手,首先我們使用strace命令來追蹤下系統調用,以便於我們追蹤內核代碼實現。
strace ifconfig eth0 up跟蹤一下

可以發現主要是ioctl的操作,SIOCSIFFLAGS,然後我們需要了解下這個宏的意思,說白了就是設置各種flag,靠ioctl第三個參數把所需要的動作flag傳入,比如說此時要對eth0進行up動作,那麼就傳入IFF_UP,例如:
struct ifreq ifr;

我們看這些主要是想知道為什麼會打印這個log:
ifconfig: SIOCSIFFLAGS: No such device
那麼內核中又是對ioctl做了什麼動作呢?因為strace命令讓我們知道了系統調用調用函數,我們可以在kernel中直接搜索SIOCSIFFLAGS,或者去以太網驅動net目錄下直接搜索更快。最終我搜到了,路徑是:net/ipv4/devinet.c
我們可以看到內核的宏定義:

查看devinet.c的代碼,我們找到了那個宏,也就是做devinet_ioctl函數中,這也就是應用層的ioctl最終的實現函數,然後我們在裏面加一些打印,

通過打印結果我們可以確認是這個函數devinet_ioctl為應用層的ioctl的實現函數,因為你在kernel中搜SIOCSIFFLAGS宏的話會有很多地方出現的,所以我們需要確認我們找的函數
沒問題:

看到這裏返回值ret是-19,那麼我們繼續順着追蹤下去,上代碼:
net/core/dev.c

繼續追蹤:net/core/dev.c

因此我們可以看到返回值-19就是如下代碼產生的

因此我們需要追蹤__dev_open函數,繼續看代碼:

通過調試,比如說加打印,或者是經驗我們可以推斷出是這裏返回的-19,那麼這個ndo_open又是在哪裡回調的呢?

我們可以看到ops這個結構的結構體
struct net_device dev
const struct net_device_ops
ops = dev->netdev_ops;

這裏熟悉驅動的朋友應該可以猜到這在在freescale的以太網控制器驅動中一定有它的實現
net_device_ops就是kernel提供給drvier操作net_device的一些操作方法,具體實現自然由相應廠商的driver自己去實現。
路徑:drivers/net/Ethernet/freescale/fec_main.c

我們可以在這個fec_enet_open函數中加入dump_stack來看下整個調用情況
我們打出kernel的dump_stack信息來看:

這個調用過程就是應用層ioctl一直到kernel最底層fec_enet_open的過程。
應用代碼這樣:

總體流程:kill() -> kill.S -> swi陷入內核態 -> 從sys_call_table查看到sys_kill -> ret_fast_syscall -> 回到用戶態執行kill()下一行代碼
Ioctl《==ret_fast_syscall 《==SyS_ioctl《==do_vfs_ioctl《==vfs_ioctl《==sock_ioctl《==
devinet_ioctl《==dev_change_flags《==__dev_change_flags《==__dev_open《==fec_enet_open
我附上每個函數的代碼:
如果大家想看系統調用流程的話,參考這篇,我就不做這塊的說明了:
Linux系統調用(syscall)原理
http://gityuan.com/2016/05/21/syscall/
Arm Linux系統調用流程詳細解析
https://www.cnblogs.com/cslunatic/p/3655970.html

4. 網址分享

http://stackoverflow.com/questions/5308090/set-ip-address-using-siocsifaddr-ioctl
http://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.commtrf2/ioctl_socket_control_operations.htm
https://lkml.org/lkml/2017/2/3/396

http://www.latelee.org/programming-under-linux/linux-phy-driver.html
Linux PHY幾個狀態的跟蹤
http://www.latelee.org/programming-under-linux/linux-phy-state.html
第十六章PHY -基於Linux3.10
https://blog.csdn.net/shichaog/article/details/44682931

“`

End

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

收購3c,收購IPHONE,收購蘋果電腦-詳細收購流程一覽表

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品在網路上成為最夯、最多人討論的話題?

※高價收購3C產品,價格不怕你比較

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!