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