Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'dpll-api'

Vadim Fedorenko says:

====================
Create common DPLL configuration API

Implement common API for DPLL configuration and status reporting.
The API utilises netlink interface as transport for commands and event
notifications. This API aims to extend current pin configuration
provided by PTP subsystem and make it flexible and easy to cover
complex configurations.

Netlink interface is based on ynl spec, it allows use of in-kernel
tools/net/ynl/cli.py application to control the interface with properly
formated command and json attribute strings. Here are few command
examples of how it works with `ice` driver on supported NIC:

- dump dpll devices:
$ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/dpll.yaml \
--dump device-get
[{'clock-id': 4658613174691613800,
'id': 0,
'lock-status': 'locked-ho-acq',
'mode': 'automatic',
'mode-supported': ['automatic'],
'module-name': 'ice',
'type': 'eec'},
{'clock-id': 4658613174691613800,
'id': 1,
'lock-status': 'locked-ho-acq',
'mode': 'automatic',
'mode-supported': ['automatic'],
'module-name': 'ice',
'type': 'pps'}]

- get single pin info:
$ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/dpll.yaml \
--do pin-get --json '{"id":2}'
{'board-label': 'C827_0-RCLKA',
'clock-id': 4658613174691613800,
'capabilities': 6,
'frequency': 1953125,
'id': 2,
'module-name': 'ice',
'parent-device': [{'direction': 'input',
'parent-id': 0,
'prio': 9,
'state': 'disconnected'},
{'direction': 'input',
'parent-id': 1,
'prio': 9,
'state': 'disconnected'}],
'type': 'mux'}

- set pin's state on dpll:
$ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/dpll.yaml \
--do pin-set --json '{"id":2, "parent-device":{"parent-id":1, "state":2}}'

- set pin's prio on dpll:
$ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/dpll.yaml \
--do pin-set --json '{"id":2, "parent-device":{"parent-id":1, "prio":4}}'

- set pin's state on parent pin:
$ sudo ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/dpll.yaml \
--do pin-set --json '{"id":13, "parent-pin":{"parent-id":2, "state":1}}'

Changelog:

v7 -> v8:
- rebase on top of net-next
- no functional changes in patchset

v6 -> v7:
- use unique id in references array to prevent possible crashes

v5 -> v6:
- change dpll-caps to pin capabilities and adjust enum accordingly
- remove dpll.h from netdevice.h

v4 -> v5:
- separate namespace for pin attributes
- small fixes, more details in the patches

v3 -> v4:
- rebase on top of net-next
- fix flag usage in ice

v2 -> v3:
- more style and warning fixes
- details in per-patch logs

v1 -> v2:
- remove FREERUN/DETACHED mode
- reorder functions in commits not to depend on files introduced in
future commits
- style and warning fixes

v9 RFC -> v1:
- Merge header patch into the patches where the actual functions are
implemented
- Address comments from previous reviews
- Per patch change log contains more details

RFC versions:
v8 -> v9:
[00/10] Create common DPLL configuration API
- update examples to reflect new pin-parent nest split

[01/10] dpll: documentation on DPLL subsystem interface
- fix docs build warnings
- separate netlink command/attribute list
- replace enum description with uapi header
- add brief explanation what is a DPLL
- fix EOPNOTSUPP typo
- fix typo .state_get -> .state_on_dpll_get

[02/10] dpll: spec: Add Netlink spec in YAML
- regenerate policy max values
- add missing enum descriptions
- split pin-parent nest:
- pin-parent-device - for configuration of pin-device tuple
- pin-parent-pin - for configuration od pin-pin tuple
- fix typos:
- s/working-modes/working modes/
- s/differentiate/differentiates/
- s/valid input, auto selected by dpll/input pin auto selected by dpll/
- remove FREERUN and HOLDOVER modes

[03/10] dpll: core: Add DPLL framework base functions
- fix description in spdx header.
- remove refcount check if refcount was already set
- do not validate dpll ptr in dpll_device_put(..)
- fix return -ENOMEM on failed memory alloc
- do not validate pin ptr in dpll_pin_put(..)
- return -EINVAL in case of module/clock_id mismatch
- do not {} around one-line xa_for_each() macro
- move dpll_<x>_registration structs to dpll_core.c
- rephrase doc comment on device and pin id struct members
- remove ref in case of memory allocation fail
- check for required ops on pin/device registration
- mark pin with DPLL_REGISTERED once pin is registered with dpll

[04/10] dpll: netlink: Add DPLL framework base functions
- fix pin-id-get/device-id-get behavior
- reshuffle order of functions
- avoid forward declarations
- functions for adding pin/device handle next to each other
- pass ops callback return values to the user
- remove dpll_cmd_pin_fill_details(..) function, merge the code into
__dpll_cmd_pin_dump_one(..)
- rename __dpll_cmd_pin_dump_one() to dpll_cmd_pin_get_one()
- use WARN_ON macro when dpll ref is missing
- remove redundant pin's dpll list not empty check
- remove double spaces inside if statement
- add extack message when set command is not possible
- do not return error when callback is not required
- WARN_ON missing ops moved to dpll_core.c
- use DPLL_REGISTERED if pin was registered with dpll
- fix pin-id-get return and add extack errors
- fix device-id-get return and add extack errors
- drop pointless init of variables
- add macro for iterating over marked pins/devices
- move dpll_set_from_nlattr() for consistent order
- use GENL_REQ_ATTR_CHECK() for checking attibute presence
- fill extack if pin/device was not found
- drop pointless init of variables
- WARN_ON if dpll not registered on send event
- rename goto labels to indicate error path
- fix docs
- drop pointless init of variables
- verify pin in notify with a mark
- prevent ops->mode_set call if missing callback
- move static dpll_msg_add_pin_handle() from pin<->netdev patch
- split pin-parent nest:
- pin-parent-device - for configuration of pin-device tuple
- pin-parent-pin - for configuration od pin-pin tuple

[06/10] netdev: expose DPLL pin handle for netdevice
- net_device->dpll_pin is only valid if IS_ENABLED(CONFIG_DPLL) fix the
code in net/core/rtnetlink.c to respect that.
- move dpll_msg_add_pin_handle to "dpll: netlink" patch + export the
function with this patch

[07/10] ice: add admin commands to access cgu configuration
- rename MAX_NETLIST_SIZE -> ICE_MAX_NETLIST_SIZE
- simplify function: s64 convert_s48_to_s64(s64 signed_48)
- do not assign 0 to field that is already 0

[08/10] ice: implement dpll interface to control cgu
- drop pointless 0 assignement
- ice_dpll_init(..) returns void instead of int
- fix context description of the functions
- fix ice_dpll_init(..) traces
- fix use package_label instead pf board_label for rclk pin
- be consistent on cgu presence naming
- remove indent in ice_dpll_deinit(..)
- remove unused struct field lock_err_num
- fix kworker resched behavior
- remove debug log from ice_dpll_deinit_worker(..)
- reorder ice internal functions
- release resources directly on error path
- remove redundant NULL checks when releasing resources
- do not assign NULL to pointers after releasing resources
- simplify variable assignement
- fix 'int ret;' declarations across the ice_dpll.c
- remove leftover ice_dpll_find(..)
- get pf pointer from dpll_priv without type cast
- improve error reporting
- fix documentation
- fix ice_dpll_update_state(..) flow
- fix return in case out of range prio set

v7 -> v8:
[0/10] Create common DPLL configuration API
- reorder the patches in patch series
- split patch "[RFC PATCH v7 2/8] dpll: Add DPLL framework base functions"
into 3 smaller patches for easier review:
- [03/10] dpll: core: Add DPLL framework base functions
- [04/10] dpll: netlink: Add DPLL framework base functions
- [05/10] dpll: api header: Add DPLL framework base
- add cli.py usage examples in commit message

[01/10] dpll: documentation on DPLL subsystem interface
- fix DPLL_MODE_MANUAL documentation
- remove DPLL_MODE_NCO
- remove DPLL_LOCK_STATUS_CALIBRATING
- add grepability Use full names of commands, attributes and values of
dpll subsystem in the documentation
- align documentation with changes introduced in v8
- fix typos
- fix phrases to better show the intentions
- move dpll.rst to Documentation/driver-api/

[02/10] dpll: spec: Add Netlink spec in YAML
- remove unspec attribute values
- add 10 KHZ and 77,5 KHZ frequency defines
- fix documentation
- remove assigned values from subset attributes
- reorder dpll attributes
- fix `device` nested attribute usage, device get is not used on pin-get
- temperature with 3 digit float precision
- remove enum from subset definitions
- move pin-direction to pin-dpll tuple/subset
- remove DPLL_MODE_NCO
- remove DPLL_LOCK_STATUS_CALIBRATING
- fix naming scheme od notification interface functions
- separate notifications for pins
- rename attribute enum name: dplla -> dpll_a
- rename pin-idx to pin-id
- remove attributes: pin-parent-idx, device
- replace bus-name and dev-name attributes with module-name
- replace pin-label with 3 new attributes: pin-board-label,
pin-panel-label, pin-package-label
- add device-id-get and pin-id-get commands
- remove rclk-dev-name atribute
- rename DPLL_PIN_DIRECTION_SOURCE -> DPLL_PIN_DIRECTION_INPUT

[03/10] dpll: core: Add DPLL framework base functions
[04/10] dpll: netlink: Add DPLL framework base functions
[05/10] dpll: api header: Add DPLL framework base
- remove unspec attributes after removing from dpll netlink spec
- move pin-direction to pin-dpll tuple
- pass parent_priv on state_on_pin_<get/set>
- align with new notification definitions from netlink spec
- use separated notifications for dpll pins and devices
- format notification messages as corresponding get netlink commands
- rename pin-idx to pin-id
- remove attributes pin-parent-idx, device
- use DPLL_A_PIN_PARENT to hold information on parent pin or dpll device
- refactor lookup for pins and dplls for dpll subsystem
- replace bus-name, dev-name with module-name
- replace pin-label with 3 new attributes: pin-board-label,
pin-panel-label, pin-package-label
- add device-id-get and pin-id-get commands
- rename dpll_xa_lock to dpll_lock
- improve doxygen in dpll_core.c
- remove unused parent and dev fields from dpll_device struct
- use u32 for pin_idx in dpll_pin_alloc
- use driver provided pin properties struct
- verify pin/dpll owner on registering pin
- remove const arg modifier for helper _priv functions
- remove function declaration _get_by_name()
- update SPDX headers
- parse netlink set attributes with nlattr array
- remove rclk-dev-name attribute
- remove device pointer from dpll_pin_register/dpll_device_register
- remove redundant doxygen from dpll header
- use module_name() to get name of module
- add missing/remove outdated kdocs
- fix call frequency_set only if available
- fix call direction_set only for pin-dpll tuple

[06/10] netdev: expose DPLL pin handle for netdevice
- rebased on top of v8 changes
- use dpll_msg_add_pin_handle() in dpll_pin_find_from_nlattr()
and dpll_msg_add_pin_parents()
- fixed handle to use DPLL_A_PIN_ID and removed temporary comments
- added documentation record for dpll_pin pointer
- fixed compilation of net/core/dev.c when CONFIG_DPLL is not enabled
- adjusted patch description a bit

[07/10] ice: add admin commands to access cgu configuration
- Remove unspec attributes after removing from dpll netlink spec.

[08/10] ice: implement dpll interface to control cgu
- remove unspec attributes
- do not store pin flags received in set commands
- use pin state field to provide pin state to the caller
- remove include of uapi header
- remove redundant check against null arguments
- propagate lock function return value to the caller
- use switch case instead of if statements
- fix dev_dbg to dev_err for error cases
- fix dpll/pin lookup on dpll subsytem callbacks
- fix extack of dpll subsystem callbacks
- remove double negation and variable cast
- simplify ice_dpll_pin_state_set function
- pass parent_priv on state_on_pin_<get/set>
- remove parent hw_idx lookup
- fix use const qualifier for dpll/dpll_pin ops
- fix IS_ERR macros usage in ice_dpll
- add notify previous source state change
- fix mutex locking on releasing pins
- use '|=' instead of '+=' when modifing capabilities field
- rename ice_dpll_register_pins function
- clock_id function to return clock ID on the stack instead of using
an output variable
- DPLL_LOCK_STATUS_CALIBRATING was removed, return:
DPLL_LOCK_STATUS_LOCKED - if dpll was locked
DPLL_LOCK_STATUS_LOCKED_HO_ACQ - if dpll was locked and holdover is
acquired
- propagate and use dpll_priv to obtain pf pointer in corresponding
functions.
- remove null check for pf pointer
- adapt to `dpll: core: fix notification scheme`
- expose pf related pin to corresponding netdevice
- fix dpll init error path
- fix dpll pins naming scheme `source` -> `input`
- replace pin-label with pin-board-label
- dpll remove parent and dev fields from dpll_device
- remove device pointer from dpll_pin_register/dpll_device_register
- rename DPLL_PIN_DIRECTION_SOURCE -> DPLL_PIN_DIRECTION_INPUT

[09/10] ptp_ocp: implement DPLL ops
- replace pin-label with pin-board-label
- dpll remove parent and dev fields from dpll_device
- remove device pointer from dpll_pin_register/dpll_device_register
- rename DPLL_PIN_DIRECTION_SOURCE -> DPLL_PIN_DIRECTION_INPUT

[10/10] mlx5: Implement SyncE support using DPLL infrastructure
- rebased on top of v8 changes:
- changed notification scheme
- no need to fill pin label
- implemented locked_ho_acq status
- rename DPLL_PIN_DIRECTION_SOURCE -> DPLL_PIN_DIRECTION_INPUT
- remove device pointer from dpll_pin_register/dpll_device_register
- fixed MSEES register writes
- adjusted pin state and lock state values reported
- fixed a white space issue

v6 -> v7:
* YAML spec:
- remove nested 'pin' attribute
- clean up definitions on top of the latest changes
* pin object:
- pin xarray uses id provided by the driver
- remove usage of PIN_IDX_INVALID in set function
- source_pin_get() returns object instead of idx
- fixes in frequency support API
* device and pin operations are const now
* small fixes in naming in Makefile and in the functions
* single mutex for the subsystem to avoid possible ABBA locks
* no special *_priv() helpers anymore, private data is passed as void*
* no netlink filters by name anymore, only index is supported
* update ptp_ocp and ice drivers to follow new API version
* add mlx5e driver as a new customer of the subsystem
v5 -> v6:
* rework pin part to better fit shared pins use cases
* add YAML spec to easy generate user-space apps
* simple implementation in ptp_ocp is back again
v4 -> v5:
* fix code issues found during last reviews:
- replace cookie with clock id
- follow one naming schema in dpll subsys
- move function comments to dpll_core.c, fix exports
- remove single-use helper functions
- merge device register with alloc
- lock and unlock mutex on dpll device release
- move dpll_type to uapi header
- rename DPLLA_DUMP_FILTER to DPLLA_FILTER
- rename dpll_pin_state to dpll_pin_mode
- rename DPLL_MODE_FORCED to DPLL_MODE_MANUAL
- remove DPLL_CHANGE_PIN_TYPE enum value
* rewrite framework once again (Arkadiusz)
- add clock class:
Provide userspace with clock class value of DPLL with dpll device
dump netlink request. Clock class is assigned by driver allocating
a dpll device. Clock class values are defined as specified in:
ITU-T G.8273.2/Y.1368.2 recommendation.
- dpll device naming schema use new pattern:
"dpll_%s_%d_%d", where:
- %s - dev_name(parent) of parent device,
- %d (1) - enum value of dpll type,
- %d (2) - device index provided by parent device.
- new muxed/shared pin registration:
Let the kernel module to register a shared or muxed pin without
finding it or its parent. Instead use a parent/shared pin
description to find correct pin internally in dpll_core, simplifing
a dpll API
* Implement complex DPLL design in ice driver (Arkadiusz)
* Remove ptp_ocp driver from the series for now
v3 -> v4:
* redesign framework to make pins dynamically allocated (Arkadiusz)
* implement shared pins (Arkadiusz)
v2 -> v3:
* implement source select mode (Arkadiusz)
* add documentation
* implementation improvements (Jakub)
v1 -> v2:
* implement returning supported input/output types
* ptp_ocp: follow suggestions from Jonathan
* add linux-clk mailing list
v0 -> v1:
* fix code style and errors
* add linux-arm mailing list
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+8050 -96
+497
Documentation/driver-api/dpll.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + =============================== 4 + The Linux kernel dpll subsystem 5 + =============================== 6 + 7 + DPLL 8 + ==== 9 + 10 + PLL - Phase Locked Loop is an electronic circuit which syntonizes clock 11 + signal of a device with an external clock signal. Effectively enabling 12 + device to run on the same clock signal beat as provided on a PLL input. 13 + 14 + DPLL - Digital Phase Locked Loop is an integrated circuit which in 15 + addition to plain PLL behavior incorporates a digital phase detector 16 + and may have digital divider in the loop. As a result, the frequency on 17 + DPLL's input and output may be configurable. 18 + 19 + Subsystem 20 + ========= 21 + 22 + The main purpose of dpll subsystem is to provide general interface 23 + to configure devices that use any kind of Digital PLL and could use 24 + different sources of input signal to synchronize to, as well as 25 + different types of outputs. 26 + The main interface is NETLINK_GENERIC based protocol with an event 27 + monitoring multicast group defined. 28 + 29 + Device object 30 + ============= 31 + 32 + Single dpll device object means single Digital PLL circuit and bunch of 33 + connected pins. 34 + It reports the supported modes of operation and current status to the 35 + user in response to the `do` request of netlink command 36 + ``DPLL_CMD_DEVICE_GET`` and list of dplls registered in the subsystem 37 + with `dump` netlink request of the same command. 38 + Changing the configuration of dpll device is done with `do` request of 39 + netlink ``DPLL_CMD_DEVICE_SET`` command. 40 + A device handle is ``DPLL_A_ID``, it shall be provided to get or set 41 + configuration of particular device in the system. It can be obtained 42 + with a ``DPLL_CMD_DEVICE_GET`` `dump` request or 43 + a ``DPLL_CMD_DEVICE_ID_GET`` `do` request, where the one must provide 44 + attributes that result in single device match. 45 + 46 + Pin object 47 + ========== 48 + 49 + A pin is amorphic object which represents either input or output, it 50 + could be internal component of the device, as well as externally 51 + connected. 52 + The number of pins per dpll vary, but usually multiple pins shall be 53 + provided for a single dpll device. 54 + Pin's properties, capabilities and status is provided to the user in 55 + response to `do` request of netlink ``DPLL_CMD_PIN_GET`` command. 56 + It is also possible to list all the pins that were registered in the 57 + system with `dump` request of ``DPLL_CMD_PIN_GET`` command. 58 + Configuration of a pin can be changed by `do` request of netlink 59 + ``DPLL_CMD_PIN_SET`` command. 60 + Pin handle is a ``DPLL_A_PIN_ID``, it shall be provided to get or set 61 + configuration of particular pin in the system. It can be obtained with 62 + ``DPLL_CMD_PIN_GET`` `dump` request or ``DPLL_CMD_PIN_ID_GET`` `do` 63 + request, where user provides attributes that result in single pin match. 64 + 65 + Pin selection 66 + ============= 67 + 68 + In general, selected pin (the one which signal is driving the dpll 69 + device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only 70 + one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll 71 + device. 72 + 73 + Pin selection can be done either manually or automatically, depending 74 + on hardware capabilities and active dpll device work mode 75 + (``DPLL_A_MODE`` attribute). The consequence is that there are 76 + differences for each mode in terms of available pin states, as well as 77 + for the states the user can request for a dpll device. 78 + 79 + In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive 80 + one of following pin states: 81 + 82 + - ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device 83 + - ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll 84 + device 85 + 86 + In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or 87 + receive one of following pin states: 88 + 89 + - ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid 90 + input for automatic selection algorithm 91 + - ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as 92 + a valid input for automatic selection algorithm 93 + 94 + In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive 95 + pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection 96 + algorithm locks a dpll device with one of the inputs. 97 + 98 + Shared pins 99 + =========== 100 + 101 + A single pin object can be attached to multiple dpll devices. 102 + Then there are two groups of configuration knobs: 103 + 104 + 1) Set on a pin - the configuration affects all dpll devices pin is 105 + registered to (i.e., ``DPLL_A_PIN_FREQUENCY``), 106 + 2) Set on a pin-dpll tuple - the configuration affects only selected 107 + dpll device (i.e., ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE``, 108 + ``DPLL_A_PIN_DIRECTION``). 109 + 110 + MUX-type pins 111 + ============= 112 + 113 + A pin can be MUX-type, it aggregates child pins and serves as a pin 114 + multiplexer. One or more pins are registered with MUX-type instead of 115 + being directly registered to a dpll device. 116 + Pins registered with a MUX-type pin provide user with additional nested 117 + attribute ``DPLL_A_PIN_PARENT_PIN`` for each parent they were registered 118 + with. 119 + If a pin was registered with multiple parent pins, they behave like a 120 + multiple output multiplexer. In this case output of a 121 + ``DPLL_CMD_PIN_GET`` would contain multiple pin-parent nested 122 + attributes with current state related to each parent, like: 123 + 124 + 'pin': [{{ 125 + 'clock-id': 282574471561216, 126 + 'module-name': 'ice', 127 + 'capabilities': 4, 128 + 'id': 13, 129 + 'parent-pin': [ 130 + {'parent-id': 2, 'state': 'connected'}, 131 + {'parent-id': 3, 'state': 'disconnected'} 132 + ], 133 + 'type': 'synce-eth-port' 134 + }}] 135 + 136 + Only one child pin can provide its signal to the parent MUX-type pin at 137 + a time, the selection is done by requesting change of a child pin state 138 + on desired parent, with the use of ``DPLL_A_PIN_PARENT`` nested 139 + attribute. Example of netlink `set state on parent pin` message format: 140 + 141 + ========================== ============================================= 142 + ``DPLL_A_PIN_ID`` child pin id 143 + ``DPLL_A_PIN_PARENT_PIN`` nested attribute for requesting configuration 144 + related to parent pin 145 + ``DPLL_A_PIN_PARENT_ID`` parent pin id 146 + ``DPLL_A_PIN_STATE`` requested pin state on parent 147 + ========================== ============================================= 148 + 149 + Pin priority 150 + ============ 151 + 152 + Some devices might offer a capability of automatic pin selection mode 153 + (enum value ``DPLL_MODE_AUTOMATIC`` of ``DPLL_A_MODE`` attribute). 154 + Usually, automatic selection is performed on the hardware level, which 155 + means only pins directly connected to the dpll can be used for automatic 156 + input pin selection. 157 + In automatic selection mode, the user cannot manually select a input 158 + pin for the device, instead the user shall provide all directly 159 + connected pins with a priority ``DPLL_A_PIN_PRIO``, the device would 160 + pick a highest priority valid signal and use it to control the DPLL 161 + device. Example of netlink `set priority on parent pin` message format: 162 + 163 + ============================ ============================================= 164 + ``DPLL_A_PIN_ID`` configured pin id 165 + ``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting configuration 166 + related to parent dpll device 167 + ``DPLL_A_PIN_PARENT_ID`` parent dpll device id 168 + ``DPLL_A_PIN_PRIO`` requested pin prio on parent dpll 169 + ============================ ============================================= 170 + 171 + Child pin of MUX-type pin is not capable of automatic input pin selection, 172 + in order to configure active input of a MUX-type pin, the user needs to 173 + request desired pin state of the child pin on the parent pin, 174 + as described in the ``MUX-type pins`` chapter. 175 + 176 + Configuration commands group 177 + ============================ 178 + 179 + Configuration commands are used to get information about registered 180 + dpll devices (and pins), as well as set configuration of device or pins. 181 + As dpll devices must be abstracted and reflect real hardware, 182 + there is no way to add new dpll device via netlink from user space and 183 + each device should be registered by its driver. 184 + 185 + All netlink commands require ``GENL_ADMIN_PERM``. This is to prevent 186 + any spamming/DoS from unauthorized userspace applications. 187 + 188 + List of netlink commands with possible attributes 189 + ================================================= 190 + 191 + Constants identifying command types for dpll device uses a 192 + ``DPLL_CMD_`` prefix and suffix according to command purpose. 193 + The dpll device related attributes use a ``DPLL_A_`` prefix and 194 + suffix according to attribute purpose. 195 + 196 + ==================================== ================================= 197 + ``DPLL_CMD_DEVICE_ID_GET`` command to get device ID 198 + ``DPLL_A_MODULE_NAME`` attr module name of registerer 199 + ``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier 200 + (EUI-64), as defined by the 201 + IEEE 1588 standard 202 + ``DPLL_A_TYPE`` attr type of dpll device 203 + ==================================== ================================= 204 + 205 + ==================================== ================================= 206 + ``DPLL_CMD_DEVICE_GET`` command to get device info or 207 + dump list of available devices 208 + ``DPLL_A_ID`` attr unique dpll device ID 209 + ``DPLL_A_MODULE_NAME`` attr module name of registerer 210 + ``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier 211 + (EUI-64), as defined by the 212 + IEEE 1588 standard 213 + ``DPLL_A_MODE`` attr selection mode 214 + ``DPLL_A_MODE_SUPPORTED`` attr available selection modes 215 + ``DPLL_A_LOCK_STATUS`` attr dpll device lock status 216 + ``DPLL_A_TEMP`` attr device temperature info 217 + ``DPLL_A_TYPE`` attr type of dpll device 218 + ==================================== ================================= 219 + 220 + ==================================== ================================= 221 + ``DPLL_CMD_DEVICE_SET`` command to set dpll device config 222 + ``DPLL_A_ID`` attr internal dpll device index 223 + ``DPLL_A_MODE`` attr selection mode to configure 224 + ==================================== ================================= 225 + 226 + Constants identifying command types for pins uses a 227 + ``DPLL_CMD_PIN_`` prefix and suffix according to command purpose. 228 + The pin related attributes use a ``DPLL_A_PIN_`` prefix and suffix 229 + according to attribute purpose. 230 + 231 + ==================================== ================================= 232 + ``DPLL_CMD_PIN_ID_GET`` command to get pin ID 233 + ``DPLL_A_PIN_MODULE_NAME`` attr module name of registerer 234 + ``DPLL_A_PIN_CLOCK_ID`` attr Unique Clock Identifier 235 + (EUI-64), as defined by the 236 + IEEE 1588 standard 237 + ``DPLL_A_PIN_BOARD_LABEL`` attr pin board label provided 238 + by registerer 239 + ``DPLL_A_PIN_PANEL_LABEL`` attr pin panel label provided 240 + by registerer 241 + ``DPLL_A_PIN_PACKAGE_LABEL`` attr pin package label provided 242 + by registerer 243 + ``DPLL_A_PIN_TYPE`` attr type of a pin 244 + ==================================== ================================= 245 + 246 + ==================================== ================================== 247 + ``DPLL_CMD_PIN_GET`` command to get pin info or dump 248 + list of available pins 249 + ``DPLL_A_PIN_ID`` attr unique a pin ID 250 + ``DPLL_A_PIN_MODULE_NAME`` attr module name of registerer 251 + ``DPLL_A_PIN_CLOCK_ID`` attr Unique Clock Identifier 252 + (EUI-64), as defined by the 253 + IEEE 1588 standard 254 + ``DPLL_A_PIN_BOARD_LABEL`` attr pin board label provided 255 + by registerer 256 + ``DPLL_A_PIN_PANEL_LABEL`` attr pin panel label provided 257 + by registerer 258 + ``DPLL_A_PIN_PACKAGE_LABEL`` attr pin package label provided 259 + by registerer 260 + ``DPLL_A_PIN_TYPE`` attr type of a pin 261 + ``DPLL_A_PIN_FREQUENCY`` attr current frequency of a pin 262 + ``DPLL_A_PIN_FREQUENCY_SUPPORTED`` nested attr provides supported 263 + frequencies 264 + ``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency 265 + ``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency 266 + ``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent device 267 + the pin is connected with 268 + ``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id 269 + ``DPLL_A_PIN_PRIO`` attr priority of pin on the 270 + dpll device 271 + ``DPLL_A_PIN_STATE`` attr state of pin on the parent 272 + dpll device 273 + ``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the 274 + parent dpll device 275 + ``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin 276 + the pin is connected with 277 + ``DPLL_A_PIN_PARENT_ID`` attr parent pin id 278 + ``DPLL_A_PIN_STATE`` attr state of pin on the parent 279 + pin 280 + ``DPLL_A_PIN_CAPABILITIES`` attr bitmask of pin capabilities 281 + ==================================== ================================== 282 + 283 + ==================================== ================================= 284 + ``DPLL_CMD_PIN_SET`` command to set pins configuration 285 + ``DPLL_A_PIN_ID`` attr unique a pin ID 286 + ``DPLL_A_PIN_FREQUENCY`` attr requested frequency of a pin 287 + ``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent dpll 288 + device configuration request 289 + ``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id 290 + ``DPLL_A_PIN_DIRECTION`` attr requested direction of a pin 291 + ``DPLL_A_PIN_PRIO`` attr requested priority of pin on 292 + the dpll device 293 + ``DPLL_A_PIN_STATE`` attr requested state of pin on 294 + the dpll device 295 + ``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin 296 + configuration request 297 + ``DPLL_A_PIN_PARENT_ID`` attr parent pin id 298 + ``DPLL_A_PIN_STATE`` attr requested state of pin on 299 + parent pin 300 + ==================================== ================================= 301 + 302 + Netlink dump requests 303 + ===================== 304 + 305 + The ``DPLL_CMD_DEVICE_GET`` and ``DPLL_CMD_PIN_GET`` commands are 306 + capable of dump type netlink requests, in which case the response is in 307 + the same format as for their ``do`` request, but every device or pin 308 + registered in the system is returned. 309 + 310 + SET commands format 311 + =================== 312 + 313 + ``DPLL_CMD_DEVICE_SET`` - to target a dpll device, the user provides 314 + ``DPLL_A_ID``, which is unique identifier of dpll device in the system, 315 + as well as parameter being configured (``DPLL_A_MODE``). 316 + 317 + ``DPLL_CMD_PIN_SET`` - to target a pin user must provide a 318 + ``DPLL_A_PIN_ID``, which is unique identifier of a pin in the system. 319 + Also configured pin parameters must be added. 320 + If ``DPLL_A_PIN_FREQUENCY`` is configured, this affects all the dpll 321 + devices that are connected with the pin, that is why frequency attribute 322 + shall not be enclosed in ``DPLL_A_PIN_PARENT_DEVICE``. 323 + Other attributes: ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE`` or 324 + ``DPLL_A_PIN_DIRECTION`` must be enclosed in 325 + ``DPLL_A_PIN_PARENT_DEVICE`` as their configuration relates to only one 326 + of parent dplls, targeted by ``DPLL_A_PIN_PARENT_ID`` attribute which is 327 + also required inside that nest. 328 + For MUX-type pins the ``DPLL_A_PIN_STATE`` attribute is configured in 329 + similar way, by enclosing required state in ``DPLL_A_PIN_PARENT_PIN`` 330 + nested attribute and targeted parent pin id in ``DPLL_A_PIN_PARENT_ID``. 331 + 332 + In general, it is possible to configure multiple parameters at once, but 333 + internally each parameter change will be invoked separately, where order 334 + of configuration is not guaranteed by any means. 335 + 336 + Configuration pre-defined enums 337 + =============================== 338 + 339 + .. kernel-doc:: include/uapi/linux/dpll.h 340 + 341 + Notifications 342 + ============= 343 + 344 + dpll device can provide notifications regarding status changes of the 345 + device, i.e. lock status changes, input/output changes or other alarms. 346 + There is one multicast group that is used to notify user-space apps via 347 + netlink socket: ``DPLL_MCGRP_MONITOR`` 348 + 349 + Notifications messages: 350 + 351 + ============================== ===================================== 352 + ``DPLL_CMD_DEVICE_CREATE_NTF`` dpll device was created 353 + ``DPLL_CMD_DEVICE_DELETE_NTF`` dpll device was deleted 354 + ``DPLL_CMD_DEVICE_CHANGE_NTF`` dpll device has changed 355 + ``DPLL_CMD_PIN_CREATE_NTF`` dpll pin was created 356 + ``DPLL_CMD_PIN_DELETE_NTF`` dpll pin was deleted 357 + ``DPLL_CMD_PIN_CHANGE_NTF`` dpll pin has changed 358 + ============================== ===================================== 359 + 360 + Events format is the same as for the corresponding get command. 361 + Format of ``DPLL_CMD_DEVICE_`` events is the same as response of 362 + ``DPLL_CMD_DEVICE_GET``. 363 + Format of ``DPLL_CMD_PIN_`` events is same as response of 364 + ``DPLL_CMD_PIN_GET``. 365 + 366 + Device driver implementation 367 + ============================ 368 + 369 + Device is allocated by dpll_device_get() call. Second call with the 370 + same arguments will not create new object but provides pointer to 371 + previously created device for given arguments, it also increases 372 + refcount of that object. 373 + Device is deallocated by dpll_device_put() call, which first 374 + decreases the refcount, once refcount is cleared the object is 375 + destroyed. 376 + 377 + Device should implement set of operations and register device via 378 + dpll_device_register() at which point it becomes available to the 379 + users. Multiple driver instances can obtain reference to it with 380 + dpll_device_get(), as well as register dpll device with their own 381 + ops and priv. 382 + 383 + The pins are allocated separately with dpll_pin_get(), it works 384 + similarly to dpll_device_get(). Function first creates object and then 385 + for each call with the same arguments only the object refcount 386 + increases. Also dpll_pin_put() works similarly to dpll_device_put(). 387 + 388 + A pin can be registered with parent dpll device or parent pin, depending 389 + on hardware needs. Each registration requires registerer to provide set 390 + of pin callbacks, and private data pointer for calling them: 391 + 392 + - dpll_pin_register() - register pin with a dpll device, 393 + - dpll_pin_on_pin_register() - register pin with another MUX type pin. 394 + 395 + Notifications of adding or removing dpll devices are created within 396 + subsystem itself. 397 + Notifications about registering/deregistering pins are also invoked by 398 + the subsystem. 399 + Notifications about status changes either of dpll device or a pin are 400 + invoked in two ways: 401 + 402 + - after successful change was requested on dpll subsystem, the subsystem 403 + calls corresponding notification, 404 + - requested by device driver with dpll_device_change_ntf() or 405 + dpll_pin_change_ntf() when driver informs about the status change. 406 + 407 + The device driver using dpll interface is not required to implement all 408 + the callback operation. Nevertheless, there are few required to be 409 + implemented. 410 + Required dpll device level callback operations: 411 + 412 + - ``.mode_get``, 413 + - ``.lock_status_get``. 414 + 415 + Required pin level callback operations: 416 + 417 + - ``.state_on_dpll_get`` (pins registered with dpll device), 418 + - ``.state_on_pin_get`` (pins registered with parent pin), 419 + - ``.direction_get``. 420 + 421 + Every other operation handler is checked for existence and 422 + ``-EOPNOTSUPP`` is returned in case of absence of specific handler. 423 + 424 + The simplest implementation is in the OCP TimeCard driver. The ops 425 + structures are defined like this: 426 + 427 + .. code-block:: c 428 + static const struct dpll_device_ops dpll_ops = { 429 + .lock_status_get = ptp_ocp_dpll_lock_status_get, 430 + .mode_get = ptp_ocp_dpll_mode_get, 431 + .mode_supported = ptp_ocp_dpll_mode_supported, 432 + }; 433 + 434 + static const struct dpll_pin_ops dpll_pins_ops = { 435 + .frequency_get = ptp_ocp_dpll_frequency_get, 436 + .frequency_set = ptp_ocp_dpll_frequency_set, 437 + .direction_get = ptp_ocp_dpll_direction_get, 438 + .direction_set = ptp_ocp_dpll_direction_set, 439 + .state_on_dpll_get = ptp_ocp_dpll_state_get, 440 + }; 441 + 442 + The registration part is then looks like this part: 443 + 444 + .. code-block:: c 445 + clkid = pci_get_dsn(pdev); 446 + bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE); 447 + if (IS_ERR(bp->dpll)) { 448 + err = PTR_ERR(bp->dpll); 449 + dev_err(&pdev->dev, "dpll_device_alloc failed\n"); 450 + goto out; 451 + } 452 + 453 + err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp); 454 + if (err) 455 + goto out; 456 + 457 + for (i = 0; i < OCP_SMA_NUM; i++) { 458 + bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].dpll_prop); 459 + if (IS_ERR(bp->sma[i].dpll_pin)) { 460 + err = PTR_ERR(bp->dpll); 461 + goto out_dpll; 462 + } 463 + 464 + err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, 465 + &bp->sma[i]); 466 + if (err) { 467 + dpll_pin_put(bp->sma[i].dpll_pin); 468 + goto out_dpll; 469 + } 470 + } 471 + 472 + In the error path we have to rewind every allocation in the reverse order: 473 + 474 + .. code-block:: c 475 + while (i) { 476 + --i; 477 + dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]); 478 + dpll_pin_put(bp->sma[i].dpll_pin); 479 + } 480 + dpll_device_put(bp->dpll); 481 + 482 + More complex example can be found in Intel's ICE driver or nVidia's mlx5 driver. 483 + 484 + SyncE enablement 485 + ================ 486 + For SyncE enablement it is required to allow control over dpll device 487 + for a software application which monitors and configures the inputs of 488 + dpll device in response to current state of a dpll device and its 489 + inputs. 490 + In such scenario, dpll device input signal shall be also configurable 491 + to drive dpll with signal recovered from the PHY netdevice. 492 + This is done by exposing a pin to the netdevice - attaching pin to the 493 + netdevice itself with 494 + ``netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)``. 495 + Exposed pin id handle ``DPLL_A_PIN_ID`` is then identifiable by the user 496 + as it is attached to rtnetlink respond to get ``RTM_NEWLINK`` command in 497 + nested attribute ``IFLA_DPLL_PIN``.
+1
Documentation/driver-api/index.rst
··· 114 114 zorro 115 115 hte/index 116 116 wmi 117 + dpll 117 118 118 119 .. only:: subproject and html 119 120
+488
Documentation/netlink/specs/dpll.yaml
··· 1 + # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 + 3 + name: dpll 4 + 5 + doc: DPLL subsystem. 6 + 7 + definitions: 8 + - 9 + type: enum 10 + name: mode 11 + doc: | 12 + working modes a dpll can support, differentiates if and how dpll selects 13 + one of its inputs to syntonize with it, valid values for DPLL_A_MODE 14 + attribute 15 + entries: 16 + - 17 + name: manual 18 + doc: input can be only selected by sending a request to dpll 19 + value: 1 20 + - 21 + name: automatic 22 + doc: highest prio input pin auto selected by dpll 23 + render-max: true 24 + - 25 + type: enum 26 + name: lock-status 27 + doc: | 28 + provides information of dpll device lock status, valid values for 29 + DPLL_A_LOCK_STATUS attribute 30 + entries: 31 + - 32 + name: unlocked 33 + doc: | 34 + dpll was not yet locked to any valid input (or forced by setting 35 + DPLL_A_MODE to DPLL_MODE_DETACHED) 36 + value: 1 37 + - 38 + name: locked 39 + doc: | 40 + dpll is locked to a valid signal, but no holdover available 41 + - 42 + name: locked-ho-acq 43 + doc: | 44 + dpll is locked and holdover acquired 45 + - 46 + name: holdover 47 + doc: | 48 + dpll is in holdover state - lost a valid lock or was forced 49 + by disconnecting all the pins (latter possible only 50 + when dpll lock-state was already DPLL_LOCK_STATUS_LOCKED_HO_ACQ, 51 + if dpll lock-state was not DPLL_LOCK_STATUS_LOCKED_HO_ACQ, the 52 + dpll's lock-state shall remain DPLL_LOCK_STATUS_UNLOCKED) 53 + render-max: true 54 + - 55 + type: const 56 + name: temp-divider 57 + value: 1000 58 + doc: | 59 + temperature divider allowing userspace to calculate the 60 + temperature as float with three digit decimal precision. 61 + Value of (DPLL_A_TEMP / DPLL_TEMP_DIVIDER) is integer part of 62 + temperature value. 63 + Value of (DPLL_A_TEMP % DPLL_TEMP_DIVIDER) is fractional part of 64 + temperature value. 65 + - 66 + type: enum 67 + name: type 68 + doc: type of dpll, valid values for DPLL_A_TYPE attribute 69 + entries: 70 + - 71 + name: pps 72 + doc: dpll produces Pulse-Per-Second signal 73 + value: 1 74 + - 75 + name: eec 76 + doc: dpll drives the Ethernet Equipment Clock 77 + render-max: true 78 + - 79 + type: enum 80 + name: pin-type 81 + doc: | 82 + defines possible types of a pin, valid values for DPLL_A_PIN_TYPE 83 + attribute 84 + entries: 85 + - 86 + name: mux 87 + doc: aggregates another layer of selectable pins 88 + value: 1 89 + - 90 + name: ext 91 + doc: external input 92 + - 93 + name: synce-eth-port 94 + doc: ethernet port PHY's recovered clock 95 + - 96 + name: int-oscillator 97 + doc: device internal oscillator 98 + - 99 + name: gnss 100 + doc: GNSS recovered clock 101 + render-max: true 102 + - 103 + type: enum 104 + name: pin-direction 105 + doc: | 106 + defines possible direction of a pin, valid values for 107 + DPLL_A_PIN_DIRECTION attribute 108 + entries: 109 + - 110 + name: input 111 + doc: pin used as a input of a signal 112 + value: 1 113 + - 114 + name: output 115 + doc: pin used to output the signal 116 + render-max: true 117 + - 118 + type: const 119 + name: pin-frequency-1-hz 120 + value: 1 121 + - 122 + type: const 123 + name: pin-frequency-10-khz 124 + value: 10000 125 + - 126 + type: const 127 + name: pin-frequency-77_5-khz 128 + value: 77500 129 + - 130 + type: const 131 + name: pin-frequency-10-mhz 132 + value: 10000000 133 + - 134 + type: enum 135 + name: pin-state 136 + doc: | 137 + defines possible states of a pin, valid values for 138 + DPLL_A_PIN_STATE attribute 139 + entries: 140 + - 141 + name: connected 142 + doc: pin connected, active input of phase locked loop 143 + value: 1 144 + - 145 + name: disconnected 146 + doc: pin disconnected, not considered as a valid input 147 + - 148 + name: selectable 149 + doc: pin enabled for automatic input selection 150 + render-max: true 151 + - 152 + type: flags 153 + name: pin-capabilities 154 + doc: | 155 + defines possible capabilities of a pin, valid flags on 156 + DPLL_A_PIN_CAPABILITIES attribute 157 + entries: 158 + - 159 + name: direction-can-change 160 + doc: pin direction can be changed 161 + - 162 + name: priority-can-change 163 + doc: pin priority can be changed 164 + - 165 + name: state-can-change 166 + doc: pin state can be changed 167 + 168 + attribute-sets: 169 + - 170 + name: dpll 171 + enum-name: dpll_a 172 + attributes: 173 + - 174 + name: id 175 + type: u32 176 + - 177 + name: module-name 178 + type: string 179 + - 180 + name: pad 181 + type: pad 182 + - 183 + name: clock-id 184 + type: u64 185 + - 186 + name: mode 187 + type: u32 188 + enum: mode 189 + - 190 + name: mode-supported 191 + type: u32 192 + enum: mode 193 + multi-attr: true 194 + - 195 + name: lock-status 196 + type: u32 197 + enum: lock-status 198 + - 199 + name: temp 200 + type: s32 201 + - 202 + name: type 203 + type: u32 204 + enum: type 205 + - 206 + name: pin 207 + enum-name: dpll_a_pin 208 + attributes: 209 + - 210 + name: id 211 + type: u32 212 + - 213 + name: parent-id 214 + type: u32 215 + - 216 + name: module-name 217 + type: string 218 + - 219 + name: pad 220 + type: pad 221 + - 222 + name: clock-id 223 + type: u64 224 + - 225 + name: board-label 226 + type: string 227 + - 228 + name: panel-label 229 + type: string 230 + - 231 + name: package-label 232 + type: string 233 + - 234 + name: type 235 + type: u32 236 + enum: pin-type 237 + - 238 + name: direction 239 + type: u32 240 + enum: pin-direction 241 + - 242 + name: frequency 243 + type: u64 244 + - 245 + name: frequency-supported 246 + type: nest 247 + multi-attr: true 248 + nested-attributes: frequency-range 249 + - 250 + name: frequency-min 251 + type: u64 252 + - 253 + name: frequency-max 254 + type: u64 255 + - 256 + name: prio 257 + type: u32 258 + - 259 + name: state 260 + type: u32 261 + enum: pin-state 262 + - 263 + name: capabilities 264 + type: u32 265 + - 266 + name: parent-device 267 + type: nest 268 + multi-attr: true 269 + nested-attributes: pin-parent-device 270 + - 271 + name: parent-pin 272 + type: nest 273 + multi-attr: true 274 + nested-attributes: pin-parent-pin 275 + - 276 + name: pin-parent-device 277 + subset-of: pin 278 + attributes: 279 + - 280 + name: parent-id 281 + type: u32 282 + - 283 + name: direction 284 + type: u32 285 + - 286 + name: prio 287 + type: u32 288 + - 289 + name: state 290 + type: u32 291 + - 292 + name: pin-parent-pin 293 + subset-of: pin 294 + attributes: 295 + - 296 + name: parent-id 297 + type: u32 298 + - 299 + name: state 300 + type: u32 301 + - 302 + name: frequency-range 303 + subset-of: pin 304 + attributes: 305 + - 306 + name: frequency-min 307 + type: u64 308 + - 309 + name: frequency-max 310 + type: u64 311 + 312 + operations: 313 + enum-name: dpll_cmd 314 + list: 315 + - 316 + name: device-id-get 317 + doc: | 318 + Get id of dpll device that matches given attributes 319 + attribute-set: dpll 320 + flags: [ admin-perm ] 321 + 322 + do: 323 + pre: dpll-lock-doit 324 + post: dpll-unlock-doit 325 + request: 326 + attributes: 327 + - module-name 328 + - clock-id 329 + - type 330 + reply: 331 + attributes: 332 + - id 333 + 334 + - 335 + name: device-get 336 + doc: | 337 + Get list of DPLL devices (dump) or attributes of a single dpll device 338 + attribute-set: dpll 339 + flags: [ admin-perm ] 340 + 341 + do: 342 + pre: dpll-pre-doit 343 + post: dpll-post-doit 344 + request: 345 + attributes: 346 + - id 347 + reply: &dev-attrs 348 + attributes: 349 + - id 350 + - module-name 351 + - mode 352 + - mode-supported 353 + - lock-status 354 + - temp 355 + - clock-id 356 + - type 357 + 358 + dump: 359 + pre: dpll-lock-dumpit 360 + post: dpll-unlock-dumpit 361 + reply: *dev-attrs 362 + 363 + - 364 + name: device-set 365 + doc: Set attributes for a DPLL device 366 + attribute-set: dpll 367 + flags: [ admin-perm ] 368 + 369 + do: 370 + pre: dpll-pre-doit 371 + post: dpll-post-doit 372 + request: 373 + attributes: 374 + - id 375 + - 376 + name: device-create-ntf 377 + doc: Notification about device appearing 378 + notify: device-get 379 + mcgrp: monitor 380 + - 381 + name: device-delete-ntf 382 + doc: Notification about device disappearing 383 + notify: device-get 384 + mcgrp: monitor 385 + - 386 + name: device-change-ntf 387 + doc: Notification about device configuration being changed 388 + notify: device-get 389 + mcgrp: monitor 390 + - 391 + name: pin-id-get 392 + doc: | 393 + Get id of a pin that matches given attributes 394 + attribute-set: pin 395 + flags: [ admin-perm ] 396 + 397 + do: 398 + pre: dpll-lock-doit 399 + post: dpll-unlock-doit 400 + request: 401 + attributes: 402 + - module-name 403 + - clock-id 404 + - board-label 405 + - panel-label 406 + - package-label 407 + - type 408 + reply: 409 + attributes: 410 + - id 411 + 412 + - 413 + name: pin-get 414 + doc: | 415 + Get list of pins and its attributes. 416 + - dump request without any attributes given - list all the pins in the 417 + system 418 + - dump request with target dpll - list all the pins registered with 419 + a given dpll device 420 + - do request with target dpll and target pin - single pin attributes 421 + attribute-set: pin 422 + flags: [ admin-perm ] 423 + 424 + do: 425 + pre: dpll-pin-pre-doit 426 + post: dpll-pin-post-doit 427 + request: 428 + attributes: 429 + - id 430 + reply: &pin-attrs 431 + attributes: 432 + - id 433 + - board-label 434 + - panel-label 435 + - package-label 436 + - type 437 + - frequency 438 + - frequency-supported 439 + - capabilities 440 + - parent-device 441 + - parent-pin 442 + 443 + dump: 444 + pre: dpll-lock-dumpit 445 + post: dpll-unlock-dumpit 446 + request: 447 + attributes: 448 + - id 449 + reply: *pin-attrs 450 + 451 + - 452 + name: pin-set 453 + doc: Set attributes of a target pin 454 + attribute-set: pin 455 + flags: [ admin-perm ] 456 + 457 + do: 458 + pre: dpll-pin-pre-doit 459 + post: dpll-pin-post-doit 460 + request: 461 + attributes: 462 + - id 463 + - frequency 464 + - direction 465 + - prio 466 + - state 467 + - parent-device 468 + - parent-pin 469 + - 470 + name: pin-create-ntf 471 + doc: Notification about pin appearing 472 + notify: pin-get 473 + mcgrp: monitor 474 + - 475 + name: pin-delete-ntf 476 + doc: Notification about pin disappearing 477 + notify: pin-get 478 + mcgrp: monitor 479 + - 480 + name: pin-change-ntf 481 + doc: Notification about pin configuration being changed 482 + notify: pin-get 483 + mcgrp: monitor 484 + 485 + mcast-groups: 486 + list: 487 + - 488 + name: monitor
+11
MAINTAINERS
··· 6333 6333 F: drivers/net/ethernet/freescale/dpaa2/dpaa2-switch* 6334 6334 F: drivers/net/ethernet/freescale/dpaa2/dpsw* 6335 6335 6336 + DPLL SUBSYSTEM 6337 + M: Vadim Fedorenko <vadim.fedorenko@linux.dev> 6338 + M: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com> 6339 + M: Jiri Pirko <jiri@resnulli.us> 6340 + L: netdev@vger.kernel.org 6341 + S: Supported 6342 + F: Documentation/driver-api/dpll.rst 6343 + F: drivers/dpll/* 6344 + F: include/net/dpll.h 6345 + F: include/uapi/linux/dpll.h 6346 + 6336 6347 DRBD DRIVER 6337 6348 M: Philipp Reisner <philipp.reisner@linbit.com> 6338 6349 M: Lars Ellenberg <lars.ellenberg@linbit.com>
+2
drivers/Kconfig
··· 243 243 244 244 source "drivers/cdx/Kconfig" 245 245 246 + source "drivers/dpll/Kconfig" 247 + 246 248 endmenu
+1
drivers/Makefile
··· 197 197 obj-$(CONFIG_HTE) += hte/ 198 198 obj-$(CONFIG_DRM_ACCEL) += accel/ 199 199 obj-$(CONFIG_CDX_BUS) += cdx/ 200 + obj-$(CONFIG_DPLL) += dpll/ 200 201 201 202 obj-$(CONFIG_S390) += s390/
+7
drivers/dpll/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # Generic DPLL drivers configuration 4 + # 5 + 6 + config DPLL 7 + bool
+9
drivers/dpll/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Makefile for DPLL drivers. 4 + # 5 + 6 + obj-$(CONFIG_DPLL) += dpll.o 7 + dpll-y += dpll_core.o 8 + dpll-y += dpll_netlink.o 9 + dpll-y += dpll_nl.o
+798
drivers/dpll/dpll_core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * dpll_core.c - DPLL subsystem kernel-space interface implementation. 4 + * 5 + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates 6 + * Copyright (c) 2023 Intel Corporation. 7 + */ 8 + 9 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 + 11 + #include <linux/device.h> 12 + #include <linux/err.h> 13 + #include <linux/slab.h> 14 + #include <linux/string.h> 15 + 16 + #include "dpll_core.h" 17 + #include "dpll_netlink.h" 18 + 19 + /* Mutex lock to protect DPLL subsystem devices and pins */ 20 + DEFINE_MUTEX(dpll_lock); 21 + 22 + DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); 23 + DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC); 24 + 25 + static u32 dpll_xa_id; 26 + 27 + #define ASSERT_DPLL_REGISTERED(d) \ 28 + WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) 29 + #define ASSERT_DPLL_NOT_REGISTERED(d) \ 30 + WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) 31 + #define ASSERT_PIN_REGISTERED(p) \ 32 + WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED)) 33 + 34 + struct dpll_device_registration { 35 + struct list_head list; 36 + const struct dpll_device_ops *ops; 37 + void *priv; 38 + }; 39 + 40 + struct dpll_pin_registration { 41 + struct list_head list; 42 + const struct dpll_pin_ops *ops; 43 + void *priv; 44 + }; 45 + 46 + struct dpll_device *dpll_device_get_by_id(int id) 47 + { 48 + if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED)) 49 + return xa_load(&dpll_device_xa, id); 50 + 51 + return NULL; 52 + } 53 + 54 + static struct dpll_pin_registration * 55 + dpll_pin_registration_find(struct dpll_pin_ref *ref, 56 + const struct dpll_pin_ops *ops, void *priv) 57 + { 58 + struct dpll_pin_registration *reg; 59 + 60 + list_for_each_entry(reg, &ref->registration_list, list) { 61 + if (reg->ops == ops && reg->priv == priv) 62 + return reg; 63 + } 64 + return NULL; 65 + } 66 + 67 + static int 68 + dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin, 69 + const struct dpll_pin_ops *ops, void *priv) 70 + { 71 + struct dpll_pin_registration *reg; 72 + struct dpll_pin_ref *ref; 73 + bool ref_exists = false; 74 + unsigned long i; 75 + int ret; 76 + 77 + xa_for_each(xa_pins, i, ref) { 78 + if (ref->pin != pin) 79 + continue; 80 + reg = dpll_pin_registration_find(ref, ops, priv); 81 + if (reg) { 82 + refcount_inc(&ref->refcount); 83 + return 0; 84 + } 85 + ref_exists = true; 86 + break; 87 + } 88 + 89 + if (!ref_exists) { 90 + ref = kzalloc(sizeof(*ref), GFP_KERNEL); 91 + if (!ref) 92 + return -ENOMEM; 93 + ref->pin = pin; 94 + INIT_LIST_HEAD(&ref->registration_list); 95 + ret = xa_insert(xa_pins, pin->pin_idx, ref, GFP_KERNEL); 96 + if (ret) { 97 + kfree(ref); 98 + return ret; 99 + } 100 + refcount_set(&ref->refcount, 1); 101 + } 102 + 103 + reg = kzalloc(sizeof(*reg), GFP_KERNEL); 104 + if (!reg) { 105 + if (!ref_exists) { 106 + xa_erase(xa_pins, pin->pin_idx); 107 + kfree(ref); 108 + } 109 + return -ENOMEM; 110 + } 111 + reg->ops = ops; 112 + reg->priv = priv; 113 + if (ref_exists) 114 + refcount_inc(&ref->refcount); 115 + list_add_tail(&reg->list, &ref->registration_list); 116 + 117 + return 0; 118 + } 119 + 120 + static int dpll_xa_ref_pin_del(struct xarray *xa_pins, struct dpll_pin *pin, 121 + const struct dpll_pin_ops *ops, void *priv) 122 + { 123 + struct dpll_pin_registration *reg; 124 + struct dpll_pin_ref *ref; 125 + unsigned long i; 126 + 127 + xa_for_each(xa_pins, i, ref) { 128 + if (ref->pin != pin) 129 + continue; 130 + reg = dpll_pin_registration_find(ref, ops, priv); 131 + if (WARN_ON(!reg)) 132 + return -EINVAL; 133 + if (refcount_dec_and_test(&ref->refcount)) { 134 + list_del(&reg->list); 135 + kfree(reg); 136 + xa_erase(xa_pins, i); 137 + WARN_ON(!list_empty(&ref->registration_list)); 138 + kfree(ref); 139 + } 140 + return 0; 141 + } 142 + 143 + return -EINVAL; 144 + } 145 + 146 + static int 147 + dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll, 148 + const struct dpll_pin_ops *ops, void *priv) 149 + { 150 + struct dpll_pin_registration *reg; 151 + struct dpll_pin_ref *ref; 152 + bool ref_exists = false; 153 + unsigned long i; 154 + int ret; 155 + 156 + xa_for_each(xa_dplls, i, ref) { 157 + if (ref->dpll != dpll) 158 + continue; 159 + reg = dpll_pin_registration_find(ref, ops, priv); 160 + if (reg) { 161 + refcount_inc(&ref->refcount); 162 + return 0; 163 + } 164 + ref_exists = true; 165 + break; 166 + } 167 + 168 + if (!ref_exists) { 169 + ref = kzalloc(sizeof(*ref), GFP_KERNEL); 170 + if (!ref) 171 + return -ENOMEM; 172 + ref->dpll = dpll; 173 + INIT_LIST_HEAD(&ref->registration_list); 174 + ret = xa_insert(xa_dplls, dpll->id, ref, GFP_KERNEL); 175 + if (ret) { 176 + kfree(ref); 177 + return ret; 178 + } 179 + refcount_set(&ref->refcount, 1); 180 + } 181 + 182 + reg = kzalloc(sizeof(*reg), GFP_KERNEL); 183 + if (!reg) { 184 + if (!ref_exists) { 185 + xa_erase(xa_dplls, dpll->id); 186 + kfree(ref); 187 + } 188 + return -ENOMEM; 189 + } 190 + reg->ops = ops; 191 + reg->priv = priv; 192 + if (ref_exists) 193 + refcount_inc(&ref->refcount); 194 + list_add_tail(&reg->list, &ref->registration_list); 195 + 196 + return 0; 197 + } 198 + 199 + static void 200 + dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll, 201 + const struct dpll_pin_ops *ops, void *priv) 202 + { 203 + struct dpll_pin_registration *reg; 204 + struct dpll_pin_ref *ref; 205 + unsigned long i; 206 + 207 + xa_for_each(xa_dplls, i, ref) { 208 + if (ref->dpll != dpll) 209 + continue; 210 + reg = dpll_pin_registration_find(ref, ops, priv); 211 + if (WARN_ON(!reg)) 212 + return; 213 + if (refcount_dec_and_test(&ref->refcount)) { 214 + list_del(&reg->list); 215 + kfree(reg); 216 + xa_erase(xa_dplls, i); 217 + WARN_ON(!list_empty(&ref->registration_list)); 218 + kfree(ref); 219 + } 220 + return; 221 + } 222 + } 223 + 224 + struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs) 225 + { 226 + struct dpll_pin_ref *ref; 227 + unsigned long i = 0; 228 + 229 + ref = xa_find(xa_refs, &i, ULONG_MAX, XA_PRESENT); 230 + WARN_ON(!ref); 231 + return ref; 232 + } 233 + 234 + static struct dpll_device * 235 + dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module) 236 + { 237 + struct dpll_device *dpll; 238 + int ret; 239 + 240 + dpll = kzalloc(sizeof(*dpll), GFP_KERNEL); 241 + if (!dpll) 242 + return ERR_PTR(-ENOMEM); 243 + refcount_set(&dpll->refcount, 1); 244 + INIT_LIST_HEAD(&dpll->registration_list); 245 + dpll->device_idx = device_idx; 246 + dpll->clock_id = clock_id; 247 + dpll->module = module; 248 + ret = xa_alloc_cyclic(&dpll_device_xa, &dpll->id, dpll, xa_limit_32b, 249 + &dpll_xa_id, GFP_KERNEL); 250 + if (ret < 0) { 251 + kfree(dpll); 252 + return ERR_PTR(ret); 253 + } 254 + xa_init_flags(&dpll->pin_refs, XA_FLAGS_ALLOC); 255 + 256 + return dpll; 257 + } 258 + 259 + /** 260 + * dpll_device_get - find existing or create new dpll device 261 + * @clock_id: clock_id of creator 262 + * @device_idx: idx given by device driver 263 + * @module: reference to registering module 264 + * 265 + * Get existing object of a dpll device, unique for given arguments. 266 + * Create new if doesn't exist yet. 267 + * 268 + * Context: Acquires a lock (dpll_lock) 269 + * Return: 270 + * * valid dpll_device struct pointer if succeeded 271 + * * ERR_PTR(X) - error 272 + */ 273 + struct dpll_device * 274 + dpll_device_get(u64 clock_id, u32 device_idx, struct module *module) 275 + { 276 + struct dpll_device *dpll, *ret = NULL; 277 + unsigned long index; 278 + 279 + mutex_lock(&dpll_lock); 280 + xa_for_each(&dpll_device_xa, index, dpll) { 281 + if (dpll->clock_id == clock_id && 282 + dpll->device_idx == device_idx && 283 + dpll->module == module) { 284 + ret = dpll; 285 + refcount_inc(&ret->refcount); 286 + break; 287 + } 288 + } 289 + if (!ret) 290 + ret = dpll_device_alloc(clock_id, device_idx, module); 291 + mutex_unlock(&dpll_lock); 292 + 293 + return ret; 294 + } 295 + EXPORT_SYMBOL_GPL(dpll_device_get); 296 + 297 + /** 298 + * dpll_device_put - decrease the refcount and free memory if possible 299 + * @dpll: dpll_device struct pointer 300 + * 301 + * Context: Acquires a lock (dpll_lock) 302 + * Drop reference for a dpll device, if all references are gone, delete 303 + * dpll device object. 304 + */ 305 + void dpll_device_put(struct dpll_device *dpll) 306 + { 307 + mutex_lock(&dpll_lock); 308 + if (refcount_dec_and_test(&dpll->refcount)) { 309 + ASSERT_DPLL_NOT_REGISTERED(dpll); 310 + WARN_ON_ONCE(!xa_empty(&dpll->pin_refs)); 311 + xa_destroy(&dpll->pin_refs); 312 + xa_erase(&dpll_device_xa, dpll->id); 313 + WARN_ON(!list_empty(&dpll->registration_list)); 314 + kfree(dpll); 315 + } 316 + mutex_unlock(&dpll_lock); 317 + } 318 + EXPORT_SYMBOL_GPL(dpll_device_put); 319 + 320 + static struct dpll_device_registration * 321 + dpll_device_registration_find(struct dpll_device *dpll, 322 + const struct dpll_device_ops *ops, void *priv) 323 + { 324 + struct dpll_device_registration *reg; 325 + 326 + list_for_each_entry(reg, &dpll->registration_list, list) { 327 + if (reg->ops == ops && reg->priv == priv) 328 + return reg; 329 + } 330 + return NULL; 331 + } 332 + 333 + /** 334 + * dpll_device_register - register the dpll device in the subsystem 335 + * @dpll: pointer to a dpll 336 + * @type: type of a dpll 337 + * @ops: ops for a dpll device 338 + * @priv: pointer to private information of owner 339 + * 340 + * Make dpll device available for user space. 341 + * 342 + * Context: Acquires a lock (dpll_lock) 343 + * Return: 344 + * * 0 on success 345 + * * negative - error value 346 + */ 347 + int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, 348 + const struct dpll_device_ops *ops, void *priv) 349 + { 350 + struct dpll_device_registration *reg; 351 + bool first_registration = false; 352 + 353 + if (WARN_ON(!ops)) 354 + return -EINVAL; 355 + if (WARN_ON(!ops->mode_get)) 356 + return -EINVAL; 357 + if (WARN_ON(!ops->lock_status_get)) 358 + return -EINVAL; 359 + if (WARN_ON(type < DPLL_TYPE_PPS || type > DPLL_TYPE_MAX)) 360 + return -EINVAL; 361 + 362 + mutex_lock(&dpll_lock); 363 + reg = dpll_device_registration_find(dpll, ops, priv); 364 + if (reg) { 365 + mutex_unlock(&dpll_lock); 366 + return -EEXIST; 367 + } 368 + 369 + reg = kzalloc(sizeof(*reg), GFP_KERNEL); 370 + if (!reg) { 371 + mutex_unlock(&dpll_lock); 372 + return -ENOMEM; 373 + } 374 + reg->ops = ops; 375 + reg->priv = priv; 376 + dpll->type = type; 377 + first_registration = list_empty(&dpll->registration_list); 378 + list_add_tail(&reg->list, &dpll->registration_list); 379 + if (!first_registration) { 380 + mutex_unlock(&dpll_lock); 381 + return 0; 382 + } 383 + 384 + xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); 385 + dpll_device_create_ntf(dpll); 386 + mutex_unlock(&dpll_lock); 387 + 388 + return 0; 389 + } 390 + EXPORT_SYMBOL_GPL(dpll_device_register); 391 + 392 + /** 393 + * dpll_device_unregister - unregister dpll device 394 + * @dpll: registered dpll pointer 395 + * @ops: ops for a dpll device 396 + * @priv: pointer to private information of owner 397 + * 398 + * Unregister device, make it unavailable for userspace. 399 + * Note: It does not free the memory 400 + * Context: Acquires a lock (dpll_lock) 401 + */ 402 + void dpll_device_unregister(struct dpll_device *dpll, 403 + const struct dpll_device_ops *ops, void *priv) 404 + { 405 + struct dpll_device_registration *reg; 406 + 407 + mutex_lock(&dpll_lock); 408 + ASSERT_DPLL_REGISTERED(dpll); 409 + dpll_device_delete_ntf(dpll); 410 + reg = dpll_device_registration_find(dpll, ops, priv); 411 + if (WARN_ON(!reg)) { 412 + mutex_unlock(&dpll_lock); 413 + return; 414 + } 415 + list_del(&reg->list); 416 + kfree(reg); 417 + 418 + if (!list_empty(&dpll->registration_list)) { 419 + mutex_unlock(&dpll_lock); 420 + return; 421 + } 422 + xa_clear_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); 423 + mutex_unlock(&dpll_lock); 424 + } 425 + EXPORT_SYMBOL_GPL(dpll_device_unregister); 426 + 427 + static struct dpll_pin * 428 + dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, 429 + const struct dpll_pin_properties *prop) 430 + { 431 + struct dpll_pin *pin; 432 + int ret; 433 + 434 + pin = kzalloc(sizeof(*pin), GFP_KERNEL); 435 + if (!pin) 436 + return ERR_PTR(-ENOMEM); 437 + pin->pin_idx = pin_idx; 438 + pin->clock_id = clock_id; 439 + pin->module = module; 440 + if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX || 441 + prop->type > DPLL_PIN_TYPE_MAX)) { 442 + ret = -EINVAL; 443 + goto err; 444 + } 445 + pin->prop = prop; 446 + refcount_set(&pin->refcount, 1); 447 + xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC); 448 + xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC); 449 + ret = xa_alloc(&dpll_pin_xa, &pin->id, pin, xa_limit_16b, GFP_KERNEL); 450 + if (ret) 451 + goto err; 452 + return pin; 453 + err: 454 + xa_destroy(&pin->dpll_refs); 455 + xa_destroy(&pin->parent_refs); 456 + kfree(pin); 457 + return ERR_PTR(ret); 458 + } 459 + 460 + /** 461 + * dpll_pin_get - find existing or create new dpll pin 462 + * @clock_id: clock_id of creator 463 + * @pin_idx: idx given by dev driver 464 + * @module: reference to registering module 465 + * @prop: dpll pin properties 466 + * 467 + * Get existing object of a pin (unique for given arguments) or create new 468 + * if doesn't exist yet. 469 + * 470 + * Context: Acquires a lock (dpll_lock) 471 + * Return: 472 + * * valid allocated dpll_pin struct pointer if succeeded 473 + * * ERR_PTR(X) - error 474 + */ 475 + struct dpll_pin * 476 + dpll_pin_get(u64 clock_id, u32 pin_idx, struct module *module, 477 + const struct dpll_pin_properties *prop) 478 + { 479 + struct dpll_pin *pos, *ret = NULL; 480 + unsigned long i; 481 + 482 + mutex_lock(&dpll_lock); 483 + xa_for_each(&dpll_pin_xa, i, pos) { 484 + if (pos->clock_id == clock_id && 485 + pos->pin_idx == pin_idx && 486 + pos->module == module) { 487 + ret = pos; 488 + refcount_inc(&ret->refcount); 489 + break; 490 + } 491 + } 492 + if (!ret) 493 + ret = dpll_pin_alloc(clock_id, pin_idx, module, prop); 494 + mutex_unlock(&dpll_lock); 495 + 496 + return ret; 497 + } 498 + EXPORT_SYMBOL_GPL(dpll_pin_get); 499 + 500 + /** 501 + * dpll_pin_put - decrease the refcount and free memory if possible 502 + * @pin: pointer to a pin to be put 503 + * 504 + * Drop reference for a pin, if all references are gone, delete pin object. 505 + * 506 + * Context: Acquires a lock (dpll_lock) 507 + */ 508 + void dpll_pin_put(struct dpll_pin *pin) 509 + { 510 + mutex_lock(&dpll_lock); 511 + if (refcount_dec_and_test(&pin->refcount)) { 512 + xa_destroy(&pin->dpll_refs); 513 + xa_destroy(&pin->parent_refs); 514 + xa_erase(&dpll_pin_xa, pin->id); 515 + kfree(pin); 516 + } 517 + mutex_unlock(&dpll_lock); 518 + } 519 + EXPORT_SYMBOL_GPL(dpll_pin_put); 520 + 521 + static int 522 + __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, 523 + const struct dpll_pin_ops *ops, void *priv) 524 + { 525 + int ret; 526 + 527 + ret = dpll_xa_ref_pin_add(&dpll->pin_refs, pin, ops, priv); 528 + if (ret) 529 + return ret; 530 + ret = dpll_xa_ref_dpll_add(&pin->dpll_refs, dpll, ops, priv); 531 + if (ret) 532 + goto ref_pin_del; 533 + xa_set_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED); 534 + dpll_pin_create_ntf(pin); 535 + 536 + return ret; 537 + 538 + ref_pin_del: 539 + dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv); 540 + return ret; 541 + } 542 + 543 + /** 544 + * dpll_pin_register - register the dpll pin in the subsystem 545 + * @dpll: pointer to a dpll 546 + * @pin: pointer to a dpll pin 547 + * @ops: ops for a dpll pin ops 548 + * @priv: pointer to private information of owner 549 + * 550 + * Context: Acquires a lock (dpll_lock) 551 + * Return: 552 + * * 0 on success 553 + * * negative - error value 554 + */ 555 + int 556 + dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, 557 + const struct dpll_pin_ops *ops, void *priv) 558 + { 559 + int ret; 560 + 561 + if (WARN_ON(!ops) || 562 + WARN_ON(!ops->state_on_dpll_get) || 563 + WARN_ON(!ops->direction_get)) 564 + return -EINVAL; 565 + if (ASSERT_DPLL_REGISTERED(dpll)) 566 + return -EINVAL; 567 + 568 + mutex_lock(&dpll_lock); 569 + if (WARN_ON(!(dpll->module == pin->module && 570 + dpll->clock_id == pin->clock_id))) 571 + ret = -EINVAL; 572 + else 573 + ret = __dpll_pin_register(dpll, pin, ops, priv); 574 + mutex_unlock(&dpll_lock); 575 + 576 + return ret; 577 + } 578 + EXPORT_SYMBOL_GPL(dpll_pin_register); 579 + 580 + static void 581 + __dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, 582 + const struct dpll_pin_ops *ops, void *priv) 583 + { 584 + dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv); 585 + dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv); 586 + if (xa_empty(&pin->dpll_refs)) 587 + xa_clear_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED); 588 + } 589 + 590 + /** 591 + * dpll_pin_unregister - unregister dpll pin from dpll device 592 + * @dpll: registered dpll pointer 593 + * @pin: pointer to a pin 594 + * @ops: ops for a dpll pin 595 + * @priv: pointer to private information of owner 596 + * 597 + * Note: It does not free the memory 598 + * Context: Acquires a lock (dpll_lock) 599 + */ 600 + void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, 601 + const struct dpll_pin_ops *ops, void *priv) 602 + { 603 + if (WARN_ON(xa_empty(&dpll->pin_refs))) 604 + return; 605 + if (WARN_ON(!xa_empty(&pin->parent_refs))) 606 + return; 607 + 608 + mutex_lock(&dpll_lock); 609 + dpll_pin_delete_ntf(pin); 610 + __dpll_pin_unregister(dpll, pin, ops, priv); 611 + mutex_unlock(&dpll_lock); 612 + } 613 + EXPORT_SYMBOL_GPL(dpll_pin_unregister); 614 + 615 + /** 616 + * dpll_pin_on_pin_register - register a pin with a parent pin 617 + * @parent: pointer to a parent pin 618 + * @pin: pointer to a pin 619 + * @ops: ops for a dpll pin 620 + * @priv: pointer to private information of owner 621 + * 622 + * Register a pin with a parent pin, create references between them and 623 + * between newly registered pin and dplls connected with a parent pin. 624 + * 625 + * Context: Acquires a lock (dpll_lock) 626 + * Return: 627 + * * 0 on success 628 + * * negative - error value 629 + */ 630 + int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, 631 + const struct dpll_pin_ops *ops, void *priv) 632 + { 633 + struct dpll_pin_ref *ref; 634 + unsigned long i, stop; 635 + int ret; 636 + 637 + if (WARN_ON(parent->prop->type != DPLL_PIN_TYPE_MUX)) 638 + return -EINVAL; 639 + 640 + if (WARN_ON(!ops) || 641 + WARN_ON(!ops->state_on_pin_get) || 642 + WARN_ON(!ops->direction_get)) 643 + return -EINVAL; 644 + if (ASSERT_PIN_REGISTERED(parent)) 645 + return -EINVAL; 646 + 647 + mutex_lock(&dpll_lock); 648 + ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv); 649 + if (ret) 650 + goto unlock; 651 + refcount_inc(&pin->refcount); 652 + xa_for_each(&parent->dpll_refs, i, ref) { 653 + ret = __dpll_pin_register(ref->dpll, pin, ops, priv); 654 + if (ret) { 655 + stop = i; 656 + goto dpll_unregister; 657 + } 658 + dpll_pin_create_ntf(pin); 659 + } 660 + mutex_unlock(&dpll_lock); 661 + 662 + return ret; 663 + 664 + dpll_unregister: 665 + xa_for_each(&parent->dpll_refs, i, ref) 666 + if (i < stop) { 667 + __dpll_pin_unregister(ref->dpll, pin, ops, priv); 668 + dpll_pin_delete_ntf(pin); 669 + } 670 + refcount_dec(&pin->refcount); 671 + dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv); 672 + unlock: 673 + mutex_unlock(&dpll_lock); 674 + return ret; 675 + } 676 + EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register); 677 + 678 + /** 679 + * dpll_pin_on_pin_unregister - unregister dpll pin from a parent pin 680 + * @parent: pointer to a parent pin 681 + * @pin: pointer to a pin 682 + * @ops: ops for a dpll pin 683 + * @priv: pointer to private information of owner 684 + * 685 + * Context: Acquires a lock (dpll_lock) 686 + * Note: It does not free the memory 687 + */ 688 + void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, 689 + const struct dpll_pin_ops *ops, void *priv) 690 + { 691 + struct dpll_pin_ref *ref; 692 + unsigned long i; 693 + 694 + mutex_lock(&dpll_lock); 695 + dpll_pin_delete_ntf(pin); 696 + dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv); 697 + refcount_dec(&pin->refcount); 698 + xa_for_each(&pin->dpll_refs, i, ref) 699 + __dpll_pin_unregister(ref->dpll, pin, ops, priv); 700 + mutex_unlock(&dpll_lock); 701 + } 702 + EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister); 703 + 704 + static struct dpll_device_registration * 705 + dpll_device_registration_first(struct dpll_device *dpll) 706 + { 707 + struct dpll_device_registration *reg; 708 + 709 + reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list, 710 + struct dpll_device_registration, list); 711 + WARN_ON(!reg); 712 + return reg; 713 + } 714 + 715 + void *dpll_priv(struct dpll_device *dpll) 716 + { 717 + struct dpll_device_registration *reg; 718 + 719 + reg = dpll_device_registration_first(dpll); 720 + return reg->priv; 721 + } 722 + 723 + const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll) 724 + { 725 + struct dpll_device_registration *reg; 726 + 727 + reg = dpll_device_registration_first(dpll); 728 + return reg->ops; 729 + } 730 + 731 + static struct dpll_pin_registration * 732 + dpll_pin_registration_first(struct dpll_pin_ref *ref) 733 + { 734 + struct dpll_pin_registration *reg; 735 + 736 + reg = list_first_entry_or_null(&ref->registration_list, 737 + struct dpll_pin_registration, list); 738 + WARN_ON(!reg); 739 + return reg; 740 + } 741 + 742 + void *dpll_pin_on_dpll_priv(struct dpll_device *dpll, 743 + struct dpll_pin *pin) 744 + { 745 + struct dpll_pin_registration *reg; 746 + struct dpll_pin_ref *ref; 747 + 748 + ref = xa_load(&dpll->pin_refs, pin->pin_idx); 749 + if (!ref) 750 + return NULL; 751 + reg = dpll_pin_registration_first(ref); 752 + return reg->priv; 753 + } 754 + 755 + void *dpll_pin_on_pin_priv(struct dpll_pin *parent, 756 + struct dpll_pin *pin) 757 + { 758 + struct dpll_pin_registration *reg; 759 + struct dpll_pin_ref *ref; 760 + 761 + ref = xa_load(&pin->parent_refs, parent->pin_idx); 762 + if (!ref) 763 + return NULL; 764 + reg = dpll_pin_registration_first(ref); 765 + return reg->priv; 766 + } 767 + 768 + const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref) 769 + { 770 + struct dpll_pin_registration *reg; 771 + 772 + reg = dpll_pin_registration_first(ref); 773 + return reg->ops; 774 + } 775 + 776 + static int __init dpll_init(void) 777 + { 778 + int ret; 779 + 780 + ret = genl_register_family(&dpll_nl_family); 781 + if (ret) 782 + goto error; 783 + 784 + return 0; 785 + 786 + error: 787 + mutex_destroy(&dpll_lock); 788 + return ret; 789 + } 790 + 791 + static void __exit dpll_exit(void) 792 + { 793 + genl_unregister_family(&dpll_nl_family); 794 + mutex_destroy(&dpll_lock); 795 + } 796 + 797 + subsys_initcall(dpll_init); 798 + module_exit(dpll_exit);
+89
drivers/dpll/dpll_core.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates 4 + * Copyright (c) 2023 Intel and affiliates 5 + */ 6 + 7 + #ifndef __DPLL_CORE_H__ 8 + #define __DPLL_CORE_H__ 9 + 10 + #include <linux/dpll.h> 11 + #include <linux/list.h> 12 + #include <linux/refcount.h> 13 + #include "dpll_nl.h" 14 + 15 + #define DPLL_REGISTERED XA_MARK_1 16 + 17 + /** 18 + * struct dpll_device - stores DPLL device internal data 19 + * @id: unique id number for device given by dpll subsystem 20 + * @device_idx: id given by dev driver 21 + * @clock_id: unique identifier (clock_id) of a dpll 22 + * @module: module of creator 23 + * @type: type of a dpll 24 + * @pin_refs: stores pins registered within a dpll 25 + * @refcount: refcount 26 + * @registration_list: list of registered ops and priv data of dpll owners 27 + **/ 28 + struct dpll_device { 29 + u32 id; 30 + u32 device_idx; 31 + u64 clock_id; 32 + struct module *module; 33 + enum dpll_type type; 34 + struct xarray pin_refs; 35 + refcount_t refcount; 36 + struct list_head registration_list; 37 + }; 38 + 39 + /** 40 + * struct dpll_pin - structure for a dpll pin 41 + * @id: unique id number for pin given by dpll subsystem 42 + * @pin_idx: index of a pin given by dev driver 43 + * @clock_id: clock_id of creator 44 + * @module: module of creator 45 + * @dpll_refs: hold referencees to dplls pin was registered with 46 + * @parent_refs: hold references to parent pins pin was registered with 47 + * @prop: pointer to pin properties given by registerer 48 + * @rclk_dev_name: holds name of device when pin can recover clock from it 49 + * @refcount: refcount 50 + **/ 51 + struct dpll_pin { 52 + u32 id; 53 + u32 pin_idx; 54 + u64 clock_id; 55 + struct module *module; 56 + struct xarray dpll_refs; 57 + struct xarray parent_refs; 58 + const struct dpll_pin_properties *prop; 59 + refcount_t refcount; 60 + }; 61 + 62 + /** 63 + * struct dpll_pin_ref - structure for referencing either dpll or pins 64 + * @dpll: pointer to a dpll 65 + * @pin: pointer to a pin 66 + * @registration_list: list of ops and priv data registered with the ref 67 + * @refcount: refcount 68 + **/ 69 + struct dpll_pin_ref { 70 + union { 71 + struct dpll_device *dpll; 72 + struct dpll_pin *pin; 73 + }; 74 + struct list_head registration_list; 75 + refcount_t refcount; 76 + }; 77 + 78 + void *dpll_priv(struct dpll_device *dpll); 79 + void *dpll_pin_on_dpll_priv(struct dpll_device *dpll, struct dpll_pin *pin); 80 + void *dpll_pin_on_pin_priv(struct dpll_pin *parent, struct dpll_pin *pin); 81 + 82 + const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll); 83 + struct dpll_device *dpll_device_get_by_id(int id); 84 + const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref); 85 + struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs); 86 + extern struct xarray dpll_device_xa; 87 + extern struct xarray dpll_pin_xa; 88 + extern struct mutex dpll_lock; 89 + #endif
+1253
drivers/dpll/dpll_netlink.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Generic netlink for DPLL management framework 4 + * 5 + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates 6 + * Copyright (c) 2023 Intel and affiliates 7 + * 8 + */ 9 + #include <linux/module.h> 10 + #include <linux/kernel.h> 11 + #include <net/genetlink.h> 12 + #include "dpll_core.h" 13 + #include "dpll_netlink.h" 14 + #include "dpll_nl.h" 15 + #include <uapi/linux/dpll.h> 16 + 17 + #define ASSERT_NOT_NULL(ptr) (WARN_ON(!ptr)) 18 + 19 + #define xa_for_each_marked_start(xa, index, entry, filter, start) \ 20 + for (index = start, entry = xa_find(xa, &index, ULONG_MAX, filter); \ 21 + entry; entry = xa_find_after(xa, &index, ULONG_MAX, filter)) 22 + 23 + struct dpll_dump_ctx { 24 + unsigned long idx; 25 + }; 26 + 27 + static struct dpll_dump_ctx *dpll_dump_context(struct netlink_callback *cb) 28 + { 29 + return (struct dpll_dump_ctx *)cb->ctx; 30 + } 31 + 32 + static int 33 + dpll_msg_add_dev_handle(struct sk_buff *msg, struct dpll_device *dpll) 34 + { 35 + if (nla_put_u32(msg, DPLL_A_ID, dpll->id)) 36 + return -EMSGSIZE; 37 + 38 + return 0; 39 + } 40 + 41 + static int 42 + dpll_msg_add_dev_parent_handle(struct sk_buff *msg, u32 id) 43 + { 44 + if (nla_put_u32(msg, DPLL_A_PIN_PARENT_ID, id)) 45 + return -EMSGSIZE; 46 + 47 + return 0; 48 + } 49 + 50 + /** 51 + * dpll_msg_pin_handle_size - get size of pin handle attribute for given pin 52 + * @pin: pin pointer 53 + * 54 + * Return: byte size of pin handle attribute for given pin. 55 + */ 56 + size_t dpll_msg_pin_handle_size(struct dpll_pin *pin) 57 + { 58 + return pin ? nla_total_size(4) : 0; /* DPLL_A_PIN_ID */ 59 + } 60 + EXPORT_SYMBOL_GPL(dpll_msg_pin_handle_size); 61 + 62 + /** 63 + * dpll_msg_add_pin_handle - attach pin handle attribute to a given message 64 + * @msg: pointer to sk_buff message to attach a pin handle 65 + * @pin: pin pointer 66 + * 67 + * Return: 68 + * * 0 - success 69 + * * -EMSGSIZE - no space in message to attach pin handle 70 + */ 71 + int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin) 72 + { 73 + if (!pin) 74 + return 0; 75 + if (nla_put_u32(msg, DPLL_A_PIN_ID, pin->id)) 76 + return -EMSGSIZE; 77 + return 0; 78 + } 79 + EXPORT_SYMBOL_GPL(dpll_msg_add_pin_handle); 80 + 81 + static int 82 + dpll_msg_add_mode(struct sk_buff *msg, struct dpll_device *dpll, 83 + struct netlink_ext_ack *extack) 84 + { 85 + const struct dpll_device_ops *ops = dpll_device_ops(dpll); 86 + enum dpll_mode mode; 87 + int ret; 88 + 89 + ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack); 90 + if (ret) 91 + return ret; 92 + if (nla_put_u32(msg, DPLL_A_MODE, mode)) 93 + return -EMSGSIZE; 94 + 95 + return 0; 96 + } 97 + 98 + static int 99 + dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll, 100 + struct netlink_ext_ack *extack) 101 + { 102 + const struct dpll_device_ops *ops = dpll_device_ops(dpll); 103 + enum dpll_mode mode; 104 + 105 + if (!ops->mode_supported) 106 + return 0; 107 + for (mode = DPLL_MODE_MANUAL; mode <= DPLL_MODE_MAX; mode++) 108 + if (ops->mode_supported(dpll, dpll_priv(dpll), mode, extack)) 109 + if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode)) 110 + return -EMSGSIZE; 111 + 112 + return 0; 113 + } 114 + 115 + static int 116 + dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll, 117 + struct netlink_ext_ack *extack) 118 + { 119 + const struct dpll_device_ops *ops = dpll_device_ops(dpll); 120 + enum dpll_lock_status status; 121 + int ret; 122 + 123 + ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status, extack); 124 + if (ret) 125 + return ret; 126 + if (nla_put_u32(msg, DPLL_A_LOCK_STATUS, status)) 127 + return -EMSGSIZE; 128 + 129 + return 0; 130 + } 131 + 132 + static int 133 + dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll, 134 + struct netlink_ext_ack *extack) 135 + { 136 + const struct dpll_device_ops *ops = dpll_device_ops(dpll); 137 + s32 temp; 138 + int ret; 139 + 140 + if (!ops->temp_get) 141 + return 0; 142 + ret = ops->temp_get(dpll, dpll_priv(dpll), &temp, extack); 143 + if (ret) 144 + return ret; 145 + if (nla_put_s32(msg, DPLL_A_TEMP, temp)) 146 + return -EMSGSIZE; 147 + 148 + return 0; 149 + } 150 + 151 + static int 152 + dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin, 153 + struct dpll_pin_ref *ref, 154 + struct netlink_ext_ack *extack) 155 + { 156 + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 157 + struct dpll_device *dpll = ref->dpll; 158 + u32 prio; 159 + int ret; 160 + 161 + if (!ops->prio_get) 162 + return 0; 163 + ret = ops->prio_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 164 + dpll_priv(dpll), &prio, extack); 165 + if (ret) 166 + return ret; 167 + if (nla_put_u32(msg, DPLL_A_PIN_PRIO, prio)) 168 + return -EMSGSIZE; 169 + 170 + return 0; 171 + } 172 + 173 + static int 174 + dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin, 175 + struct dpll_pin_ref *ref, 176 + struct netlink_ext_ack *extack) 177 + { 178 + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 179 + struct dpll_device *dpll = ref->dpll; 180 + enum dpll_pin_state state; 181 + int ret; 182 + 183 + if (!ops->state_on_dpll_get) 184 + return 0; 185 + ret = ops->state_on_dpll_get(pin, dpll_pin_on_dpll_priv(dpll, pin), 186 + dpll, dpll_priv(dpll), &state, extack); 187 + if (ret) 188 + return ret; 189 + if (nla_put_u32(msg, DPLL_A_PIN_STATE, state)) 190 + return -EMSGSIZE; 191 + 192 + return 0; 193 + } 194 + 195 + static int 196 + dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin, 197 + struct dpll_pin_ref *ref, 198 + struct netlink_ext_ack *extack) 199 + { 200 + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 201 + struct dpll_device *dpll = ref->dpll; 202 + enum dpll_pin_direction direction; 203 + int ret; 204 + 205 + ret = ops->direction_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 206 + dpll_priv(dpll), &direction, extack); 207 + if (ret) 208 + return ret; 209 + if (nla_put_u32(msg, DPLL_A_PIN_DIRECTION, direction)) 210 + return -EMSGSIZE; 211 + 212 + return 0; 213 + } 214 + 215 + static int 216 + dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, 217 + struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) 218 + { 219 + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 220 + struct dpll_device *dpll = ref->dpll; 221 + struct nlattr *nest; 222 + int fs, ret; 223 + u64 freq; 224 + 225 + if (!ops->frequency_get) 226 + return 0; 227 + ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 228 + dpll_priv(dpll), &freq, extack); 229 + if (ret) 230 + return ret; 231 + if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq, 232 + DPLL_A_PIN_PAD)) 233 + return -EMSGSIZE; 234 + for (fs = 0; fs < pin->prop->freq_supported_num; fs++) { 235 + nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED); 236 + if (!nest) 237 + return -EMSGSIZE; 238 + freq = pin->prop->freq_supported[fs].min; 239 + if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq), 240 + &freq, DPLL_A_PIN_PAD)) { 241 + nla_nest_cancel(msg, nest); 242 + return -EMSGSIZE; 243 + } 244 + freq = pin->prop->freq_supported[fs].max; 245 + if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq), 246 + &freq, DPLL_A_PIN_PAD)) { 247 + nla_nest_cancel(msg, nest); 248 + return -EMSGSIZE; 249 + } 250 + nla_nest_end(msg, nest); 251 + } 252 + 253 + return 0; 254 + } 255 + 256 + static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq) 257 + { 258 + int fs; 259 + 260 + for (fs = 0; fs < pin->prop->freq_supported_num; fs++) 261 + if (freq >= pin->prop->freq_supported[fs].min && 262 + freq <= pin->prop->freq_supported[fs].max) 263 + return true; 264 + return false; 265 + } 266 + 267 + static int 268 + dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin, 269 + struct dpll_pin_ref *dpll_ref, 270 + struct netlink_ext_ack *extack) 271 + { 272 + enum dpll_pin_state state; 273 + struct dpll_pin_ref *ref; 274 + struct dpll_pin *ppin; 275 + struct nlattr *nest; 276 + unsigned long index; 277 + int ret; 278 + 279 + xa_for_each(&pin->parent_refs, index, ref) { 280 + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 281 + void *parent_priv; 282 + 283 + ppin = ref->pin; 284 + parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, ppin); 285 + ret = ops->state_on_pin_get(pin, 286 + dpll_pin_on_pin_priv(ppin, pin), 287 + ppin, parent_priv, &state, extack); 288 + if (ret) 289 + return ret; 290 + nest = nla_nest_start(msg, DPLL_A_PIN_PARENT_PIN); 291 + if (!nest) 292 + return -EMSGSIZE; 293 + ret = dpll_msg_add_dev_parent_handle(msg, ppin->id); 294 + if (ret) 295 + goto nest_cancel; 296 + if (nla_put_u32(msg, DPLL_A_PIN_STATE, state)) { 297 + ret = -EMSGSIZE; 298 + goto nest_cancel; 299 + } 300 + nla_nest_end(msg, nest); 301 + } 302 + 303 + return 0; 304 + 305 + nest_cancel: 306 + nla_nest_cancel(msg, nest); 307 + return ret; 308 + } 309 + 310 + static int 311 + dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin, 312 + struct netlink_ext_ack *extack) 313 + { 314 + struct dpll_pin_ref *ref; 315 + struct nlattr *attr; 316 + unsigned long index; 317 + int ret; 318 + 319 + xa_for_each(&pin->dpll_refs, index, ref) { 320 + attr = nla_nest_start(msg, DPLL_A_PIN_PARENT_DEVICE); 321 + if (!attr) 322 + return -EMSGSIZE; 323 + ret = dpll_msg_add_dev_parent_handle(msg, ref->dpll->id); 324 + if (ret) 325 + goto nest_cancel; 326 + ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack); 327 + if (ret) 328 + goto nest_cancel; 329 + ret = dpll_msg_add_pin_prio(msg, pin, ref, extack); 330 + if (ret) 331 + goto nest_cancel; 332 + ret = dpll_msg_add_pin_direction(msg, pin, ref, extack); 333 + if (ret) 334 + goto nest_cancel; 335 + nla_nest_end(msg, attr); 336 + } 337 + 338 + return 0; 339 + 340 + nest_cancel: 341 + nla_nest_end(msg, attr); 342 + return ret; 343 + } 344 + 345 + static int 346 + dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, 347 + struct netlink_ext_ack *extack) 348 + { 349 + const struct dpll_pin_properties *prop = pin->prop; 350 + struct dpll_pin_ref *ref; 351 + int ret; 352 + 353 + ref = dpll_xa_ref_dpll_first(&pin->dpll_refs); 354 + ASSERT_NOT_NULL(ref); 355 + 356 + ret = dpll_msg_add_pin_handle(msg, pin); 357 + if (ret) 358 + return ret; 359 + if (nla_put_string(msg, DPLL_A_PIN_MODULE_NAME, 360 + module_name(pin->module))) 361 + return -EMSGSIZE; 362 + if (nla_put_64bit(msg, DPLL_A_PIN_CLOCK_ID, sizeof(pin->clock_id), 363 + &pin->clock_id, DPLL_A_PIN_PAD)) 364 + return -EMSGSIZE; 365 + if (prop->board_label && 366 + nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, prop->board_label)) 367 + return -EMSGSIZE; 368 + if (prop->panel_label && 369 + nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, prop->panel_label)) 370 + return -EMSGSIZE; 371 + if (prop->package_label && 372 + nla_put_string(msg, DPLL_A_PIN_PACKAGE_LABEL, 373 + prop->package_label)) 374 + return -EMSGSIZE; 375 + if (nla_put_u32(msg, DPLL_A_PIN_TYPE, prop->type)) 376 + return -EMSGSIZE; 377 + if (nla_put_u32(msg, DPLL_A_PIN_CAPABILITIES, prop->capabilities)) 378 + return -EMSGSIZE; 379 + ret = dpll_msg_add_pin_freq(msg, pin, ref, extack); 380 + if (ret) 381 + return ret; 382 + if (xa_empty(&pin->parent_refs)) 383 + ret = dpll_msg_add_pin_dplls(msg, pin, extack); 384 + else 385 + ret = dpll_msg_add_pin_parents(msg, pin, ref, extack); 386 + 387 + return ret; 388 + } 389 + 390 + static int 391 + dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, 392 + struct netlink_ext_ack *extack) 393 + { 394 + int ret; 395 + 396 + ret = dpll_msg_add_dev_handle(msg, dpll); 397 + if (ret) 398 + return ret; 399 + if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(dpll->module))) 400 + return -EMSGSIZE; 401 + if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id), 402 + &dpll->clock_id, DPLL_A_PAD)) 403 + return -EMSGSIZE; 404 + ret = dpll_msg_add_temp(msg, dpll, extack); 405 + if (ret) 406 + return ret; 407 + ret = dpll_msg_add_lock_status(msg, dpll, extack); 408 + if (ret) 409 + return ret; 410 + ret = dpll_msg_add_mode(msg, dpll, extack); 411 + if (ret) 412 + return ret; 413 + ret = dpll_msg_add_mode_supported(msg, dpll, extack); 414 + if (ret) 415 + return ret; 416 + if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type)) 417 + return -EMSGSIZE; 418 + 419 + return ret; 420 + } 421 + 422 + static int 423 + dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll) 424 + { 425 + struct sk_buff *msg; 426 + int ret = -ENOMEM; 427 + void *hdr; 428 + 429 + if (WARN_ON(!xa_get_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED))) 430 + return -ENODEV; 431 + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 432 + if (!msg) 433 + return -ENOMEM; 434 + hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event); 435 + if (!hdr) 436 + goto err_free_msg; 437 + ret = dpll_device_get_one(dpll, msg, NULL); 438 + if (ret) 439 + goto err_cancel_msg; 440 + genlmsg_end(msg, hdr); 441 + genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL); 442 + 443 + return 0; 444 + 445 + err_cancel_msg: 446 + genlmsg_cancel(msg, hdr); 447 + err_free_msg: 448 + nlmsg_free(msg); 449 + 450 + return ret; 451 + } 452 + 453 + int dpll_device_create_ntf(struct dpll_device *dpll) 454 + { 455 + return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF, dpll); 456 + } 457 + 458 + int dpll_device_delete_ntf(struct dpll_device *dpll) 459 + { 460 + return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll); 461 + } 462 + 463 + static int 464 + __dpll_device_change_ntf(struct dpll_device *dpll) 465 + { 466 + return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); 467 + } 468 + 469 + /** 470 + * dpll_device_change_ntf - notify that the dpll device has been changed 471 + * @dpll: registered dpll pointer 472 + * 473 + * Context: acquires and holds a dpll_lock. 474 + * Return: 0 if succeeds, error code otherwise. 475 + */ 476 + int dpll_device_change_ntf(struct dpll_device *dpll) 477 + { 478 + int ret; 479 + 480 + mutex_lock(&dpll_lock); 481 + ret = __dpll_device_change_ntf(dpll); 482 + mutex_unlock(&dpll_lock); 483 + 484 + return ret; 485 + } 486 + EXPORT_SYMBOL_GPL(dpll_device_change_ntf); 487 + 488 + static int 489 + dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin) 490 + { 491 + struct sk_buff *msg; 492 + int ret = -ENOMEM; 493 + void *hdr; 494 + 495 + if (WARN_ON(!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED))) 496 + return -ENODEV; 497 + 498 + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 499 + if (!msg) 500 + return -ENOMEM; 501 + 502 + hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event); 503 + if (!hdr) 504 + goto err_free_msg; 505 + ret = dpll_cmd_pin_get_one(msg, pin, NULL); 506 + if (ret) 507 + goto err_cancel_msg; 508 + genlmsg_end(msg, hdr); 509 + genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL); 510 + 511 + return 0; 512 + 513 + err_cancel_msg: 514 + genlmsg_cancel(msg, hdr); 515 + err_free_msg: 516 + nlmsg_free(msg); 517 + 518 + return ret; 519 + } 520 + 521 + int dpll_pin_create_ntf(struct dpll_pin *pin) 522 + { 523 + return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin); 524 + } 525 + 526 + int dpll_pin_delete_ntf(struct dpll_pin *pin) 527 + { 528 + return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); 529 + } 530 + 531 + static int __dpll_pin_change_ntf(struct dpll_pin *pin) 532 + { 533 + return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); 534 + } 535 + 536 + /** 537 + * dpll_pin_change_ntf - notify that the pin has been changed 538 + * @pin: registered pin pointer 539 + * 540 + * Context: acquires and holds a dpll_lock. 541 + * Return: 0 if succeeds, error code otherwise. 542 + */ 543 + int dpll_pin_change_ntf(struct dpll_pin *pin) 544 + { 545 + int ret; 546 + 547 + mutex_lock(&dpll_lock); 548 + ret = __dpll_pin_change_ntf(pin); 549 + mutex_unlock(&dpll_lock); 550 + 551 + return ret; 552 + } 553 + EXPORT_SYMBOL_GPL(dpll_pin_change_ntf); 554 + 555 + static int 556 + dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a, 557 + struct netlink_ext_ack *extack) 558 + { 559 + u64 freq = nla_get_u64(a); 560 + struct dpll_pin_ref *ref; 561 + unsigned long i; 562 + int ret; 563 + 564 + if (!dpll_pin_is_freq_supported(pin, freq)) { 565 + NL_SET_ERR_MSG_ATTR(extack, a, "frequency is not supported by the device"); 566 + return -EINVAL; 567 + } 568 + 569 + xa_for_each(&pin->dpll_refs, i, ref) { 570 + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 571 + struct dpll_device *dpll = ref->dpll; 572 + 573 + if (!ops->frequency_set) 574 + return -EOPNOTSUPP; 575 + ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin), 576 + dpll, dpll_priv(dpll), freq, extack); 577 + if (ret) 578 + return ret; 579 + } 580 + __dpll_pin_change_ntf(pin); 581 + 582 + return 0; 583 + } 584 + 585 + static int 586 + dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx, 587 + enum dpll_pin_state state, 588 + struct netlink_ext_ack *extack) 589 + { 590 + struct dpll_pin_ref *parent_ref; 591 + const struct dpll_pin_ops *ops; 592 + struct dpll_pin_ref *dpll_ref; 593 + void *pin_priv, *parent_priv; 594 + struct dpll_pin *parent; 595 + unsigned long i; 596 + int ret; 597 + 598 + if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & 599 + pin->prop->capabilities)) { 600 + NL_SET_ERR_MSG(extack, "state changing is not allowed"); 601 + return -EOPNOTSUPP; 602 + } 603 + parent = xa_load(&dpll_pin_xa, parent_idx); 604 + if (!parent) 605 + return -EINVAL; 606 + parent_ref = xa_load(&pin->parent_refs, parent->pin_idx); 607 + if (!parent_ref) 608 + return -EINVAL; 609 + xa_for_each(&parent->dpll_refs, i, dpll_ref) { 610 + ops = dpll_pin_ops(parent_ref); 611 + if (!ops->state_on_pin_set) 612 + return -EOPNOTSUPP; 613 + pin_priv = dpll_pin_on_pin_priv(parent, pin); 614 + parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, parent); 615 + ret = ops->state_on_pin_set(pin, pin_priv, parent, parent_priv, 616 + state, extack); 617 + if (ret) 618 + return ret; 619 + } 620 + __dpll_pin_change_ntf(pin); 621 + 622 + return 0; 623 + } 624 + 625 + static int 626 + dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, 627 + enum dpll_pin_state state, 628 + struct netlink_ext_ack *extack) 629 + { 630 + const struct dpll_pin_ops *ops; 631 + struct dpll_pin_ref *ref; 632 + int ret; 633 + 634 + if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & 635 + pin->prop->capabilities)) { 636 + NL_SET_ERR_MSG(extack, "state changing is not allowed"); 637 + return -EOPNOTSUPP; 638 + } 639 + ref = xa_load(&pin->dpll_refs, dpll->id); 640 + ASSERT_NOT_NULL(ref); 641 + ops = dpll_pin_ops(ref); 642 + if (!ops->state_on_dpll_set) 643 + return -EOPNOTSUPP; 644 + ret = ops->state_on_dpll_set(pin, dpll_pin_on_dpll_priv(dpll, pin), 645 + dpll, dpll_priv(dpll), state, extack); 646 + if (ret) 647 + return ret; 648 + __dpll_pin_change_ntf(pin); 649 + 650 + return 0; 651 + } 652 + 653 + static int 654 + dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin, 655 + u32 prio, struct netlink_ext_ack *extack) 656 + { 657 + const struct dpll_pin_ops *ops; 658 + struct dpll_pin_ref *ref; 659 + int ret; 660 + 661 + if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE & 662 + pin->prop->capabilities)) { 663 + NL_SET_ERR_MSG(extack, "prio changing is not allowed"); 664 + return -EOPNOTSUPP; 665 + } 666 + ref = xa_load(&pin->dpll_refs, dpll->id); 667 + ASSERT_NOT_NULL(ref); 668 + ops = dpll_pin_ops(ref); 669 + if (!ops->prio_set) 670 + return -EOPNOTSUPP; 671 + ret = ops->prio_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, 672 + dpll_priv(dpll), prio, extack); 673 + if (ret) 674 + return ret; 675 + __dpll_pin_change_ntf(pin); 676 + 677 + return 0; 678 + } 679 + 680 + static int 681 + dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll, 682 + enum dpll_pin_direction direction, 683 + struct netlink_ext_ack *extack) 684 + { 685 + const struct dpll_pin_ops *ops; 686 + struct dpll_pin_ref *ref; 687 + int ret; 688 + 689 + if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE & 690 + pin->prop->capabilities)) { 691 + NL_SET_ERR_MSG(extack, "direction changing is not allowed"); 692 + return -EOPNOTSUPP; 693 + } 694 + ref = xa_load(&pin->dpll_refs, dpll->id); 695 + ASSERT_NOT_NULL(ref); 696 + ops = dpll_pin_ops(ref); 697 + if (!ops->direction_set) 698 + return -EOPNOTSUPP; 699 + ret = ops->direction_set(pin, dpll_pin_on_dpll_priv(dpll, pin), 700 + dpll, dpll_priv(dpll), direction, extack); 701 + if (ret) 702 + return ret; 703 + __dpll_pin_change_ntf(pin); 704 + 705 + return 0; 706 + } 707 + 708 + static int 709 + dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest, 710 + struct netlink_ext_ack *extack) 711 + { 712 + struct nlattr *tb[DPLL_A_PIN_MAX + 1]; 713 + enum dpll_pin_direction direction; 714 + enum dpll_pin_state state; 715 + struct dpll_pin_ref *ref; 716 + struct dpll_device *dpll; 717 + u32 pdpll_idx, prio; 718 + int ret; 719 + 720 + nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest, 721 + dpll_pin_parent_device_nl_policy, extack); 722 + if (!tb[DPLL_A_PIN_PARENT_ID]) { 723 + NL_SET_ERR_MSG(extack, "device parent id expected"); 724 + return -EINVAL; 725 + } 726 + pdpll_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]); 727 + dpll = xa_load(&dpll_device_xa, pdpll_idx); 728 + if (!dpll) { 729 + NL_SET_ERR_MSG(extack, "parent device not found"); 730 + return -EINVAL; 731 + } 732 + ref = xa_load(&pin->dpll_refs, dpll->id); 733 + if (!ref) { 734 + NL_SET_ERR_MSG(extack, "pin not connected to given parent device"); 735 + return -EINVAL; 736 + } 737 + if (tb[DPLL_A_PIN_STATE]) { 738 + state = nla_get_u32(tb[DPLL_A_PIN_STATE]); 739 + ret = dpll_pin_state_set(dpll, pin, state, extack); 740 + if (ret) 741 + return ret; 742 + } 743 + if (tb[DPLL_A_PIN_PRIO]) { 744 + prio = nla_get_u32(tb[DPLL_A_PIN_PRIO]); 745 + ret = dpll_pin_prio_set(dpll, pin, prio, extack); 746 + if (ret) 747 + return ret; 748 + } 749 + if (tb[DPLL_A_PIN_DIRECTION]) { 750 + direction = nla_get_u32(tb[DPLL_A_PIN_DIRECTION]); 751 + ret = dpll_pin_direction_set(pin, dpll, direction, extack); 752 + if (ret) 753 + return ret; 754 + } 755 + return 0; 756 + } 757 + 758 + static int 759 + dpll_pin_parent_pin_set(struct dpll_pin *pin, struct nlattr *parent_nest, 760 + struct netlink_ext_ack *extack) 761 + { 762 + struct nlattr *tb[DPLL_A_PIN_MAX + 1]; 763 + enum dpll_pin_state state; 764 + u32 ppin_idx; 765 + int ret; 766 + 767 + nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest, 768 + dpll_pin_parent_pin_nl_policy, extack); 769 + if (!tb[DPLL_A_PIN_PARENT_ID]) { 770 + NL_SET_ERR_MSG(extack, "device parent id expected"); 771 + return -EINVAL; 772 + } 773 + ppin_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]); 774 + state = nla_get_u32(tb[DPLL_A_PIN_STATE]); 775 + ret = dpll_pin_on_pin_state_set(pin, ppin_idx, state, extack); 776 + if (ret) 777 + return ret; 778 + 779 + return 0; 780 + } 781 + 782 + static int 783 + dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info) 784 + { 785 + struct nlattr *a; 786 + int rem, ret; 787 + 788 + nla_for_each_attr(a, genlmsg_data(info->genlhdr), 789 + genlmsg_len(info->genlhdr), rem) { 790 + switch (nla_type(a)) { 791 + case DPLL_A_PIN_FREQUENCY: 792 + ret = dpll_pin_freq_set(pin, a, info->extack); 793 + if (ret) 794 + return ret; 795 + break; 796 + case DPLL_A_PIN_PARENT_DEVICE: 797 + ret = dpll_pin_parent_device_set(pin, a, info->extack); 798 + if (ret) 799 + return ret; 800 + break; 801 + case DPLL_A_PIN_PARENT_PIN: 802 + ret = dpll_pin_parent_pin_set(pin, a, info->extack); 803 + if (ret) 804 + return ret; 805 + break; 806 + } 807 + } 808 + 809 + return 0; 810 + } 811 + 812 + static struct dpll_pin * 813 + dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr, 814 + enum dpll_pin_type type, struct nlattr *board_label, 815 + struct nlattr *panel_label, struct nlattr *package_label, 816 + struct netlink_ext_ack *extack) 817 + { 818 + bool board_match, panel_match, package_match; 819 + struct dpll_pin *pin_match = NULL, *pin; 820 + const struct dpll_pin_properties *prop; 821 + bool cid_match, mod_match, type_match; 822 + unsigned long i; 823 + 824 + xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) { 825 + prop = pin->prop; 826 + cid_match = clock_id ? pin->clock_id == clock_id : true; 827 + mod_match = mod_name_attr && module_name(pin->module) ? 828 + !nla_strcmp(mod_name_attr, 829 + module_name(pin->module)) : true; 830 + type_match = type ? prop->type == type : true; 831 + board_match = board_label ? (prop->board_label ? 832 + !nla_strcmp(board_label, prop->board_label) : false) : 833 + true; 834 + panel_match = panel_label ? (prop->panel_label ? 835 + !nla_strcmp(panel_label, prop->panel_label) : false) : 836 + true; 837 + package_match = package_label ? (prop->package_label ? 838 + !nla_strcmp(package_label, prop->package_label) : 839 + false) : true; 840 + if (cid_match && mod_match && type_match && board_match && 841 + panel_match && package_match) { 842 + if (pin_match) { 843 + NL_SET_ERR_MSG(extack, "multiple matches"); 844 + return ERR_PTR(-EINVAL); 845 + } 846 + pin_match = pin; 847 + }; 848 + } 849 + if (!pin_match) { 850 + NL_SET_ERR_MSG(extack, "not found"); 851 + return ERR_PTR(-ENODEV); 852 + } 853 + return pin_match; 854 + } 855 + 856 + static struct dpll_pin *dpll_pin_find_from_nlattr(struct genl_info *info) 857 + { 858 + struct nlattr *attr, *mod_name_attr = NULL, *board_label_attr = NULL, 859 + *panel_label_attr = NULL, *package_label_attr = NULL; 860 + enum dpll_pin_type type = 0; 861 + u64 clock_id = 0; 862 + int rem = 0; 863 + 864 + nla_for_each_attr(attr, genlmsg_data(info->genlhdr), 865 + genlmsg_len(info->genlhdr), rem) { 866 + switch (nla_type(attr)) { 867 + case DPLL_A_PIN_CLOCK_ID: 868 + if (clock_id) 869 + goto duplicated_attr; 870 + clock_id = nla_get_u64(attr); 871 + break; 872 + case DPLL_A_PIN_MODULE_NAME: 873 + if (mod_name_attr) 874 + goto duplicated_attr; 875 + mod_name_attr = attr; 876 + break; 877 + case DPLL_A_PIN_TYPE: 878 + if (type) 879 + goto duplicated_attr; 880 + type = nla_get_u32(attr); 881 + break; 882 + case DPLL_A_PIN_BOARD_LABEL: 883 + if (board_label_attr) 884 + goto duplicated_attr; 885 + board_label_attr = attr; 886 + break; 887 + case DPLL_A_PIN_PANEL_LABEL: 888 + if (panel_label_attr) 889 + goto duplicated_attr; 890 + panel_label_attr = attr; 891 + break; 892 + case DPLL_A_PIN_PACKAGE_LABEL: 893 + if (package_label_attr) 894 + goto duplicated_attr; 895 + package_label_attr = attr; 896 + break; 897 + default: 898 + break; 899 + } 900 + } 901 + if (!(clock_id || mod_name_attr || board_label_attr || 902 + panel_label_attr || package_label_attr)) { 903 + NL_SET_ERR_MSG(info->extack, "missing attributes"); 904 + return ERR_PTR(-EINVAL); 905 + } 906 + return dpll_pin_find(clock_id, mod_name_attr, type, board_label_attr, 907 + panel_label_attr, package_label_attr, 908 + info->extack); 909 + duplicated_attr: 910 + NL_SET_ERR_MSG(info->extack, "duplicated attribute"); 911 + return ERR_PTR(-EINVAL); 912 + } 913 + 914 + int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info) 915 + { 916 + struct dpll_pin *pin; 917 + struct sk_buff *msg; 918 + struct nlattr *hdr; 919 + int ret; 920 + 921 + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 922 + if (!msg) 923 + return -ENOMEM; 924 + hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 925 + DPLL_CMD_PIN_ID_GET); 926 + if (!hdr) 927 + return -EMSGSIZE; 928 + 929 + pin = dpll_pin_find_from_nlattr(info); 930 + if (!IS_ERR(pin)) { 931 + ret = dpll_msg_add_pin_handle(msg, pin); 932 + if (ret) { 933 + nlmsg_free(msg); 934 + return ret; 935 + } 936 + } 937 + genlmsg_end(msg, hdr); 938 + 939 + return genlmsg_reply(msg, info); 940 + } 941 + 942 + int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info) 943 + { 944 + struct dpll_pin *pin = info->user_ptr[0]; 945 + struct sk_buff *msg; 946 + struct nlattr *hdr; 947 + int ret; 948 + 949 + if (!pin) 950 + return -ENODEV; 951 + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 952 + if (!msg) 953 + return -ENOMEM; 954 + hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 955 + DPLL_CMD_PIN_GET); 956 + if (!hdr) 957 + return -EMSGSIZE; 958 + ret = dpll_cmd_pin_get_one(msg, pin, info->extack); 959 + if (ret) { 960 + nlmsg_free(msg); 961 + return ret; 962 + } 963 + genlmsg_end(msg, hdr); 964 + 965 + return genlmsg_reply(msg, info); 966 + } 967 + 968 + int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 969 + { 970 + struct dpll_dump_ctx *ctx = dpll_dump_context(cb); 971 + struct dpll_pin *pin; 972 + struct nlattr *hdr; 973 + unsigned long i; 974 + int ret = 0; 975 + 976 + xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED, 977 + ctx->idx) { 978 + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 979 + cb->nlh->nlmsg_seq, 980 + &dpll_nl_family, NLM_F_MULTI, 981 + DPLL_CMD_PIN_GET); 982 + if (!hdr) { 983 + ret = -EMSGSIZE; 984 + break; 985 + } 986 + ret = dpll_cmd_pin_get_one(skb, pin, cb->extack); 987 + if (ret) { 988 + genlmsg_cancel(skb, hdr); 989 + break; 990 + } 991 + genlmsg_end(skb, hdr); 992 + } 993 + if (ret == -EMSGSIZE) { 994 + ctx->idx = i; 995 + return skb->len; 996 + } 997 + return ret; 998 + } 999 + 1000 + int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info) 1001 + { 1002 + struct dpll_pin *pin = info->user_ptr[0]; 1003 + 1004 + return dpll_pin_set_from_nlattr(pin, info); 1005 + } 1006 + 1007 + static struct dpll_device * 1008 + dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr, 1009 + enum dpll_type type, struct netlink_ext_ack *extack) 1010 + { 1011 + struct dpll_device *dpll_match = NULL, *dpll; 1012 + bool cid_match, mod_match, type_match; 1013 + unsigned long i; 1014 + 1015 + xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) { 1016 + cid_match = clock_id ? dpll->clock_id == clock_id : true; 1017 + mod_match = mod_name_attr ? (module_name(dpll->module) ? 1018 + !nla_strcmp(mod_name_attr, 1019 + module_name(dpll->module)) : false) : true; 1020 + type_match = type ? dpll->type == type : true; 1021 + if (cid_match && mod_match && type_match) { 1022 + if (dpll_match) { 1023 + NL_SET_ERR_MSG(extack, "multiple matches"); 1024 + return ERR_PTR(-EINVAL); 1025 + } 1026 + dpll_match = dpll; 1027 + } 1028 + } 1029 + if (!dpll_match) { 1030 + NL_SET_ERR_MSG(extack, "not found"); 1031 + return ERR_PTR(-ENODEV); 1032 + } 1033 + 1034 + return dpll_match; 1035 + } 1036 + 1037 + static struct dpll_device * 1038 + dpll_device_find_from_nlattr(struct genl_info *info) 1039 + { 1040 + struct nlattr *attr, *mod_name_attr = NULL; 1041 + enum dpll_type type = 0; 1042 + u64 clock_id = 0; 1043 + int rem = 0; 1044 + 1045 + nla_for_each_attr(attr, genlmsg_data(info->genlhdr), 1046 + genlmsg_len(info->genlhdr), rem) { 1047 + switch (nla_type(attr)) { 1048 + case DPLL_A_CLOCK_ID: 1049 + if (clock_id) 1050 + goto duplicated_attr; 1051 + clock_id = nla_get_u64(attr); 1052 + break; 1053 + case DPLL_A_MODULE_NAME: 1054 + if (mod_name_attr) 1055 + goto duplicated_attr; 1056 + mod_name_attr = attr; 1057 + break; 1058 + case DPLL_A_TYPE: 1059 + if (type) 1060 + goto duplicated_attr; 1061 + type = nla_get_u32(attr); 1062 + break; 1063 + default: 1064 + break; 1065 + } 1066 + } 1067 + if (!clock_id && !mod_name_attr && !type) { 1068 + NL_SET_ERR_MSG(info->extack, "missing attributes"); 1069 + return ERR_PTR(-EINVAL); 1070 + } 1071 + return dpll_device_find(clock_id, mod_name_attr, type, info->extack); 1072 + duplicated_attr: 1073 + NL_SET_ERR_MSG(info->extack, "duplicated attribute"); 1074 + return ERR_PTR(-EINVAL); 1075 + } 1076 + 1077 + int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info) 1078 + { 1079 + struct dpll_device *dpll; 1080 + struct sk_buff *msg; 1081 + struct nlattr *hdr; 1082 + int ret; 1083 + 1084 + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1085 + if (!msg) 1086 + return -ENOMEM; 1087 + hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1088 + DPLL_CMD_DEVICE_ID_GET); 1089 + if (!hdr) 1090 + return -EMSGSIZE; 1091 + 1092 + dpll = dpll_device_find_from_nlattr(info); 1093 + if (!IS_ERR(dpll)) { 1094 + ret = dpll_msg_add_dev_handle(msg, dpll); 1095 + if (ret) { 1096 + nlmsg_free(msg); 1097 + return ret; 1098 + } 1099 + } 1100 + genlmsg_end(msg, hdr); 1101 + 1102 + return genlmsg_reply(msg, info); 1103 + } 1104 + 1105 + int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info) 1106 + { 1107 + struct dpll_device *dpll = info->user_ptr[0]; 1108 + struct sk_buff *msg; 1109 + struct nlattr *hdr; 1110 + int ret; 1111 + 1112 + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1113 + if (!msg) 1114 + return -ENOMEM; 1115 + hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, 1116 + DPLL_CMD_DEVICE_GET); 1117 + if (!hdr) 1118 + return -EMSGSIZE; 1119 + 1120 + ret = dpll_device_get_one(dpll, msg, info->extack); 1121 + if (ret) { 1122 + nlmsg_free(msg); 1123 + return ret; 1124 + } 1125 + genlmsg_end(msg, hdr); 1126 + 1127 + return genlmsg_reply(msg, info); 1128 + } 1129 + 1130 + int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info) 1131 + { 1132 + /* placeholder for set command */ 1133 + return 0; 1134 + } 1135 + 1136 + int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 1137 + { 1138 + struct dpll_dump_ctx *ctx = dpll_dump_context(cb); 1139 + struct dpll_device *dpll; 1140 + struct nlattr *hdr; 1141 + unsigned long i; 1142 + int ret = 0; 1143 + 1144 + xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED, 1145 + ctx->idx) { 1146 + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 1147 + cb->nlh->nlmsg_seq, &dpll_nl_family, 1148 + NLM_F_MULTI, DPLL_CMD_DEVICE_GET); 1149 + if (!hdr) { 1150 + ret = -EMSGSIZE; 1151 + break; 1152 + } 1153 + ret = dpll_device_get_one(dpll, skb, cb->extack); 1154 + if (ret) { 1155 + genlmsg_cancel(skb, hdr); 1156 + break; 1157 + } 1158 + genlmsg_end(skb, hdr); 1159 + } 1160 + if (ret == -EMSGSIZE) { 1161 + ctx->idx = i; 1162 + return skb->len; 1163 + } 1164 + return ret; 1165 + } 1166 + 1167 + int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1168 + struct genl_info *info) 1169 + { 1170 + u32 id; 1171 + 1172 + if (GENL_REQ_ATTR_CHECK(info, DPLL_A_ID)) 1173 + return -EINVAL; 1174 + 1175 + mutex_lock(&dpll_lock); 1176 + id = nla_get_u32(info->attrs[DPLL_A_ID]); 1177 + info->user_ptr[0] = dpll_device_get_by_id(id); 1178 + if (!info->user_ptr[0]) { 1179 + NL_SET_ERR_MSG(info->extack, "device not found"); 1180 + goto unlock; 1181 + } 1182 + return 0; 1183 + unlock: 1184 + mutex_unlock(&dpll_lock); 1185 + return -ENODEV; 1186 + } 1187 + 1188 + void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1189 + struct genl_info *info) 1190 + { 1191 + mutex_unlock(&dpll_lock); 1192 + } 1193 + 1194 + int 1195 + dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1196 + struct genl_info *info) 1197 + { 1198 + mutex_lock(&dpll_lock); 1199 + 1200 + return 0; 1201 + } 1202 + 1203 + void 1204 + dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1205 + struct genl_info *info) 1206 + { 1207 + mutex_unlock(&dpll_lock); 1208 + } 1209 + 1210 + int dpll_lock_dumpit(struct netlink_callback *cb) 1211 + { 1212 + mutex_lock(&dpll_lock); 1213 + 1214 + return 0; 1215 + } 1216 + 1217 + int dpll_unlock_dumpit(struct netlink_callback *cb) 1218 + { 1219 + mutex_unlock(&dpll_lock); 1220 + 1221 + return 0; 1222 + } 1223 + 1224 + int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1225 + struct genl_info *info) 1226 + { 1227 + int ret; 1228 + 1229 + mutex_lock(&dpll_lock); 1230 + if (GENL_REQ_ATTR_CHECK(info, DPLL_A_PIN_ID)) { 1231 + ret = -EINVAL; 1232 + goto unlock_dev; 1233 + } 1234 + info->user_ptr[0] = xa_load(&dpll_pin_xa, 1235 + nla_get_u32(info->attrs[DPLL_A_PIN_ID])); 1236 + if (!info->user_ptr[0]) { 1237 + NL_SET_ERR_MSG(info->extack, "pin not found"); 1238 + ret = -ENODEV; 1239 + goto unlock_dev; 1240 + } 1241 + 1242 + return 0; 1243 + 1244 + unlock_dev: 1245 + mutex_unlock(&dpll_lock); 1246 + return ret; 1247 + } 1248 + 1249 + void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 1250 + struct genl_info *info) 1251 + { 1252 + mutex_unlock(&dpll_lock); 1253 + }
+13
drivers/dpll/dpll_netlink.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates 4 + * Copyright (c) 2023 Intel and affiliates 5 + */ 6 + 7 + int dpll_device_create_ntf(struct dpll_device *dpll); 8 + 9 + int dpll_device_delete_ntf(struct dpll_device *dpll); 10 + 11 + int dpll_pin_create_ntf(struct dpll_pin *pin); 12 + 13 + int dpll_pin_delete_ntf(struct dpll_pin *pin);
+162
drivers/dpll/dpll_nl.c
··· 1 + // SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/dpll.yaml */ 4 + /* YNL-GEN kernel source */ 5 + 6 + #include <net/netlink.h> 7 + #include <net/genetlink.h> 8 + 9 + #include "dpll_nl.h" 10 + 11 + #include <uapi/linux/dpll.h> 12 + 13 + /* Common nested types */ 14 + const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_STATE + 1] = { 15 + [DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, }, 16 + [DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2), 17 + [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, 18 + [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), 19 + }; 20 + 21 + const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = { 22 + [DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, }, 23 + [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), 24 + }; 25 + 26 + /* DPLL_CMD_DEVICE_ID_GET - do */ 27 + static const struct nla_policy dpll_device_id_get_nl_policy[DPLL_A_TYPE + 1] = { 28 + [DPLL_A_MODULE_NAME] = { .type = NLA_NUL_STRING, }, 29 + [DPLL_A_CLOCK_ID] = { .type = NLA_U64, }, 30 + [DPLL_A_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 2), 31 + }; 32 + 33 + /* DPLL_CMD_DEVICE_GET - do */ 34 + static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_ID + 1] = { 35 + [DPLL_A_ID] = { .type = NLA_U32, }, 36 + }; 37 + 38 + /* DPLL_CMD_DEVICE_SET - do */ 39 + static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_ID + 1] = { 40 + [DPLL_A_ID] = { .type = NLA_U32, }, 41 + }; 42 + 43 + /* DPLL_CMD_PIN_ID_GET - do */ 44 + static const struct nla_policy dpll_pin_id_get_nl_policy[DPLL_A_PIN_TYPE + 1] = { 45 + [DPLL_A_PIN_MODULE_NAME] = { .type = NLA_NUL_STRING, }, 46 + [DPLL_A_PIN_CLOCK_ID] = { .type = NLA_U64, }, 47 + [DPLL_A_PIN_BOARD_LABEL] = { .type = NLA_NUL_STRING, }, 48 + [DPLL_A_PIN_PANEL_LABEL] = { .type = NLA_NUL_STRING, }, 49 + [DPLL_A_PIN_PACKAGE_LABEL] = { .type = NLA_NUL_STRING, }, 50 + [DPLL_A_PIN_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 5), 51 + }; 52 + 53 + /* DPLL_CMD_PIN_GET - do */ 54 + static const struct nla_policy dpll_pin_get_do_nl_policy[DPLL_A_PIN_ID + 1] = { 55 + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, 56 + }; 57 + 58 + /* DPLL_CMD_PIN_GET - dump */ 59 + static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_PIN_ID + 1] = { 60 + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, 61 + }; 62 + 63 + /* DPLL_CMD_PIN_SET - do */ 64 + static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT_PIN + 1] = { 65 + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, 66 + [DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, }, 67 + [DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2), 68 + [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, 69 + [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), 70 + [DPLL_A_PIN_PARENT_DEVICE] = NLA_POLICY_NESTED(dpll_pin_parent_device_nl_policy), 71 + [DPLL_A_PIN_PARENT_PIN] = NLA_POLICY_NESTED(dpll_pin_parent_pin_nl_policy), 72 + }; 73 + 74 + /* Ops table for dpll */ 75 + static const struct genl_split_ops dpll_nl_ops[] = { 76 + { 77 + .cmd = DPLL_CMD_DEVICE_ID_GET, 78 + .pre_doit = dpll_lock_doit, 79 + .doit = dpll_nl_device_id_get_doit, 80 + .post_doit = dpll_unlock_doit, 81 + .policy = dpll_device_id_get_nl_policy, 82 + .maxattr = DPLL_A_TYPE, 83 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 84 + }, 85 + { 86 + .cmd = DPLL_CMD_DEVICE_GET, 87 + .pre_doit = dpll_pre_doit, 88 + .doit = dpll_nl_device_get_doit, 89 + .post_doit = dpll_post_doit, 90 + .policy = dpll_device_get_nl_policy, 91 + .maxattr = DPLL_A_ID, 92 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 93 + }, 94 + { 95 + .cmd = DPLL_CMD_DEVICE_GET, 96 + .start = dpll_lock_dumpit, 97 + .dumpit = dpll_nl_device_get_dumpit, 98 + .done = dpll_unlock_dumpit, 99 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, 100 + }, 101 + { 102 + .cmd = DPLL_CMD_DEVICE_SET, 103 + .pre_doit = dpll_pre_doit, 104 + .doit = dpll_nl_device_set_doit, 105 + .post_doit = dpll_post_doit, 106 + .policy = dpll_device_set_nl_policy, 107 + .maxattr = DPLL_A_ID, 108 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 109 + }, 110 + { 111 + .cmd = DPLL_CMD_PIN_ID_GET, 112 + .pre_doit = dpll_lock_doit, 113 + .doit = dpll_nl_pin_id_get_doit, 114 + .post_doit = dpll_unlock_doit, 115 + .policy = dpll_pin_id_get_nl_policy, 116 + .maxattr = DPLL_A_PIN_TYPE, 117 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 118 + }, 119 + { 120 + .cmd = DPLL_CMD_PIN_GET, 121 + .pre_doit = dpll_pin_pre_doit, 122 + .doit = dpll_nl_pin_get_doit, 123 + .post_doit = dpll_pin_post_doit, 124 + .policy = dpll_pin_get_do_nl_policy, 125 + .maxattr = DPLL_A_PIN_ID, 126 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 127 + }, 128 + { 129 + .cmd = DPLL_CMD_PIN_GET, 130 + .start = dpll_lock_dumpit, 131 + .dumpit = dpll_nl_pin_get_dumpit, 132 + .done = dpll_unlock_dumpit, 133 + .policy = dpll_pin_get_dump_nl_policy, 134 + .maxattr = DPLL_A_PIN_ID, 135 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, 136 + }, 137 + { 138 + .cmd = DPLL_CMD_PIN_SET, 139 + .pre_doit = dpll_pin_pre_doit, 140 + .doit = dpll_nl_pin_set_doit, 141 + .post_doit = dpll_pin_post_doit, 142 + .policy = dpll_pin_set_nl_policy, 143 + .maxattr = DPLL_A_PIN_PARENT_PIN, 144 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 145 + }, 146 + }; 147 + 148 + static const struct genl_multicast_group dpll_nl_mcgrps[] = { 149 + [DPLL_NLGRP_MONITOR] = { "monitor", }, 150 + }; 151 + 152 + struct genl_family dpll_nl_family __ro_after_init = { 153 + .name = DPLL_FAMILY_NAME, 154 + .version = DPLL_FAMILY_VERSION, 155 + .netnsok = true, 156 + .parallel_ops = true, 157 + .module = THIS_MODULE, 158 + .split_ops = dpll_nl_ops, 159 + .n_split_ops = ARRAY_SIZE(dpll_nl_ops), 160 + .mcgrps = dpll_nl_mcgrps, 161 + .n_mcgrps = ARRAY_SIZE(dpll_nl_mcgrps), 162 + };
+51
drivers/dpll/dpll_nl.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/dpll.yaml */ 4 + /* YNL-GEN kernel header */ 5 + 6 + #ifndef _LINUX_DPLL_GEN_H 7 + #define _LINUX_DPLL_GEN_H 8 + 9 + #include <net/netlink.h> 10 + #include <net/genetlink.h> 11 + 12 + #include <uapi/linux/dpll.h> 13 + 14 + /* Common nested types */ 15 + extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_STATE + 1]; 16 + extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1]; 17 + 18 + int dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 19 + struct genl_info *info); 20 + int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 21 + struct genl_info *info); 22 + int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 23 + struct genl_info *info); 24 + void 25 + dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 26 + struct genl_info *info); 27 + void 28 + dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 29 + struct genl_info *info); 30 + void 31 + dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, 32 + struct genl_info *info); 33 + int dpll_lock_dumpit(struct netlink_callback *cb); 34 + int dpll_unlock_dumpit(struct netlink_callback *cb); 35 + 36 + int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info); 37 + int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info); 38 + int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); 39 + int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info); 40 + int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info); 41 + int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info); 42 + int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); 43 + int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info); 44 + 45 + enum { 46 + DPLL_NLGRP_MONITOR, 47 + }; 48 + 49 + extern struct genl_family dpll_nl_family; 50 + 51 + #endif /* _LINUX_DPLL_GEN_H */
+1
drivers/net/ethernet/intel/Kconfig
··· 284 284 select DIMLIB 285 285 select NET_DEVLINK 286 286 select PLDMFW 287 + select DPLL 287 288 help 288 289 This driver supports Intel(R) Ethernet Connection E800 Series of 289 290 devices. For more information on how to identify your adapter, go
+2 -1
drivers/net/ethernet/intel/ice/Makefile
··· 34 34 ice_lag.o \ 35 35 ice_ethtool.o \ 36 36 ice_repr.o \ 37 - ice_tc_lib.o 37 + ice_tc_lib.o \ 38 + ice_dpll.o 38 39 ice-$(CONFIG_PCI_IOV) += \ 39 40 ice_sriov.o \ 40 41 ice_virtchnl.o \
+5
drivers/net/ethernet/intel/ice/ice.h
··· 76 76 #include "ice_vsi_vlan_ops.h" 77 77 #include "ice_gnss.h" 78 78 #include "ice_irq.h" 79 + #include "ice_dpll.h" 79 80 80 81 #define ICE_BAR0 0 81 82 #define ICE_REQ_DESC_MULTIPLE 32 ··· 199 198 enum ice_feature { 200 199 ICE_F_DSCP, 201 200 ICE_F_PTP_EXTTS, 201 + ICE_F_PHY_RCLK, 202 202 ICE_F_SMA_CTRL, 203 + ICE_F_CGU, 203 204 ICE_F_GNSS, 204 205 ICE_F_ROCE_LAG, 205 206 ICE_F_SRIOV_LAG, ··· 511 508 ICE_FLAG_UNPLUG_AUX_DEV, 512 509 ICE_FLAG_MTU_CHANGED, 513 510 ICE_FLAG_GNSS, /* GNSS successfully initialized */ 511 + ICE_FLAG_DPLL, /* SyncE/PTP dplls initialized */ 514 512 ICE_PF_FLAGS_NBITS /* must be last */ 515 513 }; 516 514 ··· 644 640 #define ICE_VF_AGG_NODE_ID_START 65 645 641 #define ICE_MAX_VF_AGG_NODES 32 646 642 struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES]; 643 + struct ice_dplls dplls; 647 644 }; 648 645 649 646 extern struct workqueue_struct *ice_lag_wq;
+244 -2
drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
··· 1351 1351 u8 reserved[15]; 1352 1352 }; 1353 1353 1354 + /* Set PHY recovered clock output (direct 0x0630) */ 1355 + struct ice_aqc_set_phy_rec_clk_out { 1356 + u8 phy_output; 1357 + u8 port_num; 1358 + #define ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT 0xFF 1359 + u8 flags; 1360 + #define ICE_AQC_SET_PHY_REC_CLK_OUT_OUT_EN BIT(0) 1361 + u8 rsvd; 1362 + __le32 freq; 1363 + u8 rsvd2[6]; 1364 + __le16 node_handle; 1365 + }; 1366 + 1367 + /* Get PHY recovered clock output (direct 0x0631) */ 1368 + struct ice_aqc_get_phy_rec_clk_out { 1369 + u8 phy_output; 1370 + u8 port_num; 1371 + #define ICE_AQC_GET_PHY_REC_CLK_OUT_CURR_PORT 0xFF 1372 + u8 flags; 1373 + #define ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN BIT(0) 1374 + u8 rsvd[11]; 1375 + __le16 node_handle; 1376 + }; 1377 + 1354 1378 struct ice_aqc_link_topo_params { 1355 1379 u8 lport_num; 1356 1380 u8 lport_num_valid; ··· 1391 1367 #define ICE_AQC_LINK_TOPO_NODE_TYPE_CAGE 6 1392 1368 #define ICE_AQC_LINK_TOPO_NODE_TYPE_MEZZ 7 1393 1369 #define ICE_AQC_LINK_TOPO_NODE_TYPE_ID_EEPROM 8 1370 + #define ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL 9 1371 + #define ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_MUX 10 1394 1372 #define ICE_AQC_LINK_TOPO_NODE_CTX_S 4 1395 1373 #define ICE_AQC_LINK_TOPO_NODE_CTX_M \ 1396 1374 (0xF << ICE_AQC_LINK_TOPO_NODE_CTX_S) ··· 1429 1403 struct ice_aqc_get_link_topo { 1430 1404 struct ice_aqc_link_topo_addr addr; 1431 1405 u8 node_part_num; 1432 - #define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575 0x21 1433 - #define ICE_AQC_GET_LINK_TOPO_NODE_NR_C827 0x31 1406 + #define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575 0x21 1407 + #define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032 0x24 1408 + #define ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384 0x25 1409 + #define ICE_AQC_GET_LINK_TOPO_NODE_NR_E822_PHY 0x30 1410 + #define ICE_AQC_GET_LINK_TOPO_NODE_NR_C827 0x31 1411 + #define ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX 0x47 1434 1412 u8 rsvd[9]; 1435 1413 }; 1436 1414 ··· 2155 2125 struct ice_aqc_get_pkg_info pkg_info[]; 2156 2126 }; 2157 2127 2128 + /* Get CGU abilities command response data structure (indirect 0x0C61) */ 2129 + struct ice_aqc_get_cgu_abilities { 2130 + u8 num_inputs; 2131 + u8 num_outputs; 2132 + u8 pps_dpll_idx; 2133 + u8 eec_dpll_idx; 2134 + __le32 max_in_freq; 2135 + __le32 max_in_phase_adj; 2136 + __le32 max_out_freq; 2137 + __le32 max_out_phase_adj; 2138 + u8 cgu_part_num; 2139 + u8 rsvd[3]; 2140 + }; 2141 + 2142 + /* Set CGU input config (direct 0x0C62) */ 2143 + struct ice_aqc_set_cgu_input_config { 2144 + u8 input_idx; 2145 + u8 flags1; 2146 + #define ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_FREQ BIT(6) 2147 + #define ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_DELAY BIT(7) 2148 + u8 flags2; 2149 + #define ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN BIT(5) 2150 + #define ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN BIT(6) 2151 + u8 rsvd; 2152 + __le32 freq; 2153 + __le32 phase_delay; 2154 + u8 rsvd2[2]; 2155 + __le16 node_handle; 2156 + }; 2157 + 2158 + /* Get CGU input config response descriptor structure (direct 0x0C63) */ 2159 + struct ice_aqc_get_cgu_input_config { 2160 + u8 input_idx; 2161 + u8 status; 2162 + #define ICE_AQC_GET_CGU_IN_CFG_STATUS_LOS BIT(0) 2163 + #define ICE_AQC_GET_CGU_IN_CFG_STATUS_SCM_FAIL BIT(1) 2164 + #define ICE_AQC_GET_CGU_IN_CFG_STATUS_CFM_FAIL BIT(2) 2165 + #define ICE_AQC_GET_CGU_IN_CFG_STATUS_GST_FAIL BIT(3) 2166 + #define ICE_AQC_GET_CGU_IN_CFG_STATUS_PFM_FAIL BIT(4) 2167 + #define ICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_FAIL BIT(6) 2168 + #define ICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_CAP BIT(7) 2169 + u8 type; 2170 + #define ICE_AQC_GET_CGU_IN_CFG_TYPE_READ_ONLY BIT(0) 2171 + #define ICE_AQC_GET_CGU_IN_CFG_TYPE_GPS BIT(4) 2172 + #define ICE_AQC_GET_CGU_IN_CFG_TYPE_EXTERNAL BIT(5) 2173 + #define ICE_AQC_GET_CGU_IN_CFG_TYPE_PHY BIT(6) 2174 + u8 flags1; 2175 + #define ICE_AQC_GET_CGU_IN_CFG_FLG1_PHASE_DELAY_SUPP BIT(0) 2176 + #define ICE_AQC_GET_CGU_IN_CFG_FLG1_1PPS_SUPP BIT(2) 2177 + #define ICE_AQC_GET_CGU_IN_CFG_FLG1_10MHZ_SUPP BIT(3) 2178 + #define ICE_AQC_GET_CGU_IN_CFG_FLG1_ANYFREQ BIT(7) 2179 + __le32 freq; 2180 + __le32 phase_delay; 2181 + u8 flags2; 2182 + #define ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN BIT(5) 2183 + #define ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN BIT(6) 2184 + u8 rsvd[1]; 2185 + __le16 node_handle; 2186 + }; 2187 + 2188 + /* Set CGU output config (direct 0x0C64) */ 2189 + struct ice_aqc_set_cgu_output_config { 2190 + u8 output_idx; 2191 + u8 flags; 2192 + #define ICE_AQC_SET_CGU_OUT_CFG_OUT_EN BIT(0) 2193 + #define ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN BIT(1) 2194 + #define ICE_AQC_SET_CGU_OUT_CFG_UPDATE_FREQ BIT(2) 2195 + #define ICE_AQC_SET_CGU_OUT_CFG_UPDATE_PHASE BIT(3) 2196 + #define ICE_AQC_SET_CGU_OUT_CFG_UPDATE_SRC_SEL BIT(4) 2197 + u8 src_sel; 2198 + #define ICE_AQC_SET_CGU_OUT_CFG_DPLL_SRC_SEL ICE_M(0x1F, 0) 2199 + u8 rsvd; 2200 + __le32 freq; 2201 + __le32 phase_delay; 2202 + u8 rsvd2[2]; 2203 + __le16 node_handle; 2204 + }; 2205 + 2206 + /* Get CGU output config (direct 0x0C65) */ 2207 + struct ice_aqc_get_cgu_output_config { 2208 + u8 output_idx; 2209 + u8 flags; 2210 + #define ICE_AQC_GET_CGU_OUT_CFG_OUT_EN BIT(0) 2211 + #define ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN BIT(1) 2212 + #define ICE_AQC_GET_CGU_OUT_CFG_ESYNC_ABILITY BIT(2) 2213 + u8 src_sel; 2214 + #define ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL_SHIFT 0 2215 + #define ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL \ 2216 + ICE_M(0x1F, ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL_SHIFT) 2217 + #define ICE_AQC_GET_CGU_OUT_CFG_DPLL_MODE_SHIFT 5 2218 + #define ICE_AQC_GET_CGU_OUT_CFG_DPLL_MODE \ 2219 + ICE_M(0x7, ICE_AQC_GET_CGU_OUT_CFG_DPLL_MODE_SHIFT) 2220 + u8 rsvd; 2221 + __le32 freq; 2222 + __le32 src_freq; 2223 + u8 rsvd2[2]; 2224 + __le16 node_handle; 2225 + }; 2226 + 2227 + /* Get CGU DPLL status (direct 0x0C66) */ 2228 + struct ice_aqc_get_cgu_dpll_status { 2229 + u8 dpll_num; 2230 + u8 ref_state; 2231 + #define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_LOS BIT(0) 2232 + #define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_SCM BIT(1) 2233 + #define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_CFM BIT(2) 2234 + #define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_GST BIT(3) 2235 + #define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_PFM BIT(4) 2236 + #define ICE_AQC_GET_CGU_DPLL_STATUS_FAST_LOCK_EN BIT(5) 2237 + #define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_ESYNC BIT(6) 2238 + u8 dpll_state; 2239 + #define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_LOCK BIT(0) 2240 + #define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO BIT(1) 2241 + #define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO_READY BIT(2) 2242 + #define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_FLHIT BIT(5) 2243 + #define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_PSLHIT BIT(7) 2244 + u8 config; 2245 + #define ICE_AQC_GET_CGU_DPLL_CONFIG_CLK_REF_SEL ICE_M(0x1F, 0) 2246 + #define ICE_AQC_GET_CGU_DPLL_CONFIG_MODE_SHIFT 5 2247 + #define ICE_AQC_GET_CGU_DPLL_CONFIG_MODE \ 2248 + ICE_M(0x7, ICE_AQC_GET_CGU_DPLL_CONFIG_MODE_SHIFT) 2249 + #define ICE_AQC_GET_CGU_DPLL_CONFIG_MODE_FREERUN 0 2250 + #define ICE_AQC_GET_CGU_DPLL_CONFIG_MODE_AUTOMATIC \ 2251 + ICE_M(0x3, ICE_AQC_GET_CGU_DPLL_CONFIG_MODE_SHIFT) 2252 + __le32 phase_offset_h; 2253 + __le32 phase_offset_l; 2254 + u8 eec_mode; 2255 + #define ICE_AQC_GET_CGU_DPLL_STATUS_EEC_MODE_1 0xA 2256 + #define ICE_AQC_GET_CGU_DPLL_STATUS_EEC_MODE_2 0xB 2257 + #define ICE_AQC_GET_CGU_DPLL_STATUS_EEC_MODE_UNKNOWN 0xF 2258 + u8 rsvd[1]; 2259 + __le16 node_handle; 2260 + }; 2261 + 2262 + /* Set CGU DPLL config (direct 0x0C67) */ 2263 + struct ice_aqc_set_cgu_dpll_config { 2264 + u8 dpll_num; 2265 + u8 ref_state; 2266 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_LOS BIT(0) 2267 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_SCM BIT(1) 2268 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_CFM BIT(2) 2269 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_GST BIT(3) 2270 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_PFM BIT(4) 2271 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_FLOCK_EN BIT(5) 2272 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_ESYNC BIT(6) 2273 + u8 rsvd; 2274 + u8 config; 2275 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_CLK_REF_SEL ICE_M(0x1F, 0) 2276 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_MODE_SHIFT 5 2277 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_MODE \ 2278 + ICE_M(0x7, ICE_AQC_SET_CGU_DPLL_CONFIG_MODE_SHIFT) 2279 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_MODE_FREERUN 0 2280 + #define ICE_AQC_SET_CGU_DPLL_CONFIG_MODE_AUTOMATIC \ 2281 + ICE_M(0x3, ICE_AQC_SET_CGU_DPLL_CONFIG_MODE_SHIFT) 2282 + u8 rsvd2[8]; 2283 + u8 eec_mode; 2284 + u8 rsvd3[1]; 2285 + __le16 node_handle; 2286 + }; 2287 + 2288 + /* Set CGU reference priority (direct 0x0C68) */ 2289 + struct ice_aqc_set_cgu_ref_prio { 2290 + u8 dpll_num; 2291 + u8 ref_idx; 2292 + u8 ref_priority; 2293 + u8 rsvd[11]; 2294 + __le16 node_handle; 2295 + }; 2296 + 2297 + /* Get CGU reference priority (direct 0x0C69) */ 2298 + struct ice_aqc_get_cgu_ref_prio { 2299 + u8 dpll_num; 2300 + u8 ref_idx; 2301 + u8 ref_priority; /* Valid only in response */ 2302 + u8 rsvd[13]; 2303 + }; 2304 + 2305 + /* Get CGU info (direct 0x0C6A) */ 2306 + struct ice_aqc_get_cgu_info { 2307 + __le32 cgu_id; 2308 + __le32 cgu_cfg_ver; 2309 + __le32 cgu_fw_ver; 2310 + u8 node_part_num; 2311 + u8 dev_rev; 2312 + __le16 node_handle; 2313 + }; 2314 + 2158 2315 /* Driver Shared Parameters (direct, 0x0C90) */ 2159 2316 struct ice_aqc_driver_shared_params { 2160 2317 u8 set_or_get_op; ··· 2411 2194 struct ice_aqc_get_phy_caps get_phy; 2412 2195 struct ice_aqc_set_phy_cfg set_phy; 2413 2196 struct ice_aqc_restart_an restart_an; 2197 + struct ice_aqc_set_phy_rec_clk_out set_phy_rec_clk_out; 2198 + struct ice_aqc_get_phy_rec_clk_out get_phy_rec_clk_out; 2414 2199 struct ice_aqc_gpio read_write_gpio; 2415 2200 struct ice_aqc_sff_eeprom read_write_sff_param; 2416 2201 struct ice_aqc_set_port_id_led set_port_id_led; ··· 2453 2234 struct ice_aqc_fw_logging fw_logging; 2454 2235 struct ice_aqc_get_clear_fw_log get_clear_fw_log; 2455 2236 struct ice_aqc_download_pkg download_pkg; 2237 + struct ice_aqc_set_cgu_input_config set_cgu_input_config; 2238 + struct ice_aqc_get_cgu_input_config get_cgu_input_config; 2239 + struct ice_aqc_set_cgu_output_config set_cgu_output_config; 2240 + struct ice_aqc_get_cgu_output_config get_cgu_output_config; 2241 + struct ice_aqc_get_cgu_dpll_status get_cgu_dpll_status; 2242 + struct ice_aqc_set_cgu_dpll_config set_cgu_dpll_config; 2243 + struct ice_aqc_set_cgu_ref_prio set_cgu_ref_prio; 2244 + struct ice_aqc_get_cgu_ref_prio get_cgu_ref_prio; 2245 + struct ice_aqc_get_cgu_info get_cgu_info; 2456 2246 struct ice_aqc_driver_shared_params drv_shared_params; 2457 2247 struct ice_aqc_set_mac_lb set_mac_lb; 2458 2248 struct ice_aqc_alloc_free_res_cmd sw_res_ctrl; ··· 2586 2358 ice_aqc_opc_get_link_status = 0x0607, 2587 2359 ice_aqc_opc_set_event_mask = 0x0613, 2588 2360 ice_aqc_opc_set_mac_lb = 0x0620, 2361 + ice_aqc_opc_set_phy_rec_clk_out = 0x0630, 2362 + ice_aqc_opc_get_phy_rec_clk_out = 0x0631, 2589 2363 ice_aqc_opc_get_link_topo = 0x06E0, 2590 2364 ice_aqc_opc_read_i2c = 0x06E2, 2591 2365 ice_aqc_opc_write_i2c = 0x06E3, ··· 2642 2412 ice_aqc_opc_upload_section = 0x0C41, 2643 2413 ice_aqc_opc_update_pkg = 0x0C42, 2644 2414 ice_aqc_opc_get_pkg_info_list = 0x0C43, 2415 + 2416 + /* 1588/SyncE commands/events */ 2417 + ice_aqc_opc_get_cgu_abilities = 0x0C61, 2418 + ice_aqc_opc_set_cgu_input_config = 0x0C62, 2419 + ice_aqc_opc_get_cgu_input_config = 0x0C63, 2420 + ice_aqc_opc_set_cgu_output_config = 0x0C64, 2421 + ice_aqc_opc_get_cgu_output_config = 0x0C65, 2422 + ice_aqc_opc_get_cgu_dpll_status = 0x0C66, 2423 + ice_aqc_opc_set_cgu_dpll_config = 0x0C67, 2424 + ice_aqc_opc_set_cgu_ref_prio = 0x0C68, 2425 + ice_aqc_opc_get_cgu_ref_prio = 0x0C69, 2426 + ice_aqc_opc_get_cgu_info = 0x0C6A, 2645 2427 2646 2428 ice_aqc_opc_driver_shared_params = 0x0C90, 2647 2429
+465 -27
drivers/net/ethernet/intel/ice/ice_common.c
··· 8 8 #include "ice_ptp_hw.h" 9 9 10 10 #define ICE_PF_RESET_WAIT_COUNT 300 11 + #define ICE_MAX_NETLIST_SIZE 10 11 12 12 13 static const char * const ice_link_mode_str_low[] = { 13 14 [0] = "100BASE_TX", ··· 434 433 (ICE_AQC_LINK_TOPO_NODE_TYPE_M & node_type); 435 434 436 435 return ice_aq_send_cmd(pi->hw, &desc, NULL, 0, cd); 436 + } 437 + 438 + /** 439 + * ice_aq_get_netlist_node 440 + * @hw: pointer to the hw struct 441 + * @cmd: get_link_topo AQ structure 442 + * @node_part_number: output node part number if node found 443 + * @node_handle: output node handle parameter if node found 444 + * 445 + * Get netlist node handle. 446 + */ 447 + int 448 + ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, 449 + u8 *node_part_number, u16 *node_handle) 450 + { 451 + struct ice_aq_desc desc; 452 + 453 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 454 + desc.params.get_link_topo = *cmd; 455 + 456 + if (ice_aq_send_cmd(hw, &desc, NULL, 0, NULL)) 457 + return -EINTR; 458 + 459 + if (node_handle) 460 + *node_handle = 461 + le16_to_cpu(desc.params.get_link_topo.addr.handle); 462 + if (node_part_number) 463 + *node_part_number = desc.params.get_link_topo.node_part_num; 464 + 465 + return 0; 466 + } 467 + 468 + /** 469 + * ice_find_netlist_node 470 + * @hw: pointer to the hw struct 471 + * @node_type_ctx: type of netlist node to look for 472 + * @node_part_number: node part number to look for 473 + * @node_handle: output parameter if node found - optional 474 + * 475 + * Find and return the node handle for a given node type and part number in the 476 + * netlist. When found ICE_SUCCESS is returned, ICE_ERR_DOES_NOT_EXIST 477 + * otherwise. If node_handle provided, it would be set to found node handle. 478 + */ 479 + int 480 + ice_find_netlist_node(struct ice_hw *hw, u8 node_type_ctx, u8 node_part_number, 481 + u16 *node_handle) 482 + { 483 + struct ice_aqc_get_link_topo cmd; 484 + u8 rec_node_part_number; 485 + u16 rec_node_handle; 486 + u8 idx; 487 + 488 + for (idx = 0; idx < ICE_MAX_NETLIST_SIZE; idx++) { 489 + int status; 490 + 491 + memset(&cmd, 0, sizeof(cmd)); 492 + 493 + cmd.addr.topo_params.node_type_ctx = 494 + (node_type_ctx << ICE_AQC_LINK_TOPO_NODE_TYPE_S); 495 + cmd.addr.topo_params.index = idx; 496 + 497 + status = ice_aq_get_netlist_node(hw, &cmd, 498 + &rec_node_part_number, 499 + &rec_node_handle); 500 + if (status) 501 + return status; 502 + 503 + if (rec_node_part_number == node_part_number) { 504 + if (node_handle) 505 + *node_handle = rec_node_handle; 506 + return 0; 507 + } 508 + } 509 + 510 + return -ENOTBLK; 437 511 } 438 512 439 513 /** ··· 2728 2652 } 2729 2653 2730 2654 ice_recalc_port_limited_caps(hw, &dev_p->common_cap); 2731 - } 2732 - 2733 - /** 2734 - * ice_aq_get_netlist_node 2735 - * @hw: pointer to the hw struct 2736 - * @cmd: get_link_topo AQ structure 2737 - * @node_part_number: output node part number if node found 2738 - * @node_handle: output node handle parameter if node found 2739 - */ 2740 - static int 2741 - ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, 2742 - u8 *node_part_number, u16 *node_handle) 2743 - { 2744 - struct ice_aq_desc desc; 2745 - 2746 - ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 2747 - desc.params.get_link_topo = *cmd; 2748 - 2749 - if (ice_aq_send_cmd(hw, &desc, NULL, 0, NULL)) 2750 - return -EIO; 2751 - 2752 - if (node_handle) 2753 - *node_handle = le16_to_cpu(desc.params.get_link_topo.addr.handle); 2754 - if (node_part_number) 2755 - *node_part_number = desc.params.get_link_topo.node_part_num; 2756 - 2757 - return 0; 2758 2655 } 2759 2656 2760 2657 /** ··· 5044 4995 5045 4996 mutex_unlock(&pi->sched_lock); 5046 4997 kfree(qg_list); 4998 + return status; 4999 + } 5000 + 5001 + /** 5002 + * ice_aq_get_cgu_abilities - get cgu abilities 5003 + * @hw: pointer to the HW struct 5004 + * @abilities: CGU abilities 5005 + * 5006 + * Get CGU abilities (0x0C61) 5007 + * Return: 0 on success or negative value on failure. 5008 + */ 5009 + int 5010 + ice_aq_get_cgu_abilities(struct ice_hw *hw, 5011 + struct ice_aqc_get_cgu_abilities *abilities) 5012 + { 5013 + struct ice_aq_desc desc; 5014 + 5015 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_abilities); 5016 + return ice_aq_send_cmd(hw, &desc, abilities, sizeof(*abilities), NULL); 5017 + } 5018 + 5019 + /** 5020 + * ice_aq_set_input_pin_cfg - set input pin config 5021 + * @hw: pointer to the HW struct 5022 + * @input_idx: Input index 5023 + * @flags1: Input flags 5024 + * @flags2: Input flags 5025 + * @freq: Frequency in Hz 5026 + * @phase_delay: Delay in ps 5027 + * 5028 + * Set CGU input config (0x0C62) 5029 + * Return: 0 on success or negative value on failure. 5030 + */ 5031 + int 5032 + ice_aq_set_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 flags1, u8 flags2, 5033 + u32 freq, s32 phase_delay) 5034 + { 5035 + struct ice_aqc_set_cgu_input_config *cmd; 5036 + struct ice_aq_desc desc; 5037 + 5038 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_input_config); 5039 + cmd = &desc.params.set_cgu_input_config; 5040 + cmd->input_idx = input_idx; 5041 + cmd->flags1 = flags1; 5042 + cmd->flags2 = flags2; 5043 + cmd->freq = cpu_to_le32(freq); 5044 + cmd->phase_delay = cpu_to_le32(phase_delay); 5045 + 5046 + return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5047 + } 5048 + 5049 + /** 5050 + * ice_aq_get_input_pin_cfg - get input pin config 5051 + * @hw: pointer to the HW struct 5052 + * @input_idx: Input index 5053 + * @status: Pin status 5054 + * @type: Pin type 5055 + * @flags1: Input flags 5056 + * @flags2: Input flags 5057 + * @freq: Frequency in Hz 5058 + * @phase_delay: Delay in ps 5059 + * 5060 + * Get CGU input config (0x0C63) 5061 + * Return: 0 on success or negative value on failure. 5062 + */ 5063 + int 5064 + ice_aq_get_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 *status, u8 *type, 5065 + u8 *flags1, u8 *flags2, u32 *freq, s32 *phase_delay) 5066 + { 5067 + struct ice_aqc_get_cgu_input_config *cmd; 5068 + struct ice_aq_desc desc; 5069 + int ret; 5070 + 5071 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_input_config); 5072 + cmd = &desc.params.get_cgu_input_config; 5073 + cmd->input_idx = input_idx; 5074 + 5075 + ret = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5076 + if (!ret) { 5077 + if (status) 5078 + *status = cmd->status; 5079 + if (type) 5080 + *type = cmd->type; 5081 + if (flags1) 5082 + *flags1 = cmd->flags1; 5083 + if (flags2) 5084 + *flags2 = cmd->flags2; 5085 + if (freq) 5086 + *freq = le32_to_cpu(cmd->freq); 5087 + if (phase_delay) 5088 + *phase_delay = le32_to_cpu(cmd->phase_delay); 5089 + } 5090 + 5091 + return ret; 5092 + } 5093 + 5094 + /** 5095 + * ice_aq_set_output_pin_cfg - set output pin config 5096 + * @hw: pointer to the HW struct 5097 + * @output_idx: Output index 5098 + * @flags: Output flags 5099 + * @src_sel: Index of DPLL block 5100 + * @freq: Output frequency 5101 + * @phase_delay: Output phase compensation 5102 + * 5103 + * Set CGU output config (0x0C64) 5104 + * Return: 0 on success or negative value on failure. 5105 + */ 5106 + int 5107 + ice_aq_set_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 flags, 5108 + u8 src_sel, u32 freq, s32 phase_delay) 5109 + { 5110 + struct ice_aqc_set_cgu_output_config *cmd; 5111 + struct ice_aq_desc desc; 5112 + 5113 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_output_config); 5114 + cmd = &desc.params.set_cgu_output_config; 5115 + cmd->output_idx = output_idx; 5116 + cmd->flags = flags; 5117 + cmd->src_sel = src_sel; 5118 + cmd->freq = cpu_to_le32(freq); 5119 + cmd->phase_delay = cpu_to_le32(phase_delay); 5120 + 5121 + return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5122 + } 5123 + 5124 + /** 5125 + * ice_aq_get_output_pin_cfg - get output pin config 5126 + * @hw: pointer to the HW struct 5127 + * @output_idx: Output index 5128 + * @flags: Output flags 5129 + * @src_sel: Internal DPLL source 5130 + * @freq: Output frequency 5131 + * @src_freq: Source frequency 5132 + * 5133 + * Get CGU output config (0x0C65) 5134 + * Return: 0 on success or negative value on failure. 5135 + */ 5136 + int 5137 + ice_aq_get_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 *flags, 5138 + u8 *src_sel, u32 *freq, u32 *src_freq) 5139 + { 5140 + struct ice_aqc_get_cgu_output_config *cmd; 5141 + struct ice_aq_desc desc; 5142 + int ret; 5143 + 5144 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_output_config); 5145 + cmd = &desc.params.get_cgu_output_config; 5146 + cmd->output_idx = output_idx; 5147 + 5148 + ret = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5149 + if (!ret) { 5150 + if (flags) 5151 + *flags = cmd->flags; 5152 + if (src_sel) 5153 + *src_sel = cmd->src_sel; 5154 + if (freq) 5155 + *freq = le32_to_cpu(cmd->freq); 5156 + if (src_freq) 5157 + *src_freq = le32_to_cpu(cmd->src_freq); 5158 + } 5159 + 5160 + return ret; 5161 + } 5162 + 5163 + /** 5164 + * ice_aq_get_cgu_dpll_status - get dpll status 5165 + * @hw: pointer to the HW struct 5166 + * @dpll_num: DPLL index 5167 + * @ref_state: Reference clock state 5168 + * @config: current DPLL config 5169 + * @dpll_state: current DPLL state 5170 + * @phase_offset: Phase offset in ns 5171 + * @eec_mode: EEC_mode 5172 + * 5173 + * Get CGU DPLL status (0x0C66) 5174 + * Return: 0 on success or negative value on failure. 5175 + */ 5176 + int 5177 + ice_aq_get_cgu_dpll_status(struct ice_hw *hw, u8 dpll_num, u8 *ref_state, 5178 + u8 *dpll_state, u8 *config, s64 *phase_offset, 5179 + u8 *eec_mode) 5180 + { 5181 + struct ice_aqc_get_cgu_dpll_status *cmd; 5182 + const s64 nsec_per_psec = 1000LL; 5183 + struct ice_aq_desc desc; 5184 + int status; 5185 + 5186 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_dpll_status); 5187 + cmd = &desc.params.get_cgu_dpll_status; 5188 + cmd->dpll_num = dpll_num; 5189 + 5190 + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5191 + if (!status) { 5192 + *ref_state = cmd->ref_state; 5193 + *dpll_state = cmd->dpll_state; 5194 + *config = cmd->config; 5195 + *phase_offset = le32_to_cpu(cmd->phase_offset_h); 5196 + *phase_offset <<= 32; 5197 + *phase_offset += le32_to_cpu(cmd->phase_offset_l); 5198 + *phase_offset = div64_s64(sign_extend64(*phase_offset, 47), 5199 + nsec_per_psec); 5200 + *eec_mode = cmd->eec_mode; 5201 + } 5202 + 5203 + return status; 5204 + } 5205 + 5206 + /** 5207 + * ice_aq_set_cgu_dpll_config - set dpll config 5208 + * @hw: pointer to the HW struct 5209 + * @dpll_num: DPLL index 5210 + * @ref_state: Reference clock state 5211 + * @config: DPLL config 5212 + * @eec_mode: EEC mode 5213 + * 5214 + * Set CGU DPLL config (0x0C67) 5215 + * Return: 0 on success or negative value on failure. 5216 + */ 5217 + int 5218 + ice_aq_set_cgu_dpll_config(struct ice_hw *hw, u8 dpll_num, u8 ref_state, 5219 + u8 config, u8 eec_mode) 5220 + { 5221 + struct ice_aqc_set_cgu_dpll_config *cmd; 5222 + struct ice_aq_desc desc; 5223 + 5224 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_dpll_config); 5225 + cmd = &desc.params.set_cgu_dpll_config; 5226 + cmd->dpll_num = dpll_num; 5227 + cmd->ref_state = ref_state; 5228 + cmd->config = config; 5229 + cmd->eec_mode = eec_mode; 5230 + 5231 + return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5232 + } 5233 + 5234 + /** 5235 + * ice_aq_set_cgu_ref_prio - set input reference priority 5236 + * @hw: pointer to the HW struct 5237 + * @dpll_num: DPLL index 5238 + * @ref_idx: Reference pin index 5239 + * @ref_priority: Reference input priority 5240 + * 5241 + * Set CGU reference priority (0x0C68) 5242 + * Return: 0 on success or negative value on failure. 5243 + */ 5244 + int 5245 + ice_aq_set_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, 5246 + u8 ref_priority) 5247 + { 5248 + struct ice_aqc_set_cgu_ref_prio *cmd; 5249 + struct ice_aq_desc desc; 5250 + 5251 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_ref_prio); 5252 + cmd = &desc.params.set_cgu_ref_prio; 5253 + cmd->dpll_num = dpll_num; 5254 + cmd->ref_idx = ref_idx; 5255 + cmd->ref_priority = ref_priority; 5256 + 5257 + return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5258 + } 5259 + 5260 + /** 5261 + * ice_aq_get_cgu_ref_prio - get input reference priority 5262 + * @hw: pointer to the HW struct 5263 + * @dpll_num: DPLL index 5264 + * @ref_idx: Reference pin index 5265 + * @ref_prio: Reference input priority 5266 + * 5267 + * Get CGU reference priority (0x0C69) 5268 + * Return: 0 on success or negative value on failure. 5269 + */ 5270 + int 5271 + ice_aq_get_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, 5272 + u8 *ref_prio) 5273 + { 5274 + struct ice_aqc_get_cgu_ref_prio *cmd; 5275 + struct ice_aq_desc desc; 5276 + int status; 5277 + 5278 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_ref_prio); 5279 + cmd = &desc.params.get_cgu_ref_prio; 5280 + cmd->dpll_num = dpll_num; 5281 + cmd->ref_idx = ref_idx; 5282 + 5283 + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5284 + if (!status) 5285 + *ref_prio = cmd->ref_priority; 5286 + 5287 + return status; 5288 + } 5289 + 5290 + /** 5291 + * ice_aq_get_cgu_info - get cgu info 5292 + * @hw: pointer to the HW struct 5293 + * @cgu_id: CGU ID 5294 + * @cgu_cfg_ver: CGU config version 5295 + * @cgu_fw_ver: CGU firmware version 5296 + * 5297 + * Get CGU info (0x0C6A) 5298 + * Return: 0 on success or negative value on failure. 5299 + */ 5300 + int 5301 + ice_aq_get_cgu_info(struct ice_hw *hw, u32 *cgu_id, u32 *cgu_cfg_ver, 5302 + u32 *cgu_fw_ver) 5303 + { 5304 + struct ice_aqc_get_cgu_info *cmd; 5305 + struct ice_aq_desc desc; 5306 + int status; 5307 + 5308 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_info); 5309 + cmd = &desc.params.get_cgu_info; 5310 + 5311 + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5312 + if (!status) { 5313 + *cgu_id = le32_to_cpu(cmd->cgu_id); 5314 + *cgu_cfg_ver = le32_to_cpu(cmd->cgu_cfg_ver); 5315 + *cgu_fw_ver = le32_to_cpu(cmd->cgu_fw_ver); 5316 + } 5317 + 5318 + return status; 5319 + } 5320 + 5321 + /** 5322 + * ice_aq_set_phy_rec_clk_out - set RCLK phy out 5323 + * @hw: pointer to the HW struct 5324 + * @phy_output: PHY reference clock output pin 5325 + * @enable: GPIO state to be applied 5326 + * @freq: PHY output frequency 5327 + * 5328 + * Set phy recovered clock as reference (0x0630) 5329 + * Return: 0 on success or negative value on failure. 5330 + */ 5331 + int 5332 + ice_aq_set_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, bool enable, 5333 + u32 *freq) 5334 + { 5335 + struct ice_aqc_set_phy_rec_clk_out *cmd; 5336 + struct ice_aq_desc desc; 5337 + int status; 5338 + 5339 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_rec_clk_out); 5340 + cmd = &desc.params.set_phy_rec_clk_out; 5341 + cmd->phy_output = phy_output; 5342 + cmd->port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT; 5343 + cmd->flags = enable & ICE_AQC_SET_PHY_REC_CLK_OUT_OUT_EN; 5344 + cmd->freq = cpu_to_le32(*freq); 5345 + 5346 + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5347 + if (!status) 5348 + *freq = le32_to_cpu(cmd->freq); 5349 + 5350 + return status; 5351 + } 5352 + 5353 + /** 5354 + * ice_aq_get_phy_rec_clk_out - get phy recovered signal info 5355 + * @hw: pointer to the HW struct 5356 + * @phy_output: PHY reference clock output pin 5357 + * @port_num: Port number 5358 + * @flags: PHY flags 5359 + * @node_handle: PHY output frequency 5360 + * 5361 + * Get PHY recovered clock output info (0x0631) 5362 + * Return: 0 on success or negative value on failure. 5363 + */ 5364 + int 5365 + ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num, 5366 + u8 *flags, u16 *node_handle) 5367 + { 5368 + struct ice_aqc_get_phy_rec_clk_out *cmd; 5369 + struct ice_aq_desc desc; 5370 + int status; 5371 + 5372 + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_phy_rec_clk_out); 5373 + cmd = &desc.params.get_phy_rec_clk_out; 5374 + cmd->phy_output = *phy_output; 5375 + 5376 + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 5377 + if (!status) { 5378 + *phy_output = cmd->phy_output; 5379 + if (port_num) 5380 + *port_num = cmd->port_num; 5381 + if (flags) 5382 + *flags = cmd->flags; 5383 + if (node_handle) 5384 + *node_handle = le16_to_cpu(cmd->node_handle); 5385 + } 5386 + 5047 5387 return status; 5048 5388 } 5049 5389
+44
drivers/net/ethernet/intel/ice/ice_common.h
··· 94 94 struct ice_sq_cd *cd); 95 95 bool ice_is_pf_c827(struct ice_hw *hw); 96 96 int 97 + ice_find_netlist_node(struct ice_hw *hw, u8 node_type_ctx, u8 node_part_number, 98 + u16 *node_handle); 99 + int 100 + ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, 101 + u8 *node_part_number, u16 *node_handle); 102 + int 97 103 ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, 98 104 enum ice_adminq_opc opc, struct ice_sq_cd *cd); 99 105 int ··· 202 196 struct ice_q_ctx * 203 197 ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle); 204 198 int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in); 199 + int 200 + ice_aq_get_cgu_abilities(struct ice_hw *hw, 201 + struct ice_aqc_get_cgu_abilities *abilities); 202 + int 203 + ice_aq_set_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 flags1, u8 flags2, 204 + u32 freq, s32 phase_delay); 205 + int 206 + ice_aq_get_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 *status, u8 *type, 207 + u8 *flags1, u8 *flags2, u32 *freq, s32 *phase_delay); 208 + int 209 + ice_aq_set_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 flags, 210 + u8 src_sel, u32 freq, s32 phase_delay); 211 + int 212 + ice_aq_get_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 *flags, 213 + u8 *src_sel, u32 *freq, u32 *src_freq); 214 + int 215 + ice_aq_get_cgu_dpll_status(struct ice_hw *hw, u8 dpll_num, u8 *ref_state, 216 + u8 *dpll_state, u8 *config, s64 *phase_offset, 217 + u8 *eec_mode); 218 + int 219 + ice_aq_set_cgu_dpll_config(struct ice_hw *hw, u8 dpll_num, u8 ref_state, 220 + u8 config, u8 eec_mode); 221 + int 222 + ice_aq_set_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, 223 + u8 ref_priority); 224 + int 225 + ice_aq_get_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, 226 + u8 *ref_prio); 227 + int 228 + ice_aq_get_cgu_info(struct ice_hw *hw, u32 *cgu_id, u32 *cgu_cfg_ver, 229 + u32 *cgu_fw_ver); 230 + 231 + int 232 + ice_aq_set_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, bool enable, 233 + u32 *freq); 234 + int 235 + ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num, 236 + u8 *flags, u16 *node_handle); 205 237 void 206 238 ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded, 207 239 u64 *prev_stat, u64 *cur_stat);
+1904
drivers/net/ethernet/intel/ice/ice_dpll.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (C) 2022, Intel Corporation. */ 3 + 4 + #include "ice.h" 5 + #include "ice_lib.h" 6 + #include "ice_trace.h" 7 + #include <linux/dpll.h> 8 + 9 + #define ICE_CGU_STATE_ACQ_ERR_THRESHOLD 50 10 + #define ICE_DPLL_PIN_IDX_INVALID 0xff 11 + #define ICE_DPLL_RCLK_NUM_PER_PF 1 12 + 13 + /** 14 + * enum ice_dpll_pin_type - enumerate ice pin types: 15 + * @ICE_DPLL_PIN_INVALID: invalid pin type 16 + * @ICE_DPLL_PIN_TYPE_INPUT: input pin 17 + * @ICE_DPLL_PIN_TYPE_OUTPUT: output pin 18 + * @ICE_DPLL_PIN_TYPE_RCLK_INPUT: recovery clock input pin 19 + */ 20 + enum ice_dpll_pin_type { 21 + ICE_DPLL_PIN_INVALID, 22 + ICE_DPLL_PIN_TYPE_INPUT, 23 + ICE_DPLL_PIN_TYPE_OUTPUT, 24 + ICE_DPLL_PIN_TYPE_RCLK_INPUT, 25 + }; 26 + 27 + static const char * const pin_type_name[] = { 28 + [ICE_DPLL_PIN_TYPE_INPUT] = "input", 29 + [ICE_DPLL_PIN_TYPE_OUTPUT] = "output", 30 + [ICE_DPLL_PIN_TYPE_RCLK_INPUT] = "rclk-input", 31 + }; 32 + 33 + /** 34 + * ice_dpll_pin_freq_set - set pin's frequency 35 + * @pf: private board structure 36 + * @pin: pointer to a pin 37 + * @pin_type: type of pin being configured 38 + * @freq: frequency to be set 39 + * @extack: error reporting 40 + * 41 + * Set requested frequency on a pin. 42 + * 43 + * Context: Called under pf->dplls.lock 44 + * Return: 45 + * * 0 - success 46 + * * negative - error on AQ or wrong pin type given 47 + */ 48 + static int 49 + ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, 50 + enum ice_dpll_pin_type pin_type, const u32 freq, 51 + struct netlink_ext_ack *extack) 52 + { 53 + u8 flags; 54 + int ret; 55 + 56 + switch (pin_type) { 57 + case ICE_DPLL_PIN_TYPE_INPUT: 58 + flags = ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_FREQ; 59 + ret = ice_aq_set_input_pin_cfg(&pf->hw, pin->idx, flags, 60 + pin->flags[0], freq, 0); 61 + break; 62 + case ICE_DPLL_PIN_TYPE_OUTPUT: 63 + flags = ICE_AQC_SET_CGU_OUT_CFG_UPDATE_FREQ; 64 + ret = ice_aq_set_output_pin_cfg(&pf->hw, pin->idx, flags, 65 + 0, freq, 0); 66 + break; 67 + default: 68 + return -EINVAL; 69 + } 70 + if (ret) { 71 + NL_SET_ERR_MSG_FMT(extack, 72 + "err:%d %s failed to set pin freq:%u on pin:%u\n", 73 + ret, 74 + ice_aq_str(pf->hw.adminq.sq_last_status), 75 + freq, pin->idx); 76 + return ret; 77 + } 78 + pin->freq = freq; 79 + 80 + return 0; 81 + } 82 + 83 + /** 84 + * ice_dpll_frequency_set - wrapper for pin callback for set frequency 85 + * @pin: pointer to a pin 86 + * @pin_priv: private data pointer passed on pin registration 87 + * @dpll: pointer to dpll 88 + * @dpll_priv: private data pointer passed on dpll registration 89 + * @frequency: frequency to be set 90 + * @extack: error reporting 91 + * @pin_type: type of pin being configured 92 + * 93 + * Wraps internal set frequency command on a pin. 94 + * 95 + * Context: Acquires pf->dplls.lock 96 + * Return: 97 + * * 0 - success 98 + * * negative - error pin not found or couldn't set in hw 99 + */ 100 + static int 101 + ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, 102 + const struct dpll_device *dpll, void *dpll_priv, 103 + const u32 frequency, 104 + struct netlink_ext_ack *extack, 105 + enum ice_dpll_pin_type pin_type) 106 + { 107 + struct ice_dpll_pin *p = pin_priv; 108 + struct ice_dpll *d = dpll_priv; 109 + struct ice_pf *pf = d->pf; 110 + int ret; 111 + 112 + mutex_lock(&pf->dplls.lock); 113 + ret = ice_dpll_pin_freq_set(pf, p, pin_type, frequency, extack); 114 + mutex_unlock(&pf->dplls.lock); 115 + 116 + return ret; 117 + } 118 + 119 + /** 120 + * ice_dpll_input_frequency_set - input pin callback for set frequency 121 + * @pin: pointer to a pin 122 + * @pin_priv: private data pointer passed on pin registration 123 + * @dpll: pointer to dpll 124 + * @dpll_priv: private data pointer passed on dpll registration 125 + * @frequency: frequency to be set 126 + * @extack: error reporting 127 + * 128 + * Wraps internal set frequency command on a pin. 129 + * 130 + * Context: Calls a function which acquires pf->dplls.lock 131 + * Return: 132 + * * 0 - success 133 + * * negative - error pin not found or couldn't set in hw 134 + */ 135 + static int 136 + ice_dpll_input_frequency_set(const struct dpll_pin *pin, void *pin_priv, 137 + const struct dpll_device *dpll, void *dpll_priv, 138 + u64 frequency, struct netlink_ext_ack *extack) 139 + { 140 + return ice_dpll_frequency_set(pin, pin_priv, dpll, dpll_priv, frequency, 141 + extack, ICE_DPLL_PIN_TYPE_INPUT); 142 + } 143 + 144 + /** 145 + * ice_dpll_output_frequency_set - output pin callback for set frequency 146 + * @pin: pointer to a pin 147 + * @pin_priv: private data pointer passed on pin registration 148 + * @dpll: pointer to dpll 149 + * @dpll_priv: private data pointer passed on dpll registration 150 + * @frequency: frequency to be set 151 + * @extack: error reporting 152 + * 153 + * Wraps internal set frequency command on a pin. 154 + * 155 + * Context: Calls a function which acquires pf->dplls.lock 156 + * Return: 157 + * * 0 - success 158 + * * negative - error pin not found or couldn't set in hw 159 + */ 160 + static int 161 + ice_dpll_output_frequency_set(const struct dpll_pin *pin, void *pin_priv, 162 + const struct dpll_device *dpll, void *dpll_priv, 163 + u64 frequency, struct netlink_ext_ack *extack) 164 + { 165 + return ice_dpll_frequency_set(pin, pin_priv, dpll, dpll_priv, frequency, 166 + extack, ICE_DPLL_PIN_TYPE_OUTPUT); 167 + } 168 + 169 + /** 170 + * ice_dpll_frequency_get - wrapper for pin callback for get frequency 171 + * @pin: pointer to a pin 172 + * @pin_priv: private data pointer passed on pin registration 173 + * @dpll: pointer to dpll 174 + * @dpll_priv: private data pointer passed on dpll registration 175 + * @frequency: on success holds pin's frequency 176 + * @extack: error reporting 177 + * @pin_type: type of pin being configured 178 + * 179 + * Wraps internal get frequency command of a pin. 180 + * 181 + * Context: Acquires pf->dplls.lock 182 + * Return: 183 + * * 0 - success 184 + * * negative - error pin not found or couldn't get from hw 185 + */ 186 + static int 187 + ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, 188 + const struct dpll_device *dpll, void *dpll_priv, 189 + u64 *frequency, struct netlink_ext_ack *extack, 190 + enum ice_dpll_pin_type pin_type) 191 + { 192 + struct ice_dpll_pin *p = pin_priv; 193 + struct ice_dpll *d = dpll_priv; 194 + struct ice_pf *pf = d->pf; 195 + 196 + mutex_lock(&pf->dplls.lock); 197 + *frequency = p->freq; 198 + mutex_unlock(&pf->dplls.lock); 199 + 200 + return 0; 201 + } 202 + 203 + /** 204 + * ice_dpll_input_frequency_get - input pin callback for get frequency 205 + * @pin: pointer to a pin 206 + * @pin_priv: private data pointer passed on pin registration 207 + * @dpll: pointer to dpll 208 + * @dpll_priv: private data pointer passed on dpll registration 209 + * @frequency: on success holds pin's frequency 210 + * @extack: error reporting 211 + * 212 + * Wraps internal get frequency command of a input pin. 213 + * 214 + * Context: Calls a function which acquires pf->dplls.lock 215 + * Return: 216 + * * 0 - success 217 + * * negative - error pin not found or couldn't get from hw 218 + */ 219 + static int 220 + ice_dpll_input_frequency_get(const struct dpll_pin *pin, void *pin_priv, 221 + const struct dpll_device *dpll, void *dpll_priv, 222 + u64 *frequency, struct netlink_ext_ack *extack) 223 + { 224 + return ice_dpll_frequency_get(pin, pin_priv, dpll, dpll_priv, frequency, 225 + extack, ICE_DPLL_PIN_TYPE_INPUT); 226 + } 227 + 228 + /** 229 + * ice_dpll_output_frequency_get - output pin callback for get frequency 230 + * @pin: pointer to a pin 231 + * @pin_priv: private data pointer passed on pin registration 232 + * @dpll: pointer to dpll 233 + * @dpll_priv: private data pointer passed on dpll registration 234 + * @frequency: on success holds pin's frequency 235 + * @extack: error reporting 236 + * 237 + * Wraps internal get frequency command of a pin. 238 + * 239 + * Context: Calls a function which acquires pf->dplls.lock 240 + * Return: 241 + * * 0 - success 242 + * * negative - error pin not found or couldn't get from hw 243 + */ 244 + static int 245 + ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv, 246 + const struct dpll_device *dpll, void *dpll_priv, 247 + u64 *frequency, struct netlink_ext_ack *extack) 248 + { 249 + return ice_dpll_frequency_get(pin, pin_priv, dpll, dpll_priv, frequency, 250 + extack, ICE_DPLL_PIN_TYPE_OUTPUT); 251 + } 252 + 253 + /** 254 + * ice_dpll_pin_enable - enable a pin on dplls 255 + * @hw: board private hw structure 256 + * @pin: pointer to a pin 257 + * @pin_type: type of pin being enabled 258 + * @extack: error reporting 259 + * 260 + * Enable a pin on both dplls. Store current state in pin->flags. 261 + * 262 + * Context: Called under pf->dplls.lock 263 + * Return: 264 + * * 0 - OK 265 + * * negative - error 266 + */ 267 + static int 268 + ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, 269 + enum ice_dpll_pin_type pin_type, 270 + struct netlink_ext_ack *extack) 271 + { 272 + u8 flags = 0; 273 + int ret; 274 + 275 + switch (pin_type) { 276 + case ICE_DPLL_PIN_TYPE_INPUT: 277 + if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) 278 + flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; 279 + flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN; 280 + ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); 281 + break; 282 + case ICE_DPLL_PIN_TYPE_OUTPUT: 283 + if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) 284 + flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; 285 + flags |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN; 286 + ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0); 287 + break; 288 + default: 289 + return -EINVAL; 290 + } 291 + if (ret) 292 + NL_SET_ERR_MSG_FMT(extack, 293 + "err:%d %s failed to enable %s pin:%u\n", 294 + ret, ice_aq_str(hw->adminq.sq_last_status), 295 + pin_type_name[pin_type], pin->idx); 296 + 297 + return ret; 298 + } 299 + 300 + /** 301 + * ice_dpll_pin_disable - disable a pin on dplls 302 + * @hw: board private hw structure 303 + * @pin: pointer to a pin 304 + * @pin_type: type of pin being disabled 305 + * @extack: error reporting 306 + * 307 + * Disable a pin on both dplls. Store current state in pin->flags. 308 + * 309 + * Context: Called under pf->dplls.lock 310 + * Return: 311 + * * 0 - OK 312 + * * negative - error 313 + */ 314 + static int 315 + ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, 316 + enum ice_dpll_pin_type pin_type, 317 + struct netlink_ext_ack *extack) 318 + { 319 + u8 flags = 0; 320 + int ret; 321 + 322 + switch (pin_type) { 323 + case ICE_DPLL_PIN_TYPE_INPUT: 324 + if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) 325 + flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; 326 + ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); 327 + break; 328 + case ICE_DPLL_PIN_TYPE_OUTPUT: 329 + if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) 330 + flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; 331 + ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0); 332 + break; 333 + default: 334 + return -EINVAL; 335 + } 336 + if (ret) 337 + NL_SET_ERR_MSG_FMT(extack, 338 + "err:%d %s failed to disable %s pin:%u\n", 339 + ret, ice_aq_str(hw->adminq.sq_last_status), 340 + pin_type_name[pin_type], pin->idx); 341 + 342 + return ret; 343 + } 344 + 345 + /** 346 + * ice_dpll_pin_state_update - update pin's state 347 + * @pf: private board struct 348 + * @pin: structure with pin attributes to be updated 349 + * @pin_type: type of pin being updated 350 + * @extack: error reporting 351 + * 352 + * Determine pin current state and frequency, then update struct 353 + * holding the pin info. For input pin states are separated for each 354 + * dpll, for rclk pins states are separated for each parent. 355 + * 356 + * Context: Called under pf->dplls.lock 357 + * Return: 358 + * * 0 - OK 359 + * * negative - error 360 + */ 361 + static int 362 + ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, 363 + enum ice_dpll_pin_type pin_type, 364 + struct netlink_ext_ack *extack) 365 + { 366 + u8 parent, port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT; 367 + int ret; 368 + 369 + switch (pin_type) { 370 + case ICE_DPLL_PIN_TYPE_INPUT: 371 + ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, NULL, NULL, 372 + NULL, &pin->flags[0], 373 + &pin->freq, NULL); 374 + if (ret) 375 + goto err; 376 + if (ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0]) { 377 + if (pin->pin) { 378 + pin->state[pf->dplls.eec.dpll_idx] = 379 + pin->pin == pf->dplls.eec.active_input ? 380 + DPLL_PIN_STATE_CONNECTED : 381 + DPLL_PIN_STATE_SELECTABLE; 382 + pin->state[pf->dplls.pps.dpll_idx] = 383 + pin->pin == pf->dplls.pps.active_input ? 384 + DPLL_PIN_STATE_CONNECTED : 385 + DPLL_PIN_STATE_SELECTABLE; 386 + } else { 387 + pin->state[pf->dplls.eec.dpll_idx] = 388 + DPLL_PIN_STATE_SELECTABLE; 389 + pin->state[pf->dplls.pps.dpll_idx] = 390 + DPLL_PIN_STATE_SELECTABLE; 391 + } 392 + } else { 393 + pin->state[pf->dplls.eec.dpll_idx] = 394 + DPLL_PIN_STATE_DISCONNECTED; 395 + pin->state[pf->dplls.pps.dpll_idx] = 396 + DPLL_PIN_STATE_DISCONNECTED; 397 + } 398 + break; 399 + case ICE_DPLL_PIN_TYPE_OUTPUT: 400 + ret = ice_aq_get_output_pin_cfg(&pf->hw, pin->idx, 401 + &pin->flags[0], NULL, 402 + &pin->freq, NULL); 403 + if (ret) 404 + goto err; 405 + if (ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0]) 406 + pin->state[0] = DPLL_PIN_STATE_CONNECTED; 407 + else 408 + pin->state[0] = DPLL_PIN_STATE_DISCONNECTED; 409 + break; 410 + case ICE_DPLL_PIN_TYPE_RCLK_INPUT: 411 + for (parent = 0; parent < pf->dplls.rclk.num_parents; 412 + parent++) { 413 + u8 p = parent; 414 + 415 + ret = ice_aq_get_phy_rec_clk_out(&pf->hw, &p, 416 + &port_num, 417 + &pin->flags[parent], 418 + NULL); 419 + if (ret) 420 + goto err; 421 + if (ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN & 422 + pin->flags[parent]) 423 + pin->state[parent] = DPLL_PIN_STATE_CONNECTED; 424 + else 425 + pin->state[parent] = 426 + DPLL_PIN_STATE_DISCONNECTED; 427 + } 428 + break; 429 + default: 430 + return -EINVAL; 431 + } 432 + 433 + return 0; 434 + err: 435 + if (extack) 436 + NL_SET_ERR_MSG_FMT(extack, 437 + "err:%d %s failed to update %s pin:%u\n", 438 + ret, 439 + ice_aq_str(pf->hw.adminq.sq_last_status), 440 + pin_type_name[pin_type], pin->idx); 441 + else 442 + dev_err_ratelimited(ice_pf_to_dev(pf), 443 + "err:%d %s failed to update %s pin:%u\n", 444 + ret, 445 + ice_aq_str(pf->hw.adminq.sq_last_status), 446 + pin_type_name[pin_type], pin->idx); 447 + return ret; 448 + } 449 + 450 + /** 451 + * ice_dpll_hw_input_prio_set - set input priority value in hardware 452 + * @pf: board private structure 453 + * @dpll: ice dpll pointer 454 + * @pin: ice pin pointer 455 + * @prio: priority value being set on a dpll 456 + * @extack: error reporting 457 + * 458 + * Internal wrapper for setting the priority in the hardware. 459 + * 460 + * Context: Called under pf->dplls.lock 461 + * Return: 462 + * * 0 - success 463 + * * negative - failure 464 + */ 465 + static int 466 + ice_dpll_hw_input_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, 467 + struct ice_dpll_pin *pin, const u32 prio, 468 + struct netlink_ext_ack *extack) 469 + { 470 + int ret; 471 + 472 + ret = ice_aq_set_cgu_ref_prio(&pf->hw, dpll->dpll_idx, pin->idx, 473 + (u8)prio); 474 + if (ret) 475 + NL_SET_ERR_MSG_FMT(extack, 476 + "err:%d %s failed to set pin prio:%u on pin:%u\n", 477 + ret, 478 + ice_aq_str(pf->hw.adminq.sq_last_status), 479 + prio, pin->idx); 480 + else 481 + dpll->input_prio[pin->idx] = prio; 482 + 483 + return ret; 484 + } 485 + 486 + /** 487 + * ice_dpll_lock_status_get - get dpll lock status callback 488 + * @dpll: registered dpll pointer 489 + * @dpll_priv: private data pointer passed on dpll registration 490 + * @status: on success holds dpll's lock status 491 + * @extack: error reporting 492 + * 493 + * Dpll subsystem callback, provides dpll's lock status. 494 + * 495 + * Context: Acquires pf->dplls.lock 496 + * Return: 497 + * * 0 - success 498 + * * negative - failure 499 + */ 500 + static int 501 + ice_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, 502 + enum dpll_lock_status *status, 503 + struct netlink_ext_ack *extack) 504 + { 505 + struct ice_dpll *d = dpll_priv; 506 + struct ice_pf *pf = d->pf; 507 + 508 + mutex_lock(&pf->dplls.lock); 509 + *status = d->dpll_state; 510 + mutex_unlock(&pf->dplls.lock); 511 + 512 + return 0; 513 + } 514 + 515 + /** 516 + * ice_dpll_mode_supported - check if dpll's working mode is supported 517 + * @dpll: registered dpll pointer 518 + * @dpll_priv: private data pointer passed on dpll registration 519 + * @mode: mode to be checked for support 520 + * @extack: error reporting 521 + * 522 + * Dpll subsystem callback. Provides information if working mode is supported 523 + * by dpll. 524 + * 525 + * Return: 526 + * * true - mode is supported 527 + * * false - mode is not supported 528 + */ 529 + static bool ice_dpll_mode_supported(const struct dpll_device *dpll, 530 + void *dpll_priv, 531 + enum dpll_mode mode, 532 + struct netlink_ext_ack *extack) 533 + { 534 + if (mode == DPLL_MODE_AUTOMATIC) 535 + return true; 536 + 537 + return false; 538 + } 539 + 540 + /** 541 + * ice_dpll_mode_get - get dpll's working mode 542 + * @dpll: registered dpll pointer 543 + * @dpll_priv: private data pointer passed on dpll registration 544 + * @mode: on success holds current working mode of dpll 545 + * @extack: error reporting 546 + * 547 + * Dpll subsystem callback. Provides working mode of dpll. 548 + * 549 + * Context: Acquires pf->dplls.lock 550 + * Return: 551 + * * 0 - success 552 + * * negative - failure 553 + */ 554 + static int ice_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv, 555 + enum dpll_mode *mode, 556 + struct netlink_ext_ack *extack) 557 + { 558 + struct ice_dpll *d = dpll_priv; 559 + struct ice_pf *pf = d->pf; 560 + 561 + mutex_lock(&pf->dplls.lock); 562 + *mode = d->mode; 563 + mutex_unlock(&pf->dplls.lock); 564 + 565 + return 0; 566 + } 567 + 568 + /** 569 + * ice_dpll_pin_state_set - set pin's state on dpll 570 + * @pin: pointer to a pin 571 + * @pin_priv: private data pointer passed on pin registration 572 + * @dpll: registered dpll pointer 573 + * @dpll_priv: private data pointer passed on dpll registration 574 + * @enable: if pin shalll be enabled 575 + * @extack: error reporting 576 + * @pin_type: type of a pin 577 + * 578 + * Set pin state on a pin. 579 + * 580 + * Context: Acquires pf->dplls.lock 581 + * Return: 582 + * * 0 - OK or no change required 583 + * * negative - error 584 + */ 585 + static int 586 + ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv, 587 + const struct dpll_device *dpll, void *dpll_priv, 588 + bool enable, struct netlink_ext_ack *extack, 589 + enum ice_dpll_pin_type pin_type) 590 + { 591 + struct ice_dpll_pin *p = pin_priv; 592 + struct ice_dpll *d = dpll_priv; 593 + struct ice_pf *pf = d->pf; 594 + int ret; 595 + 596 + mutex_lock(&pf->dplls.lock); 597 + if (enable) 598 + ret = ice_dpll_pin_enable(&pf->hw, p, pin_type, extack); 599 + else 600 + ret = ice_dpll_pin_disable(&pf->hw, p, pin_type, extack); 601 + if (!ret) 602 + ret = ice_dpll_pin_state_update(pf, p, pin_type, extack); 603 + mutex_unlock(&pf->dplls.lock); 604 + 605 + return ret; 606 + } 607 + 608 + /** 609 + * ice_dpll_output_state_set - enable/disable output pin on dpll device 610 + * @pin: pointer to a pin 611 + * @pin_priv: private data pointer passed on pin registration 612 + * @dpll: dpll being configured 613 + * @dpll_priv: private data pointer passed on dpll registration 614 + * @state: state of pin to be set 615 + * @extack: error reporting 616 + * 617 + * Dpll subsystem callback. Set given state on output type pin. 618 + * 619 + * Context: Calls a function which acquires pf->dplls.lock 620 + * Return: 621 + * * 0 - successfully enabled mode 622 + * * negative - failed to enable mode 623 + */ 624 + static int 625 + ice_dpll_output_state_set(const struct dpll_pin *pin, void *pin_priv, 626 + const struct dpll_device *dpll, void *dpll_priv, 627 + enum dpll_pin_state state, 628 + struct netlink_ext_ack *extack) 629 + { 630 + bool enable = state == DPLL_PIN_STATE_CONNECTED; 631 + 632 + return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable, 633 + extack, ICE_DPLL_PIN_TYPE_OUTPUT); 634 + } 635 + 636 + /** 637 + * ice_dpll_input_state_set - enable/disable input pin on dpll levice 638 + * @pin: pointer to a pin 639 + * @pin_priv: private data pointer passed on pin registration 640 + * @dpll: dpll being configured 641 + * @dpll_priv: private data pointer passed on dpll registration 642 + * @state: state of pin to be set 643 + * @extack: error reporting 644 + * 645 + * Dpll subsystem callback. Enables given mode on input type pin. 646 + * 647 + * Context: Calls a function which acquires pf->dplls.lock 648 + * Return: 649 + * * 0 - successfully enabled mode 650 + * * negative - failed to enable mode 651 + */ 652 + static int 653 + ice_dpll_input_state_set(const struct dpll_pin *pin, void *pin_priv, 654 + const struct dpll_device *dpll, void *dpll_priv, 655 + enum dpll_pin_state state, 656 + struct netlink_ext_ack *extack) 657 + { 658 + bool enable = state == DPLL_PIN_STATE_SELECTABLE; 659 + 660 + return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable, 661 + extack, ICE_DPLL_PIN_TYPE_INPUT); 662 + } 663 + 664 + /** 665 + * ice_dpll_pin_state_get - set pin's state on dpll 666 + * @pin: pointer to a pin 667 + * @pin_priv: private data pointer passed on pin registration 668 + * @dpll: registered dpll pointer 669 + * @dpll_priv: private data pointer passed on dpll registration 670 + * @state: on success holds state of the pin 671 + * @extack: error reporting 672 + * @pin_type: type of questioned pin 673 + * 674 + * Determine pin state set it on a pin. 675 + * 676 + * Context: Acquires pf->dplls.lock 677 + * Return: 678 + * * 0 - success 679 + * * negative - failed to get state 680 + */ 681 + static int 682 + ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, 683 + const struct dpll_device *dpll, void *dpll_priv, 684 + enum dpll_pin_state *state, 685 + struct netlink_ext_ack *extack, 686 + enum ice_dpll_pin_type pin_type) 687 + { 688 + struct ice_dpll_pin *p = pin_priv; 689 + struct ice_dpll *d = dpll_priv; 690 + struct ice_pf *pf = d->pf; 691 + int ret; 692 + 693 + mutex_lock(&pf->dplls.lock); 694 + ret = ice_dpll_pin_state_update(pf, p, pin_type, extack); 695 + if (ret) 696 + goto unlock; 697 + if (pin_type == ICE_DPLL_PIN_TYPE_INPUT) 698 + *state = p->state[d->dpll_idx]; 699 + else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) 700 + *state = p->state[0]; 701 + ret = 0; 702 + unlock: 703 + mutex_unlock(&pf->dplls.lock); 704 + 705 + return ret; 706 + } 707 + 708 + /** 709 + * ice_dpll_output_state_get - get output pin state on dpll device 710 + * @pin: pointer to a pin 711 + * @pin_priv: private data pointer passed on pin registration 712 + * @dpll: registered dpll pointer 713 + * @dpll_priv: private data pointer passed on dpll registration 714 + * @state: on success holds state of the pin 715 + * @extack: error reporting 716 + * 717 + * Dpll subsystem callback. Check state of a pin. 718 + * 719 + * Context: Calls a function which acquires pf->dplls.lock 720 + * Return: 721 + * * 0 - success 722 + * * negative - failed to get state 723 + */ 724 + static int 725 + ice_dpll_output_state_get(const struct dpll_pin *pin, void *pin_priv, 726 + const struct dpll_device *dpll, void *dpll_priv, 727 + enum dpll_pin_state *state, 728 + struct netlink_ext_ack *extack) 729 + { 730 + return ice_dpll_pin_state_get(pin, pin_priv, dpll, dpll_priv, state, 731 + extack, ICE_DPLL_PIN_TYPE_OUTPUT); 732 + } 733 + 734 + /** 735 + * ice_dpll_input_state_get - get input pin state on dpll device 736 + * @pin: pointer to a pin 737 + * @pin_priv: private data pointer passed on pin registration 738 + * @dpll: registered dpll pointer 739 + * @dpll_priv: private data pointer passed on dpll registration 740 + * @state: on success holds state of the pin 741 + * @extack: error reporting 742 + * 743 + * Dpll subsystem callback. Check state of a input pin. 744 + * 745 + * Context: Calls a function which acquires pf->dplls.lock 746 + * Return: 747 + * * 0 - success 748 + * * negative - failed to get state 749 + */ 750 + static int 751 + ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, 752 + const struct dpll_device *dpll, void *dpll_priv, 753 + enum dpll_pin_state *state, 754 + struct netlink_ext_ack *extack) 755 + { 756 + return ice_dpll_pin_state_get(pin, pin_priv, dpll, dpll_priv, state, 757 + extack, ICE_DPLL_PIN_TYPE_INPUT); 758 + } 759 + 760 + /** 761 + * ice_dpll_input_prio_get - get dpll's input prio 762 + * @pin: pointer to a pin 763 + * @pin_priv: private data pointer passed on pin registration 764 + * @dpll: registered dpll pointer 765 + * @dpll_priv: private data pointer passed on dpll registration 766 + * @prio: on success - returns input priority on dpll 767 + * @extack: error reporting 768 + * 769 + * Dpll subsystem callback. Handler for getting priority of a input pin. 770 + * 771 + * Context: Acquires pf->dplls.lock 772 + * Return: 773 + * * 0 - success 774 + * * negative - failure 775 + */ 776 + static int 777 + ice_dpll_input_prio_get(const struct dpll_pin *pin, void *pin_priv, 778 + const struct dpll_device *dpll, void *dpll_priv, 779 + u32 *prio, struct netlink_ext_ack *extack) 780 + { 781 + struct ice_dpll_pin *p = pin_priv; 782 + struct ice_dpll *d = dpll_priv; 783 + struct ice_pf *pf = d->pf; 784 + 785 + mutex_lock(&pf->dplls.lock); 786 + *prio = d->input_prio[p->idx]; 787 + mutex_unlock(&pf->dplls.lock); 788 + 789 + return 0; 790 + } 791 + 792 + /** 793 + * ice_dpll_input_prio_set - set dpll input prio 794 + * @pin: pointer to a pin 795 + * @pin_priv: private data pointer passed on pin registration 796 + * @dpll: registered dpll pointer 797 + * @dpll_priv: private data pointer passed on dpll registration 798 + * @prio: input priority to be set on dpll 799 + * @extack: error reporting 800 + * 801 + * Dpll subsystem callback. Handler for setting priority of a input pin. 802 + * 803 + * Context: Acquires pf->dplls.lock 804 + * Return: 805 + * * 0 - success 806 + * * negative - failure 807 + */ 808 + static int 809 + ice_dpll_input_prio_set(const struct dpll_pin *pin, void *pin_priv, 810 + const struct dpll_device *dpll, void *dpll_priv, 811 + u32 prio, struct netlink_ext_ack *extack) 812 + { 813 + struct ice_dpll_pin *p = pin_priv; 814 + struct ice_dpll *d = dpll_priv; 815 + struct ice_pf *pf = d->pf; 816 + int ret; 817 + 818 + if (prio > ICE_DPLL_PRIO_MAX) { 819 + NL_SET_ERR_MSG_FMT(extack, "prio out of supported range 0-%d", 820 + ICE_DPLL_PRIO_MAX); 821 + return -EINVAL; 822 + } 823 + 824 + mutex_lock(&pf->dplls.lock); 825 + ret = ice_dpll_hw_input_prio_set(pf, d, p, prio, extack); 826 + mutex_unlock(&pf->dplls.lock); 827 + 828 + return ret; 829 + } 830 + 831 + /** 832 + * ice_dpll_input_direction - callback for get input pin direction 833 + * @pin: pointer to a pin 834 + * @pin_priv: private data pointer passed on pin registration 835 + * @dpll: registered dpll pointer 836 + * @dpll_priv: private data pointer passed on dpll registration 837 + * @direction: holds input pin direction 838 + * @extack: error reporting 839 + * 840 + * Dpll subsystem callback. Handler for getting direction of a input pin. 841 + * 842 + * Return: 843 + * * 0 - success 844 + */ 845 + static int 846 + ice_dpll_input_direction(const struct dpll_pin *pin, void *pin_priv, 847 + const struct dpll_device *dpll, void *dpll_priv, 848 + enum dpll_pin_direction *direction, 849 + struct netlink_ext_ack *extack) 850 + { 851 + *direction = DPLL_PIN_DIRECTION_INPUT; 852 + 853 + return 0; 854 + } 855 + 856 + /** 857 + * ice_dpll_output_direction - callback for get output pin direction 858 + * @pin: pointer to a pin 859 + * @pin_priv: private data pointer passed on pin registration 860 + * @dpll: registered dpll pointer 861 + * @dpll_priv: private data pointer passed on dpll registration 862 + * @direction: holds output pin direction 863 + * @extack: error reporting 864 + * 865 + * Dpll subsystem callback. Handler for getting direction of an output pin. 866 + * 867 + * Return: 868 + * * 0 - success 869 + */ 870 + static int 871 + ice_dpll_output_direction(const struct dpll_pin *pin, void *pin_priv, 872 + const struct dpll_device *dpll, void *dpll_priv, 873 + enum dpll_pin_direction *direction, 874 + struct netlink_ext_ack *extack) 875 + { 876 + *direction = DPLL_PIN_DIRECTION_OUTPUT; 877 + 878 + return 0; 879 + } 880 + 881 + /** 882 + * ice_dpll_rclk_state_on_pin_set - set a state on rclk pin 883 + * @pin: pointer to a pin 884 + * @pin_priv: private data pointer passed on pin registration 885 + * @parent_pin: pin parent pointer 886 + * @parent_pin_priv: parent private data pointer passed on pin registration 887 + * @state: state to be set on pin 888 + * @extack: error reporting 889 + * 890 + * Dpll subsystem callback, set a state of a rclk pin on a parent pin 891 + * 892 + * Context: Acquires pf->dplls.lock 893 + * Return: 894 + * * 0 - success 895 + * * negative - failure 896 + */ 897 + static int 898 + ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv, 899 + const struct dpll_pin *parent_pin, 900 + void *parent_pin_priv, 901 + enum dpll_pin_state state, 902 + struct netlink_ext_ack *extack) 903 + { 904 + struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; 905 + bool enable = state == DPLL_PIN_STATE_CONNECTED; 906 + struct ice_pf *pf = p->pf; 907 + int ret = -EINVAL; 908 + u32 hw_idx; 909 + 910 + mutex_lock(&pf->dplls.lock); 911 + hw_idx = parent->idx - pf->dplls.base_rclk_idx; 912 + if (hw_idx >= pf->dplls.num_inputs) 913 + goto unlock; 914 + 915 + if ((enable && p->state[hw_idx] == DPLL_PIN_STATE_CONNECTED) || 916 + (!enable && p->state[hw_idx] == DPLL_PIN_STATE_DISCONNECTED)) { 917 + NL_SET_ERR_MSG_FMT(extack, 918 + "pin:%u state:%u on parent:%u already set", 919 + p->idx, state, parent->idx); 920 + goto unlock; 921 + } 922 + ret = ice_aq_set_phy_rec_clk_out(&pf->hw, hw_idx, enable, 923 + &p->freq); 924 + if (ret) 925 + NL_SET_ERR_MSG_FMT(extack, 926 + "err:%d %s failed to set pin state:%u for pin:%u on parent:%u\n", 927 + ret, 928 + ice_aq_str(pf->hw.adminq.sq_last_status), 929 + state, p->idx, parent->idx); 930 + unlock: 931 + mutex_unlock(&pf->dplls.lock); 932 + 933 + return ret; 934 + } 935 + 936 + /** 937 + * ice_dpll_rclk_state_on_pin_get - get a state of rclk pin 938 + * @pin: pointer to a pin 939 + * @pin_priv: private data pointer passed on pin registration 940 + * @parent_pin: pin parent pointer 941 + * @parent_pin_priv: pin parent priv data pointer passed on pin registration 942 + * @state: on success holds pin state on parent pin 943 + * @extack: error reporting 944 + * 945 + * dpll subsystem callback, get a state of a recovered clock pin. 946 + * 947 + * Context: Acquires pf->dplls.lock 948 + * Return: 949 + * * 0 - success 950 + * * negative - failure 951 + */ 952 + static int 953 + ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv, 954 + const struct dpll_pin *parent_pin, 955 + void *parent_pin_priv, 956 + enum dpll_pin_state *state, 957 + struct netlink_ext_ack *extack) 958 + { 959 + struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; 960 + struct ice_pf *pf = p->pf; 961 + int ret = -EINVAL; 962 + u32 hw_idx; 963 + 964 + mutex_lock(&pf->dplls.lock); 965 + hw_idx = parent->idx - pf->dplls.base_rclk_idx; 966 + if (hw_idx >= pf->dplls.num_inputs) 967 + goto unlock; 968 + 969 + ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_RCLK_INPUT, 970 + extack); 971 + if (ret) 972 + goto unlock; 973 + 974 + *state = p->state[hw_idx]; 975 + ret = 0; 976 + unlock: 977 + mutex_unlock(&pf->dplls.lock); 978 + 979 + return ret; 980 + } 981 + 982 + static const struct dpll_pin_ops ice_dpll_rclk_ops = { 983 + .state_on_pin_set = ice_dpll_rclk_state_on_pin_set, 984 + .state_on_pin_get = ice_dpll_rclk_state_on_pin_get, 985 + .direction_get = ice_dpll_input_direction, 986 + }; 987 + 988 + static const struct dpll_pin_ops ice_dpll_input_ops = { 989 + .frequency_get = ice_dpll_input_frequency_get, 990 + .frequency_set = ice_dpll_input_frequency_set, 991 + .state_on_dpll_get = ice_dpll_input_state_get, 992 + .state_on_dpll_set = ice_dpll_input_state_set, 993 + .prio_get = ice_dpll_input_prio_get, 994 + .prio_set = ice_dpll_input_prio_set, 995 + .direction_get = ice_dpll_input_direction, 996 + }; 997 + 998 + static const struct dpll_pin_ops ice_dpll_output_ops = { 999 + .frequency_get = ice_dpll_output_frequency_get, 1000 + .frequency_set = ice_dpll_output_frequency_set, 1001 + .state_on_dpll_get = ice_dpll_output_state_get, 1002 + .state_on_dpll_set = ice_dpll_output_state_set, 1003 + .direction_get = ice_dpll_output_direction, 1004 + }; 1005 + 1006 + static const struct dpll_device_ops ice_dpll_ops = { 1007 + .lock_status_get = ice_dpll_lock_status_get, 1008 + .mode_supported = ice_dpll_mode_supported, 1009 + .mode_get = ice_dpll_mode_get, 1010 + }; 1011 + 1012 + /** 1013 + * ice_generate_clock_id - generates unique clock_id for registering dpll. 1014 + * @pf: board private structure 1015 + * 1016 + * Generates unique (per board) clock_id for allocation and search of dpll 1017 + * devices in Linux dpll subsystem. 1018 + * 1019 + * Return: generated clock id for the board 1020 + */ 1021 + static u64 ice_generate_clock_id(struct ice_pf *pf) 1022 + { 1023 + return pci_get_dsn(pf->pdev); 1024 + } 1025 + 1026 + /** 1027 + * ice_dpll_notify_changes - notify dpll subsystem about changes 1028 + * @d: pointer do dpll 1029 + * 1030 + * Once change detected appropriate event is submitted to the dpll subsystem. 1031 + */ 1032 + static void ice_dpll_notify_changes(struct ice_dpll *d) 1033 + { 1034 + if (d->prev_dpll_state != d->dpll_state) { 1035 + d->prev_dpll_state = d->dpll_state; 1036 + dpll_device_change_ntf(d->dpll); 1037 + } 1038 + if (d->prev_input != d->active_input) { 1039 + if (d->prev_input) 1040 + dpll_pin_change_ntf(d->prev_input); 1041 + d->prev_input = d->active_input; 1042 + if (d->active_input) 1043 + dpll_pin_change_ntf(d->active_input); 1044 + } 1045 + } 1046 + 1047 + /** 1048 + * ice_dpll_update_state - update dpll state 1049 + * @pf: pf private structure 1050 + * @d: pointer to queried dpll device 1051 + * @init: if function called on initialization of ice dpll 1052 + * 1053 + * Poll current state of dpll from hw and update ice_dpll struct. 1054 + * 1055 + * Context: Called by kworker under pf->dplls.lock 1056 + * Return: 1057 + * * 0 - success 1058 + * * negative - AQ failure 1059 + */ 1060 + static int 1061 + ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) 1062 + { 1063 + struct ice_dpll_pin *p = NULL; 1064 + int ret; 1065 + 1066 + ret = ice_get_cgu_state(&pf->hw, d->dpll_idx, d->prev_dpll_state, 1067 + &d->input_idx, &d->ref_state, &d->eec_mode, 1068 + &d->phase_shift, &d->dpll_state); 1069 + 1070 + dev_dbg(ice_pf_to_dev(pf), 1071 + "update dpll=%d, prev_src_idx:%u, src_idx:%u, state:%d, prev:%d mode:%d\n", 1072 + d->dpll_idx, d->prev_input_idx, d->input_idx, 1073 + d->dpll_state, d->prev_dpll_state, d->mode); 1074 + if (ret) { 1075 + dev_err(ice_pf_to_dev(pf), 1076 + "update dpll=%d state failed, ret=%d %s\n", 1077 + d->dpll_idx, ret, 1078 + ice_aq_str(pf->hw.adminq.sq_last_status)); 1079 + return ret; 1080 + } 1081 + if (init) { 1082 + if (d->dpll_state == DPLL_LOCK_STATUS_LOCKED || 1083 + d->dpll_state == DPLL_LOCK_STATUS_LOCKED_HO_ACQ) 1084 + d->active_input = pf->dplls.inputs[d->input_idx].pin; 1085 + p = &pf->dplls.inputs[d->input_idx]; 1086 + return ice_dpll_pin_state_update(pf, p, 1087 + ICE_DPLL_PIN_TYPE_INPUT, NULL); 1088 + } 1089 + if (d->dpll_state == DPLL_LOCK_STATUS_HOLDOVER || 1090 + d->dpll_state == DPLL_LOCK_STATUS_UNLOCKED) { 1091 + d->active_input = NULL; 1092 + if (d->input_idx != ICE_DPLL_PIN_IDX_INVALID) 1093 + p = &pf->dplls.inputs[d->input_idx]; 1094 + d->prev_input_idx = ICE_DPLL_PIN_IDX_INVALID; 1095 + d->input_idx = ICE_DPLL_PIN_IDX_INVALID; 1096 + if (!p) 1097 + return 0; 1098 + ret = ice_dpll_pin_state_update(pf, p, 1099 + ICE_DPLL_PIN_TYPE_INPUT, NULL); 1100 + } else if (d->input_idx != d->prev_input_idx) { 1101 + if (d->prev_input_idx != ICE_DPLL_PIN_IDX_INVALID) { 1102 + p = &pf->dplls.inputs[d->prev_input_idx]; 1103 + ice_dpll_pin_state_update(pf, p, 1104 + ICE_DPLL_PIN_TYPE_INPUT, 1105 + NULL); 1106 + } 1107 + if (d->input_idx != ICE_DPLL_PIN_IDX_INVALID) { 1108 + p = &pf->dplls.inputs[d->input_idx]; 1109 + d->active_input = p->pin; 1110 + ice_dpll_pin_state_update(pf, p, 1111 + ICE_DPLL_PIN_TYPE_INPUT, 1112 + NULL); 1113 + } 1114 + d->prev_input_idx = d->input_idx; 1115 + } 1116 + 1117 + return ret; 1118 + } 1119 + 1120 + /** 1121 + * ice_dpll_periodic_work - DPLLs periodic worker 1122 + * @work: pointer to kthread_work structure 1123 + * 1124 + * DPLLs periodic worker is responsible for polling state of dpll. 1125 + * Context: Holds pf->dplls.lock 1126 + */ 1127 + static void ice_dpll_periodic_work(struct kthread_work *work) 1128 + { 1129 + struct ice_dplls *d = container_of(work, struct ice_dplls, work.work); 1130 + struct ice_pf *pf = container_of(d, struct ice_pf, dplls); 1131 + struct ice_dpll *de = &pf->dplls.eec; 1132 + struct ice_dpll *dp = &pf->dplls.pps; 1133 + int ret; 1134 + 1135 + mutex_lock(&pf->dplls.lock); 1136 + ret = ice_dpll_update_state(pf, de, false); 1137 + if (!ret) 1138 + ret = ice_dpll_update_state(pf, dp, false); 1139 + if (ret) { 1140 + d->cgu_state_acq_err_num++; 1141 + /* stop rescheduling this worker */ 1142 + if (d->cgu_state_acq_err_num > 1143 + ICE_CGU_STATE_ACQ_ERR_THRESHOLD) { 1144 + dev_err(ice_pf_to_dev(pf), 1145 + "EEC/PPS DPLLs periodic work disabled\n"); 1146 + mutex_unlock(&pf->dplls.lock); 1147 + return; 1148 + } 1149 + } 1150 + mutex_unlock(&pf->dplls.lock); 1151 + ice_dpll_notify_changes(de); 1152 + ice_dpll_notify_changes(dp); 1153 + 1154 + /* Run twice a second or reschedule if update failed */ 1155 + kthread_queue_delayed_work(d->kworker, &d->work, 1156 + ret ? msecs_to_jiffies(10) : 1157 + msecs_to_jiffies(500)); 1158 + } 1159 + 1160 + /** 1161 + * ice_dpll_release_pins - release pins resources from dpll subsystem 1162 + * @pins: pointer to pins array 1163 + * @count: number of pins 1164 + * 1165 + * Release resources of given pins array in the dpll subsystem. 1166 + */ 1167 + static void ice_dpll_release_pins(struct ice_dpll_pin *pins, int count) 1168 + { 1169 + int i; 1170 + 1171 + for (i = 0; i < count; i++) 1172 + dpll_pin_put(pins[i].pin); 1173 + } 1174 + 1175 + /** 1176 + * ice_dpll_get_pins - get pins from dpll subsystem 1177 + * @pf: board private structure 1178 + * @pins: pointer to pins array 1179 + * @start_idx: get starts from this pin idx value 1180 + * @count: number of pins 1181 + * @clock_id: clock_id of dpll device 1182 + * 1183 + * Get pins - allocate - in dpll subsystem, store them in pin field of given 1184 + * pins array. 1185 + * 1186 + * Return: 1187 + * * 0 - success 1188 + * * negative - allocation failure reason 1189 + */ 1190 + static int 1191 + ice_dpll_get_pins(struct ice_pf *pf, struct ice_dpll_pin *pins, 1192 + int start_idx, int count, u64 clock_id) 1193 + { 1194 + int i, ret; 1195 + 1196 + for (i = 0; i < count; i++) { 1197 + pins[i].pin = dpll_pin_get(clock_id, i + start_idx, THIS_MODULE, 1198 + &pins[i].prop); 1199 + if (IS_ERR(pins[i].pin)) { 1200 + ret = PTR_ERR(pins[i].pin); 1201 + goto release_pins; 1202 + } 1203 + } 1204 + 1205 + return 0; 1206 + 1207 + release_pins: 1208 + while (--i >= 0) 1209 + dpll_pin_put(pins[i].pin); 1210 + return ret; 1211 + } 1212 + 1213 + /** 1214 + * ice_dpll_unregister_pins - unregister pins from a dpll 1215 + * @dpll: dpll device pointer 1216 + * @pins: pointer to pins array 1217 + * @ops: callback ops registered with the pins 1218 + * @count: number of pins 1219 + * 1220 + * Unregister pins of a given array of pins from given dpll device registered in 1221 + * dpll subsystem. 1222 + */ 1223 + static void 1224 + ice_dpll_unregister_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, 1225 + const struct dpll_pin_ops *ops, int count) 1226 + { 1227 + int i; 1228 + 1229 + for (i = 0; i < count; i++) 1230 + dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]); 1231 + } 1232 + 1233 + /** 1234 + * ice_dpll_register_pins - register pins with a dpll 1235 + * @dpll: dpll pointer to register pins with 1236 + * @pins: pointer to pins array 1237 + * @ops: callback ops registered with the pins 1238 + * @count: number of pins 1239 + * 1240 + * Register pins of a given array with given dpll in dpll subsystem. 1241 + * 1242 + * Return: 1243 + * * 0 - success 1244 + * * negative - registration failure reason 1245 + */ 1246 + static int 1247 + ice_dpll_register_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, 1248 + const struct dpll_pin_ops *ops, int count) 1249 + { 1250 + int ret, i; 1251 + 1252 + for (i = 0; i < count; i++) { 1253 + ret = dpll_pin_register(dpll, pins[i].pin, ops, &pins[i]); 1254 + if (ret) 1255 + goto unregister_pins; 1256 + } 1257 + 1258 + return 0; 1259 + 1260 + unregister_pins: 1261 + while (--i >= 0) 1262 + dpll_pin_unregister(dpll, pins[i].pin, ops, &pins[i]); 1263 + return ret; 1264 + } 1265 + 1266 + /** 1267 + * ice_dpll_deinit_direct_pins - deinitialize direct pins 1268 + * @cgu: if cgu is present and controlled by this NIC 1269 + * @pins: pointer to pins array 1270 + * @count: number of pins 1271 + * @ops: callback ops registered with the pins 1272 + * @first: dpll device pointer 1273 + * @second: dpll device pointer 1274 + * 1275 + * If cgu is owned unregister pins from given dplls. 1276 + * Release pins resources to the dpll subsystem. 1277 + */ 1278 + static void 1279 + ice_dpll_deinit_direct_pins(bool cgu, struct ice_dpll_pin *pins, int count, 1280 + const struct dpll_pin_ops *ops, 1281 + struct dpll_device *first, 1282 + struct dpll_device *second) 1283 + { 1284 + if (cgu) { 1285 + ice_dpll_unregister_pins(first, pins, ops, count); 1286 + ice_dpll_unregister_pins(second, pins, ops, count); 1287 + } 1288 + ice_dpll_release_pins(pins, count); 1289 + } 1290 + 1291 + /** 1292 + * ice_dpll_init_direct_pins - initialize direct pins 1293 + * @pf: board private structure 1294 + * @cgu: if cgu is present and controlled by this NIC 1295 + * @pins: pointer to pins array 1296 + * @start_idx: on which index shall allocation start in dpll subsystem 1297 + * @count: number of pins 1298 + * @ops: callback ops registered with the pins 1299 + * @first: dpll device pointer 1300 + * @second: dpll device pointer 1301 + * 1302 + * Allocate directly connected pins of a given array in dpll subsystem. 1303 + * If cgu is owned register allocated pins with given dplls. 1304 + * 1305 + * Return: 1306 + * * 0 - success 1307 + * * negative - registration failure reason 1308 + */ 1309 + static int 1310 + ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu, 1311 + struct ice_dpll_pin *pins, int start_idx, int count, 1312 + const struct dpll_pin_ops *ops, 1313 + struct dpll_device *first, struct dpll_device *second) 1314 + { 1315 + int ret; 1316 + 1317 + ret = ice_dpll_get_pins(pf, pins, start_idx, count, pf->dplls.clock_id); 1318 + if (ret) 1319 + return ret; 1320 + if (cgu) { 1321 + ret = ice_dpll_register_pins(first, pins, ops, count); 1322 + if (ret) 1323 + goto release_pins; 1324 + ret = ice_dpll_register_pins(second, pins, ops, count); 1325 + if (ret) 1326 + goto unregister_first; 1327 + } 1328 + 1329 + return 0; 1330 + 1331 + unregister_first: 1332 + ice_dpll_unregister_pins(first, pins, ops, count); 1333 + release_pins: 1334 + ice_dpll_release_pins(pins, count); 1335 + return ret; 1336 + } 1337 + 1338 + /** 1339 + * ice_dpll_deinit_rclk_pin - release rclk pin resources 1340 + * @pf: board private structure 1341 + * 1342 + * Deregister rclk pin from parent pins and release resources in dpll subsystem. 1343 + */ 1344 + static void ice_dpll_deinit_rclk_pin(struct ice_pf *pf) 1345 + { 1346 + struct ice_dpll_pin *rclk = &pf->dplls.rclk; 1347 + struct ice_vsi *vsi = ice_get_main_vsi(pf); 1348 + struct dpll_pin *parent; 1349 + int i; 1350 + 1351 + for (i = 0; i < rclk->num_parents; i++) { 1352 + parent = pf->dplls.inputs[rclk->parent_idx[i]].pin; 1353 + if (!parent) 1354 + continue; 1355 + dpll_pin_on_pin_unregister(parent, rclk->pin, 1356 + &ice_dpll_rclk_ops, rclk); 1357 + } 1358 + if (WARN_ON_ONCE(!vsi || !vsi->netdev)) 1359 + return; 1360 + netdev_dpll_pin_clear(vsi->netdev); 1361 + dpll_pin_put(rclk->pin); 1362 + } 1363 + 1364 + /** 1365 + * ice_dpll_init_rclk_pins - initialize recovered clock pin 1366 + * @pf: board private structure 1367 + * @pin: pin to register 1368 + * @start_idx: on which index shall allocation start in dpll subsystem 1369 + * @ops: callback ops registered with the pins 1370 + * 1371 + * Allocate resource for recovered clock pin in dpll subsystem. Register the 1372 + * pin with the parents it has in the info. Register pin with the pf's main vsi 1373 + * netdev. 1374 + * 1375 + * Return: 1376 + * * 0 - success 1377 + * * negative - registration failure reason 1378 + */ 1379 + static int 1380 + ice_dpll_init_rclk_pins(struct ice_pf *pf, struct ice_dpll_pin *pin, 1381 + int start_idx, const struct dpll_pin_ops *ops) 1382 + { 1383 + struct ice_vsi *vsi = ice_get_main_vsi(pf); 1384 + struct dpll_pin *parent; 1385 + int ret, i; 1386 + 1387 + ret = ice_dpll_get_pins(pf, pin, start_idx, ICE_DPLL_RCLK_NUM_PER_PF, 1388 + pf->dplls.clock_id); 1389 + if (ret) 1390 + return ret; 1391 + for (i = 0; i < pf->dplls.rclk.num_parents; i++) { 1392 + parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[i]].pin; 1393 + if (!parent) { 1394 + ret = -ENODEV; 1395 + goto unregister_pins; 1396 + } 1397 + ret = dpll_pin_on_pin_register(parent, pf->dplls.rclk.pin, 1398 + ops, &pf->dplls.rclk); 1399 + if (ret) 1400 + goto unregister_pins; 1401 + } 1402 + if (WARN_ON((!vsi || !vsi->netdev))) 1403 + return -EINVAL; 1404 + netdev_dpll_pin_set(vsi->netdev, pf->dplls.rclk.pin); 1405 + 1406 + return 0; 1407 + 1408 + unregister_pins: 1409 + while (i) { 1410 + parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[--i]].pin; 1411 + dpll_pin_on_pin_unregister(parent, pf->dplls.rclk.pin, 1412 + &ice_dpll_rclk_ops, &pf->dplls.rclk); 1413 + } 1414 + ice_dpll_release_pins(pin, ICE_DPLL_RCLK_NUM_PER_PF); 1415 + return ret; 1416 + } 1417 + 1418 + /** 1419 + * ice_dpll_deinit_pins - deinitialize direct pins 1420 + * @pf: board private structure 1421 + * @cgu: if cgu is controlled by this pf 1422 + * 1423 + * If cgu is owned unregister directly connected pins from the dplls. 1424 + * Release resources of directly connected pins from the dpll subsystem. 1425 + */ 1426 + static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) 1427 + { 1428 + struct ice_dpll_pin *outputs = pf->dplls.outputs; 1429 + struct ice_dpll_pin *inputs = pf->dplls.inputs; 1430 + int num_outputs = pf->dplls.num_outputs; 1431 + int num_inputs = pf->dplls.num_inputs; 1432 + struct ice_dplls *d = &pf->dplls; 1433 + struct ice_dpll *de = &d->eec; 1434 + struct ice_dpll *dp = &d->pps; 1435 + 1436 + ice_dpll_deinit_rclk_pin(pf); 1437 + if (cgu) { 1438 + ice_dpll_unregister_pins(dp->dpll, inputs, &ice_dpll_input_ops, 1439 + num_inputs); 1440 + ice_dpll_unregister_pins(de->dpll, inputs, &ice_dpll_input_ops, 1441 + num_inputs); 1442 + } 1443 + ice_dpll_release_pins(inputs, num_inputs); 1444 + if (cgu) { 1445 + ice_dpll_unregister_pins(dp->dpll, outputs, 1446 + &ice_dpll_output_ops, num_outputs); 1447 + ice_dpll_unregister_pins(de->dpll, outputs, 1448 + &ice_dpll_output_ops, num_outputs); 1449 + ice_dpll_release_pins(outputs, num_outputs); 1450 + } 1451 + } 1452 + 1453 + /** 1454 + * ice_dpll_init_pins - init pins and register pins with a dplls 1455 + * @pf: board private structure 1456 + * @cgu: if cgu is present and controlled by this NIC 1457 + * 1458 + * Initialize directly connected pf's pins within pf's dplls in a Linux dpll 1459 + * subsystem. 1460 + * 1461 + * Return: 1462 + * * 0 - success 1463 + * * negative - initialization failure reason 1464 + */ 1465 + static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) 1466 + { 1467 + u32 rclk_idx; 1468 + int ret; 1469 + 1470 + ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.inputs, 0, 1471 + pf->dplls.num_inputs, 1472 + &ice_dpll_input_ops, 1473 + pf->dplls.eec.dpll, pf->dplls.pps.dpll); 1474 + if (ret) 1475 + return ret; 1476 + if (cgu) { 1477 + ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.outputs, 1478 + pf->dplls.num_inputs, 1479 + pf->dplls.num_outputs, 1480 + &ice_dpll_output_ops, 1481 + pf->dplls.eec.dpll, 1482 + pf->dplls.pps.dpll); 1483 + if (ret) 1484 + goto deinit_inputs; 1485 + } 1486 + rclk_idx = pf->dplls.num_inputs + pf->dplls.num_outputs + pf->hw.pf_id; 1487 + ret = ice_dpll_init_rclk_pins(pf, &pf->dplls.rclk, rclk_idx, 1488 + &ice_dpll_rclk_ops); 1489 + if (ret) 1490 + goto deinit_outputs; 1491 + 1492 + return 0; 1493 + deinit_outputs: 1494 + ice_dpll_deinit_direct_pins(cgu, pf->dplls.outputs, 1495 + pf->dplls.num_outputs, 1496 + &ice_dpll_output_ops, pf->dplls.pps.dpll, 1497 + pf->dplls.eec.dpll); 1498 + deinit_inputs: 1499 + ice_dpll_deinit_direct_pins(cgu, pf->dplls.inputs, pf->dplls.num_inputs, 1500 + &ice_dpll_input_ops, pf->dplls.pps.dpll, 1501 + pf->dplls.eec.dpll); 1502 + return ret; 1503 + } 1504 + 1505 + /** 1506 + * ice_dpll_deinit_dpll - deinitialize dpll device 1507 + * @pf: board private structure 1508 + * @d: pointer to ice_dpll 1509 + * @cgu: if cgu is present and controlled by this NIC 1510 + * 1511 + * If cgu is owned unregister the dpll from dpll subsystem. 1512 + * Release resources of dpll device from dpll subsystem. 1513 + */ 1514 + static void 1515 + ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu) 1516 + { 1517 + if (cgu) 1518 + dpll_device_unregister(d->dpll, &ice_dpll_ops, d); 1519 + dpll_device_put(d->dpll); 1520 + } 1521 + 1522 + /** 1523 + * ice_dpll_init_dpll - initialize dpll device in dpll subsystem 1524 + * @pf: board private structure 1525 + * @d: dpll to be initialized 1526 + * @cgu: if cgu is present and controlled by this NIC 1527 + * @type: type of dpll being initialized 1528 + * 1529 + * Allocate dpll instance for this board in dpll subsystem, if cgu is controlled 1530 + * by this NIC, register dpll with the callback ops. 1531 + * 1532 + * Return: 1533 + * * 0 - success 1534 + * * negative - initialization failure reason 1535 + */ 1536 + static int 1537 + ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu, 1538 + enum dpll_type type) 1539 + { 1540 + u64 clock_id = pf->dplls.clock_id; 1541 + int ret; 1542 + 1543 + d->dpll = dpll_device_get(clock_id, d->dpll_idx, THIS_MODULE); 1544 + if (IS_ERR(d->dpll)) { 1545 + ret = PTR_ERR(d->dpll); 1546 + dev_err(ice_pf_to_dev(pf), 1547 + "dpll_device_get failed (%p) err=%d\n", d, ret); 1548 + return ret; 1549 + } 1550 + d->pf = pf; 1551 + if (cgu) { 1552 + ret = dpll_device_register(d->dpll, type, &ice_dpll_ops, d); 1553 + if (ret) { 1554 + dpll_device_put(d->dpll); 1555 + return ret; 1556 + } 1557 + } 1558 + 1559 + return 0; 1560 + } 1561 + 1562 + /** 1563 + * ice_dpll_deinit_worker - deinitialize dpll kworker 1564 + * @pf: board private structure 1565 + * 1566 + * Stop dpll's kworker, release it's resources. 1567 + */ 1568 + static void ice_dpll_deinit_worker(struct ice_pf *pf) 1569 + { 1570 + struct ice_dplls *d = &pf->dplls; 1571 + 1572 + kthread_cancel_delayed_work_sync(&d->work); 1573 + kthread_destroy_worker(d->kworker); 1574 + } 1575 + 1576 + /** 1577 + * ice_dpll_init_worker - Initialize DPLLs periodic worker 1578 + * @pf: board private structure 1579 + * 1580 + * Create and start DPLLs periodic worker. 1581 + * 1582 + * Context: Shall be called after pf->dplls.lock is initialized. 1583 + * Return: 1584 + * * 0 - success 1585 + * * negative - create worker failure 1586 + */ 1587 + static int ice_dpll_init_worker(struct ice_pf *pf) 1588 + { 1589 + struct ice_dplls *d = &pf->dplls; 1590 + struct kthread_worker *kworker; 1591 + 1592 + ice_dpll_update_state(pf, &d->eec, true); 1593 + ice_dpll_update_state(pf, &d->pps, true); 1594 + kthread_init_delayed_work(&d->work, ice_dpll_periodic_work); 1595 + kworker = kthread_create_worker(0, "ice-dplls-%s", 1596 + dev_name(ice_pf_to_dev(pf))); 1597 + if (IS_ERR(kworker)) 1598 + return PTR_ERR(kworker); 1599 + d->kworker = kworker; 1600 + d->cgu_state_acq_err_num = 0; 1601 + kthread_queue_delayed_work(d->kworker, &d->work, 0); 1602 + 1603 + return 0; 1604 + } 1605 + 1606 + /** 1607 + * ice_dpll_init_info_direct_pins - initializes direct pins info 1608 + * @pf: board private structure 1609 + * @pin_type: type of pins being initialized 1610 + * 1611 + * Init information for directly connected pins, cache them in pf's pins 1612 + * structures. 1613 + * 1614 + * Return: 1615 + * * 0 - success 1616 + * * negative - init failure reason 1617 + */ 1618 + static int 1619 + ice_dpll_init_info_direct_pins(struct ice_pf *pf, 1620 + enum ice_dpll_pin_type pin_type) 1621 + { 1622 + struct ice_dpll *de = &pf->dplls.eec, *dp = &pf->dplls.pps; 1623 + int num_pins, i, ret = -EINVAL; 1624 + struct ice_hw *hw = &pf->hw; 1625 + struct ice_dpll_pin *pins; 1626 + u8 freq_supp_num; 1627 + bool input; 1628 + 1629 + switch (pin_type) { 1630 + case ICE_DPLL_PIN_TYPE_INPUT: 1631 + pins = pf->dplls.inputs; 1632 + num_pins = pf->dplls.num_inputs; 1633 + input = true; 1634 + break; 1635 + case ICE_DPLL_PIN_TYPE_OUTPUT: 1636 + pins = pf->dplls.outputs; 1637 + num_pins = pf->dplls.num_outputs; 1638 + input = false; 1639 + break; 1640 + default: 1641 + return -EINVAL; 1642 + } 1643 + 1644 + for (i = 0; i < num_pins; i++) { 1645 + pins[i].idx = i; 1646 + pins[i].prop.board_label = ice_cgu_get_pin_name(hw, i, input); 1647 + pins[i].prop.type = ice_cgu_get_pin_type(hw, i, input); 1648 + if (input) { 1649 + ret = ice_aq_get_cgu_ref_prio(hw, de->dpll_idx, i, 1650 + &de->input_prio[i]); 1651 + if (ret) 1652 + return ret; 1653 + ret = ice_aq_get_cgu_ref_prio(hw, dp->dpll_idx, i, 1654 + &dp->input_prio[i]); 1655 + if (ret) 1656 + return ret; 1657 + pins[i].prop.capabilities |= 1658 + DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE; 1659 + } 1660 + pins[i].prop.capabilities |= 1661 + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; 1662 + ret = ice_dpll_pin_state_update(pf, &pins[i], pin_type, NULL); 1663 + if (ret) 1664 + return ret; 1665 + pins[i].prop.freq_supported = 1666 + ice_cgu_get_pin_freq_supp(hw, i, input, &freq_supp_num); 1667 + pins[i].prop.freq_supported_num = freq_supp_num; 1668 + pins[i].pf = pf; 1669 + } 1670 + 1671 + return ret; 1672 + } 1673 + 1674 + /** 1675 + * ice_dpll_init_info_rclk_pin - initializes rclk pin information 1676 + * @pf: board private structure 1677 + * 1678 + * Init information for rclk pin, cache them in pf->dplls.rclk. 1679 + * 1680 + * Return: 1681 + * * 0 - success 1682 + * * negative - init failure reason 1683 + */ 1684 + static int ice_dpll_init_info_rclk_pin(struct ice_pf *pf) 1685 + { 1686 + struct ice_dpll_pin *pin = &pf->dplls.rclk; 1687 + 1688 + pin->prop.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT; 1689 + pin->prop.capabilities |= DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; 1690 + pin->pf = pf; 1691 + 1692 + return ice_dpll_pin_state_update(pf, pin, 1693 + ICE_DPLL_PIN_TYPE_RCLK_INPUT, NULL); 1694 + } 1695 + 1696 + /** 1697 + * ice_dpll_init_pins_info - init pins info wrapper 1698 + * @pf: board private structure 1699 + * @pin_type: type of pins being initialized 1700 + * 1701 + * Wraps functions for pin initialization. 1702 + * 1703 + * Return: 1704 + * * 0 - success 1705 + * * negative - init failure reason 1706 + */ 1707 + static int 1708 + ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) 1709 + { 1710 + switch (pin_type) { 1711 + case ICE_DPLL_PIN_TYPE_INPUT: 1712 + case ICE_DPLL_PIN_TYPE_OUTPUT: 1713 + return ice_dpll_init_info_direct_pins(pf, pin_type); 1714 + case ICE_DPLL_PIN_TYPE_RCLK_INPUT: 1715 + return ice_dpll_init_info_rclk_pin(pf); 1716 + default: 1717 + return -EINVAL; 1718 + } 1719 + } 1720 + 1721 + /** 1722 + * ice_dpll_deinit_info - release memory allocated for pins info 1723 + * @pf: board private structure 1724 + * 1725 + * Release memory allocated for pins by ice_dpll_init_info function. 1726 + */ 1727 + static void ice_dpll_deinit_info(struct ice_pf *pf) 1728 + { 1729 + kfree(pf->dplls.inputs); 1730 + kfree(pf->dplls.outputs); 1731 + kfree(pf->dplls.eec.input_prio); 1732 + kfree(pf->dplls.pps.input_prio); 1733 + } 1734 + 1735 + /** 1736 + * ice_dpll_init_info - prepare pf's dpll information structure 1737 + * @pf: board private structure 1738 + * @cgu: if cgu is present and controlled by this NIC 1739 + * 1740 + * Acquire (from HW) and set basic dpll information (on pf->dplls struct). 1741 + * 1742 + * Return: 1743 + * * 0 - success 1744 + * * negative - init failure reason 1745 + */ 1746 + static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) 1747 + { 1748 + struct ice_aqc_get_cgu_abilities abilities; 1749 + struct ice_dpll *de = &pf->dplls.eec; 1750 + struct ice_dpll *dp = &pf->dplls.pps; 1751 + struct ice_dplls *d = &pf->dplls; 1752 + struct ice_hw *hw = &pf->hw; 1753 + int ret, alloc_size, i; 1754 + 1755 + d->clock_id = ice_generate_clock_id(pf); 1756 + ret = ice_aq_get_cgu_abilities(hw, &abilities); 1757 + if (ret) { 1758 + dev_err(ice_pf_to_dev(pf), 1759 + "err:%d %s failed to read cgu abilities\n", 1760 + ret, ice_aq_str(hw->adminq.sq_last_status)); 1761 + return ret; 1762 + } 1763 + 1764 + de->dpll_idx = abilities.eec_dpll_idx; 1765 + dp->dpll_idx = abilities.pps_dpll_idx; 1766 + d->num_inputs = abilities.num_inputs; 1767 + d->num_outputs = abilities.num_outputs; 1768 + d->input_phase_adj_max = le32_to_cpu(abilities.max_in_phase_adj); 1769 + d->output_phase_adj_max = le32_to_cpu(abilities.max_out_phase_adj); 1770 + 1771 + alloc_size = sizeof(*d->inputs) * d->num_inputs; 1772 + d->inputs = kzalloc(alloc_size, GFP_KERNEL); 1773 + if (!d->inputs) 1774 + return -ENOMEM; 1775 + 1776 + alloc_size = sizeof(*de->input_prio) * d->num_inputs; 1777 + de->input_prio = kzalloc(alloc_size, GFP_KERNEL); 1778 + if (!de->input_prio) 1779 + return -ENOMEM; 1780 + 1781 + dp->input_prio = kzalloc(alloc_size, GFP_KERNEL); 1782 + if (!dp->input_prio) 1783 + return -ENOMEM; 1784 + 1785 + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT); 1786 + if (ret) 1787 + goto deinit_info; 1788 + 1789 + if (cgu) { 1790 + alloc_size = sizeof(*d->outputs) * d->num_outputs; 1791 + d->outputs = kzalloc(alloc_size, GFP_KERNEL); 1792 + if (!d->outputs) { 1793 + ret = -ENOMEM; 1794 + goto deinit_info; 1795 + } 1796 + 1797 + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_OUTPUT); 1798 + if (ret) 1799 + goto deinit_info; 1800 + } 1801 + 1802 + ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx, 1803 + &pf->dplls.rclk.num_parents); 1804 + if (ret) 1805 + return ret; 1806 + for (i = 0; i < pf->dplls.rclk.num_parents; i++) 1807 + pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i; 1808 + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT); 1809 + if (ret) 1810 + return ret; 1811 + de->mode = DPLL_MODE_AUTOMATIC; 1812 + dp->mode = DPLL_MODE_AUTOMATIC; 1813 + 1814 + dev_dbg(ice_pf_to_dev(pf), 1815 + "%s - success, inputs:%u, outputs:%u rclk-parents:%u\n", 1816 + __func__, d->num_inputs, d->num_outputs, d->rclk.num_parents); 1817 + 1818 + return 0; 1819 + 1820 + deinit_info: 1821 + dev_err(ice_pf_to_dev(pf), 1822 + "%s - fail: d->inputs:%p, de->input_prio:%p, dp->input_prio:%p, d->outputs:%p\n", 1823 + __func__, d->inputs, de->input_prio, 1824 + dp->input_prio, d->outputs); 1825 + ice_dpll_deinit_info(pf); 1826 + return ret; 1827 + } 1828 + 1829 + /** 1830 + * ice_dpll_deinit - Disable the driver/HW support for dpll subsystem 1831 + * the dpll device. 1832 + * @pf: board private structure 1833 + * 1834 + * Handles the cleanup work required after dpll initialization, freeing 1835 + * resources and unregistering the dpll, pin and all resources used for 1836 + * handling them. 1837 + * 1838 + * Context: Destroys pf->dplls.lock mutex. Call only if ICE_FLAG_DPLL was set. 1839 + */ 1840 + void ice_dpll_deinit(struct ice_pf *pf) 1841 + { 1842 + bool cgu = ice_is_feature_supported(pf, ICE_F_CGU); 1843 + 1844 + clear_bit(ICE_FLAG_DPLL, pf->flags); 1845 + if (cgu) 1846 + ice_dpll_deinit_worker(pf); 1847 + 1848 + ice_dpll_deinit_pins(pf, cgu); 1849 + ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu); 1850 + ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu); 1851 + ice_dpll_deinit_info(pf); 1852 + mutex_destroy(&pf->dplls.lock); 1853 + } 1854 + 1855 + /** 1856 + * ice_dpll_init - initialize support for dpll subsystem 1857 + * @pf: board private structure 1858 + * 1859 + * Set up the device dplls, register them and pins connected within Linux dpll 1860 + * subsystem. Allow userspace to obtain state of DPLL and handling of DPLL 1861 + * configuration requests. 1862 + * 1863 + * Context: Initializes pf->dplls.lock mutex. 1864 + */ 1865 + void ice_dpll_init(struct ice_pf *pf) 1866 + { 1867 + bool cgu = ice_is_feature_supported(pf, ICE_F_CGU); 1868 + struct ice_dplls *d = &pf->dplls; 1869 + int err = 0; 1870 + 1871 + err = ice_dpll_init_info(pf, cgu); 1872 + if (err) 1873 + goto err_exit; 1874 + err = ice_dpll_init_dpll(pf, &pf->dplls.eec, cgu, DPLL_TYPE_EEC); 1875 + if (err) 1876 + goto deinit_info; 1877 + err = ice_dpll_init_dpll(pf, &pf->dplls.pps, cgu, DPLL_TYPE_PPS); 1878 + if (err) 1879 + goto deinit_eec; 1880 + err = ice_dpll_init_pins(pf, cgu); 1881 + if (err) 1882 + goto deinit_pps; 1883 + mutex_init(&d->lock); 1884 + if (cgu) { 1885 + err = ice_dpll_init_worker(pf); 1886 + if (err) 1887 + goto deinit_pins; 1888 + } 1889 + set_bit(ICE_FLAG_DPLL, pf->flags); 1890 + 1891 + return; 1892 + 1893 + deinit_pins: 1894 + ice_dpll_deinit_pins(pf, cgu); 1895 + deinit_pps: 1896 + ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu); 1897 + deinit_eec: 1898 + ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu); 1899 + deinit_info: 1900 + ice_dpll_deinit_info(pf); 1901 + err_exit: 1902 + mutex_destroy(&d->lock); 1903 + dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err); 1904 + }
+104
drivers/net/ethernet/intel/ice/ice_dpll.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (C) 2022, Intel Corporation. */ 3 + 4 + #ifndef _ICE_DPLL_H_ 5 + #define _ICE_DPLL_H_ 6 + 7 + #include "ice.h" 8 + 9 + #define ICE_DPLL_PRIO_MAX 0xF 10 + #define ICE_DPLL_RCLK_NUM_MAX 4 11 + 12 + /** ice_dpll_pin - store info about pins 13 + * @pin: dpll pin structure 14 + * @pf: pointer to pf, which has registered the dpll_pin 15 + * @idx: ice pin private idx 16 + * @num_parents: hols number of parent pins 17 + * @parent_idx: hold indexes of parent pins 18 + * @flags: pin flags returned from HW 19 + * @state: state of a pin 20 + * @prop: pin properties 21 + * @freq: current frequency of a pin 22 + */ 23 + struct ice_dpll_pin { 24 + struct dpll_pin *pin; 25 + struct ice_pf *pf; 26 + u8 idx; 27 + u8 num_parents; 28 + u8 parent_idx[ICE_DPLL_RCLK_NUM_MAX]; 29 + u8 flags[ICE_DPLL_RCLK_NUM_MAX]; 30 + u8 state[ICE_DPLL_RCLK_NUM_MAX]; 31 + struct dpll_pin_properties prop; 32 + u32 freq; 33 + }; 34 + 35 + /** ice_dpll - store info required for DPLL control 36 + * @dpll: pointer to dpll dev 37 + * @pf: pointer to pf, which has registered the dpll_device 38 + * @dpll_idx: index of dpll on the NIC 39 + * @input_idx: currently selected input index 40 + * @prev_input_idx: previously selected input index 41 + * @ref_state: state of dpll reference signals 42 + * @eec_mode: eec_mode dpll is configured for 43 + * @phase_shift: phase shift delay of a dpll 44 + * @input_prio: priorities of each input 45 + * @dpll_state: current dpll sync state 46 + * @prev_dpll_state: last dpll sync state 47 + * @active_input: pointer to active input pin 48 + * @prev_input: pointer to previous active input pin 49 + */ 50 + struct ice_dpll { 51 + struct dpll_device *dpll; 52 + struct ice_pf *pf; 53 + u8 dpll_idx; 54 + u8 input_idx; 55 + u8 prev_input_idx; 56 + u8 ref_state; 57 + u8 eec_mode; 58 + s64 phase_shift; 59 + u8 *input_prio; 60 + enum dpll_lock_status dpll_state; 61 + enum dpll_lock_status prev_dpll_state; 62 + enum dpll_mode mode; 63 + struct dpll_pin *active_input; 64 + struct dpll_pin *prev_input; 65 + }; 66 + 67 + /** ice_dplls - store info required for CCU (clock controlling unit) 68 + * @kworker: periodic worker 69 + * @work: periodic work 70 + * @lock: locks access to configuration of a dpll 71 + * @eec: pointer to EEC dpll dev 72 + * @pps: pointer to PPS dpll dev 73 + * @inputs: input pins pointer 74 + * @outputs: output pins pointer 75 + * @rclk: recovered pins pointer 76 + * @num_inputs: number of input pins available on dpll 77 + * @num_outputs: number of output pins available on dpll 78 + * @cgu_state_acq_err_num: number of errors returned during periodic work 79 + * @base_rclk_idx: idx of first pin used for clock revocery pins 80 + * @clock_id: clock_id of dplls 81 + */ 82 + struct ice_dplls { 83 + struct kthread_worker *kworker; 84 + struct kthread_delayed_work work; 85 + struct mutex lock; 86 + struct ice_dpll eec; 87 + struct ice_dpll pps; 88 + struct ice_dpll_pin *inputs; 89 + struct ice_dpll_pin *outputs; 90 + struct ice_dpll_pin rclk; 91 + u8 num_inputs; 92 + u8 num_outputs; 93 + int cgu_state_acq_err_num; 94 + u8 base_rclk_idx; 95 + u64 clock_id; 96 + s32 input_phase_adj_max; 97 + s32 output_phase_adj_max; 98 + }; 99 + 100 + void ice_dpll_init(struct ice_pf *pf); 101 + 102 + void ice_dpll_deinit(struct ice_pf *pf); 103 + 104 + #endif
+13 -4
drivers/net/ethernet/intel/ice/ice_lib.c
··· 3985 3985 case ICE_DEV_ID_E810C_BACKPLANE: 3986 3986 case ICE_DEV_ID_E810C_QSFP: 3987 3987 case ICE_DEV_ID_E810C_SFP: 3988 + case ICE_DEV_ID_E810_XXV_BACKPLANE: 3989 + case ICE_DEV_ID_E810_XXV_QSFP: 3990 + case ICE_DEV_ID_E810_XXV_SFP: 3988 3991 ice_set_feature_support(pf, ICE_F_DSCP); 3989 3992 ice_set_feature_support(pf, ICE_F_PTP_EXTTS); 3990 - if (ice_is_e810t(&pf->hw)) { 3993 + if (ice_is_phy_rclk_present(&pf->hw)) 3994 + ice_set_feature_support(pf, ICE_F_PHY_RCLK); 3995 + /* If we don't own the timer - don't enable other caps */ 3996 + if (!pf->hw.func_caps.ts_func_info.src_tmr_owned) 3997 + break; 3998 + if (ice_is_cgu_present(&pf->hw)) 3999 + ice_set_feature_support(pf, ICE_F_CGU); 4000 + if (ice_is_clock_mux_present_e810t(&pf->hw)) 3991 4001 ice_set_feature_support(pf, ICE_F_SMA_CTRL); 3992 - if (ice_gnss_is_gps_present(&pf->hw)) 3993 - ice_set_feature_support(pf, ICE_F_GNSS); 3994 - } 4002 + if (ice_gnss_is_gps_present(&pf->hw)) 4003 + ice_set_feature_support(pf, ICE_F_GNSS); 3995 4004 break; 3996 4005 default: 3997 4006 break;
+6
drivers/net/ethernet/intel/ice/ice_main.c
··· 4665 4665 if (ice_is_feature_supported(pf, ICE_F_GNSS)) 4666 4666 ice_gnss_init(pf); 4667 4667 4668 + if (ice_is_feature_supported(pf, ICE_F_CGU) || 4669 + ice_is_feature_supported(pf, ICE_F_PHY_RCLK)) 4670 + ice_dpll_init(pf); 4671 + 4668 4672 /* Note: Flow director init failure is non-fatal to load */ 4669 4673 if (ice_init_fdir(pf)) 4670 4674 dev_err(dev, "could not initialize flow director\n"); ··· 4695 4691 ice_gnss_exit(pf); 4696 4692 if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) 4697 4693 ice_ptp_release(pf); 4694 + if (test_bit(ICE_FLAG_DPLL, pf->flags)) 4695 + ice_dpll_deinit(pf); 4698 4696 } 4699 4697 4700 4698 static void ice_init_wakeup(struct ice_pf *pf)
+530
drivers/net/ethernet/intel/ice/ice_ptp_hw.c
··· 7 7 #include "ice_ptp_consts.h" 8 8 #include "ice_cgu_regs.h" 9 9 10 + static struct dpll_pin_frequency ice_cgu_pin_freq_common[] = { 11 + DPLL_PIN_FREQUENCY_1PPS, 12 + DPLL_PIN_FREQUENCY_10MHZ, 13 + }; 14 + 15 + static struct dpll_pin_frequency ice_cgu_pin_freq_1_hz[] = { 16 + DPLL_PIN_FREQUENCY_1PPS, 17 + }; 18 + 19 + static struct dpll_pin_frequency ice_cgu_pin_freq_10_mhz[] = { 20 + DPLL_PIN_FREQUENCY_10MHZ, 21 + }; 22 + 23 + static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = { 24 + { "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR, 25 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 26 + { "CVL-SDP20", ZL_REF0N, DPLL_PIN_TYPE_INT_OSCILLATOR, 27 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 28 + { "C827_0-RCLKA", ZL_REF1P, DPLL_PIN_TYPE_MUX, 0, }, 29 + { "C827_0-RCLKB", ZL_REF1N, DPLL_PIN_TYPE_MUX, 0, }, 30 + { "SMA1", ZL_REF3P, DPLL_PIN_TYPE_EXT, 31 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 32 + { "SMA2/U.FL2", ZL_REF3N, DPLL_PIN_TYPE_EXT, 33 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 34 + { "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS, 35 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 36 + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, 0, }, 37 + }; 38 + 39 + static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_inputs[] = { 40 + { "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR, 41 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 42 + { "CVL-SDP20", ZL_REF0N, DPLL_PIN_TYPE_INT_OSCILLATOR, 43 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 44 + { "C827_0-RCLKA", ZL_REF1P, DPLL_PIN_TYPE_MUX, }, 45 + { "C827_0-RCLKB", ZL_REF1N, DPLL_PIN_TYPE_MUX, }, 46 + { "C827_1-RCLKA", ZL_REF2P, DPLL_PIN_TYPE_MUX, }, 47 + { "C827_1-RCLKB", ZL_REF2N, DPLL_PIN_TYPE_MUX, }, 48 + { "SMA1", ZL_REF3P, DPLL_PIN_TYPE_EXT, 49 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 50 + { "SMA2/U.FL2", ZL_REF3N, DPLL_PIN_TYPE_EXT, 51 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 52 + { "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS, 53 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 54 + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, }, 55 + }; 56 + 57 + static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_outputs[] = { 58 + { "REF-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, 59 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 60 + { "REF-SMA2/U.FL2", ZL_OUT1, DPLL_PIN_TYPE_EXT, 61 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 62 + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, }, 63 + { "MAC-CLK", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, }, 64 + { "CVL-SDP21", ZL_OUT4, DPLL_PIN_TYPE_EXT, 65 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 66 + { "CVL-SDP23", ZL_OUT5, DPLL_PIN_TYPE_EXT, 67 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 68 + }; 69 + 70 + static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_outputs[] = { 71 + { "REF-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, 72 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 73 + { "REF-SMA2/U.FL2", ZL_OUT1, DPLL_PIN_TYPE_EXT, 74 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 75 + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, 76 + { "PHY2-CLK", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, 77 + { "MAC-CLK", ZL_OUT4, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, 78 + { "CVL-SDP21", ZL_OUT5, DPLL_PIN_TYPE_EXT, 79 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 80 + { "CVL-SDP23", ZL_OUT6, DPLL_PIN_TYPE_EXT, 81 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 82 + }; 83 + 84 + static const struct ice_cgu_pin_desc ice_e823_si_cgu_inputs[] = { 85 + { "NONE", SI_REF0P, 0, 0 }, 86 + { "NONE", SI_REF0N, 0, 0 }, 87 + { "SYNCE0_DP", SI_REF1P, DPLL_PIN_TYPE_MUX, 0 }, 88 + { "SYNCE0_DN", SI_REF1N, DPLL_PIN_TYPE_MUX, 0 }, 89 + { "EXT_CLK_SYNC", SI_REF2P, DPLL_PIN_TYPE_EXT, 90 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 91 + { "NONE", SI_REF2N, 0, 0 }, 92 + { "EXT_PPS_OUT", SI_REF3, DPLL_PIN_TYPE_EXT, 93 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 94 + { "INT_PPS_OUT", SI_REF4, DPLL_PIN_TYPE_EXT, 95 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 96 + }; 97 + 98 + static const struct ice_cgu_pin_desc ice_e823_si_cgu_outputs[] = { 99 + { "1588-TIME_SYNC", SI_OUT0, DPLL_PIN_TYPE_EXT, 100 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 101 + { "PHY-CLK", SI_OUT1, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, 102 + { "10MHZ-SMA2", SI_OUT2, DPLL_PIN_TYPE_EXT, 103 + ARRAY_SIZE(ice_cgu_pin_freq_10_mhz), ice_cgu_pin_freq_10_mhz }, 104 + { "PPS-SMA1", SI_OUT3, DPLL_PIN_TYPE_EXT, 105 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 106 + }; 107 + 108 + static const struct ice_cgu_pin_desc ice_e823_zl_cgu_inputs[] = { 109 + { "NONE", ZL_REF0P, 0, 0 }, 110 + { "INT_PPS_OUT", ZL_REF0N, DPLL_PIN_TYPE_EXT, 111 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 112 + { "SYNCE0_DP", ZL_REF1P, DPLL_PIN_TYPE_MUX, 0 }, 113 + { "SYNCE0_DN", ZL_REF1N, DPLL_PIN_TYPE_MUX, 0 }, 114 + { "NONE", ZL_REF2P, 0, 0 }, 115 + { "NONE", ZL_REF2N, 0, 0 }, 116 + { "EXT_CLK_SYNC", ZL_REF3P, DPLL_PIN_TYPE_EXT, 117 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 118 + { "NONE", ZL_REF3N, 0, 0 }, 119 + { "EXT_PPS_OUT", ZL_REF4P, DPLL_PIN_TYPE_EXT, 120 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 121 + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, 0 }, 122 + }; 123 + 124 + static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = { 125 + { "PPS-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, 126 + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, 127 + { "10MHZ-SMA2", ZL_OUT1, DPLL_PIN_TYPE_EXT, 128 + ARRAY_SIZE(ice_cgu_pin_freq_10_mhz), ice_cgu_pin_freq_10_mhz }, 129 + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, 130 + { "1588-TIME_REF", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, 131 + { "CPK-TIME_SYNC", ZL_OUT4, DPLL_PIN_TYPE_EXT, 132 + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, 133 + { "NONE", ZL_OUT5, 0, 0 }, 134 + }; 135 + 10 136 /* Low level functions for interacting with and managing the device clock used 11 137 * for the Precision Time Protocol. 12 138 * ··· 3480 3354 } 3481 3355 3482 3356 /** 3357 + * ice_is_phy_rclk_present - check recovered clk presence 3358 + * @hw: pointer to the hw struct 3359 + * 3360 + * Check if the PHY Recovered Clock device is present in the netlist 3361 + * Return: 3362 + * * true - device found in netlist 3363 + * * false - device not found 3364 + */ 3365 + bool ice_is_phy_rclk_present(struct ice_hw *hw) 3366 + { 3367 + if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, 3368 + ICE_AQC_GET_LINK_TOPO_NODE_NR_C827, NULL) && 3369 + ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, 3370 + ICE_AQC_GET_LINK_TOPO_NODE_NR_E822_PHY, NULL)) 3371 + return false; 3372 + 3373 + return true; 3374 + } 3375 + 3376 + /** 3377 + * ice_is_clock_mux_present_e810t 3378 + * @hw: pointer to the hw struct 3379 + * 3380 + * Check if the Clock Multiplexer device is present in the netlist 3381 + * Return: 3382 + * * true - device found in netlist 3383 + * * false - device not found 3384 + */ 3385 + bool ice_is_clock_mux_present_e810t(struct ice_hw *hw) 3386 + { 3387 + if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_MUX, 3388 + ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX, 3389 + NULL)) 3390 + return false; 3391 + 3392 + return true; 3393 + } 3394 + 3395 + /** 3396 + * ice_get_pf_c827_idx - find and return the C827 index for the current pf 3397 + * @hw: pointer to the hw struct 3398 + * @idx: index of the found C827 PHY 3399 + * Return: 3400 + * * 0 - success 3401 + * * negative - failure 3402 + */ 3403 + int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx) 3404 + { 3405 + struct ice_aqc_get_link_topo cmd; 3406 + u8 node_part_number; 3407 + u16 node_handle; 3408 + int status; 3409 + u8 ctx; 3410 + 3411 + if (hw->mac_type != ICE_MAC_E810) 3412 + return -ENODEV; 3413 + 3414 + if (hw->device_id != ICE_DEV_ID_E810C_QSFP) { 3415 + *idx = C827_0; 3416 + return 0; 3417 + } 3418 + 3419 + memset(&cmd, 0, sizeof(cmd)); 3420 + 3421 + ctx = ICE_AQC_LINK_TOPO_NODE_TYPE_PHY << ICE_AQC_LINK_TOPO_NODE_TYPE_S; 3422 + ctx |= ICE_AQC_LINK_TOPO_NODE_CTX_PORT << ICE_AQC_LINK_TOPO_NODE_CTX_S; 3423 + cmd.addr.topo_params.node_type_ctx = ctx; 3424 + 3425 + status = ice_aq_get_netlist_node(hw, &cmd, &node_part_number, 3426 + &node_handle); 3427 + if (status || node_part_number != ICE_AQC_GET_LINK_TOPO_NODE_NR_C827) 3428 + return -ENOENT; 3429 + 3430 + if (node_handle == E810C_QSFP_C827_0_HANDLE) 3431 + *idx = C827_0; 3432 + else if (node_handle == E810C_QSFP_C827_1_HANDLE) 3433 + *idx = C827_1; 3434 + else 3435 + return -EIO; 3436 + 3437 + return 0; 3438 + } 3439 + 3440 + /** 3483 3441 * ice_ptp_reset_ts_memory - Reset timestamp memory for all blocks 3484 3442 * @hw: pointer to the HW struct 3485 3443 */ ··· 3616 3406 else 3617 3407 return ice_get_phy_tx_tstamp_ready_e822(hw, block, 3618 3408 tstamp_ready); 3409 + } 3410 + 3411 + /** 3412 + * ice_is_cgu_present - check for CGU presence 3413 + * @hw: pointer to the hw struct 3414 + * 3415 + * Check if the Clock Generation Unit (CGU) device is present in the netlist 3416 + * Return: 3417 + * * true - cgu is present 3418 + * * false - cgu is not present 3419 + */ 3420 + bool ice_is_cgu_present(struct ice_hw *hw) 3421 + { 3422 + if (!ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, 3423 + ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032, 3424 + NULL)) { 3425 + hw->cgu_part_number = ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032; 3426 + return true; 3427 + } else if (!ice_find_netlist_node(hw, 3428 + ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, 3429 + ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384, 3430 + NULL)) { 3431 + hw->cgu_part_number = ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384; 3432 + return true; 3433 + } 3434 + 3435 + return false; 3436 + } 3437 + 3438 + /** 3439 + * ice_cgu_get_pin_desc_e823 - get pin description array 3440 + * @hw: pointer to the hw struct 3441 + * @input: if request is done against input or output pin 3442 + * @size: number of inputs/outputs 3443 + * 3444 + * Return: pointer to pin description array associated to given hw. 3445 + */ 3446 + static const struct ice_cgu_pin_desc * 3447 + ice_cgu_get_pin_desc_e823(struct ice_hw *hw, bool input, int *size) 3448 + { 3449 + static const struct ice_cgu_pin_desc *t; 3450 + 3451 + if (hw->cgu_part_number == 3452 + ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032) { 3453 + if (input) { 3454 + t = ice_e823_zl_cgu_inputs; 3455 + *size = ARRAY_SIZE(ice_e823_zl_cgu_inputs); 3456 + } else { 3457 + t = ice_e823_zl_cgu_outputs; 3458 + *size = ARRAY_SIZE(ice_e823_zl_cgu_outputs); 3459 + } 3460 + } else if (hw->cgu_part_number == 3461 + ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384) { 3462 + if (input) { 3463 + t = ice_e823_si_cgu_inputs; 3464 + *size = ARRAY_SIZE(ice_e823_si_cgu_inputs); 3465 + } else { 3466 + t = ice_e823_si_cgu_outputs; 3467 + *size = ARRAY_SIZE(ice_e823_si_cgu_outputs); 3468 + } 3469 + } else { 3470 + t = NULL; 3471 + *size = 0; 3472 + } 3473 + 3474 + return t; 3475 + } 3476 + 3477 + /** 3478 + * ice_cgu_get_pin_desc - get pin description array 3479 + * @hw: pointer to the hw struct 3480 + * @input: if request is done against input or output pins 3481 + * @size: size of array returned by function 3482 + * 3483 + * Return: pointer to pin description array associated to given hw. 3484 + */ 3485 + static const struct ice_cgu_pin_desc * 3486 + ice_cgu_get_pin_desc(struct ice_hw *hw, bool input, int *size) 3487 + { 3488 + const struct ice_cgu_pin_desc *t = NULL; 3489 + 3490 + switch (hw->device_id) { 3491 + case ICE_DEV_ID_E810C_SFP: 3492 + if (input) { 3493 + t = ice_e810t_sfp_cgu_inputs; 3494 + *size = ARRAY_SIZE(ice_e810t_sfp_cgu_inputs); 3495 + } else { 3496 + t = ice_e810t_sfp_cgu_outputs; 3497 + *size = ARRAY_SIZE(ice_e810t_sfp_cgu_outputs); 3498 + } 3499 + break; 3500 + case ICE_DEV_ID_E810C_QSFP: 3501 + if (input) { 3502 + t = ice_e810t_qsfp_cgu_inputs; 3503 + *size = ARRAY_SIZE(ice_e810t_qsfp_cgu_inputs); 3504 + } else { 3505 + t = ice_e810t_qsfp_cgu_outputs; 3506 + *size = ARRAY_SIZE(ice_e810t_qsfp_cgu_outputs); 3507 + } 3508 + break; 3509 + case ICE_DEV_ID_E823L_10G_BASE_T: 3510 + case ICE_DEV_ID_E823L_1GBE: 3511 + case ICE_DEV_ID_E823L_BACKPLANE: 3512 + case ICE_DEV_ID_E823L_QSFP: 3513 + case ICE_DEV_ID_E823L_SFP: 3514 + case ICE_DEV_ID_E823C_10G_BASE_T: 3515 + case ICE_DEV_ID_E823C_BACKPLANE: 3516 + case ICE_DEV_ID_E823C_QSFP: 3517 + case ICE_DEV_ID_E823C_SFP: 3518 + case ICE_DEV_ID_E823C_SGMII: 3519 + t = ice_cgu_get_pin_desc_e823(hw, input, size); 3520 + break; 3521 + default: 3522 + break; 3523 + } 3524 + 3525 + return t; 3526 + } 3527 + 3528 + /** 3529 + * ice_cgu_get_pin_type - get pin's type 3530 + * @hw: pointer to the hw struct 3531 + * @pin: pin index 3532 + * @input: if request is done against input or output pin 3533 + * 3534 + * Return: type of a pin. 3535 + */ 3536 + enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input) 3537 + { 3538 + const struct ice_cgu_pin_desc *t; 3539 + int t_size; 3540 + 3541 + t = ice_cgu_get_pin_desc(hw, input, &t_size); 3542 + 3543 + if (!t) 3544 + return 0; 3545 + 3546 + if (pin >= t_size) 3547 + return 0; 3548 + 3549 + return t[pin].type; 3550 + } 3551 + 3552 + /** 3553 + * ice_cgu_get_pin_freq_supp - get pin's supported frequency 3554 + * @hw: pointer to the hw struct 3555 + * @pin: pin index 3556 + * @input: if request is done against input or output pin 3557 + * @num: output number of supported frequencies 3558 + * 3559 + * Get frequency supported number and array of supported frequencies. 3560 + * 3561 + * Return: array of supported frequencies for given pin. 3562 + */ 3563 + struct dpll_pin_frequency * 3564 + ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num) 3565 + { 3566 + const struct ice_cgu_pin_desc *t; 3567 + int t_size; 3568 + 3569 + *num = 0; 3570 + t = ice_cgu_get_pin_desc(hw, input, &t_size); 3571 + if (!t) 3572 + return NULL; 3573 + if (pin >= t_size) 3574 + return NULL; 3575 + *num = t[pin].freq_supp_num; 3576 + 3577 + return t[pin].freq_supp; 3578 + } 3579 + 3580 + /** 3581 + * ice_cgu_get_pin_name - get pin's name 3582 + * @hw: pointer to the hw struct 3583 + * @pin: pin index 3584 + * @input: if request is done against input or output pin 3585 + * 3586 + * Return: 3587 + * * null terminated char array with name 3588 + * * NULL in case of failure 3589 + */ 3590 + const char *ice_cgu_get_pin_name(struct ice_hw *hw, u8 pin, bool input) 3591 + { 3592 + const struct ice_cgu_pin_desc *t; 3593 + int t_size; 3594 + 3595 + t = ice_cgu_get_pin_desc(hw, input, &t_size); 3596 + 3597 + if (!t) 3598 + return NULL; 3599 + 3600 + if (pin >= t_size) 3601 + return NULL; 3602 + 3603 + return t[pin].name; 3604 + } 3605 + 3606 + /** 3607 + * ice_get_cgu_state - get the state of the DPLL 3608 + * @hw: pointer to the hw struct 3609 + * @dpll_idx: Index of internal DPLL unit 3610 + * @last_dpll_state: last known state of DPLL 3611 + * @pin: pointer to a buffer for returning currently active pin 3612 + * @ref_state: reference clock state 3613 + * @eec_mode: eec mode of the DPLL 3614 + * @phase_offset: pointer to a buffer for returning phase offset 3615 + * @dpll_state: state of the DPLL (output) 3616 + * 3617 + * This function will read the state of the DPLL(dpll_idx). Non-null 3618 + * 'pin', 'ref_state', 'eec_mode' and 'phase_offset' parameters are used to 3619 + * retrieve currently active pin, state, mode and phase_offset respectively. 3620 + * 3621 + * Return: state of the DPLL 3622 + */ 3623 + int ice_get_cgu_state(struct ice_hw *hw, u8 dpll_idx, 3624 + enum dpll_lock_status last_dpll_state, u8 *pin, 3625 + u8 *ref_state, u8 *eec_mode, s64 *phase_offset, 3626 + enum dpll_lock_status *dpll_state) 3627 + { 3628 + u8 hw_ref_state, hw_dpll_state, hw_eec_mode, hw_config; 3629 + s64 hw_phase_offset; 3630 + int status; 3631 + 3632 + status = ice_aq_get_cgu_dpll_status(hw, dpll_idx, &hw_ref_state, 3633 + &hw_dpll_state, &hw_config, 3634 + &hw_phase_offset, &hw_eec_mode); 3635 + if (status) 3636 + return status; 3637 + 3638 + if (pin) 3639 + /* current ref pin in dpll_state_refsel_status_X register */ 3640 + *pin = hw_config & ICE_AQC_GET_CGU_DPLL_CONFIG_CLK_REF_SEL; 3641 + if (phase_offset) 3642 + *phase_offset = hw_phase_offset; 3643 + if (ref_state) 3644 + *ref_state = hw_ref_state; 3645 + if (eec_mode) 3646 + *eec_mode = hw_eec_mode; 3647 + if (!dpll_state) 3648 + return 0; 3649 + 3650 + /* According to ZL DPLL documentation, once state reach LOCKED_HO_ACQ 3651 + * it would never return to FREERUN. This aligns to ITU-T G.781 3652 + * Recommendation. We cannot report HOLDOVER as HO memory is cleared 3653 + * while switching to another reference. 3654 + * Only for situations where previous state was either: "LOCKED without 3655 + * HO_ACQ" or "HOLDOVER" we actually back to FREERUN. 3656 + */ 3657 + if (hw_dpll_state & ICE_AQC_GET_CGU_DPLL_STATUS_STATE_LOCK) { 3658 + if (hw_dpll_state & ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO_READY) 3659 + *dpll_state = DPLL_LOCK_STATUS_LOCKED_HO_ACQ; 3660 + else 3661 + *dpll_state = DPLL_LOCK_STATUS_LOCKED; 3662 + } else if (last_dpll_state == DPLL_LOCK_STATUS_LOCKED_HO_ACQ || 3663 + last_dpll_state == DPLL_LOCK_STATUS_HOLDOVER) { 3664 + *dpll_state = DPLL_LOCK_STATUS_HOLDOVER; 3665 + } else { 3666 + *dpll_state = DPLL_LOCK_STATUS_UNLOCKED; 3667 + } 3668 + 3669 + return 0; 3670 + } 3671 + 3672 + /** 3673 + * ice_get_cgu_rclk_pin_info - get info on available recovered clock pins 3674 + * @hw: pointer to the hw struct 3675 + * @base_idx: returns index of first recovered clock pin on device 3676 + * @pin_num: returns number of recovered clock pins available on device 3677 + * 3678 + * Based on hw provide caller info about recovery clock pins available on the 3679 + * board. 3680 + * 3681 + * Return: 3682 + * * 0 - success, information is valid 3683 + * * negative - failure, information is not valid 3684 + */ 3685 + int ice_get_cgu_rclk_pin_info(struct ice_hw *hw, u8 *base_idx, u8 *pin_num) 3686 + { 3687 + u8 phy_idx; 3688 + int ret; 3689 + 3690 + switch (hw->device_id) { 3691 + case ICE_DEV_ID_E810C_SFP: 3692 + case ICE_DEV_ID_E810C_QSFP: 3693 + 3694 + ret = ice_get_pf_c827_idx(hw, &phy_idx); 3695 + if (ret) 3696 + return ret; 3697 + *base_idx = E810T_CGU_INPUT_C827(phy_idx, ICE_RCLKA_PIN); 3698 + *pin_num = ICE_E810_RCLK_PINS_NUM; 3699 + ret = 0; 3700 + break; 3701 + case ICE_DEV_ID_E823L_10G_BASE_T: 3702 + case ICE_DEV_ID_E823L_1GBE: 3703 + case ICE_DEV_ID_E823L_BACKPLANE: 3704 + case ICE_DEV_ID_E823L_QSFP: 3705 + case ICE_DEV_ID_E823L_SFP: 3706 + case ICE_DEV_ID_E823C_10G_BASE_T: 3707 + case ICE_DEV_ID_E823C_BACKPLANE: 3708 + case ICE_DEV_ID_E823C_QSFP: 3709 + case ICE_DEV_ID_E823C_SFP: 3710 + case ICE_DEV_ID_E823C_SGMII: 3711 + *pin_num = ICE_E822_RCLK_PINS_NUM; 3712 + ret = 0; 3713 + if (hw->cgu_part_number == 3714 + ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032) 3715 + *base_idx = ZL_REF1P; 3716 + else if (hw->cgu_part_number == 3717 + ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384) 3718 + *base_idx = SI_REF1P; 3719 + else 3720 + ret = -ENODEV; 3721 + 3722 + break; 3723 + default: 3724 + ret = -ENODEV; 3725 + break; 3726 + } 3727 + 3728 + return ret; 3619 3729 }
+86
drivers/net/ethernet/intel/ice/ice_ptp_hw.h
··· 3 3 4 4 #ifndef _ICE_PTP_HW_H_ 5 5 #define _ICE_PTP_HW_H_ 6 + #include <linux/dpll.h> 6 7 7 8 enum ice_ptp_tmr_cmd { 8 9 INIT_TIME, ··· 111 110 u32 post_pll_div; 112 111 }; 113 112 113 + #define E810C_QSFP_C827_0_HANDLE 2 114 + #define E810C_QSFP_C827_1_HANDLE 3 115 + enum ice_e810_c827_idx { 116 + C827_0, 117 + C827_1 118 + }; 119 + 120 + enum ice_phy_rclk_pins { 121 + ICE_RCLKA_PIN = 0, /* SCL pin */ 122 + ICE_RCLKB_PIN, /* SDA pin */ 123 + }; 124 + 125 + #define ICE_E810_RCLK_PINS_NUM (ICE_RCLKB_PIN + 1) 126 + #define ICE_E822_RCLK_PINS_NUM (ICE_RCLKA_PIN + 1) 127 + #define E810T_CGU_INPUT_C827(_phy, _pin) ((_phy) * ICE_E810_RCLK_PINS_NUM + \ 128 + (_pin) + ZL_REF1P) 129 + 130 + enum ice_zl_cgu_in_pins { 131 + ZL_REF0P = 0, 132 + ZL_REF0N, 133 + ZL_REF1P, 134 + ZL_REF1N, 135 + ZL_REF2P, 136 + ZL_REF2N, 137 + ZL_REF3P, 138 + ZL_REF3N, 139 + ZL_REF4P, 140 + ZL_REF4N, 141 + NUM_ZL_CGU_INPUT_PINS 142 + }; 143 + 144 + enum ice_zl_cgu_out_pins { 145 + ZL_OUT0 = 0, 146 + ZL_OUT1, 147 + ZL_OUT2, 148 + ZL_OUT3, 149 + ZL_OUT4, 150 + ZL_OUT5, 151 + ZL_OUT6, 152 + NUM_ZL_CGU_OUTPUT_PINS 153 + }; 154 + 155 + enum ice_si_cgu_in_pins { 156 + SI_REF0P = 0, 157 + SI_REF0N, 158 + SI_REF1P, 159 + SI_REF1N, 160 + SI_REF2P, 161 + SI_REF2N, 162 + SI_REF3, 163 + SI_REF4, 164 + NUM_SI_CGU_INPUT_PINS 165 + }; 166 + 167 + enum ice_si_cgu_out_pins { 168 + SI_OUT0 = 0, 169 + SI_OUT1, 170 + SI_OUT2, 171 + SI_OUT3, 172 + SI_OUT4, 173 + NUM_SI_CGU_OUTPUT_PINS 174 + }; 175 + 176 + struct ice_cgu_pin_desc { 177 + char *name; 178 + u8 index; 179 + enum dpll_pin_type type; 180 + u32 freq_supp_num; 181 + struct dpll_pin_frequency *freq_supp; 182 + }; 183 + 114 184 extern const struct 115 185 ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ]; 116 186 ··· 269 197 int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data); 270 198 int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data); 271 199 int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data); 200 + bool ice_is_pca9575_present(struct ice_hw *hw); 201 + bool ice_is_phy_rclk_present(struct ice_hw *hw); 202 + bool ice_is_clock_mux_present_e810t(struct ice_hw *hw); 203 + int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx); 204 + bool ice_is_cgu_present(struct ice_hw *hw); 205 + enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input); 206 + struct dpll_pin_frequency * 207 + ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num); 208 + const char *ice_cgu_get_pin_name(struct ice_hw *hw, u8 pin, bool input); 209 + int ice_get_cgu_state(struct ice_hw *hw, u8 dpll_idx, 210 + enum dpll_lock_status last_dpll_state, u8 *pin, 211 + u8 *ref_state, u8 *eec_mode, s64 *phase_offset, 212 + enum dpll_lock_status *dpll_state); 213 + int ice_get_cgu_rclk_pin_info(struct ice_hw *hw, u8 *base_idx, u8 *pin_num); 272 214 273 215 #define PFTSYN_SEM_BYTES 4 274 216
+1
drivers/net/ethernet/intel/ice/ice_type.h
··· 965 965 DECLARE_BITMAP(hw_ptype, ICE_FLOW_PTYPE_MAX); 966 966 u8 dvm_ena; 967 967 u16 io_expander_handle; 968 + u8 cgu_part_number; 968 969 }; 969 970 970 971 /* Statistics collected by each port, VSI, VEB, and S-channel */
+8
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
··· 189 189 port is managed through devlink. A subfunction supports RDMA, netdevice 190 190 and vdpa device. It is similar to a SRIOV VF but it doesn't require 191 191 SRIOV support. 192 + 193 + config MLX5_DPLL 194 + tristate "Mellanox 5th generation network adapters (ConnectX series) DPLL support" 195 + depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE 196 + select DPLL 197 + help 198 + DPLL support in Mellanox Technologies ConnectX NICs. 199 +
+3
drivers/net/ethernet/mellanox/mlx5/core/Makefile
··· 128 128 # SF manager 129 129 # 130 130 mlx5_core-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o 131 + 132 + obj-$(CONFIG_MLX5_DPLL) += mlx5_dpll.o 133 + mlx5_dpll-y := dpll.o
+17
drivers/net/ethernet/mellanox/mlx5/core/dev.c
··· 206 206 return err ? false : val.vbool; 207 207 } 208 208 209 + static bool is_dpll_supported(struct mlx5_core_dev *dev) 210 + { 211 + if (!IS_ENABLED(CONFIG_MLX5_DPLL)) 212 + return false; 213 + 214 + if (!MLX5_CAP_MCAM_REG2(dev, synce_registers)) { 215 + mlx5_core_warn(dev, "Missing SyncE capability\n"); 216 + return false; 217 + } 218 + 219 + return true; 220 + } 221 + 209 222 enum { 210 223 MLX5_INTERFACE_PROTOCOL_ETH, 211 224 MLX5_INTERFACE_PROTOCOL_ETH_REP, ··· 228 215 MLX5_INTERFACE_PROTOCOL_MPIB, 229 216 230 217 MLX5_INTERFACE_PROTOCOL_VNET, 218 + 219 + MLX5_INTERFACE_PROTOCOL_DPLL, 231 220 }; 232 221 233 222 static const struct mlx5_adev_device { ··· 252 237 .is_supported = &is_ib_rep_supported }, 253 238 [MLX5_INTERFACE_PROTOCOL_MPIB] = { .suffix = "multiport", 254 239 .is_supported = &is_mp_supported }, 240 + [MLX5_INTERFACE_PROTOCOL_DPLL] = { .suffix = "dpll", 241 + .is_supported = &is_dpll_supported }, 255 242 }; 256 243 257 244 int mlx5_adev_idx_alloc(void)
+432
drivers/net/ethernet/mellanox/mlx5/core/dpll.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ 3 + 4 + #include <linux/dpll.h> 5 + #include <linux/mlx5/driver.h> 6 + 7 + /* This structure represents a reference to DPLL, one is created 8 + * per mdev instance. 9 + */ 10 + struct mlx5_dpll { 11 + struct dpll_device *dpll; 12 + struct dpll_pin *dpll_pin; 13 + struct mlx5_core_dev *mdev; 14 + struct workqueue_struct *wq; 15 + struct delayed_work work; 16 + struct { 17 + bool valid; 18 + enum dpll_lock_status lock_status; 19 + enum dpll_pin_state pin_state; 20 + } last; 21 + struct notifier_block mdev_nb; 22 + struct net_device *tracking_netdev; 23 + }; 24 + 25 + static int mlx5_dpll_clock_id_get(struct mlx5_core_dev *mdev, u64 *clock_id) 26 + { 27 + u32 out[MLX5_ST_SZ_DW(msecq_reg)] = {}; 28 + u32 in[MLX5_ST_SZ_DW(msecq_reg)] = {}; 29 + int err; 30 + 31 + err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), 32 + MLX5_REG_MSECQ, 0, 0); 33 + if (err) 34 + return err; 35 + *clock_id = MLX5_GET64(msecq_reg, out, local_clock_identity); 36 + return 0; 37 + } 38 + 39 + static int 40 + mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev, 41 + enum mlx5_msees_admin_status *admin_status, 42 + enum mlx5_msees_oper_status *oper_status, 43 + bool *ho_acq) 44 + { 45 + u32 out[MLX5_ST_SZ_DW(msees_reg)] = {}; 46 + u32 in[MLX5_ST_SZ_DW(msees_reg)] = {}; 47 + int err; 48 + 49 + err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), 50 + MLX5_REG_MSEES, 0, 0); 51 + if (err) 52 + return err; 53 + if (admin_status) 54 + *admin_status = MLX5_GET(msees_reg, out, admin_status); 55 + *oper_status = MLX5_GET(msees_reg, out, oper_status); 56 + if (ho_acq) 57 + *ho_acq = MLX5_GET(msees_reg, out, ho_acq); 58 + return 0; 59 + } 60 + 61 + static int 62 + mlx5_dpll_synce_status_set(struct mlx5_core_dev *mdev, 63 + enum mlx5_msees_admin_status admin_status) 64 + { 65 + u32 out[MLX5_ST_SZ_DW(msees_reg)] = {}; 66 + u32 in[MLX5_ST_SZ_DW(msees_reg)] = {}; 67 + 68 + MLX5_SET(msees_reg, in, field_select, 69 + MLX5_MSEES_FIELD_SELECT_ENABLE | 70 + MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS); 71 + MLX5_SET(msees_reg, in, admin_status, admin_status); 72 + return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), 73 + MLX5_REG_MSEES, 0, 1); 74 + } 75 + 76 + static enum dpll_lock_status 77 + mlx5_dpll_lock_status_get(enum mlx5_msees_oper_status oper_status, bool ho_acq) 78 + { 79 + switch (oper_status) { 80 + case MLX5_MSEES_OPER_STATUS_SELF_TRACK: 81 + fallthrough; 82 + case MLX5_MSEES_OPER_STATUS_OTHER_TRACK: 83 + return ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ : 84 + DPLL_LOCK_STATUS_LOCKED; 85 + case MLX5_MSEES_OPER_STATUS_HOLDOVER: 86 + fallthrough; 87 + case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER: 88 + return DPLL_LOCK_STATUS_HOLDOVER; 89 + default: 90 + return DPLL_LOCK_STATUS_UNLOCKED; 91 + } 92 + } 93 + 94 + static enum dpll_pin_state 95 + mlx5_dpll_pin_state_get(enum mlx5_msees_admin_status admin_status, 96 + enum mlx5_msees_oper_status oper_status) 97 + { 98 + return (admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK && 99 + (oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK || 100 + oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ? 101 + DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_DISCONNECTED; 102 + } 103 + 104 + static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, 105 + void *priv, 106 + enum dpll_lock_status *status, 107 + struct netlink_ext_ack *extack) 108 + { 109 + enum mlx5_msees_oper_status oper_status; 110 + struct mlx5_dpll *mdpll = priv; 111 + bool ho_acq; 112 + int err; 113 + 114 + err = mlx5_dpll_synce_status_get(mdpll->mdev, NULL, 115 + &oper_status, &ho_acq); 116 + if (err) 117 + return err; 118 + 119 + *status = mlx5_dpll_lock_status_get(oper_status, ho_acq); 120 + return 0; 121 + } 122 + 123 + static int mlx5_dpll_device_mode_get(const struct dpll_device *dpll, 124 + void *priv, 125 + u32 *mode, struct netlink_ext_ack *extack) 126 + { 127 + *mode = DPLL_MODE_MANUAL; 128 + return 0; 129 + } 130 + 131 + static bool mlx5_dpll_device_mode_supported(const struct dpll_device *dpll, 132 + void *priv, 133 + enum dpll_mode mode, 134 + struct netlink_ext_ack *extack) 135 + { 136 + return mode == DPLL_MODE_MANUAL; 137 + } 138 + 139 + static const struct dpll_device_ops mlx5_dpll_device_ops = { 140 + .lock_status_get = mlx5_dpll_device_lock_status_get, 141 + .mode_get = mlx5_dpll_device_mode_get, 142 + .mode_supported = mlx5_dpll_device_mode_supported, 143 + }; 144 + 145 + static int mlx5_dpll_pin_direction_get(const struct dpll_pin *pin, 146 + void *pin_priv, 147 + const struct dpll_device *dpll, 148 + void *dpll_priv, 149 + enum dpll_pin_direction *direction, 150 + struct netlink_ext_ack *extack) 151 + { 152 + *direction = DPLL_PIN_DIRECTION_INPUT; 153 + return 0; 154 + } 155 + 156 + static int mlx5_dpll_state_on_dpll_get(const struct dpll_pin *pin, 157 + void *pin_priv, 158 + const struct dpll_device *dpll, 159 + void *dpll_priv, 160 + enum dpll_pin_state *state, 161 + struct netlink_ext_ack *extack) 162 + { 163 + enum mlx5_msees_admin_status admin_status; 164 + enum mlx5_msees_oper_status oper_status; 165 + struct mlx5_dpll *mdpll = pin_priv; 166 + int err; 167 + 168 + err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status, 169 + &oper_status, NULL); 170 + if (err) 171 + return err; 172 + *state = mlx5_dpll_pin_state_get(admin_status, oper_status); 173 + return 0; 174 + } 175 + 176 + static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin, 177 + void *pin_priv, 178 + const struct dpll_device *dpll, 179 + void *dpll_priv, 180 + enum dpll_pin_state state, 181 + struct netlink_ext_ack *extack) 182 + { 183 + struct mlx5_dpll *mdpll = pin_priv; 184 + 185 + return mlx5_dpll_synce_status_set(mdpll->mdev, 186 + state == DPLL_PIN_STATE_CONNECTED ? 187 + MLX5_MSEES_ADMIN_STATUS_TRACK : 188 + MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING); 189 + } 190 + 191 + static const struct dpll_pin_ops mlx5_dpll_pins_ops = { 192 + .direction_get = mlx5_dpll_pin_direction_get, 193 + .state_on_dpll_get = mlx5_dpll_state_on_dpll_get, 194 + .state_on_dpll_set = mlx5_dpll_state_on_dpll_set, 195 + }; 196 + 197 + static const struct dpll_pin_properties mlx5_dpll_pin_properties = { 198 + .type = DPLL_PIN_TYPE_SYNCE_ETH_PORT, 199 + .capabilities = DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE, 200 + }; 201 + 202 + #define MLX5_DPLL_PERIODIC_WORK_INTERVAL 500 /* ms */ 203 + 204 + static void mlx5_dpll_periodic_work_queue(struct mlx5_dpll *mdpll) 205 + { 206 + queue_delayed_work(mdpll->wq, &mdpll->work, 207 + msecs_to_jiffies(MLX5_DPLL_PERIODIC_WORK_INTERVAL)); 208 + } 209 + 210 + static void mlx5_dpll_periodic_work(struct work_struct *work) 211 + { 212 + struct mlx5_dpll *mdpll = container_of(work, struct mlx5_dpll, 213 + work.work); 214 + enum mlx5_msees_admin_status admin_status; 215 + enum mlx5_msees_oper_status oper_status; 216 + enum dpll_lock_status lock_status; 217 + enum dpll_pin_state pin_state; 218 + bool ho_acq; 219 + int err; 220 + 221 + err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status, 222 + &oper_status, &ho_acq); 223 + if (err) 224 + goto err_out; 225 + lock_status = mlx5_dpll_lock_status_get(oper_status, ho_acq); 226 + pin_state = mlx5_dpll_pin_state_get(admin_status, oper_status); 227 + 228 + if (!mdpll->last.valid) 229 + goto invalid_out; 230 + 231 + if (mdpll->last.lock_status != lock_status) 232 + dpll_device_change_ntf(mdpll->dpll); 233 + if (mdpll->last.pin_state != pin_state) 234 + dpll_pin_change_ntf(mdpll->dpll_pin); 235 + 236 + invalid_out: 237 + mdpll->last.lock_status = lock_status; 238 + mdpll->last.pin_state = pin_state; 239 + mdpll->last.valid = true; 240 + err_out: 241 + mlx5_dpll_periodic_work_queue(mdpll); 242 + } 243 + 244 + static void mlx5_dpll_netdev_dpll_pin_set(struct mlx5_dpll *mdpll, 245 + struct net_device *netdev) 246 + { 247 + if (mdpll->tracking_netdev) 248 + return; 249 + netdev_dpll_pin_set(netdev, mdpll->dpll_pin); 250 + mdpll->tracking_netdev = netdev; 251 + } 252 + 253 + static void mlx5_dpll_netdev_dpll_pin_clear(struct mlx5_dpll *mdpll) 254 + { 255 + if (!mdpll->tracking_netdev) 256 + return; 257 + netdev_dpll_pin_clear(mdpll->tracking_netdev); 258 + mdpll->tracking_netdev = NULL; 259 + } 260 + 261 + static int mlx5_dpll_mdev_notifier_event(struct notifier_block *nb, 262 + unsigned long event, void *data) 263 + { 264 + struct mlx5_dpll *mdpll = container_of(nb, struct mlx5_dpll, mdev_nb); 265 + struct net_device *netdev = data; 266 + 267 + switch (event) { 268 + case MLX5_DRIVER_EVENT_UPLINK_NETDEV: 269 + if (netdev) 270 + mlx5_dpll_netdev_dpll_pin_set(mdpll, netdev); 271 + else 272 + mlx5_dpll_netdev_dpll_pin_clear(mdpll); 273 + break; 274 + default: 275 + return NOTIFY_DONE; 276 + } 277 + 278 + return NOTIFY_OK; 279 + } 280 + 281 + static void mlx5_dpll_mdev_netdev_track(struct mlx5_dpll *mdpll, 282 + struct mlx5_core_dev *mdev) 283 + { 284 + mdpll->mdev_nb.notifier_call = mlx5_dpll_mdev_notifier_event; 285 + mlx5_blocking_notifier_register(mdev, &mdpll->mdev_nb); 286 + mlx5_core_uplink_netdev_event_replay(mdev); 287 + } 288 + 289 + static void mlx5_dpll_mdev_netdev_untrack(struct mlx5_dpll *mdpll, 290 + struct mlx5_core_dev *mdev) 291 + { 292 + mlx5_blocking_notifier_unregister(mdev, &mdpll->mdev_nb); 293 + mlx5_dpll_netdev_dpll_pin_clear(mdpll); 294 + } 295 + 296 + static int mlx5_dpll_probe(struct auxiliary_device *adev, 297 + const struct auxiliary_device_id *id) 298 + { 299 + struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev); 300 + struct mlx5_core_dev *mdev = edev->mdev; 301 + struct mlx5_dpll *mdpll; 302 + u64 clock_id; 303 + int err; 304 + 305 + err = mlx5_dpll_synce_status_set(mdev, 306 + MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING); 307 + if (err) 308 + return err; 309 + 310 + err = mlx5_dpll_clock_id_get(mdev, &clock_id); 311 + if (err) 312 + return err; 313 + 314 + mdpll = kzalloc(sizeof(*mdpll), GFP_KERNEL); 315 + if (!mdpll) 316 + return -ENOMEM; 317 + mdpll->mdev = mdev; 318 + auxiliary_set_drvdata(adev, mdpll); 319 + 320 + /* Multiple mdev instances might share one DPLL device. */ 321 + mdpll->dpll = dpll_device_get(clock_id, 0, THIS_MODULE); 322 + if (IS_ERR(mdpll->dpll)) { 323 + err = PTR_ERR(mdpll->dpll); 324 + goto err_free_mdpll; 325 + } 326 + 327 + err = dpll_device_register(mdpll->dpll, DPLL_TYPE_EEC, 328 + &mlx5_dpll_device_ops, mdpll); 329 + if (err) 330 + goto err_put_dpll_device; 331 + 332 + /* Multiple mdev instances might share one DPLL pin. */ 333 + mdpll->dpll_pin = dpll_pin_get(clock_id, mlx5_get_dev_index(mdev), 334 + THIS_MODULE, &mlx5_dpll_pin_properties); 335 + if (IS_ERR(mdpll->dpll_pin)) { 336 + err = PTR_ERR(mdpll->dpll_pin); 337 + goto err_unregister_dpll_device; 338 + } 339 + 340 + err = dpll_pin_register(mdpll->dpll, mdpll->dpll_pin, 341 + &mlx5_dpll_pins_ops, mdpll); 342 + if (err) 343 + goto err_put_dpll_pin; 344 + 345 + mdpll->wq = create_singlethread_workqueue("mlx5_dpll"); 346 + if (!mdpll->wq) { 347 + err = -ENOMEM; 348 + goto err_unregister_dpll_pin; 349 + } 350 + 351 + mlx5_dpll_mdev_netdev_track(mdpll, mdev); 352 + 353 + INIT_DELAYED_WORK(&mdpll->work, &mlx5_dpll_periodic_work); 354 + mlx5_dpll_periodic_work_queue(mdpll); 355 + 356 + return 0; 357 + 358 + err_unregister_dpll_pin: 359 + dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin, 360 + &mlx5_dpll_pins_ops, mdpll); 361 + err_put_dpll_pin: 362 + dpll_pin_put(mdpll->dpll_pin); 363 + err_unregister_dpll_device: 364 + dpll_device_unregister(mdpll->dpll, &mlx5_dpll_device_ops, mdpll); 365 + err_put_dpll_device: 366 + dpll_device_put(mdpll->dpll); 367 + err_free_mdpll: 368 + kfree(mdpll); 369 + return err; 370 + } 371 + 372 + static void mlx5_dpll_remove(struct auxiliary_device *adev) 373 + { 374 + struct mlx5_dpll *mdpll = auxiliary_get_drvdata(adev); 375 + struct mlx5_core_dev *mdev = mdpll->mdev; 376 + 377 + cancel_delayed_work(&mdpll->work); 378 + mlx5_dpll_mdev_netdev_untrack(mdpll, mdev); 379 + destroy_workqueue(mdpll->wq); 380 + dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin, 381 + &mlx5_dpll_pins_ops, mdpll); 382 + dpll_pin_put(mdpll->dpll_pin); 383 + dpll_device_unregister(mdpll->dpll, &mlx5_dpll_device_ops, mdpll); 384 + dpll_device_put(mdpll->dpll); 385 + kfree(mdpll); 386 + 387 + mlx5_dpll_synce_status_set(mdev, 388 + MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING); 389 + } 390 + 391 + static int mlx5_dpll_suspend(struct auxiliary_device *adev, pm_message_t state) 392 + { 393 + return 0; 394 + } 395 + 396 + static int mlx5_dpll_resume(struct auxiliary_device *adev) 397 + { 398 + return 0; 399 + } 400 + 401 + static const struct auxiliary_device_id mlx5_dpll_id_table[] = { 402 + { .name = MLX5_ADEV_NAME ".dpll", }, 403 + {}, 404 + }; 405 + 406 + MODULE_DEVICE_TABLE(auxiliary, mlx5_dpll_id_table); 407 + 408 + static struct auxiliary_driver mlx5_dpll_driver = { 409 + .name = "dpll", 410 + .probe = mlx5_dpll_probe, 411 + .remove = mlx5_dpll_remove, 412 + .suspend = mlx5_dpll_suspend, 413 + .resume = mlx5_dpll_resume, 414 + .id_table = mlx5_dpll_id_table, 415 + }; 416 + 417 + static int __init mlx5_dpll_init(void) 418 + { 419 + return auxiliary_driver_register(&mlx5_dpll_driver); 420 + } 421 + 422 + static void __exit mlx5_dpll_exit(void) 423 + { 424 + auxiliary_driver_unregister(&mlx5_dpll_driver); 425 + } 426 + 427 + module_init(mlx5_dpll_init); 428 + module_exit(mlx5_dpll_exit); 429 + 430 + MODULE_AUTHOR("Jiri Pirko <jiri@nvidia.com>"); 431 + MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) DPLL driver"); 432 + MODULE_LICENSE("Dual BSD/GPL");
+1
drivers/ptp/Kconfig
··· 188 188 depends on COMMON_CLK 189 189 select NET_DEVLINK 190 190 select CRC16 191 + select DPLL 191 192 help 192 193 This driver adds support for an OpenCompute time card. 193 194
+309 -60
drivers/ptp/ptp_ocp.c
··· 23 23 #include <linux/mtd/mtd.h> 24 24 #include <linux/nvmem-consumer.h> 25 25 #include <linux/crc16.h> 26 + #include <linux/dpll.h> 26 27 27 28 #define PCI_VENDOR_ID_FACEBOOK 0x1d9b 28 29 #define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400 ··· 261 260 SMA_MODE_OUT, 262 261 }; 263 262 263 + static struct dpll_pin_frequency ptp_ocp_sma_freq[] = { 264 + DPLL_PIN_FREQUENCY_1PPS, 265 + DPLL_PIN_FREQUENCY_10MHZ, 266 + DPLL_PIN_FREQUENCY_IRIG_B, 267 + DPLL_PIN_FREQUENCY_DCF77, 268 + }; 269 + 264 270 struct ptp_ocp_sma_connector { 265 271 enum ptp_ocp_sma_mode mode; 266 272 bool fixed_fcn; 267 273 bool fixed_dir; 268 274 bool disabled; 269 275 u8 default_fcn; 276 + struct dpll_pin *dpll_pin; 277 + struct dpll_pin_properties dpll_prop; 270 278 }; 271 279 272 280 struct ocp_attr_group { ··· 304 294 305 295 #define OCP_BOARD_ID_LEN 13 306 296 #define OCP_SERIAL_LEN 6 297 + #define OCP_SMA_NUM 4 307 298 308 299 struct ptp_ocp { 309 300 struct pci_dev *pdev; ··· 342 331 const struct attribute_group **attr_group; 343 332 const struct ptp_ocp_eeprom_map *eeprom_map; 344 333 struct dentry *debug_root; 334 + bool sync; 345 335 time64_t gnss_lost; 336 + struct delayed_work sync_work; 346 337 int id; 347 338 int n_irqs; 348 339 struct ptp_ocp_serial_port gnss_port; ··· 363 350 u32 ts_window_adjust; 364 351 u64 fw_cap; 365 352 struct ptp_ocp_signal signal[4]; 366 - struct ptp_ocp_sma_connector sma[4]; 353 + struct ptp_ocp_sma_connector sma[OCP_SMA_NUM]; 367 354 const struct ocp_sma_op *sma_op; 355 + struct dpll_device *dpll; 368 356 }; 369 357 370 358 #define OCP_REQ_TIMESTAMP BIT(0) ··· 849 835 struct ocp_selector { 850 836 const char *name; 851 837 int value; 838 + u64 frequency; 852 839 }; 853 840 854 841 static const struct ocp_selector ptp_ocp_clock[] = { ··· 870 855 #define SMA_SELECT_MASK GENMASK(14, 0) 871 856 872 857 static const struct ocp_selector ptp_ocp_sma_in[] = { 873 - { .name = "10Mhz", .value = 0x0000 }, 874 - { .name = "PPS1", .value = 0x0001 }, 875 - { .name = "PPS2", .value = 0x0002 }, 876 - { .name = "TS1", .value = 0x0004 }, 877 - { .name = "TS2", .value = 0x0008 }, 878 - { .name = "IRIG", .value = 0x0010 }, 879 - { .name = "DCF", .value = 0x0020 }, 880 - { .name = "TS3", .value = 0x0040 }, 881 - { .name = "TS4", .value = 0x0080 }, 882 - { .name = "FREQ1", .value = 0x0100 }, 883 - { .name = "FREQ2", .value = 0x0200 }, 884 - { .name = "FREQ3", .value = 0x0400 }, 885 - { .name = "FREQ4", .value = 0x0800 }, 886 - { .name = "None", .value = SMA_DISABLE }, 858 + { .name = "10Mhz", .value = 0x0000, .frequency = 10000000 }, 859 + { .name = "PPS1", .value = 0x0001, .frequency = 1 }, 860 + { .name = "PPS2", .value = 0x0002, .frequency = 1 }, 861 + { .name = "TS1", .value = 0x0004, .frequency = 0 }, 862 + { .name = "TS2", .value = 0x0008, .frequency = 0 }, 863 + { .name = "IRIG", .value = 0x0010, .frequency = 10000 }, 864 + { .name = "DCF", .value = 0x0020, .frequency = 77500 }, 865 + { .name = "TS3", .value = 0x0040, .frequency = 0 }, 866 + { .name = "TS4", .value = 0x0080, .frequency = 0 }, 867 + { .name = "FREQ1", .value = 0x0100, .frequency = 0 }, 868 + { .name = "FREQ2", .value = 0x0200, .frequency = 0 }, 869 + { .name = "FREQ3", .value = 0x0400, .frequency = 0 }, 870 + { .name = "FREQ4", .value = 0x0800, .frequency = 0 }, 871 + { .name = "None", .value = SMA_DISABLE, .frequency = 0 }, 887 872 { } 888 873 }; 889 874 890 875 static const struct ocp_selector ptp_ocp_sma_out[] = { 891 - { .name = "10Mhz", .value = 0x0000 }, 892 - { .name = "PHC", .value = 0x0001 }, 893 - { .name = "MAC", .value = 0x0002 }, 894 - { .name = "GNSS1", .value = 0x0004 }, 895 - { .name = "GNSS2", .value = 0x0008 }, 896 - { .name = "IRIG", .value = 0x0010 }, 897 - { .name = "DCF", .value = 0x0020 }, 876 + { .name = "10Mhz", .value = 0x0000, .frequency = 10000000 }, 877 + { .name = "PHC", .value = 0x0001, .frequency = 1 }, 878 + { .name = "MAC", .value = 0x0002, .frequency = 1 }, 879 + { .name = "GNSS1", .value = 0x0004, .frequency = 1 }, 880 + { .name = "GNSS2", .value = 0x0008, .frequency = 1 }, 881 + { .name = "IRIG", .value = 0x0010, .frequency = 10000 }, 882 + { .name = "DCF", .value = 0x0020, .frequency = 77000 }, 898 883 { .name = "GEN1", .value = 0x0040 }, 899 884 { .name = "GEN2", .value = 0x0080 }, 900 885 { .name = "GEN3", .value = 0x0100 }, ··· 905 890 }; 906 891 907 892 static const struct ocp_selector ptp_ocp_art_sma_in[] = { 908 - { .name = "PPS1", .value = 0x0001 }, 909 - { .name = "10Mhz", .value = 0x0008 }, 893 + { .name = "PPS1", .value = 0x0001, .frequency = 1 }, 894 + { .name = "10Mhz", .value = 0x0008, .frequency = 1000000 }, 910 895 { } 911 896 }; 912 897 913 898 static const struct ocp_selector ptp_ocp_art_sma_out[] = { 914 - { .name = "PHC", .value = 0x0002 }, 915 - { .name = "GNSS", .value = 0x0004 }, 916 - { .name = "10Mhz", .value = 0x0010 }, 899 + { .name = "PHC", .value = 0x0002, .frequency = 1 }, 900 + { .name = "GNSS", .value = 0x0004, .frequency = 1 }, 901 + { .name = "10Mhz", .value = 0x0010, .frequency = 10000000 }, 917 902 { } 918 903 }; 919 904 ··· 1366 1351 ptp_ocp_init_clock(struct ptp_ocp *bp) 1367 1352 { 1368 1353 struct timespec64 ts; 1369 - bool sync; 1370 1354 u32 ctrl; 1371 1355 1372 1356 ctrl = OCP_CTRL_ENABLE; ··· 1389 1375 1390 1376 ptp_ocp_estimate_pci_timing(bp); 1391 1377 1392 - sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; 1393 - if (!sync) { 1378 + bp->sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; 1379 + if (!bp->sync) { 1394 1380 ktime_get_clocktai_ts64(&ts); 1395 1381 ptp_ocp_settime(&bp->ptp_info, &ts); 1396 1382 } ··· 2303 2289 static void 2304 2290 ptp_ocp_sma_fb_init(struct ptp_ocp *bp) 2305 2291 { 2292 + struct dpll_pin_properties prop = { 2293 + .board_label = NULL, 2294 + .type = DPLL_PIN_TYPE_EXT, 2295 + .capabilities = DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE, 2296 + .freq_supported_num = ARRAY_SIZE(ptp_ocp_sma_freq), 2297 + .freq_supported = ptp_ocp_sma_freq, 2298 + 2299 + }; 2306 2300 u32 reg; 2307 2301 int i; 2308 2302 2309 2303 /* defaults */ 2304 + for (i = 0; i < OCP_SMA_NUM; i++) { 2305 + bp->sma[i].default_fcn = i & 1; 2306 + bp->sma[i].dpll_prop = prop; 2307 + bp->sma[i].dpll_prop.board_label = 2308 + bp->ptp_info.pin_config[i].name; 2309 + } 2310 2310 bp->sma[0].mode = SMA_MODE_IN; 2311 2311 bp->sma[1].mode = SMA_MODE_IN; 2312 2312 bp->sma[2].mode = SMA_MODE_OUT; 2313 2313 bp->sma[3].mode = SMA_MODE_OUT; 2314 - for (i = 0; i < 4; i++) 2315 - bp->sma[i].default_fcn = i & 1; 2316 - 2317 2314 /* If no SMA1 map, the pin functions and directions are fixed. */ 2318 2315 if (!bp->sma_map1) { 2319 - for (i = 0; i < 4; i++) { 2316 + for (i = 0; i < OCP_SMA_NUM; i++) { 2320 2317 bp->sma[i].fixed_fcn = true; 2321 2318 bp->sma[i].fixed_dir = true; 2319 + bp->sma[1].dpll_prop.capabilities &= 2320 + ~DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE; 2322 2321 } 2323 2322 return; 2324 2323 } ··· 2341 2314 */ 2342 2315 reg = ioread32(&bp->sma_map2->gpio2); 2343 2316 if (reg == 0xffffffff) { 2344 - for (i = 0; i < 4; i++) 2317 + for (i = 0; i < OCP_SMA_NUM; i++) 2345 2318 bp->sma[i].fixed_dir = true; 2346 2319 } else { 2347 2320 reg = ioread32(&bp->sma_map1->gpio1); ··· 2363 2336 }; 2364 2337 2365 2338 static int 2366 - ptp_ocp_fb_set_pins(struct ptp_ocp *bp) 2339 + ptp_ocp_set_pins(struct ptp_ocp *bp) 2367 2340 { 2368 2341 struct ptp_pin_desc *config; 2369 2342 int i; ··· 2430 2403 2431 2404 ptp_ocp_tod_init(bp); 2432 2405 ptp_ocp_nmea_out_init(bp); 2433 - ptp_ocp_sma_init(bp); 2434 2406 ptp_ocp_signal_init(bp); 2435 2407 2436 2408 err = ptp_ocp_attr_group_add(bp, fb_timecard_groups); 2437 2409 if (err) 2438 2410 return err; 2439 2411 2440 - err = ptp_ocp_fb_set_pins(bp); 2412 + err = ptp_ocp_set_pins(bp); 2441 2413 if (err) 2442 2414 return err; 2415 + ptp_ocp_sma_init(bp); 2443 2416 2444 2417 return ptp_ocp_init_clock(bp); 2445 2418 } ··· 2479 2452 static void 2480 2453 ptp_ocp_art_sma_init(struct ptp_ocp *bp) 2481 2454 { 2455 + struct dpll_pin_properties prop = { 2456 + .board_label = NULL, 2457 + .type = DPLL_PIN_TYPE_EXT, 2458 + .capabilities = 0, 2459 + .freq_supported_num = ARRAY_SIZE(ptp_ocp_sma_freq), 2460 + .freq_supported = ptp_ocp_sma_freq, 2461 + 2462 + }; 2482 2463 u32 reg; 2483 2464 int i; 2484 2465 ··· 2501 2466 bp->sma[2].default_fcn = 0x10; /* OUT: 10Mhz */ 2502 2467 bp->sma[3].default_fcn = 0x02; /* OUT: PHC */ 2503 2468 2504 - /* If no SMA map, the pin functions and directions are fixed. */ 2505 - if (!bp->art_sma) { 2506 - for (i = 0; i < 4; i++) { 2469 + for (i = 0; i < OCP_SMA_NUM; i++) { 2470 + /* If no SMA map, the pin functions and directions are fixed. */ 2471 + bp->sma[i].dpll_prop = prop; 2472 + bp->sma[i].dpll_prop.board_label = 2473 + bp->ptp_info.pin_config[i].name; 2474 + if (!bp->art_sma) { 2507 2475 bp->sma[i].fixed_fcn = true; 2508 2476 bp->sma[i].fixed_dir = true; 2477 + continue; 2509 2478 } 2510 - return; 2511 - } 2512 - 2513 - for (i = 0; i < 4; i++) { 2514 2479 reg = ioread32(&bp->art_sma->map[i].gpio); 2515 2480 2516 2481 switch (reg & 0xff) { ··· 2521 2486 case 1: 2522 2487 case 8: 2523 2488 bp->sma[i].mode = SMA_MODE_IN; 2489 + bp->sma[i].dpll_prop.capabilities = 2490 + DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE; 2524 2491 break; 2525 2492 default: 2526 2493 bp->sma[i].mode = SMA_MODE_OUT; 2494 + bp->sma[i].dpll_prop.capabilities = 2495 + DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE; 2527 2496 break; 2528 2497 } 2529 2498 } ··· 2594 2555 /* Enable MAC serial port during initialisation */ 2595 2556 iowrite32(1, &bp->board_config->mro50_serial_activate); 2596 2557 2558 + err = ptp_ocp_set_pins(bp); 2559 + if (err) 2560 + return err; 2597 2561 ptp_ocp_sma_init(bp); 2598 2562 2599 2563 err = ptp_ocp_attr_group_add(bp, art_timecard_groups); ··· 2738 2696 } 2739 2697 2740 2698 static int 2741 - ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr) 2699 + ptp_ocp_sma_store_val(struct ptp_ocp *bp, int val, enum ptp_ocp_sma_mode mode, int sma_nr) 2742 2700 { 2743 2701 struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1]; 2744 - enum ptp_ocp_sma_mode mode; 2745 - int val; 2746 - 2747 - mode = sma->mode; 2748 - val = sma_parse_inputs(bp->sma_op->tbl, buf, &mode); 2749 - if (val < 0) 2750 - return val; 2751 2702 2752 2703 if (sma->fixed_dir && (mode != sma->mode || val & SMA_DISABLE)) 2753 2704 return -EOPNOTSUPP; ··· 2773 2738 val = ptp_ocp_sma_set_output(bp, sma_nr, val); 2774 2739 2775 2740 return val; 2741 + } 2742 + 2743 + static int 2744 + ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr) 2745 + { 2746 + struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1]; 2747 + enum ptp_ocp_sma_mode mode; 2748 + int val; 2749 + 2750 + mode = sma->mode; 2751 + val = sma_parse_inputs(bp->sma_op->tbl, buf, &mode); 2752 + if (val < 0) 2753 + return val; 2754 + return ptp_ocp_sma_store_val(bp, val, mode, sma_nr); 2776 2755 } 2777 2756 2778 2757 static ssize_t ··· 3883 3834 strcpy(buf, "unknown"); 3884 3835 break; 3885 3836 } 3886 - val = ioread32(&bp->reg->status); 3887 3837 seq_printf(s, "%7s: %s, state: %s\n", "PHC src", buf, 3888 - val & OCP_STATUS_IN_SYNC ? "sync" : "unsynced"); 3838 + bp->sync ? "sync" : "unsynced"); 3889 3839 3890 3840 if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts)) { 3891 3841 struct timespec64 sys_ts; ··· 4116 4068 { 4117 4069 struct timespec64 ts; 4118 4070 u32 version, select; 4119 - bool sync; 4120 4071 4121 4072 version = ioread32(&bp->reg->version); 4122 4073 select = ioread32(&bp->reg->select); ··· 4124 4077 ptp_ocp_select_name_from_val(ptp_ocp_clock, select >> 16), 4125 4078 ptp_clock_index(bp->ptp)); 4126 4079 4127 - sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; 4128 4080 if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL)) 4129 4081 dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n", 4130 4082 ts.tv_sec, ts.tv_nsec, 4131 - sync ? "in-sync" : "UNSYNCED"); 4083 + bp->sync ? "in-sync" : "UNSYNCED"); 4132 4084 } 4133 4085 4134 4086 static void ··· 4224 4178 device_unregister(&bp->dev); 4225 4179 } 4226 4180 4181 + static int ptp_ocp_dpll_lock_status_get(const struct dpll_device *dpll, 4182 + void *priv, 4183 + enum dpll_lock_status *status, 4184 + struct netlink_ext_ack *extack) 4185 + { 4186 + struct ptp_ocp *bp = priv; 4187 + 4188 + *status = bp->sync ? DPLL_LOCK_STATUS_LOCKED : DPLL_LOCK_STATUS_UNLOCKED; 4189 + 4190 + return 0; 4191 + } 4192 + 4193 + static int ptp_ocp_dpll_state_get(const struct dpll_pin *pin, void *pin_priv, 4194 + const struct dpll_device *dpll, void *priv, 4195 + enum dpll_pin_state *state, 4196 + struct netlink_ext_ack *extack) 4197 + { 4198 + struct ptp_ocp *bp = priv; 4199 + int idx; 4200 + 4201 + if (bp->pps_select) { 4202 + idx = ioread32(&bp->pps_select->gpio1); 4203 + *state = (&bp->sma[idx] == pin_priv) ? DPLL_PIN_STATE_CONNECTED : 4204 + DPLL_PIN_STATE_SELECTABLE; 4205 + return 0; 4206 + } 4207 + NL_SET_ERR_MSG(extack, "pin selection is not supported on current HW"); 4208 + return -EINVAL; 4209 + } 4210 + 4211 + static int ptp_ocp_dpll_mode_get(const struct dpll_device *dpll, void *priv, 4212 + u32 *mode, struct netlink_ext_ack *extack) 4213 + { 4214 + *mode = DPLL_MODE_AUTOMATIC; 4215 + return 0; 4216 + } 4217 + 4218 + static bool ptp_ocp_dpll_mode_supported(const struct dpll_device *dpll, 4219 + void *priv, const enum dpll_mode mode, 4220 + struct netlink_ext_ack *extack) 4221 + { 4222 + return mode == DPLL_MODE_AUTOMATIC; 4223 + } 4224 + 4225 + static int ptp_ocp_dpll_direction_get(const struct dpll_pin *pin, 4226 + void *pin_priv, 4227 + const struct dpll_device *dpll, 4228 + void *priv, 4229 + enum dpll_pin_direction *direction, 4230 + struct netlink_ext_ack *extack) 4231 + { 4232 + struct ptp_ocp_sma_connector *sma = pin_priv; 4233 + 4234 + *direction = sma->mode == SMA_MODE_IN ? 4235 + DPLL_PIN_DIRECTION_INPUT : 4236 + DPLL_PIN_DIRECTION_OUTPUT; 4237 + return 0; 4238 + } 4239 + 4240 + static int ptp_ocp_dpll_direction_set(const struct dpll_pin *pin, 4241 + void *pin_priv, 4242 + const struct dpll_device *dpll, 4243 + void *dpll_priv, 4244 + enum dpll_pin_direction direction, 4245 + struct netlink_ext_ack *extack) 4246 + { 4247 + struct ptp_ocp_sma_connector *sma = pin_priv; 4248 + struct ptp_ocp *bp = dpll_priv; 4249 + enum ptp_ocp_sma_mode mode; 4250 + int sma_nr = (sma - bp->sma); 4251 + 4252 + if (sma->fixed_dir) 4253 + return -EOPNOTSUPP; 4254 + mode = direction == DPLL_PIN_DIRECTION_INPUT ? 4255 + SMA_MODE_IN : SMA_MODE_OUT; 4256 + return ptp_ocp_sma_store_val(bp, 0, mode, sma_nr); 4257 + } 4258 + 4259 + static int ptp_ocp_dpll_frequency_set(const struct dpll_pin *pin, 4260 + void *pin_priv, 4261 + const struct dpll_device *dpll, 4262 + void *dpll_priv, u64 frequency, 4263 + struct netlink_ext_ack *extack) 4264 + { 4265 + struct ptp_ocp_sma_connector *sma = pin_priv; 4266 + struct ptp_ocp *bp = dpll_priv; 4267 + const struct ocp_selector *tbl; 4268 + int sma_nr = (sma - bp->sma); 4269 + int i; 4270 + 4271 + if (sma->fixed_fcn) 4272 + return -EOPNOTSUPP; 4273 + 4274 + tbl = bp->sma_op->tbl[sma->mode]; 4275 + for (i = 0; tbl[i].name; i++) 4276 + if (tbl[i].frequency == frequency) 4277 + return ptp_ocp_sma_store_val(bp, i, sma->mode, sma_nr); 4278 + return -EINVAL; 4279 + } 4280 + 4281 + static int ptp_ocp_dpll_frequency_get(const struct dpll_pin *pin, 4282 + void *pin_priv, 4283 + const struct dpll_device *dpll, 4284 + void *dpll_priv, u64 *frequency, 4285 + struct netlink_ext_ack *extack) 4286 + { 4287 + struct ptp_ocp_sma_connector *sma = pin_priv; 4288 + struct ptp_ocp *bp = dpll_priv; 4289 + const struct ocp_selector *tbl; 4290 + int sma_nr = (sma - bp->sma); 4291 + u32 val; 4292 + int i; 4293 + 4294 + val = bp->sma_op->get(bp, sma_nr); 4295 + tbl = bp->sma_op->tbl[sma->mode]; 4296 + for (i = 0; tbl[i].name; i++) 4297 + if (val == tbl[i].value) { 4298 + *frequency = tbl[i].frequency; 4299 + return 0; 4300 + } 4301 + 4302 + return -EINVAL; 4303 + } 4304 + 4305 + static const struct dpll_device_ops dpll_ops = { 4306 + .lock_status_get = ptp_ocp_dpll_lock_status_get, 4307 + .mode_get = ptp_ocp_dpll_mode_get, 4308 + .mode_supported = ptp_ocp_dpll_mode_supported, 4309 + }; 4310 + 4311 + static const struct dpll_pin_ops dpll_pins_ops = { 4312 + .frequency_get = ptp_ocp_dpll_frequency_get, 4313 + .frequency_set = ptp_ocp_dpll_frequency_set, 4314 + .direction_get = ptp_ocp_dpll_direction_get, 4315 + .direction_set = ptp_ocp_dpll_direction_set, 4316 + .state_on_dpll_get = ptp_ocp_dpll_state_get, 4317 + }; 4318 + 4319 + static void 4320 + ptp_ocp_sync_work(struct work_struct *work) 4321 + { 4322 + struct ptp_ocp *bp; 4323 + bool sync; 4324 + 4325 + bp = container_of(work, struct ptp_ocp, sync_work.work); 4326 + sync = !!(ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC); 4327 + 4328 + if (bp->sync != sync) 4329 + dpll_device_change_ntf(bp->dpll); 4330 + 4331 + bp->sync = sync; 4332 + 4333 + queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ); 4334 + } 4335 + 4227 4336 static int 4228 4337 ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) 4229 4338 { 4230 4339 struct devlink *devlink; 4231 4340 struct ptp_ocp *bp; 4232 - int err; 4341 + int err, i; 4342 + u64 clkid; 4233 4343 4234 4344 devlink = devlink_alloc(&ptp_ocp_devlink_ops, sizeof(*bp), &pdev->dev); 4235 4345 if (!devlink) { ··· 4403 4201 err = ptp_ocp_device_init(bp, pdev); 4404 4202 if (err) 4405 4203 goto out_disable; 4204 + 4205 + INIT_DELAYED_WORK(&bp->sync_work, ptp_ocp_sync_work); 4406 4206 4407 4207 /* compat mode. 4408 4208 * Older FPGA firmware only returns 2 irq's. ··· 4437 4233 4438 4234 ptp_ocp_info(bp); 4439 4235 devlink_register(devlink); 4440 - return 0; 4441 4236 4237 + clkid = pci_get_dsn(pdev); 4238 + bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE); 4239 + if (IS_ERR(bp->dpll)) { 4240 + err = PTR_ERR(bp->dpll); 4241 + dev_err(&pdev->dev, "dpll_device_alloc failed\n"); 4242 + goto out; 4243 + } 4244 + 4245 + err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp); 4246 + if (err) 4247 + goto out; 4248 + 4249 + for (i = 0; i < OCP_SMA_NUM; i++) { 4250 + bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].dpll_prop); 4251 + if (IS_ERR(bp->sma[i].dpll_pin)) { 4252 + err = PTR_ERR(bp->dpll); 4253 + goto out_dpll; 4254 + } 4255 + 4256 + err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, 4257 + &bp->sma[i]); 4258 + if (err) { 4259 + dpll_pin_put(bp->sma[i].dpll_pin); 4260 + goto out_dpll; 4261 + } 4262 + } 4263 + queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ); 4264 + 4265 + return 0; 4266 + out_dpll: 4267 + while (i) { 4268 + --i; 4269 + dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]); 4270 + dpll_pin_put(bp->sma[i].dpll_pin); 4271 + } 4272 + dpll_device_put(bp->dpll); 4442 4273 out: 4443 4274 ptp_ocp_detach(bp); 4444 4275 out_disable: ··· 4488 4249 { 4489 4250 struct ptp_ocp *bp = pci_get_drvdata(pdev); 4490 4251 struct devlink *devlink = priv_to_devlink(bp); 4252 + int i; 4491 4253 4254 + cancel_delayed_work_sync(&bp->sync_work); 4255 + for (i = 0; i < OCP_SMA_NUM; i++) { 4256 + if (bp->sma[i].dpll_pin) { 4257 + dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, bp); 4258 + dpll_pin_put(bp->sma[i].dpll_pin); 4259 + } 4260 + } 4261 + dpll_device_unregister(bp->dpll, &dpll_ops, bp); 4262 + dpll_device_put(bp->dpll); 4492 4263 devlink_unregister(devlink); 4493 4264 ptp_ocp_detach(bp); 4494 4265 pci_disable_device(pdev);
+152
include/linux/dpll.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates 4 + * Copyright (c) 2023 Intel and affiliates 5 + */ 6 + 7 + #ifndef __DPLL_H__ 8 + #define __DPLL_H__ 9 + 10 + #include <uapi/linux/dpll.h> 11 + #include <linux/device.h> 12 + #include <linux/netlink.h> 13 + 14 + struct dpll_device; 15 + struct dpll_pin; 16 + 17 + struct dpll_device_ops { 18 + int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv, 19 + enum dpll_mode *mode, struct netlink_ext_ack *extack); 20 + bool (*mode_supported)(const struct dpll_device *dpll, void *dpll_priv, 21 + const enum dpll_mode mode, 22 + struct netlink_ext_ack *extack); 23 + int (*lock_status_get)(const struct dpll_device *dpll, void *dpll_priv, 24 + enum dpll_lock_status *status, 25 + struct netlink_ext_ack *extack); 26 + int (*temp_get)(const struct dpll_device *dpll, void *dpll_priv, 27 + s32 *temp, struct netlink_ext_ack *extack); 28 + }; 29 + 30 + struct dpll_pin_ops { 31 + int (*frequency_set)(const struct dpll_pin *pin, void *pin_priv, 32 + const struct dpll_device *dpll, void *dpll_priv, 33 + const u64 frequency, 34 + struct netlink_ext_ack *extack); 35 + int (*frequency_get)(const struct dpll_pin *pin, void *pin_priv, 36 + const struct dpll_device *dpll, void *dpll_priv, 37 + u64 *frequency, struct netlink_ext_ack *extack); 38 + int (*direction_set)(const struct dpll_pin *pin, void *pin_priv, 39 + const struct dpll_device *dpll, void *dpll_priv, 40 + const enum dpll_pin_direction direction, 41 + struct netlink_ext_ack *extack); 42 + int (*direction_get)(const struct dpll_pin *pin, void *pin_priv, 43 + const struct dpll_device *dpll, void *dpll_priv, 44 + enum dpll_pin_direction *direction, 45 + struct netlink_ext_ack *extack); 46 + int (*state_on_pin_get)(const struct dpll_pin *pin, void *pin_priv, 47 + const struct dpll_pin *parent_pin, 48 + void *parent_pin_priv, 49 + enum dpll_pin_state *state, 50 + struct netlink_ext_ack *extack); 51 + int (*state_on_dpll_get)(const struct dpll_pin *pin, void *pin_priv, 52 + const struct dpll_device *dpll, 53 + void *dpll_priv, enum dpll_pin_state *state, 54 + struct netlink_ext_ack *extack); 55 + int (*state_on_pin_set)(const struct dpll_pin *pin, void *pin_priv, 56 + const struct dpll_pin *parent_pin, 57 + void *parent_pin_priv, 58 + const enum dpll_pin_state state, 59 + struct netlink_ext_ack *extack); 60 + int (*state_on_dpll_set)(const struct dpll_pin *pin, void *pin_priv, 61 + const struct dpll_device *dpll, 62 + void *dpll_priv, 63 + const enum dpll_pin_state state, 64 + struct netlink_ext_ack *extack); 65 + int (*prio_get)(const struct dpll_pin *pin, void *pin_priv, 66 + const struct dpll_device *dpll, void *dpll_priv, 67 + u32 *prio, struct netlink_ext_ack *extack); 68 + int (*prio_set)(const struct dpll_pin *pin, void *pin_priv, 69 + const struct dpll_device *dpll, void *dpll_priv, 70 + const u32 prio, struct netlink_ext_ack *extack); 71 + }; 72 + 73 + struct dpll_pin_frequency { 74 + u64 min; 75 + u64 max; 76 + }; 77 + 78 + #define DPLL_PIN_FREQUENCY_RANGE(_min, _max) \ 79 + { \ 80 + .min = _min, \ 81 + .max = _max, \ 82 + } 83 + 84 + #define DPLL_PIN_FREQUENCY(_val) DPLL_PIN_FREQUENCY_RANGE(_val, _val) 85 + #define DPLL_PIN_FREQUENCY_1PPS \ 86 + DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_1_HZ) 87 + #define DPLL_PIN_FREQUENCY_10MHZ \ 88 + DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_10_MHZ) 89 + #define DPLL_PIN_FREQUENCY_IRIG_B \ 90 + DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_10_KHZ) 91 + #define DPLL_PIN_FREQUENCY_DCF77 \ 92 + DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_77_5_KHZ) 93 + 94 + struct dpll_pin_properties { 95 + const char *board_label; 96 + const char *panel_label; 97 + const char *package_label; 98 + enum dpll_pin_type type; 99 + unsigned long capabilities; 100 + u32 freq_supported_num; 101 + struct dpll_pin_frequency *freq_supported; 102 + }; 103 + 104 + #if IS_ENABLED(CONFIG_DPLL) 105 + size_t dpll_msg_pin_handle_size(struct dpll_pin *pin); 106 + int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin); 107 + #else 108 + static inline size_t dpll_msg_pin_handle_size(struct dpll_pin *pin) 109 + { 110 + return 0; 111 + } 112 + 113 + static inline int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin) 114 + { 115 + return 0; 116 + } 117 + #endif 118 + 119 + struct dpll_device * 120 + dpll_device_get(u64 clock_id, u32 dev_driver_id, struct module *module); 121 + 122 + void dpll_device_put(struct dpll_device *dpll); 123 + 124 + int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, 125 + const struct dpll_device_ops *ops, void *priv); 126 + 127 + void dpll_device_unregister(struct dpll_device *dpll, 128 + const struct dpll_device_ops *ops, void *priv); 129 + 130 + struct dpll_pin * 131 + dpll_pin_get(u64 clock_id, u32 dev_driver_id, struct module *module, 132 + const struct dpll_pin_properties *prop); 133 + 134 + int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, 135 + const struct dpll_pin_ops *ops, void *priv); 136 + 137 + void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, 138 + const struct dpll_pin_ops *ops, void *priv); 139 + 140 + void dpll_pin_put(struct dpll_pin *pin); 141 + 142 + int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, 143 + const struct dpll_pin_ops *ops, void *priv); 144 + 145 + void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, 146 + const struct dpll_pin_ops *ops, void *priv); 147 + 148 + int dpll_device_change_ntf(struct dpll_device *dpll); 149 + 150 + int dpll_pin_change_ntf(struct dpll_pin *pin); 151 + 152 + #endif
+2
include/linux/mlx5/driver.h
··· 155 155 MLX5_REG_MCC = 0x9062, 156 156 MLX5_REG_MCDA = 0x9063, 157 157 MLX5_REG_MCAM = 0x907f, 158 + MLX5_REG_MSECQ = 0x9155, 159 + MLX5_REG_MSEES = 0x9156, 158 160 MLX5_REG_MIRC = 0x9162, 159 161 MLX5_REG_SBCAM = 0xB01F, 160 162 MLX5_REG_RESOURCE_DUMP = 0xC000,
+58 -1
include/linux/mlx5/mlx5_ifc.h
··· 10176 10176 u8 mirc[0x1]; 10177 10177 u8 regs_97_to_96[0x2]; 10178 10178 10179 - u8 regs_95_to_64[0x20]; 10179 + u8 regs_95_to_87[0x09]; 10180 + u8 synce_registers[0x2]; 10181 + u8 regs_84_to_64[0x15]; 10180 10182 10181 10183 u8 regs_63_to_32[0x20]; 10182 10184 ··· 12549 12547 struct mlx5_ifc_modify_page_track_obj_in_bits { 12550 12548 struct mlx5_ifc_general_obj_in_cmd_hdr_bits general_obj_in_cmd_hdr; 12551 12549 struct mlx5_ifc_page_track_bits obj_context; 12550 + }; 12551 + 12552 + struct mlx5_ifc_msecq_reg_bits { 12553 + u8 reserved_at_0[0x20]; 12554 + 12555 + u8 reserved_at_20[0x12]; 12556 + u8 network_option[0x2]; 12557 + u8 local_ssm_code[0x4]; 12558 + u8 local_enhanced_ssm_code[0x8]; 12559 + 12560 + u8 local_clock_identity[0x40]; 12561 + 12562 + u8 reserved_at_80[0x180]; 12563 + }; 12564 + 12565 + enum { 12566 + MLX5_MSEES_FIELD_SELECT_ENABLE = BIT(0), 12567 + MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS = BIT(1), 12568 + MLX5_MSEES_FIELD_SELECT_ADMIN_FREQ_MEASURE = BIT(2), 12569 + }; 12570 + 12571 + enum mlx5_msees_admin_status { 12572 + MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING = 0x0, 12573 + MLX5_MSEES_ADMIN_STATUS_TRACK = 0x1, 12574 + }; 12575 + 12576 + enum mlx5_msees_oper_status { 12577 + MLX5_MSEES_OPER_STATUS_FREE_RUNNING = 0x0, 12578 + MLX5_MSEES_OPER_STATUS_SELF_TRACK = 0x1, 12579 + MLX5_MSEES_OPER_STATUS_OTHER_TRACK = 0x2, 12580 + MLX5_MSEES_OPER_STATUS_HOLDOVER = 0x3, 12581 + MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER = 0x4, 12582 + MLX5_MSEES_OPER_STATUS_FAIL_FREE_RUNNING = 0x5, 12583 + }; 12584 + 12585 + struct mlx5_ifc_msees_reg_bits { 12586 + u8 reserved_at_0[0x8]; 12587 + u8 local_port[0x8]; 12588 + u8 pnat[0x2]; 12589 + u8 lp_msb[0x2]; 12590 + u8 reserved_at_14[0xc]; 12591 + 12592 + u8 field_select[0x20]; 12593 + 12594 + u8 admin_status[0x4]; 12595 + u8 oper_status[0x4]; 12596 + u8 ho_acq[0x1]; 12597 + u8 reserved_at_49[0xc]; 12598 + u8 admin_freq_measure[0x1]; 12599 + u8 oper_freq_measure[0x1]; 12600 + u8 failure_reason[0x9]; 12601 + 12602 + u8 frequency_diff[0x20]; 12603 + 12604 + u8 reserved_at_80[0x180]; 12552 12605 }; 12553 12606 12554 12607 #endif /* MLX5_IFC_H */
+21
include/linux/netdevice.h
··· 79 79 struct xdp_frame; 80 80 struct xdp_metadata_ops; 81 81 struct xdp_md; 82 + /* DPLL specific */ 83 + struct dpll_pin; 82 84 83 85 typedef u32 xdp_features_t; 84 86 ··· 2051 2049 * SET_NETDEV_DEVLINK_PORT macro. This pointer is static 2052 2050 * during the time netdevice is registered. 2053 2051 * 2052 + * @dpll_pin: Pointer to the SyncE source pin of a DPLL subsystem, 2053 + * where the clock is recovered. 2054 + * 2054 2055 * FIXME: cleanup struct net_device such that network protocol info 2055 2056 * moves out. 2056 2057 */ ··· 2410 2405 struct rtnl_hw_stats64 *offload_xstats_l3; 2411 2406 2412 2407 struct devlink_port *devlink_port; 2408 + 2409 + #if IS_ENABLED(CONFIG_DPLL) 2410 + struct dpll_pin *dpll_pin; 2411 + #endif 2413 2412 }; 2414 2413 #define to_net_dev(d) container_of(d, struct net_device, dev) 2415 2414 ··· 3949 3940 int dev_get_port_parent_id(struct net_device *dev, 3950 3941 struct netdev_phys_item_id *ppid, bool recurse); 3951 3942 bool netdev_port_same_parent_id(struct net_device *a, struct net_device *b); 3943 + void netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin); 3944 + void netdev_dpll_pin_clear(struct net_device *dev); 3945 + 3946 + static inline struct dpll_pin *netdev_dpll_pin(const struct net_device *dev) 3947 + { 3948 + #if IS_ENABLED(CONFIG_DPLL) 3949 + return dev->dpll_pin; 3950 + #else 3951 + return NULL; 3952 + #endif 3953 + } 3954 + 3952 3955 struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev, bool *again); 3953 3956 struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, 3954 3957 struct netdev_queue *txq, int *ret);
+201
include/uapi/linux/dpll.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/dpll.yaml */ 4 + /* YNL-GEN uapi header */ 5 + 6 + #ifndef _UAPI_LINUX_DPLL_H 7 + #define _UAPI_LINUX_DPLL_H 8 + 9 + #define DPLL_FAMILY_NAME "dpll" 10 + #define DPLL_FAMILY_VERSION 1 11 + 12 + /** 13 + * enum dpll_mode - working modes a dpll can support, differentiates if and how 14 + * dpll selects one of its inputs to syntonize with it, valid values for 15 + * DPLL_A_MODE attribute 16 + * @DPLL_MODE_MANUAL: input can be only selected by sending a request to dpll 17 + * @DPLL_MODE_AUTOMATIC: highest prio input pin auto selected by dpll 18 + */ 19 + enum dpll_mode { 20 + DPLL_MODE_MANUAL = 1, 21 + DPLL_MODE_AUTOMATIC, 22 + 23 + /* private: */ 24 + __DPLL_MODE_MAX, 25 + DPLL_MODE_MAX = (__DPLL_MODE_MAX - 1) 26 + }; 27 + 28 + /** 29 + * enum dpll_lock_status - provides information of dpll device lock status, 30 + * valid values for DPLL_A_LOCK_STATUS attribute 31 + * @DPLL_LOCK_STATUS_UNLOCKED: dpll was not yet locked to any valid input (or 32 + * forced by setting DPLL_A_MODE to DPLL_MODE_DETACHED) 33 + * @DPLL_LOCK_STATUS_LOCKED: dpll is locked to a valid signal, but no holdover 34 + * available 35 + * @DPLL_LOCK_STATUS_LOCKED_HO_ACQ: dpll is locked and holdover acquired 36 + * @DPLL_LOCK_STATUS_HOLDOVER: dpll is in holdover state - lost a valid lock or 37 + * was forced by disconnecting all the pins (latter possible only when dpll 38 + * lock-state was already DPLL_LOCK_STATUS_LOCKED_HO_ACQ, if dpll lock-state 39 + * was not DPLL_LOCK_STATUS_LOCKED_HO_ACQ, the dpll's lock-state shall remain 40 + * DPLL_LOCK_STATUS_UNLOCKED) 41 + */ 42 + enum dpll_lock_status { 43 + DPLL_LOCK_STATUS_UNLOCKED = 1, 44 + DPLL_LOCK_STATUS_LOCKED, 45 + DPLL_LOCK_STATUS_LOCKED_HO_ACQ, 46 + DPLL_LOCK_STATUS_HOLDOVER, 47 + 48 + /* private: */ 49 + __DPLL_LOCK_STATUS_MAX, 50 + DPLL_LOCK_STATUS_MAX = (__DPLL_LOCK_STATUS_MAX - 1) 51 + }; 52 + 53 + #define DPLL_TEMP_DIVIDER 1000 54 + 55 + /** 56 + * enum dpll_type - type of dpll, valid values for DPLL_A_TYPE attribute 57 + * @DPLL_TYPE_PPS: dpll produces Pulse-Per-Second signal 58 + * @DPLL_TYPE_EEC: dpll drives the Ethernet Equipment Clock 59 + */ 60 + enum dpll_type { 61 + DPLL_TYPE_PPS = 1, 62 + DPLL_TYPE_EEC, 63 + 64 + /* private: */ 65 + __DPLL_TYPE_MAX, 66 + DPLL_TYPE_MAX = (__DPLL_TYPE_MAX - 1) 67 + }; 68 + 69 + /** 70 + * enum dpll_pin_type - defines possible types of a pin, valid values for 71 + * DPLL_A_PIN_TYPE attribute 72 + * @DPLL_PIN_TYPE_MUX: aggregates another layer of selectable pins 73 + * @DPLL_PIN_TYPE_EXT: external input 74 + * @DPLL_PIN_TYPE_SYNCE_ETH_PORT: ethernet port PHY's recovered clock 75 + * @DPLL_PIN_TYPE_INT_OSCILLATOR: device internal oscillator 76 + * @DPLL_PIN_TYPE_GNSS: GNSS recovered clock 77 + */ 78 + enum dpll_pin_type { 79 + DPLL_PIN_TYPE_MUX = 1, 80 + DPLL_PIN_TYPE_EXT, 81 + DPLL_PIN_TYPE_SYNCE_ETH_PORT, 82 + DPLL_PIN_TYPE_INT_OSCILLATOR, 83 + DPLL_PIN_TYPE_GNSS, 84 + 85 + /* private: */ 86 + __DPLL_PIN_TYPE_MAX, 87 + DPLL_PIN_TYPE_MAX = (__DPLL_PIN_TYPE_MAX - 1) 88 + }; 89 + 90 + /** 91 + * enum dpll_pin_direction - defines possible direction of a pin, valid values 92 + * for DPLL_A_PIN_DIRECTION attribute 93 + * @DPLL_PIN_DIRECTION_INPUT: pin used as a input of a signal 94 + * @DPLL_PIN_DIRECTION_OUTPUT: pin used to output the signal 95 + */ 96 + enum dpll_pin_direction { 97 + DPLL_PIN_DIRECTION_INPUT = 1, 98 + DPLL_PIN_DIRECTION_OUTPUT, 99 + 100 + /* private: */ 101 + __DPLL_PIN_DIRECTION_MAX, 102 + DPLL_PIN_DIRECTION_MAX = (__DPLL_PIN_DIRECTION_MAX - 1) 103 + }; 104 + 105 + #define DPLL_PIN_FREQUENCY_1_HZ 1 106 + #define DPLL_PIN_FREQUENCY_10_KHZ 10000 107 + #define DPLL_PIN_FREQUENCY_77_5_KHZ 77500 108 + #define DPLL_PIN_FREQUENCY_10_MHZ 10000000 109 + 110 + /** 111 + * enum dpll_pin_state - defines possible states of a pin, valid values for 112 + * DPLL_A_PIN_STATE attribute 113 + * @DPLL_PIN_STATE_CONNECTED: pin connected, active input of phase locked loop 114 + * @DPLL_PIN_STATE_DISCONNECTED: pin disconnected, not considered as a valid 115 + * input 116 + * @DPLL_PIN_STATE_SELECTABLE: pin enabled for automatic input selection 117 + */ 118 + enum dpll_pin_state { 119 + DPLL_PIN_STATE_CONNECTED = 1, 120 + DPLL_PIN_STATE_DISCONNECTED, 121 + DPLL_PIN_STATE_SELECTABLE, 122 + 123 + /* private: */ 124 + __DPLL_PIN_STATE_MAX, 125 + DPLL_PIN_STATE_MAX = (__DPLL_PIN_STATE_MAX - 1) 126 + }; 127 + 128 + /** 129 + * enum dpll_pin_capabilities - defines possible capabilities of a pin, valid 130 + * flags on DPLL_A_PIN_CAPABILITIES attribute 131 + * @DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE: pin direction can be changed 132 + * @DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE: pin priority can be changed 133 + * @DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE: pin state can be changed 134 + */ 135 + enum dpll_pin_capabilities { 136 + DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE = 1, 137 + DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE = 2, 138 + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE = 4, 139 + }; 140 + 141 + enum dpll_a { 142 + DPLL_A_ID = 1, 143 + DPLL_A_MODULE_NAME, 144 + DPLL_A_PAD, 145 + DPLL_A_CLOCK_ID, 146 + DPLL_A_MODE, 147 + DPLL_A_MODE_SUPPORTED, 148 + DPLL_A_LOCK_STATUS, 149 + DPLL_A_TEMP, 150 + DPLL_A_TYPE, 151 + 152 + __DPLL_A_MAX, 153 + DPLL_A_MAX = (__DPLL_A_MAX - 1) 154 + }; 155 + 156 + enum dpll_a_pin { 157 + DPLL_A_PIN_ID = 1, 158 + DPLL_A_PIN_PARENT_ID, 159 + DPLL_A_PIN_MODULE_NAME, 160 + DPLL_A_PIN_PAD, 161 + DPLL_A_PIN_CLOCK_ID, 162 + DPLL_A_PIN_BOARD_LABEL, 163 + DPLL_A_PIN_PANEL_LABEL, 164 + DPLL_A_PIN_PACKAGE_LABEL, 165 + DPLL_A_PIN_TYPE, 166 + DPLL_A_PIN_DIRECTION, 167 + DPLL_A_PIN_FREQUENCY, 168 + DPLL_A_PIN_FREQUENCY_SUPPORTED, 169 + DPLL_A_PIN_FREQUENCY_MIN, 170 + DPLL_A_PIN_FREQUENCY_MAX, 171 + DPLL_A_PIN_PRIO, 172 + DPLL_A_PIN_STATE, 173 + DPLL_A_PIN_CAPABILITIES, 174 + DPLL_A_PIN_PARENT_DEVICE, 175 + DPLL_A_PIN_PARENT_PIN, 176 + 177 + __DPLL_A_PIN_MAX, 178 + DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) 179 + }; 180 + 181 + enum dpll_cmd { 182 + DPLL_CMD_DEVICE_ID_GET = 1, 183 + DPLL_CMD_DEVICE_GET, 184 + DPLL_CMD_DEVICE_SET, 185 + DPLL_CMD_DEVICE_CREATE_NTF, 186 + DPLL_CMD_DEVICE_DELETE_NTF, 187 + DPLL_CMD_DEVICE_CHANGE_NTF, 188 + DPLL_CMD_PIN_ID_GET, 189 + DPLL_CMD_PIN_GET, 190 + DPLL_CMD_PIN_SET, 191 + DPLL_CMD_PIN_CREATE_NTF, 192 + DPLL_CMD_PIN_DELETE_NTF, 193 + DPLL_CMD_PIN_CHANGE_NTF, 194 + 195 + __DPLL_CMD_MAX, 196 + DPLL_CMD_MAX = (__DPLL_CMD_MAX - 1) 197 + }; 198 + 199 + #define DPLL_MCGRP_MONITOR "monitor" 200 + 201 + #endif /* _UAPI_LINUX_DPLL_H */
+1 -1
include/uapi/linux/if_link.h
··· 376 376 377 377 IFLA_GSO_IPV4_MAX_SIZE, 378 378 IFLA_GRO_IPV4_MAX_SIZE, 379 - 379 + IFLA_DPLL_PIN, 380 380 __IFLA_MAX 381 381 }; 382 382
+22
net/core/dev.c
··· 9023 9023 } 9024 9024 EXPORT_SYMBOL(netdev_port_same_parent_id); 9025 9025 9026 + static void netdev_dpll_pin_assign(struct net_device *dev, struct dpll_pin *dpll_pin) 9027 + { 9028 + #if IS_ENABLED(CONFIG_DPLL) 9029 + rtnl_lock(); 9030 + dev->dpll_pin = dpll_pin; 9031 + rtnl_unlock(); 9032 + #endif 9033 + } 9034 + 9035 + void netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin) 9036 + { 9037 + WARN_ON(!dpll_pin); 9038 + netdev_dpll_pin_assign(dev, dpll_pin); 9039 + } 9040 + EXPORT_SYMBOL(netdev_dpll_pin_set); 9041 + 9042 + void netdev_dpll_pin_clear(struct net_device *dev) 9043 + { 9044 + netdev_dpll_pin_assign(dev, NULL); 9045 + } 9046 + EXPORT_SYMBOL(netdev_dpll_pin_clear); 9047 + 9026 9048 /** 9027 9049 * dev_change_proto_down - set carrier according to proto_down. 9028 9050 *
+36
net/core/rtnetlink.c
··· 57 57 #if IS_ENABLED(CONFIG_IPV6) 58 58 #include <net/addrconf.h> 59 59 #endif 60 + #include <linux/dpll.h> 60 61 61 62 #include "dev.h" 62 63 ··· 1056 1055 return size; 1057 1056 } 1058 1057 1058 + static size_t rtnl_dpll_pin_size(const struct net_device *dev) 1059 + { 1060 + size_t size = nla_total_size(0); /* nest IFLA_DPLL_PIN */ 1061 + 1062 + size += dpll_msg_pin_handle_size(netdev_dpll_pin(dev)); 1063 + 1064 + return size; 1065 + } 1066 + 1059 1067 static noinline size_t if_nlmsg_size(const struct net_device *dev, 1060 1068 u32 ext_filter_mask) 1061 1069 { ··· 1121 1111 + rtnl_prop_list_size(dev) 1122 1112 + nla_total_size(MAX_ADDR_LEN) /* IFLA_PERM_ADDRESS */ 1123 1113 + rtnl_devlink_port_size(dev) 1114 + + rtnl_dpll_pin_size(dev) 1124 1115 + 0; 1125 1116 } 1126 1117 ··· 1785 1774 return ret; 1786 1775 } 1787 1776 1777 + static int rtnl_fill_dpll_pin(struct sk_buff *skb, 1778 + const struct net_device *dev) 1779 + { 1780 + struct nlattr *dpll_pin_nest; 1781 + int ret; 1782 + 1783 + dpll_pin_nest = nla_nest_start(skb, IFLA_DPLL_PIN); 1784 + if (!dpll_pin_nest) 1785 + return -EMSGSIZE; 1786 + 1787 + ret = dpll_msg_add_pin_handle(skb, netdev_dpll_pin(dev)); 1788 + if (ret < 0) 1789 + goto nest_cancel; 1790 + 1791 + nla_nest_end(skb, dpll_pin_nest); 1792 + return 0; 1793 + 1794 + nest_cancel: 1795 + nla_nest_cancel(skb, dpll_pin_nest); 1796 + return ret; 1797 + } 1798 + 1788 1799 static int rtnl_fill_ifinfo(struct sk_buff *skb, 1789 1800 struct net_device *dev, struct net *src_net, 1790 1801 int type, u32 pid, u32 seq, u32 change, ··· 1947 1914 goto nla_put_failure; 1948 1915 1949 1916 if (rtnl_fill_devlink_port(skb, dev)) 1917 + goto nla_put_failure; 1918 + 1919 + if (rtnl_fill_dpll_pin(skb, dev)) 1950 1920 goto nla_put_failure; 1951 1921 1952 1922 nlmsg_end(skb, nlh);