417db3f92c2fd38b1a11fcfb315f2e1eb469d284
[linux-2.6-microblaze.git] / drivers / hwtracing / coresight / coresight-syscfg.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Linaro Limited, All rights reserved.
4  * Author: Mike Leach <mike.leach@linaro.org>
5  */
6
7 #include <linux/platform_device.h>
8
9 #include "coresight-config.h"
10 #include "coresight-syscfg.h"
11
12 /*
13  * cscfg_ API manages configurations and features for the entire coresight
14  * infrastructure.
15  *
16  * It allows the loading of configurations and features, and loads these into
17  * coresight devices as appropriate.
18  */
19
20 /* protect the cscsg_data and device */
21 static DEFINE_MUTEX(cscfg_mutex);
22
23 /* only one of these */
24 static struct cscfg_manager *cscfg_mgr;
25
26 /* load features and configuations into the lists */
27
28 /* check feature list for a named feature - call with mutex locked. */
29 static bool cscfg_match_list_feat(const char *name)
30 {
31         struct cscfg_feature_desc *feat_desc;
32
33         list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
34                 if (strcmp(feat_desc->name, name) == 0)
35                         return true;
36         }
37         return false;
38 }
39
40 /* check all feat needed for cfg are in the list - call with mutex locked. */
41 static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
42 {
43         int i;
44
45         for (i = 0; i < config_desc->nr_feat_refs; i++)
46                 if (!cscfg_match_list_feat(config_desc->feat_ref_names[i]))
47                         return -EINVAL;
48         return 0;
49 }
50
51 /*
52  * load feature - add to feature list.
53  */
54 static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
55 {
56         list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list);
57
58         return 0;
59 }
60
61 /*
62  * load config into the system - validate used features exist then add to
63  * config list.
64  */
65 static int cscfg_load_config(struct cscfg_config_desc *config_desc)
66 {
67         int err;
68
69         /* validate features are present */
70         err = cscfg_check_feat_for_cfg(config_desc);
71         if (err)
72                 return err;
73
74         list_add(&config_desc->item, &cscfg_mgr->config_desc_list);
75         return 0;
76 }
77
78 /**
79  * cscfg_load_config_sets - API function to load feature and config sets.
80  *
81  * Take a 0 terminated array of feature descriptors and/or configuration
82  * descriptors and load into the system.
83  * Features are loaded first to ensure configuration dependencies can be met.
84  *
85  * @config_descs: 0 terminated array of configuration descriptors.
86  * @feat_descs:   0 terminated array of feature descriptors.
87  */
88 int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
89                            struct cscfg_feature_desc **feat_descs)
90 {
91         int err, i = 0;
92
93         mutex_lock(&cscfg_mutex);
94
95         /* load features first */
96         if (feat_descs) {
97                 while (feat_descs[i]) {
98                         err = cscfg_load_feat(feat_descs[i]);
99                         if (err) {
100                                 pr_err("coresight-syscfg: Failed to load feature %s\n",
101                                        feat_descs[i]->name);
102                                 goto exit_unlock;
103                         }
104                         i++;
105                 }
106         }
107
108         /* next any configurations to check feature dependencies */
109         i = 0;
110         if (config_descs) {
111                 while (config_descs[i]) {
112                         err = cscfg_load_config(config_descs[i]);
113                         if (err) {
114                                 pr_err("coresight-syscfg: Failed to load configuration %s\n",
115                                        config_descs[i]->name);
116                                 goto exit_unlock;
117                         }
118                         i++;
119                 }
120         }
121
122 exit_unlock:
123         mutex_unlock(&cscfg_mutex);
124         return err;
125 }
126 EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
127
128 /* Initialise system configuration management device. */
129
130 struct device *cscfg_device(void)
131 {
132         return cscfg_mgr ? &cscfg_mgr->dev : NULL;
133 }
134
135 /* Must have a release function or the kernel will complain on module unload */
136 static void cscfg_dev_release(struct device *dev)
137 {
138         kfree(cscfg_mgr);
139         cscfg_mgr = NULL;
140 }
141
142 /* a device is needed to "own" some kernel elements such as sysfs entries.  */
143 static int cscfg_create_device(void)
144 {
145         struct device *dev;
146         int err = -ENOMEM;
147
148         mutex_lock(&cscfg_mutex);
149         if (cscfg_mgr) {
150                 err = -EINVAL;
151                 goto create_dev_exit_unlock;
152         }
153
154         cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);
155         if (!cscfg_mgr)
156                 goto create_dev_exit_unlock;
157
158         /* setup the device */
159         dev = cscfg_device();
160         dev->release = cscfg_dev_release;
161         dev->init_name = "cs_system_cfg";
162
163         err = device_register(dev);
164         if (err)
165                 cscfg_dev_release(dev);
166
167 create_dev_exit_unlock:
168         mutex_unlock(&cscfg_mutex);
169         return err;
170 }
171
172 static void cscfg_clear_device(void)
173 {
174         mutex_lock(&cscfg_mutex);
175         device_unregister(cscfg_device());
176         mutex_unlock(&cscfg_mutex);
177 }
178
179 /* Initialise system config management API device  */
180 int __init cscfg_init(void)
181 {
182         int err = 0;
183
184         err = cscfg_create_device();
185         if (err)
186                 return err;
187
188         INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
189         INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
190         INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
191
192         dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
193         return 0;
194 }
195
196 void cscfg_exit(void)
197 {
198         cscfg_clear_device();
199 }