热门标签 | 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


推荐阅读
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 怀疑是每次都在新建文件,具体代码如下 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
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社区 版权所有