1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2020 Linaro Limited, All rights reserved.
4 * Author: Mike Leach <mike.leach@linaro.org>
7 #include <linux/configfs.h>
9 #include "coresight-config.h"
10 #include "coresight-syscfg-configfs.h"
12 /* create a default ci_type. */
13 static inline struct config_item_type
*cscfg_create_ci_type(void)
15 struct config_item_type
*ci_type
;
17 ci_type
= devm_kzalloc(cscfg_device(), sizeof(*ci_type
), GFP_KERNEL
);
19 ci_type
->ct_owner
= THIS_MODULE
;
24 /* configurations sub-group */
26 /* attributes for the config view group */
27 static ssize_t
cscfg_cfg_description_show(struct config_item
*item
, char *page
)
29 struct cscfg_fs_config
*fs_config
= container_of(to_config_group(item
),
30 struct cscfg_fs_config
, group
);
32 return scnprintf(page
, PAGE_SIZE
, "%s", fs_config
->config_desc
->description
);
34 CONFIGFS_ATTR_RO(cscfg_cfg_
, description
);
36 static ssize_t
cscfg_cfg_feature_refs_show(struct config_item
*item
, char *page
)
38 struct cscfg_fs_config
*fs_config
= container_of(to_config_group(item
),
39 struct cscfg_fs_config
, group
);
40 const struct cscfg_config_desc
*config_desc
= fs_config
->config_desc
;
44 for (i
= 0; i
< config_desc
->nr_feat_refs
; i
++)
45 ch_used
+= scnprintf(page
+ ch_used
, PAGE_SIZE
- ch_used
,
46 "%s\n", config_desc
->feat_ref_names
[i
]);
49 CONFIGFS_ATTR_RO(cscfg_cfg_
, feature_refs
);
51 /* list preset values in order of features and params */
52 static ssize_t
cscfg_cfg_values_show(struct config_item
*item
, char *page
)
54 const struct cscfg_feature_desc
*feat_desc
;
55 const struct cscfg_config_desc
*config_desc
;
56 struct cscfg_fs_preset
*fs_preset
;
57 int i
, j
, val_idx
, preset_idx
;
60 fs_preset
= container_of(to_config_group(item
), struct cscfg_fs_preset
, group
);
61 config_desc
= fs_preset
->config_desc
;
63 if (!config_desc
->nr_presets
)
66 preset_idx
= fs_preset
->preset_num
- 1;
68 /* start index on the correct array line */
69 val_idx
= config_desc
->nr_total_params
* preset_idx
;
72 * A set of presets is the sum of all params in used features,
73 * in order of declaration of features and params in the features
75 for (i
= 0; i
< config_desc
->nr_feat_refs
; i
++) {
76 feat_desc
= cscfg_get_named_feat_desc(config_desc
->feat_ref_names
[i
]);
77 for (j
= 0; j
< feat_desc
->nr_params
; j
++) {
78 used
+= scnprintf(page
+ used
, PAGE_SIZE
- used
,
81 feat_desc
->params_desc
[j
].name
,
82 config_desc
->presets
[val_idx
++]);
85 used
+= scnprintf(page
+ used
, PAGE_SIZE
- used
, "\n");
89 CONFIGFS_ATTR_RO(cscfg_cfg_
, values
);
91 static ssize_t
cscfg_cfg_enable_show(struct config_item
*item
, char *page
)
93 struct cscfg_fs_config
*fs_config
= container_of(to_config_group(item
),
94 struct cscfg_fs_config
, group
);
96 return scnprintf(page
, PAGE_SIZE
, "%d\n", fs_config
->active
);
99 static ssize_t
cscfg_cfg_enable_store(struct config_item
*item
,
100 const char *page
, size_t count
)
102 struct cscfg_fs_config
*fs_config
= container_of(to_config_group(item
),
103 struct cscfg_fs_config
, group
);
107 err
= kstrtobool(page
, &val
);
109 err
= cscfg_config_sysfs_activate(fs_config
->config_desc
, val
);
111 fs_config
->active
= val
;
113 cscfg_config_sysfs_set_preset(fs_config
->preset
);
115 return err
? err
: count
;
117 CONFIGFS_ATTR(cscfg_cfg_
, enable
);
119 static ssize_t
cscfg_cfg_preset_show(struct config_item
*item
, char *page
)
121 struct cscfg_fs_config
*fs_config
= container_of(to_config_group(item
),
122 struct cscfg_fs_config
, group
);
124 return scnprintf(page
, PAGE_SIZE
, "%d\n", fs_config
->preset
);
127 static ssize_t
cscfg_cfg_preset_store(struct config_item
*item
,
128 const char *page
, size_t count
)
130 struct cscfg_fs_config
*fs_config
= container_of(to_config_group(item
),
131 struct cscfg_fs_config
, group
);
134 err
= kstrtoint(page
, 0, &preset
);
137 * presets start at 1, and go up to max (15),
138 * but the config may provide fewer.
140 if ((preset
< 1) || (preset
> fs_config
->config_desc
->nr_presets
))
146 fs_config
->preset
= preset
;
147 /* set on system if active */
148 if (fs_config
->active
)
149 cscfg_config_sysfs_set_preset(fs_config
->preset
);
151 return err
? err
: count
;
153 CONFIGFS_ATTR(cscfg_cfg_
, preset
);
155 static struct configfs_attribute
*cscfg_config_view_attrs
[] = {
156 &cscfg_cfg_attr_description
,
157 &cscfg_cfg_attr_feature_refs
,
158 &cscfg_cfg_attr_enable
,
159 &cscfg_cfg_attr_preset
,
163 static struct config_item_type cscfg_config_view_type
= {
164 .ct_owner
= THIS_MODULE
,
165 .ct_attrs
= cscfg_config_view_attrs
,
168 static struct configfs_attribute
*cscfg_config_preset_attrs
[] = {
169 &cscfg_cfg_attr_values
,
173 static struct config_item_type cscfg_config_preset_type
= {
174 .ct_owner
= THIS_MODULE
,
175 .ct_attrs
= cscfg_config_preset_attrs
,
178 static int cscfg_add_preset_groups(struct cscfg_fs_config
*cfg_view
)
181 struct cscfg_fs_preset
*cfg_fs_preset
;
182 struct cscfg_config_desc
*config_desc
= cfg_view
->config_desc
;
183 char name
[CONFIGFS_ITEM_NAME_LEN
];
185 if (!config_desc
->nr_presets
)
188 for (preset_num
= 1; preset_num
<= config_desc
->nr_presets
; preset_num
++) {
189 cfg_fs_preset
= devm_kzalloc(cscfg_device(),
190 sizeof(struct cscfg_fs_preset
), GFP_KERNEL
);
195 snprintf(name
, CONFIGFS_ITEM_NAME_LEN
, "preset%d", preset_num
);
196 cfg_fs_preset
->preset_num
= preset_num
;
197 cfg_fs_preset
->config_desc
= cfg_view
->config_desc
;
198 config_group_init_type_name(&cfg_fs_preset
->group
, name
,
199 &cscfg_config_preset_type
);
200 configfs_add_default_group(&cfg_fs_preset
->group
, &cfg_view
->group
);
205 static struct config_group
*cscfg_create_config_group(struct cscfg_config_desc
*config_desc
)
207 struct cscfg_fs_config
*cfg_view
;
208 struct device
*dev
= cscfg_device();
212 return ERR_PTR(-EINVAL
);
214 cfg_view
= devm_kzalloc(dev
, sizeof(struct cscfg_fs_config
), GFP_KERNEL
);
216 return ERR_PTR(-ENOMEM
);
218 cfg_view
->config_desc
= config_desc
;
219 config_group_init_type_name(&cfg_view
->group
, config_desc
->name
, &cscfg_config_view_type
);
221 /* add in a preset<n> dir for each preset */
222 err
= cscfg_add_preset_groups(cfg_view
);
226 return &cfg_view
->group
;
229 /* attributes for features view */
231 static ssize_t
cscfg_feat_description_show(struct config_item
*item
, char *page
)
233 struct cscfg_fs_feature
*fs_feat
= container_of(to_config_group(item
),
234 struct cscfg_fs_feature
, group
);
236 return scnprintf(page
, PAGE_SIZE
, "%s", fs_feat
->feat_desc
->description
);
238 CONFIGFS_ATTR_RO(cscfg_feat_
, description
);
240 static ssize_t
cscfg_feat_matches_show(struct config_item
*item
, char *page
)
242 struct cscfg_fs_feature
*fs_feat
= container_of(to_config_group(item
),
243 struct cscfg_fs_feature
, group
);
244 u32 match_flags
= fs_feat
->feat_desc
->match_flags
;
247 if (match_flags
& CS_CFG_MATCH_CLASS_SRC_ALL
)
248 used
= scnprintf(page
, PAGE_SIZE
, "SRC_ALL ");
250 if (match_flags
& CS_CFG_MATCH_CLASS_SRC_ETM4
)
251 used
+= scnprintf(page
+ used
, PAGE_SIZE
- used
, "SRC_ETMV4 ");
253 used
+= scnprintf(page
+ used
, PAGE_SIZE
- used
, "\n");
256 CONFIGFS_ATTR_RO(cscfg_feat_
, matches
);
258 static ssize_t
cscfg_feat_nr_params_show(struct config_item
*item
, char *page
)
260 struct cscfg_fs_feature
*fs_feat
= container_of(to_config_group(item
),
261 struct cscfg_fs_feature
, group
);
263 return scnprintf(page
, PAGE_SIZE
, "%d\n", fs_feat
->feat_desc
->nr_params
);
265 CONFIGFS_ATTR_RO(cscfg_feat_
, nr_params
);
267 /* base feature desc attrib structures */
268 static struct configfs_attribute
*cscfg_feature_view_attrs
[] = {
269 &cscfg_feat_attr_description
,
270 &cscfg_feat_attr_matches
,
271 &cscfg_feat_attr_nr_params
,
275 static struct config_item_type cscfg_feature_view_type
= {
276 .ct_owner
= THIS_MODULE
,
277 .ct_attrs
= cscfg_feature_view_attrs
,
280 static ssize_t
cscfg_param_value_show(struct config_item
*item
, char *page
)
282 struct cscfg_fs_param
*param_item
= container_of(to_config_group(item
),
283 struct cscfg_fs_param
, group
);
284 u64 value
= param_item
->feat_desc
->params_desc
[param_item
->param_idx
].value
;
286 return scnprintf(page
, PAGE_SIZE
, "0x%llx\n", value
);
289 static ssize_t
cscfg_param_value_store(struct config_item
*item
,
290 const char *page
, size_t size
)
292 struct cscfg_fs_param
*param_item
= container_of(to_config_group(item
),
293 struct cscfg_fs_param
, group
);
294 struct cscfg_feature_desc
*feat_desc
= param_item
->feat_desc
;
295 int param_idx
= param_item
->param_idx
;
299 err
= kstrtoull(page
, 0, &value
);
301 err
= cscfg_update_feat_param_val(feat_desc
, param_idx
, value
);
303 return err
? err
: size
;
305 CONFIGFS_ATTR(cscfg_param_
, value
);
307 static struct configfs_attribute
*cscfg_param_view_attrs
[] = {
308 &cscfg_param_attr_value
,
312 static struct config_item_type cscfg_param_view_type
= {
313 .ct_owner
= THIS_MODULE
,
314 .ct_attrs
= cscfg_param_view_attrs
,
318 * configfs has far less functionality provided to add attributes dynamically than sysfs,
319 * and the show and store fns pass the enclosing config_item so the actual attribute cannot
320 * be determined. Therefore we add each item as a group directory, with a value attribute.
322 static int cscfg_create_params_group_items(struct cscfg_feature_desc
*feat_desc
,
323 struct config_group
*params_group
)
325 struct device
*dev
= cscfg_device();
326 struct cscfg_fs_param
*param_item
;
329 /* parameter items - as groups with default_value attribute */
330 for (i
= 0; i
< feat_desc
->nr_params
; i
++) {
331 param_item
= devm_kzalloc(dev
, sizeof(struct cscfg_fs_param
), GFP_KERNEL
);
334 param_item
->feat_desc
= feat_desc
;
335 param_item
->param_idx
= i
;
336 config_group_init_type_name(¶m_item
->group
,
337 feat_desc
->params_desc
[i
].name
,
338 &cscfg_param_view_type
);
339 configfs_add_default_group(¶m_item
->group
, params_group
);
344 static struct config_group
*cscfg_create_feature_group(struct cscfg_feature_desc
*feat_desc
)
346 struct cscfg_fs_feature
*feat_view
;
347 struct config_item_type
*params_group_type
;
348 struct config_group
*params_group
= NULL
;
349 struct device
*dev
= cscfg_device();
353 return ERR_PTR(-EINVAL
);
355 feat_view
= devm_kzalloc(dev
, sizeof(struct cscfg_fs_feature
), GFP_KERNEL
);
357 return ERR_PTR(-ENOMEM
);
359 if (feat_desc
->nr_params
) {
360 params_group
= devm_kzalloc(dev
, sizeof(struct config_group
), GFP_KERNEL
);
362 return ERR_PTR(-ENOMEM
);
364 params_group_type
= cscfg_create_ci_type();
365 if (!params_group_type
)
366 return ERR_PTR(-ENOMEM
);
369 feat_view
->feat_desc
= feat_desc
;
370 config_group_init_type_name(&feat_view
->group
,
372 &cscfg_feature_view_type
);
374 config_group_init_type_name(params_group
, "params", params_group_type
);
375 configfs_add_default_group(params_group
, &feat_view
->group
);
376 item_err
= cscfg_create_params_group_items(feat_desc
, params_group
);
378 return ERR_PTR(item_err
);
380 return &feat_view
->group
;
383 static struct config_item_type cscfg_configs_type
= {
384 .ct_owner
= THIS_MODULE
,
387 static struct config_group cscfg_configs_grp
= {
389 .ci_namebuf
= "configurations",
390 .ci_type
= &cscfg_configs_type
,
394 /* add configuration to configurations group */
395 int cscfg_configfs_add_config(struct cscfg_config_desc
*config_desc
)
397 struct config_group
*new_group
;
400 new_group
= cscfg_create_config_group(config_desc
);
401 if (IS_ERR(new_group
))
402 return PTR_ERR(new_group
);
403 err
= configfs_register_group(&cscfg_configs_grp
, new_group
);
405 config_desc
->fs_group
= new_group
;
409 void cscfg_configfs_del_config(struct cscfg_config_desc
*config_desc
)
411 if (config_desc
->fs_group
) {
412 configfs_unregister_group(config_desc
->fs_group
);
413 config_desc
->fs_group
= NULL
;
417 static struct config_item_type cscfg_features_type
= {
418 .ct_owner
= THIS_MODULE
,
421 static struct config_group cscfg_features_grp
= {
423 .ci_namebuf
= "features",
424 .ci_type
= &cscfg_features_type
,
428 /* add feature to features group */
429 int cscfg_configfs_add_feature(struct cscfg_feature_desc
*feat_desc
)
431 struct config_group
*new_group
;
434 new_group
= cscfg_create_feature_group(feat_desc
);
435 if (IS_ERR(new_group
))
436 return PTR_ERR(new_group
);
437 err
= configfs_register_group(&cscfg_features_grp
, new_group
);
439 feat_desc
->fs_group
= new_group
;
443 void cscfg_configfs_del_feature(struct cscfg_feature_desc
*feat_desc
)
445 if (feat_desc
->fs_group
) {
446 configfs_unregister_group(feat_desc
->fs_group
);
447 feat_desc
->fs_group
= NULL
;
451 int cscfg_configfs_init(struct cscfg_manager
*cscfg_mgr
)
453 struct configfs_subsystem
*subsys
;
454 struct config_item_type
*ci_type
;
459 ci_type
= cscfg_create_ci_type();
463 subsys
= &cscfg_mgr
->cfgfs_subsys
;
464 config_item_set_name(&subsys
->su_group
.cg_item
, CSCFG_FS_SUBSYS_NAME
);
465 subsys
->su_group
.cg_item
.ci_type
= ci_type
;
467 config_group_init(&subsys
->su_group
);
468 mutex_init(&subsys
->su_mutex
);
470 /* Add default groups to subsystem */
471 config_group_init(&cscfg_configs_grp
);
472 configfs_add_default_group(&cscfg_configs_grp
, &subsys
->su_group
);
474 config_group_init(&cscfg_features_grp
);
475 configfs_add_default_group(&cscfg_features_grp
, &subsys
->su_group
);
477 return configfs_register_subsystem(subsys
);
480 void cscfg_configfs_release(struct cscfg_manager
*cscfg_mgr
)
482 configfs_unregister_subsystem(&cscfg_mgr
->cfgfs_subsys
);