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}
1496