lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <c7480d0a71fb8d62108624878f549c0d91d4c9e6.camel@redhat.com>
Date: Wed, 21 Jun 2023 13:18:59 +0200
From: Petr Oros <poros@...hat.com>
To: Arkadiusz Kubalewski <arkadiusz.kubalewski@...el.com>, kuba@...nel.org, 
 jiri@...nulli.us, vadfed@...a.com, jonathan.lemon@...il.com,
 pabeni@...hat.com
Cc: corbet@....net, davem@...emloft.net, edumazet@...gle.com, vadfed@...com,
  jesse.brandeburg@...el.com, anthony.l.nguyen@...el.com, saeedm@...dia.com,
  leon@...nel.org, richardcochran@...il.com, sj@...nel.org,
 javierm@...hat.com,  ricardo.canuelo@...labora.com, mst@...hat.com,
 tzimmermann@...e.de,  michal.michalik@...el.com,
 gregkh@...uxfoundation.org,  jacek.lawrynowicz@...ux.intel.com,
 airlied@...hat.com, ogabbay@...nel.org,  arnd@...db.de,
 nipun.gupta@....com, axboe@...nel.dk, linux@...y.sk,  masahiroy@...nel.org,
 benjamin.tissoires@...hat.com, geert+renesas@...der.be, 
 milena.olech@...el.com, kuniyu@...zon.com, liuhangbin@...il.com, 
 hkallweit1@...il.com, andy.ren@...cruise.com, razor@...ckwall.org, 
 idosch@...dia.com, lucien.xin@...il.com, nicolas.dichtel@...nd.com,
 phil@....cc,  claudiajkang@...il.com, linux-doc@...r.kernel.org,
 linux-kernel@...r.kernel.org,  netdev@...r.kernel.org,
 intel-wired-lan@...ts.osuosl.org,  linux-rdma@...r.kernel.org,
 linux-arm-kernel@...ts.infradead.org,  mschmidt@...hat.com,
 linux-clk@...r.kernel.org, vadim.fedorenko@...ux.dev
Subject: Re: [RFC PATCH v8 04/10] dpll: netlink: Add DPLL framework base
 functions

