ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

[linux kernel] 内核下ksz9031驱动调试踩过的坑

2021-04-07 12:31:20  阅读:995  来源: 互联网

标签:libphy kernel ksz9031 addr get phy linux device id


系统版本:Ubuntu18.04-64

编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1)

uboot版本:2018.07 -linux4sam_6.0

板子型号:at91sama5d3x-xplained

MCU型号:sama5d36

内核中调试驱动,和uboot中会有些区别,因为内核启动过程是顺序启动的,硬件上电后,外部的器件要快速做好准备工作,内核代码初始化到这个器件如果器件没有完成上电复位,很可能会驱动失败,需要硬件和软件时序同步,这是非常重要的一点。

【Datasheet】PHY KSZ9031千兆网络芯片解读

[Linux 底层]U-boot ksz9031网络驱动调试

一、PHY在内核配置中需要使能对应的芯片厂商驱动Micrel公司PHY;

make menuconfig

Device Drivers  --->
     [*] Network device support  ---> 
        [*]   Ethernet driver support  --->
        -*-   MDIO bus device drivers  ---- //MDIO控制器读取PHY寄存器
        -*-   PHY Device support and infrastructure  --->
            <*>   Micrel PHYs       //Micrel公司的ksz9031和ksz8081


二、修改设备树文件,硬件配置语言,所有的硬件相关信息都需要从设备树中获取。这是新内核的特性。

//arch/arm/boot/dts/at91-sama5d3_xplaint.dts

            macb0: ethernet@f0028000 {
                phy-mode = "rgmii";
                #address-cells = <1>;
                #size-cells = <0>;
                status = "okay";

                ethernet-phy@0 {
                    reg = <0x0>;
                };
            };

三、把编译出的zImage烧录进板子,查看打印信息

CAN device driver interface
at91_can f000c000.can: device registered (reg_base=(ptrval), irq=42)
libphy: MACB_mii_bus: probed
Generic PHY f0028000.ethernet-ffffffff:01: attached PHY driver [Generic PHY] (mii_bus:phy_addr=f0028000.ethernet-ffffffff:01, irq=POLL)
macb f0028000.ethernet eth0: Cadence GEM rev 0x00020119 at 0xf0028000 irq 43 (ee:ab:c1:d2:e6:c6)
macb f802c000.ethernet: invalid hw address, using random
libphy: MACB_mii_bus: probed
Micrel KSZ8081 or KSZ8091 f802c000.ethernet-ffffffff:01: attached PHY driver [Micrel KSZ8081 or KSZ8091] (mii_bus:phy_addr=f802c000.ethernet-ffffffff:01, irq=49)
macb f802c000.ethernet eth1: Cadence MACB rev 0x0001010c at 0xf802c000 irq 44 (36:d7:c3:e6:2a:c7)
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver5d36

其中,Generic PHY f0028000.ethernet-ffffffff:01;获取到得ID为全FF,硬件地址01;这里获取芯片的ID错误了,可能出错的点有MDIO配置错误,或者设备树配置错误;

不用太担心,可以根据打印的信息,查找对应的代码,添加上一些标识在里面;比如:macb f0028000.ethernet: macb_probe phy_interface=2.接口方式,可以搜索出对应的代码,然后添加Jack标识,再次烧录,即可打印出添加的信息;

linux-at91-linux-4.19-at91\drivers\net\ethernet\cadence\macb_main.c

static int macb_probe(struct platform_device *pdev)函数添加打印,

使用dev_info,用调试串口把信息打印出来,这是调试的必备手段;

图片

我们下面把PHY的接口方式,PHY ID都打印出来,看看和设备树是否能够对应上;

