Linux kernel dpll 子系统¶
DPLL¶
PLL - 锁相环是一种电子电路,它将设备的时钟信号与外部时钟信号同步。 有效地使设备以与 PLL 输入上提供的相同的时钟信号节拍运行。
DPLL - 数字锁相环是一种集成电路,除了普通的 PLL 行为外,还包含数字相位检测器,并且可能在环路中具有数字分频器。 因此,DPLL 输入和输出端的频率可以配置。
子系统¶
dpll 子系统的主要目的是提供通用接口来配置使用任何类型的数字 PLL 的设备,并且可以使用不同的输入信号源进行同步,以及不同类型的输出。 主要接口是基于 NETLINK_GENERIC 的协议,并定义了一个事件监控多播组。
设备对象¶
单个 dpll 设备对象表示单个数字 PLL 电路和一堆连接的引脚。 它向用户报告支持的操作模式和当前状态,以响应 netlink 命令 DPLL_CMD_DEVICE_GET
的 do 请求,并列出子系统中注册的 dpll,以响应同一命令的 dump netlink 请求。 更改 dpll 设备的配置是通过 netlink DPLL_CMD_DEVICE_SET
命令的 do 请求完成的。 设备句柄是 DPLL_A_ID
,应提供该句柄以获取或设置系统中特定设备的配置。 它可以与 DPLL_CMD_DEVICE_GET
dump 请求或 DPLL_CMD_DEVICE_ID_GET
do 请求一起获取,其中一个必须提供导致单个设备匹配的属性。
引脚对象¶
引脚是一个非晶形对象,表示输入或输出,它可以是设备的内部组件,也可以是外部连接的组件。 每个 dpll 的引脚数各不相同,但通常会为单个 dpll 设备提供多个引脚。 引脚的属性、功能和状态在响应 netlink DPLL_CMD_PIN_GET
命令的 do 请求时提供给用户。 也可以使用 DPLL_CMD_PIN_GET
命令的 dump 请求列出系统中注册的所有引脚。 可以通过 netlink DPLL_CMD_PIN_SET
命令的 do 请求来更改引脚的配置。 引脚句柄是 DPLL_A_PIN_ID
,应提供该句柄以获取或设置系统中特定引脚的配置。 可以通过 DPLL_CMD_PIN_GET
dump 请求或 DPLL_CMD_PIN_ID_GET
do 请求来获取,其中用户提供导致单个引脚匹配的属性。
引脚选择¶
通常,所选引脚(信号驱动 dpll 设备的引脚)可以从 DPLL_A_PIN_STATE
属性获得,并且对于任何 dpll 设备,只能有一个引脚处于 DPLL_PIN_STATE_CONNECTED
状态。
引脚选择可以手动或自动完成,具体取决于硬件功能和活动的 dpll 设备工作模式(DPLL_A_MODE
属性)。 结果是,对于每种模式,可用引脚状态都存在差异,并且对于用户可以为 dpll 设备请求的状态也存在差异。
在手动模式 (DPLL_MODE_MANUAL
) 中,用户可以请求或接收以下引脚状态之一
DPLL_PIN_STATE_CONNECTED
- 引脚用于驱动 dpll 设备DPLL_PIN_STATE_DISCONNECTED
- 引脚不用于驱动 dpll 设备
在自动模式 (DPLL_MODE_AUTOMATIC
) 中,用户可以请求或接收以下引脚状态之一
DPLL_PIN_STATE_SELECTABLE
- 应将引脚视为自动选择算法的有效输入DPLL_PIN_STATE_DISCONNECTED
- 不应将引脚视为自动选择算法的有效输入
在自动模式 (DPLL_MODE_AUTOMATIC
) 中,一旦自动选择算法使用其中一个输入锁定 dpll 设备,用户只能接收引脚状态 DPLL_PIN_STATE_CONNECTED
。
MUX 类型引脚¶
引脚可以是 MUX 类型,它聚合子引脚并充当引脚多路复用器。 一个或多个引脚注册为 MUX 类型,而不是直接注册到 dpll 设备。 注册为 MUX 类型引脚的引脚为用户提供额外的嵌套属性 DPLL_A_PIN_PARENT_PIN
,用于它们注册到的每个父引脚。 如果引脚注册了多个父引脚,则它们的行为类似于多输出多路复用器。 在这种情况下,DPLL_CMD_PIN_GET
的输出将包含多个引脚-父级嵌套属性,其中包含与每个父级相关的当前状态,例如
'pin': [{{
'clock-id': 282574471561216,
'module-name': 'ice',
'capabilities': 4,
'id': 13,
'parent-pin': [
{'parent-id': 2, 'state': 'connected'},
{'parent-id': 3, 'state': 'disconnected'}
],
'type': 'synce-eth-port'
}}]
一次只有一个子引脚可以将其信号提供给父 MUX 类型引脚,选择是通过请求更改所需父级上的子引脚状态来完成的,方法是使用 DPLL_A_PIN_PARENT
嵌套属性。 在父引脚上设置状态 netlink 消息格式示例
DPLL_A_PIN_ID
子引脚 ID
DPLL_A_PIN_PARENT_PIN
用于请求与父引脚相关的配置的嵌套属性
DPLL_A_PIN_PARENT_ID
父引脚 ID
DPLL_A_PIN_STATE
父引脚上请求的引脚状态
引脚优先级¶
某些设备可能提供自动引脚选择模式的功能(DPLL_A_MODE
属性的枚举值 DPLL_MODE_AUTOMATIC
)。 通常,自动选择是在硬件级别执行的,这意味着只有直接连接到 dpll 的引脚才能用于自动输入引脚选择。 在自动选择模式下,用户无法手动选择设备的输入引脚,而是用户应为所有直接连接的引脚提供优先级 DPLL_A_PIN_PRIO
,设备将选择最高优先级的有效信号并使用它来控制 DPLL 设备。 在父引脚上设置优先级 netlink 消息格式示例
DPLL_A_PIN_ID
配置的引脚 ID
DPLL_A_PIN_PARENT_DEVICE
用于请求与父 dpll 设备相关的配置的嵌套属性
DPLL_A_PIN_PARENT_ID
父 dpll 设备 ID
DPLL_A_PIN_PRIO
在父 dpll 上请求的引脚优先级
MUX 类型引脚的子引脚无法进行自动输入引脚选择,为了配置 MUX 类型引脚的活动输入,用户需要请求父引脚上子引脚的所需引脚状态,如 MUX-type pins
章节所述。
相位偏移测量和调整¶
设备可以提供测量引脚上的信号及其父 dpll 设备之间的相位差的能力。 如果支持引脚-dpll 相位偏移测量,则应为每个父 dpll 设备提供 DPLL_A_PIN_PHASE_OFFSET
属性。
设备还可以提供调整引脚上信号相位的能力。 如果支持引脚相位调整,则引脚句柄应在 DPLL_CMD_PIN_GET
响应中为用户提供最小值和最大值,属性为 DPLL_A_PIN_PHASE_ADJUST_MIN
和 DPLL_A_PIN_PHASE_ADJUST_MAX
。 配置的相位调整值由引脚的 DPLL_A_PIN_PHASE_ADJUST
属性提供,并且可以使用相同的属性通过 DPLL_CMD_PIN_SET
命令请求更改值。
DPLL_A_PIN_ID
配置的引脚 ID
DPLL_A_PIN_PHASE_ADJUST_MIN
attr 相位调整的最小值
DPLL_A_PIN_PHASE_ADJUST_MAX
attr 相位调整的最大值
DPLL_A_PIN_PHASE_ADJUST
attr 在父 dpll 设备上配置的相位调整值
DPLL_A_PIN_PARENT_DEVICE
用于请求给定父 dpll 设备上的配置的嵌套属性
DPLL_A_PIN_PARENT_ID
父 dpll 设备 ID
DPLL_A_PIN_PHASE_OFFSET
attr 引脚和父 dpll 设备之间测量的相位差
所有与相位相关的值均以皮秒为单位提供,表示信号相位之间的时间差。 负值表示引脚上的信号的相位在时间上早于 dpll 的信号。 正值表示引脚上的信号的相位在时间上晚于 dpll 的信号。
相位调整(最小值和最大值)值是整数,但测量的相位偏移值是具有 3 位小数位的分数,并且应使用 DPLL_PIN_PHASE_OFFSET_DIVIDER
进行除以获得整数部分,并进行模运算以获得分数部分。
嵌入式 SYNC¶
设备可以提供使用嵌入式 SYNC 功能的能力。 它允许将额外的 SYNC 信号嵌入到引脚的基本频率中 - 每次发生 SYNC 信号脉冲时,基本频率信号的一个特殊脉冲。 用户可以配置嵌入式 SYNC 的频率。 嵌入式 SYNC 功能始终与给定的基本频率和硬件功能相关。 根据为引脚配置的当前基本频率,为用户提供支持的嵌入式 SYNC 频率范围。
DPLL_A_PIN_ESYNC_FREQUENCY
当前嵌入式 SYNC 频率
DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED
嵌套可用嵌入式 SYNC 频率范围
DPLL_A_PIN_FREQUENCY_MIN
attr 频率的最小值
DPLL_A_PIN_FREQUENCY_MAX
attr 频率的最大值
DPLL_A_PIN_ESYNC_PULSE
嵌入式 SYNC 的脉冲类型
配置命令组¶
配置命令用于获取有关注册的 dpll 设备(和引脚)的信息,以及设置设备或引脚的配置。 由于 dpll 设备必须被抽象化并反映真实的硬件,因此无法从用户空间通过 netlink 添加新的 dpll 设备,并且每个设备都应由其驱动程序注册。
所有 netlink 命令都需要 GENL_ADMIN_PERM
。 这是为了防止来自未经授权的用户空间应用程序的任何垃圾邮件/DoS 攻击。
带有可用属性的 netlink 命令列表¶
用于 dpll 设备的标识命令类型的常量使用 DPLL_CMD_
前缀,并根据命令目的使用后缀。 与 dpll 设备相关的属性使用 DPLL_A_
前缀,并根据属性目的使用后缀。
DPLL_CMD_DEVICE_ID_GET
获取设备 ID 的命令
DPLL_A_MODULE_NAME
attr 注册程序的模块名称
DPLL_A_CLOCK_ID
attr 唯一的时钟标识符 (EUI-64),由 IEEE 1588 标准定义
DPLL_A_TYPE
attr dpll 设备的类型
DPLL_CMD_DEVICE_GET
获取设备信息或转储可用设备列表的命令
DPLL_A_ID
attr 唯一的 dpll 设备 ID
DPLL_A_MODULE_NAME
attr 注册程序的模块名称
DPLL_A_CLOCK_ID
attr 唯一的时钟标识符 (EUI-64),由 IEEE 1588 标准定义
DPLL_A_MODE
attr 选择模式
DPLL_A_MODE_SUPPORTED
attr 可用的选择模式
DPLL_A_LOCK_STATUS
attr dpll 设备锁定状态
DPLL_A_TEMP
attr 设备温度信息
DPLL_A_TYPE
attr dpll 设备的类型
DPLL_CMD_DEVICE_SET
设置 dpll 设备配置的命令
DPLL_A_ID
attr 内部 dpll 设备索引
DPLL_A_MODE
attr 要配置的选择模式
用于引脚的标识命令类型的常量使用 DPLL_CMD_PIN_
前缀,并根据命令目的使用后缀。 与引脚相关的属性使用 DPLL_A_PIN_
前缀,并根据属性目的使用后缀。
DPLL_CMD_PIN_ID_GET
获取引脚 ID 的命令
DPLL_A_PIN_MODULE_NAME
attr 注册程序的模块名称
DPLL_A_PIN_CLOCK_ID
attr 唯一的时钟标识符 (EUI-64),由 IEEE 1588 标准定义
DPLL_A_PIN_BOARD_LABEL
attr 注册程序提供的引脚板标签
DPLL_A_PIN_PANEL_LABEL
attr 注册程序提供的引脚面板标签
DPLL_A_PIN_PACKAGE_LABEL
attr 注册程序提供的引脚封装标签
DPLL_A_PIN_TYPE
attr 引脚的类型
DPLL_CMD_PIN_GET
获取引脚信息或转储可用引脚列表的命令
DPLL_A_PIN_ID
DPLL_A_PIN_ID
DPLL_A_PIN_MODULE_NAME
attr 注册程序的模块名称
DPLL_A_PIN_CLOCK_ID
attr 唯一的时钟标识符 (EUI-64),由 IEEE 1588 标准定义
DPLL_A_PIN_BOARD_LABEL
attr 注册程序提供的引脚板标签
DPLL_A_PIN_PANEL_LABEL
attr 注册程序提供的引脚面板标签
DPLL_A_PIN_PACKAGE_LABEL
attr 注册程序提供的引脚封装标签
DPLL_A_PIN_TYPE
attr 引脚的类型
attr 唯一的引脚 ID
DPLL_A_PIN_FREQUENCY
attr 引脚的当前频率
DPLL_A_PIN_FREQUENCY_SUPPORTED
nested attr provides supported frequencies
attr 频率的最小值
DPLL_A_PIN_ANY_FREQUENCY_MIN
attr 频率的最大值
DPLL_A_PIN_PHASE_ADJUST_MIN
attr 相位调整的最小值
DPLL_A_PIN_PHASE_ADJUST_MAX
attr 相位调整的最大值
DPLL_A_PIN_PHASE_ADJUST
DPLL_A_PIN_ANY_FREQUENCY_MAX
DPLL_A_PIN_PARENT_DEVICE
attr 在父设备上配置的相位调整值
DPLL_A_PIN_PARENT_ID
嵌套 attr 用于引脚连接的每个父设备
DPLL_A_PIN_PRIO
attr 父 dpll 设备 ID
DPLL_A_PIN_STATE
attr 引脚在 dpll 设备上的优先级
attr 引脚在父 dpll 设备上的状态
DPLL_A_PIN_DIRECTION
DPLL_A_PIN_PHASE_OFFSET
attr 引脚在父 dpll 设备上的方向
DPLL_A_PIN_PARENT_PIN
attr 测量的引脚和父 dpll 之间的相位差
DPLL_A_PIN_PARENT_ID
嵌套 attr 用于引脚连接的每个父引脚
DPLL_A_PIN_STATE
attr 父引脚 ID
attr 引脚在父引脚上的状态
DPLL_A_PIN_CAPABILITIES
attr 引脚功能的位掩码
DPLL_CMD_PIN_SET
DPLL_A_PIN_ID
DPLL_A_PIN_ID
attr 唯一的引脚 ID
设置引脚配置的命令
DPLL_A_PIN_PHASE_ADJUST
attr 引脚的请求频率
DPLL_A_PIN_PARENT_DEVICE
attr 在父设备上请求的相位调整值
DPLL_A_PIN_PARENT_ID
嵌套 attr 用于引脚连接的每个父设备
attr 引脚在父 dpll 设备上的状态
嵌套 attr 用于每个父 dpll 设备配置请求
DPLL_A_PIN_PRIO
attr 引脚的请求方向
DPLL_A_PIN_STATE
attr 引脚在 dpll 设备上的请求优先级
DPLL_A_PIN_PARENT_PIN
attr 引脚在 dpll 设备上的请求状态
DPLL_A_PIN_PARENT_ID
嵌套 attr 用于引脚连接的每个父引脚
DPLL_A_PIN_STATE
嵌套 attr 用于每个父引脚配置请求
attr 引脚在父引脚上的请求状态
Netlink 转储请求¶
DPLL_CMD_DEVICE_GET
和 DPLL_CMD_PIN_GET
命令能够进行转储类型的 netlink 请求,在这种情况下,响应的格式与它们的 do
请求的格式相同,但返回系统中注册的每个设备或引脚。
SET 命令格式¶
DPLL_CMD_DEVICE_SET
- 要定位 dpll 设备,用户提供 DPLL_A_ID
,它是系统中 dpll 设备的唯一标识符,以及配置的参数 (DPLL_A_MODE
)。
通常情况下,可以一次配置多个参数,但内部每个参数更改都会单独调用,且配置顺序不以任何方式保证。
配置预定义枚举¶
-
enum dpll_mode¶
dpll可以支持的工作模式,区分 dpll 如何选择其输入之一以与之同步,DPLL_A_MODE 属性的有效值
常量
DPLL_MODE_MANUAL
输入只能通过向 dpll 发送请求来选择
DPLL_MODE_AUTOMATIC
最高优先级的输入引脚由 dpll 自动选择
-
enum dpll_lock_status¶
提供 dpll 设备锁定状态的信息,DPLL_A_LOCK_STATUS 属性的有效值
常量
DPLL_LOCK_STATUS_UNLOCKED
dpll 尚未锁定到任何有效输入(或通过将 DPLL_A_MODE 设置为 DPLL_MODE_DETACHED 强制执行)
DPLL_LOCK_STATUS_LOCKED
dpll 已锁定到有效信号,但没有保持可用
DPLL_LOCK_STATUS_LOCKED_HO_ACQ
dpll 已锁定并且已获取保持
DPLL_LOCK_STATUS_HOLDOVER
dpll 处于保持状态 - 丢失了有效的锁定或通过断开所有引脚强制执行(只有当 dpll 锁定状态已经是 DPLL_LOCK_STATUS_LOCKED_HO_ACQ 时才有可能,如果 dpll 锁定状态不是 DPLL_LOCK_STATUS_LOCKED_HO_ACQ,则 dpll 的锁定状态应保持 DPLL_LOCK_STATUS_UNLOCKED)
-
enum dpll_lock_status_error¶
如果之前的状态更改是由于故障引起的,则提供 dpll 设备锁定状态错误的信息。DPLL_A_LOCK_STATUS_ERROR 属性的有效值
常量
DPLL_LOCK_STATUS_ERROR_NONE
dpll 设备锁定状态已更改,没有任何错误
DPLL_LOCK_STATUS_ERROR_UNDEFINED
dpll 设备锁定状态由于未定义的错误而更改。如果驱动程序无法获得合适的精确错误类型,则驱动程序会填充此值。
DPLL_LOCK_STATUS_ERROR_MEDIA_DOWN
dpll 设备锁定状态已更改,因为关联的媒体已关闭。例如,如果 dpll 设备之前已锁定在 PIN_TYPE_SYNCE_ETH_PORT 类型的输入引脚上,则可能会发生这种情况。
DPLL_LOCK_STATUS_ERROR_FRACTIONAL_FREQUENCY_OFFSET_TOO_HIGH
媒体上的 RX 和 TX 符号速率之间的 FFO(分数频率偏移)太高。例如,如果 dpll 设备之前已锁定在 PIN_TYPE_SYNCE_ETH_PORT 类型的输入引脚上,则可能会发生这种情况。
-
enum dpll_type¶
dpll的类型,DPLL_A_TYPE 属性的有效值
常量
DPLL_TYPE_PPS
dpll 产生每秒脉冲信号
DPLL_TYPE_EEC
dpll 驱动以太网设备时钟
-
enum dpll_pin_type¶
定义引脚的可能类型,DPLL_A_PIN_TYPE 属性的有效值
常量
DPLL_PIN_TYPE_MUX
聚合另一层可选择的引脚
DPLL_PIN_TYPE_EXT
外部输入
DPLL_PIN_TYPE_SYNCE_ETH_PORT
以太网端口 PHY 的恢复时钟
DPLL_PIN_TYPE_INT_OSCILLATOR
设备内部振荡器
DPLL_PIN_TYPE_GNSS
GNSS 恢复时钟
-
enum dpll_pin_direction¶
定义引脚的可能方向,DPLL_A_PIN_DIRECTION 属性的有效值
常量
DPLL_PIN_DIRECTION_INPUT
引脚用作信号的输入
DPLL_PIN_DIRECTION_OUTPUT
引脚用于输出信号
-
enum dpll_pin_state¶
定义引脚的可能状态,DPLL_A_PIN_STATE 属性的有效值
常量
DPLL_PIN_STATE_CONNECTED
引脚已连接,锁相环的活动输入
DPLL_PIN_STATE_DISCONNECTED
引脚已断开,不被视为有效输入
DPLL_PIN_STATE_SELECTABLE
启用引脚以进行自动输入选择
-
enum dpll_pin_capabilities¶
定义引脚的可能功能,DPLL_A_PIN_CAPABILITIES 属性的有效标志
常量
DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE
可以更改引脚方向
DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE
可以更改引脚优先级
DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE
可以更改引脚状态
通知¶
dpll 设备可以提供有关设备状态更改的通知,即锁定状态更改、输入/输出更改或其他警报。有一个多播组用于通过 netlink 套接字通知用户空间应用程序:DPLL_MCGRP_MONITOR
通知消息
DPLL_CMD_DEVICE_CREATE_NTF
dpll 设备已创建
DPLL_CMD_DEVICE_DELETE_NTF
dpll 设备已删除
DPLL_CMD_DEVICE_CHANGE_NTF
dpll 设备已更改
DPLL_CMD_PIN_CREATE_NTF
dpll 引脚已创建
DPLL_CMD_PIN_DELETE_NTF
dpll 引脚已删除
DPLL_CMD_PIN_CHANGE_NTF
dpll 引脚已更改
事件格式与相应的 get 命令相同。DPLL_CMD_DEVICE_
事件的格式与 DPLL_CMD_DEVICE_GET
的响应相同。DPLL_CMD_PIN_
事件的格式与 DPLL_CMD_PIN_GET
的响应相同。
设备驱动程序实现¶
设备由 dpll_device_get() 调用分配。使用相同参数的第二次调用不会创建新对象,而是为给定参数提供指向先前创建的设备的指针,它还会增加该对象的引用计数。设备由 dpll_device_put() 调用释放,该调用首先减少引用计数,一旦引用计数清除,该对象将被销毁。
设备应实现一组操作并通过 dpll_device_register() 注册设备,此时它对用户可用。多个驱动程序实例可以使用 dpll_device_get() 获取对其的引用,以及使用其自己的 ops 和 priv 注册 dpll 设备。
引脚使用 dpll_pin_get() 单独分配,它的工作方式类似于 dpll_device_get()。函数首先创建对象,然后对于使用相同参数的每个调用,只有对象引用计数增加。此外,dpll_pin_put() 的工作方式类似于 dpll_device_put()。
引脚可以根据硬件需求注册到父 dpll 设备或父引脚。每个注册都需要注册者提供一组引脚回调,以及用于调用它们的数据私有指针
dpll_pin_register() - 将引脚注册到 dpll 设备,
dpll_pin_on_pin_register() - 将引脚注册到另一个 MUX 类型引脚。
添加或删除 dpll 设备的通知在子系统本身内创建。关于注册/取消注册引脚的通知也由子系统调用。关于 dpll 设备或引脚的状态更改的通知以两种方式调用
在成功请求 dpll 子系统更改后,子系统调用相应的通知,
由设备驱动程序使用 dpll_device_change_ntf() 或 dpll_pin_change_ntf() 请求,当驱动程序通知状态更改时。
使用 dpll 接口的设备驱动程序不需要实现所有回调操作。但是,有一些需要实现。所需的 dpll 设备级别回调操作
.mode_get
,.lock_status_get
.
所需的引脚级别回调操作
.state_on_dpll_get
(注册到 dpll 设备的引脚),.state_on_pin_get
(注册到父引脚的引脚),.direction_get
.
检查每个其他操作处理程序是否存在,如果缺少特定处理程序,则返回 -EOPNOTSUPP
。
最简单的实现是在 OCP TimeCard 驱动程序中。ops 结构定义如下
static const struct dpll_device_ops dpll_ops = {
.lock_status_get = ptp_ocp_dpll_lock_status_get,
.mode_get = ptp_ocp_dpll_mode_get,
.mode_supported = ptp_ocp_dpll_mode_supported,
};
static const struct dpll_pin_ops dpll_pins_ops = {
.frequency_get = ptp_ocp_dpll_frequency_get,
.frequency_set = ptp_ocp_dpll_frequency_set,
.direction_get = ptp_ocp_dpll_direction_get,
.direction_set = ptp_ocp_dpll_direction_set,
.state_on_dpll_get = ptp_ocp_dpll_state_get,
};
然后注册部分看起来像这样
clkid = pci_get_dsn(pdev);
bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE);
if (IS_ERR(bp->dpll)) {
err = PTR_ERR(bp->dpll);
dev_err(&pdev->dev, "dpll_device_alloc failed\n");
goto out;
}
err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp);
if (err)
goto out;
for (i = 0; i < OCP_SMA_NUM; i++) {
bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].dpll_prop);
if (IS_ERR(bp->sma[i].dpll_pin)) {
err = PTR_ERR(bp->dpll);
goto out_dpll;
}
err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops,
&bp->sma[i]);
if (err) {
dpll_pin_put(bp->sma[i].dpll_pin);
goto out_dpll;
}
}
在错误路径中,我们必须以相反的顺序倒退每个分配
while (i) {
--i;
dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]);
dpll_pin_put(bp->sma[i].dpll_pin);
}
dpll_device_put(bp->dpll);
更复杂的示例可以在 Intel 的 ICE 驱动程序或 nVidia 的 mlx5 驱动程序中找到。
SyncE 启用¶
对于 SyncE 启用,需要允许软件应用程序控制 dpll 设备,该应用程序监视和配置 dpll 设备的输入,以响应 dpll 设备及其输入的当前状态。在这种情况下,dpll 设备输入信号也应可配置为使用从 PHY netdevice 恢复的信号来驱动 dpll。这通过将引脚暴露给 netdevice 来完成 - 使用 dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)
将引脚附加到 netdevice 本身。暴露的引脚 id 句柄 DPLL_A_PIN_ID
然后可以被用户识别,因为它附加到 rtnetlink 以响应嵌套属性 IFLA_DPLL_PIN
中的 get RTM_NEWLINK
命令。