Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   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
  51/**
  52 * dpll_msg_add_pin_handle - attach pin handle attribute to a given message
  53 * @msg: pointer to sk_buff message to attach a pin handle
  54 * @pin: pin pointer
  55 *
  56 * Return:
  57 * * 0 - success
  58 * * -EMSGSIZE - no space in message to attach pin handle
  59 */
  60static int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin)
  61{
  62	if (!pin)
  63		return 0;
  64	if (nla_put_u32(msg, DPLL_A_PIN_ID, pin->id))
  65		return -EMSGSIZE;
  66	return 0;
  67}
  68
  69static struct dpll_pin *dpll_netdev_pin(const struct net_device *dev)
  70{
  71	return rcu_dereference_rtnl(dev->dpll_pin);
  72}
  73
  74/**
  75 * dpll_netdev_pin_handle_size - get size of pin handle attribute of a netdev
  76 * @dev: netdev from which to get the pin
  77 *
  78 * Return: byte size of pin handle attribute, or 0 if @dev has no pin.
  79 */
  80size_t dpll_netdev_pin_handle_size(const struct net_device *dev)
  81{
  82	return dpll_netdev_pin(dev) ? nla_total_size(4) : 0; /* DPLL_A_PIN_ID */
  83}
  84
  85int dpll_netdev_add_pin_handle(struct sk_buff *msg,
  86			       const struct net_device *dev)
  87{
  88	return dpll_msg_add_pin_handle(msg, dpll_netdev_pin(dev));
  89}
  90
  91static int
  92dpll_msg_add_mode(struct sk_buff *msg, struct dpll_device *dpll,
  93		  struct netlink_ext_ack *extack)
  94{
  95	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
  96	enum dpll_mode mode;
  97	int ret;
  98
  99	ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack);
 100	if (ret)
 101		return ret;
 102	if (nla_put_u32(msg, DPLL_A_MODE, mode))
 103		return -EMSGSIZE;
 104
 105	return 0;
 106}
 107
 108static int
 109dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll,
 110			    struct netlink_ext_ack *extack)
 111{
 112	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 113	enum dpll_mode mode;
 114	int ret;
 115
 116	/* No mode change is supported now, so the only supported mode is the
 117	 * one obtained by mode_get().
 118	 */
 119
 120	ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack);
 121	if (ret)
 122		return ret;
 123	if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode))
 124		return -EMSGSIZE;
 125
 126	return 0;
 127}
 128
 129static int
 130dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll,
 131			 struct netlink_ext_ack *extack)
 132{
 133	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 134	enum dpll_lock_status status;
 135	int ret;
 136
 137	ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status, extack);
 138	if (ret)
 139		return ret;
 140	if (nla_put_u32(msg, DPLL_A_LOCK_STATUS, status))
 141		return -EMSGSIZE;
 142
 143	return 0;
 144}
 145
 146static int
 147dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll,
 148		  struct netlink_ext_ack *extack)
 149{
 150	const struct dpll_device_ops *ops = dpll_device_ops(dpll);
 151	s32 temp;
 152	int ret;
 153
 154	if (!ops->temp_get)
 155		return 0;
 156	ret = ops->temp_get(dpll, dpll_priv(dpll), &temp, extack);
 157	if (ret)
 158		return ret;
 159	if (nla_put_s32(msg, DPLL_A_TEMP, temp))
 160		return -EMSGSIZE;
 161
 162	return 0;
 163}
 164
 165static int
 166dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin,
 167		      struct dpll_pin_ref *ref,
 168		      struct netlink_ext_ack *extack)
 169{
 170	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 171	struct dpll_device *dpll = ref->dpll;
 172	u32 prio;
 173	int ret;
 174
 175	if (!ops->prio_get)
 176		return 0;
 177	ret = ops->prio_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 178			    dpll_priv(dpll), &prio, extack);
 179	if (ret)
 180		return ret;
 181	if (nla_put_u32(msg, DPLL_A_PIN_PRIO, prio))
 182		return -EMSGSIZE;
 183
 184	return 0;
 185}
 186
 187static int
 188dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin,
 189			       struct dpll_pin_ref *ref,
 190			       struct netlink_ext_ack *extack)
 191{
 192	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 193	struct dpll_device *dpll = ref->dpll;
 194	enum dpll_pin_state state;
 195	int ret;
 196
 197	if (!ops->state_on_dpll_get)
 198		return 0;
 199	ret = ops->state_on_dpll_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 200				     dpll, dpll_priv(dpll), &state, extack);
 201	if (ret)
 202		return ret;
 203	if (nla_put_u32(msg, DPLL_A_PIN_STATE, state))
 204		return -EMSGSIZE;
 205
 206	return 0;
 207}
 208
 209static int
 210dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin,
 211			   struct dpll_pin_ref *ref,
 212			   struct netlink_ext_ack *extack)
 213{
 214	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 215	struct dpll_device *dpll = ref->dpll;
 216	enum dpll_pin_direction direction;
 217	int ret;
 218
 219	ret = ops->direction_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 220				 dpll_priv(dpll), &direction, extack);
 221	if (ret)
 222		return ret;
 223	if (nla_put_u32(msg, DPLL_A_PIN_DIRECTION, direction))
 224		return -EMSGSIZE;
 225
 226	return 0;
 227}
 228
 229static int
 230dpll_msg_add_pin_phase_adjust(struct sk_buff *msg, struct dpll_pin *pin,
 231			      struct dpll_pin_ref *ref,
 232			      struct netlink_ext_ack *extack)
 233{
 234	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 235	struct dpll_device *dpll = ref->dpll;
 236	s32 phase_adjust;
 237	int ret;
 238
 239	if (!ops->phase_adjust_get)
 240		return 0;
 241	ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 242				    dpll, dpll_priv(dpll),
 243				    &phase_adjust, extack);
 244	if (ret)
 245		return ret;
 246	if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST, phase_adjust))
 247		return -EMSGSIZE;
 248
 249	return 0;
 250}
 251
 252static int
 253dpll_msg_add_phase_offset(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	s64 phase_offset;
 260	int ret;
 261
 262	if (!ops->phase_offset_get)
 263		return 0;
 264	ret = ops->phase_offset_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 265				    dpll, dpll_priv(dpll), &phase_offset,
 266				    extack);
 267	if (ret)
 268		return ret;
 269	if (nla_put_64bit(msg, DPLL_A_PIN_PHASE_OFFSET, sizeof(phase_offset),
 270			  &phase_offset, DPLL_A_PIN_PAD))
 271		return -EMSGSIZE;
 272
 273	return 0;
 274}
 275
 276static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin,
 277			    struct dpll_pin_ref *ref,
 278			    struct netlink_ext_ack *extack)
 279{
 280	const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 281	struct dpll_device *dpll = ref->dpll;
 282	s64 ffo;
 283	int ret;
 284
 285	if (!ops->ffo_get)
 286		return 0;
 287	ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 288			   dpll, dpll_priv(dpll), &ffo, extack);
 289	if (ret) {
 290		if (ret == -ENODATA)
 291			return 0;
 292		return ret;
 293	}
 294	return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, ffo);
 295}
 296
 297static int
 298dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
 299		      struct dpll_pin_ref *ref, 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	struct nlattr *nest;
 304	int fs, ret;
 305	u64 freq;
 306
 307	if (!ops->frequency_get)
 308		return 0;
 309	ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 310				 dpll_priv(dpll), &freq, extack);
 311	if (ret)
 312		return ret;
 313	if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq,
 314			  DPLL_A_PIN_PAD))
 315		return -EMSGSIZE;
 316	for (fs = 0; fs < pin->prop.freq_supported_num; fs++) {
 317		nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED);
 318		if (!nest)
 319			return -EMSGSIZE;
 320		freq = pin->prop.freq_supported[fs].min;
 321		if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq),
 322				  &freq, DPLL_A_PIN_PAD)) {
 323			nla_nest_cancel(msg, nest);
 324			return -EMSGSIZE;
 325		}
 326		freq = pin->prop.freq_supported[fs].max;
 327		if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq),
 328				  &freq, DPLL_A_PIN_PAD)) {
 329			nla_nest_cancel(msg, nest);
 330			return -EMSGSIZE;
 331		}
 332		nla_nest_end(msg, nest);
 333	}
 334
 335	return 0;
 336}
 337
 338static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq)
 339{
 340	int fs;
 341
 342	for (fs = 0; fs < pin->prop.freq_supported_num; fs++)
 343		if (freq >= pin->prop.freq_supported[fs].min &&
 344		    freq <= pin->prop.freq_supported[fs].max)
 345			return true;
 346	return false;
 347}
 348
 349static int
 350dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin,
 351			 struct dpll_pin_ref *dpll_ref,
 352			 struct netlink_ext_ack *extack)
 353{
 354	enum dpll_pin_state state;
 355	struct dpll_pin_ref *ref;
 356	struct dpll_pin *ppin;
 357	struct nlattr *nest;
 358	unsigned long index;
 359	int ret;
 360
 361	xa_for_each(&pin->parent_refs, index, ref) {
 362		const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
 363		void *parent_priv;
 364
 365		ppin = ref->pin;
 366		parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, ppin);
 367		ret = ops->state_on_pin_get(pin,
 368					    dpll_pin_on_pin_priv(ppin, pin),
 369					    ppin, parent_priv, &state, extack);
 370		if (ret)
 371			return ret;
 372		nest = nla_nest_start(msg, DPLL_A_PIN_PARENT_PIN);
 373		if (!nest)
 374			return -EMSGSIZE;
 375		ret = dpll_msg_add_dev_parent_handle(msg, ppin->id);
 376		if (ret)
 377			goto nest_cancel;
 378		if (nla_put_u32(msg, DPLL_A_PIN_STATE, state)) {
 379			ret = -EMSGSIZE;
 380			goto nest_cancel;
 381		}
 382		nla_nest_end(msg, nest);
 383	}
 384
 385	return 0;
 386
 387nest_cancel:
 388	nla_nest_cancel(msg, nest);
 389	return ret;
 390}
 391
 392static int
 393dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
 394		       struct netlink_ext_ack *extack)
 395{
 396	struct dpll_pin_ref *ref;
 397	struct nlattr *attr;
 398	unsigned long index;
 399	int ret;
 400
 401	xa_for_each(&pin->dpll_refs, index, ref) {
 402		attr = nla_nest_start(msg, DPLL_A_PIN_PARENT_DEVICE);
 403		if (!attr)
 404			return -EMSGSIZE;
 405		ret = dpll_msg_add_dev_parent_handle(msg, ref->dpll->id);
 406		if (ret)
 407			goto nest_cancel;
 408		ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack);
 409		if (ret)
 410			goto nest_cancel;
 411		ret = dpll_msg_add_pin_prio(msg, pin, ref, extack);
 412		if (ret)
 413			goto nest_cancel;
 414		ret = dpll_msg_add_pin_direction(msg, pin, ref, extack);
 415		if (ret)
 416			goto nest_cancel;
 417		ret = dpll_msg_add_phase_offset(msg, pin, ref, extack);
 418		if (ret)
 419			goto nest_cancel;
 420		nla_nest_end(msg, attr);
 421	}
 422
 423	return 0;
 424
 425nest_cancel:
 426	nla_nest_end(msg, attr);
 427	return ret;
 428}
 429
 430static int
 431dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
 432		     struct netlink_ext_ack *extack)
 433{
 434	const struct dpll_pin_properties *prop = &pin->prop;
 435	struct dpll_pin_ref *ref;
 436	int ret;
 437
 438	ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
 439	ASSERT_NOT_NULL(ref);
 440
 441	ret = dpll_msg_add_pin_handle(msg, pin);
 442	if (ret)
 443		return ret;
 444	if (nla_put_string(msg, DPLL_A_PIN_MODULE_NAME,
 445			   module_name(pin->module)))
 446		return -EMSGSIZE;
 447	if (nla_put_64bit(msg, DPLL_A_PIN_CLOCK_ID, sizeof(pin->clock_id),
 448			  &pin->clock_id, DPLL_A_PIN_PAD))
 449		return -EMSGSIZE;
 450	if (prop->board_label &&
 451	    nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, prop->board_label))
 452		return -EMSGSIZE;
 453	if (prop->panel_label &&
 454	    nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, prop->panel_label))
 455		return -EMSGSIZE;
 456	if (prop->package_label &&
 457	    nla_put_string(msg, DPLL_A_PIN_PACKAGE_LABEL,
 458			   prop->package_label))
 459		return -EMSGSIZE;
 460	if (nla_put_u32(msg, DPLL_A_PIN_TYPE, prop->type))
 461		return -EMSGSIZE;
 462	if (nla_put_u32(msg, DPLL_A_PIN_CAPABILITIES, prop->capabilities))
 463		return -EMSGSIZE;
 464	ret = dpll_msg_add_pin_freq(msg, pin, ref, extack);
 465	if (ret)
 466		return ret;
 467	if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MIN,
 468			prop->phase_range.min))
 469		return -EMSGSIZE;
 470	if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MAX,
 471			prop->phase_range.max))
 472		return -EMSGSIZE;
 473	ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
 474	if (ret)
 475		return ret;
 476	ret = dpll_msg_add_ffo(msg, pin, ref, extack);
 477	if (ret)
 478		return ret;
 479	if (xa_empty(&pin->parent_refs))
 480		ret = dpll_msg_add_pin_dplls(msg, pin, extack);
 481	else
 482		ret = dpll_msg_add_pin_parents(msg, pin, ref, extack);
 483
 484	return ret;
 485}
 486
 487static int
 488dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
 489		    struct netlink_ext_ack *extack)
 490{
 491	int ret;
 492
 493	ret = dpll_msg_add_dev_handle(msg, dpll);
 494	if (ret)
 495		return ret;
 496	if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(dpll->module)))
 497		return -EMSGSIZE;
 498	if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id),
 499			  &dpll->clock_id, DPLL_A_PAD))
 500		return -EMSGSIZE;
 501	ret = dpll_msg_add_temp(msg, dpll, extack);
 502	if (ret)
 503		return ret;
 504	ret = dpll_msg_add_lock_status(msg, dpll, extack);
 505	if (ret)
 506		return ret;
 507	ret = dpll_msg_add_mode(msg, dpll, extack);
 508	if (ret)
 509		return ret;
 510	ret = dpll_msg_add_mode_supported(msg, dpll, extack);
 511	if (ret)
 512		return ret;
 513	if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type))
 514		return -EMSGSIZE;
 515
 516	return 0;
 517}
 518
 519static int
 520dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll)
 521{
 522	struct sk_buff *msg;
 523	int ret = -ENOMEM;
 524	void *hdr;
 525
 526	if (WARN_ON(!xa_get_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED)))
 527		return -ENODEV;
 528	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 529	if (!msg)
 530		return -ENOMEM;
 531	hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event);
 532	if (!hdr)
 533		goto err_free_msg;
 534	ret = dpll_device_get_one(dpll, msg, NULL);
 535	if (ret)
 536		goto err_cancel_msg;
 537	genlmsg_end(msg, hdr);
 538	genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL);
 539
 540	return 0;
 541
 542err_cancel_msg:
 543	genlmsg_cancel(msg, hdr);
 544err_free_msg:
 545	nlmsg_free(msg);
 546
 547	return ret;
 548}
 549
 550int dpll_device_create_ntf(struct dpll_device *dpll)
 551{
 552	return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF, dpll);
 553}
 554
 555int dpll_device_delete_ntf(struct dpll_device *dpll)
 556{
 557	return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll);
 558}
 559
 560static int
 561__dpll_device_change_ntf(struct dpll_device *dpll)
 562{
 563	return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll);
 564}
 565
 566static bool dpll_pin_available(struct dpll_pin *pin)
 567{
 568	struct dpll_pin_ref *par_ref;
 569	unsigned long i;
 570
 571	if (!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED))
 572		return false;
 573	xa_for_each(&pin->parent_refs, i, par_ref)
 574		if (xa_get_mark(&dpll_pin_xa, par_ref->pin->id,
 575				DPLL_REGISTERED))
 576			return true;
 577	xa_for_each(&pin->dpll_refs, i, par_ref)
 578		if (xa_get_mark(&dpll_device_xa, par_ref->dpll->id,
 579				DPLL_REGISTERED))
 580			return true;
 581	return false;
 582}
 583
 584/**
 585 * dpll_device_change_ntf - notify that the dpll device has been changed
 586 * @dpll: registered dpll pointer
 587 *
 588 * Context: acquires and holds a dpll_lock.
 589 * Return: 0 if succeeds, error code otherwise.
 590 */
 591int dpll_device_change_ntf(struct dpll_device *dpll)
 592{
 593	int ret;
 594
 595	mutex_lock(&dpll_lock);
 596	ret = __dpll_device_change_ntf(dpll);
 597	mutex_unlock(&dpll_lock);
 598
 599	return ret;
 600}
 601EXPORT_SYMBOL_GPL(dpll_device_change_ntf);
 602
 603static int
 604dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin)
 605{
 606	struct sk_buff *msg;
 607	int ret = -ENOMEM;
 608	void *hdr;
 609
 610	if (!dpll_pin_available(pin))
 611		return -ENODEV;
 612
 613	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 614	if (!msg)
 615		return -ENOMEM;
 616
 617	hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event);
 618	if (!hdr)
 619		goto err_free_msg;
 620	ret = dpll_cmd_pin_get_one(msg, pin, NULL);
 621	if (ret)
 622		goto err_cancel_msg;
 623	genlmsg_end(msg, hdr);
 624	genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL);
 625
 626	return 0;
 627
 628err_cancel_msg:
 629	genlmsg_cancel(msg, hdr);
 630err_free_msg:
 631	nlmsg_free(msg);
 632
 633	return ret;
 634}
 635
 636int dpll_pin_create_ntf(struct dpll_pin *pin)
 637{
 638	return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin);
 639}
 640
 641int dpll_pin_delete_ntf(struct dpll_pin *pin)
 642{
 643	return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin);
 644}
 645
 646static int __dpll_pin_change_ntf(struct dpll_pin *pin)
 647{
 648	return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin);
 649}
 650
 651/**
 652 * dpll_pin_change_ntf - notify that the pin has been changed
 653 * @pin: registered pin pointer
 654 *
 655 * Context: acquires and holds a dpll_lock.
 656 * Return: 0 if succeeds, error code otherwise.
 657 */
 658int dpll_pin_change_ntf(struct dpll_pin *pin)
 659{
 660	int ret;
 661
 662	mutex_lock(&dpll_lock);
 663	ret = __dpll_pin_change_ntf(pin);
 664	mutex_unlock(&dpll_lock);
 665
 666	return ret;
 667}
 668EXPORT_SYMBOL_GPL(dpll_pin_change_ntf);
 669
 670static int
 671dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
 672		  struct netlink_ext_ack *extack)
 673{
 674	u64 freq = nla_get_u64(a), old_freq;
 675	struct dpll_pin_ref *ref, *failed;
 676	const struct dpll_pin_ops *ops;
 677	struct dpll_device *dpll;
 678	unsigned long i;
 679	int ret;
 680
 681	if (!dpll_pin_is_freq_supported(pin, freq)) {
 682		NL_SET_ERR_MSG_ATTR(extack, a, "frequency is not supported by the device");
 683		return -EINVAL;
 684	}
 685
 686	xa_for_each(&pin->dpll_refs, i, ref) {
 687		ops = dpll_pin_ops(ref);
 688		if (!ops->frequency_set || !ops->frequency_get) {
 689			NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
 690			return -EOPNOTSUPP;
 691		}
 692	}
 693	ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
 694	ops = dpll_pin_ops(ref);
 695	dpll = ref->dpll;
 696	ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 697				 dpll_priv(dpll), &old_freq, extack);
 698	if (ret) {
 699		NL_SET_ERR_MSG(extack, "unable to get old frequency value");
 700		return ret;
 701	}
 702	if (freq == old_freq)
 703		return 0;
 704
 705	xa_for_each(&pin->dpll_refs, i, ref) {
 706		ops = dpll_pin_ops(ref);
 707		dpll = ref->dpll;
 708		ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
 709					 dpll, dpll_priv(dpll), freq, extack);
 710		if (ret) {
 711			failed = ref;
 712			NL_SET_ERR_MSG_FMT(extack, "frequency set failed for dpll_id:%u",
 713					   dpll->id);
 714			goto rollback;
 715		}
 716	}
 717	__dpll_pin_change_ntf(pin);
 718
 719	return 0;
 720
 721rollback:
 722	xa_for_each(&pin->dpll_refs, i, ref) {
 723		if (ref == failed)
 724			break;
 725		ops = dpll_pin_ops(ref);
 726		dpll = ref->dpll;
 727		if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
 728				       dpll, dpll_priv(dpll), old_freq, extack))
 729			NL_SET_ERR_MSG(extack, "set frequency rollback failed");
 730	}
 731	return ret;
 732}
 733
 734static int
 735dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
 736			  enum dpll_pin_state state,
 737			  struct netlink_ext_ack *extack)
 738{
 739	struct dpll_pin_ref *parent_ref;
 740	const struct dpll_pin_ops *ops;
 741	struct dpll_pin_ref *dpll_ref;
 742	void *pin_priv, *parent_priv;
 743	struct dpll_pin *parent;
 744	unsigned long i;
 745	int ret;
 746
 747	if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE &
 748	      pin->prop.capabilities)) {
 749		NL_SET_ERR_MSG(extack, "state changing is not allowed");
 750		return -EOPNOTSUPP;
 751	}
 752	parent = xa_load(&dpll_pin_xa, parent_idx);
 753	if (!parent)
 754		return -EINVAL;
 755	parent_ref = xa_load(&pin->parent_refs, parent->pin_idx);
 756	if (!parent_ref)
 757		return -EINVAL;
 758	xa_for_each(&parent->dpll_refs, i, dpll_ref) {
 759		ops = dpll_pin_ops(parent_ref);
 760		if (!ops->state_on_pin_set)
 761			return -EOPNOTSUPP;
 762		pin_priv = dpll_pin_on_pin_priv(parent, pin);
 763		parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, parent);
 764		ret = ops->state_on_pin_set(pin, pin_priv, parent, parent_priv,
 765					    state, extack);
 766		if (ret)
 767			return ret;
 768	}
 769	__dpll_pin_change_ntf(pin);
 770
 771	return 0;
 772}
 773
 774static int
 775dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin,
 776		   enum dpll_pin_state state,
 777		   struct netlink_ext_ack *extack)
 778{
 779	const struct dpll_pin_ops *ops;
 780	struct dpll_pin_ref *ref;
 781	int ret;
 782
 783	if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE &
 784	      pin->prop.capabilities)) {
 785		NL_SET_ERR_MSG(extack, "state changing is not allowed");
 786		return -EOPNOTSUPP;
 787	}
 788	ref = xa_load(&pin->dpll_refs, dpll->id);
 789	ASSERT_NOT_NULL(ref);
 790	ops = dpll_pin_ops(ref);
 791	if (!ops->state_on_dpll_set)
 792		return -EOPNOTSUPP;
 793	ret = ops->state_on_dpll_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
 794				     dpll, dpll_priv(dpll), state, extack);
 795	if (ret)
 796		return ret;
 797	__dpll_pin_change_ntf(pin);
 798
 799	return 0;
 800}
 801
 802static int
 803dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin,
 804		  u32 prio, struct netlink_ext_ack *extack)
 805{
 806	const struct dpll_pin_ops *ops;
 807	struct dpll_pin_ref *ref;
 808	int ret;
 809
 810	if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE &
 811	      pin->prop.capabilities)) {
 812		NL_SET_ERR_MSG(extack, "prio changing is not allowed");
 813		return -EOPNOTSUPP;
 814	}
 815	ref = xa_load(&pin->dpll_refs, dpll->id);
 816	ASSERT_NOT_NULL(ref);
 817	ops = dpll_pin_ops(ref);
 818	if (!ops->prio_set)
 819		return -EOPNOTSUPP;
 820	ret = ops->prio_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
 821			    dpll_priv(dpll), prio, extack);
 822	if (ret)
 823		return ret;
 824	__dpll_pin_change_ntf(pin);
 825
 826	return 0;
 827}
 828
 829static int
 830dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll,
 831		       enum dpll_pin_direction direction,
 832		       struct netlink_ext_ack *extack)
 833{
 834	const struct dpll_pin_ops *ops;
 835	struct dpll_pin_ref *ref;
 836	int ret;
 837
 838	if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE &
 839	      pin->prop.capabilities)) {
 840		NL_SET_ERR_MSG(extack, "direction changing is not allowed");
 841		return -EOPNOTSUPP;
 842	}
 843	ref = xa_load(&pin->dpll_refs, dpll->id);
 844	ASSERT_NOT_NULL(ref);
 845	ops = dpll_pin_ops(ref);
 846	if (!ops->direction_set)
 847		return -EOPNOTSUPP;
 848	ret = ops->direction_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
 849				 dpll, dpll_priv(dpll), direction, extack);
 850	if (ret)
 851		return ret;
 852	__dpll_pin_change_ntf(pin);
 853
 854	return 0;
 855}
 856
 857static int
 858dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
 859		       struct netlink_ext_ack *extack)
 860{
 861	struct dpll_pin_ref *ref, *failed;
 862	const struct dpll_pin_ops *ops;
 863	s32 phase_adj, old_phase_adj;
 864	struct dpll_device *dpll;
 865	unsigned long i;
 866	int ret;
 867
 868	phase_adj = nla_get_s32(phase_adj_attr);
 869	if (phase_adj > pin->prop.phase_range.max ||
 870	    phase_adj < pin->prop.phase_range.min) {
 871		NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr,
 872				    "phase adjust value not supported");
 873		return -EINVAL;
 874	}
 875
 876	xa_for_each(&pin->dpll_refs, i, ref) {
 877		ops = dpll_pin_ops(ref);
 878		if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
 879			NL_SET_ERR_MSG(extack, "phase adjust not supported");
 880			return -EOPNOTSUPP;
 881		}
 882	}
 883	ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
 884	ops = dpll_pin_ops(ref);
 885	dpll = ref->dpll;
 886	ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
 887				    dpll, dpll_priv(dpll), &old_phase_adj,
 888				    extack);
 889	if (ret) {
 890		NL_SET_ERR_MSG(extack, "unable to get old phase adjust value");
 891		return ret;
 892	}
 893	if (phase_adj == old_phase_adj)
 894		return 0;
 895
 896	xa_for_each(&pin->dpll_refs, i, ref) {
 897		ops = dpll_pin_ops(ref);
 898		dpll = ref->dpll;
 899		ret = ops->phase_adjust_set(pin,
 900					    dpll_pin_on_dpll_priv(dpll, pin),
 901					    dpll, dpll_priv(dpll), phase_adj,
 902					    extack);
 903		if (ret) {
 904			failed = ref;
 905			NL_SET_ERR_MSG_FMT(extack,
 906					   "phase adjust set failed for dpll_id:%u",
 907					   dpll->id);
 908			goto rollback;
 909		}
 910	}
 911	__dpll_pin_change_ntf(pin);
 912
 913	return 0;
 914
 915rollback:
 916	xa_for_each(&pin->dpll_refs, i, ref) {
 917		if (ref == failed)
 918			break;
 919		ops = dpll_pin_ops(ref);
 920		dpll = ref->dpll;
 921		if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
 922					  dpll, dpll_priv(dpll), old_phase_adj,
 923					  extack))
 924			NL_SET_ERR_MSG(extack, "set phase adjust rollback failed");
 925	}
 926	return ret;
 927}
 928
 929static int
 930dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
 931			   struct netlink_ext_ack *extack)
 932{
 933	struct nlattr *tb[DPLL_A_PIN_MAX + 1];
 934	enum dpll_pin_direction direction;
 935	enum dpll_pin_state state;
 936	struct dpll_pin_ref *ref;
 937	struct dpll_device *dpll;
 938	u32 pdpll_idx, prio;
 939	int ret;
 940
 941	nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest,
 942			 dpll_pin_parent_device_nl_policy, extack);
 943	if (!tb[DPLL_A_PIN_PARENT_ID]) {
 944		NL_SET_ERR_MSG(extack, "device parent id expected");
 945		return -EINVAL;
 946	}
 947	pdpll_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
 948	dpll = xa_load(&dpll_device_xa, pdpll_idx);
 949	if (!dpll) {
 950		NL_SET_ERR_MSG(extack, "parent device not found");
 951		return -EINVAL;
 952	}
 953	ref = xa_load(&pin->dpll_refs, dpll->id);
 954	if (!ref) {
 955		NL_SET_ERR_MSG(extack, "pin not connected to given parent device");
 956		return -EINVAL;
 957	}
 958	if (tb[DPLL_A_PIN_STATE]) {
 959		state = nla_get_u32(tb[DPLL_A_PIN_STATE]);
 960		ret = dpll_pin_state_set(dpll, pin, state, extack);
 961		if (ret)
 962			return ret;
 963	}
 964	if (tb[DPLL_A_PIN_PRIO]) {
 965		prio = nla_get_u32(tb[DPLL_A_PIN_PRIO]);
 966		ret = dpll_pin_prio_set(dpll, pin, prio, extack);
 967		if (ret)
 968			return ret;
 969	}
 970	if (tb[DPLL_A_PIN_DIRECTION]) {
 971		direction = nla_get_u32(tb[DPLL_A_PIN_DIRECTION]);
 972		ret = dpll_pin_direction_set(pin, dpll, direction, extack);
 973		if (ret)
 974			return ret;
 975	}
 976	return 0;
 977}
 978
 979static int
 980dpll_pin_parent_pin_set(struct dpll_pin *pin, struct nlattr *parent_nest,
 981			struct netlink_ext_ack *extack)
 982{
 983	struct nlattr *tb[DPLL_A_PIN_MAX + 1];
 984	u32 ppin_idx;
 985	int ret;
 986
 987	nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest,
 988			 dpll_pin_parent_pin_nl_policy, extack);
 989	if (!tb[DPLL_A_PIN_PARENT_ID]) {
 990		NL_SET_ERR_MSG(extack, "device parent id expected");
 991		return -EINVAL;
 992	}
 993	ppin_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
 994
 995	if (tb[DPLL_A_PIN_STATE]) {
 996		enum dpll_pin_state state = nla_get_u32(tb[DPLL_A_PIN_STATE]);
 997
 998		ret = dpll_pin_on_pin_state_set(pin, ppin_idx, state, extack);
 999		if (ret)
1000			return ret;
1001	}
1002
1003	return 0;
1004}
1005
1006static int
1007dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info)
1008{
1009	struct nlattr *a;
1010	int rem, ret;
1011
1012	nla_for_each_attr(a, genlmsg_data(info->genlhdr),
1013			  genlmsg_len(info->genlhdr), rem) {
1014		switch (nla_type(a)) {
1015		case DPLL_A_PIN_FREQUENCY:
1016			ret = dpll_pin_freq_set(pin, a, info->extack);
1017			if (ret)
1018				return ret;
1019			break;
1020		case DPLL_A_PIN_PHASE_ADJUST:
1021			ret = dpll_pin_phase_adj_set(pin, a, info->extack);
1022			if (ret)
1023				return ret;
1024			break;
1025		case DPLL_A_PIN_PARENT_DEVICE:
1026			ret = dpll_pin_parent_device_set(pin, a, info->extack);
1027			if (ret)
1028				return ret;
1029			break;
1030		case DPLL_A_PIN_PARENT_PIN:
1031			ret = dpll_pin_parent_pin_set(pin, a, info->extack);
1032			if (ret)
1033				return ret;
1034			break;
1035		}
1036	}
1037
1038	return 0;
1039}
1040
1041static struct dpll_pin *
1042dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr,
1043	      enum dpll_pin_type type, struct nlattr *board_label,
1044	      struct nlattr *panel_label, struct nlattr *package_label,
1045	      struct netlink_ext_ack *extack)
1046{
1047	bool board_match, panel_match, package_match;
1048	struct dpll_pin *pin_match = NULL, *pin;
1049	const struct dpll_pin_properties *prop;
1050	bool cid_match, mod_match, type_match;
1051	unsigned long i;
1052
1053	xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) {
1054		prop = &pin->prop;
1055		cid_match = clock_id ? pin->clock_id == clock_id : true;
1056		mod_match = mod_name_attr && module_name(pin->module) ?
1057			!nla_strcmp(mod_name_attr,
1058				    module_name(pin->module)) : true;
1059		type_match = type ? prop->type == type : true;
1060		board_match = board_label ? (prop->board_label ?
1061			!nla_strcmp(board_label, prop->board_label) : false) :
1062			true;
1063		panel_match = panel_label ? (prop->panel_label ?
1064			!nla_strcmp(panel_label, prop->panel_label) : false) :
1065			true;
1066		package_match = package_label ? (prop->package_label ?
1067			!nla_strcmp(package_label, prop->package_label) :
1068			false) : true;
1069		if (cid_match && mod_match && type_match && board_match &&
1070		    panel_match && package_match) {
1071			if (pin_match) {
1072				NL_SET_ERR_MSG(extack, "multiple matches");
1073				return ERR_PTR(-EINVAL);
1074			}
1075			pin_match = pin;
1076		}
1077	}
1078	if (!pin_match) {
1079		NL_SET_ERR_MSG(extack, "not found");
1080		return ERR_PTR(-ENODEV);
1081	}
1082	return pin_match;
1083}
1084
1085static struct dpll_pin *dpll_pin_find_from_nlattr(struct genl_info *info)
1086{
1087	struct nlattr *attr, *mod_name_attr = NULL, *board_label_attr = NULL,
1088		*panel_label_attr = NULL, *package_label_attr = NULL;
1089	enum dpll_pin_type type = 0;
1090	u64 clock_id = 0;
1091	int rem = 0;
1092
1093	nla_for_each_attr(attr, genlmsg_data(info->genlhdr),
1094			  genlmsg_len(info->genlhdr), rem) {
1095		switch (nla_type(attr)) {
1096		case DPLL_A_PIN_CLOCK_ID:
1097			if (clock_id)
1098				goto duplicated_attr;
1099			clock_id = nla_get_u64(attr);
1100			break;
1101		case DPLL_A_PIN_MODULE_NAME:
1102			if (mod_name_attr)
1103				goto duplicated_attr;
1104			mod_name_attr = attr;
1105			break;
1106		case DPLL_A_PIN_TYPE:
1107			if (type)
1108				goto duplicated_attr;
1109			type = nla_get_u32(attr);
1110		break;
1111		case DPLL_A_PIN_BOARD_LABEL:
1112			if (board_label_attr)
1113				goto duplicated_attr;
1114			board_label_attr = attr;
1115		break;
1116		case DPLL_A_PIN_PANEL_LABEL:
1117			if (panel_label_attr)
1118				goto duplicated_attr;
1119			panel_label_attr = attr;
1120		break;
1121		case DPLL_A_PIN_PACKAGE_LABEL:
1122			if (package_label_attr)
1123				goto duplicated_attr;
1124			package_label_attr = attr;
1125		break;
1126		default:
1127			break;
1128		}
1129	}
1130	if (!(clock_id  || mod_name_attr || board_label_attr ||
1131	      panel_label_attr || package_label_attr)) {
1132		NL_SET_ERR_MSG(info->extack, "missing attributes");
1133		return ERR_PTR(-EINVAL);
1134	}
1135	return dpll_pin_find(clock_id, mod_name_attr, type, board_label_attr,
1136			     panel_label_attr, package_label_attr,
1137			     info->extack);
1138duplicated_attr:
1139	NL_SET_ERR_MSG(info->extack, "duplicated attribute");
1140	return ERR_PTR(-EINVAL);
1141}
1142
1143int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info)
1144{
1145	struct dpll_pin *pin;
1146	struct sk_buff *msg;
1147	struct nlattr *hdr;
1148	int ret;
1149
1150	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1151	if (!msg)
1152		return -ENOMEM;
1153	hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1154				DPLL_CMD_PIN_ID_GET);
1155	if (!hdr) {
1156		nlmsg_free(msg);
1157		return -EMSGSIZE;
1158	}
1159	pin = dpll_pin_find_from_nlattr(info);
1160	if (!IS_ERR(pin)) {
1161		if (!dpll_pin_available(pin)) {
1162			nlmsg_free(msg);
1163			return -ENODEV;
1164		}
1165		ret = dpll_msg_add_pin_handle(msg, pin);
1166		if (ret) {
1167			nlmsg_free(msg);
1168			return ret;
1169		}
1170	}
1171	genlmsg_end(msg, hdr);
1172
1173	return genlmsg_reply(msg, info);
1174}
1175
1176int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info)
1177{
1178	struct dpll_pin *pin = info->user_ptr[0];
1179	struct sk_buff *msg;
1180	struct nlattr *hdr;
1181	int ret;
1182
1183	if (!pin)
1184		return -ENODEV;
1185	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1186	if (!msg)
1187		return -ENOMEM;
1188	hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1189				DPLL_CMD_PIN_GET);
1190	if (!hdr) {
1191		nlmsg_free(msg);
1192		return -EMSGSIZE;
1193	}
1194	ret = dpll_cmd_pin_get_one(msg, pin, info->extack);
1195	if (ret) {
1196		nlmsg_free(msg);
1197		return ret;
1198	}
1199	genlmsg_end(msg, hdr);
1200
1201	return genlmsg_reply(msg, info);
1202}
1203
1204int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
1205{
1206	struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
1207	struct dpll_pin *pin;
1208	struct nlattr *hdr;
1209	unsigned long i;
1210	int ret = 0;
1211
1212	mutex_lock(&dpll_lock);
1213	xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED,
1214				 ctx->idx) {
1215		if (!dpll_pin_available(pin))
1216			continue;
1217		hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
1218				  cb->nlh->nlmsg_seq,
1219				  &dpll_nl_family, NLM_F_MULTI,
1220				  DPLL_CMD_PIN_GET);
1221		if (!hdr) {
1222			ret = -EMSGSIZE;
1223			break;
1224		}
1225		ret = dpll_cmd_pin_get_one(skb, pin, cb->extack);
1226		if (ret) {
1227			genlmsg_cancel(skb, hdr);
1228			break;
1229		}
1230		genlmsg_end(skb, hdr);
1231	}
1232	mutex_unlock(&dpll_lock);
1233
1234	if (ret == -EMSGSIZE) {
1235		ctx->idx = i;
1236		return skb->len;
1237	}
1238	return ret;
1239}
1240
1241int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info)
1242{
1243	struct dpll_pin *pin = info->user_ptr[0];
1244
1245	return dpll_pin_set_from_nlattr(pin, info);
1246}
1247
1248static struct dpll_device *
1249dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr,
1250		 enum dpll_type type, struct netlink_ext_ack *extack)
1251{
1252	struct dpll_device *dpll_match = NULL, *dpll;
1253	bool cid_match, mod_match, type_match;
1254	unsigned long i;
1255
1256	xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) {
1257		cid_match = clock_id ? dpll->clock_id == clock_id : true;
1258		mod_match = mod_name_attr ? (module_name(dpll->module) ?
1259			!nla_strcmp(mod_name_attr,
1260				    module_name(dpll->module)) : false) : true;
1261		type_match = type ? dpll->type == type : true;
1262		if (cid_match && mod_match && type_match) {
1263			if (dpll_match) {
1264				NL_SET_ERR_MSG(extack, "multiple matches");
1265				return ERR_PTR(-EINVAL);
1266			}
1267			dpll_match = dpll;
1268		}
1269	}
1270	if (!dpll_match) {
1271		NL_SET_ERR_MSG(extack, "not found");
1272		return ERR_PTR(-ENODEV);
1273	}
1274
1275	return dpll_match;
1276}
1277
1278static struct dpll_device *
1279dpll_device_find_from_nlattr(struct genl_info *info)
1280{
1281	struct nlattr *attr, *mod_name_attr = NULL;
1282	enum dpll_type type = 0;
1283	u64 clock_id = 0;
1284	int rem = 0;
1285
1286	nla_for_each_attr(attr, genlmsg_data(info->genlhdr),
1287			  genlmsg_len(info->genlhdr), rem) {
1288		switch (nla_type(attr)) {
1289		case DPLL_A_CLOCK_ID:
1290			if (clock_id)
1291				goto duplicated_attr;
1292			clock_id = nla_get_u64(attr);
1293			break;
1294		case DPLL_A_MODULE_NAME:
1295			if (mod_name_attr)
1296				goto duplicated_attr;
1297			mod_name_attr = attr;
1298			break;
1299		case DPLL_A_TYPE:
1300			if (type)
1301				goto duplicated_attr;
1302			type = nla_get_u32(attr);
1303			break;
1304		default:
1305			break;
1306		}
1307	}
1308	if (!clock_id && !mod_name_attr && !type) {
1309		NL_SET_ERR_MSG(info->extack, "missing attributes");
1310		return ERR_PTR(-EINVAL);
1311	}
1312	return dpll_device_find(clock_id, mod_name_attr, type, info->extack);
1313duplicated_attr:
1314	NL_SET_ERR_MSG(info->extack, "duplicated attribute");
1315	return ERR_PTR(-EINVAL);
1316}
1317
1318int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info)
1319{
1320	struct dpll_device *dpll;
1321	struct sk_buff *msg;
1322	struct nlattr *hdr;
1323	int ret;
1324
1325	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1326	if (!msg)
1327		return -ENOMEM;
1328	hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1329				DPLL_CMD_DEVICE_ID_GET);
1330	if (!hdr) {
1331		nlmsg_free(msg);
1332		return -EMSGSIZE;
1333	}
1334
1335	dpll = dpll_device_find_from_nlattr(info);
1336	if (!IS_ERR(dpll)) {
1337		ret = dpll_msg_add_dev_handle(msg, dpll);
1338		if (ret) {
1339			nlmsg_free(msg);
1340			return ret;
1341		}
1342	}
1343	genlmsg_end(msg, hdr);
1344
1345	return genlmsg_reply(msg, info);
1346}
1347
1348int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info)
1349{
1350	struct dpll_device *dpll = info->user_ptr[0];
1351	struct sk_buff *msg;
1352	struct nlattr *hdr;
1353	int ret;
1354
1355	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1356	if (!msg)
1357		return -ENOMEM;
1358	hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1359				DPLL_CMD_DEVICE_GET);
1360	if (!hdr) {
1361		nlmsg_free(msg);
1362		return -EMSGSIZE;
1363	}
1364
1365	ret = dpll_device_get_one(dpll, msg, info->extack);
1366	if (ret) {
1367		nlmsg_free(msg);
1368		return ret;
1369	}
1370	genlmsg_end(msg, hdr);
1371
1372	return genlmsg_reply(msg, info);
1373}
1374
1375int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info)
1376{
1377	/* placeholder for set command */
1378	return 0;
1379}
1380
1381int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
1382{
1383	struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
1384	struct dpll_device *dpll;
1385	struct nlattr *hdr;
1386	unsigned long i;
1387	int ret = 0;
1388
1389	mutex_lock(&dpll_lock);
1390	xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED,
1391				 ctx->idx) {
1392		hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
1393				  cb->nlh->nlmsg_seq, &dpll_nl_family,
1394				  NLM_F_MULTI, DPLL_CMD_DEVICE_GET);
1395		if (!hdr) {
1396			ret = -EMSGSIZE;
1397			break;
1398		}
1399		ret = dpll_device_get_one(dpll, skb, cb->extack);
1400		if (ret) {
1401			genlmsg_cancel(skb, hdr);
1402			break;
1403		}
1404		genlmsg_end(skb, hdr);
1405	}
1406	mutex_unlock(&dpll_lock);
1407
1408	if (ret == -EMSGSIZE) {
1409		ctx->idx = i;
1410		return skb->len;
1411	}
1412	return ret;
1413}
1414
1415int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1416		  struct genl_info *info)
1417{
1418	u32 id;
1419
1420	if (GENL_REQ_ATTR_CHECK(info, DPLL_A_ID))
1421		return -EINVAL;
1422
1423	mutex_lock(&dpll_lock);
1424	id = nla_get_u32(info->attrs[DPLL_A_ID]);
1425	info->user_ptr[0] = dpll_device_get_by_id(id);
1426	if (!info->user_ptr[0]) {
1427		NL_SET_ERR_MSG(info->extack, "device not found");
1428		goto unlock;
1429	}
1430	return 0;
1431unlock:
1432	mutex_unlock(&dpll_lock);
1433	return -ENODEV;
1434}
1435
1436void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1437		    struct genl_info *info)
1438{
1439	mutex_unlock(&dpll_lock);
1440}
1441
1442int
1443dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1444	       struct genl_info *info)
1445{
1446	mutex_lock(&dpll_lock);
1447
1448	return 0;
1449}
1450
1451void
1452dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1453		 struct genl_info *info)
1454{
1455	mutex_unlock(&dpll_lock);
1456}
1457
1458int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1459		      struct genl_info *info)
1460{
1461	int ret;
1462
1463	mutex_lock(&dpll_lock);
1464	if (GENL_REQ_ATTR_CHECK(info, DPLL_A_PIN_ID)) {
1465		ret = -EINVAL;
1466		goto unlock_dev;
1467	}
1468	info->user_ptr[0] = xa_load(&dpll_pin_xa,
1469				    nla_get_u32(info->attrs[DPLL_A_PIN_ID]));
1470	if (!info->user_ptr[0] ||
1471	    !dpll_pin_available(info->user_ptr[0])) {
1472		NL_SET_ERR_MSG(info->extack, "pin not found");
1473		ret = -ENODEV;
1474		goto unlock_dev;
1475	}
1476
1477	return 0;
1478
1479unlock_dev:
1480	mutex_unlock(&dpll_lock);
1481	return ret;
1482}
1483
1484void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1485			struct genl_info *info)
1486{
1487	mutex_unlock(&dpll_lock);
1488}