2、内核的网卡驱动找不到对应的PHY驱动
内核打印信息
macb f0028000.ethernet: Jack macb_probe phy_interface=2.
macb f0028000.ethernet: macb_mii_init name=f0028000.ethernet,id=ffffffff
libphy: MACB_mii_bus: probed
Generic PHY f0028000.ethernet-ffffffff:07: attached PHY driver [Generic PHY] (mii_bus:phy_addr=f0028000.ethernet-ffffffff:07, irq=POLL)
macb f0028000.ethernet eth0: Cadence GEM rev 0x00020119 at 0xf0028000 irq 46 (ee:ab:c1:d2:e6:c6)
macb f802c000.ethernet: invalid hw address, using random
macb f802c000.ethernet: Jack macb_probe phy_interface=7.
macb f802c000.ethernet: macb_mii_init name=f802c000.ethernet,id=ffffffff
libphy: MACB_mii_bus: probed
Generic PHY f802c000.ethernet-ffffffff:01: attached PHY driver [Generic PHY] (mii_bus:phy_addr=f802c000.ethernet-ffffffff:01, irq=POLL)
macb f802c000.ethernet eth1: Cadence MACB rev 0x0001010c at 0xf802c000 irq 47 (06:50:95:f8:63:dc)

全是id=ffffffff,怀疑是MDIO有问题
这里只匹配了Ksz8081的驱动;

phy_interface = 2;代表是MII接口

图片

四、继续添加打印信息,PHY外部最多可挂载32个PHY设备,内核是如何做识别的呢,使用for循环扫描的,如果读取到ID不为全FF,则认为是有效的设备,会对该设备进行驱动配对;再往前添加一些打印信息,看看扫描的过程是如何的;

libphy: mdiobus_scan i= 0
libphy: get_phy_device addr=0,get_phy_id=-1,
libphy: mdiobus_scan i= 1
libphy: get_phy_device addr=1,get_phy_id=-1,
libphy: mdiobus_scan i= 2
libphy: get_phy_device addr=2,get_phy_id=-1,
libphy: mdiobus_scan i= 3
libphy: get_phy_device addr=3,get_phy_id=-1,
libphy: mdiobus_scan i= 4
libphy: get_phy_device addr=4,get_phy_id=-1,
libphy: mdiobus_scan i= 5
libphy: get_phy_device addr=5,get_phy_id=-1,
libphy: mdiobus_scan i= 6
libphy: get_phy_device addr=6,get_phy_id=-1,
libphy: mdiobus_scan i= 7
libphy: get_phy_device addr=7,get_phy_id=-1,
libphy: mdiobus_scan i= 8
libphy: get_phy_device addr=8,get_phy_id=-1,
libphy: mdiobus_scan i= 9
libphy: get_phy_device addr=9,get_phy_id=-1,
libphy: mdiobus_scan i= 10
libphy: get_phy_device addr=10,get_phy_id=-1,
libphy: mdiobus_scan i= 11
libphy: get_phy_device addr=11,get_phy_id=-1,
libphy: mdiobus_scan i= 12
libphy: get_phy_device addr=12,get_phy_id=-1,
libphy: mdiobus_scan i= 13
libphy: get_phy_device addr=13,get_phy_id=-1,
libphy: mdiobus_scan i= 14
libphy: get_phy_device addr=14,get_phy_id=-1,
libphy: mdiobus_scan i= 15
libphy: get_phy_device addr=15,get_phy_id=-1,
libphy: mdiobus_scan i= 16
libphy: get_phy_device addr=16,get_phy_id=-1,
libphy: mdiobus_scan i= 17
libphy: get_phy_device addr=17,get_phy_id=-1,
libphy: mdiobus_scan i= 18
libphy: get_phy_device addr=18,get_phy_id=-1,
libphy: mdiobus_scan i= 19
libphy: get_phy_device addr=19,get_phy_id=-1,
libphy: mdiobus_scan i= 20
libphy: get_phy_device addr=20,get_phy_id=-1,
libphy: mdiobus_scan i= 21
libphy: get_phy_device addr=21,get_phy_id=-1,
libphy: mdiobus_scan i= 22
libphy: get_phy_device addr=22,get_phy_id=-1,
libphy: mdiobus_scan i= 23
libphy: get_phy_device addr=23,get_phy_id=-1,
libphy: mdiobus_scan i= 24
libphy: get_phy_device addr=24,get_phy_id=-1,
libphy: mdiobus_scan i= 25
libphy: get_phy_device addr=25,get_phy_id=-1,
libphy: mdiobus_scan i= 26
libphy: get_phy_device addr=26,get_phy_id=-1,
libphy: mdiobus_scan i= 27
libphy: get_phy_device addr=27,get_phy_id=-1,
libphy: mdiobus_scan i= 28
libphy: get_phy_device addr=28,get_phy_id=-1,
libphy: mdiobus_scan i= 29
libphy: get_phy_device addr=29,get_phy_id=-1,
libphy: mdiobus_scan i= 30
libphy: get_phy_device addr=30,get_phy_id=-1,
libphy: mdiobus_scan i= 31
libphy: get_phy_device addr=31,get_phy_id=-1,
libphy: Fixed MDIO Bus: probed
CAN device driver interface
at91_can f000c000.can: device registered (reg_base=(ptrval), irq=45)
macb f0028000.ethernet: Jack macb_probe phy_interface=2.
macb f0028000.ethernet: Jack macb_is_gem gem_ethtool_ops
macb f0028000.ethernet: Jack macb_mdc_clk_div =0x100000
macb f0028000.ethernet: Jack macb_dbw =0x300000,bp->phy_interface=2
libphy: MACB_mii_bus: probed
libphy: get_phy_device addr=0,get_phy_id=25278624,
Generic PHY f0028000.ethernet-ffffffff:00: attached PHY driver [Generic PHY] (mii_bus:phy_addr=f0028000.ethernet-ffffffff:00, irq=POLL)
macb f0028000.ethernet eth0: Cadence GEM rev 0x00020119 at 0xf0028000 irq 46 (ee:ab:c1:d2:e6:c6)
macb f802c000.ethernet: invalid hw address, using random
macb f802c000.ethernet: Jack macb_probe phy_interface=7.
macb f802c000.ethernet: Jack macb_is_gem macb_ethtool_ops
macb f802c000.ethernet: Jack macb_mdc_clk_div =0xc00
macb f802c000.ethernet: Jack macb_dbw =0xc00,bp->phy_interface=7

