1// SPDX-License-Identifier: GPL-2.0
2/*
3 * dpll_core.c - DPLL subsystem kernel-space interface implementation.
4 *
5 * Copyright (c) 2023 Meta Platforms, Inc. and affiliates
6 * Copyright (c) 2023 Intel Corporation.
7 */
8
9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10
11#include <linux/device.h>
12#include <linux/err.h>
13#include <linux/slab.h>
14#include <linux/string.h>
15
16#include "dpll_core.h"
17#include "dpll_netlink.h"
18
19/* Mutex lock to protect DPLL subsystem devices and pins */
20DEFINE_MUTEX(dpll_lock);
21
22DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC);
23DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC);
24
25static u32 dpll_device_xa_id;
26static u32 dpll_pin_xa_id;
27
28#define ASSERT_DPLL_REGISTERED(d) \
29 WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))
30#define ASSERT_DPLL_NOT_REGISTERED(d) \
31 WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))
32#define ASSERT_DPLL_PIN_REGISTERED(p) \
33 WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED))
34
35struct dpll_device_registration {
36 struct list_head list;
37 const struct dpll_device_ops *ops;
38 void *priv;
39};
40
41struct dpll_pin_registration {
42 struct list_head list;
43 const struct dpll_pin_ops *ops;
44 void *priv;
45};
46
47struct dpll_device *dpll_device_get_by_id(int id)
48{
49 if (xa_get_mark(&dpll_device_xa, index: id, DPLL_REGISTERED))
50 return xa_load(&dpll_device_xa, index: id);
51
52 return NULL;
53}
54
55static struct dpll_pin_registration *
56dpll_pin_registration_find(struct dpll_pin_ref *ref,
57 const struct dpll_pin_ops *ops, void *priv)
58{
59 struct dpll_pin_registration *reg;
60
61 list_for_each_entry(reg, &ref->registration_list, list) {
62 if (reg->ops == ops && reg->priv == priv)
63 return reg;
64 }
65 return NULL;
66}
67
68static int
69dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin,
70 const struct dpll_pin_ops *ops, void *priv)
71{
72 struct dpll_pin_registration *reg;
73 struct dpll_pin_ref *ref;
74 bool ref_exists = false;
75 unsigned long i;
76 int ret;
77
78 xa_for_each(xa_pins, i, ref) {
79 if (ref->pin != pin)
80 continue;
81 reg = dpll_pin_registration_find(ref, ops, priv);
82 if (reg) {
83 refcount_inc(r: &ref->refcount);
84 return 0;
85 }
86 ref_exists = true;
87 break;
88 }
89
90 if (!ref_exists) {
91 ref = kzalloc(size: sizeof(*ref), GFP_KERNEL);
92 if (!ref)
93 return -ENOMEM;
94 ref->pin = pin;
95 INIT_LIST_HEAD(list: &ref->registration_list);
96 ret = xa_insert(xa: xa_pins, index: pin->pin_idx, entry: ref, GFP_KERNEL);
97 if (ret) {
98 kfree(objp: ref);
99 return ret;
100 }
101 refcount_set(r: &ref->refcount, n: 1);
102 }
103
104 reg = kzalloc(size: sizeof(*reg), GFP_KERNEL);
105 if (!reg) {
106 if (!ref_exists) {
107 xa_erase(xa_pins, index: pin->pin_idx);
108 kfree(objp: ref);
109 }
110 return -ENOMEM;
111 }
112 reg->ops = ops;
113 reg->priv = priv;
114 if (ref_exists)
115 refcount_inc(r: &ref->refcount);
116 list_add_tail(new: &reg->list, head: &ref->registration_list);
117
118 return 0;
119}
120
121static int dpll_xa_ref_pin_del(struct xarray *xa_pins, struct dpll_pin *pin,
122 const struct dpll_pin_ops *ops, void *priv)
123{
124 struct dpll_pin_registration *reg;
125 struct dpll_pin_ref *ref;
126 unsigned long i;
127
128 xa_for_each(xa_pins, i, ref) {
129 if (ref->pin != pin)
130 continue;
131 reg = dpll_pin_registration_find(ref, ops, priv);
132 if (WARN_ON(!reg))
133 return -EINVAL;
134 list_del(entry: &reg->list);
135 kfree(objp: reg);
136 if (refcount_dec_and_test(r: &ref->refcount)) {
137 xa_erase(xa_pins, index: i);
138 WARN_ON(!list_empty(&ref->registration_list));
139 kfree(objp: ref);
140 }
141 return 0;
142 }
143
144 return -EINVAL;
145}
146
147static int
148dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll,
149 const struct dpll_pin_ops *ops, void *priv)
150{
151 struct dpll_pin_registration *reg;
152 struct dpll_pin_ref *ref;
153 bool ref_exists = false;
154 unsigned long i;
155 int ret;
156
157 xa_for_each(xa_dplls, i, ref) {
158 if (ref->dpll != dpll)
159 continue;
160 reg = dpll_pin_registration_find(ref, ops, priv);
161 if (reg) {
162 refcount_inc(r: &ref->refcount);
163 return 0;
164 }
165 ref_exists = true;
166 break;
167 }
168
169 if (!ref_exists) {
170 ref = kzalloc(size: sizeof(*ref), GFP_KERNEL);
171 if (!ref)
172 return -ENOMEM;
173 ref->dpll = dpll;
174 INIT_LIST_HEAD(list: &ref->registration_list);
175 ret = xa_insert(xa: xa_dplls, index: dpll->id, entry: ref, GFP_KERNEL);
176 if (ret) {
177 kfree(objp: ref);
178 return ret;
179 }
180 refcount_set(r: &ref->refcount, n: 1);
181 }
182
183 reg = kzalloc(size: sizeof(*reg), GFP_KERNEL);
184 if (!reg) {
185 if (!ref_exists) {
186 xa_erase(xa_dplls, index: dpll->id);
187 kfree(objp: ref);
188 }
189 return -ENOMEM;
190 }
191 reg->ops = ops;
192 reg->priv = priv;
193 if (ref_exists)
194 refcount_inc(r: &ref->refcount);
195 list_add_tail(new: &reg->list, head: &ref->registration_list);
196
197 return 0;
198}
199
200static void
201dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll,
202 const struct dpll_pin_ops *ops, void *priv)
203{
204 struct dpll_pin_registration *reg;
205 struct dpll_pin_ref *ref;
206 unsigned long i;
207
208 xa_for_each(xa_dplls, i, ref) {
209 if (ref->dpll != dpll)
210 continue;
211 reg = dpll_pin_registration_find(ref, ops, priv);
212 if (WARN_ON(!reg))
213 return;
214 list_del(entry: &reg->list);
215 kfree(objp: reg);
216 if (refcount_dec_and_test(r: &ref->refcount)) {
217 xa_erase(xa_dplls, index: i);
218 WARN_ON(!list_empty(&ref->registration_list));
219 kfree(objp: ref);
220 }
221 return;
222 }
223}
224
225struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs)
226{
227 struct dpll_pin_ref *ref;
228 unsigned long i = 0;
229
230 ref = xa_find(xa: xa_refs, index: &i, ULONG_MAX, XA_PRESENT);
231 WARN_ON(!ref);
232 return ref;
233}
234
235static struct dpll_device *
236dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module)
237{
238 struct dpll_device *dpll;
239 int ret;
240
241 dpll = kzalloc(size: sizeof(*dpll), GFP_KERNEL);
242 if (!dpll)
243 return ERR_PTR(error: -ENOMEM);
244 refcount_set(r: &dpll->refcount, n: 1);
245 INIT_LIST_HEAD(list: &dpll->registration_list);
246 dpll->device_idx = device_idx;
247 dpll->clock_id = clock_id;
248 dpll->module = module;
249 ret = xa_alloc_cyclic(xa: &dpll_device_xa, id: &dpll->id, entry: dpll, xa_limit_32b,
250 next: &dpll_device_xa_id, GFP_KERNEL);
251 if (ret < 0) {
252 kfree(objp: dpll);
253 return ERR_PTR(error: ret);
254 }
255 xa_init_flags(xa: &dpll->pin_refs, XA_FLAGS_ALLOC);
256
257 return dpll;
258}
259
260/**
261 * dpll_device_get - find existing or create new dpll device
262 * @clock_id: clock_id of creator
263 * @device_idx: idx given by device driver
264 * @module: reference to registering module
265 *
266 * Get existing object of a dpll device, unique for given arguments.
267 * Create new if doesn't exist yet.
268 *
269 * Context: Acquires a lock (dpll_lock)
270 * Return:
271 * * valid dpll_device struct pointer if succeeded
272 * * ERR_PTR(X) - error
273 */
274struct dpll_device *
275dpll_device_get(u64 clock_id, u32 device_idx, struct module *module)
276{
277 struct dpll_device *dpll, *ret = NULL;
278 unsigned long index;
279
280 mutex_lock(&dpll_lock);
281 xa_for_each(&dpll_device_xa, index, dpll) {
282 if (dpll->clock_id == clock_id &&
283 dpll->device_idx == device_idx &&
284 dpll->module == module) {
285 ret = dpll;
286 refcount_inc(r: &ret->refcount);
287 break;
288 }
289 }
290 if (!ret)
291 ret = dpll_device_alloc(clock_id, device_idx, module);
292 mutex_unlock(lock: &dpll_lock);
293
294 return ret;
295}
296EXPORT_SYMBOL_GPL(dpll_device_get);
297
298/**
299 * dpll_device_put - decrease the refcount and free memory if possible
300 * @dpll: dpll_device struct pointer
301 *
302 * Context: Acquires a lock (dpll_lock)
303 * Drop reference for a dpll device, if all references are gone, delete
304 * dpll device object.
305 */
306void dpll_device_put(struct dpll_device *dpll)
307{
308 mutex_lock(&dpll_lock);
309 if (refcount_dec_and_test(r: &dpll->refcount)) {
310 ASSERT_DPLL_NOT_REGISTERED(dpll);
311 WARN_ON_ONCE(!xa_empty(&dpll->pin_refs));
312 xa_destroy(&dpll->pin_refs);
313 xa_erase(&dpll_device_xa, index: dpll->id);
314 WARN_ON(!list_empty(&dpll->registration_list));
315 kfree(objp: dpll);
316 }
317 mutex_unlock(lock: &dpll_lock);
318}
319EXPORT_SYMBOL_GPL(dpll_device_put);
320
321static struct dpll_device_registration *
322dpll_device_registration_find(struct dpll_device *dpll,
323 const struct dpll_device_ops *ops, void *priv)
324{
325 struct dpll_device_registration *reg;
326
327 list_for_each_entry(reg, &dpll->registration_list, list) {
328 if (reg->ops == ops && reg->priv == priv)
329 return reg;
330 }
331 return NULL;
332}
333
334/**
335 * dpll_device_register - register the dpll device in the subsystem
336 * @dpll: pointer to a dpll
337 * @type: type of a dpll
338 * @ops: ops for a dpll device
339 * @priv: pointer to private information of owner
340 *
341 * Make dpll device available for user space.
342 *
343 * Context: Acquires a lock (dpll_lock)
344 * Return:
345 * * 0 on success
346 * * negative - error value
347 */
348int dpll_device_register(struct dpll_device *dpll, enum dpll_type type,
349 const struct dpll_device_ops *ops, void *priv)
350{
351 struct dpll_device_registration *reg;
352 bool first_registration = false;
353
354 if (WARN_ON(!ops))
355 return -EINVAL;
356 if (WARN_ON(!ops->mode_get))
357 return -EINVAL;
358 if (WARN_ON(!ops->lock_status_get))
359 return -EINVAL;
360 if (WARN_ON(type < DPLL_TYPE_PPS || type > DPLL_TYPE_MAX))
361 return -EINVAL;
362
363 mutex_lock(&dpll_lock);
364 reg = dpll_device_registration_find(dpll, ops, priv);
365 if (reg) {
366 mutex_unlock(lock: &dpll_lock);
367 return -EEXIST;
368 }
369
370 reg = kzalloc(size: sizeof(*reg), GFP_KERNEL);
371 if (!reg) {
372 mutex_unlock(lock: &dpll_lock);
373 return -ENOMEM;
374 }
375 reg->ops = ops;
376 reg->priv = priv;
377 dpll->type = type;
378 first_registration = list_empty(head: &dpll->registration_list);
379 list_add_tail(new: &reg->list, head: &dpll->registration_list);
380 if (!first_registration) {
381 mutex_unlock(lock: &dpll_lock);
382 return 0;
383 }
384
385 xa_set_mark(&dpll_device_xa, index: dpll->id, DPLL_REGISTERED);
386 dpll_device_create_ntf(dpll);
387 mutex_unlock(lock: &dpll_lock);
388
389 return 0;
390}
391EXPORT_SYMBOL_GPL(dpll_device_register);
392
393/**
394 * dpll_device_unregister - unregister dpll device
395 * @dpll: registered dpll pointer
396 * @ops: ops for a dpll device
397 * @priv: pointer to private information of owner
398 *
399 * Unregister device, make it unavailable for userspace.
400 * Note: It does not free the memory
401 * Context: Acquires a lock (dpll_lock)
402 */
403void dpll_device_unregister(struct dpll_device *dpll,
404 const struct dpll_device_ops *ops, void *priv)
405{
406 struct dpll_device_registration *reg;
407
408 mutex_lock(&dpll_lock);
409 ASSERT_DPLL_REGISTERED(dpll);
410 dpll_device_delete_ntf(dpll);
411 reg = dpll_device_registration_find(dpll, ops, priv);
412 if (WARN_ON(!reg)) {
413 mutex_unlock(lock: &dpll_lock);
414 return;
415 }
416 list_del(entry: &reg->list);
417 kfree(objp: reg);
418
419 if (!list_empty(head: &dpll->registration_list)) {
420 mutex_unlock(lock: &dpll_lock);
421 return;
422 }
423 xa_clear_mark(&dpll_device_xa, index: dpll->id, DPLL_REGISTERED);
424 mutex_unlock(lock: &dpll_lock);
425}
426EXPORT_SYMBOL_GPL(dpll_device_unregister);
427
428static void dpll_pin_prop_free(struct dpll_pin_properties *prop)
429{
430 kfree(objp: prop->package_label);
431 kfree(objp: prop->panel_label);
432 kfree(objp: prop->board_label);
433 kfree(objp: prop->freq_supported);
434}
435
436static int dpll_pin_prop_dup(const struct dpll_pin_properties *src,
437 struct dpll_pin_properties *dst)
438{
439 memcpy(dst, src, sizeof(*dst));
440 if (src->freq_supported && src->freq_supported_num) {
441 size_t freq_size = src->freq_supported_num *
442 sizeof(*src->freq_supported);
443 dst->freq_supported = kmemdup(p: src->freq_supported,
444 size: freq_size, GFP_KERNEL);
445 if (!src->freq_supported)
446 return -ENOMEM;
447 }
448 if (src->board_label) {
449 dst->board_label = kstrdup(s: src->board_label, GFP_KERNEL);
450 if (!dst->board_label)
451 goto err_board_label;
452 }
453 if (src->panel_label) {
454 dst->panel_label = kstrdup(s: src->panel_label, GFP_KERNEL);
455 if (!dst->panel_label)
456 goto err_panel_label;
457 }
458 if (src->package_label) {
459 dst->package_label = kstrdup(s: src->package_label, GFP_KERNEL);
460 if (!dst->package_label)
461 goto err_package_label;
462 }
463
464 return 0;
465
466err_package_label:
467 kfree(objp: dst->panel_label);
468err_panel_label:
469 kfree(objp: dst->board_label);
470err_board_label:
471 kfree(objp: dst->freq_supported);
472 return -ENOMEM;
473}
474
475static struct dpll_pin *
476dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
477 const struct dpll_pin_properties *prop)
478{
479 struct dpll_pin *pin;
480 int ret;
481
482 pin = kzalloc(size: sizeof(*pin), GFP_KERNEL);
483 if (!pin)
484 return ERR_PTR(error: -ENOMEM);
485 pin->pin_idx = pin_idx;
486 pin->clock_id = clock_id;
487 pin->module = module;
488 if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX ||
489 prop->type > DPLL_PIN_TYPE_MAX)) {
490 ret = -EINVAL;
491 goto err_pin_prop;
492 }
493 ret = dpll_pin_prop_dup(src: prop, dst: &pin->prop);
494 if (ret)
495 goto err_pin_prop;
496 refcount_set(r: &pin->refcount, n: 1);
497 xa_init_flags(xa: &pin->dpll_refs, XA_FLAGS_ALLOC);
498 xa_init_flags(xa: &pin->parent_refs, XA_FLAGS_ALLOC);
499 ret = xa_alloc_cyclic(xa: &dpll_pin_xa, id: &pin->id, entry: pin, xa_limit_32b,
500 next: &dpll_pin_xa_id, GFP_KERNEL);
501 if (ret)
502 goto err_xa_alloc;
503 return pin;
504err_xa_alloc:
505 xa_destroy(&pin->dpll_refs);
506 xa_destroy(&pin->parent_refs);
507 dpll_pin_prop_free(prop: &pin->prop);
508err_pin_prop:
509 kfree(objp: pin);
510 return ERR_PTR(error: ret);
511}
512
513static void dpll_netdev_pin_assign(struct net_device *dev, struct dpll_pin *dpll_pin)
514{
515 rtnl_lock();
516 rcu_assign_pointer(dev->dpll_pin, dpll_pin);
517 rtnl_unlock();
518}
519
520void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)
521{
522 WARN_ON(!dpll_pin);
523 dpll_netdev_pin_assign(dev, dpll_pin);
524}
525EXPORT_SYMBOL(dpll_netdev_pin_set);
526
527void dpll_netdev_pin_clear(struct net_device *dev)
528{
529 dpll_netdev_pin_assign(dev, NULL);
530}
531EXPORT_SYMBOL(dpll_netdev_pin_clear);
532
533/**
534 * dpll_pin_get - find existing or create new dpll pin
535 * @clock_id: clock_id of creator
536 * @pin_idx: idx given by dev driver
537 * @module: reference to registering module
538 * @prop: dpll pin properties
539 *
540 * Get existing object of a pin (unique for given arguments) or create new
541 * if doesn't exist yet.
542 *
543 * Context: Acquires a lock (dpll_lock)
544 * Return:
545 * * valid allocated dpll_pin struct pointer if succeeded
546 * * ERR_PTR(X) - error
547 */
548struct dpll_pin *
549dpll_pin_get(u64 clock_id, u32 pin_idx, struct module *module,
550 const struct dpll_pin_properties *prop)
551{
552 struct dpll_pin *pos, *ret = NULL;
553 unsigned long i;
554
555 mutex_lock(&dpll_lock);
556 xa_for_each(&dpll_pin_xa, i, pos) {
557 if (pos->clock_id == clock_id &&
558 pos->pin_idx == pin_idx &&
559 pos->module == module) {
560 ret = pos;
561 refcount_inc(r: &ret->refcount);
562 break;
563 }
564 }
565 if (!ret)
566 ret = dpll_pin_alloc(clock_id, pin_idx, module, prop);
567 mutex_unlock(lock: &dpll_lock);
568
569 return ret;
570}
571EXPORT_SYMBOL_GPL(dpll_pin_get);
572
573/**
574 * dpll_pin_put - decrease the refcount and free memory if possible
575 * @pin: pointer to a pin to be put
576 *
577 * Drop reference for a pin, if all references are gone, delete pin object.
578 *
579 * Context: Acquires a lock (dpll_lock)
580 */
581void dpll_pin_put(struct dpll_pin *pin)
582{
583 mutex_lock(&dpll_lock);
584 if (refcount_dec_and_test(r: &pin->refcount)) {
585 xa_erase(&dpll_pin_xa, index: pin->id);
586 xa_destroy(&pin->dpll_refs);
587 xa_destroy(&pin->parent_refs);
588 dpll_pin_prop_free(prop: &pin->prop);
589 kfree_rcu(pin, rcu);
590 }
591 mutex_unlock(lock: &dpll_lock);
592}
593EXPORT_SYMBOL_GPL(dpll_pin_put);
594
595static int
596__dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
597 const struct dpll_pin_ops *ops, void *priv)
598{
599 int ret;
600
601 ret = dpll_xa_ref_pin_add(xa_pins: &dpll->pin_refs, pin, ops, priv);
602 if (ret)
603 return ret;
604 ret = dpll_xa_ref_dpll_add(xa_dplls: &pin->dpll_refs, dpll, ops, priv);
605 if (ret)
606 goto ref_pin_del;
607 xa_set_mark(&dpll_pin_xa, index: pin->id, DPLL_REGISTERED);
608 dpll_pin_create_ntf(pin);
609
610 return ret;
611
612ref_pin_del:
613 dpll_xa_ref_pin_del(xa_pins: &dpll->pin_refs, pin, ops, priv);
614 return ret;
615}
616
617/**
618 * dpll_pin_register - register the dpll pin in the subsystem
619 * @dpll: pointer to a dpll
620 * @pin: pointer to a dpll pin
621 * @ops: ops for a dpll pin ops
622 * @priv: pointer to private information of owner
623 *
624 * Context: Acquires a lock (dpll_lock)
625 * Return:
626 * * 0 on success
627 * * negative - error value
628 */
629int
630dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
631 const struct dpll_pin_ops *ops, void *priv)
632{
633 int ret;
634
635 if (WARN_ON(!ops) ||
636 WARN_ON(!ops->state_on_dpll_get) ||
637 WARN_ON(!ops->direction_get))
638 return -EINVAL;
639
640 mutex_lock(&dpll_lock);
641 if (WARN_ON(!(dpll->module == pin->module &&
642 dpll->clock_id == pin->clock_id)))
643 ret = -EINVAL;
644 else
645 ret = __dpll_pin_register(dpll, pin, ops, priv);
646 mutex_unlock(lock: &dpll_lock);
647
648 return ret;
649}
650EXPORT_SYMBOL_GPL(dpll_pin_register);
651
652static void
653__dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
654 const struct dpll_pin_ops *ops, void *priv)
655{
656 ASSERT_DPLL_PIN_REGISTERED(pin);
657 dpll_xa_ref_pin_del(xa_pins: &dpll->pin_refs, pin, ops, priv);
658 dpll_xa_ref_dpll_del(xa_dplls: &pin->dpll_refs, dpll, ops, priv);
659 if (xa_empty(xa: &pin->dpll_refs))
660 xa_clear_mark(&dpll_pin_xa, index: pin->id, DPLL_REGISTERED);
661}
662
663/**
664 * dpll_pin_unregister - unregister dpll pin from dpll device
665 * @dpll: registered dpll pointer
666 * @pin: pointer to a pin
667 * @ops: ops for a dpll pin
668 * @priv: pointer to private information of owner
669 *
670 * Note: It does not free the memory
671 * Context: Acquires a lock (dpll_lock)
672 */
673void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
674 const struct dpll_pin_ops *ops, void *priv)
675{
676 if (WARN_ON(xa_empty(&dpll->pin_refs)))
677 return;
678 if (WARN_ON(!xa_empty(&pin->parent_refs)))
679 return;
680
681 mutex_lock(&dpll_lock);
682 dpll_pin_delete_ntf(pin);
683 __dpll_pin_unregister(dpll, pin, ops, priv);
684 mutex_unlock(lock: &dpll_lock);
685}
686EXPORT_SYMBOL_GPL(dpll_pin_unregister);
687
688/**
689 * dpll_pin_on_pin_register - register a pin with a parent pin
690 * @parent: pointer to a parent pin
691 * @pin: pointer to a pin
692 * @ops: ops for a dpll pin
693 * @priv: pointer to private information of owner
694 *
695 * Register a pin with a parent pin, create references between them and
696 * between newly registered pin and dplls connected with a parent pin.
697 *
698 * Context: Acquires a lock (dpll_lock)
699 * Return:
700 * * 0 on success
701 * * negative - error value
702 */
703int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
704 const struct dpll_pin_ops *ops, void *priv)
705{
706 struct dpll_pin_ref *ref;
707 unsigned long i, stop;
708 int ret;
709
710 if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX))
711 return -EINVAL;
712
713 if (WARN_ON(!ops) ||
714 WARN_ON(!ops->state_on_pin_get) ||
715 WARN_ON(!ops->direction_get))
716 return -EINVAL;
717
718 mutex_lock(&dpll_lock);
719 ret = dpll_xa_ref_pin_add(xa_pins: &pin->parent_refs, pin: parent, ops, priv);
720 if (ret)
721 goto unlock;
722 refcount_inc(r: &pin->refcount);
723 xa_for_each(&parent->dpll_refs, i, ref) {
724 ret = __dpll_pin_register(dpll: ref->dpll, pin, ops, priv);
725 if (ret) {
726 stop = i;
727 goto dpll_unregister;
728 }
729 dpll_pin_create_ntf(pin);
730 }
731 mutex_unlock(lock: &dpll_lock);
732
733 return ret;
734
735dpll_unregister:
736 xa_for_each(&parent->dpll_refs, i, ref)
737 if (i < stop) {
738 __dpll_pin_unregister(dpll: ref->dpll, pin, ops, priv);
739 dpll_pin_delete_ntf(pin);
740 }
741 refcount_dec(r: &pin->refcount);
742 dpll_xa_ref_pin_del(xa_pins: &pin->parent_refs, pin: parent, ops, priv);
743unlock:
744 mutex_unlock(lock: &dpll_lock);
745 return ret;
746}
747EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register);
748
749/**
750 * dpll_pin_on_pin_unregister - unregister dpll pin from a parent pin
751 * @parent: pointer to a parent pin
752 * @pin: pointer to a pin
753 * @ops: ops for a dpll pin
754 * @priv: pointer to private information of owner
755 *
756 * Context: Acquires a lock (dpll_lock)
757 * Note: It does not free the memory
758 */
759void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
760 const struct dpll_pin_ops *ops, void *priv)
761{
762 struct dpll_pin_ref *ref;
763 unsigned long i;
764
765 mutex_lock(&dpll_lock);
766 dpll_pin_delete_ntf(pin);
767 dpll_xa_ref_pin_del(xa_pins: &pin->parent_refs, pin: parent, ops, priv);
768 refcount_dec(r: &pin->refcount);
769 xa_for_each(&pin->dpll_refs, i, ref)
770 __dpll_pin_unregister(dpll: ref->dpll, pin, ops, priv);
771 mutex_unlock(lock: &dpll_lock);
772}
773EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister);
774
775static struct dpll_device_registration *
776dpll_device_registration_first(struct dpll_device *dpll)
777{
778 struct dpll_device_registration *reg;
779
780 reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list,
781 struct dpll_device_registration, list);
782 WARN_ON(!reg);
783 return reg;
784}
785
786void *dpll_priv(struct dpll_device *dpll)
787{
788 struct dpll_device_registration *reg;
789
790 reg = dpll_device_registration_first(dpll);
791 return reg->priv;
792}
793
794const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll)
795{
796 struct dpll_device_registration *reg;
797
798 reg = dpll_device_registration_first(dpll);
799 return reg->ops;
800}
801
802static struct dpll_pin_registration *
803dpll_pin_registration_first(struct dpll_pin_ref *ref)
804{
805 struct dpll_pin_registration *reg;
806
807 reg = list_first_entry_or_null(&ref->registration_list,
808 struct dpll_pin_registration, list);
809 WARN_ON(!reg);
810 return reg;
811}
812
813void *dpll_pin_on_dpll_priv(struct dpll_device *dpll,
814 struct dpll_pin *pin)
815{
816 struct dpll_pin_registration *reg;
817 struct dpll_pin_ref *ref;
818
819 ref = xa_load(&dpll->pin_refs, index: pin->pin_idx);
820 if (!ref)
821 return NULL;
822 reg = dpll_pin_registration_first(ref);
823 return reg->priv;
824}
825
826void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
827 struct dpll_pin *pin)
828{
829 struct dpll_pin_registration *reg;
830 struct dpll_pin_ref *ref;
831
832 ref = xa_load(&pin->parent_refs, index: parent->pin_idx);
833 if (!ref)
834 return NULL;
835 reg = dpll_pin_registration_first(ref);
836 return reg->priv;
837}
838
839const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
840{
841 struct dpll_pin_registration *reg;
842
843 reg = dpll_pin_registration_first(ref);
844 return reg->ops;
845}
846
847static int __init dpll_init(void)
848{
849 int ret;
850
851 ret = genl_register_family(family: &dpll_nl_family);
852 if (ret)
853 goto error;
854
855 return 0;
856
857error:
858 mutex_destroy(lock: &dpll_lock);
859 return ret;
860}
861
862static void __exit dpll_exit(void)
863{
864 genl_unregister_family(family: &dpll_nl_family);
865 mutex_destroy(lock: &dpll_lock);
866}
867
868subsys_initcall(dpll_init);
869module_exit(dpll_exit);
870

source code of linux/drivers/dpll/dpll_core.c