]> Git Repo - linux.git/blob - drivers/dpll/dpll_core.c
Merge tag 's390-6.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[linux.git] / drivers / dpll / dpll_core.c
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         memcpy(dst, src, sizeof(*dst));
447         if (src->freq_supported && src->freq_supported_num) {
448                 size_t freq_size = src->freq_supported_num *
449                                    sizeof(*src->freq_supported);
450                 dst->freq_supported = kmemdup(src->freq_supported,
451                                               freq_size, GFP_KERNEL);
452                 if (!dst->freq_supported)
453                         return -ENOMEM;
454         }
455         if (src->board_label) {
456                 dst->board_label = kstrdup(src->board_label, GFP_KERNEL);
457                 if (!dst->board_label)
458                         goto err_board_label;
459         }
460         if (src->panel_label) {
461                 dst->panel_label = kstrdup(src->panel_label, GFP_KERNEL);
462                 if (!dst->panel_label)
463                         goto err_panel_label;
464         }
465         if (src->package_label) {
466                 dst->package_label = kstrdup(src->package_label, GFP_KERNEL);
467                 if (!dst->package_label)
468                         goto err_package_label;
469         }
470
471         return 0;
472
473 err_package_label:
474         kfree(dst->panel_label);
475 err_panel_label:
476         kfree(dst->board_label);
477 err_board_label:
478         kfree(dst->freq_supported);
479         return -ENOMEM;
480 }
481
482 static struct dpll_pin *
483 dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
484                const struct dpll_pin_properties *prop)
485 {
486         struct dpll_pin *pin;
487         int ret;
488
489         pin = kzalloc(sizeof(*pin), GFP_KERNEL);
490         if (!pin)
491                 return ERR_PTR(-ENOMEM);
492         pin->pin_idx = pin_idx;
493         pin->clock_id = clock_id;
494         pin->module = module;
495         if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX ||
496                     prop->type > DPLL_PIN_TYPE_MAX)) {
497                 ret = -EINVAL;
498                 goto err_pin_prop;
499         }
500         ret = dpll_pin_prop_dup(prop, &pin->prop);
501         if (ret)
502                 goto err_pin_prop;
503         refcount_set(&pin->refcount, 1);
504         xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC);
505         xa_init_flags(&pin->parent_refs, 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)
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         dpll_pin_prop_free(&pin->prop);
515 err_pin_prop:
516         kfree(pin);
517         return ERR_PTR(ret);
518 }
519
520 static void dpll_netdev_pin_assign(struct net_device *dev, struct dpll_pin *dpll_pin)
521 {
522         rtnl_lock();
523         rcu_assign_pointer(dev->dpll_pin, dpll_pin);
524         rtnl_unlock();
525 }
526
527 void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)
528 {
529         WARN_ON(!dpll_pin);
530         dpll_netdev_pin_assign(dev, dpll_pin);
531 }
532 EXPORT_SYMBOL(dpll_netdev_pin_set);
533
534 void dpll_netdev_pin_clear(struct net_device *dev)
535 {
536         dpll_netdev_pin_assign(dev, NULL);
537 }
538 EXPORT_SYMBOL(dpll_netdev_pin_clear);
539
540 /**
541  * dpll_pin_get - find existing or create new dpll pin
542  * @clock_id: clock_id of creator
543  * @pin_idx: idx given by dev driver
544  * @module: reference to registering module
545  * @prop: dpll pin properties
546  *
547  * Get existing object of a pin (unique for given arguments) or create new
548  * if doesn't exist yet.
549  *
550  * Context: Acquires a lock (dpll_lock)
551  * Return:
552  * * valid allocated dpll_pin struct pointer if succeeded
553  * * ERR_PTR(X) - error
554  */
555 struct dpll_pin *
556 dpll_pin_get(u64 clock_id, u32 pin_idx, struct module *module,
557              const struct dpll_pin_properties *prop)
558 {
559         struct dpll_pin *pos, *ret = NULL;
560         unsigned long i;
561
562         mutex_lock(&dpll_lock);
563         xa_for_each(&dpll_pin_xa, i, pos) {
564                 if (pos->clock_id == clock_id &&
565                     pos->pin_idx == pin_idx &&
566                     pos->module == module) {
567                         ret = pos;
568                         refcount_inc(&ret->refcount);
569                         break;
570                 }
571         }
572         if (!ret)
573                 ret = dpll_pin_alloc(clock_id, pin_idx, module, prop);
574         mutex_unlock(&dpll_lock);
575
576         return ret;
577 }
578 EXPORT_SYMBOL_GPL(dpll_pin_get);
579
580 /**
581  * dpll_pin_put - decrease the refcount and free memory if possible
582  * @pin: pointer to a pin to be put
583  *
584  * Drop reference for a pin, if all references are gone, delete pin object.
585  *
586  * Context: Acquires a lock (dpll_lock)
587  */
588 void dpll_pin_put(struct dpll_pin *pin)
589 {
590         mutex_lock(&dpll_lock);
591         if (refcount_dec_and_test(&pin->refcount)) {
592                 xa_erase(&dpll_pin_xa, pin->id);
593                 xa_destroy(&pin->dpll_refs);
594                 xa_destroy(&pin->parent_refs);
595                 dpll_pin_prop_free(&pin->prop);
596                 kfree_rcu(pin, rcu);
597         }
598         mutex_unlock(&dpll_lock);
599 }
600 EXPORT_SYMBOL_GPL(dpll_pin_put);
601
602 static int
603 __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
604                     const struct dpll_pin_ops *ops, void *priv, void *cookie)
605 {
606         int ret;
607
608         ret = dpll_xa_ref_pin_add(&dpll->pin_refs, pin, ops, priv, cookie);
609         if (ret)
610                 return ret;
611         ret = dpll_xa_ref_dpll_add(&pin->dpll_refs, dpll, ops, priv, cookie);
612         if (ret)
613                 goto ref_pin_del;
614         xa_set_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
615         dpll_pin_create_ntf(pin);
616
617         return ret;
618
619 ref_pin_del:
620         dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv, cookie);
621         return ret;
622 }
623
624 /**
625  * dpll_pin_register - register the dpll pin in the subsystem
626  * @dpll: pointer to a dpll
627  * @pin: pointer to a dpll pin
628  * @ops: ops for a dpll pin ops
629  * @priv: pointer to private information of owner
630  *
631  * Context: Acquires a lock (dpll_lock)
632  * Return:
633  * * 0 on success
634  * * negative - error value
635  */
636 int
637 dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
638                   const struct dpll_pin_ops *ops, void *priv)
639 {
640         int ret;
641
642         if (WARN_ON(!ops) ||
643             WARN_ON(!ops->state_on_dpll_get) ||
644             WARN_ON(!ops->direction_get))
645                 return -EINVAL;
646
647         mutex_lock(&dpll_lock);
648         if (WARN_ON(!(dpll->module == pin->module &&
649                       dpll->clock_id == pin->clock_id)))
650                 ret = -EINVAL;
651         else
652                 ret = __dpll_pin_register(dpll, pin, ops, priv, NULL);
653         mutex_unlock(&dpll_lock);
654
655         return ret;
656 }
657 EXPORT_SYMBOL_GPL(dpll_pin_register);
658
659 static void
660 __dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
661                       const struct dpll_pin_ops *ops, void *priv, void *cookie)
662 {
663         ASSERT_DPLL_PIN_REGISTERED(pin);
664         dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv, cookie);
665         dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv, cookie);
666         if (xa_empty(&pin->dpll_refs))
667                 xa_clear_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
668 }
669
670 /**
671  * dpll_pin_unregister - unregister dpll pin from dpll device
672  * @dpll: registered dpll pointer
673  * @pin: pointer to a pin
674  * @ops: ops for a dpll pin
675  * @priv: pointer to private information of owner
676  *
677  * Note: It does not free the memory
678  * Context: Acquires a lock (dpll_lock)
679  */
680 void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
681                          const struct dpll_pin_ops *ops, void *priv)
682 {
683         if (WARN_ON(xa_empty(&dpll->pin_refs)))
684                 return;
685         if (WARN_ON(!xa_empty(&pin->parent_refs)))
686                 return;
687
688         mutex_lock(&dpll_lock);
689         dpll_pin_delete_ntf(pin);
690         __dpll_pin_unregister(dpll, pin, ops, priv, NULL);
691         mutex_unlock(&dpll_lock);
692 }
693 EXPORT_SYMBOL_GPL(dpll_pin_unregister);
694
695 /**
696  * dpll_pin_on_pin_register - register a pin with a parent pin
697  * @parent: pointer to a parent pin
698  * @pin: pointer to a pin
699  * @ops: ops for a dpll pin
700  * @priv: pointer to private information of owner
701  *
702  * Register a pin with a parent pin, create references between them and
703  * between newly registered pin and dplls connected with a parent pin.
704  *
705  * Context: Acquires a lock (dpll_lock)
706  * Return:
707  * * 0 on success
708  * * negative - error value
709  */
710 int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
711                              const struct dpll_pin_ops *ops, void *priv)
712 {
713         struct dpll_pin_ref *ref;
714         unsigned long i, stop;
715         int ret;
716
717         if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX))
718                 return -EINVAL;
719
720         if (WARN_ON(!ops) ||
721             WARN_ON(!ops->state_on_pin_get) ||
722             WARN_ON(!ops->direction_get))
723                 return -EINVAL;
724
725         mutex_lock(&dpll_lock);
726         ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv, pin);
727         if (ret)
728                 goto unlock;
729         refcount_inc(&pin->refcount);
730         xa_for_each(&parent->dpll_refs, i, ref) {
731                 ret = __dpll_pin_register(ref->dpll, pin, ops, priv, parent);
732                 if (ret) {
733                         stop = i;
734                         goto dpll_unregister;
735                 }
736                 dpll_pin_create_ntf(pin);
737         }
738         mutex_unlock(&dpll_lock);
739
740         return ret;
741
742 dpll_unregister:
743         xa_for_each(&parent->dpll_refs, i, ref)
744                 if (i < stop) {
745                         __dpll_pin_unregister(ref->dpll, pin, ops, priv,
746                                               parent);
747                         dpll_pin_delete_ntf(pin);
748                 }
749         refcount_dec(&pin->refcount);
750         dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
751 unlock:
752         mutex_unlock(&dpll_lock);
753         return ret;
754 }
755 EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register);
756
757 /**
758  * dpll_pin_on_pin_unregister - unregister dpll pin from a parent pin
759  * @parent: pointer to a parent pin
760  * @pin: pointer to a pin
761  * @ops: ops for a dpll pin
762  * @priv: pointer to private information of owner
763  *
764  * Context: Acquires a lock (dpll_lock)
765  * Note: It does not free the memory
766  */
767 void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
768                                 const struct dpll_pin_ops *ops, void *priv)
769 {
770         struct dpll_pin_ref *ref;
771         unsigned long i;
772
773         mutex_lock(&dpll_lock);
774         dpll_pin_delete_ntf(pin);
775         dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
776         refcount_dec(&pin->refcount);
777         xa_for_each(&pin->dpll_refs, i, ref)
778                 __dpll_pin_unregister(ref->dpll, pin, ops, priv, parent);
779         mutex_unlock(&dpll_lock);
780 }
781 EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister);
782
783 static struct dpll_device_registration *
784 dpll_device_registration_first(struct dpll_device *dpll)
785 {
786         struct dpll_device_registration *reg;
787
788         reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list,
789                                        struct dpll_device_registration, list);
790         WARN_ON(!reg);
791         return reg;
792 }
793
794 void *dpll_priv(struct dpll_device *dpll)
795 {
796         struct dpll_device_registration *reg;
797
798         reg = dpll_device_registration_first(dpll);
799         return reg->priv;
800 }
801
802 const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll)
803 {
804         struct dpll_device_registration *reg;
805
806         reg = dpll_device_registration_first(dpll);
807         return reg->ops;
808 }
809
810 static struct dpll_pin_registration *
811 dpll_pin_registration_first(struct dpll_pin_ref *ref)
812 {
813         struct dpll_pin_registration *reg;
814
815         reg = list_first_entry_or_null(&ref->registration_list,
816                                        struct dpll_pin_registration, list);
817         WARN_ON(!reg);
818         return reg;
819 }
820
821 void *dpll_pin_on_dpll_priv(struct dpll_device *dpll,
822                             struct dpll_pin *pin)
823 {
824         struct dpll_pin_registration *reg;
825         struct dpll_pin_ref *ref;
826
827         ref = xa_load(&dpll->pin_refs, pin->pin_idx);
828         if (!ref)
829                 return NULL;
830         reg = dpll_pin_registration_first(ref);
831         return reg->priv;
832 }
833
834 void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
835                            struct dpll_pin *pin)
836 {
837         struct dpll_pin_registration *reg;
838         struct dpll_pin_ref *ref;
839
840         ref = xa_load(&pin->parent_refs, parent->pin_idx);
841         if (!ref)
842                 return NULL;
843         reg = dpll_pin_registration_first(ref);
844         return reg->priv;
845 }
846
847 const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
848 {
849         struct dpll_pin_registration *reg;
850
851         reg = dpll_pin_registration_first(ref);
852         return reg->ops;
853 }
854
855 static int __init dpll_init(void)
856 {
857         int ret;
858
859         ret = genl_register_family(&dpll_nl_family);
860         if (ret)
861                 goto error;
862
863         return 0;
864
865 error:
866         mutex_destroy(&dpll_lock);
867         return ret;
868 }
869
870 static void __exit dpll_exit(void)
871 {
872         genl_unregister_family(&dpll_nl_family);
873         mutex_destroy(&dpll_lock);
874 }
875
876 subsys_initcall(dpll_init);
877 module_exit(dpll_exit);
This page took 0.085042 seconds and 4 git commands to generate.