色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

以太網(wǎng)PHY的控制器驅(qū)動框架分析

嵌入式與Linux那些事 ? 來源:嵌入式與Linux那些事 ? 2023-05-04 10:06 ? 次閱讀

1. 概述

PHY芯片為OSI的最底層-物理層(Physical Layer),通過MII/GMII/RMII/SGMII/XGMII等多種媒體獨立接口(介質(zhì)無關(guān)接口)與數(shù)據(jù)鏈路層的MAC芯片相連,并通過MDIO接口實現(xiàn)對PHY狀態(tài)的監(jiān)控、配置和管理。

PHY與MAC整體的大致連接框架如下(圖片來源于網(wǎng)絡(luò)):87982330-e689-11ed-ab56-dac502259ad0.png

PHY的整個硬件系統(tǒng)組成比較復(fù)雜,PHY與MAC相連(也可以通過一個中間設(shè)備相連),MAC與CPU相連(有集成在內(nèi)部的,也有外接的方式)。

PHY與MAC通過MII和MDIO/MDC相連,MII是走網(wǎng)絡(luò)數(shù)據(jù)的MDIO/MDC是用來與PHY的寄存器通訊的,對PHY進(jìn)行配置

PHY的驅(qū)動與I2C/SPI的驅(qū)動一樣,分為控制器驅(qū)動設(shè)備器驅(qū)動。本節(jié)先講控制器驅(qū)動。

2. PHY的控制器驅(qū)動總述

PHY的控制器驅(qū)動和SPI/I2C非常類似,控制器的核心功能是實現(xiàn)具體的讀寫功能。區(qū)別在于PHY的控制器讀寫功能的實現(xiàn)大致可以分為兩種方式():

直接調(diào)用CPU的MDIO控制器(直接調(diào)用cpu對應(yīng)的寄存器)的方式;

通過GPIO/外圍soc模擬MDIO時序的方式;

PHY的控制器一般被描述為mdio_bus平臺設(shè)備(注意:這是一個設(shè)備,等同于SPI/I2C中的master設(shè)備;和總線、驅(qū)動、設(shè)備中的bus不是一個概念)。

既然是平臺設(shè)備,那么設(shè)備樹中必定要有可以被解析為平臺設(shè)備的節(jié)點,也要有對應(yīng)的平臺設(shè)備驅(qū)動。與SPI驅(qū)動類似,PHY設(shè)備模型也是在控制器驅(qū)動的probe函數(shù)中注冊的

3. 通過GPIO/外圍soc模擬MDIO時序的方式

3.1 控制器平臺設(shè)備在設(shè)備樹中的大致描述方式(不完全準(zhǔn)確,主要描述匹配的規(guī)則)

#linux-4.9.225Documentationdevicetreeindingssocfslcpm_qe
etwork.txt
*MDIO
Currentlydefinedcompatibles:fsl,pq1-fec-mdio(regissameasfirstresourceofFECdevice)fsl,cpm2-mdio-bitbang(regisportCregisters)
Propertiesforfsl,cpm2-mdio-bitbang:
fsl,mdio-pin:pinofportCcontrollingmdiodata
fsl,mdc-pin:pinofportCcontrollingmdioclock
Example:mdio@10d40{
compatible="fsl,mpc8272ads-mdio-bitbang",
"fsl,mpc8272-mdio-bitbang",
"fsl,cpm2-mdio-bitbang";
reg=<10d40?14>;
#address-cells=<1>;
#size-cells=<0>;
fsl,mdio-pin=<12>;
fsl,mdc-pin=<13>;

#linux-4.9.225Documentationdevicetreeindingsphy
xxx_phy:xxx-phy@xxx{//描述控制器下掛PHY設(shè)備的節(jié)點
reg=<0x0>;//PHY的地址
};
};

3.2 控制器平臺驅(qū)動代碼走讀

3.2.1 控制器平臺驅(qū)動的注冊

staticconststructof_device_idfs_enet_mdio_bb_match[]={
{
.compatible="fsl,cpm2-mdio-bitbang",//匹配平臺設(shè)備的名稱
},
{},
};
MODULE_DEVICE_TABLE(of,fs_enet_mdio_bb_match);

staticstructplatform_driverfs_enet_bb_mdio_driver={
.driver={
.name="fsl-bb-mdio",
.of_match_table=fs_enet_mdio_bb_match,
},
.probe=fs_enet_mdio_probe,
.remove=fs_enet_mdio_remove,
};

module_platform_driver(fs_enet_bb_mdio_driver);//注冊控制器平臺設(shè)備驅(qū)動

3.2.2 控制器平臺驅(qū)動的probe函數(shù)走讀

/**********************************************************************************************
通過GPIO/外圍soc模擬MDIO時序方式的MDIO驅(qū)動(probe函數(shù)中完成PHY設(shè)備的創(chuàng)建和注冊)
***********************************************************************************************/
#linux-4.9.225drivers
etethernetfreescalefs_enetmii-bitbang.c

