热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

有关PHY抽象层的总结

Purpose大多数网络设备由一组寄存器组成,这些寄存器提供到MAC层的接口,MAC层通过PHY与物理连接通信.PHY关注于与网络连接另一端的链路伙伴

Purpose

大多数网络设备由一组寄存器组成,这些寄存器提供到MAC层的接口,MAC层通过PHY与物理连接通信. PHY关注于与网络连接另一端的链路伙伴(通常是以太网电缆)协商链路参数,并提供注册接口以允许驱动程序确定选择了哪些设置,并配置允许的设置.

虽然这些设备不同于网络设备,并且符合寄存器的标准布局,但是通常的做法是将PHY管理代码与网络驱动器集成. 这导致了大量的冗余代码. 此外,在具有连接到同一管理总线的多个(有时是完全不同的)以太网控制器的嵌入式系统上,难以确保总线的安全使用.

由于PHY是设备,并且实际上它们被访问的管理总线实际上是总线,因此PHY抽象层对它们进行处理. 这样做,它有以下目标:

  1. 增加代码重用
  2. 提高整体代码可维护性
  3. 加快新网络驱动程序和新系统的开发时间

基本上,该层旨在为PHY设备提供接口,允许网络驱动程序编写者尽可能少地编写代码,同时仍提供完整的功能集.

The MDIO bus

大多数网络设备通过管理总线连接到PHY. 不同的设备使用不同的总线(尽管有些共享通用接口). 为了利用PAL,每个总线接口需要注册为不同的设备.

  1. 必须实现读写功能. 他们的原型是:

    int write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
    int read(struct mii_bus *bus, int mii_id, int regnum);

    mii_id是PHY总线上的地址,regnum是寄存器号. 保证不会从中断时间调用这些函数,因此它们可以安全地阻塞,等待中断发出操作完成的信号

  2. 复位功能是可选的. 这用于将总线返回到初始化状态.

  3. 需要探测功能. 此功能应设置总线驱动程序所需的任何内容,设置mii_bus结构,并使用mdiobus_register注册PAL. 同样,还有一个删除所有功能的删除功能(使用mdiobus_unregister).

  4. 与任何驱动程序一样,必须配置device_driver结构,并使用init exit函数注册驱动程序.

  5. 总线也必须在某处作为设备声明,并进行注册.

作为一个驱动程序如何实现mdio总线驱动程序的示例,请参阅drivers / net / ethernet / freescale / fsl_pq_mdio.c以及其中一个用户的关联DTS文件. (例如"git grep fsl,.* - mdio arch / powerpc / boot / dts /")

(RG)MII/electrical interface considerations

简化的千兆位媒体独立接口(RGMII)是一个12引脚电信号接口,使用同步125Mhz时钟信号和多条数据线. 由于此设计决定,必须在时钟线(RXC或TXC)与数据线之间添加1.5ns至2ns的延迟,以使PHY(时钟接收器)具有足够的设置和保持时间来正确采样数据线. PHY库提供不同类型的PHY_INTERFACE_MODE_RGMII *值,以使PHY驱动程序和可选的MAC驱动程序实现所需的延迟. 必须从PHY设备本身的角度理解phy_interface_t的值,从而导致以下结果:

  • PHY_INTERFACE_MODE_RGMII:PHY不负责自己插入任何内部延迟,它假设以太网MAC(如果能够或PCB走线)插入正确的1.5-2ns延迟
  • PHY_INTERFACE_MODE_RGMII_TXID:PHY应为PHY设备处理的发送数据线(TXD [3:0])插入内部延迟
  • PHY_INTERFACE_MODE_RGMII_RXID: the PHY should insert an internal delay for the receive data lines (RXD[3:0]) processed by the PHY device
  • PHY_INTERFACE_MODE_RGMII_ID:PHY应为PHY设备插入发送和接收数据线的内部延迟

出于以下原因,尽可能使用PHY端RGMII延迟:

  • PHY设备可以提供亚纳秒的粒度,以确定它们如何允许指定接收器/发送器侧延迟(例如:0.5,1.0,1.5ns). 可能需要这种精度来解决PCB走线长度的差异
  • PHY器件通常适用于大范围的应用(工业,医疗,汽车......),并且它们在温度/压力/电压范围内提供恒定且可靠的延迟
  • PHYLIB中的PHY设备驱动程序本质上是可重用的,能够正确配置指定的延迟,使具有类似延迟要求的更多设计能够正确运行

