概述
MAC与PHY是捆绑在一起的,MAC通过SMI(MDC/MDIO)去管理PHY,PHY通过MDI与网络变压器连接。
平台
SSD202D
驱动相关文件:
kernel/drivers/sstar/emac/mdrv_emac.ckernel/drivers/sstar/emac/hal/infinity2m/mhal_emac.ckernel/drivers/sstar/netphy/sstar_100_phy.ckernel/drivers/net/phy/phy.ckernel/drivers/net/phy/fixed_phy.ckernel/drivers/net/phy/phy_device.ckernel/arch/arm/boot/dts/infinity2m.dtsi
202D支持双网卡,因此dts中有两个mac的描述,从描述中可以看到,emac使用了软总线platform bus。
emac0: emac0 {
compatible = "sstar-emac";
interrupts = <GIC_SPI INT_IRQ_EMAC IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_FIQ_LAN_ESD IRQ_TYPE_LEVEL_HIGH>;
clocks = <&CLK_emac_ahb>,<&CLK_emac_tx>,<&CLK_emac_rx>;
reg = <0x1F2A2000 0x800>, <0x1F343C00 0x600>, <0x1F006200 0x600>;
pad = <0x1F203C38 0x0001 0x0000>; // pad selection from 0x0001
phy-handle = <&phy0>;
status = "ok";
mdio-bus@emac0 {
phy0: ethernet-phy@0 {
phy-mode = "mii";
};
};
};
emac1: emac1 {
compatible = "sstar-emac";
interrupts = <GIC_SPI INT_IRQ_EMAC_1 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_FIQ_LAN_ESD IRQ_TYPE_LEVEL_HIGH>;
clocks = <&CLK_emac_ahb>,<&CLK_emac1_tx>,<&CLK_emac1_rx>,<&CLK_emac1_tx_ref>,<&CLK_emac1_rx_ref>;
reg = <0x1F2A2800 0x800>, <0x1F344200 0x600>, <0x00000000 0x000>;
pad = <0x1F203C38 0x0F00 0x0300>; // pad selection from 0x0100/0x0200/0x0300/0x0400/0x0500/0x0600/0x0700/0x0800/0x0900
status = "ok";
#if 1
phy-handle = <&phy1>;
mdio-bus@emac1 {
phy1: ethernet-phy@1 {
phy-mode = "rmii";
};
};
#else
phy-mode = "rmii";
fixed-link = <0 1 100 0 0>;
#endif
};
sysfs中的一些文件:
对应emac驱动的一些关键信息:
/sys/class/mstar/emac1
/sys/class/mstar/emac0
/sys/class/mdio_bus/mdio-bus@emac0
/sys/class/mdio_bus/mdio-bus@emac1
系统启动过程中,MAC与PHY的相关打印:
MSYS: DMEM request: [emac0_buff]:0x00000812
MSYS: DMEM request: [emac0_buff]:0x00000812 success, CPU phy:@0x25242000, virt:@0xC5242000
lonbon_mac_uboot:00FA010D3EEC addr:[0x0 0xfa 0x1 0xd 0x3e 0xec]
libphy: mdio: probed
mdio_bus mdio-bus@emac0: /soc/emac0/mdio-bus@emac0/ethernet-phy@0 has invalid PHY address
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 0 //扫描mac0下的所有phy
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 1
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 2
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 3
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 4
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 5
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 6
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 7
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 8
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 9
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 10
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 11
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 12
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 13
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 14
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 15
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 16
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 17
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 18
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 19
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 20
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 21
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 22
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 23
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 24
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 25
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 26
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 27
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 28
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 29
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 30
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address 31
[emac_phy_connect][3344] connected mac emac0 to PHY at mdio-bus@emac0:00 [uid=11112222, driver=SStar 10/100 Ethernet Phy] 扫描到一张PHY,这张PHY对应的驱动为“SStar 10/100 Ethernet Phy”,(可搜索“SStar 10/100 Ethernet Phy”找到对应的phy driver)
MSYS: DMEM request: [emac1_buff]:0x00060812
MSYS: DMEM request: [emac1_buff]:0x00060812 success, CPU phy:@0x25250000, virt:@0xC5250000
lonbon_mac_uboot:00FA010D3EEC addr:[0x0 0xfa 0x1 0xd 0x3e 0xec]
libphy: mdio: probed
mdio_bus mdio-bus@emac1: /soc/emac1/mdio-bus@emac1/ethernet-phy@1 has invalid PHY address
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 0 //扫描mac1下的所有phy
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 1
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 2
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 3
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 4
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 5
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 6
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 7
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 8
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 9
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 10
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 11
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 12
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 13
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 14
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 15
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 16
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 17
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 18
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 19
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 20
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 21
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 22
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 23
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 24
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 25
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 26
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 27
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 28
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 29
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 30
mdio_bus mdio-bus@emac1: scan phy ethernet-phy at address 31
[emac_phy_connect][3344] connected mac emac1 to PHY at mdio-bus@emac1:00 [uid=00000000, driver=Generic PHY] 扫描到一张PHY,这张PHY对应的驱动为“Generic PHY”(可搜索Generic PHY找到对应的phy driver)
mdio_bus mdio-bus@emac0: scan phy ethernet-phy at address xx这些重复的scan(scan)打印和下面两个流程有关联:
流程1:
[<c001cb33>] (warn_slowpath_null) from [<c01e2651>] (get_phy_device+0xe5/0x124)
[<c01e2651>] (get_phy_device) from [<c01e2803>] (mdiobus_scan+0xf/0xa4)
[<c01e2803>] (mdiobus_scan) from [<c01e292d>] (__mdiobus_register+0x95/0x108) mdiobus_scan的作用:scan a bus for MDIO devices.
[<c01e292d>] (__mdiobus_register) from [<c049bd3d>] (fixed_mdio_bus_init+0x61/0x98)
[<c049bd3d>] (fixed_mdio_bus_init) from [<c0009605>] (do_one_initcall+0xd1/0x104)
[<c0009605>] (do_one_initcall) from [<c048da75>] (kernel_init_freeable+0x12d/0x180)
[<c048da75>] (kernel_init_freeable) from [<c02e59db>] (kernel_init+0x13/0xb4)
[<c02e59db>] (kernel_init) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
流程2:
[<c001cb33>] (warn_slowpath_null) from [<c01e2651>] (get_phy_device+0xe5/0x124)
[<c01e2651>] (get_phy_device) from [<c0236ce7>] (of_mdiobus_register_phy+0x9b/0xa4) 说明:get_phy_device的作用是reads the specified PHY device and returns its @phy_device
[<c0236ce7>] (of_mdiobus_register_phy) from [<c0237047>] (of_mdiobus_register+0xeb/0x10c)
[<c0237047>] (of_mdiobus_register) from [<c02419f5>] (mstar_emac_drv_probe+0x435/0x930) 说明:of_mdiobus_register的作用Register mii_bus and create PHYs from the device tree
[<c02419f5>] (mstar_emac_drv_probe) from [<c019a8ad>] (platform_drv_probe+0x33/0x62) 说明:mstar_emac_drv_probe对应为emac的平台驱动,这个接口会调用MDev_EMAC_mii_init,MDev_EMAC_mii_init又会调用of_mdiobus_register
[<c019a8ad>] (platform_drv_probe) from [<c0199b2d>] (driver_probe_device+0x10d/0x194)
[<c0199b2d>] (driver_probe_device) from [<c0199bf7>] (__driver_attach+0x43/0x5c)
[<c0199bf7>] (__driver_attach) from [<c0198c1f>] (bus_for_each_dev+0x3d/0x46)
[<c0198c1f>] (bus_for_each_dev) from [<c019958f>] (bus_add_driver+0xd7/0x130)
[<c019958f>] (bus_add_driver) from [<c019a0a1>] (driver_register+0x4d/0x78)
[<c019a0a1>] (driver_register) from [<c0009605>] (do_one_initcall+0xd1/0x104)
[<c0009605>] (do_one_initcall) from [<c048da75>] (kernel_init_freeable+0x12d/0x180)
[<c048da75>] (kernel_init_freeable) from [<c02e59db>] (kernel_init+0x13/0xb4)
[<c02e59db>] (kernel_init) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
热插拔网线的打印:
[emac_phy_link_adjust] EMAC Link Down
[EMAC] uRegVal_8x: -37, uRegVal_9x: 28
[EMAC] uRegVal_8x: -38, uRegVal_9x: 18
[EMAC] uRegVal_8x: -40, uRegVal_9x: 21
[EMAC] uRegVal_8x: -43, uRegVal_9x: 27
[EMAC] uRegVal_8x: -40, uRegVal_9x: 26
[EMAC] uRegVal_8x: -40, uRegVal_9x: 19
[emac_phy_link_adjust] EMAC Link Up
拔掉网卡时的堆栈调用如下:phy_state_machine接口是一个专门处理phy的状态的状态机函数,phy_state_machine函数是以INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine)工作队列形式注册到内核中:emac_phy_link_adjust函数负责处理调整phy link。
[<c023fe27>] (emac_phy_link_adjust) from [<c01e133b>] (phy_state_machine+0x215/0x2c6)
[<c01e133b>] (phy_state_machine) from [<c002aae1>] (process_one_work+0x125/0x1ec)
[<c002aae1>] (process_one_work) from [<c002af4f>] (worker_thread+0x1c3/0x2a4)
[<c002af4f>] (worker_thread) from [<c002dab7>] (kthread+0xa1/0xb2)
[<c002dab7>] (kthread) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
[emac_phy_link_adjust] EMAC Link Down
插上网线,提示“EMAC Link Up”的堆栈和拔掉网线是一样的。只是热拔插的状态机的状态不一样
[<c023fdeb>] (emac_phy_link_adjust) from [<c01e120f>] (phy_state_machine+0xe9/0x2c6)
[<c01e120f>] (phy_state_machine) from [<c002aae1>] (process_one_work+0x125/0x1ec)
[<c002aae1>] (process_one_work) from [<c002af4f>] (worker_thread+0x1c3/0x2a4)
[<c002af4f>] (worker_thread) from [<c002dab7>] (kthread+0xa1/0xb2)
[<c002dab7>] (kthread) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
[emac_phy_link_adjust] EMAC Link Up
插上网线时,会打印很多行[EMAC] uRegVal_8x: -37, uRegVal_9x: 28类似的打印,这些打印是在_MHal_EMAC_DPHY_REINIT接口中打印的,这个接口主要负责建立通路是,对phy进行复位:
[<c001cb33>] (_MHal_EMAC_DPHY_REINIT) from [<c02429bb>] (MHal_EMAC_update_speed_duplex+0x4f/0x190)
[<c02429bb>] (MHal_EMAC_update_speed_duplex) from [<c023fdcf>] (emac_phy_link_adjust+0x5b/0xb0)
[<c023fdcf>] (emac_phy_link_adjust) from [<c01e120f>] (phy_state_machine+0xe9/0x2c6)
[<c01e120f>] (phy_state_machine) from [<c002aae1>] (process_one_work+0x125/0x1ec)
[<c002aae1>] (process_one_work) from [<c002af4f>] (worker_thread+0x1c3/0x2a4)
[<c002af4f>] (worker_thread) from [<c002dab7>] (kthread+0xa1/0xb2)
[<c002dab7>] (kthread) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
mdiobus_read与mdiobus_write :
mdiobus_read/mdiobus_write的作用是Convenience function for reading/writing a given MII management register。mdiobus_read/mdiobus_write的定义如下:
int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
{
int retval;
BUG_ON(in_interrupt());
mutex_lock(&bus->mdio_lock);
retval = bus->read(bus, addr, regnum);
mutex_unlock(&bus->mdio_lock);
return retval;
}
int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
{
int err;
BUG_ON(in_interrupt());
mutex_lock(&bus->mdio_lock);
err = bus->write(bus, addr, regnum, val);
mutex_unlock(&bus->mdio_lock);
return err;
}
其中bus->read和bus->write是在下面的接口中填充:
static int MDev_EMAC_mii_init(struct net_device* emac_dev)
{
struct emac_handle *hemac = (struct emac_handle *) netdev_priv(emac_dev);
hemac->mii_bus->name = "mdio";
hemac->mii_bus->read = MDev_EMAC_mii_read; //MDev_EMAC_mii_read的作用是Read value stored in a PHY register
hemac->mii_bus->write = MDev_EMAC_mii_write; //MDev_EMAC_mii_write的作用是Write value to the a PHY register
}
注册网络设备的流程:
[<c001cb33>] (warn_slowpath_null) from [<c01e182b>] (genphy_config_init+0xf/0x9c)
[<c01e182b>] (genphy_config_init) from [<c01e2449>] (phy_attach_direct+0xe3/0x10a)
[<c01e2449>] (phy_attach_direct) from [<c01e24f7>] (phy_connect_direct+0xf/0x2e)
[<c01e24f7>] (phy_connect_direct) from [<c0236d4b>] (of_phy_connect+0x23/0x32)
[<c0236d4b>] (of_phy_connect) from [<c049e4db>] (MDev_EMAC_ndo_init+0x57/0x150)
[<c049e4db>] (MDev_EMAC_ndo_init) from [<c0264b57>] (register_netdevice+0x59/0x2ea) register_netdevice的作用是:register a network device
[<c0264b57>] (register_netdevice) from [<c0264df7>] (register_netdev+0xf/0x18)
[<c0264df7>] (register_netdev) from [<c02419fb>] (mstar_emac_drv_probe+0x43b/0x930)
[<c02419fb>] (mstar_emac_drv_probe) from [<c019a8ad>] (platform_drv_probe+0x33/0x62)
[<c019a8ad>] (platform_drv_probe) from [<c0199b2d>] (driver_probe_device+0x10d/0x194)
[<c0199b2d>] (driver_probe_device) from [<c0199bf7>] (__driver_attach+0x43/0x5c)
[<c0199bf7>] (__driver_attach) from [<c0198c1f>] (bus_for_each_dev+0x3d/0x46)
[<c0198c1f>] (bus_for_each_dev) from [<c019958f>] (bus_add_driver+0xd7/0x130)
[<c019958f>] (bus_add_driver) from [<c019a0a1>] (driver_register+0x4d/0x78)
[<c019a0a1>] (driver_register) from [<c0009605>] (do_one_initcall+0xd1/0x104)
[<c0009605>] (do_one_initcall) from [<c048da75>] (kernel_init_freeable+0x12d/0x180)
[<c048da75>] (kernel_init_freeable) from [<c02e59db>] (kernel_init+0x13/0xb4)
[<c02e59db>] (kernel_init) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
restart auto-negotiation or write BMCR的流程:
[<c001cb33>] (warn_slowpath_null) from [<c01e1d29>] (genphy_config_aneg+0x55/0x174)
[<c01e1d29>] (genphy_config_aneg) from [<c01e0c57>] (phy_start_aneg_priv+0x7f/0xf4)
[<c01e0c57>] (phy_start_aneg_priv) from [<c049e5a1>] (MDev_EMAC_ndo_init+0x11d/0x150)
[<c049e5a1>] (MDev_EMAC_ndo_init) from [<c0264b57>] (register_netdevice+0x59/0x2ea)
[<c0264b57>] (register_netdevice) from [<c0264df7>] (register_netdev+0xf/0x18)
[<c0264df7>] (register_netdev) from [<c02419fb>] (mstar_emac_drv_probe+0x43b/0x930)
[<c02419fb>] (mstar_emac_drv_probe) from [<c019a8ad>] (platform_drv_probe+0x33/0x62)
[<c019a8ad>] (platform_drv_probe) from [<c0199b2d>] (driver_probe_device+0x10d/0x194)
[<c0199b2d>] (driver_probe_device) from [<c0199bf7>] (__driver_attach+0x43/0x5c)
[<c0199bf7>] (__driver_attach) from [<c0198c1f>] (bus_for_each_dev+0x3d/0x46)
[<c0198c1f>] (bus_for_each_dev) from [<c019958f>] (bus_add_driver+0xd7/0x130)
[<c019958f>] (bus_add_driver) from [<c019a0a1>] (driver_register+0x4d/0x78)
[<c019a0a1>] (driver_register) from [<c0009605>] (do_one_initcall+0xd1/0x104)
[<c0009605>] (do_one_initcall) from [<c048da75>] (kernel_init_freeable+0x12d/0x180)
[<c048da75>] (kernel_init_freeable) from [<c02e59db>] (kernel_init+0x13/0xb4)
[<c02e59db>] (kernel_init) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
Enable and Restart Autonegotiation的流程:
[<c001cb33>] (warn_slowpath_null) from [<c01e1c0f>] (genphy_restart_aneg+0xf/0x44)
[<c01e1c0f>] (genphy_restart_aneg) from [<c01e0c57>] (phy_start_aneg_priv+0x7f/0xf4)
[<c01e0c57>] (phy_start_aneg_priv) from [<c049e5a1>] (MDev_EMAC_ndo_init+0x11d/0x150)
[<c049e5a1>] (MDev_EMAC_ndo_init) from [<c0264b57>] (register_netdevice+0x59/0x2ea)
[<c0264b57>] (register_netdevice) from [<c0264df7>] (register_netdev+0xf/0x18)
[<c0264df7>] (register_netdev) from [<c02419fb>] (mstar_emac_drv_probe+0x43b/0x930)
[<c02419fb>] (mstar_emac_drv_probe) from [<c019a8ad>] (platform_drv_probe+0x33/0x62)
[<c019a8ad>] (platform_drv_probe) from [<c0199b2d>] (driver_probe_device+0x10d/0x194)
[<c0199b2d>] (driver_probe_device) from [<c0199bf7>] (__driver_attach+0x43/0x5c)
[<c0199bf7>] (__driver_attach) from [<c0198c1f>] (bus_for_each_dev+0x3d/0x46)
[<c0198c1f>] (bus_for_each_dev) from [<c019958f>] (bus_add_driver+0xd7/0x130)
[<c019958f>] (bus_add_driver) from [<c019a0a1>] (driver_register+0x4d/0x78)
[<c019a0a1>] (driver_register) from [<c0009605>] (do_one_initcall+0xd1/0x104)
[<c0009605>] (do_one_initcall) from [<c048da75>] (kernel_init_freeable+0x12d/0x180)
[<c048da75>] (kernel_init_freeable) from [<c02e59db>] (kernel_init+0x13/0xb4)
[<c02e59db>] (kernel_init) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
update link status in @phydev的调用流程:这里的作用是侦测网络状态的变化,例如:通断、速率切换,全双工与半双工切换等等,更加侦测到的状态执行update link操作
[<c001cb33>] (warn_slowpath_null) from [<c01e210f>] (genphy_update_link+0xf/0x54)
[<c01e210f>] (genphy_update_link) from [<c01e215d>] (genphy_read_status+0x9/0x1a4) genphy_read_status的作用是check the link status and update current link state
[<c01e215d>] (genphy_read_status) from [<c023f36f>] (sstar_phy_read_status+0xb/0x134)
[<c023f36f>] (sstar_phy_read_status) from [<c01e11b9>] (phy_state_machine+0x93/0x2c6)
[<c01e11b9>] (phy_state_machine) from [<c002aae1>] (process_one_work+0x125/0x1ec)
[<c002aae1>] (process_one_work) from [<c002af4f>] (worker_thread+0x1c3/0x2a4)
[<c002af4f>] (worker_thread) from [<c002dab7>] (kthread+0xa1/0xb2)
[<c002dab7>] (kthread) from [<c000d5c1>] (ret_from_fork+0x11/0x30)
当phy_state_machine检测当前的连接状态(断开或者连接)发生变化,则调用sstar_phy_read_status读取phy的状态,
一个通用的读写PHY寄存器的程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/mii.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <linux/types.h>
#include <netinet/in.h>
#define reteck(ret) \
if(ret < 0){ \
printf("%m! \"%s\" : line: %d\n", __func__, __LINE__); \
goto lab; \
}
#define help() \
printf("mdio:\n"); \
printf("read operation: mdio reg_addr\n"); \
printf("write operation: mdio reg_addr value\n"); \
printf("For example:\n"); \
printf("mdio eth0 1\n"); \
printf("mdio eth0 0 0x12\n\n"); \
exit(0);
int sockfd;
int main(int argc, char *argv[]){
if(argc == 1 || !strcmp(argv[1], "-h")){
help();
}
struct mii_ioctl_data *mii = NULL;
struct ifreq ifr;
int ret;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1);
sockfd = socket(PF_LOCAL, SOCK_DGRAM, 0);
reteck(sockfd);
//get phy address in smi bus
ret = ioctl(sockfd, SIOCGMIIPHY, &ifr); //一个mac可以适配多个PHY,每一个PHY认为是一张网卡,根据传入的参数(假设为eth0),则这里的作用是获得eth0网卡的所对应的PHY。
reteck(ret);
mii = (struct mii_ioctl_data*)&ifr.ifr_data;
if(argc == 3){
mii->reg_num = (uint16_t)strtoul(argv[2], NULL, 0);
ret = ioctl(sockfd, SIOCGMIIREG, &ifr);
reteck(ret);
printf("read phy addr: 0x%x reg: 0x%x value : 0x%x\n\n", mii->phy_id, mii->reg_num, mii->val_out);
}else if(argc == 4){
mii->reg_num = (uint16_t)strtoul(argv[2], NULL, 0);
mii->val_in = (uint16_t)strtoul(argv[3], NULL, 0);
ret = ioctl(sockfd, SIOCSMIIREG, &ifr);
reteck(ret);
printf("write phy addr: 0x%x reg: 0x%x value : 0x%x\n\n", mii->phy_id, mii->reg_num, mii->val_in);
}
lab:
close(sockfd);
return 0;
}
