From patchwork Fri Oct 30 17:56:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Leach X-Patchwork-Id: 11870465 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 86AD4C00A89 for ; Fri, 30 Oct 2020 18:00:41 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E5C5320724 for ; Fri, 30 Oct 2020 18:00:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="16tLBYUQ"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="Lk+/Zufs" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E5C5320724 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:References:In-Reply-To:Message-Id:Date:Subject:To: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=V2x9p+HIags7mhjeYBTGM3UKiojnTApSBQZzm+Sew00=; b=16tLBYUQxcyDdCA5Lbo8edG+Pa wrQyMWl0eDnnFyGRvTvQhLSCreKEqGTsGYB9Qu2OYJs90MOQJqFDCHZZZTod+5vCVFQKvvcfR7PQP IJ2fLoCtJpaXs3/ncJkTEbYZ8YHgrBqd60ttJiRX4Q2CeS/9WnK18+ydoQ2mdwKYHYfAEpRv7+y3L kupUd5yFKoOof6xmLIAkQhVD2YZt2JbIkW6mdkRon2lLWmUY+09+8bG9GQkIxO38/SeEH4ij30By6 q7AmML3WmZNMTSwro1k5C5d+Sx8TT3KEixd9uYlY/fYGTlWTvDisR9/fHF1MWIyY87vEg7xIW2R57 Li7GLlMg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kYYfv-0004Ot-7r; Fri, 30 Oct 2020 17:58:55 +0000 Received: from mail-wm1-x344.google.com ([2a00:1450:4864:20::344]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kYYeD-0003n2-Lq for linux-arm-kernel@lists.infradead.org; Fri, 30 Oct 2020 17:57:16 +0000 Received: by mail-wm1-x344.google.com with SMTP id e2so3733791wme.1 for ; Fri, 30 Oct 2020 10:57:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=CZQQJ5phXo5/JkEzOdlf4FZRfsVcLIuuSX5X69bT7OQ=; b=Lk+/ZufsYHdwa6JlLCDrUko6mqgzuMvjdHPqDKppNR5oMIsZieY0xKnCTewkhAOvG8 Z7OaQtA9tDPhRxmvEpbjwMM9tMbbVkOaPgDp4FHHvt7EHGxr6ilK9Rt1AU+O7sJVKN3s jXpl3PmfxmNRI+bSDHzxOdElw16DrmNz/chaoVq8HWZ7cJpe0vLRXfnEzZRtpGzakSNM /tbv5MNwl6UN91PzRSHFLnFd5bLDjE+MafYB2tXzmwNKuQ6V+MwDQDy40xZVBtlwfFdA fg9AjMO9YUFklddeKXr4wORU0lSN5fS043jFJCgEE9o8p+sh01/l6vOL2WWWkiz1NfBB kkJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=CZQQJ5phXo5/JkEzOdlf4FZRfsVcLIuuSX5X69bT7OQ=; b=OSfNdDzVkFUSQauO7NoceC5T6220Po1T71kzLziDlZBilghIK5rc2Qqw9BeN44QOwG CZI6tiSjhK6keg2CNzH9tqZVEnIqGpTzPFNi4m2UJs2Y3xVJ8A3h2kpX2Ep8+sXPYA9Y wsDV38W8NWE+STOO/V1k4nGETQSJZBJgHDH6w+E/90HYf0ml+8CaJCztUo8+k8pM925z JPf2I8cuABqT2PosncwrQ4gqAWaTGMUZ3DAE96tF9lydY9BghoyRsQAElsB4RCQNIsIs xm0a7XIC2iPfjFWwAP2C++JgH+W3X7xFM7xJCcQDwLGwgGyHJNnC8qzcvpdes3DwZ4ff SXyQ== X-Gm-Message-State: AOAM530s6k0MK1kvs0QOnN4gnHutW5fbJcFAGiLf/MlABcv7SAWDNb4F psgETfMYL8Q/xW1CgXocW1r2a0OXphPK+A== X-Google-Smtp-Source: ABdhPJxXFKO8MGJuCu0ON+0Fd4rQQLf0UQfDb/3PiKcFV/krtIpOCVOTzwWs0UN5U1ioqyPY4dXGrw== X-Received: by 2002:a7b:cb8c:: with SMTP id m12mr4246219wmi.12.1604080625375; Fri, 30 Oct 2020 10:57:05 -0700 (PDT) Received: from linaro.org ([2a00:23c5:6801:1801:4964:83f8:d2e7:f2c9]) by smtp.gmail.com with ESMTPSA id o129sm5615563wmb.25.2020.10.30.10.57.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 30 Oct 2020 10:57:04 -0700 (PDT) From: Mike Leach To: linux-arm-kernel@lists.infradead.org, coresight@lists.linaro.org, mathieu.poirier@linaro.org Subject: [RFC PATCH v3 7/9] coresight: syscfg: Add initial configfs support. Date: Fri, 30 Oct 2020 17:56:53 +0000 Message-Id: <20201030175655.30126-8-mike.leach@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201030175655.30126-1-mike.leach@linaro.org> References: <20201030175655.30126-1-mike.leach@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201030_135709_912576_E1FDA5AA X-CRM114-Status: GOOD ( 28.21 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: yabinc@google.com, Mike Leach , suzuki.poulose@arm.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Adds configfs subsystem and attributes to the configuration manager to enable the listing of loaded configurations and features. The default values of feature parameters can be accessed and altered from these attributes to affect all installed devices using the feature. Signed-off-by: Mike Leach --- drivers/hwtracing/coresight/Makefile | 2 +- .../hwtracing/coresight/coresight-config.c | 2 + .../hwtracing/coresight/coresight-config.h | 5 +- .../coresight/coresight-syscfg-configfs.c | 418 ++++++++++++++++++ .../coresight/coresight-syscfg-configfs.h | 47 ++ .../hwtracing/coresight/coresight-syscfg.c | 31 ++ .../hwtracing/coresight/coresight-syscfg.h | 4 + 7 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 9de5586cfd1a..4ec226c44f5b 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ - coresight-cfg-preload.o + coresight-cfg-preload.o coresight-syscfg-configfs.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c index d911e0f083c1..04e7cb4ff769 100644 --- a/drivers/hwtracing/coresight/coresight-config.c +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -111,8 +111,10 @@ static void cscfg_reset_feat(struct cscfg_feature_csdev *feat) * set the default values for all parameters and regs from the * relevant static descriptors. */ + spin_lock(&feat->desc->param_lock); for (i = 0; i < feat->nr_params; i++) feat->params[i].current_value = feat->desc->params[i].value; + spin_unlock(&feat->desc->param_lock); for (i = 0; i < feat->nr_regs; i++) { reg_desc = &feat->desc->regs[i]; diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 372f29a59688..39fcac011aa0 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -7,6 +7,7 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_H #define _CORESIGHT_CORESIGHT_CONFIG_H +#include #include #include @@ -89,6 +90,7 @@ struct cscfg_regval { * @match_flags: matching information if loading into a device * @nr_params: number of parameters used. * @params: array of parameters used. + * @param_lock: protect params when accessing default values. * @nr_regs: number of registers used. * @reg: array of registers used. */ @@ -99,6 +101,7 @@ struct cscfg_feature_desc { u32 match_flags; int nr_params; struct cscfg_parameter_desc *params; + spinlock_t param_lock; int nr_regs; struct cscfg_regval *regs; }; @@ -239,7 +242,7 @@ struct cscfg_feat_ops { * @ops: standard ops to enable and disable features on devices. */ struct cscfg_feature_csdev { - const struct cscfg_feature_desc *desc; + struct cscfg_feature_desc *desc; struct coresight_device *csdev; struct list_head node; spinlock_t *csdev_spinlock; diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c new file mode 100644 index 000000000000..ff7ea678100a --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach + */ + +#include + +#include "coresight-syscfg-configfs.h" + +/* + * configfs support for syscfg device. + * + * config fs is used to manage configurations and features on the + * coresight system. + */ + +static struct cscfg_device *cscfg_fs_get_cscfg_dev(void); + +static struct device *cscfg_dev_to_dev(void) +{ + return cscfg_fs_get_cscfg_dev() ? &cscfg_fs_get_cscfg_dev()->dev : NULL; +} + +/* + * Declare the subsystem - with base attributes allowing listing of + * loaded configurations + */ +static inline struct cscfg_fs_config *to_cscfg_fs_config_group(struct config_group *group) +{ + return container_of(group, struct cscfg_fs_config, group); +} + +/* configurations sub-group */ + +/* attributes for the config view group */ +static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "%s\n", fs_config->desc->brief); +} +CONFIGFS_ATTR_RO(cscfg_cfg_, description); + +static ssize_t cscfg_cfg_refs_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item)); + const struct cscfg_config_desc *desc = fs_config->desc; + ssize_t ch_used = 0; + int i; + + if (desc->nr_refs) { + ch_used += scnprintf(page, PAGE_SIZE, "references %d features:-\n", desc->nr_refs); + for (i = 0; i < desc->nr_refs; i++) { + ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used, + "%s\n", desc->refs[i].name); + } + } else + ch_used = scnprintf(page, PAGE_SIZE, "no features referenced\n"); + return ch_used; +} +CONFIGFS_ATTR_RO(cscfg_cfg_, refs); + +static ssize_t cscfg_cfg_nr_presets_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->desc->nr_presets); +} +CONFIGFS_ATTR_RO(cscfg_cfg_, nr_presets); + +static ssize_t cscfg_cfg_preset_values_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = to_cscfg_fs_config_group(to_config_group(item)); + const struct cscfg_config_desc *cfg = fs_config->desc; + const struct cscfg_feature_desc *feat; + ssize_t used = 0; + int i, j, val_idx, preset_idx; + + if (!fs_config->desc->nr_presets) + return scnprintf(page, PAGE_SIZE, "No presets defined\n"); + + used = scnprintf(page, PAGE_SIZE, "%d presets, %d parameters per preset\n", + fs_config->desc->nr_presets, cfg->nr_total_params); + + for (preset_idx = 0; preset_idx < fs_config->desc->nr_presets; preset_idx++) { + /* start index on the correct array line */ + val_idx = cfg->nr_total_params * preset_idx; + + /* preset indexes are used as 1 based by the user */ + used += scnprintf(page + used, PAGE_SIZE - used, "preset[%d]: ", preset_idx+1); + + /* + * A set of presets is the sum of all params in used features, + * in order of declaration of features and params in the features + */ + for (i = 0; i < cfg->nr_refs; i++) { + feat = cscfg_get_named_feat_desc(cfg->refs[i].name); + for (j = 0; j < cfg->refs[i].nr_params; j++) { + used += scnprintf(page + used, PAGE_SIZE - used, + "%s.%s = 0x%llx ", + cfg->refs[i].name, feat->params[j].name, + cfg->presets[val_idx++]); + } + } + used += scnprintf(page + used, PAGE_SIZE - used, "\n"); + } + return used; +} +CONFIGFS_ATTR_RO(cscfg_cfg_, preset_values); + +static struct configfs_attribute *cscfg_config_view_attrs[] = { + &cscfg_cfg_attr_description, + &cscfg_cfg_attr_refs, + &cscfg_cfg_attr_nr_presets, + &cscfg_cfg_attr_preset_values, + NULL, +}; + +static struct config_item_type cscfg_config_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_config_view_attrs, +}; + +static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *cfg_desc) +{ + struct cscfg_fs_config *cfg_view; + struct device *dev = cscfg_dev_to_dev(); + + if (!dev) + return ERR_PTR(-EINVAL); + + cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL); + if (!cfg_view) + return ERR_PTR(-ENOMEM); + + cfg_view->desc = cfg_desc; + config_group_init_type_name(&cfg_view->group, cfg_desc->name, &cscfg_config_view_type); + return &cfg_view->group; +} + +static struct config_item_type cscfg_configs_type = { + .ct_owner = THIS_MODULE, +}; + +static struct cscfg_fs_def_group cscfg_configs_grp = { + .group = { + .cg_item = { + .ci_namebuf = "configurations", + .ci_type = &cscfg_configs_type, + }, + }, +}; + + +/* attributes for features view */ + +static inline struct cscfg_fs_feature *to_cscfg_fs_feature_group(struct config_group *group) +{ + return container_of(group, struct cscfg_fs_feature, group); +} + +static ssize_t cscfg_feat_description_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "%s\n", fs_feat->desc->brief); +} +CONFIGFS_ATTR_RO(cscfg_feat_, description); + +static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item)); + u32 match_flags = fs_feat->desc->match_flags; + int used = 0; + + if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL) + used = scnprintf(page, PAGE_SIZE, "SRC_ALL "); + + if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4) + used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 "); + + if (match_flags & CS_CFG_MATCH_CLASS_CTI_ALL) + used += scnprintf(page + used, PAGE_SIZE - used, "CTI_ALL "); + + if (match_flags & CS_CFG_MATCH_CLASS_CTI_CPU) + used += scnprintf(page + used, PAGE_SIZE - used, "CTI_CPU "); + + if (match_flags & CS_CFG_MATCH_CLASS_CTI_SYS) + used += scnprintf(page + used, PAGE_SIZE - used, "CTI_SYS "); + + used += scnprintf(page + used, PAGE_SIZE - used, "\n"); + return used; +} +CONFIGFS_ATTR_RO(cscfg_feat_, matches); + +static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = to_cscfg_fs_feature_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->desc->nr_params); +} +CONFIGFS_ATTR_RO(cscfg_feat_, nr_params); + +/* base feature desc attrib structures */ +static struct configfs_attribute *cscfg_feature_view_attrs[] = { + &cscfg_feat_attr_description, + &cscfg_feat_attr_matches, + &cscfg_feat_attr_nr_params, + NULL, +}; + +static struct config_item_type cscfg_feature_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_feature_view_attrs, +}; + +static inline struct cscfg_fs_param *to_cscfg_fs_param_group(struct config_group *group) +{ + return container_of(group, struct cscfg_fs_param, group); +} + +static ssize_t cscfg_param_value_show(struct config_item *item, char *page) +{ + struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item)); + + return scnprintf(page, PAGE_SIZE, "0x%llx\n", param_item->param->value); +} + +static ssize_t cscfg_param_value_store(struct config_item *item, + const char *page, size_t size) +{ + struct cscfg_fs_param *param_item = to_cscfg_fs_param_group(to_config_group(item)); + u64 val; + int err; + + err = kstrtoull(page, 0, &val); + if (err) + return err; + + spin_lock(¶m_item->desc->param_lock); + param_item->param->value = val; + spin_unlock(¶m_item->desc->param_lock); + + return size; +} +CONFIGFS_ATTR(cscfg_param_, value); + +static struct configfs_attribute *cscfg_param_view_attrs[] = { + &cscfg_param_attr_value, + NULL, +}; + +static struct config_item_type cscfg_param_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_param_view_attrs, +}; + +static struct config_item_type cscfg_feat_param_group_type = { + .ct_owner = THIS_MODULE, +}; + +/* + * configfs has far less functionality provided to add attributes dynamically than sysfs, + * and the show and store fns pass the enclosing config_item so the actual attribute cannot + * be determined. Therefore we add each item as a group directory, with a value attribute. + */ +static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc, + struct config_group *params_group) +{ + struct device *dev = cscfg_dev_to_dev(); + struct cscfg_fs_param *param_item; + int i; + + /* parameter items - as groups with default_value attribute */ + for (i = 0; i < feat_desc->nr_params; i++) { + param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL); + if (!param_item) + return -ENOMEM; + param_item->desc = feat_desc; + param_item->param = &feat_desc->params[i]; + config_group_init_type_name(¶m_item->group, param_item->param->name, + &cscfg_param_view_type); + configfs_add_default_group(¶m_item->group, params_group); + } + return 0; +} + +static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_fs_feature *feat_view; + struct device *dev = cscfg_dev_to_dev(); + struct cscfg_fs_def_group *params_group = NULL; + int item_err; + + if (!dev) + return ERR_PTR(-EINVAL); + + feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL); + if (!feat_view) + return ERR_PTR(-ENOMEM); + + if (feat_desc->nr_params) { + params_group = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL); + if (!params_group) + return ERR_PTR(-ENOMEM); + } + + feat_view->desc = feat_desc; + config_group_init_type_name(&feat_view->group, + feat_desc->name, + &cscfg_feature_view_type); + if (params_group) { + config_group_init_type_name(¶ms_group->group, "params", + &cscfg_feat_param_group_type); + configfs_add_default_group(¶ms_group->group, &feat_view->group); + item_err = cscfg_create_params_group_items(feat_desc, ¶ms_group->group); + if (item_err) + return ERR_PTR(item_err); + } + return &feat_view->group; +} + +static struct config_item_type cscfg_features_type = { + .ct_owner = THIS_MODULE, +}; + +static struct cscfg_fs_def_group cscfg_features_grp = { + .group = { + .cg_item = { + .ci_namebuf = "features", + .ci_type = &cscfg_features_type, + }, + }, +}; + +/* add configuration to configurations group */ +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc) +{ + struct config_group *new_group; + int err; + + new_group = cscfg_create_config_group(cfg_desc); + if (IS_ERR(new_group)) + return PTR_ERR(new_group); + err = configfs_register_group(&cscfg_configs_grp.group, new_group); + return err; +} + +/* add feature to features group */ +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc) +{ + struct config_group *new_group; + int err; + + new_group = cscfg_create_feature_group(feat_desc); + if (IS_ERR(new_group)) + return PTR_ERR(new_group); + err = configfs_register_group(&cscfg_features_grp.group, new_group); + return err; +} + +static const struct config_item_type syscfg_fs_type = { + .ct_owner = THIS_MODULE, +}; + +static struct cscfg_fs_subsys syscfg_fs_subsys = { + .cfgdev = NULL, + .fs_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "coresight-syscfg", + .ci_type = &syscfg_fs_type, + }, + }, + }, +}; + +static inline struct cscfg_device *cscfg_fs_get_cscfg_dev(void) +{ + return syscfg_fs_subsys.cfgdev; +} + +int cscfg_configfs_init(struct cscfg_device *cscfg_dev) +{ + int ret = 0; + struct configfs_subsystem *subsys = &syscfg_fs_subsys.fs_subsys; + + if (!cscfg_dev) + return -EINVAL; + + config_group_init(&subsys->su_group); + mutex_init(&subsys->su_mutex); + + /* Add default groups to subsystem */ + config_group_init(&cscfg_configs_grp.group); + configfs_add_default_group(&cscfg_configs_grp.group, &subsys->su_group); + + config_group_init(&cscfg_features_grp.group); + configfs_add_default_group(&cscfg_features_grp.group, &subsys->su_group); + + ret = configfs_register_subsystem(subsys); + if (!ret) { + syscfg_fs_subsys.cfgdev = cscfg_dev; + cscfg_dev->cfgfs_subsys = &syscfg_fs_subsys; + } + + return ret; +} + +void cscfg_configfs_release(struct cscfg_device *cscfg_dev) +{ + if (cscfg_dev && cscfg_dev->cfgfs_subsys) { + configfs_unregister_subsystem(&cscfg_dev->cfgfs_subsys->fs_subsys); + cscfg_dev->cfgfs_subsys = NULL; + } + syscfg_fs_subsys.cfgdev = NULL; +} diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h new file mode 100644 index 000000000000..70cc3745649e --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Coresight system configuration driver - support for configfs. + */ + +#ifndef CORESIGHT_SYSCFG_CONFIGFS_H +#define CORESIGHT_SYSCFG_CONFIGFS_H + +#include +#include "coresight-syscfg.h" + +/* container to associate the device and configfs subsystem */ +struct cscfg_fs_subsys { + struct cscfg_device *cfgdev; + struct configfs_subsystem fs_subsys; +}; + +/* container for default groups */ +struct cscfg_fs_def_group { + struct config_group group; +}; + +/* container for configuration view */ +struct cscfg_fs_config { + struct cscfg_config_desc *desc; + struct config_group group; +}; + +/* container for feature view */ +struct cscfg_fs_feature { + struct cscfg_feature_desc *desc; + struct config_group group; +}; + +/* container for parameter view */ +struct cscfg_fs_param { + struct cscfg_parameter_desc *param; + struct cscfg_feature_desc *desc; + struct config_group group; +}; + +int cscfg_configfs_init(struct cscfg_device *dev); +void cscfg_configfs_release(struct cscfg_device *dev); +int cscfg_configfs_add_config(struct cscfg_config_desc *cfg_desc); +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc); + +#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 8d52580daf04..2cf67a038cc8 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -9,6 +9,7 @@ #include "coresight-config.h" #include "coresight-etm-perf.h" #include "coresight-syscfg.h" +#include "coresight-syscfg-configfs.h" /* * cscfg_ API manages configurations and features for the entire coresight @@ -260,6 +261,8 @@ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) { int err; + spin_lock_init(&feat_desc->param_lock); + /* add feature to any matching registered devices */ err = cscfg_add_feat_to_csdevs(feat_desc); if (err) @@ -294,6 +297,24 @@ static int cscfg_load_config(struct cscfg_config_desc *cfg_desc) return err; } +/* get a feature descriptor by name */ +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) +{ + const struct cscfg_feature_desc *feat = NULL, *feat_item; + + mutex_lock(&cscfg_mutex); + + list_for_each_entry(feat_item, &cscfg_data.feat_list, item) { + if (strcmp(feat_item->name, name) == 0) { + feat = feat_item; + break; + } + } + + mutex_unlock(&cscfg_mutex); + return feat; +} + /* * External API function to load feature and config sets. * Take a 0 terminated array of feature descriptors and/or configuration @@ -316,6 +337,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, feat_descs[i]->name); goto do_unlock; } + cscfg_configfs_add_feature(feat_descs[i]); i++; } } @@ -330,6 +352,7 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, cfg_descs[i]->name); goto do_unlock; } + cscfg_configfs_add_config(cfg_descs[i]); i++; } } @@ -502,6 +525,7 @@ struct device *to_device_cscfg(void) /* Must have a release function or the kernel will complain on module unload */ void cscfg_dev_release(struct device *dev) { + cscfg_configfs_release(cscfg_dev); kfree(cscfg_dev); cscfg_dev = NULL; } @@ -530,6 +554,7 @@ int cscfg_create_device(void) cscfg_dev->cfg_data = &cscfg_data; err = device_register(dev); + if (err) cscfg_dev_release(dev); @@ -587,6 +612,10 @@ int __init cscfg_init(void) if (err) goto exit_drv_unregister; + err = cscfg_configfs_init(cscfg_dev); + if (err) + goto exit_dev_clear; + INIT_LIST_HEAD(&cscfg_data.dev_list); INIT_LIST_HEAD(&cscfg_data.feat_list); INIT_LIST_HEAD(&cscfg_data.config_list); @@ -595,6 +624,8 @@ int __init cscfg_init(void) dev_info(to_device_cscfg(), "CoreSight Configuration manager initialised"); return 0; +exit_dev_clear: + cscfg_clear_device(); exit_drv_unregister: cscfg_driver_exit(); exit_bus_unregister: diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index e8f352599dd7..ce237a69677b 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -6,6 +6,7 @@ #ifndef CORESIGHT_SYSCFG_H #define CORESIGHT_SYSCFG_H +#include #include #include @@ -46,6 +47,7 @@ struct cscfg_csdev_register { int __init cscfg_init(void); void __exit cscfg_exit(void); int cscfg_preload(void); +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name); /* syscfg external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, @@ -64,10 +66,12 @@ void cscfg_unregister_csdev(struct coresight_device *csdev); * * @dev: The device. * @cfg_data: A reference to the configuration and feature lists + * @cfgfs_subsys: configfs subsystem used to manage configurations. */ struct cscfg_device { struct device dev; struct cscfg_api_data *cfg_data; + struct cscfg_fs_subsys *cfgfs_subsys; }; /* basic device driver */