对于PHY无法提供此延迟但是以太网MAC驱动程序能够执行此操作的情况,正确的phy_interface_t值应为PHY_INTERFACE_MODE_RGMII,并且应正确配置以太网MAC驱动程序以提供所需的传输和/或或者从PHY设备的角度接收侧延迟. 相反,如果以太网MAC驱动程序查看phy_interface_t值,对于除PHY_INTERFACE_MODE_RGMII之外的任何其他模式,它应确保禁用MAC级延迟.

如果根据RGMII标准定义的以太网MAC和PHY都不能提供所需的延迟,则可以使用以下几个选项:

  • 一些SoC可能提供一个引脚焊盘/多路复用器/控制器,能够配置一组给定的引脚强度,延迟和电压; 并且可能是插入预期的2ns RGMII延迟的合适选项.
  • 修改PCB设计以包括固定延迟(例如:使用专门设计的蛇形),这可能根本不需要软件配置.

Common problems with RGMII delay mismatch

当以太网MAC和PHY之间存在RGMII延迟不匹配时,当PHY或MAC对这些信号进行快照以将其转换为逻辑1或0状态时,这很可能导致时钟和数据线信号不稳定并重建正在传输/接收的数据. 典型症状包括:

  • 发送/接收部分工作,并且观察到频繁或偶然的分组丢失
  • 以太网MAC可能会报告一些或所有因FCS / CRC错误而进入的数据包,或者只丢弃它们
  • 切换到较低的速度,例如10 / 100Mbits / sec会使问题消失(因为在这种情况下有足够的设置/保持时间)

Connecting to a PHY

在启动期间的某个时间,网络驱动程序需要在PHY设备和网络设备之间建立连接. 此时,PHY的总线和驱动程序都需要加载,因此可以进行连接. 此时,有几种方法可以连接到PHY:

  1. PAL处理所有内容,只在链接状态发生变化时才调用网络驱动程序,因此它可以做出反应.
  2. PAL处理除中断之外的所有内容(通常是因为控制器具有中断寄存器).
  3. PAL处理所有内容,但每秒都会检入驱动程序,允许网络驱动程序在PAL执行之前首先对任何更改作出反应.
  4. PAL仅用作功能库,网络设备手动调用功能以更新状态,并配置PHY

Letting the PHY Abstraction Layer do Everything

如果你选择选项1(希望每个驱动程序都可以,但仍然对那些不可用的驱动程序有用),连接到PHY很简单:

首先,您需要一个函数来响应链接状态的变化. 此功能遵循此协议:

static void adjust_link(struct net_device *dev);

接下来,您需要知道连接到此设备的PHY的设备名称. 该名称看起来像"0:00",其中第一个数字是总线ID,第二个是该总线上的PHY地址. 通常,总线负责使其ID唯一.

现在,要连接,只需调用此函数:

phydev = phy_connect(dev, phy_name, &adjust_link, interface);

phydev是指向表示PHY的phy_device结构的指针. 如果phy_connect成功,它将返回指针. dev,这里是指向你的net_device的指针. 完成后,此功能将启动PHY的软件状态机,并注册PHY的中断(如果有). phydev结构将填充有关当前状态的信息,尽管此时PHY尚未真正运行.

在调用phy_connect()之前,应在phydev-> dev_flags中设置PHY特定标志,以便底层PHY驱动程序可以检查标志并根据它们执行特定操作. 如果系统对PHY /控制器施加硬件限制(PHY需要注意),这将非常有用.

interface是一个u32,它指定控制器和PHY之间使用的连接类型. 例子是GMII,MII,RGMII和SGMII. 请参见下面的"PHY接口模式". 有关完整列表,请参阅include / linux / phy.h

现在只需确保phydev->支持和phydev->广告具有从它们中删除的任何值,这对您的控制器没有意义(10/100控制器可能连接到千兆位PHY,因此您需要屏蔽关闭SUPPORTED_1000baseT *). 有关这些位域的定义,请参阅include / linux / ethtool.h. 请注意,除了SUPPORTED_Pause和SUPPORTED_AsymPause位(见下文)之外,不应设置任何位,否则PHY可能会进入不受支持的状态.

最后,一旦控制器准备好处理网络流量,就调用phy_start(phydev). 这告诉PAL您已做好准备,并配置PHY以连接到网络. 如果网络驱动程序的MAC中断也处理PHY状态更改,则在调用phy_start之前将phydev-> irq设置为PHY_IGNORE_INTERRUPT,并使用来自网络驱动程序的phy_mac_interrupt() . 如果您不想使用中断,请将phydev-> irq设置为PHY_POLL. phy_start()启用PHY中断(如果适用)并启动phylib状态机.

