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