libphy: MACB_mii_bus: probed
libphy: get_phy_device addr=0,get_phy_id=2233697,
Micrel KSZ8081 or KSZ8091 f802c000.ethernet-ffffffff:00: attached PHY driver [Micrel KSZ8081 or KSZ8091] (mii_bus:phy_addr=f802c000.ethernet-ffffffff:00, irq=POLL)
macb f802c000.ethernet eth1: Cadence MACB rev 0x0001010c at 0xf802c000 irq 44 (86:82:71:07:ba:d2)



libphy: MACB_mii_bus: probed

libphy: get_phy_device addr=0,get_phy_id=25278624;其中在地址0上面读取到了PHY的ID,转化为16进制:0xF113644,和手册上面无法对应;但是为什么就是驱动识别不了呢?

更改设备树的PHY芯片地址;

//arch/arm/boot/dts/at91-sama5d3_xplaint.dts
GMAC外部PHY的地址为7,dts中配置的地址为0,地址不匹配,读取不了数据;
            macb0: ethernet@f0028000 {
                phy-mode = "rgmii";
                #address-cells = <1>;
                #size-cells = <0>;
                status = "okay";

                ethernet-phy@0 {
                    reg = <0x0>;
                };
            };

    改为:
            macb0: ethernet@f0028000 {
                phy-mode = "mii";
                #address-cells = <1>;
                #size-cells = <0>;
                status = "okay";

                ethernet-phy@7{
                    reg = <0x7>;
                };
            };
