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