Logo

Linux 内核

6.16.0-rc4

快速搜索

目录

  • 开发流程
  • 提交补丁
  • 行为准则
  • 维护者手册
  • 所有开发流程文档
  • 核心 API
  • 驱动 API
  • 子系统
    • 核心子系统
    • 人机界面
    • 网络接口
      • 网络
      • NetLabel
      • InfiniBand
      • ISDN
      • MHI
    • 存储接口
    • 其他子系统
  • 锁
  • 许可规则
  • 编写文档
  • 开发工具
  • 测试指南
  • 黑客指南
  • 追踪
  • 故障注入
  • 热补丁
  • Rust
  • 管理
  • 构建系统
  • 报告问题
  • 用户空间工具
  • 用户空间 API
  • 固件
  • 固件和设备树
  • CPU 架构
  • 未分类的文档
  • 翻译

本页

  • 显示源码

phylink¶

概述¶

phylink 是一种机制,用于支持直接连接到 MAC 的热插拔网络模块,而无需在热插拔事件时重新初始化适配器。

phylink 目前支持传统的基于 phylib 的设置、固定链路设置和 SFP(小型可插拔)模块。

操作模式¶

phylink 有几种操作模式,具体取决于固件设置。

  1. PHY 模式

    在 PHY 模式下,我们使用 phylib 从 PHY 读取当前的链路设置,并将它们传递给 MAC 驱动程序。我们希望 MAC 驱动程序配置指定的模式,而不在链路上启用任何协商。

  2. 固定模式

    就 MAC 驱动程序而言,固定模式与 PHY 模式相同。

  3. 带内模式

    带内模式与 802.3z、SGMII 和类似的接口模式一起使用,我们期望使用和遵守通过 serdes 通道发送的带内协商或控制字。

举例来说,这意味着

&eth {
  phy = <&phy>;
  phy-mode = "sgmii";
};

不使用带内 SGMII 信令。 PHY 应严格遵循其 mac_config() 函数中给定的设置。链路应在 mac_link_up() 和 mac_link_down() 函数中强制启动或关闭。

&eth {
  managed = "in-band-status";
  phy = <&phy>;
  phy-mode = "sgmii";
};

使用带内模式,其中来自 PHY 协商的结果通过 SGMII 控制字传递给 MAC,并且 MAC 应确认控制字。mac_link_up() 和 mac_link_down() 函数不得强制 MAC 侧链路启动和关闭。

将网络驱动程序转换为 sfp/phylink 的粗略指南¶