再次下载尝试,打印识别芯片正常,驱动可以正确匹配;
libphy: MACB_mii_bus: probed
libphy: get_phy_device addr=3,get_phy_id=-1,
mdio_bus f0028000.ethernet-ffffffff: MDIO device at address 3 is missing.
libphy: get_phy_device addr=0,get_phy_id=-1,
libphy: get_phy_device addr=1,get_phy_id=-1,
libphy: get_phy_device addr=2,get_phy_id=-1,
libphy: get_phy_device addr=3,get_phy_id=-1,
libphy: get_phy_device addr=4,get_phy_id=-1,
libphy: get_phy_device addr=5,get_phy_id=-1,
libphy: get_phy_device addr=6,get_phy_id=-1,
libphy: get_phy_device addr=7,get_phy_id=2233890,
libphy: get_phy_device addr=8,get_phy_id=-1,
libphy: get_phy_device addr=9,get_phy_id=-1,
libphy: get_phy_device addr=10,get_phy_id=-1,
libphy: get_phy_device addr=11,get_phy_id=-1,
libphy: get_phy_device addr=12,get_phy_id=-1,
libphy: get_phy_device addr=13,get_phy_id=-1,
libphy: get_phy_device addr=14,get_phy_id=-1,
libphy: get_phy_device addr=15,get_phy_id=-1,
libphy: get_phy_device addr=16,get_phy_id=-1,
libphy: get_phy_device addr=17,get_phy_id=-1,
libphy: get_phy_device addr=18,get_phy_id=-1,
libphy: get_phy_device addr=19,get_phy_id=-1,
libphy: get_phy_device addr=20,get_phy_id=-1,
libphy: get_phy_device addr=21,get_phy_id=-1,
libphy: get_phy_device addr=22,get_phy_id=-1,
libphy: get_phy_device addr=23,get_phy_id=-1,
libphy: get_phy_device addr=24,get_phy_id=-1,
libphy: get_phy_device addr=25,get_phy_id=-1,
libphy: get_phy_device addr=26,get_phy_id=-1,
libphy: get_phy_device addr=27,get_phy_id=-1,
libphy: get_phy_device addr=28,get_phy_id=-1,
libphy: get_phy_device addr=29,get_phy_id=-1,
libphy: get_phy_device addr=30,get_phy_id=-1,
libphy: get_phy_device addr=31,get_phy_id=-1,
Micrel KSZ9031 Gigabit PHY f0028000.ethernet-ffffffff:07: attached PHY driver [Micrel KSZ9031 Gigabit PHY] (mii_bus:phy_addr=f0028000.ethernet-ffffffff:07, irq=POLL)

五、下面梳理一下PHY的驱动加载流程

1、根据dts中的硬件配置,新建device

drivers\net\ethernet\cadence\macb_main.c

    { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config },
    { .compatible = "atmel,sama5d3-macb", .data = &sama5d3macb_config },

static const struct macb_config sama5d3_config = {
    .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE
          | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_JUMBO,
    .dma_burst_length = 16,
    .clk_init = macb_clk_init,
    .init = macb_init,
    .jumbo_max_len = 10240,
};

static const struct of_device_id macb_dt_ids[] = {
    { .compatible = "cdns,at32ap7000-macb" },
    { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config },
    { .compatible = "cdns,macb" },
    { .compatible = "cdns,np4-macb", .data = &np4_config },
    { .compatible = "cdns,pc302-gem", .data = &pc302gem_config },
    { .compatible = "cdns,gem", .data = &pc302gem_config },
    { .compatible = "cdns,sam9x60-macb", .data = &at91sam9260_config },
    { .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config },
    { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config },
    { .compatible = "atmel,sama5d3-macb", .data = &sama5d3macb_config },
    { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config },
    { .compatible = "cdns,at91rm9200-emac", .data = &emac_config },
    { .compatible = "cdns,emac", .data = &emac_config },
    { .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config},
    { .compatible = "cdns,zynq-gem", .data = &zynq_config },
    { /* sentinel */ }
};

2、device创建

macb_probe//入口函数
macb_mii_init//MII接口初始化
mdiobus_register//MDIO总线注册
device_register//设备注册
mdiobus_scan 0~32//循环扫描32个外部设备
get_phy_device//获取PHY ID
get_phy_id //获取硬件PHY的ID,用来匹配驱动
phy_device_create//PHY设备创建
phy_bus_match //匹配驱动函数
mdiobus_setup_mdiodev_from_board_info//MDIO创建设备
mdiobus_create_device//用于文件系统调试MDIO总线
macb_init//初始化完成

3、Driver创建

MODULE_DEVICE_TABLE(mdio, davicom_tbl);

module_phy_driver(dm91xx_driver);

启动文件系统尝试ping设备,验证驱动是否OK

测试结果为:ksz9031,需要多次插拔网线,才能检测到网线连接;

root@sama5d3-xplained:~# ifconfig
eth0      Link encap:Ethernet  HWaddr ee:ab:c1:d2:e6:c6  
          inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::ecab:c1ff:fed2:e6c6/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:1795 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1076 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:150514 (146.9 KiB)  TX bytes:113046 (110.3 KiB)
          Interrupt:46 Base address:0x8000 

