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 */
22 DEFINE_MUTEX(dpll_lock);
23
24 DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC);
25 DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC);
26
27 static RAW_NOTIFIER_HEAD(dpll_notifier_chain);
28 static DEFINE_IDA(dpll_pin_idx_ida);
29
30 static u32 dpll_device_xa_id;
31 static 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
40 struct dpll_device_registration {
41 struct list_head list;
42 const struct dpll_device_ops *ops;
43 void *priv;
44 dpll_tracker tracker;
45 };
46
47 struct 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
call_dpll_notifiers(unsigned long action,void * info)55 static 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
dpll_device_notify(struct dpll_device * dpll,unsigned long action)61 void 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
dpll_pin_notify(struct dpll_pin * pin,unsigned long action)74 void 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
dpll_device_tracker_alloc(struct dpll_device * dpll,dpll_tracker * tracker)88 static 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
dpll_device_tracker_free(struct dpll_device * dpll,dpll_tracker * tracker)96 static 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
__dpll_device_hold(struct dpll_device * dpll,dpll_tracker * tracker)104 static 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
__dpll_device_put(struct dpll_device * dpll,dpll_tracker * tracker)110 static 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
dpll_pin_tracker_alloc(struct dpll_pin * pin,dpll_tracker * tracker)124 static 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
dpll_pin_tracker_free(struct dpll_pin * pin,dpll_tracker * tracker)131 static 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
__dpll_pin_hold(struct dpll_pin * pin,dpll_tracker * tracker)138 static 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
144 static void dpll_pin_idx_free(u32 pin_idx);
145 static void dpll_pin_prop_free(struct dpll_pin_properties *prop);
146
__dpll_pin_put(struct dpll_pin * pin,dpll_tracker * tracker)147 static 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
dpll_device_get_by_id(int id)163 struct 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
171 static struct dpll_pin_registration *
dpll_pin_registration_find(struct dpll_pin_ref * ref,const struct dpll_pin_ops * ops,void * priv,void * cookie)172 dpll_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
186 static int
dpll_xa_ref_pin_add(struct xarray * xa_pins,struct dpll_pin * pin,const struct dpll_pin_ops * ops,void * priv,void * cookie)187 dpll_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
dpll_xa_ref_pin_del(struct xarray * xa_pins,struct dpll_pin * pin,const struct dpll_pin_ops * ops,void * priv,void * cookie)240 static 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
268 static int
dpll_xa_ref_dpll_add(struct xarray * xa_dplls,struct dpll_device * dpll,const struct dpll_pin_ops * ops,void * priv,void * cookie)269 dpll_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
321 static void
dpll_xa_ref_dpll_del(struct xarray * xa_dplls,struct dpll_device * dpll,const struct dpll_pin_ops * ops,void * priv,void * cookie)322 dpll_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
dpll_xa_ref_dpll_first(struct xarray * xa_refs)347 struct 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
357 static struct dpll_device *
dpll_device_alloc(const u64 clock_id,u32 device_idx,struct module * module)358 dpll_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 */
398 struct dpll_device *
dpll_device_get(u64 clock_id,u32 device_idx,struct module * module,dpll_tracker * tracker)399 dpll_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 }
425 EXPORT_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 */
dpll_device_put(struct dpll_device * dpll,dpll_tracker * tracker)436 void 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 }
442 EXPORT_SYMBOL_GPL(dpll_device_put);
443
444 static struct dpll_device_registration *
dpll_device_registration_find(struct dpll_device * dpll,const struct dpll_device_ops * ops,void * priv)445 dpll_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 */
dpll_device_register(struct dpll_device * dpll,enum dpll_type type,const struct dpll_device_ops * ops,void * priv)471 int 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 }
515 EXPORT_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 */
dpll_device_unregister(struct dpll_device * dpll,const struct dpll_device_ops * ops,void * priv)527 void 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 }
551 EXPORT_SYMBOL_GPL(dpll_device_unregister);
552
dpll_pin_idx_alloc(u32 * pin_idx)553 static 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
dpll_pin_idx_free(u32 pin_idx)571 static 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
dpll_pin_prop_free(struct dpll_pin_properties * prop)583 static 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
dpll_pin_prop_dup(const struct dpll_pin_properties * src,struct dpll_pin_properties * dst)591 static 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
624 err_package_label:
625 kfree(dst->panel_label);
626 err_panel_label:
627 kfree(dst->board_label);
628 err_board_label:
629 kfree(dst->freq_supported);
630 return -ENOMEM;
631 }
632
633 static struct dpll_pin *
dpll_pin_alloc(u64 clock_id,u32 pin_idx,struct module * module,const struct dpll_pin_properties * prop)634 dpll_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;
673 err_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);
678 err_pin_prop:
679 kfree(pin);
680 err_pin_alloc:
681 dpll_pin_idx_free(pin_idx);
682 return ERR_PTR(ret);
683 }
684
dpll_netdev_pin_assign(struct net_device * dev,struct dpll_pin * dpll_pin)685 static 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
dpll_netdev_pin_set(struct net_device * dev,struct dpll_pin * dpll_pin)692 void 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 }
697 EXPORT_SYMBOL(dpll_netdev_pin_set);
698
dpll_netdev_pin_clear(struct net_device * dev)699 void dpll_netdev_pin_clear(struct net_device *dev)
700 {
701 dpll_netdev_pin_assign(dev, NULL);
702 }
703 EXPORT_SYMBOL(dpll_netdev_pin_clear);
704
register_dpll_notifier(struct notifier_block * nb)705 int 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 }
714 EXPORT_SYMBOL_GPL(register_dpll_notifier);
715
unregister_dpll_notifier(struct notifier_block * nb)716 int 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 }
725 EXPORT_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 */
743 struct dpll_pin *
dpll_pin_get(u64 clock_id,u32 pin_idx,struct module * module,const struct dpll_pin_properties * prop,dpll_tracker * tracker)744 dpll_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 }
769 EXPORT_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 */
dpll_pin_put(struct dpll_pin * pin,dpll_tracker * tracker)780 void 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 }
786 EXPORT_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 */
dpll_pin_fwnode_set(struct dpll_pin * pin,struct fwnode_handle * fwnode)795 void 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 }
802 EXPORT_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 */
fwnode_dpll_pin_find(struct fwnode_handle * fwnode,dpll_tracker * tracker)817 struct 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 }
835 EXPORT_SYMBOL_GPL(fwnode_dpll_pin_find);
836
837 static int
__dpll_pin_register(struct dpll_device * dpll,struct dpll_pin * pin,const struct dpll_pin_ops * ops,void * priv,void * cookie)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
854 ref_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 */
871 int
dpll_pin_register(struct dpll_device * dpll,struct dpll_pin * pin,const struct dpll_pin_ops * ops,void * priv)872 dpll_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 return -EINVAL;
881
882 mutex_lock(&dpll_lock);
883 if (WARN_ON(!(dpll->module == pin->module &&
884 dpll->clock_id == pin->clock_id)))
885 ret = -EINVAL;
886 else
887 ret = __dpll_pin_register(dpll, pin, ops, priv, NULL);
888 mutex_unlock(&dpll_lock);
889
890 return ret;
891 }
892 EXPORT_SYMBOL_GPL(dpll_pin_register);
893
dpll_pin_ref_sync_pair_del(u32 ref_sync_pin_id)894 static void dpll_pin_ref_sync_pair_del(u32 ref_sync_pin_id)
895 {
896 struct dpll_pin *pin, *ref_sync_pin;
897 unsigned long i;
898
899 xa_for_each(&dpll_pin_xa, i, pin) {
900 ref_sync_pin = xa_load(&pin->ref_sync_pins, ref_sync_pin_id);
901 if (ref_sync_pin) {
902 xa_erase(&pin->ref_sync_pins, ref_sync_pin_id);
903 __dpll_pin_change_ntf(pin);
904 }
905 }
906 }
907
908 static void
__dpll_pin_unregister(struct dpll_device * dpll,struct dpll_pin * pin,const struct dpll_pin_ops * ops,void * priv,void * cookie)909 __dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
910 const struct dpll_pin_ops *ops, void *priv, void *cookie)
911 {
912 ASSERT_DPLL_PIN_REGISTERED(pin);
913 dpll_pin_ref_sync_pair_del(pin->id);
914 dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv, cookie);
915 dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv, cookie);
916 if (xa_empty(&pin->dpll_refs))
917 xa_clear_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
918 }
919
920 /**
921 * dpll_pin_unregister - unregister dpll pin from dpll device
922 * @dpll: registered dpll pointer
923 * @pin: pointer to a pin
924 * @ops: ops for a dpll pin
925 * @priv: pointer to private information of owner
926 *
927 * Note: It does not free the memory
928 * Context: Acquires a lock (dpll_lock)
929 */
dpll_pin_unregister(struct dpll_device * dpll,struct dpll_pin * pin,const struct dpll_pin_ops * ops,void * priv)930 void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
931 const struct dpll_pin_ops *ops, void *priv)
932 {
933 if (WARN_ON(xa_empty(&dpll->pin_refs)))
934 return;
935 if (WARN_ON(!xa_empty(&pin->parent_refs)))
936 return;
937
938 mutex_lock(&dpll_lock);
939 dpll_pin_delete_ntf(pin);
940 __dpll_pin_unregister(dpll, pin, ops, priv, NULL);
941 mutex_unlock(&dpll_lock);
942 }
943 EXPORT_SYMBOL_GPL(dpll_pin_unregister);
944
945 /**
946 * dpll_pin_on_pin_register - register a pin with a parent pin
947 * @parent: pointer to a parent pin
948 * @pin: pointer to a pin
949 * @ops: ops for a dpll pin
950 * @priv: pointer to private information of owner
951 *
952 * Register a pin with a parent pin, create references between them and
953 * between newly registered pin and dplls connected with a parent pin.
954 *
955 * Context: Acquires a lock (dpll_lock)
956 * Return:
957 * * 0 on success
958 * * negative - error value
959 */
dpll_pin_on_pin_register(struct dpll_pin * parent,struct dpll_pin * pin,const struct dpll_pin_ops * ops,void * priv)960 int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
961 const struct dpll_pin_ops *ops, void *priv)
962 {
963 struct dpll_pin_ref *ref;
964 unsigned long i, stop;
965 int ret;
966
967 if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX))
968 return -EINVAL;
969
970 if (WARN_ON(!ops) ||
971 WARN_ON(!ops->state_on_pin_get) ||
972 WARN_ON(!ops->direction_get))
973 return -EINVAL;
974
975 mutex_lock(&dpll_lock);
976 ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv, pin);
977 if (ret)
978 goto unlock;
979 xa_for_each(&parent->dpll_refs, i, ref) {
980 ret = __dpll_pin_register(ref->dpll, pin, ops, priv, parent);
981 if (ret) {
982 stop = i;
983 goto dpll_unregister;
984 }
985 dpll_pin_create_ntf(pin);
986 }
987 mutex_unlock(&dpll_lock);
988
989 return ret;
990
991 dpll_unregister:
992 xa_for_each(&parent->dpll_refs, i, ref)
993 if (i < stop) {
994 __dpll_pin_unregister(ref->dpll, pin, ops, priv,
995 parent);
996 dpll_pin_delete_ntf(pin);
997 }
998 dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
999 unlock:
1000 mutex_unlock(&dpll_lock);
1001 return ret;
1002 }
1003 EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register);
1004
1005 /**
1006 * dpll_pin_on_pin_unregister - unregister dpll pin from a parent pin
1007 * @parent: pointer to a parent pin
1008 * @pin: pointer to a pin
1009 * @ops: ops for a dpll pin
1010 * @priv: pointer to private information of owner
1011 *
1012 * Context: Acquires a lock (dpll_lock)
1013 * Note: It does not free the memory
1014 */
dpll_pin_on_pin_unregister(struct dpll_pin * parent,struct dpll_pin * pin,const struct dpll_pin_ops * ops,void * priv)1015 void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
1016 const struct dpll_pin_ops *ops, void *priv)
1017 {
1018 struct dpll_pin_ref *ref;
1019 unsigned long i;
1020
1021 mutex_lock(&dpll_lock);
1022 dpll_pin_delete_ntf(pin);
1023 dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
1024 xa_for_each(&pin->dpll_refs, i, ref)
1025 __dpll_pin_unregister(ref->dpll, pin, ops, priv, parent);
1026 mutex_unlock(&dpll_lock);
1027 }
1028 EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister);
1029
1030 /**
1031 * dpll_pin_ref_sync_pair_add - create a reference sync signal pin pair
1032 * @pin: pin which produces the base frequency
1033 * @ref_sync_pin: pin which produces the sync signal
1034 *
1035 * Once pins are paired, the user-space configuration of reference sync pair
1036 * is possible.
1037 * Context: Acquires a lock (dpll_lock)
1038 * Return:
1039 * * 0 on success
1040 * * negative - error value
1041 */
dpll_pin_ref_sync_pair_add(struct dpll_pin * pin,struct dpll_pin * ref_sync_pin)1042 int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,
1043 struct dpll_pin *ref_sync_pin)
1044 {
1045 int ret;
1046
1047 mutex_lock(&dpll_lock);
1048 ret = xa_insert(&pin->ref_sync_pins, ref_sync_pin->id,
1049 ref_sync_pin, GFP_KERNEL);
1050 __dpll_pin_change_ntf(pin);
1051 mutex_unlock(&dpll_lock);
1052
1053 return ret;
1054 }
1055 EXPORT_SYMBOL_GPL(dpll_pin_ref_sync_pair_add);
1056
1057 static struct dpll_device_registration *
dpll_device_registration_first(struct dpll_device * dpll)1058 dpll_device_registration_first(struct dpll_device *dpll)
1059 {
1060 struct dpll_device_registration *reg;
1061
1062 reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list,
1063 struct dpll_device_registration, list);
1064 WARN_ON(!reg);
1065 return reg;
1066 }
1067
dpll_priv(struct dpll_device * dpll)1068 void *dpll_priv(struct dpll_device *dpll)
1069 {
1070 struct dpll_device_registration *reg;
1071
1072 reg = dpll_device_registration_first(dpll);
1073 return reg->priv;
1074 }
1075
dpll_device_ops(struct dpll_device * dpll)1076 const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll)
1077 {
1078 struct dpll_device_registration *reg;
1079
1080 reg = dpll_device_registration_first(dpll);
1081 return reg->ops;
1082 }
1083
1084 static struct dpll_pin_registration *
dpll_pin_registration_first(struct dpll_pin_ref * ref)1085 dpll_pin_registration_first(struct dpll_pin_ref *ref)
1086 {
1087 struct dpll_pin_registration *reg;
1088
1089 reg = list_first_entry_or_null(&ref->registration_list,
1090 struct dpll_pin_registration, list);
1091 WARN_ON(!reg);
1092 return reg;
1093 }
1094
dpll_pin_on_dpll_priv(struct dpll_device * dpll,struct dpll_pin * pin)1095 void *dpll_pin_on_dpll_priv(struct dpll_device *dpll,
1096 struct dpll_pin *pin)
1097 {
1098 struct dpll_pin_registration *reg;
1099 struct dpll_pin_ref *ref;
1100
1101 ref = xa_load(&dpll->pin_refs, pin->pin_idx);
1102 if (!ref)
1103 return NULL;
1104 reg = dpll_pin_registration_first(ref);
1105 return reg->priv;
1106 }
1107
dpll_pin_on_pin_priv(struct dpll_pin * parent,struct dpll_pin * pin)1108 void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
1109 struct dpll_pin *pin)
1110 {
1111 struct dpll_pin_registration *reg;
1112 struct dpll_pin_ref *ref;
1113
1114 ref = xa_load(&pin->parent_refs, parent->pin_idx);
1115 if (!ref)
1116 return NULL;
1117 reg = dpll_pin_registration_first(ref);
1118 return reg->priv;
1119 }
1120
dpll_pin_ops(struct dpll_pin_ref * ref)1121 const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
1122 {
1123 struct dpll_pin_registration *reg;
1124
1125 reg = dpll_pin_registration_first(ref);
1126 return reg->ops;
1127 }
1128
dpll_init(void)1129 static int __init dpll_init(void)
1130 {
1131 int ret;
1132
1133 ret = genl_register_family(&dpll_nl_family);
1134 if (ret)
1135 goto error;
1136
1137 return 0;
1138
1139 error:
1140 mutex_destroy(&dpll_lock);
1141 return ret;
1142 }
1143
dpll_exit(void)1144 static void __exit dpll_exit(void)
1145 {
1146 genl_unregister_family(&dpll_nl_family);
1147 mutex_destroy(&dpll_lock);
1148 }
1149
1150 subsys_initcall(dpll_init);
1151 module_exit(dpll_exit);
1152