zoukankan      html  css  js  c++  java
  • PHY LINUX (转载整理)

    每每分析网络问题的时候,总要梳理层次关系,本想自己写一个关于PHY的文档,找到网上有人写的一篇比较好,所以转载下来,仅供初学者参考。

    原文地址:http://www.360doc.com/content/17/0724/12/8706683_673738481.shtml

     以太网 MAC(链路层)+PHY(物理层/RTL8201F,88E1111);集成型DM9000,RTL8139CP 由于网络数据传输量较大,不论是分开型还是集成型,通常会在MAC和PHY之间引入DMA,MAC和PHY之所以有分开,是因为MAC属于数字电路部分,而PHY则属于模拟部分,负责将接收到的数据传输给MAC层,MAC层将接收到的数据传输给上层协议,如IP层,IGMP层。PHY层也负责将由MAC层发送过来的数据,转换成差分信号,经过后边的变压器后送入RJ45接头的线缆中。 对应的数据格式为:  前导符+开始位+目的MAC地址+源MAC地址+类型长度+数据+padding(optional)+32bit CRC PHY层负责的任务还是比较多的,比如10M/100M速率的选择;全双工还是半双工;载波侦听和冲突检测,这些工作对应到具体芯片就是内部寄存器的一些设置。

    PHY功能模块和MCU的链接采用MII/RMII方式链接,这样就可以使用MCU设置相关的寄存器。MII是16根线,RMII将收发数据线各减到两根,这其中涉及串并转换,即将MCU的类的并行总线最终转换成RJ45线上传输的单bit编码。100M是曼彻斯特编码,10M是NRZ编码,这类编码主要考虑负载均衡和纠错。也带来了额外的网络开销。

     

    PHY层的初始化,主要是两个部分,一个是mdio总线的初始化,一个是PHY驱动初始化,对于通常可以使用缺省内核的PHY驱动程序,但是如果PHY芯片的内部寄存器和802.3定义的并不一样,这就需要自己实现该驱动,像8201这样的百兆速率PHY芯片就可以使用缺省的PHY驱动,但是对于一些功能强一点的集成多个PHY的switch而言,通常驱动可能需要自己实现,switch常用来更高速率传输的或者VLAN这种网络。



    PHY层从driver/net/phy/phy_device.c文件开始。
    subsys_initcall(phy_init);
    module_exit(phy_exit);
    又见subsys_initcall,该调用表明其在系统初始化时完成,
    static int __init phy_init(void)
    {
      int rc;

      rc = mdio_bus_init();
      if (rc)
      return rc;

      rc = phy_driver_register(&genphy_driver);
      if (rc)
        mdio_bus_exit();

      return rc;
    }。

    其驱动涉及如下几个重要部分:
    总线- sturct mii_bus     (mii stand for media independent interface)
    设备- struct phy_device
    驱动- struct phy_driver 

    mdiobus_register  ------probe函数会调用,创建该总线,总线然后扫描其上面的设备,如果发现有,则创建该设备。
       _|_
      drovers etphymdio_bus.c                                             drivers etphyphy_device.c
      struct phy_device *mdiobus_scan(struct mii_bus * bus, int addr) ----get_phy_device--phy_device_create
                                                                                                                            |
            |    driversaseCore.c
       ----device_register---device_add(kobject_add构建设备树)
    驱动会调用phy_driver_register去注册驱动,这是phy驱动也会形成一个链表,这里之所以不是树而上面的设备成为树,是因为
    mii可能挂载在pci总线上,当然pci上可能有其它设备,这些设备和phy设备不在一个链表上,而是通过kobject链接管理的,对应的还有 一个kset,kset其实是kobject的一个集合,
    相同的kobject对象会指向同一个kset,如USB鼠标、键盘就属于同一个kset集。 上述的总线,设备,以及驱动(假设驱动已经编写好了,驱动中多半会有一个标示符,暂且将其看作为id,
    这个id指明了其支持的设备)内; 假设不支持热插拔,那么启动时,系统就会扫描设备,并串联进设备树,当驱动注册(register时),驱动就会去设备树中,找id号和其对 应的相等的,
    如果找到,那么这两个就捆绑在一起了,通常为XXX_attcah函数,应用层对该设备的操作就变为调用驱动中对应的read、write、 ioctl等。如果支持热插拔,比上面的就复杂了,因为驱动可能先于设备(总线)存在,
    所以当有新硬件连接时,内核会调用XXX_probe函数去 探测,并注册设备,然后去驱动链表中查找驱动,如果找到,则attach。对其操作方法与上述一样。
    剩下一个问题就是驱动的编写了。
    #define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)  
    static int 8201f_config_init(struct phy_device *phydev)
    {

      int val; u32 features; /* For now, I'll claim that the generic driver supports * all possible port types */
      features =PHY_BASIC_FEATURES ; /* Do we support autonegotiation? */ val = phy_read(phydev, MII_BMSR);
      if (val < 0) return val;
      if (val & BMSR_ANEGCAPABLE) features |= SUPPORTED_Autoneg;
      if (val & BMSR_100FULL) features |= SUPPORTED_100baseT_Full;
      if (val & BMSR_100HALF) features |= SUPPORTED_100baseT_Half;
      if (val & BMSR_10FULL) features |= SUPPORTED_10baseT_Full;
      if (val & BMSR_10HALF) features |= SUPPORTED_10baseT_Half;
      if (val & BMSR_ESTATEN) { val = phy_read(phydev, MII_ESTATUS);
      if (val < 0) return val; if (val & ESTATUS_1000_TFULL) features |= SUPPORTED_1000baseT_Full;
      if (val & ESTATUS_1000_THALF) features |= SUPPORTED_1000baseT_Half;
      }

       phydev->supported = features;

      phydev->advertising = features;

       return 0;
    }
    int 8201f_config_aneg(struct phy_device *phydev)
    {
      int result;
      if (AUTONEG_ENABLE != phydev->autoneg)
      return genphy_setup_forced(phydev);
      result = genphy_config_advert(phydev);
      if (result < 0) /* error */ return result;
      if (result == 0) { /* Advertisment hasn't changed, but maybe aneg was never on to * begin with?  Or maybe phy was isolated? */
      int ctl = phy_read(phydev, MII_BMCR);
      if (ctl < 0) return ctl;
      if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
    result = 1; /* do restart aneg */
    }
    /* Only restart aneg if we are advertising something different * than we were before. */
    if (result > 0)
    result = genphy_restart_aneg(phydev);
    return result;
    }
    static struct phy_driver 8201f_driver = {
            .phy_id         = 0x001cc810,    
        .name           = "Realtack 8201f",    
        .phy_id_mask    = 0x0ffffff0,      
      .features       = PHY_BASIC_FEATURES,  
          .config_init    = 8201f_config_init,  
          .config_aneg    = 8201f_config_aneg,    
        .read_status    = genphy_read_status,    
        .driver         = { .owner = THIS_MODULE,},
    };
    static int __init 8201f_init(void) {
            int ret;  
          ret = phy_driver_register(&8201f_driver);    
        if (ret)            phy_driver_unregister(&8201f_driver);  
          return ret; } static void __exit 8201f_exit(void) {    
        phy_driver_unregister(&8201f_driver);
    }
    module_init(8201f_init); module_exit(8201f_exit);  

    PHY自协商基本原理 

      自动协商模式是端口根据另一端设备的连接速度和双工模式,自动把它的速度调节到最高的公共水平,即线路两端能具有的最快速度和双工模式。

      自协商功能允许一个网络设备能够将自己所支持的工作模式信息传达给网络上的对端,并接受对方可能传递过来的相应信息,从而解决双工和10M/100M速率自协商问题。自协商功能完全由物理层芯片设计实现,因此并不使用专用数据包或带来任何高层协议开销。 

      自协商功能的基本机制是:每个网络设备在上电、管理命令发出、或是用户干预时发出FLP(快速连接脉冲),协商信息封装在这些FLP序列中。FLT中包含有时钟/数字序列,将这些数据从中提取出来就可以得到对端设备支持的工作模式,以及一些用于协商握手机制的其他信息。当一个设备不能对FLP作出有效反应,而仅返回一个NLP(普通连接脉冲)时,它被作为一个10BASE-T兼容设备。 快速链路脉冲FLP和普通链路脉冲NLP都仅使用于非屏蔽双绞线上,而不能应用在光纤媒体。 

      自动协商的内容主要包括双工模式、运行速率、流控等内容,一旦协商通过,链路两端的设备就锁定在这样一种运行模式下。1000M以太网也支持自协商,在此从略。 

      电口和光口自协商主要区别是在OSI 中它们所处的位置不同。对于电口来说,协商发生在链路信号传输之前;对于光口来说, 自协商机制与PCS在同一层, 这意味着光口的协商必须先建立链路同步以后才可以进行协商。

     协商过程

        如果两端都支持自协商,则都会接收到对方的FLP,并且把FLP中的信息解码出来。得到对方的连接能力。并且把对端的自协商能力值记录在自协商对端能力寄存器中(Auto-Negotiation Link Partner Ability Register , PHY标准寄存器地址5 )。同时把状态寄存器(PHY标准寄存器地址1)的自协商完成bit(bit5)置成1。在自协商未完成的情况下,这个bit一直为0。

    然后各自根据自己和对方的最大连接能力,选择最好的连接方式Link。比如,如果双方都即支持10M也支持100M,则速率按照100M连接;双方都即支持全双工也支持半双工,则按照全双工连接。

    一定连接建立后,FLP就停止发送。直到链路中断,或者得到自协商Restart命令时,才会再次发送FLP。

    为了保证在对端不能支持自协商的情况下也能连接,引入了被称为并行检测(Parallel Detection)的机制。在一端打开自协商,另一端关闭自协商的情况下,连接的建立就依靠并行检测功能实现。

    并行检测机制是这样的:在具有自协商能力的设备端口上,如果接收不到FLP,则检测是否有10M链路的特征信号或100M链路的特征信号。

    如果设备是10M设备,不支持自协商,则在链路上发送普通连接脉冲(Normal Link Pulse)简称NLP。NLP仅仅表示设备在位,不包含其它的额外信息。NLP脉冲如图:

    如果是100M设备,不支持自协商,则在没有数据的情况下,在链路上一直发送4B/5B编码的Idle符号。

    并行检测机制如果检测到NLP,则知道对方支持10M速率;如果检测到4B/5B编码的Idle符号,则知道对方支持100M速率。但是对方是否支持全双工、是否支持流控帧这些信息是无法得到的。因此在这种情况下,认为对方只支持半双工,不支持全双工,且不支持流控帧。

    基于以上原理,在对端不打开自协商时,打开自协商的一方只能协商成半双工模式。

    802.3协议规定,通过并行检测建立连接后,PHY的状态寄存器(PHY标准寄存器地址1)的自协商完成bit(bit5)依然要置位成1,尽管链路上并非使用了真正的自协商操作。同时规定在自协商完成bit为1的情况下,本地自协商能力寄存器(PHY标准寄存器地址4)和对端自协商能力寄存器(PHY标准寄存器地址5)是有意义的。所以,要把寄存器5中的数据更新。如果建立的连接为10M,则寄存器5的10M能力bit(bit5)置1,其它bit置0,表示对端只能支持10M半双工;如果建立的连接为100M,则寄存器5的100M能力bit(bit7)置1,其它bit置0,表示对端只能支持100M半双工。

    千兆光口自协商

    千兆光口可以工作在强制和自协商两种模式。802.3规范中千兆光口只支持1000M速率,支持全双工(Full)和半双工(Half)两种双工模式。

    自协商和强制最根本的区别就是两者再建立物理链路时发送的码流不同,自协商模式发送的是/C/码,也就是配置(Configuration)码流,而强制模式发送的是/I/码,也就是idle码流。

    千兆光口自协商过程:

    1.两端都设置为自协商模式

    双方互相发送/C/码流,如果连续接收到3个相同的/C/码且接收到的码流和本端工作方式相匹配,则返回给对方一个带有Ack应答的/C/码,对端接收到Ack信息后,认为两者可以互通,设置端口为UP状态

    2.一端设置为自协商,一端设置为强制

    自协商端发送/C/码流,强制端发送/I/码流,强制端无法给对端提供本端的协商信息,也无法给对端返回Ack应答,故自协商端DOWN。但是强制端本身可以识别/C/码,认为对端是与自己相匹配的端口,所以直接设置本端端口为UP状态

    3.两端均设置为强制模式

    双方互相发送/I/码流,一端接收到/I/码流后,认为对端是与自己相匹配的端口,直接设置本端端口为UP状态

    快速链接脉冲(FLPs)和普通链接脉冲(NLPs)

    自动协商的执行是通过FLPs来实现的。NLPs是周期为16ms左右的脉冲,脉冲宽度为100ns(10base-T)、10ns(100base-TX)。FLPs类似于NLPs,它是连续的17~33个的脉冲用来传输16bit的连接码(link code word)以进行自动协商,码宽为125us,在125us码宽中间有脉冲为1,无脉冲为0。link code word并不是以太网通信结点的有效数据,只被PHY接口模块识别。

    以太网接口自动协商原理 - cqy-chenqiyao - cqy-chenqiyao的博客

      自协商基本页信息

    在链路初始化的时候,自协商协议向对端发送16Bit的报文,也就是所谓的脉冲信号,然后从对端接收类似的报文,这个16Bit的报文就是我们所说的基本页,不同的设备,在针对基本页做字位信息的时候,那就能识别它是属于哪一个情况.。

    bit0~4:指示自协商数据帧,对于802.3标准,设置为'10000';

    bit5~12:指示结点(端口)信息性能域;

     bit5~9:定义端口可连接类型,按照优先级从高到低如下(SETBIT有效):

      bit8:100base-TX全双工;bit9:100base-T4;bit7:100base-TX半双工;bit6:10base-T全双工;bit5:10base-T半双工;

     bit10:指示流量控制信息:0:流控无效;1:流控有效,决定了端口后续通信是否有PAUSE帧;

     bit11:支持全双工连接时的非对称暂停机制;

     bit12:扩展下一页信息页,仅用于千兆端口;

    bit13:远程故障指示;

    bit14:握手信号Ack,当收到三个连续的相同FLP后,此位置1;

    bit15:指示是否有下一页基本页信息。下一页信息用来传输在自协商过程中已连接节点的额外信息。

    PAUSE帧(流量控制)

    为什么要有流量控制呢?现在的网络有10M和100M的以太,那么当10m以太和100m以太共存的时候,那就有可能会产生这种线路速率不匹配的情况,这个时候,当通过交换机一个端口的流量过大,超出了它的处理能力时,就会发生端口拥塞,拥塞的时候那么丢包、重传、时延等都会随之而来,流量控制的作用时防止在出现拥塞的情况下丢帧。
      这里的流量控制采用的是最常用的一种方式—PAUSE帧。
      在半双工方式下,流量控制是通过后退压力(backpressure)技术实现的,模拟产生碰撞,使得信息源降低发送速度。
      在全双工方式下流控一般遵循IEEE 802.3X标准。采用一64字节的PAUSE的帧来控制,使用一个保留的组播地址:01-80-C2-00-00-01发送给正在发送的站,发送站接到该帧后,就会暂停或停止发送。这个地址的数据不会被网桥和交换机所转发,所以PAUSE帧不会产生附加信息量。
      PAUSE功能应用场合:
       ->一对终端(简单的两点网络)
       ->一个交换机和一个终端
       ->交换机和交换机之间的链路
      PAUSE功能的增加主要是为了防止瞬时流量的过载导致的缓冲区溢出而造成以太网帧的丢弃。
      PAUSE功能不能解决下列问题:
       ->稳定状态的网络拥塞
       ->端到端流量控制
       ->比简单“停—启”更复杂的机制

     以太网端口电口工作模式简单介绍

      1.以太网口的两端工作模式(10M半双工、10M全双工、100M半双工、100M全双工、自协商)必须设置一致。

      2.如果一端是固定模式(无论是10M、100M),另外一端是自协商模式,即便能够协商成功,自协商的那一端也将只能工作在半双工模式。 

      3.如果一端工作在全双工模式,另外一端工作在半双工模式(包括自协商出来的半双工,也一样处理),Ping是没有问题的,流量小的时候也没有任何问题,流量达到约15%以上时,就会出现冲突、错包,最终影响了工作性能!  

    4.对于两端工作模式都是自协商,最后协商成的结果是“两端都支持的工作模式中优先级最高的那一类”。 

    5. 如果A端自协商,B端设置为100M全双工,A协商为100M半双工后,再强制将B改为10M全双工,A端也会马上向下协商到10M半双工;如果A端自协商,B端设置为10M全双工,A协商为10M半双工后,再强制将B改为100M全双工,会出现协商不成功,连接不上!这个时候,如果插拔一下网线,又会重新协商在100M半双工。  

    建议

      以太网口的两端工作模式必须设置一致。 否则,就会出现流量一大速度变慢的问题。大多数设备以太网口的默认的出厂设置是自协商。如果两端都是自协商,协商成功了,但网络不通,此时请检查网线是否支持100M。如果两端都是自协商,协商成功并且运行在全双工,在没有Link Down的前提下,将其中一端“立刻”设置为固定的“10M/100M全双工”,两端仍然能够工作在全双工。但是,万一将来插拔网线或者其他原因出现重新Link,就会重新协商为“一端全双工&一端半双工”的不稳定连接。因此,这种情况一定要避免!

  • 相关阅读:
    CodeForces gym Nasta Rabbara lct
    bzoj 4025 二分图 lct
    CodeForces 785E Anton and Permutation
    bzoj 3669 魔法森林
    模板汇总——快读 fread
    bzoj2049 Cave 洞穴勘测 lct
    bzoj 2002 弹飞绵羊 lct裸题
    HDU 6394 Tree 分块 || lct
    HDU 6364 Ringland
    nyoj221_Tree_subsequent_traversal
  • 原文地址:https://www.cnblogs.com/mic-chen/p/13602024.html
Copyright © 2011-2022 走看看