123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * COPYRIGHT(C) 2020-2021 Samsung Electronics Co., Ltd. All Right Reserved.
- */
- #ifndef __BUILDER_PATTERN_H__
- #define __BUILDER_PATTERN_H__
- #include <linux/device.h>
- #include <linux/kernel.h>
- #include <linux/kthread.h>
- #include <linux/of.h>
- struct director_threaded;
- /* An interface 'Builder' struct
- * TODO: This struct should be embedded if the drvdata use
- * this 'Builder Pattern'.
- */
- struct builder {
- struct device *dev;
- struct director_threaded *drct;
- };
- #define DT_BUILDER(__parse_dt) \
- { .parse_dt = __parse_dt, }
- /* The prototype of 'Concrete Builde' parsing a device tree */
- typedef int (*parse_dt_t)(struct builder *bd, struct device_node *np);
- struct dt_builder {
- parse_dt_t parse_dt;
- };
- #define DEVICE_BUILDER(__construct_dev, __destruct_dev) \
- { .construct_dev = __construct_dev, .destruct_dev = __destruct_dev, }
- /* The prototype of 'Concrete Builde' constructing a device */
- typedef int (*construct_dev_t)(struct builder *bd);
- /* The prototype of 'Concrete Builde' destructing a device */
- typedef void (*destruct_dev_t)(struct builder *bd);
- struct dev_builder {
- construct_dev_t construct_dev;
- destruct_dev_t destruct_dev;
- };
- #ifdef _DEBUG_BUILDER_PATTERN
- static inline int __bp_call_parse_dt(parse_dt_t parse_dt,
- struct builder *bd, struct device_node *np)
- {
- ktime_t calltime, rettime;
- int err;
- calltime = ktime_get();
- err = parse_dt(bd, np);
- rettime = ktime_get();
- dev_info(bd->dev, "%ps returned %d after %llu\n",
- parse_dt, err,
- (unsigned long long)ktime_sub(rettime, calltime));
- return err;
- }
- static inline int __bp_call_construct_dev(construct_dev_t construct_dev,
- struct builder *bd)
- {
- ktime_t calltime, rettime;
- int err;
- calltime = ktime_get();
- err = construct_dev(bd);
- rettime = ktime_get();
- dev_info(bd->dev, "%ps returned %d after %llu\n",
- construct_dev , err,
- (unsigned long long)ktime_sub(rettime, calltime));
- return err;
- }
- static inline void __bp_call_destruct_dev(destruct_dev_t destruct_dev,
- struct builder *bd)
- {
- ktime_t calltime, rettime;
- calltime = ktime_get();
- destruct_dev(bd);
- rettime = ktime_get();
- dev_info(bd->dev, "%ps returned after %llu\n",
- destruct_dev,
- (unsigned long long)ktime_sub(rettime, calltime));
- }
- #else
- static inline int __bp_call_parse_dt(parse_dt_t parse_dt,
- struct builder *bd, struct device_node *np)
- {
- return parse_dt(bd, np);
- }
- static inline int __bp_call_construct_dev(construct_dev_t construct_dev,
- struct builder *bd)
- {
- return construct_dev(bd);
- }
- static inline void __bp_call_destruct_dev(destruct_dev_t destruct_dev,
- struct builder *bd)
- {
- destruct_dev(bd);
- }
- #endif
- static inline int __bp_call_concrete_parse_dt(struct builder *bd,
- const struct dt_builder *builder, size_t i)
- {
- struct device_node *np = dev_of_node(bd->dev);
- int err;
- parse_dt_t parse_dt = builder[i].parse_dt;
- err = __bp_call_parse_dt(parse_dt, bd, np);
- if (err)
- dev_err(bd->dev, "failed to parse a device tree - [%zu] %ps (%d)\n",
- i, parse_dt, err);
- return err;
- }
- static inline int __bp_call_concrete_construct_dev(struct builder *bd,
- const struct dev_builder *builder, size_t i)
- {
- int err;
- construct_dev_t construct_dev = builder[i].construct_dev;
- if (!construct_dev)
- return 0;
- err = __bp_call_construct_dev(construct_dev, bd);
- if (err)
- dev_err(bd->dev, "failed to construct_dev a device - [%zu] %ps (%d)\n",
- i, construct_dev, err);
- return err;
- }
- static inline void __bp_call_concrete_destruct_dev(struct builder *bd,
- const struct dev_builder *builder, size_t i)
- {
- destruct_dev_t destruct_dev = builder[i].destruct_dev;
- if (!destruct_dev)
- return;
- __bp_call_destruct_dev(destruct_dev, bd);
- }
- /* A common 'Director' parsing a device tree
- * @return - 0 on success. 'errno' of last failed on failure.
- */
- static inline int sec_director_parse_dt(struct builder *bd,
- const struct dt_builder *builder, size_t n)
- {
- int err;
- size_t i;
- for (i = 0; i < n; i++) {
- err = __bp_call_concrete_parse_dt(bd, builder, i);
- if (err)
- return err;
- }
- return 0;
- }
- /* A common 'Director' constructing a device
- * @last_failed - The number of called builders on success.
- * The "NEGATIVE" index of last failed on failure.
- * @return - 0 on success.
- * return value of the last concrete builder on failure.
- */
- static inline int sec_director_construct_dev(struct builder *bd,
- const struct dev_builder *builder, ssize_t n,
- ssize_t *last_failed)
- {
- int err;
- ssize_t i;
- for (i = 0; i < n; i++) {
- err = __bp_call_concrete_construct_dev(bd, builder, i);
- if (err) {
- *last_failed = -i;
- return err;
- }
- }
- *last_failed = n;
- return 0;
- }
- /* A common 'Director' destructing a device */
- static inline void sec_director_destruct_dev(struct builder *bd,
- const struct dev_builder *builder, ssize_t n,
- ssize_t last_failed)
- {
- ssize_t i;
- BUG_ON((last_failed > n) || (last_failed < 0));
- for (i = last_failed - 1; i >= 0; i--)
- __bp_call_concrete_destruct_dev(bd, builder, i);
- }
- /* A wrapper function for probe call-backs */
- static inline int sec_director_probe_dev(struct builder *bd,
- const struct dev_builder *builder, ssize_t n)
- {
- int err;
- ssize_t last_failed;
- err = sec_director_construct_dev(bd, builder, n, &last_failed);
- if (last_failed <= 0)
- goto err_dev_director;
- return 0;
- err_dev_director:
- sec_director_destruct_dev(bd, builder, n, -last_failed);
- return err;
- }
- struct director_threaded {
- struct builder *bd;
- const struct dev_builder *builder;
- ssize_t n;
- int *construct_result;
- };
- /* A common 'Director' constructing a device - threaded */
- static int sec_director_construct_dev_threaded(void *__drct)
- {
- struct director_threaded *drct = __drct;
- struct builder *bd = drct->bd;
- const struct dev_builder *builder = drct->builder;
- ssize_t n = drct->n;
- int *construct_result = drct->construct_result;
- ssize_t i;
- for (i = 0; i < n; i++)
- construct_result[i] =
- __bp_call_concrete_construct_dev(bd, builder, i);
- return 0;
- }
- /* A common 'Director' destructing a device */
- static inline void sec_director_destruct_dev_threaded(
- struct director_threaded *drct)
- {
- struct builder *bd = drct->bd;
- const struct dev_builder *builder = drct->builder;
- ssize_t n = drct->n;
- int *construct_result = drct->construct_result;
- ssize_t i;
- for (i = n - 1; i >= 0; i--) {
- if (!construct_result[i])
- __bp_call_concrete_destruct_dev(bd, builder, i);
- }
- }
- /* A wrapper function for probe call-backs - threaded */
- static inline int sec_director_probe_dev_threaded(struct builder *bd,
- const struct dev_builder *builder, ssize_t n, const char *name)
- {
- struct device *dev = bd->dev;
- struct director_threaded *drct;
- int *construct_result;
- struct task_struct *thread;
- drct = devm_kzalloc(dev, sizeof(*drct), GFP_KERNEL);
- if (!drct)
- return -ENOMEM;
- construct_result = devm_kcalloc(dev, n, sizeof(*construct_result),
- GFP_KERNEL);
- if (!construct_result)
- return -ENOMEM;
- drct->bd = bd;
- drct->builder = builder;
- drct->n = n;
- drct->construct_result = construct_result;
- thread = kthread_run(sec_director_construct_dev_threaded,
- drct, "drct-%s", name);
- if (IS_ERR_OR_NULL(thread)) {
- dev_err(dev, "failed to created drct thread - (%ld)!\n",
- PTR_ERR(thread));
- return -ENOMEM;
- }
- bd->drct = drct;
- return 0;
- }
- #endif /* __BUILDER_PATTERN_H__ */
|