如果要断开与网络的连接(即使只是简单地断开),则调用phy_stop(phydev). 此功能还会停止phylib状态机并禁用PHY中断.

PHY interface modes

phy_connect()系列函数中提供的PHY接口模式定义了PHY接口的初始操作模式. 这不能保证保持不变; 有些PHY根据协商结果动态改变其接口模式而无需软件交互.

一些接口模式如下所述:

PHY_INTERFACE_MODE_1000BASEX

这定义了由802.3标准部分36定义的1000BASE-X单通道serdes链路.该链路使用10B / 8B编码方案以1.25Gbaud的固定比特率工作,从而产生1Gbps的基础数据速率. 嵌入在数据流中的是一个16位控制字,用于与远程端协商双工和暂停模式. 这不包括"高速"变体,如2.5Gbps速度(见下文).

PHY_INTERFACE_MODE_2500BASEX

这定义了1000BASE-X的变体,其时钟速度比802.3标准快2.5倍,固定比特率为3.125Gbaud.

PHY_INTERFACE_MODE_SGMII

这用于Cisco SGMII,它是802.3标准定义的1000BASE-X的修改. SGMII链路由单个serdes通道组成,以1.25Gbaud的固定比特率运行,具有10B / 8B编码. 基础数据速率为1Gbps,通过复制每个数据符号实现100Mbps和10Mbps的较慢速度. 重新使用802.3控制字以将协商的速度和双工信息发送到MAC,并且MAC确认接收. 这不包括"高速"变体,例如2.5Gbps速度.

注意:链路上不匹配的SGMII与1000BASE-X配置在某些情况下可以成功传递数据,但16位控制字将无法正确解释,这可能会导致双工,暂停或其他设置不匹配. 这取决于MAC和/或PHY行为.

Pause frames / flow control

PHY不直接参与流控制/暂停帧,除非确保在MII_ADVERTISE中设置SUPPORTED_Pause和SUPPORTED_AsymPause位以向链路伙伴指示以太网MAC控制器支持这样的事情. 由于流控制/暂停帧生成涉及以太网MAC驱动程序,因此建议此驱动程序通过相应地设置SUPPORTED_Pause和SUPPORTED_AsymPause位来正确指示广告并支持此类功能. 这可以在phy_connect()之前或之后和/或由于实现ethtool :: set_pauseparam功能而完成.

Keeping Close Tabs on the PAL

PAL的内置状态机可能需要一些帮助才能使您的网络设备和PHY正确同步. 如果是这样,您可以在连接到PHY时注册辅助函数,PHY将在状态机对任何更改做出反应之前每秒调用一次. 为此,您需要手动调用phy_attach()phy_prepare_link() ,然后调用phy_start_machine()并将第二个参数设置为指向您的特殊处理程序.

目前没有关于如何使用此功能的示例,并且对它的测试受到限制,因为作者没有任何使用它的驱动程序(它们都使用选项1). 所以Caveat Emptor.

Doing it all yourself

PAL的内置状态机很可能无法跟踪PHY和网络设备之间的复杂交互. 如果是这样,您可以简单地调用phy_attach() ,而不是调用phy_start_machine或phy_prepare_link() . 这意味着phydev-> state完全由你自己处理(phy_start和phy_stop在某些状态之间切换,所以你可能需要避免它们).

已经努力确保在没有状态机运行的情况下可以访问有用的功能,并且大多数这些功能来自不与复杂状态机交互的功能. 然而,到目前为止,还没有努力测试没有状态机的运行,所以尝试者要小心.

这是功能的简要概述:

int phy_read(struct phy_device *phydev, u16 regnum);
int phy_write(struct phy_device *phydev, u16 regnum, u16 val);

简单的读/写原语. 它们调用总线的读/写函数指针.

void phy_print_status(struct phy_device *phydev);

A convenience function to print out the PHY status neatly.

void phy_request_interrupt(struct phy_device *phydev);

请求IRQ进行PHY中断.

struct phy_device * phy_attach(struct net_device *dev, const char *phy_id,phy_interface_t interface);

将网络设备连接到特定PHY,如果在总线初始化期间没有找到PHY,则将PHY绑定到通用驱动程序.

