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