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