On Wed, Jun 05, 2019 at 08:03:06PM +0100, Mike Leach wrote:
Dynamically adds sysfs attributes for all connections defined in the CTI.
Each connection has _name, _trgin_type, _trgout_type, _trgin_sig and _trgout_sig, preceded by a connection index (e.g. 0_name is the name of connection 0).
Additionally each device has a nr_cons and trigout_filtered parameter. This allows clients to explore the connection and trigger signal details without needing to refer to device tree or specification of the device.
Standardised type information is provided for certain common functions - e.g. snk_full for a trigger from a sink indicating full. Otherwise type defaults to genio.
I will skip this one and wait for V4.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 338 +++++++++++++++++- drivers/hwtracing/coresight/coresight-cti.c | 11 + drivers/hwtracing/coresight/coresight-cti.h | 4 + 3 files changed, 352 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index e1eacd2b0f6e..a083b2f4306e 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -875,7 +875,342 @@ static struct attribute *coresight_cti_channel_attrs[] = { NULL, }; -/* sysfs groups */ +/* Create the connections group attrs dynamically */
+/* group is static - .attrs will be built dynamically */ +static struct attribute_group coresight_cti_conns_group = {
- .name = "connections",
+};
+/*
- *Each connection has dynamic name, trigin/out sigs/types attrs,
- each device has static nr conns + filter attr
- */
+static ssize_t trigout_filtered_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- int b_sz = PAGE_SIZE;
- u32 sig_mask;
- int sig_idx, used = 0, nr_trig_max = cfg->nr_trig_max;
- if (cfg->trig_out_filter) {
sig_mask = 0x1;
for (sig_idx = 0; sig_idx < nr_trig_max; sig_idx++) {
if (sig_mask & cfg->trig_out_filter) {
used += scnprintf(buf+used, b_sz-used, "%d ",
sig_idx);
}
sig_mask <<= 1;
}
used += scnprintf(buf+used, b_sz-used, "\n");
- } else
used += scnprintf(buf, b_sz, "none\n");
- return used;
+} +static DEVICE_ATTR_RO(trigout_filtered);
+static ssize_t nr_cons_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- return scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->ctidev.nr_trig_con);
+} +static DEVICE_ATTR_RO(nr_cons);
+/* static attrs - 2 + null terminator */ +#define CTI_SYSFS_CONS_ST_ATTR 3 +/* dynamic attr - per connection */ +#define CTI_SYSFS_CONS_DYN_ATTR 5
+static ssize_t con_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- return scnprintf(buf, PAGE_SIZE, "%s\n", con->con_dev_name);
+}
+static ssize_t trigin_sig_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- u32 sig_mask;
- int sig_idx, used = 0, b_sz = PAGE_SIZE;
- sig_mask = 0x1;
- for (sig_idx = 0; sig_idx < cfg->nr_trig_max; sig_idx++) {
if (sig_mask & con->con_in->used_mask) {
used += scnprintf(buf+used, b_sz-used, "%d ",
sig_idx);
}
sig_mask <<= 1;
- }
- used += scnprintf(buf+used, b_sz-used, "\n");
- return used;
+}
+static ssize_t trigout_sig_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *cfg = &drvdata->config;
- u32 sig_mask;
- int sig_idx, used = 0, b_sz = PAGE_SIZE;
- sig_mask = 0x1;
- for (sig_idx = 0; sig_idx < cfg->nr_trig_max; sig_idx++) {
if (sig_mask & con->con_out->used_mask) {
used += scnprintf(buf+used, b_sz-used, "%d ",
sig_idx);
}
sig_mask <<= 1;
- }
- used += scnprintf(buf+used, b_sz-used, "\n");
- return used;
+}
+/* convert a sig type id to a name */ +static const char * +cti_sig_type_name(struct cti_trig_con *con, int used_count, bool in) +{
- static const char * const sig_type_names[] = {
"genio", "intreq", "intack", "haltreq", "restartreq",
"pe_edbgreq", "pe_dbgrestart", "pe_ctiirq", "pe_pmuirq",
"pe_dbgtrigger", "etm_extout", "etm_extin", "snk_full",
"snk_acqcomp", "snk_flushcomp", "snk_flushin", "snk_trigin",
"stm_asyncout", "stm_tout_spte", "stm_tout_sw", "stm_tout_hete",
"stm_hwevent", "ela_tstart", "ela_tstop", "ela_dbgreq",
- };
- int idx = 0;
- struct cti_trig_grp *grp = in ? con->con_in : con->con_out;
- if (grp->sig_types) {
if (used_count < grp->nr_sigs)
idx = grp->sig_types[used_count];
- }
- return sig_type_names[idx];
+}
+static ssize_t trigin_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- int sig_idx, used = 0, b_sz = PAGE_SIZE;
- const char *name;
- for (sig_idx = 0; sig_idx < con->con_in->nr_sigs; sig_idx++) {
name = cti_sig_type_name(con, sig_idx, true);
used += scnprintf(buf+used, b_sz-used, "%s ", name);
- }
- used += scnprintf(buf+used, b_sz-used, "\n");
- return used;
+}
+static ssize_t trigout_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- struct dev_ext_attribute *ext_attr = (struct dev_ext_attribute *)attr;
- struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
- int sig_idx, used = 0, b_sz = PAGE_SIZE;
- const char *name;
- for (sig_idx = 0; sig_idx < con->con_out->nr_sigs; sig_idx++) {
name = cti_sig_type_name(con, sig_idx, false);
used += scnprintf(buf+used, b_sz-used, "%s ", name);
- }
- used += scnprintf(buf+used, b_sz-used, "\n");
- return used;
+}
+typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,
char *buf);
+enum cti_conn_attr_type {
- CTI_CON_ATTR_NAME,
- CTI_CON_ATTR_TRIGIN_SIG,
- CTI_CON_ATTR_TRIGOUT_SIG,
- CTI_CON_ATTR_TRIGIN_TYPES,
- CTI_CON_ATTR_TRIGOUT_TYPES
+};
+static p_show_fn show_fns[] = {
- con_name_show,
- trigin_sig_show,
- trigout_sig_show,
- trigin_type_show,
- trigout_type_show,
+};
+static const char * const base_names[] = {
- "_name",
- "_trgin_sig",
- "_trgout_sig",
- "_trgin_type",
- "_trgout_type",
+};
+struct dev_ext_attribute * +cti_create_con_sysfs_attr(int con_idx, enum cti_conn_attr_type attr_type) +{
- struct dev_ext_attribute *dev_ext_attr = 0;
- char *name = 0;
- dev_ext_attr = kzalloc(sizeof(struct dev_ext_attribute), GFP_KERNEL);
- if (dev_ext_attr) {
name = kzalloc(sizeof(char) * 16, GFP_KERNEL);
if (name) {
/* fill out the underlying attribute struct */
sprintf(name, "%d%s", con_idx, base_names[attr_type]);
dev_ext_attr->attr.attr.name = name;
dev_ext_attr->attr.attr.mode = 0444;
/* now the device_attribute struct */
dev_ext_attr->attr.show = show_fns[attr_type];
} else {
kfree(dev_ext_attr);
dev_ext_attr = 0;
}
- }
- return dev_ext_attr;
+}
+int cti_create_con_attr_set(int con_idx, int *next_attr_idx,
struct cti_device *ctidev,
struct cti_trig_con *con)
+{
- struct dev_ext_attribute *dev_ext_attr;
- int attr_idx = *next_attr_idx;
- dev_ext_attr = cti_create_con_sysfs_attr(con_idx, CTI_CON_ATTR_NAME);
- if (!dev_ext_attr)
goto create_con_attr_err;
- dev_ext_attr->var = con;
- ctidev->con_attrs[attr_idx++] = dev_ext_attr;
- if (con->con_in->nr_sigs > 0) {
dev_ext_attr =
cti_create_con_sysfs_attr(con_idx,
CTI_CON_ATTR_TRIGIN_SIG);
if (!dev_ext_attr)
goto create_con_attr_err;
dev_ext_attr->var = con;
ctidev->con_attrs[attr_idx++] = dev_ext_attr;
dev_ext_attr =
cti_create_con_sysfs_attr(con_idx,
CTI_CON_ATTR_TRIGIN_TYPES);
if (!dev_ext_attr)
goto create_con_attr_err;
dev_ext_attr->var = con;
ctidev->con_attrs[attr_idx++] = dev_ext_attr;
- }
- if (con->con_in->nr_sigs > 0) {
dev_ext_attr =
cti_create_con_sysfs_attr(con_idx,
CTI_CON_ATTR_TRIGOUT_SIG);
if (!dev_ext_attr)
goto create_con_attr_err;
dev_ext_attr->var = con;
ctidev->con_attrs[attr_idx++] = dev_ext_attr;
dev_ext_attr =
cti_create_con_sysfs_attr(con_idx,
CTI_CON_ATTR_TRIGOUT_TYPES);
if (!dev_ext_attr)
goto create_con_attr_err;
dev_ext_attr->var = con;
ctidev->con_attrs[attr_idx++] = dev_ext_attr;
- }
- *next_attr_idx = attr_idx;
- return 0;
+create_con_attr_err:
- cti_destroy_cons_sysfs(ctidev);
- return -ENOMEM;
+}
+int cti_create_cons_sysfs(struct cti_drvdata *drvdata) +{
- struct cti_device *ctidev = &drvdata->ctidev;
- int err = 0, n_attrs = 0, con_idx = 0;
- int next_attr_idx = CTI_SYSFS_CONS_ST_ATTR - 1;
- struct cti_trig_con *tc;
- n_attrs = CTI_SYSFS_CONS_ST_ATTR +
(CTI_SYSFS_CONS_DYN_ATTR * ctidev->nr_trig_con);
- ctidev->con_attrs =
kcalloc(n_attrs, sizeof(struct dev_ext_attribute *),
GFP_KERNEL);
- if (ctidev->con_attrs != 0) {
ctidev->con_attrs[0] = (struct dev_ext_attribute *)
&dev_attr_trigout_filtered.attr;
ctidev->con_attrs[1] = (struct dev_ext_attribute *)
&dev_attr_nr_cons.attr;
/* add dynamic set for each connection */
list_for_each_entry(tc, &ctidev->trig_cons, node) {
err = cti_create_con_attr_set(con_idx++,
&next_attr_idx,
ctidev,
tc);
/* if create con fails it will free all prior cons */
if (err)
return err;
}
coresight_cti_conns_group.attrs =
(struct attribute **)ctidev->con_attrs;
- } else
err = -ENOMEM;
- return err;
+}
+void cti_destroy_cons_sysfs(struct cti_device *ctidev) +{
- int n_attrs = CTI_SYSFS_CONS_ST_ATTR +
(CTI_SYSFS_CONS_DYN_ATTR * ctidev->nr_trig_con);
- int dyn_idx = CTI_SYSFS_CONS_ST_ATTR - 1;
- bool eol = false;
- struct dev_ext_attribute *dev_ext_attr = 0;
- if (ctidev->con_attrs) {
while (!eol && (dyn_idx < n_attrs)) {
dev_ext_attr = ctidev->con_attrs[dyn_idx];
if (dev_ext_attr) {
kfree(dev_ext_attr->attr.attr.name);
kfree(dev_ext_attr);
} else
eol = true;
dyn_idx++;
}
kfree(ctidev->con_attrs);
ctidev->con_attrs = 0;
- }
+}
+/* attribute and group sysfs tables. */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; @@ -900,5 +1235,6 @@ const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_mgmt_group, &coresight_cti_regs_group, &coresight_cti_channels_group,
- &coresight_cti_conns_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 6fb924f70af2..6996b70f99e8 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -655,6 +655,14 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) goto err_out; }
- /* create dynamic attributes for connections */
- ret = cti_create_cons_sysfs(drvdata);
- if (ret) {
pr_err("%s: create dynamic sysfs entries failed\n",
cti_desc.name);
goto err_out;
- }
- /* set up coresight component description */ cti_desc.pdata = pdata; cti_desc.type = CORESIGHT_DEV_TYPE_ECT;
@@ -719,6 +727,9 @@ void cti_device_release(struct device *dev) mutex_lock(&ect_mutex);
- /* clear the dynamic sysfs associate with connections */
- cti_destroy_cons_sysfs(&drvdata->ctidev);
- /* clear the connection list items */ cti_free_conn_info(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index ab1be67eb704..99281c8fa126 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -124,12 +124,14 @@ struct cti_trig_con {
assumed there is a single CTM per SoC, ID 0).
- @trig_cons: list of connections to this device.
- @cpu: CPU ID if associated with CPU, -1 otherwise.
*/
- @con_attrs: Dymanic sysfs attributes created to display connection info.
struct cti_device { int nr_trig_con; u32 ctm_id; struct list_head trig_cons; int cpu;
- struct dev_ext_attribute **con_attrs;
}; /** @@ -247,6 +249,8 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, u32 channel_idx); int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, u32 channel_idx); +int cti_create_cons_sysfs(struct cti_drvdata *drvdata); +void cti_destroy_cons_sysfs(struct cti_device *ctidev); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); -- 2.20.1
CoreSight mailing list CoreSight@lists.linaro.org https://lists.linaro.org/mailman/listinfo/coresight