Files
linux-stable-mirror/include/linux/dpll.h
T
Grzegorz Nitka 0bf47f722f dpll: extend pin notifier with notification source ID
Extend the DPLL pin notification API to include a source identifier
indicating where the notification originates. This allows notifier
consumers to distinguish between notifications coming from
an associated DPLL instance, a parent pin, or the pin itself.

A new field, src_clock_id, is added to struct dpll_pin_notifier_info
and is passed through all pin-related notification paths. Callers of
dpll_pin_notify() are updated to provide a meaningful source identifier
based on their context:
  - pin registration/unregistration uses the DPLL's clock_id,
  - pin-on-pin operations use the parent pin's clock_id,
  - pin changes use the pin's own clock_id.

As introduced in the commit ("dpll: allow registering FW-identified pin
with a different DPLL"), it is possible to share the same physical pin
via firmware description (fwnode) with DPLL objects from different
kernel modules. This means that a given pin can be registered multiple
times.

Driver such as ICE (E825 devices) rely on this mechanism when listening
for the event where a shared-fwnode pin appears, while avoiding reacting
to events triggered by their own registration logic.

This change only extends the notification metadata and does not alter
existing semantics for drivers that do not use the new field.

Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
Link: https://patch.msgid.link/20260607183045.1213735-9-grzegorz.nitka@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2026-06-13 13:24:34 -07:00

324 lines
10 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023 Meta Platforms, Inc. and affiliates
* Copyright (c) 2023 Intel and affiliates
*/
#ifndef __DPLL_H__
#define __DPLL_H__
#include <uapi/linux/dpll.h>
#include <linux/device.h>
#include <linux/netlink.h>
#include <linux/netdevice.h>
#include <linux/notifier.h>
#include <linux/rtnetlink.h>
#include <net/netlink.h>
struct dpll_device;
struct dpll_pin;
struct dpll_pin_esync;
struct fwnode_handle;
struct ref_tracker;
struct dpll_device_ops {
int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv,
enum dpll_mode *mode, struct netlink_ext_ack *extack);
int (*mode_set)(const struct dpll_device *dpll, void *dpll_priv,
enum dpll_mode mode, struct netlink_ext_ack *extack);
int (*supported_modes_get)(const struct dpll_device *dpll,
void *dpll_priv, unsigned long *modes,
struct netlink_ext_ack *extack);
int (*lock_status_get)(const struct dpll_device *dpll, void *dpll_priv,
enum dpll_lock_status *status,
enum dpll_lock_status_error *status_error,
struct netlink_ext_ack *extack);
int (*temp_get)(const struct dpll_device *dpll, void *dpll_priv,
s32 *temp, struct netlink_ext_ack *extack);
int (*clock_quality_level_get)(const struct dpll_device *dpll,
void *dpll_priv,
unsigned long *qls,
struct netlink_ext_ack *extack);
int (*phase_offset_monitor_set)(const struct dpll_device *dpll,
void *dpll_priv,
enum dpll_feature_state state,
struct netlink_ext_ack *extack);
int (*phase_offset_monitor_get)(const struct dpll_device *dpll,
void *dpll_priv,
enum dpll_feature_state *state,
struct netlink_ext_ack *extack);
int (*phase_offset_avg_factor_set)(const struct dpll_device *dpll,
void *dpll_priv, u32 factor,
struct netlink_ext_ack *extack);
int (*phase_offset_avg_factor_get)(const struct dpll_device *dpll,
void *dpll_priv, u32 *factor,
struct netlink_ext_ack *extack);
int (*freq_monitor_set)(const struct dpll_device *dpll, void *dpll_priv,
enum dpll_feature_state state,
struct netlink_ext_ack *extack);
int (*freq_monitor_get)(const struct dpll_device *dpll, void *dpll_priv,
enum dpll_feature_state *state,
struct netlink_ext_ack *extack);
};
enum dpll_ffo_type {
DPLL_FFO_PORT_RXTX_RATE,
DPLL_FFO_PIN_DEVICE,
__DPLL_FFO_TYPE_MAX,
};
struct dpll_ffo_param {
enum dpll_ffo_type type;
s64 ffo;
};
struct dpll_pin_ops {
unsigned long supported_ffo;
int (*frequency_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
const u64 frequency,
struct netlink_ext_ack *extack);
int (*frequency_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
u64 *frequency, struct netlink_ext_ack *extack);
int (*direction_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
const enum dpll_pin_direction direction,
struct netlink_ext_ack *extack);
int (*direction_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
enum dpll_pin_direction *direction,
struct netlink_ext_ack *extack);
int (*state_on_pin_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *parent_pin,
void *parent_pin_priv,
enum dpll_pin_state *state,
struct netlink_ext_ack *extack);
int (*state_on_dpll_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll,
void *dpll_priv, enum dpll_pin_state *state,
struct netlink_ext_ack *extack);
int (*operstate_on_dpll_get)(const struct dpll_pin *pin,
void *pin_priv,
const struct dpll_device *dpll,
void *dpll_priv,
enum dpll_pin_operstate *operstate,
struct netlink_ext_ack *extack);
int (*state_on_pin_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *parent_pin,
void *parent_pin_priv,
const enum dpll_pin_state state,
struct netlink_ext_ack *extack);
int (*state_on_dpll_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll,
void *dpll_priv,
const enum dpll_pin_state state,
struct netlink_ext_ack *extack);
int (*prio_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
u32 *prio, struct netlink_ext_ack *extack);
int (*prio_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
const u32 prio, struct netlink_ext_ack *extack);
int (*phase_offset_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
s64 *phase_offset,
struct netlink_ext_ack *extack);
int (*phase_adjust_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
s32 *phase_adjust,
struct netlink_ext_ack *extack);
int (*phase_adjust_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
const s32 phase_adjust,
struct netlink_ext_ack *extack);
int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
struct dpll_ffo_param *ffo,
struct netlink_ext_ack *extack);
int (*measured_freq_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll,
void *dpll_priv, u64 *measured_freq,
struct netlink_ext_ack *extack);
int (*esync_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
u64 freq, struct netlink_ext_ack *extack);
int (*esync_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
struct dpll_pin_esync *esync,
struct netlink_ext_ack *extack);
int (*ref_sync_set)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *ref_sync_pin,
void *ref_sync_pin_priv,
const enum dpll_pin_state state,
struct netlink_ext_ack *extack);
int (*ref_sync_get)(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_pin *ref_sync_pin,
void *ref_sync_pin_priv,
enum dpll_pin_state *state,
struct netlink_ext_ack *extack);
};
struct dpll_pin_frequency {
u64 min;
u64 max;
};
#define DPLL_PIN_FREQUENCY_RANGE(_min, _max) \
{ \
.min = _min, \
.max = _max, \
}
#define DPLL_PIN_FREQUENCY(_val) DPLL_PIN_FREQUENCY_RANGE(_val, _val)
#define DPLL_PIN_FREQUENCY_1PPS \
DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_1_HZ)
#define DPLL_PIN_FREQUENCY_10MHZ \
DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_10_MHZ)
#define DPLL_PIN_FREQUENCY_IRIG_B \
DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_10_KHZ)
#define DPLL_PIN_FREQUENCY_DCF77 \
DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_77_5_KHZ)
struct dpll_pin_phase_adjust_range {
s32 min;
s32 max;
};
struct dpll_pin_esync {
u64 freq;
const struct dpll_pin_frequency *range;
u8 range_num;
u8 pulse;
};
struct dpll_pin_properties {
const char *board_label;
const char *panel_label;
const char *package_label;
enum dpll_pin_type type;
unsigned long capabilities;
u32 freq_supported_num;
struct dpll_pin_frequency *freq_supported;
struct dpll_pin_phase_adjust_range phase_range;
u32 phase_gran;
};
#ifdef CONFIG_DPLL_REFCNT_TRACKER
typedef struct ref_tracker *dpll_tracker;
#else
typedef struct {} dpll_tracker;
#endif
#define DPLL_DEVICE_CREATED 1
#define DPLL_DEVICE_DELETED 2
#define DPLL_DEVICE_CHANGED 3
#define DPLL_PIN_CREATED 4
#define DPLL_PIN_DELETED 5
#define DPLL_PIN_CHANGED 6
struct dpll_device_notifier_info {
struct dpll_device *dpll;
u32 id;
u32 idx;
u64 clock_id;
enum dpll_type type;
};
struct dpll_pin_notifier_info {
struct dpll_pin *pin;
u32 id;
u32 idx;
u64 clock_id;
const struct fwnode_handle *fwnode;
const struct dpll_pin_properties *prop;
u64 src_clock_id;
};
#if IS_ENABLED(CONFIG_DPLL)
void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin);
void dpll_netdev_pin_clear(struct net_device *dev);
static inline size_t dpll_netdev_pin_handle_size(void)
{
return nla_total_size(4); /* DPLL_A_PIN_ID */
}
int dpll_netdev_add_pin_handle(struct sk_buff *msg,
const struct net_device *dev);
struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode,
dpll_tracker *tracker);
#else
static inline void
dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin) { }
static inline void dpll_netdev_pin_clear(struct net_device *dev) { }
static inline size_t dpll_netdev_pin_handle_size(void)
{
return 0;
}
static inline int
dpll_netdev_add_pin_handle(struct sk_buff *msg, const struct net_device *dev)
{
return 0;
}
static inline struct dpll_pin *
fwnode_dpll_pin_find(struct fwnode_handle *fwnode, dpll_tracker *tracker)
{
return NULL;
}
#endif
struct dpll_device *
dpll_device_get(u64 clock_id, u32 dev_driver_id, struct module *module,
dpll_tracker *tracker);
void dpll_device_put(struct dpll_device *dpll, dpll_tracker *tracker);
int dpll_device_register(struct dpll_device *dpll, enum dpll_type type,
const struct dpll_device_ops *ops, void *priv);
void dpll_device_unregister(struct dpll_device *dpll,
const struct dpll_device_ops *ops, void *priv);
#define DPLL_PIN_IDX_UNSPEC U32_MAX
struct dpll_pin *
dpll_pin_get(u64 clock_id, u32 dev_driver_id, struct module *module,
const struct dpll_pin_properties *prop, dpll_tracker *tracker);
int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
const struct dpll_pin_ops *ops, void *priv);
void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
const struct dpll_pin_ops *ops, void *priv);
void dpll_pin_put(struct dpll_pin *pin, dpll_tracker *tracker);
void dpll_pin_fwnode_set(struct dpll_pin *pin, struct fwnode_handle *fwnode);
int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
const struct dpll_pin_ops *ops, void *priv);
void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
const struct dpll_pin_ops *ops, void *priv);
int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,
struct dpll_pin *ref_sync_pin);
int __dpll_device_change_ntf(struct dpll_device *dpll);
int dpll_device_change_ntf(struct dpll_device *dpll);
int __dpll_pin_change_ntf(struct dpll_pin *pin);
int dpll_pin_change_ntf(struct dpll_pin *pin);
int register_dpll_notifier(struct notifier_block *nb);
int unregister_dpll_notifier(struct notifier_block *nb);
#endif