单片机
返回首页

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

2022-07-13 来源:csdn

系统版本: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-at91driversnetethernetcadencemacb_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


driversnetethernetcadencemacb_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%xn',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%xn',ctl);


    //mdelay(3000);

    ictl = phy_read(phydev, MII_BMSR);

    pr_info('genphy_restart_aneg read MII_BMSR = 0x%xn',ictl);


    adv = phy_read(phydev, MII_CTRL1000);

    pr_info('genphy_restart_aneg read MII_CTRL1000 = 0x%xn',adv);


    lpagb = phy_read(phydev, MII_STAT1000);

    pr_info('genphy_restart_aneg read MII_STAT1000 = 0x%xn',lpagb);


    phy_write(phydev, MII_ADVERTISE, 0x1e1);

    iadv = phy_read(phydev, MII_ADVERTISE);

    pr_info('genphy_restart_aneg read MII_ADVERTISE = 0x%xn',iadv);

*/

    return ctl;

}


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

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 家用电源无载自动断电装置的设计与制作

  • 短波AM发射器电路设计图

  • 带有短路保护系统的5V直流稳压电源电路图

  • 如何调制IC555振荡器

  • 基于ICL296的大电流开关稳压器电源电路

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章