File Index
Files and directories
Sign in
FILE

dpll_netlink.c

File preview with syntax highlighting.

linux-6.19.14/drivers/dpll/dpll_netlink.c 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 <linux/netdevice.h>
  12#include <net/genetlink.h>
  13#include "dpll_core.h"
  14#include "dpll_netlink.h"
  15#include "dpll_nl.h"
  16#include <uapi/linux/dpll.h>
  17
  18#define ASSERT_NOT_NULL(ptr)	(WARN_ON(!ptr))
  19
  20#define xa_for_each_marked_start(xa, index, entry, filter, start) \
  21	for (index = start, entry = xa_find(xa, &index, ULONG_MAX, filter); \
  22	     entry; entry = xa_find_after(xa, &index, ULONG_MAX, filter))
  23
  24struct dpll_dump_ctx {
  25	unsigned long idx;
  26};
  27
  28static struct dpll_dump_ctx *dpll_dump_context(struct netlink_callback *cb)
  29{
  30	return (struct dpll_dump_ctx *)cb->ctx;
  31}
  32
  33static int
  34dpll_msg_add_dev_handle(struct sk_buff *msg, struct dpll_device *dpll)
  35{
  36	if (nla_put_u32(msg, DPLL_A_ID, dpll->id))
  37		return -EMSGSIZE;
  38
  39	return 0;
  40}
  41
  42static int
  43dpll_msg_add_dev_parent_handle(struct sk_buff *msg, u32 id)
  44{
  45	if (nla_put_u32(msg, DPLL_A_PIN_PARENT_ID, id))
  46		return -EMSGSIZE;
  47
  48	return 0;
  49}
  50
  51static bool dpll_pin_available(struct dpll_pin *pin)
  52{
  53	struct dpll_pin_ref *par_ref;
  54	unsigned long i;
  55
  56	if (!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED))
  57		return false;
  58	xa_for_each(&pin->parent_refs, i, par_ref)
  59		if (xa_get_mark(&dpll_pin_xa, par_ref->pin->id,
  60				DPLL_REGISTERED))
  61			return true;
  62	xa_for_each(&pin->dpll_refs, i, par_ref)
  63		if (xa_get_mark(&dpll_device_xa, par_ref->dpll->id,
  64				DPLL_REGISTERED))
  65			return true;
  66	return false;
  67}
  68
  69/**
  70 * dpll_msg_add_pin_handle - attach pin handle attribute to a given message
  71 * @msg: pointer to sk_buff message to attach a pin handle
  72 * @pin: pin pointer
  73 *
  74 * Return:
  75 * * 0 - success
  76 * * -EMSGSIZE - no space in message to attach pin handle
  77 */
  78static int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin)
  79{
  80	if (!pin)
  81		return 0;
  82	if (nla_put_u32(msg, DPLL_A_PIN_ID, pin->id))
  83		return -EMSGSIZE;
  84	return 0;
  85}
  86
  87static struct dpll_pin *dpll_netdev_pin(const struct net_device *dev)
  88{
  89	return rcu_dereference_rtnl(dev->dpll_pin);
  90}
  91
  92/**
  93 * dpll_netdev_pin_handle_size - get size of pin handle attribute of a netdev
  94 * @dev: netdev from which to get the pin
  95 *
  96 * Return: byte size of pin handle attribute, or 0 if @dev has no pin.
  97 */
  98size_t dpll_netdev_pin_handle_size(const struct net_device *dev)
  99{
 100	return dpll_netdev_pin(dev) ? nla_total_size(4) : 0; /* DPLL_A_PIN_ID */
 101}
 102
 103int dpll_netdev_add_pin_handle(struct sk_buff *msg,
 104			       const struct net_device *dev)
 105{
 106	return dpll_msg_add_pin_handle(msg, dpll_netdev_pin(dev));
 107}
 108
 109static int
 110dpll_msg_add_mode(struct sk_buff *msg, struct dpll_device *dpll,
 111		  struct netlink_ext_ack *extack)
 112{
 113	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 114	enum dpll_mode mode;
 115	int ret;
 116
 117	ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack);
 118	if (ret)
 119		return ret;
 120	if (nla_put_u32(msg, DPLL_A_MODE, mode))
 121		return -EMSGSIZE;
 122
 123	return 0;
 124}
 125
 126static int
 127dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll,
 128			    struct netlink_ext_ack *extack)
 129{
 130	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 131	enum dpll_mode mode;
 132	int ret;
 133
 134	/* No mode change is supported now, so the only supported mode is the
 135	 * one obtained by mode_get().
 136	 */
 137
 138	ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack);
 139	if (ret)
 140		return ret;
 141	if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode))
 142		return -EMSGSIZE;
 143
 144	return 0;
 145}
 146
 147static int
 148dpll_msg_add_phase_offset_monitor(struct sk_buff *msg, struct dpll_device *dpll,
 149				  struct netlink_ext_ack *extack)
 150{
 151	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 152	enum dpll_feature_state state;
 153	int ret;
 154
 155	if (ops->phase_offset_monitor_set && ops->phase_offset_monitor_get) {
 156		ret = ops->phase_offset_monitor_get(dpll, dpll_priv(dpll),
 157						    &state, extack);
 158		if (ret)
 159			return ret;
 160		if (nla_put_u32(msg, DPLL_A_PHASE_OFFSET_MONITOR, state))
 161			return -EMSGSIZE;
 162	}
 163
 164	return 0;
 165}
 166
 167static int
 168dpll_msg_add_phase_offset_avg_factor(struct sk_buff *msg,
 169				     struct dpll_device *dpll,
 170				     struct netlink_ext_ack *extack)
 171{
 172	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 173	u32 factor;
 174	int ret;
 175
 176	if (ops->phase_offset_avg_factor_get) {
 177		ret = ops->phase_offset_avg_factor_get(dpll, dpll_priv(dpll),
 178						       &factor, extack);
 179		if (ret)
 180			return ret;
 181		if (nla_put_u32(msg, DPLL_A_PHASE_OFFSET_AVG_FACTOR, factor))
 182			return -EMSGSIZE;
 183	}
 184
 185	return 0;
 186}
 187
 188static int
 189dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll,
 190			 struct netlink_ext_ack *extack)
 191{
 192	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 193	enum dpll_lock_status_error status_error = 0;
 194	enum dpll_lock_status status;
 195	int ret;
 196
 197	ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status,
 198				   &status_error, extack);
 199	if (ret)
 200		return ret;
 201	if (nla_put_u32(msg, DPLL_A_LOCK_STATUS, status))
 202		return -EMSGSIZE;
 203	if (status_error &&
 204	    (status == DPLL_LOCK_STATUS_UNLOCKED ||
 205	     status == DPLL_LOCK_STATUS_HOLDOVER) &&
 206	    nla_put_u32(msg, DPLL_A_LOCK_STATUS_ERROR, status_error))
 207		return -EMSGSIZE;
 208
 209	return 0;
 210}
 211
 212static int
 213dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll,
 214		  struct netlink_ext_ack *extack)
 215{
 216	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 217	s32 temp;
 218	int ret;
 219
 220	if (!ops->temp_get)
 221		return 0;
 222	ret = ops->temp_get(dpll, dpll_priv(dpll), &temp, extack);
 223	if (ret)
 224		return ret;
 225	if (nla_put_s32(msg, DPLL_A_TEMP, temp))
 226		return -EMSGSIZE;
 227
 228	return 0;
 229}
 230
 231static int
 232dpll_msg_add_clock_quality_level(struct sk_buff *msg, struct dpll_device *dpll,
 233				 struct netlink_ext_ack *extack)
 234{
 235	DECLARE_BITMAP(qls, DPLL_CLOCK_QUALITY_LEVEL_MAX + 1) = { 0 };
 236	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 237	enum dpll_clock_quality_level ql;
 238	int ret;
 239
 240	if (!ops->clock_quality_level_get)
 241		return 0;
 242	ret = ops->clock_quality_level_get(dpll, dpll_priv(dpll), qls, extack);
 243	if (ret)
 244		return ret;
 245	for_each_set_bit(ql, qls, DPLL_CLOCK_QUALITY_LEVEL_MAX + 1)
 246		if (nla_put_u32(msg, DPLL_A_CLOCK_QUALITY_LEVEL, ql))
 247			return -EMSGSIZE;
 248
 249	return 0;
 250}
 251
 252static int
 253dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin,
 254		      struct dpll_pin_ref *ref,
 255		      struct netlink_ext_ack *extack)
 256{
 257	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 258	struct dpll_device *dpll = ref->dpll;
 259	u32 prio;
 260	int ret;
 261
 262	if (!ops->prio_get)
 263		return 0;
 264	ret = ops->prio_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 265			    dpll_priv(dpll), &prio, extack);
 266	if (ret)
 267		return ret;
 268	if (nla_put_u32(msg, DPLL_A_PIN_PRIO, prio))
 269		return -EMSGSIZE;
 270
 271	return 0;
 272}
 273
 274static int
 275dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin,
 276			       struct dpll_pin_ref *ref,
 277			       struct netlink_ext_ack *extack)
 278{
 279	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 280	struct dpll_device *dpll = ref->dpll;
 281	enum dpll_pin_state state;
 282	int ret;
 283
 284	if (!ops->state_on_dpll_get)
 285		return 0;
 286	ret = ops->state_on_dpll_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 287				     dpll, dpll_priv(dpll), &state, extack);
 288	if (ret)
 289		return ret;
 290	if (nla_put_u32(msg, DPLL_A_PIN_STATE, state))
 291		return -EMSGSIZE;
 292
 293	return 0;
 294}
 295
 296static int
 297dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin,
 298			   struct dpll_pin_ref *ref,
 299			   struct netlink_ext_ack *extack)
 300{
 301	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 302	struct dpll_device *dpll = ref->dpll;
 303	enum dpll_pin_direction direction;
 304	int ret;
 305
 306	ret = ops->direction_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 307				 dpll_priv(dpll), &direction, extack);
 308	if (ret)
 309		return ret;
 310	if (nla_put_u32(msg, DPLL_A_PIN_DIRECTION, direction))
 311		return -EMSGSIZE;
 312
 313	return 0;
 314}
 315
 316static int
 317dpll_msg_add_pin_phase_adjust(struct sk_buff *msg, struct dpll_pin *pin,
 318			      struct dpll_pin_ref *ref,
 319			      struct netlink_ext_ack *extack)
 320{
 321	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 322	struct dpll_device *dpll = ref->dpll;
 323	s32 phase_adjust;
 324	int ret;
 325
 326	if (!ops->phase_adjust_get)
 327		return 0;
 328	ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 329				    dpll, dpll_priv(dpll),
 330				    &phase_adjust, extack);
 331	if (ret)
 332		return ret;
 333	if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST, phase_adjust))
 334		return -EMSGSIZE;
 335
 336	return 0;
 337}
 338
 339static int
 340dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin,
 341			  struct dpll_pin_ref *ref,
 342			  struct netlink_ext_ack *extack)
 343{
 344	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 345	struct dpll_device *dpll = ref->dpll;
 346	s64 phase_offset;
 347	int ret;
 348
 349	if (!ops->phase_offset_get)
 350		return 0;
 351	ret = ops->phase_offset_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 352				    dpll, dpll_priv(dpll), &phase_offset,
 353				    extack);
 354	if (ret)
 355		return ret;
 356	if (nla_put_64bit(msg, DPLL_A_PIN_PHASE_OFFSET, sizeof(phase_offset),
 357			  &phase_offset, DPLL_A_PIN_PAD))
 358		return -EMSGSIZE;
 359
 360	return 0;
 361}
 362
 363static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin,
 364			    struct dpll_pin_ref *ref,
 365			    struct netlink_ext_ack *extack)
 366{
 367	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 368	struct dpll_device *dpll = ref->dpll;
 369	s64 ffo;
 370	int ret;
 371
 372	if (!ops->ffo_get)
 373		return 0;
 374	ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 375			   dpll, dpll_priv(dpll), &ffo, extack);
 376	if (ret) {
 377		if (ret == -ENODATA)
 378			return 0;
 379		return ret;
 380	}
 381	return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, ffo);
 382}
 383
 384static int
 385dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
 386		      struct dpll_pin_ref *ref, struct netlink_ext_ack *extack)
 387{
 388	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 389	struct dpll_device *dpll = ref->dpll;
 390	struct nlattr *nest;
 391	int fs, ret;
 392	u64 freq;
 393
 394	if (!ops->frequency_get)
 395		return 0;
 396	ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 397				 dpll_priv(dpll), &freq, extack);
 398	if (ret)
 399		return ret;
 400	if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq,
 401			  DPLL_A_PIN_PAD))
 402		return -EMSGSIZE;
 403	for (fs = 0; fs < pin->prop.freq_supported_num; fs++) {
 404		nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED);
 405		if (!nest)
 406			return -EMSGSIZE;
 407		freq = pin->prop.freq_supported[fs].min;
 408		if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq),
 409				  &freq, DPLL_A_PIN_PAD)) {
 410			nla_nest_cancel(msg, nest);
 411			return -EMSGSIZE;
 412		}
 413		freq = pin->prop.freq_supported[fs].max;
 414		if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq),
 415				  &freq, DPLL_A_PIN_PAD)) {
 416			nla_nest_cancel(msg, nest);
 417			return -EMSGSIZE;
 418		}
 419		nla_nest_end(msg, nest);
 420	}
 421
 422	return 0;
 423}
 424
 425static int
 426dpll_msg_add_pin_esync(struct sk_buff *msg, struct dpll_pin *pin,
 427		       struct dpll_pin_ref *ref, struct netlink_ext_ack *extack)
 428{
 429	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 430	struct dpll_device *dpll = ref->dpll;
 431	struct dpll_pin_esync esync;
 432	struct nlattr *nest;
 433	int ret, i;
 434
 435	if (!ops->esync_get)
 436		return 0;
 437	ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 438			     dpll_priv(dpll), &esync, extack);
 439	if (ret == -EOPNOTSUPP)
 440		return 0;
 441	else if (ret)
 442		return ret;
 443	if (nla_put_64bit(msg, DPLL_A_PIN_ESYNC_FREQUENCY, sizeof(esync.freq),
 444			  &esync.freq, DPLL_A_PIN_PAD))
 445		return -EMSGSIZE;
 446	if (nla_put_u32(msg, DPLL_A_PIN_ESYNC_PULSE, esync.pulse))
 447		return -EMSGSIZE;
 448	for (i = 0; i < esync.range_num; i++) {
 449		nest = nla_nest_start(msg,
 450				      DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED);
 451		if (!nest)
 452			return -EMSGSIZE;
 453		if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN,
 454				  sizeof(esync.range[i].min),
 455				  &esync.range[i].min, DPLL_A_PIN_PAD))
 456			goto nest_cancel;
 457		if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX,
 458				  sizeof(esync.range[i].max),
 459				  &esync.range[i].max, DPLL_A_PIN_PAD))
 460			goto nest_cancel;
 461		nla_nest_end(msg, nest);
 462	}
 463	return 0;
 464
 465nest_cancel:
 466	nla_nest_cancel(msg, nest);
 467	return -EMSGSIZE;
 468}
 469
 470static int
 471dpll_msg_add_pin_ref_sync(struct sk_buff *msg, struct dpll_pin *pin,
 472			  struct dpll_pin_ref *ref,
 473			  struct netlink_ext_ack *extack)
 474{
 475	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 476	struct dpll_device *dpll = ref->dpll;
 477	void *pin_priv, *ref_sync_pin_priv;
 478	struct dpll_pin *ref_sync_pin;
 479	enum dpll_pin_state state;
 480	struct nlattr *nest;
 481	unsigned long index;
 482	int ret;
 483
 484	pin_priv = dpll_pin_on_dpll_priv(dpll, pin);
 485	xa_for_each(&pin->ref_sync_pins, index, ref_sync_pin) {
 486		if (!dpll_pin_available(ref_sync_pin))
 487			continue;
 488		ref_sync_pin_priv = dpll_pin_on_dpll_priv(dpll, ref_sync_pin);
 489		if (WARN_ON(!ops->ref_sync_get))
 490			return -EOPNOTSUPP;
 491		ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin,
 492					ref_sync_pin_priv, &state, extack);
 493		if (ret)
 494			return ret;
 495		nest = nla_nest_start(msg, DPLL_A_PIN_REFERENCE_SYNC);
 496		if (!nest)
 497			return -EMSGSIZE;
 498		if (nla_put_s32(msg, DPLL_A_PIN_ID, ref_sync_pin->id))
 499			goto nest_cancel;
 500		if (nla_put_s32(msg, DPLL_A_PIN_STATE, state))
 501			goto nest_cancel;
 502		nla_nest_end(msg, nest);
 503	}
 504	return 0;
 505
 506nest_cancel:
 507	nla_nest_cancel(msg, nest);
 508	return -EMSGSIZE;
 509}
 510
 511static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq)
 512{
 513	int fs;
 514
 515	for (fs = 0; fs < pin->prop.freq_supported_num; fs++)
 516		if (freq >= pin->prop.freq_supported[fs].min &&
 517		    freq <= pin->prop.freq_supported[fs].max)
 518			return true;
 519	return false;
 520}
 521
 522static int
 523dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin,
 524			 struct dpll_pin_ref *dpll_ref,
 525			 struct netlink_ext_ack *extack)
 526{
 527	enum dpll_pin_state state;
 528	struct dpll_pin_ref *ref;
 529	struct dpll_pin *ppin;
 530	struct nlattr *nest;
 531	unsigned long index;
 532	int ret;
 533
 534	xa_for_each(&pin->parent_refs, index, ref) {
 535		const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 536		void *parent_priv;
 537
 538		ppin = ref->pin;
 539		parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, ppin);
 540		ret = ops->state_on_pin_get(pin,
 541					    dpll_pin_on_pin_priv(ppin, pin),
 542					    ppin, parent_priv, &state, extack);
 543		if (ret)
 544			return ret;
 545		nest = nla_nest_start(msg, DPLL_A_PIN_PARENT_PIN);
 546		if (!nest)
 547			return -EMSGSIZE;
 548		ret = dpll_msg_add_dev_parent_handle(msg, ppin->id);
 549		if (ret)
 550			goto nest_cancel;
 551		if (nla_put_u32(msg, DPLL_A_PIN_STATE, state)) {
 552			ret = -EMSGSIZE;
 553			goto nest_cancel;
 554		}
 555		nla_nest_end(msg, nest);
 556	}
 557
 558	return 0;
 559
 560nest_cancel:
 561	nla_nest_cancel(msg, nest);
 562	return ret;
 563}
 564
 565static int
 566dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
 567		       struct netlink_ext_ack *extack)
 568{
 569	struct dpll_pin_ref *ref;
 570	struct nlattr *attr;
 571	unsigned long index;
 572	int ret;
 573
 574	xa_for_each(&pin->dpll_refs, index, ref) {
 575		attr = nla_nest_start(msg, DPLL_A_PIN_PARENT_DEVICE);
 576		if (!attr)
 577			return -EMSGSIZE;
 578		ret = dpll_msg_add_dev_parent_handle(msg, ref->dpll->id);
 579		if (ret)
 580			goto nest_cancel;
 581		ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack);
 582		if (ret)
 583			goto nest_cancel;
 584		ret = dpll_msg_add_pin_prio(msg, pin, ref, extack);
 585		if (ret)
 586			goto nest_cancel;
 587		ret = dpll_msg_add_pin_direction(msg, pin, ref, extack);
 588		if (ret)
 589			goto nest_cancel;
 590		ret = dpll_msg_add_phase_offset(msg, pin, ref, extack);
 591		if (ret)
 592			goto nest_cancel;
 593		nla_nest_end(msg, attr);
 594	}
 595
 596	return 0;
 597
 598nest_cancel:
 599	nla_nest_end(msg, attr);
 600	return ret;
 601}
 602
 603static int
 604dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
 605		     struct netlink_ext_ack *extack)
 606{
 607	const struct dpll_pin_properties *prop = &pin->prop;
 608	struct dpll_pin_ref *ref;
 609	int ret;
 610
 611	ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
 612	ASSERT_NOT_NULL(ref);
 613
 614	ret = dpll_msg_add_pin_handle(msg, pin);
 615	if (ret)
 616		return ret;
 617	if (nla_put_string(msg, DPLL_A_PIN_MODULE_NAME,
 618			   module_name(pin->module)))
 619		return -EMSGSIZE;
 620	if (nla_put_64bit(msg, DPLL_A_PIN_CLOCK_ID, sizeof(pin->clock_id),
 621			  &pin->clock_id, DPLL_A_PIN_PAD))
 622		return -EMSGSIZE;
 623	if (prop->board_label &&
 624	    nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, prop->board_label))
 625		return -EMSGSIZE;
 626	if (prop->panel_label &&
 627	    nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, prop->panel_label))
 628		return -EMSGSIZE;
 629	if (prop->package_label &&
 630	    nla_put_string(msg, DPLL_A_PIN_PACKAGE_LABEL,
 631			   prop->package_label))
 632		return -EMSGSIZE;
 633	if (nla_put_u32(msg, DPLL_A_PIN_TYPE, prop->type))
 634		return -EMSGSIZE;
 635	if (nla_put_u32(msg, DPLL_A_PIN_CAPABILITIES, prop->capabilities))
 636		return -EMSGSIZE;
 637	ret = dpll_msg_add_pin_freq(msg, pin, ref, extack);
 638	if (ret)
 639		return ret;
 640	if (prop->phase_gran &&
 641	    nla_put_u32(msg, DPLL_A_PIN_PHASE_ADJUST_GRAN,
 642			prop->phase_gran))
 643		return -EMSGSIZE;
 644	if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MIN,
 645			prop->phase_range.min))
 646		return -EMSGSIZE;
 647	if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MAX,
 648			prop->phase_range.max))
 649		return -EMSGSIZE;
 650	ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
 651	if (ret)
 652		return ret;
 653	ret = dpll_msg_add_ffo(msg, pin, ref, extack);
 654	if (ret)
 655		return ret;
 656	ret = dpll_msg_add_pin_esync(msg, pin, ref, extack);
 657	if (ret)
 658		return ret;
 659	if (!xa_empty(&pin->ref_sync_pins))
 660		ret = dpll_msg_add_pin_ref_sync(msg, pin, ref, extack);
 661	if (ret)
 662		return ret;
 663	if (xa_empty(&pin->parent_refs))
 664		ret = dpll_msg_add_pin_dplls(msg, pin, extack);
 665	else
 666		ret = dpll_msg_add_pin_parents(msg, pin, ref, extack);
 667
 668	return ret;
 669}
 670
 671static int
 672dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
 673		    struct netlink_ext_ack *extack)
 674{
 675	int ret;
 676
 677	ret = dpll_msg_add_dev_handle(msg, dpll);
 678	if (ret)
 679		return ret;
 680	if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(dpll->module)))
 681		return -EMSGSIZE;
 682	if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id),
 683			  &dpll->clock_id, DPLL_A_PAD))
 684		return -EMSGSIZE;
 685	ret = dpll_msg_add_temp(msg, dpll, extack);
 686	if (ret)
 687		return ret;
 688	ret = dpll_msg_add_lock_status(msg, dpll, extack);
 689	if (ret)
 690		return ret;
 691	ret = dpll_msg_add_clock_quality_level(msg, dpll, extack);
 692	if (ret)
 693		return ret;
 694	ret = dpll_msg_add_mode(msg, dpll, extack);
 695	if (ret)
 696		return ret;
 697	ret = dpll_msg_add_mode_supported(msg, dpll, extack);
 698	if (ret)
 699		return ret;
 700	if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type))
 701		return -EMSGSIZE;
 702	ret = dpll_msg_add_phase_offset_monitor(msg, dpll, extack);
 703	if (ret)
 704		return ret;
 705	ret = dpll_msg_add_phase_offset_avg_factor(msg, dpll, extack);
 706	if (ret)
 707		return ret;
 708
 709	return 0;
 710}
 711
 712static int
 713dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll)
 714{
 715	struct sk_buff *msg;
 716	int ret = -ENOMEM;
 717	void *hdr;
 718
 719	if (WARN_ON(!xa_get_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED)))
 720		return -ENODEV;
 721	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 722	if (!msg)
 723		return -ENOMEM;
 724	hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event);
 725	if (!hdr)
 726		goto err_free_msg;
 727	ret = dpll_device_get_one(dpll, msg, NULL);
 728	if (ret)
 729		goto err_cancel_msg;
 730	genlmsg_end(msg, hdr);
 731	genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL);
 732
 733	return 0;
 734
 735err_cancel_msg:
 736	genlmsg_cancel(msg, hdr);
 737err_free_msg:
 738	nlmsg_free(msg);
 739
 740	return ret;
 741}
 742
 743int dpll_device_create_ntf(struct dpll_device *dpll)
 744{
 745	return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF, dpll);
 746}
 747
 748int dpll_device_delete_ntf(struct dpll_device *dpll)
 749{
 750	return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll);
 751}
 752
 753static int
 754__dpll_device_change_ntf(struct dpll_device *dpll)
 755{
 756	return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll);
 757}
 758
 759/**
 760 * dpll_device_change_ntf - notify that the dpll device has been changed
 761 * @dpll: registered dpll pointer
 762 *
 763 * Context: acquires and holds a dpll_lock.
 764 * Return: 0 if succeeds, error code otherwise.
 765 */
 766int dpll_device_change_ntf(struct dpll_device *dpll)
 767{
 768	int ret;
 769
 770	mutex_lock(&dpll_lock);
 771	ret = __dpll_device_change_ntf(dpll);
 772	mutex_unlock(&dpll_lock);
 773
 774	return ret;
 775}
 776EXPORT_SYMBOL_GPL(dpll_device_change_ntf);
 777
 778static int
 779dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin)
 780{
 781	struct sk_buff *msg;
 782	int ret = -ENOMEM;
 783	void *hdr;
 784
 785	if (!dpll_pin_available(pin))
 786		return -ENODEV;
 787
 788	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 789	if (!msg)
 790		return -ENOMEM;
 791
 792	hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event);
 793	if (!hdr)
 794		goto err_free_msg;
 795	ret = dpll_cmd_pin_get_one(msg, pin, NULL);
 796	if (ret)
 797		goto err_cancel_msg;
 798	genlmsg_end(msg, hdr);
 799	genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL);
 800
 801	return 0;
 802
 803err_cancel_msg:
 804	genlmsg_cancel(msg, hdr);
 805err_free_msg:
 806	nlmsg_free(msg);
 807
 808	return ret;
 809}
 810
 811int dpll_pin_create_ntf(struct dpll_pin *pin)
 812{
 813	return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin);
 814}
 815
 816int dpll_pin_delete_ntf(struct dpll_pin *pin)
 817{
 818	return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin);
 819}
 820
 821int __dpll_pin_change_ntf(struct dpll_pin *pin)
 822{
 823	return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin);
 824}
 825
 826/**
 827 * dpll_pin_change_ntf - notify that the pin has been changed
 828 * @pin: registered pin pointer
 829 *
 830 * Context: acquires and holds a dpll_lock.
 831 * Return: 0 if succeeds, error code otherwise.
 832 */
 833int dpll_pin_change_ntf(struct dpll_pin *pin)
 834{
 835	int ret;
 836
 837	mutex_lock(&dpll_lock);
 838	ret = __dpll_pin_change_ntf(pin);
 839	mutex_unlock(&dpll_lock);
 840
 841	return ret;
 842}
 843EXPORT_SYMBOL_GPL(dpll_pin_change_ntf);
 844
 845static int
 846dpll_phase_offset_monitor_set(struct dpll_device *dpll, struct nlattr *a,
 847			      struct netlink_ext_ack *extack)
 848{
 849	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 850	enum dpll_feature_state state = nla_get_u32(a), old_state;
 851	int ret;
 852
 853	if (!(ops->phase_offset_monitor_set && ops->phase_offset_monitor_get)) {
 854		NL_SET_ERR_MSG_ATTR(extack, a, "dpll device not capable of phase offset monitor");
 855		return -EOPNOTSUPP;
 856	}
 857	ret = ops->phase_offset_monitor_get(dpll, dpll_priv(dpll), &old_state,
 858					    extack);
 859	if (ret) {
 860		NL_SET_ERR_MSG(extack, "unable to get current state of phase offset monitor");
 861		return ret;
 862	}
 863	if (state == old_state)
 864		return 0;
 865
 866	return ops->phase_offset_monitor_set(dpll, dpll_priv(dpll), state,
 867					     extack);
 868}
 869
 870static int
 871dpll_phase_offset_avg_factor_set(struct dpll_device *dpll, struct nlattr *a,
 872				 struct netlink_ext_ack *extack)
 873{
 874	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 875	u32 factor = nla_get_u32(a);
 876
 877	if (!ops->phase_offset_avg_factor_set) {
 878		NL_SET_ERR_MSG_ATTR(extack, a,
 879				    "device not capable of changing phase offset average factor");
 880		return -EOPNOTSUPP;
 881	}
 882
 883	return ops->phase_offset_avg_factor_set(dpll, dpll_priv(dpll), factor,
 884						extack);
 885}
 886
 887static int
 888dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
 889		  struct netlink_ext_ack *extack)
 890{
 891	u64 freq = nla_get_u64(a), old_freq;
 892	struct dpll_pin_ref *ref, *failed;
 893	const struct dpll_pin_ops *ops;
 894	struct dpll_device *dpll;
 895	unsigned long i;
 896	int ret;
 897
 898	if (!dpll_pin_is_freq_supported(pin, freq)) {
 899		NL_SET_ERR_MSG_ATTR(extack, a, "frequency is not supported by the device");
 900		return -EINVAL;
 901	}
 902
 903	xa_for_each(&pin->dpll_refs, i, ref) {
 904		ops = dpll_pin_ops(ref);
 905		if (!ops->frequency_set || !ops->frequency_get) {
 906			NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
 907			return -EOPNOTSUPP;
 908		}
 909	}
 910	ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
 911	ops = dpll_pin_ops(ref);
 912	dpll = ref->dpll;
 913	ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 914				 dpll_priv(dpll), &old_freq, extack);
 915	if (ret) {
 916		NL_SET_ERR_MSG(extack, "unable to get old frequency value");
 917		return ret;
 918	}
 919	if (freq == old_freq)
 920		return 0;
 921
 922	xa_for_each(&pin->dpll_refs, i, ref) {
 923		ops = dpll_pin_ops(ref);
 924		dpll = ref->dpll;
 925		ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
 926					 dpll, dpll_priv(dpll), freq, extack);
 927		if (ret) {
 928			failed = ref;
 929			NL_SET_ERR_MSG_FMT(extack, "frequency set failed for dpll_id:%u",
 930					   dpll->id);
 931			goto rollback;
 932		}
 933	}
 934	__dpll_pin_change_ntf(pin);
 935
 936	return 0;
 937
 938rollback:
 939	xa_for_each(&pin->dpll_refs, i, ref) {
 940		if (ref == failed)
 941			break;
 942		ops = dpll_pin_ops(ref);
 943		dpll = ref->dpll;
 944		if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
 945				       dpll, dpll_priv(dpll), old_freq, extack))
 946			NL_SET_ERR_MSG(extack, "set frequency rollback failed");
 947	}
 948	return ret;
 949}
 950
 951static int
 952dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
 953		   struct netlink_ext_ack *extack)
 954{
 955	struct dpll_pin_ref *ref, *failed;
 956	const struct dpll_pin_ops *ops;
 957	struct dpll_pin_esync esync;
 958	u64 freq = nla_get_u64(a);
 959	struct dpll_device *dpll;
 960	bool supported = false;
 961	unsigned long i;
 962	int ret;
 963
 964	xa_for_each(&pin->dpll_refs, i, ref) {
 965		ops = dpll_pin_ops(ref);
 966		if (!ops->esync_set || !ops->esync_get) {
 967			NL_SET_ERR_MSG(extack,
 968				       "embedded sync feature is not supported by this device");
 969			return -EOPNOTSUPP;
 970		}
 971	}
 972	ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
 973	ops = dpll_pin_ops(ref);
 974	dpll = ref->dpll;
 975	ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 976			     dpll_priv(dpll), &esync, extack);
 977	if (ret) {
 978		NL_SET_ERR_MSG(extack, "unable to get current embedded sync frequency value");
 979		return ret;
 980	}
 981	if (freq == esync.freq)
 982		return 0;
 983	for (i = 0; i < esync.range_num; i++)
 984		if (freq <= esync.range[i].max && freq >= esync.range[i].min)
 985			supported = true;
 986	if (!supported) {
 987		NL_SET_ERR_MSG_ATTR(extack, a,
 988				    "requested embedded sync frequency value is not supported by this device");
 989		return -EINVAL;
 990	}
 991
 992	xa_for_each(&pin->dpll_refs, i, ref) {
 993		void *pin_dpll_priv;
 994
 995		ops = dpll_pin_ops(ref);
 996		dpll = ref->dpll;
 997		pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
 998		ret = ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
 999				      freq, extack);