eth1      Link encap:Ethernet  HWaddr aa:ab:c1:d2:e6:c6  
          inet addr:192.168.2.100  Bcast:192.168.2.255  Mask:255.255.255.0
          inet6 addr: fe80::a8ab:c1ff:fed2:e6c6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2334 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1797 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:696836 (680.5 KiB)  TX bytes:671982 (656.2 KiB)
          Interrupt:47 Base address:0xc000 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:35 errors:0 dropped:0 overruns:0 frame:0
          TX packets:35 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:3836 (3.7 KiB)  TX bytes:3836 (3.7 KiB)

怀疑是硬件和文件系统状态不同步导致;

4.1 ksz9031,使用外部杜邦线短接rst,使PHY芯片强制复位,看到网口灯正常;

4.2在文件系统中同步硬件状态;ifconfig eth0 down; ifconfig eth0 up; 强制让PHY驱动不工作后,再次使能;

4.3千兆网进入正常状态,多次试验,热插拔都可以正确识别,ping也可以正常通讯;

以上三个步骤做完,发现网卡驱动正常了;这就好 办了,说明我们的猜测是对的;

抱着芯片手册又啃了几遍,发现端倪;

通过代码走查,打印PHY寄存器状态值,MII_ADVERTISE(0x04)寄存器值为0xde1,为对称和不对称暂停功能;链路不能被激活;

//driver/net/phy/phy_device.c

//driver/net/phy/phy_device.c
/**
 * genphy_restart_aneg - Enable and Restart Autonegotiation
 * @phydev: target phy_device struct
 */
int genphy_restart_aneg(struct phy_device *phydev)
{
    int ctl;//,ictl,adv,lpagb,iadv;
    ctl = phy_read(phydev, MII_BMCR);

    //pr_info("jack genphy_restart_aneg MII_BMCR = 0x%x\n",ctl);

    /* Don't isolate the PHY if we're negotiating */
    phy_write(phydev, MII_ADVERTISE, 0x1e1);    //改为无暂停;让芯片正常侦测信号

    ctl = 0;
    ctl = phy_modify(phydev, MII_BMCR, BMCR_ISOLATE,
              BMCR_ANENABLE | BMCR_ANRESTART);
    //return phy_modify(phydev, MII_BMCR, BMCR_ISOLATE,
    //        BMCR_ANENABLE  | BMCR_ANRESTART);
/*
    pr_info("genphy_restart_aneg modify MII_BMCR = 0x%x\n",ctl);

    //mdelay(3000);
    ictl = phy_read(phydev, MII_BMSR);
    pr_info("genphy_restart_aneg read MII_BMSR = 0x%x\n",ictl);

    adv = phy_read(phydev, MII_CTRL1000);
    pr_info("genphy_restart_aneg read MII_CTRL1000 = 0x%x\n",adv);

    lpagb = phy_read(phydev, MII_STAT1000);
    pr_info("genphy_restart_aneg read MII_STAT1000 = 0x%x\n",lpagb);

    phy_write(phydev, MII_ADVERTISE, 0x1e1);
    iadv = phy_read(phydev, MII_ADVERTISE);
    pr_info("genphy_restart_aneg read MII_ADVERTISE = 0x%x\n",iadv);
*/
    return ctl;
}

测试之后发现可以正常侦测网络,带载通讯也是正常的,网络驱动调试结束;

更多linux知识点推荐:

【C语言】数据结构链表算法福利视频

【C语言】C语言视频福利

[linux kernel] 内核启动流程梳理

[linux 底层]u-boot EMMC驱动

[linux 底层]u-boot图形化裁剪配置

[Linux 底层]U-boot ksz9031网络驱动调试

[Linux 底层]U-boot调试命令使用技巧

[Linux 底层]U-boot编译移植

[Linux 底层]U-boot烧录脚本介绍SecureCRT

[Linux 底层]bootstrap移植裁剪及编译

[Linux 底层] 平台软件分层介绍

[Linux 驱动] RS485测试程序编写

[Linux 驱动] CAN测试程序编写

推荐阅读:

芯片手册解读 | Linux底层

关注公众号,回复“内核ksz9031”,免费获取数驱动文件,里面有寄存器打印添加,可直观对比官网库的更改。
在这里插入图片描述

标签:libphy,kernel,ksz9031,addr,get,phy,linux,device,id
来源: https://blog.csdn.net/weixin_43771853/article/details/115482565

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有