From patchwork Thu Oct 21 07:38:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574125 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 49F29C433FE for ; Thu, 21 Oct 2021 07:41:32 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 18F89610CF for ; Thu, 21 Oct 2021 07:41:32 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 18F89610CF Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=gnv0pv+bbRFdzt0vhPxnxFWXtfk9QIF1UHiQfCNoSZ4=; b=vj8zY4h2iIGirM qvW4+MFHAY5xfgZfT+XTdYvDYscNajgGH+6KbdOeURWJvMDXF7X0HfKgCJ/SaXYZNFI9p67heaKDD ZpZJ6HZecPP2bL7UpPpA8s7bmlmZKZAqF2V+zY5EQliIKBvqYkSMrVsPB7ewSeohmOBZasfAwGoXe rYk2E+cVnFMBkqbX83pkayGQtjSLXKTkUgCXXpw+VjrRFnDDTy91+blN3Ndzr6RUYPuAkOvWrnLu1 bXzph4PK1CH2KZ0kHecxp6PKTVcGePTjqP8uakCWtU2I+rouL1vtkaLO7sXDydtrgNZe+lFvkUkQS 5Wjj3CvUSpIDKi3M3lrQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSg5-006gxg-E3; Thu, 21 Oct 2021 07:39:53 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSfr-006guF-OY for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:39:41 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634801979; x=1666337979; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=/T+Qr2cdCGei8ovEYQOwJTk3upw5VcxRxTNTUf0UW7M=; b=I3gNhcTp3/YU5UnbC9Veaa7mmmpX75h4NDSrEh6lkx77RBtLoQJGm8z+ b38VWYw9GleKf397n3bams25rZ3iqcf8hyg4xM6SeQ0JS2EOQBEzEJRTG hXOnXu3ObSR5Cxz7qVVCvMn5nc+FiBLpECEwOG0kO41HoYWrNd2Gc9scK 0=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:39:39 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:39:39 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:39:35 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni , Tingwei Zhang Subject: [PATCH 01/10] coresight: add support to enable more coresight paths Date: Thu, 21 Oct 2021 15:38:47 +0800 Message-ID: <1634801936-15080-2-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_003939_894866_5BE8C90E X-CRM114-Status: GOOD ( 28.60 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Current coresight implementation only supports enabling source ETMs or STM. This patch adds support to enable more kinds of coresight source to sink paths. We build a path from source to sink when any source is enabled and store it in a list. When the source is disabled, we fetch the corresponding path from the list and decrement the refcount on each device in the path. The device is disabled if the refcount reaches zero. Don't store path to coresight data structure of source to avoid unnecessary change to ABI. Since some targets may have coresight sources other than STM and ETMs, we need to add this change to support these coresight devices. Signed-off-by: Tingwei Zhang Signed-off-by: Tao Zhang --- drivers/hwtracing/coresight/coresight-core.c | 100 +++++++++++-------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 8a18c71df37a..1e621d61307a 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -37,18 +37,16 @@ struct coresight_node { }; /* - * When operating Coresight drivers from the sysFS interface, only a single - * path can exist from a tracer (associated to a CPU) to a sink. + * struct coresight_path - path from source to sink + * @path: Address of path list. + * @link: hook to the list. */ -static DEFINE_PER_CPU(struct list_head *, tracer_path); +struct coresight_path { + struct list_head *path; + struct list_head link; +}; -/* - * As of this writing only a single STM can be found in CS topologies. Since - * there is no way to know if we'll ever see more and what kind of - * configuration they will enact, for the time being only define a single path - * for STM. - */ -static struct list_head *stm_path; +static LIST_HEAD(cs_active_paths); /* * When losing synchronisation a new barrier packet needs to be inserted at the @@ -354,6 +352,7 @@ static void coresight_disable_sink(struct coresight_device *csdev) if (ret) return; coresight_control_assoc_ectdev(csdev, false); + csdev->activated = false; csdev->enable = false; } @@ -590,6 +589,20 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data) goto out; } +static struct coresight_device *coresight_get_source(struct list_head *path) +{ + struct coresight_device *csdev; + + if (!path) + return NULL; + + csdev = list_first_entry(path, struct coresight_node, link)->csdev; + if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) + return NULL; + + return csdev; +} + struct coresight_device *coresight_get_sink(struct list_head *path) { struct coresight_device *csdev; @@ -1086,9 +1099,23 @@ static int coresight_validate_source(struct coresight_device *csdev, return 0; } +static int coresight_store_path(struct list_head *path) +{ + struct coresight_path *node; + + node = kzalloc(sizeof(struct coresight_path), GFP_KERNEL); + if (!node) + return -ENOMEM; + + node->path = path; + list_add(&node->link, &cs_active_paths); + + return 0; +} + int coresight_enable(struct coresight_device *csdev) { - int cpu, ret = 0; + int ret = 0; struct coresight_device *sink; struct list_head *path; enum coresight_dev_subtype_source subtype; @@ -1133,25 +1160,9 @@ int coresight_enable(struct coresight_device *csdev) if (ret) goto err_source; - switch (subtype) { - case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: - /* - * When working from sysFS it is important to keep track - * of the paths that were created so that they can be - * undone in 'coresight_disable()'. Since there can only - * be a single session per tracer (when working from sysFS) - * a per-cpu variable will do just fine. - */ - cpu = source_ops(csdev)->cpu_id(csdev); - per_cpu(tracer_path, cpu) = path; - break; - case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: - stm_path = path; - break; - default: - /* We can't be here */ - break; - } + ret = coresight_store_path(path); + if (ret) + goto err_source; out: mutex_unlock(&coresight_mutex); @@ -1168,8 +1179,11 @@ EXPORT_SYMBOL_GPL(coresight_enable); void coresight_disable(struct coresight_device *csdev) { - int cpu, ret; + int ret; struct list_head *path = NULL; + struct coresight_path *cspath = NULL; + struct coresight_path *cspath_next = NULL; + struct coresight_device *src_csdev = NULL; mutex_lock(&coresight_mutex); @@ -1180,20 +1194,18 @@ void coresight_disable(struct coresight_device *csdev) if (!csdev->enable || !coresight_disable_source(csdev)) goto out; - switch (csdev->subtype.source_subtype) { - case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: - cpu = source_ops(csdev)->cpu_id(csdev); - path = per_cpu(tracer_path, cpu); - per_cpu(tracer_path, cpu) = NULL; - break; - case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: - path = stm_path; - stm_path = NULL; - break; - default: - /* We can't be here */ - break; + list_for_each_entry_safe(cspath, cspath_next, &cs_active_paths, link) { + src_csdev = coresight_get_source(cspath->path); + if (!src_csdev) + continue; + if (src_csdev == csdev) { + path = cspath->path; + list_del(&cspath->link); + kfree(cspath); + } } + if (path == NULL) + goto out; coresight_disable_path(path); coresight_release_path(path); From patchwork Thu Oct 21 07:38:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574127 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9842AC433EF for ; Thu, 21 Oct 2021 07:41:42 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 5DFA3610CF for ; Thu, 21 Oct 2021 07:41:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 5DFA3610CF Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=lmaGNeVq4+YUBRiudK9RmxQkPSiMY5ftaDuXFMH3Dv0=; b=pgPHM/G+qVP9oq dd+OYrKk4Zl6porY5XnV0VFKGursSVAm+syNe7Pbdpf5HPEYUTOTFZfr3Hfe4Bpk3TBazpaYib591 3tL1p25iFBa+eRk5RLXz80Z1C5qE1Cuy9Qi0lk1astBmfZCf/LTO75LpUuA6f9q4AOxJt8KwlFlKj i9dXRFINL/DBpHc8rrnzbWgwF5q/bWxJgHNmT76AOJ0UoANZKWlqqL3ULP8zCAFo2drdPGIGKbcgt EWIO3JrZ1u+wPGXfG1dIKbw+mwkXUPdQmQmZ1HFPpsWIcclF/v0y+sjJbYuTJXxTzW+Y+B+2LhwOz CRJcE2fcfHsveHBBPJrQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSgI-006h1d-Q4; Thu, 21 Oct 2021 07:40:07 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSfw-006gvc-H9 for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:39:46 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634801984; x=1666337984; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=iz553WRkvHQgfCNmPx8UPJtumJ+T7WxvgYhp3zGGM1Q=; b=n04X0LBcSyKYlQD/x8ke8LVVuHoyQOFCxAodM2OVIqF3S2r7TgBssEvv sptgOQtNFRyHcqfWIYdjfwQIkC8nJJWd4k2gnBD0b0GBn23s3/p3zKblR CVcCMn5es3M4iizAT7yRdJOBHwbqT9ILyjacaUVLuttyFMnHjPAkKMdkU s=; Received: from ironmsg07-lv.qualcomm.com ([10.47.202.151]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:39:44 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg07-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:39:43 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:39:39 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni , Tingwei Zhang Subject: [PATCH 02/10] coresight: funnel: add support for multiple output ports Date: Thu, 21 Oct 2021 15:38:48 +0800 Message-ID: <1634801936-15080-3-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_003944_671478_95CA3207 X-CRM114-Status: GOOD ( 28.34 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Funnel devices are now capable of supporting multiple-inputs and multiple-outputs configuration with in built hardware filtering for TPDM devices. Add software support to this function. Output port is selected according to the source of the trace path. The source of the input port on funnels will be marked in the device tree. e.g. tpdm_XXX: tpdm@xxxxxxx { ... ... ... ... }; funnel_XXX: funnel@xxxxxxx { ... ... ... ... out-ports { ... ... ... ... port@x { ... ... ... ... label = <&tpdm_XXX>; <-- To point out tpdm_XXX should }; be outputed from port@x. And ... ... ... ... this is a hardware static }; connections. Here needs ... ... ... ... to refer to hardware design. }; Then driver will parse the source name marked in the device tree, and save it to the coresight path. When the function needs to know the source name, it could get the source name from coresight path parameter. Finally, the output port knows which source it corresponds to, and it also knows which input port it corresponds to. Signed-off-by: Tingwei Zhang Signed-off-by: Tao Zhang --- drivers/hwtracing/coresight/coresight-core.c | 75 +++++++++++++++---- .../hwtracing/coresight/coresight-platform.c | 8 ++ include/linux/coresight.h | 2 + 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 1e621d61307a..490c9d8d43f9 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -56,6 +56,8 @@ static LIST_HEAD(cs_active_paths); const u32 coresight_barrier_pkt[4] = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}; EXPORT_SYMBOL_GPL(coresight_barrier_pkt); +static struct coresight_device *coresight_get_source(struct list_head *path); + static const struct cti_assoc_op *cti_assoc_ops; void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) @@ -121,14 +123,46 @@ static int coresight_source_is_unique(struct coresight_device *csdev) csdev, coresight_id_match); } +/** + * coresight_source_filter - checks whether the connection matches the source + * of path if connection is binded to specific source. + * @path: The list of devices + * @conn: The connection of one outport + * + * Return zero if the connection doesn't have a source binded or source of the + * path matches the source binds to connection. + */ +static int coresight_source_filter(struct list_head *path, + struct coresight_connection *conn) +{ + int ret = 0; + struct coresight_device *source = NULL; + + if (conn->source_name == NULL) + return ret; + + source = coresight_get_source(path); + if (source == NULL) + return ret; + + if (is_of_node(source->dev.fwnode)) + return strcmp(conn->source_name, + of_node_full_name(to_of_node(source->dev.fwnode))); + + return ret; +} + static int coresight_find_link_inport(struct coresight_device *csdev, - struct coresight_device *parent) + struct coresight_device *parent, + struct list_head *path) { int i; struct coresight_connection *conn; for (i = 0; i < parent->pdata->nr_outport; i++) { conn = &parent->pdata->conns[i]; + if (coresight_source_filter(path, conn)) + continue; if (conn->child_dev == csdev) return conn->child_port; } @@ -140,13 +174,16 @@ static int coresight_find_link_inport(struct coresight_device *csdev, } static int coresight_find_link_outport(struct coresight_device *csdev, - struct coresight_device *child) + struct coresight_device *child, + struct list_head *path) { int i; struct coresight_connection *conn; for (i = 0; i < csdev->pdata->nr_outport; i++) { conn = &csdev->pdata->conns[i]; + if (coresight_source_filter(path, conn)) + continue; if (conn->child_dev == child) return conn->outport; } @@ -358,7 +395,8 @@ static void coresight_disable_sink(struct coresight_device *csdev) static int coresight_enable_link(struct coresight_device *csdev, struct coresight_device *parent, - struct coresight_device *child) + struct coresight_device *child, + struct list_head *path) { int ret = 0; int link_subtype; @@ -367,8 +405,8 @@ static int coresight_enable_link(struct coresight_device *csdev, if (!parent || !child) return -EINVAL; - inport = coresight_find_link_inport(csdev, parent); - outport = coresight_find_link_outport(csdev, child); + inport = coresight_find_link_inport(csdev, parent, path); + outport = coresight_find_link_outport(csdev, child, path); link_subtype = csdev->subtype.link_subtype; if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0) @@ -393,7 +431,8 @@ static int coresight_enable_link(struct coresight_device *csdev, static void coresight_disable_link(struct coresight_device *csdev, struct coresight_device *parent, - struct coresight_device *child) + struct coresight_device *child, + struct list_head *path) { int i, nr_conns; int link_subtype; @@ -402,8 +441,8 @@ static void coresight_disable_link(struct coresight_device *csdev, if (!parent || !child) return; - inport = coresight_find_link_inport(csdev, parent); - outport = coresight_find_link_outport(csdev, child); + inport = coresight_find_link_inport(csdev, parent, path); + outport = coresight_find_link_outport(csdev, child, path); link_subtype = csdev->subtype.link_subtype; if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { @@ -518,7 +557,7 @@ static void coresight_disable_path_from(struct list_head *path, case CORESIGHT_DEV_TYPE_LINK: parent = list_prev_entry(nd, link)->csdev; child = list_next_entry(nd, link)->csdev; - coresight_disable_link(csdev, parent, child); + coresight_disable_link(csdev, parent, child, path); break; default: break; @@ -573,7 +612,7 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data) case CORESIGHT_DEV_TYPE_LINK: parent = list_prev_entry(nd, link)->csdev; child = list_next_entry(nd, link)->csdev; - ret = coresight_enable_link(csdev, parent, child); + ret = coresight_enable_link(csdev, parent, child, path); if (ret) goto err; break; @@ -801,7 +840,8 @@ static void coresight_drop_device(struct coresight_device *csdev) */ static int _coresight_build_path(struct coresight_device *csdev, struct coresight_device *sink, - struct list_head *path) + struct list_head *path, + struct coresight_device *source) { int i, ret; bool found = false; @@ -813,7 +853,7 @@ static int _coresight_build_path(struct coresight_device *csdev, if (coresight_is_percpu_source(csdev) && coresight_is_percpu_sink(sink) && sink == per_cpu(csdev_sink, source_ops(csdev)->cpu_id(csdev))) { - if (_coresight_build_path(sink, sink, path) == 0) { + if (_coresight_build_path(sink, sink, path, source) == 0) { found = true; goto out; } @@ -824,8 +864,15 @@ static int _coresight_build_path(struct coresight_device *csdev, struct coresight_device *child_dev; child_dev = csdev->pdata->conns[i].child_dev; + + if (csdev->pdata->conns[i].source_name && + is_of_node(source->dev.fwnode) && + strcmp(csdev->pdata->conns[i].source_name, + of_node_full_name(to_of_node(source->dev.fwnode)))) + continue; + if (child_dev && - _coresight_build_path(child_dev, sink, path) == 0) { + _coresight_build_path(child_dev, sink, path, source) == 0) { found = true; break; } @@ -870,7 +917,7 @@ struct list_head *coresight_build_path(struct coresight_device *source, INIT_LIST_HEAD(path); - rc = _coresight_build_path(source, sink, path); + rc = _coresight_build_path(source, sink, path, source); if (rc) { kfree(path); return ERR_PTR(rc); diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index c594f45319fc..60c43ab149a5 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -222,6 +222,7 @@ static int of_coresight_parse_endpoint(struct device *dev, struct of_endpoint endpoint, rendpoint; struct device_node *rparent = NULL; struct device_node *rep = NULL; + struct device_node *sn = NULL; struct device *rdev = NULL; struct fwnode_handle *rdev_fwnode; struct coresight_connection *conn; @@ -269,6 +270,13 @@ static int of_coresight_parse_endpoint(struct device *dev, */ conn->child_fwnode = fwnode_handle_get(rdev_fwnode); conn->child_port = rendpoint.port; + conn->source_name = NULL; + sn = of_parse_phandle(ep, "label", 0); + if (sn) { + conn->source_name = sn->full_name; + of_node_put(sn); + } + /* Connection record updated */ } while (0); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 93a2922b7653..7065b60a767b 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -170,6 +170,7 @@ struct coresight_desc { * struct coresight_connection - representation of a single connection * @outport: a connection's output port number. * @child_port: remote component's port number @output is connected to. + * @source_name:source component's name. * @chid_fwnode: remote component's fwnode handle. * @child_dev: a @coresight_device representation of the component connected to @outport. @@ -178,6 +179,7 @@ struct coresight_desc { struct coresight_connection { int outport; int child_port; + const char *source_name; struct fwnode_handle *child_fwnode; struct coresight_device *child_dev; struct coresight_sysfs_link *link; From patchwork Thu Oct 21 07:38:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574129 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2BB5C433EF for ; Thu, 21 Oct 2021 07:42:02 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 8B0DF610CF for ; Thu, 21 Oct 2021 07:42:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 8B0DF610CF Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=gDS6kccSVGJ3U+tZNEvGKB0BCUmcMD8ZsgVIPtC+2aY=; b=jj/mO7L1e6fDDm WusfCgXUNDyFIckmSDkxmcqKlLL2K7jdHCbkD5DzMpI6NszKzQ2+W5+avKZFT4vm7sKfPo2FFj8JQ X8wXrnNnBbuokgbBRE1kUNpaDc5XDHbLacUZr/Cq2kuuR7jMeh2oNsWJ+SeEFdwDLeuPnrN3kwPzM X8obavODRIKfOuOK0xj6Na4gX7MY0/sEWtKc3iKOiO+q1WezqNPAvcsNHJ1IoM6v6kk6MORhcWKSD 0UOBvRnxdyreK/uELBvYDyPZn15IZJOTo2X+JNCFvghaua+hteuMdxz7u7RlZOkoQhKGvznxKseiY GV3ia1la8nraBHnFDSFQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSgY-006h9u-Ms; Thu, 21 Oct 2021 07:40:22 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSg0-006gwU-C3 for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:39:51 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634801988; x=1666337988; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=9wBnXdnpEWjK/4SNmZyQstGssPdmNKJatAXSnj7hPlw=; b=i1QSQASRpntRV4nDBdJ7rDrVWa49aTyToLIwd+cATpvNScZfu+c9oHwA /0sf4zyGGp2AG7TB1HIOowpl920ifMMCbqX0HZ2cWjec1FKOkZa1mZiLS CcFWYam6Obb6/wLrviN4/IwP0gjYoTVglK6svDmTwlSVv0qP1ppOi0CdD 0=; Received: from ironmsg-lv-alpha.qualcomm.com ([10.47.202.13]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:39:47 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg-lv-alpha.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:39:47 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:39:43 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni Subject: [PATCH 03/10] Coresight: Add driver to support Coresight device TPDM Date: Thu, 21 Oct 2021 15:38:49 +0800 Message-ID: <1634801936-15080-4-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_003948_565927_5B26CDE8 X-CRM114-Status: GOOD ( 24.51 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add driver to support Coresight device TPDM. This driver provides support for configuring monitor. Monitors are primarily responsible for data set collection and support the ability to collect any permutation of data set types. Monitors are also responsible for interaction with system cross triggering. Signed-off-by: Tao Zhang --- .../bindings/arm/coresight-tpdm.yaml | 86 +++ MAINTAINERS | 5 + drivers/hwtracing/coresight/Kconfig | 9 + drivers/hwtracing/coresight/Makefile | 1 + drivers/hwtracing/coresight/coresight-tpdm.c | 583 ++++++++++++++++++ 5 files changed, 684 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/coresight-tpdm.yaml create mode 100644 drivers/hwtracing/coresight/coresight-tpdm.c diff --git a/Documentation/devicetree/bindings/arm/coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/coresight-tpdm.yaml new file mode 100644 index 000000000000..44541075d77f --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-tpdm.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/coresight-tpdm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Trace, Profiling and Diagnostics Monitor - TPDM + +description: | + The TPDM or Monitor serves as data collection component for various dataset + types specified in the QPMDA spec. It covers Basic Counts (BC), Tenure + Counts (TC), Continuous Multi-Bit (CMB), and Discrete Single Bit (DSB). It + performs data collection in the data producing clock domain and transfers it + to the data collection time domain, generally ATB clock domain. + + The primary use case of the TPDM is to collect data from different data + sources and send it to a TPDA for packetization, timestamping, and funneling. + +maintainers: + - Tao Zhang + +properties: + $nodename: + pattern: "^tpdm(@[0-9a-f]+)$" + compatible: + items: + - const: arm,primecell + + reg: + maxItems: 1 + + reg-names: + items: + - const: tpdm-base + + atid: + maxItems: 1 + description: | + The QPMDA specification repurposed the ATID field of the AMBA ATB + specification to use it to convey packetization information to the + Aggregator. + + out-ports: + description: | + Output connections from the TPDM to legacy CoreSight trace bus. + $ref: /schemas/graph.yaml#/properties/ports + properties: + port: + description: Output connection from the TPDM to legacy CoreSight + Trace bus. + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - reg + - reg-names + - atid + - clocks + - clock-names + +additionalProperties: false + +examples: + # minimum TPDM definition. + - | + tpdm@6980000 { + compatible = "arm,primecell"; + reg = <0x6980000 0x1000>; + reg-names = "tpdm-base"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + atid = <78>; + out-ports { + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index eeb4c70b3d5b..cabecf760488 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15303,6 +15303,11 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ipa/ +QCOM CORESIGHT TPDM DRIVER +M: Tao Zhang +S: Maintained +F: drivers/hwtracing/coresight/coresight-tpdm.c + QEMU MACHINE EMULATOR AND VIRTUALIZER SUPPORT M: Gabriel Somlo M: "Michael S. Tsirkin" diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index f026e5c0e777..abe244a968f6 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -188,4 +188,13 @@ config CORESIGHT_TRBE To compile this driver as a module, choose M here: the module will be called coresight-trbe. + +config CORESIGHT_TPDM + tristate "CoreSight Trace, Profiling & Diagnostics Monitor driver" + select CORESIGHT_LINKS_AND_SINKS + help + This driver provides support for configuring monitor. Monitors are + primarily responsible for data set collection and support the + ability to collect any permutation of data set types. Monitors are + also responsible for interaction with system cross triggering. endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index b6c4a48140ec..e7392a0dddeb 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -25,5 +25,6 @@ obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o obj-$(CONFIG_CORESIGHT_TRBE) += coresight-trbe.o +obj-$(CONFIG_CORESIGHT_TPDM) += coresight-tpdm.o coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \ coresight-cti-sysfs.o diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c new file mode 100644 index 000000000000..906776c859d6 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -0,0 +1,583 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coresight-priv.h" + +#define tpdm_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) +#define tpdm_readl(drvdata, off) __raw_readl(drvdata->base + off) + +#define TPDM_LOCK(drvdata) \ +do { \ + mb(); /* ensure configuration take effect before we lock it */ \ + tpdm_writel(drvdata, 0x0, CORESIGHT_LAR); \ +} while (0) +#define TPDM_UNLOCK(drvdata) \ +do { \ + tpdm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \ + mb(); /* ensure unlock take effect before we configure */ \ +} while (0) + +/* GPR Registers */ +#define TPDM_GPR_CR(n) (0x0 + (n * 4)) + +/* BC Subunit Registers */ +#define TPDM_BC_CR (0x280) +#define TPDM_BC_SATROLL (0x284) +#define TPDM_BC_CNTENSET (0x288) +#define TPDM_BC_CNTENCLR (0x28C) +#define TPDM_BC_INTENSET (0x290) +#define TPDM_BC_INTENCLR (0x294) +#define TPDM_BC_TRIG_LO(n) (0x298 + (n * 4)) +#define TPDM_BC_TRIG_HI(n) (0x318 + (n * 4)) +#define TPDM_BC_GANG (0x398) +#define TPDM_BC_OVERFLOW(n) (0x39C + (n * 4)) +#define TPDM_BC_OVSR (0x3C0) +#define TPDM_BC_SELR (0x3C4) +#define TPDM_BC_CNTR_LO (0x3C8) +#define TPDM_BC_CNTR_HI (0x3CC) +#define TPDM_BC_SHADOW_LO(n) (0x3D0 + (n * 4)) +#define TPDM_BC_SHADOW_HI(n) (0x450 + (n * 4)) +#define TPDM_BC_SWINC (0x4D0) +#define TPDM_BC_MSR(n) (0x4F0 + (n * 4)) + +/* TC Subunit Registers */ +#define TPDM_TC_CR (0x500) +#define TPDM_TC_CNTENSET (0x504) +#define TPDM_TC_CNTENCLR (0x508) +#define TPDM_TC_INTENSET (0x50C) +#define TPDM_TC_INTENCLR (0x510) +#define TPDM_TC_TRIG_SEL(n) (0x514 + (n * 4)) +#define TPDM_TC_TRIG_LO(n) (0x534 + (n * 4)) +#define TPDM_TC_TRIG_HI(n) (0x554 + (n * 4)) +#define TPDM_TC_OVSR_GP (0x580) +#define TPDM_TC_OVSR_IMPL (0x584) +#define TPDM_TC_SELR (0x588) +#define TPDM_TC_CNTR_LO (0x58C) +#define TPDM_TC_CNTR_HI (0x590) +#define TPDM_TC_SHADOW_LO(n) (0x594 + (n * 4)) +#define TPDM_TC_SHADOW_HI(n) (0x644 + (n * 4)) +#define TPDM_TC_SWINC (0x700) +#define TPDM_TC_MSR(n) (0x768 + (n * 4)) + +/* DSB Subunit Registers */ +#define TPDM_DSB_CR (0x780) +#define TPDM_DSB_TIER (0x784) +#define TPDM_DSB_TPR(n) (0x788 + (n * 4)) +#define TPDM_DSB_TPMR(n) (0x7A8 + (n * 4)) +#define TPDM_DSB_XPR(n) (0x7C8 + (n * 4)) +#define TPDM_DSB_XPMR(n) (0x7E8 + (n * 4)) +#define TPDM_DSB_EDCR(n) (0x808 + (n * 4)) +#define TPDM_DSB_EDCMR(n) (0x848 + (n * 4)) +#define TPDM_DSB_CA_SELECT(n) (0x86c + (n * 4)) +#define TPDM_DSB_MSR(n) (0x980 + (n * 4)) + +/* CMB/MCMB Subunit Registers */ +#define TPDM_CMB_CR (0xA00) +#define TPDM_CMB_TIER (0xA04) +#define TPDM_CMB_TPR(n) (0xA08 + (n * 4)) +#define TPDM_CMB_TPMR(n) (0xA10 + (n * 4)) +#define TPDM_CMB_XPR(n) (0xA18 + (n * 4)) +#define TPDM_CMB_XPMR(n) (0xA20 + (n * 4)) +#define TPDM_CMB_MARKR (0xA28) +#define TPDM_CMB_READCTL (0xA70) +#define TPDM_CMB_READVAL (0xA74) +#define TPDM_CMB_MSR(n) (0xA80 + (n * 4)) + +/* TPDM Specific Registers */ +#define TPDM_ITATBCNTRL (0xEF0) +#define TPDM_CLK_CTRL (0x220) +#define TPDM_ITCNTRL (0xF00) + + +#define TPDM_DATASETS 32 +#define TPDM_BC_MAX_COUNTERS 32 +#define TPDM_BC_MAX_OVERFLOW 6 +#define TPDM_BC_MAX_MSR 4 +#define TPDM_TC_MAX_COUNTERS 44 +#define TPDM_TC_MAX_TRIG 8 +#define TPDM_TC_MAX_MSR 6 +#define TPDM_DSB_MAX_PATT 8 +#define TPDM_DSB_MAX_SELECT 8 +#define TPDM_DSB_MAX_MSR 32 +#define TPDM_DSB_MAX_EDCR 16 +#define TPDM_DSB_MAX_LINES 256 +#define TPDM_CMB_PATT_CMP 2 +#define TPDM_CMB_MAX_MSR 128 +#define TPDM_MCMB_MAX_LANES 8 + +/* DSB programming modes */ +#define TPDM_DSB_MODE_CYCACC(val) BMVAL(val, 0, 2) +#define TPDM_DSB_MODE_PERF BIT(3) +#define TPDM_DSB_MODE_HPBYTESEL(val) BMVAL(val, 4, 8) +#define TPDM_MODE_ALL (0xFFFFFFF) + +#define NUM_OF_BITS 32 +#define TPDM_GPR_REGS_MAX 160 + +#define TPDM_TRACE_ID_START 128 + +#define TPDM_REVISION_A 0 +#define TPDM_REVISION_B 1 + +#define HW_ENABLE_CHECK_VALUE 0x10 + + +#define ATBCNTRL_VAL_32 0xC00F1409 +#define ATBCNTRL_VAL_64 0xC01F1409 + + +enum tpdm_dataset { + TPDM_DS_IMPLDEF, + TPDM_DS_DSB, + TPDM_DS_CMB, + TPDM_DS_TC, + TPDM_DS_BC, + TPDM_DS_GPR, + TPDM_DS_MCMB, +}; + +enum tpdm_mode { + TPDM_MODE_ATB, + TPDM_MODE_APB, +}; + +enum tpdm_support_type { + TPDM_SUPPORT_TYPE_FULL, + TPDM_SUPPORT_TYPE_PARTIAL, + TPDM_SUPPORT_TYPE_NO, +}; + +enum tpdm_cmb_patt_bits { + TPDM_CMB_LSB, + TPDM_CMB_MSB, +}; + +#ifdef CONFIG_CORESIGHT_TPDM_DEFAULT_ENABLE +static int boot_enable = 1; +#else +static int boot_enable; +#endif + +struct gpr_dataset { + DECLARE_BITMAP(gpr_dirty, TPDM_GPR_REGS_MAX); + uint32_t gp_regs[TPDM_GPR_REGS_MAX]; +}; + +struct bc_dataset { + enum tpdm_mode capture_mode; + enum tpdm_mode retrieval_mode; + uint32_t sat_mode; + uint32_t enable_counters; + uint32_t clear_counters; + uint32_t enable_irq; + uint32_t clear_irq; + uint32_t trig_val_lo[TPDM_BC_MAX_COUNTERS]; + uint32_t trig_val_hi[TPDM_BC_MAX_COUNTERS]; + uint32_t enable_ganging; + uint32_t overflow_val[TPDM_BC_MAX_OVERFLOW]; + uint32_t msr[TPDM_BC_MAX_MSR]; +}; + +struct tc_dataset { + enum tpdm_mode capture_mode; + enum tpdm_mode retrieval_mode; + bool sat_mode; + uint32_t enable_counters; + uint32_t clear_counters; + uint32_t enable_irq; + uint32_t clear_irq; + uint32_t trig_sel[TPDM_TC_MAX_TRIG]; + uint32_t trig_val_lo[TPDM_TC_MAX_TRIG]; + uint32_t trig_val_hi[TPDM_TC_MAX_TRIG]; + uint32_t msr[TPDM_TC_MAX_MSR]; +}; + +struct dsb_dataset { + uint32_t mode; + uint32_t edge_ctrl[TPDM_DSB_MAX_EDCR]; + uint32_t edge_ctrl_mask[TPDM_DSB_MAX_EDCR / 2]; + uint32_t patt_val[TPDM_DSB_MAX_PATT]; + uint32_t patt_mask[TPDM_DSB_MAX_PATT]; + bool patt_ts; + bool patt_type; + uint32_t trig_patt_val[TPDM_DSB_MAX_PATT]; + uint32_t trig_patt_mask[TPDM_DSB_MAX_PATT]; + bool trig_ts; + bool trig_type; + uint32_t select_val[TPDM_DSB_MAX_SELECT]; + uint32_t msr[TPDM_DSB_MAX_MSR]; +}; + +struct mcmb_dataset { + uint8_t mcmb_trig_lane; + uint8_t mcmb_lane_select; +}; + +struct cmb_dataset { + bool trace_mode; + uint32_t cycle_acc; + uint32_t patt_val[TPDM_CMB_PATT_CMP]; + uint32_t patt_mask[TPDM_CMB_PATT_CMP]; + bool patt_ts; + uint32_t trig_patt_val[TPDM_CMB_PATT_CMP]; + uint32_t trig_patt_mask[TPDM_CMB_PATT_CMP]; + bool trig_ts; + bool ts_all; + uint32_t msr[TPDM_CMB_MAX_MSR]; + uint8_t read_ctl_reg; + struct mcmb_dataset *mcmb; +}; + +DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm"); + +struct tpdm_drvdata { + void __iomem *base; + struct device *dev; + struct coresight_device *csdev; + int nr_tclk; + struct clk **tclk; + int nr_treg; + struct regulator **treg; + struct mutex lock; + bool enable; + bool clk_enable; + DECLARE_BITMAP(datasets, TPDM_DATASETS); + DECLARE_BITMAP(enable_ds, TPDM_DATASETS); + enum tpdm_support_type tc_trig_type; + enum tpdm_support_type bc_trig_type; + enum tpdm_support_type bc_gang_type; + uint32_t bc_counters_avail; + uint32_t tc_counters_avail; + struct gpr_dataset *gpr; + struct bc_dataset *bc; + struct tc_dataset *tc; + struct dsb_dataset *dsb; + struct cmb_dataset *cmb; + int traceid; + uint32_t version; + bool msr_support; + bool msr_fix_req; + bool cmb_msr_skip; +}; + +static void tpdm_init_default_data(struct tpdm_drvdata *drvdata); + +static void __tpdm_enable(struct tpdm_drvdata *drvdata) +{ + TPDM_UNLOCK(drvdata); + + if (drvdata->clk_enable) + tpdm_writel(drvdata, 0x1, TPDM_CLK_CTRL); + + TPDM_LOCK(drvdata); +} + +static int tpdm_enable(struct coresight_device *csdev, + struct perf_event *event, u32 mode) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + int ret = 0; + + if (drvdata->enable) { + dev_err(drvdata->dev, + "TPDM setup already enabled,Skipping enablei\n"); + return ret; + } + + mutex_lock(&drvdata->lock); + __tpdm_enable(drvdata); + drvdata->enable = true; + mutex_unlock(&drvdata->lock); + + dev_info(drvdata->dev, "TPDM tracing enabled\n"); + return 0; +} + +static void __tpdm_disable(struct tpdm_drvdata *drvdata) +{ + TPDM_UNLOCK(drvdata); + + if (drvdata->clk_enable) + tpdm_writel(drvdata, 0x0, TPDM_CLK_CTRL); + + TPDM_LOCK(drvdata); +} + +static void tpdm_disable(struct coresight_device *csdev, + struct perf_event *event) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + if (!drvdata->enable) { + dev_err(drvdata->dev, + "TPDM setup already disabled, Skipping disable\n"); + return; + } + mutex_lock(&drvdata->lock); + __tpdm_disable(drvdata); + drvdata->enable = false; + mutex_unlock(&drvdata->lock); + + dev_info(drvdata->dev, "TPDM tracing disabled\n"); +} + +static int tpdm_trace_id(struct coresight_device *csdev) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + return drvdata->traceid; +} + +static const struct coresight_ops_source tpdm_source_ops = { + .trace_id = tpdm_trace_id, + .enable = tpdm_enable, + .disable = tpdm_disable, +}; + +static const struct coresight_ops tpdm_cs_ops = { + .source_ops = &tpdm_source_ops, +}; + +static int tpdm_datasets_alloc(struct tpdm_drvdata *drvdata) +{ + if (test_bit(TPDM_DS_GPR, drvdata->datasets)) { + drvdata->gpr = devm_kzalloc(drvdata->dev, sizeof(*drvdata->gpr), + GFP_KERNEL); + if (!drvdata->gpr) + return -ENOMEM; + } + if (test_bit(TPDM_DS_BC, drvdata->datasets)) { + drvdata->bc = devm_kzalloc(drvdata->dev, sizeof(*drvdata->bc), + GFP_KERNEL); + if (!drvdata->bc) + return -ENOMEM; + } + if (test_bit(TPDM_DS_TC, drvdata->datasets)) { + drvdata->tc = devm_kzalloc(drvdata->dev, sizeof(*drvdata->tc), + GFP_KERNEL); + if (!drvdata->tc) + return -ENOMEM; + } + if (test_bit(TPDM_DS_DSB, drvdata->datasets)) { + drvdata->dsb = devm_kzalloc(drvdata->dev, sizeof(*drvdata->dsb), + GFP_KERNEL); + if (!drvdata->dsb) + return -ENOMEM; + } + if (test_bit(TPDM_DS_CMB, drvdata->datasets)) { + drvdata->cmb = devm_kzalloc(drvdata->dev, sizeof(*drvdata->cmb), + GFP_KERNEL); + if (!drvdata->cmb) + return -ENOMEM; + } else if (test_bit(TPDM_DS_MCMB, drvdata->datasets)) { + drvdata->cmb = devm_kzalloc(drvdata->dev, sizeof(*drvdata->cmb), + GFP_KERNEL); + if (!drvdata->cmb) + return -ENOMEM; + drvdata->cmb->mcmb = devm_kzalloc(drvdata->dev, + sizeof(*drvdata->cmb->mcmb), + GFP_KERNEL); + if (!drvdata->cmb->mcmb) + return -ENOMEM; + } + return 0; +} + +static void tpdm_init_default_data(struct tpdm_drvdata *drvdata) +{ + if (test_bit(TPDM_DS_BC, drvdata->datasets)) + drvdata->bc->retrieval_mode = TPDM_MODE_ATB; + + if (test_bit(TPDM_DS_TC, drvdata->datasets)) + drvdata->tc->retrieval_mode = TPDM_MODE_ATB; + + if (test_bit(TPDM_DS_DSB, drvdata->datasets)) { + drvdata->dsb->trig_ts = true; + drvdata->dsb->trig_type = false; + } + + if (test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets)) + drvdata->cmb->trig_ts = true; +} + +static int tpdm_parse_of_data(struct tpdm_drvdata *drvdata) +{ + int i, ret; + const char *tclk_name, *treg_name; + struct device_node *node = drvdata->dev->of_node; + + drvdata->clk_enable = of_property_read_bool(node, "qcom,clk-enable"); + drvdata->msr_fix_req = of_property_read_bool(node, "qcom,msr-fix-req"); + drvdata->cmb_msr_skip = of_property_read_bool(node, + "qcom,cmb-msr-skip"); + + drvdata->nr_tclk = of_property_count_strings(node, "qcom,tpdm-clks"); + if (drvdata->nr_tclk > 0) { + drvdata->tclk = devm_kzalloc(drvdata->dev, drvdata->nr_tclk * + sizeof(*drvdata->tclk), + GFP_KERNEL); + if (!drvdata->tclk) + return -ENOMEM; + + for (i = 0; i < drvdata->nr_tclk; i++) { + ret = of_property_read_string_index(node, + "qcom,tpdm-clks", i, &tclk_name); + if (ret) + return ret; + + drvdata->tclk[i] = devm_clk_get(drvdata->dev, + tclk_name); + if (IS_ERR(drvdata->tclk[i])) + return PTR_ERR(drvdata->tclk[i]); + } + } + + drvdata->nr_treg = of_property_count_strings(node, "qcom,tpdm-regs"); + if (drvdata->nr_treg > 0) { + drvdata->treg = devm_kzalloc(drvdata->dev, drvdata->nr_treg * + sizeof(*drvdata->treg), + GFP_KERNEL); + if (!drvdata->treg) + return -ENOMEM; + + for (i = 0; i < drvdata->nr_treg; i++) { + ret = of_property_read_string_index(node, + "qcom,tpdm-regs", i, &treg_name); + if (ret) + return ret; + + drvdata->treg[i] = devm_regulator_get(drvdata->dev, + treg_name); + if (IS_ERR(drvdata->treg[i])) + return PTR_ERR(drvdata->treg[i]); + } + } + + return 0; +} + +static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) +{ + int ret, i; + uint32_t pidr, devid; + struct device *dev = &adev->dev; + struct coresight_platform_data *pdata; + struct tpdm_drvdata *drvdata; + struct coresight_desc desc = { 0 }; + static int traceid = TPDM_TRACE_ID_START; + uint32_t version; + + desc.name = coresight_alloc_device_name(&tpdm_devs, dev); + if (!desc.name) + return -ENOMEM; + pdata = coresight_get_platform_data(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + adev->dev.platform_data = pdata; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + drvdata->dev = &adev->dev; + dev_set_drvdata(dev, drvdata); + + drvdata->base = devm_ioremap_resource(dev, &adev->res); + if (!drvdata->base) + return -ENOMEM; + + mutex_init(&drvdata->lock); + + ret = tpdm_parse_of_data(drvdata); + if (ret) { + dev_err(drvdata->dev, "TPDM parse of data fail\n"); + return -EINVAL; + } + + desc.type = CORESIGHT_DEV_TYPE_SOURCE; + desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC; + desc.ops = &tpdm_cs_ops; + desc.pdata = adev->dev.platform_data; + desc.dev = &adev->dev; + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); + + version = tpdm_readl(drvdata, CORESIGHT_PERIPHIDR2); + drvdata->version = BMVAL(version, 4, 7); + + if (drvdata->version) + drvdata->msr_support = true; + + pidr = tpdm_readl(drvdata, CORESIGHT_PERIPHIDR0); + for (i = 0; i < TPDM_DATASETS; i++) { + if (pidr & BIT(i)) { + __set_bit(i, drvdata->datasets); + __set_bit(i, drvdata->enable_ds); + } + } + + ret = tpdm_datasets_alloc(drvdata); + if (ret) { + coresight_unregister(drvdata->csdev); + return ret; + } + + tpdm_init_default_data(drvdata); + + devid = tpdm_readl(drvdata, CORESIGHT_DEVID); + drvdata->tc_trig_type = BMVAL(devid, 27, 28); + drvdata->bc_trig_type = BMVAL(devid, 25, 26); + drvdata->bc_gang_type = BMVAL(devid, 23, 24); + drvdata->bc_counters_avail = BMVAL(devid, 6, 10) + 1; + drvdata->tc_counters_avail = BMVAL(devid, 4, 5) + 1; + + drvdata->traceid = traceid++; + + dev_dbg(drvdata->dev, "TPDM initialized\n"); + + if (boot_enable) + coresight_enable(drvdata->csdev); + + pm_runtime_put(&adev->dev); + + return 0; +} + +static struct amba_id tpdm_ids[] = { + { + .id = 0x001f0e00, + .mask = 0x00ffff00, + .data = "TPDM", + }, + { 0, 0}, +}; + +static struct amba_driver tpdm_driver = { + .drv = { + .name = "coresight-tpdm", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + }, + .probe = tpdm_probe, + .id_table = tpdm_ids, +}; + +module_amba_driver(tpdm_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Monitor driver"); From patchwork Thu Oct 21 07:38:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574131 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 74809C433FE for ; Thu, 21 Oct 2021 07:42:14 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 3C6DC61284 for ; Thu, 21 Oct 2021 07:42:14 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 3C6DC61284 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=+XPuJY29Po9FNwXmBt3aBgdqkej5PPiaUTQWGtCAG0o=; b=diX3M9hcMPOwON qN+0fzkFrlr4GzeMRlT6ZX8xnYEIYrPi4gOIOPKqQgHhSvfT+IyaKwqClGc4nJYPO9/FLLJZzNQI3 xHEBgbkknTjG90PdNMhf9RucKoEUB6ZZABwQvu71nh85d/uBcx/LQpw0DoCS/xexSgT/S9yBloXv9 cWaN6w4cxzr6vNWs0EBWVubWMzB3Cmad4lkA2rIB3AyChFwOGL8YMOdKBdGVagCFALFXQ1bSZnJ3s PYguP02gfsi7wmvrCru9sYJBgfV1BFq8BinvNXw7VI24+/1OwBaLEILgGyHOvcmRZ9gHPqQPDKdqb v28R7zl77Qcr19fOX+/Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSgq-006hIo-MV; Thu, 21 Oct 2021 07:40:41 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSg3-006gwq-8w for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:39:53 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634801991; x=1666337991; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=sgRhiQWRN83ZnKrmG4BjOIzZJYwLfliEuyEKMZT6jaE=; b=hpFOM+lfkI5LO+ugpklJEzHOPbNjHPTUj3H4dWRXaWHa5g+eNd8syxiB 9KgoI0onZuCf794COBzVbt9oKF9DDff9JsmovNRiGVjrYwsk0vWijKscB QdXQ4coZjQCyPNSbs/f7SBZuIjkHofLdIIuWIaWOzAPneDB/Mz3PSmf55 Q=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:39:51 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:39:51 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:39:47 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni Subject: [PATCH 04/10] Coresight: Enable BC and GPR for TPDM driver Date: Thu, 21 Oct 2021 15:38:50 +0800 Message-ID: <1634801936-15080-5-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_003951_412733_D65DFFA4 X-CRM114-Status: GOOD ( 20.90 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Enable GPR and Basic Counts(BC) for TPDM. Add GPR interface and basic control sysFS interface for TPDM. The GPR interface has RW and RO fields for controlling external logic and mapping core signals to an APB accessible address in the TPDM address map. Signed-off-by: Tao Zhang --- drivers/hwtracing/coresight/coresight-tpdm.c | 334 +++++++++++++++++++ 1 file changed, 334 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 906776c859d6..c0a01979e42f 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -276,6 +276,93 @@ struct tpdm_drvdata { static void tpdm_init_default_data(struct tpdm_drvdata *drvdata); +static void __tpdm_enable_gpr(struct tpdm_drvdata *drvdata) +{ + int i; + + for (i = 0; i < TPDM_GPR_REGS_MAX; i++) { + if (!test_bit(i, drvdata->gpr->gpr_dirty)) + continue; + tpdm_writel(drvdata, drvdata->gpr->gp_regs[i], TPDM_GPR_CR(i)); + } +} + +static void __tpdm_config_bc_msr(struct tpdm_drvdata *drvdata) +{ + int i; + + if (!drvdata->msr_support) + return; + + for (i = 0; i < TPDM_BC_MAX_MSR; i++) + tpdm_writel(drvdata, drvdata->bc->msr[i], TPDM_BC_MSR(i)); +} + +static void __tpdm_enable_bc(struct tpdm_drvdata *drvdata) +{ + int i; + uint32_t val; + + if (drvdata->bc->sat_mode) + tpdm_writel(drvdata, drvdata->bc->sat_mode, + TPDM_BC_SATROLL); + else + tpdm_writel(drvdata, 0x0, TPDM_BC_SATROLL); + + if (drvdata->bc->enable_counters) { + tpdm_writel(drvdata, 0xFFFFFFFF, TPDM_BC_CNTENCLR); + tpdm_writel(drvdata, drvdata->bc->enable_counters, + TPDM_BC_CNTENSET); + } + if (drvdata->bc->clear_counters) + tpdm_writel(drvdata, drvdata->bc->clear_counters, + TPDM_BC_CNTENCLR); + + if (drvdata->bc->enable_irq) { + tpdm_writel(drvdata, 0xFFFFFFFF, TPDM_BC_INTENCLR); + tpdm_writel(drvdata, drvdata->bc->enable_irq, + TPDM_BC_INTENSET); + } + if (drvdata->bc->clear_irq) + tpdm_writel(drvdata, drvdata->bc->clear_irq, + TPDM_BC_INTENCLR); + + if (drvdata->bc_trig_type == TPDM_SUPPORT_TYPE_FULL) { + for (i = 0; i < drvdata->bc_counters_avail; i++) { + tpdm_writel(drvdata, drvdata->bc->trig_val_lo[i], + TPDM_BC_TRIG_LO(i)); + tpdm_writel(drvdata, drvdata->bc->trig_val_hi[i], + TPDM_BC_TRIG_HI(i)); + } + } else if (drvdata->bc_trig_type == TPDM_SUPPORT_TYPE_PARTIAL) { + tpdm_writel(drvdata, drvdata->bc->trig_val_lo[0], + TPDM_BC_TRIG_LO(0)); + tpdm_writel(drvdata, drvdata->bc->trig_val_hi[0], + TPDM_BC_TRIG_HI(0)); + } + + if (drvdata->bc->enable_ganging) + tpdm_writel(drvdata, drvdata->bc->enable_ganging, TPDM_BC_GANG); + + for (i = 0; i < TPDM_BC_MAX_OVERFLOW; i++) + tpdm_writel(drvdata, drvdata->bc->overflow_val[i], + TPDM_BC_OVERFLOW(i)); + + __tpdm_config_bc_msr(drvdata); + + val = tpdm_readl(drvdata, TPDM_BC_CR); + if (drvdata->bc->retrieval_mode == TPDM_MODE_APB) + val = val | BIT(2); + else + val = val & ~BIT(2); + tpdm_writel(drvdata, val, TPDM_BC_CR); + + val = tpdm_readl(drvdata, TPDM_BC_CR); + /* Set the enable bit */ + val = val | BIT(0); + tpdm_writel(drvdata, val, TPDM_BC_CR); +} + static void __tpdm_enable(struct tpdm_drvdata *drvdata) { TPDM_UNLOCK(drvdata); @@ -283,6 +370,12 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) if (drvdata->clk_enable) tpdm_writel(drvdata, 0x1, TPDM_CLK_CTRL); + if (test_bit(TPDM_DS_GPR, drvdata->enable_ds)) + __tpdm_enable_gpr(drvdata); + + if (test_bit(TPDM_DS_BC, drvdata->enable_ds)) + __tpdm_enable_bc(drvdata); + TPDM_LOCK(drvdata); } @@ -307,10 +400,22 @@ static int tpdm_enable(struct coresight_device *csdev, return 0; } +static void __tpdm_disable_bc(struct tpdm_drvdata *drvdata) +{ + uint32_t config; + + config = tpdm_readl(drvdata, TPDM_BC_CR); + config = config & ~BIT(0); + tpdm_writel(drvdata, config, TPDM_BC_CR); +} + static void __tpdm_disable(struct tpdm_drvdata *drvdata) { TPDM_UNLOCK(drvdata); + if (test_bit(TPDM_DS_BC, drvdata->enable_ds)) + __tpdm_disable_bc(drvdata); + if (drvdata->clk_enable) tpdm_writel(drvdata, 0x0, TPDM_CLK_CTRL); @@ -352,6 +457,234 @@ static const struct coresight_ops tpdm_cs_ops = { .source_ops = &tpdm_source_ops, }; +static ssize_t available_datasets_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + + if (test_bit(TPDM_DS_IMPLDEF, drvdata->datasets)) + size += scnprintf(buf + size, PAGE_SIZE - size, "%-8s", + "IMPLDEF"); + + if (test_bit(TPDM_DS_DSB, drvdata->datasets)) + size += scnprintf(buf + size, PAGE_SIZE - size, "%-8s", "DSB"); + + if (test_bit(TPDM_DS_CMB, drvdata->datasets)) + size += scnprintf(buf + size, PAGE_SIZE - size, "%-8s", "CMB"); + + if (test_bit(TPDM_DS_TC, drvdata->datasets)) + size += scnprintf(buf + size, PAGE_SIZE - size, "%-8s", "TC"); + + if (test_bit(TPDM_DS_BC, drvdata->datasets)) + size += scnprintf(buf + size, PAGE_SIZE - size, "%-8s", "BC"); + + if (test_bit(TPDM_DS_GPR, drvdata->datasets)) + size += scnprintf(buf + size, PAGE_SIZE - size, "%-8s", "GPR"); + + if (test_bit(TPDM_DS_MCMB, drvdata->datasets)) + size += scnprintf(buf + size, PAGE_SIZE - size, "%-8s", "MCMB"); + + size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); + return size; +} +static DEVICE_ATTR_RO(available_datasets); + +static ssize_t enable_datasets_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size; + + size = scnprintf(buf, PAGE_SIZE, "%*pb\n", TPDM_DATASETS, + drvdata->enable_ds); + + if (PAGE_SIZE - size < 2) + size = -EINVAL; + else + size += scnprintf(buf + size, 2, "\n"); + return size; +} + +static ssize_t enable_datasets_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + int i; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + if (drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + for (i = 0; i < TPDM_DATASETS; i++) { + if (test_bit(i, drvdata->datasets) && (val & BIT(i))) + __set_bit(i, drvdata->enable_ds); + else + __clear_bit(i, drvdata->enable_ds); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(enable_datasets); + +static ssize_t reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + int ret = 0; + unsigned long val; + struct mcmb_dataset *mcmb_temp = NULL; + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&drvdata->lock); + /* Reset all datasets to ZERO */ + if (drvdata->gpr != NULL) + memset(drvdata->gpr, 0, sizeof(struct gpr_dataset)); + + if (drvdata->bc != NULL) + memset(drvdata->bc, 0, sizeof(struct bc_dataset)); + + if (drvdata->tc != NULL) + memset(drvdata->tc, 0, sizeof(struct tc_dataset)); + + if (drvdata->dsb != NULL) + memset(drvdata->dsb, 0, sizeof(struct dsb_dataset)); + + if (drvdata->cmb != NULL) { + if (drvdata->cmb->mcmb != NULL) { + mcmb_temp = drvdata->cmb->mcmb; + memset(drvdata->cmb->mcmb, 0, + sizeof(struct mcmb_dataset)); + } + + memset(drvdata->cmb, 0, sizeof(struct cmb_dataset)); + drvdata->cmb->mcmb = mcmb_temp; + } + /* Init the default data */ + tpdm_init_default_data(drvdata); + + mutex_unlock(&drvdata->lock); + + /* Disable tpdm if enabled */ + if (drvdata->enable) + coresight_disable(drvdata->csdev); + + return size; +} +static DEVICE_ATTR_WO(reset); + +static ssize_t integration_test_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + int i, ret = 0; + unsigned long val; + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + if (val != 1 && val != 2) + return -EINVAL; + + if (!drvdata->enable) + return -EINVAL; + + if (val == 1) + val = ATBCNTRL_VAL_64; + else + val = ATBCNTRL_VAL_32; + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, 0x1, TPDM_ITCNTRL); + + for (i = 1; i < 5; i++) + tpdm_writel(drvdata, val, TPDM_ITATBCNTRL); + + tpdm_writel(drvdata, 0, TPDM_ITCNTRL); + TPDM_LOCK(drvdata); + return size; +} +static DEVICE_ATTR_WO(integration_test); + +static ssize_t gp_regs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_GPR, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_GPR_REGS_MAX; i++) { + if (!test_bit(i, drvdata->gpr->gpr_dirty)) + continue; + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->gpr->gp_regs[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t gp_regs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_GPR, drvdata->datasets) || + index >= TPDM_GPR_REGS_MAX) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->gpr->gp_regs[index] = val; + __set_bit(index, drvdata->gpr->gpr_dirty); + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(gp_regs); + +static struct attribute *tpdm_attrs[] = { + &dev_attr_available_datasets.attr, + &dev_attr_enable_datasets.attr, + &dev_attr_reset.attr, + &dev_attr_integration_test.attr, + &dev_attr_gp_regs.attr, + NULL, +}; + +static struct attribute_group tpdm_attr_grp = { + .attrs = tpdm_attrs, +}; +static const struct attribute_group *tpdm_attr_grps[] = { + &tpdm_attr_grp, + NULL, +}; + static int tpdm_datasets_alloc(struct tpdm_drvdata *drvdata) { if (test_bit(TPDM_DS_GPR, drvdata->datasets)) { @@ -513,6 +846,7 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) desc.ops = &tpdm_cs_ops; desc.pdata = adev->dev.platform_data; desc.dev = &adev->dev; + desc.groups = tpdm_attr_grps; drvdata->csdev = coresight_register(&desc); if (IS_ERR(drvdata->csdev)) return PTR_ERR(drvdata->csdev); From patchwork Thu Oct 21 07:38:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574133 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4BFEEC433EF for ; Thu, 21 Oct 2021 07:42:42 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 0652361130 for ; Thu, 21 Oct 2021 07:42:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 0652361130 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=kFUJZggq1uS6UKznlY7BuFmDofkK+ff7XqPwIL57QPk=; b=0PH0vusANLe0XX sYD41vWiiWiRt7Mp9u6xlVEE8+o10YwLI+yFc7IEaybH8C+zSanNhotlYi7aviKlhF1y3J1R99qxu fpVBCdNRnHSlWn9rPmZurLJ/OuoOI2Q495R+EVIYpdeztGTnJ9t73xQJ7Gl+9sKi01mcb3Qz3Y2PD ezDRnO429KVIIM2C5dKWYj3GkYSADnXJwxDpEs/qn3Zp9Mz/Nhvuy7urb0ohN9OYqmhpKYU/BCXda A/aC9xIJ8388SvnKHcoXMB2wKoERblwguabL96VGFeo8+2j+jJOEMVwmJS4Ue1EDGCU88aGdiNfD8 HRVFztX65faOa/uAo/6Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSh9-006hTe-3M; Thu, 21 Oct 2021 07:40:59 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSg7-006gy6-4L for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:39:58 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634801995; x=1666337995; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=h82+1QXe93e0GFng8zWYEmWF8Yf4Ltq2B4+LmF3L3Yo=; b=Mo1bkiVwCd/A0UkSz/2kKs/S7nU+V56bpDPrAcsuOwTuoQjmWaSJjiPw xsC4j6c6/7gA+f2aKwZeyh1JB3K0x2xRH1Y4guWiOPtHYMYAI9Tf0JR8J Fz93i8mOx7WUQ0VxTc7BGTV4l9z6KV7sm8TgE+QOeLnNlLp3V03mDXs77 E=; Received: from ironmsg-lv-alpha.qualcomm.com ([10.47.202.13]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:39:54 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg-lv-alpha.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:39:54 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:39:50 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni Subject: [PATCH 05/10] Coresight: Add interface for TPDM BC subunit Date: Thu, 21 Oct 2021 15:38:51 +0800 Message-ID: <1634801936-15080-6-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_003955_315341_073D0262 X-CRM114-Status: GOOD ( 14.49 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The BC(Basic Counters) interface has RW, WO and RO fields for controlling BC dataset elements transmitted on ATB flush. The BC data set subunit supports from 1-32 counter instances allowing for collection of BC data sets. Signed-off-by: Tao Zhang --- drivers/hwtracing/coresight/coresight-tpdm.c | 873 +++++++++++++++++++ 1 file changed, 873 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index c0a01979e42f..0970c69ac8e2 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -668,6 +668,878 @@ static ssize_t gp_regs_store(struct device *dev, } static DEVICE_ATTR_RW(gp_regs); +static ssize_t bc_capture_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%s\n", + drvdata->bc->capture_mode == TPDM_MODE_ATB ? + "ATB" : "APB"); +} + +static ssize_t bc_capture_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + char str[20] = ""; + uint32_t val; + + if (size >= 20) + return -EINVAL; + if (sscanf(buf, "%s", str) != 1) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (!strcmp(str, "ATB")) { + drvdata->bc->capture_mode = TPDM_MODE_ATB; + } else if (!strcmp(str, "APB") && + drvdata->bc->retrieval_mode == TPDM_MODE_APB) { + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_BC_CR); + val = val | BIT(3); + tpdm_writel(drvdata, val, TPDM_BC_CR); + TPDM_LOCK(drvdata); + + drvdata->bc->capture_mode = TPDM_MODE_APB; + } else { + mutex_unlock(&drvdata->lock); + return -EINVAL; + } + + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_capture_mode); + +static ssize_t bc_retrieval_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%s\n", + drvdata->bc->retrieval_mode == TPDM_MODE_ATB ? + "ATB" : "APB"); +} + +static ssize_t bc_retrieval_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + char str[20] = ""; + + if (size >= 20) + return -EINVAL; + if (sscanf(buf, "%s", str) != 1) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (!strcmp(str, "ATB")) { + drvdata->bc->retrieval_mode = TPDM_MODE_ATB; + } else if (!strcmp(str, "APB")) { + drvdata->bc->retrieval_mode = TPDM_MODE_APB; + } else { + mutex_unlock(&drvdata->lock); + return -EINVAL; + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_retrieval_mode); + +static ssize_t bc_reset_counters_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_BC_CR); + val = val | BIT(1); + tpdm_writel(drvdata, val, TPDM_BC_CR); + TPDM_LOCK(drvdata); + } + + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_WO(bc_reset_counters); + +static ssize_t bc_sat_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->bc->sat_mode); +} + +static ssize_t bc_sat_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->sat_mode = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_sat_mode); + +static ssize_t bc_enable_counters_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->bc->enable_counters); +} + +static ssize_t bc_enable_counters_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->enable_counters = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_enable_counters); + +static ssize_t bc_clear_counters_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->bc->clear_counters); +} + +static ssize_t bc_clear_counters_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->clear_counters = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_clear_counters); + +static ssize_t bc_enable_irq_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->bc->enable_irq); +} + +static ssize_t bc_enable_irq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->enable_irq = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_enable_irq); + +static ssize_t bc_clear_irq_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->bc->clear_irq); +} + +static ssize_t bc_clear_irq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->clear_irq = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_clear_irq); + +static ssize_t bc_trig_val_lo_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_BC_MAX_COUNTERS; i++) + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->bc->trig_val_lo[i]); + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t bc_trig_val_lo_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets) || + index >= drvdata->bc_counters_avail || + drvdata->bc_trig_type == TPDM_SUPPORT_TYPE_NO || + (drvdata->bc_trig_type == TPDM_SUPPORT_TYPE_PARTIAL && index > 0)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->trig_val_lo[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_trig_val_lo); + +static ssize_t bc_trig_val_hi_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_BC_MAX_COUNTERS; i++) + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->bc->trig_val_hi[i]); + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t bc_trig_val_hi_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets) || + index >= drvdata->bc_counters_avail || + drvdata->bc_trig_type == TPDM_SUPPORT_TYPE_NO || + (drvdata->bc_trig_type == TPDM_SUPPORT_TYPE_PARTIAL && index > 0)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->trig_val_hi[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_trig_val_hi); + +static ssize_t bc_enable_ganging_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->bc->enable_ganging); +} + +static ssize_t bc_enable_ganging_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->enable_ganging = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_enable_ganging); + +static ssize_t bc_overflow_val_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_BC_MAX_OVERFLOW; i++) + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->bc->overflow_val[i]); + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t bc_overflow_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->datasets) || + index >= TPDM_BC_MAX_OVERFLOW) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->bc->overflow_val[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_overflow_val); + +static ssize_t bc_ovsr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_BC_OVSR); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t bc_ovsr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_BC_OVSR); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_ovsr); + +static ssize_t bc_counter_sel_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_BC_SELR); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t bc_counter_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable || val >= drvdata->bc_counters_avail) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_BC_SELR); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_counter_sel); + +static ssize_t bc_count_val_lo_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_BC_CNTR_LO); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t bc_count_val_lo_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val, select; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + select = tpdm_readl(drvdata, TPDM_BC_SELR); + + /* Check if selected counter is disabled */ + if (BMVAL(tpdm_readl(drvdata, TPDM_BC_CNTENSET), select, select)) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + tpdm_writel(drvdata, val, TPDM_BC_CNTR_LO); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_count_val_lo); + +static ssize_t bc_count_val_hi_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_BC_CNTR_HI); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t bc_count_val_hi_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val, select; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + select = tpdm_readl(drvdata, TPDM_BC_SELR); + + /* Check if selected counter is disabled */ + if (BMVAL(tpdm_readl(drvdata, TPDM_BC_CNTENSET), select, select)) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + tpdm_writel(drvdata, val, TPDM_BC_CNTR_HI); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_count_val_hi); + +static ssize_t bc_shadow_val_lo_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + for (i = 0; i < drvdata->bc_counters_avail; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + tpdm_readl(drvdata, TPDM_BC_SHADOW_LO(i))); + } + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RO(bc_shadow_val_lo); + +static ssize_t bc_shadow_val_hi_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + for (i = 0; i < drvdata->bc_counters_avail; i++) + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + tpdm_readl(drvdata, TPDM_BC_SHADOW_HI(i))); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RO(bc_shadow_val_hi); + +static ssize_t bc_sw_inc_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_BC_SWINC); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t bc_sw_inc_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_BC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_BC_SWINC); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_sw_inc); + +static ssize_t bc_msr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int i; + ssize_t len = 0; + + if (!drvdata->msr_support) + return -EINVAL; + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + for (i = 0; i < TPDM_BC_MAX_MSR; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u 0x%x\n", + i, drvdata->bc->msr[i]); + + return len; +} + +static ssize_t bc_msr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int num, val; + int nval; + + if (!drvdata->msr_support) + return -EINVAL; + + if (!test_bit(TPDM_DS_BC, drvdata->datasets)) + return -EPERM; + + nval = sscanf(buf, "%u %x", &num, &val); + if (nval != 2) + return -EINVAL; + + if (num >= TPDM_BC_MAX_MSR) + return -EINVAL; + + mutex_lock(&drvdata->lock); + drvdata->bc->msr[num] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(bc_msr); + +static struct attribute *tpdm_bc_attrs[] = { + &dev_attr_bc_capture_mode.attr, + &dev_attr_bc_retrieval_mode.attr, + &dev_attr_bc_reset_counters.attr, + &dev_attr_bc_sat_mode.attr, + &dev_attr_bc_enable_counters.attr, + &dev_attr_bc_clear_counters.attr, + &dev_attr_bc_enable_irq.attr, + &dev_attr_bc_clear_irq.attr, + &dev_attr_bc_trig_val_lo.attr, + &dev_attr_bc_trig_val_hi.attr, + &dev_attr_bc_enable_ganging.attr, + &dev_attr_bc_overflow_val.attr, + &dev_attr_bc_ovsr.attr, + &dev_attr_bc_counter_sel.attr, + &dev_attr_bc_count_val_lo.attr, + &dev_attr_bc_count_val_hi.attr, + &dev_attr_bc_shadow_val_lo.attr, + &dev_attr_bc_shadow_val_hi.attr, + &dev_attr_bc_sw_inc.attr, + &dev_attr_bc_msr.attr, + NULL, +}; + +static struct attribute_group tpdm_bc_attr_grp = { + .attrs = tpdm_bc_attrs, +}; + static struct attribute *tpdm_attrs[] = { &dev_attr_available_datasets.attr, &dev_attr_enable_datasets.attr, @@ -682,6 +1554,7 @@ static struct attribute_group tpdm_attr_grp = { }; static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_attr_grp, + &tpdm_bc_attr_grp, NULL, }; From patchwork Thu Oct 21 07:38:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574135 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8BA8AC433EF for ; Thu, 21 Oct 2021 07:43:01 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 555B86112D for ; Thu, 21 Oct 2021 07:43:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 555B86112D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=cjUh8bCM4DZ8u753rEI/62XiZWwGBp5s3FpIYXDurq0=; b=lYEfDFGdTU0JmF i/qCvrdzDqvxFkP39g27bJhPJCfKjZSxnvVGpahqb9vfPjXDRgOzel7BFrWJSgM3dhQIDnqDQx4ny Z7+4JqE+BOEfaju97vYNwy6xo8arDBTIKib7PJ1mPNtEaY/BiuGKwHB2lektK9RflXvlcMjR73oes 7hplW/i4mYBYL/ieSWE8cT7uEgdbhpWy//GWKrsutY1X4HCDvJvEkvS2LxGK1svoO1eKY71q9ZUCZ KL477gDCd68vpNuBIHKU7u2h1SgRS7Gwrv7X7Hdx/Z2Tj1TCG9p597vK6/7dckM/5Me12Q2UvOPxQ a2F4VFIXDJ7wFayrP8VQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdShh-006hnP-2s; Thu, 21 Oct 2021 07:41:34 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSgA-006gy6-Eu for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:40:01 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634801998; x=1666337998; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=nQ1B/2pXcJg/+FgZI2xto8t+wrsmMgekSvc1/gqERXo=; b=XLbAQO1vUbRoW6WpkXbuw9gzkWfNHoDc1Iv6OhORskbjUyEkZNHWFDur 4zC+O5ERnr8C8372CCsDJH6pPYngJmRJbw2y2/2epOVCcv+54z6HQJ1yl jHZyl18yzTAaygRiGM2mzhXKv1f7UJRAUlwJ1DGDRgL2WfyLfqtAWxf41 8=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:39:58 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:39:58 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:39:54 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni Subject: [PATCH 06/10] Coresight: Enable and add interface for TPDM TC subunit Date: Thu, 21 Oct 2021 15:38:52 +0800 Message-ID: <1634801936-15080-7-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_003958_621742_25DA1305 X-CRM114-Status: GOOD ( 17.38 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Enable dataset type Tenure Counts(TC) for TPDM. The TC interface has RW, WO and RO fields for controlling BC dataset elements transmitted on ATB flush. The TC data set subunit supports from 1-4 tenure counter instances where each tenure counter instance is charged with collecting or computing elements of an STVn data set(MIN, MAX, TAT and GP Counter 0-7). Computation of data set elements MIN, MAX, and TAT is performed by the TC subunit by monitoring a pool of 1 to 1024 tenure scratchpad counters. Computation/decoding of increment enables for GP Counters 0-7 is accomplished via monitoring the state (TC subunit outputs) of the tenure scratchpad registers. This computation/decoding must be performed by the core instancing the TPDM to which the TC subunit belongs. Signed-off-by: Tao Zhang --- drivers/hwtracing/coresight/coresight-tpdm.c | 1066 +++++++++++++++++- 1 file changed, 1029 insertions(+), 37 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 0970c69ac8e2..635382be5de6 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -298,6 +298,17 @@ static void __tpdm_config_bc_msr(struct tpdm_drvdata *drvdata) tpdm_writel(drvdata, drvdata->bc->msr[i], TPDM_BC_MSR(i)); } +static void __tpdm_config_tc_msr(struct tpdm_drvdata *drvdata) +{ + int i; + + if (!drvdata->msr_support) + return; + + for (i = 0; i < TPDM_TC_MAX_MSR; i++) + tpdm_writel(drvdata, drvdata->tc->msr[i], TPDM_TC_MSR(i)); +} + static void __tpdm_enable_bc(struct tpdm_drvdata *drvdata) { int i; @@ -363,6 +374,66 @@ static void __tpdm_enable_bc(struct tpdm_drvdata *drvdata) tpdm_writel(drvdata, val, TPDM_BC_CR); } +static void __tpdm_enable_tc(struct tpdm_drvdata *drvdata) +{ + int i; + uint32_t val; + + if (drvdata->tc->enable_counters) { + tpdm_writel(drvdata, 0xF, TPDM_TC_CNTENCLR); + tpdm_writel(drvdata, drvdata->tc->enable_counters, + TPDM_TC_CNTENSET); + } + if (drvdata->tc->clear_counters) + tpdm_writel(drvdata, drvdata->tc->clear_counters, + TPDM_TC_CNTENCLR); + + if (drvdata->tc->enable_irq) { + tpdm_writel(drvdata, 0xF, TPDM_TC_INTENCLR); + tpdm_writel(drvdata, drvdata->tc->enable_irq, + TPDM_TC_INTENSET); + } + if (drvdata->tc->clear_irq) + tpdm_writel(drvdata, drvdata->tc->clear_irq, + TPDM_TC_INTENCLR); + + if (drvdata->tc_trig_type == TPDM_SUPPORT_TYPE_FULL) { + for (i = 0; i < TPDM_TC_MAX_TRIG; i++) { + tpdm_writel(drvdata, drvdata->tc->trig_sel[i], + TPDM_TC_TRIG_SEL(i)); + tpdm_writel(drvdata, drvdata->tc->trig_val_lo[i], + TPDM_TC_TRIG_LO(i)); + tpdm_writel(drvdata, drvdata->tc->trig_val_hi[i], + TPDM_TC_TRIG_HI(i)); + } + } else if (drvdata->tc_trig_type == TPDM_SUPPORT_TYPE_PARTIAL) { + tpdm_writel(drvdata, drvdata->tc->trig_sel[0], + TPDM_TC_TRIG_SEL(0)); + tpdm_writel(drvdata, drvdata->tc->trig_val_lo[0], + TPDM_TC_TRIG_LO(0)); + tpdm_writel(drvdata, drvdata->tc->trig_val_hi[0], + TPDM_TC_TRIG_HI(0)); + } + + __tpdm_config_tc_msr(drvdata); + + val = tpdm_readl(drvdata, TPDM_TC_CR); + if (drvdata->tc->sat_mode) + val = val | BIT(4); + else + val = val & ~BIT(4); + if (drvdata->tc->retrieval_mode == TPDM_MODE_APB) + val = val | BIT(2); + else + val = val & ~BIT(2); + tpdm_writel(drvdata, val, TPDM_TC_CR); + + val = tpdm_readl(drvdata, TPDM_TC_CR); + /* Set the enable bit */ + val = val | BIT(0); + tpdm_writel(drvdata, val, TPDM_TC_CR); +} + static void __tpdm_enable(struct tpdm_drvdata *drvdata) { TPDM_UNLOCK(drvdata); @@ -376,6 +447,9 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) if (test_bit(TPDM_DS_BC, drvdata->enable_ds)) __tpdm_enable_bc(drvdata); + if (test_bit(TPDM_DS_TC, drvdata->enable_ds)) + __tpdm_enable_tc(drvdata); + TPDM_LOCK(drvdata); } @@ -409,6 +483,15 @@ static void __tpdm_disable_bc(struct tpdm_drvdata *drvdata) tpdm_writel(drvdata, config, TPDM_BC_CR); } +static void __tpdm_disable_tc(struct tpdm_drvdata *drvdata) +{ + uint32_t config; + + config = tpdm_readl(drvdata, TPDM_TC_CR); + config = config & ~BIT(0); + tpdm_writel(drvdata, config, TPDM_TC_CR); +} + static void __tpdm_disable(struct tpdm_drvdata *drvdata) { TPDM_UNLOCK(drvdata); @@ -416,6 +499,9 @@ static void __tpdm_disable(struct tpdm_drvdata *drvdata) if (test_bit(TPDM_DS_BC, drvdata->enable_ds)) __tpdm_disable_bc(drvdata); + if (test_bit(TPDM_DS_TC, drvdata->enable_ds)) + __tpdm_disable_tc(drvdata); + if (drvdata->clk_enable) tpdm_writel(drvdata, 0x0, TPDM_CLK_CTRL); @@ -1512,49 +1598,955 @@ static ssize_t bc_msr_store(struct device *dev, } static DEVICE_ATTR_RW(bc_msr); -static struct attribute *tpdm_bc_attrs[] = { - &dev_attr_bc_capture_mode.attr, - &dev_attr_bc_retrieval_mode.attr, - &dev_attr_bc_reset_counters.attr, - &dev_attr_bc_sat_mode.attr, - &dev_attr_bc_enable_counters.attr, - &dev_attr_bc_clear_counters.attr, - &dev_attr_bc_enable_irq.attr, - &dev_attr_bc_clear_irq.attr, - &dev_attr_bc_trig_val_lo.attr, - &dev_attr_bc_trig_val_hi.attr, - &dev_attr_bc_enable_ganging.attr, - &dev_attr_bc_overflow_val.attr, - &dev_attr_bc_ovsr.attr, - &dev_attr_bc_counter_sel.attr, - &dev_attr_bc_count_val_lo.attr, - &dev_attr_bc_count_val_hi.attr, - &dev_attr_bc_shadow_val_lo.attr, - &dev_attr_bc_shadow_val_hi.attr, - &dev_attr_bc_sw_inc.attr, - &dev_attr_bc_msr.attr, - NULL, -}; +static ssize_t tc_capture_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); -static struct attribute_group tpdm_bc_attr_grp = { - .attrs = tpdm_bc_attrs, -}; + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; -static struct attribute *tpdm_attrs[] = { - &dev_attr_available_datasets.attr, - &dev_attr_enable_datasets.attr, - &dev_attr_reset.attr, - &dev_attr_integration_test.attr, - &dev_attr_gp_regs.attr, - NULL, -}; + return scnprintf(buf, PAGE_SIZE, "%s\n", + drvdata->tc->capture_mode == TPDM_MODE_ATB ? + "ATB" : "APB"); +} + +static ssize_t tc_capture_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + char str[20] = ""; + uint32_t val; + + if (size >= 20) + return -EINVAL; + if (sscanf(buf, "%s", str) != 1) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (!strcmp(str, "ATB")) { + drvdata->tc->capture_mode = TPDM_MODE_ATB; + } else if (!strcmp(str, "APB") && + drvdata->tc->retrieval_mode == TPDM_MODE_APB) { + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_TC_CR); + val = val | BIT(3); + tpdm_writel(drvdata, val, TPDM_TC_CR); + TPDM_LOCK(drvdata); + + drvdata->tc->capture_mode = TPDM_MODE_APB; + } else { + mutex_unlock(&drvdata->lock); + return -EINVAL; + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_capture_mode); + +static ssize_t tc_retrieval_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%s\n", + drvdata->tc->retrieval_mode == TPDM_MODE_ATB ? + "ATB" : "APB"); +} + +static ssize_t tc_retrieval_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + char str[20] = ""; + + if (size >= 20) + return -EINVAL; + if (sscanf(buf, "%s", str) != 1) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (!strcmp(str, "ATB")) { + drvdata->tc->retrieval_mode = TPDM_MODE_ATB; + } else if (!strcmp(str, "APB")) { + drvdata->tc->retrieval_mode = TPDM_MODE_APB; + } else { + mutex_unlock(&drvdata->lock); + return -EINVAL; + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_retrieval_mode); + +static ssize_t tc_reset_counters_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_TC_CR); + val = val | BIT(1); + tpdm_writel(drvdata, val, TPDM_TC_CR); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_WO(tc_reset_counters); + +static ssize_t tc_sat_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->tc->sat_mode); +} + +static ssize_t tc_sat_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->tc->sat_mode = true; + else + drvdata->tc->sat_mode = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_sat_mode); + +static ssize_t tc_enable_counters_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->tc->enable_counters); +} + +static ssize_t tc_enable_counters_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + if (val >> drvdata->tc_counters_avail) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->tc->enable_counters = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_enable_counters); + +static ssize_t tc_clear_counters_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->tc->clear_counters); +} + +static ssize_t tc_clear_counters_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + if (val >> drvdata->tc_counters_avail) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->tc->clear_counters = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_clear_counters); + +static ssize_t tc_enable_irq_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->tc->enable_irq); +} + +static ssize_t tc_enable_irq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->tc->enable_irq = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_enable_irq); + +static ssize_t tc_clear_irq_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->tc->clear_irq); +} + +static ssize_t tc_clear_irq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->tc->clear_irq = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_clear_irq); + +static ssize_t tc_trig_sel_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_TC_MAX_TRIG; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->tc->trig_sel[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t tc_trig_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets) || + index >= TPDM_TC_MAX_TRIG || + drvdata->tc_trig_type == TPDM_SUPPORT_TYPE_NO || + (drvdata->tc_trig_type == TPDM_SUPPORT_TYPE_PARTIAL && index > 0)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->tc->trig_sel[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_trig_sel); + +static ssize_t tc_trig_val_lo_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_TC_MAX_TRIG; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->tc->trig_val_lo[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t tc_trig_val_lo_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets) || + index >= TPDM_TC_MAX_TRIG || + drvdata->tc_trig_type == TPDM_SUPPORT_TYPE_NO || + (drvdata->tc_trig_type == TPDM_SUPPORT_TYPE_PARTIAL && index > 0)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->tc->trig_val_lo[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_trig_val_lo); + +static ssize_t tc_trig_val_hi_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_TC_MAX_TRIG; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->tc->trig_val_hi[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t tc_trig_val_hi_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->datasets) || + index >= TPDM_TC_MAX_TRIG || + drvdata->tc_trig_type == TPDM_SUPPORT_TYPE_NO || + (drvdata->tc_trig_type == TPDM_SUPPORT_TYPE_PARTIAL && index > 0)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->tc->trig_val_hi[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_trig_val_hi); + +static ssize_t tc_ovsr_gp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_TC_OVSR_GP); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t tc_ovsr_gp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_TC_OVSR_GP); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_ovsr_gp); + +static ssize_t tc_ovsr_impl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_TC_OVSR_IMPL); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t tc_ovsr_impl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_TC_OVSR_IMPL); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_ovsr_impl); + +static ssize_t tc_counter_sel_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_TC_SELR); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t tc_counter_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_TC_SELR); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_counter_sel); + +static ssize_t tc_count_val_lo_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_TC_CNTR_LO); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t tc_count_val_lo_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val, select; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + select = tpdm_readl(drvdata, TPDM_TC_SELR); + select = (select >> 11) & 0x3; + + /* Check if selected counter is disabled */ + if (BMVAL(tpdm_readl(drvdata, TPDM_TC_CNTENSET), select, select)) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + tpdm_writel(drvdata, val, TPDM_TC_CNTR_LO); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_count_val_lo); + +static ssize_t tc_count_val_hi_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_TC_CNTR_HI); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t tc_count_val_hi_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val, select; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + select = tpdm_readl(drvdata, TPDM_TC_SELR); + select = (select >> 11) & 0x3; + + /* Check if selected counter is disabled */ + if (BMVAL(tpdm_readl(drvdata, TPDM_TC_CNTENSET), select, select)) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + tpdm_writel(drvdata, val, TPDM_TC_CNTR_HI); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_count_val_hi); + +static ssize_t tc_shadow_val_lo_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + for (i = 0; i < TPDM_TC_MAX_COUNTERS; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + tpdm_readl(drvdata, TPDM_TC_SHADOW_LO(i))); + } + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RO(tc_shadow_val_lo); + +static ssize_t tc_shadow_val_hi_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + for (i = 0; i < TPDM_TC_MAX_COUNTERS; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + tpdm_readl(drvdata, TPDM_TC_SHADOW_HI(i))); + } + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RO(tc_shadow_val_hi); + +static ssize_t tc_sw_inc_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_TC_SWINC); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t tc_sw_inc_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_TC, drvdata->enable_ds)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_TC_SWINC); + TPDM_LOCK(drvdata); + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_sw_inc); + +static ssize_t tc_msr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int i; + ssize_t len = 0; + + if (!drvdata->msr_support) + return -EINVAL; + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + for (i = 0; i < TPDM_TC_MAX_MSR; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u 0x%x\n", + i, drvdata->tc->msr[i]); + + return len; +} + +static ssize_t tc_msr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int num, val; + int nval; + + if (!drvdata->msr_support) + return -EINVAL; + + if (!test_bit(TPDM_DS_TC, drvdata->datasets)) + return -EPERM; + + nval = sscanf(buf, "%u %x", &num, &val); + if (nval != 2) + return -EINVAL; + + if (num >= TPDM_TC_MAX_MSR) + return -EINVAL; + + mutex_lock(&drvdata->lock); + drvdata->tc->msr[num] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(tc_msr); + +static struct attribute *tpdm_bc_attrs[] = { + &dev_attr_bc_capture_mode.attr, + &dev_attr_bc_retrieval_mode.attr, + &dev_attr_bc_reset_counters.attr, + &dev_attr_bc_sat_mode.attr, + &dev_attr_bc_enable_counters.attr, + &dev_attr_bc_clear_counters.attr, + &dev_attr_bc_enable_irq.attr, + &dev_attr_bc_clear_irq.attr, + &dev_attr_bc_trig_val_lo.attr, + &dev_attr_bc_trig_val_hi.attr, + &dev_attr_bc_enable_ganging.attr, + &dev_attr_bc_overflow_val.attr, + &dev_attr_bc_ovsr.attr, + &dev_attr_bc_counter_sel.attr, + &dev_attr_bc_count_val_lo.attr, + &dev_attr_bc_count_val_hi.attr, + &dev_attr_bc_shadow_val_lo.attr, + &dev_attr_bc_shadow_val_hi.attr, + &dev_attr_bc_sw_inc.attr, + &dev_attr_bc_msr.attr, + NULL, +}; + +static struct attribute *tpdm_tc_attrs[] = { + &dev_attr_tc_capture_mode.attr, + &dev_attr_tc_retrieval_mode.attr, + &dev_attr_tc_reset_counters.attr, + &dev_attr_tc_sat_mode.attr, + &dev_attr_tc_enable_counters.attr, + &dev_attr_tc_clear_counters.attr, + &dev_attr_tc_enable_irq.attr, + &dev_attr_tc_clear_irq.attr, + &dev_attr_tc_trig_sel.attr, + &dev_attr_tc_trig_val_lo.attr, + &dev_attr_tc_trig_val_hi.attr, + &dev_attr_tc_ovsr_gp.attr, + &dev_attr_tc_ovsr_impl.attr, + &dev_attr_tc_counter_sel.attr, + &dev_attr_tc_count_val_lo.attr, + &dev_attr_tc_count_val_hi.attr, + &dev_attr_tc_shadow_val_lo.attr, + &dev_attr_tc_shadow_val_hi.attr, + &dev_attr_tc_sw_inc.attr, + &dev_attr_tc_msr.attr, + NULL, +}; + +static struct attribute_group tpdm_bc_attr_grp = { + .attrs = tpdm_bc_attrs, +}; + +static struct attribute_group tpdm_tc_attr_grp = { + .attrs = tpdm_tc_attrs, +}; + +static struct attribute *tpdm_attrs[] = { + &dev_attr_available_datasets.attr, + &dev_attr_enable_datasets.attr, + &dev_attr_reset.attr, + &dev_attr_integration_test.attr, + &dev_attr_gp_regs.attr, + NULL, +}; + +static struct attribute_group tpdm_attr_grp = { + .attrs = tpdm_attrs, +}; -static struct attribute_group tpdm_attr_grp = { - .attrs = tpdm_attrs, -}; static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_attr_grp, &tpdm_bc_attr_grp, + &tpdm_tc_attr_grp, NULL, }; From patchwork Thu Oct 21 07:38:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574269 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D17E0C433F5 for ; Thu, 21 Oct 2021 07:43:39 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 A1A1A6112D for ; Thu, 21 Oct 2021 07:43:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org A1A1A6112D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=lS5DA1xAojuvwu9zToWy5uj6W9inFG5AFrP08P72Y6c=; b=CGGTA2gxH83FC5 FK65Knouj0cYODFsMZMmSFm15h1buUp70GjtzFv02ShyiBhTGPezQ9RaDp/4YTl4++zjBuPt01VZK LySx76A7cpcDzCM5RX0UcVzK+z0sl3eqCcxII1nrri90+K3i81c/3Rjf77Nk2VOY70n4ih1lFG2vp 2mJADAWLwO9ZKsXupVCEAKEcG5kmywTXU2hVUFuvixLp+5zakgZKG10Eg+HeGPSX2+31PD6jfOa3X 3SQ5mLEGWsLe8/PhZoGCySMPaCgNn4a9bsWGC16J4Z97R5rXlNbTaSi6MhOWxH/98XPCsAj3zmvEt bvrw5MDSRd6I3OvL8pyQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSiD-006i7F-9y; Thu, 21 Oct 2021 07:42:05 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSgE-006gy6-Am for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:40:06 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634802002; x=1666338002; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=fGltqvKqGu4UMrUXclGB4ik6xX8IF8Fhe3wtc6ntjaY=; b=JgBG7ECa89E0NQJGs0m+E+g1D8vvm51j2354c31NIT1S8j09CDAVO59S hsDORqiCx7ELxwNVM6rccfpghHTccIG9eqToNxVG5LPRo+R31XSl4B1D6 MfimZ3t2/iYF4cIhvHGDxEoyuE7Q2k2fL7OmuefF5ps2Bxa0bICTwYoFu 4=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:40:02 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:40:02 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:39:58 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni Subject: [PATCH 07/10] Coresight: Enable DSB subunit for TPDM Date: Thu, 21 Oct 2021 15:38:53 +0800 Message-ID: <1634801936-15080-8-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_004002_574706_A4758E37 X-CRM114-Status: GOOD ( 16.93 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Enable Discrete Single Bit(DSB) subunit for TPDM. The DSB dataset elements flow out ATB while the BC/TC dataset elements are sent only on ATB flush requests from the TPDA. The DSB data set subunit is responsible for collection of DSB data sets. The width of the DSB subunit interface must be between 8 and 256 bits. A monitor may support either a 32 or 64 bit DSB data set element size (e.g. via a hardware parameter). Signed-off-by: Tao Zhang --- drivers/hwtracing/coresight/coresight-tpdm.c | 680 +++++++++++++++++++ 1 file changed, 680 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 635382be5de6..5f07363e4650 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -309,6 +309,17 @@ static void __tpdm_config_tc_msr(struct tpdm_drvdata *drvdata) tpdm_writel(drvdata, drvdata->tc->msr[i], TPDM_TC_MSR(i)); } +static void __tpdm_config_dsb_msr(struct tpdm_drvdata *drvdata) +{ + int i; + + if (!drvdata->msr_support) + return; + + for (i = 0; i < TPDM_DSB_MAX_MSR; i++) + tpdm_writel(drvdata, drvdata->dsb->msr[i], TPDM_DSB_MSR(i)); +} + static void __tpdm_enable_bc(struct tpdm_drvdata *drvdata) { int i; @@ -434,6 +445,86 @@ static void __tpdm_enable_tc(struct tpdm_drvdata *drvdata) tpdm_writel(drvdata, val, TPDM_TC_CR); } +static void __tpdm_enable_dsb(struct tpdm_drvdata *drvdata) +{ + uint32_t val, mode, i; + + for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) + tpdm_writel(drvdata, drvdata->dsb->edge_ctrl[i], + TPDM_DSB_EDCR(i)); + for (i = 0; i < TPDM_DSB_MAX_EDCR / 2; i++) + tpdm_writel(drvdata, drvdata->dsb->edge_ctrl_mask[i], + TPDM_DSB_EDCMR(i)); + + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + tpdm_writel(drvdata, drvdata->dsb->patt_val[i], + TPDM_DSB_TPR(i)); + tpdm_writel(drvdata, drvdata->dsb->patt_mask[i], + TPDM_DSB_TPMR(i)); + } + + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + tpdm_writel(drvdata, drvdata->dsb->trig_patt_val[i], + TPDM_DSB_XPR(i)); + tpdm_writel(drvdata, drvdata->dsb->trig_patt_mask[i], + TPDM_DSB_XPMR(i)); + } + + for (i = 0; i < TPDM_DSB_MAX_SELECT; i++) + tpdm_writel(drvdata, drvdata->dsb->select_val[i], + TPDM_DSB_CA_SELECT(i)); + + val = tpdm_readl(drvdata, TPDM_DSB_TIER); + if (drvdata->dsb->patt_ts) { + val = val | BIT(0); + if (drvdata->dsb->patt_type) + val = val | BIT(2); + else + val = val & ~BIT(2); + } else { + val = val & ~BIT(0); + } + if (drvdata->dsb->trig_ts) + val = val | BIT(1); + else + val = val & ~BIT(1); + tpdm_writel(drvdata, val, TPDM_DSB_TIER); + + if (!drvdata->msr_fix_req) + __tpdm_config_dsb_msr(drvdata); + + val = tpdm_readl(drvdata, TPDM_DSB_CR); + /* Set the cycle accurate mode */ + mode = TPDM_DSB_MODE_CYCACC(drvdata->dsb->mode); + val = val & ~(0x7 << 9); + val = val | (mode << 9); + /* Set the byte lane for high-performance mode */ + mode = TPDM_DSB_MODE_HPBYTESEL(drvdata->dsb->mode); + val = val & ~(0x1F << 2); + val = val | (mode << 2); + /* Set the performance mode */ + if (drvdata->dsb->mode & TPDM_DSB_MODE_PERF) + val = val | BIT(1); + else + val = val & ~BIT(1); + + /* Set trigger type */ + if (drvdata->dsb->trig_type) + val = val | BIT(12); + else + val = val & ~BIT(12); + + tpdm_writel(drvdata, val, TPDM_DSB_CR); + + val = tpdm_readl(drvdata, TPDM_DSB_CR); + /* Set the enable bit */ + val = val | BIT(0); + tpdm_writel(drvdata, val, TPDM_DSB_CR); + + if (drvdata->msr_fix_req) + __tpdm_config_dsb_msr(drvdata); +} + static void __tpdm_enable(struct tpdm_drvdata *drvdata) { TPDM_UNLOCK(drvdata); @@ -450,6 +541,9 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) if (test_bit(TPDM_DS_TC, drvdata->enable_ds)) __tpdm_enable_tc(drvdata); + if (test_bit(TPDM_DS_DSB, drvdata->enable_ds)) + __tpdm_enable_dsb(drvdata); + TPDM_LOCK(drvdata); } @@ -492,6 +586,15 @@ static void __tpdm_disable_tc(struct tpdm_drvdata *drvdata) tpdm_writel(drvdata, config, TPDM_TC_CR); } +static void __tpdm_disable_dsb(struct tpdm_drvdata *drvdata) +{ + uint32_t config; + + config = tpdm_readl(drvdata, TPDM_DSB_CR); + config = config & ~BIT(0); + tpdm_writel(drvdata, config, TPDM_DSB_CR); +} + static void __tpdm_disable(struct tpdm_drvdata *drvdata) { TPDM_UNLOCK(drvdata); @@ -502,6 +605,9 @@ static void __tpdm_disable(struct tpdm_drvdata *drvdata) if (test_bit(TPDM_DS_TC, drvdata->enable_ds)) __tpdm_disable_tc(drvdata); + if (test_bit(TPDM_DS_DSB, drvdata->enable_ds)) + __tpdm_disable_dsb(drvdata); + if (drvdata->clk_enable) tpdm_writel(drvdata, 0x0, TPDM_CLK_CTRL); @@ -2474,6 +2580,558 @@ static ssize_t tc_msr_store(struct device *dev, } static DEVICE_ATTR_RW(tc_msr); +static ssize_t dsb_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%lx\n", + (unsigned long)drvdata->dsb->mode); +} + +static ssize_t dsb_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->dsb->mode = val & TPDM_MODE_ALL; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_mode); + +static ssize_t dsb_edge_ctrl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index:0x%x Val:0x%x\n", i, + drvdata->dsb->edge_ctrl[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t dsb_edge_ctrl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long start, end, edge_ctrl; + uint32_t val; + int i, bit, reg; + + if (sscanf(buf, "%lx %lx %lx", &start, &end, &edge_ctrl) != 3) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets) || + (start >= TPDM_DSB_MAX_LINES) || (end >= TPDM_DSB_MAX_LINES) || + edge_ctrl > 0x2) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = start; i <= end; i++) { + reg = i / (NUM_OF_BITS / 2); + bit = i % (NUM_OF_BITS / 2); + bit = bit * 2; + + val = drvdata->dsb->edge_ctrl[reg]; + val = val & ~GENMASK((bit + 1), bit); + val = val | (edge_ctrl << bit); + drvdata->dsb->edge_ctrl[reg] = val; + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_edge_ctrl); + +static ssize_t dsb_edge_ctrl_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_DSB_MAX_EDCR / 2; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index:0x%x Val:0x%x\n", i, + drvdata->dsb->edge_ctrl_mask[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t dsb_edge_ctrl_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long start, end, val; + uint32_t set; + int i, bit, reg; + + if (sscanf(buf, "%lx %lx %lx", &start, &end, &val) != 3) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets) || + (start >= TPDM_DSB_MAX_LINES) || (end >= TPDM_DSB_MAX_LINES)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = start; i <= end; i++) { + reg = i / NUM_OF_BITS; + bit = (i % NUM_OF_BITS); + + set = drvdata->dsb->edge_ctrl_mask[reg]; + if (val) + set = set | BIT(bit); + else + set = set & ~BIT(bit); + drvdata->dsb->edge_ctrl_mask[reg] = set; + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_edge_ctrl_mask); + +static ssize_t dsb_patt_val_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->dsb->patt_val[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t dsb_patt_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets) || + index >= TPDM_DSB_MAX_PATT) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->dsb->patt_val[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_patt_val); + +static ssize_t dsb_patt_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->dsb->patt_mask[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t dsb_patt_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets) || + index >= TPDM_DSB_MAX_PATT) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->dsb->patt_mask[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_patt_mask); + +static ssize_t dsb_patt_ts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->dsb->patt_ts); +} + +static ssize_t dsb_patt_ts_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->dsb->patt_ts = true; + else + drvdata->dsb->patt_ts = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_patt_ts); + +static ssize_t dsb_patt_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->dsb->patt_type); +} + +static ssize_t dsb_patt_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->dsb->patt_type = true; + else + drvdata->dsb->patt_type = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_patt_type); + +static ssize_t dsb_trig_patt_val_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->dsb->trig_patt_val[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t dsb_trig_patt_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets) || + index >= TPDM_DSB_MAX_PATT) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->dsb->trig_patt_val[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_trig_patt_val); + +static ssize_t dsb_trig_patt_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i = 0; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->dsb->trig_patt_mask[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t dsb_trig_patt_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets) || + index >= TPDM_DSB_MAX_PATT) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->dsb->trig_patt_mask[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_trig_patt_mask); + +static ssize_t dsb_trig_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->dsb->trig_type); +} + +static ssize_t dsb_trig_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->dsb->trig_type = true; + else + drvdata->dsb->trig_type = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_trig_type); + +static ssize_t dsb_trig_ts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->dsb->trig_ts); +} + +static ssize_t dsb_trig_ts_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->dsb->trig_ts = true; + else + drvdata->dsb->trig_ts = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_trig_ts); + +static ssize_t dsb_select_val_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_DSB_MAX_SELECT; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index:0x%x Val:0x%x\n", i, + drvdata->dsb->select_val[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t dsb_select_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long start, end; + uint32_t val; + int i, bit, reg; + + if (sscanf(buf, "%lx %lx", &start, &end) != 2) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets) || + (start >= TPDM_DSB_MAX_LINES) || (end >= TPDM_DSB_MAX_LINES)) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = start; i <= end; i++) { + reg = i / NUM_OF_BITS; + bit = (i % NUM_OF_BITS); + + val = drvdata->dsb->select_val[reg]; + val = val | BIT(bit); + drvdata->dsb->select_val[reg] = val; + } + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_select_val); + +static ssize_t dsb_msr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int i; + ssize_t len = 0; + + if (!drvdata->msr_support) + return -EINVAL; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + for (i = 0; i < TPDM_DSB_MAX_MSR; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u 0x%x\n", + i, drvdata->dsb->msr[i]); + + return len; +} + +static ssize_t dsb_msr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int num, val; + int nval; + + if (!drvdata->msr_support) + return -EINVAL; + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + nval = sscanf(buf, "%u %x", &num, &val); + if (nval != 2) + return -EINVAL; + + if (num >= TPDM_DSB_MAX_MSR) + return -EINVAL; + + mutex_lock(&drvdata->lock); + drvdata->dsb->msr[num] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(dsb_msr); + static struct attribute *tpdm_bc_attrs[] = { &dev_attr_bc_capture_mode.attr, &dev_attr_bc_retrieval_mode.attr, @@ -2522,6 +3180,23 @@ static struct attribute *tpdm_tc_attrs[] = { NULL, }; +static struct attribute *tpdm_dsb_attrs[] = { + &dev_attr_dsb_mode.attr, + &dev_attr_dsb_edge_ctrl.attr, + &dev_attr_dsb_edge_ctrl_mask.attr, + &dev_attr_dsb_patt_val.attr, + &dev_attr_dsb_patt_mask.attr, + &dev_attr_dsb_patt_ts.attr, + &dev_attr_dsb_patt_type.attr, + &dev_attr_dsb_trig_patt_val.attr, + &dev_attr_dsb_trig_patt_mask.attr, + &dev_attr_dsb_trig_ts.attr, + &dev_attr_dsb_trig_type.attr, + &dev_attr_dsb_select_val.attr, + &dev_attr_dsb_msr.attr, + NULL, +}; + static struct attribute_group tpdm_bc_attr_grp = { .attrs = tpdm_bc_attrs, }; @@ -2530,6 +3205,10 @@ static struct attribute_group tpdm_tc_attr_grp = { .attrs = tpdm_tc_attrs, }; +static struct attribute_group tpdm_dsb_attr_grp = { + .attrs = tpdm_dsb_attrs, +}; + static struct attribute *tpdm_attrs[] = { &dev_attr_available_datasets.attr, &dev_attr_enable_datasets.attr, @@ -2547,6 +3226,7 @@ static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_attr_grp, &tpdm_bc_attr_grp, &tpdm_tc_attr_grp, + &tpdm_dsb_attr_grp, NULL, }; From patchwork Thu Oct 21 07:38:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574271 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 40F44C433F5 for ; Thu, 21 Oct 2021 07:44:16 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 02BF9610EA for ; Thu, 21 Oct 2021 07:44:15 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 02BF9610EA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=SwDFGKRUkM0uWpqwNpITITLOiUFR8CTZGP7dn7AJv0M=; b=Ii9s2D1HO5XGBR rDL7r5cL1fKIMuMzZC8tdNb5yEnPvz7qEJQ+cGN3DuxUNsWUDyc41z4/xiq2UwRko5NysMIW44/8Y Mvr6ZACWhcZfr/2IolxcLPmyjso8VVVAwWAcOnG5472586hHkcTM2NvIJZXLzzpYr8sIV4bJPBbWB 7N1U5A7M4LJonHFL5q3/BFdeAzFUSRRhY2RQLoGV17XUB57ZTw8eu+ofYoGZ3Z42Wbe3eqUXFTCOo Ps9OM5BXGZz/2kpiZWVPqZh8WCONzvdSeTATU2ilIqk1urwYOv7cTrI+FUGLFoIlOEgLYVNBAcjeW XWKXejv4b4x6zQ3UXQDw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSic-006iOk-Sp; Thu, 21 Oct 2021 07:42:31 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSgI-006h1r-AF for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:40:10 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634802006; x=1666338006; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=1ZZXbQ+FWiwA09Fn9nqRYPRoqHEHvoOpaFwGxLMJ7nY=; b=knaB5FQUOaYBM3dMx8ML8OeDQPP2m0sb86Ws6fFjSs8v3WM0uhojwm4l L1vyHBvGSsWyZ95KzdOqXc80KGqQgCico2ZwHt/dBVSoJIuSPA8kjQxDm zbb+bRFnHP2m+4Nsl6BReYaMMfBcbTtarAKyM0n7y79O04ugUU3Y11OLR o=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:40:05 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:40:06 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:40:02 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni Subject: [PATCH 08/10] Coresight: Enable CMB subunit for TPDM Date: Thu, 21 Oct 2021 15:38:54 +0800 Message-ID: <1634801936-15080-9-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_004006_599654_C5E3D96E X-CRM114-Status: GOOD ( 16.68 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Enable CMB subunit for TPDM. The CMB dataset elements flow out ATB while the BC/TC dataset elements are sent only on ATB flush requests from the TPDA. The CMB data set subunit is responsible for collection of CMB data sets. The CMB subunit data set interface must be a legal ATB width less than or equal to 64 bits. Signed-off-by: Tao Zhang --- drivers/hwtracing/coresight/coresight-tpdm.c | 931 +++++++++++++++++-- 1 file changed, 861 insertions(+), 70 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 5f07363e4650..3e7f5b48150b 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -320,6 +320,17 @@ static void __tpdm_config_dsb_msr(struct tpdm_drvdata *drvdata) tpdm_writel(drvdata, drvdata->dsb->msr[i], TPDM_DSB_MSR(i)); } +static void __tpdm_config_cmb_msr(struct tpdm_drvdata *drvdata) +{ + int i; + + if (!drvdata->msr_support) + return; + + for (i = 0; i < TPDM_CMB_MAX_MSR; i++) + tpdm_writel(drvdata, drvdata->cmb->msr[i], TPDM_CMB_MSR(i)); +} + static void __tpdm_enable_bc(struct tpdm_drvdata *drvdata) { int i; @@ -525,6 +536,112 @@ static void __tpdm_enable_dsb(struct tpdm_drvdata *drvdata) __tpdm_config_dsb_msr(drvdata); } +static void __tpdm_enable_cmb(struct tpdm_drvdata *drvdata) +{ + uint32_t val; + int i; + + for (i = 0; i < TPDM_CMB_PATT_CMP; i++) { + tpdm_writel(drvdata, drvdata->cmb->patt_val[i], + TPDM_CMB_TPR(i)); + tpdm_writel(drvdata, drvdata->cmb->patt_mask[i], + TPDM_CMB_TPMR(i)); + tpdm_writel(drvdata, drvdata->cmb->trig_patt_val[i], + TPDM_CMB_XPR(i)); + tpdm_writel(drvdata, drvdata->cmb->trig_patt_mask[i], + TPDM_CMB_XPMR(i)); + } + + val = tpdm_readl(drvdata, TPDM_CMB_TIER); + if (drvdata->cmb->patt_ts) + val = val | BIT(0); + else + val = val & ~BIT(0); + if (drvdata->cmb->trig_ts) + val = val | BIT(1); + else + val = val & ~BIT(1); + if (drvdata->cmb->ts_all) + val = val | BIT(2); + else + val = val & ~BIT(2); + + tpdm_writel(drvdata, val, TPDM_CMB_TIER); + + if (!drvdata->cmb_msr_skip) + __tpdm_config_cmb_msr(drvdata); + + val = tpdm_readl(drvdata, TPDM_CMB_CR); + /* Set the flow control bit */ + val = val & ~BIT(2); + if (drvdata->cmb->trace_mode) + val = val | BIT(1); + else + val = val & ~BIT(1); + + val = val & ~GENMASK(9, 8); + val = val | BMVAL(drvdata->cmb->cycle_acc, 0, 1) << 8; + tpdm_writel(drvdata, val, TPDM_CMB_CR); + /* Set the enable bit */ + val = val | BIT(0); + tpdm_writel(drvdata, val, TPDM_CMB_CR); +} + +static void __tpdm_enable_mcmb(struct tpdm_drvdata *drvdata) +{ + uint32_t val; + struct mcmb_dataset *mcmb = drvdata->cmb->mcmb; + int i; + + for (i = 0; i < TPDM_CMB_PATT_CMP; i++) { + tpdm_writel(drvdata, drvdata->cmb->patt_val[i], + TPDM_CMB_TPR(i)); + tpdm_writel(drvdata, drvdata->cmb->patt_mask[i], + TPDM_CMB_TPMR(i)); + tpdm_writel(drvdata, drvdata->cmb->trig_patt_val[i], + TPDM_CMB_XPR(i)); + tpdm_writel(drvdata, drvdata->cmb->trig_patt_mask[i], + TPDM_CMB_XPMR(i)); + } + + val = tpdm_readl(drvdata, TPDM_CMB_TIER); + if (drvdata->cmb->patt_ts) + val = val | BIT(0); + else + val = val & ~BIT(0); + if (drvdata->cmb->trig_ts) + val = val | BIT(1); + else + val = val & ~BIT(1); + if (drvdata->cmb->ts_all) + val = val | BIT(2); + else + val = val & ~BIT(2); + tpdm_writel(drvdata, val, TPDM_CMB_TIER); + + __tpdm_config_cmb_msr(drvdata); + + val = tpdm_readl(drvdata, TPDM_CMB_CR); + /* Set the flow control bit */ + val = val & ~BIT(2); + if (drvdata->cmb->trace_mode) + val = val | BIT(1); + else + val = val & ~BIT(1); + + val = val & ~GENMASK(9, 8); + val = val | BMVAL(drvdata->cmb->cycle_acc, 0, 1) << 8; + val = val & ~GENMASK(20, 18); + val = val | (BMVAL(mcmb->mcmb_trig_lane, 0, 2) << 18); + val = val & ~GENMASK(17, 10); + val = val | (BMVAL(mcmb->mcmb_lane_select, 0, 7) << 10); + + tpdm_writel(drvdata, val, TPDM_CMB_CR); + /* Set the enable bit */ + val = val | BIT(0); + tpdm_writel(drvdata, val, TPDM_CMB_CR); +} + static void __tpdm_enable(struct tpdm_drvdata *drvdata) { TPDM_UNLOCK(drvdata); @@ -544,6 +661,11 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) if (test_bit(TPDM_DS_DSB, drvdata->enable_ds)) __tpdm_enable_dsb(drvdata); + if (test_bit(TPDM_DS_CMB, drvdata->enable_ds)) + __tpdm_enable_cmb(drvdata); + else if (test_bit(TPDM_DS_MCMB, drvdata->enable_ds)) + __tpdm_enable_mcmb(drvdata); + TPDM_LOCK(drvdata); } @@ -595,6 +717,15 @@ static void __tpdm_disable_dsb(struct tpdm_drvdata *drvdata) tpdm_writel(drvdata, config, TPDM_DSB_CR); } +static void __tpdm_disable_cmb(struct tpdm_drvdata *drvdata) +{ + uint32_t config; + + config = tpdm_readl(drvdata, TPDM_CMB_CR); + config = config & ~BIT(0); + tpdm_writel(drvdata, config, TPDM_CMB_CR); +} + static void __tpdm_disable(struct tpdm_drvdata *drvdata) { TPDM_UNLOCK(drvdata); @@ -608,6 +739,10 @@ static void __tpdm_disable(struct tpdm_drvdata *drvdata) if (test_bit(TPDM_DS_DSB, drvdata->enable_ds)) __tpdm_disable_dsb(drvdata); + if (test_bit(TPDM_DS_CMB, drvdata->enable_ds) || + test_bit(TPDM_DS_MCMB, drvdata->enable_ds)) + __tpdm_disable_cmb(drvdata); + if (drvdata->clk_enable) tpdm_writel(drvdata, 0x0, TPDM_CLK_CTRL); @@ -3132,81 +3267,736 @@ static ssize_t dsb_msr_store(struct device *dev, } static DEVICE_ATTR_RW(dsb_msr); -static struct attribute *tpdm_bc_attrs[] = { - &dev_attr_bc_capture_mode.attr, - &dev_attr_bc_retrieval_mode.attr, - &dev_attr_bc_reset_counters.attr, - &dev_attr_bc_sat_mode.attr, - &dev_attr_bc_enable_counters.attr, - &dev_attr_bc_clear_counters.attr, - &dev_attr_bc_enable_irq.attr, - &dev_attr_bc_clear_irq.attr, - &dev_attr_bc_trig_val_lo.attr, - &dev_attr_bc_trig_val_hi.attr, - &dev_attr_bc_enable_ganging.attr, - &dev_attr_bc_overflow_val.attr, - &dev_attr_bc_ovsr.attr, - &dev_attr_bc_counter_sel.attr, - &dev_attr_bc_count_val_lo.attr, - &dev_attr_bc_count_val_hi.attr, - &dev_attr_bc_shadow_val_lo.attr, - &dev_attr_bc_shadow_val_hi.attr, - &dev_attr_bc_sw_inc.attr, - &dev_attr_bc_msr.attr, - NULL, -}; +static ssize_t cmb_available_modes_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", "continuous trace_on_change"); +} +static DEVICE_ATTR_RO(cmb_available_modes); -static struct attribute *tpdm_tc_attrs[] = { - &dev_attr_tc_capture_mode.attr, - &dev_attr_tc_retrieval_mode.attr, - &dev_attr_tc_reset_counters.attr, - &dev_attr_tc_sat_mode.attr, - &dev_attr_tc_enable_counters.attr, - &dev_attr_tc_clear_counters.attr, - &dev_attr_tc_enable_irq.attr, - &dev_attr_tc_clear_irq.attr, - &dev_attr_tc_trig_sel.attr, - &dev_attr_tc_trig_val_lo.attr, - &dev_attr_tc_trig_val_hi.attr, - &dev_attr_tc_ovsr_gp.attr, - &dev_attr_tc_ovsr_impl.attr, - &dev_attr_tc_counter_sel.attr, - &dev_attr_tc_count_val_lo.attr, - &dev_attr_tc_count_val_hi.attr, - &dev_attr_tc_shadow_val_lo.attr, - &dev_attr_tc_shadow_val_hi.attr, - &dev_attr_tc_sw_inc.attr, - &dev_attr_tc_msr.attr, - NULL, -}; +static ssize_t cmb_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); -static struct attribute *tpdm_dsb_attrs[] = { - &dev_attr_dsb_mode.attr, - &dev_attr_dsb_edge_ctrl.attr, - &dev_attr_dsb_edge_ctrl_mask.attr, - &dev_attr_dsb_patt_val.attr, - &dev_attr_dsb_patt_mask.attr, - &dev_attr_dsb_patt_ts.attr, - &dev_attr_dsb_patt_type.attr, - &dev_attr_dsb_trig_patt_val.attr, - &dev_attr_dsb_trig_patt_mask.attr, - &dev_attr_dsb_trig_ts.attr, - &dev_attr_dsb_trig_type.attr, - &dev_attr_dsb_select_val.attr, - &dev_attr_dsb_msr.attr, - NULL, -}; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; -static struct attribute_group tpdm_bc_attr_grp = { - .attrs = tpdm_bc_attrs, -}; + return scnprintf(buf, PAGE_SIZE, "trace_mode: %s cycle_acc: %d\n", + drvdata->cmb->trace_mode ? + "trace_on_change" : "continuous", + drvdata->cmb->cycle_acc); +} -static struct attribute_group tpdm_tc_attr_grp = { - .attrs = tpdm_tc_attrs, -}; +static ssize_t cmb_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int trace_mode, cycle_acc; + int nval; -static struct attribute_group tpdm_dsb_attr_grp = { - .attrs = tpdm_dsb_attrs, + nval = sscanf(buf, "%u %u", &trace_mode, &cycle_acc); + if (nval != 2) + return -EINVAL; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->cmb->trace_mode = trace_mode; + drvdata->cmb->cycle_acc = cycle_acc; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_mode); + +static ssize_t cmb_patt_val_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_CMB_PATT_CMP; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->cmb->patt_val[i]); + } + mutex_unlock(&drvdata->lock); + return size; +} + +static ssize_t cmb_patt_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (index >= TPDM_CMB_PATT_CMP) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->cmb->patt_val[index] = val; + mutex_unlock(&drvdata->lock); + + return size; +} +static DEVICE_ATTR_RW(cmb_patt_val); + +static ssize_t cmb_patt_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + ssize_t size = 0; + int i; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + for (i = 0; i < TPDM_CMB_PATT_CMP; i++) { + size += scnprintf(buf + size, PAGE_SIZE - size, + "Index: 0x%x Value: 0x%x\n", i, + drvdata->cmb->patt_mask[i]); + } + mutex_unlock(&drvdata->lock); + return size; + +} + +static ssize_t cmb_patt_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long index, val; + + if (sscanf(buf, "%lx %lx", &index, &val) != 2) + return -EINVAL; + if (index >= TPDM_CMB_PATT_CMP) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->cmb->patt_mask[index] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_patt_mask); + +static ssize_t cmb_patt_ts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->cmb->patt_ts); +} + +static ssize_t cmb_patt_ts_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->cmb->patt_ts = true; + else + drvdata->cmb->patt_ts = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_patt_ts); + +static ssize_t cmb_ts_all_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->cmb->ts_all); +} + +static ssize_t cmb_ts_all_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->cmb->ts_all = true; + else + drvdata->cmb->ts_all = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_ts_all); + +static ssize_t cmb_trig_patt_val_lsb_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + val = drvdata->cmb->trig_patt_val[TPDM_CMB_LSB]; + + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); +} + +static ssize_t cmb_trig_patt_val_lsb_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->cmb->trig_patt_val[TPDM_CMB_LSB] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_trig_patt_val_lsb); + +static ssize_t cmb_trig_patt_mask_lsb_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + val = drvdata->cmb->trig_patt_mask[TPDM_CMB_LSB]; + + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); +} + +static ssize_t cmb_trig_patt_mask_lsb_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->cmb->trig_patt_mask[TPDM_CMB_LSB] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_trig_patt_mask_lsb); + +static ssize_t cmb_trig_patt_val_msb_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + val = drvdata->cmb->trig_patt_val[TPDM_CMB_MSB]; + + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); +} + +static ssize_t cmb_trig_patt_val_msb_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->cmb->trig_patt_val[TPDM_CMB_MSB] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_trig_patt_val_msb); + +static ssize_t cmb_trig_patt_mask_msb_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + val = drvdata->cmb->trig_patt_mask[TPDM_CMB_MSB]; + + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); +} + +static ssize_t cmb_trig_patt_mask_msb_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->cmb->trig_patt_mask[TPDM_CMB_MSB] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_trig_patt_mask_msb); + +static ssize_t cmb_trig_ts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->cmb->trig_ts); +} + +static ssize_t cmb_trig_ts_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->cmb->trig_ts = true; + else + drvdata->cmb->trig_ts = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_trig_ts); + +static ssize_t cmb_msr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int i; + ssize_t len = 0; + + if (!drvdata->msr_support) + return -EINVAL; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + for (i = 0; i < TPDM_CMB_MAX_MSR; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u 0x%x\n", + i, drvdata->cmb->msr[i]); + + return len; +} + +static ssize_t cmb_msr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned int num, val; + int nval; + + if (!drvdata->msr_support) + return -EINVAL; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + nval = sscanf(buf, "%u %x", &num, &val); + if (nval != 2) + return -EINVAL; + + if (num >= TPDM_CMB_MAX_MSR) + return -EINVAL; + + mutex_lock(&drvdata->lock); + drvdata->cmb->msr[num] = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmb_msr); + +static ssize_t cmb_read_interface_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_CMB_READVAL); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} +static DEVICE_ATTR_RO(cmb_read_interface_state); + +static ssize_t cmb_read_ctl_reg_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + TPDM_UNLOCK(drvdata); + val = tpdm_readl(drvdata, TPDM_CMB_READCTL); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + + if (test_bit(TPDM_DS_CMB, drvdata->datasets)) + return scnprintf(buf, PAGE_SIZE, "SEL: %lx\n", val); + else + return scnprintf(buf, PAGE_SIZE, "Lane %u SEL: %lx\n", + (unsigned int)BMVAL(val, 1, 3), val & 0x1); +} + +static ssize_t cmb_read_ctl_reg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_CMB_READCTL); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + + return size; +} +static DEVICE_ATTR_RW(cmb_read_ctl_reg); + +static ssize_t mcmb_trig_lane_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_MCMB, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->cmb->mcmb->mcmb_trig_lane); +} + +static ssize_t mcmb_trig_lane_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 10, &val)) + return -EINVAL; + if (val >= TPDM_MCMB_MAX_LANES) + return -EINVAL; + if (!test_bit(TPDM_DS_MCMB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + drvdata->cmb->mcmb->mcmb_trig_lane = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(mcmb_trig_lane); + +static ssize_t mcmb_lanes_select_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_MCMB, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->cmb->mcmb->mcmb_lane_select); +} + +static ssize_t mcmb_lanes_select_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_MCMB, drvdata->datasets)) + return -EPERM; + + val = BMVAL(val, 0, TPDM_MCMB_MAX_LANES - 1); + + mutex_lock(&drvdata->lock); + drvdata->cmb->mcmb->mcmb_lane_select = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(mcmb_lanes_select); + +static ssize_t cmb_markr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) || + test_bit(TPDM_DS_MCMB, drvdata->datasets))) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + TPDM_UNLOCK(drvdata); + tpdm_writel(drvdata, val, TPDM_CMB_MARKR); + TPDM_LOCK(drvdata); + mutex_unlock(&drvdata->lock); + + return size; +} +static DEVICE_ATTR_WO(cmb_markr); + +static struct attribute *tpdm_bc_attrs[] = { + &dev_attr_bc_capture_mode.attr, + &dev_attr_bc_retrieval_mode.attr, + &dev_attr_bc_reset_counters.attr, + &dev_attr_bc_sat_mode.attr, + &dev_attr_bc_enable_counters.attr, + &dev_attr_bc_clear_counters.attr, + &dev_attr_bc_enable_irq.attr, + &dev_attr_bc_clear_irq.attr, + &dev_attr_bc_trig_val_lo.attr, + &dev_attr_bc_trig_val_hi.attr, + &dev_attr_bc_enable_ganging.attr, + &dev_attr_bc_overflow_val.attr, + &dev_attr_bc_ovsr.attr, + &dev_attr_bc_counter_sel.attr, + &dev_attr_bc_count_val_lo.attr, + &dev_attr_bc_count_val_hi.attr, + &dev_attr_bc_shadow_val_lo.attr, + &dev_attr_bc_shadow_val_hi.attr, + &dev_attr_bc_sw_inc.attr, + &dev_attr_bc_msr.attr, + NULL, +}; + +static struct attribute *tpdm_tc_attrs[] = { + &dev_attr_tc_capture_mode.attr, + &dev_attr_tc_retrieval_mode.attr, + &dev_attr_tc_reset_counters.attr, + &dev_attr_tc_sat_mode.attr, + &dev_attr_tc_enable_counters.attr, + &dev_attr_tc_clear_counters.attr, + &dev_attr_tc_enable_irq.attr, + &dev_attr_tc_clear_irq.attr, + &dev_attr_tc_trig_sel.attr, + &dev_attr_tc_trig_val_lo.attr, + &dev_attr_tc_trig_val_hi.attr, + &dev_attr_tc_ovsr_gp.attr, + &dev_attr_tc_ovsr_impl.attr, + &dev_attr_tc_counter_sel.attr, + &dev_attr_tc_count_val_lo.attr, + &dev_attr_tc_count_val_hi.attr, + &dev_attr_tc_shadow_val_lo.attr, + &dev_attr_tc_shadow_val_hi.attr, + &dev_attr_tc_sw_inc.attr, + &dev_attr_tc_msr.attr, + NULL, +}; + +static struct attribute *tpdm_dsb_attrs[] = { + &dev_attr_dsb_mode.attr, + &dev_attr_dsb_edge_ctrl.attr, + &dev_attr_dsb_edge_ctrl_mask.attr, + &dev_attr_dsb_patt_val.attr, + &dev_attr_dsb_patt_mask.attr, + &dev_attr_dsb_patt_ts.attr, + &dev_attr_dsb_patt_type.attr, + &dev_attr_dsb_trig_patt_val.attr, + &dev_attr_dsb_trig_patt_mask.attr, + &dev_attr_dsb_trig_ts.attr, + &dev_attr_dsb_trig_type.attr, + &dev_attr_dsb_select_val.attr, + &dev_attr_dsb_msr.attr, + NULL, +}; + +static struct attribute *tpdm_cmb_attrs[] = { + &dev_attr_cmb_available_modes.attr, + &dev_attr_cmb_mode.attr, + &dev_attr_cmb_patt_val.attr, + &dev_attr_cmb_patt_mask.attr, + &dev_attr_cmb_patt_ts.attr, + &dev_attr_cmb_ts_all.attr, + &dev_attr_cmb_trig_patt_val_lsb.attr, + &dev_attr_cmb_trig_patt_mask_lsb.attr, + &dev_attr_cmb_trig_patt_val_msb.attr, + &dev_attr_cmb_trig_patt_mask_msb.attr, + &dev_attr_cmb_trig_ts.attr, + &dev_attr_cmb_msr.attr, + &dev_attr_cmb_read_interface_state.attr, + &dev_attr_cmb_read_ctl_reg.attr, + &dev_attr_cmb_markr.attr, + &dev_attr_mcmb_trig_lane.attr, + &dev_attr_mcmb_lanes_select.attr, + NULL, +}; + +static struct attribute_group tpdm_bc_attr_grp = { + .attrs = tpdm_bc_attrs, +}; + +static struct attribute_group tpdm_tc_attr_grp = { + .attrs = tpdm_tc_attrs, +}; + +static struct attribute_group tpdm_dsb_attr_grp = { + .attrs = tpdm_dsb_attrs, +}; + +static struct attribute_group tpdm_cmb_attr_grp = { + .attrs = tpdm_cmb_attrs, }; static struct attribute *tpdm_attrs[] = { @@ -3227,6 +4017,7 @@ static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_bc_attr_grp, &tpdm_tc_attr_grp, &tpdm_dsb_attr_grp, + &tpdm_cmb_attr_grp, NULL, }; From patchwork Thu Oct 21 07:38:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574273 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1EE94C433EF for ; Thu, 21 Oct 2021 07:44:35 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 D5A8161130 for ; Thu, 21 Oct 2021 07:44:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org D5A8161130 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=u7wzdwjNxZbZDZ55bm1+hnuvef0Es6WvaoGMynh6VQo=; b=p4NPhdZyyf2qPu CCJ7zZsVR43/PSFuatwz1vpsh3XnqIQ8hvehBD15DTEqkzr1GpKAWiDCjouUcxT1qtEcoZzl3H8hG pQyQbSBJTRWHsUFtrZInAliCc2CYMCK71APEupUo5d4CaZOQv+qpm2ohXx1/Q2nvh/4eYmGu7F3RQ y5Wd4FAONj3E6AH6jeno6e7NiqZ7O/OorA2r19EjbRMKD0iAzqwjVzAZ+Tmdfj+7oU2O33FL82zht JtJoYGCvqAfHpFPGH7LaxwXUn8xKZEE41CaXdrRRZknNgLcyhyUuFs8+fyBpVyagqVhF4Wi9TC7Vr fnOIIEWR71r2wzH8Pvzw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSiw-006icB-ML; Thu, 21 Oct 2021 07:42:51 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSgM-006gy6-4b for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:40:14 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634802010; x=1666338010; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=XlHS7RkDidcejvawrIoMJMo619oA9BA/quUzgDc2BKw=; b=jS6rtBcfMhn6/rhzBvYmKnsHA3H4yB/2me5oU9tOUzFGFTXY4BIcx91n jethIiUfucpfkFGO5eazTEVtQ62jmZ3FKHZPzOYaLtTgqllBknEq9CyF4 nr/GZJ2XuAk9UkavY66oEni5lB7i1+O/nEmo8IcMTWdcFwkzdQFf9xGNT A=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:40:10 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:40:10 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:40:06 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni Subject: [PATCH 09/10] coresight: Add driver to support Coresight device TPDA Date: Thu, 21 Oct 2021 15:38:55 +0800 Message-ID: <1634801936-15080-10-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_004010_404220_7D2E1E6F X-CRM114-Status: GOOD ( 25.43 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add driver to support Coresight device TPDA. This driver provides support for configuring aggregator. This is primarily useful for pulling the data sets from one or more attached monitors and pushing the resultant data out. Multiple monitors are connected on different input ports of TPDA. Signed-off-by: Tao Zhang --- .../bindings/arm/coresight-tpda.yaml | 169 ++++ MAINTAINERS | 3 +- drivers/hwtracing/coresight/Kconfig | 9 + drivers/hwtracing/coresight/Makefile | 1 + drivers/hwtracing/coresight/coresight-tpda.c | 828 ++++++++++++++++++ 5 files changed, 1009 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/coresight-tpda.yaml create mode 100644 drivers/hwtracing/coresight/coresight-tpda.c diff --git a/Documentation/devicetree/bindings/arm/coresight-tpda.yaml b/Documentation/devicetree/bindings/arm/coresight-tpda.yaml new file mode 100644 index 000000000000..860e86d460b5 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coresight-tpda.yaml @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +# Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/arm/coresigh-tpda.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: "Trace, Profiling and Diagnostics Aggregator - TPDA" + +maintainers: + - Tao Zhang + +description: + TPDAs are responsible for: + Packetization and timestamping of data sets utilizing the MIPI STPv2 packet protocol + Pulling data sets from one or more attached TPDM and pushing the resultant (packetized) data out a master ATB interface + Performing an arbitrated ATB interleaving (funneling) task for free-flowing data from TPDM (i.e. CMB and DSB data set flows) + +properties: + $nodename: + pattern: "^tpda(@[0-9a-f]+)$" + + compatible: + items: + const: arm,primecell + + reg: + maxItems: 1 + + reg-names: + items: + const: tpda-base + + qcom,tpda-atid: + $ref: /schemas/types.yaml#/definitions/uint32-array + maxItems: 1 + description: + Use the ATID field for trace source identification. This allows multiple TPDMs to be interleaved + and formatted via the Coresight trace formatter framing protocol and de-formatted/parsed on a host or debugger. + + qcom,bc-elem-size: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + description: + Specifies the BC element size supported by each monitor connected to the aggregator on each port. + + qcom,tc-elem-size: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + description: + Specifies the TC element size supported by each monitor connected to the aggregator on each port. + + qcom,dsb-elem-size: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + description: + Specifies the DSB element size supported by each monitor connected to the aggregator on each port. + + qcom,cmb-elem-size: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + description: + Specifies the CMB element size supported by each monitor connected to the aggregator on each port. + + clocks: + description: + The clock node that QDSS components need to use. + + clock-names: + items: + const: apb_pclk + + in-ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input connections from TPDM to TPDA + + properties: + "#size-cells": + const: 0 + + "#address-cells": + const: 1 + + patternProperties: + '^port@([0-9]+)$': + type: object + description: + Input connections from TPDM to TPDA + + properties: + reg: + maxItems: 1 + + required: + reg + + + out-ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Output connections from the TPDA to legacy CoreSight trace bus. + + properties: + $ref: /schemas/graph.yaml#/properties/port + port: + description: + Output connection from the TPDA to legacy CoreSight Trace bus. + + +required: + - compatible + - reg + - reg-names + - qcom,tpda-atid: + - clocks + - clock-names + - in-ports + - out-ports + +additionalProperties: false + +examples: + # minimum tpda definition. + - | + tpda@10004000 { + compatible = "arm,primecell"; + + reg = <0x10004000 0x1000>; + reg-names = "tpda-base"; + + qcom,tpda-atid = <65>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + tpda_qdss_1_in_tpdm_spdm: endpoint { + remote-endpoint = + <&tpdm_spdm_out_tpda_qdss_1>; + }; + }; + + port@0 { + reg = <0>; + tpda_qdss_0_in_tpdm_dcc: endpoint { + remote-endpoint = + <&tpdm_dcc_out_tpda_qdss_0>; + }; + }; + }; + + out-ports { + port { + tpda_qdss_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_tpda_qdss>; + }; + }; + }; + }; + +... \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS index cabecf760488..71dd4178d4f8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15303,9 +15303,10 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ipa/ -QCOM CORESIGHT TPDM DRIVER +QCOM CORESIGHT COMPONENTS DRIVER M: Tao Zhang S: Maintained +F: drivers/hwtracing/coresight/coresight-tpda.c F: drivers/hwtracing/coresight/coresight-tpdm.c QEMU MACHINE EMULATOR AND VIRTUALIZER SUPPORT diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index abe244a968f6..206a27325bd3 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -197,4 +197,13 @@ config CORESIGHT_TPDM primarily responsible for data set collection and support the ability to collect any permutation of data set types. Monitors are also responsible for interaction with system cross triggering. + +config CORESIGHT_TPDA + tristate "CoreSight Trace, Profiling & Diagnostics Aggregator driver" + select CORESIGHT_LINKS_AND_SINKS + help + This driver provides support for configuring aggregator. This is + primarily useful for pulling the data sets from one or more + attached monitors and pushing the resultant data out. Multiple + monitors are connected on different input ports of TPDA. endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index e7392a0dddeb..cd8079ec276d 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -26,5 +26,6 @@ obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o obj-$(CONFIG_CORESIGHT_TRBE) += coresight-trbe.o obj-$(CONFIG_CORESIGHT_TPDM) += coresight-tpdm.o +obj-$(CONFIG_CORESIGHT_TPDA) += coresight-tpda.o coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \ coresight-cti-sysfs.o diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c new file mode 100644 index 000000000000..3dc46e173be4 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -0,0 +1,828 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coresight-priv.h" + +#define tpda_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off) +#define tpda_readl(drvdata, off) __raw_readl(drvdata->base + off) + +#define TPDA_LOCK(drvdata) \ +do { \ + mb(); /* ensure configuration take effect before we lock it */ \ + tpda_writel(drvdata, 0x0, CORESIGHT_LAR); \ +} while (0) +#define TPDA_UNLOCK(drvdata) \ +do { \ + tpda_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \ + mb(); /* ensure unlock take effect before we configure */ \ +} while (0) + +#define TPDA_CR (0x000) +#define TPDA_Pn_CR(n) (0x004 + (n * 4)) +#define TPDA_FPID_CR (0x084) +#define TPDA_FREQREQ_VAL (0x088) +#define TPDA_SYNCR (0x08C) +#define TPDA_FLUSH_CR (0x090) +#define TPDA_FLUSH_SR (0x094) +#define TPDA_FLUSH_ERR (0x098) + +#define TPDA_MAX_INPORTS 32 + +DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda"); + +struct tpda_drvdata { + void __iomem *base; + struct device *dev; + struct coresight_device *csdev; + struct mutex lock; + bool enable; + uint32_t atid; + uint32_t bc_esize[TPDA_MAX_INPORTS]; + uint32_t tc_esize[TPDA_MAX_INPORTS]; + uint32_t dsb_esize[TPDA_MAX_INPORTS]; + uint32_t cmb_esize[TPDA_MAX_INPORTS]; + bool trig_async; + bool trig_flag_ts; + bool trig_freq; + bool freq_ts; + uint32_t freq_req_val; + bool freq_req; + bool cmbchan_mode; +}; + +static void __tpda_enable_pre_port(struct tpda_drvdata *drvdata) +{ + uint32_t val; + + val = tpda_readl(drvdata, TPDA_CR); + /* Set the master id */ + val = val & ~(0x7F << 13); + val = val & ~(0x7F << 6); + val |= (drvdata->atid << 6); + if (drvdata->trig_async) + val = val | BIT(5); + else + val = val & ~BIT(5); + if (drvdata->trig_flag_ts) + val = val | BIT(4); + else + val = val & ~BIT(4); + if (drvdata->trig_freq) + val = val | BIT(3); + else + val = val & ~BIT(3); + if (drvdata->freq_ts) + val = val | BIT(2); + else + val = val & ~BIT(2); + if (drvdata->cmbchan_mode) + val = val | BIT(20); + else + val = val & ~BIT(20); + tpda_writel(drvdata, val, TPDA_CR); + + /* + * If FLRIE bit is set, set the master and channel + * id as zero + */ + if (BMVAL(tpda_readl(drvdata, TPDA_CR), 4, 4)) + tpda_writel(drvdata, 0x0, TPDA_FPID_CR); +} + +static void __tpda_enable_port(struct tpda_drvdata *drvdata, int port) +{ + uint32_t val; + + val = tpda_readl(drvdata, TPDA_Pn_CR(port)); + if (drvdata->bc_esize[port] == 32) + val = val & ~BIT(4); + else if (drvdata->bc_esize[port] == 64) + val = val | BIT(4); + + if (drvdata->tc_esize[port] == 32) + val = val & ~BIT(5); + else if (drvdata->tc_esize[port] == 64) + val = val | BIT(5); + + if (drvdata->dsb_esize[port] == 32) + val = val & ~BIT(8); + else if (drvdata->dsb_esize[port] == 64) + val = val | BIT(8); + + val = val & ~(0x3 << 6); + if (drvdata->cmb_esize[port] == 8) + val &= ~(0x3 << 6); + else if (drvdata->cmb_esize[port] == 32) + val |= (0x1 << 6); + else if (drvdata->cmb_esize[port] == 64) + val |= (0x2 << 6); + + /* Set the hold time */ + val = val & ~(0x7 << 1); + val |= (0x5 << 1); + tpda_writel(drvdata, val, TPDA_Pn_CR(port)); + /* Enable the port */ + val = val | BIT(0); + tpda_writel(drvdata, val, TPDA_Pn_CR(port)); +} + +static void __tpda_enable_post_port(struct tpda_drvdata *drvdata) +{ + uint32_t val; + + val = tpda_readl(drvdata, TPDA_SYNCR); + /* Clear the mode */ + val = val & ~BIT(12); + /* Program the counter value */ + val = val | 0xFFF; + tpda_writel(drvdata, val, TPDA_SYNCR); + + if (drvdata->freq_req_val) + tpda_writel(drvdata, drvdata->freq_req_val, TPDA_FREQREQ_VAL); + else + tpda_writel(drvdata, 0x0, TPDA_FREQREQ_VAL); + + val = tpda_readl(drvdata, TPDA_CR); + if (drvdata->freq_req) + val = val | BIT(1); + else + val = val & ~BIT(1); + tpda_writel(drvdata, val, TPDA_CR); +} + +static void __tpda_enable(struct tpda_drvdata *drvdata, int port) +{ + TPDA_UNLOCK(drvdata); + + if (!drvdata->enable) + __tpda_enable_pre_port(drvdata); + + __tpda_enable_port(drvdata, port); + + if (!drvdata->enable) + __tpda_enable_post_port(drvdata); + + TPDA_LOCK(drvdata); +} + +static int tpda_enable(struct coresight_device *csdev, int inport, int outport) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + mutex_lock(&drvdata->lock); + __tpda_enable(drvdata, inport); + drvdata->enable = true; + mutex_unlock(&drvdata->lock); + + dev_info(drvdata->dev, "TPDA inport %d enabled\n", inport); + return 0; +} + +static void __tpda_disable(struct tpda_drvdata *drvdata, int port) +{ + uint32_t val; + + TPDA_UNLOCK(drvdata); + + val = tpda_readl(drvdata, TPDA_Pn_CR(port)); + val = val & ~BIT(0); + tpda_writel(drvdata, val, TPDA_Pn_CR(port)); + + TPDA_LOCK(drvdata); +} + +static void tpda_disable(struct coresight_device *csdev, int inport, + int outport) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + mutex_lock(&drvdata->lock); + __tpda_disable(drvdata, inport); + drvdata->enable = false; + mutex_unlock(&drvdata->lock); + + dev_info(drvdata->dev, "TPDA inport %d disabled\n", inport); +} + +static const struct coresight_ops_link tpda_link_ops = { + .enable = tpda_enable, + .disable = tpda_disable, +}; + +static const struct coresight_ops tpda_cs_ops = { + .link_ops = &tpda_link_ops, +}; + +static ssize_t trig_async_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->trig_async); +} + +static ssize_t trig_async_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->trig_async = true; + else + drvdata->trig_async = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(trig_async_enable); + +static ssize_t trig_flag_ts_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->trig_flag_ts); +} + +static ssize_t trig_flag_ts_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->trig_flag_ts = true; + else + drvdata->trig_flag_ts = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(trig_flag_ts_enable); + +static ssize_t trig_freq_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->trig_freq); +} + +static ssize_t trig_freq_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->trig_freq = true; + else + drvdata->trig_freq = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(trig_freq_enable); + +static ssize_t freq_ts_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->freq_ts); +} + +static ssize_t freq_ts_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->freq_ts = true; + else + drvdata->freq_ts = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(freq_ts_enable); + +static ssize_t freq_req_val_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val = drvdata->freq_req_val; + + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); +} + +static ssize_t freq_req_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + drvdata->freq_req_val = val; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(freq_req_val); + +static ssize_t freq_req_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->freq_req); +} + +static ssize_t freq_req_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->freq_req = true; + else + drvdata->freq_req = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(freq_req); + +static ssize_t global_flush_req_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + mutex_lock(&drvdata->lock); + + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDA_UNLOCK(drvdata); + val = tpda_readl(drvdata, TPDA_CR); + TPDA_LOCK(drvdata); + + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t global_flush_req_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDA_UNLOCK(drvdata); + val = tpda_readl(drvdata, TPDA_CR); + val = val | BIT(0); + tpda_writel(drvdata, val, TPDA_CR); + TPDA_LOCK(drvdata); + } + + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(global_flush_req); + +static ssize_t port_flush_req_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + mutex_lock(&drvdata->lock); + + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + TPDA_UNLOCK(drvdata); + val = tpda_readl(drvdata, TPDA_FLUSH_CR); + TPDA_LOCK(drvdata); + + mutex_unlock(&drvdata->lock); + return scnprintf(buf, PAGE_SIZE, "%lx\n", val); +} + +static ssize_t port_flush_req_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + + if (!drvdata->enable) { + mutex_unlock(&drvdata->lock); + return -EPERM; + } + + if (val) { + TPDA_UNLOCK(drvdata); + tpda_writel(drvdata, val, TPDA_FLUSH_CR); + TPDA_LOCK(drvdata); + } + + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(port_flush_req); + +static ssize_t cmbchan_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->cmbchan_mode); +} + +static ssize_t cmbchan_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent); + bool val; + + if (kstrtobool(buf, &val)) + return -EINVAL; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->cmbchan_mode = true; + else + drvdata->cmbchan_mode = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR_RW(cmbchan_mode); + +static struct attribute *tpda_attrs[] = { + &dev_attr_trig_async_enable.attr, + &dev_attr_trig_flag_ts_enable.attr, + &dev_attr_trig_freq_enable.attr, + &dev_attr_freq_ts_enable.attr, + &dev_attr_freq_req_val.attr, + &dev_attr_freq_req.attr, + &dev_attr_global_flush_req.attr, + &dev_attr_port_flush_req.attr, + &dev_attr_cmbchan_mode.attr, + NULL, +}; + +static struct attribute_group tpda_attr_grp = { + .attrs = tpda_attrs, +}; + +static const struct attribute_group *tpda_attr_grps[] = { + &tpda_attr_grp, + NULL, +}; + +static int tpda_parse_tc(struct tpda_drvdata *drvdata) +{ + int len, port, i; + const __be32 *prop; + struct device_node *node = drvdata->dev->of_node; + + prop = of_get_property(node, "qcom,tc-elem-size", &len); + if (prop) { + len /= sizeof(__be32); + if (len < 2 || len > 63 || len % 2 != 0) { + dev_err(drvdata->dev, + "Dataset TC width entries are wrong\n"); + return -EINVAL; + } + + for (i = 0; i < len; i++) { + port = be32_to_cpu(prop[i++]); + if (port >= TPDA_MAX_INPORTS) { + dev_err(drvdata->dev, + "Wrong port specified for TC\n"); + return -EINVAL; + } + drvdata->tc_esize[port] = be32_to_cpu(prop[i]); + } + } + + return 0; +} + +static int tpda_parse_bc(struct tpda_drvdata *drvdata) +{ + int len, port, i; + const __be32 *prop; + struct device_node *node = drvdata->dev->of_node; + + prop = of_get_property(node, "qcom,bc-elem-size", &len); + if (prop) { + len /= sizeof(__be32); + if (len < 2 || len > 63 || len % 2 != 0) { + dev_err(drvdata->dev, + "Dataset BC width entries are wrong\n"); + return -EINVAL; + } + + for (i = 0; i < len; i++) { + port = be32_to_cpu(prop[i++]); + if (port >= TPDA_MAX_INPORTS) { + dev_err(drvdata->dev, + "Wrong port specified for BC\n"); + return -EINVAL; + } + drvdata->bc_esize[port] = be32_to_cpu(prop[i]); + } + } + + return 0; +} + +static int tpda_parse_dsb(struct tpda_drvdata *drvdata) +{ + int len, port, i; + const __be32 *prop; + struct device_node *node = drvdata->dev->of_node; + + prop = of_get_property(node, "qcom,dsb-elem-size", &len); + if (prop) { + len /= sizeof(__be32); + if (len < 2 || len > 63 || len % 2 != 0) { + dev_err(drvdata->dev, + "Dataset DSB width entries are wrong\n"); + return -EINVAL; + } + + for (i = 0; i < len; i++) { + port = be32_to_cpu(prop[i++]); + if (port >= TPDA_MAX_INPORTS) { + dev_err(drvdata->dev, + "Wrong port specified for DSB\n"); + return -EINVAL; + } + drvdata->dsb_esize[port] = be32_to_cpu(prop[i]); + } + } + + return 0; +} + +static int tpda_parse_cmb(struct tpda_drvdata *drvdata) +{ + int len, port, i; + const __be32 *prop; + struct device_node *node = drvdata->dev->of_node; + + prop = of_get_property(node, "qcom,cmb-elem-size", &len); + if (prop) { + len /= sizeof(__be32); + if (len < 2 || len > 63 || len % 2 != 0) { + dev_err(drvdata->dev, + "Dataset CMB width entries are wrong\n"); + return -EINVAL; + } + + for (i = 0; i < len; i++) { + port = be32_to_cpu(prop[i++]); + if (port >= TPDA_MAX_INPORTS) { + dev_err(drvdata->dev, + "Wrong port specified for CMB\n"); + return -EINVAL; + } + drvdata->cmb_esize[port] = be32_to_cpu(prop[i]); + } + } + + return 0; +} + +static int tpda_parse_of_data(struct tpda_drvdata *drvdata) +{ + int ret; + struct device_node *node = drvdata->dev->of_node; + + ret = of_property_read_u32(node, "qcom,tpda-atid", &drvdata->atid); + if (ret) { + dev_err(drvdata->dev, "TPDA ATID is not specified\n"); + return -EINVAL; + } + + ret = tpda_parse_tc(drvdata); + if (ret) { + dev_err(drvdata->dev, "Dataset TC width entries are wrong\n"); + return -EINVAL; + } + + ret = tpda_parse_bc(drvdata); + if (ret) { + dev_err(drvdata->dev, "Dataset BC width entries are wrong\n"); + return -EINVAL; + } + + ret = tpda_parse_dsb(drvdata); + if (ret) { + dev_err(drvdata->dev, "Dataset DSB width entries are wrong\n"); + return -EINVAL; + } + + ret = tpda_parse_cmb(drvdata); + if (ret) { + dev_err(drvdata->dev, "Dataset CMB width entries are wrong\n"); + return -EINVAL; + } + + return 0; +} + +static void tpda_init_default_data(struct tpda_drvdata *drvdata) +{ + drvdata->freq_ts = true; +} + +static bool coresight_authstatus_enabled(void __iomem *addr) +{ + int ret; + unsigned int auth_val; + + if (!addr) + return false; + + auth_val = readl_relaxed(addr + CORESIGHT_AUTHSTATUS); + + if ((BMVAL(auth_val, 0, 1) == 0x2) || + (BMVAL(auth_val, 2, 3) == 0x2) || + (BMVAL(auth_val, 4, 5) == 0x2) || + (BMVAL(auth_val, 6, 7) == 0x2)) + ret = false; + else + ret = true; + + return ret; +} + +static int tpda_probe(struct amba_device *adev, const struct amba_id *id) +{ + int ret; + struct device *dev = &adev->dev; + struct coresight_platform_data *pdata; + struct tpda_drvdata *drvdata; + struct coresight_desc desc = { 0 }; + + desc.name = coresight_alloc_device_name(&tpda_devs, dev); + if (!desc.name) + return -ENOMEM; + pdata = coresight_get_platform_data(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + adev->dev.platform_data = pdata; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = &adev->dev; + dev_set_drvdata(dev, drvdata); + + drvdata->base = devm_ioremap_resource(dev, &adev->res); + if (!drvdata->base) + return -ENOMEM; + + mutex_init(&drvdata->lock); + + ret = tpda_parse_of_data(drvdata); + if (ret) + return ret; + + if (!coresight_authstatus_enabled(drvdata->base)) + goto err; + + tpda_init_default_data(drvdata); + + desc.type = CORESIGHT_DEV_TYPE_LINK; + desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG; + desc.ops = &tpda_cs_ops; + desc.pdata = adev->dev.platform_data; + desc.dev = &adev->dev; + desc.groups = tpda_attr_grps; + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); + + pm_runtime_put(&adev->dev); + + dev_dbg(drvdata->dev, "TPDA initialized\n"); + return 0; +err: + return -EPERM; +} + +static struct amba_id tpda_ids[] = { + { + .id = 0x000f0f00, + .mask = 0x000fff00, + .data = "TPDA", + }, + { 0, 0}, +}; + +static struct amba_driver tpda_driver = { + .drv = { + .name = "coresight-tpda", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + }, + .probe = tpda_probe, + .id_table = tpda_ids, +}; + +module_amba_driver(tpda_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Aggregator driver"); From patchwork Thu Oct 21 07:38:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tao Zhang X-Patchwork-Id: 12574275 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC129C433EF for ; Thu, 21 Oct 2021 07:44:57 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 7D6B26112D for ; Thu, 21 Oct 2021 07:44:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 7D6B26112D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=B/Bdme3ssJ+xpz4XtL9Q0ytDxD7vOtknOkcysgQmF8g=; b=1ed0tecIak3eGi JVhATf7Lz0yePs8HwgYZzz41e7LUkGr0K+wrzNi9F3h4yGEcv8jVAUWgRseQOwM9FynkYmF0fDxEn nllFJJgckrI0CIipAQ/TOavGTeeG6DFUP3lfMY9V4SImH3xLuQYHKjXLzcB2ZAtbl8LQS2DrGUGI7 ulgLDz3DTzMdA3Llvh9tf4OammIxf4JQs5uIML7gfBTcKSQZV4/C6Ckvg7O1tb8Wt8ufY4zDRkS6g gLNBB0XC/Gu/M+/EDeAPm0eZh0pPJgD7Ne01XS+yaZZRi1zUie8W1qO80Nl9InqBLaAJ2S+/XH5PU natkWaiQZPPtp5XO8Y/A==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSjH-006inr-Pw; Thu, 21 Oct 2021 07:43:12 +0000 Received: from alexa-out.qualcomm.com ([129.46.98.28]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mdSgP-006h1r-Fb for linux-arm-kernel@lists.infradead.org; Thu, 21 Oct 2021 07:40:16 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1634802013; x=1666338013; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=9v4Qg1ARrtLQXojSgbU9s11IkaQWrSHzHUrMZaSRTSs=; b=ofQkHhT8GsVBRzYWZdkDc1kyEhVvIAjDylSfMsSv71Tn0hSmPrX9e5vG oPvQPd5TigrodRtkNeCeWfvaMJ42rpubvUQC0Xi2QuGh/QB0kysd0ru1G yW0pHB2tWBKWYRyPX30bJnSM1DcwoWsSWzNUCcG+N3h9wBVZ9RV9aVNDf w=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 21 Oct 2021 00:40:13 -0700 X-QCInternal: smtphost Received: from nalasex01c.na.qualcomm.com ([10.47.97.35]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Oct 2021 00:40:13 -0700 Received: from taozha-gv.qualcomm.com (10.80.80.8) by nalasex01c.na.qualcomm.com (10.47.97.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.7; Thu, 21 Oct 2021 00:40:09 -0700 From: Tao Zhang To: Mathieu Poirier , Suzuki K Poulose , Alexander Shishkin CC: Tao Zhang , Mike Leach , Leo Yan , Greg Kroah-Hartman , , , , Tingwei Zhang , Mao Jinlong , Yuanfang Zhang , Trilok Soni Subject: [PATCH 10/10] ARM: dts: msm: Add TPDA and TPDM support to DTS for RB5 Date: Thu, 21 Oct 2021 15:38:56 +0800 Message-ID: <1634801936-15080-11-git-send-email-quic_taozha@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> References: <1634801936-15080-1-git-send-email-quic_taozha@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01c.na.qualcomm.com (10.47.97.35) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211021_004013_687959_0B0E4091 X-CRM114-Status: GOOD ( 14.38 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add TPDA and TPDM support to DTS for RB5 board. This change is a sample for validating. After applying this patch, the new TPDM and TPDA nodes can be observed at the coresight devices path. TPDM and TPDA hardware can be operated by commands. List the commands for validating this series patches as below. echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink echo 1 > /sys/bus/coresight/devices/tpdm0/enable_source echo 1 > /sys/bus/coresight/devices/tpdm0/integration_test echo 2 > /sys/bus/coresight/devices/tpdm0/integration_test cat /dev/tmc_etf0 > /data/etf-tpdm0.bin echo 0 > /sys/bus/coresight/devices/tpdm0/enable_source echo 0 > /sys/bus/coresight/devices/tmc_etf0/enable_sink echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink echo 1 > /sys/bus/coresight/devices/tpdm1/enable_source echo 1 > /sys/bus/coresight/devices/tpdm1/integration_test echo 2 > /sys/bus/coresight/devices/tpdm1/integration_test cat /dev/tmc_etf0 > /data/etf-tpdm1.bin echo 0 > /sys/bus/coresight/devices/tpdm1/enable_source echo 0 > /sys/bus/coresight/devices/tmc_etf0/enable_sink echo 1 > /sys/bus/coresight/devices/tmc_etf0/enable_sink echo 1 > /sys/bus/coresight/devices/tpdm2/enable_source echo 1 > /sys/bus/coresight/devices/tpdm2/integration_test echo 2 > /sys/bus/coresight/devices/tpdm2/integration_test cat /dev/tmc_etf0 > /data/etf-tpdm2.bin echo 0 > /sys/bus/coresight/devices/tpdm2/enable_source echo 0 > /sys/bus/coresight/devices/tmc_etf0/enable_sink If the data from TPDMs can be obtained from the ETF, it means that the TPDMs verification is successful. At the same time, since TPDM0, TPDM1 and TPDM2 are all connected to the same funnel "funnel@6c2d000" and output via different output ports, it also means that the following patches verification is successful. coresight: add support to enable more coresight paths coresight: funnel: add support for multiple output ports Signed-off-by: Tao Zhang --- arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 439 +++++++++++++++++++++++ 1 file changed, 439 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index 8ac96f8e79d4..bcec8b181e11 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -222,6 +222,445 @@ regulator-max-microvolt = <1800000>; regulator-always-on; }; + + stm@6002000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0 0x06002000 0 0x1000>, + <0 0x16280000 0 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + stm_out: endpoint { + remote-endpoint = + <&funnel0_in7>; + }; + }; + }; + }; + + funnel@6041000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x06041000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + funnel0_out: endpoint { + remote-endpoint = + <&merge_funnel_in0>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@7 { + reg = <7>; + funnel0_in7: endpoint { + remote-endpoint = <&stm_out>; + }; + }; + }; + }; + + funnel@6042000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x06042000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + funnel2_out: endpoint { + remote-endpoint = + <&merge_funnel_in2>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@4 { + reg = <4>; + funnel2_in5: endpoint { + remote-endpoint = + <&apss_merge_funnel_out>; + }; + }; + }; + }; + + funnel@6b04000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0 0x6b04000 0 0x1000>; + reg-names = "funnel-base"; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + merge_funnel_out: endpoint { + remote-endpoint = + <&etf_in>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@7 { + reg = <7>; + swao_funnel_in7: endpoint { + slave-mode; + remote-endpoint= + <&merg_funnel_out>; + }; + }; + }; + + }; + + funnel@6045000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x06045000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + merg_funnel_out: endpoint { + remote-endpoint = <&swao_funnel_in7>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + merge_funnel_in0: endpoint { + remote-endpoint = + <&funnel0_out>; + }; + }; + + port@1 { + reg = <1>; + merge_funnel_in2: endpoint { + remote-endpoint = + <&funnel2_out>; + }; + }; + }; + }; + + etf@6b05000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x06b05000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + in-ports { + port { + etf_in: endpoint { + remote-endpoint = + <&merge_funnel_out>; + }; + }; + }; + }; + + etm@7040000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07040000 0 0x1000>; + + cpu = <&CPU0>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + out-ports { + port { + etm0_out: endpoint { + remote-endpoint = + <&apss_funnel_in0>; + }; + }; + }; + }; + + etm@7140000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07140000 0 0x1000>; + + cpu = <&CPU1>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + out-ports { + port { + etm1_out: endpoint { + remote-endpoint = + <&apss_funnel_in1>; + }; + }; + }; + }; + + etm@7240000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07240000 0 0x1000>; + + cpu = <&CPU2>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + out-ports { + port { + etm2_out: endpoint { + remote-endpoint = + <&apss_funnel_in2>; + }; + }; + }; + }; + + etm@7340000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07340000 0 0x1000>; + + cpu = <&CPU3>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + out-ports { + port { + etm3_out: endpoint { + remote-endpoint = + <&apss_funnel_in3>; + }; + }; + }; + }; + + etm@7440000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07440000 0 0x1000>; + + cpu = <&CPU4>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + out-ports { + port { + etm4_out: endpoint { + remote-endpoint = + <&apss_funnel_in4>; + }; + }; + }; + }; + + etm@7540000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07540000 0 0x1000>; + + cpu = <&CPU5>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + out-ports { + port { + etm5_out: endpoint { + remote-endpoint = + <&apss_funnel_in5>; + }; + }; + }; + }; + + etm@7640000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07640000 0 0x1000>; + + cpu = <&CPU6>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + out-ports { + port { + etm6_out: endpoint { + remote-endpoint = + <&apss_funnel_in6>; + }; + }; + }; + }; + + etm@7740000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + reg = <0 0x07740000 0 0x1000>; + + cpu = <&CPU7>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + out-ports { + port { + etm7_out: endpoint { + remote-endpoint = + <&apss_funnel_in7>; + }; + }; + }; + }; + + funnel@7800000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x07800000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + apss_funnel_out: endpoint { + remote-endpoint = + <&apss_merge_funnel_in>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + apss_funnel_in0: endpoint { + remote-endpoint = + <&etm0_out>; + }; + }; + + port@1 { + reg = <1>; + apss_funnel_in1: endpoint { + remote-endpoint = + <&etm1_out>; + }; + }; + + port@2 { + reg = <2>; + apss_funnel_in2: endpoint { + remote-endpoint = + <&etm2_out>; + }; + }; + + port@3 { + reg = <3>; + apss_funnel_in3: endpoint { + remote-endpoint = + <&etm3_out>; + }; + }; + + port@4 { + reg = <4>; + apss_funnel_in4: endpoint { + remote-endpoint = + <&etm4_out>; + }; + }; + + port@5 { + reg = <5>; + apss_funnel_in5: endpoint { + remote-endpoint = + <&etm5_out>; + }; + }; + + port@6 { + reg = <6>; + apss_funnel_in6: endpoint { + remote-endpoint = + <&etm6_out>; + }; + }; + + port@7 { + reg = <7>; + apss_funnel_in7: endpoint { + remote-endpoint = + <&etm7_out>; + }; + }; + }; + }; + + funnel@7810000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0 0x07810000 0 0x1000>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + apss_merge_funnel_out: endpoint { + remote-endpoint = + <&funnel2_in5>; + }; + }; + }; + + in-ports { + port { + apss_merge_funnel_in: endpoint { + remote-endpoint = + <&apss_funnel_out>; + }; + }; + }; + }; }; &adsp {