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