1000		if (ret) {
1001			failed = ref;
1002			NL_SET_ERR_MSG_FMT(extack,
1003					   "embedded sync frequency set failed for dpll_id: %u",
1004					   dpll->id);
1005			goto rollback;
1006		}
1007	}
1008	__dpll_pin_change_ntf(pin);
1009
1010	return 0;
1011
1012rollback:
1013	xa_for_each(&pin->dpll_refs, i, ref) {
1014		void *pin_dpll_priv;
1015
1016		if (ref == failed)
1017			break;
1018		ops = dpll_pin_ops(ref);
1019		dpll = ref->dpll;
1020		pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
1021		if (ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
1022				   esync.freq, extack))
1023			NL_SET_ERR_MSG(extack, "set embedded sync frequency rollback failed");
1024	}
1025	return ret;
1026}
1027
1028static int
1029dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
1030			    unsigned long ref_sync_pin_idx,
1031			    const enum dpll_pin_state state,
1032			    struct netlink_ext_ack *extack)
1033
1034{
1035	struct dpll_pin_ref *ref, *failed;
1036	const struct dpll_pin_ops *ops;
1037	enum dpll_pin_state old_state;
1038	struct dpll_pin *ref_sync_pin;
1039	struct dpll_device *dpll;
1040	unsigned long i;
1041	int ret;
1042
1043	ref_sync_pin = xa_find(&pin->ref_sync_pins, &ref_sync_pin_idx,
1044			       ULONG_MAX, XA_PRESENT);
1045	if (!ref_sync_pin) {
1046		NL_SET_ERR_MSG(extack, "reference sync pin not found");
1047		return -EINVAL;
1048	}
1049	if (!dpll_pin_available(ref_sync_pin)) {
1050		NL_SET_ERR_MSG(extack, "reference sync pin not available");
1051		return -EINVAL;
1052	}
1053	ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
1054	ASSERT_NOT_NULL(ref);
1055	ops = dpll_pin_ops(ref);
1056	if (!ops->ref_sync_set || !ops->ref_sync_get) {
1057		NL_SET_ERR_MSG(extack, "reference sync not supported by this pin");
1058		return -EOPNOTSUPP;
1059	}
1060	dpll = ref->dpll;
1061	ret = ops->ref_sync_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
1062				ref_sync_pin,
1063				dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
1064				&old_state, extack);
1065	if (ret) {
1066		NL_SET_ERR_MSG(extack, "unable to get old reference sync state");
1067		return ret;
1068	}
1069	if (state == old_state)
1070		return 0;
1071	xa_for_each(&pin->dpll_refs, i, ref) {
1072		ops = dpll_pin_ops(ref);
1073		dpll = ref->dpll;
1074		ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
1075					ref_sync_pin,
1076					dpll_pin_on_dpll_priv(dpll,
1077							      ref_sync_pin),
1078					state, extack);
1079		if (ret) {
1080			failed = ref;
1081			NL_SET_ERR_MSG_FMT(extack, "reference sync set failed for dpll_id:%u",
1082					   dpll->id);
1083			goto rollback;
1084		}
1085	}
1086	__dpll_pin_change_ntf(pin);
1087
1088	return 0;
1089
1090rollback:
1091	xa_for_each(&pin->dpll_refs, i, ref) {
1092		if (ref == failed)
1093			break;
1094		ops = dpll_pin_ops(ref);
1095		dpll = ref->dpll;
1096		if (ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
1097				      ref_sync_pin,
1098				      dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
1099				      old_state, extack))
1100			NL_SET_ERR_MSG(extack, "set reference sync rollback failed");
1101	}
1102	return ret;
1103}
1104
1105static int
1106dpll_pin_ref_sync_set(struct dpll_pin *pin, struct nlattr *nest,
1107		      struct netlink_ext_ack *extack)
1108{
1109	struct nlattr *tb[DPLL_A_PIN_MAX + 1];
1110	enum dpll_pin_state state;
1111	u32 sync_pin_id;
1112
1113	nla_parse_nested(tb, DPLL_A_PIN_MAX, nest,
1114			 dpll_reference_sync_nl_policy, extack);
1115	if (!tb[DPLL_A_PIN_ID]) {
1116		NL_SET_ERR_MSG(extack, "sync pin id expected");
1117		return -EINVAL;
1118	}
1119	sync_pin_id = nla_get_u32(tb[DPLL_A_PIN_ID]);
1120
1121	if (!tb[DPLL_A_PIN_STATE]) {
1122		NL_SET_ERR_MSG(extack, "sync pin state expected");
1123		return -EINVAL;
1124	}
1125	state = nla_get_u32(tb[DPLL_A_PIN_STATE]);
1126
1127	return dpll_pin_ref_sync_state_set(pin, sync_pin_id, state, extack);
1128}
1129
1130static int
1131dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
1132			  enum dpll_pin_state state,
1133			  struct netlink_ext_ack *extack)
1134{
1135	struct dpll_pin_ref *parent_ref;
1136	const struct dpll_pin_ops *ops;
1137	struct dpll_pin_ref *dpll_ref;
1138	void *pin_priv, *parent_priv;
1139	struct dpll_pin *parent;
1140	unsigned long i;
1141	int ret;
1142
1143	if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE &
1144	      pin->prop.capabilities)) {
1145		NL_SET_ERR_MSG(extack, "state changing is not allowed");
1146		return -EOPNOTSUPP;
1147	}
1148	parent = xa_load(&dpll_pin_xa, parent_idx);
1149	if (!parent)
1150		return -EINVAL;
1151	parent_ref = xa_load(&pin->parent_refs, parent->pin_idx);
1152	if (!parent_ref)
1153		return -EINVAL;
1154	xa_for_each(&parent->dpll_refs, i, dpll_ref) {
1155		ops = dpll_pin_ops(parent_ref);
1156		if (!ops->state_on_pin_set)
1157			return -EOPNOTSUPP;
1158		pin_priv = dpll_pin_on_pin_priv(parent, pin);
1159		parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, parent);
1160		ret = ops->state_on_pin_set(pin, pin_priv, parent, parent_priv,
1161					    state, extack);
1162		if (ret)
1163			return ret;
1164	}
1165	__dpll_pin_change_ntf(pin);
1166
1167	return 0;
1168}
1169
1170static int
1171dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin,
1172		   enum dpll_pin_state state,
1173		   struct netlink_ext_ack *extack)
1174{
1175	const struct dpll_pin_ops *ops;
1176	struct dpll_pin_ref *ref;
1177	int ret;
1178
1179	if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE &
1180	      pin->prop.capabilities)) {
1181		NL_SET_ERR_MSG(extack, "state changing is not allowed");
1182		return -EOPNOTSUPP;
1183	}
1184	ref = xa_load(&pin->dpll_refs, dpll->id);
1185	ASSERT_NOT_NULL(ref);
1186	ops = dpll_pin_ops(ref);
1187	if (!ops->state_on_dpll_set)
1188		return -EOPNOTSUPP;
1189	ret = ops->state_on_dpll_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
1190				     dpll, dpll_priv(dpll), state, extack);
1191	if (ret)
1192		return ret;
1193	__dpll_pin_change_ntf(pin);
1194
1195	return 0;
1196}
1197
1198static int
1199dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin,
1200		  u32 prio, struct netlink_ext_ack *extack)
1201{
1202	const struct dpll_pin_ops *ops;
1203	struct dpll_pin_ref *ref;
1204	int ret;
1205
1206	if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE &
1207	      pin->prop.capabilities)) {
1208		NL_SET_ERR_MSG(extack, "prio changing is not allowed");
1209		return -EOPNOTSUPP;
1210	}
1211	ref = xa_load(&pin->dpll_refs, dpll->id);
1212	ASSERT_NOT_NULL(ref);
1213	ops = dpll_pin_ops(ref);
1214	if (!ops->prio_set)
1215		return -EOPNOTSUPP;
1216	ret = ops->prio_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
1217			    dpll_priv(dpll), prio, extack);
1218	if (ret)
1219		return ret;
1220	__dpll_pin_change_ntf(pin);
1221
1222	return 0;
1223}
1224
1225static int
1226dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll,
1227		       enum dpll_pin_direction direction,
1228		       struct netlink_ext_ack *extack)
1229{
1230	const struct dpll_pin_ops *ops;
1231	struct dpll_pin_ref *ref;
1232	int ret;
1233
1234	if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE &
1235	      pin->prop.capabilities)) {
1236		NL_SET_ERR_MSG(extack, "direction changing is not allowed");
1237		return -EOPNOTSUPP;
1238	}
1239	ref = xa_load(&pin->dpll_refs, dpll->id);
1240	ASSERT_NOT_NULL(ref);
1241	ops = dpll_pin_ops(ref);
1242	if (!ops->direction_set)
1243		return -EOPNOTSUPP;
1244	ret = ops->direction_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
1245				 dpll, dpll_priv(dpll), direction, extack);
1246	if (ret)
1247		return ret;
1248	__dpll_pin_change_ntf(pin);
1249
1250	return 0;
1251}
1252
1253static int
1254dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
1255		       struct netlink_ext_ack *extack)
1256{
1257	struct dpll_pin_ref *ref, *failed;
1258	const struct dpll_pin_ops *ops;
1259	s32 phase_adj, old_phase_adj;
1260	struct dpll_device *dpll;
1261	unsigned long i;
1262	int ret;
1263
1264	phase_adj = nla_get_s32(phase_adj_attr);
1265	if (phase_adj > pin->prop.phase_range.max ||
1266	    phase_adj < pin->prop.phase_range.min) {
1267		NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr,
1268				    "phase adjust value of out range");
1269		return -EINVAL;
1270	}
1271	if (pin->prop.phase_gran && phase_adj % (s32)pin->prop.phase_gran) {
1272		NL_SET_ERR_MSG_ATTR_FMT(extack, phase_adj_attr,
1273					"phase adjust value not multiple of %u",
1274					pin->prop.phase_gran);
1275		return -EINVAL;
1276	}
1277
1278	xa_for_each(&pin->dpll_refs, i, ref) {
1279		ops = dpll_pin_ops(ref);
1280		if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
1281			NL_SET_ERR_MSG(extack, "phase adjust not supported");
1282			return -EOPNOTSUPP;
1283		}
1284	}
1285	ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
1286	ops = dpll_pin_ops(ref);
1287	dpll = ref->dpll;
1288	ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
1289				    dpll, dpll_priv(dpll), &old_phase_adj,
1290				    extack);
1291	if (ret) {
1292		NL_SET_ERR_MSG(extack, "unable to get old phase adjust value");
1293		return ret;
1294	}
1295	if (phase_adj == old_phase_adj)
1296		return 0;
1297
1298	xa_for_each(&pin->dpll_refs, i, ref) {
1299		ops = dpll_pin_ops(ref);
1300		dpll = ref->dpll;
1301		ret = ops->phase_adjust_set(pin,
1302					    dpll_pin_on_dpll_priv(dpll, pin),
1303					    dpll, dpll_priv(dpll), phase_adj,
1304					    extack);
1305		if (ret) {
1306			failed = ref;
1307			NL_SET_ERR_MSG_FMT(extack,
1308					   "phase adjust set failed for dpll_id:%u",
1309					   dpll->id);
1310			goto rollback;
1311		}
1312	}
1313	__dpll_pin_change_ntf(pin);
1314
1315	return 0;
1316
1317rollback:
1318	xa_for_each(&pin->dpll_refs, i, ref) {
1319		if (ref == failed)
1320			break;
1321		ops = dpll_pin_ops(ref);
1322		dpll = ref->dpll;
1323		if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
1324					  dpll, dpll_priv(dpll), old_phase_adj,
1325					  extack))
1326			NL_SET_ERR_MSG(extack, "set phase adjust rollback failed");
1327	}
1328	return ret;
1329}
1330
1331static int
1332dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
1333			   struct netlink_ext_ack *extack)
1334{
1335	struct nlattr *tb[DPLL_A_PIN_MAX + 1];
1336	enum dpll_pin_direction direction;
1337	enum dpll_pin_state state;
1338	struct dpll_pin_ref *ref;
1339	struct dpll_device *dpll;
1340	u32 pdpll_idx, prio;
1341	int ret;
1342
1343	nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest,
1344			 dpll_pin_parent_device_nl_policy, extack);
1345	if (!tb[DPLL_A_PIN_PARENT_ID]) {
1346		NL_SET_ERR_MSG(extack, "device parent id expected");
1347		return -EINVAL;
1348	}
1349	pdpll_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
1350	dpll = xa_load(&dpll_device_xa, pdpll_idx);
1351	if (!dpll) {
1352		NL_SET_ERR_MSG(extack, "parent device not found");
1353		return -EINVAL;
1354	}
1355	ref = xa_load(&pin->dpll_refs, dpll->id);
1356	if (!ref) {
1357		NL_SET_ERR_MSG(extack, "pin not connected to given parent device");
1358		return -EINVAL;
1359	}
1360	if (tb[DPLL_A_PIN_STATE]) {
1361		state = nla_get_u32(tb[DPLL_A_PIN_STATE]);
1362		ret = dpll_pin_state_set(dpll, pin, state, extack);
1363		if (ret)
1364			return ret;
1365	}
1366	if (tb[DPLL_A_PIN_PRIO]) {
1367		prio = nla_get_u32(tb[DPLL_A_PIN_PRIO]);
1368		ret = dpll_pin_prio_set(dpll, pin, prio, extack);
1369		if (ret)
1370			return ret;
1371	}
1372	if (tb[DPLL_A_PIN_DIRECTION]) {
1373		direction = nla_get_u32(tb[DPLL_A_PIN_DIRECTION]);
1374		ret = dpll_pin_direction_set(pin, dpll, direction, extack);
1375		if (ret)
1376			return ret;
1377	}
1378	return 0;
1379}
1380
1381static int
1382dpll_pin_parent_pin_set(struct dpll_pin *pin, struct nlattr *parent_nest,
1383			struct netlink_ext_ack *extack)
1384{
1385	struct nlattr *tb[DPLL_A_PIN_MAX + 1];
1386	u32 ppin_idx;
1387	int ret;
1388
1389	nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest,
1390			 dpll_pin_parent_pin_nl_policy, extack);
1391	if (!tb[DPLL_A_PIN_PARENT_ID]) {
1392		NL_SET_ERR_MSG(extack, "device parent id expected");
1393		return -EINVAL;
1394	}
1395	ppin_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
1396
1397	if (tb[DPLL_A_PIN_STATE]) {
1398		enum dpll_pin_state state = nla_get_u32(tb[DPLL_A_PIN_STATE]);
1399
1400		ret = dpll_pin_on_pin_state_set(pin, ppin_idx, state, extack);
1401		if (ret)
1402			return ret;
1403	}
1404
1405	return 0;
1406}
1407
1408static int
1409dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info)
1410{
1411	struct nlattr *a;
1412	int rem, ret;
1413
1414	nla_for_each_attr(a, genlmsg_data(info->genlhdr),
1415			  genlmsg_len(info->genlhdr), rem) {
1416		switch (nla_type(a)) {
1417		case DPLL_A_PIN_FREQUENCY:
1418			ret = dpll_pin_freq_set(pin, a, info->extack);
1419			if (ret)
1420				return ret;
1421			break;
1422		case DPLL_A_PIN_PHASE_ADJUST:
1423			ret = dpll_pin_phase_adj_set(pin, a, info->extack);
1424			if (ret)
1425				return ret;
1426			break;
1427		case DPLL_A_PIN_PARENT_DEVICE:
1428			ret = dpll_pin_parent_device_set(pin, a, info->extack);
1429			if (ret)
1430				return ret;
1431			break;
1432		case DPLL_A_PIN_PARENT_PIN:
1433			ret = dpll_pin_parent_pin_set(pin, a, info->extack);
1434			if (ret)
1435				return ret;
1436			break;
1437		case DPLL_A_PIN_ESYNC_FREQUENCY:
1438			ret = dpll_pin_esync_set(pin, a, info->extack);
1439			if (ret)
1440				return ret;
1441			break;
1442		case DPLL_A_PIN_REFERENCE_SYNC:
1443			ret = dpll_pin_ref_sync_set(pin, a, info->extack);
1444			if (ret)
1445				return ret;
1446			break;
1447		}
1448	}
1449
1450	return 0;
1451}
1452
1453static struct dpll_pin *
1454dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr,
1455	      enum dpll_pin_type type, struct nlattr *board_label,
1456	      struct nlattr *panel_label, struct nlattr *package_label,
1457	      struct netlink_ext_ack *extack)
1458{
1459	bool board_match, panel_match, package_match;
1460	struct dpll_pin *pin_match = NULL, *pin;
1461	const struct dpll_pin_properties *prop;
1462	bool cid_match, mod_match, type_match;
1463	unsigned long i;
1464
1465	xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) {
1466		prop = &pin->prop;
1467		cid_match = clock_id ? pin->clock_id == clock_id : true;
1468		mod_match = mod_name_attr && module_name(pin->module) ?
1469			!nla_strcmp(mod_name_attr,
1470				    module_name(pin->module)) : true;
1471		type_match = type ? prop->type == type : true;
1472		board_match = board_label ? (prop->board_label ?
1473			!nla_strcmp(board_label, prop->board_label) : false) :
1474			true;
1475		panel_match = panel_label ? (prop->panel_label ?
1476			!nla_strcmp(panel_label, prop->panel_label) : false) :
1477			true;
1478		package_match = package_label ? (prop->package_label ?
1479			!nla_strcmp(package_label, prop->package_label) :
1480			false) : true;
1481		if (cid_match && mod_match && type_match && board_match &&
1482		    panel_match && package_match) {
1483			if (pin_match) {
1484				NL_SET_ERR_MSG(extack, "multiple matches");
1485				return ERR_PTR(-EINVAL);
1486			}
1487			pin_match = pin;
1488		}
1489	}
1490	if (!pin_match) {
1491		NL_SET_ERR_MSG(extack, "not found");
1492		return ERR_PTR(-ENODEV);
1493	}
1494	return pin_match;
1495}
1496
1497static struct dpll_pin *dpll_pin_find_from_nlattr(struct genl_info *info)
1498{
1499	struct nlattr *attr, *mod_name_attr = NULL, *board_label_attr = NULL,
1500		*panel_label_attr = NULL, *package_label_attr = NULL;
1501	enum dpll_pin_type type = 0;
1502	u64 clock_id = 0;
1503	int rem = 0;
1504
1505	nla_for_each_attr(attr, genlmsg_data(info->genlhdr),
1506			  genlmsg_len(info->genlhdr), rem) {
1507		switch (nla_type(attr)) {
1508		case DPLL_A_PIN_CLOCK_ID:
1509			if (clock_id)
1510				goto duplicated_attr;
1511			clock_id = nla_get_u64(attr);
1512			break;
1513		case DPLL_A_PIN_MODULE_NAME:
1514			if (mod_name_attr)
1515				goto duplicated_attr;
1516			mod_name_attr = attr;
1517			break;
1518		case DPLL_A_PIN_TYPE:
1519			if (type)
1520				goto duplicated_attr;
1521			type = nla_get_u32(attr);
1522		break;
1523		case DPLL_A_PIN_BOARD_LABEL:
1524			if (board_label_attr)
1525				goto duplicated_attr;
1526			board_label_attr = attr;
1527		break;
1528		case DPLL_A_PIN_PANEL_LABEL:
1529			if (panel_label_attr)
1530				goto duplicated_attr;
1531			panel_label_attr = attr;
1532		break;
1533		case DPLL_A_PIN_PACKAGE_LABEL:
1534			if (package_label_attr)
1535				goto duplicated_attr;
1536			package_label_attr = attr;
1537		break;
1538		default:
1539			break;
1540		}
1541	}
1542	if (!(clock_id  || mod_name_attr || board_label_attr ||
1543	      panel_label_attr || package_label_attr)) {
1544		NL_SET_ERR_MSG(info->extack, "missing attributes");
1545		return ERR_PTR(-EINVAL);
1546	}
1547	return dpll_pin_find(clock_id, mod_name_attr, type, board_label_attr,
1548			     panel_label_attr, package_label_attr,
1549			     info->extack);
1550duplicated_attr:
1551	NL_SET_ERR_MSG(info->extack, "duplicated attribute");
1552	return ERR_PTR(-EINVAL);
1553}
1554
1555int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info)
1556{
1557	struct dpll_pin *pin;
1558	struct sk_buff *msg;
1559	struct nlattr *hdr;
1560	int ret;
1561
1562	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1563	if (!msg)
1564		return -ENOMEM;
1565	hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1566				DPLL_CMD_PIN_ID_GET);
1567	if (!hdr) {
1568		nlmsg_free(msg);
1569		return -EMSGSIZE;
1570	}
1571	pin = dpll_pin_find_from_nlattr(info);
1572	if (IS_ERR(pin)) {
1573		nlmsg_free(msg);
1574		return PTR_ERR(pin);
1575	}
1576	if (!dpll_pin_available(pin)) {
1577		nlmsg_free(msg);
1578		return -ENODEV;
1579	}
1580	ret = dpll_msg_add_pin_handle(msg, pin);
1581	if (ret) {
1582		nlmsg_free(msg);
1583		return ret;
1584	}
1585	genlmsg_end(msg, hdr);
1586
1587	return genlmsg_reply(msg, info);
1588}
1589
1590int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info)
1591{
1592	struct dpll_pin *pin = info->user_ptr[0];
1593	struct sk_buff *msg;
1594	struct nlattr *hdr;
1595	int ret;
1596
1597	if (!pin)
1598		return -ENODEV;
1599	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1600	if (!msg)
1601		return -ENOMEM;
1602	hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1603				DPLL_CMD_PIN_GET);
1604	if (!hdr) {
1605		nlmsg_free(msg);
1606		return -EMSGSIZE;
1607	}
1608	ret = dpll_cmd_pin_get_one(msg, pin, info->extack);
1609	if (ret) {
1610		nlmsg_free(msg);
1611		return ret;
1612	}
1613	genlmsg_end(msg, hdr);
1614
1615	return genlmsg_reply(msg, info);
1616}
1617
1618int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
1619{
1620	struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
1621	struct dpll_pin *pin;
1622	struct nlattr *hdr;
1623	unsigned long i;
1624	int ret = 0;
1625
1626	mutex_lock(&dpll_lock);
1627	xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED,
1628				 ctx->idx) {
1629		if (!dpll_pin_available(pin))
1630			continue;
1631		hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
1632				  cb->nlh->nlmsg_seq,
1633				  &dpll_nl_family, NLM_F_MULTI,
1634				  DPLL_CMD_PIN_GET);
1635		if (!hdr) {
1636			ret = -EMSGSIZE;
1637			break;
1638		}
1639		ret = dpll_cmd_pin_get_one(skb, pin, cb->extack);
1640		if (ret) {
1641			genlmsg_cancel(skb, hdr);
1642			break;
1643		}
1644		genlmsg_end(skb, hdr);
1645	}
1646	mutex_unlock(&dpll_lock);
1647
1648	if (ret == -EMSGSIZE) {
1649		ctx->idx = i;
1650		return skb->len;
1651	}
1652	return ret;
1653}
1654
1655int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info)
1656{
1657	struct dpll_pin *pin = info->user_ptr[0];
1658
1659	return dpll_pin_set_from_nlattr(pin, info);
1660}
1661
1662static struct dpll_device *
1663dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr,
1664		 enum dpll_type type, struct netlink_ext_ack *extack)
1665{
1666	struct dpll_device *dpll_match = NULL, *dpll;
1667	bool cid_match, mod_match, type_match;
1668	unsigned long i;
1669
1670	xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) {
1671		cid_match = clock_id ? dpll->clock_id == clock_id : true;
1672		mod_match = mod_name_attr ? (module_name(dpll->module) ?
1673			!nla_strcmp(mod_name_attr,
1674				    module_name(dpll->module)) : false) : true;
1675		type_match = type ? dpll->type == type : true;
1676		if (cid_match && mod_match && type_match) {
1677			if (dpll_match) {
1678				NL_SET_ERR_MSG(extack, "multiple matches");
1679				return ERR_PTR(-EINVAL);
1680			}
1681			dpll_match = dpll;
1682		}
1683	}
1684	if (!dpll_match) {
1685		NL_SET_ERR_MSG(extack, "not found");
1686		return ERR_PTR(-ENODEV);
1687	}
1688
1689	return dpll_match;
1690}
1691
1692static struct dpll_device *
1693dpll_device_find_from_nlattr(struct genl_info *info)
1694{
1695	struct nlattr *attr, *mod_name_attr = NULL;
1696	enum dpll_type type = 0;
1697	u64 clock_id = 0;
1698	int rem = 0;
1699
1700	nla_for_each_attr(attr, genlmsg_data(info->genlhdr),
1701			  genlmsg_len(info->genlhdr), rem) {
1702		switch (nla_type(attr)) {
1703		case DPLL_A_CLOCK_ID:
1704			if (clock_id)
1705				goto duplicated_attr;
1706			clock_id = nla_get_u64(attr);
1707			break;
1708		case DPLL_A_MODULE_NAME:
1709			if (mod_name_attr)
1710				goto duplicated_attr;
1711			mod_name_attr = attr;
1712			break;
1713		case DPLL_A_TYPE:
1714			if (type)
1715				goto duplicated_attr;
1716			type = nla_get_u32(attr);
1717			break;
1718		default:
1719			break;
1720		}
1721	}
1722	if (!clock_id && !mod_name_attr && !type) {
1723		NL_SET_ERR_MSG(info->extack, "missing attributes");
1724		return ERR_PTR(-EINVAL);
1725	}
1726	return dpll_device_find(clock_id, mod_name_attr, type, info->extack);
1727duplicated_attr:
1728	NL_SET_ERR_MSG(info->extack, "duplicated attribute");
1729	return ERR_PTR(-EINVAL);
1730}
1731
1732int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info)
1733{
1734	struct dpll_device *dpll;
1735	struct sk_buff *msg;
1736	struct nlattr *hdr;
1737	int ret;
1738
1739	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1740	if (!msg)
1741		return -ENOMEM;
1742	hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1743				DPLL_CMD_DEVICE_ID_GET);
1744	if (!hdr) {
1745		nlmsg_free(msg);
1746		return -EMSGSIZE;
1747	}
1748
1749	dpll = dpll_device_find_from_nlattr(info);
1750	if (IS_ERR(dpll)) {
1751		nlmsg_free(msg);
1752		return PTR_ERR(dpll);
1753	}
1754	ret = dpll_msg_add_dev_handle(msg, dpll);
1755	if (ret) {
1756		nlmsg_free(msg);
1757		return ret;
1758	}
1759	genlmsg_end(msg, hdr);
1760
1761	return genlmsg_reply(msg, info);
1762}
1763
1764int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info)
1765{
1766	struct dpll_device *dpll = info->user_ptr[0];
1767	struct sk_buff *msg;
1768	struct nlattr *hdr;
1769	int ret;
1770
1771	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1772	if (!msg)
1773		return -ENOMEM;
1774	hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1775				DPLL_CMD_DEVICE_GET);
1776	if (!hdr) {
1777		nlmsg_free(msg);
1778		return -EMSGSIZE;
1779	}
1780
1781	ret = dpll_device_get_one(dpll, msg, info->extack);
1782	if (ret) {
1783		nlmsg_free(msg);
1784		return ret;
1785	}
1786	genlmsg_end(msg, hdr);
1787
1788	return genlmsg_reply(msg, info);
1789}
1790
1791static int
1792dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info)
1793{
1794	struct nlattr *a;
1795	int rem, ret;
1796
1797	nla_for_each_attr(a, genlmsg_data(info->genlhdr),
1798			  genlmsg_len(info->genlhdr), rem) {
1799		switch (nla_type(a)) {
1800		case DPLL_A_PHASE_OFFSET_MONITOR:
1801			ret = dpll_phase_offset_monitor_set(dpll, a,
1802							    info->extack);
1803			if (ret)
1804				return ret;
1805			break;
1806		case DPLL_A_PHASE_OFFSET_AVG_FACTOR:
1807			ret = dpll_phase_offset_avg_factor_set(dpll, a,
1808							       info->extack);
1809			if (ret)
1810				return ret;
1811			break;
1812		}
1813	}
1814
1815	return 0;
1816}
1817
1818int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info)
1819{
1820	struct dpll_device *dpll = info->user_ptr[0];
1821
1822	return dpll_set_from_nlattr(dpll, info);
1823}
1824
1825int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
1826{
1827	struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
1828	struct dpll_device *dpll;
1829	struct nlattr *hdr;
1830	unsigned long i;
1831	int ret = 0;
1832
1833	mutex_lock(&dpll_lock);
1834	xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED,
1835				 ctx->idx) {
1836		hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
1837				  cb->nlh->nlmsg_seq, &dpll_nl_family,
1838				  NLM_F_MULTI, DPLL_CMD_DEVICE_GET);
1839		if (!hdr) {
1840			ret = -EMSGSIZE;
1841			break;
1842		}
1843		ret = dpll_device_get_one(dpll, skb, cb->extack);
1844		if (ret) {
1845			genlmsg_cancel(skb, hdr);
1846			break;
1847		}
1848		genlmsg_end(skb, hdr);
1849	}
1850	mutex_unlock(&dpll_lock);
1851
1852	if (ret == -EMSGSIZE) {
1853		ctx->idx = i;
1854		return skb->len;
1855	}
1856	return ret;
1857}
1858
1859int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1860		  struct genl_info *info)
1861{
1862	u32 id;
1863
1864	if (GENL_REQ_ATTR_CHECK(info, DPLL_A_ID))
1865		return -EINVAL;
1866
1867	mutex_lock(&dpll_lock);
1868	id = nla_get_u32(info->attrs[DPLL_A_ID]);
1869	info->user_ptr[0] = dpll_device_get_by_id(id);
1870	if (!info->user_ptr[0]) {
1871		NL_SET_ERR_MSG(info->extack, "device not found");
1872		goto unlock;
1873	}
1874	return 0;
1875unlock:
1876	mutex_unlock(&dpll_lock);
1877	return -ENODEV;
1878}
1879
1880void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1881		    struct genl_info *info)
1882{
1883	mutex_unlock(&dpll_lock);
1884}
1885
1886int
1887dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1888	       struct genl_info *info)
1889{
1890	mutex_lock(&dpll_lock);
1891
1892	return 0;
1893}
1894
1895void
1896dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1897		 struct genl_info *info)
1898{
1899	mutex_unlock(&dpll_lock);
1900}
1901
1902int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1903		      struct genl_info *info)
1904{
1905	int ret;
1906
1907	mutex_lock(&dpll_lock);
1908	if (GENL_REQ_ATTR_CHECK(info, DPLL_A_PIN_ID)) {
1909		ret = -EINVAL;
1910		goto unlock_dev;
1911	}
1912	info->user_ptr[0] = xa_load(&dpll_pin_xa,
1913				    nla_get_u32(info->attrs[DPLL_A_PIN_ID]));
1914	if (!info->user_ptr[0] ||
1915	    !dpll_pin_available(info->user_ptr[0])) {
1916		NL_SET_ERR_MSG(info->extack, "pin not found");
1917		ret = -ENODEV;
1918		goto unlock_dev;
1919	}
1920
1921	return 0;
1922
1923unlock_dev:
1924	mutex_unlock(&dpll_lock);
1925	return ret;
1926}
1927
1928void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1929			struct genl_info *info)
1930{
1931	mutex_unlock(&dpll_lock);
1932}
~/ Read-only file preview.