本指南简要介绍了如何将网络驱动程序从 phylib 转换为 sfp/phylink 支持。 请发送补丁来改进此文档。

  1. 可以选择将网络驱动程序的 phylib 更新函数拆分为处理链路断开和链路建立的两个部分。 这可以作为单独的准备提交来完成。

    可以在 git commit fc548b991fb0 中找到此准备工作的一个较旧示例,尽管它是拆分为三个部分;链路建立部分现在包括配置 MAC 以进行链路设置。 有关此内容的更多信息,请参见 mac_link_up()。

  2. 替换

    select FIXED_PHY
    select PHYLIB
    

    用

    select PHYLINK
    

    在驱动程序的 Kconfig 节中。

  3. 添加

    #include <linux/phylink.h>
    

    到驱动程序的头文件列表中。

  4. 添加

    struct phylink *phylink;
    struct phylink_config phylink_config;
    

    到驱动程序的私有数据结构。 我们将驱动程序的私有数据指针称为 priv,驱动程序的私有数据结构称为 struct foo_priv。

  5. 替换以下函数

    原始函数

    替换函数

    phy_start(phydev)

    phylink_start(priv->phylink)

    phy_stop(phydev)

    phylink_stop(priv->phylink)

    phy_mii_ioctl(phydev, ifr, cmd)

    phylink_mii_ioctl(priv->phylink, ifr, cmd)

    phy_ethtool_get_wol(phydev, wol)

    phylink_ethtool_get_wol(priv->phylink, wol)

    phy_ethtool_set_wol(phydev, wol)

    phylink_ethtool_set_wol(priv->phylink, wol)

    phy_disconnect(phydev)

    phylink_disconnect_phy(priv->phylink)

    请注意,其中一些函数必须在 rtnl 锁下调用,否则会发出警告。 通常情况下是这样,除非它们是从驱动程序的暂停/恢复路径中调用的。

  6. 使用以下方法添加/替换 ksettings 获取/设置方法

    static int foo_ethtool_set_link_ksettings(struct net_device *dev,
                                              const struct ethtool_link_ksettings *cmd)
    {
            struct foo_priv *priv = netdev_priv(dev);
    
            return phylink_ethtool_ksettings_set(priv->phylink, cmd);
    }
    
    static int foo_ethtool_get_link_ksettings(struct net_device *dev,
                                              struct ethtool_link_ksettings *cmd)
    {
            struct foo_priv *priv = netdev_priv(dev);
    
            return phylink_ethtool_ksettings_get(priv->phylink, cmd);
    }
    
  7. 替换对

    phy_dev = of_phy_connect(dev, node, link_func, flags, phy_interface);
    

    以及相关代码的调用,并将其替换为对

    err = phylink_of_phy_connect(priv->phylink, node, flags);
    

    在大多数情况下,flags 可以为零;如果在 DT 节点 node 中指定了 PHY,则这些标志将传递给此函数调用中的 phy_attach_direct()。

    node 应该是包含网络 phy 属性、固定链路属性的 DT 节点,并且还将包含 sfp 属性。

    还应删除固定链路的设置; 这些由 phylink 在内部处理。

    of_phy_connect() 还传递了用于链路更新的函数指针。 此函数被 (8) 中描述的不同形式的 MAC 更新所取代。

    PHY 的 supported/advertised 的操作发生在 phylink 内部,基于验证回调,请参见下面的 (8)。

    请注意,驱动程序不再需要存储 phy_interface,还要注意 phy_interface 变成了一个动态属性,就像速度、双工等设置一样。

    最后,请注意 MAC 驱动程序不再能够直接访问 PHY; 这是因为在 phylink 模型中,PHY 可以是动态的。

  8. 向驱动程序添加一个 struct phylink_mac_ops 实例,它是一个函数指针表,并实现这些函数。 用于 of_phy_connect() 的旧链路更新函数变成了三个方法:mac_link_up()、mac_link_down() 和 mac_config()。 如果执行了步骤 1,则功能将被拆分到那里。

    重要的是,如果使用了带内协商,则 mac_link_up() 和 mac_link_down() 不会阻止带内协商完成,因为这些函数是在带内链路状态更改时调用的 - 否则链路将永远不会启动。

    mac_get_caps() 方法是可选的,如果提供,则应返回为传递的 interface 模式支持的 phylink MAC 功能。 通常,无需实现此方法。 Phylink 将结合 interface 的允许功能使用这些功能来确定允许的 ethtool 链路模式。

    mac_link_state() 方法用于从 MAC 读取链路状态,并报告 MAC 当前使用的设置。 这对于带内协商方法(例如 1000base-X 和 SGMII)尤其重要。

    mac_link_up() 方法用于通知 MAC 链路已启动。 该调用仅包括协商模式和接口以供参考。 还提供了最终的链路参数(速度、双工和流量控制/暂停启用设置),当 MAC 和 PCS 没有紧密集成的,或者当设置不是来自带内协商时,应使用这些参数来配置 MAC。

    mac_config() 方法用于使用请求的状态更新 MAC,并且在更改 MAC 配置时必须避免不必要地断开链路。 这意味着该函数应修改状态,并且仅在绝对需要更改 MAC 配置时才断开链路。 可以在 drivers/net/ethernet/marvell/mvneta.c 中的 mvneta_mac_config() 中找到有关如何执行此操作的示例。

    有关这些方法的更多信息,请参见 struct phylink_mac_ops 中的内联文档。

  9. 使用对与您的 struct net_device 关联的 struct device 的引用来填充 struct phylink_config 字段

    priv->phylink_config.dev = &dev.dev;
    priv->phylink_config.type = PHYLINK_NETDEV;
    

    填充您的 MAC 可以处理的各种速度、暂停和双工模式

    priv->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD;
    
  10. 某些以太网控制器与 PCS(物理编码子层)块配对工作,该块可以处理编码/解码、链路建立检测和自动协商等。 虽然某些 MAC 具有内部 PCS,其操作是透明的,但其他一些 MAC 需要专用的 PCS 配置才能使链路正常工作。 在这种情况下,phylink 通过 struct phylink_pcs 提供 PCS 抽象。

    确定您的驱动程序是否有一个或多个内部 PCS 块,以及您的控制器是否可以使用可能在内部连接到您的控制器的外部 PCS 块。

    如果您的控制器没有任何内部 PCS,则可以转到步骤 11。

    如果您的以太网控制器包含一个或多个 PCS 块,请在驱动程序的私有数据结构中为每个 PCS 块创建一个 struct phylink_pcs 实例

    struct phylink_pcs pcs;
    

    填充相关的 struct phylink_pcs_ops 以配置您的 PCS。 创建一个 pcs_get_state() 函数,该函数报告带内链路状态,一个 pcs_config() 函数,该函数根据 phylink 提供的参数配置您的 PCS,以及一个 pcs_validate() 函数,该函数向 phylink 报告您的 PCS 接受的所有配置参数

    struct phylink_pcs_ops foo_pcs_ops = {
            .pcs_validate = foo_pcs_validate,
            .pcs_get_state = foo_pcs_get_state,
            .pcs_config = foo_pcs_config,
    };
    

    安排将 PCS 链路状态中断转发到 phylink 中,通过

    phylink_pcs_change(pcs, link_is_up);
    

    其中,如果链路当前已启动,则 link_is_up 为 true,否则为 false。 如果 PCS 无法提供这些中断,则应在创建 PCS 时设置 pcs->pcs_poll = true;。

  11. 如果您的控制器依赖于或接受通过其自身驱动程序控制的外部 PCS 的存在,请在您的驱动程序私有数据结构中添加一个指向 phylink_pcs 实例的指针

    struct phylink_pcs *pcs;
    

    获取实际 PCS 实例的方式取决于平台,一些 PCS 位于 MDIO 总线上,并通过传递指向相应的 struct mii_bus 的指针和该总线上 PCS 的地址来获取。 在此示例中,我们假设控制器连接到 Lynx PCS 实例

    priv->pcs = lynx_pcs_create_mdiodev(bus, 0);
    

    可以基于固件信息恢复一些 PCS

    priv->pcs = lynx_pcs_create_fwnode(of_fwnode_handle(node));
    
  12. 填充 mac_select_pcs() 回调,并将其添加到您的 struct phylink_mac_ops ops 集中。 此函数必须返回一个指向将用于请求的链路配置的相关 struct phylink_pcs 的指针

    static struct phylink_pcs *foo_select_pcs(struct phylink_config *config,
                                              phy_interface_t interface)
    {
            struct foo_priv *priv = container_of(config, struct foo_priv,
                                                 phylink_config);
    
            if ( /* 'interface' needs a PCS to function */ )
                    return priv->pcs;
    
            return NULL;
    }
    

    有关具有多个内部 PCS 的驱动程序的示例,请参见 mvpp2_select_pcs()。

  13. 填充您的 MAC 可以输出的所有 phy_interface_t(即,所有 MAC 到 PHY 链路模式)。 以下示例显示了可以处理所有 RGMII 模式、SGMII 和 1000BaseX 的 MAC 的配置。 您必须根据您的 MAC 和与此 MAC 关联的所有 PCS 的功能来调整这些设置,而不仅仅是您希望使用的接口

    phy_interface_set_rgmii(priv->phylink_config.supported_interfaces);
     __set_bit(PHY_INTERFACE_MODE_SGMII,
               priv->phylink_config.supported_interfaces);
     __set_bit(PHY_INTERFACE_MODE_1000BASEX,
               priv->phylink_config.supported_interfaces);
    
  14. 从探测函数中删除对 PHY 的 of_parse_phandle() 的调用、对固定链路的 of_phy_register_fixed_link() 等,并将其替换为

    struct phylink *phylink;
    
    phylink = phylink_create(&priv->phylink_config, node, phy_mode, &phylink_ops);
    if (IS_ERR(phylink)) {
            err = PTR_ERR(phylink);
            fail probe;
    }
    
    priv->phylink = phylink;
    

    并通过调用来适当地安排在探测失败路径和移除路径中销毁 phylink

    phylink_destroy(priv->phylink);
    
  15. 安排将 MAC 链路状态中断转发到 phylink 中,通过

    phylink_mac_change(priv->phylink, link_is_up);
    

    其中,如果链路当前已启动,则 link_is_up 为 true,否则为 false。

  16. 验证驱动程序是否不调用

    netif_carrier_on()
    netif_carrier_off()
    

    因为这些会干扰 phylink 对链路状态的跟踪,并导致 phylink 省略通过 mac_link_up() 和 mac_link_down() 方法的调用。

网络驱动程序应通过其暂停/恢复路径调用 phylink_stop() 和 phylink_start(),这可确保根据需要调用适当的 struct phylink_mac_ops 方法。

有关在 DT 中描述 SFP 插槽的信息,请参见内核源代码树 Documentation/devicetree/bindings/net/sff,sfp.yaml 中的绑定文档。

©内核开发社区。 | 由 Sphinx 5.3.0 & Alabaster 0.7.16 强力驱动 | 页面源码