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