int phy_start_aneg(struct phy_device *phydev);

使用phydev结构中的变量,配置广告并重置自动协商,或禁用自动协商,并配置强制设置.

static inline int phy_read_status(struct phy_device *phydev);

使用有关PHY中当前设置的最新信息填充phydev结构.

int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);

Ethtool便利功能.

int phy_mii_ioctl(struct phy_device *phydev,struct mii_ioctl_data *mii_data, int cmd);

The MII ioctl. Note that this function will completely screw up the state machine if you write registers like BMCR, BMSR, ADVERTISE, etc. Best to use this only to write registers which are not standard, and don't set off a renegotiation.

PHY Device Drivers

通过PHY抽象层,添加对新PHY的支持非常容易. 在某些情况下,根本不需要工作! 但是,许多PHY需要一点点手持操作才能启动并运行.

Generic PHY driver

如果所需的PHY没有您想要支持的任何勘误,怪癖或特殊功能,那么最好不要添加支持,并让PHY抽象层的通用PHY驱动程序完成所有工作.

Writing a PHY driver

If you do need to write a PHY driver, the first thing to do is make sure it can be matched with an appropriate PHY device. This is done during bus initialization by reading the device's UID (stored in registers 2 and 3), then comparing it to each driver's phy_id field by ANDing it with each driver's phy_id_mask field. Also, it needs a name. Here's an example:

static struct phy_driver dm9161_driver = {.phy_id = 0x0181b880,.name = "Davicom DM9161E",.phy_id_mask = 0x0ffffff0,...
}

接下来,您需要指定PHY设备和驱动程序支持的功能(速度,双工,自动等). 大多数PHY支持PHY_BASIC_FEATURES,但您可以在include / mii.h中查找其他功能.

每个驱动程序都包含许多函数指针,在phy_driver结构下的include / linux / phy.h中有记录.

其中,驱动程序代码只需要分配config_aneg和read_status. 其余的是可选的. 此外,如果可能的话,最好使用这两个函数的通用phy驱动程序版本:genphy_read_status和genphy_config_aneg. 如果这不可能,您可能只需要在调用这些函数之前和之后执行某些操作,因此您的函数将包装泛型函数.

请随意查看驱动程序/ net / phy /中的Marvell,Cicada和Davicom驱动程序(例如,在撰写本文时,lxt和qsemi驱动程序尚未经过测试).

PHY的MMD寄存器访问默认由PAL框架处理,但如果需要,可以由特定的PHY驱动程序覆盖. 如果在IEEE标准化MMD PHY寄存器定义之前发布用于制造的PHY,则可能是这种情况. 大多数现代PHY将能够使用通用PAL框架来访问PHY的MMD寄存器. 这种用法的一个例子是在PAL中实现的节能以太网支持. 如果PHY支持IEEE标准访问机制,则此支持使用PAL访问MMD寄存器以进行EEE查询和配置,或者如果特定PHY驱动程序覆盖,则可以使用PHY的特定访问接口. 有关如何实现此功能的示例,请参阅drivers / net / phy /中的Micrel驱动程序.

Board Fixups

有时,平台和PHY之间的特定交互需要特殊处理. 例如,改变PHY的时钟输入的位置,或添加延迟以解决数据路径中的延迟问题. 为了支持这种意外情况,PHY层允许平台代码注册在PHY启动(或随后重置)时运行的修正.

当PHY层启动PHY时,它会检查是否有为其注册的任何修正,基于UID(包含在PHY设备的phy_id字段中)和总线标识符(包含在phydev-> dev.bus_id中)进行匹配. 两者必须匹配,但是两个常量PHY_ANY_ID和PHY_ANY_UID分别作为总线ID和UID的通配符提供.

当找到匹配时,PHY层将调用与fixup相关联的运行功能. 该函数被传递给指向感兴趣的phy_device的指针. 因此它只应在该PHY上运行.

平台代码可以使用phy_register_fixup()注册修正:

int phy_register_fixup(const char *phy_id,u32 phy_uid, u32 phy_uid_mask,int (*run)(struct phy_device *));

或者使用两个存根中的一个,phy_register_fixup_for_uid()和phy_register_fixup_for_id():

int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,int (*run)(struct phy_device *));
int phy_register_fixup_for_id(const char *phy_id,int (*run)(struct phy_device *));

存根设置两个匹配条件中的一个,并设置另一个以匹配任何内容.