fs_enet_mdio_probe(structplatform_device*ofdev)
|---bitbang=kzalloc(sizeof(structbb_info),GFP_KERNEL)
|
|---bitbang->ctrl.ops=&bb_ops----------------------------------------------->|staticstructmdiobb_opsbb_ops={
||.owner=THIS_MODULE,
||.set_mdc=mdc,
||.set_mdio_dir=mdio_dir,
||.set_mdio_data=mdio,|-->實現(xiàn)為GPIO的讀寫
||.get_mdio_data=mdio_read,
||};
|<---------------------------------------------------------|
|---?new_bus?=?alloc_mdio_bitbang(&bitbang->ctrl)|
||---bus=mdiobus_alloc()-----------||structmdiobb_ctrl*ctrl=bus->priv||
||---bus->read=mdiobb_read-----------||ctrl->ops->set_mdc||
||---bus->write=mdiobb_write-----------|--mdiobb_read/mdiobb_write/mdiobb_reset函數(shù)的實現(xiàn)-|ctrl->ops->set_mdio_dir|--|
||---bus->reset=mdiobb_reset-----------|/|ctrl->ops->set_mdio_data|
||---bus->priv=ctrl<----------------------------????????????????????????????????????????????|?ctrl->ops->get_mdio_data|
|
|---fs_mii_bitbang_init//設(shè)置用來模擬mdc和mdio的管腳資源
||---of_address_to_resource(np,0,&res)//轉(zhuǎn)換設(shè)備樹地址并作為資源返回,設(shè)備樹中指定
||
||---snprintf(bus->id,MII_BUS_ID_SIZE,"%x",res.start)//把資源的起始地址設(shè)置為bus->id
||
||---data=of_get_property(np,"fsl,mdio-pin",&len)
||---mdio_pin=*data//決定控制mdio數(shù)據(jù)的端口的引腳
||
||---data=of_get_property(np,"fsl,mdc-pin",&len)
||---mdc_pin=*data//控制mdio時鐘的端口引腳
||
||---bitbang->dir=ioremap(res.start,resource_size(&res))
||
||---bitbang->dat=bitbang->dir+4
||---bitbang->mdio_msk=1<mdc_msk=1<dev.of_node)//注冊mii_bus設(shè)備,并通過設(shè)備樹子節(jié)點創(chuàng)建PHY設(shè)備<===of_mdiobus_register(struct?mii_bus?*mdio,?struct?device_node?*np)
|????|---?mdio->phy_mask=~0//屏蔽所有PHY,防止自動探測。相反,設(shè)備樹中列出的phy將在總線注冊后填充
||---mdio->dev.of_node=np
||---mdiobus_register(mdio)//@注意@注冊MDIO總線設(shè)備(注意是總線設(shè)備不是總線,因為總線也是一種設(shè)備。mdio_bus是在其他地方注冊的,后面會講到)
|||---__mdiobus_register(bus,THIS_MODULE)
||||---bus->owner=owner
||||---bus->dev.parent=bus->parent
||||---bus->dev.class=&mdio_bus_class
||||---bus->dev.groups=NULL
||||---dev_set_name(&bus->dev,"%s",bus->id)//設(shè)置總線設(shè)備的名稱
||||---device_register(&bus->dev)//注冊總線設(shè)備
||
||---for_each_available_child_of_node(np,child)//遍歷這個平臺設(shè)備的子節(jié)點并為每個phy注冊一個phy_device
||---addr=of_mdio_parse_addr(&mdio->dev,child)//從子節(jié)點的"reg"屬性中獲得PHY設(shè)備的地址
|||---of_property_read_u32(np,"reg",&addr)
||---if(addrmdio//mdiodev是最新的內(nèi)核引入,較老的版本沒有這個結(jié)構(gòu)
||||---mdiodev->dev.release=phy_device_release
||||---mdiodev->dev.parent=&bus->dev
||||---mdiodev->dev.bus=&mdio_bus_type//PHY設(shè)備和驅(qū)動都會掛在mdio_bus下,匹配時會調(diào)用對應(yīng)的match函數(shù)---|
||||---mdiodev->bus=bus|
||||---mdiodev->pm_ops=MDIO_BUS_PHY_PM_OPS|
||||---mdiodev->bus_match=phy_bus_match//真正實現(xiàn)PHY設(shè)備和驅(qū)動匹配的函數(shù)<--------------------------------|
|?????????|????|?????????????|---?mdiodev->addr=addr
||||---mdiodev->flags=MDIO_DEVICE_FLAG_PHY
||||---mdiodev->device_free=phy_mdio_device_free
||||---diodev->device_remove=phy_mdio_device_remove
||||---dev->speed=SPEED_UNKNOWN
||||---dev->duplex=DUPLEX_UNKNOWN
||||---dev->pause=0
||||---dev->asym_pause=0
||||---dev->link=1
||||---dev->interface=PHY_INTERFACE_MODE_GMII
||||---dev->autoneg=AUTONEG_ENABLE//默認(rèn)支持自協(xié)商
||||---dev->is_c45=is_c45
||||---dev->phy_id=phy_id
||||---if(c45_ids)
|||||---dev->c45_ids=*c45_ids
||||---dev->irq=bus->irq[addr]
||||---dev_set_name(&mdiodev->dev,PHY_ID_FMT,bus->id,addr)
||||---dev->state=PHY_DOWN//指示PHY設(shè)備和驅(qū)動程序尚未準(zhǔn)備就緒,在PHY驅(qū)動的probe函數(shù)中會更改為READY
||||---INIT_DELAYED_WORK(&dev->state_queue,phy_state_machine)//PHY的狀態(tài)機(核心WORK)
||||---INIT_WORK(&dev->phy_queue,phy_change)//由phy_interrupt/timer調(diào)度以處理PHY狀態(tài)的更改
||||---request_module(MDIO_MODULE_PREFIXMDIO_ID_FMT,MDIO_ID_ARGS(phy_id))//加載內(nèi)核模塊(這里沒有細(xì)致研究過)
||||---device_initialize(&mdiodev->dev)//設(shè)備模型中的一些設(shè)備,主要是kset、kobject、ktype的設(shè)置
|||
|||---irq_of_parse_and_map(child,0)//將中斷解析并映射到linuxvirq空間(未深入研究)
|||---if(of_property_read_bool(child,"broken-turn-around"))//MDIO總線中的TA(Turnaroundtime)
||||---mdio->phy_ignore_ta_mask|=1<mdio.dev.of_node=child
|||
|||---phy_device_register(phy)//注冊PHY設(shè)備
||||---mdiobus_register_device(&phydev->mdio)//注冊到mdiodev->bus,其實筆者認(rèn)為這是一個虛擬的注冊,僅僅是根據(jù)PHY的地址在mdiodev->bus->mdio_map數(shù)組對應(yīng)位置填充這個mdiodev
|||||---mdiodev->bus->mdio_map[mdiodev->addr]=mdiodev//方便通過mdiodev->bus統(tǒng)一管理和查找,以及關(guān)聯(lián)bus的讀寫函數(shù),方便PHY的功能配置
||||
||||---device_add(&phydev->mdio.dev)//注冊到linux設(shè)備模型框架中
||
||---if(!scanphys)//如果從子節(jié)點的"reg"屬性中獲得PHY設(shè)備的地址,scanphys=false,這里就直接返回了,因為不需要再掃描了
|||---return0
||
/******************************************************************************************************************
一般來說只要設(shè)備樹種指定了PHY設(shè)備的"reg"屬性,后面的流程可以自動忽略
******************************************************************************************************************
||---for_each_available_child_of_node(np,child)//自動掃描具有空"reg"屬性的PHY
||---if(of_find_property(child,"reg",NULL))//跳過具有reg屬性集的PHY
|||---continue
||
||---for(addr=0;addrdev,"scanphy%sataddress%i
",child->name,addr)//打印掃描的PHY,建議開發(fā)人員設(shè)置"reg"屬性
||
||---if(of_mdiobus_child_is_phy(child))
||---of_mdiobus_register_phy(mdio,child,addr)//注冊PHY設(shè)備
|
******************************************************************************************************************/

4. 直接調(diào)用CPU的MDIO控制器的方式

4.1 控制器平臺設(shè)備在設(shè)備樹中的大致描述方式(不完全準(zhǔn)確,主要描述匹配的規(guī)則)

#linux4.9.225Documentationdevicetreeindingspowerpcfslfman.txt
ExampleforFManv3internalMDIO:
mdio@e3120{//描述MDIO控制器驅(qū)動節(jié)點
compatible="fsl,fman-mdio";
reg=<0xe3120?0xee0>;
fsl,fman-internal-mdio;
tbi1:tbi-phy@8{//描述控制器下掛PHY設(shè)備的節(jié)點
reg=<0x8>;
device_type="tbi-phy";
};
};

4.2 控制器平臺驅(qū)動代碼走讀

4.2.1 控制器平臺驅(qū)動的注冊

#linux-4.9.225drivers
etethernetfreescalefsl_pq_mdio.c
staticconststructof_device_idfsl_pq_mdio_match[]={
......

/*NoKconfigoptionforFmansupportyet*/
{
.compatible="fsl,fman-mdio",//匹配平臺設(shè)備的名稱
.data=&(structfsl_pq_mdio_data){
.mii_offset=0,
/*FmanTBIoperationsarehandledelsewhere*/
},
},
......
{},
};

staticstructplatform_driverfsl_pq_mdio_driver={
.driver={
.name="fsl-pq_mdio",
.of_match_table=fsl_pq_mdio_match,
},
.probe=fsl_pq_mdio_probe,
.remove=fsl_pq_mdio_remove,
};

module_platform_driver(fsl_pq_mdio_driver);//注冊控制器平臺設(shè)備驅(qū)動

4.2.2 控制器平臺驅(qū)動的probe函數(shù)走讀

/****************************************************************************************
直接調(diào)用CPU的MDIO控制器的方式的MDIO控制器驅(qū)動(probe函數(shù)中涉及PHY設(shè)備的創(chuàng)建和注冊)
****************************************************************************************/
#linux-4.9.225drivers
etethernetfreescalefsl_pq_mdio.c

fsl_pq_mdio_probe(structplatform_device*pdev
|---structfsl_pq_mdio_priv*priv
|---structmii_bus*new_bus
|
|---new_bus=mdiobus_alloc_size(sizeof(*priv))//分配結(jié)構(gòu)體
|---priv=new_bus->priv
|---new_bus->name="FreescalePowerQUICCMIIBus"
|---new_bus->read=&fsl_pq_mdio_read//總線的讀接口
|---new_bus->write=&fsl_pq_mdio_write//總線的寫接口
|---new_bus->reset=&fsl_pq_mdio_reset//總線的復(fù)位接口
|
|---of_address_to_resource(np,0,&res)//獲取控制器地址資源
|---snprintf(bus->id,MII_BUS_ID_SIZE,"%x",res.start)//把資源的起始地址設(shè)置為bus->id
|
|---of_mdiobus_register(new_bus,np)//注冊mii_bus設(shè)備,并通過設(shè)備樹中控制器的子節(jié)點創(chuàng)建PHY設(shè)備,這一點與模擬方式流程相同

of_mdiobus_register的流程與第四小節(jié)一致,這里就不再列出。

5. 控制器的讀寫會在哪里得到調(diào)用?

在PHY設(shè)備的注冊中(讀PHY ID)、PHY的初始化、自協(xié)商、中斷、狀態(tài)、能力獲取等流程中經(jīng)常可以看到phy_read和phy_write兩個函數(shù)(下一節(jié)要講的PHY驅(qū)動),這兩個函數(shù)的實現(xiàn)就依賴于控制器設(shè)備mii_bus的讀寫。

phy_read和phy_write定義在linux-4.9.225includelinuxphy.h中,如下:

staticinlineintphy_read(structphy_device*phydev,u32regnum)
{
returnmdiobus_read(phydev->mdio.bus,phydev->mdio.addr,regnum);
}

staticinlineintphy_write(structphy_device*phydev,u32regnum,u16val)
{
returnmdiobus_write(phydev->mdio.bus,phydev->mdio.addr,regnum,val);
}

其中mdiobus_read和mdiobus_write定義在linux-4.9.225drivers etphymdio_bus.c中,如下:

/**
*mdiobus_read-ConveniencefunctionforreadingagivenMIImgmtregister
*@bus:themii_busstruct
*@addr:thephyaddress
*@regnum:registernumbertoread
*
*NOTE:MUSTNOTbecalledfrominterruptcontext,
*becausethebusread/writefunctionsmaywaitforaninterrupt
*toconcludetheoperation.
*/
intmdiobus_read(structmii_bus*bus,intaddr,u32regnum)
{
intretval;

BUG_ON(in_interrupt());

mutex_lock(&bus->mdio_lock);
retval=bus->read(bus,addr,regnum);
mutex_unlock(&bus->mdio_lock);

returnretval;
}

/**
*mdiobus_write-ConveniencefunctionforwritingagivenMIImgmtregister
*@bus:themii_busstruct
*@addr:thephyaddress
*@regnum:registernumbertowrite
*@val:valuetowriteto@regnum
*
*NOTE:MUSTNOTbecalledfrominterruptcontext,
*becausethebusread/writefunctionsmaywaitforaninterrupt
*toconcludetheoperation.
*/
intmdiobus_write(structmii_bus*bus,intaddr,u32regnum,u16val)
{
interr;

BUG_ON(in_interrupt());

mutex_lock(&bus->mdio_lock);
err=bus->write(bus,addr,regnum,val);
mutex_unlock(&bus->mdio_lock);

returnerr;
}

可以清楚的看到bus->read和bus->write讀寫接口在這里得到調(diào)用。

6. mdio_bus總線

接下來要講的PHY設(shè)備驅(qū)動是基于device、driver、bus的連接方式。其驅(qū)動涉及如下幾個重要部分:

總線 - sturct mii_bus (mii stand for media independent interface)

設(shè)備 - struct phy_device

驅(qū)動 - struct phy_driver

關(guān)于PHY設(shè)備的創(chuàng)建和注冊已經(jīng)在第5節(jié)的probe函數(shù)中有過詳細(xì)的描述(需要注意的是:phy設(shè)備不像i2c/spi有一個board_info函數(shù)進(jìn)行設(shè)備的添加,而是直接讀取phy中的寄存器<根據(jù)IEEE的規(guī)定,PHY芯片的前16個寄存器的內(nèi)容必須是固定的>),本節(jié)就不再描述;

6.1 總線注冊的入口函數(shù)

#linux-4.9.225drivers
etphyphy_device.c
staticint__initphy_init(void)
{
intrc;

rc=mdio_bus_init();//mdio_bus總線的注冊
if(rc)
returnrc;

rc=phy_drivers_register(genphy_driver,ARRAY_SIZE(genphy_driver),THIS_MODULE);//通用PHY驅(qū)動
if(rc)
mdio_bus_exit();

returnrc;
}

subsys_initcall(phy_init);

subsys_initcall(phy_init) 這行的作用非常重要,這一行就決定了內(nèi)核在啟動的時候會調(diào)用該函數(shù),注冊完了之后緊接著又注冊一個通用的PHY驅(qū)動。

6.2 總線注冊函數(shù)--- mdio_bus_init解析

#linux-4.9.225drivers
etphymdio_bus.c
staticstructclassmdio_bus_class={
.name="mdio_bus",
.dev_release=mdiobus_release,
};

staticintmdio_bus_match(structdevice*dev,structdevice_driver*drv)
{
structmdio_device*mdio=to_mdio_device(dev);

if(of_driver_match_device(dev,drv))
return1;

if(mdio->bus_match)
returnmdio->bus_match(dev,drv);

return0;
}

structbus_typemdio_bus_type={
.name="mdio_bus",//總線名稱
.match=mdio_bus_match,//用來匹配總線上設(shè)備和驅(qū)動的函數(shù)
.pm=MDIO_BUS_PM_OPS,
};
EXPORT_SYMBOL(mdio_bus_type);

int__initmdio_bus_init(void)
{
intret;

ret=class_register(&mdio_bus_class);//注冊設(shè)備類(在linux設(shè)備模型中,我再仔細(xì)講這個類的概念)
if(!ret){
ret=bus_register(&mdio_bus_type);//總線注冊
if(ret)
class_unregister(&mdio_bus_class);
}

returnret;
}

其中(1) class_register(&mdio_bus_class)執(zhí)行后會有以下設(shè)備類:

/sys/class/mdio_bus

(2)bus_register(&mdio_bus_type)執(zhí)行后會有以下總線類型:

/sys/bus/mdio_bus

6.3 總線中的match函數(shù)解析

/**
*mdio_bus_match-determineifgivenMDIOdriversupportsthegiven
*MDIOdevice
*@dev:targetMDIOdevice
*@drv:givenMDIOdriver
*
*Description:GivenaMDIOdevice,andaMDIOdriver,return1if
*thedriversupportsthedevice.Otherwise,return0.Thismay
*requirecallingthedevicesownmatchfunction,sincedifferentclasses
*ofMDIOdeviceshavedifferentmatchcriteria.
*/
staticintmdio_bus_match(structdevice*dev,structdevice_driver*drv)
{
structmdio_device*mdio=to_mdio_device(dev);

if(of_driver_match_device(dev,drv))
return1;

if(mdio->bus_match)//實現(xiàn)匹配的函數(shù)
returnmdio->bus_match(dev,drv);

return0;
}

7. 設(shè)備驅(qū)動的注冊

在phy_init函數(shù)中不僅注冊了mdio_bus總線,還注冊了一個通用的PHY驅(qū)動作為缺省的內(nèi)核PHY驅(qū)動,但是如果PHY芯片的內(nèi)部寄存器和802.3定義的并不一樣或者需要特殊的功能配置以實現(xiàn)更強的功能,這就需要專有的驅(qū)動。

關(guān)于通用PHY驅(qū)動的知識,網(wǎng)上有一大堆講解,本節(jié)就不再重復(fù)的去描述。

對于市場上存在的主流PHY品牌,一般在內(nèi)核源碼 drivers etphy目錄下都有對應(yīng)的驅(qū)動。本節(jié)主要以realtek RTL8211F為例,講述PHY的驅(qū)動,代碼如下:

#linux-4.9.225drivers
etphy
ealtek.c
staticstructphy_driverrealtek_drvs[]={
......
,{
.phy_id=0x001cc916,
.name="RTL8211FGigabitEthernet",
.phy_id_mask=0x001fffff,
.features=PHY_GBIT_FEATURES,
.flags=PHY_HAS_INTERRUPT,
.config_aneg=&genphy_config_aneg,
.config_init=&rtl8211f_config_init,
.read_status=&genphy_read_status,
.ack_interrupt=&rtl8211f_ack_interrupt,
.config_intr=&rtl8211f_config_intr,
.suspend=genphy_suspend,
.resume=genphy_resume,
},
};

module_phy_driver(realtek_drvs);//注冊PHY驅(qū)動

staticstructmdio_device_id__maybe_unusedrealtek_tbl[]={
{0x001cc912,0x001fffff},
{0x001cc914,0x001fffff},
{0x001cc915,0x001fffff},
{0x001cc916,0x001fffff},
{}
};

MODULE_DEVICE_TABLE(mdio,realtek_tbl);

7.1 phy驅(qū)動的注冊

(1)同一品牌的PHY設(shè)備有多種不同的型號,內(nèi)核為了支持一次可以注冊多個型號的PHY的驅(qū)動,在includelinuxphy.h中提供了用于注冊PHY驅(qū)動的宏module_phy_driver。該宏的定義如下:

#linux-4.9.225includelinuxphy.h

#definephy_module_driver(__phy_drivers,__count)
staticint__initphy_module_init(void)
{
returnphy_drivers_register(__phy_drivers,__count,THIS_MODULE);
}

#definemodule_phy_driver(__phy_drivers)
phy_module_driver(__phy_drivers,ARRAY_SIZE(__phy_drivers))

(2)其中phy_driver_register定義如下(注意這里與老版本內(nèi)核有一定的改動)

/**
*phy_driver_register-registeraphy_driverwiththePHYlayer
*@new_driver:newphy_drivertoregister
*@owner:moduleowningthisPHY
*/
intphy_driver_register(structphy_driver*new_driver,structmodule*owner)
{
intretval;

new_driver->mdiodrv.flags|=MDIO_DEVICE_IS_PHY;
new_driver->mdiodrv.driver.name=new_driver->name;//驅(qū)動名稱
new_driver->mdiodrv.driver.bus=&mdio_bus_type;//驅(qū)動掛載的總線
new_driver->mdiodrv.driver.probe=phy_probe;//PHY設(shè)備和驅(qū)動匹配后調(diào)用的probe函數(shù)
new_driver->mdiodrv.driver.remove=phy_remove;
new_driver->mdiodrv.driver.owner=owner;

retval=driver_register(&new_driver->mdiodrv.driver);//向linux設(shè)備模型框架中注冊device_driver驅(qū)動
if(retval){
pr_err("%s:Error%dinregisteringdriver
",
new_driver->name,retval);

returnretval;
}

pr_debug("%s:Registerednewdriver
",new_driver->name);

return0;
}

intphy_drivers_register(structphy_driver*new_driver,intn,
structmodule*owner)
{
inti,ret=0;

for(i=0;i0)
phy_driver_unregister(new_driver+i);
break;
}
}
returnret;
}

7.2 MODULE_DEVICE_TABLE宏的作用

7.2.1 C語言宏定義##連接符和#符的使用

1 . ## 連接符號"##" 連接符號其功能是在帶參數(shù)的宏定義中將兩個子串(token)聯(lián)接起來,從而形成一個新的子串。但它不可以是第一個或者最后一個子串。所謂的子串(token)就是指編譯器能夠識別的最小語法單元。

簡單的說,“##”是一種分隔連接方式,它的作用是先分隔,然后進(jìn)行強制連接。其中,分隔的作用類似于空格

我們知道在普通的宏定義中,預(yù)處理器一般把空格解釋成分段標(biāo)志,并把分隔后的每一段和前面的定義比較,相同的就被替換。

如果采用空格來分隔,被替換后段與段之間存在一些空格。如果我們不希望出現(xiàn)這些空格,就可以通過添加一些 “##”來替代空格。例如:

#defineexample(name,type)name_##type##_type

"name"和第一個 *之間,以及第2個*和第二個 "type" 之間沒有被分隔,所以預(yù)處理器會把name_##type##*type解釋成3段:"name*"、"type"、以及"_type",其中只有"type"是在宏前面出現(xiàn)過的,所以它可以被宏替換。

2 . # 符號單獨的一個 "#" 則表示: 替換這個變量后,再加雙引號引起來。例如,宏定義 __stringify_1(x) :

#linux-4.9.225includelinuxstringify.h
#define__stringify_1(x)#x

那么 __stringify_1(realtek_tbl) <=等價于=> ”realtek_tbl"

7.2.2 alias函數(shù)

alias定義的函數(shù)將作為另一個函數(shù)的別名。gcc官方的說明部分內(nèi)容如下:5.24 Declaring Attributes of Functions:

alias (“target”)The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified. For instance,

void__f(){/*Dosomething.*/;}
voidf()__attribute__((weak,alias("__f")));

declares f' to be a weak alias for__f'. In C++, the mangled name for the target must be used. It is an error if `__f' is not defined in the same translation unit.

7.2.3 指定變量的屬性 - - - unused的用法

unused 表示該函數(shù)或變量可能不使用,這個屬性可以避免編譯器產(chǎn)生警告信息。在gcc官方的說明部分內(nèi)容如下:

5.31 Specifying Attributes of Variables:unusedThis attribute, attached to a variable, means that the variable is meant to be possibly unused. GCC will not produce a warning for this variable.

7.2.4 MODULE_DEVICE_TABLE解析

MODULE_DEVICE_TABLE宏定義在 /include/linux/module.h中,如下:

/*Createsanaliassofile2alias.ccanfinddevicetable.*/
#defineMODULE_DEVICE_TABLE(type,name)
externconsttypeof(name)__mod_##type##__##name##_device_table
__attribute__((unused,alias(__stringify(name))))

根據(jù)代碼把這個宏展開之后會發(fā)現(xiàn):生成了一個 _mod_type__name_device_table 的符號表,其中type為類型,name是這個驅(qū)動的名稱。在內(nèi)核編譯的時候?qū)⑦@部分符號單獨放置在一個區(qū)域。

當(dāng)內(nèi)核運行的時,用戶可以通過類型(tpye)和類型對應(yīng)的設(shè)備表中名稱(name)中動態(tài)的加載驅(qū)動,在表中查找到了這個符號之后可以迅速的加載驅(qū)動。

MODULE_DEVICE_TABLE的第一個參數(shù)是設(shè)備的類型,如果是PHY設(shè)備,那自然是MDIO(如果是PCI設(shè)備,那將是pci)。后面一個參數(shù)是設(shè)備表,這個設(shè)備表的最后一個元素是空的,用于標(biāo)識結(jié)束。

7.2.5 MODULE_DEVICE_TABLE(mdio, realtek_tbl)解析(待驗證,后續(xù)再來修改)

1. 定義

/**
*structmdio_device_id-identifiesPHYdevicesonanMDIO/MIIbus
*@phy_id:Theresultof
*(mdio_read(&MII_PHYSID1)<

2 . 展開

#defineMODULE_DEVICE_TABLE(mdio,realtek_tbl)
externconststructmdio_device_id__mod_mdio__realtek_tbl_device_table
__attribute__((unused,"realtek_tbl")))

生成一個名為__mod_mdio__realtek_tbl_device_table,內(nèi)核構(gòu)建時,depmod程序會在所有模塊中搜索符號__mod_mdio__realtek_tbl_device_table,把數(shù)據(jù)(設(shè)備列表)從模塊中抽出,添加到映射文件 /lib/modules/KERNEL_VERSION/modules.mdiomap 中,當(dāng)depmod結(jié)束之后,所有的MDIO設(shè)備連同他們的模塊名字都被該文件列出。在需要驅(qū)動的時候,由modules.mdiomap 文件來找尋恰當(dāng)?shù)尿?qū)動程序。

8. 設(shè)備驅(qū)動與控制器驅(qū)動之間的關(guān)系圖

87d3db96-e689-11ed-ab56-dac502259ad0.png

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 控制器
    +關(guān)注

    關(guān)注

    112

    文章

    16436

    瀏覽量

    178983
  • 以太網(wǎng)
    +關(guān)注

    關(guān)注

    40

    文章

    5459

    瀏覽量

    172365
  • Mac
    Mac
    +關(guān)注

    關(guān)注

    0

    文章

    1109

    瀏覽量

    51590
  • PHY
    PHY
    +關(guān)注

    關(guān)注

    2

    文章

    305

    瀏覽量

    51819
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1216

    瀏覽量

    52268

原文標(biāo)題:【網(wǎng)絡(luò)驅(qū)動】以太網(wǎng)掃盲(三)PHY的控制器驅(qū)動框架分析

文章出處:【微信號:嵌入式與Linux那些事,微信公眾號:嵌入式與Linux那些事】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    基于Xilinx FPGA的千兆以太網(wǎng)控制器的開發(fā)

    MAC子層的FPGA設(shè)計、MAC子層與上層協(xié)議的接口設(shè)計以及MAC與物理層(PHY)的MII接口設(shè)計。##Xilinx 提供了三態(tài)以太網(wǎng)MAC控制器的IP Core,可實現(xiàn)單條吉比特以太網(wǎng)
    發(fā)表于 01-23 11:13 ?3w次閱讀
    基于Xilinx FPGA的千兆<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>的開發(fā)

    以太網(wǎng)控制器(MAC)的基本框架怎么搭建

    以太網(wǎng)標(biāo)準(zhǔn)。如圖 10-6 所示,使用這個以太網(wǎng)控制器外部連接一塊 PHY 芯片(實現(xiàn)了物理層功能的芯片)就可以進(jìn)行數(shù)據(jù)鏈路層的通信,即幀通信。在此基礎(chǔ)上可以方便、快捷地開發(fā)出更高層
    發(fā)表于 12-28 17:30

    以太網(wǎng)控制器外部PHY芯片模擬程序代碼實現(xiàn)

    模擬程序模擬了簡化的 LXT971A 芯片(Inter 公司的外部 PHY 芯片)。PHY 芯片通過 MIIM(媒體無關(guān)接口管理模塊)來連接以太網(wǎng)控制器,因此:? 當(dāng)
    發(fā)表于 01-18 14:20

    以太網(wǎng)MAC芯片與PHY芯片的關(guān)系是什么

    如何實現(xiàn)單片以太網(wǎng)控制器以太網(wǎng)MAC是什么?什么是MII?以太網(wǎng)PHY是什么?網(wǎng)卡上除RJ-45接口外,還需要其它元件嗎?造成
    發(fā)表于 12-28 06:22

    以太網(wǎng)芯片MAC和PHY的關(guān)系 精選資料分享

    問:如何實現(xiàn)單片以太網(wǎng)控制器?答:訣竅是將微控制器以太網(wǎng)媒體接入控制器(MAC)和物理接口收發(fā)
    發(fā)表于 07-29 09:22

    以太網(wǎng)控制器芯片的設(shè)計及實現(xiàn)

    以太網(wǎng)控制器芯片的設(shè)計及實現(xiàn) 網(wǎng)絡(luò)控制器芯片的功能與設(shè)計實現(xiàn)IEEE 802.3協(xié)議是針對以太網(wǎng)CSMA/CD標(biāo)準(zhǔn)的傳輸介質(zhì)物理層(PHY
    發(fā)表于 07-26 22:34 ?1566次閱讀
    <b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>芯片的設(shè)計及實現(xiàn)

    以太網(wǎng)接口的數(shù)據(jù)采集控制器

    以太網(wǎng)接口的數(shù)據(jù)采集控制器 LabJack UE9--以太網(wǎng)接口的數(shù)據(jù)采集控制器。LabJack UE9 具有 USB ( 2.0 全速)和以太網(wǎng)
    發(fā)表于 09-09 08:24 ?940次閱讀

    以太網(wǎng)控制器_以太網(wǎng)控制器2012完整版

    網(wǎng)控制器萬能驅(qū)動是一款針對以太網(wǎng)控制器驅(qū)動大全,支持國內(nèi)主流的
    發(fā)表于 09-21 14:39 ?0次下載
    <b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>_<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>控制器</b>2012完整版

    Microchip以太網(wǎng)開關(guān)和EtherCAT工業(yè)控制器及MAC PHY控制設(shè)計解決方案

    Microchip提供了旨在支持新一代以太網(wǎng)開關(guān)、EtherCAT工業(yè)控制器和10/100工業(yè)以太網(wǎng)MAC/PHY控制器的設(shè)計解決方案。
    發(fā)表于 06-15 17:26 ?36次下載
    Microchip<b class='flag-5'>以太網(wǎng)</b>開關(guān)和EtherCAT工業(yè)<b class='flag-5'>控制器</b>及MAC <b class='flag-5'>PHY</b><b class='flag-5'>控制</b>設(shè)計解決方案

    車載以太網(wǎng)MAC和PHY的問題詳解

    問:如何實現(xiàn)單片 以太網(wǎng)控制器 ?答:訣竅是將微控制器以太網(wǎng) 媒體接入控制器 (MAC )和物理接口收發(fā)
    發(fā)表于 06-02 08:00 ?5次下載
    車載<b class='flag-5'>以太網(wǎng)</b>MAC和<b class='flag-5'>PHY</b>的問題詳解

    EE-315:更改Blackfin?處理以太網(wǎng)驅(qū)動程序中的PHY

    EE-315:更改Blackfin?處理以太網(wǎng)驅(qū)動程序中的PHY
    發(fā)表于 04-25 09:51 ?8次下載
    EE-315:更改Blackfin?處理<b class='flag-5'>器</b>的<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>驅(qū)動</b>程序中的<b class='flag-5'>PHY</b>

    以太網(wǎng)——PHY、MAC、MII與網(wǎng)卡

    的芯片稱之為PHY,數(shù)據(jù)鏈路層的芯片稱之為MAC控制器。本文旨在學(xué)習(xí)以太網(wǎng)基礎(chǔ)MAC和PHY的知識,總結(jié)系統(tǒng)框架和物理硬件組成原理,了解各種
    的頭像 發(fā)表于 12-02 10:52 ?2721次閱讀
    <b class='flag-5'>以太網(wǎng)</b>——<b class='flag-5'>PHY</b>、MAC、MII與網(wǎng)卡

    更換不同的以太網(wǎng)PHY

    電子發(fā)燒友網(wǎng)站提供《更換不同的以太網(wǎng)PHY.pdf》資料免費下載
    發(fā)表于 07-31 14:45 ?3次下載
    更換不同的<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>PHY</b>

    使用C2000 EtherCAT從站控制器的SMI進(jìn)行以太網(wǎng)PHY配置

    電子發(fā)燒友網(wǎng)站提供《使用C2000 EtherCAT從站控制器的SMI進(jìn)行以太網(wǎng)PHY配置.pdf》資料免費下載
    發(fā)表于 09-07 10:37 ?0次下載
    使用C2000 EtherCAT從站<b class='flag-5'>控制器</b>的SMI進(jìn)行<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>PHY</b>配置

    AN4754-將Microchip橋接控制器與外部以太網(wǎng)PHY搭配使用

    電子發(fā)燒友網(wǎng)站提供《AN4754-將Microchip橋接控制器與外部以太網(wǎng)PHY搭配使用.pdf》資料免費下載
    發(fā)表于 01-21 13:54 ?0次下載
    AN4754-將Microchip橋接<b class='flag-5'>控制器</b>與外部<b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>PHY</b>搭配使用
    主站蜘蛛池模板: 99在线观看视频| 日韩欧美一区二区三区免费观看| 云南14学生真实初次破初视频| 99久久蜜臀AV免费看蛮| 色宅男午夜电影网站| 公交车轮C关老师| 夜夜精品视频一区二区| 久久精品男人影院| 中文字幕本庄优花喂奶| 浪小辉军警服务员VIDEOS| 一级做a爰片久久毛片潮喷动漫| 久久国产精品久久国产精品| 粗好大用力好深快点漫画| 我把寡妇日出水好爽| 国产人妻午夜无码AV天堂| 亚洲第一天堂无码专区| 好爽别插了无码视频| 别插我B嗯啊视频免费| 一区一区三区产品| 午夜片无码区在线观看| 久久久久久九九| 国产性夜夜性夜夜爽91| 真人女人无遮挡内谢免费视频%| 桃色园社区| 久久精品国产免费中文| 国产精品成人观看视频免费| 亚洲熟妇无码乱子AV电影| 男人的天堂色| 久久re这里视频精品15| 国产人妻人伦精品A区| 成人精品视频在线| 亚洲精品天堂无码中文字幕影院| 求个av网站| 狠狠鲁 我喜欢| 国产精品v片在线观看不卡| jizzxxxx18中国内地| 午夜毛片在线观看| 色偷拍自怕亚洲在线| 日韩1区1区产品乱码芒果榴莲| 欧美成人3d动漫专区| 国内精品免费久久影院|