Linux 内核 dpll 子系统¶
DPLL¶
PLL - 锁相环是一种电子电路,它将设备的时钟信号与外部时钟信号同步。有效地使设备以与 PLL 输入提供的相同的时钟信号节拍运行。
DPLL - 数字锁相环是一种集成电路,除了普通的 PLL 行为外,还包含一个数字相位检测器,并且在环路中可能具有数字分频器。因此,DPLL 的输入和输出上的频率可以配置。
子系统¶
dpll 子系统的主要目的是提供一个通用接口,用于配置使用任何类型的数字 PLL 的设备,并且可以使用不同的输入信号源进行同步,以及不同类型的输出。主要接口是基于 NETLINK_GENERIC 的协议,其中定义了事件监视多播组。
设备对象¶
单个 dpll 设备对象表示单个数字 PLL 电路和一堆连接的引脚。它响应 netlink 命令 DPLL_CMD_DEVICE_GET
的 do 请求,向用户报告支持的操作模式和当前状态,并通过同一命令的 dump netlink 请求列出在子系统中注册的 dpll。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 引脚
章节所述。
相位偏移测量和调整¶
设备可能提供测量引脚上的信号与其父 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
相位调整的属性最小值
DPLL_A_PIN_PHASE_ADJUST_MAX
相位调整的属性最大值
DPLL_A_PIN_PHASE_ADJUST
父 DPLL 设备上配置的相位调整属性值
DPLL_A_PIN_PARENT_DEVICE
用于请求给定父 DPLL 设备配置的嵌套属性
DPLL_A_PIN_PARENT_ID
父 DPLL 设备 ID
DPLL_A_PIN_PHASE_OFFSET
引脚和父 DPLL 设备之间测得的相位差属性
所有与相位相关的值均以皮秒为单位提供,表示信号相位之间的时间差。负值表示引脚上信号的相位在时间上早于 DPLL 的信号。正值表示引脚上信号的相位在时间上晚于 DPLL 的信号。
相位调整(以及最小值和最大值)是整数,但测得的相位偏移值是带 3 位小数的分数值,应除以 DPLL_PIN_PHASE_OFFSET_DIVIDER
以获得整数部分,并进行模除以获得小数部分。
嵌入式同步¶
设备可能提供使用嵌入式同步功能的能力。它允许在引脚的基本频率中嵌入额外的同步信号——每次发生同步信号脉冲时,基本频率信号的一个特殊脉冲。用户可以配置嵌入式同步的频率。嵌入式同步功能始终与给定的基本频率和硬件功能相关。根据为引脚配置的当前基本频率,会向用户提供支持的嵌入式同步频率范围。
DPLL_A_PIN_ESYNC_FREQUENCY
当前的嵌入式同步频率
DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED
嵌套可用的嵌入式同步频率范围
DPLL_A_PIN_FREQUENCY_MIN
频率的属性最小值
DPLL_A_PIN_FREQUENCY_MAX
频率的属性最大值
DPLL_A_PIN_ESYNC_PULSE
嵌入式同步的脉冲类型
配置命令组¶
配置命令用于获取有关已注册 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
注册者的属性模块名称
DPLL_A_CLOCK_ID
属性唯一时钟标识符(EUI-64),如 IEEE 1588 标准定义
DPLL_A_TYPE
DPLL 设备的属性类型
DPLL_CMD_DEVICE_GET
获取设备信息或转储可用设备列表的命令
DPLL_A_ID
属性唯一的 DPLL 设备 ID
DPLL_A_MODULE_NAME
注册者的属性模块名称
DPLL_A_CLOCK_ID
属性唯一时钟标识符(EUI-64),如 IEEE 1588 标准定义
DPLL_A_MODE
属性选择模式
DPLL_A_MODE_SUPPORTED
属性可用的选择模式
DPLL_A_LOCK_STATUS
DPLL 设备锁定状态的属性
DPLL_A_TEMP
属性设备温度信息
DPLL_A_TYPE
DPLL 设备的属性类型
DPLL_CMD_DEVICE_SET
用于设置 DPLL 设备配置的命令
DPLL_A_ID
属性内部 DPLL 设备索引
DPLL_A_MODE
属性要配置的选择模式
用于引脚的命令类型的常量使用 DPLL_CMD_PIN_
前缀,并根据命令目的使用后缀。引脚相关属性使用 DPLL_A_PIN_
前缀,并根据属性目的使用后缀。
DPLL_CMD_PIN_ID_GET
获取引脚 ID 的命令
DPLL_A_PIN_MODULE_NAME
注册者的属性模块名称
DPLL_A_PIN_CLOCK_ID
属性唯一时钟标识符(EUI-64),如 IEEE 1588 标准定义
DPLL_A_PIN_BOARD_LABEL
注册者提供的属性引脚板标签
DPLL_A_PIN_PANEL_LABEL
注册者提供的属性引脚面板标签
DPLL_A_PIN_PACKAGE_LABEL
注册者提供的属性引脚封装标签
DPLL_A_PIN_TYPE
引脚的属性类型
DPLL_CMD_PIN_GET
获取引脚信息或转储可用引脚列表的命令
DPLL_A_PIN_ID
属性唯一的引脚 ID
DPLL_A_PIN_MODULE_NAME
注册者的属性模块名称
DPLL_A_PIN_CLOCK_ID
属性唯一时钟标识符(EUI-64),如 IEEE 1588 标准定义
DPLL_A_PIN_BOARD_LABEL
注册者提供的属性引脚板标签
DPLL_A_PIN_PANEL_LABEL
注册者提供的属性引脚面板标签
DPLL_A_PIN_PACKAGE_LABEL
注册者提供的属性引脚封装标签
DPLL_A_PIN_TYPE
引脚的属性类型
DPLL_A_PIN_FREQUENCY
引脚的属性当前频率
DPLL_A_PIN_FREQUENCY_SUPPORTED
嵌套属性提供支持的频率
DPLL_A_PIN_ANY_FREQUENCY_MIN
频率的属性最小值
DPLL_A_PIN_ANY_FREQUENCY_MAX
频率的属性最大值
DPLL_A_PIN_PHASE_ADJUST_MIN
相位调整的属性最小值
DPLL_A_PIN_PHASE_ADJUST_MAX
相位调整的属性最大值
DPLL_A_PIN_PHASE_ADJUST
父设备上配置的相位调整属性值
DPLL_A_PIN_PARENT_DEVICE
对于引脚连接的每个父设备的嵌套属性
DPLL_A_PIN_PARENT_ID
属性父 DPLL 设备 ID
DPLL_A_PIN_PRIO
引脚在 DPLL 设备上的属性优先级
DPLL_A_PIN_STATE
引脚在父 DPLL 设备上的属性状态
DPLL_A_PIN_DIRECTION
引脚在父 DPLL 设备上的属性方向
DPLL_A_PIN_PHASE_OFFSET
引脚和父 DPLL 之间测得的相位差属性
DPLL_A_PIN_PARENT_PIN
对于引脚连接的每个父引脚的嵌套属性
DPLL_A_PIN_PARENT_ID
属性父引脚 ID
DPLL_A_PIN_STATE
引脚在父引脚上的属性状态
DPLL_A_PIN_CAPABILITIES
引脚功能的属性位掩码
DPLL_CMD_PIN_SET
用于设置引脚配置的命令
DPLL_A_PIN_ID
属性唯一的引脚 ID
DPLL_A_PIN_FREQUENCY
引脚的属性请求频率
DPLL_A_PIN_PHASE_ADJUST
父设备上请求的相位调整属性值
DPLL_A_PIN_PARENT_DEVICE
每个父 DPLL 设备配置请求的嵌套属性
DPLL_A_PIN_PARENT_ID
属性父 DPLL 设备 ID
DPLL_A_PIN_DIRECTION
引脚的属性请求方向
DPLL_A_PIN_PRIO
引脚在 DPLL 设备上的属性请求优先级
DPLL_A_PIN_STATE
引脚在 DPLL 设备上的属性请求状态
DPLL_A_PIN_PARENT_PIN
每个父引脚配置请求的嵌套属性
DPLL_A_PIN_PARENT_ID
属性父引脚 ID
DPLL_A_PIN_STATE
引脚在父引脚上的属性请求状态
Netlink 转储请求¶
DPLL_CMD_DEVICE_GET
和 DPLL_CMD_PIN_GET
命令能够执行转储类型 netlink 请求,在这种情况下,响应的格式与其 do
请求的格式相同,但会返回系统中注册的每个设备或引脚。
SET 命令格式¶
DPLL_CMD_DEVICE_SET
- 要定位 DPLL 设备,用户提供 DPLL_A_ID
,它是系统中 DPLL 设备的唯一标识符,以及正在配置的参数(DPLL_A_MODE
)。
DPLL_CMD_PIN_SET
- 要定位引脚,用户必须提供 DPLL_A_PIN_ID
,它是系统中引脚的唯一标识符。还必须添加配置的引脚参数。如果配置了 DPLL_A_PIN_FREQUENCY
,这将影响与该引脚连接的所有 DPLL 设备,这就是为什么频率属性不应包含在 DPLL_A_PIN_PARENT_DEVICE
中的原因。其他属性:DPLL_A_PIN_PRIO
、DPLL_A_PIN_STATE
或 DPLL_A_PIN_DIRECTION
必须包含在 DPLL_A_PIN_PARENT_DEVICE
中,因为它们的配置仅与其中一个父 DPLL 相关,该父 DPLL 由 DPLL_A_PIN_PARENT_ID
属性定位,该属性也需要在该嵌套内部。对于 MUX 类型引脚,DPLL_A_PIN_STATE
属性以类似的方式配置,方法是将所需状态包含在 DPLL_A_PIN_PARENT_PIN
嵌套属性中,并将目标父引脚 ID 包含在 DPLL_A_PIN_PARENT_ID
中。
通常,可以一次配置多个参数,但内部每个参数更改都将单独调用,并且不以任何方式保证配置顺序。
配置预定义枚举¶
-
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() 获取对它的引用,以及使用它们自己的操作和私有数据注册 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 驱动程序中。操作结构定义如下
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 网络设备恢复的信号驱动 DPLL。这是通过将引脚暴露给网络设备来实现的 - 使用 dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)
将引脚附加到网络设备本身。暴露的引脚 ID 句柄 DPLL_A_PIN_ID
然后可被用户识别,因为它附加到 rtnetlink 以响应嵌套属性 IFLA_DPLL_PIN
中的 get RTM_NEWLINK
命令。