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