Linux Audio

Check our new training course

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