Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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/idr.h>
14#include <linux/property.h>
15#include <linux/slab.h>
16#include <linux/string.h>
17
18#include "dpll_core.h"
19#include "dpll_netlink.h"
20
21/* Mutex lock to protect DPLL subsystem devices and pins */
22DEFINE_MUTEX(dpll_lock);
23
24DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC);
25DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC);
26
27static RAW_NOTIFIER_HEAD(dpll_notifier_chain);
28static DEFINE_IDA(dpll_pin_idx_ida);
29
30static u32 dpll_device_xa_id;
31static u32 dpll_pin_xa_id;
32
33#define ASSERT_DPLL_REGISTERED(d) \
34 WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))
35#define ASSERT_DPLL_NOT_REGISTERED(d) \
36 WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))
37#define ASSERT_DPLL_PIN_REGISTERED(p) \
38 WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED))
39
40struct dpll_device_registration {
41 struct list_head list;
42 const struct dpll_device_ops *ops;
43 void *priv;
44 dpll_tracker tracker;
45};
46
47struct dpll_pin_registration {
48 struct list_head list;
49 const struct dpll_pin_ops *ops;
50 void *priv;
51 void *cookie;
52 dpll_tracker tracker;
53};
54
55static int call_dpll_notifiers(unsigned long action, void *info)
56{
57 lockdep_assert_held(&dpll_lock);
58 return raw_notifier_call_chain(&dpll_notifier_chain, action, info);
59}
60
61void dpll_device_notify(struct dpll_device *dpll, unsigned long action)
62{
63 struct dpll_device_notifier_info info = {
64 .dpll = dpll,
65 .id = dpll->id,
66 .idx = dpll->device_idx,
67 .clock_id = dpll->clock_id,
68 .type = dpll->type,
69 };
70
71 call_dpll_notifiers(action, &info);
72}
73
74void dpll_pin_notify(struct dpll_pin *pin, unsigned long action)
75{
76 struct dpll_pin_notifier_info info = {
77 .pin = pin,
78 .id = pin->id,
79 .idx = pin->pin_idx,
80 .clock_id = pin->clock_id,
81 .fwnode = pin->fwnode,
82 .prop = &pin->prop,
83 };
84
85 call_dpll_notifiers(action, &info);
86}
87
88static void dpll_device_tracker_alloc(struct dpll_device *dpll,
89 dpll_tracker *tracker)
90{
91#ifdef CONFIG_DPLL_REFCNT_TRACKER
92 ref_tracker_alloc(&dpll->refcnt_tracker, tracker, GFP_KERNEL);
93#endif
94}
95
96static void dpll_device_tracker_free(struct dpll_device *dpll,
97 dpll_tracker *tracker)
98{
99#ifdef CONFIG_DPLL_REFCNT_TRACKER
100 ref_tracker_free(&dpll->refcnt_tracker, tracker);
101#endif
102}
103
104static void __dpll_device_hold(struct dpll_device *dpll, dpll_tracker *tracker)
105{
106 dpll_device_tracker_alloc(dpll, tracker);
107 refcount_inc(&dpll->refcount);
108}
109
110static void __dpll_device_put(struct dpll_device *dpll, dpll_tracker *tracker)
111{
112 dpll_device_tracker_free(dpll, tracker);
113 if (refcount_dec_and_test(&dpll->refcount)) {
114 ASSERT_DPLL_NOT_REGISTERED(dpll);
115 WARN_ON_ONCE(!xa_empty(&dpll->pin_refs));
116 xa_destroy(&dpll->pin_refs);
117 xa_erase(&dpll_device_xa, dpll->id);
118 WARN_ON(!list_empty(&dpll->registration_list));
119 ref_tracker_dir_exit(&dpll->refcnt_tracker);
120 kfree(dpll);
121 }
122}
123
124static void dpll_pin_tracker_alloc(struct dpll_pin *pin, dpll_tracker *tracker)
125{
126#ifdef CONFIG_DPLL_REFCNT_TRACKER
127 ref_tracker_alloc(&pin->refcnt_tracker, tracker, GFP_KERNEL);
128#endif
129}
130
131static void dpll_pin_tracker_free(struct dpll_pin *pin, dpll_tracker *tracker)
132{
133#ifdef CONFIG_DPLL_REFCNT_TRACKER
134 ref_tracker_free(&pin->refcnt_tracker, tracker);
135#endif
136}
137
138static void __dpll_pin_hold(struct dpll_pin *pin, dpll_tracker *tracker)
139{
140 dpll_pin_tracker_alloc(pin, tracker);
141 refcount_inc(&pin->refcount);
142}
143
144static void dpll_pin_idx_free(u32 pin_idx);
145static void dpll_pin_prop_free(struct dpll_pin_properties *prop);
146
147static void __dpll_pin_put(struct dpll_pin *pin, dpll_tracker *tracker)
148{
149 dpll_pin_tracker_free(pin, tracker);
150 if (refcount_dec_and_test(&pin->refcount)) {
151 xa_erase(&dpll_pin_xa, pin->id);
152 xa_destroy(&pin->dpll_refs);
153 xa_destroy(&pin->parent_refs);
154 xa_destroy(&pin->ref_sync_pins);
155 dpll_pin_prop_free(&pin->prop);
156 fwnode_handle_put(pin->fwnode);
157 dpll_pin_idx_free(pin->pin_idx);
158 ref_tracker_dir_exit(&pin->refcnt_tracker);
159 kfree_rcu(pin, rcu);
160 }
161}
162
163struct dpll_device *dpll_device_get_by_id(int id)
164{
165 if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED))
166 return xa_load(&dpll_device_xa, id);
167
168 return NULL;
169}
170
171static struct dpll_pin_registration *
172dpll_pin_registration_find(struct dpll_pin_ref *ref,
173 const struct dpll_pin_ops *ops, void *priv,
174 void *cookie)
175{
176 struct dpll_pin_registration *reg;
177
178 list_for_each_entry(reg, &ref->registration_list, list) {
179 if (reg->ops == ops && reg->priv == priv &&
180 reg->cookie == cookie)
181 return reg;
182 }
183 return NULL;
184}
185
186static int
187dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin,
188 const struct dpll_pin_ops *ops, void *priv,
189 void *cookie)
190{
191 struct dpll_pin_registration *reg;
192 struct dpll_pin_ref *ref;
193 bool ref_exists = false;
194 unsigned long i;
195 int ret;
196
197 xa_for_each(xa_pins, i, ref) {
198 if (ref->pin != pin)
199 continue;
200 reg = dpll_pin_registration_find(ref, ops, priv, cookie);
201 if (reg)
202 return -EEXIST;
203 ref_exists = true;
204 break;
205 }
206
207 if (!ref_exists) {
208 ref = kzalloc_obj(*ref);
209 if (!ref)
210 return -ENOMEM;
211 ref->pin = pin;
212 INIT_LIST_HEAD(&ref->registration_list);
213 ret = xa_insert(xa_pins, pin->pin_idx, ref, GFP_KERNEL);
214 if (ret) {
215 kfree(ref);
216 return ret;
217 }
218 refcount_set(&ref->refcount, 1);
219 }
220
221 reg = kzalloc_obj(*reg);
222 if (!reg) {
223 if (!ref_exists) {
224 xa_erase(xa_pins, pin->pin_idx);
225 kfree(ref);
226 }
227 return -ENOMEM;
228 }
229 reg->ops = ops;
230 reg->priv = priv;
231 reg->cookie = cookie;
232 __dpll_pin_hold(pin, ®->tracker);
233 if (ref_exists)
234 refcount_inc(&ref->refcount);
235 list_add_tail(®->list, &ref->registration_list);
236
237 return 0;
238}
239
240static int dpll_xa_ref_pin_del(struct xarray *xa_pins, struct dpll_pin *pin,
241 const struct dpll_pin_ops *ops, void *priv,
242 void *cookie)
243{
244 struct dpll_pin_registration *reg;
245 struct dpll_pin_ref *ref;
246 unsigned long i;
247
248 xa_for_each(xa_pins, i, ref) {
249 if (ref->pin != pin)
250 continue;
251 reg = dpll_pin_registration_find(ref, ops, priv, cookie);
252 if (WARN_ON(!reg))
253 return -EINVAL;
254 list_del(®->list);
255 __dpll_pin_put(pin, ®->tracker);
256 kfree(reg);
257 if (refcount_dec_and_test(&ref->refcount)) {
258 xa_erase(xa_pins, i);
259 WARN_ON(!list_empty(&ref->registration_list));
260 kfree(ref);
261 }
262 return 0;
263 }
264
265 return -EINVAL;
266}
267
268static int
269dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll,
270 const struct dpll_pin_ops *ops, void *priv, void *cookie)
271{
272 struct dpll_pin_registration *reg;
273 struct dpll_pin_ref *ref;
274 bool ref_exists = false;
275 unsigned long i;
276 int ret;
277
278 xa_for_each(xa_dplls, i, ref) {
279 if (ref->dpll != dpll)
280 continue;
281 reg = dpll_pin_registration_find(ref, ops, priv, cookie);
282 if (reg)
283 return -EEXIST;
284 ref_exists = true;
285 break;
286 }
287
288 if (!ref_exists) {
289 ref = kzalloc_obj(*ref);
290 if (!ref)
291 return -ENOMEM;
292 ref->dpll = dpll;
293 INIT_LIST_HEAD(&ref->registration_list);
294 ret = xa_insert(xa_dplls, dpll->id, ref, GFP_KERNEL);
295 if (ret) {
296 kfree(ref);
297 return ret;
298 }
299 refcount_set(&ref->refcount, 1);
300 }
301
302 reg = kzalloc_obj(*reg);
303 if (!reg) {
304 if (!ref_exists) {
305 xa_erase(xa_dplls, dpll->id);
306 kfree(ref);
307 }
308 return -ENOMEM;
309 }
310 reg->ops = ops;
311 reg->priv = priv;
312 reg->cookie = cookie;
313 __dpll_device_hold(dpll, ®->tracker);
314 if (ref_exists)
315 refcount_inc(&ref->refcount);
316 list_add_tail(®->list, &ref->registration_list);
317
318 return 0;
319}
320
321static void
322dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll,
323 const struct dpll_pin_ops *ops, void *priv, void *cookie)
324{
325 struct dpll_pin_registration *reg;
326 struct dpll_pin_ref *ref;
327 unsigned long i;
328
329 xa_for_each(xa_dplls, i, ref) {
330 if (ref->dpll != dpll)
331 continue;
332 reg = dpll_pin_registration_find(ref, ops, priv, cookie);
333 if (WARN_ON(!reg))
334 return;
335 list_del(®->list);
336 __dpll_device_put(dpll, ®->tracker);
337 kfree(reg);
338 if (refcount_dec_and_test(&ref->refcount)) {
339 xa_erase(xa_dplls, i);
340 WARN_ON(!list_empty(&ref->registration_list));
341 kfree(ref);
342 }
343 return;
344 }
345}
346
347struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs)
348{
349 struct dpll_pin_ref *ref;
350 unsigned long i = 0;
351
352 ref = xa_find(xa_refs, &i, ULONG_MAX, XA_PRESENT);
353 WARN_ON(!ref);
354 return ref;
355}
356
357static struct dpll_device *
358dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module)
359{
360 struct dpll_device *dpll;
361 int ret;
362
363 dpll = kzalloc_obj(*dpll);
364 if (!dpll)
365 return ERR_PTR(-ENOMEM);
366 refcount_set(&dpll->refcount, 1);
367 INIT_LIST_HEAD(&dpll->registration_list);
368 dpll->device_idx = device_idx;
369 dpll->clock_id = clock_id;
370 dpll->module = module;
371 ret = xa_alloc_cyclic(&dpll_device_xa, &dpll->id, dpll, xa_limit_32b,
372 &dpll_device_xa_id, GFP_KERNEL);
373 if (ret < 0) {
374 kfree(dpll);
375 return ERR_PTR(ret);
376 }
377 xa_init_flags(&dpll->pin_refs, XA_FLAGS_ALLOC);
378 ref_tracker_dir_init(&dpll->refcnt_tracker, 128, "dpll_device");
379
380 return dpll;
381}
382
383/**
384 * dpll_device_get - find existing or create new dpll device
385 * @clock_id: clock_id of creator
386 * @device_idx: idx given by device driver
387 * @module: reference to registering module
388 * @tracker: tracking object for the acquired reference
389 *
390 * Get existing object of a dpll device, unique for given arguments.
391 * Create new if doesn't exist yet.
392 *
393 * Context: Acquires a lock (dpll_lock)
394 * Return:
395 * * valid dpll_device struct pointer if succeeded
396 * * ERR_PTR(X) - error
397 */
398struct dpll_device *
399dpll_device_get(u64 clock_id, u32 device_idx, struct module *module,
400 dpll_tracker *tracker)
401{
402 struct dpll_device *dpll, *ret = NULL;
403 unsigned long index;
404
405 mutex_lock(&dpll_lock);
406 xa_for_each(&dpll_device_xa, index, dpll) {
407 if (dpll->clock_id == clock_id &&
408 dpll->device_idx == device_idx &&
409 dpll->module == module) {
410 __dpll_device_hold(dpll, tracker);
411 ret = dpll;
412 break;
413 }
414 }
415 if (!ret) {
416 ret = dpll_device_alloc(clock_id, device_idx, module);
417 if (!IS_ERR(ret))
418 dpll_device_tracker_alloc(ret, tracker);
419 }
420
421 mutex_unlock(&dpll_lock);
422
423 return ret;
424}
425EXPORT_SYMBOL_GPL(dpll_device_get);
426
427/**
428 * dpll_device_put - decrease the refcount and free memory if possible
429 * @dpll: dpll_device struct pointer
430 * @tracker: tracking object for the acquired reference
431 *
432 * Context: Acquires a lock (dpll_lock)
433 * Drop reference for a dpll device, if all references are gone, delete
434 * dpll device object.
435 */
436void dpll_device_put(struct dpll_device *dpll, dpll_tracker *tracker)
437{
438 mutex_lock(&dpll_lock);
439 __dpll_device_put(dpll, tracker);
440 mutex_unlock(&dpll_lock);
441}
442EXPORT_SYMBOL_GPL(dpll_device_put);
443
444static struct dpll_device_registration *
445dpll_device_registration_find(struct dpll_device *dpll,
446 const struct dpll_device_ops *ops, void *priv)
447{
448 struct dpll_device_registration *reg;
449
450 list_for_each_entry(reg, &dpll->registration_list, list) {
451 if (reg->ops == ops && reg->priv == priv)
452 return reg;
453 }
454 return NULL;
455}
456
457/**
458 * dpll_device_register - register the dpll device in the subsystem
459 * @dpll: pointer to a dpll
460 * @type: type of a dpll
461 * @ops: ops for a dpll device
462 * @priv: pointer to private information of owner
463 *
464 * Make dpll device available for user space.
465 *
466 * Context: Acquires a lock (dpll_lock)
467 * Return:
468 * * 0 on success
469 * * negative - error value
470 */
471int dpll_device_register(struct dpll_device *dpll, enum dpll_type type,
472 const struct dpll_device_ops *ops, void *priv)
473{
474 struct dpll_device_registration *reg;
475 bool first_registration = false;
476
477 if (WARN_ON(!ops))
478 return -EINVAL;
479 if (WARN_ON(!ops->mode_get))
480 return -EINVAL;
481 if (WARN_ON(!ops->lock_status_get))
482 return -EINVAL;
483 if (WARN_ON(type < DPLL_TYPE_PPS || type > DPLL_TYPE_MAX))
484 return -EINVAL;
485
486 mutex_lock(&dpll_lock);
487 reg = dpll_device_registration_find(dpll, ops, priv);
488 if (reg) {
489 mutex_unlock(&dpll_lock);
490 return -EEXIST;
491 }
492
493 reg = kzalloc_obj(*reg);
494 if (!reg) {
495 mutex_unlock(&dpll_lock);
496 return -ENOMEM;
497 }
498 reg->ops = ops;
499 reg->priv = priv;
500 dpll->type = type;
501 __dpll_device_hold(dpll, ®->tracker);
502 first_registration = list_empty(&dpll->registration_list);
503 list_add_tail(®->list, &dpll->registration_list);
504 if (!first_registration) {
505 mutex_unlock(&dpll_lock);
506 return 0;
507 }
508
509 xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED);
510 dpll_device_create_ntf(dpll);
511 mutex_unlock(&dpll_lock);
512
513 return 0;
514}
515EXPORT_SYMBOL_GPL(dpll_device_register);
516
517/**
518 * dpll_device_unregister - unregister dpll device
519 * @dpll: registered dpll pointer
520 * @ops: ops for a dpll device
521 * @priv: pointer to private information of owner
522 *
523 * Unregister device, make it unavailable for userspace.
524 * Note: It does not free the memory
525 * Context: Acquires a lock (dpll_lock)
526 */
527void dpll_device_unregister(struct dpll_device *dpll,
528 const struct dpll_device_ops *ops, void *priv)
529{
530 struct dpll_device_registration *reg;
531
532 mutex_lock(&dpll_lock);
533 ASSERT_DPLL_REGISTERED(dpll);
534 dpll_device_delete_ntf(dpll);
535 reg = dpll_device_registration_find(dpll, ops, priv);
536 if (WARN_ON(!reg)) {
537 mutex_unlock(&dpll_lock);
538 return;
539 }
540 list_del(®->list);
541 __dpll_device_put(dpll, ®->tracker);
542 kfree(reg);
543
544 if (!list_empty(&dpll->registration_list)) {
545 mutex_unlock(&dpll_lock);
546 return;
547 }
548 xa_clear_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED);
549 mutex_unlock(&dpll_lock);
550}
551EXPORT_SYMBOL_GPL(dpll_device_unregister);
552
553static int dpll_pin_idx_alloc(u32 *pin_idx)
554{
555 int ret;
556
557 if (!pin_idx)
558 return -EINVAL;
559
560 /* Alloc unique number from IDA. Number belongs to <0, INT_MAX> range */
561 ret = ida_alloc(&dpll_pin_idx_ida, GFP_KERNEL);
562 if (ret < 0)
563 return ret;
564
565 /* Map the value to dynamic pin index range <INT_MAX+1, U32_MAX> */
566 *pin_idx = (u32)ret + INT_MAX + 1;
567
568 return 0;
569}
570
571static void dpll_pin_idx_free(u32 pin_idx)
572{
573 if (pin_idx <= INT_MAX)
574 return; /* Not a dynamic pin index */
575
576 /* Map the index value from dynamic pin index range to IDA range and
577 * free it.
578 */
579 pin_idx -= (u32)INT_MAX + 1;
580 ida_free(&dpll_pin_idx_ida, pin_idx);
581}
582
583static void dpll_pin_prop_free(struct dpll_pin_properties *prop)
584{
585 kfree(prop->package_label);
586 kfree(prop->panel_label);
587 kfree(prop->board_label);
588 kfree(prop->freq_supported);
589}
590
591static int dpll_pin_prop_dup(const struct dpll_pin_properties *src,
592 struct dpll_pin_properties *dst)
593{
594 if (WARN_ON(src->freq_supported && !src->freq_supported_num))
595 return -EINVAL;
596
597 memcpy(dst, src, sizeof(*dst));
598 if (src->freq_supported) {
599 size_t freq_size = src->freq_supported_num *
600 sizeof(*src->freq_supported);
601 dst->freq_supported = kmemdup(src->freq_supported,
602 freq_size, GFP_KERNEL);
603 if (!dst->freq_supported)
604 return -ENOMEM;
605 }
606 if (src->board_label) {
607 dst->board_label = kstrdup(src->board_label, GFP_KERNEL);
608 if (!dst->board_label)
609 goto err_board_label;
610 }
611 if (src->panel_label) {
612 dst->panel_label = kstrdup(src->panel_label, GFP_KERNEL);
613 if (!dst->panel_label)
614 goto err_panel_label;
615 }
616 if (src->package_label) {
617 dst->package_label = kstrdup(src->package_label, GFP_KERNEL);
618 if (!dst->package_label)
619 goto err_package_label;
620 }
621
622 return 0;
623
624err_package_label:
625 kfree(dst->panel_label);
626err_panel_label:
627 kfree(dst->board_label);
628err_board_label:
629 kfree(dst->freq_supported);
630 return -ENOMEM;
631}
632
633static struct dpll_pin *
634dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
635 const struct dpll_pin_properties *prop)
636{
637 struct dpll_pin *pin;
638 int ret;
639
640 if (pin_idx == DPLL_PIN_IDX_UNSPEC) {
641 ret = dpll_pin_idx_alloc(&pin_idx);
642 if (ret)
643 return ERR_PTR(ret);
644 } else if (pin_idx > INT_MAX) {
645 return ERR_PTR(-EINVAL);
646 }
647 pin = kzalloc_obj(*pin);
648 if (!pin) {
649 ret = -ENOMEM;
650 goto err_pin_alloc;
651 }
652 pin->pin_idx = pin_idx;
653 pin->clock_id = clock_id;
654 pin->module = module;
655 if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX ||
656 prop->type > DPLL_PIN_TYPE_MAX)) {
657 ret = -EINVAL;
658 goto err_pin_prop;
659 }
660 ret = dpll_pin_prop_dup(prop, &pin->prop);
661 if (ret)
662 goto err_pin_prop;
663 refcount_set(&pin->refcount, 1);
664 xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC);
665 xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC);
666 xa_init_flags(&pin->ref_sync_pins, XA_FLAGS_ALLOC);
667 ret = xa_alloc_cyclic(&dpll_pin_xa, &pin->id, pin, xa_limit_32b,
668 &dpll_pin_xa_id, GFP_KERNEL);
669 if (ret < 0)
670 goto err_xa_alloc;
671 ref_tracker_dir_init(&pin->refcnt_tracker, 128, "dpll_pin");
672 return pin;
673err_xa_alloc:
674 xa_destroy(&pin->dpll_refs);
675 xa_destroy(&pin->parent_refs);
676 xa_destroy(&pin->ref_sync_pins);
677 dpll_pin_prop_free(&pin->prop);
678err_pin_prop:
679 kfree(pin);
680err_pin_alloc:
681 dpll_pin_idx_free(pin_idx);
682 return ERR_PTR(ret);
683}
684
685static void dpll_netdev_pin_assign(struct net_device *dev, struct dpll_pin *dpll_pin)
686{
687 rtnl_lock();
688 rcu_assign_pointer(dev->dpll_pin, dpll_pin);
689 rtnl_unlock();
690}
691
692void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)
693{
694 WARN_ON(!dpll_pin);
695 dpll_netdev_pin_assign(dev, dpll_pin);
696}
697EXPORT_SYMBOL(dpll_netdev_pin_set);
698
699void dpll_netdev_pin_clear(struct net_device *dev)
700{
701 dpll_netdev_pin_assign(dev, NULL);
702}
703EXPORT_SYMBOL(dpll_netdev_pin_clear);
704
705int register_dpll_notifier(struct notifier_block *nb)
706{
707 int ret;
708
709 mutex_lock(&dpll_lock);
710 ret = raw_notifier_chain_register(&dpll_notifier_chain, nb);
711 mutex_unlock(&dpll_lock);
712 return ret;
713}
714EXPORT_SYMBOL_GPL(register_dpll_notifier);
715
716int unregister_dpll_notifier(struct notifier_block *nb)
717{
718 int ret;
719
720 mutex_lock(&dpll_lock);
721 ret = raw_notifier_chain_unregister(&dpll_notifier_chain, nb);
722 mutex_unlock(&dpll_lock);
723 return ret;
724}
725EXPORT_SYMBOL_GPL(unregister_dpll_notifier);
726
727/**
728 * dpll_pin_get - find existing or create new dpll pin
729 * @clock_id: clock_id of creator
730 * @pin_idx: idx given by dev driver
731 * @module: reference to registering module
732 * @prop: dpll pin properties
733 * @tracker: tracking object for the acquired reference
734 *
735 * Get existing object of a pin (unique for given arguments) or create new
736 * if doesn't exist yet.
737 *
738 * Context: Acquires a lock (dpll_lock)
739 * Return:
740 * * valid allocated dpll_pin struct pointer if succeeded
741 * * ERR_PTR(X) - error
742 */
743struct dpll_pin *
744dpll_pin_get(u64 clock_id, u32 pin_idx, struct module *module,
745 const struct dpll_pin_properties *prop, dpll_tracker *tracker)
746{
747 struct dpll_pin *pos, *ret = NULL;
748 unsigned long i;
749
750 mutex_lock(&dpll_lock);
751 xa_for_each(&dpll_pin_xa, i, pos) {
752 if (pos->clock_id == clock_id &&
753 pos->pin_idx == pin_idx &&
754 pos->module == module) {
755 __dpll_pin_hold(pos, tracker);
756 ret = pos;
757 break;
758 }
759 }
760 if (!ret) {
761 ret = dpll_pin_alloc(clock_id, pin_idx, module, prop);
762 if (!IS_ERR(ret))
763 dpll_pin_tracker_alloc(ret, tracker);
764 }
765 mutex_unlock(&dpll_lock);
766
767 return ret;
768}
769EXPORT_SYMBOL_GPL(dpll_pin_get);
770
771/**
772 * dpll_pin_put - decrease the refcount and free memory if possible
773 * @pin: pointer to a pin to be put
774 * @tracker: tracking object for the acquired reference
775 *
776 * Drop reference for a pin, if all references are gone, delete pin object.
777 *
778 * Context: Acquires a lock (dpll_lock)
779 */
780void dpll_pin_put(struct dpll_pin *pin, dpll_tracker *tracker)
781{
782 mutex_lock(&dpll_lock);
783 __dpll_pin_put(pin, tracker);
784 mutex_unlock(&dpll_lock);
785}
786EXPORT_SYMBOL_GPL(dpll_pin_put);
787
788/**
789 * dpll_pin_fwnode_set - set dpll pin firmware node reference
790 * @pin: pointer to a dpll pin
791 * @fwnode: firmware node handle
792 *
793 * Set firmware node handle for the given dpll pin.
794 */
795void dpll_pin_fwnode_set(struct dpll_pin *pin, struct fwnode_handle *fwnode)
796{
797 mutex_lock(&dpll_lock);
798 fwnode_handle_put(pin->fwnode); /* Drop fwnode previously set */
799 pin->fwnode = fwnode_handle_get(fwnode);
800 mutex_unlock(&dpll_lock);
801}
802EXPORT_SYMBOL_GPL(dpll_pin_fwnode_set);
803
804/**
805 * fwnode_dpll_pin_find - find dpll pin by firmware node reference
806 * @fwnode: reference to firmware node
807 * @tracker: tracking object for the acquired reference
808 *
809 * Get existing object of a pin that is associated with given firmware node
810 * reference.
811 *
812 * Context: Acquires a lock (dpll_lock)
813 * Return:
814 * * valid dpll_pin pointer on success
815 * * NULL when no such pin exists
816 */
817struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode,
818 dpll_tracker *tracker)
819{
820 struct dpll_pin *pin, *ret = NULL;
821 unsigned long index;
822
823 mutex_lock(&dpll_lock);
824 xa_for_each(&dpll_pin_xa, index, pin) {
825 if (pin->fwnode == fwnode) {
826 __dpll_pin_hold(pin, tracker);
827 ret = pin;
828 break;
829 }
830 }
831 mutex_unlock(&dpll_lock);
832
833 return ret;
834}
835EXPORT_SYMBOL_GPL(fwnode_dpll_pin_find);
836
837static int
838__dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
839 const struct dpll_pin_ops *ops, void *priv, void *cookie)
840{
841 int ret;
842
843 ret = dpll_xa_ref_pin_add(&dpll->pin_refs, pin, ops, priv, cookie);
844 if (ret)
845 return ret;
846 ret = dpll_xa_ref_dpll_add(&pin->dpll_refs, dpll, ops, priv, cookie);
847 if (ret)
848 goto ref_pin_del;
849 xa_set_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
850 dpll_pin_create_ntf(pin);
851
852 return ret;
853
854ref_pin_del:
855 dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv, cookie);
856 return ret;
857}
858
859/**
860 * dpll_pin_register - register the dpll pin in the subsystem
861 * @dpll: pointer to a dpll
862 * @pin: pointer to a dpll pin
863 * @ops: ops for a dpll pin ops
864 * @priv: pointer to private information of owner
865 *
866 * Context: Acquires a lock (dpll_lock)
867 * Return:
868 * * 0 on success
869 * * negative - error value
870 */
871int
872dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
873 const struct dpll_pin_ops *ops, void *priv)
874{
875 int ret;
876
877 if (WARN_ON(!ops) ||
878 WARN_ON(!ops->state_on_dpll_get) ||
879 WARN_ON(!ops->direction_get) ||
880 WARN_ON(ops->measured_freq_get &&
881 (!dpll_device_ops(dpll)->freq_monitor_get ||
882 !dpll_device_ops(dpll)->freq_monitor_set)))
883 return -EINVAL;
884
885 mutex_lock(&dpll_lock);
886 if (WARN_ON(!(dpll->module == pin->module &&
887 dpll->clock_id == pin->clock_id)))
888 ret = -EINVAL;
889 else
890 ret = __dpll_pin_register(dpll, pin, ops, priv, NULL);
891 mutex_unlock(&dpll_lock);
892
893 return ret;
894}
895EXPORT_SYMBOL_GPL(dpll_pin_register);
896
897static void dpll_pin_ref_sync_pair_del(u32 ref_sync_pin_id)
898{
899 struct dpll_pin *pin, *ref_sync_pin;
900 unsigned long i;
901
902 xa_for_each(&dpll_pin_xa, i, pin) {
903 ref_sync_pin = xa_load(&pin->ref_sync_pins, ref_sync_pin_id);
904 if (ref_sync_pin) {
905 xa_erase(&pin->ref_sync_pins, ref_sync_pin_id);
906 __dpll_pin_change_ntf(pin);
907 }
908 }
909}
910
911static void
912__dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
913 const struct dpll_pin_ops *ops, void *priv, void *cookie)
914{
915 ASSERT_DPLL_PIN_REGISTERED(pin);
916 dpll_pin_ref_sync_pair_del(pin->id);
917 dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv, cookie);
918 dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv, cookie);
919 if (xa_empty(&pin->dpll_refs))
920 xa_clear_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
921}
922
923/**
924 * dpll_pin_unregister - unregister dpll pin from dpll device
925 * @dpll: registered dpll pointer
926 * @pin: pointer to a pin
927 * @ops: ops for a dpll pin
928 * @priv: pointer to private information of owner
929 *
930 * Note: It does not free the memory
931 * Context: Acquires a lock (dpll_lock)
932 */
933void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
934 const struct dpll_pin_ops *ops, void *priv)
935{
936 if (WARN_ON(xa_empty(&dpll->pin_refs)))
937 return;
938 if (WARN_ON(!xa_empty(&pin->parent_refs)))
939 return;
940
941 mutex_lock(&dpll_lock);
942 dpll_pin_delete_ntf(pin);
943 __dpll_pin_unregister(dpll, pin, ops, priv, NULL);
944 mutex_unlock(&dpll_lock);
945}
946EXPORT_SYMBOL_GPL(dpll_pin_unregister);
947
948/**
949 * dpll_pin_on_pin_register - register a pin with a parent pin
950 * @parent: pointer to a parent pin
951 * @pin: pointer to a pin
952 * @ops: ops for a dpll pin
953 * @priv: pointer to private information of owner
954 *
955 * Register a pin with a parent pin, create references between them and
956 * between newly registered pin and dplls connected with a parent pin.
957 *
958 * Context: Acquires a lock (dpll_lock)
959 * Return:
960 * * 0 on success
961 * * negative - error value
962 */
963int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
964 const struct dpll_pin_ops *ops, void *priv)
965{
966 struct dpll_pin_ref *ref;
967 unsigned long i, stop;
968 int ret;
969
970 if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX))
971 return -EINVAL;
972
973 if (WARN_ON(!ops) ||
974 WARN_ON(!ops->state_on_pin_get) ||
975 WARN_ON(!ops->direction_get))
976 return -EINVAL;
977
978 mutex_lock(&dpll_lock);
979 ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv, pin);
980 if (ret)
981 goto unlock;
982 xa_for_each(&parent->dpll_refs, i, ref) {
983 ret = __dpll_pin_register(ref->dpll, pin, ops, priv, parent);
984 if (ret) {
985 stop = i;
986 goto dpll_unregister;
987 }
988 dpll_pin_create_ntf(pin);
989 }
990 mutex_unlock(&dpll_lock);
991
992 return ret;
993
994dpll_unregister:
995 xa_for_each(&parent->dpll_refs, i, ref)
996 if (i < stop) {
997 __dpll_pin_unregister(ref->dpll, pin, ops, priv,
998 parent);
999 dpll_pin_delete_ntf(pin);
1000 }
1001 dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
1002unlock:
1003 mutex_unlock(&dpll_lock);
1004 return ret;
1005}
1006EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register);
1007
1008/**
1009 * dpll_pin_on_pin_unregister - unregister dpll pin from a parent pin
1010 * @parent: pointer to a parent pin
1011 * @pin: pointer to a pin
1012 * @ops: ops for a dpll pin
1013 * @priv: pointer to private information of owner
1014 *
1015 * Context: Acquires a lock (dpll_lock)
1016 * Note: It does not free the memory
1017 */
1018void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
1019 const struct dpll_pin_ops *ops, void *priv)
1020{
1021 struct dpll_pin_ref *ref;
1022 unsigned long i;
1023
1024 mutex_lock(&dpll_lock);
1025 dpll_pin_delete_ntf(pin);
1026 dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
1027 xa_for_each(&pin->dpll_refs, i, ref)
1028 __dpll_pin_unregister(ref->dpll, pin, ops, priv, parent);
1029 mutex_unlock(&dpll_lock);
1030}
1031EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister);
1032
1033/**
1034 * dpll_pin_ref_sync_pair_add - create a reference sync signal pin pair
1035 * @pin: pin which produces the base frequency
1036 * @ref_sync_pin: pin which produces the sync signal
1037 *
1038 * Once pins are paired, the user-space configuration of reference sync pair
1039 * is possible.
1040 * Context: Acquires a lock (dpll_lock)
1041 * Return:
1042 * * 0 on success
1043 * * negative - error value
1044 */
1045int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,
1046 struct dpll_pin *ref_sync_pin)
1047{
1048 int ret;
1049
1050 mutex_lock(&dpll_lock);
1051 ret = xa_insert(&pin->ref_sync_pins, ref_sync_pin->id,
1052 ref_sync_pin, GFP_KERNEL);
1053 __dpll_pin_change_ntf(pin);
1054 mutex_unlock(&dpll_lock);
1055
1056 return ret;
1057}
1058EXPORT_SYMBOL_GPL(dpll_pin_ref_sync_pair_add);
1059
1060static struct dpll_device_registration *
1061dpll_device_registration_first(struct dpll_device *dpll)
1062{
1063 struct dpll_device_registration *reg;
1064
1065 reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list,
1066 struct dpll_device_registration, list);
1067 WARN_ON(!reg);
1068 return reg;
1069}
1070
1071void *dpll_priv(struct dpll_device *dpll)
1072{
1073 struct dpll_device_registration *reg;
1074
1075 reg = dpll_device_registration_first(dpll);
1076 return reg->priv;
1077}
1078
1079const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll)
1080{
1081 struct dpll_device_registration *reg;
1082
1083 reg = dpll_device_registration_first(dpll);
1084 return reg->ops;
1085}
1086
1087static struct dpll_pin_registration *
1088dpll_pin_registration_first(struct dpll_pin_ref *ref)
1089{
1090 struct dpll_pin_registration *reg;
1091
1092 reg = list_first_entry_or_null(&ref->registration_list,
1093 struct dpll_pin_registration, list);
1094 WARN_ON(!reg);
1095 return reg;
1096}
1097
1098void *dpll_pin_on_dpll_priv(struct dpll_device *dpll,
1099 struct dpll_pin *pin)
1100{
1101 struct dpll_pin_registration *reg;
1102 struct dpll_pin_ref *ref;
1103
1104 ref = xa_load(&dpll->pin_refs, pin->pin_idx);
1105 if (!ref)
1106 return NULL;
1107 reg = dpll_pin_registration_first(ref);
1108 return reg->priv;
1109}
1110
1111void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
1112 struct dpll_pin *pin)
1113{
1114 struct dpll_pin_registration *reg;
1115 struct dpll_pin_ref *ref;
1116
1117 ref = xa_load(&pin->parent_refs, parent->pin_idx);
1118 if (!ref)
1119 return NULL;
1120 reg = dpll_pin_registration_first(ref);
1121 return reg->priv;
1122}
1123
1124const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
1125{
1126 struct dpll_pin_registration *reg;
1127
1128 reg = dpll_pin_registration_first(ref);
1129 return reg->ops;
1130}
1131
1132static int __init dpll_init(void)
1133{
1134 int ret;
1135
1136 ret = genl_register_family(&dpll_nl_family);
1137 if (ret)
1138 goto error;
1139
1140 return 0;
1141
1142error:
1143 mutex_destroy(&dpll_lock);
1144 return ret;
1145}
1146
1147static void __exit dpll_exit(void)
1148{
1149 genl_unregister_family(&dpll_nl_family);
1150 mutex_destroy(&dpll_lock);
1151}
1152
1153subsys_initcall(dpll_init);
1154module_exit(dpll_exit);