Arkadiusz Kubalewski píše v Pá 09. 06. 2023 v 14:18 +0200:
> From: Vadim Fedorenko <vadim.fedorenko@...ux.dev>
> 
> DPLL framework is used to represent and configure DPLL devices
> in systems. Each device that has DPLL and can configure inputs
> and outputs can use this framework.
> 
> Implement dpll netlink framework functions for enablement of dpll
> subsytem netlink family.
> 
> Co-developed-by: Milena Olech <milena.olech@...el.com>
> Signed-off-by: Milena Olech <milena.olech@...el.com>
> Co-developed-by: Michal Michalik <michal.michalik@...el.com>
> Signed-off-by: Michal Michalik <michal.michalik@...el.com>
> Signed-off-by: Vadim Fedorenko <vadim.fedorenko@...ux.dev>
> Co-developed-by: Arkadiusz Kubalewski
> <arkadiusz.kubalewski@...el.com>
> Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@...el.com>
> ---
>  drivers/dpll/dpll_netlink.c | 1183
> +++++++++++++++++++++++++++++++++++
>  drivers/dpll/dpll_netlink.h |   44 ++
>  2 files changed, 1227 insertions(+)
>  create mode 100644 drivers/dpll/dpll_netlink.c
>  create mode 100644 drivers/dpll/dpll_netlink.h
> 
> diff --git a/drivers/dpll/dpll_netlink.c
> b/drivers/dpll/dpll_netlink.c
> new file mode 100644
> index 000000000000..44d9699c9e6c
> --- /dev/null
> +++ b/drivers/dpll/dpll_netlink.c
> @@ -0,0 +1,1183 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Generic netlink for DPLL management framework
> + *
> + *  Copyright (c) 2023 Meta Platforms, Inc. and affiliates
> + *  Copyright (c) 2023 Intel and affiliates
> + *
> + */
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <net/genetlink.h>
> +#include "dpll_core.h"
> +#include "dpll_nl.h"
> +#include <uapi/linux/dpll.h>
> +
> +static int __dpll_pin_change_ntf(struct dpll_pin *pin);
> +
> +struct dpll_dump_ctx {
> +       unsigned long idx;
> +};
> +
> +static struct dpll_dump_ctx *dpll_dump_context(struct
> netlink_callback *cb)
> +{
> +       return (struct dpll_dump_ctx *)cb->ctx;
> +}
> +
> +static int
> +dpll_msg_add_dev_handle(struct sk_buff *msg, struct dpll_device
> *dpll)
> +{
> +       if (nla_put_u32(msg, DPLL_A_ID, dpll->id))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_msg_add_mode(struct sk_buff *msg, struct dpll_device *dpll,
> +                 struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_device_ops *ops = dpll_device_ops(dpll);
> +       enum dpll_mode mode;
> +
> +       if (WARN_ON(!ops->mode_get))
> +               return -EOPNOTSUPP;
> +       if (ops->mode_get(dpll, dpll_priv(dpll), &mode, extack))
> +               return -EFAULT;
> +       if (nla_put_u8(msg, DPLL_A_MODE, mode))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device
> *dpll,
> +                        struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_device_ops *ops = dpll_device_ops(dpll);
> +       enum dpll_lock_status status;
> +
> +       if (WARN_ON(!ops->lock_status_get))
> +               return -EOPNOTSUPP;
> +       if (ops->lock_status_get(dpll, dpll_priv(dpll), &status,
> extack))
> +               return -EFAULT;
> +       if (nla_put_u8(msg, DPLL_A_LOCK_STATUS, status))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll,
> +                 struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_device_ops *ops = dpll_device_ops(dpll);
> +       s32 temp;
> +
> +       if (!ops->temp_get)
> +               return -EOPNOTSUPP;
> +       if (ops->temp_get(dpll, dpll_priv(dpll), &temp, extack))
> +               return -EFAULT;
> +       if (nla_put_s32(msg, DPLL_A_TEMP, temp))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin,
> +                     struct dpll_pin_ref *ref,
> +                     struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
> +       struct dpll_device *dpll = ref->dpll;
> +       u32 prio;
> +
> +       if (!ops->prio_get)
> +               return -EOPNOTSUPP;
> +       if (ops->prio_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
> dpll,
> +                         dpll_priv(dpll), &prio, extack))
> +               return -EFAULT;
> +       if (nla_put_u32(msg, DPLL_A_PIN_PRIO, prio))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin
> *pin,
> +                              struct dpll_pin_ref *ref,
> +                              struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
> +       struct dpll_device *dpll = ref->dpll;
> +       enum dpll_pin_state state;
> +
> +       if (!ops->state_on_dpll_get)
> +               return -EOPNOTSUPP;
> +       if (ops->state_on_dpll_get(pin, dpll_pin_on_dpll_priv(dpll,
> pin), dpll,
> +                                  dpll_priv(dpll), &state, extack))
> +               return -EFAULT;
> +       if (nla_put_u8(msg, DPLL_A_PIN_STATE, state))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin
> *pin,
> +                          struct dpll_pin_ref *ref,
> +                          struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
> +       struct dpll_device *dpll = ref->dpll;
> +       enum dpll_pin_direction direction;
> +
> +       if (!ops->direction_get)
> +               return -EOPNOTSUPP;
> +       if (ops->direction_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
> dpll,
> +                              dpll_priv(dpll), &direction, extack))
> +               return -EFAULT;
> +       if (nla_put_u8(msg, DPLL_A_PIN_DIRECTION, direction))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
> +                     struct dpll_pin_ref *ref, struct
> netlink_ext_ack *extack,
> +                     bool dump_freq_supported)
> +{
> +       const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
> +       struct dpll_device *dpll = ref->dpll;
> +       struct nlattr *nest;
> +       u64 freq;
> +       int fs;
> +
> +       if (!ops->frequency_get)
> +               return -EOPNOTSUPP;
> +       if (ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
> dpll,
> +                              dpll_priv(dpll), &freq, extack))
> +               return -EFAULT;
> +       if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq),
> &freq, 0))
> +               return -EMSGSIZE;
> +       if (!dump_freq_supported)
> +               return 0;
> +       for (fs = 0; fs < pin->prop->freq_supported_num; fs++) {
> +               nest = nla_nest_start(msg,
> DPLL_A_PIN_FREQUENCY_SUPPORTED);
> +               if (!nest)
> +                       return -EMSGSIZE;
> +               freq = pin->prop->freq_supported[fs].min;
> +               if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN,
> sizeof(freq),
> +                                  &freq, 0)) {
> +                       nla_nest_cancel(msg, nest);
> +                       return -EMSGSIZE;
> +               }
> +               freq = pin->prop->freq_supported[fs].max;
> +               if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX,
> sizeof(freq),
> +                                  &freq, 0)) {
> +                       nla_nest_cancel(msg, nest);
> +                       return -EMSGSIZE;
> +               }
> +               nla_nest_end(msg, nest);
> +       }
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin,
> +                        struct dpll_pin_ref *dpll_ref,
> +                        struct netlink_ext_ack *extack)
> +{
> +       enum dpll_pin_state state;
> +       struct dpll_pin_ref *ref;
> +       struct dpll_pin *ppin;
> +       struct nlattr *nest;
> +       unsigned long index;
> +       int ret;
> +
> +       xa_for_each(&pin->parent_refs, index, ref) {
> +               const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
> +               void *parent_priv;
> +
> +               ppin = ref->pin;
> +               parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll,
> ppin);
> +               if (WARN_ON(!ops->state_on_pin_get))
> +                       return -EFAULT;
> +               ret = ops->state_on_pin_get(pin,
> +                                          
> dpll_pin_on_pin_priv(ppin, pin),
> +                                           ppin, parent_priv,
> &state, extack);
> +               if (ret)
> +                       return -EFAULT;
> +               nest = nla_nest_start(msg, DPLL_A_PIN_PARENT);
> +               if (!nest)
> +                       return -EMSGSIZE;
> +               if (nla_put_u32(msg, DPLL_A_PIN_ID, ppin->id)) {
> +                       ret = -EMSGSIZE;
> +                       goto nest_cancel;
> +               }
> +               if (nla_put_u8(msg, DPLL_A_PIN_STATE, state)) {
> +                       ret = -EMSGSIZE;
> +                       goto nest_cancel;
> +               }
> +               nla_nest_end(msg, nest);
> +       }
> +
> +       return 0;
> +
> +nest_cancel:
> +       nla_nest_cancel(msg, nest);
> +       return ret;
> +}
> +
> +static int
> +dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
> +                      struct netlink_ext_ack *extack)
> +{
> +       struct dpll_pin_ref *ref;
> +       struct nlattr *attr;
> +       unsigned long index;
> +       int ret;
> +
> +       xa_for_each(&pin->dpll_refs, index, ref) {
> +               attr = nla_nest_start(msg, DPLL_A_PIN_PARENT);
> +               if (!attr)
> +                       return -EMSGSIZE;
> +               ret = dpll_msg_add_dev_handle(msg, ref->dpll);
> +               if (ret)
> +                       goto nest_cancel;
> +               ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref,
> extack);
> +               if (ret && ret != -EOPNOTSUPP)
> +                       goto nest_cancel;
> +               ret = dpll_msg_add_pin_prio(msg, pin, ref, extack);
> +               if (ret && ret != -EOPNOTSUPP)
> +                       goto nest_cancel;
> +               ret = dpll_msg_add_pin_direction(msg, pin, ref,
> extack);
> +               if (ret)
> +                       goto nest_cancel;
> +               nla_nest_end(msg, attr);
> +       }
> +
> +       return 0;
> +
> +nest_cancel:
> +       nla_nest_end(msg, attr);
> +       return ret;
> +}
> +
> +static int
> +dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin,
> +                         struct dpll_pin_ref *ref, struct
> netlink_ext_ack *extack)
> +{
> +       const struct dpll_pin_properties *prop = pin->prop;
> +       int ret;
> +
> +       if (nla_put_u32(msg, DPLL_A_PIN_ID, pin->id))
> +               return -EMSGSIZE;
> +       if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(pin-
> >module)))
> +               return -EMSGSIZE;
> +       if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(pin-
> >clock_id),
> +                         &pin->clock_id, 0))
> +               return -EMSGSIZE;
> +       if (prop->board_label &&
> +           nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, prop-
> >board_label))
> +               return -EMSGSIZE;
> +       if (prop->panel_label &&
> +           nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, prop-
> >panel_label))
> +               return -EMSGSIZE;
> +       if (prop->package_label &&
> +           nla_put_string(msg, DPLL_A_PIN_PACKAGE_LABEL,
> +                          prop->package_label))
> +               return -EMSGSIZE;
> +       if (nla_put_u8(msg, DPLL_A_PIN_TYPE, prop->type))
> +               return -EMSGSIZE;
> +       if (nla_put_u32(msg, DPLL_A_PIN_DPLL_CAPS, prop-
> >capabilities))
> +               return -EMSGSIZE;
> +       ret = dpll_msg_add_pin_freq(msg, pin, ref, extack, true);
> +       if (ret && ret != -EOPNOTSUPP)
> +               return ret;
> +       return 0;
> +}
> +
> +static int
> +__dpll_cmd_pin_dump_one(struct sk_buff *msg, struct dpll_pin *pin,
> +                       struct netlink_ext_ack *extack)
> +{
> +       struct dpll_pin_ref *ref;
> +       int ret;
> +
> +       ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
> +       if (!ref)
> +               return -EFAULT;
> +       ret = dpll_cmd_pin_fill_details(msg, pin, ref, extack);
> +       if (ret)
> +               return ret;
> +       ret = dpll_msg_add_pin_parents(msg, pin, ref, extack);
> +       if (ret)
> +               return ret;
> +       if (!xa_empty(&pin->dpll_refs)) {
> +               ret = dpll_msg_add_pin_dplls(msg, pin, extack);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
> +                   struct netlink_ext_ack *extack)
> +{
> +       enum dpll_mode mode;
> +       int ret;
> +
> +       ret = dpll_msg_add_dev_handle(msg, dpll);
> +       if (ret)
> +               return ret;
> +       if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(dpll-
> >module)))
> +               return -EMSGSIZE;
> +       if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll-
> >clock_id),
> +                         &dpll->clock_id, 0))
> +               return -EMSGSIZE;
> +       ret = dpll_msg_add_temp(msg, dpll, extack);
> +       if (ret && ret != -EOPNOTSUPP)
> +               return ret;
> +       ret = dpll_msg_add_lock_status(msg, dpll, extack);
> +       if (ret)
> +               return ret;
> +       ret = dpll_msg_add_mode(msg, dpll, extack);
> +       if (ret)
> +               return ret;
> +       for (mode = DPLL_MODE_MANUAL; mode <= DPLL_MODE_MAX; mode++)
> +               if (test_bit(mode, &dpll->mode_supported_mask))
> +                       if (nla_put_s32(msg, DPLL_A_MODE_SUPPORTED,
> mode))
> +                               return -EMSGSIZE;
> +       if (nla_put_u8(msg, DPLL_A_TYPE, dpll->type))
> +               return -EMSGSIZE;
> +
> +       return ret;
> +}
> +
> +static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32
> freq)
> +{
> +       int fs;
> +
> +       for (fs = 0; fs < pin->prop->freq_supported_num; fs++)
> +               if (freq >=  pin->prop->freq_supported[fs].min &&
> +                   freq <=  pin->prop->freq_supported[fs].max)
> +                       return true;
> +       return false;
> +}
> +
> +static int
> +dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
> +                 struct netlink_ext_ack *extack)
> +{
> +       u64 freq = nla_get_u64(a);
> +       struct dpll_pin_ref *ref;
> +       unsigned long i;
> +       int ret;
> +
> +       if (!dpll_pin_is_freq_supported(pin, freq))
> +               return -EINVAL;
> +
> +       xa_for_each(&pin->dpll_refs, i, ref) {
> +               const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
> +               struct dpll_device *dpll = ref->dpll;
> +
> +               if (!ops->frequency_set)
> +                       return -EOPNOTSUPP;
> +               ret = ops->frequency_set(pin,
> dpll_pin_on_dpll_priv(dpll, pin),
> +                                        dpll, dpll_priv(dpll), freq,
> extack);
> +               if (ret)
> +                       return -EFAULT;
> +               __dpll_pin_change_ntf(pin);
> +       }
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
> +                         enum dpll_pin_state state,
> +                         struct netlink_ext_ack *extack)
> +{
> +       struct dpll_pin_ref *parent_ref;
> +       const struct dpll_pin_ops *ops;
> +       struct dpll_pin_ref *dpll_ref;
> +       struct dpll_pin *parent;
> +       unsigned long i;
> +
> +       if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop-
> >capabilities))
> +               return -EOPNOTSUPP;
> +       parent = xa_load(&dpll_pin_xa, parent_idx);
> +       if (!parent)
> +               return -EINVAL;
> +       parent_ref = xa_load(&pin->parent_refs, parent->pin_idx);
> +       if (!parent_ref)
> +               return -EINVAL;
> +       xa_for_each(&parent->dpll_refs, i, dpll_ref) {
> +               ops = dpll_pin_ops(parent_ref);
> +               if (!ops->state_on_pin_set)
> +                       return -EOPNOTSUPP;
> +               if (ops->state_on_pin_set(pin,
> +                                        
> dpll_pin_on_pin_priv(parent, pin),
> +                                         parent,
> +                                        
> dpll_pin_on_dpll_priv(dpll_ref->dpll,
> +                                                               paren
> t),
> +                                         state, extack))
> +                       return -EFAULT;
> +       }
> +       __dpll_pin_change_ntf(pin);
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin,
> +                  enum dpll_pin_state state,
> +                  struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_pin_ops *ops;
> +       struct dpll_pin_ref *ref;
> +
> +       if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop-
> >capabilities))
> +               return -EOPNOTSUPP;
> +       ref = xa_load(&pin->dpll_refs, dpll->device_idx);
> +       if (!ref)
> +               return -EFAULT;
> +       ops = dpll_pin_ops(ref);
> +       if (!ops->state_on_dpll_set)
> +               return -EOPNOTSUPP;
> +       if (ops->state_on_dpll_set(pin, dpll_pin_on_dpll_priv(dpll,
> pin), dpll,
> +                                  dpll_priv(dpll), state, extack))
> +               return -EINVAL;
> +       __dpll_pin_change_ntf(pin);
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin,
> +                 u32 prio, struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_pin_ops *ops;
> +       struct dpll_pin_ref *ref;
> +
> +       if (!(DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE & pin->prop-
> >capabilities))
> +               return -EOPNOTSUPP;
> +       ref = xa_load(&pin->dpll_refs, dpll->device_idx);
> +       if (!ref)
> +               return -EFAULT;
> +       ops = dpll_pin_ops(ref);
> +       if (!ops->prio_set)
> +               return -EOPNOTSUPP;
> +       if (ops->prio_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
> dpll,
> +                         dpll_priv(dpll), prio, extack))
> +               return -EINVAL;
> +       __dpll_pin_change_ntf(pin);
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device
> *dpll,
> +                      enum dpll_pin_direction direction,
> +                      struct netlink_ext_ack *extack)
> +{
> +       const struct dpll_pin_ops *ops;
> +       struct dpll_pin_ref *ref;
> +
> +       if (!(DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE & pin->prop-
> >capabilities))
> +               return -EOPNOTSUPP;
> +
> +       ref = xa_load(&pin->dpll_refs, dpll->device_idx);
> +       if (!ref)
> +               return -EFAULT;
> +       ops = dpll_pin_ops(ref);
> +       if (!ops->direction_set)
> +               return -EOPNOTSUPP;
> +       if (ops->direction_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
> +                              dpll, dpll_priv(dpll), direction,
> +                              extack))
> +               return -EFAULT;
> +       __dpll_pin_change_ntf(pin);
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_pin_parent_set(struct dpll_pin *pin, struct nlattr
> *parent_nest,
> +                   struct netlink_ext_ack *extack)
> +{
> +       struct nlattr *tb[DPLL_A_MAX + 1];
> +       enum dpll_pin_direction direction;
> +       u32 ppin_idx, pdpll_idx, prio;
> +       enum dpll_pin_state state;
> +       struct dpll_pin_ref *ref;
> +       struct dpll_device *dpll;
> +       int ret;
> +
> +       nla_parse_nested(tb, DPLL_A_MAX, parent_nest,
> +                        NULL, extack);
> +       if ((tb[DPLL_A_ID] && tb[DPLL_A_PIN_ID]) ||
> +           !(tb[DPLL_A_ID] || tb[DPLL_A_PIN_ID])) {
> +               NL_SET_ERR_MSG(extack, "one parent id expected");
> +               return -EINVAL;
> +       }
> +       if (tb[DPLL_A_ID]) {
> +               pdpll_idx = nla_get_u32(tb[DPLL_A_ID]);
> +               dpll = xa_load(&dpll_device_xa, pdpll_idx);
> +               if (!dpll)
> +                       return -EINVAL;
> +               ref = xa_load(&pin->dpll_refs, dpll->device_idx);
> +               if (!ref)
> +                       return -EINVAL;
> +               if (tb[DPLL_A_PIN_STATE]) {
> +                       state = nla_get_u8(tb[DPLL_A_PIN_STATE]);
> +                       ret = dpll_pin_state_set(dpll, pin, state,
> extack);
> +                       if (ret)
> +                               return ret;
> +               }
> +               if (tb[DPLL_A_PIN_PRIO]) {
> +                       prio = nla_get_u8(tb[DPLL_A_PIN_PRIO]);
> +                       ret = dpll_pin_prio_set(dpll, pin, prio,
> extack);
> +                       if (ret)
> +                               return ret;
> +               }
> +               if (tb[DPLL_A_PIN_DIRECTION]) {
> +                       direction =
> nla_get_u8(tb[DPLL_A_PIN_DIRECTION]);
> +                       ret = dpll_pin_direction_set(pin, dpll,
> direction,
> +                                                    extack);
> +                       if (ret)
> +                               return ret;
> +               }
> +       } else if (tb[DPLL_A_PIN_ID]) {
> +               ppin_idx = nla_get_u32(tb[DPLL_A_PIN_ID]);
> +               state = nla_get_u8(tb[DPLL_A_PIN_STATE]);
> +               ret = dpll_pin_on_pin_state_set(pin, ppin_idx, state,
> extack);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int
> +dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info
> *info)
> +{
> +       int rem, ret = -EINVAL;
> +       struct nlattr *a;
> +
> +       nla_for_each_attr(a, genlmsg_data(info->genlhdr),
> +                         genlmsg_len(info->genlhdr), rem) {
> +               switch (nla_type(a)) {
> +               case DPLL_A_PIN_FREQUENCY:
> +                       ret = dpll_pin_freq_set(pin, a, info-
> >extack);
> +                       if (ret)
> +                               return ret;
> +                       break;
> +               case DPLL_A_PIN_PARENT:
> +                       ret = dpll_pin_parent_set(pin, a, info-
> >extack);
> +                       if (ret)
> +                               return ret;
> +                       break;
> +               case DPLL_A_PIN_ID:
> +               case DPLL_A_ID:
> +                       break;
> +               default:
> +                       NL_SET_ERR_MSG_FMT(info->extack,
> +                                          "unsupported attribute
> (%d)",
> +                                          nla_type(a));
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static struct dpll_pin *
> +dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr,
> +             enum dpll_pin_type type, struct nlattr *board_label,
> +             struct nlattr *panel_label, struct nlattr
> *package_label)
> +{
> +       bool board_match, panel_match, package_match;
> +       struct dpll_pin *pin_match = NULL, *pin;
> +       const struct dpll_pin_properties *prop;
> +       bool cid_match, mod_match, type_match;
> +       unsigned long i;
> +
> +       xa_for_each(&dpll_pin_xa, i, pin) {
> +               if (xa_empty(&pin->dpll_refs))
> +                       continue;
> +               prop = pin->prop;
> +               cid_match = clock_id ? pin->clock_id == clock_id :
> true;
> +               mod_match = mod_name_attr && module_name(pin->module)
> ?
> +                       !nla_strcmp(mod_name_attr,
> +                                   module_name(pin->module)) : true;
> +               type_match = type ? prop->type == type : true;
> +               board_match = board_label && prop->board_label ?
> +                       !nla_strcmp(board_label, prop->board_label) :
> true;
> +               panel_match = panel_label && prop->panel_label ?
> +                       !nla_strcmp(panel_label, prop->panel_label) :
> true;
> +               package_match = package_label && prop->package_label
> ?
> +                       !nla_strcmp(package_label,
> +                                   prop->package_label) : true;
> +               if (cid_match && mod_match && type_match &&
> board_match &&
> +                   panel_match && package_match) {
> +                       if (pin_match)
> +                               return NULL;
> +                       pin_match = pin;
> +               };
> +       }
> +
> +       return pin_match;
> +}
> +
> +static int
> +dpll_pin_find_from_nlattr(struct genl_info *info, struct sk_buff
> *skb)
> +{
> +       struct nlattr *attr, *mod_name_attr = NULL, *board_label_attr
> = NULL,
> +               *panel_label_attr = NULL, *package_label_attr = NULL;
> +       struct dpll_pin *pin = NULL;
> +       enum dpll_pin_type type = 0;
> +       u64 clock_id = 0;
> +       int rem = 0;
> +
> +       nla_for_each_attr(attr, genlmsg_data(info->genlhdr),
> +                         genlmsg_len(info->genlhdr), rem) {
> +               switch (nla_type(attr)) {
> +               case DPLL_A_CLOCK_ID:
> +                       if (clock_id)
> +                               return -EINVAL;
> +                       clock_id = nla_get_u64(attr);
> +                       break;
> +               case DPLL_A_MODULE_NAME:
> +                       if (mod_name_attr)
> +                               return -EINVAL;
> +                       mod_name_attr = attr;
> +                       break;
> +               case DPLL_A_PIN_TYPE:
> +                       if (type)
> +                               return -EINVAL;
> +                       type = nla_get_u8(attr);
> +                       break;
> +               case DPLL_A_PIN_BOARD_LABEL:
> +                       if (board_label_attr)
> +                               return -EINVAL;
> +                       board_label_attr = attr;
> +                       break;
> +               case DPLL_A_PIN_PANEL_LABEL:
> +                       if (panel_label_attr)
> +                               return -EINVAL;
> +                       panel_label_attr = attr;
> +                       break;
> +               case DPLL_A_PIN_PACKAGE_LABEL:
> +                       if (package_label_attr)
> +                               return -EINVAL;
> +                       package_label_attr = attr;
> +                       break;
> +               default:
> +                       break;
> +               }
> +       }
> +       if (!(clock_id  || mod_name_attr || board_label_attr ||
> +             panel_label_attr || package_label_attr))
> +               return -EINVAL;
> +       pin = dpll_pin_find(clock_id, mod_name_attr, type,
> board_label_attr,
> +                           panel_label_attr, package_label_attr);
> +       if (!pin)
> +               return -EINVAL;
> +       if (nla_put_u32(skb, DPLL_A_PIN_ID, pin->id))
> +               return -EMSGSIZE;
> +       return 0;
> +}
> +
> +int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info
> *info)
> +{
> +       struct sk_buff *msg;
> +       struct nlattr *hdr;
> +       int ret;
> +
> +       msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +       hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
> +                               DPLL_CMD_PIN_ID_GET);
> +       if (!hdr)
> +               return -EMSGSIZE;
> +
> +       ret = dpll_pin_find_from_nlattr(info, msg);
> +       if (ret) {
> +               nlmsg_free(msg);
> +               return ret;
> +       }
> +       genlmsg_end(msg, hdr);
> +
> +       return genlmsg_reply(msg, info);
> +}
> +
> +int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info
> *info)
> +{
> +       struct dpll_pin *pin = info->user_ptr[0];
> +       struct sk_buff *msg;
> +       struct nlattr *hdr;
> +       int ret;
> +
> +       if (!pin)
> +               return -ENODEV;
> +       msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +       hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
> +                               DPLL_CMD_PIN_GET);
> +       if (!hdr)
> +               return -EMSGSIZE;
> +       ret = __dpll_cmd_pin_dump_one(msg, pin, info->extack);
> +       if (ret) {
> +               nlmsg_free(msg);
> +               return ret;
> +       }
> +       genlmsg_end(msg, hdr);
> +
> +       return genlmsg_reply(msg, info);
> +}
> +
> +int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct
> netlink_callback *cb)
> +{
> +       struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
> +       struct dpll_pin *pin;
> +       struct nlattr *hdr;
> +       unsigned long i;
> +       int ret = 0;
> +
> +       xa_for_each_start(&dpll_pin_xa, i, pin, ctx->idx) {
> +               if (xa_empty(&pin->dpll_refs))
> +                       continue;
> +               hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
> +                                 cb->nlh->nlmsg_seq,
> +                                 &dpll_nl_family, NLM_F_MULTI,
> +                                 DPLL_CMD_PIN_GET);
> +               if (!hdr) {
> +                       ret = -EMSGSIZE;
> +                       break;
> +               }
> +               ret = __dpll_cmd_pin_dump_one(skb, pin, cb->extack);
> +               if (ret) {
> +                       genlmsg_cancel(skb, hdr);
> +                       break;
> +               }
> +               genlmsg_end(skb, hdr);
> +       }
> +       if (ret == -EMSGSIZE) {
> +               ctx->idx = i;
> +               return skb->len;
> +       }
> +       return ret;
> +}
> +
> +int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info
> *info)
> +{
> +       struct dpll_pin *pin = info->user_ptr[0];
> +
> +       return dpll_pin_set_from_nlattr(pin, info);
> +}
> +
> +static struct dpll_device *
> +dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr,
> +                enum dpll_type type)
> +{
> +       struct dpll_device *dpll_match = NULL, *dpll;
> +       bool cid_match, mod_match, type_match;
> +       unsigned long i;
> +
> +       xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED)
> {
> +               cid_match = clock_id ? dpll->clock_id == clock_id :
> true;
> +               mod_match = mod_name_attr && module_name(dpll-
> >module) ?
> +                       !nla_strcmp(mod_name_attr,
> +                                   module_name(dpll->module)) :
> true;
> +               type_match = type ? dpll->type == type : true;
> +               if (cid_match && mod_match && type_match) {
> +                       if (dpll_match)
> +                               return NULL;
> +                       dpll_match = dpll;
> +               }
> +       }
> +
> +       return dpll_match;
> +}
> +
> +static int
> +dpll_device_find_from_nlattr(struct genl_info *info, struct sk_buff
> *skb)
> +{
> +       struct nlattr *attr, *mod_name_attr = NULL;
> +       struct dpll_device *dpll = NULL;
> +       enum dpll_type type = 0;
> +       u64 clock_id = 0;
> +       int rem = 0;
> +
> +       nla_for_each_attr(attr, genlmsg_data(info->genlhdr),
> +                         genlmsg_len(info->genlhdr), rem) {
> +               switch (nla_type(attr)) {
> +               case DPLL_A_CLOCK_ID:
> +                       if (clock_id)
> +                               return -EINVAL;
> +                       clock_id = nla_get_u64(attr);
> +                       break;
> +               case DPLL_A_MODULE_NAME:
> +                       if (mod_name_attr)
> +                               return -EINVAL;
> +                       mod_name_attr = attr;
> +                       break;
> +               case DPLL_A_TYPE:
> +                       if (type)
> +                               return -EINVAL;
> +                       type = nla_get_u8(attr);
> +                       break;
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       if (!clock_id && !mod_name_attr && !type)
> +               return -EINVAL;
> +       dpll = dpll_device_find(clock_id, mod_name_attr, type);
> +       if (!dpll)
> +               return -EINVAL;
> +
> +       return dpll_msg_add_dev_handle(skb, dpll);
> +}
> +
> +static int
> +dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info
> *info)
> +{
> +       const struct dpll_device_ops *ops = dpll_device_ops(dpll);
> +       struct nlattr *tb[DPLL_A_MAX + 1];
> +       int ret = 0;
> +
> +       nla_parse(tb, DPLL_A_MAX, genlmsg_data(info->genlhdr),
> +                 genlmsg_len(info->genlhdr), NULL, info->extack);
> +       if (tb[DPLL_A_MODE]) {
Hi,

Here should be something like:
               if (!ops->mode_set)
                       return -EOPNOTSUPP;

Regards,
Petr
> +               ret = ops->mode_set(dpll, dpll_priv(dpll),
> +                                   nla_get_u8(tb[DPLL_A_MODE]),
> info->extack);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info
> *info)
> +{
> +       struct sk_buff *msg;
> +       struct nlattr *hdr;
> +       int ret;
> +
> +       msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +       hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
> +                               DPLL_CMD_DEVICE_ID_GET);
> +       if (!hdr)
> +               return -EMSGSIZE;
> +
> +       ret = dpll_device_find_from_nlattr(info, msg);
> +       if (ret) {
> +               nlmsg_free(msg);
> +               return ret;
> +       }
> +       genlmsg_end(msg, hdr);
> +
> +       return genlmsg_reply(msg, info);
> +}
> +
> +int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info
> *info)
> +{
> +       struct dpll_device *dpll = info->user_ptr[0];
> +       struct sk_buff *msg;
> +       struct nlattr *hdr;
> +       int ret;
> +
> +       msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +       hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
> +                               DPLL_CMD_DEVICE_GET);
> +       if (!hdr)
> +               return -EMSGSIZE;
> +
> +       ret = dpll_device_get_one(dpll, msg, info->extack);
> +       if (ret) {
> +               nlmsg_free(msg);
> +               return ret;
> +       }
> +       genlmsg_end(msg, hdr);
> +
> +       return genlmsg_reply(msg, info);
> +}
> +
> +int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info
> *info)
> +{
> +       struct dpll_device *dpll = info->user_ptr[0];
> +
> +       return dpll_set_from_nlattr(dpll, info);
> +}
> +
> +int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct
> netlink_callback *cb)
> +{
> +       struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
> +       struct dpll_device *dpll;
> +       struct nlattr *hdr;
> +       unsigned long i;
> +       int ret = 0;
> +
> +       xa_for_each_start(&dpll_device_xa, i, dpll, ctx->idx) {
> +               if (!xa_get_mark(&dpll_device_xa, i,
> DPLL_REGISTERED))
> +                       continue;
> +               hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
> +                                 cb->nlh->nlmsg_seq,
> &dpll_nl_family,
> +                                 NLM_F_MULTI, DPLL_CMD_DEVICE_GET);
> +               if (!hdr) {
> +                       ret = -EMSGSIZE;
> +                       break;
> +               }
> +               ret = dpll_device_get_one(dpll, skb, cb->extack);
> +               if (ret) {
> +                       genlmsg_cancel(skb, hdr);
> +                       break;
> +               }
> +               genlmsg_end(skb, hdr);
> +       }
> +       if (ret == -EMSGSIZE) {
> +               ctx->idx = i;
> +               return skb->len;
> +       }
> +       return ret;
> +}
> +
> +int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff
> *skb,
> +                 struct genl_info *info)
> +{
> +       struct dpll_device *dpll_id = NULL;
> +       u32 id;
> +
> +       if (!info->attrs[DPLL_A_ID])
> +               return -EINVAL;
> +
> +       mutex_lock(&dpll_lock);
> +       id = nla_get_u32(info->attrs[DPLL_A_ID]);
> +
> +       dpll_id = dpll_device_get_by_id(id);
> +       if (!dpll_id)
> +               goto unlock;
> +       info->user_ptr[0] = dpll_id;
> +       return 0;
> +unlock:
> +       mutex_unlock(&dpll_lock);
> +       return -ENODEV;
> +}
> +
> +void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff
> *skb,
> +                   struct genl_info *info)
> +{
> +       mutex_unlock(&dpll_lock);
> +}
> +
> +int
> +dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff
> *skb,
> +                    struct genl_info *info)
> +{
> +       mutex_lock(&dpll_lock);
> +
> +       return 0;
> +}
> +
> +void
> +dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff
> *skb,
> +                  struct genl_info *info)
> +{
> +       mutex_unlock(&dpll_lock);
> +}
> +
> +int dpll_lock_dumpit(struct netlink_callback *cb)
> +{
> +       mutex_lock(&dpll_lock);
> +
> +       return 0;
> +}
> +
> +int dpll_unlock_dumpit(struct netlink_callback *cb)
> +{
> +       mutex_unlock(&dpll_lock);
> +
> +       return 0;
> +}
> +
> +int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct
> sk_buff *skb,
> +                     struct genl_info *info)
> +{
> +       int ret;
> +
> +       mutex_lock(&dpll_lock);
> +       if (!info->attrs[DPLL_A_PIN_ID]) {
> +               ret = -EINVAL;
> +               goto unlock_dev;
> +       }
> +       info->user_ptr[0] = xa_load(&dpll_pin_xa,
> +                                   nla_get_u32(info-
> >attrs[DPLL_A_PIN_ID]));
> +       if (!info->user_ptr[0]) {
> +               ret = -ENODEV;
> +               goto unlock_dev;
> +       }
> +
> +       return 0;
> +
> +unlock_dev:
> +       mutex_unlock(&dpll_lock);
> +       return ret;
> +}
> +
> +void dpll_pin_post_doit(const struct genl_split_ops *ops, struct
> sk_buff *skb,
> +                       struct genl_info *info)
> +{
> +       mutex_unlock(&dpll_lock);
> +}
> +
> +static int
> +dpll_device_event_send(enum dpll_cmd event, struct dpll_device
> *dpll)
> +{
> +       struct sk_buff *msg;
> +       int ret = -EMSGSIZE;
> +       void *hdr;
> +
> +       if (!xa_get_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED))
> +               return -ENODEV;
> +
> +       msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +       hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event);
> +       if (!hdr)
> +               goto out_free_msg;
> +       ret = dpll_device_get_one(dpll, msg, NULL);
> +       if (ret)
> +               goto out_cancel_msg;
> +       genlmsg_end(msg, hdr);
> +       genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL);
> +
> +       return 0;
> +
> +out_cancel_msg:
> +       genlmsg_cancel(msg, hdr);
> +out_free_msg:
> +       nlmsg_free(msg);
> +
> +       return ret;
> +}
> +
> +int dpll_device_create_ntf(struct dpll_device *dpll)
> +{
> +       return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF,
> dpll);
> +}
> +
> +int dpll_device_delete_ntf(struct dpll_device *dpll)
> +{
> +       return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF,
> dpll);
> +}
> +
> +int dpll_device_change_ntf(struct dpll_device *dpll)
> +{
> +       int ret = -EINVAL;
> +
> +       if (WARN_ON(!dpll))
> +               return ret;
> +
> +       mutex_lock(&dpll_lock);
> +       ret = dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF,
> dpll);
> +       mutex_unlock(&dpll_lock);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(dpll_device_change_ntf);
> +
> +static int
> +dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin)
> +{
> +       struct dpll_pin *pin_verify;
> +       struct sk_buff *msg;
> +       int ret = -EMSGSIZE;
> +       void *hdr;
> +
> +       pin_verify = xa_load(&dpll_pin_xa, pin->id);
> +       if (pin != pin_verify)
> +               return -ENODEV;
> +
> +       msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +
> +       hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event);
> +       if (!hdr)
> +               goto out_free_msg;
> +       ret = __dpll_cmd_pin_dump_one(msg, pin, NULL);
> +       if (ret)
> +               goto out_cancel_msg;
> +       genlmsg_end(msg, hdr);
> +       genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL);
> +
> +       return 0;
> +
> +out_cancel_msg:
> +       genlmsg_cancel(msg, hdr);
> +out_free_msg:
> +       nlmsg_free(msg);
> +
> +       return ret;
> +}
> +
> +int dpll_pin_create_ntf(struct dpll_pin *pin)
> +{
> +       return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin);
> +}
> +
> +int dpll_pin_delete_ntf(struct dpll_pin *pin)
> +{
> +       return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin);
> +}
> +
> +static int __dpll_pin_change_ntf(struct dpll_pin *pin)
> +{
> +       return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin);
> +}
> +
> +int dpll_pin_change_ntf(struct dpll_pin *pin)
> +{
> +       int ret = -EINVAL;
> +
> +       if (WARN_ON(!pin))
> +               return ret;
> +
> +       mutex_lock(&dpll_lock);
> +       ret = __dpll_pin_change_ntf(pin);
> +       mutex_unlock(&dpll_lock);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(dpll_pin_change_ntf);
> +
> +int __init dpll_netlink_init(void)
> +{
> +       return genl_register_family(&dpll_nl_family);
> +}
> +
> +void dpll_netlink_finish(void)
> +{
> +       genl_unregister_family(&dpll_nl_family);
> +}
> +
> +void __exit dpll_netlink_fini(void)
> +{
> +       dpll_netlink_finish();
> +}
> diff --git a/drivers/dpll/dpll_netlink.h
> b/drivers/dpll/dpll_netlink.h
> new file mode 100644
> index 000000000000..b5f9bfc88c9e
> --- /dev/null
> +++ b/drivers/dpll/dpll_netlink.h
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + *  Copyright (c) 2023 Meta Platforms, Inc. and affiliates
> + *  Copyright (c) 2023 Intel and affiliates
> + */
> +
> +/**
> + * dpll_device_create_ntf - notify that the device has been created
> + * @dpll: registered dpll pointer
> + *
> + * Context: caller shall hold dpll_xa_lock.
> + * Return: 0 if succeeds, error code otherwise.
> + */
> +int dpll_device_create_ntf(struct dpll_device *dpll);
> +
> +/**
> + * dpll_device_delete_ntf - notify that the device has been deleted
> + * @dpll: registered dpll pointer
> + *
> + * Context: caller shall hold dpll_xa_lock.
> + * Return: 0 if succeeds, error code otherwise.
> + */
> +int dpll_device_delete_ntf(struct dpll_device *dpll);
> +
> +/**
> + * dpll_pin_create_ntf - notify that the pin has been created
> + * @pin: registered pin pointer
> + *
> + * Context: caller shall hold dpll_xa_lock.
> + * Return: 0 if succeeds, error code otherwise.
> + */
> +int dpll_pin_create_ntf(struct dpll_pin *pin);
> +
> +/**
> + * dpll_pin_delete_ntf - notify that the pin has been deleted
> + * @pin: registered pin pointer
> + *
> + * Context: caller shall hold dpll_xa_lock.
> + * Return: 0 if succeeds, error code otherwise.
> + */
> +int dpll_pin_delete_ntf(struct dpll_pin *pin);
> +
> +int __init dpll_netlink_init(void);
> +void dpll_netlink_finish(void);

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