Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/dpll/dpll_core.c
54332 views
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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(sizeof(*ref), GFP_KERNEL);
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(sizeof(*reg), GFP_KERNEL);
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, &reg->tracker);
233
if (ref_exists)
234
refcount_inc(&ref->refcount);
235
list_add_tail(&reg->list, &ref->registration_list);
236
237
return 0;
238
}
239
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(&reg->list);
255
__dpll_pin_put(pin, &reg->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
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(sizeof(*ref), GFP_KERNEL);
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(sizeof(*reg), GFP_KERNEL);
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, &reg->tracker);
314
if (ref_exists)
315
refcount_inc(&ref->refcount);
316
list_add_tail(&reg->list, &ref->registration_list);
317
318
return 0;
319
}
320
321
static void
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(&reg->list);
336
__dpll_device_put(dpll, &reg->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
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 *
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(sizeof(*dpll), GFP_KERNEL);
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 *
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
*/
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 *
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
*/
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(sizeof(*reg), GFP_KERNEL);
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, &reg->tracker);
502
first_registration = list_empty(&dpll->registration_list);
503
list_add_tail(&reg->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
*/
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(&reg->list);
541
__dpll_device_put(dpll, &reg->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
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
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
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
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 *
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(sizeof(*pin), GFP_KERNEL);
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
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
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
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
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
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 *
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
*/
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
*/
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
*/
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
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
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
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
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
*/
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
*/
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
*/
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
*/
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 *
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
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
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 *
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
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
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
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
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
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
1153