当在模块中调用phy_register_fixup()或* _for_uid()/ * _ for_id()时,需要取消注册fixup和free allocate memory.

在卸载模块之前调用以下功能之一:

int phy_unregister_fixup(const char *phy_id, u32 phy_uid, u32 phy_uid_mask);
int phy_unregister_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask);
int phy_register_fixup_for_id(const char *phy_id);

Standards

IEEE标准802.3:CSMA / CD访问方法和物理层规范,第二部分: http : //standards.ieee.org/getieee802/download/802.3-2008_section2.pdf

RGMII v1.3: http ://web.archive.org/web/20160303212629/http: //www.hp.com/rnd/pdfs/RGMIIv1_3.pdf

RGMII v2.0: http ://web.archive.org/web/20160303171328/http: //www.hp.com/rnd/pdfs/RGMIIv2_0_final_hp.pdf

Next  Previous


推荐阅读
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 深入解析C语言中结构体的内存对齐机制及其优化方法
    为了提高CPU访问效率,C语言中的结构体成员在内存中遵循特定的对齐规则。本文详细解析了这些对齐机制,并探讨了如何通过合理的布局和编译器选项来优化结构体的内存使用,从而提升程序性能。 ... [详细]
  • 本文详细解析了 Android 系统启动过程中的核心文件 `init.c`,探讨了其在系统初始化阶段的关键作用。通过对 `init.c` 的源代码进行深入分析,揭示了其如何管理进程、解析配置文件以及执行系统启动脚本。此外,文章还介绍了 `init` 进程的生命周期及其与内核的交互方式,为开发者提供了深入了解 Android 启动机制的宝贵资料。 ... [详细]
  • 【妙】bug称它为数组越界的妙用
    1、聊一聊首先跟大家推荐一首非常温柔的歌曲,跑步的常听。本文主要把自己对C语言中柔性数组、零数组等等的理解分享给大家,并聊聊如何构建一种统一化的学习思想 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 在 Ubuntu 中遇到 Samba 服务器故障时,尝试卸载并重新安装 Samba 发现配置文件未重新生成。本文介绍了解决该问题的方法。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • Codeforces竞赛解析:Educational Round 84(Div. 2评级),题目A:奇数和问题
    Codeforces竞赛解析:Educational Round 84(Div. 2评级),题目A:奇数和问题 ... [详细]
  • 在HTML布局中,即使将 `top: 0%` 和 `left: 0%` 设置为元素的定位属性,浏览器中仍然会出现空白填充。这个问题通常与默认的浏览器样式、盒模型或父元素的定位方式有关。为了消除这些空白,可以考虑重置浏览器的默认样式,确保父元素的定位方式正确,并检查是否有其他CSS规则影响了元素的位置。 ... [详细]
  • ### 优化后的摘要本文对 HDU ACM 1073 题目进行了详细解析,该题属于基础字符串处理范畴。通过分析题目要求,我们可以发现这是一道较为简单的题目。代码实现中使用了 C++ 语言,并定义了一个常量 `N` 用于字符串长度的限制。主要操作包括字符串的输入、处理和输出,具体步骤涉及字符数组的初始化和字符串的逆序操作。通过对该题目的深入探讨,读者可以更好地理解字符串处理的基本方法和技巧。 ... [详细]
  • 本文探讨了如何通过编程手段在Linux系统中禁用硬件预取功能。基于Intel® Core™微架构的应用性能优化需求,文章详细介绍了相关配置方法和代码实现,旨在帮助开发人员有效控制硬件预取行为,提升应用程序的运行效率。 ... [详细]
  • 在Linux系统中,通过命令行查询计算机硬件配置是一项重要的技能。本文介绍了多种实用的命令和技巧,帮助用户高效地获取硬件信息。例如,可以通过 `cat /proc/cpuinfo | grep "physical id"` 命令来查看物理CPU的数量。此外,文章还涵盖了其他关键硬件组件的查询方法,如内存、磁盘和网络设备等。这些命令不仅适用于系统管理员,也适合普通用户了解自己的系统配置。 ... [详细]
  • MSP430F5438 ADC12模块应用与学习心得
    在最近的实践中,我深入研究了MSP430F5438的ADC12模块。尽管该模块的功能相对简单,但通过实际操作,我对MSP430F5438A和MSP430F5438之间的差异有了更深刻的理解。本文将分享这些学习心得,并探讨如何更好地利用ADC12模块进行数据采集和处理。 ... [详细]
author-avatar
手机用户2502886503
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有