概述

MAC与PHY是捆绑在一起的,MAC通过SMI(MDC/MDIO)去管理PHY,PHY通过MDI与网络变压器连接。

平台

SSD202D

驱动相关文件:

  1. kernel/drivers/sstar/emac/mdrv_emac.c
  2. kernel/drivers/sstar/emac/hal/infinity2m/mhal_emac.c
  3. kernel/drivers/sstar/netphy/sstar_100_phy.c
  4. kernel/drivers/net/phy/phy.c
  5. kernel/drivers/net/phy/fixed_phy.c
  6. kernel/drivers/net/phy/phy_device.c
  7. kernel/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;
}